#include <unistd.h>
#include <errno.h>
#include <sys/wait.h>
-#include <sys/stat.h>
#include "libsysfs/sysfs/libsysfs.h"
#include "list.h"
struct udevice udev_parent;
dbg("found parent '%s', get the node name", class_dev_parent->path);
- udev_init_device(&udev_parent, NULL, NULL);
+ udev_init_device(&udev_parent, NULL, NULL, NULL);
/* lookup the name in the udev_db with the DEVPATH of the parent */
if (udev_db_get_device(&udev_parent, &class_dev_parent->path[strlen(sysfs_path)]) == 0) {
strlcat(string, udev_parent.name, maxsize);
}
}
-static int execute_program(struct udevice *udev, const char *path, char *value, int len)
+static int execute_program_pipe(const char *command, const char *subsystem, char *value, int len)
{
int retval;
int count;
int status;
- int fds[2];
+ int pipefds[2];
pid_t pid;
char *pos;
char arg[PATH_SIZE];
char *argv[(sizeof(arg) / 2) + 1];
+ int devnull;
int i;
- strlcpy(arg, path, sizeof(arg));
+ strlcpy(arg, command, sizeof(arg));
i = 0;
- if (strchr(path, ' ')) {
+ if (strchr(arg, ' ')) {
pos = arg;
while (pos != NULL) {
if (pos[0] == '\'') {
dbg("execute '%s' with parsed arguments", arg);
} else {
argv[0] = arg;
- argv[1] = udev->subsystem;
+ argv[1] = (char *) subsystem;
argv[2] = NULL;
dbg("execute '%s' with subsystem '%s' argument", arg, argv[1]);
}
- retval = pipe(fds);
+ retval = pipe(pipefds);
if (retval != 0) {
err("pipe failed");
return -1;
switch(pid) {
case 0:
/* child dup2 write side of pipe to STDOUT */
- dup2(fds[1], STDOUT_FILENO);
+ devnull = open("/dev/null", O_RDWR);
+ if (devnull >= 0) {
+ dup2(devnull, STDIN_FILENO);
+ dup2(devnull, STDERR_FILENO);
+ close(devnull);
+ }
+ dup2(pipefds[1], STDOUT_FILENO);
retval = execv(arg, argv);
-
- info(KEY_PROGRAM " execution of '%s' failed", path);
- exit(1);
+ err("exec of program failed");
+ _exit(1);
case -1:
- err("fork of '%s' failed", path);
- return -1;
+ err("fork of '%s' failed", arg);
+ retval = -1;
+ break;
default:
- /* parent reads from fds[0] */
- close(fds[1]);
+ /* parent reads from pipefds[0] */
+ close(pipefds[1]);
retval = 0;
i = 0;
while (1) {
- count = read(fds[0], value + i, len - i-1);
+ count = read(pipefds[0], value + i, len - i-1);
if (count < 0) {
err("read failed with '%s'", strerror(errno));
retval = -1;
}
value[i] = '\0';
- close(fds[0]);
+ close(pipefds[0]);
waitpid(pid, &status, 0);
if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0)) {
{
struct sysfs_device *parent_device = sysfs_device;
+ 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)
+ goto exit;
+ } else {
+ dbg(KEY_ACTION " matches");
+ if (rule->action_operation == KEY_OP_NOMATCH)
+ goto exit;
+ }
+ dbg(KEY_ACTION " key is true");
+ }
+
if (rule->kernel_operation != KEY_OP_UNSET) {
- dbg("check for " KEY_KERNEL " rule->kernel='%s' class_dev->name='%s'",
- rule->kernel, class_dev->name);
- if (strcmp_pattern(rule->kernel, class_dev->name) != 0) {
+ 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)
goto exit;
}
if (rule->subsystem_operation != KEY_OP_UNSET) {
- dbg("check for " KEY_SUBSYSTEM " rule->subsystem='%s' class_dev->name='%s'",
- rule->subsystem, class_dev->name);
+ 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)
for (i = 0; i < rule->sysfs_pair_count; i++) {
struct key_pair *pair;
char value[VALUE_SIZE];
+ size_t len;
pair = &rule->sysfs_pair[i];
if (find_sysfs_attribute(class_dev, parent_device, pair->name, value, sizeof(value)) != 0)
goto try_parent;
/* strip trailing whitespace of value, if not asked to match for it */
- if (!isspace(pair->value[strlen(pair->value)-1])) {
- size_t len = strlen(value);
-
+ len = strlen(pair->value);
+ if (len && !isspace(pair->value[len-1])) {
+ len = strlen(value);
while (len > 0 && isspace(value[len-1]))
value[--len] = '\0';
dbg("removed %i trailing whitespace chars from '%s'", strlen(value)-len, value);
dbg("check " KEY_PROGRAM);
strlcpy(program, rule->program, sizeof(program));
apply_format(udev, program, sizeof(program), class_dev, sysfs_device);
- if (execute_program(udev, program, udev->program_result, sizeof(udev->program_result)) != 0) {
+ if (execute_program_pipe(program, udev->subsystem,
+ udev->program_result, sizeof(udev->program_result)) != 0) {
dbg(KEY_PROGRAM " returned nonzero");
if (rule->program_operation != KEY_OP_NOMATCH)
goto exit;
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') {
+ dbg("node name already set, rule ignored");
+ continue;
+ }
/* apply options */
if (rule->ignore_device) {
info("configured rule in '%s[%i]' applied, '%s' is ignored",
rule->config_file, rule->config_line, udev->kernel_name);
- return -1;
+ udev->ignore_device = 1;
+ return 0;
}
if (rule->ignore_remove) {
udev->ignore_remove = 1;
name_list_add(&udev->symlink_list, pos, 0);
}
- /* rule matches */
+ /* 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 (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);
+ }
- break;
+ if (rule->run[0] != '\0') {
+ char program[PATH_SIZE];
+
+ 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) {
dbg("last rule to be applied");
break;
}
-
}
}
if (udev->name[0] == '\0') {
- /* no rule matched, so we use the kernel name */
strlcpy(udev->name, udev->kernel_name, sizeof(udev->name));
info("no rule found, use kernel name '%s'", udev->name);
}
return 0;
}
+
+int udev_rules_get_run(struct udevice *udev)
+{
+ 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')
+ continue;
+
+ if (rule->name[0] != '\0' || rule->symlink[0] != '\0' ||
+ 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;
+ }
+ dbg(KEY_SUBSYSTEM " key is true");
+ }
+
+ 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;
+ }
+ 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;
+ }
+ }
+ 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;
+ }
+ }
+
+ return 0;
+}