[PATCH] libsysfs update for refresh + namedev.c changes

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.
This commit is contained in:
ananthmg@rediffmail.com 2004-01-14 22:21:38 -08:00 committed by Greg KH
parent 1782087e4f
commit 616a707807
8 changed files with 611 additions and 309 deletions

View 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

View 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,20 +299,37 @@ 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.
@ -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);

View 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,26 +581,40 @@ 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);
if ((sysfs_read_dir_attributes(cdev->directory)) != 0)
return NULL;
}
} else {
if ((sysfs_path_is_dir(cdev->path)) != 0) {
dprintf("Class device at %s no longer exists\n",
cdev->path);
return NULL;
}
if ((sysfs_refresh_attributes
(cdev->directory->attributes)) != 0) {
dprintf("Error refreshing classdev attributes\n");
return NULL;
}
}
return (cdev->directory->attributes);
}
/**
* 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
@ -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,
cur = sysfs_get_directory_attribute(sdir,
(unsigned char *)name);
} else {
if ((sysfs_refresh_attributes
(sdir->attributes)) == 0)
cur = sysfs_get_directory_attribute(sdir,
(unsigned char *)name);
}
if (cur == NULL)
continue;
}
}
return cur;

View File

@ -24,12 +24,12 @@
#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,20 +382,37 @@ 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
@ -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);

View 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);
@ -513,39 +520,6 @@ struct sysfs_link *sysfs_open_link(const unsigned char *linkpath)
return ln;
}
/**
* sysfs_refresh_attributes: Refresh attributes list
* @attrlist: list of attributes to refresh
* Returns 0 on success, 1 on failure
*/
int sysfs_refresh_attributes(struct dlist *attrlist)
{
struct sysfs_attribute *attr = NULL;
if (attrlist == NULL) {
errno = EINVAL;
return 1;
}
dlist_for_each_data(attrlist, attr, struct sysfs_attribute) {
if (attr->method & SYSFS_METHOD_SHOW) {
if ((sysfs_read_attribute(attr)) != 0) {
dprintf("Error reading attribute %s\n",
attr->path);
if ((sysfs_path_is_file(attr->path)) != 0) {
dprintf("Attr %s no longer exists\n",
attr->name);
}
}
} else {
if ((sysfs_path_is_file(attr->path)) != 0) {
dprintf("Attr %s no longer exists\n",
attr->name);
}
}
}
return 0;
}
/**
* add_attribute: open and add attribute at path to given directory
* @sysdir: directory to add attribute to
@ -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);
@ -801,6 +760,90 @@ int sysfs_read_directory(struct sysfs_directory *sysdir)
return(retval);
}
/**
* sysfs_refresh_dir_attributes: Refresh attributes list
* @sysdir: directory whose list of attributes to refresh
* Returns 0 on success, 1 on failure
*/
int sysfs_refresh_dir_attributes(struct sysfs_directory *sysdir)
{
if (sysdir == NULL) {
errno = EINVAL;
return 1;
}
if ((sysfs_path_is_dir(sysdir->path)) != 0) {
dprintf("Invalid path to directory %s\n", sysdir->path);
errno = EINVAL;
return 1;
}
if (sysdir->attributes != NULL) {
dlist_destroy(sysdir->attributes);
sysdir->attributes = NULL;
}
if ((sysfs_read_dir_attributes(sysdir)) != 0) {
dprintf("Error refreshing attributes for directory %s\n",
sysdir->path);
return 1;
}
return 0;
}
/**
* sysfs_refresh_dir_links: Refresh links list
* @sysdir: directory whose list of links to refresh
* Returns 0 on success, 1 on failure
*/
int sysfs_refresh_dir_links(struct sysfs_directory *sysdir)
{
if (sysdir == NULL) {
errno = EINVAL;
return 1;
}
if ((sysfs_path_is_dir(sysdir->path)) != 0) {
dprintf("Invalid path to directory %s\n", sysdir->path);
errno = EINVAL;
return 1;
}
if (sysdir->links != NULL) {
dlist_destroy(sysdir->links);
sysdir->links = NULL;
}
if ((sysfs_read_dir_links(sysdir)) != 0) {
dprintf("Error refreshing links for directory %s\n",
sysdir->path);
return 1;
}
return 0;
}
/**
* sysfs_refresh_dir_subdirs: Refresh subdirs list
* @sysdir: directory whose list of subdirs to refresh
* Returns 0 on success, 1 on failure
*/
int sysfs_refresh_dir_subdirs(struct sysfs_directory *sysdir)
{
if (sysdir == NULL) {
errno = EINVAL;
return 1;
}
if ((sysfs_path_is_dir(sysdir->path)) != 0) {
dprintf("Invalid path to directory %s\n", sysdir->path);
errno = EINVAL;
return 1;
}
if (sysdir->subdirs != NULL) {
dlist_destroy(sysdir->subdirs);
sysdir->subdirs = NULL;
}
if ((sysfs_read_dir_subdirs(sysdir)) != 0) {
dprintf("Error refreshing subdirs for directory %s\n",
sysdir->path);
return 1;
}
return 0;
}
/**
* sysfs_get_directory_attribute: retrieves attribute attrname from current
* directory only
@ -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);
}

View 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,25 +130,37 @@ 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");
if ((sysfs_read_dir_attributes(driver->directory)) != 0)
return NULL;
}
} else {
if ((sysfs_path_is_dir(driver->path)) != 0) {
dprintf("Driver at %s no longer exists\n",
driver->path);
return NULL;
}
if ((sysfs_refresh_attributes
(driver->directory->attributes)) != 0) {
dprintf("Error refreshing driver attributes\n");
return NULL;
}
}
return(driver->directory->attributes);
}
/**
* 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
@ -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;
}
/**
@ -233,6 +250,38 @@ struct dlist *sysfs_get_driver_devices(struct sysfs_driver *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
@ -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);

View File

@ -26,6 +26,30 @@
#include <mntent.h>
#endif
/**
* sysfs_remove_trailing_slash: Removes any trailing '/' in the given path
* @path: Path to look for the trailing '/'
* Returns 0 on success 1 on error
*/
int sysfs_remove_trailing_slash(unsigned char *path)
{
unsigned char *c = NULL;
if (path == NULL) {
errno = EINVAL;
return 1;
}
c = strrchr(path, '/');
if (c == NULL) {
dprintf("Invalid path %s\n", path);
errno = EINVAL;
return 1;
}
if (*(c+1) == '\0')
*c = '\0';
return 0;
}
/**
* sysfs_get_mnt_path: Gets the mount point for specified filesystem.
* @fs_type: filesystem type to retrieve mount point
@ -72,27 +96,13 @@ 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
@ -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++;
/*
* 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);
}
}
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);
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;
}

105
namedev.c
View File

@ -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;
}