commit c7cf6a42715af61790470dc95c1b49e5e2e0ec4b Author: Hannes Reinecke Date: Thu Mar 20 09:17:00 2008 +0100 update sysfs code This updates the sysfs code to work with the latest driver core changes. Copied from udev sources. Signed-off-by: Hannes Reinecke diff --git a/libmultipath/sysfs.c b/libmultipath/sysfs.c index b9621ac..9f11b95 100644 --- a/libmultipath/sysfs.c +++ b/libmultipath/sysfs.c @@ -4,12 +4,12 @@ * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation version 2 of the License. - * + * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. - * + * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -58,7 +58,7 @@ int sysfs_init(char *path, size_t len) strlcpy(sysfs_path, path, len); remove_trailing_chars(sysfs_path, '/'); } else - strlcpy(sysfs_path, "/sys", len); + strlcpy(sysfs_path, "/sys", sizeof(sysfs_path)); dbg("sysfs_path='%s'", sysfs_path); INIT_LIST_HEAD(&attr_list); @@ -80,6 +80,7 @@ void sysfs_cleanup(void) } list_for_each_entry_safe(sysdev_loop, sysdev_temp, &sysfs_dev_list, node) { + list_del(&sysdev_loop->node); free(sysdev_loop); } } @@ -162,9 +163,23 @@ 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) { + dbg("invalid devpath '%s'", devpath); + return NULL; + } + dbg("open '%s'", devpath); strlcpy(devpath_real, devpath, sizeof(devpath_real)); remove_trailing_chars(devpath_real, '/'); + if (devpath[0] == '\0' ) + return NULL; /* if we got a link, resolve it to the real device */ strlcpy(path, sysfs_path, sizeof(path)); @@ -174,24 +189,26 @@ struct sysfs_device *sysfs_device_get(const char *devpath) dbg("stat '%s' failed: %s", path, strerror(errno)); list_for_each_entry(sysdev_loop, &sysfs_dev_list, node) { if (strcmp(sysdev_loop->dev.devpath, devpath_real) == 0) { - dbg("found vanished dev in cache '%s'", sysdev_loop->dev.devpath); + dbg("found vanished dev in cache '%s'", + sysdev_loop->dev.devpath); return &sysdev_loop->dev; } } return NULL; } + if (S_ISLNK(statbuf.st_mode)) { if (sysfs_resolve_link(devpath_real, sizeof(devpath_real)) != 0) return NULL; - } list_for_each_entry(sysdev_loop, &sysfs_dev_list, node) { if (strcmp(sysdev_loop->dev.devpath, devpath_real) == 0) { dbg("found dev in cache '%s'", sysdev_loop->dev.devpath); - dev = &sysdev_loop->dev; + dev = &sysdev_loop->dev; } } + if(!dev) { /* it is a new device */ dbg("new device '%s'", devpath_real); @@ -217,33 +234,25 @@ 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 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'; - } else if (strncmp(dev->devpath, "/block/", 7) == 0) { - strlcpy(dev->subsystem, "block", sizeof(dev->subsystem)); - } else if (strncmp(dev->devpath, "/devices/", 9) == 0) { - /* get subsystem from "bus" link */ - strlcpy(link_path, sysfs_path, sizeof(link_path)); - strlcat(link_path, dev->devpath, sizeof(link_path)); - strlcat(link_path, "/bus", sizeof(link_path)); - len = readlink(link_path, link_target, sizeof(link_target)); - if (len > 0) { - link_target[len] = '\0'; - dbg("bus 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 (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, "/class/", 7) == 0) { + pos = strrchr(dev->devpath, '/'); + if (pos == &dev->devpath[6]) + 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 */ @@ -258,6 +267,7 @@ struct sysfs_device *sysfs_device_get(const char *devpath) if (pos != NULL) strlcpy(dev->driver, &pos[1], sizeof(dev->driver)); } + return dev; } @@ -272,13 +282,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, "/subsystem/", 11) != 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); @@ -288,20 +291,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 subsystems top level we want to follow the old-style "device" link */ - if (strncmp(parent_devpath, "/subsystem", 10) == 0) { - pos = strrchr(parent_devpath, '/'); - if (pos == &parent_devpath[10] || pos == parent_devpath || strcmp(pos, "/devices") == 0) { - dbg("/subsystem 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) { @@ -314,6 +303,11 @@ struct sysfs_device *sysfs_device_get_parent(struct sysfs_device *dev) 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; @@ -375,6 +369,8 @@ char *sysfs_attr_get_value(const char *devpath, const char *attr_name) dbg("open '%s'/'%s'", devpath, attr_name); sysfs_len = strlcpy(path_full, sysfs_path, sizeof(path_full)); + if(sysfs_len >= sizeof(path_full)) + sysfs_len = sizeof(path_full) - 1; path = &path_full[sysfs_len]; strlcat(path_full, devpath, sizeof(path_full)); strlcat(path_full, "/", sizeof(path_full)); @@ -419,8 +415,10 @@ char *sysfs_attr_get_value(const char *devpath, const char *attr_name) 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)); + 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; } } @@ -438,7 +436,8 @@ char *sysfs_attr_get_value(const char *devpath, const char *attr_name) /* read attribute value */ fd = open(path_full, O_RDONLY); if (fd < 0) { - dbg("attribute '%s' does not exist", path_full); + dbg("attribute '%s' can not be opened: %s", + path_full, strerror(errno)); goto out; } size = read(fd, value, sizeof(value)); @@ -458,3 +457,95 @@ 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; +}