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