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