]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/console.c
console: s/tty_info/ttys/g
[mirror_lxc.git] / src / lxc / console.c
CommitLineData
b0a33c1e 1/*
2 * lxc: linux Container library
3 *
4 * (C) Copyright IBM Corp. 2007, 2008
5 *
6 * Authors:
9afe19d6 7 * Daniel Lezcano <daniel.lezcano at free.fr>
b0a33c1e 8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
250b1eec 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
b0a33c1e 22 */
23
9395937a
CB
24#include <errno.h>
25#include <fcntl.h>
b5159817 26#include <signal.h>
b0a33c1e 27#include <stdio.h>
e0dc0de7 28#include <stdlib.h>
8173e600 29#include <termios.h>
9395937a 30#include <unistd.h>
da41561c
CB
31#include <sys/epoll.h>
32#include <sys/types.h>
b0a33c1e 33
948955a2 34#include <lxc/lxccontainer.h>
f2363e38 35
9395937a
CB
36#include "af_unix.h"
37#include "caps.h"
38#include "commands.h"
00dbc43e 39#include "conf.h"
e827ff7e 40#include "config.h"
0d4137cc 41#include "console.h"
9395937a 42#include "log.h"
b5159817 43#include "lxclock.h"
9395937a
CB
44#include "mainloop.h"
45#include "start.h" /* for struct lxc_handler */
b5159817 46#include "utils.h"
36eb9bde 47
e827ff7e
SG
48#if HAVE_PTY_H
49#include <pty.h>
50#else
51#include <../include/openpty.h>
52#endif
53
de708fb7 54#define LXC_TERMINAL_BUFFER_SIZE 1024
732375f5 55
2083d59d 56lxc_log_define(terminal, lxc);
36eb9bde 57
b5159817 58static struct lxc_list lxc_ttys;
724e753c 59
b5159817 60typedef void (*sighandler_t)(int);
b5159817 61
fc26f086 62__attribute__((constructor)) void lxc_terminal_init_global(void)
b5159817
DE
63{
64 lxc_list_init(&lxc_ttys);
65}
724e753c 66
4e9c0330 67void lxc_terminal_winsz(int srcfd, int dstfd)
b5159817 68{
0519b5cc 69 int ret;
b5159817 70 struct winsize wsz;
0519b5cc
CB
71
72 if (!isatty(srcfd))
73 return;
74
75 ret = ioctl(srcfd, TIOCGWINSZ, &wsz);
76 if (ret < 0) {
77 WARN("Failed to get window size");
78 return;
724e753c 79 }
0519b5cc
CB
80
81 ret = ioctl(dstfd, TIOCSWINSZ, &wsz);
82 if (ret < 0)
83 WARN("Failed to set window size");
84 else
85 DEBUG("Set window size to %d columns and %d rows", wsz.ws_col,
86 wsz.ws_row);
87
88 return;
b5159817 89}
724e753c 90
7a10164a 91static void lxc_terminal_winch(struct lxc_tty_state *ts)
b5159817 92{
4e9c0330 93 lxc_terminal_winsz(ts->stdinfd, ts->masterfd);
0519b5cc 94
0d4137cc 95 if (ts->winch_proxy)
8ccbbf94 96 lxc_cmd_terminal_winch(ts->winch_proxy, ts->winch_proxy_lxcpath);
724e753c
MN
97}
98
dad4a039 99void lxc_terminal_sigwinch(int sig)
cd453b38 100{
025ed0f3
SH
101 struct lxc_list *it;
102 struct lxc_tty_state *ts;
cd453b38 103
025ed0f3
SH
104 lxc_list_for_each(it, &lxc_ttys) {
105 ts = it->elem;
7a10164a 106 lxc_terminal_winch(ts);
cd453b38 107 }
b5159817 108}
cd453b38 109
9bafc8cb
CB
110int lxc_terminal_signalfd_cb(int fd, uint32_t events, void *cbdata,
111 struct lxc_epoll_descr *descr)
b5159817 112{
1349e92e 113 ssize_t ret;
b5159817
DE
114 struct signalfd_siginfo siginfo;
115 struct lxc_tty_state *ts = cbdata;
116
1349e92e 117 ret = read(fd, &siginfo, sizeof(siginfo));
0d4137cc 118 if (ret < 0 || (size_t)ret < sizeof(siginfo)) {
0519b5cc 119 ERROR("Failed to read signal info");
b5159817 120 return -1;
cd453b38
DL
121 }
122
1349e92e 123 if (siginfo.ssi_signo == SIGTERM) {
9bafc8cb 124 DEBUG("Received SIGTERM. Detaching from the terminal");
a529bc25 125 return LXC_MAINLOOP_CLOSE;
1349e92e
CB
126 }
127
128 if (siginfo.ssi_signo == SIGWINCH)
7a10164a 129 lxc_terminal_winch(ts);
1349e92e 130
b5159817
DE
131 return 0;
132}
133
dc8c7883 134struct lxc_tty_state *lxc_terminal_signal_init(int srcfd, int dstfd)
b5159817 135{
1349e92e 136 int ret;
0519b5cc 137 bool istty;
b5159817
DE
138 sigset_t mask;
139 struct lxc_tty_state *ts;
140
141 ts = malloc(sizeof(*ts));
142 if (!ts)
143 return NULL;
144
145 memset(ts, 0, sizeof(*ts));
341c2aed 146 ts->stdinfd = srcfd;
b5159817 147 ts->masterfd = dstfd;
341c2aed 148 ts->sigfd = -1;
b5159817 149
1349e92e
CB
150 sigemptyset(&mask);
151
0519b5cc
CB
152 istty = isatty(srcfd) == 1;
153 if (!istty) {
25964232 154 INFO("fd %d does not refer to a tty device", srcfd);
1349e92e
CB
155 } else {
156 /* Add tty to list to be scanned at SIGWINCH time. */
157 lxc_list_add_elem(&ts->node, ts);
158 lxc_list_add_tail(&lxc_ttys, &ts->node);
159 sigaddset(&mask, SIGWINCH);
25964232
LF
160 }
161
1349e92e
CB
162 /* Exit the mainloop cleanly on SIGTERM. */
163 sigaddset(&mask, SIGTERM);
b5159817 164
1349e92e
CB
165 ret = sigprocmask(SIG_BLOCK, &mask, &ts->oldmask);
166 if (ret < 0) {
167 WARN("Failed to block signals");
168 goto on_error;
b5159817
DE
169 }
170
dc5f6125 171 ts->sigfd = signalfd(-1, &mask, SFD_CLOEXEC);
b5159817 172 if (ts->sigfd < 0) {
1349e92e 173 WARN("Failed to create signal fd");
341c2aed 174 sigprocmask(SIG_SETMASK, &ts->oldmask, NULL);
1349e92e 175 goto on_error;
b5159817
DE
176 }
177
1349e92e
CB
178 DEBUG("Created signal fd %d", ts->sigfd);
179 return ts;
180
181on_error:
182 ERROR("Failed to create signal fd");
183 if (ts->sigfd >= 0) {
184 close(ts->sigfd);
185 ts->sigfd = -1;
186 }
187 if (istty)
188 lxc_list_del(&ts->node);
b5159817 189 return ts;
cd453b38
DL
190}
191
a8867251 192void lxc_terminal_signal_fini(struct lxc_tty_state *ts)
63376d7d 193{
0e6da90b 194 if (ts->sigfd >= 0) {
b5159817 195 close(ts->sigfd);
1349e92e
CB
196
197 if (sigprocmask(SIG_SETMASK, &ts->oldmask, NULL) < 0)
198 WARN("%s - Failed to restore signal mask", strerror(errno));
0e6da90b 199 }
0d4137cc 200
1349e92e
CB
201 if (isatty(ts->stdinfd))
202 lxc_list_del(&ts->node);
203
b5159817
DE
204 free(ts);
205}
1560f6c9 206
99a04585 207static int lxc_terminal_truncate_log_file(struct lxc_terminal *terminal)
861813e5
CB
208{
209 /* be very certain things are kosher */
2083d59d 210 if (!terminal->log_path || terminal->log_fd < 0)
861813e5
CB
211 return -EBADF;
212
2083d59d 213 return lxc_unpriv(ftruncate(terminal->log_fd, 0));
861813e5
CB
214}
215
99a04585 216static int lxc_console_rotate_log_file(struct lxc_terminal *terminal)
861813e5
CB
217{
218 int ret;
219 size_t len;
220 char *tmp;
221
99a04585 222 if (!terminal->log_path || terminal->log_rotate == 0)
861813e5
CB
223 return -EOPNOTSUPP;
224
225 /* be very certain things are kosher */
99a04585 226 if (terminal->log_fd < 0)
861813e5
CB
227 return -EBADF;
228
99a04585 229 len = strlen(terminal->log_path) + sizeof(".1");
861813e5
CB
230 tmp = alloca(len);
231
99a04585 232 ret = snprintf(tmp, len, "%s.1", terminal->log_path);
861813e5
CB
233 if (ret < 0 || (size_t)ret >= len)
234 return -EFBIG;
235
99a04585
CB
236 close(terminal->log_fd);
237 terminal->log_fd = -1;
238 ret = lxc_unpriv(rename(terminal->log_path, tmp));
861813e5
CB
239 if (ret < 0)
240 return ret;
241
99a04585 242 return lxc_terminal_create_log_file(terminal);
861813e5
CB
243}
244
99a04585 245static int lxc_console_write_log_file(struct lxc_terminal *terminal, char *buf,
861813e5
CB
246 int bytes_read)
247{
248 int ret;
249 int64_t space_left = -1;
250 struct stat st;
251
99a04585 252 if (terminal->log_fd < 0)
861813e5
CB
253 return 0;
254
255 /* A log size <= 0 means that there's no limit on the size of the log
256 * file at which point we simply ignore whether the log is supposed to
257 * be rotated or not.
258 */
99a04585
CB
259 if (terminal->log_size <= 0)
260 return lxc_write_nointr(terminal->log_fd, buf, bytes_read);
861813e5
CB
261
262 /* Get current size of the log file. */
99a04585 263 ret = fstat(terminal->log_fd, &st);
861813e5 264 if (ret < 0) {
99a04585 265 SYSERROR("Failed to stat the terminal log file descriptor");
861813e5
CB
266 return -1;
267 }
268
269 /* handle non-regular files */
270 if ((st.st_mode & S_IFMT) != S_IFREG) {
271 /* This isn't a regular file. so rotating the file seems a
272 * dangerous thing to do, size limits are also very
273 * questionable. Let's not risk anything and tell the user that
274 * he's requesting us to do weird stuff.
275 */
99a04585 276 if (terminal->log_rotate > 0 || terminal->log_size > 0)
861813e5
CB
277 return -EINVAL;
278
279 /* I mean, sure log wherever you want to. */
99a04585 280 return lxc_write_nointr(terminal->log_fd, buf, bytes_read);
861813e5
CB
281 }
282
99a04585 283 space_left = terminal->log_size - st.st_size;
861813e5
CB
284
285 /* User doesn't want to rotate the log file and there's no more space
286 * left so simply truncate it.
287 */
99a04585
CB
288 if (space_left <= 0 && terminal->log_rotate <= 0) {
289 ret = lxc_terminal_truncate_log_file(terminal);
861813e5
CB
290 if (ret < 0)
291 return ret;
292
99a04585
CB
293 if (bytes_read <= terminal->log_size)
294 return lxc_write_nointr(terminal->log_fd, buf, bytes_read);
861813e5
CB
295
296 /* Write as much as we can into the buffer and loose the rest. */
99a04585 297 return lxc_write_nointr(terminal->log_fd, buf, terminal->log_size);
861813e5
CB
298 }
299
300 /* There's enough space left. */
301 if (bytes_read <= space_left)
99a04585 302 return lxc_write_nointr(terminal->log_fd, buf, bytes_read);
861813e5
CB
303
304 /* There's not enough space left but at least write as much as we can
305 * into the old log file.
306 */
99a04585 307 ret = lxc_write_nointr(terminal->log_fd, buf, space_left);
861813e5
CB
308 if (ret < 0)
309 return -1;
310
311 /* Calculate how many bytes we still need to write. */
312 bytes_read -= space_left;
313
89962c6c 314 /* There'd be more to write but we aren't instructed to rotate the log
861813e5
CB
315 * file so simply return. There's no error on our side here.
316 */
99a04585
CB
317 if (terminal->log_rotate > 0)
318 ret = lxc_console_rotate_log_file(terminal);
861813e5 319 else
99a04585 320 ret = lxc_terminal_truncate_log_file(terminal);
861813e5
CB
321 if (ret < 0)
322 return ret;
323
99a04585 324 if (terminal->log_size < bytes_read) {
861813e5
CB
325 /* Well, this is unfortunate because it means that there is more
326 * to write than the user has granted us space. There are
327 * multiple ways to handle this but let's use the simplest one:
328 * write as much as we can, tell the user that there was more
329 * stuff to write and move on.
330 * Note that this scenario shouldn't actually happen with the
99a04585 331 * standard pty-based terminal that LXC allocates since it will
861813e5
CB
332 * be switched into raw mode. In raw mode only 1 byte at a time
333 * should be read and written.
334 */
99a04585
CB
335 WARN("Size of terminal log file is smaller than the bytes to write");
336 ret = lxc_write_nointr(terminal->log_fd, buf, terminal->log_size);
861813e5
CB
337 if (ret < 0)
338 return -1;
339 bytes_read -= ret;
340 return bytes_read;
341 }
342
343 /* Yay, we made it. */
99a04585 344 ret = lxc_write_nointr(terminal->log_fd, buf, bytes_read);
861813e5
CB
345 if (ret < 0)
346 return -1;
347 bytes_read -= ret;
348 return bytes_read;
349}
350
de708fb7 351int lxc_terminal_io_cb(int fd, uint32_t events, void *data,
a529bc25 352 struct lxc_epoll_descr *descr)
b5159817 353{
dcad02f8 354 struct lxc_terminal *terminal = data;
de708fb7 355 char buf[LXC_TERMINAL_BUFFER_SIZE];
732375f5 356 int r, w, w_log, w_rbuf;
e0dc0de7 357
3e6580ec
CB
358 w = r = lxc_read_nointr(fd, buf, sizeof(buf));
359 if (r <= 0) {
de708fb7 360 INFO("Terminal client on fd %d has exited", fd);
b5159817 361 lxc_mainloop_del_handler(descr, fd);
c06a0555 362
de708fb7
CB
363 if (fd == terminal->master) {
364 terminal->master = -EBADF;
365 } else if (fd == terminal->peer) {
366 if (terminal->tty_state) {
367 lxc_terminal_signal_fini(terminal->tty_state);
368 terminal->tty_state = NULL;
0b1e242b 369 }
de708fb7 370 terminal->peer = -EBADF;
c06a0555
CB
371 } else {
372 ERROR("Handler received unexpected file descriptor");
0b1e242b 373 }
b5159817 374 close(fd);
c06a0555 375
a529bc25 376 return LXC_MAINLOOP_CLOSE;
33fcb7a0 377 }
63376d7d 378
de708fb7
CB
379 if (fd == terminal->peer)
380 w = lxc_write_nointr(terminal->master, buf, r);
b5159817 381
732375f5 382 w_rbuf = w_log = 0;
de708fb7 383 if (fd == terminal->master) {
732375f5 384 /* write to peer first */
de708fb7
CB
385 if (terminal->peer >= 0)
386 w = lxc_write_nointr(terminal->peer, buf, r);
732375f5 387
de708fb7
CB
388 /* write to terminal ringbuffer */
389 if (terminal->buffer_size > 0)
390 w_rbuf = lxc_ringbuf_write(&terminal->ringbuf, buf, r);
861813e5 391
de708fb7
CB
392 /* write to terminal log */
393 if (terminal->log_fd >= 0)
394 w_log = lxc_console_write_log_file(terminal, buf, r);
63376d7d
DL
395 }
396
b5159817 397 if (w != r)
de708fb7 398 WARN("Short write on terminal r:%d != w:%d", r, w);
732375f5
CB
399
400 if (w_rbuf < 0)
de708fb7 401 TRACE("%s - Failed to write %d bytes to terminal ringbuffer",
732375f5
CB
402 strerror(-w_rbuf), r);
403
404 if (w_log < 0)
de708fb7 405 TRACE("Failed to write %d bytes to terminal log", r);
0d4137cc 406
b5159817
DE
407 return 0;
408}
409
dcad02f8 410static int lxc_terminal_mainloop_add_peer(struct lxc_terminal *terminal)
b5159817 411{
a529bc25
CB
412 int ret;
413
2083d59d
CB
414 if (terminal->peer >= 0) {
415 ret = lxc_mainloop_add_handler(terminal->descr, terminal->peer,
416 lxc_terminal_io_cb, terminal);
a529bc25 417 if (ret < 0) {
2083d59d 418 WARN("Failed to add terminal peer handler to mainloop");
a529bc25
CB
419 return -1;
420 }
63376d7d
DL
421 }
422
2083d59d 423 if (!terminal->tty_state || terminal->tty_state->sigfd < 0)
a529bc25
CB
424 return 0;
425
2083d59d
CB
426 ret = lxc_mainloop_add_handler(terminal->descr, terminal->tty_state->sigfd,
427 lxc_terminal_signalfd_cb, terminal->tty_state);
a529bc25
CB
428 if (ret < 0) {
429 WARN("Failed to add signal handler to mainloop");
430 return -1;
b5159817 431 }
a529bc25
CB
432
433 return 0;
b5159817
DE
434}
435
093bce5f 436int lxc_terminal_mainloop_add(struct lxc_epoll_descr *descr,
dcad02f8 437 struct lxc_terminal *terminal)
b5159817 438{
a529bc25 439 int ret;
b5159817 440
2083d59d
CB
441 if (terminal->master < 0) {
442 INFO("Terminal is not initialized");
b5159817 443 return 0;
596a818d
DE
444 }
445
2083d59d
CB
446 ret = lxc_mainloop_add_handler(descr, terminal->master,
447 lxc_terminal_io_cb, terminal);
30a33fbd 448 if (ret < 0) {
2083d59d 449 ERROR("Failed to add handler for %d to mainloop", terminal->master);
b5159817 450 return -1;
28a4b0e5
DL
451 }
452
30a33fbd 453 /* We cache the descr so that we can add an fd to it when someone
c1ee47cd 454 * does attach to it in lxc_terminal_allocate().
b5159817 455 */
2083d59d
CB
456 terminal->descr = descr;
457 ret = lxc_terminal_mainloop_add_peer(terminal);
a529bc25
CB
458 if (ret < 0)
459 return -1;
cd453b38 460
b5159817
DE
461 return 0;
462}
28a4b0e5 463
0d4137cc 464int lxc_setup_tios(int fd, struct termios *oldtios)
b5159817
DE
465{
466 struct termios newtios;
e0dc0de7 467
b5159817
DE
468 if (!isatty(fd)) {
469 ERROR("'%d' is not a tty", fd);
470 return -1;
e0dc0de7
DL
471 }
472
b5159817
DE
473 /* Get current termios */
474 if (tcgetattr(fd, oldtios)) {
e0dc0de7 475 SYSERROR("failed to get current terminal settings");
b5159817 476 return -1;
e0dc0de7
DL
477 }
478
4dc96430
TJ
479 /* ensure we don't end up in an endless loop:
480 * The kernel might fire SIGTTOU while an
481 * ioctl() in tcsetattr() is executed. When the ioctl()
482 * is resumed and retries, the signal handler interrupts it again.
483 */
484 signal (SIGTTIN, SIG_IGN);
485 signal (SIGTTOU, SIG_IGN);
486
b5159817 487 newtios = *oldtios;
e0dc0de7 488
a7c97a40
CB
489 /* We use the same settings that ssh does. */
490 newtios.c_iflag |= IGNPAR;
491 newtios.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF);
492#ifdef IUCLC
493 newtios.c_iflag &= ~IUCLC;
494#endif
4dc96430 495 newtios.c_lflag &= ~(TOSTOP | ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL);
a7c97a40
CB
496#ifdef IEXTEN
497 newtios.c_lflag &= ~IEXTEN;
498#endif
d3893399 499 newtios.c_oflag &= ~OPOST;
b5159817
DE
500 newtios.c_cc[VMIN] = 1;
501 newtios.c_cc[VTIME] = 0;
e0dc0de7 502
a7c97a40 503 /* Set new attributes. */
b5159817 504 if (tcsetattr(fd, TCSAFLUSH, &newtios)) {
e0dc0de7 505 ERROR("failed to set new terminal settings");
b5159817 506 return -1;
e0dc0de7
DL
507 }
508
63376d7d 509 return 0;
b5159817 510}
e0dc0de7 511
dcad02f8 512static void lxc_terminal_peer_proxy_free(struct lxc_terminal *terminal)
b5159817 513{
2083d59d
CB
514 if (terminal->tty_state) {
515 lxc_terminal_signal_fini(terminal->tty_state);
516 terminal->tty_state = NULL;
b5159817 517 }
2083d59d
CB
518 close(terminal->peerpty.master);
519 close(terminal->peerpty.slave);
520 terminal->peerpty.master = -1;
521 terminal->peerpty.slave = -1;
522 terminal->peerpty.busy = -1;
523 terminal->peerpty.name[0] = '\0';
524 terminal->peer = -1;
b5159817 525}
596a818d 526
dcad02f8 527static int lxc_terminal_peer_proxy_alloc(struct lxc_terminal *terminal, int sockfd)
b5159817
DE
528{
529 struct termios oldtermio;
530 struct lxc_tty_state *ts;
025ed0f3 531 int ret;
b5159817 532
2083d59d
CB
533 if (terminal->master < 0) {
534 ERROR("Terminal not set up");
b5159817
DE
535 return -1;
536 }
2083d59d
CB
537 if (terminal->peerpty.busy != -1 || terminal->peer != -1) {
538 NOTICE("Terminal already in use");
b5159817
DE
539 return -1;
540 }
2083d59d
CB
541 if (terminal->tty_state) {
542 ERROR("Terminal already has tty_state");
b5159817 543 return -1;
596a818d
DE
544 }
545
b5159817
DE
546 /* this is the proxy pty that will be given to the client, and that
547 * the real pty master will send to / recv from
548 */
2083d59d
CB
549 ret = openpty(&terminal->peerpty.master, &terminal->peerpty.slave,
550 terminal->peerpty.name, NULL, NULL);
025ed0f3 551 if (ret) {
b5159817
DE
552 SYSERROR("failed to create proxy pty");
553 return -1;
554 }
596a818d 555
2083d59d 556 if (lxc_setup_tios(terminal->peerpty.slave, &oldtermio) < 0)
b5159817
DE
557 goto err1;
558
2083d59d 559 ts = lxc_terminal_signal_init(terminal->peerpty.master, terminal->master);
b5159817
DE
560 if (!ts)
561 goto err1;
562
2083d59d
CB
563 terminal->tty_state = ts;
564 terminal->peer = terminal->peerpty.slave;
565 terminal->peerpty.busy = sockfd;
566 ret = lxc_terminal_mainloop_add_peer(terminal);
a529bc25
CB
567 if (ret < 0)
568 goto err1;
b5159817 569
2083d59d 570 DEBUG("%d peermaster:%d sockfd:%d", lxc_raw_getpid(), terminal->peerpty.master, sockfd);
b5159817
DE
571 return 0;
572
573err1:
2083d59d 574 lxc_terminal_peer_proxy_free(terminal);
63376d7d
DL
575 return -1;
576}
577
c1ee47cd 578int lxc_terminal_allocate(struct lxc_conf *conf, int sockfd, int *ttyreq)
b5159817
DE
579{
580 int masterfd = -1, ttynum;
0e4be3cf 581 struct lxc_tty_info *ttys = &conf->ttys;
dcad02f8 582 struct lxc_terminal *terminal = &conf->console;
b5159817 583
b5159817 584 if (*ttyreq == 0) {
2083d59d 585 if (lxc_terminal_peer_proxy_alloc(terminal, sockfd) < 0)
b5159817 586 goto out;
2083d59d 587 masterfd = terminal->peerpty.master;
b5159817
DE
588 goto out;
589 }
590
591 if (*ttyreq > 0) {
0e4be3cf 592 if (*ttyreq > ttys->nbtty)
b5159817
DE
593 goto out;
594
0e4be3cf 595 if (ttys->tty[*ttyreq - 1].busy)
b5159817
DE
596 goto out;
597
598 /* the requested tty is available */
599 ttynum = *ttyreq;
600 goto out_tty;
601 }
602
603 /* search for next available tty, fixup index tty1 => [0] */
0e4be3cf 604 for (ttynum = 1; ttynum <= ttys->nbtty && ttys->tty[ttynum - 1].busy; ttynum++)
0d4137cc 605 ;
b5159817
DE
606
607 /* we didn't find any available slot for tty */
0e4be3cf 608 if (ttynum > ttys->nbtty)
b5159817
DE
609 goto out;
610
611 *ttyreq = ttynum;
612
613out_tty:
0e4be3cf
CB
614 ttys->tty[ttynum - 1].busy = sockfd;
615 masterfd = ttys->tty[ttynum - 1].master;
b5159817 616out:
b5159817
DE
617 return masterfd;
618}
619
3dfe6f8d 620void lxc_terminal_free(struct lxc_conf *conf, int fd)
63376d7d 621{
b5159817 622 int i;
0e4be3cf 623 struct lxc_tty_info *ttys = &conf->ttys;
dcad02f8 624 struct lxc_terminal *terminal = &conf->console;
b5159817 625
0e4be3cf
CB
626 for (i = 0; i < ttys->nbtty; i++) {
627 if (ttys->tty[i].busy == fd)
628 ttys->tty[i].busy = 0;
b5159817
DE
629 }
630
2083d59d
CB
631 if (terminal->peerpty.busy == fd) {
632 lxc_mainloop_del_handler(terminal->descr, terminal->peerpty.slave);
633 lxc_terminal_peer_proxy_free(terminal);
b5159817 634 }
b5159817
DE
635}
636
dcad02f8 637static int lxc_terminal_peer_default(struct lxc_terminal *terminal)
b5159817
DE
638{
639 struct lxc_tty_state *ts;
2083d59d 640 const char *path = terminal->path;
467c7ff3
CB
641 int fd;
642 int ret = 0;
b5159817 643
2083d59d 644 /* If no terminal was given, try current controlling terminal, there
467c7ff3 645 * won't be one if we were started as a daemon (-d).
b5159817
DE
646 */
647 if (!path && !access("/dev/tty", F_OK)) {
b5159817
DE
648 fd = open("/dev/tty", O_RDWR);
649 if (fd >= 0) {
650 close(fd);
651 path = "/dev/tty";
652 }
653 }
654
467c7ff3
CB
655 if (!path) {
656 errno = ENOTTY;
657 DEBUG("process does not have a controlling terminal");
b5159817 658 goto out;
467c7ff3 659 }
b5159817 660
2083d59d
CB
661 terminal->peer = lxc_unpriv(open(path, O_RDWR | O_CLOEXEC));
662 if (terminal->peer < 0) {
a63fade5 663 ERROR("Failed to open \"%s\": %s", path, strerror(errno));
467c7ff3
CB
664 return -ENOTTY;
665 }
666 DEBUG("using \"%s\" as peer tty device", path);
b5159817 667
2083d59d 668 if (!isatty(terminal->peer)) {
467c7ff3
CB
669 ERROR("file descriptor for file \"%s\" does not refer to a tty device", path);
670 goto on_error1;
671 }
b5159817 672
2083d59d
CB
673 ts = lxc_terminal_signal_init(terminal->peer, terminal->master);
674 terminal->tty_state = ts;
341c2aed 675 if (!ts) {
0519b5cc 676 WARN("Failed to install signal handler");
467c7ff3 677 goto on_error1;
341c2aed 678 }
b5159817 679
2083d59d 680 lxc_terminal_winsz(terminal->peer, terminal->master);
b5159817 681
2083d59d
CB
682 terminal->tios = malloc(sizeof(*terminal->tios));
683 if (!terminal->tios) {
b5159817 684 SYSERROR("failed to allocate memory");
467c7ff3 685 goto on_error1;
b5159817
DE
686 }
687
2083d59d 688 if (lxc_setup_tios(terminal->peer, terminal->tios) < 0)
467c7ff3
CB
689 goto on_error2;
690 else
691 goto out;
b5159817 692
467c7ff3 693on_error2:
2083d59d
CB
694 free(terminal->tios);
695 terminal->tios = NULL;
467c7ff3
CB
696
697on_error1:
2083d59d
CB
698 close(terminal->peer);
699 terminal->peer = -1;
467c7ff3
CB
700 ret = -ENOTTY;
701
b5159817 702out:
467c7ff3 703 return ret;
b5159817
DE
704}
705
dcad02f8 706int lxc_terminal_write_ringbuffer(struct lxc_terminal *terminal)
39c6cdb7
CB
707{
708 char *r_addr;
709 ssize_t ret;
710 uint64_t used;
2083d59d 711 struct lxc_ringbuf *buf = &terminal->ringbuf;
39c6cdb7
CB
712
713 /* There's not log file where we can dump the ringbuffer to. */
2083d59d 714 if (terminal->log_fd < 0)
39c6cdb7
CB
715 return 0;
716
39c6cdb7
CB
717 used = lxc_ringbuf_used(buf);
718 if (used == 0)
719 return 0;
720
2083d59d 721 ret = lxc_terminal_truncate_log_file(terminal);
39c6cdb7
CB
722 if (ret < 0)
723 return ret;
724
725 /* Write as much as we can without exceeding the limit. */
2083d59d
CB
726 if (terminal->log_size < used)
727 used = terminal->log_size;
39c6cdb7
CB
728
729 r_addr = lxc_ringbuf_get_read_addr(buf);
2083d59d 730 ret = lxc_write_nointr(terminal->log_fd, r_addr, used);
39c6cdb7
CB
731 if (ret < 0)
732 return -EIO;
733
734 return 0;
735}
736
dcad02f8 737void lxc_terminal_delete(struct lxc_terminal *terminal)
b5159817 738{
69629c82
CB
739 int ret;
740
2083d59d 741 ret = lxc_terminal_write_ringbuffer(terminal);
39c6cdb7 742 if (ret < 0)
2083d59d 743 WARN("Failed to write terminal log to disk");
39c6cdb7 744
2083d59d
CB
745 if (terminal->tios && terminal->peer >= 0) {
746 ret = tcsetattr(terminal->peer, TCSAFLUSH, terminal->tios);
69629c82
CB
747 if (ret < 0)
748 WARN("%s - Failed to set old terminal settings", strerror(errno));
749 }
2083d59d
CB
750 free(terminal->tios);
751 terminal->tios = NULL;
596a818d 752
2083d59d
CB
753 if (terminal->peer >= 0)
754 close(terminal->peer);
755 terminal->peer = -1;
bc9724f7 756
2083d59d
CB
757 if (terminal->master >= 0)
758 close(terminal->master);
759 terminal->master = -1;
bc9724f7 760
2083d59d
CB
761 if (terminal->slave >= 0)
762 close(terminal->slave);
763 terminal->slave = -1;
bc9724f7 764
2083d59d
CB
765 if (terminal->log_fd >= 0)
766 close(terminal->log_fd);
767 terminal->log_fd = -1;
63376d7d
DL
768}
769
3b988b33
CB
770/**
771 * Note that this function needs to run before the mainloop starts. Since we
2083d59d
CB
772 * register a handler for the terminal's masterfd when we create the mainloop
773 * the terminal handler needs to see an allocated ringbuffer.
3b988b33 774 */
dcad02f8 775static int lxc_terminal_create_ringbuf(struct lxc_terminal *terminal)
3b988b33
CB
776{
777 int ret;
2083d59d
CB
778 struct lxc_ringbuf *buf = &terminal->ringbuf;
779 uint64_t size = terminal->buffer_size;
3b988b33
CB
780
781 /* no ringbuffer previously allocated and no ringbuffer requested */
782 if (!buf->addr && size <= 0)
783 return 0;
784
785 /* ringbuffer allocated but no new ringbuffer requested */
786 if (buf->addr && size <= 0) {
787 lxc_ringbuf_release(buf);
788 buf->addr = NULL;
789 buf->r_off = 0;
790 buf->w_off = 0;
791 buf->size = 0;
2083d59d 792 TRACE("Deallocated terminal ringbuffer");
3b988b33
CB
793 return 0;
794 }
795
796 if (size <= 0)
797 return 0;
798
799 /* check wether the requested size for the ringbuffer has changed */
800 if (buf->addr && buf->size != size) {
2083d59d
CB
801 TRACE("Terminal ringbuffer size changed from %" PRIu64
802 " to %" PRIu64 " bytes. Deallocating terminal ringbuffer",
3b988b33
CB
803 buf->size, size);
804 lxc_ringbuf_release(buf);
805 }
806
807 ret = lxc_ringbuf_create(buf, size);
808 if (ret < 0) {
2083d59d 809 ERROR("Failed to setup %" PRIu64 " byte terminal ringbuffer", size);
3b988b33
CB
810 return -1;
811 }
812
2083d59d 813 TRACE("Allocated %" PRIu64 " byte terminal ringbuffer", size);
3b988b33
CB
814 return 0;
815}
816
a0309168 817/**
2083d59d
CB
818 * This is the terminal log file. Please note that the terminal log file is
819 * (implementation wise not content wise) independent of the terminal ringbuffer.
a0309168 820 */
dcad02f8 821int lxc_terminal_create_log_file(struct lxc_terminal *terminal)
a0309168 822{
2083d59d 823 if (!terminal->log_path)
a0309168
CB
824 return 0;
825
2083d59d
CB
826 terminal->log_fd = lxc_unpriv(open(terminal->log_path, O_CLOEXEC | O_RDWR | O_CREAT | O_APPEND, 0600));
827 if (terminal->log_fd < 0) {
828 SYSERROR("Failed to open terminal log file \"%s\"", terminal->log_path);
a0309168
CB
829 return -1;
830 }
831
2083d59d 832 DEBUG("Using \"%s\" as terminal log file", terminal->log_path);
a0309168
CB
833 return 0;
834}
835
dcad02f8 836int lxc_terminal_create(struct lxc_terminal *terminal)
63376d7d 837{
69629c82 838 int ret, saved_errno;
b5159817 839
2083d59d 840 ret = openpty(&terminal->master, &terminal->slave, terminal->name, NULL,
5777fe90 841 NULL);
69629c82 842 saved_errno = errno;
467c7ff3 843 if (ret < 0) {
69629c82 844 ERROR("%s - Failed to allocate a pty", strerror(saved_errno));
b5159817
DE
845 return -1;
846 }
847
2083d59d 848 ret = fcntl(terminal->master, F_SETFD, FD_CLOEXEC);
69629c82 849 if (ret < 0) {
2083d59d 850 SYSERROR("Failed to set FD_CLOEXEC flag on terminal master");
b5159817
DE
851 goto err;
852 }
853
2083d59d 854 ret = fcntl(terminal->slave, F_SETFD, FD_CLOEXEC);
69629c82 855 if (ret < 0) {
2083d59d 856 SYSERROR("Failed to set FD_CLOEXEC flag on terminal slave");
b5159817
DE
857 goto err;
858 }
859
2083d59d 860 ret = lxc_terminal_peer_default(terminal);
467c7ff3 861 if (ret < 0) {
69629c82 862 ERROR("Failed to allocate a peer pty device");
467c7ff3
CB
863 goto err;
864 }
b5159817 865
5777fe90
CB
866 return 0;
867
868err:
2083d59d 869 lxc_terminal_delete(terminal);
5777fe90
CB
870 return -ENODEV;
871}
872
564e31c4 873int lxc_terminal_setup(struct lxc_conf *conf)
5777fe90
CB
874{
875 int ret;
dcad02f8 876 struct lxc_terminal *terminal = &conf->console;
5777fe90 877
2083d59d
CB
878 if (terminal->path && !strcmp(terminal->path, "none")) {
879 INFO("No terminal was requested");
5777fe90
CB
880 return 0;
881 }
882
96eee564 883 ret = lxc_terminal_create(terminal);
5777fe90
CB
884 if (ret < 0)
885 return -1;
886
2083d59d
CB
887 /* create terminal log file */
888 ret = lxc_terminal_create_log_file(terminal);
a0309168
CB
889 if (ret < 0)
890 goto err;
891
2083d59d
CB
892 /* create terminal ringbuffer */
893 ret = lxc_terminal_create_ringbuf(terminal);
a0309168
CB
894 if (ret < 0)
895 goto err;
b5159817
DE
896
897 return 0;
898
899err:
2083d59d 900 lxc_terminal_delete(terminal);
69629c82 901 return -ENODEV;
b5159817
DE
902}
903
ae6d3913 904int lxc_terminal_set_stdfds(int fd)
0d9acb99 905{
39a78bbe 906 if (fd < 0)
0d9acb99 907 return 0;
b5159817 908
39a78bbe
CB
909 if (isatty(STDIN_FILENO))
910 if (dup2(fd, STDIN_FILENO) < 0) {
911 SYSERROR("failed to duplicate stdin.");
912 return -1;
913 }
914
915 if (isatty(STDOUT_FILENO))
916 if (dup2(fd, STDOUT_FILENO) < 0) {
917 SYSERROR("failed to duplicate stdout.");
918 return -1;
919 }
920
921 if (isatty(STDERR_FILENO))
922 if (dup2(fd, STDERR_FILENO) < 0) {
923 SYSERROR("failed to duplicate stderr.");
924 return -1;
925 }
926
0d9acb99
DE
927 return 0;
928}
b5159817 929
52f9292f
CB
930int lxc_terminal_stdin_cb(int fd, uint32_t events, void *cbdata,
931 struct lxc_epoll_descr *descr)
b5159817
DE
932{
933 struct lxc_tty_state *ts = cbdata;
934 char c;
935
97bc2422 936 if (fd != ts->stdinfd)
a529bc25 937 return LXC_MAINLOOP_CLOSE;
97bc2422 938
e66b6c96 939 if (lxc_read_nointr(ts->stdinfd, &c, 1) <= 0)
a529bc25 940 return LXC_MAINLOOP_CLOSE;
63376d7d 941
525e2117 942 if (ts->escape >= 1) {
2083d59d 943 /* we want to exit the terminal with Ctrl+a q */
014d5e1e
CB
944 if (c == ts->escape && !ts->saw_escape) {
945 ts->saw_escape = 1;
946 return 0;
947 }
5c294060 948
014d5e1e 949 if (c == 'q' && ts->saw_escape)
a529bc25 950 return LXC_MAINLOOP_CLOSE;
014d5e1e
CB
951
952 ts->saw_escape = 0;
953 }
63376d7d 954
e66b6c96 955 if (lxc_write_nointr(ts->masterfd, &c, 1) <= 0)
a529bc25 956 return LXC_MAINLOOP_CLOSE;
b5159817 957
63376d7d
DL
958 return 0;
959}
960
ee9102ff
CB
961int lxc_terminal_master_cb(int fd, uint32_t events, void *cbdata,
962 struct lxc_epoll_descr *descr)
63376d7d 963{
b5159817 964 struct lxc_tty_state *ts = cbdata;
de708fb7 965 char buf[LXC_TERMINAL_BUFFER_SIZE];
0d4137cc 966 int r, w;
63376d7d 967
97bc2422 968 if (fd != ts->masterfd)
a529bc25 969 return LXC_MAINLOOP_CLOSE;
97bc2422 970
e66b6c96
CB
971 r = lxc_read_nointr(fd, buf, sizeof(buf));
972 if (r <= 0)
a529bc25 973 return LXC_MAINLOOP_CLOSE;
1560f6c9 974
e66b6c96
CB
975 w = lxc_write_nointr(ts->stdoutfd, buf, r);
976 if (w <= 0) {
a529bc25 977 return LXC_MAINLOOP_CLOSE;
e66b6c96 978 } else if (w != r) {
a529bc25 979 SYSERROR("Failed to write");
b5159817 980 return 1;
f78a1f32
DL
981 }
982
b5159817
DE
983 return 0;
984}
985
c86e2584 986int lxc_terminal_getfd(struct lxc_container *c, int *ttynum, int *masterfd)
b5159817
DE
987{
988 return lxc_cmd_console(c->name, ttynum, masterfd, c->config_path);
989}
990
991int lxc_console(struct lxc_container *c, int ttynum,
992 int stdinfd, int stdoutfd, int stderrfd,
993 int escape)
994{
995 int ret, ttyfd, masterfd;
996 struct lxc_epoll_descr descr;
997 struct termios oldtios;
998 struct lxc_tty_state *ts;
25964232 999 int istty = 0;
b5159817 1000
b5159817 1001 ttyfd = lxc_cmd_console(c->name, &ttynum, &masterfd, c->config_path);
6834f805
CB
1002 if (ttyfd < 0)
1003 return -1;
b5159817
DE
1004
1005 ret = setsid();
33b4b411
CB
1006 if (ret < 0)
1007 TRACE("Process is already group leader");
b5159817 1008
dc8c7883 1009 ts = lxc_terminal_signal_init(stdinfd, masterfd);
b5159817
DE
1010 if (!ts) {
1011 ret = -1;
33b4b411 1012 goto close_fds;
b5159817
DE
1013 }
1014 ts->escape = escape;
1015 ts->winch_proxy = c->name;
1016 ts->winch_proxy_lxcpath = c->config_path;
3b975060 1017 ts->stdoutfd = stdoutfd;
b5159817 1018
6834f805 1019 istty = isatty(stdinfd);
25964232 1020 if (istty) {
4e9c0330 1021 lxc_terminal_winsz(stdinfd, masterfd);
8ccbbf94 1022 lxc_cmd_terminal_winch(ts->winch_proxy, ts->winch_proxy_lxcpath);
6834f805
CB
1023 } else {
1024 INFO("File descriptor %d does not refer to a tty device", stdinfd);
25964232 1025 }
b5159817
DE
1026
1027 ret = lxc_mainloop_open(&descr);
1028 if (ret) {
33b4b411
CB
1029 ERROR("Failed to create mainloop");
1030 goto sigwinch_fini;
b5159817
DE
1031 }
1032
341c2aed
CB
1033 if (ts->sigfd != -1) {
1034 ret = lxc_mainloop_add_handler(&descr, ts->sigfd,
9bafc8cb 1035 lxc_terminal_signalfd_cb, ts);
33b4b411 1036 if (ret < 0) {
0519b5cc 1037 ERROR("Failed to add signal handler to mainloop");
33b4b411 1038 goto close_mainloop;
341c2aed 1039 }
b5159817
DE
1040 }
1041
1042 ret = lxc_mainloop_add_handler(&descr, ts->stdinfd,
52f9292f 1043 lxc_terminal_stdin_cb, ts);
33b4b411
CB
1044 if (ret < 0) {
1045 ERROR("Failed to add stdin handler");
1046 goto close_mainloop;
b5159817
DE
1047 }
1048
1049 ret = lxc_mainloop_add_handler(&descr, ts->masterfd,
ee9102ff 1050 lxc_terminal_master_cb, ts);
33b4b411
CB
1051 if (ret < 0) {
1052 ERROR("Failed to add master handler");
1053 goto close_mainloop;
b5159817
DE
1054 }
1055
686df166
CB
1056 if (ts->escape >= 1) {
1057 fprintf(stderr,
1058 "\n"
6834f805
CB
1059 "Connected to tty %1$d\n"
1060 "Type <Ctrl+%2$c q> to exit the console, "
1061 "<Ctrl+%2$c Ctrl+%2$c> to enter Ctrl+%2$c itself\n",
1062 ttynum, 'a' + escape - 1);
686df166 1063 }
6834f805
CB
1064
1065 if (istty) {
1066 ret = lxc_setup_tios(stdinfd, &oldtios);
1067 if (ret < 0)
1068 goto close_mainloop;
1069 }
1070
025ed0f3 1071 ret = lxc_mainloop(&descr, -1);
33b4b411
CB
1072 if (ret < 0) {
1073 ERROR("The mainloop returned an error");
6834f805 1074 goto restore_tios;
b5159817
DE
1075 }
1076
1077 ret = 0;
1078
6834f805
CB
1079restore_tios:
1080 if (istty) {
1081 istty = tcsetattr(stdinfd, TCSAFLUSH, &oldtios);
1082 if (istty < 0)
1083 WARN("%s - Failed to restore terminal properties",
1084 strerror(errno));
1085 }
1086
33b4b411 1087close_mainloop:
b5159817 1088 lxc_mainloop_close(&descr);
33b4b411
CB
1089
1090sigwinch_fini:
a8867251 1091 lxc_terminal_signal_fini(ts);
33b4b411
CB
1092
1093close_fds:
b5159817
DE
1094 close(masterfd);
1095 close(ttyfd);
33b4b411 1096
b5159817 1097 return ret;
63376d7d 1098}
e98affda
CB
1099
1100int lxc_make_controlling_pty(int fd)
1101{
1102 int ret;
1103
1104 setsid();
1105
1106 ret = ioctl(fd, TIOCSCTTY, (char *)NULL);
1107 if (ret < 0)
1108 return -1;
1109
1110 return 0;
1111}
1112
1113int lxc_login_pty(int fd)
1114{
1115 int ret;
1116
1117 ret = lxc_make_controlling_pty(fd);
1118 if (ret < 0)
1119 return -1;
1120
ae6d3913 1121 ret = lxc_terminal_set_stdfds(fd);
e98affda
CB
1122 if (ret < 0)
1123 return -1;
1124
1125 if (fd > STDERR_FILENO)
1126 close(fd);
1127
1128 return 0;
1129}
1130
99a04585 1131void lxc_terminal_info_init(struct lxc_terminal_info *pty)
e98affda
CB
1132{
1133 pty->name[0] = '\0';
1134 pty->master = -EBADF;
1135 pty->slave = -EBADF;
1136 pty->busy = -1;
1137}
1138
dcad02f8 1139void lxc_terminal_init(struct lxc_terminal *pty)
e98affda
CB
1140{
1141 memset(pty, 0, sizeof(*pty));
1142 pty->slave = -EBADF;
1143 pty->master = -EBADF;
1144 pty->peer = -EBADF;
1145 pty->log_fd = -EBADF;
780a7c82 1146 lxc_terminal_info_init(&pty->peerpty);
e98affda
CB
1147}
1148
dcad02f8 1149void lxc_terminal_conf_free(struct lxc_terminal *terminal)
e98affda 1150{
2083d59d
CB
1151 free(terminal->log_path);
1152 free(terminal->path);
1153 if (terminal->buffer_size > 0 && terminal->ringbuf.addr)
1154 lxc_ringbuf_release(&terminal->ringbuf);
e98affda 1155}
7cfeddd7 1156
dcad02f8 1157int lxc_terminal_map_ids(struct lxc_conf *c, struct lxc_terminal *pty)
7cfeddd7
CB
1158{
1159 int ret;
1160
1161 if (lxc_list_empty(&c->id_map))
1162 return 0;
1163
1164 ret = strcmp(pty->name, "");
1165 if (ret == 0)
1166 return 0;
1167
1168 ret = chown_mapped_root(pty->name, c);
1169 if (ret < 0) {
1170 ERROR("Failed to chown \"%s\"", pty->name);
1171 return -1;
1172 }
1173
1174 TRACE("Chowned \"%s\"", pty->name);
1175
1176 return 0;
1177}