diff --git a/man/systemd-nspawn.xml b/man/systemd-nspawn.xml index c6b027c58f..16d65d2b29 100644 --- a/man/systemd-nspawn.xml +++ b/man/systemd-nspawn.xml @@ -373,6 +373,22 @@ instead. + + + + Controls the hostname to set within the container, if different from the machine name. Expects + a valid hostname as argument. If this option is used, the kernel hostname of the container will be set to this + value, otherwise it will be initialized to the machine name as controlled by the + option described above. The machine name is used for various aspect of identification of the container from the + outside, the kernel hostname configurable with this option is useful for the container to identify itself from + the inside. It is usually a good idea to keep both forms of identification synchronized, in order to avoid + confusion. It is hence recommended to avoid usage of this option, and use + exclusively. Note that regardless whether the container's hostname is initialized from the name set with + or the one set with , the container can later override + its kernel hostname freely on its own as well. + + + diff --git a/man/systemd.nspawn.xml b/man/systemd.nspawn.xml index 6bd7b33b34..3f8c325fd9 100644 --- a/man/systemd.nspawn.xml +++ b/man/systemd.nspawn.xml @@ -302,6 +302,15 @@ details. + + Hostname= + + Configures the kernel hostname set for the container. This is equivalent to the + command line switch, and takes the same argument. See + systemd-nspawn1 for + details. + + diff --git a/src/nspawn/nspawn-gperf.gperf b/src/nspawn/nspawn-gperf.gperf index 58184d412d..f7d2e1a515 100644 --- a/src/nspawn/nspawn-gperf.gperf +++ b/src/nspawn/nspawn-gperf.gperf @@ -49,6 +49,7 @@ Exec.LimitMSGQUEUE, config_parse_rlimit, RLIMIT_MSGQUEUE, of Exec.LimitNICE, config_parse_rlimit, RLIMIT_NICE, offsetof(Settings, rlimit) Exec.LimitRTPRIO, config_parse_rlimit, RLIMIT_RTPRIO, offsetof(Settings, rlimit) Exec.LimitRTTIME, config_parse_rlimit, RLIMIT_RTTIME, offsetof(Settings, rlimit) +Exec.Hostname, config_parse_hostname, 0, offsetof(Settings, hostname) 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 19bf1d4b94..3757380e28 100644 --- a/src/nspawn/nspawn-settings.c +++ b/src/nspawn/nspawn-settings.c @@ -8,6 +8,7 @@ #include "alloc-util.h" #include "cap-list.h" #include "conf-parser.h" +#include "hostname-util.h" #include "nspawn-network.h" #include "nspawn-settings.h" #include "parse-util.h" @@ -82,6 +83,7 @@ Settings* settings_free(Settings *s) { strv_free(s->syscall_whitelist); strv_free(s->syscall_blacklist); rlimit_free_all(s->rlimit); + free(s->hostname); strv_free(s->network_interfaces); strv_free(s->network_macvlan); @@ -603,3 +605,31 @@ int config_parse_syscall_filter( return 0; } + +int config_parse_hostname( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + char **s = data; + + assert(rvalue); + assert(s); + + if (!hostname_is_valid(rvalue, false)) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid hostname, ignoring: %s", rvalue); + return 0; + } + + if (free_and_strdup(s, empty_to_null(rvalue)) < 0) + return log_oom(); + + return 0; +} diff --git a/src/nspawn/nspawn-settings.h b/src/nspawn/nspawn-settings.h index 0e6ce61217..3d3ee4c28c 100644 --- a/src/nspawn/nspawn-settings.h +++ b/src/nspawn/nspawn-settings.h @@ -49,9 +49,10 @@ typedef enum SettingsMask { SETTING_NOTIFY_READY = UINT64_C(1) << 14, SETTING_PIVOT_ROOT = UINT64_C(1) << 15, SETTING_SYSCALL_FILTER = UINT64_C(1) << 16, - SETTING_RLIMIT_FIRST = UINT64_C(1) << 17, /* we define one bit per resource limit here */ - SETTING_RLIMIT_LAST = UINT64_C(1) << (17 + _RLIMIT_MAX - 1), - _SETTINGS_MASK_ALL = (UINT64_C(1) << (17 + _RLIMIT_MAX)) + SETTING_HOSTNAME = UINT64_C(1) << 17, + SETTING_RLIMIT_FIRST = UINT64_C(1) << 18, /* we define one bit per resource limit here */ + SETTING_RLIMIT_LAST = UINT64_C(1) << (18 + _RLIMIT_MAX - 1), + _SETTINGS_MASK_ALL = (UINT64_C(1) << (18 + _RLIMIT_MAX)) - 1 } SettingsMask; typedef struct Settings { @@ -74,6 +75,7 @@ typedef struct Settings { char **syscall_whitelist; char **syscall_blacklist; struct rlimit *rlimit[_RLIMIT_MAX]; + char *hostname; /* [Image] */ int read_only; @@ -118,3 +120,4 @@ int config_parse_boot(const char *unit, const char *filename, unsigned line, con int config_parse_pid2(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_private_users(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_syscall_filter(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_hostname(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 8ba8e73bf7..7357576a2a 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -128,7 +128,8 @@ static char *arg_pivot_root_new = NULL; static char *arg_pivot_root_old = NULL; static char *arg_user = NULL; static sd_id128_t arg_uuid = {}; -static char *arg_machine = NULL; +static char *arg_machine = NULL; /* The name used by the host to refer to this */ +static char *arg_hostname = NULL; /* The name the payload sees by default */ static const char *arg_selinux_context = NULL; static const char *arg_selinux_apifs_context = NULL; static const char *arg_slice = NULL; @@ -223,6 +224,7 @@ static void help(void) { " Pivot root to given 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" + " --hostname=NAME Override the hostname for the container\n" " --uuid=UUID Set a specific machine UUID for the container\n" " -S --slice=SLICE Place the container in the specified slice\n" " --property=NAME=VALUE Set scope unit property\n" @@ -443,6 +445,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_ROOT_HASH, ARG_SYSTEM_CALL_FILTER, ARG_RLIMIT, + ARG_HOSTNAME, }; static const struct option options[] = { @@ -466,6 +469,7 @@ static int parse_argv(int argc, char *argv[]) { { "overlay", required_argument, NULL, ARG_OVERLAY }, { "overlay-ro", required_argument, NULL, ARG_OVERLAY_RO }, { "machine", required_argument, NULL, 'M' }, + { "hostname", required_argument, NULL, ARG_HOSTNAME }, { "slice", required_argument, NULL, 'S' }, { "setenv", required_argument, NULL, 'E' }, { "selinux-context", required_argument, NULL, 'Z' }, @@ -701,6 +705,23 @@ static int parse_argv(int argc, char *argv[]) { } break; + case ARG_HOSTNAME: + if (isempty(optarg)) + arg_hostname = mfree(arg_hostname); + else { + if (!hostname_is_valid(optarg, false)) { + log_error("Invalid hostname: %s", optarg); + return -EINVAL; + } + + r = free_and_strdup(&arg_hostname, optarg); + if (r < 0) + return log_oom(); + } + + arg_settings_mask |= SETTING_HOSTNAME; + break; + case 'Z': arg_selinux_context = optarg; break; @@ -1762,7 +1783,7 @@ static int setup_hostname(void) { if ((arg_clone_ns_flags & CLONE_NEWUTS) == 0) return 0; - if (sethostname_idempotent(arg_machine) < 0) + if (sethostname_idempotent(arg_hostname ?: arg_machine) < 0) return -errno; return 0; @@ -3314,6 +3335,10 @@ static int load_settings(void) { free_and_replace(arg_rlimit[rl], settings->rlimit[rl]); } + if ((arg_settings_mask & SETTING_HOSTNAME) == 0 && + settings->hostname) + free_and_replace(arg_hostname, settings->hostname); + return 0; } @@ -4274,6 +4299,7 @@ finish: free(arg_template); free(arg_image); free(arg_machine); + free(arg_hostname); free(arg_user); free(arg_pivot_root_new); free(arg_pivot_root_old);