mirror of
https://github.com/systemd/systemd.git
synced 2025-03-19 22:50:17 +03:00
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 <kay.sievers@suse.de>
This commit is contained in:
parent
c2401132bf
commit
c07669bd66
2
Makefile
2
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 \
|
||||
|
@ -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");
|
||||
|
||||
|
28
udev.8.in
28
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),
|
||||
|
153
udev.c
153
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);
|
||||
}
|
||||
|
||||
udev_init_device(&udev, devpath, subsystem, action);
|
||||
udev_rules_init();
|
||||
|
||||
if (udev.type == DEV_BLOCK || udev.type == DEV_CLASS || udev.type == DEV_NET) {
|
||||
udev_rules_init();
|
||||
|
||||
/* 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();
|
||||
|
9
udev.h
9
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
|
||||
|
@ -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
|
||||
|
16
udev_add.c
16
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;
|
||||
}
|
||||
|
@ -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));
|
||||
|
@ -1,92 +0,0 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
|
192
udev_rules.c
192
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);
|
||||
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';
|
||||
/* 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);
|
||||
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;
|
||||
|
||||
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);
|
||||
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;
|
||||
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_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 (!udev->run_final && rule->run_operation != KEY_OP_UNSET) {
|
||||
char program[PATH_SIZE];
|
||||
|
||||
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;
|
||||
}
|
||||
dbg(KEY_SUBSYSTEM " key is true");
|
||||
}
|
||||
if (rule->run_operation == KEY_OP_ASSIGN || rule->run_operation == KEY_OP_ASSIGN_FINAL) {
|
||||
struct name_entry *name_loop;
|
||||
struct name_entry *temp_loop;
|
||||
|
||||
if (rule->env_pair_count) {
|
||||
int i;
|
||||
|
||||
dbg("check for " KEY_ENV " pairs");
|
||||
for (i = 0; i < rule->env_pair_count; i++) {
|
||||
struct key_pair *pair;
|
||||
const char *value;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
24
udevstart.c
24
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);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user