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
commit a5e5e102ba
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
40 changed files with 440 additions and 216 deletions

4
NEWS
View file

@ -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

View file

@ -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

View file

@ -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 {
<variablelist class="dbus-property" generated="True" extra-ref="PrettyHostname"/>
<variablelist class="dbus-property" generated="True" extra-ref="FallbackHostname"/>
<variablelist class="dbus-property" generated="True" extra-ref="DefaultHostname"/>
<variablelist class="dbus-property" generated="True" extra-ref="HostnameSource"/>
@ -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.</para>
<para>The <varname>FallbackHostname</varname> property exposes the fallback hostname (configured at
compilation time).</para>
<para>The <varname>DefaultHostname</varname> property exposes the default hostname (configured through
<citerefentry><refentrytitle>os-release</refentrytitle><manvolnum>5</manvolnum></citerefentry>, or a
fallback set at compilation time).</para>
<para>The <varname>HostnameSource</varname> property exposes the origin of the currently configured
hostname. One of <literal>static</literal> (set from <filename>/etc/hostname</filename>),
<literal>transient</literal> (a non-permanent hostname from an external source),
<literal>fallback</literal> (the compiled-in fallback value).</para>
<literal>default</literal> (the value from <filename>os-release</filename> or the the compiled-in
fallback).</para>
<para>The <varname>IconName</varname> property exposes the <emphasis>icon name</emphasis> 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 {
<listitem><para>Limit the hostname to 63 chars, which is the length of a DNS label.</para></listitem>
<listitem><para>If after stripping special chars the empty string is the result, you can pass this
as-is to <filename>systemd-hostnamed</filename> in which case it will automatically use
<literal>&FALLBACK_HOSTNAME;</literal>.</para></listitem>
as-is to <filename>systemd-hostnamed</filename> in which case it will automatically use a suitable
fallback.</para></listitem>
<listitem><para>Uppercase charaacters should be replaced with their lowercase equivalents.
</para></listitem>

View file

@ -317,6 +317,23 @@
</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>DEFAULT_HOSTNAME=</varname></term>
<listitem><para>A string specifying the hostname if
<citerefentry><refentrytitle>hostname</refentrytitle><manvolnum>5</manvolnum></citerefentry> 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.</para>
<para>See
<citerefentry><refentrytitle>org.freedesktop.hostname1</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for a description of how
<citerefentry><refentrytitle>systemd-hostnamed.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
determines the fallback hostname.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>SYSEXT_LEVEL=</varname></term>

View file

@ -31,7 +31,9 @@
<filename>/etc/systemd/system.conf.d/*.conf</filename>,
<filename>/run/systemd/system.conf.d/*.conf</filename>,
<filename>/usr/lib/systemd/system.conf.d/*.conf</filename></para>
<para><filename>/etc/systemd/user.conf</filename>,
<para><filename>~/.config/systemd/user.conf</filename>,
<filename>/etc/systemd/user.conf</filename>,
<filename>/etc/systemd/user.conf.d/*.conf</filename>,
<filename>/run/systemd/user.conf.d/*.conf</filename>,
<filename>/usr/lib/systemd/user.conf.d/*.conf</filename></para>
@ -40,16 +42,16 @@
<refsect1>
<title>Description</title>
<para>When run as a system instance, systemd interprets the
configuration file <filename>system.conf</filename> and the files
in <filename>system.conf.d</filename> directories; when run as a
user instance, systemd interprets the configuration file
<filename>user.conf</filename> and the files in
<filename>user.conf.d</filename> directories. These configuration
files contain a few settings controlling basic manager
operations. See
<citerefentry><refentrytitle>systemd.syntax</refentrytitle><manvolnum>7</manvolnum></citerefentry>
for a general description of the syntax.</para>
<para>When run as a system instance, <command>systemd</command> interprets the configuration file
<filename>system.conf</filename> and the files in <filename>system.conf.d</filename> directories; when
run as a user instance, it interprets the configuration file <filename>user.conf</filename> (either in
the home directory of the user, or if not found, under <filename>/etc/systemd/</filename>) and the files
in <filename>user.conf.d</filename> directories. These configuration files contain a few settings
controlling basic manager operations.</para>
<para>See
<citerefentry><refentrytitle>systemd.syntax</refentrytitle><manvolnum>7</manvolnum></citerefentry> for a
general description of the syntax.</para>
</refsect1>
<xi:include href="standard-conf.xml" xpointer="main-conf" />
@ -321,11 +323,10 @@
<varlistentry>
<term><varname>DefaultEnvironment=</varname></term>
<listitem><para>Sets manager environment variables passed to
all executed processes. Takes a space-separated list of
variable assignments. See
<citerefentry project='man-pages'><refentrytitle>environ</refentrytitle><manvolnum>7</manvolnum></citerefentry>
for details about environment variables.</para>
<listitem><para>Configures environment variables passed to all executed processes. Takes a
space-separated list of variable assignments. See <citerefentry
project='man-pages'><refentrytitle>environ</refentrytitle><manvolnum>7</manvolnum></citerefentry> for
details about environment variables.</para>
<para>Example:
@ -337,6 +338,20 @@
<literal>VAR3</literal>.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>ManagerEnvironment=</varname></term>
<listitem><para>Takes the same arguments as <varname>DefaultEnvironment=</varname>, see above. Sets
environment variables just for the manager process itself. These variables are not inherited by
processes spawned by the service manager, use <varname>DefaultEnvironment=</varname> 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.</para>
<para>Setting environment variables for the manager process may be useful to modify its behaviour.
See <ulink url="https://systemd.io/ENVIRONMENT">ENVIRONMENT</ulink> for a descriptions of some
variables understood by <command>systemd</command>.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>DefaultCPUAccounting=</varname></term>
<term><varname>DefaultBlockIOAccounting=</varname></term>

View file

@ -60,7 +60,7 @@
<filename>$XDG_RUNTIME_DIR/systemd/user.control/*</filename>
<filename>$XDG_RUNTIME_DIR/systemd/transient/*</filename>
<filename>$XDG_RUNTIME_DIR/systemd/generator.early/*</filename>
<filename>$XDG_CONFIG_HOME/systemd/user/*</filename>
<filename>~/.config/systemd/user/*</filename>
<filename>$XDG_CONFIG_DIRS/systemd/user/*</filename>
<filename>/etc/systemd/user/*</filename>
<filename>$XDG_RUNTIME_DIR/systemd/user/*</filename>

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;

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

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] != '.');
}

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

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)

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

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

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

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

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

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

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,

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"

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"

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,

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"

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"

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"

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,

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

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

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 */

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,

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

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

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

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

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;

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

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

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

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

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;

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