]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/console.c
Merge pull request #981 from LynxChaus/master
[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 264 * will be done with master proxying */
d3893399 265 newtios.c_iflag &= ~(IGNBRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON|IXANY|IXOFF);
b5159817 266 newtios.c_iflag &= BRKINT;
d3893399
AJM
267 newtios.c_lflag &= ~(ECHO|ICANON|ISIG|IEXTEN|ECHOE|ECHOK|ECHONL);
268 newtios.c_oflag &= ~OPOST;
b5159817
DE
269 newtios.c_cc[VMIN] = 1;
270 newtios.c_cc[VTIME] = 0;
e0dc0de7
DL
271
272 /* Set new attributes */
b5159817 273 if (tcsetattr(fd, TCSAFLUSH, &newtios)) {
e0dc0de7 274 ERROR("failed to set new terminal settings");
b5159817 275 return -1;
e0dc0de7
DL
276 }
277
63376d7d 278 return 0;
b5159817 279}
e0dc0de7 280
b5159817
DE
281static void lxc_console_peer_proxy_free(struct lxc_console *console)
282{
341c2aed 283 if (console->tty_state && console->tty_state->sigfd != -1) {
b5159817
DE
284 lxc_console_sigwinch_fini(console->tty_state);
285 console->tty_state = NULL;
286 }
287 close(console->peerpty.master);
288 close(console->peerpty.slave);
289 console->peerpty.master = -1;
290 console->peerpty.slave = -1;
291 console->peerpty.busy = -1;
292 console->peerpty.name[0] = '\0';
596a818d 293 console->peer = -1;
b5159817 294}
596a818d 295
b5159817
DE
296static int lxc_console_peer_proxy_alloc(struct lxc_console *console, int sockfd)
297{
298 struct termios oldtermio;
299 struct lxc_tty_state *ts;
025ed0f3 300 int ret;
b5159817
DE
301
302 if (console->master < 0) {
303 ERROR("console not set up");
304 return -1;
305 }
306 if (console->peerpty.busy != -1 || console->peer != -1) {
307 NOTICE("console already in use");
308 return -1;
309 }
310 if (console->tty_state) {
311 ERROR("console already has tty_state");
312 return -1;
596a818d
DE
313 }
314
b5159817
DE
315 /* this is the proxy pty that will be given to the client, and that
316 * the real pty master will send to / recv from
317 */
025ed0f3
SH
318 process_lock();
319 ret = openpty(&console->peerpty.master, &console->peerpty.slave,
320 console->peerpty.name, NULL, NULL);
321 process_unlock();
322 if (ret) {
b5159817
DE
323 SYSERROR("failed to create proxy pty");
324 return -1;
325 }
596a818d 326
0d4137cc 327 if (lxc_setup_tios(console->peerpty.slave, &oldtermio) < 0)
b5159817
DE
328 goto err1;
329
330 ts = lxc_console_sigwinch_init(console->peerpty.master, console->master);
331 if (!ts)
332 goto err1;
333
334 console->tty_state = ts;
335 console->peer = console->peerpty.slave;
336 console->peerpty.busy = sockfd;
337 lxc_console_mainloop_add_peer(console);
338
339 DEBUG("%d %s peermaster:%d sockfd:%d", getpid(), __FUNCTION__, console->peerpty.master, sockfd);
340 return 0;
341
342err1:
343 lxc_console_peer_proxy_free(console);
63376d7d
DL
344 return -1;
345}
346
b5159817
DE
347int lxc_console_allocate(struct lxc_conf *conf, int sockfd, int *ttyreq)
348{
349 int masterfd = -1, ttynum;
350 struct lxc_tty_info *tty_info = &conf->tty_info;
351 struct lxc_console *console = &conf->console;
352
b5159817
DE
353 if (*ttyreq == 0) {
354 if (lxc_console_peer_proxy_alloc(console, sockfd) < 0)
355 goto out;
356 masterfd = console->peerpty.master;
357 goto out;
358 }
359
360 if (*ttyreq > 0) {
361 if (*ttyreq > tty_info->nbtty)
362 goto out;
363
364 if (tty_info->pty_info[*ttyreq - 1].busy)
365 goto out;
366
367 /* the requested tty is available */
368 ttynum = *ttyreq;
369 goto out_tty;
370 }
371
372 /* search for next available tty, fixup index tty1 => [0] */
0d4137cc
CB
373 for (ttynum = 1; ttynum <= tty_info->nbtty && tty_info->pty_info[ttynum - 1].busy; ttynum++)
374 ;
b5159817
DE
375
376 /* we didn't find any available slot for tty */
377 if (ttynum > tty_info->nbtty)
378 goto out;
379
380 *ttyreq = ttynum;
381
382out_tty:
383 tty_info->pty_info[ttynum - 1].busy = sockfd;
384 masterfd = tty_info->pty_info[ttynum - 1].master;
385out:
b5159817
DE
386 return masterfd;
387}
388
b5159817 389void lxc_console_free(struct lxc_conf *conf, int fd)
63376d7d 390{
b5159817
DE
391 int i;
392 struct lxc_tty_info *tty_info = &conf->tty_info;
393 struct lxc_console *console = &conf->console;
394
b5159817
DE
395 for (i = 0; i < tty_info->nbtty; i++) {
396 if (tty_info->pty_info[i].busy == fd)
397 tty_info->pty_info[i].busy = 0;
398 }
399
400 if (console->peerpty.busy == fd) {
401 lxc_mainloop_del_handler(console->descr, console->peerpty.slave);
402 lxc_console_peer_proxy_free(console);
403 }
b5159817
DE
404}
405
406static void lxc_console_peer_default(struct lxc_console *console)
407{
408 struct lxc_tty_state *ts;
409 const char *path = console->path;
410
411 /* if no console was given, try current controlling terminal, there
412 * won't be one if we were started as a daemon (-d)
413 */
414 if (!path && !access("/dev/tty", F_OK)) {
415 int fd;
416 fd = open("/dev/tty", O_RDWR);
417 if (fd >= 0) {
418 close(fd);
419 path = "/dev/tty";
420 }
421 }
422
423 if (!path)
424 goto out;
425
426 DEBUG("opening %s for console peer", path);
427 console->peer = lxc_unpriv(open(path, O_CLOEXEC | O_RDWR | O_CREAT |
428 O_APPEND, 0600));
429 if (console->peer < 0)
430 goto out;
431
432 DEBUG("using '%s' as console", path);
433
434 if (!isatty(console->peer))
0d9acb99 435 goto err1;
b5159817
DE
436
437 ts = lxc_console_sigwinch_init(console->peer, console->master);
b5159817 438 console->tty_state = ts;
341c2aed
CB
439 if (!ts) {
440 WARN("Unable to install SIGWINCH");
441 goto err1;
442 }
b5159817
DE
443
444 lxc_console_winsz(console->peer, console->master);
445
446 console->tios = malloc(sizeof(*console->tios));
447 if (!console->tios) {
448 SYSERROR("failed to allocate memory");
449 goto err1;
450 }
451
0d4137cc 452 if (lxc_setup_tios(console->peer, console->tios) < 0)
b5159817
DE
453 goto err2;
454
455 return;
456
457err2:
458 free(console->tios);
459 console->tios = NULL;
460err1:
461 close(console->peer);
462 console->peer = -1;
463out:
464 DEBUG("no console peer");
341c2aed 465 return;
b5159817
DE
466}
467
468void lxc_console_delete(struct lxc_console *console)
469{
470 if (console->tios && console->peer >= 0 &&
e0dc0de7
DL
471 tcsetattr(console->peer, TCSAFLUSH, console->tios))
472 WARN("failed to set old terminal settings");
596a818d
DE
473 free(console->tios);
474 console->tios = NULL;
475
476 close(console->peer);
025ed0f3
SH
477 close(console->master);
478 close(console->slave);
479 if (console->log_fd >= 0)
596a818d 480 close(console->log_fd);
596a818d 481
025ed0f3 482 console->peer = -1;
596a818d 483 console->master = -1;
596a818d 484 console->slave = -1;
025ed0f3 485 console->log_fd = -1;
63376d7d
DL
486}
487
b5159817 488int lxc_console_create(struct lxc_conf *conf)
63376d7d 489{
b5159817 490 struct lxc_console *console = &conf->console;
025ed0f3 491 int ret;
63376d7d 492
37903589
SH
493 if (conf->is_execute) {
494 INFO("no console for lxc-execute.");
495 return 0;
496 }
497
b5159817
DE
498 if (!conf->rootfs.path)
499 return 0;
500
501 if (console->path && !strcmp(console->path, "none"))
502 return 0;
503
025ed0f3
SH
504 process_lock();
505 ret = openpty(&console->master, &console->slave,
506 console->name, NULL, NULL);
507 process_unlock();
508 if (ret) {
b5159817
DE
509 SYSERROR("failed to allocate a pty");
510 return -1;
511 }
512
513 if (fcntl(console->master, F_SETFD, FD_CLOEXEC)) {
514 SYSERROR("failed to set console master to close-on-exec");
515 goto err;
516 }
517
518 if (fcntl(console->slave, F_SETFD, FD_CLOEXEC)) {
519 SYSERROR("failed to set console slave to close-on-exec");
520 goto err;
521 }
522
523 lxc_console_peer_default(console);
524
525 if (console->log_path) {
526 console->log_fd = lxc_unpriv(open(console->log_path,
527 O_CLOEXEC | O_RDWR |
528 O_CREAT | O_APPEND, 0600));
529 if (console->log_fd < 0) {
530 SYSERROR("failed to open '%s'", console->log_path);
531 goto err;
532 }
533 DEBUG("using '%s' as console log", console->log_path);
534 }
535
536 return 0;
537
538err:
539 lxc_console_delete(console);
540 return -1;
541}
542
39a78bbe 543int lxc_console_set_stdfds(int fd)
0d9acb99 544{
39a78bbe 545 if (fd < 0)
0d9acb99 546 return 0;
b5159817 547
39a78bbe
CB
548 if (isatty(STDIN_FILENO))
549 if (dup2(fd, STDIN_FILENO) < 0) {
550 SYSERROR("failed to duplicate stdin.");
551 return -1;
552 }
553
554 if (isatty(STDOUT_FILENO))
555 if (dup2(fd, STDOUT_FILENO) < 0) {
556 SYSERROR("failed to duplicate stdout.");
557 return -1;
558 }
559
560 if (isatty(STDERR_FILENO))
561 if (dup2(fd, STDERR_FILENO) < 0) {
562 SYSERROR("failed to duplicate stderr.");
563 return -1;
564 }
565
0d9acb99
DE
566 return 0;
567}
b5159817 568
0d4137cc
CB
569int lxc_console_cb_tty_stdin(int fd, uint32_t events, void *cbdata,
570 struct lxc_epoll_descr *descr)
b5159817
DE
571{
572 struct lxc_tty_state *ts = cbdata;
573 char c;
574
575 assert(fd == ts->stdinfd);
e66b6c96 576 if (lxc_read_nointr(ts->stdinfd, &c, 1) <= 0)
63376d7d 577 return 1;
63376d7d 578
014d5e1e
CB
579 if (ts->escape != -1) {
580 /* we want to exit the console with Ctrl+a q */
581 if (c == ts->escape && !ts->saw_escape) {
582 ts->saw_escape = 1;
583 return 0;
584 }
5c294060 585
014d5e1e
CB
586 if (c == 'q' && ts->saw_escape)
587 return 1;
588
589 ts->saw_escape = 0;
590 }
63376d7d 591
e66b6c96 592 if (lxc_write_nointr(ts->masterfd, &c, 1) <= 0)
b5159817 593 return 1;
b5159817 594
63376d7d
DL
595 return 0;
596}
597
0d4137cc
CB
598int lxc_console_cb_tty_master(int fd, uint32_t events, void *cbdata,
599 struct lxc_epoll_descr *descr)
63376d7d 600{
b5159817
DE
601 struct lxc_tty_state *ts = cbdata;
602 char buf[1024];
0d4137cc 603 int r, w;
63376d7d 604
b5159817 605 assert(fd == ts->masterfd);
e66b6c96
CB
606 r = lxc_read_nointr(fd, buf, sizeof(buf));
607 if (r <= 0)
b5159817 608 return 1;
1560f6c9 609
e66b6c96
CB
610 w = lxc_write_nointr(ts->stdoutfd, buf, r);
611 if (w <= 0) {
612 return 1;
613 } else if (w != r) {
b5159817
DE
614 SYSERROR("failed to write");
615 return 1;
f78a1f32
DL
616 }
617
b5159817
DE
618 return 0;
619}
620
621int lxc_console_getfd(struct lxc_container *c, int *ttynum, int *masterfd)
622{
623 return lxc_cmd_console(c->name, ttynum, masterfd, c->config_path);
624}
625
626int lxc_console(struct lxc_container *c, int ttynum,
627 int stdinfd, int stdoutfd, int stderrfd,
628 int escape)
629{
630 int ret, ttyfd, masterfd;
631 struct lxc_epoll_descr descr;
632 struct termios oldtios;
633 struct lxc_tty_state *ts;
634
635 if (!isatty(stdinfd)) {
636 ERROR("stdin is not a tty");
637 return -1;
dff21ef0
DL
638 }
639
0d4137cc 640 ret = lxc_setup_tios(stdinfd, &oldtios);
b5159817
DE
641 if (ret) {
642 ERROR("failed to setup tios");
63376d7d
DL
643 return -1;
644 }
645
b5159817
DE
646 ttyfd = lxc_cmd_console(c->name, &ttynum, &masterfd, c->config_path);
647 if (ttyfd < 0) {
648 ret = ttyfd;
649 goto err1;
650 }
63376d7d 651
b5159817
DE
652 fprintf(stderr, "\n"
653 "Connected to tty %1$d\n"
654 "Type <Ctrl+%2$c q> to exit the console, "
655 "<Ctrl+%2$c Ctrl+%2$c> to enter Ctrl+%2$c itself\n",
656 ttynum, 'a' + escape - 1);
657
658 ret = setsid();
659 if (ret)
660 INFO("already group leader");
661
662 ts = lxc_console_sigwinch_init(stdinfd, masterfd);
663 if (!ts) {
664 ret = -1;
665 goto err2;
666 }
667 ts->escape = escape;
668 ts->winch_proxy = c->name;
669 ts->winch_proxy_lxcpath = c->config_path;
670
671 lxc_console_winsz(stdinfd, masterfd);
672 lxc_cmd_console_winch(ts->winch_proxy, ts->winch_proxy_lxcpath);
673
674 ret = lxc_mainloop_open(&descr);
675 if (ret) {
676 ERROR("failed to create mainloop");
677 goto err3;
678 }
679
341c2aed
CB
680 if (ts->sigfd != -1) {
681 ret = lxc_mainloop_add_handler(&descr, ts->sigfd,
682 lxc_console_cb_sigwinch_fd, ts);
683 if (ret) {
684 ERROR("failed to add handler for SIGWINCH fd");
685 goto err4;
686 }
b5159817
DE
687 }
688
689 ret = lxc_mainloop_add_handler(&descr, ts->stdinfd,
690 lxc_console_cb_tty_stdin, ts);
691 if (ret) {
692 ERROR("failed to add handler for stdinfd");
693 goto err4;
694 }
695
696 ret = lxc_mainloop_add_handler(&descr, ts->masterfd,
697 lxc_console_cb_tty_master, ts);
698 if (ret) {
699 ERROR("failed to add handler for masterfd");
700 goto err4;
701 }
702
025ed0f3 703 ret = lxc_mainloop(&descr, -1);
b5159817
DE
704 if (ret) {
705 ERROR("mainloop returned an error");
706 goto err4;
707 }
708
709 ret = 0;
710
711err4:
712 lxc_mainloop_close(&descr);
713err3:
341c2aed
CB
714 if (ts->sigfd != -1)
715 lxc_console_sigwinch_fini(ts);
b5159817
DE
716err2:
717 close(masterfd);
718 close(ttyfd);
719err1:
720 tcsetattr(stdinfd, TCSAFLUSH, &oldtios);
b5159817
DE
721
722 return ret;
63376d7d 723}
0d4137cc 724