1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010-2013 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include <sys/epoll.h>
23 #include <sys/signalfd.h>
24 #include <sys/ioctl.h>
31 #define ESCAPE_USEC USEC_PER_SEC
33 static bool look_for_escape(usec_t *timestamp, unsigned *counter, const char *buffer, size_t n) {
41 for (p = buffer; p < buffer + n; p++) {
45 usec_t nw = now(CLOCK_MONOTONIC);
47 if (*counter == 0 || nw > *timestamp + USEC_PER_SEC) {
65 static int process_pty_loop(int master, sigset_t *mask, pid_t kill_pid, int signo) {
66 char in_buffer[LINE_MAX], out_buffer[LINE_MAX];
67 size_t in_buffer_full = 0, out_buffer_full = 0;
68 struct epoll_event stdin_ev, stdout_ev, master_ev, signal_ev;
69 bool stdin_readable = false, stdout_writable = false, master_readable = false, master_writable = false;
70 bool stdin_hangup = false, stdout_hangup = false, master_hangup = false;
71 bool tried_orderly_shutdown = false, process_signalfd = false, quit = false;
72 usec_t escape_timestamp = 0;
73 unsigned escape_counter = 0;
74 _cleanup_close_ int ep = -1, signal_fd = -1;
78 assert(kill_pid == 0 || kill_pid > 1);
79 assert(signo >= 0 && signo < _NSIG);
81 fd_nonblock(STDIN_FILENO, true);
82 fd_nonblock(STDOUT_FILENO, true);
83 fd_nonblock(master, true);
85 signal_fd = signalfd(-1, mask, SFD_NONBLOCK|SFD_CLOEXEC);
87 log_error("signalfd(): %m");
91 ep = epoll_create1(EPOLL_CLOEXEC);
93 log_error("Failed to create epoll: %m");
97 /* We read from STDIN only if this is actually a TTY,
98 * otherwise we assume non-interactivity. */
99 if (isatty(STDIN_FILENO)) {
101 stdin_ev.events = EPOLLIN|EPOLLET;
102 stdin_ev.data.fd = STDIN_FILENO;
104 if (epoll_ctl(ep, EPOLL_CTL_ADD, STDIN_FILENO, &stdin_ev) < 0) {
105 log_error("Failed to register STDIN in epoll: %m");
111 stdout_ev.events = EPOLLOUT|EPOLLET;
112 stdout_ev.data.fd = STDOUT_FILENO;
115 master_ev.events = EPOLLIN|EPOLLOUT|EPOLLET;
116 master_ev.data.fd = master;
119 signal_ev.events = EPOLLIN;
120 signal_ev.data.fd = signal_fd;
122 if (epoll_ctl(ep, EPOLL_CTL_ADD, STDOUT_FILENO, &stdout_ev) < 0) {
123 if (errno != EPERM) {
124 log_error("Failed to register stdout in epoll: %m");
128 /* stdout without epoll support. Likely redirected to regular file. */
129 stdout_writable = true;
132 if (epoll_ctl(ep, EPOLL_CTL_ADD, master, &master_ev) < 0 ||
133 epoll_ctl(ep, EPOLL_CTL_ADD, signal_fd, &signal_ev) < 0) {
134 log_error("Failed to register fds in epoll: %m");
139 struct epoll_event ev[16];
143 nfds = epoll_wait(ep, ev, ELEMENTSOF(ev), quit ? 0 : -1);
146 if (errno == EINTR || errno == EAGAIN)
149 log_error("epoll_wait(): %m");
156 for (i = 0; i < nfds; i++) {
157 if (ev[i].data.fd == STDIN_FILENO) {
159 if (ev[i].events & (EPOLLIN|EPOLLHUP))
160 stdin_readable = true;
162 } else if (ev[i].data.fd == STDOUT_FILENO) {
164 if (ev[i].events & (EPOLLOUT|EPOLLHUP))
165 stdout_writable = true;
167 } else if (ev[i].data.fd == master) {
169 if (ev[i].events & (EPOLLIN|EPOLLHUP))
170 master_readable = true;
172 if (ev[i].events & (EPOLLOUT|EPOLLHUP))
173 master_writable = true;
175 } else if (ev[i].data.fd == signal_fd)
176 process_signalfd = true;
179 while ((stdin_readable && in_buffer_full <= 0) ||
180 (master_writable && in_buffer_full > 0) ||
181 (master_readable && out_buffer_full <= 0) ||
182 (stdout_writable && out_buffer_full > 0)) {
184 if (stdin_readable && in_buffer_full < LINE_MAX) {
186 k = read(STDIN_FILENO, in_buffer + in_buffer_full, LINE_MAX - in_buffer_full);
190 stdin_readable = false;
191 else if (errno == EIO || errno == EPIPE || errno == ECONNRESET) {
192 stdin_readable = false;
194 epoll_ctl(ep, EPOLL_CTL_DEL, STDIN_FILENO, NULL);
196 log_error("read(): %m");
200 /* Check if ^] has been
201 * pressed three times within
202 * one second. If we get this
203 * we quite immediately. */
204 if (look_for_escape(&escape_timestamp, &escape_counter, in_buffer + in_buffer_full, k))
207 in_buffer_full += (size_t) k;
211 if (master_writable && in_buffer_full > 0) {
213 k = write(master, in_buffer, in_buffer_full);
216 if (errno == EAGAIN || errno == EIO)
217 master_writable = false;
218 else if (errno == EPIPE || errno == ECONNRESET) {
219 master_writable = master_readable = false;
220 master_hangup = true;
221 epoll_ctl(ep, EPOLL_CTL_DEL, master, NULL);
223 log_error("write(): %m");
228 assert(in_buffer_full >= (size_t) k);
229 memmove(in_buffer, in_buffer + k, in_buffer_full - k);
234 if (master_readable && out_buffer_full < LINE_MAX) {
236 k = read(master, out_buffer + out_buffer_full, LINE_MAX - out_buffer_full);
239 /* Note that EIO on the master
240 * device might be cause by
241 * vhangup() or temporary
242 * closing of everything on
243 * the other side, we treat it
244 * like EAGAIN here and try
247 if (errno == EAGAIN || errno == EIO)
248 master_readable = false;
249 else if (errno == EPIPE || errno == ECONNRESET) {
250 master_readable = master_writable = false;
251 master_hangup = true;
252 epoll_ctl(ep, EPOLL_CTL_DEL, master, NULL);
254 log_error("read(): %m");
258 out_buffer_full += (size_t) k;
261 if (stdout_writable && out_buffer_full > 0) {
263 k = write(STDOUT_FILENO, out_buffer, out_buffer_full);
267 stdout_writable = false;
268 else if (errno == EIO || errno == EPIPE || errno == ECONNRESET) {
269 stdout_writable = false;
270 stdout_hangup = true;
271 epoll_ctl(ep, EPOLL_CTL_DEL, STDOUT_FILENO, NULL);
273 log_error("write(): %m");
278 assert(out_buffer_full >= (size_t) k);
279 memmove(out_buffer, out_buffer + k, out_buffer_full - k);
280 out_buffer_full -= k;
286 if (process_signalfd) {
287 struct signalfd_siginfo sfsi;
290 n = read(signal_fd, &sfsi, sizeof(sfsi));
291 if (n != sizeof(sfsi)) {
294 log_error("Failed to read from signalfd: invalid block size");
298 if (errno != EINTR && errno != EAGAIN) {
299 log_error("Failed to read from signalfd: %m");
304 if (sfsi.ssi_signo == SIGWINCH) {
307 /* The window size changed, let's forward that. */
308 if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) >= 0)
309 ioctl(master, TIOCSWINSZ, &ws);
311 } else if (sfsi.ssi_signo == SIGTERM && kill_pid > 0 && signo > 0 && !tried_orderly_shutdown) {
313 if (kill(kill_pid, signo) < 0)
316 log_info("Trying to halt container. Send SIGTERM again to trigger immediate termination.");
318 /* This only works for systemd... */
319 tried_orderly_shutdown = true;
323 /* Signals that where
324 * delivered via signalfd that
325 * we didn't know are a reason
331 if (stdin_hangup || stdout_hangup || master_hangup) {
332 /* Exit the loop if any side hung up and if
333 * there's nothing more to write or nothing we
336 if ((out_buffer_full <= 0 || stdout_hangup) &&
337 (in_buffer_full <= 0 || master_hangup))
343 int process_pty(int master, sigset_t *mask, pid_t kill_pid, int signo) {
344 struct termios saved_stdin_attr, raw_stdin_attr;
345 struct termios saved_stdout_attr, raw_stdout_attr;
346 bool saved_stdin = false;
347 bool saved_stdout = false;
351 if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) >= 0)
352 ioctl(master, TIOCSWINSZ, &ws);
354 if (tcgetattr(STDIN_FILENO, &saved_stdin_attr) >= 0) {
357 raw_stdin_attr = saved_stdin_attr;
358 cfmakeraw(&raw_stdin_attr);
359 raw_stdin_attr.c_oflag = saved_stdin_attr.c_oflag;
360 tcsetattr(STDIN_FILENO, TCSANOW, &raw_stdin_attr);
362 if (tcgetattr(STDOUT_FILENO, &saved_stdout_attr) >= 0) {
365 raw_stdout_attr = saved_stdout_attr;
366 cfmakeraw(&raw_stdout_attr);
367 raw_stdout_attr.c_iflag = saved_stdout_attr.c_iflag;
368 raw_stdout_attr.c_lflag = saved_stdout_attr.c_lflag;
369 tcsetattr(STDOUT_FILENO, TCSANOW, &raw_stdout_attr);
372 r = process_pty_loop(master, mask, kill_pid, signo);
375 tcsetattr(STDOUT_FILENO, TCSANOW, &saved_stdout_attr);
377 tcsetattr(STDIN_FILENO, TCSANOW, &saved_stdin_attr);
379 /* STDIN/STDOUT should not be nonblocking normally, so let's
380 * unconditionally reset it */
381 fd_nonblock(STDIN_FILENO, false);
382 fd_nonblock(STDOUT_FILENO, false);