2 * libudev - interface to udev device information
4 * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org>
5 * Copyright (C) 2009 Alan Jenkins <alan-jenkins@tuffmail.co.uk>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
25 #include "libudev-private.h"
28 * SECTION:libudev-queue
29 * @short_description: access to currently active events
31 * The udev daemon processes events asynchronously. All events which do not have
32 * interdependencies run in parallel. This exports the current state of the
33 * event processing queue, and the current event sequence numbers from the kernel
34 * and the udev daemon.
40 * Opaque object representing the current event queue in the udev daemon.
45 struct udev_list queue_list;
50 * @udev: udev library context
52 * The initial refcount is 1, and needs to be decremented to
53 * release the resources of the udev queue context.
55 * Returns: the udev queue context, or #NULL on error.
57 UDEV_EXPORT struct udev_queue *udev_queue_new(struct udev *udev)
59 struct udev_queue *udev_queue;
64 udev_queue = calloc(1, sizeof(struct udev_queue));
65 if (udev_queue == NULL)
67 udev_queue->refcount = 1;
68 udev_queue->udev = udev;
69 udev_list_init(udev, &udev_queue->queue_list, false);
75 * @udev_queue: udev queue context
77 * Take a reference of a udev queue context.
79 * Returns: the same udev queue context.
81 UDEV_EXPORT struct udev_queue *udev_queue_ref(struct udev_queue *udev_queue)
83 if (udev_queue == NULL)
85 udev_queue->refcount++;
91 * @udev_queue: udev queue context
93 * Drop a reference of a udev queue context. If the refcount reaches zero,
94 * the resources of the queue context will be released.
96 UDEV_EXPORT void udev_queue_unref(struct udev_queue *udev_queue)
98 if (udev_queue == NULL)
100 udev_queue->refcount--;
101 if (udev_queue->refcount > 0)
103 udev_list_cleanup(&udev_queue->queue_list);
108 * udev_queue_get_udev:
109 * @udev_queue: udev queue context
111 * Retrieve the udev library context the queue context was created with.
113 * Returns: the udev library context.
115 UDEV_EXPORT struct udev *udev_queue_get_udev(struct udev_queue *udev_queue)
117 if (udev_queue == NULL)
119 return udev_queue->udev;
122 unsigned long long int udev_get_kernel_seqnum(struct udev *udev)
124 char filename[UTIL_PATH_SIZE];
125 unsigned long long int seqnum;
130 util_strscpyl(filename, sizeof(filename), udev_get_sys_path(udev), "/kernel/uevent_seqnum", NULL);
131 fd = open(filename, O_RDONLY|O_CLOEXEC);
134 len = read(fd, buf, sizeof(buf));
139 seqnum = strtoull(buf, NULL, 10);
144 * udev_queue_get_kernel_seqnum:
145 * @udev_queue: udev queue context
147 * Returns: the current kernel event sequence number.
149 UDEV_EXPORT unsigned long long int udev_queue_get_kernel_seqnum(struct udev_queue *udev_queue)
151 unsigned long long int seqnum;
153 if (udev_queue == NULL)
156 seqnum = udev_get_kernel_seqnum(udev_queue->udev);
157 dbg(udev_queue->udev, "seqnum=%llu\n", seqnum);
161 int udev_queue_read_seqnum(FILE *queue_file, unsigned long long int *seqnum)
163 if (fread(seqnum, sizeof(unsigned long long int), 1, queue_file) != 1)
169 ssize_t udev_queue_skip_devpath(FILE *queue_file)
171 unsigned short int len;
173 if (fread(&len, sizeof(unsigned short int), 1, queue_file) == 1) {
176 /* use fread to skip, fseek might drop buffered data */
177 if (fread(devpath, 1, len, queue_file) == len)
184 ssize_t udev_queue_read_devpath(FILE *queue_file, char *devpath, size_t size)
186 unsigned short int read_bytes = 0;
187 unsigned short int len;
189 if (fread(&len, sizeof(unsigned short int), 1, queue_file) != 1)
192 read_bytes = (len < size - 1) ? len : size - 1;
193 if (fread(devpath, 1, read_bytes, queue_file) != read_bytes)
195 devpath[read_bytes] = '\0';
197 /* if devpath was too long, skip unread characters */
198 if (read_bytes != len) {
199 unsigned short int skip_bytes = len - read_bytes;
200 char buf[skip_bytes];
202 if (fread(buf, 1, skip_bytes, queue_file) != skip_bytes)
209 static FILE *open_queue_file(struct udev_queue *udev_queue, unsigned long long int *seqnum_start)
211 char filename[UTIL_PATH_SIZE];
214 util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev_queue->udev), "/queue.bin", NULL);
215 queue_file = fopen(filename, "re");
216 if (queue_file == NULL)
219 if (udev_queue_read_seqnum(queue_file, seqnum_start) < 0) {
220 err(udev_queue->udev, "corrupt queue file\n");
229 * udev_queue_get_udev_seqnum:
230 * @udev_queue: udev queue context
232 * Returns: the last known udev event sequence number.
234 UDEV_EXPORT unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *udev_queue)
236 unsigned long long int seqnum_udev;
239 queue_file = open_queue_file(udev_queue, &seqnum_udev);
240 if (queue_file == NULL)
244 unsigned long long int seqnum;
247 if (udev_queue_read_seqnum(queue_file, &seqnum) < 0)
249 devpath_len = udev_queue_skip_devpath(queue_file);
253 seqnum_udev = seqnum;
261 * udev_queue_get_udev_is_active:
262 * @udev_queue: udev queue context
264 * Returns: a flag indicating if udev is active.
266 UDEV_EXPORT int udev_queue_get_udev_is_active(struct udev_queue *udev_queue)
268 unsigned long long int seqnum_start;
271 queue_file = open_queue_file(udev_queue, &seqnum_start);
272 if (queue_file == NULL)
280 * udev_queue_get_queue_is_empty:
281 * @udev_queue: udev queue context
283 * Returns: a flag indicating if udev is currently handling events.
285 UDEV_EXPORT int udev_queue_get_queue_is_empty(struct udev_queue *udev_queue)
287 unsigned long long int seqnum_kernel;
288 unsigned long long int seqnum_udev = 0;
293 if (udev_queue == NULL)
295 queue_file = open_queue_file(udev_queue, &seqnum_udev);
296 if (queue_file == NULL)
300 unsigned long long int seqnum;
303 if (udev_queue_read_seqnum(queue_file, &seqnum) < 0)
305 devpath_len = udev_queue_skip_devpath(queue_file);
309 if (devpath_len > 0) {
311 seqnum_udev = seqnum;
318 dbg(udev_queue->udev, "queue is not empty\n");
322 seqnum_kernel = udev_queue_get_kernel_seqnum(udev_queue);
323 if (seqnum_udev < seqnum_kernel) {
324 dbg(udev_queue->udev, "queue is empty but kernel events still pending [%llu]<->[%llu]\n",
325 seqnum_kernel, seqnum_udev);
329 dbg(udev_queue->udev, "queue is empty\n");
338 * udev_queue_get_seqnum_sequence_is_finished:
339 * @udev_queue: udev queue context
340 * @start: first event sequence number
341 * @end: last event sequence number
343 * Returns: a flag indicating if any of the sequence numbers in the given range is currently active.
345 UDEV_EXPORT int udev_queue_get_seqnum_sequence_is_finished(struct udev_queue *udev_queue,
346 unsigned long long int start, unsigned long long int end)
348 unsigned long long int seqnum;
353 if (udev_queue == NULL)
355 queue_file = open_queue_file(udev_queue, &seqnum);
356 if (queue_file == NULL)
364 if (end - start > INT_MAX - 1) {
370 * we might start with 0, and handle the initial seqnum
371 * only when we find an entry in the queue file
373 unfinished = end - start;
376 if (udev_queue_read_seqnum(queue_file, &seqnum) < 0)
378 devpath_len = udev_queue_skip_devpath(queue_file);
383 * we might start with an empty or re-build queue file, where
384 * the initial seqnum is not recorded as finished
386 if (start == seqnum && devpath_len > 0)
389 if (devpath_len == 0) {
390 if (seqnum >= start && seqnum <= end)
393 } while (unfinished > 0);
397 return (unfinished == 0);
401 * udev_queue_get_seqnum_is_finished:
402 * @udev_queue: udev queue context
403 * @seqnum: sequence number
405 * Returns: a flag indicating if the given sequence number is currently active.
407 UDEV_EXPORT int udev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, unsigned long long int seqnum)
409 if (!udev_queue_get_seqnum_sequence_is_finished(udev_queue, seqnum, seqnum))
412 dbg(udev_queue->udev, "seqnum: %llu finished\n", seqnum);
417 * udev_queue_get_queued_list_entry:
418 * @udev_queue: udev queue context
420 * Returns: the first entry of the list of queued events.
422 UDEV_EXPORT struct udev_list_entry *udev_queue_get_queued_list_entry(struct udev_queue *udev_queue)
424 unsigned long long int seqnum;
427 if (udev_queue == NULL)
429 udev_list_cleanup(&udev_queue->queue_list);
431 queue_file = open_queue_file(udev_queue, &seqnum);
432 if (queue_file == NULL)
436 char syspath[UTIL_PATH_SIZE];
441 struct udev_list_entry *list_entry;
443 if (udev_queue_read_seqnum(queue_file, &seqnum) < 0)
445 snprintf(seqnum_str, sizeof(seqnum_str), "%llu", seqnum);
448 l = util_strpcpyl(&s, sizeof(syspath), udev_get_sys_path(udev_queue->udev), NULL);
449 len = udev_queue_read_devpath(queue_file, s, l);
454 udev_list_entry_add(&udev_queue->queue_list, syspath, seqnum_str);
456 udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_queue->queue_list)) {
457 if (strcmp(seqnum_str, udev_list_entry_get_value(list_entry)) == 0) {
458 udev_list_entry_delete(list_entry);
466 return udev_list_get_entry(&udev_queue->queue_list);
469 struct udev_list_entry *udev_queue_get_failed_list_entry(struct udev_queue *udev_queue);
470 UDEV_EXPORT struct udev_list_entry *udev_queue_get_failed_list_entry(struct udev_queue *udev_queue)