]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/terminal.c
build: prevent the inclusion of linux/mount.h with a hack
[mirror_lxc.git] / src / lxc / terminal.c
CommitLineData
cc73685d 1/* SPDX-License-Identifier: LGPL-2.1+ */
b0a33c1e 2
1160ce89
CB
3#include "config.h"
4
9395937a
CB
5#include <errno.h>
6#include <fcntl.h>
b467714b 7#include <pthread.h>
b5159817 8#include <signal.h>
b0a33c1e 9#include <stdio.h>
e0dc0de7 10#include <stdlib.h>
da41561c
CB
11#include <sys/epoll.h>
12#include <sys/types.h>
e62912bd
CB
13#include <termios.h>
14#include <unistd.h>
f2363e38 15
12ae2a33
CB
16#include "lxc.h"
17
9395937a
CB
18#include "af_unix.h"
19#include "caps.h"
20#include "commands.h"
00dbc43e 21#include "conf.h"
9395937a 22#include "log.h"
b5159817 23#include "lxclock.h"
9395937a 24#include "mainloop.h"
2530ba95 25#include "memory_utils.h"
e62912bd 26#include "start.h"
303037d2 27#include "syscall_wrappers.h"
0ed9b1bc 28#include "terminal.h"
b5159817 29#include "utils.h"
36eb9bde 30
35eb5cdc 31#if HAVE_OPENPTY
e827ff7e
SG
32#include <pty.h>
33#else
58db1a61 34#include "openpty.h"
e827ff7e
SG
35#endif
36
de708fb7 37#define LXC_TERMINAL_BUFFER_SIZE 1024
732375f5 38
2083d59d 39lxc_log_define(terminal, lxc);
36eb9bde 40
4e9c0330 41void lxc_terminal_winsz(int srcfd, int dstfd)
b5159817 42{
0519b5cc 43 int ret;
b5159817 44 struct winsize wsz;
0519b5cc
CB
45
46 if (!isatty(srcfd))
47 return;
48
49 ret = ioctl(srcfd, TIOCGWINSZ, &wsz);
50 if (ret < 0) {
51 WARN("Failed to get window size");
52 return;
724e753c 53 }
0519b5cc
CB
54
55 ret = ioctl(dstfd, TIOCSWINSZ, &wsz);
56 if (ret < 0)
57 WARN("Failed to set window size");
58 else
59 DEBUG("Set window size to %d columns and %d rows", wsz.ws_col,
60 wsz.ws_row);
61
62 return;
b5159817 63}
724e753c 64
5b55021f 65static void lxc_terminal_winch(struct lxc_terminal_state *ts)
b5159817 66{
36a94ce8 67 lxc_terminal_winsz(ts->stdinfd, ts->ptxfd);
b5159817 68}
cd453b38 69
9bafc8cb 70int lxc_terminal_signalfd_cb(int fd, uint32_t events, void *cbdata,
3298b37d 71 struct lxc_async_descr *descr)
b5159817 72{
1349e92e 73 ssize_t ret;
b5159817 74 struct signalfd_siginfo siginfo;
5b55021f 75 struct lxc_terminal_state *ts = cbdata;
b5159817 76
72f7c19b 77 ret = lxc_read_nointr(fd, &siginfo, sizeof(siginfo));
0d4137cc 78 if (ret < 0 || (size_t)ret < sizeof(siginfo)) {
0519b5cc 79 ERROR("Failed to read signal info");
2e943b7b 80 return LXC_MAINLOOP_ERROR;
cd453b38
DL
81 }
82
1349e92e 83 if (siginfo.ssi_signo == SIGTERM) {
9bafc8cb 84 DEBUG("Received SIGTERM. Detaching from the terminal");
a529bc25 85 return LXC_MAINLOOP_CLOSE;
1349e92e
CB
86 }
87
88 if (siginfo.ssi_signo == SIGWINCH)
7a10164a 89 lxc_terminal_winch(ts);
1349e92e 90
2e943b7b 91 return LXC_MAINLOOP_CONTINUE;
b5159817
DE
92}
93
5b55021f 94struct lxc_terminal_state *lxc_terminal_signal_init(int srcfd, int dstfd)
b5159817 95{
f62cf1d4 96 __do_close int signal_fd = -EBADF;
28327a43 97 __do_free struct lxc_terminal_state *ts = NULL;
28327a43 98 int ret;
b5159817 99 sigset_t mask;
b5159817
DE
100
101 ts = malloc(sizeof(*ts));
102 if (!ts)
103 return NULL;
104
105 memset(ts, 0, sizeof(*ts));
341c2aed 106 ts->stdinfd = srcfd;
36a94ce8 107 ts->ptxfd = dstfd;
341c2aed 108 ts->sigfd = -1;
b5159817 109
b6d5de95
CB
110 ret = sigemptyset(&mask);
111 if (ret < 0) {
112 SYSERROR("Failed to initialize an empty signal set");
1ba4ae89 113 return NULL;
b6d5de95 114 }
1349e92e 115
1ba4ae89 116 if (isatty(srcfd)) {
b6d5de95
CB
117 ret = sigaddset(&mask, SIGWINCH);
118 if (ret < 0)
7874d81a 119 SYSNOTICE("Failed to add SIGWINCH to signal set");
1ba4ae89
CB
120 } else {
121 INFO("fd %d does not refer to a tty device", srcfd);
25964232
LF
122 }
123
1349e92e 124 /* Exit the mainloop cleanly on SIGTERM. */
b6d5de95
CB
125 ret = sigaddset(&mask, SIGTERM);
126 if (ret < 0) {
127 SYSERROR("Failed to add SIGWINCH to signal set");
1ba4ae89 128 return NULL;
b6d5de95 129 }
b5159817 130
b467714b 131 ret = pthread_sigmask(SIG_BLOCK, &mask, &ts->oldmask);
1349e92e
CB
132 if (ret < 0) {
133 WARN("Failed to block signals");
1ba4ae89 134 return NULL;
b5159817
DE
135 }
136
1ba4ae89
CB
137 signal_fd = signalfd(-1, &mask, SFD_CLOEXEC);
138 if (signal_fd < 0) {
1349e92e 139 WARN("Failed to create signal fd");
b467714b 140 (void)pthread_sigmask(SIG_SETMASK, &ts->oldmask, NULL);
1ba4ae89 141 return NULL;
1349e92e 142 }
1ba4ae89
CB
143 ts->sigfd = move_fd(signal_fd);
144 TRACE("Created signal fd %d", ts->sigfd);
b6d5de95 145
1ba4ae89 146 return move_ptr(ts);
cd453b38
DL
147}
148
3e3f79bd
CB
149int lxc_terminal_signal_sigmask_safe_blocked(struct lxc_terminal *terminal)
150{
151 struct lxc_terminal_state *state = terminal->tty_state;
152
153 if (!state)
154 return 0;
155
156 return pthread_sigmask(SIG_SETMASK, &state->oldmask, NULL);
157}
158
26ed61e0
CB
159/**
160 * lxc_terminal_signal_fini: uninstall signal handler
161 *
162 * @terminal: terminal instance
163 *
164 * Restore the saved signal handler that was in effect at the time
165 * lxc_terminal_signal_init() was called.
166 */
167static void lxc_terminal_signal_fini(struct lxc_terminal *terminal)
63376d7d 168{
28327a43 169 struct lxc_terminal_state *state = terminal->tty_state;
1349e92e 170
28327a43
CB
171 if (!terminal->tty_state)
172 return;
173
174 state = terminal->tty_state;
175 if (state->sigfd >= 0) {
176 close(state->sigfd);
177
178 if (pthread_sigmask(SIG_SETMASK, &state->oldmask, NULL) < 0)
a24c5678 179 SYSWARN("Failed to restore signal mask");
0e6da90b 180 }
0d4137cc 181
28327a43
CB
182 free(terminal->tty_state);
183 terminal->tty_state = NULL;
b5159817 184}
1560f6c9 185
99a04585 186static int lxc_terminal_truncate_log_file(struct lxc_terminal *terminal)
861813e5
CB
187{
188 /* be very certain things are kosher */
2083d59d 189 if (!terminal->log_path || terminal->log_fd < 0)
861813e5
CB
190 return -EBADF;
191
2083d59d 192 return lxc_unpriv(ftruncate(terminal->log_fd, 0));
861813e5
CB
193}
194
468724d3 195static int lxc_terminal_rotate_log_file(struct lxc_terminal *terminal)
861813e5 196{
2530ba95 197 __do_free char *tmp = NULL;
861813e5
CB
198 int ret;
199 size_t len;
861813e5 200
99a04585 201 if (!terminal->log_path || terminal->log_rotate == 0)
861813e5
CB
202 return -EOPNOTSUPP;
203
204 /* be very certain things are kosher */
99a04585 205 if (terminal->log_fd < 0)
861813e5
CB
206 return -EBADF;
207
99a04585 208 len = strlen(terminal->log_path) + sizeof(".1");
2530ba95 209 tmp = must_realloc(NULL, len);
861813e5 210
93d5ebf1
CB
211 ret = strnprintf(tmp, len, "%s.1", terminal->log_path);
212 if (ret < 0)
861813e5
CB
213 return -EFBIG;
214
99a04585
CB
215 close(terminal->log_fd);
216 terminal->log_fd = -1;
217 ret = lxc_unpriv(rename(terminal->log_path, tmp));
861813e5
CB
218 if (ret < 0)
219 return ret;
220
99a04585 221 return lxc_terminal_create_log_file(terminal);
861813e5
CB
222}
223
a44ae1a9 224static int lxc_terminal_write_log_file(struct lxc_terminal *terminal, char *buf,
8903fb08 225 int bytes_read)
861813e5
CB
226{
227 int ret;
861813e5 228 struct stat st;
8903fb08 229 int64_t space_left = -1;
861813e5 230
99a04585 231 if (terminal->log_fd < 0)
861813e5
CB
232 return 0;
233
234 /* A log size <= 0 means that there's no limit on the size of the log
235 * file at which point we simply ignore whether the log is supposed to
236 * be rotated or not.
237 */
99a04585
CB
238 if (terminal->log_size <= 0)
239 return lxc_write_nointr(terminal->log_fd, buf, bytes_read);
861813e5
CB
240
241 /* Get current size of the log file. */
99a04585 242 ret = fstat(terminal->log_fd, &st);
861813e5 243 if (ret < 0) {
99a04585 244 SYSERROR("Failed to stat the terminal log file descriptor");
861813e5
CB
245 return -1;
246 }
247
248 /* handle non-regular files */
249 if ((st.st_mode & S_IFMT) != S_IFREG) {
250 /* This isn't a regular file. so rotating the file seems a
251 * dangerous thing to do, size limits are also very
252 * questionable. Let's not risk anything and tell the user that
f48e8071 253 * they're requesting us to do weird stuff.
861813e5 254 */
99a04585 255 if (terminal->log_rotate > 0 || terminal->log_size > 0)
861813e5
CB
256 return -EINVAL;
257
258 /* I mean, sure log wherever you want to. */
99a04585 259 return lxc_write_nointr(terminal->log_fd, buf, bytes_read);
861813e5
CB
260 }
261
99a04585 262 space_left = terminal->log_size - st.st_size;
861813e5
CB
263
264 /* User doesn't want to rotate the log file and there's no more space
265 * left so simply truncate it.
266 */
99a04585
CB
267 if (space_left <= 0 && terminal->log_rotate <= 0) {
268 ret = lxc_terminal_truncate_log_file(terminal);
861813e5
CB
269 if (ret < 0)
270 return ret;
271
8703bf5b 272 if ((uint64_t)bytes_read <= terminal->log_size)
99a04585 273 return lxc_write_nointr(terminal->log_fd, buf, bytes_read);
861813e5
CB
274
275 /* Write as much as we can into the buffer and loose the rest. */
99a04585 276 return lxc_write_nointr(terminal->log_fd, buf, terminal->log_size);
861813e5
CB
277 }
278
279 /* There's enough space left. */
280 if (bytes_read <= space_left)
99a04585 281 return lxc_write_nointr(terminal->log_fd, buf, bytes_read);
861813e5
CB
282
283 /* There's not enough space left but at least write as much as we can
284 * into the old log file.
285 */
99a04585 286 ret = lxc_write_nointr(terminal->log_fd, buf, space_left);
861813e5
CB
287 if (ret < 0)
288 return -1;
289
290 /* Calculate how many bytes we still need to write. */
291 bytes_read -= space_left;
292
89962c6c 293 /* There'd be more to write but we aren't instructed to rotate the log
861813e5
CB
294 * file so simply return. There's no error on our side here.
295 */
99a04585 296 if (terminal->log_rotate > 0)
468724d3 297 ret = lxc_terminal_rotate_log_file(terminal);
861813e5 298 else
99a04585 299 ret = lxc_terminal_truncate_log_file(terminal);
861813e5
CB
300 if (ret < 0)
301 return ret;
302
8703bf5b 303 if (terminal->log_size < (uint64_t)bytes_read) {
861813e5
CB
304 /* Well, this is unfortunate because it means that there is more
305 * to write than the user has granted us space. There are
306 * multiple ways to handle this but let's use the simplest one:
307 * write as much as we can, tell the user that there was more
308 * stuff to write and move on.
309 * Note that this scenario shouldn't actually happen with the
99a04585 310 * standard pty-based terminal that LXC allocates since it will
861813e5
CB
311 * be switched into raw mode. In raw mode only 1 byte at a time
312 * should be read and written.
313 */
99a04585
CB
314 WARN("Size of terminal log file is smaller than the bytes to write");
315 ret = lxc_write_nointr(terminal->log_fd, buf, terminal->log_size);
861813e5
CB
316 if (ret < 0)
317 return -1;
318 bytes_read -= ret;
319 return bytes_read;
320 }
321
322 /* Yay, we made it. */
99a04585 323 ret = lxc_write_nointr(terminal->log_fd, buf, bytes_read);
861813e5
CB
324 if (ret < 0)
325 return -1;
326 bytes_read -= ret;
327 return bytes_read;
328}
329
543d2f83 330static int lxc_terminal_ptx_io(struct lxc_terminal *terminal)
b5159817 331{
de708fb7 332 char buf[LXC_TERMINAL_BUFFER_SIZE];
732375f5 333 int r, w, w_log, w_rbuf;
e0dc0de7 334
543d2f83
CB
335 w = r = lxc_read_nointr(terminal->ptx, buf, sizeof(buf));
336 if (r <= 0)
337 return -1;
c06a0555 338
543d2f83
CB
339 w_rbuf = w_log = 0;
340 /* write to peer first */
341 if (terminal->peer >= 0)
342 w = lxc_write_nointr(terminal->peer, buf, r);
63376d7d 343
543d2f83
CB
344 /* write to terminal ringbuffer */
345 if (terminal->buffer_size > 0)
346 w_rbuf = lxc_ringbuf_write(&terminal->ringbuf, buf, r);
b5159817 347
543d2f83
CB
348 /* write to terminal log */
349 if (terminal->log_fd >= 0)
350 w_log = lxc_terminal_write_log_file(terminal, buf, r);
63376d7d 351
b5159817 352 if (w != r)
de708fb7 353 WARN("Short write on terminal r:%d != w:%d", r, w);
732375f5 354
7874d81a 355 if (w_rbuf < 0) {
356 errno = -w_rbuf;
357 SYSTRACE("Failed to write %d bytes to terminal ringbuffer", r);
358 }
732375f5
CB
359
360 if (w_log < 0)
de708fb7 361 TRACE("Failed to write %d bytes to terminal log", r);
0d4137cc 362
543d2f83
CB
363 return 0;
364}
365
366static int lxc_terminal_peer_io(struct lxc_terminal *terminal)
367{
368 char buf[LXC_TERMINAL_BUFFER_SIZE];
369 int r, w;
370
371 w = r = lxc_read_nointr(terminal->peer, buf, sizeof(buf));
372 if (r <= 0)
373 return -1;
374
375 w = lxc_write_nointr(terminal->ptx, buf, r);
376 if (w != r)
377 WARN("Short write on terminal r:%d != w:%d", r, w);
378
379 return 0;
380}
381
382static int lxc_terminal_ptx_io_handler(int fd, uint32_t events, void *data,
383 struct lxc_async_descr *descr)
384{
385 struct lxc_terminal *terminal = data;
386 int ret;
387
388 ret = lxc_terminal_ptx_io(data);
389 if (ret < 0)
390 return log_info(LXC_MAINLOOP_CLOSE,
391 "Terminal client on fd %d has exited",
392 terminal->ptx);
393
394 return LXC_MAINLOOP_CONTINUE;
395}
396
397static int lxc_terminal_peer_io_handler(int fd, uint32_t events, void *data,
398 struct lxc_async_descr *descr)
399{
400 struct lxc_terminal *terminal = data;
401 int ret;
402
403 ret = lxc_terminal_peer_io(data);
404 if (ret < 0)
405 return log_info(LXC_MAINLOOP_CLOSE,
406 "Terminal client on fd %d has exited",
407 terminal->peer);
408
2b8bf299 409 return LXC_MAINLOOP_CONTINUE;
b5159817
DE
410}
411
dcad02f8 412static int lxc_terminal_mainloop_add_peer(struct lxc_terminal *terminal)
b5159817 413{
a529bc25
CB
414 int ret;
415
2083d59d
CB
416 if (terminal->peer >= 0) {
417 ret = lxc_mainloop_add_handler(terminal->descr, terminal->peer,
543d2f83
CB
418 lxc_terminal_peer_io_handler,
419 default_cleanup_handler,
420 terminal, "lxc_terminal_peer_io_handler");
a529bc25 421 if (ret < 0) {
2083d59d 422 WARN("Failed to add terminal peer handler to mainloop");
a529bc25
CB
423 return -1;
424 }
63376d7d
DL
425 }
426
2083d59d 427 if (!terminal->tty_state || terminal->tty_state->sigfd < 0)
a529bc25
CB
428 return 0;
429
543d2f83
CB
430 ret = lxc_mainloop_add_handler(terminal->descr,
431 terminal->tty_state->sigfd,
432 lxc_terminal_signalfd_cb,
433 default_cleanup_handler,
434 terminal->tty_state,
435 "lxc_terminal_signalfd_cb");
a529bc25
CB
436 if (ret < 0) {
437 WARN("Failed to add signal handler to mainloop");
438 return -1;
b5159817 439 }
a529bc25
CB
440
441 return 0;
b5159817
DE
442}
443
3298b37d 444int lxc_terminal_mainloop_add(struct lxc_async_descr *descr,
ea5b3c23 445 struct lxc_terminal *terminal)
b5159817 446{
a529bc25 447 int ret;
b5159817 448
36a94ce8 449 if (terminal->ptx < 0) {
2083d59d 450 INFO("Terminal is not initialized");
b5159817 451 return 0;
596a818d
DE
452 }
453
36a94ce8 454 ret = lxc_mainloop_add_handler(descr, terminal->ptx,
543d2f83
CB
455 lxc_terminal_ptx_io_handler,
456 default_cleanup_handler,
457 terminal, "lxc_terminal_ptx_io_handler");
30a33fbd 458 if (ret < 0) {
543d2f83 459 ERROR("Failed to add handler for terminal ptx fd %d to mainloop", terminal->ptx);
b5159817 460 return -1;
28a4b0e5
DL
461 }
462
30a33fbd 463 /* We cache the descr so that we can add an fd to it when someone
c1ee47cd 464 * does attach to it in lxc_terminal_allocate().
b5159817 465 */
2083d59d 466 terminal->descr = descr;
cd453b38 467
ea5b3c23 468 return lxc_terminal_mainloop_add_peer(terminal);
b5159817 469}
28a4b0e5 470
0d4137cc 471int lxc_setup_tios(int fd, struct termios *oldtios)
b5159817 472{
e4953e62 473 int ret;
b5159817 474 struct termios newtios;
e0dc0de7 475
b5159817 476 if (!isatty(fd)) {
8332a09c 477 ERROR("File descriptor %d does not refer to a terminal", fd);
b5159817 478 return -1;
e0dc0de7
DL
479 }
480
e4953e62
CB
481 /* Get current termios. */
482 ret = tcgetattr(fd, oldtios);
483 if (ret < 0) {
484 SYSERROR("Failed to get current terminal settings");
b5159817 485 return -1;
e0dc0de7
DL
486 }
487
4dc96430
TJ
488 /* ensure we don't end up in an endless loop:
489 * The kernel might fire SIGTTOU while an
490 * ioctl() in tcsetattr() is executed. When the ioctl()
491 * is resumed and retries, the signal handler interrupts it again.
492 */
493 signal (SIGTTIN, SIG_IGN);
494 signal (SIGTTOU, SIG_IGN);
495
b5159817 496 newtios = *oldtios;
e0dc0de7 497
a7c97a40
CB
498 /* We use the same settings that ssh does. */
499 newtios.c_iflag |= IGNPAR;
500 newtios.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF);
501#ifdef IUCLC
502 newtios.c_iflag &= ~IUCLC;
503#endif
4dc96430 504 newtios.c_lflag &= ~(TOSTOP | ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL);
a7c97a40
CB
505#ifdef IEXTEN
506 newtios.c_lflag &= ~IEXTEN;
507#endif
90275474 508 newtios.c_oflag |= ONLCR;
300ec717 509 newtios.c_oflag |= OPOST;
b5159817
DE
510 newtios.c_cc[VMIN] = 1;
511 newtios.c_cc[VTIME] = 0;
e0dc0de7 512
a7c97a40 513 /* Set new attributes. */
e4953e62
CB
514 ret = tcsetattr(fd, TCSAFLUSH, &newtios);
515 if (ret < 0) {
516 ERROR("Failed to set new terminal settings");
b5159817 517 return -1;
e0dc0de7
DL
518 }
519
63376d7d 520 return 0;
b5159817 521}
e0dc0de7 522
dcad02f8 523static void lxc_terminal_peer_proxy_free(struct lxc_terminal *terminal)
b5159817 524{
28327a43 525 lxc_terminal_signal_fini(terminal);
e788f4ac 526
36a94ce8
CB
527 close(terminal->proxy.ptx);
528 terminal->proxy.ptx = -1;
e788f4ac 529
41808e20
CB
530 close(terminal->proxy.pty);
531 terminal->proxy.pty = -1;
e788f4ac 532
fb87aa6a 533 terminal->proxy.busy = -1;
e788f4ac 534
fb87aa6a 535 terminal->proxy.name[0] = '\0';
e788f4ac 536
2083d59d 537 terminal->peer = -1;
b5159817 538}
596a818d 539
60dd8ef4
CB
540static int lxc_terminal_peer_proxy_alloc(struct lxc_terminal *terminal,
541 int sockfd)
b5159817 542{
60dd8ef4 543 int ret;
b5159817 544 struct termios oldtermio;
5b55021f 545 struct lxc_terminal_state *ts;
b5159817 546
36a94ce8 547 if (terminal->ptx < 0) {
2083d59d 548 ERROR("Terminal not set up");
b5159817
DE
549 return -1;
550 }
60dd8ef4 551
fb87aa6a 552 if (terminal->proxy.busy != -1 || terminal->peer != -1) {
2083d59d 553 NOTICE("Terminal already in use");
b5159817
DE
554 return -1;
555 }
60dd8ef4 556
2083d59d 557 if (terminal->tty_state) {
60dd8ef4 558 ERROR("Terminal has already been initialized");
b5159817 559 return -1;
596a818d
DE
560 }
561
d712f9e8 562 /* This is the proxy terminal that will be given to the client, and
36a94ce8 563 * that the real terminal ptx will send to / recv from.
b5159817 564 */
41808e20 565 ret = openpty(&terminal->proxy.ptx, &terminal->proxy.pty, NULL,
3f15bdd9 566 NULL, NULL);
60dd8ef4
CB
567 if (ret < 0) {
568 SYSERROR("Failed to open proxy terminal");
b5159817
DE
569 return -1;
570 }
596a818d 571
41808e20 572 ret = ttyname_r(terminal->proxy.pty, terminal->proxy.name,
3f15bdd9
CB
573 sizeof(terminal->proxy.name));
574 if (ret < 0) {
41808e20 575 SYSERROR("Failed to retrieve name of proxy terminal pty");
3f15bdd9
CB
576 goto on_error;
577 }
578
36a94ce8 579 ret = fd_cloexec(terminal->proxy.ptx, true);
408c18a1 580 if (ret < 0) {
36a94ce8 581 SYSERROR("Failed to set FD_CLOEXEC flag on proxy terminal ptx");
408c18a1
CB
582 goto on_error;
583 }
584
41808e20 585 ret = fd_cloexec(terminal->proxy.pty, true);
408c18a1 586 if (ret < 0) {
41808e20 587 SYSERROR("Failed to set FD_CLOEXEC flag on proxy terminal pty");
408c18a1
CB
588 goto on_error;
589 }
590
41808e20 591 ret = lxc_setup_tios(terminal->proxy.pty, &oldtermio);
60dd8ef4
CB
592 if (ret < 0)
593 goto on_error;
b5159817 594
36a94ce8 595 ts = lxc_terminal_signal_init(terminal->proxy.ptx, terminal->ptx);
b5159817 596 if (!ts)
60dd8ef4 597 goto on_error;
b5159817 598
2083d59d 599 terminal->tty_state = ts;
41808e20 600 terminal->peer = terminal->proxy.pty;
fb87aa6a 601 terminal->proxy.busy = sockfd;
2083d59d 602 ret = lxc_terminal_mainloop_add_peer(terminal);
a529bc25 603 if (ret < 0)
60dd8ef4 604 goto on_error;
b5159817 605
41808e20
CB
606 NOTICE("Opened proxy terminal with ptx fd %d and pty fd %d",
607 terminal->proxy.ptx, terminal->proxy.pty);
b5159817
DE
608 return 0;
609
60dd8ef4 610on_error:
2083d59d 611 lxc_terminal_peer_proxy_free(terminal);
63376d7d
DL
612 return -1;
613}
614
c1ee47cd 615int lxc_terminal_allocate(struct lxc_conf *conf, int sockfd, int *ttyreq)
b5159817 616{
8703bf5b 617 size_t ttynum;
36a94ce8 618 int ptxfd = -1;
0e4be3cf 619 struct lxc_tty_info *ttys = &conf->ttys;
dcad02f8 620 struct lxc_terminal *terminal = &conf->console;
b5159817 621
b5159817 622 if (*ttyreq == 0) {
12c2eaaa
CB
623 int ret;
624
625 ret = lxc_terminal_peer_proxy_alloc(terminal, sockfd);
626 if (ret < 0)
b5159817 627 goto out;
12c2eaaa 628
36a94ce8 629 ptxfd = terminal->proxy.ptx;
b5159817
DE
630 goto out;
631 }
632
633 if (*ttyreq > 0) {
8703bf5b 634 if ((size_t)*ttyreq > ttys->max)
b5159817
DE
635 goto out;
636
730aaf46 637 if (ttys->tty[*ttyreq - 1].busy >= 0)
b5159817
DE
638 goto out;
639
12c2eaaa 640 /* The requested tty is available. */
b5159817
DE
641 ttynum = *ttyreq;
642 goto out_tty;
643 }
644
12c2eaaa 645 /* Search for next available tty, fixup index tty1 => [0]. */
730aaf46 646 for (ttynum = 1; ttynum <= ttys->max && ttys->tty[ttynum - 1].busy >= 0; ttynum++) {
0d4137cc 647 ;
12c2eaaa 648 }
b5159817 649
12c2eaaa 650 /* We didn't find any available slot for tty. */
885766f5 651 if (ttynum > ttys->max)
b5159817
DE
652 goto out;
653
8703bf5b 654 *ttyreq = (int)ttynum;
b5159817
DE
655
656out_tty:
0e4be3cf 657 ttys->tty[ttynum - 1].busy = sockfd;
36a94ce8 658 ptxfd = ttys->tty[ttynum - 1].ptx;
12c2eaaa 659
b5159817 660out:
36a94ce8 661 return ptxfd;
b5159817
DE
662}
663
3dfe6f8d 664void lxc_terminal_free(struct lxc_conf *conf, int fd)
63376d7d 665{
0e4be3cf 666 struct lxc_tty_info *ttys = &conf->ttys;
dcad02f8 667 struct lxc_terminal *terminal = &conf->console;
b5159817 668
8703bf5b 669 for (size_t i = 0; i < ttys->max; i++)
0e4be3cf 670 if (ttys->tty[i].busy == fd)
730aaf46 671 ttys->tty[i].busy = -1;
b5159817 672
1b5e93c4
CB
673 if (terminal->proxy.busy != fd)
674 return;
675
41808e20 676 lxc_mainloop_del_handler(terminal->descr, terminal->proxy.pty);
1b5e93c4 677 lxc_terminal_peer_proxy_free(terminal);
b5159817
DE
678}
679
dcad02f8 680static int lxc_terminal_peer_default(struct lxc_terminal *terminal)
b5159817 681{
5b55021f 682 struct lxc_terminal_state *ts;
46768cce 683 const char *path;
467c7ff3 684 int ret = 0;
b5159817 685
46768cce
CB
686 if (terminal->path)
687 path = terminal->path;
688 else
689 path = "/dev/tty";
b5159817 690
2083d59d
CB
691 terminal->peer = lxc_unpriv(open(path, O_RDWR | O_CLOEXEC));
692 if (terminal->peer < 0) {
46768cce
CB
693 if (!terminal->path) {
694 errno = ENODEV;
7874d81a 695 SYSDEBUG("The process does not have a controlling terminal");
46768cce
CB
696 goto on_succes;
697 }
698
6d1400b5 699 SYSERROR("Failed to open proxy terminal \"%s\"", path);
467c7ff3
CB
700 return -ENOTTY;
701 }
49cd0656 702 DEBUG("Using terminal \"%s\" as proxy", path);
b5159817 703
2083d59d 704 if (!isatty(terminal->peer)) {
49cd0656
CB
705 ERROR("File descriptor for \"%s\" does not refer to a terminal", path);
706 goto on_error_free_tios;
467c7ff3 707 }
b5159817 708
36a94ce8 709 ts = lxc_terminal_signal_init(terminal->peer, terminal->ptx);
2083d59d 710 terminal->tty_state = ts;
341c2aed 711 if (!ts) {
0519b5cc 712 WARN("Failed to install signal handler");
49cd0656 713 goto on_error_free_tios;
341c2aed 714 }
b5159817 715
36a94ce8 716 lxc_terminal_winsz(terminal->peer, terminal->ptx);
b5159817 717
2083d59d 718 terminal->tios = malloc(sizeof(*terminal->tios));
49cd0656
CB
719 if (!terminal->tios)
720 goto on_error_free_tios;
b5159817 721
49cd0656
CB
722 ret = lxc_setup_tios(terminal->peer, terminal->tios);
723 if (ret < 0)
724 goto on_error_close_peer;
467c7ff3 725 else
49cd0656 726 goto on_succes;
b5159817 727
49cd0656 728on_error_free_tios:
2083d59d
CB
729 free(terminal->tios);
730 terminal->tios = NULL;
467c7ff3 731
49cd0656 732on_error_close_peer:
2083d59d
CB
733 close(terminal->peer);
734 terminal->peer = -1;
467c7ff3
CB
735 ret = -ENOTTY;
736
49cd0656 737on_succes:
467c7ff3 738 return ret;
b5159817
DE
739}
740
dcad02f8 741int lxc_terminal_write_ringbuffer(struct lxc_terminal *terminal)
39c6cdb7
CB
742{
743 char *r_addr;
744 ssize_t ret;
745 uint64_t used;
2083d59d 746 struct lxc_ringbuf *buf = &terminal->ringbuf;
39c6cdb7
CB
747
748 /* There's not log file where we can dump the ringbuffer to. */
2083d59d 749 if (terminal->log_fd < 0)
39c6cdb7
CB
750 return 0;
751
39c6cdb7
CB
752 used = lxc_ringbuf_used(buf);
753 if (used == 0)
754 return 0;
755
2083d59d 756 ret = lxc_terminal_truncate_log_file(terminal);
39c6cdb7
CB
757 if (ret < 0)
758 return ret;
759
760 /* Write as much as we can without exceeding the limit. */
2083d59d
CB
761 if (terminal->log_size < used)
762 used = terminal->log_size;
39c6cdb7
CB
763
764 r_addr = lxc_ringbuf_get_read_addr(buf);
2083d59d 765 ret = lxc_write_nointr(terminal->log_fd, r_addr, used);
39c6cdb7
CB
766 if (ret < 0)
767 return -EIO;
768
769 return 0;
770}
771
dcad02f8 772void lxc_terminal_delete(struct lxc_terminal *terminal)
b5159817 773{
69629c82
CB
774 int ret;
775
2083d59d 776 ret = lxc_terminal_write_ringbuffer(terminal);
39c6cdb7 777 if (ret < 0)
2083d59d 778 WARN("Failed to write terminal log to disk");
39c6cdb7 779
2083d59d
CB
780 if (terminal->tios && terminal->peer >= 0) {
781 ret = tcsetattr(terminal->peer, TCSAFLUSH, terminal->tios);
69629c82 782 if (ret < 0)
a24c5678 783 SYSWARN("Failed to set old terminal settings");
69629c82 784 }
2083d59d
CB
785 free(terminal->tios);
786 terminal->tios = NULL;
596a818d 787
2083d59d
CB
788 if (terminal->peer >= 0)
789 close(terminal->peer);
790 terminal->peer = -1;
bc9724f7 791
36a94ce8
CB
792 if (terminal->ptx >= 0)
793 close(terminal->ptx);
794 terminal->ptx = -1;
bc9724f7 795
41808e20
CB
796 if (terminal->pty >= 0)
797 close(terminal->pty);
798 terminal->pty = -1;
bc9724f7 799
d926c261
CB
800 terminal->pty_nr = -1;
801
2083d59d
CB
802 if (terminal->log_fd >= 0)
803 close(terminal->log_fd);
804 terminal->log_fd = -1;
63376d7d
DL
805}
806
3b988b33
CB
807/**
808 * Note that this function needs to run before the mainloop starts. Since we
36a94ce8 809 * register a handler for the terminal's ptxfd when we create the mainloop
2083d59d 810 * the terminal handler needs to see an allocated ringbuffer.
3b988b33 811 */
dcad02f8 812static int lxc_terminal_create_ringbuf(struct lxc_terminal *terminal)
3b988b33
CB
813{
814 int ret;
2083d59d
CB
815 struct lxc_ringbuf *buf = &terminal->ringbuf;
816 uint64_t size = terminal->buffer_size;
3b988b33
CB
817
818 /* no ringbuffer previously allocated and no ringbuffer requested */
819 if (!buf->addr && size <= 0)
820 return 0;
821
822 /* ringbuffer allocated but no new ringbuffer requested */
823 if (buf->addr && size <= 0) {
824 lxc_ringbuf_release(buf);
825 buf->addr = NULL;
826 buf->r_off = 0;
827 buf->w_off = 0;
828 buf->size = 0;
2083d59d 829 TRACE("Deallocated terminal ringbuffer");
3b988b33
CB
830 return 0;
831 }
832
833 if (size <= 0)
834 return 0;
835
836 /* check wether the requested size for the ringbuffer has changed */
837 if (buf->addr && buf->size != size) {
2083d59d
CB
838 TRACE("Terminal ringbuffer size changed from %" PRIu64
839 " to %" PRIu64 " bytes. Deallocating terminal ringbuffer",
3b988b33
CB
840 buf->size, size);
841 lxc_ringbuf_release(buf);
842 }
843
844 ret = lxc_ringbuf_create(buf, size);
845 if (ret < 0) {
2083d59d 846 ERROR("Failed to setup %" PRIu64 " byte terminal ringbuffer", size);
3b988b33
CB
847 return -1;
848 }
849
2083d59d 850 TRACE("Allocated %" PRIu64 " byte terminal ringbuffer", size);
3b988b33
CB
851 return 0;
852}
853
a0309168 854/**
2083d59d
CB
855 * This is the terminal log file. Please note that the terminal log file is
856 * (implementation wise not content wise) independent of the terminal ringbuffer.
a0309168 857 */
dcad02f8 858int lxc_terminal_create_log_file(struct lxc_terminal *terminal)
a0309168 859{
2083d59d 860 if (!terminal->log_path)
a0309168
CB
861 return 0;
862
2083d59d
CB
863 terminal->log_fd = lxc_unpriv(open(terminal->log_path, O_CLOEXEC | O_RDWR | O_CREAT | O_APPEND, 0600));
864 if (terminal->log_fd < 0) {
865 SYSERROR("Failed to open terminal log file \"%s\"", terminal->log_path);
a0309168
CB
866 return -1;
867 }
868
2083d59d 869 DEBUG("Using \"%s\" as terminal log file", terminal->log_path);
a0309168
CB
870 return 0;
871}
872
8ea93a0f
CB
873static int lxc_terminal_map_ids(struct lxc_conf *c, struct lxc_terminal *terminal)
874{
875 int ret;
876
0589d744 877 if (list_empty(&c->id_map))
8ea93a0f
CB
878 return 0;
879
880 if (is_empty_string(terminal->name) && terminal->pty < 0)
881 return 0;
882
883 if (terminal->pty >= 0)
884 ret = userns_exec_mapped_root(NULL, terminal->pty, c);
885 else
886 ret = userns_exec_mapped_root(terminal->name, -EBADF, c);
887 if (ret < 0)
888 return log_error(-1, "Failed to chown terminal %d(%s)", terminal->pty,
889 !is_empty_string(terminal->name) ? terminal->name : "(null)");
890
891 TRACE("Chowned terminal %d(%s)", terminal->pty,
892 !is_empty_string(terminal->name) ? terminal->name : "(null)");
893
894 return 0;
895}
896
897static int lxc_terminal_create_foreign(struct lxc_conf *conf, struct lxc_terminal *terminal)
63376d7d 898{
8ded9244 899 int ret;
b5159817 900
41808e20 901 ret = openpty(&terminal->ptx, &terminal->pty, NULL, NULL, NULL);
467c7ff3 902 if (ret < 0) {
8ded9244 903 SYSERROR("Failed to open terminal");
b5159817
DE
904 return -1;
905 }
906
8ea93a0f
CB
907 ret = lxc_terminal_map_ids(conf, terminal);
908 if (ret < 0) {
909 SYSERROR("Failed to change ownership of terminal multiplexer device");
910 goto err;
911 }
912
41808e20 913 ret = ttyname_r(terminal->pty, terminal->name, sizeof(terminal->name));
3f15bdd9 914 if (ret < 0) {
41808e20 915 SYSERROR("Failed to retrieve name of terminal pty");
3f15bdd9
CB
916 goto err;
917 }
918
36a94ce8 919 ret = fd_cloexec(terminal->ptx, true);
69629c82 920 if (ret < 0) {
36a94ce8 921 SYSERROR("Failed to set FD_CLOEXEC flag on terminal ptx");
b5159817
DE
922 goto err;
923 }
924
41808e20 925 ret = fd_cloexec(terminal->pty, true);
69629c82 926 if (ret < 0) {
41808e20 927 SYSERROR("Failed to set FD_CLOEXEC flag on terminal pty");
b5159817
DE
928 goto err;
929 }
930
2083d59d 931 ret = lxc_terminal_peer_default(terminal);
467c7ff3 932 if (ret < 0) {
8ded9244 933 ERROR("Failed to allocate proxy terminal");
467c7ff3
CB
934 goto err;
935 }
b5159817 936
5777fe90
CB
937 return 0;
938
939err:
2083d59d 940 lxc_terminal_delete(terminal);
5777fe90
CB
941 return -ENODEV;
942}
943
18129d94
CB
944int lxc_devpts_terminal(int devpts_fd, int *ret_ptx, int *ret_pty,
945 int *ret_pty_nr, bool require_tiocgptpeer)
f797f05e 946{
803839b8
CB
947 __do_close int fd_devpts = -EBADF, fd_ptx = -EBADF,
948 fd_opath_pty = -EBADF, fd_pty = -EBADF;
cb01e311 949 int pty_nr = -1;
f797f05e
CB
950 int ret;
951
803839b8
CB
952 /*
953 * When we aren't told what devpts instance to allocate from we assume
954 * it is the one in the caller's mount namespace.
955 * This poses a slight complication, a lot of distros will change
956 * permissions on /dev/ptmx so it can be opened by unprivileged users
957 * but will not change permissions on /dev/pts/ptmx itself. In
958 * addition, /dev/ptmx can either be a symlink, a bind-mount, or a
959 * separate device node. So we need to allow for fairly lax lookup.
960 */
9f77617b 961 if (devpts_fd < 0)
803839b8
CB
962 fd_ptx = open_at(-EBADF, "/dev/ptmx", PROTECT_OPEN_RW & ~O_NOFOLLOW,
963 PROTECT_LOOKUP_ABSOLUTE_XDEV_SYMLINKS, 0);
964 else
965 fd_ptx = open_beneath(devpts_fd, "ptmx", O_RDWR | O_NOCTTY | O_CLOEXEC);
4655bdd1 966 if (fd_ptx < 0) {
7a316559
CB
967 if (errno == ENOSPC)
968 return systrace("Exceeded number of allocatable terminals");
969
0cf017f0 970 return syswarn("Failed to open terminal multiplexer device");
7a316559 971 }
f797f05e 972
803839b8
CB
973 if (devpts_fd < 0) {
974 fd_devpts = open_at(-EBADF, "/dev/pts", PROTECT_OPATH_DIRECTORY,
975 PROTECT_LOOKUP_ABSOLUTE_XDEV, 0);
976 if (fd_devpts < 0)
0cf017f0 977 return syswarn("Failed to open devpts instance");
803839b8
CB
978
979 if (!same_device(fd_devpts, "ptmx", fd_ptx, ""))
0cf017f0 980 return syswarn("The acquired ptmx devices don't match");
803839b8
CB
981 devpts_fd = fd_devpts;
982 }
983
4655bdd1
CB
984 ret = unlockpt(fd_ptx);
985 if (ret < 0)
986 return syswarn_set(-ENODEV, "Failed to unlock multiplexer device device");
f797f05e 987
4655bdd1
CB
988 fd_pty = ioctl(fd_ptx, TIOCGPTPEER, O_RDWR | O_NOCTTY | O_CLOEXEC);
989 if (fd_pty < 0) {
f382bcc6
CB
990 switch (errno) {
991 case ENOTTY:
992 SYSTRACE("Pure fd-based terminal allocation not possible");
993 break;
994 case ENOSPC:
7a316559 995 SYSTRACE("Exceeded number of allocatable terminals");
f382bcc6
CB
996 break;
997 default:
998 SYSWARN("Failed to allocate new pty device");
64ac925f 999 return -errno;
f382bcc6 1000 }
f797f05e 1001
64ac925f 1002 /* The caller tells us that they trust the devpts instance. */
18129d94
CB
1003 if (require_tiocgptpeer)
1004 return ret_errno(ENODEV);
8ea93a0f 1005 }
f797f05e 1006
4655bdd1
CB
1007 ret = ioctl(fd_ptx, TIOCGPTN, &pty_nr);
1008 if (ret)
1009 return syswarn_set(-ENODEV, "Failed to retrieve name of terminal pty");
cb01e311 1010
18129d94
CB
1011 if (fd_pty < 0) {
1012 /*
1013 * If we end up it means that TIOCGPTPEER isn't supported but
1014 * the caller told us they trust the devpts instance so we use
1015 * the pty nr to open the pty side.
1016 */
1017 fd_pty = open_at(devpts_fd, fdstr(pty_nr), PROTECT_OPEN_RW,
1018 PROTECT_LOOKUP_ABSOLUTE_XDEV, 0);
1019 if (fd_pty < 0)
1020 return syswarn_set(-ENODEV, "Failed to open terminal pty fd by path %d/%d",
1021 devpts_fd, pty_nr);
1022 } else {
1023 fd_opath_pty = open_at(devpts_fd, fdstr(pty_nr), PROTECT_OPATH_FILE,
1024 PROTECT_LOOKUP_ABSOLUTE_XDEV, 0);
1025 if (fd_opath_pty < 0)
1026 return syswarn_set(-ENODEV, "Failed to open terminal pty fd by path %d/%d",
1027 devpts_fd, pty_nr);
1028
1029 if (!same_file_lax(fd_pty, fd_opath_pty))
1030 return syswarn_set(-ENODEV, "Terminal file descriptor changed");
1031 }
4655bdd1 1032
4655bdd1
CB
1033 *ret_ptx = move_fd(fd_ptx);
1034 *ret_pty = move_fd(fd_pty);
d926c261 1035 *ret_pty_nr = pty_nr;
4655bdd1
CB
1036 return 0;
1037}
1038
9f77617b
CB
1039int lxc_terminal_parent(struct lxc_conf *conf)
1040{
9f77617b
CB
1041 struct lxc_terminal *console = &conf->console;
1042 int ret;
1043
1044 if (!wants_console(&conf->console))
1045 return 0;
1046
1047 /* Allocate console from the container's devpts. */
1048 if (conf->pty_max > 1)
1049 return 0;
1050
1051 /* Allocate console for the container from the host's devpts. */
803839b8 1052 ret = lxc_devpts_terminal(-EBADF, &console->ptx, &console->pty,
18129d94 1053 &console->pty_nr, false);
9f77617b
CB
1054 if (ret < 0)
1055 return syserror("Failed to allocate console");
1056
1057 ret = strnprintf(console->name, sizeof(console->name),
1058 "/dev/pts/%d", console->pty_nr);
1059 if (ret < 0)
1060 return syserror("Failed to create console path");
1061
1062 return lxc_terminal_map_ids(conf, &conf->console);
1063}
1064
4655bdd1 1065static int lxc_terminal_create_native(const char *name, const char *lxcpath,
4655bdd1
CB
1066 struct lxc_terminal *terminal)
1067{
1068 __do_close int devpts_fd = -EBADF;
1069 int ret;
1070
1071 devpts_fd = lxc_cmd_get_devpts_fd(name, lxcpath);
1072 if (devpts_fd < 0)
23cc33cd 1073 return sysinfo("Failed to receive devpts fd");
4655bdd1 1074
4dcf0c43 1075 ret = lxc_devpts_terminal(devpts_fd, &terminal->ptx, &terminal->pty,
18129d94 1076 &terminal->pty_nr, true);
4655bdd1
CB
1077 if (ret < 0)
1078 return ret;
cb01e311 1079
d926c261
CB
1080 ret = strnprintf(terminal->name, sizeof(terminal->name),
1081 "/dev/pts/%d", terminal->pty_nr);
1082 if (ret < 0)
1083 return syserror("Failed to create path");
1084
f797f05e
CB
1085 ret = lxc_terminal_peer_default(terminal);
1086 if (ret < 0) {
4655bdd1
CB
1087 lxc_terminal_delete(terminal);
1088 return syswarn_set(-ENODEV, "Failed to allocate proxy terminal");
f797f05e
CB
1089 }
1090
1091 return 0;
f797f05e
CB
1092}
1093
550ede0a
CB
1094int lxc_terminal_create(const char *name, const char *lxcpath,
1095 struct lxc_conf *conf, struct lxc_terminal *terminal)
f797f05e 1096{
4dcf0c43 1097 if (!lxc_terminal_create_native(name, lxcpath, terminal))
f797f05e
CB
1098 return 0;
1099
8ea93a0f 1100 return lxc_terminal_create_foreign(conf, terminal);
f797f05e
CB
1101}
1102
564e31c4 1103int lxc_terminal_setup(struct lxc_conf *conf)
5777fe90
CB
1104{
1105 int ret;
dcad02f8 1106 struct lxc_terminal *terminal = &conf->console;
5777fe90 1107
5ef86378
CB
1108 if (terminal->path && strequal(terminal->path, "none"))
1109 return log_info(0, "No terminal requested");
5777fe90 1110
9f77617b 1111 ret = lxc_terminal_peer_default(terminal);
5777fe90 1112 if (ret < 0)
9f77617b 1113 goto err;
5777fe90 1114
2083d59d 1115 ret = lxc_terminal_create_log_file(terminal);
a0309168
CB
1116 if (ret < 0)
1117 goto err;
1118
2083d59d 1119 ret = lxc_terminal_create_ringbuf(terminal);
a0309168
CB
1120 if (ret < 0)
1121 goto err;
b5159817
DE
1122
1123 return 0;
1124
1125err:
2083d59d 1126 lxc_terminal_delete(terminal);
69629c82 1127 return -ENODEV;
b5159817
DE
1128}
1129
8ca7b374
CB
1130static bool __terminal_dup2(int duplicate, int original)
1131{
1132 int ret;
1133
1134 if (!isatty(original))
1135 return true;
1136
1137 ret = dup2(duplicate, original);
1138 if (ret < 0) {
1139 SYSERROR("Failed to dup2(%d, %d)", duplicate, original);
1140 return false;
1141 }
1142
1143 return true;
1144}
1145
ae6d3913 1146int lxc_terminal_set_stdfds(int fd)
0d9acb99 1147{
8ca7b374
CB
1148 int i;
1149
39a78bbe 1150 if (fd < 0)
0d9acb99 1151 return 0;
b5159817 1152
8ca7b374
CB
1153 for (i = 0; i < 3; i++)
1154 if (!__terminal_dup2(fd, (int[]){STDIN_FILENO, STDOUT_FILENO,
1155 STDERR_FILENO}[i]))
39a78bbe 1156 return -1;
39a78bbe 1157
0d9acb99
DE
1158 return 0;
1159}
b5159817 1160
52f9292f 1161int lxc_terminal_stdin_cb(int fd, uint32_t events, void *cbdata,
3298b37d 1162 struct lxc_async_descr *descr)
b5159817 1163{
15085292 1164 int ret;
b5159817 1165 char c;
15085292 1166 struct lxc_terminal_state *ts = cbdata;
b5159817 1167
97bc2422 1168 if (fd != ts->stdinfd)
a529bc25 1169 return LXC_MAINLOOP_CLOSE;
97bc2422 1170
15085292
CB
1171 ret = lxc_read_nointr(ts->stdinfd, &c, 1);
1172 if (ret <= 0)
a529bc25 1173 return LXC_MAINLOOP_CLOSE;
63376d7d 1174
525e2117 1175 if (ts->escape >= 1) {
2083d59d 1176 /* we want to exit the terminal with Ctrl+a q */
014d5e1e
CB
1177 if (c == ts->escape && !ts->saw_escape) {
1178 ts->saw_escape = 1;
15085292 1179 return LXC_MAINLOOP_CONTINUE;
014d5e1e 1180 }
5c294060 1181
014d5e1e 1182 if (c == 'q' && ts->saw_escape)
a529bc25 1183 return LXC_MAINLOOP_CLOSE;
014d5e1e
CB
1184
1185 ts->saw_escape = 0;
1186 }
63376d7d 1187
36a94ce8 1188 ret = lxc_write_nointr(ts->ptxfd, &c, 1);
15085292 1189 if (ret <= 0)
a529bc25 1190 return LXC_MAINLOOP_CLOSE;
b5159817 1191
15085292 1192 return LXC_MAINLOOP_CONTINUE;
63376d7d
DL
1193}
1194
36a94ce8 1195int lxc_terminal_ptx_cb(int fd, uint32_t events, void *cbdata,
3298b37d 1196 struct lxc_async_descr *descr)
63376d7d 1197{
0d4137cc 1198 int r, w;
5bd171bd
CB
1199 char buf[LXC_TERMINAL_BUFFER_SIZE];
1200 struct lxc_terminal_state *ts = cbdata;
63376d7d 1201
36a94ce8 1202 if (fd != ts->ptxfd)
a529bc25 1203 return LXC_MAINLOOP_CLOSE;
97bc2422 1204
e66b6c96
CB
1205 r = lxc_read_nointr(fd, buf, sizeof(buf));
1206 if (r <= 0)
a529bc25 1207 return LXC_MAINLOOP_CLOSE;
1560f6c9 1208
e66b6c96 1209 w = lxc_write_nointr(ts->stdoutfd, buf, r);
5bd171bd 1210 if (w <= 0 || w != r)
a529bc25 1211 return LXC_MAINLOOP_CLOSE;
f78a1f32 1212
5bd171bd 1213 return LXC_MAINLOOP_CONTINUE;
b5159817
DE
1214}
1215
36a94ce8 1216int lxc_terminal_getfd(struct lxc_container *c, int *ttynum, int *ptxfd)
b5159817 1217{
7e85a2c4 1218 return lxc_cmd_get_tty_fd(c->name, ttynum, ptxfd, c->config_path);
b5159817
DE
1219}
1220
1221int lxc_console(struct lxc_container *c, int ttynum,
1222 int stdinfd, int stdoutfd, int stderrfd,
1223 int escape)
1224{
36a94ce8 1225 int ptxfd, ret, ttyfd;
3298b37d 1226 struct lxc_async_descr descr;
b5159817 1227 struct termios oldtios;
5b55021f 1228 struct lxc_terminal_state *ts;
28327a43
CB
1229 struct lxc_terminal terminal = {
1230 .tty_state = NULL,
1231 };
25964232 1232 int istty = 0;
b5159817 1233
7e85a2c4 1234 ttyfd = lxc_cmd_get_tty_fd(c->name, &ttynum, &ptxfd, c->config_path);
6834f805
CB
1235 if (ttyfd < 0)
1236 return -1;
b5159817
DE
1237
1238 ret = setsid();
33b4b411
CB
1239 if (ret < 0)
1240 TRACE("Process is already group leader");
b5159817 1241
36a94ce8 1242 ts = lxc_terminal_signal_init(stdinfd, ptxfd);
b5159817
DE
1243 if (!ts) {
1244 ret = -1;
33b4b411 1245 goto close_fds;
b5159817 1246 }
28327a43 1247 terminal.tty_state = ts;
b5159817 1248 ts->escape = escape;
3b975060 1249 ts->stdoutfd = stdoutfd;
b5159817 1250
6834f805 1251 istty = isatty(stdinfd);
25964232 1252 if (istty) {
36a94ce8
CB
1253 lxc_terminal_winsz(stdinfd, ptxfd);
1254 lxc_terminal_winsz(ts->stdinfd, ts->ptxfd);
6834f805 1255 } else {
71ac3f07 1256 INFO("File descriptor %d does not refer to a terminal", stdinfd);
25964232 1257 }
b5159817
DE
1258
1259 ret = lxc_mainloop_open(&descr);
1260 if (ret) {
33b4b411
CB
1261 ERROR("Failed to create mainloop");
1262 goto sigwinch_fini;
b5159817
DE
1263 }
1264
341c2aed
CB
1265 if (ts->sigfd != -1) {
1266 ret = lxc_mainloop_add_handler(&descr, ts->sigfd,
543d2f83
CB
1267 lxc_terminal_signalfd_cb,
1268 default_cleanup_handler,
1269 ts, "lxc_terminal_signalfd_cb");
33b4b411 1270 if (ret < 0) {
0519b5cc 1271 ERROR("Failed to add signal handler to mainloop");
33b4b411 1272 goto close_mainloop;
341c2aed 1273 }
b5159817
DE
1274 }
1275
1276 ret = lxc_mainloop_add_handler(&descr, ts->stdinfd,
543d2f83
CB
1277 lxc_terminal_stdin_cb,
1278 default_cleanup_handler,
1279 ts, "lxc_terminal_stdin_cb");
33b4b411
CB
1280 if (ret < 0) {
1281 ERROR("Failed to add stdin handler");
1282 goto close_mainloop;
b5159817
DE
1283 }
1284
36a94ce8 1285 ret = lxc_mainloop_add_handler(&descr, ts->ptxfd,
543d2f83
CB
1286 lxc_terminal_ptx_cb,
1287 default_cleanup_handler,
1288 ts, "lxc_terminal_ptx_cb");
33b4b411 1289 if (ret < 0) {
36a94ce8 1290 ERROR("Failed to add ptx handler");
33b4b411 1291 goto close_mainloop;
b5159817
DE
1292 }
1293
686df166
CB
1294 if (ts->escape >= 1) {
1295 fprintf(stderr,
1296 "\n"
6834f805
CB
1297 "Connected to tty %1$d\n"
1298 "Type <Ctrl+%2$c q> to exit the console, "
1299 "<Ctrl+%2$c Ctrl+%2$c> to enter Ctrl+%2$c itself\n",
1300 ttynum, 'a' + escape - 1);
686df166 1301 }
6834f805
CB
1302
1303 if (istty) {
1304 ret = lxc_setup_tios(stdinfd, &oldtios);
1305 if (ret < 0)
1306 goto close_mainloop;
1307 }
1308
025ed0f3 1309 ret = lxc_mainloop(&descr, -1);
33b4b411
CB
1310 if (ret < 0) {
1311 ERROR("The mainloop returned an error");
6834f805 1312 goto restore_tios;
b5159817
DE
1313 }
1314
1315 ret = 0;
1316
6834f805
CB
1317restore_tios:
1318 if (istty) {
1319 istty = tcsetattr(stdinfd, TCSAFLUSH, &oldtios);
1320 if (istty < 0)
a24c5678 1321 SYSWARN("Failed to restore terminal properties");
6834f805
CB
1322 }
1323
33b4b411 1324close_mainloop:
b5159817 1325 lxc_mainloop_close(&descr);
33b4b411
CB
1326
1327sigwinch_fini:
28327a43 1328 lxc_terminal_signal_fini(&terminal);
33b4b411
CB
1329
1330close_fds:
36a94ce8 1331 close(ptxfd);
b5159817 1332 close(ttyfd);
33b4b411 1333
b5159817 1334 return ret;
63376d7d 1335}
e98affda 1336
cd0a2b2f 1337int lxc_make_controlling_terminal(int fd)
e98affda
CB
1338{
1339 int ret;
1340
1341 setsid();
1342
1343 ret = ioctl(fd, TIOCSCTTY, (char *)NULL);
1344 if (ret < 0)
1345 return -1;
1346
1347 return 0;
1348}
1349
d049f0e9 1350int lxc_terminal_prepare_login(int fd)
e98affda
CB
1351{
1352 int ret;
1353
cd0a2b2f 1354 ret = lxc_make_controlling_terminal(fd);
e98affda
CB
1355 if (ret < 0)
1356 return -1;
1357
ae6d3913 1358 ret = lxc_terminal_set_stdfds(fd);
e98affda
CB
1359 if (ret < 0)
1360 return -1;
1361
1362 if (fd > STDERR_FILENO)
1363 close(fd);
1364
1365 return 0;
1366}
1367
e9a55b51 1368void lxc_terminal_info_init(struct lxc_terminal_info *terminal)
e98affda 1369{
e9a55b51 1370 terminal->name[0] = '\0';
36a94ce8 1371 terminal->ptx = -EBADF;
41808e20 1372 terminal->pty = -EBADF;
e9a55b51 1373 terminal->busy = -1;
3b9f84fd 1374 terminal->pty_nr = -1;
e98affda
CB
1375}
1376
e9a55b51 1377void lxc_terminal_init(struct lxc_terminal *terminal)
e98affda 1378{
e9a55b51 1379 memset(terminal, 0, sizeof(*terminal));
d926c261 1380 terminal->pty_nr = -1;
41808e20 1381 terminal->pty = -EBADF;
36a94ce8 1382 terminal->ptx = -EBADF;
e9a55b51
CB
1383 terminal->peer = -EBADF;
1384 terminal->log_fd = -EBADF;
1385 lxc_terminal_info_init(&terminal->proxy);
e98affda
CB
1386}
1387
dcad02f8 1388void lxc_terminal_conf_free(struct lxc_terminal *terminal)
e98affda 1389{
2083d59d
CB
1390 free(terminal->log_path);
1391 free(terminal->path);
1392 if (terminal->buffer_size > 0 && terminal->ringbuf.addr)
1393 lxc_ringbuf_release(&terminal->ringbuf);
28327a43 1394 lxc_terminal_signal_fini(terminal);
e98affda 1395}