libudev_internal_la_SOURCES =\
$(libudev_la_SOURCES) \
- src/libudev/libudev-device-private.c \
- src/libudev/libudev-queue-private.c
+ src/libudev/libudev-device-private.c
libudev_internal_la_CFLAGS = \
$(AM_CFLAGS) \
test_libudev_sym_SOURCES = \
test-libudev-sym.c
+test_libudev_sym_CFLAGS = \
+ $(AM_CFLAGS) \
+ -Wno-deprecated-declarations
test_libudev_sym_LDADD = \
libudev.la
</listitem>
</varlistentry>
<varlistentry>
- <term><option>-s</option></term>
- <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>-e</option></term>
- <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>-E</option></term>
<term><option>--exit-if-exists=<replaceable>FILE</replaceable></option></term>
<listitem>
</listitem>
</varlistentry>
<varlistentry>
- <term><option>-q</option></term>
- <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>
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;
* 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
+++ /dev/null
-/***
- 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);
-}
#include <unistd.h>
#include <errno.h>
#include <string.h>
-#include <dirent.h>
-#include <fcntl.h>
#include <limits.h>
#include <sys/stat.h>
* 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.
*/
/**
struct udev_queue {
struct udev *udev;
int refcount;
- struct udev_list queue_list;
};
/**
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;
}
{
if (udev_queue == NULL)
return NULL;
+
udev_queue->refcount++;
return 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;
}
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;
}
/**
**/
_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;
}
/**
**/
_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;
}
/**
* @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);
}
/**
* @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;
}
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
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)
#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)
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;
}
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;
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;
case 'E':
exists = optarg;
break;
- case 'q':
- quiet = 1;
- break;
case 'h':
help();
exit(EXIT_SUCCESS);
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;
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];
-
- read(pfd[0].fd, buf, sizeof(buf));
- }
- } 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;
+ /* 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];
- 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);
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",
};
}
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 };
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);
}
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);
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));
if (match_type != EVENT_UNDEF && match_type != event->state)
continue;
- event_queue_delete(event, false);
+ event_queue_delete(event);
}
}
/* 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)
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);
}
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;
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;
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;
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->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;
}
}
}
/* 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))
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);
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();