From bc8184ede9cff156709fe053e3e02ef309cb2920 Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Sun, 28 Sep 2008 17:39:31 +0200 Subject: [PATCH] libudev: enumerate - accept list of subsystems to scan, or skip --- TODO | 11 ++-- udev/lib/exported_symbols | 3 ++ udev/lib/libudev-device.c | 16 ++++-- udev/lib/libudev-enumerate.c | 101 ++++++++++++++++++++++++++--------- udev/lib/libudev-list.c | 10 ++++ udev/lib/libudev.h | 5 +- udev/lib/test-libudev.c | 45 ++++++++++++---- udev/udevadm-info.c | 4 +- 8 files changed, 146 insertions(+), 49 deletions(-) diff --git a/TODO b/TODO index 01c41254..8d7858fb 100644 --- a/TODO +++ b/TODO @@ -1,13 +1,12 @@ - o enumerate() - add buses and drivers + o libudev enumerate + add buses and drivers + add /sys/block/ scanning crap use enumerate for "trigger" - - o add libudev interface for /dev/.udev/queue/ state + o libudev queue - interface for /dev/.udev/queue/ state use queue interface for "settle" - - o use libudev in udev_rules.c + o use libudev device in udev_rules.c get rid of udevice, store rule matching state in rule iterator o rework rules to a match-action list, instead of a rules array - o add DVB variables to kernel, and drop shell script rule o add watershed extra o log warning if the kernel uses CONFIG_SYSFS_DEPRECATED*=y, diff --git a/udev/lib/exported_symbols b/udev/lib/exported_symbols index 8c5f700d..1877f32e 100644 --- a/udev/lib/exported_symbols +++ b/udev/lib/exported_symbols @@ -10,6 +10,7 @@ udev_set_userdata udev_get_sys_path udev_get_dev_path udev_list_entry_get_next +udev_list_entry_get_by_name udev_list_entry_get_name udev_list_entry_get_value udev_device_new_from_syspath @@ -30,9 +31,11 @@ udev_device_get_driver udev_device_get_devnum udev_device_get_seqnum udev_device_get_attr_value +udev_enumerate_new_from_devices udev_enumerate_new_from_subsystems udev_enumerate_ref udev_enumerate_unref +udev_enumerate_get_udev udev_enumerate_get_list_entry udev_monitor_new_from_socket udev_monitor_new_from_netlink diff --git a/udev/lib/libudev-device.c b/udev/lib/libudev-device.c index a201fb25..3437d697 100644 --- a/udev/lib/libudev-device.c +++ b/udev/lib/libudev-device.c @@ -252,7 +252,7 @@ struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char * subdir = &syspath[len+1]; pos = strrchr(subdir, '/'); if (pos == NULL || pos < &subdir[2]) { - info(udev, "not in subdir :%s\n", syspath); + info(udev, "not a subdir :%s\n", syspath); return NULL; } @@ -312,8 +312,11 @@ struct udev_device *udev_device_new_from_devnum(struct udev *udev, char type, de if (util_resolve_sys_link(udev, path, sizeof(path)) == 0) return udev_device_new_from_syspath(udev, path); - /* fallback to search all sys devices for the major/minor */ - enumerate = udev_enumerate_new_from_subsystems(udev, NULL); + /* fallback to search sys devices for the major/minor */ + if (type == 'b') + enumerate = udev_enumerate_new_from_devices(udev, "block", NULL); + else if (type == 'c') + enumerate = udev_enumerate_new_from_devices(udev, "!block", NULL); if (enumerate == NULL) return NULL; udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(enumerate)) { @@ -322,6 +325,13 @@ struct udev_device *udev_device_new_from_devnum(struct udev *udev, char type, de device_loop = udev_device_new_from_syspath(udev, udev_list_entry_get_name(list_entry)); if (device_loop != NULL) { if (udev_device_get_devnum(device_loop) == devnum) { + const char *subsystem; + + subsystem = udev_device_get_subsystem(device_loop); + if (type == 'b' && strcmp(subsystem, "block") != 0) + continue; + if (type == 'c' && strcmp(subsystem, "block") == 0) + continue; device = device_loop; break; } diff --git a/udev/lib/libudev-enumerate.c b/udev/lib/libudev-enumerate.c index 8f5c5640..c7fb683c 100644 --- a/udev/lib/libudev-enumerate.c +++ b/udev/lib/libudev-enumerate.c @@ -54,6 +54,13 @@ void udev_enumerate_unref(struct udev_enumerate *udev_enumerate) free(udev_enumerate); } +struct udev *udev_enumerate_get_udev(struct udev_enumerate *udev_enumerate) +{ + if (udev_enumerate == NULL) + return NULL; + return udev_enumerate->udev; +} + struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *udev_enumerate) { if (udev_enumerate == NULL) @@ -63,7 +70,7 @@ struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *ude static int devices_scan_subsystem(struct udev *udev, const char *basedir, const char *subsystem, const char *subdir, - struct list_node *device_list) + struct list_node *devices_list) { char path[UTIL_PATH_SIZE]; DIR *dir; @@ -87,34 +94,44 @@ static int devices_scan_subsystem(struct udev *udev, util_strlcat(syspath, "/", sizeof(syspath)); util_strlcat(syspath, dent->d_name, sizeof(syspath)); util_resolve_sys_link(udev, syspath, sizeof(syspath)); - list_entry_add(udev, device_list, syspath, NULL, 1, 1); + list_entry_add(udev, devices_list, syspath, NULL, 1, 1); } closedir(dir); return 0; } static int devices_scan_subsystems(struct udev *udev, - const char *basedir, const char *subsystem, const char *subdir, - struct list_node *device_list) + const char *basedir, const char *subdir, + struct udev_list_entry *subsystem_include_list, + struct udev_list_entry *subsystem_exclude_list, + struct list_node *devices_list) { - char path[UTIL_PATH_SIZE]; - DIR *dir; - struct dirent *dent; - - if (subsystem != NULL) - return devices_scan_subsystem(udev, basedir, subsystem, subdir, device_list); + if (subsystem_include_list != NULL) { + struct udev_list_entry *list_entry; - util_strlcpy(path, udev_get_sys_path(udev), sizeof(path)); - util_strlcat(path, basedir, sizeof(path)); - dir = opendir(path); - if (dir == NULL) - return -1; - for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { - if (dent->d_name[0] == '.') - continue; - devices_scan_subsystem(udev, basedir, dent->d_name, subdir, device_list); + /* if list of subsystems to scan is given, just use this list */ + udev_list_entry_foreach(list_entry, subsystem_include_list) + devices_scan_subsystem(udev, basedir, udev_list_entry_get_name(list_entry), subdir, devices_list); + } else { + char path[UTIL_PATH_SIZE]; + DIR *dir; + struct dirent *dent; + + /* if no list of subsystems to scan is given, scan all, and possible exclude some subsystems */ + util_strlcpy(path, udev_get_sys_path(udev), sizeof(path)); + util_strlcat(path, basedir, sizeof(path)); + dir = opendir(path); + if (dir == NULL) + return -1; + for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { + if (dent->d_name[0] == '.') + continue; + if (udev_list_entry_get_by_name(subsystem_exclude_list, dent->d_name) != NULL) + continue; + devices_scan_subsystem(udev, basedir, dent->d_name, subdir, devices_list); + } + closedir(dir); } - closedir(dir); return 0; } @@ -140,17 +157,21 @@ static int devices_delay(struct udev *udev, const char *syspath) } /** - * udev_enumerate_new_from_subsystems: + * udev_enumerate_new_from_devices: * @udev: udev library context - * @subsystem: the subsystem to enumerate + * @subsystem: the list of names of subsystems to look for devices * * Returns: an enumeration context **/ -struct udev_enumerate *udev_enumerate_new_from_subsystems(struct udev *udev, const char *subsystem) +struct udev_enumerate *udev_enumerate_new_from_devices(struct udev *udev, const char *subsystem, ...) { struct udev_enumerate *udev_enumerate; + va_list vargs; + const char *arg; char base[UTIL_PATH_SIZE]; struct stat statbuf; + struct list_node subsystem_include_list; + struct list_node subsystem_exclude_list; struct udev_list_entry *list_entry; if (udev == NULL) @@ -164,19 +185,42 @@ struct udev_enumerate *udev_enumerate_new_from_subsystems(struct udev *udev, con udev_enumerate->udev = udev; list_init(&udev_enumerate->devices_list); + va_start(vargs, subsystem); + list_init(&subsystem_include_list); + list_init(&subsystem_exclude_list); + for (arg = subsystem; arg != NULL; arg = va_arg(vargs, const char *)) { + if (arg[0] != '!') + list_entry_add(udev, &subsystem_include_list, arg, NULL, 1, 0); + else + list_entry_add(udev, &subsystem_exclude_list, &arg[1], NULL, 1, 0); + } + va_end(vargs); + /* if we have /sys/subsystem/, forget all the old stuff */ util_strlcpy(base, udev_get_sys_path(udev), sizeof(base)); util_strlcat(base, "/subsystem", sizeof(base)); if (stat(base, &statbuf) == 0) { info(udev, "searching 'subsystem/*/devices/*' dir\n"); - devices_scan_subsystems(udev, "/subsystem", subsystem, "/devices", &udev_enumerate->devices_list); + devices_scan_subsystems(udev, "/subsystem", "/devices", + list_get_entry(&subsystem_include_list), + list_get_entry(&subsystem_exclude_list), + &udev_enumerate->devices_list); } else { info(udev, "searching 'bus/*/devices/*' dir\n"); - devices_scan_subsystems(udev, "/bus", subsystem, "/devices", &udev_enumerate->devices_list); + devices_scan_subsystems(udev, "/bus", "/devices", + list_get_entry(&subsystem_include_list), + list_get_entry(&subsystem_exclude_list), + &udev_enumerate->devices_list); info(udev, "searching 'class/*' dir\n"); - devices_scan_subsystems(udev, "/class", subsystem, NULL, &udev_enumerate->devices_list); + devices_scan_subsystems(udev, "/class", NULL, + list_get_entry(&subsystem_include_list), + list_get_entry(&subsystem_exclude_list), + &udev_enumerate->devices_list); } + list_cleanup(udev, &subsystem_include_list); + list_cleanup(udev, &subsystem_exclude_list); + /* sort delayed devices to the end of the list */ udev_list_entry_foreach(list_entry, list_get_entry(&udev_enumerate->devices_list)) { if (devices_delay(udev, udev_list_entry_get_name(list_entry))) @@ -184,3 +228,8 @@ struct udev_enumerate *udev_enumerate_new_from_subsystems(struct udev *udev, con } return udev_enumerate; } + +struct udev_enumerate *udev_enumerate_new_from_subsystems(struct udev *udev) +{ + return NULL; +} diff --git a/udev/lib/libudev-list.c b/udev/lib/libudev-list.c index 895c665e..00e3b7c3 100644 --- a/udev/lib/libudev-list.c +++ b/udev/lib/libudev-list.c @@ -192,6 +192,16 @@ struct udev_list_entry *udev_list_entry_get_next(struct udev_list_entry *list_en return list_node_to_entry(next); } +struct udev_list_entry *udev_list_entry_get_by_name(struct udev_list_entry *list_entry, const char *name) +{ + struct udev_list_entry *entry; + + udev_list_entry_foreach(entry, list_entry) + if (strcmp(udev_list_entry_get_name(entry), name) == 0) + return entry; + return NULL; +} + const char *udev_list_entry_get_name(struct udev_list_entry *list_entry) { if (list_entry == NULL) diff --git a/udev/lib/libudev.h b/udev/lib/libudev.h index 25b5f9c0..29c4a47e 100644 --- a/udev/lib/libudev.h +++ b/udev/lib/libudev.h @@ -52,6 +52,7 @@ extern void udev_selinux_lsetfilecon(struct udev *udev, const char *file, unsign /* list iteration */ struct udev_list_entry; extern struct udev_list_entry *udev_list_entry_get_next(struct udev_list_entry *list_entry); +extern struct udev_list_entry *udev_list_entry_get_by_name(struct udev_list_entry *list_entry, const char *name); extern const char *udev_list_entry_get_name(struct udev_list_entry *list_entry); extern const char *udev_list_entry_get_value(struct udev_list_entry *list_entry); #define udev_list_entry_foreach(entry, first) \ @@ -93,8 +94,10 @@ extern struct udev_device *udev_monitor_receive_device(struct udev_monitor *udev /* sys enumeration */ struct udev_enumerate; -extern struct udev_enumerate *udev_enumerate_new_from_subsystems(struct udev *udev, const char *subsystem); +extern struct udev_enumerate *udev_enumerate_new_from_devices(struct udev *udev, const char *subsystem, ...); +extern struct udev_enumerate *udev_enumerate_new_from_subsystems(struct udev *udev); extern struct udev_enumerate *udev_enumerate_ref(struct udev_enumerate *udev_enumerate); +extern struct udev *udev_enumerate_get_udev(struct udev_enumerate *udev_enumerate); extern void udev_enumerate_unref(struct udev_enumerate *udev_enumerate); extern struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *udev_enumerate); diff --git a/udev/lib/test-libudev.c b/udev/lib/test-libudev.c index bff55cfc..0f485248 100644 --- a/udev/lib/test-libudev.c +++ b/udev/lib/test-libudev.c @@ -157,20 +157,16 @@ static int test_device_devnum(struct udev *udev) return 0; } -static int test_enumerate(struct udev *udev, const char *subsystem) +static int test_enumerate_print_list(struct udev_enumerate *enumerate) { - struct udev_enumerate *enumerate; struct udev_list_entry *list_entry; int count = 0; - enumerate = udev_enumerate_new_from_subsystems(udev, NULL); - if (enumerate == NULL) - return -1; - list_entry = udev_enumerate_get_list_entry(enumerate); - while (list_entry != NULL) { + udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(enumerate)) { struct udev_device *device; - device = udev_device_new_from_syspath(udev, udev_list_entry_get_name(list_entry)); + device = udev_device_new_from_syspath(udev_enumerate_get_udev(enumerate), + udev_list_entry_get_name(list_entry)); if (device != NULL) { printf("device: '%s' (%s) '%s'\n", udev_device_get_syspath(device), @@ -179,9 +175,7 @@ static int test_enumerate(struct udev *udev, const char *subsystem) udev_device_unref(device); count++; } - list_entry = udev_list_entry_get_next(list_entry); } - udev_enumerate_unref(enumerate); printf("found %i devices\n\n", count); return count; } @@ -248,6 +242,7 @@ int main(int argc, char *argv[], char *envp[]) { "version", 0, NULL, 'V' }, {} }; + struct udev_enumerate *enumerate; const char *syspath = "/devices/virtual/mem/null"; const char *subsystem = NULL; const char *socket = "@/org/kernel/udev/monitor"; @@ -309,7 +304,35 @@ int main(int argc, char *argv[], char *envp[]) test_device(udev, syspath); test_device_devnum(udev); test_device_parents(udev, syspath); - test_enumerate(udev, subsystem); + + printf("enumerate '%s'\n", subsystem == NULL ? "" : subsystem); + enumerate = udev_enumerate_new_from_devices(udev, subsystem, NULL); + if (enumerate == NULL) + return -1; + test_enumerate_print_list(enumerate); + udev_enumerate_unref(enumerate); + + printf("enumerate 'block'\n"); + enumerate = udev_enumerate_new_from_devices(udev, "block", NULL); + if (enumerate == NULL) + return -1; + test_enumerate_print_list(enumerate); + udev_enumerate_unref(enumerate); + + printf("enumerate '!block'\n"); + enumerate = udev_enumerate_new_from_devices(udev, "!block", NULL); + if (enumerate == NULL) + return -1; + test_enumerate_print_list(enumerate); + udev_enumerate_unref(enumerate); + + printf("enumerate 'pci, mem, vc'\n"); + enumerate = udev_enumerate_new_from_devices(udev, "pci", "mem", "vc", NULL); + if (enumerate == NULL) + return -1; + test_enumerate_print_list(enumerate); + udev_enumerate_unref(enumerate); + test_monitor(udev, socket); out: udev_unref(udev); diff --git a/udev/udevadm-info.c b/udev/udevadm-info.c index f59c196e..e470ff62 100644 --- a/udev/udevadm-info.c +++ b/udev/udevadm-info.c @@ -186,7 +186,7 @@ static int export_devices(struct udev *udev) struct udev_enumerate *enumerate; struct udev_list_entry *list_entry; - enumerate = udev_enumerate_new_from_subsystems(udev, NULL); + enumerate = udev_enumerate_new_from_devices(udev, NULL); if (enumerate == NULL) return -1; udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(enumerate)) { @@ -301,7 +301,7 @@ int udevadm_info(struct udev *udev, int argc, char *argv[]) rc = 2; goto exit; } - /* add /sys if needed */ + /* add sys dir if needed */ if (strncmp(optarg, udev_get_sys_path(udev), strlen(udev_get_sys_path(udev))) != 0) { util_strlcpy(path, udev_get_sys_path(udev), sizeof(path)); util_strlcat(path, optarg, sizeof(path)); -- 2.39.5