List of commits:
Subject Hash Author Date (UTC)
Initial commit a7933be9fb44a9c0bb6834bf4f97a48db261c271 Sylvain BERTRAND 2012-09-05 09:39:46
Commit a7933be9fb44a9c0bb6834bf4f97a48db261c271 - Initial commit
Author: Sylvain BERTRAND
Author date (UTC): 2012-09-05 09:39
Committer name: Sylvain BERTRAND
Committer date (UTC): 2012-09-05 09:39
Parent(s):
Signer:
Signing key:
Signing status: N
Tree: 79c8778317f58bbcfa25cdcf41ca9f070a934d80
File Lines added Lines deleted
COPYING-GPL 339 0
COPYING-LGPL 502 0
README 109 0
TODO 20 0
conf.mk 67 0
gentoo/overlay/sys-fs/udev/udev-189.ebuild 77 0
makefile 449 0
rules/42-usb-hid-pm.rules 49 0
rules/50-udev-default.rules 107 0
rules/60-persistent-alsa.rules 14 0
rules/60-persistent-input.rules 38 0
rules/60-persistent-net.rules 55 0
rules/60-persistent-serial.rules 20 0
rules/60-persistent-storage-tape.rules 25 0
rules/60-persistent-storage.rules 89 0
rules/75-net-description.rules 14 0
rules/75-tty-description.rules 14 0
rules/78-sound-card.rules 89 0
rules/80-drivers.rules 12 0
rules/95-udev-late.rules 4 0
src/.udev-builtin-path_id.c.swp 0 0
src/libudev-device-private.c 185 0
src/libudev-device.c 1782 0
src/libudev-enumerate.c 973 0
src/libudev-list.c 353 0
src/libudev-monitor.c 880 0
src/libudev-private.h 213 0
src/libudev-queue-private.c 412 0
src/libudev-queue.c 489 0
src/libudev-util-private.c 242 0
src/libudev-util.c 595 0
src/libudev.c 458 0
src/libudev.h 190 0
src/libudev.pc.in 11 0
src/udev-builtin-blkid.c 207 0
src/udev-builtin-firmware.c 168 0
src/udev-builtin-hwdb.c 247 0
src/udev-builtin-input_id.c 218 0
src/udev-builtin-kmod.c 142 0
src/udev-builtin-path_id.c 547 0
src/udev-builtin-usb_id.c 482 0
src/udev-builtin.c 134 0
src/udev-ctrl.c 494 0
src/udev-event.c 996 0
src/udev-node.c 379 0
src/udev-rules.c 2764 0
src/udev-watch.c 170 0
src/udev.conf 3 0
src/udev.h 189 0
src/udev.pc.in 5 0
src/udev.xml 695 0
src/udevadm-control.c 175 0
src/udevadm-info.c 587 0
src/udevadm-monitor.c 297 0
src/udevadm-settle.c 235 0
src/udevadm-test-builtin.c 128 0
src/udevadm-test.c 173 0
src/udevadm-trigger.c 232 0
src/udevadm.c 165 0
src/udevadm.xml 472 0
src/udevd.c 1680 0
src/udevd.xml 151 0
File COPYING-GPL added (mode: 100644) (index 0000000..d159169)
1 GNU GENERAL PUBLIC LICENSE
2 Version 2, June 1991
3
4 Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
5 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6 Everyone is permitted to copy and distribute verbatim copies
7 of this license document, but changing it is not allowed.
8
9 Preamble
10
11 The licenses for most software are designed to take away your
12 freedom to share and change it. By contrast, the GNU General Public
13 License is intended to guarantee your freedom to share and change free
14 software--to make sure the software is free for all its users. This
15 General Public License applies to most of the Free Software
16 Foundation's software and to any other program whose authors commit to
17 using it. (Some other Free Software Foundation software is covered by
18 the GNU Lesser General Public License instead.) You can apply it to
19 your programs, too.
20
21 When we speak of free software, we are referring to freedom, not
22 price. Our General Public Licenses are designed to make sure that you
23 have the freedom to distribute copies of free software (and charge for
24 this service if you wish), that you receive source code or can get it
25 if you want it, that you can change the software or use pieces of it
26 in new free programs; and that you know you can do these things.
27
28 To protect your rights, we need to make restrictions that forbid
29 anyone to deny you these rights or to ask you to surrender the rights.
30 These restrictions translate to certain responsibilities for you if you
31 distribute copies of the software, or if you modify it.
32
33 For example, if you distribute copies of such a program, whether
34 gratis or for a fee, you must give the recipients all the rights that
35 you have. You must make sure that they, too, receive or can get the
36 source code. And you must show them these terms so they know their
37 rights.
38
39 We protect your rights with two steps: (1) copyright the software, and
40 (2) offer you this license which gives you legal permission to copy,
41 distribute and/or modify the software.
42
43 Also, for each author's protection and ours, we want to make certain
44 that everyone understands that there is no warranty for this free
45 software. If the software is modified by someone else and passed on, we
46 want its recipients to know that what they have is not the original, so
47 that any problems introduced by others will not reflect on the original
48 authors' reputations.
49
50 Finally, any free program is threatened constantly by software
51 patents. We wish to avoid the danger that redistributors of a free
52 program will individually obtain patent licenses, in effect making the
53 program proprietary. To prevent this, we have made it clear that any
54 patent must be licensed for everyone's free use or not licensed at all.
55
56 The precise terms and conditions for copying, distribution and
57 modification follow.
58
59 GNU GENERAL PUBLIC LICENSE
60 TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61
62 0. This License applies to any program or other work which contains
63 a notice placed by the copyright holder saying it may be distributed
64 under the terms of this General Public License. The "Program", below,
65 refers to any such program or work, and a "work based on the Program"
66 means either the Program or any derivative work under copyright law:
67 that is to say, a work containing the Program or a portion of it,
68 either verbatim or with modifications and/or translated into another
69 language. (Hereinafter, translation is included without limitation in
70 the term "modification".) Each licensee is addressed as "you".
71
72 Activities other than copying, distribution and modification are not
73 covered by this License; they are outside its scope. The act of
74 running the Program is not restricted, and the output from the Program
75 is covered only if its contents constitute a work based on the
76 Program (independent of having been made by running the Program).
77 Whether that is true depends on what the Program does.
78
79 1. You may copy and distribute verbatim copies of the Program's
80 source code as you receive it, in any medium, provided that you
81 conspicuously and appropriately publish on each copy an appropriate
82 copyright notice and disclaimer of warranty; keep intact all the
83 notices that refer to this License and to the absence of any warranty;
84 and give any other recipients of the Program a copy of this License
85 along with the Program.
86
87 You may charge a fee for the physical act of transferring a copy, and
88 you may at your option offer warranty protection in exchange for a fee.
89
90 2. You may modify your copy or copies of the Program or any portion
91 of it, thus forming a work based on the Program, and copy and
92 distribute such modifications or work under the terms of Section 1
93 above, provided that you also meet all of these conditions:
94
95 a) You must cause the modified files to carry prominent notices
96 stating that you changed the files and the date of any change.
97
98 b) You must cause any work that you distribute or publish, that in
99 whole or in part contains or is derived from the Program or any
100 part thereof, to be licensed as a whole at no charge to all third
101 parties under the terms of this License.
102
103 c) If the modified program normally reads commands interactively
104 when run, you must cause it, when started running for such
105 interactive use in the most ordinary way, to print or display an
106 announcement including an appropriate copyright notice and a
107 notice that there is no warranty (or else, saying that you provide
108 a warranty) and that users may redistribute the program under
109 these conditions, and telling the user how to view a copy of this
110 License. (Exception: if the Program itself is interactive but
111 does not normally print such an announcement, your work based on
112 the Program is not required to print an announcement.)
113
114 These requirements apply to the modified work as a whole. If
115 identifiable sections of that work are not derived from the Program,
116 and can be reasonably considered independent and separate works in
117 themselves, then this License, and its terms, do not apply to those
118 sections when you distribute them as separate works. But when you
119 distribute the same sections as part of a whole which is a work based
120 on the Program, the distribution of the whole must be on the terms of
121 this License, whose permissions for other licensees extend to the
122 entire whole, and thus to each and every part regardless of who wrote it.
123
124 Thus, it is not the intent of this section to claim rights or contest
125 your rights to work written entirely by you; rather, the intent is to
126 exercise the right to control the distribution of derivative or
127 collective works based on the Program.
128
129 In addition, mere aggregation of another work not based on the Program
130 with the Program (or with a work based on the Program) on a volume of
131 a storage or distribution medium does not bring the other work under
132 the scope of this License.
133
134 3. You may copy and distribute the Program (or a work based on it,
135 under Section 2) in object code or executable form under the terms of
136 Sections 1 and 2 above provided that you also do one of the following:
137
138 a) Accompany it with the complete corresponding machine-readable
139 source code, which must be distributed under the terms of Sections
140 1 and 2 above on a medium customarily used for software interchange; or,
141
142 b) Accompany it with a written offer, valid for at least three
143 years, to give any third party, for a charge no more than your
144 cost of physically performing source distribution, a complete
145 machine-readable copy of the corresponding source code, to be
146 distributed under the terms of Sections 1 and 2 above on a medium
147 customarily used for software interchange; or,
148
149 c) Accompany it with the information you received as to the offer
150 to distribute corresponding source code. (This alternative is
151 allowed only for noncommercial distribution and only if you
152 received the program in object code or executable form with such
153 an offer, in accord with Subsection b above.)
154
155 The source code for a work means the preferred form of the work for
156 making modifications to it. For an executable work, complete source
157 code means all the source code for all modules it contains, plus any
158 associated interface definition files, plus the scripts used to
159 control compilation and installation of the executable. However, as a
160 special exception, the source code distributed need not include
161 anything that is normally distributed (in either source or binary
162 form) with the major components (compiler, kernel, and so on) of the
163 operating system on which the executable runs, unless that component
164 itself accompanies the executable.
165
166 If distribution of executable or object code is made by offering
167 access to copy from a designated place, then offering equivalent
168 access to copy the source code from the same place counts as
169 distribution of the source code, even though third parties are not
170 compelled to copy the source along with the object code.
171
172 4. You may not copy, modify, sublicense, or distribute the Program
173 except as expressly provided under this License. Any attempt
174 otherwise to copy, modify, sublicense or distribute the Program is
175 void, and will automatically terminate your rights under this License.
176 However, parties who have received copies, or rights, from you under
177 this License will not have their licenses terminated so long as such
178 parties remain in full compliance.
179
180 5. You are not required to accept this License, since you have not
181 signed it. However, nothing else grants you permission to modify or
182 distribute the Program or its derivative works. These actions are
183 prohibited by law if you do not accept this License. Therefore, by
184 modifying or distributing the Program (or any work based on the
185 Program), you indicate your acceptance of this License to do so, and
186 all its terms and conditions for copying, distributing or modifying
187 the Program or works based on it.
188
189 6. Each time you redistribute the Program (or any work based on the
190 Program), the recipient automatically receives a license from the
191 original licensor to copy, distribute or modify the Program subject to
192 these terms and conditions. You may not impose any further
193 restrictions on the recipients' exercise of the rights granted herein.
194 You are not responsible for enforcing compliance by third parties to
195 this License.
196
197 7. If, as a consequence of a court judgment or allegation of patent
198 infringement or for any other reason (not limited to patent issues),
199 conditions are imposed on you (whether by court order, agreement or
200 otherwise) that contradict the conditions of this License, they do not
201 excuse you from the conditions of this License. If you cannot
202 distribute so as to satisfy simultaneously your obligations under this
203 License and any other pertinent obligations, then as a consequence you
204 may not distribute the Program at all. For example, if a patent
205 license would not permit royalty-free redistribution of the Program by
206 all those who receive copies directly or indirectly through you, then
207 the only way you could satisfy both it and this License would be to
208 refrain entirely from distribution of the Program.
209
210 If any portion of this section is held invalid or unenforceable under
211 any particular circumstance, the balance of the section is intended to
212 apply and the section as a whole is intended to apply in other
213 circumstances.
214
215 It is not the purpose of this section to induce you to infringe any
216 patents or other property right claims or to contest validity of any
217 such claims; this section has the sole purpose of protecting the
218 integrity of the free software distribution system, which is
219 implemented by public license practices. Many people have made
220 generous contributions to the wide range of software distributed
221 through that system in reliance on consistent application of that
222 system; it is up to the author/donor to decide if he or she is willing
223 to distribute software through any other system and a licensee cannot
224 impose that choice.
225
226 This section is intended to make thoroughly clear what is believed to
227 be a consequence of the rest of this License.
228
229 8. If the distribution and/or use of the Program is restricted in
230 certain countries either by patents or by copyrighted interfaces, the
231 original copyright holder who places the Program under this License
232 may add an explicit geographical distribution limitation excluding
233 those countries, so that distribution is permitted only in or among
234 countries not thus excluded. In such case, this License incorporates
235 the limitation as if written in the body of this License.
236
237 9. The Free Software Foundation may publish revised and/or new versions
238 of the General Public License from time to time. Such new versions will
239 be similar in spirit to the present version, but may differ in detail to
240 address new problems or concerns.
241
242 Each version is given a distinguishing version number. If the Program
243 specifies a version number of this License which applies to it and "any
244 later version", you have the option of following the terms and conditions
245 either of that version or of any later version published by the Free
246 Software Foundation. If the Program does not specify a version number of
247 this License, you may choose any version ever published by the Free Software
248 Foundation.
249
250 10. If you wish to incorporate parts of the Program into other free
251 programs whose distribution conditions are different, write to the author
252 to ask for permission. For software which is copyrighted by the Free
253 Software Foundation, write to the Free Software Foundation; we sometimes
254 make exceptions for this. Our decision will be guided by the two goals
255 of preserving the free status of all derivatives of our free software and
256 of promoting the sharing and reuse of software generally.
257
258 NO WARRANTY
259
260 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261 FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262 OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263 PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264 OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266 TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267 PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268 REPAIR OR CORRECTION.
269
270 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271 WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272 REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273 INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274 OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275 TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276 YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277 PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278 POSSIBILITY OF SUCH DAMAGES.
279
280 END OF TERMS AND CONDITIONS
281
282 How to Apply These Terms to Your New Programs
283
284 If you develop a new program, and you want it to be of the greatest
285 possible use to the public, the best way to achieve this is to make it
286 free software which everyone can redistribute and change under these terms.
287
288 To do so, attach the following notices to the program. It is safest
289 to attach them to the start of each source file to most effectively
290 convey the exclusion of warranty; and each file should have at least
291 the "copyright" line and a pointer to where the full notice is found.
292
293 <one line to give the program's name and a brief idea of what it does.>
294 Copyright (C) <year> <name of author>
295
296 This program is free software; you can redistribute it and/or modify
297 it under the terms of the GNU General Public License as published by
298 the Free Software Foundation; either version 2 of the License, or
299 (at your option) any later version.
300
301 This program is distributed in the hope that it will be useful,
302 but WITHOUT ANY WARRANTY; without even the implied warranty of
303 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304 GNU General Public License for more details.
305
306 You should have received a copy of the GNU General Public License along
307 with this program; if not, write to the Free Software Foundation, Inc.,
308 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309
310 Also add information on how to contact you by electronic and paper mail.
311
312 If the program is interactive, make it output a short notice like this
313 when it starts in an interactive mode:
314
315 Gnomovision version 69, Copyright (C) year name of author
316 Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317 This is free software, and you are welcome to redistribute it
318 under certain conditions; type `show c' for details.
319
320 The hypothetical commands `show w' and `show c' should show the appropriate
321 parts of the General Public License. Of course, the commands you use may
322 be called something other than `show w' and `show c'; they could even be
323 mouse-clicks or menu items--whatever suits your program.
324
325 You should also get your employer (if you work as a programmer) or your
326 school, if any, to sign a "copyright disclaimer" for the program, if
327 necessary. Here is a sample; alter the names:
328
329 Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330 `Gnomovision' (which makes passes at compilers) written by James Hacker.
331
332 <signature of Ty Coon>, 1 April 1989
333 Ty Coon, President of Vice
334
335 This General Public License does not permit incorporating your program into
336 proprietary programs. If your program is a subroutine library, you may
337 consider it more useful to permit linking proprietary applications with the
338 library. If this is what you want to do, use the GNU Lesser General
339 Public License instead of this License.
File COPYING-LGPL added (mode: 100644) (index 0000000..d2e3127)
1 GNU LESSER GENERAL PUBLIC LICENSE
2 Version 2.1, February 1999
3
4 Copyright (C) 1991, 1999 Free Software Foundation, Inc.
5 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
6 Everyone is permitted to copy and distribute verbatim copies
7 of this license document, but changing it is not allowed.
8
9 [This is the first released version of the Lesser GPL. It also counts
10 as the successor of the GNU Library Public License, version 2, hence
11 the version number 2.1.]
12
13 Preamble
14
15 The licenses for most software are designed to take away your
16 freedom to share and change it. By contrast, the GNU General Public
17 Licenses are intended to guarantee your freedom to share and change
18 free software--to make sure the software is free for all its users.
19
20 This license, the Lesser General Public License, applies to some
21 specially designated software packages--typically libraries--of the
22 Free Software Foundation and other authors who decide to use it. You
23 can use it too, but we suggest you first think carefully about whether
24 this license or the ordinary General Public License is the better
25 strategy to use in any particular case, based on the explanations below.
26
27 When we speak of free software, we are referring to freedom of use,
28 not price. Our General Public Licenses are designed to make sure that
29 you have the freedom to distribute copies of free software (and charge
30 for this service if you wish); that you receive source code or can get
31 it if you want it; that you can change the software and use pieces of
32 it in new free programs; and that you are informed that you can do
33 these things.
34
35 To protect your rights, we need to make restrictions that forbid
36 distributors to deny you these rights or to ask you to surrender these
37 rights. These restrictions translate to certain responsibilities for
38 you if you distribute copies of the library or if you modify it.
39
40 For example, if you distribute copies of the library, whether gratis
41 or for a fee, you must give the recipients all the rights that we gave
42 you. You must make sure that they, too, receive or can get the source
43 code. If you link other code with the library, you must provide
44 complete object files to the recipients, so that they can relink them
45 with the library after making changes to the library and recompiling
46 it. And you must show them these terms so they know their rights.
47
48 We protect your rights with a two-step method: (1) we copyright the
49 library, and (2) we offer you this license, which gives you legal
50 permission to copy, distribute and/or modify the library.
51
52 To protect each distributor, we want to make it very clear that
53 there is no warranty for the free library. Also, if the library is
54 modified by someone else and passed on, the recipients should know
55 that what they have is not the original version, so that the original
56 author's reputation will not be affected by problems that might be
57 introduced by others.
58
59 Finally, software patents pose a constant threat to the existence of
60 any free program. We wish to make sure that a company cannot
61 effectively restrict the users of a free program by obtaining a
62 restrictive license from a patent holder. Therefore, we insist that
63 any patent license obtained for a version of the library must be
64 consistent with the full freedom of use specified in this license.
65
66 Most GNU software, including some libraries, is covered by the
67 ordinary GNU General Public License. This license, the GNU Lesser
68 General Public License, applies to certain designated libraries, and
69 is quite different from the ordinary General Public License. We use
70 this license for certain libraries in order to permit linking those
71 libraries into non-free programs.
72
73 When a program is linked with a library, whether statically or using
74 a shared library, the combination of the two is legally speaking a
75 combined work, a derivative of the original library. The ordinary
76 General Public License therefore permits such linking only if the
77 entire combination fits its criteria of freedom. The Lesser General
78 Public License permits more lax criteria for linking other code with
79 the library.
80
81 We call this license the "Lesser" General Public License because it
82 does Less to protect the user's freedom than the ordinary General
83 Public License. It also provides other free software developers Less
84 of an advantage over competing non-free programs. These disadvantages
85 are the reason we use the ordinary General Public License for many
86 libraries. However, the Lesser license provides advantages in certain
87 special circumstances.
88
89 For example, on rare occasions, there may be a special need to
90 encourage the widest possible use of a certain library, so that it becomes
91 a de-facto standard. To achieve this, non-free programs must be
92 allowed to use the library. A more frequent case is that a free
93 library does the same job as widely used non-free libraries. In this
94 case, there is little to gain by limiting the free library to free
95 software only, so we use the Lesser General Public License.
96
97 In other cases, permission to use a particular library in non-free
98 programs enables a greater number of people to use a large body of
99 free software. For example, permission to use the GNU C Library in
100 non-free programs enables many more people to use the whole GNU
101 operating system, as well as its variant, the GNU/Linux operating
102 system.
103
104 Although the Lesser General Public License is Less protective of the
105 users' freedom, it does ensure that the user of a program that is
106 linked with the Library has the freedom and the wherewithal to run
107 that program using a modified version of the Library.
108
109 The precise terms and conditions for copying, distribution and
110 modification follow. Pay close attention to the difference between a
111 "work based on the library" and a "work that uses the library". The
112 former contains code derived from the library, whereas the latter must
113 be combined with the library in order to run.
114
115 GNU LESSER GENERAL PUBLIC LICENSE
116 TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
117
118 0. This License Agreement applies to any software library or other
119 program which contains a notice placed by the copyright holder or
120 other authorized party saying it may be distributed under the terms of
121 this Lesser General Public License (also called "this License").
122 Each licensee is addressed as "you".
123
124 A "library" means a collection of software functions and/or data
125 prepared so as to be conveniently linked with application programs
126 (which use some of those functions and data) to form executables.
127
128 The "Library", below, refers to any such software library or work
129 which has been distributed under these terms. A "work based on the
130 Library" means either the Library or any derivative work under
131 copyright law: that is to say, a work containing the Library or a
132 portion of it, either verbatim or with modifications and/or translated
133 straightforwardly into another language. (Hereinafter, translation is
134 included without limitation in the term "modification".)
135
136 "Source code" for a work means the preferred form of the work for
137 making modifications to it. For a library, complete source code means
138 all the source code for all modules it contains, plus any associated
139 interface definition files, plus the scripts used to control compilation
140 and installation of the library.
141
142 Activities other than copying, distribution and modification are not
143 covered by this License; they are outside its scope. The act of
144 running a program using the Library is not restricted, and output from
145 such a program is covered only if its contents constitute a work based
146 on the Library (independent of the use of the Library in a tool for
147 writing it). Whether that is true depends on what the Library does
148 and what the program that uses the Library does.
149
150 1. You may copy and distribute verbatim copies of the Library's
151 complete source code as you receive it, in any medium, provided that
152 you conspicuously and appropriately publish on each copy an
153 appropriate copyright notice and disclaimer of warranty; keep intact
154 all the notices that refer to this License and to the absence of any
155 warranty; and distribute a copy of this License along with the
156 Library.
157
158 You may charge a fee for the physical act of transferring a copy,
159 and you may at your option offer warranty protection in exchange for a
160 fee.
161
162 2. You may modify your copy or copies of the Library or any portion
163 of it, thus forming a work based on the Library, and copy and
164 distribute such modifications or work under the terms of Section 1
165 above, provided that you also meet all of these conditions:
166
167 a) The modified work must itself be a software library.
168
169 b) You must cause the files modified to carry prominent notices
170 stating that you changed the files and the date of any change.
171
172 c) You must cause the whole of the work to be licensed at no
173 charge to all third parties under the terms of this License.
174
175 d) If a facility in the modified Library refers to a function or a
176 table of data to be supplied by an application program that uses
177 the facility, other than as an argument passed when the facility
178 is invoked, then you must make a good faith effort to ensure that,
179 in the event an application does not supply such function or
180 table, the facility still operates, and performs whatever part of
181 its purpose remains meaningful.
182
183 (For example, a function in a library to compute square roots has
184 a purpose that is entirely well-defined independent of the
185 application. Therefore, Subsection 2d requires that any
186 application-supplied function or table used by this function must
187 be optional: if the application does not supply it, the square
188 root function must still compute square roots.)
189
190 These requirements apply to the modified work as a whole. If
191 identifiable sections of that work are not derived from the Library,
192 and can be reasonably considered independent and separate works in
193 themselves, then this License, and its terms, do not apply to those
194 sections when you distribute them as separate works. But when you
195 distribute the same sections as part of a whole which is a work based
196 on the Library, the distribution of the whole must be on the terms of
197 this License, whose permissions for other licensees extend to the
198 entire whole, and thus to each and every part regardless of who wrote
199 it.
200
201 Thus, it is not the intent of this section to claim rights or contest
202 your rights to work written entirely by you; rather, the intent is to
203 exercise the right to control the distribution of derivative or
204 collective works based on the Library.
205
206 In addition, mere aggregation of another work not based on the Library
207 with the Library (or with a work based on the Library) on a volume of
208 a storage or distribution medium does not bring the other work under
209 the scope of this License.
210
211 3. You may opt to apply the terms of the ordinary GNU General Public
212 License instead of this License to a given copy of the Library. To do
213 this, you must alter all the notices that refer to this License, so
214 that they refer to the ordinary GNU General Public License, version 2,
215 instead of to this License. (If a newer version than version 2 of the
216 ordinary GNU General Public License has appeared, then you can specify
217 that version instead if you wish.) Do not make any other change in
218 these notices.
219
220 Once this change is made in a given copy, it is irreversible for
221 that copy, so the ordinary GNU General Public License applies to all
222 subsequent copies and derivative works made from that copy.
223
224 This option is useful when you wish to copy part of the code of
225 the Library into a program that is not a library.
226
227 4. You may copy and distribute the Library (or a portion or
228 derivative of it, under Section 2) in object code or executable form
229 under the terms of Sections 1 and 2 above provided that you accompany
230 it with the complete corresponding machine-readable source code, which
231 must be distributed under the terms of Sections 1 and 2 above on a
232 medium customarily used for software interchange.
233
234 If distribution of object code is made by offering access to copy
235 from a designated place, then offering equivalent access to copy the
236 source code from the same place satisfies the requirement to
237 distribute the source code, even though third parties are not
238 compelled to copy the source along with the object code.
239
240 5. A program that contains no derivative of any portion of the
241 Library, but is designed to work with the Library by being compiled or
242 linked with it, is called a "work that uses the Library". Such a
243 work, in isolation, is not a derivative work of the Library, and
244 therefore falls outside the scope of this License.
245
246 However, linking a "work that uses the Library" with the Library
247 creates an executable that is a derivative of the Library (because it
248 contains portions of the Library), rather than a "work that uses the
249 library". The executable is therefore covered by this License.
250 Section 6 states terms for distribution of such executables.
251
252 When a "work that uses the Library" uses material from a header file
253 that is part of the Library, the object code for the work may be a
254 derivative work of the Library even though the source code is not.
255 Whether this is true is especially significant if the work can be
256 linked without the Library, or if the work is itself a library. The
257 threshold for this to be true is not precisely defined by law.
258
259 If such an object file uses only numerical parameters, data
260 structure layouts and accessors, and small macros and small inline
261 functions (ten lines or less in length), then the use of the object
262 file is unrestricted, regardless of whether it is legally a derivative
263 work. (Executables containing this object code plus portions of the
264 Library will still fall under Section 6.)
265
266 Otherwise, if the work is a derivative of the Library, you may
267 distribute the object code for the work under the terms of Section 6.
268 Any executables containing that work also fall under Section 6,
269 whether or not they are linked directly with the Library itself.
270
271 6. As an exception to the Sections above, you may also combine or
272 link a "work that uses the Library" with the Library to produce a
273 work containing portions of the Library, and distribute that work
274 under terms of your choice, provided that the terms permit
275 modification of the work for the customer's own use and reverse
276 engineering for debugging such modifications.
277
278 You must give prominent notice with each copy of the work that the
279 Library is used in it and that the Library and its use are covered by
280 this License. You must supply a copy of this License. If the work
281 during execution displays copyright notices, you must include the
282 copyright notice for the Library among them, as well as a reference
283 directing the user to the copy of this License. Also, you must do one
284 of these things:
285
286 a) Accompany the work with the complete corresponding
287 machine-readable source code for the Library including whatever
288 changes were used in the work (which must be distributed under
289 Sections 1 and 2 above); and, if the work is an executable linked
290 with the Library, with the complete machine-readable "work that
291 uses the Library", as object code and/or source code, so that the
292 user can modify the Library and then relink to produce a modified
293 executable containing the modified Library. (It is understood
294 that the user who changes the contents of definitions files in the
295 Library will not necessarily be able to recompile the application
296 to use the modified definitions.)
297
298 b) Use a suitable shared library mechanism for linking with the
299 Library. A suitable mechanism is one that (1) uses at run time a
300 copy of the library already present on the user's computer system,
301 rather than copying library functions into the executable, and (2)
302 will operate properly with a modified version of the library, if
303 the user installs one, as long as the modified version is
304 interface-compatible with the version that the work was made with.
305
306 c) Accompany the work with a written offer, valid for at
307 least three years, to give the same user the materials
308 specified in Subsection 6a, above, for a charge no more
309 than the cost of performing this distribution.
310
311 d) If distribution of the work is made by offering access to copy
312 from a designated place, offer equivalent access to copy the above
313 specified materials from the same place.
314
315 e) Verify that the user has already received a copy of these
316 materials or that you have already sent this user a copy.
317
318 For an executable, the required form of the "work that uses the
319 Library" must include any data and utility programs needed for
320 reproducing the executable from it. However, as a special exception,
321 the materials to be distributed need not include anything that is
322 normally distributed (in either source or binary form) with the major
323 components (compiler, kernel, and so on) of the operating system on
324 which the executable runs, unless that component itself accompanies
325 the executable.
326
327 It may happen that this requirement contradicts the license
328 restrictions of other proprietary libraries that do not normally
329 accompany the operating system. Such a contradiction means you cannot
330 use both them and the Library together in an executable that you
331 distribute.
332
333 7. You may place library facilities that are a work based on the
334 Library side-by-side in a single library together with other library
335 facilities not covered by this License, and distribute such a combined
336 library, provided that the separate distribution of the work based on
337 the Library and of the other library facilities is otherwise
338 permitted, and provided that you do these two things:
339
340 a) Accompany the combined library with a copy of the same work
341 based on the Library, uncombined with any other library
342 facilities. This must be distributed under the terms of the
343 Sections above.
344
345 b) Give prominent notice with the combined library of the fact
346 that part of it is a work based on the Library, and explaining
347 where to find the accompanying uncombined form of the same work.
348
349 8. You may not copy, modify, sublicense, link with, or distribute
350 the Library except as expressly provided under this License. Any
351 attempt otherwise to copy, modify, sublicense, link with, or
352 distribute the Library is void, and will automatically terminate your
353 rights under this License. However, parties who have received copies,
354 or rights, from you under this License will not have their licenses
355 terminated so long as such parties remain in full compliance.
356
357 9. You are not required to accept this License, since you have not
358 signed it. However, nothing else grants you permission to modify or
359 distribute the Library or its derivative works. These actions are
360 prohibited by law if you do not accept this License. Therefore, by
361 modifying or distributing the Library (or any work based on the
362 Library), you indicate your acceptance of this License to do so, and
363 all its terms and conditions for copying, distributing or modifying
364 the Library or works based on it.
365
366 10. Each time you redistribute the Library (or any work based on the
367 Library), the recipient automatically receives a license from the
368 original licensor to copy, distribute, link with or modify the Library
369 subject to these terms and conditions. You may not impose any further
370 restrictions on the recipients' exercise of the rights granted herein.
371 You are not responsible for enforcing compliance by third parties with
372 this License.
373
374 11. If, as a consequence of a court judgment or allegation of patent
375 infringement or for any other reason (not limited to patent issues),
376 conditions are imposed on you (whether by court order, agreement or
377 otherwise) that contradict the conditions of this License, they do not
378 excuse you from the conditions of this License. If you cannot
379 distribute so as to satisfy simultaneously your obligations under this
380 License and any other pertinent obligations, then as a consequence you
381 may not distribute the Library at all. For example, if a patent
382 license would not permit royalty-free redistribution of the Library by
383 all those who receive copies directly or indirectly through you, then
384 the only way you could satisfy both it and this License would be to
385 refrain entirely from distribution of the Library.
386
387 If any portion of this section is held invalid or unenforceable under any
388 particular circumstance, the balance of the section is intended to apply,
389 and the section as a whole is intended to apply in other circumstances.
390
391 It is not the purpose of this section to induce you to infringe any
392 patents or other property right claims or to contest validity of any
393 such claims; this section has the sole purpose of protecting the
394 integrity of the free software distribution system which is
395 implemented by public license practices. Many people have made
396 generous contributions to the wide range of software distributed
397 through that system in reliance on consistent application of that
398 system; it is up to the author/donor to decide if he or she is willing
399 to distribute software through any other system and a licensee cannot
400 impose that choice.
401
402 This section is intended to make thoroughly clear what is believed to
403 be a consequence of the rest of this License.
404
405 12. If the distribution and/or use of the Library is restricted in
406 certain countries either by patents or by copyrighted interfaces, the
407 original copyright holder who places the Library under this License may add
408 an explicit geographical distribution limitation excluding those countries,
409 so that distribution is permitted only in or among countries not thus
410 excluded. In such case, this License incorporates the limitation as if
411 written in the body of this License.
412
413 13. The Free Software Foundation may publish revised and/or new
414 versions of the Lesser General Public License from time to time.
415 Such new versions will be similar in spirit to the present version,
416 but may differ in detail to address new problems or concerns.
417
418 Each version is given a distinguishing version number. If the Library
419 specifies a version number of this License which applies to it and
420 "any later version", you have the option of following the terms and
421 conditions either of that version or of any later version published by
422 the Free Software Foundation. If the Library does not specify a
423 license version number, you may choose any version ever published by
424 the Free Software Foundation.
425
426 14. If you wish to incorporate parts of the Library into other free
427 programs whose distribution conditions are incompatible with these,
428 write to the author to ask for permission. For software which is
429 copyrighted by the Free Software Foundation, write to the Free
430 Software Foundation; we sometimes make exceptions for this. Our
431 decision will be guided by the two goals of preserving the free status
432 of all derivatives of our free software and of promoting the sharing
433 and reuse of software generally.
434
435 NO WARRANTY
436
437 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
438 WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
439 EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
440 OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
441 KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
442 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
443 PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
444 LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
445 THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
446
447 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
448 WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
449 AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
450 FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
451 CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
452 LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
453 RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
454 FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
455 SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
456 DAMAGES.
457
458 END OF TERMS AND CONDITIONS
459
460 How to Apply These Terms to Your New Libraries
461
462 If you develop a new library, and you want it to be of the greatest
463 possible use to the public, we recommend making it free software that
464 everyone can redistribute and change. You can do so by permitting
465 redistribution under these terms (or, alternatively, under the terms of the
466 ordinary General Public License).
467
468 To apply these terms, attach the following notices to the library. It is
469 safest to attach them to the start of each source file to most effectively
470 convey the exclusion of warranty; and each file should have at least the
471 "copyright" line and a pointer to where the full notice is found.
472
473 <one line to give the library's name and a brief idea of what it does.>
474 Copyright (C) <year> <name of author>
475
476 This library is free software; you can redistribute it and/or
477 modify it under the terms of the GNU Lesser General Public
478 License as published by the Free Software Foundation; either
479 version 2.1 of the License, or (at your option) any later version.
480
481 This library is distributed in the hope that it will be useful,
482 but WITHOUT ANY WARRANTY; without even the implied warranty of
483 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
484 Lesser General Public License for more details.
485
486 You should have received a copy of the GNU Lesser General Public
487 License along with this library; if not, write to the Free Software
488 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
489
490 Also add information on how to contact you by electronic and paper mail.
491
492 You should also get your employer (if you work as a programmer) or your
493 school, if any, to sign a "copyright disclaimer" for the library, if
494 necessary. Here is a sample; alter the names:
495
496 Yoyodyne, Inc., hereby disclaims all copyright interest in the
497 library `Frob' (a library for tweaking knobs) written by James Random Hacker.
498
499 <signature of Ty Coon>, 1 April 1990
500 Ty Coon, President of Vice
501
502 That's all there is to it!
File README added (mode: 100644) (index 0000000..d0ce166)
1 This is the systemd-ectomized version of udev. Most features from the upstream
2 are backported, though we do not guarantee 100% API compatibility. The
3 development tree can be found at https://bitbucket.org/braindamaged/udev
4
5 Original udev readme follows.
6
7 ----------------------------------------
8
9 udev - Linux userspace device management
10
11 Integrating udev in the system has complex dependencies and may differ from
12 distribution to distribution. A system may not be able to boot up or work
13 reliably without a properly installed udev version. The upstream udev project
14 does not recommend replacing a distro's udev installation with the upstream
15 version.
16
17 The upstream udev project's set of default rules may require a most recent
18 kernel release to work properly.
19
20 Tools and rules shipped by udev are not public API and may change at any time.
21 Never call any private tool in /usr/lib/udev from any external application; it
22 might just go away in the next release. Access to udev information is only offered
23 by udevadm and libudev. Tools and rules in /usr/lib/udev and the entire contents
24 of the /run/udev directory are private to udev and do change whenever needed.
25
26 Requirements:
27 - Version 2.6.34 of the Linux kernel with sysfs, procfs, signalfd, inotify,
28 unix domain sockets, networking and hotplug enabled
29
30 - Some architectures might need a later kernel, that supports accept4(),
31 or need to backport the accept4() syscall wiring in the kernel.
32
33 - These options are required:
34 CONFIG_DEVTMPFS=y
35 CONFIG_HOTPLUG=y
36 CONFIG_INOTIFY_USER=y
37 CONFIG_NET=y
38 CONFIG_PROC_FS=y
39 CONFIG_SIGNALFD=y
40 CONFIG_SYSFS=y
41 CONFIG_SYSFS_DEPRECATED*=n
42 CONFIG_UEVENT_HELPER_PATH=""
43
44 - These options might be needed:
45 CONFIG_BLK_DEV_BSG=y (SCSI devices)
46 CONFIG_TMPFS_POSIX_ACL=y (user ACLs for device nodes)
47
48 - The /dev directory needs the 'devtmpfs' filesystem mounted.
49 Udev only manages the permissions and ownership of the
50 kernel-provided device nodes, and possibly creates additional symlinks.
51
52 - Udev requires /run to be writable, which is usually done by mounting a
53 'tmpfs' filesystem.
54
55 - This version of udev does not work properly with the CONFIG_SYSFS_DEPRECATED*
56 option enabled.
57
58 - The deprecated hotplug helper /sbin/hotplug should be disabled in the
59 kernel configuration, it is not needed today, and may render the system
60 unusable because the kernel may create too many processes in parallel
61 so that the system runs out-of-memory.
62
63 - The proc filesystem must be mounted on /proc, and the sysfs filesystem must
64 be mounted at /sys. No other locations are supported by a standard
65 udev installation.
66
67 - The default rules set requires the following group names resolvable at udev startup:
68 disk, cdrom, floppy, tape, audio, video, lp, tty, dialout, and kmem.
69 Especially in LDAP setups, it is required that getgrnam() be able to resolve
70 these group names with only the rootfs mounted and while no network is
71 available.
72
73 - Some udev extras have external dependencies like:
74 libglib2, usbutils, pciutils, and gperf.
75 All these extras can be disabled with configure options.
76
77 Setup:
78 - The udev daemon should be started to handle device events sent by the kernel.
79 During bootup, the events for already existing devices can be replayed, so
80 that they are configured by udev. The systemd service files contain the
81 needed commands to start the udev daemon and the coldplug sequence.
82
83 - Restarting the daemon never applies any rules to existing devices.
84
85 - New/changed rule files are picked up automatically; there is usually no
86 daemon restart or signal needed.
87
88 Operation:
89 - Based on events the kernel sends out on device creation/removal, udev
90 creates/removes device nodes and symlinks in the /dev directory.
91
92 - All kernel events are matched against a set of specified rules, which
93 possibly hook into the event processing and load required kernel
94 modules to set up devices. For all devices, the kernel exports a major/minor
95 number; if needed, udev creates a device node with the default kernel
96 device name. If specified, udev applies permissions/ownership to the device
97 node, creates additional symlinks pointing to the node, and executes
98 programs to handle the device.
99
100 - The events udev handles, and the information udev merges into its device
101 database, can be accessed with libudev:
102 http://www.kernel.org/pub/linux/utils/kernel/hotplug/libudev/
103 http://www.kernel.org/pub/linux/utils/kernel/hotplug/gudev/
104
105 For more details about udev and udev rules, see the udev man pages:
106 http://www.kernel.org/pub/linux/utils/kernel/hotplug/udev/
107
108 Please direct any comment/question to the linux-hotplug mailing list at:
109 linux-hotplug@vger.kernel.org
File TODO added (mode: 100644) (index 0000000..7d05661)
1 - find a way to tell udev to not cancel firmware
2 requests in initramfs
3
4 - scsi_id -> sg3_utils?
5
6 - make gtk-doc optional like kmod
7
8 - move /usr/lib/udev/devices/ to tmpfiles
9
10 - trigger --subsystem-match=usb/usb_device
11
12 - kill rules_generator
13
14 - have a $attrs{} ?
15
16 - libudev.so.1
17 - symbol versioning
18 - return object with *_unref()
19 - udev_monitor_from_socket()
20 - udev_queue_get_failed_list_entry()
File conf.mk added (mode: 100644) (index 0000000..df91d12)
1 #*******************************************************************************
2 #this code is protected by the GNU affero GPLv3
3 #author:Sylvain BERTRAND <sylvain.bertrand AT gmail dot com>
4 # <digital.ragnarok AT gmail dot com>
5 #*******************************************************************************
6
7 #*******************************************************************************
8 #build configuration
9 export
10 DEBUG?=
11 SYSROOT?=
12
13 BUILD_DIR?=build
14 BIN_DIR?=$(BUILD_DIR)/bin
15 LIB_DIR?=$(BUILD_DIR)/lib
16 OBJ_DIR?=$(BUILD_DIR)/obj
17 S_DIR?=$(BUILD_DIR)/s
18 CPP_DIR?=$(BUILD_DIR)/cpp
19 DEVEL_DIR?=$(BUILD_DIR)/devel
20 MAN_DIR?=$(BUILD_DIR)/man
21
22 LD:=gcc
23 CC:=gcc
24 CPP:=cpp
25 AS:=as
26 PKG_CONFIG:=pkg-config
27 XSLTPROC:=xsltproc
28
29 ifndef DEBUG
30 CPPFLAGS?=-D_GNU_SOURCE -Wall -Wextra -I./ -I./src
31 CFLAGS?=-Wall -Wextra -Ofast -march=native
32 CFLAGS+= -fverbose-asm -S
33 LDFLAGS?=-Wl,-O,10
34 ASFLAGS?=
35 else
36 CPPFLAGS?=-D_GNU_SOURCE -Wall -Wextra -I./ -I./src
37 CFLAGS?=-Wall -Wextra -std=gnu99 -ggdb3 -march=native
38 CFLAGS+= -fverbose-asm -S
39 ASFLAGS?=
40 endif
41 #*******************************************************************************
42
43 #*******************************************************************************
44 #software configuration
45 PREFIX?=/usr/local
46 INCLUDEDIR?=$(PREFIX)/include
47 #want the followinc at root
48 EXECPREFIX?=/
49 LIBDIR?=/lib
50 SYSCONFDIR?=/etc
51 PKGLIBEXECDIR?=/lib/udev
52 FIRMWARE_PATH?=/lib/firmware
53 USB_DATABASE?=$(shell $(PKG_CONFIG) --variable=usbids usbutils)
54 PCI_DATABASE?=$(shell $(PKG_CONFIG) --variable=idsdir libpci)/pci.ids
55
56 CPPFLAGS+= -DSYSCONFDIR=\"$(SYSCONFDIR)\" -DPKGLIBEXECDIR=\"$(PKGLIBEXECDIR)\"
57 CPPFLAGS+= -DFIRMWARE_PATH=\"$(FIRMWARE_PATH)\"
58 CPPFLAGS+= -DUSB_DATABASE=\"$(USB_DATABASE)\" -DPCI_DATABASE=\"$(PCI_DATABASE)\"
59
60 #udevd, version is used by other software components, must be consistent
61 VERSION=189
62 CPPFLAGS+= -DVERSION=\"$(VERSION)\"
63
64 #libudev
65 LIBUDEV_API=0
66 LIBUDEV_VERSION=$(LIBUDEV_API).0.0
67 #*******************************************************************************
File gentoo/overlay/sys-fs/udev/udev-189.ebuild added (mode: 100644) (index 0000000..05241a6)
1 EAPI=4
2
3 inherit eutils
4
5 SRC_URI="http://www.legeek.net/mudev-${PV}.tar.xz"
6 KEYWORDS="~alpha ~amd64 ~arm ~hppa ~ia64 ~m68k ~mips ~ppc ~ppc64 ~s390 ~sh ~sparc ~x86"
7
8 DESCRIPTION="Linux dynamic and persistent device naming support (aka userspace devfs)"
9 HOMEPAGE="http://www.legeek.net"
10
11 LICENSE="LGPL-2.1 GPL-2"
12 SLOT="0"
13 IUSE="doc"
14
15 COMMON_DEPEND=">=sys-apps/kmod-5
16 >=sys-apps/util-linux-2.20
17 !<sys-libs/glibc-2.12"
18
19 DEPEND="${COMMON_DEPEND}
20 virtual/pkgconfig
21 sys-apps/usbutils
22 sys-apps/pciutils
23 doc? ( app-text/docbook-xsl-stylesheets
24 dev-libs/libxslt )"
25
26 RDEPEND="${COMMON_DEPEND}
27 sys-apps/hwids
28 !sys-apps/coldplug
29 !sys-apps/systemd
30 !<sys-fs/lvm2-2.02.45
31 !sys-fs/device-mapper
32 !<sys-fs/udev-init-scripts-16
33 !<sys-kernel/dracut-017-r1
34 !<sys-kernel/genkernel-3.4.25"
35
36 S="${WORKDIR}/mudev-${PV}"
37
38 src_configure() {
39 sed -i "s:PREFIX?=/usr/local:PREFIX?=/usr:" "${S}"/conf.mk
40 sed -i "s:LIBDIR?=/lib:LIBDIR?=/$(get_libdir):" "${S}"/conf.mk
41 sed -i "s:PKGLIBEXECDIR?=/lib/udev:PKGLIBEXECDIR?=/$(get_libdir)/udev:" "${S}"/conf.mk
42 sed -i "s:FIRMWARE_PATH?=/lib/firmware:FIRMWARE_PATH?=/$(get_libdir)/firmware:" "${S}"/conf.mk
43 }
44
45 src_compile() {
46 if use doc
47 then
48 MAN=1 emake all
49 else
50 emake all
51 fi
52 }
53
54 src_install() {
55 into /
56 dolib.so build/lib/libudev.so.0.0.0
57 dosym libudev.so.0.0.0 /$(get_libdir)/libudev.so.0
58 dosym libudev.so.0.0.0 /$(get_libdir)/libudev.so
59 dosbin build/bin/udevd
60 dosbin build/bin/udevadm
61
62 insinto /$(get_libdir)/udev/rules.d
63 doins rules/*
64
65 insinto /usr/share/pkgconfig
66 doins build/devel/udev.pc
67
68 insinto /usr/$(get_libdir)/pkgconfig
69 doins build/devel/libudev.pc
70
71 insinto /usr/include
72 doins src/libudev.h
73 }
74
75 pkg_postinst() {
76 mkdir -p "${ROOT}"/run
77 }
File makefile added (mode: 100644) (index 0000000..a20087c)
1 #This is a brutal makefile... but extremely easy to read as it is actually
2 #very basic makefile logic.
3 #**this is on purpose, then keep it that way**
4 include conf.mk
5
6 .PHONY:all dirs clean help
7
8 DIRS=\
9 $(S_DIR) \
10 $(CPP_DIR) \
11 $(OBJ_DIR) \
12 $(BIN_DIR) \
13 $(LIB_DIR) \
14 $(DEVEL_DIR)
15
16 ifdef MAN
17 DIRS+=$(MAN_DIR)
18 endif
19
20 LIBUDEV_OBJS=\
21 $(OBJ_DIR)/libudev.o \
22 $(OBJ_DIR)/libudev-device.o \
23 $(OBJ_DIR)/libudev-device-private.o \
24 $(OBJ_DIR)/libudev-enumerate.o \
25 $(OBJ_DIR)/libudev-list.o \
26 $(OBJ_DIR)/libudev-monitor.o \
27 $(OBJ_DIR)/libudev-queue.o \
28 $(OBJ_DIR)/libudev-queue-private.o \
29 $(OBJ_DIR)/libudev-util.o \
30 $(OBJ_DIR)/libudev-util-private.o
31
32 UDEVD_COMMON_OBJS=\
33 $(OBJ_DIR)/udev-event.o \
34 $(OBJ_DIR)/udev-watch.o \
35 $(OBJ_DIR)/udev-node.o \
36 $(OBJ_DIR)/udev-rules.o \
37 $(OBJ_DIR)/udev-ctrl.o \
38 $(OBJ_DIR)/udev-builtin.o \
39 $(OBJ_DIR)/udev-builtin-blkid.o \
40 $(OBJ_DIR)/udev-builtin-firmware.o \
41 $(OBJ_DIR)/udev-builtin-hwdb.o \
42 $(OBJ_DIR)/udev-builtin-input_id.o \
43 $(OBJ_DIR)/udev-builtin-kmod.o \
44 $(OBJ_DIR)/udev-builtin-path_id.o \
45 $(OBJ_DIR)/udev-builtin-usb_id.o
46
47 UDEVD_OBJS=\
48 $(UDEVD_COMMON_OBJS) \
49 $(OBJ_DIR)/udevd.o
50
51 UDEVADM_OBJS=\
52 $(UDEVD_COMMON_OBJS) \
53 $(OBJ_DIR)/udevadm.o \
54 $(OBJ_DIR)/udevadm-info.o \
55 $(OBJ_DIR)/udevadm-control.o \
56 $(OBJ_DIR)/udevadm-monitor.o \
57 $(OBJ_DIR)/udevadm-settle.o \
58 $(OBJ_DIR)/udevadm-trigger.o \
59 $(OBJ_DIR)/udevadm-test.o \
60 $(OBJ_DIR)/udevadm-test-builtin.o
61
62 ifdef MAN
63 MAN_PAGES=\
64 $(MAN_DIR)/udev.7 \
65 $(MAN_DIR)/udevadm.8 \
66 $(MAN_DIR)/udevd.8
67 endif
68
69 #*******************************************************************************
70 help:
71 @echo "targets are 'all', 'help'(this output), 'clean'"
72 @echo -e "you can configure the build with the following variables:\\n\
73 SYSROOT, CPP, CC, LD, CPPFLAGS, CFLAGS, LDFLAGS, SYSCONFDIR...\\n\
74 (you can tune the conf.mk file)"
75
76 all:dirs \
77 $(LIB_DIR)/libudev.so.$(LIBUDEV_VERSION) \
78 $(BIN_DIR)/udevd \
79 $(BIN_DIR)/udevadm \
80 $(DEVEL_DIR)/udev.pc \
81 $(DEVEL_DIR)/libudev.pc \
82 $(MAN_PAGES)
83
84 dirs:$(DIRS)
85 $(DIRS):
86 -mkdir -p $@
87
88 clean:
89 -rm -Rf $(BUILD_DIR)
90 #*******************************************************************************
91
92 #*******************************************************************************
93 #man pages implicit rule
94 $(MAN_DIR)/%.7 $(MAN_DIR)/%.8:src/%.xml
95 $(XSLTPROC) -o $@ -nonet \
96 http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl \
97 $<
98 #*******************************************************************************
99
100 #*******************************************************************************
101 #pkg-config
102 $(DEVEL_DIR)/udev.pc:src/udev.pc.in
103 cp -f $< $@
104 sed -i "s%@VERSION@%$(VERSION)%" $@
105 sed -i "s%@pkglibexecdir@%$(PKGLIBEXECDIR)%" $@
106
107 $(DEVEL_DIR)/libudev.pc:src/libudev.pc.in
108 cp -f $< $@
109 sed -i "s%@VERSION@%$(VERSION)%" $@
110 sed -i "s%@prefix@%$(PREFIX)%" $@
111 sed -i "s%@exec_prefix@%$(EXECPREFIX)%" $@
112 sed -i "s%@libdir@%$(LIBDIR)%" $@
113 sed -i "s%@includedir@%$(INCLUDEDIR)%" $@
114 #*******************************************************************************
115
116 #*******************************************************************************
117 #udevd
118 $(CPP_DIR)/udev-event.c:src/udev-event.c \
119 src/udev.h \
120 src/libudev.h \
121 src/libudev-private.h
122 $(CPP) $(CPPFLAGS) $< -o $@
123 $(S_DIR)/udev-event.s:$(CPP_DIR)/udev-event.c
124 $(CC) $(CFLAGS) $< -o $@
125 $(OBJ_DIR)/udev-event.o:$(S_DIR)/udev-event.s
126 $(AS) $(ASFLAGS) $< -o $@
127
128 $(CPP_DIR)/udev-watch.c:src/udev-watch.c \
129 src/udev.h \
130 src/libudev.h \
131 src/libudev-private.h
132 $(CPP) $(CPPFLAGS) $< -o $@
133 $(S_DIR)/udev-watch.s:$(CPP_DIR)/udev-watch.c
134 $(CC) $(CFLAGS) $< -o $@
135 $(OBJ_DIR)/udev-watch.o:$(S_DIR)/udev-watch.s
136 $(AS) $(ASFLAGS) $< -o $@
137
138 $(CPP_DIR)/udev-node.c:src/udev-node.c \
139 src/udev.h \
140 src/libudev.h \
141 src/libudev-private.h
142 $(CPP) $(CPPFLAGS) $< -o $@
143 $(S_DIR)/udev-node.s:$(CPP_DIR)/udev-node.c
144 $(CC) $(CFLAGS) $< -o $@
145 $(OBJ_DIR)/udev-node.o:$(S_DIR)/udev-node.s
146 $(AS) $(ASFLAGS) $< -o $@
147
148 $(CPP_DIR)/udev-rules.c:src/udev-rules.c \
149 src/udev.h \
150 src/libudev.h \
151 src/libudev-private.h
152 $(CPP) $(CPPFLAGS) $< -o $@
153 $(S_DIR)/udev-rules.s:$(CPP_DIR)/udev-rules.c
154 $(CC) $(CFLAGS) $< -o $@
155 $(OBJ_DIR)/udev-rules.o:$(S_DIR)/udev-rules.s
156 $(AS) $(ASFLAGS) $< -o $@
157
158 $(CPP_DIR)/udev-ctrl.c:src/udev-ctrl.c \
159 src/udev.h \
160 src/libudev.h \
161 src/libudev-private.h
162 $(CPP) $(CPPFLAGS) $< -o $@
163 $(S_DIR)/udev-ctrl.s:$(CPP_DIR)/udev-ctrl.c
164 $(CC) $(CFLAGS) $< -o $@
165 $(OBJ_DIR)/udev-ctrl.o:$(S_DIR)/udev-ctrl.s
166 $(AS) $(ASFLAGS) $< -o $@
167
168 $(CPP_DIR)/udev-builtin.c:src/udev-builtin.c \
169 src/udev.h \
170 src/libudev.h \
171 src/libudev-private.h
172 $(CPP) $(CPPFLAGS) $< -o $@
173 $(S_DIR)/udev-builtin.s:$(CPP_DIR)/udev-builtin.c
174 $(CC) $(CFLAGS) $< -o $@
175 $(OBJ_DIR)/udev-builtin.o:$(S_DIR)/udev-builtin.s
176 $(AS) $(ASFLAGS) $< -o $@
177
178 $(CPP_DIR)/udev-builtin-blkid.c:src/udev-builtin-blkid.c \
179 src/udev.h \
180 src/libudev.h \
181 src/libudev-private.h
182 $(CPP) $$($(PKG_CONFIG) --cflags-only-I blkid) $(CPPFLAGS) $< -o $@
183 $(S_DIR)/udev-builtin-blkid.s:$(CPP_DIR)/udev-builtin-blkid.c
184 $(CC) $$($(PKG_CONFIG) --cflags-only-other blkid) $(CFLAGS) $< -o $@
185 $(OBJ_DIR)/udev-builtin-blkid.o:$(S_DIR)/udev-builtin-blkid.s
186 $(AS) $(ASFLAGS) $< -o $@
187
188 $(CPP_DIR)/udev-builtin-firmware.c:src/udev-builtin-firmware.c \
189 src/udev.h \
190 src/libudev.h \
191 src/libudev-private.h
192 $(CPP) $(CPPFLAGS) $< -o $@
193 $(S_DIR)/udev-builtin-firmware.s:$(CPP_DIR)/udev-builtin-firmware.c
194 $(CC) $(CFLAGS) $< -o $@
195 $(OBJ_DIR)/udev-builtin-firmware.o:$(S_DIR)/udev-builtin-firmware.s
196 $(AS) $(ASFLAGS) $< -o $@
197
198 $(CPP_DIR)/udev-builtin-hwdb.c:src/udev-builtin-hwdb.c \
199 src/udev.h \
200 src/libudev.h \
201 src/libudev-private.h
202 $(CPP) $(CPPFLAGS) $< -o $@
203 $(S_DIR)/udev-builtin-hwdb.s:$(CPP_DIR)/udev-builtin-hwdb.c
204 $(CC) $(CFLAGS) $< -o $@
205 $(OBJ_DIR)/udev-builtin-hwdb.o:$(S_DIR)/udev-builtin-hwdb.s
206 $(AS) $(ASFLAGS) $< -o $@
207
208 $(CPP_DIR)/udev-builtin-input_id.c:src/udev-builtin-input_id.c \
209 src/udev.h \
210 src/libudev.h \
211 src/libudev-private.h
212 $(CPP) $(CPPFLAGS) $< -o $@
213 $(S_DIR)/udev-builtin-input_id.s:$(CPP_DIR)/udev-builtin-input_id.c
214 $(CC) $(CFLAGS) $< -o $@
215 $(OBJ_DIR)/udev-builtin-input_id.o:$(S_DIR)/udev-builtin-input_id.s
216 $(AS) $(ASFLAGS) $< -o $@
217
218 $(CPP_DIR)/udev-builtin-kmod.c:src/udev-builtin-kmod.c \
219 src/udev.h \
220 src/libudev.h \
221 src/libudev-private.h
222 $(CPP) $$($(PKG_CONFIG) --cflags-only-I libkmod) $(CPPFLAGS) $< -o $@
223 $(S_DIR)/udev-builtin-kmod.s:$(CPP_DIR)/udev-builtin-kmod.c
224 $(CC) $$($(PKG_CONFIG) --cflags-only-other libkmod) $(CFLAGS) $< -o $@
225 $(OBJ_DIR)/udev-builtin-kmod.o:$(S_DIR)/udev-builtin-kmod.s
226 $(AS) $(ASFLAGS) $< -o $@
227
228 $(CPP_DIR)/udev-builtin-path_id.c:src/udev-builtin-path_id.c \
229 src/udev.h \
230 src/libudev.h \
231 src/libudev-private.h
232 $(CPP) $(CPPFLAGS) $< -o $@
233 $(S_DIR)/udev-builtin-path_id.s:$(CPP_DIR)/udev-builtin-path_id.c
234 $(CC) $(CFLAGS) $< -o $@
235 $(OBJ_DIR)/udev-builtin-path_id.o:$(S_DIR)/udev-builtin-path_id.s
236 $(AS) $(ASFLAGS) $< -o $@
237
238 $(CPP_DIR)/udev-builtin-usb_id.c:src/udev-builtin-usb_id.c \
239 src/udev.h \
240 src/libudev.h \
241 src/libudev-private.h
242 $(CPP) $(CPPFLAGS) $< -o $@
243 $(S_DIR)/udev-builtin-usb_id.s:$(CPP_DIR)/udev-builtin-usb_id.c
244 $(CC) $(CFLAGS) $< -o $@
245 $(OBJ_DIR)/udev-builtin-usb_id.o:$(S_DIR)/udev-builtin-usb_id.s
246 $(AS) $(ASFLAGS) $< -o $@
247
248 $(CPP_DIR)/udevd.c:src/udevd.c \
249 src/udev.h \
250 src/libudev.h \
251 src/libudev-private.h
252 $(CPP) $(CPPFLAGS) $< -o $@
253 $(S_DIR)/udevd.s:$(CPP_DIR)/udevd.c
254 $(CC) $(CFLAGS) $< -o $@
255 $(OBJ_DIR)/udevd.o:$(S_DIR)/udevd.s
256 $(AS) $(ASFLAGS) $< -o $@
257 #-------------------------------------------------------------------------------
258 $(BIN_DIR)/udevd:$(LIB_DIR)/libudev.so.$(LIBUDEV_VERSION) $(UDEVD_OBJS)
259 $(CC) $(LIB_DIR)/libudev.so.$(LIBUDEV_VERSION) $(UDEVD_OBJS) \
260 $$($(PKG_CONFIG) --libs blkid) \
261 $$($(PKG_CONFIG) --libs libkmod) \
262 -o $@
263 #*******************************************************************************
264
265 #*******************************************************************************
266 #udevadm
267 $(CPP_DIR)/udevadm.c:src/udevadm.c \
268 src/udev.h \
269 src/libudev.h \
270 src/libudev-private.h
271 $(CPP) $(CPPFLAGS) $< -o $@
272 $(S_DIR)/udevadm.s:$(CPP_DIR)/udevadm.c
273 $(CC) $(CFLAGS) $< -o $@
274 $(OBJ_DIR)/udevadm.o:$(S_DIR)/udevadm.s
275 $(AS) $(ASFLAGS) $< -o $@
276
277 $(CPP_DIR)/udevadm-info.c:src/udevadm-info.c \
278 src/udev.h \
279 src/libudev.h \
280 src/libudev-private.h
281 $(CPP) $(CPPFLAGS) $< -o $@
282 $(S_DIR)/udevadm-info.s:$(CPP_DIR)/udevadm-info.c
283 $(CC) $(CFLAGS) $< -o $@
284 $(OBJ_DIR)/udevadm-info.o:$(S_DIR)/udevadm-info.s
285 $(AS) $(ASFLAGS) $< -o $@
286
287 $(CPP_DIR)/udevadm-control.c:src/udevadm-control.c \
288 src/udev.h \
289 src/libudev.h \
290 src/libudev-private.h
291 $(CPP) $(CPPFLAGS) $< -o $@
292 $(S_DIR)/udevadm-control.s:$(CPP_DIR)/udevadm-control.c
293 $(CC) $(CFLAGS) $< -o $@
294 $(OBJ_DIR)/udevadm-control.o:$(S_DIR)/udevadm-control.s
295 $(AS) $(ASFLAGS) $< -o $@
296
297 $(CPP_DIR)/udevadm-monitor.c:src/udevadm-monitor.c \
298 src/udev.h \
299 src/libudev.h \
300 src/libudev-private.h
301 $(CPP) $(CPPFLAGS) $< -o $@
302 $(S_DIR)/udevadm-monitor.s:$(CPP_DIR)/udevadm-monitor.c
303 $(CC) $(CFLAGS) $< -o $@
304 $(OBJ_DIR)/udevadm-monitor.o:$(S_DIR)/udevadm-monitor.s
305 $(AS) $(ASFLAGS) $< -o $@
306
307 $(CPP_DIR)/udevadm-settle.c:src/udevadm-settle.c \
308 src/udev.h \
309 src/libudev.h \
310 src/libudev-private.h
311 $(CPP) $(CPPFLAGS) $< -o $@
312 $(S_DIR)/udevadm-settle.s:$(CPP_DIR)/udevadm-settle.c
313 $(CC) $(CFLAGS) $< -o $@
314 $(OBJ_DIR)/udevadm-settle.o:$(S_DIR)/udevadm-settle.s
315 $(AS) $(ASFLAGS) $< -o $@
316
317 $(CPP_DIR)/udevadm-trigger.c:src/udevadm-trigger.c \
318 src/udev.h \
319 src/libudev.h \
320 src/libudev-private.h
321 $(CPP) $(CPPFLAGS) $< -o $@
322 $(S_DIR)/udevadm-trigger.s:$(CPP_DIR)/udevadm-trigger.c
323 $(CC) $(CFLAGS) $< -o $@
324 $(OBJ_DIR)/udevadm-trigger.o:$(S_DIR)/udevadm-trigger.s
325 $(AS) $(ASFLAGS) $< -o $@
326
327 $(CPP_DIR)/udevadm-test.c:src/udevadm-test.c \
328 src/udev.h \
329 src/libudev.h \
330 src/libudev-private.h
331 $(CPP) $(CPPFLAGS) $< -o $@
332 $(S_DIR)/udevadm-test.s:$(CPP_DIR)/udevadm-test.c
333 $(CC) $(CFLAGS) $< -o $@
334 $(OBJ_DIR)/udevadm-test.o:$(S_DIR)/udevadm-test.s
335 $(AS) $(ASFLAGS) $< -o $@
336
337 $(CPP_DIR)/udevadm-test-builtin.c:src/udevadm-test-builtin.c \
338 src/udev.h \
339 src/libudev.h \
340 src/libudev-private.h
341 $(CPP) $(CPPFLAGS) $< -o $@
342 $(S_DIR)/udevadm-test-builtin.s:$(CPP_DIR)/udevadm-test-builtin.c
343 $(CC) $(CFLAGS) $< -o $@
344 $(OBJ_DIR)/udevadm-test-builtin.o:$(S_DIR)/udevadm-test-builtin.s
345 $(AS) $(ASFLAGS) $< -o $@
346 #-------------------------------------------------------------------------------
347 $(BIN_DIR)/udevadm:$(LIB_DIR)/libudev.so.$(LIBUDEV_VERSION) $(UDEVADM_OBJS)
348 $(CC) $(LIB_DIR)/libudev.so.$(LIBUDEV_VERSION) $(UDEVADM_OBJS) \
349 $$($(PKG_CONFIG) --libs blkid) \
350 $$($(PKG_CONFIG) --libs libkmod) \
351 -o $@
352 #*******************************************************************************
353
354 #*******************************************************************************
355 #libudev
356 $(CPP_DIR)/libudev.c:src/libudev.c \
357 src/libudev.h \
358 src/libudev-private.h
359 $(CPP) $(CPPFLAGS) $< -o $@
360 $(S_DIR)/libudev.s:$(CPP_DIR)/libudev.c
361 $(CC) -fPIC $(CFLAGS) $< -o $@
362 $(OBJ_DIR)/libudev.o:$(S_DIR)/libudev.s
363 $(AS) $(ASFLAGS) $< -o $@
364
365 $(CPP_DIR)/libudev-device.c:src/libudev-device.c \
366 src/libudev.h \
367 src/libudev-private.h
368 $(CPP) $(CPPFLAGS) $< -o $@
369 $(S_DIR)/libudev-device.s:$(CPP_DIR)/libudev-device.c
370 $(CC) -fPIC $(CFLAGS) $< -o $@
371 $(OBJ_DIR)/libudev-device.o:$(S_DIR)/libudev-device.s
372 $(AS) $(ASFLAGS) $< -o $@
373
374 $(CPP_DIR)/libudev-device-private.c:src/libudev-device-private.c \
375 src/libudev.h \
376 src/libudev-private.h
377 $(CPP) $(CPPFLAGS) $< -o $@
378 $(S_DIR)/libudev-device-private.s:$(CPP_DIR)/libudev-device-private.c
379 $(CC) -fPIC $(CFLAGS) $< -o $@
380 $(OBJ_DIR)/libudev-device-private.o:$(S_DIR)/libudev-device-private.s
381 $(AS) $(ASFLAGS) $< -o $@
382
383 $(CPP_DIR)/libudev-enumerate.c:src/libudev-enumerate.c \
384 src/libudev.h \
385 src/libudev-private.h
386 $(CPP) $(CPPFLAGS) $< -o $@
387 $(S_DIR)/libudev-enumerate.s:$(CPP_DIR)/libudev-enumerate.c
388 $(CC) -fPIC $(CFLAGS) $< -o $@
389 $(OBJ_DIR)/libudev-enumerate.o:$(S_DIR)/libudev-enumerate.s
390 $(AS) $(ASFLAGS) $< -o $@
391
392 $(CPP_DIR)/libudev-list.c:src/libudev-list.c \
393 src/libudev.h \
394 src/libudev-private.h
395 $(CPP) $(CPPFLAGS) $< -o $@
396 $(S_DIR)/libudev-list.s:$(CPP_DIR)/libudev-list.c
397 $(CC) -fPIC $(CFLAGS) $< -o $@
398 $(OBJ_DIR)/libudev-list.o:$(S_DIR)/libudev-list.s
399 $(AS) $(ASFLAGS) $< -o $@
400
401 $(CPP_DIR)/libudev-monitor.c:src/libudev-monitor.c \
402 src/libudev.h \
403 src/libudev-private.h
404 $(CPP) $(CPPFLAGS) $< -o $@
405 $(S_DIR)/libudev-monitor.s:$(CPP_DIR)/libudev-monitor.c
406 $(CC) -fPIC $(CFLAGS) $< -o $@
407 $(OBJ_DIR)/libudev-monitor.o:$(S_DIR)/libudev-monitor.s
408 $(AS) $(ASFLAGS) $< -o $@
409
410 $(CPP_DIR)/libudev-queue.c:src/libudev-queue.c \
411 src/libudev.h \
412 src/libudev-private.h
413 $(CPP) $(CPPFLAGS) $< -o $@
414 $(S_DIR)/libudev-queue.s:$(CPP_DIR)/libudev-queue.c
415 $(CC) -fPIC $(CFLAGS) $< -o $@
416 $(OBJ_DIR)/libudev-queue.o:$(S_DIR)/libudev-queue.s
417 $(AS) $(ASFLAGS) $< -o $@
418
419 $(CPP_DIR)/libudev-queue-private.c:src/libudev-queue-private.c \
420 src/libudev.h \
421 src/libudev-private.h
422 $(CPP) $(CPPFLAGS) $< -o $@
423 $(S_DIR)/libudev-queue-private.s:$(CPP_DIR)/libudev-queue-private.c
424 $(CC) -fPIC $(CFLAGS) $< -o $@
425 $(OBJ_DIR)/libudev-queue-private.o:$(S_DIR)/libudev-queue-private.s
426 $(AS) $(ASFLAGS) $< -o $@
427
428 $(CPP_DIR)/libudev-util.c:src/libudev-util.c \
429 src/libudev.h \
430 src/libudev-private.h
431 $(CPP) $(CPPFLAGS) $< -o $@
432 $(S_DIR)/libudev-util.s:$(CPP_DIR)/libudev-util.c
433 $(CC) -fPIC $(CFLAGS) $< -o $@
434 $(OBJ_DIR)/libudev-util.o:$(S_DIR)/libudev-util.s
435 $(AS) $(ASFLAGS) $< -o $@
436
437 $(CPP_DIR)/libudev-util-private.c:src/libudev-util-private.c \
438 src/libudev.h \
439 src/libudev-private.h
440 $(CPP) $(CPPFLAGS) $< -o $@
441 $(S_DIR)/libudev-util-private.s:$(CPP_DIR)/libudev-util-private.c
442 $(CC) -fPIC $(CFLAGS) $< -o $@
443 $(OBJ_DIR)/libudev-util-private.o:$(S_DIR)/libudev-util-private.s
444 $(AS) $(ASFLAGS) $< -o $@
445 #-------------------------------------------------------------------------------
446 $(LIB_DIR)/libudev.so.$(LIBUDEV_VERSION):$(LIBUDEV_OBJS)
447 $(LD) -o $@ -shared $(LDFLAGS) -Wl,-h,libudev.so.$(LIBUDEV_API) \
448 $(LIBUDEV_OBJS) -lc -lrt
449 #*******************************************************************************
File rules/42-usb-hid-pm.rules added (mode: 100644) (index 0000000..d5d5897)
1 #
2 # Enable autosuspend for qemu emulated usb hid devices.
3 #
4 # Note that there are buggy qemu versions which advertise remote
5 # wakeup support but don't actually implement it correctly. This
6 # is the reason why we need a match for the serial number here.
7 # The serial number "42" is used to tag the implementations where
8 # remote wakeup is working.
9 #
10
11 ACTION=="add", SUBSYSTEM=="usb", ATTR{product}=="QEMU USB Mouse", ATTR{serial}=="42", TEST=="power/control", ATTR{power/control}="auto"
12 ACTION=="add", SUBSYSTEM=="usb", ATTR{product}=="QEMU USB Tablet", ATTR{serial}=="42", TEST=="power/control", ATTR{power/control}="auto"
13 ACTION=="add", SUBSYSTEM=="usb", ATTR{product}=="QEMU USB Keyboard", ATTR{serial}=="42", TEST=="power/control", ATTR{power/control}="auto"
14
15 #
16 # Enable autosuspend for KVM and iLO usb hid devices. These are
17 # effectively self-powered (despite what some claim in their USB
18 # profiles) and so it's safe to do so.
19 #
20
21 # AMI 046b:ff10
22 ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="046b", ATTR{idProduct}=="ff10", TEST=="power/control", ATTR{power/control}="auto"
23
24 #
25 # Catch-all for Avocent HID devices. Keyed off interface in order to only
26 # trigger on HID class devices.
27 #
28 ACTION=="add", SUBSYSTEM=="usb", ATTRS{idVendor}=="0624", ATTR{bInterfaceClass}=="03", TEST=="../power/control", ATTR{../power/control}="auto"
29
30 # Dell DRAC 4
31 ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="413c", ATTR{idProduct}=="2500", TEST=="power/control", ATTR{power/control}="auto"
32
33 # Dell DRAC 5
34 ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="413c", ATTR{idProduct}=="0000", TEST=="power/control", ATTR{power/control}="auto"
35
36 # Hewlett Packard iLO
37 ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="03f0", ATTR{idProduct}=="7029", TEST=="power/control", ATTR{power/control}="auto"
38 ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="03f0", ATTR{idProduct}=="1027", TEST=="power/control", ATTR{power/control}="auto"
39
40 # IBM remote access
41 ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="04b3", ATTR{idProduct}=="4001", TEST=="power/control", ATTR{power/control}="auto"
42 ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="04b3", ATTR{idProduct}=="4002", TEST=="power/control", ATTR{power/control}="auto"
43 ACTION=="add", SUBSYSTEM=="usb", ATTRS{idVendor}=="04b3", ATTR{idProduct}=="4012", TEST=="power/control", ATTR{power/control}="auto"
44
45 # Raritan Computer, Inc KVM.
46 ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="14dd", ATTR{idProduct}="0002", TEST=="power/control", ATTR{power/control}="auto"
47
48 # USB HID devices that are internal to the machine should also be safe to autosuspend
49 ACTION=="add", SUBSYSTEM=="usb", ATTR{bInterfaceClass}=="03", ATTRS{removable}=="fixed", TEST=="../power/control", ATTR{../power/control}="auto"
File rules/50-udev-default.rules added (mode: 100644) (index 0000000..5ad787f)
1 # do not edit this file, it will be overwritten on update
2
3 KERNEL=="pty[pqrstuvwxyzabcdef][0123456789abcdef]", GROUP="tty", MODE="0660"
4 KERNEL=="tty[pqrstuvwxyzabcdef][0123456789abcdef]", GROUP="tty", MODE="0660"
5 KERNEL=="ptmx", GROUP="tty", MODE="0666"
6 KERNEL=="tty", GROUP="tty", MODE="0666"
7 KERNEL=="tty[0-9]*", GROUP="tty", MODE="0620"
8 KERNEL=="vcs|vcs[0-9]*|vcsa|vcsa[0-9]*", GROUP="tty"
9
10 # serial
11 KERNEL=="tty[A-Z]*[0-9]|pppox[0-9]*|ircomm[0-9]*|noz[0-9]*|rfcomm[0-9]*", GROUP="dialout"
12 KERNEL=="mwave", GROUP="dialout"
13 KERNEL=="hvc*|hvsi*", GROUP="dialout"
14
15 # virtio serial / console ports
16 KERNEL=="vport*", ATTR{name}=="?*", SYMLINK+="virtio-ports/$attr{name}"
17
18 # mem
19 KERNEL=="null|zero|full|random|urandom", MODE="0666"
20 KERNEL=="mem|kmem|port|nvram", GROUP="kmem", MODE="0640"
21
22 # input
23 SUBSYSTEM=="input", ENV{ID_INPUT}=="", IMPORT{builtin}="input_id"
24 KERNEL=="mouse*|mice|event*", MODE="0640"
25 KERNEL=="ts[0-9]*|uinput", MODE="0640"
26 KERNEL=="js[0-9]*", MODE="0644"
27
28 # video4linux
29 SUBSYSTEM=="video4linux", GROUP="video"
30 KERNEL=="vttuner*", GROUP="video"
31 KERNEL=="vtx*|vbi*", GROUP="video"
32 KERNEL=="winradio*", GROUP="video"
33
34 # graphics
35 KERNEL=="agpgart", GROUP="video"
36 KERNEL=="pmu", GROUP="video"
37 KERNEL=="nvidia*|nvidiactl*", GROUP="video"
38 SUBSYSTEM=="graphics", GROUP="video"
39 SUBSYSTEM=="drm", GROUP="video"
40
41 # sound
42 SUBSYSTEM=="sound", GROUP="audio", \
43 OPTIONS+="static_node=snd/seq", OPTIONS+="static_node=snd/timer"
44
45 # DVB (video)
46 SUBSYSTEM=="dvb", GROUP="video"
47
48 # FireWire (firewire-core driver: IIDC devices, AV/C devices)
49 SUBSYSTEM=="firewire", ATTR{units}=="*0x00a02d:0x00010*", GROUP="video"
50 SUBSYSTEM=="firewire", ATTR{units}=="*0x00b09d:0x00010*", GROUP="video"
51 SUBSYSTEM=="firewire", ATTR{units}=="*0x00a02d:0x010001*", GROUP="video"
52 SUBSYSTEM=="firewire", ATTR{units}=="*0x00a02d:0x014001*", GROUP="video"
53
54 # 'libusb' device nodes
55 SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", MODE="0664"
56 SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", IMPORT{builtin}="usb_id"
57
58 # printer
59 KERNEL=="parport[0-9]*", GROUP="lp"
60 SUBSYSTEM=="printer", KERNEL=="lp*", GROUP="lp"
61 SUBSYSTEM=="ppdev", GROUP="lp"
62 KERNEL=="lp[0-9]*", GROUP="lp"
63 KERNEL=="irlpt[0-9]*", GROUP="lp"
64 SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{ID_USB_INTERFACES}=="*:0701??:*", GROUP="lp"
65
66 # block
67 SUBSYSTEM=="block", GROUP="disk"
68
69 # floppy
70 SUBSYSTEM=="block", KERNEL=="fd[0-9]", GROUP="floppy"
71
72 # cdrom
73 SUBSYSTEM=="block", KERNEL=="sr[0-9]*", GROUP="cdrom"
74 SUBSYSTEM=="scsi_generic", SUBSYSTEMS=="scsi", ATTRS{type}=="4|5", GROUP="cdrom"
75 KERNEL=="pktcdvd[0-9]*", GROUP="cdrom"
76 KERNEL=="pktcdvd", GROUP="cdrom"
77
78 # tape
79 KERNEL=="ht[0-9]*|nht[0-9]*", GROUP="tape"
80 KERNEL=="pt[0-9]*|npt[0-9]*|pht[0-9]*", GROUP="tape"
81 SUBSYSTEM=="scsi_generic|scsi_tape", SUBSYSTEMS=="scsi", ATTRS{type}=="1|8", GROUP="tape"
82
83 # block-related
84 KERNEL=="sch[0-9]*", GROUP="disk"
85 SUBSYSTEM=="scsi_generic", SUBSYSTEMS=="scsi", ATTRS{type}=="0", GROUP="disk"
86 KERNEL=="pg[0-9]*", GROUP="disk"
87 KERNEL=="qft[0-9]*|nqft[0-9]*|zqft[0-9]*|nzqft[0-9]*|rawqft[0-9]*|nrawqft[0-9]*", GROUP="disk"
88 KERNEL=="rawctl", GROUP="disk"
89 SUBSYSTEM=="raw", KERNEL=="raw[0-9]*", GROUP="disk"
90 SUBSYSTEM=="aoe", GROUP="disk", MODE="0220"
91 SUBSYSTEM=="aoe", KERNEL=="err", MODE="0440"
92
93 # network
94 KERNEL=="tun", MODE="0666", OPTIONS+="static_node=net/tun"
95 KERNEL=="rfkill", MODE="0644"
96
97 # CPU
98 KERNEL=="cpu[0-9]*", MODE="0444"
99
100 KERNEL=="fuse", ACTION=="add", MODE="0666", OPTIONS+="static_node=fuse"
101
102 SUBSYSTEM=="rtc", ATTR{hctosys}=="1", SYMLINK+="rtc"
103 KERNEL=="mmtimer", MODE="0644"
104 KERNEL=="rflash[0-9]*", MODE="0400"
105 KERNEL=="rrom[0-9]*", MODE="0400"
106
107 SUBSYSTEM=="firmware", ACTION=="add", IMPORT{builtin}="firmware"
File rules/60-persistent-alsa.rules added (mode: 100644) (index 0000000..8154e2d)
1 # do not edit this file, it will be overwritten on update
2
3 ACTION=="remove", GOTO="persistent_alsa_end"
4 SUBSYSTEM!="sound", GOTO="persistent_alsa_end"
5 KERNEL!="controlC[0-9]*", GOTO="persistent_alsa_end"
6
7 SUBSYSTEMS=="usb", ENV{ID_MODEL}=="", IMPORT{builtin}="usb_id"
8 ENV{ID_SERIAL}=="?*", ENV{ID_USB_INTERFACE_NUM}=="?*", SYMLINK+="snd/by-id/$env{ID_BUS}-$env{ID_SERIAL}-$env{ID_USB_INTERFACE_NUM}"
9 ENV{ID_SERIAL}=="?*", ENV{ID_USB_INTERFACE_NUM}=="", SYMLINK+="snd/by-id/$env{ID_BUS}-$env{ID_SERIAL}"
10
11 IMPORT{builtin}="path_id"
12 ENV{ID_PATH}=="?*", SYMLINK+="snd/by-path/$env{ID_PATH}"
13
14 LABEL="persistent_alsa_end"
File rules/60-persistent-input.rules added (mode: 100644) (index 0000000..fb798dd)
1 # do not edit this file, it will be overwritten on update
2
3 ACTION=="remove", GOTO="persistent_input_end"
4 SUBSYSTEM!="input", GOTO="persistent_input_end"
5 SUBSYSTEMS=="bluetooth", GOTO="persistent_input_end"
6
7 SUBSYSTEMS=="usb", ENV{ID_BUS}=="", IMPORT{builtin}="usb_id"
8
9 # determine class name for persistent symlinks
10 ENV{ID_INPUT_KEYBOARD}=="?*", ENV{.INPUT_CLASS}="kbd"
11 ENV{ID_INPUT_MOUSE}=="?*", ENV{.INPUT_CLASS}="mouse"
12 ENV{ID_INPUT_TOUCHPAD}=="?*", ENV{.INPUT_CLASS}="mouse"
13 ENV{ID_INPUT_TABLET}=="?*", ENV{.INPUT_CLASS}="mouse"
14 ENV{ID_INPUT_JOYSTICK}=="?*", ENV{.INPUT_CLASS}="joystick"
15 DRIVERS=="pcspkr", ENV{.INPUT_CLASS}="spkr"
16 ATTRS{name}=="*dvb*|*DVB*|* IR *", ENV{.INPUT_CLASS}="ir"
17
18 # fill empty serial number
19 ENV{.INPUT_CLASS}=="?*", ENV{ID_SERIAL}=="", ENV{ID_SERIAL}="noserial"
20
21 # by-id links
22 KERNEL=="mouse*|js*", ENV{ID_BUS}=="?*", ENV{.INPUT_CLASS}=="?*", SYMLINK+="input/by-id/$env{ID_BUS}-$env{ID_SERIAL}-$env{.INPUT_CLASS}"
23 KERNEL=="mouse*|js*", ENV{ID_BUS}=="?*", ENV{.INPUT_CLASS}=="?*", ATTRS{bInterfaceNumber}=="?*", ATTRS{bInterfaceNumber}!="00", SYMLINK+="input/by-id/$env{ID_BUS}-$env{ID_SERIAL}-if$attr{bInterfaceNumber}-$env{.INPUT_CLASS}"
24 KERNEL=="event*", ENV{ID_BUS}=="?*", ENV{.INPUT_CLASS}=="?*", SYMLINK+="input/by-id/$env{ID_BUS}-$env{ID_SERIAL}-event-$env{.INPUT_CLASS}"
25 KERNEL=="event*", ENV{ID_BUS}=="?*", ENV{.INPUT_CLASS}=="?*", ATTRS{bInterfaceNumber}=="?*", ATTRS{bInterfaceNumber}!="00", SYMLINK+="input/by-id/$env{ID_BUS}-$env{ID_SERIAL}-if$attr{bInterfaceNumber}-event-$env{.INPUT_CLASS}"
26 # allow empty class for USB devices, by appending the interface number
27 SUBSYSTEMS=="usb", ENV{ID_BUS}=="?*", KERNEL=="event*", ENV{.INPUT_CLASS}=="", ATTRS{bInterfaceNumber}=="?*", \
28 SYMLINK+="input/by-id/$env{ID_BUS}-$env{ID_SERIAL}-event-if$attr{bInterfaceNumber}"
29
30 # by-path
31 SUBSYSTEMS=="pci|usb|platform|acpi", IMPORT{builtin}="path_id"
32 ENV{ID_PATH}=="?*", KERNEL=="mouse*|js*", ENV{.INPUT_CLASS}=="?*", SYMLINK+="input/by-path/$env{ID_PATH}-$env{.INPUT_CLASS}"
33 ENV{ID_PATH}=="?*", KERNEL=="event*", ENV{.INPUT_CLASS}=="?*", SYMLINK+="input/by-path/$env{ID_PATH}-event-$env{.INPUT_CLASS}"
34 # allow empty class for platform and usb devices; platform supports only a single interface that way
35 SUBSYSTEMS=="usb|platform", ENV{ID_PATH}=="?*", KERNEL=="event*", ENV{.INPUT_CLASS}=="", \
36 SYMLINK+="input/by-path/$env{ID_PATH}-event"
37
38 LABEL="persistent_input_end"
File rules/60-persistent-net.rules added (mode: 100644) (index 0000000..3265afe)
1 # do not edit this file, it will be overwritten on update
2 #
3 # General idea: Set up ID_* entries in the udev db that can be looked up by the
4 # distro's network config later to find the right NIC device to configure. This
5 # is compatible with the persistent-net-generator rules if those are enabled.
6 #
7 # Find the NIC for a given attribute with something like:
8 # $(find-nic [ mac-{address} | path-{path specifier} | ethN ])
9 #
10 # where find-nic looks something like:
11 #
12 # #!/bin/bash
13 # # Accept real interfaces as well as identifiers
14 # if [ -e /sys/class/net/"${1}" ] ; then
15 # echo "${1}"
16 # exit 0
17 # fi
18 #
19 # id="${1#*-}"
20 #
21 # case "$1" in
22 # mac-*)
23 # for dev in /sys/class/net/* ; do
24 # if /sbin/udevadm info -q env -p "$dev" | grep -q "ID_ADDRESS=${id}\$" ; then
25 # echo "${dev##*/}"
26 # exit 0
27 # fi
28 # done
29 # exit 1
30 # ;;
31 # path-*)
32 # for dev in /sys/class/net/* ; do
33 # if /sbin/udevadm info -q env -p "$dev" | grep -q "ID_PATH=${id}\$" ; then
34 # echo "${dev##*/}"
35 # exit 0
36 # fi
37 # done
38 # exit 1
39 # ;;
40 # *)
41 # echo "Don't know how to dereference $1." >&2
42 # exit 2
43 # ;;
44 # esac
45
46 ACTION=="remove", GOTO="persistent_net_end"
47 SUBSYSTEM!="net", GOTO="persistent_net_end"
48
49 # Stash away the MAC address into the udev db
50 ENV{ID_ADDRESS}="$attr{address}"
51
52 # Grab a set of path-id exports as well
53 IMPORT{builtin}="path_id"
54
55 LABEL="persistent_net_end"
File rules/60-persistent-serial.rules added (mode: 100644) (index 0000000..2948200)
1 # do not edit this file, it will be overwritten on update
2
3 ACTION=="remove", GOTO="persistent_serial_end"
4 SUBSYSTEM!="tty", GOTO="persistent_serial_end"
5 KERNEL!="ttyUSB[0-9]*|ttyACM[0-9]*", GOTO="persistent_serial_end"
6
7 SUBSYSTEMS=="usb-serial", ENV{.ID_PORT}="$attr{port_number}"
8
9 IMPORT{builtin}="path_id"
10 ENV{ID_PATH}=="?*", ENV{.ID_PORT}=="", SYMLINK+="serial/by-path/$env{ID_PATH}"
11 ENV{ID_PATH}=="?*", ENV{.ID_PORT}=="?*", SYMLINK+="serial/by-path/$env{ID_PATH}-port$env{.ID_PORT}"
12
13 IMPORT{builtin}="usb_id"
14 ENV{ID_SERIAL}=="", GOTO="persistent_serial_end"
15 SUBSYSTEMS=="usb", ENV{ID_USB_INTERFACE_NUM}="$attr{bInterfaceNumber}"
16 ENV{ID_USB_INTERFACE_NUM}=="", GOTO="persistent_serial_end"
17 ENV{.ID_PORT}=="", SYMLINK+="serial/by-id/$env{ID_BUS}-$env{ID_SERIAL}-if$env{ID_USB_INTERFACE_NUM}"
18 ENV{.ID_PORT}=="?*", SYMLINK+="serial/by-id/$env{ID_BUS}-$env{ID_SERIAL}-if$env{ID_USB_INTERFACE_NUM}-port$env{.ID_PORT}"
19
20 LABEL="persistent_serial_end"
File rules/60-persistent-storage-tape.rules added (mode: 100644) (index 0000000..f2eabd9)
1 # do not edit this file, it will be overwritten on update
2
3 # persistent storage links: /dev/tape/{by-id,by-path}
4
5 ACTION=="remove", GOTO="persistent_storage_tape_end"
6
7 # type 8 devices are "Medium Changers"
8 SUBSYSTEM=="scsi_generic", SUBSYSTEMS=="scsi", ATTRS{type}=="8", IMPORT{program}="scsi_id --sg-version=3 --export --whitelisted -d $devnode", \
9 SYMLINK+="tape/by-id/scsi-$env{ID_SERIAL}"
10
11 SUBSYSTEM!="scsi_tape", GOTO="persistent_storage_tape_end"
12
13 KERNEL=="st*[0-9]|nst*[0-9]", ATTRS{ieee1394_id}=="?*", ENV{ID_SERIAL}="$attr{ieee1394_id}", ENV{ID_BUS}="ieee1394"
14 KERNEL=="st*[0-9]|nst*[0-9]", ENV{ID_SERIAL}!="?*", SUBSYSTEMS=="usb", IMPORT{builtin}="usb_id"
15 KERNEL=="st*[0-9]|nst*[0-9]", ENV{ID_SERIAL}!="?*", SUBSYSTEMS=="scsi", KERNELS=="[0-9]*:*[0-9]", ENV{.BSG_DEV}="$root/bsg/$id"
16 KERNEL=="st*[0-9]|nst*[0-9]", ENV{ID_SERIAL}!="?*", IMPORT{program}="scsi_id --whitelisted --export --device=$env{.BSG_DEV}", ENV{ID_BUS}="scsi"
17 KERNEL=="st*[0-9]", ENV{ID_SERIAL}=="?*", SYMLINK+="tape/by-id/$env{ID_BUS}-$env{ID_SERIAL}"
18 KERNEL=="nst*[0-9]", ENV{ID_SERIAL}=="?*", SYMLINK+="tape/by-id/$env{ID_BUS}-$env{ID_SERIAL}-nst"
19
20 # by-path (parent device path)
21 KERNEL=="st*[0-9]|nst*[0-9]", IMPORT{builtin}="path_id"
22 KERNEL=="st*[0-9]", ENV{ID_PATH}=="?*", SYMLINK+="tape/by-path/$env{ID_PATH}"
23 KERNEL=="nst*[0-9]", ENV{ID_PATH}=="?*", SYMLINK+="tape/by-path/$env{ID_PATH}-nst"
24
25 LABEL="persistent_storage_tape_end"
File rules/60-persistent-storage.rules added (mode: 100644) (index 0000000..b74821e)
1 # do not edit this file, it will be overwritten on update
2
3 # persistent storage links: /dev/disk/{by-id,by-uuid,by-label,by-path}
4 # scheme based on "Linux persistent device names", 2004, Hannes Reinecke <hare@suse.de>
5
6 # forward scsi device event to corresponding block device
7 ACTION=="change", SUBSYSTEM=="scsi", ENV{DEVTYPE}=="scsi_device", TEST=="block", ATTR{block/*/uevent}="change"
8
9 ACTION=="remove", GOTO="persistent_storage_end"
10
11 # enable in-kernel media-presence polling
12 ACTION=="add", SUBSYSTEM=="module", KERNEL=="block", ATTR{parameters/events_dfl_poll_msecs}=="0", ATTR{parameters/events_dfl_poll_msecs}="2000"
13
14 SUBSYSTEM!="block", GOTO="persistent_storage_end"
15
16 # skip rules for inappropriate block devices
17 KERNEL=="fd*|mtd*|nbd*|gnbd*|btibm*|dm-*|md*", GOTO="persistent_storage_end"
18
19 # ignore partitions that span the entire disk
20 TEST=="whole_disk", GOTO="persistent_storage_end"
21
22 # for partitions import parent information
23 ENV{DEVTYPE}=="partition", IMPORT{parent}="ID_*"
24
25 # virtio-blk
26 KERNEL=="vd*[!0-9]", ATTRS{serial}=="?*", ENV{ID_SERIAL}="$attr{serial}", SYMLINK+="disk/by-id/virtio-$env{ID_SERIAL}"
27 KERNEL=="vd*[0-9]", ATTRS{serial}=="?*", ENV{ID_SERIAL}="$attr{serial}", SYMLINK+="disk/by-id/virtio-$env{ID_SERIAL}-part%n"
28
29 # ATA devices with their own "ata" kernel subsystem
30 KERNEL=="sd*[!0-9]|sr*", ENV{ID_SERIAL}!="?*", SUBSYSTEMS=="ata", IMPORT{program}="ata_id --export $devnode"
31 # ATA devices using the "scsi" subsystem
32 KERNEL=="sd*[!0-9]|sr*", ENV{ID_SERIAL}!="?*", SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", IMPORT{program}="ata_id --export $devnode"
33 # ATA/ATAPI devices (SPC-3 or later) using the "scsi" subsystem
34 KERNEL=="sd*[!0-9]|sr*", ENV{ID_SERIAL}!="?*", SUBSYSTEMS=="scsi", ATTRS{type}=="5", ATTRS{scsi_level}=="[6-9]*", IMPORT{program}="ata_id --export $devnode"
35
36 # Run ata_id on non-removable USB Mass Storage (SATA/PATA disks in enclosures)
37 KERNEL=="sd*[!0-9]|sr*", ENV{ID_SERIAL}!="?*", ATTR{removable}=="0", SUBSYSTEMS=="usb", IMPORT{program}="ata_id --export $devnode"
38 # Otherwise fall back to using usb_id for USB devices
39 KERNEL=="sd*[!0-9]|sr*", ENV{ID_SERIAL}!="?*", SUBSYSTEMS=="usb", IMPORT{builtin}="usb_id"
40
41 # scsi devices
42 KERNEL=="sd*[!0-9]|sr*", ENV{ID_SERIAL}!="?*", IMPORT{program}="scsi_id --export --whitelisted -d $devnode", ENV{ID_BUS}="scsi"
43 KERNEL=="cciss*", ENV{DEVTYPE}=="disk", ENV{ID_SERIAL}!="?*", IMPORT{program}="scsi_id --export --whitelisted -d $devnode", ENV{ID_BUS}="cciss"
44 KERNEL=="sd*|sr*|cciss*", ENV{DEVTYPE}=="disk", ENV{ID_SERIAL}=="?*", SYMLINK+="disk/by-id/$env{ID_BUS}-$env{ID_SERIAL}"
45 KERNEL=="sd*|cciss*", ENV{DEVTYPE}=="partition", ENV{ID_SERIAL}=="?*", SYMLINK+="disk/by-id/$env{ID_BUS}-$env{ID_SERIAL}-part%n"
46
47 # firewire
48 KERNEL=="sd*[!0-9]|sr*", ATTRS{ieee1394_id}=="?*", SYMLINK+="disk/by-id/ieee1394-$attr{ieee1394_id}"
49 KERNEL=="sd*[0-9]", ATTRS{ieee1394_id}=="?*", SYMLINK+="disk/by-id/ieee1394-$attr{ieee1394_id}-part%n"
50
51 KERNEL=="mmcblk[0-9]", SUBSYSTEMS=="mmc", ATTRS{name}=="?*", ATTRS{serial}=="?*", ENV{ID_NAME}="$attr{name}", ENV{ID_SERIAL}="$attr{serial}", SYMLINK+="disk/by-id/mmc-$env{ID_NAME}_$env{ID_SERIAL}"
52 KERNEL=="mmcblk[0-9]p[0-9]", ENV{ID_NAME}=="?*", ENV{ID_SERIAL}=="?*", SYMLINK+="disk/by-id/mmc-$env{ID_NAME}_$env{ID_SERIAL}-part%n"
53 KERNEL=="mspblk[0-9]", SUBSYSTEMS=="memstick", ATTRS{name}=="?*", ATTRS{serial}=="?*", ENV{ID_NAME}="$attr{name}", ENV{ID_SERIAL}="$attr{serial}", SYMLINK+="disk/by-id/memstick-$env{ID_NAME}_$env{ID_SERIAL}"
54 KERNEL=="mspblk[0-9]p[0-9]", ENV{ID_NAME}=="?*", ENV{ID_SERIAL}=="?*", SYMLINK+="disk/by-id/memstick-$env{ID_NAME}_$env{ID_SERIAL}-part%n"
55
56 # by-path (parent device path)
57 ENV{DEVTYPE}=="disk", DEVPATH!="*/virtual/*", IMPORT{builtin}="path_id"
58 ENV{DEVTYPE}=="disk", ENV{ID_PATH}=="?*", SYMLINK+="disk/by-path/$env{ID_PATH}"
59 ENV{DEVTYPE}=="partition", ENV{ID_PATH}=="?*", SYMLINK+="disk/by-path/$env{ID_PATH}-part%n"
60
61 # skip unpartitioned removable media devices from drivers which do not send "change" events
62 ENV{DEVTYPE}=="disk", KERNEL!="sd*|sr*", ATTR{removable}=="1", GOTO="persistent_storage_end"
63
64 # probe filesystem metadata of optical drives which have a media inserted
65 KERNEL=="sr*", ENV{DISK_EJECT_REQUEST}!="?*", ENV{ID_CDROM_MEDIA_TRACK_COUNT_DATA}=="?*", ENV{ID_CDROM_MEDIA_SESSION_LAST_OFFSET}=="?*", \
66 IMPORT{builtin}="blkid --offset=$env{ID_CDROM_MEDIA_SESSION_LAST_OFFSET}"
67 # single-session CDs do not have ID_CDROM_MEDIA_SESSION_LAST_OFFSET
68 KERNEL=="sr*", ENV{DISK_EJECT_REQUEST}!="?*", ENV{ID_CDROM_MEDIA_TRACK_COUNT_DATA}=="?*", ENV{ID_CDROM_MEDIA_SESSION_LAST_OFFSET}=="", \
69 IMPORT{builtin}="blkid --noraid"
70
71 # probe filesystem metadata of disks
72 KERNEL!="sr*", IMPORT{builtin}="blkid"
73
74 # watch metadata changes by tools closing the device after writing
75 KERNEL!="sr*", OPTIONS+="watch"
76
77 # by-label/by-uuid links (filesystem metadata)
78 ENV{ID_FS_USAGE}=="filesystem|other|crypto", ENV{ID_FS_UUID_ENC}=="?*", SYMLINK+="disk/by-uuid/$env{ID_FS_UUID_ENC}"
79 ENV{ID_FS_USAGE}=="filesystem|other", ENV{ID_FS_LABEL_ENC}=="?*", SYMLINK+="disk/by-label/$env{ID_FS_LABEL_ENC}"
80
81 # by-id (World Wide Name)
82 ENV{DEVTYPE}=="disk", ENV{ID_WWN_WITH_EXTENSION}=="?*", SYMLINK+="disk/by-id/wwn-$env{ID_WWN_WITH_EXTENSION}"
83 ENV{DEVTYPE}=="partition", ENV{ID_WWN_WITH_EXTENSION}=="?*", SYMLINK+="disk/by-id/wwn-$env{ID_WWN_WITH_EXTENSION}-part%n"
84
85 # by-partlabel/by-partuuid links (partition metadata)
86 ENV{ID_PART_ENTRY_SCHEME}=="gpt", ENV{ID_PART_ENTRY_UUID}=="?*", SYMLINK+="disk/by-partuuid/$env{ID_PART_ENTRY_UUID}"
87 ENV{ID_PART_ENTRY_SCHEME}=="gpt", ENV{ID_PART_ENTRY_NAME}=="?*", SYMLINK+="disk/by-partlabel/$env{ID_PART_ENTRY_NAME}"
88
89 LABEL="persistent_storage_end"
File rules/75-net-description.rules added (mode: 100644) (index 0000000..ce57d48)
1 # do not edit this file, it will be overwritten on update
2
3 ACTION=="remove", GOTO="net_end"
4 SUBSYSTEM!="net", GOTO="net_end"
5
6 SUBSYSTEMS=="usb", ENV{ID_MODEL}=="", IMPORT{builtin}="usb_id"
7 SUBSYSTEMS=="usb", IMPORT{builtin}="usb-db"
8 SUBSYSTEMS=="usb", ATTRS{idVendor}!="", ATTRS{idProduct}!="", ENV{ID_VENDOR_ID}="$attr{idVendor}", ENV{ID_MODEL_ID}="$attr{idProduct}"
9 SUBSYSTEMS=="usb", GOTO="net_end"
10
11 SUBSYSTEMS=="pci", IMPORT{builtin}="pci-db"
12 SUBSYSTEMS=="pci", ENV{ID_BUS}="pci", ENV{ID_VENDOR_ID}="$attr{vendor}", ENV{ID_MODEL_ID}="$attr{device}"
13
14 LABEL="net_end"
File rules/75-tty-description.rules added (mode: 100644) (index 0000000..2e63e14)
1 # do not edit this file, it will be overwritten on update
2
3 ACTION=="remove", GOTO="tty_end"
4 SUBSYSTEM!="tty", GOTO="tty_end"
5
6 SUBSYSTEMS=="usb", ENV{ID_MODEL}=="", IMPORT{builtin}="usb_id"
7 SUBSYSTEMS=="usb", IMPORT{builtin}="usb-db"
8 SUBSYSTEMS=="usb", ATTRS{idVendor}!="", ATTRS{idProduct}!="", ENV{ID_VENDOR_ID}="$attr{idVendor}", ENV{ID_MODEL_ID}="$attr{idProduct}"
9 SUBSYSTEMS=="usb", GOTO="tty_end"
10
11 SUBSYSTEMS=="pci", IMPORT{builtin}="pci-db"
12 SUBSYSTEMS=="pci", ENV{ID_BUS}="pci", ENV{ID_VENDOR_ID}="$attr{vendor}", ENV{ID_MODEL_ID}="$attr{device}"
13
14 LABEL="tty_end"
File rules/78-sound-card.rules added (mode: 100644) (index 0000000..e564441)
1 # do not edit this file, it will be overwritten on update
2
3 SUBSYSTEM!="sound", GOTO="sound_end"
4
5 ACTION=="add|change", KERNEL=="controlC*", ATTR{../uevent}="change"
6 ACTION!="change", GOTO="sound_end"
7
8 # Ok, we probably need a little explanation here for what the two lines above
9 # are good for.
10 #
11 # The story goes like this: when ALSA registers a new sound card it emits a
12 # series of 'add' events to userspace, for the main card device and for all the
13 # child device nodes that belong to it. udev relays those to applications,
14 # however only maintains the order between father and child, but not between
15 # the siblings. The control device node creation can be used as synchronization
16 # point. All other devices that belong to a card are created in the kernel
17 # before it. However unfortunately due to the fact that siblings are forwarded
18 # out of order by udev this fact is lost to applications.
19 #
20 # OTOH before an application can open a device it needs to make sure that all
21 # its device nodes are completely created and set up.
22 #
23 # As a workaround for this issue we have added the udev rule above which will
24 # generate a 'change' event on the main card device from the 'add' event of the
25 # card's control device. Due to the ordering semantics of udev this event will
26 # only be relayed after all child devices have finished processing properly.
27 # When an application needs to listen for appearing devices it can hence look
28 # for 'change' events only, and ignore the actual 'add' events.
29 #
30 # When the application is initialized at the same time as a device is plugged
31 # in it may need to figure out if the 'change' event has already been triggered
32 # or not for a card. To find that out we store the flag environment variable
33 # SOUND_INITIALIZED on the device which simply tells us if the card 'change'
34 # event has already been processed.
35
36 KERNEL!="card*", GOTO="sound_end"
37
38 ENV{SOUND_INITIALIZED}="1"
39
40 SUBSYSTEMS=="usb", IMPORT{builtin}="usb_id"
41 SUBSYSTEMS=="usb", IMPORT{builtin}="usb-db"
42 SUBSYSTEMS=="usb", GOTO="skip_pci"
43
44 SUBSYSTEMS=="firewire", ATTRS{vendor_name}=="?*", ATTRS{model_name}=="?*", \
45 ENV{ID_BUS}="firewire", ENV{ID_VENDOR}="$attr{vendor_name}", ENV{ID_MODEL}="$attr{model_name}"
46 SUBSYSTEMS=="firewire", ATTRS{guid}=="?*", ENV{ID_ID}="firewire-$attr{guid}"
47 SUBSYSTEMS=="firewire", GOTO="skip_pci"
48
49
50 SUBSYSTEMS=="pci", IMPORT{builtin}="pci-db"
51 SUBSYSTEMS=="pci", ENV{ID_BUS}="pci", ENV{ID_VENDOR_ID}="$attr{vendor}", ENV{ID_MODEL_ID}="$attr{device}"
52
53 LABEL="skip_pci"
54
55 ENV{ID_SERIAL}=="?*", ENV{ID_USB_INTERFACE_NUM}=="?*", ENV{ID_ID}="$env{ID_BUS}-$env{ID_SERIAL}-$env{ID_USB_INTERFACE_NUM}-$attr{id}"
56 ENV{ID_SERIAL}=="?*", ENV{ID_USB_INTERFACE_NUM}=="", ENV{ID_ID}="$env{ID_BUS}-$env{ID_SERIAL}-$attr{id}"
57
58 IMPORT{builtin}="path_id"
59
60 # The values used here for $SOUND_FORM_FACTOR and $SOUND_CLASS should be kept
61 # in sync with those defined for PulseAudio's src/pulse/proplist.h
62 # PA_PROP_DEVICE_FORM_FACTOR, PA_PROP_DEVICE_CLASS properties.
63
64 # If the first PCM device of this card has the pcm class 'modem', then the card is a modem
65 ATTR{pcmC%nD0p/pcm_class}=="modem", ENV{SOUND_CLASS}="modem", GOTO="sound_end"
66
67 # Identify cards on the internal PCI bus as internal
68 SUBSYSTEMS=="pci", DEVPATH=="*/0000:00:??.?/sound/*", ENV{SOUND_FORM_FACTOR}="internal", GOTO="sound_end"
69
70 # Devices that also support Image/Video interfaces are most likely webcams
71 SUBSYSTEMS=="usb", ENV{ID_USB_INTERFACES}=="*:0e????:*", ENV{SOUND_FORM_FACTOR}="webcam", GOTO="sound_end"
72
73 # Matching on the model strings is a bit ugly, I admit
74 ENV{ID_MODEL}=="*[Ss]peaker*", ENV{SOUND_FORM_FACTOR}="speaker", GOTO="sound_end"
75 ENV{ID_MODEL_FROM_DATABASE}=="*[Ss]peaker*", ENV{SOUND_FORM_FACTOR}="speaker", GOTO="sound_end"
76
77 ENV{ID_MODEL}=="*[Hh]eadphone*", ENV{SOUND_FORM_FACTOR}="headphone", GOTO="sound_end"
78 ENV{ID_MODEL_FROM_DATABASE}=="*[Hh]eadphone*", ENV{SOUND_FORM_FACTOR}="headphone", GOTO="sound_end"
79
80 ENV{ID_MODEL}=="*[Hh]eadset*", ENV{SOUND_FORM_FACTOR}="headset", GOTO="sound_end"
81 ENV{ID_MODEL_FROM_DATABASE}=="*[Hh]eadset*", ENV{SOUND_FORM_FACTOR}="headset", GOTO="sound_end"
82
83 ENV{ID_MODEL}=="*[Hh]andset*", ENV{SOUND_FORM_FACTOR}="handset", GOTO="sound_end"
84 ENV{ID_MODEL_FROM_DATABASE}=="*[Hh]andset*", ENV{SOUND_FORM_FACTOR}="handset", GOTO="sound_end"
85
86 ENV{ID_MODEL}=="*[Mm]icrophone*", ENV{SOUND_FORM_FACTOR}="microphone", GOTO="sound_end"
87 ENV{ID_MODEL_FROM_DATABASE}=="*[Mm]icrophone*", ENV{SOUND_FORM_FACTOR}="microphone", GOTO="sound_end"
88
89 LABEL="sound_end"
File rules/80-drivers.rules added (mode: 100644) (index 0000000..38ebfeb)
1 # do not edit this file, it will be overwritten on update
2
3 ACTION=="remove", GOTO="drivers_end"
4
5 DRIVER!="?*", ENV{MODALIAS}=="?*", IMPORT{builtin}="kmod load $env{MODALIAS}"
6 SUBSYSTEM=="tifm", ENV{TIFM_CARD_TYPE}=="SD", IMPORT{builtin}="kmod load tifm_sd"
7 SUBSYSTEM=="tifm", ENV{TIFM_CARD_TYPE}=="MS", IMPORT{builtin}="kmod load tifm_ms"
8 SUBSYSTEM=="memstick", IMPORT{builtin}="kmod load ms_block mspro_block"
9 SUBSYSTEM=="i2o", IMPORT{builtin}="kmod load i2o_block"
10 SUBSYSTEM=="module", KERNEL=="parport_pc", IMPORT{builtin}="kmod load ppdev"
11
12 LABEL="drivers_end"
File rules/95-udev-late.rules added (mode: 100644) (index 0000000..eca0faa)
1 # do not edit this file, it will be overwritten on update
2
3 # run a command on remove events
4 ACTION=="remove", ENV{REMOVE_CMD}!="", RUN+="$env{REMOVE_CMD}"
File src/.udev-builtin-path_id.c.swp added (mode: 100644) (index 0000000..024a874)
File src/libudev-device-private.c added (mode: 100644) (index 0000000..13fdb8e)
1 /*
2 * libudev - interface to udev device information
3 *
4 * Copyright (C) 2008-2010 Kay Sievers <kay.sievers@vrfy.org>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 */
11
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include <string.h>
15 #include <stddef.h>
16 #include <stdbool.h>
17 #include <unistd.h>
18 #include <fcntl.h>
19 #include <string.h>
20 #include <sys/stat.h>
21
22 #include "libudev.h"
23 #include "libudev-private.h"
24
25 static void udev_device_tag(struct udev_device *dev, const char *tag, bool add)
26 {
27 const char *id;
28 struct udev *udev = udev_device_get_udev(dev);
29 char filename[UTIL_PATH_SIZE];
30
31 id = udev_device_get_id_filename(dev);
32 if (id == NULL)
33 return;
34 util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/tags/", tag, "/", id, NULL);
35
36 if (add) {
37 int fd;
38
39 util_create_path(udev, filename);
40 fd = open(filename, O_WRONLY|O_CREAT|O_CLOEXEC|O_TRUNC|O_NOFOLLOW, 0444);
41 if (fd >= 0)
42 close(fd);
43 } else {
44 unlink(filename);
45 }
46 }
47
48 int udev_device_tag_index(struct udev_device *dev, struct udev_device *dev_old, bool add)
49 {
50 struct udev_list_entry *list_entry;
51 bool found;
52
53 if (add && dev_old != NULL) {
54 /* delete possible left-over tags */
55 udev_list_entry_foreach(list_entry, udev_device_get_tags_list_entry(dev_old)) {
56 const char *tag_old = udev_list_entry_get_name(list_entry);
57 struct udev_list_entry *list_entry_current;
58
59 found = false;
60 udev_list_entry_foreach(list_entry_current, udev_device_get_tags_list_entry(dev)) {
61 const char *tag = udev_list_entry_get_name(list_entry_current);
62
63 if (strcmp(tag, tag_old) == 0) {
64 found = true;
65 break;
66 }
67 }
68 if (!found)
69 udev_device_tag(dev_old, tag_old, false);
70 }
71 }
72
73 udev_list_entry_foreach(list_entry, udev_device_get_tags_list_entry(dev))
74 udev_device_tag(dev, udev_list_entry_get_name(list_entry), add);
75
76 return 0;
77 }
78
79 static bool device_has_info(struct udev_device *udev_device)
80 {
81 struct udev_list_entry *list_entry;
82
83 if (udev_device_get_devlinks_list_entry(udev_device) != NULL)
84 return true;
85 if (udev_device_get_devlink_priority(udev_device) != 0)
86 return true;
87 udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(udev_device))
88 if (udev_list_entry_get_num(list_entry))
89 return true;
90 if (udev_device_get_tags_list_entry(udev_device) != NULL)
91 return true;
92 if (udev_device_get_watch_handle(udev_device) >= 0)
93 return true;
94 return false;
95 }
96
97 int udev_device_update_db(struct udev_device *udev_device)
98 {
99 bool has_info;
100 const char *id;
101 struct udev *udev = udev_device_get_udev(udev_device);
102 char filename[UTIL_PATH_SIZE];
103 char filename_tmp[UTIL_PATH_SIZE];
104 FILE *f;
105
106 id = udev_device_get_id_filename(udev_device);
107 if (id == NULL)
108 return -1;
109
110 has_info = device_has_info(udev_device);
111 util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/data/", id, NULL);
112
113 /* do not store anything for otherwise empty devices */
114 if (!has_info &&
115 major(udev_device_get_devnum(udev_device)) == 0 &&
116 udev_device_get_ifindex(udev_device) == 0) {
117 unlink(filename);
118 return 0;
119 }
120
121 /* write a database file */
122 util_strscpyl(filename_tmp, sizeof(filename_tmp), filename, ".tmp", NULL);
123 util_create_path(udev, filename_tmp);
124 f = fopen(filename_tmp, "we");
125 if (f == NULL) {
126 err(udev, "unable to create temporary db file '%s': %m\n", filename_tmp);
127 return -1;
128 }
129
130 /*
131 * set 'sticky' bit to indicate that we should not clean the
132 * database when we transition from initramfs to the real root
133 */
134 if (udev_device_get_db_persist(udev_device))
135 fchmod(fileno(f), 01644);
136
137 if (has_info) {
138 struct udev_list_entry *list_entry;
139
140 if (major(udev_device_get_devnum(udev_device)) > 0) {
141 size_t devlen = strlen(udev_get_dev_path(udev))+1;
142
143 udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(udev_device))
144 fprintf(f, "S:%s\n", &udev_list_entry_get_name(list_entry)[devlen]);
145 if (udev_device_get_devlink_priority(udev_device) != 0)
146 fprintf(f, "L:%i\n", udev_device_get_devlink_priority(udev_device));
147 if (udev_device_get_watch_handle(udev_device) >= 0)
148 fprintf(f, "W:%i\n", udev_device_get_watch_handle(udev_device));
149 }
150
151 if (udev_device_get_usec_initialized(udev_device) > 0)
152 fprintf(f, "I:%llu\n", udev_device_get_usec_initialized(udev_device));
153
154 udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(udev_device)) {
155 if (!udev_list_entry_get_num(list_entry))
156 continue;
157 fprintf(f, "E:%s=%s\n",
158 udev_list_entry_get_name(list_entry),
159 udev_list_entry_get_value(list_entry));
160 }
161
162 udev_list_entry_foreach(list_entry, udev_device_get_tags_list_entry(udev_device))
163 fprintf(f, "G:%s\n", udev_list_entry_get_name(list_entry));
164 }
165
166 fclose(f);
167 rename(filename_tmp, filename);
168 info(udev, "created %s file '%s' for '%s'\n", has_info ? "db" : "empty",
169 filename, udev_device_get_devpath(udev_device));
170 return 0;
171 }
172
173 int udev_device_delete_db(struct udev_device *udev_device)
174 {
175 const char *id;
176 struct udev *udev = udev_device_get_udev(udev_device);
177 char filename[UTIL_PATH_SIZE];
178
179 id = udev_device_get_id_filename(udev_device);
180 if (id == NULL)
181 return -1;
182 util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/data/", id, NULL);
183 unlink(filename);
184 return 0;
185 }
File src/libudev-device.c added (mode: 100644) (index 0000000..69b2d7b)
1 /*
2 * libudev - interface to udev device information
3 *
4 * Copyright (C) 2008-2010 Kay Sievers <kay.sievers@vrfy.org>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 */
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <stddef.h>
15 #include <unistd.h>
16 #include <stdbool.h>
17 #include <errno.h>
18 #include <string.h>
19 #include <dirent.h>
20 #include <fcntl.h>
21 #include <ctype.h>
22 #include <net/if.h>
23 #include <sys/stat.h>
24 #include <sys/ioctl.h>
25 #include <sys/socket.h>
26 #include <linux/sockios.h>
27
28 #include "libudev.h"
29 #include "libudev-private.h"
30
31 /**
32 * SECTION:libudev-device
33 * @short_description: kernel sys devices
34 *
35 * Representation of kernel sys devices. Devices are uniquely identified
36 * by their syspath, every device has exactly one path in the kernel sys
37 * filesystem. Devices usually belong to a kernel subsystem, and and have
38 * a unique name inside that subsystem.
39 */
40
41 /**
42 * udev_device:
43 *
44 * Opaque object representing one kernel sys device.
45 */
46 struct udev_device {
47 struct udev *udev;
48 struct udev_device *parent_device;
49 char *syspath;
50 const char *devpath;
51 char *sysname;
52 const char *sysnum;
53 char *devnode;
54 mode_t devnode_mode;
55 char *subsystem;
56 char *devtype;
57 char *driver;
58 char *action;
59 char *devpath_old;
60 char *id_filename;
61 char **envp;
62 char *monitor_buf;
63 size_t monitor_buf_len;
64 struct udev_list devlinks_list;
65 struct udev_list properties_list;
66 struct udev_list sysattr_value_list;
67 struct udev_list sysattr_list;
68 struct udev_list tags_list;
69 unsigned long long int seqnum;
70 unsigned long long int usec_initialized;
71 int devlink_priority;
72 int refcount;
73 dev_t devnum;
74 int ifindex;
75 int watch_handle;
76 int maj, min;
77 bool parent_set;
78 bool subsystem_set;
79 bool devtype_set;
80 bool devlinks_uptodate;
81 bool envp_uptodate;
82 bool tags_uptodate;
83 bool driver_set;
84 bool info_loaded;
85 bool db_loaded;
86 bool uevent_loaded;
87 bool is_initialized;
88 bool sysattr_list_read;
89 bool db_persist;
90 };
91
92 /**
93 * udev_device_get_seqnum:
94 * @udev_device: udev device
95 *
96 * This is only valid if the device was received through a monitor. Devices read from
97 * sys do not have a sequence number.
98 *
99 * Returns: the kernel event sequence number, or 0 if there is no sequence number available.
100 **/
101 UDEV_EXPORT unsigned long long int udev_device_get_seqnum(struct udev_device *udev_device)
102 {
103 if (udev_device == NULL)
104 return 0;
105 return udev_device->seqnum;
106 }
107
108 static int udev_device_set_seqnum(struct udev_device *udev_device, unsigned long long int seqnum)
109 {
110 char num[32];
111
112 udev_device->seqnum = seqnum;
113 snprintf(num, sizeof(num), "%llu", seqnum);
114 udev_device_add_property(udev_device, "SEQNUM", num);
115 return 0;
116 }
117
118 int udev_device_get_ifindex(struct udev_device *udev_device)
119 {
120 if (!udev_device->info_loaded)
121 udev_device_read_uevent_file(udev_device);
122 return udev_device->ifindex;
123 }
124
125 static int udev_device_set_ifindex(struct udev_device *udev_device, int ifindex)
126 {
127 char num[32];
128
129 udev_device->ifindex = ifindex;
130 snprintf(num, sizeof(num), "%u", ifindex);
131 udev_device_add_property(udev_device, "IFINDEX", num);
132 return 0;
133 }
134
135 /**
136 * udev_device_get_devnum:
137 * @udev_device: udev device
138 *
139 * Get the device major/minor number.
140 *
141 * Returns: the dev_t number.
142 **/
143 UDEV_EXPORT dev_t udev_device_get_devnum(struct udev_device *udev_device)
144 {
145 if (udev_device == NULL)
146 return makedev(0, 0);
147 if (!udev_device->info_loaded)
148 udev_device_read_uevent_file(udev_device);
149 return udev_device->devnum;
150 }
151
152 static int udev_device_set_devnum(struct udev_device *udev_device, dev_t devnum)
153 {
154 char num[32];
155
156 udev_device->devnum = devnum;
157
158 snprintf(num, sizeof(num), "%u", major(devnum));
159 udev_device_add_property(udev_device, "MAJOR", num);
160 snprintf(num, sizeof(num), "%u", minor(devnum));
161 udev_device_add_property(udev_device, "MINOR", num);
162 return 0;
163 }
164
165 const char *udev_device_get_devpath_old(struct udev_device *udev_device)
166 {
167 return udev_device->devpath_old;
168 }
169
170 static int udev_device_set_devpath_old(struct udev_device *udev_device, const char *devpath_old)
171 {
172 const char *pos;
173
174 free(udev_device->devpath_old);
175 udev_device->devpath_old = strdup(devpath_old);
176 if (udev_device->devpath_old == NULL)
177 return -ENOMEM;
178 udev_device_add_property(udev_device, "DEVPATH_OLD", udev_device->devpath_old);
179
180 pos = strrchr(udev_device->devpath_old, '/');
181 if (pos == NULL)
182 return -EINVAL;
183 return 0;
184 }
185
186 /**
187 * udev_device_get_driver:
188 * @udev_device: udev device
189 *
190 * Get the kernel driver name.
191 *
192 * Returns: the driver name string, or #NULL if there is no driver attached.
193 **/
194 UDEV_EXPORT const char *udev_device_get_driver(struct udev_device *udev_device)
195 {
196 char driver[UTIL_NAME_SIZE];
197
198 if (udev_device == NULL)
199 return NULL;
200 if (!udev_device->driver_set) {
201 udev_device->driver_set = true;
202 if (util_get_sys_core_link_value(udev_device->udev, "driver", udev_device->syspath, driver, sizeof(driver)) > 0)
203 udev_device->driver = strdup(driver);
204 }
205 return udev_device->driver;
206 }
207
208 static int udev_device_set_driver(struct udev_device *udev_device, const char *driver)
209 {
210 free(udev_device->driver);
211 udev_device->driver = strdup(driver);
212 if (udev_device->driver == NULL)
213 return -ENOMEM;
214 udev_device->driver_set = true;
215 udev_device_add_property(udev_device, "DRIVER", udev_device->driver);
216 return 0;
217 }
218
219 /**
220 * udev_device_get_devtype:
221 * @udev_device: udev device
222 *
223 * Retrieve the devtype string of the udev device.
224 *
225 * Returns: the devtype name of the udev device, or #NULL if it can not be determined
226 **/
227 UDEV_EXPORT const char *udev_device_get_devtype(struct udev_device *udev_device)
228 {
229 if (udev_device == NULL)
230 return NULL;
231 if (!udev_device->devtype_set) {
232 udev_device->devtype_set = true;
233 udev_device_read_uevent_file(udev_device);
234 }
235 return udev_device->devtype;
236 }
237
238 static int udev_device_set_devtype(struct udev_device *udev_device, const char *devtype)
239 {
240 free(udev_device->devtype);
241 udev_device->devtype = strdup(devtype);
242 if (udev_device->devtype == NULL)
243 return -ENOMEM;
244 udev_device->devtype_set = true;
245 udev_device_add_property(udev_device, "DEVTYPE", udev_device->devtype);
246 return 0;
247 }
248
249 static int udev_device_set_subsystem(struct udev_device *udev_device, const char *subsystem)
250 {
251 free(udev_device->subsystem);
252 udev_device->subsystem = strdup(subsystem);
253 if (udev_device->subsystem == NULL)
254 return -ENOMEM;
255 udev_device->subsystem_set = true;
256 udev_device_add_property(udev_device, "SUBSYSTEM", udev_device->subsystem);
257 return 0;
258 }
259
260 /**
261 * udev_device_get_subsystem:
262 * @udev_device: udev device
263 *
264 * Retrieve the subsystem string of the udev device. The string does not
265 * contain any "/".
266 *
267 * Returns: the subsystem name of the udev device, or #NULL if it can not be determined
268 **/
269 UDEV_EXPORT const char *udev_device_get_subsystem(struct udev_device *udev_device)
270 {
271 char subsystem[UTIL_NAME_SIZE];
272
273 if (udev_device == NULL)
274 return NULL;
275 if (!udev_device->subsystem_set) {
276 udev_device->subsystem_set = true;
277 /* read "subsystem" link */
278 if (util_get_sys_core_link_value(udev_device->udev, "subsystem", udev_device->syspath, subsystem, sizeof(subsystem)) > 0) {
279 udev_device_set_subsystem(udev_device, subsystem);
280 return udev_device->subsystem;
281 }
282 /* implicit names */
283 if (strncmp(udev_device->devpath, "/module/", 8) == 0) {
284 udev_device_set_subsystem(udev_device, "module");
285 return udev_device->subsystem;
286 }
287 if (strstr(udev_device->devpath, "/drivers/") != NULL) {
288 udev_device_set_subsystem(udev_device, "drivers");
289 return udev_device->subsystem;
290 }
291 if (strncmp(udev_device->devpath, "/subsystem/", 11) == 0 ||
292 strncmp(udev_device->devpath, "/class/", 7) == 0 ||
293 strncmp(udev_device->devpath, "/bus/", 5) == 0) {
294 udev_device_set_subsystem(udev_device, "subsystem");
295 return udev_device->subsystem;
296 }
297 }
298 return udev_device->subsystem;
299 }
300
301 mode_t udev_device_get_devnode_mode(struct udev_device *udev_device)
302 {
303 if (!udev_device->info_loaded)
304 udev_device_read_uevent_file(udev_device);
305 return udev_device->devnode_mode;
306 }
307
308 static int udev_device_set_devnode_mode(struct udev_device *udev_device, mode_t mode)
309 {
310 char num[32];
311
312 udev_device->devnode_mode = mode;
313 snprintf(num, sizeof(num), "%#o", mode);
314 udev_device_add_property(udev_device, "DEVMODE", num);
315 return 0;
316 }
317
318 struct udev_list_entry *udev_device_add_property(struct udev_device *udev_device, const char *key, const char *value)
319 {
320 udev_device->envp_uptodate = false;
321 if (value == NULL) {
322 struct udev_list_entry *list_entry;
323
324 list_entry = udev_device_get_properties_list_entry(udev_device);
325 list_entry = udev_list_entry_get_by_name(list_entry, key);
326 if (list_entry != NULL)
327 udev_list_entry_delete(list_entry);
328 return NULL;
329 }
330 return udev_list_entry_add(&udev_device->properties_list, key, value);
331 }
332
333 static struct udev_list_entry *udev_device_add_property_from_string(struct udev_device *udev_device, const char *property)
334 {
335 char name[UTIL_LINE_SIZE];
336 char *val;
337
338 util_strscpy(name, sizeof(name), property);
339 val = strchr(name, '=');
340 if (val == NULL)
341 return NULL;
342 val[0] = '\0';
343 val = &val[1];
344 if (val[0] == '\0')
345 val = NULL;
346 return udev_device_add_property(udev_device, name, val);
347 }
348
349 /*
350 * parse property string, and if needed, update internal values accordingly
351 *
352 * udev_device_add_property_from_string_parse_finish() needs to be
353 * called after adding properties, and its return value checked
354 *
355 * udev_device_set_info_loaded() needs to be set, to avoid trying
356 * to use a device without a DEVPATH set
357 */
358 void udev_device_add_property_from_string_parse(struct udev_device *udev_device, const char *property)
359 {
360 if (strncmp(property, "DEVPATH=", 8) == 0) {
361 char path[UTIL_PATH_SIZE];
362
363 util_strscpyl(path, sizeof(path), udev_get_sys_path(udev_device->udev), &property[8], NULL);
364 udev_device_set_syspath(udev_device, path);
365 } else if (strncmp(property, "SUBSYSTEM=", 10) == 0) {
366 udev_device_set_subsystem(udev_device, &property[10]);
367 } else if (strncmp(property, "DEVTYPE=", 8) == 0) {
368 udev_device_set_devtype(udev_device, &property[8]);
369 } else if (strncmp(property, "DEVNAME=", 8) == 0) {
370 udev_device_set_devnode(udev_device, &property[8]);
371 } else if (strncmp(property, "DEVLINKS=", 9) == 0) {
372 char devlinks[UTIL_PATH_SIZE];
373 char *slink;
374 char *next;
375
376 util_strscpy(devlinks, sizeof(devlinks), &property[9]);
377 slink = devlinks;
378 next = strchr(slink, ' ');
379 while (next != NULL) {
380 next[0] = '\0';
381 udev_device_add_devlink(udev_device, slink, 0);
382 slink = &next[1];
383 next = strchr(slink, ' ');
384 }
385 if (slink[0] != '\0')
386 udev_device_add_devlink(udev_device, slink, 0);
387 } else if (strncmp(property, "TAGS=", 5) == 0) {
388 char tags[UTIL_PATH_SIZE];
389 char *next;
390
391 util_strscpy(tags, sizeof(tags), &property[5]);
392 next = strchr(tags, ':');
393 if (next != NULL) {
394 next++;
395 while (next[0] != '\0') {
396 char *tag;
397
398 tag = next;
399 next = strchr(tag, ':');
400 if (next == NULL)
401 break;
402 next[0] = '\0';
403 next++;
404 udev_device_add_tag(udev_device, tag);
405 }
406 }
407 } else if (strncmp(property, "USEC_INITIALIZED=", 19) == 0) {
408 udev_device_set_usec_initialized(udev_device, strtoull(&property[19], NULL, 10));
409 } else if (strncmp(property, "DRIVER=", 7) == 0) {
410 udev_device_set_driver(udev_device, &property[7]);
411 } else if (strncmp(property, "ACTION=", 7) == 0) {
412 udev_device_set_action(udev_device, &property[7]);
413 } else if (strncmp(property, "MAJOR=", 6) == 0) {
414 udev_device->maj = strtoull(&property[6], NULL, 10);
415 } else if (strncmp(property, "MINOR=", 6) == 0) {
416 udev_device->min = strtoull(&property[6], NULL, 10);
417 } else if (strncmp(property, "DEVPATH_OLD=", 12) == 0) {
418 udev_device_set_devpath_old(udev_device, &property[12]);
419 } else if (strncmp(property, "SEQNUM=", 7) == 0) {
420 udev_device_set_seqnum(udev_device, strtoull(&property[7], NULL, 10));
421 } else if (strncmp(property, "IFINDEX=", 8) == 0) {
422 udev_device_set_ifindex(udev_device, strtoull(&property[8], NULL, 10));
423 } else if (strncmp(property, "DEVMODE=", 8) == 0) {
424 udev_device_set_devnode_mode(udev_device, strtoul(&property[8], NULL, 8));
425 } else {
426 udev_device_add_property_from_string(udev_device, property);
427 }
428 }
429
430 int udev_device_add_property_from_string_parse_finish(struct udev_device *udev_device)
431 {
432 if (udev_device->maj > 0)
433 udev_device_set_devnum(udev_device, makedev(udev_device->maj, udev_device->min));
434 udev_device->maj = 0;
435 udev_device->min = 0;
436
437 if (udev_device->devpath == NULL || udev_device->subsystem == NULL)
438 return -EINVAL;
439 return 0;
440 }
441
442 /**
443 * udev_device_get_property_value:
444 * @udev_device: udev device
445 * @key: property name
446 *
447 * Get the value of a given property.
448 *
449 * Returns: the property string, or #NULL if there is no such property.
450 **/
451 UDEV_EXPORT const char *udev_device_get_property_value(struct udev_device *udev_device, const char *key)
452 {
453 struct udev_list_entry *list_entry;
454
455 if (udev_device == NULL)
456 return NULL;
457 if (key == NULL)
458 return NULL;
459
460 list_entry = udev_device_get_properties_list_entry(udev_device);
461 list_entry = udev_list_entry_get_by_name(list_entry, key);
462 return udev_list_entry_get_value(list_entry);
463 }
464
465 int udev_device_read_db(struct udev_device *udev_device, const char *dbfile)
466 {
467 char filename[UTIL_PATH_SIZE];
468 char line[UTIL_LINE_SIZE];
469 FILE *f;
470
471 /* providing a database file will always force-load it */
472 if (dbfile == NULL) {
473 const char *id;
474
475 if (udev_device->db_loaded)
476 return 0;
477 udev_device->db_loaded = true;
478
479 id = udev_device_get_id_filename(udev_device);
480 if (id == NULL)
481 return -1;
482 util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev_device->udev), "/data/", id, NULL);
483 dbfile = filename;
484 }
485
486 f = fopen(dbfile, "re");
487 if (f == NULL) {
488 info(udev_device->udev, "no db file to read %s: %m\n", dbfile);
489 return -1;
490 }
491 udev_device->is_initialized = true;
492
493 while (fgets(line, sizeof(line), f)) {
494 ssize_t len;
495 const char *val;
496 struct udev_list_entry *entry;
497
498 len = strlen(line);
499 if (len < 4)
500 break;
501 line[len-1] = '\0';
502 val = &line[2];
503 switch(line[0]) {
504 case 'S':
505 util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev_device->udev), "/", val, NULL);
506 udev_device_add_devlink(udev_device, filename, 0);
507 break;
508 case 'L':
509 udev_device_set_devlink_priority(udev_device, atoi(val));
510 break;
511 case 'E':
512 entry = udev_device_add_property_from_string(udev_device, val);
513 udev_list_entry_set_num(entry, true);
514 break;
515 case 'G':
516 udev_device_add_tag(udev_device, val);
517 break;
518 case 'W':
519 udev_device_set_watch_handle(udev_device, atoi(val));
520 break;
521 case 'I':
522 udev_device_set_usec_initialized(udev_device, strtoull(val, NULL, 10));
523 break;
524 }
525 }
526 fclose(f);
527
528 info(udev_device->udev, "device %p filled with db file data\n", udev_device);
529 return 0;
530 }
531
532 int udev_device_read_uevent_file(struct udev_device *udev_device)
533 {
534 char filename[UTIL_PATH_SIZE];
535 FILE *f;
536 char line[UTIL_LINE_SIZE];
537 int maj = 0;
538 int min = 0;
539
540 if (udev_device->uevent_loaded)
541 return 0;
542
543 util_strscpyl(filename, sizeof(filename), udev_device->syspath, "/uevent", NULL);
544 f = fopen(filename, "re");
545 if (f == NULL)
546 return -1;
547 udev_device->uevent_loaded = true;
548
549 while (fgets(line, sizeof(line), f)) {
550 char *pos;
551
552 pos = strchr(line, '\n');
553 if (pos == NULL)
554 continue;
555 pos[0] = '\0';
556
557 if (strncmp(line, "DEVTYPE=", 8) == 0) {
558 udev_device_set_devtype(udev_device, &line[8]);
559 continue;
560 }
561 if (strncmp(line, "IFINDEX=", 8) == 0) {
562 udev_device_set_ifindex(udev_device, strtoull(&line[8], NULL, 10));
563 continue;
564 }
565 if (strncmp(line, "DEVNAME=", 8) == 0) {
566 udev_device_set_devnode(udev_device, &line[8]);
567 continue;
568 }
569
570 if (strncmp(line, "MAJOR=", 6) == 0)
571 maj = strtoull(&line[6], NULL, 10);
572 else if (strncmp(line, "MINOR=", 6) == 0)
573 min = strtoull(&line[6], NULL, 10);
574 else if (strncmp(line, "DEVMODE=", 8) == 0)
575 udev_device->devnode_mode = strtoul(&line[8], NULL, 8);
576
577 udev_device_add_property_from_string(udev_device, line);
578 }
579
580 udev_device->devnum = makedev(maj, min);
581 fclose(f);
582 return 0;
583 }
584
585 void udev_device_set_info_loaded(struct udev_device *device)
586 {
587 device->info_loaded = true;
588 }
589
590 struct udev_device *udev_device_new(struct udev *udev)
591 {
592 struct udev_device *udev_device;
593 struct udev_list_entry *list_entry;
594
595 if (udev == NULL)
596 return NULL;
597
598 udev_device = calloc(1, sizeof(struct udev_device));
599 if (udev_device == NULL)
600 return NULL;
601 udev_device->refcount = 1;
602 udev_device->udev = udev;
603 udev_list_init(udev, &udev_device->devlinks_list, true);
604 udev_list_init(udev, &udev_device->properties_list, true);
605 udev_list_init(udev, &udev_device->sysattr_value_list, true);
606 udev_list_init(udev, &udev_device->sysattr_list, false);
607 udev_list_init(udev, &udev_device->tags_list, true);
608 udev_device->watch_handle = -1;
609 /* copy global properties */
610 udev_list_entry_foreach(list_entry, udev_get_properties_list_entry(udev))
611 udev_device_add_property(udev_device,
612 udev_list_entry_get_name(list_entry),
613 udev_list_entry_get_value(list_entry));
614 dbg(udev_device->udev, "udev_device: %p created\n", udev_device);
615 return udev_device;
616 }
617
618 /**
619 * udev_device_new_from_syspath:
620 * @udev: udev library context
621 * @syspath: sys device path including sys directory
622 *
623 * Create new udev device, and fill in information from the sys
624 * device and the udev database entry. The syspath is the absolute
625 * path to the device, including the sys mount point.
626 *
627 * The initial refcount is 1, and needs to be decremented to
628 * release the resources of the udev device.
629 *
630 * Returns: a new udev device, or #NULL, if it does not exist
631 **/
632 UDEV_EXPORT struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *syspath)
633 {
634 size_t len;
635 const char *subdir;
636 char path[UTIL_PATH_SIZE];
637 char *pos;
638 struct stat statbuf;
639 struct udev_device *udev_device;
640
641 if (udev == NULL)
642 return NULL;
643 if (syspath == NULL)
644 return NULL;
645
646 /* path starts in sys */
647 len = strlen(udev_get_sys_path(udev));
648 if (strncmp(syspath, udev_get_sys_path(udev), len) != 0) {
649 info(udev, "not in sys :%s\n", syspath);
650 return NULL;
651 }
652
653 /* path is not a root directory */
654 subdir = &syspath[len+1];
655 pos = strrchr(subdir, '/');
656 if (pos == NULL || pos[1] == '\0' || pos < &subdir[2]) {
657 dbg(udev, "not a subdir :%s\n", syspath);
658 return NULL;
659 }
660
661 /* resolve possible symlink to real path */
662 util_strscpy(path, sizeof(path), syspath);
663 util_resolve_sys_link(udev, path, sizeof(path));
664
665 if (strncmp(&path[len], "/devices/", 9) == 0) {
666 char file[UTIL_PATH_SIZE];
667
668 /* all "devices" require a "uevent" file */
669 util_strscpyl(file, sizeof(file), path, "/uevent", NULL);
670 if (stat(file, &statbuf) != 0) {
671 dbg(udev, "not a device: %s\n", syspath);
672 return NULL;
673 }
674 } else {
675 /* everything else just needs to be a directory */
676 if (stat(path, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode)) {
677 dbg(udev, "directory not found: %s\n", syspath);
678 return NULL;
679 }
680 }
681
682 udev_device = udev_device_new(udev);
683 if (udev_device == NULL)
684 return NULL;
685
686 udev_device_set_syspath(udev_device, path);
687 info(udev, "device %p has devpath '%s'\n", udev_device, udev_device_get_devpath(udev_device));
688
689 return udev_device;
690 }
691
692 /**
693 * udev_device_new_from_devnum:
694 * @udev: udev library context
695 * @type: char or block device
696 * @devnum: device major/minor number
697 *
698 * Create new udev device, and fill in information from the sys
699 * device and the udev database entry. The device is looked-up
700 * by its major/minor number and type. Character and block device
701 * numbers are not unique across the two types.
702 *
703 * The initial refcount is 1, and needs to be decremented to
704 * release the resources of the udev device.
705 *
706 * Returns: a new udev device, or #NULL, if it does not exist
707 **/
708 UDEV_EXPORT struct udev_device *udev_device_new_from_devnum(struct udev *udev, char type, dev_t devnum)
709 {
710 char path[UTIL_PATH_SIZE];
711 const char *type_str;
712
713 if (type == 'b')
714 type_str = "block";
715 else if (type == 'c')
716 type_str = "char";
717 else
718 return NULL;
719
720 /* use /sys/dev/{block,char}/<maj>:<min> link */
721 snprintf(path, sizeof(path), "%s/dev/%s/%u:%u",
722 udev_get_sys_path(udev), type_str, major(devnum), minor(devnum));
723 return udev_device_new_from_syspath(udev, path);
724 }
725
726 /**
727 * udev_device_new_from_device_id:
728 * @udev: udev library context
729 * @id: text string identifying a kernel device
730 *
731 * Create new udev device, and fill in information from the sys
732 * device and the udev database entry. The device is looked-up
733 * by a special string:
734 * b8:2 - block device major:minor
735 * c128:1 - char device major:minor
736 * n3 - network device ifindex
737 * +sound:card29 - kernel driver core subsystem:device name
738 *
739 * The initial refcount is 1, and needs to be decremented to
740 * release the resources of the udev device.
741 *
742 * Returns: a new udev device, or #NULL, if it does not exist
743 **/
744 UDEV_EXPORT struct udev_device *udev_device_new_from_device_id(struct udev *udev, char *id)
745 {
746 char type;
747 int maj, min;
748 char subsys[UTIL_PATH_SIZE];
749 char *sysname;
750
751 switch(id[0]) {
752 case 'b':
753 case 'c':
754 if (sscanf(id, "%c%i:%i", &type, &maj, &min) != 3)
755 return NULL;
756 return udev_device_new_from_devnum(udev, type, makedev(maj, min));
757 case 'n': {
758 int sk;
759 struct ifreq ifr;
760 struct udev_device *dev;
761 int ifindex;
762
763 ifindex = strtoul(&id[1], NULL, 10);
764 if (ifindex <= 0)
765 return NULL;
766
767 sk = socket(PF_INET, SOCK_DGRAM, 0);
768 if (sk < 0)
769 return NULL;
770 memset(&ifr, 0x00, sizeof(struct ifreq));
771 ifr.ifr_ifindex = ifindex;
772 if (ioctl(sk, SIOCGIFNAME, &ifr) != 0) {
773 close(sk);
774 return NULL;
775 }
776 close(sk);
777
778 dev = udev_device_new_from_subsystem_sysname(udev, "net", ifr.ifr_name);
779 if (dev == NULL)
780 return NULL;
781 if (udev_device_get_ifindex(dev) == ifindex)
782 return dev;
783 udev_device_unref(dev);
784 return NULL;
785 }
786 case '+':
787 util_strscpy(subsys, sizeof(subsys), &id[1]);
788 sysname = strchr(subsys, ':');
789 if (sysname == NULL)
790 return NULL;
791 sysname[0] = '\0';
792 sysname = &sysname[1];
793 return udev_device_new_from_subsystem_sysname(udev, subsys, sysname);
794 default:
795 return NULL;
796 }
797 }
798
799 /**
800 * udev_device_new_from_subsystem_sysname:
801 * @udev: udev library context
802 * @subsystem: the subsystem of the device
803 * @sysname: the name of the device
804 *
805 * Create new udev device, and fill in information from the sys device
806 * and the udev database entry. The device is looked up by the subsystem
807 * and name string of the device, like "mem" / "zero", or "block" / "sda".
808 *
809 * The initial refcount is 1, and needs to be decremented to
810 * release the resources of the udev device.
811 *
812 * Returns: a new udev device, or #NULL, if it does not exist
813 **/
814 UDEV_EXPORT struct udev_device *udev_device_new_from_subsystem_sysname(struct udev *udev, const char *subsystem, const char *sysname)
815 {
816 char path_full[UTIL_PATH_SIZE];
817 char *path;
818 size_t l;
819 struct stat statbuf;
820
821 path = path_full;
822 l = util_strpcpyl(&path, sizeof(path_full), udev_get_sys_path(udev), NULL);
823
824 if (strcmp(subsystem, "subsystem") == 0) {
825 util_strscpyl(path, l, "/subsystem/", sysname, NULL);
826 if (stat(path_full, &statbuf) == 0)
827 goto found;
828
829 util_strscpyl(path, l, "/bus/", sysname, NULL);
830 if (stat(path_full, &statbuf) == 0)
831 goto found;
832
833 util_strscpyl(path, l, "/class/", sysname, NULL);
834 if (stat(path_full, &statbuf) == 0)
835 goto found;
836 goto out;
837 }
838
839 if (strcmp(subsystem, "module") == 0) {
840 util_strscpyl(path, l, "/module/", sysname, NULL);
841 if (stat(path_full, &statbuf) == 0)
842 goto found;
843 goto out;
844 }
845
846 if (strcmp(subsystem, "drivers") == 0) {
847 char subsys[UTIL_NAME_SIZE];
848 char *driver;
849
850 util_strscpy(subsys, sizeof(subsys), sysname);
851 driver = strchr(subsys, ':');
852 if (driver != NULL) {
853 driver[0] = '\0';
854 driver = &driver[1];
855
856 util_strscpyl(path, l, "/subsystem/", subsys, "/drivers/", driver, NULL);
857 if (stat(path_full, &statbuf) == 0)
858 goto found;
859
860 util_strscpyl(path, l, "/bus/", subsys, "/drivers/", driver, NULL);
861 if (stat(path_full, &statbuf) == 0)
862 goto found;
863 }
864 goto out;
865 }
866
867 util_strscpyl(path, l, "/subsystem/", subsystem, "/devices/", sysname, NULL);
868 if (stat(path_full, &statbuf) == 0)
869 goto found;
870
871 util_strscpyl(path, l, "/bus/", subsystem, "/devices/", sysname, NULL);
872 if (stat(path_full, &statbuf) == 0)
873 goto found;
874
875 util_strscpyl(path, l, "/class/", subsystem, "/", sysname, NULL);
876 if (stat(path_full, &statbuf) == 0)
877 goto found;
878 out:
879 return NULL;
880 found:
881 return udev_device_new_from_syspath(udev, path_full);
882 }
883
884 /**
885 * udev_device_new_from_environment
886 * @udev: udev library context
887 *
888 * Create new udev device, and fill in information from the
889 * current process environment. This only works reliable if
890 * the process is called from a udev rule. It is usually used
891 * for tools executed from IMPORT= rules.
892 *
893 * The initial refcount is 1, and needs to be decremented to
894 * release the resources of the udev device.
895 *
896 * Returns: a new udev device, or #NULL, if it does not exist
897 **/
898 UDEV_EXPORT struct udev_device *udev_device_new_from_environment(struct udev *udev)
899 {
900 int i;
901 struct udev_device *udev_device;
902
903 udev_device = udev_device_new(udev);
904 if (udev_device == NULL)
905 return NULL;
906 udev_device_set_info_loaded(udev_device);
907
908 for (i = 0; environ[i] != NULL; i++)
909 udev_device_add_property_from_string_parse(udev_device, environ[i]);
910
911 if (udev_device_add_property_from_string_parse_finish(udev_device) < 0) {
912 info(udev, "missing values, invalid device\n");
913 udev_device_unref(udev_device);
914 udev_device = NULL;
915 }
916
917 return udev_device;
918 }
919
920 static struct udev_device *device_new_from_parent(struct udev_device *udev_device)
921 {
922 struct udev_device *udev_device_parent = NULL;
923 char path[UTIL_PATH_SIZE];
924 const char *subdir;
925
926 util_strscpy(path, sizeof(path), udev_device->syspath);
927 subdir = &path[strlen(udev_get_sys_path(udev_device->udev))+1];
928 for (;;) {
929 char *pos;
930
931 pos = strrchr(subdir, '/');
932 if (pos == NULL || pos < &subdir[2])
933 break;
934 pos[0] = '\0';
935 udev_device_parent = udev_device_new_from_syspath(udev_device->udev, path);
936 if (udev_device_parent != NULL)
937 return udev_device_parent;
938 }
939 return NULL;
940 }
941
942 /**
943 * udev_device_get_parent:
944 * @udev_device: the device to start searching from
945 *
946 * Find the next parent device, and fill in information from the sys
947 * device and the udev database entry.
948 *
949 * The returned the device is not referenced. It is attached to the
950 * child device, and will be cleaned up when the child device
951 * is cleaned up.
952 *
953 * It is not necessarily just the upper level directory, empty or not
954 * recognized sys directories are ignored.
955 *
956 * It can be called as many times as needed, without caring about
957 * references.
958 *
959 * Returns: a new udev device, or #NULL, if it no parent exist.
960 **/
961 UDEV_EXPORT struct udev_device *udev_device_get_parent(struct udev_device *udev_device)
962 {
963 if (udev_device == NULL)
964 return NULL;
965 if (!udev_device->parent_set) {
966 udev_device->parent_set = true;
967 udev_device->parent_device = device_new_from_parent(udev_device);
968 }
969 if (udev_device->parent_device != NULL)
970 dbg(udev_device->udev, "returning existing parent %p\n", udev_device->parent_device);
971 return udev_device->parent_device;
972 }
973
974 /**
975 * udev_device_get_parent_with_subsystem_devtype:
976 * @udev_device: udev device to start searching from
977 * @subsystem: the subsystem of the device
978 * @devtype: the type (DEVTYPE) of the device
979 *
980 * Find the next parent device, with a matching subsystem and devtype
981 * value, and fill in information from the sys device and the udev
982 * database entry.
983 *
984 * If devtype is #NULL, only subsystem is checked, and any devtype will
985 * match.
986 *
987 * The returned the device is not referenced. It is attached to the
988 * child device, and will be cleaned up when the child device
989 * is cleaned up.
990 *
991 * It can be called as many times as needed, without caring about
992 * references.
993 *
994 * Returns: a new udev device, or #NULL if no matching parent exists.
995 **/
996 UDEV_EXPORT struct udev_device *udev_device_get_parent_with_subsystem_devtype(struct udev_device *udev_device, const char *subsystem, const char *devtype)
997 {
998 struct udev_device *parent;
999
1000 if (subsystem == NULL)
1001 return NULL;
1002
1003 parent = udev_device_get_parent(udev_device);
1004 while (parent != NULL) {
1005 const char *parent_subsystem;
1006 const char *parent_devtype;
1007
1008 parent_subsystem = udev_device_get_subsystem(parent);
1009 if (parent_subsystem != NULL && strcmp(parent_subsystem, subsystem) == 0) {
1010 if (devtype == NULL)
1011 break;
1012 parent_devtype = udev_device_get_devtype(parent);
1013 if (parent_devtype != NULL && strcmp(parent_devtype, devtype) == 0)
1014 break;
1015 }
1016 parent = udev_device_get_parent(parent);
1017 }
1018 return parent;
1019 }
1020
1021 /**
1022 * udev_device_get_udev:
1023 * @udev_device: udev device
1024 *
1025 * Retrieve the udev library context the device was created with.
1026 *
1027 * Returns: the udev library context
1028 **/
1029 UDEV_EXPORT struct udev *udev_device_get_udev(struct udev_device *udev_device)
1030 {
1031 if (udev_device == NULL)
1032 return NULL;
1033 return udev_device->udev;
1034 }
1035
1036 /**
1037 * udev_device_ref:
1038 * @udev_device: udev device
1039 *
1040 * Take a reference of a udev device.
1041 *
1042 * Returns: the passed udev device
1043 **/
1044 UDEV_EXPORT struct udev_device *udev_device_ref(struct udev_device *udev_device)
1045 {
1046 if (udev_device == NULL)
1047 return NULL;
1048 udev_device->refcount++;
1049 return udev_device;
1050 }
1051
1052 /**
1053 * udev_device_unref:
1054 * @udev_device: udev device
1055 *
1056 * Drop a reference of a udev device. If the refcount reaches zero,
1057 * the resources of the device will be released.
1058 *
1059 **/
1060 UDEV_EXPORT struct udev_device *udev_device_unref(struct udev_device *udev_device)
1061 {
1062 if (udev_device == NULL)
1063 return NULL;
1064 udev_device->refcount--;
1065 if (udev_device->refcount > 0)
1066 return udev_device;
1067 if (udev_device->parent_device != NULL)
1068 udev_device_unref(udev_device->parent_device);
1069 free(udev_device->syspath);
1070 free(udev_device->sysname);
1071 free(udev_device->devnode);
1072 free(udev_device->subsystem);
1073 free(udev_device->devtype);
1074 udev_list_cleanup(&udev_device->devlinks_list);
1075 udev_list_cleanup(&udev_device->properties_list);
1076 udev_list_cleanup(&udev_device->sysattr_value_list);
1077 udev_list_cleanup(&udev_device->sysattr_list);
1078 udev_list_cleanup(&udev_device->tags_list);
1079 free(udev_device->action);
1080 free(udev_device->driver);
1081 free(udev_device->devpath_old);
1082 free(udev_device->id_filename);
1083 free(udev_device->envp);
1084 free(udev_device->monitor_buf);
1085 dbg(udev_device->udev, "udev_device: %p released\n", udev_device);
1086 free(udev_device);
1087 return NULL;
1088 }
1089
1090 /**
1091 * udev_device_get_devpath:
1092 * @udev_device: udev device
1093 *
1094 * Retrieve the kernel devpath value of the udev device. The path
1095 * does not contain the sys mount point, and starts with a '/'.
1096 *
1097 * Returns: the devpath of the udev device
1098 **/
1099 UDEV_EXPORT const char *udev_device_get_devpath(struct udev_device *udev_device)
1100 {
1101 if (udev_device == NULL)
1102 return NULL;
1103 return udev_device->devpath;
1104 }
1105
1106 /**
1107 * udev_device_get_syspath:
1108 * @udev_device: udev device
1109 *
1110 * Retrieve the sys path of the udev device. The path is an
1111 * absolute path and starts with the sys mount point.
1112 *
1113 * Returns: the sys path of the udev device
1114 **/
1115 UDEV_EXPORT const char *udev_device_get_syspath(struct udev_device *udev_device)
1116 {
1117 if (udev_device == NULL)
1118 return NULL;
1119 return udev_device->syspath;
1120 }
1121
1122 /**
1123 * udev_device_get_sysname:
1124 * @udev_device: udev device
1125 *
1126 * Get the kernel device name in /sys.
1127 *
1128 * Returns: the name string of the device device
1129 **/
1130 UDEV_EXPORT const char *udev_device_get_sysname(struct udev_device *udev_device)
1131 {
1132 if (udev_device == NULL)
1133 return NULL;
1134 return udev_device->sysname;
1135 }
1136
1137 /**
1138 * udev_device_get_sysnum:
1139 * @udev_device: udev device
1140 *
1141 * Get the instance number of the device.
1142 *
1143 * Returns: the trailing number string of of the device name
1144 **/
1145 UDEV_EXPORT const char *udev_device_get_sysnum(struct udev_device *udev_device)
1146 {
1147 if (udev_device == NULL)
1148 return NULL;
1149 return udev_device->sysnum;
1150 }
1151
1152 /**
1153 * udev_device_get_devnode:
1154 * @udev_device: udev device
1155 *
1156 * Retrieve the device node file name belonging to the udev device.
1157 * The path is an absolute path, and starts with the device directory.
1158 *
1159 * Returns: the device node file name of the udev device, or #NULL if no device node exists
1160 **/
1161 UDEV_EXPORT const char *udev_device_get_devnode(struct udev_device *udev_device)
1162 {
1163 if (udev_device == NULL)
1164 return NULL;
1165 if (udev_device->devnode != NULL)
1166 return udev_device->devnode;
1167 if (!udev_device->info_loaded)
1168 udev_device_read_uevent_file(udev_device);
1169 return udev_device->devnode;
1170 }
1171
1172 /**
1173 * udev_device_get_devlinks_list_entry:
1174 * @udev_device: udev device
1175 *
1176 * Retrieve the list of device links pointing to the device file of
1177 * the udev device. The next list entry can be retrieved with
1178 * udev_list_entry_next(), which returns #NULL if no more entries exist.
1179 * The devlink path can be retrieved from the list entry by
1180 * udev_list_entry_get_name(). The path is an absolute path, and starts with
1181 * the device directory.
1182 *
1183 * Returns: the first entry of the device node link list
1184 **/
1185 UDEV_EXPORT struct udev_list_entry *udev_device_get_devlinks_list_entry(struct udev_device *udev_device)
1186 {
1187 if (udev_device == NULL)
1188 return NULL;
1189 if (!udev_device->info_loaded)
1190 udev_device_read_db(udev_device, NULL);
1191 return udev_list_get_entry(&udev_device->devlinks_list);
1192 }
1193
1194 void udev_device_cleanup_devlinks_list(struct udev_device *udev_device)
1195 {
1196 udev_device->devlinks_uptodate = false;
1197 udev_list_cleanup(&udev_device->devlinks_list);
1198 }
1199
1200 /**
1201 * udev_device_get_properties_list_entry:
1202 * @udev_device: udev device
1203 *
1204 * Retrieve the list of key/value device properties of the udev
1205 * device. The next list entry can be retrieved with udev_list_entry_next(),
1206 * which returns #NULL if no more entries exist. The property name
1207 * can be retrieved from the list entry by udev_list_get_name(),
1208 * the property value by udev_list_get_value().
1209 *
1210 * Returns: the first entry of the property list
1211 **/
1212 UDEV_EXPORT struct udev_list_entry *udev_device_get_properties_list_entry(struct udev_device *udev_device)
1213 {
1214 if (udev_device == NULL)
1215 return NULL;
1216 if (!udev_device->info_loaded) {
1217 udev_device_read_uevent_file(udev_device);
1218 udev_device_read_db(udev_device, NULL);
1219 }
1220 if (!udev_device->devlinks_uptodate) {
1221 char symlinks[UTIL_PATH_SIZE];
1222 struct udev_list_entry *list_entry;
1223
1224 udev_device->devlinks_uptodate = true;
1225 list_entry = udev_device_get_devlinks_list_entry(udev_device);
1226 if (list_entry != NULL) {
1227 char *s;
1228 size_t l;
1229
1230 s = symlinks;
1231 l = util_strpcpyl(&s, sizeof(symlinks), udev_list_entry_get_name(list_entry), NULL);
1232 udev_list_entry_foreach(list_entry, udev_list_entry_get_next(list_entry))
1233 l = util_strpcpyl(&s, l, " ", udev_list_entry_get_name(list_entry), NULL);
1234 udev_device_add_property(udev_device, "DEVLINKS", symlinks);
1235 }
1236 }
1237 if (!udev_device->tags_uptodate) {
1238 udev_device->tags_uptodate = true;
1239 if (udev_device_get_tags_list_entry(udev_device) != NULL) {
1240 char tags[UTIL_PATH_SIZE];
1241 struct udev_list_entry *list_entry;
1242 char *s;
1243 size_t l;
1244
1245 s = tags;
1246 l = util_strpcpyl(&s, sizeof(tags), ":", NULL);
1247 udev_list_entry_foreach(list_entry, udev_device_get_tags_list_entry(udev_device))
1248 l = util_strpcpyl(&s, l, udev_list_entry_get_name(list_entry), ":", NULL);
1249 udev_device_add_property(udev_device, "TAGS", tags);
1250 }
1251 }
1252 return udev_list_get_entry(&udev_device->properties_list);
1253 }
1254
1255 /**
1256 * udev_device_get_action:
1257 * @udev_device: udev device
1258 *
1259 * This is only valid if the device was received through a monitor. Devices read from
1260 * sys do not have an action string. Usual actions are: add, remove, change, online,
1261 * offline.
1262 *
1263 * Returns: the kernel action value, or #NULL if there is no action value available.
1264 **/
1265 UDEV_EXPORT const char *udev_device_get_action(struct udev_device *udev_device)
1266 {
1267 if (udev_device == NULL)
1268 return NULL;
1269 return udev_device->action;
1270 }
1271
1272 /**
1273 * udev_device_get_usec_since_initialized:
1274 * @udev_device: udev device
1275 *
1276 * Return the number of microseconds passed since udev set up the
1277 * device for the first time.
1278 *
1279 * This is only implemented for devices with need to store properties
1280 * in the udev database. All other devices return 0 here.
1281 *
1282 * Returns: the number of microseconds since the device was first seen.
1283 **/
1284 UDEV_EXPORT unsigned long long int udev_device_get_usec_since_initialized(struct udev_device *udev_device)
1285 {
1286 unsigned long long now;
1287
1288 if (udev_device == NULL)
1289 return 0;
1290 if (!udev_device->info_loaded)
1291 udev_device_read_db(udev_device, NULL);
1292 if (udev_device->usec_initialized == 0)
1293 return 0;
1294 now = now_usec();
1295 if (now == 0)
1296 return 0;
1297 return now - udev_device->usec_initialized;
1298 }
1299
1300 unsigned long long udev_device_get_usec_initialized(struct udev_device *udev_device)
1301 {
1302 return udev_device->usec_initialized;
1303 }
1304
1305 void udev_device_set_usec_initialized(struct udev_device *udev_device, unsigned long long usec_initialized)
1306 {
1307 char num[32];
1308
1309 udev_device->usec_initialized = usec_initialized;
1310 snprintf(num, sizeof(num), "%llu", usec_initialized);
1311 udev_device_add_property(udev_device, "USEC_INITIALIZED", num);
1312 }
1313
1314 /**
1315 * udev_device_get_sysattr_value:
1316 * @udev_device: udev device
1317 * @sysattr: attribute name
1318 *
1319 * The retrieved value is cached in the device. Repeated calls will return the same
1320 * value and not open the attribute again.
1321 *
1322 * Returns: the content of a sys attribute file, or #NULL if there is no sys attribute value.
1323 **/
1324 UDEV_EXPORT const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const char *sysattr)
1325 {
1326 struct udev_list_entry *list_entry;
1327 char path[UTIL_PATH_SIZE];
1328 char value[4096];
1329 struct stat statbuf;
1330 int fd;
1331 ssize_t size;
1332 const char *val = NULL;
1333
1334 if (udev_device == NULL)
1335 return NULL;
1336 if (sysattr == NULL)
1337 return NULL;
1338
1339 /* look for possibly already cached result */
1340 list_entry = udev_list_get_entry(&udev_device->sysattr_value_list);
1341 list_entry = udev_list_entry_get_by_name(list_entry, sysattr);
1342 if (list_entry != NULL) {
1343 dbg(udev_device->udev, "got '%s' (%s) from cache\n",
1344 sysattr, udev_list_entry_get_value(list_entry));
1345 return udev_list_entry_get_value(list_entry);
1346 }
1347
1348 util_strscpyl(path, sizeof(path), udev_device_get_syspath(udev_device), "/", sysattr, NULL);
1349 if (lstat(path, &statbuf) != 0) {
1350 dbg(udev_device->udev, "no attribute '%s', keep negative entry\n", path);
1351 udev_list_entry_add(&udev_device->sysattr_value_list, sysattr, NULL);
1352 goto out;
1353 }
1354
1355 if (S_ISLNK(statbuf.st_mode)) {
1356 struct udev_device *dev;
1357
1358 /*
1359 * Some core links return only the last element of the target path,
1360 * these are just values, the paths should not be exposed.
1361 */
1362 if (strcmp(sysattr, "driver") == 0 ||
1363 strcmp(sysattr, "subsystem") == 0 ||
1364 strcmp(sysattr, "module") == 0) {
1365 if (util_get_sys_core_link_value(udev_device->udev, sysattr,
1366 udev_device->syspath, value, sizeof(value)) < 0)
1367 return NULL;
1368 dbg(udev_device->udev, "cache '%s' with link value '%s'\n", sysattr, value);
1369 list_entry = udev_list_entry_add(&udev_device->sysattr_value_list, sysattr, value);
1370 val = udev_list_entry_get_value(list_entry);
1371 goto out;
1372 }
1373
1374 /* resolve link to a device and return its syspath */
1375 util_strscpyl(path, sizeof(path), udev_device->syspath, "/", sysattr, NULL);
1376 dev = udev_device_new_from_syspath(udev_device->udev, path);
1377 if (dev != NULL) {
1378 list_entry = udev_list_entry_add(&udev_device->sysattr_value_list, sysattr,
1379 udev_device_get_syspath(dev));
1380 val = udev_list_entry_get_value(list_entry);
1381 udev_device_unref(dev);
1382 }
1383
1384 goto out;
1385 }
1386
1387 /* skip directories */
1388 if (S_ISDIR(statbuf.st_mode))
1389 goto out;
1390
1391 /* skip non-readable files */
1392 if ((statbuf.st_mode & S_IRUSR) == 0)
1393 goto out;
1394
1395 /* read attribute value */
1396 fd = open(path, O_RDONLY|O_CLOEXEC);
1397 if (fd < 0) {
1398 dbg(udev_device->udev, "attribute '%s' can not be opened\n", path);
1399 goto out;
1400 }
1401 size = read(fd, value, sizeof(value));
1402 close(fd);
1403 if (size < 0)
1404 goto out;
1405 if (size == sizeof(value))
1406 goto out;
1407
1408 /* got a valid value, store it in cache and return it */
1409 value[size] = '\0';
1410 util_remove_trailing_chars(value, '\n');
1411 dbg(udev_device->udev, "'%s' has attribute value '%s'\n", path, value);
1412 list_entry = udev_list_entry_add(&udev_device->sysattr_value_list, sysattr, value);
1413 val = udev_list_entry_get_value(list_entry);
1414 out:
1415 return val;
1416 }
1417
1418 static int udev_device_sysattr_list_read(struct udev_device *udev_device)
1419 {
1420 struct dirent *dent;
1421 DIR *dir;
1422 int num = 0;
1423
1424 if (udev_device == NULL)
1425 return -1;
1426 if (udev_device->sysattr_list_read)
1427 return 0;
1428
1429 dir = opendir(udev_device_get_syspath(udev_device));
1430 if (!dir) {
1431 dbg(udev_device->udev, "sysfs dir '%s' can not be opened\n",
1432 udev_device_get_syspath(udev_device));
1433 return -1;
1434 }
1435
1436 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
1437 char path[UTIL_PATH_SIZE];
1438 struct stat statbuf;
1439
1440 /* only handle symlinks and regular files */
1441 if (dent->d_type != DT_LNK && dent->d_type != DT_REG)
1442 continue;
1443
1444 util_strscpyl(path, sizeof(path), udev_device_get_syspath(udev_device), "/", dent->d_name, NULL);
1445 if (lstat(path, &statbuf) != 0)
1446 continue;
1447 if ((statbuf.st_mode & S_IRUSR) == 0)
1448 continue;
1449
1450 udev_list_entry_add(&udev_device->sysattr_list, dent->d_name, NULL);
1451 num++;
1452 }
1453
1454 closedir(dir);
1455 dbg(udev_device->udev, "found %d sysattrs for '%s'\n", num, udev_device_get_syspath(udev_device));
1456 udev_device->sysattr_list_read = true;
1457
1458 return num;
1459 }
1460
1461 /**
1462 * udev_device_get_sysattr_list_entry:
1463 * @udev_device: udev device
1464 *
1465 * Retrieve the list of available sysattrs, with value being empty;
1466 * This just return all available sysfs attributes for a particular
1467 * device without reading their values.
1468 *
1469 * Returns: the first entry of the property list
1470 **/
1471 UDEV_EXPORT struct udev_list_entry *udev_device_get_sysattr_list_entry(struct udev_device *udev_device)
1472 {
1473 if (!udev_device->sysattr_list_read) {
1474 int ret;
1475 ret = udev_device_sysattr_list_read(udev_device);
1476 if (0 > ret)
1477 return NULL;
1478 }
1479
1480 return udev_list_get_entry(&udev_device->sysattr_list);
1481 }
1482
1483 int udev_device_set_syspath(struct udev_device *udev_device, const char *syspath)
1484 {
1485 const char *pos;
1486 size_t len;
1487
1488 free(udev_device->syspath);
1489 udev_device->syspath = strdup(syspath);
1490 if (udev_device->syspath == NULL)
1491 return -ENOMEM;
1492 udev_device->devpath = &udev_device->syspath[strlen(udev_get_sys_path(udev_device->udev))];
1493 udev_device_add_property(udev_device, "DEVPATH", udev_device->devpath);
1494
1495 pos = strrchr(udev_device->syspath, '/');
1496 if (pos == NULL)
1497 return -EINVAL;
1498 udev_device->sysname = strdup(&pos[1]);
1499 if (udev_device->sysname == NULL)
1500 return -ENOMEM;
1501
1502 /* some devices have '!' in their name, change that to '/' */
1503 len = 0;
1504 while (udev_device->sysname[len] != '\0') {
1505 if (udev_device->sysname[len] == '!')
1506 udev_device->sysname[len] = '/';
1507 len++;
1508 }
1509
1510 /* trailing number */
1511 while (len > 0 && isdigit(udev_device->sysname[--len]))
1512 udev_device->sysnum = &udev_device->sysname[len];
1513
1514 /* sysname is completely numeric */
1515 if (len == 0)
1516 udev_device->sysnum = NULL;
1517
1518 return 0;
1519 }
1520
1521 int udev_device_set_devnode(struct udev_device *udev_device, const char *devnode)
1522 {
1523 free(udev_device->devnode);
1524 if (devnode[0] != '/') {
1525 if (asprintf(&udev_device->devnode, "%s/%s", udev_get_dev_path(udev_device->udev), devnode) < 0)
1526 udev_device->devnode = NULL;
1527 } else {
1528 udev_device->devnode = strdup(devnode);
1529 }
1530 if (udev_device->devnode == NULL)
1531 return -ENOMEM;
1532 udev_device_add_property(udev_device, "DEVNAME", udev_device->devnode);
1533 return 0;
1534 }
1535
1536 int udev_device_add_devlink(struct udev_device *udev_device, const char *devlink, int unique)
1537 {
1538 struct udev_list_entry *list_entry;
1539
1540 udev_device->devlinks_uptodate = false;
1541 list_entry = udev_list_entry_add(&udev_device->devlinks_list, devlink, NULL);
1542 if (list_entry == NULL)
1543 return -ENOMEM;
1544 if (unique)
1545 udev_list_entry_set_num(list_entry, true);
1546 return 0;
1547 }
1548
1549 const char *udev_device_get_id_filename(struct udev_device *udev_device)
1550 {
1551 if (udev_device->id_filename == NULL) {
1552 if (udev_device_get_subsystem(udev_device) == NULL)
1553 return NULL;
1554
1555 if (major(udev_device_get_devnum(udev_device)) > 0) {
1556 /* use dev_t -- b259:131072, c254:0 */
1557 if (asprintf(&udev_device->id_filename, "%c%u:%u",
1558 strcmp(udev_device_get_subsystem(udev_device), "block") == 0 ? 'b' : 'c',
1559 major(udev_device_get_devnum(udev_device)),
1560 minor(udev_device_get_devnum(udev_device))) < 0)
1561 udev_device->id_filename = NULL;
1562 } else if (udev_device_get_ifindex(udev_device) > 0) {
1563 /* use netdev ifindex -- n3 */
1564 if (asprintf(&udev_device->id_filename, "n%u", udev_device_get_ifindex(udev_device)) < 0)
1565 udev_device->id_filename = NULL;
1566 } else {
1567 /*
1568 * use $subsys:$syname -- pci:0000:00:1f.2
1569 * sysname() has '!' translated, get it from devpath
1570 */
1571 const char *sysname;
1572 sysname = strrchr(udev_device->devpath, '/');
1573 if (sysname == NULL)
1574 return NULL;
1575 sysname = &sysname[1];
1576 if (asprintf(&udev_device->id_filename, "+%s:%s", udev_device_get_subsystem(udev_device), sysname) < 0)
1577 udev_device->id_filename = NULL;
1578 }
1579 }
1580 return udev_device->id_filename;
1581 }
1582
1583 /**
1584 * udev_device_get_is_initialized:
1585 * @udev_device: udev device
1586 *
1587 * Check if udev has already handled the device and has set up
1588 * device node permissions and context, or has renamed a network
1589 * device.
1590 *
1591 * This is only implemented for devices with a device node
1592 * or network interfaces. All other devices return 1 here.
1593 *
1594 * Returns: 1 if the device is set up. 0 otherwise.
1595 **/
1596 UDEV_EXPORT int udev_device_get_is_initialized(struct udev_device *udev_device)
1597 {
1598 if (!udev_device->info_loaded)
1599 udev_device_read_db(udev_device, NULL);
1600 return udev_device->is_initialized;
1601 }
1602
1603 void udev_device_set_is_initialized(struct udev_device *udev_device)
1604 {
1605 udev_device->is_initialized = true;
1606 }
1607
1608 int udev_device_add_tag(struct udev_device *udev_device, const char *tag)
1609 {
1610 if (strchr(tag, ':') != NULL || strchr(tag, ' ') != NULL)
1611 return -EINVAL;
1612 udev_device->tags_uptodate = false;
1613 if (udev_list_entry_add(&udev_device->tags_list, tag, NULL) != NULL)
1614 return 0;
1615 return -ENOMEM;
1616 }
1617
1618 void udev_device_cleanup_tags_list(struct udev_device *udev_device)
1619 {
1620 udev_device->tags_uptodate = false;
1621 udev_list_cleanup(&udev_device->tags_list);
1622 }
1623
1624 /**
1625 * udev_device_get_tags_list_entry:
1626 * @udev_device: udev device
1627 *
1628 * Retrieve the list of tags attached to the udev device. The next
1629 * list entry can be retrieved with udev_list_entry_next(),
1630 * which returns #NULL if no more entries exist. The tag string
1631 * can be retrieved from the list entry by udev_list_get_name().
1632 *
1633 * Returns: the first entry of the tag list
1634 **/
1635 UDEV_EXPORT struct udev_list_entry *udev_device_get_tags_list_entry(struct udev_device *udev_device)
1636 {
1637 if (udev_device == NULL)
1638 return NULL;
1639 if (!udev_device->info_loaded)
1640 udev_device_read_db(udev_device, NULL);
1641 return udev_list_get_entry(&udev_device->tags_list);
1642 }
1643
1644 /**
1645 * udev_device_has_tag:
1646 * @udev_device: udev device
1647 * @tag: tag name
1648 *
1649 * Check if a given device has a certain tag associated.
1650 *
1651 * Returns: 1 if the tag is found. 0 otherwise.
1652 **/
1653 UDEV_EXPORT int udev_device_has_tag(struct udev_device *udev_device, const char *tag)
1654 {
1655 struct udev_list_entry *list_entry;
1656
1657 if (udev_device == NULL)
1658 return false;
1659 if (!udev_device->info_loaded)
1660 udev_device_read_db(udev_device, NULL);
1661 list_entry = udev_device_get_tags_list_entry(udev_device);
1662 if (udev_list_entry_get_by_name(list_entry, tag) != NULL)
1663 return true;
1664 return false;
1665 }
1666
1667 #define ENVP_SIZE 128
1668 #define MONITOR_BUF_SIZE 4096
1669 static int update_envp_monitor_buf(struct udev_device *udev_device)
1670 {
1671 struct udev_list_entry *list_entry;
1672 char *s;
1673 size_t l;
1674 unsigned int i;
1675
1676 /* monitor buffer of property strings */
1677 free(udev_device->monitor_buf);
1678 udev_device->monitor_buf_len = 0;
1679 udev_device->monitor_buf = malloc(MONITOR_BUF_SIZE);
1680 if (udev_device->monitor_buf == NULL)
1681 return -ENOMEM;
1682
1683 /* envp array, strings will point into monitor buffer */
1684 if (udev_device->envp == NULL)
1685 udev_device->envp = malloc(sizeof(char *) * ENVP_SIZE);
1686 if (udev_device->envp == NULL)
1687 return -ENOMEM;
1688
1689 i = 0;
1690 s = udev_device->monitor_buf;
1691 l = MONITOR_BUF_SIZE;
1692 udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(udev_device)) {
1693 const char *key;
1694
1695 key = udev_list_entry_get_name(list_entry);
1696 /* skip private variables */
1697 if (key[0] == '.')
1698 continue;
1699
1700 /* add string to envp array */
1701 udev_device->envp[i++] = s;
1702 if (i+1 >= ENVP_SIZE)
1703 return -EINVAL;
1704
1705 /* add property string to monitor buffer */
1706 l = util_strpcpyl(&s, l, key, "=", udev_list_entry_get_value(list_entry), NULL);
1707 if (l == 0)
1708 return -EINVAL;
1709 /* advance past the trailing '\0' that util_strpcpyl() guarantees */
1710 s++;
1711 l--;
1712 }
1713 udev_device->envp[i] = NULL;
1714 udev_device->monitor_buf_len = s - udev_device->monitor_buf;
1715 udev_device->envp_uptodate = true;
1716 dbg(udev_device->udev, "filled envp/monitor buffer, %u properties, %zu bytes\n",
1717 i, udev_device->monitor_buf_len);
1718 return 0;
1719 }
1720
1721 char **udev_device_get_properties_envp(struct udev_device *udev_device)
1722 {
1723 if (!udev_device->envp_uptodate)
1724 if (update_envp_monitor_buf(udev_device) != 0)
1725 return NULL;
1726 return udev_device->envp;
1727 }
1728
1729 ssize_t udev_device_get_properties_monitor_buf(struct udev_device *udev_device, const char **buf)
1730 {
1731 if (!udev_device->envp_uptodate)
1732 if (update_envp_monitor_buf(udev_device) != 0)
1733 return -EINVAL;
1734 *buf = udev_device->monitor_buf;
1735 return udev_device->monitor_buf_len;
1736 }
1737
1738 int udev_device_set_action(struct udev_device *udev_device, const char *action)
1739 {
1740 free(udev_device->action);
1741 udev_device->action = strdup(action);
1742 if (udev_device->action == NULL)
1743 return -ENOMEM;
1744 udev_device_add_property(udev_device, "ACTION", udev_device->action);
1745 return 0;
1746 }
1747
1748 int udev_device_get_devlink_priority(struct udev_device *udev_device)
1749 {
1750 if (!udev_device->info_loaded)
1751 udev_device_read_db(udev_device, NULL);
1752 return udev_device->devlink_priority;
1753 }
1754
1755 int udev_device_set_devlink_priority(struct udev_device *udev_device, int prio)
1756 {
1757 udev_device->devlink_priority = prio;
1758 return 0;
1759 }
1760
1761 int udev_device_get_watch_handle(struct udev_device *udev_device)
1762 {
1763 if (!udev_device->info_loaded)
1764 udev_device_read_db(udev_device, NULL);
1765 return udev_device->watch_handle;
1766 }
1767
1768 int udev_device_set_watch_handle(struct udev_device *udev_device, int handle)
1769 {
1770 udev_device->watch_handle = handle;
1771 return 0;
1772 }
1773
1774 bool udev_device_get_db_persist(struct udev_device *udev_device)
1775 {
1776 return udev_device->db_persist;
1777 }
1778
1779 void udev_device_set_db_persist(struct udev_device *udev_device)
1780 {
1781 udev_device->db_persist = true;
1782 }
File src/libudev-enumerate.c added (mode: 100644) (index 0000000..9a3bf52)
1 /*
2 * libudev - interface to udev device information
3 *
4 * Copyright (C) 2008-2010 Kay Sievers <kay.sievers@vrfy.org>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 */
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <stddef.h>
15 #include <unistd.h>
16 #include <errno.h>
17 #include <string.h>
18 #include <dirent.h>
19 #include <fnmatch.h>
20 #include <stdbool.h>
21 #include <sys/stat.h>
22 #include <sys/param.h>
23
24 #include "libudev.h"
25 #include "libudev-private.h"
26
27 /**
28 * SECTION:libudev-enumerate
29 * @short_description: lookup and sort sys devices
30 *
31 * Lookup devices in the sys filesystem, filter devices by properties,
32 * and return a sorted list of devices.
33 */
34
35 struct syspath {
36 char *syspath;
37 size_t len;
38 };
39
40 /**
41 * udev_enumerate:
42 *
43 * Opaque object representing one device lookup/sort context.
44 */
45 struct udev_enumerate {
46 struct udev *udev;
47 int refcount;
48 struct udev_list sysattr_match_list;
49 struct udev_list sysattr_nomatch_list;
50 struct udev_list subsystem_match_list;
51 struct udev_list subsystem_nomatch_list;
52 struct udev_list sysname_match_list;
53 struct udev_list properties_match_list;
54 struct udev_list tags_match_list;
55 struct udev_device *parent_match;
56 struct udev_list devices_list;
57 struct syspath *devices;
58 unsigned int devices_cur;
59 unsigned int devices_max;
60 bool devices_uptodate:1;
61 bool match_is_initialized;
62 };
63
64 /**
65 * udev_enumerate_new:
66 * @udev: udev library context
67 *
68 * Create an enumeration context to scan /sys.
69 *
70 * Returns: an enumeration context.
71 **/
72 UDEV_EXPORT struct udev_enumerate *udev_enumerate_new(struct udev *udev)
73 {
74 struct udev_enumerate *udev_enumerate;
75
76 udev_enumerate = calloc(1, sizeof(struct udev_enumerate));
77 if (udev_enumerate == NULL)
78 return NULL;
79 udev_enumerate->refcount = 1;
80 udev_enumerate->udev = udev;
81 udev_list_init(udev, &udev_enumerate->sysattr_match_list, false);
82 udev_list_init(udev, &udev_enumerate->sysattr_nomatch_list, false);
83 udev_list_init(udev, &udev_enumerate->subsystem_match_list, true);
84 udev_list_init(udev, &udev_enumerate->subsystem_nomatch_list, true);
85 udev_list_init(udev, &udev_enumerate->sysname_match_list, true);
86 udev_list_init(udev, &udev_enumerate->properties_match_list, false);
87 udev_list_init(udev, &udev_enumerate->tags_match_list, true);
88 udev_list_init(udev, &udev_enumerate->devices_list, false);
89 return udev_enumerate;
90 }
91
92 /**
93 * udev_enumerate_ref:
94 * @udev_enumerate: context
95 *
96 * Take a reference of a enumeration context.
97 *
98 * Returns: the passed enumeration context
99 **/
100 UDEV_EXPORT struct udev_enumerate *udev_enumerate_ref(struct udev_enumerate *udev_enumerate)
101 {
102 if (udev_enumerate == NULL)
103 return NULL;
104 udev_enumerate->refcount++;
105 return udev_enumerate;
106 }
107
108 /**
109 * udev_enumerate_unref:
110 * @udev_enumerate: context
111 *
112 * Drop a reference of an enumeration context. If the refcount reaches zero,
113 * all resources of the enumeration context will be released.
114 **/
115 UDEV_EXPORT struct udev_enumerate *udev_enumerate_unref(struct udev_enumerate *udev_enumerate)
116 {
117 unsigned int i;
118
119 if (udev_enumerate == NULL)
120 return NULL;
121 udev_enumerate->refcount--;
122 if (udev_enumerate->refcount > 0)
123 return udev_enumerate;
124 udev_list_cleanup(&udev_enumerate->sysattr_match_list);
125 udev_list_cleanup(&udev_enumerate->sysattr_nomatch_list);
126 udev_list_cleanup(&udev_enumerate->subsystem_match_list);
127 udev_list_cleanup(&udev_enumerate->subsystem_nomatch_list);
128 udev_list_cleanup(&udev_enumerate->sysname_match_list);
129 udev_list_cleanup(&udev_enumerate->properties_match_list);
130 udev_list_cleanup(&udev_enumerate->tags_match_list);
131 udev_device_unref(udev_enumerate->parent_match);
132 udev_list_cleanup(&udev_enumerate->devices_list);
133 for (i = 0; i < udev_enumerate->devices_cur; i++)
134 free(udev_enumerate->devices[i].syspath);
135 free(udev_enumerate->devices);
136 free(udev_enumerate);
137 return NULL;
138 }
139
140 /**
141 * udev_enumerate_get_udev:
142 * @udev_enumerate: context
143 *
144 * Get the udev library context.
145 *
146 * Returns: a pointer to the context.
147 */
148 UDEV_EXPORT struct udev *udev_enumerate_get_udev(struct udev_enumerate *udev_enumerate)
149 {
150 if (udev_enumerate == NULL)
151 return NULL;
152 return udev_enumerate->udev;
153 }
154
155 static int syspath_add(struct udev_enumerate *udev_enumerate, const char *syspath)
156 {
157 char *path;
158 struct syspath *entry;
159
160 /* double array size if needed */
161 if (udev_enumerate->devices_cur >= udev_enumerate->devices_max) {
162 struct syspath *buf;
163 unsigned int add;
164
165 add = udev_enumerate->devices_max;
166 if (add < 1024)
167 add = 1024;
168 buf = realloc(udev_enumerate->devices, (udev_enumerate->devices_max + add) * sizeof(struct syspath));
169 if (buf == NULL)
170 return -ENOMEM;
171 udev_enumerate->devices = buf;
172 udev_enumerate->devices_max += add;
173 }
174
175 path = strdup(syspath);
176 if (path == NULL)
177 return -ENOMEM;
178 entry = &udev_enumerate->devices[udev_enumerate->devices_cur];
179 entry->syspath = path;
180 entry->len = strlen(path);
181 udev_enumerate->devices_cur++;
182 udev_enumerate->devices_uptodate = false;
183 return 0;
184 }
185
186 static int syspath_cmp(const void *p1, const void *p2)
187 {
188 const struct syspath *path1 = p1;
189 const struct syspath *path2 = p2;
190 size_t len;
191 int ret;
192
193 len = MIN(path1->len, path2->len);
194 ret = memcmp(path1->syspath, path2->syspath, len);
195 if (ret == 0) {
196 if (path1->len < path2->len)
197 ret = -1;
198 else if (path1->len > path2->len)
199 ret = 1;
200 }
201 return ret;
202 }
203
204 /* For devices that should be moved to the absolute end of the list */
205 static bool devices_delay_end(struct udev *udev, const char *syspath)
206 {
207 static const char *delay_device_list[] = {
208 "/block/md",
209 "/block/dm-",
210 NULL
211 };
212 size_t len;
213 int i;
214
215 len = strlen(udev_get_sys_path(udev));
216 for (i = 0; delay_device_list[i] != NULL; i++) {
217 if (strstr(&syspath[len], delay_device_list[i]) != NULL) {
218 dbg(udev, "delaying: %s\n", syspath);
219 return true;
220 }
221 }
222 return false;
223 }
224
225 /* For devices that should just be moved a little bit later, just
226 * before the point where some common path prefix changes. Returns the
227 * number of characters that make up that common prefix */
228 static size_t devices_delay_later(struct udev *udev, const char *syspath)
229 {
230 const char *c;
231
232 /* For sound cards the control device must be enumerated last
233 * to make sure it's the final device node that gets ACLs
234 * applied. Applications rely on this fact and use ACL changes
235 * on the control node as an indicator that the ACL change of
236 * the entire sound card completed. The kernel makes this
237 * guarantee when creating those devices, and hence we should
238 * too when enumerating them. */
239
240 if ((c = strstr(syspath, "/sound/card"))) {
241 c += 11;
242 c += strcspn(c, "/");
243
244 if (strncmp(c, "/controlC", 9) == 0)
245 return c - syspath + 1;
246 }
247
248 return 0;
249 }
250
251 /**
252 * udev_enumerate_get_list_entry:
253 * @udev_enumerate: context
254 *
255 * Get the first entry of the sorted list of device paths.
256 *
257 * Returns: a udev_list_entry.
258 */
259 UDEV_EXPORT struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *udev_enumerate)
260 {
261 if (udev_enumerate == NULL)
262 return NULL;
263 if (!udev_enumerate->devices_uptodate) {
264 unsigned int i;
265 unsigned int max;
266 struct syspath *prev = NULL, *move_later = NULL;
267 size_t move_later_prefix = 0;
268
269 udev_list_cleanup(&udev_enumerate->devices_list);
270 qsort(udev_enumerate->devices, udev_enumerate->devices_cur, sizeof(struct syspath), syspath_cmp);
271
272 max = udev_enumerate->devices_cur;
273 for (i = 0; i < max; i++) {
274 struct syspath *entry = &udev_enumerate->devices[i];
275
276 /* skip duplicated entries */
277 if (prev != NULL &&
278 entry->len == prev->len &&
279 memcmp(entry->syspath, prev->syspath, entry->len) == 0)
280 continue;
281 prev = entry;
282
283 /* skip to be delayed devices, and add them to the end of the list */
284 if (devices_delay_end(udev_enumerate->udev, entry->syspath)) {
285 syspath_add(udev_enumerate, entry->syspath);
286 /* need to update prev here for the case realloc() gives a different address */
287 prev = &udev_enumerate->devices[i];
288 continue;
289 }
290
291 /* skip to be delayed devices, and move the to
292 * the point where the prefix changes. We can
293 * only move one item at a time. */
294 if (!move_later) {
295 move_later_prefix = devices_delay_later(udev_enumerate->udev, entry->syspath);
296
297 if (move_later_prefix > 0) {
298 move_later = entry;
299 continue;
300 }
301 }
302
303 if (move_later &&
304 strncmp(entry->syspath, move_later->syspath, move_later_prefix) != 0) {
305
306 udev_list_entry_add(&udev_enumerate->devices_list, move_later->syspath, NULL);
307 move_later = NULL;
308 }
309
310 udev_list_entry_add(&udev_enumerate->devices_list, entry->syspath, NULL);
311 }
312
313 if (move_later)
314 udev_list_entry_add(&udev_enumerate->devices_list, move_later->syspath, NULL);
315
316 /* add and cleanup delayed devices from end of list */
317 for (i = max; i < udev_enumerate->devices_cur; i++) {
318 struct syspath *entry = &udev_enumerate->devices[i];
319
320 udev_list_entry_add(&udev_enumerate->devices_list, entry->syspath, NULL);
321 free(entry->syspath);
322 }
323 udev_enumerate->devices_cur = max;
324
325 udev_enumerate->devices_uptodate = true;
326 }
327 return udev_list_get_entry(&udev_enumerate->devices_list);
328 }
329
330 /**
331 * udev_enumerate_add_match_subsystem:
332 * @udev_enumerate: context
333 * @subsystem: filter for a subsystem of the device to include in the list
334 *
335 * Match only devices belonging to a certain kernel subsystem.
336 *
337 * Returns: 0 on success, otherwise a negative error value.
338 */
339 UDEV_EXPORT int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem)
340 {
341 if (udev_enumerate == NULL)
342 return -EINVAL;
343 if (subsystem == NULL)
344 return 0;
345 if (udev_list_entry_add(&udev_enumerate->subsystem_match_list, subsystem, NULL) == NULL)
346 return -ENOMEM;
347 return 0;
348 }
349
350 /**
351 * udev_enumerate_add_nomatch_subsystem:
352 * @udev_enumerate: context
353 * @subsystem: filter for a subsystem of the device to exclude from the list
354 *
355 * Match only devices not belonging to a certain kernel subsystem.
356 *
357 * Returns: 0 on success, otherwise a negative error value.
358 */
359 UDEV_EXPORT int udev_enumerate_add_nomatch_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem)
360 {
361 if (udev_enumerate == NULL)
362 return -EINVAL;
363 if (subsystem == NULL)
364 return 0;
365 if (udev_list_entry_add(&udev_enumerate->subsystem_nomatch_list, subsystem, NULL) == NULL)
366 return -ENOMEM;
367 return 0;
368 }
369
370 /**
371 * udev_enumerate_add_match_sysattr:
372 * @udev_enumerate: context
373 * @sysattr: filter for a sys attribute at the device to include in the list
374 * @value: optional value of the sys attribute
375 *
376 * Match only devices with a certain /sys device attribute.
377 *
378 * Returns: 0 on success, otherwise a negative error value.
379 */
380 UDEV_EXPORT int udev_enumerate_add_match_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value)
381 {
382 if (udev_enumerate == NULL)
383 return -EINVAL;
384 if (sysattr == NULL)
385 return 0;
386 if (udev_list_entry_add(&udev_enumerate->sysattr_match_list, sysattr, value) == NULL)
387 return -ENOMEM;
388 return 0;
389 }
390
391 /**
392 * udev_enumerate_add_nomatch_sysattr:
393 * @udev_enumerate: context
394 * @sysattr: filter for a sys attribute at the device to exclude from the list
395 * @value: optional value of the sys attribute
396 *
397 * Match only devices not having a certain /sys device attribute.
398 *
399 * Returns: 0 on success, otherwise a negative error value.
400 */
401 UDEV_EXPORT int udev_enumerate_add_nomatch_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value)
402 {
403 if (udev_enumerate == NULL)
404 return -EINVAL;
405 if (sysattr == NULL)
406 return 0;
407 if (udev_list_entry_add(&udev_enumerate->sysattr_nomatch_list, sysattr, value) == NULL)
408 return -ENOMEM;
409 return 0;
410 }
411
412 static int match_sysattr_value(struct udev_device *dev, const char *sysattr, const char *match_val)
413 {
414 const char *val = NULL;
415 bool match = false;
416
417 val = udev_device_get_sysattr_value(dev, sysattr);
418 if (val == NULL)
419 goto exit;
420 if (match_val == NULL) {
421 match = true;
422 goto exit;
423 }
424 if (fnmatch(match_val, val, 0) == 0) {
425 match = true;
426 goto exit;
427 }
428 exit:
429 return match;
430 }
431
432 /**
433 * udev_enumerate_add_match_property:
434 * @udev_enumerate: context
435 * @property: filter for a property of the device to include in the list
436 * @value: value of the property
437 *
438 * Match only devices with a certain property.
439 *
440 * Returns: 0 on success, otherwise a negative error value.
441 */
442 UDEV_EXPORT int udev_enumerate_add_match_property(struct udev_enumerate *udev_enumerate, const char *property, const char *value)
443 {
444 if (udev_enumerate == NULL)
445 return -EINVAL;
446 if (property == NULL)
447 return 0;
448 if (udev_list_entry_add(&udev_enumerate->properties_match_list, property, value) == NULL)
449 return -ENOMEM;
450 return 0;
451 }
452
453 /**
454 * udev_enumerate_add_match_tag:
455 * @udev_enumerate: context
456 * @tag: filter for a tag of the device to include in the list
457 *
458 * Match only devices with a certain tag.
459 *
460 * Returns: 0 on success, otherwise a negative error value.
461 */
462 UDEV_EXPORT int udev_enumerate_add_match_tag(struct udev_enumerate *udev_enumerate, const char *tag)
463 {
464 if (udev_enumerate == NULL)
465 return -EINVAL;
466 if (tag == NULL)
467 return 0;
468 if (udev_list_entry_add(&udev_enumerate->tags_match_list, tag, NULL) == NULL)
469 return -ENOMEM;
470 return 0;
471 }
472
473 /**
474 * udev_enumerate_add_match_parent:
475 * @udev_enumerate: context
476 * @parent: parent device where to start searching
477 *
478 * Return the devices on the subtree of one given device. The parent
479 * itself is included in the list.
480 *
481 * A reference for the device is held until the udev_enumerate context
482 * is cleaned up.
483 *
484 * Returns: 0 on success, otherwise a negative error value.
485 */
486 UDEV_EXPORT int udev_enumerate_add_match_parent(struct udev_enumerate *udev_enumerate, struct udev_device *parent)
487 {
488 if (udev_enumerate == NULL)
489 return -EINVAL;
490 if (parent == NULL)
491 return 0;
492 if (udev_enumerate->parent_match != NULL)
493 udev_device_unref(udev_enumerate->parent_match);
494 udev_enumerate->parent_match = udev_device_ref(parent);
495 return 0;
496 }
497
498 /**
499 * udev_enumerate_add_match_is_initialized:
500 * @udev_enumerate: context
501 *
502 * Match only devices which udev has set up already. This makes
503 * sure, that the device node permissions and context are properly set
504 * and that network devices are fully renamed.
505 *
506 * Usually, devices which are found in the kernel but not already
507 * handled by udev, have still pending events. Services should subscribe
508 * to monitor events and wait for these devices to become ready, instead
509 * of using uninitialized devices.
510 *
511 * For now, this will not affect devices which do not have a device node
512 * and are not network interfaces.
513 *
514 * Returns: 0 on success, otherwise a negative error value.
515 */
516 UDEV_EXPORT int udev_enumerate_add_match_is_initialized(struct udev_enumerate *udev_enumerate)
517 {
518 if (udev_enumerate == NULL)
519 return -EINVAL;
520 udev_enumerate->match_is_initialized = true;
521 return 0;
522 }
523
524 /**
525 * udev_enumerate_add_match_sysname:
526 * @udev_enumerate: context
527 * @sysname: filter for the name of the device to include in the list
528 *
529 * Match only devices with a given /sys device name.
530 *
531 * Returns: 0 on success, otherwise a negative error value.
532 */
533 UDEV_EXPORT int udev_enumerate_add_match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname)
534 {
535 if (udev_enumerate == NULL)
536 return -EINVAL;
537 if (sysname == NULL)
538 return 0;
539 if (udev_list_entry_add(&udev_enumerate->sysname_match_list, sysname, NULL) == NULL)
540 return -ENOMEM;
541 return 0;
542 }
543
544 static bool match_sysattr(struct udev_enumerate *udev_enumerate, struct udev_device *dev)
545 {
546 struct udev_list_entry *list_entry;
547
548 /* skip list */
549 udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->sysattr_nomatch_list)) {
550 if (match_sysattr_value(dev, udev_list_entry_get_name(list_entry),
551 udev_list_entry_get_value(list_entry)))
552 return false;
553 }
554 /* include list */
555 if (udev_list_get_entry(&udev_enumerate->sysattr_match_list) != NULL) {
556 udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->sysattr_match_list)) {
557 /* anything that does not match, will make it FALSE */
558 if (!match_sysattr_value(dev, udev_list_entry_get_name(list_entry),
559 udev_list_entry_get_value(list_entry)))
560 return false;
561 }
562 return true;
563 }
564 return true;
565 }
566
567 static bool match_property(struct udev_enumerate *udev_enumerate, struct udev_device *dev)
568 {
569 struct udev_list_entry *list_entry;
570 bool match = false;
571
572 /* no match always matches */
573 if (udev_list_get_entry(&udev_enumerate->properties_match_list) == NULL)
574 return true;
575
576 /* loop over matches */
577 udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->properties_match_list)) {
578 const char *match_key = udev_list_entry_get_name(list_entry);
579 const char *match_value = udev_list_entry_get_value(list_entry);
580 struct udev_list_entry *property_entry;
581
582 /* loop over device properties */
583 udev_list_entry_foreach(property_entry, udev_device_get_properties_list_entry(dev)) {
584 const char *dev_key = udev_list_entry_get_name(property_entry);
585 const char *dev_value = udev_list_entry_get_value(property_entry);
586
587 if (fnmatch(match_key, dev_key, 0) != 0)
588 continue;
589 if (match_value == NULL && dev_value == NULL) {
590 match = true;
591 goto out;
592 }
593 if (match_value == NULL || dev_value == NULL)
594 continue;
595 if (fnmatch(match_value, dev_value, 0) == 0) {
596 match = true;
597 goto out;
598 }
599 }
600 }
601 out:
602 return match;
603 }
604
605 static bool match_tag(struct udev_enumerate *udev_enumerate, struct udev_device *dev)
606 {
607 struct udev_list_entry *list_entry;
608
609 /* no match always matches */
610 if (udev_list_get_entry(&udev_enumerate->tags_match_list) == NULL)
611 return true;
612
613 /* loop over matches */
614 udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->tags_match_list))
615 if (!udev_device_has_tag(dev, udev_list_entry_get_name(list_entry)))
616 return false;
617
618 return true;
619 }
620
621 static bool match_parent(struct udev_enumerate *udev_enumerate, struct udev_device *dev)
622 {
623 const char *parent;
624
625 if (udev_enumerate->parent_match == NULL)
626 return true;
627
628 parent = udev_device_get_devpath(udev_enumerate->parent_match);
629 return strncmp(parent, udev_device_get_devpath(dev), strlen(parent)) == 0;
630 }
631
632 static bool match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname)
633 {
634 struct udev_list_entry *list_entry;
635
636 if (udev_list_get_entry(&udev_enumerate->sysname_match_list) == NULL)
637 return true;
638
639 udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->sysname_match_list)) {
640 if (fnmatch(udev_list_entry_get_name(list_entry), sysname, 0) != 0)
641 continue;
642 return true;
643 }
644 return false;
645 }
646
647 static int scan_dir_and_add_devices(struct udev_enumerate *udev_enumerate,
648 const char *basedir, const char *subdir1, const char *subdir2)
649 {
650 struct udev *udev = udev_enumerate_get_udev(udev_enumerate);
651 char path[UTIL_PATH_SIZE];
652 size_t l;
653 char *s;
654 DIR *dir;
655 struct dirent *dent;
656
657 s = path;
658 l = util_strpcpyl(&s, sizeof(path), udev_get_sys_path(udev), "/", basedir, NULL);
659 if (subdir1 != NULL)
660 l = util_strpcpyl(&s, l, "/", subdir1, NULL);
661 if (subdir2 != NULL)
662 util_strpcpyl(&s, l, "/", subdir2, NULL);
663 dir = opendir(path);
664 if (dir == NULL)
665 return -ENOENT;
666 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
667 char syspath[UTIL_PATH_SIZE];
668 struct udev_device *dev;
669
670 if (dent->d_name[0] == '.')
671 continue;
672
673 if (!match_sysname(udev_enumerate, dent->d_name))
674 continue;
675
676 util_strscpyl(syspath, sizeof(syspath), path, "/", dent->d_name, NULL);
677 dev = udev_device_new_from_syspath(udev_enumerate->udev, syspath);
678 if (dev == NULL)
679 continue;
680
681 if (udev_enumerate->match_is_initialized) {
682 /*
683 * All devices with a device node or network interfaces
684 * possibly need udev to adjust the device node permission
685 * or context, or rename the interface before it can be
686 * reliably used from other processes.
687 *
688 * For now, we can only check these types of devices, we
689 * might not store a database, and have no way to find out
690 * for all other types of devices.
691 */
692 if (!udev_device_get_is_initialized(dev) &&
693 (major(udev_device_get_devnum(dev)) > 0 || udev_device_get_ifindex(dev) > 0))
694 goto nomatch;
695 }
696 if (!match_parent(udev_enumerate, dev))
697 goto nomatch;
698 if (!match_tag(udev_enumerate, dev))
699 goto nomatch;
700 if (!match_property(udev_enumerate, dev))
701 goto nomatch;
702 if (!match_sysattr(udev_enumerate, dev))
703 goto nomatch;
704
705 syspath_add(udev_enumerate, udev_device_get_syspath(dev));
706 nomatch:
707 udev_device_unref(dev);
708 }
709 closedir(dir);
710 return 0;
711 }
712
713 static bool match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem)
714 {
715 struct udev_list_entry *list_entry;
716
717 udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->subsystem_nomatch_list)) {
718 if (fnmatch(udev_list_entry_get_name(list_entry), subsystem, 0) == 0)
719 return false;
720 }
721 if (udev_list_get_entry(&udev_enumerate->subsystem_match_list) != NULL) {
722 udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->subsystem_match_list)) {
723 if (fnmatch(udev_list_entry_get_name(list_entry), subsystem, 0) == 0)
724 return true;
725 }
726 return false;
727 }
728 return true;
729 }
730
731 static int scan_dir(struct udev_enumerate *udev_enumerate, const char *basedir, const char *subdir, const char *subsystem)
732 {
733 struct udev *udev = udev_enumerate_get_udev(udev_enumerate);
734
735 char path[UTIL_PATH_SIZE];
736 DIR *dir;
737 struct dirent *dent;
738
739 util_strscpyl(path, sizeof(path), udev_get_sys_path(udev), "/", basedir, NULL);
740 dir = opendir(path);
741 if (dir == NULL)
742 return -1;
743 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
744 if (dent->d_name[0] == '.')
745 continue;
746 if (!match_subsystem(udev_enumerate, subsystem != NULL ? subsystem : dent->d_name))
747 continue;
748 scan_dir_and_add_devices(udev_enumerate, basedir, dent->d_name, subdir);
749 }
750 closedir(dir);
751 return 0;
752 }
753
754 /**
755 * udev_enumerate_add_syspath:
756 * @udev_enumerate: context
757 * @syspath: path of a device
758 *
759 * Add a device to the list of devices, to retrieve it back sorted in dependency order.
760 *
761 * Returns: 0 on success, otherwise a negative error value.
762 */
763 UDEV_EXPORT int udev_enumerate_add_syspath(struct udev_enumerate *udev_enumerate, const char *syspath)
764 {
765 struct udev_device *udev_device;
766
767 if (udev_enumerate == NULL)
768 return -EINVAL;
769 if (syspath == NULL)
770 return 0;
771 /* resolve to real syspath */
772 udev_device = udev_device_new_from_syspath(udev_enumerate->udev, syspath);
773 if (udev_device == NULL)
774 return -EINVAL;
775 syspath_add(udev_enumerate, udev_device_get_syspath(udev_device));
776 udev_device_unref(udev_device);
777 return 0;
778 }
779
780 static int scan_devices_tags(struct udev_enumerate *udev_enumerate)
781 {
782 struct udev *udev = udev_enumerate_get_udev(udev_enumerate);
783 struct udev_list_entry *list_entry;
784
785 /* scan only tagged devices, use tags reverse-index, instead of searching all devices in /sys */
786 udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->tags_match_list)) {
787 DIR *dir;
788 struct dirent *dent;
789 char path[UTIL_PATH_SIZE];
790
791 util_strscpyl(path, sizeof(path), udev_get_run_path(udev), "/tags/",
792 udev_list_entry_get_name(list_entry), NULL);
793 dir = opendir(path);
794 if (dir == NULL)
795 continue;
796 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
797 struct udev_device *dev;
798
799 if (dent->d_name[0] == '.')
800 continue;
801
802 dev = udev_device_new_from_device_id(udev_enumerate->udev, dent->d_name);
803 if (dev == NULL)
804 continue;
805
806 if (!match_subsystem(udev_enumerate, udev_device_get_subsystem(dev)))
807 goto nomatch;
808 if (!match_sysname(udev_enumerate, udev_device_get_sysname(dev)))
809 goto nomatch;
810 if (!match_parent(udev_enumerate, dev))
811 goto nomatch;
812 if (!match_property(udev_enumerate, dev))
813 goto nomatch;
814 if (!match_sysattr(udev_enumerate, dev))
815 goto nomatch;
816
817 syspath_add(udev_enumerate, udev_device_get_syspath(dev));
818 nomatch:
819 udev_device_unref(dev);
820 }
821 closedir(dir);
822 }
823 return 0;
824 }
825
826 static int parent_add_child(struct udev_enumerate *enumerate, const char *path)
827 {
828 struct udev_device *dev;
829
830 dev = udev_device_new_from_syspath(enumerate->udev, path);
831 if (dev == NULL)
832 return -ENODEV;
833
834 if (!match_subsystem(enumerate, udev_device_get_subsystem(dev)))
835 return 0;
836 if (!match_sysname(enumerate, udev_device_get_sysname(dev)))
837 return 0;
838 if (!match_property(enumerate, dev))
839 return 0;
840 if (!match_sysattr(enumerate, dev))
841 return 0;
842
843 syspath_add(enumerate, udev_device_get_syspath(dev));
844 udev_device_unref(dev);
845 return 1;
846 }
847
848 static int parent_crawl_children(struct udev_enumerate *enumerate, const char *path, int maxdepth)
849 {
850 DIR *d;
851 struct dirent *dent;
852
853 d = opendir(path);
854 if (d == NULL)
855 return -errno;
856
857 for (dent = readdir(d); dent != NULL; dent = readdir(d)) {
858 char *child;
859
860 if (dent->d_name[0] == '.')
861 continue;
862 if (dent->d_type != DT_DIR)
863 continue;
864 if (asprintf(&child, "%s/%s", path, dent->d_name) < 0)
865 continue;
866 parent_add_child(enumerate, child);
867 if (maxdepth > 0)
868 parent_crawl_children(enumerate, child, maxdepth-1);
869 free(child);
870 }
871
872 closedir(d);
873 return 0;
874 }
875
876 static int scan_devices_children(struct udev_enumerate *enumerate)
877 {
878 const char *path;
879
880 path = udev_device_get_syspath(enumerate->parent_match);
881 parent_add_child(enumerate, path);
882 return parent_crawl_children(enumerate, path, 256);
883 }
884
885 static int scan_devices_all(struct udev_enumerate *udev_enumerate)
886 {
887 struct udev *udev = udev_enumerate_get_udev(udev_enumerate);
888 char base[UTIL_PATH_SIZE];
889 struct stat statbuf;
890
891 util_strscpyl(base, sizeof(base), udev_get_sys_path(udev), "/subsystem", NULL);
892 if (stat(base, &statbuf) == 0) {
893 /* we have /subsystem/, forget all the old stuff */
894 dbg(udev, "searching '/subsystem/*/devices/*' dir\n");
895 scan_dir(udev_enumerate, "subsystem", "devices", NULL);
896 } else {
897 dbg(udev, "searching '/bus/*/devices/*' dir\n");
898 scan_dir(udev_enumerate, "bus", "devices", NULL);
899 dbg(udev, "searching '/class/*' dir\n");
900 scan_dir(udev_enumerate, "class", NULL, NULL);
901 }
902 return 0;
903 }
904
905 /**
906 * udev_enumerate_scan_devices:
907 * @udev_enumerate: udev enumeration context
908 *
909 * Scan /sys for all devices which match the given filters. No matches
910 * will return all currently available devices.
911 *
912 * Returns: 0 on success, otherwise a negative error value.
913 **/
914 UDEV_EXPORT int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate)
915 {
916 if (udev_enumerate == NULL)
917 return -EINVAL;
918
919 /* efficiently lookup tags only, we maintain a reverse-index */
920 if (udev_list_get_entry(&udev_enumerate->tags_match_list) != NULL)
921 return scan_devices_tags(udev_enumerate);
922
923 /* walk the subtree of one parent device only */
924 if (udev_enumerate->parent_match != NULL)
925 return scan_devices_children(udev_enumerate);
926
927 /* scan devices of all subsystems */
928 return scan_devices_all(udev_enumerate);
929 }
930
931 /**
932 * udev_enumerate_scan_subsystems:
933 * @udev_enumerate: udev enumeration context
934 *
935 * Scan /sys for all kernel subsystems, including buses, classes, drivers.
936 *
937 * Returns: 0 on success, otherwise a negative error value.
938 **/
939 UDEV_EXPORT int udev_enumerate_scan_subsystems(struct udev_enumerate *udev_enumerate)
940 {
941 struct udev *udev = udev_enumerate_get_udev(udev_enumerate);
942 char base[UTIL_PATH_SIZE];
943 struct stat statbuf;
944 const char *subsysdir;
945
946 if (udev_enumerate == NULL)
947 return -EINVAL;
948
949 /* all kernel modules */
950 if (match_subsystem(udev_enumerate, "module")) {
951 dbg(udev, "searching 'modules/*' dir\n");
952 scan_dir_and_add_devices(udev_enumerate, "module", NULL, NULL);
953 }
954
955 util_strscpyl(base, sizeof(base), udev_get_sys_path(udev), "/subsystem", NULL);
956 if (stat(base, &statbuf) == 0)
957 subsysdir = "subsystem";
958 else
959 subsysdir = "bus";
960
961 /* all subsystems (only buses support coldplug) */
962 if (match_subsystem(udev_enumerate, "subsystem")) {
963 dbg(udev, "searching '%s/*' dir\n", subsysdir);
964 scan_dir_and_add_devices(udev_enumerate, subsysdir, NULL, NULL);
965 }
966
967 /* all subsystem drivers */
968 if (match_subsystem(udev_enumerate, "drivers")) {
969 dbg(udev, "searching '%s/*/drivers/*' dir\n", subsysdir);
970 scan_dir(udev_enumerate, subsysdir, "drivers", "drivers");
971 }
972 return 0;
973 }
File src/libudev-list.c added (mode: 100644) (index 0000000..8c0296b)
1 /*
2 * libudev - interface to udev device information
3 *
4 * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 */
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <stddef.h>
15 #include <unistd.h>
16 #include <errno.h>
17 #include <string.h>
18
19 #include "libudev.h"
20 #include "libudev-private.h"
21
22 /**
23 * SECTION:libudev-list
24 * @short_description: list operation
25 *
26 * Libudev list operations.
27 */
28
29 /**
30 * udev_list_entry:
31 *
32 * Opaque object representing one entry in a list. An entry contains
33 * contains a name, and optionally a value.
34 */
35 struct udev_list_entry {
36 struct udev_list_node node;
37 struct udev_list *list;
38 char *name;
39 char *value;
40 int num;
41 };
42
43 /* the list's head points to itself if empty */
44 void udev_list_node_init(struct udev_list_node *list)
45 {
46 list->next = list;
47 list->prev = list;
48 }
49
50 int udev_list_node_is_empty(struct udev_list_node *list)
51 {
52 return list->next == list;
53 }
54
55 static void udev_list_node_insert_between(struct udev_list_node *new,
56 struct udev_list_node *prev,
57 struct udev_list_node *next)
58 {
59 next->prev = new;
60 new->next = next;
61 new->prev = prev;
62 prev->next = new;
63 }
64
65 void udev_list_node_append(struct udev_list_node *new, struct udev_list_node *list)
66 {
67 udev_list_node_insert_between(new, list->prev, list);
68 }
69
70 void udev_list_node_remove(struct udev_list_node *entry)
71 {
72 struct udev_list_node *prev = entry->prev;
73 struct udev_list_node *next = entry->next;
74
75 next->prev = prev;
76 prev->next = next;
77
78 entry->prev = NULL;
79 entry->next = NULL;
80 }
81
82 /* return list entry which embeds this node */
83 static struct udev_list_entry *list_node_to_entry(struct udev_list_node *node)
84 {
85 char *list;
86
87 list = (char *)node;
88 list -= offsetof(struct udev_list_entry, node);
89 return (struct udev_list_entry *)list;
90 }
91
92 void udev_list_init(struct udev *udev, struct udev_list *list, bool unique)
93 {
94 memset(list, 0x00, sizeof(struct udev_list));
95 list->udev = udev;
96 list->unique = unique;
97 udev_list_node_init(&list->node);
98 }
99
100 /* insert entry into a list as the last element */
101 void udev_list_entry_append(struct udev_list_entry *new, struct udev_list *list)
102 {
103 /* inserting before the list head make the node the last node in the list */
104 udev_list_node_insert_between(&new->node, list->node.prev, &list->node);
105 new->list = list;
106 }
107
108 /* insert entry into a list, before a given existing entry */
109 void udev_list_entry_insert_before(struct udev_list_entry *new, struct udev_list_entry *entry)
110 {
111 udev_list_node_insert_between(&new->node, entry->node.prev, &entry->node);
112 new->list = entry->list;
113 }
114
115 /* binary search in sorted array */
116 static int list_search(struct udev_list *list, const char *name)
117 {
118 unsigned int first, last;
119
120 first = 0;
121 last = list->entries_cur;
122 while (first < last) {
123 unsigned int i;
124 int cmp;
125
126 i = (first + last)/2;
127 cmp = strcmp(name, list->entries[i]->name);
128 if (cmp < 0)
129 last = i;
130 else if (cmp > 0)
131 first = i+1;
132 else
133 return i;
134 }
135
136 /* not found, return negative insertion-index+1 */
137 return -(first+1);
138 }
139
140 struct udev_list_entry *udev_list_entry_add(struct udev_list *list, const char *name, const char *value)
141 {
142 struct udev_list_entry *entry;
143 int i = 0;
144
145 if (list->unique) {
146 /* lookup existing name or insertion-index */
147 i = list_search(list, name);
148 if (i >= 0) {
149 entry = list->entries[i];
150
151 dbg(list->udev, "'%s' is already in the list\n", name);
152 free(entry->value);
153 if (value == NULL) {
154 entry->value = NULL;
155 dbg(list->udev, "'%s' value unset\n", name);
156 return entry;
157 }
158 entry->value = strdup(value);
159 if (entry->value == NULL)
160 return NULL;
161 dbg(list->udev, "'%s' value replaced with '%s'\n", name, value);
162 return entry;
163 }
164 }
165
166 /* add new name */
167 entry = calloc(1, sizeof(struct udev_list_entry));
168 if (entry == NULL)
169 return NULL;
170 entry->name = strdup(name);
171 if (entry->name == NULL) {
172 free(entry);
173 return NULL;
174 }
175 if (value != NULL) {
176 entry->value = strdup(value);
177 if (entry->value == NULL) {
178 free(entry->name);
179 free(entry);
180 return NULL;
181 }
182 }
183
184 if (list->unique) {
185 /* allocate or enlarge sorted array if needed */
186 if (list->entries_cur >= list->entries_max) {
187 unsigned int add;
188
189 add = list->entries_max;
190 if (add < 1)
191 add = 64;
192 list->entries = realloc(list->entries, (list->entries_max + add) * sizeof(struct udev_list_entry *));
193 if (list->entries == NULL) {
194 free(entry->name);
195 free(entry->value);
196 free(entry);
197 return NULL;
198 }
199 list->entries_max += add;
200 }
201
202 /* the negative i returned the insertion index */
203 i = (-i)-1;
204
205 /* insert into sorted list */
206 if ((unsigned int)i < list->entries_cur)
207 udev_list_entry_insert_before(entry, list->entries[i]);
208 else
209 udev_list_entry_append(entry, list);
210
211 /* insert into sorted array */
212 memmove(&list->entries[i+1], &list->entries[i],
213 (list->entries_cur - i) * sizeof(struct udev_list_entry *));
214 list->entries[i] = entry;
215 list->entries_cur++;
216 } else {
217 udev_list_entry_append(entry, list);
218 }
219
220 dbg(list->udev, "'%s=%s' added\n", entry->name, entry->value);
221 return entry;
222 }
223
224 void udev_list_entry_delete(struct udev_list_entry *entry)
225 {
226 if (entry->list->entries != NULL) {
227 int i;
228 struct udev_list *list = entry->list;
229
230 /* remove entry from sorted array */
231 i = list_search(list, entry->name);
232 if (i >= 0) {
233 memmove(&list->entries[i], &list->entries[i+1],
234 ((list->entries_cur-1) - i) * sizeof(struct udev_list_entry *));
235 list->entries_cur--;
236 }
237 }
238
239 udev_list_node_remove(&entry->node);
240 free(entry->name);
241 free(entry->value);
242 free(entry);
243 }
244
245 void udev_list_cleanup(struct udev_list *list)
246 {
247 struct udev_list_entry *entry_loop;
248 struct udev_list_entry *entry_tmp;
249
250 free(list->entries);
251 list->entries = NULL;
252 list->entries_cur = 0;
253 list->entries_max = 0;
254 udev_list_entry_foreach_safe(entry_loop, entry_tmp, udev_list_get_entry(list))
255 udev_list_entry_delete(entry_loop);
256 }
257
258 struct udev_list_entry *udev_list_get_entry(struct udev_list *list)
259 {
260 if (udev_list_node_is_empty(&list->node))
261 return NULL;
262 return list_node_to_entry(list->node.next);
263 }
264
265 /**
266 * udev_list_entry_get_next:
267 * @list_entry: current entry
268 *
269 * Get the next entry from the list.
270 *
271 * Returns: udev_list_entry, #NULL if no more entries are available.
272 */
273 UDEV_EXPORT struct udev_list_entry *udev_list_entry_get_next(struct udev_list_entry *list_entry)
274 {
275 struct udev_list_node *next;
276
277 if (list_entry == NULL)
278 return NULL;
279 next = list_entry->node.next;
280 /* empty list or no more entries */
281 if (next == &list_entry->list->node)
282 return NULL;
283 return list_node_to_entry(next);
284 }
285
286 /**
287 * udev_list_entry_get_by_name:
288 * @list_entry: current entry
289 * @name: name string to match
290 *
291 * Lookup an entry in the list with a certain name.
292 *
293 * Returns: udev_list_entry, #NULL if no matching entry is found.
294 */
295 UDEV_EXPORT struct udev_list_entry *udev_list_entry_get_by_name(struct udev_list_entry *list_entry, const char *name)
296 {
297 int i;
298
299 if (list_entry == NULL)
300 return NULL;
301
302 if (!list_entry->list->unique)
303 return NULL;
304
305 i = list_search(list_entry->list, name);
306 if (i < 0)
307 return NULL;
308 return list_entry->list->entries[i];
309 }
310
311 /**
312 * udev_list_entry_get_name:
313 * @list_entry: current entry
314 *
315 * Get the name of a list entry.
316 *
317 * Returns: the name string of this entry.
318 */
319 UDEV_EXPORT const char *udev_list_entry_get_name(struct udev_list_entry *list_entry)
320 {
321 if (list_entry == NULL)
322 return NULL;
323 return list_entry->name;
324 }
325
326 /**
327 * udev_list_entry_get_value:
328 * @list_entry: current entry
329 *
330 * Get the value of list entry.
331 *
332 * Returns: the value string of this entry.
333 */
334 UDEV_EXPORT const char *udev_list_entry_get_value(struct udev_list_entry *list_entry)
335 {
336 if (list_entry == NULL)
337 return NULL;
338 return list_entry->value;
339 }
340
341 int udev_list_entry_get_num(struct udev_list_entry *list_entry)
342 {
343 if (list_entry == NULL)
344 return -EINVAL;
345 return list_entry->num;
346 }
347
348 void udev_list_entry_set_num(struct udev_list_entry *list_entry, int num)
349 {
350 if (list_entry == NULL)
351 return;
352 list_entry->num = num;
353 }
File src/libudev-monitor.c added (mode: 100644) (index 0000000..7029585)
1 /*
2 * libudev - interface to udev device information
3 *
4 * Copyright (C) 2008-2010 Kay Sievers <kay.sievers@vrfy.org>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 */
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <stddef.h>
15 #include <unistd.h>
16 #include <errno.h>
17 #include <string.h>
18 #include <dirent.h>
19 #include <sys/poll.h>
20 #include <sys/stat.h>
21 #include <sys/socket.h>
22 #include <sys/un.h>
23 #include <arpa/inet.h>
24 #include <linux/netlink.h>
25 #include <linux/filter.h>
26
27 #include "libudev.h"
28 #include "libudev-private.h"
29
30 /**
31 * SECTION:libudev-monitor
32 * @short_description: device event source
33 *
34 * Connects to a device event source.
35 */
36
37 /**
38 * udev_monitor:
39 *
40 * Opaque object handling an event source.
41 */
42 struct udev_monitor {
43 struct udev *udev;
44 int refcount;
45 int sock;
46 struct sockaddr_nl snl;
47 struct sockaddr_nl snl_trusted_sender;
48 struct sockaddr_nl snl_destination;
49 struct sockaddr_un sun;
50 socklen_t addrlen;
51 struct udev_list filter_subsystem_list;
52 struct udev_list filter_tag_list;
53 bool bound;
54 };
55
56 enum udev_monitor_netlink_group {
57 UDEV_MONITOR_NONE,
58 UDEV_MONITOR_KERNEL,
59 UDEV_MONITOR_UDEV,
60 };
61
62 #define UDEV_MONITOR_MAGIC 0xfeedcafe
63 struct udev_monitor_netlink_header {
64 /* "libudev" prefix to distinguish libudev and kernel messages */
65 char prefix[8];
66 /*
67 * magic to protect against daemon <-> library message format mismatch
68 * used in the kernel from socket filter rules; needs to be stored in network order
69 */
70 unsigned int magic;
71 /* total length of header structure known to the sender */
72 unsigned int header_size;
73 /* properties string buffer */
74 unsigned int properties_off;
75 unsigned int properties_len;
76 /*
77 * hashes of primary device properties strings, to let libudev subscribers
78 * use in-kernel socket filters; values need to be stored in network order
79 */
80 unsigned int filter_subsystem_hash;
81 unsigned int filter_devtype_hash;
82 unsigned int filter_tag_bloom_hi;
83 unsigned int filter_tag_bloom_lo;
84 };
85
86 static struct udev_monitor *udev_monitor_new(struct udev *udev)
87 {
88 struct udev_monitor *udev_monitor;
89
90 udev_monitor = calloc(1, sizeof(struct udev_monitor));
91 if (udev_monitor == NULL)
92 return NULL;
93 udev_monitor->refcount = 1;
94 udev_monitor->udev = udev;
95 udev_list_init(udev, &udev_monitor->filter_subsystem_list, false);
96 udev_list_init(udev, &udev_monitor->filter_tag_list, true);
97 return udev_monitor;
98 }
99
100 /**
101 * udev_monitor_new_from_socket:
102 * @udev: udev library context
103 * @socket_path: unix socket path
104 *
105 * This function should not be used in any new application. The
106 * kernel's netlink socket multiplexes messages to all interested
107 * clients. Creating custom sockets from udev to applications
108 * should be avoided.
109 *
110 * Create a new udev monitor and connect to a specified socket. The
111 * path to a socket either points to an existing socket file, or if
112 * the socket path starts with a '@' character, an abstract namespace
113 * socket will be used.
114 *
115 * A socket file will not be created. If it does not already exist,
116 * it will fall-back and connect to an abstract namespace socket with
117 * the given path. The permissions adjustment of a socket file, as
118 * well as the later cleanup, needs to be done by the caller.
119 *
120 * The initial refcount is 1, and needs to be decremented to
121 * release the resources of the udev monitor.
122 *
123 * Returns: a new udev monitor, or #NULL, in case of an error
124 **/
125 UDEV_EXPORT struct udev_monitor *udev_monitor_new_from_socket(struct udev *udev, const char *socket_path)
126 {
127 struct udev_monitor *udev_monitor;
128 struct stat statbuf;
129
130 if (udev == NULL)
131 return NULL;
132 if (socket_path == NULL)
133 return NULL;
134 udev_monitor = udev_monitor_new(udev);
135 if (udev_monitor == NULL)
136 return NULL;
137
138 udev_monitor->sun.sun_family = AF_LOCAL;
139 if (socket_path[0] == '@') {
140 /* translate leading '@' to abstract namespace */
141 util_strscpy(udev_monitor->sun.sun_path, sizeof(udev_monitor->sun.sun_path), socket_path);
142 udev_monitor->sun.sun_path[0] = '\0';
143 udev_monitor->addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(socket_path);
144 } else if (stat(socket_path, &statbuf) == 0 && S_ISSOCK(statbuf.st_mode)) {
145 /* existing socket file */
146 util_strscpy(udev_monitor->sun.sun_path, sizeof(udev_monitor->sun.sun_path), socket_path);
147 udev_monitor->addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(socket_path);
148 } else {
149 /* no socket file, assume abstract namespace socket */
150 util_strscpy(&udev_monitor->sun.sun_path[1], sizeof(udev_monitor->sun.sun_path)-1, socket_path);
151 udev_monitor->addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(socket_path)+1;
152 }
153 udev_monitor->sock = socket(AF_LOCAL, SOCK_DGRAM|SOCK_NONBLOCK|SOCK_CLOEXEC, 0);
154 if (udev_monitor->sock == -1) {
155 err(udev, "error getting socket: %m\n");
156 free(udev_monitor);
157 return NULL;
158 }
159
160 dbg(udev, "monitor %p created with '%s'\n", udev_monitor, socket_path);
161 return udev_monitor;
162 }
163
164 struct udev_monitor *udev_monitor_new_from_netlink_fd(struct udev *udev, const char *name, int fd)
165 {
166 struct udev_monitor *udev_monitor;
167 unsigned int group;
168
169 if (udev == NULL)
170 return NULL;
171
172 if (name == NULL)
173 group = UDEV_MONITOR_NONE;
174 else if (strcmp(name, "udev") == 0)
175 group = UDEV_MONITOR_UDEV;
176 else if (strcmp(name, "kernel") == 0)
177 group = UDEV_MONITOR_KERNEL;
178 else
179 return NULL;
180
181 udev_monitor = udev_monitor_new(udev);
182 if (udev_monitor == NULL)
183 return NULL;
184
185 if (fd < 0) {
186 udev_monitor->sock = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_KOBJECT_UEVENT);
187 if (udev_monitor->sock == -1) {
188 err(udev, "error getting socket: %m\n");
189 free(udev_monitor);
190 return NULL;
191 }
192 } else {
193 udev_monitor->bound = true;
194 udev_monitor->sock = fd;
195 }
196
197 udev_monitor->snl.nl_family = AF_NETLINK;
198 udev_monitor->snl.nl_groups = group;
199
200 /* default destination for sending */
201 udev_monitor->snl_destination.nl_family = AF_NETLINK;
202 udev_monitor->snl_destination.nl_groups = UDEV_MONITOR_UDEV;
203
204 dbg(udev, "monitor %p created with NETLINK_KOBJECT_UEVENT (%u)\n", udev_monitor, group);
205 return udev_monitor;
206 }
207
208 /**
209 * udev_monitor_new_from_netlink:
210 * @udev: udev library context
211 * @name: name of event source
212 *
213 * Create new udev monitor and connect to a specified event
214 * source. Valid sources identifiers are "udev" and "kernel".
215 *
216 * Applications should usually not connect directly to the
217 * "kernel" events, because the devices might not be useable
218 * at that time, before udev has configured them, and created
219 * device nodes. Accessing devices at the same time as udev,
220 * might result in unpredictable behavior. The "udev" events
221 * are sent out after udev has finished its event processing,
222 * all rules have been processed, and needed device nodes are
223 * created.
224 *
225 * The initial refcount is 1, and needs to be decremented to
226 * release the resources of the udev monitor.
227 *
228 * Returns: a new udev monitor, or #NULL, in case of an error
229 **/
230 UDEV_EXPORT struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, const char *name)
231 {
232 return udev_monitor_new_from_netlink_fd(udev, name, -1);
233 }
234
235 static inline void bpf_stmt(struct sock_filter *inss, unsigned int *i,
236 unsigned short code, unsigned int data)
237 {
238 struct sock_filter *ins = &inss[*i];
239
240 ins->code = code;
241 ins->k = data;
242 (*i)++;
243 }
244
245 static inline void bpf_jmp(struct sock_filter *inss, unsigned int *i,
246 unsigned short code, unsigned int data,
247 unsigned short jt, unsigned short jf)
248 {
249 struct sock_filter *ins = &inss[*i];
250
251 ins->code = code;
252 ins->jt = jt;
253 ins->jf = jf;
254 ins->k = data;
255 (*i)++;
256 }
257
258 /**
259 * udev_monitor_filter_update:
260 * @udev_monitor: monitor
261 *
262 * Update the installed socket filter. This is only needed,
263 * if the filter was removed or changed.
264 *
265 * Returns: 0 on success, otherwise a negative error value.
266 */
267 UDEV_EXPORT int udev_monitor_filter_update(struct udev_monitor *udev_monitor)
268 {
269 struct sock_filter ins[512];
270 struct sock_fprog filter;
271 unsigned int i;
272 struct udev_list_entry *list_entry;
273 int err;
274
275 if (udev_list_get_entry(&udev_monitor->filter_subsystem_list) == NULL &&
276 udev_list_get_entry(&udev_monitor->filter_tag_list) == NULL)
277 return 0;
278
279 memset(ins, 0x00, sizeof(ins));
280 i = 0;
281
282 /* load magic in A */
283 bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(struct udev_monitor_netlink_header, magic));
284 /* jump if magic matches */
285 bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, UDEV_MONITOR_MAGIC, 1, 0);
286 /* wrong magic, pass packet */
287 bpf_stmt(ins, &i, BPF_RET|BPF_K, 0xffffffff);
288
289 if (udev_list_get_entry(&udev_monitor->filter_tag_list) != NULL) {
290 int tag_matches;
291
292 /* count tag matches, to calculate end of tag match block */
293 tag_matches = 0;
294 udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_tag_list))
295 tag_matches++;
296
297 /* add all tags matches */
298 udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_tag_list)) {
299 uint64_t tag_bloom_bits = util_string_bloom64(udev_list_entry_get_name(list_entry));
300 uint32_t tag_bloom_hi = tag_bloom_bits >> 32;
301 uint32_t tag_bloom_lo = tag_bloom_bits & 0xffffffff;
302
303 /* load device bloom bits in A */
304 bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(struct udev_monitor_netlink_header, filter_tag_bloom_hi));
305 /* clear bits (tag bits & bloom bits) */
306 bpf_stmt(ins, &i, BPF_ALU|BPF_AND|BPF_K, tag_bloom_hi);
307 /* jump to next tag if it does not match */
308 bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, tag_bloom_hi, 0, 3);
309
310 /* load device bloom bits in A */
311 bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(struct udev_monitor_netlink_header, filter_tag_bloom_lo));
312 /* clear bits (tag bits & bloom bits) */
313 bpf_stmt(ins, &i, BPF_ALU|BPF_AND|BPF_K, tag_bloom_lo);
314 /* jump behind end of tag match block if tag matches */
315 tag_matches--;
316 bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, tag_bloom_lo, 1 + (tag_matches * 6), 0);
317 }
318
319 /* nothing matched, drop packet */
320 bpf_stmt(ins, &i, BPF_RET|BPF_K, 0);
321 }
322
323 /* add all subsystem matches */
324 if (udev_list_get_entry(&udev_monitor->filter_subsystem_list) != NULL) {
325 udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_subsystem_list)) {
326 unsigned int hash = util_string_hash32(udev_list_entry_get_name(list_entry));
327
328 /* load device subsystem value in A */
329 bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(struct udev_monitor_netlink_header, filter_subsystem_hash));
330 if (udev_list_entry_get_value(list_entry) == NULL) {
331 /* jump if subsystem does not match */
332 bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, hash, 0, 1);
333 } else {
334 /* jump if subsystem does not match */
335 bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, hash, 0, 3);
336
337 /* load device devtype value in A */
338 bpf_stmt(ins, &i, BPF_LD|BPF_W|BPF_ABS, offsetof(struct udev_monitor_netlink_header, filter_devtype_hash));
339 /* jump if value does not match */
340 hash = util_string_hash32(udev_list_entry_get_value(list_entry));
341 bpf_jmp(ins, &i, BPF_JMP|BPF_JEQ|BPF_K, hash, 0, 1);
342 }
343
344 /* matched, pass packet */
345 bpf_stmt(ins, &i, BPF_RET|BPF_K, 0xffffffff);
346
347 if (i+1 >= ARRAY_SIZE(ins))
348 return -1;
349 }
350
351 /* nothing matched, drop packet */
352 bpf_stmt(ins, &i, BPF_RET|BPF_K, 0);
353 }
354
355 /* matched, pass packet */
356 bpf_stmt(ins, &i, BPF_RET|BPF_K, 0xffffffff);
357
358 /* install filter */
359 memset(&filter, 0x00, sizeof(filter));
360 filter.len = i;
361 filter.filter = ins;
362 err = setsockopt(udev_monitor->sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter));
363 return err;
364 }
365
366 int udev_monitor_allow_unicast_sender(struct udev_monitor *udev_monitor, struct udev_monitor *sender)
367 {
368 udev_monitor->snl_trusted_sender.nl_pid = sender->snl.nl_pid;
369 return 0;
370 }
371 /**
372 * udev_monitor_enable_receiving:
373 * @udev_monitor: the monitor which should receive events
374 *
375 * Binds the @udev_monitor socket to the event source.
376 *
377 * Returns: 0 on success, otherwise a negative error value.
378 */
379 UDEV_EXPORT int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor)
380 {
381 int err = 0;
382 const int on = 1;
383
384 if (udev_monitor->sun.sun_family != 0) {
385 if (!udev_monitor->bound) {
386 err = bind(udev_monitor->sock,
387 (struct sockaddr *)&udev_monitor->sun, udev_monitor->addrlen);
388 if (err == 0)
389 udev_monitor->bound = true;
390 }
391 } else if (udev_monitor->snl.nl_family != 0) {
392 udev_monitor_filter_update(udev_monitor);
393 if (!udev_monitor->bound) {
394 err = bind(udev_monitor->sock,
395 (struct sockaddr *)&udev_monitor->snl, sizeof(struct sockaddr_nl));
396 if (err == 0)
397 udev_monitor->bound = true;
398 }
399 if (err == 0) {
400 struct sockaddr_nl snl;
401 socklen_t addrlen;
402
403 /*
404 * get the address the kernel has assigned us
405 * it is usually, but not necessarily the pid
406 */
407 addrlen = sizeof(struct sockaddr_nl);
408 err = getsockname(udev_monitor->sock, (struct sockaddr *)&snl, &addrlen);
409 if (err == 0)
410 udev_monitor->snl.nl_pid = snl.nl_pid;
411 }
412 } else {
413 return -EINVAL;
414 }
415
416 if (err < 0) {
417 err(udev_monitor->udev, "bind failed: %m\n");
418 return err;
419 }
420
421 /* enable receiving of sender credentials */
422 setsockopt(udev_monitor->sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
423 return 0;
424 }
425
426 /**
427 * udev_monitor_set_receive_buffer_size:
428 * @udev_monitor: the monitor which should receive events
429 * @size: the size in bytes
430 *
431 * Set the size of the kernel socket buffer. This call needs the
432 * appropriate privileges to succeed.
433 *
434 * Returns: 0 on success, otherwise -1 on error.
435 */
436 UDEV_EXPORT int udev_monitor_set_receive_buffer_size(struct udev_monitor *udev_monitor, int size)
437 {
438 if (udev_monitor == NULL)
439 return -1;
440 return setsockopt(udev_monitor->sock, SOL_SOCKET, SO_RCVBUFFORCE, &size, sizeof(size));
441 }
442
443 int udev_monitor_disconnect(struct udev_monitor *udev_monitor)
444 {
445 int err;
446
447 err = close(udev_monitor->sock);
448 udev_monitor->sock = -1;
449 return err;
450 }
451
452 /**
453 * udev_monitor_ref:
454 * @udev_monitor: udev monitor
455 *
456 * Take a reference of a udev monitor.
457 *
458 * Returns: the passed udev monitor
459 **/
460 UDEV_EXPORT struct udev_monitor *udev_monitor_ref(struct udev_monitor *udev_monitor)
461 {
462 if (udev_monitor == NULL)
463 return NULL;
464 udev_monitor->refcount++;
465 return udev_monitor;
466 }
467
468 /**
469 * udev_monitor_unref:
470 * @udev_monitor: udev monitor
471 *
472 * Drop a reference of a udev monitor. If the refcount reaches zero,
473 * the bound socket will be closed, and the resources of the monitor
474 * will be released.
475 *
476 **/
477 UDEV_EXPORT struct udev_monitor *udev_monitor_unref(struct udev_monitor *udev_monitor)
478 {
479 if (udev_monitor == NULL)
480 return NULL;
481 udev_monitor->refcount--;
482 if (udev_monitor->refcount > 0)
483 return udev_monitor;
484 if (udev_monitor->sock >= 0)
485 close(udev_monitor->sock);
486 udev_list_cleanup(&udev_monitor->filter_subsystem_list);
487 udev_list_cleanup(&udev_monitor->filter_tag_list);
488 dbg(udev_monitor->udev, "monitor %p released\n", udev_monitor);
489 free(udev_monitor);
490 return NULL;
491 }
492
493 /**
494 * udev_monitor_get_udev:
495 * @udev_monitor: udev monitor
496 *
497 * Retrieve the udev library context the monitor was created with.
498 *
499 * Returns: the udev library context
500 **/
501 UDEV_EXPORT struct udev *udev_monitor_get_udev(struct udev_monitor *udev_monitor)
502 {
503 if (udev_monitor == NULL)
504 return NULL;
505 return udev_monitor->udev;
506 }
507
508 /**
509 * udev_monitor_get_fd:
510 * @udev_monitor: udev monitor
511 *
512 * Retrieve the socket file descriptor associated with the monitor.
513 *
514 * Returns: the socket file descriptor
515 **/
516 UDEV_EXPORT int udev_monitor_get_fd(struct udev_monitor *udev_monitor)
517 {
518 if (udev_monitor == NULL)
519 return -1;
520 return udev_monitor->sock;
521 }
522
523 static int passes_filter(struct udev_monitor *udev_monitor, struct udev_device *udev_device)
524 {
525 struct udev_list_entry *list_entry;
526
527 if (udev_list_get_entry(&udev_monitor->filter_subsystem_list) == NULL)
528 goto tag;
529 udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_subsystem_list)) {
530 const char *subsys = udev_list_entry_get_name(list_entry);
531 const char *dsubsys = udev_device_get_subsystem(udev_device);
532 const char *devtype;
533 const char *ddevtype;
534
535 if (strcmp(dsubsys, subsys) != 0)
536 continue;
537
538 devtype = udev_list_entry_get_value(list_entry);
539 if (devtype == NULL)
540 goto tag;
541 ddevtype = udev_device_get_devtype(udev_device);
542 if (ddevtype == NULL)
543 continue;
544 if (strcmp(ddevtype, devtype) == 0)
545 goto tag;
546 }
547 return 0;
548
549 tag:
550 if (udev_list_get_entry(&udev_monitor->filter_tag_list) == NULL)
551 return 1;
552 udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_tag_list)) {
553 const char *tag = udev_list_entry_get_name(list_entry);
554
555 if (udev_device_has_tag(udev_device, tag))
556 return 1;
557 }
558 return 0;
559 }
560
561 /**
562 * udev_monitor_receive_device:
563 * @udev_monitor: udev monitor
564 *
565 * Receive data from the udev monitor socket, allocate a new udev
566 * device, fill in the received data, and return the device.
567 *
568 * Only socket connections with uid=0 are accepted.
569 *
570 * The monitor socket is by default set to NONBLOCK. A variant of poll() on
571 * the file descriptor returned by udev_monitor_get_fd() should to be used to
572 * wake up when new devices arrive, or alternatively the file descriptor
573 * switched into blocking mode.
574 *
575 * The initial refcount is 1, and needs to be decremented to
576 * release the resources of the udev device.
577 *
578 * Returns: a new udev device, or #NULL, in case of an error
579 **/
580 UDEV_EXPORT struct udev_device *udev_monitor_receive_device(struct udev_monitor *udev_monitor)
581 {
582 struct udev_device *udev_device;
583 struct msghdr smsg;
584 struct iovec iov;
585 char cred_msg[CMSG_SPACE(sizeof(struct ucred))];
586 struct cmsghdr *cmsg;
587 struct sockaddr_nl snl;
588 struct ucred *cred;
589 char buf[8192];
590 ssize_t buflen;
591 ssize_t bufpos;
592 struct udev_monitor_netlink_header *nlh;
593
594 retry:
595 if (udev_monitor == NULL)
596 return NULL;
597 iov.iov_base = &buf;
598 iov.iov_len = sizeof(buf);
599 memset (&smsg, 0x00, sizeof(struct msghdr));
600 smsg.msg_iov = &iov;
601 smsg.msg_iovlen = 1;
602 smsg.msg_control = cred_msg;
603 smsg.msg_controllen = sizeof(cred_msg);
604
605 if (udev_monitor->snl.nl_family != 0) {
606 smsg.msg_name = &snl;
607 smsg.msg_namelen = sizeof(snl);
608 }
609
610 buflen = recvmsg(udev_monitor->sock, &smsg, 0);
611 if (buflen < 0) {
612 if (errno != EINTR)
613 info(udev_monitor->udev, "unable to receive message\n");
614 return NULL;
615 }
616
617 if (buflen < 32 || (size_t)buflen >= sizeof(buf)) {
618 info(udev_monitor->udev, "invalid message length\n");
619 return NULL;
620 }
621
622 if (udev_monitor->snl.nl_family != 0) {
623 if (snl.nl_groups == 0) {
624 /* unicast message, check if we trust the sender */
625 if (udev_monitor->snl_trusted_sender.nl_pid == 0 ||
626 snl.nl_pid != udev_monitor->snl_trusted_sender.nl_pid) {
627 info(udev_monitor->udev, "unicast netlink message ignored\n");
628 return NULL;
629 }
630 } else if (snl.nl_groups == UDEV_MONITOR_KERNEL) {
631 if (snl.nl_pid > 0) {
632 info(udev_monitor->udev, "multicast kernel netlink message from pid %d ignored\n",
633 snl.nl_pid);
634 return NULL;
635 }
636 }
637 }
638
639 cmsg = CMSG_FIRSTHDR(&smsg);
640 if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) {
641 info(udev_monitor->udev, "no sender credentials received, message ignored\n");
642 return NULL;
643 }
644
645 cred = (struct ucred *)CMSG_DATA(cmsg);
646 if (cred->uid != 0) {
647 info(udev_monitor->udev, "sender uid=%d, message ignored\n", cred->uid);
648 return NULL;
649 }
650
651 if (memcmp(buf, "libudev", 8) == 0) {
652 /* udev message needs proper version magic */
653 nlh = (struct udev_monitor_netlink_header *) buf;
654 if (nlh->magic != htonl(UDEV_MONITOR_MAGIC)) {
655 err(udev_monitor->udev, "unrecognized message signature (%x != %x)\n",
656 nlh->magic, htonl(UDEV_MONITOR_MAGIC));
657 return NULL;
658 }
659 if (nlh->properties_off+32 > buflen)
660 return NULL;
661 bufpos = nlh->properties_off;
662 } else {
663 /* kernel message with header */
664 bufpos = strlen(buf) + 1;
665 if ((size_t)bufpos < sizeof("a@/d") || bufpos >= buflen) {
666 info(udev_monitor->udev, "invalid message length\n");
667 return NULL;
668 }
669
670 /* check message header */
671 if (strstr(buf, "@/") == NULL) {
672 info(udev_monitor->udev, "unrecognized message header\n");
673 return NULL;
674 }
675 }
676
677 udev_device = udev_device_new(udev_monitor->udev);
678 if (udev_device == NULL)
679 return NULL;
680 udev_device_set_info_loaded(udev_device);
681
682 while (bufpos < buflen) {
683 char *key;
684 size_t keylen;
685
686 key = &buf[bufpos];
687 keylen = strlen(key);
688 if (keylen == 0)
689 break;
690 bufpos += keylen + 1;
691 udev_device_add_property_from_string_parse(udev_device, key);
692 }
693
694 if (udev_device_add_property_from_string_parse_finish(udev_device) < 0) {
695 info(udev_monitor->udev, "missing values, invalid device\n");
696 udev_device_unref(udev_device);
697 return NULL;
698 }
699
700 /* skip device, if it does not pass the current filter */
701 if (!passes_filter(udev_monitor, udev_device)) {
702 struct pollfd pfd[1];
703 int rc;
704
705 udev_device_unref(udev_device);
706
707 /* if something is queued, get next device */
708 pfd[0].fd = udev_monitor->sock;
709 pfd[0].events = POLLIN;
710 rc = poll(pfd, 1, 0);
711 if (rc > 0)
712 goto retry;
713 return NULL;
714 }
715
716 return udev_device;
717 }
718
719 int udev_monitor_send_device(struct udev_monitor *udev_monitor,
720 struct udev_monitor *destination, struct udev_device *udev_device)
721 {
722 const char *buf;
723 ssize_t blen;
724 ssize_t count;
725
726 blen = udev_device_get_properties_monitor_buf(udev_device, &buf);
727 if (blen < 32)
728 return -EINVAL;
729
730 if (udev_monitor->sun.sun_family != 0) {
731 struct msghdr smsg;
732 struct iovec iov[2];
733 const char *action;
734 char header[2048];
735 char *s;
736
737 /* header <action>@<devpath> */
738 action = udev_device_get_action(udev_device);
739 if (action == NULL)
740 return -EINVAL;
741 s = header;
742 if (util_strpcpyl(&s, sizeof(header), action, "@", udev_device_get_devpath(udev_device), NULL) == 0)
743 return -EINVAL;
744 iov[0].iov_base = header;
745 iov[0].iov_len = (s - header)+1;
746
747 /* add properties list */
748 iov[1].iov_base = (char *)buf;
749 iov[1].iov_len = blen;
750
751 memset(&smsg, 0x00, sizeof(struct msghdr));
752 smsg.msg_iov = iov;
753 smsg.msg_iovlen = 2;
754 smsg.msg_name = &udev_monitor->sun;
755 smsg.msg_namelen = udev_monitor->addrlen;
756 count = sendmsg(udev_monitor->sock, &smsg, 0);
757 info(udev_monitor->udev, "passed %zi bytes to socket monitor %p\n", count, udev_monitor);
758 return count;
759 }
760
761 if (udev_monitor->snl.nl_family != 0) {
762 struct msghdr smsg;
763 struct iovec iov[2];
764 const char *val;
765 struct udev_monitor_netlink_header nlh;
766 struct udev_list_entry *list_entry;
767 uint64_t tag_bloom_bits;
768
769 /* add versioned header */
770 memset(&nlh, 0x00, sizeof(struct udev_monitor_netlink_header));
771 memcpy(nlh.prefix, "libudev", 8);
772 nlh.magic = htonl(UDEV_MONITOR_MAGIC);
773 nlh.header_size = sizeof(struct udev_monitor_netlink_header);
774 val = udev_device_get_subsystem(udev_device);
775 nlh.filter_subsystem_hash = htonl(util_string_hash32(val));
776 val = udev_device_get_devtype(udev_device);
777 if (val != NULL)
778 nlh.filter_devtype_hash = htonl(util_string_hash32(val));
779 iov[0].iov_base = &nlh;
780 iov[0].iov_len = sizeof(struct udev_monitor_netlink_header);
781
782 /* add tag bloom filter */
783 tag_bloom_bits = 0;
784 udev_list_entry_foreach(list_entry, udev_device_get_tags_list_entry(udev_device))
785 tag_bloom_bits |= util_string_bloom64(udev_list_entry_get_name(list_entry));
786 if (tag_bloom_bits > 0) {
787 nlh.filter_tag_bloom_hi = htonl(tag_bloom_bits >> 32);
788 nlh.filter_tag_bloom_lo = htonl(tag_bloom_bits & 0xffffffff);
789 }
790
791 /* add properties list */
792 nlh.properties_off = iov[0].iov_len;
793 nlh.properties_len = blen;
794 iov[1].iov_base = (char *)buf;
795 iov[1].iov_len = blen;
796
797 memset(&smsg, 0x00, sizeof(struct msghdr));
798 smsg.msg_iov = iov;
799 smsg.msg_iovlen = 2;
800 /*
801 * Use custom address for target, or the default one.
802 *
803 * If we send to a multicast group, we will get
804 * ECONNREFUSED, which is expected.
805 */
806 if (destination != NULL)
807 smsg.msg_name = &destination->snl;
808 else
809 smsg.msg_name = &udev_monitor->snl_destination;
810 smsg.msg_namelen = sizeof(struct sockaddr_nl);
811 count = sendmsg(udev_monitor->sock, &smsg, 0);
812 info(udev_monitor->udev, "passed %zi bytes to netlink monitor %p\n", count, udev_monitor);
813 return count;
814 }
815
816 return -EINVAL;
817 }
818
819 /**
820 * udev_monitor_filter_add_match_subsystem_devtype:
821 * @udev_monitor: the monitor
822 * @subsystem: the subsystem value to match the incoming devices against
823 * @devtype: the devtype value to match the incoming devices against
824 *
825 * This filter is efficiently executed inside the kernel, and libudev subscribers
826 * will usually not be woken up for devices which do not match.
827 *
828 * The filter must be installed before the monitor is switched to listening mode.
829 *
830 * Returns: 0 on success, otherwise a negative error value.
831 */
832 UDEV_EXPORT int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_monitor, const char *subsystem, const char *devtype)
833 {
834 if (udev_monitor == NULL)
835 return -EINVAL;
836 if (subsystem == NULL)
837 return -EINVAL;
838 if (udev_list_entry_add(&udev_monitor->filter_subsystem_list, subsystem, devtype) == NULL)
839 return -ENOMEM;
840 return 0;
841 }
842
843 /**
844 * udev_monitor_filter_add_match_tag:
845 * @udev_monitor: the monitor
846 * @tag: the name of a tag
847 *
848 * This filter is efficiently executed inside the kernel, and libudev subscribers
849 * will usually not be woken up for devices which do not match.
850 *
851 * The filter must be installed before the monitor is switched to listening mode.
852 *
853 * Returns: 0 on success, otherwise a negative error value.
854 */
855 UDEV_EXPORT int udev_monitor_filter_add_match_tag(struct udev_monitor *udev_monitor, const char *tag)
856 {
857 if (udev_monitor == NULL)
858 return -EINVAL;
859 if (tag == NULL)
860 return -EINVAL;
861 if (udev_list_entry_add(&udev_monitor->filter_tag_list, tag, NULL) == NULL)
862 return -ENOMEM;
863 return 0;
864 }
865
866 /**
867 * udev_monitor_filter_remove:
868 * @udev_monitor: monitor
869 *
870 * Remove all filters from monitor.
871 *
872 * Returns: 0 on success, otherwise a negative error value.
873 */
874 UDEV_EXPORT int udev_monitor_filter_remove(struct udev_monitor *udev_monitor)
875 {
876 static struct sock_fprog filter = { 0, NULL };
877
878 udev_list_cleanup(&udev_monitor->filter_subsystem_list);
879 return setsockopt(udev_monitor->sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter));
880 }
File src/libudev-private.h added (mode: 100644) (index 0000000..4b95ac2)
1 /*
2 * libudev - interface to udev device information
3 *
4 * Copyright (C) 2008-2010 Kay Sievers <kay.sievers@vrfy.org>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 */
11
12 #ifndef _LIBUDEV_PRIVATE_H_
13 #define _LIBUDEV_PRIVATE_H_
14
15 #include <syslog.h>
16 #include <signal.h>
17 #include <stdint.h>
18 #include <stdbool.h>
19 #include "libudev.h"
20
21 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
22 #define READ_END 0
23 #define WRITE_END 1
24
25 static inline void __attribute__((always_inline, format(printf, 2, 3)))
26 udev_log_null(struct udev *udev, const char *format, ...) {}
27
28 #define udev_log_cond(udev, prio, arg...) \
29 do { \
30 if (udev_get_log_priority(udev) >= prio) \
31 udev_log(udev, prio, __FILE__, __LINE__, __FUNCTION__, ## arg); \
32 } while (0)
33
34 #ifdef ENABLE_LOGGING
35 # ifdef ENABLE_DEBUG
36 # define dbg(udev, arg...) udev_log_cond(udev, LOG_DEBUG, ## arg)
37 # else
38 # define dbg(udev, arg...) udev_log_null(udev, ## arg)
39 # endif
40 # define info(udev, arg...) udev_log_cond(udev, LOG_INFO, ## arg)
41 # define err(udev, arg...) udev_log_cond(udev, LOG_ERR, ## arg)
42 #else
43 # define dbg(udev, arg...) udev_log_null(udev, ## arg)
44 # define info(udev, arg...) udev_log_null(udev, ## arg)
45 # define err(udev, arg...) udev_log_null(udev, ## arg)
46 #endif
47
48 #define UDEV_EXPORT __attribute__ ((visibility("default")))
49
50 static inline void udev_log_init(const char *program_name)
51 {
52 openlog(program_name, LOG_PID | LOG_CONS, LOG_DAEMON);
53 }
54
55 static inline void udev_log_close(void)
56 {
57 closelog();
58 }
59
60 /* libudev.c */
61 void udev_log(struct udev *udev,
62 int priority, const char *file, int line, const char *fn,
63 const char *format, ...)
64 __attribute__((format(printf, 6, 7)));
65 int udev_get_rules_path(struct udev *udev, char **path[], unsigned long long *ts_usec[]);
66 struct udev_list_entry *udev_add_property(struct udev *udev, const char *key, const char *value);
67 struct udev_list_entry *udev_get_properties_list_entry(struct udev *udev);
68
69 /* libudev-device.c */
70 struct udev_device *udev_device_new(struct udev *udev);
71 mode_t udev_device_get_devnode_mode(struct udev_device *udev_device);
72 int udev_device_set_syspath(struct udev_device *udev_device, const char *syspath);
73 int udev_device_set_devnode(struct udev_device *udev_device, const char *devnode);
74 int udev_device_add_devlink(struct udev_device *udev_device, const char *devlink, int unique);
75 void udev_device_cleanup_devlinks_list(struct udev_device *udev_device);
76 struct udev_list_entry *udev_device_add_property(struct udev_device *udev_device, const char *key, const char *value);
77 void udev_device_add_property_from_string_parse(struct udev_device *udev_device, const char *property);
78 int udev_device_add_property_from_string_parse_finish(struct udev_device *udev_device);
79 char **udev_device_get_properties_envp(struct udev_device *udev_device);
80 ssize_t udev_device_get_properties_monitor_buf(struct udev_device *udev_device, const char **buf);
81 int udev_device_read_db(struct udev_device *udev_device, const char *dbfile);
82 int udev_device_read_uevent_file(struct udev_device *udev_device);
83 int udev_device_set_action(struct udev_device *udev_device, const char *action);
84 const char *udev_device_get_devpath_old(struct udev_device *udev_device);
85 const char *udev_device_get_id_filename(struct udev_device *udev_device);
86 void udev_device_set_is_initialized(struct udev_device *udev_device);
87 int udev_device_add_tag(struct udev_device *udev_device, const char *tag);
88 void udev_device_cleanup_tags_list(struct udev_device *udev_device);
89 unsigned long long udev_device_get_usec_initialized(struct udev_device *udev_device);
90 void udev_device_set_usec_initialized(struct udev_device *udev_device, unsigned long long usec_initialized);
91 int udev_device_get_devlink_priority(struct udev_device *udev_device);
92 int udev_device_set_devlink_priority(struct udev_device *udev_device, int prio);
93 int udev_device_get_watch_handle(struct udev_device *udev_device);
94 int udev_device_set_watch_handle(struct udev_device *udev_device, int handle);
95 int udev_device_get_ifindex(struct udev_device *udev_device);
96 void udev_device_set_info_loaded(struct udev_device *device);
97 bool udev_device_get_db_persist(struct udev_device *udev_device);
98 void udev_device_set_db_persist(struct udev_device *udev_device);
99
100 /* libudev-device-private.c */
101 int udev_device_update_db(struct udev_device *udev_device);
102 int udev_device_delete_db(struct udev_device *udev_device);
103 int udev_device_tag_index(struct udev_device *dev, struct udev_device *dev_old, bool add);
104
105 /* libudev-monitor.c - netlink/unix socket communication */
106 int udev_monitor_disconnect(struct udev_monitor *udev_monitor);
107 int udev_monitor_allow_unicast_sender(struct udev_monitor *udev_monitor, struct udev_monitor *sender);
108 int udev_monitor_send_device(struct udev_monitor *udev_monitor,
109 struct udev_monitor *destination, struct udev_device *udev_device);
110 struct udev_monitor *udev_monitor_new_from_netlink_fd(struct udev *udev, const char *name, int fd);
111
112 /* libudev-list.c */
113 struct udev_list_node {
114 struct udev_list_node *next, *prev;
115 };
116 struct udev_list {
117 struct udev *udev;
118 struct udev_list_node node;
119 struct udev_list_entry **entries;
120 unsigned int entries_cur;
121 unsigned int entries_max;
122 bool unique;
123 };
124 #define UDEV_LIST(list) struct udev_list_node list = { &(list), &(list) }
125 void udev_list_node_init(struct udev_list_node *list);
126 int udev_list_node_is_empty(struct udev_list_node *list);
127 void udev_list_node_append(struct udev_list_node *new, struct udev_list_node *list);
128 void udev_list_node_remove(struct udev_list_node *entry);
129 #define udev_list_node_foreach(node, list) \
130 for (node = (list)->next; \
131 node != list; \
132 node = (node)->next)
133 #define udev_list_node_foreach_safe(node, tmp, list) \
134 for (node = (list)->next, tmp = (node)->next; \
135 node != list; \
136 node = tmp, tmp = (tmp)->next)
137 void udev_list_init(struct udev *udev, struct udev_list *list, bool unique);
138 void udev_list_cleanup(struct udev_list *list);
139 struct udev_list_entry *udev_list_get_entry(struct udev_list *list);
140 struct udev_list_entry *udev_list_entry_add(struct udev_list *list, const char *name, const char *value);
141 void udev_list_entry_delete(struct udev_list_entry *entry);
142 void udev_list_entry_insert_before(struct udev_list_entry *new, struct udev_list_entry *entry);
143 void udev_list_entry_append(struct udev_list_entry *new, struct udev_list *list);
144 int udev_list_entry_get_num(struct udev_list_entry *list_entry);
145 void udev_list_entry_set_num(struct udev_list_entry *list_entry, int num);
146 #define udev_list_entry_foreach_safe(entry, tmp, first) \
147 for (entry = first, tmp = udev_list_entry_get_next(entry); \
148 entry != NULL; \
149 entry = tmp, tmp = udev_list_entry_get_next(tmp))
150
151 /* libudev-queue.c */
152 unsigned long long int udev_get_kernel_seqnum(struct udev *udev);
153 int udev_queue_read_seqnum(FILE *queue_file, unsigned long long int *seqnum);
154 ssize_t udev_queue_read_devpath(FILE *queue_file, char *devpath, size_t size);
155 ssize_t udev_queue_skip_devpath(FILE *queue_file);
156
157 /* libudev-queue-private.c */
158 struct udev_queue_export *udev_queue_export_new(struct udev *udev);
159 struct udev_queue_export *udev_queue_export_unref(struct udev_queue_export *udev_queue_export);
160 void udev_queue_export_cleanup(struct udev_queue_export *udev_queue_export);
161 int udev_queue_export_device_queued(struct udev_queue_export *udev_queue_export, struct udev_device *udev_device);
162 int udev_queue_export_device_finished(struct udev_queue_export *udev_queue_export, struct udev_device *udev_device);
163
164 /* libudev-util.c */
165 #define UTIL_PATH_SIZE 1024
166 #define UTIL_NAME_SIZE 512
167 #define UTIL_LINE_SIZE 16384
168 #define UDEV_ALLOWED_CHARS_INPUT "/ $%?,"
169 ssize_t util_get_sys_core_link_value(struct udev *udev, const char *slink, const char *syspath, char *value, size_t size);
170 int util_resolve_sys_link(struct udev *udev, char *syspath, size_t size);
171 int util_log_priority(const char *priority);
172 size_t util_path_encode(const char *src, char *dest, size_t size);
173 size_t util_path_decode(char *s);
174 void util_remove_trailing_chars(char *path, char c);
175 size_t util_strpcpy(char **dest, size_t size, const char *src);
176 size_t util_strpcpyl(char **dest, size_t size, const char *src, ...) __attribute__((sentinel));
177 size_t util_strscpy(char *dest, size_t size, const char *src);
178 size_t util_strscpyl(char *dest, size_t size, const char *src, ...) __attribute__((sentinel));
179 int util_replace_whitespace(const char *str, char *to, size_t len);
180 int util_replace_chars(char *str, const char *white);
181 unsigned int util_string_hash32(const char *key);
182 uint64_t util_string_bloom64(const char *str);
183
184 /* libudev-util-private.c */
185 int util_create_path(struct udev *udev, const char *path);
186 int util_create_path_selinux(struct udev *udev, const char *path);
187 int util_delete_path(struct udev *udev, const char *path);
188 uid_t util_lookup_user(struct udev *udev, const char *user);
189 gid_t util_lookup_group(struct udev *udev, const char *group);
190 int util_resolve_subsys_kernel(struct udev *udev, const char *string,
191 char *result, size_t maxsize, int read_value);
192 unsigned long long ts_usec(const struct timespec *ts);
193 unsigned long long now_usec(void);
194 ssize_t print_kmsg(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
195
196 /* libudev-selinux-private.c */
197 #ifndef WITH_SELINUX
198 static inline void udev_selinux_init(struct udev *udev) {}
199 static inline void udev_selinux_exit(struct udev *udev) {}
200 static inline void udev_selinux_lsetfilecon(struct udev *udev, const char *file, unsigned int mode) {}
201 static inline void udev_selinux_setfscreatecon(struct udev *udev, const char *file, unsigned int mode) {}
202 static inline void udev_selinux_setfscreateconat(struct udev *udev, int dfd, const char *file, unsigned int mode) {}
203 static inline void udev_selinux_resetfscreatecon(struct udev *udev) {}
204 #else
205 void udev_selinux_init(struct udev *udev);
206 void udev_selinux_exit(struct udev *udev);
207 void udev_selinux_lsetfilecon(struct udev *udev, const char *file, unsigned int mode);
208 void udev_selinux_setfscreatecon(struct udev *udev, const char *file, unsigned int mode);
209 void udev_selinux_setfscreateconat(struct udev *udev, int dfd, const char *file, unsigned int mode);
210 void udev_selinux_resetfscreatecon(struct udev *udev);
211 #endif
212
213 #endif
File src/libudev-queue-private.c added (mode: 100644) (index 0000000..d3e09e8)
1 /*
2 * libudev - interface to udev device information
3 *
4 * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org>
5 * Copyright (C) 2009 Alan Jenkins <alan-jenkins@tuffmail.co.uk>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 */
12
13 /*
14 * DISCLAIMER - The file format mentioned here is private to udev/libudev,
15 * and may be changed without notice.
16 *
17 * The udev event queue is exported as a binary log file.
18 * Each log record consists of a sequence number followed by the device path.
19 *
20 * When a new event is queued, its details are appended to the log.
21 * When the event finishes, a second record is appended to the log
22 * with the same sequence number but a devpath len of 0.
23 *
24 * Example:
25 * { 0x0000000000000001 }
26 * { 0x0000000000000001, 0x0019, "/devices/virtual/mem/null" },
27 * { 0x0000000000000002, 0x001b, "/devices/virtual/mem/random" },
28 * { 0x0000000000000001, 0x0000 },
29 * { 0x0000000000000003, 0x0019, "/devices/virtual/mem/zero" },
30 *
31 * Events 2 and 3 are still queued, but event 1 has finished.
32 *
33 * The queue does not grow indefinitely. It is periodically re-created
34 * to remove finished events. Atomic rename() makes this transparent to readers.
35 *
36 * The queue file starts with a single sequence number which specifies the
37 * minimum sequence number in the log that follows. Any events prior to this
38 * sequence number have already finished.
39 */
40
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <unistd.h>
45 #include <fcntl.h>
46 #include <dirent.h>
47 #include <limits.h>
48 #include <errno.h>
49 #include <sys/stat.h>
50 #include <sys/types.h>
51
52 #include "libudev.h"
53 #include "libudev-private.h"
54
55 static int rebuild_queue_file(struct udev_queue_export *udev_queue_export);
56
57 struct udev_queue_export {
58 struct udev *udev;
59 int queued_count; /* number of unfinished events exported in queue file */
60 FILE *queue_file;
61 unsigned long long int seqnum_max; /* earliest sequence number in queue file */
62 unsigned long long int seqnum_min; /* latest sequence number in queue file */
63 int waste_bytes; /* queue file bytes wasted on finished events */
64 };
65
66 struct udev_queue_export *udev_queue_export_new(struct udev *udev)
67 {
68 struct udev_queue_export *udev_queue_export;
69 unsigned long long int initial_seqnum;
70
71 if (udev == NULL)
72 return NULL;
73
74 udev_queue_export = calloc(1, sizeof(struct udev_queue_export));
75 if (udev_queue_export == NULL)
76 return NULL;
77 udev_queue_export->udev = udev;
78
79 initial_seqnum = udev_get_kernel_seqnum(udev);
80 udev_queue_export->seqnum_min = initial_seqnum;
81 udev_queue_export->seqnum_max = initial_seqnum;
82
83 udev_queue_export_cleanup(udev_queue_export);
84 if (rebuild_queue_file(udev_queue_export) != 0) {
85 free(udev_queue_export);
86 return NULL;
87 }
88
89 return udev_queue_export;
90 }
91
92 struct udev_queue_export *udev_queue_export_unref(struct udev_queue_export *udev_queue_export)
93 {
94 if (udev_queue_export == NULL)
95 return NULL;
96 if (udev_queue_export->queue_file != NULL)
97 fclose(udev_queue_export->queue_file);
98 free(udev_queue_export);
99 return NULL;
100 }
101
102 void udev_queue_export_cleanup(struct udev_queue_export *udev_queue_export)
103 {
104 char filename[UTIL_PATH_SIZE];
105
106 if (udev_queue_export == NULL)
107 return;
108 util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev_queue_export->udev), "/queue.tmp", NULL);
109 unlink(filename);
110 util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev_queue_export->udev), "/queue.bin", NULL);
111 unlink(filename);
112 }
113
114 static int skip_to(FILE *file, long offset)
115 {
116 long old_offset;
117
118 /* fseek may drop buffered data, avoid it for small seeks */
119 old_offset = ftell(file);
120 if (offset > old_offset && offset - old_offset <= BUFSIZ) {
121 size_t skip_bytes = offset - old_offset;
122 char *buf = alloca(skip_bytes);
123
124 if (fread(buf, skip_bytes, 1, file) != skip_bytes)
125 return -1;
126 }
127
128 return fseek(file, offset, SEEK_SET);
129 }
130
131 struct queue_devpaths {
132 unsigned int devpaths_first; /* index of first queued event */
133 unsigned int devpaths_size;
134 long devpaths[]; /* seqnum -> offset of devpath in queue file (or 0) */
135 };
136
137 /*
138 * Returns a table mapping seqnum to devpath file offset for currently queued events.
139 * devpaths[i] represents the event with seqnum = i + udev_queue_export->seqnum_min.
140 */
141 static struct queue_devpaths *build_index(struct udev_queue_export *udev_queue_export)
142 {
143 struct queue_devpaths *devpaths;
144 unsigned long long int range;
145 long devpath_offset;
146 ssize_t devpath_len;
147 unsigned long long int seqnum;
148 unsigned long long int n;
149 unsigned int i;
150
151 /* seek to the first event in the file */
152 rewind(udev_queue_export->queue_file);
153 udev_queue_read_seqnum(udev_queue_export->queue_file, &seqnum);
154
155 /* allocate the table */
156 range = udev_queue_export->seqnum_min - udev_queue_export->seqnum_max;
157 if (range - 1 > INT_MAX) {
158 err(udev_queue_export->udev, "queue file overflow\n");
159 return NULL;
160 }
161 devpaths = calloc(1, sizeof(struct queue_devpaths) + (range + 1) * sizeof(long));
162 if (devpaths == NULL)
163 return NULL;
164 devpaths->devpaths_size = range + 1;
165
166 /* read all records and populate the table */
167 for (;;) {
168 if (udev_queue_read_seqnum(udev_queue_export->queue_file, &seqnum) < 0)
169 break;
170 n = seqnum - udev_queue_export->seqnum_max;
171 if (n >= devpaths->devpaths_size)
172 goto read_error;
173
174 devpath_offset = ftell(udev_queue_export->queue_file);
175 devpath_len = udev_queue_skip_devpath(udev_queue_export->queue_file);
176 if (devpath_len < 0)
177 goto read_error;
178
179 if (devpath_len > 0)
180 devpaths->devpaths[n] = devpath_offset;
181 else
182 devpaths->devpaths[n] = 0;
183 }
184
185 /* find first queued event */
186 for (i = 0; i < devpaths->devpaths_size; i++) {
187 if (devpaths->devpaths[i] != 0)
188 break;
189 }
190 devpaths->devpaths_first = i;
191
192 return devpaths;
193
194 read_error:
195 err(udev_queue_export->udev, "queue file corrupted\n");
196 free(devpaths);
197 return NULL;
198 }
199
200 static int rebuild_queue_file(struct udev_queue_export *udev_queue_export)
201 {
202 unsigned long long int seqnum;
203 struct queue_devpaths *devpaths = NULL;
204 char filename[UTIL_PATH_SIZE];
205 char filename_tmp[UTIL_PATH_SIZE];
206 FILE *new_queue_file = NULL;
207 unsigned int i;
208
209 /* read old queue file */
210 if (udev_queue_export->queue_file != NULL) {
211 dbg(udev_queue_export->udev, "compacting queue file, freeing %d bytes\n",
212 udev_queue_export->waste_bytes);
213
214 devpaths = build_index(udev_queue_export);
215 if (devpaths != NULL)
216 udev_queue_export->seqnum_max += devpaths->devpaths_first;
217 }
218 if (devpaths == NULL) {
219 dbg(udev_queue_export->udev, "creating empty queue file\n");
220 udev_queue_export->queued_count = 0;
221 udev_queue_export->seqnum_max = udev_queue_export->seqnum_min;
222 }
223
224 /* create new queue file */
225 util_strscpyl(filename_tmp, sizeof(filename_tmp), udev_get_run_path(udev_queue_export->udev), "/queue.tmp", NULL);
226 new_queue_file = fopen(filename_tmp, "w+");
227 if (new_queue_file == NULL)
228 goto error;
229 seqnum = udev_queue_export->seqnum_max;
230 fwrite(&seqnum, 1, sizeof(unsigned long long int), new_queue_file);
231
232 /* copy unfinished events only to the new file */
233 if (devpaths != NULL) {
234 for (i = devpaths->devpaths_first; i < devpaths->devpaths_size; i++) {
235 char devpath[UTIL_PATH_SIZE];
236 int err;
237 unsigned short devpath_len;
238
239 if (devpaths->devpaths[i] != 0)
240 {
241 skip_to(udev_queue_export->queue_file, devpaths->devpaths[i]);
242 err = udev_queue_read_devpath(udev_queue_export->queue_file, devpath, sizeof(devpath));
243 devpath_len = err;
244
245 fwrite(&seqnum, sizeof(unsigned long long int), 1, new_queue_file);
246 fwrite(&devpath_len, sizeof(unsigned short), 1, new_queue_file);
247 fwrite(devpath, 1, devpath_len, new_queue_file);
248 }
249 seqnum++;
250 }
251 free(devpaths);
252 devpaths = NULL;
253 }
254 fflush(new_queue_file);
255 if (ferror(new_queue_file))
256 goto error;
257
258 /* rename the new file on top of the old one */
259 util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev_queue_export->udev), "/queue.bin", NULL);
260 if (rename(filename_tmp, filename) != 0)
261 goto error;
262
263 if (udev_queue_export->queue_file != NULL)
264 fclose(udev_queue_export->queue_file);
265 udev_queue_export->queue_file = new_queue_file;
266 udev_queue_export->waste_bytes = 0;
267
268 return 0;
269
270 error:
271 err(udev_queue_export->udev, "failed to create queue file: %m\n");
272 udev_queue_export_cleanup(udev_queue_export);
273
274 if (udev_queue_export->queue_file != NULL) {
275 fclose(udev_queue_export->queue_file);
276 udev_queue_export->queue_file = NULL;
277 }
278 if (new_queue_file != NULL)
279 fclose(new_queue_file);
280
281 if (devpaths != NULL)
282 free(devpaths);
283 udev_queue_export->queued_count = 0;
284 udev_queue_export->waste_bytes = 0;
285 udev_queue_export->seqnum_max = udev_queue_export->seqnum_min;
286
287 return -1;
288 }
289
290 static int write_queue_record(struct udev_queue_export *udev_queue_export,
291 unsigned long long int seqnum, const char *devpath, size_t devpath_len)
292 {
293 unsigned short len;
294
295 if (udev_queue_export->queue_file == NULL) {
296 dbg(udev_queue_export->udev, "can't record event: queue file not available\n");
297 return -1;
298 }
299
300 if (fwrite(&seqnum, sizeof(unsigned long long int), 1, udev_queue_export->queue_file) != 1)
301 goto write_error;
302
303 len = (devpath_len < USHRT_MAX) ? devpath_len : USHRT_MAX;
304 if (fwrite(&len, sizeof(unsigned short), 1, udev_queue_export->queue_file) != 1)
305 goto write_error;
306 if (len > 0) {
307 if (fwrite(devpath, 1, len, udev_queue_export->queue_file) != len)
308 goto write_error;
309 }
310
311 /* *must* flush output; caller may fork */
312 if (fflush(udev_queue_export->queue_file) != 0)
313 goto write_error;
314
315 return 0;
316
317 write_error:
318 /* if we failed half way through writing a record to a file,
319 we should not try to write any further records to it. */
320 err(udev_queue_export->udev, "error writing to queue file: %m\n");
321 fclose(udev_queue_export->queue_file);
322 udev_queue_export->queue_file = NULL;
323
324 return -1;
325 }
326
327 enum device_state {
328 DEVICE_QUEUED,
329 DEVICE_FINISHED,
330 };
331
332 static inline size_t queue_record_size(size_t devpath_len)
333 {
334 return sizeof(unsigned long long int) + sizeof(unsigned short int) + devpath_len;
335 }
336
337 static int update_queue(struct udev_queue_export *udev_queue_export,
338 struct udev_device *udev_device, enum device_state state)
339 {
340 unsigned long long int seqnum = udev_device_get_seqnum(udev_device);
341 const char *devpath = NULL;
342 size_t devpath_len = 0;
343 int bytes;
344 int err;
345
346 /* FINISHED records have a zero length devpath */
347 if (state == DEVICE_QUEUED) {
348 devpath = udev_device_get_devpath(udev_device);
349 devpath_len = strlen(devpath);
350 }
351
352 /* recover from an earlier failed rebuild */
353 if (udev_queue_export->queue_file == NULL) {
354 if (rebuild_queue_file(udev_queue_export) != 0)
355 return -1;
356 }
357
358 /* if we're removing the last event from the queue, that's the best time to rebuild it */
359 if (state != DEVICE_QUEUED && udev_queue_export->queued_count == 1) {
360 /* we don't need to read the old queue file */
361 fclose(udev_queue_export->queue_file);
362 udev_queue_export->queue_file = NULL;
363 rebuild_queue_file(udev_queue_export);
364 return 0;
365 }
366
367 /* try to rebuild the queue files before they grow larger than one page. */
368 bytes = ftell(udev_queue_export->queue_file) + queue_record_size(devpath_len);
369 if ((udev_queue_export->waste_bytes > bytes / 2) && bytes > 4096)
370 rebuild_queue_file(udev_queue_export);
371
372 /* don't record a finished event, if we already dropped the event in a failed rebuild */
373 if (seqnum < udev_queue_export->seqnum_max)
374 return 0;
375
376 /* now write to the queue */
377 if (state == DEVICE_QUEUED) {
378 udev_queue_export->queued_count++;
379 udev_queue_export->seqnum_min = seqnum;
380 } else {
381 udev_queue_export->waste_bytes += queue_record_size(devpath_len) + queue_record_size(0);
382 udev_queue_export->queued_count--;
383 }
384 err = write_queue_record(udev_queue_export, seqnum, devpath, devpath_len);
385
386 /* try to handle ENOSPC */
387 if (err != 0 && udev_queue_export->queued_count == 0) {
388 udev_queue_export_cleanup(udev_queue_export);
389 err = rebuild_queue_file(udev_queue_export);
390 }
391
392 return err;
393 }
394
395 static int update(struct udev_queue_export *udev_queue_export,
396 struct udev_device *udev_device, enum device_state state)
397 {
398 if (update_queue(udev_queue_export, udev_device, state) != 0)
399 return -1;
400
401 return 0;
402 }
403
404 int udev_queue_export_device_queued(struct udev_queue_export *udev_queue_export, struct udev_device *udev_device)
405 {
406 return update(udev_queue_export, udev_device, DEVICE_QUEUED);
407 }
408
409 int udev_queue_export_device_finished(struct udev_queue_export *udev_queue_export, struct udev_device *udev_device)
410 {
411 return update(udev_queue_export, udev_device, DEVICE_FINISHED);
412 }
File src/libudev-queue.c added (mode: 100644) (index 0000000..03722ac)
1 /*
2 * libudev - interface to udev device information
3 *
4 * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org>
5 * Copyright (C) 2009 Alan Jenkins <alan-jenkins@tuffmail.co.uk>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 */
12
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <stddef.h>
16 #include <unistd.h>
17 #include <errno.h>
18 #include <string.h>
19 #include <dirent.h>
20 #include <fcntl.h>
21 #include <limits.h>
22 #include <sys/stat.h>
23
24 #include "libudev.h"
25 #include "libudev-private.h"
26
27 /**
28 * SECTION:libudev-queue
29 * @short_description: access to currently active events
30 *
31 * The udev daemon processes events asynchronously. All events which do not have
32 * interdependencies run in parallel. This exports the current state of the
33 * event processing queue, and the current event sequence numbers from the kernel
34 * and the udev daemon.
35 */
36
37 /**
38 * udev_queue:
39 *
40 * Opaque object representing the current event queue in the udev daemon.
41 */
42 struct udev_queue {
43 struct udev *udev;
44 int refcount;
45 struct udev_list queue_list;
46 };
47
48 /**
49 * udev_queue_new:
50 * @udev: udev library context
51 *
52 * The initial refcount is 1, and needs to be decremented to
53 * release the resources of the udev queue context.
54 *
55 * Returns: the udev queue context, or #NULL on error.
56 **/
57 UDEV_EXPORT struct udev_queue *udev_queue_new(struct udev *udev)
58 {
59 struct udev_queue *udev_queue;
60
61 if (udev == NULL)
62 return NULL;
63
64 udev_queue = calloc(1, sizeof(struct udev_queue));
65 if (udev_queue == NULL)
66 return NULL;
67 udev_queue->refcount = 1;
68 udev_queue->udev = udev;
69 udev_list_init(udev, &udev_queue->queue_list, false);
70 return udev_queue;
71 }
72
73 /**
74 * udev_queue_ref:
75 * @udev_queue: udev queue context
76 *
77 * Take a reference of a udev queue context.
78 *
79 * Returns: the same udev queue context.
80 **/
81 UDEV_EXPORT struct udev_queue *udev_queue_ref(struct udev_queue *udev_queue)
82 {
83 if (udev_queue == NULL)
84 return NULL;
85 udev_queue->refcount++;
86 return udev_queue;
87 }
88
89 /**
90 * udev_queue_unref:
91 * @udev_queue: udev queue context
92 *
93 * Drop a reference of a udev queue context. If the refcount reaches zero,
94 * the resources of the queue context will be released.
95 **/
96 UDEV_EXPORT struct udev_queue *udev_queue_unref(struct udev_queue *udev_queue)
97 {
98 if (udev_queue == NULL)
99 return NULL;
100 udev_queue->refcount--;
101 if (udev_queue->refcount > 0)
102 return udev_queue;
103 udev_list_cleanup(&udev_queue->queue_list);
104 free(udev_queue);
105 return NULL;
106 }
107
108 /**
109 * udev_queue_get_udev:
110 * @udev_queue: udev queue context
111 *
112 * Retrieve the udev library context the queue context was created with.
113 *
114 * Returns: the udev library context.
115 **/
116 UDEV_EXPORT struct udev *udev_queue_get_udev(struct udev_queue *udev_queue)
117 {
118 if (udev_queue == NULL)
119 return NULL;
120 return udev_queue->udev;
121 }
122
123 unsigned long long int udev_get_kernel_seqnum(struct udev *udev)
124 {
125 char filename[UTIL_PATH_SIZE];
126 unsigned long long int seqnum;
127 int fd;
128 char buf[32];
129 ssize_t len;
130
131 util_strscpyl(filename, sizeof(filename), udev_get_sys_path(udev), "/kernel/uevent_seqnum", NULL);
132 fd = open(filename, O_RDONLY|O_CLOEXEC);
133 if (fd < 0)
134 return 0;
135 len = read(fd, buf, sizeof(buf));
136 close(fd);
137 if (len <= 2)
138 return 0;
139 buf[len-1] = '\0';
140 seqnum = strtoull(buf, NULL, 10);
141 return seqnum;
142 }
143
144 /**
145 * udev_queue_get_kernel_seqnum:
146 * @udev_queue: udev queue context
147 *
148 * Get the current kernel event sequence number.
149 *
150 * Returns: the sequence number.
151 **/
152 UDEV_EXPORT unsigned long long int udev_queue_get_kernel_seqnum(struct udev_queue *udev_queue)
153 {
154 unsigned long long int seqnum;
155
156 if (udev_queue == NULL)
157 return -EINVAL;
158
159 seqnum = udev_get_kernel_seqnum(udev_queue->udev);
160 dbg(udev_queue->udev, "seqnum=%llu\n", seqnum);
161 return seqnum;
162 }
163
164 int udev_queue_read_seqnum(FILE *queue_file, unsigned long long int *seqnum)
165 {
166 if (fread(seqnum, sizeof(unsigned long long int), 1, queue_file) != 1)
167 return -1;
168
169 return 0;
170 }
171
172 ssize_t udev_queue_skip_devpath(FILE *queue_file)
173 {
174 unsigned short int len;
175
176 if (fread(&len, sizeof(unsigned short int), 1, queue_file) == 1) {
177 char *devpath = alloca(len);
178
179 /* use fread to skip, fseek might drop buffered data */
180 if (fread(devpath, 1, len, queue_file) == len)
181 return len;
182 }
183
184 return -1;
185 }
186
187 ssize_t udev_queue_read_devpath(FILE *queue_file, char *devpath, size_t size)
188 {
189 unsigned short int read_bytes = 0;
190 unsigned short int len;
191
192 if (fread(&len, sizeof(unsigned short int), 1, queue_file) != 1)
193 return -1;
194
195 read_bytes = (len < size - 1) ? len : size - 1;
196 if (fread(devpath, 1, read_bytes, queue_file) != read_bytes)
197 return -1;
198 devpath[read_bytes] = '\0';
199
200 /* if devpath was too long, skip unread characters */
201 if (read_bytes != len) {
202 unsigned short int skip_bytes = len - read_bytes;
203 char *buf = alloca(skip_bytes);
204
205 if (fread(buf, 1, skip_bytes, queue_file) != skip_bytes)
206 return -1;
207 }
208
209 return read_bytes;
210 }
211
212 static FILE *open_queue_file(struct udev_queue *udev_queue, unsigned long long int *seqnum_start)
213 {
214 char filename[UTIL_PATH_SIZE];
215 FILE *queue_file;
216
217 util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev_queue->udev), "/queue.bin", NULL);
218 queue_file = fopen(filename, "re");
219 if (queue_file == NULL)
220 return NULL;
221
222 if (udev_queue_read_seqnum(queue_file, seqnum_start) < 0) {
223 err(udev_queue->udev, "corrupt queue file\n");
224 fclose(queue_file);
225 return NULL;
226 }
227
228 return queue_file;
229 }
230
231 /**
232 * udev_queue_get_udev_seqnum:
233 * @udev_queue: udev queue context
234 *
235 * Get the last known udev event sequence number.
236 *
237 * Returns: the sequence number.
238 **/
239 UDEV_EXPORT unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *udev_queue)
240 {
241 unsigned long long int seqnum_udev;
242 FILE *queue_file;
243
244 queue_file = open_queue_file(udev_queue, &seqnum_udev);
245 if (queue_file == NULL)
246 return 0;
247
248 for (;;) {
249 unsigned long long int seqnum;
250 ssize_t devpath_len;
251
252 if (udev_queue_read_seqnum(queue_file, &seqnum) < 0)
253 break;
254 devpath_len = udev_queue_skip_devpath(queue_file);
255 if (devpath_len < 0)
256 break;
257 if (devpath_len > 0)
258 seqnum_udev = seqnum;
259 }
260
261 fclose(queue_file);
262 return seqnum_udev;
263 }
264
265 /**
266 * udev_queue_get_udev_is_active:
267 * @udev_queue: udev queue context
268 *
269 * Check if udev is active on the system.
270 *
271 * Returns: a flag indicating if udev is active.
272 **/
273 UDEV_EXPORT int udev_queue_get_udev_is_active(struct udev_queue *udev_queue)
274 {
275 unsigned long long int seqnum_start;
276 FILE *queue_file;
277
278 queue_file = open_queue_file(udev_queue, &seqnum_start);
279 if (queue_file == NULL)
280 return 0;
281
282 fclose(queue_file);
283 return 1;
284 }
285
286 /**
287 * udev_queue_get_queue_is_empty:
288 * @udev_queue: udev queue context
289 *
290 * Check if udev is currently processing any events.
291 *
292 * Returns: a flag indicating if udev is currently handling events.
293 **/
294 UDEV_EXPORT int udev_queue_get_queue_is_empty(struct udev_queue *udev_queue)
295 {
296 unsigned long long int seqnum_kernel;
297 unsigned long long int seqnum_udev = 0;
298 int queued = 0;
299 int is_empty = 0;
300 FILE *queue_file;
301
302 if (udev_queue == NULL)
303 return -EINVAL;
304 queue_file = open_queue_file(udev_queue, &seqnum_udev);
305 if (queue_file == NULL)
306 return 1;
307
308 for (;;) {
309 unsigned long long int seqnum;
310 ssize_t devpath_len;
311
312 if (udev_queue_read_seqnum(queue_file, &seqnum) < 0)
313 break;
314 devpath_len = udev_queue_skip_devpath(queue_file);
315 if (devpath_len < 0)
316 break;
317
318 if (devpath_len > 0) {
319 queued++;
320 seqnum_udev = seqnum;
321 } else {
322 queued--;
323 }
324 }
325
326 if (queued > 0) {
327 dbg(udev_queue->udev, "queue is not empty\n");
328 goto out;
329 }
330
331 seqnum_kernel = udev_queue_get_kernel_seqnum(udev_queue);
332 if (seqnum_udev < seqnum_kernel) {
333 dbg(udev_queue->udev, "queue is empty but kernel events still pending [%llu]<->[%llu]\n",
334 seqnum_kernel, seqnum_udev);
335 goto out;
336 }
337
338 dbg(udev_queue->udev, "queue is empty\n");
339 is_empty = 1;
340
341 out:
342 fclose(queue_file);
343 return is_empty;
344 }
345
346 /**
347 * udev_queue_get_seqnum_sequence_is_finished:
348 * @udev_queue: udev queue context
349 * @start: first event sequence number
350 * @end: last event sequence number
351 *
352 * Check if udev is currently processing any events in a given sequence number range.
353 *
354 * Returns: a flag indicating if any of the sequence numbers in the given range is currently active.
355 **/
356 UDEV_EXPORT int udev_queue_get_seqnum_sequence_is_finished(struct udev_queue *udev_queue,
357 unsigned long long int start, unsigned long long int end)
358 {
359 unsigned long long int seqnum;
360 ssize_t devpath_len;
361 int unfinished;
362 FILE *queue_file;
363
364 if (udev_queue == NULL)
365 return -EINVAL;
366 queue_file = open_queue_file(udev_queue, &seqnum);
367 if (queue_file == NULL)
368 return 1;
369 if (start < seqnum)
370 start = seqnum;
371 if (start > end) {
372 fclose(queue_file);
373 return 1;
374 }
375 if (end - start > INT_MAX - 1) {
376 fclose(queue_file);
377 return -EOVERFLOW;
378 }
379
380 /*
381 * we might start with 0, and handle the initial seqnum
382 * only when we find an entry in the queue file
383 **/
384 unfinished = end - start;
385
386 do {
387 if (udev_queue_read_seqnum(queue_file, &seqnum) < 0)
388 break;
389 devpath_len = udev_queue_skip_devpath(queue_file);
390 if (devpath_len < 0)
391 break;
392
393 /*
394 * we might start with an empty or re-build queue file, where
395 * the initial seqnum is not recorded as finished
396 */
397 if (start == seqnum && devpath_len > 0)
398 unfinished++;
399
400 if (devpath_len == 0) {
401 if (seqnum >= start && seqnum <= end)
402 unfinished--;
403 }
404 } while (unfinished > 0);
405
406 fclose(queue_file);
407
408 return (unfinished == 0);
409 }
410
411 /**
412 * udev_queue_get_seqnum_is_finished:
413 * @udev_queue: udev queue context
414 * @seqnum: sequence number
415 *
416 * Check if udev is currently processing a given sequence number.
417 *
418 * Returns: a flag indicating if the given sequence number is currently active.
419 **/
420 UDEV_EXPORT int udev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, unsigned long long int seqnum)
421 {
422 if (!udev_queue_get_seqnum_sequence_is_finished(udev_queue, seqnum, seqnum))
423 return 0;
424
425 dbg(udev_queue->udev, "seqnum: %llu finished\n", seqnum);
426 return 1;
427 }
428
429 /**
430 * udev_queue_get_queued_list_entry:
431 * @udev_queue: udev queue context
432 *
433 * Get the first entry of the list of queued events.
434 *
435 * Returns: a udev_list_entry.
436 **/
437 UDEV_EXPORT struct udev_list_entry *udev_queue_get_queued_list_entry(struct udev_queue *udev_queue)
438 {
439 unsigned long long int seqnum;
440 FILE *queue_file;
441
442 if (udev_queue == NULL)
443 return NULL;
444 udev_list_cleanup(&udev_queue->queue_list);
445
446 queue_file = open_queue_file(udev_queue, &seqnum);
447 if (queue_file == NULL)
448 return NULL;
449
450 for (;;) {
451 char syspath[UTIL_PATH_SIZE];
452 char *s;
453 size_t l;
454 ssize_t len;
455 char seqnum_str[32];
456 struct udev_list_entry *list_entry;
457
458 if (udev_queue_read_seqnum(queue_file, &seqnum) < 0)
459 break;
460 snprintf(seqnum_str, sizeof(seqnum_str), "%llu", seqnum);
461
462 s = syspath;
463 l = util_strpcpyl(&s, sizeof(syspath), udev_get_sys_path(udev_queue->udev), NULL);
464 len = udev_queue_read_devpath(queue_file, s, l);
465 if (len < 0)
466 break;
467
468 if (len > 0) {
469 udev_list_entry_add(&udev_queue->queue_list, syspath, seqnum_str);
470 } else {
471 udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_queue->queue_list)) {
472 if (strcmp(seqnum_str, udev_list_entry_get_value(list_entry)) == 0) {
473 udev_list_entry_delete(list_entry);
474 break;
475 }
476 }
477 }
478 }
479 fclose(queue_file);
480
481 return udev_list_get_entry(&udev_queue->queue_list);
482 }
483
484 struct udev_list_entry *udev_queue_get_failed_list_entry(struct udev_queue *udev_queue);
485 UDEV_EXPORT struct udev_list_entry *udev_queue_get_failed_list_entry(struct udev_queue *udev_queue)
486 {
487 errno = ENOSYS;
488 return NULL;
489 }
File src/libudev-util-private.c added (mode: 100644) (index 0000000..f764ab4)
1 /*
2 * libudev - interface to udev device information
3 *
4 * Copyright (C) 2003-2009 Kay Sievers <kay.sievers@vrfy.org>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 */
11
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include <stddef.h>
15 #include <unistd.h>
16 #include <string.h>
17 #include <fcntl.h>
18 #include <errno.h>
19 #include <ctype.h>
20 #include <pwd.h>
21 #include <grp.h>
22 #include <sys/param.h>
23
24 #include "libudev.h"
25 #include "libudev-private.h"
26
27 static int create_path(struct udev *udev, const char *path, bool selinux)
28 {
29 char p[UTIL_PATH_SIZE];
30 char *pos;
31 struct stat stats;
32 int err;
33
34 util_strscpy(p, sizeof(p), path);
35 pos = strrchr(p, '/');
36 if (pos == NULL)
37 return 0;
38 while (pos != p && pos[-1] == '/')
39 pos--;
40 if (pos == p)
41 return 0;
42 pos[0] = '\0';
43
44 dbg(udev, "stat '%s'\n", p);
45 if (stat(p, &stats) == 0) {
46 if ((stats.st_mode & S_IFMT) == S_IFDIR)
47 return 0;
48 else
49 return -ENOTDIR;
50 }
51
52 err = util_create_path(udev, p);
53 if (err != 0)
54 return err;
55
56 dbg(udev, "mkdir '%s'\n", p);
57 if (selinux)
58 udev_selinux_setfscreatecon(udev, p, S_IFDIR|0755);
59 err = mkdir(p, 0755);
60 if (err != 0) {
61 err = -errno;
62 if (err == -EEXIST && stat(p, &stats) == 0) {
63 if ((stats.st_mode & S_IFMT) == S_IFDIR)
64 err = 0;
65 else
66 err = -ENOTDIR;
67 }
68 }
69 if (selinux)
70 udev_selinux_resetfscreatecon(udev);
71 return err;
72 }
73
74 int util_create_path(struct udev *udev, const char *path)
75 {
76 return create_path(udev, path, false);
77 }
78
79 int util_create_path_selinux(struct udev *udev, const char *path)
80 {
81 return create_path(udev, path, true);
82 }
83
84 int util_delete_path(struct udev *udev, const char *path)
85 {
86 char p[UTIL_PATH_SIZE];
87 char *pos;
88 int err = 0;
89
90 if (path[0] == '/')
91 while(path[1] == '/')
92 path++;
93 util_strscpy(p, sizeof(p), path);
94 pos = strrchr(p, '/');
95 if (pos == p || pos == NULL)
96 return 0;
97
98 for (;;) {
99 *pos = '\0';
100 pos = strrchr(p, '/');
101
102 /* don't remove the last one */
103 if ((pos == p) || (pos == NULL))
104 break;
105
106 err = rmdir(p);
107 if (err < 0) {
108 if (errno == ENOENT)
109 err = 0;
110 break;
111 }
112 }
113 return err;
114 }
115
116 uid_t util_lookup_user(struct udev *udev, const char *user)
117 {
118 char *endptr;
119 struct passwd pwbuf;
120 struct passwd *pw;
121 uid_t uid;
122 size_t buflen = sysconf(_SC_GETPW_R_SIZE_MAX);
123 char *buf = alloca(buflen);
124
125 if (strcmp(user, "root") == 0)
126 return 0;
127 uid = strtoul(user, &endptr, 10);
128 if (endptr[0] == '\0')
129 return uid;
130
131 errno = getpwnam_r(user, &pwbuf, buf, buflen, &pw);
132 if (pw != NULL)
133 return pw->pw_uid;
134 if (errno == 0 || errno == ENOENT || errno == ESRCH)
135 err(udev, "specified user '%s' unknown\n", user);
136 else
137 err(udev, "error resolving user '%s': %m\n", user);
138 return 0;
139 }
140
141 gid_t util_lookup_group(struct udev *udev, const char *group)
142 {
143 char *endptr;
144 struct group grbuf;
145 struct group *gr;
146 gid_t gid = 0;
147 size_t buflen = sysconf(_SC_GETPW_R_SIZE_MAX);
148 char *buf = alloca(buflen);
149
150 if (strcmp(group, "root") == 0)
151 return 0;
152 gid = strtoul(group, &endptr, 10);
153 if (endptr[0] == '\0')
154 return gid;
155 buf = NULL;
156 gid = 0;
157 for (;;) {
158 char *newbuf;
159
160 newbuf = realloc(buf, buflen);
161 if (!newbuf)
162 break;
163 buf = newbuf;
164 errno = getgrnam_r(group, &grbuf, buf, buflen, &gr);
165 if (gr != NULL) {
166 gid = gr->gr_gid;
167 } else if (errno == ERANGE) {
168 buflen *= 2;
169 continue;
170 } else if (errno == 0 || errno == ENOENT || errno == ESRCH) {
171 err(udev, "specified group '%s' unknown\n", group);
172 } else {
173 err(udev, "error resolving group '%s': %m\n", group);
174 }
175 break;
176 }
177 free(buf);
178 return gid;
179 }
180
181 /* handle "[<SUBSYSTEM>/<KERNEL>]<attribute>" format */
182 int util_resolve_subsys_kernel(struct udev *udev, const char *string,
183 char *result, size_t maxsize, int read_value)
184 {
185 char temp[UTIL_PATH_SIZE];
186 char *subsys;
187 char *sysname;
188 struct udev_device *dev;
189 char *attr;
190
191 if (string[0] != '[')
192 return -1;
193
194 util_strscpy(temp, sizeof(temp), string);
195
196 subsys = &temp[1];
197
198 sysname = strchr(subsys, '/');
199 if (sysname == NULL)
200 return -1;
201 sysname[0] = '\0';
202 sysname = &sysname[1];
203
204 attr = strchr(sysname, ']');
205 if (attr == NULL)
206 return -1;
207 attr[0] = '\0';
208 attr = &attr[1];
209 if (attr[0] == '/')
210 attr = &attr[1];
211 if (attr[0] == '\0')
212 attr = NULL;
213
214 if (read_value && attr == NULL)
215 return -1;
216
217 dev = udev_device_new_from_subsystem_sysname(udev, subsys, sysname);
218 if (dev == NULL)
219 return -1;
220
221 if (read_value) {
222 const char *val;
223
224 val = udev_device_get_sysattr_value(dev, attr);
225 if (val != NULL)
226 util_strscpy(result, maxsize, val);
227 else
228 result[0] = '\0';
229 info(udev, "value '[%s/%s]%s' is '%s'\n", subsys, sysname, attr, result);
230 } else {
231 size_t l;
232 char *s;
233
234 s = result;
235 l = util_strpcpyl(&s, maxsize, udev_device_get_syspath(dev), NULL);
236 if (attr != NULL)
237 util_strpcpyl(&s, l, "/", attr, NULL);
238 info(udev, "path '[%s/%s]%s' is '%s'\n", subsys, sysname, attr, result);
239 }
240 udev_device_unref(dev);
241 return 0;
242 }
File src/libudev-util.c added (mode: 100644) (index 0000000..b0ee33e)
1 /*
2 * libudev - interface to udev device information
3 *
4 * Copyright (C) 2008-2011 Kay Sievers <kay.sievers@vrfy.org>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 */
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <stddef.h>
15 #include <unistd.h>
16 #include <errno.h>
17 #include <string.h>
18 #include <dirent.h>
19 #include <ctype.h>
20 #include <fcntl.h>
21 #include <time.h>
22 #include <sys/stat.h>
23
24 #include "libudev.h"
25 #include "libudev-private.h"
26
27 /**
28 * SECTION:libudev-util
29 * @short_description: utils
30 */
31
32 ssize_t util_get_sys_core_link_value(struct udev *udev, const char *slink, const char *syspath, char *value, size_t size)
33 {
34 char path[UTIL_PATH_SIZE];
35 char target[UTIL_PATH_SIZE];
36 ssize_t len;
37 const char *pos;
38
39 util_strscpyl(path, sizeof(path), syspath, "/", slink, NULL);
40 len = readlink(path, target, sizeof(target));
41 if (len <= 0 || len == (ssize_t)sizeof(target))
42 return -1;
43 target[len] = '\0';
44 pos = strrchr(target, '/');
45 if (pos == NULL)
46 return -1;
47 pos = &pos[1];
48 dbg(udev, "resolved link to: '%s'\n", pos);
49 return util_strscpy(value, size, pos);
50 }
51
52 int util_resolve_sys_link(struct udev *udev, char *syspath, size_t size)
53 {
54 char link_target[UTIL_PATH_SIZE];
55
56 ssize_t len;
57 int i;
58 int back;
59 char *base = NULL;
60
61 len = readlink(syspath, link_target, sizeof(link_target));
62 if (len <= 0 || len == (ssize_t)sizeof(link_target))
63 return -1;
64 link_target[len] = '\0';
65 dbg(udev, "path link '%s' points to '%s'\n", syspath, link_target);
66
67 for (back = 0; strncmp(&link_target[back * 3], "../", 3) == 0; back++)
68 ;
69 dbg(udev, "base '%s', tail '%s', back %i\n", syspath, &link_target[back * 3], back);
70 for (i = 0; i <= back; i++) {
71 base = strrchr(syspath, '/');
72 if (base == NULL)
73 return -EINVAL;
74 base[0] = '\0';
75 }
76 if (base == NULL)
77 return -EINVAL;
78 dbg(udev, "after moving back '%s'\n", syspath);
79 util_strscpyl(base, size - (base - syspath), "/", &link_target[back * 3], NULL);
80 return 0;
81 }
82
83 int util_log_priority(const char *priority)
84 {
85 char *endptr;
86 int prio;
87
88 prio = strtol(priority, &endptr, 10);
89 if (endptr[0] == '\0' || isspace(endptr[0]))
90 return prio;
91 if (strncmp(priority, "err", 3) == 0)
92 return LOG_ERR;
93 if (strncmp(priority, "info", 4) == 0)
94 return LOG_INFO;
95 if (strncmp(priority, "debug", 5) == 0)
96 return LOG_DEBUG;
97 return 0;
98 }
99
100 size_t util_path_encode(const char *src, char *dest, size_t size)
101 {
102 size_t i, j;
103
104 for (i = 0, j = 0; src[i] != '\0'; i++) {
105 if (src[i] == '/') {
106 if (j+4 >= size) {
107 j = 0;
108 break;
109 }
110 memcpy(&dest[j], "\\x2f", 4);
111 j += 4;
112 } else if (src[i] == '\\') {
113 if (j+4 >= size) {
114 j = 0;
115 break;
116 }
117 memcpy(&dest[j], "\\x5c", 4);
118 j += 4;
119 } else {
120 if (j+1 >= size) {
121 j = 0;
122 break;
123 }
124 dest[j] = src[i];
125 j++;
126 }
127 }
128 dest[j] = '\0';
129 return j;
130 }
131
132 size_t util_path_decode(char *s)
133 {
134 size_t i, j;
135
136 for (i = 0, j = 0; s[i] != '\0'; j++) {
137 if (memcmp(&s[i], "\\x2f", 4) == 0) {
138 s[j] = '/';
139 i += 4;
140 } else if (memcmp(&s[i], "\\x5c", 4) == 0) {
141 s[j] = '\\';
142 i += 4;
143 } else {
144 s[j] = s[i];
145 i++;
146 }
147 }
148 s[j] = '\0';
149 return j;
150 }
151
152 void util_remove_trailing_chars(char *path, char c)
153 {
154 size_t len;
155
156 if (path == NULL)
157 return;
158 len = strlen(path);
159 while (len > 0 && path[len-1] == c)
160 path[--len] = '\0';
161 }
162
163 /*
164 * Concatenates strings. In any case, terminates in _all_ cases with '\0'
165 * and moves the @dest pointer forward to the added '\0'. Returns the
166 * remaining size, and 0 if the string was truncated.
167 */
168 size_t util_strpcpy(char **dest, size_t size, const char *src)
169 {
170 size_t len;
171
172 len = strlen(src);
173 if (len >= size) {
174 if (size > 1)
175 *dest = mempcpy(*dest, src, size-1);
176 size = 0;
177 *dest[0] = '\0';
178 } else {
179 if (len > 0) {
180 *dest = mempcpy(*dest, src, len);
181 size -= len;
182 }
183 *dest[0] = '\0';
184 }
185 return size;
186 }
187
188 /* concatenates list of strings, moves dest forward */
189 size_t util_strpcpyl(char **dest, size_t size, const char *src, ...)
190 {
191 va_list va;
192
193 va_start(va, src);
194 do {
195 size = util_strpcpy(dest, size, src);
196 src = va_arg(va, char *);
197 } while (src != NULL);
198 va_end(va);
199
200 return size;
201 }
202
203 /* copies string */
204 size_t util_strscpy(char *dest, size_t size, const char *src)
205 {
206 char *s;
207
208 s = dest;
209 return util_strpcpy(&s, size, src);
210 }
211
212 /* concatenates list of strings */
213 size_t util_strscpyl(char *dest, size_t size, const char *src, ...)
214 {
215 va_list va;
216 char *s;
217
218 va_start(va, src);
219 s = dest;
220 do {
221 size = util_strpcpy(&s, size, src);
222 src = va_arg(va, char *);
223 } while (src != NULL);
224 va_end(va);
225
226 return size;
227 }
228
229 /* count of characters used to encode one unicode char */
230 static int utf8_encoded_expected_len(const char *str)
231 {
232 unsigned char c = (unsigned char)str[0];
233
234 if (c < 0x80)
235 return 1;
236 if ((c & 0xe0) == 0xc0)
237 return 2;
238 if ((c & 0xf0) == 0xe0)
239 return 3;
240 if ((c & 0xf8) == 0xf0)
241 return 4;
242 if ((c & 0xfc) == 0xf8)
243 return 5;
244 if ((c & 0xfe) == 0xfc)
245 return 6;
246 return 0;
247 }
248
249 /* decode one unicode char */
250 static int utf8_encoded_to_unichar(const char *str)
251 {
252 int unichar;
253 int len;
254 int i;
255
256 len = utf8_encoded_expected_len(str);
257 switch (len) {
258 case 1:
259 return (int)str[0];
260 case 2:
261 unichar = str[0] & 0x1f;
262 break;
263 case 3:
264 unichar = (int)str[0] & 0x0f;
265 break;
266 case 4:
267 unichar = (int)str[0] & 0x07;
268 break;
269 case 5:
270 unichar = (int)str[0] & 0x03;
271 break;
272 case 6:
273 unichar = (int)str[0] & 0x01;
274 break;
275 default:
276 return -1;
277 }
278
279 for (i = 1; i < len; i++) {
280 if (((int)str[i] & 0xc0) != 0x80)
281 return -1;
282 unichar <<= 6;
283 unichar |= (int)str[i] & 0x3f;
284 }
285
286 return unichar;
287 }
288
289 /* expected size used to encode one unicode char */
290 static int utf8_unichar_to_encoded_len(int unichar)
291 {
292 if (unichar < 0x80)
293 return 1;
294 if (unichar < 0x800)
295 return 2;
296 if (unichar < 0x10000)
297 return 3;
298 if (unichar < 0x200000)
299 return 4;
300 if (unichar < 0x4000000)
301 return 5;
302 return 6;
303 }
304
305 /* check if unicode char has a valid numeric range */
306 static int utf8_unichar_valid_range(int unichar)
307 {
308 if (unichar > 0x10ffff)
309 return 0;
310 if ((unichar & 0xfffff800) == 0xd800)
311 return 0;
312 if ((unichar > 0xfdcf) && (unichar < 0xfdf0))
313 return 0;
314 if ((unichar & 0xffff) == 0xffff)
315 return 0;
316 return 1;
317 }
318
319 /* validate one encoded unicode char and return its length */
320 static int utf8_encoded_valid_unichar(const char *str)
321 {
322 int len;
323 int unichar;
324 int i;
325
326 len = utf8_encoded_expected_len(str);
327 if (len == 0)
328 return -1;
329
330 /* ascii is valid */
331 if (len == 1)
332 return 1;
333
334 /* check if expected encoded chars are available */
335 for (i = 0; i < len; i++)
336 if ((str[i] & 0x80) != 0x80)
337 return -1;
338
339 unichar = utf8_encoded_to_unichar(str);
340
341 /* check if encoded length matches encoded value */
342 if (utf8_unichar_to_encoded_len(unichar) != len)
343 return -1;
344
345 /* check if value has valid range */
346 if (!utf8_unichar_valid_range(unichar))
347 return -1;
348
349 return len;
350 }
351
352 int util_replace_whitespace(const char *str, char *to, size_t len)
353 {
354 size_t i, j;
355
356 /* strip trailing whitespace */
357 len = strnlen(str, len);
358 while (len && isspace(str[len-1]))
359 len--;
360
361 /* strip leading whitespace */
362 i = 0;
363 while (isspace(str[i]) && (i < len))
364 i++;
365
366 j = 0;
367 while (i < len) {
368 /* substitute multiple whitespace with a single '_' */
369 if (isspace(str[i])) {
370 while (isspace(str[i]))
371 i++;
372 to[j++] = '_';
373 }
374 to[j++] = str[i++];
375 }
376 to[j] = '\0';
377 return 0;
378 }
379
380 static int is_whitelisted(char c, const char *white)
381 {
382 if ((c >= '0' && c <= '9') ||
383 (c >= 'A' && c <= 'Z') ||
384 (c >= 'a' && c <= 'z') ||
385 strchr("#+-.:=@_", c) != NULL ||
386 (white != NULL && strchr(white, c) != NULL))
387 return 1;
388 return 0;
389 }
390
391 /* allow chars in whitelist, plain ascii, hex-escaping and valid utf8 */
392 int util_replace_chars(char *str, const char *white)
393 {
394 size_t i = 0;
395 int replaced = 0;
396
397 while (str[i] != '\0') {
398 int len;
399
400 if (is_whitelisted(str[i], white)) {
401 i++;
402 continue;
403 }
404
405 /* accept hex encoding */
406 if (str[i] == '\\' && str[i+1] == 'x') {
407 i += 2;
408 continue;
409 }
410
411 /* accept valid utf8 */
412 len = utf8_encoded_valid_unichar(&str[i]);
413 if (len > 1) {
414 i += len;
415 continue;
416 }
417
418 /* if space is allowed, replace whitespace with ordinary space */
419 if (isspace(str[i]) && white != NULL && strchr(white, ' ') != NULL) {
420 str[i] = ' ';
421 i++;
422 replaced++;
423 continue;
424 }
425
426 /* everything else is replaced with '_' */
427 str[i] = '_';
428 i++;
429 replaced++;
430 }
431 return replaced;
432 }
433
434 /**
435 * udev_util_encode_string:
436 * @str: input string to be encoded
437 * @str_enc: output string to store the encoded input string
438 * @len: maximum size of the output string, which may be
439 * four times as long as the input string
440 *
441 * Encode all potentially unsafe characters of a string to the
442 * corresponding 2 char hex value prefixed by '\x'.
443 *
444 * Returns: 0 if the entire string was copied, non-zero otherwise.
445 **/
446 UDEV_EXPORT int udev_util_encode_string(const char *str, char *str_enc, size_t len)
447 {
448 size_t i, j;
449
450 if (str == NULL || str_enc == NULL)
451 return -1;
452
453 for (i = 0, j = 0; str[i] != '\0'; i++) {
454 int seqlen;
455
456 seqlen = utf8_encoded_valid_unichar(&str[i]);
457 if (seqlen > 1) {
458 if (len-j < (size_t)seqlen)
459 goto err;
460 memcpy(&str_enc[j], &str[i], seqlen);
461 j += seqlen;
462 i += (seqlen-1);
463 } else if (str[i] == '\\' || !is_whitelisted(str[i], NULL)) {
464 if (len-j < 4)
465 goto err;
466 sprintf(&str_enc[j], "\\x%02x", (unsigned char) str[i]);
467 j += 4;
468 } else {
469 if (len-j < 1)
470 goto err;
471 str_enc[j] = str[i];
472 j++;
473 }
474 }
475 if (len-j < 1)
476 goto err;
477 str_enc[j] = '\0';
478 return 0;
479 err:
480 return -1;
481 }
482
483 /*
484 * http://sites.google.com/site/murmurhash/
485 *
486 * All code is released to the public domain. For business purposes,
487 * Murmurhash is under the MIT license.
488 *
489 */
490 static unsigned int murmur_hash2(const char *key, int len, unsigned int seed)
491 {
492 /*
493 * 'm' and 'r' are mixing constants generated offline.
494 * They're not really 'magic', they just happen to work well.
495 */
496 const unsigned int m = 0x5bd1e995;
497 const int r = 24;
498
499 /* initialize the hash to a 'random' value */
500 unsigned int h = seed ^ len;
501
502 /* mix 4 bytes at a time into the hash */
503 const unsigned char * data = (const unsigned char *)key;
504
505 while(len >= 4) {
506 unsigned int k = *(unsigned int *)data;
507
508 k *= m;
509 k ^= k >> r;
510 k *= m;
511 h *= m;
512 h ^= k;
513
514 data += 4;
515 len -= 4;
516 }
517
518 /* handle the last few bytes of the input array */
519 switch(len) {
520 case 3:
521 h ^= data[2] << 16;
522 case 2:
523 h ^= data[1] << 8;
524 case 1:
525 h ^= data[0];
526 h *= m;
527 };
528
529 /* do a few final mixes of the hash to ensure the last few bytes are well-incorporated */
530 h ^= h >> 13;
531 h *= m;
532 h ^= h >> 15;
533
534 return h;
535 }
536
537 unsigned int util_string_hash32(const char *str)
538 {
539 return murmur_hash2(str, strlen(str), 0);
540 }
541
542 /* get a bunch of bit numbers out of the hash, and set the bits in our bit field */
543 uint64_t util_string_bloom64(const char *str)
544 {
545 uint64_t bits = 0;
546 unsigned int hash = util_string_hash32(str);
547
548 bits |= 1LLU << (hash & 63);
549 bits |= 1LLU << ((hash >> 6) & 63);
550 bits |= 1LLU << ((hash >> 12) & 63);
551 bits |= 1LLU << ((hash >> 18) & 63);
552 return bits;
553 }
554
555 #define USEC_PER_SEC 1000000ULL
556 #define NSEC_PER_USEC 1000ULL
557 unsigned long long ts_usec(const struct timespec *ts)
558 {
559 return (unsigned long long) ts->tv_sec * USEC_PER_SEC +
560 (unsigned long long) ts->tv_nsec / NSEC_PER_USEC;
561 }
562
563 unsigned long long now_usec(void)
564 {
565 struct timespec ts;
566
567 if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0)
568 return 0;
569 return ts_usec(&ts);
570 }
571
572 ssize_t print_kmsg(const char *fmt, ...)
573 {
574 int fd;
575 va_list ap;
576 char text[1024];
577 ssize_t len;
578 ssize_t ret;
579
580 fd = open("/dev/kmsg", O_WRONLY|O_NOCTTY|O_CLOEXEC);
581 if (fd < 0)
582 return -errno;
583
584 len = snprintf(text, sizeof(text), "<30>udevd[%u]: ", getpid());
585
586 va_start(ap, fmt);
587 len += vsnprintf(text + len, sizeof(text) - len, fmt, ap);
588 va_end(ap);
589
590 ret = write(fd, text, len);
591 if (ret < 0)
592 ret = -errno;
593 close(fd);
594 return ret;
595 }
File src/libudev.c added (mode: 100644) (index 0000000..9443a88)
1 /*
2 * libudev - interface to udev device information
3 *
4 * Copyright (C) 2008-2010 Kay Sievers <kay.sievers@vrfy.org>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 */
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <stddef.h>
15 #include <stdarg.h>
16 #include <unistd.h>
17 #include <errno.h>
18 #include <string.h>
19 #include <ctype.h>
20 #include <time.h>
21
22 #include "libudev.h"
23 #include "libudev-private.h"
24
25 /**
26 * SECTION:libudev
27 * @short_description: libudev context
28 *
29 * The context contains the default values read from the udev config file,
30 * and is passed to all library operations.
31 */
32
33 /**
34 * udev:
35 *
36 * Opaque object representing the library context.
37 */
38 struct udev {
39 int refcount;
40 void (*log_fn)(struct udev *udev,
41 int priority, const char *file, int line, const char *fn,
42 const char *format, va_list args);
43 void *userdata;
44 char *sys_path;
45 char *dev_path;
46 char *rules_path[4];
47 unsigned long long rules_path_ts[4];
48 int rules_path_count;
49 char *run_path;
50 struct udev_list properties_list;
51 int log_priority;
52 };
53
54 void udev_log(struct udev *udev,
55 int priority, const char *file, int line, const char *fn,
56 const char *format, ...)
57 {
58 va_list args;
59
60 va_start(args, format);
61 udev->log_fn(udev, priority, file, line, fn, format, args);
62 va_end(args);
63 }
64
65 static void log_stderr(struct udev *udev,
66 int priority, const char *file, int line, const char *fn,
67 const char *format, va_list args)
68 {
69 fprintf(stderr, "libudev: %s: ", fn);
70 vfprintf(stderr, format, args);
71 }
72
73 /**
74 * udev_get_userdata:
75 * @udev: udev library context
76 *
77 * Retrieve stored data pointer from library context. This might be useful
78 * to access from callbacks like a custom logging function.
79 *
80 * Returns: stored userdata
81 **/
82 UDEV_EXPORT void *udev_get_userdata(struct udev *udev)
83 {
84 if (udev == NULL)
85 return NULL;
86 return udev->userdata;
87 }
88
89 /**
90 * udev_set_userdata:
91 * @udev: udev library context
92 * @userdata: data pointer
93 *
94 * Store custom @userdata in the library context.
95 **/
96 UDEV_EXPORT void udev_set_userdata(struct udev *udev, void *userdata)
97 {
98 if (udev == NULL)
99 return;
100 udev->userdata = userdata;
101 }
102
103 static char *set_value(char **s, const char *v)
104 {
105 free(*s);
106 *s = strdup(v);
107 util_remove_trailing_chars(*s, '/');
108 return *s;
109 }
110
111 /**
112 * udev_new:
113 *
114 * Create udev library context. This reads the udev configuration
115 * file, and fills in the default values.
116 *
117 * The initial refcount is 1, and needs to be decremented to
118 * release the resources of the udev library context.
119 *
120 * Returns: a new udev library context
121 **/
122 UDEV_EXPORT struct udev *udev_new(void)
123 {
124 struct udev *udev;
125 const char *env;
126 char *config_file = NULL;
127 FILE *f;
128
129 udev = calloc(1, sizeof(struct udev));
130 if (udev == NULL)
131 return NULL;
132 udev->refcount = 1;
133 udev->log_fn = log_stderr;
134 udev->log_priority = LOG_ERR;
135 udev_list_init(udev, &udev->properties_list, true);
136
137 /* custom config file */
138 env = getenv("UDEV_CONFIG_FILE");
139 if (env != NULL) {
140 if (set_value(&config_file, env) == NULL)
141 goto err;
142 udev_add_property(udev, "UDEV_CONFIG_FILE", config_file);
143 }
144
145 /* default config file */
146 if (config_file == NULL)
147 config_file = strdup(SYSCONFDIR "/udev/udev.conf");
148 if (config_file == NULL)
149 goto err;
150
151 f = fopen(config_file, "re");
152 if (f != NULL) {
153 char line[UTIL_LINE_SIZE];
154 int line_nr = 0;
155
156 while (fgets(line, sizeof(line), f)) {
157 size_t len;
158 char *key;
159 char *val;
160
161 line_nr++;
162
163 /* find key */
164 key = line;
165 while (isspace(key[0]))
166 key++;
167
168 /* comment or empty line */
169 if (key[0] == '#' || key[0] == '\0')
170 continue;
171
172 /* split key/value */
173 val = strchr(key, '=');
174 if (val == NULL) {
175 err(udev, "missing <key>=<value> in '%s'[%i], skip line\n", config_file, line_nr);
176 continue;
177 }
178 val[0] = '\0';
179 val++;
180
181 /* find value */
182 while (isspace(val[0]))
183 val++;
184
185 /* terminate key */
186 len = strlen(key);
187 if (len == 0)
188 continue;
189 while (isspace(key[len-1]))
190 len--;
191 key[len] = '\0';
192
193 /* terminate value */
194 len = strlen(val);
195 if (len == 0)
196 continue;
197 while (isspace(val[len-1]))
198 len--;
199 val[len] = '\0';
200
201 if (len == 0)
202 continue;
203
204 /* unquote */
205 if (val[0] == '"' || val[0] == '\'') {
206 if (val[len-1] != val[0]) {
207 err(udev, "inconsistent quoting in '%s'[%i], skip line\n", config_file, line_nr);
208 continue;
209 }
210 val[len-1] = '\0';
211 val++;
212 }
213
214 if (strcmp(key, "udev_log") == 0) {
215 udev_set_log_priority(udev, util_log_priority(val));
216 continue;
217 }
218 if (strcmp(key, "udev_root") == 0) {
219 set_value(&udev->dev_path, val);
220 continue;
221 }
222 if (strcmp(key, "udev_run") == 0) {
223 set_value(&udev->run_path, val);
224 continue;
225 }
226 if (strcmp(key, "udev_sys") == 0) {
227 set_value(&udev->sys_path, val);
228 continue;
229 }
230 if (strcmp(key, "udev_rules") == 0) {
231 set_value(&udev->rules_path[0], val);
232 udev->rules_path_count = 1;
233 continue;
234 }
235 }
236 fclose(f);
237 }
238
239 /* environment overrides config */
240 env = getenv("UDEV_LOG");
241 if (env != NULL)
242 udev_set_log_priority(udev, util_log_priority(env));
243
244 /* set defaults */
245 if (udev->dev_path == NULL)
246 if (set_value(&udev->dev_path, "/dev") == NULL)
247 goto err;
248
249 if (udev->sys_path == NULL)
250 if (set_value(&udev->sys_path, "/sys") == NULL)
251 goto err;
252
253 if (udev->run_path == NULL)
254 if (set_value(&udev->run_path, "/run/udev") == NULL)
255 goto err;
256
257 if (udev->rules_path[0] == NULL) {
258 /* /usr/lib/udev -- system rules */
259 udev->rules_path[0] = strdup(PKGLIBEXECDIR "/rules.d");
260 if (!udev->rules_path[0])
261 goto err;
262
263 /* /run/udev -- runtime rules */
264 if (asprintf(&udev->rules_path[1], "%s/rules.d", udev->run_path) < 0)
265 goto err;
266
267 /* /etc/udev -- local administration rules */
268 udev->rules_path[2] = strdup(SYSCONFDIR "/udev/rules.d");
269 if (!udev->rules_path[2])
270 goto err;
271
272 udev->rules_path_count = 3;
273 }
274
275 dbg(udev, "context %p created\n", udev);
276 dbg(udev, "log_priority=%d\n", udev->log_priority);
277 dbg(udev, "config_file='%s'\n", config_file);
278 dbg(udev, "dev_path='%s'\n", udev->dev_path);
279 dbg(udev, "sys_path='%s'\n", udev->sys_path);
280 dbg(udev, "run_path='%s'\n", udev->run_path);
281 dbg(udev, "rules_path='%s':'%s':'%s'\n", udev->rules_path[0], udev->rules_path[1], udev->rules_path[2]);
282 free(config_file);
283 return udev;
284 err:
285 free(config_file);
286 err(udev, "context creation failed\n");
287 udev_unref(udev);
288 return NULL;
289 }
290
291 /**
292 * udev_ref:
293 * @udev: udev library context
294 *
295 * Take a reference of the udev library context.
296 *
297 * Returns: the passed udev library context
298 **/
299 UDEV_EXPORT struct udev *udev_ref(struct udev *udev)
300 {
301 if (udev == NULL)
302 return NULL;
303 udev->refcount++;
304 return udev;
305 }
306
307 /**
308 * udev_unref:
309 * @udev: udev library context
310 *
311 * Drop a reference of the udev library context. If the refcount
312 * reaches zero, the resources of the context will be released.
313 *
314 **/
315 UDEV_EXPORT struct udev *udev_unref(struct udev *udev)
316 {
317 if (udev == NULL)
318 return NULL;
319 udev->refcount--;
320 if (udev->refcount > 0)
321 return udev;
322 udev_list_cleanup(&udev->properties_list);
323 free(udev->dev_path);
324 free(udev->sys_path);
325 free(udev->rules_path[0]);
326 free(udev->rules_path[1]);
327 free(udev->rules_path[2]);
328 free(udev->run_path);
329 dbg(udev, "context %p released\n", udev);
330 free(udev);
331 return NULL;
332 }
333
334 /**
335 * udev_set_log_fn:
336 * @udev: udev library context
337 * @log_fn: function to be called for logging messages
338 *
339 * The built-in logging writes to stderr. It can be
340 * overridden by a custom function, to plug log messages
341 * into the users' logging functionality.
342 *
343 **/
344 UDEV_EXPORT void udev_set_log_fn(struct udev *udev,
345 void (*log_fn)(struct udev *udev,
346 int priority, const char *file, int line, const char *fn,
347 const char *format, va_list args))
348 {
349 udev->log_fn = log_fn;
350 info(udev, "custom logging function %p registered\n", log_fn);
351 }
352
353 /**
354 * udev_get_log_priority:
355 * @udev: udev library context
356 *
357 * The initial logging priority is read from the udev config file
358 * at startup.
359 *
360 * Returns: the current logging priority
361 **/
362 UDEV_EXPORT int udev_get_log_priority(struct udev *udev)
363 {
364 return udev->log_priority;
365 }
366
367 /**
368 * udev_set_log_priority:
369 * @udev: udev library context
370 * @priority: the new logging priority
371 *
372 * Set the current logging priority. The value controls which messages
373 * are logged.
374 **/
375 UDEV_EXPORT void udev_set_log_priority(struct udev *udev, int priority)
376 {
377 char num[32];
378
379 udev->log_priority = priority;
380 snprintf(num, sizeof(num), "%u", udev->log_priority);
381 udev_add_property(udev, "UDEV_LOG", num);
382 }
383
384 int udev_get_rules_path(struct udev *udev, char **path[], unsigned long long *stamp_usec[])
385 {
386 *path = udev->rules_path;
387 if (stamp_usec)
388 *stamp_usec = udev->rules_path_ts;
389 return udev->rules_path_count;
390 }
391
392 /**
393 * udev_get_sys_path:
394 * @udev: udev library context
395 *
396 * Retrieve the sysfs mount point. The default is "/sys". For
397 * testing purposes, it can be overridden with udev_sys=
398 * in the udev configuration file.
399 *
400 * Returns: the sys mount point
401 **/
402 UDEV_EXPORT const char *udev_get_sys_path(struct udev *udev)
403 {
404 if (udev == NULL)
405 return NULL;
406 return udev->sys_path;
407 }
408
409 /**
410 * udev_get_dev_path:
411 * @udev: udev library context
412 *
413 * Retrieve the device directory path. The default value is "/dev",
414 * the actual value may be overridden in the udev configuration
415 * file.
416 *
417 * Returns: the device directory path
418 **/
419 UDEV_EXPORT const char *udev_get_dev_path(struct udev *udev)
420 {
421 if (udev == NULL)
422 return NULL;
423 return udev->dev_path;
424 }
425
426 /**
427 * udev_get_run_path:
428 * @udev: udev library context
429 *
430 * Retrieve the udev runtime directory path. The default is "/run/udev".
431 *
432 * Returns: the runtime directory path
433 **/
434 UDEV_EXPORT const char *udev_get_run_path(struct udev *udev)
435 {
436 if (udev == NULL)
437 return NULL;
438 return udev->run_path;
439 }
440
441 struct udev_list_entry *udev_add_property(struct udev *udev, const char *key, const char *value)
442 {
443 if (value == NULL) {
444 struct udev_list_entry *list_entry;
445
446 list_entry = udev_get_properties_list_entry(udev);
447 list_entry = udev_list_entry_get_by_name(list_entry, key);
448 if (list_entry != NULL)
449 udev_list_entry_delete(list_entry);
450 return NULL;
451 }
452 return udev_list_entry_add(&udev->properties_list, key, value);
453 }
454
455 struct udev_list_entry *udev_get_properties_list_entry(struct udev *udev)
456 {
457 return udev_list_get_entry(&udev->properties_list);
458 }
File src/libudev.h added (mode: 100644) (index 0000000..dc75133)
1 /*
2 * libudev - interface to udev device information
3 *
4 * Copyright (C) 2008-2011 Kay Sievers <kay.sievers@vrfy.org>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 */
11
12 #ifndef _LIBUDEV_H_
13 #define _LIBUDEV_H_
14
15 #include <stdarg.h>
16 #include <sys/types.h>
17 #include <sys/stat.h>
18
19 #ifdef __cplusplus
20 extern "C" {
21 #endif
22
23 /*
24 * udev - library context
25 *
26 * reads the udev config and system environment
27 * allows custom logging
28 */
29 struct udev;
30 struct udev *udev_ref(struct udev *udev);
31 struct udev *udev_unref(struct udev *udev);
32 struct udev *udev_new(void);
33 void udev_set_log_fn(struct udev *udev,
34 void (*log_fn)(struct udev *udev,
35 int priority, const char *file, int line, const char *fn,
36 const char *format, va_list args));
37 int udev_get_log_priority(struct udev *udev);
38 void udev_set_log_priority(struct udev *udev, int priority);
39 const char *udev_get_sys_path(struct udev *udev);
40 const char *udev_get_dev_path(struct udev *udev);
41 const char *udev_get_run_path(struct udev *udev);
42 void *udev_get_userdata(struct udev *udev);
43 void udev_set_userdata(struct udev *udev, void *userdata);
44
45 /*
46 * udev_list
47 *
48 * access to libudev generated lists
49 */
50 struct udev_list_entry;
51 struct udev_list_entry *udev_list_entry_get_next(struct udev_list_entry *list_entry);
52 struct udev_list_entry *udev_list_entry_get_by_name(struct udev_list_entry *list_entry, const char *name);
53 const char *udev_list_entry_get_name(struct udev_list_entry *list_entry);
54 const char *udev_list_entry_get_value(struct udev_list_entry *list_entry);
55 /**
56 * udev_list_entry_foreach:
57 * @list_entry: entry to store the current position
58 * @first_entry: first entry to start with
59 *
60 * Helper to iterate over all entries of a list.
61 */
62 #define udev_list_entry_foreach(list_entry, first_entry) \
63 for (list_entry = first_entry; \
64 list_entry != NULL; \
65 list_entry = udev_list_entry_get_next(list_entry))
66
67 /*
68 * udev_device
69 *
70 * access to sysfs/kernel devices
71 */
72 struct udev_device;
73 struct udev_device *udev_device_ref(struct udev_device *udev_device);
74 struct udev_device *udev_device_unref(struct udev_device *udev_device);
75 struct udev *udev_device_get_udev(struct udev_device *udev_device);
76 struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *syspath);
77 struct udev_device *udev_device_new_from_devnum(struct udev *udev, char type, dev_t devnum);
78 struct udev_device *udev_device_new_from_subsystem_sysname(struct udev *udev, const char *subsystem, const char *sysname);
79 struct udev_device *udev_device_new_from_device_id(struct udev *udev, char *id);
80 struct udev_device *udev_device_new_from_environment(struct udev *udev);
81 /* udev_device_get_parent_*() does not take a reference on the returned device, it is automatically unref'd with the parent */
82 struct udev_device *udev_device_get_parent(struct udev_device *udev_device);
83 struct udev_device *udev_device_get_parent_with_subsystem_devtype(struct udev_device *udev_device,
84 const char *subsystem, const char *devtype);
85 /* retrieve device properties */
86 const char *udev_device_get_devpath(struct udev_device *udev_device);
87 const char *udev_device_get_subsystem(struct udev_device *udev_device);
88 const char *udev_device_get_devtype(struct udev_device *udev_device);
89 const char *udev_device_get_syspath(struct udev_device *udev_device);
90 const char *udev_device_get_sysname(struct udev_device *udev_device);
91 const char *udev_device_get_sysnum(struct udev_device *udev_device);
92 const char *udev_device_get_devnode(struct udev_device *udev_device);
93 int udev_device_get_is_initialized(struct udev_device *udev_device);
94 struct udev_list_entry *udev_device_get_devlinks_list_entry(struct udev_device *udev_device);
95 struct udev_list_entry *udev_device_get_properties_list_entry(struct udev_device *udev_device);
96 struct udev_list_entry *udev_device_get_tags_list_entry(struct udev_device *udev_device);
97 struct udev_list_entry *udev_device_get_sysattr_list_entry(struct udev_device *udev_device);
98 const char *udev_device_get_property_value(struct udev_device *udev_device, const char *key);
99 const char *udev_device_get_driver(struct udev_device *udev_device);
100 dev_t udev_device_get_devnum(struct udev_device *udev_device);
101 const char *udev_device_get_action(struct udev_device *udev_device);
102 unsigned long long int udev_device_get_seqnum(struct udev_device *udev_device);
103 unsigned long long int udev_device_get_usec_since_initialized(struct udev_device *udev_device);
104 const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const char *sysattr);
105 int udev_device_has_tag(struct udev_device *udev_device, const char *tag);
106
107 /*
108 * udev_monitor
109 *
110 * access to kernel uevents and udev events
111 */
112 struct udev_monitor;
113 struct udev_monitor *udev_monitor_ref(struct udev_monitor *udev_monitor);
114 struct udev_monitor *udev_monitor_unref(struct udev_monitor *udev_monitor);
115 struct udev *udev_monitor_get_udev(struct udev_monitor *udev_monitor);
116 /* kernel and udev generated events over netlink */
117 struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, const char *name);
118 /* custom socket (use netlink and filters instead) */
119 struct udev_monitor *udev_monitor_new_from_socket(struct udev *udev, const char *socket_path);
120 /* bind socket */
121 int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor);
122 int udev_monitor_set_receive_buffer_size(struct udev_monitor *udev_monitor, int size);
123 int udev_monitor_get_fd(struct udev_monitor *udev_monitor);
124 struct udev_device *udev_monitor_receive_device(struct udev_monitor *udev_monitor);
125 /* in-kernel socket filters to select messages that get delivered to a listener */
126 int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_monitor,
127 const char *subsystem, const char *devtype);
128 int udev_monitor_filter_add_match_tag(struct udev_monitor *udev_monitor, const char *tag);
129 int udev_monitor_filter_update(struct udev_monitor *udev_monitor);
130 int udev_monitor_filter_remove(struct udev_monitor *udev_monitor);
131
132 /*
133 * udev_enumerate
134 *
135 * search sysfs for specific devices and provide a sorted list
136 */
137 struct udev_enumerate;
138 struct udev_enumerate *udev_enumerate_ref(struct udev_enumerate *udev_enumerate);
139 struct udev_enumerate *udev_enumerate_unref(struct udev_enumerate *udev_enumerate);
140 struct udev *udev_enumerate_get_udev(struct udev_enumerate *udev_enumerate);
141 struct udev_enumerate *udev_enumerate_new(struct udev *udev);
142 /* device properties filter */
143 int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem);
144 int udev_enumerate_add_nomatch_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem);
145 int udev_enumerate_add_match_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value);
146 int udev_enumerate_add_nomatch_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value);
147 int udev_enumerate_add_match_property(struct udev_enumerate *udev_enumerate, const char *property, const char *value);
148 int udev_enumerate_add_match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname);
149 int udev_enumerate_add_match_tag(struct udev_enumerate *udev_enumerate, const char *tag);
150 int udev_enumerate_add_match_parent(struct udev_enumerate *udev_enumerate, struct udev_device *parent);
151 int udev_enumerate_add_match_is_initialized(struct udev_enumerate *udev_enumerate);
152 int udev_enumerate_add_syspath(struct udev_enumerate *udev_enumerate, const char *syspath);
153 /* run enumeration with active filters */
154 int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate);
155 int udev_enumerate_scan_subsystems(struct udev_enumerate *udev_enumerate);
156 /* return device list */
157 struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *udev_enumerate);
158
159 /*
160 * udev_queue
161 *
162 * access to the currently running udev events
163 */
164 struct udev_queue;
165 struct udev_queue *udev_queue_ref(struct udev_queue *udev_queue);
166 struct udev_queue *udev_queue_unref(struct udev_queue *udev_queue);
167 struct udev *udev_queue_get_udev(struct udev_queue *udev_queue);
168 struct udev_queue *udev_queue_new(struct udev *udev);
169 unsigned long long int udev_queue_get_kernel_seqnum(struct udev_queue *udev_queue);
170 unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *udev_queue);
171 int udev_queue_get_udev_is_active(struct udev_queue *udev_queue);
172 int udev_queue_get_queue_is_empty(struct udev_queue *udev_queue);
173 int udev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, unsigned long long int seqnum);
174 int udev_queue_get_seqnum_sequence_is_finished(struct udev_queue *udev_queue,
175 unsigned long long int start, unsigned long long int end);
176 struct udev_list_entry *udev_queue_get_queued_list_entry(struct udev_queue *udev_queue);
177
178 /*
179 * udev_util
180 *
181 * udev specific utilities
182 */
183 int udev_util_encode_string(const char *str, char *str_enc, size_t len);
184
185
186 #ifdef __cplusplus
187 } /* extern "C" */
188 #endif
189
190 #endif
File src/libudev.pc.in added (mode: 100644) (index 0000000..c9a47fc)
1 prefix=@prefix@
2 exec_prefix=@exec_prefix@
3 libdir=@libdir@
4 includedir=@includedir@
5
6 Name: libudev
7 Description: Library to access udev device information
8 Version: @VERSION@
9 Libs: -L${libdir} -ludev -lrt
10 Libs.private:
11 Cflags: -I${includedir}
File src/udev-builtin-blkid.c added (mode: 100644) (index 0000000..e57f03e)
1 /*
2 * probe disks for filesystems and partitions
3 *
4 * Copyright (C) 2011 Kay Sievers <kay.sievers@vrfy.org>
5 * Copyright (C) 2011 Karel Zak <kzak@redhat.com>
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <stdarg.h>
24 #include <unistd.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <fcntl.h>
28 #include <getopt.h>
29 #include <sys/stat.h>
30 #include <blkid/blkid.h>
31
32 #include "udev.h"
33
34 static void print_property(struct udev_device *dev, bool test, const char *name, const char *value)
35 {
36 char s[265];
37
38 s[0] = '\0';
39
40 if (!strcmp(name, "TYPE")) {
41 udev_builtin_add_property(dev, test, "ID_FS_TYPE", value);
42
43 } else if (!strcmp(name, "USAGE")) {
44 udev_builtin_add_property(dev, test, "ID_FS_USAGE", value);
45
46 } else if (!strcmp(name, "VERSION")) {
47 udev_builtin_add_property(dev, test, "ID_FS_VERSION", value);
48
49 } else if (!strcmp(name, "UUID")) {
50 blkid_safe_string(value, s, sizeof(s));
51 udev_builtin_add_property(dev, test, "ID_FS_UUID", s);
52 blkid_encode_string(value, s, sizeof(s));
53 udev_builtin_add_property(dev, test, "ID_FS_UUID_ENC", s);
54
55 } else if (!strcmp(name, "UUID_SUB")) {
56 blkid_safe_string(value, s, sizeof(s));
57 udev_builtin_add_property(dev, test, "ID_FS_UUID_SUB", s);
58 blkid_encode_string(value, s, sizeof(s));
59 udev_builtin_add_property(dev, test, "ID_FS_UUID_SUB_ENC", s);
60
61 } else if (!strcmp(name, "LABEL")) {
62 blkid_safe_string(value, s, sizeof(s));
63 udev_builtin_add_property(dev, test, "ID_FS_LABEL", s);
64 blkid_encode_string(value, s, sizeof(s));
65 udev_builtin_add_property(dev, test, "ID_FS_LABEL_ENC", s);
66
67 } else if (!strcmp(name, "PTTYPE")) {
68 udev_builtin_add_property(dev, test, "ID_PART_TABLE_TYPE", value);
69
70 } else if (!strcmp(name, "PART_ENTRY_NAME")) {
71 blkid_encode_string(value, s, sizeof(s));
72 udev_builtin_add_property(dev, test, "ID_PART_ENTRY_NAME", s);
73
74 } else if (!strcmp(name, "PART_ENTRY_TYPE")) {
75 blkid_encode_string(value, s, sizeof(s));
76 udev_builtin_add_property(dev, test, "ID_PART_ENTRY_TYPE", s);
77
78 } else if (!strncmp(name, "PART_ENTRY_", 11)) {
79 util_strscpyl(s, sizeof(s), "ID_", name, NULL);
80 udev_builtin_add_property(dev, test, s, value);
81 }
82 }
83
84 static int probe_superblocks(blkid_probe pr)
85 {
86 struct stat st;
87 int rc;
88
89 if (fstat(blkid_probe_get_fd(pr), &st))
90 return -1;
91
92 blkid_probe_enable_partitions(pr, 1);
93
94 if (!S_ISCHR(st.st_mode) && blkid_probe_get_size(pr) <= 1024 * 1440 &&
95 blkid_probe_is_wholedisk(pr)) {
96 /*
97 * check if the small disk is partitioned, if yes then
98 * don't probe for filesystems.
99 */
100 blkid_probe_enable_superblocks(pr, 0);
101
102 rc = blkid_do_fullprobe(pr);
103 if (rc < 0)
104 return rc; /* -1 = error, 1 = nothing, 0 = succes */
105
106 if (blkid_probe_lookup_value(pr, "PTTYPE", NULL, NULL) == 0)
107 return 0; /* partition table detected */
108 }
109
110 blkid_probe_set_partitions_flags(pr, BLKID_PARTS_ENTRY_DETAILS);
111 blkid_probe_enable_superblocks(pr, 1);
112
113 return blkid_do_safeprobe(pr);
114 }
115
116 static int builtin_blkid(struct udev_device *dev, int argc, char *argv[], bool test)
117 {
118 struct udev *udev = udev_device_get_udev(dev);
119 int64_t offset = 0;
120 bool noraid = false;
121 int fd = -1;
122 blkid_probe pr;
123 const char *data;
124 const char *name;
125 int nvals;
126 int i;
127 size_t len;
128 int err = 0;
129
130 static const struct option options[] = {
131 { "offset", optional_argument, NULL, 'o' },
132 { "noraid", no_argument, NULL, 'R' },
133 {}
134 };
135
136 for (;;) {
137 int option;
138
139 option = getopt_long(argc, argv, "oR", options, NULL);
140 if (option == -1)
141 break;
142
143 switch (option) {
144 case 'o':
145 offset = strtoull(optarg, NULL, 0);
146 break;
147 case 'R':
148 noraid = true;
149 break;
150 }
151 }
152
153 pr = blkid_new_probe();
154 if (!pr) {
155 err = -ENOMEM;
156 return EXIT_FAILURE;
157 }
158
159 blkid_probe_set_superblocks_flags(pr,
160 BLKID_SUBLKS_LABEL | BLKID_SUBLKS_UUID |
161 BLKID_SUBLKS_TYPE | BLKID_SUBLKS_SECTYPE |
162 BLKID_SUBLKS_USAGE | BLKID_SUBLKS_VERSION);
163
164 if (noraid)
165 blkid_probe_filter_superblocks_usage(pr, BLKID_FLTR_NOTIN, BLKID_USAGE_RAID);
166
167 fd = open(udev_device_get_devnode(dev), O_RDONLY|O_CLOEXEC);
168 if (fd < 0) {
169 fprintf(stderr, "error: %s: %m\n", udev_device_get_devnode(dev));
170 goto out;
171 }
172
173 err = blkid_probe_set_device(pr, fd, offset, 0);
174 if (err < 0)
175 goto out;
176
177 info(udev, "probe %s %sraid offset=%llu\n",
178 udev_device_get_devnode(dev),
179 noraid ? "no" : "", (unsigned long long) offset);
180
181 err = probe_superblocks(pr);
182 if (err < 0)
183 goto out;
184
185 nvals = blkid_probe_numof_values(pr);
186 for (i = 0; i < nvals; i++) {
187 if (blkid_probe_get_value(pr, i, &name, &data, &len))
188 continue;
189 len = strnlen((char *) data, len);
190 print_property(dev, test, name, (char *) data);
191 }
192
193 blkid_free_probe(pr);
194 out:
195 if (fd > 0)
196 close(fd);
197 if (err < 0)
198 return EXIT_FAILURE;
199 return EXIT_SUCCESS;
200 }
201
202 const struct udev_builtin udev_builtin_blkid = {
203 .name = "blkid",
204 .cmd = builtin_blkid,
205 .help = "filesystem and partition probing",
206 .run_once = true,
207 };
File src/udev-builtin-firmware.c added (mode: 100644) (index 0000000..d212c64)
1 /*
2 * firmware - Kernel firmware loader
3 *
4 * Copyright (C) 2009 Piter Punk <piterpunk@slackware.com>
5 * Copyright (C) 2009-2011 Kay Sievers <kay.sievers@vrfy.org>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details:*
16 */
17
18 #include <unistd.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <stdio.h>
22 #include <getopt.h>
23 #include <errno.h>
24 #include <stdbool.h>
25 #include <sys/utsname.h>
26 #include <sys/stat.h>
27
28 #include "udev.h"
29
30 static bool set_loading(struct udev *udev, char *loadpath, const char *state)
31 {
32 FILE *ldfile;
33
34 ldfile = fopen(loadpath, "we");
35 if (ldfile == NULL) {
36 err(udev, "error: can not open '%s'\n", loadpath);
37 return false;
38 };
39 fprintf(ldfile, "%s\n", state);
40 fclose(ldfile);
41 return true;
42 }
43
44 static bool copy_firmware(struct udev *udev, const char *source, const char *target, size_t size)
45 {
46 char *buf;
47 FILE *fsource = NULL, *ftarget = NULL;
48 bool ret = false;
49
50 buf = malloc(size);
51 if (buf == NULL) {
52 err(udev,"No memory available to load firmware file");
53 return false;
54 }
55
56 info(udev, "writing '%s' (%zi) to '%s'\n", source, size, target);
57
58 fsource = fopen(source, "re");
59 if (fsource == NULL)
60 goto exit;
61 ftarget = fopen(target, "we");
62 if (ftarget == NULL)
63 goto exit;
64 if (fread(buf, size, 1, fsource) != 1)
65 goto exit;
66 if (fwrite(buf, size, 1, ftarget) == 1)
67 ret = true;
68 exit:
69 if (ftarget != NULL)
70 fclose(ftarget);
71 if (fsource != NULL)
72 fclose(fsource);
73 free(buf);
74 return ret;
75 }
76
77 static int builtin_firmware(struct udev_device *dev, int argc, char *argv[], bool test)
78 {
79 struct udev *udev = udev_device_get_udev(dev);
80 static const char *searchpath[] = { FIRMWARE_PATH };
81 char fwencpath[UTIL_PATH_SIZE];
82 char misspath[UTIL_PATH_SIZE];
83 char loadpath[UTIL_PATH_SIZE];
84 char datapath[UTIL_PATH_SIZE];
85 char fwpath[UTIL_PATH_SIZE];
86 const char *firmware;
87 FILE *fwfile;
88 struct utsname kernel;
89 struct stat statbuf;
90 unsigned int i;
91 int rc = EXIT_SUCCESS;
92
93 firmware = udev_device_get_property_value(dev, "FIRMWARE");
94 if (firmware == NULL) {
95 err(udev, "firmware parameter missing\n\n");
96 rc = EXIT_FAILURE;
97 goto exit;
98 }
99
100 /* lookup firmware file */
101 uname(&kernel);
102 for (i = 0; i < ARRAY_SIZE(searchpath); i++) {
103 util_strscpyl(fwpath, sizeof(fwpath), searchpath[i], kernel.release, "/", firmware, NULL);
104 dbg(udev, "trying %s\n", fwpath);
105 fwfile = fopen(fwpath, "re");
106 if (fwfile != NULL)
107 break;
108
109 util_strscpyl(fwpath, sizeof(fwpath), searchpath[i], firmware, NULL);
110 dbg(udev, "trying %s\n", fwpath);
111 fwfile = fopen(fwpath, "re");
112 if (fwfile != NULL)
113 break;
114 }
115
116 util_path_encode(firmware, fwencpath, sizeof(fwencpath));
117 util_strscpyl(misspath, sizeof(misspath), udev_get_run_path(udev), "/firmware-missing/", fwencpath, NULL);
118 util_strscpyl(loadpath, sizeof(loadpath), udev_device_get_syspath(dev), "/loading", NULL);
119
120 if (fwfile == NULL) {
121 int err;
122
123 /* This link indicates the missing firmware file and the associated device */
124 info(udev, "did not find firmware file '%s'\n", firmware);
125 do {
126 err = util_create_path(udev, misspath);
127 if (err != 0 && err != -ENOENT)
128 break;
129 err = symlink(udev_device_get_devpath(dev), misspath);
130 if (err != 0)
131 err = -errno;
132 } while (err == -ENOENT);
133 rc = EXIT_FAILURE;
134 set_loading(udev, loadpath, "-1");
135 goto exit;
136 }
137
138 if (stat(fwpath, &statbuf) < 0 || statbuf.st_size == 0) {
139 rc = EXIT_FAILURE;
140 goto exit;
141 }
142 if (unlink(misspath) == 0)
143 util_delete_path(udev, misspath);
144
145 if (!set_loading(udev, loadpath, "1"))
146 goto exit;
147
148 util_strscpyl(datapath, sizeof(datapath), udev_device_get_syspath(dev), "/data", NULL);
149 if (!copy_firmware(udev, fwpath, datapath, statbuf.st_size)) {
150 err(udev, "error sending firmware '%s' to device\n", firmware);
151 set_loading(udev, loadpath, "-1");
152 rc = EXIT_FAILURE;
153 goto exit;
154 };
155
156 set_loading(udev, loadpath, "0");
157 exit:
158 if (fwfile)
159 fclose(fwfile);
160 return rc;
161 }
162
163 const struct udev_builtin udev_builtin_firmware = {
164 .name = "firmware",
165 .cmd = builtin_firmware,
166 .help = "kernel firmware loader",
167 .run_once = true,
168 };
File src/udev-builtin-hwdb.c added (mode: 100644) (index 0000000..aa996f3)
1 /*
2 * usb-db, pci-db - lookup vendor/product database
3 *
4 * Copyright (C) 2009 Lennart Poettering <lennart@poettering.net>
5 * Copyright (C) 2011 Kay Sievers <kay.sievers@vrfy.org>
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include <stdio.h>
22 #include <errno.h>
23 #include <string.h>
24 #include <inttypes.h>
25 #include <ctype.h>
26 #include <stdlib.h>
27
28 #include "udev.h"
29
30 static int get_id_attr(
31 struct udev_device *parent,
32 const char *name,
33 uint16_t *value) {
34
35 const char *t;
36 unsigned u;
37
38 if (!(t = udev_device_get_sysattr_value(parent, name))) {
39 fprintf(stderr, "%s lacks %s.\n", udev_device_get_syspath(parent), name);
40 return -1;
41 }
42
43 if (!strncmp(t, "0x", 2))
44 t += 2;
45
46 if (sscanf(t, "%04x", &u) != 1 || u > 0xFFFFU) {
47 fprintf(stderr, "Failed to parse %s on %s.\n", name, udev_device_get_syspath(parent));
48 return -1;
49 }
50
51 *value = (uint16_t) u;
52 return 0;
53 }
54
55 static int get_vid_pid(
56 struct udev_device *parent,
57 const char *vendor_attr,
58 const char *product_attr,
59 uint16_t *vid,
60 uint16_t *pid) {
61
62 if (get_id_attr(parent, vendor_attr, vid) < 0)
63 return -1;
64 else if (*vid <= 0) {
65 fprintf(stderr, "Invalid vendor id.\n");
66 return -1;
67 }
68
69 if (get_id_attr(parent, product_attr, pid) < 0)
70 return -1;
71
72 return 0;
73 }
74
75 static void rstrip(char *n) {
76 size_t i;
77
78 for (i = strlen(n); i > 0 && isspace(n[i-1]); i--)
79 n[i-1] = 0;
80 }
81
82 #define HEXCHARS "0123456789abcdefABCDEF"
83 #define WHITESPACE " \t\n\r"
84 static int lookup_vid_pid(const char *database,
85 uint16_t vid, uint16_t pid,
86 char **vendor, char **product)
87 {
88
89 FILE *f;
90 int ret = -1;
91 int found_vendor = 0;
92 char *line = NULL;
93
94 *vendor = *product = NULL;
95
96 if (!(f = fopen(database, "rme"))) {
97 fprintf(stderr, "Failed to open database file '%s': %s\n", database, strerror(errno));
98 return -1;
99 }
100
101 for (;;) {
102 size_t n;
103
104 if (getline(&line, &n, f) < 0)
105 break;
106
107 rstrip(line);
108
109 if (line[0] == '#' || line[0] == 0)
110 continue;
111
112 if (strspn(line, HEXCHARS) == 4) {
113 unsigned u;
114
115 if (found_vendor)
116 break;
117
118 if (sscanf(line, "%04x", &u) == 1 && u == vid) {
119 char *t;
120
121 t = line+4;
122 t += strspn(t, WHITESPACE);
123
124 if (!(*vendor = strdup(t))) {
125 fprintf(stderr, "Out of memory.\n");
126 goto finish;
127 }
128
129 found_vendor = 1;
130 }
131
132 continue;
133 }
134
135 if (found_vendor && line[0] == '\t' && strspn(line+1, HEXCHARS) == 4) {
136 unsigned u;
137
138 if (sscanf(line+1, "%04x", &u) == 1 && u == pid) {
139 char *t;
140
141 t = line+5;
142 t += strspn(t, WHITESPACE);
143
144 if (!(*product = strdup(t))) {
145 fprintf(stderr, "Out of memory.\n");
146 goto finish;
147 }
148
149 break;
150 }
151 }
152 }
153
154 ret = 0;
155
156 finish:
157 free(line);
158 fclose(f);
159
160 if (ret < 0) {
161 free(*product);
162 free(*vendor);
163
164 *product = *vendor = NULL;
165 }
166
167 return ret;
168 }
169
170 static struct udev_device *find_device(struct udev_device *dev, const char *subsys, const char *devtype)
171 {
172 const char *str;
173
174 str = udev_device_get_subsystem(dev);
175 if (str == NULL)
176 goto try_parent;
177 if (strcmp(str, subsys) != 0)
178 goto try_parent;
179
180 if (devtype != NULL) {
181 str = udev_device_get_devtype(dev);
182 if (str == NULL)
183 goto try_parent;
184 if (strcmp(str, devtype) != 0)
185 goto try_parent;
186 }
187 return dev;
188 try_parent:
189 return udev_device_get_parent_with_subsystem_devtype(dev, subsys, devtype);
190 }
191
192
193 static int builtin_db(struct udev_device *dev, bool test,
194 const char *database,
195 const char *vendor_attr, const char *product_attr,
196 const char *subsys, const char *devtype)
197 {
198 struct udev_device *parent;
199 uint16_t vid = 0, pid = 0;
200 char *vendor = NULL, *product = NULL;
201
202 parent = find_device(dev, subsys, devtype);
203 if (!parent) {
204 fprintf(stderr, "Failed to find device.\n");
205 goto finish;
206 }
207
208 if (get_vid_pid(parent, vendor_attr, product_attr, &vid, &pid) < 0)
209 goto finish;
210
211 if (lookup_vid_pid(database, vid, pid, &vendor, &product) < 0)
212 goto finish;
213
214 if (vendor)
215 udev_builtin_add_property(dev, test, "ID_VENDOR_FROM_DATABASE", vendor);
216 if (product)
217 udev_builtin_add_property(dev, test, "ID_MODEL_FROM_DATABASE", product);
218
219 finish:
220 free(vendor);
221 free(product);
222 return 0;
223 }
224
225 static int builtin_usb_db(struct udev_device *dev, int argc, char *argv[], bool test)
226 {
227 return builtin_db(dev, test, USB_DATABASE, "idVendor", "idProduct", "usb", "usb_device");
228 }
229
230 static int builtin_pci_db(struct udev_device *dev, int argc, char *argv[], bool test)
231 {
232 return builtin_db(dev, test, PCI_DATABASE, "vendor", "device", "pci", NULL);
233 }
234
235 const struct udev_builtin udev_builtin_usb_db = {
236 .name = "usb-db",
237 .cmd = builtin_usb_db,
238 .help = "USB vendor/product database",
239 .run_once = true,
240 };
241
242 const struct udev_builtin udev_builtin_pci_db = {
243 .name = "pci-db",
244 .cmd = builtin_pci_db,
245 .help = "PCI vendor/product database",
246 .run_once = true,
247 };
File src/udev-builtin-input_id.c added (mode: 100644) (index 0000000..a062ef7)
1 /*
2 * compose persistent device path
3 *
4 * Copyright (C) 2009 Martin Pitt <martin.pitt@ubuntu.com>
5 * Portions Copyright (C) 2004 David Zeuthen, <david@fubar.dk>
6 * Copyright (C) 2011 Kay Sievers <kay.sievers@vrfy.org>
7 *
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <stdarg.h>
25 #include <unistd.h>
26 #include <string.h>
27 #include <errno.h>
28 #include <linux/limits.h>
29 #include <linux/input.h>
30
31 #include "udev.h"
32
33 /* we must use this kernel-compatible implementation */
34 #define BITS_PER_LONG (sizeof(unsigned long) * 8)
35 #define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1)
36 #define OFF(x) ((x)%BITS_PER_LONG)
37 #define BIT(x) (1UL<<OFF(x))
38 #define LONG(x) ((x)/BITS_PER_LONG)
39 #define test_bit(bit, array) ((array[LONG(bit)] >> OFF(bit)) & 1)
40
41 /*
42 * Read a capability attribute and return bitmask.
43 * @param dev udev_device
44 * @param attr sysfs attribute name (e. g. "capabilities/key")
45 * @param bitmask: Output array which has a sizeof of bitmask_size
46 */
47 static void get_cap_mask(struct udev_device *dev,
48 struct udev_device *pdev, const char* attr,
49 unsigned long *bitmask, size_t bitmask_size,
50 bool test)
51 {
52 struct udev *udev = udev_device_get_udev(dev);
53 char text[4096];
54 unsigned i;
55 char* word;
56 unsigned long val;
57
58 snprintf(text, sizeof(text), "%s", udev_device_get_sysattr_value(pdev, attr));
59 info(udev, "%s raw kernel attribute: %s\n", attr, text);
60
61 memset (bitmask, 0, bitmask_size);
62 i = 0;
63 while ((word = strrchr(text, ' ')) != NULL) {
64 val = strtoul (word+1, NULL, 16);
65 if (i < bitmask_size/sizeof(unsigned long))
66 bitmask[i] = val;
67 else
68 info(udev, "ignoring %s block %lX which is larger than maximum size\n", attr, val);
69 *word = '\0';
70 ++i;
71 }
72 val = strtoul (text, NULL, 16);
73 if (i < bitmask_size / sizeof(unsigned long))
74 bitmask[i] = val;
75 else
76 info(udev, "ignoring %s block %lX which is larger than maximum size\n", attr, val);
77
78 if (test) {
79 /* printf pattern with the right unsigned long number of hex chars */
80 snprintf(text, sizeof(text), " bit %%4u: %%0%zilX\n", 2 * sizeof(unsigned long));
81 info(udev, "%s decoded bit map:\n", attr);
82 val = bitmask_size / sizeof (unsigned long);
83 /* skip over leading zeros */
84 while (bitmask[val-1] == 0 && val > 0)
85 --val;
86 for (i = 0; i < val; ++i)
87 info(udev, text, i * BITS_PER_LONG, bitmask[i]);
88 }
89 }
90
91 /* pointer devices */
92 static void test_pointers (struct udev_device *dev,
93 const unsigned long* bitmask_ev,
94 const unsigned long* bitmask_abs,
95 const unsigned long* bitmask_key,
96 const unsigned long* bitmask_rel,
97 bool test)
98 {
99 int is_mouse = 0;
100 int is_touchpad = 0;
101
102 if (!test_bit (EV_KEY, bitmask_ev)) {
103 if (test_bit (EV_ABS, bitmask_ev) &&
104 test_bit (ABS_X, bitmask_abs) &&
105 test_bit (ABS_Y, bitmask_abs) &&
106 test_bit (ABS_Z, bitmask_abs))
107 udev_builtin_add_property(dev, test, "ID_INPUT_ACCELEROMETER", "1");
108 return;
109 }
110
111 if (test_bit (EV_ABS, bitmask_ev) &&
112 test_bit (ABS_X, bitmask_abs) && test_bit (ABS_Y, bitmask_abs)) {
113 if (test_bit (BTN_STYLUS, bitmask_key) || test_bit (BTN_TOOL_PEN, bitmask_key))
114 udev_builtin_add_property(dev, test, "ID_INPUT_TABLET", "1");
115 else if (test_bit (BTN_TOOL_FINGER, bitmask_key) && !test_bit (BTN_TOOL_PEN, bitmask_key))
116 is_touchpad = 1;
117 else if (test_bit (BTN_TRIGGER, bitmask_key) ||
118 test_bit (BTN_A, bitmask_key) ||
119 test_bit (BTN_1, bitmask_key))
120 udev_builtin_add_property(dev, test, "ID_INPUT_JOYSTICK", "1");
121 else if (test_bit (BTN_MOUSE, bitmask_key))
122 /* This path is taken by VMware's USB mouse, which has
123 * absolute axes, but no touch/pressure button. */
124 is_mouse = 1;
125 else if (test_bit (BTN_TOUCH, bitmask_key))
126 udev_builtin_add_property(dev, test, "ID_INPUT_TOUCHSCREEN", "1");
127 }
128
129 if (test_bit (EV_REL, bitmask_ev) &&
130 test_bit (REL_X, bitmask_rel) && test_bit (REL_Y, bitmask_rel) &&
131 test_bit (BTN_MOUSE, bitmask_key))
132 is_mouse = 1;
133
134 if (is_mouse)
135 udev_builtin_add_property(dev, test, "ID_INPUT_MOUSE", "1");
136 if (is_touchpad)
137 udev_builtin_add_property(dev, test, "ID_INPUT_TOUCHPAD", "1");
138 }
139
140 /* key like devices */
141 static void test_key (struct udev_device *dev,
142 const unsigned long* bitmask_ev,
143 const unsigned long* bitmask_key,
144 bool test)
145 {
146 struct udev *udev = udev_device_get_udev(dev);
147 unsigned i;
148 unsigned long found;
149 unsigned long mask;
150
151 /* do we have any KEY_* capability? */
152 if (!test_bit (EV_KEY, bitmask_ev)) {
153 info(udev, "test_key: no EV_KEY capability\n");
154 return;
155 }
156
157 /* only consider KEY_* here, not BTN_* */
158 found = 0;
159 for (i = 0; i < BTN_MISC/BITS_PER_LONG; ++i) {
160 found |= bitmask_key[i];
161 info(udev, "test_key: checking bit block %lu for any keys; found=%i\n", i*BITS_PER_LONG, found > 0);
162 }
163 /* If there are no keys in the lower block, check the higher block */
164 if (!found) {
165 for (i = KEY_OK; i < BTN_TRIGGER_HAPPY; ++i) {
166 if (test_bit (i, bitmask_key)) {
167 info(udev, "test_key: Found key %x in high block\n", i);
168 found = 1;
169 break;
170 }
171 }
172 }
173
174 if (found > 0)
175 udev_builtin_add_property(dev, test, "ID_INPUT_KEY", "1");
176
177 /* the first 32 bits are ESC, numbers, and Q to D; if we have all of
178 * those, consider it a full keyboard; do not test KEY_RESERVED, though */
179 mask = 0xFFFFFFFE;
180 if ((bitmask_key[0] & mask) == mask)
181 udev_builtin_add_property(dev, test, "ID_INPUT_KEYBOARD", "1");
182 }
183
184 static int builtin_input_id(struct udev_device *dev, int argc, char *argv[], bool test)
185 {
186 struct udev_device *pdev;
187 unsigned long bitmask_ev[NBITS(EV_MAX)];
188 unsigned long bitmask_abs[NBITS(ABS_MAX)];
189 unsigned long bitmask_key[NBITS(KEY_MAX)];
190 unsigned long bitmask_rel[NBITS(REL_MAX)];
191
192 /* walk up the parental chain until we find the real input device; the
193 * argument is very likely a subdevice of this, like eventN */
194 pdev = dev;
195 while (pdev != NULL && udev_device_get_sysattr_value(pdev, "capabilities/ev") == NULL)
196 pdev = udev_device_get_parent_with_subsystem_devtype(pdev, "input", NULL);
197
198 /* not an "input" class device */
199 if (pdev == NULL)
200 return EXIT_SUCCESS;
201
202 /* Use this as a flag that input devices were detected, so that this
203 * program doesn't need to be called more than once per device */
204 udev_builtin_add_property(dev, test, "ID_INPUT", "1");
205 get_cap_mask(dev, pdev, "capabilities/ev", bitmask_ev, sizeof(bitmask_ev), test);
206 get_cap_mask(dev, pdev, "capabilities/abs", bitmask_abs, sizeof(bitmask_abs), test);
207 get_cap_mask(dev, pdev, "capabilities/rel", bitmask_rel, sizeof(bitmask_rel), test);
208 get_cap_mask(dev, pdev, "capabilities/key", bitmask_key, sizeof(bitmask_key), test);
209 test_pointers(dev, bitmask_ev, bitmask_abs, bitmask_key, bitmask_rel, test);
210 test_key(dev, bitmask_ev, bitmask_key, test);
211 return EXIT_SUCCESS;
212 }
213
214 const struct udev_builtin udev_builtin_input_id = {
215 .name = "input_id",
216 .cmd = builtin_input_id,
217 .help = "input device properties",
218 };
File src/udev-builtin-kmod.c added (mode: 100644) (index 0000000..57e813f)
1 /*
2 * load kernel modules
3 *
4 * Copyright (C) 2011 Kay Sievers <kay.sievers@vrfy.org>
5 * Copyright (C) 2011 ProFUSION embedded systems
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <stdarg.h>
24 #include <unistd.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <fcntl.h>
28 #include <sys/stat.h>
29 #include <sys/wait.h>
30 #include <libkmod.h>
31
32 #include "udev.h"
33
34 static struct kmod_ctx *ctx;
35
36 static int load_module(struct udev *udev, const char *alias)
37 {
38 struct kmod_list *list = NULL;
39 struct kmod_list *l;
40 int err;
41
42 err = kmod_module_new_from_lookup(ctx, alias, &list);
43 if (err < 0)
44 return err;
45
46 if (list == NULL)
47 info(udev, "no module matches '%s'\n", alias);
48
49 kmod_list_foreach(l, list) {
50 struct kmod_module *mod = kmod_module_get_module(l);
51
52 err = kmod_module_probe_insert_module(mod, KMOD_PROBE_APPLY_BLACKLIST, NULL, NULL, NULL, NULL);
53 if (err == KMOD_PROBE_APPLY_BLACKLIST)
54 info(udev, "module '%s' is blacklisted\n", kmod_module_get_name(mod));
55 else if (err == 0)
56 info(udev, "inserted '%s'\n", kmod_module_get_name(mod));
57 else
58 info(udev, "failed to insert '%s'\n", kmod_module_get_name(mod));
59
60 kmod_module_unref(mod);
61 }
62
63 kmod_module_unref_list(list);
64 return err;
65 }
66
67 static void udev_kmod_log(void *data, int priority, const char *file, int line,
68 const char *fn, const char *format, va_list args)
69 {
70 udev_main_log(data, priority, file, line, fn, format, args);
71 }
72
73 /* needs to re-instantiate the context after a reload */
74 static int builtin_kmod(struct udev_device *dev, int argc, char *argv[], bool test)
75 {
76 struct udev *udev = udev_device_get_udev(dev);
77 int i;
78
79 if (!ctx) {
80 ctx = kmod_new(NULL, NULL);
81 if (!ctx)
82 return -ENOMEM;
83
84 info(udev, "load module index\n");
85 kmod_set_log_fn(ctx, udev_kmod_log, udev);
86 kmod_load_resources(ctx);
87 }
88
89 if (argc < 3 || strcmp(argv[1], "load")) {
90 err(udev, "expect: %s load <module>\n", argv[0]);
91 return EXIT_FAILURE;
92 }
93
94 for (i = 2; argv[i]; i++) {
95 info(udev, "execute '%s' '%s'\n", argv[1], argv[i]);
96 load_module(udev, argv[i]);
97 }
98
99 return EXIT_SUCCESS;
100 }
101
102 /* called at udev startup */
103 static int builtin_kmod_init(struct udev *udev)
104 {
105 if (ctx)
106 return 0;
107
108 ctx = kmod_new(NULL, NULL);
109 if (!ctx)
110 return -ENOMEM;
111
112 info(udev, "load module index\n");
113 kmod_set_log_fn(ctx, udev_kmod_log, udev);
114 kmod_load_resources(ctx);
115 return 0;
116 }
117
118 /* called on udev shutdown and reload request */
119 static void builtin_kmod_exit(struct udev *udev)
120 {
121 info(udev, "unload module index\n");
122 ctx = kmod_unref(ctx);
123 }
124
125 /* called every couple of seconds during event activity; 'true' if config has changed */
126 static bool builtin_kmod_validate(struct udev *udev)
127 {
128 info(udev, "validate module index\n");
129 if (kmod_validate_resources(ctx) != KMOD_RESOURCES_OK)
130 return true;
131 return false;
132 }
133
134 const struct udev_builtin udev_builtin_kmod = {
135 .name = "kmod",
136 .cmd = builtin_kmod,
137 .init = builtin_kmod_init,
138 .exit = builtin_kmod_exit,
139 .validate = builtin_kmod_validate,
140 .help = "kernel module loader",
141 .run_once = false,
142 };
File src/udev-builtin-path_id.c added (mode: 100644) (index 0000000..dafbed7)
1 /*
2 * compose persistent device path
3 *
4 * Copyright (C) 2009-2011 Kay Sievers <kay.sievers@vrfy.org>
5 *
6 * Logic based on Hannes Reinecke's shell script.
7 *
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <stdarg.h>
25 #include <unistd.h>
26 #include <string.h>
27 #include <ctype.h>
28 #include <fcntl.h>
29 #include <errno.h>
30 #include <dirent.h>
31 #include <getopt.h>
32
33 #include "udev.h"
34
35 static int path_prepend(char **path, const char *fmt, ...)
36 {
37 va_list va;
38 char *pre;
39 int err = 0;
40
41 va_start(va, fmt);
42 err = vasprintf(&pre, fmt, va);
43 va_end(va);
44 if (err < 0)
45 goto out;
46
47 if (*path != NULL) {
48 char *new;
49
50 err = asprintf(&new, "%s-%s", pre, *path);
51 free(pre);
52 if (err < 0)
53 goto out;
54 free(*path);
55 *path = new;
56 } else {
57 *path = pre;
58 }
59
60 out:
61 return err;
62 }
63
64 /*
65 ** Linux only supports 32 bit luns.
66 ** See drivers/scsi/scsi_scan.c::scsilun_to_int() for more details.
67 */
68 static int format_lun_number(struct udev_device *dev, char **path)
69 {
70 unsigned long lun = strtoul(udev_device_get_sysnum(dev), NULL, 10);
71
72 /* address method 0, peripheral device addressing with bus id of zero */
73 if (lun < 256)
74 return path_prepend(path, "lun-%d", lun);
75 /* handle all other lun addressing methods by using a variant of the original lun format */
76 return path_prepend(path, "lun-0x%04x%04x00000000", (lun & 0xffff), (lun >> 16) & 0xffff);
77 }
78
79 static struct udev_device *skip_subsystem(struct udev_device *dev, const char *subsys)
80 {
81 struct udev_device *parent = dev;
82
83 while (parent != NULL) {
84 const char *subsystem;
85
86 subsystem = udev_device_get_subsystem(parent);
87 if (subsystem == NULL || strcmp(subsystem, subsys) != 0)
88 break;
89 dev = parent;
90 parent = udev_device_get_parent(parent);
91 }
92 return dev;
93 }
94
95 static struct udev_device *handle_scsi_fibre_channel(struct udev_device *parent, char **path)
96 {
97 struct udev *udev = udev_device_get_udev(parent);
98 struct udev_device *targetdev;
99 struct udev_device *fcdev = NULL;
100 const char *port;
101 char *lun = NULL;;
102
103 targetdev = udev_device_get_parent_with_subsystem_devtype(parent, "scsi", "scsi_target");
104 if (targetdev == NULL)
105 return NULL;
106
107 fcdev = udev_device_new_from_subsystem_sysname(udev, "fc_transport", udev_device_get_sysname(targetdev));
108 if (fcdev == NULL)
109 return NULL;
110 port = udev_device_get_sysattr_value(fcdev, "port_name");
111 if (port == NULL) {
112 parent = NULL;
113 goto out;
114 }
115
116 format_lun_number(parent, &lun);
117 path_prepend(path, "fc-%s-%s", port, lun);
118 if (lun)
119 free(lun);
120 out:
121 udev_device_unref(fcdev);
122 return parent;
123 }
124
125 static struct udev_device *handle_scsi_sas(struct udev_device *parent, char **path)
126 {
127 struct udev *udev = udev_device_get_udev(parent);
128 struct udev_device *targetdev;
129 struct udev_device *target_parent;
130 struct udev_device *sasdev;
131 const char *sas_address;
132 char *lun = NULL;
133
134 targetdev = udev_device_get_parent_with_subsystem_devtype(parent, "scsi", "scsi_target");
135 if (targetdev == NULL)
136 return NULL;
137
138 target_parent = udev_device_get_parent(targetdev);
139 if (target_parent == NULL)
140 return NULL;
141
142 sasdev = udev_device_new_from_subsystem_sysname(udev, "sas_device",
143 udev_device_get_sysname(target_parent));
144 if (sasdev == NULL)
145 return NULL;
146
147 sas_address = udev_device_get_sysattr_value(sasdev, "sas_address");
148 if (sas_address == NULL) {
149 parent = NULL;
150 goto out;
151 }
152
153 format_lun_number(parent, &lun);
154 path_prepend(path, "sas-%s-%s", sas_address, lun);
155 if (lun)
156 free(lun);
157 out:
158 udev_device_unref(sasdev);
159 return parent;
160 }
161
162 static struct udev_device *handle_scsi_iscsi(struct udev_device *parent, char **path)
163 {
164 struct udev *udev = udev_device_get_udev(parent);
165 struct udev_device *transportdev;
166 struct udev_device *sessiondev = NULL;
167 const char *target;
168 char *connname;
169 struct udev_device *conndev = NULL;
170 const char *addr;
171 const char *port;
172 char *lun = NULL;
173
174 /* find iscsi session */
175 transportdev = parent;
176 for (;;) {
177 transportdev = udev_device_get_parent(transportdev);
178 if (transportdev == NULL)
179 return NULL;
180 if (strncmp(udev_device_get_sysname(transportdev), "session", 7) == 0)
181 break;
182 }
183
184 /* find iscsi session device */
185 sessiondev = udev_device_new_from_subsystem_sysname(udev, "iscsi_session", udev_device_get_sysname(transportdev));
186 if (sessiondev == NULL)
187 return NULL;
188 target = udev_device_get_sysattr_value(sessiondev, "targetname");
189 if (target == NULL) {
190 parent = NULL;
191 goto out;
192 }
193
194 if (asprintf(&connname, "connection%s:0", udev_device_get_sysnum(transportdev)) < 0) {
195 parent = NULL;
196 goto out;
197 }
198 conndev = udev_device_new_from_subsystem_sysname(udev, "iscsi_connection", connname);
199 free(connname);
200 if (conndev == NULL) {
201 parent = NULL;
202 goto out;
203 }
204 addr = udev_device_get_sysattr_value(conndev, "persistent_address");
205 port = udev_device_get_sysattr_value(conndev, "persistent_port");
206 if (addr == NULL || port == NULL) {
207 parent = NULL;
208 goto out;
209 }
210
211 format_lun_number(parent, &lun);
212 path_prepend(path, "ip-%s:%s-iscsi-%s-%s", addr, port, target, lun);
213 if (lun)
214 free(lun);
215 out:
216 udev_device_unref(sessiondev);
217 udev_device_unref(conndev);
218 return parent;
219 }
220
221 static struct udev_device *handle_scsi_default(struct udev_device *parent, char **path)
222 {
223 struct udev_device *hostdev;
224 int host, bus, target, lun;
225 const char *name;
226 char *base;
227 char *pos;
228 DIR *dir;
229 struct dirent *dent;
230 int basenum;
231
232 hostdev = udev_device_get_parent_with_subsystem_devtype(parent, "scsi", "scsi_host");
233 if (hostdev == NULL)
234 return NULL;
235
236 name = udev_device_get_sysname(parent);
237 if (sscanf(name, "%d:%d:%d:%d", &host, &bus, &target, &lun) != 4)
238 return NULL;
239
240 /*
241 * Rebase host offset to get the local relative number
242 *
243 * Note: This is by definition racy, unreliable and too simple.
244 * Please do not copy this model anywhere. It's just a left-over
245 * from the time we had no idea how things should look like in
246 * the end.
247 *
248 * Making assumptions about a global in-kernel counter and use
249 * that to calculate a local offset is a very broken concept. It
250 * can only work as long as things are in strict order.
251 *
252 * The kernel needs to export the instance/port number of a
253 * controller directly, without the need for rebase magic like
254 * this. Manual driver unbind/bind, parallel hotplug/unplug will
255 * get into the way of this "I hope it works" logic.
256 */
257 basenum = -1;
258 base = strdup(udev_device_get_syspath(hostdev));
259 if (base == NULL)
260 return NULL;
261 pos = strrchr(base, '/');
262 if (pos == NULL) {
263 parent = NULL;
264 goto out;
265 }
266 pos[0] = '\0';
267 dir = opendir(base);
268 if (dir == NULL) {
269 parent = NULL;
270 goto out;
271 }
272 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
273 char *rest;
274 int i;
275
276 if (dent->d_name[0] == '.')
277 continue;
278 if (dent->d_type != DT_DIR && dent->d_type != DT_LNK)
279 continue;
280 if (strncmp(dent->d_name, "host", 4) != 0)
281 continue;
282 i = strtoul(&dent->d_name[4], &rest, 10);
283 if (rest[0] != '\0')
284 continue;
285 /*
286 * find the smallest number; the host really needs to export its
287 * own instance number per parent device; relying on the global host
288 * enumeration and plainly rebasing the numbers sounds unreliable
289 */
290 if (basenum == -1 || i < basenum)
291 basenum = i;
292 }
293 closedir(dir);
294 if (basenum == -1) {
295 parent = NULL;
296 goto out;
297 }
298 host -= basenum;
299
300 path_prepend(path, "scsi-%u:%u:%u:%u", host, bus, target, lun);
301 out:
302 free(base);
303 return hostdev;
304 }
305
306 static struct udev_device *handle_scsi(struct udev_device *parent, char **path)
307 {
308 const char *devtype;
309 const char *name;
310 const char *id;
311
312 devtype = udev_device_get_devtype(parent);
313 if (devtype == NULL || strcmp(devtype, "scsi_device") != 0)
314 return parent;
315
316 /* firewire */
317 id = udev_device_get_sysattr_value(parent, "ieee1394_id");
318 if (id != NULL) {
319 parent = skip_subsystem(parent, "scsi");
320 path_prepend(path, "ieee1394-0x%s", id);
321 goto out;
322 }
323
324 /* lousy scsi sysfs does not have a "subsystem" for the transport */
325 name = udev_device_get_syspath(parent);
326
327 if (strstr(name, "/rport-") != NULL) {
328 parent = handle_scsi_fibre_channel(parent, path);
329 goto out;
330 }
331
332 if (strstr(name, "/end_device-") != NULL) {
333 parent = handle_scsi_sas(parent, path);
334 goto out;
335 }
336
337 if (strstr(name, "/session") != NULL) {
338 parent = handle_scsi_iscsi(parent, path);
339 goto out;
340 }
341
342 /*
343 * We do not support the ATA transport class, it creates duplicated link
344 * names as the fake SCSI host adapters are all separated, they are all
345 * re-based as host == 0. ATA should just stop faking two duplicated
346 * hierarchies for a single topology and leave the SCSI stuff alone;
347 * until that happens, there are no by-path/ links for ATA devices behind
348 * an ATA transport class.
349 */
350 if (strstr(name, "/ata") != NULL) {
351 parent = NULL;
352 goto out;
353 }
354
355 parent = handle_scsi_default(parent, path);
356 out:
357 return parent;
358 }
359
360 static struct udev_device *handle_cciss(struct udev_device *parent, char **path)
361 {
362 const char *str;
363 unsigned int controller, disk;
364
365 str = udev_device_get_sysname(parent);
366 if (sscanf(str, "c%ud%u%*s", &controller, &disk) != 2)
367 return NULL;
368
369 path_prepend(path, "cciss-disk%u", disk);
370 parent = skip_subsystem(parent, "cciss");
371 return parent;
372 }
373
374 static void handle_scsi_tape(struct udev_device *dev, char **path)
375 {
376 const char *name;
377
378 /* must be the last device in the syspath */
379 if (*path != NULL)
380 return;
381
382 name = udev_device_get_sysname(dev);
383 if (strncmp(name, "nst", 3) == 0 && strchr("lma", name[3]) != NULL)
384 path_prepend(path, "nst%c", name[3]);
385 else if (strncmp(name, "st", 2) == 0 && strchr("lma", name[2]) != NULL)
386 path_prepend(path, "st%c", name[2]);
387 }
388
389 static struct udev_device *handle_usb(struct udev_device *parent, char **path)
390 {
391 const char *devtype;
392 const char *str;
393 const char *port;
394
395 devtype = udev_device_get_devtype(parent);
396 if (devtype == NULL)
397 return parent;
398 if (strcmp(devtype, "usb_interface") != 0 && strcmp(devtype, "usb_device") != 0)
399 return parent;
400
401 str = udev_device_get_sysname(parent);
402 port = strchr(str, '-');
403 if (port == NULL)
404 return parent;
405 port++;
406
407 parent = skip_subsystem(parent, "usb");
408 path_prepend(path, "usb-0:%s", port);
409 return parent;
410 }
411
412 static struct udev_device *handle_ccw(struct udev_device *parent, struct udev_device *dev, char **path)
413 {
414 struct udev_device *scsi_dev;
415
416 scsi_dev = udev_device_get_parent_with_subsystem_devtype(dev, "scsi", "scsi_device");
417 if (scsi_dev != NULL) {
418 const char *wwpn;
419 const char *lun;
420 const char *hba_id;
421
422 hba_id = udev_device_get_sysattr_value(scsi_dev, "hba_id");
423 wwpn = udev_device_get_sysattr_value(scsi_dev, "wwpn");
424 lun = udev_device_get_sysattr_value(scsi_dev, "fcp_lun");
425 if (hba_id != NULL && lun != NULL && wwpn != NULL) {
426 path_prepend(path, "ccw-%s-zfcp-%s:%s", hba_id, wwpn, lun);
427 goto out;
428 }
429 }
430
431 path_prepend(path, "ccw-%s", udev_device_get_sysname(parent));
432 out:
433 parent = skip_subsystem(parent, "ccw");
434 return parent;
435 }
436
437 static int builtin_path_id(struct udev_device *dev, int argc, char *argv[], bool test)
438 {
439 struct udev_device *parent;
440 char *path = NULL;
441 bool some_transport = false;
442
443 /* S390 ccw bus */
444 parent = udev_device_get_parent_with_subsystem_devtype(dev, "ccw", NULL);
445 if (parent != NULL) {
446 handle_ccw(parent, dev, &path);
447 goto out;
448 }
449
450 /* walk up the chain of devices and compose path */
451 parent = dev;
452 while (parent != NULL) {
453 const char *subsys;
454
455 subsys = udev_device_get_subsystem(parent);
456 if (subsys == NULL) {
457 ;
458 } else if (strcmp(subsys, "scsi_tape") == 0) {
459 handle_scsi_tape(parent, &path);
460 } else if (strcmp(subsys, "scsi") == 0) {
461 parent = handle_scsi(parent, &path);
462 some_transport = true;
463 } else if (strcmp(subsys, "cciss") == 0) {
464 parent = handle_cciss(parent, &path);
465 some_transport = true;
466 } else if (strcmp(subsys, "usb") == 0) {
467 parent = handle_usb(parent, &path);
468 some_transport = true;
469 } else if (strcmp(subsys, "serio") == 0) {
470 path_prepend(&path, "serio-%s", udev_device_get_sysnum(parent));
471 parent = skip_subsystem(parent, "serio");
472 } else if (strcmp(subsys, "pci") == 0) {
473 path_prepend(&path, "pci-%s", udev_device_get_sysname(parent));
474 parent = skip_subsystem(parent, "pci");
475 } else if (strcmp(subsys, "platform") == 0) {
476 path_prepend(&path, "platform-%s", udev_device_get_sysname(parent));
477 parent = skip_subsystem(parent, "platform");
478 some_transport = true;
479 } else if (strcmp(subsys, "acpi") == 0) {
480 path_prepend(&path, "acpi-%s", udev_device_get_sysname(parent));
481 parent = skip_subsystem(parent, "acpi");
482 } else if (strcmp(subsys, "xen") == 0) {
483 path_prepend(&path, "xen-%s", udev_device_get_sysname(parent));
484 parent = skip_subsystem(parent, "xen");
485 } else if (strcmp(subsys, "virtio") == 0) {
486 path_prepend(&path, "virtio-pci-%s", udev_device_get_sysname(parent));
487 parent = skip_subsystem(parent, "virtio");
488 }
489
490 parent = udev_device_get_parent(parent);
491 }
492
493 /*
494 * Do not return a single-parent-device-only for block
495 * devices, they might have entire buses behind it which
496 * do not get unique IDs only by using the parent device.
497 */
498 if (!some_transport && !strcmp(udev_device_get_subsystem(dev), "block")) {
499 free(path);
500 path = NULL;
501 }
502
503 out:
504 if (path != NULL) {
505 char tag[UTIL_NAME_SIZE];
506 size_t i;
507 const char *p;
508
509 /* compose valid udev tag name */
510 for (p = path, i = 0; *p; p++) {
511 if ((*p >= '0' && *p <= '9') ||
512 (*p >= 'A' && *p <= 'Z') ||
513 (*p >= 'a' && *p <= 'z') ||
514 *p == '-') {
515 tag[i++] = *p;
516 continue;
517 }
518
519 /* skip all leading '_' */
520 if (i == 0)
521 continue;
522
523 /* avoid second '_' */
524 if (tag[i-1] == '_')
525 continue;
526
527 tag[i++] = '_';
528 }
529 /* strip trailing '_' */
530 while (i > 0 && tag[i-1] == '_')
531 i--;
532 tag[i] = '\0';
533
534 udev_builtin_add_property(dev, test, "ID_PATH", path);
535 udev_builtin_add_property(dev, test, "ID_PATH_TAG", tag);
536 free(path);
537 return EXIT_SUCCESS;
538 }
539 return EXIT_FAILURE;
540 }
541
542 const struct udev_builtin udev_builtin_path_id = {
543 .name = "path_id",
544 .cmd = builtin_path_id,
545 .help = "compose persistent device path",
546 .run_once = true,
547 };
File src/udev-builtin-usb_id.c added (mode: 100644) (index 0000000..85828e3)
1 /*
2 * USB device properties and persistent device path
3 *
4 * Copyright (c) 2005 SUSE Linux Products GmbH, Germany
5 * Author: Hannes Reinecke <hare@suse.de>
6 *
7 * Copyright (C) 2005-2011 Kay Sievers <kay.sievers@vrfy.org>
8 *
9 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <stdarg.h>
26 #include <unistd.h>
27 #include <string.h>
28 #include <ctype.h>
29 #include <fcntl.h>
30 #include <errno.h>
31
32 #include "udev.h"
33
34 static void set_usb_iftype(char *to, int if_class_num, size_t len)
35 {
36 char *type = "generic";
37
38 switch (if_class_num) {
39 case 1:
40 type = "audio";
41 break;
42 case 2: /* CDC-Control */
43 break;
44 case 3:
45 type = "hid";
46 break;
47 case 5: /* Physical */
48 break;
49 case 6:
50 type = "media";
51 break;
52 case 7:
53 type = "printer";
54 break;
55 case 8:
56 type = "storage";
57 break;
58 case 9:
59 type = "hub";
60 break;
61 case 0x0a: /* CDC-Data */
62 break;
63 case 0x0b: /* Chip/Smart Card */
64 break;
65 case 0x0d: /* Content Security */
66 break;
67 case 0x0e:
68 type = "video";
69 break;
70 case 0xdc: /* Diagnostic Device */
71 break;
72 case 0xe0: /* Wireless Controller */
73 break;
74 case 0xfe: /* Application-specific */
75 break;
76 case 0xff: /* Vendor-specific */
77 break;
78 default:
79 break;
80 }
81 strncpy(to, type, len);
82 to[len-1] = '\0';
83 }
84
85 static int set_usb_mass_storage_ifsubtype(char *to, const char *from, size_t len)
86 {
87 int type_num = 0;
88 char *eptr;
89 char *type = "generic";
90
91 type_num = strtoul(from, &eptr, 0);
92 if (eptr != from) {
93 switch (type_num) {
94 case 2:
95 type = "atapi";
96 break;
97 case 3:
98 type = "tape";
99 break;
100 case 4: /* UFI */
101 case 5: /* SFF-8070i */
102 type = "floppy";
103 break;
104 case 1: /* RBC devices */
105 type = "rbc";
106 break;
107 case 6: /* Transparent SPC-2 devices */
108 type = "scsi";
109 break;
110 default:
111 break;
112 }
113 }
114 util_strscpy(to, len, type);
115 return type_num;
116 }
117
118 static void set_scsi_type(char *to, const char *from, size_t len)
119 {
120 int type_num;
121 char *eptr;
122 char *type = "generic";
123
124 type_num = strtoul(from, &eptr, 0);
125 if (eptr != from) {
126 switch (type_num) {
127 case 0:
128 case 0xe:
129 type = "disk";
130 break;
131 case 1:
132 type = "tape";
133 break;
134 case 4:
135 case 7:
136 case 0xf:
137 type = "optical";
138 break;
139 case 5:
140 type = "cd";
141 break;
142 default:
143 break;
144 }
145 }
146 util_strscpy(to, len, type);
147 }
148
149 #define USB_DT_DEVICE 0x01
150 #define USB_DT_INTERFACE 0x04
151
152 static int dev_if_packed_info(struct udev_device *dev, char *ifs_str, size_t len)
153 {
154 char *filename = NULL;
155 int fd;
156 ssize_t size;
157 unsigned char buf[18 + 65535];
158 unsigned int pos, strpos;
159 struct usb_interface_descriptor {
160 u_int8_t bLength;
161 u_int8_t bDescriptorType;
162 u_int8_t bInterfaceNumber;
163 u_int8_t bAlternateSetting;
164 u_int8_t bNumEndpoints;
165 u_int8_t bInterfaceClass;
166 u_int8_t bInterfaceSubClass;
167 u_int8_t bInterfaceProtocol;
168 u_int8_t iInterface;
169 } __attribute__((packed));
170 int err = 0;
171
172 if (asprintf(&filename, "%s/descriptors", udev_device_get_syspath(dev)) < 0) {
173 err = -1;
174 goto out;
175 }
176 fd = open(filename, O_RDONLY|O_CLOEXEC);
177 if (fd < 0) {
178 fprintf(stderr, "error opening USB device 'descriptors' file\n");
179 err = -1;
180 goto out;
181 }
182 size = read(fd, buf, sizeof(buf));
183 close(fd);
184 if (size < 18 || size == sizeof(buf)) {
185 err = -1;
186 goto out;
187 }
188
189 pos = 0;
190 strpos = 0;
191 ifs_str[0] = '\0';
192 while (pos < sizeof(buf) && strpos+7 < len-2) {
193 struct usb_interface_descriptor *desc;
194 char if_str[8];
195
196 desc = (struct usb_interface_descriptor *) &buf[pos];
197 if (desc->bLength < 3)
198 break;
199 pos += desc->bLength;
200
201 if (desc->bDescriptorType != USB_DT_INTERFACE)
202 continue;
203
204 if (snprintf(if_str, 8, ":%02x%02x%02x",
205 desc->bInterfaceClass,
206 desc->bInterfaceSubClass,
207 desc->bInterfaceProtocol) != 7)
208 continue;
209
210 if (strstr(ifs_str, if_str) != NULL)
211 continue;
212
213 memcpy(&ifs_str[strpos], if_str, 8),
214 strpos += 7;
215 }
216 if (strpos > 0) {
217 ifs_str[strpos++] = ':';
218 ifs_str[strpos++] = '\0';
219 }
220 out:
221 free(filename);
222 return err;
223 }
224
225 /*
226 * A unique USB identification is generated like this:
227 *
228 * 1.) Get the USB device type from InterfaceClass and InterfaceSubClass
229 * 2.) If the device type is 'Mass-Storage/SPC-2' or 'Mass-Storage/RBC'
230 * use the SCSI vendor and model as USB-Vendor and USB-model.
231 * 3.) Otherwise use the USB manufacturer and product as
232 * USB-Vendor and USB-model. Any non-printable characters
233 * in those strings will be skipped; a slash '/' will be converted
234 * into a full stop '.'.
235 * 4.) If that fails, too, we will use idVendor and idProduct
236 * as USB-Vendor and USB-model.
237 * 5.) The USB identification is the USB-vendor and USB-model
238 * string concatenated with an underscore '_'.
239 * 6.) If the device supplies a serial number, this number
240 * is concatenated with the identification with an underscore '_'.
241 */
242 static int builtin_usb_id(struct udev_device *dev, int argc, char *argv[], bool test)
243 {
244 char vendor_str[64];
245 char vendor_str_enc[256];
246 const char *vendor_id;
247 char model_str[64];
248 char model_str_enc[256];
249 const char *product_id;
250 char serial_str[UTIL_NAME_SIZE];
251 char packed_if_str[UTIL_NAME_SIZE];
252 char revision_str[64];
253 char type_str[64];
254 char instance_str[64];
255 const char *ifnum = NULL;
256 const char *driver = NULL;
257 char serial[256];
258
259 struct udev *udev = udev_device_get_udev(dev);
260 struct udev_device *dev_interface = NULL;
261 struct udev_device *dev_usb = NULL;
262 const char *if_class, *if_subclass;
263 int if_class_num;
264 int protocol = 0;
265 size_t l;
266 char *s;
267
268 vendor_str[0] = '\0';
269 model_str[0] = '\0';
270 serial_str[0] = '\0';
271 packed_if_str[0] = '\0';
272 revision_str[0] = '\0';
273 type_str[0] = '\0';
274 instance_str[0] = '\0';
275
276 dbg(udev, "syspath %s\n", udev_device_get_syspath(dev));
277
278 /* shortcut, if we are called directly for a "usb_device" type */
279 if (udev_device_get_devtype(dev) != NULL && strcmp(udev_device_get_devtype(dev), "usb_device") == 0) {
280 dev_if_packed_info(dev, packed_if_str, sizeof(packed_if_str));
281 dev_usb = dev;
282 goto fallback;
283 }
284
285 /* usb interface directory */
286 dev_interface = udev_device_get_parent_with_subsystem_devtype(dev, "usb", "usb_interface");
287 if (dev_interface == NULL) {
288 info(udev, "unable to access usb_interface device of '%s'\n",
289 udev_device_get_syspath(dev));
290 return EXIT_FAILURE;
291 }
292
293 ifnum = udev_device_get_sysattr_value(dev_interface, "bInterfaceNumber");
294 driver = udev_device_get_sysattr_value(dev_interface, "driver");
295
296 if_class = udev_device_get_sysattr_value(dev_interface, "bInterfaceClass");
297 if (!if_class) {
298 info(udev, "%s: cannot get bInterfaceClass attribute\n",
299 udev_device_get_sysname(dev));
300 return EXIT_FAILURE;
301 }
302
303 if_class_num = strtoul(if_class, NULL, 16);
304 if (if_class_num == 8) {
305 /* mass storage */
306 if_subclass = udev_device_get_sysattr_value(dev_interface, "bInterfaceSubClass");
307 if (if_subclass != NULL)
308 protocol = set_usb_mass_storage_ifsubtype(type_str, if_subclass, sizeof(type_str)-1);
309 } else {
310 set_usb_iftype(type_str, if_class_num, sizeof(type_str)-1);
311 }
312
313 info(udev, "%s: if_class %d protocol %d\n",
314 udev_device_get_syspath(dev_interface), if_class_num, protocol);
315
316 /* usb device directory */
317 dev_usb = udev_device_get_parent_with_subsystem_devtype(dev_interface, "usb", "usb_device");
318 if (!dev_usb) {
319 info(udev, "unable to find parent 'usb' device of '%s'\n",
320 udev_device_get_syspath(dev));
321 return EXIT_FAILURE;
322 }
323
324 /* all interfaces of the device in a single string */
325 dev_if_packed_info(dev_usb, packed_if_str, sizeof(packed_if_str));
326
327 /* mass storage : SCSI or ATAPI */
328 if ((protocol == 6 || protocol == 2)) {
329 struct udev_device *dev_scsi;
330 const char *scsi_model, *scsi_vendor, *scsi_type, *scsi_rev;
331 int host, bus, target, lun;
332
333 /* get scsi device */
334 dev_scsi = udev_device_get_parent_with_subsystem_devtype(dev, "scsi", "scsi_device");
335 if (dev_scsi == NULL) {
336 info(udev, "unable to find parent 'scsi' device of '%s'\n",
337 udev_device_get_syspath(dev));
338 goto fallback;
339 }
340 if (sscanf(udev_device_get_sysname(dev_scsi), "%d:%d:%d:%d", &host, &bus, &target, &lun) != 4) {
341 info(udev, "invalid scsi device '%s'\n", udev_device_get_sysname(dev_scsi));
342 goto fallback;
343 }
344
345 /* Generic SPC-2 device */
346 scsi_vendor = udev_device_get_sysattr_value(dev_scsi, "vendor");
347 if (!scsi_vendor) {
348 info(udev, "%s: cannot get SCSI vendor attribute\n",
349 udev_device_get_sysname(dev_scsi));
350 goto fallback;
351 }
352 udev_util_encode_string(scsi_vendor, vendor_str_enc, sizeof(vendor_str_enc));
353 util_replace_whitespace(scsi_vendor, vendor_str, sizeof(vendor_str)-1);
354 util_replace_chars(vendor_str, NULL);
355
356 scsi_model = udev_device_get_sysattr_value(dev_scsi, "model");
357 if (!scsi_model) {
358 info(udev, "%s: cannot get SCSI model attribute\n",
359 udev_device_get_sysname(dev_scsi));
360 goto fallback;
361 }
362 udev_util_encode_string(scsi_model, model_str_enc, sizeof(model_str_enc));
363 util_replace_whitespace(scsi_model, model_str, sizeof(model_str)-1);
364 util_replace_chars(model_str, NULL);
365
366 scsi_type = udev_device_get_sysattr_value(dev_scsi, "type");
367 if (!scsi_type) {
368 info(udev, "%s: cannot get SCSI type attribute\n",
369 udev_device_get_sysname(dev_scsi));
370 goto fallback;
371 }
372 set_scsi_type(type_str, scsi_type, sizeof(type_str)-1);
373
374 scsi_rev = udev_device_get_sysattr_value(dev_scsi, "rev");
375 if (!scsi_rev) {
376 info(udev, "%s: cannot get SCSI revision attribute\n",
377 udev_device_get_sysname(dev_scsi));
378 goto fallback;
379 }
380 util_replace_whitespace(scsi_rev, revision_str, sizeof(revision_str)-1);
381 util_replace_chars(revision_str, NULL);
382
383 /*
384 * some broken devices have the same identifiers
385 * for all luns, export the target:lun number
386 */
387 sprintf(instance_str, "%d:%d", target, lun);
388 }
389
390 fallback:
391 vendor_id = udev_device_get_sysattr_value(dev_usb, "idVendor");
392 product_id = udev_device_get_sysattr_value(dev_usb, "idProduct");
393
394 /* fallback to USB vendor & device */
395 if (vendor_str[0] == '\0') {
396 const char *usb_vendor = NULL;
397
398 usb_vendor = udev_device_get_sysattr_value(dev_usb, "manufacturer");
399 if (!usb_vendor)
400 usb_vendor = vendor_id;
401 if (!usb_vendor) {
402 info(udev, "No USB vendor information available\n");
403 return EXIT_FAILURE;
404 }
405 udev_util_encode_string(usb_vendor, vendor_str_enc, sizeof(vendor_str_enc));
406 util_replace_whitespace(usb_vendor, vendor_str, sizeof(vendor_str)-1);
407 util_replace_chars(vendor_str, NULL);
408 }
409
410 if (model_str[0] == '\0') {
411 const char *usb_model = NULL;
412
413 usb_model = udev_device_get_sysattr_value(dev_usb, "product");
414 if (!usb_model)
415 usb_model = product_id;
416 if (!usb_model) {
417 dbg(udev, "No USB model information available\n");
418 return EXIT_FAILURE;
419 }
420 udev_util_encode_string(usb_model, model_str_enc, sizeof(model_str_enc));
421 util_replace_whitespace(usb_model, model_str, sizeof(model_str)-1);
422 util_replace_chars(model_str, NULL);
423 }
424
425 if (revision_str[0] == '\0') {
426 const char *usb_rev;
427
428 usb_rev = udev_device_get_sysattr_value(dev_usb, "bcdDevice");
429 if (usb_rev) {
430 util_replace_whitespace(usb_rev, revision_str, sizeof(revision_str)-1);
431 util_replace_chars(revision_str, NULL);
432 }
433 }
434
435 if (serial_str[0] == '\0') {
436 const char *usb_serial;
437
438 usb_serial = udev_device_get_sysattr_value(dev_usb, "serial");
439 if (usb_serial) {
440 util_replace_whitespace(usb_serial, serial_str, sizeof(serial_str)-1);
441 util_replace_chars(serial_str, NULL);
442 }
443 }
444
445 s = serial;
446 l = util_strpcpyl(&s, sizeof(serial), vendor_str, "_", model_str, NULL);
447 if (serial_str[0] != '\0')
448 l = util_strpcpyl(&s, l, "_", serial_str, NULL);
449
450 if (instance_str[0] != '\0')
451 util_strpcpyl(&s, l, "-", instance_str, NULL);
452
453 udev_builtin_add_property(dev, test, "ID_VENDOR", vendor_str);
454 udev_builtin_add_property(dev, test, "ID_VENDOR_ENC", vendor_str_enc);
455 udev_builtin_add_property(dev, test, "ID_VENDOR_ID", vendor_id);
456 udev_builtin_add_property(dev, test, "ID_MODEL", model_str);
457 udev_builtin_add_property(dev, test, "ID_MODEL_ENC", model_str_enc);
458 udev_builtin_add_property(dev, test, "ID_MODEL_ID", product_id);
459 udev_builtin_add_property(dev, test, "ID_REVISION", revision_str);
460 udev_builtin_add_property(dev, test, "ID_SERIAL", serial);
461 if (serial_str[0] != '\0')
462 udev_builtin_add_property(dev, test, "ID_SERIAL_SHORT", serial_str);
463 if (type_str[0] != '\0')
464 udev_builtin_add_property(dev, test, "ID_TYPE", type_str);
465 if (instance_str[0] != '\0')
466 udev_builtin_add_property(dev, test, "ID_INSTANCE", instance_str);
467 udev_builtin_add_property(dev, test, "ID_BUS", "usb");
468 if (packed_if_str[0] != '\0')
469 udev_builtin_add_property(dev, test, "ID_USB_INTERFACES", packed_if_str);
470 if (ifnum != NULL)
471 udev_builtin_add_property(dev, test, "ID_USB_INTERFACE_NUM", ifnum);
472 if (driver != NULL)
473 udev_builtin_add_property(dev, test, "ID_USB_DRIVER", driver);
474 return EXIT_SUCCESS;
475 }
476
477 const struct udev_builtin udev_builtin_usb_id = {
478 .name = "usb_id",
479 .cmd = builtin_usb_id,
480 .help = "usb device properties",
481 .run_once = true,
482 };
File src/udev-builtin.c added (mode: 100644) (index 0000000..a2fafda)
1 /*
2 * Copyright (C) 2007-2009 Kay Sievers <kay.sievers@vrfy.org>
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include <unistd.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <stddef.h>
22 #include <string.h>
23 #include <errno.h>
24 #include <getopt.h>
25
26 #include "udev.h"
27
28 static const struct udev_builtin *builtins[] = {
29 [UDEV_BUILTIN_BLKID] = &udev_builtin_blkid,
30 [UDEV_BUILTIN_FIRMWARE] = &udev_builtin_firmware,
31 [UDEV_BUILTIN_INPUT_ID] = &udev_builtin_input_id,
32 [UDEV_BUILTIN_KMOD] = &udev_builtin_kmod,
33 [UDEV_BUILTIN_PATH_ID] = &udev_builtin_path_id,
34 [UDEV_BUILTIN_PCI_DB] = &udev_builtin_pci_db,
35 [UDEV_BUILTIN_USB_DB] = &udev_builtin_usb_db,
36 [UDEV_BUILTIN_USB_ID] = &udev_builtin_usb_id,
37 };
38
39 int udev_builtin_init(struct udev *udev)
40 {
41 unsigned int i;
42 int err = 0;
43
44 for (i = 0; i < ARRAY_SIZE(builtins); i++) {
45 if (builtins[i]->init) {
46 err = builtins[i]->init(udev);
47 if (err < 0)
48 break;
49 }
50 }
51 return err;
52 }
53
54 void udev_builtin_exit(struct udev *udev)
55 {
56 unsigned int i;
57
58 for (i = 0; i < ARRAY_SIZE(builtins); i++)
59 if (builtins[i]->exit)
60 builtins[i]->exit(udev);
61 }
62
63 bool udev_builtin_validate(struct udev *udev)
64 {
65 unsigned int i;
66 bool change = false;
67
68 for (i = 0; i < ARRAY_SIZE(builtins); i++)
69 if (builtins[i]->validate)
70 if (builtins[i]->validate(udev))
71 change = true;
72 return change;
73 }
74
75 void udev_builtin_list(struct udev *udev)
76 {
77 unsigned int i;
78
79 for (i = 0; i < ARRAY_SIZE(builtins); i++)
80 fprintf(stderr, " %-12s %s\n", builtins[i]->name, builtins[i]->help);
81 }
82
83 const char *udev_builtin_name(enum udev_builtin_cmd cmd)
84 {
85 return builtins[cmd]->name;
86 }
87
88 bool udev_builtin_run_once(enum udev_builtin_cmd cmd)
89 {
90 return builtins[cmd]->run_once;
91 }
92
93 enum udev_builtin_cmd udev_builtin_lookup(const char *command)
94 {
95 char name[UTIL_PATH_SIZE];
96 enum udev_builtin_cmd i;
97 char *pos;
98
99 util_strscpy(name, sizeof(name), command);
100 pos = strchr(name, ' ');
101 if (pos)
102 pos[0] = '\0';
103 for (i = 0; i < ARRAY_SIZE(builtins); i++)
104 if (strcmp(builtins[i]->name, name) == 0)
105 return i;
106 return UDEV_BUILTIN_MAX;
107 }
108
109 int udev_builtin_run(struct udev_device *dev, enum udev_builtin_cmd cmd, const char *command, bool test)
110 {
111 char arg[UTIL_PATH_SIZE];
112 int argc;
113 char *argv[128];
114
115 optind = 0;
116 util_strscpy(arg, sizeof(arg), command);
117 udev_build_argv(udev_device_get_udev(dev), arg, &argc, argv);
118 return builtins[cmd]->cmd(dev, argc, argv, test);
119 }
120
121 int udev_builtin_add_property(struct udev_device *dev, bool test, const char *key, const char *val)
122 {
123 struct udev_list_entry *entry;
124
125 entry = udev_device_add_property(dev, key, val);
126 /* store in db, skip private keys */
127 if (key[0] != '.')
128 udev_list_entry_set_num(entry, true);
129
130 info(udev_device_get_udev(dev), "%s=%s\n", key, val);
131 if (test)
132 printf("%s=%s\n", key, val);
133 return 0;
134 }
File src/udev-ctrl.c added (mode: 100644) (index 0000000..5556f1a)
1 /*
2 * libudev - interface to udev device information
3 *
4 * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 */
11
12 #include <errno.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <stddef.h>
16 #include <string.h>
17 #include <unistd.h>
18 #include <sys/types.h>
19 #include <sys/poll.h>
20 #include <sys/socket.h>
21 #include <sys/un.h>
22
23 #include "udev.h"
24
25 /* wire protocol magic must match */
26 #define UDEV_CTRL_MAGIC 0xdead1dea
27
28 enum udev_ctrl_msg_type {
29 UDEV_CTRL_UNKNOWN,
30 UDEV_CTRL_SET_LOG_LEVEL,
31 UDEV_CTRL_STOP_EXEC_QUEUE,
32 UDEV_CTRL_START_EXEC_QUEUE,
33 UDEV_CTRL_RELOAD,
34 UDEV_CTRL_SET_ENV,
35 UDEV_CTRL_SET_CHILDREN_MAX,
36 UDEV_CTRL_PING,
37 UDEV_CTRL_EXIT,
38 };
39
40 struct udev_ctrl_msg_wire {
41 char version[16];
42 unsigned int magic;
43 enum udev_ctrl_msg_type type;
44 union {
45 int intval;
46 char buf[256];
47 };
48 };
49
50 struct udev_ctrl_msg {
51 int refcount;
52 struct udev_ctrl_connection *conn;
53 struct udev_ctrl_msg_wire ctrl_msg_wire;
54 };
55
56 struct udev_ctrl {
57 int refcount;
58 struct udev *udev;
59 int sock;
60 struct sockaddr_un saddr;
61 socklen_t addrlen;
62 bool bound;
63 bool cleanup_socket;
64 bool connected;
65 };
66
67 struct udev_ctrl_connection {
68 int refcount;
69 struct udev_ctrl *uctrl;
70 int sock;
71 };
72
73 struct udev_ctrl *udev_ctrl_new_from_fd(struct udev *udev, int fd)
74 {
75 struct udev_ctrl *uctrl;
76
77 uctrl = calloc(1, sizeof(struct udev_ctrl));
78 if (uctrl == NULL)
79 return NULL;
80 uctrl->refcount = 1;
81 uctrl->udev = udev;
82
83 if (fd < 0) {
84 uctrl->sock = socket(AF_LOCAL, SOCK_SEQPACKET|SOCK_NONBLOCK|SOCK_CLOEXEC, 0);
85 if (uctrl->sock < 0) {
86 err(udev, "error getting socket: %m\n");
87 udev_ctrl_unref(uctrl);
88 return NULL;
89 }
90 } else {
91 uctrl->bound = true;
92 uctrl->sock = fd;
93 }
94
95 uctrl->saddr.sun_family = AF_LOCAL;
96 util_strscpyl(uctrl->saddr.sun_path, sizeof(uctrl->saddr.sun_path),
97 udev_get_run_path(udev), "/control", NULL);
98 uctrl->addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(uctrl->saddr.sun_path);
99 return uctrl;
100 }
101
102 struct udev_ctrl *udev_ctrl_new(struct udev *udev)
103 {
104 return udev_ctrl_new_from_fd(udev, -1);
105 }
106
107 int udev_ctrl_enable_receiving(struct udev_ctrl *uctrl)
108 {
109 int err;
110
111 if (!uctrl->bound) {
112 err = bind(uctrl->sock, (struct sockaddr *)&uctrl->saddr, uctrl->addrlen);
113 if (err < 0 && errno == EADDRINUSE) {
114 unlink(uctrl->saddr.sun_path);
115 err = bind(uctrl->sock, (struct sockaddr *)&uctrl->saddr, uctrl->addrlen);
116 }
117
118 if (err < 0) {
119 err = -errno;
120 err(uctrl->udev, "bind failed: %m\n");
121 return err;
122 }
123
124 err = listen(uctrl->sock, 0);
125 if (err < 0) {
126 err = -errno;
127 err(uctrl->udev, "listen failed: %m\n");
128 return err;
129 }
130
131 uctrl->bound = true;
132 uctrl->cleanup_socket = true;
133 }
134 return 0;
135 }
136
137 struct udev *udev_ctrl_get_udev(struct udev_ctrl *uctrl)
138 {
139 return uctrl->udev;
140 }
141
142 struct udev_ctrl *udev_ctrl_ref(struct udev_ctrl *uctrl)
143 {
144 if (uctrl == NULL)
145 return NULL;
146 uctrl->refcount++;
147 return uctrl;
148 }
149
150 struct udev_ctrl *udev_ctrl_unref(struct udev_ctrl *uctrl)
151 {
152 if (uctrl == NULL)
153 return NULL;
154 uctrl->refcount--;
155 if (uctrl->refcount > 0)
156 return uctrl;
157 if (uctrl->sock >= 0)
158 close(uctrl->sock);
159 free(uctrl);
160 return NULL;
161 }
162
163 int udev_ctrl_cleanup(struct udev_ctrl *uctrl)
164 {
165 if (uctrl == NULL)
166 return 0;
167 if (uctrl->cleanup_socket)
168 unlink(uctrl->saddr.sun_path);
169 return 0;
170 }
171
172 int udev_ctrl_get_fd(struct udev_ctrl *uctrl)
173 {
174 if (uctrl == NULL)
175 return -EINVAL;
176 return uctrl->sock;
177 }
178
179 struct udev_ctrl_connection *udev_ctrl_get_connection(struct udev_ctrl *uctrl)
180 {
181 struct udev_ctrl_connection *conn;
182 struct ucred ucred;
183 socklen_t slen;
184 const int on = 1;
185
186 conn = calloc(1, sizeof(struct udev_ctrl_connection));
187 if (conn == NULL)
188 return NULL;
189 conn->refcount = 1;
190 conn->uctrl = uctrl;
191
192 conn->sock = accept4(uctrl->sock, NULL, NULL, SOCK_CLOEXEC|SOCK_NONBLOCK);
193 if (conn->sock < 0) {
194 if (errno != EINTR)
195 err(uctrl->udev, "unable to receive ctrl connection: %m\n");
196 goto err;
197 }
198
199 /* check peer credential of connection */
200 slen = sizeof(ucred);
201 if (getsockopt(conn->sock, SOL_SOCKET, SO_PEERCRED, &ucred, &slen) < 0) {
202 err(uctrl->udev, "unable to receive credentials of ctrl connection: %m\n");
203 goto err;
204 }
205 if (ucred.uid > 0) {
206 err(uctrl->udev, "sender uid=%i, message ignored\n", ucred.uid);
207 goto err;
208 }
209
210 /* enable receiving of the sender credentials in the messages */
211 setsockopt(conn->sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
212 udev_ctrl_ref(uctrl);
213 return conn;
214 err:
215 if (conn->sock >= 0)
216 close(conn->sock);
217 free(conn);
218 return NULL;
219 }
220
221 struct udev_ctrl_connection *udev_ctrl_connection_ref(struct udev_ctrl_connection *conn)
222 {
223 if (conn == NULL)
224 return NULL;
225 conn->refcount++;
226 return conn;
227 }
228
229 struct udev_ctrl_connection *udev_ctrl_connection_unref(struct udev_ctrl_connection *conn)
230 {
231 if (conn == NULL)
232 return NULL;
233 conn->refcount--;
234 if (conn->refcount > 0)
235 return conn;
236 if (conn->sock >= 0)
237 close(conn->sock);
238 udev_ctrl_unref(conn->uctrl);
239 free(conn);
240 return NULL;
241 }
242
243 static int ctrl_send(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, int intval, const char *buf, int timeout)
244 {
245 struct udev_ctrl_msg_wire ctrl_msg_wire;
246 int err = 0;
247
248 memset(&ctrl_msg_wire, 0x00, sizeof(struct udev_ctrl_msg_wire));
249 strcpy(ctrl_msg_wire.version, "udev-" VERSION);
250 ctrl_msg_wire.magic = UDEV_CTRL_MAGIC;
251 ctrl_msg_wire.type = type;
252
253 if (buf != NULL)
254 util_strscpy(ctrl_msg_wire.buf, sizeof(ctrl_msg_wire.buf), buf);
255 else
256 ctrl_msg_wire.intval = intval;
257
258 if (!uctrl->connected) {
259 if (connect(uctrl->sock, (struct sockaddr *)&uctrl->saddr, uctrl->addrlen) < 0) {
260 err = -errno;
261 goto out;
262 }
263 uctrl->connected = true;
264 }
265 if (send(uctrl->sock, &ctrl_msg_wire, sizeof(ctrl_msg_wire), 0) < 0) {
266 err = -errno;
267 goto out;
268 }
269
270 /* wait for peer message handling or disconnect */
271 for (;;) {
272 struct pollfd pfd[1];
273 int r;
274
275 pfd[0].fd = uctrl->sock;
276 pfd[0].events = POLLIN;
277 r = poll(pfd, 1, timeout * 1000);
278 if (r < 0) {
279 if (errno == EINTR)
280 continue;
281 err = -errno;
282 break;
283 }
284
285 if (r > 0 && pfd[0].revents & POLLERR) {
286 err = -EIO;
287 break;
288 }
289
290 if (r == 0)
291 err = -ETIMEDOUT;
292 break;
293 }
294 out:
295 return err;
296 }
297
298 int udev_ctrl_send_set_log_level(struct udev_ctrl *uctrl, int priority, int timeout)
299 {
300 return ctrl_send(uctrl, UDEV_CTRL_SET_LOG_LEVEL, priority, NULL, timeout);
301 }
302
303 int udev_ctrl_send_stop_exec_queue(struct udev_ctrl *uctrl, int timeout)
304 {
305 return ctrl_send(uctrl, UDEV_CTRL_STOP_EXEC_QUEUE, 0, NULL, timeout);
306 }
307
308 int udev_ctrl_send_start_exec_queue(struct udev_ctrl *uctrl, int timeout)
309 {
310 return ctrl_send(uctrl, UDEV_CTRL_START_EXEC_QUEUE, 0, NULL, timeout);
311 }
312
313 int udev_ctrl_send_reload(struct udev_ctrl *uctrl, int timeout)
314 {
315 return ctrl_send(uctrl, UDEV_CTRL_RELOAD, 0, NULL, timeout);
316 }
317
318 int udev_ctrl_send_set_env(struct udev_ctrl *uctrl, const char *key, int timeout)
319 {
320 return ctrl_send(uctrl, UDEV_CTRL_SET_ENV, 0, key, timeout);
321 }
322
323 int udev_ctrl_send_set_children_max(struct udev_ctrl *uctrl, int count, int timeout)
324 {
325 return ctrl_send(uctrl, UDEV_CTRL_SET_CHILDREN_MAX, count, NULL, timeout);
326 }
327
328 int udev_ctrl_send_ping(struct udev_ctrl *uctrl, int timeout)
329 {
330 return ctrl_send(uctrl, UDEV_CTRL_PING, 0, NULL, timeout);
331 }
332
333 int udev_ctrl_send_exit(struct udev_ctrl *uctrl, int timeout)
334 {
335 return ctrl_send(uctrl, UDEV_CTRL_EXIT, 0, NULL, timeout);
336 }
337
338 struct udev_ctrl_msg *udev_ctrl_receive_msg(struct udev_ctrl_connection *conn)
339 {
340 struct udev *udev = conn->uctrl->udev;
341 struct udev_ctrl_msg *uctrl_msg;
342 ssize_t size;
343 struct msghdr smsg;
344 struct cmsghdr *cmsg;
345 struct iovec iov;
346 struct ucred *cred;
347 char cred_msg[CMSG_SPACE(sizeof(struct ucred))];
348
349 uctrl_msg = calloc(1, sizeof(struct udev_ctrl_msg));
350 if (uctrl_msg == NULL)
351 return NULL;
352 uctrl_msg->refcount = 1;
353 uctrl_msg->conn = conn;
354 udev_ctrl_connection_ref(conn);
355
356 /* wait for the incoming message */
357 for(;;) {
358 struct pollfd pfd[1];
359 int r;
360
361 pfd[0].fd = conn->sock;
362 pfd[0].events = POLLIN;
363
364 r = poll(pfd, 1, 10000);
365 if (r < 0) {
366 if (errno == EINTR)
367 continue;
368 goto err;
369 } else if (r == 0) {
370 err(udev, "timeout waiting for ctrl message\n");
371 goto err;
372 } else {
373 if (!(pfd[0].revents & POLLIN)) {
374 err(udev, "ctrl connection error: %m\n");
375 goto err;
376 }
377 }
378
379 break;
380 }
381
382 iov.iov_base = &uctrl_msg->ctrl_msg_wire;
383 iov.iov_len = sizeof(struct udev_ctrl_msg_wire);
384 memset(&smsg, 0x00, sizeof(struct msghdr));
385 smsg.msg_iov = &iov;
386 smsg.msg_iovlen = 1;
387 smsg.msg_control = cred_msg;
388 smsg.msg_controllen = sizeof(cred_msg);
389 size = recvmsg(conn->sock, &smsg, 0);
390 if (size < 0) {
391 err(udev, "unable to receive ctrl message: %m\n");
392 goto err;
393 }
394 cmsg = CMSG_FIRSTHDR(&smsg);
395 cred = (struct ucred *) CMSG_DATA(cmsg);
396
397 if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) {
398 err(udev, "no sender credentials received, message ignored\n");
399 goto err;
400 }
401
402 if (cred->uid != 0) {
403 err(udev, "sender uid=%i, message ignored\n", cred->uid);
404 goto err;
405 }
406
407 if (uctrl_msg->ctrl_msg_wire.magic != UDEV_CTRL_MAGIC) {
408 err(udev, "message magic 0x%08x doesn't match, ignore it\n", uctrl_msg->ctrl_msg_wire.magic);
409 goto err;
410 }
411
412 dbg(udev, "created ctrl_msg %p (%i)\n", uctrl_msg, uctrl_msg->ctrl_msg_wire.type);
413 return uctrl_msg;
414 err:
415 udev_ctrl_msg_unref(uctrl_msg);
416 return NULL;
417 }
418
419 struct udev_ctrl_msg *udev_ctrl_msg_ref(struct udev_ctrl_msg *ctrl_msg)
420 {
421 if (ctrl_msg == NULL)
422 return NULL;
423 ctrl_msg->refcount++;
424 return ctrl_msg;
425 }
426
427 struct udev_ctrl_msg *udev_ctrl_msg_unref(struct udev_ctrl_msg *ctrl_msg)
428 {
429 if (ctrl_msg == NULL)
430 return NULL;
431 ctrl_msg->refcount--;
432 if (ctrl_msg->refcount > 0)
433 return ctrl_msg;
434 dbg(ctrl_msg->conn->uctrl->udev, "release ctrl_msg %p\n", ctrl_msg);
435 udev_ctrl_connection_unref(ctrl_msg->conn);
436 free(ctrl_msg);
437 return NULL;
438 }
439
440 int udev_ctrl_get_set_log_level(struct udev_ctrl_msg *ctrl_msg)
441 {
442 if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_SET_LOG_LEVEL)
443 return ctrl_msg->ctrl_msg_wire.intval;
444 return -1;
445 }
446
447 int udev_ctrl_get_stop_exec_queue(struct udev_ctrl_msg *ctrl_msg)
448 {
449 if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_STOP_EXEC_QUEUE)
450 return 1;
451 return -1;
452 }
453
454 int udev_ctrl_get_start_exec_queue(struct udev_ctrl_msg *ctrl_msg)
455 {
456 if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_START_EXEC_QUEUE)
457 return 1;
458 return -1;
459 }
460
461 int udev_ctrl_get_reload(struct udev_ctrl_msg *ctrl_msg)
462 {
463 if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_RELOAD)
464 return 1;
465 return -1;
466 }
467
468 const char *udev_ctrl_get_set_env(struct udev_ctrl_msg *ctrl_msg)
469 {
470 if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_SET_ENV)
471 return ctrl_msg->ctrl_msg_wire.buf;
472 return NULL;
473 }
474
475 int udev_ctrl_get_set_children_max(struct udev_ctrl_msg *ctrl_msg)
476 {
477 if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_SET_CHILDREN_MAX)
478 return ctrl_msg->ctrl_msg_wire.intval;
479 return -1;
480 }
481
482 int udev_ctrl_get_ping(struct udev_ctrl_msg *ctrl_msg)
483 {
484 if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_PING)
485 return 1;
486 return -1;
487 }
488
489 int udev_ctrl_get_exit(struct udev_ctrl_msg *ctrl_msg)
490 {
491 if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_EXIT)
492 return 1;
493 return -1;
494 }
File src/udev-event.c added (mode: 100644) (index 0000000..63df9e8)
1 /*
2 * Copyright (C) 2003-2010 Kay Sievers <kay.sievers@vrfy.org>
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <stddef.h>
21 #include <unistd.h>
22 #include <fcntl.h>
23 #include <errno.h>
24 #include <ctype.h>
25 #include <string.h>
26 #include <time.h>
27 #include <net/if.h>
28 #include <sys/ioctl.h>
29 #include <sys/prctl.h>
30 #include <sys/poll.h>
31 #include <sys/epoll.h>
32 #include <sys/wait.h>
33 #include <sys/socket.h>
34 #include <sys/signalfd.h>
35 #include <linux/sockios.h>
36
37 #include "udev.h"
38
39 struct udev_event *udev_event_new(struct udev_device *dev)
40 {
41 struct udev *udev = udev_device_get_udev(dev);
42 struct udev_event *event;
43
44 event = calloc(1, sizeof(struct udev_event));
45 if (event == NULL)
46 return NULL;
47 event->dev = dev;
48 event->udev = udev;
49 udev_list_init(udev, &event->run_list, false);
50 event->fd_signal = -1;
51 event->birth_usec = now_usec();
52 event->timeout_usec = 30 * 1000 * 1000;
53 dbg(event->udev, "allocated event %p\n", event);
54 return event;
55 }
56
57 void udev_event_unref(struct udev_event *event)
58 {
59 if (event == NULL)
60 return;
61 udev_list_cleanup(&event->run_list);
62 free(event->program_result);
63 free(event->name);
64 dbg(event->udev, "free event %p\n", event);
65 free(event);
66 }
67
68 size_t udev_event_apply_format(struct udev_event *event, const char *src, char *dest, size_t size)
69 {
70 struct udev_device *dev = event->dev;
71 enum subst_type {
72 SUBST_UNKNOWN,
73 SUBST_DEVNODE,
74 SUBST_ATTR,
75 SUBST_ENV,
76 SUBST_KERNEL,
77 SUBST_KERNEL_NUMBER,
78 SUBST_DRIVER,
79 SUBST_DEVPATH,
80 SUBST_ID,
81 SUBST_MAJOR,
82 SUBST_MINOR,
83 SUBST_RESULT,
84 SUBST_PARENT,
85 SUBST_NAME,
86 SUBST_LINKS,
87 SUBST_ROOT,
88 SUBST_SYS,
89 };
90 static const struct subst_map {
91 char *name;
92 char fmt;
93 enum subst_type type;
94 } map[] = {
95 { .name = "devnode", .fmt = 'N', .type = SUBST_DEVNODE },
96 { .name = "tempnode", .fmt = 'N', .type = SUBST_DEVNODE },
97 { .name = "attr", .fmt = 's', .type = SUBST_ATTR },
98 { .name = "sysfs", .fmt = 's', .type = SUBST_ATTR },
99 { .name = "env", .fmt = 'E', .type = SUBST_ENV },
100 { .name = "kernel", .fmt = 'k', .type = SUBST_KERNEL },
101 { .name = "number", .fmt = 'n', .type = SUBST_KERNEL_NUMBER },
102 { .name = "driver", .fmt = 'd', .type = SUBST_DRIVER },
103 { .name = "devpath", .fmt = 'p', .type = SUBST_DEVPATH },
104 { .name = "id", .fmt = 'b', .type = SUBST_ID },
105 { .name = "major", .fmt = 'M', .type = SUBST_MAJOR },
106 { .name = "minor", .fmt = 'm', .type = SUBST_MINOR },
107 { .name = "result", .fmt = 'c', .type = SUBST_RESULT },
108 { .name = "parent", .fmt = 'P', .type = SUBST_PARENT },
109 { .name = "name", .fmt = 'D', .type = SUBST_NAME },
110 { .name = "links", .fmt = 'L', .type = SUBST_LINKS },
111 { .name = "root", .fmt = 'r', .type = SUBST_ROOT },
112 { .name = "sys", .fmt = 'S', .type = SUBST_SYS },
113 };
114 const char *from;
115 char *s;
116 size_t l;
117
118 from = src;
119 s = dest;
120 l = size;
121
122 for (;;) {
123 enum subst_type type = SUBST_UNKNOWN;
124 char attrbuf[UTIL_PATH_SIZE];
125 char *attr = NULL;
126
127 while (from[0] != '\0') {
128 if (from[0] == '$') {
129 /* substitute named variable */
130 unsigned int i;
131
132 if (from[1] == '$') {
133 from++;
134 goto copy;
135 }
136
137 for (i = 0; i < ARRAY_SIZE(map); i++) {
138 if (strncmp(&from[1], map[i].name, strlen(map[i].name)) == 0) {
139 type = map[i].type;
140 from += strlen(map[i].name)+1;
141 dbg(event->udev, "will substitute format name '%s'\n", map[i].name);
142 goto subst;
143 }
144 }
145 } else if (from[0] == '%') {
146 /* substitute format char */
147 unsigned int i;
148
149 if (from[1] == '%') {
150 from++;
151 goto copy;
152 }
153
154 for (i = 0; i < ARRAY_SIZE(map); i++) {
155 if (from[1] == map[i].fmt) {
156 type = map[i].type;
157 from += 2;
158 dbg(event->udev, "will substitute format char '%c'\n", map[i].fmt);
159 goto subst;
160 }
161 }
162 }
163 copy:
164 /* copy char */
165 if (l == 0)
166 goto out;
167 s[0] = from[0];
168 from++;
169 s++;
170 l--;
171 }
172
173 goto out;
174 subst:
175 /* extract possible $format{attr} */
176 if (from[0] == '{') {
177 unsigned int i;
178
179 from++;
180 for (i = 0; from[i] != '}'; i++) {
181 if (from[i] == '\0') {
182 err(event->udev, "missing closing brace for format '%s'\n", src);
183 goto out;
184 }
185 }
186 if (i >= sizeof(attrbuf))
187 goto out;
188 memcpy(attrbuf, from, i);
189 attrbuf[i] = '\0';
190 from += i+1;
191 attr = attrbuf;
192 } else {
193 attr = NULL;
194 }
195
196 switch (type) {
197 case SUBST_DEVPATH:
198 l = util_strpcpy(&s, l, udev_device_get_devpath(dev));
199 dbg(event->udev, "substitute devpath '%s'\n", udev_device_get_devpath(dev));
200 break;
201 case SUBST_KERNEL:
202 l = util_strpcpy(&s, l, udev_device_get_sysname(dev));
203 dbg(event->udev, "substitute kernel name '%s'\n", udev_device_get_sysname(dev));
204 break;
205 case SUBST_KERNEL_NUMBER:
206 if (udev_device_get_sysnum(dev) == NULL)
207 break;
208 l = util_strpcpy(&s, l, udev_device_get_sysnum(dev));
209 dbg(event->udev, "substitute kernel number '%s'\n", udev_device_get_sysnum(dev));
210 break;
211 case SUBST_ID:
212 if (event->dev_parent == NULL)
213 break;
214 l = util_strpcpy(&s, l, udev_device_get_sysname(event->dev_parent));
215 dbg(event->udev, "substitute id '%s'\n", udev_device_get_sysname(event->dev_parent));
216 break;
217 case SUBST_DRIVER: {
218 const char *driver;
219
220 if (event->dev_parent == NULL)
221 break;
222
223 driver = udev_device_get_driver(event->dev_parent);
224 if (driver == NULL)
225 break;
226 l = util_strpcpy(&s, l, driver);
227 dbg(event->udev, "substitute driver '%s'\n", driver);
228 break;
229 }
230 case SUBST_MAJOR: {
231 char num[UTIL_PATH_SIZE];
232
233 sprintf(num, "%d", major(udev_device_get_devnum(dev)));
234 l = util_strpcpy(&s, l, num);
235 dbg(event->udev, "substitute major number '%s'\n", num);
236 break;
237 }
238 case SUBST_MINOR: {
239 char num[UTIL_PATH_SIZE];
240
241 sprintf(num, "%d", minor(udev_device_get_devnum(dev)));
242 l = util_strpcpy(&s, l, num);
243 dbg(event->udev, "substitute minor number '%s'\n", num);
244 break;
245 }
246 case SUBST_RESULT: {
247 char *rest;
248 int i;
249
250 if (event->program_result == NULL)
251 break;
252 /* get part part of the result string */
253 i = 0;
254 if (attr != NULL)
255 i = strtoul(attr, &rest, 10);
256 if (i > 0) {
257 char result[UTIL_PATH_SIZE];
258 char tmp[UTIL_PATH_SIZE];
259 char *cpos;
260
261 dbg(event->udev, "request part #%d of result string\n", i);
262 util_strscpy(result, sizeof(result), event->program_result);
263 cpos = result;
264 while (--i) {
265 while (cpos[0] != '\0' && !isspace(cpos[0]))
266 cpos++;
267 while (isspace(cpos[0]))
268 cpos++;
269 }
270 if (i > 0) {
271 err(event->udev, "requested part of result string not found\n");
272 break;
273 }
274 util_strscpy(tmp, sizeof(tmp), cpos);
275 /* %{2+}c copies the whole string from the second part on */
276 if (rest[0] != '+') {
277 cpos = strchr(tmp, ' ');
278 if (cpos)
279 cpos[0] = '\0';
280 }
281 l = util_strpcpy(&s, l, tmp);
282 dbg(event->udev, "substitute part of result string '%s'\n", tmp);
283 } else {
284 l = util_strpcpy(&s, l, event->program_result);
285 dbg(event->udev, "substitute result string '%s'\n", event->program_result);
286 }
287 break;
288 }
289 case SUBST_ATTR: {
290 const char *value = NULL;
291 char vbuf[UTIL_NAME_SIZE];
292 size_t len;
293 int count;
294
295 if (attr == NULL) {
296 err(event->udev, "missing file parameter for attr\n");
297 break;
298 }
299
300 /* try to read the value specified by "[dmi/id]product_name" */
301 if (util_resolve_subsys_kernel(event->udev, attr, vbuf, sizeof(vbuf), 1) == 0)
302 value = vbuf;
303
304 /* try to read the attribute the device */
305 if (value == NULL)
306 value = udev_device_get_sysattr_value(event->dev, attr);
307
308 /* try to read the attribute of the parent device, other matches have selected */
309 if (value == NULL && event->dev_parent != NULL && event->dev_parent != event->dev)
310 value = udev_device_get_sysattr_value(event->dev_parent, attr);
311
312 if (value == NULL)
313 break;
314
315 /* strip trailing whitespace, and replace unwanted characters */
316 if (value != vbuf)
317 util_strscpy(vbuf, sizeof(vbuf), value);
318 len = strlen(vbuf);
319 while (len > 0 && isspace(vbuf[--len]))
320 vbuf[len] = '\0';
321 count = util_replace_chars(vbuf, UDEV_ALLOWED_CHARS_INPUT);
322 if (count > 0)
323 info(event->udev, "%i character(s) replaced\n" , count);
324 l = util_strpcpy(&s, l, vbuf);
325 dbg(event->udev, "substitute sysfs value '%s'\n", vbuf);
326 break;
327 }
328 case SUBST_PARENT: {
329 struct udev_device *dev_parent;
330 const char *devnode;
331
332 dev_parent = udev_device_get_parent(event->dev);
333 if (dev_parent == NULL)
334 break;
335 devnode = udev_device_get_devnode(dev_parent);
336 if (devnode != NULL) {
337 size_t devlen = strlen(udev_get_dev_path(event->udev))+1;
338
339 l = util_strpcpy(&s, l, &devnode[devlen]);
340 dbg(event->udev, "found parent '%s', got node name '%s'\n",
341 udev_device_get_syspath(dev_parent), &devnode[devlen]);
342 }
343 break;
344 }
345 case SUBST_DEVNODE:
346 if (udev_device_get_devnode(dev) != NULL)
347 l = util_strpcpy(&s, l, udev_device_get_devnode(dev));
348 break;
349 case SUBST_NAME: {
350 if (event->name != NULL) {
351 l = util_strpcpy(&s, l, event->name);
352 dbg(event->udev, "substitute custom node name '%s'\n", event->name);
353 } else if (udev_device_get_devnode(dev) != NULL) {
354 size_t devlen = strlen(udev_get_dev_path(event->udev))+1;
355
356 l = util_strpcpy(&s, l, &udev_device_get_devnode(dev)[devlen]);
357 dbg(event->udev, "substitute node name'%s'\n", &udev_device_get_devnode(dev)[devlen]);
358 } else {
359 l = util_strpcpy(&s, l, udev_device_get_sysname(dev));
360 dbg(event->udev, "substitute device name'%s'\n", udev_device_get_sysname(dev));
361 }
362 break;
363 }
364 case SUBST_LINKS: {
365 size_t devlen = strlen(udev_get_dev_path(event->udev))+1;
366 struct udev_list_entry *list_entry;
367
368 list_entry = udev_device_get_devlinks_list_entry(dev);
369 if (list_entry == NULL)
370 break;
371 l = util_strpcpy(&s, l, &udev_list_entry_get_name(list_entry)[devlen]);
372 udev_list_entry_foreach(list_entry, udev_list_entry_get_next(list_entry))
373 l = util_strpcpyl(&s, l, " ", &udev_list_entry_get_name(list_entry)[devlen], NULL);
374 break;
375 }
376 case SUBST_ROOT:
377 l = util_strpcpy(&s, l, udev_get_dev_path(event->udev));
378 dbg(event->udev, "substitute udev_root '%s'\n", udev_get_dev_path(event->udev));
379 break;
380 case SUBST_SYS:
381 l = util_strpcpy(&s, l, udev_get_sys_path(event->udev));
382 dbg(event->udev, "substitute sys_path '%s'\n", udev_get_sys_path(event->udev));
383 break;
384 case SUBST_ENV:
385 if (attr == NULL) {
386 dbg(event->udev, "missing attribute\n");
387 break;
388 } else {
389 const char *value;
390
391 value = udev_device_get_property_value(event->dev, attr);
392 if (value == NULL)
393 break;
394 dbg(event->udev, "substitute env '%s=%s'\n", attr, value);
395 l = util_strpcpy(&s, l, value);
396 break;
397 }
398 default:
399 err(event->udev, "unknown substitution type=%i\n", type);
400 break;
401 }
402 }
403
404 out:
405 s[0] = '\0';
406 dbg(event->udev, "'%s' -> '%s' (%zu)\n", src, dest, l);
407 return l;
408 }
409
410 static int spawn_exec(struct udev_event *event,
411 const char *cmd, char *const argv[], char **envp, const sigset_t *sigmask,
412 int fd_stdout, int fd_stderr)
413 {
414 struct udev *udev = event->udev;
415 int err;
416 int fd;
417
418 /* discard child output or connect to pipe */
419 fd = open("/dev/null", O_RDWR);
420 if (fd >= 0) {
421 dup2(fd, STDIN_FILENO);
422 if (fd_stdout < 0)
423 dup2(fd, STDOUT_FILENO);
424 if (fd_stderr < 0)
425 dup2(fd, STDERR_FILENO);
426 close(fd);
427 } else {
428 err(udev, "open /dev/null failed: %m\n");
429 }
430
431 /* connect pipes to std{out,err} */
432 if (fd_stdout >= 0) {
433 dup2(fd_stdout, STDOUT_FILENO);
434 close(fd_stdout);
435 }
436 if (fd_stderr >= 0) {
437 dup2(fd_stderr, STDERR_FILENO);
438 close(fd_stderr);
439 }
440
441 /* terminate child in case parent goes away */
442 prctl(PR_SET_PDEATHSIG, SIGTERM);
443
444 /* restore original udev sigmask before exec */
445 if (sigmask)
446 sigprocmask(SIG_SETMASK, sigmask, NULL);
447
448 execve(argv[0], argv, envp);
449
450 /* exec failed */
451 err = -errno;
452 err(udev, "failed to execute '%s' '%s': %m\n", argv[0], cmd);
453 return err;
454 }
455
456 static void spawn_read(struct udev_event *event,
457 const char *cmd,
458 int fd_stdout, int fd_stderr,
459 char *result, size_t ressize)
460 {
461 struct udev *udev = event->udev;
462 size_t respos = 0;
463 int fd_ep = -1;
464 struct epoll_event ep_outpipe, ep_errpipe;
465
466 /* read from child if requested */
467 if (fd_stdout < 0 && fd_stderr < 0)
468 return;
469
470 fd_ep = epoll_create1(EPOLL_CLOEXEC);
471 if (fd_ep < 0) {
472 err(udev, "error creating epoll fd: %m\n");
473 goto out;
474 }
475
476 if (fd_stdout >= 0) {
477 memset(&ep_outpipe, 0, sizeof(struct epoll_event));
478 ep_outpipe.events = EPOLLIN;
479 ep_outpipe.data.ptr = &fd_stdout;
480 if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_stdout, &ep_outpipe) < 0) {
481 err(udev, "fail to add fd to epoll: %m\n");
482 goto out;
483 }
484 }
485
486 if (fd_stderr >= 0) {
487 memset(&ep_errpipe, 0, sizeof(struct epoll_event));
488 ep_errpipe.events = EPOLLIN;
489 ep_errpipe.data.ptr = &fd_stderr;
490 if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_stderr, &ep_errpipe) < 0) {
491 err(udev, "fail to add fd to epoll: %m\n");
492 goto out;
493 }
494 }
495
496 /* read child output */
497 while (fd_stdout >= 0 || fd_stderr >= 0) {
498 int timeout;
499 int fdcount;
500 struct epoll_event ev[4];
501 int i;
502
503 if (event->timeout_usec > 0) {
504 unsigned long long age_usec;
505
506 age_usec = now_usec() - event->birth_usec;
507 if (age_usec >= event->timeout_usec) {
508 err(udev, "timeout '%s'\n", cmd);
509 goto out;
510 }
511 timeout = ((event->timeout_usec - age_usec) / 1000) + 1000;
512 } else {
513 timeout = -1;
514 }
515
516 fdcount = epoll_wait(fd_ep, ev, ARRAY_SIZE(ev), timeout);
517 if (fdcount < 0) {
518 if (errno == EINTR)
519 continue;
520 err(udev, "failed to poll: %m\n");
521 goto out;
522 }
523 if (fdcount == 0) {
524 err(udev, "timeout '%s'\n", cmd);
525 goto out;
526 }
527
528 for (i = 0; i < fdcount; i++) {
529 int *fd = (int *)ev[i].data.ptr;
530
531 if (ev[i].events & EPOLLIN) {
532 ssize_t count;
533 char buf[4096];
534
535 count = read(*fd, buf, sizeof(buf)-1);
536 if (count <= 0)
537 continue;
538 buf[count] = '\0';
539
540 /* store stdout result */
541 if (result != NULL && *fd == fd_stdout) {
542 if (respos + count < ressize) {
543 memcpy(&result[respos], buf, count);
544 respos += count;
545 } else {
546 err(udev, "'%s' ressize %zd too short\n", cmd, ressize);
547 }
548 }
549
550 /* log debug output only if we watch stderr */
551 if (fd_stderr >= 0) {
552 char *pos;
553 char *line;
554
555 pos = buf;
556 while ((line = strsep(&pos, "\n"))) {
557 if (pos != NULL || line[0] != '\0')
558 info(udev, "'%s'(%s) '%s'\n", cmd, *fd == fd_stdout ? "out" : "err" , line);
559 }
560 }
561 } else if (ev[i].events & EPOLLHUP) {
562 if (epoll_ctl(fd_ep, EPOLL_CTL_DEL, *fd, NULL) < 0) {
563 err(udev, "failed to remove fd from epoll: %m\n");
564 goto out;
565 }
566 *fd = -1;
567 }
568 }
569 }
570
571 /* return the child's stdout string */
572 if (result != NULL) {
573 result[respos] = '\0';
574 dbg(udev, "result='%s'\n", result);
575 }
576 out:
577 if (fd_ep >= 0)
578 close(fd_ep);
579 }
580
581 static int spawn_wait(struct udev_event *event, const char *cmd, pid_t pid)
582 {
583 struct udev *udev = event->udev;
584 struct pollfd pfd[1];
585 int err = 0;
586
587 pfd[0].events = POLLIN;
588 pfd[0].fd = event->fd_signal;
589
590 while (pid > 0) {
591 int timeout;
592 int fdcount;
593
594 if (event->timeout_usec > 0) {
595 unsigned long long age_usec;
596
597 age_usec = now_usec() - event->birth_usec;
598 if (age_usec >= event->timeout_usec)
599 timeout = 1000;
600 else
601 timeout = ((event->timeout_usec - age_usec) / 1000) + 1000;
602 } else {
603 timeout = -1;
604 }
605
606 fdcount = poll(pfd, 1, timeout);
607 if (fdcount < 0) {
608 if (errno == EINTR)
609 continue;
610 err = -errno;
611 err(udev, "failed to poll: %m\n");
612 goto out;
613 }
614 if (fdcount == 0) {
615 err(udev, "timeout: killing '%s' [%u]\n", cmd, pid);
616 kill(pid, SIGKILL);
617 }
618
619 if (pfd[0].revents & POLLIN) {
620 struct signalfd_siginfo fdsi;
621 int status;
622 ssize_t size;
623
624 size = read(event->fd_signal, &fdsi, sizeof(struct signalfd_siginfo));
625 if (size != sizeof(struct signalfd_siginfo))
626 continue;
627
628 switch (fdsi.ssi_signo) {
629 case SIGTERM:
630 event->sigterm = true;
631 break;
632 case SIGCHLD:
633 if (waitpid(pid, &status, WNOHANG) < 0)
634 break;
635 if (WIFEXITED(status)) {
636 info(udev, "'%s' [%u] exit with return code %i\n", cmd, pid, WEXITSTATUS(status));
637 if (WEXITSTATUS(status) != 0)
638 err = -1;
639 } else if (WIFSIGNALED(status)) {
640 err(udev, "'%s' [%u] terminated by signal %i (%s)\n", cmd, pid, WTERMSIG(status), strsignal(WTERMSIG(status)));
641 err = -1;
642 } else if (WIFSTOPPED(status)) {
643 err(udev, "'%s' [%u] stopped\n", cmd, pid);
644 err = -1;
645 } else if (WIFCONTINUED(status)) {
646 err(udev, "'%s' [%u] continued\n", cmd, pid);
647 err = -1;
648 } else {
649 err(udev, "'%s' [%u] exit with status 0x%04x\n", cmd, pid, status);
650 err = -1;
651 }
652 pid = 0;
653 break;
654 }
655 }
656 }
657 out:
658 return err;
659 }
660
661 int udev_build_argv(struct udev *udev, char *cmd, int *argc, char *argv[])
662 {
663 int i = 0;
664 char *pos;
665
666 if (strchr(cmd, ' ') == NULL) {
667 argv[i++] = cmd;
668 goto out;
669 }
670
671 pos = cmd;
672 while (pos != NULL && pos[0] != '\0') {
673 if (pos[0] == '\'') {
674 /* do not separate quotes */
675 pos++;
676 argv[i] = strsep(&pos, "\'");
677 if (pos != NULL)
678 while (pos[0] == ' ')
679 pos++;
680 } else {
681 argv[i] = strsep(&pos, " ");
682 if (pos != NULL)
683 while (pos[0] == ' ')
684 pos++;
685 }
686 dbg(udev, "argv[%i] '%s'\n", i, argv[i]);
687 i++;
688 }
689 out:
690 argv[i] = NULL;
691 if (argc)
692 *argc = i;
693 return 0;
694 }
695
696 int udev_event_spawn(struct udev_event *event,
697 const char *cmd, char **envp, const sigset_t *sigmask,
698 char *result, size_t ressize)
699 {
700 struct udev *udev = event->udev;
701 int outpipe[2] = {-1, -1};
702 int errpipe[2] = {-1, -1};
703 pid_t pid;
704 char arg[UTIL_PATH_SIZE];
705 char *argv[128];
706 char program[UTIL_PATH_SIZE];
707 int err = 0;
708
709 util_strscpy(arg, sizeof(arg), cmd);
710 udev_build_argv(event->udev, arg, NULL, argv);
711
712 /* pipes from child to parent */
713 if (result != NULL || udev_get_log_priority(udev) >= LOG_INFO) {
714 if (pipe2(outpipe, O_NONBLOCK) != 0) {
715 err = -errno;
716 err(udev, "pipe failed: %m\n");
717 goto out;
718 }
719 }
720 if (udev_get_log_priority(udev) >= LOG_INFO) {
721 if (pipe2(errpipe, O_NONBLOCK) != 0) {
722 err = -errno;
723 err(udev, "pipe failed: %m\n");
724 goto out;
725 }
726 }
727
728 /* allow programs in /usr/lib/udev/ to be called without the path */
729 if (argv[0][0] != '/') {
730 util_strscpyl(program, sizeof(program), PKGLIBEXECDIR "/", argv[0], NULL);
731 argv[0] = program;
732 }
733
734 pid = fork();
735 switch(pid) {
736 case 0:
737 /* child closes parent's ends of pipes */
738 if (outpipe[READ_END] >= 0) {
739 close(outpipe[READ_END]);
740 outpipe[READ_END] = -1;
741 }
742 if (errpipe[READ_END] >= 0) {
743 close(errpipe[READ_END]);
744 errpipe[READ_END] = -1;
745 }
746
747 info(udev, "starting '%s'\n", cmd);
748
749 err = spawn_exec(event, cmd, argv, envp, sigmask,
750 outpipe[WRITE_END], errpipe[WRITE_END]);
751
752 _exit(2 );
753 case -1:
754 err(udev, "fork of '%s' failed: %m\n", cmd);
755 err = -1;
756 goto out;
757 default:
758 /* parent closed child's ends of pipes */
759 if (outpipe[WRITE_END] >= 0) {
760 close(outpipe[WRITE_END]);
761 outpipe[WRITE_END] = -1;
762 }
763 if (errpipe[WRITE_END] >= 0) {
764 close(errpipe[WRITE_END]);
765 errpipe[WRITE_END] = -1;
766 }
767
768 spawn_read(event, cmd,
769 outpipe[READ_END], errpipe[READ_END],
770 result, ressize);
771
772 err = spawn_wait(event, cmd, pid);
773 }
774
775 out:
776 if (outpipe[READ_END] >= 0)
777 close(outpipe[READ_END]);
778 if (outpipe[WRITE_END] >= 0)
779 close(outpipe[WRITE_END]);
780 if (errpipe[READ_END] >= 0)
781 close(errpipe[READ_END]);
782 if (errpipe[WRITE_END] >= 0)
783 close(errpipe[WRITE_END]);
784 return err;
785 }
786
787 static inline void rename_netif_kernel_log(struct ifreq ifr)
788 {
789 print_kmsg("renamed network interface %s to %s", ifr.ifr_name, ifr.ifr_newname);
790 }
791
792 static int rename_netif(struct udev_event *event)
793 {
794 struct udev_device *dev = event->dev;
795 int sk;
796 struct ifreq ifr;
797 int loop;
798 int err;
799
800 info(event->udev, "changing net interface name from '%s' to '%s'\n",
801 udev_device_get_sysname(dev), event->name);
802
803 sk = socket(PF_INET, SOCK_DGRAM, 0);
804 if (sk < 0) {
805 err = -errno;
806 err(event->udev, "error opening socket: %m\n");
807 return err;
808 }
809
810 memset(&ifr, 0x00, sizeof(struct ifreq));
811 util_strscpy(ifr.ifr_name, IFNAMSIZ, udev_device_get_sysname(dev));
812 util_strscpy(ifr.ifr_newname, IFNAMSIZ, event->name);
813 err = ioctl(sk, SIOCSIFNAME, &ifr);
814 if (err == 0) {
815 rename_netif_kernel_log(ifr);
816 goto out;
817 }
818
819 /* keep trying if the destination interface name already exists */
820 err = -errno;
821 if (err != -EEXIST)
822 goto out;
823
824 /* free our own name, another process may wait for us */
825 snprintf(ifr.ifr_newname, IFNAMSIZ, "rename%u", udev_device_get_ifindex(dev));
826 err = ioctl(sk, SIOCSIFNAME, &ifr);
827 if (err < 0) {
828 err = -errno;
829 goto out;
830 }
831
832 /* log temporary name */
833 rename_netif_kernel_log(ifr);
834
835 /* wait a maximum of 90 seconds for our target to become available */
836 util_strscpy(ifr.ifr_name, IFNAMSIZ, ifr.ifr_newname);
837 util_strscpy(ifr.ifr_newname, IFNAMSIZ, event->name);
838 loop = 90 * 20;
839 while (loop--) {
840 const struct timespec duration = { 0, 1000 * 1000 * 1000 / 20 };
841
842 dbg(event->udev, "wait for netif '%s' to become free, loop=%i\n",
843 event->name, (90 * 20) - loop);
844 nanosleep(&duration, NULL);
845
846 err = ioctl(sk, SIOCSIFNAME, &ifr);
847 if (err == 0) {
848 rename_netif_kernel_log(ifr);
849 break;
850 }
851 err = -errno;
852 if (err != -EEXIST)
853 break;
854 }
855
856 out:
857 if (err < 0)
858 err(event->udev, "error changing net interface name %s to %s: %m\n", ifr.ifr_name, ifr.ifr_newname);
859 close(sk);
860 return err;
861 }
862
863 int udev_event_execute_rules(struct udev_event *event, struct udev_rules *rules, const sigset_t *sigmask)
864 {
865 struct udev_device *dev = event->dev;
866 int err = 0;
867
868 if (udev_device_get_subsystem(dev) == NULL)
869 return -1;
870
871 if (strcmp(udev_device_get_action(dev), "remove") == 0) {
872 udev_device_read_db(dev, NULL);
873 udev_device_delete_db(dev);
874 udev_device_tag_index(dev, NULL, false);
875
876 if (major(udev_device_get_devnum(dev)) != 0)
877 udev_watch_end(event->udev, dev);
878
879 udev_rules_apply_to_event(rules, event, sigmask);
880
881 if (major(udev_device_get_devnum(dev)) != 0)
882 udev_node_remove(dev);
883 } else {
884 event->dev_db = udev_device_new_from_syspath(event->udev, udev_device_get_syspath(dev));
885 if (event->dev_db != NULL) {
886 udev_device_read_db(event->dev_db, NULL);
887 udev_device_set_info_loaded(event->dev_db);
888
889 /* disable watch during event processing */
890 if (major(udev_device_get_devnum(dev)) != 0)
891 udev_watch_end(event->udev, event->dev_db);
892 }
893
894 udev_rules_apply_to_event(rules, event, sigmask);
895
896 /* rename a new network interface, if needed */
897 if (udev_device_get_ifindex(dev) > 0 && strcmp(udev_device_get_action(dev), "add") == 0 &&
898 event->name != NULL && strcmp(event->name, udev_device_get_sysname(dev)) != 0) {
899 char syspath[UTIL_PATH_SIZE];
900 char *pos;
901
902 err = rename_netif(event);
903 if (err == 0) {
904 info(event->udev, "renamed netif to '%s'\n", event->name);
905
906 /* remember old name */
907 udev_device_add_property(dev, "INTERFACE_OLD", udev_device_get_sysname(dev));
908
909 /* now change the devpath, because the kernel device name has changed */
910 util_strscpy(syspath, sizeof(syspath), udev_device_get_syspath(dev));
911 pos = strrchr(syspath, '/');
912 if (pos != NULL) {
913 pos++;
914 util_strscpy(pos, sizeof(syspath) - (pos - syspath), event->name);
915 udev_device_set_syspath(event->dev, syspath);
916 udev_device_add_property(dev, "INTERFACE", udev_device_get_sysname(dev));
917 info(event->udev, "changed devpath to '%s'\n", udev_device_get_devpath(dev));
918 }
919 }
920 }
921
922 if (major(udev_device_get_devnum(dev)) > 0) {
923 /* remove/update possible left-over symlinks from old database entry */
924 if (event->dev_db != NULL)
925 udev_node_update_old_links(dev, event->dev_db);
926
927 if (!event->mode_set) {
928 if (udev_device_get_devnode_mode(dev) > 0) {
929 /* kernel supplied value */
930 event->mode = udev_device_get_devnode_mode(dev);
931 } else if (event->gid > 0) {
932 /* default 0660 if a group is assigned */
933 event->mode = 0660;
934 } else {
935 /* default 0600 */
936 event->mode = 0600;
937 }
938 }
939
940 udev_node_add(dev, event->mode, event->uid, event->gid);
941 }
942
943 /* preserve old, or get new initialization timestamp */
944 if (event->dev_db != NULL && udev_device_get_usec_initialized(event->dev_db) > 0)
945 udev_device_set_usec_initialized(event->dev, udev_device_get_usec_initialized(event->dev_db));
946 else if (udev_device_get_usec_initialized(event->dev) == 0)
947 udev_device_set_usec_initialized(event->dev, now_usec());
948
949 /* (re)write database file */
950 udev_device_update_db(dev);
951 udev_device_tag_index(dev, event->dev_db, true);
952 udev_device_set_is_initialized(dev);
953
954 udev_device_unref(event->dev_db);
955 event->dev_db = NULL;
956 }
957 out:
958 return err;
959 }
960
961 int udev_event_execute_run(struct udev_event *event, const sigset_t *sigmask)
962 {
963 struct udev_list_entry *list_entry;
964 int err = 0;
965
966 dbg(event->udev, "executing run list\n");
967 udev_list_entry_foreach(list_entry, udev_list_get_entry(&event->run_list)) {
968 const char *cmd = udev_list_entry_get_name(list_entry);
969
970 if (strncmp(cmd, "socket:", strlen("socket:")) == 0) {
971 struct udev_monitor *monitor;
972
973 monitor = udev_monitor_new_from_socket(event->udev, &cmd[strlen("socket:")]);
974 if (monitor == NULL)
975 continue;
976 udev_monitor_send_device(monitor, NULL, event->dev);
977 udev_monitor_unref(monitor);
978 } else {
979 char program[UTIL_PATH_SIZE];
980 char **envp;
981
982 if (event->exec_delay > 0) {
983 info(event->udev, "delay execution of '%s'\n", program);
984 sleep(event->exec_delay);
985 }
986
987 udev_event_apply_format(event, cmd, program, sizeof(program));
988 envp = udev_device_get_properties_envp(event->dev);
989 if (udev_event_spawn(event, program, envp, sigmask, NULL, 0) < 0) {
990 if (udev_list_entry_get_num(list_entry))
991 err = -1;
992 }
993 }
994 }
995 return err;
996 }
File src/udev-node.c added (mode: 100644) (index 0000000..64d8697)
1 /*
2 * Copyright (C) 2003-2010 Kay Sievers <kay.sievers@vrfy.org>
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include <stdlib.h>
19 #include <string.h>
20 #include <stdio.h>
21 #include <stddef.h>
22 #include <stdbool.h>
23 #include <fcntl.h>
24 #include <unistd.h>
25 #include <errno.h>
26 #include <grp.h>
27 #include <dirent.h>
28 #include <sys/time.h>
29 #include <sys/stat.h>
30 #include <sys/types.h>
31
32 #include "udev.h"
33
34 #define TMP_FILE_EXT ".udev-tmp"
35
36 static int node_symlink(struct udev *udev, const char *node, const char *slink)
37 {
38 struct stat stats;
39 char target[UTIL_PATH_SIZE];
40 char *s;
41 size_t l;
42 char slink_tmp[UTIL_PATH_SIZE + sizeof(TMP_FILE_EXT)];
43 int i = 0;
44 int tail = 0;
45 int err = 0;
46
47 /* use relative link */
48 target[0] = '\0';
49 while (node[i] && (node[i] == slink[i])) {
50 if (node[i] == '/')
51 tail = i+1;
52 i++;
53 }
54 s = target;
55 l = sizeof(target);
56 while (slink[i] != '\0') {
57 if (slink[i] == '/')
58 l = util_strpcpy(&s, l, "../");
59 i++;
60 }
61 l = util_strscpy(s, l, &node[tail]);
62 if (l == 0) {
63 err = -EINVAL;
64 goto exit;
65 }
66
67 /* preserve link with correct target, do not replace node of other device */
68 if (lstat(slink, &stats) == 0) {
69 if (S_ISBLK(stats.st_mode) || S_ISCHR(stats.st_mode)) {
70 struct stat stats2;
71
72 info(udev, "found existing node instead of symlink '%s'\n", slink);
73 if (lstat(node, &stats2) == 0) {
74 if ((stats.st_mode & S_IFMT) == (stats2.st_mode & S_IFMT) &&
75 stats.st_rdev == stats2.st_rdev && stats.st_ino != stats2.st_ino) {
76 info(udev, "replace device node '%s' with symlink to our node '%s'\n",
77 slink, node);
78 } else {
79 err(udev, "device node '%s' already exists, "
80 "link to '%s' will not overwrite it\n",
81 slink, node);
82 goto exit;
83 }
84 }
85 } else if (S_ISLNK(stats.st_mode)) {
86 char buf[UTIL_PATH_SIZE];
87 int len;
88
89 dbg(udev, "found existing symlink '%s'\n", slink);
90 len = readlink(slink, buf, sizeof(buf));
91 if (len > 0 && len < (int)sizeof(buf)) {
92 buf[len] = '\0';
93 if (strcmp(target, buf) == 0) {
94 info(udev, "preserve already existing symlink '%s' to '%s'\n",
95 slink, target);
96 udev_selinux_lsetfilecon(udev, slink, S_IFLNK);
97 utimensat(AT_FDCWD, slink, NULL, AT_SYMLINK_NOFOLLOW);
98 goto exit;
99 }
100 }
101 }
102 } else {
103 info(udev, "creating symlink '%s' to '%s'\n", slink, target);
104 do {
105 err = util_create_path_selinux(udev, slink);
106 if (err != 0 && err != -ENOENT)
107 break;
108 udev_selinux_setfscreatecon(udev, slink, S_IFLNK);
109 err = symlink(target, slink);
110 if (err != 0)
111 err = -errno;
112 udev_selinux_resetfscreatecon(udev);
113 } while (err == -ENOENT);
114 if (err == 0)
115 goto exit;
116 }
117
118 info(udev, "atomically replace '%s'\n", slink);
119 util_strscpyl(slink_tmp, sizeof(slink_tmp), slink, TMP_FILE_EXT, NULL);
120 unlink(slink_tmp);
121 do {
122 err = util_create_path_selinux(udev, slink_tmp);
123 if (err != 0 && err != -ENOENT)
124 break;
125 udev_selinux_setfscreatecon(udev, slink_tmp, S_IFLNK);
126 err = symlink(target, slink_tmp);
127 if (err != 0)
128 err = -errno;
129 udev_selinux_resetfscreatecon(udev);
130 } while (err == -ENOENT);
131 if (err != 0) {
132 err(udev, "symlink '%s' '%s' failed: %m\n", target, slink_tmp);
133 goto exit;
134 }
135 err = rename(slink_tmp, slink);
136 if (err != 0) {
137 err(udev, "rename '%s' '%s' failed: %m\n", slink_tmp, slink);
138 unlink(slink_tmp);
139 }
140 exit:
141 return err;
142 }
143
144 /* find device node of device with highest priority */
145 static const char *link_find_prioritized(struct udev_device *dev, bool add, const char *stackdir, char *buf, size_t bufsize)
146 {
147 struct udev *udev = udev_device_get_udev(dev);
148 DIR *dir;
149 int priority = 0;
150 const char *target = NULL;
151
152 if (add) {
153 priority = udev_device_get_devlink_priority(dev);
154 util_strscpy(buf, bufsize, udev_device_get_devnode(dev));
155 target = buf;
156 }
157
158 dir = opendir(stackdir);
159 if (dir == NULL)
160 return target;
161 for (;;) {
162 struct udev_device *dev_db;
163 struct dirent *dent;
164
165 dent = readdir(dir);
166 if (dent == NULL || dent->d_name[0] == '\0')
167 break;
168 if (dent->d_name[0] == '.')
169 continue;
170
171 info(udev, "found '%s' claiming '%s'\n", dent->d_name, stackdir);
172
173 /* did we find ourself? */
174 if (strcmp(dent->d_name, udev_device_get_id_filename(dev)) == 0)
175 continue;
176
177 dev_db = udev_device_new_from_device_id(udev, dent->d_name);
178 if (dev_db != NULL) {
179 const char *devnode;
180
181 devnode = udev_device_get_devnode(dev_db);
182 if (devnode != NULL) {
183 dbg(udev, "compare priority of '%s'(%i) > '%s'(%i)\n", target, priority,
184 udev_device_get_devnode(dev_db), udev_device_get_devlink_priority(dev_db));
185 if (target == NULL || udev_device_get_devlink_priority(dev_db) > priority) {
186 info(udev, "'%s' claims priority %i for '%s'\n",
187 udev_device_get_syspath(dev_db), udev_device_get_devlink_priority(dev_db), stackdir);
188 priority = udev_device_get_devlink_priority(dev_db);
189 util_strscpy(buf, bufsize, devnode);
190 target = buf;
191 }
192 }
193 udev_device_unref(dev_db);
194 }
195 }
196 closedir(dir);
197 return target;
198 }
199
200 /* manage "stack of names" with possibly specified device priorities */
201 static void link_update(struct udev_device *dev, const char *slink, bool add)
202 {
203 struct udev *udev = udev_device_get_udev(dev);
204 char name_enc[UTIL_PATH_SIZE];
205 char filename[UTIL_PATH_SIZE * 2];
206 char dirname[UTIL_PATH_SIZE];
207 const char *target;
208 char buf[UTIL_PATH_SIZE];
209
210 dbg(udev, "update symlink '%s' of '%s'\n", slink, udev_device_get_syspath(dev));
211
212 util_path_encode(&slink[strlen(udev_get_dev_path(udev))+1], name_enc, sizeof(name_enc));
213 util_strscpyl(dirname, sizeof(dirname), udev_get_run_path(udev), "/links/", name_enc, NULL);
214 util_strscpyl(filename, sizeof(filename), dirname, "/", udev_device_get_id_filename(dev), NULL);
215
216 if (!add) {
217 dbg(udev, "removing index: '%s'\n", filename);
218 if (unlink(filename) == 0)
219 rmdir(dirname);
220 }
221
222 target = link_find_prioritized(dev, add, dirname, buf, sizeof(buf));
223 if (target == NULL) {
224 info(udev, "no reference left, remove '%s'\n", slink);
225 if (unlink(slink) == 0)
226 util_delete_path(udev, slink);
227 } else {
228 info(udev, "creating link '%s' to '%s'\n", slink, target);
229 node_symlink(udev, target, slink);
230 }
231
232 if (add) {
233 int err;
234
235 dbg(udev, "creating index: '%s'\n", filename);
236 do {
237 int fd;
238
239 err = util_create_path(udev, filename);
240 if (err != 0 && err != -ENOENT)
241 break;
242 fd = open(filename, O_WRONLY|O_CREAT|O_CLOEXEC|O_TRUNC|O_NOFOLLOW, 0444);
243 if (fd >= 0)
244 close(fd);
245 else
246 err = -errno;
247 } while (err == -ENOENT);
248 }
249 }
250
251 void udev_node_update_old_links(struct udev_device *dev, struct udev_device *dev_old)
252 {
253 struct udev *udev = udev_device_get_udev(dev);
254 struct udev_list_entry *list_entry;
255
256 /* update possible left-over symlinks */
257 udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev_old)) {
258 const char *name = udev_list_entry_get_name(list_entry);
259 struct udev_list_entry *list_entry_current;
260 int found;
261
262 /* check if old link name still belongs to this device */
263 found = 0;
264 udev_list_entry_foreach(list_entry_current, udev_device_get_devlinks_list_entry(dev)) {
265 const char *name_current = udev_list_entry_get_name(list_entry_current);
266
267 if (strcmp(name, name_current) == 0) {
268 found = 1;
269 break;
270 }
271 }
272 if (found)
273 continue;
274
275 info(udev, "update old name, '%s' no longer belonging to '%s'\n",
276 name, udev_device_get_devpath(dev));
277 link_update(dev, name, 0);
278 }
279 }
280
281 static int node_fixup(struct udev_device *dev, mode_t mode, uid_t uid, gid_t gid)
282 {
283 struct udev *udev = udev_device_get_udev(dev);
284 const char *devnode = udev_device_get_devnode(dev);
285 dev_t devnum = udev_device_get_devnum(dev);
286 struct stat stats;
287 int err = 0;
288
289 if (strcmp(udev_device_get_subsystem(dev), "block") == 0)
290 mode |= S_IFBLK;
291 else
292 mode |= S_IFCHR;
293
294 if (lstat(devnode, &stats) != 0) {
295 err = -errno;
296 info(udev, "can not stat() node '%s' (%m)\n", devnode);
297 goto out;
298 }
299
300 if (((stats.st_mode & S_IFMT) != (mode & S_IFMT)) || (stats.st_rdev != devnum)) {
301 err = -EEXIST;
302 info(udev, "found node '%s' with non-matching devnum %s, skip handling\n",
303 udev_device_get_devnode(dev), udev_device_get_id_filename(dev));
304 goto out;
305 }
306
307 if ((stats.st_mode & 0777) != (mode & 0777) || stats.st_uid != uid || stats.st_gid != gid) {
308 info(udev, "set permissions %s, %#o, uid=%u, gid=%u\n", devnode, mode, uid, gid);
309 chmod(devnode, mode);
310 chown(devnode, uid, gid);
311 } else {
312 info(udev, "preserve permissions %s, %#o, uid=%u, gid=%u\n", devnode, mode, uid, gid);
313 }
314
315 /*
316 * Set initial selinux file context only on add events.
317 * We set the proper context on bootup (triger) or for newly
318 * added devices, but we don't change it later, in case
319 * something else has set a custom context in the meantime.
320 */
321 if (strcmp(udev_device_get_action(dev), "add") == 0)
322 udev_selinux_lsetfilecon(udev, devnode, mode);
323
324 /* always update timestamp when we re-use the node, like on media change events */
325 utimensat(AT_FDCWD, devnode, NULL, 0);
326 out:
327 return err;
328 }
329
330 void udev_node_add(struct udev_device *dev, mode_t mode, uid_t uid, gid_t gid)
331 {
332 struct udev *udev = udev_device_get_udev(dev);
333 char filename[UTIL_PATH_SIZE];
334 struct udev_list_entry *list_entry;
335 int err = 0;
336
337 info(udev, "handling device node '%s', devnum=%s, mode=%#o, uid=%d, gid=%d\n",
338 udev_device_get_devnode(dev), udev_device_get_id_filename(dev), mode, uid, gid);
339
340 if (node_fixup(dev, mode, uid, gid) < 0)
341 return;
342
343 /* always add /dev/{block,char}/$major:$minor */
344 snprintf(filename, sizeof(filename), "%s/%s/%u:%u",
345 udev_get_dev_path(udev),
346 strcmp(udev_device_get_subsystem(dev), "block") == 0 ? "block" : "char",
347 major(udev_device_get_devnum(dev)), minor(udev_device_get_devnum(dev)));
348 node_symlink(udev, udev_device_get_devnode(dev), filename);
349
350 /* create/update symlinks, add symlinks to name index */
351 udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev)) {
352 if (udev_list_entry_get_num(list_entry))
353 /* simple unmanaged link name */
354 node_symlink(udev, udev_device_get_devnode(dev), udev_list_entry_get_name(list_entry));
355 else
356 link_update(dev, udev_list_entry_get_name(list_entry), 1);
357 }
358 }
359
360 void udev_node_remove(struct udev_device *dev)
361 {
362 struct udev *udev = udev_device_get_udev(dev);
363 struct udev_list_entry *list_entry;
364 const char *devnode;
365 struct stat stats;
366 struct udev_device *dev_check;
367 char filename[UTIL_PATH_SIZE];
368
369 /* remove/update symlinks, remove symlinks from name index */
370 udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev))
371 link_update(dev, udev_list_entry_get_name(list_entry), 0);
372
373 /* remove /dev/{block,char}/$major:$minor */
374 snprintf(filename, sizeof(filename), "%s/%s/%u:%u",
375 udev_get_dev_path(udev),
376 strcmp(udev_device_get_subsystem(dev), "block") == 0 ? "block" : "char",
377 major(udev_device_get_devnum(dev)), minor(udev_device_get_devnum(dev)));
378 unlink(filename);
379 }
File src/udev-rules.c added (mode: 100644) (index 0000000..94f0e29)
1 /*
2 * Copyright (C) 2003-2010 Kay Sievers <kay.sievers@vrfy.org>
3 * Copyright (C) 2008 Alan Jenkins <alan-jenkins@tuffmail.co.uk>
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include <stddef.h>
20 #include <limits.h>
21 #include <stdlib.h>
22 #include <stdbool.h>
23 #include <string.h>
24 #include <stdio.h>
25 #include <fcntl.h>
26 #include <ctype.h>
27 #include <unistd.h>
28 #include <errno.h>
29 #include <dirent.h>
30 #include <fnmatch.h>
31 #include <time.h>
32
33 #include "udev.h"
34
35 #define PREALLOC_TOKEN 2048
36 #define PREALLOC_STRBUF 32 * 1024
37 #define PREALLOC_TRIE 256
38
39 struct uid_gid {
40 unsigned int name_off;
41 union {
42 uid_t uid;
43 gid_t gid;
44 };
45 };
46
47 struct trie_node {
48 /* this node's first child */
49 unsigned int child_idx;
50 /* the next child of our parent node's child list */
51 unsigned int next_child_idx;
52 /* this node's last child (shortcut for append) */
53 unsigned int last_child_idx;
54 unsigned int value_off;
55 unsigned short value_len;
56 unsigned char key;
57 };
58
59 struct udev_rules {
60 struct udev *udev;
61 int resolve_names;
62
63 /* every key in the rules file becomes a token */
64 struct token *tokens;
65 unsigned int token_cur;
66 unsigned int token_max;
67
68 /* all key strings are copied to a single string buffer */
69 char *buf;
70 size_t buf_cur;
71 size_t buf_max;
72 unsigned int buf_count;
73
74 /* during rule parsing, strings are indexed to find duplicates */
75 struct trie_node *trie_nodes;
76 unsigned int trie_nodes_cur;
77 unsigned int trie_nodes_max;
78
79 /* during rule parsing, uid/gid lookup results are cached */
80 struct uid_gid *uids;
81 unsigned int uids_cur;
82 unsigned int uids_max;
83 struct uid_gid *gids;
84 unsigned int gids_cur;
85 unsigned int gids_max;
86 };
87
88 /* KEY=="", KEY!="", KEY+="", KEY="", KEY:="" */
89 enum operation_type {
90 OP_UNSET,
91
92 OP_MATCH,
93 OP_NOMATCH,
94 OP_MATCH_MAX,
95
96 OP_ADD,
97 OP_ASSIGN,
98 OP_ASSIGN_FINAL,
99 };
100
101 enum string_glob_type {
102 GL_UNSET,
103 GL_PLAIN, /* no special chars */
104 GL_GLOB, /* shell globs ?,*,[] */
105 GL_SPLIT, /* multi-value A|B */
106 GL_SPLIT_GLOB, /* multi-value with glob A*|B* */
107 GL_SOMETHING, /* commonly used "?*" */
108 };
109
110 enum string_subst_type {
111 SB_UNSET,
112 SB_NONE,
113 SB_FORMAT,
114 SB_SUBSYS,
115 };
116
117 /* tokens of a rule are sorted/handled in this order */
118 enum token_type {
119 TK_UNSET,
120 TK_RULE,
121
122 TK_M_ACTION, /* val */
123 TK_M_DEVPATH, /* val */
124 TK_M_KERNEL, /* val */
125 TK_M_DEVLINK, /* val */
126 TK_M_NAME, /* val */
127 TK_M_ENV, /* val, attr */
128 TK_M_TAG, /* val */
129 TK_M_SUBSYSTEM, /* val */
130 TK_M_DRIVER, /* val */
131 TK_M_WAITFOR, /* val */
132 TK_M_ATTR, /* val, attr */
133
134 TK_M_PARENTS_MIN,
135 TK_M_KERNELS, /* val */
136 TK_M_SUBSYSTEMS, /* val */
137 TK_M_DRIVERS, /* val */
138 TK_M_ATTRS, /* val, attr */
139 TK_M_TAGS, /* val */
140 TK_M_PARENTS_MAX,
141
142 TK_M_TEST, /* val, mode_t */
143 TK_M_EVENT_TIMEOUT, /* int */
144 TK_M_PROGRAM, /* val */
145 TK_M_IMPORT_FILE, /* val */
146 TK_M_IMPORT_PROG, /* val */
147 TK_M_IMPORT_BUILTIN, /* val */
148 TK_M_IMPORT_DB, /* val */
149 TK_M_IMPORT_CMDLINE, /* val */
150 TK_M_IMPORT_PARENT, /* val */
151 TK_M_RESULT, /* val */
152 TK_M_MAX,
153
154 TK_A_STRING_ESCAPE_NONE,
155 TK_A_STRING_ESCAPE_REPLACE,
156 TK_A_DB_PERSIST,
157 TK_A_INOTIFY_WATCH, /* int */
158 TK_A_DEVLINK_PRIO, /* int */
159 TK_A_OWNER, /* val */
160 TK_A_GROUP, /* val */
161 TK_A_MODE, /* val */
162 TK_A_OWNER_ID, /* uid_t */
163 TK_A_GROUP_ID, /* gid_t */
164 TK_A_MODE_ID, /* mode_t */
165 TK_A_STATIC_NODE, /* val */
166 TK_A_ENV, /* val, attr */
167 TK_A_TAG, /* val */
168 TK_A_NAME, /* val */
169 TK_A_DEVLINK, /* val */
170 TK_A_ATTR, /* val, attr */
171 TK_A_RUN, /* val, bool */
172 TK_A_GOTO, /* size_t */
173
174 TK_END,
175 };
176
177 /* we try to pack stuff in a way that we take only 12 bytes per token */
178 struct token {
179 union {
180 unsigned char type; /* same in rule and key */
181 struct {
182 enum token_type type:8;
183 bool can_set_name:1;
184 bool has_static_node:1;
185 unsigned int unused:6;
186 unsigned short token_count;
187 unsigned int label_off;
188 unsigned short filename_off;
189 unsigned short filename_line;
190 } rule;
191 struct {
192 enum token_type type:8;
193 enum operation_type op:8;
194 enum string_glob_type glob:8;
195 enum string_subst_type subst:4;
196 enum string_subst_type attrsubst:4;
197 unsigned int value_off;
198 union {
199 unsigned int attr_off;
200 int devlink_unique;
201 unsigned int rule_goto;
202 mode_t mode;
203 uid_t uid;
204 gid_t gid;
205 int devlink_prio;
206 int event_timeout;
207 int watch;
208 enum udev_builtin_cmd builtin_cmd;
209 };
210 } key;
211 };
212 };
213
214 #define MAX_TK 64
215 struct rule_tmp {
216 struct udev_rules *rules;
217 struct token rule;
218 struct token token[MAX_TK];
219 unsigned int token_cur;
220 };
221
222 #ifdef ENABLE_DEBUG
223 static const char *operation_str(enum operation_type type)
224 {
225 static const char *operation_strs[] = {
226 [OP_UNSET] = "UNSET",
227 [OP_MATCH] = "match",
228 [OP_NOMATCH] = "nomatch",
229 [OP_MATCH_MAX] = "MATCH_MAX",
230
231 [OP_ADD] = "add",
232 [OP_ASSIGN] = "assign",
233 [OP_ASSIGN_FINAL] = "assign-final",
234 } ;
235
236 return operation_strs[type];
237 }
238
239 static const char *string_glob_str(enum string_glob_type type)
240 {
241 static const char *string_glob_strs[] = {
242 [GL_UNSET] = "UNSET",
243 [GL_PLAIN] = "plain",
244 [GL_GLOB] = "glob",
245 [GL_SPLIT] = "split",
246 [GL_SPLIT_GLOB] = "split-glob",
247 [GL_SOMETHING] = "split-glob",
248 };
249
250 return string_glob_strs[type];
251 }
252
253 static const char *token_str(enum token_type type)
254 {
255 static const char *token_strs[] = {
256 [TK_UNSET] = "UNSET",
257 [TK_RULE] = "RULE",
258
259 [TK_M_ACTION] = "M ACTION",
260 [TK_M_DEVPATH] = "M DEVPATH",
261 [TK_M_KERNEL] = "M KERNEL",
262 [TK_M_DEVLINK] = "M DEVLINK",
263 [TK_M_NAME] = "M NAME",
264 [TK_M_ENV] = "M ENV",
265 [TK_M_TAG] = "M TAG",
266 [TK_M_SUBSYSTEM] = "M SUBSYSTEM",
267 [TK_M_DRIVER] = "M DRIVER",
268 [TK_M_WAITFOR] = "M WAITFOR",
269 [TK_M_ATTR] = "M ATTR",
270
271 [TK_M_PARENTS_MIN] = "M PARENTS_MIN",
272 [TK_M_KERNELS] = "M KERNELS",
273 [TK_M_SUBSYSTEMS] = "M SUBSYSTEMS",
274 [TK_M_DRIVERS] = "M DRIVERS",
275 [TK_M_ATTRS] = "M ATTRS",
276 [TK_M_TAGS] = "M TAGS",
277 [TK_M_PARENTS_MAX] = "M PARENTS_MAX",
278
279 [TK_M_TEST] = "M TEST",
280 [TK_M_EVENT_TIMEOUT] = "M EVENT_TIMEOUT",
281 [TK_M_PROGRAM] = "M PROGRAM",
282 [TK_M_IMPORT_FILE] = "M IMPORT_FILE",
283 [TK_M_IMPORT_PROG] = "M IMPORT_PROG",
284 [TK_M_IMPORT_BUILTIN] = "M IMPORT_BUILTIN",
285 [TK_M_IMPORT_DB] = "M IMPORT_DB",
286 [TK_M_IMPORT_CMDLINE] = "M IMPORT_CMDLINE",
287 [TK_M_IMPORT_PARENT] = "M IMPORT_PARENT",
288 [TK_M_RESULT] = "M RESULT",
289 [TK_M_MAX] = "M MAX",
290
291 [TK_A_STRING_ESCAPE_NONE] = "A STRING_ESCAPE_NONE",
292 [TK_A_STRING_ESCAPE_REPLACE] = "A STRING_ESCAPE_REPLACE",
293 [TK_A_DB_PERSIST] = "A DB_PERSIST",
294 [TK_A_INOTIFY_WATCH] = "A INOTIFY_WATCH",
295 [TK_A_DEVLINK_PRIO] = "A DEVLINK_PRIO",
296 [TK_A_OWNER] = "A OWNER",
297 [TK_A_GROUP] = "A GROUP",
298 [TK_A_MODE] = "A MODE",
299 [TK_A_OWNER_ID] = "A OWNER_ID",
300 [TK_A_GROUP_ID] = "A GROUP_ID",
301 [TK_A_STATIC_NODE] = "A STATIC_NODE",
302 [TK_A_MODE_ID] = "A MODE_ID",
303 [TK_A_ENV] = "A ENV",
304 [TK_A_TAG] = "A ENV",
305 [TK_A_NAME] = "A NAME",
306 [TK_A_DEVLINK] = "A DEVLINK",
307 [TK_A_ATTR] = "A ATTR",
308 [TK_A_RUN] = "A RUN",
309 [TK_A_GOTO] = "A GOTO",
310
311 [TK_END] = "END",
312 };
313
314 return token_strs[type];
315 }
316
317 static void dump_token(struct udev_rules *rules, struct token *token)
318 {
319 enum token_type type = token->type;
320 enum operation_type op = token->key.op;
321 enum string_glob_type glob = token->key.glob;
322 const char *value = &rules->buf[token->key.value_off];
323 const char *attr = &rules->buf[token->key.attr_off];
324
325 switch (type) {
326 case TK_RULE:
327 {
328 const char *tks_ptr = (char *)rules->tokens;
329 const char *tk_ptr = (char *)token;
330 unsigned int idx = (tk_ptr - tks_ptr) / sizeof(struct token);
331
332 dbg(rules->udev, "* RULE %s:%u, token: %u, count: %u, label: '%s'\n",
333 &rules->buf[token->rule.filename_off], token->rule.filename_line,
334 idx, token->rule.token_count,
335 &rules->buf[token->rule.label_off]);
336 break;
337 }
338 case TK_M_ACTION:
339 case TK_M_DEVPATH:
340 case TK_M_KERNEL:
341 case TK_M_SUBSYSTEM:
342 case TK_M_DRIVER:
343 case TK_M_WAITFOR:
344 case TK_M_DEVLINK:
345 case TK_M_NAME:
346 case TK_M_KERNELS:
347 case TK_M_SUBSYSTEMS:
348 case TK_M_DRIVERS:
349 case TK_M_TAGS:
350 case TK_M_PROGRAM:
351 case TK_M_IMPORT_FILE:
352 case TK_M_IMPORT_PROG:
353 case TK_M_IMPORT_DB:
354 case TK_M_IMPORT_CMDLINE:
355 case TK_M_IMPORT_PARENT:
356 case TK_M_RESULT:
357 case TK_A_NAME:
358 case TK_A_DEVLINK:
359 case TK_A_OWNER:
360 case TK_A_GROUP:
361 case TK_A_MODE:
362 case TK_A_RUN:
363 dbg(rules->udev, "%s %s '%s'(%s)\n",
364 token_str(type), operation_str(op), value, string_glob_str(glob));
365 break;
366 case TK_M_IMPORT_BUILTIN:
367 dbg(rules->udev, "%s %i '%s'\n", token_str(type), token->key.builtin_cmd, value);
368 break;
369 case TK_M_ATTR:
370 case TK_M_ATTRS:
371 case TK_M_ENV:
372 case TK_A_ATTR:
373 case TK_A_ENV:
374 dbg(rules->udev, "%s %s '%s' '%s'(%s)\n",
375 token_str(type), operation_str(op), attr, value, string_glob_str(glob));
376 break;
377 case TK_M_TAG:
378 case TK_A_TAG:
379 dbg(rules->udev, "%s %s '%s'\n", token_str(type), operation_str(op), value);
380 break;
381 case TK_A_STRING_ESCAPE_NONE:
382 case TK_A_STRING_ESCAPE_REPLACE:
383 case TK_A_DB_PERSIST:
384 dbg(rules->udev, "%s\n", token_str(type));
385 break;
386 case TK_M_TEST:
387 dbg(rules->udev, "%s %s '%s'(%s) %#o\n",
388 token_str(type), operation_str(op), value, string_glob_str(glob), token->key.mode);
389 break;
390 case TK_A_INOTIFY_WATCH:
391 dbg(rules->udev, "%s %u\n", token_str(type), token->key.watch);
392 break;
393 case TK_A_DEVLINK_PRIO:
394 dbg(rules->udev, "%s %u\n", token_str(type), token->key.devlink_prio);
395 break;
396 case TK_A_OWNER_ID:
397 dbg(rules->udev, "%s %s %u\n", token_str(type), operation_str(op), token->key.uid);
398 break;
399 case TK_A_GROUP_ID:
400 dbg(rules->udev, "%s %s %u\n", token_str(type), operation_str(op), token->key.gid);
401 break;
402 case TK_A_MODE_ID:
403 dbg(rules->udev, "%s %s %#o\n", token_str(type), operation_str(op), token->key.mode);
404 break;
405 case TK_A_STATIC_NODE:
406 dbg(rules->udev, "%s '%s'\n", token_str(type), value);
407 break;
408 case TK_M_EVENT_TIMEOUT:
409 dbg(rules->udev, "%s %u\n", token_str(type), token->key.event_timeout);
410 break;
411 case TK_A_GOTO:
412 dbg(rules->udev, "%s '%s' %u\n", token_str(type), value, token->key.rule_goto);
413 break;
414 case TK_END:
415 dbg(rules->udev, "* %s\n", token_str(type));
416 break;
417 case TK_M_PARENTS_MIN:
418 case TK_M_PARENTS_MAX:
419 case TK_M_MAX:
420 case TK_UNSET:
421 dbg(rules->udev, "unknown type %u\n", type);
422 break;
423 }
424 }
425
426 static void dump_rules(struct udev_rules *rules)
427 {
428 unsigned int i;
429
430 dbg(rules->udev, "dumping %u (%zu bytes) tokens, %u (%zu bytes) strings\n",
431 rules->token_cur,
432 rules->token_cur * sizeof(struct token),
433 rules->buf_count,
434 rules->buf_cur);
435 for(i = 0; i < rules->token_cur; i++)
436 dump_token(rules, &rules->tokens[i]);
437 }
438 #else
439 static inline const char *operation_str(enum operation_type type) { return NULL; }
440 static inline const char *token_str(enum token_type type) { return NULL; }
441 static inline void dump_token(struct udev_rules *rules, struct token *token) {}
442 static inline void dump_rules(struct udev_rules *rules) {}
443 #endif /* ENABLE_DEBUG */
444
445 static int add_new_string(struct udev_rules *rules, const char *str, size_t bytes)
446 {
447 int off;
448
449 /* grow buffer if needed */
450 if (rules->buf_cur + bytes+1 >= rules->buf_max) {
451 char *buf;
452 unsigned int add;
453
454 /* double the buffer size */
455 add = rules->buf_max;
456 if (add < bytes * 8)
457 add = bytes * 8;
458
459 buf = realloc(rules->buf, rules->buf_max + add);
460 if (buf == NULL)
461 return -1;
462 dbg(rules->udev, "extend buffer from %zu to %zu\n", rules->buf_max, rules->buf_max + add);
463 rules->buf = buf;
464 rules->buf_max += add;
465 }
466 off = rules->buf_cur;
467 memcpy(&rules->buf[rules->buf_cur], str, bytes);
468 rules->buf_cur += bytes;
469 rules->buf_count++;
470 return off;
471 }
472
473 static int add_string(struct udev_rules *rules, const char *str)
474 {
475 unsigned int node_idx;
476 struct trie_node *new_node;
477 unsigned int new_node_idx;
478 unsigned char key;
479 unsigned short len;
480 unsigned int depth;
481 unsigned int off;
482 struct trie_node *parent;
483
484 /* walk trie, start from last character of str to find matching tails */
485 len = strlen(str);
486 key = str[len-1];
487 node_idx = 0;
488 for (depth = 0; depth <= len; depth++) {
489 struct trie_node *node;
490 unsigned int child_idx;
491
492 node = &rules->trie_nodes[node_idx];
493 off = node->value_off + node->value_len - len;
494
495 /* match against current node */
496 if (depth == len || (node->value_len >= len && memcmp(&rules->buf[off], str, len) == 0))
497 return off;
498
499 /* lookup child node */
500 key = str[len - 1 - depth];
501 child_idx = node->child_idx;
502 while (child_idx > 0) {
503 struct trie_node *child;
504
505 child = &rules->trie_nodes[child_idx];
506 if (child->key == key)
507 break;
508 child_idx = child->next_child_idx;
509 }
510 if (child_idx == 0)
511 break;
512 node_idx = child_idx;
513 }
514
515 /* string not found, add it */
516 off = add_new_string(rules, str, len + 1);
517
518 /* grow trie nodes if needed */
519 if (rules->trie_nodes_cur >= rules->trie_nodes_max) {
520 struct trie_node *nodes;
521 unsigned int add;
522
523 /* double the buffer size */
524 add = rules->trie_nodes_max;
525 if (add < 8)
526 add = 8;
527
528 nodes = realloc(rules->trie_nodes, (rules->trie_nodes_max + add) * sizeof(struct trie_node));
529 if (nodes == NULL)
530 return -1;
531 dbg(rules->udev, "extend trie nodes from %u to %u\n",
532 rules->trie_nodes_max, rules->trie_nodes_max + add);
533 rules->trie_nodes = nodes;
534 rules->trie_nodes_max += add;
535 }
536
537 /* get a new node */
538 new_node_idx = rules->trie_nodes_cur;
539 rules->trie_nodes_cur++;
540 new_node = &rules->trie_nodes[new_node_idx];
541 memset(new_node, 0x00, sizeof(struct trie_node));
542 new_node->value_off = off;
543 new_node->value_len = len;
544 new_node->key = key;
545
546 /* join the parent's child list */
547 parent = &rules->trie_nodes[node_idx];
548 if (parent->child_idx == 0) {
549 parent->child_idx = new_node_idx;
550 } else {
551 struct trie_node *last_child;
552
553 last_child = &rules->trie_nodes[parent->last_child_idx];
554 last_child->next_child_idx = new_node_idx;
555 }
556 parent->last_child_idx = new_node_idx;
557 return off;
558 }
559
560 static int add_token(struct udev_rules *rules, struct token *token)
561 {
562 /* grow buffer if needed */
563 if (rules->token_cur+1 >= rules->token_max) {
564 struct token *tokens;
565 unsigned int add;
566
567 /* double the buffer size */
568 add = rules->token_max;
569 if (add < 8)
570 add = 8;
571
572 tokens = realloc(rules->tokens, (rules->token_max + add ) * sizeof(struct token));
573 if (tokens == NULL)
574 return -1;
575 dbg(rules->udev, "extend tokens from %u to %u\n", rules->token_max, rules->token_max + add);
576 rules->tokens = tokens;
577 rules->token_max += add;
578 }
579 memcpy(&rules->tokens[rules->token_cur], token, sizeof(struct token));
580 rules->token_cur++;
581 return 0;
582 }
583
584 static uid_t add_uid(struct udev_rules *rules, const char *owner)
585 {
586 unsigned int i;
587 uid_t uid;
588 unsigned int off;
589
590 /* lookup, if we know it already */
591 for (i = 0; i < rules->uids_cur; i++) {
592 off = rules->uids[i].name_off;
593 if (strcmp(&rules->buf[off], owner) == 0) {
594 uid = rules->uids[i].uid;
595 dbg(rules->udev, "return existing %u for '%s'\n", uid, owner);
596 return uid;
597 }
598 }
599 uid = util_lookup_user(rules->udev, owner);
600
601 /* grow buffer if needed */
602 if (rules->uids_cur+1 >= rules->uids_max) {
603 struct uid_gid *uids;
604 unsigned int add;
605
606 /* double the buffer size */
607 add = rules->uids_max;
608 if (add < 1)
609 add = 8;
610
611 uids = realloc(rules->uids, (rules->uids_max + add ) * sizeof(struct uid_gid));
612 if (uids == NULL)
613 return uid;
614 dbg(rules->udev, "extend uids from %u to %u\n", rules->uids_max, rules->uids_max + add);
615 rules->uids = uids;
616 rules->uids_max += add;
617 }
618 rules->uids[rules->uids_cur].uid = uid;
619 off = add_string(rules, owner);
620 if (off <= 0)
621 return uid;
622 rules->uids[rules->uids_cur].name_off = off;
623 rules->uids_cur++;
624 return uid;
625 }
626
627 static gid_t add_gid(struct udev_rules *rules, const char *group)
628 {
629 unsigned int i;
630 gid_t gid;
631 unsigned int off;
632
633 /* lookup, if we know it already */
634 for (i = 0; i < rules->gids_cur; i++) {
635 off = rules->gids[i].name_off;
636 if (strcmp(&rules->buf[off], group) == 0) {
637 gid = rules->gids[i].gid;
638 dbg(rules->udev, "return existing %u for '%s'\n", gid, group);
639 return gid;
640 }
641 }
642 gid = util_lookup_group(rules->udev, group);
643
644 /* grow buffer if needed */
645 if (rules->gids_cur+1 >= rules->gids_max) {
646 struct uid_gid *gids;
647 unsigned int add;
648
649 /* double the buffer size */
650 add = rules->gids_max;
651 if (add < 1)
652 add = 8;
653
654 gids = realloc(rules->gids, (rules->gids_max + add ) * sizeof(struct uid_gid));
655 if (gids == NULL)
656 return gid;
657 dbg(rules->udev, "extend gids from %u to %u\n", rules->gids_max, rules->gids_max + add);
658 rules->gids = gids;
659 rules->gids_max += add;
660 }
661 rules->gids[rules->gids_cur].gid = gid;
662 off = add_string(rules, group);
663 if (off <= 0)
664 return gid;
665 rules->gids[rules->gids_cur].name_off = off;
666 rules->gids_cur++;
667 return gid;
668 }
669
670 static int import_property_from_string(struct udev_device *dev, char *line)
671 {
672 struct udev *udev = udev_device_get_udev(dev);
673 char *key;
674 char *val;
675 size_t len;
676
677 /* find key */
678 key = line;
679 while (isspace(key[0]))
680 key++;
681
682 /* comment or empty line */
683 if (key[0] == '#' || key[0] == '\0')
684 return -1;
685
686 /* split key/value */
687 val = strchr(key, '=');
688 if (val == NULL)
689 return -1;
690 val[0] = '\0';
691 val++;
692
693 /* find value */
694 while (isspace(val[0]))
695 val++;
696
697 /* terminate key */
698 len = strlen(key);
699 if (len == 0)
700 return -1;
701 while (isspace(key[len-1]))
702 len--;
703 key[len] = '\0';
704
705 /* terminate value */
706 len = strlen(val);
707 if (len == 0)
708 return -1;
709 while (isspace(val[len-1]))
710 len--;
711 val[len] = '\0';
712
713 if (len == 0)
714 return -1;
715
716 /* unquote */
717 if (val[0] == '"' || val[0] == '\'') {
718 if (val[len-1] != val[0]) {
719 info(udev, "inconsistent quoting: '%s', skip\n", line);
720 return -1;
721 }
722 val[len-1] = '\0';
723 val++;
724 }
725
726 dbg(udev, "adding '%s'='%s'\n", key, val);
727
728 /* handle device, renamed by external tool, returning new path */
729 if (strcmp(key, "DEVPATH") == 0) {
730 char syspath[UTIL_PATH_SIZE];
731
732 info(udev, "updating devpath from '%s' to '%s'\n",
733 udev_device_get_devpath(dev), val);
734 util_strscpyl(syspath, sizeof(syspath), udev_get_sys_path(udev), val, NULL);
735 udev_device_set_syspath(dev, syspath);
736 } else {
737 struct udev_list_entry *entry;
738
739 entry = udev_device_add_property(dev, key, val);
740 /* store in db, skip private keys */
741 if (key[0] != '.')
742 udev_list_entry_set_num(entry, true);
743 }
744 return 0;
745 }
746
747 static int import_file_into_properties(struct udev_device *dev, const char *filename)
748 {
749 FILE *f;
750 char line[UTIL_LINE_SIZE];
751
752 f = fopen(filename, "r");
753 if (f == NULL)
754 return -1;
755 while (fgets(line, sizeof(line), f) != NULL)
756 import_property_from_string(dev, line);
757 fclose(f);
758 return 0;
759 }
760
761 static int import_program_into_properties(struct udev_event *event, const char *program, const sigset_t *sigmask)
762 {
763 struct udev_device *dev = event->dev;
764 char **envp;
765 char result[UTIL_LINE_SIZE];
766 char *line;
767 int err;
768
769 envp = udev_device_get_properties_envp(dev);
770 err = udev_event_spawn(event, program, envp, sigmask, result, sizeof(result));
771 if (err < 0)
772 return err;
773
774 line = result;
775 while (line != NULL) {
776 char *pos;
777
778 pos = strchr(line, '\n');
779 if (pos != NULL) {
780 pos[0] = '\0';
781 pos = &pos[1];
782 }
783 import_property_from_string(dev, line);
784 line = pos;
785 }
786 return 0;
787 }
788
789 static int import_parent_into_properties(struct udev_device *dev, const char *filter)
790 {
791 struct udev *udev = udev_device_get_udev(dev);
792 struct udev_device *dev_parent;
793 struct udev_list_entry *list_entry;
794
795 dev_parent = udev_device_get_parent(dev);
796 if (dev_parent == NULL)
797 return -1;
798
799 dbg(udev, "found parent '%s', get the node name\n", udev_device_get_syspath(dev_parent));
800 udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(dev_parent)) {
801 const char *key = udev_list_entry_get_name(list_entry);
802 const char *val = udev_list_entry_get_value(list_entry);
803
804 if (fnmatch(filter, key, 0) == 0) {
805 struct udev_list_entry *entry;
806
807 dbg(udev, "import key '%s=%s'\n", key, val);
808 entry = udev_device_add_property(dev, key, val);
809 /* store in db, skip private keys */
810 if (key[0] != '.')
811 udev_list_entry_set_num(entry, true);
812 }
813 }
814 return 0;
815 }
816
817 #define WAIT_LOOP_PER_SECOND 50
818 static int wait_for_file(struct udev_device *dev, const char *file, int timeout)
819 {
820 struct udev *udev = udev_device_get_udev(dev);
821 char filepath[UTIL_PATH_SIZE];
822 char devicepath[UTIL_PATH_SIZE];
823 struct stat stats;
824 int loop = timeout * WAIT_LOOP_PER_SECOND;
825
826 /* a relative path is a device attribute */
827 devicepath[0] = '\0';
828 if (file[0] != '/') {
829 util_strscpyl(devicepath, sizeof(devicepath),
830 udev_get_sys_path(udev), udev_device_get_devpath(dev), NULL);
831 util_strscpyl(filepath, sizeof(filepath), devicepath, "/", file, NULL);
832 file = filepath;
833 }
834
835 dbg(udev, "will wait %i sec for '%s'\n", timeout, file);
836 while (--loop) {
837 const struct timespec duration = { 0, 1000 * 1000 * 1000 / WAIT_LOOP_PER_SECOND };
838
839 /* lookup file */
840 if (stat(file, &stats) == 0) {
841 info(udev, "file '%s' appeared after %i loops\n", file, (timeout * WAIT_LOOP_PER_SECOND) - loop-1);
842 return 0;
843 }
844 /* make sure, the device did not disappear in the meantime */
845 if (devicepath[0] != '\0' && stat(devicepath, &stats) != 0) {
846 info(udev, "device disappeared while waiting for '%s'\n", file);
847 return -2;
848 }
849 info(udev, "wait for '%s' for %i mseconds\n", file, 1000 / WAIT_LOOP_PER_SECOND);
850 nanosleep(&duration, NULL);
851 }
852 info(udev, "waiting for '%s' failed\n", file);
853 return -1;
854 }
855
856 static int attr_subst_subdir(char *attr, size_t len)
857 {
858 bool found = false;
859
860 if (strstr(attr, "/*/")) {
861 char *pos;
862 char dirname[UTIL_PATH_SIZE];
863 const char *tail;
864 DIR *dir;
865
866 util_strscpy(dirname, sizeof(dirname), attr);
867 pos = strstr(dirname, "/*/");
868 if (pos == NULL)
869 return -1;
870 pos[0] = '\0';
871 tail = &pos[2];
872 dir = opendir(dirname);
873 if (dir != NULL) {
874 struct dirent *dent;
875
876 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
877 struct stat stats;
878
879 if (dent->d_name[0] == '.')
880 continue;
881 util_strscpyl(attr, len, dirname, "/", dent->d_name, tail, NULL);
882 if (stat(attr, &stats) == 0) {
883 found = true;
884 break;
885 }
886 }
887 closedir(dir);
888 }
889 }
890
891 return found;
892 }
893
894 static int get_key(struct udev *udev, char **line, char **key, enum operation_type *op, char **value)
895 {
896 char *linepos;
897 char *temp;
898
899 linepos = *line;
900 if (linepos == NULL || linepos[0] == '\0')
901 return -1;
902
903 /* skip whitespace */
904 while (isspace(linepos[0]) || linepos[0] == ',')
905 linepos++;
906
907 /* get the key */
908 if (linepos[0] == '\0')
909 return -1;
910 *key = linepos;
911
912 for (;;) {
913 linepos++;
914 if (linepos[0] == '\0')
915 return -1;
916 if (isspace(linepos[0]))
917 break;
918 if (linepos[0] == '=')
919 break;
920 if ((linepos[0] == '+') || (linepos[0] == '!') || (linepos[0] == ':'))
921 if (linepos[1] == '=')
922 break;
923 }
924
925 /* remember end of key */
926 temp = linepos;
927
928 /* skip whitespace after key */
929 while (isspace(linepos[0]))
930 linepos++;
931 if (linepos[0] == '\0')
932 return -1;
933
934 /* get operation type */
935 if (linepos[0] == '=' && linepos[1] == '=') {
936 *op = OP_MATCH;
937 linepos += 2;
938 } else if (linepos[0] == '!' && linepos[1] == '=') {
939 *op = OP_NOMATCH;
940 linepos += 2;
941 } else if (linepos[0] == '+' && linepos[1] == '=') {
942 *op = OP_ADD;
943 linepos += 2;
944 } else if (linepos[0] == '=') {
945 *op = OP_ASSIGN;
946 linepos++;
947 } else if (linepos[0] == ':' && linepos[1] == '=') {
948 *op = OP_ASSIGN_FINAL;
949 linepos += 2;
950 } else
951 return -1;
952
953 /* terminate key */
954 temp[0] = '\0';
955
956 /* skip whitespace after operator */
957 while (isspace(linepos[0]))
958 linepos++;
959 if (linepos[0] == '\0')
960 return -1;
961
962 /* get the value */
963 if (linepos[0] == '"')
964 linepos++;
965 else
966 return -1;
967 *value = linepos;
968
969 /* terminate */
970 temp = strchr(linepos, '"');
971 if (!temp)
972 return -1;
973 temp[0] = '\0';
974 temp++;
975 dbg(udev, "%s '%s'-'%s'\n", operation_str(*op), *key, *value);
976
977 /* move line to next key */
978 *line = temp;
979 return 0;
980 }
981
982 /* extract possible KEY{attr} */
983 static char *get_key_attribute(struct udev *udev, char *str)
984 {
985 char *pos;
986 char *attr;
987
988 attr = strchr(str, '{');
989 if (attr != NULL) {
990 attr++;
991 pos = strchr(attr, '}');
992 if (pos == NULL) {
993 err(udev, "missing closing brace for format\n");
994 return NULL;
995 }
996 pos[0] = '\0';
997 dbg(udev, "attribute='%s'\n", attr);
998 return attr;
999 }
1000 return NULL;
1001 }
1002
1003 static int rule_add_key(struct rule_tmp *rule_tmp, enum token_type type,
1004 enum operation_type op,
1005 const char *value, const void *data)
1006 {
1007 struct token *token = &rule_tmp->token[rule_tmp->token_cur];
1008 const char *attr = NULL;
1009
1010 memset(token, 0x00, sizeof(struct token));
1011
1012 switch (type) {
1013 case TK_M_ACTION:
1014 case TK_M_DEVPATH:
1015 case TK_M_KERNEL:
1016 case TK_M_SUBSYSTEM:
1017 case TK_M_DRIVER:
1018 case TK_M_WAITFOR:
1019 case TK_M_DEVLINK:
1020 case TK_M_NAME:
1021 case TK_M_KERNELS:
1022 case TK_M_SUBSYSTEMS:
1023 case TK_M_DRIVERS:
1024 case TK_M_TAGS:
1025 case TK_M_PROGRAM:
1026 case TK_M_IMPORT_FILE:
1027 case TK_M_IMPORT_PROG:
1028 case TK_M_IMPORT_DB:
1029 case TK_M_IMPORT_CMDLINE:
1030 case TK_M_IMPORT_PARENT:
1031 case TK_M_RESULT:
1032 case TK_A_OWNER:
1033 case TK_A_GROUP:
1034 case TK_A_MODE:
1035 case TK_A_NAME:
1036 case TK_A_GOTO:
1037 case TK_M_TAG:
1038 case TK_A_TAG:
1039 token->key.value_off = add_string(rule_tmp->rules, value);
1040 break;
1041 case TK_M_IMPORT_BUILTIN:
1042 token->key.value_off = add_string(rule_tmp->rules, value);
1043 token->key.builtin_cmd = *(enum udev_builtin_cmd *)data;
1044 break;
1045 case TK_M_ENV:
1046 case TK_M_ATTR:
1047 case TK_M_ATTRS:
1048 case TK_A_ATTR:
1049 case TK_A_ENV:
1050 attr = data;
1051 token->key.value_off = add_string(rule_tmp->rules, value);
1052 token->key.attr_off = add_string(rule_tmp->rules, attr);
1053 break;
1054 case TK_A_DEVLINK:
1055 token->key.value_off = add_string(rule_tmp->rules, value);
1056 token->key.devlink_unique = *(int *)data;
1057 break;
1058 case TK_M_TEST:
1059 token->key.value_off = add_string(rule_tmp->rules, value);
1060 if (data != NULL)
1061 token->key.mode = *(mode_t *)data;
1062 break;
1063 case TK_A_STRING_ESCAPE_NONE:
1064 case TK_A_STRING_ESCAPE_REPLACE:
1065 case TK_A_DB_PERSIST:
1066 break;
1067 case TK_A_RUN:
1068 token->key.value_off = add_string(rule_tmp->rules, value);
1069 break;
1070 case TK_A_INOTIFY_WATCH:
1071 case TK_A_DEVLINK_PRIO:
1072 token->key.devlink_prio = *(int *)data;
1073 break;
1074 case TK_A_OWNER_ID:
1075 token->key.uid = *(uid_t *)data;
1076 break;
1077 case TK_A_GROUP_ID:
1078 token->key.gid = *(gid_t *)data;
1079 break;
1080 case TK_A_MODE_ID:
1081 token->key.mode = *(mode_t *)data;
1082 break;
1083 case TK_A_STATIC_NODE:
1084 token->key.value_off = add_string(rule_tmp->rules, value);
1085 break;
1086 case TK_M_EVENT_TIMEOUT:
1087 token->key.event_timeout = *(int *)data;
1088 break;
1089 case TK_RULE:
1090 case TK_M_PARENTS_MIN:
1091 case TK_M_PARENTS_MAX:
1092 case TK_M_MAX:
1093 case TK_END:
1094 case TK_UNSET:
1095 err(rule_tmp->rules->udev, "wrong type %u\n", type);
1096 return -1;
1097 }
1098
1099 if (value != NULL && type < TK_M_MAX) {
1100 /* check if we need to split or call fnmatch() while matching rules */
1101 enum string_glob_type glob;
1102 int has_split;
1103 int has_glob;
1104
1105 has_split = (strchr(value, '|') != NULL);
1106 has_glob = (strchr(value, '*') != NULL || strchr(value, '?') != NULL || strchr(value, '[') != NULL);
1107 if (has_split && has_glob) {
1108 glob = GL_SPLIT_GLOB;
1109 } else if (has_split) {
1110 glob = GL_SPLIT;
1111 } else if (has_glob) {
1112 if (strcmp(value, "?*") == 0)
1113 glob = GL_SOMETHING;
1114 else
1115 glob = GL_GLOB;
1116 } else {
1117 glob = GL_PLAIN;
1118 }
1119 token->key.glob = glob;
1120 }
1121
1122 if (value != NULL && type > TK_M_MAX) {
1123 /* check if assigned value has substitution chars */
1124 if (value[0] == '[')
1125 token->key.subst = SB_SUBSYS;
1126 else if (strchr(value, '%') != NULL || strchr(value, '$') != NULL)
1127 token->key.subst = SB_FORMAT;
1128 else
1129 token->key.subst = SB_NONE;
1130 }
1131
1132 if (attr != NULL) {
1133 /* check if property/attribut name has substitution chars */
1134 if (attr[0] == '[')
1135 token->key.attrsubst = SB_SUBSYS;
1136 else if (strchr(attr, '%') != NULL || strchr(attr, '$') != NULL)
1137 token->key.attrsubst = SB_FORMAT;
1138 else
1139 token->key.attrsubst = SB_NONE;
1140 }
1141
1142 token->key.type = type;
1143 token->key.op = op;
1144 rule_tmp->token_cur++;
1145 if (rule_tmp->token_cur >= ARRAY_SIZE(rule_tmp->token)) {
1146 err(rule_tmp->rules->udev, "temporary rule array too small\n");
1147 return -1;
1148 }
1149 return 0;
1150 }
1151
1152 static int sort_token(struct udev_rules *rules, struct rule_tmp *rule_tmp)
1153 {
1154 unsigned int i;
1155 unsigned int start = 0;
1156 unsigned int end = rule_tmp->token_cur;
1157
1158 for (i = 0; i < rule_tmp->token_cur; i++) {
1159 enum token_type next_val = TK_UNSET;
1160 unsigned int next_idx = 0;
1161 unsigned int j;
1162
1163 /* find smallest value */
1164 for (j = start; j < end; j++) {
1165 if (rule_tmp->token[j].type == TK_UNSET)
1166 continue;
1167 if (next_val == TK_UNSET || rule_tmp->token[j].type < next_val) {
1168 next_val = rule_tmp->token[j].type;
1169 next_idx = j;
1170 }
1171 }
1172
1173 /* add token and mark done */
1174 if (add_token(rules, &rule_tmp->token[next_idx]) != 0)
1175 return -1;
1176 rule_tmp->token[next_idx].type = TK_UNSET;
1177
1178 /* shrink range */
1179 if (next_idx == start)
1180 start++;
1181 if (next_idx+1 == end)
1182 end--;
1183 }
1184 return 0;
1185 }
1186
1187 static int add_rule(struct udev_rules *rules, char *line,
1188 const char *filename, unsigned int filename_off, unsigned int lineno)
1189 {
1190 char *linepos;
1191 char *attr;
1192 struct rule_tmp rule_tmp;
1193
1194 memset(&rule_tmp, 0x00, sizeof(struct rule_tmp));
1195 rule_tmp.rules = rules;
1196 rule_tmp.rule.type = TK_RULE;
1197 rule_tmp.rule.rule.filename_off = filename_off;
1198 rule_tmp.rule.rule.filename_line = lineno;
1199
1200 linepos = line;
1201 for (;;) {
1202 char *key;
1203 char *value;
1204 enum operation_type op;
1205
1206 if (get_key(rules->udev, &linepos, &key, &op, &value) != 0)
1207 break;
1208
1209 if (strcmp(key, "ACTION") == 0) {
1210 if (op > OP_MATCH_MAX) {
1211 err(rules->udev, "invalid ACTION operation\n");
1212 goto invalid;
1213 }
1214 rule_add_key(&rule_tmp, TK_M_ACTION, op, value, NULL);
1215 continue;
1216 }
1217
1218 if (strcmp(key, "DEVPATH") == 0) {
1219 if (op > OP_MATCH_MAX) {
1220 err(rules->udev, "invalid DEVPATH operation\n");
1221 goto invalid;
1222 }
1223 rule_add_key(&rule_tmp, TK_M_DEVPATH, op, value, NULL);
1224 continue;
1225 }
1226
1227 if (strcmp(key, "KERNEL") == 0) {
1228 if (op > OP_MATCH_MAX) {
1229 err(rules->udev, "invalid KERNEL operation\n");
1230 goto invalid;
1231 }
1232 rule_add_key(&rule_tmp, TK_M_KERNEL, op, value, NULL);
1233 continue;
1234 }
1235
1236 if (strcmp(key, "SUBSYSTEM") == 0) {
1237 if (op > OP_MATCH_MAX) {
1238 err(rules->udev, "invalid SUBSYSTEM operation\n");
1239 goto invalid;
1240 }
1241 /* bus, class, subsystem events should all be the same */
1242 if (strcmp(value, "subsystem") == 0 ||
1243 strcmp(value, "bus") == 0 ||
1244 strcmp(value, "class") == 0) {
1245 if (strcmp(value, "bus") == 0 || strcmp(value, "class") == 0)
1246 err(rules->udev, "'%s' must be specified as 'subsystem' \n"
1247 "please fix it in %s:%u", value, filename, lineno);
1248 rule_add_key(&rule_tmp, TK_M_SUBSYSTEM, op, "subsystem|class|bus", NULL);
1249 } else
1250 rule_add_key(&rule_tmp, TK_M_SUBSYSTEM, op, value, NULL);
1251 continue;
1252 }
1253
1254 if (strcmp(key, "DRIVER") == 0) {
1255 if (op > OP_MATCH_MAX) {
1256 err(rules->udev, "invalid DRIVER operation\n");
1257 goto invalid;
1258 }
1259 rule_add_key(&rule_tmp, TK_M_DRIVER, op, value, NULL);
1260 continue;
1261 }
1262
1263 if (strncmp(key, "ATTR{", sizeof("ATTR{")-1) == 0) {
1264 attr = get_key_attribute(rules->udev, key + sizeof("ATTR")-1);
1265 if (attr == NULL) {
1266 err(rules->udev, "error parsing ATTR attribute\n");
1267 goto invalid;
1268 }
1269 if (op < OP_MATCH_MAX) {
1270 rule_add_key(&rule_tmp, TK_M_ATTR, op, value, attr);
1271 } else {
1272 rule_add_key(&rule_tmp, TK_A_ATTR, op, value, attr);
1273 }
1274 continue;
1275 }
1276
1277 if (strcmp(key, "KERNELS") == 0) {
1278 if (op > OP_MATCH_MAX) {
1279 err(rules->udev, "invalid KERNELS operation\n");
1280 goto invalid;
1281 }
1282 rule_add_key(&rule_tmp, TK_M_KERNELS, op, value, NULL);
1283 continue;
1284 }
1285
1286 if (strcmp(key, "SUBSYSTEMS") == 0) {
1287 if (op > OP_MATCH_MAX) {
1288 err(rules->udev, "invalid SUBSYSTEMS operation\n");
1289 goto invalid;
1290 }
1291 rule_add_key(&rule_tmp, TK_M_SUBSYSTEMS, op, value, NULL);
1292 continue;
1293 }
1294
1295 if (strcmp(key, "DRIVERS") == 0) {
1296 if (op > OP_MATCH_MAX) {
1297 err(rules->udev, "invalid DRIVERS operation\n");
1298 goto invalid;
1299 }
1300 rule_add_key(&rule_tmp, TK_M_DRIVERS, op, value, NULL);
1301 continue;
1302 }
1303
1304 if (strncmp(key, "ATTRS{", sizeof("ATTRS{")-1) == 0) {
1305 if (op > OP_MATCH_MAX) {
1306 err(rules->udev, "invalid ATTRS operation\n");
1307 goto invalid;
1308 }
1309 attr = get_key_attribute(rules->udev, key + sizeof("ATTRS")-1);
1310 if (attr == NULL) {
1311 err(rules->udev, "error parsing ATTRS attribute\n");
1312 goto invalid;
1313 }
1314 if (strncmp(attr, "device/", 7) == 0)
1315 err(rules->udev, "the 'device' link may not be available in a future kernel, "
1316 "please fix it in %s:%u", filename, lineno);
1317 else if (strstr(attr, "../") != NULL)
1318 err(rules->udev, "do not reference parent sysfs directories directly, "
1319 "it may break with a future kernel, please fix it in %s:%u", filename, lineno);
1320 rule_add_key(&rule_tmp, TK_M_ATTRS, op, value, attr);
1321 continue;
1322 }
1323
1324 if (strcmp(key, "TAGS") == 0) {
1325 if (op > OP_MATCH_MAX) {
1326 err(rules->udev, "invalid TAGS operation\n");
1327 goto invalid;
1328 }
1329 rule_add_key(&rule_tmp, TK_M_TAGS, op, value, NULL);
1330 continue;
1331 }
1332
1333 if (strncmp(key, "ENV{", sizeof("ENV{")-1) == 0) {
1334 attr = get_key_attribute(rules->udev, key + sizeof("ENV")-1);
1335 if (attr == NULL) {
1336 err(rules->udev, "error parsing ENV attribute\n");
1337 goto invalid;
1338 }
1339 if (op < OP_MATCH_MAX) {
1340 if (rule_add_key(&rule_tmp, TK_M_ENV, op, value, attr) != 0)
1341 goto invalid;
1342 } else {
1343 static const char *blacklist[] = {
1344 "ACTION",
1345 "SUBSYSTEM",
1346 "DEVTYPE",
1347 "MAJOR",
1348 "MINOR",
1349 "DRIVER",
1350 "IFINDEX",
1351 "DEVNAME",
1352 "DEVLINKS",
1353 "DEVPATH",
1354 "TAGS",
1355 };
1356 unsigned int i;
1357
1358 for (i = 0; i < ARRAY_SIZE(blacklist); i++)
1359 if (strcmp(attr, blacklist[i]) == 0) {
1360 err(rules->udev, "invalid ENV attribute, '%s' can not be set %s:%u\n", attr, filename, lineno);
1361 continue;
1362 }
1363 if (rule_add_key(&rule_tmp, TK_A_ENV, op, value, attr) != 0)
1364 goto invalid;
1365 }
1366 continue;
1367 }
1368
1369 if (strcmp(key, "TAG") == 0) {
1370 if (op < OP_MATCH_MAX)
1371 rule_add_key(&rule_tmp, TK_M_TAG, op, value, NULL);
1372 else
1373 rule_add_key(&rule_tmp, TK_A_TAG, op, value, NULL);
1374 continue;
1375 }
1376
1377 if (strcmp(key, "PROGRAM") == 0) {
1378 rule_add_key(&rule_tmp, TK_M_PROGRAM, op, value, NULL);
1379 continue;
1380 }
1381
1382 if (strcmp(key, "RESULT") == 0) {
1383 if (op > OP_MATCH_MAX) {
1384 err(rules->udev, "invalid RESULT operation\n");
1385 goto invalid;
1386 }
1387 rule_add_key(&rule_tmp, TK_M_RESULT, op, value, NULL);
1388 continue;
1389 }
1390
1391 if (strncmp(key, "IMPORT", sizeof("IMPORT")-1) == 0) {
1392 attr = get_key_attribute(rules->udev, key + sizeof("IMPORT")-1);
1393 if (attr == NULL) {
1394 err(rules->udev, "IMPORT{} type missing, ignoring IMPORT %s:%u\n", filename, lineno);
1395 continue;
1396 }
1397 if (strstr(attr, "program")) {
1398 /* find known built-in command */
1399 if (value[0] != '/') {
1400 enum udev_builtin_cmd cmd;
1401
1402 cmd = udev_builtin_lookup(value);
1403 if (cmd < UDEV_BUILTIN_MAX) {
1404 info(rules->udev, "IMPORT found builtin '%s', replacing %s:%u\n",
1405 value, filename, lineno);
1406 rule_add_key(&rule_tmp, TK_M_IMPORT_BUILTIN, op, value, &cmd);
1407 continue;
1408 }
1409 }
1410 dbg(rules->udev, "IMPORT will be executed\n");
1411 rule_add_key(&rule_tmp, TK_M_IMPORT_PROG, op, value, NULL);
1412 } else if (strstr(attr, "builtin")) {
1413 enum udev_builtin_cmd cmd = udev_builtin_lookup(value);
1414
1415 dbg(rules->udev, "IMPORT execute builtin\n");
1416 if (cmd < UDEV_BUILTIN_MAX)
1417 rule_add_key(&rule_tmp, TK_M_IMPORT_BUILTIN, op, value, &cmd);
1418 else
1419 err(rules->udev, "IMPORT{builtin}: '%s' unknown %s:%u\n", value, filename, lineno);
1420 } else if (strstr(attr, "file")) {
1421 dbg(rules->udev, "IMPORT will be included as file\n");
1422 rule_add_key(&rule_tmp, TK_M_IMPORT_FILE, op, value, NULL);
1423 } else if (strstr(attr, "db")) {
1424 dbg(rules->udev, "IMPORT will include db values\n");
1425 rule_add_key(&rule_tmp, TK_M_IMPORT_DB, op, value, NULL);
1426 } else if (strstr(attr, "cmdline")) {
1427 dbg(rules->udev, "IMPORT will include db values\n");
1428 rule_add_key(&rule_tmp, TK_M_IMPORT_CMDLINE, op, value, NULL);
1429 } else if (strstr(attr, "parent")) {
1430 dbg(rules->udev, "IMPORT will include the parent values\n");
1431 rule_add_key(&rule_tmp, TK_M_IMPORT_PARENT, op, value, NULL);
1432 }
1433 continue;
1434 }
1435
1436 if (strncmp(key, "TEST", sizeof("TEST")-1) == 0) {
1437 mode_t mode = 0;
1438
1439 if (op > OP_MATCH_MAX) {
1440 err(rules->udev, "invalid TEST operation\n");
1441 goto invalid;
1442 }
1443 attr = get_key_attribute(rules->udev, key + sizeof("TEST")-1);
1444 if (attr != NULL) {
1445 mode = strtol(attr, NULL, 8);
1446 rule_add_key(&rule_tmp, TK_M_TEST, op, value, &mode);
1447 } else {
1448 rule_add_key(&rule_tmp, TK_M_TEST, op, value, NULL);
1449 }
1450 continue;
1451 }
1452
1453 if (strcmp(key, "RUN") == 0) {
1454 rule_add_key(&rule_tmp, TK_A_RUN, op, value, NULL);
1455 continue;
1456 }
1457
1458 if (strcmp(key, "WAIT_FOR") == 0 || strcmp(key, "WAIT_FOR_SYSFS") == 0) {
1459 rule_add_key(&rule_tmp, TK_M_WAITFOR, 0, value, NULL);
1460 continue;
1461 }
1462
1463 if (strcmp(key, "LABEL") == 0) {
1464 rule_tmp.rule.rule.label_off = add_string(rules, value);
1465 continue;
1466 }
1467
1468 if (strcmp(key, "GOTO") == 0) {
1469 rule_add_key(&rule_tmp, TK_A_GOTO, 0, value, NULL);
1470 continue;
1471 }
1472
1473 if (strncmp(key, "NAME", sizeof("NAME")-1) == 0) {
1474 if (op < OP_MATCH_MAX) {
1475 rule_add_key(&rule_tmp, TK_M_NAME, op, value, NULL);
1476 } else {
1477 if (strcmp(value, "%k") == 0) {
1478 err(rules->udev, "NAME=\"%%k\" is ignored, because it breaks kernel supplied names, "
1479 "please remove it from %s:%u\n", filename, lineno);
1480 continue;
1481 }
1482 if (value[0] == '\0') {
1483 info(rules->udev, "NAME=\"\" is ignored, because udev will not delete any device nodes, "
1484 "please remove it from %s:%u\n", filename, lineno);
1485 continue;
1486 }
1487 rule_add_key(&rule_tmp, TK_A_NAME, op, value, NULL);
1488 }
1489 rule_tmp.rule.rule.can_set_name = true;
1490 continue;
1491 }
1492
1493 if (strncmp(key, "SYMLINK", sizeof("SYMLINK")-1) == 0) {
1494 if (op < OP_MATCH_MAX) {
1495 rule_add_key(&rule_tmp, TK_M_DEVLINK, op, value, NULL);
1496 } else {
1497 int flag = 0;
1498
1499 attr = get_key_attribute(rules->udev, key + sizeof("SYMLINK")-1);
1500 if (attr != NULL && strstr(attr, "unique") != NULL)
1501 flag = 1;
1502 rule_add_key(&rule_tmp, TK_A_DEVLINK, op, value, &flag);
1503 }
1504 rule_tmp.rule.rule.can_set_name = true;
1505 continue;
1506 }
1507
1508 if (strcmp(key, "OWNER") == 0) {
1509 uid_t uid;
1510 char *endptr;
1511
1512 uid = strtoul(value, &endptr, 10);
1513 if (endptr[0] == '\0') {
1514 rule_add_key(&rule_tmp, TK_A_OWNER_ID, op, NULL, &uid);
1515 } else if ((rules->resolve_names > 0) && strchr("$%", value[0]) == NULL) {
1516 uid = add_uid(rules, value);
1517 rule_add_key(&rule_tmp, TK_A_OWNER_ID, op, NULL, &uid);
1518 } else if (rules->resolve_names >= 0) {
1519 rule_add_key(&rule_tmp, TK_A_OWNER, op, value, NULL);
1520 }
1521 rule_tmp.rule.rule.can_set_name = true;
1522 continue;
1523 }
1524
1525 if (strcmp(key, "GROUP") == 0) {
1526 gid_t gid;
1527 char *endptr;
1528
1529 gid = strtoul(value, &endptr, 10);
1530 if (endptr[0] == '\0') {
1531 rule_add_key(&rule_tmp, TK_A_GROUP_ID, op, NULL, &gid);
1532 } else if ((rules->resolve_names > 0) && strchr("$%", value[0]) == NULL) {
1533 gid = add_gid(rules, value);
1534 rule_add_key(&rule_tmp, TK_A_GROUP_ID, op, NULL, &gid);
1535 } else if (rules->resolve_names >= 0) {
1536 rule_add_key(&rule_tmp, TK_A_GROUP, op, value, NULL);
1537 }
1538 rule_tmp.rule.rule.can_set_name = true;
1539 continue;
1540 }
1541
1542 if (strcmp(key, "MODE") == 0) {
1543 mode_t mode;
1544 char *endptr;
1545
1546 mode = strtol(value, &endptr, 8);
1547 if (endptr[0] == '\0')
1548 rule_add_key(&rule_tmp, TK_A_MODE_ID, op, NULL, &mode);
1549 else
1550 rule_add_key(&rule_tmp, TK_A_MODE, op, value, NULL);
1551 rule_tmp.rule.rule.can_set_name = true;
1552 continue;
1553 }
1554
1555 if (strcmp(key, "OPTIONS") == 0) {
1556 const char *pos;
1557
1558 pos = strstr(value, "link_priority=");
1559 if (pos != NULL) {
1560 int prio = atoi(&pos[strlen("link_priority=")]);
1561
1562 rule_add_key(&rule_tmp, TK_A_DEVLINK_PRIO, op, NULL, &prio);
1563 dbg(rules->udev, "link priority=%i\n", prio);
1564 }
1565
1566 pos = strstr(value, "event_timeout=");
1567 if (pos != NULL) {
1568 int tout = atoi(&pos[strlen("event_timeout=")]);
1569
1570 rule_add_key(&rule_tmp, TK_M_EVENT_TIMEOUT, op, NULL, &tout);
1571 dbg(rules->udev, "event timeout=%i\n", tout);
1572 }
1573
1574 pos = strstr(value, "string_escape=");
1575 if (pos != NULL) {
1576 pos = &pos[strlen("string_escape=")];
1577 if (strncmp(pos, "none", strlen("none")) == 0)
1578 rule_add_key(&rule_tmp, TK_A_STRING_ESCAPE_NONE, op, NULL, NULL);
1579 else if (strncmp(pos, "replace", strlen("replace")) == 0)
1580 rule_add_key(&rule_tmp, TK_A_STRING_ESCAPE_REPLACE, op, NULL, NULL);
1581 }
1582
1583 pos = strstr(value, "db_persist");
1584 if (pos != NULL)
1585 rule_add_key(&rule_tmp, TK_A_DB_PERSIST, op, NULL, NULL);
1586
1587 pos = strstr(value, "nowatch");
1588 if (pos != NULL) {
1589 const int off = 0;
1590
1591 rule_add_key(&rule_tmp, TK_A_INOTIFY_WATCH, op, NULL, &off);
1592 dbg(rules->udev, "inotify watch of device disabled\n");
1593 } else {
1594 pos = strstr(value, "watch");
1595 if (pos != NULL) {
1596 const int on = 1;
1597
1598 rule_add_key(&rule_tmp, TK_A_INOTIFY_WATCH, op, NULL, &on);
1599 dbg(rules->udev, "inotify watch of device requested\n");
1600 }
1601 }
1602
1603 pos = strstr(value, "static_node=");
1604 if (pos != NULL) {
1605 rule_add_key(&rule_tmp, TK_A_STATIC_NODE, op, &pos[strlen("static_node=")], NULL);
1606 rule_tmp.rule.rule.has_static_node = true;
1607 }
1608
1609 continue;
1610 }
1611
1612 err(rules->udev, "unknown key '%s' in %s:%u\n", key, filename, lineno);
1613 goto invalid;
1614 }
1615
1616 /* add rule token */
1617 rule_tmp.rule.rule.token_count = 1 + rule_tmp.token_cur;
1618 if (add_token(rules, &rule_tmp.rule) != 0)
1619 goto invalid;
1620
1621 /* add tokens to list, sorted by type */
1622 if (sort_token(rules, &rule_tmp) != 0)
1623 goto invalid;
1624
1625 return 0;
1626 invalid:
1627 err(rules->udev, "invalid rule '%s:%u'\n", filename, lineno);
1628 return -1;
1629 }
1630
1631 static int parse_file(struct udev_rules *rules, const char *filename, unsigned short filename_off)
1632 {
1633 FILE *f;
1634 unsigned int first_token;
1635 char line[UTIL_LINE_SIZE];
1636 int line_nr = 0;
1637 unsigned int i;
1638
1639 info(rules->udev, "reading '%s' as rules file\n", filename);
1640
1641 f = fopen(filename, "r");
1642 if (f == NULL)
1643 return -1;
1644
1645 first_token = rules->token_cur;
1646
1647 while (fgets(line, sizeof(line), f) != NULL) {
1648 char *key;
1649 size_t len;
1650
1651 /* skip whitespace */
1652 line_nr++;
1653 key = line;
1654 while (isspace(key[0]))
1655 key++;
1656
1657 /* comment */
1658 if (key[0] == '#')
1659 continue;
1660
1661 len = strlen(line);
1662 if (len < 3)
1663 continue;
1664
1665 /* continue reading if backslash+newline is found */
1666 while (line[len-2] == '\\') {
1667 if (fgets(&line[len-2], (sizeof(line)-len)+2, f) == NULL)
1668 break;
1669 if (strlen(&line[len-2]) < 2)
1670 break;
1671 line_nr++;
1672 len = strlen(line);
1673 }
1674
1675 if (len+1 >= sizeof(line)) {
1676 err(rules->udev, "line too long '%s':%u, ignored\n", filename, line_nr);
1677 continue;
1678 }
1679 add_rule(rules, key, filename, filename_off, line_nr);
1680 }
1681 fclose(f);
1682
1683 /* link GOTOs to LABEL rules in this file to be able to fast-forward */
1684 for (i = first_token+1; i < rules->token_cur; i++) {
1685 if (rules->tokens[i].type == TK_A_GOTO) {
1686 char *label = &rules->buf[rules->tokens[i].key.value_off];
1687 unsigned int j;
1688
1689 for (j = i+1; j < rules->token_cur; j++) {
1690 if (rules->tokens[j].type != TK_RULE)
1691 continue;
1692 if (rules->tokens[j].rule.label_off == 0)
1693 continue;
1694 if (strcmp(label, &rules->buf[rules->tokens[j].rule.label_off]) != 0)
1695 continue;
1696 rules->tokens[i].key.rule_goto = j;
1697 break;
1698 }
1699 if (rules->tokens[i].key.rule_goto == 0)
1700 err(rules->udev, "GOTO '%s' has no matching label in: '%s'\n", label, filename);
1701 }
1702 }
1703 return 0;
1704 }
1705
1706 static int add_matching_files(struct udev *udev, struct udev_list *file_list, const char *dirname, const char *suffix)
1707 {
1708 DIR *dir;
1709 struct dirent *dent;
1710 char filename[UTIL_PATH_SIZE];
1711
1712 dbg(udev, "open directory '%s'\n", dirname);
1713 dir = opendir(dirname);
1714 if (dir == NULL) {
1715 info(udev, "unable to open '%s': %m\n", dirname);
1716 return -1;
1717 }
1718
1719 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
1720 if (dent->d_name[0] == '.')
1721 continue;
1722
1723 /* look for file matching with specified suffix */
1724 if (suffix != NULL) {
1725 const char *ext;
1726
1727 ext = strrchr(dent->d_name, '.');
1728 if (ext == NULL)
1729 continue;
1730 if (strcmp(ext, suffix) != 0)
1731 continue;
1732 }
1733 util_strscpyl(filename, sizeof(filename), dirname, "/", dent->d_name, NULL);
1734 dbg(udev, "put file '%s' into list\n", filename);
1735 /*
1736 * the basename is the key, the filename the value
1737 * identical basenames from different directories override each other
1738 * entries are sorted after basename
1739 */
1740 udev_list_entry_add(file_list, dent->d_name, filename);
1741 }
1742
1743 closedir(dir);
1744 return 0;
1745 }
1746
1747 struct udev_rules *udev_rules_new(struct udev *udev, int resolve_names)
1748 {
1749 struct udev_rules *rules;
1750 struct udev_list file_list;
1751 struct udev_list_entry *file_loop;
1752 struct token end_token;
1753 char **s;
1754
1755 rules = calloc(1, sizeof(struct udev_rules));
1756 if (rules == NULL)
1757 return NULL;
1758 rules->udev = udev;
1759 rules->resolve_names = resolve_names;
1760 udev_list_init(udev, &file_list, true);
1761
1762 /* init token array and string buffer */
1763 rules->tokens = malloc(PREALLOC_TOKEN * sizeof(struct token));
1764 if (rules->tokens == NULL) {
1765 free(rules);
1766 return NULL;
1767 }
1768 rules->token_max = PREALLOC_TOKEN;
1769
1770 rules->buf = malloc(PREALLOC_STRBUF);
1771 if (rules->buf == NULL) {
1772 free(rules->tokens);
1773 free(rules);
1774 return NULL;
1775 }
1776 rules->buf_max = PREALLOC_STRBUF;
1777 /* offset 0 is always '\0' */
1778 rules->buf[0] = '\0';
1779 rules->buf_cur = 1;
1780 dbg(udev, "prealloc %zu bytes tokens (%u * %zu bytes), %zu bytes buffer\n",
1781 rules->token_max * sizeof(struct token), rules->token_max, sizeof(struct token), rules->buf_max);
1782
1783 rules->trie_nodes = malloc(PREALLOC_TRIE * sizeof(struct trie_node));
1784 if (rules->trie_nodes == NULL) {
1785 free(rules->buf);
1786 free(rules->tokens);
1787 free(rules);
1788 return NULL;
1789 }
1790 rules->trie_nodes_max = PREALLOC_TRIE;
1791 /* offset 0 is the trie root, with an empty string */
1792 memset(rules->trie_nodes, 0x00, sizeof(struct trie_node));
1793 rules->trie_nodes_cur = 1;
1794
1795 for (udev_get_rules_path(udev, &s, NULL); *s != NULL; s++)
1796 add_matching_files(udev, &file_list, *s, ".rules");
1797
1798 /* add all filenames to the string buffer */
1799 udev_list_entry_foreach(file_loop, udev_list_get_entry(&file_list)) {
1800 const char *filename = udev_list_entry_get_value(file_loop);
1801 unsigned int filename_off;
1802
1803 filename_off = add_string(rules, filename);
1804 /* the offset in the rule is limited to unsigned short */
1805 if (filename_off < USHRT_MAX)
1806 udev_list_entry_set_num(file_loop, filename_off);
1807 }
1808
1809 /* parse all rules files */
1810 udev_list_entry_foreach(file_loop, udev_list_get_entry(&file_list)) {
1811 const char *filename = udev_list_entry_get_value(file_loop);
1812 unsigned int filename_off = udev_list_entry_get_num(file_loop);
1813 struct stat st;
1814
1815 if (stat(filename, &st) != 0) {
1816 err(udev, "can not find '%s': %m\n", filename);
1817 continue;
1818 }
1819 if (S_ISREG(st.st_mode) && st.st_size <= 0) {
1820 info(udev, "ignore empty '%s'\n", filename);
1821 continue;
1822 }
1823 if (S_ISCHR(st.st_mode)) {
1824 info(udev, "ignore masked '%s'\n", filename);
1825 continue;
1826 }
1827 parse_file(rules, filename, filename_off);
1828 }
1829 udev_list_cleanup(&file_list);
1830
1831 memset(&end_token, 0x00, sizeof(struct token));
1832 end_token.type = TK_END;
1833 add_token(rules, &end_token);
1834
1835 /* shrink allocated token and string buffer */
1836 if (rules->token_cur < rules->token_max) {
1837 struct token *tokens;
1838
1839 tokens = realloc(rules->tokens, rules->token_cur * sizeof(struct token));
1840 if (tokens != NULL || rules->token_cur == 0) {
1841 rules->tokens = tokens;
1842 rules->token_max = rules->token_cur;
1843 }
1844 }
1845 if (rules->buf_cur < rules->buf_max) {
1846 char *buf;
1847
1848 buf = realloc(rules->buf, rules->buf_cur);
1849 if (buf != NULL || rules->buf_cur == 0) {
1850 rules->buf = buf;
1851 rules->buf_max = rules->buf_cur;
1852 }
1853 }
1854 info(udev, "rules use %zu bytes tokens (%u * %zu bytes), %zu bytes buffer\n",
1855 rules->token_max * sizeof(struct token), rules->token_max, sizeof(struct token), rules->buf_max);
1856 info(udev, "temporary index used %zu bytes (%u * %zu bytes)\n",
1857 rules->trie_nodes_cur * sizeof(struct trie_node),
1858 rules->trie_nodes_cur, sizeof(struct trie_node));
1859
1860 /* cleanup trie */
1861 free(rules->trie_nodes);
1862 rules->trie_nodes = NULL;
1863 rules->trie_nodes_cur = 0;
1864 rules->trie_nodes_max = 0;
1865
1866 /* cleanup uid/gid cache */
1867 free(rules->uids);
1868 rules->uids = NULL;
1869 rules->uids_cur = 0;
1870 rules->uids_max = 0;
1871 free(rules->gids);
1872 rules->gids = NULL;
1873 rules->gids_cur = 0;
1874 rules->gids_max = 0;
1875
1876 dump_rules(rules);
1877 return rules;
1878 }
1879
1880 struct udev_rules *udev_rules_unref(struct udev_rules *rules)
1881 {
1882 if (rules == NULL)
1883 return NULL;
1884 free(rules->tokens);
1885 free(rules->buf);
1886 free(rules->trie_nodes);
1887 free(rules->uids);
1888 free(rules->gids);
1889 free(rules);
1890 return NULL;
1891 }
1892
1893 static int match_key(struct udev_rules *rules, struct token *token, const char *val)
1894 {
1895 char *key_value = &rules->buf[token->key.value_off];
1896 char *pos;
1897 bool match = false;
1898
1899 if (val == NULL)
1900 val = "";
1901
1902 switch (token->key.glob) {
1903 case GL_PLAIN:
1904 match = (strcmp(key_value, val) == 0);
1905 break;
1906 case GL_GLOB:
1907 match = (fnmatch(key_value, val, 0) == 0);
1908 break;
1909 case GL_SPLIT:
1910 {
1911 const char *split;
1912 size_t len;
1913
1914 split = &rules->buf[token->key.value_off];
1915 len = strlen(val);
1916 for (;;) {
1917 const char *next;
1918
1919 next = strchr(split, '|');
1920 if (next != NULL) {
1921 size_t matchlen = (size_t)(next - split);
1922
1923 match = (matchlen == len && strncmp(split, val, matchlen) == 0);
1924 if (match)
1925 break;
1926 } else {
1927 match = (strcmp(split, val) == 0);
1928 break;
1929 }
1930 split = &next[1];
1931 }
1932 break;
1933 }
1934 case GL_SPLIT_GLOB:
1935 {
1936 char value[UTIL_PATH_SIZE];
1937
1938 util_strscpy(value, sizeof(value), &rules->buf[token->key.value_off]);
1939 key_value = value;
1940 while (key_value != NULL) {
1941 pos = strchr(key_value, '|');
1942 if (pos != NULL) {
1943 pos[0] = '\0';
1944 pos = &pos[1];
1945 }
1946 dbg(rules->udev, "match %s '%s' <-> '%s'\n", token_str(token->type), key_value, val);
1947 match = (fnmatch(key_value, val, 0) == 0);
1948 if (match)
1949 break;
1950 key_value = pos;
1951 }
1952 break;
1953 }
1954 case GL_SOMETHING:
1955 match = (val[0] != '\0');
1956 break;
1957 case GL_UNSET:
1958 return -1;
1959 }
1960
1961 if (match && (token->key.op == OP_MATCH)) {
1962 dbg(rules->udev, "%s is true (matching value)\n", token_str(token->type));
1963 return 0;
1964 }
1965 if (!match && (token->key.op == OP_NOMATCH)) {
1966 dbg(rules->udev, "%s is true (non-matching value)\n", token_str(token->type));
1967 return 0;
1968 }
1969 dbg(rules->udev, "%s is not true\n", token_str(token->type));
1970 return -1;
1971 }
1972
1973 static int match_attr(struct udev_rules *rules, struct udev_device *dev, struct udev_event *event, struct token *cur)
1974 {
1975 const char *name;
1976 char nbuf[UTIL_NAME_SIZE];
1977 const char *value;
1978 char vbuf[UTIL_NAME_SIZE];
1979 size_t len;
1980
1981 name = &rules->buf[cur->key.attr_off];
1982 switch (cur->key.attrsubst) {
1983 case SB_FORMAT:
1984 udev_event_apply_format(event, name, nbuf, sizeof(nbuf));
1985 name = nbuf;
1986 /* fall through */
1987 case SB_NONE:
1988 value = udev_device_get_sysattr_value(dev, name);
1989 if (value == NULL)
1990 return -1;
1991 break;
1992 case SB_SUBSYS:
1993 if (util_resolve_subsys_kernel(event->udev, name, vbuf, sizeof(vbuf), 1) != 0)
1994 return -1;
1995 value = vbuf;
1996 break;
1997 default:
1998 return -1;
1999 }
2000
2001 /* remove trailing whitespace, if not asked to match for it */
2002 len = strlen(value);
2003 if (len > 0 && isspace(value[len-1])) {
2004 const char *key_value;
2005 size_t klen;
2006
2007 key_value = &rules->buf[cur->key.value_off];
2008 klen = strlen(key_value);
2009 if (klen > 0 && !isspace(key_value[klen-1])) {
2010 if (value != vbuf) {
2011 util_strscpy(vbuf, sizeof(vbuf), value);
2012 value = vbuf;
2013 }
2014 while (len > 0 && isspace(vbuf[--len]))
2015 vbuf[len] = '\0';
2016 dbg(rules->udev, "removed trailing whitespace from '%s'\n", value);
2017 }
2018 }
2019
2020 return match_key(rules, cur, value);
2021 }
2022
2023 enum escape_type {
2024 ESCAPE_UNSET,
2025 ESCAPE_NONE,
2026 ESCAPE_REPLACE,
2027 };
2028
2029 int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event, const sigset_t *sigmask)
2030 {
2031 struct token *cur;
2032 struct token *rule;
2033 enum escape_type esc = ESCAPE_UNSET;
2034 bool can_set_name;
2035
2036 if (rules->tokens == NULL)
2037 return -1;
2038
2039 can_set_name = ((strcmp(udev_device_get_action(event->dev), "remove") != 0) &&
2040 (major(udev_device_get_devnum(event->dev)) > 0 ||
2041 udev_device_get_ifindex(event->dev) > 0));
2042
2043 /* loop through token list, match, run actions or forward to next rule */
2044 cur = &rules->tokens[0];
2045 rule = cur;
2046 for (;;) {
2047 dump_token(rules, cur);
2048 switch (cur->type) {
2049 case TK_RULE:
2050 /* current rule */
2051 rule = cur;
2052 /* possibly skip rules which want to set NAME, SYMLINK, OWNER, GROUP, MODE */
2053 if (!can_set_name && rule->rule.can_set_name)
2054 goto nomatch;
2055 esc = ESCAPE_UNSET;
2056 break;
2057 case TK_M_ACTION:
2058 if (match_key(rules, cur, udev_device_get_action(event->dev)) != 0)
2059 goto nomatch;
2060 break;
2061 case TK_M_DEVPATH:
2062 if (match_key(rules, cur, udev_device_get_devpath(event->dev)) != 0)
2063 goto nomatch;
2064 break;
2065 case TK_M_KERNEL:
2066 if (match_key(rules, cur, udev_device_get_sysname(event->dev)) != 0)
2067 goto nomatch;
2068 break;
2069 case TK_M_DEVLINK: {
2070 size_t devlen = strlen(udev_get_dev_path(event->udev))+1;
2071 struct udev_list_entry *list_entry;
2072 bool match = false;
2073
2074 udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(event->dev)) {
2075 const char *devlink;
2076
2077 devlink = &udev_list_entry_get_name(list_entry)[devlen];
2078 if (match_key(rules, cur, devlink) == 0) {
2079 match = true;
2080 break;
2081 }
2082 }
2083 if (!match)
2084 goto nomatch;
2085 break;
2086 }
2087 case TK_M_NAME:
2088 if (match_key(rules, cur, event->name) != 0)
2089 goto nomatch;
2090 break;
2091 case TK_M_ENV: {
2092 const char *key_name = &rules->buf[cur->key.attr_off];
2093 const char *value;
2094
2095 value = udev_device_get_property_value(event->dev, key_name);
2096 if (value == NULL) {
2097 dbg(event->udev, "ENV{%s} is not set, treat as empty\n", key_name);
2098 value = "";
2099 }
2100 if (match_key(rules, cur, value))
2101 goto nomatch;
2102 break;
2103 }
2104 case TK_M_TAG: {
2105 struct udev_list_entry *list_entry;
2106 bool match = false;
2107
2108 udev_list_entry_foreach(list_entry, udev_device_get_tags_list_entry(event->dev)) {
2109 if (strcmp(&rules->buf[cur->key.value_off], udev_list_entry_get_name(list_entry)) == 0) {
2110 match = true;
2111 break;
2112 }
2113 }
2114 if (!match && (cur->key.op != OP_NOMATCH))
2115 goto nomatch;
2116 break;
2117 }
2118 case TK_M_SUBSYSTEM:
2119 if (match_key(rules, cur, udev_device_get_subsystem(event->dev)) != 0)
2120 goto nomatch;
2121 break;
2122 case TK_M_DRIVER:
2123 if (match_key(rules, cur, udev_device_get_driver(event->dev)) != 0)
2124 goto nomatch;
2125 break;
2126 case TK_M_WAITFOR: {
2127 char filename[UTIL_PATH_SIZE];
2128 int found;
2129
2130 udev_event_apply_format(event, &rules->buf[cur->key.value_off], filename, sizeof(filename));
2131 found = (wait_for_file(event->dev, filename, 10) == 0);
2132 if (!found && (cur->key.op != OP_NOMATCH))
2133 goto nomatch;
2134 break;
2135 }
2136 case TK_M_ATTR:
2137 if (match_attr(rules, event->dev, event, cur) != 0)
2138 goto nomatch;
2139 break;
2140 case TK_M_KERNELS:
2141 case TK_M_SUBSYSTEMS:
2142 case TK_M_DRIVERS:
2143 case TK_M_ATTRS:
2144 case TK_M_TAGS: {
2145 struct token *next;
2146
2147 /* get whole sequence of parent matches */
2148 next = cur;
2149 while (next->type > TK_M_PARENTS_MIN && next->type < TK_M_PARENTS_MAX)
2150 next++;
2151
2152 /* loop over parents */
2153 event->dev_parent = event->dev;
2154 for (;;) {
2155 struct token *key;
2156
2157 dbg(event->udev, "parent: '%s'\n", udev_device_get_syspath(event->dev_parent));
2158 /* loop over sequence of parent match keys */
2159 for (key = cur; key < next; key++ ) {
2160 dump_token(rules, key);
2161 switch(key->type) {
2162 case TK_M_KERNELS:
2163 if (match_key(rules, key, udev_device_get_sysname(event->dev_parent)) != 0)
2164 goto try_parent;
2165 break;
2166 case TK_M_SUBSYSTEMS:
2167 if (match_key(rules, key, udev_device_get_subsystem(event->dev_parent)) != 0)
2168 goto try_parent;
2169 break;
2170 case TK_M_DRIVERS:
2171 if (match_key(rules, key, udev_device_get_driver(event->dev_parent)) != 0)
2172 goto try_parent;
2173 break;
2174 case TK_M_ATTRS:
2175 if (match_attr(rules, event->dev_parent, event, key) != 0)
2176 goto try_parent;
2177 break;
2178 case TK_M_TAGS: {
2179 bool match = udev_device_has_tag(event->dev_parent, &rules->buf[cur->key.value_off]);
2180
2181 if (match && key->key.op == OP_NOMATCH)
2182 goto try_parent;
2183 if (!match && key->key.op == OP_MATCH)
2184 goto try_parent;
2185 break;
2186 }
2187 default:
2188 goto nomatch;
2189 }
2190 dbg(event->udev, "parent key matched\n");
2191 }
2192 dbg(event->udev, "all parent keys matched\n");
2193 break;
2194
2195 try_parent:
2196 event->dev_parent = udev_device_get_parent(event->dev_parent);
2197 if (event->dev_parent == NULL)
2198 goto nomatch;
2199 }
2200 /* move behind our sequence of parent match keys */
2201 cur = next;
2202 continue;
2203 }
2204 case TK_M_TEST: {
2205 char filename[UTIL_PATH_SIZE];
2206 struct stat statbuf;
2207 int match;
2208
2209 udev_event_apply_format(event, &rules->buf[cur->key.value_off], filename, sizeof(filename));
2210 if (util_resolve_subsys_kernel(event->udev, filename, filename, sizeof(filename), 0) != 0) {
2211 if (filename[0] != '/') {
2212 char tmp[UTIL_PATH_SIZE];
2213
2214 util_strscpy(tmp, sizeof(tmp), filename);
2215 util_strscpyl(filename, sizeof(filename),
2216 udev_device_get_syspath(event->dev), "/", tmp, NULL);
2217 }
2218 }
2219 attr_subst_subdir(filename, sizeof(filename));
2220
2221 match = (stat(filename, &statbuf) == 0);
2222 dbg(event->udev, "'%s' %s", filename, match ? "exists\n" : "does not exist\n");
2223 if (match && cur->key.mode > 0) {
2224 match = ((statbuf.st_mode & cur->key.mode) > 0);
2225 dbg(event->udev, "'%s' has mode=%#o and %s %#o\n", filename, statbuf.st_mode,
2226 match ? "matches" : "does not match", cur->key.mode);
2227 }
2228 if (match && cur->key.op == OP_NOMATCH)
2229 goto nomatch;
2230 if (!match && cur->key.op == OP_MATCH)
2231 goto nomatch;
2232 break;
2233 }
2234 case TK_M_EVENT_TIMEOUT:
2235 info(event->udev, "OPTIONS event_timeout=%u\n", cur->key.event_timeout);
2236 event->timeout_usec = cur->key.event_timeout * 1000 * 1000;
2237 break;
2238 case TK_M_PROGRAM: {
2239 char program[UTIL_PATH_SIZE];
2240 char **envp;
2241 char result[UTIL_PATH_SIZE];
2242
2243 free(event->program_result);
2244 event->program_result = NULL;
2245 udev_event_apply_format(event, &rules->buf[cur->key.value_off], program, sizeof(program));
2246 envp = udev_device_get_properties_envp(event->dev);
2247 info(event->udev, "PROGRAM '%s' %s:%u\n",
2248 program,
2249 &rules->buf[rule->rule.filename_off],
2250 rule->rule.filename_line);
2251
2252 if (udev_event_spawn(event, program, envp, sigmask, result, sizeof(result)) < 0) {
2253 if (cur->key.op != OP_NOMATCH)
2254 goto nomatch;
2255 } else {
2256 int count;
2257
2258 util_remove_trailing_chars(result, '\n');
2259 if (esc == ESCAPE_UNSET || esc == ESCAPE_REPLACE) {
2260 count = util_replace_chars(result, UDEV_ALLOWED_CHARS_INPUT);
2261 if (count > 0)
2262 info(event->udev, "%i character(s) replaced\n" , count);
2263 }
2264 event->program_result = strdup(result);
2265 dbg(event->udev, "storing result '%s'\n", event->program_result);
2266 if (cur->key.op == OP_NOMATCH)
2267 goto nomatch;
2268 }
2269 break;
2270 }
2271 case TK_M_IMPORT_FILE: {
2272 char import[UTIL_PATH_SIZE];
2273
2274 udev_event_apply_format(event, &rules->buf[cur->key.value_off], import, sizeof(import));
2275 if (import_file_into_properties(event->dev, import) != 0)
2276 if (cur->key.op != OP_NOMATCH)
2277 goto nomatch;
2278 break;
2279 }
2280 case TK_M_IMPORT_PROG: {
2281 char import[UTIL_PATH_SIZE];
2282
2283 udev_event_apply_format(event, &rules->buf[cur->key.value_off], import, sizeof(import));
2284 info(event->udev, "IMPORT '%s' %s:%u\n",
2285 import,
2286 &rules->buf[rule->rule.filename_off],
2287 rule->rule.filename_line);
2288
2289 if (import_program_into_properties(event, import, sigmask) != 0)
2290 if (cur->key.op != OP_NOMATCH)
2291 goto nomatch;
2292 break;
2293 }
2294 case TK_M_IMPORT_BUILTIN: {
2295 char command[UTIL_PATH_SIZE];
2296
2297 if (udev_builtin_run_once(cur->key.builtin_cmd)) {
2298 /* check if we ran already */
2299 if (event->builtin_run & (1 << cur->key.builtin_cmd)) {
2300 info(event->udev, "IMPORT builtin skip '%s' %s:%u\n",
2301 udev_builtin_name(cur->key.builtin_cmd),
2302 &rules->buf[rule->rule.filename_off],
2303 rule->rule.filename_line);
2304 /* return the result from earlier run */
2305 if (event->builtin_ret & (1 << cur->key.builtin_cmd))
2306 if (cur->key.op != OP_NOMATCH)
2307 goto nomatch;
2308 break;
2309 }
2310 /* mark as ran */
2311 event->builtin_run |= (1 << cur->key.builtin_cmd);
2312 }
2313
2314 udev_event_apply_format(event, &rules->buf[cur->key.value_off], command, sizeof(command));
2315 info(event->udev, "IMPORT builtin '%s' %s:%u\n",
2316 udev_builtin_name(cur->key.builtin_cmd),
2317 &rules->buf[rule->rule.filename_off],
2318 rule->rule.filename_line);
2319
2320 if (udev_builtin_run(event->dev, cur->key.builtin_cmd, command, false) != 0) {
2321 /* remember failure */
2322 info(rules->udev, "IMPORT builtin '%s' returned non-zero\n",
2323 udev_builtin_name(cur->key.builtin_cmd));
2324 event->builtin_ret |= (1 << cur->key.builtin_cmd);
2325 if (cur->key.op != OP_NOMATCH)
2326 goto nomatch;
2327 }
2328 break;
2329 }
2330 case TK_M_IMPORT_DB: {
2331 const char *key = &rules->buf[cur->key.value_off];
2332 const char *value;
2333
2334 value = udev_device_get_property_value(event->dev_db, key);
2335 if (value != NULL) {
2336 struct udev_list_entry *entry;
2337
2338 entry = udev_device_add_property(event->dev, key, value);
2339 udev_list_entry_set_num(entry, true);
2340 } else {
2341 if (cur->key.op != OP_NOMATCH)
2342 goto nomatch;
2343 }
2344 break;
2345 }
2346 case TK_M_IMPORT_CMDLINE: {
2347 FILE *f;
2348 bool imported = false;
2349
2350 f = fopen("/proc/cmdline", "r");
2351 if (f != NULL) {
2352 char cmdline[4096];
2353
2354 if (fgets(cmdline, sizeof(cmdline), f) != NULL) {
2355 const char *key = &rules->buf[cur->key.value_off];
2356 char *pos;
2357
2358 pos = strstr(cmdline, key);
2359 if (pos != NULL) {
2360 struct udev_list_entry *entry;
2361
2362 pos += strlen(key);
2363 if (pos[0] == '\0' || isspace(pos[0])) {
2364 /* we import simple flags as 'FLAG=1' */
2365 entry = udev_device_add_property(event->dev, key, "1");
2366 udev_list_entry_set_num(entry, true);
2367 imported = true;
2368 } else if (pos[0] == '=') {
2369 const char *value;
2370
2371 pos++;
2372 value = pos;
2373 while (pos[0] != '\0' && !isspace(pos[0]))
2374 pos++;
2375 pos[0] = '\0';
2376 entry = udev_device_add_property(event->dev, key, value);
2377 udev_list_entry_set_num(entry, true);
2378 imported = true;
2379 }
2380 }
2381 }
2382 fclose(f);
2383 }
2384 if (!imported && cur->key.op != OP_NOMATCH)
2385 goto nomatch;
2386 break;
2387 }
2388 case TK_M_IMPORT_PARENT: {
2389 char import[UTIL_PATH_SIZE];
2390
2391 udev_event_apply_format(event, &rules->buf[cur->key.value_off], import, sizeof(import));
2392 if (import_parent_into_properties(event->dev, import) != 0)
2393 if (cur->key.op != OP_NOMATCH)
2394 goto nomatch;
2395 break;
2396 }
2397 case TK_M_RESULT:
2398 if (match_key(rules, cur, event->program_result) != 0)
2399 goto nomatch;
2400 break;
2401 case TK_A_STRING_ESCAPE_NONE:
2402 esc = ESCAPE_NONE;
2403 break;
2404 case TK_A_STRING_ESCAPE_REPLACE:
2405 esc = ESCAPE_REPLACE;
2406 break;
2407 case TK_A_DB_PERSIST:
2408 udev_device_set_db_persist(event->dev);
2409 break;
2410 case TK_A_INOTIFY_WATCH:
2411 if (event->inotify_watch_final)
2412 break;
2413 if (cur->key.op == OP_ASSIGN_FINAL)
2414 event->inotify_watch_final = true;
2415 event->inotify_watch = cur->key.watch;
2416 break;
2417 case TK_A_DEVLINK_PRIO:
2418 udev_device_set_devlink_priority(event->dev, cur->key.devlink_prio);
2419 break;
2420 case TK_A_OWNER: {
2421 char owner[UTIL_NAME_SIZE];
2422
2423 if (event->owner_final)
2424 break;
2425 if (cur->key.op == OP_ASSIGN_FINAL)
2426 event->owner_final = true;
2427 udev_event_apply_format(event, &rules->buf[cur->key.value_off], owner, sizeof(owner));
2428 event->uid = util_lookup_user(event->udev, owner);
2429 info(event->udev, "OWNER %u %s:%u\n",
2430 event->uid,
2431 &rules->buf[rule->rule.filename_off],
2432 rule->rule.filename_line);
2433 break;
2434 }
2435 case TK_A_GROUP: {
2436 char group[UTIL_NAME_SIZE];
2437
2438 if (event->group_final)
2439 break;
2440 if (cur->key.op == OP_ASSIGN_FINAL)
2441 event->group_final = true;
2442 udev_event_apply_format(event, &rules->buf[cur->key.value_off], group, sizeof(group));
2443 event->gid = util_lookup_group(event->udev, group);
2444 info(event->udev, "GROUP %u %s:%u\n",
2445 event->gid,
2446 &rules->buf[rule->rule.filename_off],
2447 rule->rule.filename_line);
2448 break;
2449 }
2450 case TK_A_MODE: {
2451 char mode_str[UTIL_NAME_SIZE];
2452 mode_t mode;
2453 char *endptr;
2454
2455 if (event->mode_final)
2456 break;
2457 udev_event_apply_format(event, &rules->buf[cur->key.value_off], mode_str, sizeof(mode_str));
2458 mode = strtol(mode_str, &endptr, 8);
2459 if (endptr[0] != '\0') {
2460 err(event->udev, "ignoring invalid mode '%s'\n", mode_str);
2461 break;
2462 }
2463 if (cur->key.op == OP_ASSIGN_FINAL)
2464 event->mode_final = true;
2465 event->mode_set = true;
2466 event->mode = mode;
2467 info(event->udev, "MODE %#o %s:%u\n",
2468 event->mode,
2469 &rules->buf[rule->rule.filename_off],
2470 rule->rule.filename_line);
2471 break;
2472 }
2473 case TK_A_OWNER_ID:
2474 if (event->owner_final)
2475 break;
2476 if (cur->key.op == OP_ASSIGN_FINAL)
2477 event->owner_final = true;
2478 event->uid = cur->key.uid;
2479 info(event->udev, "OWNER %u %s:%u\n",
2480 event->uid,
2481 &rules->buf[rule->rule.filename_off],
2482 rule->rule.filename_line);
2483 break;
2484 case TK_A_GROUP_ID:
2485 if (event->group_final)
2486 break;
2487 if (cur->key.op == OP_ASSIGN_FINAL)
2488 event->group_final = true;
2489 event->gid = cur->key.gid;
2490 info(event->udev, "GROUP %u %s:%u\n",
2491 event->gid,
2492 &rules->buf[rule->rule.filename_off],
2493 rule->rule.filename_line);
2494 break;
2495 case TK_A_MODE_ID:
2496 if (event->mode_final)
2497 break;
2498 if (cur->key.op == OP_ASSIGN_FINAL)
2499 event->mode_final = true;
2500 event->mode_set = true;
2501 event->mode = cur->key.mode;
2502 info(event->udev, "MODE %#o %s:%u\n",
2503 event->mode,
2504 &rules->buf[rule->rule.filename_off],
2505 rule->rule.filename_line);
2506 break;
2507 case TK_A_ENV: {
2508 const char *name = &rules->buf[cur->key.attr_off];
2509 char *value = &rules->buf[cur->key.value_off];
2510
2511 if (value[0] != '\0') {
2512 char temp_value[UTIL_NAME_SIZE];
2513 struct udev_list_entry *entry;
2514
2515 udev_event_apply_format(event, value, temp_value, sizeof(temp_value));
2516 entry = udev_device_add_property(event->dev, name, temp_value);
2517 /* store in db, skip private keys */
2518 if (name[0] != '.')
2519 udev_list_entry_set_num(entry, true);
2520 } else {
2521 udev_device_add_property(event->dev, name, NULL);
2522 }
2523 break;
2524 }
2525 case TK_A_TAG: {
2526 char tag[UTIL_PATH_SIZE];
2527 const char *p;
2528
2529 udev_event_apply_format(event, &rules->buf[cur->key.value_off], tag, sizeof(tag));
2530 if (cur->key.op == OP_ASSIGN || cur->key.op == OP_ASSIGN_FINAL)
2531 udev_device_cleanup_tags_list(event->dev);
2532 for (p = tag; *p != '\0'; p++) {
2533 if ((*p >= 'a' && *p <= 'z') ||
2534 (*p >= 'A' && *p <= 'Z') ||
2535 (*p >= '0' && *p <= '9') ||
2536 *p == '-' || *p == '_')
2537 continue;
2538 err(event->udev, "ignoring invalid tag name '%s'\n", tag);
2539 break;
2540 }
2541 udev_device_add_tag(event->dev, tag);
2542 break;
2543 }
2544 case TK_A_NAME: {
2545 const char *name = &rules->buf[cur->key.value_off];
2546
2547 char name_str[UTIL_PATH_SIZE];
2548 int count;
2549
2550 if (event->name_final)
2551 break;
2552 if (cur->key.op == OP_ASSIGN_FINAL)
2553 event->name_final = true;
2554 udev_event_apply_format(event, name, name_str, sizeof(name_str));
2555 if (esc == ESCAPE_UNSET || esc == ESCAPE_REPLACE) {
2556 count = util_replace_chars(name_str, "/");
2557 if (count > 0)
2558 info(event->udev, "%i character(s) replaced\n", count);
2559 }
2560 if (major(udev_device_get_devnum(event->dev))) {
2561 size_t devlen = strlen(udev_get_dev_path(event->udev))+1;
2562
2563 if (strcmp(name_str, &udev_device_get_devnode(event->dev)[devlen]) != 0) {
2564 err(event->udev, "NAME=\"%s\" ignored, kernel device nodes "
2565 "can not be renamed; please fix it in %s:%u\n", name,
2566 &rules->buf[rule->rule.filename_off], rule->rule.filename_line);
2567 break;
2568 }
2569 }
2570 free(event->name);
2571 event->name = strdup(name_str);
2572 info(event->udev, "NAME '%s' %s:%u\n",
2573 event->name,
2574 &rules->buf[rule->rule.filename_off],
2575 rule->rule.filename_line);
2576 break;
2577 }
2578 case TK_A_DEVLINK: {
2579 char temp[UTIL_PATH_SIZE];
2580 char filename[UTIL_PATH_SIZE];
2581 char *pos, *next;
2582 int count = 0;
2583
2584 if (event->devlink_final)
2585 break;
2586 if (major(udev_device_get_devnum(event->dev)) == 0)
2587 break;
2588 if (cur->key.op == OP_ASSIGN_FINAL)
2589 event->devlink_final = true;
2590 if (cur->key.op == OP_ASSIGN || cur->key.op == OP_ASSIGN_FINAL)
2591 udev_device_cleanup_devlinks_list(event->dev);
2592
2593 /* allow multiple symlinks separated by spaces */
2594 udev_event_apply_format(event, &rules->buf[cur->key.value_off], temp, sizeof(temp));
2595 if (esc == ESCAPE_UNSET)
2596 count = util_replace_chars(temp, "/ ");
2597 else if (esc == ESCAPE_REPLACE)
2598 count = util_replace_chars(temp, "/");
2599 if (count > 0)
2600 info(event->udev, "%i character(s) replaced\n" , count);
2601 dbg(event->udev, "rule applied, added symlink(s) '%s'\n", temp);
2602 pos = temp;
2603 while (isspace(pos[0]))
2604 pos++;
2605 next = strchr(pos, ' ');
2606 while (next != NULL) {
2607 next[0] = '\0';
2608 info(event->udev, "LINK '%s' %s:%u\n", pos,
2609 &rules->buf[rule->rule.filename_off], rule->rule.filename_line);
2610 util_strscpyl(filename, sizeof(filename), udev_get_dev_path(event->udev), "/", pos, NULL);
2611 udev_device_add_devlink(event->dev, filename, cur->key.devlink_unique);
2612 while (isspace(next[1]))
2613 next++;
2614 pos = &next[1];
2615 next = strchr(pos, ' ');
2616 }
2617 if (pos[0] != '\0') {
2618 info(event->udev, "LINK '%s' %s:%u\n", pos,
2619 &rules->buf[rule->rule.filename_off], rule->rule.filename_line);
2620 util_strscpyl(filename, sizeof(filename), udev_get_dev_path(event->udev), "/", pos, NULL);
2621 udev_device_add_devlink(event->dev, filename, cur->key.devlink_unique);
2622 }
2623 break;
2624 }
2625 case TK_A_ATTR: {
2626 const char *key_name = &rules->buf[cur->key.attr_off];
2627 char attr[UTIL_PATH_SIZE];
2628 char value[UTIL_NAME_SIZE];
2629 FILE *f;
2630
2631 if (util_resolve_subsys_kernel(event->udev, key_name, attr, sizeof(attr), 0) != 0)
2632 util_strscpyl(attr, sizeof(attr), udev_device_get_syspath(event->dev), "/", key_name, NULL);
2633 attr_subst_subdir(attr, sizeof(attr));
2634
2635 udev_event_apply_format(event, &rules->buf[cur->key.value_off], value, sizeof(value));
2636 info(event->udev, "ATTR '%s' writing '%s' %s:%u\n", attr, value,
2637 &rules->buf[rule->rule.filename_off],
2638 rule->rule.filename_line);
2639 f = fopen(attr, "w");
2640 if (f != NULL) {
2641 if (fprintf(f, "%s", value) <= 0)
2642 err(event->udev, "error writing ATTR{%s}: %m\n", attr);
2643 fclose(f);
2644 } else {
2645 err(event->udev, "error opening ATTR{%s} for writing: %m\n", attr);
2646 }
2647 break;
2648 }
2649 case TK_A_RUN: {
2650 if (cur->key.op == OP_ASSIGN || cur->key.op == OP_ASSIGN_FINAL)
2651 udev_list_cleanup(&event->run_list);
2652 info(event->udev, "RUN '%s' %s:%u\n",
2653 &rules->buf[cur->key.value_off],
2654 &rules->buf[rule->rule.filename_off],
2655 rule->rule.filename_line);
2656 udev_list_entry_add(&event->run_list, &rules->buf[cur->key.value_off], NULL);
2657 break;
2658 }
2659 case TK_A_GOTO:
2660 if (cur->key.rule_goto == 0)
2661 break;
2662 cur = &rules->tokens[cur->key.rule_goto];
2663 continue;
2664 case TK_END:
2665 return 0;
2666
2667 case TK_M_PARENTS_MIN:
2668 case TK_M_PARENTS_MAX:
2669 case TK_M_MAX:
2670 case TK_UNSET:
2671 err(rules->udev, "wrong type %u\n", cur->type);
2672 goto nomatch;
2673 }
2674
2675 cur++;
2676 continue;
2677 nomatch:
2678 /* fast-forward to next rule */
2679 cur = rule + rule->rule.token_count;
2680 dbg(rules->udev, "forward to rule: %u\n",
2681 (unsigned int) (cur - rules->tokens));
2682 }
2683 }
2684
2685 void udev_rules_apply_static_dev_perms(struct udev_rules *rules)
2686 {
2687 struct token *cur;
2688 struct token *rule;
2689 uid_t uid = 0;
2690 gid_t gid = 0;
2691 mode_t mode = 0;
2692
2693 if (rules->tokens == NULL)
2694 return;
2695
2696 cur = &rules->tokens[0];
2697 rule = cur;
2698 for (;;) {
2699 switch (cur->type) {
2700 case TK_RULE:
2701 /* current rule */
2702 rule = cur;
2703
2704 /* skip rules without a static_node tag */
2705 if (!rule->rule.has_static_node)
2706 goto next;
2707
2708 uid = 0;
2709 gid = 0;
2710 mode = 0;
2711 break;
2712 case TK_A_OWNER_ID:
2713 uid = cur->key.uid;
2714 break;
2715 case TK_A_GROUP_ID:
2716 gid = cur->key.gid;
2717 break;
2718 case TK_A_MODE_ID:
2719 mode = cur->key.mode;
2720 break;
2721 case TK_A_STATIC_NODE: {
2722 char filename[UTIL_PATH_SIZE];
2723 struct stat stats;
2724
2725 /* we assure, that the permissions tokens are sorted before the static token */
2726 if (mode == 0 && uid == 0 && gid == 0)
2727 goto next;
2728 util_strscpyl(filename, sizeof(filename), udev_get_dev_path(rules->udev), "/",
2729 &rules->buf[cur->key.value_off], NULL);
2730 if (stat(filename, &stats) != 0)
2731 goto next;
2732 if (!S_ISBLK(stats.st_mode) && !S_ISCHR(stats.st_mode))
2733 goto next;
2734 if (mode == 0) {
2735 if (gid > 0)
2736 mode = 0660;
2737 else
2738 mode = 0600;
2739 }
2740 if (mode != (stats.st_mode & 01777)) {
2741 chmod(filename, mode);
2742 info(rules->udev, "chmod '%s' %#o\n", filename, mode);
2743 }
2744
2745 if ((uid != 0 && uid != stats.st_uid) || (gid != 0 && gid != stats.st_gid)) {
2746 chown(filename, uid, gid);
2747 info(rules->udev, "chown '%s' %u %u\n", filename, uid, gid);
2748 }
2749
2750 utimensat(AT_FDCWD, filename, NULL, 0);
2751 break;
2752 }
2753 case TK_END:
2754 return;
2755 }
2756
2757 cur++;
2758 continue;
2759 next:
2760 /* fast-forward to next rule */
2761 cur = rule + rule->rule.token_count;
2762 continue;
2763 }
2764 }
File src/udev-watch.c added (mode: 100644) (index 0000000..fba7028)
1 /*
2 * Copyright (C) 2004-2010 Kay Sievers <kay.sievers@vrfy.org>
3 * Copyright (C) 2009 Canonical Ltd.
4 * Copyright (C) 2009 Scott James Remnant <scott@netsplit.com>
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <sys/types.h>
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <stdio.h>
24 #include <dirent.h>
25 #include <stddef.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <sys/inotify.h>
30
31 #include "udev.h"
32
33 static int inotify_fd = -1;
34
35 /* inotify descriptor, will be shared with rules directory;
36 * set to cloexec since we need our children to be able to add
37 * watches for us
38 */
39 int udev_watch_init(struct udev *udev)
40 {
41 inotify_fd = inotify_init1(IN_CLOEXEC);
42 if (inotify_fd < 0)
43 err(udev, "inotify_init failed: %m\n");
44 return inotify_fd;
45 }
46
47 /* move any old watches directory out of the way, and then restore
48 * the watches
49 */
50 void udev_watch_restore(struct udev *udev)
51 {
52 char filename[UTIL_PATH_SIZE], oldname[UTIL_PATH_SIZE];
53
54 if (inotify_fd < 0)
55 return;
56
57 util_strscpyl(oldname, sizeof(oldname), udev_get_run_path(udev), "/watch.old", NULL);
58 util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/watch", NULL);
59 if (rename(filename, oldname) == 0) {
60 DIR *dir;
61 struct dirent *ent;
62
63 dir = opendir(oldname);
64 if (dir == NULL) {
65 err(udev, "unable to open old watches dir '%s', old watches will not be restored: %m", oldname);
66 return;
67 }
68
69 for (ent = readdir(dir); ent != NULL; ent = readdir(dir)) {
70 char device[UTIL_PATH_SIZE];
71 char *s;
72 size_t l;
73 ssize_t len;
74 struct udev_device *dev;
75
76 if (ent->d_name[0] == '.')
77 continue;
78
79 s = device;
80 l = util_strpcpy(&s, sizeof(device), udev_get_sys_path(udev));
81 len = readlinkat(dirfd(dir), ent->d_name, s, l);
82 if (len <= 0 || len == (ssize_t)l)
83 goto unlink;
84 s[len] = '\0';
85
86 dev = udev_device_new_from_device_id(udev, s);
87 if (dev == NULL)
88 goto unlink;
89
90 info(udev, "restoring old watch on '%s'\n", udev_device_get_devnode(dev));
91 udev_watch_begin(udev, dev);
92 udev_device_unref(dev);
93 unlink:
94 unlinkat(dirfd(dir), ent->d_name, 0);
95 }
96
97 closedir(dir);
98 rmdir(oldname);
99
100 } else if (errno != ENOENT) {
101 err(udev, "unable to move watches dir '%s', old watches will not be restored: %m", filename);
102 }
103 }
104
105 void udev_watch_begin(struct udev *udev, struct udev_device *dev)
106 {
107 char filename[UTIL_PATH_SIZE];
108 int wd;
109
110 if (inotify_fd < 0)
111 return;
112
113 info(udev, "adding watch on '%s'\n", udev_device_get_devnode(dev));
114 wd = inotify_add_watch(inotify_fd, udev_device_get_devnode(dev), IN_CLOSE_WRITE);
115 if (wd < 0) {
116 err(udev, "inotify_add_watch(%d, %s, %o) failed: %m\n",
117 inotify_fd, udev_device_get_devnode(dev), IN_CLOSE_WRITE);
118 return;
119 }
120
121 snprintf(filename, sizeof(filename), "%s/watch/%d", udev_get_run_path(udev), wd);
122 util_create_path(udev, filename);
123 unlink(filename);
124 symlink(udev_device_get_id_filename(dev), filename);
125
126 udev_device_set_watch_handle(dev, wd);
127 }
128
129 void udev_watch_end(struct udev *udev, struct udev_device *dev)
130 {
131 int wd;
132 char filename[UTIL_PATH_SIZE];
133
134 if (inotify_fd < 0)
135 return;
136
137 wd = udev_device_get_watch_handle(dev);
138 if (wd < 0)
139 return;
140
141 info(udev, "removing watch on '%s'\n", udev_device_get_devnode(dev));
142 inotify_rm_watch(inotify_fd, wd);
143
144 snprintf(filename, sizeof(filename), "%s/watch/%d", udev_get_run_path(udev), wd);
145 unlink(filename);
146
147 udev_device_set_watch_handle(dev, -1);
148 }
149
150 struct udev_device *udev_watch_lookup(struct udev *udev, int wd)
151 {
152 char filename[UTIL_PATH_SIZE];
153 char majmin[UTIL_PATH_SIZE];
154 char *s;
155 size_t l;
156 ssize_t len;
157
158 if (inotify_fd < 0 || wd < 0)
159 return NULL;
160
161 snprintf(filename, sizeof(filename), "%s/watch/%d", udev_get_run_path(udev), wd);
162 s = majmin;
163 l = util_strpcpy(&s, sizeof(majmin), udev_get_sys_path(udev));
164 len = readlink(filename, s, l);
165 if (len <= 0 || (size_t)len == l)
166 return NULL;
167 s[len] = '\0';
168
169 return udev_device_new_from_device_id(udev, s);
170 }
File src/udev.conf added (mode: 100644) (index 0000000..f39253e)
1 # see udev(7) for details
2
3 #udev_log="info"
File src/udev.h added (mode: 100644) (index 0000000..ecf8cc5)
1 /*
2 * Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com>
3 * Copyright (C) 2003-2010 Kay Sievers <kay.sievers@vrfy.org>
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #ifndef _UDEV_H_
20 #define _UDEV_H_
21
22 #include <sys/types.h>
23 #include <sys/param.h>
24 #include <signal.h>
25
26 #include "libudev.h"
27 #include "libudev-private.h"
28
29 struct udev_event {
30 struct udev *udev;
31 struct udev_device *dev;
32 struct udev_device *dev_parent;
33 struct udev_device *dev_db;
34 char *name;
35 char *program_result;
36 mode_t mode;
37 uid_t uid;
38 gid_t gid;
39 struct udev_list run_list;
40 int exec_delay;
41 unsigned long long birth_usec;
42 unsigned long long timeout_usec;
43 int fd_signal;
44 unsigned int builtin_run;
45 unsigned int builtin_ret;
46 bool sigterm;
47 bool inotify_watch;
48 bool inotify_watch_final;
49 bool group_final;
50 bool owner_final;
51 bool mode_set;
52 bool mode_final;
53 bool name_final;
54 bool devlink_final;
55 bool run_final;
56 };
57
58 struct udev_watch {
59 struct udev_list_node node;
60 int handle;
61 char *name;
62 };
63
64 /* udev-rules.c */
65 struct udev_rules;
66 struct udev_rules *udev_rules_new(struct udev *udev, int resolve_names);
67 struct udev_rules *udev_rules_unref(struct udev_rules *rules);
68 int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event, const sigset_t *sigmask);
69 void udev_rules_apply_static_dev_perms(struct udev_rules *rules);
70
71 /* udev-event.c */
72 struct udev_event *udev_event_new(struct udev_device *dev);
73 void udev_event_unref(struct udev_event *event);
74 size_t udev_event_apply_format(struct udev_event *event, const char *src, char *dest, size_t size);
75 int udev_event_apply_subsys_kernel(struct udev_event *event, const char *string,
76 char *result, size_t maxsize, int read_value);
77 int udev_event_spawn(struct udev_event *event,
78 const char *cmd, char **envp, const sigset_t *sigmask,
79 char *result, size_t ressize);
80 int udev_event_execute_rules(struct udev_event *event, struct udev_rules *rules, const sigset_t *sigset);
81 int udev_event_execute_run(struct udev_event *event, const sigset_t *sigset);
82 int udev_build_argv(struct udev *udev, char *cmd, int *argc, char *argv[]);
83
84 /* udev-watch.c */
85 int udev_watch_init(struct udev *udev);
86 void udev_watch_restore(struct udev *udev);
87 void udev_watch_begin(struct udev *udev, struct udev_device *dev);
88 void udev_watch_end(struct udev *udev, struct udev_device *dev);
89 struct udev_device *udev_watch_lookup(struct udev *udev, int wd);
90
91 /* udev-node.c */
92 void udev_node_add(struct udev_device *dev, mode_t mode, uid_t uid, gid_t gid);
93 void udev_node_remove(struct udev_device *dev);
94 void udev_node_update_old_links(struct udev_device *dev, struct udev_device *dev_old);
95
96 /* udev-ctrl.c */
97 struct udev_ctrl;
98 struct udev_ctrl *udev_ctrl_new(struct udev *udev);
99 struct udev_ctrl *udev_ctrl_new_from_fd(struct udev *udev, int fd);
100 int udev_ctrl_enable_receiving(struct udev_ctrl *uctrl);
101 struct udev_ctrl *udev_ctrl_ref(struct udev_ctrl *uctrl);
102 struct udev_ctrl *udev_ctrl_unref(struct udev_ctrl *uctrl);
103 int udev_ctrl_cleanup(struct udev_ctrl *uctrl);
104 struct udev *udev_ctrl_get_udev(struct udev_ctrl *uctrl);
105 int udev_ctrl_get_fd(struct udev_ctrl *uctrl);
106 int udev_ctrl_send_set_log_level(struct udev_ctrl *uctrl, int priority, int timeout);
107 int udev_ctrl_send_stop_exec_queue(struct udev_ctrl *uctrl, int timeout);
108 int udev_ctrl_send_start_exec_queue(struct udev_ctrl *uctrl, int timeout);
109 int udev_ctrl_send_reload(struct udev_ctrl *uctrl, int timeout);
110 int udev_ctrl_send_ping(struct udev_ctrl *uctrl, int timeout);
111 int udev_ctrl_send_exit(struct udev_ctrl *uctrl, int timeout);
112 int udev_ctrl_send_set_env(struct udev_ctrl *uctrl, const char *key, int timeout);
113 int udev_ctrl_send_set_children_max(struct udev_ctrl *uctrl, int count, int timeout);
114 struct udev_ctrl_connection;
115 struct udev_ctrl_connection *udev_ctrl_get_connection(struct udev_ctrl *uctrl);
116 struct udev_ctrl_connection *udev_ctrl_connection_ref(struct udev_ctrl_connection *conn);
117 struct udev_ctrl_connection *udev_ctrl_connection_unref(struct udev_ctrl_connection *conn);
118 struct udev_ctrl_msg;
119 struct udev_ctrl_msg *udev_ctrl_receive_msg(struct udev_ctrl_connection *conn);
120 struct udev_ctrl_msg *udev_ctrl_msg_ref(struct udev_ctrl_msg *ctrl_msg);
121 struct udev_ctrl_msg *udev_ctrl_msg_unref(struct udev_ctrl_msg *ctrl_msg);
122 int udev_ctrl_get_set_log_level(struct udev_ctrl_msg *ctrl_msg);
123 int udev_ctrl_get_stop_exec_queue(struct udev_ctrl_msg *ctrl_msg);
124 int udev_ctrl_get_start_exec_queue(struct udev_ctrl_msg *ctrl_msg);
125 int udev_ctrl_get_reload(struct udev_ctrl_msg *ctrl_msg);
126 int udev_ctrl_get_ping(struct udev_ctrl_msg *ctrl_msg);
127 int udev_ctrl_get_exit(struct udev_ctrl_msg *ctrl_msg);
128 const char *udev_ctrl_get_set_env(struct udev_ctrl_msg *ctrl_msg);
129 int udev_ctrl_get_set_children_max(struct udev_ctrl_msg *ctrl_msg);
130
131 /* built-in commands */
132 enum udev_builtin_cmd {
133 UDEV_BUILTIN_BLKID,
134 UDEV_BUILTIN_FIRMWARE,
135 UDEV_BUILTIN_INPUT_ID,
136 UDEV_BUILTIN_KMOD,
137 UDEV_BUILTIN_PATH_ID,
138 UDEV_BUILTIN_PCI_DB,
139 UDEV_BUILTIN_USB_DB,
140 UDEV_BUILTIN_USB_ID,
141 UDEV_BUILTIN_MAX
142 };
143 struct udev_builtin {
144 const char *name;
145 int (*cmd)(struct udev_device *dev, int argc, char *argv[], bool test);
146 const char *help;
147 int (*init)(struct udev *udev);
148 void (*exit)(struct udev *udev);
149 bool (*validate)(struct udev *udev);
150 bool run_once;
151 };
152 extern const struct udev_builtin udev_builtin_blkid;
153 extern const struct udev_builtin udev_builtin_firmware;
154 extern const struct udev_builtin udev_builtin_input_id;
155 extern const struct udev_builtin udev_builtin_kmod;
156 extern const struct udev_builtin udev_builtin_path_id;
157 extern const struct udev_builtin udev_builtin_pci_db;
158 extern const struct udev_builtin udev_builtin_usb_db;
159 extern const struct udev_builtin udev_builtin_usb_id;
160 int udev_builtin_init(struct udev *udev);
161 void udev_builtin_exit(struct udev *udev);
162 enum udev_builtin_cmd udev_builtin_lookup(const char *command);
163 const char *udev_builtin_name(enum udev_builtin_cmd cmd);
164 bool udev_builtin_run_once(enum udev_builtin_cmd cmd);
165 int udev_builtin_run(struct udev_device *dev, enum udev_builtin_cmd cmd, const char *command, bool test);
166 void udev_builtin_list(struct udev *udev);
167 bool udev_builtin_validate(struct udev *udev);
168 int udev_builtin_add_property(struct udev_device *dev, bool test, const char *key, const char *val);
169
170 /* udev logging */
171 void udev_main_log(struct udev *udev, int priority,
172 const char *file, int line, const char *fn,
173 const char *format, va_list args);
174
175 /* udevadm commands */
176 struct udevadm_cmd {
177 const char *name;
178 int (*cmd)(struct udev *udev, int argc, char *argv[]);
179 const char *help;
180 int debug;
181 };
182 extern const struct udevadm_cmd udevadm_info;
183 extern const struct udevadm_cmd udevadm_trigger;
184 extern const struct udevadm_cmd udevadm_settle;
185 extern const struct udevadm_cmd udevadm_control;
186 extern const struct udevadm_cmd udevadm_monitor;
187 extern const struct udevadm_cmd udevadm_test;
188 extern const struct udevadm_cmd udevadm_test_builtin;
189 #endif
File src/udev.pc.in added (mode: 100644) (index 0000000..0b04c02)
1 Name: udev
2 Description: udev
3 Version: @VERSION@
4
5 udevdir=@pkglibexecdir@
File src/udev.xml added (mode: 100644) (index 0000000..8eb583a)
1 <?xml version='1.0'?>
2 <?xml-stylesheet type="text/xsl" href="http://docbook.sourceforge.net/release/xsl/current/xhtml/docbook.xsl"?>
3 <!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
4 "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
5
6 <refentry id="udev">
7 <refentryinfo>
8 <title>udev</title>
9 <productname>udev</productname>
10 </refentryinfo>
11
12 <refmeta>
13 <refentrytitle>udev</refentrytitle>
14 <manvolnum>7</manvolnum>
15 </refmeta>
16
17 <refnamediv>
18 <refname>udev</refname>
19 <refpurpose>Linux dynamic device management</refpurpose>
20 </refnamediv>
21
22 <refsect1><title>Description</title>
23 <para>udev supplies the system software with device events, manages permissions
24 of device nodes and may create additional symlinks in the <filename>/dev</filename>
25 directory, or renames network interfaces. The kernel usually just assigns unpredictable
26 device names based on the order of discovery. Meaningful symlinks or network device
27 names provide a way to reliably identify devices based on their properties or
28 current configuration.</para>
29
30 <para>The udev daemon, <citerefentry><refentrytitle>udevd</refentrytitle>
31 <manvolnum>8</manvolnum></citerefentry>, receives device uevents directly from
32 the kernel whenever a device is added or removed from the system, or it changes its
33 state. When udev receives a device event, it matches its configured set of rules
34 against various device attributes to identify the device. Rules that match may
35 provide additional device information to be stored in the udev database or
36 to be used to create meaningful symlink names.</para>
37
38 <para>All device information udev processes is stored in the udev database and
39 sent out to possible event subscribers. Access to all stored data and the event
40 sources is provided by the library libudev.</para>
41 </refsect1>
42
43 <refsect1><title>Configuration</title>
44 <para>udev configuration files are placed in <filename>/etc/udev</filename>
45 and <filename>/usr/lib/udev</filename>. All empty lines or lines beginning with
46 '#' are ignored.</para>
47
48 <refsect2><title>Configuration file</title>
49 <para>udev expects its main configuration file at <filename>/etc/udev/udev.conf</filename>.
50 It consists of a set of variables allowing the user to override default udev values.
51 The following variables can be set:</para>
52 <variablelist>
53 <varlistentry>
54 <term><option>udev_root</option></term>
55 <listitem>
56 <para>Specifies where to place the device nodes in the filesystem.
57 The default value is <filename>/dev</filename>.</para>
58 </listitem>
59 </varlistentry>
60
61 <varlistentry>
62 <term><option>udev_log</option></term>
63 <listitem>
64 <para>The logging priority. Valid values are the numerical syslog priorities
65 or their textual representations: <option>err</option>, <option>info</option>
66 and <option>debug</option>.</para>
67 </listitem>
68 </varlistentry>
69 </variablelist>
70 </refsect2>
71
72 <refsect2><title>Rules files</title>
73 <para>The udev rules are read from the files located in the
74 system rules directory <filename>/usr/lib/udev/rules.d</filename>,
75 the volatile runtime directory <filename>/run/udev/rules.d</filename>
76 and the local administration directory <filename>/etc/udev/rules.d</filename>.
77 All rules files are collectively sorted and processed in lexical order,
78 regardless of the directories in which they live. However, files with
79 identical file names replace each other. Files in <filename>/etc</filename>
80 have the highest priority, files in <filename>/run</filename> take precedence
81 over files with the same name in <filename>/lib</filename>. This can be
82 used to override a system-supplied rules file with a local file if needed;
83 a symlink in <filename>/etc</filename> with the same name as a rules file in
84 <filename>/lib</filename>, pointing to <filename>/dev/null</filename>,
85 disables the rules file entirely.</para>
86
87 <para>Rule files must have the extension <filename>.rules</filename>; other
88 extensions are ignored.</para>
89
90 <para>Every line in the rules file contains at least one key-value pair.
91 There are two kind of keys: match and assignment.
92 If all match keys are matching against its value, the rule gets applied and the
93 assignment keys get the specified value assigned.</para>
94
95 <para>A matching rule may rename a network interface, add symlinks
96 pointing to the device node, or run a specified program as part of
97 the event handling.</para>
98
99 <para>A rule consists of a comma-separated list of one or more key-value pairs.
100 Each key has a distinct operation, depending on the used operator. Valid
101 operators are:</para>
102 <variablelist>
103 <varlistentry>
104 <term><option>==</option></term>
105 <listitem>
106 <para>Compare for equality.</para>
107 </listitem>
108 </varlistentry>
109
110 <varlistentry>
111 <term><option>!=</option></term>
112 <listitem>
113 <para>Compare for inequality.</para>
114 </listitem>
115 </varlistentry>
116
117 <varlistentry>
118 <term><option>=</option></term>
119 <listitem>
120 <para>Assign a value to a key. Keys that represent a list are reset
121 and only this single value is assigned.</para>
122 </listitem>
123 </varlistentry>
124
125 <varlistentry>
126 <term><option>+=</option></term>
127 <listitem>
128 <para>Add the value to a key that holds a list of entries.</para>
129 </listitem>
130 </varlistentry>
131
132 <varlistentry>
133 <term><option>:=</option></term>
134 <listitem>
135 <para>Assign a value to a key finally; disallow any later changes.</para>
136 </listitem>
137 </varlistentry>
138 </variablelist>
139
140 <para>The following key names can be used to match against device properties.
141 Some of the keys also match against properties of the parent devices in sysfs,
142 not only the device that has generated the event. If multiple keys that match
143 a parent device are specified in a single rule, all these keys must match at
144 one and the same parent device.</para>
145 <variablelist>
146 <varlistentry>
147 <term><option>ACTION</option></term>
148 <listitem>
149 <para>Match the name of the event action.</para>
150 </listitem>
151 </varlistentry>
152
153 <varlistentry>
154 <term><option>DEVPATH</option></term>
155 <listitem>
156 <para>Match the devpath of the event device.</para>
157 </listitem>
158 </varlistentry>
159
160 <varlistentry>
161 <term><option>KERNEL</option></term>
162 <listitem>
163 <para>Match the name of the event device.</para>
164 </listitem>
165 </varlistentry>
166
167 <varlistentry>
168 <term><option>NAME</option></term>
169 <listitem>
170 <para>Match the name of a network interface. It can be used once the
171 NAME key has been set in one of the preceding rules.</para>
172 </listitem>
173 </varlistentry>
174
175 <varlistentry>
176 <term><option>SYMLINK</option></term>
177 <listitem>
178 <para>Match the name of a symlink targeting the node. It can
179 be used once a SYMLINK key has been set in one of the preceding
180 rules. There may be multiple symlinks; only one needs to match.
181 </para>
182 </listitem>
183 </varlistentry>
184
185 <varlistentry>
186 <term><option>SUBSYSTEM</option></term>
187 <listitem>
188 <para>Match the subsystem of the event device.</para>
189 </listitem>
190 </varlistentry>
191 <varlistentry>
192 <term><option>DRIVER</option></term>
193 <listitem>
194 <para>Match the driver name of the event device. Only set this key for devices
195 which are bound to a driver at the time the event is generated.</para>
196 </listitem>
197 </varlistentry>
198 <varlistentry>
199 <term><option>ATTR{<replaceable>filename</replaceable>}</option></term>
200 <listitem>
201 <para>Match sysfs attribute values of the event device. Trailing
202 whitespace in the attribute values is ignored unless the specified match
203 value itself contains trailing whitespace.
204 </para>
205 </listitem>
206 </varlistentry>
207
208 <varlistentry>
209 <term><option>KERNELS</option></term>
210 <listitem>
211 <para>Search the devpath upwards for a matching device name.</para>
212 </listitem>
213 </varlistentry>
214
215 <varlistentry>
216 <term><option>SUBSYSTEMS</option></term>
217 <listitem>
218 <para>Search the devpath upwards for a matching device subsystem name.</para>
219 </listitem>
220 </varlistentry>
221
222 <varlistentry>
223 <term><option>DRIVERS</option></term>
224 <listitem>
225 <para>Search the devpath upwards for a matching device driver name.</para>
226 </listitem>
227 </varlistentry>
228
229 <varlistentry>
230 <term><option>ATTRS{<replaceable>filename</replaceable>}</option></term>
231 <listitem>
232 <para>Search the devpath upwards for a device with matching sysfs attribute values.
233 If multiple <option>ATTRS</option> matches are specified, all of them
234 must match on the same device. Trailing whitespace in the attribute values is ignored
235 unless the specified match value itself contains trailing whitespace.</para>
236 </listitem>
237 </varlistentry>
238
239 <varlistentry>
240 <term><option>TAGS</option></term>
241 <listitem>
242 <para>Search the devpath upwards for a device with matching tag.</para>
243 </listitem>
244 </varlistentry>
245
246 <varlistentry>
247 <term><option>ENV{<replaceable>key</replaceable>}</option></term>
248 <listitem>
249 <para>Match against a device property value.</para>
250 </listitem>
251 </varlistentry>
252
253 <varlistentry>
254 <term><option>TAG</option></term>
255 <listitem>
256 <para>Match against a device tag.</para>
257 </listitem>
258 </varlistentry>
259
260 <varlistentry>
261 <term><option>TEST{<replaceable>octal mode mask</replaceable>}</option></term>
262 <listitem>
263 <para>Test the existence of a file. An octal mode mask can be specified
264 if needed.</para>
265 </listitem>
266 </varlistentry>
267
268 <varlistentry>
269 <term><option>PROGRAM</option></term>
270 <listitem>
271 <para>Execute a program to determine whether there
272 is a match; the key is true if the program returns
273 successfully. The device properties are made available to the
274 executed program in the environment. The program's stdout
275 is available in the RESULT key.</para>
276 </listitem>
277 </varlistentry>
278
279 <varlistentry>
280 <term><option>RESULT</option></term>
281 <listitem>
282 <para>Match the returned string of the last PROGRAM call. This key can
283 be used in the same or in any later rule after a PROGRAM call.</para>
284 </listitem>
285 </varlistentry>
286 </variablelist>
287
288 <para>Most of the fields support shell-style pattern matching. The following
289 pattern characters are supported:</para>
290 <variablelist>
291 <varlistentry>
292 <term><option>*</option></term>
293 <listitem>
294 <para>Matches zero or more characters.</para>
295 </listitem>
296 </varlistentry>
297 <varlistentry>
298 <term><option>?</option></term>
299 <listitem>
300 <para>Matches any single character.</para>
301 </listitem>
302 </varlistentry>
303 <varlistentry>
304 <term><option>[]</option></term>
305 <listitem>
306 <para>Matches any single character specified within the brackets. For
307 example, the pattern string 'tty[SR]' would match either 'ttyS' or 'ttyR'.
308 Ranges are also supported via the '-' character.
309 For example, to match on the range of all digits, the pattern [0-9] could
310 be used. If the first character following the '[' is a '!', any characters
311 not enclosed are matched.</para>
312 </listitem>
313 </varlistentry>
314 </variablelist>
315
316 <para>The following keys can get values assigned:</para>
317 <variablelist>
318 <varlistentry>
319 <term><option>NAME</option></term>
320 <listitem>
321 <para>The name to use for a network interface. The name of a device node
322 can not be changed by udev, only additional symlinks can be created.</para>
323 </listitem>
324 </varlistentry>
325
326 <varlistentry>
327 <term><option>SYMLINK</option></term>
328 <listitem>
329 <para>The name of a symlink targeting the node. Every matching rule adds
330 this value to the list of symlinks to be created. Multiple symlinks may be
331 specified by separating the names by the space character. In case multiple
332 devices claim the same name, the link always points to the device with
333 the highest link_priority. If the current device goes away, the links are
334 re-evaluated and the device with the next highest link_priority becomes the owner of
335 the link. If no link_priority is specified, the order of the devices (and
336 which one of them owns the link) is undefined. Also, symlink names must
337 never conflict with the kernel's default device node names, as that would
338 result in unpredictable behavior.
339 </para>
340 </listitem>
341 </varlistentry>
342
343 <varlistentry>
344 <term><option>OWNER, GROUP, MODE</option></term>
345 <listitem>
346 <para>The permissions for the device node. Every specified value overrides
347 the compiled-in default value.</para>
348 </listitem>
349 </varlistentry>
350
351 <varlistentry>
352 <term><option>ATTR{<replaceable>key</replaceable>}</option></term>
353 <listitem>
354 <para>The value that should be written to a sysfs attribute of the
355 event device.</para>
356 </listitem>
357 </varlistentry>
358
359 <varlistentry>
360 <term><option>ENV{<replaceable>key</replaceable>}</option></term>
361 <listitem>
362 <para>Set a device property value. Property names with a leading '.'
363 are neither stored in the database nor exported to events or
364 external tools (run by, say, the PROGRAM match key).</para>
365 </listitem>
366 </varlistentry>
367
368 <varlistentry>
369 <term><option>TAG</option></term>
370 <listitem>
371 <para>Attach a tag to a device. This is used to filter events for users
372 of libudev's monitor functionality, or to enumerate a group of tagged
373 devices. The implementation can only work efficiently if only a few
374 tags are attached to a device. It is only meant to be used in
375 contexts with specific device filter requirements, and not as a
376 general-purpose flag. Excessive use might result in inefficient event
377 handling.</para>
378 </listitem>
379 </varlistentry>
380
381 <varlistentry>
382 <term><option>RUN</option></term>
383 <listitem>
384 <para>Add a program to the list of programs to be executed for a specific
385 device.</para>
386 <para>If no absolute path is given, the program is expected to live in
387 /usr/lib/udev, otherwise the absolute path must be specified. The program
388 name and following arguments are separated by spaces. Single quotes can
389 be used to specify arguments with spaces.</para>
390 <para>This can only be used for very short running tasks. Running an
391 event process for a long period of time may block all further events for
392 this or a dependent device. Starting daemons or other long running processes
393 is not appropriate for udev.</para>
394 </listitem>
395 </varlistentry>
396
397 <varlistentry>
398 <term><option>LABEL</option></term>
399 <listitem>
400 <para>A named label to which a GOTO may jump.</para>
401 </listitem>
402 </varlistentry>
403
404 <varlistentry>
405 <term><option>GOTO</option></term>
406 <listitem>
407 <para>Jumps to the next LABEL with a matching name.</para>
408 </listitem>
409 </varlistentry>
410
411 <varlistentry>
412 <term><option>IMPORT{<replaceable>type</replaceable>}</option></term>
413 <listitem>
414 <para>Import a set of variables as device properties,
415 depending on <replaceable>type</replaceable>:</para>
416 <variablelist>
417 <varlistentry>
418 <term><option>program</option></term>
419 <listitem>
420 <para>Execute an external program specified as the assigned value and
421 import its output, which must be in environment key
422 format. Path specification, command/argument separation,
423 and quoting work like in <option>RUN</option>.</para>
424 </listitem>
425 </varlistentry>
426 <varlistentry>
427 <term><option>file</option></term>
428 <listitem>
429 <para>Import a text file specified as the assigned value, the content
430 of which must be in environment key format.</para>
431 </listitem>
432 </varlistentry>
433 <varlistentry>
434 <term><option>db</option></term>
435 <listitem>
436 <para>Import a single property specified as the assigned value from the
437 current device database. This works only if the database is already populated
438 by an earlier event.</para>
439 </listitem>
440 </varlistentry>
441 <varlistentry>
442 <term><option>cmdline</option></term>
443 <listitem>
444 <para>Import a single property from the kernel command line. For simple flags
445 the value of the property is set to '1'.</para>
446 </listitem>
447 </varlistentry>
448 <varlistentry>
449 <term><option>parent</option></term>
450 <listitem>
451 <para>Import the stored keys from the parent device by reading
452 the database entry of the parent device. The value assigned to
453 <option>IMPORT{parent}</option> is used as a filter of key names
454 to import (with the same shell-style pattern matching used for
455 comparisons).</para>
456 </listitem>
457 </varlistentry>
458 </variablelist>
459 </listitem>
460 </varlistentry>
461
462 <varlistentry>
463 <term><option>WAIT_FOR</option></term>
464 <listitem>
465 <para>Wait for a file to become available or until a timeout of
466 10 seconds expires. The path is relative to the sysfs device;
467 if no path is specified, this waits for an attribute to appear.</para>
468 </listitem>
469 </varlistentry>
470
471 <varlistentry>
472 <term><option>OPTIONS</option></term>
473 <listitem>
474 <para>Rule and device options:</para>
475 <variablelist>
476 <varlistentry>
477 <term><option>link_priority=<replaceable>value</replaceable></option></term>
478 <listitem>
479 <para>Specify the priority of the created symlinks. Devices with higher
480 priorities overwrite existing symlinks of other devices. The default is 0.</para>
481 </listitem>
482 </varlistentry>
483 <varlistentry>
484 <term><option>event_timeout=</option></term>
485 <listitem>
486 <para>Number of seconds an event waits for operations to finish before
487 giving up and terminating itself.</para>
488 </listitem>
489 </varlistentry>
490 <varlistentry>
491 <term><option>string_escape=<replaceable>none|replace</replaceable></option></term>
492 <listitem>
493 <para>Usually control and other possibly unsafe characters are replaced
494 in strings used for device naming. The mode of replacement can be specified
495 with this option.</para>
496 </listitem>
497 </varlistentry>
498 <varlistentry>
499 <term><option>static_node=</option></term>
500 <listitem>
501 <para>Apply the permissions specified in this rule to the static device node with
502 the specified name. Static device nodes might be provided by kernel modules
503 or copied from <filename>/usr/lib/udev/devices</filename>. These nodes might not have
504 a corresponding kernel device at the time udevd is started; they can trigger
505 automatic kernel module loading.</para>
506 </listitem>
507 </varlistentry>
508 <varlistentry>
509 <term><option>watch</option></term>
510 <listitem>
511 <para>Watch the device node with inotify; when the node is closed after being opened for
512 writing, a change uevent is synthesized.</para>
513 </listitem>
514 </varlistentry>
515 <varlistentry>
516 <term><option>nowatch</option></term>
517 <listitem>
518 <para>Disable the watching of a device node with inotify.</para>
519 </listitem>
520 </varlistentry>
521 </variablelist>
522 </listitem>
523 </varlistentry>
524 </variablelist>
525
526 <para>The <option>NAME</option>, <option>SYMLINK</option>, <option>PROGRAM</option>,
527 <option>OWNER</option>, <option>GROUP</option>, <option>MODE</option> and <option>RUN</option>
528 fields support simple string substitutions. The <option>RUN</option>
529 substitutions are performed after all rules have been processed, right before the program
530 is executed, allowing for the use of device properties set by earlier matching
531 rules. For all other fields, substitutions are performed while the individual rule is
532 being processed. The available substitutions are:</para>
533 <variablelist>
534 <varlistentry>
535 <term><option>$kernel</option>, <option>%k</option></term>
536 <listitem>
537 <para>The kernel name for this device.</para>
538 </listitem>
539 </varlistentry>
540
541 <varlistentry>
542 <term><option>$number</option>, <option>%n</option></term>
543 <listitem>
544 <para>The kernel number for this device. For example, 'sda3' has
545 kernel number of '3'</para>
546 </listitem>
547 </varlistentry>
548
549 <varlistentry>
550 <term><option>$devpath</option>, <option>%p</option></term>
551 <listitem>
552 <para>The devpath of the device.</para>
553 </listitem>
554 </varlistentry>
555
556 <varlistentry>
557 <term><option>$id</option>, <option>%b</option></term>
558 <listitem>
559 <para>The name of the device matched while searching the devpath upwards for
560 <option>SUBSYSTEMS</option>, <option>KERNELS</option>, <option>DRIVERS</option> and <option>ATTRS</option>.
561 </para>
562 </listitem>
563 </varlistentry>
564
565 <varlistentry>
566 <term><option>$driver</option></term>
567 <listitem>
568 <para>The driver name of the device matched while searching the devpath upwards for
569 <option>SUBSYSTEMS</option>, <option>KERNELS</option>, <option>DRIVERS</option> and <option>ATTRS</option>.
570 </para>
571 </listitem>
572 </varlistentry>
573
574 <varlistentry>
575 <term><option>$attr{<replaceable>file</replaceable>}</option>, <option>%s{<replaceable>file</replaceable>}</option></term>
576 <listitem>
577 <para>The value of a sysfs attribute found at the device where
578 all keys of the rule have matched. If the matching device does not have
579 such an attribute, and a previous KERNELS, SUBSYSTEMS, DRIVERS, or
580 ATTRS test selected a parent device, then the attribute from that
581 parent device is used.</para>
582 <para>If the attribute is a symlink, the last element of the symlink target is
583 returned as the value.</para>
584 </listitem>
585 </varlistentry>
586
587 <varlistentry>
588 <term><option>$env{<replaceable>key</replaceable>}</option>, <option>%E{<replaceable>key</replaceable>}</option></term>
589 <listitem>
590 <para>A device property value.</para>
591 </listitem>
592 </varlistentry>
593
594 <varlistentry>
595 <term><option>$major</option>, <option>%M</option></term>
596 <listitem>
597 <para>The kernel major number for the device.</para>
598 </listitem>
599 </varlistentry>
600
601 <varlistentry>
602 <term><option>$minor</option>, <option>%m</option></term>
603 <listitem>
604 <para>The kernel minor number for the device.</para>
605 </listitem>
606 </varlistentry>
607
608 <varlistentry>
609 <term><option>$result</option>, <option>%c</option></term>
610 <listitem>
611 <para>The string returned by the external program requested with PROGRAM.
612 A single part of the string, separated by a space character, may be selected
613 by specifying the part number as an attribute: <option>%c{N}</option>.
614 If the number is followed by the '+' character, this part plus all remaining parts
615 of the result string are substituted: <option>%c{N+}</option></para>
616 </listitem>
617 </varlistentry>
618
619 <varlistentry>
620 <term><option>$parent</option>, <option>%P</option></term>
621 <listitem>
622 <para>The node name of the parent device.</para>
623 </listitem>
624 </varlistentry>
625
626 <varlistentry>
627 <term><option>$name</option></term>
628 <listitem>
629 <para>The current name of the device. If not changed by a rule, it is the
630 name of the kernel device.</para>
631 </listitem>
632 </varlistentry>
633
634 <varlistentry>
635 <term><option>$links</option></term>
636 <listitem>
637 <para>A space-separated list of the current symlinks. The value is
638 only set during a remove event or if an earlier rule assigned a value.</para>
639 </listitem>
640 </varlistentry>
641
642 <varlistentry>
643 <term><option>$root</option>, <option>%r</option></term>
644 <listitem>
645 <para>The udev_root value.</para>
646 </listitem>
647 </varlistentry>
648
649 <varlistentry>
650 <term><option>$sys</option>, <option>%S</option></term>
651 <listitem>
652 <para>The sysfs mount point.</para>
653 </listitem>
654 </varlistentry>
655
656 <varlistentry>
657 <term><option>$devnode</option>, <option>%N</option></term>
658 <listitem>
659 <para>The name of the device node.</para>
660 </listitem>
661 </varlistentry>
662
663 <varlistentry>
664 <term><option>%%</option></term>
665 <listitem>
666 <para>The '%' character itself.</para>
667 </listitem>
668 </varlistentry>
669
670 <varlistentry>
671 <term><option>$$</option></term>
672 <listitem>
673 <para>The '$' character itself.</para>
674 </listitem>
675 </varlistentry>
676 </variablelist>
677 </refsect2>
678 </refsect1>
679
680 <refsect1><title>Author</title>
681 <para>Written by Greg Kroah-Hartman <email>greg@kroah.com</email> and
682 Kay Sievers <email>kay.sievers@vrfy.org</email>. With much help from
683 Dan Stekloff and many others.</para>
684 </refsect1>
685
686 <refsect1>
687 <title>See Also</title>
688 <para><citerefentry>
689 <refentrytitle>udevd</refentrytitle><manvolnum>8</manvolnum>
690 </citerefentry>,
691 <citerefentry>
692 <refentrytitle>udevadm</refentrytitle><manvolnum>8</manvolnum>
693 </citerefentry></para>
694 </refsect1>
695 </refentry>
File src/udevadm-control.c added (mode: 100644) (index 0000000..cafa214)
1 /*
2 * Copyright (C) 2005-2011 Kay Sievers <kay.sievers@vrfy.org>
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15 #include <time.h>
16 #include <errno.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <stddef.h>
20 #include <string.h>
21 #include <unistd.h>
22 #include <getopt.h>
23 #include <sys/types.h>
24 #include <sys/socket.h>
25 #include <sys/wait.h>
26 #include <sys/un.h>
27
28 #include "udev.h"
29
30 static void print_help(void)
31 {
32 printf("Usage: udevadm control COMMAND\n"
33 " --exit instruct the daemon to cleanup and exit\n"
34 " --log-priority=<level> set the udev log level for the daemon\n"
35 " --stop-exec-queue do not execute events, queue only\n"
36 " --start-exec-queue execute events, flush queue\n"
37 " --reload reload rules and databases\n"
38 " --property=<KEY>=<value> set a global property for all events\n"
39 " --children-max=<N> maximum number of children\n"
40 " --timeout=<seconds> maximum time to block for a reply\n"
41 " --help print this help text\n\n");
42 }
43
44 static int adm_control(struct udev *udev, int argc, char *argv[])
45 {
46 struct udev_ctrl *uctrl = NULL;
47 int timeout = 60;
48 int rc = 1;
49
50 static const struct option options[] = {
51 { "exit", no_argument, NULL, 'e' },
52 { "log-priority", required_argument, NULL, 'l' },
53 { "stop-exec-queue", no_argument, NULL, 's' },
54 { "start-exec-queue", no_argument, NULL, 'S' },
55 { "reload", no_argument, NULL, 'R' },
56 { "reload-rules", no_argument, NULL, 'R' },
57 { "property", required_argument, NULL, 'p' },
58 { "env", required_argument, NULL, 'p' },
59 { "children-max", required_argument, NULL, 'm' },
60 { "timeout", required_argument, NULL, 't' },
61 { "help", no_argument, NULL, 'h' },
62 {}
63 };
64
65 if (getuid() != 0) {
66 fprintf(stderr, "root privileges required\n");
67 return 1;
68 }
69
70 uctrl = udev_ctrl_new(udev);
71 if (uctrl == NULL)
72 return 2;
73
74 for (;;) {
75 int option;
76
77 option = getopt_long(argc, argv, "el:sSRp:m:h", options, NULL);
78 if (option == -1)
79 break;
80
81 switch (option) {
82 case 'e':
83 if (udev_ctrl_send_exit(uctrl, timeout) < 0)
84 rc = 2;
85 else
86 rc = 0;
87 break;
88 case 'l': {
89 int i;
90
91 i = util_log_priority(optarg);
92 if (i < 0) {
93 fprintf(stderr, "invalid number '%s'\n", optarg);
94 goto out;
95 }
96 if (udev_ctrl_send_set_log_level(uctrl, util_log_priority(optarg), timeout) < 0)
97 rc = 2;
98 else
99 rc = 0;
100 break;
101 }
102 case 's':
103 if (udev_ctrl_send_stop_exec_queue(uctrl, timeout) < 0)
104 rc = 2;
105 else
106 rc = 0;
107 break;
108 case 'S':
109 if (udev_ctrl_send_start_exec_queue(uctrl, timeout) < 0)
110 rc = 2;
111 else
112 rc = 0;
113 break;
114 case 'R':
115 if (udev_ctrl_send_reload(uctrl, timeout) < 0)
116 rc = 2;
117 else
118 rc = 0;
119 break;
120 case 'p':
121 if (strchr(optarg, '=') == NULL) {
122 fprintf(stderr, "expect <KEY>=<value> instead of '%s'\n", optarg);
123 goto out;
124 }
125 if (udev_ctrl_send_set_env(uctrl, optarg, timeout) < 0)
126 rc = 2;
127 else
128 rc = 0;
129 break;
130 case 'm': {
131 char *endp;
132 int i;
133
134 i = strtoul(optarg, &endp, 0);
135 if (endp[0] != '\0' || i < 1) {
136 fprintf(stderr, "invalid number '%s'\n", optarg);
137 goto out;
138 }
139 if (udev_ctrl_send_set_children_max(uctrl, i, timeout) < 0)
140 rc = 2;
141 else
142 rc = 0;
143 break;
144 }
145 case 't': {
146 int seconds;
147
148 seconds = atoi(optarg);
149 if (seconds >= 0)
150 timeout = seconds;
151 else
152 fprintf(stderr, "invalid timeout value\n");
153 break;
154 }
155 case 'h':
156 print_help();
157 rc = 0;
158 break;
159 }
160 }
161
162 if (argv[optind] != NULL)
163 fprintf(stderr, "unknown option\n");
164 else if (optind == 1)
165 fprintf(stderr, "missing option\n");
166 out:
167 udev_ctrl_unref(uctrl);
168 return rc;
169 }
170
171 const struct udevadm_cmd udevadm_control = {
172 .name = "control",
173 .cmd = adm_control,
174 .help = "control the udev daemon",
175 };
File src/udevadm-info.c added (mode: 100644) (index 0000000..bbb89f5)
1 /*
2 * Copyright (C) 2004-2009 Kay Sievers <kay.sievers@vrfy.org>
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include <stdlib.h>
19 #include <string.h>
20 #include <stdio.h>
21 #include <stddef.h>
22 #include <ctype.h>
23 #include <stdarg.h>
24 #include <unistd.h>
25 #include <dirent.h>
26 #include <errno.h>
27 #include <getopt.h>
28 #include <fcntl.h>
29 #include <sys/stat.h>
30 #include <sys/types.h>
31
32 #include "udev.h"
33
34 static bool skip_attribute(const char *name)
35 {
36 static const char const *skip[] = {
37 "uevent",
38 "dev",
39 "modalias",
40 "resource",
41 "driver",
42 "subsystem",
43 "module",
44 };
45 unsigned int i;
46
47 for (i = 0; i < ARRAY_SIZE(skip); i++)
48 if (strcmp(name, skip[i]) == 0)
49 return true;
50 return false;
51 }
52
53 static void print_all_attributes(struct udev_device *device, const char *key)
54 {
55 struct udev *udev = udev_device_get_udev(device);
56 struct udev_list_entry *sysattr;
57
58 udev_list_entry_foreach(sysattr, udev_device_get_sysattr_list_entry(device)) {
59 const char *name;
60 const char *value;
61 size_t len;
62
63 name = udev_list_entry_get_name(sysattr);
64 if (skip_attribute(name))
65 continue;
66
67 value = udev_device_get_sysattr_value(device, name);
68 if (value == NULL)
69 continue;
70 dbg(udev, "attr '%s'='%s'\n", name, value);
71
72 /* skip any values that look like a path */
73 if (value[0] == '/')
74 continue;
75
76 /* skip nonprintable attributes */
77 len = strlen(value);
78 while (len > 0 && isprint(value[len-1]))
79 len--;
80 if (len > 0) {
81 dbg(udev, "attribute value of '%s' non-printable, skip\n", name);
82 continue;
83 }
84
85 printf(" %s{%s}==\"%s\"\n", key, name, value);
86 }
87 printf("\n");
88 }
89
90 static int print_device_chain(struct udev_device *device)
91 {
92 struct udev_device *device_parent;
93 const char *str;
94
95 printf("\n"
96 "Udevadm info starts with the device specified by the devpath and then\n"
97 "walks up the chain of parent devices. It prints for every device\n"
98 "found, all possible attributes in the udev rules key format.\n"
99 "A rule to match, can be composed by the attributes of the device\n"
100 "and the attributes from one single parent device.\n"
101 "\n");
102
103 printf(" looking at device '%s':\n", udev_device_get_devpath(device));
104 printf(" KERNEL==\"%s\"\n", udev_device_get_sysname(device));
105 str = udev_device_get_subsystem(device);
106 if (str == NULL)
107 str = "";
108 printf(" SUBSYSTEM==\"%s\"\n", str);
109 str = udev_device_get_driver(device);
110 if (str == NULL)
111 str = "";
112 printf(" DRIVER==\"%s\"\n", str);
113 print_all_attributes(device, "ATTR");
114
115 device_parent = device;
116 do {
117 device_parent = udev_device_get_parent(device_parent);
118 if (device_parent == NULL)
119 break;
120 printf(" looking at parent device '%s':\n", udev_device_get_devpath(device_parent));
121 printf(" KERNELS==\"%s\"\n", udev_device_get_sysname(device_parent));
122 str = udev_device_get_subsystem(device_parent);
123 if (str == NULL)
124 str = "";
125 printf(" SUBSYSTEMS==\"%s\"\n", str);
126 str = udev_device_get_driver(device_parent);
127 if (str == NULL)
128 str = "";
129 printf(" DRIVERS==\"%s\"\n", str);
130 print_all_attributes(device_parent, "ATTRS");
131 } while (device_parent != NULL);
132
133 return 0;
134 }
135
136 static void print_record(struct udev_device *device)
137 {
138 size_t len;
139 const char *str;
140 int i;
141 struct udev_list_entry *list_entry;
142
143 printf("P: %s\n", udev_device_get_devpath(device));
144
145 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
146 str = udev_device_get_devnode(device);
147 if (str != NULL)
148 printf("N: %s\n", &str[len+1]);
149
150 i = udev_device_get_devlink_priority(device);
151 if (i != 0)
152 printf("L: %i\n", i);
153
154 udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(device)) {
155 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
156 printf("S: %s\n", &udev_list_entry_get_name(list_entry)[len+1]);
157 }
158
159 udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(device))
160 printf("E: %s=%s\n",
161 udev_list_entry_get_name(list_entry),
162 udev_list_entry_get_value(list_entry));
163 printf("\n");
164 }
165
166 static int stat_device(const char *name, bool export, const char *prefix)
167 {
168 struct stat statbuf;
169
170 if (stat(name, &statbuf) != 0)
171 return -1;
172
173 if (export) {
174 if (prefix == NULL)
175 prefix = "INFO_";
176 printf("%sMAJOR=%d\n"
177 "%sMINOR=%d\n",
178 prefix, major(statbuf.st_dev),
179 prefix, minor(statbuf.st_dev));
180 } else
181 printf("%d:%d\n", major(statbuf.st_dev), minor(statbuf.st_dev));
182 return 0;
183 }
184
185 static int export_devices(struct udev *udev)
186 {
187 struct udev_enumerate *udev_enumerate;
188 struct udev_list_entry *list_entry;
189
190 udev_enumerate = udev_enumerate_new(udev);
191 if (udev_enumerate == NULL)
192 return -1;
193 udev_enumerate_scan_devices(udev_enumerate);
194 udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(udev_enumerate)) {
195 struct udev_device *device;
196
197 device = udev_device_new_from_syspath(udev, udev_list_entry_get_name(list_entry));
198 if (device != NULL) {
199 print_record(device);
200 udev_device_unref(device);
201 }
202 }
203 udev_enumerate_unref(udev_enumerate);
204 return 0;
205 }
206
207 static void cleanup_dir(DIR *dir, mode_t mask, int depth)
208 {
209 struct dirent *dent;
210
211 if (depth <= 0)
212 return;
213
214 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
215 struct stat stats;
216
217 if (dent->d_name[0] == '.')
218 continue;
219 if (fstatat(dirfd(dir), dent->d_name, &stats, AT_SYMLINK_NOFOLLOW) != 0)
220 continue;
221 if ((stats.st_mode & mask) != 0)
222 continue;
223 if (S_ISDIR(stats.st_mode)) {
224 DIR *dir2;
225
226 dir2 = fdopendir(openat(dirfd(dir), dent->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC));
227 if (dir2 != NULL) {
228 cleanup_dir(dir2, mask, depth-1);
229 closedir(dir2);
230 }
231 unlinkat(dirfd(dir), dent->d_name, AT_REMOVEDIR);
232 } else {
233 unlinkat(dirfd(dir), dent->d_name, 0);
234 }
235 }
236 }
237
238 static void cleanup_db(struct udev *udev)
239 {
240 char filename[UTIL_PATH_SIZE];
241 DIR *dir;
242
243 util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/queue.bin", NULL);
244 unlink(filename);
245
246 util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/data", NULL);
247 dir = opendir(filename);
248 if (dir != NULL) {
249 cleanup_dir(dir, S_ISVTX, 1);
250 closedir(dir);
251 }
252
253 util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/links", NULL);
254 dir = opendir(filename);
255 if (dir != NULL) {
256 cleanup_dir(dir, 0, 2);
257 closedir(dir);
258 }
259
260 util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/tags", NULL);
261 dir = opendir(filename);
262 if (dir != NULL) {
263 cleanup_dir(dir, 0, 2);
264 closedir(dir);
265 }
266
267 util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/watch", NULL);
268 dir = opendir(filename);
269 if (dir != NULL) {
270 cleanup_dir(dir, 0, 1);
271 closedir(dir);
272 }
273
274 util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/firmware-missing", NULL);
275 dir = opendir(filename);
276 if (dir != NULL) {
277 cleanup_dir(dir, 0, 1);
278 closedir(dir);
279 }
280 }
281
282 static struct udev_device *find_device(struct udev *udev, const char *id, const char *prefix)
283 {
284 char name[UTIL_PATH_SIZE];
285
286 if (prefix && strncmp(id, prefix, strlen(prefix))) {
287 util_strscpyl(name, sizeof(name), prefix, id, NULL);
288 id = name;
289 }
290
291 if (strstr(id, udev_get_dev_path(udev)) == id) {
292 struct stat statbuf;
293 char type;
294
295 if (stat(id, &statbuf) < 0)
296 return NULL;
297
298 if (S_ISBLK(statbuf.st_mode))
299 type = 'b';
300 else if (S_ISCHR(statbuf.st_mode))
301 type = 'c';
302 else
303 return NULL;
304
305 return udev_device_new_from_devnum(udev, type, statbuf.st_rdev);
306 } else if (strstr(id, udev_get_sys_path(udev)) == id)
307 return udev_device_new_from_syspath(udev, id);
308 else
309 return NULL;
310 }
311
312 static int uinfo(struct udev *udev, int argc, char *argv[])
313 {
314 struct udev_device *device = NULL;
315 bool root = 0;
316 bool export = 0;
317 const char *export_prefix = NULL;
318 char name[UTIL_PATH_SIZE];
319 struct udev_list_entry *list_entry;
320 int rc = 0;
321
322 static const struct option options[] = {
323 { "name", required_argument, NULL, 'n' },
324 { "path", required_argument, NULL, 'p' },
325 { "query", required_argument, NULL, 'q' },
326 { "attribute-walk", no_argument, NULL, 'a' },
327 { "cleanup-db", no_argument, NULL, 'c' },
328 { "export-db", no_argument, NULL, 'e' },
329 { "root", no_argument, NULL, 'r' },
330 { "run", no_argument, NULL, 'R' },
331 { "device-id-of-file", required_argument, NULL, 'd' },
332 { "export", no_argument, NULL, 'x' },
333 { "export-prefix", required_argument, NULL, 'P' },
334 { "version", no_argument, NULL, 'V' },
335 { "help", no_argument, NULL, 'h' },
336 {}
337 };
338
339 static const char usage[] =
340 "Usage: udevadm info OPTIONS\n"
341 " --query=<type> query device information:\n"
342 " name name of device node\n"
343 " symlink pointing to node\n"
344 " path sys device path\n"
345 " property the device properties\n"
346 " all all values\n"
347 " --path=<syspath> sys device path used for query or attribute walk\n"
348 " --name=<name> node or symlink name used for query or attribute walk\n"
349 " --root prepend dev directory to path names\n"
350 " --attribute-walk print all key matches while walking along the chain\n"
351 " of parent devices\n"
352 " --device-id-of-file=<file> print major:minor of device containing this file\n"
353 " --export export key/value pairs\n"
354 " --export-prefix export the key name with a prefix\n"
355 " --export-db export the content of the udev database\n"
356 " --cleanup-db cleanup the udev database\n"
357 " --help\n";
358
359
360 enum action_type {
361 ACTION_NONE,
362 ACTION_QUERY,
363 ACTION_ATTRIBUTE_WALK,
364 ACTION_ROOT,
365 ACTION_DEVICE_ID_FILE,
366 } action = ACTION_QUERY;
367
368 enum query_type {
369 QUERY_NONE,
370 QUERY_NAME,
371 QUERY_PATH,
372 QUERY_SYMLINK,
373 QUERY_PROPERTY,
374 QUERY_ALL,
375 } query = QUERY_ALL;
376
377 for (;;) {
378 int option;
379
380 option = getopt_long(argc, argv, "aced:n:p:q:rxP:RVh", options, NULL);
381 if (option == -1)
382 break;
383
384 dbg(udev, "option '%c'\n", option);
385 switch (option) {
386 case 'n':
387 if (device != NULL) {
388 fprintf(stderr, "device already specified\n");
389 rc = 2;
390 goto exit;
391 }
392 device = find_device(udev, optarg, udev_get_dev_path(udev));
393 if(device == NULL) {
394 fprintf(stderr, "device node not found\n");
395 rc = 2;
396 goto exit;
397 }
398 break;
399 case 'p':
400 if (device != NULL) {
401 fprintf(stderr, "device already specified\n");
402 rc = 2;
403 goto exit;
404 }
405
406 device = find_device(udev, optarg, udev_get_sys_path(udev));
407 if (device == NULL) {
408 fprintf(stderr, "device path not found\n");
409 rc = 2;
410 goto exit;
411 }
412 break;
413 case 'q':
414 action = ACTION_QUERY;
415 if (strcmp(optarg, "property") == 0 || strcmp(optarg, "env") == 0) {
416 query = QUERY_PROPERTY;
417 } else if (strcmp(optarg, "name") == 0) {
418 query = QUERY_NAME;
419 } else if (strcmp(optarg, "symlink") == 0) {
420 query = QUERY_SYMLINK;
421 } else if (strcmp(optarg, "path") == 0) {
422 query = QUERY_PATH;
423 } else if (strcmp(optarg, "all") == 0) {
424 query = QUERY_ALL;
425 } else {
426 fprintf(stderr, "unknown query type\n");
427 rc = 3;
428 goto exit;
429 }
430 break;
431 case 'r':
432 if (action == ACTION_NONE)
433 action = ACTION_ROOT;
434 root = true;
435 break;
436 case 'R':
437 printf("%s\n", udev_get_run_path(udev));
438 goto exit;
439 case 'd':
440 action = ACTION_DEVICE_ID_FILE;
441 util_strscpy(name, sizeof(name), optarg);
442 break;
443 case 'a':
444 action = ACTION_ATTRIBUTE_WALK;
445 break;
446 case 'e':
447 export_devices(udev);
448 goto exit;
449 case 'c':
450 cleanup_db(udev);
451 goto exit;
452 case 'x':
453 export = true;
454 break;
455 case 'P':
456 export_prefix = optarg;
457 break;
458 case 'V':
459 printf("%s\n", VERSION);
460 goto exit;
461 case 'h':
462 printf("%s\n", usage);
463 goto exit;
464 default:
465 rc = 1;
466 goto exit;
467 }
468 }
469
470 switch (action) {
471 case ACTION_QUERY:
472 if (device == NULL) {
473 if(!argv[optind]) {
474 fprintf(stderr, "%s\n", usage);
475 rc = 2;
476 goto exit;
477 }
478 device = find_device(udev, argv[optind], NULL);
479 if(device == NULL) {
480 fprintf(stderr,
481 "query needs a valid device specified"
482 "by --path=, --name=, or absolute path"
483 "in %s or %s\n", udev_get_dev_path(udev), udev_get_sys_path(udev));
484 rc = 4;
485 goto exit;
486 }
487 }
488
489 switch(query) {
490 case QUERY_NAME: {
491 const char *node = udev_device_get_devnode(device);
492
493 if (node == NULL) {
494 fprintf(stderr, "no device node found\n");
495 rc = 5;
496 goto exit;
497 }
498
499 if (root) {
500 printf("%s\n", udev_device_get_devnode(device));
501 } else {
502 size_t len = strlen(udev_get_dev_path(udev));
503
504 printf("%s\n", &udev_device_get_devnode(device)[len+1]);
505 }
506 break;
507 }
508 case QUERY_SYMLINK:
509 list_entry = udev_device_get_devlinks_list_entry(device);
510 while (list_entry != NULL) {
511 if (root) {
512 printf("%s", udev_list_entry_get_name(list_entry));
513 } else {
514 size_t len;
515
516 len = strlen(udev_get_dev_path(udev_device_get_udev(device)));
517 printf("%s", &udev_list_entry_get_name(list_entry)[len+1]);
518 }
519 list_entry = udev_list_entry_get_next(list_entry);
520 if (list_entry != NULL)
521 printf(" ");
522 }
523 printf("\n");
524 break;
525 case QUERY_PATH:
526 printf("%s\n", udev_device_get_devpath(device));
527 goto exit;
528 case QUERY_PROPERTY:
529 list_entry = udev_device_get_properties_list_entry(device);
530 while (list_entry != NULL) {
531 if (export) {
532 const char *prefix = export_prefix;
533
534 if (prefix == NULL)
535 prefix = "";
536 printf("%s%s='%s'\n", prefix,
537 udev_list_entry_get_name(list_entry),
538 udev_list_entry_get_value(list_entry));
539 } else {
540 printf("%s=%s\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry));
541 }
542 list_entry = udev_list_entry_get_next(list_entry);
543 }
544 break;
545 case QUERY_ALL:
546 print_record(device);
547 break;
548 default:
549 fprintf(stderr, "unknown query type\n");
550 break;
551 }
552 break;
553 case ACTION_ATTRIBUTE_WALK:
554 if (device == NULL) {
555 if(argv[optind])
556 device = find_device(udev, argv[optind], NULL);
557 if(device == NULL) {
558 fprintf(stderr, "query needs a valid device specified by --path= or --name=\n");
559 rc = 4;
560 goto exit;
561 }
562 }
563 print_device_chain(device);
564 break;
565 case ACTION_DEVICE_ID_FILE:
566 if (stat_device(name, export, export_prefix) != 0)
567 rc = 1;
568 break;
569 case ACTION_ROOT:
570 printf("%s\n", udev_get_dev_path(udev));
571 break;
572 default:
573 fprintf(stderr, "missing option\n");
574 rc = 1;
575 break;
576 }
577
578 exit:
579 udev_device_unref(device);
580 return rc;
581 }
582
583 const struct udevadm_cmd udevadm_info = {
584 .name = "info",
585 .cmd = uinfo,
586 .help = "query sysfs or the udev database",
587 };
File src/udevadm-monitor.c added (mode: 100644) (index 0000000..5997dd8)
1 /*
2 * Copyright (C) 2004-2010 Kay Sievers <kay.sievers@vrfy.org>
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include <unistd.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <stddef.h>
22 #include <string.h>
23 #include <fcntl.h>
24 #include <errno.h>
25 #include <signal.h>
26 #include <getopt.h>
27 #include <time.h>
28 #include <sys/time.h>
29 #include <sys/socket.h>
30 #include <sys/un.h>
31 #include <sys/epoll.h>
32 #include <linux/types.h>
33 #include <linux/netlink.h>
34
35 #include "udev.h"
36
37 static bool udev_exit;
38
39 static void sig_handler(int signum)
40 {
41 if (signum == SIGINT || signum == SIGTERM)
42 udev_exit = true;
43 }
44
45 static void print_device(struct udev_device *device, const char *source, int prop)
46 {
47 struct timespec ts;
48
49 clock_gettime(CLOCK_MONOTONIC, &ts);
50 printf("%-6s[%llu.%06u] %-8s %s (%s)\n",
51 source,
52 (unsigned long long) ts.tv_sec, (unsigned int) ts.tv_nsec/1000,
53 udev_device_get_action(device),
54 udev_device_get_devpath(device),
55 udev_device_get_subsystem(device));
56 if (prop) {
57 struct udev_list_entry *list_entry;
58
59 udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(device))
60 printf("%s=%s\n",
61 udev_list_entry_get_name(list_entry),
62 udev_list_entry_get_value(list_entry));
63 printf("\n");
64 }
65 }
66
67 static int adm_monitor(struct udev *udev, int argc, char *argv[])
68 {
69 struct sigaction act;
70 sigset_t mask;
71 int option;
72 bool prop = false;
73 bool print_kernel = false;
74 bool print_udev = false;
75 struct udev_list subsystem_match_list;
76 struct udev_list tag_match_list;
77 struct udev_monitor *udev_monitor = NULL;
78 struct udev_monitor *kernel_monitor = NULL;
79 int fd_ep = -1;
80 int fd_kernel = -1, fd_udev = -1;
81 struct epoll_event ep_kernel, ep_udev;
82 int rc = 0;
83
84 static const struct option options[] = {
85 { "property", no_argument, NULL, 'p' },
86 { "environment", no_argument, NULL, 'e' },
87 { "kernel", no_argument, NULL, 'k' },
88 { "udev", no_argument, NULL, 'u' },
89 { "subsystem-match", required_argument, NULL, 's' },
90 { "tag-match", required_argument, NULL, 't' },
91 { "help", no_argument, NULL, 'h' },
92 {}
93 };
94
95 udev_list_init(udev, &subsystem_match_list, true);
96 udev_list_init(udev, &tag_match_list, true);
97
98 for (;;) {
99 option = getopt_long(argc, argv, "pekus:t:h", options, NULL);
100 if (option == -1)
101 break;
102
103 switch (option) {
104 case 'p':
105 case 'e':
106 prop = true;
107 break;
108 case 'k':
109 print_kernel = true;
110 break;
111 case 'u':
112 print_udev = true;
113 break;
114 case 's':
115 {
116 char subsys[UTIL_NAME_SIZE];
117 char *devtype;
118
119 util_strscpy(subsys, sizeof(subsys), optarg);
120 devtype = strchr(subsys, '/');
121 if (devtype != NULL) {
122 devtype[0] = '\0';
123 devtype++;
124 }
125 udev_list_entry_add(&subsystem_match_list, subsys, devtype);
126 break;
127 }
128 case 't':
129 udev_list_entry_add(&tag_match_list, optarg, NULL);
130 break;
131 case 'h':
132 printf("Usage: udevadm monitor [--property] [--kernel] [--udev] [--help]\n"
133 " --property print the event properties\n"
134 " --kernel print kernel uevents\n"
135 " --udev print udev events\n"
136 " --subsystem-match=<subsystem[/devtype]> filter events by subsystem\n"
137 " --tag-match=<tag> filter events by tag\n"
138 " --help\n\n");
139 goto out;
140 default:
141 rc = 1;
142 goto out;
143 }
144 }
145
146 if (!print_kernel && !print_udev) {
147 print_kernel = true;
148 print_udev = true;
149 }
150
151 /* set signal handlers */
152 memset(&act, 0x00, sizeof(struct sigaction));
153 act.sa_handler = sig_handler;
154 sigemptyset(&act.sa_mask);
155 act.sa_flags = SA_RESTART;
156 sigaction(SIGINT, &act, NULL);
157 sigaction(SIGTERM, &act, NULL);
158 sigemptyset(&mask);
159 sigaddset(&mask, SIGINT);
160 sigaddset(&mask, SIGTERM);
161 sigprocmask(SIG_UNBLOCK, &mask, NULL);
162
163 fd_ep = epoll_create1(EPOLL_CLOEXEC);
164 if (fd_ep < 0) {
165 err(udev, "error creating epoll fd: %m\n");
166 goto out;
167 }
168
169 printf("monitor will print the received events for:\n");
170 if (print_udev) {
171 struct udev_list_entry *entry;
172
173 udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
174 if (udev_monitor == NULL) {
175 fprintf(stderr, "error: unable to create netlink socket\n");
176 rc = 1;
177 goto out;
178 }
179 udev_monitor_set_receive_buffer_size(udev_monitor, 128*1024*1024);
180 fd_udev = udev_monitor_get_fd(udev_monitor);
181
182 udev_list_entry_foreach(entry, udev_list_get_entry(&subsystem_match_list)) {
183 const char *subsys = udev_list_entry_get_name(entry);
184 const char *devtype = udev_list_entry_get_value(entry);
185
186 if (udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, subsys, devtype) < 0)
187 fprintf(stderr, "error: unable to apply subsystem filter '%s'\n", subsys);
188 }
189
190 udev_list_entry_foreach(entry, udev_list_get_entry(&tag_match_list)) {
191 const char *tag = udev_list_entry_get_name(entry);
192
193 if (udev_monitor_filter_add_match_tag(udev_monitor, tag) < 0)
194 fprintf(stderr, "error: unable to apply tag filter '%s'\n", tag);
195 }
196
197 if (udev_monitor_enable_receiving(udev_monitor) < 0) {
198 fprintf(stderr, "error: unable to subscribe to udev events\n");
199 rc = 2;
200 goto out;
201 }
202
203 memset(&ep_udev, 0, sizeof(struct epoll_event));
204 ep_udev.events = EPOLLIN;
205 ep_udev.data.fd = fd_udev;
206 if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_udev, &ep_udev) < 0) {
207 err(udev, "fail to add fd to epoll: %m\n");
208 goto out;
209 }
210
211 printf("UDEV - the event which udev sends out after rule processing\n");
212 }
213
214 if (print_kernel) {
215 struct udev_list_entry *entry;
216
217 kernel_monitor = udev_monitor_new_from_netlink(udev, "kernel");
218 if (kernel_monitor == NULL) {
219 fprintf(stderr, "error: unable to create netlink socket\n");
220 rc = 3;
221 goto out;
222 }
223 udev_monitor_set_receive_buffer_size(kernel_monitor, 128*1024*1024);
224 fd_kernel = udev_monitor_get_fd(kernel_monitor);
225
226 udev_list_entry_foreach(entry, udev_list_get_entry(&subsystem_match_list)) {
227 const char *subsys = udev_list_entry_get_name(entry);
228
229 if (udev_monitor_filter_add_match_subsystem_devtype(kernel_monitor, subsys, NULL) < 0)
230 fprintf(stderr, "error: unable to apply subsystem filter '%s'\n", subsys);
231 }
232
233 if (udev_monitor_enable_receiving(kernel_monitor) < 0) {
234 fprintf(stderr, "error: unable to subscribe to kernel events\n");
235 rc = 4;
236 goto out;
237 }
238
239 memset(&ep_kernel, 0, sizeof(struct epoll_event));
240 ep_kernel.events = EPOLLIN;
241 ep_kernel.data.fd = fd_kernel;
242 if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_kernel, &ep_kernel) < 0) {
243 err(udev, "fail to add fd to epoll: %m\n");
244 goto out;
245 }
246
247 printf("KERNEL - the kernel uevent\n");
248 }
249 printf("\n");
250
251 while (!udev_exit) {
252 int fdcount;
253 struct epoll_event ev[4];
254 int i;
255
256 fdcount = epoll_wait(fd_ep, ev, ARRAY_SIZE(ev), -1);
257 if (fdcount < 0) {
258 if (errno != EINTR)
259 fprintf(stderr, "error receiving uevent message: %m\n");
260 continue;
261 }
262
263 for (i = 0; i < fdcount; i++) {
264 if (ev[i].data.fd == fd_kernel && ev[i].events & EPOLLIN) {
265 struct udev_device *device;
266
267 device = udev_monitor_receive_device(kernel_monitor);
268 if (device == NULL)
269 continue;
270 print_device(device, "KERNEL", prop);
271 udev_device_unref(device);
272 } else if (ev[i].data.fd == fd_udev && ev[i].events & EPOLLIN) {
273 struct udev_device *device;
274
275 device = udev_monitor_receive_device(udev_monitor);
276 if (device == NULL)
277 continue;
278 print_device(device, "UDEV", prop);
279 udev_device_unref(device);
280 }
281 }
282 }
283 out:
284 if (fd_ep >= 0)
285 close(fd_ep);
286 udev_monitor_unref(udev_monitor);
287 udev_monitor_unref(kernel_monitor);
288 udev_list_cleanup(&subsystem_match_list);
289 udev_list_cleanup(&tag_match_list);
290 return rc;
291 }
292
293 const struct udevadm_cmd udevadm_monitor = {
294 .name = "monitor",
295 .cmd = adm_monitor,
296 .help = "listen to kernel and udev events",
297 };
File src/udevadm-settle.c added (mode: 100644) (index 0000000..b168def)
1 /*
2 * Copyright (C) 2006-2009 Kay Sievers <kay@vrfy.org>
3 * Copyright (C) 2009 Canonical Ltd.
4 * Copyright (C) 2009 Scott James Remnant <scott@netsplit.com>
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <stdlib.h>
21 #include <stddef.h>
22 #include <string.h>
23 #include <stdio.h>
24 #include <unistd.h>
25 #include <errno.h>
26 #include <dirent.h>
27 #include <fcntl.h>
28 #include <syslog.h>
29 #include <getopt.h>
30 #include <signal.h>
31 #include <time.h>
32 #include <sys/inotify.h>
33 #include <sys/poll.h>
34 #include <sys/stat.h>
35 #include <sys/types.h>
36
37 #include "udev.h"
38
39 static int adm_settle(struct udev *udev, int argc, char *argv[])
40 {
41 static const struct option options[] = {
42 { "seq-start", required_argument, NULL, 's' },
43 { "seq-end", required_argument, NULL, 'e' },
44 { "timeout", required_argument, NULL, 't' },
45 { "exit-if-exists", required_argument, NULL, 'E' },
46 { "quiet", no_argument, NULL, 'q' },
47 { "help", no_argument, NULL, 'h' },
48 {}
49 };
50 unsigned long long start_usec = now_usec();
51 unsigned long long start = 0;
52 unsigned long long end = 0;
53 int quiet = 0;
54 const char *exists = NULL;
55 unsigned int timeout = 120;
56 struct pollfd pfd[1];
57 struct udev_queue *udev_queue = NULL;
58 int rc = EXIT_FAILURE;
59
60 dbg(udev, "version %s\n", VERSION);
61
62 for (;;) {
63 int option;
64 int seconds;
65
66 option = getopt_long(argc, argv, "s:e:t:E:qh", options, NULL);
67 if (option == -1)
68 break;
69
70 switch (option) {
71 case 's':
72 start = strtoull(optarg, NULL, 0);
73 break;
74 case 'e':
75 end = strtoull(optarg, NULL, 0);
76 break;
77 case 't':
78 seconds = atoi(optarg);
79 if (seconds >= 0)
80 timeout = seconds;
81 else
82 fprintf(stderr, "invalid timeout value\n");
83 dbg(udev, "timeout=%i\n", timeout);
84 break;
85 case 'q':
86 quiet = 1;
87 break;
88 case 'E':
89 exists = optarg;
90 break;
91 case 'h':
92 printf("Usage: udevadm settle OPTIONS\n"
93 " --timeout=<seconds> maximum time to wait for events\n"
94 " --seq-start=<seqnum> first seqnum to wait for\n"
95 " --seq-end=<seqnum> last seqnum to wait for\n"
96 " --exit-if-exists=<file> stop waiting if file exists\n"
97 " --quiet do not print list after timeout\n"
98 " --help\n\n");
99 exit(EXIT_SUCCESS);
100 default:
101 exit(EXIT_FAILURE);
102 }
103 }
104
105 udev_queue = udev_queue_new(udev);
106 if (udev_queue == NULL)
107 exit(2);
108
109 if (start > 0) {
110 unsigned long long kernel_seq;
111
112 kernel_seq = udev_queue_get_kernel_seqnum(udev_queue);
113
114 /* unless specified, the last event is the current kernel seqnum */
115 if (end == 0)
116 end = udev_queue_get_kernel_seqnum(udev_queue);
117
118 if (start > end) {
119 err(udev, "seq-start larger than seq-end, ignoring\n");
120 start = 0;
121 end = 0;
122 }
123
124 if (start > kernel_seq || end > kernel_seq) {
125 err(udev, "seq-start or seq-end larger than current kernel value, ignoring\n");
126 start = 0;
127 end = 0;
128 }
129 info(udev, "start=%llu end=%llu current=%llu\n", start, end, kernel_seq);
130 } else {
131 if (end > 0) {
132 err(udev, "seq-end needs seq-start parameter, ignoring\n");
133 end = 0;
134 }
135 }
136
137 /* guarantee that the udev daemon isn't pre-processing */
138 if (getuid() == 0) {
139 struct udev_ctrl *uctrl;
140
141 uctrl = udev_ctrl_new(udev);
142 if (uctrl != NULL) {
143 if (udev_ctrl_send_ping(uctrl, timeout) < 0) {
144 info(udev, "no connection to daemon\n");
145 udev_ctrl_unref(uctrl);
146 rc = EXIT_SUCCESS;
147 goto out;
148 }
149 udev_ctrl_unref(uctrl);
150 }
151 }
152
153 pfd[0].events = POLLIN;
154 pfd[0].fd = inotify_init1(IN_CLOEXEC);
155 if (pfd[0].fd < 0) {
156 err(udev, "inotify_init failed: %m\n");
157 } else {
158 if (inotify_add_watch(pfd[0].fd, udev_get_run_path(udev), IN_MOVED_TO) < 0) {
159 err(udev, "watching '%s' failed\n", udev_get_run_path(udev));
160 close(pfd[0].fd);
161 pfd[0].fd = -1;
162 }
163 }
164
165 for (;;) {
166 struct stat statbuf;
167
168 if (exists != NULL && stat(exists, &statbuf) == 0) {
169 rc = EXIT_SUCCESS;
170 break;
171 }
172
173 if (start > 0) {
174 /* if asked for, wait for a specific sequence of events */
175 if (udev_queue_get_seqnum_sequence_is_finished(udev_queue, start, end) == 1) {
176 rc = EXIT_SUCCESS;
177 break;
178 }
179 } else {
180 /* exit if queue is empty */
181 if (udev_queue_get_queue_is_empty(udev_queue)) {
182 rc = EXIT_SUCCESS;
183 break;
184 }
185 }
186
187 if (pfd[0].fd >= 0) {
188 int delay;
189
190 if (exists != NULL || start > 0)
191 delay = 100;
192 else
193 delay = 1000;
194 /* wake up after delay, or immediately after the queue is rebuilt */
195 if (poll(pfd, 1, delay) > 0 && pfd[0].revents & POLLIN) {
196 char buf[sizeof(struct inotify_event) + PATH_MAX];
197
198 read(pfd[0].fd, buf, sizeof(buf));
199 }
200 } else {
201 sleep(1);
202 }
203
204 if (timeout > 0) {
205 unsigned long long age_usec;
206
207 age_usec = now_usec() - start_usec;
208 if (age_usec / (1000 * 1000) >= timeout) {
209 struct udev_list_entry *list_entry;
210
211 if (!quiet && udev_queue_get_queued_list_entry(udev_queue) != NULL) {
212 info(udev, "timeout waiting for udev queue\n");
213 printf("\nudevadm settle - timeout of %i seconds reached, the event queue contains:\n", timeout);
214 udev_list_entry_foreach(list_entry, udev_queue_get_queued_list_entry(udev_queue))
215 printf(" %s (%s)\n",
216 udev_list_entry_get_name(list_entry),
217 udev_list_entry_get_value(list_entry));
218 }
219
220 break;
221 }
222 }
223 }
224 out:
225 if (pfd[0].fd >= 0)
226 close(pfd[0].fd);
227 udev_queue_unref(udev_queue);
228 return rc;
229 }
230
231 const struct udevadm_cmd udevadm_settle = {
232 .name = "settle",
233 .cmd = adm_settle,
234 .help = "wait for the event queue to finish",
235 };
File src/udevadm-test-builtin.c added (mode: 100644) (index 0000000..3a49f7c)
1 /*
2 * Copyright (C) 2011 Kay Sievers <kay.sievers@vrfy.org>
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include <stdlib.h>
19 #include <stddef.h>
20 #include <string.h>
21 #include <stdio.h>
22 #include <unistd.h>
23 #include <errno.h>
24 #include <dirent.h>
25 #include <fcntl.h>
26 #include <syslog.h>
27 #include <getopt.h>
28 #include <signal.h>
29 #include <time.h>
30 #include <sys/inotify.h>
31 #include <sys/poll.h>
32 #include <sys/stat.h>
33 #include <sys/types.h>
34
35 #include "udev.h"
36
37 static void help(struct udev *udev)
38 {
39 fprintf(stderr, "\n");
40 fprintf(stderr, "Usage: udevadm builtin [--help] <command> <syspath>\n");
41 udev_builtin_list(udev);
42 fprintf(stderr, "\n");
43 }
44
45 static int adm_builtin(struct udev *udev, int argc, char *argv[])
46 {
47 static const struct option options[] = {
48 { "help", no_argument, NULL, 'h' },
49 {}
50 };
51 char *command = NULL;
52 char *syspath = NULL;
53 char filename[UTIL_PATH_SIZE];
54 struct udev_device *dev = NULL;
55 enum udev_builtin_cmd cmd;
56 int rc = EXIT_SUCCESS;
57
58 dbg(udev, "version %s\n", VERSION);
59
60 for (;;) {
61 int option;
62
63 option = getopt_long(argc, argv, "h", options, NULL);
64 if (option == -1)
65 break;
66
67 switch (option) {
68 case 'h':
69 help(udev);
70 goto out;
71 }
72 }
73
74 command = argv[optind++];
75 if (command == NULL) {
76 fprintf(stderr, "command missing\n");
77 help(udev);
78 rc = 2;
79 goto out;
80 }
81
82 syspath = argv[optind++];
83 if (syspath == NULL) {
84 fprintf(stderr, "syspath missing\n\n");
85 rc = 3;
86 goto out;
87 }
88
89 udev_builtin_init(udev);
90
91 cmd = udev_builtin_lookup(command);
92 if (cmd >= UDEV_BUILTIN_MAX) {
93 fprintf(stderr, "unknown command '%s'\n", command);
94 help(udev);
95 rc = 5;
96 goto out;
97 }
98
99 /* add /sys if needed */
100 if (strncmp(syspath, udev_get_sys_path(udev), strlen(udev_get_sys_path(udev))) != 0)
101 util_strscpyl(filename, sizeof(filename), udev_get_sys_path(udev), syspath, NULL);
102 else
103 util_strscpy(filename, sizeof(filename), syspath);
104 util_remove_trailing_chars(filename, '/');
105
106 dev = udev_device_new_from_syspath(udev, filename);
107 if (dev == NULL) {
108 fprintf(stderr, "unable to open device '%s'\n\n", filename);
109 rc = 4;
110 goto out;
111 }
112
113 if (udev_builtin_run(dev, cmd, command, true) < 0) {
114 fprintf(stderr, "error executing '%s'\n\n", command);
115 rc = 6;
116 }
117 out:
118 udev_device_unref(dev);
119 udev_builtin_exit(udev);
120 return rc;
121 }
122
123 const struct udevadm_cmd udevadm_test_builtin = {
124 .name = "test-builtin",
125 .cmd = adm_builtin,
126 .help = "test a built-in command",
127 .debug = true,
128 };
File src/udevadm-test.c added (mode: 100644) (index 0000000..6275cff)
1 /*
2 * Copyright (C) 2003-2004 Greg Kroah-Hartman <greg@kroah.com>
3 * Copyright (C) 2004-2008 Kay Sievers <kay.sievers@vrfy.org>
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include <stdlib.h>
20 #include <string.h>
21 #include <stdio.h>
22 #include <stddef.h>
23 #include <unistd.h>
24 #include <errno.h>
25 #include <ctype.h>
26 #include <fcntl.h>
27 #include <signal.h>
28 #include <syslog.h>
29 #include <getopt.h>
30 #include <sys/signalfd.h>
31
32 #include "udev.h"
33
34 static int adm_test(struct udev *udev, int argc, char *argv[])
35 {
36 int resolve_names = 1;
37 char filename[UTIL_PATH_SIZE];
38 const char *action = "add";
39 const char *syspath = NULL;
40 struct udev_event *event = NULL;
41 struct udev_device *dev = NULL;
42 struct udev_rules *rules = NULL;
43 struct udev_list_entry *entry;
44 sigset_t mask, sigmask_orig;
45 int err;
46 int rc = 0;
47
48 static const struct option options[] = {
49 { "action", required_argument, NULL, 'a' },
50 { "resolve-names", required_argument, NULL, 'N' },
51 { "help", no_argument, NULL, 'h' },
52 {}
53 };
54
55 info(udev, "version %s\n", VERSION);
56
57 for (;;) {
58 int option;
59
60 option = getopt_long(argc, argv, "a:s:N:fh", options, NULL);
61 if (option == -1)
62 break;
63
64 dbg(udev, "option '%c'\n", option);
65 switch (option) {
66 case 'a':
67 action = optarg;
68 break;
69 case 'N':
70 if (strcmp (optarg, "early") == 0) {
71 resolve_names = 1;
72 } else if (strcmp (optarg, "late") == 0) {
73 resolve_names = 0;
74 } else if (strcmp (optarg, "never") == 0) {
75 resolve_names = -1;
76 } else {
77 fprintf(stderr, "resolve-names must be early, late or never\n");
78 err(udev, "resolve-names must be early, late or never\n");
79 exit(EXIT_FAILURE);
80 }
81 break;
82 case 'h':
83 printf("Usage: udevadm test OPTIONS <syspath>\n"
84 " --action=<string> set action string\n"
85 " --help\n\n");
86 exit(EXIT_SUCCESS);
87 default:
88 exit(EXIT_FAILURE);
89 }
90 }
91 syspath = argv[optind];
92
93 if (syspath == NULL) {
94 fprintf(stderr, "syspath parameter missing\n");
95 rc = 2;
96 goto out;
97 }
98
99 printf("This program is for debugging only, it does not run any program,\n"
100 "specified by a RUN key. It may show incorrect results, because\n"
101 "some values may be different, or not available at a simulation run.\n"
102 "\n");
103
104 sigprocmask(SIG_SETMASK, NULL, &sigmask_orig);
105
106 udev_builtin_init(udev);
107
108 rules = udev_rules_new(udev, resolve_names);
109 if (rules == NULL) {
110 fprintf(stderr, "error reading rules\n");
111 rc = 3;
112 goto out;
113 }
114
115 /* add /sys if needed */
116 if (strncmp(syspath, udev_get_sys_path(udev), strlen(udev_get_sys_path(udev))) != 0)
117 util_strscpyl(filename, sizeof(filename), udev_get_sys_path(udev), syspath, NULL);
118 else
119 util_strscpy(filename, sizeof(filename), syspath);
120 util_remove_trailing_chars(filename, '/');
121
122 dev = udev_device_new_from_syspath(udev, filename);
123 if (dev == NULL) {
124 fprintf(stderr, "unable to open device '%s'\n", filename);
125 rc = 4;
126 goto out;
127 }
128
129 /* skip reading of db, but read kernel parameters */
130 udev_device_set_info_loaded(dev);
131 udev_device_read_uevent_file(dev);
132
133 udev_device_set_action(dev, action);
134 event = udev_event_new(dev);
135
136 sigfillset(&mask);
137 sigprocmask(SIG_SETMASK, &mask, &sigmask_orig);
138 event->fd_signal = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
139 if (event->fd_signal < 0) {
140 fprintf(stderr, "error creating signalfd\n");
141 rc = 5;
142 goto out;
143 }
144
145 err = udev_event_execute_rules(event, rules, &sigmask_orig);
146
147 udev_list_entry_foreach(entry, udev_device_get_properties_list_entry(dev))
148 printf("%s=%s\n", udev_list_entry_get_name(entry), udev_list_entry_get_value(entry));
149
150 if (err == 0) {
151 udev_list_entry_foreach(entry, udev_list_get_entry(&event->run_list)) {
152 char program[UTIL_PATH_SIZE];
153
154 udev_event_apply_format(event, udev_list_entry_get_name(entry), program, sizeof(program));
155 printf("run: '%s'\n", program);
156 }
157 }
158 out:
159 if (event != NULL && event->fd_signal >= 0)
160 close(event->fd_signal);
161 udev_event_unref(event);
162 udev_device_unref(dev);
163 udev_rules_unref(rules);
164 udev_builtin_exit(udev);
165 return rc;
166 }
167
168 const struct udevadm_cmd udevadm_test = {
169 .name = "test",
170 .cmd = adm_test,
171 .help = "test an event run",
172 .debug = true,
173 };
File src/udevadm-trigger.c added (mode: 100644) (index 0000000..3cce23d)
1 /*
2 * Copyright (C) 2008-2009 Kay Sievers <kay.sievers@vrfy.org>
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include <stdlib.h>
19 #include <stddef.h>
20 #include <string.h>
21 #include <stdio.h>
22 #include <unistd.h>
23 #include <getopt.h>
24 #include <errno.h>
25 #include <dirent.h>
26 #include <fcntl.h>
27 #include <syslog.h>
28 #include <fnmatch.h>
29 #include <sys/stat.h>
30 #include <sys/types.h>
31 #include <sys/socket.h>
32 #include <sys/un.h>
33
34 #include "udev.h"
35
36 static int verbose;
37 static int dry_run;
38
39 static void exec_list(struct udev_enumerate *udev_enumerate, const char *action)
40 {
41 struct udev *udev = udev_enumerate_get_udev(udev_enumerate);
42 struct udev_list_entry *entry;
43
44 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(udev_enumerate)) {
45 char filename[UTIL_PATH_SIZE];
46 int fd;
47
48 if (verbose)
49 printf("%s\n", udev_list_entry_get_name(entry));
50 if (dry_run)
51 continue;
52 util_strscpyl(filename, sizeof(filename), udev_list_entry_get_name(entry), "/uevent", NULL);
53 fd = open(filename, O_WRONLY);
54 if (fd < 0) {
55 dbg(udev, "error on opening %s: %m\n", filename);
56 continue;
57 }
58 if (write(fd, action, strlen(action)) < 0)
59 info(udev, "error writing '%s' to '%s': %m\n", action, filename);
60 close(fd);
61 }
62 }
63
64 static const char *keyval(const char *str, const char **val, char *buf, size_t size)
65 {
66 char *pos;
67
68 util_strscpy(buf, size,str);
69 pos = strchr(buf, '=');
70 if (pos != NULL) {
71 pos[0] = 0;
72 pos++;
73 }
74 *val = pos;
75 return buf;
76 }
77
78 static int adm_trigger(struct udev *udev, int argc, char *argv[])
79 {
80 static const struct option options[] = {
81 { "verbose", no_argument, NULL, 'v' },
82 { "dry-run", no_argument, NULL, 'n' },
83 { "type", required_argument, NULL, 't' },
84 { "action", required_argument, NULL, 'c' },
85 { "subsystem-match", required_argument, NULL, 's' },
86 { "subsystem-nomatch", required_argument, NULL, 'S' },
87 { "attr-match", required_argument, NULL, 'a' },
88 { "attr-nomatch", required_argument, NULL, 'A' },
89 { "property-match", required_argument, NULL, 'p' },
90 { "tag-match", required_argument, NULL, 'g' },
91 { "sysname-match", required_argument, NULL, 'y' },
92 { "parent-match", required_argument, NULL, 'b' },
93 { "help", no_argument, NULL, 'h' },
94 {}
95 };
96 enum {
97 TYPE_DEVICES,
98 TYPE_SUBSYSTEMS,
99 } device_type = TYPE_DEVICES;
100 const char *action = "change";
101 struct udev_enumerate *udev_enumerate;
102 int rc = 0;
103
104 dbg(udev, "version %s\n", VERSION);
105 udev_enumerate = udev_enumerate_new(udev);
106 if (udev_enumerate == NULL) {
107 rc = 1;
108 goto exit;
109 }
110
111 for (;;) {
112 int option;
113 const char *key;
114 const char *val;
115 char buf[UTIL_PATH_SIZE];
116
117 option = getopt_long(argc, argv, "vng:o:t:hc:p:s:S:a:A:y:b:", options, NULL);
118 if (option == -1)
119 break;
120
121 switch (option) {
122 case 'v':
123 verbose = 1;
124 break;
125 case 'n':
126 dry_run = 1;
127 break;
128 case 't':
129 if (strcmp(optarg, "devices") == 0) {
130 device_type = TYPE_DEVICES;
131 } else if (strcmp(optarg, "subsystems") == 0) {
132 device_type = TYPE_SUBSYSTEMS;
133 } else {
134 err(udev, "unknown type --type=%s\n", optarg);
135 rc = 2;
136 goto exit;
137 }
138 break;
139 case 'c':
140 action = optarg;
141 break;
142 case 's':
143 udev_enumerate_add_match_subsystem(udev_enumerate, optarg);
144 break;
145 case 'S':
146 udev_enumerate_add_nomatch_subsystem(udev_enumerate, optarg);
147 break;
148 case 'a':
149 key = keyval(optarg, &val, buf, sizeof(buf));
150 udev_enumerate_add_match_sysattr(udev_enumerate, key, val);
151 break;
152 case 'A':
153 key = keyval(optarg, &val, buf, sizeof(buf));
154 udev_enumerate_add_nomatch_sysattr(udev_enumerate, key, val);
155 break;
156 case 'p':
157 key = keyval(optarg, &val, buf, sizeof(buf));
158 udev_enumerate_add_match_property(udev_enumerate, key, val);
159 break;
160 case 'g':
161 udev_enumerate_add_match_tag(udev_enumerate, optarg);
162 break;
163 case 'y':
164 udev_enumerate_add_match_sysname(udev_enumerate, optarg);
165 break;
166 case 'b': {
167 char path[UTIL_PATH_SIZE];
168 struct udev_device *dev;
169
170 /* add sys dir if needed */
171 if (strncmp(optarg, udev_get_sys_path(udev), strlen(udev_get_sys_path(udev))) != 0)
172 util_strscpyl(path, sizeof(path), udev_get_sys_path(udev), optarg, NULL);
173 else
174 util_strscpy(path, sizeof(path), optarg);
175 util_remove_trailing_chars(path, '/');
176 dev = udev_device_new_from_syspath(udev, path);
177 if (dev == NULL) {
178 err(udev, "unable to open the device '%s'\n", optarg);
179 rc = 2;
180 goto exit;
181 }
182 udev_enumerate_add_match_parent(udev_enumerate, dev);
183 /* drop reference immediately, enumerate pins the device as long as needed */
184 udev_device_unref(dev);
185 break;
186 }
187 case 'h':
188 printf("Usage: udevadm trigger OPTIONS\n"
189 " --verbose print the list of devices while running\n"
190 " --dry-run do not actually trigger the events\n"
191 " --type= type of events to trigger\n"
192 " devices sys devices (default)\n"
193 " subsystems sys subsystems and drivers\n"
194 " --action=<action> event action value, default is \"change\"\n"
195 " --subsystem-match=<subsystem> trigger devices from a matching subsystem\n"
196 " --subsystem-nomatch=<subsystem> exclude devices from a matching subsystem\n"
197 " --attr-match=<file[=<value>]> trigger devices with a matching attribute\n"
198 " --attr-nomatch=<file[=<value>]> exclude devices with a matching attribute\n"
199 " --property-match=<key>=<value> trigger devices with a matching property\n"
200 " --tag-match=<key>=<value> trigger devices with a matching property\n"
201 " --sysname-match=<name> trigger devices with a matching name\n"
202 " --parent-match=<name> trigger devices with that parent device\n"
203 " --help\n\n");
204 goto exit;
205 default:
206 rc = 1;
207 goto exit;
208 }
209 }
210
211 switch (device_type) {
212 case TYPE_SUBSYSTEMS:
213 udev_enumerate_scan_subsystems(udev_enumerate);
214 exec_list(udev_enumerate, action);
215 goto exit;
216 case TYPE_DEVICES:
217 udev_enumerate_scan_devices(udev_enumerate);
218 exec_list(udev_enumerate, action);
219 goto exit;
220 default:
221 goto exit;
222 }
223 exit:
224 udev_enumerate_unref(udev_enumerate);
225 return rc;
226 }
227
228 const struct udevadm_cmd udevadm_trigger = {
229 .name = "trigger",
230 .cmd = adm_trigger,
231 .help = "request events from the kernel",
232 };
File src/udevadm.c added (mode: 100644) (index 0000000..224ece0)
1 /*
2 * Copyright (C) 2007-2009 Kay Sievers <kay.sievers@vrfy.org>
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include <unistd.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <stddef.h>
22 #include <string.h>
23 #include <errno.h>
24 #include <getopt.h>
25
26 #include "udev.h"
27
28 static bool debug;
29
30 void udev_main_log(struct udev *udev, int priority,
31 const char *file, int line, const char *fn,
32 const char *format, va_list args)
33 {
34 if (debug) {
35 fprintf(stderr, "%s: ", fn);
36 vfprintf(stderr, format, args);
37 } else {
38 va_list args2;
39
40 va_copy(args2, args);
41 vfprintf(stderr, format, args2);
42 va_end(args2);
43 vsyslog(priority, format, args);
44 }
45 }
46
47 static int adm_version(struct udev *udev, int argc, char *argv[])
48 {
49 printf("%s\n", VERSION);
50 return 0;
51 }
52 static const struct udevadm_cmd udevadm_version = {
53 .name = "version",
54 .cmd = adm_version,
55 };
56
57 static int adm_help(struct udev *udev, int argc, char *argv[]);
58 static const struct udevadm_cmd udevadm_help = {
59 .name = "help",
60 .cmd = adm_help,
61 };
62
63 static const struct udevadm_cmd *udevadm_cmds[] = {
64 &udevadm_info,
65 &udevadm_trigger,
66 &udevadm_settle,
67 &udevadm_control,
68 &udevadm_monitor,
69 &udevadm_test,
70 &udevadm_test_builtin,
71 &udevadm_version,
72 &udevadm_help,
73 };
74
75 static int adm_help(struct udev *udev, int argc, char *argv[])
76 {
77 unsigned int i;
78
79 fprintf(stderr, "Usage: udevadm [--help] [--version] [--debug] COMMAND [COMMAND OPTIONS]\n");
80 for (i = 0; i < ARRAY_SIZE(udevadm_cmds); i++)
81 if (udevadm_cmds[i]->help != NULL)
82 printf(" %-12s %s\n", udevadm_cmds[i]->name, udevadm_cmds[i]->help);
83 fprintf(stderr, "\n");
84 return 0;
85 }
86
87 static int run_command(struct udev *udev, const struct udevadm_cmd *cmd, int argc, char *argv[])
88 {
89 if (cmd->debug) {
90 debug = true;
91 if (udev_get_log_priority(udev) < LOG_INFO)
92 udev_set_log_priority(udev, LOG_INFO);
93 }
94 info(udev, "calling: %s\n", cmd->name);
95 return cmd->cmd(udev, argc, argv);
96 }
97
98 int main(int argc, char *argv[])
99 {
100 struct udev *udev;
101 static const struct option options[] = {
102 { "debug", no_argument, NULL, 'd' },
103 { "help", no_argument, NULL, 'h' },
104 { "version", no_argument, NULL, 'V' },
105 {}
106 };
107 const char *command;
108 unsigned int i;
109 int rc = 1;
110
111 udev = udev_new();
112 if (udev == NULL)
113 goto out;
114
115 udev_log_init("udevadm");
116 udev_set_log_fn(udev, udev_main_log);
117 udev_selinux_init(udev);
118
119 for (;;) {
120 int option;
121
122 option = getopt_long(argc, argv, "+dhV", options, NULL);
123 if (option == -1)
124 break;
125
126 switch (option) {
127 case 'd':
128 debug = true;
129 if (udev_get_log_priority(udev) < LOG_INFO)
130 udev_set_log_priority(udev, LOG_INFO);
131 break;
132 case 'h':
133 rc = adm_help(udev, argc, argv);
134 goto out;
135 case 'V':
136 rc = adm_version(udev, argc, argv);
137 goto out;
138 default:
139 goto out;
140 }
141 }
142 command = argv[optind];
143
144 info(udev, "runtime dir '%s'\n", udev_get_run_path(udev));
145
146 if (command != NULL)
147 for (i = 0; i < ARRAY_SIZE(udevadm_cmds); i++) {
148 if (strcmp(udevadm_cmds[i]->name, command) == 0) {
149 argc -= optind;
150 argv += optind;
151 optind = 0;
152 rc = run_command(udev, udevadm_cmds[i], argc, argv);
153 goto out;
154 }
155 }
156
157 fprintf(stderr, "missing or unknown command\n\n");
158 adm_help(udev, argc, argv);
159 rc = 2;
160 out:
161 udev_selinux_exit(udev);
162 udev_unref(udev);
163 udev_log_close();
164 return rc;
165 }
File src/udevadm.xml added (mode: 100644) (index 0000000..455ce80)
1 <?xml version='1.0'?>
2 <?xml-stylesheet type="text/xsl" href="http://docbook.sourceforge.net/release/xsl/current/xhtml/docbook.xsl"?>
3 <!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
4 "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
5
6 <refentry id="udevadm">
7 <refentryinfo>
8 <title>udevadm</title>
9 <productname>udev</productname>
10 </refentryinfo>
11
12 <refmeta>
13 <refentrytitle>udevadm</refentrytitle>
14 <manvolnum>8</manvolnum>
15 <refmiscinfo class="version"></refmiscinfo>
16 </refmeta>
17
18 <refnamediv>
19 <refname>udevadm</refname><refpurpose>udev management tool</refpurpose>
20 </refnamediv>
21
22 <refsynopsisdiv>
23 <cmdsynopsis>
24 <command>udevadm</command>
25 <arg><option>--debug</option></arg>
26 <arg><option>--version</option></arg>
27 <arg><option>--help</option></arg>
28 </cmdsynopsis>
29 <cmdsynopsis>
30 <command>udevadm info <replaceable>options</replaceable></command>
31 </cmdsynopsis>
32 <cmdsynopsis>
33 <command>udevadm trigger <optional>options</optional></command>
34 </cmdsynopsis>
35 <cmdsynopsis>
36 <command>udevadm settle <optional>options</optional></command>
37 </cmdsynopsis>
38 <cmdsynopsis>
39 <command>udevadm control <replaceable>command</replaceable></command>
40 </cmdsynopsis>
41 <cmdsynopsis>
42 <command>udevadm monitor <optional>options</optional></command>
43 </cmdsynopsis>
44 <cmdsynopsis>
45 <command>udevadm test <optional>options</optional> <replaceable>devpath</replaceable></command>
46 </cmdsynopsis>
47 <cmdsynopsis>
48 <command>udevadm test-builtin <optional>options</optional> <replaceable>command</replaceable> <replaceable>devpath</replaceable></command>
49 </cmdsynopsis>
50 </refsynopsisdiv>
51
52 <refsect1><title>Description</title>
53 <para>udevadm expects a command and command specific options. It
54 controls the runtime behavior of udev, requests kernel events,
55 manages the event queue, and provides simple debugging mechanisms.</para>
56 </refsect1>
57
58 <refsect1><title>OPTIONS</title>
59 <variablelist>
60 <varlistentry>
61 <term><option>--debug</option></term>
62 <listitem>
63 <para>Print debug messages to stderr.</para>
64 </listitem>
65 </varlistentry>
66 <varlistentry>
67 <term><option>--version</option></term>
68 <listitem>
69 <para>Print version number.</para>
70 </listitem>
71 </varlistentry>
72 <varlistentry>
73 <term><option>--help</option></term>
74 <listitem>
75 <para>Print help text.</para>
76 </listitem>
77 </varlistentry>
78 </variablelist>
79
80 <refsect2><title>udevadm info <replaceable>options</replaceable></title>
81 <para>Queries the udev database for device information
82 stored in the udev database. It can also query the properties
83 of a device from its sysfs representation to help creating udev
84 rules that match this device.</para>
85 <variablelist>
86 <varlistentry>
87 <term><option>--query=<replaceable>type</replaceable></option></term>
88 <listitem>
89 <para>Query the database for specified type of device data. It needs the
90 <option>--path</option> or <option>--name</option> to identify the specified
91 device. Valid queries are:
92 <command>name</command>, <command>symlink</command>, <command>path</command>,
93 <command>property</command>, <command>all</command>.</para>
94 </listitem>
95 </varlistentry>
96 <varlistentry>
97 <term><option>--path=<replaceable>devpath</replaceable></option></term>
98 <listitem>
99 <para>The devpath of the device to query.</para>
100 </listitem>
101 </varlistentry>
102 <varlistentry>
103 <term><option>--name=<replaceable>file</replaceable></option></term>
104 <listitem>
105 <para>The name of the device node or a symlink to query</para>
106 </listitem>
107 </varlistentry>
108 <varlistentry>
109 <term><option>--root</option></term>
110 <listitem>
111 <para>The udev root directory: <filename>/dev</filename>. If used in conjunction
112 with a <command>name</command> or <command>symlink</command> query, the
113 query returns the absolute path including the root directory.</para>
114 </listitem>
115 </varlistentry>
116 <varlistentry>
117 <term><option>--run</option></term>
118 <listitem>
119 <para>The udev runtime directory: <filename>/run/udev</filename>.</para>
120 </listitem>
121 </varlistentry>
122 <varlistentry>
123 <term><option>--attribute-walk</option></term>
124 <listitem>
125 <para>Print all sysfs properties of the specified device that can be used
126 in udev rules to match the specified device. It prints all devices
127 along the chain, up to the root of sysfs that can be used in udev rules.</para>
128 </listitem>
129 </varlistentry>
130 <varlistentry>
131 <term><option>--export</option></term>
132 <listitem>
133 <para>Print output as key/value pairs. Values are enclosed in single quotes.</para>
134 </listitem>
135 </varlistentry>
136 <varlistentry>
137 <term><option>--export-prefix=<replaceable>name</replaceable></option></term>
138 <listitem>
139 <para>Add a prefix to the key name of exported values.</para>
140 </listitem>
141 </varlistentry>
142 <varlistentry>
143 <term><option>--device-id-of-file=<replaceable>file</replaceable></option></term>
144 <listitem>
145 <para>Print major/minor numbers of the underlying device, where the file
146 lives on.</para>
147 </listitem>
148 </varlistentry>
149 <varlistentry>
150 <term><option>--export-db</option></term>
151 <listitem>
152 <para>Export the content of the udev database.</para>
153 </listitem>
154 </varlistentry>
155 <varlistentry>
156 <term><option>--cleanup-db</option></term>
157 <listitem>
158 <para>Cleanup the udev database.</para>
159 </listitem>
160 </varlistentry>
161 <varlistentry>
162 <term><option>--version</option></term>
163 <listitem>
164 <para>Print version.</para>
165 </listitem>
166 </varlistentry>
167 <varlistentry>
168 <term><option>--help</option></term>
169 <listitem>
170 <para>Print help text.</para>
171 </listitem>
172 </varlistentry>
173 </variablelist>
174 </refsect2>
175
176 <refsect2><title>udevadm trigger <optional>options</optional></title>
177 <para>Request device events from the kernel. Primarily used to replay events at system coldplug time.</para>
178 <variablelist>
179 <varlistentry>
180 <term><option>--verbose</option></term>
181 <listitem>
182 <para>Print the list of devices which will be triggered.</para>
183 </listitem>
184 </varlistentry>
185 <varlistentry>
186 <term><option>--dry-run</option></term>
187 <listitem>
188 <para>Do not actually trigger the event.</para>
189 </listitem>
190 </varlistentry>
191 <varlistentry>
192 <term><option>--type=<replaceable>type</replaceable></option></term>
193 <listitem>
194 <para>Trigger a specific type of devices. Valid types are:
195 <command>devices</command>, <command>subsystems</command>.
196 The default value is <command>devices</command>.</para>
197 </listitem>
198 </varlistentry>
199 <varlistentry>
200 <term><option>--action=<replaceable>action</replaceable></option></term>
201 <listitem>
202 <para>Type of event to be triggered. The default value is <command>change</command>.</para>
203 </listitem>
204 </varlistentry>
205 <varlistentry>
206 <term><option>--subsystem-match=<replaceable>subsystem</replaceable></option></term>
207 <listitem>
208 <para>Trigger events for devices which belong to a matching subsystem. This option
209 can be specified multiple times and supports shell style pattern matching.</para>
210 </listitem>
211 </varlistentry>
212 <varlistentry>
213 <term><option>--subsystem-nomatch=<replaceable>subsystem</replaceable></option></term>
214 <listitem>
215 <para>Do not trigger events for devices which belong to a matching subsystem. This option
216 can be specified multiple times and supports shell style pattern matching.</para>
217 </listitem>
218 </varlistentry>
219 <varlistentry>
220 <term><option>--attr-match=<replaceable>attribute</replaceable>=<replaceable>value</replaceable></option></term>
221 <listitem>
222 <para>Trigger events for devices with a matching sysfs attribute. If a value is specified
223 along with the attribute name, the content of the attribute is matched against the given
224 value using shell style pattern matching. If no value is specified, the existence of the
225 sysfs attribute is checked. This option can be specified multiple times.</para>
226 </listitem>
227 </varlistentry>
228 <varlistentry>
229 <term><option>--attr-nomatch=<replaceable>attribute</replaceable>=<replaceable>value</replaceable></option></term>
230 <listitem>
231 <para>Do not trigger events for devices with a matching sysfs attribute. If a value is
232 specified along with the attribute name, the content of the attribute is matched against
233 the given value using shell style pattern matching. If no value is specified, the existence
234 of the sysfs attribute is checked. This option can be specified multiple times.</para>
235 </listitem>
236 </varlistentry>
237 <varlistentry>
238 <term><option>--property-match=<replaceable>property</replaceable>=<replaceable>value</replaceable></option></term>
239 <listitem>
240 <para>Trigger events for devices with a matching property value. This option can be
241 specified multiple times and supports shell style pattern matching.</para>
242 </listitem>
243 </varlistentry>
244 <varlistentry>
245 <term><option>--tag-match=<replaceable>property</replaceable></option></term>
246 <listitem>
247 <para>Trigger events for devices with a matching tag. This option can be
248 specified multiple times.</para>
249 </listitem>
250 </varlistentry>
251 <varlistentry>
252 <term><option>--sysname-match=<replaceable>name</replaceable></option></term>
253 <listitem>
254 <para>Trigger events for devices with a matching sys device name. This option can be
255 specified multiple times and supports shell style pattern matching.</para>
256 </listitem>
257 </varlistentry>
258 <varlistentry>
259 <term><option>--parent-match=<replaceable>syspath</replaceable></option></term>
260 <listitem>
261 <para>Trigger events for all children of a given device.</para>
262 </listitem>
263 </varlistentry>
264 </variablelist>
265 </refsect2>
266
267 <refsect2><title>udevadm settle <optional>options</optional></title>
268 <para>Watches the udev event queue, and exits if all current events are handled.</para>
269 <variablelist>
270 <varlistentry>
271 <term><option>--timeout=<replaceable>seconds</replaceable></option></term>
272 <listitem>
273 <para>Maximum number of seconds to wait for the event queue to become empty.
274 The default value is 120 seconds. A value of 0 will check if the queue is empty
275 and always return immediately.</para>
276 </listitem>
277 </varlistentry>
278 <varlistentry>
279 <term><option>--seq-start=<replaceable>seqnum</replaceable></option></term>
280 <listitem>
281 <para>Wait only for events after the given sequence number.</para>
282 </listitem>
283 </varlistentry>
284 <varlistentry>
285 <term><option>--seq-end=<replaceable>seqnum</replaceable></option></term>
286 <listitem>
287 <para>Wait only for events before the given sequence number.</para>
288 </listitem>
289 </varlistentry>
290 <varlistentry>
291 <term><option>--exit-if-exists=<replaceable>file</replaceable></option></term>
292 <listitem>
293 <para>Stop waiting if file exists.</para>
294 </listitem>
295 </varlistentry>
296 <varlistentry>
297 <term><option>--quiet</option></term>
298 <listitem>
299 <para>Do not print any output, like the remaining queue entries when reaching the timeout.</para>
300 </listitem>
301 </varlistentry>
302 <varlistentry>
303 <term><option>--help</option></term>
304 <listitem>
305 <para>Print help text.</para>
306 </listitem>
307 </varlistentry>
308 </variablelist>
309 </refsect2>
310
311 <refsect2><title>udevadm control <replaceable>command</replaceable></title>
312 <para>Modify the internal state of the running udev daemon.</para>
313 <variablelist>
314 <varlistentry>
315 <term><option>--exit</option></term>
316 <listitem>
317 <para>Signal and wait for udevd to exit.</para>
318 </listitem>
319 </varlistentry>
320 <varlistentry>
321 <term><option>--log-priority=<replaceable>value</replaceable></option></term>
322 <listitem>
323 <para>Set the internal log level of udevd. Valid values are the numerical
324 syslog priorities or their textual representations: <option>err</option>,
325 <option>info</option> and <option>debug</option>.</para>
326 </listitem>
327 </varlistentry>
328 <varlistentry>
329 <term><option>--stop-exec-queue</option></term>
330 <listitem>
331 <para>Signal udevd to stop executing new events. Incoming events
332 will be queued.</para>
333 </listitem>
334 </varlistentry>
335 <varlistentry>
336 <term><option>--start-exec-queue</option></term>
337 <listitem>
338 <para>Signal udevd to enable the execution of events.</para>
339 </listitem>
340 </varlistentry>
341 <varlistentry>
342 <term><option>--reload</option></term>
343 <listitem>
344 <para>Signal udevd to reload the rules files and other databases like the kernel
345 module index. Reloading rules and databases does not apply any changes to already
346 existing devices; the new configuration will only be applied to new events.</para>
347 </listitem>
348 </varlistentry>
349 <varlistentry>
350 <term><option>--property=<replaceable>KEY</replaceable>=<replaceable>value</replaceable></option></term>
351 <listitem>
352 <para>Set a global property for all events.</para>
353 </listitem>
354 </varlistentry>
355 <varlistentry>
356 <term><option>--children-max=</option><replaceable>value</replaceable></term>
357 <listitem>
358 <para>Set the maximum number of events, udevd will handle at the
359 same time.</para>
360 </listitem>
361 </varlistentry>
362 <varlistentry>
363 <term><option>--timeout=</option><replaceable>seconds</replaceable></term>
364 <listitem>
365 <para>The maximum number seconds to wait for a reply from udevd.</para>
366 </listitem>
367 </varlistentry>
368 <varlistentry>
369 <term><option>--help</option></term>
370 <listitem>
371 <para>Print help text.</para>
372 </listitem>
373 </varlistentry>
374 </variablelist>
375 </refsect2>
376
377 <refsect2><title>udevadm monitor <optional>options</optional></title>
378 <para>Listens to the kernel uevents and events sent out by a udev rule
379 and prints the devpath of the event to the console. It can be used to analyze the
380 event timing, by comparing the timestamps of the kernel uevent and the udev event.
381 </para>
382 <variablelist>
383 <varlistentry>
384 <term><option>--kernel</option></term>
385 <listitem>
386 <para>Print the kernel uevents.</para>
387 </listitem>
388 </varlistentry>
389 <varlistentry>
390 <term><option>--udev</option></term>
391 <listitem>
392 <para>Print the udev event after the rule processing.</para>
393 </listitem>
394 </varlistentry>
395 <varlistentry>
396 <term><option>--property</option></term>
397 <listitem>
398 <para>Also print the properties of the event.</para>
399 </listitem>
400 </varlistentry>
401 <varlistentry>
402 <term><option>--subsystem-match=<replaceable>string[/string]</replaceable></option></term>
403 <listitem>
404 <para>Filter events by subsystem[/devtype]. Only udev events with a matching subsystem value will pass.</para>
405 </listitem>
406 </varlistentry>
407 <varlistentry>
408 <term><option>--tag-match=<replaceable>string</replaceable></option></term>
409 <listitem>
410 <para>Filter events by property. Only udev events with a given tag attached will pass.</para>
411 </listitem>
412 </varlistentry>
413 <varlistentry>
414 <term><option>--help</option></term>
415 <listitem>
416 <para>Print help text.</para>
417 </listitem>
418 </varlistentry>
419 </variablelist>
420 </refsect2>
421
422 <refsect2><title>udevadm test <optional>options</optional> <replaceable>devpath</replaceable></title>
423 <para>Simulate a udev event run for the given device, and print debug output.</para>
424 <variablelist>
425 <varlistentry>
426 <term><option>--action=<replaceable>string</replaceable></option></term>
427 <listitem>
428 <para>The action string.</para>
429 </listitem>
430 </varlistentry>
431 <varlistentry>
432 <term><option>--subsystem=<replaceable>string</replaceable></option></term>
433 <listitem>
434 <para>The subsystem string.</para>
435 </listitem>
436 </varlistentry>
437 <varlistentry>
438 <term><option>--help</option></term>
439 <listitem>
440 <para>Print help text.</para>
441 </listitem>
442 </varlistentry>
443 </variablelist>
444 </refsect2>
445
446 <refsect2><title>udevadm test-builtin <optional>options</optional> <replaceable>command</replaceable> <replaceable>devpath</replaceable></title>
447 <para>Run a built-in command for the given device, and print debug output.</para>
448 <variablelist>
449 <varlistentry>
450 <term><option>--help</option></term>
451 <listitem>
452 <para>Print help text.</para>
453 </listitem>
454 </varlistentry>
455 </variablelist>
456 </refsect2>
457 </refsect1>
458
459 <refsect1><title>Author</title>
460 <para>Written by Kay Sievers <email>kay.sievers@vrfy.org</email>.</para>
461 </refsect1>
462
463 <refsect1>
464 <title>See Also</title>
465 <para><citerefentry>
466 <refentrytitle>udev</refentrytitle><manvolnum>7</manvolnum>
467 </citerefentry>
468 <citerefentry>
469 <refentrytitle>udevd</refentrytitle><manvolnum>8</manvolnum>
470 </citerefentry></para>
471 </refsect1>
472 </refentry>
File src/udevd.c added (mode: 100644) (index 0000000..fde4519)
1 /*
2 * Copyright (C) 2004-2011 Kay Sievers <kay.sievers@vrfy.org>
3 * Copyright (C) 2004 Chris Friesen <chris_friesen@sympatico.ca>
4 * Copyright (C) 2009 Canonical Ltd.
5 * Copyright (C) 2009 Scott James Remnant <scott@netsplit.com>
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include <stddef.h>
22 #include <signal.h>
23 #include <unistd.h>
24 #include <errno.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <stdbool.h>
28 #include <string.h>
29 #include <ctype.h>
30 #include <fcntl.h>
31 #include <time.h>
32 #include <getopt.h>
33 #include <dirent.h>
34 #include <sys/time.h>
35 #include <sys/prctl.h>
36 #include <sys/socket.h>
37 #include <sys/un.h>
38 #include <sys/signalfd.h>
39 #include <sys/epoll.h>
40 #include <sys/poll.h>
41 #include <sys/wait.h>
42 #include <sys/stat.h>
43 #include <sys/ioctl.h>
44 #include <sys/inotify.h>
45 #include <sys/utsname.h>
46
47 #include "udev.h"
48
49 static bool debug;
50
51 void udev_main_log(struct udev *udev, int priority,
52 const char *file, int line, const char *fn,
53 const char *format, va_list args)
54 {
55 if (debug) {
56 char buf[1024];
57 struct timespec ts;
58
59 vsnprintf(buf, sizeof(buf), format, args);
60 clock_gettime(CLOCK_MONOTONIC, &ts);
61 fprintf(stderr, "[%llu.%06u] [%u] %s: %s",
62 (unsigned long long) ts.tv_sec, (unsigned int) ts.tv_nsec/1000,
63 (int) getpid(), fn, buf);
64 } else {
65 vsyslog(priority, format, args);
66 }
67 }
68
69 static struct udev_rules *rules;
70 static struct udev_queue_export *udev_queue_export;
71 static struct udev_ctrl *udev_ctrl;
72 static struct udev_monitor *monitor;
73 static int worker_watch[2] = { -1, -1 };
74 static int fd_signal = -1;
75 static int fd_ep = -1;
76 static int fd_inotify = -1;
77 static bool stop_exec_queue;
78 static bool reload;
79 static int children;
80 static int children_max;
81 static int exec_delay;
82 static sigset_t sigmask_orig;
83 static UDEV_LIST(event_list);
84 static UDEV_LIST(worker_list);
85 static bool udev_exit;
86
87 enum event_state {
88 EVENT_UNDEF,
89 EVENT_QUEUED,
90 EVENT_RUNNING,
91 };
92
93 struct event {
94 struct udev_list_node node;
95 struct udev *udev;
96 struct udev_device *dev;
97 enum event_state state;
98 int exitcode;
99 unsigned long long int delaying_seqnum;
100 unsigned long long int seqnum;
101 const char *devpath;
102 size_t devpath_len;
103 const char *devpath_old;
104 dev_t devnum;
105 bool is_block;
106 int ifindex;
107 };
108
109 static struct event *node_to_event(struct udev_list_node *node)
110 {
111 char *event;
112
113 event = (char *)node;
114 event -= offsetof(struct event, node);
115 return (struct event *)event;
116 }
117
118 static void event_queue_cleanup(struct udev *udev, enum event_state type);
119
120 enum worker_state {
121 WORKER_UNDEF,
122 WORKER_RUNNING,
123 WORKER_IDLE,
124 WORKER_KILLED,
125 };
126
127 struct worker {
128 struct udev_list_node node;
129 struct udev *udev;
130 int refcount;
131 pid_t pid;
132 struct udev_monitor *monitor;
133 enum worker_state state;
134 struct event *event;
135 unsigned long long event_start_usec;
136 };
137
138 /* passed from worker to main process */
139 struct worker_message {
140 pid_t pid;
141 int exitcode;
142 };
143
144 static struct worker *node_to_worker(struct udev_list_node *node)
145 {
146 char *worker;
147
148 worker = (char *)node;
149 worker -= offsetof(struct worker, node);
150 return (struct worker *)worker;
151 }
152
153 static void event_queue_delete(struct event *event, bool export)
154 {
155 udev_list_node_remove(&event->node);
156
157 if (export) {
158 udev_queue_export_device_finished(udev_queue_export, event->dev);
159 info(event->udev, "seq %llu done with %i\n", udev_device_get_seqnum(event->dev), event->exitcode);
160 }
161 udev_device_unref(event->dev);
162 free(event);
163 }
164
165 static struct worker *worker_ref(struct worker *worker)
166 {
167 worker->refcount++;
168 return worker;
169 }
170
171 static void worker_cleanup(struct worker *worker)
172 {
173 udev_list_node_remove(&worker->node);
174 udev_monitor_unref(worker->monitor);
175 children--;
176 free(worker);
177 }
178
179 static void worker_unref(struct worker *worker)
180 {
181 worker->refcount--;
182 if (worker->refcount > 0)
183 return;
184 info(worker->udev, "worker [%u] cleaned up\n", worker->pid);
185 worker_cleanup(worker);
186 }
187
188 static void worker_list_cleanup(struct udev *udev)
189 {
190 struct udev_list_node *loop, *tmp;
191
192 udev_list_node_foreach_safe(loop, tmp, &worker_list) {
193 struct worker *worker = node_to_worker(loop);
194
195 worker_cleanup(worker);
196 }
197 }
198
199 static void worker_new(struct event *event)
200 {
201 struct udev *udev = event->udev;
202 struct worker *worker;
203 struct udev_monitor *worker_monitor;
204 pid_t pid;
205
206 /* listen for new events */
207 worker_monitor = udev_monitor_new_from_netlink(udev, NULL);
208 if (worker_monitor == NULL)
209 return;
210 /* allow the main daemon netlink address to send devices to the worker */
211 udev_monitor_allow_unicast_sender(worker_monitor, monitor);
212 udev_monitor_enable_receiving(worker_monitor);
213
214 worker = calloc(1, sizeof(struct worker));
215 if (worker == NULL) {
216 udev_monitor_unref(worker_monitor);
217 return;
218 }
219 /* worker + event reference */
220 worker->refcount = 2;
221 worker->udev = udev;
222
223 pid = fork();
224 switch (pid) {
225 case 0: {
226 struct udev_device *dev = NULL;
227 int fd_monitor;
228 struct epoll_event ep_signal, ep_monitor;
229 sigset_t mask;
230 int rc = EXIT_SUCCESS;
231
232 /* take initial device from queue */
233 dev = event->dev;
234 event->dev = NULL;
235
236 free(worker);
237 worker_list_cleanup(udev);
238 event_queue_cleanup(udev, EVENT_UNDEF);
239 udev_queue_export_unref(udev_queue_export);
240 udev_monitor_unref(monitor);
241 udev_ctrl_unref(udev_ctrl);
242 close(fd_signal);
243 close(fd_ep);
244 close(worker_watch[READ_END]);
245
246 sigfillset(&mask);
247 fd_signal = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
248 if (fd_signal < 0) {
249 err(udev, "error creating signalfd %m\n");
250 rc = 2;
251 goto out;
252 }
253
254 fd_ep = epoll_create1(EPOLL_CLOEXEC);
255 if (fd_ep < 0) {
256 err(udev, "error creating epoll fd: %m\n");
257 rc = 3;
258 goto out;
259 }
260
261 memset(&ep_signal, 0, sizeof(struct epoll_event));
262 ep_signal.events = EPOLLIN;
263 ep_signal.data.fd = fd_signal;
264
265 fd_monitor = udev_monitor_get_fd(worker_monitor);
266 memset(&ep_monitor, 0, sizeof(struct epoll_event));
267 ep_monitor.events = EPOLLIN;
268 ep_monitor.data.fd = fd_monitor;
269
270 if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_signal, &ep_signal) < 0 ||
271 epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_monitor, &ep_monitor) < 0) {
272 err(udev, "fail to add fds to epoll: %m\n");
273 rc = 4;
274 goto out;
275 }
276
277 /* request TERM signal if parent exits */
278 prctl(PR_SET_PDEATHSIG, SIGTERM);
279
280 for (;;) {
281 struct udev_event *udev_event;
282 struct worker_message msg;
283 int err;
284
285 info(udev, "seq %llu running\n", udev_device_get_seqnum(dev));
286 udev_event = udev_event_new(dev);
287 if (udev_event == NULL) {
288 rc = 5;
289 goto out;
290 }
291
292 /* needed for SIGCHLD/SIGTERM in spawn() */
293 udev_event->fd_signal = fd_signal;
294
295 if (exec_delay > 0)
296 udev_event->exec_delay = exec_delay;
297
298 /* apply rules, create node, symlinks */
299 err = udev_event_execute_rules(udev_event, rules, &sigmask_orig);
300
301 if (err == 0)
302 udev_event_execute_run(udev_event, &sigmask_orig);
303
304 /* apply/restore inotify watch */
305 if (err == 0 && udev_event->inotify_watch) {
306 udev_watch_begin(udev, dev);
307 udev_device_update_db(dev);
308 }
309
310 /* send processed event back to libudev listeners */
311 udev_monitor_send_device(worker_monitor, NULL, dev);
312
313 /* send udevd the result of the event execution */
314 memset(&msg, 0, sizeof(struct worker_message));
315 if (err != 0)
316 msg.exitcode = err;
317 msg.pid = getpid();
318 send(worker_watch[WRITE_END], &msg, sizeof(struct worker_message), 0);
319
320 info(udev, "seq %llu processed with %i\n", udev_device_get_seqnum(dev), err);
321
322 udev_device_unref(dev);
323 dev = NULL;
324
325 if (udev_event->sigterm) {
326 udev_event_unref(udev_event);
327 goto out;
328 }
329
330 udev_event_unref(udev_event);
331
332 /* wait for more device messages from main udevd, or term signal */
333 while (dev == NULL) {
334 struct epoll_event ev[4];
335 int fdcount;
336 int i;
337
338 fdcount = epoll_wait(fd_ep, ev, ARRAY_SIZE(ev), -1);
339 if (fdcount < 0) {
340 if (errno == EINTR)
341 continue;
342 err = -errno;
343 err(udev, "failed to poll: %m\n");
344 goto out;
345 }
346
347 for (i = 0; i < fdcount; i++) {
348 if (ev[i].data.fd == fd_monitor && ev[i].events & EPOLLIN) {
349 dev = udev_monitor_receive_device(worker_monitor);
350 break;
351 } else if (ev[i].data.fd == fd_signal && ev[i].events & EPOLLIN) {
352 struct signalfd_siginfo fdsi;
353 ssize_t size;
354
355 size = read(fd_signal, &fdsi, sizeof(struct signalfd_siginfo));
356 if (size != sizeof(struct signalfd_siginfo))
357 continue;
358 switch (fdsi.ssi_signo) {
359 case SIGTERM:
360 goto out;
361 }
362 }
363 }
364 }
365 }
366 out:
367 udev_device_unref(dev);
368 if (fd_signal >= 0)
369 close(fd_signal);
370 if (fd_ep >= 0)
371 close(fd_ep);
372 close(fd_inotify);
373 close(worker_watch[WRITE_END]);
374 udev_rules_unref(rules);
375 udev_builtin_exit(udev);
376 udev_monitor_unref(worker_monitor);
377 udev_unref(udev);
378 udev_log_close();
379 exit(rc);
380 }
381 case -1:
382 udev_monitor_unref(worker_monitor);
383 event->state = EVENT_QUEUED;
384 free(worker);
385 err(udev, "fork of child failed: %m\n");
386 break;
387 default:
388 /* close monitor, but keep address around */
389 udev_monitor_disconnect(worker_monitor);
390 worker->monitor = worker_monitor;
391 worker->pid = pid;
392 worker->state = WORKER_RUNNING;
393 worker->event_start_usec = now_usec();
394 worker->event = event;
395 event->state = EVENT_RUNNING;
396 udev_list_node_append(&worker->node, &worker_list);
397 children++;
398 info(udev, "seq %llu forked new worker [%u]\n", udev_device_get_seqnum(event->dev), pid);
399 break;
400 }
401 }
402
403 static void event_run(struct event *event)
404 {
405 struct udev_list_node *loop;
406
407 udev_list_node_foreach(loop, &worker_list) {
408 struct worker *worker = node_to_worker(loop);
409 ssize_t count;
410
411 if (worker->state != WORKER_IDLE)
412 continue;
413
414 count = udev_monitor_send_device(monitor, worker->monitor, event->dev);
415 if (count < 0) {
416 err(event->udev, "worker [%u] did not accept message %zi (%m), kill it\n", worker->pid, count);
417 kill(worker->pid, SIGKILL);
418 worker->state = WORKER_KILLED;
419 continue;
420 }
421 worker_ref(worker);
422 worker->event = event;
423 worker->state = WORKER_RUNNING;
424 worker->event_start_usec = now_usec();
425 event->state = EVENT_RUNNING;
426 return;
427 }
428
429 if (children >= children_max) {
430 if (children_max > 1)
431 info(event->udev, "maximum number (%i) of children reached\n", children);
432 return;
433 }
434
435 /* start new worker and pass initial device */
436 worker_new(event);
437 }
438
439 static int event_queue_insert(struct udev_device *dev)
440 {
441 struct event *event;
442
443 event = calloc(1, sizeof(struct event));
444 if (event == NULL)
445 return -1;
446
447 event->udev = udev_device_get_udev(dev);
448 event->dev = dev;
449 event->seqnum = udev_device_get_seqnum(dev);
450 event->devpath = udev_device_get_devpath(dev);
451 event->devpath_len = strlen(event->devpath);
452 event->devpath_old = udev_device_get_devpath_old(dev);
453 event->devnum = udev_device_get_devnum(dev);
454 event->is_block = (strcmp("block", udev_device_get_subsystem(dev)) == 0);
455 event->ifindex = udev_device_get_ifindex(dev);
456
457 udev_queue_export_device_queued(udev_queue_export, dev);
458 info(event->udev, "seq %llu queued, '%s' '%s'\n", udev_device_get_seqnum(dev),
459 udev_device_get_action(dev), udev_device_get_subsystem(dev));
460
461 event->state = EVENT_QUEUED;
462 udev_list_node_append(&event->node, &event_list);
463 return 0;
464 }
465
466 static void worker_kill(struct udev *udev, int retain)
467 {
468 struct udev_list_node *loop;
469 int max;
470
471 if (children <= retain)
472 return;
473
474 max = children - retain;
475
476 udev_list_node_foreach(loop, &worker_list) {
477 struct worker *worker = node_to_worker(loop);
478
479 if (max-- <= 0)
480 break;
481
482 if (worker->state == WORKER_KILLED)
483 continue;
484
485 worker->state = WORKER_KILLED;
486 kill(worker->pid, SIGTERM);
487 }
488 }
489
490 /* lookup event for identical, parent, child device */
491 static bool is_devpath_busy(struct event *event)
492 {
493 struct udev_list_node *loop;
494 size_t common;
495
496 /* check if queue contains events we depend on */
497 udev_list_node_foreach(loop, &event_list) {
498 struct event *loop_event = node_to_event(loop);
499
500 /* we already found a later event, earlier can not block us, no need to check again */
501 if (loop_event->seqnum < event->delaying_seqnum)
502 continue;
503
504 /* event we checked earlier still exists, no need to check again */
505 if (loop_event->seqnum == event->delaying_seqnum)
506 return true;
507
508 /* found ourself, no later event can block us */
509 if (loop_event->seqnum >= event->seqnum)
510 break;
511
512 /* check major/minor */
513 if (major(event->devnum) != 0 && event->devnum == loop_event->devnum && event->is_block == loop_event->is_block)
514 return true;
515
516 /* check network device ifindex */
517 if (event->ifindex != 0 && event->ifindex == loop_event->ifindex)
518 return true;
519
520 /* check our old name */
521 if (event->devpath_old != NULL && strcmp(loop_event->devpath, event->devpath_old) == 0) {
522 event->delaying_seqnum = loop_event->seqnum;
523 return true;
524 }
525
526 /* compare devpath */
527 common = MIN(loop_event->devpath_len, event->devpath_len);
528
529 /* one devpath is contained in the other? */
530 if (memcmp(loop_event->devpath, event->devpath, common) != 0)
531 continue;
532
533 /* identical device event found */
534 if (loop_event->devpath_len == event->devpath_len) {
535 /* devices names might have changed/swapped in the meantime */
536 if (major(event->devnum) != 0 && (event->devnum != loop_event->devnum || event->is_block != loop_event->is_block))
537 continue;
538 if (event->ifindex != 0 && event->ifindex != loop_event->ifindex)
539 continue;
540 event->delaying_seqnum = loop_event->seqnum;
541 return true;
542 }
543
544 /* parent device event found */
545 if (event->devpath[common] == '/') {
546 event->delaying_seqnum = loop_event->seqnum;
547 return true;
548 }
549
550 /* child device event found */
551 if (loop_event->devpath[common] == '/') {
552 event->delaying_seqnum = loop_event->seqnum;
553 return true;
554 }
555
556 /* no matching device */
557 continue;
558 }
559
560 return false;
561 }
562
563 static void event_queue_start(struct udev *udev)
564 {
565 struct udev_list_node *loop;
566
567 udev_list_node_foreach(loop, &event_list) {
568 struct event *event = node_to_event(loop);
569
570 if (event->state != EVENT_QUEUED)
571 continue;
572
573 /* do not start event if parent or child event is still running */
574 if (is_devpath_busy(event)) {
575 dbg(udev, "delay seq %llu (%s)\n", event->seqnum, event->devpath);
576 continue;
577 }
578
579 event_run(event);
580 }
581 }
582
583 static void event_queue_cleanup(struct udev *udev, enum event_state match_type)
584 {
585 struct udev_list_node *loop, *tmp;
586
587 udev_list_node_foreach_safe(loop, tmp, &event_list) {
588 struct event *event = node_to_event(loop);
589
590 if (match_type != EVENT_UNDEF && match_type != event->state)
591 continue;
592
593 event_queue_delete(event, false);
594 }
595 }
596
597 static void worker_returned(int fd_worker)
598 {
599 for (;;) {
600 struct worker_message msg;
601 ssize_t size;
602 struct udev_list_node *loop;
603
604 size = recv(fd_worker, &msg, sizeof(struct worker_message), MSG_DONTWAIT);
605 if (size != sizeof(struct worker_message))
606 break;
607
608 /* lookup worker who sent the signal */
609 udev_list_node_foreach(loop, &worker_list) {
610 struct worker *worker = node_to_worker(loop);
611
612 if (worker->pid != msg.pid)
613 continue;
614
615 /* worker returned */
616 if (worker->event) {
617 worker->event->exitcode = msg.exitcode;
618 event_queue_delete(worker->event, true);
619 worker->event = NULL;
620 }
621 if (worker->state != WORKER_KILLED)
622 worker->state = WORKER_IDLE;
623 worker_unref(worker);
624 break;
625 }
626 }
627 }
628
629 /* receive the udevd message from userspace */
630 static struct udev_ctrl_connection *handle_ctrl_msg(struct udev_ctrl *uctrl)
631 {
632 struct udev *udev = udev_ctrl_get_udev(uctrl);
633 struct udev_ctrl_connection *ctrl_conn;
634 struct udev_ctrl_msg *ctrl_msg = NULL;
635 const char *str;
636 int i;
637
638 ctrl_conn = udev_ctrl_get_connection(uctrl);
639 if (ctrl_conn == NULL)
640 goto out;
641
642 ctrl_msg = udev_ctrl_receive_msg(ctrl_conn);
643 if (ctrl_msg == NULL)
644 goto out;
645
646 i = udev_ctrl_get_set_log_level(ctrl_msg);
647 if (i >= 0) {
648 info(udev, "udevd message (SET_LOG_PRIORITY) received, log_priority=%i\n", i);
649 udev_set_log_priority(udev, i);
650 worker_kill(udev, 0);
651 }
652
653 if (udev_ctrl_get_stop_exec_queue(ctrl_msg) > 0) {
654 info(udev, "udevd message (STOP_EXEC_QUEUE) received\n");
655 stop_exec_queue = true;
656 }
657
658 if (udev_ctrl_get_start_exec_queue(ctrl_msg) > 0) {
659 info(udev, "udevd message (START_EXEC_QUEUE) received\n");
660 stop_exec_queue = false;
661 }
662
663 if (udev_ctrl_get_reload(ctrl_msg) > 0) {
664 info(udev, "udevd message (RELOAD) received\n");
665 reload = true;
666 }
667
668 str = udev_ctrl_get_set_env(ctrl_msg);
669 if (str != NULL) {
670 char *key;
671
672 key = strdup(str);
673 if (key != NULL) {
674 char *val;
675
676 val = strchr(key, '=');
677 if (val != NULL) {
678 val[0] = '\0';
679 val = &val[1];
680 if (val[0] == '\0') {
681 info(udev, "udevd message (ENV) received, unset '%s'\n", key);
682 udev_add_property(udev, key, NULL);
683 } else {
684 info(udev, "udevd message (ENV) received, set '%s=%s'\n", key, val);
685 udev_add_property(udev, key, val);
686 }
687 } else {
688 err(udev, "wrong key format '%s'\n", key);
689 }
690 free(key);
691 }
692 worker_kill(udev, 0);
693 }
694
695 i = udev_ctrl_get_set_children_max(ctrl_msg);
696 if (i >= 0) {
697 info(udev, "udevd message (SET_MAX_CHILDREN) received, children_max=%i\n", i);
698 children_max = i;
699 }
700
701 if (udev_ctrl_get_ping(ctrl_msg) > 0)
702 info(udev, "udevd message (SYNC) received\n");
703
704 if (udev_ctrl_get_exit(ctrl_msg) > 0) {
705 info(udev, "udevd message (EXIT) received\n");
706 udev_exit = true;
707 /* keep reference to block the client until we exit */
708 udev_ctrl_connection_ref(ctrl_conn);
709 }
710 out:
711 udev_ctrl_msg_unref(ctrl_msg);
712 return udev_ctrl_connection_unref(ctrl_conn);
713 }
714
715 /* read inotify messages */
716 static int handle_inotify(struct udev *udev)
717 {
718 int nbytes, pos;
719 char *buf;
720 struct inotify_event *ev;
721
722 if ((ioctl(fd_inotify, FIONREAD, &nbytes) < 0) || (nbytes <= 0))
723 return 0;
724
725 buf = malloc(nbytes);
726 if (buf == NULL) {
727 err(udev, "error getting buffer for inotify\n");
728 return -1;
729 }
730
731 nbytes = read(fd_inotify, buf, nbytes);
732
733 for (pos = 0; pos < nbytes; pos += sizeof(struct inotify_event) + ev->len) {
734 struct udev_device *dev;
735
736 ev = (struct inotify_event *)(buf + pos);
737 dev = udev_watch_lookup(udev, ev->wd);
738 if (dev != NULL) {
739 info(udev, "inotify event: %x for %s\n", ev->mask, udev_device_get_devnode(dev));
740 if (ev->mask & IN_CLOSE_WRITE) {
741 char filename[UTIL_PATH_SIZE];
742 int fd;
743
744 info(udev, "device %s closed, synthesising 'change'\n", udev_device_get_devnode(dev));
745 util_strscpyl(filename, sizeof(filename), udev_device_get_syspath(dev), "/uevent", NULL);
746 fd = open(filename, O_WRONLY);
747 if (fd >= 0) {
748 if (write(fd, "change", 6) < 0)
749 info(udev, "error writing uevent: %m\n");
750 close(fd);
751 }
752 }
753 if (ev->mask & IN_IGNORED)
754 udev_watch_end(udev, dev);
755
756 udev_device_unref(dev);
757 }
758
759 }
760
761 free(buf);
762 return 0;
763 }
764
765 static void handle_signal(struct udev *udev, int signo)
766 {
767 switch (signo) {
768 case SIGINT:
769 case SIGTERM:
770 udev_exit = true;
771 break;
772 case SIGCHLD:
773 for (;;) {
774 pid_t pid;
775 int status;
776 struct udev_list_node *loop, *tmp;
777
778 pid = waitpid(-1, &status, WNOHANG);
779 if (pid <= 0)
780 break;
781
782 udev_list_node_foreach_safe(loop, tmp, &worker_list) {
783 struct worker *worker = node_to_worker(loop);
784
785 if (worker->pid != pid)
786 continue;
787 info(udev, "worker [%u] exit\n", pid);
788
789 if (WIFEXITED(status)) {
790 if (WEXITSTATUS(status) != 0)
791 err(udev, "worker [%u] exit with return code %i\n", pid, WEXITSTATUS(status));
792 } else if (WIFSIGNALED(status)) {
793 err(udev, "worker [%u] terminated by signal %i (%s)\n",
794 pid, WTERMSIG(status), strsignal(WTERMSIG(status)));
795 } else if (WIFSTOPPED(status)) {
796 err(udev, "worker [%u] stopped\n", pid);
797 } else if (WIFCONTINUED(status)) {
798 err(udev, "worker [%u] continued\n", pid);
799 } else {
800 err(udev, "worker [%u] exit with status 0x%04x\n", pid, status);
801 }
802
803 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
804 if (worker->event) {
805 err(udev, "worker [%u] failed while handling '%s'\n",
806 pid, worker->event->devpath);
807 worker->event->exitcode = -32;
808 event_queue_delete(worker->event, true);
809 /* drop reference taken for state 'running' */
810 worker_unref(worker);
811 }
812 }
813 worker_unref(worker);
814 break;
815 }
816 }
817 break;
818 case SIGHUP:
819 reload = true;
820 break;
821 }
822 }
823
824 static void static_dev_create_from_modules(struct udev *udev)
825 {
826 struct utsname kernel;
827 char modules[UTIL_PATH_SIZE];
828 char buf[4096];
829 FILE *f;
830
831 uname(&kernel);
832 util_strscpyl(modules, sizeof(modules), "/lib/modules/", kernel.release, "/modules.devname", NULL);
833 f = fopen(modules, "r");
834 if (f == NULL)
835 return;
836
837 while (fgets(buf, sizeof(buf), f) != NULL) {
838 char *s;
839 const char *modname;
840 const char *devname;
841 const char *devno;
842 int maj, min;
843 char type;
844 mode_t mode;
845 char filename[UTIL_PATH_SIZE];
846
847 if (buf[0] == '#')
848 continue;
849
850 modname = buf;
851 s = strchr(modname, ' ');
852 if (s == NULL)
853 continue;
854 s[0] = '\0';
855
856 devname = &s[1];
857 s = strchr(devname, ' ');
858 if (s == NULL)
859 continue;
860 s[0] = '\0';
861
862 devno = &s[1];
863 s = strchr(devno, ' ');
864 if (s == NULL)
865 s = strchr(devno, '\n');
866 if (s != NULL)
867 s[0] = '\0';
868 if (sscanf(devno, "%c%u:%u", &type, &maj, &min) != 3)
869 continue;
870
871 mode = 0600;
872 if (type == 'c')
873 mode |= S_IFCHR;
874 else if (type == 'b')
875 mode |= S_IFBLK;
876 else
877 continue;
878
879 util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev), "/", devname, NULL);
880 util_create_path_selinux(udev, filename);
881 udev_selinux_setfscreatecon(udev, filename, mode);
882 info(udev, "mknod '%s' %c%u:%u\n", filename, type, maj, min);
883 if (mknod(filename, mode, makedev(maj, min)) < 0 && errno == EEXIST)
884 utimensat(AT_FDCWD, filename, NULL, 0);
885 udev_selinux_resetfscreatecon(udev);
886 }
887
888 fclose(f);
889 }
890
891 static int copy_dev_dir(struct udev *udev, DIR *dir_from, DIR *dir_to, int maxdepth)
892 {
893 struct dirent *dent;
894
895 for (dent = readdir(dir_from); dent != NULL; dent = readdir(dir_from)) {
896 struct stat stats;
897
898 if (dent->d_name[0] == '.')
899 continue;
900 if (fstatat(dirfd(dir_from), dent->d_name, &stats, AT_SYMLINK_NOFOLLOW) != 0)
901 continue;
902
903 if (S_ISBLK(stats.st_mode) || S_ISCHR(stats.st_mode)) {
904 udev_selinux_setfscreateconat(udev, dirfd(dir_to), dent->d_name, stats.st_mode & 0777);
905 if (mknodat(dirfd(dir_to), dent->d_name, stats.st_mode, stats.st_rdev) == 0) {
906 fchmodat(dirfd(dir_to), dent->d_name, stats.st_mode & 0777, 0);
907 fchownat(dirfd(dir_to), dent->d_name, stats.st_uid, stats.st_gid, 0);
908 } else {
909 utimensat(dirfd(dir_to), dent->d_name, NULL, 0);
910 }
911 udev_selinux_resetfscreatecon(udev);
912 } else if (S_ISLNK(stats.st_mode)) {
913 char target[UTIL_PATH_SIZE];
914 ssize_t len;
915
916 len = readlinkat(dirfd(dir_from), dent->d_name, target, sizeof(target));
917 if (len <= 0 || len == (ssize_t)sizeof(target))
918 continue;
919 target[len] = '\0';
920 udev_selinux_setfscreateconat(udev, dirfd(dir_to), dent->d_name, S_IFLNK);
921 if (symlinkat(target, dirfd(dir_to), dent->d_name) < 0 && errno == EEXIST)
922 utimensat(dirfd(dir_to), dent->d_name, NULL, AT_SYMLINK_NOFOLLOW);
923 udev_selinux_resetfscreatecon(udev);
924 } else if (S_ISDIR(stats.st_mode)) {
925 DIR *dir2_from, *dir2_to;
926
927 if (maxdepth == 0)
928 continue;
929
930 udev_selinux_setfscreateconat(udev, dirfd(dir_to), dent->d_name, S_IFDIR|0755);
931 mkdirat(dirfd(dir_to), dent->d_name, 0755);
932 udev_selinux_resetfscreatecon(udev);
933
934 dir2_to = fdopendir(openat(dirfd(dir_to), dent->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC));
935 if (dir2_to == NULL)
936 continue;
937
938 dir2_from = fdopendir(openat(dirfd(dir_from), dent->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC));
939 if (dir2_from == NULL) {
940 closedir(dir2_to);
941 continue;
942 }
943
944 copy_dev_dir(udev, dir2_from, dir2_to, maxdepth-1);
945
946 closedir(dir2_to);
947 closedir(dir2_from);
948 }
949 }
950
951 return 0;
952 }
953
954 static void static_dev_create_links(struct udev *udev, DIR *dir)
955 {
956 struct stdlinks {
957 const char *link;
958 const char *target;
959 };
960 static const struct stdlinks stdlinks[] = {
961 { "core", "/proc/kcore" },
962 { "fd", "/proc/self/fd" },
963 { "stdin", "/proc/self/fd/0" },
964 { "stdout", "/proc/self/fd/1" },
965 { "stderr", "/proc/self/fd/2" },
966 };
967 unsigned int i;
968
969 for (i = 0; i < ARRAY_SIZE(stdlinks); i++) {
970 struct stat sb;
971
972 if (stat(stdlinks[i].target, &sb) == 0) {
973 udev_selinux_setfscreateconat(udev, dirfd(dir), stdlinks[i].link, S_IFLNK);
974 if (symlinkat(stdlinks[i].target, dirfd(dir), stdlinks[i].link) < 0 && errno == EEXIST)
975 utimensat(dirfd(dir), stdlinks[i].link, NULL, AT_SYMLINK_NOFOLLOW);
976 udev_selinux_resetfscreatecon(udev);
977 }
978 }
979 }
980
981 static void static_dev_create_from_devices(struct udev *udev, DIR *dir)
982 {
983 DIR *dir_from;
984
985 dir_from = opendir(PKGLIBEXECDIR "/devices");
986 if (dir_from == NULL)
987 return;
988 copy_dev_dir(udev, dir_from, dir, 8);
989 closedir(dir_from);
990 }
991
992 static void static_dev_create(struct udev *udev)
993 {
994 DIR *dir;
995
996 dir = opendir(udev_get_dev_path(udev));
997 if (dir == NULL)
998 return;
999
1000 static_dev_create_links(udev, dir);
1001 static_dev_create_from_devices(udev, dir);
1002
1003 closedir(dir);
1004 }
1005
1006 static int mem_size_mb(void)
1007 {
1008 FILE *f;
1009 char buf[4096];
1010 long int memsize = -1;
1011
1012 f = fopen("/proc/meminfo", "r");
1013 if (f == NULL)
1014 return -1;
1015
1016 while (fgets(buf, sizeof(buf), f) != NULL) {
1017 long int value;
1018
1019 if (sscanf(buf, "MemTotal: %ld kB", &value) == 1) {
1020 memsize = value / 1024;
1021 break;
1022 }
1023 }
1024
1025 fclose(f);
1026 return memsize;
1027 }
1028
1029 static int convert_db(struct udev *udev)
1030 {
1031 char filename[UTIL_PATH_SIZE];
1032 FILE *f;
1033 struct udev_enumerate *udev_enumerate;
1034 struct udev_list_entry *list_entry;
1035
1036 /* current database */
1037 util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/data", NULL);
1038 if (access(filename, F_OK) >= 0)
1039 return 0;
1040
1041 /* make sure we do not get here again */
1042 util_create_path(udev, filename);
1043 mkdir(filename, 0755);
1044
1045 /* old database */
1046 util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev), "/.udev/db", NULL);
1047 if (access(filename, F_OK) < 0)
1048 return 0;
1049
1050 print_kmsg("converting old udev database\n");
1051
1052 udev_enumerate = udev_enumerate_new(udev);
1053 if (udev_enumerate == NULL)
1054 return -1;
1055 udev_enumerate_scan_devices(udev_enumerate);
1056 udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(udev_enumerate)) {
1057 struct udev_device *device;
1058
1059 device = udev_device_new_from_syspath(udev, udev_list_entry_get_name(list_entry));
1060 if (device == NULL)
1061 continue;
1062
1063 /* try to find the old database for devices without a current one */
1064 if (udev_device_read_db(device, NULL) < 0) {
1065 bool have_db;
1066 const char *id;
1067 struct stat stats;
1068 char devpath[UTIL_PATH_SIZE];
1069 char from[UTIL_PATH_SIZE];
1070
1071 have_db = false;
1072
1073 /* find database in old location */
1074 id = udev_device_get_id_filename(device);
1075 util_strscpyl(from, sizeof(from), udev_get_dev_path(udev), "/.udev/db/", id, NULL);
1076 if (lstat(from, &stats) == 0) {
1077 if (!have_db) {
1078 udev_device_read_db(device, from);
1079 have_db = true;
1080 }
1081 unlink(from);
1082 }
1083
1084 /* find old database with $subsys:$sysname name */
1085 util_strscpyl(from, sizeof(from), udev_get_dev_path(udev),
1086 "/.udev/db/", udev_device_get_subsystem(device), ":",
1087 udev_device_get_sysname(device), NULL);
1088 if (lstat(from, &stats) == 0) {
1089 if (!have_db) {
1090 udev_device_read_db(device, from);
1091 have_db = true;
1092 }
1093 unlink(from);
1094 }
1095
1096 /* find old database with the encoded devpath name */
1097 util_path_encode(udev_device_get_devpath(device), devpath, sizeof(devpath));
1098 util_strscpyl(from, sizeof(from), udev_get_dev_path(udev), "/.udev/db/", devpath, NULL);
1099 if (lstat(from, &stats) == 0) {
1100 if (!have_db) {
1101 udev_device_read_db(device, from);
1102 have_db = true;
1103 }
1104 unlink(from);
1105 }
1106
1107 /* write out new database */
1108 if (have_db)
1109 udev_device_update_db(device);
1110 }
1111 udev_device_unref(device);
1112 }
1113 udev_enumerate_unref(udev_enumerate);
1114 return 0;
1115 }
1116
1117 static bool check_rules_timestamp(struct udev *udev)
1118 {
1119 char **p;
1120 unsigned long long *stamp_usec;
1121 int i, n;
1122 bool changed = false;
1123
1124 n = udev_get_rules_path(udev, &p, &stamp_usec);
1125 for (i = 0; i < n; i++) {
1126 struct stat stats;
1127
1128 if (stat(p[i], &stats) < 0)
1129 continue;
1130
1131 if (stamp_usec[i] == ts_usec(&stats.st_mtim))
1132 continue;
1133
1134 /* first check */
1135 if (stamp_usec[i] != 0) {
1136 info(udev, "reload - timestamp of '%s' changed\n", p[i]);
1137 changed = true;
1138 }
1139
1140 /* update timestamp */
1141 stamp_usec[i] = ts_usec(&stats.st_mtim);
1142 }
1143
1144 return changed;
1145 }
1146
1147 /*
1148 * read the kernel commandline, in case we need to get into debug mode
1149 * udev.log-priority=<level> syslog priority
1150 * udev.children-max=<number of workers> events are fully serialized if set to 1
1151 * udev.exec-delay=<number of seconds> delay execution of every executed program
1152 */
1153
1154 static void kernel_cmdline_opts(struct udev *udev)
1155 {
1156 FILE *f;
1157
1158 f = fopen("/proc/cmdline", "r");
1159 if (f != NULL) {
1160 char cmdline[4096];
1161
1162 if (fgets(cmdline, sizeof(cmdline), f) != NULL) {
1163 char *pos;
1164
1165 pos = strstr(cmdline, "udev.log-priority=");
1166 if (pos != NULL) {
1167 pos += strlen("udev.log-priority=");
1168 udev_set_log_priority(udev, util_log_priority(pos));
1169 }
1170
1171 pos = strstr(cmdline, "udev.children-max=");
1172 if (pos != NULL) {
1173 pos += strlen("udev.children-max=");
1174 children_max = strtoul(pos, NULL, 0);
1175 }
1176
1177 pos = strstr(cmdline, "udev.exec-delay=");
1178 if (pos != NULL) {
1179 pos += strlen("udev.exec-delay=");
1180 exec_delay = strtoul(pos, NULL, 0);
1181 }
1182 }
1183 fclose(f);
1184 }
1185 }
1186
1187 int main(int argc, char *argv[])
1188 {
1189 struct udev *udev;
1190 FILE *f;
1191 sigset_t mask;
1192 int daemonize = false;
1193 int resolve_names = 1;
1194 static const struct option options[] = {
1195 { "daemon", no_argument, NULL, 'd' },
1196 { "debug", no_argument, NULL, 'D' },
1197 { "children-max", required_argument, NULL, 'c' },
1198 { "exec-delay", required_argument, NULL, 'e' },
1199 { "resolve-names", required_argument, NULL, 'N' },
1200 { "help", no_argument, NULL, 'h' },
1201 { "version", no_argument, NULL, 'V' },
1202 {}
1203 };
1204 int fd_ctrl = -1;
1205 int fd_netlink = -1;
1206 int fd_worker = -1;
1207 struct epoll_event ep_ctrl, ep_inotify, ep_signal, ep_netlink, ep_worker;
1208 struct udev_ctrl_connection *ctrl_conn = NULL;
1209 char **s;
1210 int rc = 1;
1211
1212 udev = udev_new();
1213 if (udev == NULL)
1214 goto exit;
1215
1216 udev_log_init("udevd");
1217 udev_set_log_fn(udev, udev_main_log);
1218 info(udev, "version %s\n", VERSION);
1219 udev_selinux_init(udev);
1220
1221 for (;;) {
1222 int option;
1223
1224 option = getopt_long(argc, argv, "c:deDtN:hV", options, NULL);
1225 if (option == -1)
1226 break;
1227
1228 switch (option) {
1229 case 'd':
1230 daemonize = true;
1231 break;
1232 case 'c':
1233 children_max = strtoul(optarg, NULL, 0);
1234 break;
1235 case 'e':
1236 exec_delay = strtoul(optarg, NULL, 0);
1237 break;
1238 case 'D':
1239 debug = true;
1240 if (udev_get_log_priority(udev) < LOG_INFO)
1241 udev_set_log_priority(udev, LOG_INFO);
1242 break;
1243 case 'N':
1244 if (strcmp (optarg, "early") == 0) {
1245 resolve_names = 1;
1246 } else if (strcmp (optarg, "late") == 0) {
1247 resolve_names = 0;
1248 } else if (strcmp (optarg, "never") == 0) {
1249 resolve_names = -1;
1250 } else {
1251 fprintf(stderr, "resolve-names must be early, late or never\n");
1252 err(udev, "resolve-names must be early, late or never\n");
1253 goto exit;
1254 }
1255 break;
1256 case 'h':
1257 printf("Usage: udevd OPTIONS\n"
1258 " --daemon\n"
1259 " --debug\n"
1260 " --children-max=<maximum number of workers>\n"
1261 " --exec-delay=<seconds to wait before executing RUN=>\n"
1262 " --resolve-names=early|late|never\n"
1263 " --version\n"
1264 " --help\n"
1265 "\n");
1266 goto exit;
1267 case 'V':
1268 printf("%s\n", VERSION);
1269 goto exit;
1270 default:
1271 goto exit;
1272 }
1273 }
1274
1275 kernel_cmdline_opts(udev);
1276
1277 if (getuid() != 0) {
1278 fprintf(stderr, "root privileges required\n");
1279 err(udev, "root privileges required\n");
1280 goto exit;
1281 }
1282
1283 /* set umask before creating any file/directory */
1284 chdir("/");
1285 umask(022);
1286
1287 /* /run/udev */
1288 mkdir(udev_get_run_path(udev), 0755);
1289
1290 /* create standard links, copy static nodes, create nodes from modules */
1291 static_dev_create(udev);
1292 static_dev_create_from_modules(udev);
1293
1294 /* before opening new files, make sure std{in,out,err} fds are in a sane state */
1295 if (daemonize) {
1296 int fd;
1297
1298 fd = open("/dev/null", O_RDWR);
1299 if (fd >= 0) {
1300 if (write(STDOUT_FILENO, 0, 0) < 0)
1301 dup2(fd, STDOUT_FILENO);
1302 if (write(STDERR_FILENO, 0, 0) < 0)
1303 dup2(fd, STDERR_FILENO);
1304 if (fd > STDERR_FILENO)
1305 close(fd);
1306 } else {
1307 fprintf(stderr, "cannot open /dev/null\n");
1308 err(udev, "cannot open /dev/null\n");
1309 }
1310 }
1311
1312 udev_ctrl = udev_ctrl_new(udev);
1313 if (udev_ctrl == NULL) {
1314 fprintf(stderr, "error initializing udev control socket");
1315 err(udev, "error initializing udev control socket");
1316 rc = 1;
1317 goto exit;
1318 }
1319 fd_ctrl = udev_ctrl_get_fd(udev_ctrl);
1320
1321 monitor = udev_monitor_new_from_netlink(udev, "kernel");
1322 if (monitor == NULL) {
1323 fprintf(stderr, "error initializing netlink socket\n");
1324 err(udev, "error initializing netlink socket\n");
1325 rc = 3;
1326 goto exit;
1327 }
1328 fd_netlink = udev_monitor_get_fd(monitor);
1329
1330 if (udev_monitor_enable_receiving(monitor) < 0) {
1331 fprintf(stderr, "error binding netlink socket\n");
1332 err(udev, "error binding netlink socket\n");
1333 rc = 3;
1334 goto exit;
1335 }
1336
1337 if (udev_ctrl_enable_receiving(udev_ctrl) < 0) {
1338 fprintf(stderr, "error binding udev control socket\n");
1339 err(udev, "error binding udev control socket\n");
1340 rc = 1;
1341 goto exit;
1342 }
1343
1344 udev_monitor_set_receive_buffer_size(monitor, 128*1024*1024);
1345
1346 /* create queue file before signalling 'ready', to make sure we block 'settle' */
1347 udev_queue_export = udev_queue_export_new(udev);
1348 if (udev_queue_export == NULL) {
1349 err(udev, "error creating queue file\n");
1350 goto exit;
1351 }
1352
1353 if (daemonize) {
1354 pid_t pid;
1355 int fd;
1356
1357 pid = fork();
1358 switch (pid) {
1359 case 0:
1360 break;
1361 case -1:
1362 err(udev, "fork of daemon failed: %m\n");
1363 rc = 4;
1364 goto exit;
1365 default:
1366 rc = EXIT_SUCCESS;
1367 goto exit_daemonize;
1368 }
1369
1370 setsid();
1371
1372 fd = open("/proc/self/oom_score_adj", O_RDWR|O_CLOEXEC);
1373 if (fd >= 0) {
1374 write(fd, "-1000", 5);
1375 close(fd);
1376 }
1377 }
1378
1379 print_kmsg("starting version " VERSION "\n");
1380
1381 if (!debug) {
1382 int fd;
1383
1384 fd = open("/dev/null", O_RDWR);
1385 if (fd >= 0) {
1386 dup2(fd, STDIN_FILENO);
1387 dup2(fd, STDOUT_FILENO);
1388 dup2(fd, STDERR_FILENO);
1389 close(fd);
1390 }
1391 }
1392
1393 fd_inotify = udev_watch_init(udev);
1394 if (fd_inotify < 0) {
1395 fprintf(stderr, "error initializing inotify\n");
1396 err(udev, "error initializing inotify\n");
1397 rc = 4;
1398 goto exit;
1399 }
1400 udev_watch_restore(udev);
1401
1402 /* block and listen to all signals on signalfd */
1403 sigfillset(&mask);
1404 sigprocmask(SIG_SETMASK, &mask, &sigmask_orig);
1405 fd_signal = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
1406 if (fd_signal < 0) {
1407 fprintf(stderr, "error creating signalfd\n");
1408 err(udev, "error creating signalfd\n");
1409 rc = 5;
1410 goto exit;
1411 }
1412
1413 /* unnamed socket from workers to the main daemon */
1414 if (socketpair(AF_LOCAL, SOCK_DGRAM|SOCK_CLOEXEC, 0, worker_watch) < 0) {
1415 fprintf(stderr, "error creating socketpair\n");
1416 err(udev, "error creating socketpair\n");
1417 rc = 6;
1418 goto exit;
1419 }
1420 fd_worker = worker_watch[READ_END];
1421
1422 udev_builtin_init(udev);
1423
1424 rules = udev_rules_new(udev, resolve_names);
1425 if (rules == NULL) {
1426 err(udev, "error reading rules\n");
1427 goto exit;
1428 }
1429
1430 memset(&ep_ctrl, 0, sizeof(struct epoll_event));
1431 ep_ctrl.events = EPOLLIN;
1432 ep_ctrl.data.fd = fd_ctrl;
1433
1434 memset(&ep_inotify, 0, sizeof(struct epoll_event));
1435 ep_inotify.events = EPOLLIN;
1436 ep_inotify.data.fd = fd_inotify;
1437
1438 memset(&ep_signal, 0, sizeof(struct epoll_event));
1439 ep_signal.events = EPOLLIN;
1440 ep_signal.data.fd = fd_signal;
1441
1442 memset(&ep_netlink, 0, sizeof(struct epoll_event));
1443 ep_netlink.events = EPOLLIN;
1444 ep_netlink.data.fd = fd_netlink;
1445
1446 memset(&ep_worker, 0, sizeof(struct epoll_event));
1447 ep_worker.events = EPOLLIN;
1448 ep_worker.data.fd = fd_worker;
1449
1450 fd_ep = epoll_create1(EPOLL_CLOEXEC);
1451 if (fd_ep < 0) {
1452 err(udev, "error creating epoll fd: %m\n");
1453 goto exit;
1454 }
1455 if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_ctrl, &ep_ctrl) < 0 ||
1456 epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_inotify, &ep_inotify) < 0 ||
1457 epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_signal, &ep_signal) < 0 ||
1458 epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_netlink, &ep_netlink) < 0 ||
1459 epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_worker, &ep_worker) < 0) {
1460 err(udev, "fail to add fds to epoll: %m\n");
1461 goto exit;
1462 }
1463
1464 /* if needed, convert old database from earlier udev version */
1465 convert_db(udev);
1466
1467 if (children_max <= 0) {
1468 int memsize = mem_size_mb();
1469
1470 /* set value depending on the amount of RAM */
1471 if (memsize > 0)
1472 children_max = 16 + (memsize / 8);
1473 else
1474 children_max = 16;
1475 }
1476 info(udev, "set children_max to %u\n", children_max);
1477
1478 udev_rules_apply_static_dev_perms(rules);
1479
1480 udev_list_node_init(&event_list);
1481 udev_list_node_init(&worker_list);
1482
1483 for (;;) {
1484 static unsigned long long last_usec;
1485 struct epoll_event ev[8];
1486 int fdcount;
1487 int timeout;
1488 bool is_worker, is_signal, is_inotify, is_netlink, is_ctrl;
1489 int i;
1490
1491 if (udev_exit) {
1492 /* close sources of new events and discard buffered events */
1493 if (fd_ctrl >= 0) {
1494 epoll_ctl(fd_ep, EPOLL_CTL_DEL, fd_ctrl, NULL);
1495 fd_ctrl = -1;
1496 }
1497 if (monitor != NULL) {
1498 epoll_ctl(fd_ep, EPOLL_CTL_DEL, fd_netlink, NULL);
1499 udev_monitor_unref(monitor);
1500 monitor = NULL;
1501 }
1502 if (fd_inotify >= 0) {
1503 epoll_ctl(fd_ep, EPOLL_CTL_DEL, fd_inotify, NULL);
1504 close(fd_inotify);
1505 fd_inotify = -1;
1506 }
1507
1508 /* discard queued events and kill workers */
1509 event_queue_cleanup(udev, EVENT_QUEUED);
1510 worker_kill(udev, 0);
1511
1512 /* exit after all has cleaned up */
1513 if (udev_list_node_is_empty(&event_list) && udev_list_node_is_empty(&worker_list))
1514 break;
1515
1516 /* timeout at exit for workers to finish */
1517 timeout = 30 * 1000;
1518 } else if (udev_list_node_is_empty(&event_list) && children <= 2) {
1519 /* we are idle */
1520 timeout = -1;
1521 } else {
1522 /* kill idle or hanging workers */
1523 timeout = 3 * 1000;
1524 }
1525 fdcount = epoll_wait(fd_ep, ev, ARRAY_SIZE(ev), timeout);
1526 if (fdcount < 0)
1527 continue;
1528
1529 if (fdcount == 0) {
1530 struct udev_list_node *loop;
1531
1532 /* timeout */
1533 if (udev_exit) {
1534 err(udev, "timeout, giving up waiting for workers to finish\n");
1535 break;
1536 }
1537
1538 /* kill idle workers */
1539 if (udev_list_node_is_empty(&event_list)) {
1540 info(udev, "cleanup idle workers\n");
1541 worker_kill(udev, 2);
1542 }
1543
1544 /* check for hanging events */
1545 udev_list_node_foreach(loop, &worker_list) {
1546 struct worker *worker = node_to_worker(loop);
1547
1548 if (worker->state != WORKER_RUNNING)
1549 continue;
1550
1551 if ((now_usec() - worker->event_start_usec) > 30 * 1000 * 1000) {
1552 err(udev, "worker [%u] timeout, kill it\n", worker->pid,
1553 worker->event ? worker->event->devpath : "<idle>");
1554 kill(worker->pid, SIGKILL);
1555 worker->state = WORKER_KILLED;
1556 /* drop reference taken for state 'running' */
1557 worker_unref(worker);
1558 if (worker->event) {
1559 err(udev, "seq %llu '%s' killed\n",
1560 udev_device_get_seqnum(worker->event->dev), worker->event->devpath);
1561 worker->event->exitcode = -64;
1562 event_queue_delete(worker->event, true);
1563 worker->event = NULL;
1564 }
1565 }
1566 }
1567
1568 }
1569
1570 is_worker = is_signal = is_inotify = is_netlink = is_ctrl = false;
1571 for (i = 0; i < fdcount; i++) {
1572 if (ev[i].data.fd == fd_worker && ev[i].events & EPOLLIN)
1573 is_worker = true;
1574 else if (ev[i].data.fd == fd_netlink && ev[i].events & EPOLLIN)
1575 is_netlink = true;
1576 else if (ev[i].data.fd == fd_signal && ev[i].events & EPOLLIN)
1577 is_signal = true;
1578 else if (ev[i].data.fd == fd_inotify && ev[i].events & EPOLLIN)
1579 is_inotify = true;
1580 else if (ev[i].data.fd == fd_ctrl && ev[i].events & EPOLLIN)
1581 is_ctrl = true;
1582 }
1583
1584 /* check for changed config, every 3 seconds at most */
1585 if ((now_usec() - last_usec) > 3 * 1000 * 1000) {
1586 if (check_rules_timestamp(udev))
1587 reload = true;
1588 if (udev_builtin_validate(udev))
1589 reload = true;
1590
1591 last_usec = now_usec();
1592 }
1593
1594 /* reload requested, HUP signal received, rules changed, builtin changed */
1595 if (reload) {
1596 worker_kill(udev, 0);
1597 rules = udev_rules_unref(rules);
1598 udev_builtin_exit(udev);
1599 reload = 0;
1600 }
1601
1602 /* event has finished */
1603 if (is_worker)
1604 worker_returned(fd_worker);
1605
1606 if (is_netlink) {
1607 struct udev_device *dev;
1608
1609 dev = udev_monitor_receive_device(monitor);
1610 if (dev != NULL) {
1611 udev_device_set_usec_initialized(dev, now_usec());
1612 if (event_queue_insert(dev) < 0)
1613 udev_device_unref(dev);
1614 }
1615 }
1616
1617 /* start new events */
1618 if (!udev_list_node_is_empty(&event_list) && !udev_exit && !stop_exec_queue) {
1619 if (rules == NULL)
1620 rules = udev_rules_new(udev, resolve_names);
1621 if (rules != NULL)
1622 event_queue_start(udev);
1623 }
1624
1625 if (is_signal) {
1626 struct signalfd_siginfo fdsi;
1627 ssize_t size;
1628
1629 size = read(fd_signal, &fdsi, sizeof(struct signalfd_siginfo));
1630 if (size == sizeof(struct signalfd_siginfo))
1631 handle_signal(udev, fdsi.ssi_signo);
1632 }
1633
1634 /* we are shutting down, the events below are not handled anymore */
1635 if (udev_exit)
1636 continue;
1637
1638 /* device node watch */
1639 if (is_inotify)
1640 handle_inotify(udev);
1641
1642 /*
1643 * This needs to be after the inotify handling, to make sure,
1644 * that the ping is send back after the possibly generated
1645 * "change" events by the inotify device node watch.
1646 *
1647 * A single time we may receive a client connection which we need to
1648 * keep open to block the client. It will be closed right before we
1649 * exit.
1650 */
1651 if (is_ctrl)
1652 ctrl_conn = handle_ctrl_msg(udev_ctrl);
1653 }
1654
1655 rc = EXIT_SUCCESS;
1656 exit:
1657 udev_queue_export_cleanup(udev_queue_export);
1658 udev_ctrl_cleanup(udev_ctrl);
1659 exit_daemonize:
1660 if (fd_ep >= 0)
1661 close(fd_ep);
1662 worker_list_cleanup(udev);
1663 event_queue_cleanup(udev, EVENT_UNDEF);
1664 udev_rules_unref(rules);
1665 udev_builtin_exit(udev);
1666 if (fd_signal >= 0)
1667 close(fd_signal);
1668 if (worker_watch[READ_END] >= 0)
1669 close(worker_watch[READ_END]);
1670 if (worker_watch[WRITE_END] >= 0)
1671 close(worker_watch[WRITE_END]);
1672 udev_monitor_unref(monitor);
1673 udev_queue_export_unref(udev_queue_export);
1674 udev_ctrl_connection_unref(ctrl_conn);
1675 udev_ctrl_unref(udev_ctrl);
1676 udev_selinux_exit(udev);
1677 udev_unref(udev);
1678 udev_log_close();
1679 return rc;
1680 }
File src/udevd.xml added (mode: 100644) (index 0000000..c516eb9)
1 <?xml version='1.0'?>
2 <?xml-stylesheet type="text/xsl" href="http://docbook.sourceforge.net/release/xsl/current/xhtml/docbook.xsl"?>
3 <!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
4 "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
5
6 <refentry id="udevd">
7 <refentryinfo>
8 <title>udevd</title>
9 <productname>udev</productname>
10 </refentryinfo>
11
12 <refmeta>
13 <refentrytitle>udevd</refentrytitle>
14 <manvolnum>8</manvolnum>
15 <refmiscinfo class="version"></refmiscinfo>
16 </refmeta>
17
18 <refnamediv>
19 <refname>udevd</refname><refpurpose>event managing daemon</refpurpose>
20 </refnamediv>
21
22 <refsynopsisdiv>
23 <cmdsynopsis>
24 <command>udevd</command>
25 <arg><option>--daemon</option></arg>
26 <arg><option>--debug</option></arg>
27 <arg><option>--children-max=</option></arg>
28 <arg><option>--exec-delay=</option></arg>
29 <arg><option>--resolve-names=early|late|never</option></arg>
30 <arg><option>--version</option></arg>
31 <arg><option>--help</option></arg>
32 </cmdsynopsis>
33 </refsynopsisdiv>
34
35 <refsect1><title>Description</title>
36 <para>udevd listens to kernel uevents. For every event, udevd executes matching
37 instructions specified in udev rules. See <citerefentry>
38 <refentrytitle>udev</refentrytitle><manvolnum>7</manvolnum>
39 </citerefentry>.</para>
40 <para>On startup the content of the directory <filename>/usr/lib/udev/devices</filename>
41 is copied to <filename>/dev</filename>. If kernel modules specify static device
42 nodes, these nodes are created even without a corresponding kernel device, to
43 allow on-demand loading of kernel modules. Matching permissions specified in udev
44 rules are applied to these static device nodes.</para>
45 <para>The behavior of the running daemon can be changed with
46 <command>udevadm control</command>.</para>
47 </refsect1>
48
49 <refsect1><title>Options</title>
50 <variablelist>
51 <varlistentry>
52 <term><option>--daemon</option></term>
53 <listitem>
54 <para>Detach and run in the background.</para>
55 </listitem>
56 </varlistentry>
57 <varlistentry>
58 <term><option>--debug</option></term>
59 <listitem>
60 <para>Print debug messages to stderr.</para>
61 </listitem>
62 </varlistentry>
63 <varlistentry>
64 <term><option>--children-max=</option></term>
65 <listitem>
66 <para>Limit the number of parallel executed events.</para>
67 </listitem>
68 </varlistentry>
69 <varlistentry>
70 <term><option>--exec-delay=</option></term>
71 <listitem>
72 <para>Number of seconds to delay the execution of RUN instructions.
73 This might be useful when debugging system crashes during coldplug
74 cause by loading non-working kernel modules.</para>
75 </listitem>
76 </varlistentry>
77 <varlistentry>
78 <term><option>--resolve-names=</option></term>
79 <listitem>
80 <para>Specify when udevd should resolve names of users and groups.
81 When set to <option>early</option> (the default) names will be
82 resolved when the rules are parsed. When set to
83 <option>late</option> names will be resolved for every event.
84 When set to <option>never</option> names will never be resolved
85 and all devices will be owned by root.</para>
86 </listitem>
87 </varlistentry>
88 <varlistentry>
89 <term><option>--version</option></term>
90 <listitem>
91 <para>Print version number.</para>
92 </listitem>
93 </varlistentry>
94 <varlistentry>
95 <term><option>--help</option></term>
96 <listitem>
97 <para>Print help text.</para>
98 </listitem>
99 </varlistentry>
100 </variablelist>
101 </refsect1>
102
103 <refsect1><title>Environment</title>
104 <variablelist>
105 <varlistentry>
106 <term><varname>UDEV_LOG=</varname></term>
107 <listitem>
108 <para>Set the logging priority.</para>
109 </listitem>
110 </varlistentry>
111 </variablelist>
112 </refsect1>
113
114 <refsect1><title>Kernel command line</title>
115 <variablelist>
116 <varlistentry>
117 <term><varname>udev.log-priority=</varname></term>
118 <listitem>
119 <para>Set the logging priority.</para>
120 </listitem>
121 </varlistentry>
122 <varlistentry>
123 <term><varname>udev.children-max=</varname></term>
124 <listitem>
125 <para>Limit the number of parallel executed events.</para>
126 </listitem>
127 </varlistentry>
128 <varlistentry>
129 <term><varname>udev.exec-delay=</varname></term>
130 <listitem>
131 <para>Number of seconds to delay the execution of RUN instructions.
132 This might be useful when debugging system crashes during coldplug
133 cause by loading non-working kernel modules.</para>
134 </listitem>
135 </varlistentry>
136 </variablelist>
137 </refsect1>
138
139 <refsect1><title>Author</title>
140 <para>Written by Kay Sievers <email>kay.sievers@vrfy.org</email>.</para>
141 </refsect1>
142
143 <refsect1>
144 <title>See Also</title>
145 <para><citerefentry>
146 <refentrytitle>udev</refentrytitle><manvolnum>7</manvolnum>
147 </citerefentry>, <citerefentry>
148 <refentrytitle>udevadm</refentrytitle><manvolnum>8</manvolnum>
149 </citerefentry></para>
150 </refsect1>
151 </refentry>
Hints:
Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://rocketgit.com/user/sylware/mudev

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@ssh.rocketgit.com/user/sylware/mudev

Clone this repository using git:
git clone git://git.rocketgit.com/user/sylware/mudev

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a merge request:
... clone the repository ...
... make some changes and some commits ...
git push origin main