summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xtest/udev-test.pl23
-rw-r--r--udev.h5
-rw-r--r--udev_rules.c20
-rw-r--r--udev_rules.h6
-rw-r--r--udev_rules_parse.c11
5 files changed, 60 insertions, 5 deletions
diff --git a/test/udev-test.pl b/test/udev-test.pl
index 3172d3302f..27fe35456e 100755
--- a/test/udev-test.pl
+++ b/test/udev-test.pl
@@ -1306,6 +1306,29 @@ KERNEL=="sda", ACTION=="remove", RUN+="/bin/rm -f %r/testsymlink2"
KERNEL=="sda", NAME="not-ok2"
EOF
},
+ {
+ desc => "final assignment",
+ subsys => "block",
+ devpath => "/block/sda",
+ exp_name => "ok",
+ exp_perms => "root:nobody:0640",
+ rules => <<EOF
+KERNEL=="sda", GROUP:="nobody"
+KERNEL=="sda", GROUP="not-ok", MODE="0640", NAME="ok"
+EOF
+ },
+ {
+ desc => "final assignment",
+ subsys => "block",
+ devpath => "/block/sda",
+ exp_name => "ok",
+ exp_perms => "root:nobody:0640",
+ rules => <<EOF
+KERNEL=="sda", GROUP:="nobody"
+SUBSYSTEM=="block", MODE:="640"
+KERNEL=="sda", GROUP="not-ok", MODE="0666", NAME="ok"
+EOF
+ },
);
# set env
diff --git a/udev.h b/udev.h
index f7a65c60d8..c6f26b3bfb 100644
--- a/udev.h
+++ b/udev.h
@@ -64,11 +64,16 @@ struct udevice {
char name[PATH_SIZE];
char devname[PATH_SIZE];
struct list_head symlink_list;
+ int symlink_final;
char owner[USER_SIZE];
+ int owner_final;
char group[USER_SIZE];
+ int group_final;
mode_t mode;
+ int mode_final;
dev_t devt;
struct list_head run_list;
+ int run_final;
char tmp_node[PATH_SIZE];
int partitions;
diff --git a/udev_rules.c b/udev_rules.c
index 6f82fac841..42509f16ce 100644
--- a/udev_rules.c
+++ b/udev_rules.c
@@ -754,26 +754,34 @@ int udev_rules_get_name(struct udevice *udev, struct sysfs_class_device *class_d
}
/* apply permissions */
- if (rule->mode != 0000) {
+ if (!udev->mode_final && rule->mode != 0000) {
+ if (rule->mode_operation == KEY_OP_ASSIGN_FINAL)
+ udev->mode_final = 1;
udev->mode = rule->mode;
dbg("applied mode=%#o to '%s'", udev->mode, udev->kernel_name);
}
- if (rule->owner[0] != '\0') {
+ if (!udev->owner_final && rule->owner[0] != '\0') {
+ if (rule->owner_operation == KEY_OP_ASSIGN_FINAL)
+ udev->owner_final = 1;
strlcpy(udev->owner, rule->owner, sizeof(udev->owner));
apply_format(udev, udev->owner, sizeof(udev->owner), class_dev, sysfs_device);
dbg("applied owner='%s' to '%s'", udev->owner, udev->kernel_name);
}
- if (rule->group[0] != '\0') {
+ if (!udev->group_final && rule->group[0] != '\0') {
+ if (rule->group_operation == KEY_OP_ASSIGN_FINAL)
+ udev->group_final = 1;
strlcpy(udev->group, rule->group, sizeof(udev->group));
apply_format(udev, udev->group, sizeof(udev->group), class_dev, sysfs_device);
dbg("applied group='%s' to '%s'", udev->group, udev->kernel_name);
}
/* collect symlinks */
- if (rule->symlink[0] != '\0') {
+ if (!udev->symlink_final && rule->symlink[0] != '\0') {
char temp[PATH_SIZE];
char *pos, *next;
+ if (rule->symlink_operation == KEY_OP_ASSIGN_FINAL)
+ udev->symlink_final = 1;
info("configured rule in '%s[%i]' applied, added symlink '%s'",
rule->config_file, rule->config_line, rule->symlink);
strlcpy(temp, rule->symlink, sizeof(temp));
@@ -808,9 +816,11 @@ int udev_rules_get_name(struct udevice *udev, struct sysfs_class_device *class_d
udev->name, udev->owner, udev->group, udev->mode, udev->partitions);
}
- if (rule->run[0] != '\0') {
+ if (!udev->run_final && rule->run[0] != '\0') {
char program[PATH_SIZE];
+ if (rule->run_operation == KEY_OP_ASSIGN_FINAL)
+ udev->run_final = 1;
strlcpy(program, rule->run, sizeof(program));
apply_format(udev, program, sizeof(program), class_dev, sysfs_device);
dbg("add run '%s'", program);
diff --git a/udev_rules.h b/udev_rules.h
index 5fba2d5571..f4a74bba45 100644
--- a/udev_rules.h
+++ b/udev_rules.h
@@ -62,6 +62,7 @@ enum key_operation {
KEY_OP_NOMATCH,
KEY_OP_ADD,
KEY_OP_ASSIGN,
+ KEY_OP_ASSIGN_FINAL,
};
struct key_pair {
@@ -96,10 +97,15 @@ struct udev_rule {
char name[PATH_SIZE];
char symlink[PATH_SIZE];
+ enum key_operation symlink_operation;
char owner[USER_SIZE];
+ enum key_operation owner_operation;
char group[USER_SIZE];
+ enum key_operation group_operation;
mode_t mode;
+ enum key_operation mode_operation;
char run[PATH_SIZE];
+ enum key_operation run_operation;
int last_rule;
int ignore_device;
diff --git a/udev_rules_parse.c b/udev_rules_parse.c
index e665957b81..3f07521ccb 100644
--- a/udev_rules_parse.c
+++ b/udev_rules_parse.c
@@ -89,6 +89,8 @@ static int get_key(char **line, char **key, enum key_operation *operation, char
break;
if (linepos[0] == '!')
break;
+ if (linepos[0] == ':')
+ break;
}
/* remember end of key */
@@ -115,6 +117,10 @@ static int get_key(char **line, char **key, enum key_operation *operation, char
*operation = KEY_OP_ASSIGN;
linepos++;
dbg("operator=assign");
+ } else if (linepos[0] == ':' && linepos[1] == '=') {
+ *operation = KEY_OP_ASSIGN_FINAL;
+ linepos += 2;
+ dbg("operator=assign_final");
} else
return -1;
@@ -364,30 +370,35 @@ static int rules_parse(const char *filename)
if (strcasecmp(key, KEY_SYMLINK) == 0) {
strlcpy(rule.symlink, value, sizeof(rule.symlink));
+ rule.symlink_operation = operation;
valid = 1;
continue;
}
if (strcasecmp(key, KEY_OWNER) == 0) {
strlcpy(rule.owner, value, sizeof(rule.owner));
+ rule.owner_operation = operation;
valid = 1;
continue;
}
if (strcasecmp(key, KEY_GROUP) == 0) {
strlcpy(rule.group, value, sizeof(rule.group));
+ rule.group_operation = operation;
valid = 1;
continue;
}
if (strcasecmp(key, KEY_MODE) == 0) {
rule.mode = strtol(value, NULL, 8);
+ rule.mode_operation = operation;
valid = 1;
continue;
}
if (strcasecmp(key, KEY_RUN) == 0) {
strlcpy(rule.run, value, sizeof(rule.run));
+ rule.run_operation = operation;
valid = 1;
continue;
}