mirror of
https://github.com/systemd/systemd
synced 2026-04-23 15:34:50 +02:00
Compare commits
27 Commits
a321e0e463
...
93efd9cadb
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
93efd9cadb | ||
|
|
c0f6a6a542 | ||
|
|
d328346944 | ||
|
|
8bab619383 | ||
|
|
678f2b1667 | ||
|
|
d8b50e5df7 | ||
|
|
2336bde964 | ||
|
|
1baeee5784 | ||
|
|
873cf95c2f | ||
|
|
3c5cc23a93 | ||
|
|
37cf83d9bf | ||
|
|
95a6f969fc | ||
|
|
87c3a0f9f8 | ||
|
|
deac0c9c04 | ||
|
|
9e871965a0 | ||
|
|
41f630598d | ||
|
|
80889bd9cc | ||
|
|
a5b30e156a | ||
|
|
f6ad0282c9 | ||
|
|
cafa9d87b4 | ||
|
|
838f094ce7 | ||
|
|
d212b862bf | ||
|
|
84df0f315a | ||
|
|
ffc97a1cc4 | ||
|
|
354a244177 | ||
|
|
b72676e7a0 | ||
|
|
ea29abece9 |
16
NEWS
16
NEWS
@ -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.
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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',
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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 )
|
||||||
|
|||||||
@ -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] )) ||
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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;
|
||||||
|
|
||||||
|
|||||||
@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user