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 int process_pty(int master, sigset_t *mask, pid_t kill_pid, int signo) {
32 char in_buffer[LINE_MAX], out_buffer[LINE_MAX];
33 size_t in_buffer_full = 0, out_buffer_full = 0;
34 struct epoll_event stdin_ev, stdout_ev, master_ev, signal_ev;
35 bool stdin_readable = false, stdout_writable = false, master_readable = false, master_writable = false;
36 bool tried_orderly_shutdown = false;
37 _cleanup_close_ int ep = -1, signal_fd = -1;
41 assert(kill_pid == 0 || kill_pid > 1);
42 assert(signo >= 0 && signo < _NSIG);
44 fd_nonblock(STDIN_FILENO, 1);
45 fd_nonblock(STDOUT_FILENO, 1);
46 fd_nonblock(master, 1);
48 signal_fd = signalfd(-1, mask, SFD_NONBLOCK|SFD_CLOEXEC);
50 log_error("signalfd(): %m");
54 ep = epoll_create1(EPOLL_CLOEXEC);
56 log_error("Failed to create epoll: %m");
60 /* We read from STDIN only if this is actually a TTY,
61 * otherwise we assume non-interactivity. */
62 if (isatty(STDIN_FILENO)) {
64 stdin_ev.events = EPOLLIN|EPOLLET;
65 stdin_ev.data.fd = STDIN_FILENO;
67 if (epoll_ctl(ep, EPOLL_CTL_ADD, STDIN_FILENO, &stdin_ev) < 0) {
68 log_error("Failed to register STDIN in epoll: %m");
74 stdout_ev.events = EPOLLOUT|EPOLLET;
75 stdout_ev.data.fd = STDOUT_FILENO;
78 master_ev.events = EPOLLIN|EPOLLOUT|EPOLLET;
79 master_ev.data.fd = master;
82 signal_ev.events = EPOLLIN;
83 signal_ev.data.fd = signal_fd;
85 if (epoll_ctl(ep, EPOLL_CTL_ADD, STDOUT_FILENO, &stdout_ev) < 0) {
87 log_error("Failed to register stdout in epoll: %m");
91 /* stdout without epoll support. Likely redirected to regular file. */
92 stdout_writable = true;
95 if (epoll_ctl(ep, EPOLL_CTL_ADD, master, &master_ev) < 0 ||
96 epoll_ctl(ep, EPOLL_CTL_ADD, signal_fd, &signal_ev) < 0) {
97 log_error("Failed to register fds in epoll: %m");
102 struct epoll_event ev[16];
106 nfds = epoll_wait(ep, ev, ELEMENTSOF(ev), -1);
109 if (errno == EINTR || errno == EAGAIN)
112 log_error("epoll_wait(): %m");
118 for (i = 0; i < nfds; i++) {
119 if (ev[i].data.fd == STDIN_FILENO) {
121 if (ev[i].events & (EPOLLIN|EPOLLHUP))
122 stdin_readable = true;
124 } else if (ev[i].data.fd == STDOUT_FILENO) {
126 if (ev[i].events & (EPOLLOUT|EPOLLHUP))
127 stdout_writable = true;
129 } else if (ev[i].data.fd == master) {
131 if (ev[i].events & (EPOLLIN|EPOLLHUP))
132 master_readable = true;
134 if (ev[i].events & (EPOLLOUT|EPOLLHUP))
135 master_writable = true;
137 } else if (ev[i].data.fd == signal_fd) {
138 struct signalfd_siginfo sfsi;
141 n = read(signal_fd, &sfsi, sizeof(sfsi));
142 if (n != sizeof(sfsi)) {
145 log_error("Failed to read from signalfd: invalid block size");
149 if (errno != EINTR && errno != EAGAIN) {
150 log_error("Failed to read from signalfd: %m");
155 if (sfsi.ssi_signo == SIGWINCH) {
158 /* The window size changed, let's forward that. */
159 if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) >= 0)
160 ioctl(master, TIOCSWINSZ, &ws);
162 } else if (sfsi.ssi_signo == SIGTERM && kill_pid > 0 && signo > 0 && !tried_orderly_shutdown) {
164 if (kill(kill_pid, signo) < 0)
167 log_info("Trying to halt container. Send SIGTERM again to trigger immediate termination.");
169 /* This only works for systemd... */
170 tried_orderly_shutdown = true;
178 while ((stdin_readable && in_buffer_full <= 0) ||
179 (master_writable && in_buffer_full > 0) ||
180 (master_readable && out_buffer_full <= 0) ||
181 (stdout_writable && out_buffer_full > 0)) {
183 if (stdin_readable && in_buffer_full < LINE_MAX) {
185 k = read(STDIN_FILENO, in_buffer + in_buffer_full, LINE_MAX - in_buffer_full);
188 if (errno == EAGAIN || errno == EPIPE || errno == ECONNRESET || errno == EIO)
189 stdin_readable = false;
191 log_error("read(): %m");
195 in_buffer_full += (size_t) k;
198 if (master_writable && in_buffer_full > 0) {
200 k = write(master, in_buffer, in_buffer_full);
203 if (errno == EAGAIN || errno == EPIPE || errno == ECONNRESET || errno == EIO)
204 master_writable = false;
206 log_error("write(): %m");
211 assert(in_buffer_full >= (size_t) k);
212 memmove(in_buffer, in_buffer + k, in_buffer_full - k);
217 if (master_readable && out_buffer_full < LINE_MAX) {
219 k = read(master, out_buffer + out_buffer_full, LINE_MAX - out_buffer_full);
222 if (errno == EAGAIN || errno == EPIPE || errno == ECONNRESET || errno == EIO)
223 master_readable = false;
225 log_error("read(): %m");
229 out_buffer_full += (size_t) k;
232 if (stdout_writable && out_buffer_full > 0) {
234 k = write(STDOUT_FILENO, out_buffer, out_buffer_full);
237 if (errno == EAGAIN || errno == EPIPE || errno == ECONNRESET || errno == EIO)
238 stdout_writable = false;
240 log_error("write(): %m");
245 assert(out_buffer_full >= (size_t) k);
246 memmove(out_buffer, out_buffer + k, out_buffer_full - k);
247 out_buffer_full -= k;