From: Kay Sievers Date: Tue, 14 Dec 2010 13:18:32 +0000 (+0100) Subject: libudev: enumerate - allow to filter-out not-already-initialized devices X-Git-Tag: 174~283 X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=commitdiff_plain;h=48a0170b111b55e961be769d2cc4890511bcd991 libudev: enumerate - allow to filter-out not-already-initialized devices --- diff --git a/Makefile.am b/Makefile.am index 9fe4a3ac5..2e0edd0b1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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 diff --git a/libudev/docs/libudev-sections.txt b/libudev/docs/libudev-sections.txt index 63c0ee2e9..05647768f 100644 --- a/libudev/docs/libudev-sections.txt +++ b/libudev/docs/libudev-sections.txt @@ -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 diff --git a/libudev/exported_symbols b/libudev/exported_symbols index 935e361db..9e77fb1be 100644 --- a/libudev/exported_symbols +++ b/libudev/exported_symbols @@ -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 diff --git a/libudev/libudev-device-private.c b/libudev/libudev-device-private.c index 406d8704f..d1df45ee7 100644 --- a/libudev/libudev-device-private.c +++ b/libudev/libudev-device-private.c @@ -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; } diff --git a/libudev/libudev-device.c b/libudev/libudev-device.c index 8b0cccd53..66f806316 100644 --- a/libudev/libudev-device.c +++ b/libudev/libudev-device.c @@ -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) diff --git a/libudev/libudev-enumerate.c b/libudev/libudev-enumerate.c index 363d445f9..e46bc087f 100644 --- a/libudev/libudev-enumerate.c +++ b/libudev/libudev-enumerate.c @@ -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)) diff --git a/libudev/libudev-private.h b/libudev/libudev-private.h index 2b638ce06..f7b4f9051 100644 --- a/libudev/libudev-private.h +++ b/libudev/libudev-private.h @@ -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); diff --git a/libudev/libudev.h b/libudev/libudev.h index 5bc42df5b..087991caf 100644 --- a/libudev/libudev.h +++ b/libudev/libudev.h @@ -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); diff --git a/libudev/test-libudev.c b/libudev/test-libudev.c index 3eb34494d..f8eb8e5d5 100644 --- a/libudev/test-libudev.c +++ b/libudev/test-libudev.c @@ -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); diff --git a/udev/udev-event.c b/udev/udev-event.c index 02a1767b1..4d38c5b89 100644 --- a/udev/udev-event.c +++ b/udev/udev-event.c @@ -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; }