1
0
mirror of https://github.com/systemd/systemd synced 2026-04-23 15:34:50 +02:00

Compare commits

..

No commits in common. "93efd9cadbc83d97bfff088eded925d736ea3f13" and "a321e0e4630518c547b42a1854d076a9fbe19a91" have entirely different histories.

20 changed files with 238 additions and 679 deletions

16
NEWS
View File

@ -656,13 +656,15 @@ CHANGES WITH 250:
may be used to set the boot menu time-out of the boot loader (for all may be used to set the boot menu time-out of the boot loader (for all
or just the subsequent boot). or just the subsequent boot).
* bootctl and kernel-install will now read variables * bootctl and kernel-install will now read KERNEL_INSTALL_MACHINE_ID
KERNEL_INSTALL_LAYOUT= from /etc/machine-info and layout= from and KERNEL_INSTALL_LAYOUT from kernel/install.conf. The first
/etc/kernel/install.conf. When set, it specifies the layout to use variable specifies the machine-id to use for installation. It would
for installation directories on the boot partition, so that tools previously be used if set in the environment, and now it'll also be
don't need to guess it based on the already-existing directories. The read automatically from the config file. The second variable is new.
only value that is defined natively is "bls", corresponding to the When set, it specifies the layout to use for installation directories
layout specified in on the boot partition, so that tools don't need to guess it based on
the already-existing directories. The only value that is defined
natively is "bls", corresponding to the layout specified in
https://systemd.io/BOOT_LOADER_SPECIFICATION/. Plugins for https://systemd.io/BOOT_LOADER_SPECIFICATION/. Plugins for
kernel-install that implement a different layout can declare other kernel-install that implement a different layout can declare other
values for this variable. values for this variable.

View File

@ -309,18 +309,6 @@ focus for this specification. More specifically, on non-EFI systems
configuration snippets following this specification cannot be used to spawn configuration snippets following this specification cannot be used to spawn
other operating systems (such as Windows). other operating systems (such as Windows).
Unfortunately, there are implementations of boot loading infrastructure that
are also using the /loader/entries/ directory, but place files in them that are
not valid by this specification. In order to minimize confusion a boot loader
implementation may place a file /loader/entries.srel next to the
/loader/entries/ directory containing the ASCII string "type1" (suffixed
with a UNIX newline). Tools that need to determine whether an existing
directory implements the semantics described here may check for this file and
contents: if it exists and contains the mentioned string, it shall assume a
standards compliant implementation is in place. If it exists but contains a
different string it shall assume non-standard semantics are implemented. If the
file does not exist no assumptions should be made.
### Type #2 EFI Unified Kernel Images ### Type #2 EFI Unified Kernel Images
A unified kernel image is a single EFI PE executable combining an EFI stub A unified kernel image is a single EFI PE executable combining an EFI stub

View File

@ -237,8 +237,9 @@
</variablelist> </variablelist>
<para><varname>$KERNEL_INSTALL_INITRD_GENERATOR</varname> is set for plugins to select the initrd <para><varname>$KERNEL_INSTALL_INITRD_GENERATOR</varname> is set for plugins to select the initrd
generator. This may be configured as <varname>initrd_generator=</varname> in generator. This should be configured as <varname>initrd_generator=</varname> in
<filename>install.conf</filename>. See below.</para> <filename>install.conf</filename>.
</para>
<para><varname>$KERNEL_INSTALL_STAGING_AREA</varname> is set for plugins to a path to a directory. <para><varname>$KERNEL_INSTALL_STAGING_AREA</varname> is set for plugins to a path to a directory.
Plugins may drop files in that directory, and they will be installed as part of the loader entry, based Plugins may drop files in that directory, and they will be installed as part of the loader entry, based
@ -324,10 +325,10 @@
<filename>/etc/kernel/install.conf</filename> <filename>/etc/kernel/install.conf</filename>
</term> </term>
<listitem> <listitem>
<para>Configuration options for <command>kernel-install</command>, as a series of <para>Configuration options for <command>kernel-install</command>,
<varname>KEY=</varname><replaceable>VALUE</replaceable> assignments, compatible with shell as a series of <varname>KEY=</varname><replaceable>VALUE</replaceable> assignments,
syntax. This currently supports two keys: <varname>layout=</varname> and compatible with shell syntax.
<varname>initrd_generator=</varname>, for details see the Environment variables section above.</para> See the Environment variables section for supported keys.</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
</variablelist> </variablelist>

View File

@ -23,7 +23,6 @@
<refsynopsisdiv> <refsynopsisdiv>
<para><filename><replaceable>ESP</replaceable>/loader/loader.conf</filename>, <para><filename><replaceable>ESP</replaceable>/loader/loader.conf</filename>,
<filename><replaceable>ESP</replaceable>/loader/entries/*.conf</filename> <filename><replaceable>ESP</replaceable>/loader/entries/*.conf</filename>
<filename><replaceable>XBOOTLDR</replaceable>/loader/entries/*.conf</filename>
</para> </para>
</refsynopsisdiv> </refsynopsisdiv>
@ -34,16 +33,13 @@
<citerefentry><refentrytitle>systemd-boot</refentrytitle><manvolnum>7</manvolnum></citerefentry> will <citerefentry><refentrytitle>systemd-boot</refentrytitle><manvolnum>7</manvolnum></citerefentry> will
read <filename><replaceable>ESP</replaceable>/loader/loader.conf</filename>, and any files with the read <filename><replaceable>ESP</replaceable>/loader/loader.conf</filename>, and any files with the
<literal>.conf</literal> extension under <literal>.conf</literal> extension under
<filename><replaceable>ESP</replaceable>/loader/entries/</filename> on the EFI system partition (ESP), <filename><replaceable>ESP</replaceable>/loader/entries/</filename> on the EFI system partition (ESP) as
and <filename><replaceable>XBOOTLDR</replaceable>/loader/entries/</filename> on the extended boot loader defined by <ulink url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot Loader Specification</ulink>.
partition (XBOOTLDR) as defined by <ulink url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot Loader
Specification</ulink>.
</para> </para>
<para>Each of these configuration files must consist of series of newline (i.e. ASCII code 10) separated <para>Each configuration file must consist of an option name, followed by
lines, each consisting of an option name, followed by whitespace, and the option whitespace, and the option value. <literal>#</literal> may be used to start
value. <literal>#</literal> may be used to start a comment line. Empty and comment lines are ignored. The a comment line. Empty and comment lines are ignored.</para>
files use UTF-8 encoding.</para>
<para>Boolean arguments may be written as <para>Boolean arguments may be written as
<literal>yes</literal>/<literal>y</literal>/<literal>true</literal>/<literal>t</literal>/<literal>on</literal>/<literal>1</literal> or <literal>yes</literal>/<literal>y</literal>/<literal>true</literal>/<literal>t</literal>/<literal>on</literal>/<literal>1</literal> or
@ -54,14 +50,7 @@
<refsect1> <refsect1>
<title>Options</title> <title>Options</title>
<para>The configuration options supported by <para>The following configuration options in <filename>loader.conf</filename> are understood:</para>
<filename><replaceable>ESP</replaceable>/loader/entries/*.conf</filename> and
<filename><replaceable>XBOOTLDR</replaceable>/loader/entries/*.conf</filename> files are defined as part
of the <ulink url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot Loader
Specification</ulink>.</para>
<para>The following configuration are supported by the <filename>loader.conf</filename> configuration
file:</para>
<variablelist> <variablelist>
<varlistentry> <varlistentry>

View File

@ -971,7 +971,7 @@ manpages = [
['systemd-stdio-bridge', '1', [], ''], ['systemd-stdio-bridge', '1', [], ''],
['systemd-stub', ['systemd-stub',
'7', '7',
['linuxaa64.efi.stub', 'linuxia32.efi.stub', 'linuxx64.efi.stub', 'sd-stub'], ['linuxaa64.efi.stub', 'linuxia32.efi.stub', 'linuxx64.efi.stub'],
'HAVE_GNU_EFI'], 'HAVE_GNU_EFI'],
['systemd-suspend.service', ['systemd-suspend.service',
'8', '8',

View File

@ -30,12 +30,12 @@
<para><command>systemd-boot</command> loads boot entry information from the EFI system partition (ESP), <para><command>systemd-boot</command> loads boot entry information from the EFI system partition (ESP),
usually mounted at <filename>/efi/</filename>, <filename>/boot/</filename>, or usually mounted at <filename>/efi/</filename>, <filename>/boot/</filename>, or
<filename>/boot/efi/</filename> during OS runtime, as well as from the Extended Boot Loader partition <filename>/boot/efi/</filename> during OS runtime, as well as from the Extended Boot Loader partition if
(XBOOTLDR) if it exists (usually mounted to <filename>/boot/</filename>). Configuration file fragments, it exists (usually mounted to <filename>/boot/</filename>). Configuration file fragments, kernels,
kernels, initrds and other EFI images to boot generally need to reside on the ESP or the Extended Boot initrds and other EFI images to boot generally need to reside on the ESP or the Extended Boot Loader
Loader partition. Linux kernels must be built with <option>CONFIG_EFI_STUB</option> to be able to be partition. Linux kernels must be built with <option>CONFIG_EFI_STUB</option> to be able to be directly
directly executed as an EFI image. During boot <command>systemd-boot</command> automatically assembles a executed as an EFI image. During boot <command>systemd-boot</command> automatically assembles a list of
list of boot entries from the following sources:</para> boot entries from the following sources:</para>
<itemizedlist> <itemizedlist>
<listitem><para>Boot entries defined with <ulink <listitem><para>Boot entries defined with <ulink

View File

@ -17,7 +17,6 @@
<refnamediv> <refnamediv>
<refname>systemd-stub</refname> <refname>systemd-stub</refname>
<refname>sd-stub</refname>
<refname>linuxx64.efi.stub</refname> <refname>linuxx64.efi.stub</refname>
<refname>linuxia32.efi.stub</refname> <refname>linuxia32.efi.stub</refname>
<refname>linuxaa64.efi.stub</refname> <refname>linuxaa64.efi.stub</refname>

View File

@ -280,9 +280,9 @@
<term><option>-t</option></term> <term><option>-t</option></term>
<term><option>--type=<replaceable>TYPE</replaceable></option></term> <term><option>--type=<replaceable>TYPE</replaceable></option></term>
<listitem> <listitem>
<para>Trigger a specific type of devices. Valid types are <literal>all</literal>, <para>Trigger a specific type of devices. Valid types are:
<literal>devices</literal>, and <literal>subsystems</literal>. The default value is <command>devices</command>, <command>subsystems</command>.
<literal>devices</literal>.</para> The default value is <command>devices</command>.</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
@ -297,19 +297,6 @@
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><option>--prioritized-subsystem=<replaceable>SUBSYSTEM<optional>,<replaceable>SUBSYSTEM</replaceable></optional></replaceable></option></term>
<listitem>
<para>Takes a comma separated list of subsystems. When triggering events for devices, the
devices from the specified subsystems and their parents are triggered first. For example,
if <option>--prioritized-subsystem=block,net</option>, then firstly all block devices and
their parents are triggered, in the next all network devices and their parents are
triggered, and lastly the other devices are triggered. This option can be specified
multiple times, and in that case the lists of the subsystems will be merged. That is,
<option>--prioritized-subsystem=block --prioritized-subsystem=net</option> is equivalent to
<option>--prioritized-subsystem=block,net</option>.</para>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><option>-s</option></term> <term><option>-s</option></term>
<term><option>--subsystem-match=<replaceable>SUBSYSTEM</replaceable></option></term> <term><option>--subsystem-match=<replaceable>SUBSYSTEM</replaceable></option></term>
@ -395,35 +382,6 @@
then each matching result is ORed, that is, all children of each specified device are triggered.</para> then each matching result is ORed, that is, all children of each specified device are triggered.</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><option>--initialized-match</option></term>
<term><option>--initialized-nomatch</option></term>
<listitem>
<para>When <option>--initialized-match</option> is specified, trigger events for devices
that are already initialized by <command>systemd-udevd</command>, and skip devices that
are not initialized yet.</para>
<para>When <option>--initialized-nomatch</option> is specified, trigger events for devices
that are not initialized by <command>systemd-udevd</command> yet, and skip devices that
are already initialized.</para>
<para>Here, initialized devices are those for which at least one udev rule already
completed execution for any action but <literal>remove</literal> — that set a property
or other device setting (and thus has an entry in the udev device database). Devices are
no longer considered initialized if a <literal>remove</literal> action is seen for them
(which removes their entry in the udev device database). Note that devices that have no
udev rules are never considered initialized, but might still be announced via the sd-device
API (or similar). Typically, it is thus essential that applications which intend to use
such a match, make sure a suitable udev rule is installed that sets at least one property
on devices that shall be matched.</para>
<para>WARNING: <option>--initialized-nomatch</option> can potentially save a significant
amount of time compared to re-triggering all devices in the system and e.g. can be used to
optimize boot time. However, this is not safe to be used in a boot sequence in general.
Especially, when udev rules for a device depend on its parent devices (e.g.
<literal>ATTRS</literal> or <literal>IMPORT{parent}</literal> keys, see
<citerefentry><refentrytitle>udev</refentrytitle><manvolnum>7</manvolnum></citerefentry>
for more details), the final state of the device becomes easily unstable with this option.
</para>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><option>-w</option></term> <term><option>-w</option></term>
<term><option>--settle</option></term> <term><option>--settle</option></term>

View File

@ -51,12 +51,10 @@ _udevadm() {
[INFO_STANDALONE]='-r --root -a --attribute-walk -x --export -e --export-db -c --cleanup-db [INFO_STANDALONE]='-r --root -a --attribute-walk -x --export -e --export-db -c --cleanup-db
-w --wait-for-initialization --value' -w --wait-for-initialization --value'
[INFO_ARG]='-q --query -p --path -n --name -P --export-prefix -d --device-id-of-file --property' [INFO_ARG]='-q --query -p --path -n --name -P --export-prefix -d --device-id-of-file --property'
[TRIGGER_STANDALONE]='-v --verbose -n --dry-run -q --quiet -w --settle --wait-daemon --uuid [TRIGGER_STANDALONE]='-v --verbose -n --dry-run -q --quiet -w --settle --wait-daemon --uuid'
--initialized-match --initialized-nomatch'
[TRIGGER_ARG]='-t --type -c --action -s --subsystem-match -S --subsystem-nomatch [TRIGGER_ARG]='-t --type -c --action -s --subsystem-match -S --subsystem-nomatch
-a --attr-match -A --attr-nomatch -p --property-match -a --attr-match -A --attr-nomatch -p --property-match
-g --tag-match -y --sysname-match --name-match -b --parent-match -g --tag-match -y --sysname-match --name-match -b --parent-match'
--prioritized-subsystem'
[SETTLE]='-t --timeout -E --exit-if-exists' [SETTLE]='-t --timeout -E --exit-if-exists'
[CONTROL_STANDALONE]='-e --exit -s --stop-exec-queue -S --start-exec-queue -R --reload --ping' [CONTROL_STANDALONE]='-e --exit -s --stop-exec-queue -S --start-exec-queue -R --reload --ping'
[CONTROL_ARG]='-l --log-priority -p --property -m --children-max -t --timeout' [CONTROL_ARG]='-l --log-priority -p --property -m --children-max -t --timeout'
@ -119,7 +117,7 @@ _udevadm() {
if __contains_word "$prev" ${OPTS[TRIGGER_ARG]}; then if __contains_word "$prev" ${OPTS[TRIGGER_ARG]}; then
case $prev in case $prev in
-t|--type) -t|--type)
comps='all devices subsystems' comps='devices subsystems'
;; ;;
-c|--action) -c|--action)
comps=$( udevadm trigger --action help ) comps=$( udevadm trigger --action help )

View File

@ -24,7 +24,7 @@ _udevadm_trigger(){
'--verbose[Print the list of devices which will be triggered.]' \ '--verbose[Print the list of devices which will be triggered.]' \
'--dry-run[Do not actually trigger the event.]' \ '--dry-run[Do not actually trigger the event.]' \
'--quiet[Suppress error logging in triggering events.]' \ '--quiet[Suppress error logging in triggering events.]' \
'--type=[Trigger a specific type of devices.]:types:(all devices subsystems failed)' \ '--type=[Trigger a specific type of devices.]:types:(devices subsystems failed)' \
'--action=[Type of event to be triggered.]:actions:(add change remove move online offline bind unbind)' \ '--action=[Type of event to be triggered.]:actions:(add change remove move online offline bind unbind)' \
'--subsystem-match=[Trigger events for devices which belong to a matching subsystem.]' \ '--subsystem-match=[Trigger events for devices which belong to a matching subsystem.]' \
'--subsystem-nomatch=[Do not trigger events for devices which belong to a matching subsystem.]' \ '--subsystem-nomatch=[Do not trigger events for devices which belong to a matching subsystem.]' \
@ -34,10 +34,7 @@ _udevadm_trigger(){
'--tag-match=property[Trigger events for devices with a matching tag.]' \ '--tag-match=property[Trigger events for devices with a matching tag.]' \
'--sysname-match=[Trigger events for devices with a matching sys device name.]' \ '--sysname-match=[Trigger events for devices with a matching sys device name.]' \
'--parent-match=[Trigger events for all children of a given device.]' \ '--parent-match=[Trigger events for all children of a given device.]' \
'--initialized-match[Trigger events for devices that are already initialized.]' \ '--uuid[Print synthetic uevent UUID.]'
'--initialized-nomatch[Trigger events for devices that are not initialized yet.]' \
'--uuid[Print synthetic uevent UUID.]' \
'--prioritized-subsystem=[Trigger events for devices which belong to a matching subsystem earlier.]'
} }
(( $+functions[_udevadm_settle] )) || (( $+functions[_udevadm_settle] )) ||

View File

@ -28,7 +28,7 @@ static inline uint32_t random_u32(void) {
} }
/* Some limits on the pool sizes when we deal with the kernel random pool */ /* Some limits on the pool sizes when we deal with the kernel random pool */
#define RANDOM_POOL_SIZE_MIN 32U #define RANDOM_POOL_SIZE_MIN 512U
#define RANDOM_POOL_SIZE_MAX (10U*1024U*1024U) #define RANDOM_POOL_SIZE_MAX (10U*1024U*1024U)
size_t random_pool_size(void); size_t random_pool_size(void);

View File

@ -275,28 +275,6 @@ int open_tmpfile_linkable(const char *target, int flags, char **ret_path) {
return fd; return fd;
} }
int fopen_tmpfile_linkable(const char *target, int flags, char **ret_path, FILE **ret_file) {
_cleanup_free_ char *path = NULL;
_cleanup_fclose_ FILE *f = NULL;
_cleanup_close_ int fd = -1;
assert(target);
assert(ret_file);
assert(ret_path);
fd = open_tmpfile_linkable(target, flags, &path);
if (fd < 0)
return fd;
f = take_fdopen(&fd, "w");
if (!f)
return -ENOMEM;
*ret_path = TAKE_PTR(path);
*ret_file = TAKE_PTR(f);
return 0;
}
int link_tmpfile(int fd, const char *path, const char *target) { int link_tmpfile(int fd, const char *path, const char *target) {
assert(fd >= 0); assert(fd >= 0);
assert(target); assert(target);
@ -314,23 +292,6 @@ int link_tmpfile(int fd, const char *path, const char *target) {
return RET_NERRNO(linkat(AT_FDCWD, FORMAT_PROC_FD_PATH(fd), AT_FDCWD, target, AT_SYMLINK_FOLLOW)); return RET_NERRNO(linkat(AT_FDCWD, FORMAT_PROC_FD_PATH(fd), AT_FDCWD, target, AT_SYMLINK_FOLLOW));
} }
int flink_tmpfile(FILE *f, const char *path, const char *target) {
int fd, r;
assert(f);
assert(target);
fd = fileno(f);
if (fd < 0) /* Not all FILE* objects encapsulate fds */
return -EBADF;
r = fflush_sync_and_check(f);
if (r < 0)
return r;
return link_tmpfile(fd, path, target);
}
int mkdtemp_malloc(const char *template, char **ret) { int mkdtemp_malloc(const char *template, char **ret) {
_cleanup_free_ char *p = NULL; _cleanup_free_ char *p = NULL;
int r; int r;

View File

@ -13,9 +13,7 @@ int tempfn_random_child(const char *p, const char *extra, char **ret);
int open_tmpfile_unlinkable(const char *directory, int flags); int open_tmpfile_unlinkable(const char *directory, int flags);
int open_tmpfile_linkable(const char *target, int flags, char **ret_path); int open_tmpfile_linkable(const char *target, int flags, char **ret_path);
int fopen_tmpfile_linkable(const char *target, int flags, char **ret_path, FILE **ret_file);
int link_tmpfile(int fd, const char *path, const char *target); int link_tmpfile(int fd, const char *path, const char *target);
int flink_tmpfile(FILE *f, const char *path, const char *target);
int mkdtemp_malloc(const char *template, char **ret); int mkdtemp_malloc(const char *template, char **ret);

View File

@ -144,70 +144,38 @@ static int acquire_xbootldr(
return 1; return 1;
} }
static int load_etc_machine_id(void) { static int load_install_machine_id_and_layout(void) {
int r; /* Figure out the right machine-id for operations. If KERNEL_INSTALL_MACHINE_ID is configured in
* /etc/machine-info, let's use that. Otherwise, just use the real machine-id.
r = sd_id128_get_machine(&arg_machine_id); *
if (IN_SET(r, -ENOENT, -ENOMEDIUM)) /* Not set or empty */ * Also load KERNEL_INSTALL_LAYOUT.
return 0; */
if (r < 0)
return log_error_errno(r, "Failed to get machine-id: %m");
log_debug("Loaded machine ID %s from /etc/machine-id.", SD_ID128_TO_STRING(arg_machine_id));
return 0;
}
static int load_etc_machine_info(void) {
/* systemd v250 added support to store the kernel-install layout setting and the machine ID to use
* for setting up the ESP in /etc/machine-info. The newer /etc/kernel/entry-token file, as well as
* the $layout field in /etc/kernel/install.conf are better replacements for this though, hence this
* has been deprecated and is only returned for compatibility. */
_cleanup_free_ char *s = NULL, *layout = NULL; _cleanup_free_ char *s = NULL, *layout = NULL;
int r; int r;
r = parse_env_file(NULL, "/etc/machine-info", r = parse_env_file(NULL, "/etc/machine-info",
"KERNEL_INSTALL_LAYOUT", &layout, "KERNEL_INSTALL_LAYOUT", &layout,
"KERNEL_INSTALL_MACHINE_ID", &s); "KERNEL_INSTALL_MACHINE_ID", &s);
if (r == -ENOENT) if (r < 0 && r != -ENOENT)
return 0;
if (r < 0)
return log_error_errno(r, "Failed to parse /etc/machine-info: %m"); return log_error_errno(r, "Failed to parse /etc/machine-info: %m");
if (!isempty(s)) { if (isempty(s)) {
log_notice("Read $KERNEL_INSTALL_MACHINE_ID from /etc/machine-info. Please move it to /etc/kernel/entry-token."); r = sd_id128_get_machine(&arg_machine_id);
if (r < 0 && !IN_SET(r, -ENOENT, -ENOMEDIUM))
return log_error_errno(r, "Failed to get machine-id: %m");
} else {
r = sd_id128_from_string(s, &arg_machine_id); r = sd_id128_from_string(s, &arg_machine_id);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to parse KERNEL_INSTALL_MACHINE_ID=%s in /etc/machine-info: %m", s); return log_error_errno(r, "Failed to parse KERNEL_INSTALL_MACHINE_ID=%s in /etc/machine-info: %m", s);
log_debug("Loaded KERNEL_INSTALL_MACHINE_ID=%s from KERNEL_INSTALL_MACHINE_ID in /etc/machine-info.",
SD_ID128_TO_STRING(arg_machine_id));
} }
log_debug("Using KERNEL_INSTALL_MACHINE_ID=%s from %s.",
SD_ID128_TO_STRING(arg_machine_id),
isempty(s) ? "/etc/machine_id" : "KERNEL_INSTALL_MACHINE_ID in /etc/machine-info");
if (!isempty(layout)) { if (!isempty(layout)) {
log_notice("Read $KERNEL_INSTALL_LAYOUT from /etc/machine-info. Please move it to the layout= setting of /etc/kernel/install.conf.");
log_debug("KERNEL_INSTALL_LAYOUT=%s is specified in /etc/machine-info.", layout); log_debug("KERNEL_INSTALL_LAYOUT=%s is specified in /etc/machine-info.", layout);
free_and_replace(arg_install_layout, layout); arg_install_layout = TAKE_PTR(layout);
}
return 0;
}
static int load_etc_kernel_install_conf(void) {
_cleanup_free_ char *layout = NULL;
int r;
r = parse_env_file(NULL, "/etc/kernel/install.conf",
"layout", &layout);
if (r == -ENOENT)
return 0;
if (r < 0)
return log_error_errno(r, "Failed to parse /etc/kernel/install.conf: %m");
if (!isempty(layout)) {
log_debug("layout=%s is specified in /etc/machine-info.", layout);
free_and_replace(arg_install_layout, layout);
} }
return 0; return 0;
@ -314,15 +282,7 @@ static bool use_boot_loader_spec_type1(void) {
static int settle_make_entry_directory(void) { static int settle_make_entry_directory(void) {
int r; int r;
r = load_etc_machine_id(); r = load_install_machine_id_and_layout();
if (r < 0)
return r;
r = load_etc_machine_info();
if (r < 0)
return r;
r = load_etc_kernel_install_conf();
if (r < 0) if (r < 0)
return r; return r;
@ -1286,6 +1246,7 @@ static int remove_loader_variables(void) {
static int install_loader_config(const char *esp_path) { static int install_loader_config(const char *esp_path) {
_cleanup_(unlink_and_freep) char *t = NULL; _cleanup_(unlink_and_freep) char *t = NULL;
_cleanup_fclose_ FILE *f = NULL; _cleanup_fclose_ FILE *f = NULL;
_cleanup_close_ int fd = -1;
const char *p; const char *p;
int r; int r;
@ -1295,9 +1256,13 @@ static int install_loader_config(const char *esp_path) {
if (access(p, F_OK) >= 0) /* Silently skip creation if the file already exists (early check) */ if (access(p, F_OK) >= 0) /* Silently skip creation if the file already exists (early check) */
return 0; return 0;
r = fopen_tmpfile_linkable(p, O_WRONLY|O_CLOEXEC, &t, &f); fd = open_tmpfile_linkable(p, O_WRONLY|O_CLOEXEC, &t);
if (r < 0) if (fd < 0)
return log_error_errno(r, "Failed to open \"%s\" for writing: %m", p); return log_error_errno(fd, "Failed to open \"%s\" for writing: %m", p);
f = take_fdopen(&fd, "w");
if (!f)
return log_oom();
fprintf(f, "#timeout 3\n" fprintf(f, "#timeout 3\n"
"#console-mode keep\n"); "#console-mode keep\n");
@ -1307,36 +1272,11 @@ static int install_loader_config(const char *esp_path) {
fprintf(f, "default %s-*\n", arg_entry_token); fprintf(f, "default %s-*\n", arg_entry_token);
} }
r = flink_tmpfile(f, t, p); r = fflush_sync_and_check(f);
if (r == -EEXIST)
return 0; /* Silently skip creation if the file exists now (recheck) */
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to move \"%s\" into place: %m", p); return log_error_errno(r, "Failed to write \"%s\": %m", p);
t = mfree(t); r = link_tmpfile(fileno(f), t, p);
return 1;
}
static int install_loader_specification(const char *root) {
_cleanup_(unlink_and_freep) char *t = NULL;
_cleanup_fclose_ FILE *f = NULL;
_cleanup_free_ char *p = NULL;
int r;
p = path_join(root, "/loader/entries.srel");
if (!p)
return log_oom();
if (access(p, F_OK) >= 0) /* Silently skip creation if the file already exists (early check) */
return 0;
r = fopen_tmpfile_linkable(p, O_WRONLY|O_CLOEXEC, &t, &f);
if (r < 0)
return log_error_errno(r, "Failed to open \"%s\" for writing: %m", p);
fprintf(f, "type1\n");
r = flink_tmpfile(f, t, p);
if (r == -EEXIST) if (r == -EEXIST)
return 0; /* Silently skip creation if the file exists now (recheck) */ return 0; /* Silently skip creation if the file exists now (recheck) */
if (r < 0) if (r < 0)
@ -2058,10 +1998,6 @@ static int verb_install(int argc, char *argv[], void *userdata) {
if (r < 0) if (r < 0)
return r; return r;
} }
r = install_loader_specification(arg_dollar_boot_path());
if (r < 0)
return r;
} }
(void) sync_everything(); (void) sync_everything();
@ -2101,10 +2037,6 @@ static int verb_remove(int argc, char *argv[], void *userdata) {
if (q < 0 && r >= 0) if (q < 0 && r >= 0)
r = q; r = q;
q = remove_file(arg_esp_path, "/loader/entries.srel");
if (q < 0 && r >= 0)
r = q;
q = remove_subdirs(arg_esp_path, esp_subdirs); q = remove_subdirs(arg_esp_path, esp_subdirs);
if (q < 0 && r >= 0) if (q < 0 && r >= 0)
r = q; r = q;
@ -2118,12 +2050,7 @@ static int verb_remove(int argc, char *argv[], void *userdata) {
r = q; r = q;
if (arg_xbootldr_path) { if (arg_xbootldr_path) {
/* Remove a subset of these also from the XBOOTLDR partition if it exists */ /* Remove the latter two also in the XBOOTLDR partition if it exists */
q = remove_file(arg_xbootldr_path, "/loader/entries.srel");
if (q < 0 && r >= 0)
r = q;
q = remove_subdirs(arg_xbootldr_path, dollar_boot_subdirs); q = remove_subdirs(arg_xbootldr_path, dollar_boot_subdirs);
if (q < 0 && r >= 0) if (q < 0 && r >= 0)
r = q; r = q;

View File

@ -155,29 +155,10 @@ done
[ -z "$ENTRY_TOKEN" ] && ENTRY_TOKEN="$MACHINE_ID" [ -z "$ENTRY_TOKEN" ] && ENTRY_TOKEN="$MACHINE_ID"
if [ -z "$layout" ]; then if [ -z "$layout" ]; then
# No layout configured by the administrator. Let's try to figure it out # Administrative decision: if not present, some scripts generate into /boot.
# automatically from metadata already contained in $BOOT_ROOT. if [ -d "$BOOT_ROOT/$ENTRY_TOKEN" ]; then
if [ -e "$BOOT_ROOT/loader/entries.srel" ]; then
read -r ENTRIES_SREL <"$BOOT_ROOT/loader/entries.srel"
if [ "$ENTRIES_SREL" = "type1" ]; then
# The loader/entries.srel file clearly indicates that the installed
# boot loader implements the proper standard upstream boot loader
# spec for Type #1 entries. Let's default to that, then.
layout="bls" layout="bls"
else else
# The loader/entries.srel file indicates some other spec is
# implemented and owns the /loader/entries/ directory. Since we
# have no idea what that means, let's stay away from it by default.
layout="other"
fi
elif [ -d "$BOOT_ROOT/$ENTRY_TOKEN" ]; then
# If the metadata in $BOOT_ROOT doesn't tell us anything, then check if
# the entry token directory already exists. If so, let's assume it's
# the standard boot loader spec, too.
layout="bls"
else
# There's no metadata in $BOOT_ROOT, and apparently no entry token
# directory installed? Then we really don't know anything.
layout="other" layout="other"
fi fi
fi fi

View File

@ -3,22 +3,11 @@
#include "sd-device.h" #include "sd-device.h"
typedef enum MatchInitializedType {
MATCH_INITIALIZED_NO, /* only devices without a db entry */
MATCH_INITIALIZED_YES, /* only devices with a db entry */
MATCH_INITIALIZED_ALL, /* all devices */
MATCH_INITIALIZED_COMPAT, /* only devices that have no devnode/ifindex or have a db entry */
_MATCH_INITIALIZED_MAX,
_MATCH_INITIALIZED_INVALID = -EINVAL,
} MatchInitializedType;
int device_enumerator_scan_devices(sd_device_enumerator *enumeartor); int device_enumerator_scan_devices(sd_device_enumerator *enumeartor);
int device_enumerator_scan_subsystems(sd_device_enumerator *enumeartor); int device_enumerator_scan_subsystems(sd_device_enumerator *enumeartor);
int device_enumerator_scan_devices_and_subsystems(sd_device_enumerator *enumerator);
int device_enumerator_add_device(sd_device_enumerator *enumerator, sd_device *device); int device_enumerator_add_device(sd_device_enumerator *enumerator, sd_device *device);
int device_enumerator_add_match_is_initialized(sd_device_enumerator *enumerator, MatchInitializedType type); int device_enumerator_add_match_is_initialized(sd_device_enumerator *enumerator);
int device_enumerator_add_match_parent_incremental(sd_device_enumerator *enumerator, sd_device *parent); int device_enumerator_add_match_parent_incremental(sd_device_enumerator *enumerator, sd_device *parent);
int device_enumerator_add_prioritized_subsystem(sd_device_enumerator *enumerator, const char *subsystem);
sd_device *device_enumerator_get_first(sd_device_enumerator *enumerator); sd_device *device_enumerator_get_first(sd_device_enumerator *enumerator);
sd_device *device_enumerator_get_next(sd_device_enumerator *enumerator); sd_device *device_enumerator_get_next(sd_device_enumerator *enumerator);
sd_device **device_enumerator_get_devices(sd_device_enumerator *enumerator, size_t *ret_n_devices); sd_device **device_enumerator_get_devices(sd_device_enumerator *enumerator, size_t *ret_n_devices);

View File

@ -20,7 +20,6 @@
typedef enum DeviceEnumerationType { typedef enum DeviceEnumerationType {
DEVICE_ENUMERATION_TYPE_DEVICES, DEVICE_ENUMERATION_TYPE_DEVICES,
DEVICE_ENUMERATION_TYPE_SUBSYSTEMS, DEVICE_ENUMERATION_TYPE_SUBSYSTEMS,
DEVICE_ENUMERATION_TYPE_ALL,
_DEVICE_ENUMERATION_TYPE_MAX, _DEVICE_ENUMERATION_TYPE_MAX,
_DEVICE_ENUMERATION_TYPE_INVALID = -EINVAL, _DEVICE_ENUMERATION_TYPE_INVALID = -EINVAL,
} DeviceEnumerationType; } DeviceEnumerationType;
@ -29,13 +28,10 @@ struct sd_device_enumerator {
unsigned n_ref; unsigned n_ref;
DeviceEnumerationType type; DeviceEnumerationType type;
Hashmap *devices_by_syspath;
sd_device **devices; sd_device **devices;
size_t n_devices, current_device_index; size_t n_devices, current_device_index;
bool scan_uptodate; bool scan_uptodate;
bool sorted;
char **prioritized_subsystems;
Set *match_subsystem; Set *match_subsystem;
Set *nomatch_subsystem; Set *nomatch_subsystem;
Hashmap *match_sysattr; Hashmap *match_sysattr;
@ -44,7 +40,7 @@ struct sd_device_enumerator {
Set *match_sysname; Set *match_sysname;
Set *match_tag; Set *match_tag;
Set *match_parent; Set *match_parent;
MatchInitializedType match_initialized; bool match_allow_uninitialized;
}; };
_public_ int sd_device_enumerator_new(sd_device_enumerator **ret) { _public_ int sd_device_enumerator_new(sd_device_enumerator **ret) {
@ -59,7 +55,6 @@ _public_ int sd_device_enumerator_new(sd_device_enumerator **ret) {
*enumerator = (sd_device_enumerator) { *enumerator = (sd_device_enumerator) {
.n_ref = 1, .n_ref = 1,
.type = _DEVICE_ENUMERATION_TYPE_INVALID, .type = _DEVICE_ENUMERATION_TYPE_INVALID,
.match_initialized = MATCH_INITIALIZED_COMPAT,
}; };
*ret = TAKE_PTR(enumerator); *ret = TAKE_PTR(enumerator);
@ -67,29 +62,13 @@ _public_ int sd_device_enumerator_new(sd_device_enumerator **ret) {
return 0; return 0;
} }
static void device_unref_many(sd_device **devices, size_t n) {
assert(devices || n == 0);
for (size_t i = 0; i < n; i++)
sd_device_unref(devices[i]);
}
static void device_enumerator_unref_devices(sd_device_enumerator *enumerator) {
assert(enumerator);
hashmap_clear_with_destructor(enumerator->devices_by_syspath, sd_device_unref);
device_unref_many(enumerator->devices, enumerator->n_devices);
enumerator->devices = mfree(enumerator->devices);
enumerator->n_devices = 0;
}
static sd_device_enumerator *device_enumerator_free(sd_device_enumerator *enumerator) { static sd_device_enumerator *device_enumerator_free(sd_device_enumerator *enumerator) {
assert(enumerator); assert(enumerator);
device_enumerator_unref_devices(enumerator); for (size_t i = 0; i < enumerator->n_devices; i++)
sd_device_unref(enumerator->devices[i]);
hashmap_free(enumerator->devices_by_syspath); free(enumerator->devices);
strv_free(enumerator->prioritized_subsystems);
set_free(enumerator->match_subsystem); set_free(enumerator->match_subsystem);
set_free(enumerator->nomatch_subsystem); set_free(enumerator->nomatch_subsystem);
hashmap_free(enumerator->match_sysattr); hashmap_free(enumerator->match_sysattr);
@ -104,24 +83,6 @@ static sd_device_enumerator *device_enumerator_free(sd_device_enumerator *enumer
DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_device_enumerator, sd_device_enumerator, device_enumerator_free); DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_device_enumerator, sd_device_enumerator, device_enumerator_free);
int device_enumerator_add_prioritized_subsystem(sd_device_enumerator *enumerator, const char *subsystem) {
int r;
assert(enumerator);
assert(subsystem);
if (strv_contains(enumerator->prioritized_subsystems, subsystem))
return 0;
r = strv_extend(&enumerator->prioritized_subsystems, subsystem);
if (r < 0)
return r;
enumerator->scan_uptodate = false;
return 1;
}
_public_ int sd_device_enumerator_add_match_subsystem(sd_device_enumerator *enumerator, const char *subsystem, int match) { _public_ int sd_device_enumerator_add_match_subsystem(sd_device_enumerator *enumerator, const char *subsystem, int match) {
Set **set; Set **set;
int r; int r;
@ -245,214 +206,82 @@ _public_ int sd_device_enumerator_add_match_parent(sd_device_enumerator *enumera
_public_ int sd_device_enumerator_allow_uninitialized(sd_device_enumerator *enumerator) { _public_ int sd_device_enumerator_allow_uninitialized(sd_device_enumerator *enumerator) {
assert_return(enumerator, -EINVAL); assert_return(enumerator, -EINVAL);
enumerator->match_initialized = MATCH_INITIALIZED_ALL; enumerator->match_allow_uninitialized = true;
enumerator->scan_uptodate = false; enumerator->scan_uptodate = false;
return 1; return 1;
} }
int device_enumerator_add_match_is_initialized(sd_device_enumerator *enumerator, MatchInitializedType type) { int device_enumerator_add_match_is_initialized(sd_device_enumerator *enumerator) {
assert_return(enumerator, -EINVAL); assert_return(enumerator, -EINVAL);
assert_return(type >= 0 && type < _MATCH_INITIALIZED_MAX, -EINVAL);
enumerator->match_initialized = type; enumerator->match_allow_uninitialized = false;
enumerator->scan_uptodate = false; enumerator->scan_uptodate = false;
return 1; return 1;
} }
static int sound_device_compare(const char *devpath_a, const char *devpath_b) { static int device_compare(sd_device * const *_a, sd_device * const *_b) {
const char *sound_a, *sound_b; sd_device *a = *(sd_device **)_a, *b = *(sd_device **)_b;
size_t prefix_len; const char *devpath_a, *devpath_b, *sound_a;
bool delay_a, delay_b;
int r;
assert(devpath_a); assert_se(sd_device_get_devpath(a, &devpath_a) >= 0);
assert(devpath_b); assert_se(sd_device_get_devpath(b, &devpath_b) >= 0);
/* For sound cards the control device must be enumerated last to make sure it's the final
* device node that gets ACLs applied. Applications rely on this fact and use ACL changes on
* the control node as an indicator that the ACL change of the entire sound card completed. The
* kernel makes this guarantee when creating those devices, and hence we should too when
* enumerating them. */
sound_a = strstr(devpath_a, "/sound/card"); sound_a = strstr(devpath_a, "/sound/card");
if (!sound_a) if (sound_a) {
return 0; /* For sound cards the control device must be enumerated last to
* make sure it's the final device node that gets ACLs applied.
* Applications rely on this fact and use ACL changes on the
* control node as an indicator that the ACL change of the
* entire sound card completed. The kernel makes this guarantee
* when creating those devices, and hence we should too when
* enumerating them. */
sound_a += STRLEN("/sound/card"); sound_a += STRLEN("/sound/card");
sound_a = strchr(devpath_a, '/'); sound_a = strchr(sound_a, '/');
if (!sound_a)
return 0; if (sound_a) {
unsigned prefix_len;
prefix_len = sound_a - devpath_a; prefix_len = sound_a - devpath_a;
if (!strneq(devpath_a, devpath_b, prefix_len)) if (strneq(devpath_a, devpath_b, prefix_len)) {
return 0; const char *sound_b;
sound_b = devpath_b + prefix_len; sound_b = devpath_b + prefix_len;
return CMP(!!startswith(sound_a, "/controlC"), r = CMP(!!startswith(sound_a, "/controlC"),
!!startswith(sound_b, "/controlC")); !!startswith(sound_b, "/controlC"));
}
static bool devpath_is_late_block(const char *devpath) {
assert(devpath);
return strstr(devpath, "/block/md") || strstr(devpath, "/block/dm-");
}
static int device_compare(sd_device * const *a, sd_device * const *b) {
const char *devpath_a, *devpath_b;
int r;
assert(a);
assert(b);
assert(*a);
assert(*b);
assert_se(sd_device_get_devpath(*(sd_device**) a, &devpath_a) >= 0);
assert_se(sd_device_get_devpath(*(sd_device**) b, &devpath_b) >= 0);
r = sound_device_compare(devpath_a, devpath_b);
if (r != 0) if (r != 0)
return r; return r;
}
}
}
/* md and dm devices are enumerated after all other devices */ /* md and dm devices are enumerated after all other devices */
r = CMP(devpath_is_late_block(devpath_a), devpath_is_late_block(devpath_b)); delay_a = strstr(devpath_a, "/block/md") || strstr(devpath_a, "/block/dm-");
delay_b = strstr(devpath_b, "/block/md") || strstr(devpath_b, "/block/dm-");
r = CMP(delay_a, delay_b);
if (r != 0) if (r != 0)
return r; return r;
return strcmp(devpath_a, devpath_b); return strcmp(devpath_a, devpath_b);
} }
static int enumerator_sort_devices(sd_device_enumerator *enumerator) {
size_t n_sorted = 0, n = 0;
sd_device **devices;
sd_device *device;
int r;
assert(enumerator);
if (enumerator->sorted)
return 0;
devices = new(sd_device*, hashmap_size(enumerator->devices_by_syspath));
if (!devices)
return -ENOMEM;
STRV_FOREACH(prioritized_subsystem, enumerator->prioritized_subsystems) {
for (;;) {
const char *syspath;
size_t m = n;
HASHMAP_FOREACH_KEY(device, syspath, enumerator->devices_by_syspath) {
_cleanup_free_ char *p = NULL;
const char *subsys;
if (sd_device_get_subsystem(device, &subsys) < 0)
continue;
if (!streq(subsys, *prioritized_subsystem))
continue;
devices[n++] = sd_device_ref(device);
for (;;) {
_cleanup_free_ char *q = NULL;
r = path_extract_directory(p ?: syspath, &q);
if (r == -EADDRNOTAVAIL)
break;
if (r < 0)
goto failed;
device = hashmap_get(enumerator->devices_by_syspath, q);
if (device)
devices[n++] = sd_device_ref(device);
free_and_replace(p, q);
}
break;
}
/* We cannot remove multiple entries in the loop HASHMAP_FOREACH_KEY() above. */
for (size_t i = m; i < n; i++) {
r = sd_device_get_syspath(devices[i], &syspath);
if (r < 0)
goto failed;
assert_se(hashmap_remove(enumerator->devices_by_syspath, syspath) == devices[i]);
sd_device_unref(devices[i]);
}
if (m == n)
break;
}
typesafe_qsort(devices + n_sorted, n - n_sorted, device_compare);
n_sorted = n;
}
HASHMAP_FOREACH(device, enumerator->devices_by_syspath)
devices[n++] = sd_device_ref(device);
/* Move all devices back to the hashmap. Otherwise, devices added by
* udev_enumerate_add_syspath() -> device_enumerator_add_device() may not be listed. */
for (size_t i = 0; i < n_sorted; i++) {
const char *syspath;
r = sd_device_get_syspath(devices[i], &syspath);
if (r < 0)
goto failed;
r = hashmap_put(enumerator->devices_by_syspath, syspath, devices[i]);
if (r < 0)
goto failed;
assert(r > 0);
sd_device_ref(devices[i]);
}
typesafe_qsort(devices + n_sorted, n - n_sorted, device_compare);
device_unref_many(enumerator->devices, enumerator->n_devices);
enumerator->n_devices = n;
free_and_replace(enumerator->devices, devices);
enumerator->sorted = true;
return 0;
failed:
device_unref_many(devices, n);
free(devices);
return r;
}
int device_enumerator_add_device(sd_device_enumerator *enumerator, sd_device *device) { int device_enumerator_add_device(sd_device_enumerator *enumerator, sd_device *device) {
const char *syspath;
int r;
assert_return(enumerator, -EINVAL); assert_return(enumerator, -EINVAL);
assert_return(device, -EINVAL); assert_return(device, -EINVAL);
r = sd_device_get_syspath(device, &syspath); if (!GREEDY_REALLOC(enumerator->devices, enumerator->n_devices + 1))
if (r < 0) return -ENOMEM;
return r;
enumerator->devices[enumerator->n_devices++] = sd_device_ref(device);
r = hashmap_ensure_put(&enumerator->devices_by_syspath, &string_hash_ops, syspath, device);
if (IN_SET(r, -EEXIST, 0))
return 0; return 0;
if (r < 0)
return r;
sd_device_ref(device);
enumerator->sorted = false;
return 1;
} }
static bool match_property(sd_device_enumerator *enumerator, sd_device *device) { static bool match_property(sd_device_enumerator *enumerator, sd_device *device) {
@ -515,42 +344,10 @@ static bool match_sysname(sd_device_enumerator *enumerator, const char *sysname)
return false; return false;
} }
static int match_initialized(sd_device_enumerator *enumerator, sd_device *device) {
int r;
assert(enumerator);
assert(device);
if (enumerator->match_initialized == MATCH_INITIALIZED_ALL)
return true;
r = sd_device_get_is_initialized(device);
if (r == -ENOENT) /* this is necessarily racey, so ignore missing devices */
return false;
if (r < 0)
return r;
if (enumerator->match_initialized == MATCH_INITIALIZED_COMPAT) {
/* only devices that have no devnode/ifindex or have a db entry are accepted. */
if (r > 0)
return true;
if (sd_device_get_devnum(device, NULL) >= 0)
return true;
if (sd_device_get_ifindex(device, NULL) >= 0)
return true;
return false;
}
return (enumerator->match_initialized == MATCH_INITIALIZED_NO) == (r == 0);
}
static int enumerator_scan_dir_and_add_devices(sd_device_enumerator *enumerator, const char *basedir, const char *subdir1, const char *subdir2) { static int enumerator_scan_dir_and_add_devices(sd_device_enumerator *enumerator, const char *basedir, const char *subdir1, const char *subdir2) {
_cleanup_closedir_ DIR *dir = NULL; _cleanup_closedir_ DIR *dir = NULL;
char *path; char *path;
int k, r = 0; int r = 0;
assert(enumerator); assert(enumerator);
assert(basedir); assert(basedir);
@ -571,6 +368,7 @@ static int enumerator_scan_dir_and_add_devices(sd_device_enumerator *enumerator,
FOREACH_DIRENT_ALL(de, dir, return -errno) { FOREACH_DIRENT_ALL(de, dir, return -errno) {
_cleanup_(sd_device_unrefp) sd_device *device = NULL; _cleanup_(sd_device_unrefp) sd_device *device = NULL;
char syspath[strlen(path) + 1 + strlen(de->d_name) + 1]; char syspath[strlen(path) + 1 + strlen(de->d_name) + 1];
int initialized, k;
if (de->d_name[0] == '.') if (de->d_name[0] == '.')
continue; continue;
@ -589,13 +387,31 @@ static int enumerator_scan_dir_and_add_devices(sd_device_enumerator *enumerator,
continue; continue;
} }
k = match_initialized(enumerator, device); initialized = sd_device_get_is_initialized(device);
if (k <= 0) { if (initialized < 0) {
if (k < 0) if (initialized != -ENOENT)
r = k; /* this is necessarily racey, so ignore missing devices */
r = initialized;
continue; continue;
} }
/*
* All devices with a device node or network interfaces
* possibly need udev to adjust the device node permission
* or context, or rename the interface before it can be
* reliably used from other processes.
*
* For now, we can only check these types of devices, we
* might not store a database, and have no way to find out
* for all other types of devices.
*/
if (!enumerator->match_allow_uninitialized &&
!initialized &&
(sd_device_get_devnum(device, NULL) >= 0 ||
sd_device_get_ifindex(device, NULL) >= 0))
continue;
if (!device_match_parent(device, enumerator->match_parent, NULL)) if (!device_match_parent(device, enumerator->match_parent, NULL))
continue; continue;
@ -854,10 +670,18 @@ static int enumerator_scan_devices_children(sd_device_enumerator *enumerator) {
} }
static int enumerator_scan_devices_all(sd_device_enumerator *enumerator) { static int enumerator_scan_devices_all(sd_device_enumerator *enumerator) {
int k, r = 0; int r = 0;
log_debug("sd-device-enumerator: Scan all dirs"); log_debug("sd-device-enumerator: Scan all dirs");
if (access("/sys/subsystem", F_OK) >= 0) {
/* we have /subsystem/, forget all the old stuff */
r = enumerator_scan_dir(enumerator, "subsystem", "devices", NULL);
if (r < 0)
return log_debug_errno(r, "sd-device-enumerator: Failed to scan /sys/subsystem: %m");
} else {
int k;
k = enumerator_scan_dir(enumerator, "bus", "devices", NULL); k = enumerator_scan_dir(enumerator, "bus", "devices", NULL);
if (k < 0) if (k < 0)
r = log_debug_errno(k, "sd-device-enumerator: Failed to scan /sys/bus: %m"); r = log_debug_errno(k, "sd-device-enumerator: Failed to scan /sys/bus: %m");
@ -865,10 +689,38 @@ static int enumerator_scan_devices_all(sd_device_enumerator *enumerator) {
k = enumerator_scan_dir(enumerator, "class", NULL, NULL); k = enumerator_scan_dir(enumerator, "class", NULL, NULL);
if (k < 0) if (k < 0)
r = log_debug_errno(k, "sd-device-enumerator: Failed to scan /sys/class: %m"); r = log_debug_errno(k, "sd-device-enumerator: Failed to scan /sys/class: %m");
}
return r; return r;
} }
static void device_enumerator_dedup_devices(sd_device_enumerator *enumerator) {
sd_device **a, **b, **end;
assert(enumerator);
if (enumerator->n_devices <= 1)
return;
a = enumerator->devices + 1;
b = enumerator->devices;
end = enumerator->devices + enumerator->n_devices;
for (; a < end; a++) {
const char *devpath_a, *devpath_b;
assert_se(sd_device_get_devpath(*a, &devpath_a) >= 0);
assert_se(sd_device_get_devpath(*b, &devpath_b) >= 0);
if (path_equal(devpath_a, devpath_b))
sd_device_unref(*a);
else
*(++b) = *a;
}
enumerator->n_devices = b - enumerator->devices + 1;
}
int device_enumerator_scan_devices(sd_device_enumerator *enumerator) { int device_enumerator_scan_devices(sd_device_enumerator *enumerator) {
int r = 0, k; int r = 0, k;
@ -878,7 +730,10 @@ int device_enumerator_scan_devices(sd_device_enumerator *enumerator) {
enumerator->type == DEVICE_ENUMERATION_TYPE_DEVICES) enumerator->type == DEVICE_ENUMERATION_TYPE_DEVICES)
return 0; return 0;
device_enumerator_unref_devices(enumerator); for (size_t i = 0; i < enumerator->n_devices; i++)
sd_device_unref(enumerator->devices[i]);
enumerator->n_devices = 0;
if (!set_isempty(enumerator->match_tag)) { if (!set_isempty(enumerator->match_tag)) {
k = enumerator_scan_devices_tags(enumerator); k = enumerator_scan_devices_tags(enumerator);
@ -894,6 +749,9 @@ int device_enumerator_scan_devices(sd_device_enumerator *enumerator) {
r = k; r = k;
} }
typesafe_qsort(enumerator->devices, enumerator->n_devices, device_compare);
device_enumerator_dedup_devices(enumerator);
enumerator->scan_uptodate = true; enumerator->scan_uptodate = true;
enumerator->type = DEVICE_ENUMERATION_TYPE_DEVICES; enumerator->type = DEVICE_ENUMERATION_TYPE_DEVICES;
@ -901,12 +759,12 @@ int device_enumerator_scan_devices(sd_device_enumerator *enumerator) {
} }
_public_ sd_device *sd_device_enumerator_get_device_first(sd_device_enumerator *enumerator) { _public_ sd_device *sd_device_enumerator_get_device_first(sd_device_enumerator *enumerator) {
int r;
assert_return(enumerator, NULL); assert_return(enumerator, NULL);
if (device_enumerator_scan_devices(enumerator) < 0) r = device_enumerator_scan_devices(enumerator);
return NULL; if (r < 0)
if (enumerator_sort_devices(enumerator) < 0)
return NULL; return NULL;
enumerator->current_device_index = 0; enumerator->current_device_index = 0;
@ -921,7 +779,6 @@ _public_ sd_device *sd_device_enumerator_get_device_next(sd_device_enumerator *e
assert_return(enumerator, NULL); assert_return(enumerator, NULL);
if (!enumerator->scan_uptodate || if (!enumerator->scan_uptodate ||
!enumerator->sorted ||
enumerator->type != DEVICE_ENUMERATION_TYPE_DEVICES || enumerator->type != DEVICE_ENUMERATION_TYPE_DEVICES ||
enumerator->current_device_index + 1 >= enumerator->n_devices) enumerator->current_device_index + 1 >= enumerator->n_devices)
return NULL; return NULL;
@ -930,6 +787,7 @@ _public_ sd_device *sd_device_enumerator_get_device_next(sd_device_enumerator *e
} }
int device_enumerator_scan_subsystems(sd_device_enumerator *enumerator) { int device_enumerator_scan_subsystems(sd_device_enumerator *enumerator) {
const char *subsysdir;
int r = 0, k; int r = 0, k;
assert(enumerator); assert(enumerator);
@ -938,7 +796,10 @@ int device_enumerator_scan_subsystems(sd_device_enumerator *enumerator) {
enumerator->type == DEVICE_ENUMERATION_TYPE_SUBSYSTEMS) enumerator->type == DEVICE_ENUMERATION_TYPE_SUBSYSTEMS)
return 0; return 0;
device_enumerator_unref_devices(enumerator); for (size_t i = 0; i < enumerator->n_devices; i++)
sd_device_unref(enumerator->devices[i]);
enumerator->n_devices = 0;
/* modules */ /* modules */
if (match_subsystem(enumerator, "module")) { if (match_subsystem(enumerator, "module")) {
@ -947,20 +808,28 @@ int device_enumerator_scan_subsystems(sd_device_enumerator *enumerator) {
r = log_debug_errno(k, "sd-device-enumerator: Failed to scan modules: %m"); r = log_debug_errno(k, "sd-device-enumerator: Failed to scan modules: %m");
} }
if (access("/sys/subsystem", F_OK) >= 0)
subsysdir = "subsystem";
else
subsysdir = "bus";
/* subsystems (only buses support coldplug) */ /* subsystems (only buses support coldplug) */
if (match_subsystem(enumerator, "subsystem")) { if (match_subsystem(enumerator, "subsystem")) {
k = enumerator_scan_dir_and_add_devices(enumerator, "bus", NULL, NULL); k = enumerator_scan_dir_and_add_devices(enumerator, subsysdir, NULL, NULL);
if (k < 0) if (k < 0)
r = log_debug_errno(k, "sd-device-enumerator: Failed to scan subsystems: %m"); r = log_debug_errno(k, "sd-device-enumerator: Failed to scan subsystems: %m");
} }
/* subsystem drivers */ /* subsystem drivers */
if (match_subsystem(enumerator, "drivers")) { if (match_subsystem(enumerator, "drivers")) {
k = enumerator_scan_dir(enumerator, "bus", "drivers", "drivers"); k = enumerator_scan_dir(enumerator, subsysdir, "drivers", "drivers");
if (k < 0) if (k < 0)
r = log_debug_errno(k, "sd-device-enumerator: Failed to scan drivers: %m"); r = log_debug_errno(k, "sd-device-enumerator: Failed to scan drivers: %m");
} }
typesafe_qsort(enumerator->devices, enumerator->n_devices, device_compare);
device_enumerator_dedup_devices(enumerator);
enumerator->scan_uptodate = true; enumerator->scan_uptodate = true;
enumerator->type = DEVICE_ENUMERATION_TYPE_SUBSYSTEMS; enumerator->type = DEVICE_ENUMERATION_TYPE_SUBSYSTEMS;
@ -968,12 +837,12 @@ int device_enumerator_scan_subsystems(sd_device_enumerator *enumerator) {
} }
_public_ sd_device *sd_device_enumerator_get_subsystem_first(sd_device_enumerator *enumerator) { _public_ sd_device *sd_device_enumerator_get_subsystem_first(sd_device_enumerator *enumerator) {
int r;
assert_return(enumerator, NULL); assert_return(enumerator, NULL);
if (device_enumerator_scan_subsystems(enumerator) < 0) r = device_enumerator_scan_subsystems(enumerator);
return NULL; if (r < 0)
if (enumerator_sort_devices(enumerator) < 0)
return NULL; return NULL;
enumerator->current_device_index = 0; enumerator->current_device_index = 0;
@ -988,7 +857,6 @@ _public_ sd_device *sd_device_enumerator_get_subsystem_next(sd_device_enumerator
assert_return(enumerator, NULL); assert_return(enumerator, NULL);
if (!enumerator->scan_uptodate || if (!enumerator->scan_uptodate ||
!enumerator->sorted ||
enumerator->type != DEVICE_ENUMERATION_TYPE_SUBSYSTEMS || enumerator->type != DEVICE_ENUMERATION_TYPE_SUBSYSTEMS ||
enumerator->current_device_index + 1 >= enumerator->n_devices) enumerator->current_device_index + 1 >= enumerator->n_devices)
return NULL; return NULL;
@ -996,67 +864,12 @@ _public_ sd_device *sd_device_enumerator_get_subsystem_next(sd_device_enumerator
return enumerator->devices[++enumerator->current_device_index]; return enumerator->devices[++enumerator->current_device_index];
} }
int device_enumerator_scan_devices_and_subsystems(sd_device_enumerator *enumerator) {
int r = 0, k;
assert(enumerator);
if (enumerator->scan_uptodate &&
enumerator->type == DEVICE_ENUMERATION_TYPE_ALL)
return 0;
device_enumerator_unref_devices(enumerator);
if (!set_isempty(enumerator->match_tag)) {
k = enumerator_scan_devices_tags(enumerator);
if (k < 0)
r = k;
} else if (enumerator->match_parent) {
k = enumerator_scan_devices_children(enumerator);
if (k < 0)
r = k;
} else {
k = enumerator_scan_dir(enumerator, "class", NULL, NULL);
if (k < 0)
r = log_debug_errno(k, "sd-device-enumerator: Failed to scan /sys/class: %m");
k = enumerator_scan_dir(enumerator, "bus", "devices", NULL);
if (k < 0)
r = log_debug_errno(k, "sd-device-enumerator: Failed to scan /sys/bus: %m");
if (match_subsystem(enumerator, "module")) {
k = enumerator_scan_dir_and_add_devices(enumerator, "module", NULL, NULL);
if (k < 0)
r = log_debug_errno(k, "sd-device-enumerator: Failed to scan modules: %m");
}
if (match_subsystem(enumerator, "subsystem")) {
k = enumerator_scan_dir_and_add_devices(enumerator, "bus", NULL, NULL);
if (k < 0)
r = log_debug_errno(k, "sd-device-enumerator: Failed to scan subsystems: %m");
}
if (match_subsystem(enumerator, "drivers")) {
k = enumerator_scan_dir(enumerator, "bus", "drivers", "drivers");
if (k < 0)
r = log_debug_errno(k, "sd-device-enumerator: Failed to scan drivers: %m");
}
}
enumerator->scan_uptodate = true;
enumerator->type = DEVICE_ENUMERATION_TYPE_ALL;
return r;
}
sd_device *device_enumerator_get_first(sd_device_enumerator *enumerator) { sd_device *device_enumerator_get_first(sd_device_enumerator *enumerator) {
assert_return(enumerator, NULL); assert_return(enumerator, NULL);
if (!enumerator->scan_uptodate) if (!enumerator->scan_uptodate)
return NULL; return NULL;
if (enumerator_sort_devices(enumerator) < 0)
return NULL;
enumerator->current_device_index = 0; enumerator->current_device_index = 0;
if (enumerator->n_devices == 0) if (enumerator->n_devices == 0)
@ -1069,7 +882,6 @@ sd_device *device_enumerator_get_next(sd_device_enumerator *enumerator) {
assert_return(enumerator, NULL); assert_return(enumerator, NULL);
if (!enumerator->scan_uptodate || if (!enumerator->scan_uptodate ||
!enumerator->sorted ||
enumerator->current_device_index + 1 >= enumerator->n_devices) enumerator->current_device_index + 1 >= enumerator->n_devices)
return NULL; return NULL;
@ -1083,9 +895,6 @@ sd_device **device_enumerator_get_devices(sd_device_enumerator *enumerator, size
if (!enumerator->scan_uptodate) if (!enumerator->scan_uptodate)
return NULL; return NULL;
if (enumerator_sort_devices(enumerator) < 0)
return NULL;
*ret_n_devices = enumerator->n_devices; *ret_n_devices = enumerator->n_devices;
return enumerator->devices; return enumerator->devices;
} }

View File

@ -365,7 +365,7 @@ _public_ int udev_enumerate_add_match_is_initialized(struct udev_enumerate *udev
assert_return(udev_enumerate, -EINVAL); assert_return(udev_enumerate, -EINVAL);
r = device_enumerator_add_match_is_initialized(udev_enumerate->enumerator, MATCH_INITIALIZED_COMPAT); r = device_enumerator_add_match_is_initialized(udev_enumerate->enumerator);
if (r < 0) if (r < 0)
return r; return r;

View File

@ -11,7 +11,6 @@
#include "device-util.h" #include "device-util.h"
#include "fd-util.h" #include "fd-util.h"
#include "fileio.h" #include "fileio.h"
#include "parse-util.h"
#include "path-util.h" #include "path-util.h"
#include "process-util.h" #include "process-util.h"
#include "set.h" #include "set.h"
@ -227,14 +226,10 @@ static int help(void) {
" -y --sysname-match=NAME Trigger devices with this /sys path\n" " -y --sysname-match=NAME Trigger devices with this /sys path\n"
" --name-match=NAME Trigger devices with this /dev name\n" " --name-match=NAME Trigger devices with this /dev name\n"
" -b --parent-match=NAME Trigger devices with that parent device\n" " -b --parent-match=NAME Trigger devices with that parent device\n"
" --initialized-match Trigger devices that are already initialized\n"
" --initialized-nomatch Trigger devices that are not initialized yet\n"
" -w --settle Wait for the triggered events to complete\n" " -w --settle Wait for the triggered events to complete\n"
" --wait-daemon[=SECONDS] Wait for udevd daemon to be initialized\n" " --wait-daemon[=SECONDS] Wait for udevd daemon to be initialized\n"
" before triggering uevents\n" " before triggering uevents\n"
" --uuid Print synthetic uevent UUID\n" " --uuid Print synthetic uevent UUID\n",
" --prioritized-subsystem=SUBSYSTEM[,SUBSYSTEM…]\n"
" Trigger devices from a matching subsystem first\n",
program_invocation_short_name); program_invocation_short_name);
return 0; return 0;
@ -245,9 +240,6 @@ int trigger_main(int argc, char *argv[], void *userdata) {
ARG_NAME = 0x100, ARG_NAME = 0x100,
ARG_PING, ARG_PING,
ARG_UUID, ARG_UUID,
ARG_PRIORITIZED_SUBSYSTEM,
ARG_INITIALIZED_MATCH,
ARG_INITIALIZED_NOMATCH,
}; };
static const struct option options[] = { static const struct option options[] = {
@ -265,20 +257,16 @@ int trigger_main(int argc, char *argv[], void *userdata) {
{ "sysname-match", required_argument, NULL, 'y' }, { "sysname-match", required_argument, NULL, 'y' },
{ "name-match", required_argument, NULL, ARG_NAME }, { "name-match", required_argument, NULL, ARG_NAME },
{ "parent-match", required_argument, NULL, 'b' }, { "parent-match", required_argument, NULL, 'b' },
{ "initialized-match", no_argument, NULL, ARG_INITIALIZED_MATCH },
{ "initialized-nomatch", no_argument, NULL, ARG_INITIALIZED_NOMATCH },
{ "settle", no_argument, NULL, 'w' }, { "settle", no_argument, NULL, 'w' },
{ "wait-daemon", optional_argument, NULL, ARG_PING }, { "wait-daemon", optional_argument, NULL, ARG_PING },
{ "version", no_argument, NULL, 'V' }, { "version", no_argument, NULL, 'V' },
{ "help", no_argument, NULL, 'h' }, { "help", no_argument, NULL, 'h' },
{ "uuid", no_argument, NULL, ARG_UUID }, { "uuid", no_argument, NULL, ARG_UUID },
{ "prioritized-subsystem", required_argument, NULL, ARG_PRIORITIZED_SUBSYSTEM },
{} {}
}; };
enum { enum {
TYPE_DEVICES, TYPE_DEVICES,
TYPE_SUBSYSTEMS, TYPE_SUBSYSTEMS,
TYPE_ALL,
} device_type = TYPE_DEVICES; } device_type = TYPE_DEVICES;
sd_device_action_t action = SD_DEVICE_CHANGE; sd_device_action_t action = SD_DEVICE_CHANGE;
_cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL; _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
@ -321,8 +309,6 @@ int trigger_main(int argc, char *argv[], void *userdata) {
device_type = TYPE_DEVICES; device_type = TYPE_DEVICES;
else if (streq(optarg, "subsystems")) else if (streq(optarg, "subsystems"))
device_type = TYPE_SUBSYSTEMS; device_type = TYPE_SUBSYSTEMS;
else if (streq(optarg, "all"))
device_type = TYPE_ALL;
else else
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown type --type=%s", optarg); return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown type --type=%s", optarg);
break; break;
@ -419,26 +405,6 @@ int trigger_main(int argc, char *argv[], void *userdata) {
arg_uuid = true; arg_uuid = true;
break; break;
case ARG_PRIORITIZED_SUBSYSTEM: {
_cleanup_strv_free_ char **subsystems = NULL;
subsystems = strv_split(optarg, ",");
if (!subsystems)
return log_error_errno(r, "Failed to parse prioritized subsystem '%s': %m", optarg);
STRV_FOREACH(p, subsystems) {
r = device_enumerator_add_prioritized_subsystem(e, *p);
if (r < 0)
return log_error_errno(r, "Failed to add prioritized subsystem '%s': %m", *p);
}
break;
}
case ARG_INITIALIZED_MATCH:
case ARG_INITIALIZED_NOMATCH:
r = device_enumerator_add_match_is_initialized(e, c == ARG_INITIALIZED_MATCH ? MATCH_INITIALIZED_YES : MATCH_INITIALIZED_NO);
if (r < 0)
return log_error_errno(r, "Failed to set initialized filter: %m");
break;
case 'V': case 'V':
return print_version(); return print_version();
case 'h': case 'h':
@ -511,11 +477,6 @@ int trigger_main(int argc, char *argv[], void *userdata) {
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to scan devices: %m"); return log_error_errno(r, "Failed to scan devices: %m");
break; break;
case TYPE_ALL:
r = device_enumerator_scan_devices_and_subsystems(e);
if (r < 0)
return log_error_errno(r, "Failed to scan devices and subsystems: %m");
break;
default: default:
assert_not_reached(); assert_not_reached();
} }

View File

@ -19,4 +19,5 @@ ConditionPathIsReadWrite=/sys
[Service] [Service]
Type=oneshot Type=oneshot
RemainAfterExit=yes RemainAfterExit=yes
ExecStart=-udevadm trigger --type=all --action=add --prioritized-subsystem=block,tpmrm ExecStart=-udevadm trigger --type=subsystems --action=add
ExecStart=-udevadm trigger --type=devices --action=add