summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-x.github/workflows/build_test.sh1
-rw-r--r--TODO2
-rw-r--r--hwdb.d/60-sensor.hwdb12
-rw-r--r--man/bootctl.xml13
-rw-r--r--meson.build3
-rw-r--r--rules.d/50-udev-default.rules.in2
-rw-r--r--src/basic/selinux-util.c29
-rw-r--r--src/basic/unit-file.c199
-rw-r--r--src/boot/bootctl.c116
-rw-r--r--src/core/manager.c3
-rw-r--r--src/test/test-unit-file.c1
-rw-r--r--test/test-functions17
-rwxr-xr-xtest/units/testsuite-15.sh44
13 files changed, 321 insertions, 121 deletions
diff --git a/.github/workflows/build_test.sh b/.github/workflows/build_test.sh
index 8ad7e76790..8471ea181e 100755
--- a/.github/workflows/build_test.sh
+++ b/.github/workflows/build_test.sh
@@ -13,6 +13,7 @@ ARGS=(
"--optimization=3 -Db_lto=true"
"--optimization=3 -Db_lto=false"
"--optimization=3 -Ddns-over-tls=openssl"
+ "--optimization=3 -Dfexecve=true -Dstandalone-binaries=true -Dstatic-libsystemd=true -Dstatic-libudev=true"
"-Db_ndebug=true"
)
PACKAGES=(
diff --git a/TODO b/TODO
index b8cbd3b793..859bd76e3e 100644
--- a/TODO
+++ b/TODO
@@ -228,8 +228,6 @@ Features:
* systemd-analyze netif that explains predictable interface (or networkctl)
-* port selinux code from mallinfo() to mallinfo2() once added to glibc
-
* Add service setting to run a service within the specified VRF. i.e. do the
equivalent of "ip vrf exec".
diff --git a/hwdb.d/60-sensor.hwdb b/hwdb.d/60-sensor.hwdb
index c76509e2af..1c061b3e90 100644
--- a/hwdb.d/60-sensor.hwdb
+++ b/hwdb.d/60-sensor.hwdb
@@ -345,6 +345,14 @@ sensor:modalias:acpi:KIOX010A*:dmi:*:svnGEO*:pnGeoFlex*:*
ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, -1, 0; 0, 0, 1
#########################################
+# Glavey
+#########################################
+
+# Glavey TM800A550L
+sensor:modalias:acpi:KXCJ9000*:dmi:*:bvrZY-8-BI-PX4S70VTR400-X423B-005-D:*:rvnAMICorporation:rnAptioCRB:*
+ ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, 1, 0; 0, 0, 1
+
+#########################################
# Google Chromebooks
#########################################
sensor:modalias:platform:cros-ec-accel:dmi:*:svnGOOGLE:*
@@ -778,6 +786,10 @@ sensor:modalias:acpi:BMA250E*:dmi:bvnAmericanMegatrendsInc.:bvr5.6.5:bd04/15/201
# Toshiba
#########################################
+# Toshiba Encore WT8-B tablet
+sensor:modalias:acpi:INVN6500*:dmi:*:svnTOSHIBA:pnTOSHIBAENCORE2WT8-B:*
+ ACCEL_MOUNT_MATRIX=0, -1, 0; -1, 0, 0; 0, 0, 1
+
# Toshiba Encore WT10A tablet
sensor:modalias:acpi:INVN6500*:dmi:*:svnTOSHIBA:pnTOSHIBAWT10-A-103:*
ACCEL_MOUNT_MATRIX=0, -1, 0; -1, 0, 0; 0, 0, 1
diff --git a/man/bootctl.xml b/man/bootctl.xml
index 878f24742e..5dfed110dd 100644
--- a/man/bootctl.xml
+++ b/man/bootctl.xml
@@ -237,6 +237,19 @@
cannot be written. Currently only applies to random seed operations.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--make-machine-id-directory=yes|no|auto</option></term>
+ <listitem><para>Control creation and deletion of <literal>$ESP/$MACHINE_ID</literal> during
+ <option>install</option> and <option>remove</option>, respectively.
+ <literal>auto</literal> is equivalent to to <literal>yes</literal> if <literal>/etc/machine-id</literal>
+ resides on a filesystem other than tmpfs and <literal>no</literal> otherwise.
+ Defaults to <literal>auto</literal>.</para>
+
+ <para>Overriding this may be desired to hide the machine ID from the (unencrypted) ESP,
+ configure a <citerefentry><refentrytitle>kernel-install</refentrytitle><manvolnum>8</manvolnum></citerefentry> script, or,
+ conversely, commit a machine-id that only appears transient.</para></listitem>
+ </varlistentry>
+
<xi:include href="standard-options.xml" xpointer="no-pager"/>
<xi:include href="standard-options.xml" xpointer="help"/>
<xi:include href="standard-options.xml" xpointer="version"/>
diff --git a/meson.build b/meson.build
index b13817f0d2..ee94d5c354 100644
--- a/meson.build
+++ b/meson.build
@@ -555,6 +555,7 @@ foreach ident : [
#include <signal.h>
#include <sys/wait.h>'''],
['mallinfo', '''#include <malloc.h>'''],
+ ['mallinfo2', '''#include <malloc.h>'''],
['execveat', '''#include <unistd.h>'''],
['close_range', '''#include <unistd.h>'''],
['epoll_pwait2', '''#include <sys/epoll.h>'''],
@@ -721,7 +722,7 @@ if time_epoch == -1
if time_epoch == '' and git.found() and run_command('test', '-e', '.git').returncode() == 0
# If we're in a git repository, use the creation time of the latest git tag.
latest_tag = run_command('git', 'describe', '--abbrev=0', '--tags').stdout().strip()
- time_epoch = run_command('git', 'log', '-1', '--format=%at', latest_tag).stdout()
+ time_epoch = run_command('git', 'log', '--no-show-signature', '-1', '--format=%at', latest_tag).stdout()
endif
if time_epoch == ''
NEWS = files('NEWS')
diff --git a/rules.d/50-udev-default.rules.in b/rules.d/50-udev-default.rules.in
index 53d485dabf..3304e32bb6 100644
--- a/rules.d/50-udev-default.rules.in
+++ b/rules.d/50-udev-default.rules.in
@@ -91,6 +91,8 @@ KERNEL=="fuse", MODE="0666", OPTIONS+="static_node=fuse"
# The static_node is required on s390x and ppc (they are using MODULE_ALIAS)
KERNEL=="kvm", GROUP="kvm", MODE="@DEV_KVM_MODE@", OPTIONS+="static_node=kvm"
+KERNEL=="vfio", MODE="0666", OPTIONS+="static_node=vfio/vfio"
+
KERNEL=="vsock", MODE="0666"
KERNEL=="vhost-vsock", GROUP="kvm", MODE="@DEV_KVM_MODE@", OPTIONS+="static_node=vhost-vsock"
diff --git a/src/basic/selinux-util.c b/src/basic/selinux-util.c
index ee9e34ed47..8c5544d46b 100644
--- a/src/basic/selinux-util.c
+++ b/src/basic/selinux-util.c
@@ -84,15 +84,24 @@ void mac_selinux_retest(void) {
}
#if HAVE_SELINUX
-# if HAVE_MALLINFO
-static struct mallinfo mallinfo_nowarn(void) {
- /* glibc has deprecated mallinfo(), but the replacement malloc_info() returns an XML blob ;=[ */
+# if HAVE_MALLINFO2
+# define HAVE_GENERIC_MALLINFO 1
+typedef struct mallinfo2 generic_mallinfo;
+static generic_mallinfo generic_mallinfo_get(void) {
+ return mallinfo2();
+}
+# elif HAVE_MALLINFO
+# define HAVE_GENERIC_MALLINFO 1
+typedef struct mallinfo generic_mallinfo;
+static generic_mallinfo generic_mallinfo_get(void) {
+ /* glibc has deprecated mallinfo(), let's suppress the deprecation warning if mallinfo2() doesn't
+ * exist yet. */
DISABLE_WARNING_DEPRECATED_DECLARATIONS
return mallinfo();
REENABLE_WARNING
}
# else
-# warning "mallinfo() is missing, add mallinfo2() supported instead."
+# define HAVE_GENERIC_MALLINFO 0
# endif
static int open_label_db(void) {
@@ -100,8 +109,8 @@ static int open_label_db(void) {
usec_t before_timestamp, after_timestamp;
char timespan[FORMAT_TIMESPAN_MAX];
-# if HAVE_MALLINFO
- struct mallinfo before_mallinfo = mallinfo_nowarn();
+# if HAVE_GENERIC_MALLINFO
+ generic_mallinfo before_mallinfo = generic_mallinfo_get();
# endif
before_timestamp = now(CLOCK_MONOTONIC);
@@ -110,10 +119,10 @@ static int open_label_db(void) {
return log_enforcing_errno(errno, "Failed to initialize SELinux labeling handle: %m");
after_timestamp = now(CLOCK_MONOTONIC);
-# if HAVE_MALLINFO
- struct mallinfo after_mallinfo = mallinfo_nowarn();
- int l = after_mallinfo.uordblks > before_mallinfo.uordblks ? after_mallinfo.uordblks - before_mallinfo.uordblks : 0;
- log_debug("Successfully loaded SELinux database in %s, size on heap is %iK.",
+# if HAVE_GENERIC_MALLINFO
+ generic_mallinfo after_mallinfo = generic_mallinfo_get();
+ size_t l = LESS_BY((size_t) after_mallinfo.uordblks, (size_t) before_mallinfo.uordblks);
+ log_debug("Successfully loaded SELinux database in %s, size on heap is %zuK.",
format_timespan(timespan, sizeof(timespan), after_timestamp - before_timestamp, 0),
DIV_ROUND_UP(l, 1024));
# else
diff --git a/src/basic/unit-file.c b/src/basic/unit-file.c
index 50e6eccbf7..ff8aa02d10 100644
--- a/src/basic/unit-file.c
+++ b/src/basic/unit-file.c
@@ -284,7 +284,7 @@ int unit_file_build_name_map(
continue;
}
- FOREACH_DIRENT_ALL(de, d, log_warning_errno(errno, "Failed to read \"%s\", ignoring: %m", *dir)) {
+ FOREACH_DIRENT(de, d, log_warning_errno(errno, "Failed to read \"%s\", ignoring: %m", *dir)) {
char *filename;
_cleanup_free_ char *_filename_free = NULL, *simplified = NULL;
const char *suffix, *dst = NULL;
@@ -403,6 +403,7 @@ int unit_file_build_name_map(
/* Let's also put the names in the reverse db. */
const char *dummy, *src;
HASHMAP_FOREACH_KEY(dummy, src, ids) {
+ _cleanup_free_ char *inst = NULL, *dst_inst = NULL;
const char *dst;
r = unit_ids_map_get(ids, src, &dst);
@@ -412,15 +413,31 @@ int unit_file_build_name_map(
if (null_or_empty_path(dst) != 0)
continue;
- /* Do not treat instance symlinks that point to the template as aliases */
- if (unit_name_is_valid(basename(dst), UNIT_NAME_TEMPLATE) &&
- unit_name_is_valid(src, UNIT_NAME_INSTANCE))
- continue;
+ dst = basename(dst);
+
+ /* If we have an symlink from an instance name to a template name, it is an alias just for
+ * this specific instance, foo@id.service ↔ template@id.service. */
+ if (unit_name_is_valid(dst, UNIT_NAME_TEMPLATE)) {
+ UnitNameFlags t = unit_name_to_instance(src, &inst);
+ if (t < 0)
+ return log_error_errno(t, "Failed to extract instance part from %s: %m", src);
+ if (t == UNIT_NAME_INSTANCE) {
+ r = unit_name_replace_instance(dst, inst, &dst_inst);
+ if (r < 0) {
+ /* This might happen e.g. if the combined length is too large.
+ * Let's not make too much of a fuss. */
+ log_debug_errno(r, "Failed to build alias name (%s + %s), ignoring: %m",
+ dst, inst);
+ continue;
+ }
- r = string_strv_hashmap_put(&names, basename(dst), src);
+ dst = dst_inst;
+ }
+ }
+
+ r = string_strv_hashmap_put(&names, dst, src);
if (r < 0)
- return log_warning_errno(r, "Failed to add entry to hashmap (%s→%s): %m",
- basename(dst), src);
+ return log_warning_errno(r, "Failed to add entry to hashmap (%s→%s): %m", dst, src);
}
if (cache_timestamp_hash)
@@ -434,6 +451,88 @@ int unit_file_build_name_map(
return 1;
}
+static int add_name(
+ const char *unit_name,
+ Set **names,
+ const char *name) {
+ int r;
+
+ assert(names);
+ assert(name);
+
+ r = set_put_strdup(names, name);
+ if (r < 0)
+ return r;
+ if (r > 0 && !streq(unit_name, name))
+ log_debug("Unit %s has alias %s.", unit_name, name);
+ return r;
+}
+
+static int add_names(
+ Hashmap *unit_ids_map,
+ Hashmap *unit_name_map,
+ const char *unit_name,
+ const char *fragment_basename, /* Only set when adding additional names based on fragment path */
+ UnitNameFlags name_type,
+ const char *instance,
+ Set **names,
+ const char *name) {
+
+ char **aliases, **alias;
+ int r;
+
+ assert(name_type == UNIT_NAME_PLAIN || instance);
+
+ /* The unit has its own name if it's not a template. If we're looking at a fragment, the fragment
+ * name (possibly with instance inserted), is also always one of the unit names. */
+ if (name_type != UNIT_NAME_TEMPLATE) {
+ r = add_name(unit_name, names, name);
+ if (r < 0)
+ return r;
+ }
+
+ /* Add any aliases of the name to the set of names.
+ *
+ * We don't even need to know which fragment we will use. The unit_name_map should return the same
+ * set of names for any of the aliases. */
+ aliases = hashmap_get(unit_name_map, name);
+ STRV_FOREACH(alias, aliases) {
+ if (name_type == UNIT_NAME_INSTANCE && unit_name_is_valid(*alias, UNIT_NAME_TEMPLATE)) {
+ _cleanup_free_ char *inst = NULL;
+ const char *inst_fragment = NULL;
+
+ r = unit_name_replace_instance(*alias, instance, &inst);
+ if (r < 0)
+ return log_debug_errno(r, "Cannot build instance name %s + %s: %m",
+ *alias, instance);
+
+ /* Exclude any aliases that point in some other direction.
+ *
+ * See https://github.com/systemd/systemd/pull/13119#discussion_r308145418. */
+ r = unit_ids_map_get(unit_ids_map, inst, &inst_fragment);
+ if (r < 0 && !IN_SET(r, -ENOENT, -ENXIO))
+ return log_debug_errno(r, "Cannot find instance fragment %s: %m", inst);
+
+ if (inst_fragment &&
+ !streq(basename(inst_fragment), fragment_basename)) {
+ log_debug("Instance %s has fragment %s and is not an alias of %s.",
+ inst, inst_fragment, unit_name);
+ continue;
+ }
+
+ r = set_consume(*names, TAKE_PTR(inst));
+ if (r > 0)
+ log_debug("Unit %s has alias %s.", unit_name, inst);
+ } else
+ r = add_name(unit_name, names, *alias);
+
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+}
+
int unit_file_find_fragment(
Hashmap *unit_ids_map,
Hashmap *unit_name_map,
@@ -443,9 +542,8 @@ int unit_file_find_fragment(
const char *fragment = NULL;
_cleanup_free_ char *template = NULL, *instance = NULL;
- _cleanup_set_free_free_ Set *names = NULL;
- char **t, **nnn;
- int r, name_type;
+ _cleanup_set_free_ Set *names = NULL;
+ int r;
/* Finds a fragment path, and returns the set of names:
* if we have …/foo.service and …/foo-alias.service→foo.service,
@@ -461,53 +559,19 @@ int unit_file_find_fragment(
* foo-alias@inst.service → …/foo@inst.service, {foo@inst.service, foo-alias@inst.service}.
*/
- name_type = unit_name_to_instance(unit_name, &instance);
+ UnitNameFlags name_type = unit_name_to_instance(unit_name, &instance);
if (name_type < 0)
return name_type;
- names = set_new(&string_hash_ops);
- if (!names)
- return -ENOMEM;
-
- /* The unit always has its own name if it's not a template. */
- if (IN_SET(name_type, UNIT_NAME_PLAIN, UNIT_NAME_INSTANCE)) {
- r = set_put_strdup(&names, unit_name);
- if (r < 0)
- return r;
- }
+ r = add_names(unit_ids_map, unit_name_map, unit_name, NULL, name_type, instance, &names, unit_name);
+ if (r < 0)
+ return r;
/* First try to load fragment under the original name */
r = unit_ids_map_get(unit_ids_map, unit_name, &fragment);
if (r < 0 && !IN_SET(r, -ENOENT, -ENXIO))
return log_debug_errno(r, "Cannot load unit %s: %m", unit_name);
- if (fragment) {
- /* Add any aliases of the original name to the set of names */
- nnn = hashmap_get(unit_name_map, basename(fragment));
- STRV_FOREACH(t, nnn) {
- if (name_type == UNIT_NAME_INSTANCE && unit_name_is_valid(*t, UNIT_NAME_TEMPLATE)) {
- char *inst;
-
- r = unit_name_replace_instance(*t, instance, &inst);
- if (r < 0)
- return log_debug_errno(r, "Cannot build instance name %s+%s: %m", *t, instance);
-
- if (!streq(unit_name, inst))
- log_debug("%s: %s has alias %s", __func__, unit_name, inst);
-
- log_info("%s: %s+%s → %s", __func__, *t, instance, inst);
- r = set_consume(names, inst);
- } else {
- if (!streq(unit_name, *t))
- log_debug("%s: %s has alias %s", __func__, unit_name, *t);
-
- r = set_put_strdup(&names, *t);
- }
- if (r < 0)
- return r;
- }
- }
-
if (!fragment && name_type == UNIT_NAME_INSTANCE) {
/* Look for a fragment under the template name */
@@ -518,43 +582,22 @@ int unit_file_find_fragment(
r = unit_ids_map_get(unit_ids_map, template, &fragment);
if (r < 0 && !IN_SET(r, -ENOENT, -ENXIO))
return log_debug_errno(r, "Cannot load template %s: %m", template);
+ }
- if (fragment) {
- /* Add any aliases of the original name to the set of names */
- nnn = hashmap_get(unit_name_map, basename(fragment));
- STRV_FOREACH(t, nnn) {
- _cleanup_free_ char *inst = NULL;
- const char *inst_fragment = NULL;
-
- r = unit_name_replace_instance(*t, instance, &inst);
- if (r < 0)
- return log_debug_errno(r, "Cannot build instance name %s+%s: %m", template, instance);
-
- /* Exclude any aliases that point in some other direction. */
- r = unit_ids_map_get(unit_ids_map, inst, &inst_fragment);
- if (r < 0 && !IN_SET(r, -ENOENT, -ENXIO))
- return log_debug_errno(r, "Cannot find instance fragment %s: %m", inst);
-
- if (inst_fragment &&
- !streq(basename(inst_fragment), basename(fragment))) {
- log_debug("Instance %s has fragment %s and is not an alias of %s.",
- inst, inst_fragment, unit_name);
- continue;
- }
+ if (fragment) {
+ const char *fragment_basename = basename(fragment);
- if (!streq(unit_name, inst))
- log_debug("%s: %s has alias %s", __func__, unit_name, inst);
- r = set_consume(names, TAKE_PTR(inst));
- if (r < 0)
- return r;
- }
+ if (!streq(fragment_basename, unit_name)) {
+ /* Add names based on the fragment name to the set of names */
+ r = add_names(unit_ids_map, unit_name_map, unit_name, fragment_basename, name_type, instance, &names, fragment_basename);
+ if (r < 0)
+ return r;
}
}
*ret_fragment_path = fragment;
*ret_names = TAKE_PTR(names);
- // FIXME: if instance, consider any unit names with different template name
return 0;
}
diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c
index a684717bb0..34f0c14b44 100644
--- a/src/boot/bootctl.c
+++ b/src/boot/bootctl.c
@@ -29,6 +29,7 @@
#include "main-func.h"
#include "mkdir.h"
#include "pager.h"
+#include "parse-argument.h"
#include "parse-util.h"
#include "pretty-print.h"
#include "random-util.h"
@@ -52,6 +53,7 @@ static bool arg_print_dollar_boot_path = false;
static bool arg_touch_variables = true;
static PagerFlags arg_pager_flags = 0;
static bool arg_graceful = false;
+static int arg_make_machine_id_directory = -1;
STATIC_DESTRUCTOR_REGISTER(arg_esp_path, freep);
STATIC_DESTRUCTOR_REGISTER(arg_xbootldr_path, freep);
@@ -112,6 +114,19 @@ static int acquire_xbootldr(bool unprivileged_mode, sd_id128_t *ret_uuid) {
return 1;
}
+static void settle_make_machine_id_directory(void) {
+ int r;
+
+ if (arg_make_machine_id_directory >= 0)
+ return;
+
+ r = path_is_temporary_fs("/etc/machine-id");
+ if (r < 0)
+ log_debug_errno(r, "Couldn't determine whether /etc/machine-id is on a temporary file system, assuming so.");
+
+ arg_make_machine_id_directory = r == 0;
+}
+
/* search for "#### LoaderInfo: systemd-boot 218 ####" string inside the binary */
static int get_file_version(int fd, char **v) {
struct stat st;
@@ -888,6 +903,24 @@ static int remove_subdirs(const char *root, const char *const *subdirs) {
return r < 0 ? r : q;
}
+static int remove_machine_id_directory(const char *root) {
+ sd_id128_t machine_id;
+ char buf[SD_ID128_STRING_MAX];
+ int r;
+
+ assert(root);
+ assert(arg_make_machine_id_directory >= 0);
+
+ if (!arg_make_machine_id_directory)
+ return 0;
+
+ r = sd_id128_get_machine(&machine_id);
+ if (r < 0)
+ return log_error_errno(r, "Failed to get machine id: %m");
+
+ return rmdir_one(root, sd_id128_to_string(machine_id, buf));
+}
+
static int remove_binaries(const char *esp_path) {
const char *p;
int r, q;
@@ -974,9 +1007,13 @@ static int install_loader_config(const char *esp_path) {
_cleanup_(unlink_and_freep) char *t = NULL;
_cleanup_fclose_ FILE *f = NULL;
_cleanup_close_ int fd = -1;
+ sd_id128_t machine_id;
+ char machine_string[SD_ID128_STRING_MAX];
const char *p;
int r;
+ assert(arg_make_machine_id_directory >= 0);
+
p = prefix_roota(esp_path, "/loader/loader.conf");
if (access(p, F_OK) >= 0) /* Silently skip creation if the file already exists (early check) */
return 0;
@@ -991,6 +1028,13 @@ static int install_loader_config(const char *esp_path) {
fprintf(f, "#timeout 3\n"
"#console-mode keep\n");
+ if (arg_make_machine_id_directory) {
+ r = sd_id128_get_machine(&machine_id);
+ if (r < 0)
+ return log_error_errno(r, "Failed to get machine id: %m");
+
+ fprintf(f, "default %s-*\n", sd_id128_to_string(machine_id, machine_string));
+ }
r = fflush_sync_and_check(f);
if (r < 0)
@@ -1006,6 +1050,24 @@ static int install_loader_config(const char *esp_path) {
return 1;
}
+static int install_machine_id_directory(const char *root) {
+ sd_id128_t machine_id;
+ char buf[SD_ID128_STRING_MAX];
+ int r;
+
+ assert(root);
+ assert(arg_make_machine_id_directory >= 0);
+
+ if (!arg_make_machine_id_directory)
+ return 0;
+
+ r = sd_id128_get_machine(&machine_id);
+ if (r < 0)
+ return log_error_errno(r, "Failed to get machine id: %m");
+
+ return mkdir_one(root, sd_id128_to_string(machine_id, buf));
+}
+
static int help(int argc, char *argv[], void *userdata) {
_cleanup_free_ char *link = NULL;
int r;
@@ -1043,6 +1105,8 @@ static int help(int argc, char *argv[], void *userdata) {
" --no-pager Do not pipe output into a pager\n"
" --graceful Don't fail when the ESP cannot be found or EFI\n"
" variables cannot be written\n"
+ " --make-machine-id-directory=yes|no|auto\n"
+ " Create $BOOT/$MACHINE_ID\n"
"\nSee the %2$s for details.\n",
program_invocation_short_name,
link,
@@ -1062,24 +1126,27 @@ static int parse_argv(int argc, char *argv[]) {
ARG_NO_VARIABLES,
ARG_NO_PAGER,
ARG_GRACEFUL,
+ ARG_MAKE_MACHINE_ID_DIRECTORY,
};
static const struct option options[] = {
- { "help", no_argument, NULL, 'h' },
- { "version", no_argument, NULL, ARG_VERSION },
- { "esp-path", required_argument, NULL, ARG_ESP_PATH },
- { "path", required_argument, NULL, ARG_ESP_PATH }, /* Compatibility alias */
- { "boot-path", required_argument, NULL, ARG_BOOT_PATH },
- { "print-esp-path", no_argument, NULL, 'p' },
- { "print-path", no_argument, NULL, 'p' }, /* Compatibility alias */
- { "print-boot-path", no_argument, NULL, 'x' },
- { "no-variables", no_argument, NULL, ARG_NO_VARIABLES },
- { "no-pager", no_argument, NULL, ARG_NO_PAGER },
- { "graceful", no_argument, NULL, ARG_GRACEFUL },
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, ARG_VERSION },
+ { "esp-path", required_argument, NULL, ARG_ESP_PATH },
+ { "path", required_argument, NULL, ARG_ESP_PATH }, /* Compatibility alias */
+ { "boot-path", required_argument, NULL, ARG_BOOT_PATH },
+ { "print-esp-path", no_argument, NULL, 'p' },
+ { "print-path", no_argument, NULL, 'p' }, /* Compatibility alias */
+ { "print-boot-path", no_argument, NULL, 'x' },
+ { "no-variables", no_argument, NULL, ARG_NO_VARIABLES },
+ { "no-pager", no_argument, NULL, ARG_NO_PAGER },
+ { "graceful", no_argument, NULL, ARG_GRACEFUL },
+ { "make-machine-id-directory", required_argument, NULL, ARG_MAKE_MACHINE_ID_DIRECTORY },
{}
};
int c, r;
+ bool b;
assert(argc >= 0);
assert(argv);
@@ -1132,6 +1199,17 @@ static int parse_argv(int argc, char *argv[]) {
arg_graceful = true;
break;
+ case ARG_MAKE_MACHINE_ID_DIRECTORY:
+ if (streq(optarg, "auto"))
+ arg_make_machine_id_directory = -1; /* default */
+ else {
+ r = parse_boolean_argument("--make-machine-id-directory=", optarg, &b);
+ if (r < 0)
+ return r;
+ arg_make_machine_id_directory = b;
+ }
+ break;
+
case '?':
return -EINVAL;
@@ -1530,6 +1608,8 @@ static int verb_install(int argc, char *argv[], void *userdata) {
if (r < 0)
return r;
+ settle_make_machine_id_directory();
+
install = streq(argv[0], "install");
RUN_WITH_UMASK(0002) {
@@ -1555,6 +1635,10 @@ static int verb_install(int argc, char *argv[], void *userdata) {
if (r < 0)
return r;
+ r = install_machine_id_directory(arg_dollar_boot_path());
+ if (r < 0)
+ return r;
+
r = install_random_seed(arg_esp_path);
if (r < 0)
return r;
@@ -1584,6 +1668,8 @@ static int verb_remove(int argc, char *argv[], void *userdata) {
if (r < 0)
return r;
+ settle_make_machine_id_directory();
+
r = remove_binaries(arg_esp_path);
q = remove_file(arg_esp_path, "/loader/loader.conf");
@@ -1602,11 +1688,19 @@ static int verb_remove(int argc, char *argv[], void *userdata) {
if (q < 0 && r >= 0)
r = q;
+ q = remove_machine_id_directory(arg_esp_path);
+ if (q < 0 && r >= 0)
+ r = 1;
+
if (arg_xbootldr_path) {
/* Remove the latter two also in the XBOOTLDR partition if it exists */
q = remove_subdirs(arg_xbootldr_path, dollar_boot_subdirs);
if (q < 0 && r >= 0)
r = q;
+
+ q = remove_machine_id_directory(arg_xbootldr_path);
+ if (q < 0 && r >= 0)
+ r = q;
}
(void) sync_everything();
diff --git a/src/core/manager.c b/src/core/manager.c
index 4abe6606f6..30aadb0944 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -688,7 +688,8 @@ static int manager_setup_prefix(Manager *m) {
for (ExecDirectoryType i = 0; i < _EXEC_DIRECTORY_TYPE_MAX; i++) {
r = sd_path_lookup(p[i].type, p[i].suffix, &m->prefix[i]);
if (r < 0)
- return r;
+ return log_warning_errno(r, "Failed to lookup %s path: %m",
+ exec_directory_type_to_string(i));
}
return 0;
diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c
index 8f9679051d..477ae03a02 100644
--- a/src/test/test-unit-file.c
+++ b/src/test/test-unit-file.c
@@ -92,6 +92,7 @@ static void test_runlevel_to_target(void) {
}
int main(int argc, char **argv) {
+ log_show_color(true);
test_setup_logging(LOG_DEBUG);
test_unit_validate_alias_symlink_and_warn();
diff --git a/test/test-functions b/test/test-functions
index fdab3b9d41..65e3c96539 100644
--- a/test/test-functions
+++ b/test/test-functions
@@ -1134,8 +1134,7 @@ check_result_common() {
local ret
if [ -s "$workspace/failed" ]; then
- # …/failed only counts if non-empty
- ls -l "$workspace/failed"
+ # Non-empty …/failed has highest priority
cp -a "$workspace/failed" "${TESTDIR:?}/"
ret=1
elif [ -e "$workspace/testok" ]; then
@@ -1147,24 +1146,28 @@ check_result_common() {
cat "$workspace/skipped"
ret=0
elif [ -n "$TIMED_OUT" ]; then
- echo "${TESTNAME:?} timed out!"
+ echo "(timeout)" >"${TESTDIR:?}/failed"
ret=2
else
- echo "${TESTNAME:?} did not report a result!"
+ echo "(failed; see logs)" >"${TESTDIR:?}/failed"
+ ret=3
fi
save_journal "$workspace/var/log/journal"
- check_asan_reports "$workspace" || ret=3
+ check_asan_reports "$workspace" || ret=4
if [ -d "${ARTIFACT_DIRECTORY}" ] && [ -f "$workspace/strace.out" ]; then
cp "$workspace/strace.out" "${ARTIFACT_DIRECTORY}/"
fi
- [ -f "$TESTDIR/failed" ] && cat "$TESTDIR/failed"
+ if [ ${ret:?} != 0 ] && [ -f "$TESTDIR/failed" ]; then
+ echo -n "${TESTNAME:?}: "
+ cat "$TESTDIR/failed"
+ fi
echo "${JOURNAL_LIST:-"No journals were saved"}"
- return $ret
+ return ${ret:?}
}
check_result_nspawn() {
diff --git a/test/units/testsuite-15.sh b/test/units/testsuite-15.sh
index 23c2156501..c3784e299d 100755
--- a/test/units/testsuite-15.sh
+++ b/test/units/testsuite-15.sh
@@ -32,12 +32,9 @@ create_service () {
Description=$SERVICE_NAME unit
[Service]
-ExecStart=/bin/sleep 100000
+ExecStart=sleep 100000
EOF
- mkdir -p /{etc,run,usr/lib}/systemd/system/"$SERVICE_NAME".service.d
- mkdir -p /etc/systemd/system/"$SERVICE_NAME".service.{wants,requires}
- mkdir -p /run/systemd/system/"$SERVICE_NAME".service.{wants,requires}
- mkdir -p /usr/lib/systemd/system/"$SERVICE_NAME".service.{wants,requires}
+ mkdir -p /{etc,run,usr/lib}/systemd/system/"$SERVICE_NAME".service.{d,wants,requires}
}
create_services () {
@@ -47,12 +44,10 @@ create_services () {
}
check_ok () {
- [ $# -eq 3 ] || return
-
- x="$(systemctl show --value -p "$2" "$1")"
+ x="$(systemctl show --value -p "${2:?}" "${1:?}")"
case "$x" in
- *$3*) return 0 ;;
- *) return 1 ;;
+ *${3:?}*) return 0 ;;
+ *) return 1 ;;
esac
}
@@ -123,7 +118,7 @@ EOF
check_ok test15-b ExecCondition "/bin/echo test15-b"
rm -rf /usr/lib/systemd/system/service.d
- clear_services test15-a test15-b test15-c
+ clear_services test15-a test15-b test15-c test15-c1
}
test_linked_units () {
@@ -153,6 +148,32 @@ test_linked_units () {
clear_services test15-a test15-b
}
+test_template_alias() {
+ echo "Testing instance alias..."
+ echo "*** forward"
+
+ create_service test15-a@
+ ln -s test15-a@inst.service /etc/systemd/system/test15-b@inst.service # alias
+
+ check_ok test15-a@inst Names test15-a@inst.service
+ check_ok test15-a@inst Names test15-b@inst.service
+
+ check_ok test15-a@other Names test15-a@other.service
+ check_ko test15-a@other Names test15-b@other.service
+
+ echo "*** reverse"
+
+ systemctl daemon-reload
+
+ check_ok test15-b@inst Names test15-a@inst.service
+ check_ok test15-b@inst Names test15-b@inst.service
+
+ check_ko test15-b@other Names test15-a@other.service
+ check_ok test15-b@other Names test15-b@other.service
+
+ clear_services test15-a@ test15-b@
+}
+
test_hierarchical_dropins () {
echo "Testing hierarchical dropins..."
echo "*** test service.d/ top level drop-in"
@@ -495,6 +516,7 @@ test_invalid_dropins () {
test_basic_dropins
test_linked_units
+test_template_alias
test_hierarchical_dropins
test_template_dropins
test_alias_dropins