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