diff --git a/NEWS b/NEWS
index 3ee2381191..50ef954cc8 100644
--- a/NEWS
+++ b/NEWS
@@ -256,8 +256,8 @@ CHANGES WITH 248:
ignored. The goal is to honour configuration as specified by the
user.
- * systemd-hostnamed now exports the fallback hostname and the source of
- the configured hostname ("static", "transient", or "fallback") as
+ * systemd-hostnamed now exports the default hostname and the source of
+ the configured hostname ("static", "transient", or "default") as
D-Bus properties.
* systemd-hostnamed now exports the "HardwareVendor" and
diff --git a/docs/ENVIRONMENT.md b/docs/ENVIRONMENT.md
index 7eec455934..a3916f8cde 100644
--- a/docs/ENVIRONMENT.md
+++ b/docs/ENVIRONMENT.md
@@ -56,6 +56,10 @@ All tools:
* `$SYSTEMD_EFI_OPTIONS` — if set, used instead of the string in the
`SystemdOptions` EFI variable. Analogous to `$SYSTEMD_PROC_CMDLINE`.
+* `$SYSTEMD_DEFAULT_HOSTNAME` — override the compiled-in fallback hostname
+ (relevant in particular for the system manager and `systemd-hostnamed`).
+ Must be a valid hostname (either a single label or a FQDN).
+
* `$SYSTEMD_IN_INITRD=[auto|lenient|0|1]` — if set, specifies initrd detection
method. Defaults to `auto`. Behavior is defined as follows:
`auto`: Checks if `/etc/initrd-release` exists, and a temporary fs is mounted
diff --git a/man/org.freedesktop.hostname1.xml b/man/org.freedesktop.hostname1.xml
index 5b5f4fb3a7..3a5088eded 100644
--- a/man/org.freedesktop.hostname1.xml
+++ b/man/org.freedesktop.hostname1.xml
@@ -63,7 +63,7 @@ node /org/freedesktop/hostname1 {
readonly s StaticHostname = '...';
readonly s PrettyHostname = '...';
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
- readonly s FallbackHostname = '...';
+ readonly s DefaultHostname = '...';
readonly s HostnameSource = '...';
readonly s IconName = '...';
readonly s Chassis = '...';
@@ -124,7 +124,7 @@ node /org/freedesktop/hostname1 {
-
+
@@ -183,13 +183,15 @@ node /org/freedesktop/hostname1 {
set this setting will be the empty string. Applications should then find a suitable fallback, such as the
dynamic hostname.
- The FallbackHostname property exposes the fallback hostname (configured at
- compilation time).
+ The DefaultHostname property exposes the default hostname (configured through
+ os-release5, or a
+ fallback set at compilation time).
The HostnameSource property exposes the origin of the currently configured
hostname. One of static (set from /etc/hostname),
transient (a non-permanent hostname from an external source),
- fallback (the compiled-in fallback value).
+ default (the value from os-release or the the compiled-in
+ fallback).
The IconName property exposes the icon name following the
XDG icon naming spec. If not set, information such as the chassis type (see below) is used to find a
@@ -332,8 +334,8 @@ node /org/freedesktop/hostname1 {
Limit the hostname to 63 chars, which is the length of a DNS label.
If after stripping special chars the empty string is the result, you can pass this
- as-is to systemd-hostnamed in which case it will automatically use
- &FALLBACK_HOSTNAME;.
+ as-is to systemd-hostnamed in which case it will automatically use a suitable
+ fallback.
Uppercase charaacters should be replaced with their lowercase equivalents.
diff --git a/man/os-release.xml b/man/os-release.xml
index 5a0cfd2887..a6d333f278 100644
--- a/man/os-release.xml
+++ b/man/os-release.xml
@@ -317,6 +317,23 @@
+
+ DEFAULT_HOSTNAME=
+
+ A string specifying the hostname if
+ hostname5 is not
+ present and no other configuration source specifies the hostname. Must be either a single DNS label
+ (a string composed of 7-bit ASCII lower-case characters and no spaces or dots, limited to the format
+ allowed for DNS domain name labels), or a sequence of such labels separated by single dots that forms
+ a valid DNS FQDN. The total length must be at most 64 characters.
+
+ See
+ org.freedesktop.hostname15
+ for a description of how
+ systemd-hostnamed.service8
+ determines the fallback hostname.
+
+
SYSEXT_LEVEL=
diff --git a/man/systemd-system.conf.xml b/man/systemd-system.conf.xml
index 075666ac6b..d39928ec23 100644
--- a/man/systemd-system.conf.xml
+++ b/man/systemd-system.conf.xml
@@ -31,7 +31,9 @@
/etc/systemd/system.conf.d/*.conf,
/run/systemd/system.conf.d/*.conf,
/usr/lib/systemd/system.conf.d/*.conf
- /etc/systemd/user.conf,
+
+ ~/.config/systemd/user.conf,
+ /etc/systemd/user.conf,
/etc/systemd/user.conf.d/*.conf,
/run/systemd/user.conf.d/*.conf,
/usr/lib/systemd/user.conf.d/*.conf
@@ -40,16 +42,16 @@
Description
- When run as a system instance, systemd interprets the
- configuration file system.conf and the files
- in system.conf.d directories; when run as a
- user instance, systemd interprets the configuration file
- user.conf and the files in
- user.conf.d directories. These configuration
- files contain a few settings controlling basic manager
- operations. See
- systemd.syntax7
- for a general description of the syntax.
+ When run as a system instance, systemd interprets the configuration file
+ system.conf and the files in system.conf.d directories; when
+ run as a user instance, it interprets the configuration file user.conf (either in
+ the home directory of the user, or if not found, under /etc/systemd/) and the files
+ in user.conf.d directories. These configuration files contain a few settings
+ controlling basic manager operations.
+
+ See
+ systemd.syntax7 for a
+ general description of the syntax.
@@ -321,11 +323,10 @@
DefaultEnvironment=
- Sets manager environment variables passed to
- all executed processes. Takes a space-separated list of
- variable assignments. See
- environ7
- for details about environment variables.
+ Configures environment variables passed to all executed processes. Takes a
+ space-separated list of variable assignments. See environ7 for
+ details about environment variables.
Example:
@@ -337,6 +338,20 @@
VAR3.
+
+ ManagerEnvironment=
+
+ Takes the same arguments as DefaultEnvironment=, see above. Sets
+ environment variables just for the manager process itself. These variables are not inherited by
+ processes spawned by the service manager, use DefaultEnvironment= for that. Note
+ that these variables are merged into the existing environment block. In particular, in case of the
+ system manager, this includes variables set by the kernel based on the kernel command line.
+
+ Setting environment variables for the manager process may be useful to modify its behaviour.
+ See ENVIRONMENT for a descriptions of some
+ variables understood by systemd.
+
+
DefaultCPUAccounting=
DefaultBlockIOAccounting=
diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml
index 1a823b3feb..333449097f 100644
--- a/man/systemd.unit.xml
+++ b/man/systemd.unit.xml
@@ -60,7 +60,7 @@
$XDG_RUNTIME_DIR/systemd/user.control/*
$XDG_RUNTIME_DIR/systemd/transient/*
$XDG_RUNTIME_DIR/systemd/generator.early/*
-$XDG_CONFIG_HOME/systemd/user/*
+~/.config/systemd/user/*
$XDG_CONFIG_DIRS/systemd/user/*
/etc/systemd/user/*
$XDG_RUNTIME_DIR/systemd/user/*
diff --git a/src/basic/env-util.c b/src/basic/env-util.c
index df24cb935d..7fa598a3b5 100644
--- a/src/basic/env-util.c
+++ b/src/basic/env-util.c
@@ -768,6 +768,21 @@ int set_unset_env(const char *name, const char *value, bool overwrite) {
return 0;
}
+int putenv_dup(const char *assignment, bool override) {
+ const char *e, *n;
+
+ e = strchr(assignment, '=');
+ if (!e)
+ return -EINVAL;
+
+ n = strndupa(assignment, e - assignment);
+
+ /* This is like putenv(), but uses setenv() so that our memory doesn't become part of environ[]. */
+ if (setenv(n, e + 1, override) < 0)
+ return -errno;
+ return 0;
+}
+
int setenv_systemd_exec_pid(bool update_only) {
char str[DECIMAL_STR_MAX(pid_t)];
const char *e;
diff --git a/src/basic/env-util.h b/src/basic/env-util.h
index 7ba8488af7..1fbe7e4270 100644
--- a/src/basic/env-util.h
+++ b/src/basic/env-util.h
@@ -58,6 +58,9 @@ int getenv_bool_secure(const char *p);
/* Like setenv, but calls unsetenv if value == NULL. */
int set_unset_env(const char *name, const char *value, bool overwrite);
+/* Like putenv, but duplicates the memory like setenv. */
+int putenv_dup(const char *assignment, bool override);
+
int setenv_systemd_exec_pid(bool update_only);
/* Parses and does sanity checks on an environment variable containing
diff --git a/src/basic/hostname-util.c b/src/basic/hostname-util.c
index d7aba2c263..29d69910d2 100644
--- a/src/basic/hostname-util.c
+++ b/src/basic/hostname-util.c
@@ -3,14 +3,39 @@
#include
#include
#include
+#include
#include
#include
#include "alloc-util.h"
#include "hostname-util.h"
+#include "os-util.h"
#include "string-util.h"
#include "strv.h"
+char* get_default_hostname(void) {
+ int r;
+
+ const char *e = secure_getenv("SYSTEMD_DEFAULT_HOSTNAME");
+ if (e) {
+ if (hostname_is_valid(e, 0))
+ return strdup(e);
+ log_debug("Invalid hostname in $SYSTEMD_DEFAULT_HOSTNAME, ignoring: %s", e);
+ }
+
+ _cleanup_free_ char *f = NULL;
+ r = parse_os_release(NULL, "DEFAULT_HOSTNAME", &f);
+ if (r < 0)
+ log_debug_errno(r, "Failed to parse os-release, ignoring: %m");
+ else if (f) {
+ if (hostname_is_valid(f, 0))
+ return TAKE_PTR(f);
+ log_debug("Invalid hostname in os-release, ignoring: %s", f);
+ }
+
+ return strdup(FALLBACK_HOSTNAME);
+}
+
char* gethostname_malloc(void) {
struct utsname u;
const char *s;
@@ -23,7 +48,7 @@ char* gethostname_malloc(void) {
s = u.nodename;
if (isempty(s) || streq(s, "(none)"))
- s = FALLBACK_HOSTNAME;
+ return get_default_hostname();
return strdup(s);
}
@@ -31,6 +56,7 @@ char* gethostname_malloc(void) {
char* gethostname_short_malloc(void) {
struct utsname u;
const char *s;
+ _cleanup_free_ char *f = NULL;
/* Like above, but kills the FQDN part if present. */
@@ -38,7 +64,10 @@ char* gethostname_short_malloc(void) {
s = u.nodename;
if (isempty(s) || streq(s, "(none)") || s[0] == '.') {
- s = FALLBACK_HOSTNAME;
+ s = f = get_default_hostname();
+ if (!s)
+ return NULL;
+
assert(s[0] != '.');
}
diff --git a/src/basic/hostname-util.h b/src/basic/hostname-util.h
index 6cff9c1d4c..576ca083e0 100644
--- a/src/basic/hostname-util.h
+++ b/src/basic/hostname-util.h
@@ -7,6 +7,7 @@
#include "macro.h"
#include "strv.h"
+char* get_default_hostname(void);
char* gethostname_malloc(void);
char* gethostname_short_malloc(void);
int gethostname_strict(char **ret);
diff --git a/src/basic/macro.h b/src/basic/macro.h
index eebd0769dd..f1d5e0894e 100644
--- a/src/basic/macro.h
+++ b/src/basic/macro.h
@@ -376,6 +376,7 @@ static inline int __coverity_check_and_return__(int condition) {
#define STRV_MAKE(...) ((char**) ((const char*[]) { __VA_ARGS__, NULL }))
#define STRV_MAKE_EMPTY ((char*[1]) { NULL })
+#define STRV_MAKE_CONST(...) ((const char* const*) ((const char*[]) { __VA_ARGS__, NULL }))
/* Pointers range from NULL to POINTER_MAX */
#define POINTER_MAX ((void*) UINTPTR_MAX)
diff --git a/src/basic/meson.build b/src/basic/meson.build
index 88639bc9b5..282118bb1a 100644
--- a/src/basic/meson.build
+++ b/src/basic/meson.build
@@ -170,6 +170,8 @@ basic_sources = files('''
nulstr-util.h
ordered-set.c
ordered-set.h
+ os-util.c
+ os-util.h
parse-util.c
parse-util.h
path-lookup.c
diff --git a/src/shared/os-util.c b/src/basic/os-util.c
similarity index 60%
rename from src/shared/os-util.c
rename to src/basic/os-util.c
index 9aed3b5df4..3d199f028d 100644
--- a/src/shared/os-util.c
+++ b/src/basic/os-util.c
@@ -1,7 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "alloc-util.h"
-#include "discover-image.h"
#include "env-file.h"
#include "env-util.h"
#include "fd-util.h"
@@ -9,8 +8,27 @@
#include "fs-util.h"
#include "macro.h"
#include "os-util.h"
+#include "path-util.h"
#include "string-util.h"
#include "strv.h"
+#include "utf8.h"
+
+bool image_name_is_valid(const char *s) {
+ if (!filename_is_valid(s))
+ return false;
+
+ if (string_has_cc(s, NULL))
+ return false;
+
+ if (!utf8_is_valid(s))
+ return false;
+
+ /* Temporary files for atomically creating new files */
+ if (startswith(s, ".#"))
+ return false;
+
+ return true;
+}
int path_is_extension_tree(const char *path, const char *extension) {
int r;
@@ -118,7 +136,7 @@ static int parse_release_internal(const char *root, const char *extension, va_li
return parse_env_filev(f, p, ap);
}
-int parse_extension_release(const char *root, const char *extension, ...) {
+int _parse_extension_release(const char *root, const char *extension, ...) {
va_list ap;
int r;
@@ -129,7 +147,7 @@ int parse_extension_release(const char *root, const char *extension, ...) {
return r;
}
-int parse_os_release(const char *root, ...) {
+int _parse_os_release(const char *root, ...) {
va_list ap;
int r;
@@ -193,74 +211,3 @@ int load_extension_release_pairs(const char *root, const char *extension, char *
return load_env_file_pairs(f, p, ret);
}
-
-int extension_release_validate(
- const char *name,
- const char *host_os_release_id,
- const char *host_os_release_version_id,
- const char *host_os_release_sysext_level,
- char **extension_release) {
-
- const char *extension_release_id = NULL, *extension_release_sysext_level = NULL;
-
- assert(name);
- assert(!isempty(host_os_release_id));
-
- /* Now that we can look into the extension image, let's see if the OS version is compatible */
- if (strv_isempty(extension_release)) {
- log_debug("Extension '%s' carries no extension-release data, ignoring extension.", name);
- return 0;
- }
-
- extension_release_id = strv_env_pairs_get(extension_release, "ID");
- if (isempty(extension_release_id)) {
- log_debug("Extension '%s' does not contain ID in extension-release but requested to match '%s'",
- name, strna(host_os_release_id));
- return 0;
- }
-
- if (!streq_ptr(host_os_release_id, extension_release_id)) {
- log_debug("Extension '%s' is for OS '%s', but deployed on top of '%s'.",
- name, strna(extension_release_id), strna(host_os_release_id));
- return 0;
- }
-
- /* Rolling releases do not typically set VERSION_ID (eg: ArchLinux) */
- if (isempty(host_os_release_version_id) && isempty(host_os_release_sysext_level)) {
- log_debug("No version info on the host (rolling release?), but ID in %s matched.", name);
- return 1;
- }
-
- /* If the extension has a sysext API level declared, then it must match the host API
- * level. Otherwise, compare OS version as a whole */
- extension_release_sysext_level = strv_env_pairs_get(extension_release, "SYSEXT_LEVEL");
- if (!isempty(host_os_release_sysext_level) && !isempty(extension_release_sysext_level)) {
- if (!streq_ptr(host_os_release_sysext_level, extension_release_sysext_level)) {
- log_debug("Extension '%s' is for sysext API level '%s', but running on sysext API level '%s'",
- name, strna(extension_release_sysext_level), strna(host_os_release_sysext_level));
- return 0;
- }
- } else if (!isempty(host_os_release_version_id)) {
- const char *extension_release_version_id;
-
- extension_release_version_id = strv_env_pairs_get(extension_release, "VERSION_ID");
- if (isempty(extension_release_version_id)) {
- log_debug("Extension '%s' does not contain VERSION_ID in extension-release but requested to match '%s'",
- name, strna(host_os_release_version_id));
- return 0;
- }
-
- if (!streq_ptr(host_os_release_version_id, extension_release_version_id)) {
- log_debug("Extension '%s' is for OS '%s', but deployed on top of '%s'.",
- name, strna(extension_release_version_id), strna(host_os_release_version_id));
- return 0;
- }
- } else if (isempty(host_os_release_version_id) && isempty(host_os_release_sysext_level)) {
- /* Rolling releases do not typically set VERSION_ID (eg: ArchLinux) */
- log_debug("No version info on the host (rolling release?), but ID in %s matched.", name);
- return 1;
- }
-
- log_debug("Version info of extension '%s' matches host.", name);
- return 1;
-}
diff --git a/src/shared/os-util.h b/src/basic/os-util.h
similarity index 67%
rename from src/shared/os-util.h
rename to src/basic/os-util.h
index d4bff5e48e..271b35fa4e 100644
--- a/src/shared/os-util.h
+++ b/src/basic/os-util.h
@@ -6,6 +6,8 @@
/* The *_extension_release flavours will look for /usr/lib/extension-release/extension-release.NAME
* in accordance with the OS extension specification, rather than for /usr/lib/ or /etc/os-release. */
+bool image_name_is_valid(const char *s) _pure_;
+
int path_is_extension_tree(const char *path, const char *extension);
static inline int path_is_os_tree(const char *path) {
return path_is_extension_tree(path, NULL);
@@ -21,13 +23,11 @@ static inline int fopen_os_release(const char *root, char **ret_path, FILE **ret
return fopen_extension_release(root, NULL, ret_path, ret_file);
}
-int parse_extension_release(const char *root, const char *extension, ...) _sentinel_;
-int parse_os_release(const char *root, ...) _sentinel_;
+int _parse_extension_release(const char *root, const char *extension, ...) _sentinel_;
+int _parse_os_release(const char *root, ...) _sentinel_;
+#define parse_extension_release(root, extension, ...) _parse_extension_release(root, extension, __VA_ARGS__, NULL)
+#define parse_os_release(root, ...) _parse_os_release(root, __VA_ARGS__, NULL)
+
int load_extension_release_pairs(const char *root, const char *extension, char ***ret);
int load_os_release_pairs(const char *root, char ***ret);
int load_os_release_pairs_with_prefix(const char *root, const char *prefix, char ***ret);
-
-/* Given an image name (for logging purposes), a set of os-release values from the host
- * and a key-value pair vector of extension-release variables, check that the distro and
- * (system extension level or distro version) match and return 1, and 0 otherwise. */
-int extension_release_validate(const char *name, const char *host_os_release_id, const char *host_os_release_version_id, const char *host_os_release_sysext_level, char **extension_release);
diff --git a/src/core/main.c b/src/core/main.c
index b8ff184af0..9ad7db192c 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -134,6 +134,7 @@ static usec_t arg_kexec_watchdog;
static char *arg_early_core_pattern;
static char *arg_watchdog_device;
static char **arg_default_environment;
+static char **arg_manager_environment;
static struct rlimit *arg_default_rlimit[_RLIMIT_MAX];
static uint64_t arg_capability_bounding_set;
static bool arg_no_new_privs;
@@ -163,6 +164,36 @@ static char **saved_env = NULL;
static int parse_configuration(const struct rlimit *saved_rlimit_nofile,
const struct rlimit *saved_rlimit_memlock);
+static int manager_find_user_config_paths(char ***ret_files, char ***ret_dirs) {
+ _cleanup_free_ char *base = NULL;
+ _cleanup_strv_free_ char **files = NULL, **dirs = NULL;
+ int r;
+
+ r = xdg_user_config_dir(&base, "/systemd");
+ if (r < 0)
+ return r;
+
+ r = strv_extendf(&files, "%s/user.conf", base);
+ if (r < 0)
+ return r;
+
+ r = strv_extend(&files, PKGSYSCONFDIR "/user.conf");
+ if (r < 0)
+ return r;
+
+ r = strv_consume(&dirs, TAKE_PTR(base));
+ if (r < 0)
+ return r;
+
+ r = strv_extend_strv(&dirs, CONF_PATHS_STRV("systemd"), false);
+ if (r < 0)
+ return r;
+
+ *ret_files = TAKE_PTR(files);
+ *ret_dirs = TAKE_PTR(dirs);
+ return 0;
+}
+
_noreturn_ static void freeze_or_exit_or_reboot(void) {
/* If we are running in a container, let's prefer exiting, after all we can propagate an exit code to
@@ -640,6 +671,7 @@ static int parse_config_file(void) {
{ "Manager", "DefaultStartLimitIntervalSec", config_parse_sec, 0, &arg_default_start_limit_interval },
{ "Manager", "DefaultStartLimitBurst", config_parse_unsigned, 0, &arg_default_start_limit_burst },
{ "Manager", "DefaultEnvironment", config_parse_environ, 0, &arg_default_environment },
+ { "Manager", "ManagerEnvironment", config_parse_environ, 0, &arg_manager_environment },
{ "Manager", "DefaultLimitCPU", config_parse_rlimit, RLIMIT_CPU, arg_default_rlimit },
{ "Manager", "DefaultLimitFSIZE", config_parse_rlimit, RLIMIT_FSIZE, arg_default_rlimit },
{ "Manager", "DefaultLimitDATA", config_parse_rlimit, RLIMIT_DATA, arg_default_rlimit },
@@ -668,26 +700,34 @@ static int parse_config_file(void) {
{}
};
- const char *fn, *conf_dirs_nulstr;
+ _cleanup_strv_free_ char **_free_files = NULL, **_free_dirs = NULL;
- fn = arg_system ?
- PKGSYSCONFDIR "/system.conf" :
- PKGSYSCONFDIR "/user.conf";
+ const char *const *files, *const *dirs, *suffix;
+ int r;
- conf_dirs_nulstr = arg_system ?
- CONF_PATHS_NULSTR("systemd/system.conf.d") :
- CONF_PATHS_NULSTR("systemd/user.conf.d");
+ if (arg_system) {
+ files = STRV_MAKE_CONST(PKGSYSCONFDIR "/system.conf");
+ dirs = (const char* const*) CONF_PATHS_STRV("systemd");
+ suffix = "system.conf.d";
+ } else {
+ r = manager_find_user_config_paths(&_free_files, &_free_dirs);
+ if (r < 0)
+ return log_error_errno(r, "Failed to determine config file paths: %m");
+ files = (const char* const*) _free_files;
+ dirs = (const char* const*) _free_dirs;
+ suffix = "user.conf.d";
+ }
- (void) config_parse_many_nulstr(
- fn, conf_dirs_nulstr,
+ (void) config_parse_many(
+ files, dirs, suffix,
"Manager\0",
config_item_table_lookup, items,
CONFIG_PARSE_WARN,
NULL,
NULL);
- /* Traditionally "0" was used to turn off the default unit timeouts. Fix this up so that we used USEC_INFINITY
- * like everywhere else. */
+ /* Traditionally "0" was used to turn off the default unit timeouts. Fix this up so that we use
+ * USEC_INFINITY like everywhere else. */
if (arg_default_timeout_start_usec <= 0)
arg_default_timeout_start_usec = USEC_INFINITY;
if (arg_default_timeout_stop_usec <= 0)
@@ -1312,8 +1352,7 @@ static int status_welcome(void) {
r = parse_os_release(NULL,
"PRETTY_NAME", &pretty_name,
- "ANSI_COLOR", &ansi_color,
- NULL);
+ "ANSI_COLOR", &ansi_color);
if (r < 0)
log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r,
"Failed to read os-release file, ignoring: %m");
@@ -2263,6 +2302,19 @@ static void fallback_rlimit_memlock(const struct rlimit *saved_rlimit_memlock) {
arg_default_rlimit[RLIMIT_MEMLOCK] = rl;
}
+static void setenv_manager_environment(void) {
+ char **p;
+ int r;
+
+ STRV_FOREACH(p, arg_manager_environment) {
+ log_debug("Setting '%s' in our own environment.", *p);
+
+ r = putenv_dup(*p, true);
+ if (r < 0)
+ log_warning_errno(errno, "Failed to setenv \"%s\", ignoring: %m", *p);
+ }
+}
+
static void reset_arguments(void) {
/* Frees/resets arg_* variables, with a few exceptions commented below. */
@@ -2296,6 +2348,7 @@ static void reset_arguments(void) {
arg_watchdog_device = NULL;
arg_default_environment = strv_free(arg_default_environment);
+ arg_manager_environment = strv_free(arg_manager_environment);
rlimit_free_all(arg_default_rlimit);
arg_capability_bounding_set = CAP_ALL;
@@ -2357,6 +2410,9 @@ static int parse_configuration(const struct rlimit *saved_rlimit_nofile,
if (arg_show_status == _SHOW_STATUS_INVALID)
arg_show_status = SHOW_STATUS_YES;
+ /* Push variables into the manager environment block */
+ setenv_manager_environment();
+
return 0;
}
diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c
index 40f0de28c2..c0e88e7915 100644
--- a/src/firstboot/firstboot.c
+++ b/src/firstboot/firstboot.c
@@ -106,8 +106,7 @@ static void print_welcome(void) {
r = parse_os_release(
arg_root,
"PRETTY_NAME", &pretty_name,
- "ANSI_COLOR", &ansi_color,
- NULL);
+ "ANSI_COLOR", &ansi_color);
if (r < 0)
log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r,
"Failed to read os-release file, ignoring: %m");
diff --git a/src/hostname/hostnamed.c b/src/hostname/hostnamed.c
index 34333a6530..2ece8b2fbd 100644
--- a/src/hostname/hostnamed.c
+++ b/src/hostname/hostnamed.c
@@ -159,8 +159,7 @@ static void context_read_os_release(Context *c) {
r = parse_os_release(NULL,
"PRETTY_NAME", &c->data[PROP_OS_PRETTY_NAME],
"CPE_NAME", &c->data[PROP_OS_CPE_NAME],
- "HOME_URL", &c->data[PROP_OS_HOME_URL],
- NULL);
+ "HOME_URL", &c->data[PROP_OS_HOME_URL]);
if (r < 0 && r != -ENOENT)
log_warning_errno(r, "Failed to read os-release file, ignoring: %m");
@@ -323,6 +322,7 @@ static int context_update_kernel_hostname(
Context *c,
const char *transient_hn) {
+ _cleanup_free_ char *_hn_free = NULL;
const char *hn;
HostnameSource hns;
int r;
@@ -341,8 +341,11 @@ static int context_update_kernel_hostname(
/* ... and the ultimate fallback */
} else {
- hn = FALLBACK_HOSTNAME;
- hns = HOSTNAME_FALLBACK;
+ hn = _hn_free = get_default_hostname();
+ if (!hn)
+ return log_oom();
+
+ hns = HOSTNAME_DEFAULT;
}
r = sethostname_idempotent(hn);
@@ -503,16 +506,20 @@ static int property_get_hostname(
void *userdata,
sd_bus_error *error) {
- _cleanup_free_ char *current = NULL;
+ _cleanup_free_ char *hn = NULL;
int r;
- r = gethostname_strict(¤t);
- if (r == -ENXIO)
- return sd_bus_message_append(reply, "s", FALLBACK_HOSTNAME);
- if (r < 0)
- return r;
+ r = gethostname_strict(&hn);
+ if (r < 0) {
+ if (r != -ENXIO)
+ return r;
- return sd_bus_message_append(reply, "s", current);
+ hn = get_default_hostname();
+ if (!hn)
+ return -ENOMEM;
+ }
+
+ return sd_bus_message_append(reply, "s", hn);
}
static int property_get_static_hostname(
@@ -532,7 +539,21 @@ static int property_get_static_hostname(
return sd_bus_message_append(reply, "s", c->data[PROP_STATIC_HOSTNAME]);
}
-static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_fallback_hostname, "s", FALLBACK_HOSTNAME);
+static int property_get_default_hostname(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ _cleanup_free_ char *hn = get_default_hostname();
+ if (!hn)
+ return log_oom();
+
+ return sd_bus_message_append(reply, "s", hn);
+}
static int property_get_hostname_source(
sd_bus *bus,
@@ -560,16 +581,16 @@ static int property_get_hostname_source(
else {
/* If the hostname was not set by us, try to figure out where it came from. If we set
- * it to the fallback hostname, the file will tell us. We compare the string because
+ * it to the default hostname, the file will tell us. We compare the string because
* it is possible that the hostname was set by an older version that had a different
* fallback, in the initramfs or before we reexecuted. */
- r = read_one_line_file("/run/systemd/fallback-hostname", &fallback);
+ r = read_one_line_file("/run/systemd/default-hostname", &fallback);
if (r < 0 && r != -ENOENT)
- log_warning_errno(r, "Failed to read /run/systemd/fallback-hostname, ignoring: %m");
+ log_warning_errno(r, "Failed to read /run/systemd/default-hostname, ignoring: %m");
if (streq_ptr(fallback, hostname))
- c->hostname_source = HOSTNAME_FALLBACK;
+ c->hostname_source = HOSTNAME_DEFAULT;
else
c->hostname_source = HOSTNAME_TRANSIENT;
}
@@ -967,7 +988,7 @@ static const sd_bus_vtable hostname_vtable[] = {
SD_BUS_PROPERTY("Hostname", "s", property_get_hostname, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("StaticHostname", "s", property_get_static_hostname, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("PrettyHostname", "s", property_get_machine_info_field, offsetof(Context, data) + sizeof(char*) * PROP_PRETTY_HOSTNAME, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("FallbackHostname", "s", property_get_fallback_hostname, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultHostname", "s", property_get_default_hostname, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("HostnameSource", "s", property_get_hostname_source, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("IconName", "s", property_get_icon_name, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("Chassis", "s", property_get_chassis, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
diff --git a/src/journal-remote/journal-gatewayd.c b/src/journal-remote/journal-gatewayd.c
index 4ece66b51b..bd1edb1797 100644
--- a/src/journal-remote/journal-gatewayd.c
+++ b/src/journal-remote/journal-gatewayd.c
@@ -755,7 +755,7 @@ static int request_handler_machine(
if (r < 0)
return mhd_respondf(connection, r, MHD_HTTP_INTERNAL_SERVER_ERROR, "Failed to determine disk usage: %m");
- (void) parse_os_release(NULL, "PRETTY_NAME", &os_name, NULL);
+ (void) parse_os_release(NULL, "PRETTY_NAME", &os_name);
(void) get_virtualization(&v);
r = asprintf(&json,
diff --git a/src/machine/image-dbus.c b/src/machine/image-dbus.c
index 539b4c802a..309de0b116 100644
--- a/src/machine/image-dbus.c
+++ b/src/machine/image-dbus.c
@@ -18,6 +18,7 @@
#include "loop-util.h"
#include "missing_capability.h"
#include "mount-util.h"
+#include "os-util.h"
#include "process-util.h"
#include "raw-clone.h"
#include "strv.h"
diff --git a/src/machine/machined-dbus.c b/src/machine/machined-dbus.c
index 08179eb400..bb6a2bc576 100644
--- a/src/machine/machined-dbus.c
+++ b/src/machine/machined-dbus.c
@@ -24,6 +24,7 @@
#include "machine-pool.h"
#include "machined.h"
#include "missing_capability.h"
+#include "os-util.h"
#include "path-util.h"
#include "process-util.h"
#include "stdio-util.h"
diff --git a/src/network/netdev/netdev.c b/src/network/netdev/netdev.c
index b26064297b..36d6c5168a 100644
--- a/src/network/netdev/netdev.c
+++ b/src/network/netdev/netdev.c
@@ -686,7 +686,7 @@ int netdev_load_one(Manager *manager, const char *filename) {
dropin_dirname = strjoina(basename(filename), ".d");
r = config_parse_many(
- filename, NETWORK_DIRS, dropin_dirname,
+ STRV_MAKE_CONST(filename), NETWORK_DIRS, dropin_dirname,
NETDEV_COMMON_SECTIONS NETDEV_OTHER_SECTIONS,
config_item_perf_lookup, network_netdev_gperf_lookup,
CONFIG_PARSE_WARN,
@@ -729,7 +729,7 @@ int netdev_load_one(Manager *manager, const char *filename) {
NETDEV_VTABLE(netdev)->init(netdev);
r = config_parse_many(
- filename, NETWORK_DIRS, dropin_dirname,
+ STRV_MAKE_CONST(filename), NETWORK_DIRS, dropin_dirname,
NETDEV_VTABLE(netdev)->sections,
config_item_perf_lookup, network_netdev_gperf_lookup,
CONFIG_PARSE_WARN,
diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c
index 4f0dfe469f..e3c138411e 100644
--- a/src/network/networkd-network.c
+++ b/src/network/networkd-network.c
@@ -446,7 +446,7 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
};
r = config_parse_many(
- filename, NETWORK_DIRS, dropin_dirname,
+ STRV_MAKE_CONST(filename), NETWORK_DIRS, dropin_dirname,
"Match\0"
"Link\0"
"SR-IOV\0"
diff --git a/src/portable/portablectl.c b/src/portable/portablectl.c
index 278dae0e1b..af4acc2125 100644
--- a/src/portable/portablectl.c
+++ b/src/portable/portablectl.c
@@ -12,7 +12,6 @@
#include "bus-wait-for-jobs.h"
#include "def.h"
#include "dirent-util.h"
-#include "discover-image.h"
#include "env-file.h"
#include "fd-util.h"
#include "fileio.h"
@@ -20,6 +19,7 @@
#include "fs-util.h"
#include "locale-util.h"
#include "main-func.h"
+#include "os-util.h"
#include "pager.h"
#include "parse-util.h"
#include "path-util.h"
diff --git a/src/portable/portabled-image-bus.c b/src/portable/portabled-image-bus.c
index 018cc9b818..8332332c91 100644
--- a/src/portable/portabled-image-bus.c
+++ b/src/portable/portabled-image-bus.c
@@ -17,6 +17,7 @@
#include "fileio.h"
#include "io-util.h"
#include "missing_capability.h"
+#include "os-util.h"
#include "portable.h"
#include "portabled-bus.h"
#include "portabled-image-bus.h"
diff --git a/src/resolve/resolved-dnssd.c b/src/resolve/resolved-dnssd.c
index 34c96e18bd..33d695a9ce 100644
--- a/src/resolve/resolved-dnssd.c
+++ b/src/resolve/resolved-dnssd.c
@@ -88,7 +88,7 @@ static int dnssd_service_load(Manager *manager, const char *filename) {
dropin_dirname = strjoina(service->name, ".dnssd.d");
r = config_parse_many(
- filename, DNSSD_SERVICE_DIRS, dropin_dirname,
+ STRV_MAKE_CONST(filename), DNSSD_SERVICE_DIRS, dropin_dirname,
"Service\0",
config_item_perf_lookup, resolved_dnssd_gperf_lookup,
CONFIG_PARSE_WARN,
diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c
index 2ed9f2d47b..ae46d2dcd8 100644
--- a/src/resolve/resolved-manager.c
+++ b/src/resolve/resolved-manager.c
@@ -442,20 +442,25 @@ static int determine_hostname(char **full_hostname, char **llmnr_hostname, char
return 0;
}
-static const char *fallback_hostname(void) {
+static char* fallback_hostname(void) {
- /* Determine the fall back hostname. For exposing this system to the outside world, we cannot have it to be
- * "localhost" even if that's the compiled in hostname. In this case, let's revert to "linux" instead. */
+ /* Determine the fall back hostname. For exposing this system to the outside world, we cannot have it
+ * to be "localhost" even if that's the default hostname. In this case, let's revert to "linux"
+ * instead. */
- if (is_localhost(FALLBACK_HOSTNAME))
- return "linux";
+ _cleanup_free_ char *n = get_default_hostname();
+ if (!n)
+ return NULL;
- return FALLBACK_HOSTNAME;
+ if (is_localhost(n))
+ return strdup("linux");
+
+ return TAKE_PTR(n);
}
static int make_fallback_hostnames(char **full_hostname, char **llmnr_hostname, char **mdns_hostname) {
- _cleanup_free_ char *n = NULL, *m = NULL;
- char label[DNS_LABEL_MAX], *h;
+ _cleanup_free_ char *h = NULL, *n = NULL, *m = NULL;
+ char label[DNS_LABEL_MAX];
const char *p;
int r;
@@ -463,7 +468,10 @@ static int make_fallback_hostnames(char **full_hostname, char **llmnr_hostname,
assert(llmnr_hostname);
assert(mdns_hostname);
- p = fallback_hostname();
+ p = h = fallback_hostname();
+ if (!h)
+ return log_oom();
+
r = dns_label_unescape(&p, label, sizeof label, 0);
if (r < 0)
return log_error_errno(r, "Failed to unescape fallback hostname: %m");
@@ -478,14 +486,9 @@ static int make_fallback_hostnames(char **full_hostname, char **llmnr_hostname,
if (r < 0)
return log_error_errno(r, "Failed to concatenate mDNS hostname: %m");
- h = strdup(fallback_hostname());
- if (!h)
- return log_oom();
-
*llmnr_hostname = TAKE_PTR(n);
*mdns_hostname = TAKE_PTR(m);
-
- *full_hostname = h;
+ *full_hostname = TAKE_PTR(h);
return 0;
}
diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c
index df6472d4be..64ed2571e9 100644
--- a/src/shared/conf-parser.c
+++ b/src/shared/conf-parser.c
@@ -420,11 +420,11 @@ int config_parse(
if (ret_mtime)
*ret_mtime = mtime;
- return 0;
+ return 1;
}
static int config_parse_many_files(
- const char *conf_file,
+ const char* const* conf_files,
char **files,
const char *sections,
ConfigItemLookup lookup,
@@ -437,20 +437,23 @@ static int config_parse_many_files(
char **fn;
int r;
- if (conf_file) {
- r = config_parse(NULL, conf_file, NULL, sections, lookup, table, flags, userdata, &mtime);
+ /* First read the first found main config file. */
+ STRV_FOREACH(fn, (char**) conf_files) {
+ r = config_parse(NULL, *fn, NULL, sections, lookup, table, flags, userdata, &mtime);
if (r < 0)
return r;
+ if (r > 0)
+ break;
}
+ /* Then read all the drop-ins. */
STRV_FOREACH(fn, files) {
usec_t t;
r = config_parse(NULL, *fn, NULL, sections, lookup, table, flags, userdata, &t);
if (r < 0)
return r;
- if (t > mtime) /* Find the newest */
- mtime = t;
+ mtime = MAX(mtime, t); /* Find the newest */
}
if (ret_mtime)
@@ -477,12 +480,14 @@ int config_parse_many_nulstr(
if (r < 0)
return r;
- return config_parse_many_files(conf_file, files, sections, lookup, table, flags, userdata, ret_mtime);
+ return config_parse_many_files(STRV_MAKE_CONST(conf_file),
+ files, sections, lookup, table, flags, userdata,
+ ret_mtime);
}
/* Parse each config file in the directories specified as strv. */
int config_parse_many(
- const char *conf_file,
+ const char* const* conf_files,
const char* const* conf_file_dirs,
const char *dropin_dirname,
const char *sections,
@@ -506,7 +511,7 @@ int config_parse_many(
if (r < 0)
return r;
- return config_parse_many_files(conf_file, files, sections, lookup, table, flags, userdata, ret_mtime);
+ return config_parse_many_files(conf_files, files, sections, lookup, table, flags, userdata, ret_mtime);
}
#define DEFINE_PARSER(type, vartype, conv_func) \
diff --git a/src/shared/conf-parser.h b/src/shared/conf-parser.h
index 5a7dc7ff59..cd09491112 100644
--- a/src/shared/conf-parser.h
+++ b/src/shared/conf-parser.h
@@ -102,7 +102,7 @@ int config_parse_many_nulstr(
usec_t *ret_mtime); /* possibly NULL */
int config_parse_many(
- const char *conf_file, /* possibly NULL */
+ const char* const* conf_files, /* possibly empty */
const char* const* conf_file_dirs,
const char *dropin_dirname,
const char *sections, /* nulstr */
diff --git a/src/shared/discover-image.c b/src/shared/discover-image.c
index fbce201e29..fb59d1d704 100644
--- a/src/shared/discover-image.c
+++ b/src/shared/discover-image.c
@@ -1250,23 +1250,6 @@ int image_name_lock(const char *name, int operation, LockFile *ret) {
return make_lock_file(p, operation, ret);
}
-bool image_name_is_valid(const char *s) {
- if (!filename_is_valid(s))
- return false;
-
- if (string_has_cc(s, NULL))
- return false;
-
- if (!utf8_is_valid(s))
- return false;
-
- /* Temporary files for atomically creating new files */
- if (startswith(s, ".#"))
- return false;
-
- return true;
-}
-
bool image_in_search_path(
ImageClass class,
const char *root,
diff --git a/src/shared/discover-image.h b/src/shared/discover-image.h
index af67d167c4..3726e98d30 100644
--- a/src/shared/discover-image.h
+++ b/src/shared/discover-image.h
@@ -76,8 +76,6 @@ int image_read_only(Image *i, bool b);
const char* image_type_to_string(ImageType t) _const_;
ImageType image_type_from_string(const char *s) _pure_;
-bool image_name_is_valid(const char *s) _pure_;
-
int image_path_lock(const char *path, int operation, LockFile *global, LockFile *local);
int image_name_lock(const char *name, int operation, LockFile *ret);
diff --git a/src/shared/extension-release.c b/src/shared/extension-release.c
new file mode 100644
index 0000000000..5eecf5a323
--- /dev/null
+++ b/src/shared/extension-release.c
@@ -0,0 +1,79 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "alloc-util.h"
+#include "env-util.h"
+#include "extension-release.h"
+#include "log.h"
+#include "os-util.h"
+#include "strv.h"
+
+int extension_release_validate(
+ const char *name,
+ const char *host_os_release_id,
+ const char *host_os_release_version_id,
+ const char *host_os_release_sysext_level,
+ char **extension_release) {
+
+ const char *extension_release_id = NULL, *extension_release_sysext_level = NULL;
+
+ assert(name);
+ assert(!isempty(host_os_release_id));
+
+ /* Now that we can look into the extension image, let's see if the OS version is compatible */
+ if (strv_isempty(extension_release)) {
+ log_debug("Extension '%s' carries no extension-release data, ignoring extension.", name);
+ return 0;
+ }
+
+ extension_release_id = strv_env_pairs_get(extension_release, "ID");
+ if (isempty(extension_release_id)) {
+ log_debug("Extension '%s' does not contain ID in extension-release but requested to match '%s'",
+ name, strna(host_os_release_id));
+ return 0;
+ }
+
+ if (!streq_ptr(host_os_release_id, extension_release_id)) {
+ log_debug("Extension '%s' is for OS '%s', but deployed on top of '%s'.",
+ name, strna(extension_release_id), strna(host_os_release_id));
+ return 0;
+ }
+
+ /* Rolling releases do not typically set VERSION_ID (eg: ArchLinux) */
+ if (isempty(host_os_release_version_id) && isempty(host_os_release_sysext_level)) {
+ log_debug("No version info on the host (rolling release?), but ID in %s matched.", name);
+ return 1;
+ }
+
+ /* If the extension has a sysext API level declared, then it must match the host API
+ * level. Otherwise, compare OS version as a whole */
+ extension_release_sysext_level = strv_env_pairs_get(extension_release, "SYSEXT_LEVEL");
+ if (!isempty(host_os_release_sysext_level) && !isempty(extension_release_sysext_level)) {
+ if (!streq_ptr(host_os_release_sysext_level, extension_release_sysext_level)) {
+ log_debug("Extension '%s' is for sysext API level '%s', but running on sysext API level '%s'",
+ name, strna(extension_release_sysext_level), strna(host_os_release_sysext_level));
+ return 0;
+ }
+ } else if (!isempty(host_os_release_version_id)) {
+ const char *extension_release_version_id;
+
+ extension_release_version_id = strv_env_pairs_get(extension_release, "VERSION_ID");
+ if (isempty(extension_release_version_id)) {
+ log_debug("Extension '%s' does not contain VERSION_ID in extension-release but requested to match '%s'",
+ name, strna(host_os_release_version_id));
+ return 0;
+ }
+
+ if (!streq_ptr(host_os_release_version_id, extension_release_version_id)) {
+ log_debug("Extension '%s' is for OS '%s', but deployed on top of '%s'.",
+ name, strna(extension_release_version_id), strna(host_os_release_version_id));
+ return 0;
+ }
+ } else if (isempty(host_os_release_version_id) && isempty(host_os_release_sysext_level)) {
+ /* Rolling releases do not typically set VERSION_ID (eg: ArchLinux) */
+ log_debug("No version info on the host (rolling release?), but ID in %s matched.", name);
+ return 1;
+ }
+
+ log_debug("Version info of extension '%s' matches host.", name);
+ return 1;
+}
diff --git a/src/shared/extension-release.h b/src/shared/extension-release.h
new file mode 100644
index 0000000000..5c77010b0e
--- /dev/null
+++ b/src/shared/extension-release.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+/* Given an image name (for logging purposes), a set of os-release values from the host and a key-value pair
+ * vector of extension-release variables, check that the distro and (system extension level or distro
+ * version) match and return 1, and 0 otherwise. */
+int extension_release_validate(
+ const char *name,
+ const char *host_os_release_id,
+ const char *host_os_release_version_id,
+ const char *host_os_release_sysext_level,
+ char **extension_release);
diff --git a/src/shared/hostname-setup.c b/src/shared/hostname-setup.c
index 5cdcdbd93c..511aa7d031 100644
--- a/src/shared/hostname-setup.c
+++ b/src/shared/hostname-setup.c
@@ -152,13 +152,13 @@ void hostname_update_source_hint(const char *hostname, HostnameSource source) {
* notice if somebody sets the hostname directly (not going through hostnamed).
*/
- if (source == HOSTNAME_FALLBACK) {
- r = write_string_file("/run/systemd/fallback-hostname", hostname,
+ if (source == HOSTNAME_DEFAULT) {
+ r = write_string_file("/run/systemd/default-hostname", hostname,
WRITE_STRING_FILE_CREATE | WRITE_STRING_FILE_ATOMIC);
if (r < 0)
- log_warning_errno(r, "Failed to create \"/run/systemd/fallback-hostname\": %m");
+ log_warning_errno(r, "Failed to create \"/run/systemd/default-hostname\": %m");
} else
- unlink_or_warn("/run/systemd/fallback-hostname");
+ unlink_or_warn("/run/systemd/default-hostname");
}
int hostname_setup(bool really) {
@@ -194,7 +194,7 @@ int hostname_setup(bool really) {
}
}
- if (isempty(hn)) {
+ if (!hn) {
/* Don't override the hostname if it is already set and not explicitly configured */
char buf[HOST_NAME_MAX + 1] = {};
@@ -204,10 +204,13 @@ int hostname_setup(bool really) {
}
if (enoent)
- log_info("No hostname configured, using fallback hostname.");
+ log_info("No hostname configured, using default hostname.");
- hn = FALLBACK_HOSTNAME;
- source = HOSTNAME_FALLBACK;
+ hn = b = get_default_hostname();
+ if (!hn)
+ return log_oom();
+
+ source = HOSTNAME_DEFAULT;
}
@@ -230,7 +233,7 @@ int hostname_setup(bool really) {
static const char* const hostname_source_table[] = {
[HOSTNAME_STATIC] = "static",
[HOSTNAME_TRANSIENT] = "transient",
- [HOSTNAME_FALLBACK] = "fallback",
+ [HOSTNAME_DEFAULT] = "default",
};
DEFINE_STRING_TABLE_LOOKUP(hostname_source, HostnameSource);
diff --git a/src/shared/hostname-setup.h b/src/shared/hostname-setup.h
index 1fa0b6f333..5ac7241a59 100644
--- a/src/shared/hostname-setup.h
+++ b/src/shared/hostname-setup.h
@@ -7,7 +7,7 @@
typedef enum HostnameSource {
HOSTNAME_STATIC, /* from /etc/hostname */
HOSTNAME_TRANSIENT, /* a transient hostname set through systemd, hostnamed, the container manager, or otherwise */
- HOSTNAME_FALLBACK, /* the compiled-in fallback was used */
+ HOSTNAME_DEFAULT, /* the os-release default or the compiled-in fallback were used */
_HOSTNAME_INVALID = -EINVAL,
} HostnameSource;
diff --git a/src/shared/meson.build b/src/shared/meson.build
index 6d9a5c5b65..4b27a95cc2 100644
--- a/src/shared/meson.build
+++ b/src/shared/meson.build
@@ -100,6 +100,8 @@ shared_sources = files('''
exec-util.h
exit-status.c
exit-status.h
+ extension-release.c
+ extension-release.h
fdset.c
fdset.h
fileio-label.c
@@ -196,8 +198,6 @@ shared_sources = files('''
numa-util.h
openssl-util.c
openssl-util.h
- os-util.c
- os-util.h
output-mode.c
output-mode.h
pager.c
diff --git a/src/shared/specifier.c b/src/shared/specifier.c
index 86731f8cd2..24e8781805 100644
--- a/src/shared/specifier.c
+++ b/src/shared/specifier.c
@@ -203,7 +203,7 @@ static int specifier_os_release_common(const char *field, char **ret) {
char *t = NULL;
int r;
- r = parse_os_release(NULL, field, &t, NULL);
+ r = parse_os_release(NULL, field, &t);
if (r < 0)
return r;
if (!t) {
diff --git a/src/sysext/sysext.c b/src/sysext/sysext.c
index cd824887bf..60f4dee353 100644
--- a/src/sysext/sysext.c
+++ b/src/sysext/sysext.c
@@ -10,6 +10,7 @@
#include "dissect-image.h"
#include "env-util.h"
#include "escape.h"
+#include "extension-release.h"
#include "fd-util.h"
#include "fileio.h"
#include "format-table.h"
@@ -472,8 +473,7 @@ static int merge_subprocess(Hashmap *images, const char *workspace) {
arg_root,
"ID", &host_os_release_id,
"VERSION_ID", &host_os_release_version_id,
- "SYSEXT_LEVEL", &host_os_release_sysext_level,
- NULL);
+ "SYSEXT_LEVEL", &host_os_release_sysext_level);
if (r < 0)
return log_error_errno(r, "Failed to acquire 'os-release' data of OS tree '%s': %m", empty_to_root(arg_root));
diff --git a/src/test/test-conf-parser.c b/src/test/test-conf-parser.c
index 04b610c6f1..5da864347e 100644
--- a/src/test/test-conf-parser.c
+++ b/src/test/test-conf-parser.c
@@ -349,27 +349,27 @@ static void test_config_parse(unsigned i, const char *s) {
switch (i) {
case 0 ... 4:
- assert_se(r == 0);
+ assert_se(r == 1);
assert_se(streq(setting1, "1"));
break;
case 5 ... 10:
- assert_se(r == 0);
+ assert_se(r == 1);
assert_se(streq(setting1, "1 2 3"));
break;
case 11:
- assert_se(r == 0);
+ assert_se(r == 1);
assert_se(streq(setting1, "1\\\\ \\\\2"));
break;
case 12:
- assert_se(r == 0);
+ assert_se(r == 1);
assert_se(streq(setting1, x1000("ABCD")));
break;
case 13 ... 14:
- assert_se(r == 0);
+ assert_se(r == 1);
assert_se(streq(setting1, x1000("ABCD") " foobar"));
break;
@@ -379,7 +379,7 @@ static void test_config_parse(unsigned i, const char *s) {
break;
case 17:
- assert_se(r == 0);
+ assert_se(r == 1);
assert_se(streq(setting1, "2"));
break;
}
diff --git a/src/test/test-env-util.c b/src/test/test-env-util.c
index 77b8952f83..1e2e936592 100644
--- a/src/test/test-env-util.c
+++ b/src/test/test-env-util.c
@@ -361,6 +361,19 @@ static void test_env_assignment_is_valid(void) {
assert_se(!env_assignment_is_valid("głąb=printf \"\x1b]0;\x07\""));
}
+static void test_putenv_dup(void) {
+ log_info("/* %s */", __func__);
+
+ assert_se(putenv_dup("A=a1", true) == 0);
+ assert_se(streq(getenv("A"), "a1"));
+ assert_se(putenv_dup("A=a1", true) == 0);
+ assert_se(streq(getenv("A"), "a1"));
+ assert_se(putenv_dup("A=a2", false) == 0);
+ assert_se(streq(getenv("A"), "a1"));
+ assert_se(putenv_dup("A=a2", true) == 0);
+ assert_se(streq(getenv("A"), "a2"));
+}
+
static void test_setenv_systemd_exec_pid(void) {
_cleanup_free_ char *saved = NULL;
const char *e;
@@ -416,6 +429,7 @@ int main(int argc, char *argv[]) {
test_env_name_is_valid();
test_env_value_is_valid();
test_env_assignment_is_valid();
+ test_putenv_dup();
test_setenv_systemd_exec_pid();
return 0;
diff --git a/src/test/test-hostname-util.c b/src/test/test-hostname-util.c
index 24c8ed9e3b..6d62958d67 100644
--- a/src/test/test-hostname-util.c
+++ b/src/test/test-hostname-util.c
@@ -10,6 +10,8 @@
#include "tmpfile-util.h"
static void test_hostname_is_valid(void) {
+ log_info("/* %s */", __func__);
+
assert_se(hostname_is_valid("foobar", 0));
assert_se(hostname_is_valid("foobar.com", 0));
assert_se(!hostname_is_valid("foobar.com.", 0));
@@ -49,6 +51,8 @@ static void test_hostname_is_valid(void) {
static void test_hostname_cleanup(void) {
char *s;
+ log_info("/* %s */", __func__);
+
s = strdupa("foobar");
assert_se(streq(hostname_cleanup(s), "foobar"));
s = strdupa("foobar.com");
@@ -94,6 +98,8 @@ static void test_hostname_cleanup(void) {
static void test_hostname_malloc(void) {
_cleanup_free_ char *h = NULL, *l = NULL;
+ log_info("/* %s */", __func__);
+
assert_se(h = gethostname_malloc());
log_info("hostname_malloc: \"%s\"", h);
@@ -101,21 +107,27 @@ static void test_hostname_malloc(void) {
log_info("hostname_short_malloc: \"%s\"", l);
}
-static void test_fallback_hostname(void) {
+static void test_default_hostname(void) {
+ log_info("/* %s */", __func__);
+
if (!hostname_is_valid(FALLBACK_HOSTNAME, 0)) {
log_error("Configured fallback hostname \"%s\" is not valid.", FALLBACK_HOSTNAME);
exit(EXIT_FAILURE);
}
+
+ _cleanup_free_ char *n = get_default_hostname();
+ assert_se(n);
+ log_info("get_default_hostname: \"%s\"", n);
+ assert_se(hostname_is_valid(n, 0));
}
int main(int argc, char *argv[]) {
- test_setup_logging(LOG_INFO);
+ test_setup_logging(LOG_DEBUG);
test_hostname_is_valid();
test_hostname_cleanup();
test_hostname_malloc();
-
- test_fallback_hostname();
+ test_default_hostname();
return 0;
}