]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/console.c
use lxc_read_nointr() and lxc_write_nointr()
[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
b5159817 24#include <assert.h>
9395937a
CB
25#include <errno.h>
26#include <fcntl.h>
b5159817 27#include <signal.h>
b0a33c1e 28#include <stdio.h>
e0dc0de7 29#include <stdlib.h>
8173e600 30#include <termios.h>
9395937a 31#include <unistd.h>
da41561c
CB
32#include <sys/epoll.h>
33#include <sys/types.h>
b0a33c1e 34
948955a2 35#include <lxc/lxccontainer.h>
f2363e38 36
9395937a
CB
37#include "af_unix.h"
38#include "caps.h"
39#include "commands.h"
00dbc43e 40#include "conf.h"
e827ff7e 41#include "config.h"
0d4137cc 42#include "console.h"
9395937a 43#include "log.h"
b5159817 44#include "lxclock.h"
9395937a
CB
45#include "mainloop.h"
46#include "start.h" /* for struct lxc_handler */
b5159817 47#include "utils.h"
36eb9bde 48
e827ff7e
SG
49#if HAVE_PTY_H
50#include <pty.h>
51#else
52#include <../include/openpty.h>
53#endif
54
36eb9bde
CLG
55lxc_log_define(lxc_console, lxc);
56
b5159817 57static struct lxc_list lxc_ttys;
724e753c 58
b5159817 59typedef void (*sighandler_t)(int);
b5159817
DE
60
61__attribute__((constructor))
62void lxc_console_init(void)
63{
64 lxc_list_init(&lxc_ttys);
65}
724e753c 66
0d4137cc 67void lxc_console_winsz(int srcfd, int dstfd)
b5159817
DE
68{
69 struct winsize wsz;
70 if (isatty(srcfd) && ioctl(srcfd, TIOCGWINSZ, &wsz) == 0) {
71 DEBUG("set winsz dstfd:%d cols:%d rows:%d", dstfd,
72 wsz.ws_col, wsz.ws_row);
73 ioctl(dstfd, TIOCSWINSZ, &wsz);
724e753c 74 }
b5159817 75}
724e753c 76
b5159817
DE
77static void lxc_console_winch(struct lxc_tty_state *ts)
78{
79 lxc_console_winsz(ts->stdinfd, ts->masterfd);
0d4137cc
CB
80 if (ts->winch_proxy)
81 lxc_cmd_console_winch(ts->winch_proxy, ts->winch_proxy_lxcpath);
724e753c
MN
82}
83
b5159817 84void lxc_console_sigwinch(int sig)
cd453b38 85{
025ed0f3
SH
86 struct lxc_list *it;
87 struct lxc_tty_state *ts;
cd453b38 88
025ed0f3
SH
89 lxc_list_for_each(it, &lxc_ttys) {
90 ts = it->elem;
91 lxc_console_winch(ts);
cd453b38 92 }
b5159817 93}
cd453b38 94
0d4137cc
CB
95int lxc_console_cb_sigwinch_fd(int fd, uint32_t events, void *cbdata,
96 struct lxc_epoll_descr *descr)
b5159817
DE
97{
98 struct signalfd_siginfo siginfo;
99 struct lxc_tty_state *ts = cbdata;
100
0d4137cc
CB
101 ssize_t ret = read(fd, &siginfo, sizeof(siginfo));
102 if (ret < 0 || (size_t)ret < sizeof(siginfo)) {
b5159817
DE
103 ERROR("failed to read signal info");
104 return -1;
cd453b38
DL
105 }
106
b5159817
DE
107 lxc_console_winch(ts);
108 return 0;
109}
110
0d4137cc 111struct lxc_tty_state *lxc_console_sigwinch_init(int srcfd, int dstfd)
b5159817
DE
112{
113 sigset_t mask;
114 struct lxc_tty_state *ts;
115
116 ts = malloc(sizeof(*ts));
117 if (!ts)
118 return NULL;
119
120 memset(ts, 0, sizeof(*ts));
341c2aed 121 ts->stdinfd = srcfd;
b5159817 122 ts->masterfd = dstfd;
341c2aed 123 ts->sigfd = -1;
b5159817
DE
124
125 /* add tty to list to be scanned at SIGWINCH time */
126 lxc_list_add_elem(&ts->node, ts);
127 lxc_list_add_tail(&lxc_ttys, &ts->node);
128
129 sigemptyset(&mask);
130 sigaddset(&mask, SIGWINCH);
131 if (sigprocmask(SIG_BLOCK, &mask, &ts->oldmask)) {
341c2aed
CB
132 SYSERROR("failed to block SIGWINCH.");
133 ts->sigfd = -1;
134 return ts;
b5159817
DE
135 }
136
137 ts->sigfd = signalfd(-1, &mask, 0);
138 if (ts->sigfd < 0) {
341c2aed
CB
139 SYSERROR("failed to get signalfd.");
140 sigprocmask(SIG_SETMASK, &ts->oldmask, NULL);
141 ts->sigfd = -1;
142 return ts;
b5159817
DE
143 }
144
145 DEBUG("%d got SIGWINCH fd %d", getpid(), ts->sigfd);
b5159817 146 return ts;
cd453b38
DL
147}
148
0d4137cc 149void lxc_console_sigwinch_fini(struct lxc_tty_state *ts)
63376d7d 150{
0d4137cc 151 if (ts->sigfd >= 0)
b5159817 152 close(ts->sigfd);
0d4137cc 153
b5159817
DE
154 lxc_list_del(&ts->node);
155 sigprocmask(SIG_SETMASK, &ts->oldmask, NULL);
156 free(ts);
157}
1560f6c9 158
84c92abd 159static int lxc_console_cb_con(int fd, uint32_t events, void *data,
b5159817
DE
160 struct lxc_epoll_descr *descr)
161{
162 struct lxc_console *console = (struct lxc_console *)data;
163 char buf[1024];
3e6580ec 164 int r, w;
e0dc0de7 165
3e6580ec
CB
166 w = r = lxc_read_nointr(fd, buf, sizeof(buf));
167 if (r <= 0) {
b5159817
DE
168 INFO("console client on fd %d has exited", fd);
169 lxc_mainloop_del_handler(descr, fd);
170 close(fd);
3e6580ec 171 return 1;
33fcb7a0 172 }
63376d7d 173
b5159817 174 if (fd == console->peer)
3e6580ec 175 w = lxc_write_nointr(console->master, buf, r);
b5159817
DE
176
177 if (fd == console->master) {
178 if (console->log_fd >= 0)
3e6580ec 179 w = lxc_write_nointr(console->log_fd, buf, r);
b5159817
DE
180
181 if (console->peer >= 0)
3e6580ec 182 w = lxc_write_nointr(console->peer, buf, r);
63376d7d
DL
183 }
184
b5159817
DE
185 if (w != r)
186 WARN("console short write r:%d w:%d", r, w);
0d4137cc 187
b5159817
DE
188 return 0;
189}
190
191static void lxc_console_mainloop_add_peer(struct lxc_console *console)
192{
193 if (console->peer >= 0) {
194 if (lxc_mainloop_add_handler(console->descr, console->peer,
195 lxc_console_cb_con, console))
196 WARN("console peer not added to mainloop");
63376d7d
DL
197 }
198
341c2aed 199 if (console->tty_state && console->tty_state->sigfd != -1) {
b5159817
DE
200 if (lxc_mainloop_add_handler(console->descr,
201 console->tty_state->sigfd,
202 lxc_console_cb_sigwinch_fd,
203 console->tty_state)) {
204 WARN("failed to add to mainloop SIGWINCH handler for '%d'",
205 console->tty_state->sigfd);
596a818d 206 }
b5159817
DE
207 }
208}
209
da41561c
CB
210extern int lxc_console_mainloop_add(struct lxc_epoll_descr *descr,
211 struct lxc_conf *conf)
b5159817 212{
b5159817
DE
213 struct lxc_console *console = &conf->console;
214
37903589
SH
215 if (conf->is_execute) {
216 INFO("no console for lxc-execute.");
217 return 0;
218 }
219
b5159817
DE
220 if (!conf->rootfs.path) {
221 INFO("no rootfs, no console.");
222 return 0;
223 }
224
225 if (console->master < 0) {
226 INFO("no console");
227 return 0;
596a818d
DE
228 }
229
b5159817
DE
230 if (lxc_mainloop_add_handler(descr, console->master,
231 lxc_console_cb_con, console)) {
232 ERROR("failed to add to mainloop console handler for '%d'",
233 console->master);
234 return -1;
28a4b0e5
DL
235 }
236
b5159817
DE
237 /* we cache the descr so that we can add an fd to it when someone
238 * does attach to it in lxc_console_allocate()
239 */
240 console->descr = descr;
241 lxc_console_mainloop_add_peer(console);
cd453b38 242
b5159817
DE
243 return 0;
244}
28a4b0e5 245
0d4137cc 246int lxc_setup_tios(int fd, struct termios *oldtios)
b5159817
DE
247{
248 struct termios newtios;
e0dc0de7 249
b5159817
DE
250 if (!isatty(fd)) {
251 ERROR("'%d' is not a tty", fd);
252 return -1;
e0dc0de7
DL
253 }
254
b5159817
DE
255 /* Get current termios */
256 if (tcgetattr(fd, oldtios)) {
e0dc0de7 257 SYSERROR("failed to get current terminal settings");
b5159817 258 return -1;
e0dc0de7
DL
259 }
260
b5159817 261 newtios = *oldtios;
e0dc0de7
DL
262
263 /* Remove the echo characters and signal reception, the echo
b5159817
DE
264 * will be done with master proxying */
265 newtios.c_iflag &= ~IGNBRK;
266 newtios.c_iflag &= BRKINT;
267 newtios.c_lflag &= ~(ECHO|ICANON|ISIG);
268 newtios.c_cc[VMIN] = 1;
269 newtios.c_cc[VTIME] = 0;
e0dc0de7
DL
270
271 /* Set new attributes */
b5159817 272 if (tcsetattr(fd, TCSAFLUSH, &newtios)) {
e0dc0de7 273 ERROR("failed to set new terminal settings");
b5159817 274 return -1;
e0dc0de7
DL
275 }
276
63376d7d 277 return 0;
b5159817 278}
e0dc0de7 279
b5159817
DE
280static void lxc_console_peer_proxy_free(struct lxc_console *console)
281{
341c2aed 282 if (console->tty_state && console->tty_state->sigfd != -1) {
b5159817
DE
283 lxc_console_sigwinch_fini(console->tty_state);
284 console->tty_state = NULL;
285 }
286 close(console->peerpty.master);
287 close(console->peerpty.slave);
288 console->peerpty.master = -1;
289 console->peerpty.slave = -1;
290 console->peerpty.busy = -1;
291 console->peerpty.name[0] = '\0';
596a818d 292 console->peer = -1;
b5159817 293}
596a818d 294
b5159817
DE
295static int lxc_console_peer_proxy_alloc(struct lxc_console *console, int sockfd)
296{
297 struct termios oldtermio;
298 struct lxc_tty_state *ts;
025ed0f3 299 int ret;
b5159817
DE
300
301 if (console->master < 0) {
302 ERROR("console not set up");
303 return -1;
304 }
305 if (console->peerpty.busy != -1 || console->peer != -1) {
306 NOTICE("console already in use");
307 return -1;
308 }
309 if (console->tty_state) {
310 ERROR("console already has tty_state");
311 return -1;
596a818d
DE
312 }
313
b5159817
DE
314 /* this is the proxy pty that will be given to the client, and that
315 * the real pty master will send to / recv from
316 */
025ed0f3
SH
317 process_lock();
318 ret = openpty(&console->peerpty.master, &console->peerpty.slave,
319 console->peerpty.name, NULL, NULL);
320 process_unlock();
321 if (ret) {
b5159817
DE
322 SYSERROR("failed to create proxy pty");
323 return -1;
324 }
596a818d 325
0d4137cc 326 if (lxc_setup_tios(console->peerpty.slave, &oldtermio) < 0)
b5159817
DE
327 goto err1;
328
329 ts = lxc_console_sigwinch_init(console->peerpty.master, console->master);
330 if (!ts)
331 goto err1;
332
333 console->tty_state = ts;
334 console->peer = console->peerpty.slave;
335 console->peerpty.busy = sockfd;
336 lxc_console_mainloop_add_peer(console);
337
338 DEBUG("%d %s peermaster:%d sockfd:%d", getpid(), __FUNCTION__, console->peerpty.master, sockfd);
339 return 0;
340
341err1:
342 lxc_console_peer_proxy_free(console);
63376d7d
DL
343 return -1;
344}
345
b5159817
DE
346int lxc_console_allocate(struct lxc_conf *conf, int sockfd, int *ttyreq)
347{
348 int masterfd = -1, ttynum;
349 struct lxc_tty_info *tty_info = &conf->tty_info;
350 struct lxc_console *console = &conf->console;
351
b5159817
DE
352 if (*ttyreq == 0) {
353 if (lxc_console_peer_proxy_alloc(console, sockfd) < 0)
354 goto out;
355 masterfd = console->peerpty.master;
356 goto out;
357 }
358
359 if (*ttyreq > 0) {
360 if (*ttyreq > tty_info->nbtty)
361 goto out;
362
363 if (tty_info->pty_info[*ttyreq - 1].busy)
364 goto out;
365
366 /* the requested tty is available */
367 ttynum = *ttyreq;
368 goto out_tty;
369 }
370
371 /* search for next available tty, fixup index tty1 => [0] */
0d4137cc
CB
372 for (ttynum = 1; ttynum <= tty_info->nbtty && tty_info->pty_info[ttynum - 1].busy; ttynum++)
373 ;
b5159817
DE
374
375 /* we didn't find any available slot for tty */
376 if (ttynum > tty_info->nbtty)
377 goto out;
378
379 *ttyreq = ttynum;
380
381out_tty:
382 tty_info->pty_info[ttynum - 1].busy = sockfd;
383 masterfd = tty_info->pty_info[ttynum - 1].master;
384out:
b5159817
DE
385 return masterfd;
386}
387
b5159817 388void lxc_console_free(struct lxc_conf *conf, int fd)
63376d7d 389{
b5159817
DE
390 int i;
391 struct lxc_tty_info *tty_info = &conf->tty_info;
392 struct lxc_console *console = &conf->console;
393
b5159817
DE
394 for (i = 0; i < tty_info->nbtty; i++) {
395 if (tty_info->pty_info[i].busy == fd)
396 tty_info->pty_info[i].busy = 0;
397 }
398
399 if (console->peerpty.busy == fd) {
400 lxc_mainloop_del_handler(console->descr, console->peerpty.slave);
401 lxc_console_peer_proxy_free(console);
402 }
b5159817
DE
403}
404
405static void lxc_console_peer_default(struct lxc_console *console)
406{
407 struct lxc_tty_state *ts;
408 const char *path = console->path;
409
410 /* if no console was given, try current controlling terminal, there
411 * won't be one if we were started as a daemon (-d)
412 */
413 if (!path && !access("/dev/tty", F_OK)) {
414 int fd;
415 fd = open("/dev/tty", O_RDWR);
416 if (fd >= 0) {
417 close(fd);
418 path = "/dev/tty";
419 }
420 }
421
422 if (!path)
423 goto out;
424
425 DEBUG("opening %s for console peer", path);
426 console->peer = lxc_unpriv(open(path, O_CLOEXEC | O_RDWR | O_CREAT |
427 O_APPEND, 0600));
428 if (console->peer < 0)
429 goto out;
430
431 DEBUG("using '%s' as console", path);
432
433 if (!isatty(console->peer))
0d9acb99 434 goto err1;
b5159817
DE
435
436 ts = lxc_console_sigwinch_init(console->peer, console->master);
b5159817 437 console->tty_state = ts;
341c2aed
CB
438 if (!ts) {
439 WARN("Unable to install SIGWINCH");
440 goto err1;
441 }
b5159817
DE
442
443 lxc_console_winsz(console->peer, console->master);
444
445 console->tios = malloc(sizeof(*console->tios));
446 if (!console->tios) {
447 SYSERROR("failed to allocate memory");
448 goto err1;
449 }
450
0d4137cc 451 if (lxc_setup_tios(console->peer, console->tios) < 0)
b5159817
DE
452 goto err2;
453
454 return;
455
456err2:
457 free(console->tios);
458 console->tios = NULL;
459err1:
460 close(console->peer);
461 console->peer = -1;
462out:
463 DEBUG("no console peer");
341c2aed 464 return;
b5159817
DE
465}
466
467void lxc_console_delete(struct lxc_console *console)
468{
469 if (console->tios && console->peer >= 0 &&
e0dc0de7
DL
470 tcsetattr(console->peer, TCSAFLUSH, console->tios))
471 WARN("failed to set old terminal settings");
596a818d
DE
472 free(console->tios);
473 console->tios = NULL;
474
475 close(console->peer);
025ed0f3
SH
476 close(console->master);
477 close(console->slave);
478 if (console->log_fd >= 0)
596a818d 479 close(console->log_fd);
596a818d 480
025ed0f3 481 console->peer = -1;
596a818d 482 console->master = -1;
596a818d 483 console->slave = -1;
025ed0f3 484 console->log_fd = -1;
63376d7d
DL
485}
486
b5159817 487int lxc_console_create(struct lxc_conf *conf)
63376d7d 488{
b5159817 489 struct lxc_console *console = &conf->console;
025ed0f3 490 int ret;
63376d7d 491
37903589
SH
492 if (conf->is_execute) {
493 INFO("no console for lxc-execute.");
494 return 0;
495 }
496
b5159817
DE
497 if (!conf->rootfs.path)
498 return 0;
499
500 if (console->path && !strcmp(console->path, "none"))
501 return 0;
502
025ed0f3
SH
503 process_lock();
504 ret = openpty(&console->master, &console->slave,
505 console->name, NULL, NULL);
506 process_unlock();
507 if (ret) {
b5159817
DE
508 SYSERROR("failed to allocate a pty");
509 return -1;
510 }
511
512 if (fcntl(console->master, F_SETFD, FD_CLOEXEC)) {
513 SYSERROR("failed to set console master to close-on-exec");
514 goto err;
515 }
516
517 if (fcntl(console->slave, F_SETFD, FD_CLOEXEC)) {
518 SYSERROR("failed to set console slave to close-on-exec");
519 goto err;
520 }
521
522 lxc_console_peer_default(console);
523
524 if (console->log_path) {
525 console->log_fd = lxc_unpriv(open(console->log_path,
526 O_CLOEXEC | O_RDWR |
527 O_CREAT | O_APPEND, 0600));
528 if (console->log_fd < 0) {
529 SYSERROR("failed to open '%s'", console->log_path);
530 goto err;
531 }
532 DEBUG("using '%s' as console log", console->log_path);
533 }
534
535 return 0;
536
537err:
538 lxc_console_delete(console);
539 return -1;
540}
541
39a78bbe 542int lxc_console_set_stdfds(int fd)
0d9acb99 543{
39a78bbe 544 if (fd < 0)
0d9acb99 545 return 0;
b5159817 546
39a78bbe
CB
547 if (isatty(STDIN_FILENO))
548 if (dup2(fd, STDIN_FILENO) < 0) {
549 SYSERROR("failed to duplicate stdin.");
550 return -1;
551 }
552
553 if (isatty(STDOUT_FILENO))
554 if (dup2(fd, STDOUT_FILENO) < 0) {
555 SYSERROR("failed to duplicate stdout.");
556 return -1;
557 }
558
559 if (isatty(STDERR_FILENO))
560 if (dup2(fd, STDERR_FILENO) < 0) {
561 SYSERROR("failed to duplicate stderr.");
562 return -1;
563 }
564
0d9acb99
DE
565 return 0;
566}
b5159817 567
0d4137cc
CB
568int lxc_console_cb_tty_stdin(int fd, uint32_t events, void *cbdata,
569 struct lxc_epoll_descr *descr)
b5159817
DE
570{
571 struct lxc_tty_state *ts = cbdata;
572 char c;
573
9395937a
CB
574 if (events & EPOLLHUP)
575 return 1;
576
b5159817
DE
577 assert(fd == ts->stdinfd);
578 if (read(ts->stdinfd, &c, 1) < 0) {
63376d7d
DL
579 SYSERROR("failed to read");
580 return 1;
581 }
582
014d5e1e
CB
583 if (ts->escape != -1) {
584 /* we want to exit the console with Ctrl+a q */
585 if (c == ts->escape && !ts->saw_escape) {
586 ts->saw_escape = 1;
587 return 0;
588 }
5c294060 589
014d5e1e
CB
590 if (c == 'q' && ts->saw_escape)
591 return 1;
592
593 ts->saw_escape = 0;
594 }
63376d7d 595
b5159817
DE
596 if (write(ts->masterfd, &c, 1) < 0) {
597 SYSERROR("failed to write");
598 return 1;
596a818d 599 }
b5159817 600
63376d7d
DL
601 return 0;
602}
603
0d4137cc
CB
604int lxc_console_cb_tty_master(int fd, uint32_t events, void *cbdata,
605 struct lxc_epoll_descr *descr)
63376d7d 606{
b5159817
DE
607 struct lxc_tty_state *ts = cbdata;
608 char buf[1024];
0d4137cc 609 int r, w;
63376d7d 610
9395937a
CB
611 if (events & EPOLLHUP)
612 return 1;
613
b5159817
DE
614 assert(fd == ts->masterfd);
615 r = read(fd, buf, sizeof(buf));
616 if (r < 0) {
617 SYSERROR("failed to read");
618 return 1;
1560f6c9
DL
619 }
620
b5159817
DE
621 w = write(ts->stdoutfd, buf, r);
622 if (w < 0 || w != r) {
623 SYSERROR("failed to write");
624 return 1;
f78a1f32
DL
625 }
626
b5159817
DE
627 return 0;
628}
629
630int lxc_console_getfd(struct lxc_container *c, int *ttynum, int *masterfd)
631{
632 return lxc_cmd_console(c->name, ttynum, masterfd, c->config_path);
633}
634
635int lxc_console(struct lxc_container *c, int ttynum,
636 int stdinfd, int stdoutfd, int stderrfd,
637 int escape)
638{
639 int ret, ttyfd, masterfd;
640 struct lxc_epoll_descr descr;
641 struct termios oldtios;
642 struct lxc_tty_state *ts;
643
644 if (!isatty(stdinfd)) {
645 ERROR("stdin is not a tty");
646 return -1;
dff21ef0
DL
647 }
648
0d4137cc 649 ret = lxc_setup_tios(stdinfd, &oldtios);
b5159817
DE
650 if (ret) {
651 ERROR("failed to setup tios");
63376d7d
DL
652 return -1;
653 }
654
b5159817
DE
655 ttyfd = lxc_cmd_console(c->name, &ttynum, &masterfd, c->config_path);
656 if (ttyfd < 0) {
657 ret = ttyfd;
658 goto err1;
659 }
63376d7d 660
b5159817
DE
661 fprintf(stderr, "\n"
662 "Connected to tty %1$d\n"
663 "Type <Ctrl+%2$c q> to exit the console, "
664 "<Ctrl+%2$c Ctrl+%2$c> to enter Ctrl+%2$c itself\n",
665 ttynum, 'a' + escape - 1);
666
667 ret = setsid();
668 if (ret)
669 INFO("already group leader");
670
671 ts = lxc_console_sigwinch_init(stdinfd, masterfd);
672 if (!ts) {
673 ret = -1;
674 goto err2;
675 }
676 ts->escape = escape;
677 ts->winch_proxy = c->name;
678 ts->winch_proxy_lxcpath = c->config_path;
679
680 lxc_console_winsz(stdinfd, masterfd);
681 lxc_cmd_console_winch(ts->winch_proxy, ts->winch_proxy_lxcpath);
682
683 ret = lxc_mainloop_open(&descr);
684 if (ret) {
685 ERROR("failed to create mainloop");
686 goto err3;
687 }
688
341c2aed
CB
689 if (ts->sigfd != -1) {
690 ret = lxc_mainloop_add_handler(&descr, ts->sigfd,
691 lxc_console_cb_sigwinch_fd, ts);
692 if (ret) {
693 ERROR("failed to add handler for SIGWINCH fd");
694 goto err4;
695 }
b5159817
DE
696 }
697
698 ret = lxc_mainloop_add_handler(&descr, ts->stdinfd,
699 lxc_console_cb_tty_stdin, ts);
700 if (ret) {
701 ERROR("failed to add handler for stdinfd");
702 goto err4;
703 }
704
705 ret = lxc_mainloop_add_handler(&descr, ts->masterfd,
706 lxc_console_cb_tty_master, ts);
707 if (ret) {
708 ERROR("failed to add handler for masterfd");
709 goto err4;
710 }
711
025ed0f3 712 ret = lxc_mainloop(&descr, -1);
b5159817
DE
713 if (ret) {
714 ERROR("mainloop returned an error");
715 goto err4;
716 }
717
718 ret = 0;
719
720err4:
721 lxc_mainloop_close(&descr);
722err3:
341c2aed
CB
723 if (ts->sigfd != -1)
724 lxc_console_sigwinch_fini(ts);
b5159817
DE
725err2:
726 close(masterfd);
727 close(ttyfd);
728err1:
729 tcsetattr(stdinfd, TCSAFLUSH, &oldtios);
b5159817
DE
730
731 return ret;
63376d7d 732}
0d4137cc 733