X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=udev_rules.c;h=cbd76e66ebe84f3f4f31a82fdffa3de0c1e69973;hp=069dec7d047286b455c42af64dfcf9d94d309739;hb=d27d8d6a8d63ffce768842324dd53067b9b0e905;hpb=fb39f0566e248c09772ed15a3218ef2381700b6a diff --git a/udev_rules.c b/udev_rules.c index 069dec7d0..cbd76e66e 100644 --- a/udev_rules.c +++ b/udev_rules.c @@ -474,6 +474,21 @@ static int match_rule(struct udevice *udev, struct udev_rule *rule, { 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' udev_kernel_name='%s'", rule->kernel, udev->kernel_name); @@ -716,12 +731,17 @@ 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_set && rule->name_operation != KEY_OP_UNSET) { + 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; @@ -734,72 +754,116 @@ 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_operation != KEY_OP_UNSET) { char temp[PATH_SIZE]; char *pos, *next; - 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'; + if (rule->symlink_operation == KEY_OP_ASSIGN_FINAL) + udev->symlink_final = 1; + 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); + } + } + 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'; + 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); } - /* rule matches */ - 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); + /* set name, later rules with name set will be ignored */ + 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; + + 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); + } + } - 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->run_final && rule->run_operation != KEY_OP_UNSET) { + char program[PATH_SIZE]; - 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 (rule->run_operation == KEY_OP_ASSIGN_FINAL) + udev->run_final = 1; + if (rule->run_operation == KEY_OP_ASSIGN || rule->run_operation == KEY_OP_ASSIGN_FINAL) { + struct name_entry *name_loop; + struct name_entry *temp_loop; - break; + 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 (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) { 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); } @@ -812,3 +876,61 @@ int udev_rules_get_name(struct udevice *udev, struct sysfs_class_device *class_d return 0; } + +int udev_rules_get_run(struct udevice *udev, struct sysfs_device *sysfs_device) +{ + struct udev_rule *rule; + + /* look for a matching rule to apply */ + list_for_each_entry(rule, &udev_rule_list, node) { + dbg("process rule"); + + if (rule->run_operation == KEY_OP_UNSET) + continue; + + 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 (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; + } + + if (!udev->run_final && rule->run_operation != KEY_OP_UNSET) { + char program[PATH_SIZE]; + + 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); + } + } + 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; + } + + if (rule->last_rule) { + dbg("last rule to be applied"); + break; + } + } + } + + return 0; +}