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_node queue_list;
46 struct udev_list_node failed_list;
51 * @udev: udev library context
53 * The initial refcount is 1, and needs to be decremented to
54 * release the resources of the udev queue context.
56 * Returns: the udev queue context, or #NULL on error.
58 struct udev_queue *udev_queue_new(struct udev *udev)
60 struct udev_queue *udev_queue;
65 udev_queue = calloc(1, sizeof(struct udev_queue));
66 if (udev_queue == NULL)
68 udev_queue->refcount = 1;
69 udev_queue->udev = udev;
70 udev_list_init(&udev_queue->queue_list);
71 udev_list_init(&udev_queue->failed_list);
77 * @udev_queue: udev queue context
79 * Take a reference of a udev queue context.
81 * Returns: the same udev queue context.
83 struct udev_queue *udev_queue_ref(struct udev_queue *udev_queue)
85 if (udev_queue == NULL)
87 udev_queue->refcount++;
93 * @udev_queue: udev queue context
95 * Drop a reference of a udev queue context. If the refcount reaches zero,
96 * the resources of the queue context will be released.
98 void udev_queue_unref(struct udev_queue *udev_queue)
100 if (udev_queue == NULL)
102 udev_queue->refcount--;
103 if (udev_queue->refcount > 0)
105 udev_list_cleanup_entries(udev_queue->udev, &udev_queue->queue_list);
106 udev_list_cleanup_entries(udev_queue->udev, &udev_queue->failed_list);
111 * udev_queue_get_udev:
112 * @udev_queue: udev queue context
114 * Retrieve the udev library context the queue context was created with.
116 * Returns: the udev library context.
118 struct udev *udev_queue_get_udev(struct udev_queue *udev_queue)
120 if (udev_queue == NULL)
122 return udev_queue->udev;
125 unsigned long long int udev_get_kernel_seqnum(struct udev *udev)
127 char filename[UTIL_PATH_SIZE];
128 unsigned long long int seqnum;
133 util_strscpyl(filename, sizeof(filename), udev_get_sys_path(udev), "/kernel/uevent_seqnum", NULL);
134 fd = open(filename, O_RDONLY|O_CLOEXEC);
137 len = read(fd, buf, sizeof(buf));
142 seqnum = strtoull(buf, NULL, 10);
147 * udev_queue_get_kernel_seqnum:
148 * @udev_queue: udev queue context
150 * Returns: the current kernel event sequence number.
152 unsigned long long int udev_queue_get_kernel_seqnum(struct udev_queue *udev_queue)
154 unsigned long long int seqnum;
156 if (udev_queue == NULL)
159 seqnum = udev_get_kernel_seqnum(udev_queue->udev);
160 dbg(udev_queue->udev, "seqnum=%llu\n", seqnum);
164 int udev_queue_read_seqnum(FILE *queue_file, unsigned long long int *seqnum)
166 if (fread(seqnum, sizeof(unsigned long long int), 1, queue_file) != 1)
172 ssize_t udev_queue_skip_devpath(FILE *queue_file)
174 unsigned short int len;
176 if (fread(&len, sizeof(unsigned short int), 1, queue_file) == 1) {
179 /* use fread to skip, fseek might drop buffered data */
180 if (fread(devpath, 1, len, queue_file) == len)
187 ssize_t udev_queue_read_devpath(FILE *queue_file, char *devpath, size_t size)
189 unsigned short int read_bytes = 0;
190 unsigned short int len;
192 if (fread(&len, sizeof(unsigned short int), 1, queue_file) != 1)
195 read_bytes = (len < size - 1) ? len : size - 1;
196 if (fread(devpath, 1, read_bytes, queue_file) != read_bytes)
198 devpath[read_bytes] = '\0';
200 /* if devpath was too long, skip unread characters */
201 if (read_bytes != len) {
202 unsigned short int skip_bytes = len - read_bytes;
203 char buf[skip_bytes];
205 if (fread(buf, 1, skip_bytes, queue_file) != skip_bytes)
212 static FILE *open_queue_file(struct udev_queue *udev_queue, unsigned long long int *seqnum_start)
214 char filename[UTIL_PATH_SIZE];
217 util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev_queue->udev), "/.udev/queue.bin", NULL);
218 queue_file = fopen(filename, "re");
219 if (queue_file == NULL)
222 if (udev_queue_read_seqnum(queue_file, seqnum_start) < 0) {
223 err(udev_queue->udev, "corrupt queue file\n");
232 * udev_queue_get_udev_seqnum:
233 * @udev_queue: udev queue context
235 * Returns: the last known udev event sequence number.
237 unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *udev_queue)
239 unsigned long long int seqnum_udev;
242 queue_file = open_queue_file(udev_queue, &seqnum_udev);
243 if (queue_file == NULL)
247 unsigned long long int seqnum;
250 if (udev_queue_read_seqnum(queue_file, &seqnum) < 0)
252 devpath_len = udev_queue_skip_devpath(queue_file);
256 seqnum_udev = seqnum;
264 * udev_queue_get_udev_is_active:
265 * @udev_queue: udev queue context
267 * Returns: a flag indicating if udev is active.
269 int udev_queue_get_udev_is_active(struct udev_queue *udev_queue)
271 unsigned long long int seqnum_start;
274 queue_file = open_queue_file(udev_queue, &seqnum_start);
275 if (queue_file == NULL)
283 * udev_queue_get_queue_is_empty:
284 * @udev_queue: udev queue context
286 * Returns: a flag indicating if udev is currently handling events.
288 int udev_queue_get_queue_is_empty(struct udev_queue *udev_queue)
290 unsigned long long int seqnum_kernel;
291 unsigned long long int seqnum_udev = 0;
296 if (udev_queue == NULL)
298 queue_file = open_queue_file(udev_queue, &seqnum_udev);
299 if (queue_file == NULL)
303 unsigned long long int seqnum;
306 if (udev_queue_read_seqnum(queue_file, &seqnum) < 0)
308 devpath_len = udev_queue_skip_devpath(queue_file);
312 if (devpath_len > 0) {
314 seqnum_udev = seqnum;
321 dbg(udev_queue->udev, "queue is not empty\n");
325 seqnum_kernel = udev_queue_get_kernel_seqnum(udev_queue);
326 if (seqnum_udev < seqnum_kernel) {
327 dbg(udev_queue->udev, "queue is empty but kernel events still pending [%llu]<->[%llu]\n",
328 seqnum_kernel, seqnum_udev);
332 dbg(udev_queue->udev, "queue is empty\n");
341 * udev_queue_get_seqnum_sequence_is_finished:
342 * @udev_queue: udev queue context
343 * @start: first event sequence number
344 * @end: last event sequence number
346 * Returns: if any of the sequence numbers in the given range is currently active.
348 int udev_queue_get_seqnum_sequence_is_finished(struct udev_queue *udev_queue,
349 unsigned long long int start, unsigned long long int end)
351 unsigned long long int seqnum;
356 if (udev_queue == NULL)
358 queue_file = open_queue_file(udev_queue, &seqnum);
359 if (queue_file == NULL)
367 if (end - start > INT_MAX - 1) {
373 * we might start with 0, and handle the initial seqnum
374 * only when we find an entry in the queue file
376 unfinished = end - start;
379 if (udev_queue_read_seqnum(queue_file, &seqnum) < 0)
381 devpath_len = udev_queue_skip_devpath(queue_file);
386 * we might start with an empty or re-build queue file, where
387 * the initial seqnum is not recorded as finished
389 if (start == seqnum && devpath_len > 0)
392 if (devpath_len == 0) {
393 if (seqnum >= start && seqnum <= end)
396 } while (unfinished > 0);
400 return (unfinished == 0);
404 * udev_queue_get_seqnum_is_finished:
405 * @udev_queue: udev queue context
406 * @seqnum: sequence number
408 * Returns: a flag indicating if the given sequence number is handled.
410 int udev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, unsigned long long int seqnum)
412 if (!udev_queue_get_seqnum_sequence_is_finished(udev_queue, seqnum, seqnum))
415 dbg(udev_queue->udev, "seqnum: %llu finished\n", seqnum);
420 * udev_queue_get_queued_list_entry:
421 * @udev_queue: udev queue context
423 * Returns: the first entry of the list of queued events.
425 struct udev_list_entry *udev_queue_get_queued_list_entry(struct udev_queue *udev_queue)
427 unsigned long long int seqnum;
430 if (udev_queue == NULL)
432 udev_list_cleanup_entries(udev_queue->udev, &udev_queue->queue_list);
434 queue_file = open_queue_file(udev_queue, &seqnum);
435 if (queue_file == NULL)
439 char syspath[UTIL_PATH_SIZE];
444 struct udev_list_entry *list_entry;
446 if (udev_queue_read_seqnum(queue_file, &seqnum) < 0)
448 snprintf(seqnum_str, sizeof(seqnum_str), "%llu", seqnum);
451 l = util_strpcpyl(&s, sizeof(syspath), udev_get_sys_path(udev_queue->udev), NULL);
452 len = udev_queue_read_devpath(queue_file, s, l);
457 udev_list_entry_add(udev_queue->udev, &udev_queue->queue_list, syspath, seqnum_str, 0, 0);
459 udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_queue->queue_list)) {
460 if (strcmp(seqnum_str, udev_list_entry_get_value(list_entry)) == 0) {
461 udev_list_entry_delete(list_entry);
469 return udev_list_get_entry(&udev_queue->queue_list);
473 * udev_queue_get_failed_list_entry:
474 * @udev_queue: udev queue context
476 * Returns: the first entry of the list of recorded failed events.
478 struct udev_list_entry *udev_queue_get_failed_list_entry(struct udev_queue *udev_queue)
480 char path[UTIL_PATH_SIZE];
484 if (udev_queue == NULL)
486 udev_list_cleanup_entries(udev_queue->udev, &udev_queue->failed_list);
487 util_strscpyl(path, sizeof(path), udev_get_dev_path(udev_queue->udev), "/.udev/failed", NULL);
491 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
492 char filename[UTIL_PATH_SIZE];
493 char syspath[UTIL_PATH_SIZE];
499 if (dent->d_name[0] == '.')
502 l = util_strpcpyl(&s, sizeof(syspath), udev_get_sys_path(udev_queue->udev), NULL);
503 len = readlinkat(dirfd(dir), dent->d_name, s, l);
504 if (len <= 0 || (size_t)len == l)
507 dbg(udev_queue->udev, "found '%s' [%s]\n", syspath, dent->d_name);
508 util_strscpyl(filename, sizeof(filename), syspath, "/uevent", NULL);
509 if (stat(filename, &statbuf) != 0)
511 udev_list_entry_add(udev_queue->udev, &udev_queue->failed_list, syspath, NULL, 0, 0);
514 return udev_list_get_entry(&udev_queue->failed_list);