diff options
author | Kay Sievers <kay.sievers@vrfy.org> | 2012-01-05 22:41:45 +0100 |
---|---|---|
committer | Kay Sievers <kay.sievers@vrfy.org> | 2012-01-06 05:07:10 +0100 |
commit | ad29a9f14fa8b1932c0e418bfcf1c10ce6a35a33 (patch) | |
tree | 9212c3d9d937234c25d19b993664b8ed164869a5 /libudev | |
parent | 9fbe27d9d6dc6e4530ce904d35c74326e415e34e (diff) |
merge udev/, libudev/, systemd/ files in src/; move extras/ to src/
Diffstat (limited to 'libudev')
-rw-r--r-- | libudev/.gitignore | 4 | ||||
-rw-r--r-- | libudev/COPYING | 504 | ||||
-rw-r--r-- | libudev/docs/.gitignore | 18 | ||||
-rw-r--r-- | libudev/docs/Makefile.am | 99 | ||||
-rw-r--r-- | libudev/docs/libudev-docs.xml | 32 | ||||
-rw-r--r-- | libudev/docs/libudev-overrides.txt | 0 | ||||
-rw-r--r-- | libudev/docs/libudev-sections.txt | 127 | ||||
-rw-r--r-- | libudev/docs/libudev.types | 0 | ||||
-rw-r--r-- | libudev/docs/version.xml.in | 1 | ||||
-rw-r--r-- | libudev/libudev-device-private.c | 185 | ||||
-rw-r--r-- | libudev/libudev-device.c | 1737 | ||||
-rw-r--r-- | libudev/libudev-enumerate.c | 947 | ||||
-rw-r--r-- | libudev/libudev-list.c | 344 | ||||
-rw-r--r-- | libudev/libudev-monitor.c | 875 | ||||
-rw-r--r-- | libudev/libudev-private.h | 213 | ||||
-rw-r--r-- | libudev/libudev-queue-private.c | 412 | ||||
-rw-r--r-- | libudev/libudev-queue.c | 474 | ||||
-rw-r--r-- | libudev/libudev-selinux-private.c | 109 | ||||
-rw-r--r-- | libudev/libudev-util-private.c | 242 | ||||
-rw-r--r-- | libudev/libudev-util.c | 568 | ||||
-rw-r--r-- | libudev/libudev.c | 457 | ||||
-rw-r--r-- | libudev/libudev.h | 189 | ||||
-rw-r--r-- | libudev/libudev.pc.in | 11 | ||||
-rw-r--r-- | libudev/test-libudev.c | 501 |
24 files changed, 0 insertions, 8049 deletions
diff --git a/libudev/.gitignore b/libudev/.gitignore deleted file mode 100644 index 74a5f1d379..0000000000 --- a/libudev/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -test-libudev -libudev.pc -libudev.so* - diff --git a/libudev/COPYING b/libudev/COPYING deleted file mode 100644 index 8add30ad59..0000000000 --- a/libudev/COPYING +++ /dev/null @@ -1,504 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 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. - - GNU LESSER GENERAL PUBLIC LICENSE - 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 - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - <one line to give the library's name and a brief idea of what it does.> - Copyright (C) <year> <name of author> - - 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - <signature of Ty Coon>, 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! - - diff --git a/libudev/docs/.gitignore b/libudev/docs/.gitignore deleted file mode 100644 index 286f244fa2..0000000000 --- a/libudev/docs/.gitignore +++ /dev/null @@ -1,18 +0,0 @@ -libudev-overrides.txt -html/ -tmpl/ -xml/ -*.stamp -*.bak -version.xml -libudev-decl-list.txt -libudev-decl.txt -libudev-undeclared.txt -libudev-undocumented.txt -libudev-unused.txt -libudev.args -libudev.hierarchy -libudev.interfaces -libudev.prerequisites -libudev.signals - diff --git a/libudev/docs/Makefile.am b/libudev/docs/Makefile.am deleted file mode 100644 index 965902627f..0000000000 --- a/libudev/docs/Makefile.am +++ /dev/null @@ -1,99 +0,0 @@ -## Process this file with automake to produce Makefile.in - -# We require automake 1.10 at least. -AUTOMAKE_OPTIONS = 1.10 - -# This is a blank Makefile.am for using gtk-doc. -# Copy this to your project's API docs directory and modify the variables to -# suit your project. See the GTK+ Makefiles in gtk+/docs/reference for examples -# of using the various options. - -# The name of the module, e.g. 'glib'. -DOC_MODULE=libudev - -# Uncomment for versioned docs and specify the version of the module, e.g. '2'. -#DOC_MODULE_VERSION=2 - -# The top-level SGML file. You can change this if you want to. -DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.xml - -# The directory containing the source code. Relative to $(srcdir). -# gtk-doc will search all .c & .h files beneath here for inline comments -# documenting the functions and macros. -# e.g. DOC_SOURCE_DIR=../../../gtk -DOC_SOURCE_DIR=.. - -# Extra options to pass to gtkdoc-scangobj. Not normally needed. -SCANGOBJ_OPTIONS= - -# Extra options to supply to gtkdoc-scan. -# e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED" -SCAN_OPTIONS= - -# Extra options to supply to gtkdoc-mkdb. -# e.g. MKDB_OPTIONS=--sgml-mode --output-format=xml -MKDB_OPTIONS=--sgml-mode --output-format=xml --name-space udev - -# Extra options to supply to gtkdoc-mktmpl -# e.g. MKTMPL_OPTIONS=--only-section-tmpl -MKTMPL_OPTIONS= - -# Extra options to supply to gtkdoc-mkhtml -MKHTML_OPTIONS=--path=$(abs_srcdir) --path=$(abs_builddir) - -# Extra options to supply to gtkdoc-fixref. Not normally needed. -# e.g. FIXXREF_OPTIONS=--extra-dir=../gdk-pixbuf/html --extra-dir=../gdk/html -FIXXREF_OPTIONS= - -# Used for dependencies. The docs will be rebuilt if any of these change. -# e.g. HFILE_GLOB=$(top_srcdir)/gtk/*.h -# e.g. CFILE_GLOB=$(top_srcdir)/gtk/*.c -HFILE_GLOB=$(top_srcdir)/libudev/libudev*.h -CFILE_GLOB=$(top_srcdir)/libudev/libudev*.c - -# Extra header to include when scanning, which are not under DOC_SOURCE_DIR -# e.g. EXTRA_HFILES=$(top_srcdir}/contrib/extra.h -EXTRA_HFILES= - -# Header files to ignore when scanning. Use base file name, no paths -# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h -IGNORE_HFILES= libudev-private.h - -# Images to copy into HTML directory. -# e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png -HTML_IMAGES= - -# Extra SGML files that are included by $(DOC_MAIN_SGML_FILE). -# e.g. content_files=running.sgml building.sgml changes-2.0.sgml -content_files = version.xml - -# SGML files where gtk-doc abbrevations (#GtkWidget) are expanded -# These files must be listed here *and* in content_files -# e.g. expand_content_files=running.sgml -expand_content_files= - -# CFLAGS and LDFLAGS for compiling gtkdoc-scangobj with your library. -# Only needed if you are using gtkdoc-scangobj to dynamically query widget -# signals and properties. -# e.g. GTKDOC_CFLAGS=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS) -# e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib) -GTKDOC_CFLAGS= -GTKDOC_LIBS= - -# This includes the standard gtk-doc make rules, copied by gtkdocize. -include $(top_srcdir)/gtk-doc.make - -# Other files to distribute -# e.g. EXTRA_DIST += version.xml.in -EXTRA_DIST += version.xml.in - -# Files not to distribute -# for --rebuild-types in $(SCAN_OPTIONS), e.g. $(DOC_MODULE).types -# for --rebuild-sections in $(SCAN_OPTIONS) e.g. $(DOC_MODULE)-sections.txt -#DISTCLEANFILES += - -# Comment this out if you want your docs-status tested during 'make check' -if ENABLE_GTK_DOC -#TESTS_ENVIRONMENT = cd $(srcsrc) -#TESTS = $(GTKDOC_CHECK) -endif diff --git a/libudev/docs/libudev-docs.xml b/libudev/docs/libudev-docs.xml deleted file mode 100644 index b7feb45529..0000000000 --- a/libudev/docs/libudev-docs.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0"?> -<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN" - "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" -[ - <!ENTITY version SYSTEM "version.xml"> -]> -<book id="index" xmlns:xi="http://www.w3.org/2003/XInclude"> - <bookinfo> - <title>libudev Reference Manual</title> - <releaseinfo>for libudev version &version;</releaseinfo> - <copyright> - <year>2009-2011</year> - <holder>Kay Sievers <kay.sievers@vrfy.org></holder> - </copyright> - </bookinfo> - - <chapter> - <title>libudev</title> - <xi:include href="xml/libudev.xml"/> - <xi:include href="xml/libudev-list.xml"/> - <xi:include href="xml/libudev-device.xml"/> - <xi:include href="xml/libudev-monitor.xml"/> - <xi:include href="xml/libudev-enumerate.xml"/> - <xi:include href="xml/libudev-queue.xml"/> - <xi:include href="xml/libudev-util.xml"/> - </chapter> - - <index id="api-index-full"> - <title>API Index</title> - <xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include> - </index> -</book> diff --git a/libudev/docs/libudev-overrides.txt b/libudev/docs/libudev-overrides.txt deleted file mode 100644 index e69de29bb2..0000000000 --- a/libudev/docs/libudev-overrides.txt +++ /dev/null diff --git a/libudev/docs/libudev-sections.txt b/libudev/docs/libudev-sections.txt deleted file mode 100644 index 15c3e934b5..0000000000 --- a/libudev/docs/libudev-sections.txt +++ /dev/null @@ -1,127 +0,0 @@ -<SECTION> -<FILE>libudev</FILE> -<TITLE>udev</TITLE> -udev -udev_ref -udev_unref -udev_new -udev_set_log_fn -udev_get_log_priority -udev_set_log_priority -udev_get_sys_path -udev_get_dev_path -udev_get_run_path -udev_get_userdata -udev_set_userdata -</SECTION> - -<SECTION> -<FILE>libudev-list</FILE> -<TITLE>udev_list</TITLE> -udev_list_entry -udev_list_entry_get_next -udev_list_entry_get_by_name -udev_list_entry_get_name -udev_list_entry_get_value -udev_list_entry_foreach -</SECTION> - -<SECTION> -<FILE>libudev-device</FILE> -<TITLE>udev_device</TITLE> -udev_device -udev_device_ref -udev_device_unref -udev_device_get_udev -udev_device_new_from_syspath -udev_device_new_from_devnum -udev_device_new_from_subsystem_sysname -udev_device_new_from_environment -udev_device_get_parent -udev_device_get_parent_with_subsystem_devtype -udev_device_get_devpath -udev_device_get_subsystem -udev_device_get_devtype -udev_device_get_syspath -udev_device_get_sysname -udev_device_get_sysnum -udev_device_get_devnode -udev_device_get_is_initialized -udev_device_get_devlinks_list_entry -udev_device_get_properties_list_entry -udev_device_get_tags_list_entry -udev_device_get_property_value -udev_device_get_driver -udev_device_get_devnum -udev_device_get_action -udev_device_get_sysattr_value -udev_device_get_sysattr_list_entry -udev_device_get_seqnum -udev_device_get_usec_since_initialized -udev_device_has_tag -</SECTION> - -<SECTION> -<FILE>libudev-monitor</FILE> -<TITLE>udev_monitor</TITLE> -udev_monitor -udev_monitor_ref -udev_monitor_unref -udev_monitor_get_udev -udev_monitor_new_from_netlink -udev_monitor_new_from_socket -udev_monitor_enable_receiving -udev_monitor_set_receive_buffer_size -udev_monitor_get_fd -udev_monitor_receive_device -udev_monitor_filter_add_match_subsystem_devtype -udev_monitor_filter_add_match_tag -udev_monitor_filter_update -udev_monitor_filter_remove -</SECTION> - -<SECTION> -<FILE>libudev-enumerate</FILE> -<TITLE>udev_enumerate</TITLE> -udev_enumerate -udev_enumerate_ref -udev_enumerate_unref -udev_enumerate_get_udev -udev_enumerate_new -udev_enumerate_add_match_subsystem -udev_enumerate_add_nomatch_subsystem -udev_enumerate_add_match_sysattr -udev_enumerate_add_nomatch_sysattr -udev_enumerate_add_match_property -udev_enumerate_add_match_tag -udev_enumerate_add_match_parent -udev_enumerate_add_match_is_initialized -udev_enumerate_add_match_sysname -udev_enumerate_add_syspath -udev_enumerate_scan_devices -udev_enumerate_scan_subsystems -udev_enumerate_get_list_entry -</SECTION> - -<SECTION> -<FILE>libudev-queue</FILE> -<TITLE>udev_queue</TITLE> -udev_queue -udev_queue_ref -udev_queue_unref -udev_queue_get_udev -udev_queue_new -udev_queue_get_udev_is_active -udev_queue_get_queue_is_empty -udev_queue_get_seqnum_is_finished -udev_queue_get_seqnum_sequence_is_finished -udev_queue_get_queued_list_entry -udev_queue_get_kernel_seqnum -udev_queue_get_udev_seqnum -</SECTION> - -<SECTION> -<FILE>libudev-util</FILE> -<TITLE>udev_util</TITLE> -udev_util_encode_string -</SECTION> diff --git a/libudev/docs/libudev.types b/libudev/docs/libudev.types deleted file mode 100644 index e69de29bb2..0000000000 --- a/libudev/docs/libudev.types +++ /dev/null diff --git a/libudev/docs/version.xml.in b/libudev/docs/version.xml.in deleted file mode 100644 index d78bda9342..0000000000 --- a/libudev/docs/version.xml.in +++ /dev/null @@ -1 +0,0 @@ -@VERSION@ diff --git a/libudev/libudev-device-private.c b/libudev/libudev-device-private.c deleted file mode 100644 index 0864919301..0000000000 --- a/libudev/libudev-device-private.c +++ /dev/null @@ -1,185 +0,0 @@ -/* - * libudev - interface to udev device information - * - * Copyright (C) 2008-2010 Kay Sievers <kay.sievers@vrfy.org> - * - * 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. - */ - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <stddef.h> -#include <stdbool.h> -#include <unistd.h> -#include <fcntl.h> -#include <string.h> -#include <sys/stat.h> - -#include "libudev.h" -#include "libudev-private.h" - -static void udev_device_tag(struct udev_device *dev, const char *tag, bool add) -{ - const char *id; - struct udev *udev = udev_device_get_udev(dev); - char filename[UTIL_PATH_SIZE]; - - id = udev_device_get_id_filename(dev); - if (id == NULL) - return; - util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/tags/", tag, "/", id, NULL); - - if (add) { - int fd; - - util_create_path(udev, filename); - fd = open(filename, O_WRONLY|O_CREAT|O_CLOEXEC|O_TRUNC|O_NOFOLLOW, 0444); - if (fd >= 0) - close(fd); - } else { - unlink(filename); - } -} - -int udev_device_tag_index(struct udev_device *dev, struct udev_device *dev_old, bool add) -{ - struct udev_list_entry *list_entry; - bool found; - - if (add && dev_old != NULL) { - /* delete possible left-over tags */ - udev_list_entry_foreach(list_entry, udev_device_get_tags_list_entry(dev_old)) { - const char *tag_old = udev_list_entry_get_name(list_entry); - struct udev_list_entry *list_entry_current; - - found = false; - udev_list_entry_foreach(list_entry_current, udev_device_get_tags_list_entry(dev)) { - const char *tag = udev_list_entry_get_name(list_entry_current); - - if (strcmp(tag, tag_old) == 0) { - found = true; - break; - } - } - if (!found) - udev_device_tag(dev_old, tag_old, false); - } - } - - udev_list_entry_foreach(list_entry, udev_device_get_tags_list_entry(dev)) - udev_device_tag(dev, udev_list_entry_get_name(list_entry), add); - - return 0; -} - -static bool device_has_info(struct udev_device *udev_device) -{ - struct udev_list_entry *list_entry; - - if (udev_device_get_devlinks_list_entry(udev_device) != NULL) - return true; - if (udev_device_get_devlink_priority(udev_device) != 0) - return true; - udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(udev_device)) - if (udev_list_entry_get_num(list_entry)) - return true; - if (udev_device_get_tags_list_entry(udev_device) != NULL) - return true; - if (udev_device_get_watch_handle(udev_device) >= 0) - return true; - return false; -} - -int udev_device_update_db(struct udev_device *udev_device) -{ - bool has_info; - const char *id; - struct udev *udev = udev_device_get_udev(udev_device); - char filename[UTIL_PATH_SIZE]; - char filename_tmp[UTIL_PATH_SIZE]; - FILE *f; - - id = udev_device_get_id_filename(udev_device); - if (id == NULL) - return -1; - - has_info = device_has_info(udev_device); - util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/data/", id, NULL); - - /* do not store anything for otherwise empty devices */ - if (!has_info && - major(udev_device_get_devnum(udev_device)) == 0 && - udev_device_get_ifindex(udev_device) == 0) { - unlink(filename); - return 0; - } - - /* write a database file */ - util_strscpyl(filename_tmp, sizeof(filename_tmp), filename, ".tmp", NULL); - util_create_path(udev, filename_tmp); - f = fopen(filename_tmp, "we"); - if (f == NULL) { - err(udev, "unable to create temporary db file '%s': %m\n", filename_tmp); - return -1; - } - - /* - * set 'sticky' bit to indicate that we should not clean the - * database when we transition from initramfs to the real root - */ - if (udev_device_get_db_persist(udev_device)) - fchmod(fileno(f), 01644); - - if (has_info) { - struct udev_list_entry *list_entry; - - if (major(udev_device_get_devnum(udev_device)) > 0) { - size_t devlen = strlen(udev_get_dev_path(udev))+1; - - udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(udev_device)) - fprintf(f, "S:%s\n", &udev_list_entry_get_name(list_entry)[devlen]); - if (udev_device_get_devlink_priority(udev_device) != 0) - fprintf(f, "L:%i\n", udev_device_get_devlink_priority(udev_device)); - if (udev_device_get_watch_handle(udev_device) >= 0) - fprintf(f, "W:%i\n", udev_device_get_watch_handle(udev_device)); - } - - if (udev_device_get_usec_initialized(udev_device) > 0) - fprintf(f, "I:%llu\n", udev_device_get_usec_initialized(udev_device)); - - udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(udev_device)) { - if (!udev_list_entry_get_num(list_entry)) - continue; - fprintf(f, "E:%s=%s\n", - udev_list_entry_get_name(list_entry), - udev_list_entry_get_value(list_entry)); - } - - udev_list_entry_foreach(list_entry, udev_device_get_tags_list_entry(udev_device)) - fprintf(f, "G:%s\n", udev_list_entry_get_name(list_entry)); - } - - fclose(f); - rename(filename_tmp, filename); - info(udev, "created %s file '%s' for '%s'\n", has_info ? "db" : "empty", - filename, udev_device_get_devpath(udev_device)); - return 0; -} - -int udev_device_delete_db(struct udev_device *udev_device) -{ - const char *id; - struct udev *udev = udev_device_get_udev(udev_device); - char filename[UTIL_PATH_SIZE]; - - id = udev_device_get_id_filename(udev_device); - if (id == NULL) - return -1; - util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/data/", id, NULL); - unlink(filename); - return 0; -} diff --git a/libudev/libudev-device.c b/libudev/libudev-device.c deleted file mode 100644 index e5950bb4b1..0000000000 --- a/libudev/libudev-device.c +++ /dev/null @@ -1,1737 +0,0 @@ -/* - * libudev - interface to udev device information - * - * Copyright (C) 2008-2010 Kay Sievers <kay.sievers@vrfy.org> - * - * 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. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <stddef.h> -#include <unistd.h> -#include <stdbool.h> -#include <errno.h> -#include <string.h> -#include <dirent.h> -#include <fcntl.h> -#include <ctype.h> -#include <net/if.h> -#include <sys/stat.h> -#include <sys/ioctl.h> -#include <sys/socket.h> -#include <linux/sockios.h> - -#include "libudev.h" -#include "libudev-private.h" - -/** - * SECTION:libudev-device - * @short_description: kernel sys devices - * - * Representation of kernel sys devices. Devices are uniquely identified - * by their syspath, every device has exactly one path in the kernel sys - * filesystem. Devices usually belong to a kernel subsystem, and and have - * a unique name inside that subsystem. - */ - -/** - * udev_device: - * - * Opaque object representing one kernel sys device. - */ -struct udev_device { - struct udev *udev; - struct udev_device *parent_device; - char *syspath; - const char *devpath; - char *sysname; - const char *sysnum; - char *devnode; - mode_t devnode_mode; - char *subsystem; - char *devtype; - char *driver; - char *action; - char *devpath_old; - char *id_filename; - char **envp; - char *monitor_buf; - size_t monitor_buf_len; - struct udev_list devlinks_list; - struct udev_list properties_list; - struct udev_list sysattr_value_list; - struct udev_list sysattr_list; - struct udev_list tags_list; - unsigned long long int seqnum; - unsigned long long int usec_initialized; - int devlink_priority; - int refcount; - dev_t devnum; - int ifindex; - int watch_handle; - int maj, min; - bool parent_set; - bool subsystem_set; - bool devtype_set; - bool devlinks_uptodate; - bool envp_uptodate; - bool tags_uptodate; - bool driver_set; - bool info_loaded; - bool db_loaded; - bool uevent_loaded; - bool is_initialized; - bool sysattr_list_read; - bool db_persist; -}; - -/** - * udev_device_get_seqnum: - * @udev_device: udev device - * - * This is only valid if the device was received through a monitor. Devices read from - * sys do not have a sequence number. - * - * Returns: the kernel event sequence number, or 0 if there is no sequence number available. - **/ -UDEV_EXPORT unsigned long long int udev_device_get_seqnum(struct udev_device *udev_device) -{ - if (udev_device == NULL) - return 0; - return udev_device->seqnum; -} - -static int udev_device_set_seqnum(struct udev_device *udev_device, unsigned long long int seqnum) -{ - char num[32]; - - udev_device->seqnum = seqnum; - snprintf(num, sizeof(num), "%llu", seqnum); - udev_device_add_property(udev_device, "SEQNUM", num); - return 0; -} - -int udev_device_get_ifindex(struct udev_device *udev_device) -{ - if (!udev_device->info_loaded) - udev_device_read_uevent_file(udev_device); - return udev_device->ifindex; -} - -static int udev_device_set_ifindex(struct udev_device *udev_device, int ifindex) -{ - char num[32]; - - udev_device->ifindex = ifindex; - snprintf(num, sizeof(num), "%u", ifindex); - udev_device_add_property(udev_device, "IFINDEX", num); - return 0; -} - -/** - * udev_device_get_devnum: - * @udev_device: udev device - * - * Returns: the device major/minor number. - **/ -UDEV_EXPORT dev_t udev_device_get_devnum(struct udev_device *udev_device) -{ - if (udev_device == NULL) - return makedev(0, 0); - if (!udev_device->info_loaded) - udev_device_read_uevent_file(udev_device); - return udev_device->devnum; -} - -static int udev_device_set_devnum(struct udev_device *udev_device, dev_t devnum) -{ - char num[32]; - - udev_device->devnum = devnum; - - snprintf(num, sizeof(num), "%u", major(devnum)); - udev_device_add_property(udev_device, "MAJOR", num); - snprintf(num, sizeof(num), "%u", minor(devnum)); - udev_device_add_property(udev_device, "MINOR", num); - return 0; -} - -const char *udev_device_get_devpath_old(struct udev_device *udev_device) -{ - return udev_device->devpath_old; -} - -static int udev_device_set_devpath_old(struct udev_device *udev_device, const char *devpath_old) -{ - const char *pos; - - free(udev_device->devpath_old); - udev_device->devpath_old = strdup(devpath_old); - if (udev_device->devpath_old == NULL) - return -ENOMEM; - udev_device_add_property(udev_device, "DEVPATH_OLD", udev_device->devpath_old); - - pos = strrchr(udev_device->devpath_old, '/'); - if (pos == NULL) - return -EINVAL; - return 0; -} - -/** - * udev_device_get_driver: - * @udev_device: udev device - * - * Returns: the driver string, or #NULL if there is no driver attached. - **/ -UDEV_EXPORT const char *udev_device_get_driver(struct udev_device *udev_device) -{ - char driver[UTIL_NAME_SIZE]; - - if (udev_device == NULL) - return NULL; - if (!udev_device->driver_set) { - udev_device->driver_set = true; - if (util_get_sys_core_link_value(udev_device->udev, "driver", udev_device->syspath, driver, sizeof(driver)) > 0) - udev_device->driver = strdup(driver); - } - return udev_device->driver; -} - -static int udev_device_set_driver(struct udev_device *udev_device, const char *driver) -{ - free(udev_device->driver); - udev_device->driver = strdup(driver); - if (udev_device->driver == NULL) - return -ENOMEM; - udev_device->driver_set = true; - udev_device_add_property(udev_device, "DRIVER", udev_device->driver); - return 0; -} - -/** - * udev_device_get_devtype: - * @udev_device: udev device - * - * Retrieve the devtype string of the udev device. - * - * Returns: the devtype name of the udev device, or #NULL if it can not be determined - **/ -UDEV_EXPORT const char *udev_device_get_devtype(struct udev_device *udev_device) -{ - if (udev_device == NULL) - return NULL; - if (!udev_device->devtype_set) { - udev_device->devtype_set = true; - udev_device_read_uevent_file(udev_device); - } - return udev_device->devtype; -} - -static int udev_device_set_devtype(struct udev_device *udev_device, const char *devtype) -{ - free(udev_device->devtype); - udev_device->devtype = strdup(devtype); - if (udev_device->devtype == NULL) - return -ENOMEM; - udev_device->devtype_set = true; - udev_device_add_property(udev_device, "DEVTYPE", udev_device->devtype); - return 0; -} - -static int udev_device_set_subsystem(struct udev_device *udev_device, const char *subsystem) -{ - free(udev_device->subsystem); - udev_device->subsystem = strdup(subsystem); - if (udev_device->subsystem == NULL) - return -ENOMEM; - udev_device->subsystem_set = true; - udev_device_add_property(udev_device, "SUBSYSTEM", udev_device->subsystem); - return 0; -} - -/** - * udev_device_get_subsystem: - * @udev_device: udev device - * - * Retrieve the subsystem string of the udev device. The string does not - * contain any "/". - * - * Returns: the subsystem name of the udev device, or #NULL if it can not be determined - **/ -UDEV_EXPORT const char *udev_device_get_subsystem(struct udev_device *udev_device) -{ - char subsystem[UTIL_NAME_SIZE]; - - if (udev_device == NULL) - return NULL; - if (!udev_device->subsystem_set) { - udev_device->subsystem_set = true; - /* read "subsystem" link */ - if (util_get_sys_core_link_value(udev_device->udev, "subsystem", udev_device->syspath, subsystem, sizeof(subsystem)) > 0) { - udev_device_set_subsystem(udev_device, subsystem); - return udev_device->subsystem; - } - /* implicit names */ - if (strncmp(udev_device->devpath, "/module/", 8) == 0) { - udev_device_set_subsystem(udev_device, "module"); - return udev_device->subsystem; - } - if (strstr(udev_device->devpath, "/drivers/") != NULL) { - udev_device_set_subsystem(udev_device, "drivers"); - return udev_device->subsystem; - } - if (strncmp(udev_device->devpath, "/subsystem/", 11) == 0 || - strncmp(udev_device->devpath, "/class/", 7) == 0 || - strncmp(udev_device->devpath, "/bus/", 5) == 0) { - udev_device_set_subsystem(udev_device, "subsystem"); - return udev_device->subsystem; - } - } - return udev_device->subsystem; -} - -mode_t udev_device_get_devnode_mode(struct udev_device *udev_device) -{ - if (!udev_device->info_loaded) - udev_device_read_uevent_file(udev_device); - return udev_device->devnode_mode; -} - -static int udev_device_set_devnode_mode(struct udev_device *udev_device, mode_t mode) -{ - char num[32]; - - udev_device->devnode_mode = mode; - snprintf(num, sizeof(num), "%#o", mode); - udev_device_add_property(udev_device, "DEVMODE", num); - return 0; -} - -struct udev_list_entry *udev_device_add_property(struct udev_device *udev_device, const char *key, const char *value) -{ - udev_device->envp_uptodate = false; - if (value == NULL) { - struct udev_list_entry *list_entry; - - list_entry = udev_device_get_properties_list_entry(udev_device); - list_entry = udev_list_entry_get_by_name(list_entry, key); - if (list_entry != NULL) - udev_list_entry_delete(list_entry); - return NULL; - } - return udev_list_entry_add(&udev_device->properties_list, key, value); -} - -static struct udev_list_entry *udev_device_add_property_from_string(struct udev_device *udev_device, const char *property) -{ - char name[UTIL_LINE_SIZE]; - char *val; - - util_strscpy(name, sizeof(name), property); - val = strchr(name, '='); - if (val == NULL) - return NULL; - val[0] = '\0'; - val = &val[1]; - if (val[0] == '\0') - val = NULL; - return udev_device_add_property(udev_device, name, val); -} - -/* - * parse property string, and if needed, update internal values accordingly - * - * udev_device_add_property_from_string_parse_finish() needs to be - * called after adding properties, and its return value checked - * - * udev_device_set_info_loaded() needs to be set, to avoid trying - * to use a device without a DEVPATH set - */ -void udev_device_add_property_from_string_parse(struct udev_device *udev_device, const char *property) -{ - if (strncmp(property, "DEVPATH=", 8) == 0) { - char path[UTIL_PATH_SIZE]; - - util_strscpyl(path, sizeof(path), udev_get_sys_path(udev_device->udev), &property[8], NULL); - udev_device_set_syspath(udev_device, path); - } else if (strncmp(property, "SUBSYSTEM=", 10) == 0) { - udev_device_set_subsystem(udev_device, &property[10]); - } else if (strncmp(property, "DEVTYPE=", 8) == 0) { - udev_device_set_devtype(udev_device, &property[8]); - } else if (strncmp(property, "DEVNAME=", 8) == 0) { - udev_device_set_devnode(udev_device, &property[8]); - } else if (strncmp(property, "DEVLINKS=", 9) == 0) { - char devlinks[UTIL_PATH_SIZE]; - char *slink; - char *next; - - util_strscpy(devlinks, sizeof(devlinks), &property[9]); - slink = devlinks; - next = strchr(slink, ' '); - while (next != NULL) { - next[0] = '\0'; - udev_device_add_devlink(udev_device, slink, 0); - slink = &next[1]; - next = strchr(slink, ' '); - } - if (slink[0] != '\0') - udev_device_add_devlink(udev_device, slink, 0); - } else if (strncmp(property, "TAGS=", 5) == 0) { - char tags[UTIL_PATH_SIZE]; - char *next; - - util_strscpy(tags, sizeof(tags), &property[5]); - next = strchr(tags, ':'); - if (next != NULL) { - next++; - while (next[0] != '\0') { - char *tag; - - tag = next; - next = strchr(tag, ':'); - if (next == NULL) - break; - next[0] = '\0'; - next++; - udev_device_add_tag(udev_device, tag); - } - } - } else if (strncmp(property, "USEC_INITIALIZED=", 19) == 0) { - udev_device_set_usec_initialized(udev_device, strtoull(&property[19], NULL, 10)); - } else if (strncmp(property, "DRIVER=", 7) == 0) { - udev_device_set_driver(udev_device, &property[7]); - } else if (strncmp(property, "ACTION=", 7) == 0) { - udev_device_set_action(udev_device, &property[7]); - } else if (strncmp(property, "MAJOR=", 6) == 0) { - udev_device->maj = strtoull(&property[6], NULL, 10); - } else if (strncmp(property, "MINOR=", 6) == 0) { - udev_device->min = strtoull(&property[6], NULL, 10); - } else if (strncmp(property, "DEVPATH_OLD=", 12) == 0) { - udev_device_set_devpath_old(udev_device, &property[12]); - } else if (strncmp(property, "SEQNUM=", 7) == 0) { - udev_device_set_seqnum(udev_device, strtoull(&property[7], NULL, 10)); - } else if (strncmp(property, "IFINDEX=", 8) == 0) { - udev_device_set_ifindex(udev_device, strtoull(&property[8], NULL, 10)); - } else if (strncmp(property, "DEVMODE=", 8) == 0) { - udev_device_set_devnode_mode(udev_device, strtoul(&property[8], NULL, 8)); - } else { - udev_device_add_property_from_string(udev_device, property); - } -} - -int udev_device_add_property_from_string_parse_finish(struct udev_device *udev_device) -{ - if (udev_device->maj > 0) - udev_device_set_devnum(udev_device, makedev(udev_device->maj, udev_device->min)); - udev_device->maj = 0; - udev_device->min = 0; - - if (udev_device->devpath == NULL || udev_device->subsystem == NULL) - return -EINVAL; - return 0; -} - -/** - * udev_device_get_property_value: - * @udev_device: udev device - * @key: property name - * - * Returns: the value of a device property, or #NULL if there is no such property. - **/ -UDEV_EXPORT const char *udev_device_get_property_value(struct udev_device *udev_device, const char *key) -{ - struct udev_list_entry *list_entry; - - if (udev_device == NULL) - return NULL; - if (key == NULL) - return NULL; - - list_entry = udev_device_get_properties_list_entry(udev_device); - list_entry = udev_list_entry_get_by_name(list_entry, key); - return udev_list_entry_get_value(list_entry); -} - -int udev_device_read_db(struct udev_device *udev_device, const char *dbfile) -{ - char filename[UTIL_PATH_SIZE]; - char line[UTIL_LINE_SIZE]; - FILE *f; - - /* providing a database file will always force-load it */ - if (dbfile == NULL) { - const char *id; - - if (udev_device->db_loaded) - return 0; - udev_device->db_loaded = true; - - id = udev_device_get_id_filename(udev_device); - if (id == NULL) - return -1; - util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev_device->udev), "/data/", id, NULL); - dbfile = filename; - } - - f = fopen(dbfile, "re"); - if (f == NULL) { - info(udev_device->udev, "no db file to read %s: %m\n", dbfile); - return -1; - } - udev_device->is_initialized = true; - - while (fgets(line, sizeof(line), f)) { - ssize_t len; - const char *val; - struct udev_list_entry *entry; - - len = strlen(line); - if (len < 4) - break; - line[len-1] = '\0'; - val = &line[2]; - switch(line[0]) { - case 'S': - util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev_device->udev), "/", val, NULL); - udev_device_add_devlink(udev_device, filename, 0); - break; - case 'L': - udev_device_set_devlink_priority(udev_device, atoi(val)); - break; - case 'E': - entry = udev_device_add_property_from_string(udev_device, val); - udev_list_entry_set_num(entry, true); - break; - case 'G': - udev_device_add_tag(udev_device, val); - break; - case 'W': - udev_device_set_watch_handle(udev_device, atoi(val)); - break; - case 'I': - udev_device_set_usec_initialized(udev_device, strtoull(val, NULL, 10)); - break; - } - } - fclose(f); - - info(udev_device->udev, "device %p filled with db file data\n", udev_device); - return 0; -} - -int udev_device_read_uevent_file(struct udev_device *udev_device) -{ - char filename[UTIL_PATH_SIZE]; - FILE *f; - char line[UTIL_LINE_SIZE]; - int maj = 0; - int min = 0; - - if (udev_device->uevent_loaded) - return 0; - - util_strscpyl(filename, sizeof(filename), udev_device->syspath, "/uevent", NULL); - f = fopen(filename, "re"); - if (f == NULL) - return -1; - udev_device->uevent_loaded = true; - - while (fgets(line, sizeof(line), f)) { - char *pos; - - pos = strchr(line, '\n'); - if (pos == NULL) - continue; - pos[0] = '\0'; - - if (strncmp(line, "DEVTYPE=", 8) == 0) - udev_device_set_devtype(udev_device, &line[8]); - else if (strncmp(line, "MAJOR=", 6) == 0) - maj = strtoull(&line[6], NULL, 10); - else if (strncmp(line, "MINOR=", 6) == 0) - min = strtoull(&line[6], NULL, 10); - else if (strncmp(line, "IFINDEX=", 8) == 0) - udev_device_set_ifindex(udev_device, strtoull(&line[8], NULL, 10)); - else if (strncmp(line, "DEVNAME=", 8) == 0) - udev_device_set_devnode(udev_device, &line[8]); - else if (strncmp(line, "DEVMODE=", 8) == 0) - udev_device->devnode_mode = strtoul(&line[8], NULL, 8); - - udev_device_add_property_from_string(udev_device, line); - } - - udev_device->devnum = makedev(maj, min); - fclose(f); - return 0; -} - -void udev_device_set_info_loaded(struct udev_device *device) -{ - device->info_loaded = true; -} - -struct udev_device *udev_device_new(struct udev *udev) -{ - struct udev_device *udev_device; - struct udev_list_entry *list_entry; - - if (udev == NULL) - return NULL; - - udev_device = calloc(1, sizeof(struct udev_device)); - if (udev_device == NULL) - return NULL; - udev_device->refcount = 1; - udev_device->udev = udev; - udev_list_init(udev, &udev_device->devlinks_list, true); - udev_list_init(udev, &udev_device->properties_list, true); - udev_list_init(udev, &udev_device->sysattr_value_list, true); - udev_list_init(udev, &udev_device->sysattr_list, false); - udev_list_init(udev, &udev_device->tags_list, true); - udev_device->watch_handle = -1; - /* copy global properties */ - udev_list_entry_foreach(list_entry, udev_get_properties_list_entry(udev)) - udev_device_add_property(udev_device, - udev_list_entry_get_name(list_entry), - udev_list_entry_get_value(list_entry)); - dbg(udev_device->udev, "udev_device: %p created\n", udev_device); - return udev_device; -} - -/** - * udev_device_new_from_syspath: - * @udev: udev library context - * @syspath: sys device path including sys directory - * - * Create new udev device, and fill in information from the sys - * device and the udev database entry. The syspath is the absolute - * path to the device, including the sys mount point. - * - * The initial refcount is 1, and needs to be decremented to - * release the resources of the udev device. - * - * Returns: a new udev device, or #NULL, if it does not exist - **/ -UDEV_EXPORT struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *syspath) -{ - size_t len; - const char *subdir; - char path[UTIL_PATH_SIZE]; - char *pos; - struct stat statbuf; - struct udev_device *udev_device; - - if (udev == NULL) - return NULL; - if (syspath == NULL) - return NULL; - - /* path starts in sys */ - len = strlen(udev_get_sys_path(udev)); - if (strncmp(syspath, udev_get_sys_path(udev), len) != 0) { - info(udev, "not in sys :%s\n", syspath); - return NULL; - } - - /* path is not a root directory */ - subdir = &syspath[len+1]; - pos = strrchr(subdir, '/'); - if (pos == NULL || pos[1] == '\0' || pos < &subdir[2]) { - dbg(udev, "not a subdir :%s\n", syspath); - return NULL; - } - - /* resolve possible symlink to real path */ - util_strscpy(path, sizeof(path), syspath); - util_resolve_sys_link(udev, path, sizeof(path)); - - if (strncmp(&path[len], "/devices/", 9) == 0) { - char file[UTIL_PATH_SIZE]; - - /* all "devices" require a "uevent" file */ - util_strscpyl(file, sizeof(file), path, "/uevent", NULL); - if (stat(file, &statbuf) != 0) { - dbg(udev, "not a device: %s\n", syspath); - return NULL; - } - } else { - /* everything else just needs to be a directory */ - if (stat(path, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode)) { - dbg(udev, "directory not found: %s\n", syspath); - return NULL; - } - } - - udev_device = udev_device_new(udev); - if (udev_device == NULL) - return NULL; - - udev_device_set_syspath(udev_device, path); - info(udev, "device %p has devpath '%s'\n", udev_device, udev_device_get_devpath(udev_device)); - - return udev_device; -} - -/** - * udev_device_new_from_devnum: - * @udev: udev library context - * @type: char or block device - * @devnum: device major/minor number - * - * Create new udev device, and fill in information from the sys - * device and the udev database entry. The device is looked-up - * by its major/minor number and type. Character and block device - * numbers are not unique across the two types. - * - * The initial refcount is 1, and needs to be decremented to - * release the resources of the udev device. - * - * Returns: a new udev device, or #NULL, if it does not exist - **/ -UDEV_EXPORT struct udev_device *udev_device_new_from_devnum(struct udev *udev, char type, dev_t devnum) -{ - char path[UTIL_PATH_SIZE]; - const char *type_str; - - if (type == 'b') - type_str = "block"; - else if (type == 'c') - type_str = "char"; - else - return NULL; - - /* use /sys/dev/{block,char}/<maj>:<min> link */ - snprintf(path, sizeof(path), "%s/dev/%s/%u:%u", - udev_get_sys_path(udev), type_str, major(devnum), minor(devnum)); - return udev_device_new_from_syspath(udev, path); -} - -struct udev_device *udev_device_new_from_id_filename(struct udev *udev, char *id) -{ - char type; - int maj, min; - char subsys[UTIL_PATH_SIZE]; - char *sysname; - - switch(id[0]) { - case 'b': - case 'c': - if (sscanf(id, "%c%i:%i", &type, &maj, &min) != 3) - return NULL; - return udev_device_new_from_devnum(udev, type, makedev(maj, min)); - case 'n': { - int sk; - struct ifreq ifr; - struct udev_device *dev; - int ifindex; - - ifindex = strtoul(&id[1], NULL, 10); - if (ifindex <= 0) - return NULL; - - sk = socket(PF_INET, SOCK_DGRAM, 0); - if (sk < 0) - return NULL; - memset(&ifr, 0x00, sizeof(struct ifreq)); - ifr.ifr_ifindex = ifindex; - if (ioctl(sk, SIOCGIFNAME, &ifr) != 0) { - close(sk); - return NULL; - } - close(sk); - - dev = udev_device_new_from_subsystem_sysname(udev, "net", ifr.ifr_name); - if (dev == NULL) - return NULL; - if (udev_device_get_ifindex(dev) == ifindex) - return dev; - udev_device_unref(dev); - return NULL; - } - case '+': - util_strscpy(subsys, sizeof(subsys), &id[1]); - sysname = strchr(subsys, ':'); - if (sysname == NULL) - return NULL; - sysname[0] = '\0'; - sysname = &sysname[1]; - return udev_device_new_from_subsystem_sysname(udev, subsys, sysname); - default: - return NULL; - } -} - -/** - * udev_device_new_from_subsystem_sysname: - * @udev: udev library context - * @subsystem: the subsystem of the device - * @sysname: the name of the device - * - * Create new udev device, and fill in information from the sys device - * and the udev database entry. The device is looked up by the subsystem - * and name string of the device, like "mem" / "zero", or "block" / "sda". - * - * The initial refcount is 1, and needs to be decremented to - * release the resources of the udev device. - * - * Returns: a new udev device, or #NULL, if it does not exist - **/ -UDEV_EXPORT struct udev_device *udev_device_new_from_subsystem_sysname(struct udev *udev, const char *subsystem, const char *sysname) -{ - char path_full[UTIL_PATH_SIZE]; - char *path; - size_t l; - struct stat statbuf; - - path = path_full; - l = util_strpcpyl(&path, sizeof(path_full), udev_get_sys_path(udev), NULL); - - if (strcmp(subsystem, "subsystem") == 0) { - util_strscpyl(path, l, "/subsystem/", sysname, NULL); - if (stat(path_full, &statbuf) == 0) - goto found; - - util_strscpyl(path, l, "/bus/", sysname, NULL); - if (stat(path_full, &statbuf) == 0) - goto found; - - util_strscpyl(path, l, "/class/", sysname, NULL); - if (stat(path_full, &statbuf) == 0) - goto found; - goto out; - } - - if (strcmp(subsystem, "module") == 0) { - util_strscpyl(path, l, "/module/", sysname, NULL); - if (stat(path_full, &statbuf) == 0) - goto found; - goto out; - } - - if (strcmp(subsystem, "drivers") == 0) { - char subsys[UTIL_NAME_SIZE]; - char *driver; - - util_strscpy(subsys, sizeof(subsys), sysname); - driver = strchr(subsys, ':'); - if (driver != NULL) { - driver[0] = '\0'; - driver = &driver[1]; - - util_strscpyl(path, l, "/subsystem/", subsys, "/drivers/", driver, NULL); - if (stat(path_full, &statbuf) == 0) - goto found; - - util_strscpyl(path, l, "/bus/", subsys, "/drivers/", driver, NULL); - if (stat(path_full, &statbuf) == 0) - goto found; - } - goto out; - } - - util_strscpyl(path, l, "/subsystem/", subsystem, "/devices/", sysname, NULL); - if (stat(path_full, &statbuf) == 0) - goto found; - - util_strscpyl(path, l, "/bus/", subsystem, "/devices/", sysname, NULL); - if (stat(path_full, &statbuf) == 0) - goto found; - - util_strscpyl(path, l, "/class/", subsystem, "/", sysname, NULL); - if (stat(path_full, &statbuf) == 0) - goto found; -out: - return NULL; -found: - return udev_device_new_from_syspath(udev, path_full); -} - -/** - * udev_device_new_from_environment - * @udev: udev library context - * - * Create new udev device, and fill in information from the - * current process environment. This only works reliable if - * the process is called from a udev rule. It is usually used - * for tools executed from IMPORT= rules. - * - * The initial refcount is 1, and needs to be decremented to - * release the resources of the udev device. - * - * Returns: a new udev device, or #NULL, if it does not exist - **/ -UDEV_EXPORT struct udev_device *udev_device_new_from_environment(struct udev *udev) -{ - int i; - struct udev_device *udev_device; - - udev_device = udev_device_new(udev); - if (udev_device == NULL) - return NULL; - udev_device_set_info_loaded(udev_device); - - for (i = 0; environ[i] != NULL; i++) - udev_device_add_property_from_string_parse(udev_device, environ[i]); - - if (udev_device_add_property_from_string_parse_finish(udev_device) < 0) { - info(udev, "missing values, invalid device\n"); - udev_device_unref(udev_device); - udev_device = NULL; - } - - return udev_device; -} - -static struct udev_device *device_new_from_parent(struct udev_device *udev_device) -{ - struct udev_device *udev_device_parent = NULL; - char path[UTIL_PATH_SIZE]; - const char *subdir; - - util_strscpy(path, sizeof(path), udev_device->syspath); - subdir = &path[strlen(udev_get_sys_path(udev_device->udev))+1]; - for (;;) { - char *pos; - - pos = strrchr(subdir, '/'); - if (pos == NULL || pos < &subdir[2]) - break; - pos[0] = '\0'; - udev_device_parent = udev_device_new_from_syspath(udev_device->udev, path); - if (udev_device_parent != NULL) - return udev_device_parent; - } - return NULL; -} - -/** - * udev_device_get_parent: - * @udev_device: the device to start searching from - * - * Find the next parent device, and fill in information from the sys - * device and the udev database entry. - * - * The returned the device is not referenced. It is attached to the - * child device, and will be cleaned up when the child device - * is cleaned up. - * - * It is not necessarily just the upper level directory, empty or not - * recognized sys directories are ignored. - * - * It can be called as many times as needed, without caring about - * references. - * - * Returns: a new udev device, or #NULL, if it no parent exist. - **/ -UDEV_EXPORT struct udev_device *udev_device_get_parent(struct udev_device *udev_device) -{ - if (udev_device == NULL) - return NULL; - if (!udev_device->parent_set) { - udev_device->parent_set = true; - udev_device->parent_device = device_new_from_parent(udev_device); - } - if (udev_device->parent_device != NULL) - dbg(udev_device->udev, "returning existing parent %p\n", udev_device->parent_device); - return udev_device->parent_device; -} - -/** - * udev_device_get_parent_with_subsystem_devtype: - * @udev_device: udev device to start searching from - * @subsystem: the subsystem of the device - * @devtype: the type (DEVTYPE) of the device - * - * Find the next parent device, with a matching subsystem and devtype - * value, and fill in information from the sys device and the udev - * database entry. - * - * If devtype is #NULL, only subsystem is checked, and any devtype will - * match. - * - * The returned the device is not referenced. It is attached to the - * child device, and will be cleaned up when the child device - * is cleaned up. - * - * It can be called as many times as needed, without caring about - * references. - * - * Returns: a new udev device, or #NULL if no matching parent exists. - **/ -UDEV_EXPORT struct udev_device *udev_device_get_parent_with_subsystem_devtype(struct udev_device *udev_device, const char *subsystem, const char *devtype) -{ - struct udev_device *parent; - - if (subsystem == NULL) - return NULL; - - parent = udev_device_get_parent(udev_device); - while (parent != NULL) { - const char *parent_subsystem; - const char *parent_devtype; - - parent_subsystem = udev_device_get_subsystem(parent); - if (parent_subsystem != NULL && strcmp(parent_subsystem, subsystem) == 0) { - if (devtype == NULL) - break; - parent_devtype = udev_device_get_devtype(parent); - if (parent_devtype != NULL && strcmp(parent_devtype, devtype) == 0) - break; - } - parent = udev_device_get_parent(parent); - } - return parent; -} - -/** - * udev_device_get_udev: - * @udev_device: udev device - * - * Retrieve the udev library context the device was created with. - * - * Returns: the udev library context - **/ -UDEV_EXPORT struct udev *udev_device_get_udev(struct udev_device *udev_device) -{ - if (udev_device == NULL) - return NULL; - return udev_device->udev; -} - -/** - * udev_device_ref: - * @udev_device: udev device - * - * Take a reference of a udev device. - * - * Returns: the passed udev device - **/ -UDEV_EXPORT struct udev_device *udev_device_ref(struct udev_device *udev_device) -{ - if (udev_device == NULL) - return NULL; - udev_device->refcount++; - return udev_device; -} - -/** - * udev_device_unref: - * @udev_device: udev device - * - * Drop a reference of a udev device. If the refcount reaches zero, - * the resources of the device will be released. - * - **/ -UDEV_EXPORT void udev_device_unref(struct udev_device *udev_device) -{ - if (udev_device == NULL) - return; - udev_device->refcount--; - if (udev_device->refcount > 0) - return; - if (udev_device->parent_device != NULL) - udev_device_unref(udev_device->parent_device); - free(udev_device->syspath); - free(udev_device->sysname); - free(udev_device->devnode); - free(udev_device->subsystem); - free(udev_device->devtype); - udev_list_cleanup(&udev_device->devlinks_list); - udev_list_cleanup(&udev_device->properties_list); - udev_list_cleanup(&udev_device->sysattr_value_list); - udev_list_cleanup(&udev_device->sysattr_list); - udev_list_cleanup(&udev_device->tags_list); - free(udev_device->action); - free(udev_device->driver); - free(udev_device->devpath_old); - free(udev_device->id_filename); - free(udev_device->envp); - free(udev_device->monitor_buf); - dbg(udev_device->udev, "udev_device: %p released\n", udev_device); - free(udev_device); -} - -/** - * udev_device_get_devpath: - * @udev_device: udev device - * - * Retrieve the kernel devpath value of the udev device. The path - * does not contain the sys mount point, and starts with a '/'. - * - * Returns: the devpath of the udev device - **/ -UDEV_EXPORT const char *udev_device_get_devpath(struct udev_device *udev_device) -{ - if (udev_device == NULL) - return NULL; - return udev_device->devpath; -} - -/** - * udev_device_get_syspath: - * @udev_device: udev device - * - * Retrieve the sys path of the udev device. The path is an - * absolute path and starts with the sys mount point. - * - * Returns: the sys path of the udev device - **/ -UDEV_EXPORT const char *udev_device_get_syspath(struct udev_device *udev_device) -{ - if (udev_device == NULL) - return NULL; - return udev_device->syspath; -} - -/** - * udev_device_get_sysname: - * @udev_device: udev device - * - * Returns: the sys name of the device device - **/ -UDEV_EXPORT const char *udev_device_get_sysname(struct udev_device *udev_device) -{ - if (udev_device == NULL) - return NULL; - return udev_device->sysname; -} - -/** - * udev_device_get_sysnum: - * @udev_device: udev device - * - * Returns: the trailing number of of the device name - **/ -UDEV_EXPORT const char *udev_device_get_sysnum(struct udev_device *udev_device) -{ - if (udev_device == NULL) - return NULL; - return udev_device->sysnum; -} - -/** - * udev_device_get_devnode: - * @udev_device: udev device - * - * Retrieve the device node file name belonging to the udev device. - * The path is an absolute path, and starts with the device directory. - * - * Returns: the device node file name of the udev device, or #NULL if no device node exists - **/ -UDEV_EXPORT const char *udev_device_get_devnode(struct udev_device *udev_device) -{ - if (udev_device == NULL) - return NULL; - if (udev_device->devnode != NULL) - return udev_device->devnode; - if (!udev_device->info_loaded) - udev_device_read_uevent_file(udev_device); - return udev_device->devnode; -} - -/** - * udev_device_get_devlinks_list_entry: - * @udev_device: udev device - * - * Retrieve the list of device links pointing to the device file of - * the udev device. The next list entry can be retrieved with - * udev_list_entry_next(), which returns #NULL if no more entries exist. - * The devlink path can be retrieved from the list entry by - * udev_list_entry_get_name(). The path is an absolute path, and starts with - * the device directory. - * - * Returns: the first entry of the device node link list - **/ -UDEV_EXPORT struct udev_list_entry *udev_device_get_devlinks_list_entry(struct udev_device *udev_device) -{ - if (udev_device == NULL) - return NULL; - if (!udev_device->info_loaded) - udev_device_read_db(udev_device, NULL); - return udev_list_get_entry(&udev_device->devlinks_list); -} - -void udev_device_cleanup_devlinks_list(struct udev_device *udev_device) -{ - udev_device->devlinks_uptodate = false; - udev_list_cleanup(&udev_device->devlinks_list); -} - -/** - * udev_device_get_properties_list_entry: - * @udev_device: udev device - * - * Retrieve the list of key/value device properties of the udev - * device. The next list entry can be retrieved with udev_list_entry_next(), - * which returns #NULL if no more entries exist. The property name - * can be retrieved from the list entry by udev_list_get_name(), - * the property value by udev_list_get_value(). - * - * Returns: the first entry of the property list - **/ -UDEV_EXPORT struct udev_list_entry *udev_device_get_properties_list_entry(struct udev_device *udev_device) -{ - if (udev_device == NULL) - return NULL; - if (!udev_device->info_loaded) { - udev_device_read_uevent_file(udev_device); - udev_device_read_db(udev_device, NULL); - } - if (!udev_device->devlinks_uptodate) { - char symlinks[UTIL_PATH_SIZE]; - struct udev_list_entry *list_entry; - - udev_device->devlinks_uptodate = true; - list_entry = udev_device_get_devlinks_list_entry(udev_device); - if (list_entry != NULL) { - char *s; - size_t l; - - s = symlinks; - l = util_strpcpyl(&s, sizeof(symlinks), udev_list_entry_get_name(list_entry), NULL); - udev_list_entry_foreach(list_entry, udev_list_entry_get_next(list_entry)) - l = util_strpcpyl(&s, l, " ", udev_list_entry_get_name(list_entry), NULL); - udev_device_add_property(udev_device, "DEVLINKS", symlinks); - } - } - if (!udev_device->tags_uptodate) { - udev_device->tags_uptodate = true; - if (udev_device_get_tags_list_entry(udev_device) != NULL) { - char tags[UTIL_PATH_SIZE]; - struct udev_list_entry *list_entry; - char *s; - size_t l; - - s = tags; - l = util_strpcpyl(&s, sizeof(tags), ":", NULL); - udev_list_entry_foreach(list_entry, udev_device_get_tags_list_entry(udev_device)) - l = util_strpcpyl(&s, l, udev_list_entry_get_name(list_entry), ":", NULL); - udev_device_add_property(udev_device, "TAGS", tags); - } - } - return udev_list_get_entry(&udev_device->properties_list); -} - -/** - * udev_device_get_action: - * @udev_device: udev device - * - * This is only valid if the device was received through a monitor. Devices read from - * sys do not have an action string. Usual actions are: add, remove, change, online, - * offline. - * - * Returns: the kernel action value, or #NULL if there is no action value available. - **/ -UDEV_EXPORT const char *udev_device_get_action(struct udev_device *udev_device) -{ - if (udev_device == NULL) - return NULL; - return udev_device->action; -} - -/** - * udev_device_get_usec_since_initialized: - * @udev_device: udev device - * - * Return the number of microseconds passed since udev set up the - * device for the first time. - * - * This is only implemented for devices with need to store properties - * in the udev database. All other devices return 0 here. - * - * Returns: the number of microseconds since the device was first seen. - **/ -UDEV_EXPORT unsigned long long int udev_device_get_usec_since_initialized(struct udev_device *udev_device) -{ - unsigned long long now; - - if (udev_device == NULL) - return 0; - if (!udev_device->info_loaded) - udev_device_read_db(udev_device, NULL); - if (udev_device->usec_initialized == 0) - return 0; - now = now_usec(); - if (now == 0) - return 0; - return now - udev_device->usec_initialized; -} - -unsigned long long udev_device_get_usec_initialized(struct udev_device *udev_device) -{ - return udev_device->usec_initialized; -} - -void udev_device_set_usec_initialized(struct udev_device *udev_device, unsigned long long usec_initialized) -{ - char num[32]; - - udev_device->usec_initialized = usec_initialized; - snprintf(num, sizeof(num), "%llu", usec_initialized); - udev_device_add_property(udev_device, "USEC_INITIALIZED", num); -} - -/** - * udev_device_get_sysattr_value: - * @udev_device: udev device - * @sysattr: attribute name - * - * The retrieved value is cached in the device. Repeated calls will return the same - * value and not open the attribute again. - * - * Returns: the content of a sys attribute file, or #NULL if there is no sys attribute value. - **/ -UDEV_EXPORT const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const char *sysattr) -{ - struct udev_list_entry *list_entry; - char path[UTIL_PATH_SIZE]; - char value[4096]; - struct stat statbuf; - int fd; - ssize_t size; - const char *val = NULL; - - if (udev_device == NULL) - return NULL; - if (sysattr == NULL) - return NULL; - - /* look for possibly already cached result */ - list_entry = udev_list_get_entry(&udev_device->sysattr_value_list); - list_entry = udev_list_entry_get_by_name(list_entry, sysattr); - if (list_entry != NULL) { - dbg(udev_device->udev, "got '%s' (%s) from cache\n", - sysattr, udev_list_entry_get_value(list_entry)); - return udev_list_entry_get_value(list_entry); - } - - util_strscpyl(path, sizeof(path), udev_device_get_syspath(udev_device), "/", sysattr, NULL); - if (lstat(path, &statbuf) != 0) { - dbg(udev_device->udev, "no attribute '%s', keep negative entry\n", path); - udev_list_entry_add(&udev_device->sysattr_value_list, sysattr, NULL); - goto out; - } - - if (S_ISLNK(statbuf.st_mode)) { - struct udev_device *dev; - - /* - * Some core links return only the last element of the target path, - * these are just values, the paths should not be exposed. - */ - if (strcmp(sysattr, "driver") == 0 || - strcmp(sysattr, "subsystem") == 0 || - strcmp(sysattr, "module") == 0) { - if (util_get_sys_core_link_value(udev_device->udev, sysattr, - udev_device->syspath, value, sizeof(value)) < 0) - return NULL; - dbg(udev_device->udev, "cache '%s' with link value '%s'\n", sysattr, value); - list_entry = udev_list_entry_add(&udev_device->sysattr_value_list, sysattr, value); - val = udev_list_entry_get_value(list_entry); - goto out; - } - - /* resolve link to a device and return its syspath */ - util_strscpyl(path, sizeof(path), udev_device->syspath, "/", sysattr, NULL); - dev = udev_device_new_from_syspath(udev_device->udev, path); - if (dev != NULL) { - list_entry = udev_list_entry_add(&udev_device->sysattr_value_list, sysattr, - udev_device_get_syspath(dev)); - val = udev_list_entry_get_value(list_entry); - udev_device_unref(dev); - } - - goto out; - } - - /* skip directories */ - if (S_ISDIR(statbuf.st_mode)) - goto out; - - /* skip non-readable files */ - if ((statbuf.st_mode & S_IRUSR) == 0) - goto out; - - /* read attribute value */ - fd = open(path, O_RDONLY|O_CLOEXEC); - if (fd < 0) { - dbg(udev_device->udev, "attribute '%s' can not be opened\n", path); - goto out; - } - size = read(fd, value, sizeof(value)); - close(fd); - if (size < 0) - goto out; - if (size == sizeof(value)) - goto out; - - /* got a valid value, store it in cache and return it */ - value[size] = '\0'; - util_remove_trailing_chars(value, '\n'); - dbg(udev_device->udev, "'%s' has attribute value '%s'\n", path, value); - list_entry = udev_list_entry_add(&udev_device->sysattr_value_list, sysattr, value); - val = udev_list_entry_get_value(list_entry); -out: - return val; -} - -static int udev_device_sysattr_list_read(struct udev_device *udev_device) -{ - struct dirent *dent; - DIR *dir; - int num = 0; - - if (udev_device == NULL) - return -1; - if (udev_device->sysattr_list_read) - return 0; - - dir = opendir(udev_device_get_syspath(udev_device)); - if (!dir) { - dbg(udev_device->udev, "sysfs dir '%s' can not be opened\n", - udev_device_get_syspath(udev_device)); - return -1; - } - - for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { - char path[UTIL_PATH_SIZE]; - struct stat statbuf; - - /* only handle symlinks and regular files */ - if (dent->d_type != DT_LNK && dent->d_type != DT_REG) - continue; - - util_strscpyl(path, sizeof(path), udev_device_get_syspath(udev_device), "/", dent->d_name, NULL); - if (lstat(path, &statbuf) != 0) - continue; - if ((statbuf.st_mode & S_IRUSR) == 0) - continue; - - udev_list_entry_add(&udev_device->sysattr_list, dent->d_name, NULL); - num++; - } - - closedir(dir); - dbg(udev_device->udev, "found %d sysattrs for '%s'\n", num, udev_device_get_syspath(udev_device)); - udev_device->sysattr_list_read = true; - - return num; -} - -/** - * udev_device_get_sysattr_list_entry: - * @udev_device: udev device - * - * Retrieve the list of available sysattrs, with value being empty; - * This just return all available sysfs attributes for a particular - * device without reading their values. - * - * Returns: the first entry of the property list - **/ -UDEV_EXPORT struct udev_list_entry *udev_device_get_sysattr_list_entry(struct udev_device *udev_device) -{ - if (!udev_device->sysattr_list_read) { - int ret; - ret = udev_device_sysattr_list_read(udev_device); - if (0 > ret) - return NULL; - } - - return udev_list_get_entry(&udev_device->sysattr_list); -} - -int udev_device_set_syspath(struct udev_device *udev_device, const char *syspath) -{ - const char *pos; - size_t len; - - free(udev_device->syspath); - udev_device->syspath = strdup(syspath); - if (udev_device->syspath == NULL) - return -ENOMEM; - udev_device->devpath = &udev_device->syspath[strlen(udev_get_sys_path(udev_device->udev))]; - udev_device_add_property(udev_device, "DEVPATH", udev_device->devpath); - - pos = strrchr(udev_device->syspath, '/'); - if (pos == NULL) - return -EINVAL; - udev_device->sysname = strdup(&pos[1]); - if (udev_device->sysname == NULL) - return -ENOMEM; - - /* some devices have '!' in their name, change that to '/' */ - len = 0; - while (udev_device->sysname[len] != '\0') { - if (udev_device->sysname[len] == '!') - udev_device->sysname[len] = '/'; - len++; - } - - /* trailing number */ - while (len > 0 && isdigit(udev_device->sysname[--len])) - udev_device->sysnum = &udev_device->sysname[len]; - - /* sysname is completely numeric */ - if (len == 0) - udev_device->sysnum = NULL; - - return 0; -} - -int udev_device_set_devnode(struct udev_device *udev_device, const char *devnode) -{ - free(udev_device->devnode); - if (devnode[0] != '/') { - if (asprintf(&udev_device->devnode, "%s/%s", udev_get_dev_path(udev_device->udev), devnode) < 0) - udev_device->devnode = NULL; - } else { - udev_device->devnode = strdup(devnode); - } - if (udev_device->devnode == NULL) - return -ENOMEM; - udev_device_add_property(udev_device, "DEVNAME", udev_device->devnode); - return 0; -} - -int udev_device_add_devlink(struct udev_device *udev_device, const char *devlink, int unique) -{ - struct udev_list_entry *list_entry; - - udev_device->devlinks_uptodate = false; - list_entry = udev_list_entry_add(&udev_device->devlinks_list, devlink, NULL); - if (list_entry == NULL) - return -ENOMEM; - if (unique) - udev_list_entry_set_num(list_entry, true); - return 0; -} - -const char *udev_device_get_id_filename(struct udev_device *udev_device) -{ - if (udev_device->id_filename == NULL) { - if (udev_device_get_subsystem(udev_device) == NULL) - return NULL; - - if (major(udev_device_get_devnum(udev_device)) > 0) { - /* use dev_t -- b259:131072, c254:0 */ - if (asprintf(&udev_device->id_filename, "%c%u:%u", - strcmp(udev_device_get_subsystem(udev_device), "block") == 0 ? 'b' : 'c', - major(udev_device_get_devnum(udev_device)), - minor(udev_device_get_devnum(udev_device))) < 0) - udev_device->id_filename = NULL; - } else if (udev_device_get_ifindex(udev_device) > 0) { - /* use netdev ifindex -- n3 */ - if (asprintf(&udev_device->id_filename, "n%u", udev_device_get_ifindex(udev_device)) < 0) - udev_device->id_filename = NULL; - } else { - /* - * use $subsys:$syname -- pci:0000:00:1f.2 - * sysname() has '!' translated, get it from devpath - */ - const char *sysname; - sysname = strrchr(udev_device->devpath, '/'); - if (sysname == NULL) - return NULL; - sysname = &sysname[1]; - if (asprintf(&udev_device->id_filename, "+%s:%s", udev_device_get_subsystem(udev_device), sysname) < 0) - udev_device->id_filename = NULL; - } - } - return udev_device->id_filename; -} - -/** - * udev_device_get_is_initialized: - * @udev_device: udev device - * - * Check if udev has already handled the device and has set up - * device node permissions and context, or has renamed a network - * device. - * - * This is only implemented for devices with a device node - * or network interfaces. All other devices return 1 here. - * - * Returns: 1 if the device is set up. 0 otherwise. - **/ -UDEV_EXPORT int udev_device_get_is_initialized(struct udev_device *udev_device) -{ - if (!udev_device->info_loaded) - udev_device_read_db(udev_device, NULL); - return udev_device->is_initialized; -} - -void udev_device_set_is_initialized(struct udev_device *udev_device) -{ - udev_device->is_initialized = true; -} - -int udev_device_add_tag(struct udev_device *udev_device, const char *tag) -{ - if (strchr(tag, ':') != NULL || strchr(tag, ' ') != NULL) - return -EINVAL; - udev_device->tags_uptodate = false; - if (udev_list_entry_add(&udev_device->tags_list, tag, NULL) != NULL) - return 0; - return -ENOMEM; -} - -void udev_device_cleanup_tags_list(struct udev_device *udev_device) -{ - udev_device->tags_uptodate = false; - udev_list_cleanup(&udev_device->tags_list); -} - -/** - * udev_device_get_tags_list_entry: - * @udev_device: udev device - * - * Retrieve the list of tags attached to the udev device. The next - * list entry can be retrieved with udev_list_entry_next(), - * which returns #NULL if no more entries exist. The tag string - * can be retrieved from the list entry by udev_list_get_name(). - * - * Returns: the first entry of the tag list - **/ -UDEV_EXPORT struct udev_list_entry *udev_device_get_tags_list_entry(struct udev_device *udev_device) -{ - if (udev_device == NULL) - return NULL; - if (!udev_device->info_loaded) - udev_device_read_db(udev_device, NULL); - return udev_list_get_entry(&udev_device->tags_list); -} - -UDEV_EXPORT int udev_device_has_tag(struct udev_device *udev_device, const char *tag) -{ - struct udev_list_entry *list_entry; - - if (udev_device == NULL) - return false; - if (!udev_device->info_loaded) - udev_device_read_db(udev_device, NULL); - list_entry = udev_device_get_tags_list_entry(udev_device); - if (udev_list_entry_get_by_name(list_entry, tag) != NULL) - return true; - return false; -} - -#define ENVP_SIZE 128 -#define MONITOR_BUF_SIZE 4096 -static int update_envp_monitor_buf(struct udev_device *udev_device) -{ - struct udev_list_entry *list_entry; - char *s; - size_t l; - unsigned int i; - - /* monitor buffer of property strings */ - free(udev_device->monitor_buf); - udev_device->monitor_buf_len = 0; - udev_device->monitor_buf = malloc(MONITOR_BUF_SIZE); - if (udev_device->monitor_buf == NULL) - return -ENOMEM; - - /* envp array, strings will point into monitor buffer */ - if (udev_device->envp == NULL) - udev_device->envp = malloc(sizeof(char *) * ENVP_SIZE); - if (udev_device->envp == NULL) - return -ENOMEM; - - i = 0; - s = udev_device->monitor_buf; - l = MONITOR_BUF_SIZE; - udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(udev_device)) { - const char *key; - - key = udev_list_entry_get_name(list_entry); - /* skip private variables */ - if (key[0] == '.') - continue; - - /* add string to envp array */ - udev_device->envp[i++] = s; - if (i+1 >= ENVP_SIZE) - return -EINVAL; - - /* add property string to monitor buffer */ - l = util_strpcpyl(&s, l, key, "=", udev_list_entry_get_value(list_entry), NULL); - if (l == 0) - return -EINVAL; - /* advance past the trailing '\0' that util_strpcpyl() guarantees */ - s++; - l--; - } - udev_device->envp[i] = NULL; - udev_device->monitor_buf_len = s - udev_device->monitor_buf; - udev_device->envp_uptodate = true; - dbg(udev_device->udev, "filled envp/monitor buffer, %u properties, %zu bytes\n", - i, udev_device->monitor_buf_len); - return 0; -} - -char **udev_device_get_properties_envp(struct udev_device *udev_device) -{ - if (!udev_device->envp_uptodate) - if (update_envp_monitor_buf(udev_device) != 0) - return NULL; - return udev_device->envp; -} - -ssize_t udev_device_get_properties_monitor_buf(struct udev_device *udev_device, const char **buf) -{ - if (!udev_device->envp_uptodate) - if (update_envp_monitor_buf(udev_device) != 0) - return -EINVAL; - *buf = udev_device->monitor_buf; - return udev_device->monitor_buf_len; -} - -int udev_device_set_action(struct udev_device *udev_device, const char *action) -{ - free(udev_device->action); - udev_device->action = strdup(action); - if (udev_device->action == NULL) - return -ENOMEM; - udev_device_add_property(udev_device, "ACTION", udev_device->action); - return 0; -} - -int udev_device_get_devlink_priority(struct udev_device *udev_device) -{ - if (!udev_device->info_loaded) - udev_device_read_db(udev_device, NULL); - return udev_device->devlink_priority; -} - -int udev_device_set_devlink_priority(struct udev_device *udev_device, int prio) -{ - udev_device->devlink_priority = prio; - return 0; -} - -int udev_device_get_watch_handle(struct udev_device *udev_device) -{ - if (!udev_device->info_loaded) - udev_device_read_db(udev_device, NULL); - return udev_device->watch_handle; -} - -int udev_device_set_watch_handle(struct udev_device *udev_device, int handle) -{ - udev_device->watch_handle = handle; - return 0; -} - -bool udev_device_get_db_persist(struct udev_device *udev_device) -{ - return udev_device->db_persist; -} - -void udev_device_set_db_persist(struct udev_device *udev_device) -{ - udev_device->db_persist = true; -} diff --git a/libudev/libudev-enumerate.c b/libudev/libudev-enumerate.c deleted file mode 100644 index f14d5c8f57..0000000000 --- a/libudev/libudev-enumerate.c +++ /dev/null @@ -1,947 +0,0 @@ -/* - * libudev - interface to udev device information - * - * Copyright (C) 2008-2010 Kay Sievers <kay.sievers@vrfy.org> - * - * 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. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <stddef.h> -#include <unistd.h> -#include <errno.h> -#include <string.h> -#include <dirent.h> -#include <fnmatch.h> -#include <stdbool.h> -#include <sys/stat.h> -#include <sys/param.h> - -#include "libudev.h" -#include "libudev-private.h" - -/** - * SECTION:libudev-enumerate - * @short_description: lookup and sort sys devices - * - * Lookup devices in the sys filesystem, filter devices by properties, - * and return a sorted list of devices. - */ - -struct syspath { - char *syspath; - size_t len; -}; - -/** - * udev_enumerate: - * - * Opaque object representing one device lookup/sort context. - */ -struct udev_enumerate { - struct udev *udev; - int refcount; - struct udev_list sysattr_match_list; - struct udev_list sysattr_nomatch_list; - struct udev_list subsystem_match_list; - struct udev_list subsystem_nomatch_list; - struct udev_list sysname_match_list; - struct udev_list properties_match_list; - struct udev_list tags_match_list; - struct udev_device *parent_match; - struct udev_list devices_list; - struct syspath *devices; - unsigned int devices_cur; - unsigned int devices_max; - bool devices_uptodate:1; - bool match_is_initialized; -}; - -/** - * udev_enumerate_new: - * @udev: udev library context - * - * Returns: an enumeration context - **/ -UDEV_EXPORT struct udev_enumerate *udev_enumerate_new(struct udev *udev) -{ - struct udev_enumerate *udev_enumerate; - - udev_enumerate = calloc(1, sizeof(struct udev_enumerate)); - if (udev_enumerate == NULL) - return NULL; - udev_enumerate->refcount = 1; - udev_enumerate->udev = udev; - udev_list_init(udev, &udev_enumerate->sysattr_match_list, false); - udev_list_init(udev, &udev_enumerate->sysattr_nomatch_list, false); - udev_list_init(udev, &udev_enumerate->subsystem_match_list, true); - udev_list_init(udev, &udev_enumerate->subsystem_nomatch_list, true); - udev_list_init(udev, &udev_enumerate->sysname_match_list, true); - udev_list_init(udev, &udev_enumerate->properties_match_list, false); - udev_list_init(udev, &udev_enumerate->tags_match_list, true); - udev_list_init(udev, &udev_enumerate->devices_list, false); - return udev_enumerate; -} - -/** - * udev_enumerate_ref: - * @udev_enumerate: context - * - * Take a reference of a enumeration context. - * - * Returns: the passed enumeration context - **/ -UDEV_EXPORT struct udev_enumerate *udev_enumerate_ref(struct udev_enumerate *udev_enumerate) -{ - if (udev_enumerate == NULL) - return NULL; - udev_enumerate->refcount++; - return udev_enumerate; -} - -/** - * udev_enumerate_unref: - * @udev_enumerate: context - * - * Drop a reference of an enumeration context. If the refcount reaches zero, - * all resources of the enumeration context will be released. - **/ -UDEV_EXPORT void udev_enumerate_unref(struct udev_enumerate *udev_enumerate) -{ - unsigned int i; - - if (udev_enumerate == NULL) - return; - udev_enumerate->refcount--; - if (udev_enumerate->refcount > 0) - return; - udev_list_cleanup(&udev_enumerate->sysattr_match_list); - udev_list_cleanup(&udev_enumerate->sysattr_nomatch_list); - udev_list_cleanup(&udev_enumerate->subsystem_match_list); - udev_list_cleanup(&udev_enumerate->subsystem_nomatch_list); - udev_list_cleanup(&udev_enumerate->sysname_match_list); - udev_list_cleanup(&udev_enumerate->properties_match_list); - udev_list_cleanup(&udev_enumerate->tags_match_list); - udev_device_unref(udev_enumerate->parent_match); - udev_list_cleanup(&udev_enumerate->devices_list); - for (i = 0; i < udev_enumerate->devices_cur; i++) - free(udev_enumerate->devices[i].syspath); - free(udev_enumerate->devices); - free(udev_enumerate); -} - -/** - * udev_enumerate_get_udev: - * @udev_enumerate: context - * - * Returns: the udev library context. - */ -UDEV_EXPORT struct udev *udev_enumerate_get_udev(struct udev_enumerate *udev_enumerate) -{ - if (udev_enumerate == NULL) - return NULL; - return udev_enumerate->udev; -} - -static int syspath_add(struct udev_enumerate *udev_enumerate, const char *syspath) -{ - char *path; - struct syspath *entry; - - /* double array size if needed */ - if (udev_enumerate->devices_cur >= udev_enumerate->devices_max) { - struct syspath *buf; - unsigned int add; - - add = udev_enumerate->devices_max; - if (add < 1024) - add = 1024; - buf = realloc(udev_enumerate->devices, (udev_enumerate->devices_max + add) * sizeof(struct syspath)); - if (buf == NULL) - return -ENOMEM; - udev_enumerate->devices = buf; - udev_enumerate->devices_max += add; - } - - path = strdup(syspath); - if (path == NULL) - return -ENOMEM; - entry = &udev_enumerate->devices[udev_enumerate->devices_cur]; - entry->syspath = path; - entry->len = strlen(path); - udev_enumerate->devices_cur++; - udev_enumerate->devices_uptodate = false; - return 0; -} - -static int syspath_cmp(const void *p1, const void *p2) -{ - const struct syspath *path1 = p1; - const struct syspath *path2 = p2; - size_t len; - int ret; - - len = MIN(path1->len, path2->len); - ret = memcmp(path1->syspath, path2->syspath, len); - if (ret == 0) { - if (path1->len < path2->len) - ret = -1; - else if (path1->len > path2->len) - ret = 1; - } - return ret; -} - -/* For devices that should be moved to the absolute end of the list */ -static bool devices_delay_end(struct udev *udev, const char *syspath) -{ - static const char *delay_device_list[] = { - "/block/md", - "/block/dm-", - NULL - }; - size_t len; - int i; - - len = strlen(udev_get_sys_path(udev)); - for (i = 0; delay_device_list[i] != NULL; i++) { - if (strstr(&syspath[len], delay_device_list[i]) != NULL) { - dbg(udev, "delaying: %s\n", syspath); - return true; - } - } - return false; -} - -/* For devices that should just be moved a little bit later, just - * before the point where some common path prefix changes. Returns the - * number of characters that make up that common prefix */ -static size_t devices_delay_later(struct udev *udev, const char *syspath) -{ - const char *c; - - /* For sound cards the control device must be enumerated last - * to make sure it's the final device node that gets ACLs - * applied. Applications rely on this fact and use ACL changes - * on the control node as an indicator that the ACL change of - * the entire sound card completed. The kernel makes this - * guarantee when creating those devices, and hence we should - * too when enumerating them. */ - - if ((c = strstr(syspath, "/sound/card"))) { - c += 11; - c += strcspn(c, "/"); - - if (strncmp(c, "/controlC", 9) == 0) - return c - syspath + 1; - } - - return 0; -} - -/** - * udev_enumerate_get_list_entry: - * @udev_enumerate: context - * - * Returns: the first entry of the sorted list of device paths. - */ -UDEV_EXPORT struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *udev_enumerate) -{ - if (udev_enumerate == NULL) - return NULL; - if (!udev_enumerate->devices_uptodate) { - unsigned int i; - unsigned int max; - struct syspath *prev = NULL, *move_later = NULL; - size_t move_later_prefix = 0; - - udev_list_cleanup(&udev_enumerate->devices_list); - qsort(udev_enumerate->devices, udev_enumerate->devices_cur, sizeof(struct syspath), syspath_cmp); - - max = udev_enumerate->devices_cur; - for (i = 0; i < max; i++) { - struct syspath *entry = &udev_enumerate->devices[i]; - - /* skip duplicated entries */ - if (prev != NULL && - entry->len == prev->len && - memcmp(entry->syspath, prev->syspath, entry->len) == 0) - continue; - prev = entry; - - /* skip to be delayed devices, and add them to the end of the list */ - if (devices_delay_end(udev_enumerate->udev, entry->syspath)) { - syspath_add(udev_enumerate, entry->syspath); - /* need to update prev here for the case realloc() gives a different address */ - prev = &udev_enumerate->devices[i]; - continue; - } - - /* skip to be delayed devices, and move the to - * the point where the prefix changes. We can - * only move one item at a time. */ - if (!move_later) { - move_later_prefix = devices_delay_later(udev_enumerate->udev, entry->syspath); - - if (move_later_prefix > 0) { - move_later = entry; - continue; - } - } - - if (move_later && - strncmp(entry->syspath, move_later->syspath, move_later_prefix) != 0) { - - udev_list_entry_add(&udev_enumerate->devices_list, move_later->syspath, NULL); - move_later = NULL; - } - - udev_list_entry_add(&udev_enumerate->devices_list, entry->syspath, NULL); - } - - if (move_later) - udev_list_entry_add(&udev_enumerate->devices_list, move_later->syspath, NULL); - - /* add and cleanup delayed devices from end of list */ - for (i = max; i < udev_enumerate->devices_cur; i++) { - struct syspath *entry = &udev_enumerate->devices[i]; - - udev_list_entry_add(&udev_enumerate->devices_list, entry->syspath, NULL); - free(entry->syspath); - } - udev_enumerate->devices_cur = max; - - udev_enumerate->devices_uptodate = true; - } - return udev_list_get_entry(&udev_enumerate->devices_list); -} - -/** - * udev_enumerate_add_match_subsystem: - * @udev_enumerate: context - * @subsystem: filter for a subsystem of the device to include in the list - * - * Returns: 0 on success, otherwise a negative error value. - */ -UDEV_EXPORT int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem) -{ - if (udev_enumerate == NULL) - return -EINVAL; - if (subsystem == NULL) - return 0; - if (udev_list_entry_add(&udev_enumerate->subsystem_match_list, subsystem, NULL) == NULL) - return -ENOMEM; - return 0; -} - -/** - * udev_enumerate_add_nomatch_subsystem: - * @udev_enumerate: context - * @subsystem: filter for a subsystem of the device to exclude from the list - * - * Returns: 0 on success, otherwise a negative error value. - */ -UDEV_EXPORT int udev_enumerate_add_nomatch_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem) -{ - if (udev_enumerate == NULL) - return -EINVAL; - if (subsystem == NULL) - return 0; - if (udev_list_entry_add(&udev_enumerate->subsystem_nomatch_list, subsystem, NULL) == NULL) - return -ENOMEM; - return 0; -} - -/** - * udev_enumerate_add_match_sysattr: - * @udev_enumerate: context - * @sysattr: filter for a sys attribute at the device to include in the list - * @value: optional value of the sys attribute - * - * Returns: 0 on success, otherwise a negative error value. - */ -UDEV_EXPORT int udev_enumerate_add_match_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value) -{ - if (udev_enumerate == NULL) - return -EINVAL; - if (sysattr == NULL) - return 0; - if (udev_list_entry_add(&udev_enumerate->sysattr_match_list, sysattr, value) == NULL) - return -ENOMEM; - return 0; -} - -/** - * udev_enumerate_add_nomatch_sysattr: - * @udev_enumerate: context - * @sysattr: filter for a sys attribute at the device to exclude from the list - * @value: optional value of the sys attribute - * - * Returns: 0 on success, otherwise a negative error value. - */ -UDEV_EXPORT int udev_enumerate_add_nomatch_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value) -{ - if (udev_enumerate == NULL) - return -EINVAL; - if (sysattr == NULL) - return 0; - if (udev_list_entry_add(&udev_enumerate->sysattr_nomatch_list, sysattr, value) == NULL) - return -ENOMEM; - return 0; -} - -static int match_sysattr_value(struct udev_device *dev, const char *sysattr, const char *match_val) -{ - const char *val = NULL; - bool match = false; - - val = udev_device_get_sysattr_value(dev, sysattr); - if (val == NULL) - goto exit; - if (match_val == NULL) { - match = true; - goto exit; - } - if (fnmatch(match_val, val, 0) == 0) { - match = true; - goto exit; - } -exit: - return match; -} - -/** - * udev_enumerate_add_match_property: - * @udev_enumerate: context - * @property: filter for a property of the device to include in the list - * @value: value of the property - * - * Returns: 0 on success, otherwise a negative error value. - */ -UDEV_EXPORT int udev_enumerate_add_match_property(struct udev_enumerate *udev_enumerate, const char *property, const char *value) -{ - if (udev_enumerate == NULL) - return -EINVAL; - if (property == NULL) - return 0; - if (udev_list_entry_add(&udev_enumerate->properties_match_list, property, value) == NULL) - return -ENOMEM; - return 0; -} - -/** - * udev_enumerate_add_match_tag: - * @udev_enumerate: context - * @tag: filter for a tag of the device to include in the list - * - * Returns: 0 on success, otherwise a negative error value. - */ -UDEV_EXPORT int udev_enumerate_add_match_tag(struct udev_enumerate *udev_enumerate, const char *tag) -{ - if (udev_enumerate == NULL) - return -EINVAL; - if (tag == NULL) - return 0; - if (udev_list_entry_add(&udev_enumerate->tags_match_list, tag, NULL) == NULL) - return -ENOMEM; - return 0; -} - -/** - * udev_enumerate_add_match_parent: - * @udev_enumerate: context - * @parent: parent device where to start searching - * - * Return the devices on the subtree of one given device. The parent - * itself is included in the list. - * - * A reference for the device is held until the udev_enumerate context - * is cleaned up. - * - * Returns: 0 on success, otherwise a negative error value. - */ -UDEV_EXPORT int udev_enumerate_add_match_parent(struct udev_enumerate *udev_enumerate, struct udev_device *parent) -{ - if (udev_enumerate == NULL) - return -EINVAL; - if (parent == NULL) - return 0; - if (udev_enumerate->parent_match != NULL) - udev_device_unref(udev_enumerate->parent_match); - udev_enumerate->parent_match = udev_device_ref(parent); - return 0; -} - -/** - * udev_enumerate_add_match_is_initialized: - * @udev_enumerate: context - * - * Match only devices which udev has set up already. This makes - * sure, that the device node permissions and context are properly set - * and that network devices are fully renamed. - * - * Usually, devices which are found in the kernel but not already - * handled by udev, have still pending events. Services should subscribe - * to monitor events and wait for these devices to become ready, instead - * of using uninitialized devices. - * - * For now, this will not affect devices which do not have a device node - * and are not network interfaces. - * - * Returns: 0 on success, otherwise a negative error value. - */ -UDEV_EXPORT int udev_enumerate_add_match_is_initialized(struct udev_enumerate *udev_enumerate) -{ - if (udev_enumerate == NULL) - return -EINVAL; - udev_enumerate->match_is_initialized = true; - return 0; -} - -/** - * udev_enumerate_add_match_sysname: - * @udev_enumerate: context - * @sysname: filter for the name of the device to include in the list - * - * Returns: 0 on success, otherwise a negative error value. - */ -UDEV_EXPORT int udev_enumerate_add_match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname) -{ - if (udev_enumerate == NULL) - return -EINVAL; - if (sysname == NULL) - return 0; - if (udev_list_entry_add(&udev_enumerate->sysname_match_list, sysname, NULL) == NULL) - return -ENOMEM; - return 0; -} - -static bool match_sysattr(struct udev_enumerate *udev_enumerate, struct udev_device *dev) -{ - struct udev_list_entry *list_entry; - - /* skip list */ - udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->sysattr_nomatch_list)) { - if (match_sysattr_value(dev, udev_list_entry_get_name(list_entry), - udev_list_entry_get_value(list_entry))) - return false; - } - /* include list */ - if (udev_list_get_entry(&udev_enumerate->sysattr_match_list) != NULL) { - udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->sysattr_match_list)) { - /* anything that does not match, will make it FALSE */ - if (!match_sysattr_value(dev, udev_list_entry_get_name(list_entry), - udev_list_entry_get_value(list_entry))) - return false; - } - return true; - } - return true; -} - -static bool match_property(struct udev_enumerate *udev_enumerate, struct udev_device *dev) -{ - struct udev_list_entry *list_entry; - bool match = false; - - /* no match always matches */ - if (udev_list_get_entry(&udev_enumerate->properties_match_list) == NULL) - return true; - - /* loop over matches */ - udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->properties_match_list)) { - const char *match_key = udev_list_entry_get_name(list_entry); - const char *match_value = udev_list_entry_get_value(list_entry); - struct udev_list_entry *property_entry; - - /* loop over device properties */ - udev_list_entry_foreach(property_entry, udev_device_get_properties_list_entry(dev)) { - const char *dev_key = udev_list_entry_get_name(property_entry); - const char *dev_value = udev_list_entry_get_value(property_entry); - - if (fnmatch(match_key, dev_key, 0) != 0) - continue; - if (match_value == NULL && dev_value == NULL) { - match = true; - goto out; - } - if (match_value == NULL || dev_value == NULL) - continue; - if (fnmatch(match_value, dev_value, 0) == 0) { - match = true; - goto out; - } - } - } -out: - return match; -} - -static bool match_tag(struct udev_enumerate *udev_enumerate, struct udev_device *dev) -{ - struct udev_list_entry *list_entry; - - /* no match always matches */ - if (udev_list_get_entry(&udev_enumerate->tags_match_list) == NULL) - return true; - - /* loop over matches */ - udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->tags_match_list)) - if (!udev_device_has_tag(dev, udev_list_entry_get_name(list_entry))) - return false; - - return true; -} - -static bool match_parent(struct udev_enumerate *udev_enumerate, struct udev_device *dev) -{ - const char *parent; - - if (udev_enumerate->parent_match == NULL) - return true; - - parent = udev_device_get_devpath(udev_enumerate->parent_match); - return strncmp(parent, udev_device_get_devpath(dev), strlen(parent)) == 0; -} - -static bool match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname) -{ - struct udev_list_entry *list_entry; - - if (udev_list_get_entry(&udev_enumerate->sysname_match_list) == NULL) - return true; - - udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->sysname_match_list)) { - if (fnmatch(udev_list_entry_get_name(list_entry), sysname, 0) != 0) - continue; - return true; - } - return false; -} - -static int scan_dir_and_add_devices(struct udev_enumerate *udev_enumerate, - const char *basedir, const char *subdir1, const char *subdir2) -{ - struct udev *udev = udev_enumerate_get_udev(udev_enumerate); - char path[UTIL_PATH_SIZE]; - size_t l; - char *s; - DIR *dir; - struct dirent *dent; - - s = path; - l = util_strpcpyl(&s, sizeof(path), udev_get_sys_path(udev), "/", basedir, NULL); - if (subdir1 != NULL) - l = util_strpcpyl(&s, l, "/", subdir1, NULL); - if (subdir2 != NULL) - util_strpcpyl(&s, l, "/", subdir2, NULL); - dir = opendir(path); - if (dir == NULL) - return -ENOENT; - for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { - char syspath[UTIL_PATH_SIZE]; - struct udev_device *dev; - - if (dent->d_name[0] == '.') - continue; - - if (!match_sysname(udev_enumerate, dent->d_name)) - continue; - - util_strscpyl(syspath, sizeof(syspath), path, "/", dent->d_name, NULL); - dev = udev_device_new_from_syspath(udev_enumerate->udev, syspath); - if (dev == NULL) - continue; - - if (udev_enumerate->match_is_initialized) { - /* - * All devices with a device node or network interfaces - * possibly need udev to adjust the device node permission - * or context, or rename the interface before it can be - * reliably used from other processes. - * - * For now, we can only check these types of devices, we - * might not store a database, and have no way to find out - * for all other types of devices. - */ - if (!udev_device_get_is_initialized(dev) && - (major(udev_device_get_devnum(dev)) > 0 || udev_device_get_ifindex(dev) > 0)) - goto nomatch; - } - if (!match_parent(udev_enumerate, dev)) - goto nomatch; - if (!match_tag(udev_enumerate, dev)) - goto nomatch; - if (!match_property(udev_enumerate, dev)) - goto nomatch; - if (!match_sysattr(udev_enumerate, dev)) - goto nomatch; - - syspath_add(udev_enumerate, udev_device_get_syspath(dev)); -nomatch: - udev_device_unref(dev); - } - closedir(dir); - return 0; -} - -static bool match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem) -{ - struct udev_list_entry *list_entry; - - udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->subsystem_nomatch_list)) { - if (fnmatch(udev_list_entry_get_name(list_entry), subsystem, 0) == 0) - return false; - } - if (udev_list_get_entry(&udev_enumerate->subsystem_match_list) != NULL) { - udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->subsystem_match_list)) { - if (fnmatch(udev_list_entry_get_name(list_entry), subsystem, 0) == 0) - return true; - } - return false; - } - return true; -} - -static int scan_dir(struct udev_enumerate *udev_enumerate, const char *basedir, const char *subdir, const char *subsystem) -{ - struct udev *udev = udev_enumerate_get_udev(udev_enumerate); - - char path[UTIL_PATH_SIZE]; - DIR *dir; - struct dirent *dent; - - util_strscpyl(path, sizeof(path), udev_get_sys_path(udev), "/", basedir, NULL); - dir = opendir(path); - if (dir == NULL) - return -1; - for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { - if (dent->d_name[0] == '.') - continue; - if (!match_subsystem(udev_enumerate, subsystem != NULL ? subsystem : dent->d_name)) - continue; - scan_dir_and_add_devices(udev_enumerate, basedir, dent->d_name, subdir); - } - closedir(dir); - return 0; -} - -/** - * udev_enumerate_add_syspath: - * @udev_enumerate: context - * @syspath: path of a device - * - * Add a device to the list of devices, to retrieve it back sorted in dependency order. - * - * Returns: 0 on success, otherwise a negative error value. - */ -UDEV_EXPORT int udev_enumerate_add_syspath(struct udev_enumerate *udev_enumerate, const char *syspath) -{ - struct udev_device *udev_device; - - if (udev_enumerate == NULL) - return -EINVAL; - if (syspath == NULL) - return 0; - /* resolve to real syspath */ - udev_device = udev_device_new_from_syspath(udev_enumerate->udev, syspath); - if (udev_device == NULL) - return -EINVAL; - syspath_add(udev_enumerate, udev_device_get_syspath(udev_device)); - udev_device_unref(udev_device); - return 0; -} - -static int scan_devices_tags(struct udev_enumerate *udev_enumerate) -{ - struct udev *udev = udev_enumerate_get_udev(udev_enumerate); - struct udev_list_entry *list_entry; - - /* scan only tagged devices, use tags reverse-index, instead of searching all devices in /sys */ - udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->tags_match_list)) { - DIR *dir; - struct dirent *dent; - char path[UTIL_PATH_SIZE]; - - util_strscpyl(path, sizeof(path), udev_get_run_path(udev), "/tags/", - udev_list_entry_get_name(list_entry), NULL); - dir = opendir(path); - if (dir == NULL) - continue; - for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { - struct udev_device *dev; - - if (dent->d_name[0] == '.') - continue; - - dev = udev_device_new_from_id_filename(udev_enumerate->udev, dent->d_name); - if (dev == NULL) - continue; - - if (!match_subsystem(udev_enumerate, udev_device_get_subsystem(dev))) - goto nomatch; - if (!match_sysname(udev_enumerate, udev_device_get_sysname(dev))) - goto nomatch; - if (!match_parent(udev_enumerate, dev)) - goto nomatch; - if (!match_property(udev_enumerate, dev)) - goto nomatch; - if (!match_sysattr(udev_enumerate, dev)) - goto nomatch; - - syspath_add(udev_enumerate, udev_device_get_syspath(dev)); -nomatch: - udev_device_unref(dev); - } - closedir(dir); - } - return 0; -} - -static int parent_add_child(struct udev_enumerate *enumerate, const char *path) -{ - struct udev_device *dev; - - dev = udev_device_new_from_syspath(enumerate->udev, path); - if (dev == NULL) - return -ENODEV; - - if (!match_subsystem(enumerate, udev_device_get_subsystem(dev))) - return 0; - if (!match_sysname(enumerate, udev_device_get_sysname(dev))) - return 0; - if (!match_property(enumerate, dev)) - return 0; - if (!match_sysattr(enumerate, dev)) - return 0; - - syspath_add(enumerate, udev_device_get_syspath(dev)); - udev_device_unref(dev); - return 1; -} - -static int parent_crawl_children(struct udev_enumerate *enumerate, const char *path, int maxdepth) -{ - DIR *d; - struct dirent *dent; - - d = opendir(path); - if (d == NULL) - return -errno; - - for (dent = readdir(d); dent != NULL; dent = readdir(d)) { - char *child; - - if (dent->d_name[0] == '.') - continue; - if (dent->d_type != DT_DIR) - continue; - if (asprintf(&child, "%s/%s", path, dent->d_name) < 0) - continue; - parent_add_child(enumerate, child); - if (maxdepth > 0) - parent_crawl_children(enumerate, child, maxdepth-1); - free(child); - } - - closedir(d); - return 0; -} - -static int scan_devices_children(struct udev_enumerate *enumerate) -{ - const char *path; - - path = udev_device_get_syspath(enumerate->parent_match); - parent_add_child(enumerate, path); - return parent_crawl_children(enumerate, path, 256); -} - -static int scan_devices_all(struct udev_enumerate *udev_enumerate) -{ - struct udev *udev = udev_enumerate_get_udev(udev_enumerate); - char base[UTIL_PATH_SIZE]; - struct stat statbuf; - - util_strscpyl(base, sizeof(base), udev_get_sys_path(udev), "/subsystem", NULL); - if (stat(base, &statbuf) == 0) { - /* we have /subsystem/, forget all the old stuff */ - dbg(udev, "searching '/subsystem/*/devices/*' dir\n"); - scan_dir(udev_enumerate, "subsystem", "devices", NULL); - } else { - dbg(udev, "searching '/bus/*/devices/*' dir\n"); - scan_dir(udev_enumerate, "bus", "devices", NULL); - dbg(udev, "searching '/class/*' dir\n"); - scan_dir(udev_enumerate, "class", NULL, NULL); - } - return 0; -} - -/** - * udev_enumerate_scan_devices: - * @udev_enumerate: udev enumeration context - * - * Returns: 0 on success, otherwise a negative error value. - **/ -UDEV_EXPORT int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate) -{ - if (udev_enumerate == NULL) - return -EINVAL; - - /* efficiently lookup tags only, we maintain a reverse-index */ - if (udev_list_get_entry(&udev_enumerate->tags_match_list) != NULL) - return scan_devices_tags(udev_enumerate); - - /* walk the subtree of one parent device only */ - if (udev_enumerate->parent_match != NULL) - return scan_devices_children(udev_enumerate); - - /* scan devices of all subsystems */ - return scan_devices_all(udev_enumerate); -} - -/** - * udev_enumerate_scan_subsystems: - * @udev_enumerate: udev enumeration context - * - * Returns: 0 on success, otherwise a negative error value. - **/ -UDEV_EXPORT int udev_enumerate_scan_subsystems(struct udev_enumerate *udev_enumerate) -{ - struct udev *udev = udev_enumerate_get_udev(udev_enumerate); - char base[UTIL_PATH_SIZE]; - struct stat statbuf; - const char *subsysdir; - - if (udev_enumerate == NULL) - return -EINVAL; - - /* all kernel modules */ - if (match_subsystem(udev_enumerate, "module")) { - dbg(udev, "searching '%s/modules/*' dir\n", subsysdir); - scan_dir_and_add_devices(udev_enumerate, "module", NULL, NULL); - } - - util_strscpyl(base, sizeof(base), udev_get_sys_path(udev), "/subsystem", NULL); - if (stat(base, &statbuf) == 0) - subsysdir = "subsystem"; - else - subsysdir = "bus"; - - /* all subsystems (only buses support coldplug) */ - if (match_subsystem(udev_enumerate, "subsystem")) { - dbg(udev, "searching '%s/*' dir\n", subsysdir); - scan_dir_and_add_devices(udev_enumerate, subsysdir, NULL, NULL); - } - - /* all subsystem drivers */ - if (match_subsystem(udev_enumerate, "drivers")) { - dbg(udev, "searching '%s/*/drivers/*' dir\n", subsysdir); - scan_dir(udev_enumerate, subsysdir, "drivers", "drivers"); - } - return 0; -} diff --git a/libudev/libudev-list.c b/libudev/libudev-list.c deleted file mode 100644 index f74a88ca49..0000000000 --- a/libudev/libudev-list.c +++ /dev/null @@ -1,344 +0,0 @@ -/* - * libudev - interface to udev device information - * - * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org> - * - * 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. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <stddef.h> -#include <unistd.h> -#include <errno.h> -#include <string.h> - -#include "libudev.h" -#include "libudev-private.h" - -/** - * SECTION:libudev-list - * @short_description: list operation - * - * Libudev list operations. - */ - -/** - * udev_list_entry: - * - * Opaque object representing one entry in a list. An entry contains - * contains a name, and optionally a value. - */ -struct udev_list_entry { - struct udev_list_node node; - struct udev_list *list; - char *name; - char *value; - int num; -}; - -/* the list's head points to itself if empty */ -void udev_list_node_init(struct udev_list_node *list) -{ - list->next = list; - list->prev = list; -} - -int udev_list_node_is_empty(struct udev_list_node *list) -{ - return list->next == list; -} - -static void udev_list_node_insert_between(struct udev_list_node *new, - struct udev_list_node *prev, - struct udev_list_node *next) -{ - next->prev = new; - new->next = next; - new->prev = prev; - prev->next = new; -} - -void udev_list_node_append(struct udev_list_node *new, struct udev_list_node *list) -{ - udev_list_node_insert_between(new, list->prev, list); -} - -void udev_list_node_remove(struct udev_list_node *entry) -{ - struct udev_list_node *prev = entry->prev; - struct udev_list_node *next = entry->next; - - next->prev = prev; - prev->next = next; - - entry->prev = NULL; - entry->next = NULL; -} - -/* return list entry which embeds this node */ -static struct udev_list_entry *list_node_to_entry(struct udev_list_node *node) -{ - char *list; - - list = (char *)node; - list -= offsetof(struct udev_list_entry, node); - return (struct udev_list_entry *)list; -} - -void udev_list_init(struct udev *udev, struct udev_list *list, bool unique) -{ - memset(list, 0x00, sizeof(struct udev_list)); - list->udev = udev; - list->unique = unique; - udev_list_node_init(&list->node); -} - -/* insert entry into a list as the last element */ -void udev_list_entry_append(struct udev_list_entry *new, struct udev_list *list) -{ - /* inserting before the list head make the node the last node in the list */ - udev_list_node_insert_between(&new->node, list->node.prev, &list->node); - new->list = list; -} - -/* insert entry into a list, before a given existing entry */ -void udev_list_entry_insert_before(struct udev_list_entry *new, struct udev_list_entry *entry) -{ - udev_list_node_insert_between(&new->node, entry->node.prev, &entry->node); - new->list = entry->list; -} - -/* binary search in sorted array */ -static int list_search(struct udev_list *list, const char *name) -{ - unsigned int first, last; - - first = 0; - last = list->entries_cur; - while (first < last) { - unsigned int i; - int cmp; - - i = (first + last)/2; - cmp = strcmp(name, list->entries[i]->name); - if (cmp < 0) - last = i; - else if (cmp > 0) - first = i+1; - else - return i; - } - - /* not found, return negative insertion-index+1 */ - return -(first+1); -} - -struct udev_list_entry *udev_list_entry_add(struct udev_list *list, const char *name, const char *value) -{ - struct udev_list_entry *entry; - int i = 0; - - if (list->unique) { - /* lookup existing name or insertion-index */ - i = list_search(list, name); - if (i >= 0) { - entry = list->entries[i]; - - dbg(list->udev, "'%s' is already in the list\n", name); - free(entry->value); - if (value == NULL) { - entry->value = NULL; - dbg(list->udev, "'%s' value unset\n", name); - return entry; - } - entry->value = strdup(value); - if (entry->value == NULL) - return NULL; - dbg(list->udev, "'%s' value replaced with '%s'\n", name, value); - return entry; - } - } - - /* add new name */ - entry = calloc(1, sizeof(struct udev_list_entry)); - if (entry == NULL) - return NULL; - entry->name = strdup(name); - if (entry->name == NULL) { - free(entry); - return NULL; - } - if (value != NULL) { - entry->value = strdup(value); - if (entry->value == NULL) { - free(entry->name); - free(entry); - return NULL; - } - } - - if (list->unique) { - /* allocate or enlarge sorted array if needed */ - if (list->entries_cur >= list->entries_max) { - unsigned int add; - - add = list->entries_max; - if (add < 1) - add = 64; - list->entries = realloc(list->entries, (list->entries_max + add) * sizeof(struct udev_list_entry *)); - if (list->entries == NULL) { - free(entry->name); - free(entry->value); - return NULL; - } - list->entries_max += add; - } - - /* the negative i returned the insertion index */ - i = (-i)-1; - - /* insert into sorted list */ - if ((unsigned int)i < list->entries_cur) - udev_list_entry_insert_before(entry, list->entries[i]); - else - udev_list_entry_append(entry, list); - - /* insert into sorted array */ - memmove(&list->entries[i+1], &list->entries[i], - (list->entries_cur - i) * sizeof(struct udev_list_entry *)); - list->entries[i] = entry; - list->entries_cur++; - } else { - udev_list_entry_append(entry, list); - } - - dbg(list->udev, "'%s=%s' added\n", entry->name, entry->value); - return entry; -} - -void udev_list_entry_delete(struct udev_list_entry *entry) -{ - if (entry->list->entries != NULL) { - int i; - struct udev_list *list = entry->list; - - /* remove entry from sorted array */ - i = list_search(list, entry->name); - if (i >= 0) { - memmove(&list->entries[i], &list->entries[i+1], - ((list->entries_cur-1) - i) * sizeof(struct udev_list_entry *)); - list->entries_cur--; - } - } - - udev_list_node_remove(&entry->node); - free(entry->name); - free(entry->value); - free(entry); -} - -void udev_list_cleanup(struct udev_list *list) -{ - struct udev_list_entry *entry_loop; - struct udev_list_entry *entry_tmp; - - free(list->entries); - list->entries = NULL; - list->entries_cur = 0; - list->entries_max = 0; - udev_list_entry_foreach_safe(entry_loop, entry_tmp, udev_list_get_entry(list)) - udev_list_entry_delete(entry_loop); -} - -struct udev_list_entry *udev_list_get_entry(struct udev_list *list) -{ - if (udev_list_node_is_empty(&list->node)) - return NULL; - return list_node_to_entry(list->node.next); -} - -/** - * udev_list_entry_get_next: - * @list_entry: current entry - * - * Returns: the next entry from the list, #NULL is no more entries are found. - */ -UDEV_EXPORT struct udev_list_entry *udev_list_entry_get_next(struct udev_list_entry *list_entry) -{ - struct udev_list_node *next; - - if (list_entry == NULL) - return NULL; - next = list_entry->node.next; - /* empty list or no more entries */ - if (next == &list_entry->list->node) - return NULL; - return list_node_to_entry(next); -} - -/** - * udev_list_entry_get_by_name: - * @list_entry: current entry - * @name: name string to match - * - * Returns: the entry where @name matched, #NULL if no matching entry is found. - */ -UDEV_EXPORT struct udev_list_entry *udev_list_entry_get_by_name(struct udev_list_entry *list_entry, const char *name) -{ - int i; - - if (list_entry == NULL) - return NULL; - - if (!list_entry->list->unique) - return NULL; - - i = list_search(list_entry->list, name); - if (i < 0) - return NULL; - return list_entry->list->entries[i]; -} - -/** - * udev_list_entry_get_name: - * @list_entry: current entry - * - * Returns: the name string of this entry. - */ -UDEV_EXPORT const char *udev_list_entry_get_name(struct udev_list_entry *list_entry) -{ - if (list_entry == NULL) - return NULL; - return list_entry->name; -} - -/** - * udev_list_entry_get_value: - * @list_entry: current entry - * - * Returns: the value string of this entry. - */ -UDEV_EXPORT const char *udev_list_entry_get_value(struct udev_list_entry *list_entry) -{ - if (list_entry == NULL) - return NULL; - return list_entry->value; -} - -int udev_list_entry_get_num(struct udev_list_entry *list_entry) -{ - if (list_entry == NULL) - return -EINVAL; - return list_entry->num; -} - -void udev_list_entry_set_num(struct udev_list_entry *list_entry, int num) -{ - if (list_entry == NULL) - return; - list_entry->num = num; -} diff --git a/libudev/libudev-monitor.c b/libudev/libudev-monitor.c deleted file mode 100644 index f2f39f9582..0000000000 --- a/libudev/libudev-monitor.c +++ /dev/null @@ -1,875 +0,0 @@ -/* - * libudev - interface to udev device information - * - * Copyright (C) 2008-2010 Kay Sievers <kay.sievers@vrfy.org> - * - * 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. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <stddef.h> -#include <unistd.h> -#include <errno.h> -#include <string.h> -#include <dirent.h> -#include <sys/poll.h> -#include <sys/stat.h> -#include <sys/socket.h> -#include <sys/un.h> -#include <arpa/inet.h> -#include <linux/netlink.h> -#include <linux/filter.h> - -#include "libudev.h" -#include "libudev-private.h" - -/** - * SECTION:libudev-monitor - * @short_description: device event source - * - * Connects to a device event source. - */ - -/** - * udev_monitor: - * - * Opaque object handling an event source. - */ -struct udev_monitor { - struct udev *udev; - int refcount; - int sock; - struct sockaddr_nl snl; - struct sockaddr_nl snl_trusted_sender; - struct sockaddr_nl snl_destination; - struct sockaddr_un sun; - socklen_t addrlen; - struct udev_list filter_subsystem_list; - struct udev_list filter_tag_list; - bool bound; -}; - -enum udev_monitor_netlink_group { - UDEV_MONITOR_NONE, - UDEV_MONITOR_KERNEL, - UDEV_MONITOR_UDEV, -}; - -#define UDEV_MONITOR_MAGIC 0xfeedcafe -struct udev_monitor_netlink_header { - /* "libudev" prefix to distinguish libudev and kernel messages */ - char prefix[8]; - /* - * magic to protect against daemon <-> library message format mismatch - * used in the kernel from socket filter rules; needs to be stored in network order - */ - unsigned int magic; - /* total length of header structure known to the sender */ - unsigned int header_size; - /* properties string buffer */ - unsigned int properties_off; - unsigned int properties_len; - /* - * hashes of primary device properties strings, to let libudev subscribers - * use in-kernel socket filters; values need to be stored in network order - */ - unsigned int filter_subsystem_hash; - unsigned int filter_devtype_hash; - unsigned int filter_tag_bloom_hi; - unsigned int filter_tag_bloom_lo; -}; - -static struct udev_monitor *udev_monitor_new(struct udev *udev) -{ - struct udev_monitor *udev_monitor; - - udev_monitor = calloc(1, sizeof(struct udev_monitor)); - if (udev_monitor == NULL) - return NULL; - udev_monitor->refcount = 1; - udev_monitor->udev = udev; - udev_list_init(udev, &udev_monitor->filter_subsystem_list, false); - udev_list_init(udev, &udev_monitor->filter_tag_list, true); - return udev_monitor; -} - -/** - * udev_monitor_new_from_socket: - * @udev: udev library context - * @socket_path: unix socket path - * - * This function should not be used in any new application. The - * kernel's netlink socket multiplexes messages to all interested - * clients. Creating custom sockets from udev to applications - * should be avoided. - * - * Create a new udev monitor and connect to a specified socket. The - * path to a socket either points to an existing socket file, or if - * the socket path starts with a '@' character, an abstract namespace - * socket will be used. - * - * A socket file will not be created. If it does not already exist, - * it will fall-back and connect to an abstract namespace socket with - * the given path. The permissions adjustment of a socket file, as - * well as the later cleanup, needs to be done by the caller. - * - * The initial refcount is 1, and needs to be decremented to - * release the resources of the udev monitor. - * - * Returns: a new udev monitor, or #NULL, in case of an error - **/ -UDEV_EXPORT struct udev_monitor *udev_monitor_new_from_socket(struct udev *udev, const char *socket_path) -{ - struct udev_monitor *udev_monitor; - struct stat statbuf; - - if (udev == NULL) - return NULL; - if (socket_path == NULL) - return NULL; - udev_monitor = udev_monitor_new(udev); - if (udev_monitor == NULL) - return NULL; - - udev_monitor->sun.sun_family = AF_LOCAL; - if (socket_path[0] == '@') { - /* translate leading '@' to abstract namespace */ - util_strscpy(udev_monitor->sun.sun_path, sizeof(udev_monitor->sun.sun_path), socket_path); - udev_monitor->sun.sun_path[0] = '\0'; - udev_monitor->addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(socket_path); - } else if (stat(socket_path, &statbuf) == 0 && S_ISSOCK(statbuf.st_mode)) { - /* existing socket file */ - util_strscpy(udev_monitor->sun.sun_path, sizeof(udev_monitor->sun.sun_path), socket_path); - udev_monitor->addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(socket_path); - } else { - /* no socket file, assume abstract namespace socket */ - util_strscpy(&udev_monitor->sun.sun_path[1], sizeof(udev_monitor->sun.sun_path)-1, socket_path); - udev_monitor->addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(socket_path)+1; - } - udev_monitor->sock = socket(AF_LOCAL, SOCK_DGRAM|SOCK_NONBLOCK|SOCK_CLOEXEC, 0); - if (udev_monitor->sock == -1) { - err(udev, "error getting socket: %m\n"); - free(udev_monitor); - return NULL; - } - - dbg(udev, "monitor %p created with '%s'\n", udev_monitor, socket_path); - return udev_monitor; -} - -struct udev_monitor *udev_monitor_new_from_netlink_fd(struct udev *udev, const char *name, int fd) -{ - struct udev_monitor *udev_monitor; - unsigned int group; - - if (udev == NULL) - return NULL; - - if (name == NULL) - group = UDEV_MONITOR_NONE; - else if (strcmp(name, "udev") == 0) - group = UDEV_MONITOR_UDEV; - else if (strcmp(name, "kernel") == 0) - group = UDEV_MONITOR_KERNEL; - else - return NULL; - - udev_monitor = udev_monitor_new(udev); - if (udev_monitor == NULL) - return NULL; - - if (fd < 0) { - udev_monitor->sock = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_KOBJECT_UEVENT); - if (udev_monitor->sock == -1) { - err(udev, "error getting socket: %m\n"); - free(udev_monitor); - return NULL; - } - } else { - udev_monitor->bound = true; - udev_monitor->sock = fd; - } - - udev_monitor->snl.nl_family = AF_NETLINK; - udev_monitor->snl.nl_groups = group; - - /* default destination for sending */ - udev_monitor->snl_destination.nl_family = AF_NETLINK; - udev_monitor->snl_destination.nl_groups = UDEV_MONITOR_UDEV; - - dbg(udev, "monitor %p created with NETLINK_KOBJECT_UEVENT (%u)\n", udev_monitor, group); - return udev_monitor; -} - -/** - * udev_monitor_new_from_netlink: - * @udev: udev library context - * @name: name of event source - * - * Create new udev monitor and connect to a specified event - * source. Valid sources identifiers are "udev" and "kernel". - * - * Applications should usually not connect directly to the - * "kernel" events, because the devices might not be useable - * at that time, before udev has configured them, and created - * device nodes. Accessing devices at the same time as udev, - * might result in unpredictable behavior. The "udev" events - * are sent out after udev has finished its event processing, - * all rules have been processed, and needed device nodes are - * created. - * - * The initial refcount is 1, and needs to be decremented to - * release the resources of the udev monitor. - * - * Returns: a new udev monitor, or #NULL, in case of an error - **/ -UDEV_EXPORT struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, const char *name) -{ - return udev_monitor_new_from_netlink_fd(udev, name, -1); -} - -static inline void bpf_stmt(struct sock_filter *inss, unsigned int *i, - unsigned short code, unsigned int data) -{ - struct sock_filter *ins = &inss[*i]; - - ins->code = code; - ins->k = data; - (*i)++; -} - -static inline void bpf_jmp(struct sock_filter *inss, unsigned int *i, - unsigned short code, unsigned int data, - unsigned short jt, unsigned short jf) -{ - struct sock_filter *ins = &inss[*i]; - - ins->code = code; - ins->jt = jt; - ins->jf = jf; - ins->k = data; - (*i)++; -} - -/** - * udev_monitor_filter_update: - * @udev_monitor: monitor - * - * Update the installed socket filter. This is only needed, - * if the filter was removed or changed. - * - * Returns: 0 on success, otherwise a negative error value. - */ -UDEV_EXPORT int udev_monitor_filter_update(struct udev_monitor *udev_monitor) -{ - struct sock_filter ins[512]; - struct sock_fprog filter; - unsigned int i; - struct udev_list_entry *list_entry; - int err; - - if (udev_list_get_entry(&udev_monitor->filter_subsystem_list) == NULL && - udev_list_get_entry(&udev_monitor->filter_tag_list) == NULL) - return 0; - - memset(ins, 0x00, sizeof(ins)); - i = 0; - - /* load magic in A */ - bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(struct udev_monitor_netlink_header, magic)); - /* jump if magic matches */ - bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, UDEV_MONITOR_MAGIC, 1, 0); - /* wrong magic, pass packet */ - bpf_stmt(ins, &i, BPF_RET|BPF_K, 0xffffffff); - - if (udev_list_get_entry(&udev_monitor->filter_tag_list) != NULL) { - int tag_matches; - - /* count tag matches, to calculate end of tag match block */ - tag_matches = 0; - udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_tag_list)) - tag_matches++; - - /* add all tags matches */ - udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_tag_list)) { - uint64_t tag_bloom_bits = util_string_bloom64(udev_list_entry_get_name(list_entry)); - uint32_t tag_bloom_hi = tag_bloom_bits >> 32; - uint32_t tag_bloom_lo = tag_bloom_bits & 0xffffffff; - - /* load device bloom bits in A */ - bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(struct udev_monitor_netlink_header, filter_tag_bloom_hi)); - /* clear bits (tag bits & bloom bits) */ - bpf_stmt(ins, &i, BPF_ALU|BPF_AND|BPF_K, tag_bloom_hi); - /* jump to next tag if it does not match */ - bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, tag_bloom_hi, 0, 3); - - /* load device bloom bits in A */ - bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(struct udev_monitor_netlink_header, filter_tag_bloom_lo)); - /* clear bits (tag bits & bloom bits) */ - bpf_stmt(ins, &i, BPF_ALU|BPF_AND|BPF_K, tag_bloom_lo); - /* jump behind end of tag match block if tag matches */ - tag_matches--; - bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, tag_bloom_lo, 1 + (tag_matches * 6), 0); - } - - /* nothing matched, drop packet */ - bpf_stmt(ins, &i, BPF_RET|BPF_K, 0); - } - - /* add all subsystem matches */ - if (udev_list_get_entry(&udev_monitor->filter_subsystem_list) != NULL) { - udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_subsystem_list)) { - unsigned int hash = util_string_hash32(udev_list_entry_get_name(list_entry)); - - /* load device subsystem value in A */ - bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(struct udev_monitor_netlink_header, filter_subsystem_hash)); - if (udev_list_entry_get_value(list_entry) == NULL) { - /* jump if subsystem does not match */ - bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, hash, 0, 1); - } else { - /* jump if subsystem does not match */ - bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, hash, 0, 3); - - /* load device devtype value in A */ - bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(struct udev_monitor_netlink_header, filter_devtype_hash)); - /* jump if value does not match */ - hash = util_string_hash32(udev_list_entry_get_value(list_entry)); - bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, hash, 0, 1); - } - - /* matched, pass packet */ - bpf_stmt(ins, &i, BPF_RET|BPF_K, 0xffffffff); - - if (i+1 >= ARRAY_SIZE(ins)) - return -1; - } - - /* nothing matched, drop packet */ - bpf_stmt(ins, &i, BPF_RET|BPF_K, 0); - } - - /* matched, pass packet */ - bpf_stmt(ins, &i, BPF_RET|BPF_K, 0xffffffff); - - /* install filter */ - memset(&filter, 0x00, sizeof(filter)); - filter.len = i; - filter.filter = ins; - err = setsockopt(udev_monitor->sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)); - return err; -} - -int udev_monitor_allow_unicast_sender(struct udev_monitor *udev_monitor, struct udev_monitor *sender) -{ - udev_monitor->snl_trusted_sender.nl_pid = sender->snl.nl_pid; - return 0; -} -/** - * udev_monitor_enable_receiving: - * @udev_monitor: the monitor which should receive events - * - * Binds the @udev_monitor socket to the event source. - * - * Returns: 0 on success, otherwise a negative error value. - */ -UDEV_EXPORT int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor) -{ - int err = 0; - const int on = 1; - - if (udev_monitor->sun.sun_family != 0) { - if (!udev_monitor->bound) { - err = bind(udev_monitor->sock, - (struct sockaddr *)&udev_monitor->sun, udev_monitor->addrlen); - if (err == 0) - udev_monitor->bound = true; - } - } else if (udev_monitor->snl.nl_family != 0) { - udev_monitor_filter_update(udev_monitor); - if (!udev_monitor->bound) { - err = bind(udev_monitor->sock, - (struct sockaddr *)&udev_monitor->snl, sizeof(struct sockaddr_nl)); - if (err == 0) - udev_monitor->bound = true; - } - if (err == 0) { - struct sockaddr_nl snl; - socklen_t addrlen; - - /* - * get the address the kernel has assigned us - * it is usually, but not necessarily the pid - */ - addrlen = sizeof(struct sockaddr_nl); - err = getsockname(udev_monitor->sock, (struct sockaddr *)&snl, &addrlen); - if (err == 0) - udev_monitor->snl.nl_pid = snl.nl_pid; - } - } else { - return -EINVAL; - } - - if (err < 0) { - err(udev_monitor->udev, "bind failed: %m\n"); - return err; - } - - /* enable receiving of sender credentials */ - setsockopt(udev_monitor->sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)); - return 0; -} - -/** - * udev_monitor_set_receive_buffer_size: - * @udev_monitor: the monitor which should receive events - * @size: the size in bytes - * - * Set the size of the kernel socket buffer. This call needs the - * appropriate privileges to succeed. - * - * Returns: 0 on success, otherwise -1 on error. - */ -UDEV_EXPORT int udev_monitor_set_receive_buffer_size(struct udev_monitor *udev_monitor, int size) -{ - if (udev_monitor == NULL) - return -1; - return setsockopt(udev_monitor->sock, SOL_SOCKET, SO_RCVBUFFORCE, &size, sizeof(size)); -} - -int udev_monitor_disconnect(struct udev_monitor *udev_monitor) -{ - int err; - - err = close(udev_monitor->sock); - udev_monitor->sock = -1; - return err; -} - -/** - * udev_monitor_ref: - * @udev_monitor: udev monitor - * - * Take a reference of a udev monitor. - * - * Returns: the passed udev monitor - **/ -UDEV_EXPORT struct udev_monitor *udev_monitor_ref(struct udev_monitor *udev_monitor) -{ - if (udev_monitor == NULL) - return NULL; - udev_monitor->refcount++; - return udev_monitor; -} - -/** - * udev_monitor_unref: - * @udev_monitor: udev monitor - * - * Drop a reference of a udev monitor. If the refcount reaches zero, - * the bound socket will be closed, and the resources of the monitor - * will be released. - * - **/ -UDEV_EXPORT void udev_monitor_unref(struct udev_monitor *udev_monitor) -{ - if (udev_monitor == NULL) - return; - udev_monitor->refcount--; - if (udev_monitor->refcount > 0) - return; - if (udev_monitor->sock >= 0) - close(udev_monitor->sock); - udev_list_cleanup(&udev_monitor->filter_subsystem_list); - udev_list_cleanup(&udev_monitor->filter_tag_list); - dbg(udev_monitor->udev, "monitor %p released\n", udev_monitor); - free(udev_monitor); -} - -/** - * udev_monitor_get_udev: - * @udev_monitor: udev monitor - * - * Retrieve the udev library context the monitor was created with. - * - * Returns: the udev library context - **/ -UDEV_EXPORT struct udev *udev_monitor_get_udev(struct udev_monitor *udev_monitor) -{ - if (udev_monitor == NULL) - return NULL; - return udev_monitor->udev; -} - -/** - * udev_monitor_get_fd: - * @udev_monitor: udev monitor - * - * Retrieve the socket file descriptor associated with the monitor. - * - * Returns: the socket file descriptor - **/ -UDEV_EXPORT int udev_monitor_get_fd(struct udev_monitor *udev_monitor) -{ - if (udev_monitor == NULL) - return -1; - return udev_monitor->sock; -} - -static int passes_filter(struct udev_monitor *udev_monitor, struct udev_device *udev_device) -{ - struct udev_list_entry *list_entry; - - if (udev_list_get_entry(&udev_monitor->filter_subsystem_list) == NULL) - goto tag; - udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_subsystem_list)) { - const char *subsys = udev_list_entry_get_name(list_entry); - const char *dsubsys = udev_device_get_subsystem(udev_device); - const char *devtype; - const char *ddevtype; - - if (strcmp(dsubsys, subsys) != 0) - continue; - - devtype = udev_list_entry_get_value(list_entry); - if (devtype == NULL) - goto tag; - ddevtype = udev_device_get_devtype(udev_device); - if (ddevtype == NULL) - continue; - if (strcmp(ddevtype, devtype) == 0) - goto tag; - } - return 0; - -tag: - if (udev_list_get_entry(&udev_monitor->filter_tag_list) == NULL) - return 1; - udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_tag_list)) { - const char *tag = udev_list_entry_get_name(list_entry); - - if (udev_device_has_tag(udev_device, tag)) - return 1; - } - return 0; -} - -/** - * udev_monitor_receive_device: - * @udev_monitor: udev monitor - * - * Receive data from the udev monitor socket, allocate a new udev - * device, fill in the received data, and return the device. - * - * Only socket connections with uid=0 are accepted. - * - * The initial refcount is 1, and needs to be decremented to - * release the resources of the udev device. - * - * Returns: a new udev device, or #NULL, in case of an error - **/ -UDEV_EXPORT struct udev_device *udev_monitor_receive_device(struct udev_monitor *udev_monitor) -{ - struct udev_device *udev_device; - struct msghdr smsg; - struct iovec iov; - char cred_msg[CMSG_SPACE(sizeof(struct ucred))]; - struct cmsghdr *cmsg; - struct sockaddr_nl snl; - struct ucred *cred; - char buf[8192]; - ssize_t buflen; - ssize_t bufpos; - struct udev_monitor_netlink_header *nlh; - -retry: - if (udev_monitor == NULL) - return NULL; - memset(buf, 0x00, sizeof(buf)); - iov.iov_base = &buf; - iov.iov_len = sizeof(buf); - memset (&smsg, 0x00, sizeof(struct msghdr)); - smsg.msg_iov = &iov; - smsg.msg_iovlen = 1; - smsg.msg_control = cred_msg; - smsg.msg_controllen = sizeof(cred_msg); - - if (udev_monitor->snl.nl_family != 0) { - smsg.msg_name = &snl; - smsg.msg_namelen = sizeof(snl); - } - - buflen = recvmsg(udev_monitor->sock, &smsg, 0); - if (buflen < 0) { - if (errno != EINTR) - info(udev_monitor->udev, "unable to receive message\n"); - return NULL; - } - - if (buflen < 32 || (size_t)buflen >= sizeof(buf)) { - info(udev_monitor->udev, "invalid message length\n"); - return NULL; - } - - if (udev_monitor->snl.nl_family != 0) { - if (snl.nl_groups == 0) { - /* unicast message, check if we trust the sender */ - if (udev_monitor->snl_trusted_sender.nl_pid == 0 || - snl.nl_pid != udev_monitor->snl_trusted_sender.nl_pid) { - info(udev_monitor->udev, "unicast netlink message ignored\n"); - return NULL; - } - } else if (snl.nl_groups == UDEV_MONITOR_KERNEL) { - if (snl.nl_pid > 0) { - info(udev_monitor->udev, "multicast kernel netlink message from pid %d ignored\n", - snl.nl_pid); - return NULL; - } - } - } - - cmsg = CMSG_FIRSTHDR(&smsg); - if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) { - info(udev_monitor->udev, "no sender credentials received, message ignored\n"); - return NULL; - } - - cred = (struct ucred *)CMSG_DATA(cmsg); - if (cred->uid != 0) { - info(udev_monitor->udev, "sender uid=%d, message ignored\n", cred->uid); - return NULL; - } - - if (memcmp(buf, "libudev", 8) == 0) { - /* udev message needs proper version magic */ - nlh = (struct udev_monitor_netlink_header *) buf; - if (nlh->magic != htonl(UDEV_MONITOR_MAGIC)) { - err(udev_monitor->udev, "unrecognized message signature (%x != %x)\n", - nlh->magic, htonl(UDEV_MONITOR_MAGIC)); - return NULL; - } - if (nlh->properties_off+32 > buflen) - return NULL; - bufpos = nlh->properties_off; - } else { - /* kernel message with header */ - bufpos = strlen(buf) + 1; - if ((size_t)bufpos < sizeof("a@/d") || bufpos >= buflen) { - info(udev_monitor->udev, "invalid message length\n"); - return NULL; - } - - /* check message header */ - if (strstr(buf, "@/") == NULL) { - info(udev_monitor->udev, "unrecognized message header\n"); - return NULL; - } - } - - udev_device = udev_device_new(udev_monitor->udev); - if (udev_device == NULL) - return NULL; - udev_device_set_info_loaded(udev_device); - - while (bufpos < buflen) { - char *key; - size_t keylen; - - key = &buf[bufpos]; - keylen = strlen(key); - if (keylen == 0) - break; - bufpos += keylen + 1; - udev_device_add_property_from_string_parse(udev_device, key); - } - - if (udev_device_add_property_from_string_parse_finish(udev_device) < 0) { - info(udev_monitor->udev, "missing values, invalid device\n"); - udev_device_unref(udev_device); - return NULL; - } - - /* skip device, if it does not pass the current filter */ - if (!passes_filter(udev_monitor, udev_device)) { - struct pollfd pfd[1]; - int rc; - - udev_device_unref(udev_device); - - /* if something is queued, get next device */ - pfd[0].fd = udev_monitor->sock; - pfd[0].events = POLLIN; - rc = poll(pfd, 1, 0); - if (rc > 0) - goto retry; - return NULL; - } - - return udev_device; -} - -int udev_monitor_send_device(struct udev_monitor *udev_monitor, - struct udev_monitor *destination, struct udev_device *udev_device) -{ - const char *buf; - ssize_t blen; - ssize_t count; - - blen = udev_device_get_properties_monitor_buf(udev_device, &buf); - if (blen < 32) - return -EINVAL; - - if (udev_monitor->sun.sun_family != 0) { - struct msghdr smsg; - struct iovec iov[2]; - const char *action; - char header[2048]; - char *s; - - /* header <action>@<devpath> */ - action = udev_device_get_action(udev_device); - if (action == NULL) - return -EINVAL; - s = header; - if (util_strpcpyl(&s, sizeof(header), action, "@", udev_device_get_devpath(udev_device), NULL) == 0) - return -EINVAL; - iov[0].iov_base = header; - iov[0].iov_len = (s - header)+1; - - /* add properties list */ - iov[1].iov_base = (char *)buf; - iov[1].iov_len = blen; - - memset(&smsg, 0x00, sizeof(struct msghdr)); - smsg.msg_iov = iov; - smsg.msg_iovlen = 2; - smsg.msg_name = &udev_monitor->sun; - smsg.msg_namelen = udev_monitor->addrlen; - count = sendmsg(udev_monitor->sock, &smsg, 0); - info(udev_monitor->udev, "passed %zi bytes to socket monitor %p\n", count, udev_monitor); - return count; - } - - if (udev_monitor->snl.nl_family != 0) { - struct msghdr smsg; - struct iovec iov[2]; - const char *val; - struct udev_monitor_netlink_header nlh; - struct udev_list_entry *list_entry; - uint64_t tag_bloom_bits; - - /* add versioned header */ - memset(&nlh, 0x00, sizeof(struct udev_monitor_netlink_header)); - memcpy(nlh.prefix, "libudev", 8); - nlh.magic = htonl(UDEV_MONITOR_MAGIC); - nlh.header_size = sizeof(struct udev_monitor_netlink_header); - val = udev_device_get_subsystem(udev_device); - nlh.filter_subsystem_hash = htonl(util_string_hash32(val)); - val = udev_device_get_devtype(udev_device); - if (val != NULL) - nlh.filter_devtype_hash = htonl(util_string_hash32(val)); - iov[0].iov_base = &nlh; - iov[0].iov_len = sizeof(struct udev_monitor_netlink_header); - - /* add tag bloom filter */ - tag_bloom_bits = 0; - udev_list_entry_foreach(list_entry, udev_device_get_tags_list_entry(udev_device)) - tag_bloom_bits |= util_string_bloom64(udev_list_entry_get_name(list_entry)); - if (tag_bloom_bits > 0) { - nlh.filter_tag_bloom_hi = htonl(tag_bloom_bits >> 32); - nlh.filter_tag_bloom_lo = htonl(tag_bloom_bits & 0xffffffff); - } - - /* add properties list */ - nlh.properties_off = iov[0].iov_len; - nlh.properties_len = blen; - iov[1].iov_base = (char *)buf; - iov[1].iov_len = blen; - - memset(&smsg, 0x00, sizeof(struct msghdr)); - smsg.msg_iov = iov; - smsg.msg_iovlen = 2; - /* - * Use custom address for target, or the default one. - * - * If we send to a multicast group, we will get - * ECONNREFUSED, which is expected. - */ - if (destination != NULL) - smsg.msg_name = &destination->snl; - else - smsg.msg_name = &udev_monitor->snl_destination; - smsg.msg_namelen = sizeof(struct sockaddr_nl); - count = sendmsg(udev_monitor->sock, &smsg, 0); - info(udev_monitor->udev, "passed %zi bytes to netlink monitor %p\n", count, udev_monitor); - return count; - } - - return -EINVAL; -} - -/** - * udev_monitor_filter_add_match_subsystem_devtype: - * @udev_monitor: the monitor - * @subsystem: the subsystem value to match the incoming devices against - * @devtype: the devtype value to match the incoming devices against - * - * This filter is efficiently executed inside the kernel, and libudev subscribers - * will usually not be woken up for devices which do not match. - * - * The filter must be installed before the monitor is switched to listening mode. - * - * Returns: 0 on success, otherwise a negative error value. - */ -UDEV_EXPORT int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_monitor, const char *subsystem, const char *devtype) -{ - if (udev_monitor == NULL) - return -EINVAL; - if (subsystem == NULL) - return -EINVAL; - if (udev_list_entry_add(&udev_monitor->filter_subsystem_list, subsystem, devtype) == NULL) - return -ENOMEM; - return 0; -} - -/** - * udev_monitor_filter_add_match_tag: - * @udev_monitor: the monitor - * @tag: the name of a tag - * - * This filter is efficiently executed inside the kernel, and libudev subscribers - * will usually not be woken up for devices which do not match. - * - * The filter must be installed before the monitor is switched to listening mode. - * - * Returns: 0 on success, otherwise a negative error value. - */ -UDEV_EXPORT int udev_monitor_filter_add_match_tag(struct udev_monitor *udev_monitor, const char *tag) -{ - if (udev_monitor == NULL) - return -EINVAL; - if (tag == NULL) - return -EINVAL; - if (udev_list_entry_add(&udev_monitor->filter_tag_list, tag, NULL) == NULL) - return -ENOMEM; - return 0; -} - -/** - * udev_monitor_filter_remove: - * @udev_monitor: monitor - * - * Remove all filters from monitor. - * - * Returns: 0 on success, otherwise a negative error value. - */ -UDEV_EXPORT int udev_monitor_filter_remove(struct udev_monitor *udev_monitor) -{ - static struct sock_fprog filter = { 0, NULL }; - - udev_list_cleanup(&udev_monitor->filter_subsystem_list); - return setsockopt(udev_monitor->sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)); -} diff --git a/libudev/libudev-private.h b/libudev/libudev-private.h deleted file mode 100644 index 83976698a9..0000000000 --- a/libudev/libudev-private.h +++ /dev/null @@ -1,213 +0,0 @@ -/* - * libudev - interface to udev device information - * - * Copyright (C) 2008-2010 Kay Sievers <kay.sievers@vrfy.org> - * - * 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. - */ - -#ifndef _LIBUDEV_PRIVATE_H_ -#define _LIBUDEV_PRIVATE_H_ - -#include <syslog.h> -#include <signal.h> -#include <stdint.h> -#include <stdbool.h> -#include "libudev.h" - -#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) -#define READ_END 0 -#define WRITE_END 1 - -static inline void __attribute__((always_inline, format(printf, 2, 3))) -udev_log_null(struct udev *udev, const char *format, ...) {} - -#define udev_log_cond(udev, prio, arg...) \ - do { \ - if (udev_get_log_priority(udev) >= prio) \ - udev_log(udev, prio, __FILE__, __LINE__, __FUNCTION__, ## arg); \ - } while (0) - -#ifdef ENABLE_LOGGING -# ifdef ENABLE_DEBUG -# define dbg(udev, arg...) udev_log_cond(udev, LOG_DEBUG, ## arg) -# else -# define dbg(udev, arg...) udev_log_null(udev, ## arg) -# endif -# define info(udev, arg...) udev_log_cond(udev, LOG_INFO, ## arg) -# define err(udev, arg...) udev_log_cond(udev, LOG_ERR, ## arg) -#else -# define dbg(udev, arg...) udev_log_null(udev, ## arg) -# define info(udev, arg...) udev_log_null(udev, ## arg) -# define err(udev, arg...) udev_log_null(udev, ## arg) -#endif - -#define UDEV_EXPORT __attribute__ ((visibility("default"))) - -static inline void udev_log_init(const char *program_name) -{ - openlog(program_name, LOG_PID | LOG_CONS, LOG_DAEMON); -} - -static inline void udev_log_close(void) -{ - closelog(); -} - -/* libudev.c */ -void udev_log(struct udev *udev, - int priority, const char *file, int line, const char *fn, - const char *format, ...) - __attribute__((format(printf, 6, 7))); -int udev_get_rules_path(struct udev *udev, char **path[], unsigned long long *ts_usec[]); -struct udev_list_entry *udev_add_property(struct udev *udev, const char *key, const char *value); -struct udev_list_entry *udev_get_properties_list_entry(struct udev *udev); - -/* libudev-device.c */ -struct udev_device *udev_device_new(struct udev *udev); -struct udev_device *udev_device_new_from_id_filename(struct udev *udev, char *id); -mode_t udev_device_get_devnode_mode(struct udev_device *udev_device); -int udev_device_set_syspath(struct udev_device *udev_device, const char *syspath); -int udev_device_set_devnode(struct udev_device *udev_device, const char *devnode); -int udev_device_add_devlink(struct udev_device *udev_device, const char *devlink, int unique); -void udev_device_cleanup_devlinks_list(struct udev_device *udev_device); -struct udev_list_entry *udev_device_add_property(struct udev_device *udev_device, const char *key, const char *value); -void udev_device_add_property_from_string_parse(struct udev_device *udev_device, const char *property); -int udev_device_add_property_from_string_parse_finish(struct udev_device *udev_device); -char **udev_device_get_properties_envp(struct udev_device *udev_device); -ssize_t udev_device_get_properties_monitor_buf(struct udev_device *udev_device, const char **buf); -int udev_device_read_db(struct udev_device *udev_device, const char *dbfile); -int udev_device_read_uevent_file(struct udev_device *udev_device); -int udev_device_set_action(struct udev_device *udev_device, const char *action); -const char *udev_device_get_devpath_old(struct udev_device *udev_device); -const char *udev_device_get_id_filename(struct udev_device *udev_device); -void udev_device_set_is_initialized(struct udev_device *udev_device); -int udev_device_add_tag(struct udev_device *udev_device, const char *tag); -void udev_device_cleanup_tags_list(struct udev_device *udev_device); -unsigned long long udev_device_get_usec_initialized(struct udev_device *udev_device); -void udev_device_set_usec_initialized(struct udev_device *udev_device, unsigned long long usec_initialized); -int udev_device_get_devlink_priority(struct udev_device *udev_device); -int udev_device_set_devlink_priority(struct udev_device *udev_device, int prio); -int udev_device_get_watch_handle(struct udev_device *udev_device); -int udev_device_set_watch_handle(struct udev_device *udev_device, int handle); -int udev_device_get_ifindex(struct udev_device *udev_device); -void udev_device_set_info_loaded(struct udev_device *device); -bool udev_device_get_db_persist(struct udev_device *udev_device); -void udev_device_set_db_persist(struct udev_device *udev_device); - -/* libudev-device-private.c */ -int udev_device_update_db(struct udev_device *udev_device); -int udev_device_delete_db(struct udev_device *udev_device); -int udev_device_tag_index(struct udev_device *dev, struct udev_device *dev_old, bool add); - -/* libudev-monitor.c - netlink/unix socket communication */ -int udev_monitor_disconnect(struct udev_monitor *udev_monitor); -int udev_monitor_allow_unicast_sender(struct udev_monitor *udev_monitor, struct udev_monitor *sender); -int udev_monitor_send_device(struct udev_monitor *udev_monitor, - struct udev_monitor *destination, struct udev_device *udev_device); -struct udev_monitor *udev_monitor_new_from_netlink_fd(struct udev *udev, const char *name, int fd); - -/* libudev-list.c */ -struct udev_list_node { - struct udev_list_node *next, *prev; -}; -struct udev_list { - struct udev *udev; - struct udev_list_node node; - struct udev_list_entry **entries; - unsigned int entries_cur; - unsigned int entries_max; - bool unique; -}; -#define UDEV_LIST(list) struct udev_list_node list = { &(list), &(list) } -void udev_list_node_init(struct udev_list_node *list); -int udev_list_node_is_empty(struct udev_list_node *list); -void udev_list_node_append(struct udev_list_node *new, struct udev_list_node *list); -void udev_list_node_remove(struct udev_list_node *entry); -#define udev_list_node_foreach(node, list) \ - for (node = (list)->next; \ - node != list; \ - node = (node)->next) -#define udev_list_node_foreach_safe(node, tmp, list) \ - for (node = (list)->next, tmp = (node)->next; \ - node != list; \ - node = tmp, tmp = (tmp)->next) -void udev_list_init(struct udev *udev, struct udev_list *list, bool unique); -void udev_list_cleanup(struct udev_list *list); -struct udev_list_entry *udev_list_get_entry(struct udev_list *list); -struct udev_list_entry *udev_list_entry_add(struct udev_list *list, const char *name, const char *value); -void udev_list_entry_delete(struct udev_list_entry *entry); -void udev_list_entry_insert_before(struct udev_list_entry *new, struct udev_list_entry *entry); -void udev_list_entry_append(struct udev_list_entry *new, struct udev_list *list); -int udev_list_entry_get_num(struct udev_list_entry *list_entry); -void udev_list_entry_set_num(struct udev_list_entry *list_entry, int num); -#define udev_list_entry_foreach_safe(entry, tmp, first) \ - for (entry = first, tmp = udev_list_entry_get_next(entry); \ - entry != NULL; \ - entry = tmp, tmp = udev_list_entry_get_next(tmp)) - -/* libudev-queue.c */ -unsigned long long int udev_get_kernel_seqnum(struct udev *udev); -int udev_queue_read_seqnum(FILE *queue_file, unsigned long long int *seqnum); -ssize_t udev_queue_read_devpath(FILE *queue_file, char *devpath, size_t size); -ssize_t udev_queue_skip_devpath(FILE *queue_file); - -/* libudev-queue-private.c */ -struct udev_queue_export *udev_queue_export_new(struct udev *udev); -struct udev_queue_export *udev_queue_export_unref(struct udev_queue_export *udev_queue_export); -void udev_queue_export_cleanup(struct udev_queue_export *udev_queue_export); -int udev_queue_export_device_queued(struct udev_queue_export *udev_queue_export, struct udev_device *udev_device); -int udev_queue_export_device_finished(struct udev_queue_export *udev_queue_export, struct udev_device *udev_device); - -/* libudev-util.c */ -#define UTIL_PATH_SIZE 1024 -#define UTIL_NAME_SIZE 512 -#define UTIL_LINE_SIZE 16384 -#define UDEV_ALLOWED_CHARS_INPUT "/ $%?," -ssize_t util_get_sys_core_link_value(struct udev *udev, const char *slink, const char *syspath, char *value, size_t size); -int util_resolve_sys_link(struct udev *udev, char *syspath, size_t size); -int util_log_priority(const char *priority); -size_t util_path_encode(const char *src, char *dest, size_t size); -size_t util_path_decode(char *s); -void util_remove_trailing_chars(char *path, char c); -size_t util_strpcpy(char **dest, size_t size, const char *src); -size_t util_strpcpyl(char **dest, size_t size, const char *src, ...) __attribute__((sentinel)); -size_t util_strscpy(char *dest, size_t size, const char *src); -size_t util_strscpyl(char *dest, size_t size, const char *src, ...) __attribute__((sentinel)); -int util_replace_whitespace(const char *str, char *to, size_t len); -int util_replace_chars(char *str, const char *white); -unsigned int util_string_hash32(const char *key); -uint64_t util_string_bloom64(const char *str); - -/* libudev-util-private.c */ -int util_create_path(struct udev *udev, const char *path); -int util_create_path_selinux(struct udev *udev, const char *path); -int util_delete_path(struct udev *udev, const char *path); -uid_t util_lookup_user(struct udev *udev, const char *user); -gid_t util_lookup_group(struct udev *udev, const char *group); -int util_resolve_subsys_kernel(struct udev *udev, const char *string, - char *result, size_t maxsize, int read_value); -unsigned long long ts_usec(const struct timespec *ts); -unsigned long long now_usec(void); - -/* libudev-selinux-private.c */ -#ifndef WITH_SELINUX -static inline void udev_selinux_init(struct udev *udev) {} -static inline void udev_selinux_exit(struct udev *udev) {} -static inline void udev_selinux_lsetfilecon(struct udev *udev, const char *file, unsigned int mode) {} -static inline void udev_selinux_setfscreatecon(struct udev *udev, const char *file, unsigned int mode) {} -static inline void udev_selinux_setfscreateconat(struct udev *udev, int dfd, const char *file, unsigned int mode) {} -static inline void udev_selinux_resetfscreatecon(struct udev *udev) {} -#else -void udev_selinux_init(struct udev *udev); -void udev_selinux_exit(struct udev *udev); -void udev_selinux_lsetfilecon(struct udev *udev, const char *file, unsigned int mode); -void udev_selinux_setfscreatecon(struct udev *udev, const char *file, unsigned int mode); -void udev_selinux_setfscreateconat(struct udev *udev, int dfd, const char *file, unsigned int mode); -void udev_selinux_resetfscreatecon(struct udev *udev); -#endif - -#endif diff --git a/libudev/libudev-queue-private.c b/libudev/libudev-queue-private.c deleted file mode 100644 index e0a7b53b81..0000000000 --- a/libudev/libudev-queue-private.c +++ /dev/null @@ -1,412 +0,0 @@ -/* - * libudev - interface to udev device information - * - * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org> - * Copyright (C) 2009 Alan Jenkins <alan-jenkins@tuffmail.co.uk> - * - * 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. - */ - -/* - * DISCLAIMER - The file format mentioned here is private to udev/libudev, - * and may be changed without notice. - * - * The udev event queue is exported as a binary log file. - * Each log record consists of a sequence number followed by the device path. - * - * When a new event is queued, its details are appended to the log. - * When the event finishes, a second record is appended to the log - * with the same sequence number but a devpath len of 0. - * - * Example: - * { 0x0000000000000001 } - * { 0x0000000000000001, 0x0019, "/devices/virtual/mem/null" }, - * { 0x0000000000000002, 0x001b, "/devices/virtual/mem/random" }, - * { 0x0000000000000001, 0x0000 }, - * { 0x0000000000000003, 0x0019, "/devices/virtual/mem/zero" }, - * - * Events 2 and 3 are still queued, but event 1 has finished. - * - * The queue does not grow indefinitely. It is periodically re-created - * to remove finished events. Atomic rename() makes this transparent to readers. - * - * The queue file starts with a single sequence number which specifies the - * minimum sequence number in the log that follows. Any events prior to this - * sequence number have already finished. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <fcntl.h> -#include <dirent.h> -#include <limits.h> -#include <errno.h> -#include <sys/stat.h> -#include <sys/types.h> - -#include "libudev.h" -#include "libudev-private.h" - -static int rebuild_queue_file(struct udev_queue_export *udev_queue_export); - -struct udev_queue_export { - struct udev *udev; - int queued_count; /* number of unfinished events exported in queue file */ - FILE *queue_file; - unsigned long long int seqnum_max; /* earliest sequence number in queue file */ - unsigned long long int seqnum_min; /* latest sequence number in queue file */ - int waste_bytes; /* queue file bytes wasted on finished events */ -}; - -struct udev_queue_export *udev_queue_export_new(struct udev *udev) -{ - struct udev_queue_export *udev_queue_export; - unsigned long long int initial_seqnum; - - if (udev == NULL) - return NULL; - - udev_queue_export = calloc(1, sizeof(struct udev_queue_export)); - if (udev_queue_export == NULL) - return NULL; - udev_queue_export->udev = udev; - - initial_seqnum = udev_get_kernel_seqnum(udev); - udev_queue_export->seqnum_min = initial_seqnum; - udev_queue_export->seqnum_max = initial_seqnum; - - udev_queue_export_cleanup(udev_queue_export); - if (rebuild_queue_file(udev_queue_export) != 0) { - free(udev_queue_export); - return NULL; - } - - return udev_queue_export; -} - -struct udev_queue_export *udev_queue_export_unref(struct udev_queue_export *udev_queue_export) -{ - if (udev_queue_export == NULL) - return NULL; - if (udev_queue_export->queue_file != NULL) - fclose(udev_queue_export->queue_file); - free(udev_queue_export); - return NULL; -} - -void udev_queue_export_cleanup(struct udev_queue_export *udev_queue_export) -{ - char filename[UTIL_PATH_SIZE]; - - if (udev_queue_export == NULL) - return; - util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev_queue_export->udev), "/queue.tmp", NULL); - unlink(filename); - util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev_queue_export->udev), "/queue.bin", NULL); - unlink(filename); -} - -static int skip_to(FILE *file, long offset) -{ - long old_offset; - - /* fseek may drop buffered data, avoid it for small seeks */ - old_offset = ftell(file); - if (offset > old_offset && offset - old_offset <= BUFSIZ) { - size_t skip_bytes = offset - old_offset; - char buf[skip_bytes]; - - if (fread(buf, skip_bytes, 1, file) != skip_bytes) - return -1; - } - - return fseek(file, offset, SEEK_SET); -} - -struct queue_devpaths { - unsigned int devpaths_first; /* index of first queued event */ - unsigned int devpaths_size; - long devpaths[]; /* seqnum -> offset of devpath in queue file (or 0) */ -}; - -/* - * Returns a table mapping seqnum to devpath file offset for currently queued events. - * devpaths[i] represents the event with seqnum = i + udev_queue_export->seqnum_min. - */ -static struct queue_devpaths *build_index(struct udev_queue_export *udev_queue_export) -{ - struct queue_devpaths *devpaths; - unsigned long long int range; - long devpath_offset; - ssize_t devpath_len; - unsigned long long int seqnum; - unsigned long long int n; - unsigned int i; - - /* seek to the first event in the file */ - rewind(udev_queue_export->queue_file); - udev_queue_read_seqnum(udev_queue_export->queue_file, &seqnum); - - /* allocate the table */ - range = udev_queue_export->seqnum_min - udev_queue_export->seqnum_max; - if (range - 1 > INT_MAX) { - err(udev_queue_export->udev, "queue file overflow\n"); - return NULL; - } - devpaths = calloc(1, sizeof(struct queue_devpaths) + (range + 1) * sizeof(long)); - if (devpaths == NULL) - return NULL; - devpaths->devpaths_size = range + 1; - - /* read all records and populate the table */ - for (;;) { - if (udev_queue_read_seqnum(udev_queue_export->queue_file, &seqnum) < 0) - break; - n = seqnum - udev_queue_export->seqnum_max; - if (n >= devpaths->devpaths_size) - goto read_error; - - devpath_offset = ftell(udev_queue_export->queue_file); - devpath_len = udev_queue_skip_devpath(udev_queue_export->queue_file); - if (devpath_len < 0) - goto read_error; - - if (devpath_len > 0) - devpaths->devpaths[n] = devpath_offset; - else - devpaths->devpaths[n] = 0; - } - - /* find first queued event */ - for (i = 0; i < devpaths->devpaths_size; i++) { - if (devpaths->devpaths[i] != 0) - break; - } - devpaths->devpaths_first = i; - - return devpaths; - -read_error: - err(udev_queue_export->udev, "queue file corrupted\n"); - free(devpaths); - return NULL; -} - -static int rebuild_queue_file(struct udev_queue_export *udev_queue_export) -{ - unsigned long long int seqnum; - struct queue_devpaths *devpaths = NULL; - char filename[UTIL_PATH_SIZE]; - char filename_tmp[UTIL_PATH_SIZE]; - FILE *new_queue_file = NULL; - unsigned int i; - - /* read old queue file */ - if (udev_queue_export->queue_file != NULL) { - dbg(udev_queue_export->udev, "compacting queue file, freeing %d bytes\n", - udev_queue_export->waste_bytes); - - devpaths = build_index(udev_queue_export); - if (devpaths != NULL) - udev_queue_export->seqnum_max += devpaths->devpaths_first; - } - if (devpaths == NULL) { - dbg(udev_queue_export->udev, "creating empty queue file\n"); - udev_queue_export->queued_count = 0; - udev_queue_export->seqnum_max = udev_queue_export->seqnum_min; - } - - /* create new queue file */ - util_strscpyl(filename_tmp, sizeof(filename_tmp), udev_get_run_path(udev_queue_export->udev), "/queue.tmp", NULL); - new_queue_file = fopen(filename_tmp, "w+"); - if (new_queue_file == NULL) - goto error; - seqnum = udev_queue_export->seqnum_max; - fwrite(&seqnum, 1, sizeof(unsigned long long int), new_queue_file); - - /* copy unfinished events only to the new file */ - if (devpaths != NULL) { - for (i = devpaths->devpaths_first; i < devpaths->devpaths_size; i++) { - char devpath[UTIL_PATH_SIZE]; - int err; - unsigned short devpath_len; - - if (devpaths->devpaths[i] != 0) - { - skip_to(udev_queue_export->queue_file, devpaths->devpaths[i]); - err = udev_queue_read_devpath(udev_queue_export->queue_file, devpath, sizeof(devpath)); - devpath_len = err; - - fwrite(&seqnum, sizeof(unsigned long long int), 1, new_queue_file); - fwrite(&devpath_len, sizeof(unsigned short), 1, new_queue_file); - fwrite(devpath, 1, devpath_len, new_queue_file); - } - seqnum++; - } - free(devpaths); - devpaths = NULL; - } - fflush(new_queue_file); - if (ferror(new_queue_file)) - goto error; - - /* rename the new file on top of the old one */ - util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev_queue_export->udev), "/queue.bin", NULL); - if (rename(filename_tmp, filename) != 0) - goto error; - - if (udev_queue_export->queue_file != NULL) - fclose(udev_queue_export->queue_file); - udev_queue_export->queue_file = new_queue_file; - udev_queue_export->waste_bytes = 0; - - return 0; - -error: - err(udev_queue_export->udev, "failed to create queue file: %m\n"); - udev_queue_export_cleanup(udev_queue_export); - - if (udev_queue_export->queue_file != NULL) { - fclose(udev_queue_export->queue_file); - udev_queue_export->queue_file = NULL; - } - if (new_queue_file != NULL) - fclose(new_queue_file); - - if (devpaths != NULL) - free(devpaths); - udev_queue_export->queued_count = 0; - udev_queue_export->waste_bytes = 0; - udev_queue_export->seqnum_max = udev_queue_export->seqnum_min; - - return -1; -} - -static int write_queue_record(struct udev_queue_export *udev_queue_export, - unsigned long long int seqnum, const char *devpath, size_t devpath_len) -{ - unsigned short len; - - if (udev_queue_export->queue_file == NULL) { - dbg(udev_queue_export->udev, "can't record event: queue file not available\n"); - return -1; - } - - if (fwrite(&seqnum, sizeof(unsigned long long int), 1, udev_queue_export->queue_file) != 1) - goto write_error; - - len = (devpath_len < USHRT_MAX) ? devpath_len : USHRT_MAX; - if (fwrite(&len, sizeof(unsigned short), 1, udev_queue_export->queue_file) != 1) - goto write_error; - if (len > 0) { - if (fwrite(devpath, 1, len, udev_queue_export->queue_file) != len) - goto write_error; - } - - /* *must* flush output; caller may fork */ - if (fflush(udev_queue_export->queue_file) != 0) - goto write_error; - - return 0; - -write_error: - /* if we failed half way through writing a record to a file, - we should not try to write any further records to it. */ - err(udev_queue_export->udev, "error writing to queue file: %m\n"); - fclose(udev_queue_export->queue_file); - udev_queue_export->queue_file = NULL; - - return -1; -} - -enum device_state { - DEVICE_QUEUED, - DEVICE_FINISHED, -}; - -static inline size_t queue_record_size(size_t devpath_len) -{ - return sizeof(unsigned long long int) + sizeof(unsigned short int) + devpath_len; -} - -static int update_queue(struct udev_queue_export *udev_queue_export, - struct udev_device *udev_device, enum device_state state) -{ - unsigned long long int seqnum = udev_device_get_seqnum(udev_device); - const char *devpath = NULL; - size_t devpath_len = 0; - int bytes; - int err; - - /* FINISHED records have a zero length devpath */ - if (state == DEVICE_QUEUED) { - devpath = udev_device_get_devpath(udev_device); - devpath_len = strlen(devpath); - } - - /* recover from an earlier failed rebuild */ - if (udev_queue_export->queue_file == NULL) { - if (rebuild_queue_file(udev_queue_export) != 0) - return -1; - } - - /* if we're removing the last event from the queue, that's the best time to rebuild it */ - if (state != DEVICE_QUEUED && udev_queue_export->queued_count == 1) { - /* we don't need to read the old queue file */ - fclose(udev_queue_export->queue_file); - udev_queue_export->queue_file = NULL; - rebuild_queue_file(udev_queue_export); - return 0; - } - - /* try to rebuild the queue files before they grow larger than one page. */ - bytes = ftell(udev_queue_export->queue_file) + queue_record_size(devpath_len); - if ((udev_queue_export->waste_bytes > bytes / 2) && bytes > 4096) - rebuild_queue_file(udev_queue_export); - - /* don't record a finished event, if we already dropped the event in a failed rebuild */ - if (seqnum < udev_queue_export->seqnum_max) - return 0; - - /* now write to the queue */ - if (state == DEVICE_QUEUED) { - udev_queue_export->queued_count++; - udev_queue_export->seqnum_min = seqnum; - } else { - udev_queue_export->waste_bytes += queue_record_size(devpath_len) + queue_record_size(0); - udev_queue_export->queued_count--; - } - err = write_queue_record(udev_queue_export, seqnum, devpath, devpath_len); - - /* try to handle ENOSPC */ - if (err != 0 && udev_queue_export->queued_count == 0) { - udev_queue_export_cleanup(udev_queue_export); - err = rebuild_queue_file(udev_queue_export); - } - - return err; -} - -static int update(struct udev_queue_export *udev_queue_export, - struct udev_device *udev_device, enum device_state state) -{ - if (update_queue(udev_queue_export, udev_device, state) != 0) - return -1; - - return 0; -} - -int udev_queue_export_device_queued(struct udev_queue_export *udev_queue_export, struct udev_device *udev_device) -{ - return update(udev_queue_export, udev_device, DEVICE_QUEUED); -} - -int udev_queue_export_device_finished(struct udev_queue_export *udev_queue_export, struct udev_device *udev_device) -{ - return update(udev_queue_export, udev_device, DEVICE_FINISHED); -} diff --git a/libudev/libudev-queue.c b/libudev/libudev-queue.c deleted file mode 100644 index 3d46b67d19..0000000000 --- a/libudev/libudev-queue.c +++ /dev/null @@ -1,474 +0,0 @@ -/* - * libudev - interface to udev device information - * - * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org> - * Copyright (C) 2009 Alan Jenkins <alan-jenkins@tuffmail.co.uk> - * - * 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. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <stddef.h> -#include <unistd.h> -#include <errno.h> -#include <string.h> -#include <dirent.h> -#include <fcntl.h> -#include <limits.h> -#include <sys/stat.h> - -#include "libudev.h" -#include "libudev-private.h" - -/** - * SECTION:libudev-queue - * @short_description: access to currently active events - * - * The udev daemon processes events asynchronously. All events which do not have - * interdependencies run in parallel. This exports the current state of the - * event processing queue, and the current event sequence numbers from the kernel - * and the udev daemon. - */ - -/** - * udev_queue: - * - * Opaque object representing the current event queue in the udev daemon. - */ -struct udev_queue { - struct udev *udev; - int refcount; - struct udev_list queue_list; -}; - -/** - * udev_queue_new: - * @udev: udev library context - * - * The initial refcount is 1, and needs to be decremented to - * release the resources of the udev queue context. - * - * Returns: the udev queue context, or #NULL on error. - **/ -UDEV_EXPORT struct udev_queue *udev_queue_new(struct udev *udev) -{ - struct udev_queue *udev_queue; - - if (udev == NULL) - return NULL; - - udev_queue = calloc(1, sizeof(struct udev_queue)); - if (udev_queue == NULL) - return NULL; - udev_queue->refcount = 1; - udev_queue->udev = udev; - udev_list_init(udev, &udev_queue->queue_list, false); - return udev_queue; -} - -/** - * udev_queue_ref: - * @udev_queue: udev queue context - * - * Take a reference of a udev queue context. - * - * Returns: the same udev queue context. - **/ -UDEV_EXPORT struct udev_queue *udev_queue_ref(struct udev_queue *udev_queue) -{ - if (udev_queue == NULL) - return NULL; - udev_queue->refcount++; - return udev_queue; -} - -/** - * udev_queue_unref: - * @udev_queue: udev queue context - * - * Drop a reference of a udev queue context. If the refcount reaches zero, - * the resources of the queue context will be released. - **/ -UDEV_EXPORT void udev_queue_unref(struct udev_queue *udev_queue) -{ - if (udev_queue == NULL) - return; - udev_queue->refcount--; - if (udev_queue->refcount > 0) - return; - udev_list_cleanup(&udev_queue->queue_list); - free(udev_queue); -} - -/** - * udev_queue_get_udev: - * @udev_queue: udev queue context - * - * Retrieve the udev library context the queue context was created with. - * - * Returns: the udev library context. - **/ -UDEV_EXPORT struct udev *udev_queue_get_udev(struct udev_queue *udev_queue) -{ - if (udev_queue == NULL) - return NULL; - return udev_queue->udev; -} - -unsigned long long int udev_get_kernel_seqnum(struct udev *udev) -{ - char filename[UTIL_PATH_SIZE]; - unsigned long long int seqnum; - int fd; - char buf[32]; - ssize_t len; - - util_strscpyl(filename, sizeof(filename), udev_get_sys_path(udev), "/kernel/uevent_seqnum", NULL); - fd = open(filename, O_RDONLY|O_CLOEXEC); - if (fd < 0) - return 0; - len = read(fd, buf, sizeof(buf)); - close(fd); - if (len <= 2) - return 0; - buf[len-1] = '\0'; - seqnum = strtoull(buf, NULL, 10); - return seqnum; -} - -/** - * udev_queue_get_kernel_seqnum: - * @udev_queue: udev queue context - * - * Returns: the current kernel event sequence number. - **/ -UDEV_EXPORT unsigned long long int udev_queue_get_kernel_seqnum(struct udev_queue *udev_queue) -{ - unsigned long long int seqnum; - - if (udev_queue == NULL) - return -EINVAL; - - seqnum = udev_get_kernel_seqnum(udev_queue->udev); - dbg(udev_queue->udev, "seqnum=%llu\n", seqnum); - return seqnum; -} - -int udev_queue_read_seqnum(FILE *queue_file, unsigned long long int *seqnum) -{ - if (fread(seqnum, sizeof(unsigned long long int), 1, queue_file) != 1) - return -1; - - return 0; -} - -ssize_t udev_queue_skip_devpath(FILE *queue_file) -{ - unsigned short int len; - - if (fread(&len, sizeof(unsigned short int), 1, queue_file) == 1) { - char devpath[len]; - - /* use fread to skip, fseek might drop buffered data */ - if (fread(devpath, 1, len, queue_file) == len) - return len; - } - - return -1; -} - -ssize_t udev_queue_read_devpath(FILE *queue_file, char *devpath, size_t size) -{ - unsigned short int read_bytes = 0; - unsigned short int len; - - if (fread(&len, sizeof(unsigned short int), 1, queue_file) != 1) - return -1; - - read_bytes = (len < size - 1) ? len : size - 1; - if (fread(devpath, 1, read_bytes, queue_file) != read_bytes) - return -1; - devpath[read_bytes] = '\0'; - - /* if devpath was too long, skip unread characters */ - if (read_bytes != len) { - unsigned short int skip_bytes = len - read_bytes; - char buf[skip_bytes]; - - if (fread(buf, 1, skip_bytes, queue_file) != skip_bytes) - return -1; - } - - return read_bytes; -} - -static FILE *open_queue_file(struct udev_queue *udev_queue, unsigned long long int *seqnum_start) -{ - char filename[UTIL_PATH_SIZE]; - FILE *queue_file; - - util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev_queue->udev), "/queue.bin", NULL); - queue_file = fopen(filename, "re"); - if (queue_file == NULL) - return NULL; - - if (udev_queue_read_seqnum(queue_file, seqnum_start) < 0) { - err(udev_queue->udev, "corrupt queue file\n"); - fclose(queue_file); - return NULL; - } - - return queue_file; -} - -/** - * udev_queue_get_udev_seqnum: - * @udev_queue: udev queue context - * - * Returns: the last known udev event sequence number. - **/ -UDEV_EXPORT unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *udev_queue) -{ - unsigned long long int seqnum_udev; - FILE *queue_file; - - queue_file = open_queue_file(udev_queue, &seqnum_udev); - if (queue_file == NULL) - return 0; - - for (;;) { - unsigned long long int seqnum; - ssize_t devpath_len; - - if (udev_queue_read_seqnum(queue_file, &seqnum) < 0) - break; - devpath_len = udev_queue_skip_devpath(queue_file); - if (devpath_len < 0) - break; - if (devpath_len > 0) - seqnum_udev = seqnum; - } - - fclose(queue_file); - return seqnum_udev; -} - -/** - * udev_queue_get_udev_is_active: - * @udev_queue: udev queue context - * - * Returns: a flag indicating if udev is active. - **/ -UDEV_EXPORT int udev_queue_get_udev_is_active(struct udev_queue *udev_queue) -{ - unsigned long long int seqnum_start; - FILE *queue_file; - - queue_file = open_queue_file(udev_queue, &seqnum_start); - if (queue_file == NULL) - return 0; - - fclose(queue_file); - return 1; -} - -/** - * udev_queue_get_queue_is_empty: - * @udev_queue: udev queue context - * - * Returns: a flag indicating if udev is currently handling events. - **/ -UDEV_EXPORT int udev_queue_get_queue_is_empty(struct udev_queue *udev_queue) -{ - unsigned long long int seqnum_kernel; - unsigned long long int seqnum_udev = 0; - int queued = 0; - int is_empty = 0; - FILE *queue_file; - - if (udev_queue == NULL) - return -EINVAL; - queue_file = open_queue_file(udev_queue, &seqnum_udev); - if (queue_file == NULL) - return 1; - - for (;;) { - unsigned long long int seqnum; - ssize_t devpath_len; - - if (udev_queue_read_seqnum(queue_file, &seqnum) < 0) - break; - devpath_len = udev_queue_skip_devpath(queue_file); - if (devpath_len < 0) - break; - - if (devpath_len > 0) { - queued++; - seqnum_udev = seqnum; - } else { - queued--; - } - } - - if (queued > 0) { - dbg(udev_queue->udev, "queue is not empty\n"); - goto out; - } - - seqnum_kernel = udev_queue_get_kernel_seqnum(udev_queue); - if (seqnum_udev < seqnum_kernel) { - dbg(udev_queue->udev, "queue is empty but kernel events still pending [%llu]<->[%llu]\n", - seqnum_kernel, seqnum_udev); - goto out; - } - - dbg(udev_queue->udev, "queue is empty\n"); - is_empty = 1; - -out: - fclose(queue_file); - return is_empty; -} - -/** - * udev_queue_get_seqnum_sequence_is_finished: - * @udev_queue: udev queue context - * @start: first event sequence number - * @end: last event sequence number - * - * Returns: a flag indicating if any of the sequence numbers in the given range is currently active. - **/ -UDEV_EXPORT int udev_queue_get_seqnum_sequence_is_finished(struct udev_queue *udev_queue, - unsigned long long int start, unsigned long long int end) -{ - unsigned long long int seqnum; - ssize_t devpath_len; - int unfinished; - FILE *queue_file; - - if (udev_queue == NULL) - return -EINVAL; - queue_file = open_queue_file(udev_queue, &seqnum); - if (queue_file == NULL) - return 1; - if (start < seqnum) - start = seqnum; - if (start > end) { - fclose(queue_file); - return 1; - } - if (end - start > INT_MAX - 1) { - fclose(queue_file); - return -EOVERFLOW; - } - - /* - * we might start with 0, and handle the initial seqnum - * only when we find an entry in the queue file - **/ - unfinished = end - start; - - do { - if (udev_queue_read_seqnum(queue_file, &seqnum) < 0) - break; - devpath_len = udev_queue_skip_devpath(queue_file); - if (devpath_len < 0) - break; - - /* - * we might start with an empty or re-build queue file, where - * the initial seqnum is not recorded as finished - */ - if (start == seqnum && devpath_len > 0) - unfinished++; - - if (devpath_len == 0) { - if (seqnum >= start && seqnum <= end) - unfinished--; - } - } while (unfinished > 0); - - fclose(queue_file); - - return (unfinished == 0); -} - -/** - * udev_queue_get_seqnum_is_finished: - * @udev_queue: udev queue context - * @seqnum: sequence number - * - * Returns: a flag indicating if the given sequence number is currently active. - **/ -UDEV_EXPORT int udev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, unsigned long long int seqnum) -{ - if (!udev_queue_get_seqnum_sequence_is_finished(udev_queue, seqnum, seqnum)) - return 0; - - dbg(udev_queue->udev, "seqnum: %llu finished\n", seqnum); - return 1; -} - -/** - * udev_queue_get_queued_list_entry: - * @udev_queue: udev queue context - * - * Returns: the first entry of the list of queued events. - **/ -UDEV_EXPORT struct udev_list_entry *udev_queue_get_queued_list_entry(struct udev_queue *udev_queue) -{ - unsigned long long int seqnum; - FILE *queue_file; - - if (udev_queue == NULL) - return NULL; - udev_list_cleanup(&udev_queue->queue_list); - - queue_file = open_queue_file(udev_queue, &seqnum); - if (queue_file == NULL) - return NULL; - - for (;;) { - char syspath[UTIL_PATH_SIZE]; - char *s; - size_t l; - ssize_t len; - char seqnum_str[32]; - struct udev_list_entry *list_entry; - - if (udev_queue_read_seqnum(queue_file, &seqnum) < 0) - break; - snprintf(seqnum_str, sizeof(seqnum_str), "%llu", seqnum); - - s = syspath; - l = util_strpcpyl(&s, sizeof(syspath), udev_get_sys_path(udev_queue->udev), NULL); - len = udev_queue_read_devpath(queue_file, s, l); - if (len < 0) - break; - - if (len > 0) { - udev_list_entry_add(&udev_queue->queue_list, syspath, seqnum_str); - } else { - udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_queue->queue_list)) { - if (strcmp(seqnum_str, udev_list_entry_get_value(list_entry)) == 0) { - udev_list_entry_delete(list_entry); - break; - } - } - } - } - fclose(queue_file); - - return udev_list_get_entry(&udev_queue->queue_list); -} - -struct udev_list_entry *udev_queue_get_failed_list_entry(struct udev_queue *udev_queue); -UDEV_EXPORT struct udev_list_entry *udev_queue_get_failed_list_entry(struct udev_queue *udev_queue) -{ - errno = ENOSYS; - return NULL; -} diff --git a/libudev/libudev-selinux-private.c b/libudev/libudev-selinux-private.c deleted file mode 100644 index cb06a280f7..0000000000 --- a/libudev/libudev-selinux-private.c +++ /dev/null @@ -1,109 +0,0 @@ -/* - * libudev - interface to udev device information - * - * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org> - * - * 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. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <stddef.h> -#include <stdarg.h> -#include <unistd.h> -#include <selinux/selinux.h> - -#include "libudev.h" -#include "libudev-private.h" - -static int selinux_enabled; -security_context_t selinux_prev_scontext; - -void udev_selinux_init(struct udev *udev) -{ - /* record the present security context */ - selinux_enabled = (is_selinux_enabled() > 0); - info(udev, "selinux=%i\n", selinux_enabled); - if (!selinux_enabled) - return; - matchpathcon_init_prefix(NULL, udev_get_dev_path(udev)); - if (getfscreatecon(&selinux_prev_scontext) < 0) { - err(udev, "getfscreatecon failed\n"); - selinux_prev_scontext = NULL; - } -} - -void udev_selinux_exit(struct udev *udev) -{ - if (!selinux_enabled) - return; - freecon(selinux_prev_scontext); - selinux_prev_scontext = NULL; -} - -void udev_selinux_lsetfilecon(struct udev *udev, const char *file, unsigned int mode) -{ - security_context_t scontext = NULL; - - if (!selinux_enabled) - return; - if (matchpathcon(file, mode, &scontext) < 0) { - err(udev, "matchpathcon(%s) failed\n", file); - return; - } - if (lsetfilecon(file, scontext) < 0) - err(udev, "setfilecon %s failed: %m\n", file); - freecon(scontext); -} - -void udev_selinux_setfscreatecon(struct udev *udev, const char *file, unsigned int mode) -{ - security_context_t scontext = NULL; - - if (!selinux_enabled) - return; - - if (matchpathcon(file, mode, &scontext) < 0) { - err(udev, "matchpathcon(%s) failed\n", file); - return; - } - if (setfscreatecon(scontext) < 0) - err(udev, "setfscreatecon %s failed: %m\n", file); - freecon(scontext); -} - -void udev_selinux_resetfscreatecon(struct udev *udev) -{ - if (!selinux_enabled) - return; - if (setfscreatecon(selinux_prev_scontext) < 0) - err(udev, "setfscreatecon failed: %m\n"); -} - -void udev_selinux_setfscreateconat(struct udev *udev, int dfd, const char *file, unsigned int mode) -{ - char filename[UTIL_PATH_SIZE]; - - if (!selinux_enabled) - return; - - /* resolve relative filename */ - if (file[0] != '/') { - char procfd[UTIL_PATH_SIZE]; - char target[UTIL_PATH_SIZE]; - ssize_t len; - - snprintf(procfd, sizeof(procfd), "/proc/%u/fd/%u", getpid(), dfd); - len = readlink(procfd, target, sizeof(target)); - if (len <= 0 || len == sizeof(target)) - return; - target[len] = '\0'; - - util_strscpyl(filename, sizeof(filename), target, "/", file, NULL); - file = filename; - } - udev_selinux_setfscreatecon(udev, file, mode); -} diff --git a/libudev/libudev-util-private.c b/libudev/libudev-util-private.c deleted file mode 100644 index 015e6d5862..0000000000 --- a/libudev/libudev-util-private.c +++ /dev/null @@ -1,242 +0,0 @@ -/* - * libudev - interface to udev device information - * - * Copyright (C) 2003-2009 Kay Sievers <kay.sievers@vrfy.org> - * - * 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. - */ - -#include <stdlib.h> -#include <stdio.h> -#include <stddef.h> -#include <unistd.h> -#include <string.h> -#include <fcntl.h> -#include <errno.h> -#include <ctype.h> -#include <pwd.h> -#include <grp.h> -#include <sys/param.h> - -#include "libudev.h" -#include "libudev-private.h" - -static int create_path(struct udev *udev, const char *path, bool selinux) -{ - char p[UTIL_PATH_SIZE]; - char *pos; - struct stat stats; - int err; - - util_strscpy(p, sizeof(p), path); - pos = strrchr(p, '/'); - if (pos == NULL) - return 0; - while (pos != p && pos[-1] == '/') - pos--; - if (pos == p) - return 0; - pos[0] = '\0'; - - dbg(udev, "stat '%s'\n", p); - if (stat(p, &stats) == 0) { - if ((stats.st_mode & S_IFMT) == S_IFDIR) - return 0; - else - return -ENOTDIR; - } - - err = util_create_path(udev, p); - if (err != 0) - return err; - - dbg(udev, "mkdir '%s'\n", p); - if (selinux) - udev_selinux_setfscreatecon(udev, p, S_IFDIR|0755); - err = mkdir(p, 0755); - if (err != 0) { - err = -errno; - if (err == -EEXIST && stat(p, &stats) == 0) { - if ((stats.st_mode & S_IFMT) == S_IFDIR) - err = 0; - else - err = -ENOTDIR; - } - } - if (selinux) - udev_selinux_resetfscreatecon(udev); - return err; -} - -int util_create_path(struct udev *udev, const char *path) -{ - return create_path(udev, path, false); -} - -int util_create_path_selinux(struct udev *udev, const char *path) -{ - return create_path(udev, path, true); -} - -int util_delete_path(struct udev *udev, const char *path) -{ - char p[UTIL_PATH_SIZE]; - char *pos; - int err = 0; - - if (path[0] == '/') - while(path[1] == '/') - path++; - util_strscpy(p, sizeof(p), path); - pos = strrchr(p, '/'); - if (pos == p || pos == NULL) - return 0; - - for (;;) { - *pos = '\0'; - pos = strrchr(p, '/'); - - /* don't remove the last one */ - if ((pos == p) || (pos == NULL)) - break; - - err = rmdir(p); - if (err < 0) { - if (errno == ENOENT) - err = 0; - break; - } - } - return err; -} - -uid_t util_lookup_user(struct udev *udev, const char *user) -{ - char *endptr; - size_t buflen = sysconf(_SC_GETPW_R_SIZE_MAX); - char buf[buflen]; - struct passwd pwbuf; - struct passwd *pw; - uid_t uid; - - if (strcmp(user, "root") == 0) - return 0; - uid = strtoul(user, &endptr, 10); - if (endptr[0] == '\0') - return uid; - - errno = getpwnam_r(user, &pwbuf, buf, buflen, &pw); - if (pw != NULL) - return pw->pw_uid; - if (errno == 0 || errno == ENOENT || errno == ESRCH) - err(udev, "specified user '%s' unknown\n", user); - else - err(udev, "error resolving user '%s': %m\n", user); - return 0; -} - -gid_t util_lookup_group(struct udev *udev, const char *group) -{ - char *endptr; - size_t buflen = sysconf(_SC_GETGR_R_SIZE_MAX); - char *buf; - struct group grbuf; - struct group *gr; - gid_t gid = 0; - - if (strcmp(group, "root") == 0) - return 0; - gid = strtoul(group, &endptr, 10); - if (endptr[0] == '\0') - return gid; - buf = NULL; - gid = 0; - for (;;) { - char *newbuf; - - newbuf = realloc(buf, buflen); - if (!newbuf) - break; - buf = newbuf; - errno = getgrnam_r(group, &grbuf, buf, buflen, &gr); - if (gr != NULL) { - gid = gr->gr_gid; - } else if (errno == ERANGE) { - buflen *= 2; - continue; - } else if (errno == 0 || errno == ENOENT || errno == ESRCH) { - err(udev, "specified group '%s' unknown\n", group); - } else { - err(udev, "error resolving group '%s': %m\n", group); - } - break; - } - free(buf); - return gid; -} - -/* handle "[<SUBSYSTEM>/<KERNEL>]<attribute>" format */ -int util_resolve_subsys_kernel(struct udev *udev, const char *string, - char *result, size_t maxsize, int read_value) -{ - char temp[UTIL_PATH_SIZE]; - char *subsys; - char *sysname; - struct udev_device *dev; - char *attr; - - if (string[0] != '[') - return -1; - - util_strscpy(temp, sizeof(temp), string); - - subsys = &temp[1]; - - sysname = strchr(subsys, '/'); - if (sysname == NULL) - return -1; - sysname[0] = '\0'; - sysname = &sysname[1]; - - attr = strchr(sysname, ']'); - if (attr == NULL) - return -1; - attr[0] = '\0'; - attr = &attr[1]; - if (attr[0] == '/') - attr = &attr[1]; - if (attr[0] == '\0') - attr = NULL; - - if (read_value && attr == NULL) - return -1; - - dev = udev_device_new_from_subsystem_sysname(udev, subsys, sysname); - if (dev == NULL) - return -1; - - if (read_value) { - const char *val; - - val = udev_device_get_sysattr_value(dev, attr); - if (val != NULL) - util_strscpy(result, maxsize, val); - else - result[0] = '\0'; - info(udev, "value '[%s/%s]%s' is '%s'\n", subsys, sysname, attr, result); - } else { - size_t l; - char *s; - - s = result; - l = util_strpcpyl(&s, maxsize, udev_device_get_syspath(dev), NULL); - if (attr != NULL) - util_strpcpyl(&s, l, "/", attr, NULL); - info(udev, "path '[%s/%s]%s' is '%s'\n", subsys, sysname, attr, result); - } - udev_device_unref(dev); - return 0; -} diff --git a/libudev/libudev-util.c b/libudev/libudev-util.c deleted file mode 100644 index 5369fe734e..0000000000 --- a/libudev/libudev-util.c +++ /dev/null @@ -1,568 +0,0 @@ -/* - * libudev - interface to udev device information - * - * Copyright (C) 2008-2011 Kay Sievers <kay.sievers@vrfy.org> - * - * 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. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <stddef.h> -#include <unistd.h> -#include <errno.h> -#include <string.h> -#include <dirent.h> -#include <ctype.h> -#include <fcntl.h> -#include <time.h> -#include <sys/stat.h> - -#include "libudev.h" -#include "libudev-private.h" - -/** - * SECTION:libudev-util - * @short_description: utils - */ - -ssize_t util_get_sys_core_link_value(struct udev *udev, const char *slink, const char *syspath, char *value, size_t size) -{ - char path[UTIL_PATH_SIZE]; - char target[UTIL_PATH_SIZE]; - ssize_t len; - const char *pos; - - util_strscpyl(path, sizeof(path), syspath, "/", slink, NULL); - len = readlink(path, target, sizeof(target)); - if (len <= 0 || len == (ssize_t)sizeof(target)) - return -1; - target[len] = '\0'; - pos = strrchr(target, '/'); - if (pos == NULL) - return -1; - pos = &pos[1]; - dbg(udev, "resolved link to: '%s'\n", pos); - return util_strscpy(value, size, pos); -} - -int util_resolve_sys_link(struct udev *udev, char *syspath, size_t size) -{ - char link_target[UTIL_PATH_SIZE]; - - ssize_t len; - int i; - int back; - char *base; - - len = readlink(syspath, link_target, sizeof(link_target)); - if (len <= 0 || len == (ssize_t)sizeof(link_target)) - return -1; - link_target[len] = '\0'; - dbg(udev, "path link '%s' points to '%s'\n", syspath, link_target); - - for (back = 0; strncmp(&link_target[back * 3], "../", 3) == 0; back++) - ; - dbg(udev, "base '%s', tail '%s', back %i\n", syspath, &link_target[back * 3], back); - for (i = 0; i <= back; i++) { - base = strrchr(syspath, '/'); - if (base == NULL) - return -1; - base[0] = '\0'; - } - dbg(udev, "after moving back '%s'\n", syspath); - util_strscpyl(base, size - (base - syspath), "/", &link_target[back * 3], NULL); - return 0; -} - -int util_log_priority(const char *priority) -{ - char *endptr; - int prio; - - prio = strtol(priority, &endptr, 10); - if (endptr[0] == '\0' || isspace(endptr[0])) - return prio; - if (strncmp(priority, "err", 3) == 0) - return LOG_ERR; - if (strncmp(priority, "info", 4) == 0) - return LOG_INFO; - if (strncmp(priority, "debug", 5) == 0) - return LOG_DEBUG; - return 0; -} - -size_t util_path_encode(const char *src, char *dest, size_t size) -{ - size_t i, j; - - for (i = 0, j = 0; src[i] != '\0'; i++) { - if (src[i] == '/') { - if (j+4 >= size) { - j = 0; - break; - } - memcpy(&dest[j], "\\x2f", 4); - j += 4; - } else if (src[i] == '\\') { - if (j+4 >= size) { - j = 0; - break; - } - memcpy(&dest[j], "\\x5c", 4); - j += 4; - } else { - if (j+1 >= size) { - j = 0; - break; - } - dest[j] = src[i]; - j++; - } - } - dest[j] = '\0'; - return j; -} - -size_t util_path_decode(char *s) -{ - size_t i, j; - - for (i = 0, j = 0; s[i] != '\0'; j++) { - if (memcmp(&s[i], "\\x2f", 4) == 0) { - s[j] = '/'; - i += 4; - } else if (memcmp(&s[i], "\\x5c", 4) == 0) { - s[j] = '\\'; - i += 4; - } else { - s[j] = s[i]; - i++; - } - } - s[j] = '\0'; - return j; -} - -void util_remove_trailing_chars(char *path, char c) -{ - size_t len; - - if (path == NULL) - return; - len = strlen(path); - while (len > 0 && path[len-1] == c) - path[--len] = '\0'; -} - -/* - * Concatenates strings. In any case, terminates in _all_ cases with '\0' - * and moves the @dest pointer forward to the added '\0'. Returns the - * remaining size, and 0 if the string was truncated. - */ -size_t util_strpcpy(char **dest, size_t size, const char *src) -{ - size_t len; - - len = strlen(src); - if (len >= size) { - if (size > 1) - *dest = mempcpy(*dest, src, size-1); - size = 0; - *dest[0] = '\0'; - } else { - if (len > 0) { - *dest = mempcpy(*dest, src, len); - size -= len; - } - *dest[0] = '\0'; - } - return size; -} - -/* concatenates list of strings, moves dest forward */ -size_t util_strpcpyl(char **dest, size_t size, const char *src, ...) -{ - va_list va; - - va_start(va, src); - do { - size = util_strpcpy(dest, size, src); - src = va_arg(va, char *); - } while (src != NULL); - va_end(va); - - return size; -} - -/* copies string */ -size_t util_strscpy(char *dest, size_t size, const char *src) -{ - char *s; - - s = dest; - return util_strpcpy(&s, size, src); -} - -/* concatenates list of strings */ -size_t util_strscpyl(char *dest, size_t size, const char *src, ...) -{ - va_list va; - char *s; - - va_start(va, src); - s = dest; - do { - size = util_strpcpy(&s, size, src); - src = va_arg(va, char *); - } while (src != NULL); - va_end(va); - - return size; -} - -/* count of characters used to encode one unicode char */ -static int utf8_encoded_expected_len(const char *str) -{ - unsigned char c = (unsigned char)str[0]; - - if (c < 0x80) - return 1; - if ((c & 0xe0) == 0xc0) - return 2; - if ((c & 0xf0) == 0xe0) - return 3; - if ((c & 0xf8) == 0xf0) - return 4; - if ((c & 0xfc) == 0xf8) - return 5; - if ((c & 0xfe) == 0xfc) - return 6; - return 0; -} - -/* decode one unicode char */ -static int utf8_encoded_to_unichar(const char *str) -{ - int unichar; - int len; - int i; - - len = utf8_encoded_expected_len(str); - switch (len) { - case 1: - return (int)str[0]; - case 2: - unichar = str[0] & 0x1f; - break; - case 3: - unichar = (int)str[0] & 0x0f; - break; - case 4: - unichar = (int)str[0] & 0x07; - break; - case 5: - unichar = (int)str[0] & 0x03; - break; - case 6: - unichar = (int)str[0] & 0x01; - break; - default: - return -1; - } - - for (i = 1; i < len; i++) { - if (((int)str[i] & 0xc0) != 0x80) - return -1; - unichar <<= 6; - unichar |= (int)str[i] & 0x3f; - } - - return unichar; -} - -/* expected size used to encode one unicode char */ -static int utf8_unichar_to_encoded_len(int unichar) -{ - if (unichar < 0x80) - return 1; - if (unichar < 0x800) - return 2; - if (unichar < 0x10000) - return 3; - if (unichar < 0x200000) - return 4; - if (unichar < 0x4000000) - return 5; - return 6; -} - -/* check if unicode char has a valid numeric range */ -static int utf8_unichar_valid_range(int unichar) -{ - if (unichar > 0x10ffff) - return 0; - if ((unichar & 0xfffff800) == 0xd800) - return 0; - if ((unichar > 0xfdcf) && (unichar < 0xfdf0)) - return 0; - if ((unichar & 0xffff) == 0xffff) - return 0; - return 1; -} - -/* validate one encoded unicode char and return its length */ -static int utf8_encoded_valid_unichar(const char *str) -{ - int len; - int unichar; - int i; - - len = utf8_encoded_expected_len(str); - if (len == 0) - return -1; - - /* ascii is valid */ - if (len == 1) - return 1; - - /* check if expected encoded chars are available */ - for (i = 0; i < len; i++) - if ((str[i] & 0x80) != 0x80) - return -1; - - unichar = utf8_encoded_to_unichar(str); - - /* check if encoded length matches encoded value */ - if (utf8_unichar_to_encoded_len(unichar) != len) - return -1; - - /* check if value has valid range */ - if (!utf8_unichar_valid_range(unichar)) - return -1; - - return len; -} - -int util_replace_whitespace(const char *str, char *to, size_t len) -{ - size_t i, j; - - /* strip trailing whitespace */ - len = strnlen(str, len); - while (len && isspace(str[len-1])) - len--; - - /* strip leading whitespace */ - i = 0; - while (isspace(str[i]) && (i < len)) - i++; - - j = 0; - while (i < len) { - /* substitute multiple whitespace with a single '_' */ - if (isspace(str[i])) { - while (isspace(str[i])) - i++; - to[j++] = '_'; - } - to[j++] = str[i++]; - } - to[j] = '\0'; - return 0; -} - -static int is_whitelisted(char c, const char *white) -{ - if ((c >= '0' && c <= '9') || - (c >= 'A' && c <= 'Z') || - (c >= 'a' && c <= 'z') || - strchr("#+-.:=@_", c) != NULL || - (white != NULL && strchr(white, c) != NULL)) - return 1; - return 0; -} - -/* allow chars in whitelist, plain ascii, hex-escaping and valid utf8 */ -int util_replace_chars(char *str, const char *white) -{ - size_t i = 0; - int replaced = 0; - - while (str[i] != '\0') { - int len; - - if (is_whitelisted(str[i], white)) { - i++; - continue; - } - - /* accept hex encoding */ - if (str[i] == '\\' && str[i+1] == 'x') { - i += 2; - continue; - } - - /* accept valid utf8 */ - len = utf8_encoded_valid_unichar(&str[i]); - if (len > 1) { - i += len; - continue; - } - - /* if space is allowed, replace whitespace with ordinary space */ - if (isspace(str[i]) && white != NULL && strchr(white, ' ') != NULL) { - str[i] = ' '; - i++; - replaced++; - continue; - } - - /* everything else is replaced with '_' */ - str[i] = '_'; - i++; - replaced++; - } - return replaced; -} - -/** - * udev_util_encode_string: - * @str: input string to be encoded - * @str_enc: output string to store the encoded input string - * @len: maximum size of the output string, which may be - * four times as long as the input string - * - * Encode all potentially unsafe characters of a string to the - * corresponding 2 char hex value prefixed by '\x'. - * - * Returns: 0 if the entire string was copied, non-zero otherwise. - **/ -UDEV_EXPORT int udev_util_encode_string(const char *str, char *str_enc, size_t len) -{ - size_t i, j; - - if (str == NULL || str_enc == NULL) - return -1; - - for (i = 0, j = 0; str[i] != '\0'; i++) { - int seqlen; - - seqlen = utf8_encoded_valid_unichar(&str[i]); - if (seqlen > 1) { - if (len-j < (size_t)seqlen) - goto err; - memcpy(&str_enc[j], &str[i], seqlen); - j += seqlen; - i += (seqlen-1); - } else if (str[i] == '\\' || !is_whitelisted(str[i], NULL)) { - if (len-j < 4) - goto err; - sprintf(&str_enc[j], "\\x%02x", (unsigned char) str[i]); - j += 4; - } else { - if (len-j < 1) - goto err; - str_enc[j] = str[i]; - j++; - } - } - if (len-j < 1) - goto err; - str_enc[j] = '\0'; - return 0; -err: - return -1; -} - -/* - * http://sites.google.com/site/murmurhash/ - * - * All code is released to the public domain. For business purposes, - * Murmurhash is under the MIT license. - * - */ -static unsigned int murmur_hash2(const char *key, int len, unsigned int seed) -{ - /* - * 'm' and 'r' are mixing constants generated offline. - * They're not really 'magic', they just happen to work well. - */ - const unsigned int m = 0x5bd1e995; - const int r = 24; - - /* initialize the hash to a 'random' value */ - unsigned int h = seed ^ len; - - /* mix 4 bytes at a time into the hash */ - const unsigned char * data = (const unsigned char *)key; - - while(len >= 4) { - unsigned int k = *(unsigned int *)data; - - k *= m; - k ^= k >> r; - k *= m; - h *= m; - h ^= k; - - data += 4; - len -= 4; - } - - /* handle the last few bytes of the input array */ - switch(len) { - case 3: - h ^= data[2] << 16; - case 2: - h ^= data[1] << 8; - case 1: - h ^= data[0]; - h *= m; - }; - - /* do a few final mixes of the hash to ensure the last few bytes are well-incorporated */ - h ^= h >> 13; - h *= m; - h ^= h >> 15; - - return h; -} - -unsigned int util_string_hash32(const char *str) -{ - return murmur_hash2(str, strlen(str), 0); -} - -/* get a bunch of bit numbers out of the hash, and set the bits in our bit field */ -uint64_t util_string_bloom64(const char *str) -{ - uint64_t bits = 0; - unsigned int hash = util_string_hash32(str); - - bits |= 1LLU << (hash & 63); - bits |= 1LLU << ((hash >> 6) & 63); - bits |= 1LLU << ((hash >> 12) & 63); - bits |= 1LLU << ((hash >> 18) & 63); - return bits; -} - -#define USEC_PER_SEC 1000000ULL -#define NSEC_PER_USEC 1000ULL -unsigned long long ts_usec(const struct timespec *ts) -{ - return (unsigned long long) ts->tv_sec * USEC_PER_SEC + - (unsigned long long) ts->tv_nsec / NSEC_PER_USEC; -} - -unsigned long long now_usec(void) -{ - struct timespec ts; - - if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) - return 0; - return ts_usec(&ts); -} diff --git a/libudev/libudev.c b/libudev/libudev.c deleted file mode 100644 index f0f59e3a4d..0000000000 --- a/libudev/libudev.c +++ /dev/null @@ -1,457 +0,0 @@ -/* - * libudev - interface to udev device information - * - * Copyright (C) 2008-2010 Kay Sievers <kay.sievers@vrfy.org> - * - * 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. - */ - -#include <stdio.h> -#include <stdlib.h> -#include <stddef.h> -#include <stdarg.h> -#include <unistd.h> -#include <errno.h> -#include <string.h> -#include <ctype.h> -#include <time.h> - -#include "libudev.h" -#include "libudev-private.h" - -/** - * SECTION:libudev - * @short_description: libudev context - * - * The context contains the default values read from the udev config file, - * and is passed to all library operations. - */ - -/** - * udev: - * - * Opaque object representing the library context. - */ -struct udev { - int refcount; - void (*log_fn)(struct udev *udev, - int priority, const char *file, int line, const char *fn, - const char *format, va_list args); - void *userdata; - char *sys_path; - char *dev_path; - char *rules_path[4]; - unsigned long long rules_path_ts[4]; - int rules_path_count; - char *run_path; - struct udev_list properties_list; - int log_priority; -}; - -void udev_log(struct udev *udev, - int priority, const char *file, int line, const char *fn, - const char *format, ...) -{ - va_list args; - - va_start(args, format); - udev->log_fn(udev, priority, file, line, fn, format, args); - va_end(args); -} - -static void log_stderr(struct udev *udev, - int priority, const char *file, int line, const char *fn, - const char *format, va_list args) -{ - fprintf(stderr, "libudev: %s: ", fn); - vfprintf(stderr, format, args); -} - -/** - * udev_get_userdata: - * @udev: udev library context - * - * Retrieve stored data pointer from library context. This might be useful - * to access from callbacks like a custom logging function. - * - * Returns: stored userdata - **/ -UDEV_EXPORT void *udev_get_userdata(struct udev *udev) -{ - if (udev == NULL) - return NULL; - return udev->userdata; -} - -/** - * udev_set_userdata: - * @udev: udev library context - * @userdata: data pointer - * - * Store custom @userdata in the library context. - **/ -UDEV_EXPORT void udev_set_userdata(struct udev *udev, void *userdata) -{ - if (udev == NULL) - return; - udev->userdata = userdata; -} - -static char *set_value(char **s, const char *v) -{ - free(*s); - *s = strdup(v); - util_remove_trailing_chars(*s, '/'); - return *s; -} - -/** - * udev_new: - * - * Create udev library context. This reads the udev configuration - * file, and fills in the default values. - * - * The initial refcount is 1, and needs to be decremented to - * release the resources of the udev library context. - * - * Returns: a new udev library context - **/ -UDEV_EXPORT struct udev *udev_new(void) -{ - struct udev *udev; - const char *env; - char *config_file = NULL; - FILE *f; - - udev = calloc(1, sizeof(struct udev)); - if (udev == NULL) - return NULL; - udev->refcount = 1; - udev->log_fn = log_stderr; - udev->log_priority = LOG_ERR; - udev_list_init(udev, &udev->properties_list, true); - - /* custom config file */ - env = getenv("UDEV_CONFIG_FILE"); - if (env != NULL) { - if (set_value(&config_file, env) == NULL) - goto err; - udev_add_property(udev, "UDEV_CONFIG_FILE", config_file); - } - - /* default config file */ - if (config_file == NULL) - config_file = strdup(SYSCONFDIR "/udev/udev.conf"); - if (config_file == NULL) - goto err; - - f = fopen(config_file, "re"); - if (f != NULL) { - char line[UTIL_LINE_SIZE]; - int line_nr = 0; - - while (fgets(line, sizeof(line), f)) { - size_t len; - char *key; - char *val; - - line_nr++; - - /* find key */ - key = line; - while (isspace(key[0])) - key++; - - /* comment or empty line */ - if (key[0] == '#' || key[0] == '\0') - continue; - - /* split key/value */ - val = strchr(key, '='); - if (val == NULL) { - err(udev, "missing <key>=<value> in '%s'[%i], skip line\n", config_file, line_nr); - continue; - } - val[0] = '\0'; - val++; - - /* find value */ - while (isspace(val[0])) - val++; - - /* terminate key */ - len = strlen(key); - if (len == 0) - continue; - while (isspace(key[len-1])) - len--; - key[len] = '\0'; - - /* terminate value */ - len = strlen(val); - if (len == 0) - continue; - while (isspace(val[len-1])) - len--; - val[len] = '\0'; - - if (len == 0) - continue; - - /* unquote */ - if (val[0] == '"' || val[0] == '\'') { - if (val[len-1] != val[0]) { - err(udev, "inconsistent quoting in '%s'[%i], skip line\n", config_file, line_nr); - continue; - } - val[len-1] = '\0'; - val++; - } - - if (strcmp(key, "udev_log") == 0) { - udev_set_log_priority(udev, util_log_priority(val)); - continue; - } - if (strcmp(key, "udev_root") == 0) { - set_value(&udev->dev_path, val); - continue; - } - if (strcmp(key, "udev_run") == 0) { - set_value(&udev->run_path, val); - continue; - } - if (strcmp(key, "udev_sys") == 0) { - set_value(&udev->sys_path, val); - continue; - } - if (strcmp(key, "udev_rules") == 0) { - set_value(&udev->rules_path[0], val); - udev->rules_path_count = 1; - continue; - } - } - fclose(f); - } - - /* environment overwrites config */ - env = getenv("UDEV_LOG"); - if (env != NULL) - udev_set_log_priority(udev, util_log_priority(env)); - - /* set defaults */ - if (udev->dev_path == NULL) - if (set_value(&udev->dev_path, "/dev") == NULL) - goto err; - - if (udev->sys_path == NULL) - if (set_value(&udev->sys_path, "/sys") == NULL) - goto err; - - if (udev->run_path == NULL) - if (set_value(&udev->run_path, "/run/udev") == NULL) - goto err; - - if (udev->rules_path[0] == NULL) { - /* /usr/lib/udev -- system rules */ - udev->rules_path[0] = strdup(PKGLIBEXECDIR "/rules.d"); - if (!udev->rules_path[0]) - goto err; - - /* /etc/udev -- local administration rules */ - udev->rules_path[1] = strdup(SYSCONFDIR "/udev/rules.d"); - if (!udev->rules_path[1]) - goto err; - - /* /run/udev -- runtime rules */ - if (asprintf(&udev->rules_path[2], "%s/rules.d", udev->run_path) < 0) - goto err; - - udev->rules_path_count = 3; - } - - dbg(udev, "context %p created\n", udev); - dbg(udev, "log_priority=%d\n", udev->log_priority); - dbg(udev, "config_file='%s'\n", config_file); - dbg(udev, "dev_path='%s'\n", udev->dev_path); - dbg(udev, "sys_path='%s'\n", udev->sys_path); - dbg(udev, "run_path='%s'\n", udev->run_path); - dbg(udev, "rules_path='%s':'%s':'%s'\n", udev->rules_path[0], udev->rules_path[1], udev->rules_path[2]); - free(config_file); - return udev; -err: - free(config_file); - err(udev, "context creation failed\n"); - udev_unref(udev); - return NULL; -} - -/** - * udev_ref: - * @udev: udev library context - * - * Take a reference of the udev library context. - * - * Returns: the passed udev library context - **/ -UDEV_EXPORT struct udev *udev_ref(struct udev *udev) -{ - if (udev == NULL) - return NULL; - udev->refcount++; - return udev; -} - -/** - * udev_unref: - * @udev: udev library context - * - * Drop a reference of the udev library context. If the refcount - * reaches zero, the resources of the context will be released. - * - **/ -UDEV_EXPORT void udev_unref(struct udev *udev) -{ - if (udev == NULL) - return; - udev->refcount--; - if (udev->refcount > 0) - return; - udev_list_cleanup(&udev->properties_list); - free(udev->dev_path); - free(udev->sys_path); - free(udev->rules_path[0]); - free(udev->rules_path[1]); - free(udev->rules_path[2]); - free(udev->run_path); - dbg(udev, "context %p released\n", udev); - free(udev); -} - -/** - * udev_set_log_fn: - * @udev: udev library context - * @log_fn: function to be called for logging messages - * - * The built-in logging writes to stderr. It can be - * overridden by a custom function, to plug log messages - * into the users' logging functionality. - * - **/ -UDEV_EXPORT void udev_set_log_fn(struct udev *udev, - void (*log_fn)(struct udev *udev, - int priority, const char *file, int line, const char *fn, - const char *format, va_list args)) -{ - udev->log_fn = log_fn; - info(udev, "custom logging function %p registered\n", log_fn); -} - -/** - * udev_get_log_priority: - * @udev: udev library context - * - * The initial logging priority is read from the udev config file - * at startup. - * - * Returns: the current logging priority - **/ -UDEV_EXPORT int udev_get_log_priority(struct udev *udev) -{ - return udev->log_priority; -} - -/** - * udev_set_log_priority: - * @udev: udev library context - * @priority: the new logging priority - * - * Set the current logging priority. The value controls which messages - * are logged. - **/ -UDEV_EXPORT void udev_set_log_priority(struct udev *udev, int priority) -{ - char num[32]; - - udev->log_priority = priority; - snprintf(num, sizeof(num), "%u", udev->log_priority); - udev_add_property(udev, "UDEV_LOG", num); -} - -int udev_get_rules_path(struct udev *udev, char **path[], unsigned long long *stamp_usec[]) -{ - *path = udev->rules_path; - if (stamp_usec) - *stamp_usec = udev->rules_path_ts; - return udev->rules_path_count; -} - -/** - * udev_get_sys_path: - * @udev: udev library context - * - * Retrieve the sysfs mount point. The default is "/sys". For - * testing purposes, it can be overridden with udev_sys= - * in the udev configuration file. - * - * Returns: the sys mount point - **/ -UDEV_EXPORT const char *udev_get_sys_path(struct udev *udev) -{ - if (udev == NULL) - return NULL; - return udev->sys_path; -} - -/** - * udev_get_dev_path: - * @udev: udev library context - * - * Retrieve the device directory path. The default value is "/dev", - * the actual value may be overridden in the udev configuration - * file. - * - * Returns: the device directory path - **/ -UDEV_EXPORT const char *udev_get_dev_path(struct udev *udev) -{ - if (udev == NULL) - return NULL; - return udev->dev_path; -} - -/** - * udev_get_run_path: - * @udev: udev library context - * - * Retrieve the udev runtime directory path. The default is "/run/udev". - * - * Returns: the runtime directory path - **/ -UDEV_EXPORT const char *udev_get_run_path(struct udev *udev) -{ - if (udev == NULL) - return NULL; - return udev->run_path; -} - -struct udev_list_entry *udev_add_property(struct udev *udev, const char *key, const char *value) -{ - if (value == NULL) { - struct udev_list_entry *list_entry; - - list_entry = udev_get_properties_list_entry(udev); - list_entry = udev_list_entry_get_by_name(list_entry, key); - if (list_entry != NULL) - udev_list_entry_delete(list_entry); - return NULL; - } - return udev_list_entry_add(&udev->properties_list, key, value); -} - -struct udev_list_entry *udev_get_properties_list_entry(struct udev *udev) -{ - return udev_list_get_entry(&udev->properties_list); -} diff --git a/libudev/libudev.h b/libudev/libudev.h deleted file mode 100644 index 497f752fca..0000000000 --- a/libudev/libudev.h +++ /dev/null @@ -1,189 +0,0 @@ -/* - * libudev - interface to udev device information - * - * Copyright (C) 2008-2011 Kay Sievers <kay.sievers@vrfy.org> - * - * 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. - */ - -#ifndef _LIBUDEV_H_ -#define _LIBUDEV_H_ - -#include <stdarg.h> -#include <sys/types.h> -#include <sys/stat.h> - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * udev - library context - * - * reads the udev config and system environment - * allows custom logging - */ -struct udev; -struct udev *udev_ref(struct udev *udev); -void udev_unref(struct udev *udev); -struct udev *udev_new(void); -void udev_set_log_fn(struct udev *udev, - void (*log_fn)(struct udev *udev, - int priority, const char *file, int line, const char *fn, - const char *format, va_list args)); -int udev_get_log_priority(struct udev *udev); -void udev_set_log_priority(struct udev *udev, int priority); -const char *udev_get_sys_path(struct udev *udev); -const char *udev_get_dev_path(struct udev *udev); -const char *udev_get_run_path(struct udev *udev); -void *udev_get_userdata(struct udev *udev); -void udev_set_userdata(struct udev *udev, void *userdata); - -/* - * udev_list - * - * access to libudev generated lists - */ -struct udev_list_entry; -struct udev_list_entry *udev_list_entry_get_next(struct udev_list_entry *list_entry); -struct udev_list_entry *udev_list_entry_get_by_name(struct udev_list_entry *list_entry, const char *name); -const char *udev_list_entry_get_name(struct udev_list_entry *list_entry); -const char *udev_list_entry_get_value(struct udev_list_entry *list_entry); -/** - * udev_list_entry_foreach: - * @list_entry: entry to store the current position - * @first_entry: first entry to start with - * - * Helper to iterate over all entries of a list. - */ -#define udev_list_entry_foreach(list_entry, first_entry) \ - for (list_entry = first_entry; \ - list_entry != NULL; \ - list_entry = udev_list_entry_get_next(list_entry)) - -/* - * udev_device - * - * access to sysfs/kernel devices - */ -struct udev_device; -struct udev_device *udev_device_ref(struct udev_device *udev_device); -void udev_device_unref(struct udev_device *udev_device); -struct udev *udev_device_get_udev(struct udev_device *udev_device); -struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *syspath); -struct udev_device *udev_device_new_from_devnum(struct udev *udev, char type, dev_t devnum); -struct udev_device *udev_device_new_from_subsystem_sysname(struct udev *udev, const char *subsystem, const char *sysname); -struct udev_device *udev_device_new_from_environment(struct udev *udev); -/* udev_device_get_parent_*() does not take a reference on the returned device, it is automatically unref'd with the parent */ -struct udev_device *udev_device_get_parent(struct udev_device *udev_device); -struct udev_device *udev_device_get_parent_with_subsystem_devtype(struct udev_device *udev_device, - const char *subsystem, const char *devtype); -/* retrieve device properties */ -const char *udev_device_get_devpath(struct udev_device *udev_device); -const char *udev_device_get_subsystem(struct udev_device *udev_device); -const char *udev_device_get_devtype(struct udev_device *udev_device); -const char *udev_device_get_syspath(struct udev_device *udev_device); -const char *udev_device_get_sysname(struct udev_device *udev_device); -const char *udev_device_get_sysnum(struct udev_device *udev_device); -const char *udev_device_get_devnode(struct udev_device *udev_device); -int udev_device_get_is_initialized(struct udev_device *udev_device); -struct udev_list_entry *udev_device_get_devlinks_list_entry(struct udev_device *udev_device); -struct udev_list_entry *udev_device_get_properties_list_entry(struct udev_device *udev_device); -struct udev_list_entry *udev_device_get_tags_list_entry(struct udev_device *udev_device); -struct udev_list_entry *udev_device_get_sysattr_list_entry(struct udev_device *udev_device); -const char *udev_device_get_property_value(struct udev_device *udev_device, const char *key); -const char *udev_device_get_driver(struct udev_device *udev_device); -dev_t udev_device_get_devnum(struct udev_device *udev_device); -const char *udev_device_get_action(struct udev_device *udev_device); -unsigned long long int udev_device_get_seqnum(struct udev_device *udev_device); -unsigned long long int udev_device_get_usec_since_initialized(struct udev_device *udev_device); -const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const char *sysattr); -int udev_device_has_tag(struct udev_device *udev_device, const char *tag); - -/* - * udev_monitor - * - * access to kernel uevents and udev events - */ -struct udev_monitor; -struct udev_monitor *udev_monitor_ref(struct udev_monitor *udev_monitor); -void udev_monitor_unref(struct udev_monitor *udev_monitor); -struct udev *udev_monitor_get_udev(struct udev_monitor *udev_monitor); -/* kernel and udev generated events over netlink */ -struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, const char *name); -/* custom socket (use netlink and filters instead) */ -struct udev_monitor *udev_monitor_new_from_socket(struct udev *udev, const char *socket_path); -/* bind socket */ -int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor); -int udev_monitor_set_receive_buffer_size(struct udev_monitor *udev_monitor, int size); -int udev_monitor_get_fd(struct udev_monitor *udev_monitor); -struct udev_device *udev_monitor_receive_device(struct udev_monitor *udev_monitor); -/* in-kernel socket filters to select messages that get delivered to a listener */ -int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_monitor, - const char *subsystem, const char *devtype); -int udev_monitor_filter_add_match_tag(struct udev_monitor *udev_monitor, const char *tag); -int udev_monitor_filter_update(struct udev_monitor *udev_monitor); -int udev_monitor_filter_remove(struct udev_monitor *udev_monitor); - -/* - * udev_enumerate - * - * search sysfs for specific devices and provide a sorted list - */ -struct udev_enumerate; -struct udev_enumerate *udev_enumerate_ref(struct udev_enumerate *udev_enumerate); -void udev_enumerate_unref(struct udev_enumerate *udev_enumerate); -struct udev *udev_enumerate_get_udev(struct udev_enumerate *udev_enumerate); -struct udev_enumerate *udev_enumerate_new(struct udev *udev); -/* device properties filter */ -int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem); -int udev_enumerate_add_nomatch_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem); -int udev_enumerate_add_match_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value); -int udev_enumerate_add_nomatch_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value); -int udev_enumerate_add_match_property(struct udev_enumerate *udev_enumerate, const char *property, const char *value); -int udev_enumerate_add_match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname); -int udev_enumerate_add_match_tag(struct udev_enumerate *udev_enumerate, const char *tag); -int udev_enumerate_add_match_parent(struct udev_enumerate *udev_enumerate, struct udev_device *parent); -int udev_enumerate_add_match_is_initialized(struct udev_enumerate *udev_enumerate); -int udev_enumerate_add_syspath(struct udev_enumerate *udev_enumerate, const char *syspath); -/* run enumeration with active filters */ -int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate); -int udev_enumerate_scan_subsystems(struct udev_enumerate *udev_enumerate); -/* return device list */ -struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *udev_enumerate); - -/* - * udev_queue - * - * access to the currently running udev events - */ -struct udev_queue; -struct udev_queue *udev_queue_ref(struct udev_queue *udev_queue); -void udev_queue_unref(struct udev_queue *udev_queue); -struct udev *udev_queue_get_udev(struct udev_queue *udev_queue); -struct udev_queue *udev_queue_new(struct udev *udev); -unsigned long long int udev_queue_get_kernel_seqnum(struct udev_queue *udev_queue); -unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *udev_queue); -int udev_queue_get_udev_is_active(struct udev_queue *udev_queue); -int udev_queue_get_queue_is_empty(struct udev_queue *udev_queue); -int udev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, unsigned long long int seqnum); -int udev_queue_get_seqnum_sequence_is_finished(struct udev_queue *udev_queue, - unsigned long long int start, unsigned long long int end); -struct udev_list_entry *udev_queue_get_queued_list_entry(struct udev_queue *udev_queue); - -/* - * udev_util - * - * udev specific utilities - */ -int udev_util_encode_string(const char *str, char *str_enc, size_t len); - - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif diff --git a/libudev/libudev.pc.in b/libudev/libudev.pc.in deleted file mode 100644 index 93c8366480..0000000000 --- a/libudev/libudev.pc.in +++ /dev/null @@ -1,11 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ - -Name: libudev -Description: Library to access udev device information -Version: @VERSION@ -Libs: -L${libdir} -ludev -lrt -Libs.private: -Cflags: -I${includedir} diff --git a/libudev/test-libudev.c b/libudev/test-libudev.c deleted file mode 100644 index c325f8eef5..0000000000 --- a/libudev/test-libudev.c +++ /dev/null @@ -1,501 +0,0 @@ -/* - * test-libudev - * - * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org> - * - * 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. - */ - -#include <stdio.h> -#include <stdarg.h> -#include <stdlib.h> -#include <unistd.h> -#include <errno.h> -#include <string.h> -#include <getopt.h> -#include <syslog.h> -#include <fcntl.h> -#include <sys/epoll.h> - -#include "libudev.h" - -#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) - -static void log_fn(struct udev *udev, - int priority, const char *file, int line, const char *fn, - const char *format, va_list args) -{ - printf("test-libudev: %s %s:%d ", fn, file, line); - vprintf(format, args); -} - -static void print_device(struct udev_device *device) -{ - const char *str; - dev_t devnum; - int count; - struct udev_list_entry *list_entry; - - printf("*** device: %p ***\n", device); - str = udev_device_get_action(device); - if (str != NULL) - printf("action: '%s'\n", str); - - str = udev_device_get_syspath(device); - printf("syspath: '%s'\n", str); - - str = udev_device_get_sysname(device); - printf("sysname: '%s'\n", str); - - str = udev_device_get_sysnum(device); - if (str != NULL) - printf("sysnum: '%s'\n", str); - - str = udev_device_get_devpath(device); - printf("devpath: '%s'\n", str); - - str = udev_device_get_subsystem(device); - if (str != NULL) - printf("subsystem: '%s'\n", str); - - str = udev_device_get_devtype(device); - if (str != NULL) - printf("devtype: '%s'\n", str); - - str = udev_device_get_driver(device); - if (str != NULL) - printf("driver: '%s'\n", str); - - str = udev_device_get_devnode(device); - if (str != NULL) - printf("devname: '%s'\n", str); - - devnum = udev_device_get_devnum(device); - if (major(devnum) > 0) - printf("devnum: %u:%u\n", major(devnum), minor(devnum)); - - count = 0; - udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(device)) { - printf("link: '%s'\n", udev_list_entry_get_name(list_entry)); - count++; - } - if (count > 0) - printf("found %i links\n", count); - - count = 0; - udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(device)) { - printf("property: '%s=%s'\n", - udev_list_entry_get_name(list_entry), - udev_list_entry_get_value(list_entry)); - count++; - } - if (count > 0) - printf("found %i properties\n", count); - - str = udev_device_get_property_value(device, "MAJOR"); - if (str != NULL) - printf("MAJOR: '%s'\n", str); - - str = udev_device_get_sysattr_value(device, "dev"); - if (str != NULL) - printf("attr{dev}: '%s'\n", str); - - printf("\n"); -} - -static int test_device(struct udev *udev, const char *syspath) -{ - struct udev_device *device; - - printf("looking at device: %s\n", syspath); - device = udev_device_new_from_syspath(udev, syspath); - if (device == NULL) { - printf("no device found\n"); - return -1; - } - print_device(device); - udev_device_unref(device); - return 0; -} - -static int test_device_parents(struct udev *udev, const char *syspath) -{ - struct udev_device *device; - struct udev_device *device_parent; - - printf("looking at device: %s\n", syspath); - device = udev_device_new_from_syspath(udev, syspath); - if (device == NULL) - return -1; - - printf("looking at parents\n"); - device_parent = device; - do { - print_device(device_parent); - device_parent = udev_device_get_parent(device_parent); - } while (device_parent != NULL); - - printf("looking at parents again\n"); - device_parent = device; - do { - print_device(device_parent); - device_parent = udev_device_get_parent(device_parent); - } while (device_parent != NULL); - udev_device_unref(device); - - return 0; -} - -static int test_device_devnum(struct udev *udev) -{ - dev_t devnum = makedev(1, 3); - struct udev_device *device; - - printf("looking up device: %u:%u\n", major(devnum), minor(devnum)); - device = udev_device_new_from_devnum(udev, 'c', devnum); - if (device == NULL) - return -1; - print_device(device); - udev_device_unref(device); - return 0; -} - -static int test_device_subsys_name(struct udev *udev) -{ - struct udev_device *device; - - printf("looking up device: 'block':'sda'\n"); - device = udev_device_new_from_subsystem_sysname(udev, "block", "sda"); - if (device == NULL) - return -1; - print_device(device); - udev_device_unref(device); - - printf("looking up device: 'subsystem':'pci'\n"); - device = udev_device_new_from_subsystem_sysname(udev, "subsystem", "pci"); - if (device == NULL) - return -1; - print_device(device); - udev_device_unref(device); - - printf("looking up device: 'drivers':'scsi:sd'\n"); - device = udev_device_new_from_subsystem_sysname(udev, "drivers", "scsi:sd"); - if (device == NULL) - return -1; - print_device(device); - udev_device_unref(device); - - printf("looking up device: 'module':'printk'\n"); - device = udev_device_new_from_subsystem_sysname(udev, "module", "printk"); - if (device == NULL) - return -1; - print_device(device); - udev_device_unref(device); - return 0; -} - -static int test_enumerate_print_list(struct udev_enumerate *enumerate) -{ - struct udev_list_entry *list_entry; - int count = 0; - - udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(enumerate)) { - struct udev_device *device; - - device = udev_device_new_from_syspath(udev_enumerate_get_udev(enumerate), - udev_list_entry_get_name(list_entry)); - if (device != NULL) { - printf("device: '%s' (%s)\n", - udev_device_get_syspath(device), - udev_device_get_subsystem(device)); - udev_device_unref(device); - count++; - } - } - printf("found %i devices\n\n", count); - return count; -} - -static int test_monitor(struct udev *udev) -{ - struct udev_monitor *udev_monitor = NULL; - int fd_ep; - int fd_udev = -1; - struct epoll_event ep_udev, ep_stdin; - - fd_ep = epoll_create1(EPOLL_CLOEXEC); - if (fd_ep < 0) { - printf("error creating epoll fd: %m\n"); - goto out; - } - - udev_monitor = udev_monitor_new_from_netlink(udev, "udev"); - if (udev_monitor == NULL) { - printf("no socket\n"); - goto out; - } - fd_udev = udev_monitor_get_fd(udev_monitor); - - if (udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "block", NULL) < 0 || - udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "tty", NULL) < 0 || - udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "usb", "usb_device") < 0) { - printf("filter failed\n"); - goto out; - } - - if (udev_monitor_enable_receiving(udev_monitor) < 0) { - printf("bind failed\n"); - goto out; - } - - memset(&ep_udev, 0, sizeof(struct epoll_event)); - ep_udev.events = EPOLLIN; - ep_udev.data.fd = fd_udev; - if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_udev, &ep_udev) < 0) { - printf("fail to add fd to epoll: %m\n"); - goto out; - } - - memset(&ep_stdin, 0, sizeof(struct epoll_event)); - ep_stdin.events = EPOLLIN; - ep_stdin.data.fd = STDIN_FILENO; - if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, STDIN_FILENO, &ep_stdin) < 0) { - printf("fail to add fd to epoll: %m\n"); - goto out; - } - - for (;;) { - int fdcount; - struct epoll_event ev[4]; - struct udev_device *device; - int i; - - printf("waiting for events from udev, press ENTER to exit\n"); - fdcount = epoll_wait(fd_ep, ev, ARRAY_SIZE(ev), -1); - printf("epoll fd count: %i\n", fdcount); - - for (i = 0; i < fdcount; i++) { - if (ev[i].data.fd == fd_udev && ev[i].events & EPOLLIN) { - device = udev_monitor_receive_device(udev_monitor); - if (device == NULL) { - printf("no device from socket\n"); - continue; - } - print_device(device); - udev_device_unref(device); - } else if (ev[i].data.fd == STDIN_FILENO && ev[i].events & EPOLLIN) { - printf("exiting loop\n"); - goto out; - } - } - } -out: - if (fd_ep >= 0) - close(fd_ep); - udev_monitor_unref(udev_monitor); - return 0; -} - -static int test_queue(struct udev *udev) -{ - struct udev_queue *udev_queue; - unsigned long long int seqnum; - struct udev_list_entry *list_entry; - - udev_queue = udev_queue_new(udev); - if (udev_queue == NULL) - return -1; - seqnum = udev_queue_get_kernel_seqnum(udev_queue); - printf("seqnum kernel: %llu\n", seqnum); - seqnum = udev_queue_get_udev_seqnum(udev_queue); - printf("seqnum udev : %llu\n", seqnum); - - if (udev_queue_get_queue_is_empty(udev_queue)) - printf("queue is empty\n"); - printf("get queue list\n"); - udev_list_entry_foreach(list_entry, udev_queue_get_queued_list_entry(udev_queue)) - printf("queued: '%s' [%s]\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry)); - printf("\n"); - printf("get queue list again\n"); - udev_list_entry_foreach(list_entry, udev_queue_get_queued_list_entry(udev_queue)) - printf("queued: '%s' [%s]\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry)); - printf("\n"); - - list_entry = udev_queue_get_queued_list_entry(udev_queue); - if (list_entry != NULL) { - printf("event [%llu] is queued\n", seqnum); - seqnum = strtoull(udev_list_entry_get_value(list_entry), NULL, 10); - if (udev_queue_get_seqnum_is_finished(udev_queue, seqnum)) - printf("event [%llu] is not finished\n", seqnum); - else - printf("event [%llu] is finished\n", seqnum); - } - printf("\n"); - udev_queue_unref(udev_queue); - return 0; -} - -static int test_enumerate(struct udev *udev, const char *subsystem) -{ - struct udev_enumerate *udev_enumerate; - - printf("enumerate '%s'\n", subsystem == NULL ? "<all>" : subsystem); - udev_enumerate = udev_enumerate_new(udev); - if (udev_enumerate == NULL) - return -1; - udev_enumerate_add_match_subsystem(udev_enumerate, subsystem); - udev_enumerate_scan_devices(udev_enumerate); - test_enumerate_print_list(udev_enumerate); - udev_enumerate_unref(udev_enumerate); - - printf("enumerate 'net' + duplicated scan + null + zero\n"); - udev_enumerate = udev_enumerate_new(udev); - if (udev_enumerate == NULL) - return -1; - udev_enumerate_add_match_subsystem(udev_enumerate, "net"); - udev_enumerate_scan_devices(udev_enumerate); - udev_enumerate_scan_devices(udev_enumerate); - udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/zero"); - udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/null"); - udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/zero"); - udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/null"); - udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/zero"); - udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/null"); - udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/null"); - udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/zero"); - udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/zero"); - udev_enumerate_scan_devices(udev_enumerate); - test_enumerate_print_list(udev_enumerate); - udev_enumerate_unref(udev_enumerate); - - printf("enumerate 'block'\n"); - udev_enumerate = udev_enumerate_new(udev); - if (udev_enumerate == NULL) - return -1; - udev_enumerate_add_match_subsystem(udev_enumerate,"block"); - udev_enumerate_add_match_is_initialized(udev_enumerate); - udev_enumerate_scan_devices(udev_enumerate); - test_enumerate_print_list(udev_enumerate); - udev_enumerate_unref(udev_enumerate); - - printf("enumerate 'not block'\n"); - udev_enumerate = udev_enumerate_new(udev); - if (udev_enumerate == NULL) - return -1; - udev_enumerate_add_nomatch_subsystem(udev_enumerate, "block"); - udev_enumerate_scan_devices(udev_enumerate); - test_enumerate_print_list(udev_enumerate); - udev_enumerate_unref(udev_enumerate); - - printf("enumerate 'pci, mem, vc'\n"); - udev_enumerate = udev_enumerate_new(udev); - if (udev_enumerate == NULL) - return -1; - udev_enumerate_add_match_subsystem(udev_enumerate, "pci"); - udev_enumerate_add_match_subsystem(udev_enumerate, "mem"); - udev_enumerate_add_match_subsystem(udev_enumerate, "vc"); - udev_enumerate_scan_devices(udev_enumerate); - test_enumerate_print_list(udev_enumerate); - udev_enumerate_unref(udev_enumerate); - - printf("enumerate 'subsystem'\n"); - udev_enumerate = udev_enumerate_new(udev); - if (udev_enumerate == NULL) - return -1; - udev_enumerate_scan_subsystems(udev_enumerate); - test_enumerate_print_list(udev_enumerate); - udev_enumerate_unref(udev_enumerate); - - printf("enumerate 'property IF_FS_*=filesystem'\n"); - udev_enumerate = udev_enumerate_new(udev); - if (udev_enumerate == NULL) - return -1; - udev_enumerate_add_match_property(udev_enumerate, "ID_FS*", "filesystem"); - udev_enumerate_scan_devices(udev_enumerate); - test_enumerate_print_list(udev_enumerate); - udev_enumerate_unref(udev_enumerate); - return 0; -} - -int main(int argc, char *argv[]) -{ - struct udev *udev = NULL; - static const struct option options[] = { - { "syspath", required_argument, NULL, 'p' }, - { "subsystem", required_argument, NULL, 's' }, - { "debug", no_argument, NULL, 'd' }, - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, 'V' }, - {} - }; - const char *syspath = "/devices/virtual/mem/null"; - const char *subsystem = NULL; - char path[1024]; - const char *str; - - udev = udev_new(); - printf("context: %p\n", udev); - if (udev == NULL) { - printf("no context\n"); - return 1; - } - udev_set_log_fn(udev, log_fn); - printf("set log: %p\n", log_fn); - - for (;;) { - int option; - - option = getopt_long(argc, argv, "+p:s:dhV", options, NULL); - if (option == -1) - break; - - switch (option) { - case 'p': - syspath = optarg; - break; - case 's': - subsystem = optarg; - break; - case 'd': - if (udev_get_log_priority(udev) < LOG_INFO) - udev_set_log_priority(udev, LOG_INFO); - break; - case 'h': - printf("--debug --syspath= --subsystem= --help\n"); - goto out; - case 'V': - printf("%s\n", VERSION); - goto out; - default: - goto out; - } - } - - str = udev_get_sys_path(udev); - printf("sys_path: '%s'\n", str); - str = udev_get_dev_path(udev); - printf("dev_path: '%s'\n", str); - - /* add sys path if needed */ - if (strncmp(syspath, udev_get_sys_path(udev), strlen(udev_get_sys_path(udev))) != 0) { - snprintf(path, sizeof(path), "%s%s", udev_get_sys_path(udev), syspath); - syspath = path; - } - - test_device(udev, syspath); - test_device_devnum(udev); - test_device_subsys_name(udev); - test_device_parents(udev, syspath); - - test_enumerate(udev, subsystem); - - test_queue(udev); - - test_monitor(udev); -out: - udev_unref(udev); - return 0; -} |