diff options
author | mananth <mananth> | 2003-08-25 08:12:27 +0000 |
---|---|---|
committer | mananth <mananth> | 2003-08-25 08:12:27 +0000 |
commit | 84e213ec1680275dc69477c34f34a372b9fddf2d (patch) | |
tree | e5c717a88b8b980780cd15dc86056b442f13fcaf | |
download | sysfsutils-84e213ec1680275dc69477c34f34a372b9fddf2d.tar.gz |
Initial revision
-rw-r--r-- | AUTHORS | 2 | ||||
-rw-r--r-- | COPYING | 10 | ||||
-rw-r--r-- | CREDITS | 8 | ||||
-rw-r--r-- | ChangeLog | 37 | ||||
-rw-r--r-- | Makefile | 12 | ||||
-rw-r--r-- | NEWS | 15 | ||||
-rw-r--r-- | README | 61 | ||||
-rw-r--r-- | TODO | 18 | ||||
-rw-r--r-- | cmd/GPL | 272 | ||||
-rw-r--r-- | cmd/Makefile | 20 | ||||
-rw-r--r-- | cmd/lsbus.c | 492 | ||||
-rw-r--r-- | cmd/systool.c | 706 | ||||
-rw-r--r-- | docs/libsysfs.txt | 769 | ||||
-rw-r--r-- | include/libsysfs.h | 161 | ||||
-rw-r--r-- | lib/LGPL | 441 | ||||
-rw-r--r-- | lib/Makefile | 44 | ||||
-rw-r--r-- | lib/sysfs.h | 49 | ||||
-rw-r--r-- | lib/sysfs_bus.c | 301 | ||||
-rw-r--r-- | lib/sysfs_class.c | 270 | ||||
-rw-r--r-- | lib/sysfs_device.c | 199 | ||||
-rw-r--r-- | lib/sysfs_dir.c | 453 | ||||
-rw-r--r-- | lib/sysfs_driver.c | 89 | ||||
-rw-r--r-- | lib/sysfs_utils.c | 156 |
23 files changed, 4585 insertions, 0 deletions
@@ -0,0 +1,2 @@ +Ananth Mavinakayanahalli <ananth@in.ibm.com> +Daniel Stekloff <dsteklof@us.ibm.com> @@ -0,0 +1,10 @@ + +The commands are licensed under the GNU General Public License (GPL) +Version 2, June 1991. The full text of the GPL is located at: + +sysutils/cmd/GPL + +The sysfs library is licensed under the GNU Lesser Public License (LGPL) +Version 2.1, February 1999. The full text of the LGPL is located at: + +sysutils/lib/LGPL @@ -0,0 +1,8 @@ + +The authors of sysutils would like to thank the following people who +have made contributions: + + o Lev Makhlis <mlev@despammed.com>: + - Supplied libsysfs code cleanup including code + simplification, read-only strings, and + C++ compatibility. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..b3064ca --- /dev/null +++ b/ChangeLog @@ -0,0 +1,37 @@ + +07/24/2003 - Daniel Stekloff <dsteklof@us.ibm.com> + * Changed sysutils name to sysfsutils + +07/23/2003 - Daniel Stekloff <dsteklof@us.ibm.com> + * Changed sysfs_dlink to sysfs_link, got rid of + sysfs_directory link for target char path. + +07/18/2003 - Ananth Mavinakayanahalli <ananth@in.ibm.com> + * Changed default systool and lsbus to just print + device info. Device info already prints drivers. + +07/10/2003 - Daniel Stekloff <dsteklof@us.ibm.com> + Ananth Mavinakayanahalli <ananth@in.ibm.com> + * Added printing binary attribute support to systool + and lsbus + +07/09/2003 - Lev Makhlis <mlev@despammed.com> + * Libsysfs code cleanup including: + - code simplification + - read-only strings + - C++ compatibility + - Daniel Stekloff <dsteklof@us.ibm.com> + * Removed "-t" option + +07/08/2003 - Daniel Stekloff <dsteklof@us.ibm.com> + * Created NEWS file listing version history + +07/07/2003 - Daniel Stekloff <dsteklof@us.ibm.com> + * Merged version 0.1.0 into main tree + * Tagged new branch - version 0.1.1 + +07/07/2003 - Ananth Mavinakayanahalli <ananth@in.ibm.com> + * Added parent reference to sysfs_device + * Added device reference to sysfs_driver + +06/30/2003 - Initial Version Released diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..ab758cf --- /dev/null +++ b/Makefile @@ -0,0 +1,12 @@ +# sysutils Makefile +# +# Copyright (c) International Business Machines Corp., 2003 +# + +all: + $(MAKE) -C lib + $(MAKE) -C cmd + +clean: + $(MAKE) -C lib clean + $(MAKE) -C cmd clean @@ -0,0 +1,15 @@ +Version History: +--------------- + + 0.1.1 - Current Development Branch + * Created NEWS file for Version History. + * Added device reference in sysfs_driver. + * Added parent reference in sysfs_device. + * Applied Lev Makhlis' code cleanup patch. + * Removed "-t" option. + * Added binary attribute support. + * Changed sysfs_dlink to generic sysfs_link and + removed sysfs_read_dlinks function. + * Changed sysutils to sysfsutils + + 0.1.0 - Released June 30, 2003 @@ -0,0 +1,61 @@ + + System Utilities Package - Includes Libsysfs(v. 0.1.1) + ====================================================== + +Contents +-------- + 1. Introduction + 2. How to Install + 3. Licenses + 4. Reporting Bugs + + +1. Introduction +--------------- + +This package's purpose is to provide a set of utilities for interfacing +with sysfs, a virtual filesystem in Linux kernel versions 2.5+ that +provides a tree of system devices. While a filesystem is a very useful +interface, we've decided to provide a stable programming interface +that will hopefully make it easier for applications to query system devices +and their attributes. + +This package currently includes: + +- libsysfs: a library for accessing system devices. +- lsbus: a small application to query system bus information. +- systool: an application to view system device information by bus, class, + and topology. + + +2. How to Install +----------------- + +Use make to create the library and the commands. + + +3. Licenses +----------- + +The commands are licensed under the GNU Public License (GPL) Version2, +June 1991. The full text of the GPL is located in this package's "cmd" +directory: + +sysutils/cmd/GPL + +The library is licensed under the GNU Lesser Public License (LGPL) +Version 2.1, February 1999. The full text of the LGPL is located in +this package's "lib" directory: + +sysutils/lib/LGPL + + +4. Reporting Bugs +----------------- + +Please direct all bugs to either the linux-diag mailing list - +linux-diag@lists.sourceforge.net - or to the authors: + +Ananth Mavinakayanahalli <ananth@in.ibm.com> +Daniel Stekloff <dsteklof@us.ibm.com> + @@ -0,0 +1,18 @@ +Library: +-------- +- Implement a better device tree, so we can eventually walk the tree. +- Add write attribute write commands: + sysfs_write_attribute() + sysfs_write_attribute_value() +- Possibly add abstract data list to make device tree easier and to + give calling applications a means to easily manage large lists + of devices. +- Make bus lists of devices using topology. +- Need to properly set errno. + +Commands: +--------- +- Add capability to just take a device as an argument. +- Add topology tree view. +- Need to clean up error messages. +- Clean up how attribute values are printed. @@ -0,0 +1,272 @@ + + The GNU General Public License (GPL) + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your freedom to + share and change it. By contrast, the GNU General Public License is + intended to guarantee your freedom to share and change free software--to + make sure the software is free for all its users. This General Public + License applies to most of the Free Software Foundation's software and to + any other program whose authors commit to using it. (Some other Free + Software Foundation software is covered by the GNU Library General Public + License instead.) You can apply it to your programs, too. + + When we speak of free software, we are referring to freedom, not price. + Our General Public Licenses are designed to make sure that you have the + freedom to distribute copies of free software (and charge for this service + if you wish), that you receive source code or can get it if you want it, + that you can change the software or use pieces of it in new free programs; + and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid anyone to + deny you these rights or to ask you to surrender the rights. These + restrictions translate to certain responsibilities for you if you + distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether gratis or + for a fee, you must give the recipients all the rights that you have. You + must make sure that they, too, receive or can get the source code. And you + must show them these terms so they know their rights. + + We protect your rights with two steps: (1) copyright the software, and (2) + offer you this license which gives you legal permission to copy, + distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain that + everyone understands that there is no warranty for this free software. If + the software is modified by someone else and passed on, we want its + recipients to know that what they have is not the original, so that any + problems introduced by others will not reflect on the original authors' + reputations. + + Finally, any free program is threatened constantly by software patents. We + wish to avoid the danger that redistributors of a free program will + individually obtain patent licenses, in effect making the program + proprietary. To prevent this, we have made it clear that any patent must + be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and + modification follow. + + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains a + notice placed by the copyright holder saying it may be distributed under + the terms of this General Public License. The "Program", below, refers to + any such program or work, and a "work based on the Program" means either + the Program or any derivative work under copyright law: that is to say, a + work containing the Program or a portion of it, either verbatim or with + modifications and/or translated into another language. (Hereinafter, + translation is included without limitation in the term "modification".) + Each licensee is addressed as "you". + + Activities other than copying, distribution and modification are not + covered by this License; they are outside its scope. The act of running + the Program is not restricted, and the output from the Program is covered + only if its contents constitute a work based on the Program (independent + of having been made by running the Program). Whether that is true depends + on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's source + code as you receive it, in any medium, provided that you conspicuously and + appropriately publish on each copy an appropriate copyright notice and + disclaimer of warranty; keep intact all the notices that refer to this + License and to the absence of any warranty; and give any other recipients + of the Program a copy of this License along with the Program. + + You may charge a fee for the physical act of transferring a copy, and you + may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion of it, + thus forming a work based on the Program, and copy and distribute such + modifications or work under the terms of Section 1 above, provided that + you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices stating + that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in whole + or in part contains or is derived from the Program or any part thereof, + to be licensed as a whole at no charge to all third parties under the + terms of this License. + + c) If the modified program normally reads commands interactively when + run, you must cause it, when started running for such interactive use in + the most ordinary way, to print or display an announcement including an + appropriate copyright notice and a notice that there is no warranty (or + else, saying that you provide a warranty) and that users may + redistribute the program under these conditions, and telling the user + how to view a copy of this License. (Exception: if the Program itself is + interactive but does not normally print such an announcement, your work + based on the Program is not required to print an announcement.) + + These requirements apply to the modified work as a whole. If identifiable + sections of that work are not derived from the Program, and can be + reasonably considered independent and separate works in themselves, then + this License, and its terms, do not apply to those sections when you + distribute them as separate works. But when you distribute the same + sections as part of a whole which is a work based on the Program, the + distribution of the whole must be on the terms of this License, whose + permissions for other licensees extend to the entire whole, and thus to + each and every part regardless of who wrote it. + + Thus, it is not the intent of this section to claim rights or contest your + rights to work written entirely by you; rather, the intent is to exercise + the right to control the distribution of derivative or collective works + based on the Program. + + In addition, mere aggregation of another work not based on the Program + with the Program (or with a work based on the Program) on a volume of a + storage or distribution medium does not bring the other work under the + scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, under + Section 2) in object code or executable form under the terms of Sections 1 + and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable source + code, which must be distributed under the terms of Sections 1 and 2 + above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three years, to + give any third party, for a charge no more than your cost of physically + performing source distribution, a complete machine-readable copy of the + corresponding source code, to be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer to + distribute corresponding source code. (This alternative is allowed only + for noncommercial distribution and only if you received the program in + object code or executable form with such an offer, in accord with + Subsection b above.) + + The source code for a work means the preferred form of the work for making + modifications to it. For an executable work, complete source code means + all the source code for all modules it contains, plus any associated + interface definition files, plus the scripts used to control compilation + and installation of the executable. However, as a special exception, the + source code distributed need not include anything that is normally + distributed (in either source or binary form) with the major components + (compiler, kernel, and so on) of the operating system on which the + executable runs, unless that component itself accompanies the executable. + + If distribution of executable or object code is made by offering access to + copy from a designated place, then offering equivalent access to copy the + source code from the same place counts as distribution of the source code, + even though third parties are not compelled to copy the source along with + the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program except + as expressly provided under this License. Any attempt otherwise to copy, + modify, sublicense or distribute the Program is void, and will + automatically terminate your rights under this License. However, parties + who have received copies, or rights, from you under this License will not + have their licenses terminated so long as such parties remain in full + compliance. + + 5. You are not required to accept this License, since you have not signed + it. However, nothing else grants you permission to modify or distribute + the Program or its derivative works. These actions are prohibited by law + if you do not accept this License. Therefore, by modifying or distributing + the Program (or any work based on the Program), you indicate your + acceptance of this License to do so, and all its terms and conditions for + copying, distributing or modifying the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the + Program), the recipient automatically receives a license from the original + licensor to copy, distribute or modify the Program subject to these terms + and conditions. You may not impose any further restrictions on the + recipients' exercise of the rights granted herein. You are not responsible + for enforcing compliance by third parties to this License. + + 7. If, as a consequence of a court judgment or allegation of patent + infringement or for any other reason (not limited to patent issues), + conditions are imposed on you (whether by court order, agreement or + otherwise) that contradict the conditions of this License, they do not + excuse you from the conditions of this License. If you cannot distribute + so as to satisfy simultaneously your obligations under this License and + any other pertinent obligations, then as a consequence you may not + distribute the Program at all. For example, if a patent license would not + permit royalty-free redistribution of the Program by all those who receive + copies directly or indirectly through you, then the only way you could + satisfy both it and this License would be to refrain entirely from + distribution of the Program. + + If any portion of this section is held invalid or unenforceable under any + particular circumstance, the balance of the section is intended to apply + and the section as a whole is intended to apply in other circumstances. + + It is not the purpose of this section to induce you to infringe any + patents or other property right claims or to contest validity of any such + claims; this section has the sole purpose of protecting the integrity of + the free software distribution system, which is implemented by public + license practices. Many people have made generous contributions to the + wide range of software distributed through that system in reliance on + consistent application of that system; it is up to the author/donor to + decide if he or she is willing to distribute software through any other + system and a licensee cannot impose that choice. + + This section is intended to make thoroughly clear what is believed to be a + consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in certain + countries either by patents or by copyrighted interfaces, the original + copyright holder who places the Program under this License may add an + explicit geographical distribution limitation excluding those countries, + so that distribution is permitted only in or among countries not thus + excluded. In such case, this License incorporates the limitation as if + written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions of + the General Public License from time to time. Such new versions will be + similar in spirit to the present version, but may differ in detail to + address new problems or concerns. + + Each version is given a distinguishing version number. If the Program + specifies a version number of this License which applies to it and "any + later version", you have the option of following the terms and conditions + either of that version or of any later version published by the Free + Software Foundation. If the Program does not specify a version number of + this License, you may choose any version ever published by the Free + Software Foundation. + + 10. If you wish to incorporate parts of the Program into other free + programs whose distribution conditions are different, write to the author + to ask for permission. For software which is copyrighted by the Free + Software Foundation, write to the Free Software Foundation; we sometimes + make exceptions for this. Our decision will be guided by the two goals of + preserving the free status of all derivatives of our free software and of + promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY + FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN + OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES + PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED + OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS + TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE + PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, + REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING + WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR + REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, + INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES + ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT + LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES + SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE + WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + diff --git a/cmd/Makefile b/cmd/Makefile new file mode 100644 index 0000000..d53677e --- /dev/null +++ b/cmd/Makefile @@ -0,0 +1,20 @@ +# System utilities makefile + +CC=gcc + +CFLAGS=-g -Wall +INCLUDE=../include +LIB=../lib + +RM=rm -f + +all: lsbus systool + +lsbus: lsbus.c + $(CC) $(CFLAGS) -I$(INCLUDE) -o lsbus lsbus.c -lsysfs -L$(LIB) + +systool: systool.c + $(CC) $(CFLAGS) -I$(INCLUDE) -o systool systool.c -lsysfs -L$(LIB) + +clean: + $(RM) *.o *~ lsbus systool diff --git a/cmd/lsbus.c b/cmd/lsbus.c new file mode 100644 index 0000000..bd4676f --- /dev/null +++ b/cmd/lsbus.c @@ -0,0 +1,492 @@ +/* + * lsbus.c + * + * Utility to list bus devices + * + * Copyright (C) 2003 International Business Machines, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <mntent.h> +#include <dirent.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> +#include <ctype.h> + +#include "libsysfs.h" + +/* Command Options */ +static int show_options = 0; /* bitmask of show options */ +static char *attr_to_show = NULL; /* print value for this attribute */ +static char *bus_device = NULL; /* print only this bus device */ + +#define SHOW_ATTRIBUTES 0x01 /* show attributes command option */ +#define SHOW_ATTRIBUTE_VALUE 0x02 /* show an attribute value option */ +#define SHOW_DEVICES 0x04 /* show only devices option */ +#define SHOW_DRIVERS 0x08 /* show only drivers option */ +#define SHOW_ALL_ATTRIB_VALUES 0x10 /* show all attributes with values */ + +#define SHOW_ALL 0xff + +static char cmd_options[] = "aA:dDhv"; + +/* + * binary_files - defines existing sysfs binary files that should be printed + * in hex. + */ +static char *binary_files[] = { + "config", + "data" +}; + +static int binfiles = 2; + +/** + * usage: prints utility usage. + */ +void usage(void) +{ + fprintf(stdout, "Usage: lsbus [<options> bus [device]]\n"); + fprintf(stdout, "\t-a\t\t\tShow attributes\n"); + fprintf(stdout, "\t-d\t\t\tShow only devices\n"); + fprintf(stdout, "\t-h\t\t\tShow usage\n"); + fprintf(stdout, "\t-v\t\t\tShow all attributes with values\n"); + fprintf(stdout, "\t-A <attribute_name>\tShow attribute value\n"); + fprintf(stdout, "\t-D\t\t\tShow only drivers\n"); +} + +/** + * remove_end_newline: removes newline on the end of an attribute value + * @value: string to remove newline from + */ +void remove_end_newline(char *value) +{ + char *p = value + (strlen(value) - 1); + + if (p != NULL && *p == '\n') + *p = '\0'; +} + +/** + * print_device_children: prints out device subdirs. + * @sdir: print this directory's subdirectories/children. + */ +void print_device_children(struct sysfs_directory *sdir) +{ + if (sdir != NULL) { + fprintf(stdout, "\tChildren:\n"); + if (sdir->subdirs != NULL) { + char dirname[SYSFS_NAME_LEN]; + struct sysfs_directory *cur = sdir->subdirs; + + while (cur != NULL) { + if ((sysfs_get_name_from_path(cur->path, + dirname, SYSFS_NAME_LEN)) == 0) + fprintf(stdout, "\t\t%s\n", dirname); + else + fprintf(stdout, "\t\t%s\n", cur->path); + cur = cur->next; + } + } + if (sdir->links != NULL) { + struct sysfs_link *curl = sdir->links; + + while(curl != NULL) { + fprintf(stdout, "\t\t%s\n", curl->name); + curl = curl->next; + } + } + } +} + +/** + * isbinaryvalue: checks to see if attribute is binary or not. + * @attr: attribute to check. + * returns 1 if binary or 0 if not. + */ +int isbinaryvalue(struct sysfs_attribute *attr) +{ + char attrname[SYSFS_NAME_LEN]; + int i; + + if (attr == NULL || attr->value == NULL) + return 0; + if ((sysfs_get_name_from_path(attr->path, attrname, SYSFS_NAME_LEN)) + != 0) + return 0; + + for (i = 0; i < binfiles; i++) + if ((strcmp(attrname, binary_files[i])) == 0) + return 1; + + return 0; +} + +/** + * print_attribute_value: prints out single attribute value. + * @attr: attricute to print. + */ +void print_attribute_value(struct sysfs_attribute *attr) +{ + if (attr == NULL) + return; + + if (attr->method & SYSFS_METHOD_SHOW) { + if (isbinaryvalue(attr) != 0) { + int i; + fprintf(stdout, "\t: "); + for (i = 0; i < attr->len; i++) { + if (!(i %16)) { + fprintf(stdout, "\n\t\t\t"); + } else if (!(i %8)) + fprintf(stdout, " "); + fprintf(stdout, "%02x ", + (unsigned char)attr->value[i]); + } + fprintf(stdout, "\n"); + + } else if (attr->value != NULL && strlen(attr->value) > 0) { + remove_end_newline(attr->value); + fprintf(stdout, "\t: %s\n", attr->value); + } else + fprintf(stdout, "\n"); + } else { + fprintf(stdout, "\t: store method only\n"); + } +} + +/** + * print_attribute: prints out a single attribute + * @attr: attribute to print. + */ +void print_attribute(struct sysfs_attribute *attr) +{ + char attrname[SYSFS_NAME_LEN]; + + if (attr == NULL) + return; + + if ((sysfs_get_name_from_path(attr->path, attrname, SYSFS_NAME_LEN)) + != 0) + return; + + if (show_options & SHOW_ALL_ATTRIB_VALUES) { + fprintf(stdout, "\t\t%s", attrname); + print_attribute_value(attr); + + } else if ((show_options & SHOW_ATTRIBUTES) || ((show_options + & SHOW_ATTRIBUTE_VALUE) && (strcmp(attrname, attr_to_show) + == 0))) { + fprintf (stdout, "\t\t%s", attrname); + if (show_options & SHOW_ATTRIBUTE_VALUE && attr->value != NULL + && (strcmp(attrname, attr_to_show)) == 0) { + print_attribute_value(attr); + } else { + fprintf(stdout, "\n"); + } + } +} + +/** + * print_device_attributes: prints out device attributes. + * @sdir: print this directory's attributes/files. + */ +void print_device_attributes(struct sysfs_directory *sdir) +{ + if (sdir != NULL && sdir->attributes != NULL) { + struct sysfs_attribute *cur = sdir->attributes; + + fprintf (stdout, "\tAttributes:\n"); + while (cur != NULL) { + print_attribute(cur); + cur = cur->next; + } + } +} + +/** + * print_device: prints out device information. + * @device: device to print. + */ +void print_device(struct sysfs_device *device) +{ + if (device != NULL && device->directory != NULL) { + fprintf (stdout, " %s %s\n", device->bus_id, device->name); + if (device->directory->subdirs != NULL + || device->directory->links != NULL) + print_device_children(device->directory); + if (device->directory->attributes != NULL && (show_options + & (SHOW_ATTRIBUTES | SHOW_ATTRIBUTE_VALUE + | SHOW_ALL_ATTRIB_VALUES))) + print_device_attributes(device->directory); + if (device->driver != NULL) + fprintf (stdout, "\tDriver: %s\n", + device->driver->name); + } +} + +/** + * print_driver_attributes: prints out driver attributes . + * @driver: print this driver's attributes. + */ +void print_driver_attributes(struct sysfs_driver *driver) +{ + if (driver != NULL && driver->directory != NULL) { + struct sysfs_directory *sdir = driver->directory; + + if (sdir->attributes != NULL) { + struct sysfs_attribute *cur = sdir->attributes; + + fprintf (stdout, "\t%s Attributes:\n", driver->name); + while (cur != NULL) { + print_attribute(cur); + cur = cur->next; + } + } + } +} + +/** + * print_driver_devices: prints out devices under driver. + * @driver: print devices bound to this driver. + */ +void print_driver_devices(struct sysfs_driver *driver) +{ + if (driver != NULL && driver->directory != NULL) { + struct sysfs_directory *sdir = driver->directory; + + if (sdir->links != NULL) { + struct sysfs_link *cur = sdir->links; + + fprintf (stdout, "\tDevices:\n"); + while (cur != NULL) { + fprintf(stdout, "\t\t%s\n", cur->name); + cur = cur->next; + } + } + } +} + +/** + * print_driver: prints out driver information. + * @driver: driver to print. + */ +void print_driver(struct sysfs_driver *driver) +{ + struct sysfs_directory *sdir = NULL; + + if (driver != NULL) { + fprintf (stdout, " %s\n", driver->name); + sdir = driver->directory; + if (sdir != NULL) { + if (sdir->links != NULL) + print_driver_devices(driver); + if(sdir->attributes != NULL && (show_options + & (SHOW_ATTRIBUTES | SHOW_ATTRIBUTE_VALUE + | SHOW_ALL_ATTRIB_VALUES))) + print_driver_attributes(driver); + } + } +} + +/** + * print_default_bus: prints out everything on a bus. + * @busname: bus to print. + * returns 0 with success or 1 with error. + */ +int print_sysfs_bus(char *busname) +{ + struct sysfs_bus *bus = NULL; + struct sysfs_device *curdev = NULL; + struct sysfs_driver *curdrv = NULL; + + if (busname == NULL) { + errno = EINVAL; + return 1; + } + bus = sysfs_open_bus(busname); + if (bus == NULL) { + fprintf(stderr, "Error opening bus %s\n", busname); + return 1; + } + + fprintf(stdout, "Bus: %s\n", busname); + if (bus->devices != NULL && (show_options & SHOW_DEVICES)) { + curdev = bus->devices; + if (bus_device == NULL) + fprintf(stdout, "Devices:\n"); + while (curdev != NULL) { + if (bus_device == NULL || (strcmp(bus_device, + curdev->bus_id) == 0)) + print_device(curdev); + curdev = curdev->next; + } + } + if (bus->drivers != NULL && (show_options & SHOW_DRIVERS)) { + curdrv = bus->drivers; + fprintf(stdout, "Drivers:\n"); + while (curdrv != NULL) { + print_driver(curdrv); + curdrv = curdrv->next; + } + } + sysfs_close_bus(bus); + return 0; +} + +/** + * print_sysfs_buses: prints out supported buses. + * @buses: list of supported system buses. + * returns 0 with success or 1 with error. + */ +int print_sysfs_buses(void) +{ + struct sysfs_directory *busdir = NULL, *current = NULL; + char busname[SYSFS_NAME_LEN]; + char buspath[SYSFS_PATH_MAX]; + int ret = 0; + + /* get sysfs mount point */ + if ((sysfs_get_mnt_path(buspath, SYSFS_PATH_MAX) != 0)) { + perror("sysfs_get_mnt_path"); + fprintf(stderr, "Error getting sysfs mount path - exiting\n"); + exit(1); + } + strcat(buspath, SYSFS_BUS_DIR); + busdir = sysfs_open_directory(buspath); + if (busdir == NULL) { + fprintf(stderr, "Error opening sysfs bus directory at %s\n", + buspath); + return 1; + } + if ((sysfs_read_directory(busdir)) != 0) { + fprintf(stderr, "Error reading sysfs bus directory at %s\n", + buspath); + sysfs_close_directory(busdir); + return 1; + } + + fprintf(stdout, "Supported sysfs buses:\n"); + current = busdir->subdirs; + while (current != NULL) { + if ((sysfs_get_name_from_path(current->path, busname, + SYSFS_NAME_LEN)) != 0) { + sysfs_close_directory(busdir); + return 1; + } + fprintf(stdout, "\t%s\n", busname); + current = current->next; + } + sysfs_close_directory(busdir); + return ret; +} + +/* MAIN */ +int main(int argc, char *argv[]) +{ + char *bus_to_print = NULL; + int retval = 0; + int opt; + extern int optind; + extern char *optarg; + + while((opt = getopt(argc, argv, cmd_options)) != EOF) { + switch(opt) { + case 'a': + show_options |= SHOW_ATTRIBUTES; + break; + case 'A': + if ((strlen(optarg) + 1) > SYSFS_NAME_LEN) { + fprintf(stderr, + "Attribute name %s is too long\n", + optarg); + exit(1); + } + attr_to_show = optarg; + show_options |= SHOW_ATTRIBUTE_VALUE; + break; + case 'd': + show_options |= SHOW_DEVICES; + break; + case 'D': + show_options |= SHOW_DRIVERS; + break; + case 'h': + usage(); + exit(0); + break; + case 'v': + show_options |= SHOW_ALL_ATTRIB_VALUES; + break; + default: + usage(); + exit(1); + } + } + argc -= optind; + argv += optind; + + switch(argc) { + case 0: + break; + case 1: + /* get bus to view */ + if ((strlen(*argv)+1) < SYSFS_NAME_LEN) + bus_to_print = *argv; + else + fprintf(stderr, + "Invalid argument: busname too long\n"); + break; + case 2: + /* get bus and device to view */ + if ((strlen(argv[0])) < SYSFS_NAME_LEN && (strlen(argv[1])) + < SYSFS_NAME_LEN) { + bus_to_print = argv[0]; + bus_device = argv[1]; + show_options |= SHOW_DEVICES; + } else { + fprintf(stderr, + "Invalid argument: bus or device name too long\n"); + exit(1); + } + break; + default: + usage(); + exit(1); + } + + if (bus_to_print == NULL && (show_options & (SHOW_ATTRIBUTES + | SHOW_ATTRIBUTE_VALUE | SHOW_DEVICES | SHOW_DRIVERS + | SHOW_ALL_ATTRIB_VALUES))) { + fprintf(stderr, "Please specify a bus\n"); + usage(); + exit(1); + } + /* default is to print devices */ + if (!(show_options & (SHOW_DEVICES | SHOW_DRIVERS))) + show_options |= SHOW_DEVICES; + + if (bus_to_print != NULL) + retval = print_sysfs_bus(bus_to_print); + else + retval = print_sysfs_buses(); + + exit(retval); +} diff --git a/cmd/systool.c b/cmd/systool.c new file mode 100644 index 0000000..60c8d67 --- /dev/null +++ b/cmd/systool.c @@ -0,0 +1,706 @@ +/* + * systool.c + * + * Sysfs utility to list buses, classes, and devices + * + * Copyright (C) 2003 International Business Machines, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <mntent.h> +#include <dirent.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> +#include <ctype.h> + +#include "libsysfs.h" + +/* Command Options */ +static int show_options = 0; /* bitmask of show options */ +static char *attribute_to_show = NULL; /* show value for this attribute */ +static char *device_to_show = NULL; /* show only this bus device */ + +#define SHOW_ATTRIBUTES 0x01 /* show attributes command option */ +#define SHOW_ATTRIBUTE_VALUE 0x02 /* show an attribute value option */ +#define SHOW_DEVICES 0x04 /* show only devices option */ +#define SHOW_DRIVERS 0x08 /* show only drivers option */ +#define SHOW_ALL_ATTRIB_VALUES 0x10 /* show all attributes with values */ + +#define SHOW_ALL 0xff + +static char cmd_options[] = "aA:b:c:dDhr:v"; + +/* + * binary_files - defines existing sysfs binary files. These files will be + * printed in hex. + */ +static char *binary_files[] = { + "config", + "data" +}; + +static int binfiles = 2; + +/** + * usage: prints utility usage. + */ +void usage(void) +{ + fprintf(stdout, "Usage: systool [<options> [device]]\n"); + fprintf(stdout, "\t-a\t\t\tShow attributes\n"); + fprintf(stdout, "\t-b <bus_name>\t\tShow a specific bus\n"); + fprintf(stdout, "\t-c <class_name>\t\tShow a specific class\n"); + fprintf(stdout, "\t-d\t\t\tShow only devices\n"); + fprintf(stdout, "\t-h\t\t\tShow usage\n"); + fprintf(stdout, + "\t-r <root_device>\tShow a specific root device tree\n"); + fprintf(stdout, "\t-v\t\t\tShow all attributes with values\n"); + fprintf(stdout, "\t-A <attribute_name>\tShow attribute value\n"); + fprintf(stdout, "\t-D\t\t\tShow only drivers\n"); +} + +/** + * indent: called before printing a line, it adds indent to the line up to + * level passed in. + * @level: number of spaces to indent. + */ +void indent(int level) +{ + int i; + + for (i = 0; i <= level; i++) + fprintf(stdout, " "); +} + +/** + * remove_end_newline: removes newline on the end of an attribute value + * @value: string to remove newline from + */ +void remove_end_newline(char *value) +{ + char *p = value + (strlen(value) - 1); + + if (p != NULL && *p == '\n') + *p = '\0'; +} + +/** + * show_device_children: prints out device subdirs. + * @sdir: print this directory's subdirectories/children. + */ +void show_device_children(struct sysfs_directory *sdir, int level) +{ + if (sdir != NULL) { + indent(level); + fprintf(stdout, "Children:\n"); + if (sdir->subdirs != NULL) { + char dirname[SYSFS_NAME_LEN]; + struct sysfs_directory *cur = sdir->subdirs; + + while (cur != NULL) { + indent(level+4); + if ((sysfs_get_name_from_path(cur->path, + dirname, SYSFS_NAME_LEN)) == 0) + fprintf(stdout, "%s\n", dirname); + else + fprintf(stdout, "%s\n", cur->path); + cur = cur->next; + } + } + if (sdir->links != NULL) { + struct sysfs_link *curl = sdir->links; + + while (curl != NULL) { + indent(level+4); + fprintf(stdout, "%s\n", curl->name); + curl = curl->next; + } + } + } +} + +/** + * isbinaryvalue: checks to see if attribute is binary or not. + * @attr: attribute to check. + * returns 1 if binary, 0 if not. + */ +int isbinaryvalue(struct sysfs_attribute *attr) +{ + char attrname[SYSFS_NAME_LEN]; + int i; + + if (attr == NULL || attr->value == NULL) + return 0; + + if ((sysfs_get_name_from_path(attr->path, attrname, SYSFS_NAME_LEN)) + != 0) + return 0; + + for (i = 0; i < binfiles; i++) + if ((strcmp(attrname, binary_files[i])) == 0) + return 1; + + return 0; +} + +/** + * show_attribute_value: prints out single attribute value. + * @attr: attricute to print. + */ +void show_attribute_value(struct sysfs_attribute *attr, int level) +{ + if (attr == NULL) + return; + + if (attr->method & SYSFS_METHOD_SHOW) { + if (isbinaryvalue(attr) != 0) { + int i; + fprintf(stdout, "\t: "); + for (i = 0; i < attr->len; i++) { + if (!(i %16)) { + fprintf(stdout, "\n"); + indent(level+8); + } else if (!(i %8)) + fprintf(stdout, " "); + fprintf(stdout, "%02x ", + (unsigned char)attr->value[i]); + } + fprintf(stdout, "\n"); + + } else if (attr->value != NULL && strlen(attr->value) > 0) { + remove_end_newline(attr->value); + fprintf(stdout, "\t: %s\n", attr->value); + } else + fprintf(stdout, "\n"); + } else { + fprintf(stdout, "\t: store method only\n"); + } +} + +/** + * show_attribute: prints out a single attribute + * @attr: attribute to print. + */ +void show_attribute(struct sysfs_attribute *attr, int level) +{ + char attrname[SYSFS_NAME_LEN]; + + if (attr == NULL) + return; + + if ((sysfs_get_name_from_path(attr->path, attrname, SYSFS_NAME_LEN)) + != 0) + return; + + if (show_options & SHOW_ALL_ATTRIB_VALUES) { + indent(level); + fprintf(stdout, "%s", attrname); + show_attribute_value(attr, level); + + } else if ((show_options & SHOW_ATTRIBUTES) || ((show_options + & SHOW_ATTRIBUTE_VALUE) && (strcmp(attrname, attribute_to_show) + == 0))) { + indent(level); + fprintf (stdout, "%s", attrname); + if (show_options & SHOW_ATTRIBUTE_VALUE && attr->value + != NULL && (strcmp(attrname, attribute_to_show)) == 0) + show_attribute_value(attr, level); + + else + fprintf(stdout, "\n"); + } +} + +/** + * show_attributes: prints out a directory's attributes. + * @sdir: print this directory's attributes/files. + */ +void show_attributes(struct sysfs_directory *sdir, int level) +{ + if (sdir != NULL && sdir->attributes != NULL) { + struct sysfs_attribute *cur = sdir->attributes; + + indent(level); + fprintf (stdout, "Attributes:\n"); + while (cur != NULL) { + show_attribute(cur, (level+4)); + cur = cur->next; + } + } +} + +/** + * show_device: prints out device information. + * @device: device to print. + */ +void show_device(struct sysfs_device *device, int level) +{ + if (device != NULL && device->directory != NULL) { + indent(level); + fprintf (stdout, "%s %s\n", device->bus_id, device->name); + if (device->directory->subdirs != NULL + || device->directory->links != NULL) + show_device_children(device->directory, (level+4)); + if (device->directory->attributes != NULL && (show_options + & (SHOW_ATTRIBUTES | SHOW_ATTRIBUTE_VALUE + | SHOW_ALL_ATTRIB_VALUES))) + show_attributes(device->directory, (level+4)); + if (device->driver != NULL) { + indent(level+4); + fprintf (stdout, "Driver: %s\n", + device->driver->name); + } + } +} + +/** + * show_root_device: prints out sys/devices device information. + * @device: device to print. + */ +void show_root_device(struct sysfs_device *device, int level) +{ + if (device != NULL && device->directory != NULL) { + indent(level); + fprintf (stdout, "%s %s\n", device->bus_id, device->name); + if (device->directory->attributes != NULL && (show_options + & (SHOW_ATTRIBUTES | SHOW_ATTRIBUTE_VALUE + | SHOW_ALL_ATTRIB_VALUES))) + show_attributes(device->directory, (level+4)); + } +} + +/** + * show_driver_attributes: prints out driver attributes . + * @driver: print this driver's attributes. + */ +void show_driver_attributes(struct sysfs_driver *driver, int level) +{ + if (driver != NULL && driver->directory != NULL) { + struct sysfs_directory *sdir = driver->directory; + + if (sdir->attributes != NULL) { + struct sysfs_attribute *cur = sdir->attributes; + + indent(level); + fprintf (stdout, "%s Attributes:\n", driver->name); + while (cur != NULL) { + show_attribute(cur, (level+4)); + cur = cur->next; + } + } + } +} + +/** + * show_driver_devices: prints out devices under driver. + * @driver: print devices bound to this driver. + */ +void show_driver_devices(struct sysfs_driver *driver, int level) +{ + if (driver != NULL && driver->directory != NULL) { + struct sysfs_directory *sdir = driver->directory; + + if (sdir->links != NULL) { + struct sysfs_link *cur = sdir->links; + + indent(level); + fprintf (stdout, "Devices:\n"); + while (cur != NULL) { + indent(level+4); + fprintf (stdout, "%s\n", cur->name); + cur = cur->next; + } + } + } +} + +/** + * show_driver: prints out driver information. + * @driver: driver to print. + */ +void show_driver(struct sysfs_driver *driver, int level) +{ + struct sysfs_directory *sdir = NULL; + + if (driver != NULL) { + indent(level); + fprintf (stdout, "%s\n", driver->name); + sdir = driver->directory; + if (sdir != NULL) { + if (sdir->links != NULL) + show_driver_devices(driver, (level+4)); + if(sdir->attributes != NULL && (show_options + & (SHOW_ATTRIBUTES | SHOW_ATTRIBUTE_VALUE + | SHOW_ALL_ATTRIB_VALUES))) + show_driver_attributes(driver, (level+4)); + } + } +} + +/** + * show_device_tree: prints out device tree. + * @root: root device + */ +void show_device_tree(struct sysfs_device *root, int level) +{ + if (root != NULL) { + struct sysfs_device *cur = NULL; + + if (device_to_show == NULL || (strcmp(device_to_show, + root->bus_id) == 0)) { + show_root_device(root, level); + } + cur = root->children; + while (cur != NULL) { + show_device_tree(cur, (level+6)); + cur = cur->next; + } + } +} + +/** + * show_sysfs_bus: prints out everything on a bus. + * @busname: bus to print. + * returns 0 with success or 1 with error. + */ +int show_sysfs_bus(char *busname) +{ + struct sysfs_bus *bus = NULL; + struct sysfs_device *curdev = NULL; + struct sysfs_driver *curdrv = NULL; + + if (busname == NULL) { + errno = EINVAL; + return 1; + } + bus = sysfs_open_bus(busname); + if (bus == NULL) { + fprintf(stderr, "Error opening bus %s\n", busname); + return 1; + } + + fprintf(stdout, "Bus: %s\n", busname); + if (bus->devices != NULL && (show_options & SHOW_DEVICES)) { + curdev = bus->devices; + if (device_to_show == NULL) + fprintf(stdout, "Devices:\n"); + while (curdev != NULL) { + if (device_to_show == NULL || (strcmp(device_to_show, + curdev->bus_id) == 0)) + show_device(curdev, 2); + curdev = curdev->next; + } + } + if (bus->drivers != NULL && (show_options & SHOW_DRIVERS)) { + curdrv = bus->drivers; + fprintf(stdout, "Drivers:\n"); + while (curdrv != NULL) { + show_driver(curdrv, 2); + curdrv = curdrv->next; + } + } + sysfs_close_bus(bus); + return 0; +} + +/** + * show_class_device: prints out class device. + * @dev: class device to print. + */ +void show_class_device(struct sysfs_class_device *dev, int level) +{ + struct sysfs_directory *cur = NULL; + char dirname[SYSFS_NAME_LEN]; + + if (dev != NULL) { + indent(level); + fprintf(stdout, "%s\n", dev->name); + if (dev->directory != NULL && (show_options + & (SHOW_ATTRIBUTES | SHOW_ATTRIBUTE_VALUE + | SHOW_ALL_ATTRIB_VALUES))) { + show_attributes(dev->directory, (level+4)); + cur = dev->directory->subdirs; + while (cur != NULL) { + if ((sysfs_get_name_from_path(cur->path, + dirname, SYSFS_NAME_LEN)) == 0) { + indent(level+4); + fprintf(stdout, "%s\n", dirname); + } + show_attributes(cur, (level+4)); + cur = cur->next; + } + } + if (dev->sysdevice != NULL && (show_options & SHOW_DEVICES)) + show_device(dev->sysdevice, (level+4)); + if (dev->driver != NULL && (show_options & SHOW_DRIVERS)) + show_driver(dev->driver, (level+4)); + } +} + +/** + * show_sysfs_class: prints out sysfs class and all its devices. + * @classname: class to print. + * returns 0 with success and 1 with error. + */ +int show_sysfs_class(char *classname) +{ + struct sysfs_class *cls = NULL; + struct sysfs_class_device *cur = NULL; + + if (classname == NULL) { + errno = EINVAL; + return 1; + } + cls = sysfs_open_class(classname); + if (cls == NULL) { + fprintf(stderr, "Error opening class %s\n", classname); + return 1; + } + fprintf(stdout, "Class: %s\n", classname); + if (cls->devices != NULL) { + cur = cls->devices; + if (device_to_show == NULL) + fprintf(stdout, "Class Devices:\n"); + while (cur != NULL) { + if (device_to_show == NULL || (strcmp(device_to_show, + cur->name) == 0)) + show_class_device(cur, 2); + cur = cur->next; + } + } + + sysfs_close_class(cls); + return 0; +} + +/** + * show_sysfs_root: prints out sysfs root device tree + * @rootname: device root to print. + * returns 0 with success and 1 with error. + */ +int show_sysfs_root(char *rootname) +{ + struct sysfs_device *root = NULL; + char path[SYSFS_PATH_MAX]; + + if (rootname == NULL) { + errno = EINVAL; + return 1; + } + if (sysfs_get_mnt_path(path, SYSFS_PATH_MAX) != 0) { + perror("sysfs_get_mnt_path"); + fprintf(stderr, "Error getting sysfs mount point\n"); + exit(1); + } + + strcat(path, SYSFS_DEVICES_DIR); + strcat(path, "/"); + strcat(path, rootname); + root = sysfs_open_device_tree(path); + if (root == NULL) { + fprintf(stderr, "Error opening root device %s\n", rootname); + return 1; + } + fprintf(stdout, "Root Device Tree: %s\n", rootname); + show_device_tree(root, 2); + sysfs_close_device_tree(root); + + return 0; +} + +/** + * show_subdirectories: prints all subdirectory names at path + * @path: sysfs path where subdirs are. + * returns 0 with success or 1 with error. + */ +int show_subdirectories(char *path, int level) +{ + struct sysfs_directory *dir = NULL, *current = NULL; + char name[SYSFS_NAME_LEN]; + int ret = 0; + + dir = sysfs_open_directory(path); + if (dir == NULL) { + fprintf(stderr, "Error opening sysfs directory at %s\n", path); + return 1; + } + if ((sysfs_read_directory(dir)) != 0) { + fprintf(stderr, "Error reading sysfs directory at %s\n", path); + sysfs_close_directory(dir); + return 1; + } + + current = dir->subdirs; + while (current != NULL) { + if ((sysfs_get_name_from_path(current->path, name, + SYSFS_NAME_LEN)) != 0) { + sysfs_close_directory(dir); + return 1; + } + indent(level); + fprintf(stdout, "%s\n", name); + current = current->next; + } + sysfs_close_directory(dir); + return ret; +} + +/** + * show_default_info: prints current buses, classes, and root devices + * supported by sysfs. + * returns 0 with success or 1 with error. + */ +int show_default_info(void) +{ + char sysfs_root[SYSFS_PATH_MAX]; + char path_to_print[SYSFS_PATH_MAX]; + int retval = 0; + + /* get sysfs mount point */ + if (sysfs_get_mnt_path(sysfs_root, SYSFS_PATH_MAX) != 0) { + perror("sysfs_get_mnt_path"); + fprintf(stderr, "Error getting sysfs mount point\n"); + exit(1); + } + strcpy(path_to_print, sysfs_root); + + /* print supported buses */ + strcat(path_to_print, SYSFS_BUS_DIR); + fprintf(stdout, "Supported sysfs buses:\n"); + retval = show_subdirectories(path_to_print, 4); + + if (retval == 0) { + /* print supported classes */ + strcpy(path_to_print, sysfs_root); + strcat(path_to_print, SYSFS_CLASS_DIR); + fprintf(stdout, "Supported sysfs classes:\n"); + retval = show_subdirectories(path_to_print, 4); + } + + if (retval == 0) { + /* print supported root devices */ + strcpy(path_to_print, sysfs_root); + strcat(path_to_print, SYSFS_DEVICES_DIR); + fprintf(stdout, "Supported sysfs root devices:\n"); + retval = show_subdirectories(path_to_print, 4); + } + + return retval; +} + +/* MAIN */ +int main(int argc, char *argv[]) +{ + char *show_bus = NULL; + char *show_class = NULL; + char *show_root = NULL; + int retval = 0; + int opt; + extern int optind; + extern char *optarg; + + while((opt = getopt(argc, argv, cmd_options)) != EOF) { + switch(opt) { + case 'a': + show_options |= SHOW_ATTRIBUTES; + break; + case 'A': + if ((strlen(optarg) + 1) > SYSFS_NAME_LEN) { + fprintf(stderr, + "Attribute name %s is too long\n", + optarg); + exit(1); + } + attribute_to_show = optarg; + show_options |= SHOW_ATTRIBUTE_VALUE; + break; + case 'b': + show_bus = optarg; + break; + case 'c': + show_class = optarg; + break; + case 'd': + show_options |= SHOW_DEVICES; + break; + case 'D': + show_options |= SHOW_DRIVERS; + break; + case 'h': + usage(); + exit(0); + break; + case 'r': + show_root = optarg; + break; + case 'v': + show_options |= SHOW_ALL_ATTRIB_VALUES; + break; + default: + usage(); + exit(1); + } + } + argc -= optind; + argv += optind; + + switch(argc) { + case 0: + break; + case 1: + /* get bus to view */ + if ((strlen(*argv)) < SYSFS_NAME_LEN) { + device_to_show = *argv; + show_options |= SHOW_DEVICES; + } else { + fprintf(stderr, + "Invalid argument - device name too long\n"); + exit(1); + } + break; + default: + usage(); + exit(1); + } + + if ((show_bus == NULL && show_class == NULL && show_root == NULL) + && (show_options & (SHOW_ATTRIBUTES | SHOW_ATTRIBUTE_VALUE + | SHOW_DEVICES | SHOW_DRIVERS | SHOW_ALL_ATTRIB_VALUES))) { + fprintf(stderr, + "Please specify a bus, class, or root device\n"); + usage(); + exit(1); + } + /* default is to print devices */ + if (!(show_options & (SHOW_DEVICES | SHOW_DRIVERS))) + show_options |= SHOW_DEVICES; + + if (show_bus != NULL) + retval = show_sysfs_bus(show_bus); + if (show_class != NULL) + retval = show_sysfs_class(show_class); + if (show_root != NULL) + retval = show_sysfs_root(show_root); + + if (show_bus == NULL && show_class == NULL && show_root == NULL) + retval = show_default_info(); + + exit(retval); +} diff --git a/docs/libsysfs.txt b/docs/libsysfs.txt new file mode 100644 index 0000000..c38d74d --- /dev/null +++ b/docs/libsysfs.txt @@ -0,0 +1,769 @@ + + System Utilities sysfs Library - libsysfs + ========================================= + +Version: 0.1.0 +June 30, 2003 + +Contents +-------- +1. Introduction +2. Requirements +3. Definitions +4. Overview +5. Data Structures + 5.1 Directory and Attribute Data Structures + 5.1.1 Attribute Structure + 5.1.2 Link Structure + 5.1.3 Directory Structure + 5.2 Bus Data Structure + 5.3 Class Data Structures + 5.4 Device Data Structure + 5.5 Driver Data Structure +6. Functions + 6.1 Utility Functions + 6.2 Filesystem Functions + 6.2.1 Attribute Functions + 6.2.2 Directory Link Functions + 6.2.3 Directory Functions + 6.3 Bus Functions + 6.4 Class Functions + 6.5 Device Functions + 6.6 Driver Functions +7. Usage +8. Conclusion + + +1. Introduction +--------------- + +Libsysfs' purpose is to provide a consistant and stable interface for +querying system device information exposed through the sysfs filesystem. +The library implements functions for querying filesystem information, +such as reading directories and files. It also contains routines for +working with buses, classes, and the device tree. + + +2. Requirements +--------------- + +The library must satisfy the following requirements: + +- It must provide a stable programming interfaces that applications can + be built upon. + +- It must provide functions to retrieve device Vital Product Data (VPD) + information for Error Log Analysis (ELA) support. ELA will provide + device driver and device bus address information. + +- It must provide access to all system devices and information exposed + by sysfs. + +- It must provide a function to find sysfs' current mount point. + +- It must provide a function for udev to retrieve a device's major and + minor numbers. + + +3. Definitions +-------------- + +- sysfs: Sysfs is a virtual filesystem in 2.5+ Linux kernels that + presents a hierarchical representation of all system physical and + virtual devices. It presents system devices by bus, by class, and + by topology. Callbacks to device drivers are exposed as files in + device directories. Sysfs, for all purposes, is our tree of system + devices. For more information, please see: + + http://www.kernel.org/pub/linux/kernel/people/mochel/doc/ + +- udev: Udev is Greg Kroah-Hartman's User Space implementation of devfs. + Udev creates /dev nodes for devices upon Hotplug events. The Hotplug + event provides udev with a sysfs directory location of the device. Udev + must use that directory to grab device's major and minor number, which it + will use to create the /dev node. For more information, please see: + + http://www.kernel.org/pub/linux/utils/kernel/hotplug/ + + +4. Overview +----------- + +Libsysfs grew from a common need. There are several applications under +development that need access to sysfs and system devices. Udev, on a +hotplug event, must take a sysfs device path and create a /dev node. Our +diagnostic client needs to list all system devices. Finally, our Error +Log Analysis piece is required to retrieve VPD information for a +failing device. We devided to create a single library interface rather +than having these separate applications create their own accesses to +sysfs involving reading directories and files. + +Libsysfs will also provide stability for applications to be built upon. Sysfs +currently doesn't enforce any standards for callback or file names. File +names change depending on bus or class. Sysfs is also changing, it is +currently being developed. Libsysfs will provide a stable interface to +applications while allowing sysfs to change underneath it. + +Like sysfs, the library will provide devices to applications by bus, by +class, and by topology. The library will function similar to directories +and files that lie underneath it. To query a device on a PCI bus, one would +"open" the bus to scan or read devices and "close" the bus when +completed. Besides supplying functions to retrieve devices, the library +will also provide some utility functions like getting sysfs mount point. + + +5. Data Structures +------------------ + +Libsysfs will classify system devices following sysfs' example, dividing +them by bus, class, and devices. The library presents this information +generically. It doesn't, for example, differentiate between PCI and USB +buses. Device attributes are presented with values as they are exposed +by sysfs, the values are not formatted. + +The library will provide standard definitions for working with sysfs +and devices, here's some examples: + +#define SYSFS_FSTYPE_NAME "sysfs" +#define SYSFS_PROC_MNTS "/proc/mounts" +#define SYSFS_BUS_DIR "/bus" +#define SYSFS_CLASS_DIR "/class" +#define SYSFS_DEVICES_DIR "/devices" +#define SYSFS_DEVICES_NAME "devices" +#define SYSFS_DRIVERS_DIR "/drivers" +#define SYSFS_DRIVERS_NAME "drivers" +#define SYSFS_NAME_ATTRIBUTE "name" + +The library uses some definitions to mark maximum size of a sysfs name or +path length: + +#define SYSFS_PATH_MAX 255 +#define SYSFS_NAME_LEN 50 +#define SYSFS_BUS_ID_SIZE 20 + + +5.1 Directory and Attribute Data Structures +------------------------------------------- + +The library implements structures to represent sysfs directories, links, +and files. + + +5.1.1 Attribute Structure +------------------------- + +A file in sysfs represents a device or driver attribute. Attributes can be +read only, write only, or read and write. File data can be ASCII and +binary. The library has the following structure to represent files: + +struct sysfs_attribute { + struct sysfs_attribute *next; + char path[SYSFS_PATH_MAX]; + char *value; + int method; /* show and store */ +}; + +The library links attributes together using the "next" pointer. Path +represents the file/attribute's full path. Value is used when reading +from or writing to an attribute. Method is a bitmask for defining if +the attribute supports show(read) and/or store(write). + + +5.1.2 Link Structure +-------------------- + +Symbolic links are used in sysfs to link bus or class views with +particular devices. + +struct sysfs_link { + struct sysfs_link *next; + char name[SYSFS_NAME_LEN]; + char target[SYSFS_NAME_LEN]; +}; + +The "next" pointer is for linking links together. Link's name is stored +in name and it's target stored in target. + + +5.1.3 Directory Structure +------------------------- + +The directory structure represents a sysfs directory: + +struct sysfs_directory { + struct sysfs_directory *next; + char path[SYSFS_PATH_MAX]; + struct sysfs_directory *subdirs; + struct sysfs_link *links; + struct sysfs_attribute *attributes; +}; + +The directory structure includes a "next" pointer for linking directories +together. It also includes the directory's full path and links to +subdirectories, links, and attributes. + + +5.2 Bus Data Structure +---------------------- + +All buses look similar in sysfs including lists of devices and drivers, +therefore we use the following structure to represent all sysfs buses: + +struct sysfs_bus { + struct sysfs_bus *next; + char name[SYSFS_NAME_LEN]; + struct sysfs_directory *directory; + struct sysfs_driver *drivers; + struct sysfs_device *devices; +}; + +The "next" pointer, as with other structures, is used for linking buses +together. The bus name, like "pci" or "usb", is stored in the name field. +The bus' directory is represented by the sysfs_directory structure and +it contains references to all the subdirectories, links, and attributes +associated with the bus. Finally, the bus contains lists of those +devices on the bus and their drivers. + + +5.3 Class Data Structures +------------------------- + +The library uses two data structures to represent classes in sysfs. Sysfs +classes contains a class directory like "net" or "scsi_host" and then +class devices like "eth0", "lo", or "eth1" for the "net" class. + +struct sysfs_class { + struct sysfs_class *next; + char name[SYSFS_NAME_LEN]; + struct sysfs_directory *directory; + struct sysfs_class_device *devices; +}; + +The sysfs_class represents device classes in sysfs like "net". It contains +a "next" pointer for list management, the class name, and the directory +representation. Finally, it contains a linked list of class devices. + +struct sysfs_class_device { + struct sysfs_class_device *next; + char name[SYSFS_NAME_LEN]; + struct sysfs_directory *directory; + struct sysfs_device *sysdevice; /* NULL if virtual */ + struct sysfs_driver *driver; /* NULL if not implemented */ +}; + +A class device isn't the same as a sysfs_device, it's specific to the +class in which it belongs. The class device structure contains a "next" +pointer for list management, the name of the class device - like "eth0", +its sysfs directory information including links and attributes, and +finally the sysfs_device reference and that device's driver reference. + + +5.4 Device Data Structure +------------------------- + +The sysfs_device structure represents a system device that's exposed +in sysfs under the /sys/devices directory structure. + +struct sysfs_device { + struct sysfs_device *next; + char name[SYSFS_NAME_LEN]; + char bus_id[SYSFS_NAME_LEN]; + struct sysfs_driver *driver; + struct sysfs_directory *directory; + struct sysfs_device *children; +}; + +The sysfs_device structure contains a "next" pointer for linking a list +of devices together, its name as read from the "name" attribute in the +device's directory, its bus id - which is the name of device's directory, +and a reference to its driver. The device structure also contains a +directory structure, which contains a list of the device's attributes, +and a list of its child devices, if it has any. + + +5.5 Driver Data Structure +------------------------- + +The sysfs_driver structure represents a device driver. + +struct sysfs_driver { + struct sysfs_driver *next; + char name[SYSFS_NAME_LEN]; + struct sysfs_directory *directory; +}; + +It contains a "next" pointer, the name of the driver, and its directory +information, which includes the driver's attributes. + + +6. Functions +------------ + +Libsysfs will provide functions to access system devices by bus, by class, +and by device. Functions will act like accessing directories and files, +using "open" and "close". Open returns a structure and close is used +to clean that structure up. + + +6.1 Utility Functions +--------------------- + +The library will provide a few utility functions for working with sysfs. + +------------------------------------------------------------------------------- +Name: sysfs_get_mnt_path + +Description: Function finds the mount path for filesystem type "sysfs". + +Arguments: chat *mnt_path Mount path buffer + size_t len Size of mount path buffer + +Returns: Zero with success. + -1 with error. Errno will be set with error: + - EINVAL for invalid argument, if buffer is NULL. + +Prototype: sysfs_get_mnt_path(char *mnt_path, size_t len); +------------------------------------------------------------------------------- + +------------------------------------------------------------------------------- +Name: sysfs_get_name_from_path + +Description: Function returns the last directory or file name from the + included path. + +Arguments: char *path Path to parse name from + char *name Buffer to put parsed name into + size_t *len Size of name buffer + +Returns: 0 with success. + -1 on Error. Errno will be set with error, returning + - EINVAL for invalid arguments + +Prototype: int sysfs_get_name_from_path(char *path, char *name, + size_t *len) +------------------------------------------------------------------------------- + +------------------------------------------------------------------------------- +Name: sysfs_get_link + +Description: Sysfs realink function, reads the link at supplied path + and returns its target path. + +Arguments: const char *path Link's path + char *target Buffer to place link's target path + size_t len Size of target buffer + +Returns: 0 with success + -1 with error. Errno will be set with error, returning + - EINVAL for invalid arguments + +Prototype: int sysfs_get_link(const char *path, char *target, size_t len) +------------------------------------------------------------------------------- + + +6.2 Filesystem Functions +------------------------ + +Libsysfs provides a set of functions to open, read, and close directories +and attributes/files in sysfs. These functions mirror their filesystem +function counterparts. + +6.2.1 Attribute Functions +------------------------- + +Along with the usual open, read, and close functions, libsysfs provides +a couple other functions for accessing attribute values. Specific +functions to write attributes or attribute values will be added in the +near future. + +------------------------------------------------------------------------------- +Name: sysfs_open_attribute + +Description: Opens up a file in sysfs and creates a sysfs_attribute + structure. File isn't read with this function. + +Arguments: char *path File/Attribute's path + +Returns: struct sysfs_attribute * with success. + NULL with error. Errno will be set with error, returning + - EINVAL for invalid arguments + +Prototype: struct sysfs_attribute *sysfs_open_attribute(char *path) +------------------------------------------------------------------------------- + +------------------------------------------------------------------------------- +Name: sysfs_close_attribute + +Description: Cleans up and closes sysfs_attribute structure. + +Arguments: struct sysfs_attribute *sysattr Attribute to close + +Prototype: void sysfs_close_attribute(struct sysfs_attribute *sysattr) +------------------------------------------------------------------------------- + +------------------------------------------------------------------------------- +Name: sysfs_read_attribute + +Description: Reads the supplied attribute. Since the maximum transfer + from a sysfs attribute is a pagesize, function reads in + up to a page from the file and stores it in the "value" + field in the attribute. + +Arguments: struct sysfs_attribute *sysattr Attribute to read + +Returns: 0 with success. + -1 with error. Errno will be set with error, returning + - EINVAL for invalid arguments + +Prototype: int sysfs_read_attribute(struct sysfs_attribute *sysattr) +------------------------------------------------------------------------------- + +------------------------------------------------------------------------------- +Name: sysfs_read_attribute_value + +Description: Given a path to a specific attribute, function reads and + returns its value to the supplied value buffer. + +Arguments: char *attrpath Attribute path to read + char *value Buffer to place attribute's value + size_t vsize Size of buffer + +Returns: 0 with success. + -1 with error. Errno will be set with error, returning + - EINVAL for invalid arguments + +Prototype: int sysfs_read_attribute_value(char *attrpath, char *value, + size_t vsize) +------------------------------------------------------------------------------- + +------------------------------------------------------------------------------- +Name: sysfs_get_value_from_attributes + +Description: Function takes a single or linked list of sysfs attribute + structures and returns the value of the specified attribute + name. + +Arguments: struct sysfs_attribute *attr + Attribute list to search through + char *name Name of attribute to return value + +Returns: char * attribute value with success. + NULL with error. Errno will be set with error, returning + - EINVAL for invalid arguments + +Prototype: char *sysfs_get_value_from_attributes + (struct sysfs_attribute *attr, char * name) +------------------------------------------------------------------------------- + + +6.2.2 Link Functions +-------------------- + +Sysfs contains many symbolic links, like bus links to bus devices. Libsysfs +treats links differently than directories due to processing differences. A +link in the /sys/bus/"busname"/devices/ directory indicates a device in the +/sys/devices directory. Through links we give the functionality to know +what is and what isn't a link and the ability to query the links target. + +------------------------------------------------------------------------------- +Name: sysfs_open_link + +Description: Opens a directory link. + +Arguments: char *linkpath Path to link + +Returns: struct sysfs_link * with success. + NULL with error. Errno will be set with error, returning + - EINVAL for invalid arguments + +Prototype: struct sysfs_link *sysfs_open_link(char *linkpath) +------------------------------------------------------------------------------- + +------------------------------------------------------------------------------- +Name: sysfs_close_link + +Description: Closes a directory link structure. + +Arguments: struct sysfs_link *ln Link to close + +Prototype: void sysfs_close_link(struct sysfs_link *ln) +------------------------------------------------------------------------------- + + +6.2.3 Directory Functions +------------------------- + +Sysfs directories can represent every directory under sysfs. The structures +keep track of subdirectories, links, and files. Like opendir, readdir, and +closedir, libsysfs provides open, read, and close functions for working with +sysfs directories. Open creates the sysfs_directory structure. Read reads in +its contents - like subdirectories, links, and files. Close cleans it all +up. + +------------------------------------------------------------------------------- +Name: sysfs_open_directory + +Description: Opens a sysfs directory at a specific path + +Arguments: char *path Directory path to open + +Returns: struct sysfs_directory * with success. + NULL with error. Errno will be set with error, returning + - EINVAL for invalid arguments + +Prototype: struct sysfs_directory *sysfs_open_directory(char *path) +------------------------------------------------------------------------------- + +------------------------------------------------------------------------------- +Name: sysfs_close_directory + +Description: Closes specific directory, its subdirectories, links, and + files. + +Arguments: struct sysfs_directory *sysdir Directory to close + +Prototype: void sysfs_close_directory(struct sysfs_directory *sysdir) +------------------------------------------------------------------------------- + +------------------------------------------------------------------------------- +Name: sysfs_read_directory + +Description: Read the supplied directory. Reading fills in the directory's + contents like subdirectories, links, and attributes. + +Arguments: struct sysfs_directory *sysdir Directory to read + +Returns: 0 with success. + -1 with error. Errno will be set with error, returning + - EINVAL for invalid arguments + +Prototype: int sysfs_read_directory(struct sysfs_directory *sysdir) +------------------------------------------------------------------------------- + + +6.3 Bus Functions +----------------- + +The library provides a couple functions for viewing buses represented in +sysfs. The sysfs_open_bus opens a bus in the /sys/bus directory, such as +"pci", "usb", or "scsi". The open command returns a sysfs_bus structure +that contains a list of the bus' devices. The sysfs_close_bus function +is used to clean up the bus structure. + +------------------------------------------------------------------------------- +Name: sysfs_open_bus + +Description: Function opens up one of the buses represented in sysfs in + the /sys/bus directory. It returns a sysfs_bus structure + that includes a list of bus devices and drivers. + +Arguments: char *name Bus name to open, like "pci".... + +Returns: struct sysfs_bus * with success + NULL with error. Errno will be set with error, returning + - EINVAL for invalid arguments + +Prototype: struct sysfs_bus *sysfs_open_bus(char *name) +------------------------------------------------------------------------------- + +------------------------------------------------------------------------------- +Name: sysfs_close_bus + +Description: Function closes up the sysfs_bus structure including its + devices, drivers, and directory. + +Arguments: sysfs_bus *bus Bus structure to close + +Prototype: void sysfs_close_bus(struct sysfs_bus *bus); +------------------------------------------------------------------------------- + + +6.4 Class Functions +------------------- + +Libsysfs provides functions to open sysfs classes and their class devices. +These functions too operate with open and close, close must be called to +clean up the class structures. + +------------------------------------------------------------------------------- +Name: sysfs_open_class + +Description: Function opens up one of the classes represented in sysfs in + the /sys/class directory. It returns a sysfs_class structure + that includes a list of class devices. + +Arguments: char *name Class name to open, like "net".... + +Returns: struct sysfs_class * with success + NULL with error. Errno will be set with error, returning + - EINVAL for invalid arguments + +Prototype: struct sysfs_class *sysfs_open_class(char *name) +------------------------------------------------------------------------------- + +------------------------------------------------------------------------------- +Name: sysfs_close_class + +Description: Function closes up the sysfs_class structure including its + class devices. + +Arguments: sysfs_class *class Class structure to close + +Prototype: void sysfs_close_class(struct sysfs_class *class); +------------------------------------------------------------------------------- + +------------------------------------------------------------------------------- +Name: sysfs_open_class_device + +Description: Function opens up one of the class devices represented in + sysfs in sysfs/class/"class"/ directory. It retunrs a + sysfs_class_device structure. + +Arguments: char *path Path to class device + +Returns: struct sysfs_class_device * with success + NULL with error. Errno will be set with error, returning + - EINVAL for invalid arguments + +Prototype: struct sysfs_class_device *sysfs_open_class_device(char *path) +------------------------------------------------------------------------------- + +------------------------------------------------------------------------------- +Name: sysfs_close_class_device + +Description: Function closes up the sysfs_class_device structure. + +Arguments: sysfs_class_device *dev Class device structure to close + +Prototype: void sysfs_close_class_device(struct sysfs_class_device *dev) +------------------------------------------------------------------------------- + + +6.5 Device Functions +-------------------- + +Devices represent everything in sysfs under /sys/devices, which is a +hierarchical view of system devices. Besides the expected open and +close functions, libsysfs provides open and close tree functions. The +tree functions recursively open or close a device and all of its +children. + +------------------------------------------------------------------------------- +Name: sysfs_open_device + +Description: Opens up a device at a specific path. It opens the device's + directory, reads the directory, and returns a sysfs_device + structure. + +Arguments: char *path Path to device + +Returns: struct sysfs_device * with success + NULL with error. Errno will be set with error, returning + - EINVAL for invalid arguments + +Prototype: struct sysfs_device *sysfs_open_device(char *path) +------------------------------------------------------------------------------- + +------------------------------------------------------------------------------- +Name: sysfs_close_device + +Description: Function closes up the sysfs_device structure. + +Arguments: sysfs_device *dev Device structure to close + +Prototype: void sysfs_close_device(struct sysfs_device *dev) +------------------------------------------------------------------------------- + +------------------------------------------------------------------------------- +Name: sysfs_open_device_tree + +Description: Same as sysfs_open_device except it recursively opens + children devices and adds them to the tree. Returns root + tree. + +Arguments: char *path Path to device + +Returns: struct sysfs_device * with success + NULL with error. Errno will be set with error, returning + - EINVAL for invalid arguments + +Prototype: struct sysfs_device *sysfs_open_device_tree(char *path) +------------------------------------------------------------------------------- + +------------------------------------------------------------------------------- +Name: sysfs_close_device_tree + +Description: Same as sysfs_close_device except it recursively closes + all child devices. + +Arguments: sysfs_device *dev Root device structure to close + +Prototype: void sysfs_close_device_tree(struct sysfs_device *dev) +------------------------------------------------------------------------------- + +------------------------------------------------------------------------------- +Name: sysfs_get_device_attr + +Description: Searches supplied device's attributes by name and returns + the attribute. + +Arguments: struct sysfs_device *dev Device to search + char *name Attribute name to find + +Returns: struct sysfs_attribute * with success + NULL with error. Errno will be set with error, returning + - EINVAL for invalid arguments + +Prototype: struct sysfs_attribute *sysfs_get_device_attr + (struct sysfs_device *dev, char *name) +------------------------------------------------------------------------------- + + +6.6 Driver Functions +-------------------- + +Libsysfs includes two functions - open and close - for drivers. + +------------------------------------------------------------------------------- +Name: sysfs_open_driver + +Description: Opens driver at specific path. + +Arguments: char *path Path to driver + +Returns: struct sysfs_driver * with success + NULL with error. Errno will be set with error, returning + - EINVAL for invalid arguments + +Prototype: struct sysfs_driver *sysfs_open_driver(char *path) +------------------------------------------------------------------------------- + +------------------------------------------------------------------------------- +Name: sysfs_close_driver + +Description: Closes and cleans up sysfs_driver structure. + +Arguments: sysfs_driver *driver Driver structure to close + +Prototype: void sysfs_close_driver(struct sysfs_driver *driver) +------------------------------------------------------------------------------- + + +7. Usage +-------- + +Accessing devices through libsysfs is supposed to mirror accessing devices +in the filesystem it represents. Here's a typical order of operation: + + - get sysfs mount point + - "open" sysfs category, ie. bus, class, or device + - work with category + - "close" sysfs category + + +8. Conclusion +------------- + +Libsysfs is meant to provide a stable application programming interface to +sysfs. Applications can depend upon the library to access system devices +and functions exposed through sysfs. diff --git a/include/libsysfs.h b/include/libsysfs.h new file mode 100644 index 0000000..06c5f3a --- /dev/null +++ b/include/libsysfs.h @@ -0,0 +1,161 @@ +/* + * libsysfs.h + * + * Header Definitions for libsysfs + * + * Copyright (C) 2003 International Business Machines, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#ifndef _LIBSYSFS_H_ +#define _LIBSYSFS_H_ + +#include <sys/types.h> + +/* + * Generic #defines go here.. + */ +#define SYSFS_FSTYPE_NAME "sysfs" +#define SYSFS_PROC_MNTS "/proc/mounts" +#define SYSFS_BUS_DIR "/bus" +#define SYSFS_CLASS_DIR "/class" +#define SYSFS_DEVICES_DIR "/devices" +#define SYSFS_DEVICES_NAME "devices" +#define SYSFS_DRIVERS_DIR "/drivers" +#define SYSFS_DRIVERS_NAME "drivers" +#define SYSFS_NAME_ATTRIBUTE "name" + +#define SYSFS_PATH_MAX 255 +#define SYSFS_NAME_LEN 50 +#define SYSFS_BUS_ID_SIZE 20 + +#define SYSFS_METHOD_SHOW 0x01 /* attr can be read by user */ +#define SYSFS_METHOD_STORE 0x02 /* attr can be changed by user */ + +struct sysfs_attribute { + struct sysfs_attribute *next; + char path[SYSFS_PATH_MAX]; + char *value; + unsigned short len; /* value length */ + unsigned short method; /* show and store */ +}; + +struct sysfs_link { + struct sysfs_link *next; + char name[SYSFS_NAME_LEN]; + char target[SYSFS_PATH_MAX]; +}; + +struct sysfs_directory { + struct sysfs_directory *next; + char path[SYSFS_PATH_MAX]; + struct sysfs_directory *subdirs; + struct sysfs_link *links; + struct sysfs_attribute *attributes; +}; + +struct sysfs_driver { + struct sysfs_driver *next; + char name[SYSFS_NAME_LEN]; + struct sysfs_directory *directory; + struct sysfs_device *device; +}; + +struct sysfs_device { + struct sysfs_device *next; + char name[SYSFS_NAME_LEN]; + char bus_id[SYSFS_NAME_LEN]; + struct sysfs_driver *driver; + struct sysfs_directory *directory; + struct sysfs_device *parent; + struct sysfs_device *children; +}; + +struct sysfs_bus { + struct sysfs_bus *next; + char name[SYSFS_NAME_LEN]; + struct sysfs_directory *directory; + struct sysfs_driver *drivers; + struct sysfs_device *devices; +}; + +struct sysfs_class_device { + struct sysfs_class_device *next; + char name[SYSFS_NAME_LEN]; + struct sysfs_directory *directory; + struct sysfs_device *sysdevice; /* NULL if virtual */ + struct sysfs_driver *driver; /* NULL if not implemented */ +}; + +struct sysfs_class { + struct sysfs_class *next; + char name[SYSFS_NAME_LEN]; + struct sysfs_directory *directory; + struct sysfs_class_device *devices; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Function Prototypes + */ +extern int sysfs_get_mnt_path(char *mnt_path, size_t len); +extern int sysfs_get_name_from_path(const char *path, char *name, size_t len); +extern int sysfs_get_link(const char *path, char *target, size_t len); + +/* 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 char *sysfs_get_value_from_attributes(struct sysfs_attribute *attr, + const char * name); +extern void sysfs_close_directory(struct sysfs_directory *sysdir); +extern struct sysfs_directory *sysfs_open_directory(const char *path); +extern int sysfs_read_directory(struct sysfs_directory *sysdir); +extern void sysfs_close_link(struct sysfs_link *ln); +extern struct sysfs_link *sysfs_open_link(const char *lnpath); + +/* sysfs driver access */ +extern void sysfs_close_driver(struct sysfs_driver *driver); +extern struct sysfs_driver *sysfs_open_driver(const char *path); + +/* generic sysfs device access */ +extern void sysfs_close_device(struct sysfs_device *dev); +extern void sysfs_close_device_tree(struct sysfs_device *dev); +extern struct sysfs_device *sysfs_open_device(const char *path); +extern struct sysfs_device *sysfs_open_device_tree(const char *path); +extern struct sysfs_attribute *sysfs_get_device_attr + (struct sysfs_device *dev, const char *name); + +/* generic sysfs bus access */ +extern void sysfs_close_bus(struct sysfs_bus *bus); +extern struct sysfs_bus *sysfs_open_bus(const char *name); + +/* generic sysfs class access */ +extern void sysfs_close_class_device(struct sysfs_class_device *dev); +extern struct sysfs_class_device *sysfs_open_class_device(const char *path); +extern void sysfs_close_class(struct sysfs_class *cls); +extern struct sysfs_class *sysfs_open_class(const char *name); + +#ifdef __cplusplus +} +#endif + +#endif /* _LIBSYSFS_H_ */ diff --git a/lib/LGPL b/lib/LGPL new file mode 100644 index 0000000..e00a829 --- /dev/null +++ b/lib/LGPL @@ -0,0 +1,441 @@ + + GNU Lesser Public License + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + [This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your freedom to + share and change it. By contrast, the GNU General Public Licenses are + intended to guarantee your freedom to share and change free software--to + make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some specially + designated software packages--typically libraries--of the Free Software + Foundation and other authors who decide to use it. You can use it too, but + we suggest you first think carefully about whether this license or the + ordinary General Public License is the better strategy to use in any + particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, not + price. Our General Public Licenses are designed to make sure that you have + the freedom to distribute copies of free software (and charge for this + service if you wish); that you receive source code or can get it if you + want it; that you can change the software and use pieces of it in new free + programs; and that you are informed that you can do these things. + + To protect your rights, we need to make restrictions that forbid + distributors to deny you these rights or to ask you to surrender these + rights. These restrictions translate to certain responsibilities for you + if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis or + for a fee, you must give the recipients all the rights that we gave you. + You must make sure that they, too, receive or can get the source code. If + you link other code with the library, you must provide complete object + files to the recipients, so that they can relink them with the library + after making changes to the library and recompiling it. And you must show + them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the + library, and (2) we offer you this license, which gives you legal + permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that there is + no warranty for the free library. Also, if the library is modified by + someone else and passed on, the recipients should know that what they have + is not the original version, so that the original author's reputation will + not be affected by problems that might be introduced by others. + + Finally, software patents pose a constant threat to the existence of any + free program. We wish to make sure that a company cannot effectively + restrict the users of a free program by obtaining a restrictive license + from a patent holder. Therefore, we insist that any patent license + obtained for a version of the library must be consistent with the full + freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the ordinary + GNU General Public License. This license, the GNU Lesser General Public + License, applies to certain designated libraries, and is quite different + from the ordinary General Public License. We use this license for certain + libraries in order to permit linking those libraries into non-free + programs. + + When a program is linked with a library, whether statically or using a + shared library, the combination of the two is legally speaking a combined + work, a derivative of the original library. The ordinary General Public + License therefore permits such linking only if the entire combination fits + its criteria of freedom. The Lesser General Public License permits more + lax criteria for linking other code with the library. + + We call this license the "Lesser" General Public License because it does + Less to protect the user's freedom than the ordinary General Public + License. It also provides other free software developers Less of an + advantage over competing non-free programs. These disadvantages are the + reason we use the ordinary General Public License for many libraries. + However, the Lesser license provides advantages in certain special + circumstances. + + For example, on rare occasions, there may be a special need to encourage + the widest possible use of a certain library, so that it becomes a + de-facto standard. To achieve this, non-free programs must be allowed to + use the library. A more frequent case is that a free library does the same + job as widely used non-free libraries. In this case, there is little to + gain by limiting the free library to free software only, so we use the + Lesser General Public License. + + In other cases, permission to use a particular library in non-free + programs enables a greater number of people to use a large body of free + software. For example, permission to use the GNU C Library in non-free + programs enables many more people to use the whole GNU operating system, + as well as its variant, the GNU/Linux operating system. + + Although the Lesser General Public License is Less protective of the + users' freedom, it does ensure that the user of a program that is linked + with the Library has the freedom and the wherewithal to run that program + using a modified version of the Library. + + The precise terms and conditions for copying, distribution and + modification follow. Pay close attention to the difference between a "work + based on the library" and a "work that uses the library". The former + contains code derived from the library, whereas the latter must be + combined with the library in order to run. + + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other program + which contains a notice placed by the copyright holder or other authorized + party saying it may be distributed under the terms of this Lesser General + Public License (also called "this License"). Each licensee is addressed as + "you". + + A "library" means a collection of software functions and/or data prepared + so as to be conveniently linked with application programs (which use some + of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work which + has been distributed under these terms. A "work based on the Library" + means either the Library or any derivative work under copyright law: that + is to say, a work containing the Library or a portion of it, either + verbatim or with modifications and/or translated straightforwardly into + another language. (Hereinafter, translation is included without limitation + in the term "modification".) + + "Source code" for a work means the preferred form of the work for making + modifications to it. For a library, complete source code means all the + source code for all modules it contains, plus any associated interface + definition files, plus the scripts used to control compilation and + installation of the library. + + Activities other than copying, distribution and modification are not + covered by this License; they are outside its scope. The act of running a + program using the Library is not restricted, and output from such a + program is covered only if its contents constitute a work based on the + Library (independent of the use of the Library in a tool for writing it). + Whether that is true depends on what the Library does and what the program + that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's complete + source code as you receive it, in any medium, provided that you + conspicuously and appropriately publish on each copy an appropriate + copyright notice and disclaimer of warranty; keep intact all the notices + that refer to this License and to the absence of any warranty; and + distribute a copy of this License along with the Library. + + You may charge a fee for the physical act of transferring a copy, and you + may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Library or any portion of it, + thus forming a work based on the Library, and copy and distribute such + modifications or work under the terms of Section 1 above, provided that + you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices stating + that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no charge to + all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a table + of data to be supplied by an application program that uses the facility, + other than as an argument passed when the facility is invoked, then you + must make a good faith effort to ensure that, in the event an + application does not supply such function or table, the facility still + operates, and performs whatever part of its purpose remains meaningful. + + (For example, a function in a library to compute square roots has a + purpose that is entirely well-defined independent of the application. + Therefore, Subsection 2d requires that any application-supplied function + or table used by this function must be optional: if the application does + not supply it, the square root function must still compute square + roots.) + + These requirements apply to the modified work as a whole. If + identifiable sections of that work are not derived from the Library, and + can be reasonably considered independent and separate works in + themselves, then this License, and its terms, do not apply to those + sections when you distribute them as separate works. But when you + distribute the same sections as part of a whole which is a work based on + the Library, the distribution of the whole must be on the terms of this + License, whose permissions for other licensees extend to the entire + whole, and thus to each and every part regardless of who wrote it. + + Thus, it is not the intent of this section to claim rights or contest + your rights to work written entirely by you; rather, the intent is to + exercise the right to control the distribution of derivative or + collective works based on the Library. + + In addition, mere aggregation of another work not based on the Library + with the Library (or with a work based on the Library) on a volume of a + storage or distribution medium does not bring the other work under the + scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public + License instead of this License to a given copy of the Library. To do + this, you must alter all the notices that refer to this License, so that + they refer to the ordinary GNU General Public License, version 2, instead + of to this License. (If a newer version than version 2 of the ordinary GNU + General Public License has appeared, then you can specify that version + instead if you wish.) Do not make any other change in these notices. + + Once this change is made in a given copy, it is irreversible for that + copy, so the ordinary GNU General Public License applies to all subsequent + copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of the + Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or derivative of + it, under Section 2) in object code or executable form under the terms of + Sections 1 and 2 above provided that you accompany it with the complete + corresponding machine-readable source code, which must be distributed + under the terms of Sections 1 and 2 above on a medium customarily used for + software interchange. + + If distribution of object code is made by offering access to copy from a + designated place, then offering equivalent access to copy the source code + from the same place satisfies the requirement to distribute the source + code, even though third parties are not compelled to copy the source along + with the object code. + + 5. A program that contains no derivative of any portion of the Library, + but is designed to work with the Library by being compiled or linked with + it, is called a "work that uses the Library". Such a work, in isolation, + is not a derivative work of the Library, and therefore falls outside the + scope of this License. + + However, linking a "work that uses the Library" with the Library creates + an executable that is a derivative of the Library (because it contains + portions of the Library), rather than a "work that uses the library". The + executable is therefore covered by this License. Section 6 states terms + for distribution of such executables. + + When a "work that uses the Library" uses material from a header file that + is part of the Library, the object code for the work may be a derivative + work of the Library even though the source code is not. Whether this is + true is especially significant if the work can be linked without the + Library, or if the work is itself a library. The threshold for this to be + true is not precisely defined by law. + + If such an object file uses only numerical parameters, data structure + layouts and accessors, and small macros and small inline functions (ten + lines or less in length), then the use of the object file is unrestricted, + regardless of whether it is legally a derivative work. (Executables + containing this object code plus portions of the Library will still fall + under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may distribute + the object code for the work under the terms of Section 6. Any executables + containing that work also fall under Section 6, whether or not they are + linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or link a + "work that uses the Library" with the Library to produce a work containing + portions of the Library, and distribute that work under terms of your + choice, provided that the terms permit modification of the work for the + customer's own use and reverse engineering for debugging such + modifications. + + You must give prominent notice with each copy of the work that the Library + is used in it and that the Library and its use are covered by this + License. You must supply a copy of this License. If the work during + execution displays copyright notices, you must include the copyright + notice for the Library among them, as well as a reference directing the + user to the copy of this License. Also, you must do one of these things: + + a) Accompany the work with the complete corresponding machine-readable + source code for the Library including whatever changes were used in the + work (which must be distributed under Sections 1 and 2 above); and, if + the work is an executable linked with the Library, with the complete + machine-readable "work that uses the Library", as object code and/or + source code, so that the user can modify the Library and then relink to + produce a modified executable containing the modified Library. (It is + understood that the user who changes the contents of definitions files + in the Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the Library. + A suitable mechanism is one that (1) uses at run time a copy of the + library already present on the user's computer system, rather than + copying library functions into the executable, and (2) will operate + properly with a modified version of the library, if the user installs + one, as long as the modified version is interface-compatible with the + version that the work was made with. + + c) Accompany the work with a written offer, valid for at least three + years, to give the same user the materials specified in Subsection 6a, + above, for a charge no more than the cost of performing this + distribution. + + d) If distribution of the work is made by offering access to copy from a + designated place, offer equivalent access to copy the above specified + materials from the same place. + + e) Verify that the user has already received a copy of these materials + or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the Library" + must include any data and utility programs needed for reproducing the + executable from it. However, as a special exception, the materials to be + distributed need not include anything that is normally distributed (in + either source or binary form) with the major components (compiler, kernel, + and so on) of the operating system on which the executable runs, unless + that component itself accompanies the executable. + + It may happen that this requirement contradicts the license restrictions + of other proprietary libraries that do not normally accompany the + operating system. Such a contradiction means you cannot use both them and + the Library together in an executable that you distribute. + + 7. You may place library facilities that are a work based on the Library + side-by-side in a single library together with other library facilities + not covered by this License, and distribute such a combined library, + provided that the separate distribution of the work based on the Library + and of the other library facilities is otherwise permitted, and provided + that you do these two things: + + a) Accompany the combined library with a copy of the same work based on + the Library, uncombined with any other library facilities. This must be + distributed under the terms of the Sections above. + + b) Give prominent notice with the combined library of the fact that part + of it is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute the + Library except as expressly provided under this License. Any attempt + otherwise to copy, modify, sublicense, link with, or distribute the + Library is void, and will automatically terminate your rights under this + License. However, parties who have received copies, or rights, from you + under this License will not have their licenses terminated so long as such + parties remain in full compliance. + + 9. You are not required to accept this License, since you have not signed + it. However, nothing else grants you permission to modify or distribute + the Library or its derivative works. These actions are prohibited by law + if you do not accept this License. Therefore, by modifying or distributing + the Library (or any work based on the Library), you indicate your + acceptance of this License to do so, and all its terms and conditions for + copying, distributing or modifying the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the + Library), the recipient automatically receives a license from the original + licensor to copy, distribute, link with or modify the Library subject to + these terms and conditions. You may not impose any further restrictions on + the recipients' exercise of the rights granted herein. You are not + responsible for enforcing compliance by third parties with this License. + + 11. If, as a consequence of a court judgment or allegation of patent + infringement or for any other reason (not limited to patent issues), + conditions are imposed on you (whether by court order, agreement or + otherwise) that contradict the conditions of this License, they do not + excuse you from the conditions of this License. If you cannot distribute + so as to satisfy simultaneously your obligations under this License and + any other pertinent obligations, then as a consequence you may not + distribute the Library at all. For example, if a patent license would not + permit royalty-free redistribution of the Library by all those who receive + copies directly or indirectly through you, then the only way you could + satisfy both it and this License would be to refrain entirely from + distribution of the Library. + + If any portion of this section is held invalid or unenforceable under any + particular circumstance, the balance of the section is intended to apply, + and the section as a whole is intended to apply in other circumstances. + + It is not the purpose of this section to induce you to infringe any + patents or other property right claims or to contest validity of any such + claims; this section has the sole purpose of protecting the integrity of + the free software distribution system which is implemented by public + license practices. Many people have made generous contributions to the + wide range of software distributed through that system in reliance on + consistent application of that system; it is up to the author/donor to + decide if he or she is willing to distribute software through any other + system and a licensee cannot impose that choice. + + This section is intended to make thoroughly clear what is believed to be a + consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in certain + countries either by patents or by copyrighted interfaces, the original + copyright holder who places the Library under this License may add an + explicit geographical distribution limitation excluding those countries, + so that distribution is permitted only in or among countries not thus + excluded. In such case, this License incorporates the limitation as if + written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new versions + of the Lesser General Public License from time to time. Such new versions + will be similar in spirit to the present version, but may differ in detail + to address new problems or concerns. + + Each version is given a distinguishing version number. If the Library + specifies a version number of this License which applies to it and "any + later version", you have the option of following the terms and conditions + either of that version or of any later version published by the Free + Software Foundation. If the Library does not specify a license version + number, you may choose any version ever published by the Free Software + Foundation. + + 14. If you wish to incorporate parts of the Library into other free + programs whose distribution conditions are incompatible with these, write + to the author to ask for permission. For software which is copyrighted by + the Free Software Foundation, write to the Free Software Foundation; we + sometimes make exceptions for this. Our decision will be guided by the two + goals of preserving the free status of all derivatives of our free + software and of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY + FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN + OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES + PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED + OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS + TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE + LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, + REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING + WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR + REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, + INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES + ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT + LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES + SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE + WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + diff --git a/lib/Makefile b/lib/Makefile new file mode 100644 index 0000000..cf07a84 --- /dev/null +++ b/lib/Makefile @@ -0,0 +1,44 @@ +# Makefile for libsysfs.a +# Copyright (c) International Business Machines Corp., 2003 + +CC=gcc + +H_INCLUDE=../include +LIB_INCLUDE=. +OBJS=sysfs_bus.o sysfs_class.o sysfs_device.o sysfs_dir.o sysfs_driver.o \ + sysfs_utils.o + +# Install directory + +# Options +CFLAGS=-O2 -Wall -ansi -g + +# sysfs library +LIBSYSFS=libsysfs.a + +RM=rm -f + +libsysfs.a: $(OBJS) + ar cru $(LIBSYSFS) $(OBJS) + ranlib $(LIBSYSFS) + +sysfs_bus.o: sysfs_bus.c + $(CC) -I$(H_INCLUDE) -I$(LIB_INCLUDE) $(CFLAGS) -c sysfs_bus.c + +sysfs_class.o: sysfs_class.c + $(CC) -I$(H_INCLUDE) -I$(LIB_INCLUDE) $(CFLAGS) -c sysfs_class.c + +sysfs_device.o: sysfs_device.c + $(CC) -I$(H_INCLUDE) -I$(LIB_INCLUDE) $(CFLAGS) -c sysfs_device.c + +sysfs_dir.o: sysfs_dir.c + $(CC) -I$(H_INCLUDE) -I$(LIB_INCLUDE) $(CFLAGS) -c sysfs_dir.c + +sysfs_driver.o: sysfs_driver.c + $(CC) -I$(H_INCLUDE) -I$(LIB_INCLUDE) $(CFLAGS) -c sysfs_driver.c + +sysfs_utils.o: sysfs_utils.c + $(CC) -I$(H_INCLUDE) -I$(LIB_INCLUDE) $(CFLAGS) -c sysfs_utils.c + +clean: + $(RM) *.o *~ core $(LIBSYSFS) diff --git a/lib/sysfs.h b/lib/sysfs.h new file mode 100644 index 0000000..eb2a002 --- /dev/null +++ b/lib/sysfs.h @@ -0,0 +1,49 @@ +/* + * sysfs.h + * + * Internal Header Definitions for libsysfs + * + * Copyright (C) 2003 International Business Machines, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#ifndef _SYSFS_H_ +#define _SYSFS_H_ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <mntent.h> +#include <dirent.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> + +/* external library functions */ +extern int lstat(const char *file_name, struct stat *buf); +extern int readlink(const char *path, char *buf, size_t bufsize); +extern int getpagesize(void); +extern int isascii(int c); + +/* Debugging */ +#ifdef DEBUG +#define dprintf(format, arg...) fprintf(stderr, format, ## arg) +#else +#define dprintf(format, arg...) do { } while (0) +#endif + +#endif /* _SYSFS_H_ */ diff --git a/lib/sysfs_bus.c b/lib/sysfs_bus.c new file mode 100644 index 0000000..c7b6036 --- /dev/null +++ b/lib/sysfs_bus.c @@ -0,0 +1,301 @@ +/* + * sysfs_bus.c + * + * Generic bus utility functions for libsysfs + * + * Copyright (C) 2003 International Business Machines, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#include "libsysfs.h" +#include "sysfs.h" + +/** + * sysfs_close_bus: close single bus + * @bus: bus structure + */ +void sysfs_close_bus(struct sysfs_bus *bus) +{ + struct sysfs_device *curdev = NULL, *nextdev = NULL; + struct sysfs_driver *curdrv = NULL, *nextdrv = NULL; + + if (bus != NULL) { + if (bus->directory != NULL) + sysfs_close_directory(bus->directory); + for (curdev = bus->devices; curdev != NULL; + curdev = nextdev) { + nextdev = curdev->next; + sysfs_close_device(curdev); + } + for (curdrv = bus->drivers; curdrv != NULL; + curdrv = nextdrv) { + nextdrv = curdrv->next; + sysfs_close_driver(curdrv); + } + free(bus); + } +} + +/** + * alloc_bus: mallocs new bus structure + * returns sysfs_bus_bus struct or NULL + */ +static struct sysfs_bus *alloc_bus(void) +{ + return (struct sysfs_bus *)calloc(1, sizeof(struct sysfs_bus)); +} + +/** + * open_bus_dir: opens up sysfs bus directory + * returns sysfs_directory struct with success and NULL with error + */ +static struct sysfs_directory *open_bus_dir(const char *name) +{ + struct sysfs_directory *busdir = NULL, *cur = NULL, *next = NULL; + char buspath[SYSFS_PATH_MAX]; + + if (name == NULL) { + errno = EINVAL; + return NULL; + } + + memset(buspath, 0, SYSFS_PATH_MAX); + if ((sysfs_get_mnt_path(buspath, SYSFS_PATH_MAX)) != 0) { + dprintf(stderr, "Sysfs not supported on this system\n"); + return NULL; + } + + strcat(buspath, SYSFS_BUS_DIR); + strcat(buspath, "/"); + strcat(buspath, name); + busdir = sysfs_open_directory(buspath); + if (busdir == NULL) { + errno = EINVAL; + dprintf(stderr,"Bus %s not supported on this system\n", + name); + return NULL; + } + if ((sysfs_read_directory(busdir)) != 0) { + dprintf(stderr, "Error reading %s bus dir %s\n", name, + buspath); + sysfs_close_directory(busdir); + return NULL; + } + /* read in devices and drivers subdirs */ + for (cur = busdir->subdirs; cur != NULL; cur = next) { + next = cur->next; + if ((sysfs_read_directory(cur)) != 0) + continue; + } + + return busdir; +} + +/** + * add_dev_to_bus: adds a bus device to bus device list + * @bus: bus to add the device + * @dev: device to add + */ +static void add_dev_to_bus(struct sysfs_bus *bus, struct sysfs_device *dev) +{ + if (bus != NULL && dev != NULL) { + dev->next = bus->devices; + bus->devices = dev; + } +} + +/** + * add_driver_to_bus: adds a bus driver to bus driver list + * @bus: bus to add driver to + * @driver: driver to add + */ +static void add_driver_to_bus(struct sysfs_bus *bus, + struct sysfs_driver *driver) +{ + if (bus != NULL && driver != NULL) { + driver->next = bus->drivers; + bus->drivers = driver; + } +} + +/** + * get_all_bus_devices: gets all devices for bus + * @bus: bus to get devices for + * returns 0 with success and -1 with failure + */ +static int get_all_bus_devices(struct sysfs_bus *bus) +{ + struct sysfs_device *bdev = NULL; + struct sysfs_directory *cur = NULL; + struct sysfs_link *curl = NULL, *nextl = NULL; + char dirname[SYSFS_NAME_LEN]; + + if (bus == NULL || bus->directory == NULL) { + errno = EINVAL; + return -1; + } + for (cur = bus->directory->subdirs; cur != NULL; cur = cur->next) { + memset(dirname, 0, SYSFS_NAME_LEN); + if ((sysfs_get_name_from_path(cur->path, dirname, + SYSFS_NAME_LEN)) != 0) + continue; + if (strcmp(dirname, SYSFS_DEVICES_NAME) != 0) + continue; + for (curl = cur->links; curl != NULL; curl = nextl) { + nextl = curl->next; + bdev = sysfs_open_device(curl->target); + if (bdev == NULL) { + dprintf(stderr, "Error opening device at %s\n", + curl->target); + continue; + } + add_dev_to_bus(bus, bdev); + } + } + + return 0; +} + +/** + * get_all_bus_drivers: get all pci drivers + * @bus: pci bus to add drivers to + * returns 0 with success and -1 with error + */ +static int get_all_bus_drivers(struct sysfs_bus *bus) +{ + struct sysfs_driver *driver = NULL; + struct sysfs_directory *cur = NULL, *next = NULL; + struct sysfs_directory *cursub = NULL, *nextsub = NULL; + char dirname[SYSFS_NAME_LEN]; + + if (bus == NULL || bus->directory == NULL) { + errno = EINVAL; + return -1; + } + for (cur = bus->directory->subdirs; cur != NULL; cur = next) { + next = cur->next; + memset(dirname, 0, SYSFS_NAME_LEN); + if ((sysfs_get_name_from_path(cur->path, dirname, + SYSFS_NAME_LEN)) != 0) + continue; + if (strcmp(dirname, SYSFS_DRIVERS_NAME) != 0) + continue; + for (cursub = cur->subdirs; cursub != NULL; cursub = nextsub) { + nextsub = cursub->next; + driver = sysfs_open_driver(cursub->path); + if (driver == NULL) { + dprintf(stderr, "Error opening driver at %s\n", + cursub->path); + continue; + } + add_driver_to_bus(bus, driver); + } + } + + return 0; +} + +/** + * match_bus_device_to_driver: returns 1 if device is bound to driver + * @driver: driver to match + * @busid: busid of device to match + * returns 1 if found and 0 if not found + */ +static int match_bus_device_to_driver(struct sysfs_driver *driver, char *busid) +{ + struct sysfs_link *cur = NULL, *next = NULL; + int found = 0; + + if (driver == NULL || driver->directory == NULL || busid == NULL) { + errno = EINVAL; + return found; + } + for (cur = driver->directory->links; cur != NULL && found == 0; + cur = next) { + next = cur->next; + if ((strcmp(cur->name, busid)) == 0) + found++; + } + return found; +} + +/** + * link_bus_devices_to_drivers: goes through and links devices to drivers + * @bus: bus to link + */ +static void link_bus_devices_to_drivers(struct sysfs_bus *bus) +{ + struct sysfs_device *dev = NULL, *nextdev = NULL; + struct sysfs_driver *drv = NULL, *nextdrv = NULL; + + if (bus != NULL && bus->devices != NULL && bus->drivers != NULL) { + for (dev = bus->devices; dev != NULL; dev = nextdev) { + nextdev = dev->next; + + for (drv = bus->drivers; drv != NULL; drv = nextdrv) { + nextdrv = drv->next; + if ((match_bus_device_to_driver(drv, + dev->bus_id)) != 0) { + dev->driver = drv; + drv->device = dev; + } + } + } + } +} + +/** + * sysfs_open_bus: opens specific bus and all its devices on system + * returns sysfs_bus structure with success or NULL with error. + */ +struct sysfs_bus *sysfs_open_bus(const char *name) +{ + struct sysfs_bus *bus = NULL; + struct sysfs_directory *busdir = NULL; + + if (name == NULL) { + errno = EINVAL; + return NULL; + } + + bus = alloc_bus(); + if (bus == NULL) { + perror("malloc"); + return NULL; + } + strcpy(bus->name, name); + busdir = open_bus_dir(name); + if (busdir == NULL) { + dprintf(stderr,"Invalid bus, %s not supported on this system\n", + name); + sysfs_close_bus(bus); + return NULL; + } + bus->directory = busdir; + if ((get_all_bus_devices(bus)) != 0) { + dprintf(stderr, "Error reading %s bus devices\n", name); + sysfs_close_bus(bus); + return NULL; + } + if ((get_all_bus_drivers(bus)) != 0) { + dprintf(stderr, "Error reading %s bus drivers\n", name); + sysfs_close_bus(bus); + return NULL; + } + link_bus_devices_to_drivers(bus); + + return bus; +} diff --git a/lib/sysfs_class.c b/lib/sysfs_class.c new file mode 100644 index 0000000..dee8514 --- /dev/null +++ b/lib/sysfs_class.c @@ -0,0 +1,270 @@ +/* + * sysfs_class.c + * + * Generic class utility functions for libsysfs + * + * Copyright (C) 2003 International Business Machines, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#include "libsysfs.h" +#include "sysfs.h" + +/** + * 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); + free(dev); + } +} + +/** + * sysfs_close_class: close single class + * @class: class structure + */ +void sysfs_close_class(struct sysfs_class *cls) +{ + struct sysfs_class_device *cur = NULL, *next = NULL; + + if (cls != NULL) { + if (cls->directory != NULL) + sysfs_close_directory(cls->directory); + for (cur = cls->devices; cur != NULL; cur = next) { + next = cur->next; + sysfs_close_class_device(cur); + } + 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)); +} + +/** + * 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)); +} + +/** + * open_class_dir: opens up sysfs class directory + * returns sysfs_directory struct with success and NULL with error + */ +static struct sysfs_directory *open_class_dir(const char *name) +{ + struct sysfs_directory *classdir = NULL; + char classpath[SYSFS_PATH_MAX]; + + if (name == NULL) { + errno = EINVAL; + return NULL; + } + + memset(classpath, 0, SYSFS_PATH_MAX); + if ((sysfs_get_mnt_path(classpath, SYSFS_PATH_MAX)) != 0) { + dprintf(stderr, "Sysfs not supported on this system\n"); + return NULL; + } + + strcat(classpath, SYSFS_CLASS_DIR); + strcat(classpath, "/"); + strcat(classpath, name); + classdir = sysfs_open_directory(classpath); + if (classdir == NULL) { + errno = EINVAL; + dprintf(stderr,"Class %s not supported on this system\n", + name); + return NULL; + } + if ((sysfs_read_directory(classdir)) != 0) { + dprintf(stderr, "Error reading %s class dir %s\n", name, + classpath); + sysfs_close_directory(classdir); + return NULL; + } + + return classdir; +} + +/** + * sysfs_open_class_device: Opens and populates class device + * @path: path to class device. + * returns struct sysfs_class_device with success and NULL with error. + */ +struct sysfs_class_device *sysfs_open_class_device(const char *path) +{ + struct sysfs_class_device *cdev = NULL; + struct sysfs_directory *dir = NULL, *cur = NULL; + struct sysfs_link *curl = NULL; + struct sysfs_device *sdev = NULL; + struct sysfs_driver *drv = NULL; + + if (path == NULL) { + errno = EINVAL; + return NULL; + } + cdev = alloc_class_device(); + if (cdev == NULL) { + perror("malloc"); + return NULL; + } + if ((sysfs_get_name_from_path(path, cdev->name, SYSFS_NAME_LEN)) != 0) { + errno = EINVAL; + dprintf(stderr, "Invalid class device path %s\n", path); + sysfs_close_class_device(cdev); + return NULL; + } + + dir = sysfs_open_directory(path); + if (dir == NULL) { + dprintf(stderr, "Error opening class device at %s\n", path); + sysfs_close_class_device(cdev); + return NULL; + } + if ((sysfs_read_directory(dir)) != 0) { + dprintf(stderr, "Error reading class device at %s\n", path); + sysfs_close_directory(dir); + sysfs_close_class_device(cdev); + return NULL; + } + cdev->directory = dir; + + cur = cdev->directory->subdirs; + while(cur != NULL) { + sysfs_read_directory(cur); + cur = cur->next; + } + /* get driver and device, if implemented */ + curl = cdev->directory->links; + while (curl != NULL) { + if (strncmp(curl->name, SYSFS_DEVICES_NAME, 6) == 0) { + sdev = sysfs_open_device(curl->target); + if (sdev != NULL) { + cdev->sysdevice = sdev; + if (cdev->driver != NULL) + sdev->driver = cdev->driver; + } + } else if (strncmp(curl->name, SYSFS_DRIVERS_NAME, 6) == 0) { + drv = sysfs_open_driver(curl->target); + if (drv != NULL) { + cdev->driver = drv; + if (cdev->sysdevice != NULL) + drv->device = cdev->sysdevice; + } + } + curl = curl->next; + } + return cdev; +} + +/** + * add_dev_to_class: adds a class device to class list + * @class: class to add the device + * @dev: device to add + */ +static void add_dev_to_class(struct sysfs_class *cls, + struct sysfs_class_device *dev) +{ + if (cls != NULL && dev != NULL) { + dev->next = cls->devices; + cls->devices = dev; + } +} + +/** + * get_all_class_devices: gets all devices for class + * @class: class to get devices for + * returns 0 with success and -1 with failure + */ +static int get_all_class_devices(struct sysfs_class *cls) +{ + struct sysfs_class_device *dev = NULL; + struct sysfs_directory *cur = NULL, *next = NULL; + + if (cls == NULL || cls->directory == NULL) { + errno = EINVAL; + return -1; + } + for (cur = cls->directory->subdirs; cur != NULL; cur = next) { + next = cur->next; + dev = sysfs_open_class_device(cur->path); + if (dev == NULL) { + dprintf(stderr, "Error opening device at %s\n", + cur->path); + continue; + } + add_dev_to_class(cls, dev); + } + + return 0; +} + +/** + * 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; + struct sysfs_directory *classdir = NULL; + + if (name == NULL) { + errno = EINVAL; + return NULL; + } + + cls = alloc_class(); + if (cls == NULL) { + perror("malloc"); + return NULL; + } + strcpy(cls->name, name); + classdir = open_class_dir(name); + if (classdir == NULL) { + dprintf(stderr, + "Invalid class, %s not supported on this system\n", + name); + sysfs_close_class(cls); + return NULL; + } + cls->directory = classdir; + if ((get_all_class_devices(cls)) != 0) { + dprintf(stderr, "Error reading %s class devices\n", name); + sysfs_close_class(cls); + return NULL; + } + + return cls; +} diff --git a/lib/sysfs_device.c b/lib/sysfs_device.c new file mode 100644 index 0000000..185b5cf --- /dev/null +++ b/lib/sysfs_device.c @@ -0,0 +1,199 @@ +/* + * sysfs_device.c + * + * Generic device utility functions for libsysfs + * + * Copyright (C) 2003 International Business Machines, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#include "libsysfs.h" +#include "sysfs.h" + +/** + * 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) { + dev->next = NULL; + dev->driver = NULL; + if (dev->directory != NULL) + sysfs_close_directory(dev->directory); + dev->children = NULL; + free(dev); + } +} + +/** + * alloc_device: allocates and initializes device structure + * returns struct sysfs_device + */ +static struct sysfs_device *alloc_device(void) +{ + return (struct sysfs_device *)calloc(1, sizeof(struct sysfs_device)); +} + +/** + * sysfs_get_device_attr: searches dev's attributes by name + * @dev: device to look through + * @name: attribute name to get + * returns sysfs_attribute reference with success or NULL with error. + */ +struct sysfs_attribute *sysfs_get_device_attr(struct sysfs_device *dev, + const char *name) +{ + struct sysfs_attribute *cur = NULL; + char attrname[SYSFS_NAME_LEN]; + + if (dev == NULL || dev->directory == NULL || name == NULL) { + errno = EINVAL; + return NULL; + } + for (cur = dev->directory->attributes; cur != NULL; cur = cur->next) { + if ((sysfs_get_name_from_path(cur->path, attrname, + SYSFS_NAME_LEN)) != 0) + continue; + if (strcmp(name, attrname) != 0) + continue; + + return cur; + } + + return NULL; +} + +/** + * sysfs_open_device: opens and populates device structure + * @path: path to device, this is the /sys/devices/ path + * returns sysfs_device structure with success or NULL with error + */ +struct sysfs_device *sysfs_open_device(const char *path) +{ + struct sysfs_device *dev = NULL; + struct sysfs_directory *sdir = NULL; + char *p = NULL; + + if (path == NULL) { + errno = EINVAL; + return NULL; + } + dev = alloc_device(); + if (dev == NULL) { + dprintf(stderr, "Error allocating device at %s\n", path); + return NULL; + } + sdir = sysfs_open_directory(path); + if (sdir == NULL) { + dprintf(stderr, "Invalid device at %s\n", path); + errno = EINVAL; + sysfs_close_device(dev); + return NULL; + } + if ((sysfs_read_directory(sdir)) != 0) { + dprintf(stderr, "Error reading device directory at %s\n", path); + sysfs_close_directory(sdir); + sysfs_close_device(dev); + return NULL; + } + dev->directory = sdir; + sysfs_get_name_from_path(sdir->path, dev->bus_id, SYSFS_NAME_LEN); + /* get device name */ + p = sysfs_get_value_from_attributes(sdir->attributes, + SYSFS_NAME_ATTRIBUTE); + if (p != NULL) { + strncpy(dev->name, p, SYSFS_NAME_LEN); + p = dev->name + strlen(dev->name) - 1; + if ((strlen(dev->name) > 0) && *p == '\n') + *p = '\0'; + } + + return dev; +} + +/** + * sysfs_close_device_tree: closes every device in the supplied tree, + * closing children only. + * @devroot: device root of tree. + */ +void sysfs_close_device_tree(struct sysfs_device *devroot) +{ + if (devroot != NULL) { + if (devroot->children != NULL) { + struct sysfs_device *child = NULL, *next = NULL; + + for (child = devroot->children; child != NULL; + child = next) { + next = child->next; + sysfs_close_device_tree(child); + } + } + sysfs_close_device(devroot); + } +} + +/** + * add_device_child_to_parent: adds child device to parent + * @parent: parent device. + * @child: child device to add. + */ +static void add_device_child_to_parent(struct sysfs_device *parent, + struct sysfs_device *child) +{ + if (parent != NULL && child != NULL) { + child->next = parent->children; + parent->children = child; + child->parent = parent; + } +} + +/** + * 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); + if (rootdev == NULL) { + dprintf(stderr, "Error opening root device at %s\n", path); + return NULL; + } + cur = rootdev->directory->subdirs; + while (cur != NULL) { + new = sysfs_open_device_tree(cur->path); + if (new == NULL) { + dprintf(stderr, "Error opening device tree at %s\n", + cur->path); + sysfs_close_device_tree(rootdev); + return NULL; + } + add_device_child_to_parent(rootdev, new); + cur = cur->next; + } + + return rootdev; +} diff --git a/lib/sysfs_dir.c b/lib/sysfs_dir.c new file mode 100644 index 0000000..e6ad906 --- /dev/null +++ b/lib/sysfs_dir.c @@ -0,0 +1,453 @@ +/* + * syfs_dir.c + * + * Directory utility functions for libsysfs + * + * Copyright (C) 2003 International Business Machines, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#include "libsysfs.h" +#include "sysfs.h" + +/** + * 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) + free(sysattr->value); + free(sysattr); + } +} + +/** + * alloc_attribute: allocates and initializes attribute structure + * returns struct sysfs_attribute with success and NULL with error. + */ +static struct sysfs_attribute *alloc_attribute(void) +{ + return (struct sysfs_attribute *) + calloc(1, sizeof(struct sysfs_attribute)); +} + +/** + * sysfs_open_attribute: creates sysfs_attribute structure + * @path: path to attribute. + * returns sysfs_attribute struct with success and NULL with error. + */ +struct sysfs_attribute *sysfs_open_attribute(const char *path) +{ + struct sysfs_attribute *sysattr = NULL; + struct stat fileinfo; + + if (path == NULL) { + errno = EINVAL; + return NULL; + } + sysattr = alloc_attribute(); + if (sysattr == NULL) { + dprintf(stderr, "Error allocating attribute at %s\n", path); + return NULL; + } + strncpy(sysattr->path, path, sizeof(sysattr->path)); + if ((stat(sysattr->path, &fileinfo)) != 0) { + perror("stat"); + sysattr->method = 0; + } else { + if (fileinfo.st_mode & S_IRUSR) + sysattr->method |= SYSFS_METHOD_SHOW; + if (fileinfo.st_mode & S_IWUSR) + sysattr->method |= SYSFS_METHOD_STORE; + } + + return sysattr; +} + +/** + * sysfs_read_attribute: reads value from attribute + * @sysattr: attribute to read + * returns 0 with success and -1 with error. + */ +int sysfs_read_attribute(struct sysfs_attribute *sysattr) +{ + char *fbuf = NULL; + char *vbuf = NULL; + size_t length = 0; + int pgsize = 0; + int fd; + + if (sysattr == NULL) { + errno = EINVAL; + return -1; + } + if (!(sysattr->method & SYSFS_METHOD_SHOW)) { + dprintf (stderr, "Show method not supported for attribute %s\n", + sysattr->path); + return -1; + } + pgsize = getpagesize(); + fbuf = (char *)calloc(1, pgsize+1); + if (fbuf == NULL) { + perror("calloc"); + return -1; + } + if ((fd = open(sysattr->path, O_RDONLY)) < 0) { + dprintf (stderr, "Error reading attribute %s\n", sysattr->path); + free(fbuf); + return -1; + } + length = read(fd, fbuf, pgsize); + if (length < 0) { + dprintf (stderr, "Error reading from attribute %s\n", + sysattr->path); + close(fd); + free(fbuf); + return -1; + } + sysattr->len = length; + close(fd); + vbuf = (char *)realloc(fbuf, length+1); + if (vbuf == NULL) { + perror("realloc"); + free(fbuf); + return -1; + } + sysattr->value = vbuf; + + return 0; +} + +/** + * 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 + * returns 0 with success and -1 with error. + */ +int sysfs_read_attribute_value(const char *attrpath, char *value, size_t vsize) +{ + struct sysfs_attribute *attr = NULL; + size_t length = 0; + + if (attrpath == NULL || value == NULL) { + errno = EINVAL; + return -1; + } + + attr = sysfs_open_attribute(attrpath); + if (attr == NULL) { + dprintf(stderr, "Invalid attribute path %s\n", attrpath); + errno = EINVAL; + return -1; + } + if((sysfs_read_attribute(attr)) != 0 || attr->value == NULL) { + dprintf(stderr, "Error reading from attribute %s\n", attrpath); + sysfs_close_attribute(attr); + return -1; + } + length = strlen(attr->value); + if (length > vsize) + dprintf(stderr, + "Value length %d is larger than supplied buffer %d\n", + length, vsize); + strncpy(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 sysfs_attribute *attr, + const char *name) +{ + struct sysfs_attribute *cur = NULL; + char tmpname[SYSFS_NAME_LEN]; + + if (attr == NULL || name == NULL) { + errno = EINVAL; + return NULL; + } + cur = attr; + while (cur != NULL) { + memset(tmpname, 0, SYSFS_NAME_LEN); + if ((sysfs_get_name_from_path(cur->path, tmpname, + SYSFS_NAME_LEN)) != 0) { + cur = cur->next; + continue; + } + if (strcmp(tmpname, name) == 0) + return cur->value; + cur = cur->next; + } + return NULL; +} + +/** + * add_subdir_to_dir: adds subdirectory to directory's subdirs + * @sysdir: directory to add subdir to + * @subdir: subdirectory to add. + */ +static void add_subdir_to_dir(struct sysfs_directory *sysdir, + struct sysfs_directory *subdir) +{ + if (sysdir != NULL && subdir != NULL) { + subdir->next = sysdir->subdirs; + sysdir->subdirs = subdir; + } +} + +/** + * add_attr_to_dir: adds attribute to directory's attributes + * @sysdir: directory to add attribute to + * @sysattr: attribute to add. + */ +static void add_attr_to_dir(struct sysfs_directory *sysdir, + struct sysfs_attribute *sysattr) +{ + if (sysdir != NULL && sysattr != NULL) { + sysattr->next = sysdir->attributes; + sysdir->attributes = sysattr; + } +} + +/** + * sysfs_close_link: closes and cleans up link. + * @ln: link to close. + */ +void sysfs_close_link(struct sysfs_link *ln) +{ + if (ln != NULL) { + ln->next = NULL; + free(ln); + } +} + +/** + * add_link_to_dir: adds link to directory's links list. + * @sysdir: directory to add it to. + * @ln: link to add. + */ +static void add_link_to_dir(struct sysfs_directory *sysdir, + struct sysfs_link *ln) +{ + if (sysdir != NULL && ln != NULL) { + ln->next = sysdir->links; + sysdir->links = ln; + } +} + +/** + * sysfs_close_directory: closes directory, cleans up attributes and links + * @sysdir: sysfs_directory to close + */ +void sysfs_close_directory(struct sysfs_directory *sysdir) +{ + struct sysfs_directory *sdir = NULL, *dnext = NULL; + struct sysfs_link *dlink = NULL, *nextl = NULL; + struct sysfs_attribute *attr = NULL, *anext = NULL; + + if (sysdir != NULL) { + if (sysdir->subdirs != NULL) { + for (sdir = sysdir->subdirs; sdir != NULL; + sdir = dnext) { + dnext = sdir->next; + sysfs_close_directory(sdir); + } + } + if (sysdir->links != NULL) { + for (dlink = sysdir->links; dlink != NULL; + dlink = nextl) { + nextl = dlink->next; + sysfs_close_link(dlink); + } + } + if (sysdir->attributes != NULL) { + for (attr = sysdir->attributes; attr != NULL; + attr = anext) { + anext = attr->next; + /* sysfs_close_attribute(attr); */ + if (attr->value != NULL) + free(attr->value); + free(attr); + } + } + free(sysdir); + } +} + +/** + * 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_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; + } + sdir = alloc_directory(); + if (sdir == NULL) { + dprintf(stderr, "Error allocating directory %s\n", path); + return NULL; + } + strncpy(sdir->path, path, sizeof(sdir->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) { + errno = EINVAL; + return NULL; + } + + ln = alloc_link(); + if (ln == NULL) { + dprintf(stderr, + "Error allocating link %s\n", linkpath); + return NULL; + } + if ((sysfs_get_name_from_path(linkpath, ln->name, SYSFS_NAME_LEN)) != 0 + || (sysfs_get_link(linkpath, ln->target, SYSFS_PATH_MAX)) != 0) { + errno = EINVAL; + dprintf(stderr, "Invalid link path %s\n", linkpath); + return NULL; + } + + return ln; +} + +/** + * sysfs_read_directory: grabs attributes, links, and subdirectories + * @sysdir: sysfs directory to open + * returns 0 with success and -1 with error. + */ +int sysfs_read_directory(struct sysfs_directory *sysdir) +{ + DIR *dir = NULL; + struct dirent *dirent = NULL; + struct stat astats; + struct sysfs_attribute *attr = NULL; + struct sysfs_directory *subdir = NULL; + struct sysfs_link *ln = NULL; + char file_path[SYSFS_PATH_MAX]; + int retval = 0; + + if (sysdir == NULL) { + errno = EINVAL; + return -1; + } + dir = opendir(sysdir->path); + if (dir == NULL) { + perror("opendir"); + return -1; + } + while(((dirent = readdir(dir)) != NULL) && retval == 0) { + if (0 == strcmp(dirent->d_name, ".")) + continue; + if (0 == strcmp(dirent->d_name, "..")) + continue; + memset(file_path, 0, SYSFS_PATH_MAX); + strncpy(file_path, sysdir->path, sizeof(file_path)); + strncat(file_path, "/", sizeof(file_path)); + strncat(file_path, dirent->d_name, sizeof(file_path)); + if ((lstat(file_path, &astats)) != 0) { + perror("stat"); + continue; + } + if (S_ISREG(astats.st_mode)) { + attr = sysfs_open_attribute(file_path); + if (attr == NULL) { + dprintf (stderr, "Error opening attribute %s\n", + file_path); + retval = -1; + break; + } + if (attr->method & SYSFS_METHOD_SHOW) { + if ((sysfs_read_attribute(attr)) != 0) { + dprintf (stderr, + "Error reading attribute %s\n", + file_path); + sysfs_close_attribute(attr); + continue; + } + } + add_attr_to_dir(sysdir, attr); + } else if (S_ISDIR(astats.st_mode)) { + subdir = sysfs_open_directory(file_path); + if (subdir == NULL) { + dprintf (stderr, "Error opening directory %s\n", + file_path); + retval = -1; + break; + } + add_subdir_to_dir(sysdir, subdir); + } else if (S_ISLNK(astats.st_mode)) { + ln = sysfs_open_link(file_path); + if (ln == NULL) { + dprintf(stderr, "Error opening link %s\n", + file_path); + retval = -1; + break; + } + add_link_to_dir(sysdir, ln); + } + } + closedir(dir); + return(retval); +} diff --git a/lib/sysfs_driver.c b/lib/sysfs_driver.c new file mode 100644 index 0000000..6813c85 --- /dev/null +++ b/lib/sysfs_driver.c @@ -0,0 +1,89 @@ +/* + * sysfs_driver.c + * + * Driver utility functions for libsysfs + * + * Copyright (C) 2003 International Business Machines, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#include "libsysfs.h" +#include "sysfs.h" + +/** + * sysfs_close_driver: closes and cleans up driver structure + * @driver: driver to close + */ +void sysfs_close_driver(struct sysfs_driver *driver) +{ + if (driver != NULL) { + if (driver->directory != NULL) + sysfs_close_directory(driver->directory); + free(driver); + } +} + +/** + * alloc_driver: allocates and initializes driver + * returns struct sysfs_driver with success and NULL with error. + */ +static struct sysfs_driver *alloc_driver(void) +{ + return (struct sysfs_driver *)calloc(1, sizeof(struct sysfs_driver)); +} + +/** + * sysfs_open_driver: opens and initializes driver structure + * @path: path to driver directory + * returns struct sysfs_driver with success and NULL with error + */ +struct sysfs_driver *sysfs_open_driver(const char *path) +{ + struct sysfs_driver *driver = NULL; + struct sysfs_directory *sdir = NULL; + char devname[SYSFS_NAME_LEN]; + + if (path == NULL) { + errno = EINVAL; + return NULL; + } + sdir = sysfs_open_directory(path); + if (sdir == NULL) { + dprintf (stderr, "Error opening directory %s\n", path); + return NULL; + } + if ((sysfs_read_directory(sdir)) != 0) { + dprintf (stderr, "Error reading directory %s\n", path); + sysfs_close_directory(sdir); + return NULL; + } + driver = alloc_driver(); + if (driver == NULL) { + dprintf(stderr, "Error allocating driver at %s\n", path); + sysfs_close_directory(sdir); + return NULL; + } + if ((sysfs_get_name_from_path(path, devname, SYSFS_NAME_LEN)) != 0) { + dprintf (stderr, "Error reading directory %s\n", path); + sysfs_close_directory(sdir); + free(driver); + return NULL; + } + strncpy(driver->name, devname, sizeof(driver->name)); + driver->directory = sdir; + + return driver; +} diff --git a/lib/sysfs_utils.c b/lib/sysfs_utils.c new file mode 100644 index 0000000..a2410ab --- /dev/null +++ b/lib/sysfs_utils.c @@ -0,0 +1,156 @@ +/* + * syfs_utils.c + * + * System utility functions for libsysfs + * + * Copyright (C) 2003 International Business Machines, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#include "libsysfs.h" +#include "sysfs.h" + +/** + * sysfs_get_mnt_path: Gets the mount point for specified filesystem. + * @fs_type: filesystem type to retrieve mount point + * @mnt_path: place to put the retrieved mount path + * @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) { + errno = EINVAL; + return -1; + } + + if ((mnt = setmntent(SYSFS_PROC_MNTS, "r")) == NULL) { + dprintf(stderr, "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)) { + strcpy(mnt_path, mntent->mnt_dir); + } else { + dprintf(stderr, + "Error - mount path too long\n"); + ret = -1; + } + } + } + endmntent(mnt); + if (dirlen == 0 && ret == 0) { + dprintf(stderr, "Filesystem %s not found!\n", fs_type); + errno = EINVAL; + ret = -1; + } + return ret; +} + +/* + * sysfs_get_mnt_path: Gets the sysfs mount point. + * @mnt_path: place to put "sysfs" mount point + * @len: size of mnt_path + * returns 0 with success and -1 with error. + */ +int sysfs_get_mnt_path(char *mnt_path, size_t len) +{ + int ret = -1; + + if (mnt_path != NULL) + ret = sysfs_get_fs_mnt_path(SYSFS_FSTYPE_NAME, mnt_path, len); + else + errno = EINVAL; + + return ret; +} + +/** + * sysfs_get_name_from_path: returns last name from a "/" delimited path + * @path: path to get name from + * @name: where to put name + * @len: size of name + */ +int sysfs_get_name_from_path(const char *path, char *name, size_t len) +{ + char *n = NULL; + + if (path == NULL || name == NULL) { + errno = EINVAL; + return -1; + } + n = strrchr(path, '/'); + if (n == NULL) { + errno = EINVAL; + return -1; + } + n++; + strncpy(name, n, len); + + return 0; +} + +/** + * sysfs_get_link: returns link source + * @path: symbolic link's path + * @target: where to put name + * @len: size of name + */ +int sysfs_get_link(const char *path, char *target, size_t len) +{ + char devdir[SYSFS_PATH_MAX]; + char linkpath[SYSFS_PATH_MAX]; + char *d = NULL; + + if (path == NULL || target == NULL) { + errno = EINVAL; + return -1; + } + + memset(devdir, 0, SYSFS_PATH_MAX); + memset(linkpath, 0, SYSFS_PATH_MAX); + + if ((sysfs_get_mnt_path(devdir, SYSFS_PATH_MAX)) != 0) { + dprintf(stderr, "Sysfs not supported on this system\n"); + return -1; + } + + if ((readlink(path, linkpath, SYSFS_PATH_MAX)) < 0) { + return -1; + } + + d = linkpath; + + /* getting rid of leading "../.." */ + while (*d == '/' || *d == '.') + d++; + + d--; + + strcat(devdir, d); + strncpy(target, devdir, len); + + return 0; +} |