hal/hald/linux/libsysfs dlist.c, 1.1, 1.2 dlist.h, 1.1, 1.2 libsysfs.h, 1.1, 1.2 sysfs.h, 1.1, 1.2 sysfs_bus.c, 1.1, 1.2 sysfs_class.c, 1.1, 1.2 sysfs_device.c, 1.1, 1.2 sysfs_dir.c, 1.1, 1.2 sysfs_driver.c, 1.1, 1.2 sysfs_utils.c, 1.1, 1.2

David Zeuthen david at freedesktop.org
Sun Jul 18 08:21:25 PDT 2004


Update of /cvs/hal/hal/hald/linux/libsysfs
In directory pdx:/tmp/cvs-serv32699/hald/linux/libsysfs

Modified Files:
	dlist.c dlist.h libsysfs.h sysfs.h sysfs_bus.c sysfs_class.c 
	sysfs_device.c sysfs_dir.c sysfs_driver.c sysfs_utils.c 
Log Message:
2004-07-18  David Zeuthen  <david at fubar.dk>

	Patch from Kay Sievers <kay.sievers at vrfy.org>

	* hald/linux/libsysfs/*.[ch]: 
	(visit_device), (osspec_probe): Update to libsysfs 1.1

	* hald/linux/bus_device.c: (bus_device_got_parent):
	* hald/linux/class_device.c: (class_device_final):
	* hald/linux/osspec.c: (visit_class_device), (visit_class),
	Adjust to use libsysfs 1.1



Index: dlist.c
===================================================================
RCS file: /cvs/hal/hal/hald/linux/libsysfs/dlist.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- dlist.c	14 Dec 2003 21:22:43 -0000	1.1
+++ dlist.c	18 Jul 2004 15:21:23 -0000	1.2
@@ -73,14 +73,14 @@
 {
   if(direction)
     {
-      if( list->marker->next!=NULL)
+      if( list->marker && list->marker->next!=NULL)
 	list->marker=list->marker->next;
       else
 	return(NULL);
     }
   else
     {
-      if( list->marker->prev!=NULL)
+      if( list->marker && list->marker->prev!=NULL)
 	list->marker=list->marker->prev;
       else
 	return(NULL);
@@ -259,6 +259,16 @@
   dlist_insert(list,data,0);
 }
 
+void dlist_unshift_sorted(Dlist *list, void *data, 
+			int (*sorter)(void *new_elem, void *old_elem))
+{
+	if (list->count == 0)
+		dlist_unshift(list, data);
+	else {
+		list->marker=list->head->next;
+		dlist_insert_sorted(list, data, sorter);
+	}
+}
 
 /* 
  * Remove end node from list.

Index: dlist.h
===================================================================
RCS file: /cvs/hal/hal/hald/linux/libsysfs/dlist.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- dlist.h	14 Dec 2003 21:22:43 -0000	1.1
+++ dlist.h	18 Jul 2004 15:21:23 -0000	1.2
@@ -77,13 +77,14 @@
 
 void *dlist_insert(Dlist *,void *,int) ;
 
-void *dlist_insert_sorted(struct dlist *list, void *new, int (*sorter)(void *, void *));
+void *dlist_insert_sorted(struct dlist *list, void *new_elem, int (*sorter)(void *, void *));
 
 void dlist_delete(Dlist *,int);
 
 void dlist_push(Dlist *,void *);
 
 void dlist_unshift(Dlist *,void *);
+void dlist_unshift_sorted(Dlist *,void *,int (*sorter)(void *, void *));
 
 void *dlist_pop(Dlist *);
 

Index: libsysfs.h
===================================================================
RCS file: /cvs/hal/hal/hald/linux/libsysfs/libsysfs.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- libsysfs.h	14 Dec 2003 21:22:43 -0000	1.1
+++ libsysfs.h	18 Jul 2004 15:21:23 -0000	1.2
@@ -24,22 +24,36 @@
 #define _LIBSYSFS_H_
 
 #include <sys/types.h>
+#include <string.h>
 #include "dlist.h"
 
+/* 
+ * Defines to prevent buffer overruns
+ */
+#define safestrcpy(to, from)	strncpy(to, from, sizeof(to)-1)
+#define safestrcat(to, from)	strncat(to, from, sizeof(to) - strlen(to)-1)
+
+#define safestrcpymax(to, from, max) \
+do { \
+	to[max-1] = '\0'; \
+	strncpy(to, from, max-1); \
+} while (0)
+
+#define safestrcatmax(to, from, max) \
+do { \
+	to[max-1] = '\0'; \
+	strncat(to, from, max - strlen(to)-1); \
+} while (0)
+
 /*
  * Generic #defines go here..
  */ 
 #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"
@@ -52,86 +66,94 @@
 #define SYSFS_METHOD_SHOW	0x01	/* attr can be read by user */
 #define SYSFS_METHOD_STORE	0x02	/* attr can be changed by user */
 
+/*
+ * NOTE: We have the statically allocated "name" as the first element of all 
+ * the structures. This feature is used in the "sorter" function for dlists
+ */
+
 struct sysfs_attribute {
-	unsigned char *value;
+	char name[SYSFS_NAME_LEN];
+	char path[SYSFS_PATH_MAX];
+	char *value;
 	unsigned short len;		/* value length */
 	unsigned short method;		/* show and store */
-	unsigned char name[SYSFS_NAME_LEN];
-	unsigned char path[SYSFS_PATH_MAX];
 };
 
 struct sysfs_link {
-	unsigned char name[SYSFS_NAME_LEN];
-	unsigned char path[SYSFS_PATH_MAX];
-	unsigned char target[SYSFS_PATH_MAX];
+	char name[SYSFS_NAME_LEN];
+	char path[SYSFS_PATH_MAX];
+	char target[SYSFS_PATH_MAX];
 };
 
 struct sysfs_directory {
+	char name[SYSFS_NAME_LEN];
+	char path[SYSFS_PATH_MAX];
+
+	/* Private: for internal use only */
 	struct dlist *subdirs;	
 	struct dlist *links;		
 	struct dlist *attributes;
-	unsigned char name[SYSFS_NAME_LEN];
-	unsigned char path[SYSFS_PATH_MAX];
 };
 
 struct sysfs_driver {
-	struct dlist *devices;
-	unsigned char name[SYSFS_NAME_LEN];
-	unsigned char path[SYSFS_PATH_MAX];
+	char name[SYSFS_NAME_LEN];
+	char path[SYSFS_PATH_MAX];
 
-	/* for internal use only */
+	/* Private: for internal use only */
+	struct dlist *devices;
 	struct sysfs_directory *directory;	
 };
 
 struct sysfs_device {
+	char name[SYSFS_NAME_LEN];
+	char bus_id[SYSFS_NAME_LEN];
+	char bus[SYSFS_NAME_LEN];
+	char driver_name[SYSFS_NAME_LEN];
+	char path[SYSFS_PATH_MAX];
+
+	/* Private: for internal use only */
 	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];
-	unsigned char driver_name[SYSFS_NAME_LEN];
-	unsigned char path[SYSFS_PATH_MAX];
-
-	/* for internal use only */
 	struct sysfs_directory *directory;	
 };
 
 struct sysfs_root_device {
-	struct dlist *devices;
-	unsigned char name[SYSFS_NAME_LEN];
-	unsigned char path[SYSFS_PATH_MAX];
+	char name[SYSFS_NAME_LEN];
+	char path[SYSFS_PATH_MAX];
 
-	/* for internal use only */
+	/* Private: for internal use only */
+	struct dlist *devices;
 	struct sysfs_directory *directory;
 };
 
 struct sysfs_bus {
+	char name[SYSFS_NAME_LEN];
+	char path[SYSFS_PATH_MAX];
+
+	/* Private: for internal use only */
 	struct dlist *drivers;
 	struct dlist *devices;
-	unsigned char name[SYSFS_NAME_LEN];
-	unsigned char path[SYSFS_PATH_MAX];
-
-	/* internal use only */
 	struct sysfs_directory *directory;	
 };
 
 struct sysfs_class_device {
+	char name[SYSFS_NAME_LEN];
+	char classname[SYSFS_NAME_LEN];
+	char path[SYSFS_PATH_MAX];
+
+	/* Private: for internal use only */
+	struct sysfs_class_device *parent;	
 	struct sysfs_device *sysdevice;		/* NULL if virtual */
 	struct sysfs_driver *driver;		/* NULL if not implemented */
-	unsigned char name[SYSFS_NAME_LEN];
-	unsigned char classname[SYSFS_NAME_LEN];
-	unsigned char path[SYSFS_PATH_MAX];
-
-	/* for internal use only */
 	struct sysfs_directory *directory;	
 };
 
 struct sysfs_class {
-	struct dlist *devices;
-	unsigned char name[SYSFS_NAME_LEN];
-	unsigned char path[SYSFS_PATH_MAX];
+	char name[SYSFS_NAME_LEN];
+	char path[SYSFS_PATH_MAX];
 
-	/* for internal use only */
+	/* Private: for internal use only */
+	struct dlist *devices;
 	struct sysfs_directory *directory;	
 };
 
@@ -142,99 +164,149 @@
 /*
  * Function Prototypes
  */
-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_get_link(const unsigned char *path, unsigned char *target, 
-								size_t len);
-extern struct dlist *sysfs_open_subsystem_list(unsigned char *name);
-extern struct dlist *sysfs_open_bus_devices_list(unsigned char *name);
+extern int sysfs_get_mnt_path(char *mnt_path, size_t len);
+extern int sysfs_remove_trailing_slash(char *path);
+extern int sysfs_get_name_from_path(const char *path, char *name, size_t len);
+extern int sysfs_path_is_dir(const char *path);
+extern int sysfs_path_is_link(const char *path);
+extern int sysfs_path_is_file(const char *path);
+extern int sysfs_get_link(const char *path, char *target, size_t len);
+extern struct dlist *sysfs_open_subsystem_list(char *name);
+extern struct dlist *sysfs_open_bus_devices_list(char *name);
 extern void sysfs_close_list(struct dlist *list);
 
 /* sysfs directory and file access */
 extern void sysfs_close_attribute(struct sysfs_attribute *sysattr);
-extern struct sysfs_attribute *sysfs_open_attribute(const unsigned char *path);
+extern struct sysfs_attribute *sysfs_open_attribute(const char *path);
 extern int sysfs_read_attribute(struct sysfs_attribute *sysattr);
-extern int sysfs_read_attribute_value(const unsigned char *attrpath, 
-				unsigned char *value, size_t vsize);
+extern int sysfs_read_attribute_value(const char *attrpath, 
+		char *value, size_t vsize);
 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);
+		const char *new_value, size_t len);
+extern char *sysfs_get_value_from_attributes(struct dlist *attr, 
+		const char *name);
+extern int sysfs_refresh_dir_attributes(struct sysfs_directory *sysdir);
+extern int sysfs_refresh_dir_links(struct sysfs_directory *sysdir);
+extern int sysfs_refresh_dir_subdirs(struct sysfs_directory *sysdir);
 extern void sysfs_close_directory(struct sysfs_directory *sysdir);
-extern struct sysfs_directory *sysfs_open_directory(const unsigned char *path);
+extern struct sysfs_directory *sysfs_open_directory(const 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
-			(struct sysfs_directory *dir, unsigned char *subname);
+	(struct sysfs_directory *dir, char *subname);
 extern void sysfs_close_link(struct sysfs_link *ln);
-extern struct sysfs_link *sysfs_open_link(const unsigned char *lnpath);
-extern struct sysfs_link *sysfs_get_directory_link(struct sysfs_directory *dir,
-						unsigned char *linkname);
+extern struct sysfs_link *sysfs_open_link(const char *lnpath);
+extern struct sysfs_link *sysfs_get_directory_link
+	(struct sysfs_directory *dir, char *linkname);
 extern struct sysfs_link *sysfs_get_subdirectory_link
-			(struct sysfs_directory *dir, unsigned char *linkname);
+	(struct sysfs_directory *dir, char *linkname);
 extern struct sysfs_attribute *sysfs_get_directory_attribute
-			(struct sysfs_directory *dir, unsigned char *attrname);
+	(struct sysfs_directory *dir, char *attrname);
+extern struct dlist *sysfs_get_dir_attributes(struct sysfs_directory *dir);
+extern struct dlist *sysfs_get_dir_links(struct sysfs_directory *dir);
+extern struct dlist *sysfs_get_dir_subdirs(struct sysfs_directory *dir);
 
 /* sysfs driver access */
 extern void sysfs_close_driver(struct sysfs_driver *driver);
-extern struct sysfs_driver *sysfs_open_driver(const unsigned char *path);
+extern struct sysfs_driver *sysfs_open_driver
+	(const char *bus_name, const char *drv_name);
+extern struct sysfs_driver *sysfs_open_driver_path(const char *path);
 extern struct sysfs_attribute *sysfs_get_driver_attr
-		(struct sysfs_driver *drv, const unsigned char *name);
+	(struct sysfs_driver *drv, const char *name);
 extern struct dlist *sysfs_get_driver_attributes(struct sysfs_driver *driver);
+extern struct dlist *sysfs_get_driver_devices(struct sysfs_driver *driver);
+extern struct dlist *sysfs_refresh_driver_devices(struct sysfs_driver *driver);
 extern struct dlist *sysfs_get_driver_links(struct sysfs_driver *driver);
-extern 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_attribute *sysfs_open_driver_attr(const unsigned char *bus, 
-		const unsigned char *drv, const unsigned char *attrib);
+extern struct sysfs_device *sysfs_get_driver_device
+	(struct sysfs_driver *driver, const char *name);
+extern struct dlist *sysfs_refresh_driver_attributes
+	(struct sysfs_driver *driver);
+extern struct sysfs_attribute *sysfs_open_driver_attr
+	(const char *bus, const char *drv, const char *attrib);
 
 /* generic sysfs device access */
 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 sysfs_root_device *sysfs_open_root_device(const char *name);
+extern struct dlist *sysfs_get_root_devices(struct sysfs_root_device *root);
+extern void sysfs_close_device_tree(struct sysfs_device *device);
+extern struct sysfs_device *sysfs_open_device_tree(const char *path);
 extern void sysfs_close_device(struct sysfs_device *dev);
-extern struct sysfs_device *sysfs_open_device(const unsigned char *path);
+extern struct sysfs_device *sysfs_open_device
+	(const char *bus, const char *bus_id);
+extern struct sysfs_device *sysfs_get_device_parent(struct sysfs_device *dev);
+extern struct sysfs_device *sysfs_open_device_path(const char *path);
+extern int sysfs_get_device_bus(struct sysfs_device *dev);
 extern struct sysfs_attribute *sysfs_get_device_attr
-			(struct sysfs_device *dev, const unsigned char *name);
+	(struct sysfs_device *dev, const 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);
-extern struct sysfs_attribute *sysfs_open_device_attr(const unsigned char *bus, 
-		const unsigned char *bus_id, const unsigned char *attrib);
+extern struct dlist *sysfs_refresh_device_attributes
+	(struct sysfs_device *device);
+extern struct sysfs_attribute *sysfs_open_device_attr(const char *bus, 
+		const char *bus_id, const char *attrib);
 
 /* generic sysfs bus access */
 extern void sysfs_close_bus(struct sysfs_bus *bus);
-extern struct sysfs_bus *sysfs_open_bus(const unsigned char *name);
-extern struct sysfs_device *sysfs_get_bus_device(struct sysfs_bus *bus,
-						unsigned char *id);
+extern struct sysfs_bus *sysfs_open_bus(const char *name);
+extern struct sysfs_device *sysfs_get_bus_device(struct sysfs_bus *bus, 
+		char *id);
 extern struct sysfs_driver *sysfs_get_bus_driver(struct sysfs_bus *bus,
-						unsigned char *drvname);
+		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);
-extern struct sysfs_device *sysfs_open_bus_device(unsigned char *busname, 
-							unsigned char *dev_id);
-extern int sysfs_find_driver_bus(const unsigned char *driver, 
-					unsigned char *busname,	size_t bsize);
+extern struct dlist *sysfs_refresh_bus_attributes(struct sysfs_bus *bus);
+extern struct sysfs_attribute *sysfs_get_bus_attribute
+	(struct sysfs_bus *bus,	char *attrname);
+extern int sysfs_find_driver_bus(const char *driver, char *busname, 
+		size_t bsize);
 
 /* generic sysfs class access */
 extern void sysfs_close_class_device(struct sysfs_class_device *dev);
+extern struct sysfs_class_device *sysfs_open_class_device_path
+	(const char *path);
 extern struct sysfs_class_device *sysfs_open_class_device
-					(const unsigned char *path);
+	(const char *classname, const char *name);
+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 sysfs_class *sysfs_open_class(const 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
-	(const unsigned char *class, const unsigned char *name);
+	(struct sysfs_class *cls, char *name);
 extern struct dlist *sysfs_get_classdev_attributes
 	(struct sysfs_class_device *cdev);
+extern struct dlist *sysfs_refresh_classdev_attributes
+	(struct sysfs_class_device *cdev);
 extern struct sysfs_attribute *sysfs_get_classdev_attr
-	(struct sysfs_class_device *clsdev, const unsigned char *name);
+	(struct sysfs_class_device *clsdev, const char *name);
 extern struct sysfs_attribute *sysfs_open_classdev_attr
-	(const unsigned char *classname, const unsigned char *dev, 
-	 					const unsigned char *attrib); 
+	(const char *classname, const char *dev, 
+	 					const char *attrib); 
+
+/**
+ * sort_list: sorter function to keep list elements sorted in alphabetical 
+ * 	order. Just does a strncmp as you can see :)
+ * 	
+ * Returns 1 if less than 0 otherwise
+ *
+ * NOTE: We take care to have a statically allocated "name" as the first 
+ * 	lement of all libsysfs structures. Hence, this function will work 
+ * 	AS IS for _ALL_ the lists that have to be sorted.
+ */
+static inline int sort_list(void *new_elem, void *old_elem)
+{
+        return ((strncmp(((struct sysfs_attribute *)new_elem)->name,
+		((struct sysfs_attribute *)old_elem)->name,
+		strlen(((struct sysfs_attribute *)new_elem)->name))) < 0 ? 1 : 0);
+}
+
 
 #ifdef __cplusplus
 }

Index: sysfs.h
===================================================================
RCS file: /cvs/hal/hal/hald/linux/libsysfs/sysfs.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- sysfs.h	14 Dec 2003 21:22:43 -0000	1.1
+++ sysfs.h	18 Jul 2004 15:21:23 -0000	1.2
@@ -34,9 +34,6 @@
 #include <errno.h>
 
 /* external library functions */
-extern int lstat(const char *file_name, struct stat *buf);
-extern int readlink(const char *path, char *buf, size_t bufsize);
-extern int getpagesize(void);
 extern int isascii(int c);
 
 /* Debugging */

Index: sysfs_bus.c
===================================================================
RCS file: /cvs/hal/hal/hald/linux/libsysfs/sysfs_bus.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- sysfs_bus.c	14 Dec 2003 21:22:43 -0000	1.1
+++ sysfs_bus.c	18 Jul 2004 15:21:23 -0000	1.2
@@ -44,7 +44,7 @@
 	if (a == NULL || b == NULL)
 		return 0;
 
-	if (strcmp(((unsigned char *)a), ((struct sysfs_device *)b)->bus_id) 
+	if (strcmp(((char *)a), ((struct sysfs_device *)b)->bus_id) 
 	    == 0)
 		return 1;
 	return 0;
@@ -61,7 +61,7 @@
 	if (a == NULL || b == NULL)
 		return 0;
 
-	if (strcmp(((unsigned char *)a), ((struct sysfs_driver *)b)->name) == 0)
+	if (strcmp(((char *)a), ((struct sysfs_driver *)b)->name) == 0)
 		return 1;
 	return 0;
 }
@@ -93,226 +93,142 @@
 }
 
 /**
- * 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;
+	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);
+	safestrcpy(path, bus->path);
+	safestrcat(path, "/");
+	safestrcat(path, SYSFS_DEVICES_NAME);
+	devdir = sysfs_open_directory(path);
+	if (devdir == NULL) 
 		return NULL;
-	}
 
-	strcat(buspath, SYSFS_BUS_DIR);
-	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);
-		return NULL;
-	}
-	if ((sysfs_read_directory(busdir)) != 0) {
-		dprintf("Error reading %s bus dir %s\n", name, 
-			buspath);
-		sysfs_close_directory(busdir);
+	if (sysfs_read_dir_links(devdir) != 0) {
+		sysfs_close_directory(devdir);
 		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)
-			continue;
-		if (cur->links == NULL)
-			continue;
-		dlist_for_each_data(cur->links, curl, struct sysfs_link) {
-			bdev = sysfs_open_device(curl->target);
+	if (devdir->links != NULL) {
+		dlist_for_each_data(devdir->links, curl, struct sysfs_link) {
+			bdev = sysfs_open_device_path(curl->target);
 			if (bdev == NULL) {
-				dprintf("Error opening device at %s\n",
-					curl->target);
+				dprintf("Error opening device at %s\n",	
+								curl->target);
 				continue;
 			}
-                        if (bus->devices == NULL)
+			if (bus->devices == NULL)
 				bus->devices = dlist_new_with_delete
-					(sizeof(struct sysfs_device),
-						 	sysfs_close_dev);
-			dlist_unshift(bus->devices, bdev);
+					(sizeof(struct sysfs_device), 
+					 		sysfs_close_dev);
+			dlist_unshift_sorted(bus->devices, bdev, sort_list);
 		}
 	}
-			
-	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;
+	char path[SYSFS_PATH_MAX];
 
-	if (bus == NULL || bus->directory == NULL) {
+	if (bus == NULL) {
 		errno = EINVAL;
-		return -1;
+		return NULL;
 	}
-	if (bus->directory->subdirs == NULL)
-		return 0;
+	memset(path, 0, SYSFS_PATH_MAX);
+	safestrcpy(path, bus->path);
+	safestrcat(path, "/");
+	safestrcat(path, SYSFS_DRIVERS_NAME);
+	drvdir = sysfs_open_directory(path);
+	if (drvdir == NULL) 
+		return NULL;
 
-	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 (sysfs_read_dir_subdirs(drvdir) != 0) {
+		sysfs_close_directory(drvdir);
+		return NULL;
+	}
+	if (drvdir->subdirs != NULL) {
+		dlist_for_each_data(drvdir->subdirs, cursub, 
+						struct sysfs_directory) {
+			driver = sysfs_open_driver_path(cursub->path);
 			if (driver == NULL) {
-				dprintf("Error opening driver at %s\n",
-					cursub->path);
+				dprintf("Error opening driver at %s\n",	
+								cursub->path);
 				continue;
 			}
-                        if (bus->drivers == NULL)
+			if (bus->drivers == NULL)
 				bus->drivers = dlist_new_with_delete
-					(sizeof(struct sysfs_driver),
+					(sizeof(struct sysfs_driver), 
 					 		sysfs_close_drv);
-			dlist_unshift(bus->drivers, driver);
-		}
-	}
-	
-	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;
-
-	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++;
-		}
-	}
-	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_unshift_sorted(bus->drivers, driver, sort_list);
 		}
 	}
+	sysfs_close_directory(drvdir);
+	return (bus->drivers);
 }
 
 /**
  * sysfs_open_bus: opens specific bus and all its devices on system
  * returns sysfs_bus structure with success or NULL with error.
  */
-struct sysfs_bus *sysfs_open_bus(const unsigned char *name)
+struct sysfs_bus *sysfs_open_bus(const char *name)
 {
 	struct sysfs_bus *bus = NULL;
-	struct sysfs_directory *busdir = NULL;
+	char buspath[SYSFS_PATH_MAX];
 
 	if (name == NULL) {
 		errno = EINVAL;
 		return NULL;
 	}
 
-	bus = alloc_bus();
-	if (bus == NULL) {
-		dprintf("calloc failed\n");
+	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->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);
+
+	safestrcat(buspath, "/");
+	safestrcat(buspath, SYSFS_BUS_NAME);
+	safestrcat(buspath, "/");
+	safestrcat(buspath, name);
+	if ((sysfs_path_is_dir(buspath)) != 0) {
+		dprintf("Invalid path to bus: %s\n", buspath);
 		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);
+	bus = alloc_bus();
+	if (bus == NULL) {
+		dprintf("calloc failed\n");
 		return NULL;
 	}
-	if ((get_all_bus_drivers(bus)) != 0) {
-		dprintf("Error reading %s bus drivers\n", name);
+	safestrcpy(bus->name, name);	
+	safestrcpy(bus->path, buspath);
+	if ((sysfs_remove_trailing_slash(bus->path)) != 0) {
+		dprintf("Incorrect path to bus %s\n", bus->path);
 		sysfs_close_bus(bus);
 		return NULL;
 	}
-	link_bus_devices_to_drivers(bus);
 
 	return bus;
 }
@@ -323,14 +239,19 @@
  * @id: bus_id for device
  * returns struct sysfs_device reference or NULL if not found.
  */
-struct sysfs_device *sysfs_get_bus_device(struct sysfs_bus *bus, 
-							unsigned char *id)
+struct sysfs_device *sysfs_get_bus_device(struct sysfs_bus *bus, char *id)
 {
 	if (bus == NULL || id == NULL) {
 		errno = EINVAL;
 		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);
 }
@@ -342,13 +263,19 @@
  * returns struct sysfs_driver reference or NULL if not found.
  */
 struct sysfs_driver *sysfs_get_bus_driver(struct sysfs_bus *bus, 
-							unsigned char *drvname)
+							char *drvname)
 {
 	if (bus == NULL || drvname == NULL) {
 		errno = EINVAL;
 		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);
 }
@@ -360,67 +287,69 @@
  */
 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;
+	}
 	return bus->directory->attributes;
 }
 
 /**
- * sysfs_get_bus_attribute: gets a specific bus attribute, if buses had
- * 	attributes.
- * @bus: bus to retrieve attribute from
- * @attrname: attribute name to retrieve
- * returns reference to sysfs_attribute if found or NULL if not found
+ * sysfs_refresh_bus_attributes: refreshes the bus's list of attributes
+ * @bus: sysfs_bus whose attributes to refresh
+ * 
+ * NOTE: Upon return, prior references to sysfs_attributes for this bus
+ * 		_may_ not be valid
+ * 
+ * Returns list of attributes on success and NULL on failure
  */
-struct sysfs_attribute *sysfs_get_bus_attribute(struct sysfs_bus *bus,
-						unsigned char *attrname)
+struct dlist *sysfs_refresh_bus_attributes(struct sysfs_bus *bus)
 {
-	if (bus == NULL || bus->directory == NULL || attrname == NULL) {
+	if (bus == NULL) {
 		errno = EINVAL;
 		return NULL;
 	}
-	return sysfs_get_directory_attribute(bus->directory, attrname);
+
+	if (bus->directory == NULL)
+		return (sysfs_get_bus_attributes(bus));
+	
+	if ((sysfs_refresh_dir_attributes(bus->directory)) != 0) {
+		dprintf("Error refreshing bus attributes\n");
+		return NULL;
+	}
+
+	return (bus->directory->attributes);
 }
 
 /**
- * sysfs_open_bus_device: locates a device on a bus and returns it. Device
- * 	must be closed using sysfs_close_device.
- * @busname: Name of bus to search
- * @dev_id: Id of device on bus.
- * returns sysfs_device if found or NULL if not.
+ * sysfs_get_bus_attribute: gets a specific bus attribute, if buses had
+ * 	attributes.
+ * @bus: bus to retrieve attribute from
+ * @attrname: attribute name to retrieve
+ * returns reference to sysfs_attribute if found or NULL if not found
  */
-struct sysfs_device *sysfs_open_bus_device(unsigned char *busname, 
-							unsigned char *dev_id)
+struct sysfs_attribute *sysfs_get_bus_attribute(struct sysfs_bus *bus,
+						char *attrname)
 {
-	struct sysfs_device *rdev = NULL;
-	char path[SYSFS_PATH_MAX];
-
-	if (busname == NULL || dev_id == NULL) {
+	struct dlist *attrlist = NULL;
+	
+	if (bus == NULL) {
 		errno = EINVAL;
 		return NULL;
 	}
-
-	memset(path, 0, SYSFS_PATH_MAX);
-	if (sysfs_get_mnt_path(path, SYSFS_PATH_MAX) != 0) {
-		dprintf("Error getting sysfs mount point\n");
-		return NULL;
-	}
-
-	strcat(path, SYSFS_BUS_DIR);
-	strcat(path, "/");
-	strcat(path, busname);
-	strcat(path, SYSFS_DEVICES_DIR);
-	strcat(path, "/");
-	strcat(path, dev_id);
-
-	rdev = sysfs_open_device(path);
-	if (rdev == NULL) {
-		dprintf("Error getting device %s on bus %s\n",
-				dev_id, busname);
+	attrlist = sysfs_get_bus_attributes(bus);
+	if (attrlist == NULL)
 		return NULL;
-	}
 	
-	return rdev;
+	return sysfs_get_directory_attribute(bus->directory, attrname);
 }
 
 /**
@@ -430,10 +359,9 @@
  * @bsize: buffer size
  * returns 0 with success, -1 with error
  */
-int sysfs_find_driver_bus(const unsigned char *driver, unsigned char *busname,
-							size_t bsize)
+int sysfs_find_driver_bus(const char *driver, char *busname, size_t bsize)
 {
-	unsigned char subsys[SYSFS_PATH_MAX], *bus = NULL, *curdrv = NULL;
+	char subsys[SYSFS_PATH_MAX], *bus = NULL, *curdrv = NULL;
 	struct dlist *buslist = NULL, *drivers = NULL;
 
 	if (driver == NULL || busname == NULL) {
@@ -442,20 +370,22 @@
 	}
 
 	memset(subsys, 0, SYSFS_PATH_MAX);
-	strcpy(subsys, SYSFS_BUS_DIR);
+	safestrcpy(subsys, SYSFS_BUS_NAME);
 	buslist = sysfs_open_subsystem_list(subsys);
 	if (buslist != NULL) {
 		dlist_for_each_data(buslist, bus, char) {
 			memset(subsys, 0, SYSFS_PATH_MAX);
-			strcpy(subsys, SYSFS_BUS_DIR);
-			strcat(subsys, "/");
-			strcat(subsys, bus);
-			strcat(subsys, SYSFS_DRIVERS_DIR);
+			safestrcpy(subsys, SYSFS_BUS_NAME);
+			safestrcat(subsys, "/");
+			safestrcat(subsys, bus);
+			safestrcat(subsys, "/");
+			safestrcat(subsys, SYSFS_DRIVERS_NAME);
 			drivers = sysfs_open_subsystem_list(subsys);
 			if (drivers != NULL) {
 				dlist_for_each_data(drivers, curdrv, char) {
 					if (strcmp(driver, curdrv) == 0) {
-						strncpy(busname, bus, bsize);
+						safestrcpymax(busname, 
+								bus, bsize);
 						sysfs_close_list(drivers);
 						sysfs_close_list(buslist);
 						return 0;
@@ -468,4 +398,3 @@
 	}
 	return -1;
 }
-					

Index: sysfs_class.c
===================================================================
RCS file: /cvs/hal/hal/hald/linux/libsysfs/sysfs_class.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- sysfs_class.c	14 Dec 2003 21:22:43 -0000	1.1
+++ sysfs_class.c	18 Jul 2004 15:21:23 -0000	1.2
@@ -23,7 +23,7 @@
 #include "libsysfs.h"
 #include "sysfs.h"
 
-void sysfs_close_cls_dev(void *dev)
+static void sysfs_close_cls_dev(void *dev)
 {
 	sysfs_close_class_device((struct sysfs_class_device *)dev);
 }
@@ -38,8 +38,7 @@
 	if (a == NULL || b == NULL)
 		return 0;
 
-	if (strcmp(((unsigned char *)a), ((struct sysfs_class_device *)b)->name)
-		== 0)
+	if (strcmp(((char *)a), ((struct sysfs_class_device *)b)->name) == 0)
 		return 1;
 
 	return 0;
@@ -58,13 +57,15 @@
 			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);
 	}
 }
 
 /**
  * sysfs_close_class: close single class
- * @class: class structure
+ * @cls: class structure
  */
 void sysfs_close_class(struct sysfs_class *cls)
 {
@@ -96,52 +97,6 @@
 	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;
-	}
-
-	/* 
-	 * 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_DIR);
-	} else {
-		strcat(classpath, SYSFS_CLASS_DIR);
-		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
@@ -149,25 +104,23 @@
  */
 static void set_classdev_classname(struct sysfs_class_device *cdev)
 {
-	unsigned char *c = NULL, *e = NULL;
+	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)
-		strcpy(cdev->classname, SYSFS_UNKNOWN);
-
+		safestrcpy(cdev->classname, SYSFS_UNKNOWN);
 	else {
-		c++;
+		if (*c == '/')
+			c++;
 		e = c;
-		while (e != NULL && *e != '/') {
+		while (e != NULL && *e != '/' && *e != '\0') {
 			e++;
 			count++;
 		}
@@ -176,22 +129,22 @@
 }
 
 /**
- * sysfs_open_class_device: Opens and populates class device
+ * sysfs_open_class_device_path: Opens and populates class device
  * @path: path to class device.
  * returns struct sysfs_class_device with success and NULL with error.
  */
-struct sysfs_class_device *sysfs_open_class_device(const unsigned char *path)
+struct sysfs_class_device *sysfs_open_class_device_path(const 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");
@@ -199,132 +152,119 @@
 	}
 	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);
+	safestrcpy(cdev->path, path);
+	if ((sysfs_remove_trailing_slash(cdev->path)) != 0) {
+		dprintf("Invalid path to class device %s\n", cdev->path);
 		sysfs_close_class_device(cdev);
 		return NULL;
 	}
-	sysfs_read_all_subdirs(dir);
-	cdev->directory = dir;
-	strcpy(cdev->path, dir->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
- * @class: class to get devices for
- * returns 0 with success and -1 with failure
+ * sysfs_get_class_devices: gets all devices for class
+ * @cls: class to get devices for
+ * 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;
-	dlist_for_each_data(cls->directory->subdirs, cur, 
-			struct sysfs_directory) {
-		dev = sysfs_open_class_device(cur->path);
-		if (dev == NULL) {
-			dprintf("Error opening device at %s\n",	cur->path);
-			continue;
-		}
-		if (cls->devices == NULL)
-			cls->devices = dlist_new_with_delete
+
+	if (cls->devices != NULL) 
+		return cls->devices;
+
+	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) 
+		return NULL;
+
+	if (cls->directory->subdirs != NULL) {
+		dlist_for_each_data(cls->directory->subdirs, cur, 
+						struct sysfs_directory) {
+			dev = sysfs_open_class_device_path(cur->path);
+			if (dev == NULL) {
+				dprintf("Error opening device at %s\n",	
+								cur->path);
+				continue;
+			}
+			if (cls->devices == NULL)
+				cls->devices = dlist_new_with_delete
 					(sizeof(struct sysfs_class_device),
 					 		sysfs_close_cls_dev);
-		dlist_unshift(cls->devices, dev);
+			dlist_unshift_sorted(cls->devices, dev, sort_list);
+		}
 	}
-	return 0;
+	return cls->devices;
 }
 
 /**
  * sysfs_open_class: opens specific class and all its devices on system
  * returns sysfs_class structure with success or NULL with error.
  */
-struct sysfs_class *sysfs_open_class(const unsigned char *name)
+struct sysfs_class *sysfs_open_class(const char *name)
 {
 	struct sysfs_class *cls = NULL;
-	struct sysfs_directory *classdir = NULL;
+	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;
+        }
+
+	/* 
+	 * 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) {
+		safestrcat(classpath, "/");
+		safestrcat(classpath, SYSFS_BLOCK_NAME);
+	} else {
+		safestrcat(classpath, "/");
+		safestrcat(classpath, SYSFS_CLASS_NAME);
+		safestrcat(classpath, "/");
+		safestrcat(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);
+	safestrcpy(cls->name, name);	
+	safestrcpy(cls->path, classpath);
+	if ((sysfs_remove_trailing_slash(cls->path)) != 0) {
+		dprintf("Invalid path to class device %s\n", cls->path);
 		sysfs_close_class(cls);
 		return NULL;
 	}
-
+	
 	return cls;
 }
 
@@ -333,19 +273,221 @@
  * @class: class to find device on
  * @name: class name of the device
  */ 
-struct sysfs_class_device *sysfs_get_class_device(struct sysfs_class *class,
-					unsigned char *name)
+struct sysfs_class_device *sysfs_get_class_device(struct sysfs_class *cls,
+					char *name)
 {
-	if (class == NULL || name == NULL) {
+	if (cls == NULL || name == NULL) {
 		errno = EINVAL;
 		return NULL;
 	}
 
-	return (struct sysfs_class_device *)dlist_find_custom(class->devices,
+	if (cls->devices == NULL) {
+		cls->devices = sysfs_get_class_devices(cls);
+		if (cls->devices == NULL) 
+			return NULL;
+	}
+	return (struct sysfs_class_device *)dlist_find_custom(cls->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;
+	char devpath[SYSFS_PATH_MAX];
+	
+	if (clsdev == NULL) {
+		errno = EINVAL;
+		return NULL;
+	}
+	safestrcpy(devpath, clsdev->path);
+	safestrcat(devpath, "/device");
+	if ((sysfs_path_is_link(devpath)) != 0) {
+		if (clsdev->sysdevice != NULL) {
+			sysfs_close_device(clsdev->sysdevice);
+			clsdev->sysdevice = NULL;
+		}
+		return NULL;
+	}
+	
+	if (clsdev->directory == NULL) {
+		clsdev->directory = sysfs_open_directory(clsdev->path);
+		if (clsdev->directory == NULL)
+			return NULL;
+	}
+	devlink = sysfs_get_directory_link(clsdev->directory, "device");
+	if (devlink == NULL) {
+		if (clsdev->sysdevice != NULL) {
+			dprintf("Device link no longer exists\n");
+			sysfs_close_device(clsdev->sysdevice);
+			clsdev->sysdevice = NULL;
+		}
+		return NULL;
+	}
+
+	if (clsdev->sysdevice != NULL) {
+		if (!strncmp(devlink->target, clsdev->sysdevice->path,
+						SYSFS_PATH_MAX)) 
+			/* sysdevice hasn't changed */
+			return (clsdev->sysdevice);
+		else 
+			/* come here only if the device link for has changed */
+			sysfs_close_device(clsdev->sysdevice);
+	}
+
+	clsdev->sysdevice = sysfs_open_device_path(devlink->target);
+	if (clsdev->sysdevice == NULL)
+		return NULL;
+
+	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;
+	char drvpath[SYSFS_PATH_MAX];
+	
+	if (clsdev == NULL) {
+		errno = EINVAL;
+		return NULL;
+	}
+ 	safestrcpy(drvpath, clsdev->path);
+	safestrcat(drvpath, "/driver");
+	if ((sysfs_path_is_link(drvpath)) != 0) {
+		if (clsdev->driver != NULL) {
+			sysfs_close_driver(clsdev->driver);
+			clsdev->driver = NULL;
+		}
+		return NULL;
+	}
+	 
+	if (clsdev->directory == NULL) {
+		clsdev->directory = sysfs_open_directory(clsdev->path);
+		if (clsdev->directory == NULL)
+			return NULL;
+	}
+	drvlink = sysfs_get_directory_link(clsdev->directory, "driver");
+	if (drvlink == NULL) {
+		if (clsdev->driver != NULL) {
+			dprintf("Driver link no longer exists\n");
+			sysfs_close_driver(clsdev->driver);
+			clsdev->driver = NULL;
+		}
+		return NULL;
+	}
+	if (clsdev->driver != NULL) {
+		if (!strncmp(drvlink->target, clsdev->driver->path,
+	      						SYSFS_PATH_MAX))
+			/* driver hasn't changed */
+	 		return (clsdev->driver);
+ 		else
+			/* come here only if the device link for has changed */
+			sysfs_close_driver(clsdev->driver);
+	}
+		
+	clsdev->driver = sysfs_open_driver_path(drvlink->target);
+	if (clsdev->driver == NULL)
+		return NULL;
+
+	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)
+{
+	char parent_path[SYSFS_PATH_MAX], *c = NULL;
+
+	safestrcpy(parent_path, clsdev->path);
+	c = strstr(parent_path, SYSFS_BLOCK_NAME);
+	if (c == NULL) {
+		dprintf("Class device %s does not belong to BLOCK subsystem\n",
+				clsdev->name);
+		return 1;
+	}
+	c += strlen(SYSFS_BLOCK_NAME);
+	if (*c == '/')
+		c++;
+	else
+		goto errout;
+
+       /* validate whether the given class device is a partition or not */
+        if ((strncmp(c, clsdev->name, strlen(clsdev->name))) == 0) {
+                dprintf("%s not a partition\n", clsdev->name);
+                return 1;
+        }
+		      
+      	c = strchr(c, '/');
+	if (c == NULL)
+		goto errout;
+
+	*c = '\0';
+					
+	clsdev->parent = sysfs_open_class_device_path(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 (!(strncmp(clsdev->classname, SYSFS_BLOCK_NAME, 
+					sizeof(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
@@ -354,8 +496,8 @@
  * @psize: size of "path"
  * Returns 0 on SUCCESS or -1 on error
  */
-static int get_classdev_path(const unsigned char *classname, 
-		const unsigned char *clsdev, unsigned char *path, size_t len)
+static int get_classdev_path(const char *classname, const char *clsdev, 
+		char *path, size_t len)
 {
 	if (classname == NULL || clsdev == NULL || path == NULL) {
 		errno = EINVAL;
@@ -365,20 +507,23 @@
                 dprintf("Error getting sysfs mount path\n");
                 return -1;
 	}
-	if (strcmp(classname, SYSFS_BLOCK_NAME) == 0) {
-		strcat(path, SYSFS_BLOCK_DIR);
+	if (strncmp(classname, SYSFS_BLOCK_NAME,
+				sizeof(SYSFS_BLOCK_NAME)) == 0) {
+		safestrcatmax(path, "/", len);
+		safestrcatmax(path, SYSFS_BLOCK_NAME, len);
 	} else {
-		strcat(path, SYSFS_CLASS_DIR);
-		strcat(path, "/");
-		strcat(path, classname);
+		safestrcatmax(path, "/", len);
+		safestrcatmax(path, SYSFS_CLASS_NAME, len);
+		safestrcatmax(path, "/", len);
+		safestrcatmax(path, classname, len);
 	}
-	strcat(path, "/");
-	strcat(path, clsdev);
+	safestrcatmax(path, "/", len);
+	safestrcatmax(path, clsdev, len);
 	return 0;
 }
 
 /**
- * sysfs_open_class_device_by_name: Locates a specific class_device and returns it.
+ * sysfs_open_class_device: Locates a specific class_device and returns it.
  * Class_device must be closed using sysfs_close_class_device
  * @classname: Class to search
  * @name: name of the class_device
@@ -386,10 +531,10 @@
  * NOTE:
  * 	Call sysfs_close_class_device() to close the class device
  */
-struct sysfs_class_device *sysfs_open_class_device_by_name
-		(const unsigned char *classname, const unsigned char *name)
+struct sysfs_class_device *sysfs_open_class_device
+		(const char *classname, const char *name)
 {
-	unsigned char devpath[SYSFS_PATH_MAX];
+	char devpath[SYSFS_PATH_MAX];
 	struct sysfs_class_device *cdev = NULL;
 
 	if (classname == NULL || name == NULL) {
@@ -405,7 +550,7 @@
 		return NULL;
 	}
 	
-	cdev = sysfs_open_class_device(devpath);
+	cdev = sysfs_open_class_device_path(devpath);
 	if (cdev == NULL) {
 		dprintf("Error getting class device %s from class %s\n",
 				name, classname);
@@ -422,35 +567,96 @@
  */
 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) 
+			return NULL;
+	}
 	return (cdev->directory->attributes);
 }
 
 /**
+ * sysfs_refresh_clsassdev_attributes: refreshes the driver's list of attributes
+ * @clsdev: sysfs_class_device whose attributes to refresh
+ *
+ * NOTE: Upon return, prior references to sysfs_attributes for this classdev
+ *              _may_ not be valid
+ *
+ * Returns list of attributes on success and NULL on failure
+ */
+struct dlist *sysfs_refresh_classdev_attributes
+			(struct sysfs_class_device *clsdev)
+{
+	if (clsdev == NULL) {
+		errno = EINVAL;
+		return NULL;
+	}
+
+	if (clsdev->directory == NULL)
+		return (sysfs_get_classdev_attributes(clsdev));
+
+	if ((sysfs_refresh_dir_attributes(clsdev->directory)) != 0) {
+		dprintf("Error refreshing class_device attributes\n");
+		return NULL;
+	}
+
+	return (clsdev->directory->attributes);
+}
+
+/**
  * sysfs_get_classdev_attr: searches class device's attributes by name
  * @clsdev: class device to look through
  * @name: attribute name to get
  * returns sysfs_attribute reference with success or NULL with error
  */
 struct sysfs_attribute *sysfs_get_classdev_attr
-		(struct sysfs_class_device *clsdev, const unsigned char *name)
+		(struct sysfs_class_device *clsdev, const 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) {
+		cur = sysfs_get_directory_attribute(clsdev->directory,
+						(char *)name);
+		if (cur != NULL)
+			return cur;
+	}
 
-	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;
 
-	return NULL;
+	if (clsdev->directory->subdirs != NULL) {
+		dlist_for_each_data(clsdev->directory->subdirs, sdir,
+						struct sysfs_directory) {
+			if ((sysfs_path_is_dir(sdir->path)) != 0) 
+				continue;
+			cur = sysfs_get_directory_attribute(sdir,
+							(char *)name);
+			if (cur == NULL)
+				continue;
+		}
+	}
+	return cur;
 }
 
 /**
@@ -464,11 +670,11 @@
  * 	A call to sysfs_close_attribute() is required to close the
  * 	attribute returned and to free memory
  */
-struct sysfs_attribute *sysfs_open_classdev_attr(const unsigned char *classname,
-		const unsigned char *dev, const unsigned char *attrib)
+struct sysfs_attribute *sysfs_open_classdev_attr(const char *classname,
+		const char *dev, const char *attrib)
 {
 	struct sysfs_attribute *attribute = NULL;
-	unsigned char path[SYSFS_PATH_MAX];
+	char path[SYSFS_PATH_MAX];
 
 	if (classname == NULL || dev == NULL || attrib == NULL) {
 		errno = EINVAL;
@@ -480,8 +686,8 @@
 						dev, classname);
 		return NULL;
 	}
-	strcat(path, "/");
-	strcat(path, attrib);
+	safestrcat(path, "/");
+	safestrcat(path, attrib);
 	attribute = sysfs_open_attribute(path);
 	if (attribute == NULL) {
 		dprintf("Error opening attribute %s on class device %s\n",
@@ -496,3 +702,4 @@
 	}
 	return attribute;
 }
+

Index: sysfs_device.c
===================================================================
RCS file: /cvs/hal/hal/hald/linux/libsysfs/sysfs_device.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- sysfs_device.c	14 Dec 2003 21:22:43 -0000	1.1
+++ sysfs_device.c	18 Jul 2004 15:21:23 -0000	1.2
@@ -23,71 +23,111 @@
 #include "libsysfs.h"
 #include "sysfs.h"
 
-static int confirm_device_bus(struct sysfs_device *dev, 
-				unsigned char *busname, unsigned char *bus_id)
+/**
+ * get_dev_driver: fills in the dev->driver_name field 
+ *
+ * Returns 0 on SUCCESS and 1 on error
+ */
+static int get_dev_driver(struct sysfs_device *dev)
 {
-        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;
-
-        strcat(devpath, SYSFS_BUS_DIR);
-        strcat(devpath, "/");
-        strcat(devpath, busname);
-        strcat(devpath, SYSFS_DEVICES_DIR);
-        strcat(devpath, "/");
-        strcat(devpath, bus_id);
+	struct dlist *drvlist = NULL;
+	char path[SYSFS_PATH_MAX], devpath[SYSFS_PATH_MAX];
+	char *drv = NULL, *c = NULL;
+	
+	if (dev == NULL) {
+		errno = EINVAL;
+		return 1;
+	}
+	if (dev->bus[0] == '\0')
+		return 1;
+	memset(path, 0, SYSFS_PATH_MAX);
+	memset(devpath, 0, SYSFS_PATH_MAX);
+	safestrcpy(path, SYSFS_BUS_NAME);
+	safestrcat(path, "/");
+	safestrcat(path, dev->bus);
+	safestrcat(path, "/");
+	safestrcat(path, SYSFS_DRIVERS_NAME);
 
-	devlink = sysfs_open_link(devpath);
-	if (devlink == NULL)
-		return -1;
+	safestrcpy(devpath, dev->path);
+	c = strstr(devpath, SYSFS_DEVICES_NAME);
+	if (c == NULL)
+		return 1;
+	*c = '\0';
+	safestrcatmax(c, path, (sizeof(devpath) - strlen(devpath)));
 
-	if (strcmp(devlink->target, dev->path) == 0)
-		result++;
-	sysfs_close_link(devlink);
-	return result;
+	drvlist = sysfs_open_subsystem_list(path);
+	if (drvlist != NULL) {
+		dlist_for_each_data(drvlist, drv, char) {
+			safestrcpy(path, devpath);
+			safestrcat(path, "/");
+			safestrcat(path, drv);
+			safestrcat(path, "/");
+			safestrcat(path, dev->bus_id);
+			if (sysfs_path_is_link(path) == 0) {
+				safestrcpy(dev->driver_name, drv);
+				sysfs_close_list(drvlist);
+				return 0;
+			}
+		}
+		sysfs_close_list(drvlist);
+	}
+	return 1;
 }
-
+	
 /**
- * get_device_bus: retrieves the bus name the device is on, checks path to
- *	bus' link to make sure it has correct device.
+ * sysfs_get_device_bus: retrieves the bus name the device is on, checks path 
+ * 	to bus' link to make sure it has correct device.
  * @dev: device to get busname.
  * returns 0 with success and -1 with error.
  */
-static int get_device_bus(struct sysfs_device *dev)
+int sysfs_get_device_bus(struct sysfs_device *dev)
 {
-	unsigned char subsys[SYSFS_NAME_LEN], *bus = NULL, *curdev = NULL;
-	struct dlist *buslist = NULL, *device_list = NULL;
+	char subsys[SYSFS_NAME_LEN], path[SYSFS_PATH_MAX];
+	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);
+	safestrcpy(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);
+			safestrcpy(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';
+			safestrcat(path, "/");
+			safestrcat(path, SYSFS_BUS_NAME);
+			safestrcat(path, "/");
+			safestrcat(path, bus);
+			safestrcat(path, "/");
+			safestrcat(path, SYSFS_DEVICES_NAME);
+			safestrcat(path, "/");
+			safestrcat(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))) {
+					safestrcpy(dev->bus, bus);
+					sysfs_close_list(buslist);
+					return 0;
+				}
+			}
                 }
                 sysfs_close_list(buslist);
         }
@@ -99,7 +139,7 @@
  * 	closing children only.
  * @devroot: device root of tree.
  */
-static void sysfs_close_device_tree(struct sysfs_device *devroot)
+void sysfs_close_device_tree(struct sysfs_device *devroot)
 {
 	if (devroot != NULL) {
 		if (devroot->children != NULL) {
@@ -115,14 +155,6 @@
 }
 
 /**
- * sysfs_del_device: routine for dlist integration
- */
-static void sysfs_del_device(void *dev)
-{
-	sysfs_close_device((struct sysfs_device *)dev);
-}
-
-/**
  * sysfs_close_dev_tree: routine for dlist integration
  */
 static void sysfs_close_dev_tree(void *dev)
@@ -137,6 +169,8 @@
 void sysfs_close_device(struct sysfs_device *dev)
 {
 	if (dev != NULL) {
+		if (dev->parent != NULL)
+			sysfs_close_device(dev->parent);
 		if (dev->directory != NULL)
 			sysfs_close_directory(dev->directory);
 		if (dev->children != NULL && dev->children->count == 0)
@@ -155,75 +189,83 @@
 }
 
 /**
- * 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 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_dir_subdirs(rdir)) != 0) {
+		dprintf ("Error reading device at dir %s\n", path);
+		sysfs_close_directory(rdir);
+		return NULL;
+	}
+	
+	return rdir;
 }
 
 /**
- * sysfs_open_device: opens and populates device structure
+ * sysfs_open_device_path: opens and populates device structure
  * @path: path to device, this is the /sys/devices/ path
  * returns sysfs_device structure with success or NULL with error
  */
-struct sysfs_device *sysfs_open_device(const unsigned char *path)
+struct sysfs_device *sysfs_open_device_path(const 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);
+	safestrcpy(dev->path, path);
+	if ((sysfs_remove_trailing_slash(dev->path)) != 0) {
+		dprintf("Invalid path to device %s\n", dev->path);
 		sysfs_close_device(dev);
 		return NULL;
 	}
-	dev->directory = sdir;
-	strcpy(dev->bus_id, sdir->name);
-	strcpy(dev->path, sdir->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);
+	safestrcpy(dev->name, dev->bus_id);
 	
-	if (get_device_bus(dev) != 0)
-		strcpy(dev->bus, SYSFS_UNKNOWN);
+	if (sysfs_get_device_bus(dev) != 0)
+		dprintf("Could not get device bus\n");
+	
+	if (get_dev_driver(dev) != 0) {
+		dprintf("Could not get device %s's driver\n", dev->bus_id);
+		safestrcpy(dev->driver_name, SYSFS_UNKNOWN);
+	}
 
 	return dev;
 }
@@ -235,7 +277,7 @@
  * returns struct sysfs_device and its children with success or NULL with
  *	error.
  */
-static struct sysfs_device *sysfs_open_device_tree(const unsigned char *path)
+struct sysfs_device *sysfs_open_device_tree(const char *path)
 {
 	struct sysfs_device *rootdev = NULL, *new = NULL;
 	struct sysfs_directory *cur = NULL;
@@ -244,11 +286,16 @@
 		errno = EINVAL;
 		return NULL;
 	}
-	rootdev = sysfs_open_device(path);
+	rootdev = sysfs_open_device_path(path);
 	if (rootdev == NULL) {
 		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) {
@@ -262,8 +309,9 @@
 			if (rootdev->children == NULL)
 				rootdev->children = dlist_new_with_delete
 					(sizeof(struct sysfs_device),
-					sysfs_del_device);
-			dlist_unshift(rootdev->children, new);
+					sysfs_close_dev_tree);
+			dlist_unshift_sorted(rootdev->children, 
+							new, sort_list);
 		}
 	}
 
@@ -286,60 +334,25 @@
 }
 
 /**
- * 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;
-	}
-
-	strcat(rootpath, SYSFS_DEVICES_DIR);
-	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;
 
@@ -354,10 +367,10 @@
 			root->devices = dlist_new_with_delete
 				(sizeof(struct sysfs_device), 
 				sysfs_close_dev_tree);
-		dlist_unshift(root->devices, dev);
+		dlist_unshift_sorted(root->devices, dev, sort_list);
 	}
 
-	return 0;
+	return root->devices;
 }
 
 /**
@@ -366,36 +379,44 @@
  * @name: name of /sys/devices/root to open
  * returns struct sysfs_root_device if success and NULL with error
  */
-struct sysfs_root_device *sysfs_open_root_device(const unsigned char *name)
+struct sysfs_root_device *sysfs_open_root_device(const char *name)
 {
 	struct sysfs_root_device *root = NULL;
-	struct sysfs_directory *rootdir = NULL;
+	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;
+	}
+
+	safestrcat(rootpath, "/");
+	safestrcat(rootpath, SYSFS_DEVICES_NAME);
+	safestrcat(rootpath, "/");
+	safestrcat(rootpath, name);
+	if ((sysfs_path_is_dir(rootpath)) != 0) {
+		errno = EINVAL;
+		dprintf("Invalid root device: %s\n", name);
+		return NULL;
+	}
 	root = (struct sysfs_root_device *)calloc
 					(1, sizeof(struct sysfs_root_device));
 	if (root == NULL) {
 		dprintf("calloc failure\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);
-		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);
+	safestrcpy(root->name, name);
+	safestrcpy(root->path, rootpath);
+	if ((sysfs_remove_trailing_slash(root->path)) != 0) {
+		dprintf("Invalid path to root device %s\n", root->path);
 		sysfs_close_root_device(root);
 		return NULL;
 	}
-
 	return root;
 }
 
@@ -406,13 +427,74 @@
  */
 struct dlist *sysfs_get_device_attributes(struct sysfs_device *device)
 {
-	if (device == NULL || device->directory == NULL) 
+	if (device == NULL) {
+		errno = EINVAL;
 		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;
+	}
+	return (device->directory->attributes);
+}
+
+/**
+ * sysfs_refresh_device_attributes: refreshes the device's list of attributes
+ * @device: sysfs_device whose attributes to refresh
+ *  
+ * NOTE: Upon return, prior references to sysfs_attributes for this device
+ * 		_may_ not be valid
+ *
+ * Returns list of attributes on success and NULL on failure
+ */
+struct dlist *sysfs_refresh_device_attributes(struct sysfs_device *device)
+{
+	if (device == NULL) {
+		errno = EINVAL;
+		return NULL;
+	}
+
+	if (device->directory == NULL)
+		return (sysfs_get_device_attributes(device));
+
+	if ((sysfs_refresh_dir_attributes(device->directory)) != 0) {
+		dprintf("Error refreshing device attributes\n");
+		return NULL;
+	}
 
 	return (device->directory->attributes);
 }
 
 /**
+ * sysfs_get_device_attr: searches dev's attributes by name
+ * @dev: device to look through
+ * @name: attribute name to get
+ * returns sysfs_attribute reference with success or NULL with error.
+ */
+struct sysfs_attribute *sysfs_get_device_attr(struct sysfs_device *dev,
+						const char *name)
+{
+	struct dlist *attrlist = NULL;
+
+	if (dev == NULL || name == NULL) {
+		errno = EINVAL;
+		return NULL;
+	}
+	
+	attrlist = sysfs_get_device_attributes(dev);
+	if (attrlist == NULL)
+		return NULL;
+
+	return sysfs_get_directory_attribute(dev->directory, (char *)name);
+}
+
+/**
  * 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
@@ -420,32 +502,34 @@
  * @psize: size of "path"
  * Returns 0 on success -1 on failure
  */
-static int get_device_absolute_path(const unsigned char *device,
-		const unsigned char *bus, unsigned char *path, size_t psize)
+static int get_device_absolute_path(const char *device,	const char *bus, 
+				char *path, size_t psize)
 {
-	unsigned char bus_path[SYSFS_NAME_LEN];
+	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;
 	}
-	strcat(bus_path, SYSFS_BUS_DIR);
-	strcat(bus_path, "/");
-	strcat(bus_path, bus);
-	strcat(bus_path, SYSFS_DEVICES_DIR);
-	strcat(bus_path, "/");
-	strcat(bus_path, device);
+	safestrcat(bus_path, "/");
+	safestrcat(bus_path, SYSFS_BUS_NAME);
+	safestrcat(bus_path, "/");
+	safestrcat(bus_path, bus);
+	safestrcat(bus_path, "/");
+	safestrcat(bus_path, SYSFS_DEVICES_NAME);
+	safestrcat(bus_path, "/");
+	safestrcat(bus_path, device);
 	/*
 	 * We now are at /sys/bus/"bus_name"/devices/"device" which is a link.
 	 * Now read this link to reach to the device.
 	 */ 
-	if ((sysfs_get_link(bus_path, path, SYSFS_PATH_MAX)) != 0) {
+	if ((sysfs_get_link(bus_path, path, psize)) != 0) {
 		dprintf("Error getting to device %s\n", device);
 		return -1;
 	}
@@ -453,19 +537,17 @@
 }
 
 /**
- * sysfs_open_device_by_id: open a device by id (use the "bus" subsystem)
+ * sysfs_open_device: open a device by id (use the "bus" subsystem)
+ * @bus: bus the device belongs to
  * @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
  * 2. Bus the device is on must be supplied
  * 	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)
+struct sysfs_device *sysfs_open_device(const char *bus,	const char *bus_id)
 {
 	char sysfs_path[SYSFS_PATH_MAX];
 	struct sysfs_device *device = NULL;
@@ -481,7 +563,7 @@
 		return NULL;
 	}
 	
-	device = sysfs_open_device(sysfs_path);
+	device = sysfs_open_device_path(sysfs_path);
 	if (device == NULL) {
 		dprintf("Error opening device %s\n", bus_id);
 		return NULL;
@@ -490,6 +572,60 @@
 	return device;
 }
 
+/**
+ * sysfs_get_device_parent: opens up given device's parent and returns a 
+ * 	reference to its sysfs_device
+ * @dev: sysfs_device whose parent is requested
+ * Returns sysfs_device of the parent on success and NULL on failure
+ */
+struct sysfs_device *sysfs_get_device_parent(struct sysfs_device *dev)
+{
+	char ppath[SYSFS_PATH_MAX], *tmp = NULL;
+
+	if (dev == NULL) {
+		errno = EINVAL;
+		return NULL;
+	}
+
+	if (dev->parent != NULL)
+		return (dev->parent);
+
+	memset(ppath, 0, SYSFS_PATH_MAX);
+	safestrcpy(ppath, dev->path);
+	tmp = strrchr(ppath, '/');
+	if (tmp == NULL) {
+		dprintf("Invalid path to device %s\n", ppath);
+		return NULL;
+	}
+	if (*(tmp + 1) == '\0') {
+		*tmp = '\0';
+		tmp = strrchr(tmp, '/');
+		if (tmp == NULL) {
+			dprintf("Invalid path to device %s\n", ppath);
+			return NULL;
+		}
+	}
+	*tmp = '\0';
+	
+	/*
+	 * All "devices" have the "detach_state" attribute - validate here
+	 */
+	safestrcat(ppath, "/detach_state");
+	if ((sysfs_path_is_file(ppath)) != 0) {
+		dprintf("Device at %s does not have a parent\n", dev->path);
+		return NULL;
+	}
+	tmp = strrchr(ppath, '/');
+	*tmp = '\0';
+	dev->parent = sysfs_open_device_path(ppath);
+	if (dev->parent == NULL) {
+		dprintf("Error opening device %s's parent at %s\n", 
+					dev->bus_id, ppath);
+		return NULL;
+	}
+	return (dev->parent);
+}
+
 /*
  * sysfs_open_device_attr: open the given device's attribute
  * @bus: Bus on which to look
@@ -501,11 +637,11 @@
  * 	A call to sysfs_close_attribute() is required to close
  * 	the attribute returned and free memory. 
  */
-struct sysfs_attribute *sysfs_open_device_attr(const unsigned char *bus,
-		const unsigned char *bus_id, const unsigned char *attrib)
+struct sysfs_attribute *sysfs_open_device_attr(const char *bus,
+		const char *bus_id, const char *attrib)
 {
 	struct sysfs_attribute *attribute = NULL;
-	unsigned char devpath[SYSFS_PATH_MAX];
+	char devpath[SYSFS_PATH_MAX];
 	
 	if (bus == NULL || bus_id == NULL || attrib == NULL) {
 		errno = EINVAL;
@@ -518,8 +654,8 @@
 		dprintf("Error getting to device %s\n", bus_id);
 		return NULL;
 	}
-	strcat(devpath, "/");
-	strcat(devpath, attrib);
+	safestrcat(devpath, "/");
+	safestrcat(devpath, attrib);
 	attribute = sysfs_open_attribute(devpath);
 	if (attribute == NULL) {
 		dprintf("Error opening attribute %s for device %s\n",

Index: sysfs_dir.c
===================================================================
RCS file: /cvs/hal/hal/hald/linux/libsysfs/sysfs_dir.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- sysfs_dir.c	14 Dec 2003 21:22:43 -0000	1.1
+++ sysfs_dir.c	18 Jul 2004 15:21:23 -0000	1.2
@@ -1,5 +1,5 @@
 /*
- * syfs_dir.c
+ * sysfs_dir.c
  *
  * Directory utility functions for libsysfs
  *
@@ -58,9 +58,9 @@
 	if (a == NULL || b == NULL)
 		return 0;
 
-	if (strcmp(((unsigned char *)a), ((struct sysfs_attribute *)b)->name) 
-	    == 0)
+	if (strcmp(((char *)a), ((struct sysfs_attribute *)b)->name) == 0)
 		return 1;
+
 	return 0;
 }
 
@@ -75,9 +75,9 @@
 	if (a == NULL || b == NULL)
 		return 0;
 
-	if (strcmp(((unsigned char *)a), ((struct sysfs_link *)b)->name) 
-	    == 0)
+	if (strcmp(((char *)a), ((struct sysfs_link *)b)->name) == 0)
 		return 1;
+
 	return 0;
 }
 
@@ -92,9 +92,9 @@
 	if (a == NULL || b == NULL)
 		return 0;
 
-	if (strcmp(((unsigned char *)a), ((struct sysfs_directory *)b)->name)
-	    == 0)
+	if (strcmp(((char *)a), ((struct sysfs_directory *)b)->name) == 0)
 		return 1;
+
 	return 0;
 }
 
@@ -126,7 +126,7 @@
  * @path: path to attribute.
  * returns sysfs_attribute struct with success and NULL with error.
  */
-struct sysfs_attribute *sysfs_open_attribute(const unsigned char *path)
+struct sysfs_attribute *sysfs_open_attribute(const char *path)
 {
 	struct sysfs_attribute *sysattr = NULL;
 	struct stat fileinfo;
@@ -140,14 +140,13 @@
 		dprintf("Error allocating attribute at %s\n", path);
 		return NULL;
 	}
-	if (sysfs_get_name_from_path(path, sysattr->name, SYSFS_NAME_LEN) 
-	    != 0) {
-		dprintf("Error retrieving attribute name from path: %s\n", 
-			path);
+	if (sysfs_get_name_from_path(path, sysattr->name, 
+				SYSFS_NAME_LEN) != 0) {
+		dprintf("Error retrieving attrib name from path: %s\n", path);
 		sysfs_close_attribute(sysattr);
 		return NULL;
 	}
-	strncpy(sysattr->path, path, sizeof(sysattr->path));
+	safestrcpy(sysattr->path, path);
 	if ((stat(sysattr->path, &fileinfo)) != 0) {
 		dprintf("Stat failed: No such attribute?\n");
 		sysattr->method = 0;
@@ -171,7 +170,7 @@
  * returns 0 with success and -1 with error.
  */
 int sysfs_write_attribute(struct sysfs_attribute *sysattr,
-		const unsigned char *new_value, size_t len)
+		const char *new_value, size_t len)
 {
 	int fd;
 	int length;
@@ -184,11 +183,19 @@
 	if (!(sysattr->method & SYSFS_METHOD_STORE)) {
 		dprintf ("Store method not supported for attribute %s\n",
 			sysattr->path);
+		errno = EACCES;
 		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",
+			dprintf("Attr %s already has the requested value %s\n",
 					sysattr->name, new_value);
 			return 0;	
 		}
@@ -208,7 +215,7 @@
 			sysattr->name);
 		close(fd);
 		return -1;
-	} else if (length != len) {
+	} else if ((unsigned int)length != len) {
 		dprintf("Could not write %d bytes to attribute %s\n", 
 					len, sysattr->name);
 		/* 
@@ -229,13 +236,13 @@
 	 */ 
 	if (sysattr->method & SYSFS_METHOD_SHOW) {
 		if (length != sysattr->len) {
-			sysattr->value = (char *)realloc(sysattr->value, 
-								length);
+			sysattr->value = (char *)realloc
+				(sysattr->value, length);
 			sysattr->len = length;
-			strncpy(sysattr->value, new_value, length);
+			safestrcpymax(sysattr->value, new_value, length);
 		} else {
 			/*"length" of the new value is same as old one */ 
-			strncpy(sysattr->value, new_value, length);
+			safestrcpymax(sysattr->value, new_value, length);
 		}
 	}
 			
@@ -243,7 +250,6 @@
 	return 0;
 }
 
-
 /**
  * sysfs_read_attribute: reads value from attribute
  * @sysattr: attribute to read
@@ -251,10 +257,10 @@
  */
 int sysfs_read_attribute(struct sysfs_attribute *sysattr)
 {
-	unsigned char *fbuf = NULL;
-	unsigned char *vbuf = NULL;
-	size_t length = 0;
-	int pgsize = 0;
+	char *fbuf = NULL;
+	char *vbuf = NULL;
+	ssize_t length = 0;
+	long pgsize = 0;
 	int fd;
 
 	if (sysattr == NULL) {
@@ -264,10 +270,11 @@
 	if (!(sysattr->method & SYSFS_METHOD_SHOW)) {
 		dprintf("Show method not supported for attribute %s\n",
 			sysattr->path);
+		errno = EACCES;
 		return -1;
 	}
-	pgsize = getpagesize();
-	fbuf = (unsigned char *)calloc(1, pgsize+1);
+	pgsize = sysconf(_SC_PAGESIZE);
+	fbuf = (char *)calloc(1, pgsize+1);
 	if (fbuf == NULL) {
 		dprintf("calloc failed\n");
 		return -1;
@@ -284,9 +291,18 @@
 		free(fbuf);
 		return -1;
 	}
+	if (sysattr->len > 0) {
+		if ((sysattr->len == length) && 
+				(!(strncmp(sysattr->value, fbuf, length)))) {
+			close(fd);
+			free(fbuf);
+			return 0;
+		}
+		free(sysattr->value);
+	}
 	sysattr->len = length;
 	close(fd);
-	vbuf = (unsigned char *)realloc(fbuf, length+1);
+	vbuf = (char *)realloc(fbuf, length+1);
 	if (vbuf == NULL) {
 		dprintf("realloc failed\n");
 		free(fbuf);
@@ -306,13 +322,13 @@
  * @vsize: size of value buffer
  * returns 0 with success and -1 with error.
  */
-int sysfs_read_attribute_value(const unsigned char *attrpath, 
-					unsigned char *value, size_t vsize)
+int sysfs_read_attribute_value(const char *attrpath, 
+					char *value, size_t vsize)
 {
 	struct sysfs_attribute *attr = NULL;
 	size_t length = 0;
 
-	if (attrpath == NULL || value == NULL) {
+	if (attrpath == NULL || value == NULL || vsize == 0) {
 		errno = EINVAL;
 		return -1;
 	}
@@ -332,7 +348,7 @@
 	if (length > vsize) 
 		dprintf("Value length %d is larger than supplied buffer %d\n",
 			length, vsize);
-	strncpy(value, attr->value, vsize);
+	safestrcpymax(value, attr->value, vsize);
 	sysfs_close_attribute(attr);
 
 	return 0;
@@ -343,10 +359,9 @@
  * 	attribute name, return its value
  * @attr: attribute to search
  * @name: name to look for
- * returns unsigned char * value - could be NULL
+ * returns char * value - could be NULL
  */
-unsigned char *sysfs_get_value_from_attributes(struct dlist *attr, 
-					const unsigned char *name)
+char *sysfs_get_value_from_attributes(struct dlist *attr, const char *name)
 {	
 	struct sysfs_attribute *cur = NULL;
 	
@@ -385,6 +400,7 @@
 		if (sysdir->attributes != NULL) 
 			dlist_destroy(sysdir->attributes);
 		free(sysdir);
+		sysdir = NULL;
 	}
 }
 
@@ -415,19 +431,28 @@
 int sysfs_read_all_subdirs(struct sysfs_directory *sysdir)
 {
 	struct sysfs_directory *cursub = NULL;
+	int retval = 0;
 
 	if (sysdir == NULL) {
 		errno = EINVAL;
 		return -1;
 	}
-	if (sysdir->subdirs == NULL)
-		return 0;
-	dlist_for_each_data(sysdir->subdirs, cursub, struct sysfs_directory) {
-		if (sysfs_read_directory(cursub) != 0) 
-			dprintf ("Error reading subdirectory %s\n",
-				cursub->name);
+	if (sysdir->subdirs == NULL) 
+		if ((sysfs_read_dir_subdirs(sysdir)) != 0) 
+			return 0;
+	if (sysdir->subdirs != NULL) {
+		dlist_for_each_data(sysdir->subdirs, cursub, 
+						struct sysfs_directory) {
+			if ((sysfs_read_dir_subdirs(cursub)) != 0) {
+				dprintf ("Error reading subdirectory %s\n",
+						cursub->name);
+				retval = -1;
+			}
+		}
 	}
-	return 0;
+	if (!retval)
+		errno = 0;
+	return retval;
 }
 
 /**
@@ -436,7 +461,7 @@
  * @path: path of directory to open.
  * returns: struct sysfs_directory * with success and NULL on error.
  */
-struct sysfs_directory *sysfs_open_directory(const unsigned char *path)
+struct sysfs_directory *sysfs_open_directory(const char *path)
 {
 	struct sysfs_directory *sdir = NULL;
 
@@ -444,6 +469,13 @@
 		errno = EINVAL;
 		return NULL;
 	}
+
+	if (sysfs_path_is_dir(path) != 0) {
+		dprintf("Invalid path to directory %s\n", path);
+		errno = EINVAL;
+		return NULL;
+	}
+
 	sdir = alloc_directory();
 	if (sdir == NULL) {
 		dprintf("Error allocating directory %s\n", path);
@@ -454,7 +486,7 @@
 		sysfs_close_directory(sdir);
 		return NULL;
 	}
-	strncpy(sdir->path, path, sizeof(sdir->path));
+	safestrcpy(sdir->path, path);
 
 	return sdir;
 }
@@ -464,7 +496,7 @@
  * @path: path of link to open.
  * returns: struct sysfs_link * with success and NULL on error.
  */
-struct sysfs_link *sysfs_open_link(const unsigned char *linkpath)
+struct sysfs_link *sysfs_open_link(const char *linkpath)
 {
 	struct sysfs_link *ln = NULL;
 
@@ -478,7 +510,7 @@
 		dprintf("Error allocating link %s\n", linkpath);
 		return NULL;
 	}
-	strcpy(ln->path, linkpath);
+	safestrcpy(ln->path, linkpath);
 	if ((sysfs_get_name_from_path(linkpath, ln->name, SYSFS_NAME_LEN)) != 0
 	    || (sysfs_get_link(linkpath, ln->target, SYSFS_PATH_MAX)) != 0) {
 		errno = EINVAL;
@@ -490,6 +522,202 @@
 }
 
 /**
+ * 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 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_sorted(sysdir->attributes, attr, sort_list);
+
+	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 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_sorted(sysdir->subdirs, subdir, sort_list);
+	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 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_sorted(sysdir->links, ln, sort_list);
+	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_dir_attributes(struct sysfs_directory *sysdir)
+{
+	DIR *dir = NULL;
+	struct dirent *dirent = NULL;
+	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);
+		safestrcpy(file_path, sysdir->path);
+		safestrcat(file_path, "/");
+		safestrcat(file_path, dirent->d_name);
+		if ((sysfs_path_is_file(file_path)) == 0)
+			retval = add_attribute(sysdir, file_path);
+	}
+	closedir(dir);
+	if (!retval)
+		errno = 0;
+	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;
+	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);
+		safestrcpy(file_path, sysdir->path);
+		safestrcat(file_path, "/");
+		safestrcat(file_path, dirent->d_name);
+		if ((sysfs_path_is_link(file_path)) == 0) {
+			retval = add_link(sysdir, file_path);
+			if (retval != 0)
+				break;
+		}
+	}
+	closedir(dir);
+	if (!retval)
+		errno = 0;
+	return(retval);
+}
+
+/**
+ * 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;
+	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);
+		safestrcpy(file_path, sysdir->path);
+		safestrcat(file_path, "/");
+		safestrcat(file_path, dirent->d_name);
+		if ((sysfs_path_is_dir(file_path)) == 0)
+			retval = add_subdirectory(sysdir, file_path);
+	}
+	closedir(dir);
+	if (!retval)
+		errno = 0;
+	return(retval);
+}
+
+/**
  * sysfs_read_directory: grabs attributes, links, and subdirectories
  * @sysdir: sysfs directory to open
  * returns 0 with success and -1 with error.
@@ -499,10 +727,7 @@
 	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];
+	char file_path[SYSFS_PATH_MAX];
 	int retval = 0;
 
 	if (sysdir == NULL) {
@@ -520,100 +745,164 @@
 		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));
+		safestrcpy(file_path, sysdir->path);
+		safestrcat(file_path, "/");
+		safestrcat(file_path, dirent->d_name);
 		if ((lstat(file_path, &astats)) != 0) {
 			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;
-				break;
-			}
-			if (sysdir->links == NULL)
-				sysdir->links = dlist_new_with_delete
-						(sizeof(struct sysfs_link),
-						 		sysfs_del_link);
-			dlist_unshift(sysdir->links, ln);
-		}
+		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);
+	if (!retval)
+		errno = 0;
 	return(retval);
 }
 
 /**
- * sysfs_get_directory_attribute: retrieves attribute attrname
+ * sysfs_refresh_dir_attributes: Refresh attributes list
+ * @sysdir: directory whose list of attributes to refresh
+ * Returns 0 on success, 1 on failure
+ */
+int sysfs_refresh_dir_attributes(struct sysfs_directory *sysdir)
+{
+	if (sysdir == NULL) {
+		errno = EINVAL;
+		return 1;
+	}
+	if ((sysfs_path_is_dir(sysdir->path)) != 0) {
+		dprintf("Invalid path to directory %s\n", sysdir->path);
+		errno = EINVAL;
+		return 1;
+	}
+	if (sysdir->attributes != NULL) {
+		dlist_destroy(sysdir->attributes);
+		sysdir->attributes = NULL;
+	}
+	if ((sysfs_read_dir_attributes(sysdir)) != 0) {
+		dprintf("Error refreshing attributes for directory %s\n", 
+							sysdir->path);
+		return 1;
+	}
+	errno = 0;
+	return 0;
+}
+
+/**
+ * sysfs_refresh_dir_links: Refresh links list
+ * @sysdir: directory whose list of links to refresh
+ * Returns 0 on success, 1 on failure
+ */
+int sysfs_refresh_dir_links(struct sysfs_directory *sysdir)
+{
+	if (sysdir == NULL) {
+		errno = EINVAL;
+		return 1;
+	}
+	if ((sysfs_path_is_dir(sysdir->path)) != 0) {
+		dprintf("Invalid path to directory %s\n", sysdir->path);
+		errno = EINVAL;
+		return 1;
+	}
+	if (sysdir->links != NULL) {
+		dlist_destroy(sysdir->links);
+		sysdir->links = NULL;
+	}
+	if ((sysfs_read_dir_links(sysdir)) != 0) {
+		dprintf("Error refreshing links for directory %s\n", 
+							sysdir->path);
+		return 1;
+	}
+	errno = 0;
+	return 0;
+}
+
+/**
+ * sysfs_refresh_dir_subdirs: Refresh subdirs list
+ * @sysdir: directory whose list of subdirs to refresh
+ * Returns 0 on success, 1 on failure
+ */
+int sysfs_refresh_dir_subdirs(struct sysfs_directory *sysdir)
+{
+	if (sysdir == NULL) {
+		errno = EINVAL;
+		return 1;
+	}
+	if ((sysfs_path_is_dir(sysdir->path)) != 0) {
+		dprintf("Invalid path to directory %s\n", sysdir->path);
+		errno = EINVAL;
+		return 1;
+	}
+	if (sysdir->subdirs != NULL) {
+		dlist_destroy(sysdir->subdirs);
+		sysdir->subdirs = NULL;
+	}
+	if ((sysfs_read_dir_subdirs(sysdir)) != 0) {
+		dprintf("Error refreshing subdirs for directory %s\n", 
+							sysdir->path);
+		return 1;
+	}
+	errno = 0;
+	return 0;
+}
+
+/**
+ * sysfs_get_directory_attribute: retrieves attribute attrname from current
+ *	directory only
  * @dir: directory to retrieve attribute from
  * @attrname: name of attribute to look for
+ *
+ * NOTE: Since we know the attribute to look for, this routine looks for the
+ * 	attribute if it was created _after_ the attrlist was read initially.
+ * 	
  * returns sysfs_attribute if found and NULL if not found
  */
 struct sysfs_attribute *sysfs_get_directory_attribute
-			(struct sysfs_directory *dir, unsigned char *attrname)
+			(struct sysfs_directory *dir, char *attrname)
 {
-	struct sysfs_directory *sdir = NULL;
 	struct sysfs_attribute *attr = NULL;
+	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)
-		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;
+
+	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) {
+		if ((sysfs_read_attribute(attr)) != 0) {
+			dprintf("Error reading attribute %s\n", attr->name);
+			return NULL;
+		}
+	} else {
+		memset(new_path, 0, SYSFS_PATH_MAX);
+		safestrcpy(new_path, dir->path);
+		safestrcat(new_path, "/");
+		safestrcat(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 NULL;
+		
+	return attr;
 }
 
 /**
@@ -623,12 +912,20 @@
  * returns reference to sysfs_link if found and NULL if not found
  */
 struct sysfs_link *sysfs_get_directory_link
-			(struct sysfs_directory *dir, unsigned char *linkname)
+			(struct sysfs_directory *dir, char *linkname)
 {
 	if (dir == NULL || linkname == NULL) {
 		errno = EINVAL;
 		return NULL;
 	}
+	if (dir->links == NULL) {
+		if ((sysfs_read_dir_links(dir) != 0) || (dir->links == NULL))
+			return NULL;
+	} else {
+		if ((sysfs_refresh_dir_links(dir)) != 0) 
+			return NULL;
+	}
+
 	return (struct sysfs_link *)dlist_find_custom(dir->links,
 		linkname, dir_link_name_equal);
 }
@@ -640,14 +937,19 @@
  * returns reference to subdirectory or NULL if not found
  */
 struct sysfs_directory *sysfs_get_subdirectory(struct sysfs_directory *dir,
-						unsigned char *subname)
+						char *subname)
 {
 	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) 
@@ -656,8 +958,12 @@
 	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;
@@ -673,12 +979,12 @@
  * returns reference to link or NULL if not found
  */
 struct sysfs_link *sysfs_get_subdirectory_link(struct sysfs_directory *dir,
-						unsigned char *linkname)
+						char *linkname)
 {
 	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;
 	}
@@ -687,14 +993,13 @@
 	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;
@@ -702,3 +1007,63 @@
 	}
 	return NULL;
 }
+
+/**
+ * sysfs_get_dir_attributes: returns dlist of directory attributes
+ * @dir: directory to retrieve attributes from
+ * returns dlist of attributes or NULL
+ */
+struct dlist *sysfs_get_dir_attributes(struct sysfs_directory *dir)
+{
+	if (dir == NULL) {
+		errno = EINVAL;
+		return NULL;
+	}
+
+	if (dir->attributes == NULL) {
+		if (sysfs_read_dir_attributes(dir) != 0)
+			return NULL;
+	}
+
+	return (dir->attributes);
+}
+
+/**
+ * sysfs_get_dir_links: returns dlist of directory links
+ * @dir: directory to return links for
+ * returns dlist of links or NULL
+ */
+struct dlist *sysfs_get_dir_links(struct sysfs_directory *dir)
+{
+	if (dir == NULL) {
+		errno = EINVAL;
+		return NULL;
+	}
+
+	if (dir->links == NULL) {
+		if (sysfs_read_dir_links(dir) != 0)
+			return NULL;
+	}
+
+	return (dir->links);
+}
+
+/**
+ * sysfs_get_dir_subdirs: returns dlist of directory subdirectories
+ * @dir: directory to return subdirs for
+ * returns dlist of subdirs or NULL
+ */
+struct dlist *sysfs_get_dir_subdirs(struct sysfs_directory *dir)
+{
+	if (dir == NULL) {
+		errno = EINVAL;
+		return NULL;
+	}
+
+	if (dir->subdirs == NULL) {
+		if (sysfs_read_dir_subdirs(dir) != 0)
+			return NULL;
+	}
+
+	return (dir->subdirs);
+}

Index: sysfs_driver.c
===================================================================
RCS file: /cvs/hal/hal/hald/linux/libsysfs/sysfs_driver.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- sysfs_driver.c	14 Dec 2003 21:22:43 -0000	1.1
+++ sysfs_driver.c	18 Jul 2004 15:21:23 -0000	1.2
@@ -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,28 @@
 }
 		
 /**
+ * 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;
+}
+
+/**
  * alloc_driver: allocates and initializes driver
  * returns struct sysfs_driver with success and NULL with error.
  */
@@ -73,38 +75,39 @@
 }
 
 /**
- * sysfs_open_driver: opens and initializes driver structure
+ * sysfs_open_driver_path: opens and initializes driver structure
  * @path: path to driver directory
  * returns struct sysfs_driver with success and NULL with error
  */
-struct sysfs_driver *sysfs_open_driver(const unsigned char *path)
+struct sysfs_driver *sysfs_open_driver_path(const 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;
+	}
+	safestrcpy(driver->path, path);
+	if ((sysfs_remove_trailing_slash(driver->path)) != 0) {
+		dprintf("Invalid path to driver %s\n", driver->path);
+		sysfs_close_driver(driver);
+		return NULL;
+	}
 	
 	return driver;
 }
@@ -117,35 +120,68 @@
  */
 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) 
+			return NULL;
+	}
 	return(driver->directory->attributes);
 }
 
 /**
+ * sysfs_refresh_driver_attributes: refreshes the driver's list of attributes
+ * @driver: sysfs_driver whose attributes to refresh
+ *
+ * NOTE: Upon return, prior references to sysfs_attributes for this driver
+ * 		_may_ not be valid
+ * 		
+ * Returns list of attributes on success and NULL on failure
+ */
+struct dlist *sysfs_refresh_driver_attributes(struct sysfs_driver *driver)
+{
+	if (driver == NULL) {
+		errno = EINVAL;
+		return NULL;
+	}
+	if (driver->directory == NULL)
+		return (sysfs_get_driver_attributes(driver));
+	
+	if ((sysfs_refresh_dir_attributes(driver->directory)) != 0) {
+		dprintf("Error refreshing driver attributes\n");
+		return NULL;
+	}
+	return (driver->directory->attributes);
+}
+
+/**
  * sysfs_get_driver_attr: searches driver's attributes by name
  * @drv: driver to look through
  * @name: attribute name to get
  * returns sysfs_attribute reference on success or NULL with error
  */ 
 struct sysfs_attribute *sysfs_get_driver_attr(struct sysfs_driver *drv,
-					const unsigned char *name)
+					const 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;
         }
+	
+	attrlist = sysfs_get_driver_attributes(drv);
+	if (attrlist == NULL) 
+		return NULL;
 
-        cur = sysfs_get_directory_attribute(drv->directory,
-		                        (unsigned char *)name);
-        if (cur != NULL)
-                return cur;
-
-        return NULL;
+	return sysfs_get_directory_attribute(drv->directory, (char *)name);
 }
 
 /**
@@ -156,97 +192,159 @@
  */
 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 (driver->directory->links == NULL)
+		if ((sysfs_read_dir_links(driver->directory)) != 0) 
+			return NULL;
+		
 	return(driver->directory->links);
 }
 
 /**
- * get_driver_path: looks up the bus the driver is on and builds path to
- * 		the driver.
- * @bus: bus on which to search
- * @drv: driver to look for
- * @path: buffer to return path to 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)
-{
-	if (bus == NULL || drv == NULL || path == NULL) {
-		errno = EINVAL;
-		return -1;
-	}
-	if (sysfs_get_mnt_path(path, psize) != 0) {
-		dprintf("Error getting sysfs mount path\n");
-		return -1;
-	}
-	strcat(path, SYSFS_BUS_DIR);
-	strcat(path, "/");
-	strcat(path, bus);
-	strcat(path, SYSFS_DRIVERS_DIR);
-	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)
+ * 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_driver *driver = NULL;
-	struct sysfs_device *device = NULL;
 	struct sysfs_link *curlink = NULL;
-	unsigned char path[SYSFS_PATH_MAX];
+	struct sysfs_device *device = NULL;
 
-	if (drv_name == NULL || bus == NULL) {
+	if (driver == NULL) {
 		errno = EINVAL;
 		return NULL;
 	}
+	
+	if (driver->devices != NULL)
+		return (driver->devices);
 
-	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 == NULL || driver->directory->links == NULL) {
+		struct dlist *list = NULL;
+		list = sysfs_get_driver_links(driver);
 	}
+	
 	if (driver->directory->links != NULL) {
 		dlist_for_each_data(driver->directory->links, curlink, 
-							struct sysfs_link) {
-			device = sysfs_open_device(curlink->target);
+						struct sysfs_link) {
+			device = sysfs_open_device_path(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);
+						 sysfs_close_driver_device);
+			dlist_unshift_sorted(driver->devices, device, 
+								sort_list);
 		}
 	}
-	return driver;
+	return (driver->devices);
+}
+
+/**
+ * sysfs_refresh_driver_devices: Refreshes drivers list of devices
+ * @driver: sysfs_driver whose devices list needs to be refreshed
+ *
+ * NOTE: Upon return from this function, prior sysfs_device references from
+ * 		this driver's list of devices _may_ not be valid
+ * 		
+ * Returns dlist of devices on success and NULL on failure
+ */
+struct dlist *sysfs_refresh_driver_devices(struct sysfs_driver *driver)
+{
+	if (driver == NULL) {
+		errno = EINVAL;
+		return NULL;
+	}
+	
+	if (driver->devices != NULL) {
+		dlist_destroy(driver->devices);
+		driver->devices = NULL;
+	}
+	
+	if (driver->directory == NULL)
+		return (sysfs_get_driver_devices(driver));
+
+	if ((sysfs_refresh_dir_links(driver->directory)) != 0) {
+		dprintf("Error refreshing driver links\n");
+		return NULL;
+	}
+	
+	return (sysfs_get_driver_devices(driver));
+}
+
+/**
+ * sysfs_get_driver_device: looks up a device from a list of driver's devices
+ * 	and returns its sysfs_device corresponding to it
+ * @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 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
+ * @drv: driver to look for
+ * @path: buffer to return path to driver
+ * @psize: size of "path"
+ * Returns 0 on success and -1 on error
+ */
+static int get_driver_path(const char *bus, const char *drv, 
+			char *path, size_t psize)
+{
+	if (bus == NULL || drv == NULL || path == NULL || psize == 0) {
+		errno = EINVAL;
+		return -1;
+	}
+	if (sysfs_get_mnt_path(path, psize) != 0) {
+		dprintf("Error getting sysfs mount path\n");
+		return -1;
+	}
+	safestrcatmax(path, "/", psize);
+	safestrcatmax(path, SYSFS_BUS_NAME, psize);
+	safestrcatmax(path, "/", psize);
+	safestrcatmax(path, bus, psize);
+	safestrcatmax(path, "/", psize);
+	safestrcatmax(path, SYSFS_DRIVERS_NAME, psize);
+	safestrcatmax(path, "/", psize);
+	safestrcatmax(path, drv, psize);
+	return 0;
+}
 
 /**
  * sysfs_open_driver_attr: read the user supplied driver attribute
@@ -259,24 +357,24 @@
  * 	A call to sysfs_close_attribute() is required to close the
  * 	attribute returned and to free memory
  */ 
-struct sysfs_attribute *sysfs_open_driver_attr(const unsigned char *bus, 
-		const unsigned char *drv, const unsigned char *attrib)
+struct sysfs_attribute *sysfs_open_driver_attr(const char *bus, 
+		const char *drv, const char *attrib)
 {
 	struct sysfs_attribute *attribute = NULL;
-	unsigned char path[SYSFS_PATH_MAX];
+	char path[SYSFS_PATH_MAX];
 
 	if (bus == NULL || drv == NULL || attrib == NULL) {
 		errno = EINVAL;
 		return NULL;
 	}
 
-	memset(path, 0, SYSFS_NAME_LEN);
+	memset(path, 0, SYSFS_PATH_MAX);
 	if ((get_driver_path(bus, drv, path, SYSFS_PATH_MAX)) != 0) {
 		dprintf("Error getting to driver %s\n", drv);
 		return NULL;
 	}
-	strcat(path, "/");
-	strcat(path, attrib);
+	safestrcat(path, "/");
+	safestrcat(path, attrib);
 	attribute = sysfs_open_attribute(path);
         if (attribute == NULL) {
 		dprintf("Error opening attribute %s for driver %s\n",
@@ -292,3 +390,33 @@
 	return attribute;
 }
 
+/**
+ * sysfs_open_driver: open driver by name, given its bus
+ * @bus_name: Name of the bus
+ * @drv_name: Name of the driver
+ * Returns the sysfs_driver reference on success and NULL on failure
+ */
+struct sysfs_driver *sysfs_open_driver(const char *bus_name, 
+			const char *drv_name)
+{
+	char path[SYSFS_PATH_MAX];
+	struct sysfs_driver *driver = NULL;
+
+	if (drv_name == NULL || bus_name == NULL) {
+		errno = EINVAL;
+		return NULL;
+	}
+
+	memset(path, 0, SYSFS_PATH_MAX);
+	if ((get_driver_path(bus_name, drv_name, path, SYSFS_PATH_MAX)) != 0) {
+		dprintf("Error getting to driver %s\n", drv_name);
+		return NULL;
+	}
+	driver = sysfs_open_driver_path(path);
+	if (driver == NULL) {
+		dprintf("Error opening driver at %s\n", path);
+		return NULL;
+	}
+	return driver;
+}
+

Index: sysfs_utils.c
===================================================================
RCS file: /cvs/hal/hal/hald/linux/libsysfs/sysfs_utils.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- sysfs_utils.c	14 Dec 2003 21:22:43 -0000	1.1
+++ sysfs_utils.c	18 Jul 2004 15:21:23 -0000	1.2
@@ -1,5 +1,5 @@
 /*
- * syfs_utils.c
+ * sysfs_utils.c
  *
  * System utility functions for libsysfs
  *
@@ -23,15 +23,45 @@
 #include "libsysfs.h"
 #include "sysfs.h"
 
+static int sort_char(void *new, void *old)
+{
+	return ((strncmp((char *)new, (char *)old, 
+			strlen((char *)new))) < 0 ? 1 : 0);
+}
+
 /**
- * sysfs_get_mnt_path: Gets the mount point for specified filesystem.
+ * sysfs_remove_trailing_slash: Removes any trailing '/' in the given path
+ * @path: Path to look for the trailing '/'
+ * Returns 0 on success 1 on error
+ */ 
+int sysfs_remove_trailing_slash(char *path)
+{
+	char *c = NULL;
+
+	if (path == NULL) {
+		errno = EINVAL;
+		return 1;
+	}
+	c = strrchr(path, '/');
+	if (c == NULL) {
+		dprintf("Invalid path %s\n", path);
+		errno = EINVAL;
+		return 1;
+	}
+	if (*(c+1) == '\0') 
+		*c = '\0';
+	return 0;
+}
+
+/**
+ * sysfs_get_fs_mnt_path: Gets the mount point for specified filesystem.
  * @fs_type: filesystem type to retrieve mount point
  * @mnt_path: place to put the retrieved mount path
  * @len: size of mnt_path
  * returns 0 with success and -1 with error.
  */
-static int sysfs_get_fs_mnt_path(const unsigned char *fs_type, 
-				unsigned char *mnt_path, size_t len)
+static int sysfs_get_fs_mnt_path(const char *fs_type, 
+				char *mnt_path, size_t len)
 {
 	FILE *mnt;
 	struct mntent *mntent;
@@ -39,7 +69,7 @@
 	size_t dirlen = 0;
 
 	/* check arg */
-	if (fs_type == NULL || mnt_path == NULL) {
+	if (fs_type == NULL || mnt_path == NULL || len == 0) {
 		errno = EINVAL;
 		return -1;
 	}
@@ -52,7 +82,7 @@
 		if (strcmp(mntent->mnt_type, fs_type) == 0) {
 			dirlen = strlen(mntent->mnt_dir);
 			if (dirlen <= (len - 1)) {
-				strcpy(mnt_path, mntent->mnt_dir);
+				safestrcpymax(mnt_path, mntent->mnt_dir, len);
 			} else {
 				dprintf("Error - mount path too long\n");
 				ret = -1;
@@ -65,6 +95,9 @@
 		errno = EINVAL;
 		ret = -1;
 	}
+	if ((sysfs_remove_trailing_slash(mnt_path)) != 0)
+		ret = -1;
+	
 	return ret;
 }
 
@@ -74,19 +107,21 @@
  * @len: size of mnt_path
  * returns 0 with success and -1 with error.
  */
-int sysfs_get_mnt_path(unsigned char *mnt_path, size_t len)
+int sysfs_get_mnt_path(char *mnt_path, size_t len)
 {
 	char *sysfs_path = NULL;
 	int ret = 0;
 
-	if (mnt_path == NULL) {
+	if (mnt_path == NULL || len == 0) {
 		errno = EINVAL;
 		return -1;
 	}
 	sysfs_path = getenv(SYSFS_PATH_ENV);
-	if (sysfs_path != NULL) 
-		strncpy(mnt_path, sysfs_path, len);
-	else
+	if (sysfs_path != NULL) {
+		safestrcpymax(mnt_path, sysfs_path, len);
+		if ((sysfs_remove_trailing_slash(mnt_path)) != 0)
+			return 1;
+	} else
 		ret = sysfs_get_fs_mnt_path(SYSFS_FSTYPE_NAME, mnt_path, len);
 
 	return ret;
@@ -98,88 +133,132 @@
  * @name: where to put name
  * @len: size of name
  */
-int sysfs_get_name_from_path(const unsigned char *path, unsigned char *name, 
-								size_t len)
+int sysfs_get_name_from_path(const char *path, char *name, size_t len)
 {
-	unsigned char tmp[SYSFS_PATH_MAX];
-	unsigned char *n = NULL;
+	char tmp[SYSFS_PATH_MAX];
+	char *n = NULL;
                                                                                 
-	if (path == NULL || name == NULL) {
+	if (path == NULL || name == NULL || len == 0) {
 		errno = EINVAL;
 		return -1;
 	}
 	memset(tmp, 0, SYSFS_PATH_MAX);
-	strcpy(tmp, path);
-	n = &tmp[strlen(tmp)-1];
-	if (strncmp(n, "/", 1) == 0)
-		*n = '\0';	
+	safestrcpy(tmp, path);
 	n = strrchr(tmp, '/');
 	if (n == NULL) {
 		errno = EINVAL;
 		return -1;
 	}
+	if (*(n+1) == '\0') {
+		*n = '\0';
+		n = strrchr(tmp, '/');
+		if (n == NULL) {
+			errno = EINVAL;
+			return -1;
+		}
+	}
 	n++;
-	strncpy(name, n, len);
-
+	safestrcpymax(name, n, len);
 	return 0;
 }
-
+	
 /**
  * sysfs_get_link: returns link source
  * @path: symbolic link's path
  * @target: where to put name
  * @len: size of name
  */
-int sysfs_get_link(const unsigned char *path, unsigned char *target, size_t len)
+int sysfs_get_link(const char *path, char *target, size_t len)
 {
-	unsigned char devdir[SYSFS_PATH_MAX];
-	unsigned char linkpath[SYSFS_PATH_MAX];
-	unsigned char *d = NULL, *s = NULL;
+	char devdir[SYSFS_PATH_MAX];
+	char linkpath[SYSFS_PATH_MAX];
+	char temp_path[SYSFS_PATH_MAX];
+	char *d = NULL, *s = NULL;
 	int slashes = 0, count = 0;
 
-	if (path == NULL || target == NULL) {
+	if (path == NULL || target == NULL || len == 0) {
 		errno = EINVAL;
 		return -1;
 	}
 
 	memset(devdir, 0, SYSFS_PATH_MAX);
 	memset(linkpath, 0, SYSFS_PATH_MAX);
-	strncpy(devdir, path, SYSFS_PATH_MAX);
+	memset(temp_path, 0, SYSFS_PATH_MAX);
+	safestrcpy(devdir, path);
 
 	if ((readlink(path, linkpath, SYSFS_PATH_MAX)) < 0) {
 		return -1;
 	}
-									        
 	d = linkpath;
-
-	/* getting rid of leading "../.." */	
-	while (*d == '/' || *d == '.') {
-		if (*d == '/')
-			slashes++;
-		d++;
-	}
-
-	d--;
-
-	s = &devdir[strlen(devdir)-1];
-	while (s != NULL && count != (slashes+1)) {
-		s--;
-		if (*s == '/')
-			count++;
+	/* 
+	 * Three cases here:
+	 * 1. relative path => format ../..
+	 * 2. absolute path => format /abcd/efgh
+	 * 3. relative path _from_ this dir => format abcd/efgh
+	 */ 
+	switch (*d) {
+		case '.': 
+			/* 
+			 * handle the case where link is of type ./abcd/xxx
+			 */
+			safestrcpy(temp_path, devdir);
+			if (*(d+1) == '/')
+				d += 2;
+			else if (*(d+1) == '.')
+				goto parse_path;
+			s = strrchr(temp_path, '/');
+			if (s != NULL) {
+				*(s+1) = '\0';
+				safestrcat(temp_path, d);
+			} else {
+				safestrcpy(temp_path, d);
+			}
+			safestrcpymax(target, temp_path, len);
+			break;
+			/* 
+			 * relative path  
+			 * getting rid of leading "../.." 
+			 */
+parse_path:
+			while (*d == '/' || *d == '.') {
+				if (*d == '/')
+					slashes++;
+				d++;
+			}
+			d--;
+			s = &devdir[strlen(devdir)-1];
+			while (s != NULL && count != (slashes+1)) {
+				s--;
+				if (*s == '/')
+					count++;
+			}
+			safestrcpymax(s, d, (SYSFS_PATH_MAX-strlen(devdir)));
+			safestrcpymax(target, devdir, len);
+			break;
+		case '/':
+			/* absolute path - copy as is */
+			safestrcpymax(target, linkpath, len);
+			break;
+		default:
+			/* relative path from this directory */
+			safestrcpy(temp_path, devdir);
+			s = strrchr(temp_path, '/');
+			if (s != NULL) {
+				*(s+1) = '\0';
+				safestrcat(temp_path, linkpath);
+			} else {
+				safestrcpy(temp_path, linkpath);
+			}
+			safestrcpymax(target, temp_path, len);
 	}
-	
-	strncpy(s, d, (SYSFS_PATH_MAX-strlen(devdir)));
-	strncpy(target, devdir, len);
-
 	return 0;
 }
 
-
 /**
  * sysfs_del_name: free function for sysfs_open_subsystem_list
  * @name: memory area to be freed
  */ 
-void sysfs_del_name(void *name)
+static void sysfs_del_name(void *name)
 {
 	free(name);
 }
@@ -202,13 +281,12 @@
  * @name: name of the subsystem, eg., "bus", "class", "devices"
  * Returns a dlist of supported names or NULL if subsystem not supported
  */ 
-struct dlist *sysfs_open_subsystem_list(unsigned char *name)
+struct dlist *sysfs_open_subsystem_list(char *name)
 {
-	unsigned char sysfs_path[SYSFS_PATH_MAX], *subsys_name = NULL;
-	unsigned char *c = NULL;
+	char sysfs_path[SYSFS_PATH_MAX], *subsys_name = NULL;
+	char *c = NULL;
 	struct sysfs_directory *dir = NULL, *cur = NULL;
 	struct dlist *list = NULL;
-	struct stat astats;
 	
 	if (name == NULL)
 		return NULL;
@@ -218,14 +296,15 @@
 		return NULL;
 	}
 
-	strcat(sysfs_path, name);
+	safestrcat(sysfs_path, "/");
+	safestrcat(sysfs_path, name);
 	dir = sysfs_open_directory(sysfs_path);
 	if (dir == NULL) {
 		dprintf("Error opening sysfs_directory at %s\n", sysfs_path);
 		return NULL;
 	}
 
-	if (sysfs_read_directory(dir) != 0) {
+	if ((sysfs_read_dir_subdirs(dir)) != 0) {
 		dprintf("Error reading sysfs_directory at %s\n", sysfs_path);
 		sysfs_close_directory(dir);
 		return NULL;
@@ -243,8 +322,8 @@
 		dlist_for_each_data(dir->subdirs, cur,
 				struct sysfs_directory) {
 			subsys_name = (char *)calloc(1, SYSFS_NAME_LEN);
-			strcpy(subsys_name, cur->name);
-			dlist_unshift(list, subsys_name);
+			safestrcpymax(subsys_name, cur->name, SYSFS_NAME_LEN);
+			dlist_unshift_sorted(list, subsys_name, sort_char);
 		}
 	}
 	sysfs_close_directory(dir);
@@ -253,19 +332,18 @@
 	 * 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;
-		strcpy(c, SYSFS_BLOCK_NAME);
-		if ((lstat(sysfs_path, &astats)) != 0) {
-			dprintf("stat() failed\n");
-			goto out;
-		}
-		if (S_ISDIR(astats.st_mode)) {
+		*c = '\0';
+		safestrcpymax(c, SYSFS_BLOCK_NAME, 
+				sizeof(sysfs_path) - strlen(sysfs_path));
+		if ((sysfs_path_is_dir(sysfs_path)) == 0) {
 			subsys_name = (char *)calloc(1, SYSFS_NAME_LEN);
-			strcpy(subsys_name, SYSFS_BLOCK_NAME);
-			dlist_unshift(list, subsys_name);
+			safestrcpymax(subsys_name, SYSFS_BLOCK_NAME, 
+					SYSFS_NAME_LEN);
+			dlist_unshift_sorted(list, subsys_name, sort_char);
 		}
 	}
 out:
@@ -278,9 +356,9 @@
  * @name: name of the subsystem, eg., "pci", "scsi", "usb"
  * Returns a dlist of supported names or NULL if subsystem not supported
  */ 
-struct dlist *sysfs_open_bus_devices_list(unsigned char *name)
+struct dlist *sysfs_open_bus_devices_list(char *name)
 {
-	unsigned char sysfs_path[SYSFS_PATH_MAX], *device_name = NULL;
+	char sysfs_path[SYSFS_PATH_MAX], *device_name = NULL;
 	struct sysfs_directory *dir = NULL;
 	struct sysfs_link *cur = NULL;
 	struct dlist *list = NULL;
@@ -293,17 +371,19 @@
 		return NULL;
 	}
 
-	strcat(sysfs_path, SYSFS_BUS_DIR);
-	strcat(sysfs_path, "/");
-	strcat(sysfs_path, name);
-	strcat(sysfs_path, SYSFS_DEVICES_DIR);
+	safestrcat(sysfs_path, "/");
+	safestrcat(sysfs_path, SYSFS_BUS_NAME);
+	safestrcat(sysfs_path, "/");
+	safestrcat(sysfs_path, name);
+	safestrcat(sysfs_path, "/");
+	safestrcat(sysfs_path, SYSFS_DEVICES_NAME);
 	dir = sysfs_open_directory(sysfs_path);
 	if (dir == NULL) {
 		dprintf("Error opening sysfs_directory at %s\n", sysfs_path);
 		return NULL;
 	}
 
-	if (sysfs_read_directory(dir) != 0) {
+	if ((sysfs_read_dir_links(dir)) != 0) {
 		dprintf("Error reading sysfs_directory at %s\n", sysfs_path);
 		sysfs_close_directory(dir);
 		return NULL;
@@ -321,11 +401,79 @@
 		dlist_for_each_data(dir->links, cur,
 				struct sysfs_link) {
 			device_name = (char *)calloc(1, SYSFS_NAME_LEN);
-			strcpy(device_name, cur->name);
-			dlist_unshift(list, device_name);
+			safestrcpymax(device_name, cur->name, SYSFS_NAME_LEN);
+			dlist_unshift_sorted(list, device_name, sort_char);
 		}
 	}
 	sysfs_close_directory(dir);
 	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 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 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 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;
+}




More information about the hal-commit mailing list