diff options
Diffstat (limited to 'libsysfs')
-rw-r--r-- | libsysfs/LGPL | 441 | ||||
-rw-r--r-- | libsysfs/Makefile.am | 7 | ||||
-rw-r--r-- | libsysfs/Makefile.in | 587 | ||||
-rw-r--r-- | libsysfs/dlist.c | 657 | ||||
-rw-r--r-- | libsysfs/sysfs.h | 64 | ||||
-rw-r--r-- | libsysfs/sysfs_attr.c | 632 | ||||
-rw-r--r-- | libsysfs/sysfs_bus.c | 317 | ||||
-rw-r--r-- | libsysfs/sysfs_class.c | 551 | ||||
-rw-r--r-- | libsysfs/sysfs_device.c | 424 | ||||
-rw-r--r-- | libsysfs/sysfs_dir.c | 1071 | ||||
-rw-r--r-- | libsysfs/sysfs_driver.c | 289 | ||||
-rw-r--r-- | libsysfs/sysfs_module.c | 279 | ||||
-rw-r--r-- | libsysfs/sysfs_utils.c | 307 |
13 files changed, 5626 insertions, 0 deletions
diff --git a/libsysfs/LGPL b/libsysfs/LGPL new file mode 100644 index 0000000..e00a829 --- /dev/null +++ b/libsysfs/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/libsysfs/Makefile.am b/libsysfs/Makefile.am new file mode 100644 index 0000000..8d37bcc --- /dev/null +++ b/libsysfs/Makefile.am @@ -0,0 +1,7 @@ +lib_LTLIBRARIES = libsysfs.la +libsysfs_la_SOURCES = sysfs_utils.c sysfs_attr.c sysfs_class.c dlist.c \ + sysfs_device.c sysfs_driver.c sysfs_bus.c sysfs_module.c sysfs.h +INCLUDES = -I../include +libsysfs_la_LDFLAGS = -version-info 2:1:0 +EXTRA_CFLAGS = @EXTRA_CLFAGS@ +libsysfs_la_CFLAGS = -Wall -W -Wstrict-prototypes $(EXTRA_CLFAGS) diff --git a/libsysfs/Makefile.in b/libsysfs/Makefile.in new file mode 100644 index 0000000..840aeea --- /dev/null +++ b/libsysfs/Makefile.in @@ -0,0 +1,587 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = libsysfs +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(libdir)" +LTLIBRARIES = $(lib_LTLIBRARIES) +libsysfs_la_LIBADD = +am_libsysfs_la_OBJECTS = libsysfs_la-sysfs_utils.lo \ + libsysfs_la-sysfs_attr.lo libsysfs_la-sysfs_class.lo \ + libsysfs_la-dlist.lo libsysfs_la-sysfs_device.lo \ + libsysfs_la-sysfs_driver.lo libsysfs_la-sysfs_bus.lo \ + libsysfs_la-sysfs_module.lo +libsysfs_la_OBJECTS = $(am_libsysfs_la_OBJECTS) +libsysfs_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(libsysfs_la_CFLAGS) \ + $(CFLAGS) $(libsysfs_la_LDFLAGS) $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libsysfs_la_SOURCES) +DIST_SOURCES = $(libsysfs_la_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBTOOL_DEPS = @LIBTOOL_DEPS@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +lib_LTLIBRARIES = libsysfs.la +libsysfs_la_SOURCES = sysfs_utils.c sysfs_attr.c sysfs_class.c dlist.c \ + sysfs_device.c sysfs_driver.c sysfs_bus.c sysfs_module.c sysfs.h + +INCLUDES = -I../include +libsysfs_la_LDFLAGS = -version-info 2:1:0 +EXTRA_CFLAGS = @EXTRA_CLFAGS@ +libsysfs_la_CFLAGS = -Wall -W -Wstrict-prototypes $(EXTRA_CLFAGS) +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu libsysfs/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu libsysfs/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libsysfs.la: $(libsysfs_la_OBJECTS) $(libsysfs_la_DEPENDENCIES) + $(libsysfs_la_LINK) -rpath $(libdir) $(libsysfs_la_OBJECTS) $(libsysfs_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsysfs_la-dlist.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsysfs_la-sysfs_attr.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsysfs_la-sysfs_bus.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsysfs_la-sysfs_class.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsysfs_la-sysfs_device.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsysfs_la-sysfs_driver.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsysfs_la-sysfs_module.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsysfs_la-sysfs_utils.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +libsysfs_la-sysfs_utils.lo: sysfs_utils.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsysfs_la_CFLAGS) $(CFLAGS) -MT libsysfs_la-sysfs_utils.lo -MD -MP -MF $(DEPDIR)/libsysfs_la-sysfs_utils.Tpo -c -o libsysfs_la-sysfs_utils.lo `test -f 'sysfs_utils.c' || echo '$(srcdir)/'`sysfs_utils.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libsysfs_la-sysfs_utils.Tpo $(DEPDIR)/libsysfs_la-sysfs_utils.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sysfs_utils.c' object='libsysfs_la-sysfs_utils.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsysfs_la_CFLAGS) $(CFLAGS) -c -o libsysfs_la-sysfs_utils.lo `test -f 'sysfs_utils.c' || echo '$(srcdir)/'`sysfs_utils.c + +libsysfs_la-sysfs_attr.lo: sysfs_attr.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsysfs_la_CFLAGS) $(CFLAGS) -MT libsysfs_la-sysfs_attr.lo -MD -MP -MF $(DEPDIR)/libsysfs_la-sysfs_attr.Tpo -c -o libsysfs_la-sysfs_attr.lo `test -f 'sysfs_attr.c' || echo '$(srcdir)/'`sysfs_attr.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libsysfs_la-sysfs_attr.Tpo $(DEPDIR)/libsysfs_la-sysfs_attr.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sysfs_attr.c' object='libsysfs_la-sysfs_attr.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsysfs_la_CFLAGS) $(CFLAGS) -c -o libsysfs_la-sysfs_attr.lo `test -f 'sysfs_attr.c' || echo '$(srcdir)/'`sysfs_attr.c + +libsysfs_la-sysfs_class.lo: sysfs_class.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsysfs_la_CFLAGS) $(CFLAGS) -MT libsysfs_la-sysfs_class.lo -MD -MP -MF $(DEPDIR)/libsysfs_la-sysfs_class.Tpo -c -o libsysfs_la-sysfs_class.lo `test -f 'sysfs_class.c' || echo '$(srcdir)/'`sysfs_class.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libsysfs_la-sysfs_class.Tpo $(DEPDIR)/libsysfs_la-sysfs_class.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sysfs_class.c' object='libsysfs_la-sysfs_class.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsysfs_la_CFLAGS) $(CFLAGS) -c -o libsysfs_la-sysfs_class.lo `test -f 'sysfs_class.c' || echo '$(srcdir)/'`sysfs_class.c + +libsysfs_la-dlist.lo: dlist.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsysfs_la_CFLAGS) $(CFLAGS) -MT libsysfs_la-dlist.lo -MD -MP -MF $(DEPDIR)/libsysfs_la-dlist.Tpo -c -o libsysfs_la-dlist.lo `test -f 'dlist.c' || echo '$(srcdir)/'`dlist.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libsysfs_la-dlist.Tpo $(DEPDIR)/libsysfs_la-dlist.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='dlist.c' object='libsysfs_la-dlist.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsysfs_la_CFLAGS) $(CFLAGS) -c -o libsysfs_la-dlist.lo `test -f 'dlist.c' || echo '$(srcdir)/'`dlist.c + +libsysfs_la-sysfs_device.lo: sysfs_device.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsysfs_la_CFLAGS) $(CFLAGS) -MT libsysfs_la-sysfs_device.lo -MD -MP -MF $(DEPDIR)/libsysfs_la-sysfs_device.Tpo -c -o libsysfs_la-sysfs_device.lo `test -f 'sysfs_device.c' || echo '$(srcdir)/'`sysfs_device.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libsysfs_la-sysfs_device.Tpo $(DEPDIR)/libsysfs_la-sysfs_device.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sysfs_device.c' object='libsysfs_la-sysfs_device.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsysfs_la_CFLAGS) $(CFLAGS) -c -o libsysfs_la-sysfs_device.lo `test -f 'sysfs_device.c' || echo '$(srcdir)/'`sysfs_device.c + +libsysfs_la-sysfs_driver.lo: sysfs_driver.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsysfs_la_CFLAGS) $(CFLAGS) -MT libsysfs_la-sysfs_driver.lo -MD -MP -MF $(DEPDIR)/libsysfs_la-sysfs_driver.Tpo -c -o libsysfs_la-sysfs_driver.lo `test -f 'sysfs_driver.c' || echo '$(srcdir)/'`sysfs_driver.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libsysfs_la-sysfs_driver.Tpo $(DEPDIR)/libsysfs_la-sysfs_driver.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sysfs_driver.c' object='libsysfs_la-sysfs_driver.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsysfs_la_CFLAGS) $(CFLAGS) -c -o libsysfs_la-sysfs_driver.lo `test -f 'sysfs_driver.c' || echo '$(srcdir)/'`sysfs_driver.c + +libsysfs_la-sysfs_bus.lo: sysfs_bus.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsysfs_la_CFLAGS) $(CFLAGS) -MT libsysfs_la-sysfs_bus.lo -MD -MP -MF $(DEPDIR)/libsysfs_la-sysfs_bus.Tpo -c -o libsysfs_la-sysfs_bus.lo `test -f 'sysfs_bus.c' || echo '$(srcdir)/'`sysfs_bus.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libsysfs_la-sysfs_bus.Tpo $(DEPDIR)/libsysfs_la-sysfs_bus.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sysfs_bus.c' object='libsysfs_la-sysfs_bus.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsysfs_la_CFLAGS) $(CFLAGS) -c -o libsysfs_la-sysfs_bus.lo `test -f 'sysfs_bus.c' || echo '$(srcdir)/'`sysfs_bus.c + +libsysfs_la-sysfs_module.lo: sysfs_module.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsysfs_la_CFLAGS) $(CFLAGS) -MT libsysfs_la-sysfs_module.lo -MD -MP -MF $(DEPDIR)/libsysfs_la-sysfs_module.Tpo -c -o libsysfs_la-sysfs_module.lo `test -f 'sysfs_module.c' || echo '$(srcdir)/'`sysfs_module.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libsysfs_la-sysfs_module.Tpo $(DEPDIR)/libsysfs_la-sysfs_module.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sysfs_module.c' object='libsysfs_la-sysfs_module.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libsysfs_la_CFLAGS) $(CFLAGS) -c -o libsysfs_la-sysfs_module.lo `test -f 'sysfs_module.c' || echo '$(srcdir)/'`sysfs_module.c + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(libdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-libLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-libLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libLTLIBRARIES clean-libtool ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am \ + install-libLTLIBRARIES install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-libLTLIBRARIES + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/libsysfs/dlist.c b/libsysfs/dlist.c new file mode 100644 index 0000000..a0c771a --- /dev/null +++ b/libsysfs/dlist.c @@ -0,0 +1,657 @@ +/* + * dlist.c + * + * Copyright (C) 2003 Eric J Bohm + * + * 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 021110307 USA + * + */ + + +/* Double linked list implementation. + + * You allocate the data and give dlist the pointer. + * If your data is complex set the dlist->del_func to a an appropriate + * delete function. Otherwise dlist will just use free. + +*/ +#include <stdlib.h> +#include "dlist.h" + +/* + * Return pointer to node at marker. + * else null if no nodes. + */ + +inline void *dlist_mark(Dlist *list) +{ + if(list->marker!=NULL) + return(list->marker->data); + else + return(NULL); +} + +/* + * Set marker to start. + */ + +inline void dlist_start(Dlist *list) +{ + list->marker=list->head; +} + +/* + * Set marker to end. + */ + +inline void dlist_end(Dlist *list) +{ + list->marker=list->head; +} + +/* internal use function + * quickie inline to consolidate the marker movement logic + * in one place + * + * when direction true it moves marker after + * when direction false it moves marker before. + * return pointer to data at new marker + * if nowhere to move the marker in desired direction return null + */ +inline void *_dlist_mark_move(Dlist *list,int direction) +{ + if(direction) + { + if( list->marker && list->marker->next!=NULL) + list->marker=list->marker->next; + else + return(NULL); + } + else + { + if( list->marker && list->marker->prev!=NULL) + list->marker=list->marker->prev; + else + return(NULL); + } + if(list->marker!=list->head) + return(list->marker->data); + else + return(NULL); +} + +/* + * Create new linked list to store nodes of datasize. + * return null if list cannot be created. + */ +Dlist *dlist_new(size_t datasize) +{ + Dlist *list=NULL; + if((list=malloc(sizeof(Dlist)))) + { + list->marker=NULL; + list->count=0L; + list->data_size=datasize; + list->del_func=free; + list->head=&(list->headnode); + list->head->prev=NULL; + list->head->next=NULL; + list->head->data=NULL; + } + return(list); +} + +/* + * Create new linked list to store nodes of datasize set list + * data node delete function to the passed in del_func + * return null if list cannot be created. + */ +Dlist *dlist_new_with_delete(size_t datasize,void (*del_func)(void*)) +{ + Dlist *list=NULL; + list=dlist_new(datasize); + if(list!=NULL) + list->del_func=del_func; + return(list); +} + + +/* + * remove marker node from list + * call data_delete function on data if registered. + * otherwise call free. + * when direction true it moves marker after + * when direction false it moves marker before. + * free marker node + * return nothing. + */ +void dlist_delete(Dlist *list,int direction) +{ + if((list->marker != list->head)&&(list->marker!=NULL)) + { + DL_node *corpse; + corpse=list->marker; + _dlist_mark_move(list,direction); + if(list->head->next==corpse) + list->head->next=corpse->next; + if(list->head->prev==corpse) + list->head->prev=corpse->prev; + if(corpse->prev!=NULL) //should be impossible + corpse->prev->next=corpse->next; + if(corpse->next!=NULL) //should be impossible + corpse->next->prev=corpse->prev; + list->del_func(corpse->data); + list->count--; + free(corpse); + } +} + +/* + * Insert node containing data at marker. + * If direction true it inserts after. + * If direction false it inserts before. + * move marker to inserted node + * return pointer to inserted node + */ +void *dlist_insert(Dlist *list,void *data,int direction) +{ + DL_node *new_node=NULL; + if(list==NULL || data==NULL) + return(NULL); + if(list->marker==NULL) //in case the marker ends up unset + list->marker=list->head; + if((new_node=malloc(sizeof(DL_node)))) + { + new_node->data=data; + new_node->prev=NULL; + new_node->next=NULL; + list->count++; + if(list->head->next==NULL) //no l + { + list->head->next=list->head->prev=new_node; + new_node->prev=list->head; + new_node->next=list->head; + } + else if(direction) + { + new_node->next=list->marker->next; + new_node->prev=list->marker; + list->marker->next->prev=new_node; + list->marker->next=new_node; + } + else + { + new_node->prev=list->marker->prev; + new_node->next=list->marker; + list->marker->prev->next=new_node; + list->marker->prev=new_node; + } + list->marker=new_node; + } + else + { + return(NULL); + } + return(list->marker->data); +} + +/* internal use only + * Insert dl_node at marker. + * If direction true it inserts after. + * If direction false it inserts before. + * move marker to inserted node + * return pointer to inserted node + */ +void *_dlist_insert_dlnode(struct dlist *list,struct dl_node *new_node,int direction) +{ + if(list==NULL || new_node==NULL) + return(NULL); + if(list->marker==NULL) //in case the marker ends up unset + list->marker=list->head; + list->count++; + if(list->head->next==NULL) + { + list->head->next=list->head->prev=new_node; + new_node->prev=list->head; + new_node->next=list->head; + } + else if(direction) + { + new_node->next=list->marker->next; + new_node->prev=list->marker; + list->marker->next->prev=new_node; + list->marker->next=new_node; + } + else + { + new_node->prev=list->marker->prev; + new_node->next=list->marker; + list->marker->prev->next=new_node; + list->marker->prev=new_node; + } + list->marker=new_node; + return(list->marker); +} + + + +/* + * Remove DL_node from list without deallocating data. + * if marker == killme . + * when direction true it moves marker after + * when direction false it moves marker before. + * to previous if there is no next. + */ +void *_dlist_remove(Dlist *list,DL_node *killme,int direction) +{ + if(killme!=NULL) + { + void *killer_data=killme->data; + // take care of head and marker pointers. + if(list->marker==killme) + _dlist_mark_move(list,direction); + if(killme ==list->head->next) + list->head->next=killme->next; + if(killme==list->head->prev) + list->head->prev=killme->prev; + // remove from list + if(killme->prev !=NULL) + killme->prev->next=killme->next; + if(killme->next !=NULL) + killme->next->prev=killme->prev; + list->count--; + free(killme); + return(killer_data); + } + else + return (NULL); +} + +/* + * move dl_node from source to dest + * if marker == target . + * when direction true it moves marker after + * when direction false it moves marker before. + * to previous if there is no next. + */ +void dlist_move(struct dlist *source, struct dlist *dest, struct dl_node *target,int direction) +{ + + if(target!=NULL) + { + if(target==source->head) + { + //not even going to try + } + else + { + // take care of head and marker pointers. + if(source->marker==target) + _dlist_mark_move(source,direction); + if(target ==source->head->next) + source->head->next=target->next; + if(target==source->head->prev) + source->head->prev=target->prev; + // remove from list + if(source->count==1) + { + target->prev=NULL; + target->next=NULL; + source->head->next=NULL; + source->head->prev=NULL; + } + else + { + if(target->prev !=NULL) + target->prev->next=target->next; + if(target->next !=NULL) + target->next->prev=target->prev; + target->prev=NULL; + target->next=NULL; + } + source->count--; + _dlist_insert_dlnode(dest,target,direction); + } + } +} + + +/* + * Insert node containing data after end. + */ +void dlist_push(Dlist *list,void *data) +{ + list->marker=list->head->prev; + dlist_insert(list,data,1); +} + +/* + * Insert node containing data at start. + */ + +void dlist_unshift(Dlist *list,void *data) + +{ + list->marker=list->head->next; + dlist_insert(list,data,0); +} + +void dlist_unshift_sorted(Dlist *list, void *data, + int (*sorter)(void *new_elem, void *old_elem)) +{ + if (list->count == 0) + dlist_unshift(list, data); + else { + list->marker=list->head->next; + dlist_insert_sorted(list, data, sorter); + } +} + +/* + * Remove end node from list. + * Return pointer to data in removed node. + * Null if no nodes. + */ + +void *dlist_pop(Dlist *list) +{ + return(_dlist_remove(list,list->head->prev,0)); +} + +/* + * Remove start node from list. + * Return pointer to data in removed node. + * Null if no nodes. + */ + +void *dlist_shift(Dlist *list) +{ + return(_dlist_remove(list,list->head->next,1)); +} + + +/* + * destroy the list freeing all memory + */ + + +void dlist_destroy(Dlist *list) +{ + if(list !=NULL) + { + dlist_start(list); + dlist_next(list); + while (dlist_mark(list)) { + dlist_delete(list,1); + } + free(list); + } +} + +/** + * Return void pointer to list_data element matching comp function criteria + * else null + * Does not move the marker. + */ + +void *dlist_find_custom(struct dlist *list, void *target, int (*comp)(void *, void *)) +{ + /* test the comp function on each node */ + struct dl_node *nodepointer; + dlist_for_each_nomark(list,nodepointer) + if(comp(target,nodepointer->data)) + return(nodepointer->data); + return(NULL); +} + +/** + * Apply the node_operation function to each data node in the list + */ +void dlist_transform(struct dlist *list, void (*node_operation)(void *)) +{ + struct dl_node *nodepointer; + dlist_for_each_nomark(list,nodepointer) + node_operation(nodepointer->data); +} + +/** + * insert new into list in sorted order + * sorter function in form int sorter(new,ith) + * must return 1 for when new should go before ith + * else 0 + * return pointer to inserted node + * NOTE: assumes list is already sorted + */ +void *dlist_insert_sorted(struct dlist *list, void *new, int (*sorter)(void *, void *)) +{ + for(dlist_start(list),dlist_next(list); \ + list->marker!=list->head && !sorter(new,list->marker->data);dlist_next(list)); + return(dlist_insert_before(list,new)); +} + +/* + * NOTE: internal use only + */ +int _dlist_merge(struct dlist *listsource, struct dlist *listdest, unsigned int passcount, int (*compare)(void *, void *)) +{ + + struct dl_node *l1head; + struct dl_node *l2head; + struct dl_node *target; + unsigned int l1count=0; + unsigned int l2count=0; + unsigned int mergecount=0; + while(listsource->count>0) + { + l1head=listsource->head->next; + l2head=l1head; + while((l1count<passcount)&&(l2head!=listsource->head)) + { + l2head=l2head->next; + l1count++; + } + // so now we have two lists to merge + + if(l2head==listsource->head) + {// l2count + l2count=0; + } + else + { + l2count=passcount; + } + while(l1count>0 || l2count>0) + { + mergecount++; + if((l2count>0)&&(l1count>0)) + { + // we have things to merge + int result=compare(l1head->data,l2head->data); + if(result>0) + { + // move from l2 + target=l2head; + l2head=l2head->next; + dlist_move(listsource,listdest,target,1); + l2count--; + if(l2head==listsource->head) + l2count=0; + } + else + { + // move from l1 + target=l1head; + l1head=l1head->next; + dlist_move(listsource,listdest,target,1); + l1count--; + } + } + else if(l1count>0) + { + // only have l1 to work with + while(l1count>0) + { + target=l1head; + l1head=l1head->next; + dlist_move(listsource,listdest,target,1); + l1count--; + } + } + else if(l2count>0) + { + // only have l2 to work with + while(l2count>0) + { + if(l2head==listsource->head) + { + l2count=0; + } + else + { + target=l2head; + l2head=l2head->next; + dlist_move(listsource,listdest,target,1); + l2count--; + } + } + } + else + { //nothing left and this should be unreachable + } + } + } + return(mergecount); +} + +/** + * mergesort the list based on compare + * compare function in form int sorter(void * a,void * b) + * must return >0 for a after b + * must return <0 for a before b + * else 0 + + * NOTE: mergesort changes the mark pointer + */ +void dlist_sort_custom(struct dlist *list, int (*compare)(void *, void *)) +{ + + struct dlist *listsource, *listdest, *swap; + struct dlist *templist; + unsigned int passcount = 1; + unsigned int mergecount = 1; + + if(list->count<2) + return; + + dlist_start(list); + templist = dlist_new(list->data_size); + + templist->del_func = list->del_func; + + // do nothing if there isn't anything to sort + listsource = list; + listdest = templist; + while(mergecount>0) + { + mergecount=_dlist_merge(listsource, listdest, passcount, compare); + if(mergecount>1) + { + passcount=passcount*2; + //start new pass + swap=listsource; + listsource=listdest; + listdest=swap; + } + } + // now put the input list pointers right + // list pointers = newlist pointers + // including the forward and next nodes prev and back pointers + if(list->count==0) + {//copy + list->marker = listdest->marker; + list->count = listdest->count; + list->data_size = listdest->data_size; + list->del_func = listdest->del_func; + list->head->prev = listdest->head->prev; + list->head->next = listdest->head->next; + list->head->data = listdest->head->data; + list->head->next->prev=list->head; + list->head->prev->next=list->head; + templist->head->next=NULL; + templist->head->prev=NULL; + templist->count=0; + } + else + {// no need to copy + + } + + dlist_destroy(templist); +} + +/* + * The dlist_filter_sort() function scans the list, calling + * filter() on each list entry. Entries for which filter() + * returns zero are discarded from the list. Then the list is + * sorted using mergesort() with the comparison function compare() + * and returned. If filter is NULL, all entries are selected. +*/ +void dlist_filter_sort(struct dlist *list, int (*filter) (void *), + int (*compare) (void *, void *)) +{ + struct dl_node *nodepointer,*temp; + void *data; + + if(!list->count) + return; + + /* if there is no filter function, directly sort all the entries */ + if (!filter) + goto sort; + + /* filter the unwanted entries in the list */ + nodepointer = list->head->next; + while(nodepointer!=list->head) { + if (!filter(nodepointer->data)) { + temp = nodepointer->next; + data = _dlist_remove(list, nodepointer, 0); + if(data) + list->del_func(data); + nodepointer = temp; + } + else + nodepointer=nodepointer->next; + } + +sort: + /* sort out the entries */ + dlist_sort_custom(list, compare); +} + + +/* internal use function + swaps elements a and b + No sense in juggling node pointers when we can just swap the data pointers +*/ + +void _dlist_swap(struct dlist *list, struct dl_node *a, struct dl_node *b) +{ + + void *swap=a->data; + a->data=b->data; + b->data=swap; + +} + diff --git a/libsysfs/sysfs.h b/libsysfs/sysfs.h new file mode 100644 index 0000000..76754a4 --- /dev/null +++ b/libsysfs/sysfs.h @@ -0,0 +1,64 @@ +/* + * sysfs.h + * + * Internal Header Definitions for libsysfs + * + * Copyright (C) IBM Corp. 2003-2005 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * 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 <ctype.h> +#include <dirent.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> + +#define safestrcpy(to, from) strncpy(to, from, sizeof(to)-1) +#define safestrcat(to, from) strncat(to, from, sizeof(to) - strlen(to)-1) + +#define safestrcpymax(to, from, max) \ +do { \ + to[max-1] = '\0'; \ + strncpy(to, from, max-1); \ +} while (0) + +#define safestrcatmax(to, from, max) \ +do { \ + to[max-1] = '\0'; \ + strncat(to, from, max - strlen(to)-1); \ +} while (0) + +extern struct sysfs_attribute *get_attribute(void *dev, const char *name); +extern struct dlist *read_dir_subdirs(const char *path); +extern struct dlist *read_dir_links(const char *path); +extern struct dlist *get_dev_attributes_list(void *dev); +extern struct dlist *get_attributes_list(struct dlist *alist, const char *path); + +/* 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/libsysfs/sysfs_attr.c b/libsysfs/sysfs_attr.c new file mode 100644 index 0000000..8819926 --- /dev/null +++ b/libsysfs/sysfs_attr.c @@ -0,0 +1,632 @@ +/* + * sysfs_dir.c + * + * Directory utility functions for libsysfs + * + * Copyright (C) IBM Corp. 2003-2005 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * 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" + +static int sort_char(void *new, void *old) +{ + return ((strncmp((char *)new, (char *)old, + strlen((char *)new))) < 0 ? 1 : 0); +} + +/** + * sysfs_del_name: free function for sysfs_open_subsystem_list + * @name: memory area to be freed + */ +static void sysfs_del_name(void *name) +{ + free(name); +} + +/** + * sysfs_del_attribute: routine for dlist integration + */ +static void sysfs_del_attribute(void *attr) +{ + sysfs_close_attribute((struct sysfs_attribute *)attr); +} + +/** + * attr_name_equal: compares attributes by name + * @a: attribute name for comparison + * @b: sysfs_attribute to be compared. + * returns 1 if a==b->name or 0 if not equal + */ +static int attr_name_equal(void *a, void *b) +{ + if (!a || !b) + return 0; + + if (strcmp(((char *)a), ((struct sysfs_attribute *)b)->name) == 0) + return 1; + + return 0; +} + +/** + * sysfs_close_attribute: closes and cleans up attribute + * @sysattr: attribute to close. + */ +void sysfs_close_attribute(struct sysfs_attribute *sysattr) +{ + if (sysattr) { + if (sysattr->value) + 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) { + errno = EINVAL; + return NULL; + } + sysattr = alloc_attribute(); + if (!sysattr) { + dprintf("Error allocating attribute at %s\n", path); + return NULL; + } + if (sysfs_get_name_from_path(path, sysattr->name, + SYSFS_NAME_LEN) != 0) { + dprintf("Error retrieving attrib name from path: %s\n", path); + sysfs_close_attribute(sysattr); + return NULL; + } + safestrcpy(sysattr->path, path); + if ((stat(sysattr->path, &fileinfo)) != 0) { + dprintf("Stat failed: No such attribute?\n"); + sysattr->method = 0; + free(sysattr); + sysattr = NULL; + } else { + if (fileinfo.st_mode & S_IRUSR) + sysattr->method |= SYSFS_METHOD_SHOW; + 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; + ssize_t length = 0; + long pgsize = 0; + int fd; + + if (!sysattr) { + errno = EINVAL; + return -1; + } + if (!(sysattr->method & SYSFS_METHOD_SHOW)) { + dprintf("Show method not supported for attribute %s\n", + sysattr->path); + errno = EACCES; + return -1; + } + pgsize = getpagesize(); + fbuf = (char *)calloc(1, pgsize+1); + if (!fbuf) { + dprintf("calloc failed\n"); + return -1; + } + if ((fd = open(sysattr->path, O_RDONLY)) < 0) { + dprintf("Error reading attribute %s\n", sysattr->path); + free(fbuf); + return -1; + } + length = read(fd, fbuf, pgsize); + if (length < 0) { + dprintf("Error reading from attribute %s\n", sysattr->path); + close(fd); + free(fbuf); + return -1; + } + if (sysattr->len > 0) { + if ((sysattr->len == length) && + (!(strncmp(sysattr->value, fbuf, length)))) { + close(fd); + free(fbuf); + return 0; + } + free(sysattr->value); + } + sysattr->len = length; + close(fd); + vbuf = (char *)realloc(fbuf, length+1); + if (!vbuf) { + dprintf("realloc failed\n"); + free(fbuf); + return -1; + } + sysattr->value = vbuf; + + return 0; +} + +/** + * sysfs_write_attribute: write value to the attribute + * @sysattr: attribute to write + * @new_value: value to write + * @len: length of "new_value" + * returns 0 with success and -1 with error. + */ +int sysfs_write_attribute(struct sysfs_attribute *sysattr, + const char *new_value, size_t len) +{ + int fd; + int length; + + if (!sysattr || !new_value || len == 0) { + errno = EINVAL; + return -1; + } + + if (!(sysattr->method & SYSFS_METHOD_STORE)) { + dprintf ("Store method not supported for attribute %s\n", + sysattr->path); + errno = EACCES; + return -1; + } + if (sysattr->method & SYSFS_METHOD_SHOW) { + /* + * read attribute again to see if we can get an updated value + */ + if ((sysfs_read_attribute(sysattr))) { + dprintf("Error reading attribute\n"); + return -1; + } + if ((strncmp(sysattr->value, new_value, sysattr->len)) == 0 && + (len == sysattr->len)) { + dprintf("Attr %s already has the requested value %s\n", + sysattr->name, new_value); + return 0; + } + } + /* + * open O_WRONLY since some attributes have no "read" but only + * "write" permission + */ + if ((fd = open(sysattr->path, O_WRONLY)) < 0) { + dprintf("Error reading attribute %s\n", sysattr->path); + return -1; + } + + length = write(fd, new_value, len); + if (length < 0) { + dprintf("Error writing to the attribute %s - invalid value?\n", + sysattr->name); + close(fd); + return -1; + } else if ((unsigned int)length != len) { + dprintf("Could not write %zd bytes to attribute %s\n", + len, sysattr->name); + /* + * since we could not write user supplied number of bytes, + * restore the old value if one available + */ + if (sysattr->method & SYSFS_METHOD_SHOW) { + length = write(fd, sysattr->value, sysattr->len); + close(fd); + return -1; + } + } + + /* + * Validate length that has been copied. Alloc appropriate area + * in sysfs_attribute. Verify first if the attribute supports reading + * (show method). If it does not, do not bother + */ + if (sysattr->method & SYSFS_METHOD_SHOW) { + if (length != sysattr->len) { + sysattr->value = (char *)realloc + (sysattr->value, length); + sysattr->len = length; + safestrcpymax(sysattr->value, new_value, length); + } else { + /*"length" of the new value is same as old one */ + safestrcpymax(sysattr->value, new_value, length); + } + } + + close(fd); + return 0; +} + +/** + * add_attribute_to_list: open and add attribute at path to given dlist + * @list: dlist attribute is to be added + * @path: path to attribute + * returns pointer to attr added with success and NULL with error. + */ +static struct sysfs_attribute *add_attribute_to_list(struct dlist *alist, + const char *path) +{ + struct sysfs_attribute *attr; + + attr = sysfs_open_attribute(path); + if (!attr) { + dprintf("Error opening attribute %s\n", path); + return NULL; + } + if (attr->method & SYSFS_METHOD_SHOW) { + if (sysfs_read_attribute(attr)) { + dprintf("Error reading attribute %s\n", path); + sysfs_close_attribute(attr); + return NULL; + } + } + + if (!alist) { + alist = dlist_new_with_delete + (sizeof(struct sysfs_attribute), sysfs_del_attribute); + } + dlist_unshift_sorted(alist, attr, sort_list); + return attr; +} + +/** + * add_attribute: open and add attribute at path to given directory + * @dev: device whose attribute is to be added + * @path: path to attribute + * returns pointer to attr added with success and NULL with error. + */ +static struct sysfs_attribute *add_attribute(void *dev, const char *path) +{ + struct sysfs_attribute *attr; + + attr = sysfs_open_attribute(path); + if (!attr) { + dprintf("Error opening attribute %s\n", path); + return NULL; + } + if (attr->method & SYSFS_METHOD_SHOW) { + if (sysfs_read_attribute(attr)) { + dprintf("Error reading attribute %s\n", path); + sysfs_close_attribute(attr); + return NULL; + } + } + + if (!((struct sysfs_device *)dev)->attrlist) { + ((struct sysfs_device *)dev)->attrlist = dlist_new_with_delete + (sizeof(struct sysfs_attribute), sysfs_del_attribute); + } + dlist_unshift_sorted(((struct sysfs_device *)dev)->attrlist, + attr, sort_list); + + return attr; +} + +/* + * get_attribute - given a sysfs_* struct and a name, return the + * sysfs_attribute corresponding to "name" + * returns sysfs_attribute on success and NULL on error + */ +struct sysfs_attribute *get_attribute(void *dev, const char *name) +{ + struct sysfs_attribute *cur = NULL; + char path[SYSFS_PATH_MAX]; + + if (!dev || !name) { + errno = EINVAL; + return NULL; + } + + if (((struct sysfs_device *)dev)->attrlist) { + /* check if attr is already in the list */ + cur = (struct sysfs_attribute *)dlist_find_custom + ((((struct sysfs_device *)dev)->attrlist), + (void *)name, attr_name_equal); + if (cur) + return cur; + } + safestrcpymax(path, ((struct sysfs_device *)dev)->path, + SYSFS_PATH_MAX); + safestrcatmax(path, "/", SYSFS_PATH_MAX); + safestrcatmax(path, name, SYSFS_PATH_MAX); + if (!sysfs_path_is_file(path)) + cur = add_attribute((void *)dev, path); + return cur; +} + +/** + * read_dir_links: grabs links in a specific directory + * @sysdir: sysfs directory to read + * returns list of link names with success and NULL with error. + */ +struct dlist *read_dir_links(const char *path) +{ + DIR *dir = NULL; + struct dirent *dirent = NULL; + char file_path[SYSFS_PATH_MAX], *linkname; + struct dlist *linklist = NULL; + + if (!path) { + errno = EINVAL; + return NULL; + } + dir = opendir(path); + if (!dir) { + dprintf("Error opening directory %s\n", path); + return NULL; + } + while ((dirent = readdir(dir)) != NULL) { + if (0 == strcmp(dirent->d_name, ".")) + continue; + if (0 == strcmp(dirent->d_name, "..")) + continue; + memset(file_path, 0, SYSFS_PATH_MAX); + safestrcpy(file_path, path); + safestrcat(file_path, "/"); + safestrcat(file_path, dirent->d_name); + if (!sysfs_path_is_link(file_path)) { + if (!linklist) { + linklist = dlist_new_with_delete + (SYSFS_NAME_LEN, sysfs_del_name); + if (!linklist) { + dprintf("Error creating list\n"); + return NULL; + } + } + linkname = (char *)calloc(1, SYSFS_NAME_LEN); + safestrcpymax(linkname, dirent->d_name, SYSFS_NAME_LEN); + dlist_unshift_sorted(linklist, linkname, sort_char); + } + } + closedir(dir); + return linklist; +} + +void sysfs_close_dev_tree(void *dev); + +int add_subdirectory(struct sysfs_device *dev, char *path) +{ + struct sysfs_device *newdev; + + if (!path) + return -1; + + newdev = sysfs_open_device_path(path); + if (newdev == NULL) + return -1; + + if (dev->children == NULL) + dev->children = dlist_new_with_delete( + sizeof(struct sysfs_device), sysfs_close_dev_tree); + + dlist_unshift_sorted(dev->children, newdev, sort_list); + return 0; +} + +/** + * read_dir_subdirs: grabs subdirs in a specific directory + * @sysdir: sysfs directory to read + * returns list of directory names with success and NULL with error. + */ +struct sysfs_device *sysfs_read_dir_subdirs(const char *path) +{ + DIR *dir = NULL; + struct dirent *dirent = NULL; + char file_path[SYSFS_PATH_MAX]; + struct sysfs_device *dev = NULL; + + if (!path) { + errno = EINVAL; + return NULL; + } + + dev = sysfs_open_device_path(path); + + dir = opendir(path); + if (!dir) { + dprintf("Error opening directory %s\n", path); + return NULL; + } + while ((dirent = readdir(dir)) != NULL) { + if (0 == strcmp(dirent->d_name, ".")) + continue; + if (0 == strcmp(dirent->d_name, "..")) + continue; + memset(file_path, 0, SYSFS_PATH_MAX); + safestrcpy(file_path, path); + safestrcat(file_path, "/"); + safestrcat(file_path, dirent->d_name); + if (!sysfs_path_is_dir(file_path)) + add_subdirectory(dev, file_path); + } + closedir(dir); + return dev; +} + +/** + * read_dir_subdirs: grabs subdirs in a specific directory + * @sysdir: sysfs directory to read + * returns list of directory names with success and NULL with error. + */ +struct dlist *read_dir_subdirs(const char *path) +{ + DIR *dir = NULL; + struct dirent *dirent = NULL; + char file_path[SYSFS_PATH_MAX], *dir_name; + struct dlist *dirlist = NULL; + + if (!path) { + errno = EINVAL; + return NULL; + } + dir = opendir(path); + if (!dir) { + dprintf("Error opening directory %s\n", path); + return NULL; + } + while ((dirent = readdir(dir)) != NULL) { + if (0 == strcmp(dirent->d_name, ".")) + continue; + if (0 == strcmp(dirent->d_name, "..")) + continue; + memset(file_path, 0, SYSFS_PATH_MAX); + safestrcpy(file_path, path); + safestrcat(file_path, "/"); + safestrcat(file_path, dirent->d_name); + if (!sysfs_path_is_dir(file_path)) { + if (!dirlist) { + dirlist = dlist_new_with_delete + (SYSFS_NAME_LEN, sysfs_del_name); + if (!dirlist) { + dprintf("Error creating list\n"); + return NULL; + } + } + dir_name = (char *)calloc(1, SYSFS_NAME_LEN); + safestrcpymax(dir_name, dirent->d_name, SYSFS_NAME_LEN); + dlist_unshift_sorted(dirlist, dir_name, sort_char); + } + } + closedir(dir); + return dirlist; +} + +/** + * get_attributes_list: build a list of attributes for the given path + * @path: grab attributes at the given path + * returns dlist of attributes on success and NULL on failure + */ +struct dlist *get_attributes_list(struct dlist *alist, const char *path) +{ + DIR *dir = NULL; + struct dirent *dirent = NULL; + char file_path[SYSFS_PATH_MAX]; + + if (!path) { + errno = EINVAL; + return NULL; + } + + dir = opendir(path); + if (!dir) { + dprintf("Error opening directory %s\n", path); + return NULL; + } + while ((dirent = readdir(dir)) != NULL) { + if (0 == strcmp(dirent->d_name, ".")) + continue; + if (0 == strcmp(dirent->d_name, "..")) + continue; + memset(file_path, 0, SYSFS_PATH_MAX); + safestrcpy(file_path, path); + safestrcat(file_path, "/"); + safestrcat(file_path, dirent->d_name); + if (!sysfs_path_is_file(file_path)) { + if (!alist) { + alist = dlist_new_with_delete + (sizeof(struct sysfs_attribute), + sysfs_del_attribute); + if (!alist) { + dprintf("Error creating list\n"); + return NULL; + } + } + add_attribute_to_list(alist, file_path); + } + } + closedir(dir); + return alist; +} + +/** + * get_dev_attributes_list: build a list of attributes for the given device + * @dev: devices whose attributes list is required + * returns dlist of attributes on success and NULL on failure + */ +struct dlist *get_dev_attributes_list(void *dev) +{ + DIR *dir = NULL; + struct dirent *dirent = NULL; + struct sysfs_attribute *attr = NULL; + char file_path[SYSFS_PATH_MAX], path[SYSFS_PATH_MAX]; + + if (!dev) { + errno = EINVAL; + return NULL; + } + memset(path, 0, SYSFS_PATH_MAX); + safestrcpy(path, ((struct sysfs_device *)dev)->path); + dir = opendir(path); + if (!dir) { + dprintf("Error opening directory %s\n", path); + return NULL; + } + while ((dirent = readdir(dir)) != NULL) { + if (0 == strcmp(dirent->d_name, ".")) + continue; + if (0 == strcmp(dirent->d_name, "..")) + continue; + memset(file_path, 0, SYSFS_PATH_MAX); + safestrcpy(file_path, path); + safestrcat(file_path, "/"); + safestrcat(file_path, dirent->d_name); + if (!sysfs_path_is_file(file_path)) { + if (((struct sysfs_device *)dev)->attrlist) { + /* check if attr is already in the list */ + attr = (struct sysfs_attribute *) + dlist_find_custom + ((((struct sysfs_device *)dev)->attrlist), + (void *)dirent->d_name, attr_name_equal); + if (attr) + continue; + else + add_attribute(dev, file_path); + } else + attr = add_attribute(dev, file_path); + } + } + closedir(dir); + return ((struct sysfs_device *)dev)->attrlist; +} diff --git a/libsysfs/sysfs_bus.c b/libsysfs/sysfs_bus.c new file mode 100644 index 0000000..8d236a7 --- /dev/null +++ b/libsysfs/sysfs_bus.c @@ -0,0 +1,317 @@ +/* + * sysfs_bus.c + * + * Generic bus utility functions for libsysfs + * + * Copyright (C) IBM Corp. 2003-2005 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * 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" + +static void sysfs_close_dev(void *dev) +{ + sysfs_close_device((struct sysfs_device *)dev); +} + +static void sysfs_close_drv(void *drv) +{ + sysfs_close_driver((struct sysfs_driver *)drv); +} + +/* + * compares names. + * @a: name looked for + * @b: sysfs_device comparing being compared + * returns 1 if a==b->name or 0 not equal + */ +static int name_equal(void *a, void *b) +{ + if (!a || !b) + return 0; + + if (strcmp(((char *)a), ((struct sysfs_device *)b)->name) == 0) + return 1; + + return 0; +} + +/** + * sysfs_close_bus: close single bus + * @bus: bus structure + */ +void sysfs_close_bus(struct sysfs_bus *bus) +{ + if (bus) { + if (bus->attrlist) + dlist_destroy(bus->attrlist); + if (bus->devices) + dlist_destroy(bus->devices); + if (bus->drivers) + dlist_destroy(bus->drivers); + 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)); +} + +/** + * sysfs_get_bus_devices: gets all devices for bus + * @bus: bus to get devices for + * returns dlist of devices with success and NULL with failure + */ +struct dlist *sysfs_get_bus_devices(struct sysfs_bus *bus) +{ + struct sysfs_device *dev; + struct dlist *linklist; + char path[SYSFS_PATH_MAX], devpath[SYSFS_PATH_MAX]; + char target[SYSFS_PATH_MAX]; + char *curlink; + + if (!bus) { + errno = EINVAL; + return NULL; + } + memset(path, 0, SYSFS_PATH_MAX); + safestrcpy(path, bus->path); + safestrcat(path, "/"); + safestrcat(path, SYSFS_DEVICES_NAME); + + linklist = read_dir_links(path); + if (linklist) { + dlist_for_each_data(linklist, curlink, char) { + if (bus->devices) { + dev = (struct sysfs_device *) + dlist_find_custom(bus->devices, + (void *)curlink, name_equal); + if (dev) + continue; + } + safestrcpy(devpath, path); + safestrcat(devpath, "/"); + safestrcat(devpath, curlink); + if (sysfs_get_link(devpath, target, SYSFS_PATH_MAX)) { + dprintf("Error getting link - %s\n", devpath); + continue; + } + dev = sysfs_open_device_path(target); + if (!dev) { + dprintf("Error opening device at %s\n", + target); + continue; + } + if (!bus->devices) + bus->devices = dlist_new_with_delete + (sizeof(struct sysfs_device), + sysfs_close_dev); + dlist_unshift_sorted(bus->devices, dev, sort_list); + } + sysfs_close_list(linklist); + } + return (bus->devices); +} + +/** + * sysfs_get_bus_drivers: gets all drivers for bus + * @bus: bus to get devices for + * returns dlist of devices with success and NULL with failure + */ +struct dlist *sysfs_get_bus_drivers(struct sysfs_bus *bus) +{ + struct sysfs_driver *drv; + struct dlist *dirlist; + char path[SYSFS_PATH_MAX], drvpath[SYSFS_PATH_MAX]; + char *curdir; + + if (!bus) { + errno = EINVAL; + return NULL; + } + memset(path, 0, SYSFS_PATH_MAX); + safestrcpy(path, bus->path); + safestrcat(path, "/"); + safestrcat(path, SYSFS_DRIVERS_NAME); + + dirlist = read_dir_subdirs(path); + if (dirlist) { + dlist_for_each_data(dirlist, curdir, char) { + if (bus->drivers) { + drv = (struct sysfs_driver *) + dlist_find_custom(bus->drivers, + (void *)curdir, name_equal); + if (drv) + continue; + } + safestrcpy(drvpath, path); + safestrcat(drvpath, "/"); + safestrcat(drvpath, curdir); + drv = sysfs_open_driver_path(drvpath); + if (!drv) { + dprintf("Error opening driver at %s\n", + drvpath); + continue; + } + if (!bus->drivers) + bus->drivers = dlist_new_with_delete + (sizeof(struct sysfs_driver), + sysfs_close_drv); + dlist_unshift_sorted(bus->drivers, drv, sort_list); + } + sysfs_close_list(dirlist); + } + return (bus->drivers); +} + +/** + * 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; + char buspath[SYSFS_PATH_MAX]; + + if (!name) { + errno = EINVAL; + return NULL; + } + + memset(buspath, 0, SYSFS_PATH_MAX); + if (sysfs_get_mnt_path(buspath, SYSFS_PATH_MAX)) { + dprintf("Sysfs not supported on this system\n"); + return NULL; + } + + safestrcat(buspath, "/"); + safestrcat(buspath, SYSFS_BUS_NAME); + safestrcat(buspath, "/"); + safestrcat(buspath, name); + if (sysfs_path_is_dir(buspath)) { + dprintf("Invalid path to bus: %s\n", buspath); + return NULL; + } + bus = alloc_bus(); + if (!bus) { + dprintf("calloc failed\n"); + return NULL; + } + safestrcpy(bus->name, name); + safestrcpy(bus->path, buspath); + if (sysfs_remove_trailing_slash(bus->path)) { + dprintf("Incorrect path to bus %s\n", bus->path); + sysfs_close_bus(bus); + return NULL; + } + + return bus; +} + +/** + * sysfs_get_bus_device: Get specific device on bus using device's id + * @bus: bus to find device on + * @id: bus_id for device + * returns struct sysfs_device reference or NULL if not found. + */ +struct sysfs_device *sysfs_get_bus_device(struct sysfs_bus *bus, + const char *id) +{ + struct sysfs_device *dev = NULL; + char devpath[SYSFS_PATH_MAX], target[SYSFS_PATH_MAX]; + + if (!bus || !id) { + errno = EINVAL; + return NULL; + } + + if (bus->devices) { + dev = (struct sysfs_device *)dlist_find_custom + (bus->devices, (void *)id, name_equal); + if (dev) + return dev; + } + safestrcpy(devpath, bus->path); + safestrcat(devpath, "/"); + safestrcat(devpath, SYSFS_DEVICES_NAME); + safestrcat(devpath, "/"); + safestrcat(devpath, id); + if (sysfs_path_is_link(devpath)) { + dprintf("No such device %s on bus %s?\n", id, bus->name); + return NULL; + } + if (!sysfs_get_link(devpath, target, SYSFS_PATH_MAX)) { + dev = sysfs_open_device_path(target); + if (!dev) { + dprintf("Error opening device at %s\n", target); + return NULL; + } + if (!bus->devices) + bus->devices = dlist_new_with_delete + (sizeof(struct sysfs_device), + sysfs_close_dev); + dlist_unshift_sorted(bus->devices, dev, sort_list); + } + return dev; +} + +/** + * sysfs_get_bus_driver: Get specific driver on bus using driver name + * @bus: bus to find driver on + * @drvname: name of driver + * returns struct sysfs_driver reference or NULL if not found. + */ +struct sysfs_driver *sysfs_get_bus_driver(struct sysfs_bus *bus, + const char *drvname) +{ + struct sysfs_driver *drv; + char drvpath[SYSFS_PATH_MAX]; + + if (!bus || !drvname) { + errno = EINVAL; + return NULL; + } + + if (bus->drivers) { + drv = (struct sysfs_driver *)dlist_find_custom + (bus->drivers, (void *)drvname, name_equal); + if (drv) + return drv; + } + safestrcpy(drvpath, bus->path); + safestrcat(drvpath, "/"); + safestrcat(drvpath, SYSFS_DRIVERS_NAME); + safestrcat(drvpath, "/"); + safestrcat(drvpath, drvname); + drv = sysfs_open_driver_path(drvpath); + if (!drv) { + dprintf("Error opening driver at %s\n", drvpath); + return NULL; + } + if (!bus->drivers) + bus->drivers = dlist_new_with_delete + (sizeof(struct sysfs_driver), + sysfs_close_drv); + dlist_unshift_sorted(bus->drivers, drv, sort_list); + return drv; +} + diff --git a/libsysfs/sysfs_class.c b/libsysfs/sysfs_class.c new file mode 100644 index 0000000..4fe0b82 --- /dev/null +++ b/libsysfs/sysfs_class.c @@ -0,0 +1,551 @@ +/* + * sysfs_class.c + * + * Generic class utility functions for libsysfs + * + * Copyright (C) IBM Corp. 2003-2005 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * 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) { + if (dev->parent) + sysfs_close_class_device(dev->parent); + if (dev->sysdevice) + sysfs_close_device(dev->sysdevice); + if (dev->attrlist) + dlist_destroy(dev->attrlist); + free(dev); + } +} + +static void sysfs_close_cls_dev(void *dev) +{ + sysfs_close_class_device((struct sysfs_class_device *)dev); +} + +/** + * sysfs_close_class: close the given class + * @cls: sysfs_class to close + */ +void sysfs_close_class(struct sysfs_class *cls) +{ + if (cls) { + if (cls->devices) + dlist_destroy(cls->devices); + if (cls->attrlist) + dlist_destroy(cls->attrlist); + free(cls); + } +} + +static int cdev_name_equal(void *a, void *b) +{ + if (!a || !b) + return 0; + + if (strncmp((char *)a, ((struct sysfs_class_device *)b)->name, + strlen((char *)a)) == 0) + return 1; + + return 0; +} + +static struct sysfs_class *alloc_class(void) +{ + return (struct sysfs_class *) calloc(1, sizeof(struct sysfs_class)); +} + +/** + * 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) +{ + struct sysfs_class_device *dev; + + dev = calloc(1, sizeof(struct sysfs_class_device)); + return dev; +} + +/** + * set_classdev_classname: Grabs classname from path + * @cdev: class device to set + * Returns nothing + */ +static void set_classdev_classname(struct sysfs_class_device *cdev) +{ + char *c, *e, name[SYSFS_PATH_MAX], link[SYSFS_PATH_MAX]; + struct stat stats; + int count = 0; + + /* + * Newer driver core changes have a class:class_device representation. + * Check if this cdev belongs to the newer style subsystem and + * set the classname appropriately. + */ + memset(name, 0, SYSFS_PATH_MAX); + safestrcpy(name, cdev->name); + c = strchr(name, ':'); + if (c) { + safestrcpy(cdev->name, c+1); + *c = '\0'; + safestrcpy(cdev->classname, name); + return; + } + + c = strstr(cdev->path, SYSFS_CLASS_NAME); + if (c == NULL) + c = strstr(cdev->path, SYSFS_BLOCK_NAME); + else + c = strstr(c, "/"); + + if (c) { + if (*c == '/') + c++; + e = c; + while (e != NULL && *e != '/' && *e != '\0') { + e++; + count++; + } + strncpy(cdev->classname, c, count); + } else { + strcpy(link, cdev->path); + strcat(link, "/subsystem"); + sysfs_get_link(link, name, SYSFS_PATH_MAX); + if (lstat(name, &stats)) + safestrcpy(cdev->classname, SYSFS_UNKNOWN); + else { + c = strrchr(name, '/'); + if (c) + safestrcpy(cdev->classname, c+1); + else + safestrcpy(cdev->classname, SYSFS_UNKNOWN); + } + } +} + +/** + * sysfs_open_class_device_path: 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_path(const char *path) +{ + struct sysfs_class_device *cdev; + char temp_path[SYSFS_PATH_MAX]; + + if (!path) { + errno = EINVAL; + return NULL; + } + + /* + * Post linux-2.6.14 driver model supports nested classes with + * links to the nested hierarchy at /sys/class/xxx/. Check for + * a link to the actual class device if a directory isn't found + */ + if (sysfs_path_is_dir(path)) { + dprintf("%s: Directory not found, checking for a link\n", path); + if (!sysfs_path_is_link(path)) { + if (sysfs_get_link(path, temp_path, SYSFS_PATH_MAX)) { + dprintf("Error retrieving link at %s\n", path); + return NULL; + } + } else { + dprintf("%s is not a valid class device path\n", path); + return NULL; + } + } else + safestrcpy(temp_path, path); + + cdev = alloc_class_device(); + if (!cdev) { + dprintf("calloc failed\n"); + return NULL; + } + if (sysfs_get_name_from_path(temp_path, cdev->name, SYSFS_NAME_LEN)) { + errno = EINVAL; + dprintf("Error getting class device name\n"); + sysfs_close_class_device(cdev); + return NULL; + } + + safestrcpy(cdev->path, temp_path); + if (sysfs_remove_trailing_slash(cdev->path)) { + dprintf("Invalid path to class device %s\n", cdev->path); + sysfs_close_class_device(cdev); + return NULL; + } + set_classdev_classname(cdev); + + return cdev; +} + +/** + * sysfs_get_classdev_parent: Retrieves the parent of a class device. + * eg., when working with hda1, this function can be used to retrieve the + * sysfs_class_device for hda + * + * @clsdev: class device whose parent details are required. + * Returns sysfs_class_device of the parent on success, NULL on failure + */ +struct sysfs_class_device *sysfs_get_classdev_parent + (struct sysfs_class_device *clsdev) +{ + char abs_path[SYSFS_PATH_MAX], tmp_path[SYSFS_PATH_MAX]; + char *c; + + if (!clsdev) { + errno = EINVAL; + return NULL; + } + + if (clsdev->parent) + return (clsdev->parent); + + memset(abs_path, 0, SYSFS_PATH_MAX); + memset(tmp_path, 0, SYSFS_PATH_MAX); + + safestrcpy(tmp_path, clsdev->path); + c = strstr(tmp_path, clsdev->classname); + c = strchr(c, '/'); + *c = '\0'; + + safestrcpy(abs_path, clsdev->path); + c = strrchr(abs_path, '/'); + *c = '\0'; + + if ((strncmp(tmp_path, abs_path, strlen(abs_path))) == 0) { + dprintf("Class device %s doesn't have a parent\n", + clsdev->name); + return NULL; + } + + clsdev->parent = sysfs_open_class_device_path(abs_path); + + return clsdev->parent; +} + +/** + * get_classdev_path: given the class and a device in the class, return the + * absolute path to the device + * @classname: name of the class + * @clsdev: the class device + * @path: buffer to return path + * @psize: size of "path" + * Returns 0 on SUCCESS or -1 on error + */ +static int get_classdev_path(const char *classname, const char *clsdev, + char *path, size_t len) +{ + char *c; + + if (!classname || !clsdev || !path) { + errno = EINVAL; + return -1; + } + if (sysfs_get_mnt_path(path, len) != 0) { + dprintf("Error getting sysfs mount path\n"); + return -1; + } + safestrcatmax(path, "/", len); + if (strncmp(classname, SYSFS_BLOCK_NAME, + sizeof(SYSFS_BLOCK_NAME)) == 0) { + safestrcatmax(path, SYSFS_BLOCK_NAME, len); + if (!sysfs_path_is_dir(path)) + goto done; + c = strrchr(path, '/'); + *(c+1) = '\0'; + } + safestrcatmax(path, SYSFS_CLASS_NAME, len); + safestrcatmax(path, "/", len); + safestrcatmax(path, classname, len); +done: + safestrcatmax(path, "/", len); + safestrcatmax(path, clsdev, len); + return 0; +} + +/** + * sysfs_open_class_device: Locates a specific class_device and returns it. + * Class_device must be closed using sysfs_close_class_device + * @classname: Class to search + * @name: name of the class_device + * + * NOTE: + * Call sysfs_close_class_device() to close the class device + */ +struct sysfs_class_device *sysfs_open_class_device + (const char *classname, const char *name) +{ + char devpath[SYSFS_PATH_MAX]; + struct sysfs_class_device *cdev; + + if (!classname || !name) { + errno = EINVAL; + return NULL; + } + + memset(devpath, 0, SYSFS_PATH_MAX); + if ((get_classdev_path(classname, name, devpath, + SYSFS_PATH_MAX)) != 0) { + dprintf("Error getting to device %s on class %s\n", + name, classname); + return NULL; + } + + cdev = sysfs_open_class_device_path(devpath); + if (!cdev) { + dprintf("Error getting class device %s from class %s\n", + name, classname); + return NULL; + } + return cdev; +} + +/** + * sysfs_get_classdev_attr: searches class device's attributes by name + * @clsdev: class device to look through + * @name: attribute name to get + * returns sysfs_attribute reference with success or NULL with error + */ +struct sysfs_attribute *sysfs_get_classdev_attr + (struct sysfs_class_device *clsdev, const char *name) +{ + if (!clsdev || !name) { + errno = EINVAL; + return NULL; + } + return get_attribute(clsdev, (char *)name); +} + +/** + * sysfs_get_classdev_attributes: gets list of classdev attributes + * @clsdev: class device whose attributes list is needed + * returns dlist of attributes on success or NULL on error + */ +struct dlist *sysfs_get_classdev_attributes(struct sysfs_class_device *clsdev) +{ + if (!clsdev) { + errno = EINVAL; + return NULL; + } + return get_dev_attributes_list(clsdev); +} + +/** + * sysfs_get_classdev_device: gets the sysfs_device associated with the + * given sysfs_class_device + * @clsdev: class device whose associated sysfs_device is needed + * returns struct sysfs_device * on success or NULL on error + */ +struct sysfs_device *sysfs_get_classdev_device + (struct sysfs_class_device *clsdev) +{ + char linkpath[SYSFS_PATH_MAX], devpath[SYSFS_PATH_MAX]; + + if (!clsdev) { + errno = EINVAL; + return NULL; + } + + if (clsdev->sysdevice) + return clsdev->sysdevice; + + memset(linkpath, 0, SYSFS_PATH_MAX); + safestrcpy(linkpath, clsdev->path); + safestrcat(linkpath, "/device"); + if (!sysfs_path_is_link(linkpath)) { + memset(devpath, 0, SYSFS_PATH_MAX); + if (!sysfs_get_link(linkpath, devpath, SYSFS_PATH_MAX)) + clsdev->sysdevice = sysfs_open_device_path(devpath); + } + return clsdev->sysdevice; +} + +/** + * sysfs_open_class: opens specific class and all its devices on system + * returns sysfs_class structure with success or NULL with error. + */ +struct sysfs_class *sysfs_open_class(const char *name) +{ + struct sysfs_class *cls = NULL; + char *c, classpath[SYSFS_PATH_MAX]; + + if (!name) { + errno = EINVAL; + return NULL; + } + + memset(classpath, 0, SYSFS_PATH_MAX); + if ((sysfs_get_mnt_path(classpath, SYSFS_PATH_MAX)) != 0) { + dprintf("Sysfs not supported on this system\n"); + return NULL; + } + + safestrcat(classpath, "/"); + if (strcmp(name, SYSFS_BLOCK_NAME) == 0) { + safestrcat(classpath, SYSFS_BLOCK_NAME); + if (!sysfs_path_is_dir(classpath)) + goto done; + c = strrchr(classpath, '/'); + *(c+1) = '\0'; + } + safestrcat(classpath, SYSFS_CLASS_NAME); + safestrcat(classpath, "/"); + safestrcat(classpath, name); +done: + if (sysfs_path_is_dir(classpath)) { + dprintf("Class %s not found on the system\n", name); + return NULL; + } + + cls = alloc_class(); + if (cls == NULL) { + dprintf("calloc failed\n"); + return NULL; + } + safestrcpy(cls->name, name); + safestrcpy(cls->path, classpath); + if ((sysfs_remove_trailing_slash(cls->path)) != 0) { + dprintf("Invalid path to class device %s\n", cls->path); + sysfs_close_class(cls); + return NULL; + } + + return cls; +} + +/** + * sysfs_get_class_device: get specific class device using the device's id + * @cls: sysfs_class to find the device on + * @name: name of the class device to look for + * + * Returns sysfs_class_device * on success and NULL on failure + */ +struct sysfs_class_device *sysfs_get_class_device(struct sysfs_class *cls, + const char *name) +{ + char path[SYSFS_PATH_MAX]; + struct sysfs_class_device *cdev = NULL; + + if (!cls || !name) { + errno = EINVAL; + return NULL; + } + + if (cls->devices) { + cdev = (struct sysfs_class_device *)dlist_find_custom + (cls->devices, (void *)name, cdev_name_equal); + if (cdev) + return cdev; + } + + safestrcpy(path, cls->path); + safestrcat(path, "/"); + safestrcat(path, name); + cdev = sysfs_open_class_device_path(path); + if (!cdev) { + dprintf("Error opening class device at %s\n", path); + return NULL; + } + if (!cls->devices) + cls->devices = dlist_new_with_delete + (sizeof(struct sysfs_class_device), + sysfs_close_cls_dev); + + dlist_unshift_sorted(cls->devices, cdev, sort_list); + return cdev; +} + +/** + * Add class devices to list + */ +static void add_cdevs_to_classlist(struct sysfs_class *cls, struct dlist *list) +{ + char path[SYSFS_PATH_MAX], *cdev_name; + struct sysfs_class_device *cdev = NULL; + + if (cls == NULL || list == NULL) + return; + + dlist_for_each_data(list, cdev_name, char) { + if (cls->devices) { + cdev = (struct sysfs_class_device *) + dlist_find_custom(cls->devices, + (void *)cdev_name, cdev_name_equal); + if (cdev) + continue; + } + safestrcpy(path, cls->path); + safestrcat(path, "/"); + safestrcat(path, cdev_name); + cdev = sysfs_open_class_device_path(path); + if (cdev) { + if (!cls->devices) + cls->devices = dlist_new_with_delete + (sizeof(struct sysfs_class_device), + sysfs_close_cls_dev); + dlist_unshift_sorted(cls->devices, cdev, + sort_list); + } + } +} + +/** + * sysfs_get_class_devices: get all class devices in the given class + * @cls: sysfs_class whose devices list is needed + * + * Returns a dlist of sysfs_class_device * on success and NULL on failure + */ +struct dlist *sysfs_get_class_devices(struct sysfs_class *cls) +{ + char path[SYSFS_PATH_MAX]; + struct dlist *dirlist, *linklist; + + if (!cls) { + errno = EINVAL; + return NULL; + } + + /* + * Post linux-2.6.14, we have nested classes and links under + * /sys/class/xxx/. are also valid class devices + */ + safestrcpy(path, cls->path); + dirlist = read_dir_subdirs(path); + if (dirlist) { + add_cdevs_to_classlist(cls, dirlist); + sysfs_close_list(dirlist); + } + + linklist = read_dir_links(path); + if (linklist) { + add_cdevs_to_classlist(cls, linklist); + sysfs_close_list(linklist); + } + + return cls->devices; +} diff --git a/libsysfs/sysfs_device.c b/libsysfs/sysfs_device.c new file mode 100644 index 0000000..b783ec5 --- /dev/null +++ b/libsysfs/sysfs_device.c @@ -0,0 +1,424 @@ +/* + * sysfs_device.c + * + * Generic device utility functions for libsysfs + * + * Copyright (C) IBM Corp. 2003-2005 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * 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" + +/** + * get_dev_driver: fills in the dev->driver_name field + * Returns 0 on SUCCESS and -1 on error + */ +static int get_dev_driver(struct sysfs_device *dev) +{ + char path[SYSFS_PATH_MAX], devpath[SYSFS_PATH_MAX]; + + if (!dev) { + errno = EINVAL; + return -1; + } + memset(path, 0, SYSFS_PATH_MAX); + memset(devpath, 0, SYSFS_PATH_MAX); + safestrcpymax(path, dev->path, SYSFS_PATH_MAX); + safestrcatmax(path, "/driver", SYSFS_PATH_MAX); + if (!sysfs_path_is_link(path)) { + if (!sysfs_get_link(path, devpath, SYSFS_PATH_MAX)) { + if (!sysfs_get_name_from_path(devpath, + dev->driver_name, SYSFS_NAME_LEN)) + return 0; + } + } + return -1; +} + +/** + * sysfs_get_device_bus: retrieves the bus name the device is on, checks path + * to bus' link to make sure it has correct device. + * @dev: device to get busname. + * returns 0 with success and -1 with error. + */ +int sysfs_get_device_bus(struct sysfs_device *dev) +{ + char devpath[SYSFS_PATH_MAX], path[SYSFS_PATH_MAX]; + + if (!dev) { + errno = EINVAL; + return -1; + } + + memset(path, 0, SYSFS_PATH_MAX); + memset(devpath, 0, SYSFS_PATH_MAX); + safestrcpymax(path, dev->path, SYSFS_PATH_MAX); + safestrcatmax(path, "/bus", SYSFS_PATH_MAX); + if (!sysfs_path_is_link(path)) { + if (!sysfs_get_link(path, devpath, SYSFS_PATH_MAX)) { + if (!sysfs_get_name_from_path(devpath, + dev->bus, SYSFS_NAME_LEN)) + return 0; + } + } + return -1; +} + +/** + * get_dev_subsystem: fills in the dev->subsystem field + * Returns 0 on SUCCESS and -1 on error + */ +static int get_dev_subsystem(struct sysfs_device *dev) +{ + char path[SYSFS_PATH_MAX], devpath[SYSFS_PATH_MAX]; + + if (!dev) { + errno = EINVAL; + return -1; + } + memset(path, 0, SYSFS_PATH_MAX); + memset(devpath, 0, SYSFS_PATH_MAX); + safestrcpymax(path, dev->path, SYSFS_PATH_MAX); + safestrcatmax(path, "/subsystem", SYSFS_PATH_MAX); + if (!sysfs_path_is_link(path)) { + if (!sysfs_get_link(path, devpath, SYSFS_PATH_MAX)) { + if (!sysfs_get_name_from_path(devpath, + dev->subsystem, SYSFS_NAME_LEN)) + return 0; + } + } + return -1; +} +/** + * sysfs_close_dev_tree: routine for dlist integration + */ +void sysfs_close_dev_tree(void *dev) +{ + sysfs_close_device_tree((struct sysfs_device *)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) { + if (devroot->children) { + struct sysfs_device *child = NULL; + + dlist_for_each_data(devroot->children, child, + struct sysfs_device) + sysfs_close_device_tree(child); + } + devroot->children = NULL; + sysfs_close_device(devroot); + } +} + +/** + * sysfs_close_device: closes and cleans up a device + * @dev = device to clean up + */ +void sysfs_close_device(struct sysfs_device *dev) +{ + if (dev) { + if (dev->parent) + sysfs_close_device(dev->parent); + if (dev->children && dev->children->count) + dlist_destroy(dev->children); + if (dev->attrlist) + dlist_destroy(dev->attrlist); + 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_open_device_path: 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_path(const char *path) +{ + struct sysfs_device *dev; + + if (!path) { + errno = EINVAL; + return NULL; + } + if (sysfs_path_is_dir(path)) { + dprintf("Incorrect path to device: %s\n", path); + return NULL; + } + dev = alloc_device(); + if (!dev) { + dprintf("Error allocating device at %s\n", path); + return NULL; + } + if (sysfs_get_name_from_path(path, dev->bus_id, SYSFS_NAME_LEN)) { + errno = EINVAL; + dprintf("Error getting device bus_id\n"); + sysfs_close_device(dev); + return NULL; + } + safestrcpy(dev->path, path); + if (sysfs_remove_trailing_slash(dev->path)) { + dprintf("Invalid path to device %s\n", dev->path); + sysfs_close_device(dev); + return NULL; + } + /* + * The "name" attribute no longer exists... return the device's + * sysfs representation instead, in the "dev->name" field, which + * implies that the dev->name and dev->bus_id contain same data. + */ + safestrcpy(dev->name, dev->bus_id); + + if (sysfs_get_device_bus(dev)) + dprintf("Could not get device bus\n"); + + if (get_dev_driver(dev)) { + dprintf("Could not get device %s's driver\n", dev->bus_id); + safestrcpy(dev->driver_name, SYSFS_UNKNOWN); + } + + if (get_dev_subsystem(dev)) { + dprintf("Could not get device %s's subsystem\n", dev->bus_id); + safestrcpy(dev->subsystem, SYSFS_UNKNOWN); + } + return dev; +} + +/** + * 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_device *cur = NULL; + struct sysfs_device *devlist; + + if (path == NULL) { + errno = EINVAL; + return NULL; + } + rootdev = sysfs_open_device_path(path); + if (rootdev == NULL) { + dprintf("Error opening root device at %s\n", path); + return NULL; + } + + devlist = sysfs_read_dir_subdirs(path); + if (devlist->children) { + dlist_for_each_data(devlist->children, cur, + struct sysfs_device) { + new = sysfs_open_device_tree(cur->path); + if (new == NULL) { + dprintf("Error opening device tree at %s\n", + cur->path); + sysfs_close_device_tree(rootdev); + return NULL; + } + if (rootdev->children == NULL) + rootdev->children = dlist_new_with_delete + (sizeof(struct sysfs_device), + sysfs_close_dev_tree); + dlist_unshift_sorted(rootdev->children, new, sort_list); + } + } + + return rootdev; +} + +/** + * sysfs_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) +{ + if (!dev || !name) { + errno = EINVAL; + return NULL; + } + return get_attribute(dev, (char *)name); +} + +/** + * sysfs_get_device_attributes: gets list of device attributes + * @dev: device whose attributes list is needed + * returns dlist of attributes on success or NULL on error + */ +struct dlist *sysfs_get_device_attributes(struct sysfs_device *dev) +{ + if (!dev) { + errno = EINVAL; + return NULL; + } + return get_dev_attributes_list(dev); +} + +/** + * get_device_absolute_path: looks up the bus the device is on, gets + * absolute path to the device + * @device: device for which path is needed + * @path: buffer to store absolute path + * @psize: size of "path" + * Returns 0 on success -1 on failure + */ +static int get_device_absolute_path(const char *device, const char *bus, + char *path, size_t psize) +{ + char bus_path[SYSFS_PATH_MAX]; + + if (!device || !path) { + errno = EINVAL; + return -1; + } + + memset(bus_path, 0, SYSFS_PATH_MAX); + if (sysfs_get_mnt_path(bus_path, SYSFS_PATH_MAX)) { + dprintf ("Sysfs not supported on this system\n"); + return -1; + } + safestrcat(bus_path, "/"); + safestrcat(bus_path, SYSFS_BUS_NAME); + safestrcat(bus_path, "/"); + safestrcat(bus_path, bus); + safestrcat(bus_path, "/"); + safestrcat(bus_path, SYSFS_DEVICES_NAME); + safestrcat(bus_path, "/"); + safestrcat(bus_path, device); + /* + * We now are at /sys/bus/"bus_name"/devices/"device" which is a link. + * Now read this link to reach to the device. + */ + if (sysfs_get_link(bus_path, path, psize)) { + dprintf("Error getting to device %s\n", device); + return -1; + } + return 0; +} + +/** + * sysfs_open_device: open a device by id (use the "bus" subsystem) + * @bus: bus the device belongs to + * @bus_id: bus_id of the device to open - has to be the "bus_id" in + * /sys/bus/xxx/devices + * returns struct sysfs_device if found, NULL otherwise + * NOTE: + * 1. Use sysfs_close_device to close the device + * 2. Bus the device is on must be supplied + * Use sysfs_find_device_bus to get the bus name + */ +struct sysfs_device *sysfs_open_device(const char *bus, const char *bus_id) +{ + char sysfs_path[SYSFS_PATH_MAX]; + struct sysfs_device *device; + + if (!bus_id || !bus) { + errno = EINVAL; + return NULL; + } + memset(sysfs_path, 0, SYSFS_PATH_MAX); + if (get_device_absolute_path(bus_id, bus, sysfs_path, + SYSFS_PATH_MAX)) { + dprintf("Error getting to device %s\n", bus_id); + return NULL; + } + + device = sysfs_open_device_path(sysfs_path); + if (!device) { + dprintf("Error opening device %s\n", bus_id); + return NULL; + } + return device; +} + +/** + * sysfs_get_device_parent: opens up given device's parent and returns a + * reference to its sysfs_device + * @dev: sysfs_device whose parent is requested + * Returns sysfs_device of the parent on success and NULL on failure + */ +struct sysfs_device *sysfs_get_device_parent(struct sysfs_device *dev) +{ + char ppath[SYSFS_PATH_MAX], dpath[SYSFS_PATH_MAX], *tmp; + + if (!dev) { + errno = EINVAL; + return NULL; + } + + if (dev->parent) + return (dev->parent); + + memset(ppath, 0, SYSFS_PATH_MAX); + memset(dpath, 0, SYSFS_PATH_MAX); + safestrcpy(ppath, dev->path); + tmp = strrchr(ppath, '/'); + if (!tmp) { + dprintf("Invalid path to device %s\n", ppath); + return NULL; + } + if (*(tmp + 1) == '\0') { + *tmp = '\0'; + tmp = strrchr(tmp, '/'); + if (tmp == NULL) { + dprintf("Invalid path to device %s\n", ppath); + return NULL; + } + } + *tmp = '\0'; + + /* Make sure we're at the top of the device tree */ + if (sysfs_get_mnt_path(dpath, SYSFS_PATH_MAX) != 0) { + dprintf("Sysfs not supported on this system\n"); + return NULL; + } + safestrcat(dpath, "/"); + safestrcat(dpath, SYSFS_DEVICES_NAME); + + if (strcmp(dpath, ppath) == 0) { + dprintf("Device at %s does not have a parent\n", dev->path); + return NULL; + } + + dev->parent = sysfs_open_device_path(ppath); + if (!dev->parent) { + dprintf("Error opening device %s's parent at %s\n", + dev->bus_id, ppath); + return NULL; + } + return (dev->parent); +} diff --git a/libsysfs/sysfs_dir.c b/libsysfs/sysfs_dir.c new file mode 100644 index 0000000..5276991 --- /dev/null +++ b/libsysfs/sysfs_dir.c @@ -0,0 +1,1071 @@ +/* + * sysfs_dir.c + * + * Directory utility functions for libsysfs + * + * Copyright (C) IBM Corp. 2003 + * + * 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_del_attribute: routine for dlist integration + */ +static void sysfs_del_attribute(void *attr) +{ + sysfs_close_attribute((struct sysfs_attribute *)attr); +} + +/** + * sysfs_del_link: routine for dlist integration + */ +static void sysfs_del_link(void *ln) +{ + sysfs_close_link((struct sysfs_link *)ln); +} + +/** + * sysfs_del_dir: routine for dlist integration + */ +static void sysfs_del_directory(void *dir) +{ + sysfs_close_directory((struct sysfs_directory *)dir); +} + +/** + * dir_attribute_name_equal: compares dir attributes by name + * @a: attribute name for comparison + * @b: sysfs_attribute to be compared. + * returns 1 if a==b->name or 0 if not equal + */ +static int dir_attribute_name_equal(void *a, void *b) +{ + if (a == NULL || b == NULL) + return 0; + + if (strcmp(((char *)a), ((struct sysfs_attribute *)b)->name) == 0) + return 1; + + return 0; +} + +/** + * dir_link_name_equal: compares dir links by name + * @a: link name for comparison + * @b: sysfs_link to be compared. + * returns 1 if a==b->name or 0 if not equal + */ +static int dir_link_name_equal(void *a, void *b) +{ + if (a == NULL || b == NULL) + return 0; + + if (strcmp(((char *)a), ((struct sysfs_link *)b)->name) == 0) + return 1; + + return 0; +} + +/** + * dir_subdir_name_equal: compares subdirs by name + * @a: name of subdirectory to compare + * @b: sysfs_directory subdirectory to be compared + * returns 1 if a==b->name or 0 if not equal + */ +static int dir_subdir_name_equal(void *a, void *b) +{ + if (a == NULL || b == NULL) + return 0; + + if (strcmp(((char *)a), ((struct sysfs_directory *)b)->name) == 0) + return 1; + + return 0; +} + +/** + * sysfs_close_attribute: closes and cleans up attribute + * @sysattr: attribute to close. + */ +void sysfs_close_attribute(struct sysfs_attribute *sysattr) +{ + if (sysattr != NULL) { + if (sysattr->value != NULL) + 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("Error allocating attribute at %s\n", path); + return NULL; + } + if (sysfs_get_name_from_path(path, sysattr->name, + SYSFS_NAME_LEN) != 0) { + dprintf("Error retrieving attrib name from path: %s\n", path); + sysfs_close_attribute(sysattr); + return NULL; + } + safestrcpy(sysattr->path, path); + if ((stat(sysattr->path, &fileinfo)) != 0) { + dprintf("Stat failed: No such attribute?\n"); + sysattr->method = 0; + free(sysattr); + sysattr = NULL; + } else { + if (fileinfo.st_mode & S_IRUSR) + sysattr->method |= SYSFS_METHOD_SHOW; + if (fileinfo.st_mode & S_IWUSR) + sysattr->method |= SYSFS_METHOD_STORE; + } + + return sysattr; +} + +/** + * sysfs_write_attribute: write value to the attribute + * @sysattr: attribute to write + * @new_value: value to write + * @len: length of "new_value" + * returns 0 with success and -1 with error. + */ +int sysfs_write_attribute(struct sysfs_attribute *sysattr, + const char *new_value, size_t len) +{ + int fd; + int length; + + if (sysattr == NULL || new_value == NULL || len == 0) { + errno = EINVAL; + return -1; + } + + if (!(sysattr->method & SYSFS_METHOD_STORE)) { + dprintf ("Store method not supported for attribute %s\n", + sysattr->path); + errno = EACCES; + return -1; + } + if (sysattr->method & SYSFS_METHOD_SHOW) { + /* + * read attribute again to see if we can get an updated value + */ + if ((sysfs_read_attribute(sysattr)) != 0) { + dprintf("Error reading attribute\n"); + return -1; + } + if ((strncmp(sysattr->value, new_value, sysattr->len)) == 0) { + dprintf("Attr %s already has the requested value %s\n", + sysattr->name, new_value); + return 0; + } + } + /* + * open O_WRONLY since some attributes have no "read" but only + * "write" permission + */ + if ((fd = open(sysattr->path, O_WRONLY)) < 0) { + dprintf("Error reading attribute %s\n", sysattr->path); + return -1; + } + + length = write(fd, new_value, len); + if (length < 0) { + dprintf("Error writing to the attribute %s - invalid value?\n", + sysattr->name); + close(fd); + return -1; + } else if ((unsigned int)length != len) { + dprintf("Could not write %d bytes to attribute %s\n", + len, sysattr->name); + /* + * since we could not write user supplied number of bytes, + * restore the old value if one available + */ + if (sysattr->method & SYSFS_METHOD_SHOW) { + length = write(fd, sysattr->value, sysattr->len); + close(fd); + return -1; + } + } + + /* + * Validate length that has been copied. Alloc appropriate area + * in sysfs_attribute. Verify first if the attribute supports reading + * (show method). If it does not, do not bother + */ + if (sysattr->method & SYSFS_METHOD_SHOW) { + if (length != sysattr->len) { + sysattr->value = (char *)realloc + (sysattr->value, length); + sysattr->len = length; + safestrcpymax(sysattr->value, new_value, length); + } else { + /*"length" of the new value is same as old one */ + safestrcpymax(sysattr->value, new_value, length); + } + } + + close(fd); + return 0; +} + +/** + * sysfs_read_attribute: reads value from attribute + * @sysattr: attribute to read + * returns 0 with success and -1 with error. + */ +int sysfs_read_attribute(struct sysfs_attribute *sysattr) +{ + char *fbuf = NULL; + char *vbuf = NULL; + ssize_t length = 0; + long pgsize = 0; + int fd; + + if (sysattr == NULL) { + errno = EINVAL; + return -1; + } + if (!(sysattr->method & SYSFS_METHOD_SHOW)) { + dprintf("Show method not supported for attribute %s\n", + sysattr->path); + errno = EACCES; + return -1; + } + pgsize = sysconf(_SC_PAGESIZE); + fbuf = (char *)calloc(1, pgsize+1); + if (fbuf == NULL) { + dprintf("calloc failed\n"); + return -1; + } + if ((fd = open(sysattr->path, O_RDONLY)) < 0) { + dprintf("Error reading attribute %s\n", sysattr->path); + free(fbuf); + return -1; + } + length = read(fd, fbuf, pgsize); + if (length < 0) { + dprintf("Error reading from attribute %s\n", sysattr->path); + close(fd); + free(fbuf); + return -1; + } + if (sysattr->len > 0) { + if ((sysattr->len == length) && + (!(strncmp(sysattr->value, fbuf, length)))) { + close(fd); + free(fbuf); + return 0; + } + free(sysattr->value); + } + sysattr->len = length; + close(fd); + vbuf = (char *)realloc(fbuf, length+1); + if (vbuf == NULL) { + dprintf("realloc failed\n"); + 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 || vsize == 0) { + errno = EINVAL; + return -1; + } + + attr = sysfs_open_attribute(attrpath); + if (attr == NULL) { + dprintf("Invalid attribute path %s\n", attrpath); + errno = EINVAL; + return -1; + } + if((sysfs_read_attribute(attr)) != 0 || attr->value == NULL) { + dprintf("Error reading from attribute %s\n", attrpath); + sysfs_close_attribute(attr); + return -1; + } + length = strlen(attr->value); + if (length > vsize) + dprintf("Value length %d is larger than supplied buffer %d\n", + length, vsize); + safestrcpymax(value, attr->value, vsize); + sysfs_close_attribute(attr); + + return 0; +} + +/** + * sysfs_get_value_from_attrbutes: given a linked list of attributes and an + * attribute name, return its value + * @attr: attribute to search + * @name: name to look for + * returns char * value - could be NULL + */ +char *sysfs_get_value_from_attributes(struct dlist *attr, const char *name) +{ + struct sysfs_attribute *cur = NULL; + + if (attr == NULL || name == NULL) { + errno = EINVAL; + return NULL; + } + dlist_for_each_data(attr, cur, struct sysfs_attribute) { + if (strcmp(cur->name, name) == 0) + return cur->value; + } + return NULL; +} + +/** + * sysfs_close_link: closes and cleans up link. + * @ln: link to close. + */ +void sysfs_close_link(struct sysfs_link *ln) +{ + if (ln != NULL) + free(ln); +} + +/** + * sysfs_close_directory: closes directory, cleans up attributes and links + * @sysdir: sysfs_directory to close + */ +void sysfs_close_directory(struct sysfs_directory *sysdir) +{ + if (sysdir != NULL) { + if (sysdir->subdirs != NULL) + dlist_destroy(sysdir->subdirs); + if (sysdir->links != NULL) + dlist_destroy(sysdir->links); + if (sysdir->attributes != NULL) + dlist_destroy(sysdir->attributes); + free(sysdir); + sysdir = NULL; + } +} + +/** + * alloc_directory: allocates and initializes directory structure + * returns struct sysfs_directory with success or NULL with error. + */ +static struct sysfs_directory *alloc_directory(void) +{ + return (struct sysfs_directory *) + calloc(1, sizeof(struct sysfs_directory)); +} + +/** + * alloc_link: allocates and initializes link structure + * returns struct sysfs_link with success or NULL with error. + */ +static struct sysfs_link *alloc_link(void) +{ + return (struct sysfs_link *)calloc(1, sizeof(struct sysfs_link)); +} + +/** + * sysfs_read_all_subdirs: calls sysfs_read_directory for all subdirs + * @sysdir: directory whose subdirs need reading. + * returns 0 with success and -1 with error. + */ +int sysfs_read_all_subdirs(struct sysfs_directory *sysdir) +{ + struct sysfs_directory *cursub = NULL; + int retval = 0; + + if (sysdir == NULL) { + errno = EINVAL; + return -1; + } + if (sysdir->subdirs == NULL) + if ((sysfs_read_dir_subdirs(sysdir)) != 0) + return 0; + if (sysdir->subdirs != NULL) { + dlist_for_each_data(sysdir->subdirs, cursub, + struct sysfs_directory) { + if ((sysfs_read_dir_subdirs(cursub)) != 0) { + dprintf ("Error reading subdirectory %s\n", + cursub->name); + retval = -1; + } + } + } + if (!retval) + errno = 0; + return retval; +} + +/** + * sysfs_open_directory: opens a sysfs directory, creates dir struct, and + * returns. + * @path: path of directory to open. + * returns: struct sysfs_directory * with success and NULL on error. + */ +struct sysfs_directory *sysfs_open_directory(const char *path) +{ + struct sysfs_directory *sdir = NULL; + + if (path == NULL) { + errno = EINVAL; + return NULL; + } + + if (sysfs_path_is_dir(path) != 0) { + dprintf("Invalid path to directory %s\n", path); + errno = EINVAL; + return NULL; + } + + sdir = alloc_directory(); + if (sdir == NULL) { + dprintf("Error allocating directory %s\n", path); + return NULL; + } + if (sysfs_get_name_from_path(path, sdir->name, SYSFS_NAME_LEN) != 0) { + dprintf("Error getting directory name from path: %s\n", path); + sysfs_close_directory(sdir); + return NULL; + } + safestrcpy(sdir->path, path); + + return sdir; +} + +/** + * sysfs_open_link: opens a sysfs link, creates struct, and returns + * @path: path of link to open. + * returns: struct sysfs_link * with success and NULL on error. + */ +struct sysfs_link *sysfs_open_link(const char *linkpath) +{ + struct sysfs_link *ln = NULL; + + if (linkpath == NULL || strlen(linkpath) > SYSFS_PATH_MAX) { + errno = EINVAL; + return NULL; + } + + ln = alloc_link(); + if (ln == NULL) { + dprintf("Error allocating link %s\n", linkpath); + return NULL; + } + safestrcpy(ln->path, linkpath); + if ((sysfs_get_name_from_path(linkpath, ln->name, SYSFS_NAME_LEN)) != 0 + || (sysfs_get_link(linkpath, ln->target, SYSFS_PATH_MAX)) != 0) { + sysfs_close_link(ln); + errno = EINVAL; + dprintf("Invalid link path %s\n", linkpath); + return NULL; + } + + return ln; +} + +/** + * add_attribute: open and add attribute at path to given directory + * @sysdir: directory to add attribute to + * @path: path to attribute + * returns 0 with success and -1 with error. + */ +static int add_attribute(struct sysfs_directory *sysdir, const char *path) +{ + struct sysfs_attribute *attr = NULL; + + attr = sysfs_open_attribute(path); + if (attr == NULL) { + dprintf("Error opening attribute %s\n", path); + return -1; + } + if (attr->method & SYSFS_METHOD_SHOW) { + if ((sysfs_read_attribute(attr)) != 0) { + dprintf("Error reading attribute %s\n", path); + sysfs_close_attribute(attr); + return 0; + } + } + + if (sysdir->attributes == NULL) { + sysdir->attributes = dlist_new_with_delete + (sizeof(struct sysfs_attribute), sysfs_del_attribute); + } + dlist_unshift_sorted(sysdir->attributes, attr, sort_list); + + return 0; +} + +/** + * add_subdirectory: open and add subdirectory at path to given directory + * @sysdir: directory to add subdir to + * @path: path to subdirectory + * returns 0 with success and -1 with error. + */ +static int add_subdirectory(struct sysfs_directory *sysdir, const char *path) +{ + struct sysfs_directory *subdir = NULL; + + subdir = sysfs_open_directory(path); + if (subdir == NULL) { + dprintf("Error opening directory %s\n", path); + return -1; + } + if (sysdir->subdirs == NULL) + sysdir->subdirs = dlist_new_with_delete + (sizeof(struct sysfs_directory), sysfs_del_directory); + dlist_unshift_sorted(sysdir->subdirs, subdir, sort_list); + return 0; +} + +/** + * add_link: open and add link at path to given directory + * @sysdir: directory to add link to + * @path: path to link + * returns 0 with success and -1 with error. + */ +static int add_link(struct sysfs_directory *sysdir, const char *path) +{ + struct sysfs_link *ln = NULL; + + ln = sysfs_open_link(path); + if (ln == NULL) { + dprintf("Error opening link %s\n", path); + return -1; + } + if (sysdir->links == NULL) + sysdir->links = dlist_new_with_delete + (sizeof(struct sysfs_link), sysfs_del_link); + dlist_unshift_sorted(sysdir->links, ln, sort_list); + return 0; +} + +/** + * sysfs_read_dir_attributes: grabs attributes for the given directory + * @sysdir: sysfs directory to open + * returns 0 with success and -1 with error. + */ +int sysfs_read_dir_attributes(struct sysfs_directory *sysdir) +{ + DIR *dir = NULL; + struct dirent *dirent = NULL; + char file_path[SYSFS_PATH_MAX]; + int retval = 0; + + if (sysdir == NULL) { + errno = EINVAL; + return -1; + } + dir = opendir(sysdir->path); + if (dir == NULL) { + dprintf("Error opening directory %s\n", sysdir->path); + 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); + safestrcpy(file_path, sysdir->path); + safestrcat(file_path, "/"); + safestrcat(file_path, dirent->d_name); + if ((sysfs_path_is_file(file_path)) == 0) + retval = add_attribute(sysdir, file_path); + } + closedir(dir); + if (!retval) + errno = 0; + return(retval); +} + +/** + * sysfs_read_dir_links: grabs links in a specific directory + * @sysdir: sysfs directory to read links + * returns 0 with success and -1 with error. + */ +int sysfs_read_dir_links(struct sysfs_directory *sysdir) +{ + DIR *dir = NULL; + struct dirent *dirent = NULL; + char file_path[SYSFS_PATH_MAX]; + int retval = 0; + + if (sysdir == NULL) { + errno = EINVAL; + return -1; + } + dir = opendir(sysdir->path); + if (dir == NULL) { + dprintf("Error opening directory %s\n", sysdir->path); + 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); + safestrcpy(file_path, sysdir->path); + safestrcat(file_path, "/"); + safestrcat(file_path, dirent->d_name); + if ((sysfs_path_is_link(file_path)) == 0) { + retval = add_link(sysdir, file_path); + if (retval != 0) + break; + } + } + closedir(dir); + if (!retval) + errno = 0; + return(retval); +} + +/** + * sysfs_read_dir_subdirs: grabs subdirs in a specific directory + * @sysdir: sysfs directory to read links + * returns 0 with success and -1 with error. + */ +int sysfs_read_dir_subdirs(struct sysfs_directory *sysdir) +{ + DIR *dir = NULL; + struct dirent *dirent = NULL; + char file_path[SYSFS_PATH_MAX]; + int retval = 0; + + if (sysdir == NULL) { + errno = EINVAL; + return -1; + } + dir = opendir(sysdir->path); + if (dir == NULL) { + dprintf("Error opening directory %s\n", sysdir->path); + 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); + safestrcpy(file_path, sysdir->path); + safestrcat(file_path, "/"); + safestrcat(file_path, dirent->d_name); + if ((sysfs_path_is_dir(file_path)) == 0) + retval = add_subdirectory(sysdir, file_path); + } + closedir(dir); + if (!retval) + errno = 0; + return(retval); +} + +/** + * 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; + char file_path[SYSFS_PATH_MAX]; + int retval = 0; + + if (sysdir == NULL) { + errno = EINVAL; + return -1; + } + dir = opendir(sysdir->path); + if (dir == NULL) { + dprintf("Error opening directory %s\n", sysdir->path); + 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); + safestrcpy(file_path, sysdir->path); + safestrcat(file_path, "/"); + safestrcat(file_path, dirent->d_name); + if ((lstat(file_path, &astats)) != 0) { + dprintf("stat failed\n"); + continue; + } + if (S_ISDIR(astats.st_mode)) + retval = add_subdirectory(sysdir, file_path); + + else if (S_ISLNK(astats.st_mode)) + retval = add_link(sysdir, file_path); + + else if (S_ISREG(astats.st_mode)) + retval = add_attribute(sysdir, file_path); + } + closedir(dir); + if (!retval) + errno = 0; + return(retval); +} + +/** + * sysfs_refresh_dir_attributes: Refresh attributes list + * @sysdir: directory whose list of attributes to refresh + * Returns 0 on success, 1 on failure + */ +int sysfs_refresh_dir_attributes(struct sysfs_directory *sysdir) +{ + if (sysdir == NULL) { + errno = EINVAL; + return 1; + } + if ((sysfs_path_is_dir(sysdir->path)) != 0) { + dprintf("Invalid path to directory %s\n", sysdir->path); + errno = EINVAL; + return 1; + } + if (sysdir->attributes != NULL) { + dlist_destroy(sysdir->attributes); + sysdir->attributes = NULL; + } + if ((sysfs_read_dir_attributes(sysdir)) != 0) { + dprintf("Error refreshing attributes for directory %s\n", + sysdir->path); + return 1; + } + errno = 0; + return 0; +} + +/** + * sysfs_refresh_dir_links: Refresh links list + * @sysdir: directory whose list of links to refresh + * Returns 0 on success, 1 on failure + */ +int sysfs_refresh_dir_links(struct sysfs_directory *sysdir) +{ + if (sysdir == NULL) { + errno = EINVAL; + return 1; + } + if ((sysfs_path_is_dir(sysdir->path)) != 0) { + dprintf("Invalid path to directory %s\n", sysdir->path); + errno = EINVAL; + return 1; + } + if (sysdir->links != NULL) { + dlist_destroy(sysdir->links); + sysdir->links = NULL; + } + if ((sysfs_read_dir_links(sysdir)) != 0) { + dprintf("Error refreshing links for directory %s\n", + sysdir->path); + return 1; + } + errno = 0; + return 0; +} + +/** + * sysfs_refresh_dir_subdirs: Refresh subdirs list + * @sysdir: directory whose list of subdirs to refresh + * Returns 0 on success, 1 on failure + */ +int sysfs_refresh_dir_subdirs(struct sysfs_directory *sysdir) +{ + if (sysdir == NULL) { + errno = EINVAL; + return 1; + } + if ((sysfs_path_is_dir(sysdir->path)) != 0) { + dprintf("Invalid path to directory %s\n", sysdir->path); + errno = EINVAL; + return 1; + } + if (sysdir->subdirs != NULL) { + dlist_destroy(sysdir->subdirs); + sysdir->subdirs = NULL; + } + if ((sysfs_read_dir_subdirs(sysdir)) != 0) { + dprintf("Error refreshing subdirs for directory %s\n", + sysdir->path); + return 1; + } + errno = 0; + return 0; +} + +/** + * sysfs_get_directory_attribute: retrieves attribute attrname from current + * directory only + * @dir: directory to retrieve attribute from + * @attrname: name of attribute to look for + * + * NOTE: Since we know the attribute to look for, this routine looks for the + * attribute if it was created _after_ the attrlist was read initially. + * + * returns sysfs_attribute if found and NULL if not found + */ +struct sysfs_attribute *sysfs_get_directory_attribute + (struct sysfs_directory *dir, char *attrname) +{ + struct sysfs_attribute *attr = NULL; + char new_path[SYSFS_PATH_MAX]; + + if (dir == NULL || attrname == NULL) { + errno = EINVAL; + return NULL; + } + + if (dir->attributes == NULL) + if ((sysfs_read_dir_attributes(dir) != 0) + || (dir->attributes == NULL)) + return NULL; + + attr = (struct sysfs_attribute *)dlist_find_custom + (dir->attributes, attrname, dir_attribute_name_equal); + if (attr != NULL) { + if ((attr->method & SYSFS_METHOD_SHOW) && + (sysfs_read_attribute(attr)) != 0) { + dprintf("Error reading attribute %s\n", attr->name); + return NULL; + } + } else { + memset(new_path, 0, SYSFS_PATH_MAX); + safestrcpy(new_path, dir->path); + safestrcat(new_path, "/"); + safestrcat(new_path, attrname); + if ((sysfs_path_is_file(new_path)) == 0) { + if ((add_attribute(dir, new_path)) == 0) { + attr = (struct sysfs_attribute *) + dlist_find_custom(dir->attributes, + attrname, dir_attribute_name_equal); + } + } + } + + return attr; +} + +/** + * sysfs_get_directory_link: retrieves link from one directory list + * @dir: directory to retrieve link from + * @linkname: name of link to look for + * returns reference to sysfs_link if found and NULL if not found + */ +struct sysfs_link *sysfs_get_directory_link + (struct sysfs_directory *dir, char *linkname) +{ + if (dir == NULL || linkname == NULL) { + errno = EINVAL; + return NULL; + } + if (dir->links == NULL) { + if ((sysfs_read_dir_links(dir) != 0) || (dir->links == NULL)) + return NULL; + } else { + if ((sysfs_refresh_dir_links(dir)) != 0) + return NULL; + } + + return (struct sysfs_link *)dlist_find_custom(dir->links, + linkname, dir_link_name_equal); +} + +/** + * sysfs_get_subdirectory: retrieves subdirectory by name. + * @dir: directory to search for subdirectory. + * @subname: subdirectory name to get. + * returns reference to subdirectory or NULL if not found + */ +struct sysfs_directory *sysfs_get_subdirectory(struct sysfs_directory *dir, + char *subname) +{ + struct sysfs_directory *sub = NULL, *cursub = NULL; + + if (dir == NULL || subname == NULL) { + errno = EINVAL; + return NULL; + } + + if (dir->subdirs == NULL) + if (sysfs_read_dir_subdirs(dir) != 0) + return NULL; + + sub = (struct sysfs_directory *)dlist_find_custom(dir->subdirs, + subname, dir_subdir_name_equal); + if (sub != NULL) + return sub; + + if (dir->subdirs != NULL) { + dlist_for_each_data(dir->subdirs, cursub, + struct sysfs_directory) { + if (cursub->subdirs == NULL) { + if (sysfs_read_dir_subdirs(cursub) != 0) + continue; + if (cursub->subdirs == NULL) + continue; + } + sub = sysfs_get_subdirectory(cursub, subname); + if (sub != NULL) + return sub; + } + } + return NULL; +} + +/** + * sysfs_get_subdirectory_link: looks through all subdirs for specific link. + * @dir: directory and subdirectories to search for link. + * @linkname: link name to get. + * returns reference to link or NULL if not found + */ +struct sysfs_link *sysfs_get_subdirectory_link(struct sysfs_directory *dir, + char *linkname) +{ + struct sysfs_directory *cursub = NULL; + struct sysfs_link *ln = NULL; + + if (dir == NULL || linkname == NULL) { + errno = EINVAL; + return NULL; + } + + ln = sysfs_get_directory_link(dir, linkname); + if (ln != NULL) + return ln; + + if (dir->subdirs == NULL) + if (sysfs_read_dir_subdirs(dir) != 0) + return NULL; + + if (dir->subdirs != NULL) { + dlist_for_each_data(dir->subdirs, cursub, + struct sysfs_directory) { + ln = sysfs_get_subdirectory_link(cursub, linkname); + if (ln != NULL) + return ln; + } + } + return NULL; +} + +/** + * sysfs_get_dir_attributes: returns dlist of directory attributes + * @dir: directory to retrieve attributes from + * returns dlist of attributes or NULL + */ +struct dlist *sysfs_get_dir_attributes(struct sysfs_directory *dir) +{ + if (dir == NULL) { + errno = EINVAL; + return NULL; + } + + if (dir->attributes == NULL) { + if (sysfs_read_dir_attributes(dir) != 0) + return NULL; + } + + return (dir->attributes); +} + +/** + * sysfs_get_dir_links: returns dlist of directory links + * @dir: directory to return links for + * returns dlist of links or NULL + */ +struct dlist *sysfs_get_dir_links(struct sysfs_directory *dir) +{ + if (dir == NULL) { + errno = EINVAL; + return NULL; + } + + if (dir->links == NULL) { + if (sysfs_read_dir_links(dir) != 0) + return NULL; + } + + return (dir->links); +} + +/** + * sysfs_get_dir_subdirs: returns dlist of directory subdirectories + * @dir: directory to return subdirs for + * returns dlist of subdirs or NULL + */ +struct dlist *sysfs_get_dir_subdirs(struct sysfs_directory *dir) +{ + if (dir == NULL) { + errno = EINVAL; + return NULL; + } + + if (dir->subdirs == NULL) { + if (sysfs_read_dir_subdirs(dir) != 0) + return NULL; + } + + return (dir->subdirs); +} diff --git a/libsysfs/sysfs_driver.c b/libsysfs/sysfs_driver.c new file mode 100644 index 0000000..5458129 --- /dev/null +++ b/libsysfs/sysfs_driver.c @@ -0,0 +1,289 @@ +/* + * sysfs_driver.c + * + * Driver utility functions for libsysfs + * + * Copyright (C) IBM Corp. 2003-2005 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * 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" + +static void sysfs_close_driver_device(void *device) +{ + sysfs_close_device((struct sysfs_device *)device); +} + +/** + * sysfs_close_driver: closes driver and deletes device lists too + * @driver: driver to close + */ +void sysfs_close_driver(struct sysfs_driver *driver) +{ + if (driver) { + if (driver->devices) + dlist_destroy(driver->devices); + if (driver->attrlist) + dlist_destroy(driver->attrlist); + if (driver->module) + sysfs_close_module(driver->module); + 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)); +} + +/** + * get_driver_bus: gets bus the driver is on + * Returns 0 on success and 1 on error + */ +static int get_driver_bus(struct sysfs_driver *drv) +{ + char drvpath[SYSFS_PATH_MAX], *c = NULL; + + if (!drv) { + errno = EINVAL; + return 1; + } + + safestrcpy(drvpath, drv->path); + c = strstr(drvpath, SYSFS_DRIVERS_NAME); + if (c == NULL) + return 1; + *--c = '\0'; + c = strstr(drvpath, SYSFS_BUS_NAME); + if (c == NULL) + return 1; + c = strstr(c, "/"); + if (c == NULL) + return 1; + c++; + safestrcpy(drv->bus, c); + return 0; +} + +/** + * sysfs_get_driver_attr: searches drv's attributes by name + * @drv: driver to look through + * @name: attribute name to get + * returns sysfs_attribute reference with success or NULL with error. + */ +struct sysfs_attribute *sysfs_get_driver_attr(struct sysfs_driver *drv, + const char *name) +{ + if (!drv || !name) { + errno = EINVAL; + return NULL; + } + return get_attribute(drv, (char *)name); +} + +/** + * sysfs_get_driver_attributes: gets list of driver attributes + * @dev: driver whose attributes list is needed + * returns dlist of attributes on success or NULL on error + */ +struct dlist *sysfs_get_driver_attributes(struct sysfs_driver *drv) +{ + if (!drv) { + errno = EINVAL; + return NULL; + } + return get_dev_attributes_list(drv); +} + +/** + * sysfs_open_driver_path: opens and initializes driver structure + * @path: path to driver directory + * returns struct sysfs_driver with success and NULL with error + */ +struct sysfs_driver *sysfs_open_driver_path(const char *path) +{ + struct sysfs_driver *driver = NULL; + + if (!path) { + errno = EINVAL; + return NULL; + } + if (sysfs_path_is_dir(path)) { + dprintf("Invalid path to driver: %s\n", path); + return NULL; + } + driver = alloc_driver(); + if (!driver) { + dprintf("Error allocating driver at %s\n", path); + return NULL; + } + if (sysfs_get_name_from_path(path, driver->name, SYSFS_NAME_LEN)) { + dprintf("Error getting driver name from path\n"); + free(driver); + return NULL; + } + safestrcpy(driver->path, path); + if (sysfs_remove_trailing_slash(driver->path)) { + dprintf("Invalid path to driver %s\n", driver->path); + sysfs_close_driver(driver); + return NULL; + } + if (get_driver_bus(driver)) { + dprintf("Could not get the bus driver is on\n"); + sysfs_close_driver(driver); + return NULL; + } + + return driver; +} + +/** + * get_driver_path: looks up the bus the driver is on and builds path to + * the driver. + * @bus: bus on which to search + * @drv: driver to look for + * @path: buffer to return path to driver + * @psize: size of "path" + * Returns 0 on success and -1 on error + */ +static int get_driver_path(const char *bus, const char *drv, + char *path, size_t psize) +{ + if (!bus || !drv || !path || psize == 0) { + errno = EINVAL; + return -1; + } + if (sysfs_get_mnt_path(path, psize)) { + dprintf("Error getting sysfs mount path\n"); + return -1; + } + safestrcatmax(path, "/", psize); + safestrcatmax(path, SYSFS_BUS_NAME, psize); + safestrcatmax(path, "/", psize); + safestrcatmax(path, bus, psize); + safestrcatmax(path, "/", psize); + safestrcatmax(path, SYSFS_DRIVERS_NAME, psize); + safestrcatmax(path, "/", psize); + safestrcatmax(path, drv, psize); + return 0; +} + +/** + * sysfs_open_driver: open driver by name, given its bus + * @bus_name: Name of the bus + * @drv_name: Name of the driver + * Returns the sysfs_driver reference on success and NULL on failure + */ +struct sysfs_driver *sysfs_open_driver(const char *bus_name, + const char *drv_name) +{ + char path[SYSFS_PATH_MAX]; + struct sysfs_driver *driver = NULL; + + if (!drv_name || !bus_name) { + errno = EINVAL; + return NULL; + } + + memset(path, 0, SYSFS_PATH_MAX); + if (get_driver_path(bus_name, drv_name, path, SYSFS_PATH_MAX)) { + dprintf("Error getting to driver %s\n", drv_name); + return NULL; + } + driver = sysfs_open_driver_path(path); + if (!driver) { + dprintf("Error opening driver at %s\n", path); + return NULL; + } + return driver; +} + +/** + * sysfs_get_driver_devices: gets list of devices that use the driver + * @drv: sysfs_driver whose device list is needed + * Returns dlist of struct sysfs_device on success and NULL on failure + */ +struct dlist *sysfs_get_driver_devices(struct sysfs_driver *drv) +{ + char *ln = NULL; + struct dlist *linklist = NULL; + struct sysfs_device *dev = NULL; + + if (!drv) { + errno = EINVAL; + return NULL; + } + + linklist = read_dir_links(drv->path); + if (linklist) { + dlist_for_each_data(linklist, ln, char) { + + if (!strncmp(ln, SYSFS_MODULE_NAME, strlen(ln))) + continue; + + dev = sysfs_open_device(drv->bus, ln); + if (!dev) { + dprintf("Error opening driver's device\n"); + sysfs_close_list(linklist); + return NULL; + } + if (!drv->devices) { + drv->devices = dlist_new_with_delete + (sizeof(struct sysfs_device), + sysfs_close_driver_device); + if (!drv->devices) { + dprintf("Error creating device list\n"); + sysfs_close_list(linklist); + return NULL; + } + } + dlist_unshift_sorted(drv->devices, dev, sort_list); + } + sysfs_close_list(linklist); + } + return drv->devices; +} + +/** + * sysfs_get_driver_module: gets the module being used by this driver + * @drv: sysfs_driver whose "module" is needed + * Returns sysfs_module on success and NULL on failure + */ +struct sysfs_module *sysfs_get_driver_module(struct sysfs_driver *drv) +{ + char path[SYSFS_PATH_MAX], mod_path[SYSFS_PATH_MAX]; + + if (!drv) { + errno = EINVAL; + return NULL; + } + + memset(path, 0, SYSFS_PATH_MAX); + safestrcpy(path, drv->path); + safestrcat(path, "/"); + safestrcat(path, SYSFS_MODULE_NAME); + if (!sysfs_path_is_link(path)) { + memset(mod_path, 0, SYSFS_PATH_MAX); + if (!sysfs_get_link(path, mod_path, SYSFS_PATH_MAX)) + drv->module = sysfs_open_module_path(mod_path); + } + return drv->module; +} diff --git a/libsysfs/sysfs_module.c b/libsysfs/sysfs_module.c new file mode 100644 index 0000000..375de1a --- /dev/null +++ b/libsysfs/sysfs_module.c @@ -0,0 +1,279 @@ +/* + * sysfs_module.c + * + * Generic module utility functions for libsysfs + * + * Copyright (C) IBM Corp. 2003-2005 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * 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" + +/** + * mod_name_equal: compares modules' name + * @a: module_name looking for + * @b: sysfs_module being compared + */ +static int mod_name_equal(void *a, void *b) +{ + if (a == NULL || b == NULL) + return 0; + + if (strcmp(((char *)a), ((struct sysfs_module *)b)->name) == 0) + return 1; + + return 0; +} + +/** + * sysfs_close_module: closes a module. + * @module: sysfs_module device to close. + */ +void sysfs_close_module(struct sysfs_module *module) +{ + /* + * since both parms and sections are attribs _under_ the + * subdir of module->directory, they will get closed by + * this single call + */ + if (module != NULL) { + if (module->attrlist != NULL) + dlist_destroy(module->attrlist); + if (module->parmlist != NULL) + dlist_destroy(module->parmlist); + if (module->sections != NULL) + dlist_destroy(module->sections); + free(module); + } +} + +/** + * alloc_module: callocs and initializes new module struct. + * returns sysfs_module or NULL. + */ +static struct sysfs_module *alloc_module(void) +{ + return (struct sysfs_module *)calloc(1, sizeof(struct sysfs_module)); +} + +/** + * sysfs_open_module_path: Opens and populates the module struct + * @path: path to module. + * returns struct sysfs_module with success and NULL with error. + */ +struct sysfs_module *sysfs_open_module_path(const char *path) +{ + struct sysfs_module *mod = NULL; + + if (path == NULL) { + errno = EINVAL; + return NULL; + } + if ((sysfs_path_is_dir(path)) != 0) { + dprintf("%s is not a valid path to a module\n", path); + return NULL; + } + mod = alloc_module(); + if (mod == NULL) { + dprintf("calloc failed\n"); + return NULL; + } + if ((sysfs_get_name_from_path(path, mod->name, SYSFS_NAME_LEN)) != 0) { + errno = EINVAL; + dprintf("Error getting module name\n"); + sysfs_close_module(mod); + return NULL; + } + + safestrcpy(mod->path, path); + if ((sysfs_remove_trailing_slash(mod->path)) != 0) { + dprintf("Invalid path to module %s\n", mod->path); + sysfs_close_module(mod); + return NULL; + } + + return mod; +} + +/** + * sysfs_open_module: opens specific module on a system + * returns sysfs_module structure with success or NULL with error. + */ +struct sysfs_module *sysfs_open_module(const char *name) +{ + struct sysfs_module *mod = NULL; + char modpath[SYSFS_PATH_MAX]; + + if (name == NULL) { + errno = EINVAL; + return NULL; + } + + memset(modpath, 0, SYSFS_PATH_MAX); + if ((sysfs_get_mnt_path(modpath, SYSFS_PATH_MAX)) != 0) { + dprintf("Sysfs not supported on this system\n"); + return NULL; + } + + safestrcat(modpath, "/"); + safestrcat(modpath, SYSFS_MODULE_NAME); + safestrcat(modpath, "/"); + safestrcat(modpath, name); + + if ((sysfs_path_is_dir(modpath)) != 0) { + dprintf("Module %s not found on the system\n", name); + return NULL; + } + + mod = alloc_module(); + if (mod == NULL) { + dprintf("calloc failed\n"); + return NULL; + } + safestrcpy(mod->name, name); + safestrcpy(mod->path, modpath); + if ((sysfs_remove_trailing_slash(mod->path)) != 0) { + dprintf("Invalid path to module %s\n", mod->path); + sysfs_close_module(mod); + return NULL; + } + + return mod; +} + +/** + * sysfs_get_module_attributes: returns a dlist of attributes for + * the requested sysfs_module + * @cdev: sysfs_module for which attributes are needed + * returns a dlist of attributes if exists, NULL otherwise + */ +struct dlist *sysfs_get_module_attributes(struct sysfs_module *module) +{ + if (module == NULL) { + errno = EINVAL; + return NULL; + } + return get_dev_attributes_list(module); +} + +/** + * sysfs_get_module_attr: searches module's attributes by name + * @module: module to look through + * @name: attribute name to get + * returns sysfs_attribute reference with success or NULL with error + */ +struct sysfs_attribute *sysfs_get_module_attr + (struct sysfs_module *module, const char *name) +{ + if (module == NULL || name == NULL) { + errno = EINVAL; + return NULL; + } + + return get_attribute(module, (char *)name); +} + +/** + * sysfs_get_module_parms: Get modules list of parameters + * @module: sysfs_module whose parmameter list is required + * Returns dlist of parameters on SUCCESS and NULL on error + */ +struct dlist *sysfs_get_module_parms(struct sysfs_module *module) +{ + char ppath[SYSFS_PATH_MAX]; + + if (module == NULL) { + errno = EINVAL; + return NULL; + } + memset(ppath, 0, SYSFS_PATH_MAX); + safestrcpy(ppath, module->path); + safestrcat(ppath,"/"); + safestrcat(ppath, SYSFS_MOD_PARM_NAME); + + return (get_attributes_list(module->parmlist, ppath)); +} + +/** + * sysfs_get_module_sections: Get the set of sections for this module + * @module: sysfs_module whose list of sections is required + * Returns dlist of sections on SUCCESS and NULL on error + */ +struct dlist *sysfs_get_module_sections(struct sysfs_module *module) +{ + char ppath[SYSFS_PATH_MAX]; + + if (module == NULL) { + errno = EINVAL; + return NULL; + } + + memset(ppath, 0, SYSFS_PATH_MAX); + safestrcpy(ppath, module->path); + safestrcat(ppath,"/"); + safestrcat(ppath, SYSFS_MOD_SECT_NAME); + + return (get_attributes_list(module->sections, ppath)); +} + +/** + * sysfs_get_module_parm: + * @module: sysfs_module to look through + * @parm: name of the parameter to look for + * Returns sysfs_attribute * on SUCCESS and NULL on error + */ +struct sysfs_attribute *sysfs_get_module_parm + (struct sysfs_module *module, const char *parm) +{ + struct dlist *parm_list = NULL; + + if (module == NULL || parm == NULL) { + errno = EINVAL; + return NULL; + } + + parm_list = sysfs_get_module_parms(module); + if (parm_list == NULL) + return NULL; + + return (struct sysfs_attribute *)dlist_find_custom(parm_list, + (void *)parm, mod_name_equal); +} + +/** + * sysfs_get_module_section + * @module: sysfs_module to look through + * @section: name of the section to look for + * Returns sysfs_attribute * on SUCCESS and NULL on error + */ +struct sysfs_attribute *sysfs_get_module_section + (struct sysfs_module *module, const char *section) +{ + struct dlist *sect_list = NULL; + + if (module == NULL || section == NULL) { + errno = EINVAL; + return NULL; + } + + sect_list = sysfs_get_module_sections(module); + if (sect_list == NULL) + return NULL; + + return (struct sysfs_attribute *)dlist_find_custom(sect_list, + (void *)section, mod_name_equal); +} diff --git a/libsysfs/sysfs_utils.c b/libsysfs/sysfs_utils.c new file mode 100644 index 0000000..9ca207c --- /dev/null +++ b/libsysfs/sysfs_utils.c @@ -0,0 +1,307 @@ +/* + * sysfs_utils.c + * + * System utility functions for libsysfs + * + * Copyright (C) IBM Corp. 2003-2005 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * 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_remove_trailing_slash: Removes any trailing '/' in the given path + * @path: Path to look for the trailing '/' + * Returns 0 on success 1 on error + */ +int sysfs_remove_trailing_slash(char *path) +{ + size_t len; + + if (!path) { + errno = EINVAL; + return 1; + } + + len = strlen(path); + while (len > 0 && path[len-1] == '/') + path[--len] = '\0'; + return 0; +} + +/* + * 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) +{ + static char sysfs_path[SYSFS_PATH_MAX] = ""; + const char *sysfs_path_env; + + if (len == 0 || mnt_path == NULL) + return -1; + + /* evaluate only at the first call */ + if (sysfs_path[0] == '\0') { + /* possible overrride of real mount path */ + sysfs_path_env = getenv(SYSFS_PATH_ENV); + if (sysfs_path_env != NULL) { + safestrcpymax(mnt_path, sysfs_path_env, len); + sysfs_remove_trailing_slash(mnt_path); + return 0; + } + safestrcpymax(mnt_path, SYSFS_MNT_PATH, len); + } + + return 0; +} + +/** + * 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 tmp[SYSFS_PATH_MAX]; + char *n = NULL; + + if (!path || !name || len == 0) { + errno = EINVAL; + return -1; + } + memset(tmp, 0, SYSFS_PATH_MAX); + safestrcpy(tmp, path); + n = strrchr(tmp, '/'); + if (n == NULL) { + errno = EINVAL; + return -1; + } + if (*(n+1) == '\0') { + *n = '\0'; + n = strrchr(tmp, '/'); + if (n == NULL) { + errno = EINVAL; + return -1; + } + } + n++; + safestrcpymax(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 temp_path[SYSFS_PATH_MAX]; + char *d = NULL, *s = NULL; + int slashes = 0, count = 0; + + if (!path || !target || len == 0) { + errno = EINVAL; + return -1; + } + + memset(devdir, 0, SYSFS_PATH_MAX); + memset(linkpath, 0, SYSFS_PATH_MAX); + memset(temp_path, 0, SYSFS_PATH_MAX); + safestrcpy(devdir, path); + + if ((readlink(path, linkpath, SYSFS_PATH_MAX)) < 0) { + return -1; + } + d = linkpath; + /* + * Three cases here: + * 1. relative path => format ../.. + * 2. absolute path => format /abcd/efgh + * 3. relative path _from_ this dir => format abcd/efgh + */ + switch (*d) { + case '.': + /* + * handle the case where link is of type ./abcd/xxx + */ + safestrcpy(temp_path, devdir); + if (*(d+1) == '/') + d += 2; + else if (*(d+1) == '.') + goto parse_path; + s = strrchr(temp_path, '/'); + if (s != NULL) { + *(s+1) = '\0'; + safestrcat(temp_path, d); + } else { + safestrcpy(temp_path, d); + } + safestrcpymax(target, temp_path, len); + break; + /* + * relative path, getting rid of leading "../.." + */ +parse_path: + while (*d == '/' || *d == '.') { + if (*d == '/') + slashes++; + d++; + } + d--; + s = &devdir[strlen(devdir)-1]; + while (s != NULL && count != (slashes+1)) { + s--; + if (*s == '/') + count++; + } + safestrcpymax(s, d, (SYSFS_PATH_MAX-strlen(devdir))); + safestrcpymax(target, devdir, len); + break; + case '/': + /* absolute path - copy as is */ + safestrcpymax(target, linkpath, len); + break; + default: + /* relative path from this directory */ + safestrcpy(temp_path, devdir); + s = strrchr(temp_path, '/'); + if (s != NULL) { + *(s+1) = '\0'; + safestrcat(temp_path, linkpath); + } else { + safestrcpy(temp_path, linkpath); + } + safestrcpymax(target, temp_path, len); + } + return 0; +} + +/** + * sysfs_close_list: generic list free routine + * @list: dlist to free + * Returns nothing + */ +void sysfs_close_list(struct dlist *list) +{ + if (list) + dlist_destroy(list); +} + +/** + * sysfs_open_directory_list: gets a list of all directories under "path" + * @path: path to read + * Returns a dlist of supported names or NULL no directories (errno is set + * in case of error + */ +struct dlist *sysfs_open_directory_list(const char *path) +{ + if (!path) + return NULL; + + return (read_dir_subdirs(path)); +} + +/** + * sysfs_open_link_list: gets a list of all links under "path" + * @path: path to read + * Returns a dlist of supported links or NULL no directories (errno is set + * in case of error + */ +struct dlist *sysfs_open_link_list(const char *path) +{ + if (!path) + return NULL; + + return (read_dir_links(path)); +} + +/** + * sysfs_path_is_dir: Check if the path supplied points to a directory + * @path: path to validate + * Returns 0 if path points to dir, 1 otherwise + */ +int sysfs_path_is_dir(const char *path) +{ + struct stat astats; + + if (!path) { + errno = EINVAL; + return 1; + } + if ((lstat(path, &astats)) != 0) { + dprintf("stat() failed\n"); + return 1; + } + if (S_ISDIR(astats.st_mode)) + return 0; + + return 1; +} + +/** + * sysfs_path_is_link: Check if the path supplied points to a link + * @path: path to validate + * Returns 0 if path points to link, 1 otherwise + */ +int sysfs_path_is_link(const char *path) +{ + struct stat astats; + + if (!path) { + errno = EINVAL; + return 1; + } + if ((lstat(path, &astats)) != 0) { + dprintf("stat() failed\n"); + return 1; + } + if (S_ISLNK(astats.st_mode)) + return 0; + + return 1; +} + +/** + * sysfs_path_is_file: Check if the path supplied points to a file + * @path: path to validate + * Returns 0 if path points to file, 1 otherwise + */ +int sysfs_path_is_file(const char *path) +{ + struct stat astats; + + if (!path) { + errno = EINVAL; + return 1; + } + if ((lstat(path, &astats)) != 0) { + dprintf("stat() failed\n"); + return 1; + } + if (S_ISREG(astats.st_mode)) + return 0; + + return 1; +} |