mirror of
https://github.com/AuxXxilium/eudev.git
synced 2025-01-20 11:09:22 +07:00
udev: remove seqnum API and all assumptions about seqnums
The way the kernel namespaces have been implemented breaks assumptions udev made regarding uevent sequence numbers. Creating devices in a namespace "steals" uevents and its sequence numbers from the host. It confuses the "udevadmin settle" logic, which might block until util a timeout is reached, even when no uevent is pending. Remove any assumptions about sequence numbers and deprecate libudev's API exposing these numbers; none of that can reliably be used anymore when namespaces are involved. Signed-off-by: Anthony G. Basile <blueness@gentoo.org>
This commit is contained in:
parent
dbc5e32fae
commit
2500dbc810
@ -1,6 +1,6 @@
|
||||
|
||||
AC_PREREQ([2.68])
|
||||
AC_INIT([eudev],[1.6],[https://github.com/gentoo/eudev/issues])
|
||||
AC_INIT([eudev],[1.7],[https://github.com/gentoo/eudev/issues])
|
||||
AC_SUBST(UDEV_VERSION, 212)
|
||||
AC_CONFIG_SRCDIR([src/udev/udevd.c])
|
||||
|
||||
|
227
man/udevadm.xml
227
man/udevadm.xml
@ -61,9 +61,10 @@
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1><title>Description</title>
|
||||
<para>udevadm expects a command and command specific options. It
|
||||
controls the runtime behavior of udev, requests kernel events,
|
||||
manages the event queue, and provides simple debugging mechanisms.</para>
|
||||
<para><command>udevadm</command> expects a command and command
|
||||
specific options. It controls the runtime behavior of
|
||||
<command>udev</command>, requests kernel events, manages
|
||||
the event queue, and provides simple debugging mechanisms.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1><title>OPTIONS</title>
|
||||
@ -71,7 +72,7 @@
|
||||
<varlistentry>
|
||||
<term><option>--debug</option></term>
|
||||
<listitem>
|
||||
<para>Print debug messages to stderr.</para>
|
||||
<para>Print debug messages to standard error.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
@ -81,6 +82,7 @@
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>-h</option></term>
|
||||
<term><option>--help</option></term>
|
||||
<listitem>
|
||||
<para>Print help text.</para>
|
||||
@ -88,35 +90,53 @@
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
<refsect2><title>udevadm info <replaceable>options</replaceable></title>
|
||||
<refsect2><title>udevadm info <optional><replaceable>OPTIONS</replaceable></optional> <optional><replaceable>DEVPATH</replaceable>|<replaceable>FILE</replaceable></optional></title>
|
||||
<para>Queries the udev database for device information
|
||||
stored in the udev database. It can also query the properties
|
||||
of a device from its sysfs representation to help creating udev
|
||||
rules that match this device.</para>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><option>--query=<replaceable>type</replaceable></option></term>
|
||||
<term><option>-q</option></term>
|
||||
<term><option>--query=<replaceable>TYPE</replaceable></option></term>
|
||||
<listitem>
|
||||
<para>Query the database for specified type of device data. It needs the
|
||||
<option>--path</option> or <option>--name</option> to identify the specified
|
||||
device. Valid queries are:
|
||||
<command>name</command>, <command>symlink</command>, <command>path</command>,
|
||||
<command>property</command>, <command>all</command>.</para>
|
||||
<para>Query the database for the specified type of device
|
||||
data. It needs the <option>--path</option> or
|
||||
<option>--name</option> to identify the specified device.
|
||||
Valid <replaceable>TYPE</replaceable>s are:
|
||||
<constant>name</constant>, <constant>symlink</constant>,
|
||||
<constant>path</constant>, <constant>property</constant>,
|
||||
<constant>all</constant>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>--path=<replaceable>devpath</replaceable></option></term>
|
||||
<term><option>-p</option></term>
|
||||
<term><option>--path=<replaceable>DEVPATH</replaceable></option></term>
|
||||
<listitem>
|
||||
<para>The devpath of the device to query.</para>
|
||||
<para>The <filename>/sys</filename> path of the device to
|
||||
query, e.g.
|
||||
<filename><optional>/sys</optional>/class/block/sda</filename>.
|
||||
Note that this option usually is not very useful, since
|
||||
<command>udev</command> can guess the type of the
|
||||
argument, so <command>udevadm
|
||||
--devpath=/class/block/sda</command> is equivalent to
|
||||
<command>udevadm /sys/class/block/sda</command>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>--name=<replaceable>file</replaceable></option></term>
|
||||
<term><option>-n</option></term>
|
||||
<term><option>--name=<replaceable>FILE</replaceable></option></term>
|
||||
<listitem>
|
||||
<para>The name of the device node or a symlink to query</para>
|
||||
<para>The name of the device node or a symlink to query,
|
||||
e.g. <filename><optional>/dev</optional>/sda</filename>.
|
||||
Note that this option usually is not very useful, since
|
||||
<command>udev</command> can guess the type of the
|
||||
argument, so <command>udevadm --name=sda</command> is
|
||||
equivalent to <command>udevadm /dev/sda</command>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>-r</option></term>
|
||||
<term><option>--root</option></term>
|
||||
<listitem>
|
||||
<para>Print absolute paths in <command>name</command> or <command>symlink</command>
|
||||
@ -124,6 +144,7 @@
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>-a</option></term>
|
||||
<term><option>--attribute-walk</option></term>
|
||||
<listitem>
|
||||
<para>Print all sysfs properties of the specified device that can be used
|
||||
@ -132,31 +153,36 @@
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>-x</option></term>
|
||||
<term><option>--export</option></term>
|
||||
<listitem>
|
||||
<para>Print output as key/value pairs. Values are enclosed in single quotes.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>--export-prefix=<replaceable>name</replaceable></option></term>
|
||||
<term><option>-P</option></term>
|
||||
<term><option>--export-prefix=<replaceable>NAME</replaceable></option></term>
|
||||
<listitem>
|
||||
<para>Add a prefix to the key name of exported values.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>--device-id-of-file=<replaceable>file</replaceable></option></term>
|
||||
<term><option>-d</option></term>
|
||||
<term><option>--device-id-of-file=<replaceable>FILE</replaceable></option></term>
|
||||
<listitem>
|
||||
<para>Print major/minor numbers of the underlying device, where the file
|
||||
lives on.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>-e</option></term>
|
||||
<term><option>--export-db</option></term>
|
||||
<listitem>
|
||||
<para>Export the content of the udev database.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>-c</option></term>
|
||||
<term><option>--cleanup-db</option></term>
|
||||
<listitem>
|
||||
<para>Cleanup the udev database.</para>
|
||||
@ -169,6 +195,7 @@
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>-h</option></term>
|
||||
<term><option>--help</option></term>
|
||||
<listitem>
|
||||
<para>Print help text.</para>
|
||||
@ -181,19 +208,22 @@
|
||||
<para>Request device events from the kernel. Primarily used to replay events at system coldplug time.</para>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><option>-v</option></term>
|
||||
<term><option>--verbose</option></term>
|
||||
<listitem>
|
||||
<para>Print the list of devices which will be triggered.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>-n</option></term>
|
||||
<term><option>--dry-run</option></term>
|
||||
<listitem>
|
||||
<para>Do not actually trigger the event.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>--type=<replaceable>type</replaceable></option></term>
|
||||
<term><option>-t</option></term>
|
||||
<term><option>--type=<replaceable>TYPE</replaceable></option></term>
|
||||
<listitem>
|
||||
<para>Trigger a specific type of devices. Valid types are:
|
||||
<command>devices</command>, <command>subsystems</command>.
|
||||
@ -201,68 +231,95 @@
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>--action=<replaceable>action</replaceable></option></term>
|
||||
<term><option>-c</option></term>
|
||||
<term><option>--action=<replaceable>ACTION</replaceable></option></term>
|
||||
<listitem>
|
||||
<para>Type of event to be triggered. The default value is <command>change</command>.</para>
|
||||
<para>Type of event to be triggered. The default value is
|
||||
<command>change</command>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>--subsystem-match=<replaceable>subsystem</replaceable></option></term>
|
||||
<term><option>-s</option></term>
|
||||
<term><option>--subsystem-match=<replaceable>SUBSYSTEM</replaceable></option></term>
|
||||
<listitem>
|
||||
<para>Trigger events for devices which belong to a matching subsystem. This option
|
||||
can be specified multiple times and supports shell style pattern matching.</para>
|
||||
<para>Trigger events for devices which belong to a
|
||||
matching subsystem. This option can be specified multiple
|
||||
times and supports shell style pattern matching.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>--subsystem-nomatch=<replaceable>subsystem</replaceable></option></term>
|
||||
<term><option>-S</option></term>
|
||||
<term><option>--subsystem-nomatch=<replaceable>SUBSYSTEM</replaceable></option></term>
|
||||
<listitem>
|
||||
<para>Do not trigger events for devices which belong to a matching subsystem. This option
|
||||
can be specified multiple times and supports shell style pattern matching.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>--attr-match=<replaceable>attribute</replaceable>=<replaceable>value</replaceable></option></term>
|
||||
<term><option>-a</option></term>
|
||||
<term><option>--attr-match=<replaceable>ATTRIBUTE</replaceable>=<replaceable>VALUE</replaceable></option></term>
|
||||
<listitem>
|
||||
<para>Trigger events for devices with a matching sysfs attribute. If a value is specified
|
||||
along with the attribute name, the content of the attribute is matched against the given
|
||||
value using shell style pattern matching. If no value is specified, the existence of the
|
||||
sysfs attribute is checked. This option can be specified multiple times.</para>
|
||||
<para>Trigger events for devices with a matching sysfs
|
||||
attribute. If a value is specified along with the
|
||||
attribute name, the content of the attribute is matched
|
||||
against the given value using shell style pattern
|
||||
matching. If no value is specified, the existence of the
|
||||
sysfs attribute is checked. This option can be specified
|
||||
multiple times.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>--attr-nomatch=<replaceable>attribute</replaceable>=<replaceable>value</replaceable></option></term>
|
||||
<term><option>-A</option></term>
|
||||
<term><option>--attr-nomatch=<replaceable>ATTRIBUTE</replaceable>=<replaceable>VALUE</replaceable></option></term>
|
||||
<listitem>
|
||||
<para>Do not trigger events for devices with a matching sysfs attribute. If a value is
|
||||
specified along with the attribute name, the content of the attribute is matched against
|
||||
the given value using shell style pattern matching. If no value is specified, the existence
|
||||
of the sysfs attribute is checked. This option can be specified multiple times.</para>
|
||||
<para>Do not trigger events for devices with a matching
|
||||
sysfs attribute. If a value is specified along with the
|
||||
attribute name, the content of the attribute is matched
|
||||
against the given value using shell style pattern
|
||||
matching. If no value is specified, the existence of the
|
||||
sysfs attribute is checked. This option can be specified
|
||||
multiple times.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>--property-match=<replaceable>property</replaceable>=<replaceable>value</replaceable></option></term>
|
||||
<term><option>-p</option></term>
|
||||
<term><option>--property-match=<replaceable>PROPERTY</replaceable>=<replaceable>VALUE</replaceable></option></term>
|
||||
<listitem>
|
||||
<para>Trigger events for devices with a matching property value. This option can be
|
||||
specified multiple times and supports shell style pattern matching.</para>
|
||||
<para>Trigger events for devices with a matching property
|
||||
value. This option can be specified multiple times and
|
||||
supports shell style pattern matching.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>--tag-match=<replaceable>property</replaceable></option></term>
|
||||
<term><option>-g</option></term>
|
||||
<term><option>--tag-match=<replaceable>PROPERTY</replaceable></option></term>
|
||||
<listitem>
|
||||
<para>Trigger events for devices with a matching tag. This option can be
|
||||
specified multiple times.</para>
|
||||
<para>Trigger events for devices with a matching tag. This
|
||||
option can be specified multiple times.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>--sysname-match=<replaceable>name</replaceable></option></term>
|
||||
<term><option>-y</option></term>
|
||||
<term><option>--sysname-match=<replaceable>NAME</replaceable></option></term>
|
||||
<listitem>
|
||||
<para>Trigger events for devices with a matching sys device name. This option can be
|
||||
specified multiple times and supports shell style pattern matching.</para>
|
||||
<para>Trigger events for devices with a matching sys
|
||||
device name. This option can be specified multiple times
|
||||
and supports shell style pattern matching.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>--parent-match=<replaceable>syspath</replaceable></option></term>
|
||||
<term><option>-b</option></term>
|
||||
<term><option>--parent-match=<replaceable>SYSPATH</replaceable></option></term>
|
||||
<listitem>
|
||||
<para>Trigger events for all children of a given device.</para>
|
||||
<para>Trigger events for all children of a given
|
||||
device.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>-h</option></term>
|
||||
<term><option>--help</option></term>
|
||||
<listitem>
|
||||
<para>Print help text.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
@ -272,38 +329,24 @@
|
||||
<para>Watches the udev event queue, and exits if all current events are handled.</para>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><option>--timeout=<replaceable>seconds</replaceable></option></term>
|
||||
<term><option>-t</option></term>
|
||||
<term><option>--timeout=<replaceable>SECONDS</replaceable></option></term>
|
||||
<listitem>
|
||||
<para>Maximum number of seconds to wait for the event queue to become empty.
|
||||
The default value is 120 seconds. A value of 0 will check if the queue is empty
|
||||
and always return immediately.</para>
|
||||
<para>Maximum number of seconds to wait for the event
|
||||
queue to become empty. The default value is 120 seconds. A
|
||||
value of 0 will check if the queue is empty and always
|
||||
return immediately.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>--seq-start=<replaceable>seqnum</replaceable></option></term>
|
||||
<listitem>
|
||||
<para>Wait only for events after the given sequence number.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>--seq-end=<replaceable>seqnum</replaceable></option></term>
|
||||
<listitem>
|
||||
<para>Wait only for events before the given sequence number.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>--exit-if-exists=<replaceable>file</replaceable></option></term>
|
||||
<term><option>-E</option></term>
|
||||
<term><option>--exit-if-exists=<replaceable>FILE</replaceable></option></term>
|
||||
<listitem>
|
||||
<para>Stop waiting if file exists.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>--quiet</option></term>
|
||||
<listitem>
|
||||
<para>Do not print any output, like the remaining queue entries when reaching the timeout.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>-h</option></term>
|
||||
<term><option>--help</option></term>
|
||||
<listitem>
|
||||
<para>Print help text.</para>
|
||||
@ -316,12 +359,14 @@
|
||||
<para>Modify the internal state of the running udev daemon.</para>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><option>-x</option></term>
|
||||
<term><option>--exit</option></term>
|
||||
<listitem>
|
||||
<para>Signal and wait for udevd to exit.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>-l</option></term>
|
||||
<term><option>--log-priority=<replaceable>value</replaceable></option></term>
|
||||
<listitem>
|
||||
<para>Set the internal log level of udevd. Valid values are the numerical
|
||||
@ -330,6 +375,7 @@
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>-s</option></term>
|
||||
<term><option>--stop-exec-queue</option></term>
|
||||
<listitem>
|
||||
<para>Signal udevd to stop executing new events. Incoming events
|
||||
@ -337,12 +383,14 @@
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>-S</option></term>
|
||||
<term><option>--start-exec-queue</option></term>
|
||||
<listitem>
|
||||
<para>Signal udevd to enable the execution of events.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>-R</option></term>
|
||||
<term><option>--reload</option></term>
|
||||
<listitem>
|
||||
<para>Signal udevd to reload the rules files and other databases like the kernel
|
||||
@ -351,12 +399,14 @@
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>-p</option></term>
|
||||
<term><option>--property=<replaceable>KEY</replaceable>=<replaceable>value</replaceable></option></term>
|
||||
<listitem>
|
||||
<para>Set a global property for all events.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>-m</option></term>
|
||||
<term><option>--children-max=</option><replaceable>value</replaceable></term>
|
||||
<listitem>
|
||||
<para>Set the maximum number of events, udevd will handle at the
|
||||
@ -370,6 +420,7 @@
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>-h</option></term>
|
||||
<term><option>--help</option></term>
|
||||
<listitem>
|
||||
<para>Print help text.</para>
|
||||
@ -385,36 +436,42 @@
|
||||
</para>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><option>-k</option></term>
|
||||
<term><option>--kernel</option></term>
|
||||
<listitem>
|
||||
<para>Print the kernel uevents.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>-u</option></term>
|
||||
<term><option>--udev</option></term>
|
||||
<listitem>
|
||||
<para>Print the udev event after the rule processing.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>-p</option></term>
|
||||
<term><option>--property</option></term>
|
||||
<listitem>
|
||||
<para>Also print the properties of the event.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>-s</option></term>
|
||||
<term><option>--subsystem-match=<replaceable>string[/string]</replaceable></option></term>
|
||||
<listitem>
|
||||
<para>Filter events by subsystem[/devtype]. Only udev events with a matching subsystem value will pass.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>-t</option></term>
|
||||
<term><option>--tag-match=<replaceable>string</replaceable></option></term>
|
||||
<listitem>
|
||||
<para>Filter events by property. Only udev events with a given tag attached will pass.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>-h</option></term>
|
||||
<term><option>--help</option></term>
|
||||
<listitem>
|
||||
<para>Print help text.</para>
|
||||
@ -427,6 +484,7 @@
|
||||
<para>Maintain the hardware database index in <filename>/etc/udev/hwdb.bin</filename>.</para>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><option>-u</option></term>
|
||||
<term><option>--update</option></term>
|
||||
<listitem>
|
||||
<para>Compile the hardware database information located in /usr/lib/udev/hwdb.d/,
|
||||
@ -437,6 +495,7 @@
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>-t</option></term>
|
||||
<term><option>--test=<replaceable>string</replaceable></option></term>
|
||||
<listitem>
|
||||
<para>Query the database with a modalias string, and print the
|
||||
@ -444,9 +503,17 @@
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>-r</option></term>
|
||||
<term><option>--root=<replaceable>string</replaceable></option></term>
|
||||
<listitem>
|
||||
<para>Alternative root path in the filesystem for reading and writing files.</para>
|
||||
<para>Alternative root path in the file system for reading and writing files.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>-h</option></term>
|
||||
<term><option>--help</option></term>
|
||||
<listitem>
|
||||
<para>Print help text.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
@ -456,18 +523,27 @@
|
||||
<para>Simulate a udev event run for the given device, and print debug output.</para>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><option>-a</option></term>
|
||||
<term><option>--action=<replaceable>string</replaceable></option></term>
|
||||
<listitem>
|
||||
<para>The action string.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>--subsystem=<replaceable>string</replaceable></option></term>
|
||||
<term><option>-N</option></term>
|
||||
<term><option>--resolve-names=<constant>early</constant>|<constant>late</constant>|<constant>never</constant></option></term>
|
||||
<listitem>
|
||||
<para>The subsystem string.</para>
|
||||
<para>Specify when udevadm should resolve names of users
|
||||
and groups. When set to <constant>early</constant> (the
|
||||
default), names will be resolved when the rules are
|
||||
parsed. When set to <constant>late</constant>, names will
|
||||
be resolved for every event. When set to
|
||||
<constant>never</constant>, names will never be resolved
|
||||
and all devices will be owned by root.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><option>-h</option></term>
|
||||
<term><option>--help</option></term>
|
||||
<listitem>
|
||||
<para>Print help text.</para>
|
||||
@ -476,10 +552,13 @@
|
||||
</variablelist>
|
||||
</refsect2>
|
||||
|
||||
<refsect2><title>udevadm test-builtin <optional>options</optional> <replaceable>command</replaceable> <replaceable>devpath</replaceable></title>
|
||||
<para>Run a built-in command for the given device, and print debug output.</para>
|
||||
<refsect2><title>udevadm test-builtin <optional>options</optional> <replaceable>COMMAND</replaceable> <replaceable>DEVPATH</replaceable></title>
|
||||
<para>Run a built-in command <replaceable>COMMAND</replaceable>
|
||||
for device <replaceable>DEVPATH</replaceable>, and print debug
|
||||
output.</para>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><option>-h</option></term>
|
||||
<term><option>--help</option></term>
|
||||
<listitem>
|
||||
<para>Print help text.</para>
|
||||
@ -493,7 +572,7 @@
|
||||
<title>See Also</title>
|
||||
<para><citerefentry>
|
||||
<refentrytitle>udev</refentrytitle><manvolnum>7</manvolnum>
|
||||
</citerefentry>
|
||||
</citerefentry>,
|
||||
<citerefentry>
|
||||
<refentrytitle>udevd.service</refentrytitle><manvolnum>8</manvolnum>
|
||||
</citerefentry></para>
|
||||
|
@ -88,8 +88,7 @@ libudev_la_LDFLAGS = \
|
||||
|
||||
|
||||
libudev_private_la_SOURCES =\
|
||||
libudev-device-private.c \
|
||||
libudev-queue-private.c
|
||||
libudev-device-private.c
|
||||
|
||||
libudev_private_la_LIBADD =\
|
||||
libudev.la
|
||||
|
@ -146,21 +146,6 @@ static bool udev_has_devtmpfs(struct udev *udev) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* we consider udev running when we have running udev service */
|
||||
static bool udev_has_service(struct udev *udev) {
|
||||
struct udev_queue *queue;
|
||||
bool active;
|
||||
|
||||
queue = udev_queue_new(udev);
|
||||
if (!queue)
|
||||
return false;
|
||||
|
||||
active = udev_queue_get_udev_is_active(queue);
|
||||
udev_queue_unref(queue);
|
||||
|
||||
return active;
|
||||
}
|
||||
|
||||
struct udev_monitor *udev_monitor_new_from_netlink_fd(struct udev *udev, const char *name, int fd)
|
||||
{
|
||||
struct udev_monitor *udev_monitor;
|
||||
@ -184,7 +169,7 @@ struct udev_monitor *udev_monitor_new_from_netlink_fd(struct udev *udev, const c
|
||||
* We do not set a netlink multicast group here, so the socket
|
||||
* will not receive any messages.
|
||||
*/
|
||||
if (!udev_has_service(udev) && !udev_has_devtmpfs(udev)) {
|
||||
if (access("/run/udev/control", F_OK) < 0 && !udev_has_devtmpfs(udev)) {
|
||||
udev_dbg(udev, "the udev service seems not to be active, disable the monitor\n");
|
||||
group = UDEV_MONITOR_NONE;
|
||||
} else
|
||||
|
@ -1,406 +0,0 @@
|
||||
/***
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2008-2012 Kay Sievers <kay@vrfy.org>
|
||||
Copyright 2009 Alan Jenkins <alan-jenkins@tuffmail.co.uk>
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
/*
|
||||
* DISCLAIMER - The file format mentioned here is private to udev/libudev,
|
||||
* and may be changed without notice.
|
||||
*
|
||||
* The udev event queue is exported as a binary log file.
|
||||
* Each log record consists of a sequence number followed by the device path.
|
||||
*
|
||||
* When a new event is queued, its details are appended to the log.
|
||||
* When the event finishes, a second record is appended to the log
|
||||
* with the same sequence number but a devpath len of 0.
|
||||
*
|
||||
* Example:
|
||||
* { 0x0000000000000001 }
|
||||
* { 0x0000000000000001, 0x0019, "/devices/virtual/mem/null" },
|
||||
* { 0x0000000000000002, 0x001b, "/devices/virtual/mem/random" },
|
||||
* { 0x0000000000000001, 0x0000 },
|
||||
* { 0x0000000000000003, 0x0019, "/devices/virtual/mem/zero" },
|
||||
*
|
||||
* Events 2 and 3 are still queued, but event 1 has finished.
|
||||
*
|
||||
* The queue does not grow indefinitely. It is periodically re-created
|
||||
* to remove finished events. Atomic rename() makes this transparent to readers.
|
||||
*
|
||||
* The queue file starts with a single sequence number which specifies the
|
||||
* minimum sequence number in the log that follows. Any events prior to this
|
||||
* sequence number have already finished.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <dirent.h>
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "libudev.h"
|
||||
#include "libudev-private.h"
|
||||
|
||||
static int rebuild_queue_file(struct udev_queue_export *udev_queue_export);
|
||||
|
||||
struct udev_queue_export {
|
||||
struct udev *udev;
|
||||
int queued_count; /* number of unfinished events exported in queue file */
|
||||
FILE *queue_file;
|
||||
unsigned long long int seqnum_max; /* earliest sequence number in queue file */
|
||||
unsigned long long int seqnum_min; /* latest sequence number in queue file */
|
||||
int waste_bytes; /* queue file bytes wasted on finished events */
|
||||
};
|
||||
|
||||
struct udev_queue_export *udev_queue_export_new(struct udev *udev)
|
||||
{
|
||||
struct udev_queue_export *udev_queue_export;
|
||||
unsigned long long int initial_seqnum;
|
||||
|
||||
if (udev == NULL)
|
||||
return NULL;
|
||||
|
||||
udev_queue_export = new0(struct udev_queue_export, 1);
|
||||
if (udev_queue_export == NULL)
|
||||
return NULL;
|
||||
udev_queue_export->udev = udev;
|
||||
|
||||
initial_seqnum = udev_get_kernel_seqnum(udev);
|
||||
udev_queue_export->seqnum_min = initial_seqnum;
|
||||
udev_queue_export->seqnum_max = initial_seqnum;
|
||||
|
||||
udev_queue_export_cleanup(udev_queue_export);
|
||||
if (rebuild_queue_file(udev_queue_export) != 0) {
|
||||
free(udev_queue_export);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return udev_queue_export;
|
||||
}
|
||||
|
||||
struct udev_queue_export *udev_queue_export_unref(struct udev_queue_export *udev_queue_export)
|
||||
{
|
||||
if (udev_queue_export == NULL)
|
||||
return NULL;
|
||||
if (udev_queue_export->queue_file != NULL)
|
||||
fclose(udev_queue_export->queue_file);
|
||||
free(udev_queue_export);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void udev_queue_export_cleanup(struct udev_queue_export *udev_queue_export)
|
||||
{
|
||||
if (udev_queue_export == NULL)
|
||||
return;
|
||||
unlink("/run/udev/queue.tmp");
|
||||
unlink("/run/udev/queue.bin");
|
||||
}
|
||||
|
||||
static int skip_to(FILE *file, long offset)
|
||||
{
|
||||
long old_offset;
|
||||
|
||||
/* fseek may drop buffered data, avoid it for small seeks */
|
||||
old_offset = ftell(file);
|
||||
if (offset > old_offset && offset - old_offset <= BUFSIZ) {
|
||||
size_t skip_bytes = offset - old_offset;
|
||||
char *buf = alloca(skip_bytes);
|
||||
|
||||
if (fread(buf, skip_bytes, 1, file) != skip_bytes)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fseek(file, offset, SEEK_SET);
|
||||
}
|
||||
|
||||
struct queue_devpaths {
|
||||
unsigned int devpaths_first; /* index of first queued event */
|
||||
unsigned int devpaths_size;
|
||||
long devpaths[]; /* seqnum -> offset of devpath in queue file (or 0) */
|
||||
};
|
||||
|
||||
/*
|
||||
* Returns a table mapping seqnum to devpath file offset for currently queued events.
|
||||
* devpaths[i] represents the event with seqnum = i + udev_queue_export->seqnum_min.
|
||||
*/
|
||||
static struct queue_devpaths *build_index(struct udev_queue_export *udev_queue_export)
|
||||
{
|
||||
struct queue_devpaths *devpaths;
|
||||
unsigned long long int range;
|
||||
long devpath_offset;
|
||||
ssize_t devpath_len;
|
||||
unsigned long long int seqnum;
|
||||
unsigned long long int n;
|
||||
unsigned int i;
|
||||
|
||||
/* seek to the first event in the file */
|
||||
rewind(udev_queue_export->queue_file);
|
||||
udev_queue_read_seqnum(udev_queue_export->queue_file, &seqnum);
|
||||
|
||||
/* allocate the table */
|
||||
range = udev_queue_export->seqnum_min - udev_queue_export->seqnum_max;
|
||||
if (range - 1 > INT_MAX) {
|
||||
udev_err(udev_queue_export->udev, "queue file overflow\n");
|
||||
return NULL;
|
||||
}
|
||||
devpaths = malloc0(sizeof(struct queue_devpaths) + (range + 1) * sizeof(long));
|
||||
if (devpaths == NULL)
|
||||
return NULL;
|
||||
devpaths->devpaths_size = range + 1;
|
||||
|
||||
/* read all records and populate the table */
|
||||
for (;;) {
|
||||
if (udev_queue_read_seqnum(udev_queue_export->queue_file, &seqnum) < 0)
|
||||
break;
|
||||
n = seqnum - udev_queue_export->seqnum_max;
|
||||
if (n >= devpaths->devpaths_size)
|
||||
goto read_error;
|
||||
|
||||
devpath_offset = ftell(udev_queue_export->queue_file);
|
||||
devpath_len = udev_queue_skip_devpath(udev_queue_export->queue_file);
|
||||
if (devpath_len < 0)
|
||||
goto read_error;
|
||||
|
||||
if (devpath_len > 0)
|
||||
devpaths->devpaths[n] = devpath_offset;
|
||||
else
|
||||
devpaths->devpaths[n] = 0;
|
||||
}
|
||||
|
||||
/* find first queued event */
|
||||
for (i = 0; i < devpaths->devpaths_size; i++) {
|
||||
if (devpaths->devpaths[i] != 0)
|
||||
break;
|
||||
}
|
||||
devpaths->devpaths_first = i;
|
||||
|
||||
return devpaths;
|
||||
|
||||
read_error:
|
||||
udev_err(udev_queue_export->udev, "queue file corrupted\n");
|
||||
free(devpaths);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int rebuild_queue_file(struct udev_queue_export *udev_queue_export)
|
||||
{
|
||||
unsigned long long int seqnum;
|
||||
struct queue_devpaths *devpaths = NULL;
|
||||
FILE *new_queue_file = NULL;
|
||||
unsigned int i;
|
||||
|
||||
/* read old queue file */
|
||||
if (udev_queue_export->queue_file != NULL) {
|
||||
devpaths = build_index(udev_queue_export);
|
||||
if (devpaths != NULL)
|
||||
udev_queue_export->seqnum_max += devpaths->devpaths_first;
|
||||
}
|
||||
if (devpaths == NULL) {
|
||||
udev_queue_export->queued_count = 0;
|
||||
udev_queue_export->seqnum_max = udev_queue_export->seqnum_min;
|
||||
}
|
||||
|
||||
/* create new queue file */
|
||||
new_queue_file = fopen("/run/udev/queue.tmp", "w+e");
|
||||
if (new_queue_file == NULL)
|
||||
goto error;
|
||||
seqnum = udev_queue_export->seqnum_max;
|
||||
fwrite(&seqnum, 1, sizeof(unsigned long long int), new_queue_file);
|
||||
|
||||
/* copy unfinished events only to the new file */
|
||||
if (devpaths != NULL) {
|
||||
for (i = devpaths->devpaths_first; i < devpaths->devpaths_size; i++) {
|
||||
char devpath[UTIL_PATH_SIZE];
|
||||
int err;
|
||||
unsigned short devpath_len;
|
||||
|
||||
if (devpaths->devpaths[i] != 0)
|
||||
{
|
||||
skip_to(udev_queue_export->queue_file, devpaths->devpaths[i]);
|
||||
err = udev_queue_read_devpath(udev_queue_export->queue_file, devpath, sizeof(devpath));
|
||||
devpath_len = err;
|
||||
|
||||
fwrite(&seqnum, sizeof(unsigned long long int), 1, new_queue_file);
|
||||
fwrite(&devpath_len, sizeof(unsigned short), 1, new_queue_file);
|
||||
fwrite(devpath, 1, devpath_len, new_queue_file);
|
||||
}
|
||||
seqnum++;
|
||||
}
|
||||
free(devpaths);
|
||||
devpaths = NULL;
|
||||
}
|
||||
fflush(new_queue_file);
|
||||
if (ferror(new_queue_file))
|
||||
goto error;
|
||||
|
||||
/* rename the new file on top of the old one */
|
||||
if (rename("/run/udev/queue.tmp", "/run/udev/queue.bin") != 0)
|
||||
goto error;
|
||||
|
||||
if (udev_queue_export->queue_file != NULL)
|
||||
fclose(udev_queue_export->queue_file);
|
||||
udev_queue_export->queue_file = new_queue_file;
|
||||
udev_queue_export->waste_bytes = 0;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
udev_err(udev_queue_export->udev, "failed to create queue file: %m\n");
|
||||
udev_queue_export_cleanup(udev_queue_export);
|
||||
|
||||
if (udev_queue_export->queue_file != NULL) {
|
||||
fclose(udev_queue_export->queue_file);
|
||||
udev_queue_export->queue_file = NULL;
|
||||
}
|
||||
if (new_queue_file != NULL)
|
||||
fclose(new_queue_file);
|
||||
|
||||
if (devpaths != NULL)
|
||||
free(devpaths);
|
||||
udev_queue_export->queued_count = 0;
|
||||
udev_queue_export->waste_bytes = 0;
|
||||
udev_queue_export->seqnum_max = udev_queue_export->seqnum_min;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int write_queue_record(struct udev_queue_export *udev_queue_export,
|
||||
unsigned long long int seqnum, const char *devpath, size_t devpath_len)
|
||||
{
|
||||
unsigned short len;
|
||||
|
||||
if (udev_queue_export->queue_file == NULL)
|
||||
return -1;
|
||||
|
||||
if (fwrite(&seqnum, sizeof(unsigned long long int), 1, udev_queue_export->queue_file) != 1)
|
||||
goto write_error;
|
||||
|
||||
len = (devpath_len < USHRT_MAX) ? devpath_len : USHRT_MAX;
|
||||
if (fwrite(&len, sizeof(unsigned short), 1, udev_queue_export->queue_file) != 1)
|
||||
goto write_error;
|
||||
if (len > 0) {
|
||||
if (fwrite(devpath, 1, len, udev_queue_export->queue_file) != len)
|
||||
goto write_error;
|
||||
}
|
||||
|
||||
/* *must* flush output; caller may fork */
|
||||
if (fflush(udev_queue_export->queue_file) != 0)
|
||||
goto write_error;
|
||||
|
||||
return 0;
|
||||
|
||||
write_error:
|
||||
/* if we failed half way through writing a record to a file,
|
||||
we should not try to write any further records to it. */
|
||||
udev_err(udev_queue_export->udev, "error writing to queue file: %m\n");
|
||||
fclose(udev_queue_export->queue_file);
|
||||
udev_queue_export->queue_file = NULL;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
enum device_state {
|
||||
DEVICE_QUEUED,
|
||||
DEVICE_FINISHED,
|
||||
};
|
||||
|
||||
static inline size_t queue_record_size(size_t devpath_len)
|
||||
{
|
||||
return sizeof(unsigned long long int) + sizeof(unsigned short int) + devpath_len;
|
||||
}
|
||||
|
||||
static int update_queue(struct udev_queue_export *udev_queue_export,
|
||||
struct udev_device *udev_device, enum device_state state)
|
||||
{
|
||||
unsigned long long int seqnum = udev_device_get_seqnum(udev_device);
|
||||
const char *devpath = NULL;
|
||||
size_t devpath_len = 0;
|
||||
int bytes;
|
||||
int err;
|
||||
|
||||
/* FINISHED records have a zero length devpath */
|
||||
if (state == DEVICE_QUEUED) {
|
||||
devpath = udev_device_get_devpath(udev_device);
|
||||
devpath_len = strlen(devpath);
|
||||
}
|
||||
|
||||
/* recover from an earlier failed rebuild */
|
||||
if (udev_queue_export->queue_file == NULL) {
|
||||
if (rebuild_queue_file(udev_queue_export) != 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* if we're removing the last event from the queue, that's the best time to rebuild it */
|
||||
if (state != DEVICE_QUEUED && udev_queue_export->queued_count == 1) {
|
||||
/* we don't need to read the old queue file */
|
||||
fclose(udev_queue_export->queue_file);
|
||||
udev_queue_export->queue_file = NULL;
|
||||
rebuild_queue_file(udev_queue_export);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* try to rebuild the queue files before they grow larger than one page. */
|
||||
bytes = ftell(udev_queue_export->queue_file) + queue_record_size(devpath_len);
|
||||
if ((udev_queue_export->waste_bytes > bytes / 2) && bytes > 4096)
|
||||
rebuild_queue_file(udev_queue_export);
|
||||
|
||||
/* don't record a finished event, if we already dropped the event in a failed rebuild */
|
||||
if (seqnum < udev_queue_export->seqnum_max)
|
||||
return 0;
|
||||
|
||||
/* now write to the queue */
|
||||
if (state == DEVICE_QUEUED) {
|
||||
udev_queue_export->queued_count++;
|
||||
udev_queue_export->seqnum_min = seqnum;
|
||||
} else {
|
||||
udev_queue_export->waste_bytes += queue_record_size(devpath_len) + queue_record_size(0);
|
||||
udev_queue_export->queued_count--;
|
||||
}
|
||||
err = write_queue_record(udev_queue_export, seqnum, devpath, devpath_len);
|
||||
|
||||
/* try to handle ENOSPC */
|
||||
if (err != 0 && udev_queue_export->queued_count == 0) {
|
||||
udev_queue_export_cleanup(udev_queue_export);
|
||||
err = rebuild_queue_file(udev_queue_export);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int update(struct udev_queue_export *udev_queue_export,
|
||||
struct udev_device *udev_device, enum device_state state)
|
||||
{
|
||||
if (update_queue(udev_queue_export, udev_device, state) != 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int udev_queue_export_device_queued(struct udev_queue_export *udev_queue_export, struct udev_device *udev_device)
|
||||
{
|
||||
return update(udev_queue_export, udev_device, DEVICE_QUEUED);
|
||||
}
|
||||
|
||||
int udev_queue_export_device_finished(struct udev_queue_export *udev_queue_export, struct udev_device *udev_device)
|
||||
{
|
||||
return update(udev_queue_export, udev_device, DEVICE_FINISHED);
|
||||
}
|
@ -24,8 +24,6 @@
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
@ -36,10 +34,7 @@
|
||||
* SECTION:libudev-queue
|
||||
* @short_description: access to currently active events
|
||||
*
|
||||
* The udev daemon processes events asynchronously. All events which do not have
|
||||
* interdependencies run in parallel. This exports the current state of the
|
||||
* event processing queue, and the current event sequence numbers from the kernel
|
||||
* and the udev daemon.
|
||||
* This exports the current state of the udev processing queue.
|
||||
*/
|
||||
|
||||
/**
|
||||
@ -50,7 +45,6 @@
|
||||
struct udev_queue {
|
||||
struct udev *udev;
|
||||
int refcount;
|
||||
struct udev_list queue_list;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -72,9 +66,9 @@ _public_ struct udev_queue *udev_queue_new(struct udev *udev)
|
||||
udev_queue = new0(struct udev_queue, 1);
|
||||
if (udev_queue == NULL)
|
||||
return NULL;
|
||||
|
||||
udev_queue->refcount = 1;
|
||||
udev_queue->udev = udev;
|
||||
udev_list_init(udev, &udev_queue->queue_list, false);
|
||||
return udev_queue;
|
||||
}
|
||||
|
||||
@ -90,6 +84,7 @@ _public_ struct udev_queue *udev_queue_ref(struct udev_queue *udev_queue)
|
||||
{
|
||||
if (udev_queue == NULL)
|
||||
return NULL;
|
||||
|
||||
udev_queue->refcount++;
|
||||
return udev_queue;
|
||||
}
|
||||
@ -107,10 +102,11 @@ _public_ struct udev_queue *udev_queue_unref(struct udev_queue *udev_queue)
|
||||
{
|
||||
if (udev_queue == NULL)
|
||||
return NULL;
|
||||
|
||||
udev_queue->refcount--;
|
||||
if (udev_queue->refcount > 0)
|
||||
return NULL;
|
||||
udev_list_cleanup(&udev_queue->queue_list);
|
||||
|
||||
free(udev_queue);
|
||||
return NULL;
|
||||
}
|
||||
@ -130,141 +126,30 @@ _public_ struct udev *udev_queue_get_udev(struct udev_queue *udev_queue)
|
||||
return udev_queue->udev;
|
||||
}
|
||||
|
||||
unsigned long long int udev_get_kernel_seqnum(struct udev *udev)
|
||||
{
|
||||
unsigned long long int seqnum;
|
||||
int fd;
|
||||
char buf[32];
|
||||
ssize_t len;
|
||||
|
||||
fd = open("/sys/kernel/uevent_seqnum", O_RDONLY|O_CLOEXEC);
|
||||
if (fd < 0)
|
||||
return 0;
|
||||
len = read(fd, buf, sizeof(buf));
|
||||
close(fd);
|
||||
if (len <= 2)
|
||||
return 0;
|
||||
buf[len-1] = '\0';
|
||||
seqnum = strtoull(buf, NULL, 10);
|
||||
return seqnum;
|
||||
}
|
||||
|
||||
/**
|
||||
* udev_queue_get_kernel_seqnum:
|
||||
* @udev_queue: udev queue context
|
||||
*
|
||||
* Get the current kernel event sequence number.
|
||||
* This function is deprecated.
|
||||
*
|
||||
* Returns: the sequence number.
|
||||
* Returns: 0.
|
||||
**/
|
||||
_public_ unsigned long long int udev_queue_get_kernel_seqnum(struct udev_queue *udev_queue)
|
||||
{
|
||||
unsigned long long int seqnum;
|
||||
|
||||
if (udev_queue == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
seqnum = udev_get_kernel_seqnum(udev_queue->udev);
|
||||
return seqnum;
|
||||
}
|
||||
|
||||
int udev_queue_read_seqnum(FILE *queue_file, unsigned long long int *seqnum)
|
||||
{
|
||||
if (fread(seqnum, sizeof(unsigned long long int), 1, queue_file) != 1)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t udev_queue_skip_devpath(FILE *queue_file)
|
||||
{
|
||||
unsigned short int len;
|
||||
|
||||
if (fread(&len, sizeof(unsigned short int), 1, queue_file) == 1) {
|
||||
char *devpath = alloca(len);
|
||||
|
||||
/* use fread to skip, fseek might drop buffered data */
|
||||
if (fread(devpath, 1, len, queue_file) == len)
|
||||
return len;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
ssize_t udev_queue_read_devpath(FILE *queue_file, char *devpath, size_t size)
|
||||
{
|
||||
unsigned short int read_bytes = 0;
|
||||
unsigned short int len;
|
||||
|
||||
if (fread(&len, sizeof(unsigned short int), 1, queue_file) != 1)
|
||||
return -1;
|
||||
|
||||
read_bytes = (len < size - 1) ? len : size - 1;
|
||||
if (fread(devpath, 1, read_bytes, queue_file) != read_bytes)
|
||||
return -1;
|
||||
devpath[read_bytes] = '\0';
|
||||
|
||||
/* if devpath was too long, skip unread characters */
|
||||
if (read_bytes != len) {
|
||||
unsigned short int skip_bytes = len - read_bytes;
|
||||
char *buf = alloca(skip_bytes);
|
||||
|
||||
if (fread(buf, 1, skip_bytes, queue_file) != skip_bytes)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return read_bytes;
|
||||
}
|
||||
|
||||
static FILE *open_queue_file(struct udev_queue *udev_queue, unsigned long long int *seqnum_start)
|
||||
{
|
||||
FILE *queue_file;
|
||||
|
||||
queue_file = fopen("/run/udev/queue.bin", "re");
|
||||
if (queue_file == NULL)
|
||||
return NULL;
|
||||
|
||||
if (udev_queue_read_seqnum(queue_file, seqnum_start) < 0) {
|
||||
udev_err(udev_queue->udev, "corrupt queue file\n");
|
||||
fclose(queue_file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return queue_file;
|
||||
}
|
||||
|
||||
/**
|
||||
* udev_queue_get_udev_seqnum:
|
||||
* @udev_queue: udev queue context
|
||||
*
|
||||
* Get the last known udev event sequence number.
|
||||
* This function is deprecated.
|
||||
*
|
||||
* Returns: the sequence number.
|
||||
* Returns: 0.
|
||||
**/
|
||||
_public_ unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *udev_queue)
|
||||
{
|
||||
unsigned long long int seqnum_udev;
|
||||
FILE *queue_file;
|
||||
|
||||
queue_file = open_queue_file(udev_queue, &seqnum_udev);
|
||||
if (queue_file == NULL)
|
||||
return 0;
|
||||
|
||||
for (;;) {
|
||||
unsigned long long int seqnum;
|
||||
ssize_t devpath_len;
|
||||
|
||||
if (udev_queue_read_seqnum(queue_file, &seqnum) < 0)
|
||||
break;
|
||||
devpath_len = udev_queue_skip_devpath(queue_file);
|
||||
if (devpath_len < 0)
|
||||
break;
|
||||
if (devpath_len > 0)
|
||||
seqnum_udev = seqnum;
|
||||
}
|
||||
|
||||
fclose(queue_file);
|
||||
return seqnum_udev;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -277,15 +162,7 @@ _public_ unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *ud
|
||||
**/
|
||||
_public_ int udev_queue_get_udev_is_active(struct udev_queue *udev_queue)
|
||||
{
|
||||
unsigned long long int seqnum_start;
|
||||
FILE *queue_file;
|
||||
|
||||
queue_file = open_queue_file(udev_queue, &seqnum_start);
|
||||
if (queue_file == NULL)
|
||||
return 0;
|
||||
|
||||
fclose(queue_file);
|
||||
return 1;
|
||||
return access("/run/udev/control", F_OK) >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -298,48 +175,7 @@ _public_ int udev_queue_get_udev_is_active(struct udev_queue *udev_queue)
|
||||
**/
|
||||
_public_ int udev_queue_get_queue_is_empty(struct udev_queue *udev_queue)
|
||||
{
|
||||
unsigned long long int seqnum_kernel;
|
||||
unsigned long long int seqnum_udev = 0;
|
||||
int queued = 0;
|
||||
int is_empty = 0;
|
||||
FILE *queue_file;
|
||||
|
||||
if (udev_queue == NULL)
|
||||
return -EINVAL;
|
||||
queue_file = open_queue_file(udev_queue, &seqnum_udev);
|
||||
if (queue_file == NULL)
|
||||
return 1;
|
||||
|
||||
for (;;) {
|
||||
unsigned long long int seqnum;
|
||||
ssize_t devpath_len;
|
||||
|
||||
if (udev_queue_read_seqnum(queue_file, &seqnum) < 0)
|
||||
break;
|
||||
devpath_len = udev_queue_skip_devpath(queue_file);
|
||||
if (devpath_len < 0)
|
||||
break;
|
||||
|
||||
if (devpath_len > 0) {
|
||||
queued++;
|
||||
seqnum_udev = seqnum;
|
||||
} else {
|
||||
queued--;
|
||||
}
|
||||
}
|
||||
|
||||
if (queued > 0)
|
||||
goto out;
|
||||
|
||||
seqnum_kernel = udev_queue_get_kernel_seqnum(udev_queue);
|
||||
if (seqnum_udev < seqnum_kernel)
|
||||
goto out;
|
||||
|
||||
is_empty = 1;
|
||||
|
||||
out:
|
||||
fclose(queue_file);
|
||||
return is_empty;
|
||||
return access("/run/udev/queue", F_OK) >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -348,63 +184,15 @@ out:
|
||||
* @start: first event sequence number
|
||||
* @end: last event sequence number
|
||||
*
|
||||
* Check if udev is currently processing any events in a given sequence number range.
|
||||
* This function is deprecated, it just returns the result of
|
||||
* udev_queue_get_queue_is_empty().
|
||||
*
|
||||
* Returns: a flag indicating if any of the sequence numbers in the given range is currently active.
|
||||
* Returns: a flag indicating if udev is currently handling events.
|
||||
**/
|
||||
_public_ int udev_queue_get_seqnum_sequence_is_finished(struct udev_queue *udev_queue,
|
||||
unsigned long long int start, unsigned long long int end)
|
||||
{
|
||||
unsigned long long int seqnum;
|
||||
ssize_t devpath_len;
|
||||
int unfinished;
|
||||
FILE *queue_file;
|
||||
|
||||
if (udev_queue == NULL)
|
||||
return -EINVAL;
|
||||
queue_file = open_queue_file(udev_queue, &seqnum);
|
||||
if (queue_file == NULL)
|
||||
return 1;
|
||||
if (start < seqnum)
|
||||
start = seqnum;
|
||||
if (start > end) {
|
||||
fclose(queue_file);
|
||||
return 1;
|
||||
}
|
||||
if (end - start > INT_MAX - 1) {
|
||||
fclose(queue_file);
|
||||
return -EOVERFLOW;
|
||||
}
|
||||
|
||||
/*
|
||||
* we might start with 0, and handle the initial seqnum
|
||||
* only when we find an entry in the queue file
|
||||
**/
|
||||
unfinished = end - start;
|
||||
|
||||
do {
|
||||
if (udev_queue_read_seqnum(queue_file, &seqnum) < 0)
|
||||
break;
|
||||
devpath_len = udev_queue_skip_devpath(queue_file);
|
||||
if (devpath_len < 0)
|
||||
break;
|
||||
|
||||
/*
|
||||
* we might start with an empty or re-build queue file, where
|
||||
* the initial seqnum is not recorded as finished
|
||||
*/
|
||||
if (start == seqnum && devpath_len > 0)
|
||||
unfinished++;
|
||||
|
||||
if (devpath_len == 0) {
|
||||
if (seqnum >= start && seqnum <= end)
|
||||
unfinished--;
|
||||
}
|
||||
} while (unfinished > 0);
|
||||
|
||||
fclose(queue_file);
|
||||
|
||||
return (unfinished == 0);
|
||||
return udev_queue_get_queue_is_empty(udev_queue);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -412,69 +200,25 @@ _public_ int udev_queue_get_seqnum_sequence_is_finished(struct udev_queue *udev_
|
||||
* @udev_queue: udev queue context
|
||||
* @seqnum: sequence number
|
||||
*
|
||||
* Check if udev is currently processing a given sequence number.
|
||||
* This function is deprecated, it just returns the result of
|
||||
* udev_queue_get_queue_is_empty().
|
||||
*
|
||||
* Returns: a flag indicating if the given sequence number is currently active.
|
||||
* Returns: a flag indicating if udev is currently handling events.
|
||||
**/
|
||||
_public_ int udev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, unsigned long long int seqnum)
|
||||
{
|
||||
if (!udev_queue_get_seqnum_sequence_is_finished(udev_queue, seqnum, seqnum))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
return udev_queue_get_queue_is_empty(udev_queue);
|
||||
}
|
||||
|
||||
/**
|
||||
* udev_queue_get_queued_list_entry:
|
||||
* @udev_queue: udev queue context
|
||||
*
|
||||
* Get the first entry of the list of queued events.
|
||||
* This function is deprecated.
|
||||
*
|
||||
* Returns: a udev_list_entry.
|
||||
* Returns: NULL.
|
||||
**/
|
||||
_public_ struct udev_list_entry *udev_queue_get_queued_list_entry(struct udev_queue *udev_queue)
|
||||
{
|
||||
unsigned long long int seqnum;
|
||||
FILE *queue_file;
|
||||
|
||||
if (udev_queue == NULL)
|
||||
return NULL;
|
||||
udev_list_cleanup(&udev_queue->queue_list);
|
||||
|
||||
queue_file = open_queue_file(udev_queue, &seqnum);
|
||||
if (queue_file == NULL)
|
||||
return NULL;
|
||||
|
||||
for (;;) {
|
||||
char syspath[UTIL_PATH_SIZE];
|
||||
char *s;
|
||||
size_t l;
|
||||
ssize_t len;
|
||||
char seqnum_str[32];
|
||||
struct udev_list_entry *list_entry;
|
||||
|
||||
if (udev_queue_read_seqnum(queue_file, &seqnum) < 0)
|
||||
break;
|
||||
snprintf(seqnum_str, sizeof(seqnum_str), "%llu", seqnum);
|
||||
|
||||
s = syspath;
|
||||
l = strpcpy(&s, sizeof(syspath), "/sys");
|
||||
len = udev_queue_read_devpath(queue_file, s, l);
|
||||
if (len < 0)
|
||||
break;
|
||||
|
||||
if (len > 0) {
|
||||
udev_list_entry_add(&udev_queue->queue_list, syspath, seqnum_str);
|
||||
} else {
|
||||
udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_queue->queue_list)) {
|
||||
if (streq(seqnum_str, udev_list_entry_get_value(list_entry))) {
|
||||
udev_list_entry_delete(list_entry);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(queue_file);
|
||||
|
||||
return udev_list_get_entry(&udev_queue->queue_list);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -170,14 +170,14 @@ struct udev_queue *udev_queue_ref(struct udev_queue *udev_queue);
|
||||
struct udev_queue *udev_queue_unref(struct udev_queue *udev_queue);
|
||||
struct udev *udev_queue_get_udev(struct udev_queue *udev_queue);
|
||||
struct udev_queue *udev_queue_new(struct udev *udev);
|
||||
unsigned long long int udev_queue_get_kernel_seqnum(struct udev_queue *udev_queue);
|
||||
unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *udev_queue);
|
||||
unsigned long long int udev_queue_get_kernel_seqnum(struct udev_queue *udev_queue) __attribute__ ((deprecated));
|
||||
unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *udev_queue) __attribute__ ((deprecated));
|
||||
int udev_queue_get_udev_is_active(struct udev_queue *udev_queue);
|
||||
int udev_queue_get_queue_is_empty(struct udev_queue *udev_queue);
|
||||
int udev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, unsigned long long int seqnum);
|
||||
int udev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, unsigned long long int seqnum) __attribute__ ((deprecated));
|
||||
int udev_queue_get_seqnum_sequence_is_finished(struct udev_queue *udev_queue,
|
||||
unsigned long long int start, unsigned long long int end);
|
||||
struct udev_list_entry *udev_queue_get_queued_list_entry(struct udev_queue *udev_queue);
|
||||
unsigned long long int start, unsigned long long int end) __attribute__ ((deprecated));
|
||||
struct udev_list_entry *udev_queue_get_queued_list_entry(struct udev_queue *udev_queue) __attribute__ ((deprecated));
|
||||
|
||||
/*
|
||||
* udev_hwdb
|
||||
|
@ -297,7 +297,7 @@ static int ctrl_send(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, int
|
||||
|
||||
pfd[0].fd = uctrl->sock;
|
||||
pfd[0].events = POLLIN;
|
||||
r = poll(pfd, 1, timeout * 1000);
|
||||
r = poll(pfd, 1, timeout * MSEC_PER_SEC);
|
||||
if (r < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
|
@ -31,7 +31,6 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_event*, udev_event_unref);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_rules*, udev_rules_unref);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_ctrl*, udev_ctrl_unref);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_monitor*, udev_monitor_unref);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_queue*, udev_queue_unref);
|
||||
|
||||
#define _cleanup_udev_unref_ _cleanup_(udev_unrefp)
|
||||
#define _cleanup_udev_device_unref_ _cleanup_(udev_device_unrefp)
|
||||
@ -40,5 +39,4 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_queue*, udev_queue_unref);
|
||||
#define _cleanup_udev_rules_unref_ _cleanup_(udev_rules_unrefp)
|
||||
#define _cleanup_udev_ctrl_unref_ _cleanup_(udev_ctrl_unrefp)
|
||||
#define _cleanup_udev_monitor_unref_ _cleanup_(udev_monitor_unrefp)
|
||||
#define _cleanup_udev_queue_unref_ _cleanup_(udev_queue_unrefp)
|
||||
#define _cleanup_udev_list_cleanup_ _cleanup_(udev_list_cleanup)
|
||||
|
@ -41,42 +41,28 @@
|
||||
static void help(void) {
|
||||
printf("Usage: udevadm settle OPTIONS\n"
|
||||
" -t,--timeout=<seconds> maximum time to wait for events\n"
|
||||
" -s,--seq-start=<seqnum> first seqnum to wait for\n"
|
||||
" -e,--seq-end=<seqnum> last seqnum to wait for\n"
|
||||
" -E,--exit-if-exists=<file> stop waiting if file exists\n"
|
||||
" -q,--quiet do not print list after timeout\n"
|
||||
" -h,--help\n\n");
|
||||
}
|
||||
|
||||
static int adm_settle(struct udev *udev, int argc, char *argv[])
|
||||
{
|
||||
static const struct option options[] = {
|
||||
{ "seq-start", required_argument, NULL, 's' },
|
||||
{ "seq-end", required_argument, NULL, 'e' },
|
||||
{ "seq-start", required_argument, NULL, '\0' }, /* removed */
|
||||
{ "seq-end", required_argument, NULL, '\0' }, /* removed */
|
||||
{ "timeout", required_argument, NULL, 't' },
|
||||
{ "exit-if-exists", required_argument, NULL, 'E' },
|
||||
{ "quiet", no_argument, NULL, 'q' },
|
||||
{ "quiet", no_argument, NULL, 'q' }, /* removed */
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{}
|
||||
};
|
||||
usec_t start_usec = now(CLOCK_MONOTONIC);
|
||||
usec_t start = 0;
|
||||
usec_t end = 0;
|
||||
int quiet = 0;
|
||||
const char *exists = NULL;
|
||||
unsigned int timeout = 120;
|
||||
struct pollfd pfd[1] = { {.fd = -1}, };
|
||||
_cleanup_udev_queue_unref_ struct udev_queue *udev_queue = NULL;
|
||||
int rc = EXIT_FAILURE, c;
|
||||
|
||||
while ((c = getopt_long(argc, argv, "s:e:t:E:qh", options, NULL)) >= 0)
|
||||
while ((c = getopt_long(argc, argv, "s:e:t:E:qh", options, NULL)) >= 0) {
|
||||
switch (c) {
|
||||
case 's':
|
||||
start = strtoull(optarg, NULL, 0);
|
||||
break;
|
||||
case 'e':
|
||||
end = strtoull(optarg, NULL, 0);
|
||||
break;
|
||||
case 't': {
|
||||
int r;
|
||||
|
||||
@ -91,9 +77,6 @@ static int adm_settle(struct udev *udev, int argc, char *argv[])
|
||||
case 'E':
|
||||
exists = optarg;
|
||||
break;
|
||||
case 'q':
|
||||
quiet = 1;
|
||||
break;
|
||||
case 'h':
|
||||
help();
|
||||
exit(EXIT_SUCCESS);
|
||||
@ -102,44 +85,13 @@ static int adm_settle(struct udev *udev, int argc, char *argv[])
|
||||
default:
|
||||
assert_not_reached("Unknown argument");
|
||||
}
|
||||
}
|
||||
|
||||
if (optind < argc) {
|
||||
fprintf(stderr, "Extraneous argument: '%s'\n", argv[optind]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
udev_queue = udev_queue_new(udev);
|
||||
if (udev_queue == NULL)
|
||||
exit(2);
|
||||
|
||||
if (start > 0) {
|
||||
unsigned long long kernel_seq;
|
||||
|
||||
kernel_seq = udev_queue_get_kernel_seqnum(udev_queue);
|
||||
|
||||
/* unless specified, the last event is the current kernel seqnum */
|
||||
if (end == 0)
|
||||
end = udev_queue_get_kernel_seqnum(udev_queue);
|
||||
|
||||
if (start > end) {
|
||||
log_error("seq-start larger than seq-end, ignoring");
|
||||
start = 0;
|
||||
end = 0;
|
||||
}
|
||||
|
||||
if (start > kernel_seq || end > kernel_seq) {
|
||||
log_error("seq-start or seq-end larger than current kernel value, ignoring");
|
||||
start = 0;
|
||||
end = 0;
|
||||
}
|
||||
log_debug("start=%llu end=%llu current=%llu", (unsigned long long)start, (unsigned long long)end, kernel_seq);
|
||||
} else {
|
||||
if (end > 0) {
|
||||
log_error("seq-end needs seq-start parameter, ignoring");
|
||||
end = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* guarantee that the udev daemon isn't pre-processing */
|
||||
if (getuid() == 0) {
|
||||
struct udev_ctrl *uctrl;
|
||||
@ -160,76 +112,34 @@ static int adm_settle(struct udev *udev, int argc, char *argv[])
|
||||
pfd[0].fd = inotify_init1(IN_CLOEXEC);
|
||||
if (pfd[0].fd < 0) {
|
||||
log_error("inotify_init failed: %m");
|
||||
} else {
|
||||
if (inotify_add_watch(pfd[0].fd, "/run/udev" , IN_MOVED_TO) < 0) {
|
||||
log_error("watching /run/udev failed");
|
||||
close(pfd[0].fd);
|
||||
pfd[0].fd = -1;
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (inotify_add_watch(pfd[0].fd, "/run/udev/queue" , IN_DELETE) < 0) {
|
||||
log_debug("watching /run/udev failed");
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
struct stat statbuf;
|
||||
|
||||
if (exists != NULL && stat(exists, &statbuf) == 0) {
|
||||
if (exists && access(exists, F_OK) >= 0) {
|
||||
rc = EXIT_SUCCESS;
|
||||
break;
|
||||
}
|
||||
|
||||
if (start > 0) {
|
||||
/* if asked for, wait for a specific sequence of events */
|
||||
if (udev_queue_get_seqnum_sequence_is_finished(udev_queue, start, end) == 1) {
|
||||
rc = EXIT_SUCCESS;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* exit if queue is empty */
|
||||
if (udev_queue_get_queue_is_empty(udev_queue)) {
|
||||
rc = EXIT_SUCCESS;
|
||||
break;
|
||||
}
|
||||
/* exit if queue is empty */
|
||||
if (access("/run/udev/queue", F_OK) < 0) {
|
||||
rc = EXIT_SUCCESS;
|
||||
break;
|
||||
}
|
||||
|
||||
if (pfd[0].fd >= 0) {
|
||||
int delay;
|
||||
/* wake up when "queue" file is deleted */
|
||||
if (poll(pfd, 1, 100) > 0 && pfd[0].revents & POLLIN) {
|
||||
char buf[sizeof(struct inotify_event) + PATH_MAX];
|
||||
|
||||
if (exists != NULL || start > 0)
|
||||
delay = 100;
|
||||
else
|
||||
delay = 1000;
|
||||
/* wake up after delay, or immediately after the queue is rebuilt */
|
||||
if (poll(pfd, 1, delay) > 0 && pfd[0].revents & POLLIN) {
|
||||
char buf[sizeof(struct inotify_event) + PATH_MAX];
|
||||
|
||||
if(read(pfd[0].fd, buf, sizeof(buf)) < 0){
|
||||
log_error("failed to read /run/udev");
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
if (timeout > 0) {
|
||||
usec_t age_usec;
|
||||
|
||||
age_usec = now(CLOCK_MONOTONIC) - start_usec;
|
||||
if (age_usec / (1000 * 1000) >= timeout) {
|
||||
struct udev_list_entry *list_entry;
|
||||
|
||||
if (!quiet && udev_queue_get_queued_list_entry(udev_queue) != NULL) {
|
||||
log_debug("timeout waiting for udev queue");
|
||||
printf("\nudevadm settle - timeout of %i seconds reached, the event queue contains:\n", timeout);
|
||||
udev_list_entry_foreach(list_entry, udev_queue_get_queued_list_entry(udev_queue))
|
||||
printf(" %s (%s)\n",
|
||||
udev_list_entry_get_name(list_entry),
|
||||
udev_list_entry_get_value(list_entry));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
read(pfd[0].fd, buf, sizeof(buf));
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
if (pfd[0].fd >= 0)
|
||||
close(pfd[0].fd);
|
||||
@ -239,5 +149,5 @@ out:
|
||||
const struct udevadm_cmd udevadm_settle = {
|
||||
.name = "settle",
|
||||
.cmd = adm_settle,
|
||||
.help = "wait for the event queue to finish",
|
||||
.help = "wait for pending udev events",
|
||||
};
|
||||
|
@ -60,7 +60,6 @@ void udev_main_log(struct udev *udev, int priority,
|
||||
}
|
||||
|
||||
static struct udev_rules *rules;
|
||||
static struct udev_queue_export *udev_queue_export;
|
||||
static struct udev_ctrl *udev_ctrl;
|
||||
static struct udev_monitor *monitor;
|
||||
static int worker_watch[2] = { -1, -1 };
|
||||
@ -139,14 +138,9 @@ static inline struct worker *node_to_worker(struct udev_list_node *node)
|
||||
return container_of(node, struct worker, node);
|
||||
}
|
||||
|
||||
static void event_queue_delete(struct event *event, bool export)
|
||||
static void event_queue_delete(struct event *event)
|
||||
{
|
||||
udev_list_node_remove(&event->node);
|
||||
|
||||
if (export) {
|
||||
udev_queue_export_device_finished(udev_queue_export, event->dev);
|
||||
log_debug("seq %llu done with %i", udev_device_get_seqnum(event->dev), event->exitcode);
|
||||
}
|
||||
udev_device_unref(event->dev);
|
||||
free(event);
|
||||
}
|
||||
@ -225,7 +219,6 @@ static void worker_new(struct event *event)
|
||||
free(worker);
|
||||
worker_list_cleanup(udev);
|
||||
event_queue_cleanup(udev, EVENT_UNDEF);
|
||||
udev_queue_export_unref(udev_queue_export);
|
||||
udev_monitor_unref(monitor);
|
||||
udev_ctrl_unref(udev_ctrl);
|
||||
close(fd_signal);
|
||||
@ -449,7 +442,6 @@ static int event_queue_insert(struct udev_device *dev)
|
||||
event->nodelay = true;
|
||||
#endif
|
||||
|
||||
udev_queue_export_device_queued(udev_queue_export, dev);
|
||||
log_debug("seq %llu queued, '%s' '%s'", udev_device_get_seqnum(dev),
|
||||
udev_device_get_action(dev), udev_device_get_subsystem(dev));
|
||||
|
||||
@ -580,7 +572,7 @@ static void event_queue_cleanup(struct udev *udev, enum event_state match_type)
|
||||
if (match_type != EVENT_UNDEF && match_type != event->state)
|
||||
continue;
|
||||
|
||||
event_queue_delete(event, false);
|
||||
event_queue_delete(event);
|
||||
}
|
||||
}
|
||||
|
||||
@ -605,7 +597,7 @@ static void worker_returned(int fd_worker)
|
||||
/* worker returned */
|
||||
if (worker->event) {
|
||||
worker->event->exitcode = msg.exitcode;
|
||||
event_queue_delete(worker->event, true);
|
||||
event_queue_delete(worker->event);
|
||||
worker->event = NULL;
|
||||
}
|
||||
if (worker->state != WORKER_KILLED)
|
||||
@ -797,7 +789,8 @@ static void handle_signal(struct udev *udev, int signo)
|
||||
log_error("worker [%u] failed while handling '%s'",
|
||||
pid, worker->event->devpath);
|
||||
worker->event->exitcode = -32;
|
||||
event_queue_delete(worker->event, true);
|
||||
event_queue_delete(worker->event);
|
||||
|
||||
/* drop reference taken for state 'running' */
|
||||
worker_unref(worker);
|
||||
}
|
||||
@ -1093,14 +1086,7 @@ int main(int argc, char *argv[])
|
||||
goto exit;
|
||||
}
|
||||
|
||||
udev_monitor_set_receive_buffer_size(monitor, 128*1024*1024);
|
||||
|
||||
/* create queue file before signalling 'ready', to make sure we block 'settle' */
|
||||
udev_queue_export = udev_queue_export_new(udev);
|
||||
if (udev_queue_export == NULL) {
|
||||
log_error("error creating queue file");
|
||||
goto exit;
|
||||
}
|
||||
udev_monitor_set_receive_buffer_size(monitor, 128 * 1024 * 1024);
|
||||
|
||||
if (daemonize) {
|
||||
pid_t pid;
|
||||
@ -1268,12 +1254,12 @@ int main(int argc, char *argv[])
|
||||
worker_kill(udev);
|
||||
|
||||
/* exit after all has cleaned up */
|
||||
if (udev_list_node_is_empty(&event_list) && udev_list_node_is_empty(&worker_list))
|
||||
if (udev_list_node_is_empty(&event_list) && children == 0)
|
||||
break;
|
||||
|
||||
/* timeout at exit for workers to finish */
|
||||
timeout = 30 * 1000;
|
||||
} else if (udev_list_node_is_empty(&event_list) && !children) {
|
||||
timeout = 30 * MSEC_PER_SEC;
|
||||
} else if (udev_list_node_is_empty(&event_list) && children == 0) {
|
||||
/* we are idle */
|
||||
timeout = -1;
|
||||
|
||||
@ -1282,8 +1268,20 @@ int main(int argc, char *argv[])
|
||||
cg_kill(SYSTEMD_CGROUP_CONTROLLER, udev_cgroup, SIGKILL, false, true, NULL);
|
||||
} else {
|
||||
/* kill idle or hanging workers */
|
||||
timeout = 3 * 1000;
|
||||
timeout = 3 * MSEC_PER_SEC;
|
||||
}
|
||||
|
||||
/* tell settle that we are busy or idle */
|
||||
if (!udev_list_node_is_empty(&event_list)) {
|
||||
int fd;
|
||||
|
||||
fd = open("/run/udev/queue", O_WRONLY|O_CREAT|O_CLOEXEC|O_TRUNC|O_NOFOLLOW, 0444);
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
} else {
|
||||
unlink("/run/udev/queue");
|
||||
}
|
||||
|
||||
fdcount = epoll_wait(fd_ep, ev, ELEMENTSOF(ev), timeout);
|
||||
if (fdcount < 0)
|
||||
continue;
|
||||
@ -1310,18 +1308,18 @@ int main(int argc, char *argv[])
|
||||
if (worker->state != WORKER_RUNNING)
|
||||
continue;
|
||||
|
||||
if ((now(CLOCK_MONOTONIC) - worker->event_start_usec) > 30 * 1000 * 1000) {
|
||||
if ((now(CLOCK_MONOTONIC) - worker->event_start_usec) > 30 * USEC_PER_SEC) {
|
||||
log_error("worker [%u] %s timeout; kill it", worker->pid,
|
||||
worker->event ? worker->event->devpath : "<idle>");
|
||||
kill(worker->pid, SIGKILL);
|
||||
worker->state = WORKER_KILLED;
|
||||
|
||||
/* drop reference taken for state 'running' */
|
||||
worker_unref(worker);
|
||||
if (worker && worker->event) {
|
||||
log_error("seq %llu '%s' killed",
|
||||
udev_device_get_seqnum(worker->event->dev), worker->event->devpath);
|
||||
log_error("seq %llu '%s' killed", udev_device_get_seqnum(worker->event->dev), worker->event->devpath);
|
||||
worker->event->exitcode = -64;
|
||||
event_queue_delete(worker->event, true);
|
||||
event_queue_delete(worker->event);
|
||||
worker->event = NULL;
|
||||
}
|
||||
}
|
||||
@ -1344,7 +1342,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
/* check for changed config, every 3 seconds at most */
|
||||
if ((now(CLOCK_MONOTONIC) - last_usec) > 3 * 1000 * 1000) {
|
||||
if ((now(CLOCK_MONOTONIC) - last_usec) > 3 * USEC_PER_SEC) {
|
||||
if (udev_rules_check_timestamp(rules))
|
||||
reload = true;
|
||||
if (udev_builtin_validate(udev))
|
||||
@ -1417,8 +1415,8 @@ int main(int argc, char *argv[])
|
||||
|
||||
rc = EXIT_SUCCESS;
|
||||
exit:
|
||||
udev_queue_export_cleanup(udev_queue_export);
|
||||
udev_ctrl_cleanup(udev_ctrl);
|
||||
unlink("/run/udev/queue");
|
||||
exit_daemonize:
|
||||
if (fd_ep >= 0)
|
||||
close(fd_ep);
|
||||
@ -1433,7 +1431,6 @@ exit_daemonize:
|
||||
if (worker_watch[WRITE_END] >= 0)
|
||||
close(worker_watch[WRITE_END]);
|
||||
udev_monitor_unref(monitor);
|
||||
udev_queue_export_unref(udev_queue_export);
|
||||
udev_ctrl_connection_unref(ctrl_conn);
|
||||
udev_ctrl_unref(udev_ctrl);
|
||||
label_finish();
|
||||
|
@ -303,38 +303,14 @@ out:
|
||||
|
||||
static int test_queue(struct udev *udev) {
|
||||
struct udev_queue *udev_queue;
|
||||
unsigned long long int seqnum;
|
||||
struct udev_list_entry *list_entry;
|
||||
|
||||
udev_queue = udev_queue_new(udev);
|
||||
if (udev_queue == NULL)
|
||||
return -1;
|
||||
seqnum = udev_queue_get_kernel_seqnum(udev_queue);
|
||||
printf("seqnum kernel: %llu\n", seqnum);
|
||||
seqnum = udev_queue_get_udev_seqnum(udev_queue);
|
||||
printf("seqnum udev : %llu\n", seqnum);
|
||||
|
||||
if (udev_queue_get_queue_is_empty(udev_queue))
|
||||
printf("queue is empty\n");
|
||||
printf("get queue list\n");
|
||||
udev_list_entry_foreach(list_entry, udev_queue_get_queued_list_entry(udev_queue))
|
||||
printf("queued: '%s' [%s]\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry));
|
||||
printf("\n");
|
||||
printf("get queue list again\n");
|
||||
udev_list_entry_foreach(list_entry, udev_queue_get_queued_list_entry(udev_queue))
|
||||
printf("queued: '%s' [%s]\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry));
|
||||
printf("\n");
|
||||
|
||||
list_entry = udev_queue_get_queued_list_entry(udev_queue);
|
||||
if (list_entry != NULL) {
|
||||
printf("event [%llu] is queued\n", seqnum);
|
||||
seqnum = strtoull(udev_list_entry_get_value(list_entry), NULL, 10);
|
||||
if (udev_queue_get_seqnum_is_finished(udev_queue, seqnum))
|
||||
printf("event [%llu] is not finished\n", seqnum);
|
||||
else
|
||||
printf("event [%llu] is finished\n", seqnum);
|
||||
}
|
||||
printf("\n");
|
||||
udev_queue_unref(udev_queue);
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user