X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=libudev%2Flibudev-queue.c;h=be6409d02a4d82e462f0400d2f5d30aead2fa9d7;hp=bfd90975069eada8bdab949f0ddbb1128e2554b2;hb=2906cbbae4d97291c1cfc456cf132726fffd8fc0;hpb=ce1d6d7fb47582588cfbcf0baba0c58e42a90ca6;ds=sidebyside diff --git a/libudev/libudev-queue.c b/libudev/libudev-queue.c index bfd909750..be6409d02 100644 --- a/libudev/libudev-queue.c +++ b/libudev/libudev-queue.c @@ -28,9 +28,9 @@ * SECTION:libudev-queue * @short_description: access to currently active events * - * The udev daemon processes event asynchronously. All events wich do not have - * interdependencies are run in parallel. This exports the current state of the - * event processing queue, and the currently event sequence numbers from the kernel + * The udev daemon processes events asynchronously. All events which do not have + * interdependencies run in parallel. This exports the current state of the + * event processing queue, and the current event sequence numbers from the kernel * and the udev daemon. */ @@ -46,6 +46,15 @@ struct udev_queue { struct udev_list_node failed_list; }; +/** + * udev_queue_new: + * @udev: udev library context + * + * The initial refcount is 1, and needs to be decremented to + * release the resources of the udev queue context. + * + * Returns: the udev queue context, or #NULL on error. + **/ struct udev_queue *udev_queue_new(struct udev *udev) { struct udev_queue *udev_queue; @@ -63,6 +72,14 @@ struct udev_queue *udev_queue_new(struct udev *udev) return udev_queue; } +/** + * udev_queue_ref: + * @udev_queue: udev queue context + * + * Take a reference of a udev queue context. + * + * Returns: the same udev queue context. + **/ struct udev_queue *udev_queue_ref(struct udev_queue *udev_queue) { if (udev_queue == NULL) @@ -71,6 +88,13 @@ struct udev_queue *udev_queue_ref(struct udev_queue *udev_queue) return udev_queue; } +/** + * udev_queue_unref: + * @udev_queue: udev queue context + * + * Drop a reference of a udev queue context. If the refcount reaches zero, + * the resources of the queue context will be released. + **/ void udev_queue_unref(struct udev_queue *udev_queue) { if (udev_queue == NULL) @@ -83,6 +107,14 @@ void udev_queue_unref(struct udev_queue *udev_queue) free(udev_queue); } +/** + * udev_queue_get_udev: + * @udev_queue: udev queue context + * + * Retrieve the udev library context the queue context was created with. + * + * Returns: the udev library context. + **/ struct udev *udev_queue_get_udev(struct udev_queue *udev_queue) { if (udev_queue == NULL) @@ -99,7 +131,7 @@ unsigned long long int udev_get_kernel_seqnum(struct udev *udev) ssize_t len; util_strscpyl(filename, sizeof(filename), udev_get_sys_path(udev), "/kernel/uevent_seqnum", NULL); - fd = open(filename, O_RDONLY); + fd = open(filename, O_RDONLY|O_CLOEXEC); if (fd < 0) return 0; len = read(fd, buf, sizeof(buf)); @@ -111,6 +143,12 @@ unsigned long long int udev_get_kernel_seqnum(struct udev *udev) return seqnum; } +/** + * udev_queue_get_kernel_seqnum: + * @udev_queue: udev queue context + * + * Returns: the current kernel event sequence number. + **/ unsigned long long int udev_queue_get_kernel_seqnum(struct udev_queue *udev_queue) { unsigned long long int seqnum; @@ -176,8 +214,8 @@ static FILE *open_queue_file(struct udev_queue *udev_queue, unsigned long long i char filename[UTIL_PATH_SIZE]; FILE *queue_file; - util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev_queue->udev), "/.udev/queue.bin", NULL); - queue_file = fopen(filename, "r"); + util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev_queue->udev), "/queue.bin", NULL); + queue_file = fopen(filename, "re"); if (queue_file == NULL) return NULL; @@ -190,7 +228,12 @@ static FILE *open_queue_file(struct udev_queue *udev_queue, unsigned long long i return queue_file; } - +/** + * udev_queue_get_udev_seqnum: + * @udev_queue: udev queue context + * + * Returns: the last known udev event sequence number. + **/ unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *udev_queue) { unsigned long long int seqnum_udev; @@ -200,7 +243,7 @@ unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *udev_queue) if (queue_file == NULL) return 0; - while (1) { + for (;;) { unsigned long long int seqnum; ssize_t devpath_len; @@ -217,6 +260,12 @@ unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *udev_queue) return seqnum_udev; } +/** + * udev_queue_get_udev_is_active: + * @udev_queue: udev queue context + * + * Returns: a flag indicating if udev is active. + **/ int udev_queue_get_udev_is_active(struct udev_queue *udev_queue) { unsigned long long int seqnum_start; @@ -230,6 +279,12 @@ int udev_queue_get_udev_is_active(struct udev_queue *udev_queue) return 1; } +/** + * udev_queue_get_queue_is_empty: + * @udev_queue: udev queue context + * + * Returns: a flag indicating if udev is currently handling events. + **/ int udev_queue_get_queue_is_empty(struct udev_queue *udev_queue) { unsigned long long int seqnum_kernel; @@ -244,7 +299,7 @@ int udev_queue_get_queue_is_empty(struct udev_queue *udev_queue) if (queue_file == NULL) return 1; - while (1) { + for (;;) { unsigned long long int seqnum; ssize_t devpath_len; @@ -282,10 +337,18 @@ out: return is_empty; } +/** + * udev_queue_get_seqnum_sequence_is_finished: + * @udev_queue: udev queue context + * @start: first event sequence number + * @end: last event sequence number + * + * Returns: a flag indicating if any of the sequence numbers in the given range is currently active. + **/ int udev_queue_get_seqnum_sequence_is_finished(struct udev_queue *udev_queue, unsigned long long int start, unsigned long long int end) { - unsigned long long int seqnum = 0; + unsigned long long int seqnum; ssize_t devpath_len; int unfinished; FILE *queue_file; @@ -297,29 +360,53 @@ int udev_queue_get_seqnum_sequence_is_finished(struct udev_queue *udev_queue, return 1; if (start < seqnum) start = seqnum; - if (start > end) + if (start > end) { + fclose(queue_file); return 1; - if (end - start > INT_MAX - 1) + } + if (end - start > INT_MAX - 1) { + fclose(queue_file); return -EOVERFLOW; - unfinished = (end - start) + 1; + } + + /* + * we might start with 0, and handle the initial seqnum + * only when we find an entry in the queue file + **/ + unfinished = end - start; - while (unfinished > 0) { + do { if (udev_queue_read_seqnum(queue_file, &seqnum) < 0) break; devpath_len = udev_queue_skip_devpath(queue_file); if (devpath_len < 0) break; + /* + * we might start with an empty or re-build queue file, where + * the initial seqnum is not recorded as finished + */ + if (start == seqnum && devpath_len > 0) + unfinished++; + if (devpath_len == 0) { if (seqnum >= start && seqnum <= end) unfinished--; } - } + } while (unfinished > 0); + fclose(queue_file); return (unfinished == 0); } +/** + * udev_queue_get_seqnum_is_finished: + * @udev_queue: udev queue context + * @seqnum: sequence number + * + * Returns: a flag indicating if the given sequence number is currently active. + **/ int udev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, unsigned long long int seqnum) { if (!udev_queue_get_seqnum_sequence_is_finished(udev_queue, seqnum, seqnum)) @@ -329,6 +416,12 @@ int udev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, unsigned lo return 1; } +/** + * udev_queue_get_queued_list_entry: + * @udev_queue: udev queue context + * + * Returns: the first entry of the list of queued events. + **/ struct udev_list_entry *udev_queue_get_queued_list_entry(struct udev_queue *udev_queue) { unsigned long long int seqnum; @@ -342,7 +435,7 @@ struct udev_list_entry *udev_queue_get_queued_list_entry(struct udev_queue *udev if (queue_file == NULL) return NULL; - while (1) { + for (;;) { char syspath[UTIL_PATH_SIZE]; char *s; size_t l; @@ -361,7 +454,7 @@ struct udev_list_entry *udev_queue_get_queued_list_entry(struct udev_queue *udev break; if (len > 0) { - udev_list_entry_add(udev_queue->udev, &udev_queue->queue_list, syspath, seqnum_str, 0, 0); + udev_list_entry_add(udev_queue->udev, &udev_queue->queue_list, syspath, seqnum_str, 0); } else { udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_queue->queue_list)) { if (strcmp(seqnum_str, udev_list_entry_get_value(list_entry)) == 0) { @@ -376,6 +469,12 @@ struct udev_list_entry *udev_queue_get_queued_list_entry(struct udev_queue *udev return udev_list_get_entry(&udev_queue->queue_list); } +/** + * udev_queue_get_failed_list_entry: + * @udev_queue: udev queue context + * + * Returns: the first entry of the list of recorded failed events. + **/ struct udev_list_entry *udev_queue_get_failed_list_entry(struct udev_queue *udev_queue) { char path[UTIL_PATH_SIZE]; @@ -385,7 +484,7 @@ struct udev_list_entry *udev_queue_get_failed_list_entry(struct udev_queue *udev if (udev_queue == NULL) return NULL; udev_list_cleanup_entries(udev_queue->udev, &udev_queue->failed_list); - util_strscpyl(path, sizeof(path), udev_get_dev_path(udev_queue->udev), "/.udev/failed", NULL); + util_strscpyl(path, sizeof(path), udev_get_run_path(udev_queue->udev), "/failed", NULL); dir = opendir(path); if (dir == NULL) return NULL; @@ -402,14 +501,14 @@ struct udev_list_entry *udev_queue_get_failed_list_entry(struct udev_queue *udev s = syspath; l = util_strpcpyl(&s, sizeof(syspath), udev_get_sys_path(udev_queue->udev), NULL); len = readlinkat(dirfd(dir), dent->d_name, s, l); - if (len < 0 || (size_t)len >= l) + if (len <= 0 || (size_t)len == l) continue; s[len] = '\0'; dbg(udev_queue->udev, "found '%s' [%s]\n", syspath, dent->d_name); util_strscpyl(filename, sizeof(filename), syspath, "/uevent", NULL); if (stat(filename, &statbuf) != 0) continue; - udev_list_entry_add(udev_queue->udev, &udev_queue->failed_list, syspath, NULL, 0, 0); + udev_list_entry_add(udev_queue->udev, &udev_queue->failed_list, syspath, NULL, 0); } closedir(dir); return udev_list_get_entry(&udev_queue->failed_list);