]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/terminal.c
Merge pull request #3689 from brauner/2021-02-21/fixes
[mirror_lxc.git] / src / lxc / terminal.c
CommitLineData
cc73685d 1/* SPDX-License-Identifier: LGPL-2.1+ */
b0a33c1e 2
d38dd64a
CB
3#ifndef _GNU_SOURCE
4#define _GNU_SOURCE 1
5#endif
9395937a
CB
6#include <errno.h>
7#include <fcntl.h>
e62912bd 8#include <lxc/lxccontainer.h>
b467714b 9#include <pthread.h>
b5159817 10#include <signal.h>
b0a33c1e 11#include <stdio.h>
e0dc0de7 12#include <stdlib.h>
da41561c
CB
13#include <sys/epoll.h>
14#include <sys/types.h>
e62912bd
CB
15#include <termios.h>
16#include <unistd.h>
f2363e38 17
9395937a
CB
18#include "af_unix.h"
19#include "caps.h"
20#include "commands.h"
00dbc43e 21#include "conf.h"
e827ff7e 22#include "config.h"
9395937a 23#include "log.h"
b5159817 24#include "lxclock.h"
9395937a 25#include "mainloop.h"
2530ba95 26#include "memory_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
35#include <../include/openpty.h>
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
CB
71int lxc_terminal_signalfd_cb(int fd, uint32_t events, void *cbdata,
72 struct lxc_epoll_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
254 * he's requesting us to do weird stuff.
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
99a04585
CB
273 if (bytes_read <= terminal->log_size)
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
99a04585 304 if (terminal->log_size < 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
de708fb7 331int lxc_terminal_io_cb(int fd, uint32_t events, void *data,
a529bc25 332 struct lxc_epoll_descr *descr)
b5159817 333{
dcad02f8 334 struct lxc_terminal *terminal = data;
de708fb7 335 char buf[LXC_TERMINAL_BUFFER_SIZE];
732375f5 336 int r, w, w_log, w_rbuf;
e0dc0de7 337
3e6580ec
CB
338 w = r = lxc_read_nointr(fd, buf, sizeof(buf));
339 if (r <= 0) {
de708fb7 340 INFO("Terminal client on fd %d has exited", fd);
b5159817 341 lxc_mainloop_del_handler(descr, fd);
c06a0555 342
36a94ce8
CB
343 if (fd == terminal->ptx) {
344 terminal->ptx = -EBADF;
de708fb7 345 } else if (fd == terminal->peer) {
28327a43 346 lxc_terminal_signal_fini(terminal);
de708fb7 347 terminal->peer = -EBADF;
c06a0555
CB
348 } else {
349 ERROR("Handler received unexpected file descriptor");
0b1e242b 350 }
b5159817 351 close(fd);
c06a0555 352
a529bc25 353 return LXC_MAINLOOP_CLOSE;
33fcb7a0 354 }
63376d7d 355
de708fb7 356 if (fd == terminal->peer)
36a94ce8 357 w = lxc_write_nointr(terminal->ptx, buf, r);
b5159817 358
732375f5 359 w_rbuf = w_log = 0;
36a94ce8 360 if (fd == terminal->ptx) {
732375f5 361 /* write to peer first */
de708fb7
CB
362 if (terminal->peer >= 0)
363 w = lxc_write_nointr(terminal->peer, buf, r);
732375f5 364
de708fb7
CB
365 /* write to terminal ringbuffer */
366 if (terminal->buffer_size > 0)
367 w_rbuf = lxc_ringbuf_write(&terminal->ringbuf, buf, r);
861813e5 368
de708fb7
CB
369 /* write to terminal log */
370 if (terminal->log_fd >= 0)
a44ae1a9 371 w_log = lxc_terminal_write_log_file(terminal, buf, r);
63376d7d
DL
372 }
373
b5159817 374 if (w != r)
de708fb7 375 WARN("Short write on terminal r:%d != w:%d", r, w);
732375f5 376
7874d81a 377 if (w_rbuf < 0) {
378 errno = -w_rbuf;
379 SYSTRACE("Failed to write %d bytes to terminal ringbuffer", r);
380 }
732375f5
CB
381
382 if (w_log < 0)
de708fb7 383 TRACE("Failed to write %d bytes to terminal log", r);
0d4137cc 384
2b8bf299 385 return LXC_MAINLOOP_CONTINUE;
b5159817
DE
386}
387
dcad02f8 388static int lxc_terminal_mainloop_add_peer(struct lxc_terminal *terminal)
b5159817 389{
a529bc25
CB
390 int ret;
391
2083d59d
CB
392 if (terminal->peer >= 0) {
393 ret = lxc_mainloop_add_handler(terminal->descr, terminal->peer,
394 lxc_terminal_io_cb, terminal);
a529bc25 395 if (ret < 0) {
2083d59d 396 WARN("Failed to add terminal peer handler to mainloop");
a529bc25
CB
397 return -1;
398 }
63376d7d
DL
399 }
400
2083d59d 401 if (!terminal->tty_state || terminal->tty_state->sigfd < 0)
a529bc25
CB
402 return 0;
403
2083d59d
CB
404 ret = lxc_mainloop_add_handler(terminal->descr, terminal->tty_state->sigfd,
405 lxc_terminal_signalfd_cb, terminal->tty_state);
a529bc25
CB
406 if (ret < 0) {
407 WARN("Failed to add signal handler to mainloop");
408 return -1;
b5159817 409 }
a529bc25
CB
410
411 return 0;
b5159817
DE
412}
413
093bce5f 414int lxc_terminal_mainloop_add(struct lxc_epoll_descr *descr,
ea5b3c23 415 struct lxc_terminal *terminal)
b5159817 416{
a529bc25 417 int ret;
b5159817 418
36a94ce8 419 if (terminal->ptx < 0) {
2083d59d 420 INFO("Terminal is not initialized");
b5159817 421 return 0;
596a818d
DE
422 }
423
36a94ce8 424 ret = lxc_mainloop_add_handler(descr, terminal->ptx,
2083d59d 425 lxc_terminal_io_cb, terminal);
30a33fbd 426 if (ret < 0) {
36a94ce8
CB
427 ERROR("Failed to add handler for terminal ptx fd %d to "
428 "mainloop", terminal->ptx);
b5159817 429 return -1;
28a4b0e5
DL
430 }
431
30a33fbd 432 /* We cache the descr so that we can add an fd to it when someone
c1ee47cd 433 * does attach to it in lxc_terminal_allocate().
b5159817 434 */
2083d59d 435 terminal->descr = descr;
cd453b38 436
ea5b3c23 437 return lxc_terminal_mainloop_add_peer(terminal);
b5159817 438}
28a4b0e5 439
0d4137cc 440int lxc_setup_tios(int fd, struct termios *oldtios)
b5159817 441{
e4953e62 442 int ret;
b5159817 443 struct termios newtios;
e0dc0de7 444
b5159817 445 if (!isatty(fd)) {
8332a09c 446 ERROR("File descriptor %d does not refer to a terminal", fd);
b5159817 447 return -1;
e0dc0de7
DL
448 }
449
e4953e62
CB
450 /* Get current termios. */
451 ret = tcgetattr(fd, oldtios);
452 if (ret < 0) {
453 SYSERROR("Failed to get current terminal settings");
b5159817 454 return -1;
e0dc0de7
DL
455 }
456
4dc96430
TJ
457 /* ensure we don't end up in an endless loop:
458 * The kernel might fire SIGTTOU while an
459 * ioctl() in tcsetattr() is executed. When the ioctl()
460 * is resumed and retries, the signal handler interrupts it again.
461 */
462 signal (SIGTTIN, SIG_IGN);
463 signal (SIGTTOU, SIG_IGN);
464
b5159817 465 newtios = *oldtios;
e0dc0de7 466
a7c97a40
CB
467 /* We use the same settings that ssh does. */
468 newtios.c_iflag |= IGNPAR;
469 newtios.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF);
470#ifdef IUCLC
471 newtios.c_iflag &= ~IUCLC;
472#endif
4dc96430 473 newtios.c_lflag &= ~(TOSTOP | ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL);
a7c97a40
CB
474#ifdef IEXTEN
475 newtios.c_lflag &= ~IEXTEN;
476#endif
e5adb2b5 477 newtios.c_oflag &= ~ONLCR;
300ec717 478 newtios.c_oflag |= OPOST;
b5159817
DE
479 newtios.c_cc[VMIN] = 1;
480 newtios.c_cc[VTIME] = 0;
e0dc0de7 481
a7c97a40 482 /* Set new attributes. */
e4953e62
CB
483 ret = tcsetattr(fd, TCSAFLUSH, &newtios);
484 if (ret < 0) {
485 ERROR("Failed to set new terminal settings");
b5159817 486 return -1;
e0dc0de7
DL
487 }
488
63376d7d 489 return 0;
b5159817 490}
e0dc0de7 491
dcad02f8 492static void lxc_terminal_peer_proxy_free(struct lxc_terminal *terminal)
b5159817 493{
28327a43 494 lxc_terminal_signal_fini(terminal);
e788f4ac 495
36a94ce8
CB
496 close(terminal->proxy.ptx);
497 terminal->proxy.ptx = -1;
e788f4ac 498
41808e20
CB
499 close(terminal->proxy.pty);
500 terminal->proxy.pty = -1;
e788f4ac 501
fb87aa6a 502 terminal->proxy.busy = -1;
e788f4ac 503
fb87aa6a 504 terminal->proxy.name[0] = '\0';
e788f4ac 505
2083d59d 506 terminal->peer = -1;
b5159817 507}
596a818d 508
60dd8ef4
CB
509static int lxc_terminal_peer_proxy_alloc(struct lxc_terminal *terminal,
510 int sockfd)
b5159817 511{
60dd8ef4 512 int ret;
b5159817 513 struct termios oldtermio;
5b55021f 514 struct lxc_terminal_state *ts;
b5159817 515
36a94ce8 516 if (terminal->ptx < 0) {
2083d59d 517 ERROR("Terminal not set up");
b5159817
DE
518 return -1;
519 }
60dd8ef4 520
fb87aa6a 521 if (terminal->proxy.busy != -1 || terminal->peer != -1) {
2083d59d 522 NOTICE("Terminal already in use");
b5159817
DE
523 return -1;
524 }
60dd8ef4 525
2083d59d 526 if (terminal->tty_state) {
60dd8ef4 527 ERROR("Terminal has already been initialized");
b5159817 528 return -1;
596a818d
DE
529 }
530
d712f9e8 531 /* This is the proxy terminal that will be given to the client, and
36a94ce8 532 * that the real terminal ptx will send to / recv from.
b5159817 533 */
41808e20 534 ret = openpty(&terminal->proxy.ptx, &terminal->proxy.pty, NULL,
3f15bdd9 535 NULL, NULL);
60dd8ef4
CB
536 if (ret < 0) {
537 SYSERROR("Failed to open proxy terminal");
b5159817
DE
538 return -1;
539 }
596a818d 540
41808e20 541 ret = ttyname_r(terminal->proxy.pty, terminal->proxy.name,
3f15bdd9
CB
542 sizeof(terminal->proxy.name));
543 if (ret < 0) {
41808e20 544 SYSERROR("Failed to retrieve name of proxy terminal pty");
3f15bdd9
CB
545 goto on_error;
546 }
547
36a94ce8 548 ret = fd_cloexec(terminal->proxy.ptx, true);
408c18a1 549 if (ret < 0) {
36a94ce8 550 SYSERROR("Failed to set FD_CLOEXEC flag on proxy terminal ptx");
408c18a1
CB
551 goto on_error;
552 }
553
41808e20 554 ret = fd_cloexec(terminal->proxy.pty, true);
408c18a1 555 if (ret < 0) {
41808e20 556 SYSERROR("Failed to set FD_CLOEXEC flag on proxy terminal pty");
408c18a1
CB
557 goto on_error;
558 }
559
41808e20 560 ret = lxc_setup_tios(terminal->proxy.pty, &oldtermio);
60dd8ef4
CB
561 if (ret < 0)
562 goto on_error;
b5159817 563
36a94ce8 564 ts = lxc_terminal_signal_init(terminal->proxy.ptx, terminal->ptx);
b5159817 565 if (!ts)
60dd8ef4 566 goto on_error;
b5159817 567
2083d59d 568 terminal->tty_state = ts;
41808e20 569 terminal->peer = terminal->proxy.pty;
fb87aa6a 570 terminal->proxy.busy = sockfd;
2083d59d 571 ret = lxc_terminal_mainloop_add_peer(terminal);
a529bc25 572 if (ret < 0)
60dd8ef4 573 goto on_error;
b5159817 574
41808e20
CB
575 NOTICE("Opened proxy terminal with ptx fd %d and pty fd %d",
576 terminal->proxy.ptx, terminal->proxy.pty);
b5159817
DE
577 return 0;
578
60dd8ef4 579on_error:
2083d59d 580 lxc_terminal_peer_proxy_free(terminal);
63376d7d
DL
581 return -1;
582}
583
c1ee47cd 584int lxc_terminal_allocate(struct lxc_conf *conf, int sockfd, int *ttyreq)
b5159817 585{
12c2eaaa 586 int ttynum;
36a94ce8 587 int ptxfd = -1;
0e4be3cf 588 struct lxc_tty_info *ttys = &conf->ttys;
dcad02f8 589 struct lxc_terminal *terminal = &conf->console;
b5159817 590
b5159817 591 if (*ttyreq == 0) {
12c2eaaa
CB
592 int ret;
593
594 ret = lxc_terminal_peer_proxy_alloc(terminal, sockfd);
595 if (ret < 0)
b5159817 596 goto out;
12c2eaaa 597
36a94ce8 598 ptxfd = terminal->proxy.ptx;
b5159817
DE
599 goto out;
600 }
601
602 if (*ttyreq > 0) {
885766f5 603 if (*ttyreq > ttys->max)
b5159817
DE
604 goto out;
605
730aaf46 606 if (ttys->tty[*ttyreq - 1].busy >= 0)
b5159817
DE
607 goto out;
608
12c2eaaa 609 /* The requested tty is available. */
b5159817
DE
610 ttynum = *ttyreq;
611 goto out_tty;
612 }
613
12c2eaaa 614 /* Search for next available tty, fixup index tty1 => [0]. */
730aaf46 615 for (ttynum = 1; ttynum <= ttys->max && ttys->tty[ttynum - 1].busy >= 0; ttynum++) {
0d4137cc 616 ;
12c2eaaa 617 }
b5159817 618
12c2eaaa 619 /* We didn't find any available slot for tty. */
885766f5 620 if (ttynum > ttys->max)
b5159817
DE
621 goto out;
622
623 *ttyreq = ttynum;
624
625out_tty:
0e4be3cf 626 ttys->tty[ttynum - 1].busy = sockfd;
36a94ce8 627 ptxfd = ttys->tty[ttynum - 1].ptx;
12c2eaaa 628
b5159817 629out:
36a94ce8 630 return ptxfd;
b5159817
DE
631}
632
3dfe6f8d 633void lxc_terminal_free(struct lxc_conf *conf, int fd)
63376d7d 634{
b5159817 635 int i;
0e4be3cf 636 struct lxc_tty_info *ttys = &conf->ttys;
dcad02f8 637 struct lxc_terminal *terminal = &conf->console;
b5159817 638
885766f5 639 for (i = 0; i < ttys->max; i++)
0e4be3cf 640 if (ttys->tty[i].busy == fd)
730aaf46 641 ttys->tty[i].busy = -1;
b5159817 642
1b5e93c4
CB
643 if (terminal->proxy.busy != fd)
644 return;
645
41808e20 646 lxc_mainloop_del_handler(terminal->descr, terminal->proxy.pty);
1b5e93c4 647 lxc_terminal_peer_proxy_free(terminal);
b5159817
DE
648}
649
dcad02f8 650static int lxc_terminal_peer_default(struct lxc_terminal *terminal)
b5159817 651{
5b55021f 652 struct lxc_terminal_state *ts;
46768cce 653 const char *path;
467c7ff3 654 int ret = 0;
b5159817 655
46768cce
CB
656 if (terminal->path)
657 path = terminal->path;
658 else
659 path = "/dev/tty";
b5159817 660
2083d59d
CB
661 terminal->peer = lxc_unpriv(open(path, O_RDWR | O_CLOEXEC));
662 if (terminal->peer < 0) {
46768cce
CB
663 if (!terminal->path) {
664 errno = ENODEV;
7874d81a 665 SYSDEBUG("The process does not have a controlling terminal");
46768cce
CB
666 goto on_succes;
667 }
668
6d1400b5 669 SYSERROR("Failed to open proxy terminal \"%s\"", path);
467c7ff3
CB
670 return -ENOTTY;
671 }
49cd0656 672 DEBUG("Using terminal \"%s\" as proxy", path);
b5159817 673
2083d59d 674 if (!isatty(terminal->peer)) {
49cd0656
CB
675 ERROR("File descriptor for \"%s\" does not refer to a terminal", path);
676 goto on_error_free_tios;
467c7ff3 677 }
b5159817 678
36a94ce8 679 ts = lxc_terminal_signal_init(terminal->peer, terminal->ptx);
2083d59d 680 terminal->tty_state = ts;
341c2aed 681 if (!ts) {
0519b5cc 682 WARN("Failed to install signal handler");
49cd0656 683 goto on_error_free_tios;
341c2aed 684 }
b5159817 685
36a94ce8 686 lxc_terminal_winsz(terminal->peer, terminal->ptx);
b5159817 687
2083d59d 688 terminal->tios = malloc(sizeof(*terminal->tios));
49cd0656
CB
689 if (!terminal->tios)
690 goto on_error_free_tios;
b5159817 691
49cd0656
CB
692 ret = lxc_setup_tios(terminal->peer, terminal->tios);
693 if (ret < 0)
694 goto on_error_close_peer;
467c7ff3 695 else
49cd0656 696 goto on_succes;
b5159817 697
49cd0656 698on_error_free_tios:
2083d59d
CB
699 free(terminal->tios);
700 terminal->tios = NULL;
467c7ff3 701
49cd0656 702on_error_close_peer:
2083d59d
CB
703 close(terminal->peer);
704 terminal->peer = -1;
467c7ff3
CB
705 ret = -ENOTTY;
706
49cd0656 707on_succes:
467c7ff3 708 return ret;
b5159817
DE
709}
710
dcad02f8 711int lxc_terminal_write_ringbuffer(struct lxc_terminal *terminal)
39c6cdb7
CB
712{
713 char *r_addr;
714 ssize_t ret;
715 uint64_t used;
2083d59d 716 struct lxc_ringbuf *buf = &terminal->ringbuf;
39c6cdb7
CB
717
718 /* There's not log file where we can dump the ringbuffer to. */
2083d59d 719 if (terminal->log_fd < 0)
39c6cdb7
CB
720 return 0;
721
39c6cdb7
CB
722 used = lxc_ringbuf_used(buf);
723 if (used == 0)
724 return 0;
725
2083d59d 726 ret = lxc_terminal_truncate_log_file(terminal);
39c6cdb7
CB
727 if (ret < 0)
728 return ret;
729
730 /* Write as much as we can without exceeding the limit. */
2083d59d
CB
731 if (terminal->log_size < used)
732 used = terminal->log_size;
39c6cdb7
CB
733
734 r_addr = lxc_ringbuf_get_read_addr(buf);
2083d59d 735 ret = lxc_write_nointr(terminal->log_fd, r_addr, used);
39c6cdb7
CB
736 if (ret < 0)
737 return -EIO;
738
739 return 0;
740}
741
dcad02f8 742void lxc_terminal_delete(struct lxc_terminal *terminal)
b5159817 743{
69629c82
CB
744 int ret;
745
2083d59d 746 ret = lxc_terminal_write_ringbuffer(terminal);
39c6cdb7 747 if (ret < 0)
2083d59d 748 WARN("Failed to write terminal log to disk");
39c6cdb7 749
2083d59d
CB
750 if (terminal->tios && terminal->peer >= 0) {
751 ret = tcsetattr(terminal->peer, TCSAFLUSH, terminal->tios);
69629c82 752 if (ret < 0)
a24c5678 753 SYSWARN("Failed to set old terminal settings");
69629c82 754 }
2083d59d
CB
755 free(terminal->tios);
756 terminal->tios = NULL;
596a818d 757
2083d59d
CB
758 if (terminal->peer >= 0)
759 close(terminal->peer);
760 terminal->peer = -1;
bc9724f7 761
36a94ce8
CB
762 if (terminal->ptx >= 0)
763 close(terminal->ptx);
764 terminal->ptx = -1;
bc9724f7 765
41808e20
CB
766 if (terminal->pty >= 0)
767 close(terminal->pty);
768 terminal->pty = -1;
bc9724f7 769
2083d59d
CB
770 if (terminal->log_fd >= 0)
771 close(terminal->log_fd);
772 terminal->log_fd = -1;
63376d7d
DL
773}
774
3b988b33
CB
775/**
776 * Note that this function needs to run before the mainloop starts. Since we
36a94ce8 777 * register a handler for the terminal's ptxfd when we create the mainloop
2083d59d 778 * the terminal handler needs to see an allocated ringbuffer.
3b988b33 779 */
dcad02f8 780static int lxc_terminal_create_ringbuf(struct lxc_terminal *terminal)
3b988b33
CB
781{
782 int ret;
2083d59d
CB
783 struct lxc_ringbuf *buf = &terminal->ringbuf;
784 uint64_t size = terminal->buffer_size;
3b988b33
CB
785
786 /* no ringbuffer previously allocated and no ringbuffer requested */
787 if (!buf->addr && size <= 0)
788 return 0;
789
790 /* ringbuffer allocated but no new ringbuffer requested */
791 if (buf->addr && size <= 0) {
792 lxc_ringbuf_release(buf);
793 buf->addr = NULL;
794 buf->r_off = 0;
795 buf->w_off = 0;
796 buf->size = 0;
2083d59d 797 TRACE("Deallocated terminal ringbuffer");
3b988b33
CB
798 return 0;
799 }
800
801 if (size <= 0)
802 return 0;
803
804 /* check wether the requested size for the ringbuffer has changed */
805 if (buf->addr && buf->size != size) {
2083d59d
CB
806 TRACE("Terminal ringbuffer size changed from %" PRIu64
807 " to %" PRIu64 " bytes. Deallocating terminal ringbuffer",
3b988b33
CB
808 buf->size, size);
809 lxc_ringbuf_release(buf);
810 }
811
812 ret = lxc_ringbuf_create(buf, size);
813 if (ret < 0) {
2083d59d 814 ERROR("Failed to setup %" PRIu64 " byte terminal ringbuffer", size);
3b988b33
CB
815 return -1;
816 }
817
2083d59d 818 TRACE("Allocated %" PRIu64 " byte terminal ringbuffer", size);
3b988b33
CB
819 return 0;
820}
821
a0309168 822/**
2083d59d
CB
823 * This is the terminal log file. Please note that the terminal log file is
824 * (implementation wise not content wise) independent of the terminal ringbuffer.
a0309168 825 */
dcad02f8 826int lxc_terminal_create_log_file(struct lxc_terminal *terminal)
a0309168 827{
2083d59d 828 if (!terminal->log_path)
a0309168
CB
829 return 0;
830
2083d59d
CB
831 terminal->log_fd = lxc_unpriv(open(terminal->log_path, O_CLOEXEC | O_RDWR | O_CREAT | O_APPEND, 0600));
832 if (terminal->log_fd < 0) {
833 SYSERROR("Failed to open terminal log file \"%s\"", terminal->log_path);
a0309168
CB
834 return -1;
835 }
836
2083d59d 837 DEBUG("Using \"%s\" as terminal log file", terminal->log_path);
a0309168
CB
838 return 0;
839}
840
8ea93a0f
CB
841static int lxc_terminal_map_ids(struct lxc_conf *c, struct lxc_terminal *terminal)
842{
843 int ret;
844
845 if (lxc_list_empty(&c->id_map))
846 return 0;
847
848 if (is_empty_string(terminal->name) && terminal->pty < 0)
849 return 0;
850
851 if (terminal->pty >= 0)
852 ret = userns_exec_mapped_root(NULL, terminal->pty, c);
853 else
854 ret = userns_exec_mapped_root(terminal->name, -EBADF, c);
855 if (ret < 0)
856 return log_error(-1, "Failed to chown terminal %d(%s)", terminal->pty,
857 !is_empty_string(terminal->name) ? terminal->name : "(null)");
858
859 TRACE("Chowned terminal %d(%s)", terminal->pty,
860 !is_empty_string(terminal->name) ? terminal->name : "(null)");
861
862 return 0;
863}
864
865static int lxc_terminal_create_foreign(struct lxc_conf *conf, struct lxc_terminal *terminal)
63376d7d 866{
8ded9244 867 int ret;
b5159817 868
41808e20 869 ret = openpty(&terminal->ptx, &terminal->pty, NULL, NULL, NULL);
467c7ff3 870 if (ret < 0) {
8ded9244 871 SYSERROR("Failed to open terminal");
b5159817
DE
872 return -1;
873 }
874
8ea93a0f
CB
875 ret = lxc_terminal_map_ids(conf, terminal);
876 if (ret < 0) {
877 SYSERROR("Failed to change ownership of terminal multiplexer device");
878 goto err;
879 }
880
41808e20 881 ret = ttyname_r(terminal->pty, terminal->name, sizeof(terminal->name));
3f15bdd9 882 if (ret < 0) {
41808e20 883 SYSERROR("Failed to retrieve name of terminal pty");
3f15bdd9
CB
884 goto err;
885 }
886
36a94ce8 887 ret = fd_cloexec(terminal->ptx, true);
69629c82 888 if (ret < 0) {
36a94ce8 889 SYSERROR("Failed to set FD_CLOEXEC flag on terminal ptx");
b5159817
DE
890 goto err;
891 }
892
41808e20 893 ret = fd_cloexec(terminal->pty, true);
69629c82 894 if (ret < 0) {
41808e20 895 SYSERROR("Failed to set FD_CLOEXEC flag on terminal pty");
b5159817
DE
896 goto err;
897 }
898
2083d59d 899 ret = lxc_terminal_peer_default(terminal);
467c7ff3 900 if (ret < 0) {
8ded9244 901 ERROR("Failed to allocate proxy terminal");
467c7ff3
CB
902 goto err;
903 }
b5159817 904
5777fe90
CB
905 return 0;
906
907err:
2083d59d 908 lxc_terminal_delete(terminal);
5777fe90
CB
909 return -ENODEV;
910}
911
8ea93a0f 912static int lxc_terminal_create_native(const char *name, const char *lxcpath, struct lxc_conf *conf,
f797f05e
CB
913 struct lxc_terminal *terminal)
914{
8ea93a0f 915 __do_close int devpts_fd = -EBADF;
f797f05e
CB
916 int ret;
917
918 devpts_fd = lxc_cmd_get_devpts_fd(name, lxcpath);
919 if (devpts_fd < 0)
920 return log_error_errno(-1, errno, "Failed to receive devpts fd");
921
8ea93a0f
CB
922 terminal->ptx = open_beneath(devpts_fd, "ptmx", O_RDWR | O_NOCTTY | O_CLOEXEC);
923 if (terminal->ptx < 0)
f797f05e
CB
924 return log_error_errno(-1, errno, "Failed to open terminal multiplexer device");
925
8ea93a0f
CB
926 ret = unlockpt(terminal->ptx);
927 if (ret < 0) {
928 SYSERROR("Failed to unlock multiplexer device device");
929 goto err;
930 }
f797f05e 931
8ea93a0f
CB
932 terminal->pty = ioctl(terminal->ptx, TIOCGPTPEER, O_RDWR | O_NOCTTY | O_CLOEXEC);
933 if (terminal->pty < 0) {
934 SYSERROR("Failed to allocate new pty device");
935 goto err;
936 }
f797f05e 937
8ea93a0f 938 // ret = lxc_terminal_map_ids(conf, terminal);
f797f05e
CB
939
940 ret = ttyname_r(terminal->pty, terminal->name, sizeof(terminal->name));
8ea93a0f
CB
941 if (ret < 0) {
942 SYSERROR("Failed to retrieve name of terminal pty");
943 goto err;
944 }
f797f05e 945
f797f05e
CB
946 ret = lxc_terminal_peer_default(terminal);
947 if (ret < 0) {
948 ERROR("Failed to allocate proxy terminal");
949 goto err;
950 }
951
952 return 0;
953
954err:
955 lxc_terminal_delete(terminal);
956 return -ENODEV;
957}
958
8ea93a0f
CB
959int lxc_terminal_create(const char *name, const char *lxcpath, struct lxc_conf *conf,
960 struct lxc_terminal *terminal)
f797f05e 961{
8ea93a0f 962 if (!lxc_terminal_create_native(name, lxcpath, conf, terminal))
f797f05e
CB
963 return 0;
964
8ea93a0f 965 return lxc_terminal_create_foreign(conf, terminal);
f797f05e
CB
966}
967
564e31c4 968int lxc_terminal_setup(struct lxc_conf *conf)
5777fe90
CB
969{
970 int ret;
dcad02f8 971 struct lxc_terminal *terminal = &conf->console;
5777fe90 972
5ef86378
CB
973 if (terminal->path && strequal(terminal->path, "none"))
974 return log_info(0, "No terminal requested");
5777fe90 975
8ea93a0f 976 ret = lxc_terminal_create_foreign(conf, terminal);
5777fe90
CB
977 if (ret < 0)
978 return -1;
979
2083d59d 980 ret = lxc_terminal_create_log_file(terminal);
a0309168
CB
981 if (ret < 0)
982 goto err;
983
2083d59d 984 ret = lxc_terminal_create_ringbuf(terminal);
a0309168
CB
985 if (ret < 0)
986 goto err;
b5159817
DE
987
988 return 0;
989
990err:
2083d59d 991 lxc_terminal_delete(terminal);
69629c82 992 return -ENODEV;
b5159817
DE
993}
994
8ca7b374
CB
995static bool __terminal_dup2(int duplicate, int original)
996{
997 int ret;
998
999 if (!isatty(original))
1000 return true;
1001
1002 ret = dup2(duplicate, original);
1003 if (ret < 0) {
1004 SYSERROR("Failed to dup2(%d, %d)", duplicate, original);
1005 return false;
1006 }
1007
1008 return true;
1009}
1010
ae6d3913 1011int lxc_terminal_set_stdfds(int fd)
0d9acb99 1012{
8ca7b374
CB
1013 int i;
1014
39a78bbe 1015 if (fd < 0)
0d9acb99 1016 return 0;
b5159817 1017
8ca7b374
CB
1018 for (i = 0; i < 3; i++)
1019 if (!__terminal_dup2(fd, (int[]){STDIN_FILENO, STDOUT_FILENO,
1020 STDERR_FILENO}[i]))
39a78bbe 1021 return -1;
39a78bbe 1022
0d9acb99
DE
1023 return 0;
1024}
b5159817 1025
52f9292f 1026int lxc_terminal_stdin_cb(int fd, uint32_t events, void *cbdata,
15085292 1027 struct lxc_epoll_descr *descr)
b5159817 1028{
15085292 1029 int ret;
b5159817 1030 char c;
15085292 1031 struct lxc_terminal_state *ts = cbdata;
b5159817 1032
97bc2422 1033 if (fd != ts->stdinfd)
a529bc25 1034 return LXC_MAINLOOP_CLOSE;
97bc2422 1035
15085292
CB
1036 ret = lxc_read_nointr(ts->stdinfd, &c, 1);
1037 if (ret <= 0)
a529bc25 1038 return LXC_MAINLOOP_CLOSE;
63376d7d 1039
525e2117 1040 if (ts->escape >= 1) {
2083d59d 1041 /* we want to exit the terminal with Ctrl+a q */
014d5e1e
CB
1042 if (c == ts->escape && !ts->saw_escape) {
1043 ts->saw_escape = 1;
15085292 1044 return LXC_MAINLOOP_CONTINUE;
014d5e1e 1045 }
5c294060 1046
014d5e1e 1047 if (c == 'q' && ts->saw_escape)
a529bc25 1048 return LXC_MAINLOOP_CLOSE;
014d5e1e
CB
1049
1050 ts->saw_escape = 0;
1051 }
63376d7d 1052
36a94ce8 1053 ret = lxc_write_nointr(ts->ptxfd, &c, 1);
15085292 1054 if (ret <= 0)
a529bc25 1055 return LXC_MAINLOOP_CLOSE;
b5159817 1056
15085292 1057 return LXC_MAINLOOP_CONTINUE;
63376d7d
DL
1058}
1059
36a94ce8 1060int lxc_terminal_ptx_cb(int fd, uint32_t events, void *cbdata,
ee9102ff 1061 struct lxc_epoll_descr *descr)
63376d7d 1062{
0d4137cc 1063 int r, w;
5bd171bd
CB
1064 char buf[LXC_TERMINAL_BUFFER_SIZE];
1065 struct lxc_terminal_state *ts = cbdata;
63376d7d 1066
36a94ce8 1067 if (fd != ts->ptxfd)
a529bc25 1068 return LXC_MAINLOOP_CLOSE;
97bc2422 1069
e66b6c96
CB
1070 r = lxc_read_nointr(fd, buf, sizeof(buf));
1071 if (r <= 0)
a529bc25 1072 return LXC_MAINLOOP_CLOSE;
1560f6c9 1073
e66b6c96 1074 w = lxc_write_nointr(ts->stdoutfd, buf, r);
5bd171bd 1075 if (w <= 0 || w != r)
a529bc25 1076 return LXC_MAINLOOP_CLOSE;
f78a1f32 1077
5bd171bd 1078 return LXC_MAINLOOP_CONTINUE;
b5159817
DE
1079}
1080
36a94ce8 1081int lxc_terminal_getfd(struct lxc_container *c, int *ttynum, int *ptxfd)
b5159817 1082{
36a94ce8 1083 return lxc_cmd_console(c->name, ttynum, ptxfd, c->config_path);
b5159817
DE
1084}
1085
1086int lxc_console(struct lxc_container *c, int ttynum,
1087 int stdinfd, int stdoutfd, int stderrfd,
1088 int escape)
1089{
36a94ce8 1090 int ptxfd, ret, ttyfd;
b5159817
DE
1091 struct lxc_epoll_descr descr;
1092 struct termios oldtios;
5b55021f 1093 struct lxc_terminal_state *ts;
28327a43
CB
1094 struct lxc_terminal terminal = {
1095 .tty_state = NULL,
1096 };
25964232 1097 int istty = 0;
b5159817 1098
36a94ce8 1099 ttyfd = lxc_cmd_console(c->name, &ttynum, &ptxfd, c->config_path);
6834f805
CB
1100 if (ttyfd < 0)
1101 return -1;
b5159817
DE
1102
1103 ret = setsid();
33b4b411
CB
1104 if (ret < 0)
1105 TRACE("Process is already group leader");
b5159817 1106
36a94ce8 1107 ts = lxc_terminal_signal_init(stdinfd, ptxfd);
b5159817
DE
1108 if (!ts) {
1109 ret = -1;
33b4b411 1110 goto close_fds;
b5159817 1111 }
28327a43 1112 terminal.tty_state = ts;
b5159817 1113 ts->escape = escape;
3b975060 1114 ts->stdoutfd = stdoutfd;
b5159817 1115
6834f805 1116 istty = isatty(stdinfd);
25964232 1117 if (istty) {
36a94ce8
CB
1118 lxc_terminal_winsz(stdinfd, ptxfd);
1119 lxc_terminal_winsz(ts->stdinfd, ts->ptxfd);
6834f805 1120 } else {
71ac3f07 1121 INFO("File descriptor %d does not refer to a terminal", stdinfd);
25964232 1122 }
b5159817
DE
1123
1124 ret = lxc_mainloop_open(&descr);
1125 if (ret) {
33b4b411
CB
1126 ERROR("Failed to create mainloop");
1127 goto sigwinch_fini;
b5159817
DE
1128 }
1129
341c2aed
CB
1130 if (ts->sigfd != -1) {
1131 ret = lxc_mainloop_add_handler(&descr, ts->sigfd,
9bafc8cb 1132 lxc_terminal_signalfd_cb, ts);
33b4b411 1133 if (ret < 0) {
0519b5cc 1134 ERROR("Failed to add signal handler to mainloop");
33b4b411 1135 goto close_mainloop;
341c2aed 1136 }
b5159817
DE
1137 }
1138
1139 ret = lxc_mainloop_add_handler(&descr, ts->stdinfd,
52f9292f 1140 lxc_terminal_stdin_cb, ts);
33b4b411
CB
1141 if (ret < 0) {
1142 ERROR("Failed to add stdin handler");
1143 goto close_mainloop;
b5159817
DE
1144 }
1145
36a94ce8
CB
1146 ret = lxc_mainloop_add_handler(&descr, ts->ptxfd,
1147 lxc_terminal_ptx_cb, ts);
33b4b411 1148 if (ret < 0) {
36a94ce8 1149 ERROR("Failed to add ptx handler");
33b4b411 1150 goto close_mainloop;
b5159817
DE
1151 }
1152
686df166
CB
1153 if (ts->escape >= 1) {
1154 fprintf(stderr,
1155 "\n"
6834f805
CB
1156 "Connected to tty %1$d\n"
1157 "Type <Ctrl+%2$c q> to exit the console, "
1158 "<Ctrl+%2$c Ctrl+%2$c> to enter Ctrl+%2$c itself\n",
1159 ttynum, 'a' + escape - 1);
686df166 1160 }
6834f805
CB
1161
1162 if (istty) {
1163 ret = lxc_setup_tios(stdinfd, &oldtios);
1164 if (ret < 0)
1165 goto close_mainloop;
1166 }
1167
025ed0f3 1168 ret = lxc_mainloop(&descr, -1);
33b4b411
CB
1169 if (ret < 0) {
1170 ERROR("The mainloop returned an error");
6834f805 1171 goto restore_tios;
b5159817
DE
1172 }
1173
1174 ret = 0;
1175
6834f805
CB
1176restore_tios:
1177 if (istty) {
1178 istty = tcsetattr(stdinfd, TCSAFLUSH, &oldtios);
1179 if (istty < 0)
a24c5678 1180 SYSWARN("Failed to restore terminal properties");
6834f805
CB
1181 }
1182
33b4b411 1183close_mainloop:
b5159817 1184 lxc_mainloop_close(&descr);
33b4b411
CB
1185
1186sigwinch_fini:
28327a43 1187 lxc_terminal_signal_fini(&terminal);
33b4b411
CB
1188
1189close_fds:
36a94ce8 1190 close(ptxfd);
b5159817 1191 close(ttyfd);
33b4b411 1192
b5159817 1193 return ret;
63376d7d 1194}
e98affda 1195
cd0a2b2f 1196int lxc_make_controlling_terminal(int fd)
e98affda
CB
1197{
1198 int ret;
1199
1200 setsid();
1201
1202 ret = ioctl(fd, TIOCSCTTY, (char *)NULL);
1203 if (ret < 0)
1204 return -1;
1205
1206 return 0;
1207}
1208
d049f0e9 1209int lxc_terminal_prepare_login(int fd)
e98affda
CB
1210{
1211 int ret;
1212
cd0a2b2f 1213 ret = lxc_make_controlling_terminal(fd);
e98affda
CB
1214 if (ret < 0)
1215 return -1;
1216
ae6d3913 1217 ret = lxc_terminal_set_stdfds(fd);
e98affda
CB
1218 if (ret < 0)
1219 return -1;
1220
1221 if (fd > STDERR_FILENO)
1222 close(fd);
1223
1224 return 0;
1225}
1226
e9a55b51 1227void lxc_terminal_info_init(struct lxc_terminal_info *terminal)
e98affda 1228{
e9a55b51 1229 terminal->name[0] = '\0';
36a94ce8 1230 terminal->ptx = -EBADF;
41808e20 1231 terminal->pty = -EBADF;
e9a55b51 1232 terminal->busy = -1;
e98affda
CB
1233}
1234
e9a55b51 1235void lxc_terminal_init(struct lxc_terminal *terminal)
e98affda 1236{
e9a55b51 1237 memset(terminal, 0, sizeof(*terminal));
41808e20 1238 terminal->pty = -EBADF;
36a94ce8 1239 terminal->ptx = -EBADF;
e9a55b51
CB
1240 terminal->peer = -EBADF;
1241 terminal->log_fd = -EBADF;
1242 lxc_terminal_info_init(&terminal->proxy);
e98affda
CB
1243}
1244
dcad02f8 1245void lxc_terminal_conf_free(struct lxc_terminal *terminal)
e98affda 1246{
2083d59d
CB
1247 free(terminal->log_path);
1248 free(terminal->path);
1249 if (terminal->buffer_size > 0 && terminal->ringbuf.addr)
1250 lxc_ringbuf_release(&terminal->ringbuf);
28327a43 1251 lxc_terminal_signal_fini(terminal);
e98affda 1252}