X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=udev_sysfs.c;h=34ae9ac14fd400758d5d3a618dc527d19a9bbd54;hp=0e448894fef8f3c6edee1a0cd49cdd631f4d2893;hb=fcfeda1907035a3d3c7afc67ad38b032b87f36d9;hpb=82c60ce57206148d00e8d3a210a72a0e7f2aa380 diff --git a/udev_sysfs.c b/udev_sysfs.c index 0e448894f..34ae9ac14 100644 --- a/udev_sysfs.c +++ b/udev_sysfs.c @@ -92,7 +92,6 @@ void sysfs_device_set_values(struct sysfs_device *dev, const char *devpath, pos = strrchr(dev->devpath, '/'); if (pos == NULL) return; - strlcpy(dev->kernel, &pos[1], sizeof(dev->kernel)); dbg("kernel='%s'", dev->kernel); @@ -156,9 +155,21 @@ struct sysfs_device *sysfs_device_get(const char *devpath) int len; char *pos; + /* we handle only these devpathes */ + if (devpath != NULL && + strncmp(devpath, "/devices/", 9) != 0 && + strncmp(devpath, "/subsystem/", 11) != 0 && + strncmp(devpath, "/module/", 8) != 0 && + strncmp(devpath, "/bus/", 5) != 0 && + strncmp(devpath, "/class/", 7) != 0 && + strncmp(devpath, "/block/", 7) != 0) + return NULL; + dbg("open '%s'", devpath); strlcpy(devpath_real, devpath, sizeof(devpath_real)); remove_trailing_chars(devpath_real, '/'); + if (devpath[0] == '\0' ) + return NULL; /* look for device already in cache (we never put an untranslated path in the cache) */ list_for_each_entry(dev_loop, &dev_list, node) { @@ -197,14 +208,26 @@ struct sysfs_device *sysfs_device_get(const char *devpath) sysfs_device_set_values(dev, devpath_real, NULL, NULL); - /* get subsystem */ - if (strncmp(dev->devpath, "/class/", 7) == 0) { + /* get subsystem name */ + strlcpy(link_path, sysfs_path, sizeof(link_path)); + strlcat(link_path, dev->devpath, sizeof(link_path)); + strlcat(link_path, "/subsystem", sizeof(link_path)); + len = readlink(link_path, link_target, sizeof(link_target)); + if (len > 0) { + /* get subsystem from "subsystem" link */ + link_target[len] = '\0'; + dbg("subsystem link '%s' points to '%s'", link_path, link_target); + pos = strrchr(link_target, '/'); + if (pos != NULL) + strlcpy(dev->subsystem, &pos[1], sizeof(dev->subsystem)); + } else if (strncmp(dev->devpath, "/class/", 7) == 0) { + /* get subsystem from class dir */ strlcpy(dev->subsystem, &dev->devpath[7], sizeof(dev->subsystem)); pos = strchr(dev->subsystem, '/'); if (pos != NULL) pos[0] = '\0'; else - dev->subsystem[0] = '\0'; + strlcpy(dev->subsystem, "subsystem", sizeof(dev->subsystem)); } else if (strncmp(dev->devpath, "/block/", 7) == 0) { strlcpy(dev->subsystem, "block", sizeof(dev->subsystem)); } else if (strncmp(dev->devpath, "/devices/", 9) == 0) { @@ -219,36 +242,32 @@ struct sysfs_device *sysfs_device_get(const char *devpath) pos = strrchr(link_target, '/'); if (pos != NULL) strlcpy(dev->subsystem, &pos[1], sizeof(dev->subsystem)); - } else { - /* get subsystem from "subsystem" link */ - strlcpy(link_path, sysfs_path, sizeof(link_path)); - strlcat(link_path, dev->devpath, sizeof(link_path)); - strlcat(link_path, "/subsystem", sizeof(link_path)); - len = readlink(link_path, link_target, sizeof(link_target)); - if (len > 0) { - link_target[len] = '\0'; - dbg("subsystem link '%s' points to '%s'", link_path, link_target); - pos = strrchr(link_target, '/'); - if (pos != NULL) - strlcpy(dev->subsystem, &pos[1], sizeof(dev->subsystem)); - } - } - /* get driver name */ - strlcpy(link_path, sysfs_path, sizeof(link_path)); - strlcat(link_path, dev->devpath, sizeof(link_path)); - strlcat(link_path, "/driver", sizeof(link_path)); - len = readlink(link_path, link_target, sizeof(link_target)); - if (len > 0) { - link_target[len] = '\0'; - dbg("driver link '%s' points to '%s'", link_path, link_target); - pos = strrchr(link_target, '/'); - if (pos != NULL) - strlcpy(dev->driver, &pos[1], sizeof(dev->driver)); } - } else if (strncmp(dev->devpath, "/bus/", 5) == 0 && strstr(dev->devpath, "/drivers/")) { + } else if (strstr(dev->devpath, "/drivers/") != NULL) { strlcpy(dev->subsystem, "drivers", sizeof(dev->subsystem)); } else if (strncmp(dev->devpath, "/module/", 8) == 0) { strlcpy(dev->subsystem, "module", sizeof(dev->subsystem)); + } else if (strncmp(dev->devpath, "/subsystem/", 11) == 0) { + pos = strrchr(dev->devpath, '/'); + if (pos == &dev->devpath[10]) + strlcpy(dev->subsystem, "subsystem", sizeof(dev->subsystem)); + } else if (strncmp(dev->devpath, "/bus/", 5) == 0) { + pos = strrchr(dev->devpath, '/'); + if (pos == &dev->devpath[4]) + strlcpy(dev->subsystem, "subsystem", sizeof(dev->subsystem)); + } + + /* get driver name */ + strlcpy(link_path, sysfs_path, sizeof(link_path)); + strlcat(link_path, dev->devpath, sizeof(link_path)); + strlcat(link_path, "/driver", sizeof(link_path)); + len = readlink(link_path, link_target, sizeof(link_target)); + if (len > 0) { + link_target[len] = '\0'; + dbg("driver link '%s' points to '%s'", link_path, link_target); + pos = strrchr(link_target, '/'); + if (pos != NULL) + strlcpy(dev->driver, &pos[1], sizeof(dev->driver)); } dbg("add to cache 'devpath=%s', subsystem='%s', driver='%s'", dev->devpath, dev->subsystem, dev->driver); @@ -268,12 +287,6 @@ struct sysfs_device *sysfs_device_get_parent(struct sysfs_device *dev) if (dev->parent != NULL) return dev->parent; - /* requesting a parent is only valid for devices */ - if ((strncmp(dev->devpath, "/devices/", 9) != 0) && - (strncmp(dev->devpath, "/class/", 7) != 0) && - (strncmp(dev->devpath, "/block/", 7) != 0)) - return NULL; - strlcpy(parent_devpath, dev->devpath, sizeof(parent_devpath)); dbg("'%s'", parent_devpath); @@ -283,17 +296,6 @@ struct sysfs_device *sysfs_device_get_parent(struct sysfs_device *dev) return NULL; pos[0] = '\0'; - /* are we at the top level of /devices */ - if (strcmp(parent_devpath, "/devices") == 0) { - dbg("/devices top level"); - return NULL; - } - - /* at the top level of class/block we want to follow the "device" link */ - if (strcmp(parent_devpath, "/block") == 0) { - dbg("/block top level, look for device link"); - goto device_link; - } if (strncmp(parent_devpath, "/class", 6) == 0) { pos = strrchr(parent_devpath, '/'); if (pos == &parent_devpath[6] || pos == parent_devpath) { @@ -301,6 +303,16 @@ struct sysfs_device *sysfs_device_get_parent(struct sysfs_device *dev) goto device_link; } } + if (strcmp(parent_devpath, "/block") == 0) { + dbg("/block top level, look for device link"); + goto device_link; + } + + /* are we at the top level? */ + pos = strrchr(parent_devpath, '/'); + if (pos == NULL || pos == parent_devpath) + return NULL; + /* get parent and remember it */ dev->parent = sysfs_device_get(parent_devpath); return dev->parent; @@ -421,3 +433,94 @@ char *sysfs_attr_get_value(const char *devpath, const char *attr_name) out: return attr->value; } + +int sysfs_lookup_devpath_by_subsys_id(char *devpath_full, size_t len, const char *subsystem, const char *id) +{ + size_t sysfs_len; + char path_full[PATH_SIZE]; + char *path; + struct stat statbuf; + + sysfs_len = strlcpy(path_full, sysfs_path, sizeof(path_full)); + path = &path_full[sysfs_len]; + + if (strcmp(subsystem, "subsystem") == 0) { + strlcpy(path, "/subsystem/", sizeof(path_full) - sysfs_len); + strlcat(path, id, sizeof(path_full) - sysfs_len); + if (stat(path_full, &statbuf) == 0) + goto found; + + strlcpy(path, "/bus/", sizeof(path_full) - sysfs_len); + strlcat(path, id, sizeof(path_full) - sysfs_len); + if (stat(path_full, &statbuf) == 0) + goto found; + goto out; + + strlcpy(path, "/class/", sizeof(path_full) - sysfs_len); + strlcat(path, id, sizeof(path_full) - sysfs_len); + if (stat(path_full, &statbuf) == 0) + goto found; + } + + if (strcmp(subsystem, "module") == 0) { + strlcpy(path, "/module/", sizeof(path_full) - sysfs_len); + strlcat(path, id, sizeof(path_full) - sysfs_len); + if (stat(path_full, &statbuf) == 0) + goto found; + goto out; + } + + if (strcmp(subsystem, "drivers") == 0) { + char subsys[NAME_SIZE]; + char *driver; + + strlcpy(subsys, id, sizeof(subsys)); + driver = strchr(subsys, ':'); + if (driver != NULL) { + driver[0] = '\0'; + driver = &driver[1]; + strlcpy(path, "/subsystem/", sizeof(path_full) - sysfs_len); + strlcat(path, subsys, sizeof(path_full) - sysfs_len); + strlcat(path, "/drivers/", sizeof(path_full) - sysfs_len); + strlcat(path, driver, sizeof(path_full) - sysfs_len); + if (stat(path_full, &statbuf) == 0) + goto found; + + strlcpy(path, "/bus/", sizeof(path_full) - sysfs_len); + strlcat(path, subsys, sizeof(path_full) - sysfs_len); + strlcat(path, "/drivers/", sizeof(path_full) - sysfs_len); + strlcat(path, driver, sizeof(path_full) - sysfs_len); + if (stat(path_full, &statbuf) == 0) + goto found; + } + goto out; + } + + strlcpy(path, "/subsystem/", sizeof(path_full) - sysfs_len); + strlcat(path, subsystem, sizeof(path_full) - sysfs_len); + strlcat(path, "/devices/", sizeof(path_full) - sysfs_len); + strlcat(path, id, sizeof(path_full) - sysfs_len); + if (stat(path_full, &statbuf) == 0) + goto found; + + strlcpy(path, "/bus/", sizeof(path_full) - sysfs_len); + strlcat(path, subsystem, sizeof(path_full) - sysfs_len); + strlcat(path, "/devices/", sizeof(path_full) - sysfs_len); + strlcat(path, id, sizeof(path_full) - sysfs_len); + if (stat(path_full, &statbuf) == 0) + goto found; + + strlcpy(path, "/class/", sizeof(path_full) - sysfs_len); + strlcat(path, subsystem, sizeof(path_full) - sysfs_len); + strlcat(path, "/", sizeof(path_full) - sysfs_len); + strlcat(path, id, sizeof(path_full) - sysfs_len); + if (stat(path_full, &statbuf) == 0) + goto found; +out: + return 0; +found: + if (S_ISLNK(statbuf.st_mode)) + sysfs_resolve_link(path, sizeof(path_full) - sysfs_len); + strlcpy(devpath_full, path, len); + return 1; +}