]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libudev/libudev-queue.c
udev: update docs, NEWS
[thirdparty/systemd.git] / src / libudev / libudev-queue.c
CommitLineData
64ccdf82
KS
1/*
2 * libudev - interface to udev device information
3 *
4 * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org>
f503f6b2 5 * Copyright (C) 2009 Alan Jenkins <alan-jenkins@tuffmail.co.uk>
64ccdf82 6 *
4061ab9f
KS
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.
64ccdf82
KS
11 */
12
13#include <stdio.h>
14#include <stdlib.h>
15#include <stddef.h>
16#include <unistd.h>
17#include <errno.h>
18#include <string.h>
19#include <dirent.h>
20#include <fcntl.h>
f503f6b2 21#include <limits.h>
64ccdf82
KS
22#include <sys/stat.h>
23
24#include "libudev.h"
25#include "libudev-private.h"
26
ce1d6d7f
KS
27/**
28 * SECTION:libudev-queue
29 * @short_description: access to currently active events
30 *
a7d29d15
KS
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
ce1d6d7f
KS
34 * and the udev daemon.
35 */
36
37/**
38 * udev_queue:
39 *
40 * Opaque object representing the current event queue in the udev daemon.
41 */
64ccdf82 42struct udev_queue {
912541b0
KS
43 struct udev *udev;
44 int refcount;
45 struct udev_list queue_list;
64ccdf82
KS
46};
47
8d6bc73a
KS
48/**
49 * udev_queue_new:
50 * @udev: udev library context
51 *
52 * The initial refcount is 1, and needs to be decremented to
53 * release the resources of the udev queue context.
54 *
55 * Returns: the udev queue context, or #NULL on error.
56 **/
54cf0b7f 57_public_ struct udev_queue *udev_queue_new(struct udev *udev)
64ccdf82 58{
912541b0
KS
59 struct udev_queue *udev_queue;
60
61 if (udev == NULL)
62 return NULL;
63
64 udev_queue = calloc(1, sizeof(struct udev_queue));
65 if (udev_queue == NULL)
66 return NULL;
67 udev_queue->refcount = 1;
68 udev_queue->udev = udev;
69 udev_list_init(udev, &udev_queue->queue_list, false);
70 return udev_queue;
64ccdf82
KS
71}
72
8d6bc73a
KS
73/**
74 * udev_queue_ref:
75 * @udev_queue: udev queue context
76 *
77 * Take a reference of a udev queue context.
78 *
79 * Returns: the same udev queue context.
80 **/
54cf0b7f 81_public_ struct udev_queue *udev_queue_ref(struct udev_queue *udev_queue)
64ccdf82 82{
912541b0
KS
83 if (udev_queue == NULL)
84 return NULL;
85 udev_queue->refcount++;
86 return udev_queue;
64ccdf82
KS
87}
88
8d6bc73a
KS
89/**
90 * udev_queue_unref:
91 * @udev_queue: udev queue context
92 *
93 * Drop a reference of a udev queue context. If the refcount reaches zero,
94 * the resources of the queue context will be released.
c1959569
KS
95 *
96 * Returns: the passed queue context if it has still an active reference, or #NULL otherwise.
8d6bc73a 97 **/
20bbd54f 98_public_ struct udev_queue *udev_queue_unref(struct udev_queue *udev_queue)
64ccdf82 99{
912541b0 100 if (udev_queue == NULL)
20bbd54f 101 return NULL;
912541b0
KS
102 udev_queue->refcount--;
103 if (udev_queue->refcount > 0)
20bbd54f 104 return udev_queue;
912541b0
KS
105 udev_list_cleanup(&udev_queue->queue_list);
106 free(udev_queue);
20bbd54f 107 return NULL;
64ccdf82
KS
108}
109
8d6bc73a
KS
110/**
111 * udev_queue_get_udev:
112 * @udev_queue: udev queue context
113 *
114 * Retrieve the udev library context the queue context was created with.
115 *
116 * Returns: the udev library context.
117 **/
54cf0b7f 118_public_ struct udev *udev_queue_get_udev(struct udev_queue *udev_queue)
64ccdf82 119{
912541b0
KS
120 if (udev_queue == NULL)
121 return NULL;
122 return udev_queue->udev;
64ccdf82
KS
123}
124
f503f6b2 125unsigned long long int udev_get_kernel_seqnum(struct udev *udev)
64ccdf82 126{
912541b0
KS
127 unsigned long long int seqnum;
128 int fd;
129 char buf[32];
130 ssize_t len;
131
6ada823a 132 fd = open("/sys/kernel/uevent_seqnum", O_RDONLY|O_CLOEXEC);
912541b0
KS
133 if (fd < 0)
134 return 0;
135 len = read(fd, buf, sizeof(buf));
136 close(fd);
137 if (len <= 2)
138 return 0;
139 buf[len-1] = '\0';
140 seqnum = strtoull(buf, NULL, 10);
141 return seqnum;
64ccdf82
KS
142}
143
8d6bc73a
KS
144/**
145 * udev_queue_get_kernel_seqnum:
146 * @udev_queue: udev queue context
147 *
21dbe43a
KS
148 * Get the current kernel event sequence number.
149 *
150 * Returns: the sequence number.
8d6bc73a 151 **/
54cf0b7f 152_public_ unsigned long long int udev_queue_get_kernel_seqnum(struct udev_queue *udev_queue)
64ccdf82 153{
912541b0 154 unsigned long long int seqnum;
64ccdf82 155
912541b0
KS
156 if (udev_queue == NULL)
157 return -EINVAL;
f503f6b2 158
912541b0 159 seqnum = udev_get_kernel_seqnum(udev_queue->udev);
912541b0 160 return seqnum;
64ccdf82
KS
161}
162
f503f6b2
AJ
163int udev_queue_read_seqnum(FILE *queue_file, unsigned long long int *seqnum)
164{
912541b0
KS
165 if (fread(seqnum, sizeof(unsigned long long int), 1, queue_file) != 1)
166 return -1;
f503f6b2 167
912541b0 168 return 0;
f503f6b2
AJ
169}
170
171ssize_t udev_queue_skip_devpath(FILE *queue_file)
172{
912541b0 173 unsigned short int len;
f503f6b2 174
912541b0 175 if (fread(&len, sizeof(unsigned short int), 1, queue_file) == 1) {
fc863dea 176 char *devpath = alloca(len);
f503f6b2 177
912541b0
KS
178 /* use fread to skip, fseek might drop buffered data */
179 if (fread(devpath, 1, len, queue_file) == len)
180 return len;
181 }
f503f6b2 182
912541b0 183 return -1;
f503f6b2
AJ
184}
185
186ssize_t udev_queue_read_devpath(FILE *queue_file, char *devpath, size_t size)
187{
912541b0
KS
188 unsigned short int read_bytes = 0;
189 unsigned short int len;
f503f6b2 190
912541b0
KS
191 if (fread(&len, sizeof(unsigned short int), 1, queue_file) != 1)
192 return -1;
f503f6b2 193
912541b0
KS
194 read_bytes = (len < size - 1) ? len : size - 1;
195 if (fread(devpath, 1, read_bytes, queue_file) != read_bytes)
196 return -1;
197 devpath[read_bytes] = '\0';
f503f6b2 198
912541b0
KS
199 /* if devpath was too long, skip unread characters */
200 if (read_bytes != len) {
201 unsigned short int skip_bytes = len - read_bytes;
fc863dea 202 char *buf = alloca(skip_bytes);
f503f6b2 203
912541b0
KS
204 if (fread(buf, 1, skip_bytes, queue_file) != skip_bytes)
205 return -1;
206 }
f503f6b2 207
912541b0 208 return read_bytes;
f503f6b2
AJ
209}
210
211static FILE *open_queue_file(struct udev_queue *udev_queue, unsigned long long int *seqnum_start)
11d5eec2 212{
912541b0
KS
213 char filename[UTIL_PATH_SIZE];
214 FILE *queue_file;
11d5eec2 215
6ada823a 216 util_strscpyl(filename, sizeof(filename), "/run/udev/queue.bin", NULL);
912541b0
KS
217 queue_file = fopen(filename, "re");
218 if (queue_file == NULL)
219 return NULL;
f503f6b2 220
912541b0 221 if (udev_queue_read_seqnum(queue_file, seqnum_start) < 0) {
c8f8394a 222 udev_err(udev_queue->udev, "corrupt queue file\n");
912541b0
KS
223 fclose(queue_file);
224 return NULL;
225 }
f503f6b2 226
912541b0 227 return queue_file;
f503f6b2
AJ
228}
229
8d6bc73a
KS
230/**
231 * udev_queue_get_udev_seqnum:
232 * @udev_queue: udev queue context
233 *
21dbe43a
KS
234 * Get the last known udev event sequence number.
235 *
236 * Returns: the sequence number.
8d6bc73a 237 **/
54cf0b7f 238_public_ unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *udev_queue)
f503f6b2 239{
912541b0
KS
240 unsigned long long int seqnum_udev;
241 FILE *queue_file;
242
243 queue_file = open_queue_file(udev_queue, &seqnum_udev);
244 if (queue_file == NULL)
245 return 0;
246
247 for (;;) {
248 unsigned long long int seqnum;
249 ssize_t devpath_len;
250
251 if (udev_queue_read_seqnum(queue_file, &seqnum) < 0)
252 break;
253 devpath_len = udev_queue_skip_devpath(queue_file);
254 if (devpath_len < 0)
255 break;
256 if (devpath_len > 0)
257 seqnum_udev = seqnum;
258 }
259
260 fclose(queue_file);
261 return seqnum_udev;
f503f6b2
AJ
262}
263
8d6bc73a
KS
264/**
265 * udev_queue_get_udev_is_active:
266 * @udev_queue: udev queue context
267 *
21dbe43a
KS
268 * Check if udev is active on the system.
269 *
8d6bc73a
KS
270 * Returns: a flag indicating if udev is active.
271 **/
54cf0b7f 272_public_ int udev_queue_get_udev_is_active(struct udev_queue *udev_queue)
f503f6b2 273{
912541b0
KS
274 unsigned long long int seqnum_start;
275 FILE *queue_file;
f503f6b2 276
912541b0
KS
277 queue_file = open_queue_file(udev_queue, &seqnum_start);
278 if (queue_file == NULL)
279 return 0;
f503f6b2 280
912541b0
KS
281 fclose(queue_file);
282 return 1;
11d5eec2
KS
283}
284
8d6bc73a
KS
285/**
286 * udev_queue_get_queue_is_empty:
287 * @udev_queue: udev queue context
288 *
21dbe43a
KS
289 * Check if udev is currently processing any events.
290 *
8d6bc73a
KS
291 * Returns: a flag indicating if udev is currently handling events.
292 **/
54cf0b7f 293_public_ int udev_queue_get_queue_is_empty(struct udev_queue *udev_queue)
64ccdf82 294{
912541b0
KS
295 unsigned long long int seqnum_kernel;
296 unsigned long long int seqnum_udev = 0;
297 int queued = 0;
298 int is_empty = 0;
299 FILE *queue_file;
300
301 if (udev_queue == NULL)
302 return -EINVAL;
303 queue_file = open_queue_file(udev_queue, &seqnum_udev);
304 if (queue_file == NULL)
305 return 1;
306
307 for (;;) {
308 unsigned long long int seqnum;
309 ssize_t devpath_len;
310
311 if (udev_queue_read_seqnum(queue_file, &seqnum) < 0)
312 break;
313 devpath_len = udev_queue_skip_devpath(queue_file);
314 if (devpath_len < 0)
315 break;
316
317 if (devpath_len > 0) {
318 queued++;
319 seqnum_udev = seqnum;
320 } else {
321 queued--;
322 }
323 }
324
baa30fbc 325 if (queued > 0)
912541b0 326 goto out;
912541b0
KS
327
328 seqnum_kernel = udev_queue_get_kernel_seqnum(udev_queue);
baa30fbc 329 if (seqnum_udev < seqnum_kernel)
912541b0 330 goto out;
912541b0 331
912541b0 332 is_empty = 1;
f503f6b2
AJ
333
334out:
912541b0
KS
335 fclose(queue_file);
336 return is_empty;
64ccdf82
KS
337}
338
8d6bc73a
KS
339/**
340 * udev_queue_get_seqnum_sequence_is_finished:
341 * @udev_queue: udev queue context
342 * @start: first event sequence number
343 * @end: last event sequence number
344 *
21dbe43a
KS
345 * Check if udev is currently processing any events in a given sequence number range.
346 *
2906cbba 347 * Returns: a flag indicating if any of the sequence numbers in the given range is currently active.
8d6bc73a 348 **/
54cf0b7f 349_public_ int udev_queue_get_seqnum_sequence_is_finished(struct udev_queue *udev_queue,
912541b0 350 unsigned long long int start, unsigned long long int end)
64ccdf82 351{
912541b0
KS
352 unsigned long long int seqnum;
353 ssize_t devpath_len;
354 int unfinished;
355 FILE *queue_file;
356
357 if (udev_queue == NULL)
358 return -EINVAL;
359 queue_file = open_queue_file(udev_queue, &seqnum);
360 if (queue_file == NULL)
361 return 1;
362 if (start < seqnum)
363 start = seqnum;
364 if (start > end) {
365 fclose(queue_file);
366 return 1;
367 }
368 if (end - start > INT_MAX - 1) {
369 fclose(queue_file);
370 return -EOVERFLOW;
371 }
372
373 /*
374 * we might start with 0, and handle the initial seqnum
375 * only when we find an entry in the queue file
376 **/
377 unfinished = end - start;
378
379 do {
380 if (udev_queue_read_seqnum(queue_file, &seqnum) < 0)
381 break;
382 devpath_len = udev_queue_skip_devpath(queue_file);
383 if (devpath_len < 0)
384 break;
385
386 /*
387 * we might start with an empty or re-build queue file, where
388 * the initial seqnum is not recorded as finished
389 */
390 if (start == seqnum && devpath_len > 0)
391 unfinished++;
392
393 if (devpath_len == 0) {
394 if (seqnum >= start && seqnum <= end)
395 unfinished--;
396 }
397 } while (unfinished > 0);
398
399 fclose(queue_file);
400
401 return (unfinished == 0);
f503f6b2
AJ
402}
403
8d6bc73a
KS
404/**
405 * udev_queue_get_seqnum_is_finished:
406 * @udev_queue: udev queue context
407 * @seqnum: sequence number
408 *
21dbe43a
KS
409 * Check if udev is currently processing a given sequence number.
410 *
2906cbba 411 * Returns: a flag indicating if the given sequence number is currently active.
8d6bc73a 412 **/
54cf0b7f 413_public_ int udev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, unsigned long long int seqnum)
f503f6b2 414{
912541b0
KS
415 if (!udev_queue_get_seqnum_sequence_is_finished(udev_queue, seqnum, seqnum))
416 return 0;
f503f6b2 417
912541b0 418 return 1;
64ccdf82
KS
419}
420
8d6bc73a
KS
421/**
422 * udev_queue_get_queued_list_entry:
423 * @udev_queue: udev queue context
424 *
21dbe43a
KS
425 * Get the first entry of the list of queued events.
426 *
427 * Returns: a udev_list_entry.
8d6bc73a 428 **/
54cf0b7f 429_public_ struct udev_list_entry *udev_queue_get_queued_list_entry(struct udev_queue *udev_queue)
64ccdf82 430{
912541b0
KS
431 unsigned long long int seqnum;
432 FILE *queue_file;
433
434 if (udev_queue == NULL)
435 return NULL;
436 udev_list_cleanup(&udev_queue->queue_list);
437
438 queue_file = open_queue_file(udev_queue, &seqnum);
439 if (queue_file == NULL)
440 return NULL;
441
442 for (;;) {
443 char syspath[UTIL_PATH_SIZE];
444 char *s;
445 size_t l;
446 ssize_t len;
447 char seqnum_str[32];
448 struct udev_list_entry *list_entry;
449
450 if (udev_queue_read_seqnum(queue_file, &seqnum) < 0)
451 break;
452 snprintf(seqnum_str, sizeof(seqnum_str), "%llu", seqnum);
453
454 s = syspath;
6ada823a 455 l = util_strpcpy(&s, sizeof(syspath), "/sys");
912541b0
KS
456 len = udev_queue_read_devpath(queue_file, s, l);
457 if (len < 0)
458 break;
459
460 if (len > 0) {
461 udev_list_entry_add(&udev_queue->queue_list, syspath, seqnum_str);
462 } else {
463 udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_queue->queue_list)) {
464 if (strcmp(seqnum_str, udev_list_entry_get_value(list_entry)) == 0) {
465 udev_list_entry_delete(list_entry);
466 break;
467 }
468 }
469 }
470 }
471 fclose(queue_file);
472
473 return udev_list_get_entry(&udev_queue->queue_list);
64ccdf82 474}