summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormananth <mananth>2004-01-07 06:42:36 +0000
committermananth <mananth>2004-01-07 06:42:36 +0000
commit0eb5d7d2815f3717cffd451b7bab769a36fc0bb6 (patch)
tree189ed6e04769a67974c50cec2ba9ec5a12b85e6f
parent3350196531cb367b5c10a869a0d78ef6558d74de (diff)
downloadsysfsutils-0eb5d7d2815f3717cffd451b7bab769a36fc0bb6.tar.gz
Refersh, path '/' and sysfs_get_link() and Martin Hicks' patch
-rw-r--r--ChangeLog8
-rw-r--r--include/libsysfs.h13
-rw-r--r--lib/sysfs_bus.c42
-rw-r--r--lib/sysfs_class.c193
-rw-r--r--lib/sysfs_device.c54
-rw-r--r--lib/sysfs_dir.c174
-rw-r--r--lib/sysfs_driver.c83
-rw-r--r--lib/sysfs_utils.c112
8 files changed, 474 insertions, 205 deletions
diff --git a/ChangeLog b/ChangeLog
index 717332b..826de98 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,12 @@
+01/07/2003 - Ananth Mavinakayanahalli <ananth@in.ibm.com>
+ * Added numerous "refresh" functions
+ * Added funtion to remove trailing slash from paths
+ * Fixed sysfs_get_link() to handle different possibilities
+
+01/07/2003 - Martin Hicks <mort@bork.org>
+ * Fixed sysfs_get_class_device()
+
12/26/2003 - Daniel Stekloff <dsteklof@us.ibm.com>
* Removed unneeded functions
* Added APIs to get directory links, subdirs and attribs
diff --git a/include/libsysfs.h b/include/libsysfs.h
index b49bd58..6d3cbcd 100644
--- a/include/libsysfs.h
+++ b/include/libsysfs.h
@@ -141,6 +141,7 @@ extern "C" {
* Function Prototypes
*/
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);
@@ -162,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);
@@ -193,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);
@@ -212,6 +218,8 @@ extern struct sysfs_device *sysfs_open_device_path(const unsigned char *path);
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);
@@ -225,6 +233,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,
@@ -251,6 +260,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/lib/sysfs_bus.c b/lib/sysfs_bus.c
index e8c2c32..aca3928 100644
--- a/lib/sysfs_bus.c
+++ b/lib/sysfs_bus.c
@@ -224,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;
}
@@ -294,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
diff --git a/lib/sysfs_class.c b/lib/sysfs_class.c
index 12f505f..160ca05 100644
--- a/lib/sysfs_class.c
+++ b/lib/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)
@@ -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,28 @@ 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",
- 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",
@@ -535,27 +575,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
@@ -595,15 +649,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/lib/sysfs_device.c b/lib/sysfs_device.c
index 4834155..bee3294 100644
--- a/lib/sysfs_device.c
+++ b/lib/sysfs_device.c
@@ -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
@@ -351,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;
}
@@ -372,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
@@ -395,7 +422,6 @@ 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) {
@@ -407,10 +433,8 @@ struct sysfs_attribute *sysfs_get_device_attr(struct sysfs_device *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);
}
/**
diff --git a/lib/sysfs_dir.c b/lib/sysfs_dir.c
index 7f2afb4..fe4c71c 100644
--- a/lib/sysfs_dir.c
+++ b/lib/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;
}
@@ -517,39 +517,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
@@ -636,7 +603,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;
@@ -658,11 +624,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);
@@ -678,7 +640,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;
@@ -700,11 +661,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;
@@ -723,7 +680,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;
@@ -745,11 +701,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);
@@ -805,10 +757,98 @@ 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
* @attrname: name of attribute to look for
+ *
+ * NOTE: Since we know the attribute to look for, this routine looks for the
+ * attribute if it was created _after_ the attrlist was read initially.
+ *
* returns sysfs_attribute if found and NULL if not found
*/
struct sysfs_attribute *sysfs_get_directory_attribute
@@ -829,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;
}
@@ -858,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);
@@ -959,18 +1009,8 @@ struct dlist *sysfs_get_dir_attributes(struct sysfs_directory *dir)
if (dir->attributes == NULL) {
if (sysfs_read_dir_attributes(dir) != 0)
return NULL;
- } else {
- if (sysfs_path_is_dir(dir->path) != 0) {
- dprintf("Directory at %s no longer exists\n",
- dir->path);
- return NULL;
- }
- if (sysfs_refresh_attributes(dir->attributes) != 0) {
- dprintf("Error refreshing attributes at %s\n",
- dir->path);
- return NULL;
- }
}
+
return (dir->attributes);
}
diff --git a/lib/sysfs_driver.c b/lib/sysfs_driver.c
index 8b85aa7..a4440cf 100644
--- a/lib/sysfs_driver.c
+++ b/lib/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
diff --git a/lib/sysfs_utils.c b/lib/sysfs_utils.c
index b10dedc..b8de9bd 100644
--- a/lib/sysfs_utils.c
+++ b/lib/sysfs_utils.c
@@ -24,6 +24,30 @@
#include "sysfs.h"
/**
+ * 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
@@ -65,6 +89,9 @@ 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;
}
@@ -84,9 +111,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;
@@ -153,32 +182,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