]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/console.c
start: non-functional changes
[mirror_lxc.git] / src / lxc / console.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
9395937a
CB
24#include <errno.h>
25#include <fcntl.h>
b5159817 26#include <signal.h>
b0a33c1e 27#include <stdio.h>
e0dc0de7 28#include <stdlib.h>
8173e600 29#include <termios.h>
9395937a 30#include <unistd.h>
da41561c
CB
31#include <sys/epoll.h>
32#include <sys/types.h>
b0a33c1e 33
948955a2 34#include <lxc/lxccontainer.h>
f2363e38 35
9395937a
CB
36#include "af_unix.h"
37#include "caps.h"
38#include "commands.h"
00dbc43e 39#include "conf.h"
e827ff7e 40#include "config.h"
0d4137cc 41#include "console.h"
9395937a 42#include "log.h"
b5159817 43#include "lxclock.h"
9395937a
CB
44#include "mainloop.h"
45#include "start.h" /* for struct lxc_handler */
b5159817 46#include "utils.h"
36eb9bde 47
e827ff7e
SG
48#if HAVE_PTY_H
49#include <pty.h>
50#else
51#include <../include/openpty.h>
52#endif
53
732375f5
CB
54#define LXC_CONSOLE_BUFFER_SIZE 1024
55
f36e1654 56lxc_log_define(console, lxc);
36eb9bde 57
b5159817 58static struct lxc_list lxc_ttys;
724e753c 59
b5159817 60typedef void (*sighandler_t)(int);
b5159817 61
0519b5cc 62__attribute__((constructor)) void lxc_console_init(void)
b5159817
DE
63{
64 lxc_list_init(&lxc_ttys);
65}
724e753c 66
0d4137cc 67void lxc_console_winsz(int srcfd, int dstfd)
b5159817 68{
0519b5cc 69 int ret;
b5159817 70 struct winsize wsz;
0519b5cc
CB
71
72 if (!isatty(srcfd))
73 return;
74
75 ret = ioctl(srcfd, TIOCGWINSZ, &wsz);
76 if (ret < 0) {
77 WARN("Failed to get window size");
78 return;
724e753c 79 }
0519b5cc
CB
80
81 ret = ioctl(dstfd, TIOCSWINSZ, &wsz);
82 if (ret < 0)
83 WARN("Failed to set window size");
84 else
85 DEBUG("Set window size to %d columns and %d rows", wsz.ws_col,
86 wsz.ws_row);
87
88 return;
b5159817 89}
724e753c 90
b5159817
DE
91static void lxc_console_winch(struct lxc_tty_state *ts)
92{
93 lxc_console_winsz(ts->stdinfd, ts->masterfd);
0519b5cc 94
0d4137cc
CB
95 if (ts->winch_proxy)
96 lxc_cmd_console_winch(ts->winch_proxy, ts->winch_proxy_lxcpath);
724e753c
MN
97}
98
b5159817 99void lxc_console_sigwinch(int sig)
cd453b38 100{
025ed0f3
SH
101 struct lxc_list *it;
102 struct lxc_tty_state *ts;
cd453b38 103
025ed0f3
SH
104 lxc_list_for_each(it, &lxc_ttys) {
105 ts = it->elem;
106 lxc_console_winch(ts);
cd453b38 107 }
b5159817 108}
cd453b38 109
0519b5cc
CB
110int lxc_console_cb_signal_fd(int fd, uint32_t events, void *cbdata,
111 struct lxc_epoll_descr *descr)
b5159817 112{
1349e92e 113 ssize_t ret;
b5159817
DE
114 struct signalfd_siginfo siginfo;
115 struct lxc_tty_state *ts = cbdata;
116
1349e92e 117 ret = read(fd, &siginfo, sizeof(siginfo));
0d4137cc 118 if (ret < 0 || (size_t)ret < sizeof(siginfo)) {
0519b5cc 119 ERROR("Failed to read signal info");
b5159817 120 return -1;
cd453b38
DL
121 }
122
1349e92e
CB
123 if (siginfo.ssi_signo == SIGTERM) {
124 DEBUG("Received SIGTERM. Detaching from the console");
a529bc25 125 return LXC_MAINLOOP_CLOSE;
1349e92e
CB
126 }
127
128 if (siginfo.ssi_signo == SIGWINCH)
129 lxc_console_winch(ts);
130
b5159817
DE
131 return 0;
132}
133
0519b5cc 134struct lxc_tty_state *lxc_console_signal_init(int srcfd, int dstfd)
b5159817 135{
1349e92e 136 int ret;
0519b5cc 137 bool istty;
b5159817
DE
138 sigset_t mask;
139 struct lxc_tty_state *ts;
140
141 ts = malloc(sizeof(*ts));
142 if (!ts)
143 return NULL;
144
145 memset(ts, 0, sizeof(*ts));
341c2aed 146 ts->stdinfd = srcfd;
b5159817 147 ts->masterfd = dstfd;
341c2aed 148 ts->sigfd = -1;
b5159817 149
1349e92e
CB
150 sigemptyset(&mask);
151
0519b5cc
CB
152 istty = isatty(srcfd) == 1;
153 if (!istty) {
25964232 154 INFO("fd %d does not refer to a tty device", srcfd);
1349e92e
CB
155 } else {
156 /* Add tty to list to be scanned at SIGWINCH time. */
157 lxc_list_add_elem(&ts->node, ts);
158 lxc_list_add_tail(&lxc_ttys, &ts->node);
159 sigaddset(&mask, SIGWINCH);
25964232
LF
160 }
161
1349e92e
CB
162 /* Exit the mainloop cleanly on SIGTERM. */
163 sigaddset(&mask, SIGTERM);
b5159817 164
1349e92e
CB
165 ret = sigprocmask(SIG_BLOCK, &mask, &ts->oldmask);
166 if (ret < 0) {
167 WARN("Failed to block signals");
168 goto on_error;
b5159817
DE
169 }
170
171 ts->sigfd = signalfd(-1, &mask, 0);
172 if (ts->sigfd < 0) {
1349e92e 173 WARN("Failed to create signal fd");
341c2aed 174 sigprocmask(SIG_SETMASK, &ts->oldmask, NULL);
1349e92e 175 goto on_error;
b5159817
DE
176 }
177
1349e92e
CB
178 DEBUG("Created signal fd %d", ts->sigfd);
179 return ts;
180
181on_error:
182 ERROR("Failed to create signal fd");
183 if (ts->sigfd >= 0) {
184 close(ts->sigfd);
185 ts->sigfd = -1;
186 }
187 if (istty)
188 lxc_list_del(&ts->node);
b5159817 189 return ts;
cd453b38
DL
190}
191
0519b5cc 192void lxc_console_signal_fini(struct lxc_tty_state *ts)
63376d7d 193{
0e6da90b 194 if (ts->sigfd >= 0) {
b5159817 195 close(ts->sigfd);
1349e92e
CB
196
197 if (sigprocmask(SIG_SETMASK, &ts->oldmask, NULL) < 0)
198 WARN("%s - Failed to restore signal mask", strerror(errno));
0e6da90b 199 }
0d4137cc 200
1349e92e
CB
201 if (isatty(ts->stdinfd))
202 lxc_list_del(&ts->node);
203
b5159817
DE
204 free(ts);
205}
1560f6c9 206
a529bc25
CB
207int lxc_console_cb_con(int fd, uint32_t events, void *data,
208 struct lxc_epoll_descr *descr)
b5159817
DE
209{
210 struct lxc_console *console = (struct lxc_console *)data;
732375f5
CB
211 char buf[LXC_CONSOLE_BUFFER_SIZE];
212 int r, w, w_log, w_rbuf;
e0dc0de7 213
3e6580ec
CB
214 w = r = lxc_read_nointr(fd, buf, sizeof(buf));
215 if (r <= 0) {
732375f5 216 INFO("Console client on fd %d has exited", fd);
b5159817 217 lxc_mainloop_del_handler(descr, fd);
0b1e242b
L
218 if (fd == console->peer) {
219 if (console->tty_state) {
0519b5cc 220 lxc_console_signal_fini(console->tty_state);
0b1e242b
L
221 console->tty_state = NULL;
222 }
223 console->peer = -1;
224 close(fd);
225 return 0;
226 }
b5159817 227 close(fd);
a529bc25 228 return LXC_MAINLOOP_CLOSE;
33fcb7a0 229 }
63376d7d 230
b5159817 231 if (fd == console->peer)
3e6580ec 232 w = lxc_write_nointr(console->master, buf, r);
b5159817 233
732375f5 234 w_rbuf = w_log = 0;
b5159817 235 if (fd == console->master) {
732375f5 236 /* write to peer first */
b5159817 237 if (console->peer >= 0)
3e6580ec 238 w = lxc_write_nointr(console->peer, buf, r);
732375f5
CB
239
240 /* write to console ringbuffer */
28f3b1cd 241 if (console->buffer_size > 0)
732375f5
CB
242 w_rbuf = lxc_ringbuf_write(&console->ringbuf, buf, r);
243
244 /* write to console log */
245 if (console->log_fd >= 0)
246 w_log = lxc_write_nointr(console->log_fd, buf, r);
63376d7d
DL
247 }
248
b5159817 249 if (w != r)
732375f5
CB
250 WARN("Console short write r:%d != w:%d", r, w);
251
252 if (w_rbuf < 0)
253 TRACE("%s - Failed to write %d bytes to console ringbuffer",
254 strerror(-w_rbuf), r);
255
256 if (w_log < 0)
257 TRACE("Failed to write %d bytes to console log", r);
0d4137cc 258
b5159817
DE
259 return 0;
260}
261
a529bc25 262static int lxc_console_mainloop_add_peer(struct lxc_console *console)
b5159817 263{
a529bc25
CB
264 int ret;
265
b5159817 266 if (console->peer >= 0) {
a529bc25
CB
267 ret = lxc_mainloop_add_handler(console->descr, console->peer,
268 lxc_console_cb_con, console);
269 if (ret < 0) {
0519b5cc 270 WARN("Failed to add console peer handler to mainloop");
a529bc25
CB
271 return -1;
272 }
63376d7d
DL
273 }
274
a529bc25
CB
275 if (!console->tty_state || console->tty_state->sigfd < 0)
276 return 0;
277
278 ret = lxc_mainloop_add_handler(console->descr, console->tty_state->sigfd,
279 lxc_console_cb_signal_fd, console->tty_state);
280 if (ret < 0) {
281 WARN("Failed to add signal handler to mainloop");
282 return -1;
b5159817 283 }
a529bc25
CB
284
285 return 0;
b5159817
DE
286}
287
da41561c
CB
288extern int lxc_console_mainloop_add(struct lxc_epoll_descr *descr,
289 struct lxc_conf *conf)
b5159817 290{
a529bc25 291 int ret;
b5159817
DE
292 struct lxc_console *console = &conf->console;
293
294 if (!conf->rootfs.path) {
295 INFO("no rootfs, no console.");
296 return 0;
297 }
298
299 if (console->master < 0) {
300 INFO("no console");
301 return 0;
596a818d
DE
302 }
303
b5159817
DE
304 if (lxc_mainloop_add_handler(descr, console->master,
305 lxc_console_cb_con, console)) {
306 ERROR("failed to add to mainloop console handler for '%d'",
307 console->master);
308 return -1;
28a4b0e5
DL
309 }
310
b5159817
DE
311 /* we cache the descr so that we can add an fd to it when someone
312 * does attach to it in lxc_console_allocate()
313 */
314 console->descr = descr;
a529bc25
CB
315 ret = lxc_console_mainloop_add_peer(console);
316 if (ret < 0)
317 return -1;
cd453b38 318
b5159817
DE
319 return 0;
320}
28a4b0e5 321
0d4137cc 322int lxc_setup_tios(int fd, struct termios *oldtios)
b5159817
DE
323{
324 struct termios newtios;
e0dc0de7 325
b5159817
DE
326 if (!isatty(fd)) {
327 ERROR("'%d' is not a tty", fd);
328 return -1;
e0dc0de7
DL
329 }
330
b5159817
DE
331 /* Get current termios */
332 if (tcgetattr(fd, oldtios)) {
e0dc0de7 333 SYSERROR("failed to get current terminal settings");
b5159817 334 return -1;
e0dc0de7
DL
335 }
336
4dc96430
TJ
337 /* ensure we don't end up in an endless loop:
338 * The kernel might fire SIGTTOU while an
339 * ioctl() in tcsetattr() is executed. When the ioctl()
340 * is resumed and retries, the signal handler interrupts it again.
341 */
342 signal (SIGTTIN, SIG_IGN);
343 signal (SIGTTOU, SIG_IGN);
344
b5159817 345 newtios = *oldtios;
e0dc0de7 346
a7c97a40
CB
347 /* We use the same settings that ssh does. */
348 newtios.c_iflag |= IGNPAR;
349 newtios.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF);
350#ifdef IUCLC
351 newtios.c_iflag &= ~IUCLC;
352#endif
4dc96430 353 newtios.c_lflag &= ~(TOSTOP | ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL);
a7c97a40
CB
354#ifdef IEXTEN
355 newtios.c_lflag &= ~IEXTEN;
356#endif
d3893399 357 newtios.c_oflag &= ~OPOST;
b5159817
DE
358 newtios.c_cc[VMIN] = 1;
359 newtios.c_cc[VTIME] = 0;
e0dc0de7 360
a7c97a40 361 /* Set new attributes. */
b5159817 362 if (tcsetattr(fd, TCSAFLUSH, &newtios)) {
e0dc0de7 363 ERROR("failed to set new terminal settings");
b5159817 364 return -1;
e0dc0de7
DL
365 }
366
63376d7d 367 return 0;
b5159817 368}
e0dc0de7 369
b5159817
DE
370static void lxc_console_peer_proxy_free(struct lxc_console *console)
371{
0e6da90b 372 if (console->tty_state) {
0519b5cc 373 lxc_console_signal_fini(console->tty_state);
b5159817
DE
374 console->tty_state = NULL;
375 }
376 close(console->peerpty.master);
377 close(console->peerpty.slave);
378 console->peerpty.master = -1;
379 console->peerpty.slave = -1;
380 console->peerpty.busy = -1;
381 console->peerpty.name[0] = '\0';
596a818d 382 console->peer = -1;
b5159817 383}
596a818d 384
b5159817
DE
385static int lxc_console_peer_proxy_alloc(struct lxc_console *console, int sockfd)
386{
387 struct termios oldtermio;
388 struct lxc_tty_state *ts;
025ed0f3 389 int ret;
b5159817
DE
390
391 if (console->master < 0) {
392 ERROR("console not set up");
393 return -1;
394 }
395 if (console->peerpty.busy != -1 || console->peer != -1) {
396 NOTICE("console already in use");
397 return -1;
398 }
399 if (console->tty_state) {
400 ERROR("console already has tty_state");
401 return -1;
596a818d
DE
402 }
403
b5159817
DE
404 /* this is the proxy pty that will be given to the client, and that
405 * the real pty master will send to / recv from
406 */
025ed0f3
SH
407 process_lock();
408 ret = openpty(&console->peerpty.master, &console->peerpty.slave,
409 console->peerpty.name, NULL, NULL);
410 process_unlock();
411 if (ret) {
b5159817
DE
412 SYSERROR("failed to create proxy pty");
413 return -1;
414 }
596a818d 415
0d4137cc 416 if (lxc_setup_tios(console->peerpty.slave, &oldtermio) < 0)
b5159817
DE
417 goto err1;
418
0519b5cc 419 ts = lxc_console_signal_init(console->peerpty.master, console->master);
b5159817
DE
420 if (!ts)
421 goto err1;
422
423 console->tty_state = ts;
424 console->peer = console->peerpty.slave;
425 console->peerpty.busy = sockfd;
a529bc25
CB
426 ret = lxc_console_mainloop_add_peer(console);
427 if (ret < 0)
428 goto err1;
b5159817 429
0059379f 430 DEBUG("%d %s peermaster:%d sockfd:%d", lxc_raw_getpid(), __FUNCTION__, console->peerpty.master, sockfd);
b5159817
DE
431 return 0;
432
433err1:
434 lxc_console_peer_proxy_free(console);
63376d7d
DL
435 return -1;
436}
437
b5159817
DE
438int lxc_console_allocate(struct lxc_conf *conf, int sockfd, int *ttyreq)
439{
440 int masterfd = -1, ttynum;
441 struct lxc_tty_info *tty_info = &conf->tty_info;
442 struct lxc_console *console = &conf->console;
443
b5159817
DE
444 if (*ttyreq == 0) {
445 if (lxc_console_peer_proxy_alloc(console, sockfd) < 0)
446 goto out;
447 masterfd = console->peerpty.master;
448 goto out;
449 }
450
451 if (*ttyreq > 0) {
452 if (*ttyreq > tty_info->nbtty)
453 goto out;
454
455 if (tty_info->pty_info[*ttyreq - 1].busy)
456 goto out;
457
458 /* the requested tty is available */
459 ttynum = *ttyreq;
460 goto out_tty;
461 }
462
463 /* search for next available tty, fixup index tty1 => [0] */
0d4137cc
CB
464 for (ttynum = 1; ttynum <= tty_info->nbtty && tty_info->pty_info[ttynum - 1].busy; ttynum++)
465 ;
b5159817
DE
466
467 /* we didn't find any available slot for tty */
468 if (ttynum > tty_info->nbtty)
469 goto out;
470
471 *ttyreq = ttynum;
472
473out_tty:
474 tty_info->pty_info[ttynum - 1].busy = sockfd;
475 masterfd = tty_info->pty_info[ttynum - 1].master;
476out:
b5159817
DE
477 return masterfd;
478}
479
b5159817 480void lxc_console_free(struct lxc_conf *conf, int fd)
63376d7d 481{
b5159817
DE
482 int i;
483 struct lxc_tty_info *tty_info = &conf->tty_info;
484 struct lxc_console *console = &conf->console;
485
b5159817
DE
486 for (i = 0; i < tty_info->nbtty; i++) {
487 if (tty_info->pty_info[i].busy == fd)
488 tty_info->pty_info[i].busy = 0;
489 }
490
491 if (console->peerpty.busy == fd) {
492 lxc_mainloop_del_handler(console->descr, console->peerpty.slave);
493 lxc_console_peer_proxy_free(console);
494 }
b5159817
DE
495}
496
467c7ff3 497static int lxc_console_peer_default(struct lxc_console *console)
b5159817
DE
498{
499 struct lxc_tty_state *ts;
500 const char *path = console->path;
467c7ff3
CB
501 int fd;
502 int ret = 0;
b5159817 503
467c7ff3
CB
504 /* If no console was given, try current controlling terminal, there
505 * won't be one if we were started as a daemon (-d).
b5159817
DE
506 */
507 if (!path && !access("/dev/tty", F_OK)) {
b5159817
DE
508 fd = open("/dev/tty", O_RDWR);
509 if (fd >= 0) {
510 close(fd);
511 path = "/dev/tty";
512 }
513 }
514
467c7ff3
CB
515 if (!path) {
516 errno = ENOTTY;
517 DEBUG("process does not have a controlling terminal");
b5159817 518 goto out;
467c7ff3 519 }
b5159817 520
a63fade5 521 console->peer = lxc_unpriv(open(path, O_RDWR | O_CLOEXEC));
467c7ff3 522 if (console->peer < 0) {
a63fade5 523 ERROR("Failed to open \"%s\": %s", path, strerror(errno));
467c7ff3
CB
524 return -ENOTTY;
525 }
526 DEBUG("using \"%s\" as peer tty device", path);
b5159817 527
467c7ff3
CB
528 if (!isatty(console->peer)) {
529 ERROR("file descriptor for file \"%s\" does not refer to a tty device", path);
530 goto on_error1;
531 }
b5159817 532
0519b5cc 533 ts = lxc_console_signal_init(console->peer, console->master);
b5159817 534 console->tty_state = ts;
341c2aed 535 if (!ts) {
0519b5cc 536 WARN("Failed to install signal handler");
467c7ff3 537 goto on_error1;
341c2aed 538 }
b5159817
DE
539
540 lxc_console_winsz(console->peer, console->master);
541
542 console->tios = malloc(sizeof(*console->tios));
543 if (!console->tios) {
544 SYSERROR("failed to allocate memory");
467c7ff3 545 goto on_error1;
b5159817
DE
546 }
547
0d4137cc 548 if (lxc_setup_tios(console->peer, console->tios) < 0)
467c7ff3
CB
549 goto on_error2;
550 else
551 goto out;
b5159817 552
467c7ff3 553on_error2:
b5159817
DE
554 free(console->tios);
555 console->tios = NULL;
467c7ff3
CB
556
557on_error1:
b5159817
DE
558 close(console->peer);
559 console->peer = -1;
467c7ff3
CB
560 ret = -ENOTTY;
561
b5159817 562out:
467c7ff3 563 return ret;
b5159817
DE
564}
565
63b74cda 566int lxc_console_write_ringbuffer(struct lxc_console *console)
40117d05 567{
40117d05
CB
568 char *r_addr;
569 ssize_t ret;
570 uint64_t used;
571 struct lxc_ringbuf *buf = &console->ringbuf;
572
3a784510 573 if (!console->buffer_log_file)
40117d05
CB
574 return 0;
575
576 used = lxc_ringbuf_used(buf);
577 if (used == 0)
578 return 0;
579
40117d05 580 r_addr = lxc_ringbuf_get_read_addr(buf);
a0309168 581 ret = lxc_write_nointr(console->buffer_log_file_fd, r_addr, used);
40117d05 582 if (ret < 0)
63b74cda 583 return -EIO;
40117d05
CB
584
585 return 0;
586}
587
b5159817
DE
588void lxc_console_delete(struct lxc_console *console)
589{
69629c82
CB
590 int ret;
591
40117d05
CB
592 ret = lxc_console_write_ringbuffer(console);
593 if (ret < 0)
594 WARN("Failed to write console log to disk");
595
69629c82
CB
596 if (console->tios && console->peer >= 0) {
597 ret = tcsetattr(console->peer, TCSAFLUSH, console->tios);
598 if (ret < 0)
599 WARN("%s - Failed to set old terminal settings", strerror(errno));
600 }
596a818d
DE
601 free(console->tios);
602 console->tios = NULL;
603
bc9724f7
CB
604 if (console->peer >= 0)
605 close(console->peer);
025ed0f3 606 console->peer = -1;
bc9724f7
CB
607
608 if (console->master >= 0)
609 close(console->master);
596a818d 610 console->master = -1;
bc9724f7
CB
611
612 if (console->slave >= 0)
613 close(console->slave);
596a818d 614 console->slave = -1;
bc9724f7
CB
615
616 if (console->log_fd >= 0)
617 close(console->log_fd);
025ed0f3 618 console->log_fd = -1;
bc9724f7 619
a0309168
CB
620 if (console->buffer_log_file_fd >= 0)
621 close(console->buffer_log_file_fd);
622 console->buffer_log_file_fd = -1;
623}
624
625/* This is the console ringbuffer log file. Please note that the console
626 * ringbuffer log file is (implementation wise not content wise) independent of
627 * the console log file.
628 */
629static int lxc_console_create_ringbuf_log_file(struct lxc_console *console)
630{
631 if (!console->buffer_log_file)
632 return 0;
633
634 console->buffer_log_file_fd = lxc_unpriv(open(console->buffer_log_file,
635 O_CLOEXEC | O_RDWR | O_CREAT | O_TRUNC, 0600));
636 if (console->buffer_log_file_fd < 0) {
637 SYSERROR("Failed to open console ringbuffer log file \"%s\"",
638 console->buffer_log_file);
639 return -EIO;
640 }
641
642 DEBUG("Using \"%s\" as console ringbuffer log file", console->buffer_log_file);
643 return 0;
63376d7d
DL
644}
645
3b988b33
CB
646/**
647 * Note that this function needs to run before the mainloop starts. Since we
648 * register a handler for the console's masterfd when we create the mainloop
649 * the console handler needs to see an allocated ringbuffer.
650 */
a0309168 651static int lxc_console_create_ringbuf(struct lxc_console *console)
3b988b33
CB
652{
653 int ret;
654 struct lxc_ringbuf *buf = &console->ringbuf;
28f3b1cd 655 uint64_t size = console->buffer_size;
3b988b33
CB
656
657 /* no ringbuffer previously allocated and no ringbuffer requested */
658 if (!buf->addr && size <= 0)
659 return 0;
660
661 /* ringbuffer allocated but no new ringbuffer requested */
662 if (buf->addr && size <= 0) {
663 lxc_ringbuf_release(buf);
664 buf->addr = NULL;
665 buf->r_off = 0;
666 buf->w_off = 0;
667 buf->size = 0;
668 TRACE("Deallocated console ringbuffer");
669 return 0;
670 }
671
672 if (size <= 0)
673 return 0;
674
675 /* check wether the requested size for the ringbuffer has changed */
676 if (buf->addr && buf->size != size) {
677 TRACE("Console ringbuffer size changed from %" PRIu64
678 " to %" PRIu64 " bytes. Deallocating console ringbuffer",
679 buf->size, size);
680 lxc_ringbuf_release(buf);
681 }
682
683 ret = lxc_ringbuf_create(buf, size);
684 if (ret < 0) {
685 ERROR("Failed to setup %" PRIu64 " byte console ringbuffer", size);
686 return -1;
687 }
688
689 TRACE("Allocated %" PRIu64 " byte console ringbuffer", size);
690 return 0;
691}
692
a0309168
CB
693/**
694 * This is the console log file. Please note that the console log file is
695 * (implementation wise not content wise) independent of the console ringbuffer.
696 */
966b9ecd 697int lxc_console_create_log_file(struct lxc_console *console)
a0309168
CB
698{
699 if (!console->log_path)
700 return 0;
701
702 console->log_fd = lxc_unpriv(open(console->log_path, O_CLOEXEC | O_RDWR | O_CREAT | O_APPEND, 0600));
703 if (console->log_fd < 0) {
704 SYSERROR("Failed to open console log file \"%s\"", console->log_path);
705 return -1;
706 }
707
708 DEBUG("Using \"%s\" as console log file", console->log_path);
709 return 0;
710}
711
5777fe90 712int lxc_pty_create(struct lxc_console *console)
63376d7d 713{
69629c82 714 int ret, saved_errno;
b5159817 715
025ed0f3 716 process_lock();
5777fe90
CB
717 ret = openpty(&console->master, &console->slave, console->name, NULL,
718 NULL);
69629c82 719 saved_errno = errno;
025ed0f3 720 process_unlock();
467c7ff3 721 if (ret < 0) {
69629c82 722 ERROR("%s - Failed to allocate a pty", strerror(saved_errno));
b5159817
DE
723 return -1;
724 }
725
69629c82
CB
726 ret = fcntl(console->master, F_SETFD, FD_CLOEXEC);
727 if (ret < 0) {
728 SYSERROR("Failed to set FD_CLOEXEC flag on console master");
b5159817
DE
729 goto err;
730 }
731
69629c82
CB
732 ret = fcntl(console->slave, F_SETFD, FD_CLOEXEC);
733 if (ret < 0) {
734 SYSERROR("Failed to set FD_CLOEXEC flag on console slave");
b5159817
DE
735 goto err;
736 }
737
467c7ff3
CB
738 ret = lxc_console_peer_default(console);
739 if (ret < 0) {
69629c82 740 ERROR("Failed to allocate a peer pty device");
467c7ff3
CB
741 goto err;
742 }
b5159817 743
5777fe90
CB
744 return 0;
745
746err:
747 lxc_console_delete(console);
748 return -ENODEV;
749}
750
751int lxc_console_create(struct lxc_conf *conf)
752{
753 int ret;
754 struct lxc_console *console = &conf->console;
755
756 if (!conf->rootfs.path) {
757 INFO("Container does not have a rootfs. The console will be "
758 "shared with the host");
759 return 0;
760 }
761
762 if (console->path && !strcmp(console->path, "none")) {
763 INFO("No console was requested");
764 return 0;
765 }
766
767 ret = lxc_pty_create(console);
768 if (ret < 0)
769 return -1;
770
a0309168
CB
771 /* create console log file */
772 ret = lxc_console_create_log_file(console);
773 if (ret < 0)
774 goto err;
775
776 /* create console ringbuffer */
777 ret = lxc_console_create_ringbuf(console);
778 if (ret < 0)
779 goto err;
b5159817 780
a0309168
CB
781 /* create console ringbuffer log file */
782 ret = lxc_console_create_ringbuf_log_file(console);
3b988b33
CB
783 if (ret < 0)
784 goto err;
785
b5159817
DE
786 return 0;
787
788err:
789 lxc_console_delete(console);
69629c82 790 return -ENODEV;
b5159817
DE
791}
792
39a78bbe 793int lxc_console_set_stdfds(int fd)
0d9acb99 794{
39a78bbe 795 if (fd < 0)
0d9acb99 796 return 0;
b5159817 797
39a78bbe
CB
798 if (isatty(STDIN_FILENO))
799 if (dup2(fd, STDIN_FILENO) < 0) {
800 SYSERROR("failed to duplicate stdin.");
801 return -1;
802 }
803
804 if (isatty(STDOUT_FILENO))
805 if (dup2(fd, STDOUT_FILENO) < 0) {
806 SYSERROR("failed to duplicate stdout.");
807 return -1;
808 }
809
810 if (isatty(STDERR_FILENO))
811 if (dup2(fd, STDERR_FILENO) < 0) {
812 SYSERROR("failed to duplicate stderr.");
813 return -1;
814 }
815
0d9acb99
DE
816 return 0;
817}
b5159817 818
0d4137cc
CB
819int lxc_console_cb_tty_stdin(int fd, uint32_t events, void *cbdata,
820 struct lxc_epoll_descr *descr)
b5159817
DE
821{
822 struct lxc_tty_state *ts = cbdata;
823 char c;
824
97bc2422 825 if (fd != ts->stdinfd)
a529bc25 826 return LXC_MAINLOOP_CLOSE;
97bc2422 827
e66b6c96 828 if (lxc_read_nointr(ts->stdinfd, &c, 1) <= 0)
a529bc25 829 return LXC_MAINLOOP_CLOSE;
63376d7d 830
525e2117 831 if (ts->escape >= 1) {
014d5e1e
CB
832 /* we want to exit the console with Ctrl+a q */
833 if (c == ts->escape && !ts->saw_escape) {
834 ts->saw_escape = 1;
835 return 0;
836 }
5c294060 837
014d5e1e 838 if (c == 'q' && ts->saw_escape)
a529bc25 839 return LXC_MAINLOOP_CLOSE;
014d5e1e
CB
840
841 ts->saw_escape = 0;
842 }
63376d7d 843
e66b6c96 844 if (lxc_write_nointr(ts->masterfd, &c, 1) <= 0)
a529bc25 845 return LXC_MAINLOOP_CLOSE;
b5159817 846
63376d7d
DL
847 return 0;
848}
849
0d4137cc
CB
850int lxc_console_cb_tty_master(int fd, uint32_t events, void *cbdata,
851 struct lxc_epoll_descr *descr)
63376d7d 852{
b5159817 853 struct lxc_tty_state *ts = cbdata;
732375f5 854 char buf[LXC_CONSOLE_BUFFER_SIZE];
0d4137cc 855 int r, w;
63376d7d 856
97bc2422 857 if (fd != ts->masterfd)
a529bc25 858 return LXC_MAINLOOP_CLOSE;
97bc2422 859
e66b6c96
CB
860 r = lxc_read_nointr(fd, buf, sizeof(buf));
861 if (r <= 0)
a529bc25 862 return LXC_MAINLOOP_CLOSE;
1560f6c9 863
e66b6c96
CB
864 w = lxc_write_nointr(ts->stdoutfd, buf, r);
865 if (w <= 0) {
a529bc25 866 return LXC_MAINLOOP_CLOSE;
e66b6c96 867 } else if (w != r) {
a529bc25 868 SYSERROR("Failed to write");
b5159817 869 return 1;
f78a1f32
DL
870 }
871
b5159817
DE
872 return 0;
873}
874
875int lxc_console_getfd(struct lxc_container *c, int *ttynum, int *masterfd)
876{
877 return lxc_cmd_console(c->name, ttynum, masterfd, c->config_path);
878}
879
880int lxc_console(struct lxc_container *c, int ttynum,
881 int stdinfd, int stdoutfd, int stderrfd,
882 int escape)
883{
884 int ret, ttyfd, masterfd;
885 struct lxc_epoll_descr descr;
886 struct termios oldtios;
887 struct lxc_tty_state *ts;
25964232 888 int istty = 0;
b5159817 889
b5159817 890 ttyfd = lxc_cmd_console(c->name, &ttynum, &masterfd, c->config_path);
6834f805
CB
891 if (ttyfd < 0)
892 return -1;
b5159817
DE
893
894 ret = setsid();
33b4b411
CB
895 if (ret < 0)
896 TRACE("Process is already group leader");
b5159817 897
0519b5cc 898 ts = lxc_console_signal_init(stdinfd, masterfd);
b5159817
DE
899 if (!ts) {
900 ret = -1;
33b4b411 901 goto close_fds;
b5159817
DE
902 }
903 ts->escape = escape;
904 ts->winch_proxy = c->name;
905 ts->winch_proxy_lxcpath = c->config_path;
3b975060 906 ts->stdoutfd = stdoutfd;
b5159817 907
6834f805 908 istty = isatty(stdinfd);
25964232
LF
909 if (istty) {
910 lxc_console_winsz(stdinfd, masterfd);
911 lxc_cmd_console_winch(ts->winch_proxy, ts->winch_proxy_lxcpath);
6834f805
CB
912 } else {
913 INFO("File descriptor %d does not refer to a tty device", stdinfd);
25964232 914 }
b5159817
DE
915
916 ret = lxc_mainloop_open(&descr);
917 if (ret) {
33b4b411
CB
918 ERROR("Failed to create mainloop");
919 goto sigwinch_fini;
b5159817
DE
920 }
921
341c2aed
CB
922 if (ts->sigfd != -1) {
923 ret = lxc_mainloop_add_handler(&descr, ts->sigfd,
0519b5cc 924 lxc_console_cb_signal_fd, ts);
33b4b411 925 if (ret < 0) {
0519b5cc 926 ERROR("Failed to add signal handler to mainloop");
33b4b411 927 goto close_mainloop;
341c2aed 928 }
b5159817
DE
929 }
930
931 ret = lxc_mainloop_add_handler(&descr, ts->stdinfd,
932 lxc_console_cb_tty_stdin, ts);
33b4b411
CB
933 if (ret < 0) {
934 ERROR("Failed to add stdin handler");
935 goto close_mainloop;
b5159817
DE
936 }
937
938 ret = lxc_mainloop_add_handler(&descr, ts->masterfd,
939 lxc_console_cb_tty_master, ts);
33b4b411
CB
940 if (ret < 0) {
941 ERROR("Failed to add master handler");
942 goto close_mainloop;
b5159817
DE
943 }
944
686df166
CB
945 if (ts->escape >= 1) {
946 fprintf(stderr,
947 "\n"
6834f805
CB
948 "Connected to tty %1$d\n"
949 "Type <Ctrl+%2$c q> to exit the console, "
950 "<Ctrl+%2$c Ctrl+%2$c> to enter Ctrl+%2$c itself\n",
951 ttynum, 'a' + escape - 1);
686df166 952 }
6834f805
CB
953
954 if (istty) {
955 ret = lxc_setup_tios(stdinfd, &oldtios);
956 if (ret < 0)
957 goto close_mainloop;
958 }
959
025ed0f3 960 ret = lxc_mainloop(&descr, -1);
33b4b411
CB
961 if (ret < 0) {
962 ERROR("The mainloop returned an error");
6834f805 963 goto restore_tios;
b5159817
DE
964 }
965
966 ret = 0;
967
6834f805
CB
968restore_tios:
969 if (istty) {
970 istty = tcsetattr(stdinfd, TCSAFLUSH, &oldtios);
971 if (istty < 0)
972 WARN("%s - Failed to restore terminal properties",
973 strerror(errno));
974 }
975
33b4b411 976close_mainloop:
b5159817 977 lxc_mainloop_close(&descr);
33b4b411
CB
978
979sigwinch_fini:
0519b5cc 980 lxc_console_signal_fini(ts);
33b4b411
CB
981
982close_fds:
b5159817
DE
983 close(masterfd);
984 close(ttyfd);
33b4b411 985
b5159817 986 return ret;
63376d7d 987}