diff options
Diffstat (limited to 'libsysfs')
-rw-r--r-- | libsysfs/sysfs.h | 24 | ||||
-rw-r--r-- | libsysfs/sysfs/libsysfs.h | 177 | ||||
-rw-r--r-- | libsysfs/sysfs_class.c | 519 | ||||
-rw-r--r-- | libsysfs/sysfs_device.c | 542 | ||||
-rw-r--r-- | libsysfs/sysfs_dir.c | 1000 | ||||
-rw-r--r-- | libsysfs/sysfs_driver.c | 393 | ||||
-rw-r--r-- | libsysfs/sysfs_utils.c | 262 |
7 files changed, 631 insertions, 2286 deletions
diff --git a/libsysfs/sysfs.h b/libsysfs/sysfs.h index 1e58e8abb4..30bd9b4089 100644 --- a/libsysfs/sysfs.h +++ b/libsysfs/sysfs.h @@ -27,19 +27,37 @@ #include <stdlib.h> #include <unistd.h> #include <string.h> +#include <ctype.h> #include <mntent.h> #include <dirent.h> #include <sys/stat.h> #include <fcntl.h> #include <errno.h> -/* external library functions */ -extern int isascii(int c); +#define safestrcpy(to, from) strncpy(to, from, sizeof(to)-1) +#define safestrcat(to, from) strncat(to, from, sizeof(to) - strlen(to)-1) + +#define safestrcpymax(to, from, max) \ +do { \ + to[max-1] = '\0'; \ + strncpy(to, from, max-1); \ +} while (0) + +#define safestrcatmax(to, from, max) \ +do { \ + to[max-1] = '\0'; \ + strncat(to, from, max - strlen(to)-1); \ +} while (0) + +extern struct sysfs_attribute *get_attribute(void *dev, const char *name); +extern struct dlist *read_dir_subdirs(const char *path); +extern struct dlist *read_dir_links(const char *path); +extern struct dlist *get_attributes_list(void *dev); /* Debugging */ #ifdef DEBUG #include "../logging.h" -#define dprintf(format, arg...) dbg(format, ##arg) +#define dprintf(format, arg...) dbg(format, ## arg) #else #define dprintf(format, arg...) do { } while (0) #endif diff --git a/libsysfs/sysfs/libsysfs.h b/libsysfs/sysfs/libsysfs.h index 29194f61a6..6140c3aecb 100644 --- a/libsysfs/sysfs/libsysfs.h +++ b/libsysfs/sysfs/libsysfs.h @@ -3,7 +3,7 @@ * * Header Definitions for libsysfs * - * Copyright (C) IBM Corp. 2003 + * Copyright (C) IBM Corp. 2004-2005 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -27,27 +27,6 @@ #include <string.h> #include "dlist.h" -/* - * Defines to prevent buffer overruns - */ -#define safestrcpy(to, from) strncpy(to, from, sizeof(to)-1) -#define safestrcat(to, from) strncat(to, from, sizeof(to) - strlen(to)-1) - -#define safestrcpymax(to, from, max) \ -do { \ - to[max-1] = '\0'; \ - strncpy(to, from, max-1); \ -} while (0) - -#define safestrcatmax(to, from, max) \ -do { \ - to[max-1] = '\0'; \ - strncat(to, from, max - strlen(to)-1); \ -} while (0) - -/* - * Generic #defines go here.. - */ #define SYSFS_FSTYPE_NAME "sysfs" #define SYSFS_PROC_MNTS "/proc/mounts" #define SYSFS_BUS_NAME "bus" @@ -55,106 +34,92 @@ do { \ #define SYSFS_BLOCK_NAME "block" #define SYSFS_DEVICES_NAME "devices" #define SYSFS_DRIVERS_NAME "drivers" +#define SYSFS_MODULE_NAME "module" #define SYSFS_NAME_ATTRIBUTE "name" #define SYSFS_UNKNOWN "unknown" #define SYSFS_PATH_ENV "SYSFS_PATH" -#define SYSFS_PATH_MAX 255 -#define SYSFS_NAME_LEN 50 -#define SYSFS_BUS_ID_SIZE 20 +#define SYSFS_PATH_MAX 256 +#define SYSFS_NAME_LEN 64 +#define SYSFS_BUS_ID_SIZE 32 -#define SYSFS_METHOD_SHOW 0x01 /* attr can be read by user */ -#define SYSFS_METHOD_STORE 0x02 /* attr can be changed by user */ +enum sysfs_attribute_method { + SYSFS_METHOD_SHOW = 0x01, /* attr can be read by user */ + SYSFS_METHOD_STORE = 0x02, /* attr can be changed by user */ +}; + +/* NOTE: statically define mnt path for sysfs */ +#define SYSFS_MNT_PATH "/sys" /* - * NOTE: We have the statically allocated "name" as the first element of all + * NOTE: + * 1. We have the statically allocated "name" as the first element of all * the structures. This feature is used in the "sorter" function for dlists + * 2. As is the case with attrlist + * 3. As is the case with path */ - struct sysfs_attribute { char name[SYSFS_NAME_LEN]; char path[SYSFS_PATH_MAX]; char *value; - unsigned short len; /* value length */ - unsigned short method; /* show and store */ -}; - -struct sysfs_link { - char name[SYSFS_NAME_LEN]; - char path[SYSFS_PATH_MAX]; - char target[SYSFS_PATH_MAX]; -}; - -struct sysfs_directory { - char name[SYSFS_NAME_LEN]; - char path[SYSFS_PATH_MAX]; - - /* Private: for internal use only */ - struct dlist *subdirs; - struct dlist *links; - struct dlist *attributes; + unsigned short len; /* value length */ + enum sysfs_attribute_method method; /* show and store */ }; struct sysfs_driver { char name[SYSFS_NAME_LEN]; char path[SYSFS_PATH_MAX]; + struct dlist *attrlist; + char bus[SYSFS_NAME_LEN]; /* Private: for internal use only */ struct dlist *devices; - struct sysfs_directory *directory; }; struct sysfs_device { char name[SYSFS_NAME_LEN]; + char path[SYSFS_PATH_MAX]; + struct dlist *attrlist; char bus_id[SYSFS_NAME_LEN]; char bus[SYSFS_NAME_LEN]; char driver_name[SYSFS_NAME_LEN]; - char path[SYSFS_PATH_MAX]; /* Private: for internal use only */ struct sysfs_device *parent; + /* NOTE - we still don't populate this */ struct dlist *children; - struct sysfs_directory *directory; -}; - -struct sysfs_root_device { - char name[SYSFS_NAME_LEN]; - char path[SYSFS_PATH_MAX]; - - /* Private: for internal use only */ - struct dlist *devices; - struct sysfs_directory *directory; }; +/* NOTE: not used as of now */ struct sysfs_bus { char name[SYSFS_NAME_LEN]; char path[SYSFS_PATH_MAX]; + struct dlist *attrlist; /* Private: for internal use only */ struct dlist *drivers; struct dlist *devices; - struct sysfs_directory *directory; }; struct sysfs_class_device { char name[SYSFS_NAME_LEN]; - char classname[SYSFS_NAME_LEN]; char path[SYSFS_PATH_MAX]; + struct dlist *attrlist; + char classname[SYSFS_NAME_LEN]; /* 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 */ - struct sysfs_directory *directory; }; +/* NOTE: not used as of now */ struct sysfs_class { char name[SYSFS_NAME_LEN]; char path[SYSFS_PATH_MAX]; + struct dlist *attrlist; /* Private: for internal use only */ struct dlist *devices; - struct sysfs_directory *directory; }; #ifdef __cplusplus @@ -171,43 +136,15 @@ extern int sysfs_path_is_dir(const char *path); extern int sysfs_path_is_link(const char *path); extern int sysfs_path_is_file(const char *path); extern int sysfs_get_link(const char *path, char *target, size_t len); -extern struct dlist *sysfs_open_subsystem_list(char *name); -extern struct dlist *sysfs_open_bus_devices_list(char *name); +extern struct dlist *sysfs_open_directory_list(const char *path); extern void sysfs_close_list(struct dlist *list); /* sysfs directory and file access */ extern void sysfs_close_attribute(struct sysfs_attribute *sysattr); extern struct sysfs_attribute *sysfs_open_attribute(const char *path); extern int sysfs_read_attribute(struct sysfs_attribute *sysattr); -extern int sysfs_read_attribute_value(const char *attrpath, - char *value, size_t vsize); extern int sysfs_write_attribute(struct sysfs_attribute *sysattr, const char *new_value, size_t len); -extern char *sysfs_get_value_from_attributes(struct dlist *attr, - const char *name); -extern int sysfs_refresh_dir_attributes(struct sysfs_directory *sysdir); -extern int sysfs_refresh_dir_links(struct sysfs_directory *sysdir); -extern int sysfs_refresh_dir_subdirs(struct sysfs_directory *sysdir); -extern void sysfs_close_directory(struct sysfs_directory *sysdir); -extern struct sysfs_directory *sysfs_open_directory(const char *path); -extern int sysfs_read_dir_attributes(struct sysfs_directory *sysdir); -extern int sysfs_read_dir_links(struct sysfs_directory *sysdir); -extern int sysfs_read_dir_subdirs(struct sysfs_directory *sysdir); -extern int sysfs_read_directory(struct sysfs_directory *sysdir); -extern int sysfs_read_all_subdirs(struct sysfs_directory *sysdir); -extern struct sysfs_directory *sysfs_get_subdirectory - (struct sysfs_directory *dir, char *subname); -extern void sysfs_close_link(struct sysfs_link *ln); -extern struct sysfs_link *sysfs_open_link(const char *lnpath); -extern struct sysfs_link *sysfs_get_directory_link - (struct sysfs_directory *dir, char *linkname); -extern struct sysfs_link *sysfs_get_subdirectory_link - (struct sysfs_directory *dir, char *linkname); -extern struct sysfs_attribute *sysfs_get_directory_attribute - (struct sysfs_directory *dir, char *attrname); -extern struct dlist *sysfs_get_dir_attributes(struct sysfs_directory *dir); -extern struct dlist *sysfs_get_dir_links(struct sysfs_directory *dir); -extern struct dlist *sysfs_get_dir_subdirs(struct sysfs_directory *dir); /* sysfs driver access */ extern void sysfs_close_driver(struct sysfs_driver *driver); @@ -218,19 +155,8 @@ extern struct sysfs_attribute *sysfs_get_driver_attr (struct sysfs_driver *drv, const char *name); extern struct dlist *sysfs_get_driver_attributes(struct sysfs_driver *driver); extern struct dlist *sysfs_get_driver_devices(struct sysfs_driver *driver); -extern struct dlist *sysfs_refresh_driver_devices(struct sysfs_driver *driver); -extern struct dlist *sysfs_get_driver_links(struct sysfs_driver *driver); -extern struct sysfs_device *sysfs_get_driver_device - (struct sysfs_driver *driver, const char *name); -extern struct dlist *sysfs_refresh_driver_attributes - (struct sysfs_driver *driver); -extern struct sysfs_attribute *sysfs_open_driver_attr - (const char *bus, const char *drv, const char *attrib); /* generic sysfs device access */ -extern void sysfs_close_root_device(struct sysfs_root_device *root); -extern struct sysfs_root_device *sysfs_open_root_device(const char *name); -extern struct dlist *sysfs_get_root_devices(struct sysfs_root_device *root); extern void sysfs_close_device_tree(struct sysfs_device *device); extern struct sysfs_device *sysfs_open_device_tree(const char *path); extern void sysfs_close_device(struct sysfs_device *dev); @@ -241,27 +167,8 @@ extern struct sysfs_device *sysfs_open_device_path(const char *path); extern int sysfs_get_device_bus(struct sysfs_device *dev); extern struct sysfs_attribute *sysfs_get_device_attr (struct sysfs_device *dev, const 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 char *bus, - const char *bus_id, const char *attrib); - -/* generic sysfs bus access */ -extern void sysfs_close_bus(struct sysfs_bus *bus); -extern struct sysfs_bus *sysfs_open_bus(const char *name); -extern struct sysfs_device *sysfs_get_bus_device(struct sysfs_bus *bus, - char *id); -extern struct sysfs_driver *sysfs_get_bus_driver(struct sysfs_bus *bus, - char *drvname); -extern struct dlist *sysfs_get_bus_drivers(struct sysfs_bus *bus); -extern struct dlist *sysfs_get_bus_devices(struct sysfs_bus *bus); -extern struct dlist *sysfs_get_bus_attributes(struct sysfs_bus *bus); -extern struct dlist *sysfs_refresh_bus_attributes(struct sysfs_bus *bus); -extern struct sysfs_attribute *sysfs_get_bus_attribute - (struct sysfs_bus *bus, char *attrname); -extern int sysfs_find_driver_bus(const char *driver, char *busname, - size_t bsize); +extern struct dlist *sysfs_get_device_attributes + (struct sysfs_device *dev); /* generic sysfs class access */ extern void sysfs_close_class_device(struct sysfs_class_device *dev); @@ -269,26 +176,14 @@ extern struct sysfs_class_device *sysfs_open_class_device_path (const char *path); extern struct sysfs_class_device *sysfs_open_class_device (const char *classname, const char *name); -extern struct sysfs_device *sysfs_get_classdev_device - (struct sysfs_class_device *clsdev); -extern struct sysfs_driver *sysfs_get_classdev_driver - (struct sysfs_class_device *clsdev); extern struct sysfs_class_device *sysfs_get_classdev_parent (struct sysfs_class_device *clsdev); -extern void sysfs_close_class(struct sysfs_class *cls); -extern struct sysfs_class *sysfs_open_class(const char *name); -extern struct dlist *sysfs_get_class_devices(struct sysfs_class *cls); -extern struct sysfs_class_device *sysfs_get_class_device - (struct sysfs_class *cls, char *name); -extern struct dlist *sysfs_get_classdev_attributes - (struct sysfs_class_device *cdev); -extern struct dlist *sysfs_refresh_classdev_attributes - (struct sysfs_class_device *cdev); extern struct sysfs_attribute *sysfs_get_classdev_attr (struct sysfs_class_device *clsdev, const char *name); -extern struct sysfs_attribute *sysfs_open_classdev_attr - (const char *classname, const char *dev, - const char *attrib); +extern struct dlist *sysfs_get_classdev_attributes + (struct sysfs_class_device *clsdev); +extern struct sysfs_device *sysfs_get_classdev_device + (struct sysfs_class_device *clsdev); /** * sort_list: sorter function to keep list elements sorted in alphabetical diff --git a/libsysfs/sysfs_class.c b/libsysfs/sysfs_class.c index 4ea7f41c99..a93de573d4 100644 --- a/libsysfs/sysfs_class.c +++ b/libsysfs/sysfs_class.c @@ -3,7 +3,7 @@ * * Generic class utility functions for libsysfs * - * Copyright (C) IBM Corp. 2003 + * Copyright (C) IBM Corp. 2003-2005 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -23,95 +23,50 @@ #include "libsysfs.h" #include "sysfs.h" -static void sysfs_close_cls_dev(void *dev) -{ - sysfs_close_class_device((struct sysfs_class_device *)dev); -} - -/** - * class_name_equal: compares class_devices' name - * @a: class_name looking for - * @b: sysfs_class_device being compared - */ -static int class_name_equal(void *a, void *b) -{ - if (a == NULL || b == NULL) - return 0; - - if (strcmp(((char *)a), ((struct sysfs_class_device *)b)->name) == 0) - return 1; - - return 0; -} - /** * sysfs_close_class_device: closes a single class device. * @dev: class device to close. */ void sysfs_close_class_device(struct sysfs_class_device *dev) { - if (dev != NULL) { - if (dev->directory != NULL) - sysfs_close_directory(dev->directory); - if (dev->sysdevice != NULL) - sysfs_close_device(dev->sysdevice); - if (dev->driver != NULL) - sysfs_close_driver(dev->driver); - if (dev->parent != NULL) + if (dev) { + if (dev->parent) sysfs_close_class_device(dev->parent); + if (dev->sysdevice) + sysfs_close_device(dev->sysdevice); + if (dev->attrlist) + dlist_destroy(dev->attrlist); free(dev); } } /** - * sysfs_close_class: close single class - * @cls: class structure - */ -void sysfs_close_class(struct sysfs_class *cls) -{ - if (cls != NULL) { - if (cls->directory != NULL) - sysfs_close_directory(cls->directory); - if (cls->devices != NULL) - dlist_destroy(cls->devices); - free(cls); - } -} - -/** * alloc_class_device: mallocs and initializes new class device struct. * returns sysfs_class_device or NULL. */ static struct sysfs_class_device *alloc_class_device(void) { - return (struct sysfs_class_device *) - calloc(1, sizeof(struct sysfs_class_device)); -} + struct sysfs_class_device *dev; -/** - * alloc_class: mallocs new class structure - * returns sysfs_class struct or NULL - */ -static struct sysfs_class *alloc_class(void) -{ - return (struct sysfs_class *)calloc(1, sizeof(struct sysfs_class)); + dev = calloc(1, sizeof(struct sysfs_class_device)); + return dev; } -/** +/** * set_classdev_classname: Grabs classname from path * @cdev: class device to set * Returns nothing */ static void set_classdev_classname(struct sysfs_class_device *cdev) { - char *c = NULL, *e = NULL; + char *c, *e; int count = 0; c = strstr(cdev->path, SYSFS_CLASS_NAME); if (c == NULL) { c = strstr(cdev->path, SYSFS_BLOCK_NAME); } else { - c = strchr(c, '/'); + c = strstr(c, "/"); } if (c == NULL) @@ -135,9 +90,9 @@ static void set_classdev_classname(struct sysfs_class_device *cdev) */ struct sysfs_class_device *sysfs_open_class_device_path(const char *path) { - struct sysfs_class_device *cdev = NULL; + struct sysfs_class_device *cdev; - if (path == NULL) { + if (!path) { errno = EINVAL; return NULL; } @@ -146,11 +101,11 @@ struct sysfs_class_device *sysfs_open_class_device_path(const char *path) return NULL; } cdev = alloc_class_device(); - if (cdev == NULL) { + if (!cdev) { dprintf("calloc failed\n"); return NULL; } - if ((sysfs_get_name_from_path(path, cdev->name, SYSFS_NAME_LEN)) != 0) { + if (sysfs_get_name_from_path(path, cdev->name, SYSFS_NAME_LEN)) { errno = EINVAL; dprintf("Error getting class device name\n"); sysfs_close_class_device(cdev); @@ -168,245 +123,6 @@ struct sysfs_class_device *sysfs_open_class_device_path(const char *path) return cdev; } -/** - * sysfs_get_class_devices: gets all devices for class - * @cls: class to get devices for - * returns dlist of class_devices with success and NULL with error - */ -struct dlist *sysfs_get_class_devices(struct sysfs_class *cls) -{ - struct sysfs_class_device *dev = NULL; - struct sysfs_directory *cur = NULL; - - if (cls == NULL) { - 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) - return NULL; - } - - if ((sysfs_read_dir_subdirs(cls->directory)) != 0) - return NULL; - - if (cls->directory->subdirs != NULL) { - dlist_for_each_data(cls->directory->subdirs, cur, - struct sysfs_directory) { - dev = sysfs_open_class_device_path(cur->path); - if (dev == NULL) { - dprintf("Error opening device at %s\n", - cur->path); - continue; - } - if (cls->devices == NULL) - cls->devices = dlist_new_with_delete - (sizeof(struct sysfs_class_device), - sysfs_close_cls_dev); - dlist_unshift_sorted(cls->devices, dev, sort_list); - } - } - return cls->devices; -} - -/** - * sysfs_open_class: opens specific class and all its devices on system - * returns sysfs_class structure with success or NULL with error. - */ -struct sysfs_class *sysfs_open_class(const char *name) -{ - struct sysfs_class *cls = NULL; - char classpath[SYSFS_PATH_MAX]; - - if (name == NULL) { - errno = EINVAL; - return NULL; - } - - memset(classpath, 0, SYSFS_PATH_MAX); - if ((sysfs_get_mnt_path(classpath, SYSFS_PATH_MAX)) != 0) { - dprintf("Sysfs not supported on this system\n"); - return NULL; - } - - /* - * We shall now treat "block" also as a class. Hence, check here - * if "name" is "block" and proceed accordingly - */ - if (strcmp(name, SYSFS_BLOCK_NAME) == 0) { - safestrcat(classpath, "/"); - safestrcat(classpath, SYSFS_BLOCK_NAME); - } else { - safestrcat(classpath, "/"); - safestrcat(classpath, SYSFS_CLASS_NAME); - safestrcat(classpath, "/"); - safestrcat(classpath, name); - } - if ((sysfs_path_is_dir(classpath)) != 0) { - dprintf("Class %s not found on the system\n", name); - return NULL; - } - - cls = alloc_class(); - if (cls == NULL) { - dprintf("calloc failed\n"); - return NULL; - } - safestrcpy(cls->name, name); - safestrcpy(cls->path, classpath); - if ((sysfs_remove_trailing_slash(cls->path)) != 0) { - dprintf("Invalid path to class device %s\n", cls->path); - sysfs_close_class(cls); - return NULL; - } - - return cls; -} - -/** - * sysfs_get_class_device: Get specific class device using the device's id - * @class: class to find device on - * @name: class name of the device - */ -struct sysfs_class_device *sysfs_get_class_device(struct sysfs_class *cls, - char *name) -{ - if (cls == NULL || name == NULL) { - errno = EINVAL; - return NULL; - } - - if (cls->devices == NULL) { - cls->devices = sysfs_get_class_devices(cls); - if (cls->devices == NULL) - return NULL; - } - return (struct sysfs_class_device *)dlist_find_custom(cls->devices, - name, class_name_equal); -} - -/** - * sysfs_get_classdev_device: returns the sysfs_device corresponding to - * sysfs_class_device, if present - * @clsdev: class device whose sysfs_device is required - * Returns sysfs_device on success, NULL on error or if device is not - * implemented - */ -struct sysfs_device *sysfs_get_classdev_device - (struct sysfs_class_device *clsdev) -{ - struct sysfs_link *devlink = NULL; - char devpath[SYSFS_PATH_MAX]; - - if (clsdev == NULL) { - errno = EINVAL; - return NULL; - } - safestrcpy(devpath, clsdev->path); - safestrcat(devpath, "/device"); - if ((sysfs_path_is_link(devpath)) != 0) { - if (clsdev->sysdevice != NULL) { - sysfs_close_device(clsdev->sysdevice); - clsdev->sysdevice = NULL; - } - return NULL; - } - - if (clsdev->directory == NULL) { - clsdev->directory = sysfs_open_directory(clsdev->path); - if (clsdev->directory == NULL) - return NULL; - } - devlink = sysfs_get_directory_link(clsdev->directory, "device"); - if (devlink == NULL) { - if (clsdev->sysdevice != NULL) { - dprintf("Device link no longer exists\n"); - sysfs_close_device(clsdev->sysdevice); - clsdev->sysdevice = NULL; - } - return NULL; - } - - if (clsdev->sysdevice != NULL) { - if (!strncmp(devlink->target, clsdev->sysdevice->path, - SYSFS_PATH_MAX)) - /* sysdevice hasn't changed */ - return (clsdev->sysdevice); - else - /* come here only if the device link for has changed */ - sysfs_close_device(clsdev->sysdevice); - } - - clsdev->sysdevice = sysfs_open_device_path(devlink->target); - if (clsdev->sysdevice == NULL) - return NULL; - - return (clsdev->sysdevice); -} - -/** - * sysfs_get_classdev_driver: returns the sysfs_driver corresponding to - * sysfs_class_device, if present - * @clsdev: class device whose sysfs_device is required - * Returns sysfs_driver on success, NULL on error or if driver is not - * implemented - */ -struct sysfs_driver *sysfs_get_classdev_driver - (struct sysfs_class_device *clsdev) -{ - struct sysfs_link *drvlink = NULL; - char drvpath[SYSFS_PATH_MAX]; - - if (clsdev == NULL) { - errno = EINVAL; - return NULL; - } - safestrcpy(drvpath, clsdev->path); - safestrcat(drvpath, "/driver"); - if ((sysfs_path_is_link(drvpath)) != 0) { - if (clsdev->driver != NULL) { - sysfs_close_driver(clsdev->driver); - clsdev->driver = NULL; - } - return NULL; - } - - if (clsdev->directory == NULL) { - clsdev->directory = sysfs_open_directory(clsdev->path); - if (clsdev->directory == NULL) - return NULL; - } - drvlink = sysfs_get_directory_link(clsdev->directory, "driver"); - if (drvlink == NULL) { - if (clsdev->driver != NULL) { - dprintf("Driver link no longer exists\n"); - sysfs_close_driver(clsdev->driver); - clsdev->driver = NULL; - } - return NULL; - } - if (clsdev->driver != NULL) { - if (!strncmp(drvlink->target, clsdev->driver->path, - SYSFS_PATH_MAX)) - /* driver hasn't changed */ - return (clsdev->driver); - else - /* come here only if the device link for has changed */ - sysfs_close_driver(clsdev->driver); - } - - clsdev->driver = sysfs_open_driver_path(drvlink->target); - if (clsdev->driver == NULL) - return NULL; - - return (clsdev->driver); -} - /** * get_blockdev_parent: Get the parent class device for a "block" subsystem * device if present @@ -415,7 +131,8 @@ struct sysfs_driver *sysfs_get_classdev_driver */ static int get_blockdev_parent(struct sysfs_class_device *clsdev) { - char parent_path[SYSFS_PATH_MAX], *c = NULL; + char parent_path[SYSFS_PATH_MAX]; + char *c; safestrcpy(parent_path, clsdev->path); c = strstr(parent_path, SYSFS_BLOCK_NAME); @@ -430,20 +147,20 @@ static int get_blockdev_parent(struct sysfs_class_device *clsdev) 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, '/'); + /* 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) { + if (!clsdev->parent) { dprintf("Error opening the parent class device at %s\n", parent_path); return 1; @@ -466,19 +183,19 @@ errout: struct sysfs_class_device *sysfs_get_classdev_parent (struct sysfs_class_device *clsdev) { - if (clsdev == NULL) { + if (!clsdev) { errno = EINVAL; return NULL; } - if (clsdev->parent != NULL) + if (clsdev->parent) return (clsdev->parent); - - /* + + /* * As of now, only block devices have a parent child heirarchy in sysfs * We do not know, if, in the future, more classes will have a similar * structure. Hence, we now call a specialized function for block and * later we can add support functions for other subsystems as required. - */ + */ if (!(strncmp(clsdev->classname, SYSFS_BLOCK_NAME, sizeof(SYSFS_BLOCK_NAME)))) { if ((get_blockdev_parent(clsdev)) == 0) @@ -499,13 +216,13 @@ struct sysfs_class_device *sysfs_get_classdev_parent static int get_classdev_path(const char *classname, const char *clsdev, char *path, size_t len) { - if (classname == NULL || clsdev == NULL || path == NULL) { + if (!classname || !clsdev || !path) { errno = EINVAL; return -1; } - if (sysfs_get_mnt_path(path, len) != 0) { - dprintf("Error getting sysfs mount path\n"); - return -1; + if (sysfs_get_mnt_path(path, len) != 0) { + dprintf("Error getting sysfs mount path\n"); + return -1; } if (strncmp(classname, SYSFS_BLOCK_NAME, sizeof(SYSFS_BLOCK_NAME)) == 0) { @@ -535,9 +252,9 @@ struct sysfs_class_device *sysfs_open_class_device (const char *classname, const char *name) { char devpath[SYSFS_PATH_MAX]; - struct sysfs_class_device *cdev = NULL; + struct sysfs_class_device *cdev; - if (classname == NULL || name == NULL) { + if (!classname || !name) { errno = EINVAL; return NULL; } @@ -549,9 +266,9 @@ struct sysfs_class_device *sysfs_open_class_device name, classname); return NULL; } - + cdev = sysfs_open_class_device_path(devpath); - if (cdev == NULL) { + if (!cdev) { dprintf("Error getting class device %s from class %s\n", name, classname); return NULL; @@ -560,57 +277,6 @@ struct sysfs_class_device *sysfs_open_class_device } /** - * sysfs_get_classdev_attributes: returns a dlist of attributes for - * the requested class_device - * @cdev: sysfs_class_dev for which attributes are needed - * returns a dlist of attributes if exists, NULL otherwise - */ -struct dlist *sysfs_get_classdev_attributes(struct sysfs_class_device *cdev) -{ - if (cdev == NULL) - return NULL; - - if (cdev->directory == NULL) { - cdev->directory = sysfs_open_directory(cdev->path); - if (cdev->directory == NULL) - return NULL; - } - if (cdev->directory->attributes == NULL) { - if ((sysfs_read_dir_attributes(cdev->directory)) != 0) - return NULL; - } - return (cdev->directory->attributes); -} - -/** - * sysfs_refresh_clsassdev_attributes: refreshes the driver's list of attributes - * @clsdev: sysfs_class_device whose attributes to refresh - * - * NOTE: Upon return, prior references to sysfs_attributes for this classdev - * _may_ not be valid - * - * Returns list of attributes on success and NULL on failure - */ -struct dlist *sysfs_refresh_classdev_attributes - (struct sysfs_class_device *clsdev) -{ - if (clsdev == NULL) { - errno = EINVAL; - return NULL; - } - - if (clsdev->directory == NULL) - return (sysfs_get_classdev_attributes(clsdev)); - - if ((sysfs_refresh_dir_attributes(clsdev->directory)) != 0) { - dprintf("Error refreshing class_device attributes\n"); - return NULL; - } - - return (clsdev->directory->attributes); -} - -/** * sysfs_get_classdev_attr: searches class device's attributes by name * @clsdev: class device to look through * @name: attribute name to get @@ -619,90 +285,53 @@ struct dlist *sysfs_refresh_classdev_attributes struct sysfs_attribute *sysfs_get_classdev_attr (struct sysfs_class_device *clsdev, const char *name) { - struct sysfs_attribute *cur = NULL; - struct sysfs_directory *sdir = NULL; - struct dlist *attrlist = NULL; - - if (clsdev == NULL || name == NULL) { + if (!clsdev || !name) { errno = EINVAL; return NULL; } - - /* - * First, see if it's in the current directory. Then look at - * subdirs since class devices can have subdirs of attributes. - */ - attrlist = sysfs_get_classdev_attributes(clsdev); - if (attrlist != NULL) { - cur = sysfs_get_directory_attribute(clsdev->directory, - (char *)name); - if (cur != NULL) - return cur; - } + return get_attribute(clsdev, (char *)name); +} - if (clsdev->directory == NULL) +/** + * sysfs_get_classdev_attributes: gets list of classdev attributes + * @clsdev: class device whose attributes list is needed + * returns dlist of attributes on success or NULL on error + */ +struct dlist *sysfs_get_classdev_attributes(struct sysfs_class_device *clsdev) +{ + if (!clsdev) { + errno = EINVAL; return NULL; - - if (clsdev->directory->subdirs == NULL) - if ((sysfs_read_dir_subdirs(clsdev->directory)) != 0 || - clsdev->directory->subdirs == NULL) - return NULL; - - if (clsdev->directory->subdirs != NULL) { - dlist_for_each_data(clsdev->directory->subdirs, sdir, - struct sysfs_directory) { - if ((sysfs_path_is_dir(sdir->path)) != 0) - continue; - cur = sysfs_get_directory_attribute(sdir, - (char *)name); - if (cur == NULL) - continue; - } } - return cur; + return get_attributes_list(clsdev); } /** - * sysfs_open_classdev_attr: read an attribute for a given class device - * @classname: name of the class on which to look - * @dev: class device name for which the attribute has to be read - * @attrib: attribute to read - * Returns sysfs_attribute * on SUCCESS and NULL on error - * - * NOTE: - * A call to sysfs_close_attribute() is required to close the - * attribute returned and to free memory + * sysfs_get_classdev_device: gets the sysfs_device associated with the + * given sysfs_class_device + * @clsdev: class device whose associated sysfs_device is needed + * returns struct sysfs_device * on success or NULL on error */ -struct sysfs_attribute *sysfs_open_classdev_attr(const char *classname, - const char *dev, const char *attrib) +struct sysfs_device *sysfs_get_classdev_device + (struct sysfs_class_device *clsdev) { - struct sysfs_attribute *attribute = NULL; - char path[SYSFS_PATH_MAX]; + char linkpath[SYSFS_PATH_MAX], devpath[SYSFS_PATH_MAX]; - if (classname == NULL || dev == NULL || attrib == NULL) { + if (!clsdev) { errno = EINVAL; return NULL; } - memset(path, 0, SYSFS_PATH_MAX); - if ((get_classdev_path(classname, dev, path, SYSFS_PATH_MAX)) != 0) { - dprintf("Error getting to device %s on class %s\n", - dev, classname); - return NULL; - } - safestrcat(path, "/"); - safestrcat(path, attrib); - attribute = sysfs_open_attribute(path); - if (attribute == NULL) { - dprintf("Error opening attribute %s on class device %s\n", - attrib, dev); - return NULL; - } - if ((sysfs_read_attribute(attribute)) != 0) { - dprintf("Error reading attribute %s for class device %s\n", - attrib, dev); - sysfs_close_attribute(attribute); - return NULL; + + if (clsdev->sysdevice) + return clsdev->sysdevice; + + memset(linkpath, 0, SYSFS_PATH_MAX); + safestrcpy(linkpath, clsdev->path); + safestrcat(linkpath, "/device"); + if (!sysfs_path_is_link(linkpath)) { + memset(devpath, 0, SYSFS_PATH_MAX); + if (!sysfs_get_link(linkpath, devpath, SYSFS_PATH_MAX)) + clsdev->sysdevice = sysfs_open_device_path(devpath); } - return attribute; + return clsdev->sysdevice; } - diff --git a/libsysfs/sysfs_device.c b/libsysfs/sysfs_device.c index 83c3adc080..7087730d5f 100644 --- a/libsysfs/sysfs_device.c +++ b/libsysfs/sysfs_device.c @@ -3,7 +3,7 @@ * * Generic device utility functions for libsysfs * - * Copyright (C) IBM Corp. 2003 + * Copyright (C) IBM Corp. 2003-2005 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -24,48 +24,64 @@ #include "sysfs.h" /** - * get_dev_driver: fills in the dev->driver_name field, but searches by - * opening subsystem. Only to be used if no driver link exists in - * device directory. - * - * Returns 0 on SUCCESS and 1 on error + * get_dev_driver: fills in the dev->driver_name field + * Returns 0 on SUCCESS and -1 on error */ static int get_dev_driver(struct sysfs_device *dev) { - struct dlist *drvlist = NULL; - char path[SYSFS_PATH_MAX], devpath[SYSFS_PATH_MAX]; - char *drv = NULL, *c = NULL; - - if (dev == NULL) { + struct dlist *drvlist; + char path[SYSFS_PATH_MAX]; + char devpath[SYSFS_PATH_MAX]; + char *drv = NULL, *c; + + if (!dev) { errno = EINVAL; - return 1; + return -1; + } + + memset(path, 0, SYSFS_PATH_MAX); + memset(devpath, 0, SYSFS_PATH_MAX); + safestrcpymax(path, dev->path, SYSFS_PATH_MAX); + safestrcatmax(path, "/driver", SYSFS_PATH_MAX); + if (!sysfs_path_is_link(path)) { + if (!sysfs_get_link(path, devpath, SYSFS_PATH_MAX)) { + if (sysfs_get_name_from_path(devpath, + dev->driver_name, SYSFS_NAME_LEN)) + return -1; + } + return 0; } + + /* + * Devices on on earlier kernels do not have the "driver" link. + * Look it up in the bus directory. + */ if (dev->bus[0] == '\0') - return 1; + return -1; memset(path, 0, SYSFS_PATH_MAX); memset(devpath, 0, SYSFS_PATH_MAX); - safestrcpy(path, SYSFS_BUS_NAME); + safestrcpy(path, dev->path); + c = strstr(path, SYSFS_DEVICES_NAME); + if (c == NULL) { + dprintf("Invalid path to device - %s\n", dev->path); + return -1; + } else + *c = '\0'; + safestrcat(path, SYSFS_BUS_NAME); safestrcat(path, "/"); safestrcat(path, dev->bus); safestrcat(path, "/"); safestrcat(path, SYSFS_DRIVERS_NAME); - safestrcpy(devpath, dev->path); - c = strstr(devpath, SYSFS_DEVICES_NAME); - if (c == NULL) - return 1; - *c = '\0'; - safestrcatmax(c, path, (sizeof(devpath) - strlen(devpath))); - - drvlist = sysfs_open_subsystem_list(path); - if (drvlist != NULL) { + drvlist = sysfs_open_directory_list(path); + if (drvlist) { dlist_for_each_data(drvlist, drv, char) { - safestrcpy(path, devpath); - safestrcat(path, "/"); - safestrcat(path, drv); - safestrcat(path, "/"); - safestrcat(path, dev->bus_id); - if (sysfs_path_is_link(path) == 0) { + safestrcpy(devpath, path); + safestrcat(devpath, "/"); + safestrcat(devpath, drv); + safestrcat(devpath, "/"); + safestrcat(devpath, dev->bus_id); + if (sysfs_path_is_link(devpath) == 0) { safestrcpy(dev->driver_name, drv); sysfs_close_list(drvlist); return 0; @@ -73,35 +89,9 @@ static int get_dev_driver(struct sysfs_device *dev) } sysfs_close_list(drvlist); } - return 1; + return -1; } -/* - * get_device_driver_name: gets device's driver name, searches for driver - * link first before going the brute force route. - * @dev: device to retrieve driver - * returns 0 with success and 1 with error - */ -static int get_device_driver_name(struct sysfs_device *dev) -{ - char devpath[SYSFS_PATH_MAX], drvpath[SYSFS_PATH_MAX]; - - if (dev == NULL) { - errno = EINVAL; - return 1; - } - memset(devpath, 0, SYSFS_PATH_MAX); - memset(drvpath, 0, SYSFS_PATH_MAX); - safestrcpy(devpath, dev->path); - safestrcat(devpath, "/driver"); - - if ((sysfs_get_link(devpath, drvpath, SYSFS_PATH_MAX)) != 0) - return(get_dev_driver(dev)); - - return (sysfs_get_name_from_path(drvpath, dev->driver_name, - SYSFS_NAME_LEN)); -} - /** * sysfs_get_device_bus: retrieves the bus name the device is on, checks path * to bus' link to make sure it has correct device. @@ -110,31 +100,49 @@ static int get_device_driver_name(struct sysfs_device *dev) */ int sysfs_get_device_bus(struct sysfs_device *dev) { - char subsys[SYSFS_NAME_LEN], path[SYSFS_PATH_MAX]; - char target[SYSFS_PATH_MAX], *bus = NULL, *c = NULL; - struct dlist *buslist = NULL; + char devpath[SYSFS_PATH_MAX]; + char subsys[SYSFS_NAME_LEN]; + char path[SYSFS_PATH_MAX]; + char target[SYSFS_PATH_MAX]; + char *bus = NULL, *c; + struct dlist *buslist; - if (dev == NULL) { + if (!dev) { errno = EINVAL; return -1; } + memset(path, 0, SYSFS_PATH_MAX); + memset(devpath, 0, SYSFS_PATH_MAX); + safestrcpymax(path, dev->path, SYSFS_PATH_MAX); + safestrcatmax(path, "/bus", SYSFS_PATH_MAX); + if (!sysfs_path_is_link(path)) { + if (!sysfs_get_link(path, devpath, SYSFS_PATH_MAX)) { + if (sysfs_get_name_from_path(devpath, + dev->bus, SYSFS_NAME_LEN)) + return -1; + } + return 0; + } + + /* + * Devices on on earlier kernels do not have the "bus" link. + * Look it up in the bus directory. + */ memset(subsys, 0, SYSFS_NAME_LEN); - safestrcpy(subsys, SYSFS_BUS_NAME); /* subsys = bus */ - buslist = sysfs_open_subsystem_list(subsys); - if (buslist != NULL) { + safestrcpy(subsys, dev->path); + c = strstr(subsys, SYSFS_DEVICES_NAME); + if (c == NULL) { + dprintf("Invalid path to device - %s\n", dev->path); + return -1; + } else + *c = '\0'; + safestrcat(subsys, SYSFS_BUS_NAME); + buslist = sysfs_open_directory_list(subsys); + if (buslist) { dlist_for_each_data(buslist, bus, char) { memset(path, 0, SYSFS_PATH_MAX); - safestrcpy(path, dev->path); - c = strstr(path, "/devices"); - if (c == NULL) { - dprintf("Invalid path to device %s\n", path); - sysfs_close_list(buslist); - return -1; - } - *c = '\0'; - safestrcat(path, "/"); - safestrcat(path, SYSFS_BUS_NAME); + safestrcpy(path, subsys); safestrcat(path, "/"); safestrcat(path, bus); safestrcat(path, "/"); @@ -143,8 +151,8 @@ int sysfs_get_device_bus(struct sysfs_device *dev) safestrcat(path, dev->bus_id); if ((sysfs_path_is_link(path)) == 0) { memset(target, 0, SYSFS_PATH_MAX); - if ((sysfs_get_link(path, target, - SYSFS_PATH_MAX)) != 0) { + if (sysfs_get_link(path, target, + SYSFS_PATH_MAX)) { dprintf("Error getting link target\n"); sysfs_close_list(buslist); return -1; @@ -156,10 +164,10 @@ int sysfs_get_device_bus(struct sysfs_device *dev) return 0; } } - } - sysfs_close_list(buslist); - } - return -1; + } + sysfs_close_list(buslist); + } + return -1; } /** @@ -169,8 +177,8 @@ int sysfs_get_device_bus(struct sysfs_device *dev) */ void sysfs_close_device_tree(struct sysfs_device *devroot) { - if (devroot != NULL) { - if (devroot->children != NULL) { + if (devroot) { + if (devroot->children) { struct sysfs_device *child = NULL; dlist_for_each_data(devroot->children, child, @@ -183,26 +191,18 @@ void sysfs_close_device_tree(struct sysfs_device *devroot) } /** - * sysfs_close_dev_tree: routine for dlist integration - */ -static void sysfs_close_dev_tree(void *dev) -{ - sysfs_close_device_tree((struct sysfs_device *)dev); -} - -/** * sysfs_close_device: closes and cleans up a device * @dev = device to clean up */ void sysfs_close_device(struct sysfs_device *dev) { - if (dev != NULL) { - if (dev->parent != NULL) + if (dev) { + if (dev->parent) sysfs_close_device(dev->parent); - if (dev->directory != NULL) - sysfs_close_directory(dev->directory); - if (dev->children != NULL && dev->children->count == 0) + if (dev->children && dev->children->count) dlist_destroy(dev->children); + if (dev->attrlist) + dlist_destroy(dev->attrlist); free(dev); } } @@ -213,36 +213,7 @@ void sysfs_close_device(struct sysfs_device *dev) */ static struct sysfs_device *alloc_device(void) { - return (struct sysfs_device *)calloc(1, sizeof(struct sysfs_device)); -} - -/** - * open_device_dir: opens up sysfs_directory for specific root dev - * @name: name of root - * returns struct sysfs_directory with success and NULL with error - */ -static struct sysfs_directory *open_device_dir(const char *path) -{ - struct sysfs_directory *rdir = NULL; - - if (path == NULL) { - errno = EINVAL; - return NULL; - } - - rdir = sysfs_open_directory(path); - if (rdir == NULL) { - errno = EINVAL; - dprintf ("Device %s not supported on this system\n", path); - return NULL; - } - if ((sysfs_read_dir_subdirs(rdir)) != 0) { - dprintf ("Error reading device at dir %s\n", path); - sysfs_close_directory(rdir); - return NULL; - } - - return rdir; + return (struct sysfs_device *) calloc(1, sizeof(struct sysfs_device)); } /** @@ -252,45 +223,44 @@ static struct sysfs_directory *open_device_dir(const char *path) */ struct sysfs_device *sysfs_open_device_path(const char *path) { - struct sysfs_device *dev = NULL; + struct sysfs_device *dev; - if (path == NULL) { + if (!path) { errno = EINVAL; return NULL; } - if ((sysfs_path_is_dir(path)) != 0) { + if (sysfs_path_is_dir(path)) { dprintf("Incorrect path to device: %s\n", path); return NULL; } - dev = alloc_device(); - if (dev == NULL) { + dev = alloc_device(); + if (!dev) { dprintf("Error allocating device at %s\n", path); return NULL; } - if ((sysfs_get_name_from_path(path, dev->bus_id, - SYSFS_NAME_LEN)) != 0) { + if (sysfs_get_name_from_path(path, dev->bus_id, SYSFS_NAME_LEN)) { errno = EINVAL; dprintf("Error getting device bus_id\n"); sysfs_close_device(dev); return NULL; } safestrcpy(dev->path, path); - if ((sysfs_remove_trailing_slash(dev->path)) != 0) { + if (sysfs_remove_trailing_slash(dev->path)) { 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 * implies that the dev->name and dev->bus_id contain same data. */ safestrcpy(dev->name, dev->bus_id); - - if (sysfs_get_device_bus(dev) != 0) + + if (sysfs_get_device_bus(dev)) dprintf("Could not get device bus\n"); - - if (get_device_driver_name(dev) != 0) { + + if (get_dev_driver(dev)) { dprintf("Could not get device %s's driver\n", dev->bus_id); safestrcpy(dev->driver_name, SYSFS_UNKNOWN); } @@ -299,227 +269,33 @@ struct sysfs_device *sysfs_open_device_path(const char *path) } /** - * sysfs_open_device_tree: opens root device and all of its children, - * creating a tree of devices. Only opens children. - * @path: sysfs path to devices - * returns struct sysfs_device and its children with success or NULL with - * error. - */ -struct sysfs_device *sysfs_open_device_tree(const char *path) -{ - struct sysfs_device *rootdev = NULL, *new = NULL; - struct sysfs_directory *cur = NULL; - - if (path == NULL) { - errno = EINVAL; - return NULL; - } - rootdev = sysfs_open_device_path(path); - if (rootdev == NULL) { - dprintf("Error opening root device at %s\n", path); - return NULL; - } - if (rootdev->directory == NULL) { - rootdev->directory = open_device_dir(rootdev->path); - if (rootdev->directory == NULL) - return NULL; - } - if (rootdev->directory->subdirs != NULL) { - dlist_for_each_data(rootdev->directory->subdirs, cur, - struct sysfs_directory) { - new = sysfs_open_device_tree(cur->path); - if (new == NULL) { - dprintf("Error opening device tree at %s\n", - cur->path); - sysfs_close_device_tree(rootdev); - return NULL; - } - if (rootdev->children == NULL) - rootdev->children = dlist_new_with_delete - (sizeof(struct sysfs_device), - sysfs_close_dev_tree); - dlist_unshift_sorted(rootdev->children, - new, sort_list); - } - } - - return rootdev; -} - -/** - * sysfs_close_root_device: closes root and all devices - * @root: root device to close - */ -void sysfs_close_root_device(struct sysfs_root_device *root) -{ - if (root != NULL) { - if (root->devices != NULL) - dlist_destroy(root->devices); - if (root->directory != NULL) - sysfs_close_directory(root->directory); - free(root); - } -} - -/** - * sysfs_get_root_devices: opens up all the devices under this root device - * @root: root device to open devices for - * returns dlist of devices with success and NULL with error - */ -struct dlist *sysfs_get_root_devices(struct sysfs_root_device *root) -{ - struct sysfs_device *dev = NULL; - struct sysfs_directory *cur = NULL; - - if (root == NULL) { - errno = EINVAL; - return NULL; - } - if (root->directory == NULL) { - root->directory = open_device_dir(root->path); - if (root->directory == NULL) - return NULL; - } - - if (root->directory->subdirs == NULL) - return 0; - - dlist_for_each_data(root->directory->subdirs, cur, - struct sysfs_directory) { - dev = sysfs_open_device_tree(cur->path); - if (dev == NULL) { - dprintf ("Error opening device at %s\n", cur->path); - continue; - } - if (root->devices == NULL) - root->devices = dlist_new_with_delete - (sizeof(struct sysfs_device), - sysfs_close_dev_tree); - dlist_unshift_sorted(root->devices, dev, sort_list); - } - - return root->devices; -} - -/** - * sysfs_open_root_device: opens sysfs devices root and all of its - * devices. - * @name: name of /sys/devices/root to open - * returns struct sysfs_root_device if success and NULL with error - */ -struct sysfs_root_device *sysfs_open_root_device(const char *name) -{ - struct sysfs_root_device *root = NULL; - char rootpath[SYSFS_PATH_MAX]; - - if (name == NULL) { - errno = EINVAL; - return NULL; - } - - memset(rootpath, 0, SYSFS_PATH_MAX); - if (sysfs_get_mnt_path(rootpath, SYSFS_PATH_MAX) != 0) { - dprintf ("Sysfs not supported on this system\n"); - return NULL; - } - - safestrcat(rootpath, "/"); - safestrcat(rootpath, SYSFS_DEVICES_NAME); - safestrcat(rootpath, "/"); - safestrcat(rootpath, name); - if ((sysfs_path_is_dir(rootpath)) != 0) { - errno = EINVAL; - dprintf("Invalid root device: %s\n", name); - return NULL; - } - root = (struct sysfs_root_device *)calloc - (1, sizeof(struct sysfs_root_device)); - if (root == NULL) { - dprintf("calloc failure\n"); - return NULL; - } - safestrcpy(root->name, name); - safestrcpy(root->path, rootpath); - if ((sysfs_remove_trailing_slash(root->path)) != 0) { - dprintf("Invalid path to root device %s\n", root->path); - sysfs_close_root_device(root); - return NULL; - } - return root; -} - -/** - * sysfs_get_device_attributes: returns a dlist of attributes corresponding to - * the specific device - * @device: struct sysfs_device * for which attributes are to be returned - */ -struct dlist *sysfs_get_device_attributes(struct sysfs_device *device) -{ - if (device == NULL) { - errno = EINVAL; - return NULL; - } - - if (device->directory == NULL) { - device->directory = sysfs_open_directory(device->path); - if (device->directory == NULL) - return NULL; - } - if (device->directory->attributes == NULL) { - if ((sysfs_read_dir_attributes(device->directory)) != 0) - return NULL; - } - return (device->directory->attributes); -} - -/** - * sysfs_refresh_device_attributes: refreshes the device's list of attributes - * @device: sysfs_device whose attributes to refresh - * - * NOTE: Upon return, prior references to sysfs_attributes for this device - * _may_ not be valid - * - * Returns list of attributes on success and NULL on failure + * sysfs_get_device_attr: searches dev's attributes by name + * @dev: device to look through + * @name: attribute name to get + * returns sysfs_attribute reference with success or NULL with error. */ -struct dlist *sysfs_refresh_device_attributes(struct sysfs_device *device) +struct sysfs_attribute *sysfs_get_device_attr(struct sysfs_device *dev, + const char *name) { - if (device == NULL) { + if (!dev || !name) { 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); + return get_attribute(dev, (char *)name); } /** - * sysfs_get_device_attr: searches dev's attributes by name - * @dev: device to look through - * @name: attribute name to get - * returns sysfs_attribute reference with success or NULL with error. + * sysfs_get_device_attributes: gets list of device attributes + * @dev: device whose attributes list is needed + * returns dlist of attributes on success or NULL on error */ -struct sysfs_attribute *sysfs_get_device_attr(struct sysfs_device *dev, - const char *name) +struct dlist *sysfs_get_device_attributes(struct sysfs_device *dev) { - struct dlist *attrlist = NULL; - - if (dev == NULL || name == NULL) { + if (!dev) { errno = EINVAL; return NULL; } - - attrlist = sysfs_get_device_attributes(dev); - if (attrlist == NULL) - return NULL; - - return sysfs_get_directory_attribute(dev->directory, (char *)name); + return get_attributes_list(dev); } /** @@ -535,13 +311,13 @@ static int get_device_absolute_path(const char *device, const char *bus, { char bus_path[SYSFS_PATH_MAX]; - if (device == NULL || path == NULL) { + if (!device || !path) { errno = EINVAL; return -1; } memset(bus_path, 0, SYSFS_PATH_MAX); - if (sysfs_get_mnt_path(bus_path, SYSFS_PATH_MAX) != 0) { + if (sysfs_get_mnt_path(bus_path, SYSFS_PATH_MAX)) { dprintf ("Sysfs not supported on this system\n"); return -1; } @@ -557,7 +333,7 @@ static int get_device_absolute_path(const char *device, const char *bus, * We now are at /sys/bus/"bus_name"/devices/"device" which is a link. * Now read this link to reach to the device. */ - if ((sysfs_get_link(bus_path, path, psize)) != 0) { + if (sysfs_get_link(bus_path, path, psize)) { dprintf("Error getting to device %s\n", device); return -1; } @@ -578,21 +354,21 @@ static int get_device_absolute_path(const char *device, const char *bus, struct sysfs_device *sysfs_open_device(const char *bus, const char *bus_id) { char sysfs_path[SYSFS_PATH_MAX]; - struct sysfs_device *device = NULL; + struct sysfs_device *device; - if (bus_id == NULL || bus == NULL) { + if (!bus_id || !bus) { errno = EINVAL; return NULL; } memset(sysfs_path, 0, SYSFS_PATH_MAX); - if ((get_device_absolute_path(bus_id, bus, sysfs_path, - SYSFS_PATH_MAX)) != 0) { + if (get_device_absolute_path(bus_id, bus, sysfs_path, + SYSFS_PATH_MAX)) { dprintf("Error getting to device %s\n", bus_id); return NULL; } device = sysfs_open_device_path(sysfs_path); - if (device == NULL) { + if (!device) { dprintf("Error opening device %s\n", bus_id); return NULL; } @@ -608,20 +384,20 @@ struct sysfs_device *sysfs_open_device(const char *bus, const char *bus_id) */ struct sysfs_device *sysfs_get_device_parent(struct sysfs_device *dev) { - char ppath[SYSFS_PATH_MAX], *tmp = NULL; + char ppath[SYSFS_PATH_MAX], *tmp; - if (dev == NULL) { + if (!dev) { errno = EINVAL; return NULL; } - if (dev->parent != NULL) + if (dev->parent) return (dev->parent); memset(ppath, 0, SYSFS_PATH_MAX); safestrcpy(ppath, dev->path); tmp = strrchr(ppath, '/'); - if (tmp == NULL) { + if (!tmp) { dprintf("Invalid path to device %s\n", ppath); return NULL; } @@ -634,68 +410,22 @@ struct sysfs_device *sysfs_get_device_parent(struct sysfs_device *dev) } } *tmp = '\0'; - + /* * All "devices" have the "detach_state" attribute - validate here */ safestrcat(ppath, "/detach_state"); - if ((sysfs_path_is_file(ppath)) != 0) { + if (sysfs_path_is_file(ppath)) { dprintf("Device at %s does not have a parent\n", dev->path); return NULL; } tmp = strrchr(ppath, '/'); *tmp = '\0'; dev->parent = sysfs_open_device_path(ppath); - if (dev->parent == NULL) { + if (!dev->parent) { dprintf("Error opening device %s's parent at %s\n", dev->bus_id, ppath); return NULL; } return (dev->parent); } - -/* - * sysfs_open_device_attr: open the given device's attribute - * @bus: Bus on which to look - * @dev_id: device for which attribute is required - * @attrname: name of the attribute to look for - * Returns struct sysfs_attribute on success and NULL on failure - * - * NOTE: - * A call to sysfs_close_attribute() is required to close - * the attribute returned and free memory. - */ -struct sysfs_attribute *sysfs_open_device_attr(const char *bus, - const char *bus_id, const char *attrib) -{ - struct sysfs_attribute *attribute = NULL; - char devpath[SYSFS_PATH_MAX]; - - if (bus == NULL || bus_id == NULL || attrib == NULL) { - errno = EINVAL; - return NULL; - } - - memset(devpath, 0, SYSFS_PATH_MAX); - if ((get_device_absolute_path(bus_id, bus, devpath, - SYSFS_PATH_MAX)) != 0) { - dprintf("Error getting to device %s\n", bus_id); - return NULL; - } - safestrcat(devpath, "/"); - safestrcat(devpath, attrib); - attribute = sysfs_open_attribute(devpath); - if (attribute == NULL) { - dprintf("Error opening attribute %s for device %s\n", - attrib, bus_id); - return NULL; - } - if ((sysfs_read_attribute(attribute)) != 0) { - dprintf("Error reading attribute %s for device %s\n", - attrib, bus_id); - sysfs_close_attribute(attribute); - return NULL; - } - return attribute; -} - diff --git a/libsysfs/sysfs_dir.c b/libsysfs/sysfs_dir.c index 52769916cc..c86617934b 100644 --- a/libsysfs/sysfs_dir.c +++ b/libsysfs/sysfs_dir.c @@ -3,7 +3,7 @@ * * Directory utility functions for libsysfs * - * Copyright (C) IBM Corp. 2003 + * Copyright (C) IBM Corp. 2003-2005 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -23,39 +23,38 @@ #include "libsysfs.h" #include "sysfs.h" -/** - * sysfs_del_attribute: routine for dlist integration - */ -static void sysfs_del_attribute(void *attr) +static int sort_char(void *new, void *old) { - sysfs_close_attribute((struct sysfs_attribute *)attr); + return ((strncmp((char *)new, (char *)old, + strlen((char *)new))) < 0 ? 1 : 0); } /** - * sysfs_del_link: routine for dlist integration + * sysfs_del_name: free function for sysfs_open_subsystem_list + * @name: memory area to be freed */ -static void sysfs_del_link(void *ln) +static void sysfs_del_name(void *name) { - sysfs_close_link((struct sysfs_link *)ln); + free(name); } /** - * sysfs_del_dir: routine for dlist integration + * sysfs_del_attribute: routine for dlist integration */ -static void sysfs_del_directory(void *dir) +static void sysfs_del_attribute(void *attr) { - sysfs_close_directory((struct sysfs_directory *)dir); + sysfs_close_attribute((struct sysfs_attribute *)attr); } /** - * dir_attribute_name_equal: compares dir attributes by name + * attr_name_equal: compares attributes by name * @a: attribute name for comparison * @b: sysfs_attribute to be compared. * returns 1 if a==b->name or 0 if not equal */ -static int dir_attribute_name_equal(void *a, void *b) +static int attr_name_equal(void *a, void *b) { - if (a == NULL || b == NULL) + if (!a || !b) return 0; if (strcmp(((char *)a), ((struct sysfs_attribute *)b)->name) == 0) @@ -65,47 +64,13 @@ static int dir_attribute_name_equal(void *a, void *b) } /** - * dir_link_name_equal: compares dir links by name - * @a: link name for comparison - * @b: sysfs_link to be compared. - * returns 1 if a==b->name or 0 if not equal - */ -static int dir_link_name_equal(void *a, void *b) -{ - if (a == NULL || b == NULL) - return 0; - - if (strcmp(((char *)a), ((struct sysfs_link *)b)->name) == 0) - return 1; - - return 0; -} - -/** - * dir_subdir_name_equal: compares subdirs by name - * @a: name of subdirectory to compare - * @b: sysfs_directory subdirectory to be compared - * returns 1 if a==b->name or 0 if not equal - */ -static int dir_subdir_name_equal(void *a, void *b) -{ - if (a == NULL || b == NULL) - return 0; - - if (strcmp(((char *)a), ((struct sysfs_directory *)b)->name) == 0) - return 1; - - return 0; -} - -/** * sysfs_close_attribute: closes and cleans up attribute * @sysattr: attribute to close. */ void sysfs_close_attribute(struct sysfs_attribute *sysattr) { - if (sysattr != NULL) { - if (sysattr->value != NULL) + if (sysattr) { + if (sysattr->value) free(sysattr->value); free(sysattr); } @@ -130,13 +95,13 @@ struct sysfs_attribute *sysfs_open_attribute(const char *path) { struct sysfs_attribute *sysattr = NULL; struct stat fileinfo; - - if (path == NULL) { + + if (!path) { errno = EINVAL; return NULL; } sysattr = alloc_attribute(); - if (sysattr == NULL) { + if (!sysattr) { dprintf("Error allocating attribute at %s\n", path); return NULL; } @@ -163,94 +128,6 @@ struct sysfs_attribute *sysfs_open_attribute(const char *path) } /** - * sysfs_write_attribute: write value to the attribute - * @sysattr: attribute to write - * @new_value: value to write - * @len: length of "new_value" - * returns 0 with success and -1 with error. - */ -int sysfs_write_attribute(struct sysfs_attribute *sysattr, - const char *new_value, size_t len) -{ - int fd; - int length; - - if (sysattr == NULL || new_value == NULL || len == 0) { - errno = EINVAL; - return -1; - } - - if (!(sysattr->method & SYSFS_METHOD_STORE)) { - dprintf ("Store method not supported for attribute %s\n", - sysattr->path); - errno = EACCES; - return -1; - } - if (sysattr->method & SYSFS_METHOD_SHOW) { - /* - * read attribute again to see if we can get an updated value - */ - if ((sysfs_read_attribute(sysattr)) != 0) { - dprintf("Error reading attribute\n"); - return -1; - } - if ((strncmp(sysattr->value, new_value, sysattr->len)) == 0) { - dprintf("Attr %s already has the requested value %s\n", - sysattr->name, new_value); - return 0; - } - } - /* - * open O_WRONLY since some attributes have no "read" but only - * "write" permission - */ - if ((fd = open(sysattr->path, O_WRONLY)) < 0) { - dprintf("Error reading attribute %s\n", sysattr->path); - return -1; - } - - length = write(fd, new_value, len); - if (length < 0) { - dprintf("Error writing to the attribute %s - invalid value?\n", - sysattr->name); - close(fd); - return -1; - } else if ((unsigned int)length != len) { - dprintf("Could not write %d bytes to attribute %s\n", - len, sysattr->name); - /* - * since we could not write user supplied number of bytes, - * restore the old value if one available - */ - if (sysattr->method & SYSFS_METHOD_SHOW) { - length = write(fd, sysattr->value, sysattr->len); - close(fd); - return -1; - } - } - - /* - * Validate length that has been copied. Alloc appropriate area - * in sysfs_attribute. Verify first if the attribute supports reading - * (show method). If it does not, do not bother - */ - if (sysattr->method & SYSFS_METHOD_SHOW) { - if (length != sysattr->len) { - sysattr->value = (char *)realloc - (sysattr->value, length); - sysattr->len = length; - safestrcpymax(sysattr->value, new_value, length); - } else { - /*"length" of the new value is same as old one */ - safestrcpymax(sysattr->value, new_value, length); - } - } - - close(fd); - return 0; -} - -/** * sysfs_read_attribute: reads value from attribute * @sysattr: attribute to read * returns 0 with success and -1 with error. @@ -263,7 +140,7 @@ int sysfs_read_attribute(struct sysfs_attribute *sysattr) long pgsize = 0; int fd; - if (sysattr == NULL) { + if (!sysattr) { errno = EINVAL; return -1; } @@ -275,7 +152,7 @@ int sysfs_read_attribute(struct sysfs_attribute *sysattr) } pgsize = sysconf(_SC_PAGESIZE); fbuf = (char *)calloc(1, pgsize+1); - if (fbuf == NULL) { + if (!fbuf) { dprintf("calloc failed\n"); return -1; } @@ -303,7 +180,7 @@ int sysfs_read_attribute(struct sysfs_attribute *sysattr) sysattr->len = length; close(fd); vbuf = (char *)realloc(fbuf, length+1); - if (vbuf == NULL) { + if (!vbuf) { dprintf("realloc failed\n"); free(fbuf); return -1; @@ -314,758 +191,301 @@ int sysfs_read_attribute(struct sysfs_attribute *sysattr) } /** - * sysfs_read_attribute_value: given path to attribute, return its value. - * values can be up to a pagesize, if buffer is smaller the value will - * be truncated. - * @attrpath: sysfs path to attribute - * @value: buffer to put value - * @vsize: size of value buffer + * sysfs_write_attribute: write value to the attribute + * @sysattr: attribute to write + * @new_value: value to write + * @len: length of "new_value" * returns 0 with success and -1 with error. */ -int sysfs_read_attribute_value(const char *attrpath, - char *value, size_t vsize) +int sysfs_write_attribute(struct sysfs_attribute *sysattr, + const char *new_value, size_t len) { - struct sysfs_attribute *attr = NULL; - size_t length = 0; + int fd; + int length; - if (attrpath == NULL || value == NULL || vsize == 0) { + if (!sysattr || !new_value || len == 0) { errno = EINVAL; return -1; } - attr = sysfs_open_attribute(attrpath); - if (attr == NULL) { - dprintf("Invalid attribute path %s\n", attrpath); - errno = EINVAL; - return -1; - } - if((sysfs_read_attribute(attr)) != 0 || attr->value == NULL) { - dprintf("Error reading from attribute %s\n", attrpath); - sysfs_close_attribute(attr); + if (!(sysattr->method & SYSFS_METHOD_STORE)) { + dprintf ("Store method not supported for attribute %s\n", + sysattr->path); + errno = EACCES; return -1; } - length = strlen(attr->value); - if (length > vsize) - dprintf("Value length %d is larger than supplied buffer %d\n", - length, vsize); - safestrcpymax(value, attr->value, vsize); - sysfs_close_attribute(attr); - - return 0; -} - -/** - * sysfs_get_value_from_attrbutes: given a linked list of attributes and an - * attribute name, return its value - * @attr: attribute to search - * @name: name to look for - * returns char * value - could be NULL - */ -char *sysfs_get_value_from_attributes(struct dlist *attr, const char *name) -{ - struct sysfs_attribute *cur = NULL; - - if (attr == NULL || name == NULL) { - errno = EINVAL; - return NULL; - } - dlist_for_each_data(attr, cur, struct sysfs_attribute) { - if (strcmp(cur->name, name) == 0) - return cur->value; + if (sysattr->method & SYSFS_METHOD_SHOW) { + /* + * read attribute again to see if we can get an updated value + */ + if ((sysfs_read_attribute(sysattr))) { + dprintf("Error reading attribute\n"); + return -1; + } + if ((strncmp(sysattr->value, new_value, sysattr->len)) == 0) { + dprintf("Attr %s already has the requested value %s\n", + sysattr->name, new_value); + return 0; + } } - return NULL; -} - -/** - * sysfs_close_link: closes and cleans up link. - * @ln: link to close. - */ -void sysfs_close_link(struct sysfs_link *ln) -{ - if (ln != NULL) - free(ln); -} - -/** - * sysfs_close_directory: closes directory, cleans up attributes and links - * @sysdir: sysfs_directory to close - */ -void sysfs_close_directory(struct sysfs_directory *sysdir) -{ - if (sysdir != NULL) { - if (sysdir->subdirs != NULL) - dlist_destroy(sysdir->subdirs); - if (sysdir->links != NULL) - dlist_destroy(sysdir->links); - if (sysdir->attributes != NULL) - dlist_destroy(sysdir->attributes); - free(sysdir); - sysdir = NULL; + /* + * open O_WRONLY since some attributes have no "read" but only + * "write" permission + */ + if ((fd = open(sysattr->path, O_WRONLY)) < 0) { + dprintf("Error reading attribute %s\n", sysattr->path); + return -1; } -} - -/** - * alloc_directory: allocates and initializes directory structure - * returns struct sysfs_directory with success or NULL with error. - */ -static struct sysfs_directory *alloc_directory(void) -{ - return (struct sysfs_directory *) - calloc(1, sizeof(struct sysfs_directory)); -} - -/** - * alloc_link: allocates and initializes link structure - * returns struct sysfs_link with success or NULL with error. - */ -static struct sysfs_link *alloc_link(void) -{ - return (struct sysfs_link *)calloc(1, sizeof(struct sysfs_link)); -} - -/** - * sysfs_read_all_subdirs: calls sysfs_read_directory for all subdirs - * @sysdir: directory whose subdirs need reading. - * returns 0 with success and -1 with error. - */ -int sysfs_read_all_subdirs(struct sysfs_directory *sysdir) -{ - struct sysfs_directory *cursub = NULL; - int retval = 0; - if (sysdir == NULL) { - errno = EINVAL; + length = write(fd, new_value, len); + if (length < 0) { + dprintf("Error writing to the attribute %s - invalid value?\n", + sysattr->name); + close(fd); return -1; - } - if (sysdir->subdirs == NULL) - if ((sysfs_read_dir_subdirs(sysdir)) != 0) - return 0; - if (sysdir->subdirs != NULL) { - dlist_for_each_data(sysdir->subdirs, cursub, - struct sysfs_directory) { - if ((sysfs_read_dir_subdirs(cursub)) != 0) { - dprintf ("Error reading subdirectory %s\n", - cursub->name); - retval = -1; - } + } else if ((unsigned int)length != len) { + dprintf("Could not write %d bytes to attribute %s\n", + len, sysattr->name); + /* + * since we could not write user supplied number of bytes, + * restore the old value if one available + */ + if (sysattr->method & SYSFS_METHOD_SHOW) { + length = write(fd, sysattr->value, sysattr->len); + close(fd); + return -1; } } - if (!retval) - errno = 0; - return retval; -} -/** - * sysfs_open_directory: opens a sysfs directory, creates dir struct, and - * returns. - * @path: path of directory to open. - * returns: struct sysfs_directory * with success and NULL on error. - */ -struct sysfs_directory *sysfs_open_directory(const char *path) -{ - struct sysfs_directory *sdir = NULL; - - if (path == NULL) { - errno = EINVAL; - return NULL; - } - - if (sysfs_path_is_dir(path) != 0) { - dprintf("Invalid path to directory %s\n", path); - errno = EINVAL; - return NULL; - } - - sdir = alloc_directory(); - if (sdir == NULL) { - dprintf("Error allocating directory %s\n", path); - return NULL; - } - if (sysfs_get_name_from_path(path, sdir->name, SYSFS_NAME_LEN) != 0) { - dprintf("Error getting directory name from path: %s\n", path); - sysfs_close_directory(sdir); - return NULL; - } - safestrcpy(sdir->path, path); - - return sdir; -} - -/** - * sysfs_open_link: opens a sysfs link, creates struct, and returns - * @path: path of link to open. - * returns: struct sysfs_link * with success and NULL on error. - */ -struct sysfs_link *sysfs_open_link(const char *linkpath) -{ - struct sysfs_link *ln = NULL; - - if (linkpath == NULL || strlen(linkpath) > SYSFS_PATH_MAX) { - errno = EINVAL; - return NULL; - } - - ln = alloc_link(); - if (ln == NULL) { - dprintf("Error allocating link %s\n", linkpath); - return NULL; - } - safestrcpy(ln->path, linkpath); - if ((sysfs_get_name_from_path(linkpath, ln->name, SYSFS_NAME_LEN)) != 0 - || (sysfs_get_link(linkpath, ln->target, SYSFS_PATH_MAX)) != 0) { - sysfs_close_link(ln); - errno = EINVAL; - dprintf("Invalid link path %s\n", linkpath); - return NULL; + /* + * Validate length that has been copied. Alloc appropriate area + * in sysfs_attribute. Verify first if the attribute supports reading + * (show method). If it does not, do not bother + */ + if (sysattr->method & SYSFS_METHOD_SHOW) { + if (length != sysattr->len) { + sysattr->value = (char *)realloc + (sysattr->value, length); + sysattr->len = length; + safestrcpymax(sysattr->value, new_value, length); + } else { + /*"length" of the new value is same as old one */ + safestrcpymax(sysattr->value, new_value, length); + } } - - return ln; + + close(fd); + return 0; } /** * add_attribute: open and add attribute at path to given directory - * @sysdir: directory to add attribute to + * @dev: device whose attribute is to be added * @path: path to attribute - * returns 0 with success and -1 with error. + * returns pointer to attr added with success and NULL with error. */ -static int add_attribute(struct sysfs_directory *sysdir, const char *path) +static struct sysfs_attribute *add_attribute(void *dev, const char *path) { - struct sysfs_attribute *attr = NULL; + struct sysfs_attribute *attr; attr = sysfs_open_attribute(path); - if (attr == NULL) { + if (!attr) { dprintf("Error opening attribute %s\n", path); - return -1; + return NULL; } if (attr->method & SYSFS_METHOD_SHOW) { - if ((sysfs_read_attribute(attr)) != 0) { + if (sysfs_read_attribute(attr)) { dprintf("Error reading attribute %s\n", path); sysfs_close_attribute(attr); - return 0; + return NULL; } } - - if (sysdir->attributes == NULL) { - sysdir->attributes = dlist_new_with_delete - (sizeof(struct sysfs_attribute), sysfs_del_attribute); - } - dlist_unshift_sorted(sysdir->attributes, attr, sort_list); - - return 0; -} - -/** - * add_subdirectory: open and add subdirectory at path to given directory - * @sysdir: directory to add subdir to - * @path: path to subdirectory - * returns 0 with success and -1 with error. - */ -static int add_subdirectory(struct sysfs_directory *sysdir, const char *path) -{ - struct sysfs_directory *subdir = NULL; - subdir = sysfs_open_directory(path); - if (subdir == NULL) { - dprintf("Error opening directory %s\n", path); - return -1; + if (!((struct sysfs_device *)dev)->attrlist) { + ((struct sysfs_device *)dev)->attrlist = dlist_new_with_delete + (sizeof(struct sysfs_attribute), sysfs_del_attribute); } - if (sysdir->subdirs == NULL) - sysdir->subdirs = dlist_new_with_delete - (sizeof(struct sysfs_directory), sysfs_del_directory); - dlist_unshift_sorted(sysdir->subdirs, subdir, sort_list); - return 0; -} + dlist_unshift_sorted(((struct sysfs_device *)dev)->attrlist, + attr, sort_list); -/** - * add_link: open and add link at path to given directory - * @sysdir: directory to add link to - * @path: path to link - * returns 0 with success and -1 with error. - */ -static int add_link(struct sysfs_directory *sysdir, const char *path) -{ - struct sysfs_link *ln = NULL; - - ln = sysfs_open_link(path); - if (ln == NULL) { - dprintf("Error opening link %s\n", path); - return -1; - } - if (sysdir->links == NULL) - sysdir->links = dlist_new_with_delete - (sizeof(struct sysfs_link), sysfs_del_link); - dlist_unshift_sorted(sysdir->links, ln, sort_list); - return 0; + return attr; } -/** - * sysfs_read_dir_attributes: grabs attributes for the given directory - * @sysdir: sysfs directory to open - * returns 0 with success and -1 with error. +/* + * get_attribute - given a sysfs_* struct and a name, return the + * sysfs_attribute corresponding to "name" + * returns sysfs_attribute on success and NULL on error */ -int sysfs_read_dir_attributes(struct sysfs_directory *sysdir) +struct sysfs_attribute *get_attribute(void *dev, const char *name) { - DIR *dir = NULL; - struct dirent *dirent = NULL; - char file_path[SYSFS_PATH_MAX]; - int retval = 0; + struct sysfs_attribute *cur = NULL; + char path[SYSFS_PATH_MAX]; - if (sysdir == NULL) { + if (!dev || !name) { errno = EINVAL; - return -1; - } - dir = opendir(sysdir->path); - if (dir == NULL) { - dprintf("Error opening directory %s\n", sysdir->path); - return -1; + return NULL; } - while(((dirent = readdir(dir)) != NULL) && retval == 0) { - if (0 == strcmp(dirent->d_name, ".")) - continue; - if (0 == strcmp(dirent->d_name, "..")) - continue; - memset(file_path, 0, SYSFS_PATH_MAX); - safestrcpy(file_path, sysdir->path); - safestrcat(file_path, "/"); - safestrcat(file_path, dirent->d_name); - if ((sysfs_path_is_file(file_path)) == 0) - retval = add_attribute(sysdir, file_path); + + if (((struct sysfs_device *)dev)->attrlist) { + /* check if attr is already in the list */ + cur = (struct sysfs_attribute *)dlist_find_custom + ((((struct sysfs_device *)dev)->attrlist), + (void *)name, attr_name_equal); + if (cur) + return cur; } - closedir(dir); - if (!retval) - errno = 0; - return(retval); + safestrcpymax(path, ((struct sysfs_device *)dev)->path, + SYSFS_PATH_MAX); + safestrcatmax(path, "/", SYSFS_PATH_MAX); + safestrcatmax(path, name, SYSFS_PATH_MAX); + if (!(sysfs_path_is_file(path))) + cur = add_attribute((void *)dev, path); + return cur; } /** - * sysfs_read_dir_links: grabs links in a specific directory - * @sysdir: sysfs directory to read links - * returns 0 with success and -1 with error. + * read_dir_links: grabs links in a specific directory + * @sysdir: sysfs directory to read + * returns list of link names with success and NULL with error. */ -int sysfs_read_dir_links(struct sysfs_directory *sysdir) +struct dlist *read_dir_links(const char *path) { DIR *dir = NULL; struct dirent *dirent = NULL; - char file_path[SYSFS_PATH_MAX]; - int retval = 0; + char file_path[SYSFS_PATH_MAX], *linkname; + struct dlist *linklist = NULL; - if (sysdir == NULL) { + if (!path) { errno = EINVAL; - return -1; + return NULL; } - dir = opendir(sysdir->path); - if (dir == NULL) { - dprintf("Error opening directory %s\n", sysdir->path); - return -1; + dir = opendir(path); + if (!dir) { + dprintf("Error opening directory %s\n", path); + return NULL; } - while(((dirent = readdir(dir)) != NULL) && retval == 0) { + while ((dirent = readdir(dir)) != NULL) { if (0 == strcmp(dirent->d_name, ".")) continue; if (0 == strcmp(dirent->d_name, "..")) continue; memset(file_path, 0, SYSFS_PATH_MAX); - safestrcpy(file_path, sysdir->path); + safestrcpy(file_path, path); safestrcat(file_path, "/"); safestrcat(file_path, dirent->d_name); if ((sysfs_path_is_link(file_path)) == 0) { - retval = add_link(sysdir, file_path); - if (retval != 0) - break; + if (!linklist) { + linklist = dlist_new_with_delete + (SYSFS_NAME_LEN, sysfs_del_name); + if (!linklist) { + dprintf("Error creating list\n"); + return NULL; + } + } + linkname = (char *)calloc(1, SYSFS_NAME_LEN); + safestrcpymax(linkname, dirent->d_name, SYSFS_NAME_LEN); + dlist_unshift_sorted(linklist, linkname, sort_char); } } closedir(dir); - if (!retval) - errno = 0; - return(retval); + return linklist; } /** - * sysfs_read_dir_subdirs: grabs subdirs in a specific directory - * @sysdir: sysfs directory to read links - * returns 0 with success and -1 with error. + * read_dir_subdirs: grabs subdirs in a specific directory + * @sysdir: sysfs directory to read + * returns list of directory names with success and NULL with error. */ -int sysfs_read_dir_subdirs(struct sysfs_directory *sysdir) +struct dlist *read_dir_subdirs(const char *path) { DIR *dir = NULL; struct dirent *dirent = NULL; - char file_path[SYSFS_PATH_MAX]; - int retval = 0; + char file_path[SYSFS_PATH_MAX], *dir_name; + struct dlist *dirlist = NULL; - if (sysdir == NULL) { + if (!path) { errno = EINVAL; - return -1; + return NULL; } - dir = opendir(sysdir->path); - if (dir == NULL) { - dprintf("Error opening directory %s\n", sysdir->path); - return -1; + dir = opendir(path); + if (!dir) { + dprintf("Error opening directory %s\n", path); + return NULL; } - while(((dirent = readdir(dir)) != NULL) && retval == 0) { + while ((dirent = readdir(dir)) != NULL) { if (0 == strcmp(dirent->d_name, ".")) continue; if (0 == strcmp(dirent->d_name, "..")) continue; memset(file_path, 0, SYSFS_PATH_MAX); - safestrcpy(file_path, sysdir->path); + safestrcpy(file_path, path); safestrcat(file_path, "/"); safestrcat(file_path, dirent->d_name); - if ((sysfs_path_is_dir(file_path)) == 0) - retval = add_subdirectory(sysdir, file_path); + if ((sysfs_path_is_dir(file_path)) == 0) { + if (!dirlist) { + dirlist = dlist_new_with_delete + (SYSFS_NAME_LEN, sysfs_del_name); + if (!dirlist) { + dprintf("Error creating list\n"); + return NULL; + } + } + dir_name = (char *)calloc(1, SYSFS_NAME_LEN); + safestrcpymax(dir_name, dirent->d_name, SYSFS_NAME_LEN); + dlist_unshift_sorted(dirlist, dir_name, sort_char); + } } closedir(dir); - if (!retval) - errno = 0; - return(retval); + return dirlist; } /** - * sysfs_read_directory: grabs attributes, links, and subdirectories - * @sysdir: sysfs directory to open - * returns 0 with success and -1 with error. + * get_attributes_list: build a list of attributes for the given device + * @dev: devices whose attributes list is required + * returns dlist of attributes on success and NULL on failure */ -int sysfs_read_directory(struct sysfs_directory *sysdir) +struct dlist *get_attributes_list(void *dev) { DIR *dir = NULL; struct dirent *dirent = NULL; - struct stat astats; - char file_path[SYSFS_PATH_MAX]; - int retval = 0; + struct sysfs_attribute *attr = NULL; + char file_path[SYSFS_PATH_MAX], path[SYSFS_PATH_MAX]; - if (sysdir == NULL) { + if (!dev) { errno = EINVAL; - return -1; + return NULL; } - dir = opendir(sysdir->path); - if (dir == NULL) { - dprintf("Error opening directory %s\n", sysdir->path); - return -1; + memset(path, 0, SYSFS_PATH_MAX); + safestrcpy(path, ((struct sysfs_device *)dev)->path); + dir = opendir(path); + if (!dir) { + dprintf("Error opening directory %s\n", path); + return NULL; } - while(((dirent = readdir(dir)) != NULL) && retval == 0) { + while ((dirent = readdir(dir)) != NULL) { if (0 == strcmp(dirent->d_name, ".")) continue; if (0 == strcmp(dirent->d_name, "..")) continue; memset(file_path, 0, SYSFS_PATH_MAX); - safestrcpy(file_path, sysdir->path); + safestrcpy(file_path, path); safestrcat(file_path, "/"); safestrcat(file_path, dirent->d_name); - if ((lstat(file_path, &astats)) != 0) { - dprintf("stat failed\n"); - continue; - } - if (S_ISDIR(astats.st_mode)) - retval = add_subdirectory(sysdir, file_path); - - else if (S_ISLNK(astats.st_mode)) - retval = add_link(sysdir, file_path); - - else if (S_ISREG(astats.st_mode)) - retval = add_attribute(sysdir, file_path); - } - closedir(dir); - if (!retval) - errno = 0; - 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; - } - errno = 0; - return 0; -} - -/** - * sysfs_refresh_dir_links: Refresh links list - * @sysdir: directory whose list of links to refresh - * Returns 0 on success, 1 on failure - */ -int sysfs_refresh_dir_links(struct sysfs_directory *sysdir) -{ - if (sysdir == NULL) { - errno = EINVAL; - return 1; - } - if ((sysfs_path_is_dir(sysdir->path)) != 0) { - dprintf("Invalid path to directory %s\n", sysdir->path); - errno = EINVAL; - return 1; - } - if (sysdir->links != NULL) { - dlist_destroy(sysdir->links); - sysdir->links = NULL; - } - if ((sysfs_read_dir_links(sysdir)) != 0) { - dprintf("Error refreshing links for directory %s\n", - sysdir->path); - return 1; - } - errno = 0; - return 0; -} - -/** - * sysfs_refresh_dir_subdirs: Refresh subdirs list - * @sysdir: directory whose list of subdirs to refresh - * Returns 0 on success, 1 on failure - */ -int sysfs_refresh_dir_subdirs(struct sysfs_directory *sysdir) -{ - if (sysdir == NULL) { - errno = EINVAL; - return 1; - } - if ((sysfs_path_is_dir(sysdir->path)) != 0) { - dprintf("Invalid path to directory %s\n", sysdir->path); - errno = EINVAL; - return 1; - } - if (sysdir->subdirs != NULL) { - dlist_destroy(sysdir->subdirs); - sysdir->subdirs = NULL; - } - if ((sysfs_read_dir_subdirs(sysdir)) != 0) { - dprintf("Error refreshing subdirs for directory %s\n", - sysdir->path); - return 1; - } - errno = 0; - return 0; -} - -/** - * sysfs_get_directory_attribute: retrieves attribute attrname from current - * directory only - * @dir: directory to retrieve attribute from - * @attrname: name of attribute to look for - * - * NOTE: Since we know the attribute to look for, this routine looks for the - * attribute if it was created _after_ the attrlist was read initially. - * - * returns sysfs_attribute if found and NULL if not found - */ -struct sysfs_attribute *sysfs_get_directory_attribute - (struct sysfs_directory *dir, char *attrname) -{ - struct sysfs_attribute *attr = NULL; - char new_path[SYSFS_PATH_MAX]; - - if (dir == NULL || attrname == NULL) { - errno = EINVAL; - return NULL; - } - - if (dir->attributes == NULL) - if ((sysfs_read_dir_attributes(dir) != 0) - || (dir->attributes == NULL)) - return NULL; - - attr = (struct sysfs_attribute *)dlist_find_custom - (dir->attributes, attrname, dir_attribute_name_equal); - if (attr != NULL) { - if ((attr->method & SYSFS_METHOD_SHOW) && - (sysfs_read_attribute(attr)) != 0) { - dprintf("Error reading attribute %s\n", attr->name); - return NULL; - } - } else { - memset(new_path, 0, SYSFS_PATH_MAX); - safestrcpy(new_path, dir->path); - safestrcat(new_path, "/"); - safestrcat(new_path, attrname); - if ((sysfs_path_is_file(new_path)) == 0) { - if ((add_attribute(dir, new_path)) == 0) { + if ((sysfs_path_is_file(file_path)) == 0) { + if (((struct sysfs_device *)dev)->attrlist) { + /* check if attr is already in the list */ attr = (struct sysfs_attribute *) - dlist_find_custom(dir->attributes, - attrname, dir_attribute_name_equal); - } - } - } - - return attr; -} - -/** - * sysfs_get_directory_link: retrieves link from one directory list - * @dir: directory to retrieve link from - * @linkname: name of link to look for - * returns reference to sysfs_link if found and NULL if not found - */ -struct sysfs_link *sysfs_get_directory_link - (struct sysfs_directory *dir, char *linkname) -{ - if (dir == NULL || linkname == NULL) { - errno = EINVAL; - return NULL; - } - if (dir->links == NULL) { - if ((sysfs_read_dir_links(dir) != 0) || (dir->links == NULL)) - return NULL; - } else { - if ((sysfs_refresh_dir_links(dir)) != 0) - return NULL; - } - - return (struct sysfs_link *)dlist_find_custom(dir->links, - linkname, dir_link_name_equal); -} - -/** - * sysfs_get_subdirectory: retrieves subdirectory by name. - * @dir: directory to search for subdirectory. - * @subname: subdirectory name to get. - * returns reference to subdirectory or NULL if not found - */ -struct sysfs_directory *sysfs_get_subdirectory(struct sysfs_directory *dir, - char *subname) -{ - struct sysfs_directory *sub = NULL, *cursub = NULL; - - if (dir == NULL || subname == NULL) { - errno = EINVAL; - return NULL; - } - - if (dir->subdirs == NULL) - if (sysfs_read_dir_subdirs(dir) != 0) - return NULL; - - sub = (struct sysfs_directory *)dlist_find_custom(dir->subdirs, - subname, dir_subdir_name_equal); - if (sub != NULL) - return sub; - - if (dir->subdirs != NULL) { - dlist_for_each_data(dir->subdirs, cursub, - struct sysfs_directory) { - if (cursub->subdirs == NULL) { - if (sysfs_read_dir_subdirs(cursub) != 0) - continue; - if (cursub->subdirs == NULL) + dlist_find_custom + ((((struct sysfs_device *)dev)->attrlist), + (void *)dirent->d_name, attr_name_equal); + if (attr) continue; - } - sub = sysfs_get_subdirectory(cursub, subname); - if (sub != NULL) - return sub; - } - } - return NULL; -} - -/** - * sysfs_get_subdirectory_link: looks through all subdirs for specific link. - * @dir: directory and subdirectories to search for link. - * @linkname: link name to get. - * returns reference to link or NULL if not found - */ -struct sysfs_link *sysfs_get_subdirectory_link(struct sysfs_directory *dir, - char *linkname) -{ - struct sysfs_directory *cursub = NULL; - struct sysfs_link *ln = NULL; - - if (dir == NULL || linkname == NULL) { - errno = EINVAL; - return NULL; - } - - ln = sysfs_get_directory_link(dir, linkname); - if (ln != NULL) - return ln; - - if (dir->subdirs == NULL) - if (sysfs_read_dir_subdirs(dir) != 0) - return NULL; - - if (dir->subdirs != NULL) { - dlist_for_each_data(dir->subdirs, cursub, - struct sysfs_directory) { - ln = sysfs_get_subdirectory_link(cursub, linkname); - if (ln != NULL) - return ln; + else + add_attribute(dev, file_path); + } else + attr = add_attribute(dev, file_path); } } - 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); + closedir(dir); + return ((struct sysfs_device *)dev)->attrlist; } diff --git a/libsysfs/sysfs_driver.c b/libsysfs/sysfs_driver.c index 88d26b56dd..c2464faa9e 100644 --- a/libsysfs/sysfs_driver.c +++ b/libsysfs/sysfs_driver.c @@ -3,7 +3,7 @@ * * Driver utility functions for libsysfs * - * Copyright (C) IBM Corp. 2003 + * Copyright (C) IBM Corp. 2003-2005 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -28,42 +28,20 @@ static void sysfs_close_driver_device(void *device) sysfs_close_device((struct sysfs_device *)device); } -/** +/** * sysfs_close_driver: closes driver and deletes device lists too * @driver: driver to close - */ + */ void sysfs_close_driver(struct sysfs_driver *driver) { - if (driver != NULL) { - if (driver->devices != NULL) + if (driver) { + if (driver->devices) dlist_destroy(driver->devices); - if (driver->directory != NULL) - sysfs_close_directory(driver->directory); + if (driver->attrlist) + dlist_destroy(driver->attrlist); free(driver); } } - -/** - * open_driver_dir: Open the sysfs_directory for this driver - * @driver: Driver whose directory to be opened - * Returns 0 on success and 1 on failure - */ -static int open_driver_dir(struct sysfs_driver *driver) -{ - if (driver == NULL) { - errno = EINVAL; - return 1; - } - if (driver->directory == NULL) { - driver->directory = sysfs_open_directory(driver->path); - if (driver->directory == NULL) { - dprintf("Error opening driver directory at %s\n", - driver->path); - return 1; - } - } - return 0; -} /** * alloc_driver: allocates and initializes driver @@ -75,244 +53,104 @@ static struct sysfs_driver *alloc_driver(void) } /** - * sysfs_open_driver_path: opens and initializes driver structure - * @path: path to driver directory - * returns struct sysfs_driver with success and NULL with error + * get_driver_bus: gets bus the driver is on + * Returns 0 on success and 1 on error */ -struct sysfs_driver *sysfs_open_driver_path(const char *path) +static int get_driver_bus(struct sysfs_driver *drv) { - struct sysfs_driver *driver = NULL; - - if (path == NULL) { - errno = EINVAL; - return NULL; - } - if ((sysfs_path_is_dir(path)) != 0) { - dprintf("Invalid path to driver: %s\n", path); - return NULL; - } - driver = alloc_driver(); - if (driver == NULL) { - dprintf("Error allocating driver at %s\n", path); - return NULL; - } - if ((sysfs_get_name_from_path(path, driver->name, - SYSFS_NAME_LEN)) != 0) { - dprintf("Error getting driver name from path\n"); - free(driver); - return NULL; - } - safestrcpy(driver->path, path); - if ((sysfs_remove_trailing_slash(driver->path)) != 0) { - dprintf("Invalid path to driver %s\n", driver->path); - sysfs_close_driver(driver); - return NULL; - } + char drvpath[SYSFS_PATH_MAX], *c = NULL; - return driver; -} - -/** - * sysfs_get_driver_attributes: gets list of attributes for the given driver - * @driver: sysfs_driver for which attributes are required - * returns a dlist of attributes corresponding to the driver if present - * NULL otherwise - */ -struct dlist *sysfs_get_driver_attributes(struct sysfs_driver *driver) -{ - if (driver == NULL) { + if (!drv) { errno = EINVAL; - return NULL; - } - - if (driver->directory == NULL) { - if ((open_driver_dir(driver)) == 1) - return NULL; - } - if (driver->directory->attributes == NULL) { - if ((sysfs_read_dir_attributes(driver->directory)) != 0) - return NULL; + return 1; } - 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); + safestrcpy(drvpath, drv->path); + c = strstr(drvpath, SYSFS_DRIVERS_NAME); + if (c == NULL) + return 1; + *--c = '\0'; + c = strstr(drvpath, SYSFS_BUS_NAME); + if (c == NULL) + return 1; + c = strstr(c, "/"); + if (c == NULL) + return 1; + c++; + safestrcpy(drv->bus, c); + return 0; } /** - * sysfs_get_driver_attr: searches driver's attributes by name + * sysfs_get_driver_attr: searches drv's attributes by name * @drv: driver to look through * @name: attribute name to get - * returns sysfs_attribute reference on success or NULL with error - */ + * returns sysfs_attribute reference with success or NULL with error. + */ struct sysfs_attribute *sysfs_get_driver_attr(struct sysfs_driver *drv, - const char *name) + const char *name) { - struct dlist *attrlist = NULL; - - if (drv == NULL) { - errno = EINVAL; - return NULL; - } - - attrlist = sysfs_get_driver_attributes(drv); - if (attrlist == NULL) + if (!drv || !name) { + errno = EINVAL; return NULL; - - return sysfs_get_directory_attribute(drv->directory, (char *)name); + } + return get_attribute(drv, (char *)name); } /** - * sysfs_get_driver_links: gets list of links from the given driver - * @driver: sysfs_driver for which links list is required - * returns a dlist of links corresponding to the driver if present - * NULL otherwise + * sysfs_get_driver_attributes: gets list of driver attributes + * @dev: driver whose attributes list is needed + * returns dlist of attributes on success or NULL on error */ -struct dlist *sysfs_get_driver_links(struct sysfs_driver *driver) +struct dlist *sysfs_get_driver_attributes(struct sysfs_driver *drv) { - if (driver == NULL) { + if (!drv) { errno = EINVAL; return NULL; } - - if (driver->directory == NULL) - if ((open_driver_dir(driver)) == 1) - return NULL; - - if (driver->directory->links == NULL) - if ((sysfs_read_dir_links(driver->directory)) != 0) - return NULL; - - return(driver->directory->links); + return get_attributes_list(drv); } /** - * sysfs_get_driver_devices: open up the list of devices this driver supports - * @driver: sysfs_driver for which devices are needed - * Returns dlist of devices on SUCCESS or NULL with ERROR - */ -struct dlist *sysfs_get_driver_devices(struct sysfs_driver *driver) + * sysfs_open_driver_path: opens and initializes driver structure + * @path: path to driver directory + * returns struct sysfs_driver with success and NULL with error + */ +struct sysfs_driver *sysfs_open_driver_path(const char *path) { - struct sysfs_link *curlink = NULL; - struct sysfs_device *device = NULL; + struct sysfs_driver *driver = NULL; - if (driver == NULL) { + if (!path) { errno = EINVAL; return NULL; } - - if (driver->devices != NULL) - return (driver->devices); - - if (driver->directory == NULL || driver->directory->links == NULL) { - struct dlist *list = NULL; - list = sysfs_get_driver_links(driver); - } - - if (driver->directory->links != NULL) { - dlist_for_each_data(driver->directory->links, curlink, - struct sysfs_link) { - device = sysfs_open_device_path(curlink->target); - if (device == NULL) { - dprintf("Error opening device at %s\n", - curlink->target); - return NULL; - } - if (driver->devices == NULL) - driver->devices = dlist_new_with_delete - (sizeof(struct sysfs_device), - sysfs_close_driver_device); - dlist_unshift_sorted(driver->devices, device, - sort_list); - } + if (sysfs_path_is_dir(path)) { + dprintf("Invalid path to driver: %s\n", path); + return NULL; } - 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; + driver = alloc_driver(); + if (!driver) { + dprintf("Error allocating driver at %s\n", path); return NULL; } - - if (driver->devices != NULL) { - dlist_destroy(driver->devices); - driver->devices = NULL; + if (sysfs_get_name_from_path(path, driver->name, SYSFS_NAME_LEN)) { + dprintf("Error getting driver name from path\n"); + free(driver); + return 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"); + safestrcpy(driver->path, path); + if (sysfs_remove_trailing_slash(driver->path)) { + dprintf("Invalid path to driver %s\n", driver->path); + sysfs_close_driver(driver); return NULL; } - - return (sysfs_get_driver_devices(driver)); -} - -/** - * sysfs_get_driver_device: looks up a device from a list of driver's devices - * and returns its sysfs_device corresponding to it - * @driver: sysfs_driver on which to search - * @name: name of the device to search - * Returns a sysfs_device if found, NULL otherwise - */ -struct sysfs_device *sysfs_get_driver_device(struct sysfs_driver *driver, - const char *name) -{ - struct sysfs_device *device = NULL; - struct dlist *devlist = NULL; - - if (driver == NULL || name == NULL) { - errno = EINVAL; + if (get_driver_bus(driver)) { + dprintf("Could not get the bus driver is on\n"); + sysfs_close_driver(driver); return NULL; } - if (driver->devices == NULL) { - devlist = sysfs_get_driver_devices(driver); - if (devlist == NULL) { - dprintf("Error getting driver devices\n"); - return NULL; - } - } - dlist_for_each_data(driver->devices, device, struct sysfs_device) { - if (!(strncmp(device->name, name, SYSFS_NAME_LEN))) - return device; - } - return NULL; + return driver; } /** @@ -327,11 +165,11 @@ struct sysfs_device *sysfs_get_driver_device(struct sysfs_driver *driver, static int get_driver_path(const char *bus, const char *drv, char *path, size_t psize) { - if (bus == NULL || drv == NULL || path == NULL || psize == 0) { + if (!bus || !drv || !path || psize == 0) { errno = EINVAL; return -1; } - if (sysfs_get_mnt_path(path, psize) != 0) { + if (sysfs_get_mnt_path(path, psize)) { dprintf("Error getting sysfs mount path\n"); return -1; } @@ -347,50 +185,6 @@ static int get_driver_path(const char *bus, const char *drv, } /** - * sysfs_open_driver_attr: read the user supplied driver attribute - * @bus: bus on which to look - * @drv: driver whose attribute has to be read - * @attrib: Attribute to be read - * Returns struct sysfs_attribute on success and NULL on failure - * - * NOTE: - * A call to sysfs_close_attribute() is required to close the - * attribute returned and to free memory - */ -struct sysfs_attribute *sysfs_open_driver_attr(const char *bus, - const char *drv, const char *attrib) -{ - struct sysfs_attribute *attribute = NULL; - char path[SYSFS_PATH_MAX]; - - if (bus == NULL || drv == NULL || attrib == NULL) { - errno = EINVAL; - return NULL; - } - - memset(path, 0, SYSFS_PATH_MAX); - if ((get_driver_path(bus, drv, path, SYSFS_PATH_MAX)) != 0) { - dprintf("Error getting to driver %s\n", drv); - return NULL; - } - safestrcat(path, "/"); - safestrcat(path, attrib); - attribute = sysfs_open_attribute(path); - if (attribute == NULL) { - dprintf("Error opening attribute %s for driver %s\n", - attrib, drv); - return NULL; - } - if ((sysfs_read_attribute(attribute)) != 0) { - dprintf("Error reading attribute %s for driver %s\n", - attrib, drv); - sysfs_close_attribute(attribute); - return NULL; - } - return attribute; -} - -/** * sysfs_open_driver: open driver by name, given its bus * @bus_name: Name of the bus * @drv_name: Name of the driver @@ -402,21 +196,66 @@ struct sysfs_driver *sysfs_open_driver(const char *bus_name, char path[SYSFS_PATH_MAX]; struct sysfs_driver *driver = NULL; - if (drv_name == NULL || bus_name == NULL) { + if (!drv_name || !bus_name) { errno = EINVAL; return NULL; } memset(path, 0, SYSFS_PATH_MAX); - if ((get_driver_path(bus_name, drv_name, path, SYSFS_PATH_MAX)) != 0) { + if (get_driver_path(bus_name, drv_name, path, SYSFS_PATH_MAX)) { dprintf("Error getting to driver %s\n", drv_name); return NULL; } driver = sysfs_open_driver_path(path); - if (driver == NULL) { + if (!driver) { dprintf("Error opening driver at %s\n", path); return NULL; } return driver; } +/** + * sysfs_get_driver_devices: gets list of devices that use the driver + * @drv: sysfs_driver whose device list is needed + * Returns dlist of struct sysfs_device on success and NULL on failure + */ +struct dlist *sysfs_get_driver_devices(struct sysfs_driver *drv) +{ + char *ln = NULL; + struct dlist *linklist = NULL; + struct sysfs_device *dev = NULL; + + if (!drv) { + errno = EINVAL; + return NULL; + } + + linklist = read_dir_links(drv->path); + if (linklist) { + dlist_for_each_data(linklist, ln, char) { + + if (!strncmp(ln, SYSFS_MODULE_NAME, strlen(ln))) + continue; + + dev = sysfs_open_device(drv->bus, ln); + if (!dev) { + dprintf("Error opening driver's device\n"); + sysfs_close_list(linklist); + return NULL; + } + if (!drv->devices) { + drv->devices = dlist_new_with_delete + (sizeof(struct sysfs_device), + sysfs_close_driver_device); + if (!drv->devices) { + dprintf("Error creating device list\n"); + sysfs_close_list(linklist); + return NULL; + } + } + dlist_unshift_sorted(drv->devices, dev, sort_list); + } + sysfs_close_list(linklist); + } + return drv->devices; +} diff --git a/libsysfs/sysfs_utils.c b/libsysfs/sysfs_utils.c index 8b1f56ed14..9f6e18f665 100644 --- a/libsysfs/sysfs_utils.c +++ b/libsysfs/sysfs_utils.c @@ -23,12 +23,6 @@ #include "libsysfs.h" #include "sysfs.h" -static int sort_char(void *new, void *old) -{ - return ((strncmp((char *)new, (char *)old, - strlen((char *)new))) < 0 ? 1 : 0); -} - /** * sysfs_remove_trailing_slash: Removes any trailing '/' in the given path * @path: Path to look for the trailing '/' @@ -38,7 +32,7 @@ int sysfs_remove_trailing_slash(char *path) { char *c = NULL; - if (path == NULL) { + if (!path) { errno = EINVAL; return 1; } @@ -53,54 +47,6 @@ int sysfs_remove_trailing_slash(char *path) return 0; } -/** - * sysfs_get_fs_mnt_path: Gets the mount point for specified filesystem. - * @fs_type: filesystem type to retrieve mount point - * @mnt_path: place to put the retrieved mount path - * @len: size of mnt_path - * returns 0 with success and -1 with error. - */ -static int sysfs_get_fs_mnt_path(const char *fs_type, - char *mnt_path, size_t len) -{ - FILE *mnt; - struct mntent *mntent; - int ret = 0; - size_t dirlen = 0; - - /* check arg */ - if (fs_type == NULL || mnt_path == NULL || len == 0) { - errno = EINVAL; - return -1; - } - - if ((mnt = setmntent(SYSFS_PROC_MNTS, "r")) == NULL) { - dprintf("Error getting mount information\n"); - return -1; - } - while (ret == 0 && dirlen == 0 && (mntent = getmntent(mnt)) != NULL) { - if (strcmp(mntent->mnt_type, fs_type) == 0) { - dirlen = strlen(mntent->mnt_dir); - if (dirlen <= (len - 1)) { - safestrcpymax(mnt_path, mntent->mnt_dir, len); - } else { - dprintf("Error - mount path too long\n"); - ret = -1; - } - } - } - endmntent(mnt); - if (dirlen == 0 && ret == 0) { - dprintf("Filesystem %s not found!\n", fs_type); - errno = EINVAL; - ret = -1; - } - if ((sysfs_remove_trailing_slash(mnt_path)) != 0) - ret = -1; - - return ret; -} - /* * sysfs_get_mnt_path: Gets the sysfs mount point. * @mnt_path: place to put "sysfs" mount point @@ -109,22 +55,21 @@ static int sysfs_get_fs_mnt_path(const char *fs_type, */ int sysfs_get_mnt_path(char *mnt_path, size_t len) { - char *sysfs_path = NULL; - int ret = 0; - - if (mnt_path == NULL || len == 0) { - errno = EINVAL; - return -1; + static char sysfs_path[SYSFS_PATH_MAX] = ""; + const char *sysfs_path_env; + + /* evaluate only at the first call */ + if (sysfs_path[0] == '\0') { + /* possible overrride of real mount path */ + sysfs_path_env = getenv(SYSFS_PATH_ENV); + if (sysfs_path_env != NULL) { + safestrcpymax(mnt_path, sysfs_path_env, len); + return 0; + } + safestrcpymax(mnt_path, SYSFS_MNT_PATH, len); } - sysfs_path = getenv(SYSFS_PATH_ENV); - if (sysfs_path != NULL) { - safestrcpymax(mnt_path, sysfs_path, len); - if ((sysfs_remove_trailing_slash(mnt_path)) != 0) - return 1; - } else - ret = sysfs_get_fs_mnt_path(SYSFS_FSTYPE_NAME, mnt_path, len); - return ret; + return 0; } /** @@ -137,8 +82,8 @@ int sysfs_get_name_from_path(const char *path, char *name, size_t len) { char tmp[SYSFS_PATH_MAX]; char *n = NULL; - - if (path == NULL || name == NULL || len == 0) { + + if (!path || !name || len == 0) { errno = EINVAL; return -1; } @@ -161,7 +106,7 @@ int sysfs_get_name_from_path(const char *path, char *name, size_t len) safestrcpymax(name, n, len); return 0; } - + /** * sysfs_get_link: returns link source * @path: symbolic link's path @@ -176,7 +121,7 @@ int sysfs_get_link(const char *path, char *target, size_t len) char *d = NULL, *s = NULL; int slashes = 0, count = 0; - if (path == NULL || target == NULL || len == 0) { + if (!path || !target || len == 0) { errno = EINVAL; return -1; } @@ -190,15 +135,15 @@ int sysfs_get_link(const char *path, char *target, size_t len) return -1; } d = linkpath; - /* + /* * Three cases here: * 1. relative path => format ../.. * 2. absolute path => format /abcd/efgh * 3. relative path _from_ this dir => format abcd/efgh - */ + */ switch (*d) { case '.': - /* + /* * handle the case where link is of type ./abcd/xxx */ safestrcpy(temp_path, devdir); @@ -215,9 +160,8 @@ int sysfs_get_link(const char *path, char *target, size_t len) } safestrcpymax(target, temp_path, len); break; - /* - * relative path - * getting rid of leading "../.." + /* + * relative path, getting rid of leading "../.." */ parse_path: while (*d == '/' || *d == '.') { @@ -255,158 +199,28 @@ parse_path: } /** - * sysfs_del_name: free function for sysfs_open_subsystem_list - * @name: memory area to be freed - */ -static void sysfs_del_name(void *name) -{ - free(name); -} - - -/** * sysfs_close_list: generic list free routine * @list: dlist to free * Returns nothing */ void sysfs_close_list(struct dlist *list) { - if (list != NULL) + if (list) dlist_destroy(list); } /** - * sysfs_open_subsystem_list: gets a list of all supported "name" subsystem - * details from the system - * @name: name of the subsystem, eg., "bus", "class", "devices" - * Returns a dlist of supported names or NULL if subsystem not supported - */ -struct dlist *sysfs_open_subsystem_list(char *name) -{ - char sysfs_path[SYSFS_PATH_MAX], *subsys_name = NULL; - char *c = NULL; - struct sysfs_directory *dir = NULL, *cur = NULL; - struct dlist *list = NULL; - - if (name == NULL) - return NULL; - - if (sysfs_get_mnt_path(sysfs_path, SYSFS_PATH_MAX) != 0) { - dprintf("Error getting sysfs mount point\n"); - return NULL; - } - - safestrcat(sysfs_path, "/"); - safestrcat(sysfs_path, name); - dir = sysfs_open_directory(sysfs_path); - if (dir == NULL) { - dprintf("Error opening sysfs_directory at %s\n", sysfs_path); - return NULL; - } - - if ((sysfs_read_dir_subdirs(dir)) != 0) { - dprintf("Error reading sysfs_directory at %s\n", sysfs_path); - sysfs_close_directory(dir); - return NULL; - } - - if (dir->subdirs != NULL) { - list = dlist_new_with_delete(SYSFS_NAME_LEN, - sysfs_del_name); - if (list == NULL) { - dprintf("Error creating list\n"); - sysfs_close_directory(dir); - return NULL; - } - - dlist_for_each_data(dir->subdirs, cur, - struct sysfs_directory) { - subsys_name = (char *)calloc(1, SYSFS_NAME_LEN); - safestrcpymax(subsys_name, cur->name, SYSFS_NAME_LEN); - dlist_unshift_sorted(list, subsys_name, sort_char); - } - } - sysfs_close_directory(dir); - /* - * We are now considering "block" as a "class". Hence, if the subsys - * name requested here is "class", verify if "block" is supported on - * this system and return the same. - */ - if (strcmp(name, SYSFS_CLASS_NAME) == 0) { - c = strstr(sysfs_path, SYSFS_CLASS_NAME); - if (c == NULL) - goto out; - *c = '\0'; - safestrcpymax(c, SYSFS_BLOCK_NAME, - sizeof(sysfs_path) - strlen(sysfs_path)); - if ((sysfs_path_is_dir(sysfs_path)) == 0) { - subsys_name = (char *)calloc(1, SYSFS_NAME_LEN); - safestrcpymax(subsys_name, SYSFS_BLOCK_NAME, - SYSFS_NAME_LEN); - dlist_unshift_sorted(list, subsys_name, sort_char); - } - } -out: - return list; -} - - -/** - * sysfs_open_bus_devices_list: gets a list of all devices on "name" bus - * @name: name of the subsystem, eg., "pci", "scsi", "usb" - * Returns a dlist of supported names or NULL if subsystem not supported - */ -struct dlist *sysfs_open_bus_devices_list(char *name) + * sysfs_open_directory_list: gets a list of all directories under "path" + * @path: path to read + * Returns a dlist of supported names or NULL no directories (errno is set + * in case of error + */ +struct dlist *sysfs_open_directory_list(const char *path) { - char sysfs_path[SYSFS_PATH_MAX], *device_name = NULL; - struct sysfs_directory *dir = NULL; - struct sysfs_link *cur = NULL; - struct dlist *list = NULL; - - if (name == NULL) - return NULL; - - if (sysfs_get_mnt_path(sysfs_path, SYSFS_PATH_MAX) != 0) { - dprintf("Error getting sysfs mount point\n"); - return NULL; - } - - safestrcat(sysfs_path, "/"); - safestrcat(sysfs_path, SYSFS_BUS_NAME); - safestrcat(sysfs_path, "/"); - safestrcat(sysfs_path, name); - safestrcat(sysfs_path, "/"); - safestrcat(sysfs_path, SYSFS_DEVICES_NAME); - dir = sysfs_open_directory(sysfs_path); - if (dir == NULL) { - dprintf("Error opening sysfs_directory at %s\n", sysfs_path); - return NULL; - } - - if ((sysfs_read_dir_links(dir)) != 0) { - dprintf("Error reading sysfs_directory at %s\n", sysfs_path); - sysfs_close_directory(dir); + if (!path) return NULL; - } - - if (dir->links != NULL) { - list = dlist_new_with_delete(SYSFS_NAME_LEN, - sysfs_del_name); - if (list == NULL) { - dprintf("Error creating list\n"); - sysfs_close_directory(dir); - return NULL; - } - dlist_for_each_data(dir->links, cur, - struct sysfs_link) { - device_name = (char *)calloc(1, SYSFS_NAME_LEN); - safestrcpymax(device_name, cur->name, SYSFS_NAME_LEN); - dlist_unshift_sorted(list, device_name, sort_char); - } - } - sysfs_close_directory(dir); - return list; + return (read_dir_subdirs(path)); } /** @@ -418,7 +232,7 @@ int sysfs_path_is_dir(const char *path) { struct stat astats; - if (path == NULL) { + if (!path) { errno = EINVAL; return 1; } @@ -428,7 +242,7 @@ int sysfs_path_is_dir(const char *path) } if (S_ISDIR(astats.st_mode)) return 0; - + return 1; } @@ -441,7 +255,7 @@ int sysfs_path_is_link(const char *path) { struct stat astats; - if (path == NULL) { + if (!path) { errno = EINVAL; return 1; } @@ -451,7 +265,7 @@ int sysfs_path_is_link(const char *path) } if (S_ISLNK(astats.st_mode)) return 0; - + return 1; } @@ -464,7 +278,7 @@ int sysfs_path_is_file(const char *path) { struct stat astats; - if (path == NULL) { + if (!path) { errno = EINVAL; return 1; } @@ -474,6 +288,6 @@ int sysfs_path_is_file(const char *path) } if (S_ISREG(astats.st_mode)) return 0; - + return 1; } |