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