summaryrefslogtreecommitdiff
path: root/libsysfs
diff options
context:
space:
mode:
Diffstat (limited to 'libsysfs')
-rw-r--r--libsysfs/libsysfs.h49
-rw-r--r--libsysfs/sysfs_bus.c294
-rw-r--r--libsysfs/sysfs_class.c424
-rw-r--r--libsysfs/sysfs_device.c309
-rw-r--r--libsysfs/sysfs_dir.c403
-rw-r--r--libsysfs/sysfs_driver.c287
-rw-r--r--libsysfs/sysfs_utils.c73
7 files changed, 1163 insertions, 676 deletions
diff --git a/libsysfs/libsysfs.h b/libsysfs/libsysfs.h
index 6d8e58de21..aca25772b5 100644
--- a/libsysfs/libsysfs.h
+++ b/libsysfs/libsysfs.h
@@ -31,15 +31,10 @@
*/
#define SYSFS_FSTYPE_NAME "sysfs"
#define SYSFS_PROC_MNTS "/proc/mounts"
-#define SYSFS_BUS_DIR "/bus"
#define SYSFS_BUS_NAME "bus"
-#define SYSFS_CLASS_DIR "/class"
#define SYSFS_CLASS_NAME "class"
-#define SYSFS_BLOCK_DIR "/block"
#define SYSFS_BLOCK_NAME "block"
-#define SYSFS_DEVICES_DIR "/devices"
#define SYSFS_DEVICES_NAME "devices"
-#define SYSFS_DRIVERS_DIR "/drivers"
#define SYSFS_DRIVERS_NAME "drivers"
#define SYSFS_NAME_ATTRIBUTE "name"
#define SYSFS_UNKNOWN "unknown"
@@ -75,17 +70,15 @@ struct sysfs_directory {
};
struct sysfs_driver {
- struct dlist *devices;
unsigned char name[SYSFS_NAME_LEN];
unsigned char path[SYSFS_PATH_MAX];
/* for internal use only */
+ struct dlist *devices;
struct sysfs_directory *directory;
};
struct sysfs_device {
- struct sysfs_device *parent;
- struct dlist *children;
unsigned char name[SYSFS_NAME_LEN];
unsigned char bus_id[SYSFS_NAME_LEN];
unsigned char bus[SYSFS_NAME_LEN];
@@ -93,45 +86,48 @@ struct sysfs_device {
unsigned char path[SYSFS_PATH_MAX];
/* for internal use only */
+ struct sysfs_device *parent;
+ struct dlist *children;
struct sysfs_directory *directory;
};
struct sysfs_root_device {
- struct dlist *devices;
unsigned char name[SYSFS_NAME_LEN];
unsigned char path[SYSFS_PATH_MAX];
/* for internal use only */
+ struct dlist *devices;
struct sysfs_directory *directory;
};
struct sysfs_bus {
- struct dlist *drivers;
- struct dlist *devices;
unsigned char name[SYSFS_NAME_LEN];
unsigned char path[SYSFS_PATH_MAX];
/* internal use only */
+ struct dlist *drivers;
+ struct dlist *devices;
struct sysfs_directory *directory;
};
struct sysfs_class_device {
- struct sysfs_device *sysdevice; /* NULL if virtual */
- struct sysfs_driver *driver; /* NULL if not implemented */
unsigned char name[SYSFS_NAME_LEN];
unsigned char classname[SYSFS_NAME_LEN];
unsigned char path[SYSFS_PATH_MAX];
/* for internal use only */
+ struct sysfs_class_device *parent;
+ struct sysfs_device *sysdevice; /* NULL if virtual */
+ struct sysfs_driver *driver; /* NULL if not implemented */
struct sysfs_directory *directory;
};
struct sysfs_class {
- struct dlist *devices;
unsigned char name[SYSFS_NAME_LEN];
unsigned char path[SYSFS_PATH_MAX];
/* for internal use only */
+ struct dlist *devices;
struct sysfs_directory *directory;
};
@@ -146,6 +142,9 @@ extern int sysfs_trailing_slash(unsigned char *path);
extern int sysfs_get_mnt_path(unsigned char *mnt_path, size_t len);
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);
+extern int sysfs_path_is_link(const unsigned char *path);
+extern int sysfs_path_is_file(const unsigned char *path);
extern int sysfs_get_link(const unsigned char *path, unsigned char *target,
size_t len);
extern struct dlist *sysfs_open_subsystem_list(unsigned char *name);
@@ -162,8 +161,12 @@ 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 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);
+extern int sysfs_read_dir_links(struct sysfs_directory *sysdir);
+extern int sysfs_read_dir_subdirs(struct sysfs_directory *sysdir);
extern int sysfs_read_directory(struct sysfs_directory *sysdir);
extern int sysfs_read_all_subdirs(struct sysfs_directory *sysdir);
extern struct sysfs_directory *sysfs_get_subdirectory
@@ -183,10 +186,10 @@ extern struct sysfs_driver *sysfs_open_driver(const unsigned char *path);
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_get_driver_links(struct sysfs_driver *driver);
-extern void sysfs_close_driver_by_name(struct sysfs_driver *driver);
-extern struct sysfs_driver *sysfs_open_driver_by_name
- (const unsigned char *drv_name, const unsigned char *bus, size_t bsize);
+extern struct sysfs_device *sysfs_get_driver_device
+ (struct sysfs_driver *driver, const unsigned char *name);
extern struct sysfs_attribute *sysfs_open_driver_attr(const unsigned char *bus,
const unsigned char *drv, const unsigned char *attrib);
@@ -194,13 +197,14 @@ extern struct sysfs_attribute *sysfs_open_driver_attr(const unsigned char *bus,
extern void sysfs_close_root_device(struct sysfs_root_device *root);
extern struct sysfs_root_device *sysfs_open_root_device
(const unsigned char *name);
+extern struct dlist *sysfs_get_root_devices(struct sysfs_root_device *root);
extern void sysfs_close_device(struct sysfs_device *dev);
extern struct sysfs_device *sysfs_open_device(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 sysfs_device *sysfs_open_device_by_id
- (const unsigned char *bus_id, const unsigned char *bus, size_t bsize);
+ (const unsigned char *bus_id, const unsigned char *bus);
extern struct sysfs_attribute *sysfs_open_device_attr(const unsigned char *bus,
const unsigned char *bus_id, const unsigned char *attrib);
@@ -211,6 +215,8 @@ extern struct sysfs_device *sysfs_get_bus_device(struct sysfs_bus *bus,
unsigned char *id);
extern struct sysfs_driver *sysfs_get_bus_driver(struct sysfs_bus *bus,
unsigned char *drvname);
+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 sysfs_attribute *sysfs_get_bus_attribute(struct sysfs_bus *bus,
unsigned char *attrname);
@@ -223,8 +229,15 @@ extern int sysfs_find_driver_bus(const unsigned char *driver,
extern void sysfs_close_class_device(struct sysfs_class_device *dev);
extern struct sysfs_class_device *sysfs_open_class_device
(const unsigned char *path);
+extern struct sysfs_device *sysfs_get_classdev_device
+ (struct sysfs_class_device *clsdev);
+extern struct sysfs_driver *sysfs_get_classdev_driver
+ (struct sysfs_class_device *clsdev);
+extern struct sysfs_class_device *sysfs_get_classdev_parent
+ (struct sysfs_class_device *clsdev);
extern void sysfs_close_class(struct sysfs_class *cls);
extern struct sysfs_class *sysfs_open_class(const unsigned char *name);
+extern struct dlist *sysfs_get_class_devices(struct sysfs_class *cls);
extern struct sysfs_class_device *sysfs_get_class_device
(struct sysfs_class *class, unsigned char *name);
extern struct sysfs_class_device *sysfs_open_class_device_by_name
diff --git a/libsysfs/sysfs_bus.c b/libsysfs/sysfs_bus.c
index 639acef4ee..3e6c22bbb1 100644
--- a/libsysfs/sysfs_bus.c
+++ b/libsysfs/sysfs_bus.c
@@ -93,187 +93,91 @@ static struct sysfs_bus *alloc_bus(void)
}
/**
- * open_bus_dir: opens up sysfs bus directory
- * returns sysfs_directory struct with success and NULL with error
+ * sysfs_get_bus_devices: gets all devices for bus
+ * @bus: bus to get devices for
+ * returns dlist of devices with success and NULL with failure
*/
-static struct sysfs_directory *open_bus_dir(const unsigned char *name)
+struct dlist *sysfs_get_bus_devices(struct sysfs_bus *bus)
{
- struct sysfs_directory *busdir = NULL;
- unsigned char buspath[SYSFS_PATH_MAX];
+ struct sysfs_device *bdev = NULL;
+ struct sysfs_directory *devdir = NULL;
+ struct sysfs_link *curl = NULL;
+ unsigned char path[SYSFS_PATH_MAX];
- if (name == NULL) {
+ if (bus == NULL) {
errno = EINVAL;
return NULL;
}
-
- memset(buspath, 0, SYSFS_PATH_MAX);
- if ((sysfs_get_mnt_path(buspath, SYSFS_PATH_MAX)) != 0) {
- dprintf("Sysfs not supported on this system\n");
+ memset(path, 0, SYSFS_PATH_MAX);
+ strcpy(path, bus->path);
+ strcat(path, "/");
+ strcat(path, SYSFS_DEVICES_NAME);
+ devdir = sysfs_open_directory(path);
+ if (devdir == NULL)
return NULL;
- }
- if (sysfs_trailing_slash(buspath) == 0)
- strcat(buspath, "/");
-
- strcat(buspath, SYSFS_BUS_NAME);
- strcat(buspath, "/");
- strcat(buspath, name);
- busdir = sysfs_open_directory(buspath);
- if (busdir == NULL) {
- errno = EINVAL;
- dprintf("Bus %s not supported on this system\n",
- name);
+ if (sysfs_read_dir_links(devdir) != 0) {
+ sysfs_close_directory(devdir);
return NULL;
}
- if ((sysfs_read_directory(busdir)) != 0) {
- dprintf("Error reading %s bus dir %s\n", name,
- buspath);
- sysfs_close_directory(busdir);
- return NULL;
- }
- /* read in devices and drivers subdirs */
- sysfs_read_all_subdirs(busdir);
-
- return busdir;
-}
-
-/**
- * get_all_bus_devices: gets all devices for bus
- * @bus: bus to get devices for
- * returns 0 with success and -1 with failure
- */
-static int get_all_bus_devices(struct sysfs_bus *bus)
-{
- struct sysfs_device *bdev = NULL;
- struct sysfs_directory *cur = NULL;
- struct sysfs_link *curl = NULL;
-
- if (bus == NULL || bus->directory == NULL) {
- errno = EINVAL;
- return -1;
- }
- if (bus->directory->subdirs == NULL)
- return 0;
- dlist_for_each_data(bus->directory->subdirs, cur,
- struct sysfs_directory) {
- if (strcmp(cur->name, SYSFS_DEVICES_NAME) != 0)
+ dlist_for_each_data(devdir->links, curl, struct sysfs_link) {
+ bdev = sysfs_open_device(curl->target);
+ if (bdev == NULL) {
+ dprintf("Error opening device at %s\n", curl->target);
continue;
- if (cur->links == NULL)
- continue;
- dlist_for_each_data(cur->links, curl, struct sysfs_link) {
- bdev = sysfs_open_device(curl->target);
- if (bdev == NULL) {
- dprintf("Error opening device at %s\n",
- curl->target);
- continue;
- }
- if (bus->devices == NULL)
- bus->devices = dlist_new_with_delete
- (sizeof(struct sysfs_device),
- sysfs_close_dev);
- dlist_unshift(bus->devices, bdev);
}
+ if (bus->devices == NULL)
+ bus->devices = dlist_new_with_delete
+ (sizeof(struct sysfs_device), sysfs_close_dev);
+ dlist_unshift(bus->devices, bdev);
}
-
- return 0;
+ sysfs_close_directory(devdir);
+
+ return (bus->devices);
}
/**
- * get_all_bus_drivers: get all pci drivers
+ * sysfs_get_bus_drivers: get all pci drivers
* @bus: pci bus to add drivers to
- * returns 0 with success and -1 with error
+ * returns dlist of drivers with success and NULL with error
*/
-static int get_all_bus_drivers(struct sysfs_bus *bus)
+struct dlist *sysfs_get_bus_drivers(struct sysfs_bus *bus)
{
struct sysfs_driver *driver = NULL;
- struct sysfs_directory *cur = NULL;
+ struct sysfs_directory *drvdir = NULL;
struct sysfs_directory *cursub = NULL;
+ unsigned char path[SYSFS_PATH_MAX];
- if (bus == NULL || bus->directory == NULL) {
+ if (bus == NULL) {
errno = EINVAL;
- return -1;
- }
- if (bus->directory->subdirs == NULL)
- return 0;
-
- dlist_for_each_data(bus->directory->subdirs, cur,
- struct sysfs_directory) {
- if (strcmp(cur->name, SYSFS_DRIVERS_NAME) != 0)
- continue;
- if (cur->subdirs == NULL)
- continue;
- dlist_for_each_data(cur->subdirs, cursub,
- struct sysfs_directory) {
- driver = sysfs_open_driver(cursub->path);
- if (driver == NULL) {
- dprintf("Error opening driver at %s\n",
- cursub->path);
- continue;
- }
- if (bus->drivers == NULL)
- bus->drivers = dlist_new_with_delete
- (sizeof(struct sysfs_driver),
- sysfs_close_drv);
- dlist_unshift(bus->drivers, driver);
- }
+ return NULL;
}
-
- return 0;
-}
-
-/**
- * match_bus_device_to_driver: returns 1 if device is bound to driver
- * @driver: driver to match
- * @busid: busid of device to match
- * returns 1 if found and 0 if not found
- */
-static int match_bus_device_to_driver(struct sysfs_driver *driver,
- unsigned char *busid)
-{
- struct sysfs_link *cur = NULL;
- int found = 0;
+ memset(path, 0, SYSFS_PATH_MAX);
+ strcpy(path, bus->path);
+ strcat(path, "/");
+ strcat(path, SYSFS_DRIVERS_NAME);
+ drvdir = sysfs_open_directory(path);
+ if (drvdir == NULL)
+ return NULL;
- if (driver == NULL || driver->directory == NULL || busid == NULL) {
- errno = EINVAL;
- return found;
- }
- if (driver->directory->links != NULL) {
- dlist_for_each_data(driver->directory->links, cur,
- struct sysfs_link) {
- if ((strcmp(cur->name, busid)) == 0)
- found++;
- }
+ if (sysfs_read_dir_subdirs(drvdir) != 0) {
+ sysfs_close_directory(drvdir);
+ return NULL;
}
- return found;
-}
-
-/**
- * link_bus_devices_to_drivers: goes through and links devices to drivers
- * @bus: bus to link
- */
-static void link_bus_devices_to_drivers(struct sysfs_bus *bus)
-{
- struct sysfs_device *dev = NULL;
- struct sysfs_driver *drv = NULL;
-
- if (bus != NULL && bus->devices != NULL && bus->drivers != NULL) {
- dlist_for_each_data(bus->devices, dev, struct sysfs_device) {
- dlist_for_each_data(bus->drivers, drv,
- struct sysfs_driver) {
- if ((match_bus_device_to_driver(drv,
- dev->bus_id)) != 0) {
- strncpy(dev->driver_name, drv->name,
- SYSFS_NAME_LEN);
- if (drv->devices == NULL)
- drv->devices = dlist_new
- (sizeof(struct
- sysfs_device));
- dlist_unshift(drv->devices, dev);
- }
- }
+ dlist_for_each_data(drvdir->subdirs, cursub, struct sysfs_directory) {
+ driver = sysfs_open_driver(cursub->path);
+ if (driver == NULL) {
+ dprintf("Error opening driver at %s\n", cursub->path);
+ continue;
}
+ if (bus->drivers == NULL)
+ bus->drivers = dlist_new_with_delete
+ (sizeof(struct sysfs_driver), sysfs_close_drv);
+ dlist_unshift(bus->drivers, driver);
}
+ sysfs_close_directory(drvdir);
+ return (bus->drivers);
}
/**
@@ -283,39 +187,36 @@ static void link_bus_devices_to_drivers(struct sysfs_bus *bus)
struct sysfs_bus *sysfs_open_bus(const unsigned char *name)
{
struct sysfs_bus *bus = NULL;
- struct sysfs_directory *busdir = NULL;
+ unsigned char buspath[SYSFS_PATH_MAX];
if (name == NULL) {
errno = EINVAL;
return NULL;
}
- bus = alloc_bus();
- if (bus == NULL) {
- dprintf("calloc failed\n");
- return NULL;
- }
- strcpy(bus->name, name);
- busdir = open_bus_dir(name);
- if (busdir == NULL) {
- dprintf("Invalid bus, %s not supported on this system\n",
- name);
- sysfs_close_bus(bus);
+ memset(buspath, 0, SYSFS_PATH_MAX);
+ if ((sysfs_get_mnt_path(buspath, SYSFS_PATH_MAX)) != 0) {
+ dprintf("Sysfs not supported on this system\n");
return NULL;
}
- strcpy(bus->path, busdir->path);
- bus->directory = busdir;
- if ((get_all_bus_devices(bus)) != 0) {
- dprintf("Error reading %s bus devices\n", name);
- sysfs_close_bus(bus);
+
+ if (sysfs_trailing_slash(buspath) == 0)
+ strcat(buspath, "/");
+
+ strcat(buspath, SYSFS_BUS_NAME);
+ strcat(buspath, "/");
+ strcat(buspath, name);
+ if ((sysfs_path_is_dir(buspath)) != 0) {
+ dprintf("Invalid path to bus: %s\n", buspath);
return NULL;
}
- if ((get_all_bus_drivers(bus)) != 0) {
- dprintf("Error reading %s bus drivers\n", name);
- sysfs_close_bus(bus);
+ bus = alloc_bus();
+ if (bus == NULL) {
+ dprintf("calloc failed\n");
return NULL;
}
- link_bus_devices_to_drivers(bus);
+ strcpy(bus->name, name);
+ strcpy(bus->path, buspath);
return bus;
}
@@ -334,6 +235,12 @@ struct sysfs_device *sysfs_get_bus_device(struct sysfs_bus *bus,
return NULL;
}
+ if (bus->devices == NULL) {
+ bus->devices = sysfs_get_bus_devices(bus);
+ if (bus->devices == NULL)
+ return NULL;
+ }
+
return (struct sysfs_device *)dlist_find_custom(bus->devices, id,
bus_device_id_equal);
}
@@ -352,6 +259,12 @@ struct sysfs_driver *sysfs_get_bus_driver(struct sysfs_bus *bus,
return NULL;
}
+ if (bus->drivers == NULL) {
+ bus->drivers = sysfs_get_bus_drivers(bus);
+ if (bus->drivers == NULL)
+ return NULL;
+ }
+
return (struct sysfs_driver *)dlist_find_custom(bus->drivers, drvname,
bus_driver_name_equal);
}
@@ -363,8 +276,28 @@ struct sysfs_driver *sysfs_get_bus_driver(struct sysfs_bus *bus,
*/
struct dlist *sysfs_get_bus_attributes(struct sysfs_bus *bus)
{
- if (bus == NULL || bus->directory == NULL)
+ if (bus == NULL)
return NULL;
+
+ if (bus->directory == NULL) {
+ bus->directory = sysfs_open_directory(bus->path);
+ if (bus->directory == NULL)
+ return NULL;
+ }
+ 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;
}
@@ -378,10 +311,16 @@ struct dlist *sysfs_get_bus_attributes(struct sysfs_bus *bus)
struct sysfs_attribute *sysfs_get_bus_attribute(struct sysfs_bus *bus,
unsigned char *attrname)
{
- if (bus == NULL || bus->directory == NULL || attrname == NULL) {
+ struct dlist *attrlist = NULL;
+
+ if (bus == NULL) {
errno = EINVAL;
return NULL;
}
+ attrlist = sysfs_get_bus_attributes(bus);
+ if (attrlist == NULL)
+ return NULL;
+
return sysfs_get_directory_attribute(bus->directory, attrname);
}
@@ -408,9 +347,10 @@ struct sysfs_device *sysfs_open_bus_device(unsigned char *busname,
dprintf("Error getting sysfs mount point\n");
return NULL;
}
-
+
if (sysfs_trailing_slash(path) == 0)
strcat(path, "/");
+
strcat(path, SYSFS_BUS_NAME);
strcat(path, "/");
strcat(path, busname);
@@ -448,6 +388,7 @@ int sysfs_find_driver_bus(const unsigned char *driver, unsigned char *busname,
}
memset(subsys, 0, SYSFS_PATH_MAX);
+ strcat(subsys, "/");
strcpy(subsys, SYSFS_BUS_NAME);
buslist = sysfs_open_subsystem_list(subsys);
if (buslist != NULL) {
@@ -476,4 +417,3 @@ int sysfs_find_driver_bus(const unsigned char *driver, unsigned char *busname,
}
return -1;
}
-
diff --git a/libsysfs/sysfs_class.c b/libsysfs/sysfs_class.c
index 54f22eee24..169600d5fd 100644
--- a/libsysfs/sysfs_class.c
+++ b/libsysfs/sysfs_class.c
@@ -58,6 +58,8 @@ void sysfs_close_class_device(struct sysfs_class_device *dev)
sysfs_close_device(dev->sysdevice);
if (dev->driver != NULL)
sysfs_close_driver(dev->driver);
+ if (dev->parent != NULL)
+ sysfs_close_class_device(dev->parent);
free(dev);
}
}
@@ -96,54 +98,6 @@ static struct sysfs_class *alloc_class(void)
return (struct sysfs_class *)calloc(1, sizeof(struct sysfs_class));
}
-/**
- * open_class_dir: opens up sysfs class directory
- * returns sysfs_directory struct with success and NULL with error
- */
-static struct sysfs_directory *open_class_dir(const unsigned char *name)
-{
- struct sysfs_directory *classdir = NULL;
- unsigned char classpath[SYSFS_PATH_MAX];
-
- if (name == NULL) {
- errno = EINVAL;
- return NULL;
- }
-
- memset(classpath, 0, SYSFS_PATH_MAX);
- if ((sysfs_get_mnt_path(classpath, SYSFS_PATH_MAX)) != 0) {
- 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, SYSFS_BLOCK_NAME);
- } else {
- strcat(classpath, SYSFS_CLASS_NAME);
- strcat(classpath, "/");
- strcat(classpath, name);
- }
- classdir = sysfs_open_directory(classpath);
- if (classdir == NULL) {
- errno = EINVAL;
- dprintf("Class %s not supported on this system\n", name);
- return NULL;
- }
- if ((sysfs_read_directory(classdir)) != 0) {
- dprintf("Error reading %s class dir %s\n", name, classpath);
- sysfs_close_directory(classdir);
- return NULL;
- }
-
- return classdir;
-}
-
/**
* set_classdev_classname: Grabs classname from path
* @cdev: class device to set
@@ -154,20 +108,18 @@ static void set_classdev_classname(struct sysfs_class_device *cdev)
unsigned char *c = NULL, *e = NULL;
int count = 0;
- c = strstr(cdev->path, SYSFS_CLASS_DIR);
- if (c == NULL)
- c = strstr(cdev->path, SYSFS_BLOCK_DIR);
- else {
- c++;
- while (c != NULL && *c != '/')
- c++;
+ c = strstr(cdev->path, SYSFS_CLASS_NAME);
+ if (c == NULL) {
+ c = strstr(cdev->path, SYSFS_BLOCK_NAME);
+ } else {
+ c = strstr(c, "/");
}
- if (c == NULL)
+ if (c == NULL)
strcpy(cdev->classname, SYSFS_UNKNOWN);
-
else {
- c++;
+ if (*c == '/')
+ c++;
e = c;
while (e != NULL && *e != '/' && *e != '\0') {
e++;
@@ -185,15 +137,15 @@ static void set_classdev_classname(struct sysfs_class_device *cdev)
struct sysfs_class_device *sysfs_open_class_device(const unsigned char *path)
{
struct sysfs_class_device *cdev = NULL;
- struct sysfs_directory *dir = NULL;
- struct sysfs_link *curl = NULL;
- struct sysfs_device *sdev = NULL;
- struct sysfs_driver *drv = NULL;
if (path == NULL) {
errno = EINVAL;
return NULL;
}
+ if ((sysfs_path_is_dir(path)) != 0) {
+ dprintf("%s is not a valid path to a class device\n", path);
+ return NULL;
+ }
cdev = alloc_class_device();
if (cdev == NULL) {
dprintf("calloc failed\n");
@@ -201,81 +153,41 @@ struct sysfs_class_device *sysfs_open_class_device(const unsigned char *path)
}
if ((sysfs_get_name_from_path(path, cdev->name, SYSFS_NAME_LEN)) != 0) {
errno = EINVAL;
- dprintf("Invalid class device path %s\n", path);
+ dprintf("Error getting class device name\n");
sysfs_close_class_device(cdev);
return NULL;
}
- dir = sysfs_open_directory(path);
- if (dir == NULL) {
- dprintf("Error opening class device at %s\n", path);
- sysfs_close_class_device(cdev);
- return NULL;
- }
- if ((sysfs_read_directory(dir)) != 0) {
- dprintf("Error reading class device at %s\n", path);
- sysfs_close_directory(dir);
- sysfs_close_class_device(cdev);
- return NULL;
- }
- sysfs_read_all_subdirs(dir);
- cdev->directory = dir;
- strcpy(cdev->path, dir->path);
+ strcpy(cdev->path, path);
set_classdev_classname(cdev);
- /* get driver and device, if implemented */
- if (cdev->directory->links != NULL) {
- dlist_for_each_data(cdev->directory->links, curl,
- struct sysfs_link) {
- if (strncmp(curl->name, SYSFS_DEVICES_NAME, 6) == 0) {
- sdev = sysfs_open_device(curl->target);
- if (sdev != NULL) {
- cdev->sysdevice = sdev;
- if (cdev->driver != NULL)
- strncpy(sdev->driver_name,
- cdev->driver->name,
- SYSFS_NAME_LEN);
- }
- } else if (strncmp(curl->name,
- SYSFS_DRIVERS_NAME, 6) == 0) {
- drv = sysfs_open_driver(curl->target);
- if (drv != NULL) {
- cdev->driver = drv;
- if (cdev->sysdevice != NULL) {
- strncpy(cdev->sysdevice->name,
- drv->name,
- SYSFS_NAME_LEN);
- if (drv->devices == NULL)
- drv->devices =
- dlist_new
- (sizeof(struct
- sysfs_device));
- dlist_unshift(drv->devices,
- cdev->sysdevice);
- }
- }
- }
- }
- }
return cdev;
}
/**
- * get_all_class_devices: gets all devices for class
+ * sysfs_get_class_devices: gets all devices for class
* @class: class to get devices for
- * returns 0 with success and -1 with failure
+ * returns dlist of class_devices with success and NULL with error
*/
-static int get_all_class_devices(struct sysfs_class *cls)
+struct dlist *sysfs_get_class_devices(struct sysfs_class *cls)
{
struct sysfs_class_device *dev = NULL;
struct sysfs_directory *cur = NULL;
- if (cls == NULL || cls->directory == NULL) {
+ if (cls == NULL) {
errno = EINVAL;
- return -1;
+ return NULL;
}
- if (cls->directory->subdirs == NULL)
- return 0;
+ if (cls->directory == NULL) {
+ cls->directory = sysfs_open_directory(cls->path);
+ if (cls->directory == NULL)
+ return NULL;
+ }
+
+ if ((sysfs_read_dir_subdirs(cls->directory) != 0)
+ || cls->directory->subdirs == NULL)
+ return NULL;
+
dlist_for_each_data(cls->directory->subdirs, cur,
struct sysfs_directory) {
dev = sysfs_open_class_device(cur->path);
@@ -289,7 +201,7 @@ static int get_all_class_devices(struct sysfs_class *cls)
sysfs_close_cls_dev);
dlist_unshift(cls->devices, dev);
}
- return 0;
+ return cls->devices;
}
/**
@@ -299,34 +211,46 @@ static int get_all_class_devices(struct sysfs_class *cls)
struct sysfs_class *sysfs_open_class(const unsigned char *name)
{
struct sysfs_class *cls = NULL;
- struct sysfs_directory *classdir = NULL;
+ unsigned char classpath[SYSFS_PATH_MAX];
if (name == NULL) {
errno = EINVAL;
return NULL;
}
+ memset(classpath, 0, SYSFS_PATH_MAX);
+ if ((sysfs_get_mnt_path(classpath, SYSFS_PATH_MAX)) != 0) {
+ 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, SYSFS_BLOCK_NAME);
+ } else {
+ strcat(classpath, SYSFS_CLASS_NAME);
+ strcat(classpath, "/");
+ strcat(classpath, name);
+ }
+ if ((sysfs_path_is_dir(classpath)) != 0) {
+ dprintf("Class %s not found on the system\n", name);
+ return NULL;
+ }
+
cls = alloc_class();
if (cls == NULL) {
dprintf("calloc failed\n");
return NULL;
}
strcpy(cls->name, name);
- classdir = open_class_dir(name);
- if (classdir == NULL) {
- dprintf("Invalid class, %s not supported on this system\n",
- name);
- sysfs_close_class(cls);
- return NULL;
- }
- cls->directory = classdir;
- strcpy(cls->path, classdir->path);
- if ((get_all_class_devices(cls)) != 0) {
- dprintf("Error reading %s class devices\n", name);
- sysfs_close_class(cls);
- return NULL;
- }
-
+ strcpy(cls->path, classpath);
+
return cls;
}
@@ -338,16 +262,190 @@ 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;
}
+ if (class->devices == NULL) {
+ class->devices = sysfs_get_class_devices(class);
+ if (devlist == NULL)
+ return NULL;
+ }
return (struct sysfs_class_device *)dlist_find_custom(class->devices,
name, class_name_equal);
}
/**
+ * sysfs_get_classdev_device: returns the sysfs_device corresponding to
+ * sysfs_class_device, if present
+ * @clsdev: class device whose sysfs_device is required
+ * Returns sysfs_device on success, NULL on error or if device is not
+ * implemented
+ */
+struct sysfs_device *sysfs_get_classdev_device
+ (struct sysfs_class_device *clsdev)
+{
+ struct sysfs_link *devlink = NULL;
+
+ if (clsdev == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ if (clsdev->sysdevice != NULL)
+ return (clsdev->sysdevice);
+
+ if (clsdev->directory == NULL) {
+ clsdev->directory = sysfs_open_directory(clsdev->path);
+ if (clsdev->directory == NULL)
+ return NULL;
+ }
+ devlink = sysfs_get_directory_link(clsdev->directory, "device");
+ if (devlink == NULL)
+ return NULL;
+
+ clsdev->sysdevice = sysfs_open_device(devlink->target);
+ if (clsdev->sysdevice == NULL)
+ return NULL;
+ if (clsdev->driver != NULL)
+ strcpy(clsdev->sysdevice->driver_name, clsdev->driver->name);
+
+ return (clsdev->sysdevice);
+}
+
+/**
+ * sysfs_get_classdev_driver: returns the sysfs_driver corresponding to
+ * sysfs_class_device, if present
+ * @clsdev: class device whose sysfs_device is required
+ * Returns sysfs_driver on success, NULL on error or if driver is not
+ * implemented
+ */
+struct sysfs_driver *sysfs_get_classdev_driver
+ (struct sysfs_class_device *clsdev)
+{
+ struct sysfs_link *drvlink = NULL;
+
+ if (clsdev == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ if (clsdev->driver != NULL)
+ return (clsdev->driver);
+
+ 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(drvlink->target);
+ if (clsdev->driver == NULL)
+ return NULL;
+
+ }
+ 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
+ * Returns 0 on success and 1 on error
+ */
+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);
+
+ 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, '/');
+ if (c == NULL)
+ goto errout;
+
+ *c = '\0';
+ clsdev->parent = sysfs_open_class_device(parent_path);
+ if (clsdev->parent == NULL) {
+ dprintf("Error opening the parent class device at %s\n",
+ parent_path);
+ return 1;
+ }
+ return 0;
+
+errout:
+ dprintf("Invalid path %s\n", clsdev->path);
+ return 1;
+}
+
+/**
+ * sysfs_get_classdev_parent: Retrieves the parent of a class device.
+ * eg., when working with hda1, this function can be used to retrieve the
+ * sysfs_class_device for hda
+ *
+ * @clsdev: class device whose parent details are required.
+ * Returns sysfs_class_device of the parent on success, NULL on failure
+ */
+struct sysfs_class_device *sysfs_get_classdev_parent
+ (struct sysfs_class_device *clsdev)
+{
+ if (clsdev == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+ if (clsdev->parent != NULL)
+ return (clsdev->parent);
+
+ /*
+ * As of now, only block devices have a parent child heirarchy in sysfs
+ * We do not know, if, in the future, more classes will have a similar
+ * structure. Hence, we now call a specialized function for block and
+ * later we can add support functions for other subsystems as required.
+ */
+ if (!(strcmp(clsdev->classname, SYSFS_BLOCK_NAME))) {
+ if ((get_blockdev_parent(clsdev)) == 0)
+ return (clsdev->parent);
+ }
+ return NULL;
+}
+
+/**
* get_classdev_path: given the class and a device in the class, return the
* absolute path to the device
* @classname: name of the class
@@ -367,6 +465,7 @@ 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, "/");
@@ -427,9 +526,32 @@ struct sysfs_class_device *sysfs_open_class_device_by_name
*/
struct dlist *sysfs_get_classdev_attributes(struct sysfs_class_device *cdev)
{
- if (cdev == NULL || cdev->directory == NULL)
+ if (cdev == NULL)
return NULL;
+ if (cdev->directory == NULL) {
+ cdev->directory = sysfs_open_directory(cdev->path);
+ if (cdev->directory == NULL)
+ 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");
+ return NULL;
+ }
+ }
return (cdev->directory->attributes);
}
@@ -443,18 +565,38 @@ struct sysfs_attribute *sysfs_get_classdev_attr
(struct sysfs_class_device *clsdev, const unsigned char *name)
{
struct sysfs_attribute *cur = NULL;
-
- if (clsdev == NULL || clsdev->directory == NULL ||
- clsdev->directory->attributes == NULL || name == NULL) {
+ struct sysfs_directory *sdir = NULL;
+ struct dlist *attrlist = NULL;
+
+ if (clsdev == NULL || name == NULL) {
errno = EINVAL;
return NULL;
}
-
+ /*
+ * First, see if it's in the current directory. Then look at
+ * subdirs since class devices can have subdirs of attributes.
+ */
+ attrlist = sysfs_get_classdev_attributes(clsdev);
+ if (attrlist == NULL)
+ return NULL;
cur = sysfs_get_directory_attribute(clsdev->directory,
(unsigned char *)name);
if (cur != NULL)
return cur;
+ if (clsdev->directory->subdirs == NULL)
+ if ((sysfs_read_dir_subdirs(clsdev->directory)) != 0 ||
+ clsdev->directory->subdirs == NULL)
+ return NULL;
+
+ dlist_for_each_data(clsdev->directory->subdirs, sdir,
+ struct sysfs_directory) {
+ cur = sysfs_get_directory_attribute(sdir,
+ (unsigned char *)name);
+ if (cur != NULL)
+ return cur;
+ }
+
return NULL;
}
diff --git a/libsysfs/sysfs_device.c b/libsysfs/sysfs_device.c
index 323a43dac1..82b54719ff 100644
--- a/libsysfs/sysfs_device.c
+++ b/libsysfs/sysfs_device.c
@@ -23,38 +23,6 @@
#include "libsysfs.h"
#include "sysfs.h"
-static int confirm_device_bus(struct sysfs_device *dev,
- unsigned char *busname, unsigned char *bus_id)
-{
- struct sysfs_link *devlink = NULL;
- unsigned char devpath[SYSFS_PATH_MAX];
- int result = 0;
-
- if (busname == NULL || bus_id == NULL)
- return -1;
-
- if (sysfs_get_mnt_path(devpath, SYSFS_PATH_MAX) != 0)
- return -1;
-
- if (sysfs_trailing_slash(devpath) == 0)
- strcat(devpath, "/");
- strcat(devpath, SYSFS_BUS_NAME);
- strcat(devpath, "/");
- strcat(devpath, busname);
- strcat(devpath, SYSFS_DEVICES_DIR);
- strcat(devpath, "/");
- strcat(devpath, bus_id);
-
- devlink = sysfs_open_link(devpath);
- if (devlink == NULL)
- return -1;
-
- if (strcmp(devlink->target, dev->path) == 0)
- result++;
- sysfs_close_link(devlink);
- return result;
-}
-
/**
* get_device_bus: retrieves the bus name the device is on, checks path to
* bus' link to make sure it has correct device.
@@ -63,33 +31,53 @@ static int confirm_device_bus(struct sysfs_device *dev,
*/
static int get_device_bus(struct sysfs_device *dev)
{
- unsigned char subsys[SYSFS_NAME_LEN], *bus = NULL, *curdev = NULL;
- struct dlist *buslist = NULL, *device_list = NULL;
+ unsigned char subsys[SYSFS_NAME_LEN], path[SYSFS_PATH_MAX];
+ unsigned char target[SYSFS_PATH_MAX], *bus = NULL, *c = NULL;
+ struct dlist *buslist = NULL;
if (dev == NULL) {
errno = EINVAL;
return -1;
}
- strcpy(subsys, SYSFS_BUS_DIR); /* subsys = /bus */
+ memset(subsys, 0, SYSFS_NAME_LEN);
+ strcat(subsys, "/");
+ strcpy(subsys, SYSFS_BUS_NAME); /* subsys = /bus */
buslist = sysfs_open_subsystem_list(subsys);
if (buslist != NULL) {
dlist_for_each_data(buslist, bus, char) {
- device_list = sysfs_open_bus_devices_list(bus);
- if (device_list != NULL) {
- dlist_for_each_data(device_list,
- curdev, char) {
- if (strcmp(dev->bus_id, curdev) == 0
- && confirm_device_bus(dev, bus,
- curdev) > 0) {
- strcpy(dev->bus, bus);
- sysfs_close_list(device_list);
- sysfs_close_list(buslist);
- return 0;
- }
- }
- sysfs_close_list(device_list);
- }
+ memset(path, 0, SYSFS_PATH_MAX);
+ strcpy(path, dev->path);
+ c = strstr(path, "/devices");
+ if (c == NULL) {
+ dprintf("Invalid path to device %s\n", path);
+ sysfs_close_list(buslist);
+ return -1;
+ }
+ *c = '\0';
+ strcat(path, "/");
+ strcat(path, SYSFS_BUS_NAME);
+ strcat(path, "/");
+ strcat(path, bus);
+ strcat(path, "/");
+ strcat(path, SYSFS_DEVICES_NAME);
+ strcat(path, "/");
+ strcat(path, dev->bus_id);
+ if ((sysfs_path_is_link(path)) == 0) {
+ memset(target, 0, SYSFS_PATH_MAX);
+ if ((sysfs_get_link(path, target,
+ SYSFS_PATH_MAX)) != 0) {
+ dprintf("Error getting link target\n");
+ sysfs_close_list(buslist);
+ return -1;
+ }
+ if (!(strncmp(target, dev->path,
+ SYSFS_PATH_MAX))) {
+ strcpy(dev->bus, bus);
+ sysfs_close_list(buslist);
+ return 0;
+ }
+ }
}
sysfs_close_list(buslist);
}
@@ -157,28 +145,32 @@ static struct sysfs_device *alloc_device(void)
}
/**
- * sysfs_get_device_attr: searches dev's attributes by name
- * @dev: device to look through
- * @name: attribute name to get
- * returns sysfs_attribute reference with success or NULL with error.
+ * open_device_dir: opens up sysfs_directory for specific root dev
+ * @name: name of root
+ * returns struct sysfs_directory with success and NULL with error
*/
-struct sysfs_attribute *sysfs_get_device_attr(struct sysfs_device *dev,
- const unsigned char *name)
+static struct sysfs_directory *open_device_dir(const unsigned char *path)
{
- struct sysfs_attribute *cur = NULL;
+ struct sysfs_directory *rdir = NULL;
- if (dev == NULL || dev->directory == NULL
- || dev->directory->attributes == NULL || name == NULL) {
+ if (path == NULL) {
errno = EINVAL;
return NULL;
}
-
- cur = sysfs_get_directory_attribute(dev->directory,
- (unsigned char *)name);
- if (cur != NULL)
- return cur;
- return NULL;
+ rdir = sysfs_open_directory(path);
+ if (rdir == NULL) {
+ errno = EINVAL;
+ dprintf ("Device %s not supported on this system\n", path);
+ return NULL;
+ }
+ if ((sysfs_read_directory(rdir)) != 0) {
+ dprintf ("Error reading device at dir %s\n", path);
+ sysfs_close_directory(rdir);
+ return NULL;
+ }
+
+ return rdir;
}
/**
@@ -189,40 +181,34 @@ struct sysfs_attribute *sysfs_get_device_attr(struct sysfs_device *dev,
struct sysfs_device *sysfs_open_device(const unsigned char *path)
{
struct sysfs_device *dev = NULL;
- struct sysfs_directory *sdir = NULL;
if (path == NULL) {
errno = EINVAL;
return NULL;
}
+ if ((sysfs_path_is_dir(path)) != 0) {
+ dprintf("Incorrect path to device: %s\n", path);
+ return NULL;
+ }
dev = alloc_device();
if (dev == NULL) {
dprintf("Error allocating device at %s\n", path);
return NULL;
}
- sdir = sysfs_open_directory(path);
- if (sdir == NULL) {
- dprintf("Invalid device at %s\n", path);
+ if ((sysfs_get_name_from_path(path, dev->bus_id,
+ SYSFS_NAME_LEN)) != 0) {
errno = EINVAL;
+ dprintf("Error getting device bus_id\n");
sysfs_close_device(dev);
return NULL;
}
- if ((sysfs_read_directory(sdir)) != 0) {
- dprintf("Error reading device directory at %s\n", path);
- sysfs_close_directory(sdir);
- sysfs_close_device(dev);
- return NULL;
- }
- dev->directory = sdir;
- strcpy(dev->bus_id, sdir->name);
- strcpy(dev->path, sdir->path);
-
+ strcpy(dev->path, path);
/*
* The "name" attribute no longer exists... return the device's
* sysfs representation instead, in the "dev->name" field, which
* implies that the dev->name and dev->bus_id contain same data.
*/
- strncpy(dev->name, sdir->name, SYSFS_NAME_LEN);
+ strncpy(dev->name, dev->bus_id, SYSFS_NAME_LEN);
if (get_device_bus(dev) != 0)
strcpy(dev->bus, SYSFS_UNKNOWN);
@@ -251,6 +237,11 @@ static struct sysfs_device *sysfs_open_device_tree(const unsigned char *path)
dprintf("Error opening root device at %s\n", path);
return NULL;
}
+ if (rootdev->directory == NULL) {
+ rootdev->directory = open_device_dir(rootdev->path);
+ if (rootdev->directory == NULL)
+ return NULL;
+ }
if (rootdev->directory->subdirs != NULL) {
dlist_for_each_data(rootdev->directory->subdirs, cur,
struct sysfs_directory) {
@@ -288,63 +279,25 @@ void sysfs_close_root_device(struct sysfs_root_device *root)
}
/**
- * open_root_device_dir: opens up sysfs_directory for specific root dev
- * @name: name of root
- * returns struct sysfs_directory with success and NULL with error
- */
-static struct sysfs_directory *open_root_device_dir(const unsigned char *name)
-{
- struct sysfs_directory *rdir = NULL;
- unsigned char rootpath[SYSFS_PATH_MAX];
-
- if (name == NULL) {
- errno = EINVAL;
- return NULL;
- }
-
- memset(rootpath, 0, SYSFS_PATH_MAX);
- if (sysfs_get_mnt_path(rootpath, SYSFS_PATH_MAX) != 0) {
- dprintf ("Sysfs not supported on this system\n");
- return NULL;
- }
-
- if (sysfs_trailing_slash(rootpath) == 0)
- strcat(rootpath, "/");
-
- strcat(rootpath, SYSFS_DEVICES_NAME);
- strcat(rootpath, "/");
- strcat(rootpath, name);
- rdir = sysfs_open_directory(rootpath);
- if (rdir == NULL) {
- errno = EINVAL;
- dprintf ("Root device %s not supported on this system\n",
- name);
- return NULL;
- }
- if (sysfs_read_directory(rdir) != 0) {
- dprintf ("Error reading %s root device at dir %s\n", name,
- rootpath);
- sysfs_close_directory(rdir);
- return NULL;
- }
-
- return rdir;
-}
-
-/**
- * get_all_root_devices: opens up all the devices under this root device
+ * sysfs_get_root_devices: opens up all the devices under this root device
* @root: root device to open devices for
- * returns 0 with success and -1 with error
+ * returns dlist of devices with success and NULL with error
*/
-static int get_all_root_devices(struct sysfs_root_device *root)
+struct dlist *sysfs_get_root_devices(struct sysfs_root_device *root)
{
struct sysfs_device *dev = NULL;
struct sysfs_directory *cur = NULL;
- if (root == NULL || root->directory == NULL) {
+ if (root == NULL) {
errno = EINVAL;
- return -1;
+ return NULL;
+ }
+ if (root->directory == NULL) {
+ root->directory = open_device_dir(root->path);
+ if (root->directory == NULL)
+ return NULL;
}
+
if (root->directory->subdirs == NULL)
return 0;
@@ -362,7 +315,7 @@ static int get_all_root_devices(struct sysfs_root_device *root)
dlist_unshift(root->devices, dev);
}
- return 0;
+ return root->devices;
}
/**
@@ -374,33 +327,37 @@ static int get_all_root_devices(struct sysfs_root_device *root)
struct sysfs_root_device *sysfs_open_root_device(const unsigned char *name)
{
struct sysfs_root_device *root = NULL;
- struct sysfs_directory *rootdir = NULL;
+ unsigned char rootpath[SYSFS_PATH_MAX];
if (name == NULL) {
errno = EINVAL;
return NULL;
}
- root = (struct sysfs_root_device *)calloc
- (1, sizeof(struct sysfs_root_device));
- if (root == NULL) {
- dprintf("calloc failure\n");
+ memset(rootpath, 0, SYSFS_PATH_MAX);
+ if (sysfs_get_mnt_path(rootpath, SYSFS_PATH_MAX) != 0) {
+ dprintf ("Sysfs not supported on this system\n");
return NULL;
}
- rootdir = open_root_device_dir(name);
- if (rootdir == NULL) {
- dprintf ("Invalid root device, %s not supported\n", name);
- sysfs_close_root_device(root);
+
+ if (sysfs_trailing_slash(rootpath) == 0)
+ strcat(rootpath, "/");
+
+ strcat(rootpath, SYSFS_DEVICES_NAME);
+ strcat(rootpath, "/");
+ strcat(rootpath, name);
+ if ((sysfs_path_is_dir(rootpath)) != 0) {
+ errno = EINVAL;
+ dprintf("Invalid root device: %s\n", name);
return NULL;
}
- strcpy(root->path, rootdir->path);
- root->directory = rootdir;
- if (get_all_root_devices(root) != 0) {
- dprintf ("Error retrieving devices for root %s\n", name);
- sysfs_close_root_device(root);
+ root = (struct sysfs_root_device *)calloc
+ (1, sizeof(struct sysfs_root_device));
+ if (root == NULL) {
+ dprintf("calloc failure\n");
return NULL;
}
-
+ strcpy(root->path, rootpath);
return root;
}
@@ -411,13 +368,61 @@ struct sysfs_root_device *sysfs_open_root_device(const unsigned char *name)
*/
struct dlist *sysfs_get_device_attributes(struct sysfs_device *device)
{
- if (device == NULL || device->directory == NULL)
+ if (device == NULL)
return NULL;
+ if (device->directory == NULL) {
+ device->directory = sysfs_open_directory(device->path);
+ if (device->directory == NULL)
+ return NULL;
+ }
+ 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_get_device_attr: searches dev's attributes by name
+ * @dev: device to look through
+ * @name: attribute name to get
+ * returns sysfs_attribute reference with success or NULL with error.
+ */
+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);
+ if (cur != NULL)
+ return cur;
+
+ return NULL;
+}
+
+/**
* get_device_absolute_path: looks up the bus the device is on, gets
* absolute path to the device
* @device: device for which path is needed
@@ -428,24 +433,27 @@ struct dlist *sysfs_get_device_attributes(struct sysfs_device *device)
static int get_device_absolute_path(const unsigned char *device,
const unsigned char *bus, unsigned char *path, size_t psize)
{
- unsigned char bus_path[SYSFS_NAME_LEN];
+ unsigned char bus_path[SYSFS_PATH_MAX];
if (device == NULL || path == NULL) {
errno = EINVAL;
return -1;
}
- memset(bus_path, 0, SYSFS_NAME_LEN);
+ memset(bus_path, 0, SYSFS_PATH_MAX);
if (sysfs_get_mnt_path(bus_path, SYSFS_PATH_MAX) != 0) {
dprintf ("Sysfs not supported on this system\n");
return -1;
}
+
if (sysfs_trailing_slash(bus_path) == 0)
strcat(bus_path, "/");
+
strcat(bus_path, SYSFS_BUS_NAME);
strcat(bus_path, "/");
strcat(bus_path, bus);
- strcat(bus_path, SYSFS_DEVICES_DIR);
+ strcat(bus_path, "/");
+ strcat(bus_path, SYSFS_DEVICES_NAME);
strcat(bus_path, "/");
strcat(bus_path, device);
/*
@@ -464,7 +472,6 @@ static int get_device_absolute_path(const unsigned char *device,
* @bus_id: bus_id of the device to open - has to be the "bus_id" in
* /sys/bus/xxx/devices
* @bus: bus the device belongs to
- * @bsize: size of the bus buffer
* returns struct sysfs_device if found, NULL otherwise
* NOTE:
* 1. Use sysfs_close_device to close the device
@@ -472,7 +479,7 @@ static int get_device_absolute_path(const unsigned char *device,
* Use sysfs_find_device_bus to get the bus name
*/
struct sysfs_device *sysfs_open_device_by_id(const unsigned char *bus_id,
- const unsigned char *bus, size_t bsize)
+ const unsigned char *bus)
{
char sysfs_path[SYSFS_PATH_MAX];
struct sysfs_device *device = NULL;
diff --git a/libsysfs/sysfs_dir.c b/libsysfs/sysfs_dir.c
index e983d0eff4..ac2ecfcbe1 100644
--- a/libsysfs/sysfs_dir.c
+++ b/libsysfs/sysfs_dir.c
@@ -187,6 +187,13 @@ int sysfs_write_attribute(struct sysfs_attribute *sysattr,
return -1;
}
if (sysattr->method & SYSFS_METHOD_SHOW) {
+ /*
+ * read attribute again to see if we can get an updated value
+ */
+ if ((sysfs_read_attribute(sysattr)) != 0) {
+ dprintf("Error reading attribute\n");
+ return -1;
+ }
if ((strncmp(sysattr->value, new_value, sysattr->len)) == 0) {
dprintf("Attribute %s already has the requested value %s\n",
sysattr->name, new_value);
@@ -254,7 +261,7 @@ int sysfs_read_attribute(struct sysfs_attribute *sysattr)
unsigned char *fbuf = NULL;
unsigned char *vbuf = NULL;
size_t length = 0;
- int pgsize = 0;
+ long pgsize = 0;
int fd;
if (sysattr == NULL) {
@@ -269,7 +276,7 @@ int sysfs_read_attribute(struct sysfs_attribute *sysattr)
#ifdef __KLIBC__
pgsize = 0x4000;
#else
- pgsize = getpagesize();
+ pgsize = sysconf(_SC_PAGESIZE);
#endif
fbuf = (unsigned char *)calloc(1, pgsize+1);
if (fbuf == NULL) {
@@ -288,6 +295,14 @@ int sysfs_read_attribute(struct sysfs_attribute *sysattr)
free(fbuf);
return -1;
}
+ if (sysattr->len > 0) {
+ if ((sysattr->len == length) &&
+ (!(strncmp(sysattr->value, fbuf, length)))) {
+ close(fd);
+ return 0;
+ }
+ free(sysattr->value);
+ }
sysattr->len = length;
close(fd);
vbuf = (unsigned char *)realloc(fbuf, length+1);
@@ -389,6 +404,7 @@ void sysfs_close_directory(struct sysfs_directory *sysdir)
if (sysdir->attributes != NULL)
dlist_destroy(sysdir->attributes);
free(sysdir);
+ sysdir = NULL;
}
}
@@ -424,10 +440,12 @@ int sysfs_read_all_subdirs(struct sysfs_directory *sysdir)
errno = EINVAL;
return -1;
}
- if (sysdir->subdirs == NULL)
- return 0;
+ if (sysdir->subdirs == NULL)
+ if ((sysfs_read_dir_subdirs(sysdir) != 0)
+ || sysdir->subdirs == NULL)
+ return 0;
dlist_for_each_data(sysdir->subdirs, cursub, struct sysfs_directory) {
- if (sysfs_read_directory(cursub) != 0)
+ if ((sysfs_read_directory(cursub)) != 0)
dprintf ("Error reading subdirectory %s\n",
cursub->name);
}
@@ -494,18 +512,131 @@ struct sysfs_link *sysfs_open_link(const unsigned char *linkpath)
}
/**
- * sysfs_read_directory: grabs attributes, links, and subdirectories
+ * 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);
+ }
+ }
+ }
+ if (attrlist->count == 0) {
+ dprintf("No attributes in the list, destroying list now\n");
+ dlist_destroy(attrlist);
+ attrlist = NULL;
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * add_attribute: open and add attribute at path to given directory
+ * @sysdir: directory to add attribute to
+ * @path: path to attribute
+ * returns 0 with success and -1 with error.
+ */
+static int add_attribute(struct sysfs_directory *sysdir,
+ const unsigned char *path)
+{
+ struct sysfs_attribute *attr = NULL;
+
+ attr = sysfs_open_attribute(path);
+ if (attr == NULL) {
+ dprintf("Error opening attribute %s\n", path);
+ return -1;
+ }
+ if (attr->method & SYSFS_METHOD_SHOW) {
+ if ((sysfs_read_attribute(attr)) != 0) {
+ dprintf("Error reading attribute %s\n", path);
+ sysfs_close_attribute(attr);
+ return 0;
+ }
+ }
+
+ if (sysdir->attributes == NULL) {
+ sysdir->attributes = dlist_new_with_delete
+ (sizeof(struct sysfs_attribute), sysfs_del_attribute);
+ }
+ dlist_unshift(sysdir->attributes, attr);
+
+ return 0;
+}
+
+/**
+ * add_subdirectory: open and add subdirectory at path to given directory
+ * @sysdir: directory to add subdir to
+ * @path: path to subdirectory
+ * returns 0 with success and -1 with error.
+ */
+static int add_subdirectory(struct sysfs_directory *sysdir,
+ const unsigned char *path)
+{
+ struct sysfs_directory *subdir = NULL;
+
+ subdir = sysfs_open_directory(path);
+ if (subdir == NULL) {
+ dprintf("Error opening directory %s\n", path);
+ return -1;
+ }
+ if (sysdir->subdirs == NULL)
+ sysdir->subdirs = dlist_new_with_delete
+ (sizeof(struct sysfs_directory), sysfs_del_directory);
+ dlist_unshift(sysdir->subdirs, subdir);
+ return 0;
+}
+
+/**
+ * add_link: open and add link at path to given directory
+ * @sysdir: directory to add link to
+ * @path: path to link
+ * returns 0 with success and -1 with error.
+ */
+static int add_link(struct sysfs_directory *sysdir, const unsigned char *path)
+{
+ struct sysfs_link *ln = NULL;
+
+ ln = sysfs_open_link(path);
+ if (ln == NULL) {
+ dprintf("Error opening link %s\n", path);
+ return -1;
+ }
+ if (sysdir->links == NULL)
+ sysdir->links = dlist_new_with_delete
+ (sizeof(struct sysfs_link), sysfs_del_link);
+ dlist_unshift(sysdir->links, ln);
+ return 0;
+}
+
+/**
+ * sysfs_read_dir_attributes: grabs attributes for the given directory
* @sysdir: sysfs directory to open
* returns 0 with success and -1 with error.
*/
-int sysfs_read_directory(struct sysfs_directory *sysdir)
+int sysfs_read_dir_attributes(struct sysfs_directory *sysdir)
{
DIR *dir = NULL;
struct dirent *dirent = NULL;
struct stat astats;
- struct sysfs_attribute *attr = NULL;
- struct sysfs_directory *subdir = NULL;
- struct sysfs_link *ln = NULL;
unsigned char file_path[SYSFS_PATH_MAX];
int retval = 0;
@@ -531,54 +662,52 @@ int sysfs_read_directory(struct sysfs_directory *sysdir)
dprintf("stat failed\n");
continue;
}
- if (S_ISREG(astats.st_mode)) {
- attr = sysfs_open_attribute(file_path);
- if (attr == NULL) {
- dprintf("Error opening attribute %s\n",
- file_path);
- retval = -1;
- break;
- }
- if (attr->method & SYSFS_METHOD_SHOW) {
- if ((sysfs_read_attribute(attr)) != 0) {
- dprintf("Error reading attribute %s\n",
- file_path);
- sysfs_close_attribute(attr);
- continue;
- }
- }
-
- if (sysdir->attributes == NULL) {
- sysdir->attributes = dlist_new_with_delete
- (sizeof(struct sysfs_attribute),
- sysfs_del_attribute);
- }
- dlist_unshift(sysdir->attributes, attr);
- } else if (S_ISDIR(astats.st_mode)) {
- subdir = sysfs_open_directory(file_path);
- if (subdir == NULL) {
- dprintf("Error opening directory %s\n",
- file_path);
- retval = -1;
- break;
- }
- if (sysdir->subdirs == NULL)
- sysdir->subdirs = dlist_new_with_delete
- (sizeof(struct sysfs_directory),
- sysfs_del_directory);
- dlist_unshift(sysdir->subdirs, subdir);
- } else if (S_ISLNK(astats.st_mode)) {
- ln = sysfs_open_link(file_path);
- if (ln == NULL) {
- dprintf("Error opening link %s\n", file_path);
- retval = -1;
+ if (S_ISREG(astats.st_mode))
+ retval = add_attribute(sysdir, file_path);
+ }
+ closedir(dir);
+ return(retval);
+}
+
+/**
+ * sysfs_read_dir_links: grabs links in a specific directory
+ * @sysdir: sysfs directory to read links
+ * returns 0 with success and -1 with error.
+ */
+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;
+
+ if (sysdir == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ dir = opendir(sysdir->path);
+ if (dir == NULL) {
+ dprintf("Error opening directory %s\n", sysdir->path);
+ return -1;
+ }
+ while(((dirent = readdir(dir)) != NULL) && retval == 0) {
+ if (0 == strcmp(dirent->d_name, "."))
+ continue;
+ if (0 == strcmp(dirent->d_name, ".."))
+ continue;
+ memset(file_path, 0, SYSFS_PATH_MAX);
+ strncpy(file_path, sysdir->path, sizeof(file_path));
+ strncat(file_path, "/", sizeof(file_path));
+ strncat(file_path, dirent->d_name, sizeof(file_path));
+ if ((lstat(file_path, &astats)) != 0) {
+ dprintf("stat failed\n");
+ continue;
+ }
+ if (S_ISLNK(astats.st_mode)) {
+ retval = add_link(sysdir, file_path);
+ if (retval != 0)
break;
- }
- if (sysdir->links == NULL)
- sysdir->links = dlist_new_with_delete
- (sizeof(struct sysfs_link),
- sysfs_del_link);
- dlist_unshift(sysdir->links, ln);
}
}
closedir(dir);
@@ -586,7 +715,98 @@ int sysfs_read_directory(struct sysfs_directory *sysdir)
}
/**
- * sysfs_get_directory_attribute: retrieves attribute attrname
+ * sysfs_read_dir_subdirs: grabs subdirs in a specific directory
+ * @sysdir: sysfs directory to read links
+ * returns 0 with success and -1 with error.
+ */
+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;
+
+ if (sysdir == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ dir = opendir(sysdir->path);
+ if (dir == NULL) {
+ dprintf("Error opening directory %s\n", sysdir->path);
+ return -1;
+ }
+ while(((dirent = readdir(dir)) != NULL) && retval == 0) {
+ if (0 == strcmp(dirent->d_name, "."))
+ continue;
+ if (0 == strcmp(dirent->d_name, ".."))
+ continue;
+ memset(file_path, 0, SYSFS_PATH_MAX);
+ strncpy(file_path, sysdir->path, sizeof(file_path));
+ strncat(file_path, "/", sizeof(file_path));
+ strncat(file_path, dirent->d_name, sizeof(file_path));
+ if ((lstat(file_path, &astats)) != 0) {
+ dprintf("stat failed\n");
+ continue;
+ }
+ if (S_ISDIR(astats.st_mode))
+ retval = add_subdirectory(sysdir, file_path);
+ }
+ closedir(dir);
+ return(retval);
+}
+
+/**
+ * sysfs_read_directory: grabs attributes, links, and subdirectories
+ * @sysdir: sysfs directory to open
+ * returns 0 with success and -1 with error.
+ */
+int sysfs_read_directory(struct sysfs_directory *sysdir)
+{
+ DIR *dir = NULL;
+ struct dirent *dirent = NULL;
+ struct stat astats;
+ unsigned char file_path[SYSFS_PATH_MAX];
+ int retval = 0;
+
+ if (sysdir == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+ dir = opendir(sysdir->path);
+ if (dir == NULL) {
+ dprintf("Error opening directory %s\n", sysdir->path);
+ return -1;
+ }
+ while(((dirent = readdir(dir)) != NULL) && retval == 0) {
+ if (0 == strcmp(dirent->d_name, "."))
+ continue;
+ if (0 == strcmp(dirent->d_name, ".."))
+ continue;
+ memset(file_path, 0, SYSFS_PATH_MAX);
+ strncpy(file_path, sysdir->path, sizeof(file_path));
+ strncat(file_path, "/", sizeof(file_path));
+ strncat(file_path, dirent->d_name, sizeof(file_path));
+ if ((lstat(file_path, &astats)) != 0) {
+ dprintf("stat failed\n");
+ continue;
+ }
+ if (S_ISDIR(astats.st_mode))
+ retval = add_subdirectory(sysdir, file_path);
+
+ else if (S_ISLNK(astats.st_mode))
+ retval = add_link(sysdir, file_path);
+
+ else if (S_ISREG(astats.st_mode))
+ retval = add_attribute(sysdir, file_path);
+ }
+ closedir(dir);
+ return(retval);
+}
+
+/**
+ * sysfs_get_directory_attribute: retrieves attribute attrname from current
+ * directory only
* @dir: directory to retrieve attribute from
* @attrname: name of attribute to look for
* returns sysfs_attribute if found and NULL if not found
@@ -594,27 +814,38 @@ int sysfs_read_directory(struct sysfs_directory *sysdir)
struct sysfs_attribute *sysfs_get_directory_attribute
(struct sysfs_directory *dir, unsigned char *attrname)
{
- struct sysfs_directory *sdir = NULL;
struct sysfs_attribute *attr = NULL;
+ unsigned char new_path[SYSFS_PATH_MAX];
if (dir == NULL || attrname == NULL) {
errno = EINVAL;
return NULL;
}
-
- attr = (struct sysfs_attribute *)dlist_find_custom(dir->attributes,
- attrname, dir_attribute_name_equal);
- if (attr != NULL)
+
+ if (dir->attributes == NULL)
+ if ((sysfs_read_dir_attributes(dir) != 0)
+ || (dir->attributes == NULL))
+ return NULL;
+
+ attr = (struct sysfs_attribute *)dlist_find_custom
+ (dir->attributes, attrname, dir_attribute_name_equal);
+ if (attr != NULL) {
+ /*
+ * don't read here since we would have read the attribute in
+ * in the routine that called this routine
+ */
return attr;
-
- if (dir->subdirs != NULL) {
- dlist_for_each_data(dir->subdirs, sdir,
- struct sysfs_directory) {
- if (sdir->attributes == NULL)
- continue;
- attr = sysfs_get_directory_attribute(sdir, attrname);
- if (attr != NULL)
- return attr;
+ } 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) {
+ attr = (struct sysfs_attribute *)dlist_find_custom
+ (dir->attributes, attrname, dir_attribute_name_equal);
+ }
+ return attr;
}
}
return NULL;
@@ -633,6 +864,10 @@ struct sysfs_link *sysfs_get_directory_link
errno = EINVAL;
return NULL;
}
+ if (dir->links == NULL)
+ if ((sysfs_read_dir_links(dir) != 0) || (dir->links == NULL))
+ return NULL;
+
return (struct sysfs_link *)dlist_find_custom(dir->links,
linkname, dir_link_name_equal);
}
@@ -648,10 +883,15 @@ struct sysfs_directory *sysfs_get_subdirectory(struct sysfs_directory *dir,
{
struct sysfs_directory *sub = NULL, *cursub = NULL;
- if (dir == NULL || dir->subdirs == NULL || subname == NULL) {
+ if (dir == NULL || subname == NULL) {
errno = EINVAL;
return NULL;
}
+
+ if (dir->subdirs == NULL)
+ if (sysfs_read_dir_subdirs(dir) != 0)
+ return NULL;
+
sub = (struct sysfs_directory *)dlist_find_custom(dir->subdirs,
subname, dir_subdir_name_equal);
if (sub != NULL)
@@ -660,8 +900,12 @@ struct sysfs_directory *sysfs_get_subdirectory(struct sysfs_directory *dir,
if (dir->subdirs != NULL) {
dlist_for_each_data(dir->subdirs, cursub,
struct sysfs_directory) {
- if (cursub->subdirs == NULL)
- continue;
+ if (cursub->subdirs == NULL) {
+ if (sysfs_read_dir_subdirs(cursub) != 0)
+ continue;
+ if (cursub->subdirs == NULL)
+ continue;
+ }
sub = sysfs_get_subdirectory(cursub, subname);
if (sub != NULL)
return sub;
@@ -682,7 +926,7 @@ struct sysfs_link *sysfs_get_subdirectory_link(struct sysfs_directory *dir,
struct sysfs_directory *cursub = NULL;
struct sysfs_link *ln = NULL;
- if (dir == NULL || dir->links == NULL || linkname == NULL) {
+ if (dir == NULL || linkname == NULL) {
errno = EINVAL;
return NULL;
}
@@ -691,14 +935,13 @@ struct sysfs_link *sysfs_get_subdirectory_link(struct sysfs_directory *dir,
if (ln != NULL)
return ln;
- if (dir->subdirs == NULL)
- return NULL;
+ if (dir->subdirs == NULL)
+ if (sysfs_read_dir_subdirs(dir) != 0)
+ return NULL;
if (dir->subdirs != NULL) {
dlist_for_each_data(dir->subdirs, cursub,
struct sysfs_directory) {
- if (cursub->subdirs == NULL)
- continue;
ln = sysfs_get_subdirectory_link(cursub, linkname);
if (ln != NULL)
return ln;
diff --git a/libsysfs/sysfs_driver.c b/libsysfs/sysfs_driver.c
index 1877dbce0b..4372b19f10 100644
--- a/libsysfs/sysfs_driver.c
+++ b/libsysfs/sysfs_driver.c
@@ -23,36 +23,16 @@
#include "libsysfs.h"
#include "sysfs.h"
-static void sysfs_close_driver_by_name_dev(void *device)
+static void sysfs_close_driver_device(void *device)
{
sysfs_close_device((struct sysfs_device *)device);
}
-/**
- * sysfs_close_driver: closes and cleans up driver structure
- * NOTE: This routine does not deallocate devices list
- * @driver: driver to close
- */
-void sysfs_close_driver(struct sysfs_driver *driver)
-{
- if (driver != NULL) {
- if (driver->devices != NULL) {
- dlist_for_each(driver->devices)
- dlist_shift(driver->devices);
- free(driver->devices);
- driver->devices = NULL;
- }
- if (driver->directory != NULL)
- sysfs_close_directory(driver->directory);
- free(driver);
- }
-}
-
/**
- * sysfs_close_driver_by_name: closes driver and deletes device lists too
+ * sysfs_close_driver: closes driver and deletes device lists too
* @driver: driver to close
*/
-void sysfs_close_driver_by_name(struct sysfs_driver *driver)
+void sysfs_close_driver(struct sysfs_driver *driver)
{
if (driver != NULL) {
if (driver->devices != NULL)
@@ -64,6 +44,51 @@ void sysfs_close_driver_by_name(struct sysfs_driver *driver)
}
/**
+ * open_driver_dir: Open the sysfs_directory for this driver
+ * @driver: Driver whose directory to be opened
+ * Returns 0 on success and 1 on failure
+ */
+static int open_driver_dir(struct sysfs_driver *driver)
+{
+ if (driver == NULL) {
+ errno = EINVAL;
+ return 1;
+ }
+ if (driver->directory == NULL) {
+ driver->directory = sysfs_open_directory(driver->path);
+ if (driver->directory == NULL) {
+ dprintf("Error opening driver directory at %s\n",
+ driver->path);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/**
+ * read_driver_dir: Read driver directory's subdirs and links
+ * @driver: Driver to read
+ * Returns 0 on success and 1 on failure
+ */
+static int read_driver_dir(struct sysfs_driver *driver)
+{
+ if (driver == NULL) {
+ errno = EINVAL;
+ return 1;
+ }
+ if (driver->directory == NULL) {
+ if ((open_driver_dir(driver)) == 1)
+ return 1;
+ }
+ if ((sysfs_read_directory(driver->directory)) != 0) {
+ dprintf("Error reading driver directory at %s\n",
+ driver->path);
+ return 1;
+ }
+ return 0;
+}
+
+/**
* alloc_driver: allocates and initializes driver
* returns struct sysfs_driver with success and NULL with error.
*/
@@ -80,31 +105,27 @@ static struct sysfs_driver *alloc_driver(void)
struct sysfs_driver *sysfs_open_driver(const unsigned char *path)
{
struct sysfs_driver *driver = NULL;
- struct sysfs_directory *sdir = NULL;
if (path == NULL) {
errno = EINVAL;
return NULL;
}
- sdir = sysfs_open_directory(path);
- if (sdir == NULL) {
- dprintf("Error opening directory %s\n", path);
- return NULL;
- }
- if ((sysfs_read_directory(sdir)) != 0) {
- dprintf("Error reading directory %s\n", path);
- sysfs_close_directory(sdir);
+ if ((sysfs_path_is_dir(path)) != 0) {
+ dprintf("Invalid path to driver: %s\n", path);
return NULL;
}
driver = alloc_driver();
if (driver == NULL) {
dprintf("Error allocating driver at %s\n", path);
- sysfs_close_directory(sdir);
return NULL;
}
- strcpy(driver->name, sdir->name);
- driver->directory = sdir;
- strcpy(driver->path, sdir->path);
+ if ((sysfs_get_name_from_path(path, driver->name,
+ SYSFS_NAME_LEN)) != 0) {
+ dprintf("Error getting driver name from path\n");
+ free(driver);
+ return NULL;
+ }
+ strcpy(driver->path, path);
return driver;
}
@@ -117,9 +138,32 @@ struct sysfs_driver *sysfs_open_driver(const unsigned char *path)
*/
struct dlist *sysfs_get_driver_attributes(struct sysfs_driver *driver)
{
- if (driver == NULL || driver->directory == NULL)
+ if (driver == NULL) {
+ errno = EINVAL;
return NULL;
+ }
+ if (driver->directory == NULL) {
+ if ((open_driver_dir(driver)) == 1)
+ 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");
+ return NULL;
+ }
+ }
return(driver->directory->attributes);
}
@@ -133,18 +177,20 @@ 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 || drv->directory == NULL
- || drv->directory->attributes == NULL || name == NULL) {
+ if (drv == NULL) {
errno = EINVAL;
return NULL;
}
-
- cur = sysfs_get_directory_attribute(drv->directory,
- (unsigned char *)name);
- if (cur != NULL)
- return cur;
-
+
+ attrlist = sysfs_get_driver_attributes(drv);
+ if (attrlist != NULL) {
+ cur = sysfs_get_directory_attribute(drv->directory,
+ (unsigned char *)name);
+ if (cur != NULL)
+ return cur;
+ }
return NULL;
}
@@ -156,13 +202,96 @@ struct sysfs_attribute *sysfs_get_driver_attr(struct sysfs_driver *drv,
*/
struct dlist *sysfs_get_driver_links(struct sysfs_driver *driver)
{
- if (driver == NULL || driver->directory == NULL)
+ if (driver == NULL) {
+ errno = EINVAL;
return NULL;
-
+ }
+ if (driver->directory == NULL) {
+ if ((open_driver_dir(driver)) == 1)
+ return NULL;
+ if ((read_driver_dir(driver)) != 0)
+ return NULL;
+ }
return(driver->directory->links);
}
/**
+ * sysfs_get_driver_devices: open up the list of devices this driver supports
+ * @driver: sysfs_driver for which devices are needed
+ * Returns dlist of devices on SUCCESS or NULL with ERROR
+ */
+struct dlist *sysfs_get_driver_devices(struct sysfs_driver *driver)
+{
+ struct sysfs_link *curlink = NULL;
+ struct sysfs_device *device = NULL;
+
+ if (driver == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ if (driver->devices != NULL)
+ return (driver->devices);
+
+ if (driver->directory == NULL) {
+ if ((open_driver_dir(driver)) == 1)
+ return NULL;
+ if ((read_driver_dir(driver)) != 0)
+ return NULL;
+ }
+ if (driver->directory->links != NULL) {
+ dlist_for_each_data(driver->directory->links, curlink,
+ struct sysfs_link) {
+ device = sysfs_open_device(curlink->target);
+ if (device == NULL) {
+ dprintf("Error opening device at %s\n",
+ curlink->target);
+ return NULL;
+ }
+ strcpy(device->driver_name, driver->name);
+ if (driver->devices == NULL)
+ driver->devices = dlist_new_with_delete
+ (sizeof(struct sysfs_device),
+ sysfs_close_driver_device);
+ dlist_unshift(driver->devices, device);
+ }
+ }
+ return (driver->devices);
+}
+
+/**
+ * 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
+ * @name: name of the device to search
+ * Returns a sysfs_device if found, NULL otherwise
+ */
+struct sysfs_device *sysfs_get_driver_device(struct sysfs_driver *driver,
+ const unsigned char *name)
+{
+ struct sysfs_device *device = NULL;
+ struct dlist *devlist = NULL;
+
+ if (driver == NULL || name == NULL) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ if (driver->devices == NULL) {
+ devlist = sysfs_get_driver_devices(driver);
+ if (devlist == NULL) {
+ dprintf("Error getting driver devices\n");
+ return NULL;
+ }
+ }
+ dlist_for_each_data(driver->devices, device, struct sysfs_device) {
+ if (!(strncmp(device->name, name, SYSFS_NAME_LEN)))
+ return device;
+ }
+ return NULL;
+}
+
+/**
* get_driver_path: looks up the bus the driver is on and builds path to
* the driver.
* @bus: bus on which to search
@@ -171,8 +300,8 @@ struct dlist *sysfs_get_driver_links(struct sysfs_driver *driver)
* @psize: size of "path"
* Returns 0 on success and -1 on error
*/
-static int get_driver_path(const unsigned char *bus, const unsigned char *drv,
- unsigned char *path, size_t psize)
+static int get_driver_path(const unsigned char *bus,
+ const unsigned char *drv, unsigned char *path, size_t psize)
{
if (bus == NULL || drv == NULL || path == NULL) {
errno = EINVAL;
@@ -187,70 +316,14 @@ static int get_driver_path(const unsigned char *bus, const unsigned char *drv,
strcat(path, SYSFS_BUS_NAME);
strcat(path, "/");
strcat(path, bus);
- strcat(path, SYSFS_DRIVERS_DIR);
+ strcat(path, "/");
+ strcat(path, SYSFS_DRIVERS_NAME);
strcat(path, "/");
strcat(path, drv);
return 0;
}
/**
- * sysfs_open_driver_by_name: open a driver by name and return the bus
- * the driver is on.
- * @drv_name: driver to open
- * @bus: the driver bus
- * @bsize: size of bus buffer
- * returns struct sysfs_driver if found, NULL otherwise
- * NOTE:
- * 1. Need to call sysfs_close_driver_by_name to free up memory
- * 2. Bus the driver is registered with must be supplied.
- * Use sysfs_find_driver_bus() to obtain the bus name
- */
-struct sysfs_driver *sysfs_open_driver_by_name(const unsigned char *drv_name,
- const unsigned char *bus, size_t bsize)
-{
- struct sysfs_driver *driver = NULL;
- struct sysfs_device *device = NULL;
- struct sysfs_link *curlink = NULL;
- unsigned char path[SYSFS_PATH_MAX];
-
- if (drv_name == NULL || bus == NULL) {
- errno = EINVAL;
- return NULL;
- }
-
- memset(path, 0, SYSFS_PATH_MAX);
- if (get_driver_path(bus, drv_name, path, SYSFS_PATH_MAX) != 0) {
- dprintf("Error getting to driver %s\n", drv_name);
- return NULL;
- }
- driver = sysfs_open_driver(path);
- if (driver == NULL) {
- dprintf("Could not open driver %s\n", drv_name);
- return NULL;
- }
- if (driver->directory->links != NULL) {
- dlist_for_each_data(driver->directory->links, curlink,
- struct sysfs_link) {
- device = sysfs_open_device(curlink->target);
- if (device == NULL) {
- dprintf("Error opening device at %s\n",
- curlink->target);
- sysfs_close_driver_by_name(driver);
- return NULL;
- }
- strcpy(device->driver_name, drv_name);
- if (driver->devices == NULL)
- driver->devices = dlist_new_with_delete
- (sizeof(struct sysfs_device),
- sysfs_close_driver_by_name_dev);
- dlist_unshift(driver->devices, device);
- }
- }
- return driver;
-}
-
-
-/**
* sysfs_open_driver_attr: read the user supplied driver attribute
* @bus: bus on which to look
* @drv: driver whose attribute has to be read
diff --git a/libsysfs/sysfs_utils.c b/libsysfs/sysfs_utils.c
index 627e618dce..c2ce13433d 100644
--- a/libsysfs/sysfs_utils.c
+++ b/libsysfs/sysfs_utils.c
@@ -280,7 +280,7 @@ struct dlist *sysfs_open_subsystem_list(unsigned char *name)
* name requested here is "class", verify if "block" is supported on
* this system and return the same.
*/
- if (strcmp(name, SYSFS_CLASS_DIR) == 0) {
+ if (strcmp(name, SYSFS_CLASS_NAME) == 0) {
c = strstr(sysfs_path, SYSFS_CLASS_NAME);
if (c == NULL)
goto out;
@@ -325,7 +325,8 @@ struct dlist *sysfs_open_bus_devices_list(unsigned char *name)
strcat(sysfs_path, SYSFS_BUS_NAME);
strcat(sysfs_path, "/");
strcat(sysfs_path, name);
- strcat(sysfs_path, SYSFS_DEVICES_DIR);
+ strcat(sysfs_path, "/");
+ strcat(sysfs_path, SYSFS_DEVICES_NAME);
dir = sysfs_open_directory(sysfs_path);
if (dir == NULL) {
dprintf("Error opening sysfs_directory at %s\n", sysfs_path);
@@ -358,3 +359,71 @@ struct dlist *sysfs_open_bus_devices_list(unsigned char *name)
return list;
}
+/**
+ * sysfs_path_is_dir: Check if the path supplied points to a directory
+ * @path: path to validate
+ * Returns 0 if path points to dir, 1 otherwise
+ */
+int sysfs_path_is_dir(const unsigned char *path)
+{
+ struct stat astats;
+
+ if (path == NULL) {
+ errno = EINVAL;
+ return 1;
+ }
+ if ((lstat(path, &astats)) != 0) {
+ dprintf("stat() failed\n");
+ return 1;
+ }
+ if (S_ISDIR(astats.st_mode))
+ return 0;
+
+ return 1;
+}
+
+/**
+ * sysfs_path_is_link: Check if the path supplied points to a link
+ * @path: path to validate
+ * Returns 0 if path points to link, 1 otherwise
+ */
+int sysfs_path_is_link(const unsigned char *path)
+{
+ struct stat astats;
+
+ if (path == NULL) {
+ errno = EINVAL;
+ return 1;
+ }
+ if ((lstat(path, &astats)) != 0) {
+ dprintf("stat() failed\n");
+ return 1;
+ }
+ if (S_ISLNK(astats.st_mode))
+ return 0;
+
+ return 1;
+}
+
+/**
+ * sysfs_path_is_file: Check if the path supplied points to a file
+ * @path: path to validate
+ * Returns 0 if path points to file, 1 otherwise
+ */
+int sysfs_path_is_file(const unsigned char *path)
+{
+ struct stat astats;
+
+ if (path == NULL) {
+ errno = EINVAL;
+ return 1;
+ }
+ if ((lstat(path, &astats)) != 0) {
+ dprintf("stat() failed\n");
+ return 1;
+ }
+ if (S_ISREG(astats.st_mode))
+ return 0;
+
+ return 1;
+}