From a40e495847ab0722ce566e989325008195da7275 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 5 Apr 2024 20:05:06 +0900 Subject: [PATCH 1/7] network-generator: rename NETWORKD_UNIT_... -> NETWORK_UNIT_... As .link files are used by systemd-udevd, rather than systemd-networkd. Also, this makes it ends with '/', to follow our recent coding style. --- src/network/generator/main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/network/generator/main.c b/src/network/generator/main.c index 4c8e5dee37..0455d5f5c3 100644 --- a/src/network/generator/main.c +++ b/src/network/generator/main.c @@ -16,7 +16,7 @@ #include "proc-cmdline.h" #include "recurse-dir.h" -#define NETWORKD_UNIT_DIRECTORY "/run/systemd/network" +#define NETWORK_UNIT_DIRECTORY "/run/systemd/network/" static const char *arg_root = NULL; @@ -125,11 +125,11 @@ static int context_save(Context *context) { Link *link; int r; - const char *p = prefix_roota(arg_root, NETWORKD_UNIT_DIRECTORY); + const char *p = prefix_roota(arg_root, NETWORK_UNIT_DIRECTORY); r = mkdir_p(p, 0755); if (r < 0) - return log_error_errno(r, "Failed to create directory " NETWORKD_UNIT_DIRECTORY ": %m"); + return log_error_errno(r, "Failed to create directory " NETWORK_UNIT_DIRECTORY ": %m"); HASHMAP_FOREACH(network, context->networks_by_name) RET_GATHER(r, network_save(network, p)); @@ -194,7 +194,7 @@ static int pick_up_credentials(void) { continue; } - _cleanup_free_ char *output = path_join(NETWORKD_UNIT_DIRECTORY, fn); + _cleanup_free_ char *output = path_join(NETWORK_UNIT_DIRECTORY, fn); if (!output) return log_oom(); From 6c15a28454c80a4d777b1b59826893ab5901b75d Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 5 Apr 2024 12:21:30 +0900 Subject: [PATCH 2/7] creds-util: move pick_up_credentials() from network-generator The function is quite general, and can be used at other places. Let's move to our shared library. --- src/network/generator/main.c | 80 +++---------------------------- src/shared/creds-util.c | 91 +++++++++++++++++++++++++++++++++++- src/shared/creds-util.h | 8 ++++ 3 files changed, 105 insertions(+), 74 deletions(-) diff --git a/src/network/generator/main.c b/src/network/generator/main.c index 0455d5f5c3..5a26a54fc5 100644 --- a/src/network/generator/main.c +++ b/src/network/generator/main.c @@ -3,7 +3,6 @@ #include #include "build.h" -#include "copy.h" #include "creds-util.h" #include "fd-util.h" #include "fs-util.h" @@ -14,7 +13,6 @@ #include "network-generator.h" #include "path-util.h" #include "proc-cmdline.h" -#include "recurse-dir.h" #define NETWORK_UNIT_DIRECTORY "/run/systemd/network/" @@ -143,76 +141,6 @@ static int context_save(Context *context) { return r; } -static int pick_up_credentials(void) { - _cleanup_close_ int credential_dir_fd = -EBADF; - int r, ret = 0; - - credential_dir_fd = open_credentials_dir(); - if (IN_SET(credential_dir_fd, -ENXIO, -ENOENT)) /* Credential env var not set, or dir doesn't exist. */ - return 0; - if (credential_dir_fd < 0) - return log_error_errno(credential_dir_fd, "Failed to open credentials directory: %m"); - - _cleanup_free_ DirectoryEntries *des = NULL; - r = readdir_all(credential_dir_fd, RECURSE_DIR_SORT|RECURSE_DIR_IGNORE_DOT|RECURSE_DIR_ENSURE_TYPE, &des); - if (r < 0) - return log_error_errno(r, "Failed to enumerate credentials: %m"); - - FOREACH_ARRAY(i, des->entries, des->n_entries) { - static const struct { - const char *credential_prefix; - const char *filename_suffix; - } table[] = { - { "network.link.", ".link" }, - { "network.netdev.", ".netdev" }, - { "network.network.", ".network" }, - }; - - _cleanup_free_ char *fn = NULL; - struct dirent *de = *i; - - if (de->d_type != DT_REG) - continue; - - FOREACH_ARRAY(t, table, ELEMENTSOF(table)) { - const char *e = startswith(de->d_name, t->credential_prefix); - - if (e) { - fn = strjoin(e, t->filename_suffix); - if (!fn) - return log_oom(); - - break; - } - } - - if (!fn) - continue; - - if (!filename_is_valid(fn)) { - log_warning("Passed credential '%s' would result in invalid filename '%s', ignoring.", de->d_name, fn); - continue; - } - - _cleanup_free_ char *output = path_join(NETWORK_UNIT_DIRECTORY, fn); - if (!output) - return log_oom(); - - r = copy_file_at( - credential_dir_fd, de->d_name, - AT_FDCWD, output, - /* open_flags= */ 0, - 0644, - /* flags= */ 0); - if (r < 0) - RET_GATHER(ret, log_warning_errno(r, "Failed to copy credential %s → file %s: %m", de->d_name, output)); - else - log_info("Installed %s from credential.", output); - } - - return ret; -} - static int help(void) { printf("%s [OPTIONS...] [-- KERNEL_CMDLINE]\n" " -h --help Show this help\n" @@ -304,7 +232,13 @@ static int run(int argc, char *argv[]) { return log_warning_errno(r, "Failed to merge multiple command line options: %m"); RET_GATHER(ret, context_save(&context)); - RET_GATHER(ret, pick_up_credentials()); + + static const PickUpCredential table[] = { + { "network.link.", NETWORK_UNIT_DIRECTORY, ".link" }, + { "network.netdev.", NETWORK_UNIT_DIRECTORY, ".netdev" }, + { "network.network.", NETWORK_UNIT_DIRECTORY, ".network" }, + }; + RET_GATHER(ret, pick_up_credentials(table, ELEMENTSOF(table))); return ret; } diff --git a/src/shared/creds-util.c b/src/shared/creds-util.c index ba8aee3355..bd2af6d172 100644 --- a/src/shared/creds-util.c +++ b/src/shared/creds-util.c @@ -12,6 +12,7 @@ #include "capability-util.h" #include "chattr-util.h" #include "constants.h" +#include "copy.h" #include "creds-util.h" #include "efi-api.h" #include "env-util.h" @@ -21,11 +22,12 @@ #include "fs-util.h" #include "io-util.h" #include "memory-util.h" -#include "mkdir.h" +#include "mkdir-label.h" #include "openssl-util.h" #include "parse-util.h" #include "path-util.h" #include "random-util.h" +#include "recurse-dir.h" #include "sparse-endian.h" #include "stat-util.h" #include "tmpfile-util.h" @@ -1652,3 +1654,90 @@ int ipc_decrypt_credential(const char *validate_name, usec_t validate_timestamp, return 0; } + +static int pick_up_credential_one( + int credential_dir_fd, + const char *credential_name, + const PickUpCredential *table_entry) { + + _cleanup_free_ char *fn = NULL, *target_path = NULL; + const char *e; + int r; + + assert(credential_dir_fd >= 0); + assert(credential_name); + assert(table_entry); + + e = startswith(credential_name, table_entry->credential_prefix); + if (!e) + return 0; /* unmatched */ + + fn = strjoin(e, table_entry->filename_suffix); + if (!fn) + return log_oom(); + + if (!filename_is_valid(fn)) + return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), + "Passed credential '%s' would result in invalid filename '%s'.", + credential_name, fn); + + r = mkdir_p_label(table_entry->target_dir, 0755); + if (r < 0) + return log_warning_errno(r, "Failed to create '%s': %m", table_entry->target_dir); + + target_path = path_join(table_entry->target_dir, fn); + if (!target_path) + return log_oom(); + + r = copy_file_at( + credential_dir_fd, credential_name, + AT_FDCWD, target_path, + /* open_flags= */ 0, + 0644, + /* flags= */ 0); + if (r < 0) + return log_warning_errno(r, "Failed to copy credential %s → file %s: %m", + credential_name, target_path); + + log_info("Installed %s from credential.", target_path); + return 1; /* done */ +} + +int pick_up_credentials(const PickUpCredential *table, size_t n_table_entry) { + _cleanup_close_ int credential_dir_fd = -EBADF; + int r, ret = 0; + + assert(table); + assert(n_table_entry > 0); + + credential_dir_fd = open_credentials_dir(); + if (IN_SET(credential_dir_fd, -ENXIO, -ENOENT)) { + /* Credential env var not set, or dir doesn't exist. */ + log_debug("No credentials found."); + return 0; + } + if (credential_dir_fd < 0) + return log_error_errno(credential_dir_fd, "Failed to open credentials directory: %m"); + + _cleanup_free_ DirectoryEntries *des = NULL; + r = readdir_all(credential_dir_fd, RECURSE_DIR_SORT|RECURSE_DIR_IGNORE_DOT|RECURSE_DIR_ENSURE_TYPE, &des); + if (r < 0) + return log_error_errno(r, "Failed to enumerate credentials: %m"); + + FOREACH_ARRAY(i, des->entries, des->n_entries) { + struct dirent *de = *i; + + if (de->d_type != DT_REG) + continue; + + FOREACH_ARRAY(t, table, n_table_entry) { + r = pick_up_credential_one(credential_dir_fd, de->d_name, t); + if (r != 0) { + RET_GATHER(ret, r); + break; /* Done, or failed. Let's move to the next credential. */ + } + } + } + + return ret; +} diff --git a/src/shared/creds-util.h b/src/shared/creds-util.h index e56292c795..b80755b7d7 100644 --- a/src/shared/creds-util.h +++ b/src/shared/creds-util.h @@ -93,3 +93,11 @@ int decrypt_credential_and_warn(const char *validate_name, usec_t validate_times int ipc_encrypt_credential(const char *name, usec_t timestamp, usec_t not_after, uid_t uid, const struct iovec *input, CredentialFlags flags, struct iovec *ret); int ipc_decrypt_credential(const char *validate_name, usec_t validate_timestamp, uid_t uid, const struct iovec *input, CredentialFlags flags, struct iovec *ret); + +typedef struct PickUpCredential { + const char *credential_prefix; + const char *target_dir; + const char *filename_suffix; +} PickUpCredential; + +int pick_up_credentials(const PickUpCredential *table, size_t n_table_entry); From b2800ec597a796b99508c1fbed51b55d17fa5229 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 5 Apr 2024 02:51:34 +0900 Subject: [PATCH 3/7] udevadm-control: check if control command really specified Previously, 'udevadm control' only checked the number of the arguments. So, if only `--timeout` is specified, it spuriously did nothing and succeeded. This makes the command request at least one control command. --- src/udev/udevadm-control.c | 19 +++++++++++++++---- test/units/testsuite-17.10.sh | 3 +-- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/udev/udevadm-control.c b/src/udev/udevadm-control.c index b8215ddd1f..530dca8a5f 100644 --- a/src/udev/udevadm-control.c +++ b/src/udev/udevadm-control.c @@ -29,6 +29,17 @@ static int arg_start_exec_queue = -1; STATIC_DESTRUCTOR_REGISTER(arg_env, strv_freep); +static bool arg_has_control_commands(void) { + return + arg_exit || + arg_log_level >= 0 || + arg_start_exec_queue >= 0 || + arg_reload || + !strv_isempty(arg_env) || + arg_max_children >= 0 || + arg_ping; +} + static int help(void) { printf("%s control OPTION\n\n" "Control the udev daemon.\n\n" @@ -76,10 +87,6 @@ static int parse_argv(int argc, char *argv[]) { assert(argc >= 0); assert(argv); - if (argc <= 1) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "This command expects one or more options."); - while ((c = getopt_long(argc, argv, "el:sSRp:m:t:Vh", options, NULL)) >= 0) switch (c) { @@ -147,6 +154,10 @@ static int parse_argv(int argc, char *argv[]) { assert_not_reached(); } + if (!arg_has_control_commands()) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "No control command option is specified."); + if (optind < argc) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Extraneous argument: %s", argv[optind]); diff --git a/test/units/testsuite-17.10.sh b/test/units/testsuite-17.10.sh index f229dcf25f..f643b0d6b4 100755 --- a/test/units/testsuite-17.10.sh +++ b/test/units/testsuite-17.10.sh @@ -45,8 +45,7 @@ udevadm control -S udevadm control -R udevadm control -p HELLO=world udevadm control -m 42 -udevadm control --ping -udevadm control -t 5 +udevadm control --ping -t 5 udevadm control -h udevadm info /dev/null From 7b3048358b79f1eb7485c0c926cd32edc4ba8aa7 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 5 Apr 2024 05:09:19 +0900 Subject: [PATCH 4/7] udevadm-control: split out send_control_commands() No functional change, just refactoring and preparation for later commits. --- src/udev/udevadm-control.c | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/src/udev/udevadm-control.c b/src/udev/udevadm-control.c index 530dca8a5f..428d590413 100644 --- a/src/udev/udevadm-control.c +++ b/src/udev/udevadm-control.c @@ -165,19 +165,10 @@ static int parse_argv(int argc, char *argv[]) { return 1; } -int control_main(int argc, char *argv[], void *userdata) { +static int send_control_commands(void) { _cleanup_(udev_ctrl_unrefp) UdevCtrl *uctrl = NULL; int r; - if (running_in_chroot() > 0) { - log_info("Running in chroot, ignoring request."); - return 0; - } - - r = parse_argv(argc, argv); - if (r <= 0) - return r; - r = udev_ctrl_new(&uctrl); if (r < 0) return log_error_errno(r, "Failed to initialize udev control: %m"); @@ -237,3 +228,24 @@ int control_main(int argc, char *argv[], void *userdata) { return 0; } + +int control_main(int argc, char *argv[], void *userdata) { + int r; + + if (running_in_chroot() > 0) { + log_info("Running in chroot, ignoring request."); + return 0; + } + + r = parse_argv(argc, argv); + if (r <= 0) + return r; + + if (arg_has_control_commands()) { + r = send_control_commands(); + if (r < 0) + return r; + } + + return 0; +} From 51be364bbb3199b48afc2433ccbb3ee0132465ac Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 5 Apr 2024 03:55:25 +0900 Subject: [PATCH 5/7] udevadm-control: add --load-credentials option When specified, credentials udev.conf.* and udev.rules.* are copied to the corresponding directories. --- man/udevadm.xml | 41 ++++++++++++++++++++++++++++++ src/udev/udevadm-control.c | 51 ++++++++++++++++++++++++++------------ 2 files changed, 76 insertions(+), 16 deletions(-) diff --git a/man/udevadm.xml b/man/udevadm.xml index 41c8ae7a12..b515f3c79c 100644 --- a/man/udevadm.xml +++ b/man/udevadm.xml @@ -727,6 +727,47 @@ + + + + When specified, the following credentials are used when passed in: + + + + udev.conf.* + + These credentials should contain valid + udev.conf5 + configuration data. From each matching credential a separate file is created. Example: a + passed credential udev.conf.50-foobar will be copied into a + configuration file /run/udev/udev.conf.d/50-foobar.conf. + + + + + + udev.rules.* + + These credentials should contain valid + udev7 + rules. From each matching credential a separate file is created. Example: a passed credential + udev.rules.50-foobar will be copied into a configuration file + /run/udev/rules.d/50-foobar.rules. + + + + + + + Note, this does not imply option. So, if + systemd-udevd is already running, please consider to also specify + to make the copied udev rules files used by + systemd-udevd. + + + + + diff --git a/src/udev/udevadm-control.c b/src/udev/udevadm-control.c index 428d590413..29dc88330c 100644 --- a/src/udev/udevadm-control.c +++ b/src/udev/udevadm-control.c @@ -8,6 +8,7 @@ #include #include +#include "creds-util.h" #include "parse-util.h" #include "process-util.h" #include "static-destruct.h" @@ -26,6 +27,7 @@ static bool arg_exit = false; static int arg_max_children = -1; static int arg_log_level = -1; static int arg_start_exec_queue = -1; +static bool arg_load_credentials = false; STATIC_DESTRUCTOR_REGISTER(arg_env, strv_freep); @@ -53,7 +55,8 @@ static int help(void) { " -p --property=KEY=VALUE Set a global property for all events\n" " -m --children-max=N Maximum number of children\n" " --ping Wait for udev to respond to a ping message\n" - " -t --timeout=SECONDS Maximum time to block for a reply\n", + " -t --timeout=SECONDS Maximum time to block for a reply\n" + " --load-credentials Load udev rules from credentials\n", program_invocation_short_name); return 0; @@ -62,23 +65,25 @@ static int help(void) { static int parse_argv(int argc, char *argv[]) { enum { ARG_PING = 0x100, + ARG_LOAD_CREDENTIALS, }; static const struct option options[] = { - { "exit", no_argument, NULL, 'e' }, - { "log-level", required_argument, NULL, 'l' }, - { "log-priority", required_argument, NULL, 'l' }, /* for backward compatibility */ - { "stop-exec-queue", no_argument, NULL, 's' }, - { "start-exec-queue", no_argument, NULL, 'S' }, - { "reload", no_argument, NULL, 'R' }, - { "reload-rules", no_argument, NULL, 'R' }, /* alias for -R */ - { "property", required_argument, NULL, 'p' }, - { "env", required_argument, NULL, 'p' }, /* alias for -p */ - { "children-max", required_argument, NULL, 'm' }, - { "ping", no_argument, NULL, ARG_PING }, - { "timeout", required_argument, NULL, 't' }, - { "version", no_argument, NULL, 'V' }, - { "help", no_argument, NULL, 'h' }, + { "exit", no_argument, NULL, 'e' }, + { "log-level", required_argument, NULL, 'l' }, + { "log-priority", required_argument, NULL, 'l' }, /* for backward compatibility */ + { "stop-exec-queue", no_argument, NULL, 's' }, + { "start-exec-queue", no_argument, NULL, 'S' }, + { "reload", no_argument, NULL, 'R' }, + { "reload-rules", no_argument, NULL, 'R' }, /* alias for -R */ + { "property", required_argument, NULL, 'p' }, + { "env", required_argument, NULL, 'p' }, /* alias for -p */ + { "children-max", required_argument, NULL, 'm' }, + { "ping", no_argument, NULL, ARG_PING }, + { "timeout", required_argument, NULL, 't' }, + { "load-credentials", no_argument, NULL, ARG_LOAD_CREDENTIALS }, + { "version", no_argument, NULL, 'V' }, + { "help", no_argument, NULL, 'h' }, {} }; @@ -141,6 +146,10 @@ static int parse_argv(int argc, char *argv[]) { return log_error_errno(r, "Failed to parse timeout value '%s': %m", optarg); break; + case ARG_LOAD_CREDENTIALS: + arg_load_credentials = true; + break; + case 'V': return print_version(); @@ -154,7 +163,7 @@ static int parse_argv(int argc, char *argv[]) { assert_not_reached(); } - if (!arg_has_control_commands()) + if (!arg_has_control_commands() && !arg_load_credentials) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No control command option is specified."); @@ -241,6 +250,16 @@ int control_main(int argc, char *argv[], void *userdata) { if (r <= 0) return r; + if (arg_load_credentials) { + static const PickUpCredential table[] = { + { "udev.conf.", "/run/udev/udev.conf.d/", ".conf" }, + { "udev.rules.", "/run/udev/rules.d/", ".rules" }, + }; + r = pick_up_credentials(table, ELEMENTSOF(table)); + if (r < 0) + return r; + } + if (arg_has_control_commands()) { r = send_control_commands(); if (r < 0) From 5700e755a909a7c22481b20ab8be1dc4fc6e3b65 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 5 Apr 2024 04:04:31 +0900 Subject: [PATCH 6/7] units: introduce systemd-udev-load-credentials.service --- man/systemd.system-credentials.xml | 25 ++++++++++++++++++ units/meson.build | 1 + units/systemd-udev-load-credentials.service | 29 +++++++++++++++++++++ units/systemd-udevd.service.in | 1 + 4 files changed, 56 insertions(+) create mode 100644 units/systemd-udev-load-credentials.service diff --git a/man/systemd.system-credentials.xml b/man/systemd.system-credentials.xml index b0fb70c6c5..271c495d2a 100644 --- a/man/systemd.system-credentials.xml +++ b/man/systemd.system-credentials.xml @@ -377,6 +377,31 @@ + + + udev.conf.* + udev.rules.* + + + Configures udev configuration file and udev rules. Read by + systemd-udev-load-credentials.service, which invokes + udevadm control --load-credentials. These credentials directly translate to a + matching + udev.conf5 or + udev7 rules + file. Example: the contents of a credential + udev.conf.50-foobar will be copied into a file + /run/udev/udev.conf.d/50-foobar.conf, and + udev.rules.50-foobar will be copied into a file + /run/udev/rules.d/50-foobar.rules. See + udev7, + udev.conf5, and + udevadm8 + for details. + + + + diff --git a/units/meson.build b/units/meson.build index 2f972901d4..5b2410fe93 100644 --- a/units/meson.build +++ b/units/meson.build @@ -688,6 +688,7 @@ units = [ 'conditions' : ['ENABLE_TMPFILES'], 'symlinks' : ['sysinit.target.wants/'], }, + { 'file' : 'systemd-udev-load-credentials.service' }, { 'file' : 'systemd-udev-settle.service' }, { 'file' : 'systemd-udev-trigger.service', diff --git a/units/systemd-udev-load-credentials.service b/units/systemd-udev-load-credentials.service new file mode 100644 index 0000000000..70f69dcf24 --- /dev/null +++ b/units/systemd-udev-load-credentials.service @@ -0,0 +1,29 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. + +[Unit] +Description=Load udev Rules from Credentials +Documentation=man:udevadm(8) +Documentation=man:udev(7) +Documentation=man:systemd.system-credentials(7) + +DefaultDependencies=no +Before=systemd-udevd.service +Conflicts=shutdown.target initrd-switch-root.target +Before=shutdown.target initrd-switch-root.target + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=udevadm control --load-credentials +ImportCredential=udev.conf.* +ImportCredential=udev.rules.* + +[Install] +WantedBy=sysinit.target diff --git a/units/systemd-udevd.service.in b/units/systemd-udevd.service.in index b59fdef9b0..f4a4482088 100644 --- a/units/systemd-udevd.service.in +++ b/units/systemd-udevd.service.in @@ -13,6 +13,7 @@ Documentation=man:systemd-udevd.service(8) man:udev(7) DefaultDependencies=no After=systemd-sysusers.service systemd-hwdb-update.service Before=sysinit.target +Wants=systemd-udev-load-credentials.service ConditionPathIsReadWrite=/sys [Service] From a3e4edd1af817625bdc598a2beb3fea2a84e2d5f Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 5 Apr 2024 04:14:19 +0900 Subject: [PATCH 7/7] test: add test for systemd-udev-load-credentials.service --- test/units/testsuite-17.10.sh | 1 + test/units/testsuite-17.credentials.sh | 33 ++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100755 test/units/testsuite-17.credentials.sh diff --git a/test/units/testsuite-17.10.sh b/test/units/testsuite-17.10.sh index f643b0d6b4..a2b8b14d0c 100755 --- a/test/units/testsuite-17.10.sh +++ b/test/units/testsuite-17.10.sh @@ -46,6 +46,7 @@ udevadm control -R udevadm control -p HELLO=world udevadm control -m 42 udevadm control --ping -t 5 +udevadm control --load-credentials udevadm control -h udevadm info /dev/null diff --git a/test/units/testsuite-17.credentials.sh b/test/units/testsuite-17.credentials.sh new file mode 100755 index 0000000000..cbdc57037e --- /dev/null +++ b/test/units/testsuite-17.credentials.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later +# shellcheck disable=SC2016 +set -eux +set -o pipefail + +at_exit() { + rm -f /run/credstore/udev.* + rm -f /run/udev/udev.conf.d/* + rm -f /run/udev/rules.d/* + rm -rf /run/systemd/system/systemd-udev-load-credentials.service.d +} + +trap at_exit EXIT + +mkdir -p /run/credstore +cat > /run/credstore/udev.conf.50-testme < /run/credstore/udev.rules.50-testme <