Merge pull request #32103 from yuwata/udev-load-credentials
udev: load udev rules from credentials
This commit is contained in:
@@ -377,6 +377,31 @@
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v256"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>udev.conf.*</varname></term>
|
||||
<term><varname>udev.rules.*</varname></term>
|
||||
|
||||
<listitem>
|
||||
<para>Configures udev configuration file and udev rules. Read by
|
||||
<filename>systemd-udev-load-credentials.service</filename>, which invokes
|
||||
<command>udevadm control --load-credentials</command>. These credentials directly translate to a
|
||||
matching
|
||||
<citerefentry><refentrytitle>udev.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry> or
|
||||
<citerefentry><refentrytitle>udev</refentrytitle><manvolnum>7</manvolnum></citerefentry> rules
|
||||
file. Example: the contents of a credential
|
||||
<filename>udev.conf.50-foobar</filename> will be copied into a file
|
||||
<filename>/run/udev/udev.conf.d/50-foobar.conf</filename>, and
|
||||
<filename>udev.rules.50-foobar</filename> will be copied into a file
|
||||
<filename>/run/udev/rules.d/50-foobar.rules</filename>. See
|
||||
<citerefentry><refentrytitle>udev</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>udev.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>, and
|
||||
<citerefentry><refentrytitle>udevadm</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
for details.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v256"/>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
|
||||
@@ -727,6 +727,47 @@
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--load-credentials</option></term>
|
||||
<listitem>
|
||||
<para>When specified, the following credentials are used when passed in:</para>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><varname>udev.conf.*</varname></term>
|
||||
<listitem>
|
||||
<para>These credentials should contain valid
|
||||
<citerefentry><refentrytitle>udev.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
|
||||
configuration data. From each matching credential a separate file is created. Example: a
|
||||
passed credential <filename>udev.conf.50-foobar</filename> will be copied into a
|
||||
configuration file <filename>/run/udev/udev.conf.d/50-foobar.conf</filename>.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v256"/>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>udev.rules.*</varname></term>
|
||||
<listitem>
|
||||
<para>These credentials should contain valid
|
||||
<citerefentry><refentrytitle>udev</refentrytitle><manvolnum>7</manvolnum></citerefentry>
|
||||
rules. From each matching credential a separate file is created. Example: a passed credential
|
||||
<filename>udev.rules.50-foobar</filename> will be copied into a configuration file
|
||||
<filename>/run/udev/rules.d/50-foobar.rules</filename>.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v256"/>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
<para>Note, this <emphasis>does not</emphasis> imply <option>--reload</option> option. So, if
|
||||
<command>systemd-udevd</command> is already running, please consider to also specify
|
||||
<option>-reload</option> to make the copied udev rules files used by
|
||||
<command>systemd-udevd</command>.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v256"/>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<xi:include href="standard-options.xml" xpointer="help" />
|
||||
</variablelist>
|
||||
</refsect2>
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include <getopt.h>
|
||||
|
||||
#include "build.h"
|
||||
#include "copy.h"
|
||||
#include "creds-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "fs-util.h"
|
||||
@@ -14,9 +13,8 @@
|
||||
#include "network-generator.h"
|
||||
#include "path-util.h"
|
||||
#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 +123,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));
|
||||
@@ -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(NETWORKD_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;
|
||||
}
|
||||
|
||||
+90
-1
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
+71
-29
@@ -8,6 +8,7 @@
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "creds-util.h"
|
||||
#include "parse-util.h"
|
||||
#include "process-util.h"
|
||||
#include "static-destruct.h"
|
||||
@@ -26,9 +27,21 @@ 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);
|
||||
|
||||
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"
|
||||
@@ -42,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;
|
||||
@@ -51,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' },
|
||||
{}
|
||||
};
|
||||
|
||||
@@ -76,10 +92,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) {
|
||||
|
||||
@@ -134,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();
|
||||
|
||||
@@ -147,6 +163,10 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
assert_not_reached();
|
||||
}
|
||||
|
||||
if (!arg_has_control_commands() && !arg_load_credentials)
|
||||
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]);
|
||||
@@ -154,19 +174,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");
|
||||
@@ -226,3 +237,34 @@ 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_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)
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -45,8 +45,8 @@ 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 --load-credentials
|
||||
udevadm control -h
|
||||
|
||||
udevadm info /dev/null
|
||||
|
||||
Executable
+33
@@ -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 <<EOF
|
||||
udev_log=debug
|
||||
EOF
|
||||
cat > /run/credstore/udev.rules.50-testme <<EOF
|
||||
SUBSYSTEM=="net", OPTIONS="log_level=debug"
|
||||
EOF
|
||||
|
||||
systemctl edit systemd-udev-load-credentials.service --stdin --drop-in=50-testme.conf <<EOF
|
||||
[Service]
|
||||
LoadCredential=udev.conf.50-testme
|
||||
LoadCredential=udev.rules.50-testme
|
||||
EOF
|
||||
|
||||
systemctl restart systemd-udev-load-credentials.service
|
||||
|
||||
diff /run/credstore/udev.conf.50-testme /run/udev/udev.conf.d/50-testme.conf
|
||||
diff /run/credstore/udev.rules.50-testme /run/udev/rules.d/50-testme.rules
|
||||
@@ -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',
|
||||
|
||||
@@ -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
|
||||
@@ -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]
|
||||
|
||||
Reference in New Issue
Block a user