]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/terminal.c
network: Fixes bug in macvlan mode selection
[mirror_lxc.git] / src / lxc / terminal.c
CommitLineData
b0a33c1e 1/*
2 * lxc: linux Container library
3 *
4 * (C) Copyright IBM Corp. 2007, 2008
5 *
6 * Authors:
9afe19d6 7 * Daniel Lezcano <daniel.lezcano at free.fr>
b0a33c1e 8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
250b1eec 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
b0a33c1e 22 */
23
d38dd64a
CB
24#ifndef _GNU_SOURCE
25#define _GNU_SOURCE 1
26#endif
9395937a
CB
27#include <errno.h>
28#include <fcntl.h>
e62912bd 29#include <lxc/lxccontainer.h>
b467714b 30#include <pthread.h>
b5159817 31#include <signal.h>
b0a33c1e 32#include <stdio.h>
e0dc0de7 33#include <stdlib.h>
da41561c
CB
34#include <sys/epoll.h>
35#include <sys/types.h>
e62912bd
CB
36#include <termios.h>
37#include <unistd.h>
f2363e38 38
9395937a
CB
39#include "af_unix.h"
40#include "caps.h"
41#include "commands.h"
00dbc43e 42#include "conf.h"
e827ff7e 43#include "config.h"
9395937a 44#include "log.h"
b5159817 45#include "lxclock.h"
9395937a 46#include "mainloop.h"
2530ba95 47#include "memory_utils.h"
e62912bd 48#include "start.h"
303037d2 49#include "syscall_wrappers.h"
0ed9b1bc 50#include "terminal.h"
b5159817 51#include "utils.h"
36eb9bde 52
e827ff7e
SG
53#if HAVE_PTY_H
54#include <pty.h>
55#else
56#include <../include/openpty.h>
57#endif
58
de708fb7 59#define LXC_TERMINAL_BUFFER_SIZE 1024
732375f5 60
2083d59d 61lxc_log_define(terminal, lxc);
36eb9bde 62
4e9c0330 63void lxc_terminal_winsz(int srcfd, int dstfd)
b5159817 64{
0519b5cc 65 int ret;
b5159817 66 struct winsize wsz;
0519b5cc
CB
67
68 if (!isatty(srcfd))
69 return;
70
71 ret = ioctl(srcfd, TIOCGWINSZ, &wsz);
72 if (ret < 0) {
73 WARN("Failed to get window size");
74 return;
724e753c 75 }
0519b5cc
CB
76
77 ret = ioctl(dstfd, TIOCSWINSZ, &wsz);
78 if (ret < 0)
79 WARN("Failed to set window size");
80 else
81 DEBUG("Set window size to %d columns and %d rows", wsz.ws_col,
82 wsz.ws_row);
83
84 return;
b5159817 85}
724e753c 86
5b55021f 87static void lxc_terminal_winch(struct lxc_terminal_state *ts)
b5159817 88{
4e9c0330 89 lxc_terminal_winsz(ts->stdinfd, ts->masterfd);
b5159817 90}
cd453b38 91
9bafc8cb
CB
92int lxc_terminal_signalfd_cb(int fd, uint32_t events, void *cbdata,
93 struct lxc_epoll_descr *descr)
b5159817 94{
1349e92e 95 ssize_t ret;
b5159817 96 struct signalfd_siginfo siginfo;
5b55021f 97 struct lxc_terminal_state *ts = cbdata;
b5159817 98
72f7c19b 99 ret = lxc_read_nointr(fd, &siginfo, sizeof(siginfo));
0d4137cc 100 if (ret < 0 || (size_t)ret < sizeof(siginfo)) {
0519b5cc 101 ERROR("Failed to read signal info");
2e943b7b 102 return LXC_MAINLOOP_ERROR;
cd453b38
DL
103 }
104
1349e92e 105 if (siginfo.ssi_signo == SIGTERM) {
9bafc8cb 106 DEBUG("Received SIGTERM. Detaching from the terminal");
a529bc25 107 return LXC_MAINLOOP_CLOSE;
1349e92e
CB
108 }
109
110 if (siginfo.ssi_signo == SIGWINCH)
7a10164a 111 lxc_terminal_winch(ts);
1349e92e 112
2e943b7b 113 return LXC_MAINLOOP_CONTINUE;
b5159817
DE
114}
115
5b55021f 116struct lxc_terminal_state *lxc_terminal_signal_init(int srcfd, int dstfd)
b5159817 117{
1349e92e 118 int ret;
b6d5de95 119 bool istty = false;
b5159817 120 sigset_t mask;
5b55021f 121 struct lxc_terminal_state *ts;
b5159817
DE
122
123 ts = malloc(sizeof(*ts));
124 if (!ts)
125 return NULL;
126
127 memset(ts, 0, sizeof(*ts));
341c2aed 128 ts->stdinfd = srcfd;
b5159817 129 ts->masterfd = dstfd;
341c2aed 130 ts->sigfd = -1;
b5159817 131
b6d5de95
CB
132 ret = sigemptyset(&mask);
133 if (ret < 0) {
134 SYSERROR("Failed to initialize an empty signal set");
135 goto on_error;
136 }
1349e92e 137
b6d5de95 138 istty = (isatty(srcfd) == 1);
0519b5cc 139 if (!istty) {
25964232 140 INFO("fd %d does not refer to a tty device", srcfd);
1349e92e 141 } else {
b6d5de95
CB
142 ret = sigaddset(&mask, SIGWINCH);
143 if (ret < 0)
7874d81a 144 SYSNOTICE("Failed to add SIGWINCH to signal set");
25964232
LF
145 }
146
1349e92e 147 /* Exit the mainloop cleanly on SIGTERM. */
b6d5de95
CB
148 ret = sigaddset(&mask, SIGTERM);
149 if (ret < 0) {
150 SYSERROR("Failed to add SIGWINCH to signal set");
151 goto on_error;
152 }
b5159817 153
b467714b 154 ret = pthread_sigmask(SIG_BLOCK, &mask, &ts->oldmask);
1349e92e
CB
155 if (ret < 0) {
156 WARN("Failed to block signals");
157 goto on_error;
b5159817
DE
158 }
159
dc5f6125 160 ts->sigfd = signalfd(-1, &mask, SFD_CLOEXEC);
b5159817 161 if (ts->sigfd < 0) {
1349e92e 162 WARN("Failed to create signal fd");
b467714b 163 (void)pthread_sigmask(SIG_SETMASK, &ts->oldmask, NULL);
1349e92e 164 goto on_error;
b5159817
DE
165 }
166
1349e92e
CB
167 DEBUG("Created signal fd %d", ts->sigfd);
168 return ts;
169
170on_error:
171 ERROR("Failed to create signal fd");
172 if (ts->sigfd >= 0) {
173 close(ts->sigfd);
174 ts->sigfd = -1;
175 }
b6d5de95 176
b5159817 177 return ts;
cd453b38
DL
178}
179
5b55021f 180void lxc_terminal_signal_fini(struct lxc_terminal_state *ts)
63376d7d 181{
0e6da90b 182 if (ts->sigfd >= 0) {
b5159817 183 close(ts->sigfd);
1349e92e 184
b467714b 185 if (pthread_sigmask(SIG_SETMASK, &ts->oldmask, NULL) < 0)
a24c5678 186 SYSWARN("Failed to restore signal mask");
0e6da90b 187 }
0d4137cc 188
b5159817
DE
189 free(ts);
190}
1560f6c9 191
99a04585 192static int lxc_terminal_truncate_log_file(struct lxc_terminal *terminal)
861813e5
CB
193{
194 /* be very certain things are kosher */
2083d59d 195 if (!terminal->log_path || terminal->log_fd < 0)
861813e5
CB
196 return -EBADF;
197
2083d59d 198 return lxc_unpriv(ftruncate(terminal->log_fd, 0));
861813e5
CB
199}
200
468724d3 201static int lxc_terminal_rotate_log_file(struct lxc_terminal *terminal)
861813e5 202{
2530ba95 203 __do_free char *tmp = NULL;
861813e5
CB
204 int ret;
205 size_t len;
861813e5 206
99a04585 207 if (!terminal->log_path || terminal->log_rotate == 0)
861813e5
CB
208 return -EOPNOTSUPP;
209
210 /* be very certain things are kosher */
99a04585 211 if (terminal->log_fd < 0)
861813e5
CB
212 return -EBADF;
213
99a04585 214 len = strlen(terminal->log_path) + sizeof(".1");
2530ba95 215 tmp = must_realloc(NULL, len);
861813e5 216
99a04585 217 ret = snprintf(tmp, len, "%s.1", terminal->log_path);
861813e5
CB
218 if (ret < 0 || (size_t)ret >= len)
219 return -EFBIG;
220
99a04585
CB
221 close(terminal->log_fd);
222 terminal->log_fd = -1;
223 ret = lxc_unpriv(rename(terminal->log_path, tmp));
861813e5
CB
224 if (ret < 0)
225 return ret;
226
99a04585 227 return lxc_terminal_create_log_file(terminal);
861813e5
CB
228}
229
a44ae1a9 230static int lxc_terminal_write_log_file(struct lxc_terminal *terminal, char *buf,
8903fb08 231 int bytes_read)
861813e5
CB
232{
233 int ret;
861813e5 234 struct stat st;
8903fb08 235 int64_t space_left = -1;
861813e5 236
99a04585 237 if (terminal->log_fd < 0)
861813e5
CB
238 return 0;
239
240 /* A log size <= 0 means that there's no limit on the size of the log
241 * file at which point we simply ignore whether the log is supposed to
242 * be rotated or not.
243 */
99a04585
CB
244 if (terminal->log_size <= 0)
245 return lxc_write_nointr(terminal->log_fd, buf, bytes_read);
861813e5
CB
246
247 /* Get current size of the log file. */
99a04585 248 ret = fstat(terminal->log_fd, &st);
861813e5 249 if (ret < 0) {
99a04585 250 SYSERROR("Failed to stat the terminal log file descriptor");
861813e5
CB
251 return -1;
252 }
253
254 /* handle non-regular files */
255 if ((st.st_mode & S_IFMT) != S_IFREG) {
256 /* This isn't a regular file. so rotating the file seems a
257 * dangerous thing to do, size limits are also very
258 * questionable. Let's not risk anything and tell the user that
259 * he's requesting us to do weird stuff.
260 */
99a04585 261 if (terminal->log_rotate > 0 || terminal->log_size > 0)
861813e5
CB
262 return -EINVAL;
263
264 /* I mean, sure log wherever you want to. */
99a04585 265 return lxc_write_nointr(terminal->log_fd, buf, bytes_read);
861813e5
CB
266 }
267
99a04585 268 space_left = terminal->log_size - st.st_size;
861813e5
CB
269
270 /* User doesn't want to rotate the log file and there's no more space
271 * left so simply truncate it.
272 */
99a04585
CB
273 if (space_left <= 0 && terminal->log_rotate <= 0) {
274 ret = lxc_terminal_truncate_log_file(terminal);
861813e5
CB
275 if (ret < 0)
276 return ret;
277
99a04585
CB
278 if (bytes_read <= terminal->log_size)
279 return lxc_write_nointr(terminal->log_fd, buf, bytes_read);
861813e5
CB
280
281 /* Write as much as we can into the buffer and loose the rest. */
99a04585 282 return lxc_write_nointr(terminal->log_fd, buf, terminal->log_size);
861813e5
CB
283 }
284
285 /* There's enough space left. */
286 if (bytes_read <= space_left)
99a04585 287 return lxc_write_nointr(terminal->log_fd, buf, bytes_read);
861813e5
CB
288
289 /* There's not enough space left but at least write as much as we can
290 * into the old log file.
291 */
99a04585 292 ret = lxc_write_nointr(terminal->log_fd, buf, space_left);
861813e5
CB
293 if (ret < 0)
294 return -1;
295
296 /* Calculate how many bytes we still need to write. */
297 bytes_read -= space_left;
298
89962c6c 299 /* There'd be more to write but we aren't instructed to rotate the log
861813e5
CB
300 * file so simply return. There's no error on our side here.
301 */
99a04585 302 if (terminal->log_rotate > 0)
468724d3 303 ret = lxc_terminal_rotate_log_file(terminal);
861813e5 304 else
99a04585 305 ret = lxc_terminal_truncate_log_file(terminal);
861813e5
CB
306 if (ret < 0)
307 return ret;
308
99a04585 309 if (terminal->log_size < bytes_read) {
861813e5
CB
310 /* Well, this is unfortunate because it means that there is more
311 * to write than the user has granted us space. There are
312 * multiple ways to handle this but let's use the simplest one:
313 * write as much as we can, tell the user that there was more
314 * stuff to write and move on.
315 * Note that this scenario shouldn't actually happen with the
99a04585 316 * standard pty-based terminal that LXC allocates since it will
861813e5
CB
317 * be switched into raw mode. In raw mode only 1 byte at a time
318 * should be read and written.
319 */
99a04585
CB
320 WARN("Size of terminal log file is smaller than the bytes to write");
321 ret = lxc_write_nointr(terminal->log_fd, buf, terminal->log_size);
861813e5
CB
322 if (ret < 0)
323 return -1;
324 bytes_read -= ret;
325 return bytes_read;
326 }
327
328 /* Yay, we made it. */
99a04585 329 ret = lxc_write_nointr(terminal->log_fd, buf, bytes_read);
861813e5
CB
330 if (ret < 0)
331 return -1;
332 bytes_read -= ret;
333 return bytes_read;
334}
335
de708fb7 336int lxc_terminal_io_cb(int fd, uint32_t events, void *data,
a529bc25 337 struct lxc_epoll_descr *descr)
b5159817 338{
dcad02f8 339 struct lxc_terminal *terminal = data;
de708fb7 340 char buf[LXC_TERMINAL_BUFFER_SIZE];
732375f5 341 int r, w, w_log, w_rbuf;
e0dc0de7 342
3e6580ec
CB
343 w = r = lxc_read_nointr(fd, buf, sizeof(buf));
344 if (r <= 0) {
de708fb7 345 INFO("Terminal client on fd %d has exited", fd);
b5159817 346 lxc_mainloop_del_handler(descr, fd);
c06a0555 347
de708fb7
CB
348 if (fd == terminal->master) {
349 terminal->master = -EBADF;
350 } else if (fd == terminal->peer) {
351 if (terminal->tty_state) {
352 lxc_terminal_signal_fini(terminal->tty_state);
353 terminal->tty_state = NULL;
0b1e242b 354 }
de708fb7 355 terminal->peer = -EBADF;
c06a0555
CB
356 } else {
357 ERROR("Handler received unexpected file descriptor");
0b1e242b 358 }
b5159817 359 close(fd);
c06a0555 360
a529bc25 361 return LXC_MAINLOOP_CLOSE;
33fcb7a0 362 }
63376d7d 363
de708fb7
CB
364 if (fd == terminal->peer)
365 w = lxc_write_nointr(terminal->master, buf, r);
b5159817 366
732375f5 367 w_rbuf = w_log = 0;
de708fb7 368 if (fd == terminal->master) {
732375f5 369 /* write to peer first */
de708fb7
CB
370 if (terminal->peer >= 0)
371 w = lxc_write_nointr(terminal->peer, buf, r);
732375f5 372
de708fb7
CB
373 /* write to terminal ringbuffer */
374 if (terminal->buffer_size > 0)
375 w_rbuf = lxc_ringbuf_write(&terminal->ringbuf, buf, r);
861813e5 376
de708fb7
CB
377 /* write to terminal log */
378 if (terminal->log_fd >= 0)
a44ae1a9 379 w_log = lxc_terminal_write_log_file(terminal, buf, r);
63376d7d
DL
380 }
381
b5159817 382 if (w != r)
de708fb7 383 WARN("Short write on terminal r:%d != w:%d", r, w);
732375f5 384
7874d81a 385 if (w_rbuf < 0) {
386 errno = -w_rbuf;
387 SYSTRACE("Failed to write %d bytes to terminal ringbuffer", r);
388 }
732375f5
CB
389
390 if (w_log < 0)
de708fb7 391 TRACE("Failed to write %d bytes to terminal log", r);
0d4137cc 392
2b8bf299 393 return LXC_MAINLOOP_CONTINUE;
b5159817
DE
394}
395
dcad02f8 396static int lxc_terminal_mainloop_add_peer(struct lxc_terminal *terminal)
b5159817 397{
a529bc25
CB
398 int ret;
399
2083d59d
CB
400 if (terminal->peer >= 0) {
401 ret = lxc_mainloop_add_handler(terminal->descr, terminal->peer,
402 lxc_terminal_io_cb, terminal);
a529bc25 403 if (ret < 0) {
2083d59d 404 WARN("Failed to add terminal peer handler to mainloop");
a529bc25
CB
405 return -1;
406 }
63376d7d
DL
407 }
408
2083d59d 409 if (!terminal->tty_state || terminal->tty_state->sigfd < 0)
a529bc25
CB
410 return 0;
411
2083d59d
CB
412 ret = lxc_mainloop_add_handler(terminal->descr, terminal->tty_state->sigfd,
413 lxc_terminal_signalfd_cb, terminal->tty_state);
a529bc25
CB
414 if (ret < 0) {
415 WARN("Failed to add signal handler to mainloop");
416 return -1;
b5159817 417 }
a529bc25
CB
418
419 return 0;
b5159817
DE
420}
421
093bce5f 422int lxc_terminal_mainloop_add(struct lxc_epoll_descr *descr,
ea5b3c23 423 struct lxc_terminal *terminal)
b5159817 424{
a529bc25 425 int ret;
b5159817 426
2083d59d
CB
427 if (terminal->master < 0) {
428 INFO("Terminal is not initialized");
b5159817 429 return 0;
596a818d
DE
430 }
431
2083d59d
CB
432 ret = lxc_mainloop_add_handler(descr, terminal->master,
433 lxc_terminal_io_cb, terminal);
30a33fbd 434 if (ret < 0) {
ea5b3c23
CB
435 ERROR("Failed to add handler for terminal master fd %d to "
436 "mainloop", terminal->master);
b5159817 437 return -1;
28a4b0e5
DL
438 }
439
30a33fbd 440 /* We cache the descr so that we can add an fd to it when someone
c1ee47cd 441 * does attach to it in lxc_terminal_allocate().
b5159817 442 */
2083d59d 443 terminal->descr = descr;
cd453b38 444
ea5b3c23 445 return lxc_terminal_mainloop_add_peer(terminal);
b5159817 446}
28a4b0e5 447
0d4137cc 448int lxc_setup_tios(int fd, struct termios *oldtios)
b5159817 449{
e4953e62 450 int ret;
b5159817 451 struct termios newtios;
e0dc0de7 452
b5159817 453 if (!isatty(fd)) {
e4953e62 454 ERROR("File descriptor %d does not refert to a terminal", fd);
b5159817 455 return -1;
e0dc0de7
DL
456 }
457
e4953e62
CB
458 /* Get current termios. */
459 ret = tcgetattr(fd, oldtios);
460 if (ret < 0) {
461 SYSERROR("Failed to get current terminal settings");
b5159817 462 return -1;
e0dc0de7
DL
463 }
464
4dc96430
TJ
465 /* ensure we don't end up in an endless loop:
466 * The kernel might fire SIGTTOU while an
467 * ioctl() in tcsetattr() is executed. When the ioctl()
468 * is resumed and retries, the signal handler interrupts it again.
469 */
470 signal (SIGTTIN, SIG_IGN);
471 signal (SIGTTOU, SIG_IGN);
472
b5159817 473 newtios = *oldtios;
e0dc0de7 474
a7c97a40
CB
475 /* We use the same settings that ssh does. */
476 newtios.c_iflag |= IGNPAR;
477 newtios.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF);
478#ifdef IUCLC
479 newtios.c_iflag &= ~IUCLC;
480#endif
4dc96430 481 newtios.c_lflag &= ~(TOSTOP | ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL);
a7c97a40
CB
482#ifdef IEXTEN
483 newtios.c_lflag &= ~IEXTEN;
484#endif
e5adb2b5 485 newtios.c_oflag &= ~ONLCR;
300ec717 486 newtios.c_oflag |= OPOST;
b5159817
DE
487 newtios.c_cc[VMIN] = 1;
488 newtios.c_cc[VTIME] = 0;
e0dc0de7 489
a7c97a40 490 /* Set new attributes. */
e4953e62
CB
491 ret = tcsetattr(fd, TCSAFLUSH, &newtios);
492 if (ret < 0) {
493 ERROR("Failed to set new terminal settings");
b5159817 494 return -1;
e0dc0de7
DL
495 }
496
63376d7d 497 return 0;
b5159817 498}
e0dc0de7 499
dcad02f8 500static void lxc_terminal_peer_proxy_free(struct lxc_terminal *terminal)
b5159817 501{
2083d59d
CB
502 if (terminal->tty_state) {
503 lxc_terminal_signal_fini(terminal->tty_state);
504 terminal->tty_state = NULL;
b5159817 505 }
e788f4ac 506
fb87aa6a 507 close(terminal->proxy.master);
fb87aa6a 508 terminal->proxy.master = -1;
e788f4ac
CB
509
510 close(terminal->proxy.slave);
fb87aa6a 511 terminal->proxy.slave = -1;
e788f4ac 512
fb87aa6a 513 terminal->proxy.busy = -1;
e788f4ac 514
fb87aa6a 515 terminal->proxy.name[0] = '\0';
e788f4ac 516
2083d59d 517 terminal->peer = -1;
b5159817 518}
596a818d 519
60dd8ef4
CB
520static int lxc_terminal_peer_proxy_alloc(struct lxc_terminal *terminal,
521 int sockfd)
b5159817 522{
60dd8ef4 523 int ret;
b5159817 524 struct termios oldtermio;
5b55021f 525 struct lxc_terminal_state *ts;
b5159817 526
2083d59d
CB
527 if (terminal->master < 0) {
528 ERROR("Terminal not set up");
b5159817
DE
529 return -1;
530 }
60dd8ef4 531
fb87aa6a 532 if (terminal->proxy.busy != -1 || terminal->peer != -1) {
2083d59d 533 NOTICE("Terminal already in use");
b5159817
DE
534 return -1;
535 }
60dd8ef4 536
2083d59d 537 if (terminal->tty_state) {
60dd8ef4 538 ERROR("Terminal has already been initialized");
b5159817 539 return -1;
596a818d
DE
540 }
541
d712f9e8
CB
542 /* This is the proxy terminal that will be given to the client, and
543 * that the real terminal master will send to / recv from.
b5159817 544 */
3f15bdd9
CB
545 ret = openpty(&terminal->proxy.master, &terminal->proxy.slave, NULL,
546 NULL, NULL);
60dd8ef4
CB
547 if (ret < 0) {
548 SYSERROR("Failed to open proxy terminal");
b5159817
DE
549 return -1;
550 }
596a818d 551
3f15bdd9
CB
552 ret = ttyname_r(terminal->proxy.slave, terminal->proxy.name,
553 sizeof(terminal->proxy.name));
554 if (ret < 0) {
555 SYSERROR("Failed to retrieve name of proxy terminal slave");
556 goto on_error;
557 }
558
408c18a1
CB
559 ret = fd_cloexec(terminal->proxy.master, true);
560 if (ret < 0) {
561 SYSERROR("Failed to set FD_CLOEXEC flag on proxy terminal master");
562 goto on_error;
563 }
564
565 ret = fd_cloexec(terminal->proxy.slave, true);
566 if (ret < 0) {
567 SYSERROR("Failed to set FD_CLOEXEC flag on proxy terminal slave");
568 goto on_error;
569 }
570
60dd8ef4
CB
571 ret = lxc_setup_tios(terminal->proxy.slave, &oldtermio);
572 if (ret < 0)
573 goto on_error;
b5159817 574
fb87aa6a 575 ts = lxc_terminal_signal_init(terminal->proxy.master, terminal->master);
b5159817 576 if (!ts)
60dd8ef4 577 goto on_error;
b5159817 578
2083d59d 579 terminal->tty_state = ts;
fb87aa6a
CB
580 terminal->peer = terminal->proxy.slave;
581 terminal->proxy.busy = sockfd;
2083d59d 582 ret = lxc_terminal_mainloop_add_peer(terminal);
a529bc25 583 if (ret < 0)
60dd8ef4 584 goto on_error;
b5159817 585
60dd8ef4
CB
586 NOTICE("Opened proxy terminal with master fd %d and slave fd %d",
587 terminal->proxy.master, terminal->proxy.slave);
b5159817
DE
588 return 0;
589
60dd8ef4 590on_error:
2083d59d 591 lxc_terminal_peer_proxy_free(terminal);
63376d7d
DL
592 return -1;
593}
594
c1ee47cd 595int lxc_terminal_allocate(struct lxc_conf *conf, int sockfd, int *ttyreq)
b5159817 596{
12c2eaaa
CB
597 int ttynum;
598 int masterfd = -1;
0e4be3cf 599 struct lxc_tty_info *ttys = &conf->ttys;
dcad02f8 600 struct lxc_terminal *terminal = &conf->console;
b5159817 601
b5159817 602 if (*ttyreq == 0) {
12c2eaaa
CB
603 int ret;
604
605 ret = lxc_terminal_peer_proxy_alloc(terminal, sockfd);
606 if (ret < 0)
b5159817 607 goto out;
12c2eaaa 608
fb87aa6a 609 masterfd = terminal->proxy.master;
b5159817
DE
610 goto out;
611 }
612
613 if (*ttyreq > 0) {
885766f5 614 if (*ttyreq > ttys->max)
b5159817
DE
615 goto out;
616
0e4be3cf 617 if (ttys->tty[*ttyreq - 1].busy)
b5159817
DE
618 goto out;
619
12c2eaaa 620 /* The requested tty is available. */
b5159817
DE
621 ttynum = *ttyreq;
622 goto out_tty;
623 }
624
12c2eaaa 625 /* Search for next available tty, fixup index tty1 => [0]. */
885766f5 626 for (ttynum = 1; ttynum <= ttys->max && ttys->tty[ttynum - 1].busy; ttynum++) {
0d4137cc 627 ;
12c2eaaa 628 }
b5159817 629
12c2eaaa 630 /* We didn't find any available slot for tty. */
885766f5 631 if (ttynum > ttys->max)
b5159817
DE
632 goto out;
633
634 *ttyreq = ttynum;
635
636out_tty:
0e4be3cf
CB
637 ttys->tty[ttynum - 1].busy = sockfd;
638 masterfd = ttys->tty[ttynum - 1].master;
12c2eaaa 639
b5159817 640out:
b5159817
DE
641 return masterfd;
642}
643
3dfe6f8d 644void lxc_terminal_free(struct lxc_conf *conf, int fd)
63376d7d 645{
b5159817 646 int i;
0e4be3cf 647 struct lxc_tty_info *ttys = &conf->ttys;
dcad02f8 648 struct lxc_terminal *terminal = &conf->console;
b5159817 649
885766f5 650 for (i = 0; i < ttys->max; i++)
0e4be3cf
CB
651 if (ttys->tty[i].busy == fd)
652 ttys->tty[i].busy = 0;
b5159817 653
1b5e93c4
CB
654 if (terminal->proxy.busy != fd)
655 return;
656
657 lxc_mainloop_del_handler(terminal->descr, terminal->proxy.slave);
658 lxc_terminal_peer_proxy_free(terminal);
b5159817
DE
659}
660
dcad02f8 661static int lxc_terminal_peer_default(struct lxc_terminal *terminal)
b5159817 662{
5b55021f 663 struct lxc_terminal_state *ts;
46768cce 664 const char *path;
467c7ff3 665 int ret = 0;
b5159817 666
46768cce
CB
667 if (terminal->path)
668 path = terminal->path;
669 else
670 path = "/dev/tty";
b5159817 671
2083d59d
CB
672 terminal->peer = lxc_unpriv(open(path, O_RDWR | O_CLOEXEC));
673 if (terminal->peer < 0) {
46768cce
CB
674 if (!terminal->path) {
675 errno = ENODEV;
7874d81a 676 SYSDEBUG("The process does not have a controlling terminal");
46768cce
CB
677 goto on_succes;
678 }
679
6d1400b5 680 SYSERROR("Failed to open proxy terminal \"%s\"", path);
467c7ff3
CB
681 return -ENOTTY;
682 }
49cd0656 683 DEBUG("Using terminal \"%s\" as proxy", path);
b5159817 684
2083d59d 685 if (!isatty(terminal->peer)) {
49cd0656
CB
686 ERROR("File descriptor for \"%s\" does not refer to a terminal", path);
687 goto on_error_free_tios;
467c7ff3 688 }
b5159817 689
2083d59d
CB
690 ts = lxc_terminal_signal_init(terminal->peer, terminal->master);
691 terminal->tty_state = ts;
341c2aed 692 if (!ts) {
0519b5cc 693 WARN("Failed to install signal handler");
49cd0656 694 goto on_error_free_tios;
341c2aed 695 }
b5159817 696
2083d59d 697 lxc_terminal_winsz(terminal->peer, terminal->master);
b5159817 698
2083d59d 699 terminal->tios = malloc(sizeof(*terminal->tios));
49cd0656
CB
700 if (!terminal->tios)
701 goto on_error_free_tios;
b5159817 702
49cd0656
CB
703 ret = lxc_setup_tios(terminal->peer, terminal->tios);
704 if (ret < 0)
705 goto on_error_close_peer;
467c7ff3 706 else
49cd0656 707 goto on_succes;
b5159817 708
49cd0656 709on_error_free_tios:
2083d59d
CB
710 free(terminal->tios);
711 terminal->tios = NULL;
467c7ff3 712
49cd0656 713on_error_close_peer:
2083d59d
CB
714 close(terminal->peer);
715 terminal->peer = -1;
467c7ff3
CB
716 ret = -ENOTTY;
717
49cd0656 718on_succes:
467c7ff3 719 return ret;
b5159817
DE
720}
721
dcad02f8 722int lxc_terminal_write_ringbuffer(struct lxc_terminal *terminal)
39c6cdb7
CB
723{
724 char *r_addr;
725 ssize_t ret;
726 uint64_t used;
2083d59d 727 struct lxc_ringbuf *buf = &terminal->ringbuf;
39c6cdb7
CB
728
729 /* There's not log file where we can dump the ringbuffer to. */
2083d59d 730 if (terminal->log_fd < 0)
39c6cdb7
CB
731 return 0;
732
39c6cdb7
CB
733 used = lxc_ringbuf_used(buf);
734 if (used == 0)
735 return 0;
736
2083d59d 737 ret = lxc_terminal_truncate_log_file(terminal);
39c6cdb7
CB
738 if (ret < 0)
739 return ret;
740
741 /* Write as much as we can without exceeding the limit. */
2083d59d
CB
742 if (terminal->log_size < used)
743 used = terminal->log_size;
39c6cdb7
CB
744
745 r_addr = lxc_ringbuf_get_read_addr(buf);
2083d59d 746 ret = lxc_write_nointr(terminal->log_fd, r_addr, used);
39c6cdb7
CB
747 if (ret < 0)
748 return -EIO;
749
750 return 0;
751}
752
dcad02f8 753void lxc_terminal_delete(struct lxc_terminal *terminal)
b5159817 754{
69629c82
CB
755 int ret;
756
2083d59d 757 ret = lxc_terminal_write_ringbuffer(terminal);
39c6cdb7 758 if (ret < 0)
2083d59d 759 WARN("Failed to write terminal log to disk");
39c6cdb7 760
2083d59d
CB
761 if (terminal->tios && terminal->peer >= 0) {
762 ret = tcsetattr(terminal->peer, TCSAFLUSH, terminal->tios);
69629c82 763 if (ret < 0)
a24c5678 764 SYSWARN("Failed to set old terminal settings");
69629c82 765 }
2083d59d
CB
766 free(terminal->tios);
767 terminal->tios = NULL;
596a818d 768
2083d59d
CB
769 if (terminal->peer >= 0)
770 close(terminal->peer);
771 terminal->peer = -1;
bc9724f7 772
2083d59d
CB
773 if (terminal->master >= 0)
774 close(terminal->master);
775 terminal->master = -1;
bc9724f7 776
2083d59d
CB
777 if (terminal->slave >= 0)
778 close(terminal->slave);
779 terminal->slave = -1;
bc9724f7 780
2083d59d
CB
781 if (terminal->log_fd >= 0)
782 close(terminal->log_fd);
783 terminal->log_fd = -1;
63376d7d
DL
784}
785
3b988b33
CB
786/**
787 * Note that this function needs to run before the mainloop starts. Since we
2083d59d
CB
788 * register a handler for the terminal's masterfd when we create the mainloop
789 * the terminal handler needs to see an allocated ringbuffer.
3b988b33 790 */
dcad02f8 791static int lxc_terminal_create_ringbuf(struct lxc_terminal *terminal)
3b988b33
CB
792{
793 int ret;
2083d59d
CB
794 struct lxc_ringbuf *buf = &terminal->ringbuf;
795 uint64_t size = terminal->buffer_size;
3b988b33
CB
796
797 /* no ringbuffer previously allocated and no ringbuffer requested */
798 if (!buf->addr && size <= 0)
799 return 0;
800
801 /* ringbuffer allocated but no new ringbuffer requested */
802 if (buf->addr && size <= 0) {
803 lxc_ringbuf_release(buf);
804 buf->addr = NULL;
805 buf->r_off = 0;
806 buf->w_off = 0;
807 buf->size = 0;
2083d59d 808 TRACE("Deallocated terminal ringbuffer");
3b988b33
CB
809 return 0;
810 }
811
812 if (size <= 0)
813 return 0;
814
815 /* check wether the requested size for the ringbuffer has changed */
816 if (buf->addr && buf->size != size) {
2083d59d
CB
817 TRACE("Terminal ringbuffer size changed from %" PRIu64
818 " to %" PRIu64 " bytes. Deallocating terminal ringbuffer",
3b988b33
CB
819 buf->size, size);
820 lxc_ringbuf_release(buf);
821 }
822
823 ret = lxc_ringbuf_create(buf, size);
824 if (ret < 0) {
2083d59d 825 ERROR("Failed to setup %" PRIu64 " byte terminal ringbuffer", size);
3b988b33
CB
826 return -1;
827 }
828
2083d59d 829 TRACE("Allocated %" PRIu64 " byte terminal ringbuffer", size);
3b988b33
CB
830 return 0;
831}
832
a0309168 833/**
2083d59d
CB
834 * This is the terminal log file. Please note that the terminal log file is
835 * (implementation wise not content wise) independent of the terminal ringbuffer.
a0309168 836 */
dcad02f8 837int lxc_terminal_create_log_file(struct lxc_terminal *terminal)
a0309168 838{
2083d59d 839 if (!terminal->log_path)
a0309168
CB
840 return 0;
841
2083d59d
CB
842 terminal->log_fd = lxc_unpriv(open(terminal->log_path, O_CLOEXEC | O_RDWR | O_CREAT | O_APPEND, 0600));
843 if (terminal->log_fd < 0) {
844 SYSERROR("Failed to open terminal log file \"%s\"", terminal->log_path);
a0309168
CB
845 return -1;
846 }
847
2083d59d 848 DEBUG("Using \"%s\" as terminal log file", terminal->log_path);
a0309168
CB
849 return 0;
850}
851
dcad02f8 852int lxc_terminal_create(struct lxc_terminal *terminal)
63376d7d 853{
8ded9244 854 int ret;
b5159817 855
3f15bdd9 856 ret = openpty(&terminal->master, &terminal->slave, NULL, NULL, NULL);
467c7ff3 857 if (ret < 0) {
8ded9244 858 SYSERROR("Failed to open terminal");
b5159817
DE
859 return -1;
860 }
861
3f15bdd9
CB
862 ret = ttyname_r(terminal->slave, terminal->name, sizeof(terminal->name));
863 if (ret < 0) {
864 SYSERROR("Failed to retrieve name of terminal slave");
865 goto err;
866 }
867
408c18a1 868 ret = fd_cloexec(terminal->master, true);
69629c82 869 if (ret < 0) {
2083d59d 870 SYSERROR("Failed to set FD_CLOEXEC flag on terminal master");
b5159817
DE
871 goto err;
872 }
873
408c18a1 874 ret = fd_cloexec(terminal->slave, true);
69629c82 875 if (ret < 0) {
2083d59d 876 SYSERROR("Failed to set FD_CLOEXEC flag on terminal slave");
b5159817
DE
877 goto err;
878 }
879
2083d59d 880 ret = lxc_terminal_peer_default(terminal);
467c7ff3 881 if (ret < 0) {
8ded9244 882 ERROR("Failed to allocate proxy terminal");
467c7ff3
CB
883 goto err;
884 }
b5159817 885
5777fe90
CB
886 return 0;
887
888err:
2083d59d 889 lxc_terminal_delete(terminal);
5777fe90
CB
890 return -ENODEV;
891}
892
564e31c4 893int lxc_terminal_setup(struct lxc_conf *conf)
5777fe90
CB
894{
895 int ret;
dcad02f8 896 struct lxc_terminal *terminal = &conf->console;
5777fe90 897
1a443ac1
CB
898 if (terminal->path && strcmp(terminal->path, "none") == 0) {
899 INFO("No terminal requested");
5777fe90
CB
900 return 0;
901 }
902
96eee564 903 ret = lxc_terminal_create(terminal);
5777fe90
CB
904 if (ret < 0)
905 return -1;
906
2083d59d 907 ret = lxc_terminal_create_log_file(terminal);
a0309168
CB
908 if (ret < 0)
909 goto err;
910
2083d59d 911 ret = lxc_terminal_create_ringbuf(terminal);
a0309168
CB
912 if (ret < 0)
913 goto err;
b5159817
DE
914
915 return 0;
916
917err:
2083d59d 918 lxc_terminal_delete(terminal);
69629c82 919 return -ENODEV;
b5159817
DE
920}
921
8ca7b374
CB
922static bool __terminal_dup2(int duplicate, int original)
923{
924 int ret;
925
926 if (!isatty(original))
927 return true;
928
929 ret = dup2(duplicate, original);
930 if (ret < 0) {
931 SYSERROR("Failed to dup2(%d, %d)", duplicate, original);
932 return false;
933 }
934
935 return true;
936}
937
ae6d3913 938int lxc_terminal_set_stdfds(int fd)
0d9acb99 939{
8ca7b374
CB
940 int i;
941
39a78bbe 942 if (fd < 0)
0d9acb99 943 return 0;
b5159817 944
8ca7b374
CB
945 for (i = 0; i < 3; i++)
946 if (!__terminal_dup2(fd, (int[]){STDIN_FILENO, STDOUT_FILENO,
947 STDERR_FILENO}[i]))
39a78bbe 948 return -1;
39a78bbe 949
0d9acb99
DE
950 return 0;
951}
b5159817 952
52f9292f 953int lxc_terminal_stdin_cb(int fd, uint32_t events, void *cbdata,
15085292 954 struct lxc_epoll_descr *descr)
b5159817 955{
15085292 956 int ret;
b5159817 957 char c;
15085292 958 struct lxc_terminal_state *ts = cbdata;
b5159817 959
97bc2422 960 if (fd != ts->stdinfd)
a529bc25 961 return LXC_MAINLOOP_CLOSE;
97bc2422 962
15085292
CB
963 ret = lxc_read_nointr(ts->stdinfd, &c, 1);
964 if (ret <= 0)
a529bc25 965 return LXC_MAINLOOP_CLOSE;
63376d7d 966
525e2117 967 if (ts->escape >= 1) {
2083d59d 968 /* we want to exit the terminal with Ctrl+a q */
014d5e1e
CB
969 if (c == ts->escape && !ts->saw_escape) {
970 ts->saw_escape = 1;
15085292 971 return LXC_MAINLOOP_CONTINUE;
014d5e1e 972 }
5c294060 973
014d5e1e 974 if (c == 'q' && ts->saw_escape)
a529bc25 975 return LXC_MAINLOOP_CLOSE;
014d5e1e
CB
976
977 ts->saw_escape = 0;
978 }
63376d7d 979
15085292
CB
980 ret = lxc_write_nointr(ts->masterfd, &c, 1);
981 if (ret <= 0)
a529bc25 982 return LXC_MAINLOOP_CLOSE;
b5159817 983
15085292 984 return LXC_MAINLOOP_CONTINUE;
63376d7d
DL
985}
986
ee9102ff
CB
987int lxc_terminal_master_cb(int fd, uint32_t events, void *cbdata,
988 struct lxc_epoll_descr *descr)
63376d7d 989{
0d4137cc 990 int r, w;
5bd171bd
CB
991 char buf[LXC_TERMINAL_BUFFER_SIZE];
992 struct lxc_terminal_state *ts = cbdata;
63376d7d 993
97bc2422 994 if (fd != ts->masterfd)
a529bc25 995 return LXC_MAINLOOP_CLOSE;
97bc2422 996
e66b6c96
CB
997 r = lxc_read_nointr(fd, buf, sizeof(buf));
998 if (r <= 0)
a529bc25 999 return LXC_MAINLOOP_CLOSE;
1560f6c9 1000
e66b6c96 1001 w = lxc_write_nointr(ts->stdoutfd, buf, r);
5bd171bd 1002 if (w <= 0 || w != r)
a529bc25 1003 return LXC_MAINLOOP_CLOSE;
f78a1f32 1004
5bd171bd 1005 return LXC_MAINLOOP_CONTINUE;
b5159817
DE
1006}
1007
c86e2584 1008int lxc_terminal_getfd(struct lxc_container *c, int *ttynum, int *masterfd)
b5159817
DE
1009{
1010 return lxc_cmd_console(c->name, ttynum, masterfd, c->config_path);
1011}
1012
1013int lxc_console(struct lxc_container *c, int ttynum,
1014 int stdinfd, int stdoutfd, int stderrfd,
1015 int escape)
1016{
71ac3f07 1017 int masterfd, ret, ttyfd;
b5159817
DE
1018 struct lxc_epoll_descr descr;
1019 struct termios oldtios;
5b55021f 1020 struct lxc_terminal_state *ts;
25964232 1021 int istty = 0;
b5159817 1022
b5159817 1023 ttyfd = lxc_cmd_console(c->name, &ttynum, &masterfd, c->config_path);
6834f805
CB
1024 if (ttyfd < 0)
1025 return -1;
b5159817
DE
1026
1027 ret = setsid();
33b4b411
CB
1028 if (ret < 0)
1029 TRACE("Process is already group leader");
b5159817 1030
dc8c7883 1031 ts = lxc_terminal_signal_init(stdinfd, masterfd);
b5159817
DE
1032 if (!ts) {
1033 ret = -1;
33b4b411 1034 goto close_fds;
b5159817
DE
1035 }
1036 ts->escape = escape;
3b975060 1037 ts->stdoutfd = stdoutfd;
b5159817 1038
6834f805 1039 istty = isatty(stdinfd);
25964232 1040 if (istty) {
4e9c0330 1041 lxc_terminal_winsz(stdinfd, masterfd);
2bd158cc 1042 lxc_terminal_winsz(ts->stdinfd, ts->masterfd);
6834f805 1043 } else {
71ac3f07 1044 INFO("File descriptor %d does not refer to a terminal", stdinfd);
25964232 1045 }
b5159817
DE
1046
1047 ret = lxc_mainloop_open(&descr);
1048 if (ret) {
33b4b411
CB
1049 ERROR("Failed to create mainloop");
1050 goto sigwinch_fini;
b5159817
DE
1051 }
1052
341c2aed
CB
1053 if (ts->sigfd != -1) {
1054 ret = lxc_mainloop_add_handler(&descr, ts->sigfd,
9bafc8cb 1055 lxc_terminal_signalfd_cb, ts);
33b4b411 1056 if (ret < 0) {
0519b5cc 1057 ERROR("Failed to add signal handler to mainloop");
33b4b411 1058 goto close_mainloop;
341c2aed 1059 }
b5159817
DE
1060 }
1061
1062 ret = lxc_mainloop_add_handler(&descr, ts->stdinfd,
52f9292f 1063 lxc_terminal_stdin_cb, ts);
33b4b411
CB
1064 if (ret < 0) {
1065 ERROR("Failed to add stdin handler");
1066 goto close_mainloop;
b5159817
DE
1067 }
1068
1069 ret = lxc_mainloop_add_handler(&descr, ts->masterfd,
ee9102ff 1070 lxc_terminal_master_cb, ts);
33b4b411
CB
1071 if (ret < 0) {
1072 ERROR("Failed to add master handler");
1073 goto close_mainloop;
b5159817
DE
1074 }
1075
686df166
CB
1076 if (ts->escape >= 1) {
1077 fprintf(stderr,
1078 "\n"
6834f805
CB
1079 "Connected to tty %1$d\n"
1080 "Type <Ctrl+%2$c q> to exit the console, "
1081 "<Ctrl+%2$c Ctrl+%2$c> to enter Ctrl+%2$c itself\n",
1082 ttynum, 'a' + escape - 1);
686df166 1083 }
6834f805
CB
1084
1085 if (istty) {
1086 ret = lxc_setup_tios(stdinfd, &oldtios);
1087 if (ret < 0)
1088 goto close_mainloop;
1089 }
1090
025ed0f3 1091 ret = lxc_mainloop(&descr, -1);
33b4b411
CB
1092 if (ret < 0) {
1093 ERROR("The mainloop returned an error");
6834f805 1094 goto restore_tios;
b5159817
DE
1095 }
1096
1097 ret = 0;
1098
6834f805
CB
1099restore_tios:
1100 if (istty) {
1101 istty = tcsetattr(stdinfd, TCSAFLUSH, &oldtios);
1102 if (istty < 0)
a24c5678 1103 SYSWARN("Failed to restore terminal properties");
6834f805
CB
1104 }
1105
33b4b411 1106close_mainloop:
b5159817 1107 lxc_mainloop_close(&descr);
33b4b411
CB
1108
1109sigwinch_fini:
a8867251 1110 lxc_terminal_signal_fini(ts);
33b4b411
CB
1111
1112close_fds:
b5159817
DE
1113 close(masterfd);
1114 close(ttyfd);
33b4b411 1115
b5159817 1116 return ret;
63376d7d 1117}
e98affda 1118
cd0a2b2f 1119int lxc_make_controlling_terminal(int fd)
e98affda
CB
1120{
1121 int ret;
1122
1123 setsid();
1124
1125 ret = ioctl(fd, TIOCSCTTY, (char *)NULL);
1126 if (ret < 0)
1127 return -1;
1128
1129 return 0;
1130}
1131
d049f0e9 1132int lxc_terminal_prepare_login(int fd)
e98affda
CB
1133{
1134 int ret;
1135
cd0a2b2f 1136 ret = lxc_make_controlling_terminal(fd);
e98affda
CB
1137 if (ret < 0)
1138 return -1;
1139
ae6d3913 1140 ret = lxc_terminal_set_stdfds(fd);
e98affda
CB
1141 if (ret < 0)
1142 return -1;
1143
1144 if (fd > STDERR_FILENO)
1145 close(fd);
1146
1147 return 0;
1148}
1149
e9a55b51 1150void lxc_terminal_info_init(struct lxc_terminal_info *terminal)
e98affda 1151{
e9a55b51
CB
1152 terminal->name[0] = '\0';
1153 terminal->master = -EBADF;
1154 terminal->slave = -EBADF;
1155 terminal->busy = -1;
e98affda
CB
1156}
1157
e9a55b51 1158void lxc_terminal_init(struct lxc_terminal *terminal)
e98affda 1159{
e9a55b51
CB
1160 memset(terminal, 0, sizeof(*terminal));
1161 terminal->slave = -EBADF;
1162 terminal->master = -EBADF;
1163 terminal->peer = -EBADF;
1164 terminal->log_fd = -EBADF;
1165 lxc_terminal_info_init(&terminal->proxy);
e98affda
CB
1166}
1167
dcad02f8 1168void lxc_terminal_conf_free(struct lxc_terminal *terminal)
e98affda 1169{
2083d59d
CB
1170 free(terminal->log_path);
1171 free(terminal->path);
1172 if (terminal->buffer_size > 0 && terminal->ringbuf.addr)
1173 lxc_ringbuf_release(&terminal->ringbuf);
e98affda 1174}
7cfeddd7 1175
03700cab 1176int lxc_terminal_map_ids(struct lxc_conf *c, struct lxc_terminal *terminal)
7cfeddd7
CB
1177{
1178 int ret;
1179
1180 if (lxc_list_empty(&c->id_map))
1181 return 0;
1182
03700cab 1183 if (strcmp(terminal->name, "") == 0)
7cfeddd7
CB
1184 return 0;
1185
03700cab 1186 ret = chown_mapped_root(terminal->name, c);
7cfeddd7 1187 if (ret < 0) {
03700cab 1188 ERROR("Failed to chown terminal \"%s\"", terminal->name);
7cfeddd7
CB
1189 return -1;
1190 }
1191
03700cab 1192 TRACE("Chowned terminal \"%s\"", terminal->name);
7cfeddd7
CB
1193
1194 return 0;
1195}