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.
14 * DISCLAIMER - The file format mentioned here is private to udev/libudev,
15 * and may be changed without notice.
17 * The udev event queue is exported as a binary log file.
18 * Each log record consists of a sequence number followed by the device path.
20 * When a new event is queued, its details are appended to the log.
21 * When the event finishes, a second record is appended to the log
22 * with the same sequence number but a devpath len of 0.
25 * { 0x0000000000000001 }
26 * { 0x0000000000000001, 0x0019, "/devices/virtual/mem/null" },
27 * { 0x0000000000000002, 0x001b, "/devices/virtual/mem/random" },
28 * { 0x0000000000000001, 0x0000 },
29 * { 0x0000000000000003, 0x0019, "/devices/virtual/mem/zero" },
31 * Events 2 and 3 are still queued, but event 1 has finished.
33 * The queue does not grow indefinitely. It is periodically re-created
34 * to remove finished events. Atomic rename() makes this transparent to readers.
36 * The queue file starts with a single sequence number which specifies the
37 * minimum sequence number in the log that follows. Any events prior to this
38 * sequence number have already finished.
50 #include <sys/types.h>
53 #include "libudev-private.h"
55 static int rebuild_queue_file(struct udev_queue_export *udev_queue_export);
57 struct udev_queue_export {
59 int queued_count; /* number of unfinished events exported in queue file */
61 unsigned long long int seqnum_max; /* earliest sequence number in queue file */
62 unsigned long long int seqnum_min; /* latest sequence number in queue file */
63 int waste_bytes; /* queue file bytes wasted on finished events */
66 struct udev_queue_export *udev_queue_export_new(struct udev *udev)
68 struct udev_queue_export *udev_queue_export;
69 unsigned long long int initial_seqnum;
74 udev_queue_export = calloc(1, sizeof(struct udev_queue_export));
75 if (udev_queue_export == NULL)
77 udev_queue_export->udev = udev;
79 initial_seqnum = udev_get_kernel_seqnum(udev);
80 udev_queue_export->seqnum_min = initial_seqnum;
81 udev_queue_export->seqnum_max = initial_seqnum;
83 udev_queue_export_cleanup(udev_queue_export);
84 if (rebuild_queue_file(udev_queue_export) != 0) {
85 free(udev_queue_export);
89 return udev_queue_export;
92 struct udev_queue_export *udev_queue_export_unref(struct udev_queue_export *udev_queue_export)
94 if (udev_queue_export == NULL)
96 if (udev_queue_export->queue_file != NULL)
97 fclose(udev_queue_export->queue_file);
98 free(udev_queue_export);
102 void udev_queue_export_cleanup(struct udev_queue_export *udev_queue_export)
104 if (udev_queue_export == NULL)
106 unlink("/run/udev/queue.tmp");
107 unlink("/run/udev/queue.bin");
110 static int skip_to(FILE *file, long offset)
114 /* fseek may drop buffered data, avoid it for small seeks */
115 old_offset = ftell(file);
116 if (offset > old_offset && offset - old_offset <= BUFSIZ) {
117 size_t skip_bytes = offset - old_offset;
118 char *buf = alloca(skip_bytes);
120 if (fread(buf, skip_bytes, 1, file) != skip_bytes)
124 return fseek(file, offset, SEEK_SET);
127 struct queue_devpaths {
128 unsigned int devpaths_first; /* index of first queued event */
129 unsigned int devpaths_size;
130 long devpaths[]; /* seqnum -> offset of devpath in queue file (or 0) */
134 * Returns a table mapping seqnum to devpath file offset for currently queued events.
135 * devpaths[i] represents the event with seqnum = i + udev_queue_export->seqnum_min.
137 static struct queue_devpaths *build_index(struct udev_queue_export *udev_queue_export)
139 struct queue_devpaths *devpaths;
140 unsigned long long int range;
143 unsigned long long int seqnum;
144 unsigned long long int n;
147 /* seek to the first event in the file */
148 rewind(udev_queue_export->queue_file);
149 udev_queue_read_seqnum(udev_queue_export->queue_file, &seqnum);
151 /* allocate the table */
152 range = udev_queue_export->seqnum_min - udev_queue_export->seqnum_max;
153 if (range - 1 > INT_MAX) {
154 udev_err(udev_queue_export->udev, "queue file overflow\n");
157 devpaths = calloc(1, sizeof(struct queue_devpaths) + (range + 1) * sizeof(long));
158 if (devpaths == NULL)
160 devpaths->devpaths_size = range + 1;
162 /* read all records and populate the table */
164 if (udev_queue_read_seqnum(udev_queue_export->queue_file, &seqnum) < 0)
166 n = seqnum - udev_queue_export->seqnum_max;
167 if (n >= devpaths->devpaths_size)
170 devpath_offset = ftell(udev_queue_export->queue_file);
171 devpath_len = udev_queue_skip_devpath(udev_queue_export->queue_file);
176 devpaths->devpaths[n] = devpath_offset;
178 devpaths->devpaths[n] = 0;
181 /* find first queued event */
182 for (i = 0; i < devpaths->devpaths_size; i++) {
183 if (devpaths->devpaths[i] != 0)
186 devpaths->devpaths_first = i;
191 udev_err(udev_queue_export->udev, "queue file corrupted\n");
196 static int rebuild_queue_file(struct udev_queue_export *udev_queue_export)
198 unsigned long long int seqnum;
199 struct queue_devpaths *devpaths = NULL;
200 FILE *new_queue_file = NULL;
203 /* read old queue file */
204 if (udev_queue_export->queue_file != NULL) {
205 devpaths = build_index(udev_queue_export);
206 if (devpaths != NULL)
207 udev_queue_export->seqnum_max += devpaths->devpaths_first;
209 if (devpaths == NULL) {
210 udev_queue_export->queued_count = 0;
211 udev_queue_export->seqnum_max = udev_queue_export->seqnum_min;
214 /* create new queue file */
215 new_queue_file = fopen("/run/udev/queue.tmp", "w+");
216 if (new_queue_file == NULL)
218 seqnum = udev_queue_export->seqnum_max;
219 fwrite(&seqnum, 1, sizeof(unsigned long long int), new_queue_file);
221 /* copy unfinished events only to the new file */
222 if (devpaths != NULL) {
223 for (i = devpaths->devpaths_first; i < devpaths->devpaths_size; i++) {
224 char devpath[UTIL_PATH_SIZE];
226 unsigned short devpath_len;
228 if (devpaths->devpaths[i] != 0)
230 skip_to(udev_queue_export->queue_file, devpaths->devpaths[i]);
231 err = udev_queue_read_devpath(udev_queue_export->queue_file, devpath, sizeof(devpath));
234 fwrite(&seqnum, sizeof(unsigned long long int), 1, new_queue_file);
235 fwrite(&devpath_len, sizeof(unsigned short), 1, new_queue_file);
236 fwrite(devpath, 1, devpath_len, new_queue_file);
243 fflush(new_queue_file);
244 if (ferror(new_queue_file))
247 /* rename the new file on top of the old one */
248 if (rename("/run/udev/queue.tmp", "/run/udev/queue.bin") != 0)
251 if (udev_queue_export->queue_file != NULL)
252 fclose(udev_queue_export->queue_file);
253 udev_queue_export->queue_file = new_queue_file;
254 udev_queue_export->waste_bytes = 0;
259 udev_err(udev_queue_export->udev, "failed to create queue file: %m\n");
260 udev_queue_export_cleanup(udev_queue_export);
262 if (udev_queue_export->queue_file != NULL) {
263 fclose(udev_queue_export->queue_file);
264 udev_queue_export->queue_file = NULL;
266 if (new_queue_file != NULL)
267 fclose(new_queue_file);
269 if (devpaths != NULL)
271 udev_queue_export->queued_count = 0;
272 udev_queue_export->waste_bytes = 0;
273 udev_queue_export->seqnum_max = udev_queue_export->seqnum_min;
278 static int write_queue_record(struct udev_queue_export *udev_queue_export,
279 unsigned long long int seqnum, const char *devpath, size_t devpath_len)
283 if (udev_queue_export->queue_file == NULL)
286 if (fwrite(&seqnum, sizeof(unsigned long long int), 1, udev_queue_export->queue_file) != 1)
289 len = (devpath_len < USHRT_MAX) ? devpath_len : USHRT_MAX;
290 if (fwrite(&len, sizeof(unsigned short), 1, udev_queue_export->queue_file) != 1)
293 if (fwrite(devpath, 1, len, udev_queue_export->queue_file) != len)
297 /* *must* flush output; caller may fork */
298 if (fflush(udev_queue_export->queue_file) != 0)
304 /* if we failed half way through writing a record to a file,
305 we should not try to write any further records to it. */
306 udev_err(udev_queue_export->udev, "error writing to queue file: %m\n");
307 fclose(udev_queue_export->queue_file);
308 udev_queue_export->queue_file = NULL;
318 static inline size_t queue_record_size(size_t devpath_len)
320 return sizeof(unsigned long long int) + sizeof(unsigned short int) + devpath_len;
323 static int update_queue(struct udev_queue_export *udev_queue_export,
324 struct udev_device *udev_device, enum device_state state)
326 unsigned long long int seqnum = udev_device_get_seqnum(udev_device);
327 const char *devpath = NULL;
328 size_t devpath_len = 0;
332 /* FINISHED records have a zero length devpath */
333 if (state == DEVICE_QUEUED) {
334 devpath = udev_device_get_devpath(udev_device);
335 devpath_len = strlen(devpath);
338 /* recover from an earlier failed rebuild */
339 if (udev_queue_export->queue_file == NULL) {
340 if (rebuild_queue_file(udev_queue_export) != 0)
344 /* if we're removing the last event from the queue, that's the best time to rebuild it */
345 if (state != DEVICE_QUEUED && udev_queue_export->queued_count == 1) {
346 /* we don't need to read the old queue file */
347 fclose(udev_queue_export->queue_file);
348 udev_queue_export->queue_file = NULL;
349 rebuild_queue_file(udev_queue_export);
353 /* try to rebuild the queue files before they grow larger than one page. */
354 bytes = ftell(udev_queue_export->queue_file) + queue_record_size(devpath_len);
355 if ((udev_queue_export->waste_bytes > bytes / 2) && bytes > 4096)
356 rebuild_queue_file(udev_queue_export);
358 /* don't record a finished event, if we already dropped the event in a failed rebuild */
359 if (seqnum < udev_queue_export->seqnum_max)
362 /* now write to the queue */
363 if (state == DEVICE_QUEUED) {
364 udev_queue_export->queued_count++;
365 udev_queue_export->seqnum_min = seqnum;
367 udev_queue_export->waste_bytes += queue_record_size(devpath_len) + queue_record_size(0);
368 udev_queue_export->queued_count--;
370 err = write_queue_record(udev_queue_export, seqnum, devpath, devpath_len);
372 /* try to handle ENOSPC */
373 if (err != 0 && udev_queue_export->queued_count == 0) {
374 udev_queue_export_cleanup(udev_queue_export);
375 err = rebuild_queue_file(udev_queue_export);
381 static int update(struct udev_queue_export *udev_queue_export,
382 struct udev_device *udev_device, enum device_state state)
384 if (update_queue(udev_queue_export, udev_device, state) != 0)
390 int udev_queue_export_device_queued(struct udev_queue_export *udev_queue_export, struct udev_device *udev_device)
392 return update(udev_queue_export, udev_device, DEVICE_QUEUED);
395 int udev_queue_export_device_finished(struct udev_queue_export *udev_queue_export, struct udev_device *udev_device)
397 return update(udev_queue_export, udev_device, DEVICE_FINISHED);