chiark / gitweb /
libudev: enumerate - allow to filter-out not-already-initialized devices
authorKay Sievers <kay.sievers@vrfy.org>
Tue, 14 Dec 2010 13:18:32 +0000 (14:18 +0100)
committerKay Sievers <kay.sievers@vrfy.org>
Tue, 14 Dec 2010 13:18:32 +0000 (14:18 +0100)
Makefile.am
libudev/docs/libudev-sections.txt
libudev/exported_symbols
libudev/libudev-device-private.c
libudev/libudev-device.c
libudev/libudev-enumerate.c
libudev/libudev-private.h
libudev/libudev.h
libudev/test-libudev.c
udev/udev-event.c

index 9fe4a3ac51282b07942e07f41686f0002f0a43e3..2e0edd0b14409d286fad0050a2c787826a70abb9 100644 (file)
@@ -34,9 +34,9 @@ DISTCHECK_HOOKS =
 # ------------------------------------------------------------------------------
 # libudev
 # ------------------------------------------------------------------------------
-LIBUDEV_CURRENT=9
-LIBUDEV_REVISION=4
-LIBUDEV_AGE=9
+LIBUDEV_CURRENT=10
+LIBUDEV_REVISION=0
+LIBUDEV_AGE=10
 
 SUBDIRS += libudev/docs
 
index 63c0ee2e98d270fb856e3dafc45c49a11302c4a9..05647768fbd596d071e9f0990d2aa78028a86bf0 100644 (file)
@@ -45,6 +45,7 @@ udev_device_get_syspath
 udev_device_get_sysname
 udev_device_get_sysnum
 udev_device_get_devnode
+udev_device_get_is_initialized
 udev_device_get_devlinks_list_entry
 udev_device_get_properties_list_entry
 udev_device_get_tags_list_entry
@@ -89,6 +90,7 @@ udev_enumerate_add_match_sysattr
 udev_enumerate_add_nomatch_sysattr
 udev_enumerate_add_match_property
 udev_enumerate_add_match_tag
+udev_enumerate_add_match_is_initialized
 udev_enumerate_add_match_sysname
 udev_enumerate_add_syspath
 udev_enumerate_scan_devices
index 935e361db533c197c6df05ca043f72b589dfe927..9e77fb1be10ae8a936be220d88f5461d979ce0f4 100644 (file)
@@ -28,6 +28,7 @@ udev_device_get_sysname
 udev_device_get_sysnum
 udev_device_get_subsystem
 udev_device_get_devtype
+udev_device_get_is_initialized
 udev_device_get_devlinks_list_entry
 udev_device_get_properties_list_entry
 udev_device_get_tags_list_entry
@@ -48,6 +49,7 @@ udev_enumerate_add_match_sysattr
 udev_enumerate_add_nomatch_sysattr
 udev_enumerate_add_match_property
 udev_enumerate_add_match_tag
+udev_enumerate_add_match_is_initialized
 udev_enumerate_add_match_sysname
 udev_enumerate_scan_devices
 udev_enumerate_scan_subsystems
index 406d8704f54e465f2d761cdce06e5f54d1a2b76f..d1df45ee742506a4a8d74d1158999db7237a62d9 100644 (file)
@@ -114,7 +114,9 @@ int udev_device_update_db(struct udev_device *udev_device)
        util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev), "/.udev/db/", id, NULL);
 
        /* do not store anything for otherwise empty devices */
-       if (!has_info && udev_device_get_devnode(udev_device) == NULL) {
+       if (!has_info &&
+           major(udev_device_get_devnum(udev_device)) == 0 &&
+           udev_device_get_ifindex(udev_device) == 0) {
                unlink(filename);
                return 0;
        }
index 8b0cccd533f01a76ff7ae5108c12691c999f9f34..66f806316f55d75143f4d7a2e2242f99bcad805b 100644 (file)
@@ -81,6 +81,7 @@ struct udev_device {
        bool info_loaded;
        bool db_loaded;
        bool uevent_loaded;
+       bool is_initialized;
 };
 
 struct udev_list_entry *udev_device_add_property(struct udev_device *udev_device, const char *key, const char *value)
@@ -249,6 +250,7 @@ int udev_device_read_db(struct udev_device *udev_device)
                info(udev_device->udev, "no db file to read %s: %m\n", filename);
                return -1;
        }
+       udev_device->is_initialized = true;
 
        while (fgets(line, sizeof(line), f)) {
                ssize_t len;
@@ -1308,6 +1310,31 @@ const char *udev_device_get_id_filename(struct udev_device *udev_device)
        return udev_device->id_filename;
 }
 
+/**
+ * udev_device_get_is_initialized:
+ * @udev_device: udev device
+ *
+ * Check if udev has already handled the device and has set up
+ * device node permissions and context, or has renamed a network
+ * device.
+ *
+ * For now, this is only implemented for devices with a device node
+ * or network interfaces. All other devices return 1 here.
+ *
+ * Returns: 1 if the device is set up. 0 otherwise.
+ **/
+int udev_device_get_is_initialized(struct udev_device *udev_device)
+{
+       if (!udev_device->info_loaded)
+               udev_device_read_db(udev_device);
+       return udev_device->is_initialized;
+}
+
+void udev_device_set_is_initialized(struct udev_device *udev_device)
+{
+       udev_device->is_initialized = true;
+}
+
 int udev_device_add_tag(struct udev_device *udev_device, const char *tag)
 {
        if (strchr(tag, ':') != NULL || strchr(tag, ' ') != NULL)
index 363d445f90a5f63a569cf4d1d15378456b119180..e46bc087fa31879573a3107f189be62b6191d9d5 100644 (file)
@@ -57,6 +57,7 @@ struct udev_enumerate {
        unsigned int devices_cur;
        unsigned int devices_max;
        bool devices_uptodate:1;
+       bool match_is_initialized;
 };
 
 /**
@@ -456,6 +457,32 @@ int udev_enumerate_add_match_tag(struct udev_enumerate *udev_enumerate, const ch
        return 0;
 }
 
+/**
+ * udev_enumerate_add_match_is_initialized:
+ * @udev_enumerate: context
+ *
+ * Match only devices which udev has set up already. This makes
+ * sure, that the device node permissions and context are properly set
+ * and that network devices are fully renamed.
+ *
+ * Usually, devices which are found in the kernel but not already
+ * handled by udev, have still pending events. Services should subscribe
+ * to monitor events and wait for these devices to become ready, instead
+ * of using uninitialized devices.
+ *
+ * For now, this will not affect devices which do not have a device node
+ * and are not network interfaces.
+ *
+ * Returns: 0 on success, otherwise a negative error value.
+ */
+int udev_enumerate_add_match_is_initialized(struct udev_enumerate *udev_enumerate)
+{
+       if (udev_enumerate == NULL)
+               return -EINVAL;
+       udev_enumerate->match_is_initialized = true;
+       return 0;
+}
+
 /**
  * udev_enumerate_add_match_sysname:
  * @udev_enumerate: context
@@ -601,6 +628,21 @@ static int scan_dir_and_add_devices(struct udev_enumerate *udev_enumerate,
                if (dev == NULL)
                        continue;
 
+               if (udev_enumerate->match_is_initialized) {
+                       /*
+                        * All devices with a device node or network interfaces
+                        * possibly need udev to adjust the device node permission
+                        * or context, or rename the interface before it can be
+                        * reliably used from other processes.
+                        *
+                        * For now, we can only check these types of devices, we
+                        * might not store a database, and have no way to find out
+                        * for all other types of devices.
+                        */
+                       if (!udev_device_get_is_initialized(dev) &&
+                           (major(udev_device_get_devnum(dev)) > 0 || udev_device_get_ifindex(dev) > 0))
+                               goto nomatch;
+               }
                if (!match_tag(udev_enumerate, dev))
                        goto nomatch;
                if (!match_property(udev_enumerate, dev))
index 2b638ce06eb3d4baeca17932ea6a0193268cf201..f7b4f90519ce4a352cbe861fc9084ea557f49522 100644 (file)
@@ -87,6 +87,7 @@ const char *udev_device_get_sysname_old(struct udev_device *udev_device);
 int udev_device_set_devpath_old(struct udev_device *udev_device, const char *devpath_old);
 const char *udev_device_get_knodename(struct udev_device *udev_device);
 const char *udev_device_get_id_filename(struct udev_device *udev_device);
+void udev_device_set_is_initialized(struct udev_device *udev_device);
 int udev_device_add_tag(struct udev_device *udev_device, const char *tag);
 void udev_device_cleanup_tags_list(struct udev_device *udev_device);
 int udev_device_has_tag(struct udev_device *udev_device, const char *tag);
index 5bc42df5bea7427d479f21d9a43785fc22f55385..087991caf46144cb8c5e6ce69ae30dd7ad15d38b 100644 (file)
@@ -88,6 +88,7 @@ const char *udev_device_get_syspath(struct udev_device *udev_device);
 const char *udev_device_get_sysname(struct udev_device *udev_device);
 const char *udev_device_get_sysnum(struct udev_device *udev_device);
 const char *udev_device_get_devnode(struct udev_device *udev_device);
+int udev_device_get_is_initialized(struct udev_device *udev_device);
 struct udev_list_entry *udev_device_get_devlinks_list_entry(struct udev_device *udev_device);
 struct udev_list_entry *udev_device_get_properties_list_entry(struct udev_device *udev_device);
 struct udev_list_entry *udev_device_get_tags_list_entry(struct udev_device *udev_device);
@@ -141,6 +142,7 @@ int udev_enumerate_add_nomatch_sysattr(struct udev_enumerate *udev_enumerate, co
 int udev_enumerate_add_match_property(struct udev_enumerate *udev_enumerate, const char *property, const char *value);
 int udev_enumerate_add_match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname);
 int udev_enumerate_add_match_tag(struct udev_enumerate *udev_enumerate, const char *tag);
+int udev_enumerate_add_match_is_initialized(struct udev_enumerate *udev_enumerate);
 int udev_enumerate_add_syspath(struct udev_enumerate *udev_enumerate, const char *syspath);
 /* run enumeration with active filters */
 int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate);
index 3eb34494df8a8bcf2d1d57a687e0b9079fed3e93..f8eb8e5d5ac3f9a87eaa7a8373849b9452ecee1e 100644 (file)
@@ -354,6 +354,7 @@ static int test_enumerate(struct udev *udev, const char *subsystem)
        if (udev_enumerate == NULL)
                return -1;
        udev_enumerate_add_match_subsystem(udev_enumerate,"block");
+       udev_enumerate_add_match_is_initialized(udev_enumerate);
        udev_enumerate_scan_devices(udev_enumerate);
        test_enumerate_print_list(udev_enumerate);
        udev_enumerate_unref(udev_enumerate);
index 02a1767b1f8d7bd78c5d66af37344d3f66bc571e..4d38c5b893effab649237417b044f8e17c6b1c76 100644 (file)
@@ -631,12 +631,7 @@ int udev_event_execute_rules(struct udev_event *event, struct udev_rules *rules)
                        /* set device node name */
                        util_strscpyl(filename, sizeof(filename), udev_get_dev_path(event->udev), "/", event->name, NULL);
                        udev_device_set_devnode(dev, filename);
-               }
-
-               udev_device_update_db(dev);
-               udev_device_tag_index(dev, event->dev_db, true);
 
-               if (major(udev_device_get_devnum(dev)) != 0) {
                        /* remove/update possible left-over symlinks from old database entry */
                        if (event->dev_db != NULL)
                                udev_node_update_old_links(dev, event->dev_db);
@@ -648,6 +643,10 @@ int udev_event_execute_rules(struct udev_event *event, struct udev_rules *rules)
                        err = udev_node_add(dev, event->mode, event->uid, event->gid);
                }
 
+               udev_device_update_db(dev);
+               udev_device_tag_index(dev, event->dev_db, true);
+               udev_device_set_is_initialized(dev);
+
                udev_device_unref(event->dev_db);
                event->dev_db = NULL;
        }