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"
30 struct udev_list_node queue_list;
31 struct udev_list_node failed_list;
34 struct udev_queue *udev_queue_new(struct udev *udev)
36 struct udev_queue *udev_queue;
41 udev_queue = calloc(1, sizeof(struct udev_queue));
42 if (udev_queue == NULL)
44 udev_queue->refcount = 1;
45 udev_queue->udev = udev;
46 udev_list_init(&udev_queue->queue_list);
47 udev_list_init(&udev_queue->failed_list);
51 struct udev_queue *udev_queue_ref(struct udev_queue *udev_queue)
53 if (udev_queue == NULL)
55 udev_queue->refcount++;
59 void udev_queue_unref(struct udev_queue *udev_queue)
61 if (udev_queue == NULL)
63 udev_queue->refcount--;
64 if (udev_queue->refcount > 0)
66 udev_list_cleanup_entries(udev_queue->udev, &udev_queue->queue_list);
67 udev_list_cleanup_entries(udev_queue->udev, &udev_queue->failed_list);
71 struct udev *udev_queue_get_udev(struct udev_queue *udev_queue)
73 if (udev_queue == NULL)
75 return udev_queue->udev;
78 unsigned long long int udev_get_kernel_seqnum(struct udev *udev)
80 char filename[UTIL_PATH_SIZE];
81 unsigned long long int seqnum;
86 util_strscpyl(filename, sizeof(filename), udev_get_sys_path(udev), "/kernel/uevent_seqnum", NULL);
87 fd = open(filename, O_RDONLY);
90 len = read(fd, buf, sizeof(buf));
95 seqnum = strtoull(buf, NULL, 10);
99 unsigned long long int udev_queue_get_kernel_seqnum(struct udev_queue *udev_queue)
101 unsigned long long int seqnum;
103 if (udev_queue == NULL)
106 seqnum = udev_get_kernel_seqnum(udev_queue->udev);
107 dbg(udev_queue->udev, "seqnum=%llu\n", seqnum);
111 int udev_queue_read_seqnum(FILE *queue_file, unsigned long long int *seqnum)
113 if (fread(seqnum, sizeof(unsigned long long int), 1, queue_file) != 1)
119 ssize_t udev_queue_skip_devpath(FILE *queue_file)
121 unsigned short int len;
123 if (fread(&len, sizeof(unsigned short int), 1, queue_file) == 1) {
126 /* use fread to skip, fseek might drop buffered data */
127 if (fread(devpath, 1, len, queue_file) == len)
134 ssize_t udev_queue_read_devpath(FILE *queue_file, char *devpath, size_t size)
136 unsigned short int read_bytes = 0;
137 unsigned short int len;
139 if (fread(&len, sizeof(unsigned short int), 1, queue_file) != 1)
142 read_bytes = (len < size - 1) ? len : size - 1;
143 if (fread(devpath, 1, read_bytes, queue_file) != read_bytes)
145 devpath[read_bytes] = '\0';
147 /* if devpath was too long, skip unread characters */
148 if (read_bytes != len) {
149 unsigned short int skip_bytes = len - read_bytes;
150 char buf[skip_bytes];
152 if (fread(buf, 1, skip_bytes, queue_file) != skip_bytes)
159 static FILE *open_queue_file(struct udev_queue *udev_queue, unsigned long long int *seqnum_start)
161 char filename[UTIL_PATH_SIZE];
164 util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev_queue->udev), "/.udev/queue.bin", NULL);
165 queue_file = fopen(filename, "r");
166 if (queue_file == NULL)
169 if (udev_queue_read_seqnum(queue_file, seqnum_start) < 0) {
170 err(udev_queue->udev, "corrupt queue file\n");
179 unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *udev_queue)
181 unsigned long long int seqnum_udev;
184 queue_file = open_queue_file(udev_queue, &seqnum_udev);
185 if (queue_file == NULL)
189 unsigned long long int seqnum;
192 if (udev_queue_read_seqnum(queue_file, &seqnum) < 0)
194 devpath_len = udev_queue_skip_devpath(queue_file);
198 seqnum_udev = seqnum;
205 int udev_queue_get_udev_is_active(struct udev_queue *udev_queue)
207 unsigned long long int seqnum_start;
210 queue_file = open_queue_file(udev_queue, &seqnum_start);
211 if (queue_file == NULL)
218 int udev_queue_get_queue_is_empty(struct udev_queue *udev_queue)
220 unsigned long long int seqnum_kernel;
221 unsigned long long int seqnum_udev = 0;
226 if (udev_queue == NULL)
228 queue_file = open_queue_file(udev_queue, &seqnum_udev);
229 if (queue_file == NULL)
233 unsigned long long int seqnum;
236 if (udev_queue_read_seqnum(queue_file, &seqnum) < 0)
238 devpath_len = udev_queue_skip_devpath(queue_file);
242 if (devpath_len > 0) {
244 seqnum_udev = seqnum;
251 dbg(udev_queue->udev, "queue is not empty\n");
255 seqnum_kernel = udev_queue_get_kernel_seqnum(udev_queue);
256 if (seqnum_udev < seqnum_kernel) {
257 dbg(udev_queue->udev, "queue is empty but kernel events still pending [%llu]<->[%llu]\n",
258 seqnum_kernel, seqnum_udev);
262 dbg(udev_queue->udev, "queue is empty\n");
270 int udev_queue_get_seqnum_sequence_is_finished(struct udev_queue *udev_queue,
271 unsigned long long int start, unsigned long long int end)
273 unsigned long long int seqnum = 0;
278 if (udev_queue == NULL)
280 queue_file = open_queue_file(udev_queue, &seqnum);
281 if (queue_file == NULL)
287 if (end - start > INT_MAX - 1)
289 unfinished = (end - start) + 1;
291 while (unfinished > 0) {
292 if (udev_queue_read_seqnum(queue_file, &seqnum) < 0)
294 devpath_len = udev_queue_skip_devpath(queue_file);
298 if (devpath_len == 0) {
299 if (seqnum >= start && seqnum <= end)
305 return (unfinished == 0);
308 int udev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, unsigned long long int seqnum)
310 if (!udev_queue_get_seqnum_sequence_is_finished(udev_queue, seqnum, seqnum))
313 dbg(udev_queue->udev, "seqnum: %llu finished\n", seqnum);
317 struct udev_list_entry *udev_queue_get_queued_list_entry(struct udev_queue *udev_queue)
319 unsigned long long int seqnum;
322 if (udev_queue == NULL)
324 udev_list_cleanup_entries(udev_queue->udev, &udev_queue->queue_list);
326 queue_file = open_queue_file(udev_queue, &seqnum);
327 if (queue_file == NULL)
331 char syspath[UTIL_PATH_SIZE];
336 struct udev_list_entry *list_entry;
338 if (udev_queue_read_seqnum(queue_file, &seqnum) < 0)
340 snprintf(seqnum_str, sizeof(seqnum_str), "%llu", seqnum);
343 l = util_strpcpyl(&s, sizeof(syspath), udev_get_sys_path(udev_queue->udev), NULL);
344 len = udev_queue_read_devpath(queue_file, s, l);
349 udev_list_entry_add(udev_queue->udev, &udev_queue->queue_list, syspath, seqnum_str, 0, 0);
351 udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_queue->queue_list)) {
352 if (strcmp(seqnum_str, udev_list_entry_get_value(list_entry)) == 0) {
353 udev_list_entry_delete(list_entry);
361 return udev_list_get_entry(&udev_queue->queue_list);
364 struct udev_list_entry *udev_queue_get_failed_list_entry(struct udev_queue *udev_queue)
366 char path[UTIL_PATH_SIZE];
370 if (udev_queue == NULL)
372 udev_list_cleanup_entries(udev_queue->udev, &udev_queue->failed_list);
373 util_strscpyl(path, sizeof(path), udev_get_dev_path(udev_queue->udev), "/.udev/failed", NULL);
377 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
378 char filename[UTIL_PATH_SIZE];
379 char syspath[UTIL_PATH_SIZE];
385 if (dent->d_name[0] == '.')
388 l = util_strpcpyl(&s, sizeof(syspath), udev_get_sys_path(udev_queue->udev), NULL);
389 len = readlinkat(dirfd(dir), dent->d_name, s, l);
390 if (len < 0 || (size_t)len >= l)
393 dbg(udev_queue->udev, "found '%s' [%s]\n", syspath, dent->d_name);
394 util_strscpyl(filename, sizeof(filename), syspath, "/uevent", NULL);
395 if (stat(filename, &statbuf) != 0)
397 udev_list_entry_add(udev_queue->udev, &udev_queue->failed_list, syspath, NULL, 0, 0);
400 return udev_list_get_entry(&udev_queue->failed_list);