X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fnspawn%2Fnspawn.c;h=caf1aa9bedfee1373d5aca396cbf26a1dc50d37f;hb=354bfd2b166d1044eea05ac9ba1cda05c93a24bc;hp=b3ca10ea9116c67168e904592f55e532d194e1a3;hpb=9e5548644f76e893c246d54ae613856b67b8dc1d;p=elogind.git diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index b3ca10ea9..caf1aa9be 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -40,6 +40,7 @@ #include #include #include +#include #include "sd-daemon.h" #include "sd-bus.h" @@ -62,6 +63,7 @@ #include "bus-error.h" #include "ptyfwd.h" #include "bus-kernel.h" +#include "env-util.h" #ifndef TTY_GID #define TTY_GID 5 @@ -111,6 +113,7 @@ static uint64_t arg_retain = (1ULL << CAP_AUDIT_CONTROL); static char **arg_bind = NULL; static char **arg_bind_ro = NULL; +static char **arg_setenv = NULL; static int help(void) { @@ -133,7 +136,8 @@ static int help(void) { " -j Equivalent to --link-journal=host\n" " --bind=PATH[:PATH] Bind mount a file or directory from the host into\n" " the container\n" - " --bind-ro=PATH[:PATH] Similar, but creates a read-only bind mount\n", + " --bind-ro=PATH[:PATH] Similar, but creates a read-only bind mount\n" + " --setenv=NAME=VALUE Pass an environment variable to PID 1\n", program_invocation_short_name); return 0; @@ -150,7 +154,8 @@ static int parse_argv(int argc, char *argv[]) { ARG_DROP_CAPABILITY, ARG_LINK_JOURNAL, ARG_BIND, - ARG_BIND_RO + ARG_BIND_RO, + ARG_SETENV, }; static const struct option options[] = { @@ -169,6 +174,7 @@ static int parse_argv(int argc, char *argv[]) { { "bind-ro", required_argument, NULL, ARG_BIND_RO }, { "machine", required_argument, NULL, 'M' }, { "slice", required_argument, NULL, 'S' }, + { "setenv", required_argument, NULL, ARG_SETENV }, {} }; @@ -333,6 +339,23 @@ static int parse_argv(int argc, char *argv[]) { break; } + case ARG_SETENV: { + char **n; + + if (!env_assignment_is_valid(optarg)) { + log_error("Environment variable assignment '%s' is not valid.", optarg); + return -EINVAL; + } + + n = strv_env_set(arg_setenv, optarg); + if (!n) + return log_oom(); + + strv_free(arg_setenv); + arg_setenv = n; + break; + } + case '?': return -EINVAL; @@ -804,14 +827,11 @@ static int setup_hostname(void) { } static int setup_journal(const char *directory) { - sd_id128_t machine_id; + sd_id128_t machine_id, this_id; _cleanup_free_ char *p = NULL, *b = NULL, *q = NULL, *d = NULL; char *id; int r; - if (arg_link_journal == LINK_NO) - return 0; - p = strappend(directory, "/etc/machine-id"); if (!p) return log_oom(); @@ -835,6 +855,24 @@ static int setup_journal(const char *directory) { return r; } + r = sd_id128_get_machine(&this_id); + if (r < 0) { + log_error("Failed to retrieve machine ID: %s", strerror(-r)); + return r; + } + + if (sd_id128_equal(machine_id, this_id)) { + log_full(arg_link_journal == LINK_AUTO ? LOG_WARNING : LOG_ERR, + "Host and machine ids are equal (%s): refusing to link journals", id); + if (arg_link_journal == LINK_AUTO) + return 0; + return + -EEXIST; + } + + if (arg_link_journal == LINK_NO) + return 0; + free(p); p = strappend("/var/log/journal/", id); q = strjoin(directory, "/var/log/journal/", id, NULL); @@ -959,7 +997,7 @@ static int drop_capabilities(void) { return capability_bounding_set_drop(~arg_retain, false); } -static int register_machine(void) { +static int register_machine(pid_t pid) { _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_bus_unref_ sd_bus *bus = NULL; int r; @@ -983,7 +1021,7 @@ static int register_machine(void) { SD_BUS_MESSAGE_APPEND_ID128(arg_uuid), "nspawn", "container", - (uint32_t) 0, + (uint32_t) pid, strempty(arg_directory), !isempty(arg_slice), "Slice", "s", arg_slice); if (r < 0) { @@ -1060,7 +1098,7 @@ static bool audit_enabled(void) { int main(int argc, char *argv[]) { pid_t pid = 0; int r = EXIT_FAILURE, k; - _cleanup_close_ int master = -1, kdbus_fd = -1; + _cleanup_close_ int master = -1, kdbus_fd = -1, sync_fd = -1; int n_fd_passed; const char *console = NULL; sigset_t mask; @@ -1176,7 +1214,13 @@ int main(int argc, char *argv[]) { log_debug("Successfully created kdbus namespace as %s", kdbus_namespace); if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_NONBLOCK|SOCK_CLOEXEC, 0, kmsg_socket_pair) < 0) { - log_error("Failed to create kmsg socket pair."); + log_error("Failed to create kmsg socket pair: %m"); + goto finish; + } + + sync_fd = eventfd(0, EFD_CLOEXEC); + if (sync_fd < 0) { + log_error("Failed to create event fd: %m"); goto finish; } @@ -1206,7 +1250,7 @@ int main(int argc, char *argv[]) { gid_t gid = (gid_t) -1; unsigned n_env = 2; const char *envp[] = { - "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "PATH=" DEFAULT_PATH_SPLIT_USR, "container=systemd-nspawn", /* LXC sets container=lxc, so follow the scheme here */ NULL, /* TERM */ NULL, /* HOME */ @@ -1217,6 +1261,8 @@ int main(int argc, char *argv[]) { NULL, /* LISTEN_PID */ NULL }; + char **env_use; + eventfd_t x; envp[n_env] = strv_find_prefix(environ, "TERM="); if (envp[n_env]) @@ -1264,10 +1310,6 @@ int main(int argc, char *argv[]) { goto child_fail; } - r = register_machine(); - if (r < 0) - goto finish; - /* Mark everything as slave, so that we still * receive mounts from the real root, but don't * propagate mounts to the real root. */ @@ -1444,6 +1486,23 @@ int main(int argc, char *argv[]) { setup_hostname(); + eventfd_read(sync_fd, &x); + close_nointr_nofail(sync_fd); + sync_fd = -1; + + if (!strv_isempty(arg_setenv)) { + char **n; + + n = strv_env_merge(2, envp, arg_setenv); + if (!n) { + log_oom(); + goto child_fail; + } + + env_use = n; + } else + env_use = (char**) envp; + if (arg_boot) { char **a; size_t l; @@ -1455,18 +1514,18 @@ int main(int argc, char *argv[]) { memcpy(a + 1, argv + optind, l * sizeof(char*)); a[0] = (char*) "/usr/lib/systemd/systemd"; - execve(a[0], a, (char**) envp); + execve(a[0], a, env_use); a[0] = (char*) "/lib/systemd/systemd"; - execve(a[0], a, (char**) envp); + execve(a[0], a, env_use); a[0] = (char*) "/sbin/init"; - execve(a[0], a, (char**) envp); + execve(a[0], a, env_use); } else if (argc > optind) - execvpe(argv[optind], argv + optind, (char**) envp); + execvpe(argv[optind], argv + optind, env_use); else { chdir(home ? home : "/root"); - execle("/bin/bash", "-bash", NULL, (char**) envp); + execle("/bin/bash", "-bash", NULL, env_use); } log_error("execv() failed: %m"); @@ -1478,6 +1537,14 @@ int main(int argc, char *argv[]) { fdset_free(fds); fds = NULL; + r = register_machine(pid); + if (r < 0) + goto finish; + + eventfd_write(sync_fd, 1); + close_nointr_nofail(sync_fd); + sync_fd = -1; + k = process_pty(master, &mask, arg_boot ? pid : 0, SIGRTMIN+3); if (k < 0) { r = EXIT_FAILURE; @@ -1537,6 +1604,7 @@ finish: free(arg_directory); free(arg_machine); + free(arg_setenv); return r; }