chiark / gitweb /
build-sys: re-add old symbols for abi compat
[elogind.git] / src / libudev / libudev-queue.c
index 0dd20313d9fe892dad73a1256b83041bd55bc002..ae0b415e368d9f6a31894e7a75018f028935d289 100644 (file)
 #include <unistd.h>
 #include <errno.h>
 #include <string.h>
-#include <dirent.h>
-#include <fcntl.h>
 #include <limits.h>
 #include <sys/stat.h>
+#include <sys/inotify.h>
 
 #include "libudev.h"
 #include "libudev-private.h"
  * SECTION:libudev-queue
  * @short_description: access to currently active events
  *
- * 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.
+ * This exports the current state of the udev processing queue.
  */
 
 /**
@@ -50,7 +46,7 @@
 struct udev_queue {
         struct udev *udev;
         int refcount;
-        struct udev_list queue_list;
+        int fd;
 };
 
 /**
@@ -69,12 +65,13 @@ _public_ struct udev_queue *udev_queue_new(struct udev *udev)
         if (udev == NULL)
                 return NULL;
 
-        udev_queue = calloc(1, sizeof(struct udev_queue));
+        udev_queue = new0(struct udev_queue, 1);
         if (udev_queue == NULL)
                 return NULL;
+
         udev_queue->refcount = 1;
         udev_queue->udev = udev;
-        udev_list_init(udev, &udev_queue->queue_list, false);
+        udev_queue->fd = -1;
         return udev_queue;
 }
 
@@ -90,6 +87,7 @@ _public_ struct udev_queue *udev_queue_ref(struct udev_queue *udev_queue)
 {
         if (udev_queue == NULL)
                 return NULL;
+
         udev_queue->refcount++;
         return udev_queue;
 }
@@ -101,16 +99,19 @@ _public_ struct udev_queue *udev_queue_ref(struct udev_queue *udev_queue)
  * Drop a reference of a udev queue context. If the refcount reaches zero,
  * the resources of the queue context will be released.
  *
- * Returns: the passed queue context if it has still an active reference, or #NULL otherwise.
+ * Returns: #NULL
  **/
 _public_ struct udev_queue *udev_queue_unref(struct udev_queue *udev_queue)
 {
         if (udev_queue == NULL)
                 return NULL;
+
         udev_queue->refcount--;
         if (udev_queue->refcount > 0)
-                return udev_queue;
-        udev_list_cleanup(&udev_queue->queue_list);
+                return NULL;
+
+        safe_close(udev_queue->fd);
+
         free(udev_queue);
         return NULL;
 }
@@ -130,141 +131,30 @@ _public_ struct udev *udev_queue_get_udev(struct udev_queue *udev_queue)
         return udev_queue->udev;
 }
 
-unsigned long long int udev_get_kernel_seqnum(struct udev *udev)
-{
-        unsigned long long int seqnum;
-        int fd;
-        char buf[32];
-        ssize_t len;
-
-        fd = open("/sys/kernel/uevent_seqnum", O_RDONLY|O_CLOEXEC);
-        if (fd < 0)
-                return 0;
-        len = read(fd, buf, sizeof(buf));
-        close(fd);
-        if (len <= 2)
-                return 0;
-        buf[len-1] = '\0';
-        seqnum = strtoull(buf, NULL, 10);
-        return seqnum;
-}
-
 /**
  * udev_queue_get_kernel_seqnum:
  * @udev_queue: udev queue context
  *
- * Get the current kernel event sequence number.
+ * This function is deprecated.
  *
- * Returns: the sequence number.
+ * Returns: 0.
  **/
 _public_ unsigned long long int udev_queue_get_kernel_seqnum(struct udev_queue *udev_queue)
 {
-        unsigned long long int seqnum;
-
-        if (udev_queue == NULL)
-                return -EINVAL;
-
-        seqnum = udev_get_kernel_seqnum(udev_queue->udev);
-        return seqnum;
-}
-
-int udev_queue_read_seqnum(FILE *queue_file, unsigned long long int *seqnum)
-{
-        if (fread(seqnum, sizeof(unsigned long long int), 1, queue_file) != 1)
-                return -1;
-
         return 0;
 }
 
-ssize_t udev_queue_skip_devpath(FILE *queue_file)
-{
-        unsigned short int len;
-
-        if (fread(&len, sizeof(unsigned short int), 1, queue_file) == 1) {
-                char *devpath = alloca(len);
-
-                /* use fread to skip, fseek might drop buffered data */
-                if (fread(devpath, 1, len, queue_file) == len)
-                        return len;
-        }
-
-        return -1;
-}
-
-ssize_t udev_queue_read_devpath(FILE *queue_file, char *devpath, size_t size)
-{
-        unsigned short int read_bytes = 0;
-        unsigned short int len;
-
-        if (fread(&len, sizeof(unsigned short int), 1, queue_file) != 1)
-                return -1;
-
-        read_bytes = (len < size - 1) ? len : size - 1;
-        if (fread(devpath, 1, read_bytes, queue_file) != read_bytes)
-                return -1;
-        devpath[read_bytes] = '\0';
-
-        /* if devpath was too long, skip unread characters */
-        if (read_bytes != len) {
-                unsigned short int skip_bytes = len - read_bytes;
-                char *buf = alloca(skip_bytes);
-
-                if (fread(buf, 1, skip_bytes, queue_file) != skip_bytes)
-                        return -1;
-        }
-
-        return read_bytes;
-}
-
-static FILE *open_queue_file(struct udev_queue *udev_queue, unsigned long long int *seqnum_start)
-{
-        FILE *queue_file;
-
-        queue_file = fopen("/run/udev/queue.bin", "re");
-        if (queue_file == NULL)
-                return NULL;
-
-        if (udev_queue_read_seqnum(queue_file, seqnum_start) < 0) {
-                udev_err(udev_queue->udev, "corrupt queue file\n");
-                fclose(queue_file);
-                return NULL;
-        }
-
-        return queue_file;
-}
-
 /**
  * udev_queue_get_udev_seqnum:
  * @udev_queue: udev queue context
  *
- * Get the last known udev event sequence number.
+ * This function is deprecated.
  *
- * Returns: the sequence number.
+ * Returns: 0.
  **/
 _public_ unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *udev_queue)
 {
-        unsigned long long int seqnum_udev;
-        FILE *queue_file;
-
-        queue_file = open_queue_file(udev_queue, &seqnum_udev);
-        if (queue_file == NULL)
-                return 0;
-
-        for (;;) {
-                unsigned long long int seqnum;
-                ssize_t devpath_len;
-
-                if (udev_queue_read_seqnum(queue_file, &seqnum) < 0)
-                        break;
-                devpath_len = udev_queue_skip_devpath(queue_file);
-                if (devpath_len < 0)
-                        break;
-                if (devpath_len > 0)
-                        seqnum_udev = seqnum;
-        }
-
-        fclose(queue_file);
-        return seqnum_udev;
+        return 0;
 }
 
 /**
@@ -277,15 +167,7 @@ _public_ unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *ud
  **/
 _public_ int udev_queue_get_udev_is_active(struct udev_queue *udev_queue)
 {
-        unsigned long long int seqnum_start;
-        FILE *queue_file;
-
-        queue_file = open_queue_file(udev_queue, &seqnum_start);
-        if (queue_file == NULL)
-                return 0;
-
-        fclose(queue_file);
-        return 1;
+        return access("/run/udev/control", F_OK) >= 0;
 }
 
 /**
@@ -298,48 +180,7 @@ _public_ int udev_queue_get_udev_is_active(struct udev_queue *udev_queue)
  **/
 _public_ int udev_queue_get_queue_is_empty(struct udev_queue *udev_queue)
 {
-        unsigned long long int seqnum_kernel;
-        unsigned long long int seqnum_udev = 0;
-        int queued = 0;
-        int is_empty = 0;
-        FILE *queue_file;
-
-        if (udev_queue == NULL)
-                return -EINVAL;
-        queue_file = open_queue_file(udev_queue, &seqnum_udev);
-        if (queue_file == NULL)
-                return 1;
-
-        for (;;) {
-                unsigned long long int seqnum;
-                ssize_t devpath_len;
-
-                if (udev_queue_read_seqnum(queue_file, &seqnum) < 0)
-                        break;
-                devpath_len = udev_queue_skip_devpath(queue_file);
-                if (devpath_len < 0)
-                        break;
-
-                if (devpath_len > 0) {
-                        queued++;
-                        seqnum_udev = seqnum;
-                } else {
-                        queued--;
-                }
-        }
-
-        if (queued > 0)
-                goto out;
-
-        seqnum_kernel = udev_queue_get_kernel_seqnum(udev_queue);
-        if (seqnum_udev < seqnum_kernel)
-                goto out;
-
-        is_empty = 1;
-
-out:
-        fclose(queue_file);
-        return is_empty;
+        return access("/run/udev/queue", F_OK) < 0;
 }
 
 /**
@@ -348,63 +189,15 @@ out:
  * @start: first event sequence number
  * @end: last event sequence number
  *
- * Check if udev is currently processing any events in a given sequence number range.
+ * This function is deprecated, it just returns the result of
+ * udev_queue_get_queue_is_empty().
  *
- * Returns: a flag indicating if any of the sequence numbers in the given range is currently active.
+ * Returns: a flag indicating if udev is currently handling events.
  **/
 _public_ 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;
-        ssize_t devpath_len;
-        int unfinished;
-        FILE *queue_file;
-
-        if (udev_queue == NULL)
-                return -EINVAL;
-        queue_file = open_queue_file(udev_queue, &seqnum);
-        if (queue_file == NULL)
-                return 1;
-        if (start < seqnum)
-                start = seqnum;
-        if (start > end) {
-                fclose(queue_file);
-                return 1;
-        }
-        if (end - start > INT_MAX - 1) {
-                fclose(queue_file);
-                return -EOVERFLOW;
-        }
-
-        /*
-         * we might start with 0, and handle the initial seqnum
-         * only when we find an entry in the queue file
-         **/
-        unfinished = end - start;
-
-        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);
+        return udev_queue_get_queue_is_empty(udev_queue);
 }
 
 /**
@@ -412,69 +205,69 @@ _public_ int udev_queue_get_seqnum_sequence_is_finished(struct udev_queue *udev_
  * @udev_queue: udev queue context
  * @seqnum: sequence number
  *
- * Check if udev is currently processing a given sequence number.
+ * This function is deprecated, it just returns the result of
+ * udev_queue_get_queue_is_empty().
  *
- * Returns: a flag indicating if the given sequence number is currently active.
+ * Returns: a flag indicating if udev is currently handling events.
  **/
 _public_ 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))
-                return 0;
-
-        return 1;
+        return udev_queue_get_queue_is_empty(udev_queue);
 }
 
 /**
  * udev_queue_get_queued_list_entry:
  * @udev_queue: udev queue context
  *
- * Get the first entry of the list of queued events.
+ * This function is deprecated.
  *
- * Returns: a udev_list_entry.
+ * Returns: NULL.
  **/
 _public_ struct udev_list_entry *udev_queue_get_queued_list_entry(struct udev_queue *udev_queue)
 {
-        unsigned long long int seqnum;
-        FILE *queue_file;
+        return NULL;
+}
 
-        if (udev_queue == NULL)
-                return NULL;
-        udev_list_cleanup(&udev_queue->queue_list);
+/**
+ * udev_queue_get_fd:
+ * @udev_queue: udev queue context
+ *
+ * Returns: a file descriptor to watch for a queue to become empty.
+ */
+_public_ int udev_queue_get_fd(struct udev_queue *udev_queue) {
+        int fd;
+        int r;
 
-        queue_file = open_queue_file(udev_queue, &seqnum);
-        if (queue_file == NULL)
-                return NULL;
+        if (udev_queue->fd >= 0)
+                return udev_queue->fd;
 
-        for (;;) {
-                char syspath[UTIL_PATH_SIZE];
-                char *s;
-                size_t l;
-                ssize_t len;
-                char seqnum_str[32];
-                struct udev_list_entry *list_entry;
-
-                if (udev_queue_read_seqnum(queue_file, &seqnum) < 0)
-                        break;
-                snprintf(seqnum_str, sizeof(seqnum_str), "%llu", seqnum);
-
-                s = syspath;
-                l = strpcpy(&s, sizeof(syspath), "/sys");
-                len = udev_queue_read_devpath(queue_file, s, l);
-                if (len < 0)
-                        break;
-
-                if (len > 0) {
-                        udev_list_entry_add(&udev_queue->queue_list, syspath, seqnum_str);
-                } else {
-                        udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_queue->queue_list)) {
-                                if (streq(seqnum_str, udev_list_entry_get_value(list_entry))) {
-                                        udev_list_entry_delete(list_entry);
-                                        break;
-                                }
-                        }
-                }
+        fd = inotify_init1(IN_CLOEXEC);
+        if (fd < 0)
+                return -errno;
+
+        r = inotify_add_watch(fd, "/run/udev" , IN_DELETE);
+        if (r < 0) {
+                r = -errno;
+                close(fd);
+                return r;
         }
-        fclose(queue_file);
 
-        return udev_list_get_entry(&udev_queue->queue_list);
+        udev_queue->fd = fd;
+        return fd;
 }
+
+/**
+ * udev_queue_flush:
+ * @udev_queue: udev queue context
+ *
+ * Returns: the result of clearing the watch for queue changes.
+ */
+_public_ int udev_queue_flush(struct udev_queue *udev_queue) {
+        if (udev_queue->fd < 0)
+                return -EINVAL;
+
+        return flush_fd(udev_queue->fd);
+}
+
+__asm__(".symver udev_queue_flush,udev_queue_flush@LIBUDEV_183");
+__asm__(".symver udev_queue_get_fd,udev_queue_get_fd@LIBUDEV_183");