X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=udev_rules.c;h=d1c3f042c390ce5dd4c913a664159ffce350f1c2;hp=8a2066d70931dee89a915d13b92d7360584c5e7f;hb=1bcfb137e838a9fa8c607aa2e88b1b1f0716f296;hpb=27b77df44daebbd7597c572343105c16de099233 diff --git a/udev_rules.c b/udev_rules.c index 8a2066d70..d1c3f042c 100644 --- a/udev_rules.c +++ b/udev_rules.c @@ -364,6 +364,8 @@ void udev_rules_apply_format(struct udevice *udev, char *string, size_t maxsize) goto found; } } + head[0] = '$'; + err("unknown format variable '%s'", head); } else if (head[0] == '%') { /* substitute format char */ if (head[1] == '\0') @@ -385,6 +387,8 @@ void udev_rules_apply_format(struct udevice *udev, char *string, size_t maxsize) goto found; } } + head[0] = '%'; + err("unknown format char '%c'", tail[0]); } head++; } @@ -458,30 +462,42 @@ found: } break; case SUBST_ATTR: - if (attr == NULL) { - dbg("missing attribute"); - break; - } else { - struct sysfs_device *dev_parent; - const char *value; + if (attr == NULL) + err("missing file parameter for attr"); + else { + 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) + value = sysfs_attr_get_value(udev->dev_parent->devpath, attr); + + /* look at all devices along the chain of parents */ + if (value == NULL) { + struct sysfs_device *dev_parent = udev->dev; + + do { + dbg("looking at '%s'", dev_parent->devpath); + value = sysfs_attr_get_value(dev_parent->devpath, attr); + if (value != NULL) { + strlcpy(temp2, value, sizeof(temp2)); + break; + } + dev_parent = sysfs_device_get_parent(dev_parent); + } while (dev_parent != NULL); + } - dev_parent = udev->dev; - do { - dbg("looking at '%s'", dev_parent->devpath); - value = sysfs_attr_get_value(dev_parent->devpath, attr); - if (value != NULL) { - strlcpy(temp2, value, sizeof(temp2)); - break; - } - dev_parent = sysfs_device_get_parent(dev_parent); - } while (dev_parent != NULL); + if (value == NULL) + break; - /* strip trailing whitespace of sysfs value */ - i = strlen(temp2); - while (i > 0 && isspace(temp2[i-1])) - temp2[--i] = '\0'; + /* strip trailing whitespace and replace untrusted characters of sysfs value */ + size = strlcpy(temp2, value, sizeof(temp2)); + if (size >= sizeof(temp2)) + size = sizeof(temp2)-1; + while (size > 0 && isspace(temp2[size-1])) + temp2[--size] = '\0'; count = replace_untrusted_chars(temp2); - if (count) + if (count > 0) info("%i untrusted character(s) replaced" , count); strlcat(string, temp2, maxsize); dbg("substitute sysfs value '%s'", temp2); @@ -542,7 +558,7 @@ found: break; } /* possibly truncate to format-char specified length */ - if (len != -1) { + if (len >= 0 && len < (int)strlen(head)) { head[len] = '\0'; dbg("truncate to %i chars, subtitution string becomes '%s'", len, head); } @@ -693,7 +709,7 @@ static int match_rule(struct udevice *udev, struct udev_rule *rule) if (match_key("DRIVERS", rule, &rule->drivers, udev->dev_parent->driver)) goto try_parent; - /* check for matching sysfs attrubute pairs */ + /* check for matching sysfs attribute pairs */ for (i = 0; i < rule->attrs.count; i++) { struct key_pair *pair = &rule->attrs.keys[i]; @@ -802,13 +818,19 @@ try_parent: struct key_pair *pair = &rule->env.keys[i]; if (pair->key.operation == KEY_OP_ASSIGN) { + char temp_value[NAME_SIZE]; const char *key_name = key_pair_name(rule, pair); const char *value = key_val(rule, &pair->key); - char *key_value = name_list_key_add(&udev->env_list, key_name, value); + char *key_value; + + /* make sure we don't write to the same string we possibly read from */ + strlcpy(temp_value, value, sizeof(temp_value)); + udev_rules_apply_format(udev, temp_value, NAME_SIZE); + + key_value = name_list_key_add(&udev->env_list, key_name, temp_value); if (key_value == NULL) break; - udev_rules_apply_format(udev, key_value, NAME_SIZE); putenv(key_value); dbg("export ENV '%s'", key_value); }