]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/udev/libudev-queue.c
udev: ata_id - remove assert() until we switch over to systemd logging
[thirdparty/systemd.git] / src / udev / 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 **/
666fcf03 57UDEV_EXPORT 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 **/
666fcf03 81UDEV_EXPORT 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.
95 **/
666fcf03 96UDEV_EXPORT void udev_queue_unref(struct udev_queue *udev_queue)
64ccdf82 97{
912541b0
KS
98 if (udev_queue == NULL)
99 return;
100 udev_queue->refcount--;
101 if (udev_queue->refcount > 0)
102 return;
103 udev_list_cleanup(&udev_queue->queue_list);
104 free(udev_queue);
64ccdf82
KS
105}
106
8d6bc73a
KS
107/**
108 * udev_queue_get_udev:
109 * @udev_queue: udev queue context
110 *
111 * Retrieve the udev library context the queue context was created with.
112 *
113 * Returns: the udev library context.
114 **/
666fcf03 115UDEV_EXPORT struct udev *udev_queue_get_udev(struct udev_queue *udev_queue)
64ccdf82 116{
912541b0
KS
117 if (udev_queue == NULL)
118 return NULL;
119 return udev_queue->udev;
64ccdf82
KS
120}
121
f503f6b2 122unsigned long long int udev_get_kernel_seqnum(struct udev *udev)
64ccdf82 123{
912541b0
KS
124 char filename[UTIL_PATH_SIZE];
125 unsigned long long int seqnum;
126 int fd;
127 char buf[32];
128 ssize_t len;
129
130 util_strscpyl(filename, sizeof(filename), udev_get_sys_path(udev), "/kernel/uevent_seqnum", NULL);
131 fd = open(filename, O_RDONLY|O_CLOEXEC);
132 if (fd < 0)
133 return 0;
134 len = read(fd, buf, sizeof(buf));
135 close(fd);
136 if (len <= 2)
137 return 0;
138 buf[len-1] = '\0';
139 seqnum = strtoull(buf, NULL, 10);
140 return seqnum;
64ccdf82
KS
141}
142
8d6bc73a
KS
143/**
144 * udev_queue_get_kernel_seqnum:
145 * @udev_queue: udev queue context
146 *
147 * Returns: the current kernel event sequence number.
148 **/
666fcf03 149UDEV_EXPORT unsigned long long int udev_queue_get_kernel_seqnum(struct udev_queue *udev_queue)
64ccdf82 150{
912541b0 151 unsigned long long int seqnum;
64ccdf82 152
912541b0
KS
153 if (udev_queue == NULL)
154 return -EINVAL;
f503f6b2 155
912541b0
KS
156 seqnum = udev_get_kernel_seqnum(udev_queue->udev);
157 dbg(udev_queue->udev, "seqnum=%llu\n", seqnum);
158 return seqnum;
64ccdf82
KS
159}
160
f503f6b2
AJ
161int udev_queue_read_seqnum(FILE *queue_file, unsigned long long int *seqnum)
162{
912541b0
KS
163 if (fread(seqnum, sizeof(unsigned long long int), 1, queue_file) != 1)
164 return -1;
f503f6b2 165
912541b0 166 return 0;
f503f6b2
AJ
167}
168
169ssize_t udev_queue_skip_devpath(FILE *queue_file)
170{
912541b0 171 unsigned short int len;
f503f6b2 172
912541b0 173 if (fread(&len, sizeof(unsigned short int), 1, queue_file) == 1) {
fc863dea 174 char *devpath = alloca(len);
f503f6b2 175
912541b0
KS
176 /* use fread to skip, fseek might drop buffered data */
177 if (fread(devpath, 1, len, queue_file) == len)
178 return len;
179 }
f503f6b2 180
912541b0 181 return -1;
f503f6b2
AJ
182}
183
184ssize_t udev_queue_read_devpath(FILE *queue_file, char *devpath, size_t size)
185{
912541b0
KS
186 unsigned short int read_bytes = 0;
187 unsigned short int len;
f503f6b2 188
912541b0
KS
189 if (fread(&len, sizeof(unsigned short int), 1, queue_file) != 1)
190 return -1;
f503f6b2 191
912541b0
KS
192 read_bytes = (len < size - 1) ? len : size - 1;
193 if (fread(devpath, 1, read_bytes, queue_file) != read_bytes)
194 return -1;
195 devpath[read_bytes] = '\0';
f503f6b2 196
912541b0
KS
197 /* if devpath was too long, skip unread characters */
198 if (read_bytes != len) {
199 unsigned short int skip_bytes = len - read_bytes;
fc863dea 200 char *buf = alloca(skip_bytes);
f503f6b2 201
912541b0
KS
202 if (fread(buf, 1, skip_bytes, queue_file) != skip_bytes)
203 return -1;
204 }
f503f6b2 205
912541b0 206 return read_bytes;
f503f6b2
AJ
207}
208
209static FILE *open_queue_file(struct udev_queue *udev_queue, unsigned long long int *seqnum_start)
11d5eec2 210{
912541b0
KS
211 char filename[UTIL_PATH_SIZE];
212 FILE *queue_file;
11d5eec2 213
912541b0
KS
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)
217 return NULL;
f503f6b2 218
912541b0
KS
219 if (udev_queue_read_seqnum(queue_file, seqnum_start) < 0) {
220 err(udev_queue->udev, "corrupt queue file\n");
221 fclose(queue_file);
222 return NULL;
223 }
f503f6b2 224
912541b0 225 return queue_file;
f503f6b2
AJ
226}
227
8d6bc73a
KS
228/**
229 * udev_queue_get_udev_seqnum:
230 * @udev_queue: udev queue context
231 *
232 * Returns: the last known udev event sequence number.
233 **/
666fcf03 234UDEV_EXPORT unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *udev_queue)
f503f6b2 235{
912541b0
KS
236 unsigned long long int seqnum_udev;
237 FILE *queue_file;
238
239 queue_file = open_queue_file(udev_queue, &seqnum_udev);
240 if (queue_file == NULL)
241 return 0;
242
243 for (;;) {
244 unsigned long long int seqnum;
245 ssize_t devpath_len;
246
247 if (udev_queue_read_seqnum(queue_file, &seqnum) < 0)
248 break;
249 devpath_len = udev_queue_skip_devpath(queue_file);
250 if (devpath_len < 0)
251 break;
252 if (devpath_len > 0)
253 seqnum_udev = seqnum;
254 }
255
256 fclose(queue_file);
257 return seqnum_udev;
f503f6b2
AJ
258}
259
8d6bc73a
KS
260/**
261 * udev_queue_get_udev_is_active:
262 * @udev_queue: udev queue context
263 *
264 * Returns: a flag indicating if udev is active.
265 **/
666fcf03 266UDEV_EXPORT int udev_queue_get_udev_is_active(struct udev_queue *udev_queue)
f503f6b2 267{
912541b0
KS
268 unsigned long long int seqnum_start;
269 FILE *queue_file;
f503f6b2 270
912541b0
KS
271 queue_file = open_queue_file(udev_queue, &seqnum_start);
272 if (queue_file == NULL)
273 return 0;
f503f6b2 274
912541b0
KS
275 fclose(queue_file);
276 return 1;
11d5eec2
KS
277}
278
8d6bc73a
KS
279/**
280 * udev_queue_get_queue_is_empty:
281 * @udev_queue: udev queue context
282 *
283 * Returns: a flag indicating if udev is currently handling events.
284 **/
666fcf03 285UDEV_EXPORT int udev_queue_get_queue_is_empty(struct udev_queue *udev_queue)
64ccdf82 286{
912541b0
KS
287 unsigned long long int seqnum_kernel;
288 unsigned long long int seqnum_udev = 0;
289 int queued = 0;
290 int is_empty = 0;
291 FILE *queue_file;
292
293 if (udev_queue == NULL)
294 return -EINVAL;
295 queue_file = open_queue_file(udev_queue, &seqnum_udev);
296 if (queue_file == NULL)
297 return 1;
298
299 for (;;) {
300 unsigned long long int seqnum;
301 ssize_t devpath_len;
302
303 if (udev_queue_read_seqnum(queue_file, &seqnum) < 0)
304 break;
305 devpath_len = udev_queue_skip_devpath(queue_file);
306 if (devpath_len < 0)
307 break;
308
309 if (devpath_len > 0) {
310 queued++;
311 seqnum_udev = seqnum;
312 } else {
313 queued--;
314 }
315 }
316
317 if (queued > 0) {
318 dbg(udev_queue->udev, "queue is not empty\n");
319 goto out;
320 }
321
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",
6997e3b2 325 seqnum_kernel, seqnum_udev);
912541b0
KS
326 goto out;
327 }
328
329 dbg(udev_queue->udev, "queue is empty\n");
330 is_empty = 1;
f503f6b2
AJ
331
332out:
912541b0
KS
333 fclose(queue_file);
334 return is_empty;
64ccdf82
KS
335}
336
8d6bc73a
KS
337/**
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
342 *
2906cbba 343 * Returns: a flag indicating if any of the sequence numbers in the given range is currently active.
8d6bc73a 344 **/
666fcf03 345UDEV_EXPORT int udev_queue_get_seqnum_sequence_is_finished(struct udev_queue *udev_queue,
912541b0 346 unsigned long long int start, unsigned long long int end)
64ccdf82 347{
912541b0
KS
348 unsigned long long int seqnum;
349 ssize_t devpath_len;
350 int unfinished;
351 FILE *queue_file;
352
353 if (udev_queue == NULL)
354 return -EINVAL;
355 queue_file = open_queue_file(udev_queue, &seqnum);
356 if (queue_file == NULL)
357 return 1;
358 if (start < seqnum)
359 start = seqnum;
360 if (start > end) {
361 fclose(queue_file);
362 return 1;
363 }
364 if (end - start > INT_MAX - 1) {
365 fclose(queue_file);
366 return -EOVERFLOW;
367 }
368
369 /*
370 * we might start with 0, and handle the initial seqnum
371 * only when we find an entry in the queue file
372 **/
373 unfinished = end - start;
374
375 do {
376 if (udev_queue_read_seqnum(queue_file, &seqnum) < 0)
377 break;
378 devpath_len = udev_queue_skip_devpath(queue_file);
379 if (devpath_len < 0)
380 break;
381
382 /*
383 * we might start with an empty or re-build queue file, where
384 * the initial seqnum is not recorded as finished
385 */
386 if (start == seqnum && devpath_len > 0)
387 unfinished++;
388
389 if (devpath_len == 0) {
390 if (seqnum >= start && seqnum <= end)
391 unfinished--;
392 }
393 } while (unfinished > 0);
394
395 fclose(queue_file);
396
397 return (unfinished == 0);
f503f6b2
AJ
398}
399
8d6bc73a
KS
400/**
401 * udev_queue_get_seqnum_is_finished:
402 * @udev_queue: udev queue context
403 * @seqnum: sequence number
404 *
2906cbba 405 * Returns: a flag indicating if the given sequence number is currently active.
8d6bc73a 406 **/
666fcf03 407UDEV_EXPORT int udev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, unsigned long long int seqnum)
f503f6b2 408{
912541b0
KS
409 if (!udev_queue_get_seqnum_sequence_is_finished(udev_queue, seqnum, seqnum))
410 return 0;
f503f6b2 411
912541b0
KS
412 dbg(udev_queue->udev, "seqnum: %llu finished\n", seqnum);
413 return 1;
64ccdf82
KS
414}
415
8d6bc73a
KS
416/**
417 * udev_queue_get_queued_list_entry:
418 * @udev_queue: udev queue context
419 *
420 * Returns: the first entry of the list of queued events.
421 **/
666fcf03 422UDEV_EXPORT struct udev_list_entry *udev_queue_get_queued_list_entry(struct udev_queue *udev_queue)
64ccdf82 423{
912541b0
KS
424 unsigned long long int seqnum;
425 FILE *queue_file;
426
427 if (udev_queue == NULL)
428 return NULL;
429 udev_list_cleanup(&udev_queue->queue_list);
430
431 queue_file = open_queue_file(udev_queue, &seqnum);
432 if (queue_file == NULL)
433 return NULL;
434
435 for (;;) {
436 char syspath[UTIL_PATH_SIZE];
437 char *s;
438 size_t l;
439 ssize_t len;
440 char seqnum_str[32];
441 struct udev_list_entry *list_entry;
442
443 if (udev_queue_read_seqnum(queue_file, &seqnum) < 0)
444 break;
445 snprintf(seqnum_str, sizeof(seqnum_str), "%llu", seqnum);
446
447 s = syspath;
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);
450 if (len < 0)
451 break;
452
453 if (len > 0) {
454 udev_list_entry_add(&udev_queue->queue_list, syspath, seqnum_str);
455 } else {
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);
459 break;
460 }
461 }
462 }
463 }
464 fclose(queue_file);
465
466 return udev_list_get_entry(&udev_queue->queue_list);
64ccdf82
KS
467}
468
289a1821 469struct udev_list_entry *udev_queue_get_failed_list_entry(struct udev_queue *udev_queue);
666fcf03 470UDEV_EXPORT struct udev_list_entry *udev_queue_get_failed_list_entry(struct udev_queue *udev_queue)
64ccdf82 471{
912541b0
KS
472 errno = ENOSYS;
473 return NULL;
64ccdf82 474}