};
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;
};
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;
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;
};
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;
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 */
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;
};
/*
* 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);
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);
(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);
(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);
(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);
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,
(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
return NULL;
}
- if (sysfs_trailing_slash(buspath) == 0)
- strcat(buspath, "/");
-
+ strcat(buspath, "/");
strcat(buspath, SYSFS_BUS_NAME);
strcat(buspath, "/");
strcat(buspath, 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;
}
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.
return NULL;
}
- if (sysfs_trailing_slash(path) == 0)
- strcat(path, "/");
+ strcat(path, "/");
strcat(path, SYSFS_BUS_NAME);
strcat(path, "/");
strcat(path, busname);
}
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;
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)
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);
}
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;
}
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;
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,
(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);
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)
(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
*/
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",
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);
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
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;
#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;
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
*/
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;
}
return NULL;
}
- if (sysfs_trailing_slash(rootpath) == 0)
- strcat(rootpath, "/");
+ strcat(rootpath, "/");
strcat(rootpath, SYSFS_DEVICES_NAME);
strcat(rootpath, "/");
strcat(rootpath, 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;
}
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
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);
}
/**
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);
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;
}
return -1;
}
#ifdef __KLIBC__
- pgsize = 0x1000;
+ pgsize = 0x1000;
#else
pgsize = sysconf(_SC_PAGESIZE);
#endif
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);
return ln;
}
-/**
- * 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
{
DIR *dir = NULL;
struct dirent *dirent = NULL;
- struct stat astats;
unsigned char file_path[SYSFS_PATH_MAX];
int retval = 0;
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);
{
DIR *dir = NULL;
struct dirent *dirent = NULL;
- struct stat astats;
unsigned char file_path[SYSFS_PATH_MAX];
int retval = 0;
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;
{
DIR *dir = NULL;
struct dirent *dirent = NULL;
- struct stat astats;
unsigned char file_path[SYSFS_PATH_MAX];
int retval = 0;
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);
return(retval);
}
+/**
+ * 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
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;
}
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);
}
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);
+}
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;
}
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
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) {
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;
}
/**
return (driver->devices);
}
+/**
+ * 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
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);
#include <mntent.h>
#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
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
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;
strncpy(name, n, len);
return 0;
}
-
+
/**
* sysfs_get_link: returns link source
* @path: symbolic link's path
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
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) {
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);
}
if (S_ISDIR(astats.st_mode))
return 0;
-
+
return 1;
}
}
if (S_ISLNK(astats.st_mode))
return 0;
-
+
return 1;
}
}
if (S_ISREG(astats.st_mode))
return 0;
-
+
return 1;
}
#include <ctype.h>
#include <unistd.h>
#include <errno.h>
+#include <time.h>
#include <sys/wait.h>
#include <sys/stat.h>
{
struct sysfs_device *sysfs_device;
struct sysfs_class_device *class_dev_parent;
+ struct timespec tspec;
int loop;
- char filename[SYSFS_PATH_MAX + 6];
- int retval;
- char *temp;
- int partition = 0;
/* Figure out where the device symlink is at. For char devices this will
* always be in the class_dev->path. But for block devices, it's different.
* symlink yet. We do sit and spin on waiting for them right now, we should
* possibly have a whitelist for these devices here...
*/
- strcpy(filename, class_dev->path);
- dbg("filename = %s", filename);
- if (strcmp(class_dev->classname, SYSFS_BLOCK_NAME) == 0) {
- if (isdigit(class_dev->path[strlen(class_dev->path)-1])) {
- temp = strrchr(filename, '/');
- if (temp) {
- char *temp2 = strrchr(filename, '/');
- partition = 1;
- *temp = 0x00;
- dbg("temp2 = %s", temp2);
- if (temp2 && (strcmp(temp2, "/block") == 0)) {
- /* oops, we have no parent block device, so go back to original directory */
- strcpy(filename, class_dev->path);
- partition = 0;
- }
- }
- }
- }
- strcat(filename, "/device");
+ class_dev_parent = sysfs_get_classdev_parent(class_dev);
+ if (class_dev_parent)
+ dbg("Really a partition");
- loop = 2;
+ tspec.tv_sec = 0;
+ tspec.tv_nsec = 10000000; /* sleep 10 millisec */
+ loop = 10;
while (loop--) {
- struct stat buf;
- dbg("looking for '%s'", filename);
- retval = stat(filename, &buf);
- if (!retval)
- break;
- /* sleep to give the kernel a chance to create the device file */
- sleep(1);
- }
+ nanosleep(&tspec, NULL);
+ if (class_dev_parent)
+ sysfs_device = sysfs_get_classdev_device(class_dev_parent);
+ else
+ sysfs_device = sysfs_get_classdev_device(class_dev);
- loop = 1; /* FIXME put a real value in here for when everything is fixed... */
- while (loop--) {
- /* find the sysfs_device for this class device */
- /* Wouldn't it really be nice if libsysfs could do this for us? */
- sysfs_device = sysfs_get_classdev_device(class_dev);
if (sysfs_device != NULL)
- goto exit;
-
- /* if it's a partition, we need to get the parent device */
- if (partition) {
- /* FIXME HACK HACK HACK HACK
- * for some reason partitions need this extra sleep here, in order
- * to wait for the device properly. Once the libsysfs code is
- * fixed properly, this sleep should go away, and we can just loop above.
- */
- sleep(1);
- dbg("really is a partition");
- class_dev_parent = sysfs_get_classdev_parent(class_dev);
- if (class_dev_parent == NULL) {
- dbg("sysfs_get_classdev_parent for class device '%s' failed", class_dev->name);
- } else {
- dbg("class_dev_parent->name='%s'", class_dev_parent->name);
- sysfs_device = sysfs_get_classdev_device(class_dev_parent);
- if (sysfs_device != NULL)
- goto exit;
- }
- }
- /* sleep to give the kernel a chance to create the link */
- /* FIXME remove comment...
- sleep(1); */
+ goto device_found;
}
dbg("Timed out waiting for device symlink, continuing on anyway...");
+
+device_found:
+ /* We have another issue with just the wait above - the sysfs part of
+ * the kernel may not be quick enough to have created the link to the
+ * device under the "bus" subsystem. Due to this, the sysfs_device->bus
+ * will not contain the actual bus name :(
+ *
+ * Libsysfs now provides a new API sysfs_get_device_bus(), so use it
+ * if needed
+ */
+ if (sysfs_device) {
+
+ if (sysfs_device->bus[0] != '\0')
+ goto bus_found;
+
+ loop = 10;
+ tspec.tv_nsec = 10000000;
+ while (loop--) {
+ nanosleep(&tspec, NULL);
+ sysfs_get_device_bus(sysfs_device);
+
+ if (sysfs_device->bus[0] != '\0')
+ goto bus_found;
+ }
+ dbg("Timed out waiting to find the device bus, continuing on anyway\n");
+ goto exit;
+bus_found:
+ dbg("Device %s is registered with bus %s\n",
+ sysfs_device->name, sysfs_device->bus);
+ }
exit:
return sysfs_device;
}