diff options
-rwxr-xr-x | test/udev-test.pl | 23 | ||||
-rw-r--r-- | udev.h | 5 | ||||
-rw-r--r-- | udev_rules.c | 20 | ||||
-rw-r--r-- | udev_rules.h | 6 | ||||
-rw-r--r-- | udev_rules_parse.c | 11 |
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 @@ -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; } |