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