chiark / gitweb /
let $attr{symlink} return the last element of the path
authorKay Sievers <kay.sievers@suse.de>
Tue, 5 Sep 2006 00:18:06 +0000 (02:18 +0200)
committerKay Sievers <kay.sievers@suse.de>
Tue, 5 Sep 2006 00:18:06 +0000 (02:18 +0200)
Example for /block/sda:
  SUBSYSTEMS="scsi", ENV{COMMENT}="$attr{driver}"
sets COMMENT=sd
  SUBSYSTEMS="pci", ENV{COMMENT}="$attr{driver}"
sets COMMENT=ata_piix

test/udev-test.pl
udev_rules.c
udev_sysfs.c

index 464098f..54c3378 100755 (executable)
@@ -582,6 +582,24 @@ SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", NAME="bad"
 EOF
        },
        {
+               desc            => "substitute attr with link target value (first match)",
+               subsys          => "block",
+               devpath         => "/block/sda",
+               exp_name        => "driver-is-sd",
+               rules           => <<EOF
+SUBSYSTEMS=="scsi", NAME="driver-is-\$attr{driver}"
+EOF
+       },
+       {
+               desc            => "substitute attr with link target value (currently selected device)",
+               subsys          => "block",
+               devpath         => "/block/sda",
+               exp_name        => "driver-is-aic7xxx",
+               rules           => <<EOF
+SUBSYSTEMS=="pci", NAME="driver-is-\$attr{driver}"
+EOF
+       },
+       {
                desc            => "ignore ATTRS attribute whitespace",
                subsys          => "block",
                devpath         => "/block/sda",
index 1483f8f..edaaa71 100644 (file)
@@ -458,30 +458,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);
@@ -693,7 +705,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];
 
index c192696..e733d41 100644 (file)
@@ -346,6 +346,7 @@ char *sysfs_attr_get_value(const char *devpath, const char *attr_name)
        char value[NAME_SIZE];
        struct sysfs_attr *attr_loop;
        struct sysfs_attr *attr;
+       struct stat statbuf;
        int fd;
        ssize_t size;
        size_t sysfs_len;
@@ -375,25 +376,48 @@ char *sysfs_attr_get_value(const char *devpath, const char *attr_name)
        dbg("add to cache '%s'", path_full);
        list_add(&attr->node, &attr_list);
 
-       /* read attribute value */
-       fd = open(path_full, O_RDONLY);
-       if (fd < 0) {
-               dbg("attribute '%s' does not exist", path_full);
+       if (lstat(path_full, &statbuf) != 0) {
+               dbg("stat '%s' failed: %s", path_full, strerror(errno));
                goto out;
        }
-       size = read(fd, value, sizeof(value));
-       close(fd);
-       if (size < 0)
-               goto out;
-       if (size == sizeof(value))
-               goto out;
 
-       /* got a valid value, store and return it */
-       value[size] = '\0';
-       remove_trailing_chars(value, '\n');
-       dbg("cache '%s' with value '%s'", path_full, value);
-       strlcpy(attr->value_local, value, sizeof(attr->value_local));
-       attr->value = attr->value_local;
+       if (S_ISLNK(statbuf.st_mode)) {
+               /* links return the last element of the target path */
+               char link_target[PATH_SIZE];
+               int len;
+               const char *pos;
+
+               len = readlink(path_full, link_target, sizeof(link_target));
+               if (len > 0) {
+                       link_target[len] = '\0';
+                       pos = strrchr(link_target, '/');
+                       if (pos != NULL) {
+                               dbg("cache '%s' with link value '%s'", path_full, value);
+                               strlcpy(attr->value_local, &pos[1], sizeof(attr->value_local));
+                               attr->value = attr->value_local;
+                       }
+               }
+       } else {
+               /* read attribute value */
+               fd = open(path_full, O_RDONLY);
+               if (fd < 0) {
+                       dbg("attribute '%s' does not exist", path_full);
+                       goto out;
+               }
+               size = read(fd, value, sizeof(value));
+               close(fd);
+               if (size < 0)
+                       goto out;
+               if (size == sizeof(value))
+                       goto out;
+
+               /* got a valid value, store and return it */
+               value[size] = '\0';
+               remove_trailing_chars(value, '\n');
+               dbg("cache '%s' with attribute value '%s'", path_full, value);
+               strlcpy(attr->value_local, value, sizeof(attr->value_local));
+               attr->value = attr->value_local;
+       }
 
 out:
        return attr->value;