diff --git a/keventd/rules.c b/keventd/rules.c index 2ef4a9f2..d1a7c8d3 100644 --- a/keventd/rules.c +++ b/keventd/rules.c @@ -602,12 +602,12 @@ static void subst_value(const char *src, char *buf, size_t bufsz, if (al >= sizeof(attr)) al = sizeof(attr) - 1; - memcpy(attr, as, al); - attr[al] = 0; - if (!sysfs_read_attr(ev->devpath, attr, - tmp, sizeof(tmp))) - append_str(buf, &pos, bufsz, tmp); - p = ae + 1; + memcpy(attr, as, al); + attr[al] = 0; + if (!sysfs_read_attr_chain(ev->devpath, attr, + tmp, sizeof(tmp))) + append_str(buf, &pos, bufsz, tmp); + p = ae + 1; } else { buf[pos++] = '%'; buf[pos] = 0; } @@ -681,7 +681,8 @@ static void subst_value(const char *src, char *buf, size_t bufsz, al = sizeof(attr) - 1; memcpy(attr, as, al); attr[al] = 0; - if (!sysfs_read_attr(ev->devpath, attr, tmp, sizeof(tmp))) + if (!sysfs_read_attr_chain(ev->devpath, attr, + tmp, sizeof(tmp))) append_str(buf, &pos, bufsz, tmp); p = ae + 1; } else { diff --git a/keventd/sysfs.c b/keventd/sysfs.c index a9e88326..763f2791 100644 --- a/keventd/sysfs.c +++ b/keventd/sysfs.c @@ -61,6 +61,41 @@ int sysfs_read_attr(const char *devpath, const char *attr, return sysfs_read_file(path, buf, len); } +struct attr_ctx { + const char *attr; + char *buf; + size_t len; +}; + +static int attr_cb(const char *syspath, void *data) +{ + struct attr_ctx *ctx = data; + char path[PATH_MAX]; + + snprintf(path, sizeof(path), "%s/%s", syspath, ctx->attr); + if (sysfs_read_file(path, ctx->buf, ctx->len) == 0) + return 0; /* found, stop walking */ + + return 1; +} + +int sysfs_read_attr_chain(const char *devpath, const char *attr, + char *buf, size_t len) +{ + struct attr_ctx ctx = { attr, buf, len }; + + if (!devpath || !attr || !*attr) + return -1; + + /* Device itself first then walk up toward the parent devices */ + if (sysfs_read_attr(devpath, attr, buf, len) == 0) + return 0; + + sysfs_parent_walk(devpath, attr_cb, &ctx); + + return buf[0] ? 0 : -1; +} + int sysfs_parent_walk(const char *devpath, int (*cb)(const char *syspath, void *data), void *data) diff --git a/keventd/sysfs.h b/keventd/sysfs.h index 576a7914..64713862 100644 --- a/keventd/sysfs.h +++ b/keventd/sysfs.h @@ -40,6 +40,15 @@ int sysfs_read_file(const char *path, char *buf, size_t len); int sysfs_read_attr(const char *devpath, const char *attr, char *buf, size_t len); +/* + * Read a sysfs attribute for the device at /sys{devpath}, falling back + * to the parent chain, partitions have no "serial" of their own, it + * lives in the parent disk's sysfs directory. + * Returns 0 on success, -1 if no level of the chain has the attribute. + */ +int sysfs_read_attr_chain(const char *devpath, const char *attr, + char *buf, size_t len); + /* * Walk the sysfs device tree upward from devpath toward /sys/devices, * calling cb at each level. cb receives the absolute syspath and the