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

Compare commits

..

27 Commits

Author SHA1 Message Date
Zbigniew Jędrzejewski-Szmek
93efd9cadb
Merge pull request #22778 from poettering/kernel-install-layout-rework
kernel-install/bootctl: layout fixes
2022-03-22 13:57:28 +01:00
Lennart Poettering
c0f6a6a542
Merge pull request #22662 from yuwata/udev-trigger-priority
udevadm trigger: add --prioritized-subsystem option
2022-03-22 12:56:32 +01:00
Jason A. Donenfeld
d328346944 random-util: use correct minimum pool size constant
The actual minimum size of the pool across supported kernel versions is
32 bytes. So adjust this minimum.

I've audited every single usage of random_pool_size(), and cannot see
anywhere that this would have any impact at all on anything. We could
actually just not change the constant and everything would be fine, or
we could change it here and that's fine too. From both a functionality
and crypto perspective, it doesn't really seem to make a substantive
difference any which way, so long as the value is ≥32. However, it's
better to be correct and have the function do what it says, so clamp it
to the right minimum.
2022-03-22 08:46:20 +01:00
Zbigniew Jędrzejewski-Szmek
8bab619383
Merge pull request #22813 from poettering/sd-boot-man-fixes
man: some sd-boot doc tweaks
2022-03-22 08:26:57 +01:00
Danilo Krummrich
678f2b1667 udevadm: trigger: implement --initialized-match/nomatch arguments
systemd-udev-trigger.service by default triggeres all devices regardless
of whether they were already recognized by systemd-udevd.

There are machines (especially in embedded environments) where
systemd-udev-trigger.service is configured to run at a later stage of
the boot sequence, which can lead to quite a lot of devices being
triggered although they were already recognized by systemd-udevd.

Re-triggering a lot of devices is a relatively expensive operation and
therefore should be avoided if unnecessary.

Therefore this patch introduces --initialized-nomatch, which filters out
devices that are already present in the udev database. For consistance
reasons --initialized-match is implemented as well, which filters out devices
that are *not* already present in the udev database.

Replaces #19949.
2022-03-22 15:54:10 +09:00
Yu Watanabe
d8b50e5df7 sd-device-enumerator: support to list only initialized or uninitialized devices 2022-03-22 15:27:06 +09:00
Yu Watanabe
2336bde964 unit: make systemd-udev-trigger.service use --prioritized-subsystem
Replaces #19637 and #22643.
2022-03-22 15:27:06 +09:00
Yu Watanabe
1baeee5784 udevadm trigger: introduce --type=all option 2022-03-22 15:27:06 +09:00
Yu Watanabe
873cf95c2f udevadm trigger: introduce --prioritized-subsystem option 2022-03-22 15:27:06 +09:00
Yu Watanabe
3c5cc23a93 sd-device-enumerator: introduce device_enumerator_scan_devices_and_subsystems() 2022-03-22 15:27:06 +09:00
Yu Watanabe
37cf83d9bf sd-device-enumerator: drop /sys/subsystem support
This addresses the comment by Lennart
https://github.com/systemd/systemd/pull/22662#discussion_r829799863:
> /sys/subsystem is preparation for a future that never came.
> And given that the main proponent of this left Linux kernel
> development (Kay), I doubt this will ever come. So maybe we
> should start dropping references to /sys/subsystem/ given it's
> unlikely to materialize anytime soon.
2022-03-22 15:27:06 +09:00
Yu Watanabe
95a6f969fc sd-device-enumerator: introduce device_enumerator_add_prioritized_subsystem()
If a subsystem is specified, then matching devices and their parents are
listed at first.
2022-03-22 12:29:08 +09:00
Yu Watanabe
87c3a0f9f8 sd-device-enumerator: introduce device_enumerator_sort_devices()
and devices are sorted when the iteration started.

Previously, devices added by udev_enumerate_add_syspath() ->
device_enumerator_add_device() are not sorted. This fixes the issue.
2022-03-22 11:56:18 +09:00
Yu Watanabe
deac0c9c04 sd-device-enumerator: introduce device_enumerator_unref_devices() helper function 2022-03-22 11:56:18 +09:00
Yu Watanabe
9e871965a0 sd-device-enumerator: introduce sound_device_compare() and devpath_is_late_block() helper functions 2022-03-22 11:56:13 +09:00
Lennart Poettering
41f630598d kernel-install: check for /loader/entries.srel file as explicit marker for standards compliant /loader/entries directory 2022-03-22 00:34:49 +01:00
Lennart Poettering
80889bd9cc bootctl: automatically write out $BOOT/entries/standard.srel 2022-03-22 00:34:49 +01:00
Lennart Poettering
a5b30e156a bootctl: generalize open_tmpfile_linkable() use a bit
We want FILE* here, instead of a plain fd. Let's generalize this in
tmpfile-util.c, so we can reuse it later easily.
2022-03-22 00:34:48 +01:00
Lennart Poettering
f6ad0282c9 docs: add /loader/entries.srel to the boot loader spec
This new file is supposed to address conflicts with Fedora/Grub's
frankenbootloaderspec implementation, that squatted the /loader/entries/
dir, but place incompatible files in them (that do variable expansion?).

A simple text file /loader/entries.srel shall indicate which spec is
implemented. If it contains the string "type1\n" then the
/loader/entries/ directory implements our standard spec, otherwise
something else.
2022-03-22 00:34:33 +01:00
Lennart Poettering
cafa9d87b4 man: clarify that type #1 entries are also read from the XBOOTLDR partition 2022-03-22 00:23:25 +01:00
Lennart Poettering
838f094ce7 man: also install systemd-stub man page as sd-stub
So, typically systemd-boot is referenced as sd-boot, due to te usual
shorter naming in ESP resources. systemd-stub didnt do that so far,
since it never appears as separate files in the ESP. However it's super
annoying that you can find "man sd-boot", but not the very closely
related "man sd-stub". Let's fix that, and also add an "sd-stub" alias
to the "systemd-stub" man page.
2022-03-22 00:22:07 +01:00
Lennart Poettering
d212b862bf man: clarify where the settings in type #1 entries are documented
So (maybe weirdly) loader.conf(5) documents both loader.conf and type #1
entries (because they share a similar syntax). But it then only lists
the options of loader.conf. Let's add an explicit hint where to find
the documentation of the type #1 entries.
2022-03-22 00:22:07 +01:00
Lennart Poettering
84df0f315a man: clarify the format used by sd-boot config files 2022-03-22 00:22:07 +01:00
Lennart Poettering
ffc97a1cc4 NEWS: try to fix old entry regarding KERNEL_INSTALL_LAYOUT
The old text was simply wrong, we used to read $layout from
/etc/kernel/install.conf and the machine ID from
$KERNEL_INSTALL_MACHINE_ID from /etc/machine-info. Correct that.

Apparently KERNEL_INSTALL_MACHINE_ID was already known back in v235
times, hence don't mention it anymore.

it's kinda weird retro-fixing these NEWS entries, given we deprecate
them again, but I couldn't let this really incorrect stuff be.
2022-03-21 23:54:33 +01:00
Lennart Poettering
354a244177 kernel-install: list fields we honour in /etc/kernel/install.conf 2022-03-21 23:54:33 +01:00
Lennart Poettering
b72676e7a0 bootctl: load /etc/kernel/install.conf's $layout field, too
bootctl so far tried to determine the layout from /etc/machine-info, but
that's obsolete, and the kernel-install script never looked there. Let's
read the setting from /etc/kernel/install.conf instead, where
kernel-install actually looks.

Support for reading the field from /etc/machine-info is retained for
compat.

This means we'll now read /etc/machine-id, /etc/machine-info and
/etc/kernel/install.conf, and read the machine ID from the former too
and the layout setting from the latter two.
2022-03-21 23:54:33 +01:00
Lennart Poettering
ea29abece9 bootctl: $KERNEL_INSTALL_MACHINE_ID + $KERNEL_INSTALL_LAYOUT are deprecated
Let's add a comment about this, and generate log messages if these
fields are actually used.
2022-03-21 23:50:17 +01:00
20 changed files with 675 additions and 234 deletions

16
NEWS
View File

@ -656,15 +656,13 @@ 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 KERNEL_INSTALL_MACHINE_ID * bootctl and kernel-install will now read variables
and KERNEL_INSTALL_LAYOUT from kernel/install.conf. The first KERNEL_INSTALL_LAYOUT= from /etc/machine-info and layout= from
variable specifies the machine-id to use for installation. It would /etc/kernel/install.conf. When set, it specifies the layout to use
previously be used if set in the environment, and now it'll also be for installation directories on the boot partition, so that tools
read automatically from the config file. The second variable is new. don't need to guess it based on the already-existing directories. The
When set, it specifies the layout to use for installation directories only value that is defined natively is "bls", corresponding to the
on the boot partition, so that tools don't need to guess it based on layout specified in
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,6 +309,18 @@ 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,9 +237,8 @@
</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 should be configured as <varname>initrd_generator=</varname> in generator. This may be configured as <varname>initrd_generator=</varname> in
<filename>install.conf</filename>. <filename>install.conf</filename>. See below.</para>
</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
@ -325,10 +324,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>, <para>Configuration options for <command>kernel-install</command>, as a series of
as a series of <varname>KEY=</varname><replaceable>VALUE</replaceable> assignments, <varname>KEY=</varname><replaceable>VALUE</replaceable> assignments, compatible with shell
compatible with shell syntax. syntax. This currently supports two keys: <varname>layout=</varname> and
See the Environment variables section for supported keys.</para> <varname>initrd_generator=</varname>, for details see the Environment variables section above.</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
</variablelist> </variablelist>

View File

@ -23,6 +23,7 @@
<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>
@ -33,13 +34,16 @@
<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) as <filename><replaceable>ESP</replaceable>/loader/entries/</filename> on the EFI system partition (ESP),
defined by <ulink url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot Loader Specification</ulink>. and <filename><replaceable>XBOOTLDR</replaceable>/loader/entries/</filename> on the extended boot loader
partition (XBOOTLDR) as defined by <ulink url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot Loader
Specification</ulink>.
</para> </para>
<para>Each configuration file must consist of an option name, followed by <para>Each of these configuration files must consist of series of newline (i.e. ASCII code 10) separated
whitespace, and the option value. <literal>#</literal> may be used to start lines, each consisting of an option name, followed by whitespace, and the option
a comment line. Empty and comment lines are ignored.</para> value. <literal>#</literal> may be used to start a comment line. Empty and comment lines are ignored. The
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
@ -50,7 +54,14 @@
<refsect1> <refsect1>
<title>Options</title> <title>Options</title>
<para>The following configuration options in <filename>loader.conf</filename> are understood:</para> <para>The configuration options supported by
<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'], ['linuxaa64.efi.stub', 'linuxia32.efi.stub', 'linuxx64.efi.stub', 'sd-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 if <filename>/boot/efi/</filename> during OS runtime, as well as from the Extended Boot Loader partition
it exists (usually mounted to <filename>/boot/</filename>). Configuration file fragments, kernels, (XBOOTLDR) if it exists (usually mounted to <filename>/boot/</filename>). Configuration file fragments,
initrds and other EFI images to boot generally need to reside on the ESP or the Extended Boot Loader kernels, initrds and other EFI images to boot generally need to reside on the ESP or the Extended Boot
partition. Linux kernels must be built with <option>CONFIG_EFI_STUB</option> to be able to be directly Loader partition. Linux kernels must be built with <option>CONFIG_EFI_STUB</option> to be able to be
executed as an EFI image. During boot <command>systemd-boot</command> automatically assembles a list of directly executed as an EFI image. During boot <command>systemd-boot</command> automatically assembles a
boot entries from the following sources:</para> list of 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,6 +17,7 @@
<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: <para>Trigger a specific type of devices. Valid types are <literal>all</literal>,
<command>devices</command>, <command>subsystems</command>. <literal>devices</literal>, and <literal>subsystems</literal>. The default value is
The default value is <command>devices</command>.</para> <literal>devices</literal>.</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
@ -297,6 +297,19 @@
</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>
@ -382,6 +395,35 @@
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,10 +51,12 @@ _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'
@ -117,7 +119,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='devices subsystems' comps='all 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:(devices subsystems failed)' \ '--type=[Trigger a specific type of devices.]:types:(all 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,7 +34,10 @@ _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.]' \
'--uuid[Print synthetic uevent UUID.]' '--initialized-match[Trigger events for devices that are already initialized.]' \
'--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 512U #define RANDOM_POOL_SIZE_MIN 32U
#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,6 +275,28 @@ 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);
@ -292,6 +314,23 @@ 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,7 +13,9 @@ 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,38 +144,70 @@ static int acquire_xbootldr(
return 1; return 1;
} }
static int load_install_machine_id_and_layout(void) { static int load_etc_machine_id(void) {
/* Figure out the right machine-id for operations. If KERNEL_INSTALL_MACHINE_ID is configured in int r;
* /etc/machine-info, let's use that. Otherwise, just use the real machine-id.
* r = sd_id128_get_machine(&arg_machine_id);
* Also load KERNEL_INSTALL_LAYOUT. if (IN_SET(r, -ENOENT, -ENOMEDIUM)) /* Not set or empty */
*/ 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 < 0 && r != -ENOENT) if (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)) {
r = sd_id128_get_machine(&arg_machine_id); log_notice("Read $KERNEL_INSTALL_MACHINE_ID from /etc/machine-info. Please move it to /etc/kernel/entry-token.");
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);
arg_install_layout = TAKE_PTR(layout); free_and_replace(arg_install_layout, 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;
@ -282,7 +314,15 @@ 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_install_machine_id_and_layout(); r = load_etc_machine_id();
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;
@ -1246,7 +1286,6 @@ 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;
@ -1256,13 +1295,9 @@ 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;
fd = open_tmpfile_linkable(p, O_WRONLY|O_CLOEXEC, &t); r = fopen_tmpfile_linkable(p, O_WRONLY|O_CLOEXEC, &t, &f);
if (fd < 0) if (r < 0)
return log_error_errno(fd, "Failed to open \"%s\" for writing: %m", p); return log_error_errno(r, "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");
@ -1272,11 +1307,36 @@ 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 = fflush_sync_and_check(f); r = flink_tmpfile(f, t, p);
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 write \"%s\": %m", p); return log_error_errno(r, "Failed to move \"%s\" into place: %m", p);
r = link_tmpfile(fileno(f), t, p); t = mfree(t);
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)
@ -1998,6 +2058,10 @@ 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();
@ -2037,6 +2101,10 @@ 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;
@ -2050,7 +2118,12 @@ static int verb_remove(int argc, char *argv[], void *userdata) {
r = q; r = q;
if (arg_xbootldr_path) { if (arg_xbootldr_path) {
/* Remove the latter two also in the XBOOTLDR partition if it exists */ /* Remove a subset of these also from 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,10 +155,29 @@ done
[ -z "$ENTRY_TOKEN" ] && ENTRY_TOKEN="$MACHINE_ID" [ -z "$ENTRY_TOKEN" ] && ENTRY_TOKEN="$MACHINE_ID"
if [ -z "$layout" ]; then if [ -z "$layout" ]; then
# Administrative decision: if not present, some scripts generate into /boot. # No layout configured by the administrator. Let's try to figure it out
if [ -d "$BOOT_ROOT/$ENTRY_TOKEN" ]; then # automatically from metadata already contained in $BOOT_ROOT.
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,11 +3,22 @@
#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); int device_enumerator_add_match_is_initialized(sd_device_enumerator *enumerator, MatchInitializedType type);
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,6 +20,7 @@
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;
@ -28,10 +29,13 @@ 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;
@ -40,7 +44,7 @@ struct sd_device_enumerator {
Set *match_sysname; Set *match_sysname;
Set *match_tag; Set *match_tag;
Set *match_parent; Set *match_parent;
bool match_allow_uninitialized; MatchInitializedType match_initialized;
}; };
_public_ int sd_device_enumerator_new(sd_device_enumerator **ret) { _public_ int sd_device_enumerator_new(sd_device_enumerator **ret) {
@ -55,6 +59,7 @@ _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);
@ -62,13 +67,29 @@ _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);
for (size_t i = 0; i < enumerator->n_devices; i++) device_enumerator_unref_devices(enumerator);
sd_device_unref(enumerator->devices[i]);
free(enumerator->devices); hashmap_free(enumerator->devices_by_syspath);
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);
@ -83,6 +104,24 @@ 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;
@ -206,82 +245,214 @@ _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_allow_uninitialized = true; enumerator->match_initialized = MATCH_INITIALIZED_ALL;
enumerator->scan_uptodate = false; enumerator->scan_uptodate = false;
return 1; return 1;
} }
int device_enumerator_add_match_is_initialized(sd_device_enumerator *enumerator) { int device_enumerator_add_match_is_initialized(sd_device_enumerator *enumerator, MatchInitializedType type) {
assert_return(enumerator, -EINVAL); assert_return(enumerator, -EINVAL);
assert_return(type >= 0 && type < _MATCH_INITIALIZED_MAX, -EINVAL);
enumerator->match_allow_uninitialized = false; enumerator->match_initialized = type;
enumerator->scan_uptodate = false; enumerator->scan_uptodate = false;
return 1; return 1;
} }
static int device_compare(sd_device * const *_a, sd_device * const *_b) { static int sound_device_compare(const char *devpath_a, const char *devpath_b) {
sd_device *a = *(sd_device **)_a, *b = *(sd_device **)_b; const char *sound_a, *sound_b;
const char *devpath_a, *devpath_b, *sound_a; size_t prefix_len;
bool delay_a, delay_b;
int r;
assert_se(sd_device_get_devpath(a, &devpath_a) >= 0); assert(devpath_a);
assert_se(sd_device_get_devpath(b, &devpath_b) >= 0); assert(devpath_b);
/* 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)
/* For sound cards the control device must be enumerated last to return 0;
* 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 = strchr(sound_a, '/');
if (sound_a) { sound_a += STRLEN("/sound/card");
unsigned prefix_len; sound_a = strchr(devpath_a, '/');
if (!sound_a)
return 0;
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))
const char *sound_b; return 0;
sound_b = devpath_b + prefix_len; sound_b = devpath_b + prefix_len;
r = CMP(!!startswith(sound_a, "/controlC"), return CMP(!!startswith(sound_a, "/controlC"),
!!startswith(sound_b, "/controlC")); !!startswith(sound_b, "/controlC"));
if (r != 0)
return r;
}
}
} }
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)
return r;
/* md and dm devices are enumerated after all other devices */ /* md and dm devices are enumerated after all other devices */
delay_a = strstr(devpath_a, "/block/md") || strstr(devpath_a, "/block/dm-"); r = CMP(devpath_is_late_block(devpath_a), devpath_is_late_block(devpath_b));
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);
if (!GREEDY_REALLOC(enumerator->devices, enumerator->n_devices + 1)) r = sd_device_get_syspath(device, &syspath);
return -ENOMEM; if (r < 0)
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) {
@ -344,10 +515,42 @@ 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 r = 0; int k, r = 0;
assert(enumerator); assert(enumerator);
assert(basedir); assert(basedir);
@ -368,7 +571,6 @@ 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;
@ -387,31 +589,13 @@ static int enumerator_scan_dir_and_add_devices(sd_device_enumerator *enumerator,
continue; continue;
} }
initialized = sd_device_get_is_initialized(device); k = match_initialized(enumerator, device);
if (initialized < 0) { if (k <= 0) {
if (initialized != -ENOENT) if (k < 0)
/* this is necessarily racey, so ignore missing devices */ r = k;
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;
@ -670,18 +854,10 @@ 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 r = 0; int k, 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");
@ -689,38 +865,10 @@ 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;
@ -730,10 +878,7 @@ 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;
for (size_t i = 0; i < enumerator->n_devices; i++) device_enumerator_unref_devices(enumerator);
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);
@ -749,9 +894,6 @@ 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;
@ -759,12 +901,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);
r = device_enumerator_scan_devices(enumerator); if (device_enumerator_scan_devices(enumerator) < 0)
if (r < 0) return NULL;
if (enumerator_sort_devices(enumerator) < 0)
return NULL; return NULL;
enumerator->current_device_index = 0; enumerator->current_device_index = 0;
@ -779,6 +921,7 @@ _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;
@ -787,7 +930,6 @@ _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);
@ -796,10 +938,7 @@ 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;
for (size_t i = 0; i < enumerator->n_devices; i++) device_enumerator_unref_devices(enumerator);
sd_device_unref(enumerator->devices[i]);
enumerator->n_devices = 0;
/* modules */ /* modules */
if (match_subsystem(enumerator, "module")) { if (match_subsystem(enumerator, "module")) {
@ -808,28 +947,20 @@ 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, subsysdir, NULL, NULL); k = enumerator_scan_dir_and_add_devices(enumerator, "bus", 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, subsysdir, "drivers", "drivers"); k = enumerator_scan_dir(enumerator, "bus", "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;
@ -837,12 +968,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);
r = device_enumerator_scan_subsystems(enumerator); if (device_enumerator_scan_subsystems(enumerator) < 0)
if (r < 0) return NULL;
if (enumerator_sort_devices(enumerator) < 0)
return NULL; return NULL;
enumerator->current_device_index = 0; enumerator->current_device_index = 0;
@ -857,6 +988,7 @@ _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;
@ -864,12 +996,67 @@ _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)
@ -882,6 +1069,7 @@ 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;
@ -895,6 +1083,9 @@ 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); r = device_enumerator_add_match_is_initialized(udev_enumerate->enumerator, MATCH_INITIALIZED_COMPAT);
if (r < 0) if (r < 0)
return r; return r;

View File

@ -11,6 +11,7 @@
#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"
@ -226,10 +227,14 @@ 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;
@ -240,6 +245,9 @@ 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[] = {
@ -257,16 +265,20 @@ 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;
@ -309,6 +321,8 @@ 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;
@ -405,6 +419,26 @@ 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':
@ -477,6 +511,11 @@ 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,5 +19,4 @@ ConditionPathIsReadWrite=/sys
[Service] [Service]
Type=oneshot Type=oneshot
RemainAfterExit=yes RemainAfterExit=yes
ExecStart=-udevadm trigger --type=subsystems --action=add ExecStart=-udevadm trigger --type=all --action=add --prioritized-subsystem=block,tpmrm
ExecStart=-udevadm trigger --type=devices --action=add