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