Merge pull request #18704 from keszybz/fallback-hostame-override

Allow overriding of fallback hostname through envvar and os-release field
This commit is contained in:
Zbigniew Jędrzejewski-Szmek
2021-02-23 00:41:27 +01:00
committed by GitHub
40 changed files with 440 additions and 216 deletions
+15
View File
@@ -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;
+3
View File
@@ -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
+31 -2
View File
@@ -3,14 +3,39 @@
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/utsname.h>
#include <unistd.h>
#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] != '.');
}
+1
View File
@@ -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);
+1
View File
@@ -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)
+2
View File
@@ -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
+21 -74
View File
@@ -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;
}
+7 -7
View File
@@ -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);
+69 -13
View File
@@ -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;
}
+1 -2
View File
@@ -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");
+38 -17
View File
@@ -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(&current);
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),
+1 -1
View File
@@ -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,
+1
View File
@@ -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"
+1
View File
@@ -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"
+2 -2
View File
@@ -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,
+1 -1
View File
@@ -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"
+1 -1
View File
@@ -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"
+1
View File
@@ -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"
+1 -1
View File
@@ -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,
+18 -15
View File
@@ -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;
}
+14 -9
View File
@@ -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) \
+1 -1
View File
@@ -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 */
-17
View File
@@ -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,
-2
View File
@@ -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);
+79
View File
@@ -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;
}
+12
View File
@@ -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);
+12 -9
View File
@@ -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);
+1 -1
View File
@@ -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;
+2 -2
View File
@@ -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
+1 -1
View File
@@ -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) {
+2 -2
View File
@@ -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));
+6 -6
View File
@@ -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;
}
+14
View File
@@ -361,6 +361,19 @@ static void test_env_assignment_is_valid(void) {
assert_se(!env_assignment_is_valid("głąb=printf \"\x1b]0;<mock-chroot>\x07<mock-chroot>\""));
}
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;
+16 -4
View File
@@ -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;
}