diff options
-rw-r--r-- | ChangeLog | 10 | ||||
-rw-r--r-- | Makefile.am | 1 | ||||
-rw-r--r-- | Makefile.in | 54 | ||||
-rw-r--r-- | include/libsysfs.h | 6 | ||||
-rw-r--r-- | lib/sysfs_class.c | 53 | ||||
-rw-r--r-- | lib/sysfs_device.c | 133 | ||||
-rw-r--r-- | lib/sysfs_dir.c | 84 | ||||
-rw-r--r-- | lib/sysfs_driver.c | 126 |
8 files changed, 394 insertions, 73 deletions
@@ -1,6 +1,14 @@ +10/20/2003 - Ananth Mavinakayanahalli <ananth@in.ibm.com> + * Added code to install header files (from include dir) + to /usr/local/include/ directory + * Added "read_attr" functions for device, driver and + class; simplified "write_attr" handling + * Made sysfs_get_directory_attribute() recurse subdirs + * Fixed potential bugs in sysfs_dir.c + 10/17/2003 - Daniel Stekloff <dsteklof@us.ibm.com> - * Add "path" to device in sysfs_device structure + * Added "path" to device in sysfs_device structure 10/15/2003 - Ananth Mavinakayanahalli <ananth@in.ibm.com> * Fixed bug in sysfs_block.c (initrd) diff --git a/Makefile.am b/Makefile.am index ead8a23..b48ca6d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,5 +1,6 @@ EXTRA_DIST = docs include SUBDIRS = lib cmd test +include_HEADERS = include/libsysfs.h include/dlist.h dist-hook: rm -rf `find $(distdir)/docs -name CVS` diff --git a/Makefile.in b/Makefile.in index 5382b28..0510d3e 100644 --- a/Makefile.in +++ b/Makefile.in @@ -85,21 +85,24 @@ am__quote = @am__quote@ install_sh = @install_sh@ EXTRA_DIST = docs include SUBDIRS = lib cmd test +include_HEADERS = include/libsysfs.h include/dlist.h subdir = . ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs CONFIG_HEADER = config.h CONFIG_CLEAN_FILES = DIST_SOURCES = +HEADERS = $(include_HEADERS) + RECURSIVE_TARGETS = info-recursive dvi-recursive install-info-recursive \ uninstall-info-recursive all-recursive install-data-recursive \ install-exec-recursive installdirs-recursive install-recursive \ uninstall-recursive check-recursive installcheck-recursive -DIST_COMMON = README AUTHORS COPYING ChangeLog INSTALL Makefile.am \ - Makefile.in NEWS TODO aclocal.m4 config.guess config.h.in \ - config.sub configure configure.ac depcomp install-sh ltmain.sh \ - missing mkinstalldirs +DIST_COMMON = README $(include_HEADERS) AUTHORS COPYING ChangeLog \ + INSTALL Makefile.am Makefile.in NEWS TODO aclocal.m4 \ + config.guess config.h.in config.sub configure configure.ac \ + depcomp install-sh ltmain.sh missing mkinstalldirs DIST_SUBDIRS = $(SUBDIRS) all: config.h $(MAKE) $(AM_MAKEFLAGS) all-recursive @@ -148,6 +151,24 @@ clean-libtool: distclean-libtool: -rm -f libtool uninstall-info-am: +includeHEADERS_INSTALL = $(INSTALL_HEADER) +install-includeHEADERS: $(include_HEADERS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(includedir) + @list='$(include_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(includeHEADERS_INSTALL) $$d$$p $(DESTDIR)$(includedir)/$$f"; \ + $(includeHEADERS_INSTALL) $$d$$p $(DESTDIR)$(includedir)/$$f; \ + done + +uninstall-includeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(include_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f $(DESTDIR)$(includedir)/$$f"; \ + rm -f $(DESTDIR)$(includedir)/$$f; \ + done # This directory's subdirectories are mostly independent; you can cd # into them and run `make' without going through this Makefile. @@ -260,6 +281,7 @@ distcleancheck_listfiles = find . -type f -print distdir: $(DISTFILES) $(am__remove_distdir) mkdir $(distdir) + $(mkinstalldirs) $(distdir)/include @list='$(DISTFILES)'; for file in $$list; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ @@ -350,9 +372,10 @@ distcleancheck: distclean exit 1; } >&2 check-am: all-am check: check-recursive -all-am: Makefile config.h +all-am: Makefile $(HEADERS) config.h installdirs: installdirs-recursive installdirs-am: + $(mkinstalldirs) $(DESTDIR)$(includedir) install: install-recursive install-exec: install-exec-recursive @@ -395,7 +418,7 @@ info: info-recursive info-am: -install-data-am: +install-data-am: install-includeHEADERS install-exec-am: @@ -414,7 +437,7 @@ mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic mostlyclean-libtool -uninstall-am: uninstall-info-am +uninstall-am: uninstall-includeHEADERS uninstall-info-am uninstall-info: uninstall-info-recursive @@ -425,14 +448,15 @@ uninstall-info: uninstall-info-recursive distcleancheck distdir dvi dvi-am dvi-recursive info info-am \ info-recursive install install-am install-data install-data-am \ install-data-recursive install-exec install-exec-am \ - install-exec-recursive install-info install-info-am \ - install-info-recursive install-man install-recursive \ - install-strip installcheck installcheck-am installdirs \ - installdirs-am installdirs-recursive maintainer-clean \ - maintainer-clean-generic maintainer-clean-recursive mostlyclean \ - mostlyclean-generic mostlyclean-libtool mostlyclean-recursive \ - tags tags-recursive uninstall uninstall-am uninstall-info-am \ - uninstall-info-recursive uninstall-recursive + install-exec-recursive install-includeHEADERS install-info \ + install-info-am install-info-recursive install-man \ + install-recursive install-strip installcheck installcheck-am \ + installdirs installdirs-am installdirs-recursive \ + maintainer-clean maintainer-clean-generic \ + maintainer-clean-recursive mostlyclean mostlyclean-generic \ + mostlyclean-libtool mostlyclean-recursive tags tags-recursive \ + uninstall uninstall-am uninstall-includeHEADERS \ + uninstall-info-am uninstall-info-recursive uninstall-recursive dist-hook: diff --git a/include/libsysfs.h b/include/libsysfs.h index 819959e..980d91b 100644 --- a/include/libsysfs.h +++ b/include/libsysfs.h @@ -203,6 +203,8 @@ extern struct sysfs_driver *sysfs_open_driver_by_name (const unsigned char *drv_name, const unsigned char *bus, size_t bsize); extern int sysfs_write_driver_attr(unsigned char *drv, unsigned char *attrib, unsigned char *value, size_t len); +extern int sysfs_read_driver_attr(unsigned char *drv, unsigned char *attrib, + unsigned char *value, size_t len); /* generic sysfs device access */ extern void sysfs_close_root_device(struct sysfs_root_device *root); @@ -217,6 +219,8 @@ extern struct sysfs_device *sysfs_open_device_by_id (const unsigned char *bus_id, const unsigned char *bus, size_t bsize); extern int sysfs_write_device_attr(unsigned char *dev, unsigned char *attrib, unsigned char *value, size_t len); +extern int sysfs_read_device_attr(unsigned char *dev, unsigned char *attrib, + unsigned char *value, size_t len); /* generic sysfs bus access */ extern void sysfs_close_bus(struct sysfs_bus *bus); @@ -253,6 +257,8 @@ extern struct sysfs_attribute *sysfs_get_classdev_attr (struct sysfs_class_device *clsdev, const unsigned char *name); extern int sysfs_write_classdev_attr(unsigned char *dev, unsigned char *attrib, unsigned char *value, size_t len); +extern int sysfs_read_classdev_attr(unsigned char *dev, unsigned char *attrib, + unsigned char *value, size_t len); /* generic sysfs block access */ extern void sysfs_close_block_device(struct sysfs_block_device *block); diff --git a/lib/sysfs_class.c b/lib/sysfs_class.c index 37c5243..cb6ca9d 100644 --- a/lib/sysfs_class.c +++ b/lib/sysfs_class.c @@ -413,7 +413,7 @@ int sysfs_find_device_class(const unsigned char *bus_id, * @name: attribute name to get * returns sysfs_attribute reference with success or NULL with error */ -struct sysfs_attribute *sysfs_get_classdev_attribute +struct sysfs_attribute *sysfs_get_classdev_attr (struct sysfs_class_device *clsdev, const unsigned char *name) { struct sysfs_attribute *cur = NULL; @@ -438,6 +438,7 @@ struct sysfs_attribute *sysfs_get_classdev_attribute * @dev: class device name for which the attribute has to be changed * @attrib: attribute to change * @value: value to change to + * @len: size of buffer at "value" * Returns 0 on success and -1 on error */ int sysfs_write_classdev_attr(unsigned char *dev, unsigned char *attrib, @@ -478,3 +479,53 @@ int sysfs_write_classdev_attr(unsigned char *dev, unsigned char *attrib, sysfs_close_class_device(clsdev); return 0; } + +/** + * sysfs_read_classdev_attr: read an attribute for a given class device + * @dev: class device name for which the attribute has to be read + * @attrib: attribute to read + * @value: buffer to return value to user + * @len: size of buffer at "value" + * Returns 0 on success and -1 on error + */ +int sysfs_read_classdev_attr(unsigned char *dev, unsigned char *attrib, + unsigned char *value, size_t len) +{ + struct sysfs_class_device *clsdev = NULL; + struct sysfs_attribute *attribute = NULL; + unsigned char class_name[SYSFS_NAME_LEN]; + + if (dev == NULL || attrib == NULL || value == NULL) { + errno = EINVAL; + return -1; + } + + memset(class_name, 0, SYSFS_NAME_LEN); + if ((sysfs_find_device_class(dev, + class_name, SYSFS_NAME_LEN)) < 0) { + dprintf("Class device %s not found\n", dev); + return -1; + } + clsdev = sysfs_open_class_device_by_name(class_name, dev); + if (clsdev == NULL) { + dprintf("Error opening %s in class %s\n", dev, class_name); + return -1; + } + attribute = sysfs_get_directory_attribute(clsdev->directory, attrib); + if (attribute == NULL) { + dprintf("Attribute %s not defined for device %s on class %s\n", + attrib, dev, class_name); + sysfs_close_class_device(clsdev); + return -1; + } + if (attribute->len > len) { + dprintf("Value length %d is greater that suppled buffer %d\n", + attribute->len, len); + sysfs_close_class_device(clsdev); + return -1; + } + strncpy(value, attribute->value, attribute->len); + value[(attribute->len)+1] = 0; + sysfs_close_class_device(clsdev); + return 0; +} diff --git a/lib/sysfs_device.c b/lib/sysfs_device.c index 635ba64..89704dc 100644 --- a/lib/sysfs_device.c +++ b/lib/sysfs_device.c @@ -388,6 +388,51 @@ struct sysfs_device *sysfs_open_device_by_id(const unsigned char *bus_id, } /** + * get_device_absolute_path: looks up the bus the device is on, gets + * absolute path to the device + * @device: device for which path is needed + * @path: buffer to store absolute path + * @psize: size of "path" + * Returns 0 on success -1 on failure + */ +static int get_device_absolute_path(const unsigned char *device, + unsigned char *path, size_t psize) +{ + unsigned char bus_name[SYSFS_NAME_LEN], bus_path[SYSFS_PATH_MAX]; + + if (device == NULL || path == NULL) { + errno = EINVAL; + return -1; + } + + memset(bus_name, 0, SYSFS_NAME_LEN); + memset(bus_path, 0, SYSFS_NAME_LEN); + if ((sysfs_find_device_bus(device, bus_name, SYSFS_NAME_LEN)) != 0) { + dprintf("Device %s not found\n", device); + return -1; + } + if (sysfs_get_mnt_path(bus_path, SYSFS_PATH_MAX) != 0) { + dprintf ("Sysfs not supported on this system\n"); + return -1; + } + strcat(bus_path, SYSFS_BUS_DIR); + strcat(bus_path, "/"); + strcat(bus_path, bus_name); + strcat(bus_path, SYSFS_DEVICES_DIR); + strcat(bus_path, "/"); + strcat(bus_path, device); + /* + * We now are at /sys/bus/"bus_name"/devices/"device" which is a link. + * Now read this link to reach to the device. + */ + if ((sysfs_get_link(bus_path, path, SYSFS_PATH_MAX)) != 0) { + dprintf("Error getting to device %s\n", device); + return -1; + } + return 0; +} + +/** * sysfs_write_device_attr: modify a "writable" attribute for the given device * @dev: device bus_id for which attribute has to be changed * @attrib: attribute to change @@ -398,38 +443,96 @@ struct sysfs_device *sysfs_open_device_by_id(const unsigned char *bus_id, int sysfs_write_device_attr(unsigned char *dev, unsigned char *attrib, unsigned char *value, size_t len) { - struct sysfs_device *device = NULL; struct sysfs_attribute *attribute = NULL; - unsigned char bus_name[SYSFS_NAME_LEN]; + unsigned char devpath[SYSFS_PATH_MAX]; if (dev == NULL || attrib == NULL || value == NULL) { errno = EINVAL; return -1; } - memset(bus_name, 0, SYSFS_NAME_LEN); - if ((sysfs_find_device_bus(dev, bus_name, SYSFS_NAME_LEN)) != 0) { - dprintf("Device %s not found\n", dev); + memset(devpath, 0, SYSFS_PATH_MAX); + if ((get_device_absolute_path(dev, devpath, SYSFS_PATH_MAX)) != 0) { + dprintf("Error finding absolute path to device %s\n", dev); return -1; } - device = sysfs_open_device_by_id(dev, bus_name, SYSFS_NAME_LEN); - if (device == NULL) { - dprintf("Error opening device %s\n", dev); - return -1; - } - attribute = sysfs_get_directory_attribute(device->directory, attrib); + strcat(devpath, "/"); + strcat(devpath, attrib); + attribute = sysfs_open_attribute(devpath); if (attribute == NULL) { - dprintf("Attribute %s not defined for device %s\n", + dprintf("Attribute %s could not be retrieved for device %s\n", attrib, dev); - sysfs_close_device(device); return -1; } + if (attribute->method & SYSFS_METHOD_SHOW) { + if ((sysfs_read_attribute(attribute)) != 0) { + dprintf("Error reading attribute %s for device %s\n", + attrib, dev); + sysfs_close_attribute(attribute); + return -1; + } + } if ((sysfs_write_attribute(attribute, value, len)) < 0) { dprintf("Error setting %s to %s\n", attrib, value); - sysfs_close_device(device); + sysfs_close_attribute(attribute); return -1; } - sysfs_close_device(device); + sysfs_close_attribute(attribute); return 0; } + +/** + * sysfs_read_device_attr: read an attribute of the given device + * @dev: device bus_id for which attribute has to be changed + * @attrib: attribute to read + * @value: buffer to return value in + * @len: size of buffer available + * Returns 0 on success -1 on error + */ +int sysfs_read_device_attr(unsigned char *dev, unsigned char *attrib, + unsigned char *value, size_t len) +{ + struct sysfs_attribute *attribute = NULL; + unsigned char devpath[SYSFS_PATH_MAX]; + + if (dev == NULL || attrib == NULL || value == NULL) { + errno = EINVAL; + return -1; + } + memset(devpath, 0, SYSFS_PATH_MAX); + if ((get_device_absolute_path(dev, devpath, SYSFS_PATH_MAX)) != 0) { + dprintf("Error finding absolute path to device %s\n", dev); + return -1; + } + strcat(devpath, "/"); + strcat(devpath, attrib); + attribute = sysfs_open_attribute(devpath); + if (attribute == NULL) { + dprintf("Error opening attribute %s for device %s\n", + attrib, dev); + return -1; + } + if (!(attribute->method & SYSFS_METHOD_SHOW)) { + dprintf("Show method not supported for attribute %s\n", + attrib); + sysfs_close_attribute(attribute); + return -1; + } + if ((sysfs_read_attribute(attribute)) != 0) { + dprintf("Error reading attribute %s for device %s\n", + attrib, dev); + sysfs_close_attribute(attribute); + return -1; + } + if (attribute->len > len) { + dprintf("Value length %d is larger than supplied buffer %d\n", + attribute->len, len); + sysfs_close_attribute(attribute); + return -1; + } + strncpy(value, attribute->value, attribute->len); + value[(attribute->len)+1] = 0; + sysfs_close_attribute(attribute); + return 0; +} diff --git a/lib/sysfs_dir.c b/lib/sysfs_dir.c index 77375f0..ff2edf4 100644 --- a/lib/sysfs_dir.c +++ b/lib/sysfs_dir.c @@ -149,8 +149,10 @@ struct sysfs_attribute *sysfs_open_attribute(const unsigned char *path) } strncpy(sysattr->path, path, sizeof(sysattr->path)); if ((stat(sysattr->path, &fileinfo)) != 0) { - dprintf("stat failed\n"); + dprintf("Stat failed: No such attribute?\n"); sysattr->method = 0; + free(sysattr); + sysattr = NULL; } else { if (fileinfo.st_mode & S_IRUSR) sysattr->method |= SYSFS_METHOD_SHOW; @@ -211,24 +213,30 @@ int sysfs_write_attribute(struct sysfs_attribute *sysattr, len, sysattr->name); /* * since we could not write user supplied number of bytes, - * restore the old value + * restore the old value if one available */ - length = write(fd, sysattr->value, sysattr->len); - close(fd); - return -1; + 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 + * in sysfs_attribute. Verify first if the attribute supports reading + * (show method). If it does not, do not bother */ - if (length != sysattr->len) { - sysattr->value = (char *)realloc(sysattr->value, length); - sysattr->len = length; - strncpy(sysattr->value, new_value, length); - } else { - /*"length" of the new value is same as old one */ - strncpy(sysattr->value, new_value, length); + if (sysattr->method & SYSFS_METHOD_SHOW) { + if (length != sysattr->len) { + sysattr->value = (char *)realloc(sysattr->value, + length); + sysattr->len = length; + strncpy(sysattr->value, new_value, length); + } else { + /*"length" of the new value is same as old one */ + strncpy(sysattr->value, new_value, length); + } } close(fd); @@ -582,12 +590,30 @@ int sysfs_read_directory(struct sysfs_directory *sysdir) struct sysfs_attribute *sysfs_get_directory_attribute (struct sysfs_directory *dir, unsigned char *attrname) { + struct sysfs_directory *sdir = NULL; + struct sysfs_attribute *attr = NULL; + if (dir == NULL || attrname == NULL) { errno = EINVAL; return NULL; } - return (struct sysfs_attribute *)dlist_find_custom(dir->attributes, + + attr = (struct sysfs_attribute *)dlist_find_custom(dir->attributes, attrname, dir_attribute_name_equal); + if (attr != NULL) + return attr; + + if (dir->subdirs != NULL) { + dlist_for_each_data(dir->subdirs, sdir, + struct sysfs_directory) { + if (sdir->attributes == NULL) + continue; + attr = sysfs_get_directory_attribute(sdir, attrname); + if (attr != NULL) + return attr; + } + } + return NULL; } /** @@ -627,12 +653,15 @@ struct sysfs_directory *sysfs_get_subdirectory(struct sysfs_directory *dir, if (sub != NULL) return sub; - dlist_for_each_data(dir->subdirs, cursub, struct sysfs_directory) { - if (cursub->subdirs == NULL) - continue; - sub = sysfs_get_subdirectory(cursub, subname); - if (sub != NULL) - return sub; + if (dir->subdirs != NULL) { + dlist_for_each_data(dir->subdirs, cursub, + struct sysfs_directory) { + if (cursub->subdirs == NULL) + continue; + sub = sysfs_get_subdirectory(cursub, subname); + if (sub != NULL) + return sub; + } } return NULL; } @@ -661,12 +690,15 @@ struct sysfs_link *sysfs_get_subdirectory_link(struct sysfs_directory *dir, if (dir->subdirs == NULL) return NULL; - dlist_for_each_data(dir->subdirs, cursub, struct sysfs_directory) { - if (cursub->subdirs == NULL) - continue; - ln = sysfs_get_subdirectory_link(cursub, linkname); - if (ln != NULL) - return ln; + if (dir->subdirs != NULL) { + dlist_for_each_data(dir->subdirs, cursub, + struct sysfs_directory) { + if (cursub->subdirs == NULL) + continue; + ln = sysfs_get_subdirectory_link(cursub, linkname); + if (ln != NULL) + return ln; + } } return NULL; } diff --git a/lib/sysfs_driver.c b/lib/sysfs_driver.c index 51a9107..9d331cc 100644 --- a/lib/sysfs_driver.c +++ b/lib/sysfs_driver.c @@ -225,6 +225,43 @@ struct sysfs_driver *sysfs_open_driver_by_name(const unsigned char *drv_name, } /** + * get_driver_path: looks up the bus the driver is on and builds path to + * the driver. + * @drv: driver to look for + * @path: buffer to return path to driver + * @psize: size of "path" + * Returns 0 on success and -1 on error + */ +static int get_driver_path(const unsigned char *drv, + unsigned char *path, size_t psize) +{ + unsigned char bus_name[SYSFS_NAME_LEN]; + + if (drv == NULL || path == NULL) { + errno = EINVAL; + return -1; + } + memset(bus_name, 0, SYSFS_NAME_LEN); + memset(path, 0, SYSFS_PATH_MAX); + if ((sysfs_find_driver_bus(drv, bus_name, SYSFS_NAME_LEN)) < 0) { + dprintf("Driver %s not found\n", drv); + return -1; + } + if (sysfs_get_mnt_path(path, SYSFS_PATH_MAX) != 0) { + dprintf("Error getting sysfs mount path\n"); + return -1; + } + strcat(path, SYSFS_BUS_DIR); + strcat(path, "/"); + strcat(path, bus_name); + strcat(path, SYSFS_DRIVERS_DIR); + strcat(path, "/"); + strcat(path, drv); + fprintf(stdout, "get_driver_path %s\n", path); + return 0; +} + +/** * sysfs_write_driver_attr: modify "writable" driver attribute * @drv: driver whose attribute has to be modified * @attrib: Attribute to be modified @@ -234,38 +271,97 @@ struct sysfs_driver *sysfs_open_driver_by_name(const unsigned char *drv_name, int sysfs_write_driver_attr(unsigned char *drv, unsigned char *attrib, unsigned char *value, size_t len) { - struct sysfs_driver *driver = NULL; struct sysfs_attribute *attribute = NULL; - unsigned char busname[SYSFS_NAME_LEN]; + unsigned char path[SYSFS_PATH_MAX]; if (drv == NULL || attrib == NULL || value == NULL) { errno = EINVAL; return -1; } - memset(busname, 0, SYSFS_NAME_LEN); - if ((sysfs_find_driver_bus(drv, busname, SYSFS_NAME_LEN)) < 0) { - dprintf("Driver %s not found\n", drv); - return -1; - } - driver = sysfs_open_driver_by_name(drv, busname, SYSFS_NAME_LEN); - if (driver == NULL) { - dprintf("Could not open driverr %s\n", drv); + memset(path, 0, SYSFS_PATH_MAX); + if ((get_driver_path(drv, path, SYSFS_PATH_MAX)) != 0) { + dprintf("Error getting to driver %s\n", drv); return -1; } - attribute = sysfs_get_directory_attribute(driver->directory, attrib); + strcat(path, "/"); + strcat(path, attrib); + attribute = sysfs_open_attribute(path); if (attribute == NULL) { - dprintf("Attribute %s not defined for driver %s\n", + dprintf("Attribute %s could not be retrieved for driver %s\n", attrib, drv); - sysfs_close_driver_by_name(driver); return -1; } + if (attribute->method & SYSFS_METHOD_SHOW) { + if ((sysfs_read_attribute(attribute)) != 0) { + dprintf("Error reading attribute %s for driver %s\n", + attrib, drv); + sysfs_close_attribute(attribute); + return -1; + } + } if ((sysfs_write_attribute(attribute, value, len)) < 0) { dprintf("Error setting %s to %s\n", attrib, value); - sysfs_close_driver_by_name(driver); + sysfs_close_attribute(attribute); + return -1; + } + sysfs_close_attribute(attribute); + return 0; +} + +/** + * sysfs_read_driver_attr: read the user supplied driver attribute + * @drv: driver whose attribute has to be read + * @attrib: Attribute to be read + * @value: Buffer to return the read value + * @len: Length of the buffer "value" + * Returns 0 on success -1 on failure + */ +int sysfs_read_driver_attr(unsigned char *drv, unsigned char *attrib, + unsigned char *value, size_t len) +{ + struct sysfs_attribute *attribute = NULL; + unsigned char busname[SYSFS_NAME_LEN], path[SYSFS_PATH_MAX]; + + if (drv == NULL || attrib == NULL || value == NULL) { + errno = EINVAL; + return -1; + } + + memset(path, 0, SYSFS_NAME_LEN); + if ((get_driver_path(drv, path, SYSFS_PATH_MAX)) != 0) { + dprintf("Error getting to driver %s\n", drv); + return -1; + } + strcat(path, "/"); + strcat(path, attrib); + attribute = sysfs_open_attribute(path); + if (attribute == NULL) { + dprintf("Error opening attribute %s for driver %s\n", + attrib, drv); + return -1; + } + if (!(attribute->method & SYSFS_METHOD_SHOW)) { + dprintf("Show method not supported for attribute %s\n", + attrib); + sysfs_close_attribute(attribute); + return -1; + } + if ((sysfs_read_attribute(attribute)) != 0) { + dprintf("Error reading attribute %s for driver %s\n", + attrib, drv); + sysfs_close_attribute(attribute); + return -1; + } + if (attribute->len > len) { + dprintf("Value length %d is larger than supplied buffer %d\n", + attribute->len, len); + sysfs_close_attribute(attribute); return -1; } - sysfs_close_driver_by_name(driver); + strncpy(value, attribute->value, attribute->len); + value[(attribute->len)+1] = 0; + sysfs_close_attribute(attribute); return 0; } |