X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=udev%2Fudevadm-trigger.c;h=5cd4acd6ed0be944e19b03b34cd1aaaa30d87af5;hp=322040582e75506c5e91a91f09b43e9d39ce56af;hb=b02140b6bcd080c5fd60306a493447ce7afdad64;hpb=32bf83996b1f7d7df83f99e6bf063685146ffe06 diff --git a/udev/udevadm-trigger.c b/udev/udevadm-trigger.c index 322040582..5cd4acd6e 100644 --- a/udev/udevadm-trigger.c +++ b/udev/udevadm-trigger.c @@ -1,20 +1,18 @@ /* - * Copyright (C) 2004-2006 Kay Sievers - * Copyright (C) 2006 Hannes Reinecke + * Copyright (C) 2008-2009 Kay Sievers * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation version 2 of the License. - * - * This program 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 - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ #include @@ -34,563 +32,102 @@ #include #include "udev.h" -#include "udevd.h" -#include "udev_rules.h" static int verbose; static int dry_run; -LIST_HEAD(device_list); -LIST_HEAD(filter_subsystem_match_list); -LIST_HEAD(filter_subsystem_nomatch_list); -LIST_HEAD(filter_attr_match_list); -LIST_HEAD(filter_attr_nomatch_list); -static int sock = -1; -static struct sockaddr_un saddr; -static socklen_t saddrlen; -/* devices that should run last cause of their dependencies */ -static int delay_device(const char *devpath) +static void exec_list(struct udev_enumerate *udev_enumerate, const char *action) { - static const char *delay_device_list[] = { - "*/md*", - "*/dm-*", - NULL - }; - int i; - - for (i = 0; delay_device_list[i] != NULL; i++) - if (fnmatch(delay_device_list[i], devpath, 0) == 0) - return 1; - return 0; -} - -static int device_list_insert(const char *path) -{ - char filename[PATH_SIZE]; - char devpath[PATH_SIZE]; - struct stat statbuf; - - dbg("add '%s'\n" , path); - - /* we only have a device, if we have an uevent file */ - strlcpy(filename, path, sizeof(filename)); - strlcat(filename, "/uevent", sizeof(filename)); - if (stat(filename, &statbuf) < 0) - return -1; - if (!(statbuf.st_mode & S_IWUSR)) - return -1; - - strlcpy(devpath, &path[strlen(sysfs_path)], sizeof(devpath)); - - /* resolve possible link to real target */ - if (lstat(path, &statbuf) < 0) - return -1; - if (S_ISLNK(statbuf.st_mode)) - if (sysfs_resolve_link(devpath, sizeof(devpath)) != 0) - return -1; - - name_list_add(&device_list, devpath, 1); - return 0; -} - -static void trigger_uevent(const char *devpath, const char *action) -{ - char filename[PATH_SIZE]; - int fd; - - strlcpy(filename, sysfs_path, sizeof(filename)); - strlcat(filename, devpath, sizeof(filename)); - strlcat(filename, "/uevent", sizeof(filename)); - - if (verbose) - printf("%s\n", devpath); + struct udev *udev = udev_enumerate_get_udev(udev_enumerate); + struct udev_list_entry *entry; - if (dry_run) - return; - - fd = open(filename, O_WRONLY); - if (fd < 0) { - dbg("error on opening %s: %s\n", filename, strerror(errno)); - return; - } - - if (write(fd, action, strlen(action)) < 0) - info("error writing '%s' to '%s': %s\n", action, filename, strerror(errno)); - - close(fd); -} - -static int pass_to_socket(const char *devpath, const char *action, const char *env) -{ - struct udevice *udev; - struct name_entry *name_loop; - char buf[4096]; - size_t bufpos = 0; - ssize_t count; - char path[PATH_SIZE]; - int fd; - char link_target[PATH_SIZE]; - int len; - int err = 0; - - if (verbose) - printf("%s\n", devpath); - - udev = udev_device_init(); - if (udev == NULL) - return -1; - udev_db_get_device(udev, devpath); - - /* add header */ - bufpos = snprintf(buf, sizeof(buf)-1, "%s@%s", action, devpath); - bufpos++; - - /* add cookie */ - if (env != NULL) { - bufpos += snprintf(&buf[bufpos], sizeof(buf)-1, "%s", env); - bufpos++; - } - - /* add standard keys */ - bufpos += snprintf(&buf[bufpos], sizeof(buf)-1, "DEVPATH=%s", devpath); - bufpos++; - bufpos += snprintf(&buf[bufpos], sizeof(buf)-1, "ACTION=%s", action); - bufpos++; - - /* add subsystem */ - strlcpy(path, sysfs_path, sizeof(path)); - strlcat(path, devpath, sizeof(path)); - strlcat(path, "/subsystem", sizeof(path)); - len = readlink(path, link_target, sizeof(link_target)); - if (len > 0) { - char *pos; + udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(udev_enumerate)) { + char filename[UTIL_PATH_SIZE]; + int fd; - link_target[len] = '\0'; - pos = strrchr(link_target, '/'); - if (pos != NULL) { - bufpos += snprintf(&buf[bufpos], sizeof(buf)-1, "SUBSYSTEM=%s", &pos[1]); - bufpos++; + if (verbose) + printf("%s\n", udev_list_entry_get_name(entry)); + if (dry_run) + continue; + util_strscpyl(filename, sizeof(filename), udev_list_entry_get_name(entry), "/uevent", NULL); + fd = open(filename, O_WRONLY); + if (fd < 0) { + dbg(udev, "error on opening %s: %m\n", filename); + continue; } - } - - /* add symlinks and node name */ - path[0] = '\0'; - list_for_each_entry(name_loop, &udev->symlink_list, node) { - strlcat(path, udev_root, sizeof(path)); - strlcat(path, "/", sizeof(path)); - strlcat(path, name_loop->name, sizeof(path)); - strlcat(path, " ", sizeof(path)); - } - remove_trailing_chars(path, ' '); - if (path[0] != '\0') { - bufpos += snprintf(&buf[bufpos], sizeof(buf)-1, "DEVLINKS=%s", path); - bufpos++; - } - if (udev->name[0] != '\0') { - strlcpy(path, udev_root, sizeof(path)); - strlcat(path, "/", sizeof(path)); - strlcat(path, udev->name, sizeof(path)); - bufpos += snprintf(&buf[bufpos], sizeof(buf)-1, "DEVNAME=%s", path); - bufpos++; - } - - /* add keys from device "uevent" file */ - strlcpy(path, sysfs_path, sizeof(path)); - strlcat(path, devpath, sizeof(path)); - strlcat(path, "/uevent", sizeof(path)); - fd = open(path, O_RDONLY); - if (fd >= 0) { - char value[4096]; - - count = read(fd, value, sizeof(value)); + if (write(fd, action, strlen(action)) < 0) + info(udev, "error writing '%s' to '%s': %m\n", action, filename); close(fd); - if (count > 0) { - char *key; - - value[count] = '\0'; - key = value; - while (key[0] != '\0') { - char *next; - - next = strchr(key, '\n'); - if (next == NULL) - break; - next[0] = '\0'; - bufpos += strlcpy(&buf[bufpos], key, sizeof(buf) - bufpos-1); - bufpos++; - key = &next[1]; - } - } - } - - /* add keys from database */ - list_for_each_entry(name_loop, &udev->env_list, node) { - bufpos += strlcpy(&buf[bufpos], name_loop->name, sizeof(buf) - bufpos-1); - bufpos++; - } - if (bufpos > sizeof(buf)) - bufpos = sizeof(buf); - - count = sendto(sock, &buf, bufpos, 0, (struct sockaddr *)&saddr, saddrlen); - if (count < 0) - err = -1; - - return err; -} - -static void exec_list(const char *action, const char *env) -{ - struct name_entry *loop_device; - struct name_entry *tmp_device; - - list_for_each_entry_safe(loop_device, tmp_device, &device_list, node) { - if (delay_device(loop_device->name)) - continue; - if (sock >= 0) - pass_to_socket(loop_device->name, action, env); - else - trigger_uevent(loop_device->name, action); - list_del(&loop_device->node); - free(loop_device); - } - - /* trigger remaining delayed devices */ - list_for_each_entry_safe(loop_device, tmp_device, &device_list, node) { - if (sock >= 0) - pass_to_socket(loop_device->name, action, env); - else - trigger_uevent(loop_device->name, action); - list_del(&loop_device->node); - free(loop_device); } } -static int subsystem_filtered(const char *subsystem) +static int scan_failed(struct udev_enumerate *udev_enumerate) { - struct name_entry *loop_name; + struct udev *udev = udev_enumerate_get_udev(udev_enumerate); + struct udev_queue *udev_queue; + struct udev_list_entry *list_entry; - /* skip devices matching the listed subsystems */ - list_for_each_entry(loop_name, &filter_subsystem_nomatch_list, node) - if (fnmatch(loop_name->name, subsystem, 0) == 0) - return 1; - - /* skip devices not matching the listed subsystems */ - if (!list_empty(&filter_subsystem_match_list)) { - list_for_each_entry(loop_name, &filter_subsystem_match_list, node) - if (fnmatch(loop_name->name, subsystem, 0) == 0) - return 0; - return 1; - } - - return 0; -} - -static int attr_match(const char *path, const char *attr_value) -{ - char attr[NAME_SIZE]; - char file[PATH_SIZE]; - char *match_value; - - strlcpy(attr, attr_value, sizeof(attr)); - - /* separate attr and match value */ - match_value = strchr(attr, '='); - if (match_value != NULL) { - match_value[0] = '\0'; - match_value = &match_value[1]; - } - - strlcpy(file, path, sizeof(file)); - strlcat(file, "/", sizeof(file)); - strlcat(file, attr, sizeof(file)); - - if (match_value != NULL) { - /* match file content */ - char value[NAME_SIZE]; - int fd; - ssize_t size; - - fd = open(file, O_RDONLY); - if (fd < 0) - return 0; - size = read(fd, value, sizeof(value)); - close(fd); - if (size < 0) - return 0; - value[size] = '\0'; - remove_trailing_chars(value, '\n'); - - /* match if attribute value matches */ - if (fnmatch(match_value, value, 0) == 0) - return 1; - } else { - /* match if attribute exists */ - struct stat statbuf; - - if (stat(file, &statbuf) == 0) - return 1; - } - return 0; -} - -static int attr_filtered(const char *path) -{ - struct name_entry *loop_name; - - /* skip devices matching the listed sysfs attributes */ - list_for_each_entry(loop_name, &filter_attr_nomatch_list, node) - if (attr_match(path, loop_name->name)) - return 1; - - /* skip devices not matching the listed sysfs attributes */ - if (!list_empty(&filter_attr_match_list)) { - list_for_each_entry(loop_name, &filter_attr_match_list, node) - if (attr_match(path, loop_name->name)) - return 0; - return 1; - } + udev_queue = udev_queue_new(udev); + if (udev_queue == NULL) + return -1; + udev_list_entry_foreach(list_entry, udev_queue_get_failed_list_entry(udev_queue)) + udev_enumerate_add_syspath(udev_enumerate, udev_list_entry_get_name(list_entry)); return 0; } -enum scan_type { - SCAN_DEVICES, - SCAN_SUBSYSTEM, -}; - -static void scan_subsystem(const char *subsys, enum scan_type scan) +static const char *keyval(const char *str, const char **val, char *buf, size_t size) { - char base[PATH_SIZE]; - DIR *dir; - struct dirent *dent; - const char *subdir; - - if (scan == SCAN_DEVICES) - subdir = "/devices"; - else if (scan == SCAN_SUBSYSTEM) - subdir = "/drivers"; - else - return; - - strlcpy(base, sysfs_path, sizeof(base)); - strlcat(base, "/", sizeof(base)); - strlcat(base, subsys, sizeof(base)); - - dir = opendir(base); - if (dir != NULL) { - for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { - char dirname[PATH_SIZE]; - DIR *dir2; - struct dirent *dent2; - - if (dent->d_name[0] == '.') - continue; + char *pos; - if (scan == SCAN_DEVICES) - if (subsystem_filtered(dent->d_name)) - continue; - - strlcpy(dirname, base, sizeof(dirname)); - strlcat(dirname, "/", sizeof(dirname)); - strlcat(dirname, dent->d_name, sizeof(dirname)); - - if (scan == SCAN_SUBSYSTEM) { - if (attr_filtered(dirname)) - continue; - if (!subsystem_filtered("subsystem")) - device_list_insert(dirname); - if (subsystem_filtered("drivers")) - continue; - } - - strlcat(dirname, subdir, sizeof(dirname)); - - /* look for devices/drivers */ - dir2 = opendir(dirname); - if (dir2 != NULL) { - for (dent2 = readdir(dir2); dent2 != NULL; dent2 = readdir(dir2)) { - char dirname2[PATH_SIZE]; - - if (dent2->d_name[0] == '.') - continue; - - strlcpy(dirname2, dirname, sizeof(dirname2)); - strlcat(dirname2, "/", sizeof(dirname2)); - strlcat(dirname2, dent2->d_name, sizeof(dirname2)); - if (attr_filtered(dirname2)) - continue; - device_list_insert(dirname2); - } - closedir(dir2); - } - } - closedir(dir); + util_strscpy(buf, size,str); + pos = strchr(buf, '='); + if (pos != NULL) { + pos[0] = 0; + pos++; } + *val = pos; + return buf; } -static void scan_block(void) +int udevadm_trigger(struct udev *udev, int argc, char *argv[]) { - char base[PATH_SIZE]; - DIR *dir; - struct dirent *dent; - - if (subsystem_filtered("block")) - return; - - strlcpy(base, sysfs_path, sizeof(base)); - strlcat(base, "/block", sizeof(base)); - - dir = opendir(base); - if (dir != NULL) { - for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { - char dirname[PATH_SIZE]; - DIR *dir2; - struct dirent *dent2; - - if (dent->d_name[0] == '.') - continue; - - strlcpy(dirname, base, sizeof(dirname)); - strlcat(dirname, "/", sizeof(dirname)); - strlcat(dirname, dent->d_name, sizeof(dirname)); - if (attr_filtered(dirname)) - continue; - if (device_list_insert(dirname) != 0) - continue; - - /* look for partitions */ - dir2 = opendir(dirname); - if (dir2 != NULL) { - for (dent2 = readdir(dir2); dent2 != NULL; dent2 = readdir(dir2)) { - char dirname2[PATH_SIZE]; - - if (dent2->d_name[0] == '.') - continue; - - if (!strcmp(dent2->d_name,"device")) - continue; - - strlcpy(dirname2, dirname, sizeof(dirname2)); - strlcat(dirname2, "/", sizeof(dirname2)); - strlcat(dirname2, dent2->d_name, sizeof(dirname2)); - if (attr_filtered(dirname2)) - continue; - device_list_insert(dirname2); - } - closedir(dir2); - } - } - closedir(dir); - } -} - -static void scan_class(void) -{ - char base[PATH_SIZE]; - DIR *dir; - struct dirent *dent; - - strlcpy(base, sysfs_path, sizeof(base)); - strlcat(base, "/class", sizeof(base)); - - dir = opendir(base); - if (dir != NULL) { - for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { - char dirname[PATH_SIZE]; - DIR *dir2; - struct dirent *dent2; - - if (dent->d_name[0] == '.') - continue; - - if (subsystem_filtered(dent->d_name)) - continue; - - strlcpy(dirname, base, sizeof(dirname)); - strlcat(dirname, "/", sizeof(dirname)); - strlcat(dirname, dent->d_name, sizeof(dirname)); - dir2 = opendir(dirname); - if (dir2 != NULL) { - for (dent2 = readdir(dir2); dent2 != NULL; dent2 = readdir(dir2)) { - char dirname2[PATH_SIZE]; - - if (dent2->d_name[0] == '.') - continue; - - if (!strcmp(dent2->d_name, "device")) - continue; - - strlcpy(dirname2, dirname, sizeof(dirname2)); - strlcat(dirname2, "/", sizeof(dirname2)); - strlcat(dirname2, dent2->d_name, sizeof(dirname2)); - if (attr_filtered(dirname2)) - continue; - device_list_insert(dirname2); - } - closedir(dir2); - } - } - closedir(dir); - } -} - -static void scan_failed(void) -{ - char base[PATH_SIZE]; - DIR *dir; - struct dirent *dent; - - strlcpy(base, udev_root, sizeof(base)); - strlcat(base, "/.udev/failed", sizeof(base)); - - dir = opendir(base); - if (dir != NULL) { - for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { - char device[PATH_SIZE]; - size_t start; - - if (dent->d_name[0] == '.') - continue; - - start = strlcpy(device, sysfs_path, sizeof(device)); - if(start >= sizeof(device)) - start = sizeof(device) - 1; - strlcat(device, dent->d_name, sizeof(device)); - path_decode(&device[start]); - device_list_insert(device); - } - closedir(dir); - } -} - -int udevadm_trigger(int argc, char *argv[]) -{ - int failed = 0; - const char *sockpath = NULL; - int option; - const char *action = "add"; - const char *env = NULL; static const struct option options[] = { - { "verbose", 0, NULL, 'v' }, - { "dry-run", 0, NULL, 'n' }, - { "retry-failed", 0, NULL, 'F' }, - { "socket", 1, NULL, 'o' }, - { "help", 0, NULL, 'h' }, - { "action", 1, NULL, 'c' }, - { "subsystem-match", 1, NULL, 's' }, - { "subsystem-nomatch", 1, NULL, 'S' }, - { "attr-match", 1, NULL, 'a' }, - { "attr-nomatch", 1, NULL, 'A' }, - { "env", 1, NULL, 'e' }, + { "verbose", no_argument, NULL, 'v' }, + { "dry-run", no_argument, NULL, 'n' }, + { "type", required_argument, NULL, 't' }, + { "action", required_argument, NULL, 'c' }, + { "subsystem-match", required_argument, NULL, 's' }, + { "subsystem-nomatch", required_argument, NULL, 'S' }, + { "attr-match", required_argument, NULL, 'a' }, + { "attr-nomatch", required_argument, NULL, 'A' }, + { "property-match", required_argument, NULL, 'p' }, + { "sysname-match", required_argument, NULL, 'y' }, + { "help", no_argument, NULL, 'h' }, {} }; + enum { + TYPE_DEVICES, + TYPE_SUBSYSTEMS, + TYPE_FAILED, + } device_type = TYPE_DEVICES; + const char *action = "add"; + struct udev_enumerate *udev_enumerate; + int rc = 0; - logging_init("udevtrigger"); - udev_config_init(); - dbg("version %s\n", VERSION); - sysfs_init(); + dbg(udev, "version %s\n", VERSION); + udev_enumerate = udev_enumerate_new(udev); + if (udev_enumerate == NULL) { + rc = 1; + goto exit; + } while (1) { - option = getopt_long(argc, argv, "vnFo:hce::s:S:a:A:", options, NULL); + int option; + const char *key; + const char *val; + char buf[UTIL_PATH_SIZE]; + + option = getopt_long(argc, argv, "vnFo:t:hcp:s:S:a:A:y:", options, NULL); if (option == -1) break; @@ -601,116 +138,84 @@ int udevadm_trigger(int argc, char *argv[]) case 'n': dry_run = 1; break; - case 'F': - failed = 1; - break; - case 'o': - sockpath = optarg; + case 't': + if (strcmp(optarg, "devices") == 0) { + device_type = TYPE_DEVICES; + } else if (strcmp(optarg, "subsystems") == 0) { + device_type = TYPE_SUBSYSTEMS; + } else if (strcmp(optarg, "failed") == 0) { + device_type = TYPE_FAILED; + } else { + fprintf(stderr, "unknown type --type=%s\n", optarg); + err(udev, "unknown type --type=%s\n", optarg); + rc = 2; + goto exit; + } break; case 'c': action = optarg; break; - case 'e': - if (strchr(optarg, '=') != NULL) - env = optarg; - break; case 's': - name_list_add(&filter_subsystem_match_list, optarg, 0); + udev_enumerate_add_match_subsystem(udev_enumerate, optarg); break; case 'S': - name_list_add(&filter_subsystem_nomatch_list, optarg, 0); + udev_enumerate_add_nomatch_subsystem(udev_enumerate, optarg); break; case 'a': - name_list_add(&filter_attr_match_list, optarg, 0); + key = keyval(optarg, &val, buf, sizeof(buf)); + udev_enumerate_add_match_sysattr(udev_enumerate, key, val); break; case 'A': - name_list_add(&filter_attr_nomatch_list, optarg, 0); + key = keyval(optarg, &val, buf, sizeof(buf)); + udev_enumerate_add_nomatch_sysattr(udev_enumerate, key, val); + break; + case 'p': + key = keyval(optarg, &val, buf, sizeof(buf)); + udev_enumerate_add_match_property(udev_enumerate, key, val); + break; + case 'y': + udev_enumerate_add_match_sysname(udev_enumerate, optarg); break; case 'h': printf("Usage: udevadm trigger OPTIONS\n" " --verbose print the list of devices while running\n" " --dry-run do not actually trigger the events\n" - " --retry-failed trigger only the events which have been\n" - " marked as failed during a previous run\n" - " --socket= pass events to socket instead of triggering kernel events\n" - " --env== pass an additional key (works only with --socket=)\n" + " --type= type of events to trigger\n" + " devices sys devices (default)\n" + " subsystems sys subsystems and drivers\n" + " failed trigger only the events which have been\n" + " marked as failed during a previous run\n" + " --action= event action value, default is \"add\"\n" " --subsystem-match= trigger devices from a matching subystem\n" " --subsystem-nomatch= exclude devices from a matching subystem\n" - " --attr-match=]> trigger devices with a matching sysfs\n" - " attribute\n" - " --attr-nomatch=]> exclude devices with a matching sysfs\n" - " attribute\n" - " --help print this text\n" - "\n"); + " --attr-match=]> trigger devices with a matching attribute\n" + " --attr-nomatch=]> exclude devices with a matching attribute\n" + " --property-match== trigger devices with a matching property\n" + " --sysname-match= trigger devices with a matching name\n" + " --help\n\n"); goto exit; default: goto exit; } } - if (sockpath != NULL) { - struct stat stats; - - sock = socket(AF_LOCAL, SOCK_DGRAM, 0); - memset(&saddr, 0x00, sizeof(struct sockaddr_un)); - saddr.sun_family = AF_LOCAL; - if (sockpath[0] == '@') { - /* abstract namespace socket requested */ - strlcpy(&saddr.sun_path[1], &sockpath[1], sizeof(saddr.sun_path)-1); - saddrlen = offsetof(struct sockaddr_un, sun_path) + 1 + strlen(&saddr.sun_path[1]); - } else if (stat(sockpath, &stats) == 0 && S_ISSOCK(stats.st_mode)) { - /* existing socket file */ - strlcpy(saddr.sun_path, sockpath, sizeof(saddr.sun_path)); - saddrlen = offsetof(struct sockaddr_un, sun_path) + strlen(saddr.sun_path); - } else { - /* no socket file, assume abstract namespace socket */ - strlcpy(&saddr.sun_path[1], sockpath, sizeof(saddr.sun_path)-1); - saddrlen = offsetof(struct sockaddr_un, sun_path) + 1 + strlen(&saddr.sun_path[1]); - } - } else if (env != NULL) { - fprintf(stderr, "error: --env= only valid with --socket= option\n"); + switch (device_type) { + case TYPE_FAILED: + scan_failed(udev_enumerate); + exec_list(udev_enumerate, action); + goto exit; + case TYPE_SUBSYSTEMS: + udev_enumerate_scan_subsystems(udev_enumerate); + exec_list(udev_enumerate, action); + goto exit; + case TYPE_DEVICES: + udev_enumerate_scan_devices(udev_enumerate); + exec_list(udev_enumerate, action); + goto exit; + default: goto exit; } - - if (failed) { - scan_failed(); - exec_list(action, env); - } else { - char base[PATH_SIZE]; - struct stat statbuf; - - /* if we have /sys/subsystem, forget all the old stuff */ - strlcpy(base, sysfs_path, sizeof(base)); - strlcat(base, "/subsystem", sizeof(base)); - if (stat(base, &statbuf) == 0) { - scan_subsystem("subsystem", SCAN_SUBSYSTEM); - exec_list(action, env); - scan_subsystem("subsystem", SCAN_DEVICES); - exec_list(action, env); - } else { - scan_subsystem("bus", SCAN_SUBSYSTEM); - exec_list(action, env); - scan_subsystem("bus", SCAN_DEVICES); - scan_class(); - - /* scan "block" if it isn't a "class" */ - strlcpy(base, sysfs_path, sizeof(base)); - strlcat(base, "/class/block", sizeof(base)); - if (stat(base, &statbuf) != 0) - scan_block(); - exec_list(action, env); - } - } - exit: - name_list_cleanup(&filter_subsystem_match_list); - name_list_cleanup(&filter_subsystem_nomatch_list); - name_list_cleanup(&filter_attr_match_list); - name_list_cleanup(&filter_attr_nomatch_list); - - if (sock >= 0) - close(sock); - sysfs_cleanup(); - logging_close(); - return 0; + udev_enumerate_unref(udev_enumerate); + return rc; }