nspawn: add new --chdir= switch
authorLennart Poettering <lennart@poettering.net>
Tue, 2 Feb 2016 00:52:01 +0000 (01:52 +0100)
committerLennart Poettering <lennart@poettering.net>
Wed, 3 Feb 2016 22:58:24 +0000 (23:58 +0100)
Fixes: #2192

man/systemd-nspawn.xml
man/systemd.nspawn.xml
src/nspawn/nspawn-gperf.gperf
src/nspawn/nspawn-settings.c
src/nspawn/nspawn-settings.h
src/nspawn/nspawn.c

index 28b91de..1cfef93 100644 (file)
       </varlistentry>
 
       <varlistentry>
+        <term><option>--chdir=</option></term>
+
+        <listitem><para>Change to the specified working directory before invoking the process in the container. Expects
+        an absolute path in the container's file system namespace.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
         <term><option>-u</option></term>
         <term><option>--user=</option></term>
 
index f39e1ad..7e60424 100644 (file)
       </varlistentry>
 
       <varlistentry>
+        <term><varname>WorkingDirectory=</varname></term>
+
+        <listitem><para>Selects the working directory for the process invoked in the container. Expects an absolute
+        path in the container's file system namespace. This corresponds to the <option>--chdir=</option> command line
+        switch.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
         <term><varname>Capability=</varname></term>
         <term><varname>DropCapability=</varname></term>
 
index 58f9f4c..08020d5 100644 (file)
@@ -24,6 +24,7 @@ Exec.DropCapability,          config_parse_capability,    0, offsetof(Settings,
 Exec.KillSignal,              config_parse_signal,        0, offsetof(Settings, kill_signal)
 Exec.Personality,             config_parse_personality,   0, offsetof(Settings, personality)
 Exec.MachineID,               config_parse_id128,         0, offsetof(Settings, machine_id)
+Exec.WorkingDirectory,        config_parse_path,          0, offsetof(Settings, working_directory)
 Files.ReadOnly,               config_parse_tristate,      0, offsetof(Settings, read_only)
 Files.Volatile,               config_parse_volatile_mode, 0, offsetof(Settings, volatile_mode)
 Files.Bind,                   config_parse_bind,          0, 0
index d6b64d8..3c552e0 100644 (file)
@@ -74,6 +74,7 @@ Settings* settings_free(Settings *s) {
         strv_free(s->parameters);
         strv_free(s->environment);
         free(s->user);
+        free(s->working_directory);
 
         strv_free(s->network_interfaces);
         strv_free(s->network_macvlan);
index 10230a5..236a1ba 100644 (file)
@@ -40,7 +40,8 @@ typedef enum SettingsMask {
         SETTING_READ_ONLY     = 1 << 9,
         SETTING_VOLATILE_MODE = 1 << 10,
         SETTING_CUSTOM_MOUNTS = 1 << 11,
-        _SETTINGS_MASK_ALL    = (1 << 12) -1
+        SETTING_WORKING_DIRECTORY = 1 << 12,
+        _SETTINGS_MASK_ALL    = (1 << 13) -1
 } SettingsMask;
 
 typedef struct Settings {
@@ -54,6 +55,7 @@ typedef struct Settings {
         int kill_signal;
         unsigned long personality;
         sd_id128_t machine_id;
+        char *working_directory;
 
         /* [Image] */
         int read_only;
index 9dd4c05..0dae998 100644 (file)
@@ -114,6 +114,7 @@ typedef enum LinkJournal {
 
 static char *arg_directory = NULL;
 static char *arg_template = NULL;
+static char *arg_chdir = NULL;
 static char *arg_user = NULL;
 static sd_id128_t arg_uuid = {};
 static char *arg_machine = NULL;
@@ -193,6 +194,7 @@ static void help(void) {
                "                            remove it after exit\n"
                "  -i --image=PATH           File system device or disk image for the container\n"
                "  -b --boot                 Boot up full system (i.e. invoke init)\n"
+               "     --chdir=PATH           Set working directory in the container\n"
                "  -u --user=USER            Run the command under specified user or uid\n"
                "  -M --machine=NAME         Set the machine name for the container\n"
                "     --uuid=UUID            Set a specific machine UUID for the container\n"
@@ -345,6 +347,7 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_PRIVATE_USERS,
                 ARG_KILL_SIGNAL,
                 ARG_SETTINGS,
+                ARG_CHDIR,
         };
 
         static const struct option options[] = {
@@ -389,6 +392,7 @@ static int parse_argv(int argc, char *argv[]) {
                 { "private-users",         optional_argument, NULL, ARG_PRIVATE_USERS     },
                 { "kill-signal",           required_argument, NULL, ARG_KILL_SIGNAL       },
                 { "settings",              required_argument, NULL, ARG_SETTINGS          },
+                { "chdir",                 required_argument, NULL, ARG_CHDIR             },
                 {}
         };
 
@@ -849,6 +853,19 @@ static int parse_argv(int argc, char *argv[]) {
 
                         break;
 
+                case ARG_CHDIR:
+                        if (!path_is_absolute(optarg)) {
+                                log_error("Working directory %s is not an absolute path.", optarg);
+                                return -EINVAL;
+                        }
+
+                        r = free_and_strdup(&arg_chdir, optarg);
+                        if (r < 0)
+                                return log_oom();
+
+                        arg_settings_mask |= SETTING_WORKING_DIRECTORY;
+                        break;
+
                 case '?':
                         return -EINVAL;
 
@@ -2563,6 +2580,10 @@ static int inner_child(
                 return -ESRCH;
         }
 
+        if (arg_chdir)
+                if (chdir(arg_chdir) < 0)
+                        return log_error_errno(errno, "Failed to change to specified working directory %s: %m", arg_chdir);
+
         /* Now, explicitly close the log, so that we
          * then can close all remaining fds. Closing
          * the log explicitly first has the benefit
@@ -2598,7 +2619,9 @@ static int inner_child(
         } else if (!strv_isempty(arg_parameters))
                 execvpe(arg_parameters[0], arg_parameters, env_use);
         else {
-                chdir(home ?: "/root");
+                if (!arg_chdir)
+                        chdir(home ?: "/root");
+
                 execle("/bin/bash", "-bash", NULL, env_use);
                 execle("/bin/sh", "-sh", NULL, env_use);
         }
@@ -2903,6 +2926,13 @@ static int load_settings(void) {
                 settings->parameters = NULL;
         }
 
+        if ((arg_settings_mask & SETTING_WORKING_DIRECTORY) == 0 &&
+            settings->working_directory) {
+                free(arg_chdir);
+                arg_chdir = settings->working_directory;
+                settings->working_directory = NULL;
+        }
+
         if ((arg_settings_mask & SETTING_ENVIRONMENT) == 0 &&
             settings->environment) {
                 strv_free(arg_setenv);
@@ -3629,6 +3659,7 @@ finish:
         free(arg_image);
         free(arg_machine);
         free(arg_user);
+        free(arg_chdir);
         strv_free(arg_setenv);
         free(arg_network_bridge);
         strv_free(arg_network_interfaces);