summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xtest/udev-test.pl21
-rw-r--r--udev_rules.c51
-rw-r--r--udev_rules.h11
-rw-r--r--udev_rules_parse.c13
4 files changed, 88 insertions, 8 deletions
diff --git a/test/udev-test.pl b/test/udev-test.pl
index e8cb7c48a9..1bb60bb76e 100755
--- a/test/udev-test.pl
+++ b/test/udev-test.pl
@@ -1473,6 +1473,27 @@ KERNEL=="dontknow*|ttyUSB*|nothing*", NAME="right"
KERNEL=="ttyUSB*", NAME="wrong"
EOF
},
+ {
+ desc => "IMPORT parent test sequence 1/2 (keep)",
+ subsys => "block",
+ devpath => "/block/sda",
+ exp_name => "parent",
+ option => "keep",
+ rules => <<EOF
+KERNEL=="sda", IMPORT="/bin/echo -e \'PARENT_KEY=parent_right\\nWRONG_PARENT_KEY=parent_wrong'"
+KERNEL=="sda", NAME="parent"
+EOF
+ },
+ {
+ desc => "IMPORT parent test sequence 2/2 (keep)",
+ subsys => "block",
+ devpath => "/block/sda/sda1",
+ exp_name => "parentenv-parent_right",
+ option => "clean",
+ rules => <<EOF
+KERNEL=="sda1", IMPORT{parent}="PARENT*", NAME="parentenv-\$env{PARENT_KEY}\$env{WRONG_PARENT_KEY}"
+EOF
+ },
);
# set env
diff --git a/udev_rules.c b/udev_rules.c
index 8ec8fc54a4..d08edf7782 100644
--- a/udev_rules.c
+++ b/udev_rules.c
@@ -281,6 +281,46 @@ static int import_program_into_env(struct udevice *udev, const char *program)
return import_keys_into_env(udev, result, reslen);
}
+static int import_parent_into_env(struct udevice *udev, struct sysfs_class_device *class_dev, const char *filter)
+{
+ struct sysfs_class_device *parent = sysfs_get_classdev_parent(class_dev);
+ int rc = -1;
+
+ if (parent != NULL) {
+ struct udevice udev_parent;
+ struct name_entry *name_loop;
+
+ dbg("found parent '%s', get the node name", parent->path);
+ udev_init_device(&udev_parent, NULL, NULL, NULL);
+ /* import the udev_db of the parent */
+ if (udev_db_get_device(&udev_parent, &parent->path[strlen(sysfs_path)]) == 0) {
+ dbg("import stored parent env '%s'", udev_parent.name);
+ list_for_each_entry(name_loop, &udev_parent.env_list, node) {
+ char name[NAME_SIZE];
+ char *pos;
+
+ strlcpy(name, name_loop->name, sizeof(name));
+ pos = strchr(name, '=');
+ if (pos) {
+ pos[0] = '\0';
+ pos++;
+ if (strcmp_pattern(filter, name) == 0) {
+ dbg("import key '%s'", name_loop->name);
+ name_list_add(&udev->env_list, name_loop->name, 0);
+ setenv(name, pos, 1);
+ } else
+ dbg("skip key '%s'", name_loop->name);
+ }
+ }
+ rc = 0;
+ } else
+ dbg("parent not found in database");
+ udev_cleanup_device(&udev_parent);
+ }
+
+ return rc;
+}
+
/* finds the lowest positive N such that <name>N isn't present in the udevdb
* if <name> doesn't exist, 0 is returned, N otherwise
*/
@@ -604,8 +644,10 @@ found:
break;
}
pos = getenv(attr);
- if (pos == NULL)
+ if (pos == NULL) {
+ dbg("env '%s' not avialable", attr);
break;
+ }
dbg("substitute env '%s=%s'", attr, pos);
strlcat(string, pos, maxsize);
break;
@@ -812,12 +854,15 @@ try_parent:
strlcpy(import, key_val(rule, &rule->import), sizeof(import));
apply_format(udev, import, sizeof(import), class_dev, sysfs_device);
dbg("check for IMPORT import='%s'", import);
- if (rule->import_exec) {
+ if (rule->import_type == IMPORT_PROGRAM) {
dbg("run executable file import='%s'", import);
rc = import_program_into_env(udev, import);
- } else {
+ } else if (rule->import_type == IMPORT_FILE) {
dbg("import file import='%s'", import);
rc = import_file_into_env(udev, import);
+ } else if (rule->import_type == IMPORT_PARENT && class_dev) {
+ dbg("import parent import='%s'", import);
+ rc = import_parent_into_env(udev, class_dev, import);
}
if (rc) {
dbg("IMPORT failed");
diff --git a/udev_rules.h b/udev_rules.h
index 959524a802..3f37d4b0b4 100644
--- a/udev_rules.h
+++ b/udev_rules.h
@@ -54,6 +54,13 @@ struct key_pairs {
struct key_pair keys[PAIRS_MAX];
};
+enum import_type {
+ IMPORT_UNSET,
+ IMPORT_PROGRAM,
+ IMPORT_FILE,
+ IMPORT_PARENT,
+};
+
struct udev_rule {
struct key kernel_name;
struct key subsystem;
@@ -66,6 +73,7 @@ struct udev_rule {
struct key result;
struct key modalias;
struct key import;
+ enum import_type import_type;
struct key wait_for_sysfs;
struct key_pairs sysfs;
struct key_pairs env;
@@ -81,8 +89,7 @@ struct udev_rule {
unsigned int partitions;
unsigned int last_rule:1,
ignore_device:1,
- ignore_remove:1,
- import_exec:1;
+ ignore_remove:1;
size_t bufsize;
char buf[];
diff --git a/udev_rules_parse.c b/udev_rules_parse.c
index 9483bcd71f..7c3c2e7fc2 100644
--- a/udev_rules_parse.c
+++ b/udev_rules_parse.c
@@ -311,9 +311,13 @@ static int add_to_rules(struct udev_rules *rules, char *line)
attr = get_key_attribute(key + sizeof("IMPORT")-1);
if (attr && strstr(attr, "program")) {
dbg("IMPORT will be executed");
- rule->import_exec = 1;
+ rule->import_type = IMPORT_PROGRAM;
} else if (attr && strstr(attr, "file")) {
dbg("IMPORT will be included as file");
+ rule->import_type = IMPORT_FILE;
+ } else if (attr && strstr(attr, "parent")) {
+ dbg("IMPORT will include the parent values");
+ rule->import_type = IMPORT_PARENT;
} else {
/* figure it out if it is executable */
char file[PATH_SIZE];
@@ -326,8 +330,11 @@ static int add_to_rules(struct udev_rules *rules, char *line)
pos[0] = '\0';
dbg("IMPORT auto mode for '%s'", file);
if (!lstat(file, &stats) && (stats.st_mode & S_IXUSR)) {
- dbg("IMPORT is executable, will be executed");
- rule->import_exec = 1;
+ dbg("IMPORT is executable, will be executed (autotype)");
+ rule->import_type = IMPORT_PROGRAM;
+ } else {
+ dbg("IMPORT is not executable, will be included as file (autotype)");
+ rule->import_type = IMPORT_FILE;
}
}
add_rule_key(rule, &rule->import, operation, value);