diff options
-rw-r--r-- | man/systemd-nspawn.xml | 7 | ||||
-rw-r--r-- | man/systemd.nspawn.xml | 8 | ||||
-rw-r--r-- | src/nspawn/nspawn-gperf.gperf | 1 | ||||
-rw-r--r-- | src/nspawn/nspawn-settings.c | 1 | ||||
-rw-r--r-- | src/nspawn/nspawn-settings.h | 4 | ||||
-rw-r--r-- | src/nspawn/nspawn.c | 33 |
6 files changed, 52 insertions, 2 deletions
diff --git a/man/systemd-nspawn.xml b/man/systemd-nspawn.xml index 28b91dee24..1cfef93df1 100644 --- a/man/systemd-nspawn.xml +++ b/man/systemd-nspawn.xml @@ -261,6 +261,13 @@ </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> diff --git a/man/systemd.nspawn.xml b/man/systemd.nspawn.xml index f39e1ad42c..7e604246f6 100644 --- a/man/systemd.nspawn.xml +++ b/man/systemd.nspawn.xml @@ -187,6 +187,14 @@ </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> diff --git a/src/nspawn/nspawn-gperf.gperf b/src/nspawn/nspawn-gperf.gperf index 58f9f4c635..08020d510c 100644 --- a/src/nspawn/nspawn-gperf.gperf +++ b/src/nspawn/nspawn-gperf.gperf @@ -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 diff --git a/src/nspawn/nspawn-settings.c b/src/nspawn/nspawn-settings.c index d6b64d8d5a..3c552e0734 100644 --- a/src/nspawn/nspawn-settings.c +++ b/src/nspawn/nspawn-settings.c @@ -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); diff --git a/src/nspawn/nspawn-settings.h b/src/nspawn/nspawn-settings.h index 10230a5b83..236a1baa4f 100644 --- a/src/nspawn/nspawn-settings.h +++ b/src/nspawn/nspawn-settings.h @@ -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; diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 9dd4c051b2..0dae9984c9 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -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); |