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