X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=udev_rules.c;h=598c1ba7393a9d62828404abf88647dee4e8433e;hb=4ad47b2de6534dce23fd3182ec1e7472e299b05f;hp=e61c9a69b062c02fa2fe083911cc964ba8789d3e;hpb=5e9eb88f2f6d99eaee16aeeb76ac08a1bf98a668;p=elogind.git diff --git a/udev_rules.c b/udev_rules.c index e61c9a69b..598c1ba73 100644 --- a/udev_rules.c +++ b/udev_rules.c @@ -267,10 +267,48 @@ static int wait_for_sysfs(struct udevice *udev, const char *file, int timeout) info("wait for '%s' for %i mseconds", filepath, 1000 / WAIT_LOOP_PER_SECOND); usleep(1000 * 1000 / WAIT_LOOP_PER_SECOND); } - err("waiting for '%s' failed", filepath); + info("waiting for '%s' failed", filepath); return -1; } +/* handle "[$SUBSYSTEM/$KERNEL]" lookup */ +static int attr_get_by_subsys_id(const char *attrstr, char *devpath, size_t len, char **attr) +{ + char subsys[NAME_SIZE]; + char *attrib; + char *id; + int found = 0; + + if (attrstr[0] != '[') + goto out; + + strlcpy(subsys, &attrstr[1], sizeof(subsys)); + + attrib = strchr(subsys, ']'); + if (attrib == NULL) + goto out; + attrib[0] = '\0'; + attrib = &attrib[1]; + + id = strchr(subsys, '/'); + if (id == NULL) + goto out; + id[0] = '\0'; + id = &id[1]; + + if (sysfs_lookup_devpath_by_subsys_id(devpath, len, subsys, id)) { + if (attr != NULL) { + if (attrib[0] != '\0') + *attr = attrib; + else + *attr = NULL; + } + found = 1; + } +out: + return found; +} + void udev_rules_apply_format(struct udevice *udev, char *string, size_t maxsize) { char temp[PATH_SIZE]; @@ -443,11 +481,20 @@ found: if (attr == NULL) err("missing file parameter for attr"); else { + char devpath[PATH_SIZE]; + char *attrib; const char *value = NULL; size_t size; - /* first try the current device, other matches may have selected */ - if (udev->dev_parent != NULL && udev->dev_parent != udev->dev) + if (attr_get_by_subsys_id(attr, devpath, sizeof(devpath), &attrib)) { + if (attrib != NULL) + value = sysfs_attr_get_value(devpath, attrib); + else + break; + } + + /* try the current device, other matches may have selected */ + if (value == NULL && udev->dev_parent != NULL && udev->dev_parent != udev->dev) value = sysfs_attr_get_value(udev->dev_parent->devpath, attr); /* look at all devices along the chain of parents */ @@ -641,6 +688,40 @@ static int match_rule(struct udevice *udev, struct udev_rule *rule) } } + if (rule->test.operation != KEY_OP_UNSET) { + char filename[PATH_SIZE]; + char devpath[PATH_SIZE]; + char *attr; + struct stat statbuf; + int match; + + strlcpy(filename, key_val(rule, &rule->test), sizeof(filename)); + udev_rules_apply_format(udev, filename, sizeof(filename)); + + if (attr_get_by_subsys_id(filename, devpath, sizeof(devpath), &attr)) { + strlcpy(filename, sysfs_path, sizeof(filename)); + strlcat(filename, devpath, sizeof(filename)); + if (attr != NULL) { + strlcat(filename, "/", sizeof(filename)); + strlcat(filename, attr, sizeof(filename)); + } + } + + match = (stat(filename, &statbuf) == 0); + info("'%s' %s", filename, match ? "exists" : "does not exist"); + if (match && rule->test_mode_mask > 0) { + match = ((statbuf.st_mode & rule->test_mode_mask) > 0); + info("'%s' has mode=%#o and %s %#o", filename, statbuf.st_mode, + match ? "matches" : "does not match", + rule->test_mode_mask); + } + if (match && rule->test.operation == KEY_OP_NOMATCH) + goto nomatch; + if (!match && rule->test.operation == KEY_OP_MATCH) + goto nomatch; + dbg("TEST key is true"); + } + if (rule->wait_for_sysfs.operation != KEY_OP_UNSET) { int found; @@ -657,11 +738,20 @@ static int match_rule(struct udevice *udev, struct udev_rule *rule) pair->key.operation == KEY_OP_NOMATCH) { const char *key_name = key_pair_name(rule, pair); const char *key_value = key_val(rule, &pair->key); - const char *value; + char devpath[PATH_SIZE]; + char *attrib; + const char *value = NULL; char val[VALUE_SIZE]; size_t len; - value = sysfs_attr_get_value(udev->dev->devpath, key_name); + if (attr_get_by_subsys_id(key_name, devpath, sizeof(devpath), &attrib)) { + if (attrib != NULL) + value = sysfs_attr_get_value(devpath, attrib); + else + goto nomatch; + } + if (value == NULL) + value = sysfs_attr_get_value(udev->dev->devpath, key_name); if (value == NULL) goto nomatch; strlcpy(val, value, sizeof(val)); @@ -1037,7 +1127,8 @@ int udev_rules_get_run(struct udev_rules *rules, struct udevice *udev) dbg("process rule"); if (rule->name.operation != KEY_OP_UNSET || rule->symlink.operation != KEY_OP_UNSET || - rule->mode_operation != KEY_OP_UNSET || rule->owner.operation != KEY_OP_UNSET || rule->group.operation != KEY_OP_UNSET) { + rule->mode_operation != KEY_OP_UNSET || rule->owner.operation != KEY_OP_UNSET || + rule->group.operation != KEY_OP_UNSET) { dbg("skip rule that names a device"); continue; } @@ -1050,7 +1141,8 @@ int udev_rules_get_run(struct udev_rules *rules, struct udevice *udev) } if (!udev->run_final && rule->run.operation != KEY_OP_UNSET) { - if (rule->run.operation == KEY_OP_ASSIGN || rule->run.operation == KEY_OP_ASSIGN_FINAL) { + if (rule->run.operation == KEY_OP_ASSIGN || + rule->run.operation == KEY_OP_ASSIGN_FINAL) { info("reset run list"); name_list_cleanup(&udev->run_list); }