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