summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordsteklof@us.ibm.com <dsteklof@us.ibm.com>2003-12-15 21:53:28 -0800
committerGreg KH <gregkh@suse.de>2005-04-26 21:13:07 -0700
commit5d4754f19521568b775ba7a31465d3af192ce382 (patch)
tree7a012e2f8729e9667e7ba61a6417b2338973c209
parent71896b56ee03a8f31c89263bbf5f4cb7201666be (diff)
[PATCH] pre-libsysfs-0.4.0 patch
I am sending you a pre-release patch. It's everything that's in our current CVS tree. It adds the functionality you've been looking for. Please play with this before checking it into your tree, I'd like to know if it's ok with you or if you find problems. I have tested this out with test.all and the perl regression test. Let me know what you think. Still need to do more testing for our work and add some more functions related to the changes. I've gone into namedev.c and udev-add.c to make the necessary changes in line with the library. I have not gone and edited any of the "extras". Changes: 1) Libsysfs object structures work more as handles now, their included directories or devices are labeled private. If you need attributes from a sysfs_class_device, call the available function and don't access the directory directly. Same holds true for a sysfs_class_device sysfs_device. Do not access the link directly but call the function sysfs_get_classdev_device() instead. We only populate entries upon request, makes things faster and uses less memory. 2) Added sysfs_get_classdev_parent() as requested. 3) Changed getpagesize to sysconf. 4) Added sysfs_refresh_attributes function for refreshing views of attribute lists. We still need to add refresh for links and subdirs. All udev needs to do is keep calling sysfs_get_classdev_attr() and that will internally call the refresh routine.
-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
-rw-r--r--namedev.c25
-rw-r--r--udev-add.c10
9 files changed, 1175 insertions, 699 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;
+}
diff --git a/namedev.c b/namedev.c
index 75e4d22370..633a7bf0da 100644
--- a/namedev.c
+++ b/namedev.c
@@ -552,37 +552,29 @@ int namedev_name_device(struct sysfs_class_device *class_dev, struct udevice *ud
struct sysfs_device *sysfs_device = NULL;
struct sysfs_class_device *class_dev_parent = NULL;
int retval = 0;
- char *temp = NULL;
struct perm_device *perm;
udev->mode = 0;
/* find the sysfs_device for this class device */
/* Wouldn't it really be nice if libsysfs could do this for us? */
- if (class_dev->sysdevice) {
- sysfs_device = class_dev->sysdevice;
- } else {
+ sysfs_device = sysfs_get_classdev_device(class_dev);
+ if (sysfs_device == NULL) {
/* bah, let's go backwards up a level to see if the device is there,
* as block partitions don't point to the physical device. Need to fix that
* up in the kernel...
*/
- if (strstr(class_dev->path, "block")) {
+ if (strcmp(class_dev->classname, SYSFS_BLOCK_NAME) == 0) {
dbg("looking at block device");
if (isdigit(class_dev->path[strlen(class_dev->path)-1])) {
- char path[SYSFS_PATH_MAX];
-
dbg("really is a partition");
- strfieldcpy(path, class_dev->path);
- temp = strrchr(path, '/');
- *temp = 0x00;
- dbg("looking for a class device at '%s'", path);
- class_dev_parent = sysfs_open_class_device(path);
+ class_dev_parent = sysfs_get_classdev_parent
+ (class_dev);
if (class_dev_parent == NULL) {
- dbg("sysfs_open_class_device at '%s' failed", path);
+ dbg("sysfs_get_classdev_parent for class device '%s' failed", class_dev->name);
} else {
dbg("class_dev_parent->name='%s'", class_dev_parent->name);
- if (class_dev_parent->sysdevice)
- sysfs_device = class_dev_parent->sysdevice;
+ sysfs_device = sysfs_get_classdev_device(class_dev_parent);
}
}
}
@@ -643,9 +635,6 @@ done:
dbg("name, '%s' is going to have owner='%s', group='%s', mode = %#o",
udev->name, udev->owner, udev->group, udev->mode);
- if (class_dev_parent)
- sysfs_close_class_device(class_dev_parent);
-
return 0;
}
diff --git a/udev-add.c b/udev-add.c
index e64a845c7e..33ee633fd8 100644
--- a/udev-add.c
+++ b/udev-add.c
@@ -54,14 +54,14 @@
static int get_major_minor(struct sysfs_class_device *class_dev, struct udevice *udev)
{
int retval = -ENODEV;
- char *dev;
+ struct sysfs_attribute *attr = NULL;
- dev = sysfs_get_value_from_attributes(class_dev->directory->attributes, "dev");
- if (dev == NULL)
+ attr = sysfs_get_classdev_attr(class_dev, "dev");
+ if (attr == NULL)
goto exit;
- dbg("dev='%s'", dev);
+ dbg("dev='%s'", attr->value);
- if (sscanf(dev, "%u:%u", &udev->major, &udev->minor) != 2)
+ if (sscanf(attr->value, "%u:%u", &udev->major, &udev->minor) != 2)
goto exit;
dbg("found major=%d, minor=%d", udev->major, udev->minor);