udev_remove.o \
udev_sysfs.o \
udev_db.o \
- udev_multiplex.o \
udev_rules.o \
udev_rules_parse.o \
udev_libc_wrapper.o
- 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 \
const char *subsystem;
int fd;
- if (getenv("DEVNAME") == NULL)
- exit(0);
-
subsystem = argv[1];
logging_init("udev_run_hotplugd");
.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
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:
.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),
}
#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) {
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;
/* 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");
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];
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();
#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 {
enum device_type type;
char name[PATH_SIZE];
+ int name_set;
char devname[PATH_SIZE];
struct list_head symlink_list;
int symlink_final;
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];
extern char udev_rules_filename[PATH_SIZE];
extern int udev_log_priority;
extern int udev_run;
-extern int udev_hotplug_d;
#endif
%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
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) {
exit:
selinux_exit();
-
return retval;
}
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)
{
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 */
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));
+++ /dev/null
-/*
- * udev_multiplex.c directory multiplexer
- *
- * Copyright (C) 2004 Greg Kroah-Hartman <greg@kroah.com>
- *
- * 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 <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-#include "udev.h"
-#include "udev_libc_wrapper.h"
-#include "udev_utils.h"
-#include "logging.h"
-
-
-/*
- * runs files in these directories in order:
- * <node name given by udev>/
- * 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);
- }
-
-}
*/
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);
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;
}
}
/* 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) {
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;
+ }
}
}
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];
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
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;
}
#include "libsysfs/sysfs/libsysfs.h"
#include "udev_libc_wrapper.h"
+#include "udev_sysfs.h"
#include "udev.h"
#include "udev_version.h"
#include "logging.h"
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;
execute_command(name_loop->name, udev.subsystem);
}
+exit:
sysfs_close_class_device(class_dev);
udev_cleanup_device(&udev);