From: Lennart Poettering Date: Sat, 22 Dec 2012 18:29:04 +0000 (+0100) Subject: nspawn: allow passing socket activation fds through nspawn X-Git-Tag: v197~107 X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=commitdiff_plain;h=842f3b0fc983d9161e152da5b765008e3e6942a8 nspawn: allow passing socket activation fds through nspawn --- diff --git a/Makefile.am b/Makefile.am index 429da59ee..8021c9db2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1662,7 +1662,9 @@ systemd_nspawn_SOURCES = \ src/core/mount-setup.c \ src/core/mount-setup.h \ src/core/loopback-setup.c \ - src/core/loopback-setup.h + src/core/loopback-setup.h \ + src/core/fdset.c \ + src/core/fdset.h systemd_nspawn_LDADD = \ libsystemd-label.la \ diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 4e4c5601e..f5fb59d2d 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -55,6 +55,7 @@ #include "loopback-setup.h" #include "sd-id128.h" #include "dev-setup.h" +#include "fdset.h" typedef enum LinkJournal { LINK_NO, @@ -1041,13 +1042,14 @@ int main(int argc, char *argv[]) { int r = EXIT_FAILURE, k; char *oldcg = NULL, *newcg = NULL; char **controller = NULL; - int master = -1; + int master = -1, n_fd_passed; 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 }; + FDSet *fds = NULL; log_parse_environment(); log_open(); @@ -1092,6 +1094,18 @@ int main(int argc, char *argv[]) { goto finish; } + 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)); @@ -1180,6 +1194,7 @@ int main(int argc, char *argv[]) { const char *home = NULL; uid_t uid = (uid_t) -1; gid_t gid = (gid_t) -1; + unsigned n_env = 0; 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 */ @@ -1188,28 +1203,45 @@ int main(int argc, char *argv[]) { NULL, /* USER */ NULL, /* LOGNAME */ NULL, /* container_uuid */ + NULL, /* LISTEN_FDS */ + NULL, /* LISTEN_PID */ NULL }; envp[2] = strv_find_prefix(environ, "TERM="); + n_env = 3; close_nointr_nofail(master); + master = -1; close_nointr(STDIN_FILENO); close_nointr(STDOUT_FILENO); close_nointr(STDERR_FILENO); - close_all_fds(&kmsg_socket_pair[1], 1); + close_nointr_nofail(kmsg_socket_pair[0]); + kmsg_socket_pair[0] = -1; 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"); goto child_fail; + } if (setsid() < 0) { log_error("setsid() failed: %m"); @@ -1256,6 +1288,7 @@ int main(int argc, char *argv[]) { goto child_fail; close_nointr_nofail(kmsg_socket_pair[1]); + kmsg_socket_pair[1] = -1; if (setup_boot_id(arg_directory) < 0) goto child_fail; @@ -1354,15 +1387,29 @@ int main(int argc, char *argv[]) { } } - 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)) { log_oom(); goto child_fail; } if (arg_uuid) { - 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)) { log_oom(); goto child_fail; } @@ -1401,10 +1448,12 @@ int main(int argc, char *argv[]) { _exit(EXIT_FAILURE); } + fdset_free(fds); + fds = NULL; + if (process_pty(master, &mask) < 0) goto finish; - if (saved_attr_valid) tcsetattr(STDIN_FILENO, TCSANOW, &saved_attr); @@ -1465,5 +1514,7 @@ finish: free(oldcg); free(newcg); + fdset_free(fds); + return r; } diff --git a/src/shared/util.h b/src/shared/util.h index af18d0b65..bf24272ea 100644 --- a/src/shared/util.h +++ b/src/shared/util.h @@ -46,7 +46,6 @@ union dirent_storage { ((NAME_MAX + 1 + sizeof(long)) & ~(sizeof(long) - 1))]; }; - /* What is interpreted as whitespace? */ #define WHITESPACE " \t\n\r" #define NEWLINE "\n\r"