]> 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
30a33fbd
CB
288int lxc_console_mainloop_add(struct lxc_epoll_descr *descr,
289 struct lxc_console *console)
b5159817 290{
a529bc25 291 int ret;
b5159817
DE
292
293 if (console->master < 0) {
294 INFO("no console");
295 return 0;
596a818d
DE
296 }
297
30a33fbd
CB
298 ret = lxc_mainloop_add_handler(descr, console->master,
299 lxc_console_cb_con, console);
300 if (ret < 0) {
301 ERROR("Failed to add handler for %d to mainloop", console->master);
b5159817 302 return -1;
28a4b0e5
DL
303 }
304
30a33fbd
CB
305 /* We cache the descr so that we can add an fd to it when someone
306 * does attach to it in lxc_console_allocate().
b5159817
DE
307 */
308 console->descr = descr;
a529bc25
CB
309 ret = lxc_console_mainloop_add_peer(console);
310 if (ret < 0)
311 return -1;
cd453b38 312
b5159817
DE
313 return 0;
314}
28a4b0e5 315
0d4137cc 316int lxc_setup_tios(int fd, struct termios *oldtios)
b5159817
DE
317{
318 struct termios newtios;
e0dc0de7 319
b5159817
DE
320 if (!isatty(fd)) {
321 ERROR("'%d' is not a tty", fd);
322 return -1;
e0dc0de7
DL
323 }
324
b5159817
DE
325 /* Get current termios */
326 if (tcgetattr(fd, oldtios)) {
e0dc0de7 327 SYSERROR("failed to get current terminal settings");
b5159817 328 return -1;
e0dc0de7
DL
329 }
330
4dc96430
TJ
331 /* ensure we don't end up in an endless loop:
332 * The kernel might fire SIGTTOU while an
333 * ioctl() in tcsetattr() is executed. When the ioctl()
334 * is resumed and retries, the signal handler interrupts it again.
335 */
336 signal (SIGTTIN, SIG_IGN);
337 signal (SIGTTOU, SIG_IGN);
338
b5159817 339 newtios = *oldtios;
e0dc0de7 340
a7c97a40
CB
341 /* We use the same settings that ssh does. */
342 newtios.c_iflag |= IGNPAR;
343 newtios.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF);
344#ifdef IUCLC
345 newtios.c_iflag &= ~IUCLC;
346#endif
4dc96430 347 newtios.c_lflag &= ~(TOSTOP | ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL);
a7c97a40
CB
348#ifdef IEXTEN
349 newtios.c_lflag &= ~IEXTEN;
350#endif
d3893399 351 newtios.c_oflag &= ~OPOST;
b5159817
DE
352 newtios.c_cc[VMIN] = 1;
353 newtios.c_cc[VTIME] = 0;
e0dc0de7 354
a7c97a40 355 /* Set new attributes. */
b5159817 356 if (tcsetattr(fd, TCSAFLUSH, &newtios)) {
e0dc0de7 357 ERROR("failed to set new terminal settings");
b5159817 358 return -1;
e0dc0de7
DL
359 }
360
63376d7d 361 return 0;
b5159817 362}
e0dc0de7 363
b5159817
DE
364static void lxc_console_peer_proxy_free(struct lxc_console *console)
365{
0e6da90b 366 if (console->tty_state) {
0519b5cc 367 lxc_console_signal_fini(console->tty_state);
b5159817
DE
368 console->tty_state = NULL;
369 }
370 close(console->peerpty.master);
371 close(console->peerpty.slave);
372 console->peerpty.master = -1;
373 console->peerpty.slave = -1;
374 console->peerpty.busy = -1;
375 console->peerpty.name[0] = '\0';
596a818d 376 console->peer = -1;
b5159817 377}
596a818d 378
b5159817
DE
379static int lxc_console_peer_proxy_alloc(struct lxc_console *console, int sockfd)
380{
381 struct termios oldtermio;
382 struct lxc_tty_state *ts;
025ed0f3 383 int ret;
b5159817
DE
384
385 if (console->master < 0) {
386 ERROR("console not set up");
387 return -1;
388 }
389 if (console->peerpty.busy != -1 || console->peer != -1) {
390 NOTICE("console already in use");
391 return -1;
392 }
393 if (console->tty_state) {
394 ERROR("console already has tty_state");
395 return -1;
596a818d
DE
396 }
397
b5159817
DE
398 /* this is the proxy pty that will be given to the client, and that
399 * the real pty master will send to / recv from
400 */
025ed0f3
SH
401 process_lock();
402 ret = openpty(&console->peerpty.master, &console->peerpty.slave,
403 console->peerpty.name, NULL, NULL);
404 process_unlock();
405 if (ret) {
b5159817
DE
406 SYSERROR("failed to create proxy pty");
407 return -1;
408 }
596a818d 409
0d4137cc 410 if (lxc_setup_tios(console->peerpty.slave, &oldtermio) < 0)
b5159817
DE
411 goto err1;
412
0519b5cc 413 ts = lxc_console_signal_init(console->peerpty.master, console->master);
b5159817
DE
414 if (!ts)
415 goto err1;
416
417 console->tty_state = ts;
418 console->peer = console->peerpty.slave;
419 console->peerpty.busy = sockfd;
a529bc25
CB
420 ret = lxc_console_mainloop_add_peer(console);
421 if (ret < 0)
422 goto err1;
b5159817 423
0059379f 424 DEBUG("%d %s peermaster:%d sockfd:%d", lxc_raw_getpid(), __FUNCTION__, console->peerpty.master, sockfd);
b5159817
DE
425 return 0;
426
427err1:
428 lxc_console_peer_proxy_free(console);
63376d7d
DL
429 return -1;
430}
431
b5159817
DE
432int lxc_console_allocate(struct lxc_conf *conf, int sockfd, int *ttyreq)
433{
434 int masterfd = -1, ttynum;
435 struct lxc_tty_info *tty_info = &conf->tty_info;
436 struct lxc_console *console = &conf->console;
437
b5159817
DE
438 if (*ttyreq == 0) {
439 if (lxc_console_peer_proxy_alloc(console, sockfd) < 0)
440 goto out;
441 masterfd = console->peerpty.master;
442 goto out;
443 }
444
445 if (*ttyreq > 0) {
446 if (*ttyreq > tty_info->nbtty)
447 goto out;
448
449 if (tty_info->pty_info[*ttyreq - 1].busy)
450 goto out;
451
452 /* the requested tty is available */
453 ttynum = *ttyreq;
454 goto out_tty;
455 }
456
457 /* search for next available tty, fixup index tty1 => [0] */
0d4137cc
CB
458 for (ttynum = 1; ttynum <= tty_info->nbtty && tty_info->pty_info[ttynum - 1].busy; ttynum++)
459 ;
b5159817
DE
460
461 /* we didn't find any available slot for tty */
462 if (ttynum > tty_info->nbtty)
463 goto out;
464
465 *ttyreq = ttynum;
466
467out_tty:
468 tty_info->pty_info[ttynum - 1].busy = sockfd;
469 masterfd = tty_info->pty_info[ttynum - 1].master;
470out:
b5159817
DE
471 return masterfd;
472}
473
b5159817 474void lxc_console_free(struct lxc_conf *conf, int fd)
63376d7d 475{
b5159817
DE
476 int i;
477 struct lxc_tty_info *tty_info = &conf->tty_info;
478 struct lxc_console *console = &conf->console;
479
b5159817
DE
480 for (i = 0; i < tty_info->nbtty; i++) {
481 if (tty_info->pty_info[i].busy == fd)
482 tty_info->pty_info[i].busy = 0;
483 }
484
485 if (console->peerpty.busy == fd) {
486 lxc_mainloop_del_handler(console->descr, console->peerpty.slave);
487 lxc_console_peer_proxy_free(console);
488 }
b5159817
DE
489}
490
467c7ff3 491static int lxc_console_peer_default(struct lxc_console *console)
b5159817
DE
492{
493 struct lxc_tty_state *ts;
494 const char *path = console->path;
467c7ff3
CB
495 int fd;
496 int ret = 0;
b5159817 497
467c7ff3
CB
498 /* If no console was given, try current controlling terminal, there
499 * won't be one if we were started as a daemon (-d).
b5159817
DE
500 */
501 if (!path && !access("/dev/tty", F_OK)) {
b5159817
DE
502 fd = open("/dev/tty", O_RDWR);
503 if (fd >= 0) {
504 close(fd);
505 path = "/dev/tty";
506 }
507 }
508
467c7ff3
CB
509 if (!path) {
510 errno = ENOTTY;
511 DEBUG("process does not have a controlling terminal");
b5159817 512 goto out;
467c7ff3 513 }
b5159817 514
a63fade5 515 console->peer = lxc_unpriv(open(path, O_RDWR | O_CLOEXEC));
467c7ff3 516 if (console->peer < 0) {
a63fade5 517 ERROR("Failed to open \"%s\": %s", path, strerror(errno));
467c7ff3
CB
518 return -ENOTTY;
519 }
520 DEBUG("using \"%s\" as peer tty device", path);
b5159817 521
467c7ff3
CB
522 if (!isatty(console->peer)) {
523 ERROR("file descriptor for file \"%s\" does not refer to a tty device", path);
524 goto on_error1;
525 }
b5159817 526
0519b5cc 527 ts = lxc_console_signal_init(console->peer, console->master);
b5159817 528 console->tty_state = ts;
341c2aed 529 if (!ts) {
0519b5cc 530 WARN("Failed to install signal handler");
467c7ff3 531 goto on_error1;
341c2aed 532 }
b5159817
DE
533
534 lxc_console_winsz(console->peer, console->master);
535
536 console->tios = malloc(sizeof(*console->tios));
537 if (!console->tios) {
538 SYSERROR("failed to allocate memory");
467c7ff3 539 goto on_error1;
b5159817
DE
540 }
541
0d4137cc 542 if (lxc_setup_tios(console->peer, console->tios) < 0)
467c7ff3
CB
543 goto on_error2;
544 else
545 goto out;
b5159817 546
467c7ff3 547on_error2:
b5159817
DE
548 free(console->tios);
549 console->tios = NULL;
467c7ff3
CB
550
551on_error1:
b5159817
DE
552 close(console->peer);
553 console->peer = -1;
467c7ff3
CB
554 ret = -ENOTTY;
555
b5159817 556out:
467c7ff3 557 return ret;
b5159817
DE
558}
559
63b74cda 560int lxc_console_write_ringbuffer(struct lxc_console *console)
40117d05 561{
40117d05
CB
562 char *r_addr;
563 ssize_t ret;
564 uint64_t used;
565 struct lxc_ringbuf *buf = &console->ringbuf;
566
3a784510 567 if (!console->buffer_log_file)
40117d05
CB
568 return 0;
569
570 used = lxc_ringbuf_used(buf);
571 if (used == 0)
572 return 0;
573
40117d05 574 r_addr = lxc_ringbuf_get_read_addr(buf);
a0309168 575 ret = lxc_write_nointr(console->buffer_log_file_fd, r_addr, used);
40117d05 576 if (ret < 0)
63b74cda 577 return -EIO;
40117d05
CB
578
579 return 0;
580}
581
b5159817
DE
582void lxc_console_delete(struct lxc_console *console)
583{
69629c82
CB
584 int ret;
585
40117d05
CB
586 ret = lxc_console_write_ringbuffer(console);
587 if (ret < 0)
588 WARN("Failed to write console log to disk");
589
69629c82
CB
590 if (console->tios && console->peer >= 0) {
591 ret = tcsetattr(console->peer, TCSAFLUSH, console->tios);
592 if (ret < 0)
593 WARN("%s - Failed to set old terminal settings", strerror(errno));
594 }
596a818d
DE
595 free(console->tios);
596 console->tios = NULL;
597
bc9724f7
CB
598 if (console->peer >= 0)
599 close(console->peer);
025ed0f3 600 console->peer = -1;
bc9724f7
CB
601
602 if (console->master >= 0)
603 close(console->master);
596a818d 604 console->master = -1;
bc9724f7
CB
605
606 if (console->slave >= 0)
607 close(console->slave);
596a818d 608 console->slave = -1;
bc9724f7
CB
609
610 if (console->log_fd >= 0)
611 close(console->log_fd);
025ed0f3 612 console->log_fd = -1;
bc9724f7 613
a0309168
CB
614 if (console->buffer_log_file_fd >= 0)
615 close(console->buffer_log_file_fd);
616 console->buffer_log_file_fd = -1;
617}
618
619/* This is the console ringbuffer log file. Please note that the console
620 * ringbuffer log file is (implementation wise not content wise) independent of
621 * the console log file.
622 */
623static int lxc_console_create_ringbuf_log_file(struct lxc_console *console)
624{
625 if (!console->buffer_log_file)
626 return 0;
627
628 console->buffer_log_file_fd = lxc_unpriv(open(console->buffer_log_file,
629 O_CLOEXEC | O_RDWR | O_CREAT | O_TRUNC, 0600));
630 if (console->buffer_log_file_fd < 0) {
631 SYSERROR("Failed to open console ringbuffer log file \"%s\"",
632 console->buffer_log_file);
633 return -EIO;
634 }
635
636 DEBUG("Using \"%s\" as console ringbuffer log file", console->buffer_log_file);
637 return 0;
63376d7d
DL
638}
639
3b988b33
CB
640/**
641 * Note that this function needs to run before the mainloop starts. Since we
642 * register a handler for the console's masterfd when we create the mainloop
643 * the console handler needs to see an allocated ringbuffer.
644 */
a0309168 645static int lxc_console_create_ringbuf(struct lxc_console *console)
3b988b33
CB
646{
647 int ret;
648 struct lxc_ringbuf *buf = &console->ringbuf;
28f3b1cd 649 uint64_t size = console->buffer_size;
3b988b33
CB
650
651 /* no ringbuffer previously allocated and no ringbuffer requested */
652 if (!buf->addr && size <= 0)
653 return 0;
654
655 /* ringbuffer allocated but no new ringbuffer requested */
656 if (buf->addr && size <= 0) {
657 lxc_ringbuf_release(buf);
658 buf->addr = NULL;
659 buf->r_off = 0;
660 buf->w_off = 0;
661 buf->size = 0;
662 TRACE("Deallocated console ringbuffer");
663 return 0;
664 }
665
666 if (size <= 0)
667 return 0;
668
669 /* check wether the requested size for the ringbuffer has changed */
670 if (buf->addr && buf->size != size) {
671 TRACE("Console ringbuffer size changed from %" PRIu64
672 " to %" PRIu64 " bytes. Deallocating console ringbuffer",
673 buf->size, size);
674 lxc_ringbuf_release(buf);
675 }
676
677 ret = lxc_ringbuf_create(buf, size);
678 if (ret < 0) {
679 ERROR("Failed to setup %" PRIu64 " byte console ringbuffer", size);
680 return -1;
681 }
682
683 TRACE("Allocated %" PRIu64 " byte console ringbuffer", size);
684 return 0;
685}
686
a0309168
CB
687/**
688 * This is the console log file. Please note that the console log file is
689 * (implementation wise not content wise) independent of the console ringbuffer.
690 */
966b9ecd 691int lxc_console_create_log_file(struct lxc_console *console)
a0309168
CB
692{
693 if (!console->log_path)
694 return 0;
695
696 console->log_fd = lxc_unpriv(open(console->log_path, O_CLOEXEC | O_RDWR | O_CREAT | O_APPEND, 0600));
697 if (console->log_fd < 0) {
698 SYSERROR("Failed to open console log file \"%s\"", console->log_path);
699 return -1;
700 }
701
702 DEBUG("Using \"%s\" as console log file", console->log_path);
703 return 0;
704}
705
5777fe90 706int lxc_pty_create(struct lxc_console *console)
63376d7d 707{
69629c82 708 int ret, saved_errno;
b5159817 709
025ed0f3 710 process_lock();
5777fe90
CB
711 ret = openpty(&console->master, &console->slave, console->name, NULL,
712 NULL);
69629c82 713 saved_errno = errno;
025ed0f3 714 process_unlock();
467c7ff3 715 if (ret < 0) {
69629c82 716 ERROR("%s - Failed to allocate a pty", strerror(saved_errno));
b5159817
DE
717 return -1;
718 }
719
69629c82
CB
720 ret = fcntl(console->master, F_SETFD, FD_CLOEXEC);
721 if (ret < 0) {
722 SYSERROR("Failed to set FD_CLOEXEC flag on console master");
b5159817
DE
723 goto err;
724 }
725
69629c82
CB
726 ret = fcntl(console->slave, F_SETFD, FD_CLOEXEC);
727 if (ret < 0) {
728 SYSERROR("Failed to set FD_CLOEXEC flag on console slave");
b5159817
DE
729 goto err;
730 }
731
467c7ff3
CB
732 ret = lxc_console_peer_default(console);
733 if (ret < 0) {
69629c82 734 ERROR("Failed to allocate a peer pty device");
467c7ff3
CB
735 goto err;
736 }
b5159817 737
5777fe90
CB
738 return 0;
739
740err:
741 lxc_console_delete(console);
742 return -ENODEV;
743}
744
745int lxc_console_create(struct lxc_conf *conf)
746{
747 int ret;
748 struct lxc_console *console = &conf->console;
749
750 if (!conf->rootfs.path) {
751 INFO("Container does not have a rootfs. The console will be "
752 "shared with the host");
753 return 0;
754 }
755
756 if (console->path && !strcmp(console->path, "none")) {
757 INFO("No console was requested");
758 return 0;
759 }
760
761 ret = lxc_pty_create(console);
762 if (ret < 0)
763 return -1;
764
a0309168
CB
765 /* create console log file */
766 ret = lxc_console_create_log_file(console);
767 if (ret < 0)
768 goto err;
769
770 /* create console ringbuffer */
771 ret = lxc_console_create_ringbuf(console);
772 if (ret < 0)
773 goto err;
b5159817 774
a0309168
CB
775 /* create console ringbuffer log file */
776 ret = lxc_console_create_ringbuf_log_file(console);
3b988b33
CB
777 if (ret < 0)
778 goto err;
779
b5159817
DE
780 return 0;
781
782err:
783 lxc_console_delete(console);
69629c82 784 return -ENODEV;
b5159817
DE
785}
786
39a78bbe 787int lxc_console_set_stdfds(int fd)
0d9acb99 788{
39a78bbe 789 if (fd < 0)
0d9acb99 790 return 0;
b5159817 791
39a78bbe
CB
792 if (isatty(STDIN_FILENO))
793 if (dup2(fd, STDIN_FILENO) < 0) {
794 SYSERROR("failed to duplicate stdin.");
795 return -1;
796 }
797
798 if (isatty(STDOUT_FILENO))
799 if (dup2(fd, STDOUT_FILENO) < 0) {
800 SYSERROR("failed to duplicate stdout.");
801 return -1;
802 }
803
804 if (isatty(STDERR_FILENO))
805 if (dup2(fd, STDERR_FILENO) < 0) {
806 SYSERROR("failed to duplicate stderr.");
807 return -1;
808 }
809
0d9acb99
DE
810 return 0;
811}
b5159817 812
0d4137cc
CB
813int lxc_console_cb_tty_stdin(int fd, uint32_t events, void *cbdata,
814 struct lxc_epoll_descr *descr)
b5159817
DE
815{
816 struct lxc_tty_state *ts = cbdata;
817 char c;
818
97bc2422 819 if (fd != ts->stdinfd)
a529bc25 820 return LXC_MAINLOOP_CLOSE;
97bc2422 821
e66b6c96 822 if (lxc_read_nointr(ts->stdinfd, &c, 1) <= 0)
a529bc25 823 return LXC_MAINLOOP_CLOSE;
63376d7d 824
525e2117 825 if (ts->escape >= 1) {
014d5e1e
CB
826 /* we want to exit the console with Ctrl+a q */
827 if (c == ts->escape && !ts->saw_escape) {
828 ts->saw_escape = 1;
829 return 0;
830 }
5c294060 831
014d5e1e 832 if (c == 'q' && ts->saw_escape)
a529bc25 833 return LXC_MAINLOOP_CLOSE;
014d5e1e
CB
834
835 ts->saw_escape = 0;
836 }
63376d7d 837
e66b6c96 838 if (lxc_write_nointr(ts->masterfd, &c, 1) <= 0)
a529bc25 839 return LXC_MAINLOOP_CLOSE;
b5159817 840
63376d7d
DL
841 return 0;
842}
843
0d4137cc
CB
844int lxc_console_cb_tty_master(int fd, uint32_t events, void *cbdata,
845 struct lxc_epoll_descr *descr)
63376d7d 846{
b5159817 847 struct lxc_tty_state *ts = cbdata;
732375f5 848 char buf[LXC_CONSOLE_BUFFER_SIZE];
0d4137cc 849 int r, w;
63376d7d 850
97bc2422 851 if (fd != ts->masterfd)
a529bc25 852 return LXC_MAINLOOP_CLOSE;
97bc2422 853
e66b6c96
CB
854 r = lxc_read_nointr(fd, buf, sizeof(buf));
855 if (r <= 0)
a529bc25 856 return LXC_MAINLOOP_CLOSE;
1560f6c9 857
e66b6c96
CB
858 w = lxc_write_nointr(ts->stdoutfd, buf, r);
859 if (w <= 0) {
a529bc25 860 return LXC_MAINLOOP_CLOSE;
e66b6c96 861 } else if (w != r) {
a529bc25 862 SYSERROR("Failed to write");
b5159817 863 return 1;
f78a1f32
DL
864 }
865
b5159817
DE
866 return 0;
867}
868
869int lxc_console_getfd(struct lxc_container *c, int *ttynum, int *masterfd)
870{
871 return lxc_cmd_console(c->name, ttynum, masterfd, c->config_path);
872}
873
874int lxc_console(struct lxc_container *c, int ttynum,
875 int stdinfd, int stdoutfd, int stderrfd,
876 int escape)
877{
878 int ret, ttyfd, masterfd;
879 struct lxc_epoll_descr descr;
880 struct termios oldtios;
881 struct lxc_tty_state *ts;
25964232 882 int istty = 0;
b5159817 883
b5159817 884 ttyfd = lxc_cmd_console(c->name, &ttynum, &masterfd, c->config_path);
6834f805
CB
885 if (ttyfd < 0)
886 return -1;
b5159817
DE
887
888 ret = setsid();
33b4b411
CB
889 if (ret < 0)
890 TRACE("Process is already group leader");
b5159817 891
0519b5cc 892 ts = lxc_console_signal_init(stdinfd, masterfd);
b5159817
DE
893 if (!ts) {
894 ret = -1;
33b4b411 895 goto close_fds;
b5159817
DE
896 }
897 ts->escape = escape;
898 ts->winch_proxy = c->name;
899 ts->winch_proxy_lxcpath = c->config_path;
3b975060 900 ts->stdoutfd = stdoutfd;
b5159817 901
6834f805 902 istty = isatty(stdinfd);
25964232
LF
903 if (istty) {
904 lxc_console_winsz(stdinfd, masterfd);
905 lxc_cmd_console_winch(ts->winch_proxy, ts->winch_proxy_lxcpath);
6834f805
CB
906 } else {
907 INFO("File descriptor %d does not refer to a tty device", stdinfd);
25964232 908 }
b5159817
DE
909
910 ret = lxc_mainloop_open(&descr);
911 if (ret) {
33b4b411
CB
912 ERROR("Failed to create mainloop");
913 goto sigwinch_fini;
b5159817
DE
914 }
915
341c2aed
CB
916 if (ts->sigfd != -1) {
917 ret = lxc_mainloop_add_handler(&descr, ts->sigfd,
0519b5cc 918 lxc_console_cb_signal_fd, ts);
33b4b411 919 if (ret < 0) {
0519b5cc 920 ERROR("Failed to add signal handler to mainloop");
33b4b411 921 goto close_mainloop;
341c2aed 922 }
b5159817
DE
923 }
924
925 ret = lxc_mainloop_add_handler(&descr, ts->stdinfd,
926 lxc_console_cb_tty_stdin, ts);
33b4b411
CB
927 if (ret < 0) {
928 ERROR("Failed to add stdin handler");
929 goto close_mainloop;
b5159817
DE
930 }
931
932 ret = lxc_mainloop_add_handler(&descr, ts->masterfd,
933 lxc_console_cb_tty_master, ts);
33b4b411
CB
934 if (ret < 0) {
935 ERROR("Failed to add master handler");
936 goto close_mainloop;
b5159817
DE
937 }
938
686df166
CB
939 if (ts->escape >= 1) {
940 fprintf(stderr,
941 "\n"
6834f805
CB
942 "Connected to tty %1$d\n"
943 "Type <Ctrl+%2$c q> to exit the console, "
944 "<Ctrl+%2$c Ctrl+%2$c> to enter Ctrl+%2$c itself\n",
945 ttynum, 'a' + escape - 1);
686df166 946 }
6834f805
CB
947
948 if (istty) {
949 ret = lxc_setup_tios(stdinfd, &oldtios);
950 if (ret < 0)
951 goto close_mainloop;
952 }
953
025ed0f3 954 ret = lxc_mainloop(&descr, -1);
33b4b411
CB
955 if (ret < 0) {
956 ERROR("The mainloop returned an error");
6834f805 957 goto restore_tios;
b5159817
DE
958 }
959
960 ret = 0;
961
6834f805
CB
962restore_tios:
963 if (istty) {
964 istty = tcsetattr(stdinfd, TCSAFLUSH, &oldtios);
965 if (istty < 0)
966 WARN("%s - Failed to restore terminal properties",
967 strerror(errno));
968 }
969
33b4b411 970close_mainloop:
b5159817 971 lxc_mainloop_close(&descr);
33b4b411
CB
972
973sigwinch_fini:
0519b5cc 974 lxc_console_signal_fini(ts);
33b4b411
CB
975
976close_fds:
b5159817
DE
977 close(masterfd);
978 close(ttyfd);
33b4b411 979
b5159817 980 return ret;
63376d7d 981}
e98affda
CB
982
983int lxc_make_controlling_pty(int fd)
984{
985 int ret;
986
987 setsid();
988
989 ret = ioctl(fd, TIOCSCTTY, (char *)NULL);
990 if (ret < 0)
991 return -1;
992
993 return 0;
994}
995
996int lxc_login_pty(int fd)
997{
998 int ret;
999
1000 ret = lxc_make_controlling_pty(fd);
1001 if (ret < 0)
1002 return -1;
1003
1004 ret = lxc_console_set_stdfds(fd);
1005 if (ret < 0)
1006 return -1;
1007
1008 if (fd > STDERR_FILENO)
1009 close(fd);
1010
1011 return 0;
1012}
1013
1014void lxc_pty_info_init(struct lxc_pty_info *pty)
1015{
1016 pty->name[0] = '\0';
1017 pty->master = -EBADF;
1018 pty->slave = -EBADF;
1019 pty->busy = -1;
1020}
1021
1022void lxc_pty_init(struct lxc_console *pty)
1023{
1024 memset(pty, 0, sizeof(*pty));
1025 pty->slave = -EBADF;
1026 pty->master = -EBADF;
1027 pty->peer = -EBADF;
1028 pty->log_fd = -EBADF;
1029 pty->buffer_log_file_fd = -EBADF;
1030 lxc_pty_info_init(&pty->peerpty);
1031}
1032
1033void lxc_pty_conf_free(struct lxc_console *console)
1034{
1035 free(console->buffer_log_file);
1036 free(console->log_path);
1037 free(console->path);
1038 if (console->buffer_size > 0 && console->ringbuf.addr)
1039 lxc_ringbuf_release(&console->ringbuf);
1040}
7cfeddd7
CB
1041
1042int lxc_pty_map_ids(struct lxc_conf *c, struct lxc_console *pty)
1043{
1044 int ret;
1045
1046 if (lxc_list_empty(&c->id_map))
1047 return 0;
1048
1049 ret = strcmp(pty->name, "");
1050 if (ret == 0)
1051 return 0;
1052
1053 ret = chown_mapped_root(pty->name, c);
1054 if (ret < 0) {
1055 ERROR("Failed to chown \"%s\"", pty->name);
1056 return -1;
1057 }
1058
1059 TRACE("Chowned \"%s\"", pty->name);
1060
1061 return 0;
1062}