chiark / gitweb /
[PATCH] libsysfs update for refresh + namedev.c changes
authorananthmg@rediffmail.com <ananthmg@rediffmail.com>
Thu, 15 Jan 2004 06:21:38 +0000 (22:21 -0800)
committerGreg KH <gregkh@suse.de>
Wed, 27 Apr 2005 04:13:16 +0000 (21:13 -0700)
Please find inlined a patch which contains updates to libsysfs
(pre-release) for refresh and also changes to namedev.c to take
advantage of it.

libsysfs/libsysfs.h
libsysfs/sysfs_bus.c
libsysfs/sysfs_class.c
libsysfs/sysfs_device.c
libsysfs/sysfs_dir.c
libsysfs/sysfs_driver.c
libsysfs/sysfs_utils.c
namedev.c

index 2ffe100..10faab9 100644 (file)
@@ -62,18 +62,20 @@ struct sysfs_link {
 };
 
 struct sysfs_directory {
+       unsigned char name[SYSFS_NAME_LEN];
+       unsigned char path[SYSFS_PATH_MAX];
+
+       /* Private: for internal use only */
        struct dlist *subdirs;  
        struct dlist *links;            
        struct dlist *attributes;
-       unsigned char name[SYSFS_NAME_LEN];
-       unsigned char path[SYSFS_PATH_MAX];
 };
 
 struct sysfs_driver {
        unsigned char name[SYSFS_NAME_LEN];
        unsigned char path[SYSFS_PATH_MAX];
 
-       /* for internal use only */
+       /* Private: for internal use only */
        struct dlist *devices;
        struct sysfs_directory *directory;      
 };
@@ -85,7 +87,7 @@ struct sysfs_device {
        unsigned char driver_name[SYSFS_NAME_LEN];
        unsigned char path[SYSFS_PATH_MAX];
 
-       /* for internal use only */
+       /* Private: for internal use only */
        struct sysfs_device *parent;            
        struct dlist *children; 
        struct sysfs_directory *directory;      
@@ -95,7 +97,7 @@ struct sysfs_root_device {
        unsigned char name[SYSFS_NAME_LEN];
        unsigned char path[SYSFS_PATH_MAX];
 
-       /* for internal use only */
+       /* Private: for internal use only */
        struct dlist *devices;
        struct sysfs_directory *directory;
 };
@@ -104,7 +106,7 @@ struct sysfs_bus {
        unsigned char name[SYSFS_NAME_LEN];
        unsigned char path[SYSFS_PATH_MAX];
 
-       /* internal use only */
+       /* Private: for internal use only */
        struct dlist *drivers;
        struct dlist *devices;
        struct sysfs_directory *directory;      
@@ -115,7 +117,7 @@ struct sysfs_class_device {
        unsigned char classname[SYSFS_NAME_LEN];
        unsigned char path[SYSFS_PATH_MAX];
 
-       /* for internal use only */
+       /* Private: for internal use only */
        struct sysfs_class_device *parent;      
        struct sysfs_device *sysdevice;         /* NULL if virtual */
        struct sysfs_driver *driver;            /* NULL if not implemented */
@@ -126,7 +128,7 @@ struct sysfs_class {
        unsigned char name[SYSFS_NAME_LEN];
        unsigned char path[SYSFS_PATH_MAX];
 
-       /* for internal use only */
+       /* Private: for internal use only */
        struct dlist *devices;
        struct sysfs_directory *directory;      
 };
@@ -138,8 +140,8 @@ extern "C" {
 /*
  * Function Prototypes
  */
-extern int sysfs_trailing_slash(unsigned char *path);
 extern int sysfs_get_mnt_path(unsigned char *mnt_path, size_t len);
+extern int sysfs_remove_trailing_slash(unsigned char *path);
 extern int sysfs_get_name_from_path(const unsigned char *path, 
                                        unsigned char *name, size_t len);
 extern int sysfs_path_is_dir(const unsigned char *path);
@@ -161,7 +163,9 @@ extern int sysfs_write_attribute(struct sysfs_attribute *sysattr,
                const unsigned char *new_value, size_t len);
 extern unsigned char *sysfs_get_value_from_attributes(struct dlist *attr, 
                                                const unsigned char * name);
-extern int sysfs_refresh_attributes(struct dlist *attrlist);
+extern int sysfs_refresh_dir_attributes(struct sysfs_directory *sysdir);
+extern int sysfs_refresh_dir_links(struct sysfs_directory *sysdir);
+extern int sysfs_refresh_dir_subdirs(struct sysfs_directory *sysdir);
 extern void sysfs_close_directory(struct sysfs_directory *sysdir);
 extern struct sysfs_directory *sysfs_open_directory(const unsigned char *path);
 extern int sysfs_read_dir_attributes(struct sysfs_directory *sysdir);
@@ -179,6 +183,9 @@ extern struct sysfs_link *sysfs_get_subdirectory_link
                        (struct sysfs_directory *dir, unsigned char *linkname);
 extern struct sysfs_attribute *sysfs_get_directory_attribute
                        (struct sysfs_directory *dir, unsigned char *attrname);
+extern struct dlist *sysfs_get_dir_attributes(struct sysfs_directory *dir);
+extern struct dlist *sysfs_get_dir_links(struct sysfs_directory *dir);
+extern struct dlist *sysfs_get_dir_subdirs(struct sysfs_directory *dir);
 
 /* sysfs driver access */
 extern void sysfs_close_driver(struct sysfs_driver *driver);
@@ -189,9 +196,12 @@ extern struct sysfs_attribute *sysfs_get_driver_attr
                (struct sysfs_driver *drv, const unsigned char *name);
 extern struct dlist *sysfs_get_driver_attributes(struct sysfs_driver *driver);
 extern struct dlist *sysfs_get_driver_devices(struct sysfs_driver *driver);
+extern struct dlist *sysfs_refresh_driver_devices(struct sysfs_driver *driver);
 extern struct dlist *sysfs_get_driver_links(struct sysfs_driver *driver);
 extern struct sysfs_device *sysfs_get_driver_device
        (struct sysfs_driver *driver, const unsigned char *name);
+extern struct dlist *sysfs_refresh_driver_attributes
+                       (struct sysfs_driver *driver);
 extern struct sysfs_attribute *sysfs_open_driver_attr(const unsigned char *bus, 
                const unsigned char *drv, const unsigned char *attrib);
 
@@ -205,9 +215,12 @@ extern struct sysfs_device *sysfs_open_device
                (const unsigned char *bus_id, const unsigned char *bus);
 extern struct sysfs_device *sysfs_get_device_parent(struct sysfs_device *dev);
 extern struct sysfs_device *sysfs_open_device_path(const unsigned char *path);
+extern int sysfs_get_device_bus(struct sysfs_device *dev);
 extern struct sysfs_attribute *sysfs_get_device_attr
                        (struct sysfs_device *dev, const unsigned char *name);
 extern struct dlist *sysfs_get_device_attributes(struct sysfs_device *device);
+extern struct dlist *sysfs_refresh_device_attributes
+                       (struct sysfs_device *device);
 extern struct sysfs_attribute *sysfs_open_device_attr(const unsigned char *bus, 
                const unsigned char *bus_id, const unsigned char *attrib);
 
@@ -221,6 +234,7 @@ extern struct sysfs_driver *sysfs_get_bus_driver(struct sysfs_bus *bus,
 extern struct dlist *sysfs_get_bus_drivers(struct sysfs_bus *bus);
 extern struct dlist *sysfs_get_bus_devices(struct sysfs_bus *bus);
 extern struct dlist *sysfs_get_bus_attributes(struct sysfs_bus *bus);
+extern struct dlist *sysfs_refresh_bus_attributes(struct sysfs_bus *bus);
 extern struct sysfs_attribute *sysfs_get_bus_attribute(struct sysfs_bus *bus,
                                                unsigned char *attrname);
 extern struct sysfs_device *sysfs_open_bus_device(unsigned char *busname, 
@@ -247,6 +261,8 @@ extern struct sysfs_class_device *sysfs_get_class_device
        (struct sysfs_class *class, unsigned char *name);
 extern struct dlist *sysfs_get_classdev_attributes
        (struct sysfs_class_device *cdev);
+extern struct dlist *sysfs_refresh_classdev_attributes
+       (struct sysfs_class_device *cdev);
 extern struct sysfs_attribute *sysfs_get_classdev_attr
        (struct sysfs_class_device *clsdev, const unsigned char *name);
 extern struct sysfs_attribute *sysfs_open_classdev_attr
index d9da0f8..aca3928 100644 (file)
@@ -209,9 +209,7 @@ struct sysfs_bus *sysfs_open_bus(const unsigned char *name)
                return NULL;
        }
 
-       if (sysfs_trailing_slash(buspath) == 0)
-               strcat(buspath, "/");
-
+       strcat(buspath, "/");
        strcat(buspath, SYSFS_BUS_NAME);
        strcat(buspath, "/");
        strcat(buspath, name);
@@ -226,6 +224,11 @@ struct sysfs_bus *sysfs_open_bus(const unsigned char *name)
        }
        strcpy(bus->name, name);        
        strcpy(bus->path, buspath);
+       if ((sysfs_remove_trailing_slash(bus->path)) != 0) {
+               dprintf("Incorrect path to bus %s\n", bus->path);
+               sysfs_close_bus(bus);
+               return NULL;
+       }
 
        return bus;
 }
@@ -296,21 +299,38 @@ struct dlist *sysfs_get_bus_attributes(struct sysfs_bus *bus)
        if (bus->directory->attributes == NULL) {
                if ((sysfs_read_dir_attributes(bus->directory)) != 0) 
                        return NULL;
-       } else {
-               if ((sysfs_path_is_dir(bus->path)) != 0) {
-                       dprintf("Bus at %s no longer exists\n", bus->path);
-                       return NULL;
-               }
-               if ((sysfs_refresh_attributes
-                                       (bus->directory->attributes)) != 0) {
-                       dprintf("Error refreshing bus attributes\n");
-                       return NULL;
-               }
        }
        return bus->directory->attributes;
 }
 
 /**
+ * sysfs_refresh_bus_attributes: refreshes the bus's list of attributes
+ * @bus: sysfs_bus whose attributes to refresh
+ * 
+ * NOTE: Upon return, prior references to sysfs_attributes for this bus
+ *             _may_ not be valid
+ * 
+ * Returns list of attributes on success and NULL on failure
+ */
+struct dlist *sysfs_refresh_bus_attributes(struct sysfs_bus *bus)
+{
+       if (bus == NULL) {
+               errno = EINVAL;
+               return NULL;
+       }
+
+       if (bus->directory == NULL)
+               return (sysfs_get_bus_attributes(bus));
+       
+       if ((sysfs_refresh_dir_attributes(bus->directory)) != 0) {
+               dprintf("Error refreshing bus attributes\n");
+               return NULL;
+       }
+
+       return (bus->directory->attributes);
+}
+
+/**
  * sysfs_get_bus_attribute: gets a specific bus attribute, if buses had
  *     attributes.
  * @bus: bus to retrieve attribute from
@@ -357,8 +377,7 @@ struct sysfs_device *sysfs_open_bus_device(unsigned char *busname,
                return NULL;
        }
 
-       if (sysfs_trailing_slash(path) == 0)
-               strcat(path, "/");
+       strcat(path, "/");
        strcat(path, SYSFS_BUS_NAME);
        strcat(path, "/");
        strcat(path, busname);
index 16eaf6e..cd86912 100644 (file)
@@ -160,6 +160,11 @@ struct sysfs_class_device *sysfs_open_class_device_path
        }
 
        strcpy(cdev->path, path);
+       if ((sysfs_remove_trailing_slash(cdev->path)) != 0) {
+               dprintf("Invalid path to class device %s\n", cdev->path);
+               sysfs_close_class_device(cdev);
+               return NULL;
+       }
        set_classdev_classname(cdev);
 
        return cdev;
@@ -179,6 +184,10 @@ struct dlist *sysfs_get_class_devices(struct sysfs_class *cls)
                errno = EINVAL;
                return NULL;
        }
+
+       if (cls->devices != NULL) 
+               return cls->devices;
+
        if (cls->directory == NULL) {
                cls->directory = sysfs_open_directory(cls->path);
                if (cls->directory == NULL) 
@@ -226,16 +235,16 @@ struct sysfs_class *sysfs_open_class(const unsigned char *name)
                 dprintf("Sysfs not supported on this system\n");
                 return NULL;
         }
-       if (sysfs_trailing_slash(classpath) == 0)
-               strcat(classpath, "/");
 
        /* 
         * We shall now treat "block" also as a class. Hence, check here
         * if "name" is "block" and proceed accordingly
         */
        if (strcmp(name, SYSFS_BLOCK_NAME) == 0) {
+               strcat(classpath, "/");
                strcat(classpath, SYSFS_BLOCK_NAME);
        } else {
+               strcat(classpath, "/");
                strcat(classpath, SYSFS_CLASS_NAME);
                strcat(classpath, "/");
                strcat(classpath, name);
@@ -252,6 +261,11 @@ struct sysfs_class *sysfs_open_class(const unsigned char *name)
        }
        strcpy(cls->name, name);        
        strcpy(cls->path, classpath);
+       if ((sysfs_remove_trailing_slash(cls->path)) != 0) {
+               dprintf("Invalid path to class device %s\n", cls->path);
+               sysfs_close_class(cls);
+               return NULL;
+       }
        
        return cls;
 }
@@ -264,8 +278,6 @@ struct sysfs_class *sysfs_open_class(const unsigned char *name)
 struct sysfs_class_device *sysfs_get_class_device(struct sysfs_class *class,
                                        unsigned char *name)
 {
-       struct dlist *devlist = NULL;
-       
        if (class == NULL || name == NULL) {
                errno = EINVAL;
                return NULL;
@@ -273,7 +285,7 @@ struct sysfs_class_device *sysfs_get_class_device(struct sysfs_class *class,
 
        if (class->devices == NULL) {
                class->devices = sysfs_get_class_devices(class);
-               if (devlist == NULL) 
+               if (class->devices == NULL) 
                        return NULL;
        }
        return (struct sysfs_class_device *)dlist_find_custom(class->devices,
@@ -291,14 +303,21 @@ struct sysfs_device *sysfs_get_classdev_device
                        (struct sysfs_class_device *clsdev)
 {
        struct sysfs_link *devlink = NULL;
+       unsigned char devpath[SYSFS_PATH_MAX];
        
        if (clsdev == NULL) {
                errno = EINVAL;
                return NULL;
        }
-       
-       if (clsdev->sysdevice != NULL)
-               return (clsdev->sysdevice);
+       strcpy(devpath, clsdev->path);
+       strcat(devpath, "/device");
+       if ((sysfs_path_is_link(devpath)) != 0) {
+               if (clsdev->sysdevice != NULL) {
+                       sysfs_close_device(clsdev->sysdevice);
+                       clsdev->sysdevice = NULL;
+               }
+               return NULL;
+       }
        
        if (clsdev->directory == NULL) {
                clsdev->directory = sysfs_open_directory(clsdev->path);
@@ -306,8 +325,24 @@ struct sysfs_device *sysfs_get_classdev_device
                        return NULL;
        }
        devlink = sysfs_get_directory_link(clsdev->directory, "device");
-       if (devlink == NULL) 
+       if (devlink == NULL) {
+               if (clsdev->sysdevice != NULL) {
+                       dprintf("Device link no longer exists\n");
+                       sysfs_close_device(clsdev->sysdevice);
+                       clsdev->sysdevice = NULL;
+               }
                return NULL;
+       }
+
+       if (clsdev->sysdevice != NULL) {
+               if (!strncmp(devlink->target, clsdev->sysdevice->path,
+                                               SYSFS_PATH_MAX)) 
+                       /* sysdevice hasn't changed */
+                       return (clsdev->sysdevice);
+               else 
+                       /* come here only if the device link for has changed */
+                       sysfs_close_device(clsdev->sysdevice);
+       }
 
        clsdev->sysdevice = sysfs_open_device_path(devlink->target);
        if (clsdev->sysdevice == NULL)
@@ -329,31 +364,56 @@ struct sysfs_driver *sysfs_get_classdev_driver
                        (struct sysfs_class_device *clsdev)
 {
        struct sysfs_link *drvlink = NULL;
+       unsigned char drvpath[SYSFS_PATH_MAX];
        
        if (clsdev == NULL) {
                errno = EINVAL;
                return NULL;
        }
-       
-       if (clsdev->driver != NULL)
-               return (clsdev->driver);
-       
+       strcpy(drvpath, clsdev->path);
+        strcat(drvpath, "/driver");
+       if ((sysfs_path_is_link(drvpath)) != 0) {
+               if (clsdev->driver != NULL) {
+                       sysfs_close_driver(clsdev->driver);
+                       clsdev->driver = NULL;
+               }
+               return NULL;
+       }
+        
        if (clsdev->directory == NULL) {
                clsdev->directory = sysfs_open_directory(clsdev->path);
                if (clsdev->directory == NULL)
                        return NULL;
        }
        drvlink = sysfs_get_directory_link(clsdev->directory, "driver");
-       if (drvlink != NULL) {
-               clsdev->driver = sysfs_open_driver_path(drvlink->target);
-               if (clsdev->driver == NULL)
-                       return NULL;
-                       
+       if (drvlink == NULL) {
+               if (clsdev->driver != NULL) {
+                       dprintf("Driver link no longer exists\n");
+                       sysfs_close_driver(clsdev->driver);
+                       clsdev->driver = NULL;
+               }
+               return NULL;
+       }
+       if (clsdev->driver != NULL) {
+               if (!strncmp(drvlink->target, clsdev->driver->path,
+                                                       SYSFS_PATH_MAX))
+                       /* driver hasn't changed */
+                       return (clsdev->driver);
+               else
+                       /* come here only if the device link for has changed */
+                       sysfs_close_driver(clsdev->driver);
        }
+               
+       clsdev->driver = sysfs_open_driver_path(drvlink->target);
+       if (clsdev->driver == NULL)
+               return NULL;
+       if (clsdev->sysdevice != NULL)
+               strcpy(clsdev->sysdevice->driver_name, clsdev->driver->name);
+
        return (clsdev->driver);
 }
-       
-/* 
+
+/** 
  * get_blockdev_parent: Get the parent class device for a "block" subsystem 
  *             device if present
  * @clsdev: block subsystem class device whose parent needs to be found
@@ -361,48 +421,34 @@ struct sysfs_driver *sysfs_get_classdev_driver
  */
 static int get_blockdev_parent(struct sysfs_class_device *clsdev)
 {
-       unsigned char parent_path[SYSFS_PATH_MAX], value[256], *c = NULL;
-       
-       memset(parent_path, 0, SYSFS_PATH_MAX);
-       strcpy(parent_path, clsdev->path);
+       unsigned char parent_path[SYSFS_PATH_MAX], *c = NULL;
 
+       strcpy(parent_path, clsdev->path);
        c = strstr(parent_path, SYSFS_BLOCK_NAME);
        if (c == NULL) {
-               dprintf("Class device %s does not belong to BLOCK subsystem",
+               dprintf("Class device %s does not belong to BLOCK subsystem\n",
                                clsdev->name);
                return 1;
        }
-       
+
        c += strlen(SYSFS_BLOCK_NAME);
        if (*c == '/')
                c++;
        else
                goto errout;
-       
-       /* validate whether the given class device is a partition or not */ 
-       if ((strncmp(c, clsdev->name, strlen(clsdev->name))) == 0) {
-               dprintf("%s not a partition\n", clsdev->name);
-               return 1;
-       }
-       c = strchr(c, '/');
-       if (c == NULL) 
-               goto errout;
-       *c = '\0';
-       
-       /* Now validate if the parent has the "dev" attribute */
-       memset(value, 0, 256);
-       strcat(parent_path, "/dev");
-       if ((sysfs_read_attribute_value(parent_path, value, 256)) != 0) {
-               dprintf("Block device %s does not have a parent\n", 
-                                                       clsdev->name);
-               return 1;
-       }
-               
-       c = strrchr(parent_path, '/');
+
+       /* validate whether the given class device is a partition or not */
+        if ((strncmp(c, clsdev->name, strlen(clsdev->name))) == 0) {
+                dprintf("%s not a partition\n", clsdev->name);
+                return 1;
+        }
+                     
+       c = strchr(c, '/');
        if (c == NULL)
                goto errout;
 
        *c = '\0';
+                                       
        clsdev->parent = sysfs_open_class_device_path(parent_path);
        if (clsdev->parent == NULL) {
                dprintf("Error opening the parent class device at %s\n", 
@@ -467,13 +513,11 @@ static int get_classdev_path(const unsigned char *classname,
                 dprintf("Error getting sysfs mount path\n");
                 return -1;
        }
-
-       if (sysfs_trailing_slash(path) == 0)
-               strcat(path, "/");
-
        if (strcmp(classname, SYSFS_BLOCK_NAME) == 0) {
+               strcat(path, "/");
                strcat(path, SYSFS_BLOCK_NAME);
        } else {
+               strcat(path, "/");
                strcat(path, SYSFS_CLASS_NAME);
                strcat(path, "/");
                strcat(path, classname);
@@ -537,27 +581,41 @@ struct dlist *sysfs_get_classdev_attributes(struct sysfs_class_device *cdev)
                        return NULL;
        }
        if (cdev->directory->attributes == NULL) {
-               if ((sysfs_read_dir_attributes(cdev->directory)) != 0) {
-                       dprintf("Error reading attributes for directory %s\n",
-                                                       cdev->directory->path);
-                       return NULL;
-               }
-       } else {
-               if ((sysfs_path_is_dir(cdev->path)) != 0) {
-                       dprintf("Class device at %s no longer exists\n", 
-                                                       cdev->path);
-                       return NULL;
-               }
-               if ((sysfs_refresh_attributes
-                                       (cdev->directory->attributes)) != 0) {
-                       dprintf("Error refreshing classdev attributes\n");
+               if ((sysfs_read_dir_attributes(cdev->directory)) != 0) 
                        return NULL;
-               }
        }
        return (cdev->directory->attributes);
 }
 
 /**
+ * sysfs_refresh_clsassdev_attributes: refreshes the driver's list of attributes
+ * @clsdev: sysfs_class_device whose attributes to refresh
+ *
+ * NOTE: Upon return, prior references to sysfs_attributes for this classdev
+ *              _may_ not be valid
+ *
+ * Returns list of attributes on success and NULL on failure
+ */
+struct dlist *sysfs_refresh_classdev_attributes
+                       (struct sysfs_class_device *clsdev)
+{
+       if (clsdev == NULL) {
+               errno = EINVAL;
+               return NULL;
+       }
+
+       if (clsdev->directory == NULL)
+               return (sysfs_get_classdev_attributes(clsdev));
+
+       if ((sysfs_refresh_dir_attributes(clsdev->directory)) != 0) {
+               dprintf("Error refreshing class_device attributes\n");
+               return NULL;
+       }
+
+       return (clsdev->directory->attributes);
+}
+
+/**
  * sysfs_get_classdev_attr: searches class device's attributes by name
  * @clsdev: class device to look through
  * @name: attribute name to get
@@ -597,15 +655,10 @@ struct sysfs_attribute *sysfs_get_classdev_attr
                                                struct sysfs_directory) {
                        if ((sysfs_path_is_dir(sdir->path)) != 0) 
                                continue;
-                       if (sdir->attributes == NULL) {
-                               cur = sysfs_get_directory_attribute(sdir,
-                                                       (unsigned char *)name);
-                       } else {
-                               if ((sysfs_refresh_attributes
-                                               (sdir->attributes)) == 0)
-                               cur = sysfs_get_directory_attribute(sdir, 
+                       cur = sysfs_get_directory_attribute(sdir,
                                                        (unsigned char *)name);
-                       }
+                       if (cur == NULL)
+                               continue;
                }
        }
        return cur;
index 66d5f9a..bfd761b 100644 (file)
 #include "sysfs.h"
 
 /**
- * get_device_bus: retrieves the bus name the device is on, checks path to
- *     bus' link to make sure it has correct device.
+ * sysfs_get_device_bus: retrieves the bus name the device is on, checks path 
+ *     to bus' link to make sure it has correct device.
  * @dev: device to get busname.
  * returns 0 with success and -1 with error.
  */
-static int get_device_bus(struct sysfs_device *dev)
+int sysfs_get_device_bus(struct sysfs_device *dev)
 {
        unsigned char subsys[SYSFS_NAME_LEN], path[SYSFS_PATH_MAX];
        unsigned char target[SYSFS_PATH_MAX], *bus = NULL, *c = NULL;
@@ -197,6 +197,11 @@ struct sysfs_device *sysfs_open_device_path(const unsigned char *path)
                return NULL;
        }
        strcpy(dev->path, path);
+       if ((sysfs_remove_trailing_slash(dev->path)) != 0) {
+               dprintf("Invalid path to device %s\n", dev->path);
+               sysfs_close_device(dev);
+               return NULL;
+       }
        /* 
         * The "name" attribute no longer exists... return the device's
         * sysfs representation instead, in the "dev->name" field, which
@@ -204,8 +209,8 @@ struct sysfs_device *sysfs_open_device_path(const unsigned char *path)
         */
        strncpy(dev->name, dev->bus_id, SYSFS_NAME_LEN);
        
-       if (get_device_bus(dev) != 0)
-               strcpy(dev->bus, SYSFS_UNKNOWN);
+       if (sysfs_get_device_bus(dev) != 0)
+               dprintf("Could not get device bus\n");
 
        return dev;
 }
@@ -334,8 +339,7 @@ struct sysfs_root_device *sysfs_open_root_device(const unsigned char *name)
                return NULL;
        }
 
-       if (sysfs_trailing_slash(rootpath) == 0)
-               strcat(rootpath, "/");
+       strcat(rootpath, "/");
        strcat(rootpath, SYSFS_DEVICES_NAME);
        strcat(rootpath, "/");
        strcat(rootpath, name);
@@ -352,6 +356,11 @@ struct sysfs_root_device *sysfs_open_root_device(const unsigned char *name)
        }
        strcpy(root->name, name);
        strcpy(root->path, rootpath);
+       if ((sysfs_remove_trailing_slash(root->path)) != 0) {
+               dprintf("Invalid path to root device %s\n", root->path);
+               sysfs_close_root_device(root);
+               return NULL;
+       }
        return root;
 }
 
@@ -373,21 +382,38 @@ struct dlist *sysfs_get_device_attributes(struct sysfs_device *device)
        if (device->directory->attributes == NULL) {
                if ((sysfs_read_dir_attributes(device->directory)) != 0)
                        return NULL;
-       } else {
-               if ((sysfs_path_is_dir(device->path)) != 0) {
-                       dprintf("Device at %s no longer exists", device->path);
-                       return NULL;
-               }
-               if ((sysfs_refresh_attributes
-                               (device->directory->attributes)) != 0) {
-                       dprintf("Error refreshing device attributes\n");
-                       return NULL;
-               }
        }
        return (device->directory->attributes);
 }
 
 /**
+ * sysfs_refresh_device_attributes: refreshes the device's list of attributes
+ * @device: sysfs_device whose attributes to refresh
+ *  
+ * NOTE: Upon return, prior references to sysfs_attributes for this device
+ *             _may_ not be valid
+ *
+ * Returns list of attributes on success and NULL on failure
+ */
+struct dlist *sysfs_refresh_device_attributes(struct sysfs_device *device)
+{
+       if (device == NULL) {
+               errno = EINVAL;
+               return NULL;
+       }
+
+       if (device->directory == NULL)
+               return (sysfs_get_device_attributes(device));
+
+       if ((sysfs_refresh_dir_attributes(device->directory)) != 0) {
+               dprintf("Error refreshing device attributes\n");
+               return NULL;
+       }
+
+       return (device->directory->attributes);
+}
+
+/**
  * sysfs_get_device_attr: searches dev's attributes by name
  * @dev: device to look through
  * @name: attribute name to get
@@ -396,22 +422,19 @@ struct dlist *sysfs_get_device_attributes(struct sysfs_device *device)
 struct sysfs_attribute *sysfs_get_device_attr(struct sysfs_device *dev,
                                                const unsigned char *name)
 {
-       struct sysfs_attribute *cur = NULL;
        struct dlist *attrlist = NULL;
 
        if (dev == NULL || name == NULL) {
                errno = EINVAL;
                return NULL;
        }
-
+       
        attrlist = sysfs_get_device_attributes(dev);
        if (attrlist == NULL)
                return NULL;
 
-       cur = sysfs_get_directory_attribute(dev->directory, 
-                       (unsigned char *)name);
-
-       return cur;
+       return sysfs_get_directory_attribute(dev->directory, 
+                                       (unsigned char *)name);
 }
 
 /**
@@ -437,8 +460,7 @@ static int get_device_absolute_path(const unsigned char *device,
                dprintf ("Sysfs not supported on this system\n");
                return -1;
        }
-       if (sysfs_trailing_slash(bus_path) == 0)
-               strcat(bus_path, "/");
+       strcat(bus_path, "/");
        strcat(bus_path, SYSFS_BUS_NAME);
        strcat(bus_path, "/");
        strcat(bus_path, bus);
index c159db7..a60410e 100644 (file)
@@ -195,7 +195,7 @@ int sysfs_write_attribute(struct sysfs_attribute *sysattr,
                        return -1;
                }
                if ((strncmp(sysattr->value, new_value, sysattr->len)) == 0) {
-                       dprintf("Attribute %s already has the requested value %s\n",
+                       dprintf("Attr %s already has the requested value %s\n",
                                        sysattr->name, new_value);
                        return 0;       
                }
@@ -274,7 +274,7 @@ int sysfs_read_attribute(struct sysfs_attribute *sysattr)
                return -1;
        }
 #ifdef __KLIBC__
-       pgsize = 0x1000;                
+       pgsize = 0x1000;
 #else
        pgsize = sysconf(_SC_PAGESIZE);
 #endif
@@ -468,6 +468,13 @@ struct sysfs_directory *sysfs_open_directory(const unsigned char *path)
                errno = EINVAL;
                return NULL;
        }
+
+       if (sysfs_path_is_dir(path) != 0) {
+               dprintf("Invalid path directory %s\n", path);
+               errno = EINVAL;
+               return NULL;
+       }
+
        sdir = alloc_directory();
        if (sdir == NULL) {
                dprintf("Error allocating directory %s\n", path);
@@ -514,39 +521,6 @@ struct sysfs_link *sysfs_open_link(const unsigned char *linkpath)
 }
 
 /**
- * sysfs_refresh_attributes: Refresh attributes list
- * @attrlist: list of attributes to refresh
- * Returns 0 on success, 1 on failure
- */
-int sysfs_refresh_attributes(struct dlist *attrlist)
-{
-       struct sysfs_attribute *attr = NULL;
-
-       if (attrlist == NULL) {
-               errno = EINVAL;
-               return 1;
-       }
-       dlist_for_each_data(attrlist, attr, struct sysfs_attribute) {
-               if (attr->method & SYSFS_METHOD_SHOW) {
-                       if ((sysfs_read_attribute(attr)) != 0) {
-                               dprintf("Error reading attribute %s\n", 
-                                                               attr->path);
-                               if ((sysfs_path_is_file(attr->path)) != 0) {
-                                       dprintf("Attr %s no longer exists\n", 
-                                                               attr->name);
-                               }
-                       }
-               } else {
-                       if ((sysfs_path_is_file(attr->path)) != 0) {
-                               dprintf("Attr %s no longer exists\n", 
-                                                               attr->name);
-                       }
-               }
-       }
-       return 0;
-}
-
-/**
  * add_attribute: open and add attribute at path to given directory
  * @sysdir: directory to add attribute to
  * @path: path to attribute
@@ -633,7 +607,6 @@ int sysfs_read_dir_attributes(struct sysfs_directory *sysdir)
 {
        DIR *dir = NULL;
        struct dirent *dirent = NULL;
-       struct stat astats;
        unsigned char file_path[SYSFS_PATH_MAX];
        int retval = 0;
 
@@ -655,11 +628,7 @@ int sysfs_read_dir_attributes(struct sysfs_directory *sysdir)
                strncpy(file_path, sysdir->path, SYSFS_PATH_MAX);
                strcat(file_path, "/");
                strcat(file_path, dirent->d_name);
-               if ((lstat(file_path, &astats)) != 0) {
-                       dprintf("stat failed\n");
-                       continue;
-               }
-               if (S_ISREG(astats.st_mode)) 
+               if ((sysfs_path_is_file(file_path)) == 0)
                        retval = add_attribute(sysdir, file_path);
        }
        closedir(dir);
@@ -675,7 +644,6 @@ int sysfs_read_dir_links(struct sysfs_directory *sysdir)
 {
        DIR *dir = NULL;
        struct dirent *dirent = NULL;
-       struct stat astats;
        unsigned char file_path[SYSFS_PATH_MAX];
        int retval = 0;
 
@@ -697,11 +665,7 @@ int sysfs_read_dir_links(struct sysfs_directory *sysdir)
                strncpy(file_path, sysdir->path, SYSFS_PATH_MAX);
                strcat(file_path, "/");
                strcat(file_path, dirent->d_name);
-               if ((lstat(file_path, &astats)) != 0) {
-                       dprintf("stat failed\n");
-                       continue;
-               }
-               if (S_ISLNK(astats.st_mode)) {
+               if ((sysfs_path_is_link(file_path)) == 0) {
                        retval = add_link(sysdir, file_path);
                        if (retval != 0)
                                break;
@@ -720,7 +684,6 @@ int sysfs_read_dir_subdirs(struct sysfs_directory *sysdir)
 {
        DIR *dir = NULL;
        struct dirent *dirent = NULL;
-       struct stat astats;
        unsigned char file_path[SYSFS_PATH_MAX];
        int retval = 0;
 
@@ -742,11 +705,7 @@ int sysfs_read_dir_subdirs(struct sysfs_directory *sysdir)
                strncpy(file_path, sysdir->path, SYSFS_PATH_MAX);
                strcat(file_path, "/");
                strcat(file_path, dirent->d_name);
-               if ((lstat(file_path, &astats)) != 0) {
-                       dprintf("stat failed\n");
-                       continue;
-               }
-               if (S_ISDIR(astats.st_mode))
+               if ((sysfs_path_is_dir(file_path)) == 0)
                        retval = add_subdirectory(sysdir, file_path);
        }
        closedir(dir);
@@ -802,6 +761,90 @@ int sysfs_read_directory(struct sysfs_directory *sysdir)
 }
 
 /**
+ * sysfs_refresh_dir_attributes: Refresh attributes list
+ * @sysdir: directory whose list of attributes to refresh
+ * Returns 0 on success, 1 on failure
+ */
+int sysfs_refresh_dir_attributes(struct sysfs_directory *sysdir)
+{
+       if (sysdir == NULL) {
+               errno = EINVAL;
+               return 1;
+       }
+       if ((sysfs_path_is_dir(sysdir->path)) != 0) {
+               dprintf("Invalid path to directory %s\n", sysdir->path);
+               errno = EINVAL;
+               return 1;
+       }
+       if (sysdir->attributes != NULL) {
+               dlist_destroy(sysdir->attributes);
+               sysdir->attributes = NULL;
+       }
+       if ((sysfs_read_dir_attributes(sysdir)) != 0) {
+               dprintf("Error refreshing attributes for directory %s\n", 
+                                                       sysdir->path);
+               return 1;
+       }
+       return 0;
+}
+
+/**
+ * sysfs_refresh_dir_links: Refresh links list
+ * @sysdir: directory whose list of links to refresh
+ * Returns 0 on success, 1 on failure
+ */
+int sysfs_refresh_dir_links(struct sysfs_directory *sysdir)
+{
+       if (sysdir == NULL) {
+               errno = EINVAL;
+               return 1;
+       }
+       if ((sysfs_path_is_dir(sysdir->path)) != 0) {
+               dprintf("Invalid path to directory %s\n", sysdir->path);
+               errno = EINVAL;
+               return 1;
+       }
+       if (sysdir->links != NULL) {
+               dlist_destroy(sysdir->links);
+               sysdir->links = NULL;
+       }
+       if ((sysfs_read_dir_links(sysdir)) != 0) {
+               dprintf("Error refreshing links for directory %s\n", 
+                                                       sysdir->path);
+               return 1;
+       }
+       return 0;
+}
+
+/**
+ * sysfs_refresh_dir_subdirs: Refresh subdirs list
+ * @sysdir: directory whose list of subdirs to refresh
+ * Returns 0 on success, 1 on failure
+ */
+int sysfs_refresh_dir_subdirs(struct sysfs_directory *sysdir)
+{
+       if (sysdir == NULL) {
+               errno = EINVAL;
+               return 1;
+       }
+       if ((sysfs_path_is_dir(sysdir->path)) != 0) {
+               dprintf("Invalid path to directory %s\n", sysdir->path);
+               errno = EINVAL;
+               return 1;
+       }
+       if (sysdir->subdirs != NULL) {
+               dlist_destroy(sysdir->subdirs);
+               sysdir->subdirs = NULL;
+       }
+       if ((sysfs_read_dir_subdirs(sysdir)) != 0) {
+               dprintf("Error refreshing subdirs for directory %s\n", 
+                                                       sysdir->path);
+               return 1;
+       }
+       return 0;
+}
+
+/**
  * sysfs_get_directory_attribute: retrieves attribute attrname from current
  *     directory only
  * @dir: directory to retrieve attribute from
@@ -826,19 +869,25 @@ struct sysfs_attribute *sysfs_get_directory_attribute
 
        attr = (struct sysfs_attribute *)dlist_find_custom
                        (dir->attributes, attrname, dir_attribute_name_equal);
-       if (attr == NULL) {
+       if (attr != NULL) {
+               if ((sysfs_read_attribute(attr)) != 0) {
+                       dprintf("Error reading attribute %s\n", attr->name);
+                       return NULL;
+               }
+       } else {
                memset(new_path, 0, SYSFS_PATH_MAX);
                strcpy(new_path, dir->path);
                strcat(new_path, "/");
                strcat(new_path, attrname);
                if ((sysfs_path_is_file(new_path)) == 0) {
-                       if ((add_attribute(dir, new_path)) == 0) {
+                       if ((add_attribute(dir, new_path)) == 0) {
                                attr = (struct sysfs_attribute *)
-                                       dlist_find_custom(dir->attributes, 
+                                       dlist_find_custom(dir->attributes,
                                        attrname, dir_attribute_name_equal);
                        }
                }
        }
+               
        return attr;
 }
 
@@ -855,9 +904,13 @@ struct sysfs_link *sysfs_get_directory_link
                errno = EINVAL;
                return NULL;
        }
-       if (dir->links == NULL)
+       if (dir->links == NULL) {
                if ((sysfs_read_dir_links(dir) != 0) || (dir->links == NULL))
                        return NULL;
+       } else {
+               if ((sysfs_refresh_dir_links(dir)) != 0) 
+                       return NULL;
+       }
 
        return (struct sysfs_link *)dlist_find_custom(dir->links,
                linkname, dir_link_name_equal);
@@ -940,3 +993,63 @@ struct sysfs_link *sysfs_get_subdirectory_link(struct sysfs_directory *dir,
        }
        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 695ca79..a4440cf 100644 (file)
@@ -103,6 +103,11 @@ struct sysfs_driver *sysfs_open_driver_path(const unsigned char *path)
                return NULL;
        }
        strcpy(driver->path, path);
+       if ((sysfs_remove_trailing_slash(driver->path)) != 0) {
+               dprintf("Invalid path to driver %s\n", driver->path);
+               sysfs_close_driver(driver);
+               return NULL;
+       }
        
        return driver;
 }
@@ -125,26 +130,38 @@ struct dlist *sysfs_get_driver_attributes(struct sysfs_driver *driver)
                        return NULL;
        }
        if (driver->directory->attributes == NULL) {
-               if ((sysfs_read_dir_attributes(driver->directory)) != 0) {
-                       dprintf("Error reading driver attributes\n");
-                       return NULL;
-               }
-       } else {
-               if ((sysfs_path_is_dir(driver->path)) != 0) {
-                       dprintf("Driver at %s no longer exists\n", 
-                                                       driver->path);
-                       return NULL;
-               }
-               if ((sysfs_refresh_attributes
-                               (driver->directory->attributes)) != 0) {
-                       dprintf("Error refreshing driver attributes\n");
+               if ((sysfs_read_dir_attributes(driver->directory)) != 0) 
                        return NULL;
-               }
        }
        return(driver->directory->attributes);
 }
 
 /**
+ * sysfs_refresh_driver_attributes: refreshes the driver's list of attributes
+ * @driver: sysfs_driver whose attributes to refresh
+ *
+ * NOTE: Upon return, prior references to sysfs_attributes for this driver
+ *             _may_ not be valid
+ *             
+ * Returns list of attributes on success and NULL on failure
+ */
+struct dlist *sysfs_refresh_driver_attributes(struct sysfs_driver *driver)
+{
+       if (driver == NULL) {
+               errno = EINVAL;
+               return NULL;
+       }
+       if (driver->directory == NULL)
+               return (sysfs_get_driver_attributes(driver));
+       
+       if ((sysfs_refresh_dir_attributes(driver->directory)) != 0) {
+               dprintf("Error refreshing driver attributes\n");
+               return NULL;
+       }
+       return (driver->directory->attributes);
+}
+
+/**
  * sysfs_get_driver_attr: searches driver's attributes by name
  * @drv: driver to look through
  * @name: attribute name to get
@@ -153,7 +170,6 @@ struct dlist *sysfs_get_driver_attributes(struct sysfs_driver *driver)
 struct sysfs_attribute *sysfs_get_driver_attr(struct sysfs_driver *drv,
                                        const unsigned char *name)
 {
-       struct sysfs_attribute *cur = NULL;
        struct dlist *attrlist = NULL;
 
         if (drv == NULL) {
@@ -163,9 +179,10 @@ struct sysfs_attribute *sysfs_get_driver_attr(struct sysfs_driver *drv,
        
        attrlist = sysfs_get_driver_attributes(drv);
        if (attrlist != NULL) 
-               cur = sysfs_get_directory_attribute(drv->directory,
+               return NULL;
+
+       return sysfs_get_directory_attribute(drv->directory,
                                                (unsigned char *)name);
-        return cur;
 }
 
 /**
@@ -234,6 +251,38 @@ struct dlist *sysfs_get_driver_devices(struct sysfs_driver *driver)
 }
 
 /**
+ * sysfs_refresh_driver_devices: Refreshes drivers list of devices
+ * @driver: sysfs_driver whose devices list needs to be refreshed
+ *
+ * NOTE: Upon return from this function, prior sysfs_device references from
+ *             this driver's list of devices _may_ not be valid
+ *             
+ * Returns dlist of devices on success and NULL on failure
+ */
+struct dlist *sysfs_refresh_driver_devices(struct sysfs_driver *driver)
+{
+       if (driver == NULL) {
+               errno = EINVAL;
+               return NULL;
+       }
+       
+       if (driver->devices != NULL) {
+               dlist_destroy(driver->devices);
+               driver->devices = NULL;
+       }
+       
+       if (driver->directory == NULL)
+               return (sysfs_get_driver_devices(driver));
+
+       if ((sysfs_refresh_dir_links(driver->directory)) != 0) {
+               dprintf("Error refreshing driver links\n");
+               return NULL;
+       }
+       
+       return (sysfs_get_driver_devices(driver));
+}
+
+/**
  * sysfs_get_driver_device: looks up a device from a list of driver's devices
  *     and returns its sysfs_device corresponding to it
  * @driver: sysfs_driver on which to search
@@ -285,8 +334,7 @@ static int get_driver_path(const unsigned char *bus,
                dprintf("Error getting sysfs mount path\n");
                return -1;
        }
-       if (sysfs_trailing_slash(path) == 0)
-               strcat(path, "/");
+       strcat(path, "/");
        strcat(path, SYSFS_BUS_NAME);
        strcat(path, "/");
        strcat(path, bus);
index 009ae94..f1f8236 100644 (file)
 #endif
 
 /**
+ * sysfs_remove_trailing_slash: Removes any trailing '/' in the given path
+ * @path: Path to look for the trailing '/'
+ * Returns 0 on success 1 on error
+ */ 
+int sysfs_remove_trailing_slash(unsigned char *path)
+{
+       unsigned char *c = NULL;
+
+       if (path == NULL) {
+               errno = EINVAL;
+               return 1;
+       }
+       c = strrchr(path, '/');
+       if (c == NULL) {
+               dprintf("Invalid path %s\n", path);
+               errno = EINVAL;
+               return 1;
+       }
+       if (*(c+1) == '\0') 
+               *c = '\0';
+       return 0;
+}
+
+/**
  * sysfs_get_mnt_path: Gets the mount point for specified filesystem.
  * @fs_type: filesystem type to retrieve mount point
  * @mnt_path: place to put the retrieved mount path
@@ -72,28 +96,14 @@ static int sysfs_get_fs_mnt_path(const unsigned char *fs_type,
                errno = EINVAL;
                ret = -1;
        }
+       if ((sysfs_remove_trailing_slash(mnt_path)) != 0)
+               ret = -1;
+       
        return ret;
 #endif
 }
 
 /*
- * sysfs_trailing_slash: checks if there's a trailing slash to path
- * @path: path to check
- * returns 1 if true and 0 if not
- */
-int sysfs_trailing_slash(unsigned char *path)
-{
-       unsigned char *s = NULL;
-
-       if (path == NULL)
-               return 0;
-       s = &path[strlen(path)-1];
-       if (strncmp(s, "/", 1) == 0)
-               return 1;
-       return 0;
-}
-
-/*
  * sysfs_get_mnt_path: Gets the sysfs mount point.
  * @mnt_path: place to put "sysfs" mount point
  * @len: size of mnt_path
@@ -109,9 +119,11 @@ int sysfs_get_mnt_path(unsigned char *mnt_path, size_t len)
                return -1;
        }
        sysfs_path = getenv(SYSFS_PATH_ENV);
-       if (sysfs_path != NULL) 
+       if (sysfs_path != NULL) {
                strncpy(mnt_path, sysfs_path, len);
-       else
+               if ((sysfs_remove_trailing_slash(mnt_path)) != 0)
+                       return 1;
+       } else
                ret = sysfs_get_fs_mnt_path(SYSFS_FSTYPE_NAME, mnt_path, len);
 
        return ret;
@@ -152,7 +164,7 @@ int sysfs_get_name_from_path(const unsigned char *path, unsigned char *name,
        strncpy(name, n, len);
        return 0;
 }
-
+       
 /**
  * sysfs_get_link: returns link source
  * @path: symbolic link's path
@@ -178,32 +190,69 @@ int sysfs_get_link(const unsigned char *path, unsigned char *target, size_t len)
        if ((readlink(path, linkpath, SYSFS_PATH_MAX)) < 0) {
                return -1;
        }
-                                                                               
        d = linkpath;
-
-       /* getting rid of leading "../.." */    
-       while (*d == '/' || *d == '.') {
-               if (*d == '/')
-                       slashes++;
-               d++;
-       }
-
-       d--;
-
-       s = &devdir[strlen(devdir)-1];
-       while (s != NULL && count != (slashes+1)) {
-               s--;
-               if (*s == '/')
-                       count++;
+       /* 
+        * Three cases here:
+        * 1. relative path => format ../..
+        * 2. absolute path => format /abcd/efgh
+        * 3. relative path _from_ this dir => format abcd/efgh
+        */ 
+       switch (*d) {
+               case '.': 
+                       /* 
+                        * handle the case where link is of type ./abcd/xxx
+                        */
+                       strncpy(target, devdir, len);
+                       if (*(d+1) == '/')
+                               d += 2;
+                       else if (*(d+1) == '.')
+                               goto parse_path;
+                       s = strrchr(target, '/');
+                       if (s != NULL) {
+                               *(s+1) = '\0';
+                               strcat(target, d);
+                       } else {
+                               strcpy(target, d);
+                       }
+                       break;
+                       /* 
+                        * relative path  
+                        * getting rid of leading "../.." 
+                        */
+parse_path:
+                       while (*d == '/' || *d == '.') {
+                               if (*d == '/')
+                                       slashes++;
+                               d++;
+                       }
+                       d--;
+                       s = &devdir[strlen(devdir)-1];
+                       while (s != NULL && count != (slashes+1)) {
+                               s--;
+                               if (*s == '/')
+                                       count++;
+                       }
+                       strncpy(s, d, (SYSFS_PATH_MAX-strlen(devdir)));
+                       strncpy(target, devdir, len);
+                       break;
+               case '/':
+                       /* absolute path - copy as is */
+                       strncpy(target, linkpath, len);
+                       break;
+               default:
+                       /* relative path from this directory */
+                       strncpy(target, devdir, len);
+                       s = strrchr(target, '/');
+                       if (s != NULL) {
+                               *(s+1) = '\0';
+                               strcat(target, linkpath);
+                       } else {
+                               strcpy(target, linkpath);
+                       }                       
        }
-       
-       strncpy(s, d, (SYSFS_PATH_MAX-strlen(devdir)));
-       strncpy(target, devdir, len);
-
        return 0;
 }
 
-
 /**
  * sysfs_del_name: free function for sysfs_open_subsystem_list
  * @name: memory area to be freed
@@ -245,8 +294,8 @@ struct dlist *sysfs_open_subsystem_list(unsigned char *name)
                dprintf("Error getting sysfs mount point\n");
                return NULL;
        }
-       if (sysfs_trailing_slash(sysfs_path) == 0)
-               strcat(sysfs_path, "/");
+
+       strcat(sysfs_path, "/");
        strcat(sysfs_path, name);
        dir = sysfs_open_directory(sysfs_path);
        if (dir == NULL) {
@@ -318,8 +367,7 @@ struct dlist *sysfs_open_bus_devices_list(unsigned char *name)
                return NULL;
        }
 
-       if (sysfs_trailing_slash(sysfs_path) == 0)
-               strcat(sysfs_path, "/");
+       strcat(sysfs_path, "/");
        strcat(sysfs_path, SYSFS_BUS_NAME);
        strcat(sysfs_path, "/");
        strcat(sysfs_path, name);
@@ -376,7 +424,7 @@ int sysfs_path_is_dir(const unsigned char *path)
        }
        if (S_ISDIR(astats.st_mode))
                return 0;
-
+               
        return 1;
 }
 
@@ -399,7 +447,7 @@ int sysfs_path_is_link(const unsigned char *path)
        }
        if (S_ISLNK(astats.st_mode))
                return 0;
-
+               
        return 1;
 }
 
@@ -422,6 +470,6 @@ int sysfs_path_is_file(const unsigned char *path)
        }
        if (S_ISREG(astats.st_mode))
                return 0;
-
+               
        return 1;
 }
index 0e1af93..fdda039 100644 (file)
--- a/namedev.c
+++ b/namedev.c
@@ -29,6 +29,7 @@
 #include <ctype.h>
 #include <unistd.h>
 #include <errno.h>
+#include <time.h>
 #include <sys/wait.h>
 #include <sys/stat.h>
 
@@ -514,11 +515,8 @@ static struct sysfs_device *get_sysfs_device(struct sysfs_class_device *class_de
 {
        struct sysfs_device *sysfs_device;
        struct sysfs_class_device *class_dev_parent;
+       struct timespec tspec;
        int loop;
-       char filename[SYSFS_PATH_MAX + 6];
-       int retval;
-       char *temp;
-       int partition = 0;
 
        /* Figure out where the device symlink is at.  For char devices this will
         * always be in the class_dev->path.  But for block devices, it's different.
@@ -529,69 +527,54 @@ static struct sysfs_device *get_sysfs_device(struct sysfs_class_device *class_de
         * symlink yet.  We do sit and spin on waiting for them right now, we should
         * possibly have a whitelist for these devices here...
         */
-       strcpy(filename, class_dev->path);
-       dbg("filename = %s", filename);
-       if (strcmp(class_dev->classname, SYSFS_BLOCK_NAME) == 0) {
-               if (isdigit(class_dev->path[strlen(class_dev->path)-1])) {
-                       temp = strrchr(filename, '/');
-                       if (temp) {
-                               char *temp2 = strrchr(filename, '/');
-                               partition = 1;
-                               *temp = 0x00;
-                               dbg("temp2 = %s", temp2);
-                               if (temp2 && (strcmp(temp2, "/block") == 0)) {
-                                       /* oops, we have no parent block device, so go back to original directory */
-                                       strcpy(filename, class_dev->path);
-                                       partition = 0;
-                               }
-                       }
-               }
-       }
-       strcat(filename, "/device");
+       class_dev_parent = sysfs_get_classdev_parent(class_dev);
+       if (class_dev_parent) 
+               dbg("Really a partition");
 
-       loop = 2;
+       tspec.tv_sec = 0;
+       tspec.tv_nsec = 10000000;  /* sleep 10 millisec */
+       loop = 10;
        while (loop--) {
-               struct stat buf;
-               dbg("looking for '%s'", filename);
-               retval = stat(filename, &buf);
-               if (!retval)
-                       break;
-               /* sleep to give the kernel a chance to create the device file */
-               sleep(1);
-       }
+               nanosleep(&tspec, NULL);
+               if (class_dev_parent)
+                       sysfs_device = sysfs_get_classdev_device(class_dev_parent);
+               else
+                       sysfs_device = sysfs_get_classdev_device(class_dev);
 
-       loop = 1;       /* FIXME put a real value in here for when everything is fixed... */
-       while (loop--) {
-               /* find the sysfs_device for this class device */
-               /* Wouldn't it really be nice if libsysfs could do this for us? */
-               sysfs_device = sysfs_get_classdev_device(class_dev);
                if (sysfs_device != NULL)
-                       goto exit;
-
-               /* if it's a partition, we need to get the parent device */
-               if (partition) {
-                       /* FIXME  HACK HACK HACK HACK
-                        * for some reason partitions need this extra sleep here, in order
-                        * to wait for the device properly.  Once the libsysfs code is
-                        * fixed properly, this sleep should go away, and we can just loop above.
-                        */
-                       sleep(1);
-                       dbg("really is a partition");
-                       class_dev_parent = sysfs_get_classdev_parent(class_dev);
-                       if (class_dev_parent == NULL) {
-                               dbg("sysfs_get_classdev_parent for class device '%s' failed", class_dev->name);
-                       } else {
-                               dbg("class_dev_parent->name='%s'", class_dev_parent->name);
-                               sysfs_device = sysfs_get_classdev_device(class_dev_parent);
-                               if (sysfs_device != NULL)
-                                       goto exit;
-                       }
-               }
-               /* sleep to give the kernel a chance to create the link */
-               /* FIXME remove comment...
-               sleep(1); */
+                       goto device_found;
        }
        dbg("Timed out waiting for device symlink, continuing on anyway...");
+       
+device_found:
+        /* We have another issue with just the wait above - the sysfs part of
+        * the kernel may not be quick enough to have created the link to the
+        * device under the "bus" subsystem. Due to this, the sysfs_device->bus
+        * will not contain the actual bus name :(
+        *
+        * Libsysfs now provides a new API sysfs_get_device_bus(), so use it
+        * if needed
+        */
+        if (sysfs_device) {
+               
+               if (sysfs_device->bus[0] != '\0')
+                       goto bus_found;
+               
+               loop = 10;
+               tspec.tv_nsec = 10000000;
+               while (loop--) {
+                       nanosleep(&tspec, NULL);
+                       sysfs_get_device_bus(sysfs_device);
+                       
+                       if (sysfs_device->bus[0] != '\0')
+                               goto bus_found;
+               }
+               dbg("Timed out waiting to find the device bus, continuing on anyway\n");
+               goto exit;
+bus_found:
+               dbg("Device %s is registered with bus %s\n",
+                               sysfs_device->name, sysfs_device->bus);
+       }
 exit:
        return sysfs_device;
 }