diff options
Diffstat (limited to 'libsysfs')
-rw-r--r-- | libsysfs/libsysfs.h | 36 | ||||
-rw-r--r-- | libsysfs/sysfs_bus.c | 49 | ||||
-rw-r--r-- | libsysfs/sysfs_class.c | 201 | ||||
-rw-r--r-- | libsysfs/sysfs_device.c | 72 | ||||
-rw-r--r-- | libsysfs/sysfs_dir.c | 227 | ||||
-rw-r--r-- | libsysfs/sysfs_driver.c | 86 | ||||
-rw-r--r-- | libsysfs/sysfs_utils.c | 144 |
7 files changed, 567 insertions, 248 deletions
diff --git a/libsysfs/libsysfs.h b/libsysfs/libsysfs.h index 2ffe1005cc..10faab92aa 100644 --- a/libsysfs/libsysfs.h +++ b/libsysfs/libsysfs.h @@ -62,18 +62,20 @@ struct sysfs_link { }; struct sysfs_directory { + unsigned char name[SYSFS_NAME_LEN]; + unsigned char path[SYSFS_PATH_MAX]; + + /* Private: for internal use only */ struct dlist *subdirs; struct dlist *links; struct dlist *attributes; - unsigned char name[SYSFS_NAME_LEN]; - unsigned char path[SYSFS_PATH_MAX]; }; struct sysfs_driver { unsigned char name[SYSFS_NAME_LEN]; unsigned char path[SYSFS_PATH_MAX]; - /* for internal use only */ + /* Private: for internal use only */ struct dlist *devices; struct sysfs_directory *directory; }; @@ -85,7 +87,7 @@ struct sysfs_device { unsigned char driver_name[SYSFS_NAME_LEN]; unsigned char path[SYSFS_PATH_MAX]; - /* for internal use only */ + /* Private: for internal use only */ struct sysfs_device *parent; struct dlist *children; struct sysfs_directory *directory; @@ -95,7 +97,7 @@ struct sysfs_root_device { unsigned char name[SYSFS_NAME_LEN]; unsigned char path[SYSFS_PATH_MAX]; - /* for internal use only */ + /* Private: for internal use only */ struct dlist *devices; struct sysfs_directory *directory; }; @@ -104,7 +106,7 @@ struct sysfs_bus { unsigned char name[SYSFS_NAME_LEN]; unsigned char path[SYSFS_PATH_MAX]; - /* internal use only */ + /* Private: for internal use only */ struct dlist *drivers; struct dlist *devices; struct sysfs_directory *directory; @@ -115,7 +117,7 @@ struct sysfs_class_device { unsigned char classname[SYSFS_NAME_LEN]; unsigned char path[SYSFS_PATH_MAX]; - /* for internal use only */ + /* Private: for internal use only */ struct sysfs_class_device *parent; struct sysfs_device *sysdevice; /* NULL if virtual */ struct sysfs_driver *driver; /* NULL if not implemented */ @@ -126,7 +128,7 @@ struct sysfs_class { unsigned char name[SYSFS_NAME_LEN]; unsigned char path[SYSFS_PATH_MAX]; - /* for internal use only */ + /* Private: for internal use only */ struct dlist *devices; struct sysfs_directory *directory; }; @@ -138,8 +140,8 @@ extern "C" { /* * Function Prototypes */ -extern int sysfs_trailing_slash(unsigned char *path); extern int sysfs_get_mnt_path(unsigned char *mnt_path, size_t len); +extern int sysfs_remove_trailing_slash(unsigned char *path); extern int sysfs_get_name_from_path(const unsigned char *path, unsigned char *name, size_t len); extern int sysfs_path_is_dir(const unsigned char *path); @@ -161,7 +163,9 @@ extern int sysfs_write_attribute(struct sysfs_attribute *sysattr, const unsigned char *new_value, size_t len); extern unsigned char *sysfs_get_value_from_attributes(struct dlist *attr, const unsigned char * name); -extern int sysfs_refresh_attributes(struct dlist *attrlist); +extern int sysfs_refresh_dir_attributes(struct sysfs_directory *sysdir); +extern int sysfs_refresh_dir_links(struct sysfs_directory *sysdir); +extern int sysfs_refresh_dir_subdirs(struct sysfs_directory *sysdir); extern void sysfs_close_directory(struct sysfs_directory *sysdir); extern struct sysfs_directory *sysfs_open_directory(const unsigned char *path); extern int sysfs_read_dir_attributes(struct sysfs_directory *sysdir); @@ -179,6 +183,9 @@ extern struct sysfs_link *sysfs_get_subdirectory_link (struct sysfs_directory *dir, unsigned char *linkname); extern struct sysfs_attribute *sysfs_get_directory_attribute (struct sysfs_directory *dir, unsigned char *attrname); +extern struct dlist *sysfs_get_dir_attributes(struct sysfs_directory *dir); +extern struct dlist *sysfs_get_dir_links(struct sysfs_directory *dir); +extern struct dlist *sysfs_get_dir_subdirs(struct sysfs_directory *dir); /* sysfs driver access */ extern void sysfs_close_driver(struct sysfs_driver *driver); @@ -189,9 +196,12 @@ extern struct sysfs_attribute *sysfs_get_driver_attr (struct sysfs_driver *drv, const unsigned char *name); extern struct dlist *sysfs_get_driver_attributes(struct sysfs_driver *driver); extern struct dlist *sysfs_get_driver_devices(struct sysfs_driver *driver); +extern struct dlist *sysfs_refresh_driver_devices(struct sysfs_driver *driver); extern struct dlist *sysfs_get_driver_links(struct sysfs_driver *driver); extern struct sysfs_device *sysfs_get_driver_device (struct sysfs_driver *driver, const unsigned char *name); +extern struct dlist *sysfs_refresh_driver_attributes + (struct sysfs_driver *driver); extern struct sysfs_attribute *sysfs_open_driver_attr(const unsigned char *bus, const unsigned char *drv, const unsigned char *attrib); @@ -205,9 +215,12 @@ extern struct sysfs_device *sysfs_open_device (const unsigned char *bus_id, const unsigned char *bus); extern struct sysfs_device *sysfs_get_device_parent(struct sysfs_device *dev); extern struct sysfs_device *sysfs_open_device_path(const unsigned char *path); +extern int sysfs_get_device_bus(struct sysfs_device *dev); extern struct sysfs_attribute *sysfs_get_device_attr (struct sysfs_device *dev, const unsigned char *name); extern struct dlist *sysfs_get_device_attributes(struct sysfs_device *device); +extern struct dlist *sysfs_refresh_device_attributes + (struct sysfs_device *device); extern struct sysfs_attribute *sysfs_open_device_attr(const unsigned char *bus, const unsigned char *bus_id, const unsigned char *attrib); @@ -221,6 +234,7 @@ extern struct sysfs_driver *sysfs_get_bus_driver(struct sysfs_bus *bus, extern struct dlist *sysfs_get_bus_drivers(struct sysfs_bus *bus); extern struct dlist *sysfs_get_bus_devices(struct sysfs_bus *bus); extern struct dlist *sysfs_get_bus_attributes(struct sysfs_bus *bus); +extern struct dlist *sysfs_refresh_bus_attributes(struct sysfs_bus *bus); extern struct sysfs_attribute *sysfs_get_bus_attribute(struct sysfs_bus *bus, unsigned char *attrname); extern struct sysfs_device *sysfs_open_bus_device(unsigned char *busname, @@ -247,6 +261,8 @@ extern struct sysfs_class_device *sysfs_get_class_device (struct sysfs_class *class, unsigned char *name); extern struct dlist *sysfs_get_classdev_attributes (struct sysfs_class_device *cdev); +extern struct dlist *sysfs_refresh_classdev_attributes + (struct sysfs_class_device *cdev); extern struct sysfs_attribute *sysfs_get_classdev_attr (struct sysfs_class_device *clsdev, const unsigned char *name); extern struct sysfs_attribute *sysfs_open_classdev_attr diff --git a/libsysfs/sysfs_bus.c b/libsysfs/sysfs_bus.c index d9da0f84cf..aca392875e 100644 --- a/libsysfs/sysfs_bus.c +++ b/libsysfs/sysfs_bus.c @@ -209,9 +209,7 @@ struct sysfs_bus *sysfs_open_bus(const unsigned char *name) return NULL; } - if (sysfs_trailing_slash(buspath) == 0) - strcat(buspath, "/"); - + strcat(buspath, "/"); strcat(buspath, SYSFS_BUS_NAME); strcat(buspath, "/"); strcat(buspath, name); @@ -226,6 +224,11 @@ struct sysfs_bus *sysfs_open_bus(const unsigned char *name) } strcpy(bus->name, name); strcpy(bus->path, buspath); + if ((sysfs_remove_trailing_slash(bus->path)) != 0) { + dprintf("Incorrect path to bus %s\n", bus->path); + sysfs_close_bus(bus); + return NULL; + } return bus; } @@ -296,21 +299,38 @@ struct dlist *sysfs_get_bus_attributes(struct sysfs_bus *bus) if (bus->directory->attributes == NULL) { if ((sysfs_read_dir_attributes(bus->directory)) != 0) return NULL; - } else { - if ((sysfs_path_is_dir(bus->path)) != 0) { - dprintf("Bus at %s no longer exists\n", bus->path); - return NULL; - } - if ((sysfs_refresh_attributes - (bus->directory->attributes)) != 0) { - dprintf("Error refreshing bus attributes\n"); - return NULL; - } } return bus->directory->attributes; } /** + * sysfs_refresh_bus_attributes: refreshes the bus's list of attributes + * @bus: sysfs_bus whose attributes to refresh + * + * NOTE: Upon return, prior references to sysfs_attributes for this bus + * _may_ not be valid + * + * Returns list of attributes on success and NULL on failure + */ +struct dlist *sysfs_refresh_bus_attributes(struct sysfs_bus *bus) +{ + if (bus == NULL) { + errno = EINVAL; + return NULL; + } + + if (bus->directory == NULL) + return (sysfs_get_bus_attributes(bus)); + + if ((sysfs_refresh_dir_attributes(bus->directory)) != 0) { + dprintf("Error refreshing bus attributes\n"); + return NULL; + } + + return (bus->directory->attributes); +} + +/** * sysfs_get_bus_attribute: gets a specific bus attribute, if buses had * attributes. * @bus: bus to retrieve attribute from @@ -357,8 +377,7 @@ struct sysfs_device *sysfs_open_bus_device(unsigned char *busname, return NULL; } - if (sysfs_trailing_slash(path) == 0) - strcat(path, "/"); + strcat(path, "/"); strcat(path, SYSFS_BUS_NAME); strcat(path, "/"); strcat(path, busname); diff --git a/libsysfs/sysfs_class.c b/libsysfs/sysfs_class.c index 16eaf6e514..cd86912142 100644 --- a/libsysfs/sysfs_class.c +++ b/libsysfs/sysfs_class.c @@ -160,6 +160,11 @@ struct sysfs_class_device *sysfs_open_class_device_path } strcpy(cdev->path, path); + if ((sysfs_remove_trailing_slash(cdev->path)) != 0) { + dprintf("Invalid path to class device %s\n", cdev->path); + sysfs_close_class_device(cdev); + return NULL; + } set_classdev_classname(cdev); return cdev; @@ -179,6 +184,10 @@ struct dlist *sysfs_get_class_devices(struct sysfs_class *cls) errno = EINVAL; return NULL; } + + if (cls->devices != NULL) + return cls->devices; + if (cls->directory == NULL) { cls->directory = sysfs_open_directory(cls->path); if (cls->directory == NULL) @@ -226,16 +235,16 @@ struct sysfs_class *sysfs_open_class(const unsigned char *name) dprintf("Sysfs not supported on this system\n"); return NULL; } - if (sysfs_trailing_slash(classpath) == 0) - strcat(classpath, "/"); /* * We shall now treat "block" also as a class. Hence, check here * if "name" is "block" and proceed accordingly */ if (strcmp(name, SYSFS_BLOCK_NAME) == 0) { + strcat(classpath, "/"); strcat(classpath, SYSFS_BLOCK_NAME); } else { + strcat(classpath, "/"); strcat(classpath, SYSFS_CLASS_NAME); strcat(classpath, "/"); strcat(classpath, name); @@ -252,6 +261,11 @@ struct sysfs_class *sysfs_open_class(const unsigned char *name) } strcpy(cls->name, name); strcpy(cls->path, classpath); + if ((sysfs_remove_trailing_slash(cls->path)) != 0) { + dprintf("Invalid path to class device %s\n", cls->path); + sysfs_close_class(cls); + return NULL; + } return cls; } @@ -264,8 +278,6 @@ struct sysfs_class *sysfs_open_class(const unsigned char *name) struct sysfs_class_device *sysfs_get_class_device(struct sysfs_class *class, unsigned char *name) { - struct dlist *devlist = NULL; - if (class == NULL || name == NULL) { errno = EINVAL; return NULL; @@ -273,7 +285,7 @@ struct sysfs_class_device *sysfs_get_class_device(struct sysfs_class *class, if (class->devices == NULL) { class->devices = sysfs_get_class_devices(class); - if (devlist == NULL) + if (class->devices == NULL) return NULL; } return (struct sysfs_class_device *)dlist_find_custom(class->devices, @@ -291,14 +303,21 @@ struct sysfs_device *sysfs_get_classdev_device (struct sysfs_class_device *clsdev) { struct sysfs_link *devlink = NULL; + unsigned char devpath[SYSFS_PATH_MAX]; if (clsdev == NULL) { errno = EINVAL; return NULL; } - - if (clsdev->sysdevice != NULL) - return (clsdev->sysdevice); + strcpy(devpath, clsdev->path); + strcat(devpath, "/device"); + if ((sysfs_path_is_link(devpath)) != 0) { + if (clsdev->sysdevice != NULL) { + sysfs_close_device(clsdev->sysdevice); + clsdev->sysdevice = NULL; + } + return NULL; + } if (clsdev->directory == NULL) { clsdev->directory = sysfs_open_directory(clsdev->path); @@ -306,8 +325,24 @@ struct sysfs_device *sysfs_get_classdev_device return NULL; } devlink = sysfs_get_directory_link(clsdev->directory, "device"); - if (devlink == NULL) + if (devlink == NULL) { + if (clsdev->sysdevice != NULL) { + dprintf("Device link no longer exists\n"); + sysfs_close_device(clsdev->sysdevice); + clsdev->sysdevice = NULL; + } return NULL; + } + + if (clsdev->sysdevice != NULL) { + if (!strncmp(devlink->target, clsdev->sysdevice->path, + SYSFS_PATH_MAX)) + /* sysdevice hasn't changed */ + return (clsdev->sysdevice); + else + /* come here only if the device link for has changed */ + sysfs_close_device(clsdev->sysdevice); + } clsdev->sysdevice = sysfs_open_device_path(devlink->target); if (clsdev->sysdevice == NULL) @@ -329,31 +364,56 @@ struct sysfs_driver *sysfs_get_classdev_driver (struct sysfs_class_device *clsdev) { struct sysfs_link *drvlink = NULL; + unsigned char drvpath[SYSFS_PATH_MAX]; if (clsdev == NULL) { errno = EINVAL; return NULL; } - - if (clsdev->driver != NULL) - return (clsdev->driver); - + strcpy(drvpath, clsdev->path); + strcat(drvpath, "/driver"); + if ((sysfs_path_is_link(drvpath)) != 0) { + if (clsdev->driver != NULL) { + sysfs_close_driver(clsdev->driver); + clsdev->driver = NULL; + } + return NULL; + } + if (clsdev->directory == NULL) { clsdev->directory = sysfs_open_directory(clsdev->path); if (clsdev->directory == NULL) return NULL; } drvlink = sysfs_get_directory_link(clsdev->directory, "driver"); - if (drvlink != NULL) { - clsdev->driver = sysfs_open_driver_path(drvlink->target); - if (clsdev->driver == NULL) - return NULL; - + if (drvlink == NULL) { + if (clsdev->driver != NULL) { + dprintf("Driver link no longer exists\n"); + sysfs_close_driver(clsdev->driver); + clsdev->driver = NULL; + } + return NULL; + } + if (clsdev->driver != NULL) { + if (!strncmp(drvlink->target, clsdev->driver->path, + SYSFS_PATH_MAX)) + /* driver hasn't changed */ + return (clsdev->driver); + else + /* come here only if the device link for has changed */ + sysfs_close_driver(clsdev->driver); } + + clsdev->driver = sysfs_open_driver_path(drvlink->target); + if (clsdev->driver == NULL) + return NULL; + if (clsdev->sysdevice != NULL) + strcpy(clsdev->sysdevice->driver_name, clsdev->driver->name); + return (clsdev->driver); } - -/* + +/** * get_blockdev_parent: Get the parent class device for a "block" subsystem * device if present * @clsdev: block subsystem class device whose parent needs to be found @@ -361,48 +421,34 @@ struct sysfs_driver *sysfs_get_classdev_driver */ static int get_blockdev_parent(struct sysfs_class_device *clsdev) { - unsigned char parent_path[SYSFS_PATH_MAX], value[256], *c = NULL; - - memset(parent_path, 0, SYSFS_PATH_MAX); - strcpy(parent_path, clsdev->path); + unsigned char parent_path[SYSFS_PATH_MAX], *c = NULL; + strcpy(parent_path, clsdev->path); c = strstr(parent_path, SYSFS_BLOCK_NAME); if (c == NULL) { - dprintf("Class device %s does not belong to BLOCK subsystem", + dprintf("Class device %s does not belong to BLOCK subsystem\n", clsdev->name); return 1; } - + c += strlen(SYSFS_BLOCK_NAME); if (*c == '/') c++; else goto errout; - - /* validate whether the given class device is a partition or not */ - if ((strncmp(c, clsdev->name, strlen(clsdev->name))) == 0) { - dprintf("%s not a partition\n", clsdev->name); - return 1; - } - c = strchr(c, '/'); - if (c == NULL) - goto errout; - *c = '\0'; - - /* Now validate if the parent has the "dev" attribute */ - memset(value, 0, 256); - strcat(parent_path, "/dev"); - if ((sysfs_read_attribute_value(parent_path, value, 256)) != 0) { - dprintf("Block device %s does not have a parent\n", - clsdev->name); - return 1; - } - - c = strrchr(parent_path, '/'); + + /* validate whether the given class device is a partition or not */ + if ((strncmp(c, clsdev->name, strlen(clsdev->name))) == 0) { + dprintf("%s not a partition\n", clsdev->name); + return 1; + } + + c = strchr(c, '/'); if (c == NULL) goto errout; *c = '\0'; + clsdev->parent = sysfs_open_class_device_path(parent_path); if (clsdev->parent == NULL) { dprintf("Error opening the parent class device at %s\n", @@ -467,13 +513,11 @@ static int get_classdev_path(const unsigned char *classname, dprintf("Error getting sysfs mount path\n"); return -1; } - - if (sysfs_trailing_slash(path) == 0) - strcat(path, "/"); - if (strcmp(classname, SYSFS_BLOCK_NAME) == 0) { + strcat(path, "/"); strcat(path, SYSFS_BLOCK_NAME); } else { + strcat(path, "/"); strcat(path, SYSFS_CLASS_NAME); strcat(path, "/"); strcat(path, classname); @@ -537,27 +581,41 @@ struct dlist *sysfs_get_classdev_attributes(struct sysfs_class_device *cdev) return NULL; } if (cdev->directory->attributes == NULL) { - if ((sysfs_read_dir_attributes(cdev->directory)) != 0) { - dprintf("Error reading attributes for directory %s\n", - cdev->directory->path); - return NULL; - } - } else { - if ((sysfs_path_is_dir(cdev->path)) != 0) { - dprintf("Class device at %s no longer exists\n", - cdev->path); - return NULL; - } - if ((sysfs_refresh_attributes - (cdev->directory->attributes)) != 0) { - dprintf("Error refreshing classdev attributes\n"); + if ((sysfs_read_dir_attributes(cdev->directory)) != 0) return NULL; - } } return (cdev->directory->attributes); } /** + * sysfs_refresh_clsassdev_attributes: refreshes the driver's list of attributes + * @clsdev: sysfs_class_device whose attributes to refresh + * + * NOTE: Upon return, prior references to sysfs_attributes for this classdev + * _may_ not be valid + * + * Returns list of attributes on success and NULL on failure + */ +struct dlist *sysfs_refresh_classdev_attributes + (struct sysfs_class_device *clsdev) +{ + if (clsdev == NULL) { + errno = EINVAL; + return NULL; + } + + if (clsdev->directory == NULL) + return (sysfs_get_classdev_attributes(clsdev)); + + if ((sysfs_refresh_dir_attributes(clsdev->directory)) != 0) { + dprintf("Error refreshing class_device attributes\n"); + return NULL; + } + + return (clsdev->directory->attributes); +} + +/** * sysfs_get_classdev_attr: searches class device's attributes by name * @clsdev: class device to look through * @name: attribute name to get @@ -597,15 +655,10 @@ struct sysfs_attribute *sysfs_get_classdev_attr struct sysfs_directory) { if ((sysfs_path_is_dir(sdir->path)) != 0) continue; - if (sdir->attributes == NULL) { - cur = sysfs_get_directory_attribute(sdir, - (unsigned char *)name); - } else { - if ((sysfs_refresh_attributes - (sdir->attributes)) == 0) - cur = sysfs_get_directory_attribute(sdir, + cur = sysfs_get_directory_attribute(sdir, (unsigned char *)name); - } + if (cur == NULL) + continue; } } return cur; diff --git a/libsysfs/sysfs_device.c b/libsysfs/sysfs_device.c index 66d5f9aef7..bfd761b885 100644 --- a/libsysfs/sysfs_device.c +++ b/libsysfs/sysfs_device.c @@ -24,12 +24,12 @@ #include "sysfs.h" /** - * get_device_bus: retrieves the bus name the device is on, checks path to - * bus' link to make sure it has correct device. + * sysfs_get_device_bus: retrieves the bus name the device is on, checks path + * to bus' link to make sure it has correct device. * @dev: device to get busname. * returns 0 with success and -1 with error. */ -static int get_device_bus(struct sysfs_device *dev) +int sysfs_get_device_bus(struct sysfs_device *dev) { unsigned char subsys[SYSFS_NAME_LEN], path[SYSFS_PATH_MAX]; unsigned char target[SYSFS_PATH_MAX], *bus = NULL, *c = NULL; @@ -197,6 +197,11 @@ struct sysfs_device *sysfs_open_device_path(const unsigned char *path) return NULL; } strcpy(dev->path, path); + if ((sysfs_remove_trailing_slash(dev->path)) != 0) { + dprintf("Invalid path to device %s\n", dev->path); + sysfs_close_device(dev); + return NULL; + } /* * The "name" attribute no longer exists... return the device's * sysfs representation instead, in the "dev->name" field, which @@ -204,8 +209,8 @@ struct sysfs_device *sysfs_open_device_path(const unsigned char *path) */ strncpy(dev->name, dev->bus_id, SYSFS_NAME_LEN); - if (get_device_bus(dev) != 0) - strcpy(dev->bus, SYSFS_UNKNOWN); + if (sysfs_get_device_bus(dev) != 0) + dprintf("Could not get device bus\n"); return dev; } @@ -334,8 +339,7 @@ struct sysfs_root_device *sysfs_open_root_device(const unsigned char *name) return NULL; } - if (sysfs_trailing_slash(rootpath) == 0) - strcat(rootpath, "/"); + strcat(rootpath, "/"); strcat(rootpath, SYSFS_DEVICES_NAME); strcat(rootpath, "/"); strcat(rootpath, name); @@ -352,6 +356,11 @@ struct sysfs_root_device *sysfs_open_root_device(const unsigned char *name) } strcpy(root->name, name); strcpy(root->path, rootpath); + if ((sysfs_remove_trailing_slash(root->path)) != 0) { + dprintf("Invalid path to root device %s\n", root->path); + sysfs_close_root_device(root); + return NULL; + } return root; } @@ -373,21 +382,38 @@ struct dlist *sysfs_get_device_attributes(struct sysfs_device *device) if (device->directory->attributes == NULL) { if ((sysfs_read_dir_attributes(device->directory)) != 0) return NULL; - } else { - if ((sysfs_path_is_dir(device->path)) != 0) { - dprintf("Device at %s no longer exists", device->path); - return NULL; - } - if ((sysfs_refresh_attributes - (device->directory->attributes)) != 0) { - dprintf("Error refreshing device attributes\n"); - return NULL; - } } return (device->directory->attributes); } /** + * sysfs_refresh_device_attributes: refreshes the device's list of attributes + * @device: sysfs_device whose attributes to refresh + * + * NOTE: Upon return, prior references to sysfs_attributes for this device + * _may_ not be valid + * + * Returns list of attributes on success and NULL on failure + */ +struct dlist *sysfs_refresh_device_attributes(struct sysfs_device *device) +{ + if (device == NULL) { + errno = EINVAL; + return NULL; + } + + if (device->directory == NULL) + return (sysfs_get_device_attributes(device)); + + if ((sysfs_refresh_dir_attributes(device->directory)) != 0) { + dprintf("Error refreshing device attributes\n"); + return NULL; + } + + return (device->directory->attributes); +} + +/** * sysfs_get_device_attr: searches dev's attributes by name * @dev: device to look through * @name: attribute name to get @@ -396,22 +422,19 @@ struct dlist *sysfs_get_device_attributes(struct sysfs_device *device) struct sysfs_attribute *sysfs_get_device_attr(struct sysfs_device *dev, const unsigned char *name) { - struct sysfs_attribute *cur = NULL; struct dlist *attrlist = NULL; if (dev == NULL || name == NULL) { errno = EINVAL; return NULL; } - + attrlist = sysfs_get_device_attributes(dev); if (attrlist == NULL) return NULL; - cur = sysfs_get_directory_attribute(dev->directory, - (unsigned char *)name); - - return cur; + return sysfs_get_directory_attribute(dev->directory, + (unsigned char *)name); } /** @@ -437,8 +460,7 @@ static int get_device_absolute_path(const unsigned char *device, dprintf ("Sysfs not supported on this system\n"); return -1; } - if (sysfs_trailing_slash(bus_path) == 0) - strcat(bus_path, "/"); + strcat(bus_path, "/"); strcat(bus_path, SYSFS_BUS_NAME); strcat(bus_path, "/"); strcat(bus_path, bus); diff --git a/libsysfs/sysfs_dir.c b/libsysfs/sysfs_dir.c index c159db7af8..a60410ed28 100644 --- a/libsysfs/sysfs_dir.c +++ b/libsysfs/sysfs_dir.c @@ -195,7 +195,7 @@ int sysfs_write_attribute(struct sysfs_attribute *sysattr, return -1; } if ((strncmp(sysattr->value, new_value, sysattr->len)) == 0) { - dprintf("Attribute %s already has the requested value %s\n", + dprintf("Attr %s already has the requested value %s\n", sysattr->name, new_value); return 0; } @@ -274,7 +274,7 @@ int sysfs_read_attribute(struct sysfs_attribute *sysattr) return -1; } #ifdef __KLIBC__ - pgsize = 0x1000; + pgsize = 0x1000; #else pgsize = sysconf(_SC_PAGESIZE); #endif @@ -468,6 +468,13 @@ struct sysfs_directory *sysfs_open_directory(const unsigned char *path) errno = EINVAL; return NULL; } + + if (sysfs_path_is_dir(path) != 0) { + dprintf("Invalid path directory %s\n", path); + errno = EINVAL; + return NULL; + } + sdir = alloc_directory(); if (sdir == NULL) { dprintf("Error allocating directory %s\n", path); @@ -514,39 +521,6 @@ struct sysfs_link *sysfs_open_link(const unsigned char *linkpath) } /** - * sysfs_refresh_attributes: Refresh attributes list - * @attrlist: list of attributes to refresh - * Returns 0 on success, 1 on failure - */ -int sysfs_refresh_attributes(struct dlist *attrlist) -{ - struct sysfs_attribute *attr = NULL; - - if (attrlist == NULL) { - errno = EINVAL; - return 1; - } - dlist_for_each_data(attrlist, attr, struct sysfs_attribute) { - if (attr->method & SYSFS_METHOD_SHOW) { - if ((sysfs_read_attribute(attr)) != 0) { - dprintf("Error reading attribute %s\n", - attr->path); - if ((sysfs_path_is_file(attr->path)) != 0) { - dprintf("Attr %s no longer exists\n", - attr->name); - } - } - } else { - if ((sysfs_path_is_file(attr->path)) != 0) { - dprintf("Attr %s no longer exists\n", - attr->name); - } - } - } - return 0; -} - -/** * add_attribute: open and add attribute at path to given directory * @sysdir: directory to add attribute to * @path: path to attribute @@ -633,7 +607,6 @@ int sysfs_read_dir_attributes(struct sysfs_directory *sysdir) { DIR *dir = NULL; struct dirent *dirent = NULL; - struct stat astats; unsigned char file_path[SYSFS_PATH_MAX]; int retval = 0; @@ -655,11 +628,7 @@ int sysfs_read_dir_attributes(struct sysfs_directory *sysdir) strncpy(file_path, sysdir->path, SYSFS_PATH_MAX); strcat(file_path, "/"); strcat(file_path, dirent->d_name); - if ((lstat(file_path, &astats)) != 0) { - dprintf("stat failed\n"); - continue; - } - if (S_ISREG(astats.st_mode)) + if ((sysfs_path_is_file(file_path)) == 0) retval = add_attribute(sysdir, file_path); } closedir(dir); @@ -675,7 +644,6 @@ int sysfs_read_dir_links(struct sysfs_directory *sysdir) { DIR *dir = NULL; struct dirent *dirent = NULL; - struct stat astats; unsigned char file_path[SYSFS_PATH_MAX]; int retval = 0; @@ -697,11 +665,7 @@ int sysfs_read_dir_links(struct sysfs_directory *sysdir) strncpy(file_path, sysdir->path, SYSFS_PATH_MAX); strcat(file_path, "/"); strcat(file_path, dirent->d_name); - if ((lstat(file_path, &astats)) != 0) { - dprintf("stat failed\n"); - continue; - } - if (S_ISLNK(astats.st_mode)) { + if ((sysfs_path_is_link(file_path)) == 0) { retval = add_link(sysdir, file_path); if (retval != 0) break; @@ -720,7 +684,6 @@ int sysfs_read_dir_subdirs(struct sysfs_directory *sysdir) { DIR *dir = NULL; struct dirent *dirent = NULL; - struct stat astats; unsigned char file_path[SYSFS_PATH_MAX]; int retval = 0; @@ -742,11 +705,7 @@ int sysfs_read_dir_subdirs(struct sysfs_directory *sysdir) strncpy(file_path, sysdir->path, SYSFS_PATH_MAX); strcat(file_path, "/"); strcat(file_path, dirent->d_name); - if ((lstat(file_path, &astats)) != 0) { - dprintf("stat failed\n"); - continue; - } - if (S_ISDIR(astats.st_mode)) + if ((sysfs_path_is_dir(file_path)) == 0) retval = add_subdirectory(sysdir, file_path); } closedir(dir); @@ -802,6 +761,90 @@ int sysfs_read_directory(struct sysfs_directory *sysdir) } /** + * sysfs_refresh_dir_attributes: Refresh attributes list + * @sysdir: directory whose list of attributes to refresh + * Returns 0 on success, 1 on failure + */ +int sysfs_refresh_dir_attributes(struct sysfs_directory *sysdir) +{ + if (sysdir == NULL) { + errno = EINVAL; + return 1; + } + if ((sysfs_path_is_dir(sysdir->path)) != 0) { + dprintf("Invalid path to directory %s\n", sysdir->path); + errno = EINVAL; + return 1; + } + if (sysdir->attributes != NULL) { + dlist_destroy(sysdir->attributes); + sysdir->attributes = NULL; + } + if ((sysfs_read_dir_attributes(sysdir)) != 0) { + dprintf("Error refreshing attributes for directory %s\n", + sysdir->path); + return 1; + } + return 0; +} + +/** + * sysfs_refresh_dir_links: Refresh links list + * @sysdir: directory whose list of links to refresh + * Returns 0 on success, 1 on failure + */ +int sysfs_refresh_dir_links(struct sysfs_directory *sysdir) +{ + if (sysdir == NULL) { + errno = EINVAL; + return 1; + } + if ((sysfs_path_is_dir(sysdir->path)) != 0) { + dprintf("Invalid path to directory %s\n", sysdir->path); + errno = EINVAL; + return 1; + } + if (sysdir->links != NULL) { + dlist_destroy(sysdir->links); + sysdir->links = NULL; + } + if ((sysfs_read_dir_links(sysdir)) != 0) { + dprintf("Error refreshing links for directory %s\n", + sysdir->path); + return 1; + } + return 0; +} + +/** + * sysfs_refresh_dir_subdirs: Refresh subdirs list + * @sysdir: directory whose list of subdirs to refresh + * Returns 0 on success, 1 on failure + */ +int sysfs_refresh_dir_subdirs(struct sysfs_directory *sysdir) +{ + if (sysdir == NULL) { + errno = EINVAL; + return 1; + } + if ((sysfs_path_is_dir(sysdir->path)) != 0) { + dprintf("Invalid path to directory %s\n", sysdir->path); + errno = EINVAL; + return 1; + } + if (sysdir->subdirs != NULL) { + dlist_destroy(sysdir->subdirs); + sysdir->subdirs = NULL; + } + if ((sysfs_read_dir_subdirs(sysdir)) != 0) { + dprintf("Error refreshing subdirs for directory %s\n", + sysdir->path); + return 1; + } + return 0; +} + +/** * sysfs_get_directory_attribute: retrieves attribute attrname from current * directory only * @dir: directory to retrieve attribute from @@ -826,19 +869,25 @@ struct sysfs_attribute *sysfs_get_directory_attribute attr = (struct sysfs_attribute *)dlist_find_custom (dir->attributes, attrname, dir_attribute_name_equal); - if (attr == NULL) { + if (attr != NULL) { + if ((sysfs_read_attribute(attr)) != 0) { + dprintf("Error reading attribute %s\n", attr->name); + return NULL; + } + } else { memset(new_path, 0, SYSFS_PATH_MAX); strcpy(new_path, dir->path); strcat(new_path, "/"); strcat(new_path, attrname); if ((sysfs_path_is_file(new_path)) == 0) { - if ((add_attribute(dir, new_path)) == 0) { + if ((add_attribute(dir, new_path)) == 0) { attr = (struct sysfs_attribute *) - dlist_find_custom(dir->attributes, + dlist_find_custom(dir->attributes, attrname, dir_attribute_name_equal); } } } + return attr; } @@ -855,9 +904,13 @@ struct sysfs_link *sysfs_get_directory_link errno = EINVAL; return NULL; } - if (dir->links == NULL) + if (dir->links == NULL) { if ((sysfs_read_dir_links(dir) != 0) || (dir->links == NULL)) return NULL; + } else { + if ((sysfs_refresh_dir_links(dir)) != 0) + return NULL; + } return (struct sysfs_link *)dlist_find_custom(dir->links, linkname, dir_link_name_equal); @@ -940,3 +993,63 @@ struct sysfs_link *sysfs_get_subdirectory_link(struct sysfs_directory *dir, } return NULL; } + +/** + * sysfs_get_dir_attributes: returns dlist of directory attributes + * @dir: directory to retrieve attributes from + * returns dlist of attributes or NULL + */ +struct dlist *sysfs_get_dir_attributes(struct sysfs_directory *dir) +{ + if (dir == NULL) { + errno = EINVAL; + return NULL; + } + + if (dir->attributes == NULL) { + if (sysfs_read_dir_attributes(dir) != 0) + return NULL; + } + + return (dir->attributes); +} + +/** + * sysfs_get_dir_links: returns dlist of directory links + * @dir: directory to return links for + * returns dlist of links or NULL + */ +struct dlist *sysfs_get_dir_links(struct sysfs_directory *dir) +{ + if (dir == NULL) { + errno = EINVAL; + return NULL; + } + + if (dir->links == NULL) { + if (sysfs_read_dir_links(dir) != 0) + return NULL; + } + + return (dir->links); +} + +/** + * sysfs_get_dir_subdirs: returns dlist of directory subdirectories + * @dir: directory to return subdirs for + * returns dlist of subdirs or NULL + */ +struct dlist *sysfs_get_dir_subdirs(struct sysfs_directory *dir) +{ + if (dir == NULL) { + errno = EINVAL; + return NULL; + } + + if (dir->subdirs == NULL) { + if (sysfs_read_dir_subdirs(dir) != 0) + return NULL; + } + + return (dir->subdirs); +} diff --git a/libsysfs/sysfs_driver.c b/libsysfs/sysfs_driver.c index 695ca794f1..a4440cfdf9 100644 --- a/libsysfs/sysfs_driver.c +++ b/libsysfs/sysfs_driver.c @@ -103,6 +103,11 @@ struct sysfs_driver *sysfs_open_driver_path(const unsigned char *path) return NULL; } strcpy(driver->path, path); + if ((sysfs_remove_trailing_slash(driver->path)) != 0) { + dprintf("Invalid path to driver %s\n", driver->path); + sysfs_close_driver(driver); + return NULL; + } return driver; } @@ -125,26 +130,38 @@ struct dlist *sysfs_get_driver_attributes(struct sysfs_driver *driver) return NULL; } if (driver->directory->attributes == NULL) { - if ((sysfs_read_dir_attributes(driver->directory)) != 0) { - dprintf("Error reading driver attributes\n"); - return NULL; - } - } else { - if ((sysfs_path_is_dir(driver->path)) != 0) { - dprintf("Driver at %s no longer exists\n", - driver->path); - return NULL; - } - if ((sysfs_refresh_attributes - (driver->directory->attributes)) != 0) { - dprintf("Error refreshing driver attributes\n"); + if ((sysfs_read_dir_attributes(driver->directory)) != 0) return NULL; - } } return(driver->directory->attributes); } /** + * sysfs_refresh_driver_attributes: refreshes the driver's list of attributes + * @driver: sysfs_driver whose attributes to refresh + * + * NOTE: Upon return, prior references to sysfs_attributes for this driver + * _may_ not be valid + * + * Returns list of attributes on success and NULL on failure + */ +struct dlist *sysfs_refresh_driver_attributes(struct sysfs_driver *driver) +{ + if (driver == NULL) { + errno = EINVAL; + return NULL; + } + if (driver->directory == NULL) + return (sysfs_get_driver_attributes(driver)); + + if ((sysfs_refresh_dir_attributes(driver->directory)) != 0) { + dprintf("Error refreshing driver attributes\n"); + return NULL; + } + return (driver->directory->attributes); +} + +/** * sysfs_get_driver_attr: searches driver's attributes by name * @drv: driver to look through * @name: attribute name to get @@ -153,7 +170,6 @@ struct dlist *sysfs_get_driver_attributes(struct sysfs_driver *driver) struct sysfs_attribute *sysfs_get_driver_attr(struct sysfs_driver *drv, const unsigned char *name) { - struct sysfs_attribute *cur = NULL; struct dlist *attrlist = NULL; if (drv == NULL) { @@ -163,9 +179,10 @@ struct sysfs_attribute *sysfs_get_driver_attr(struct sysfs_driver *drv, attrlist = sysfs_get_driver_attributes(drv); if (attrlist != NULL) - cur = sysfs_get_directory_attribute(drv->directory, + return NULL; + + return sysfs_get_directory_attribute(drv->directory, (unsigned char *)name); - return cur; } /** @@ -234,6 +251,38 @@ struct dlist *sysfs_get_driver_devices(struct sysfs_driver *driver) } /** + * sysfs_refresh_driver_devices: Refreshes drivers list of devices + * @driver: sysfs_driver whose devices list needs to be refreshed + * + * NOTE: Upon return from this function, prior sysfs_device references from + * this driver's list of devices _may_ not be valid + * + * Returns dlist of devices on success and NULL on failure + */ +struct dlist *sysfs_refresh_driver_devices(struct sysfs_driver *driver) +{ + if (driver == NULL) { + errno = EINVAL; + return NULL; + } + + if (driver->devices != NULL) { + dlist_destroy(driver->devices); + driver->devices = NULL; + } + + if (driver->directory == NULL) + return (sysfs_get_driver_devices(driver)); + + if ((sysfs_refresh_dir_links(driver->directory)) != 0) { + dprintf("Error refreshing driver links\n"); + return NULL; + } + + return (sysfs_get_driver_devices(driver)); +} + +/** * sysfs_get_driver_device: looks up a device from a list of driver's devices * and returns its sysfs_device corresponding to it * @driver: sysfs_driver on which to search @@ -285,8 +334,7 @@ static int get_driver_path(const unsigned char *bus, dprintf("Error getting sysfs mount path\n"); return -1; } - if (sysfs_trailing_slash(path) == 0) - strcat(path, "/"); + strcat(path, "/"); strcat(path, SYSFS_BUS_NAME); strcat(path, "/"); strcat(path, bus); diff --git a/libsysfs/sysfs_utils.c b/libsysfs/sysfs_utils.c index 009ae94efa..f1f82361d0 100644 --- a/libsysfs/sysfs_utils.c +++ b/libsysfs/sysfs_utils.c @@ -27,6 +27,30 @@ #endif /** + * sysfs_remove_trailing_slash: Removes any trailing '/' in the given path + * @path: Path to look for the trailing '/' + * Returns 0 on success 1 on error + */ +int sysfs_remove_trailing_slash(unsigned char *path) +{ + unsigned char *c = NULL; + + if (path == NULL) { + errno = EINVAL; + return 1; + } + c = strrchr(path, '/'); + if (c == NULL) { + dprintf("Invalid path %s\n", path); + errno = EINVAL; + return 1; + } + if (*(c+1) == '\0') + *c = '\0'; + return 0; +} + +/** * sysfs_get_mnt_path: Gets the mount point for specified filesystem. * @fs_type: filesystem type to retrieve mount point * @mnt_path: place to put the retrieved mount path @@ -72,28 +96,14 @@ static int sysfs_get_fs_mnt_path(const unsigned char *fs_type, errno = EINVAL; ret = -1; } + if ((sysfs_remove_trailing_slash(mnt_path)) != 0) + ret = -1; + return ret; #endif } /* - * sysfs_trailing_slash: checks if there's a trailing slash to path - * @path: path to check - * returns 1 if true and 0 if not - */ -int sysfs_trailing_slash(unsigned char *path) -{ - unsigned char *s = NULL; - - if (path == NULL) - return 0; - s = &path[strlen(path)-1]; - if (strncmp(s, "/", 1) == 0) - return 1; - return 0; -} - -/* * sysfs_get_mnt_path: Gets the sysfs mount point. * @mnt_path: place to put "sysfs" mount point * @len: size of mnt_path @@ -109,9 +119,11 @@ int sysfs_get_mnt_path(unsigned char *mnt_path, size_t len) return -1; } sysfs_path = getenv(SYSFS_PATH_ENV); - if (sysfs_path != NULL) + if (sysfs_path != NULL) { strncpy(mnt_path, sysfs_path, len); - else + if ((sysfs_remove_trailing_slash(mnt_path)) != 0) + return 1; + } else ret = sysfs_get_fs_mnt_path(SYSFS_FSTYPE_NAME, mnt_path, len); return ret; @@ -152,7 +164,7 @@ int sysfs_get_name_from_path(const unsigned char *path, unsigned char *name, strncpy(name, n, len); return 0; } - + /** * sysfs_get_link: returns link source * @path: symbolic link's path @@ -178,32 +190,69 @@ int sysfs_get_link(const unsigned char *path, unsigned char *target, size_t len) if ((readlink(path, linkpath, SYSFS_PATH_MAX)) < 0) { return -1; } - d = linkpath; - - /* getting rid of leading "../.." */ - while (*d == '/' || *d == '.') { - if (*d == '/') - slashes++; - d++; - } - - d--; - - s = &devdir[strlen(devdir)-1]; - while (s != NULL && count != (slashes+1)) { - s--; - if (*s == '/') - count++; + /* + * Three cases here: + * 1. relative path => format ../.. + * 2. absolute path => format /abcd/efgh + * 3. relative path _from_ this dir => format abcd/efgh + */ + switch (*d) { + case '.': + /* + * handle the case where link is of type ./abcd/xxx + */ + strncpy(target, devdir, len); + if (*(d+1) == '/') + d += 2; + else if (*(d+1) == '.') + goto parse_path; + s = strrchr(target, '/'); + if (s != NULL) { + *(s+1) = '\0'; + strcat(target, d); + } else { + strcpy(target, d); + } + break; + /* + * relative path + * getting rid of leading "../.." + */ +parse_path: + while (*d == '/' || *d == '.') { + if (*d == '/') + slashes++; + d++; + } + d--; + s = &devdir[strlen(devdir)-1]; + while (s != NULL && count != (slashes+1)) { + s--; + if (*s == '/') + count++; + } + strncpy(s, d, (SYSFS_PATH_MAX-strlen(devdir))); + strncpy(target, devdir, len); + break; + case '/': + /* absolute path - copy as is */ + strncpy(target, linkpath, len); + break; + default: + /* relative path from this directory */ + strncpy(target, devdir, len); + s = strrchr(target, '/'); + if (s != NULL) { + *(s+1) = '\0'; + strcat(target, linkpath); + } else { + strcpy(target, linkpath); + } } - - strncpy(s, d, (SYSFS_PATH_MAX-strlen(devdir))); - strncpy(target, devdir, len); - return 0; } - /** * sysfs_del_name: free function for sysfs_open_subsystem_list * @name: memory area to be freed @@ -245,8 +294,8 @@ struct dlist *sysfs_open_subsystem_list(unsigned char *name) dprintf("Error getting sysfs mount point\n"); return NULL; } - if (sysfs_trailing_slash(sysfs_path) == 0) - strcat(sysfs_path, "/"); + + strcat(sysfs_path, "/"); strcat(sysfs_path, name); dir = sysfs_open_directory(sysfs_path); if (dir == NULL) { @@ -318,8 +367,7 @@ struct dlist *sysfs_open_bus_devices_list(unsigned char *name) return NULL; } - if (sysfs_trailing_slash(sysfs_path) == 0) - strcat(sysfs_path, "/"); + strcat(sysfs_path, "/"); strcat(sysfs_path, SYSFS_BUS_NAME); strcat(sysfs_path, "/"); strcat(sysfs_path, name); @@ -376,7 +424,7 @@ int sysfs_path_is_dir(const unsigned char *path) } if (S_ISDIR(astats.st_mode)) return 0; - + return 1; } @@ -399,7 +447,7 @@ int sysfs_path_is_link(const unsigned char *path) } if (S_ISLNK(astats.st_mode)) return 0; - + return 1; } @@ -422,6 +470,6 @@ int sysfs_path_is_file(const unsigned char *path) } if (S_ISREG(astats.st_mode)) return 0; - + return 1; } |