diff options
author | Kay Sievers <kay@vrfy.org> | 2014-04-24 15:40:08 -0400 |
---|---|---|
committer | Anthony G. Basile <blueness@gentoo.org> | 2014-04-24 15:40:08 -0400 |
commit | 2500dbc810d8898c1359c6579715586fffa08a27 (patch) | |
tree | e24445a5829c7c4f4da6bf7652ece1acaf008b6c | |
parent | dbc5e32faeca842ec5a4a07702080b3195e21d66 (diff) |
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>
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | man/udevadm.xml | 227 | ||||
-rw-r--r-- | src/libudev/Makefile.am | 3 | ||||
-rw-r--r-- | src/libudev/libudev-monitor.c | 17 | ||||
-rw-r--r-- | src/libudev/libudev-queue-private.c | 406 | ||||
-rw-r--r-- | src/libudev/libudev-queue.c | 302 | ||||
-rw-r--r-- | src/libudev/libudev.h | 10 | ||||
-rw-r--r-- | src/udev/udev-ctrl.c | 2 | ||||
-rw-r--r-- | src/udev/udev-util.h | 2 | ||||
-rw-r--r-- | src/udev/udevadm-settle.c | 134 | ||||
-rw-r--r-- | src/udev/udevd.c | 59 | ||||
-rw-r--r-- | test/test-libudev.c | 24 |
12 files changed, 235 insertions, 953 deletions
diff --git a/configure.ac b/configure.ac index ee70d4c868..61fabe8d10 100644 --- a/configure.ac +++ b/configure.ac @@ -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]) diff --git a/man/udevadm.xml b/man/udevadm.xml index 51370cc4e7..1b349c6b4e 100644 --- a/man/udevadm.xml +++ b/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> diff --git a/src/libudev/Makefile.am b/src/libudev/Makefile.am index 3a0de58865..c9c4d42fb8 100644 --- a/src/libudev/Makefile.am +++ b/src/libudev/Makefile.am @@ -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 diff --git a/src/libudev/libudev-monitor.c b/src/libudev/libudev-monitor.c index ff522b8607..43fd8762da 100644 --- a/src/libudev/libudev-monitor.c +++ b/src/libudev/libudev-monitor.c @@ -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 diff --git a/src/libudev/libudev-queue-private.c b/src/libudev/libudev-queue-private.c deleted file mode 100644 index d5a2b503dd..0000000000 --- a/src/libudev/libudev-queue-private.c +++ /dev/null @@ -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); -} diff --git a/src/libudev/libudev-queue.c b/src/libudev/libudev-queue.c index 2cb4d67121..eb0e096f84 100644 --- a/src/libudev/libudev-queue.c +++ b/src/libudev/libudev-queue.c @@ -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; } diff --git a/src/libudev/libudev.h b/src/libudev/libudev.h index b9b8f13e44..ceb89bd593 100644 --- a/src/libudev/libudev.h +++ b/src/libudev/libudev.h @@ -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 diff --git a/src/udev/udev-ctrl.c b/src/udev/udev-ctrl.c index 522195ced7..8d07c993b7 100644 --- a/src/udev/udev-ctrl.c +++ b/src/udev/udev-ctrl.c @@ -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; diff --git a/src/udev/udev-util.h b/src/udev/udev-util.h index 40f8b776ce..5f09ce181f 100644 --- a/src/udev/udev-util.h +++ b/src/udev/udev-util.h @@ -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) diff --git a/src/udev/udevadm-settle.c b/src/udev/udevadm-settle.c index 9ae6c6bf8e..73f74e1ac8 100644 --- a/src/udev/udevadm-settle.c +++ b/src/udev/udevadm-settle.c @@ -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; } - for (;;) { - struct stat statbuf; + if (inotify_add_watch(pfd[0].fd, "/run/udev/queue" , IN_DELETE) < 0) { + log_debug("watching /run/udev failed"); + goto out; + } - if (exists != NULL && stat(exists, &statbuf) == 0) { + for (;;) { + 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; - } - } - - if (pfd[0].fd >= 0) { - int delay; - - 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); + /* exit if queue is empty */ + if (access("/run/udev/queue", F_OK) < 0) { + rc = EXIT_SUCCESS; + break; } - 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; + /* 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 (!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", }; diff --git a/src/udev/udevd.c b/src/udev/udevd.c index 03de852c02..586e302d8e 100644 --- a/src/udev/udevd.c +++ b/src/udev/udevd.c @@ -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(); diff --git a/test/test-libudev.c b/test/test-libudev.c index 71b981ca74..92c5ceba15 100644 --- a/test/test-libudev.c +++ b/test/test-libudev.c @@ -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; } |