char in_buffer[LINE_MAX], out_buffer[LINE_MAX];
size_t in_buffer_full = 0, out_buffer_full = 0;
struct epoll_event stdin_ev, stdout_ev, master_ev, signal_ev;
bool stdin_readable = false, stdout_writable = false, master_readable = false, master_writable = false;
int ep = -1, signal_fd = -1, r;
char in_buffer[LINE_MAX], out_buffer[LINE_MAX];
size_t in_buffer_full = 0, out_buffer_full = 0;
struct epoll_event stdin_ev, stdout_ev, master_ev, signal_ev;
bool stdin_readable = false, stdout_writable = false, master_readable = false, master_writable = false;
int ep = -1, signal_fd = -1, r;
fd_nonblock(STDIN_FILENO, 1);
fd_nonblock(STDOUT_FILENO, 1);
fd_nonblock(STDIN_FILENO, 1);
fd_nonblock(STDOUT_FILENO, 1);
- zero(stdin_ev);
- stdin_ev.events = EPOLLIN|EPOLLET;
- stdin_ev.data.fd = STDIN_FILENO;
+ /* We read from STDIN only if this is actually a TTY,
+ * otherwise we assume non-interactivity. */
+ if (isatty(STDIN_FILENO)) {
+ zero(stdin_ev);
+ stdin_ev.events = EPOLLIN|EPOLLET;
+ stdin_ev.data.fd = STDIN_FILENO;
+
+ if (epoll_ctl(ep, EPOLL_CTL_ADD, STDIN_FILENO, &stdin_ev) < 0) {
+ log_error("Failed to register STDIN in epoll: %m");
+ r = -errno;
+ goto finish;
+ }
+ }
- if (epoll_ctl(ep, EPOLL_CTL_ADD, STDIN_FILENO, &stdin_ev) < 0 ||
- epoll_ctl(ep, EPOLL_CTL_ADD, STDOUT_FILENO, &stdout_ev) < 0 ||
+ if (epoll_ctl(ep, EPOLL_CTL_ADD, STDOUT_FILENO, &stdout_ev) < 0 ||
epoll_ctl(ep, EPOLL_CTL_ADD, master, &master_ev) < 0 ||
epoll_ctl(ep, EPOLL_CTL_ADD, signal_fd, &signal_ev) < 0) {
epoll_ctl(ep, EPOLL_CTL_ADD, master, &master_ev) < 0 ||
epoll_ctl(ep, EPOLL_CTL_ADD, signal_fd, &signal_ev) < 0) {
/* The window size changed, let's forward that. */
if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) >= 0)
ioctl(master, TIOCSWINSZ, &ws);
/* The window size changed, let's forward that. */
if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) >= 0)
ioctl(master, TIOCSWINSZ, &ws);
+ } else if (sfsi.ssi_signo == SIGTERM && arg_boot && !tried_orderly_shutdown) {
+
+ log_info("Trying to halt container. Send SIGTERM again to trigger immediate termination.");
+
+ /* This only works for systemd... */
+ tried_orderly_shutdown = true;
+ kill(pid, SIGRTMIN+3);
+
int r = EXIT_FAILURE, k;
char *oldcg = NULL, *newcg = NULL;
char **controller = NULL;
int r = EXIT_FAILURE, k;
char *oldcg = NULL, *newcg = NULL;
char **controller = NULL;
const char *console = NULL;
struct termios saved_attr, raw_attr;
sigset_t mask;
bool saved_attr_valid = false;
struct winsize ws;
int kmsg_socket_pair[2] = { -1, -1 };
const char *console = NULL;
struct termios saved_attr, raw_attr;
sigset_t mask;
bool saved_attr_valid = false;
struct winsize ws;
int kmsg_socket_pair[2] = { -1, -1 };
+ log_close();
+ n_fd_passed = sd_listen_fds(false);
+ if (n_fd_passed > 0) {
+ k = fdset_new_listen_fds(&fds, false);
+ if (k < 0) {
+ log_error("Failed to collect file descriptors: %s", strerror(-k));
+ goto finish;
+ }
+ }
+ fdset_close_others(fds);
+ log_open();
+
k = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 0, &oldcg);
if (k < 0) {
log_error("Failed to determine current cgroup: %s", strerror(-k));
k = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 0, &oldcg);
if (k < 0) {
log_error("Failed to determine current cgroup: %s", strerror(-k));
- if (tcgetattr(STDIN_FILENO, &saved_attr) < 0) {
- log_error("Failed to get terminal attributes: %m");
- goto finish;
- }
-
- saved_attr_valid = true;
+ if (tcgetattr(STDIN_FILENO, &saved_attr) >= 0) {
+ saved_attr_valid = true;
if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_NONBLOCK|SOCK_CLOEXEC, 0, kmsg_socket_pair) < 0) {
log_error("Failed to create kmsg socket pair");
if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_NONBLOCK|SOCK_CLOEXEC, 0, kmsg_socket_pair) < 0) {
log_error("Failed to create kmsg socket pair");
- if (tcsetattr(STDIN_FILENO, TCSANOW, &raw_attr) < 0) {
- log_error("Failed to set terminal attributes: %m");
- goto finish;
+ if (saved_attr_valid) {
+ if (tcsetattr(STDIN_FILENO, TCSANOW, &raw_attr) < 0) {
+ log_error("Failed to set terminal attributes: %m");
+ goto finish;
+ }
}
pid = syscall(__NR_clone, SIGCHLD|CLONE_NEWIPC|CLONE_NEWNS|CLONE_NEWPID|CLONE_NEWUTS|(arg_private_network ? CLONE_NEWNET : 0), NULL);
}
pid = syscall(__NR_clone, SIGCHLD|CLONE_NEWIPC|CLONE_NEWNS|CLONE_NEWPID|CLONE_NEWUTS|(arg_private_network ? CLONE_NEWNET : 0), NULL);
const char *envp[] = {
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"container=systemd-nspawn", /* LXC sets container=lxc, so follow the scheme here */
const char *envp[] = {
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"container=systemd-nspawn", /* LXC sets container=lxc, so follow the scheme here */
close_nointr(STDIN_FILENO);
close_nointr(STDOUT_FILENO);
close_nointr(STDERR_FILENO);
close_nointr(STDIN_FILENO);
close_nointr(STDOUT_FILENO);
close_nointr(STDERR_FILENO);
reset_all_signal_handlers();
assert_se(sigemptyset(&mask) == 0);
assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
reset_all_signal_handlers();
assert_se(sigemptyset(&mask) == 0);
assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
- if (open_terminal(console, O_RDWR) != STDIN_FILENO ||
- dup2(STDIN_FILENO, STDOUT_FILENO) != STDOUT_FILENO ||
- dup2(STDIN_FILENO, STDERR_FILENO) != STDERR_FILENO)
+ k = open_terminal(console, O_RDWR);
+ if (k != STDIN_FILENO) {
+ if (k >= 0) {
+ close_nointr_nofail(k);
+ k = -EINVAL;
+ }
+
+ log_error("Failed to open console: %s", strerror(-k));
+ goto child_fail;
+ }
+
+ if (dup2(STDIN_FILENO, STDOUT_FILENO) != STDOUT_FILENO ||
+ dup2(STDIN_FILENO, STDERR_FILENO) != STDERR_FILENO) {
+ log_error("Failed to duplicate console: %m");
- if ((asprintf((char**)(envp + 3), "HOME=%s", home ? home: "/root") < 0) ||
- (asprintf((char**)(envp + 4), "USER=%s", arg_user ? arg_user : "root") < 0) ||
- (asprintf((char**)(envp + 5), "LOGNAME=%s", arg_user ? arg_user : "root") < 0)) {
+ if ((asprintf((char**)(envp + n_env++), "HOME=%s", home ? home: "/root") < 0) ||
+ (asprintf((char**)(envp + n_env++), "USER=%s", arg_user ? arg_user : "root") < 0) ||
+ (asprintf((char**)(envp + n_env++), "LOGNAME=%s", arg_user ? arg_user : "root") < 0)) {
- if (asprintf((char**)(envp + 6), "container_uuid=%s", arg_uuid) < 0) {
+ if (asprintf((char**)(envp + n_env++), "container_uuid=%s", arg_uuid) < 0) {
+ log_oom();
+ goto child_fail;
+ }
+ }
+
+ if (fdset_size(fds) > 0) {
+ k = fdset_cloexec(fds, false);
+ if (k < 0) {
+ log_error("Failed to unset O_CLOEXEC for file descriptors.");
+ goto child_fail;
+ }
+
+ if ((asprintf((char **)(envp + n_env++), "LISTEN_FDS=%u", n_fd_passed) < 0) ||
+ (asprintf((char **)(envp + n_env++), "LISTEN_PID=%lu", (unsigned long) getpid()) < 0)) {