1
0
mirror of https://github.com/systemd/systemd synced 2026-04-24 07:55:12 +02:00

Compare commits

...

30 Commits

Author SHA1 Message Date
Yu Watanabe
f379362157
Merge pull request #22963 from poettering/udevadm-diskseq-fix
sd-device diskseq fix + udevadm info improvements
2022-04-05 03:57:24 +09:00
Yu Watanabe
cf708d803e
Merge pull request #22867 from poettering/lockdev-util
add small "udevadm lock" tool for locking a block device
2022-04-05 03:04:23 +09:00
Luca Boccassi
4e9a7022c5
Merge pull request #22960 from mrc0mmand/use-udevadm-wait
test: use the new `udevadm wait` verb to wait for the loop device
2022-04-04 18:39:59 +01:00
Lennart Poettering
6b41a7b281 tree-wide: use 'Architecture' type consistently across the tree
Some parts of our tree used 'Architecture' for storing architectures,
others used ints. Let's unify on the former.

Inspired by #22952's rework of the 'Virtualization' enum.
2022-04-05 02:19:37 +09:00
Lennart Poettering
b51f4eaf7b man: document various sd_device_get_xyz() functions 2022-04-04 18:25:18 +02:00
Lennart Poettering
7ba77d8f55 udevadm: if invalid devices are specified on "info" verb, continue
If multiple devices are specified on "udevadm info", then show data
about them all even if one is missing. Return first encountered error
though.
2022-04-04 18:25:18 +02:00
Lennart Poettering
13005c8f2c udevadm: add a dash of color to "udevadm info"
Let's make it easier to discern the "header" of device records from the
"body", i.e. non-property data from property data, by using some
conservative coloring.
2022-04-04 18:25:16 +02:00
Lennart Poettering
a0e902598c udevadm: show more fields of sd_device objects in "udevadm info"
Let's make things easier to debug, and show a more comprehensive set of
fields, extending on the existing output syntax that starts with one
marker character followed by a colon and a space.
2022-04-04 18:24:14 +02:00
Lennart Poettering
1ce0d04059 sd-device: actually read diskseq if told so
sd_device_get_diskseq() actually called device_read_uevent_file() but
that function didn't actually parse DISKSEQ= so far. Fix that.
2022-04-04 18:21:41 +02:00
Lennart Poettering
d4df6ce215 sd-device: rename return parameter of sd_device_get_devpath() to ret 2022-04-04 18:21:41 +02:00
Lennart Poettering
9858e6d2e7 man: properly conditionalize kernel-install man page
Change f887eab1da85d0053321d43228042d90720eb77e conditionalized the
building of ther kenel-install man page in the generated meson output,
instead of the source in the XML markup. Thus, whenever the rules file
is updated the conditionalization is lost. Correct that.

Follow-up for: f887eab1da85d0053321d43228042d90720eb77e
2022-04-05 01:20:35 +09:00
Franck Bui
6d7afa3b58 journald: make use of CLAMP() in cache_space_refresh() 2022-04-04 17:51:34 +02:00
Franck Bui
4bb37be07b journald: make sure journal_file_open() doesn't leave a corrupted file around after failing
This can be problematic especially when there's no more free disk
space. Consider the following:.

When disk space becomes sparse, writting to the system journal can lead to
error. In this case journald attempts to make room by rotating the journals,
which consists in archiving online journals and opening new ones.

However opening new files is likely to fail too and in this case
journal_file_open() leaves half initialized file around but in online
state. Then the error is propagated and journald switches into volatile mode.

Next time a new message is received by journald, it tries to open the
persistent system journal file to switch automatically back to persistent
mode.

When opening the system journal, journal_file_open(), called by
managed_journal_file_open_reliably(), finds the persistent system journal left
previously and assumes that it was uncleanly closed and considers it as
corrupted. The error is reported to managed_journal_file_open_reliably(), which
backs the file up and attempts to create a new system file, which fails and
leaves a corrupted system file again.

Since this is done for each message received by journald, /var/log/message can
be filled with backup files pretty quickly.

To prevent this, the patch makes sure to delete the newly created file in case
of error.
2022-04-04 17:51:10 +02:00
Lennart Poettering
ae61c53c3b man: document new udevadm lock tool 2022-04-04 17:19:51 +02:00
Lennart Poettering
8b12a516e9 udevadm: add new "lock" verb for locking block devices 2022-04-04 17:19:51 +02:00
Lennart Poettering
1748853700 hash-funcs: tweak odering in devt_compare_func()
Let's order dev_t's by their major first, minor secondary. The binary
encoding of the two fields is weirdly interleaved and different in
kernel and glibc, hence let's focus on the generic part that works like
users would expect it.

So far the function is only used to compare for equality, not for
sorting, hence this has no immediate effect.
2022-04-04 17:04:14 +02:00
Lennart Poettering
666efe94c9 TODO 2022-04-04 16:07:26 +02:00
Frantisek Sumsal
9b264c1dfa partition: use udevadm wait 2022-04-04 15:59:40 +02:00
Frantisek Sumsal
c189d3bd78 test: use the new udevadm wait verb to wait for the loop device
The original workaround didn't work, as `systemd-repart` kept failing
 even when the `/dev/loopX` device was present:

 ```
 [   13.959419] H testsuite-58.sh[280]: + LOOP=/dev/loop1
 [   13.959636] H testsuite-58.sh[280]: + :
 [   13.959764] H testsuite-58.sh[280]: + test -e /dev/loop1
 [   13.959895] H testsuite-58.sh[280]: + break
 [   13.960023] H testsuite-58.sh[280]: + systemd-repart --pretty=yes --definitions=/tmp/testsuite-58-sector/ --seed=750b6cd5c4ae4012a15e7be3c29e6a47 --empty=require --dry-run=no /dev/loop1
 [   13.970538] H testsuite-58.sh[363]: Device '/dev/loop1' has no dm-crypt/dm-verity device, no need to look for underlying block device.
 [   13.970538] H testsuite-58.sh[363]: Failed to determine canonical path for '/dev/loop1': No such file or directory
 [   13.970538] H testsuite-58.sh[363]: Failed to open file or determine backing device of /dev/loop1: No such file or directory
 ```
2022-04-04 15:58:03 +02:00
Yu Watanabe
f3e5c781f3
Merge pull request #22943 from yuwata/dhcp6-client-requet-options
sd-dhcp6-client: requet options
2022-04-04 22:55:02 +09:00
Yu Watanabe
d315b47e2d
Merge pull request #22952 from poettering/rework-kvm-hyperv
virt: tweak kvm with hyperv enlightenments
2022-04-04 22:53:56 +09:00
Lennart Poettering
cc97a3a5e8 gpt: introduce common implementation of type uuid search loop 2022-04-04 22:50:48 +09:00
Lennart Poettering
0ee2d5b2a9 virt: move array iterators to smaller scope, and use right type 2022-04-04 11:36:26 +02:00
Lennart Poettering
1b86c7c59e virt: make virtualization enum a named type
These days we have a mechanism for safely returning errnos in enum
types, via definining -ERRNO_MAX as one special enu value. Let's use
that for Virtualization.

No change in behaviour, just some typesafety improvement.
2022-04-04 11:36:26 +02:00
Lennart Poettering
0f534758d1 virt: rework kvm with hyperv enlightenment checks a bit
Let's avoid extending the virtualization with an "alias" entry that has
the same string assigned as another.

The only reason this was done was to make the patch small that added a
second CPUID vendor string for kvm to the vm_table[] array. Let's
instead rework the array to use struct elements that match up strings
with ids. Given the array was previously mostly sparse this should be a
general improvement.

Fixes: #22950
Follow-up for: #22945
2022-04-04 11:28:56 +02:00
Yu Watanabe
822883b3e7 sd-dhcp6-client: request several options
Even though these options are not currently used by sd-dhcp6-client,
RFC 8415 states these options MUST be requested.
2022-04-04 01:22:02 +09:00
Yu Watanabe
612caa2626 network: dhcp6: request DNS servers or friends only when they will be used 2022-04-03 19:55:25 +09:00
Yu Watanabe
f697ab358a dhcp: make option names singular 2022-04-03 19:50:02 +09:00
Yu Watanabe
0e0c4daea6 sd-dhcp6-client: sort requesting options 2022-04-03 19:23:03 +09:00
Yu Watanabe
2f53b311c3 sd-dhcp6-client: rename req_opts_len -> n_req_opts
As 'len' is confusing and we may misunderstand it as the size of
the buffer instead of the number of options.
2022-04-03 19:23:03 +09:00
46 changed files with 1263 additions and 322 deletions

5
TODO
View File

@ -78,7 +78,10 @@ Janitorial Clean-ups:
Features:
* bootctl: show whether audit mode is available
* udevadm: a new "tree" verb that shows tree of devices as syspath hierarchy,
along with their properties. uninitialized devices should be greyed out.
* bootctl: show whether UEFI audit mode is available
* dissect: rework how we access partitions: instead of letting the kernel probe
partition tables asynchronously, just pass the stuff we parsed in userspace

View File

@ -75,6 +75,25 @@ And please keep in mind: BSD file locks (`flock()`) and POSIX file locks
orthogonal. The scheme discussed above uses the former and not the latter,
because these types of locks more closely match the required semantics.
If multiple devices are to be locked at the same time (for example in order to
format a RAID file system), the devices should be locked in the order of the
the device nodes' major numbers (primary ordering key, ascending) and minor
numbers (secondary ordering key, ditto), in order to avoid ABBA locking issues
between subsystems.
Note that the locks should only be taken while the device is repartitioned,
file systems formatted or `dd`'ed in, and similar cases that
apply/remove/change superblocks/partition information. It should not be held
during normal operation, i.e. while file systems on it are mounted for
application use.
The [`udevadm
lock`](https://www.freedesktop.org/software/systemd/man/udevadm.html) command
is provided to lock block devices following this scheme from the command line,
for the use in scripts and similar. (Note though that it's typically preferable
to use native support for block device locking in tools where that's
available.)
Summarizing: it is recommended to take `LOCK_EX` BSD file locks when
manipulating block devices in all tools that change file system block devices
(`mkfs`, `fsck`, …) or partition tables (`fdisk`, `parted`, …), right after

View File

@ -3,7 +3,7 @@
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
<!-- SPDX-License-Identifier: LGPL-2.1-or-later -->
<refentry id="kernel-install"
<refentry id="kernel-install" conditional='ENABLE_KERNEL_INSTALL'
xmlns:xi="http://www.w3.org/2001/XInclude">
<refentryinfo>

View File

@ -502,6 +502,19 @@ manpages = [
'sd_bus_track_unrefp'],
''],
['sd_bus_wait', '3', [], ''],
['sd_device_get_syspath',
'3',
['sd_device_get_devname',
'sd_device_get_devnum',
'sd_device_get_devpath',
'sd_device_get_devtype',
'sd_device_get_diskseq',
'sd_device_get_driver',
'sd_device_get_ifindex',
'sd_device_get_subsystem',
'sd_device_get_sysname',
'sd_device_get_sysnum'],
''],
['sd_event_add_child',
'3',
['sd_event_add_child_pidfd',

View File

@ -0,0 +1,200 @@
<?xml version='1.0'?> <!--*-nxml-*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
<!-- SPDX-License-Identifier: LGPL-2.1-or-later -->
<refentry id="sd_device_get_syspath"
xmlns:xi="http://www.w3.org/2001/XInclude">
<refentryinfo>
<title>sd_device_get_syspath</title>
<productname>systemd</productname>
</refentryinfo>
<refmeta>
<refentrytitle>sd_device_get_syspath</refentrytitle>
<manvolnum>3</manvolnum>
</refmeta>
<refnamediv>
<refname>sd_device_get_syspath</refname>
<refname>sd_device_get_devpath</refname>
<refname>sd_device_get_sysname</refname>
<refname>sd_device_get_sysnum</refname>
<refname>sd_device_get_subsystem</refname>
<refname>sd_device_get_devtype</refname>
<refname>sd_device_get_devname</refname>
<refname>sd_device_get_devnum</refname>
<refname>sd_device_get_ifindex</refname>
<refname>sd_device_get_driver</refname>
<refname>sd_device_get_diskseq</refname>
<refpurpose>Returns various fields of device objects</refpurpose>
</refnamediv>
<refsynopsisdiv>
<funcsynopsis>
<funcsynopsisinfo>#include &lt;systemd/sd-device.h&gt;</funcsynopsisinfo>
<funcprototype>
<funcdef>int <function>sd_device_get_syspath</function></funcdef>
<paramdef>sd_device *<parameter>device</parameter></paramdef>
<paramdef>const char **<parameter>ret</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>int <function>sd_device_get_devpath</function></funcdef>
<paramdef>sd_device *<parameter>device</parameter></paramdef>
<paramdef>const char **<parameter>ret</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>int <function>sd_device_get_sysname</function></funcdef>
<paramdef>sd_device *<parameter>device</parameter></paramdef>
<paramdef>const char **<parameter>ret</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>int <function>sd_device_get_sysnum</function></funcdef>
<paramdef>sd_device *<parameter>device</parameter></paramdef>
<paramdef>const char **<parameter>ret</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>int <function>sd_device_get_subsystem</function></funcdef>
<paramdef>sd_device *<parameter>device</parameter></paramdef>
<paramdef>const char **<parameter>ret</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>int <function>sd_device_get_devtype</function></funcdef>
<paramdef>sd_device *<parameter>device</parameter></paramdef>
<paramdef>const char **<parameter>ret</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>int <function>sd_device_get_devname</function></funcdef>
<paramdef>sd_device *<parameter>device</parameter></paramdef>
<paramdef>const char **<parameter>ret</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>int <function>sd_device_get_devnum</function></funcdef>
<paramdef>sd_device *<parameter>device</parameter></paramdef>
<paramdef>dev_t *<parameter>ret</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>int <function>sd_device_get_ifindex</function></funcdef>
<paramdef>sd_device *<parameter>device</parameter></paramdef>
<paramdef>int *<parameter>ret</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>int <function>sd_device_get_driver</function></funcdef>
<paramdef>sd_device *<parameter>device</parameter></paramdef>
<paramdef>const char **<parameter>ret</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>int <function>sd_device_get_diskseq</function></funcdef>
<paramdef>sd_device *<parameter>device</parameter></paramdef>
<paramdef>uint64_t *<parameter>ret</parameter></paramdef>
</funcprototype>
</funcsynopsis>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
<para><function>sd_device_get_syspath()</function> returns the sysfs path of the specified device record,
including the <filename>/sys</filename> prefix. Example: <filename>/sys/devices/virtual/tty/tty7</filename></para>
<para><function>sd_device_get_devpath()</function> returns the sysfs path of the specified device record,
excluding the <filename>/sys</filename> prefix. Example: <filename>/devices/virtual/tty/tty7</filename></para>
<para><function>sd_device_get_sysname()</function> returns the sysfs name of the specified device record,
i.e. the last component of the sysfs path. Example: <literal>tty7</literal> for the device
<filename>/sys/devices/virtual/tty/tty7</filename></para>
<para><function>sd_device_get_sysnum()</function> returns the sysfs device number of the specified device
record, i.e. the numeric suffix of the last component of the sysfs path. Example: <literal>7</literal>
for the device <filename>/sys/devices/virtual/tty/tty7</filename></para>
<para><function>sd_device_get_subsystem()</function> returns the kernel subsystem of the specified device
record. This is a short string fitting into a filename, and thus does not contain a slash and cannot be
empty. Example: <literal>tty</literal>, <literal>block</literal> or <literal>net</literal>.</para>
<para><function>sd_device_get_devtype()</function> returns the device type of the specified device
record, if the subsystem manages multiple types of devices. Example: for devices of the
<literal>block</literal> subsystem this can be <literal>disk</literal> or <literal>partition</literal>
</para>
<para><function>sd_device_get_devname()</function> returns the device node path of the specified device
record if the device has a device node. Example: for <filename>/sys/devices/virtual/tty/tty7</filename>
the string <filename>/dev/tty7</filename> is typically returned.</para>
<para><function>sd_device_get_devnum()</function> returns the device node major/minor
(i.e. <type>dev_t</type>) of the specified device record if the device has a device node (i.e. the one
returned by <function>sd_device_get_devname()</function>). For devices belonging to the
<literal>block</literal> subsystem this refers to a block device node, in all other cases to a character
device node. Example: for the <filename>/sys/devices/virtual/tty/tty7</filename> device this typically
returns the device number with major/minor <literal>4:7</literal>.</para>
<para><function>sd_device_get_ifindex()</function> returns the network interface index of the specified
device record, if the device encapsulates a network interface device, i.e. belongs to the
<literal>net</literal> subsystem. Example: the <literal>lo</literal> interface typically has interface
index 1.</para>
<para><function>sd_device_get_driver()</function> returns the kernel driver name attached to the
device. Note that the driver field is set on the devices consumed by the driver, not on the device
created by it. Example: a PCI device <filename>/sys/bus/pci/devices/0000:00:1f.6</filename> might be
attached to a driver <literal>e1000e</literal>.</para>
<para><function>sd_device_get_diskseq()</function> returns the kernel disk sequence number of the block
device. This number monotonically increases whenever a backing medium of a block device changes without
the device name changing, and is relevant for block devices encapsulating devices with changing media
(e.g. floppy or CD-ROM), or loopback block devices. Only defined for block devices, i.e. those of
subsystem <literal>block</literal>.</para>
</refsect1>
<refsect1>
<title>Return Value</title>
<para>On success, these calls return 0 or a positive integer. On failure, they return a negative
errno-style error code.</para>
<refsect2>
<title>Errors</title>
<para>Returned errors may indicate the following problems:</para>
<variablelist>
<varlistentry>
<term><constant>-EINVAL</constant></term>
<listitem><para>A specified parameter is invalid.</para></listitem>
</varlistentry>
<varlistentry>
<term><constant>-ENOENT</constant></term>
<listitem><para>The requested field is not present in the device record.</para></listitem>
</varlistentry>
</variablelist>
</refsect2>
</refsect1>
<xi:include href="libsystemd-pkgconfig.xml" />
<refsect1>
<title>See Also</title>
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>
</para>
</refsect1>
</refentry>

View File

@ -51,6 +51,9 @@
<cmdsynopsis>
<command>udevadm wait <optional>options</optional> <replaceable>device|syspath</replaceable></command>
</cmdsynopsis>
<cmdsynopsis>
<command>udevadm lock <optional>options</optional> <replaceable>command</replaceable></command>
</cmdsynopsis>
</refsynopsisdiv>
<refsect1><title>Description</title>
@ -227,6 +230,30 @@
<entry><literal>P:</literal></entry>
<entry>Device path in <filename>/sys/</filename></entry>
</row>
<row>
<entry><literal>M:</literal></entry>
<entry>Device name in <filename>/sys/</filename> (i.e. the last component of <literal>P:</literal>)</entry>
</row>
<row>
<entry><literal>R:</literal></entry>
<entry>Device number in <filename>/sys/</filename> (i.e. the numeric suffix of the last component of <literal>P:</literal>)</entry>
</row>
<row>
<entry><literal>U:</literal></entry>
<entry>Kernel subsystem</entry>
</row>
<row>
<entry><literal>T:</literal></entry>
<entry>Kernel device type within subsystem</entry>
</row>
<row>
<entry><literal>D:</literal></entry>
<entry>Kernel device node major/minor</entry>
</row>
<row>
<entry><literal>I:</literal></entry>
<entry>Network interface index</entry>
</row>
<row>
<entry><literal>N:</literal></entry>
<entry>Kernel device node name</entry>
@ -239,6 +266,14 @@
<entry><literal>S:</literal></entry>
<entry>Device node symlink</entry>
</row>
<row>
<entry><literal>Q:</literal></entry>
<entry>Block device sequence number (DISKSEQ)</entry>
</row>
<row>
<entry><literal>V:</literal></entry>
<entry>Attached driver</entry>
</row>
<row>
<entry><literal>E:</literal></entry>
<entry>Device property</entry>
@ -747,6 +782,87 @@
<xi:include href="standard-options.xml" xpointer="help" />
</variablelist>
</refsect2>
<refsect2>
<title>udevadm lock
<arg choice="opt"><replaceable>options</replaceable></arg>
<arg choice="opt"><replaceable>command</replaceable></arg>
</title>
<para><command>udevadm lock</command> takes an (advisory) exclusive lock(s) on a block device (or
multiple therof), as per <ulink url="https://systemd.io/BLOCK_DEVICE_LOCKING">Locking Block Device
Access</ulink> and invokes a program with the lock(s) taken. When the invoked program exits the lock(s)
are automatically released.</para>
<para>This tool is in particular useful to ensure that
<citerefentry><refentrytitle>systemd-udevd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
does not probe a block device while changes are made to it, for example partitions created or file
systems formatted. Note that many tools that interface with block devices natively support taking
relevant locks, see for example
<citerefentry><refentrytitle>sfdisk</refentrytitle><manvolnum>8</manvolnum></citerefentry>'s
<option>--lock</option> switch.</para>
<para>The command expects at least one block device specified via <option>--device=</option> or
<option>--backing=</option>, and a command line to execute as arguments.</para>
<variablelist>
<varlistentry>
<term><option>--device=<replaceable>DEVICE</replaceable></option></term>
<term><option>-d <replaceable>DEVICE</replaceable></option></term>
<listitem><para>Takes a path to a device node of the device to lock. This switch may be used
multiple times (and in combination with <option>--backing=</option>) in order to lock multiple
devices. If a partition block device node is specified the containing "whole" block device is
automatically determined and used for the lock, as per the specification. If multiple devices are
specified, they are deduplicated, sorted by the major/minor of their device nodes and then locked
in order.</para>
<para>This switch must be used at least once, to specify at least one device to
lock. (Alternatively, use <option>--backing=</option>, see below.)</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--backing=<replaceable>PATH</replaceable></option></term>
<term><option>-b <replaceable>PATH</replaceable></option></term>
<listitem><para>If a path to a device node is specified, identical to
<option>--device=</option>. However, this switch alternatively accepts a path to a regular file or
directory, in which case the block device of the file system the file/directory resides on is
automatically determined and used as if it was specified with
<option>--device=</option>.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--timeout=<replaceable>SECS</replaceable></option></term>
<term><option>-t <replaceable>SECS</replaceable></option></term>
<listitem><para>Specifies how long to wait at most until all locks can be taken. Takes a value in
seconds, or in the usual supported time units, see
<citerefentry><refentrytitle>systemd.time</refentrytitle><manvolnum>7</manvolnum></citerefentry>. If
specified as zero the lock is attempted and if not successful the invocation will immediately
fail. If passed as <literal>infinity</literal> (the default) the invocation will wait indefinitely
until the lock can be acquired. If the lock cannot be taken in the specified time the specified
command will not be executed and the invocation will fail.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--print</option></term>
<term><option>-p</option></term>
<listitem><para>Instead of locking the specified device(s) and executing a command, just print the
device path(s) that would be locked, and execute no command. This command is useful to determine
the "whole" block device in case a partition block device is specified. The devices will be sorted
by their device node major number as primary ordering key and the minor number as secondary
ordering key (i.e. they are shown in the order they'd be locked). Note that the number of lines
printed here can be less than the the number of <option>--device=</option> and
<option>--backing=</option> switches specified in case these resolve to the same "whole"
devices.</para></listitem>
</varlistentry>
<xi:include href="standard-options.xml" xpointer="help" />
</variablelist>
</refsect2>
</refsect1>
<refsect1>
@ -760,6 +876,38 @@
still be announced via the sd-device API (or similar).</para>
</refsect1>
<refsect1>
<title>Example</title>
<example>
<title>Format a File System</title>
<para>Take a lock on the backing block device while creating a file system, to ensure that
<command>systemd-udevd</command> doesn't probe or announce the new superblock before it is
comprehensively written:</para>
<programlisting># udevadm lock --device=/dev/sda1 mkfs.ext4 /dev/sda1</programlisting>
</example>
<example>
<title>Format a RAID File System</title>
<para>Similar, but take locks on multiple devices at once:</para>
<programlisting># udevadm lock --device=/dev/sda1 --device=/dev/sdb1 mkfs.btrfs /dev/sda1 /dev/sdb1</programlisting>
</example>
<example>
<title>Copy in a File System</title>
<para>Take a lock on the backing block device while copying in a prepared file system image, to ensure
that <command>systemd-udevd</command> doesn't probe or announce the new superblock before it is fully
written:</para>
<programlisting># udevadm lock -d /dev/sda1 dd if=fs.raw of=/dev/sda1</programlisting>
</example>
</refsect1>
<refsect1>
<title>See Also</title>
<para><citerefentry>

View File

@ -3076,27 +3076,6 @@ if conf.get('ENABLE_BINFMT') == 1
endif
endif
if conf.get('ENABLE_REPART') == 1
exe = executable(
'systemd-repart',
systemd_repart_sources,
include_directories : includes,
link_with : [libshared],
dependencies : [threads,
libblkid,
libfdisk],
install_rpath : rootlibexecdir,
install : true,
install_dir : rootbindir)
public_programs += exe
if want_tests != 'false'
test('test-repart',
test_repart_sh,
args : exe.full_path())
endif
endif
if conf.get('ENABLE_SYSUPDATE') == 1
exe = executable(
'systemd-sysupdate',
@ -3517,7 +3496,7 @@ public_programs += executable(
install : true,
install_dir : rootlibexecdir)
public_programs += executable(
udevadm = executable(
'udevadm',
udevadm_sources,
include_directories : includes,
@ -3531,6 +3510,28 @@ public_programs += executable(
install_rpath : udev_rpath,
install : true,
install_dir : rootbindir)
public_programs += udevadm
if conf.get('ENABLE_REPART') == 1
exe = executable(
'systemd-repart',
systemd_repart_sources,
include_directories : includes,
link_with : [libshared],
dependencies : [threads,
libblkid,
libfdisk],
install_rpath : rootlibexecdir,
install : true,
install_dir : rootbindir)
public_programs += exe
if want_tests != 'false'
test('test-repart',
test_repart_sh,
args : [exe.full_path(), udevadm.full_path()])
endif
endif
executable(
'systemd-shutdown',

View File

@ -7,7 +7,7 @@
#include "string-table.h"
#include "string-util.h"
int uname_architecture(void) {
Architecture uname_architecture(void) {
/* Return a sanitized enum identifying the architecture we are running on. This
* is based on uname(), and the user may hence control what this returns by using
@ -22,7 +22,7 @@ int uname_architecture(void) {
static const struct {
const char *machine;
int arch;
Architecture arch;
} arch_map[] = {
#if defined(__aarch64__) || defined(__arm__)
{ "aarch64", ARCHITECTURE_ARM64 },
@ -122,7 +122,7 @@ int uname_architecture(void) {
#endif
};
static int cached = _ARCHITECTURE_INVALID;
static Architecture cached = _ARCHITECTURE_INVALID;
struct utsname u;
if (cached != _ARCHITECTURE_INVALID)
@ -175,4 +175,4 @@ static const char *const architecture_table[_ARCHITECTURE_MAX] = {
[ARCHITECTURE_TILEGX] = "tilegx",
};
DEFINE_STRING_TABLE_LOOKUP(architecture, int);
DEFINE_STRING_TABLE_LOOKUP(architecture, Architecture);

View File

@ -48,7 +48,7 @@ typedef enum {
_ARCHITECTURE_INVALID = -EINVAL,
} Architecture;
int uname_architecture(void);
Architecture uname_architecture(void);
/*
* LIB_ARCH_TUPLE should resolve to the local library path
@ -243,5 +243,5 @@ int uname_architecture(void);
# error "Please register your architecture here!"
#endif
const char *architecture_to_string(int a) _const_;
int architecture_from_string(const char *s) _pure_;
const char *architecture_to_string(Architecture a) _const_;
Architecture architecture_from_string(const char *s) _pure_;

View File

@ -102,10 +102,16 @@ DEFINE_HASH_OPS(uint64_hash_ops, uint64_t, uint64_hash_func, uint64_compare_func
void devt_hash_func(const dev_t *p, struct siphash *state) {
siphash24_compress(p, sizeof(dev_t), state);
}
#endif
int devt_compare_func(const dev_t *a, const dev_t *b) {
return CMP(*a, *b);
int r;
r = CMP(major(*a), major(*b));
if (r != 0)
return r;
return CMP(minor(*a), minor(*b));
}
DEFINE_HASH_OPS(devt_hash_ops, dev_t, devt_hash_func, devt_compare_func);
#endif

View File

@ -102,10 +102,9 @@ extern const struct hash_ops uint64_hash_ops;
* 64bit archs. Yuck! */
#if SIZEOF_DEV_T != 8
void devt_hash_func(const dev_t *p, struct siphash *state) _pure_;
int devt_compare_func(const dev_t *a, const dev_t *b) _pure_;
extern const struct hash_ops devt_hash_ops;
#else
#define devt_hash_func uint64_hash_func
#define devt_compare_func uint64_compare_func
#define devt_hash_ops uint64_hash_ops
#endif
int devt_compare_func(const dev_t *a, const dev_t *b) _pure_;
extern const struct hash_ops devt_hash_ops;

View File

@ -1026,7 +1026,7 @@ bool oom_score_adjust_is_valid(int oa) {
}
unsigned long personality_from_string(const char *p) {
int architecture;
Architecture architecture;
if (!p)
return PERSONALITY_INVALID;
@ -1050,7 +1050,7 @@ unsigned long personality_from_string(const char *p) {
}
const char* personality_to_string(unsigned long p) {
int architecture = _ARCHITECTURE_INVALID;
Architecture architecture = _ARCHITECTURE_INVALID;
if (p == PER_LINUX)
architecture = native_architecture();

View File

@ -28,31 +28,30 @@ enum {
SMBIOS_VM_BIT_UNKNOWN,
};
#if defined(__i386__) || defined(__x86_64__)
static const char *const vm_table[_VIRTUALIZATION_MAX] = {
[VIRTUALIZATION_XEN] = "XenVMMXenVMM",
[VIRTUALIZATION_KVM] = "KVMKVMKVM",
[VIRTUALIZATION_HV_KVM] = "Linux KVM Hv",
[VIRTUALIZATION_QEMU] = "TCGTCGTCGTCG",
/* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
[VIRTUALIZATION_VMWARE] = "VMwareVMware",
/* https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/reference/tlfs */
[VIRTUALIZATION_MICROSOFT] = "Microsoft Hv",
/* https://wiki.freebsd.org/bhyve */
[VIRTUALIZATION_BHYVE] = "bhyve bhyve ",
[VIRTUALIZATION_QNX] = "QNXQVMBSQG",
/* https://projectacrn.org */
[VIRTUALIZATION_ACRN] = "ACRNACRNACRN",
};
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(vm, int);
#endif
static int detect_vm_cpuid(void) {
static Virtualization detect_vm_cpuid(void) {
/* CPUID is an x86 specific interface. */
#if defined(__i386__) || defined(__x86_64__)
static const struct {
const char sig[13];
Virtualization id;
} vm_table[] = {
{ "XenVMMXenVMM", VIRTUALIZATION_XEN },
{ "KVMKVMKVM", VIRTUALIZATION_KVM }, /* qemu with KVM */
{ "Linux KVM Hv", VIRTUALIZATION_KVM }, /* qemu with KVM + HyperV Enlightenments */
{ "TCGTCGTCGTCG", VIRTUALIZATION_QEMU }, /* qemu without KVM */
/* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
{ "VMwareVMware", VIRTUALIZATION_VMWARE },
/* https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/reference/tlfs */
{ "Microsoft Hv", VIRTUALIZATION_MICROSOFT },
/* https://wiki.freebsd.org/bhyve */
{ "bhyve bhyve ", VIRTUALIZATION_BHYVE },
{ "QNXQVMBSQG", VIRTUALIZATION_QNX },
/* https://projectacrn.org */
{ "ACRNACRNACRN", VIRTUALIZATION_ACRN },
};
uint32_t eax, ebx, ecx, edx;
bool hypervisor;
@ -69,7 +68,6 @@ static int detect_vm_cpuid(void) {
uint32_t sig32[3];
char text[13];
} sig = {};
int v;
/* There is a hypervisor, see what it is */
__cpuid(0x40000000U, eax, ebx, ecx, edx);
@ -80,11 +78,13 @@ static int detect_vm_cpuid(void) {
log_debug("Virtualization found, CPUID=%s", sig.text);
v = vm_from_string(sig.text);
if (v < 0)
return VIRTUALIZATION_VM_OTHER;
for (size_t i = 0; i < ELEMENTSOF(vm_table); i++)
if (memcmp_nn(sig.text, sizeof(sig.text),
vm_table[i].sig, sizeof(vm_table[i].sig)) == 0)
return vm_table[i].id;
return v;
log_debug("Unknown virtualization with CPUID=%s. Add to vm_table[]?", sig.text);
return VIRTUALIZATION_VM_OTHER;
}
#endif
log_debug("No virtualization found in CPUID");
@ -92,7 +92,7 @@ static int detect_vm_cpuid(void) {
return VIRTUALIZATION_NONE;
}
static int detect_vm_device_tree(void) {
static Virtualization detect_vm_device_tree(void) {
#if defined(__arm__) || defined(__aarch64__) || defined(__powerpc__) || defined(__powerpc64__)
_cleanup_free_ char *hvtype = NULL;
int r;
@ -142,7 +142,7 @@ static int detect_vm_device_tree(void) {
}
#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__aarch64__) || defined(__loongarch64)
static int detect_vm_dmi_vendor(void) {
static Virtualization detect_vm_dmi_vendor(void) {
static const char *const dmi_vendors[] = {
"/sys/class/dmi/id/product_name", /* Test this before sys_vendor to detect KVM over QEMU */
"/sys/class/dmi/id/sys_vendor",
@ -153,7 +153,7 @@ static int detect_vm_dmi_vendor(void) {
static const struct {
const char *vendor;
int id;
Virtualization id;
} dmi_vendor_table[] = {
{ "KVM", VIRTUALIZATION_KVM },
{ "Amazon EC2", VIRTUALIZATION_AMAZON },
@ -173,7 +173,6 @@ static int detect_vm_dmi_vendor(void) {
for (size_t i = 0; i < ELEMENTSOF(dmi_vendors); i++) {
_cleanup_free_ char *s = NULL;
unsigned j;
r = read_one_line_file(dmi_vendors[i], &s);
if (r < 0) {
@ -183,7 +182,7 @@ static int detect_vm_dmi_vendor(void) {
return r;
}
for (j = 0; j < ELEMENTSOF(dmi_vendor_table); j++)
for (size_t j = 0; j < ELEMENTSOF(dmi_vendor_table); j++)
if (startswith(s, dmi_vendor_table[j].vendor)) {
log_debug("Virtualization %s found in DMI (%s)", s, dmi_vendors[i]);
return dmi_vendor_table[j].id;
@ -230,7 +229,7 @@ static int detect_vm_smbios(void) {
}
#endif /* defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__aarch64__) || defined(__loongarch64) */
static int detect_vm_dmi(void) {
static Virtualization detect_vm_dmi(void) {
#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__aarch64__) || defined(__loongarch64)
int r;
@ -332,7 +331,7 @@ static int detect_vm_xen_dom0(void) {
}
}
static int detect_vm_xen(void) {
static Virtualization detect_vm_xen(void) {
/* The presence of /proc/xen indicates some form of a Xen domain
The check for Dom0 is handled outside this function */
if (access("/proc/xen", F_OK) < 0) {
@ -343,7 +342,7 @@ static int detect_vm_xen(void) {
return VIRTUALIZATION_XEN;
}
static int detect_vm_hypervisor(void) {
static Virtualization detect_vm_hypervisor(void) {
_cleanup_free_ char *hvtype = NULL;
int r;
@ -361,7 +360,7 @@ static int detect_vm_hypervisor(void) {
return VIRTUALIZATION_VM_OTHER;
}
static int detect_vm_uml(void) {
static Virtualization detect_vm_uml(void) {
_cleanup_fclose_ FILE *f = NULL;
int r;
@ -400,7 +399,7 @@ static int detect_vm_uml(void) {
return VIRTUALIZATION_NONE;
}
static int detect_vm_zvm(void) {
static Virtualization detect_vm_zvm(void) {
#if defined(__s390__)
_cleanup_free_ char *t = NULL;
@ -424,10 +423,11 @@ static int detect_vm_zvm(void) {
}
/* Returns a short identifier for the various VM implementations */
int detect_vm(void) {
static thread_local int cached_found = _VIRTUALIZATION_INVALID;
Virtualization detect_vm(void) {
static thread_local Virtualization cached_found = _VIRTUALIZATION_INVALID;
bool other = false;
int r, dmi, xen_dom0 = 0;
int xen_dom0 = 0;
Virtualization v, dmi;
if (cached_found >= 0)
return cached_found;
@ -446,22 +446,22 @@ int detect_vm(void) {
dmi = detect_vm_dmi();
if (IN_SET(dmi, VIRTUALIZATION_ORACLE, VIRTUALIZATION_XEN, VIRTUALIZATION_AMAZON)) {
r = dmi;
v = dmi;
goto finish;
}
/* Detect UML */
r = detect_vm_uml();
if (r < 0)
return r;
if (r != VIRTUALIZATION_NONE)
v = detect_vm_uml();
if (v < 0)
return v;
if (v != VIRTUALIZATION_NONE)
goto finish;
/* Detect Xen */
r = detect_vm_xen();
if (r < 0)
return r;
if (r == VIRTUALIZATION_XEN) {
v = detect_vm_xen();
if (v < 0)
return v;
if (v == VIRTUALIZATION_XEN) {
/* If we are Dom0, then we expect to not report as a VM. However, as we might be nested
* inside another hypervisor which can be detected via the CPUID check, wait to report this
* until after the CPUID check. */
@ -471,17 +471,17 @@ int detect_vm(void) {
if (xen_dom0 == 0)
goto finish;
r = VIRTUALIZATION_NONE;
} else if (r != VIRTUALIZATION_NONE)
v = VIRTUALIZATION_NONE;
} else if (v != VIRTUALIZATION_NONE)
assert_not_reached();
/* Detect from CPUID */
r = detect_vm_cpuid();
if (r < 0)
return r;
if (r == VIRTUALIZATION_VM_OTHER)
v = detect_vm_cpuid();
if (v < 0)
return v;
if (v == VIRTUALIZATION_VM_OTHER)
other = true;
else if (r != VIRTUALIZATION_NONE)
else if (v != VIRTUALIZATION_NONE)
goto finish;
/* If we are in Dom0 and have not yet finished, finish with the result of detect_vm_cpuid */
@ -494,38 +494,38 @@ int detect_vm(void) {
if (dmi == VIRTUALIZATION_VM_OTHER)
other = true;
else if (dmi != VIRTUALIZATION_NONE) {
r = dmi;
v = dmi;
goto finish;
}
/* Check high-level hypervisor sysfs file */
r = detect_vm_hypervisor();
if (r < 0)
return r;
if (r == VIRTUALIZATION_VM_OTHER)
v = detect_vm_hypervisor();
if (v < 0)
return v;
if (v == VIRTUALIZATION_VM_OTHER)
other = true;
else if (r != VIRTUALIZATION_NONE)
else if (v != VIRTUALIZATION_NONE)
goto finish;
r = detect_vm_device_tree();
if (r < 0)
return r;
if (r == VIRTUALIZATION_VM_OTHER)
v = detect_vm_device_tree();
if (v < 0)
return v;
if (v == VIRTUALIZATION_VM_OTHER)
other = true;
else if (r != VIRTUALIZATION_NONE)
else if (v != VIRTUALIZATION_NONE)
goto finish;
r = detect_vm_zvm();
if (r < 0)
return r;
v = detect_vm_zvm();
if (v < 0)
return v;
finish:
if (r == VIRTUALIZATION_NONE && other)
r = VIRTUALIZATION_VM_OTHER;
if (v == VIRTUALIZATION_NONE && other)
v = VIRTUALIZATION_VM_OTHER;
cached_found = r;
log_debug("Found VM virtualization %s", virtualization_to_string(r));
return r;
cached_found = v;
log_debug("Found VM virtualization %s", virtualization_to_string(v));
return v;
}
static const char *const container_table[_VIRTUALIZATION_MAX] = {
@ -608,12 +608,10 @@ static int running_in_cgroupns(void) {
}
}
static int detect_container_files(void) {
unsigned i;
static Virtualization detect_container_files(void) {
static const struct {
const char *file_path;
int id;
Virtualization id;
} container_file_table[] = {
/* https://github.com/containers/podman/issues/6192 */
/* https://github.com/containers/podman/issues/3586#issuecomment-661918679 */
@ -623,7 +621,7 @@ static int detect_container_files(void) {
{ "/.dockerenv", VIRTUALIZATION_DOCKER },
};
for (i = 0; i < ELEMENTSOF(container_file_table); i++) {
for (size_t i = 0; i < ELEMENTSOF(container_file_table); i++) {
if (access(container_file_table[i].file_path, F_OK) >= 0)
return container_file_table[i].id;
@ -636,10 +634,11 @@ static int detect_container_files(void) {
return VIRTUALIZATION_NONE;
}
int detect_container(void) {
static thread_local int cached_found = _VIRTUALIZATION_INVALID;
Virtualization detect_container(void) {
static thread_local Virtualization cached_found = _VIRTUALIZATION_INVALID;
_cleanup_free_ char *m = NULL, *o = NULL, *p = NULL;
const char *e = NULL;
Virtualization v;
int r;
if (cached_found >= 0)
@ -651,7 +650,7 @@ int detect_container(void) {
log_debug_errno(errno, "Failed to check if /proc/vz exists, ignoring: %m");
} else if (access("/proc/bc", F_OK) < 0) {
if (errno == ENOENT) {
r = VIRTUALIZATION_OPENVZ;
v = VIRTUALIZATION_OPENVZ;
goto finish;
}
@ -663,7 +662,7 @@ int detect_container(void) {
if (r < 0)
log_debug_errno(r, "Failed to read /proc/sys/kernel/osrelease, ignoring: %m");
else if (strstr(o, "Microsoft") || strstr(o, "WSL")) {
r = VIRTUALIZATION_WSL;
v = VIRTUALIZATION_WSL;
goto finish;
}
@ -688,7 +687,7 @@ int detect_container(void) {
if (r < 0)
log_debug_errno(r, "Failed to read %s, ignoring: %m", pf);
else if (startswith(ptrace_comm, "proot")) {
r = VIRTUALIZATION_PROOT;
v = VIRTUALIZATION_PROOT;
goto finish;
}
}
@ -715,7 +714,7 @@ int detect_container(void) {
if (!e)
goto check_files;
if (isempty(e)) {
r = VIRTUALIZATION_NONE;
v = VIRTUALIZATION_NONE;
goto finish;
}
@ -746,49 +745,51 @@ check_files:
* for other specific container managers, otherwise we risk mistaking another
* container manager for Docker: the /.dockerenv file could inadvertently end up
* in a file system image. */
r = detect_container_files();
if (r)
v = detect_container_files();
if (v < 0)
return v;
if (v != VIRTUALIZATION_NONE)
goto finish;
r = running_in_cgroupns();
if (r > 0) {
r = VIRTUALIZATION_CONTAINER_OTHER;
v = VIRTUALIZATION_CONTAINER_OTHER;
goto finish;
}
if (r < 0)
log_debug_errno(r, "Failed to detect cgroup namespace: %m");
/* If none of that worked, give up, assume no container manager. */
r = VIRTUALIZATION_NONE;
v = VIRTUALIZATION_NONE;
goto finish;
translate_name:
if (streq(e, "oci")) {
/* Some images hardcode container=oci, but OCI is not a specific container manager.
* Try to detect one based on well-known files. */
r = detect_container_files();
if (!r)
r = VIRTUALIZATION_CONTAINER_OTHER;
v = detect_container_files();
if (v != VIRTUALIZATION_NONE)
v = VIRTUALIZATION_CONTAINER_OTHER;
goto finish;
}
r = container_from_string(e);
if (r < 0)
r = VIRTUALIZATION_CONTAINER_OTHER;
v = container_from_string(e);
if (v < 0)
v = VIRTUALIZATION_CONTAINER_OTHER;
finish:
log_debug("Found container virtualization %s.", virtualization_to_string(r));
cached_found = r;
return r;
log_debug("Found container virtualization %s.", virtualization_to_string(v));
cached_found = v;
return v;
}
int detect_virtualization(void) {
int r;
Virtualization detect_virtualization(void) {
int v;
r = detect_container();
if (r == 0)
r = detect_vm();
v = detect_container();
if (v != VIRTUALIZATION_NONE)
return v;
return r;
return detect_vm();
}
static int userns_has_mapping(const char *name) {
@ -996,7 +997,6 @@ bool has_cpu_with_flag(const char *flag) {
static const char *const virtualization_table[_VIRTUALIZATION_MAX] = {
[VIRTUALIZATION_NONE] = "none",
[VIRTUALIZATION_KVM] = "kvm",
[VIRTUALIZATION_HV_KVM] = "kvm",
[VIRTUALIZATION_AMAZON] = "amazon",
[VIRTUALIZATION_QEMU] = "qemu",
[VIRTUALIZATION_BOCHS] = "bochs",
@ -1026,4 +1026,4 @@ static const char *const virtualization_table[_VIRTUALIZATION_MAX] = {
[VIRTUALIZATION_CONTAINER_OTHER] = "container-other",
};
DEFINE_STRING_TABLE_LOOKUP(virtualization, int);
DEFINE_STRING_TABLE_LOOKUP(virtualization, Virtualization);

View File

@ -3,14 +3,14 @@
#include <stdbool.h>
#include "errno-list.h"
#include "macro.h"
enum {
typedef enum Virtualization {
VIRTUALIZATION_NONE = 0,
VIRTUALIZATION_VM_FIRST,
VIRTUALIZATION_KVM = VIRTUALIZATION_VM_FIRST,
VIRTUALIZATION_HV_KVM,
VIRTUALIZATION_AMAZON,
VIRTUALIZATION_QEMU,
VIRTUALIZATION_BOCHS,
@ -44,23 +44,24 @@ enum {
_VIRTUALIZATION_MAX,
_VIRTUALIZATION_INVALID = -EINVAL,
};
_VIRTUALIZATION_ERRNO_MAX = -ERRNO_MAX, /* ensure full range of errno fits into this enum */
} Virtualization;
static inline bool VIRTUALIZATION_IS_VM(int x) {
static inline bool VIRTUALIZATION_IS_VM(Virtualization x) {
return x >= VIRTUALIZATION_VM_FIRST && x <= VIRTUALIZATION_VM_LAST;
}
static inline bool VIRTUALIZATION_IS_CONTAINER(int x) {
static inline bool VIRTUALIZATION_IS_CONTAINER(Virtualization x) {
return x >= VIRTUALIZATION_CONTAINER_FIRST && x <= VIRTUALIZATION_CONTAINER_LAST;
}
int detect_vm(void);
int detect_container(void);
int detect_virtualization(void);
Virtualization detect_vm(void);
Virtualization detect_container(void);
Virtualization detect_virtualization(void);
int running_in_userns(void);
int running_in_chroot(void);
const char *virtualization_to_string(int v) _const_;
int virtualization_from_string(const char *s) _pure_;
const char *virtualization_to_string(Virtualization v) _const_;
Virtualization virtualization_from_string(const char *s) _pure_;
bool has_cpu_with_flag(const char *flag);

View File

@ -71,7 +71,7 @@ static int property_get_virtualization(
void *userdata,
sd_bus_error *error) {
int v;
Virtualization v;
assert(bus);
assert(reply);

View File

@ -102,7 +102,7 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_LIST:
DUMP_STRING_TABLE(virtualization, int, _VIRTUALIZATION_MAX);
DUMP_STRING_TABLE(virtualization, Virtualization, _VIRTUALIZATION_MAX);
return 0;
case '?':
@ -121,6 +121,7 @@ static int parse_argv(int argc, char *argv[]) {
}
static int run(int argc, char *argv[]) {
Virtualization v;
int r;
/* This is mostly intended to be used for scripts which want
@ -135,15 +136,15 @@ static int run(int argc, char *argv[]) {
switch (arg_mode) {
case ONLY_VM:
r = detect_vm();
if (r < 0)
return log_error_errno(r, "Failed to check for VM: %m");
v = detect_vm();
if (v < 0)
return log_error_errno(v, "Failed to check for VM: %m");
break;
case ONLY_CONTAINER:
r = detect_container();
if (r < 0)
return log_error_errno(r, "Failed to check for container: %m");
v = detect_container();
if (v < 0)
return log_error_errno(v, "Failed to check for container: %m");
break;
case ONLY_CHROOT:
@ -160,16 +161,16 @@ static int run(int argc, char *argv[]) {
case ANY_VIRTUALIZATION:
default:
r = detect_virtualization();
if (r < 0)
return log_error_errno(r, "Failed to check for virtualization: %m");
v = detect_virtualization();
if (v < 0)
return log_error_errno(v, "Failed to check for virtualization: %m");
break;
}
if (!arg_quiet)
puts(virtualization_to_string(r));
puts(virtualization_to_string(v));
return r == VIRTUALIZATION_NONE;
return v == VIRTUALIZATION_NONE;
}
DEFINE_MAIN_FUNCTION_WITH_POSITIVE_FAILURE(run);

View File

@ -261,8 +261,9 @@ static bool valid_deployment(const char *deployment) {
static const char* fallback_chassis(void) {
const char *chassis;
_cleanup_free_ char *type = NULL;
Virtualization v;
unsigned t;
int v, r;
int r;
v = detect_virtualization();
if (v < 0)

View File

@ -157,7 +157,7 @@ static int cache_space_refresh(Server *s, JournalStorage *storage) {
avail = LESS_BY(vfs_avail, metrics->keep_free);
space->limit = MIN(MAX(vfs_used + avail, metrics->min_use), metrics->max_use);
space->limit = CLAMP(vfs_used + avail, metrics->min_use, metrics->max_use);
space->available = LESS_BY(space->limit, vfs_used);
space->timestamp = ts;
return 1;

View File

@ -64,7 +64,7 @@ struct sd_dhcp6_client {
struct duid duid;
size_t duid_len;
be16_t *req_opts;
size_t req_opts_len;
size_t n_req_opts;
char *fqdn;
char *mudurl;
char **user_class;

View File

@ -51,18 +51,20 @@ bool dhcp6_option_can_request(uint16_t option) {
return false;
case SD_DHCP6_OPTION_SIP_SERVER_DOMAIN_NAME:
case SD_DHCP6_OPTION_SIP_SERVER_ADDRESS:
case SD_DHCP6_OPTION_DNS_SERVERS:
case SD_DHCP6_OPTION_DOMAIN_LIST:
case SD_DHCP6_OPTION_DNS_SERVER:
case SD_DHCP6_OPTION_DOMAIN:
return true;
case SD_DHCP6_OPTION_IA_PD:
case SD_DHCP6_OPTION_IA_PD_PREFIX:
return false;
case SD_DHCP6_OPTION_NIS_SERVERS:
case SD_DHCP6_OPTION_NISP_SERVERS:
case SD_DHCP6_OPTION_NIS_SERVER:
case SD_DHCP6_OPTION_NISP_SERVER:
case SD_DHCP6_OPTION_NIS_DOMAIN_NAME:
case SD_DHCP6_OPTION_NISP_DOMAIN_NAME:
case SD_DHCP6_OPTION_SNTP_SERVERS:
case SD_DHCP6_OPTION_SNTP_SERVER:
return true;
case SD_DHCP6_OPTION_INFORMATION_REFRESH_TIME:
return false; /* This is automatically set when sending INFORMATION_REQUEST message. */
case SD_DHCP6_OPTION_BCMCS_SERVER_D:
case SD_DHCP6_OPTION_BCMCS_SERVER_A:
case SD_DHCP6_OPTION_GEOCONF_CIVIC:
@ -124,9 +126,9 @@ bool dhcp6_option_can_request(uint16_t option) {
case SD_DHCP6_OPTION_CLIENT_LINKLAYER_ADDR:
case SD_DHCP6_OPTION_LINK_ADDRESS:
case SD_DHCP6_OPTION_RADIUS:
case SD_DHCP6_OPTION_SOL_MAX_RT: /* Automatically set when sending SOLICIT message. */
case SD_DHCP6_OPTION_INF_MAX_RT: /* Automatically set when sending INFORMATION_REQUEST message. */
return false;
case SD_DHCP6_OPTION_SOL_MAX_RT:
case SD_DHCP6_OPTION_INF_MAX_RT:
case SD_DHCP6_OPTION_ADDRSEL:
case SD_DHCP6_OPTION_ADDRSEL_TABLE:
case SD_DHCP6_OPTION_V6_PCP_SERVER:

View File

@ -23,16 +23,10 @@
#include "io-util.h"
#include "random-util.h"
#include "socket-util.h"
#include "sort-util.h"
#include "strv.h"
#include "web-util.h"
static const uint16_t default_req_opts[] = {
SD_DHCP6_OPTION_DNS_SERVERS,
SD_DHCP6_OPTION_DOMAIN_LIST,
SD_DHCP6_OPTION_NTP_SERVER,
SD_DHCP6_OPTION_SNTP_SERVERS,
};
#define DHCP6_CLIENT_DONT_DESTROY(client) \
_cleanup_(sd_dhcp6_client_unrefp) _unused_ sd_dhcp6_client *_dont_destroy_##client = sd_dhcp6_client_ref(client)
@ -371,8 +365,12 @@ int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client, int *enable
return 0;
}
static int be16_compare_func(const be16_t *a, const be16_t *b) {
return CMP(be16toh(*a), be16toh(*b));
}
int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, uint16_t option) {
size_t t;
be16_t opt;
assert_return(client, -EINVAL);
assert_return(!sd_dhcp6_client_is_running(client), -EBUSY);
@ -380,15 +378,17 @@ int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, uint16_t option)
if (!dhcp6_option_can_request(option))
return -EINVAL;
for (t = 0; t < client->req_opts_len; t++)
if (client->req_opts[t] == htobe16(option))
return -EEXIST;
opt = htobe16(option);
if (typesafe_bsearch(&opt, client->req_opts, client->n_req_opts, be16_compare_func))
return -EEXIST;
if (!GREEDY_REALLOC(client->req_opts, client->req_opts_len + 1))
if (!GREEDY_REALLOC(client->req_opts, client->n_req_opts + 1))
return -ENOMEM;
client->req_opts[client->req_opts_len++] = htobe16(option);
client->req_opts[client->n_req_opts++] = opt;
/* Sort immediately to make the above binary search will work for the next time. */
typesafe_qsort(client->req_opts, client->n_req_opts, be16_compare_func);
return 0;
}
@ -635,6 +635,51 @@ static DHCP6MessageType client_message_type_from_state(sd_dhcp6_client *client)
}
}
static int client_append_oro(sd_dhcp6_client *client, uint8_t **opt, size_t *optlen) {
_cleanup_free_ be16_t *buf = NULL;
be16_t *req_opts;
size_t n;
assert(client);
assert(opt);
assert(optlen);
switch (client->state) {
case DHCP6_STATE_INFORMATION_REQUEST:
n = client->n_req_opts;
buf = new(be16_t, n + 2);
if (!buf)
return -ENOMEM;
memcpy_safe(buf, client->req_opts, n * sizeof(be16_t));
buf[n++] = htobe16(SD_DHCP6_OPTION_INFORMATION_REFRESH_TIME); /* RFC 8415 section 21.23 */
buf[n++] = htobe16(SD_DHCP6_OPTION_INF_MAX_RT); /* RFC 8415 section 21.25 */
typesafe_qsort(buf, n, be16_compare_func);
req_opts = buf;
break;
case DHCP6_STATE_SOLICITATION:
n = client->n_req_opts;
buf = new(be16_t, n + 1);
if (!buf)
return -ENOMEM;
memcpy_safe(buf, client->req_opts, n * sizeof(be16_t));
buf[n++] = htobe16(SD_DHCP6_OPTION_SOL_MAX_RT); /* RFC 8415 section 21.24 */
typesafe_qsort(buf, n, be16_compare_func);
req_opts = buf;
break;
default:
n = client->n_req_opts;
req_opts = client->req_opts;
}
return dhcp6_option_append(opt, optlen, SD_DHCP6_OPTION_ORO, n * sizeof(be16_t), req_opts);
}
int dhcp6_client_send_message(sd_dhcp6_client *client) {
_cleanup_free_ DHCP6Message *message = NULL;
struct in6_addr all_servers =
@ -712,9 +757,7 @@ int dhcp6_client_send_message(sd_dhcp6_client *client) {
return r;
}
r = dhcp6_option_append(&opt, &optlen, SD_DHCP6_OPTION_ORO,
client->req_opts_len * sizeof(be16_t),
client->req_opts);
r = client_append_oro(client, &opt, &optlen);
if (r < 0)
return r;
@ -1413,18 +1456,9 @@ DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp6_client, sd_dhcp6_client, dhcp6_client_fre
int sd_dhcp6_client_new(sd_dhcp6_client **ret) {
_cleanup_(sd_dhcp6_client_unrefp) sd_dhcp6_client *client = NULL;
_cleanup_free_ be16_t *req_opts = NULL;
size_t t;
assert_return(ret, -EINVAL);
req_opts = new(be16_t, ELEMENTSOF(default_req_opts));
if (!req_opts)
return -ENOMEM;
for (t = 0; t < ELEMENTSOF(default_req_opts); t++)
req_opts[t] = htobe16(default_req_opts[t]);
client = new(sd_dhcp6_client, 1);
if (!client)
return -ENOMEM;
@ -1436,8 +1470,6 @@ int sd_dhcp6_client_new(sd_dhcp6_client **ret) {
.ifindex = -1,
.request_ia = DHCP6_REQUEST_IA_NA | DHCP6_REQUEST_IA_PD,
.fd = -1,
.req_opts_len = ELEMENTSOF(default_req_opts),
.req_opts = TAKE_PTR(req_opts),
};
*ret = TAKE_PTR(client);

View File

@ -570,14 +570,14 @@ static int dhcp6_lease_parse_message(
break;
case SD_DHCP6_OPTION_DNS_SERVERS:
case SD_DHCP6_OPTION_DNS_SERVER:
r = dhcp6_lease_add_dns(lease, optval, optlen);
if (r < 0)
log_dhcp6_client_errno(client, r, "Failed to parse DNS server option, ignoring: %m");
break;
case SD_DHCP6_OPTION_DOMAIN_LIST:
case SD_DHCP6_OPTION_DOMAIN:
r = dhcp6_lease_add_domains(lease, optval, optlen);
if (r < 0)
log_dhcp6_client_errno(client, r, "Failed to parse domain list option, ignoring: %m");
@ -591,7 +591,7 @@ static int dhcp6_lease_parse_message(
break;
case SD_DHCP6_OPTION_SNTP_SERVERS:
case SD_DHCP6_OPTION_SNTP_SERVER:
r = dhcp6_lease_add_sntp(lease, optval, optlen);
if (r < 0)
log_dhcp6_client_errno(client, r, "Failed to parse SNTP server option, ignoring: %m");

View File

@ -97,15 +97,15 @@ TEST(client_basic) {
assert_se(sd_dhcp6_client_set_fqdn(client, "~host.domain") == -EINVAL);
assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_CLIENTID) == -EINVAL);
assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_DNS_SERVERS) == -EEXIST);
assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_NTP_SERVER) == -EEXIST);
assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_SNTP_SERVERS) == -EEXIST);
assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_DOMAIN_LIST) == -EEXIST);
assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_DNS_SERVER) >= 0);
assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_NTP_SERVER) >= 0);
assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_SNTP_SERVER) >= 0);
assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_DOMAIN) >= 0);
assert_se(sd_dhcp6_client_set_request_option(client, 10) == -EINVAL);
assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_NIS_SERVERS) == 0);
assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_NISP_SERVERS) == 0);
assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_NIS_SERVERS) == -EEXIST);
assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_NISP_SERVERS) == -EEXIST);
assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_NIS_SERVER) >= 0);
assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_NISP_SERVER) >= 0);
assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_NIS_SERVER) == -EEXIST);
assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_NISP_SERVER) == -EEXIST);
assert_se(sd_dhcp6_client_set_information_request(client, 1) >= 0);
v = 0;
@ -403,7 +403,7 @@ TEST(client_parse_message_issue_22099) {
0x00, SD_DHCP6_OPTION_PREFERENCE, 0x00, 0x01,
0x00,
/* DNS servers */
0x00, SD_DHCP6_OPTION_DNS_SERVERS, 0x00, 0x10,
0x00, SD_DHCP6_OPTION_DNS_SERVER, 0x00, 0x10,
0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x15, 0xc8, 0xff, 0xfe, 0xef, 0x1e, 0x4e,
/* v6 pcp server */
0x00, SD_DHCP6_OPTION_V6_PCP_SERVER, 0x00, 0x10,
@ -450,11 +450,13 @@ static const uint8_t msg_information_request[] = {
0x0f, 0xb4, 0xe5,
/* MUD URL */
/* ORO */
0x00, SD_DHCP6_OPTION_ORO, 0x00, 0x08,
0x00, SD_DHCP6_OPTION_DNS_SERVERS,
0x00, SD_DHCP6_OPTION_DOMAIN_LIST,
0x00, SD_DHCP6_OPTION_ORO, 0x00, 0x0c,
0x00, SD_DHCP6_OPTION_DNS_SERVER,
0x00, SD_DHCP6_OPTION_DOMAIN,
0x00, SD_DHCP6_OPTION_SNTP_SERVER,
0x00, SD_DHCP6_OPTION_INFORMATION_REFRESH_TIME,
0x00, SD_DHCP6_OPTION_NTP_SERVER,
0x00, SD_DHCP6_OPTION_SNTP_SERVERS,
0x00, SD_DHCP6_OPTION_INF_MAX_RT,
/* Client ID */
0x00, SD_DHCP6_OPTION_CLIENTID, 0x00, 0x0e,
CLIENT_ID_BYTES,
@ -490,11 +492,12 @@ static const uint8_t msg_solicit[] = {
/* Vendor Options */
/* MUD URL */
/* ORO */
0x00, SD_DHCP6_OPTION_ORO, 0x00, 0x08,
0x00, SD_DHCP6_OPTION_DNS_SERVERS,
0x00, SD_DHCP6_OPTION_DOMAIN_LIST,
0x00, SD_DHCP6_OPTION_ORO, 0x00, 0x0a,
0x00, SD_DHCP6_OPTION_DNS_SERVER,
0x00, SD_DHCP6_OPTION_DOMAIN,
0x00, SD_DHCP6_OPTION_SNTP_SERVER,
0x00, SD_DHCP6_OPTION_NTP_SERVER,
0x00, SD_DHCP6_OPTION_SNTP_SERVERS,
0x00, SD_DHCP6_OPTION_SOL_MAX_RT,
/* Client ID */
0x00, SD_DHCP6_OPTION_CLIENTID, 0x00, 0x0e,
CLIENT_ID_BYTES,
@ -554,10 +557,10 @@ static const uint8_t msg_request[] = {
/* MUD URL */
/* ORO */
0x00, SD_DHCP6_OPTION_ORO, 0x00, 0x08,
0x00, SD_DHCP6_OPTION_DNS_SERVERS,
0x00, SD_DHCP6_OPTION_DOMAIN_LIST,
0x00, SD_DHCP6_OPTION_DNS_SERVER,
0x00, SD_DHCP6_OPTION_DOMAIN,
0x00, SD_DHCP6_OPTION_SNTP_SERVER,
0x00, SD_DHCP6_OPTION_NTP_SERVER,
0x00, SD_DHCP6_OPTION_SNTP_SERVERS,
/* Client ID */
0x00, SD_DHCP6_OPTION_CLIENTID, 0x00, 0x0e,
CLIENT_ID_BYTES,
@ -619,11 +622,11 @@ static const uint8_t msg_reply[] = {
0x40, /* prefixlen */
IA_PD_PREFIX1_BYTES,
/* DNS servers */
0x00, SD_DHCP6_OPTION_DNS_SERVERS, 0x00, 0x20,
0x00, SD_DHCP6_OPTION_DNS_SERVER, 0x00, 0x20,
DNS1_BYTES,
DNS2_BYTES,
/* SNTP servers */
0x00, SD_DHCP6_OPTION_SNTP_SERVERS, 0x00, 0x20,
0x00, SD_DHCP6_OPTION_SNTP_SERVER, 0x00, 0x20,
SNTP1_BYTES,
SNTP2_BYTES,
/* NTP servers */
@ -638,7 +641,7 @@ static const uint8_t msg_reply[] = {
0x00, DHCP6_NTP_SUBOPTION_SRV_FQDN, 0x00, 0x0b,
0x03, 'n', 't', 'p', 0x05, 'i', 'n', 't', 'r', 'a', 0x00,
/* Domain list */
0x00, SD_DHCP6_OPTION_DOMAIN_LIST, 0x00, 0x0b,
0x00, SD_DHCP6_OPTION_DOMAIN, 0x00, 0x0b,
0x03, 'l', 'a', 'b', 0x05, 'i', 'n', 't', 'r', 'a', 0x00,
/* Client FQDN */
0x00, SD_DHCP6_OPTION_CLIENT_FQDN, 0x00, 0x12,
@ -698,11 +701,11 @@ static const uint8_t msg_advertise[] = {
0x40, /* prefixlen */
IA_PD_PREFIX1_BYTES,
/* DNS servers */
0x00, SD_DHCP6_OPTION_DNS_SERVERS, 0x00, 0x20,
0x00, SD_DHCP6_OPTION_DNS_SERVER, 0x00, 0x20,
DNS1_BYTES,
DNS2_BYTES,
/* SNTP servers */
0x00, SD_DHCP6_OPTION_SNTP_SERVERS, 0x00, 0x20,
0x00, SD_DHCP6_OPTION_SNTP_SERVER, 0x00, 0x20,
SNTP1_BYTES,
SNTP2_BYTES,
/* NTP servers */
@ -717,7 +720,7 @@ static const uint8_t msg_advertise[] = {
0x00, DHCP6_NTP_SUBOPTION_SRV_FQDN, 0x00, 0x0b,
0x03, 'n', 't', 'p', 0x05, 'i', 'n', 't', 'r', 'a', 0x00,
/* Domain list */
0x00, SD_DHCP6_OPTION_DOMAIN_LIST, 0x00, 0x0b,
0x00, SD_DHCP6_OPTION_DOMAIN, 0x00, 0x0b,
0x03, 'l', 'a', 'b', 0x05, 'i', 'n', 't', 'r', 'a', 0x00,
/* Client FQDN */
0x00, SD_DHCP6_OPTION_CLIENT_FQDN, 0x00, 0x12,
@ -977,6 +980,11 @@ TEST(dhcp6_client) {
assert_se(sd_dhcp6_client_set_iaid(client, unaligned_read_be32((uint8_t[]) { IA_ID_BYTES })) >= 0);
dhcp6_client_set_test_mode(client, true);
assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_DNS_SERVER) >= 0);
assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_DOMAIN) >= 0);
assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_NTP_SERVER) >= 0);
assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_SNTP_SERVER) >= 0);
assert_se(sd_dhcp6_client_set_information_request(client, true) >= 0);
assert_se(sd_dhcp6_client_set_callback(client, test_client_callback, NULL) >= 0);

View File

@ -109,6 +109,7 @@ int device_set_devname(sd_device *device, const char *devname);
int device_set_devtype(sd_device *device, const char *devtype);
int device_set_devnum(sd_device *device, const char *major, const char *minor);
int device_set_subsystem(sd_device *device, const char *subsystem);
int device_set_diskseq(sd_device *device, const char *str);
int device_set_drivers_subsystem(sd_device *device);
int device_set_driver(sd_device *device, const char *driver);
int device_set_usec_initialized(sd_device *device, usec_t when);

View File

@ -255,28 +255,6 @@ static int device_set_seqnum(sd_device *device, const char *str) {
return 0;
}
static int device_set_diskseq(sd_device *device, const char *str) {
uint64_t diskseq;
int r;
assert(device);
assert(str);
r = safe_atou64(str, &diskseq);
if (r < 0)
return r;
if (diskseq == 0)
return -EINVAL;
r = device_add_property_internal(device, "DISKSEQ", str);
if (r < 0)
return r;
device->diskseq = diskseq;
return 0;
}
static int device_amend(sd_device *device, const char *key, const char *value) {
int r;

View File

@ -570,7 +570,34 @@ int device_set_devnum(sd_device *device, const char *major, const char *minor) {
return 0;
}
static int handle_uevent_line(sd_device *device, const char *key, const char *value, const char **major, const char **minor) {
int device_set_diskseq(sd_device *device, const char *str) {
uint64_t diskseq;
int r;
assert(device);
assert(str);
r = safe_atou64(str, &diskseq);
if (r < 0)
return r;
if (diskseq == 0)
return -EINVAL;
r = device_add_property_internal(device, "DISKSEQ", str);
if (r < 0)
return r;
device->diskseq = diskseq;
return 0;
}
static int handle_uevent_line(
sd_device *device,
const char *key,
const char *value,
const char **major,
const char **minor) {
int r;
assert(device);
@ -595,6 +622,10 @@ static int handle_uevent_line(sd_device *device, const char *key, const char *va
r = device_set_devmode(device, value);
if (r < 0)
return r;
} else if (streq(key, "DISKSEQ")) {
r = device_set_diskseq(device, value);
if (r < 0)
return r;
} else if (streq(key, "MAJOR"))
*major = value;
else if (streq(key, "MINOR"))
@ -1047,14 +1078,15 @@ _public_ int sd_device_get_driver(sd_device *device, const char **ret) {
return 0;
}
_public_ int sd_device_get_devpath(sd_device *device, const char **devpath) {
_public_ int sd_device_get_devpath(sd_device *device, const char **ret) {
assert_return(device, -EINVAL);
assert(device->devpath);
assert(device->devpath[0] == '/');
if (devpath)
*devpath = device->devpath;
if (ret)
*ret = device->devpath;
return 0;
}

View File

@ -3585,6 +3585,9 @@ fail:
(void) journal_file_close(f);
if (newly_created && fd < 0)
(void) unlink(fname);
return r;
}

View File

@ -622,6 +622,29 @@ static int dhcp6_configure(Link *link) {
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to set MUD URL: %m");
}
if (link->network->dhcp6_use_dns) {
r = sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_DNS_SERVER);
if (r < 0)
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to request DNS servers: %m");
}
if (link->network->dhcp6_use_domains > 0) {
r = sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_DOMAIN);
if (r < 0)
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to request domains: %m");
}
if (link->network->dhcp6_use_ntp) {
r = sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_NTP_SERVER);
if (r < 0)
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to request NTP servers: %m");
/* If the server does not provide NTP servers, then we fallback to use SNTP servers. */
r = sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_SNTP_SERVER);
if (r < 0)
return log_link_debug_errno(link, r, "DHCPv6 CLIENT: Failed to request SNTP servers: %m");
}
SET_FOREACH(request_options, link->network->dhcp6_request_options) {
uint32_t option = PTR_TO_UINT32(request_options);

View File

@ -6,7 +6,9 @@ set -o pipefail
[[ -e /dev/loop-control ]] || exit 77
repart="${1:?}"
udevadm="${2:?}"
test -x "$repart"
test -x "$udevadm"
PATH=$PATH:/sbin:/usr/sbin
@ -199,10 +201,7 @@ $D/zzz7 : start= 6291416, size= 98304, type=0FC63DAF-8483-4772-8E79-3D
EOF
LOOP="$(losetup -P --show --find "$D/zzz")"
while : ; do
test -e "$LOOP" && break
sleep .2
done
"${udevadm:?}" wait --timeout 60 --initialized=yes --settle "${LOOP:?}"
VOLUME="test-repart-$RANDOM"

View File

@ -459,7 +459,8 @@ static int condition_test_group(Condition *c, char **env) {
}
static int condition_test_virtualization(Condition *c, char **env) {
int b, v;
Virtualization v;
int b;
assert(c);
assert(c->parameter);
@ -475,7 +476,7 @@ static int condition_test_virtualization(Condition *c, char **env) {
/* First, compare with yes/no */
b = parse_boolean(c->parameter);
if (b >= 0)
return b == !!v;
return b == (v != VIRTUALIZATION_NONE);
/* Then, compare categorization */
if (streq(c->parameter, "vm"))
@ -489,7 +490,7 @@ static int condition_test_virtualization(Condition *c, char **env) {
}
static int condition_test_architecture(Condition *c, char **env) {
int a, b;
Architecture a, b;
assert(c);
assert(c->parameter);

View File

@ -612,7 +612,7 @@ static void dissected_partition_done(DissectedPartition *p) {
*p = (DissectedPartition) {
.partno = -1,
.architecture = -1
.architecture = _ARCHITECTURE_INVALID,
};
}
@ -917,7 +917,7 @@ int dissect_image(
if (is_gpt) {
PartitionDesignator designator = _PARTITION_DESIGNATOR_INVALID;
int architecture = _ARCHITECTURE_INVALID;
Architecture architecture = _ARCHITECTURE_INVALID;
const char *stype, *sid, *fstype = NULL, *label;
sd_id128_t type_id, id;
bool rw = true, growfs = false;

View File

@ -20,9 +20,9 @@ struct DissectedPartition {
bool found:1;
bool rw:1;
bool growfs:1;
int partno; /* -1 if there was no partition and the images contains a file system directly */
int architecture; /* Intended architecture: either native, secondary or unset (-1). */
sd_id128_t uuid; /* Partition entry UUID as reported by the GPT */
int partno; /* -1 if there was no partition and the images contains a file system directly */
Architecture architecture; /* Intended architecture: either native, secondary or unset ARCHITECTURE_INVALID. */
sd_id128_t uuid; /* Partition entry UUID as reported by the GPT */
char *fstype;
char *node;
char *label;

View File

@ -65,14 +65,25 @@ const GptPartitionType gpt_partition_type_table[] = {
{}
};
const char *gpt_partition_type_uuid_to_string(sd_id128_t id) {
static const GptPartitionType *gpt_partition_type_find_by_uuid(sd_id128_t id) {
for (size_t i = 0; i < ELEMENTSOF(gpt_partition_type_table) - 1; i++)
if (sd_id128_equal(id, gpt_partition_type_table[i].uuid))
return gpt_partition_type_table[i].name;
return gpt_partition_type_table + i;
return NULL;
}
const char *gpt_partition_type_uuid_to_string(sd_id128_t id) {
const GptPartitionType *pt;
pt = gpt_partition_type_find_by_uuid(id);
if (!pt)
return NULL;
return pt->name;
}
const char *gpt_partition_type_uuid_to_string_harder(
sd_id128_t id,
char buffer[static SD_ID128_UUID_STRING_MAX]) {
@ -102,11 +113,13 @@ int gpt_partition_type_uuid_from_string(const char *s, sd_id128_t *ret) {
}
Architecture gpt_partition_type_uuid_to_arch(sd_id128_t id) {
for (size_t i = 0; i < ELEMENTSOF(gpt_partition_type_table) - 1; i++)
if (sd_id128_equal(id, gpt_partition_type_table[i].uuid))
return gpt_partition_type_table[i].arch;
const GptPartitionType *pt;
return _ARCHITECTURE_INVALID;
pt = gpt_partition_type_find_by_uuid(id);
if (!pt)
return _ARCHITECTURE_INVALID;
return pt->arch;
}
int gpt_partition_label_valid(const char *s) {
@ -120,9 +133,11 @@ int gpt_partition_label_valid(const char *s) {
}
static GptPartitionType gpt_partition_type_from_uuid(sd_id128_t id) {
for (size_t i = 0; i < ELEMENTSOF(gpt_partition_type_table) - 1; i++)
if (sd_id128_equal(id, gpt_partition_type_table[i].uuid))
return gpt_partition_type_table[i];
const GptPartitionType *pt;
pt = gpt_partition_type_find_by_uuid(id);
if (pt)
return *pt;
return (GptPartitionType) { .uuid = id, .arch = _ARCHITECTURE_INVALID };
}

View File

@ -134,7 +134,7 @@ enum {
SD_DHCP_OPTION_NDS_SERVER = 85, /* [RFC2241] */
SD_DHCP_OPTION_NDS_TREE_NAME = 86, /* [RFC2241] */
SD_DHCP_OPTION_NDS_CONTEXT = 87, /* [RFC2241] */
SD_DHCP_OPTION_BCMCS_CONTROLLER_DOMAIN_NAM = 88, /* [RFC4280] */
SD_DHCP_OPTION_BCMCS_CONTROLLER_DOMAIN_NAME = 88, /* [RFC4280] */
SD_DHCP_OPTION_BCMCS_CONTROLLER_ADDRESS = 89, /* [RFC4280] */
SD_DHCP_OPTION_AUTHENTICATION = 90, /* [RFC3118] */
SD_DHCP_OPTION_CLIENT_LAST_TRANSACTION_TIME = 91, /* [RFC4388] */
@ -173,7 +173,7 @@ enum {
SD_DHCP_OPTION_CAPWAP_AC_ADDRESS = 138, /* [RFC5417] */
SD_DHCP_OPTION_MOS_ADDRESS = 139, /* [RFC5678] */
SD_DHCP_OPTION_MOS_FQDN = 140, /* [RFC5678] */
SD_DHCP_OPTION_SIP_SERVICE_DOMAINS = 141, /* [RFC6011] */
SD_DHCP_OPTION_SIP_SERVICE_DOMAIN = 141, /* [RFC6011] */
SD_DHCP_OPTION_ANDSF_ADDRESS = 142, /* [RFC6153] */
SD_DHCP_OPTION_SZTP_REDIRECT = 143, /* [RFC8572] */
SD_DHCP_OPTION_GEOLOC = 144, /* [RFC6225] */

View File

@ -63,15 +63,15 @@ enum {
SD_DHCP6_OPTION_RECONF_ACCEPT = 20, /* RFC 8415 */
SD_DHCP6_OPTION_SIP_SERVER_DOMAIN_NAME = 21, /* RFC 3319 */
SD_DHCP6_OPTION_SIP_SERVER_ADDRESS = 22, /* RFC 3319 */
SD_DHCP6_OPTION_DNS_SERVERS = 23, /* RFC 3646 */
SD_DHCP6_OPTION_DOMAIN_LIST = 24, /* RFC 3646 */
SD_DHCP6_OPTION_DNS_SERVER = 23, /* RFC 3646 */
SD_DHCP6_OPTION_DOMAIN = 24, /* RFC 3646 */
SD_DHCP6_OPTION_IA_PD = 25, /* RFC 3633, RFC 8415 */
SD_DHCP6_OPTION_IA_PD_PREFIX = 26, /* RFC 3633, RFC 8415 */
SD_DHCP6_OPTION_NIS_SERVERS = 27, /* RFC 3898 */
SD_DHCP6_OPTION_NISP_SERVERS = 28, /* RFC 3898 */
SD_DHCP6_OPTION_NIS_SERVER = 27, /* RFC 3898 */
SD_DHCP6_OPTION_NISP_SERVER = 28, /* RFC 3898 */
SD_DHCP6_OPTION_NIS_DOMAIN_NAME = 29, /* RFC 3898 */
SD_DHCP6_OPTION_NISP_DOMAIN_NAME = 30, /* RFC 3898 */
SD_DHCP6_OPTION_SNTP_SERVERS = 31, /* RFC 4075, deprecated */
SD_DHCP6_OPTION_SNTP_SERVER = 31, /* RFC 4075, deprecated */
SD_DHCP6_OPTION_INFORMATION_REFRESH_TIME = 32, /* RFC 4242, 8415, sec. 21.23 */
SD_DHCP6_OPTION_BCMCS_SERVER_D = 33, /* RFC 4280 */
SD_DHCP6_OPTION_BCMCS_SERVER_A = 34, /* RFC 4280 */

View File

@ -1,13 +1,15 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "architecture.h"
#include "errno-util.h"
#include "log.h"
#include "tests.h"
#include "util.h"
#include "virt.h"
int main(int argc, char *argv[]) {
int a, v;
Virtualization v;
Architecture a;
const char *p;
test_setup_logging(LOG_INFO);
@ -20,7 +22,7 @@ int main(int argc, char *argv[]) {
assert_se(architecture_from_string(architecture_to_string(1)) == 1);
v = detect_virtualization();
if (IN_SET(v, -EPERM, -EACCES))
if (v < 0 && ERRNO_IS_PRIVILEGE(v))
return log_tests_skipped("Cannot detect virtualization");
assert_se(v >= 0);

View File

@ -15,10 +15,11 @@
#include <unistd.h>
#include "barrier.h"
#include "util.h"
#include "errno-util.h"
#include "tests.h"
#include "virt.h"
#include "time-util.h"
#include "util.h"
#include "virt.h"
/* 20ms to test deadlocks; All timings use multiples of this constant as
* alarm/sleep timers. If this timeout is too small for slow machines to perform
@ -434,8 +435,8 @@ static int intro(void) {
* false-positives in CIs.
*/
int v = detect_virtualization();
if (IN_SET(v, -EPERM, -EACCES))
Virtualization v = detect_virtualization();
if (v < 0 && ERRNO_IS_PRIVILEGE(v))
return log_tests_skipped("Cannot detect virtualization");
if (v != VIRTUALIZATION_NONE)

View File

@ -276,7 +276,7 @@ TEST(condition_test_host) {
TEST(condition_test_architecture) {
Condition *condition;
const char *sa;
int a;
Architecture a;
a = uname_architecture();
assert_se(a >= 0);

View File

@ -17,7 +17,7 @@ TEST(gpt_types_against_architectures) {
* types. Also validates whether we can properly categorize the entries. */
FOREACH_STRING(prefix, "root-", "usr-")
for (int a = 0; a < _ARCHITECTURE_MAX; a++)
for (Architecture a = 0; a < _ARCHITECTURE_MAX; a++)
FOREACH_STRING(suffix, "", "-verity", "-verity-sig") {
_cleanup_free_ char *joined = NULL;
sd_id128_t id;

View File

@ -121,6 +121,7 @@ int main(int argc, char **argv) {
test_table(unit_file_state, UNIT_FILE_STATE);
test_table(unit_load_state, UNIT_LOAD_STATE);
test_table(unit_type, UNIT_TYPE);
test_table(virtualization, VIRTUALIZATION);
test_table_sparse(object_compressed, OBJECT_COMPRESSED);

View File

@ -6,6 +6,7 @@ udevadm_sources = files(
'udevadm-control.c',
'udevadm-hwdb.c',
'udevadm-info.c',
'udevadm-lock.c',
'udevadm-monitor.c',
'udevadm-settle.c',
'udevadm-test.c',

View File

@ -22,9 +22,10 @@
#include "static-destruct.h"
#include "string-table.h"
#include "string-util.h"
#include "terminal-util.h"
#include "udev-util.h"
#include "udevadm-util.h"
#include "udevadm.h"
#include "udevadm-util.h"
typedef enum ActionType {
ACTION_QUERY,
@ -171,26 +172,72 @@ static int print_device_chain(sd_device *device) {
}
static int print_record(sd_device *device) {
const char *str, *val;
int i;
const char *str, *val, *subsys;
dev_t devnum;
uint64_t q;
int i, ifi;
assert(device);
(void) sd_device_get_devpath(device, &str);
printf("P: %s\n", str);
/* We don't show syspath here, because it's identical to devpath (modulo the "/sys" prefix).
*
* We don't show action/seqnum here because that only makes sense for records synthesized from
* uevents, not for those synthesized from database entries.
*
* We don't show sysattrs here, because they can be expensive and potentially issue expensive driver
* IO.
*
* Coloring: let's be conservative with coloring. Let's use it to group related fields. Right now:
*
* white for fields that give the device a name
* green for fields that categorize the device into subsystem/devtype and similar
* cyan for fields about associated device nodes/symlinks/network interfaces and such
* magenta for block device diskseq
* yellow for driver info
* no color for regular properties */
assert_se(sd_device_get_devpath(device, &str) >= 0);
printf("P: %s%s%s\n", ansi_highlight_white(), str, ansi_normal());
if (sd_device_get_sysname(device, &str) >= 0)
printf("M: %s%s%s\n", ansi_highlight_white(), str, ansi_normal());
if (sd_device_get_sysnum(device, &str) >= 0)
printf("R: %s%s%s\n", ansi_highlight_white(), str, ansi_normal());
if (sd_device_get_subsystem(device, &subsys) >= 0)
printf("U: %s%s%s\n", ansi_highlight_green(), subsys, ansi_normal());
if (sd_device_get_devtype(device, &str) >= 0)
printf("T: %s%s%s\n", ansi_highlight_green(), str, ansi_normal());
if (sd_device_get_devnum(device, &devnum) >= 0)
printf("D: %s%c %u:%u%s\n",
ansi_highlight_cyan(),
streq_ptr(subsys, "block") ? 'b' : 'c', major(devnum), minor(devnum),
ansi_normal());
if (sd_device_get_ifindex(device, &ifi) >= 0)
printf("I: %s%i%s\n", ansi_highlight_cyan(), ifi, ansi_normal());
if (sd_device_get_devname(device, &str) >= 0) {
assert_se(val = path_startswith(str, "/dev/"));
printf("N: %s\n", val);
printf("N: %s%s%s\n", ansi_highlight_cyan(), val, ansi_normal());
if (device_get_devlink_priority(device, &i) >= 0)
printf("L: %s%i%s\n", ansi_highlight_cyan(), i, ansi_normal());
FOREACH_DEVICE_DEVLINK(device, str) {
assert_se(val = path_startswith(str, "/dev/"));
printf("S: %s%s%s\n", ansi_highlight_cyan(), val, ansi_normal());
}
}
if (device_get_devlink_priority(device, &i) >= 0)
printf("L: %i\n", i);
if (sd_device_get_diskseq(device, &q) >= 0)
printf("Q: %s%" PRIu64 "%s\n", ansi_highlight_magenta(), q, ansi_normal());
FOREACH_DEVICE_DEVLINK(device, str) {
assert_se(val = path_startswith(str, "/dev/"));
printf("S: %s\n", val);
}
if (sd_device_get_driver(device, &str) >= 0)
printf("V: %s%s%s\n", ansi_highlight_yellow4(), str, ansi_normal());
FOREACH_DEVICE_PROPERTY(device, str, val)
printf("E: %s=%s\n", str, val);
@ -442,7 +489,7 @@ static int help(void) {
int info_main(int argc, char *argv[], void *userdata) {
_cleanup_strv_free_ char **devices = NULL;
_cleanup_free_ char *name = NULL;
int c, r;
int c, r, ret;
enum {
ARG_PROPERTY = 0x100,
@ -584,14 +631,21 @@ int info_main(int argc, char *argv[], void *userdata) {
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"-x/--export or -P/--export-prefix cannot be used with --value");
ret = 0;
STRV_FOREACH(p, devices) {
_cleanup_(sd_device_unrefp) sd_device *device = NULL;
r = find_device(*p, NULL, &device);
if (r == -EINVAL)
return log_error_errno(r, "Bad argument \"%s\", expected an absolute path in /dev/ or /sys or a unit name: %m", *p);
if (r < 0)
return log_error_errno(r, "Unknown device \"%s\": %m", *p);
if (r < 0) {
if (r == -EINVAL)
log_error_errno(r, "Bad argument \"%s\", expected an absolute path in /dev/ or /sys/ or a unit name: %m", *p);
else
log_error_errno(r, "Unknown device \"%s\": %m", *p);
if (ret == 0)
ret = r;
continue;
}
if (arg_wait_for_initialization_timeout > 0) {
sd_device *d;
@ -618,5 +672,5 @@ int info_main(int argc, char *argv[], void *userdata) {
return r;
}
return 0;
return ret;
}

399
src/udev/udevadm-lock.c Normal file
View File

@ -0,0 +1,399 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include <getopt.h>
#include <stdlib.h>
#include <sys/file.h>
#include <unistd.h>
#include "blockdev-util.h"
#include "btrfs-util.h"
#include "fd-util.h"
#include "fdset.h"
#include "main-func.h"
#include "parse-util.h"
#include "path-util.h"
#include "pretty-print.h"
#include "process-util.h"
#include "signal-util.h"
#include "sort-util.h"
#include "stat-util.h"
#include "strv.h"
#include "time-util.h"
#include "udevadm.h"
static usec_t arg_timeout_usec = USEC_INFINITY;
static char **arg_devices = NULL;
static char **arg_backing = NULL;
static char **arg_cmdline = NULL;
static bool arg_print = false;
STATIC_DESTRUCTOR_REGISTER(arg_devices, strv_freep);
STATIC_DESTRUCTOR_REGISTER(arg_backing, strv_freep);
STATIC_DESTRUCTOR_REGISTER(arg_cmdline, strv_freep);
static int help(void) {
_cleanup_free_ char *link = NULL;
int r;
r = terminal_urlify_man("udevadm", "8", &link);
if (r < 0)
return log_oom();
printf("%s [OPTIONS...] COMMAND\n"
"%s [OPTIONS...] --print\n"
"\n%sLock a block device and run a comand.%s\n\n"
" -h --help Print this message\n"
" -V --version Print version of the program\n"
" -d --device=DEVICE Block device to lock\n"
" -b --backing=FILE File whose backing block device to lock\n"
" -t --timeout=SECS Block at most the specified time waiting for lock\n"
" -p --print Only show which block device the lock would be taken on\n"
"\nSee the %s for details.\n",
program_invocation_short_name,
program_invocation_short_name,
ansi_highlight(),
ansi_normal(),
link);
return 0;
}
static int parse_argv(int argc, char *argv[]) {
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'V' },
{ "device", required_argument, NULL, 'd' },
{ "backing", required_argument, NULL, 'b' },
{ "timeout", required_argument, NULL, 't' },
{ "print", no_argument, NULL, 'p' },
{}
};
int c, r;
assert(argc >= 0);
assert(argv);
while ((c = getopt_long(argc, argv, arg_print ? "hVd:b:t:p" : "+hVd:b:t:p", options, NULL)) >= 0)
switch (c) {
case 'h':
return help();
case 'V':
return print_version();
case 'd':
case 'b': {
_cleanup_free_ char *s = NULL;
char ***l = c == 'd' ? &arg_devices : &arg_backing;
r = path_make_absolute_cwd(optarg, &s);
if (r < 0)
return log_error_errno(r, "Failed to make path '%s' absolute: %m", optarg);
path_simplify(s);
if (strv_consume(l, TAKE_PTR(s)) < 0)
return log_oom();
strv_uniq(*l);
break;
}
case 't':
r = parse_sec(optarg, &arg_timeout_usec);
if (r < 0)
return log_error_errno(r, "Failed to parse --timeout= parameter: %s", optarg);
break;
case 'p':
arg_print = true;
break;
case '?':
return -EINVAL;
default:
assert_not_reached();
}
if (arg_print) {
if (optind != argc)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No arguments expected");
} else {
if (optind + 1 > argc)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Too few arguments, command to execute.");
arg_cmdline = strv_copy(argv + optind);
if (!arg_cmdline)
return log_oom();
}
if (strv_isempty(arg_devices) && strv_isempty(arg_backing))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No devices to lock specified, refusing.");
return 1;
}
static int find_devno(
dev_t **devnos,
size_t *n_devnos,
const char *device,
bool backing) {
dev_t devt, whole_devt;
struct stat st;
int r;
assert(devnos);
assert(n_devnos);
assert(*devnos || *n_devnos == 0);
assert(device);
if (stat(device, &st) < 0)
return log_error_errno(errno, "Failed to stat '%s': %m", device);
if (S_ISBLK(st.st_mode))
devt = st.st_rdev;
else if (!backing)
return log_error_errno(SYNTHETIC_ERRNO(ENOTBLK), "Not a block device: %s", device);
else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
return log_error_errno(SYNTHETIC_ERRNO(ENOTBLK), "Not a block device, regular file or directory: %s", device);
else if (major(st.st_dev) != 0)
devt = st.st_dev;
else {
_cleanup_close_ int regfd = -1;
struct stat st2;
/* If major(st.st_dev) is zero, this might mean we are backed by btrfs, which needs special
* handing, to get the backing device node. */
regfd = open(device, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
if (regfd < 0)
return log_error_errno(errno, "Failed to open '%s': %m", device);
/* Extra safety: let's check we are still looking at the same file */
if (fstat(regfd, &st2) < 0)
return log_error_errno(errno, "Failed to stat '%s': %m", device);
if (!stat_inode_same(&st, &st2))
return log_error_errno(SYNTHETIC_ERRNO(ENXIO), "File '%s' was replaced while we were looking at it.", device);
r = btrfs_get_block_device_fd(regfd, &devt);
if (r == -ENOTTY)
return log_error_errno(SYNTHETIC_ERRNO(ENOTBLK), "Path '%s' not backed by block device.", device);
if (r < 0)
return log_error_errno(r, "Failed to acquire btrfs backing device of '%s': %m", device);
}
r = block_get_whole_disk(devt, &whole_devt);
if (r < 0)
return log_error_errno(r, "Failed to find whole block device for '%s': %m", device);
if (typesafe_bsearch(&whole_devt, *devnos, *n_devnos, devt_compare_func)) {
log_debug("Device %u:%u already listed for locking, ignoring.", major(whole_devt), minor(whole_devt));
return 0;
}
if (!GREEDY_REALLOC(*devnos, *n_devnos + 1))
return log_oom();
(*devnos)[(*n_devnos)++] = whole_devt;
/* Immediately sort again, to ensure the binary search above will work for the next device we add */
typesafe_qsort(*devnos, *n_devnos, devt_compare_func);
return 1;
}
static int lock_device(
const char *path,
dev_t devno,
usec_t deadline) {
_cleanup_close_ int fd = -1;
struct stat st;
int r;
fd = open(path, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
if (fd < 0)
return log_error_errno(errno, "Failed to open '%s': %m", path);
if (fstat(fd, &st) < 0)
return log_error_errno(errno, "Failed to stat '%s': %m", path);
/* Extra safety: check that the device still refers to what we think it refers to */
if (!S_ISBLK(st.st_mode) || st.st_rdev != devno)
return log_error_errno(SYNTHETIC_ERRNO(ENXIO), "Path '%s' no longer refers to specified block device %u:%u: %m", path, major(devno), minor(devno));
if (flock(fd, LOCK_EX|LOCK_NB) < 0) {
if (errno != EAGAIN)
return log_error_errno(errno, "Failed to lock device '%s': %m", path);
if (deadline == 0)
return log_error_errno(SYNTHETIC_ERRNO(EBUSY), "Device '%s' is currently locked.", path);
if (deadline == USEC_INFINITY) {
log_info("Device '%s' is currently locked, waiting…", path);
if (flock(fd, LOCK_EX) < 0)
return log_error_errno(errno, "Failed to lock device '%s': %m", path);
} else {
_cleanup_(sigkill_waitp) pid_t flock_pid = 0;
/* flock() doesn't support a time-out. Let's fake one then. The traditional way to do
* this is via alarm()/setitimer()/timer_create(), but that's racy, given that the
* SIGALRM might aleady fire between the alarm() and the flock() in which case the
* flock() is never cancelled and we lock up (this is a short time window, but with
* short timeouts on a loaded machine we might run into it, who knows?). Let's
* instead do the lock out-of-process: fork off a child that does the locking, and
* that we'll wait on and kill if it takes too long. */
log_info("Device '%s' is currently locked, waiting %s…",
path, FORMAT_TIMESPAN(usec_sub_unsigned(deadline, now(CLOCK_MONOTONIC)), 0));
BLOCK_SIGNALS(SIGCHLD);
r = safe_fork("(timed-flock)", FORK_DEATHSIG|FORK_LOG, &flock_pid);
if (r < 0)
return r;
if (r == 0) {
/* Child */
if (flock(fd, LOCK_EX) < 0) {
log_error_errno(errno, "Failed to lock device '%s': %m", path);
_exit(EXIT_FAILURE);
}
_exit(EXIT_SUCCESS);
}
for (;;) {
siginfo_t si;
sigset_t ss;
usec_t n;
assert(sigemptyset(&ss) >= 0);
assert(sigaddset(&ss, SIGCHLD) >= 0);
n = now(CLOCK_MONOTONIC);
if (n >= deadline)
return log_error_errno(SYNTHETIC_ERRNO(ETIMEDOUT), "Timeout reached.");
r = sigtimedwait(&ss, NULL, TIMESPEC_STORE(deadline - n));
if (r < 0) {
if (errno != EAGAIN)
return log_error_errno(errno, "Failed to wait for SIGCHLD: %m");
return log_error_errno(SYNTHETIC_ERRNO(ETIMEDOUT), "Timeout reached.");
}
assert(r == SIGCHLD);
zero(si);
if (waitid(P_PID, flock_pid, &si, WEXITED|WNOHANG|WNOWAIT) < 0)
return log_error_errno(errno, "Failed to wait for child: %m");
if (si.si_pid != 0) {
assert(si.si_pid == flock_pid);
if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
return log_error_errno(SYNTHETIC_ERRNO(EPROTO), "Unexpected exit status of file lock child.");
break;
}
log_debug("Got SIGCHLD for other child, continuing.");
}
}
}
log_debug("Successfully locked %s (%u:%u)…", path, major(devno), minor(devno));
return TAKE_FD(fd);
}
int lock_main(int argc, char *argv[], void *userdata) {
_cleanup_(fdset_freep) FDSet *fds = NULL;
_cleanup_free_ dev_t *devnos = NULL;
size_t n_devnos = 0;
usec_t deadline;
pid_t pid;
int r;
r = parse_argv(argc, argv);
if (r <= 0)
return r;
STRV_FOREACH(i, arg_devices) {
r = find_devno(&devnos, &n_devnos, *i, /* backing= */ false);
if (r < 0)
return r;
}
STRV_FOREACH(i, arg_backing) {
r = find_devno(&devnos, &n_devnos, *i, /* backing= */ true);
if (r < 0)
return r;
}
assert(n_devnos > 0);
fds = fdset_new();
if (!fds)
return log_oom();
if (IN_SET(arg_timeout_usec, 0, USEC_INFINITY))
deadline = arg_timeout_usec;
else
deadline = usec_add(now(CLOCK_MONOTONIC), arg_timeout_usec);
for (size_t i = 0; i < n_devnos; i++) {
_cleanup_free_ char *node = NULL;
r = device_path_make_canonical(S_IFBLK, devnos[i], &node);
if (r < 0)
return log_error_errno(r, "Failed to format block device path: %m");
if (arg_print)
printf("%s\n", node);
else {
_cleanup_close_ int fd = -1;
fd = lock_device(node, devnos[i], deadline);
if (fd < 0)
return fd;
r = fdset_put(fds, fd);
if (r < 0)
return log_oom();
TAKE_FD(fd);
}
}
if (arg_print)
return EXIT_SUCCESS;
/* Ignore SIGINT and allow the forked process to receive it */
(void) ignore_signals(SIGINT);
r = safe_fork("(lock)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_CLOSE_ALL_FDS|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG, &pid);
if (r < 0)
return r;
if (r == 0) {
/* Child */
execvp(arg_cmdline[0], arg_cmdline);
log_open();
log_error_errno(errno, "Failed to execute %s: %m", arg_cmdline[0]);
_exit(EXIT_FAILURE);
}
return wait_for_terminate_and_check(arg_cmdline[0], pid, 0);
}

View File

@ -27,6 +27,7 @@ static int help(void) {
{ "test", "Test an event run" },
{ "test-builtin", "Test a built-in command" },
{ "wait", "Wait for device or device symlink" },
{ "lock", "Lock a block device" },
};
_cleanup_free_ char *link = NULL;
@ -103,6 +104,7 @@ static int udevadm_main(int argc, char *argv[]) {
{ "test", VERB_ANY, VERB_ANY, 0, test_main },
{ "test-builtin", VERB_ANY, VERB_ANY, 0, builtin_main },
{ "wait", VERB_ANY, VERB_ANY, 0, wait_main },
{ "lock", VERB_ANY, VERB_ANY, 0, lock_main },
{ "version", VERB_ANY, VERB_ANY, 0, version_main },
{ "help", VERB_ANY, VERB_ANY, 0, help_main },
{}

View File

@ -14,6 +14,7 @@ int hwdb_main(int argc, char *argv[], void *userdata);
int test_main(int argc, char *argv[], void *userdata);
int builtin_main(int argc, char *argv[], void *userdata);
int wait_main(int argc, char *argv[], void *userdata);
int lock_main(int argc, char *argv[], void *userdata);
static inline int print_version(void) {
/* Dracut relies on the version being a single integer */

View File

@ -174,10 +174,7 @@ rm -r /tmp/testsuite-58.3-defs/
mkdir -p /tmp/testsuite-58-issue-21817-defs/
truncate -s 100m /var/tmp/testsuite-58-issue-21817.img
LOOP=$(losetup -P --show -f /var/tmp/testsuite-58-issue-21817.img)
while : ; do
test -e "$LOOP" && break
sleep .2
done
udevadm wait --timeout 60 --initialized=yes --settle "${LOOP:?}"
printf 'size=50M,type=%s\n,\n' "${root_guid}" | sfdisk -X gpt "$LOOP"
cat >/tmp/testsuite-58-issue-21817-defs/test.conf <<EOF
[Partition]
@ -219,10 +216,7 @@ EOF
truncate -s 100m "/tmp/testsuite-58-sector-$1.img"
LOOP=$(losetup -b "$1" -P --show -f "/tmp/testsuite-58-sector-$1.img" )
while : ; do
test -e "$LOOP" && break
sleep .2
done
udevadm wait --timeout 60 --initialized=yes --settle "${LOOP:?}"
systemd-repart --pretty=yes --definitions=/tmp/testsuite-58-sector/ --seed=750b6cd5c4ae4012a15e7be3c29e6a47 --empty=require --dry-run=no "$LOOP"
rm -rf /tmp/testsuite-58-sector
sfdisk --verify "$LOOP"