From c07669bd663d780e4957691e488798aa0178e76b Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Sun, 5 Jun 2005 15:55:29 +0200 Subject: [PATCH] udev: handle all events - not only class and block devices Handle all events with rules. If udev is expected to handle hotplug.d/ the exernal helper must be called. Signed-off-by: Kay Sievers --- Makefile | 2 +- extras/run_directory/udev_run_hotplugd.c | 3 - udev.8.in | 28 +--- udev.c | 155 ++++++++---------- udev.h | 9 +- udev.spec | 3 - udev_add.c | 16 -- udev_config.c | 6 - udev_multiplex.c | 92 ----------- udev_remove.c | 26 ++- udev_rules.c | 196 +++++++++-------------- udev_rules.h | 3 +- udev_rules_parse.c | 8 +- udevstart.c | 24 ++- 14 files changed, 180 insertions(+), 391 deletions(-) delete mode 100644 udev_multiplex.c diff --git a/Makefile b/Makefile index 1cf3e54f..d36bd586 100644 --- a/Makefile +++ b/Makefile @@ -143,7 +143,6 @@ UDEV_OBJS = \ udev_remove.o \ udev_sysfs.o \ udev_db.o \ - udev_multiplex.o \ udev_rules.o \ udev_rules_parse.o \ udev_libc_wrapper.o @@ -382,6 +381,7 @@ install: install-config install-man install-dev.d all - ln -f -s $(sbindir)/$(SENDER) $(DESTDIR)$(hotplugdir)/10-udev.hotplug ifndef DESTDIR - killall $(DAEMON) + - $(sbindir)/$(DAEMON) -d - rm -rf $(udevdb) endif @extras="$(EXTRAS)" ; for target in $$extras ; do \ diff --git a/extras/run_directory/udev_run_hotplugd.c b/extras/run_directory/udev_run_hotplugd.c index 463473d7..54b6bf44 100644 --- a/extras/run_directory/udev_run_hotplugd.c +++ b/extras/run_directory/udev_run_hotplugd.c @@ -58,9 +58,6 @@ int main(int argc, char *argv[], char *envp[]) const char *subsystem; int fd; - if (getenv("DEVNAME") == NULL) - exit(0); - subsystem = argv[1]; logging_init("udev_run_hotplugd"); diff --git a/udev.8.in b/udev.8.in index 79c4a83d..e4c1c11a 100644 --- a/udev.8.in +++ b/udev.8.in @@ -306,11 +306,9 @@ following the '[' is a '!', any characters not enclosed are matched. .P After device node creation, removal, or network device renaming, .B udev -executes the programs located in the directory tree under -.IR /etc/dev.d/ . -The name of a program must have the suffix -.I .dev -to be recognized. +executes the programs specified by the +.B RUN +key. .br In addition to the kernel provided hotplug environment variables, .B UDEV_LOG @@ -319,15 +317,7 @@ is set and contains the numerical priority value, if udev is configured to use Executed programs may want to follow that setting. .B DEVNAME is exported to make the name of the created node, or the name the network -device is renamed to, available to the executed program. The programs in every -directory are sorted in lexical order, while the directories are searched in -the following order: -.sp -.nf -/etc/dev.d/$(DEVNAME)/*.dev -/etc/dev.d/$(SUBSYSTEM)/*.dev -/etc/dev.d/default/*.dev -.fi +device is renamed to, available to the executed programs. .SH "ENVIRONMENT" .P The following variables are read from the environment: @@ -353,20 +343,10 @@ Overrides the log priority specified in the config file. .TP .B UDEV_RUN If set to "0", it disables the execution of programs added by rules. -.TP -.B UDEV_NO_DEVD -The default behavior of -.B udev -is to execute programs in the -.I /etc/dev.d/ -directory after device handling. If set, -.B udev -will skip this step. .SH "FILES" .nf /sbin/udev udev program /etc/udev/* udev config files -/etc/dev.d/* programs invoked by udev .fi .SH "SEE ALSO" .BR udevinfo (8), diff --git a/udev.c b/udev.c index 3f76e98b..d623cbcc 100644 --- a/udev.c +++ b/udev.c @@ -54,39 +54,6 @@ void log_message(int priority, const char *format, ...) } #endif -/* Decide if we should manage the whole uevent, including multiplexing - * of the hotplug directories. - * For now look if the kernel calls udevsend instead of /sbin/hotplug, - * or the uevent-helper in /proc/sys/kernel/hotplug is empty. - */ -static int manage_hotplug_event(void) { - char helper[256]; - int fd; - int len; - - /* don't handle hotplug.d if we are called directly */ - if (!getenv("UDEVD_EVENT")) - return 0; - - fd = open("/proc/sys/kernel/hotplug", O_RDONLY); - if (fd < 0) - return 0; - - len = read(fd, helper, sizeof(helper)-1); - close(fd); - - if (len < 0) - return 0; - helper[len] = '\0'; - - if (helper[0] == '\0' || helper[0] == '\n') - return 1; - if (strstr(helper, "udevsend")) - return 1; - - return 0; -} - static void asmlinkage sig_handler(int signum) { switch (signum) { @@ -100,15 +67,12 @@ static void asmlinkage sig_handler(int signum) int main(int argc, char *argv[], char *envp[]) { - struct sysfs_class_device *class_dev; - struct sysfs_device *devices_dev; struct udevice udev; char path[PATH_SIZE]; const char *error; const char *action; const char *devpath; const char *subsystem; - int managed_event; struct sigaction act; int retval = -EINVAL; @@ -133,11 +97,6 @@ int main(int argc, char *argv[], char *envp[]) /* trigger timeout to prevent hanging processes */ alarm(ALARM_TIMEOUT); - /* let the executed programs know if we handle the whole hotplug event */ - managed_event = manage_hotplug_event(); - if (managed_event) - setenv("MANAGED_EVENT", "1", 1); - action = getenv("ACTION"); devpath = getenv("DEVPATH"); subsystem = getenv("SUBSYSTEM"); @@ -145,14 +104,12 @@ int main(int argc, char *argv[], char *envp[]) if (!subsystem && argc == 2) subsystem = argv[1]; - udev_init_device(&udev, devpath, subsystem, action); - if (!action || !subsystem || !devpath) { err("action, subsystem or devpath missing"); - goto hotplug; + goto exit; } - /* export logging flag, as called programs may want to do the same as udev */ + /* export log_level , as called programs may want to do the same as udev */ if (udev_log_priority) { char priority[32]; @@ -160,93 +117,109 @@ int main(int argc, char *argv[], char *envp[]) setenv("UDEV_LOG", priority, 1); } - if (udev.type == DEV_BLOCK || udev.type == DEV_CLASS || udev.type == DEV_NET) { - udev_rules_init(); + udev_init_device(&udev, devpath, subsystem, action); + udev_rules_init(); + if (udev.type == DEV_BLOCK || udev.type == DEV_CLASS || udev.type == DEV_NET) { + /* handle device node */ if (strcmp(action, "add") == 0) { - /* wait for sysfs and possibly add node */ - dbg("udev add"); - - /* skip subsystems without "dev", but handle net devices */ - if (udev.type != DEV_NET && subsystem_expect_no_dev(udev.subsystem)) { - dbg("don't care about '%s' devices", udev.subsystem); - goto hotplug; - } + struct sysfs_class_device *class_dev; + /* wait for sysfs of /sys/class /sys/block */ + dbg("node add"); snprintf(path, sizeof(path), "%s%s", sysfs_path, udev.devpath); path[sizeof(path)-1] = '\0'; class_dev = wait_class_device_open(path); if (class_dev == NULL) { dbg("open class device failed"); - goto hotplug; + goto run; } dbg("opened class_dev->name='%s'", class_dev->name); - wait_for_class_device(class_dev, &error); - /* name, create node, store in db */ - retval = udev_add_device(&udev, class_dev); - + /* get major/minor */ + if (udev.type == DEV_BLOCK || udev.type == DEV_CLASS) { + udev.devt = get_devt(class_dev); + if (udev.devt) { + /* name device */ + udev_rules_get_name(&udev, class_dev); + if (udev.ignore_device) { + info("device event will be ignored"); + goto exit; + } + if (udev.name[0] == '\0') { + info("device node creation supressed"); + goto run; + } + + /* create node, store in db */ + retval = udev_add_device(&udev, class_dev); + } else { + dbg("no dev-file found"); + udev_rules_get_run(&udev, NULL); + if (udev.ignore_device) { + info("device event will be ignored"); + goto exit; + } + } + } sysfs_close_class_device(class_dev); } else if (strcmp(action, "remove") == 0) { - /* possibly remove a node */ - dbg("udev remove"); - - /* skip subsystems without "dev" */ - if (subsystem_expect_no_dev(udev.subsystem)) { - dbg("don't care about '%s' devices", udev.subsystem); - goto hotplug; - } - - udev_rules_get_run(&udev); + dbg("node remove"); + udev_rules_get_run(&udev, NULL); if (udev.ignore_device) { dbg("device event will be ignored"); - goto hotplug; + goto exit; } - /* get node from db, remove db-entry, delete created node */ + /* get name from db, remove db-entry, delete node */ retval = udev_remove_device(&udev); } + /* export name of device node or netif */ if (udev.devname[0] != '\0') setenv("DEVNAME", udev.devname, 1); - - if (udev_run && !list_empty(&udev.run_list)) { - struct name_entry *name_loop; - - dbg("executing run list"); - list_for_each_entry(name_loop, &udev.run_list, node) - execute_command(name_loop->name, udev.subsystem); - } - } else if (udev.type == DEV_DEVICE) { if (strcmp(action, "add") == 0) { - /* wait for sysfs */ - dbg("devices add"); + struct sysfs_device *devices_dev; + /* wait for sysfs of /sys/devices/ */ + dbg("devices add"); snprintf(path, sizeof(path), "%s%s", sysfs_path, devpath); path[sizeof(path)-1] = '\0'; devices_dev = wait_devices_device_open(path); if (!devices_dev) { dbg("devices device unavailable (probably remove has beaten us)"); - goto hotplug; + goto run; } dbg("devices device opened '%s'", path); - wait_for_devices_device(devices_dev, &error); - + udev_rules_get_run(&udev, devices_dev); sysfs_close_device(devices_dev); + if (udev.ignore_device) { + info("device event will be ignored"); + goto exit; + } } else if (strcmp(action, "remove") == 0) { dbg("devices remove"); + udev_rules_get_run(&udev, NULL); + if (udev.ignore_device) { + info("device event will be ignored"); + goto exit; + } } - } else { - dbg("unhandled"); } -hotplug: - if (udev_hotplug_d && managed_event) - udev_multiplex_directory(&udev, HOTPLUGD_DIR, HOTPLUG_SUFFIX); +run: + if (udev_run && !list_empty(&udev.run_list)) { + struct name_entry *name_loop; + + dbg("executing run list"); + list_for_each_entry(name_loop, &udev.run_list, node) + execute_command(name_loop->name, udev.subsystem); + } +exit: udev_cleanup_device(&udev); logging_close(); diff --git a/udev.h b/udev.h index 2c3377ad..11fbe024 100644 --- a/udev.h +++ b/udev.h @@ -39,12 +39,6 @@ #define SEQNUM_SIZE 32 #define VALUE_SIZE 128 -#define DEVD_DIR "/etc/dev.d" -#define DEVD_SUFFIX ".dev" - -#define HOTPLUGD_DIR "/etc/hotplug.d" -#define HOTPLUG_SUFFIX ".hotplug" - #define DEFAULT_PARTITIONS_COUNT 15 enum device_type { @@ -62,6 +56,7 @@ struct udevice { enum device_type type; char name[PATH_SIZE]; + int name_set; char devname[PATH_SIZE]; struct list_head symlink_list; int symlink_final; @@ -92,7 +87,6 @@ extern int udev_add_device(struct udevice *udev, struct sysfs_class_device *clas extern int udev_remove_device(struct udevice *udev); extern void udev_init_config(void); extern int udev_start(void); -extern void udev_multiplex_directory(struct udevice *udev, const char *basedir, const char *suffix); extern int udev_make_node(struct udevice *udev, const char *file, dev_t devt, mode_t mode, uid_t uid, gid_t gid); extern char sysfs_path[PATH_SIZE]; @@ -102,6 +96,5 @@ extern char udev_config_filename[PATH_SIZE]; extern char udev_rules_filename[PATH_SIZE]; extern int udev_log_priority; extern int udev_run; -extern int udev_hotplug_d; #endif diff --git a/udev.spec b/udev.spec index 28f19565..0430a125 100644 --- a/udev.spec +++ b/udev.spec @@ -112,9 +112,6 @@ rm -rf $RPM_BUILD_ROOT %attr(-,root,root) /etc/hotplug.d/default/udev.hotplug %attr(755,root,root) /etc/init.d/udev %attr(0644,root,root) %{_mandir}/man8/udev*.8* -%attr(755,root,root) %dir /etc/dev.d/ -%attr(755,root,root) %dir /etc/dev.d/net/ -%attr(0755,root,root) /etc/dev.d/net/hotplug.dev %if %{scsi_id} %attr(755,root,root) /sbin/scsi_id diff --git a/udev_add.c b/udev_add.c index 9764cb9b..2081e503 100644 --- a/udev_add.c +++ b/udev_add.c @@ -268,22 +268,7 @@ int udev_add_device(struct udevice *udev, struct sysfs_class_device *class_dev) char *pos; int retval = 0; - if (udev->type == DEV_BLOCK || udev->type == DEV_CLASS) { - udev->devt = get_devt(class_dev); - if (!udev->devt) { - dbg("no dev-file found, do nothing"); - return 0; - } - } - - udev_rules_get_name(udev, class_dev); - if (udev->ignore_device) { - dbg("device event will be ignored"); - return 0; - } - dbg("adding name='%s'", udev->name); - selinux_init(); if (udev->type == DEV_BLOCK || udev->type == DEV_CLASS) { @@ -325,6 +310,5 @@ int udev_add_device(struct udevice *udev, struct sysfs_class_device *class_dev) exit: selinux_exit(); - return retval; } diff --git a/udev_config.c b/udev_config.c index 0701d37e..773ee67f 100644 --- a/udev_config.c +++ b/udev_config.c @@ -45,7 +45,6 @@ char udev_config_filename[PATH_SIZE]; char udev_rules_filename[PATH_SIZE]; int udev_log_priority; int udev_run; -int udev_hotplug_d; static int get_key(char **line, char **key, char **value) { @@ -187,7 +186,6 @@ void udev_init_config(void) strcpy(udev_rules_filename, UDEV_RULES_FILE); udev_log_priority = LOG_ERR; udev_run = 1; - udev_hotplug_d = 1; sysfs_get_mnt_path(sysfs_path, sizeof(sysfs_path)); /* disable RUN key execution */ @@ -195,10 +193,6 @@ void udev_init_config(void) if (env && !string_is_true(env)) udev_run = 0; - env = getenv("UDEV_NO_HOTPLUGD"); - if (env && string_is_true(env)) - udev_hotplug_d = 0; - env = getenv("UDEV_CONFIG_FILE"); if (env) { strlcpy(udev_config_filename, env, sizeof(udev_config_filename)); diff --git a/udev_multiplex.c b/udev_multiplex.c deleted file mode 100644 index 22bbaf7b..00000000 --- a/udev_multiplex.c +++ /dev/null @@ -1,92 +0,0 @@ -/* - * udev_multiplex.c directory multiplexer - * - * Copyright (C) 2004 Greg Kroah-Hartman - * - * 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 essentially emulates the following shell script logic in C: - * DIR="/etc/dev.d" - * export DEVNAME="whatever_dev_name_udev_just_gave" - * for I in "${DIR}/$DEVNAME/"*.dev "${DIR}/$1/"*.dev "${DIR}/default/"*.dev ; do - * if [ -f $I ]; then $I $1 ; fi - * done - * exit 1; - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "udev.h" -#include "udev_libc_wrapper.h" -#include "udev_utils.h" -#include "logging.h" - - -/* - * runs files in these directories in order: - * / - * subsystem/ - * default/ - */ -void udev_multiplex_directory(struct udevice *udev, const char *basedir, const char *suffix) -{ - char dirname[PATH_SIZE]; - struct name_entry *name_loop, *name_tmp; - LIST_HEAD(name_list); - - /* chop the device name up into pieces based on '/' */ - if (udev->name[0] != '\0') { - char devname[PATH_SIZE]; - char *temp; - - strlcpy(devname, udev->name, sizeof(devname)); - temp = strchr(devname, '/'); - while (temp != NULL) { - temp[0] = '\0'; - - /* don't call the subsystem directory here */ - if (strcmp(devname, udev->subsystem) != 0) { - snprintf(dirname, sizeof(dirname), "%s/%s", basedir, devname); - dirname[sizeof(dirname)-1] = '\0'; - add_matching_files(&name_list, dirname, suffix); - } - - temp[0] = '/'; - ++temp; - temp = strchr(temp, '/'); - } - } - - if (udev->name[0] != '\0') { - snprintf(dirname, sizeof(dirname), "%s/%s", basedir, udev->name); - dirname[sizeof(dirname)-1] = '\0'; - add_matching_files(&name_list, dirname, suffix); - } - - if (udev->subsystem[0] != '\0') { - snprintf(dirname, sizeof(dirname), "%s/%s", basedir, udev->subsystem); - dirname[sizeof(dirname)-1] = '\0'; - add_matching_files(&name_list, dirname, suffix); - } - - snprintf(dirname, sizeof(dirname), "%s/default", basedir); - dirname[sizeof(dirname)-1] = '\0'; - add_matching_files(&name_list, dirname, suffix); - - list_for_each_entry_safe(name_loop, name_tmp, &name_list, node) { - execute_command(name_loop->name, udev->subsystem); - list_del(&name_loop->node); - } - -} diff --git a/udev_remove.c b/udev_remove.c index 2df55532..cf28ff37 100644 --- a/udev_remove.c +++ b/udev_remove.c @@ -140,26 +140,20 @@ static int delete_node(struct udevice *udev) */ int udev_remove_device(struct udevice *udev) { - const char *temp; - if (udev->type != DEV_BLOCK && udev->type != DEV_CLASS) return 0; - if (udev_db_get_device(udev, udev->devpath) == 0) { - if (udev->ignore_remove) { - dbg("remove event for '%s' requested to be ignored by rule", udev->name); - return 0; - } - dbg("remove name='%s'", udev->name); - udev_db_delete_device(udev); - } else { - /* fall back to kernel name */ - temp = strrchr(udev->devpath, '/'); - if (temp == NULL) - return -ENODEV; - strlcpy(udev->name, &temp[1], sizeof(udev->name)); - info("'%s' not found in database, falling back on default name", udev->name); + /* remove node only if we can find it in our database */ + if (udev_db_get_device(udev, udev->devpath) != 0) { + dbg("'%s' not found in database, ignore event", udev->name); + return -1; + } + if (udev->ignore_remove) { + dbg("remove event for '%s' requested to be ignored by rule", udev->name); + return 0; } + dbg("remove name='%s'", udev->name); + udev_db_delete_device(udev); /* use full path to the environment */ snprintf(udev->devname, sizeof(udev->devname), "%s/%s", udev_root, udev->name); diff --git a/udev_rules.c b/udev_rules.c index 631cc427..cbd76e66 100644 --- a/udev_rules.c +++ b/udev_rules.c @@ -731,7 +731,7 @@ int udev_rules_get_name(struct udevice *udev, struct sysfs_class_device *class_d list_for_each_entry(rule, &udev_rule_list, node) { dbg("process rule"); if (match_rule(udev, rule, class_dev, sysfs_device) == 0) { - if (udev->name[0] != '\0' && rule->name[0] != '\0') { + if (udev->name_set && rule->name_operation != KEY_OP_UNSET) { dbg("node name already set, rule ignored"); continue; } @@ -776,73 +776,84 @@ int udev_rules_get_name(struct udevice *udev, struct sysfs_class_device *class_d } /* collect symlinks */ - if (!udev->symlink_final && rule->symlink[0] != '\0') { + if (!udev->symlink_final && rule->symlink_operation != KEY_OP_UNSET) { char temp[PATH_SIZE]; char *pos, *next; if (rule->symlink_operation == KEY_OP_ASSIGN_FINAL) udev->symlink_final = 1; - else if (rule->symlink_operation == KEY_OP_ASSIGN) { + if (rule->symlink_operation == KEY_OP_ASSIGN || rule->symlink_operation == KEY_OP_ASSIGN_FINAL) { struct name_entry *name_loop; struct name_entry *temp_loop; + info("reset symlink list"); list_for_each_entry_safe(name_loop, temp_loop, &udev->symlink_list, node) { list_del(&name_loop->node); free(name_loop); } } - info("configured rule in '%s[%i]' applied, added symlink '%s'", - rule->config_file, rule->config_line, rule->symlink); - strlcpy(temp, rule->symlink, sizeof(temp)); - apply_format(udev, temp, sizeof(temp), class_dev, sysfs_device); - - /* add multiple symlinks separated by spaces */ - pos = temp; - next = strchr(temp, ' '); - while (next) { - next[0] = '\0'; + if (rule->symlink[0] != '\0') { + info("configured rule in '%s[%i]' applied, added symlink '%s'", + rule->config_file, rule->config_line, rule->symlink); + strlcpy(temp, rule->symlink, sizeof(temp)); + apply_format(udev, temp, sizeof(temp), class_dev, sysfs_device); + + /* add multiple symlinks separated by spaces */ + pos = temp; + next = strchr(temp, ' '); + while (next) { + next[0] = '\0'; + info("add symlink '%s'", pos); + name_list_add(&udev->symlink_list, pos, 0); + pos = &next[1]; + next = strchr(pos, ' '); + } info("add symlink '%s'", pos); name_list_add(&udev->symlink_list, pos, 0); - pos = &next[1]; - next = strchr(pos, ' '); } - info("add symlink '%s'", pos); - name_list_add(&udev->symlink_list, pos, 0); } /* set name, later rules with name set will be ignored */ - if (rule->name[0] != '\0') { - info("configured rule in '%s[%i]' applied, '%s' becomes '%s'", - rule->config_file, rule->config_line, udev->kernel_name, rule->name); - - strlcpy(udev->name, rule->name, sizeof(udev->name)); - apply_format(udev, udev->name, sizeof(udev->name), class_dev, sysfs_device); - strlcpy(udev->config_file, rule->config_file, sizeof(udev->config_file)); - udev->config_line = rule->config_line; - - if (udev->type != DEV_NET) - dbg("name, '%s' is going to have owner='%s', group='%s', mode=%#o partitions=%i", - udev->name, udev->owner, udev->group, udev->mode, udev->partitions); + if (rule->name_operation != KEY_OP_UNSET) { + udev->name_set = 1; + if (rule->name[0] == '\0') { + info("configured rule in '%s[%i]' applied, node handling for '%s' supressed", + rule->config_file, rule->config_line, udev->kernel_name); + } else { + strlcpy(udev->name, rule->name, sizeof(udev->name)); + apply_format(udev, udev->name, sizeof(udev->name), class_dev, sysfs_device); + strlcpy(udev->config_file, rule->config_file, sizeof(udev->config_file)); + udev->config_line = rule->config_line; + + info("configured rule in '%s:%i' applied, '%s' becomes '%s'", + rule->config_file, rule->config_line, udev->kernel_name, rule->name); + if (udev->type != DEV_NET) + dbg("name, '%s' is going to have owner='%s', group='%s', mode=%#o partitions=%i", + udev->name, udev->owner, udev->group, udev->mode, udev->partitions); + } } - if (!udev->run_final && rule->run[0] != '\0') { + if (!udev->run_final && rule->run_operation != KEY_OP_UNSET) { char program[PATH_SIZE]; if (rule->run_operation == KEY_OP_ASSIGN_FINAL) udev->run_final = 1; - else if (rule->run_operation == KEY_OP_ASSIGN) { + if (rule->run_operation == KEY_OP_ASSIGN || rule->run_operation == KEY_OP_ASSIGN_FINAL) { struct name_entry *name_loop; struct name_entry *temp_loop; + info("reset run list"); list_for_each_entry_safe(name_loop, temp_loop, &udev->run_list, node) { list_del(&name_loop->node); free(name_loop); } } - strlcpy(program, rule->run, sizeof(program)); - apply_format(udev, program, sizeof(program), class_dev, sysfs_device); - dbg("add run '%s'", program); - name_list_add(&udev->run_list, program, 0); + if (rule->run[0] != '\0') { + strlcpy(program, rule->run, sizeof(program)); + apply_format(udev, program, sizeof(program), class_dev, sysfs_device); + dbg("add run '%s'", program); + name_list_add(&udev->run_list, program, 0); + } } if (rule->last_rule) { @@ -866,113 +877,58 @@ int udev_rules_get_name(struct udevice *udev, struct sysfs_class_device *class_d return 0; } -int udev_rules_get_run(struct udevice *udev) +int udev_rules_get_run(struct udevice *udev, struct sysfs_device *sysfs_device) { struct udev_rule *rule; - char program[PATH_SIZE]; /* look for a matching rule to apply */ list_for_each_entry(rule, &udev_rule_list, node) { dbg("process rule"); - if (rule->run[0] == '\0') + if (rule->run_operation == KEY_OP_UNSET) continue; - if (rule->name[0] != '\0' || rule->symlink[0] != '\0' || + if (rule->name_operation != KEY_OP_UNSET || rule->symlink_operation != KEY_OP_UNSET || rule->mode != 0000 || rule->owner[0] != '\0' || rule->group[0] != '\0') { dbg("skip rule that names a device"); continue; } - if (rule->action_operation != KEY_OP_UNSET) { - dbg("check for " KEY_ACTION " rule->action='%s' udev->action='%s'", - rule->action, udev->action); - if (strcmp_pattern(rule->action, udev->action) != 0) { - dbg(KEY_ACTION " is not matching"); - if (rule->action_operation != KEY_OP_NOMATCH) - continue; - } else { - dbg(KEY_ACTION " matches"); - if (rule->action_operation == KEY_OP_NOMATCH) - continue; - } - dbg(KEY_ACTION " key is true"); - } - - if (rule->kernel_operation != KEY_OP_UNSET) { - dbg("check for " KEY_KERNEL " rule->kernel='%s' udev->kernel_name='%s'", - rule->kernel, udev->kernel_name); - if (strcmp_pattern(rule->kernel, udev->kernel_name) != 0) { - dbg(KEY_KERNEL " is not matching"); - if (rule->kernel_operation != KEY_OP_NOMATCH) - continue; - } else { - dbg(KEY_KERNEL " matches"); - if (rule->kernel_operation == KEY_OP_NOMATCH) - continue; - } - dbg(KEY_KERNEL " key is true"); - } - - if (rule->subsystem_operation != KEY_OP_UNSET) { - dbg("check for " KEY_SUBSYSTEM " rule->subsystem='%s' udev->subsystem='%s'", - rule->subsystem, udev->subsystem); - if (strcmp_pattern(rule->subsystem, udev->subsystem) != 0) { - dbg(KEY_SUBSYSTEM " is not matching"); - if (rule->subsystem_operation != KEY_OP_NOMATCH) - continue; - } else { - dbg(KEY_SUBSYSTEM " matches"); - if (rule->subsystem_operation == KEY_OP_NOMATCH) - continue; + if (match_rule(udev, rule, NULL, sysfs_device) == 0) { + if (rule->ignore_device) { + info("configured rule in '%s[%i]' applied, '%s' is ignored", + rule->config_file, rule->config_line, udev->kernel_name); + udev->ignore_device = 1; + return 0; } - dbg(KEY_SUBSYSTEM " key is true"); - } - if (rule->env_pair_count) { - int i; + if (!udev->run_final && rule->run_operation != KEY_OP_UNSET) { + char program[PATH_SIZE]; - dbg("check for " KEY_ENV " pairs"); - for (i = 0; i < rule->env_pair_count; i++) { - struct key_pair *pair; - const char *value; + if (rule->run_operation == KEY_OP_ASSIGN || rule->run_operation == KEY_OP_ASSIGN_FINAL) { + struct name_entry *name_loop; + struct name_entry *temp_loop; - pair = &rule->env_pair[i]; - value = getenv(pair->name); - if (!value) { - dbg(KEY_ENV "{'%s'} is not found", pair->name); - continue; + info("reset run list"); + list_for_each_entry_safe(name_loop, temp_loop, &udev->run_list, node) { + list_del(&name_loop->node); + free(name_loop); + } } - if (strcmp_pattern(pair->value, value) != 0) { - dbg(KEY_ENV "{'%s'} is not matching", pair->name); - if (pair->operation != KEY_OP_NOMATCH) - continue; - } else { - dbg(KEY_ENV "{'%s'} matches", pair->name); - if (pair->operation == KEY_OP_NOMATCH) - continue; + if (rule->run[0] != '\0') { + strlcpy(program, rule->run, sizeof(program)); + apply_format(udev, program, sizeof(program), NULL, NULL); + dbg("add run '%s'", program); + name_list_add(&udev->run_list, program, 0); } + if (rule->run_operation == KEY_OP_ASSIGN_FINAL) + break; } - dbg(KEY_ENV " key is true"); - } - - /* rule matches */ - - if (rule->ignore_device) { - info("configured rule in '%s[%i]' applied, '%s' is ignored", - rule->config_file, rule->config_line, udev->kernel_name); - udev->ignore_device = 1; - return 0; - } - - strlcpy(program, rule->run, sizeof(program)); - apply_format(udev, program, sizeof(program), NULL, NULL); - dbg("add run '%s'", program); - name_list_add(&udev->run_list, program, 0); - if (rule->last_rule) { - dbg("last rule to be applied"); - break; + if (rule->last_rule) { + dbg("last rule to be applied"); + break; + } } } diff --git a/udev_rules.h b/udev_rules.h index f4a74bba..75ffd5cb 100644 --- a/udev_rules.h +++ b/udev_rules.h @@ -96,6 +96,7 @@ struct udev_rule { int env_pair_count; char name[PATH_SIZE]; + enum key_operation name_operation; char symlink[PATH_SIZE]; enum key_operation symlink_operation; char owner[USER_SIZE]; @@ -120,7 +121,7 @@ extern struct list_head udev_rule_list; extern int udev_rules_init(void); extern int udev_rules_get_name(struct udevice *udev, struct sysfs_class_device *class_dev); -extern int udev_rules_get_run(struct udevice *udev); +extern int udev_rules_get_run(struct udevice *udev, struct sysfs_device *sysfs_device); extern void udev_rules_close(void); #endif diff --git a/udev_rules_parse.c b/udev_rules_parse.c index 3f07521c..57c797dd 100644 --- a/udev_rules_parse.c +++ b/udev_rules_parse.c @@ -349,21 +349,19 @@ static int rules_parse(const char *filename) if (strncasecmp(key, KEY_NAME, sizeof(KEY_NAME)-1) == 0) { attr = get_key_attribute(key + sizeof(KEY_NAME)-1); - /* FIXME: remove old style options and make OPTIONS= mandatory */ if (attr != NULL) { if (strstr(attr, OPTION_PARTITIONS) != NULL) { dbg("creation of partition nodes requested"); rule.partitions = DEFAULT_PARTITIONS_COUNT; } + /* FIXME: remove old style option and make OPTIONS= mandatory */ if (strstr(attr, OPTION_IGNORE_REMOVE) != NULL) { dbg("remove event should be ignored"); rule.ignore_remove = 1; } } - if (value[0] != '\0') - strlcpy(rule.name, value, sizeof(rule.name)); - else - rule.ignore_device = 1; + rule.name_operation = operation; + strlcpy(rule.name, value, sizeof(rule.name)); valid = 1; continue; } diff --git a/udevstart.c b/udevstart.c index 34f3835d..d1a0a837 100644 --- a/udevstart.c +++ b/udevstart.c @@ -37,6 +37,7 @@ #include "libsysfs/sysfs/libsysfs.h" #include "udev_libc_wrapper.h" +#include "udev_sysfs.h" #include "udev.h" #include "udev_version.h" #include "logging.h" @@ -110,25 +111,37 @@ static int add_device(const char *path, const char *subsystem) const char *devpath; devpath = &path[strlen(sysfs_path)]; - - /* set environment for callouts and dev.d/ */ setenv("DEVPATH", devpath, 1); setenv("SUBSYSTEM", subsystem, 1); - dbg("exec: '%s' (%s)\n", devpath, path); class_dev = sysfs_open_class_device_path(path); if (class_dev == NULL) { dbg ("sysfs_open_class_device_path failed"); - return -ENODEV; + return -1; } udev_init_device(&udev, devpath, subsystem, "add"); - udev_add_device(&udev, class_dev); + udev.devt = get_devt(class_dev); + if (!udev.devt) { + dbg ("sysfs_open_class_device_path failed"); + return -1; + } + udev_rules_get_name(&udev, class_dev); + if (udev.ignore_device) { + info("device event will be ignored"); + goto exit; + } + if (udev.name[0] == '\0') { + info("device node creation supressed"); + goto run; + } + udev_add_device(&udev, class_dev); if (udev.devname[0] != '\0') setenv("DEVNAME", udev.devname, 1); +run: if (udev_run && !list_empty(&udev.run_list)) { struct name_entry *name_loop; @@ -137,6 +150,7 @@ static int add_device(const char *path, const char *subsystem) execute_command(name_loop->name, udev.subsystem); } +exit: sysfs_close_class_device(class_dev); udev_cleanup_device(&udev); -- 2.39.5