chiark / gitweb /
nspawn: add new --setenv= switch to set an environment variable for the container...
[elogind.git] / src / nspawn / nspawn.c
index 583912f57c51bb3c0b40c7646896c69c5e374ffb..a85579b9402a0c8310fd10cd8c4cb20055449c23 100644 (file)
@@ -62,6 +62,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 +112,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 +135,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 +153,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 +173,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 +338,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 +826,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 +854,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);
@@ -1067,6 +1104,7 @@ int main(int argc, char *argv[]) {
         _cleanup_close_pipe_ int kmsg_socket_pair[2] = { -1, -1 };
         _cleanup_fdset_free_ FDSet *fds = NULL;
         _cleanup_free_ char *kdbus_namespace = NULL;
+        const char *ns;
 
         log_parse_environment();
         log_open();
@@ -1167,7 +1205,8 @@ int main(int argc, char *argv[]) {
                 goto finish;
         }
 
-        kdbus_fd = bus_kernel_create_namespace(arg_machine, &kdbus_namespace);
+        ns = strappenda("machine-", arg_machine);
+        kdbus_fd = bus_kernel_create_namespace(ns, &kdbus_namespace);
         if (r < 0)
                 log_debug("Failed to create kdbus namespace: %s", strerror(-r));
         else
@@ -1215,6 +1254,7 @@ int main(int argc, char *argv[]) {
                                 NULL, /* LISTEN_PID */
                                 NULL
                         };
+                        char **env_use;
 
                         envp[n_env] = strv_find_prefix(environ, "TERM=");
                         if (envp[n_env])
@@ -1442,6 +1482,19 @@ int main(int argc, char *argv[]) {
 
                         setup_hostname();
 
+                        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;
@@ -1453,18 +1506,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");
@@ -1535,6 +1588,7 @@ finish:
 
         free(arg_directory);
         free(arg_machine);
+        free(arg_setenv);
 
         return r;
 }