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);