X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=libudev%2Flibudev-enumerate.c;h=6870bb611598a3f752b67d2301624a4506c00869;hp=da831449dcaf5e936a14409e8e68ab12d30a98e2;hb=ff2c503df091e6e4e9ab48cdb6df6ec8b7b525d0;hpb=28460195c2ae90892bf556aff2b80705a8f37795 diff --git a/libudev/libudev-enumerate.c b/libudev/libudev-enumerate.c index da831449d..6870bb611 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; }; /** @@ -273,6 +274,8 @@ struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *ude /* skip to be delayed devices, and add them to the end of the list */ if (devices_delay_end(udev_enumerate->udev, entry->syspath)) { syspath_add(udev_enumerate, entry->syspath); + /* need to update prev here for the case realloc() gives a different address */ + prev = &udev_enumerate->devices[i]; continue; } @@ -456,6 +459,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 +630,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)) @@ -707,34 +751,24 @@ int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate) struct dirent *dent; char path[UTIL_PATH_SIZE]; - util_strscpyl(path, sizeof(path), udev_get_dev_path(udev), "/.udev/tags/", + util_strscpyl(path, sizeof(path), udev_get_run_path(udev), "/tags/", udev_list_entry_get_name(list_entry), NULL); dir = opendir(path); if (dir == NULL) continue; for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { struct udev_device *dev; - char syspath[UTIL_PATH_SIZE]; - char *s; - size_t l; - ssize_t len; if (dent->d_name[0] == '.') continue; - s = syspath; - l = util_strpcpyl(&s, sizeof(syspath), udev_get_sys_path(udev), NULL); - len = readlinkat(dirfd(dir), dent->d_name, s, l); - if (len <= 0 || (size_t)len == l) - continue; - s[len] = '\0'; - - dev = udev_device_new_from_syspath(udev_enumerate->udev, syspath); + dev = udev_device_new_from_id_filename(udev_enumerate->udev, dent->d_name); if (dev == NULL) continue; syspath_add(udev_enumerate, udev_device_get_syspath(dev)); udev_device_unref(dev); } + closedir(dir); } } else { util_strscpyl(base, sizeof(base), udev_get_sys_path(udev), "/subsystem", NULL);