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