2 This file is part of systemd.
4 Copyright 2008-2012 Kay Sievers <kay@vrfy.org>
5 Copyright 2009 Alan Jenkins <alan-jenkins@tuffmail.co.uk>
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
33 #include "libudev-private.h"
36 * SECTION:libudev-queue
37 * @short_description: access to currently active events
39 * The udev daemon processes events asynchronously. All events which do not have
40 * interdependencies run in parallel. This exports the current state of the
41 * event processing queue, and the current event sequence numbers from the kernel
42 * and the udev daemon.
48 * Opaque object representing the current event queue in the udev daemon.
53 struct udev_list queue_list;
58 * @udev: udev library context
60 * The initial refcount is 1, and needs to be decremented to
61 * release the resources of the udev queue context.
63 * Returns: the udev queue context, or #NULL on error.
65 _public_ struct udev_queue *udev_queue_new(struct udev *udev)
67 struct udev_queue *udev_queue;
72 udev_queue = calloc(1, sizeof(struct udev_queue));
73 if (udev_queue == NULL)
75 udev_queue->refcount = 1;
76 udev_queue->udev = udev;
77 udev_list_init(udev, &udev_queue->queue_list, false);
83 * @udev_queue: udev queue context
85 * Take a reference of a udev queue context.
87 * Returns: the same udev queue context.
89 _public_ struct udev_queue *udev_queue_ref(struct udev_queue *udev_queue)
91 if (udev_queue == NULL)
93 udev_queue->refcount++;
99 * @udev_queue: udev queue context
101 * Drop a reference of a udev queue context. If the refcount reaches zero,
102 * the resources of the queue context will be released.
104 * Returns: the passed queue context if it has still an active reference, or #NULL otherwise.
106 _public_ struct udev_queue *udev_queue_unref(struct udev_queue *udev_queue)
108 if (udev_queue == NULL)
110 udev_queue->refcount--;
111 if (udev_queue->refcount > 0)
113 udev_list_cleanup(&udev_queue->queue_list);
119 * udev_queue_get_udev:
120 * @udev_queue: udev queue context
122 * Retrieve the udev library context the queue context was created with.
124 * Returns: the udev library context.
126 _public_ struct udev *udev_queue_get_udev(struct udev_queue *udev_queue)
128 if (udev_queue == NULL)
130 return udev_queue->udev;
133 unsigned long long int udev_get_kernel_seqnum(struct udev *udev)
135 unsigned long long int seqnum;
140 fd = open("/sys/kernel/uevent_seqnum", O_RDONLY|O_CLOEXEC);
143 len = read(fd, buf, sizeof(buf));
148 seqnum = strtoull(buf, NULL, 10);
153 * udev_queue_get_kernel_seqnum:
154 * @udev_queue: udev queue context
156 * Get the current kernel event sequence number.
158 * Returns: the sequence number.
160 _public_ unsigned long long int udev_queue_get_kernel_seqnum(struct udev_queue *udev_queue)
162 unsigned long long int seqnum;
164 if (udev_queue == NULL)
167 seqnum = udev_get_kernel_seqnum(udev_queue->udev);
171 int udev_queue_read_seqnum(FILE *queue_file, unsigned long long int *seqnum)
173 if (fread(seqnum, sizeof(unsigned long long int), 1, queue_file) != 1)
179 ssize_t udev_queue_skip_devpath(FILE *queue_file)
181 unsigned short int len;
183 if (fread(&len, sizeof(unsigned short int), 1, queue_file) == 1) {
184 char *devpath = alloca(len);
186 /* use fread to skip, fseek might drop buffered data */
187 if (fread(devpath, 1, len, queue_file) == len)
194 ssize_t udev_queue_read_devpath(FILE *queue_file, char *devpath, size_t size)
196 unsigned short int read_bytes = 0;
197 unsigned short int len;
199 if (fread(&len, sizeof(unsigned short int), 1, queue_file) != 1)
202 read_bytes = (len < size - 1) ? len : size - 1;
203 if (fread(devpath, 1, read_bytes, queue_file) != read_bytes)
205 devpath[read_bytes] = '\0';
207 /* if devpath was too long, skip unread characters */
208 if (read_bytes != len) {
209 unsigned short int skip_bytes = len - read_bytes;
210 char *buf = alloca(skip_bytes);
212 if (fread(buf, 1, skip_bytes, queue_file) != skip_bytes)
219 static FILE *open_queue_file(struct udev_queue *udev_queue, unsigned long long int *seqnum_start)
223 queue_file = fopen("/run/udev/queue.bin", "re");
224 if (queue_file == NULL)
227 if (udev_queue_read_seqnum(queue_file, seqnum_start) < 0) {
228 udev_err(udev_queue->udev, "corrupt queue file\n");
237 * udev_queue_get_udev_seqnum:
238 * @udev_queue: udev queue context
240 * Get the last known udev event sequence number.
242 * Returns: the sequence number.
244 _public_ unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *udev_queue)
246 unsigned long long int seqnum_udev;
249 queue_file = open_queue_file(udev_queue, &seqnum_udev);
250 if (queue_file == NULL)
254 unsigned long long int seqnum;
257 if (udev_queue_read_seqnum(queue_file, &seqnum) < 0)
259 devpath_len = udev_queue_skip_devpath(queue_file);
263 seqnum_udev = seqnum;
271 * udev_queue_get_udev_is_active:
272 * @udev_queue: udev queue context
274 * Check if udev is active on the system.
276 * Returns: a flag indicating if udev is active.
278 _public_ int udev_queue_get_udev_is_active(struct udev_queue *udev_queue)
280 unsigned long long int seqnum_start;
283 queue_file = open_queue_file(udev_queue, &seqnum_start);
284 if (queue_file == NULL)
292 * udev_queue_get_queue_is_empty:
293 * @udev_queue: udev queue context
295 * Check if udev is currently processing any events.
297 * Returns: a flag indicating if udev is currently handling events.
299 _public_ int udev_queue_get_queue_is_empty(struct udev_queue *udev_queue)
301 unsigned long long int seqnum_kernel;
302 unsigned long long int seqnum_udev = 0;
307 if (udev_queue == NULL)
309 queue_file = open_queue_file(udev_queue, &seqnum_udev);
310 if (queue_file == NULL)
314 unsigned long long int seqnum;
317 if (udev_queue_read_seqnum(queue_file, &seqnum) < 0)
319 devpath_len = udev_queue_skip_devpath(queue_file);
323 if (devpath_len > 0) {
325 seqnum_udev = seqnum;
334 seqnum_kernel = udev_queue_get_kernel_seqnum(udev_queue);
335 if (seqnum_udev < seqnum_kernel)
346 * udev_queue_get_seqnum_sequence_is_finished:
347 * @udev_queue: udev queue context
348 * @start: first event sequence number
349 * @end: last event sequence number
351 * Check if udev is currently processing any events in a given sequence number range.
353 * Returns: a flag indicating if any of the sequence numbers in the given range is currently active.
355 _public_ int udev_queue_get_seqnum_sequence_is_finished(struct udev_queue *udev_queue,
356 unsigned long long int start, unsigned long long int end)
358 unsigned long long int seqnum;
363 if (udev_queue == NULL)
365 queue_file = open_queue_file(udev_queue, &seqnum);
366 if (queue_file == NULL)
374 if (end - start > INT_MAX - 1) {
380 * we might start with 0, and handle the initial seqnum
381 * only when we find an entry in the queue file
383 unfinished = end - start;
386 if (udev_queue_read_seqnum(queue_file, &seqnum) < 0)
388 devpath_len = udev_queue_skip_devpath(queue_file);
393 * we might start with an empty or re-build queue file, where
394 * the initial seqnum is not recorded as finished
396 if (start == seqnum && devpath_len > 0)
399 if (devpath_len == 0) {
400 if (seqnum >= start && seqnum <= end)
403 } while (unfinished > 0);
407 return (unfinished == 0);
411 * udev_queue_get_seqnum_is_finished:
412 * @udev_queue: udev queue context
413 * @seqnum: sequence number
415 * Check if udev is currently processing a given sequence number.
417 * Returns: a flag indicating if the given sequence number is currently active.
419 _public_ int udev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, unsigned long long int seqnum)
421 if (!udev_queue_get_seqnum_sequence_is_finished(udev_queue, seqnum, seqnum))
428 * udev_queue_get_queued_list_entry:
429 * @udev_queue: udev queue context
431 * Get the first entry of the list of queued events.
433 * Returns: a udev_list_entry.
435 _public_ struct udev_list_entry *udev_queue_get_queued_list_entry(struct udev_queue *udev_queue)
437 unsigned long long int seqnum;
440 if (udev_queue == NULL)
442 udev_list_cleanup(&udev_queue->queue_list);
444 queue_file = open_queue_file(udev_queue, &seqnum);
445 if (queue_file == NULL)
449 char syspath[UTIL_PATH_SIZE];
454 struct udev_list_entry *list_entry;
456 if (udev_queue_read_seqnum(queue_file, &seqnum) < 0)
458 snprintf(seqnum_str, sizeof(seqnum_str), "%llu", seqnum);
461 l = strpcpy(&s, sizeof(syspath), "/sys");
462 len = udev_queue_read_devpath(queue_file, s, l);
467 udev_list_entry_add(&udev_queue->queue_list, syspath, seqnum_str);
469 udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_queue->queue_list)) {
470 if (streq(seqnum_str, udev_list_entry_get_value(list_entry))) {
471 udev_list_entry_delete(list_entry);
479 return udev_list_get_entry(&udev_queue->queue_list);