chiark / gitweb /
build-sys: re-add old symbols for abi compat
[elogind.git] / src / libudev / libudev-queue.c
index ca230023072065cb9c1c837fff01ce60c080eb35..ae0b415e368d9f6a31894e7a75018f028935d289 100644 (file)
@@ -1,14 +1,22 @@
-/*
- * libudev - interface to udev device information
- *
- * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org>
- * Copyright (C) 2009 Alan Jenkins <alan-jenkins@tuffmail.co.uk>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- */
+/***
+  This file is part of systemd.
+
+  Copyright 2008-2012 Kay Sievers <kay@vrfy.org>
+  Copyright 2009 Alan Jenkins <alan-jenkins@tuffmail.co.uk>
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
 
 #include <stdio.h>
 #include <stdlib.h>
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <errno.h>
 #include <string.h>
 #include <unistd.h>
 #include <errno.h>
 #include <string.h>
-#include <dirent.h>
-#include <fcntl.h>
 #include <limits.h>
 #include <sys/stat.h>
 #include <limits.h>
 #include <sys/stat.h>
+#include <sys/inotify.h>
 
 #include "libudev.h"
 #include "libudev-private.h"
 
 #include "libudev.h"
 #include "libudev-private.h"
  * SECTION:libudev-queue
  * @short_description: access to currently active events
  *
  * 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.
  */
 
 /**
  */
 
 /**
@@ -42,7 +46,7 @@
 struct udev_queue {
         struct udev *udev;
         int refcount;
 struct udev_queue {
         struct udev *udev;
         int refcount;
-        struct udev_list queue_list;
+        int fd;
 };
 
 /**
 };
 
 /**
@@ -61,12 +65,13 @@ _public_ struct udev_queue *udev_queue_new(struct udev *udev)
         if (udev == NULL)
                 return NULL;
 
         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;
         if (udev_queue == NULL)
                 return NULL;
+
         udev_queue->refcount = 1;
         udev_queue->udev = udev;
         udev_queue->refcount = 1;
         udev_queue->udev = udev;
-        udev_list_init(udev, &udev_queue->queue_list, false);
+        udev_queue->fd = -1;
         return udev_queue;
 }
 
         return udev_queue;
 }
 
@@ -82,6 +87,7 @@ _public_ struct udev_queue *udev_queue_ref(struct udev_queue *udev_queue)
 {
         if (udev_queue == NULL)
                 return NULL;
 {
         if (udev_queue == NULL)
                 return NULL;
+
         udev_queue->refcount++;
         return udev_queue;
 }
         udev_queue->refcount++;
         return udev_queue;
 }
@@ -92,16 +98,22 @@ _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.
  *
  * Drop a reference of a udev queue context. If the refcount reaches zero,
  * the resources of the queue context will be released.
+ *
+ * Returns: #NULL
  **/
  **/
-_public_ void udev_queue_unref(struct udev_queue *udev_queue)
+_public_ struct udev_queue *udev_queue_unref(struct udev_queue *udev_queue)
 {
         if (udev_queue == NULL)
 {
         if (udev_queue == NULL)
-                return;
+                return NULL;
+
         udev_queue->refcount--;
         if (udev_queue->refcount > 0)
         udev_queue->refcount--;
         if (udev_queue->refcount > 0)
-                return;
-        udev_list_cleanup(&udev_queue->queue_list);
+                return NULL;
+
+        safe_close(udev_queue->fd);
+
         free(udev_queue);
         free(udev_queue);
+        return NULL;
 }
 
 /**
 }
 
 /**
@@ -119,210 +131,56 @@ _public_ struct udev *udev_queue_get_udev(struct udev_queue *udev_queue)
         return udev_queue->udev;
 }
 
         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
  *
 /**
  * udev_queue_get_kernel_seqnum:
  * @udev_queue: udev queue context
  *
- * Returns: the current kernel event sequence number.
+ * This function is deprecated.
+ *
+ * Returns: 0.
  **/
 _public_ unsigned long long int udev_queue_get_kernel_seqnum(struct udev_queue *udev_queue)
 {
  **/
 _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;
 }
 
         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)
-{
-        char filename[UTIL_PATH_SIZE];
-        FILE *queue_file;
-
-        util_strscpyl(filename, sizeof(filename), "/run/udev/queue.bin", NULL);
-        queue_file = fopen(filename, "re");
-        if (queue_file == NULL)
-                return NULL;
-
-        if (udev_queue_read_seqnum(queue_file, seqnum_start) < 0) {
-                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
  *
 /**
  * udev_queue_get_udev_seqnum:
  * @udev_queue: udev queue context
  *
- * Returns: the last known udev event sequence number.
+ * This function is deprecated.
+ *
+ * Returns: 0.
  **/
 _public_ unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *udev_queue)
 {
  **/
 _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;
 }
 
 /**
  * udev_queue_get_udev_is_active:
  * @udev_queue: udev queue context
  *
 }
 
 /**
  * udev_queue_get_udev_is_active:
  * @udev_queue: udev queue context
  *
+ * Check if udev is active on the system.
+ *
  * Returns: a flag indicating if udev is active.
  **/
 _public_ int udev_queue_get_udev_is_active(struct udev_queue *udev_queue)
 {
  * Returns: a flag indicating if udev is active.
  **/
 _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;
 }
 
 /**
  * udev_queue_get_queue_is_empty:
  * @udev_queue: udev queue context
  *
 }
 
 /**
  * udev_queue_get_queue_is_empty:
  * @udev_queue: udev queue context
  *
+ * Check if udev is currently processing any events.
+ *
  * Returns: a flag indicating if udev is currently handling events.
  **/
 _public_ int udev_queue_get_queue_is_empty(struct udev_queue *udev_queue)
 {
  * Returns: a flag indicating if udev is currently handling events.
  **/
 _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;
 }
 
 /**
 }
 
 /**
@@ -331,61 +189,15 @@ out:
  * @start: first event sequence number
  * @end: last event sequence number
  *
  * @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.
+ * This function is deprecated, it just returns the result of
+ * udev_queue_get_queue_is_empty().
+ *
+ * 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)
 {
  **/
 _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);
 }
 
 /**
 }
 
 /**
@@ -393,73 +205,69 @@ _public_ int udev_queue_get_seqnum_sequence_is_finished(struct udev_queue *udev_
  * @udev_queue: udev queue context
  * @seqnum: sequence number
  *
  * @udev_queue: udev queue context
  * @seqnum: sequence number
  *
- * Returns: a flag indicating if the given sequence number is currently active.
+ * This function is deprecated, it just returns the result of
+ * udev_queue_get_queue_is_empty().
+ *
+ * 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)
 {
  **/
 _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
  *
 }
 
 /**
  * udev_queue_get_queued_list_entry:
  * @udev_queue: udev queue context
  *
- * Returns: the first entry of the list of queued events.
+ * This function is deprecated.
+ *
+ * Returns: NULL.
  **/
 _public_ struct udev_list_entry *udev_queue_get_queued_list_entry(struct udev_queue *udev_queue)
 {
  **/
 _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;
+
+        fd = inotify_init1(IN_CLOEXEC);
+        if (fd < 0)
+                return -errno;
 
 
-        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 = util_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 (strcmp(seqnum_str, udev_list_entry_get_value(list_entry)) == 0) {
-                                        udev_list_entry_delete(list_entry);
-                                        break;
-                                }
-                        }
-                }
+        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;
 }
 
 }
 
-struct udev_list_entry *udev_queue_get_failed_list_entry(struct udev_queue *udev_queue);
-_public_ struct udev_list_entry *udev_queue_get_failed_list_entry(struct udev_queue *udev_queue)
-{
-        err(udev_queue->udev, "udev_queue_get_failed_list_entry() does not return anything; failed events are not recorded\n");
-        errno = ENOSYS;
-        return NULL;
+/**
+ * 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");