diff options
author | Kay Sievers <kay.sievers@vrfy.org> | 2012-04-03 21:08:04 +0200 |
---|---|---|
committer | Kay Sievers <kay.sievers@vrfy.org> | 2012-04-03 21:08:04 +0200 |
commit | 19c5f19d69bb5f520fa7213239490c55de06d99d (patch) | |
tree | 0066ff6b95da3b86812f72f771fd09bab25d4e7a | |
parent | 3eff4208ffecedd778fec260f0d4b18e94dab443 (diff) | |
parent | 4db539b27021dcaa716828cbb689f591adb5af23 (diff) |
import udev repository
210 files changed, 43585 insertions, 0 deletions
diff --git a/src/udev/.gitignore b/src/udev/.gitignore new file mode 100644 index 000000000..fa3500ba9 --- /dev/null +++ b/src/udev/.gitignore | |||
@@ -0,0 +1,40 @@ | |||
1 | *~ | ||
2 | *.o | ||
3 | *.a | ||
4 | *.lo | ||
5 | *.la | ||
6 | .libs | ||
7 | .deps | ||
8 | .dirstamp | ||
9 | Makefile | ||
10 | Makefile.in | ||
11 | /aclocal.m4 | ||
12 | /autom4te.cache | ||
13 | /config.h | ||
14 | /config.h.in | ||
15 | /config.log | ||
16 | /config.status | ||
17 | /config.guess | ||
18 | /config.sub | ||
19 | /libtool | ||
20 | /ltmain.sh | ||
21 | /install-sh | ||
22 | /missing | ||
23 | /configure | ||
24 | /stamp-h1 | ||
25 | /depcomp | ||
26 | /gtk-doc.make | ||
27 | /build-aux | ||
28 | /udev-test-install | ||
29 | /udevd | ||
30 | /udevadm | ||
31 | /test-udev | ||
32 | /test-libudev | ||
33 | /accelerometer | ||
34 | /ata_id | ||
35 | /cdrom_id | ||
36 | /collect | ||
37 | /mtd_probe | ||
38 | /v4l_id | ||
39 | /keymap | ||
40 | /scsi_id | ||
diff --git a/src/udev/.vimrc b/src/udev/.vimrc new file mode 100644 index 000000000..366fbdca4 --- /dev/null +++ b/src/udev/.vimrc | |||
@@ -0,0 +1,4 @@ | |||
1 | " 'set exrc' in ~/.vimrc will read .vimrc from the current directory | ||
2 | set tabstop=8 | ||
3 | set shiftwidth=8 | ||
4 | set expandtab | ||
diff --git a/src/udev/COPYING b/src/udev/COPYING new file mode 100644 index 000000000..d159169d1 --- /dev/null +++ b/src/udev/COPYING | |||
@@ -0,0 +1,339 @@ | |||
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. | ||
diff --git a/src/udev/ChangeLog b/src/udev/ChangeLog new file mode 100644 index 000000000..dd5813826 --- /dev/null +++ b/src/udev/ChangeLog | |||
@@ -0,0 +1,6387 @@ | |||
1 | Summary of changes from v181 to v182 | ||
2 | ============================================ | ||
3 | |||
4 | Kay Sievers (22): | ||
5 | build-sys: unpack test sysfs only for 'make check' | ||
6 | build-sys: add --disable-manpages | ||
7 | update sd-daemon files | ||
8 | test: remove outdated key attributes | ||
9 | update TOO | ||
10 | builtin: path_id - remove dead cciss code | ||
11 | rules: do not create by-id/scsi-* links for ATA devices | ||
12 | remove udev-acl | ||
13 | udev.conf - do not set any value by default | ||
14 | move src/extras subdirectories to src/ | ||
15 | rules: delete outdated 30-kernel-compat.rules | ||
16 | rules: move 42-qemu-usb.rules to rules/ dir | ||
17 | remove edd_id extra | ||
18 | build-sys: remove empty directory | ||
19 | rules: delete s390 rules, they will move to s390utils | ||
20 | update TODO | ||
21 | rules: move all rules to top level rules/ dir | ||
22 | extras: path_id - skip ATA transport class devices | ||
23 | extras: path_id - add comment about readdir() rebase logic | ||
24 | extras: ata_id - do not log error if HDIO_GET_IDENTITY fails | ||
25 | rules sort order: /lib, /run, /etc | ||
26 | build-sys: place build binaries in the root | ||
27 | |||
28 | Matthew Garrett (1): | ||
29 | rules: Enable USB autosuspend on more USB HID devices | ||
30 | |||
31 | |||
32 | Summary of changes from v180 to v181 | ||
33 | ============================================ | ||
34 | |||
35 | Andreas Schwab (1): | ||
36 | ata_id: fix identify string fixup | ||
37 | |||
38 | Bruno Redondi (1): | ||
39 | keymap: Add Fujitsu Siemens Amilo Li 2732 | ||
40 | |||
41 | James M. Leddy (1): | ||
42 | keymap: Fix touchpad toggle button on Lenovo Ideapad | ||
43 | |||
44 | Kay Sievers (4): | ||
45 | configure: show ROOTPREFIX in firmware path option help text | ||
46 | extras: cdrom_id - create /dev/cdrom and conditionally /dev/dvd for sr0 | ||
47 | extras: cdrom_id - create only /dev/cdrom | ||
48 | ata_id: whitespace fixes | ||
49 | |||
50 | Lucas De Marchi (1): | ||
51 | builtin: kmod - depend on libkmod >= 5 | ||
52 | |||
53 | |||
54 | Summary of changes from v179 to v180 | ||
55 | ============================================ | ||
56 | |||
57 | Kay Sievers (4): | ||
58 | Makefile: update kernel.org hooks | ||
59 | build-sys: we need to install shipped man pages without xsltproc installed | ||
60 | builtin: blkid - add missing ID_ prefix for PART_ENTRY_* keys | ||
61 | do not stop rule processing when device node is no longer around | ||
62 | |||
63 | |||
64 | Summary of changes from v178 to v179 | ||
65 | ============================================ | ||
66 | |||
67 | Kay Sievers (8): | ||
68 | fix some fallout from tab removal | ||
69 | use devnode() for $name not sysname(), device nodes might be in a subdirectory | ||
70 | print warning when rules try to rename kernel device nodes | ||
71 | move variable inside condition | ||
72 | update TODO | ||
73 | build-sys: enable everything for 'make distcheck' | ||
74 | use sysname() for devices without a device node | ||
75 | fix path to extras | ||
76 | |||
77 | |||
78 | Summary of changes from v177 to v178 | ||
79 | ============================================ | ||
80 | |||
81 | Evan Nemerson (1): | ||
82 | gudev: several minor introspection fixes | ||
83 | |||
84 | Kay Sievers (7): | ||
85 | Makefile: update kernel.org doc hooks for kup | ||
86 | builtin: blkid - add missing ID_ prefix | ||
87 | udevd: kill hanging event processes after 30 seconds | ||
88 | Makefile: switch from .asc to .sign | ||
89 | rules: rtc - point /dev/rtc symlink to 'hctosys' device | ||
90 | warn about deprecated RUN+="socket:" use | ||
91 | libudev: do not set DEVNAME= twice | ||
92 | |||
93 | Martin Pitt (4): | ||
94 | keymap: Fix rfkill button on Hewlett-Packard HP ProBook | ||
95 | keymap: Fix eject button on Samsung 700Z series | ||
96 | keymap: Fix keyboard brightness keys on Samsung 700Z series | ||
97 | keymap: Add Alienware M14xR1 | ||
98 | |||
99 | |||
100 | Summary of changes from v176 to v177 | ||
101 | ============================================ | ||
102 | |||
103 | Kay Sievers (3): | ||
104 | Makefile: update kernel.org sign and upload hook | ||
105 | rule_generator: fix to install rules in rules.d/ | ||
106 | rule_generator: use += for dist_udevhome_DATA | ||
107 | |||
108 | |||
109 | Summary of changes from v175 to v176 | ||
110 | ============================================ | ||
111 | |||
112 | Alan Stern (1): | ||
113 | [PATCH[ udev: ata_id: Fix length of INQUIRY command | ||
114 | |||
115 | Kay Sievers (61): | ||
116 | libudev: print log_fn address instead of ctx when setting logging function | ||
117 | do not ship autogen.sh in the tarball | ||
118 | man: clarify 'config file stack' | ||
119 | rename 'init' directory to 'systemd' | ||
120 | systemd: use PassCred=yes | ||
121 | use libexecdir, bindir, sbindir, switch to /usr/lib/udev in documentation | ||
122 | configure: fix typo | ||
123 | make: do not (mis-)use the config file generator, create .xz tarball | ||
124 | prepare builtins for blkid and kmod | ||
125 | add builtin load/unload initializers | ||
126 | build argv[] for builtin commands | ||
127 | update blkid builtin | ||
128 | rules: switch to built-in blkid | ||
129 | rules: do not preprocess 60-persistent-storage.rules | ||
130 | buildsys: disable tar.gz | ||
131 | builtin: blkid - add missing newline | ||
132 | builtin: blkid - add missing ID_FS_USAGE | ||
133 | builtin: kmod - switch modprobe to builtin | ||
134 | rules: do not preprocess 80-drivers.rules + 75-probe_mtd.rules | ||
135 | builtin: apply format string | ||
136 | remove last sbindir use | ||
137 | update NEWS | ||
138 | autogen.sh: moce CFLAGS from to configure.ac; print common ./configure options | ||
139 | builtin: kmod - link against libkmod | ||
140 | add copyright | ||
141 | builtin: kmod - reload index when rules are reloaded | ||
142 | builtin: rename load()/unload() to init()/exit() | ||
143 | invalidate rules and kmod index with 'udevadm control --reload' | ||
144 | update NEWS | ||
145 | builtin: firmware - move 'firmware' tool to builtins | ||
146 | builtin: firmware - add missing file | ||
147 | builtin: kmod - hook up udev main logging to libkmod | ||
148 | make: introduce --with-rootprefix= | ||
149 | update NEWS | ||
150 | move rules dirs to udev context; replace inotify with time-controlled stat() | ||
151 | udevd: always create runtime dir | ||
152 | builtin: move usb-db, pci-db to builtins | ||
153 | builtin: kmod - switch to kmod_module_probe_insert_module() | ||
154 | udevd: remove TIMEOUT= handling | ||
155 | update README | ||
156 | systemd: rename PassCred= to PsssCredentials= | ||
157 | remove mknod() logic and rely on 'devtmpfs' | ||
158 | builtin: kmod - hook up kmod_validate_resources() | ||
159 | build-sys: use use ${ac_default_prefix} | ||
160 | require kmod >= 3 | ||
161 | build-sys: use --libexecdir=/usr/lib instead of /usr/lib/udev | ||
162 | autogen.sh: enable git pre-commit | ||
163 | merge udev/, libudev/, systemd/ files in src/; move extras/ to src/ | ||
164 | replace unpacked sysfs test tree 'test/sys/' with packed tarball | ||
165 | rules: delete arch specific rules | ||
166 | doc: fix out of tree build (copy from libkmod) | ||
167 | autogen.sh: add CFLAGS and print entire line, so that mouse copy/paste works | ||
168 | build-sys: try to build without installed xsltproc | ||
169 | add test/src to .gitignore | ||
170 | tabs are as useful as a hole in the head | ||
171 | autogen.sh: makedev() misteriously breaks with -O0 here, use -O1 for now | ||
172 | fix debug message | ||
173 | add .vimrc | ||
174 | cdrom_id: int -> bool | ||
175 | fix compiler warning | ||
176 | man: mention that no daemons should be started by udev | ||
177 | |||
178 | Lucas De Marchi (1): | ||
179 | builtin: kmod - log if modules are blacklisted | ||
180 | |||
181 | Luis Felipe Strano Moraes (1): | ||
182 | Switch spawn_read to void and remove useless stores there. | ||
183 | |||
184 | Martin Pitt (1): | ||
185 | 75-persistent-net-generator.rules: Add Xen | ||
186 | |||
187 | Mike Frysinger (1): | ||
188 | hwdb: drop useless line freeing | ||
189 | |||
190 | Sjoerd Simons (1): | ||
191 | keymap: Add Lenovo Thinkpad X220 Tablet | ||
192 | |||
193 | Ville Skyttä (1): | ||
194 | man: spelling fix | ||
195 | |||
196 | |||
197 | Summary of changes from v174 to v175 | ||
198 | ============================================ | ||
199 | |||
200 | David Zeuthen (2): | ||
201 | gudev: Use strtoul to parse unsigned 64-bit integers | ||
202 | gudev: Use g_ascii_strtoull() instead of strtoul() | ||
203 | |||
204 | Harald Hoyer (1): | ||
205 | extras/keymap/findkeyboards: beautify shell code and get rid of grep | ||
206 | |||
207 | Jerone Young (1): | ||
208 | keymap: Fix micmute remap for Lenovo Thinkpads | ||
209 | |||
210 | Kay Sievers (7): | ||
211 | make: add gpg signing bits | ||
212 | ignore entire rules line if unknown keys are used | ||
213 | do not skip /dev/{disk,char}/M:m removal when the device node is already gone | ||
214 | replace AC_DISABLE_STATIC with LT_INIT([disable-static]) | ||
215 | make: tweak some autofoo according to Flameeyes' recommendations for libabc | ||
216 | rules: restore rule to set cdrom group for optical drives | ||
217 | rules: fix typo | ||
218 | |||
219 | Martin Pitt (8): | ||
220 | check-keymaps.sh: Allow running separately | ||
221 | extras/keymap/findkeyboards: Filter out non-event devices | ||
222 | findkeyboards: Consistently use spaces instead of tabs | ||
223 | keymap: Fix stuck keys on GIGABYTE i1520M | ||
224 | keymap: More Asus module variants | ||
225 | keymap: Fix "internet" key on HP G62 | ||
226 | keymap: Fix bluetooth key on Acer TravelMate 7720 | ||
227 | keymap: Fix stuck keys on BenQ nScreen | ||
228 | |||
229 | |||
230 | Summary of changes from v173 to v174 | ||
231 | ============================================ | ||
232 | |||
233 | David Zeuthen (1): | ||
234 | ata_id: Check for Compact Flash card | ||
235 | |||
236 | Jerone Young (1): | ||
237 | Add mic mute keycode support for Lenovo Thinkpad USB keyboard | ||
238 | |||
239 | Kay Sievers (34): | ||
240 | gtk-doc: delete empty files | ||
241 | libudev: list - use binary search for list lookup | ||
242 | rules: move input_id to default rules | ||
243 | implement path_id, usb_id, input_id as built-in command | ||
244 | do not remove static nodes on module unload | ||
245 | rules: remove legacy rules for cdrom and usb printer | ||
246 | update TODO | ||
247 | preserve 'sticky bit' on 'add/change' events | ||
248 | libudev: util_get_sys_(subsystem,driver}() -> util_get_sys_core_link_value() | ||
249 | export USEC_INITIALIZED= and take timestamp on message receive time | ||
250 | libudev: udev_device_get_sysattr_value() return syspath of custom links | ||
251 | libudev: list - properly sort linked list not only the index | ||
252 | mknod: do not complain about existing node | ||
253 | update README | ||
254 | libudev: fix typo in documentation | ||
255 | rules: fuse: do not mount fusectl from udev rules | ||
256 | keymap: add genius keymap to Makefile | ||
257 | update NEWS | ||
258 | usb_id: can't use global variables when used as built-in | ||
259 | remove 'udevadm trigger --type=failed' and SYSFS, ID, BUS keys | ||
260 | libudev: export udev_util_encode_string() | ||
261 | update TODO | ||
262 | systemd: no not start udev in a container | ||
263 | systemd: no not start udev in a container | ||
264 | delete left-over files in extras/ | ||
265 | systemd: update drop-in sd-daemon files | ||
266 | udevadm: control - use /run/udev/control socket instead of abstract namespace one | ||
267 | udevd: control - no not delete socket file when --daemon is used | ||
268 | udev_ctrl_cleanup()- accept NULL as argument | ||
269 | update NEWS | ||
270 | udevd: install into /lib/udev instead of /sbin | ||
271 | udevd: add missing braces | ||
272 | systemd: use ConditionCapability=CAP_MKNOD instead of ConditionVirtualization=!container | ||
273 | rules: do not load sg module | ||
274 | |||
275 | Kir Kolyshkin (1): | ||
276 | keymap: add Genius SlimStar 320 | ||
277 | |||
278 | Martin Pitt (1): | ||
279 | keymap: Update Acer Aspire 5920g | ||
280 | |||
281 | Matthias Clasen (1): | ||
282 | make: allow to pass ${ACLOCAL_FLAGS} | ||
283 | |||
284 | Paul Fox (1): | ||
285 | keymap: update the OLPC keymap for correct function key behavior | ||
286 | |||
287 | Petr Uzel (1): | ||
288 | udevadm: settle - return failure if unknown option is given | ||
289 | |||
290 | Steve Langasek (1): | ||
291 | udevd: exit - process events before signals in worker | ||
292 | |||
293 | Thomas Hood (2): | ||
294 | keymap: Support keymap overrides in /etc/udev/keymaps | ||
295 | keymap: Support for microphone mute button on ThinkPad X220 et al | ||
296 | |||
297 | |||
298 | Summary of changes from v172 to v173 | ||
299 | ============================================ | ||
300 | |||
301 | Allin Cottrell (1): | ||
302 | configure: allow to disable mtd_probe | ||
303 | |||
304 | Kay Sievers (15): | ||
305 | make: fix 'make tar-sync' | ||
306 | udevd: use 'uptime' in debug timestamp | ||
307 | udevd: fix (recently) broken static node permission setting | ||
308 | rules: mount fuse filesystem only 'add' | ||
309 | udevadm: move udevadm command descriptions into their files | ||
310 | udev-acl: skip ACLs when systemd is running, disable by default | ||
311 | do not delete database when renaming netif, the db name does not change anymore | ||
312 | do not allow kernel properties to be set by udev rules | ||
313 | configure: reorder options | ||
314 | rules: input - do not create (broken) links for bluetooth devices | ||
315 | rules: serial - do not export ID_PORT, use ID_USB_INTERFACE_NUM | ||
316 | rules: sound - instead of ID_IFACE use standard ID_USB_INTERFACE_NUM | ||
317 | keymap: do not run usb_id for bluetooth devices | ||
318 | udevadm: trigger --type=failed - log deprecation warning | ||
319 | udevd: debug - put timestamp in [] | ||
320 | |||
321 | Martin Pitt (4): | ||
322 | gudev: Ship JavaScript examples | ||
323 | scsi_id: Ship README | ||
324 | Remove obsolete extras/scsi_id/scsi_id.config | ||
325 | keymap: Only run on key devices | ||
326 | |||
327 | |||
328 | Summary of changes from v171 to v172 | ||
329 | ============================================ | ||
330 | |||
331 | Bastien Nocera (3): | ||
332 | accelerometer: add orientation property | ||
333 | udev-acl: fix memleak | ||
334 | accelerometer: add documentation | ||
335 | |||
336 | Harald Hoyer (2): | ||
337 | udevadm-*.c: return != 0, if unknown option given | ||
338 | udev/udevadm-monitor.c: fixed misplaced brace | ||
339 | |||
340 | Kay Sievers (33): | ||
341 | rules: apply 'audio' group of the static snd/{seq,timer} nodes | ||
342 | Makefile: add tar-sync | ||
343 | rules: static_node - use 0660 if group is given to get the cigar | ||
344 | rule-syntax-check.py: use print() | ||
345 | make: use 'git tag' | ||
346 | rules: run input_id for main input devices too | ||
347 | update TODO | ||
348 | configure: add AC_CONFIG_AUX_DIR, AC_CONFIG_SRCDIR | ||
349 | cdrom_id: add tray lock and eject handling | ||
350 | rules: enable in-kernel media-presence polling | ||
351 | update TODO | ||
352 | delete mobile-action-modeswitch which has moved to usb_modeswitch | ||
353 | libudev: enumerate - scan /sys/module | ||
354 | rules: move polling rule above 'block' match | ||
355 | libudev: monitor - update doc | ||
356 | rules: set polling value only if it is disabled | ||
357 | libudev: device - fix udev_device_get_tags_list_entry() to always load database | ||
358 | rules: remove redundant MODE="0664" from lp rules | ||
359 | rules: fix wrong wildcard match, we always need a ':*' at the end | ||
360 | libudev: device - export udev_device_has_tag() | ||
361 | path_id: add missing '-' to tape suffix | ||
362 | path_id: add ID_PATH_TAG= to be used in udev tags | ||
363 | enforce valid TAG+= names | ||
364 | update TODO | ||
365 | libudev: device - add udev_device_has_tag() to libudev.h and gtk-doc | ||
366 | libudev: enumerate - add udev_enumerate_add_match_parent() | ||
367 | libudev: enumerate - include parent device itself with match_parent() | ||
368 | libudev: enumerate - clarify documentation | ||
369 | path_id: recognize ACPI parent devices | ||
370 | rules: input - call path_id for ACPI devices | ||
371 | udevadm: monitor - use uptime to match the kernel's timestamp | ||
372 | libudev: ctrl - move code to udev directory | ||
373 | update sd-daemon.[ch] | ||
374 | |||
375 | Keshav P.R (1): | ||
376 | rules: support for gpt partition uuid/label | ||
377 | |||
378 | Lee, Chun-Yi (1): | ||
379 | Support more MSI notebook by using asterisk on dmi vendor name | ||
380 | |||
381 | Marco d'Itri (1): | ||
382 | Add missing commas to 95-keymap.rules | ||
383 | |||
384 | Martin Pitt (3): | ||
385 | keymap: Add Microsoft Natural Keyboard | ||
386 | keymap: Add force-release quirk for Hannspree SN10. | ||
387 | keymap: Add slight name variations of Toshiba Satellites | ||
388 | |||
389 | Peter Jones (1): | ||
390 | ata_id: show the error message when HDIO_GET_IDENTITY fails | ||
391 | |||
392 | |||
393 | Summary of changes from v170 to v171 | ||
394 | ============================================ | ||
395 | |||
396 | Kay Sievers (17): | ||
397 | libudev: export symbols explicitely and individually from C code not from separate file or prefix match | ||
398 | libudev: device - make a bunch of symbols static | ||
399 | systemd: Replace Requires= with Wants=, run trigger in parallel | ||
400 | systemd: sort trigger after socket | ||
401 | systemd: trigger - run after udev.service (for now) | ||
402 | systemd: set socket buffer size to 128 MB like udev has | ||
403 | update TODO | ||
404 | update TODO | ||
405 | libudev: monitor - use SOCK_NONBLOCK | ||
406 | systemd: split socket file | ||
407 | systemd: add missing socket files | ||
408 | rules: fix whitespace | ||
409 | rules: implement TAGS== match | ||
410 | libudev: enumerate - do not ignore other matches when add_match_tag() is used | ||
411 | rules: support substitutions in TAG= | ||
412 | path_id: allow to be asked about usb_devices not only usb_interfaces | ||
413 | systemd: run udev.service and udev-trigger.service in parallel | ||
414 | |||
415 | Scott James Remnant (1): | ||
416 | configure: allow usb.ids location to be specified | ||
417 | |||
418 | |||
419 | Summary of changes from v169 to v170 | ||
420 | ============================================ | ||
421 | |||
422 | Kay Sievers (1): | ||
423 | libudev: ctrl - properly wait for incoming message after connect | ||
424 | |||
425 | Michal Soltys (1): | ||
426 | configure.ac: fixes for rule_generator and modeswitch | ||
427 | |||
428 | |||
429 | Summary of changes from v168 to v169 | ||
430 | ============================================ | ||
431 | |||
432 | Kay Sievers (26): | ||
433 | simplify rules file overwrite logic | ||
434 | libudev: list - use bit flags for 'sort' and 'unique' | ||
435 | libudev: queue - _unref() should return the object | ||
436 | remove dead fstab_import files | ||
437 | hid2hci: prepare move to bluez package | ||
438 | set event timeout to 60 sec and settle timeout to 120 | ||
439 | udevd: improve error message in case exec() fails | ||
440 | configure: allow to enable/disable extras individually | ||
441 | delete hid2hci which moved to the bluez tree | ||
442 | update TODO/NEWS | ||
443 | bump requirement to Linux kernel 2.6.32 and ARM 2.6.36 | ||
444 | libudev: ctrl - log accept4() errors | ||
445 | update NEWS | ||
446 | update INSTALL, NEWS, configure comment, queue doc | ||
447 | update TODO | ||
448 | udevd: create queue file before daemonizing to reliably block 'settle' | ||
449 | udevd: remove left-over SIGALRM | ||
450 | gudev: silent gtk-doc warnings | ||
451 | cdrom_id: remove unused --export switch to silent gcc | ||
452 | libudev: queue - always rebuild queue file when nothing is queued anymore | ||
453 | libudev: device - use DEVMODE from kernel as the default mode | ||
454 | update TODO | ||
455 | Merge branch 'docs/udev.xml' of git://github.com/mfwitten/udev | ||
456 | udate TODO, NEWS, INSTALL | ||
457 | build: use --gc-sections, -fvisibility=hidden | ||
458 | udevadm: settle: wake up more often if --seq-start= or --exit-if-exists= is used | ||
459 | |||
460 | Koen Kooi (1): | ||
461 | configure: reintroduce introspection flags to fix crosscompilation | ||
462 | |||
463 | Michael Witten (36): | ||
464 | Docs: udev.xml: Offset daemon name with commas | ||
465 | Docs: udev.xml: Remove commas (and unnecessary repetition) | ||
466 | Docs: udev.xml: `are' -> `is'; the subject is `Access' | ||
467 | Docs: udev.xml: Use present tense | ||
468 | Docs: udev.xml: Clarification through proper wording | ||
469 | Docs: udev.xml: `,' -> `;' | ||
470 | Docs: udev.xml: `key value' -> `key-value' | ||
471 | Docs: udev.xml: `,' -> `:' | ||
472 | Docs: udev.xml: Use `assignment' consistently | ||
473 | Docs: udev.xml: `comma-separated' is a better description | ||
474 | Docs: udev.xml: Remove unnecessary repitition | ||
475 | Docs: udev.xml: Add a few more words for context | ||
476 | Docs: udev.xml: Use `unless' for clarity | ||
477 | Docs: udev.xml: Clarify PROGRAM key | ||
478 | Docs: udev.xml: `a shell style' -> `shell-style' | ||
479 | Docs: udev.xml: Clean `*' description | ||
480 | Docs: udev.xml: Clean character range description | ||
481 | Docs: udev.xml: Clean up description of NAME assignment key | ||
482 | Docs: udev.xml: Clean up description of SYMLINK assignment key | ||
483 | Docs: udev.xml: Clean up description of ENV assignment key | ||
484 | Docs: udev.xml: Clean up description of RUN assignment key | ||
485 | Docs: udev.xml: Clean up description of LABEL assignment key | ||
486 | Docs: udev.xml: Add missing `.' | ||
487 | Docs: udev.xml: `which' -> `content of which' | ||
488 | Docs: udev.xml: `commandline' -> `command line' | ||
489 | Docs: udev.xml: Clean up WAIT_FOR description | ||
490 | Docs: udev.xml: `a' -> `the' | ||
491 | Docs: udev.xml: Clean up introduction to substitutions. | ||
492 | Docs: udev.xml: Use normal sentence structure | ||
493 | Docs: udev.xml: Actually make a separate paragraph | ||
494 | Docs: udev.xml: Add comma | ||
495 | Docs: udev.xml: `char' -> `character' | ||
496 | Docs: udev.xml: `comma-separated' is a better description | ||
497 | Docs: udev.xml: Clarify through a change in word ordering | ||
498 | Docs: udev.xml: Improved word order | ||
499 | Docs: udev.xml: Fix dangling modifier | ||
500 | |||
501 | Nix (1): | ||
502 | libudev: queue - accept NULL passed into udev_queue_export_cleanup() | ||
503 | |||
504 | |||
505 | Summary of changes from v167 to v168 | ||
506 | ============================================ | ||
507 | |||
508 | David Zeuthen (1): | ||
509 | Run ata_id on non-removable USB devices | ||
510 | |||
511 | Harald Hoyer (1): | ||
512 | udevd: clarify worker exit status | ||
513 | |||
514 | Kay Sievers (35): | ||
515 | version bump | ||
516 | systemd: let settle depend on trigger, do not block basic with trigger | ||
517 | selinux: do not label files in runtime dir | ||
518 | selinux: firmware - do not label files in runtime dir | ||
519 | udevadm: control - add --exit | ||
520 | trivial cleanups | ||
521 | udevd: log warning if /run is not writable | ||
522 | libudev: ctrl - fix refcounting in connection handling | ||
523 | udevadm: settle - watch queue file | ||
524 | libudev: bump revision | ||
525 | udevadm: info --cleanup-db | ||
526 | udevd: do not nice processes | ||
527 | "db_persist=" -> "db_persist" | ||
528 | udevd: move OOM disable into --daemon option | ||
529 | systemd: add OOMScoreAdjust=-1000 | ||
530 | require explicit "db_persist" to exclude device info from --db-cleanup | ||
531 | udevd: get netlink socket from systemd | ||
532 | fix more warnings | ||
533 | libudev: ctrl, monitor - use SOCK_NONBLOCK | ||
534 | systemd: socket -> sockets | ||
535 | udevadm: monitor - use epoll | ||
536 | libudev: test - use epoll | ||
537 | udevadm: test - use printf() instead of info() for non-debug output | ||
538 | use 'else if' in epoll event array loop | ||
539 | libudev: run_program() - select() -> epoll | ||
540 | udevd: ppoll() -> epoll + signalfd | ||
541 | Merge branch 'docs/README' of git://github.com/mfwitten/udev | ||
542 | timeout handling without alarm() | ||
543 | udevadm: settle - kill alarm() | ||
544 | udevd: netif rename - use ifindex for temporary name | ||
545 | udevd: always use udevd[] log prefix | ||
546 | udevd: rules files - accept empty or /dev/null links | ||
547 | udevd: log signal number when spawned processes fail | ||
548 | systemd: Reqires= -> Wants=udev.socket | ||
549 | udevd, udev-event: sync waitpid() error handling | ||
550 | |||
551 | Lee, Chun-Yi (1): | ||
552 | Add rule for Acer Aspire One ZG8 to use acer-aspire_5720 keymap | ||
553 | |||
554 | Leonid Antonenkov (1): | ||
555 | rule-generator: net - ignore Hyper-V virtual interfaces | ||
556 | |||
557 | Martin Pitt (3): | ||
558 | Revert "Do not build extras with --disable-extras" | ||
559 | Avoid spinning up CD on pressing eject button | ||
560 | keymap: Another ID for Logitech Wave keyboard | ||
561 | |||
562 | Michael Reed (1): | ||
563 | path_id: rework SAS device handling | ||
564 | |||
565 | Michael Witten (12): | ||
566 | Docs: README: `to replace' -> `replacing' | ||
567 | Docs: README: `,' -> `;' | ||
568 | Docs: README: Clean up a sentence | ||
569 | Docs: README: Use present tense | ||
570 | Docs: README: Add missing `and' | ||
571 | Docs: README: Remove commas and use subjective mood | ||
572 | Docs: README: Clean up `udev extras' requirements | ||
573 | Docs: README: Clarify configuration of existing devices | ||
574 | Docs: README: `does never apply' -> `never applies' | ||
575 | Docs: README: Flip sentence structure to improve wording | ||
576 | Docs: README: `set up' is the verb; `setup' is a noun | ||
577 | Docs: README: Add a comma to offset the modifier | ||
578 | |||
579 | Seth Forshee (1): | ||
580 | keymap: Support Dell Latitude XT2 tablet-mode navigation keys | ||
581 | |||
582 | Thomas Egerer (1): | ||
583 | udevd: add 'N:' to optstring in getopt_long | ||
584 | |||
585 | |||
586 | Summary of changes from v166 to v167 | ||
587 | ============================================ | ||
588 | |||
589 | Andrey Borzenkov (1): | ||
590 | udev-acl: add /dev/sgX nodes for CD-ROM | ||
591 | |||
592 | David Zeuthen (1): | ||
593 | cdrom_id: Don't ignore profiles when there is no media available | ||
594 | |||
595 | Harald Hoyer (2): | ||
596 | cdrom_id: cd_media_toc() extend toc size to 65536 | ||
597 | udev-acl/70-acl.rules: tag ID_REMOTE_CONTROL with acl | ||
598 | |||
599 | Kay Sievers (29): | ||
600 | version bump | ||
601 | Merge branch 'master' of git+ssh://master.kernel.org/pub/scm/linux/hotplug/udev | ||
602 | v4l_id: kill the v4l1 ioctl | ||
603 | v4l_id: remove left-over variable | ||
604 | update some comments | ||
605 | test-libudev: add short options | ||
606 | libudev: udev_device_get_sysattr_list_entry() update | ||
607 | libudev: resolve ifindex in udev_device_new_from_id_filename() | ||
608 | libudev: bump minor version | ||
609 | udev-acl: move sg rule to optical drive rule | ||
610 | move /dev/.udev/ to /dev/.run/udev/ and convert old udev database at udevd startup | ||
611 | NEWS: clarify /dev/.run/ requirements | ||
612 | input_id: silent gcc warnings | ||
613 | fstab_import: disable build | ||
614 | systemd: remove deprecated udev-retry.service | ||
615 | fstab_import: remove from configure | ||
616 | update sd-daemon.[ch] | ||
617 | udevd: use facility == LOG_DAEMON when writing to /dev/kmsg | ||
618 | udevd: initialize fds, for proper close() on exit | ||
619 | use /run/udev/ if possible and fall back to /dev/.udev/ | ||
620 | rules: run ata_id only on SPC-3 or later optical drives | ||
621 | systemd: bind udev control socket in systemd and split udev.service | ||
622 | systemd: use sockets.target not socket.target | ||
623 | man: remove trigger --type=failed handling | ||
624 | libudev: export udev_get_run_path() | ||
625 | libudev: docs - add udev_get_run_path() | ||
626 | libudev: make valgrind happy | ||
627 | systemd: do not enable udev-settle.service by default | ||
628 | systemd: udev.socket - disable implicit dependencies | ||
629 | |||
630 | Kei Tokunaga (1): | ||
631 | udevadm: enumerate - update prev pointer properly | ||
632 | |||
633 | Lee, Chun-Yi (2): | ||
634 | Remap Acer WMI touchpad toggle key to F21 used by X | ||
635 | Remap MSI Laptop touchpad on/off key to F22 and F23 | ||
636 | |||
637 | Martin Pitt (12): | ||
638 | 60-persistent-input.rules: Support multiple interfaces | ||
639 | Only build v4l_id if V4L1 header file is available | ||
640 | 60-persistent-input.rules: Do not create duplicate links | ||
641 | Fix building with --disable-extras | ||
642 | Do not build extras with --disable-extras | ||
643 | v4l_id: Drop videodev.h check again | ||
644 | keymap: Fix Acer Aspire 5920G media key | ||
645 | input_id: Consistently use tabs for indentation | ||
646 | input_id: Add some debugging output | ||
647 | input_id: Avoid memory overflow with too long capability masks | ||
648 | input_id: Cover key devices which only have KEY_* > 255 | ||
649 | input_id: Rewrite debug logging to use standard udev info() | ||
650 | |||
651 | Seth Forshee (1): | ||
652 | keymap: continue reading keymap after invalid scancodes | ||
653 | |||
654 | Thomas Egerer (3): | ||
655 | libudev: allow to get list of all available sysfs attrs for a device | ||
656 | libudev: use sysfs attr ilist interface for attribute walk | ||
657 | udevadm: info - make attribute array static and const | ||
658 | |||
659 | |||
660 | Summary of changes from v165 to v166 | ||
661 | ============================================ | ||
662 | |||
663 | Chris Bagwell (1): | ||
664 | Remap Eee PC touchpad toggle key to F21 used by X | ||
665 | |||
666 | Gerd Hoffmann (1): | ||
667 | extras: add rules for qemu guests | ||
668 | |||
669 | Jürgen Kaiser (1): | ||
670 | keymap: Add Acer Aspire 8930 | ||
671 | |||
672 | Kay Sievers (7): | ||
673 | version bump | ||
674 | man: generate html pages for www.kernel.org | ||
675 | man: fix typo | ||
676 | make: fix qemu rules file name | ||
677 | extras: qemu - fix typo | ||
678 | ata_id: do not print empty serial numbers to avoid unwanted trailing '_' | ||
679 | update gitignore | ||
680 | |||
681 | Martin Pitt (6): | ||
682 | keymap: Add Acer TravelMate C310 | ||
683 | keymap: Update README.keymap.txt | ||
684 | keymap: Add Lenovo ThinkPad X201 tablet | ||
685 | keymap: Move reading of event in separate function | ||
686 | keymap: More robust state machine | ||
687 | keymap: Explain how to end the program | ||
688 | |||
689 | Matthew Garrett (1): | ||
690 | keymap: Remove wlan from Dell | ||
691 | |||
692 | |||
693 | Summary of changes from v164 to v165 | ||
694 | ============================================ | ||
695 | |||
696 | Andy Whitcroft (1): | ||
697 | keymap: Add release quirks for two Zepto Znote models and AMILO Xi 2428 | ||
698 | |||
699 | Bastien Nocera (2): | ||
700 | keymap: Add force release for HP touchpad off | ||
701 | extras/keymap: Make touchpad buttons consistent | ||
702 | |||
703 | David Henningsson (1): | ||
704 | Add ACLs for FFADO supported sound cards | ||
705 | |||
706 | David Zeuthen (6): | ||
707 | ata_id: Support SG_IO version 4 interface | ||
708 | Run scsi_id and ata_id on the scsi_device object | ||
709 | Use ata_id, not scsi_id, on ATAPI devices | ||
710 | Add GUdevEnumerator type and Device.get_tags() method | ||
711 | Add g_udev_device_get_is_initialized() method | ||
712 | gudev: Add Device.get_usec_since_initialized | ||
713 | |||
714 | Harald Hoyer (2): | ||
715 | udev-rules.c: change import property buffer to 16384 bytes | ||
716 | 70-acl.rules: add ACLs for ID_PDA devices | ||
717 | |||
718 | Jakub Wilk (1): | ||
719 | man: udev - workaraound -> workaround | ||
720 | |||
721 | Jan Drzewiecki (1): | ||
722 | cdrom_id: Fix media state for unreadable DVDs | ||
723 | |||
724 | Kay Sievers (19): | ||
725 | version bump | ||
726 | rules: 78-sound-card - remove specific hardware matches, they do not belong here | ||
727 | rules: drop OSS audio rule | ||
728 | rules: drop alsa jack-plug input devices | ||
729 | rules: revert bsg use until the event ordering problem is sorted out | ||
730 | libudev: do not overwrite path with readlink() call | ||
731 | udevadm: info - honor --export and --export-prefix for property query | ||
732 | udevadm: info - honor --export, --export-prefix= | ||
733 | udevd: use dev_t or netif ifindex as database key | ||
734 | udevd: always create /dev/{char,block}/$major:$minor | ||
735 | udevd: simplify udev database and fix DEVNAME handling | ||
736 | udevd: switch to common id_filename functions | ||
737 | udevd: write full database file for (unsupported) renamed device nodes | ||
738 | check ifindex > 0 instead of subsystem == "net" | ||
739 | libudev: enumerate - allow to filter-out not-already-initialized devices | ||
740 | libudev: fix renamed device nodes detection logic | ||
741 | libudev: record and export "age" of device record | ||
742 | gudev: bump minor version | ||
743 | update NEWS | ||
744 | |||
745 | Martin Pitt (5): | ||
746 | keymap: Add Sony Vaio VGN71 | ||
747 | keymap: Add some more Sony Vaio VGN-* models | ||
748 | Add ACL for media player USB devices | ||
749 | keymap: Fix struck Touchpad key on Dell Latitude E series | ||
750 | keymap: Fix struck Touchpad key on Dell Precision M series | ||
751 | |||
752 | Michal Soltys (1): | ||
753 | udevd: create static nodes before /dev/null is needed | ||
754 | |||
755 | |||
756 | Summary of changes from v163 to v164 | ||
757 | ============================================ | ||
758 | |||
759 | David Zeuthen (1): | ||
760 | Install libgudev-1.0.so in prefix / instead of prefix /usr | ||
761 | |||
762 | Harald Hoyer (1): | ||
763 | cdrom_id: request the drive profile features with a dynamic length | ||
764 | |||
765 | Kay Sievers (4): | ||
766 | version bump | ||
767 | udevd: do not wrongly delay events for devices with swapped names | ||
768 | return proper error code in rename_netif() | ||
769 | libudev: return kernel provided devnode when asked before we handled any rules | ||
770 | |||
771 | Martin Pitt (2): | ||
772 | keymap: Apply force-release rules to all Samsung models. | ||
773 | keymap: Add Toshiba Satellite U500 | ||
774 | |||
775 | |||
776 | Summary of changes from v162 to v163 | ||
777 | ============================================ | ||
778 | |||
779 | David Zeuthen (2): | ||
780 | gudev: Deliver ::uevent signal in the thread-default main loop | ||
781 | Bump required GLib version to 2.22 | ||
782 | |||
783 | Hannes Reinecke (1): | ||
784 | scsi_id: export target port group | ||
785 | |||
786 | Kay Sievers (5): | ||
787 | version bump | ||
788 | scsi_id: fix compiler warnings | ||
789 | systemd: hook into basic.target instead of sysinit.target | ||
790 | systemd: sort before basic.target | ||
791 | udevd: add sd-daemon.c | ||
792 | |||
793 | Lee, Chun-Yi (1): | ||
794 | keymap: Add alternate MSI vendor name | ||
795 | |||
796 | Martin Pitt (8): | ||
797 | keymap: Add Lenovo Y550 | ||
798 | Clarify WAIT_FOR documentation | ||
799 | fix various syntax errors in rules | ||
800 | Add automatic rules syntax check | ||
801 | cdrom_id: Try reading the medium if all MMC commands fail | ||
802 | Revert "cdrom_id: Try reading the medium if all MMC commands fail" | ||
803 | cdrom_id: Fall back to CDROM_DRIVE_STATUS if all MMC commands fail | ||
804 | cdrom_id: Don't read beyond "last track" in TOC | ||
805 | |||
806 | Torsten Schoenfeld (1): | ||
807 | gudev: add a few annotations that newer gobject-introspection versions demand | ||
808 | |||
809 | |||
810 | Summary of changes from v161 to v162 | ||
811 | ============================================ | ||
812 | |||
813 | David Woodhouse (1): | ||
814 | Add keymap for Lenovo IdeaPad S10-3 | ||
815 | |||
816 | Jan Drzewiecki (2): | ||
817 | cdrom_id: Drop MEDIA_SESSION_NEXT for DVD-RW-RO | ||
818 | cdrom_id: Fix DVD blank detection for sloppy firmware | ||
819 | |||
820 | Kay Sievers (10): | ||
821 | init: update systemd service files | ||
822 | init: update systemd service files | ||
823 | init: add 'udev -' to description in systemd service files | ||
824 | udevd: add pid to kmsg logs | ||
825 | init: edit systemd service descriptions | ||
826 | version bump | ||
827 | udevd: remove unneeded credential passing from init_notify() | ||
828 | set SELinux context on 'add' but not on 'change' events | ||
829 | systemd: enable all udev services unconditionally | ||
830 | Revert "Add alternative KVM MAC address blacklist" | ||
831 | |||
832 | Luca Tettamanti (1): | ||
833 | Add support for oom_score_adj | ||
834 | |||
835 | Marco d'Itri (2): | ||
836 | udev-acl: do not mistake all SCSI "processor" devices for scanner | ||
837 | do not create persistent name rules for KVM network interfaces | ||
838 | |||
839 | Martin Pitt (12): | ||
840 | cdrom_id: Add media status debugging | ||
841 | udev(7): Point out required extension, and remove some confusion | ||
842 | keymap: Add Onkyo PC | ||
843 | keymap: Add HP G60 | ||
844 | keymap: Fix Sony VAIO VGN-SZ2HP/B | ||
845 | udev(7) manpage: Fix description of $attr | ||
846 | gudev: fix crash if netlink is not available | ||
847 | keymap: Fix Acer TravelMate 4720 | ||
848 | cdrom_id: Fix DVD-RW media detection | ||
849 | Fix KVM MAC address range | ||
850 | do not create persistent name rules for VMWare network interfaces | ||
851 | Add alternative KVM MAC address blacklist | ||
852 | |||
853 | Michael Forney (1): | ||
854 | Don't install systemd scripts with --without-systemdsystemunitdir | ||
855 | |||
856 | Michal Soltys (1): | ||
857 | ChangeLog fix | ||
858 | |||
859 | |||
860 | Summary of changes from v160 to v161 | ||
861 | ============================================ | ||
862 | |||
863 | Fortunato Ventre (1): | ||
864 | keymap: Add force-release quirks for a lot more Samsung models | ||
865 | |||
866 | Harald Hoyer (3): | ||
867 | udev-event.c: rename interface to <src>-<dest>, if <dest> taken | ||
868 | rule_generator/write_net_rules: prevent interface to be named "eth" | ||
869 | cdrom_id: READ TOC before READ DISC INFORMATION fixes qemu | ||
870 | |||
871 | Jan Drzewiecki (5): | ||
872 | cdrom_id: Fix detection of reblanked DVD+RW and DVD-RAM | ||
873 | cdrom_id: Handle pre-MMC2 drives | ||
874 | cdrom_id: Also apply format check to DVD-RW | ||
875 | cdrom_id: No "next session" for "other" media state | ||
876 | cdrom_id: Fix state for fresh DVD-RW | ||
877 | |||
878 | Jerone Young (1): | ||
879 | Fix volume keys not releasing on Mivvy G310 | ||
880 | |||
881 | Kay Sievers (12): | ||
882 | version bump | ||
883 | rules: remove firewire rules for deprecated drivers | ||
884 | udev-acl: update firewire matches to recent rule changes | ||
885 | libudev: bump minor so version after adding symbols | ||
886 | call util_delete_path() only when we actually deleted stuff | ||
887 | udev-acl: properly handle CK change events for root user | ||
888 | udev-acl: remove specific device matches from the rules file | ||
889 | fix broken "compile warning fix" | ||
890 | always log error when renaming a network interface fails | ||
891 | do not rename the database on device rename | ||
892 | cdrom_id: whitespace fix | ||
893 | cdrom_id: do not bail out when we can not read the TOC like for empty CDRW | ||
894 | |||
895 | Marco d'Itri (3): | ||
896 | hid2hci: fix Logitech diNovo, MX5500 and other keyboards | ||
897 | log an error when a message from the wrong version of udevadm is ignored | ||
898 | hid2hci: fix for Logitech diNovo Edge keyboard | ||
899 | |||
900 | Martin Pitt (1): | ||
901 | keymap: Generalize Samsung keymaps | ||
902 | |||
903 | Michal Schmidt (1): | ||
904 | udev-acl: really fix ACL assignment in CK events | ||
905 | |||
906 | Richard Hughes (1): | ||
907 | udev-acl: add DDC_DEVICE to the types that are managed | ||
908 | |||
909 | Stefan Richter (1): | ||
910 | rules: add more FireWire IDs: Point Grey IIDC; AV/C + vendor unique | ||
911 | |||
912 | Yin Kangkai (7): | ||
913 | udevadm: fix short options in getopt() | ||
914 | udevd: fix some memory leaks in error path | ||
915 | malloc()+memset() -> calloc() | ||
916 | udevd: fix short options in getopt() | ||
917 | udevd: fix unref'ing of device in error path | ||
918 | udevd: create static device links only when the target exists | ||
919 | udev: fix compile warning | ||
920 | |||
921 | |||
922 | Summary of changes from v159 to v160 | ||
923 | ============================================ | ||
924 | |||
925 | Harald Hoyer (2): | ||
926 | 60-persistent-storage-tape: s/path_id.sh/path_id/ | ||
927 | 60-persistent-storage-tape.rules: make own by-path symlink for nst tapes | ||
928 | |||
929 | Kay Sievers (4): | ||
930 | version bump | ||
931 | rules: tape - remove WAIT_FOR instruction and don't export BSG_DEV | ||
932 | allow final assignment for OPTIONS:="nowatch" | ||
933 | udevd: init_notify() fix abstract namespace name handling | ||
934 | |||
935 | Lennart Poettering (1): | ||
936 | systemd: make service files readable by GKeyFile | ||
937 | |||
938 | Martin Pitt (2): | ||
939 | keymap: Find alternate Lenovo module | ||
940 | keymap: Add Lenovo ThinkPad SL Series extra buttons | ||
941 | |||
942 | |||
943 | Summary of changes from v158 to v159 | ||
944 | ============================================ | ||
945 | |||
946 | Jerone Young (1): | ||
947 | Fix stuck volume key presses for Toshiba Satellite U300 & U305models | ||
948 | |||
949 | Kay Sievers (5): | ||
950 | version bump | ||
951 | add systemd service files | ||
952 | make: pre-process and install systemd service files when needed | ||
953 | make: fix 'make distcheck' | ||
954 | switch a few left-over from GPLv2 to GPLv2 or later | ||
955 | |||
956 | Lennart Poettering (1): | ||
957 | systemd: update service files for newly introduced DefaultDependencies= option | ||
958 | |||
959 | Martin Pitt (1): | ||
960 | keymap: Add Logitech Cordless Wave Pro | ||
961 | |||
962 | Matthew Garrett (1): | ||
963 | keymap: Add support for IBM-branded USB devices | ||
964 | |||
965 | Michael Meeks (1): | ||
966 | gudev: respect possibly given LD_LIBRARY_PATH | ||
967 | |||
968 | Ryan Harper (2): | ||
969 | Add virtio-blk support to path_id | ||
970 | Add virtio-blk by-id rules based on 'serial' attribute | ||
971 | |||
972 | |||
973 | Summary of changes from v157 to v158 | ||
974 | ============================================ | ||
975 | |||
976 | Harald Hoyer (1): | ||
977 | extras/keymap: add Samsung N210 to keymap rules | ||
978 | |||
979 | Kay Sievers (7): | ||
980 | version bump | ||
981 | libudev: fix fd leak in udev_enumerate_scan_devices() when tags are searched | ||
982 | udevd: in case we don't daemonize, send READY message to /sbin/init | ||
983 | delete last distro specific rules | ||
984 | remove a few comments in file headers | ||
985 | mtd_probe: add needed include, modprobe blacklist flag, and change some whitespace | ||
986 | rules: remove unused subdir | ||
987 | |||
988 | Martin Pitt (4): | ||
989 | Fix hid2hci rules harder | ||
990 | add Vala vapi for gudev-1.0 | ||
991 | Revert "add Vala vapi for gudev-1.0" | ||
992 | Fix usb printer rule for multiple USB interfaces | ||
993 | |||
994 | Maxim Levitsky (1): | ||
995 | mtd_probe: add autodetection for xD cards | ||
996 | |||
997 | Paul Bender (1): | ||
998 | configure.ac: fix cross compilation | ||
999 | |||
1000 | |||
1001 | Summary of changes from v156 to v157 | ||
1002 | ============================================ | ||
1003 | |||
1004 | Harald Hoyer (1): | ||
1005 | 40-redhat.rules: removed file | ||
1006 | |||
1007 | Jerone Young (3): | ||
1008 | Fix wlan key on Inspirion 1210 | ||
1009 | Fix wlan key on Inspiron 910 | ||
1010 | Fix wlan key on Inspiron 1010 & 1110 | ||
1011 | |||
1012 | Kay Sievers (25): | ||
1013 | configure.ac: version bump | ||
1014 | Makefile.am: silent build mkdir | ||
1015 | rules: mount fuse control filesystem | ||
1016 | fix compilation with --enable-debug | ||
1017 | while (1) -> for (;;) | ||
1018 | childs -> children | ||
1019 | udevd: replace --debug-trace with --children-max | ||
1020 | udevd: fix comments | ||
1021 | rules: add -v to modprobe calls to be able see what will be loaded | ||
1022 | udevd: read debug settings from kernel commandline | ||
1023 | update NEWS | ||
1024 | rules: delete pilot rules and remove redhat directory | ||
1025 | man: add static device nodes and udevd debug options | ||
1026 | man: add kernel command line parameters | ||
1027 | man: udevd - update intro | ||
1028 | rules: rename packages -> arch | ||
1029 | rules: SUSE - move last distro rule to package | ||
1030 | rules: add misc/30-kernel-compat.rules | ||
1031 | make: mkdir /lib/udev/devices/ | ||
1032 | make: fix rules/ subdir names | ||
1033 | udevd: set umask before creating files/directories | ||
1034 | add IMPORT{cmdline} | ||
1035 | IMPORT{cmdline}: start at first char after '=' | ||
1036 | libudev: doc - fix typo | ||
1037 | update NEWS | ||
1038 | |||
1039 | |||
1040 | Summary of changes from v155 to v156 | ||
1041 | ============================================ | ||
1042 | |||
1043 | Bryan Kadzban (1): | ||
1044 | udevd: fix typo /proc/fd -> /proc/self/fd | ||
1045 | |||
1046 | Kay Sievers (4): | ||
1047 | configure.ac: version bump | ||
1048 | cdrom_id: do not export ID_CDROM_MEDIA_SESSION_LAST_OFFSET= for single session media | ||
1049 | rules: optical drives - use ID_CDROM_MEDIA_TRACK_COUNT_DATA | ||
1050 | libudev: fix udev_queue_get_seqnum_sequence_is_finished() with empty queue file | ||
1051 | |||
1052 | |||
1053 | Summary of changes from v154 to v155 | ||
1054 | ============================================ | ||
1055 | |||
1056 | Kay Sievers (11): | ||
1057 | reset process priority before executing RUN+= | ||
1058 | configure.ac: version bump | ||
1059 | rules: SUSE - delete device-mapper rules | ||
1060 | libudev: add O_CLOEXEC | ||
1061 | use default mode of 0600 for nodes if gid == 0 | ||
1062 | udevd: create standard symlinks and handle /lib/udev/devices | ||
1063 | update NEWS README | ||
1064 | fix tests and allow MODE=000 | ||
1065 | create static nodes provided by kernel modules to allow module autoloading | ||
1066 | update NEWS | ||
1067 | man: directly use 'refentry' | ||
1068 | |||
1069 | |||
1070 | Summary of changes from v153 to v154 | ||
1071 | ============================================ | ||
1072 | |||
1073 | Harald Hoyer (2): | ||
1074 | Makefile.am: add LGPL COPYING file to EXTRA_DIST | ||
1075 | cdrom_id: only mark sr[0-9]* as ID_CDROM | ||
1076 | |||
1077 | Jerone Young (1): | ||
1078 | Fix volume keys not releasing for Pegatron platform | ||
1079 | |||
1080 | Kay Sievers (23): | ||
1081 | configure.ac: version bump | ||
1082 | more readlink buffer size handling | ||
1083 | remove left-over from ignore_remove and all_partitions | ||
1084 | fix previous commit | ||
1085 | udevadm: info --export-db -- remove watch handle export | ||
1086 | add TAG= to improve event filtering and device enumeration | ||
1087 | all to match against a given TAG== | ||
1088 | udev-acl: use a tag instead of a property to mark devices | ||
1089 | fix logic on-demand loading logic for db and uevent | ||
1090 | use the usual TAG+=, TAG= logic | ||
1091 | delete old tags when configuration changes | ||
1092 | libudev: accept NULL in udev_device_get_tags_list_entry() | ||
1093 | export tag functions | ||
1094 | export udev_device_get_tags_list_entry() | ||
1095 | udevd: always try to find an idle worker instead of forking a new one | ||
1096 | remove unused parameter from udev_node_mknod() | ||
1097 | remove debug output during rules parsing | ||
1098 | warn when renaming kernel-provided nodes instead of adding symlinks | ||
1099 | man: udevadm trigger - the default is "change" not "add" | ||
1100 | update README regarding kernel version and default rules | ||
1101 | add info message when empty NAME is given | ||
1102 | libudev: add documentation for recently added functions | ||
1103 | udevd: reload config only for *.rules files | ||
1104 | |||
1105 | Martin Pitt (1): | ||
1106 | keymap: Fix Bluetooth key on Acer TravelMate 4720 | ||
1107 | |||
1108 | Mathias Nyman (1): | ||
1109 | remove buffer-overrun risk in readlink call | ||
1110 | |||
1111 | Matthias Schwarzott (1): | ||
1112 | rules: Gentoo - remove old devfs compat rules | ||
1113 | |||
1114 | Michael Thayer (1): | ||
1115 | fix device node deletion | ||
1116 | |||
1117 | Robby Workman (1): | ||
1118 | configure.ac: move firmware-path setting out of extras section | ||
1119 | |||
1120 | Yin Kangkai (2): | ||
1121 | keymap: Add keymap and force-release quirk for Samsung N128 | ||
1122 | keymap: Add keymap quirk of WebCam key for MSI netbooks. | ||
1123 | |||
1124 | |||
1125 | Summary of changes from v152 to v153 | ||
1126 | ============================================ | ||
1127 | |||
1128 | Kay Sievers (1): | ||
1129 | configure.ac: version bump | ||
1130 | |||
1131 | Robby Workman (1): | ||
1132 | configure.ac: fix broken firmware search path in configure.ac | ||
1133 | |||
1134 | |||
1135 | Summary of changes from v151 to v152 | ||
1136 | ============================================ | ||
1137 | |||
1138 | Adrian Bunk (1): | ||
1139 | udev needs automake 1.10 | ||
1140 | |||
1141 | Amit Shah (2): | ||
1142 | Fix virtio-ports rule to use $attr instead of $ATTR | ||
1143 | rules: virtio - fix is to check if the 'name' attribute is present | ||
1144 | |||
1145 | Andy Whitcroft (2): | ||
1146 | keymap: Add Samsung Q210/P210 force-release quirk | ||
1147 | keymap: Add Fujitsu Amilo 1848+u force-release quirk | ||
1148 | |||
1149 | Dan Williams (1): | ||
1150 | modeswitch: morph into tool that only switches Mobile Action cables | ||
1151 | |||
1152 | David Zeuthen (3): | ||
1153 | Decrease buffer size when advancing past NUL byte | ||
1154 | Use UTIL_LINE_SIZE, not UTIL_PATH_SIZE to truncate properties | ||
1155 | Increase UTIL_LINE_SIZE from 2048 to 16384 | ||
1156 | |||
1157 | Harald Hoyer (1): | ||
1158 | cdrom_id: remove debugging code | ||
1159 | |||
1160 | Jerone Young (6): | ||
1161 | Force key release for volume keys on Dell Studio 1557 | ||
1162 | Fix Keymapping for upcoming Dell Laptops | ||
1163 | Add new Dell touchpad keycode | ||
1164 | Revert special casing 0xD8 to latitude XT only | ||
1165 | Fix Dell Studio 1558 volume keys not releasing | ||
1166 | Add support for another Dell touchpad toggle key | ||
1167 | |||
1168 | Kamal Mostafa (3): | ||
1169 | keymap: Unite laptop models needing common volume-key release quirk | ||
1170 | keymap: Add force-release quirk for Coolbox QBook 270-02 | ||
1171 | keymap: Add force-release quirk for Mitac 8050QDA | ||
1172 | |||
1173 | Kay Sievers (43): | ||
1174 | libudev: bump minor version | ||
1175 | udevadm: fix untested and broken commit to set buffer size | ||
1176 | configure.ac: version bump | ||
1177 | udev-acl: no not encourage use of ACL_MANAGE outside of rules file | ||
1178 | replace utimes() with utimensat() | ||
1179 | libbudev-private: rename udev_list_entry_get_flag() | ||
1180 | udevadm: monitor - use / as separator in --subsystem-match=subsystem[/devtype] | ||
1181 | use major:minor as entries in symlink stack instead of devpath | ||
1182 | use major:minor as entries in watch directory | ||
1183 | libudev: docs - .gitignore backup files | ||
1184 | firmware: fix possible segfault when firmware device goes away while loading | ||
1185 | do not reset SELinux context when the node was not touched | ||
1186 | libudev: add udev_device_new_from_environment() | ||
1187 | add LGPL COPYING to libudev and GUdev | ||
1188 | cdrom_id: open non-mounted optical media with O_EXCL | ||
1189 | libudev: update documentation | ||
1190 | extras: mobile-action-modeswitch - update gitignore | ||
1191 | scsi_id: add rand() in retry loop | ||
1192 | cdrom_id: retry to open the device, if EBUSY | ||
1193 | cdrom_id: check mount state in retry loop | ||
1194 | cdrom_id: always set ID_CDROM regardless if we can run cdrom_id | ||
1195 | rules: delete outdated packagees rules | ||
1196 | rules: we do not have static devices which are renamed | ||
1197 | unify/cleanup event handling | ||
1198 | allow IMPORT{db}="KEY" | ||
1199 | usb-db: remove double '/' | ||
1200 | replace "add|change" with "!remove" | ||
1201 | update NEWS | ||
1202 | log info only if we actually delete the node | ||
1203 | udevadm: trigger - switch default action from "add" to "change" | ||
1204 | remove "all_partitions" option | ||
1205 | rules: call modprobe on all events but "remove" | ||
1206 | remove "ignore_remove" option | ||
1207 | update NEWS | ||
1208 | cdrom_id: rework feature/profiles buffer parsing | ||
1209 | cdrom_id: print more debug messages | ||
1210 | cdrom_id: debug - print feature values in hex | ||
1211 | cdrom_id: debug - print feature values in hex | ||
1212 | cdrom_id: set ID_CDROM_MEDIA=1 only for known media | ||
1213 | Revert "Fix switching Logitech bluetooth adapters into hci mode." | ||
1214 | add O_NOFOLLOW when creating files in link stack | ||
1215 | delete only device nodes, not symlinks when deleting a devtmpfs node | ||
1216 | doc: add section about how *not* to rename device nodes | ||
1217 | |||
1218 | Marco d'Itri (3): | ||
1219 | rules: input - create by-path/ links for pci devices | ||
1220 | Fix switching Logitech bluetooth adapters into hci mode. | ||
1221 | doc: document the WAIT_FOR timeout | ||
1222 | |||
1223 | Martin Pitt (12): | ||
1224 | keymap: Add Dell Inspiron 1011 (Mini 10) | ||
1225 | Fix brightness keys on MSI Wind U-100 | ||
1226 | keymap: Fix LG X110 | ||
1227 | keymap: Add Toshiba Satellite M30X | ||
1228 | udev-acl: Correctly handle ENV{ACL_MANAGE}==0 | ||
1229 | input_id: Fix linking | ||
1230 | keymap: Add Acer TravelMate 6593G and Acer Aspire 1640 | ||
1231 | keymap: Fix another key for Acer TravelMate 6593 | ||
1232 | cdrom_id: Fix uninitialized variables | ||
1233 | cdrom_id: Fix uninitialized buffers | ||
1234 | cdrom_id: Do not ignore errors from scsi_cmd_run() | ||
1235 | cdrom_id: Swap media state and TOC info probing | ||
1236 | |||
1237 | Mike Brudevold (1): | ||
1238 | cdrom_id: add missing profiles to feature_profiles | ||
1239 | |||
1240 | Robert Hooker (1): | ||
1241 | keymap: Add support for Gateway AOA110/AOA150 clones. | ||
1242 | |||
1243 | Scott James Remnant (2): | ||
1244 | libudev: export udev_monitor_set_receive_buffer_size() | ||
1245 | udevadm monitor: increase netlink buffer size | ||
1246 | |||
1247 | Thomas Bächler (1): | ||
1248 | firmware: fix error reporting on missing firmware files | ||
1249 | |||
1250 | Yury G. Kudryashov (3): | ||
1251 | configure.ac - fix typo in --with-pci-ids-path option | ||
1252 | hid2hci: include linux/types.h for __u32 | ||
1253 | configure.ac: ddd --with-firmware-path option | ||
1254 | |||
1255 | |||
1256 | Summary of changes from v150 to v151 | ||
1257 | ============================================ | ||
1258 | |||
1259 | Amit Shah (1): | ||
1260 | rules: Add symlink rule for virtio ports | ||
1261 | |||
1262 | Bryan Kadzban (1): | ||
1263 | Fix reverted floppy-device permissions | ||
1264 | |||
1265 | Egbert Eich (1): | ||
1266 | rulews: suse - add do-not-load-KMS-modules rules | ||
1267 | |||
1268 | Frederic Crozat (1): | ||
1269 | rules: acl - add COLOR_MEASUREMENT_DEVICE match | ||
1270 | |||
1271 | Kay Sievers (11): | ||
1272 | configure.ac: version bump | ||
1273 | udevd: inotify - do not parse rules at create but at close | ||
1274 | do not remove device nodes of active kernel devices | ||
1275 | libudev: device - create db file atomically | ||
1276 | clarify message about not removed device node | ||
1277 | input_id: include limits.h | ||
1278 | keymap: include linux/limits.h | ||
1279 | keymap: linux/input.h - get absolute include path from gcc | ||
1280 | delete outdated and unmaintained writing_udev_rules | ||
1281 | update README and NEWS | ||
1282 | update tests | ||
1283 | |||
1284 | Marco d'Itri (2): | ||
1285 | writing_udev_rules: update rules files names | ||
1286 | keymap: support for the Samsung N140 keyboard | ||
1287 | |||
1288 | Martin Pitt (4): | ||
1289 | add ACL rule for Garmin GPSMap 60 | ||
1290 | keymap: move force-release directory | ||
1291 | extras/keymap/check-keymaps.sh: Ignore comment-only lines | ||
1292 | keymap: Fix invalid map line | ||
1293 | |||
1294 | |||
1295 | Summary of changes from v149 to v150 | ||
1296 | ============================================ | ||
1297 | |||
1298 | Clemens Buchacher (2): | ||
1299 | add Samsung R70/R71 keymap | ||
1300 | keymap: Samsung R70/R71 force-release quirk | ||
1301 | |||
1302 | Daniel Drake (2): | ||
1303 | keymap: Add OLPC XO key mappings | ||
1304 | keymap: Fix typo in compal rules | ||
1305 | |||
1306 | Daniel Elstner (1): | ||
1307 | libudev: wrap in extern "C" block for C++ | ||
1308 | |||
1309 | David Zeuthen (1): | ||
1310 | Export ID_WWN_VENDOR_EXTENSION and ID_WWN_WITH_EXTENSION | ||
1311 | |||
1312 | Jerone Young (1): | ||
1313 | keymap: Lenovo Thinkpad USB Keyboard with Tracepoint | ||
1314 | |||
1315 | Johannes Stezenbach (2): | ||
1316 | keymap: add Samsung N130 | ||
1317 | keymap: handle atkbd force_release quirk | ||
1318 | |||
1319 | Kay Sievers (15): | ||
1320 | util_unlink_secure(): chmod() before chown() | ||
1321 | floppy: fix rule to create additional floppy device nodes | ||
1322 | configure.ac: version bump | ||
1323 | remove remaining support for CONFIG_SYSFS_DEPRECATED | ||
1324 | cdrom_id: remove deprecated device matches | ||
1325 | rules: add "block" match to floppy rule | ||
1326 | update mtime of nodes and links when we re-use them | ||
1327 | udevadm: info - fix info --root --query=name --path= for device without a device node | ||
1328 | remove remaining support for CONFIG_SYSFS_DEPRECATED | ||
1329 | fix typo in log message priority handling | ||
1330 | remove UDEV_RUN environment variable | ||
1331 | udevadm: logging - copy va_list and do not use it twice | ||
1332 | libudev: doc - add symbols to sections.txt | ||
1333 | work around gtk-doc which breaks distcheck | ||
1334 | gobject-introspection: use $datadir instead of $prefix | ||
1335 | |||
1336 | Marco d'Itri (2): | ||
1337 | build: keymap - create subdir | ||
1338 | rules: udev-acl - add firewire video devices | ||
1339 | |||
1340 | Martin Pitt (12): | ||
1341 | keymap: Add Acer Aspire 1810T | ||
1342 | 95-keymap.rules: Run on change events, too | ||
1343 | keymap: fix findkeyboards | ||
1344 | Speed up udev_enumerate_scan_* | ||
1345 | keymap: Add hotkey quirk for Acer Aspire One (AO531h/AO751h) | ||
1346 | Clarify RUN/IMPORT documentation | ||
1347 | keymap: Add Logitech S510 USB keyboard | ||
1348 | keymap: add Acer TravelMate 8471 | ||
1349 | keymap: Add Acer Aspire 1810TZ | ||
1350 | keymap: Add LG X110 | ||
1351 | keymap: Add Fujitsu Amilo Li 1718 | ||
1352 | keymap: Document force-release | ||
1353 | |||
1354 | Piter PUNK (1): | ||
1355 | firmware: convert shell script to C | ||
1356 | |||
1357 | Scott James Remnant (1): | ||
1358 | 70-acl.rules: ACL manage Android G1 dev phones | ||
1359 | |||
1360 | Thomas de Grenier de Latour (1): | ||
1361 | libudev: enumerate - fix move_later logic | ||
1362 | |||
1363 | |||
1364 | Summary of changes from v148 to v149 | ||
1365 | ============================================ | ||
1366 | |||
1367 | Daniel Elstner (1): | ||
1368 | really fix both in-tree and out-of-tree builds | ||
1369 | |||
1370 | Dmitry Torokhov (1): | ||
1371 | input-id: identify touchscreens | ||
1372 | |||
1373 | Kay Sievers (4): | ||
1374 | libudev: doc - use #NULL | ||
1375 | configure.ac: version bump | ||
1376 | really really fix both in-tree and out-of-tree builds | ||
1377 | fix both in-tree and out-of-tree builds | ||
1378 | |||
1379 | Martin Pitt (6): | ||
1380 | input_id: Fix endless loop for non-input devices | ||
1381 | input_id: Do not tag non-input devices with ID_INPUT | ||
1382 | input_id: small optimization | ||
1383 | input_id: check event mask | ||
1384 | input_id: Check mouse button for ID_INPUT_MOUSE | ||
1385 | udev_device_get_parent_with_subsystem_devtype(): Clarify documentation | ||
1386 | |||
1387 | |||
1388 | Summary of changes from v147 to v148 | ||
1389 | ============================================ | ||
1390 | |||
1391 | Dan Williams (3): | ||
1392 | Revert "modem-modeswitch: add a device" | ||
1393 | Revert "extras/modem-modeswitch: Add Huawei E1550 GSM modem" | ||
1394 | modem-modeswitch: 61-option-modem-modeswitch.rules is only for Option NV devices | ||
1395 | |||
1396 | Daniel Mierswa (1): | ||
1397 | Fix typo in NEWS, ConsoleKit-0.4.11 -> 0.4.1 | ||
1398 | |||
1399 | David Zeuthen (4): | ||
1400 | cdrom_id: Still check profiles even if there is no media | ||
1401 | scsi_id: Export WWN and Unit Serial Number | ||
1402 | Create /dev/disk/by-id/wwn-0x... symlinks | ||
1403 | Also create /dev/disk/by-id/wwn-0x..-part%n symlinks for partitions | ||
1404 | |||
1405 | Dmitry Torokhov (1): | ||
1406 | extras/input_id: Correctly identify touchpads | ||
1407 | |||
1408 | Harald Hoyer (1): | ||
1409 | modem-modeswitch: add a device | ||
1410 | |||
1411 | Kay Sievers (8): | ||
1412 | rules: set mode of floppy device nodes to 0660 | ||
1413 | remove "ignore_device" | ||
1414 | print warning for BUS=, SYSFS{}=, ID= | ||
1415 | test-udev: remove "ignore_device" code | ||
1416 | udev-test.pl: catch-up with recent changes | ||
1417 | rules: remove support for IDE (hd*) devices | ||
1418 | ata_id: skip ATA commands if we find an optical drive | ||
1419 | Revert "Fix out-of-tree builds" | ||
1420 | |||
1421 | Martin Pitt (5): | ||
1422 | README.keymap.txt: small clarification | ||
1423 | extras: Add input_id | ||
1424 | 70-acl.rules: Use new-style input properties | ||
1425 | input: Deprecate ENV{ID_CLASS} | ||
1426 | input_id: code cleanup | ||
1427 | |||
1428 | Scott James Remnant (1): | ||
1429 | Fix out-of-tree builds | ||
1430 | |||
1431 | |||
1432 | Summary of changes from v146 to v147 | ||
1433 | ============================================ | ||
1434 | |||
1435 | Alan Jenkins (1): | ||
1436 | udevd: queue-export - remove retry loop | ||
1437 | |||
1438 | Andrew Church (1): | ||
1439 | fix wrong parameter size on ioctl FIONREAD | ||
1440 | |||
1441 | Daniel Mierswa (2): | ||
1442 | don't compare a non-existing function with NULL | ||
1443 | use nanosleep() instead of usleep() | ||
1444 | |||
1445 | David Zeuthen (4): | ||
1446 | gudev: remove G_UDEV_API_IS_SUBJECT_TO_CHANGE since API is now stable | ||
1447 | ata_id: export more advanced ATA features | ||
1448 | gudev: Fix up GUdevDeviceNumber | ||
1449 | gudev: Remove LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE from priv header | ||
1450 | |||
1451 | Florian Zumbiehl (10): | ||
1452 | util_delete_path(): use util_strscpy() | ||
1453 | util_lookup_group(): fix memory leak if realloc() fails | ||
1454 | util_delete_path(): handle multiple leading slashes | ||
1455 | util_create_path(): fix possible out of bounds array access | ||
1456 | ude_rules.c: fix possible NULL pointer dereference in get_key() | ||
1457 | util_resolve_sys_link(): fix possible buffer overflow | ||
1458 | udev_util_encode_string(): fix possible buffer overflow | ||
1459 | udev-rules.c: parse_file() - fix possible buffer overflow | ||
1460 | udev_queue_get_seqnum_sequence_is_finished(): fix possible file handle leak | ||
1461 | util_run_program(): fix possible buffer overflow #2 | ||
1462 | |||
1463 | Harald Hoyer (2): | ||
1464 | scsi_id: prevent buffer overflow in check_fill_0x83_prespc3() | ||
1465 | rename interfaces to <iface>_rename if rename fails | ||
1466 | |||
1467 | Jeremy Kerr (1): | ||
1468 | util_run_program: restore signal mask before executing event RUN commands | ||
1469 | |||
1470 | Kay Sievers (45): | ||
1471 | make: sort Makefile.am per target/extra | ||
1472 | configure.ac: version bump | ||
1473 | udev-acl: allow to skip ACL handling | ||
1474 | rules: rfkill has no group, so use 0644 | ||
1475 | rule_generator: net - fix MATCHDEVID | ||
1476 | make: add comment | ||
1477 | update NEWS | ||
1478 | print warning for NAME="%k" - it breaks the kernel supplied DEVNAME | ||
1479 | warn about non-readable or empty rules file | ||
1480 | change database file names | ||
1481 | assign errno for getgrnam_r()/getpwnam_r() | ||
1482 | doc: udevadm test *does* create nodes and links these days | ||
1483 | util_unlink_secure(): chmod() before chown() | ||
1484 | util_create_path(): fix errno usage | ||
1485 | inotify_add_watch(): do not store watch, if it failed | ||
1486 | update TODO | ||
1487 | update README | ||
1488 | rules: suse - use NAME for mapper/control | ||
1489 | libudev-util.c: get_sys_link() - return error for empty link target | ||
1490 | udev-rules.c: remove 'first_token' variable | ||
1491 | Revert "udev-rules.c: remove 'first_token' variable" | ||
1492 | test: catch possible bug in GOTO resolving | ||
1493 | udevadm: remove symlink support for old commands | ||
1494 | util_run_program(): skip multiple spaces in argv creation | ||
1495 | fix whitespace | ||
1496 | require 2.6.27 for proper signalfd handling | ||
1497 | fix randonm findings from llvm-clang-analyzer | ||
1498 | simplify "symlink name stack" | ||
1499 | reorder create_path() and node/link creation to be called in a direct sequence | ||
1500 | put util_create_path() and file creastion in a retry loop | ||
1501 | udevadm: control - remove compat code | ||
1502 | scsi_id: delete copy of bsg.h | ||
1503 | fix SYMLINK{} option parsing | ||
1504 | rules: remove remaining NAME="%k" | ||
1505 | rules: drop almost all NAME= keys | ||
1506 | update TODO, NEWS | ||
1507 | udevd: serialize events for with the same major/minor | ||
1508 | break loops if util_create_path() returns error | ||
1509 | remove "last_rule" option | ||
1510 | use CLOEXEC flags instead of fcntl() | ||
1511 | unblock signals we might want to handle | ||
1512 | udevd: create /dev/.udev/rules.d/ before watching it wit inotify | ||
1513 | gudev: fix pkg-config call to work with "make distcheck" | ||
1514 | update NEWS | ||
1515 | Revert "gudev: fix out-of-tree build" | ||
1516 | |||
1517 | Lennart Poettering (5): | ||
1518 | pci-db: make sure we actually read the pci.ids file instead of usb.ids | ||
1519 | sound: recognize saa7134 TV card sound devices as TV cards | ||
1520 | sound: include ALSA sound card id in ID_ID property | ||
1521 | sound: include ALSA sound card id in /dev/snd/by-id/ links | ||
1522 | Revert "sound: include ALSA sound card id in /dev/snd/by-id/ links" | ||
1523 | |||
1524 | Marco d'Itri (6): | ||
1525 | doc: writing_udev_rules updated for the new command names | ||
1526 | rules: sound - do not use /usr/bin/env | ||
1527 | udevadm: print all messages to stderr with priority higher or equal than LOG_ERR | ||
1528 | udevadmi: control = exit with rc=2 if there is some system error | ||
1529 | gudev: gir-scanner workaround for out of tree builds | ||
1530 | gudev: fix out-of-tree build | ||
1531 | |||
1532 | Mario Limonciello (1): | ||
1533 | hid2hci: remove superfluous bmAttributes match | ||
1534 | |||
1535 | Martin Pitt (24): | ||
1536 | extras/keymap: Add Acer Aspire 6920 | ||
1537 | extras/modem-modeswitch: eject ZTE MF6xx fake CD-ROMs | ||
1538 | extras/keymap: Fix hold key on Acer Aspire 6920 | ||
1539 | extras/keymap: Fix case matching for Micro-Star | ||
1540 | Revert "extras/keymap: Fix case matching for Micro-Star" | ||
1541 | make raw USB printer devices accessible for lp | ||
1542 | modem-modeswitch rules: Match more devices | ||
1543 | extras/keymap: fix hash table collisions | ||
1544 | extras/keymap: Rename KEY_COFFEE to KEY_SCREENLOCK | ||
1545 | fix single-session CD detection | ||
1546 | fix previous commit for CD detection | ||
1547 | make raw USB printer devices world-readable again | ||
1548 | 50-udev-default.rules: fix printer MODE | ||
1549 | keymap: Add Logitech Wave USB | ||
1550 | keymap: add missing map file | ||
1551 | keymap: fix usb_id invocation | ||
1552 | keymap: make USB keyboards really work | ||
1553 | keymap: Add Logitech Wave cordless | ||
1554 | keymap: add HP Pavillion dv6315ea | ||
1555 | keymap: add HP 2230s | ||
1556 | Makefile.am: fix build with mawk | ||
1557 | extras/keymap/README.keymap.txt: Fix bug report link | ||
1558 | fix major fd leak in link handling | ||
1559 | modem-modeswitch: fix ZTE MF6xx rule | ||
1560 | |||
1561 | Matthias Schwarzott (2): | ||
1562 | rules: Gentoo update | ||
1563 | rules: Gentoo update | ||
1564 | |||
1565 | Maxim Levitsky (1): | ||
1566 | keymap for Acer Aspire 5720 | ||
1567 | |||
1568 | Peter Rajnoha (1): | ||
1569 | libudev: allow to store negative values in the udev database | ||
1570 | |||
1571 | Scott James Remnant (1): | ||
1572 | util_run_program: *really* restore signal mask before executing event RUN commands | ||
1573 | |||
1574 | William Jon McCann (1): | ||
1575 | udev-acl: catch up with ConsoleKit 0.4.1 | ||
1576 | |||
1577 | |||
1578 | Summary of changes from v145 to v146 | ||
1579 | ============================================ | ||
1580 | |||
1581 | Alan Jenkins (3): | ||
1582 | man: fix unused, inaccurate metadata | ||
1583 | man: SYMLINK can be matched as well as assigned | ||
1584 | fix spelling | ||
1585 | |||
1586 | Anssi Hannula (2): | ||
1587 | rules: exclude digitizers from joystick class | ||
1588 | udev-acl: add joystick devices | ||
1589 | |||
1590 | Diego Elio 'Flameeyes' Pettenò (21): | ||
1591 | Merge libudev, udev, and the unconditional extras in a single Makefile.am. | ||
1592 | Replace the custom test-run target with the standard make check. | ||
1593 | Also merge into the top-level Makefile.am the simpler extras. | ||
1594 | Change hook handling to be more portable. | ||
1595 | Merge keymap building in the top-level Makefile.am. | ||
1596 | Make keymap generation rules be silent (backward-compatible). | ||
1597 | Move pkg-config docs and man pages before conditionals. | ||
1598 | Finally, also merge gudev into the top-level Makefile.am. | ||
1599 | Make sure to clean up all the built sources. | ||
1600 | Make sure to use dependency/target variables. | ||
1601 | Add silent-rule support for the gudev rules. | ||
1602 | Fix building of introspection library on top-level Makefile.am. | ||
1603 | Fix another relative path for the new working directory. | ||
1604 | Include the correct directory for out-of-source builds. | ||
1605 | Add tests to the distribution; this fixes "make distcheck". | ||
1606 | Ask gperf to use ANSI-C for generation. | ||
1607 | Merge in Makefile.am.inc into Makefile.am | ||
1608 | Use the keymap check during “make distcheck” rather than “check”. | ||
1609 | Fix building of documentation when doing out-of-source builds. | ||
1610 | Fix “make distcheck” run outside of the source directory. | ||
1611 | Use LT_INIT to explicit that udev needs libtool series 2. | ||
1612 | |||
1613 | Eric W. Biederman (1): | ||
1614 | fix util_lookup_group to handle large groups | ||
1615 | |||
1616 | Erik Forsberg (1): | ||
1617 | extras/modem-modeswitch: Add Huawei E1550 GSM modem | ||
1618 | |||
1619 | Kay Sievers (18): | ||
1620 | udevd: add timestamp to --debug output | ||
1621 | v4l_id: exit with 0 when --help is given | ||
1622 | configure.ac: version bump | ||
1623 | hid2hci: remove hid structures and include kernel header | ||
1624 | path_id: make global variable static | ||
1625 | udevadm: trigger - add --sysname-match= | ||
1626 | rules: serial - fix path_id call | ||
1627 | path_id: fix typo in comment | ||
1628 | format names are not case insensitive | ||
1629 | hid2hci: rewrite (and break) rules and device handling | ||
1630 | make: build internal tools against libudev-private.la | ||
1631 | update a few years of copyright | ||
1632 | libudev: silent gcc warning: may be used uninitialized in this function | ||
1633 | make: suppress enter/leaving directory messages | ||
1634 | re-enable failed event tracking | ||
1635 | "record_failed" -> "fail_event_on_error" | ||
1636 | udevd: block for 15 seconds after error when too old kernel is detected | ||
1637 | make: fix issues from non-recursive conversion | ||
1638 | |||
1639 | Lennart Poettering (1): | ||
1640 | enumeration: move ALSA control devices to the end of the enumerated devices of each card | ||
1641 | |||
1642 | Mario Limonciello (2): | ||
1643 | hid2hci: support to hid2hci for recovering Dell BT devices after S3 | ||
1644 | hid2hci: install re-trigger for hid device when recovering from S3 | ||
1645 | |||
1646 | Martin Pitt (17): | ||
1647 | add keymap for Clevo D410J laptop | ||
1648 | extras/keymap: add Zepto ZNote | ||
1649 | extras/keymap: add Everex Stepnote XT5000T | ||
1650 | extras/keymap: add Compal Hel80i | ||
1651 | keymap tool: improve help | ||
1652 | keymap tool: support scancode/keycode pair arguments | ||
1653 | keymap: inline one-line key maps | ||
1654 | extras/keymap: fix check-keymaps.sh for inline mappings | ||
1655 | extras/keymap: add recently added keymap files to Makefile.am | ||
1656 | extras/keymap: Add HP Presario 2100 | ||
1657 | extras/keymap: cover more Compaq Evo models | ||
1658 | extras/keymap: Add Fujitsu Amilo M | ||
1659 | extras/keymap: teach findkeyboards about USB keyboards | ||
1660 | extras/keymap: Add Samsung SX22S | ||
1661 | extras/keymap: Fix crash for unknown keys | ||
1662 | extras/keymap: Add Samsung NC20 | ||
1663 | extras/keymap: Fix Bluetooth key on Acer Aspire 6920 | ||
1664 | |||
1665 | |||
1666 | Summary of changes from v144 to v145 | ||
1667 | ============================================ | ||
1668 | |||
1669 | Ian Campbell (1): | ||
1670 | scsi_id: correct error handling in prepend_vendor_model | ||
1671 | |||
1672 | Kay Sievers (10): | ||
1673 | README: add CONFIG_BLK_DEV_BSG | ||
1674 | use MIN() MAX() from param.h | ||
1675 | configure.ac: version bump | ||
1676 | libudev: device - free values before updating them | ||
1677 | libudev: enumerate - sort with qsort() | ||
1678 | udevd: detach event from worker if we kill a worker | ||
1679 | udevadm: info - add space after R:, A:, W: on database export | ||
1680 | udevd: make sure a worker finishes event handling before exiting | ||
1681 | udevd: handle SIGCHLD before the worker event message | ||
1682 | udevd: use bool | ||
1683 | |||
1684 | |||
1685 | Summary of changes from v143 to v144 | ||
1686 | ============================================ | ||
1687 | |||
1688 | Jon Masters (1): | ||
1689 | firmware: search for third party or sysadmin supplied firmware updates | ||
1690 | |||
1691 | Kay Sievers (19): | ||
1692 | configure.ac: add AM_SILENT_RULES | ||
1693 | configure.ac: version bump | ||
1694 | TODO: add cleanup of ATA_COMPAT | ||
1695 | libudev: queue - add comments for queue format | ||
1696 | udev/.gitignore: add udev.pc | ||
1697 | configure.ac: version bump | ||
1698 | do not exports properties starting with a '.' | ||
1699 | scsi_id: --reformat_serial - use udev_util_replace_whitespace() | ||
1700 | ata_id: sync ID_SERIAL(_SHORT) with other *_id tools | ||
1701 | rules: make ata_id properties the default for all ATA block devices | ||
1702 | scsi_id: delete no longer needed config file | ||
1703 | update NEWS | ||
1704 | man: udev - add private properties like ENV{.FOO}="bar" | ||
1705 | Merge branch 'firmware' of git://git.kernel.org/pub/scm/linux/kernel/git/jcm/udev-jcm | ||
1706 | udevadm: test - print list of properties | ||
1707 | build: do not delete .la files | ||
1708 | libudev: monitor - handle kernel supplied DEVNAME properly | ||
1709 | update NEWS | ||
1710 | build: add *exec* to the internal rootlibdir name | ||
1711 | |||
1712 | Martin Pitt (2): | ||
1713 | hid2hci: narrow matches to real HCI devices | ||
1714 | extras/udev-acl: add smartcard readers | ||
1715 | |||
1716 | Stefan Richter (1): | ||
1717 | rules: set group ownership of new firewire driver device files | ||
1718 | |||
1719 | |||
1720 | Summary of changes from v142 to v143 | ||
1721 | ============================================ | ||
1722 | |||
1723 | Alan Jenkins (5): | ||
1724 | udevadm: settle - fix timeout | ||
1725 | udevd: remove tiny bit of dead code | ||
1726 | udevd: implement a more efficient queue file format | ||
1727 | udev-selinux.c: remove libudev header | ||
1728 | udevd: queue-export - fix crash | ||
1729 | |||
1730 | Benjamin Gilbert (1): | ||
1731 | test: check string substitutions in OWNER and GROUP | ||
1732 | |||
1733 | Dan Williams (2): | ||
1734 | rules: tty/net - move from udev-extras | ||
1735 | extras/modem-modeswitch: move from udev-extras | ||
1736 | |||
1737 | David Zeuthen (1): | ||
1738 | gudev: move from udev-extras | ||
1739 | |||
1740 | Kay Sievers (95): | ||
1741 | version bump | ||
1742 | rules: v4l do not mix vbi and video nodes | ||
1743 | fix possible endless loop for GOTO to non-existent LABEL | ||
1744 | Revert "rules: v4l do not mix vbi and video nodes" | ||
1745 | rule-generator: cd - skip by-path links if we create by-id links | ||
1746 | remove format char string truncation syntax | ||
1747 | use more efficient string copying | ||
1748 | edd_id: use openat() | ||
1749 | use openat(), unlinkat(), fstatat() | ||
1750 | update TODO | ||
1751 | remove unused GL_FORMAT from rules parser | ||
1752 | require key names in uppercase | ||
1753 | keep the ifdef'd udevd testing/profiling hack | ||
1754 | fix location of database files | ||
1755 | udevadm: settle - make --timeout=0 working | ||
1756 | update NEWS | ||
1757 | rules: add SUBSYSTEM match to scsi rules | ||
1758 | cdrom_id: suppress ID_CDROM_MEDIA_STATE=blank for plain non-writable CDROM media | ||
1759 | udevadm: control - add comment to man page about --reload-rules | ||
1760 | cdrom_id: add error message if open() fails | ||
1761 | udevadm: settle - add --exit-if-exists=<file> | ||
1762 | udevd: remove check for dev_t, DEVPATH_OLD takes care of that | ||
1763 | str[sp]cpyl: add __attribute__ ((sentinel)) | ||
1764 | udevd: convert to event worker processes | ||
1765 | udevd: close netlink socket in worker and set cloexec | ||
1766 | rules: do not call path_id for virtual devices | ||
1767 | udevd: use enum instead of char in struct declaration | ||
1768 | allow format substitution in path of ATTR{<path>}=="<value>" | ||
1769 | cleanup $attr{} substitution | ||
1770 | path_id: implement in C using libudev | ||
1771 | path_id: update SCSI handling | ||
1772 | path_id: add comments | ||
1773 | fix signed/unsigned warning | ||
1774 | libudev: enumerate - allow multiple keys with the same name | ||
1775 | udevadm: trigger - add --property-match=<key>:<value> | ||
1776 | udevadm: info - accept --query without a value and print properties | ||
1777 | udevadm: control - --env -> --property | ||
1778 | udevadm: monitor --environment -> --property | ||
1779 | path_id: handle fibre channel | ||
1780 | path_id: add iscsi support | ||
1781 | path_id: delete old shell script | ||
1782 | udevd: print error if worker dies unexpectedly | ||
1783 | path_id: rename scsi sub-fuctions | ||
1784 | libudev: add comments to libudev.h | ||
1785 | libudev: move to top-level directory | ||
1786 | fix libudev include in Makefile.am.in | ||
1787 | libudev: device_new() -> udev_device_new() | ||
1788 | udevd: log info for created/killed workers | ||
1789 | libudev: call log functions conditionally | ||
1790 | move syslog wrapper to libudev | ||
1791 | move common stuff from udev/ to private parts of libudev/ | ||
1792 | libudev: rename private files to *-private.c | ||
1793 | rules: remove scsi ch module loading rule | ||
1794 | update NEWS | ||
1795 | udevadm: info -revert "accept --query without argument" | ||
1796 | README: add kernel options | ||
1797 | README: add INOTIFY and SIGNALFD | ||
1798 | USE_LOG -> ENABLE_LOGGING, DEBUG -> ENABLE_DEBUG, USE_SELINUX -> WITH_SELINUX | ||
1799 | libudev: add gtk-doc | ||
1800 | libudev: update documentation | ||
1801 | libudev: doc - add section headers | ||
1802 | libudev: doc - add enumerate | ||
1803 | libudev: doc - add queue | ||
1804 | update TODO | ||
1805 | libudev: doc - add namespace for index | ||
1806 | libudev: move .so version to libudev Makefile | ||
1807 | autogen.sh: simplify | ||
1808 | TODO: update | ||
1809 | libudev: remove prefix from .so version variables | ||
1810 | libudev: doc - add empty libudev.types | ||
1811 | udev-acl: move from udev-extras | ||
1812 | INSTALL: add --enable-extras | ||
1813 | udev-acl: handle missing action when called in CK mode | ||
1814 | v4l_id: move from udev-extras | ||
1815 | libudev: doc - libudev-docs.sgml -> libudev-doc.xml | ||
1816 | gudev: fix typo in configure option | ||
1817 | v4l_id: 70-v4l.rules -> 60-persistent-v4l.rules | ||
1818 | configure: enable all extras by default, provide --disable-extras | ||
1819 | autogen.sh: make "CFLAGS=-O0 ./autogen.sh" working | ||
1820 | NEWS: add --disable-extras | ||
1821 | cleanup ./configure installation directory options | ||
1822 | rules: remove MMC rule, 2.6.30 has the modalias | ||
1823 | configure.ac: print error if gperf is missing | ||
1824 | libudev: install in $libdir and move later to $rootlibdir | ||
1825 | extras/keymap: use LIBEXECDIR instead /lib/udev | ||
1826 | README: add /lib/udev/ is private | ||
1827 | rules: do not install usb-id/pci-id rules when --disable-extras is used | ||
1828 | extras: delete man pages for private udev tools | ||
1829 | README: update | ||
1830 | extras/keymap: install findkeyboards in /lib/udev | ||
1831 | INSTALL: use /sbin instead of %{sbindir} | ||
1832 | NEWS: update | ||
1833 | udev.pc: add | ||
1834 | Merge branch 'master' of git+ssh://master.kernel.org/pub/scm/linux/hotplug/udev | ||
1835 | docs: install writing_udev_rules | ||
1836 | |||
1837 | Lennart Poettering (2): | ||
1838 | rules: sound - move from udev-extra | ||
1839 | usb-db: move from udev-extras | ||
1840 | |||
1841 | Marcel Holtmann (1): | ||
1842 | rules: make RFKILL control device world readable | ||
1843 | |||
1844 | Mario Limonciello (1): | ||
1845 | hid2hci: move from udev-extras | ||
1846 | |||
1847 | Martin Pitt (5): | ||
1848 | keymap: move from udev-extras | ||
1849 | extras/keymap: Fix WLAN button on ThinkPads | ||
1850 | keymap: Update findkeyboard path in docs | ||
1851 | udev-acl: Manage hplip device permissions | ||
1852 | extras/keymap: Update findkeyboards location | ||
1853 | |||
1854 | Matthias Schwarzott (3): | ||
1855 | rules: Gentoo update | ||
1856 | rules: Gentoo update | ||
1857 | rules: Gentoo update | ||
1858 | |||
1859 | Scott James Remnant (1): | ||
1860 | OWNER/GROUP: fix if logic | ||
1861 | |||
1862 | |||
1863 | Summary of changes from v141 to v142 | ||
1864 | ============================================ | ||
1865 | |||
1866 | Andre Przywara (1): | ||
1867 | rules: create /dev/cpu/<n>/cpuid world readable | ||
1868 | |||
1869 | Ian Campbell (1): | ||
1870 | path_id: support identification of Xen virtual block devices | ||
1871 | |||
1872 | John Wright (1): | ||
1873 | edd_id: add cciss devices | ||
1874 | |||
1875 | Kay Sievers (46): | ||
1876 | version bump | ||
1877 | libudev: path_encode - always return 0 if encoded string does not fit into size | ||
1878 | libudev: monitor - clarify socket handling documentation | ||
1879 | udevd: log error for too old kernels or CONFIG_SYSFS_DEPRECATED | ||
1880 | rules: remove DVB shell script | ||
1881 | update NEWS | ||
1882 | cdrom_id: add Xen cdrom support | ||
1883 | test-libudev: update monitor source | ||
1884 | TODO: add packet filter | ||
1885 | update NEWS | ||
1886 | cdrom_id: add and use ID_CDROM_MEDIA to decide if we run vol_id | ||
1887 | libudev: monitor - add client socket filter for subsystem value | ||
1888 | udevadm: monitor - print error if we can not bind to socket | ||
1889 | update TODO | ||
1890 | udevadm monitor - add --subsystem-match= | ||
1891 | libudev: monitor - use simpler hash | ||
1892 | libudev: monitor - switch to filter_add_match_subsystem_devtype() | ||
1893 | libudev: monitor - do not filter messages with wrong magic | ||
1894 | udevadm: monitor - add <subsytem>:<devtype> support | ||
1895 | libudev: monitor - add udev_monitor_filter_remove | ||
1896 | libudev: queue - fix get_seqnum_is_finished() | ||
1897 | cdrom_id: skip media tests if CDROM_DRIVE_STATUS != CDS_DISC_OK | ||
1898 | libudev: queue - clarify comments | ||
1899 | libudev: monitor - export filter_update() | ||
1900 | update NEWS | ||
1901 | drop "extern" keyword from non-static function | ||
1902 | rule_generator: net - fix usb comment generation | ||
1903 | rules: input - add links for USB/platform non-kbd/mouse devices | ||
1904 | rules: input - fix comments | ||
1905 | rules: add rfcomm* to group dialout | ||
1906 | accept DEVNAME from the kernel as a hint for the node name | ||
1907 | update TODO | ||
1908 | build: use AC_MSG_RESULT | ||
1909 | rules: add "event*" match | ||
1910 | udevd: revert initial device node creation | ||
1911 | rules: remove initramfs comment | ||
1912 | handle devtmpfs nodes | ||
1913 | oops, removed ppp entry from rules got committed | ||
1914 | remove all PHYSDEVPATH handling and warning about | ||
1915 | remove asmlinkage | ||
1916 | rules: fix ieee1394 rules | ||
1917 | add "static" back to the inline functions | ||
1918 | update TODO | ||
1919 | delete vol_id and require util-linux-ng's blkid | ||
1920 | delete libvolume_id | ||
1921 | |||
1922 | Lubomir Rintel (1): | ||
1923 | rule-generator: net - whitelist NICs that violate MAC local scheme | ||
1924 | |||
1925 | |||
1926 | Summary of changes from v140 to v141 | ||
1927 | ============================================ | ||
1928 | |||
1929 | Adam Buchbinder (4): | ||
1930 | usb_id: add manpage | ||
1931 | cdrom_id: update manpage | ||
1932 | create_floppy_devices: expand manpage | ||
1933 | vol_id: fix language in manpage | ||
1934 | |||
1935 | Alan Jenkins (1): | ||
1936 | avoid leaking netlink socket fd to external programs | ||
1937 | |||
1938 | Borislav Petkov (1): | ||
1939 | rules: rename ide-floppy to ide-gd | ||
1940 | |||
1941 | David Brownell (1): | ||
1942 | rules: exclude mtd* from persistent disk links | ||
1943 | |||
1944 | Kay Sievers (15): | ||
1945 | rules: fix extra quote in 50-udev-default.rules | ||
1946 | version bump | ||
1947 | udevadm: test - handling trailing '/' in devpath | ||
1948 | udevadm: monitor - clarify printed header | ||
1949 | rules: remove ram* from persisten disk links blacklist | ||
1950 | rules: serial - support ttyACM devices | ||
1951 | rules: replace IDE driver with media match | ||
1952 | usb_id: add ID_VENDOR_ID, ID_MODEL_ID, ID_USB_INTERFACE_NUM, ID_USB_DRIVER | ||
1953 | libudev: GPL -> LGPL | ||
1954 | usb_id: remove unused variable | ||
1955 | send monitor events back to netlink socket | ||
1956 | "UDEV_MONITOR_KERNEL/UDEV" -> "kernel/udev" | ||
1957 | IMPORT: 2048 -> 4096 bytes buffer | ||
1958 | path_encode: fix max length calculation | ||
1959 | libudev: monitor - unify socket message handling | ||
1960 | |||
1961 | Michal Soltys (1): | ||
1962 | rules: md-raid.rules fix | ||
1963 | |||
1964 | Robby Workman (1): | ||
1965 | udevadm: trigger - add "--action" to --help | ||
1966 | |||
1967 | Scott James Remnant (1): | ||
1968 | libudev: monitor - ignore messages from unusual sources | ||
1969 | |||
1970 | |||
1971 | Summary of changes from v139 to v140 | ||
1972 | ============================================ | ||
1973 | |||
1974 | Harald Hoyer (1): | ||
1975 | libvolume_id: bump age | ||
1976 | |||
1977 | Kay Sievers (12): | ||
1978 | version bump | ||
1979 | update TODO | ||
1980 | volume_id: ntfs - fix uuid setting | ||
1981 | update TODO | ||
1982 | rules: Fedora update | ||
1983 | libudev: queue - use lstat() to check existence of symlink | ||
1984 | udevadm: settle - add --seq-start= --seq-end= | ||
1985 | udevd: switch watch symlinks to devpath | ||
1986 | udevadm: add text for new options to command and man page | ||
1987 | update TODO | ||
1988 | libudev: ctrl - return error after sending ctrl message | ||
1989 | udevadm: settle - use timeout signal, instead of loop counter | ||
1990 | |||
1991 | Michael Prokop (1): | ||
1992 | fix compile error in debug mode | ||
1993 | |||
1994 | Scott James Remnant (1): | ||
1995 | udevadm: settle - synchronise with the udev daemon | ||
1996 | |||
1997 | |||
1998 | Summary of changes from v138 to v139 | ||
1999 | ============================================ | ||
2000 | |||
2001 | Kay Sievers (11): | ||
2002 | version bump | ||
2003 | remove static local variable | ||
2004 | use the event udev_device to disable the watch on "remove" | ||
2005 | add "nowatch" to disable a default installed watch with a later rule | ||
2006 | add m4/ subdir | ||
2007 | use AC_USE_SYSTEM_EXTENSIONS instead of AC_GNU_SOURCE | ||
2008 | usb_id: add ID_USB_INTERFACES=:0e0100:0e0200:010100:010200: | ||
2009 | usb_id: return values if called directly for an usb_device | ||
2010 | usb_id: fix NULL string usage | ||
2011 | usb_id: fix comment | ||
2012 | udevadm: info - export all devices with --export-db | ||
2013 | |||
2014 | Scott James Remnant (10): | ||
2015 | Don't add inotify watch until RUN rules processed. | ||
2016 | Clear existing inotify watch before processing. | ||
2017 | Cleanup a little. | ||
2018 | Allow watch handle to be stored in the udevdb. | ||
2019 | Store watch handle in db. | ||
2020 | Use the udevdb to speed up watch clearing. | ||
2021 | Put a log message in a more sensible place. | ||
2022 | Output watch handle in udevadm info. | ||
2023 | lookup the old watch handle; reload only if has a path | ||
2024 | Look at more inotify events in the buffer than just the first. | ||
2025 | |||
2026 | |||
2027 | Summary of changes from v137 to v138 | ||
2028 | ============================================ | ||
2029 | |||
2030 | David Zeuthen (1): | ||
2031 | *_id: add model/vendor enc strings | ||
2032 | |||
2033 | Karel Zak (2): | ||
2034 | vol_id: fix ddf version string | ||
2035 | vol_id: add missing id->type to swap0 | ||
2036 | |||
2037 | Kay Sievers (13): | ||
2038 | man: fix grammar | ||
2039 | version bump | ||
2040 | fix NAME="" logic | ||
2041 | rules: dm - add escape for uuid links with whitespace | ||
2042 | test: add test for empty and non-existent ATTR | ||
2043 | rules: fix md "change"/"remove" handling | ||
2044 | autogen.sh: add more warnings | ||
2045 | fix NAME= and OPTION+="string_escape=..." logic | ||
2046 | rules: move OPTIONS to separate rule | ||
2047 | use global "reload_config" flag | ||
2048 | rules: add "watch" option to dm and md rules | ||
2049 | rules: include loop block devices in persistent links | ||
2050 | release 138 | ||
2051 | |||
2052 | Matthias Schwarzott (1): | ||
2053 | rules: Gentoo update | ||
2054 | |||
2055 | Miklos Vajna (1): | ||
2056 | doc: writing udev rules - refer to 'udevadm info' instead of 'udevinfo' | ||
2057 | |||
2058 | Scott James Remnant (2): | ||
2059 | udevd: optionally watch device nodes with inotify | ||
2060 | rules: update persistent storage rules to use inotify watches | ||
2061 | |||
2062 | |||
2063 | Summary of changes from v136 to v137 | ||
2064 | ============================================ | ||
2065 | |||
2066 | Alan Jenkins (2): | ||
2067 | man: typo fixes | ||
2068 | remove stray initializer | ||
2069 | |||
2070 | Kay Sievers (17): | ||
2071 | version bump | ||
2072 | rules: fix typo in ide cd rule | ||
2073 | libudev: use 4096 bytes buffer for attribute reading | ||
2074 | rules: add drm devices to group "video" | ||
2075 | do not complain about a missing /etc/udev/rules.d/ | ||
2076 | udevadm: test - remove --force option | ||
2077 | update NEWS | ||
2078 | remove name from index if the node name has changed | ||
2079 | cleanup old names before creating the new names | ||
2080 | open-code pollfd setup | ||
2081 | increase netif renaming timeout from 30 to 90 seconds | ||
2082 | Merge commit '5f03ed8a56d308af72db8a48ab66ed68667af2c6' | ||
2083 | Merge commit '9032f119f07ad3b5116b3d4858816d851d4127de' | ||
2084 | split up long line | ||
2085 | udevd: add back SA_RESTART | ||
2086 | usb_id: handle ATAPI devices like SCSI devices | ||
2087 | udevadm: settle - fix typo | ||
2088 | |||
2089 | Lennart Poettering (1): | ||
2090 | fix naming for tape nst devices in /dev/tape/by-path/ | ||
2091 | |||
2092 | Olaf Kirch (2): | ||
2093 | udevd: use ppoll instead of signal pipes | ||
2094 | reap children faster | ||
2095 | |||
2096 | Scott James Remnant (2): | ||
2097 | Allow user and group lookup to be disabled. | ||
2098 | Expose delayed name resolution | ||
2099 | |||
2100 | Sven Jost (1): | ||
2101 | volume_id: support via raid version 2 | ||
2102 | |||
2103 | |||
2104 | Summary of changes from v135 to v136 | ||
2105 | ============================================ | ||
2106 | |||
2107 | Adam Buchbinder (1): | ||
2108 | extras: fix mis-spelling of "environment" | ||
2109 | |||
2110 | Harald Hoyer (1): | ||
2111 | rule_generator: fix enumeration for write_cd_rules | ||
2112 | |||
2113 | Jeremy Higdon (1): | ||
2114 | path_id: rework SAS persistent names | ||
2115 | |||
2116 | Karel Zak (1): | ||
2117 | volume_id: HPFS code clean up | ||
2118 | |||
2119 | Kay Sievers (54): | ||
2120 | rules: ATA_COMPAT do not try to match on sr*, it will never have vendor ATA | ||
2121 | scsi_id: do not fail if no serial is found like for optical drives | ||
2122 | update configure and NEWS | ||
2123 | rules: fix isdn rules | ||
2124 | rules: add persistent /dev/serial/{by-id,by-path} rules | ||
2125 | make: install serial rules file | ||
2126 | make: do not delete autotools generated file with distclean | ||
2127 | udevadm: settle - allow --timeout=0 and --quiet | ||
2128 | rules: move aoe rules to default rules file | ||
2129 | volume_id: btrfs - update format | ||
2130 | rules: add "do not edit header" | ||
2131 | volume_id: support sub-uuid's and plug in btrfs device uuid | ||
2132 | libudev: include <sys/types.h> | ||
2133 | build: add -lsepol | ||
2134 | build: just use autoreconf -i | ||
2135 | rules: remove ide-scsi | ||
2136 | rules: first simple step merging with Ubuntu rules | ||
2137 | "'/sbin/modprobe abnormal' exit" - also print program options | ||
2138 | rules: more changes toward Ubuntu rules merge | ||
2139 | rules: more changes toward Ubuntu rules merge | ||
2140 | rules: remove /dev/raw/raxctl symlink, it's a devfs leftover | ||
2141 | rules: rtc - create rtc compat link only for cmos type rtc | ||
2142 | rules: remove legacy symlinks | ||
2143 | rules: do not put raw1394 in "video" group | ||
2144 | rules: second round merging with Ubuntu rules | ||
2145 | rules: remove /dev/dsp /dev/audio | ||
2146 | rules: put alsa in group "audio" | ||
2147 | rules: isdn - remove /dev/isdn/capi20 symlink | ||
2148 | rules: provide /dev/raw/rawctl | ||
2149 | if needed, store database entries also for devices which do not have a device node | ||
2150 | build: use autoreconf --symlink | ||
2151 | usb_id: add "image" class | ||
2152 | require non-SYSFS_DEPRECATED 2.6.20+ kernel | ||
2153 | build: default to --prefix=/usr --exec-prefix="" | ||
2154 | libudev: enumerate - add lookup by property | ||
2155 | rules: input - make sure needed variables are set | ||
2156 | libudev: device - read "uevent" only if info is not already loaded | ||
2157 | libudev: subsytem -> subsystem | ||
2158 | libudev: bump revision | ||
2159 | usb_id: use devtype lookup | ||
2160 | require 2.6.22+ kernel | ||
2161 | rules: Ubuntu merge - use group "cdrom" | ||
2162 | rules: Ubuntu merge - use group "tape" | ||
2163 | rules: replace DVB shell script rule | ||
2164 | rules: Ubuntu merge - s/uucp/dialout/ | ||
2165 | update NEWS | ||
2166 | update NEWS | ||
2167 | enable skipping of "naming-only" rules | ||
2168 | usb_id: s/image/media/ | ||
2169 | udevadm: s/udevinfo/udevadm info/ | ||
2170 | rules: reorder block rules | ||
2171 | rules: zaptel - add "dialout" group | ||
2172 | libudev: device - add udev_device_get_property_value() | ||
2173 | libudev: test - add udev_device_get_property_value() | ||
2174 | |||
2175 | Marcel Holtmann (3): | ||
2176 | libudev: device - add devtype support | ||
2177 | libudev: device - lookup subsystem and devtype together | ||
2178 | libudev: device - remove udev_device_get_parent_with_subsystem | ||
2179 | |||
2180 | Michal Soltys (1): | ||
2181 | man: udev - update NAME assignment | ||
2182 | |||
2183 | Ryan Thomas (1): | ||
2184 | rules: add rules for AoE devices | ||
2185 | |||
2186 | |||
2187 | Summary of changes from v134 to v135 | ||
2188 | ============================================ | ||
2189 | |||
2190 | Kay Sievers (6): | ||
2191 | usb_id: add "break" to currently unused case labels | ||
2192 | rules: fix cciss disk/by-id/ links | ||
2193 | rules: add infiniband rules | ||
2194 | rules: infiniband.rules -> 40-infiniband.rules | ||
2195 | fix network interface name swapping | ||
2196 | update configure and NEWS | ||
2197 | |||
2198 | Marcel Holtmann (1): | ||
2199 | usb_id: fix switch statement for video type | ||
2200 | |||
2201 | Piter PUNK (2): | ||
2202 | rules: /dev/null -> X0R | ||
2203 | rules: add usb device nodes | ||
2204 | |||
2205 | |||
2206 | Summary of changes from v133 to v134 | ||
2207 | ============================================ | ||
2208 | |||
2209 | Gabor Z. Papp (1): | ||
2210 | include errno.h in sysdeps.h | ||
2211 | |||
2212 | Harald Hoyer (1): | ||
2213 | rules: add persistent rules for memory stick block devices | ||
2214 | |||
2215 | Kay Sievers (19): | ||
2216 | autogen.sh: fix -print-multi-os-directory usage | ||
2217 | volume_id: update btrfs magic | ||
2218 | bump version | ||
2219 | rules: merge group "video" into default rules | ||
2220 | rules: v4l - add by-id/ links for USB devices | ||
2221 | libudev: accept NULL whitelist in util_replace_chars() | ||
2222 | usb_id: replace chars in returned strings | ||
2223 | ata_id: make sure, we do not have slashes in values | ||
2224 | scsi_id: make sure, we do not have slashes in values | ||
2225 | volume_id: remove unused usage types | ||
2226 | vol_id: if regular files are probed, use stat() for the size value | ||
2227 | volume_id: update btrfs | ||
2228 | volume_id: clear probing result before probing and do not probe a second time, if not needed | ||
2229 | path_id: fix fibre channel handling | ||
2230 | update NEWS TODO | ||
2231 | floppy: use ARRAY_SIZE() | ||
2232 | fix handling of swapping node name with symlink name | ||
2233 | silence PHYSDEV* warning for WAIT_FOR* rules | ||
2234 | rules: exclude "btibm" devices from vol_id calls | ||
2235 | |||
2236 | Matthias Schwarzott (1): | ||
2237 | rules: Gentoo update | ||
2238 | |||
2239 | Peter Breitenlohner (2): | ||
2240 | man: fix typos | ||
2241 | floppy: fix array bounds check and minor calculation | ||
2242 | |||
2243 | |||
2244 | Summary of changes from v132 to v133 | ||
2245 | ============================================ | ||
2246 | |||
2247 | Alan Jenkins (2): | ||
2248 | udevd: de-duplicate strings in rules | ||
2249 | scsi_id: we don't use DEVPATH env var anymore, update man page | ||
2250 | |||
2251 | Karel Zak (1): | ||
2252 | volume_id: fat - move check for msdos signature (0x55 0xaa) | ||
2253 | |||
2254 | Kay Sievers (22): | ||
2255 | silence "comparison between signed and unsigned" | ||
2256 | string index - split nodes and childs to allow and unlimited number of childs | ||
2257 | reserve child slot 0 | ||
2258 | merge trie nodes, childs and root into a single array | ||
2259 | set errno = ENOSYS in inotify stub | ||
2260 | udevadm: info - unify -V and --version | ||
2261 | rules: remove DEVTYPE disk/partition | ||
2262 | rules: remove pnp shell script, acpi loads these modules properly | ||
2263 | update NEWS | ||
2264 | configure: add linux-hotplug mail address | ||
2265 | remove len == 0 check, the index root is always '\0' | ||
2266 | volume_id: bump revision | ||
2267 | volume_id: always check for all filesystem types and skip conflicting results | ||
2268 | volume_id: fat - accept empty FAT32 fsinfo signature | ||
2269 | fix spelling in comment | ||
2270 | volume_id: ntfs - mark as no other fs must match | ||
2271 | vol_id: clarify error message | ||
2272 | libudev: device - handle disk "device" link for partitions in deprecated sysfs layout | ||
2273 | limit $attr(<symlink>) magic to well-known links only | ||
2274 | udevd: fix cleanup of /dev/.udev/uevent_seqnum | ||
2275 | fix $links substitution for devices without any link | ||
2276 | update NEWS | ||
2277 | |||
2278 | Sergey Vlasov (1): | ||
2279 | udevadm: fix option parsing breakage with klibc | ||
2280 | |||
2281 | |||
2282 | Summary of changes from v131 to v132 | ||
2283 | ============================================ | ||
2284 | |||
2285 | Kay Sievers (2): | ||
2286 | fix size_t compiler warning on 32 bit platforms | ||
2287 | convert debug string arrays to functions | ||
2288 | |||
2289 | |||
2290 | Summary of changes from v130 to v131 | ||
2291 | ============================================ | ||
2292 | |||
2293 | Alan Jenkins (17): | ||
2294 | libudev: fix sysnum logic for digit-only device names | ||
2295 | udevd: avoid overhead of calling rmdir on non-empty directories | ||
2296 | use more appropriate alternatives to malloc() | ||
2297 | libudev: util - optimize path_encode() | ||
2298 | libudev: allocate udev_device->envp[] dynamically | ||
2299 | replace strncpy() with strlcpy() | ||
2300 | use re-entrant variants of getpwnam and getgrnam | ||
2301 | udevd: fix memory leak | ||
2302 | udevd: fix WAIT_FOR_SYSFS execution order | ||
2303 | fix handling of string_escape option | ||
2304 | udevd: use a tighter loop for compare_devpath() | ||
2305 | udevd: avoid implicit memset in match_attr() | ||
2306 | kerneldoc comment fixes | ||
2307 | udevd: simplify rules execution loop | ||
2308 | udevd: fix termination of rule execution | ||
2309 | udevd: be more careful when matching against parents | ||
2310 | udevd: shrink struct token to 12 bytes | ||
2311 | |||
2312 | Kay Sievers (113): | ||
2313 | remove outdated docs/README-gcov_for_udev | ||
2314 | libudev: device - add device lookup by subsystem:sysname | ||
2315 | libudev: also prefix non-exported functions with udev_* | ||
2316 | libudev: add udev_monitor_send_device() | ||
2317 | libudev: list - add flag | ||
2318 | libudev: device - generate DEVNAME and DEVLINKS properties | ||
2319 | vol_id: update README | ||
2320 | libudev: handle ! in sysname, add sysnum, return allocated list_entry on add | ||
2321 | delete simple-build-check.sh | ||
2322 | test: move global ENV{ENV_KEY_TEST}="test" to local rule | ||
2323 | libudev: monitor - fix send_device() property copying | ||
2324 | libudev: device - add get_envp() to construct envp from property list | ||
2325 | libudev: do not include ctrl in libudev.so | ||
2326 | libudev: monitor - do not mangle DEVLINKS property | ||
2327 | libudev: update DEVLINKS property when properties are read | ||
2328 | libudev: device - lookup "subsystem" and "driver" only once | ||
2329 | libudev: device - export properties when values are set | ||
2330 | libudev: list - handle update of key with NULL value | ||
2331 | libudev: ctrl - fix typo in set_env() | ||
2332 | libudev: add global property list | ||
2333 | libudev: device - copy global properties, unset empty properties | ||
2334 | volume_id: btrfs - update magic to latest disk format | ||
2335 | udevd: use libudev | ||
2336 | move udev_device_db to libudev | ||
2337 | rename udev source files | ||
2338 | libudev: always add UDEV_LOG | ||
2339 | libudev: monitor - export MAJOR/MINOR only if available | ||
2340 | udev-node: name_list -> udev_list | ||
2341 | udev-rules-parse: name_list -> udev_list | ||
2342 | delete name_list, move common file functions | ||
2343 | fix sorting of rules files | ||
2344 | run_program: prevent empty last argv entry | ||
2345 | update IMPORT= file/stdout property parsing | ||
2346 | update rules file parsing | ||
2347 | delete udev-util-file.c | ||
2348 | libudev: list - prepend udev_* to all functions | ||
2349 | libudev: add sysnum to test program | ||
2350 | test: fix a few unintentially wrongly written rules which cause parse errors | ||
2351 | libudev: monitor - add set_receive_buffer_size() | ||
2352 | libudev: ctrl - change magic to integer | ||
2353 | libudev: make list_node functions available | ||
2354 | udevd: use udev_list_node | ||
2355 | collect: use udev_list | ||
2356 | delete list.h | ||
2357 | merge udev-rules.c and udev-rules-parse.c | ||
2358 | make struct udev_rules opaque | ||
2359 | move run_program to util | ||
2360 | udev_event_run() -> udev_event_execute_rules() | ||
2361 | udev_rules_run() -> udev_event_execute_run(); | ||
2362 | move udev_rules_apply_format() to udev-event.c | ||
2363 | udev_list_cleanup() -> udev_list_cleanup_entries() | ||
2364 | selinux_init(udev) -> udev_selinux_init(udev) | ||
2365 | prefix udev-util.c functions with util_* | ||
2366 | pass make distcheck | ||
2367 | libudev: device - get_attr_value() -> get_sysattr_value() | ||
2368 | cdrom_id: remove ARRAY_SIZE() declaration | ||
2369 | replace missing get_attr_value() -> get_sysattr_value() | ||
2370 | add "root" == 0 shortcuts to lookup_user/group() | ||
2371 | do not use the new work-in-progress parser rule matcher | ||
2372 | libudev: device - 128 -> ENVP_SIZE | ||
2373 | add util_resolve_subsys_kernel() | ||
2374 | handle numerical owner/group string in lookup_user/group() | ||
2375 | replace in-memory rules array with match/action token list | ||
2376 | do not create temporary node ($tempnode) if node already exists | ||
2377 | shrink struct udev_event | ||
2378 | shrink struct udev_event | ||
2379 | rule_generator: fix netif NAME= value extraction regex | ||
2380 | skip SYMLINK rules for devices without a device node | ||
2381 | rules: let empty strings added to buffer always return offset 0 | ||
2382 | fix uninitialized variable warnings | ||
2383 | cache uid/gid during rule parsing | ||
2384 | distinguish "match" from "assign" by (op < OP_MATCH_MAX) | ||
2385 | determine at rule parse time if we need to call fnmatch() | ||
2386 | special-case "?*" match to skip fnmatch() | ||
2387 | libudev: monitor - replace far too expensive snprintf() with strlcpy() | ||
2388 | libudev: monitor - cache result of monitor send buffer | ||
2389 | fix "unused" warnings | ||
2390 | remove debug printf | ||
2391 | match KEY="A|B" without temporary string copy | ||
2392 | match_attr() - copy attr value only when needed | ||
2393 | do not init string arrays, just clear first byte | ||
2394 | fix $attr{[<subsystem>/<sysname>]<attribute>} substitution | ||
2395 | libudev: device - fill envp array while composing monitor buffer | ||
2396 | test: add RUN+="socket: ..." to a test to run monitor code | ||
2397 | libudev: device - allocate envp array only once | ||
2398 | update NEWS | ||
2399 | udevd: merge exec and run queue to minimize devpath string compares | ||
2400 | ATTR{}== always fails if the attribute does not exist | ||
2401 | rules: remove SCSI timeouts | ||
2402 | rules: remove "add" match from usb device node rule | ||
2403 | edd_id: add "change" event match | ||
2404 | fstab_import: add "change" event match | ||
2405 | write trace log to stderr | ||
2406 | log rules file and line number when NAME, SYMLINK, OWNER, GROUP, MODE, RUN is applied | ||
2407 | skip entire rule containing device naming keys, if no device can be named | ||
2408 | fix udev_node_update_old_links() logic | ||
2409 | move some info() to dbg() | ||
2410 | add "devel" and "install" switches to autogen.sh | ||
2411 | move debugging strings inside #ifdef DEBUG | ||
2412 | firmware.sh: record missing files in /dev/.udev/firmware-missing/ | ||
2413 | fix list handling in enumerate and rules file sorting | ||
2414 | volume_id: btrfs update | ||
2415 | info() PROGRAM and IMPORT execution | ||
2416 | fix $links substitution | ||
2417 | fix cleanup of possible left-over symlinks | ||
2418 | do not import the "uevent" file when we only read the db to get old symlinks | ||
2419 | usb_id: MassStorage SubClass 6 is "scsi" not "disk" | ||
2420 | unify string replacement | ||
2421 | $links should be relative | ||
2422 | fix indentation | ||
2423 | rules: md - add mdadm 3 device naming | ||
2424 | cleanup /dev/.udev/queue on startup and exit | ||
2425 | udevadm: settle - exit if udevd exits | ||
2426 | |||
2427 | Matthias Koenig (1): | ||
2428 | volume_id: swap - larger PAGE_SIZE support | ||
2429 | |||
2430 | Steven Whitehouse (1): | ||
2431 | volume_id: support for GFS2 UUIDs | ||
2432 | |||
2433 | |||
2434 | Summary of changes from v129 to v130 | ||
2435 | ============================================ | ||
2436 | |||
2437 | Kay Sievers (26): | ||
2438 | fix compile error with --disable-logging | ||
2439 | libudev: enumerate - add_device() -> add_syspath() | ||
2440 | volume_id: hpfs - read label and uuid | ||
2441 | use no_argument, required_argument, optional_argument in longopts | ||
2442 | libudev: get rid of selinux | ||
2443 | libudev: device - add get_parent_with_subsystem() | ||
2444 | usb_id: use libudev | ||
2445 | udevadm: info - fix --query=all for devices without a device node | ||
2446 | vol_id: add size= option | ||
2447 | move selinux noops to udev.h | ||
2448 | volume_id: add dbg() as noop to check for compile errors | ||
2449 | vol_id: fix logging glue | ||
2450 | vol_id: always use the safe string versions for unencoded label and uuid | ||
2451 | volume_id: better DDF raid detection | ||
2452 | volume_id: add btrfs | ||
2453 | volume_id: use PRIu64i, PRIx64 macros | ||
2454 | udevd: clarify deprecated sysfs layout warning | ||
2455 | libudev: fix --enable-debug | ||
2456 | don not print error if GOTO jumps just to next rule | ||
2457 | volume_id: add more vfat debugging information | ||
2458 | libudev: libudev.pc remove selinux | ||
2459 | store node name and symlinks into db symlink target if they are small enough | ||
2460 | volume_id: more fat debugging | ||
2461 | libudev: fix typo in "multiple entries in symlink" handling | ||
2462 | connect /sys and /dev with /sys/dev/{block,char}/<maj>:<min> and /dev/{block,char}/<maj>:<min> | ||
2463 | replace spaces in dm and md name symlinks | ||
2464 | |||
2465 | |||
2466 | Summary of changes from v128 to v129 | ||
2467 | ============================================ | ||
2468 | |||
2469 | Alan Jenkins (7): | ||
2470 | udev-test.pl: set non-zero exitcode if tests fail | ||
2471 | scsi_id: compiler warning on 32-bit | ||
2472 | trivial cleanup in udev_rules_iter | ||
2473 | avoid repeated scans for goto targets (udev_iter_find_label) | ||
2474 | replace strerror() usage with threadsafe "%m" format string | ||
2475 | fix messages (inc. debug compile failure) introduced when optimizing "goto" | ||
2476 | allow compiler to check dbg() arguments on non-debug builds | ||
2477 | |||
2478 | Kay Sievers (46): | ||
2479 | libudev: switch to "udev_device_get_parent" | ||
2480 | libudev: udev_device - add attribute cache | ||
2481 | libudev: handle "device" link as parent, handle "class" "block" as "subsystem" | ||
2482 | udevadm: info - fix lookup-by-name | ||
2483 | libudev: switch API from devpath to syspath | ||
2484 | libudev: rename ctrl_msg to ctrl_msg_wire | ||
2485 | vol_id: fix lib logging glue | ||
2486 | fix broken symlink resolving | ||
2487 | fix udevadm trigger | ||
2488 | libudev: pass udev_device in enumerate | ||
2489 | libudev: fix "subsystem" value | ||
2490 | always include config.h from Makefile | ||
2491 | libudev: udev_device_get_devname -> udev_device_get_devnode | ||
2492 | libudev: add udev_device_new_from_devnum() | ||
2493 | libudev: also import "uevent" file when reading udev database | ||
2494 | libudev: add userdata pointer | ||
2495 | libudev: replace awkward callback list interfaces with list iterators | ||
2496 | libudev: get devnum from uevent file | ||
2497 | libudev: enumerate_get_devices_list -> enumerate_get_list | ||
2498 | libudev: initialize selinux only when needed | ||
2499 | libudev: device - read database only when needed | ||
2500 | libudev: rework list handling | ||
2501 | libudev: more list rework | ||
2502 | lubudev: accept more sys directories as devices, and parent devices | ||
2503 | libudev: enumerate - accept list of subsystems to scan, or skip | ||
2504 | libudev: enumerate "subsystem" | ||
2505 | libudev: enumerate - scan /sys/block/ if needed | ||
2506 | libudev: enumerate - split new() and scan() | ||
2507 | test: replace ancient sysfs tree with recent one | ||
2508 | test: add missing pci directory because of .gitignore *.7 | ||
2509 | gitignore: move *.8 to subdirs | ||
2510 | test: replace last reference of "/class/*" devpath | ||
2511 | fix dbg() callers | ||
2512 | libudev: enumerate - scan devices and subsystems, add subsystem and attribute filter | ||
2513 | udevadm: trigger: use libudev | ||
2514 | fix segfault caused by wrong pointer used in dbg() | ||
2515 | libudev: device_init() -> device_new() | ||
2516 | udevadm: trigger fix long option --type= | ||
2517 | libudev: add queue interface | ||
2518 | udevadm: settle - use libudev queue | ||
2519 | libudev: device - handle /sys/block/<disk-device-link>/<partition> | ||
2520 | libudev: enumerate - ignore regular files while scanning | ||
2521 | udevadm: trigger --type=failed - use libudev queue | ||
2522 | rules: ieee1394 - create both, by-id/scsi-* and by-id/ieee-* links | ||
2523 | build: include Makefile.am.inc in all Makefile.am | ||
2524 | udevd: print warning if CONFIG_SYSFS_DEPRECATED is used | ||
2525 | |||
2526 | |||
2527 | Summary of changes from v127 to v128 | ||
2528 | ============================================ | ||
2529 | |||
2530 | Alan Jenkins (8): | ||
2531 | fix uninitialized name_list error::ignore_error | ||
2532 | do not needlessly declare some local variables in udev_rules_parse.c as static | ||
2533 | remove deprecated envp[] in main() | ||
2534 | fix name compare bug name_list_key_add() | ||
2535 | remove redundant string copy in udev_rules_apply_format() | ||
2536 | remove redundant "remove trailing newlines" in udevadm info | ||
2537 | threadsafe rules iteration | ||
2538 | fix off-by-one in pass_env_to_socket() | ||
2539 | |||
2540 | Kay Sievers (53): | ||
2541 | libudev: add monitor documentation | ||
2542 | libudev: fix --disable-log | ||
2543 | autogen.sh: add --with-selinux | ||
2544 | volume_id: hfs - calculate proper uuid | ||
2545 | fix dangling pointer returned by attr_get_by_subsys_id() | ||
2546 | udev-test.pl: add --valgrind option | ||
2547 | libudev: libudev.pc add Libs.private | ||
2548 | volume_id: fail on undefined __BYTE_ORDER | ||
2549 | remove FAQ | ||
2550 | libudev: fix monitor documentation | ||
2551 | libudev: add udev_device_get_syspath() | ||
2552 | udev_device_init() remove statically allocated device support | ||
2553 | udevadm: info - fix broken --device-id-of-file= | ||
2554 | udevadm: control - use getopt_long() | ||
2555 | udevadm: print warning to stderr if udevadm is called by symlink | ||
2556 | udev-test.pl: remove left-over comment from --valgrind option | ||
2557 | udevadm: rename source files | ||
2558 | udevadm: rename internal functions to udevadm_* | ||
2559 | udevadm: split out control functions | ||
2560 | udevadm: move init from commands to udevadm | ||
2561 | autogen.sh: add debug | ||
2562 | use libudev code, unify logging, pass udev context around everywhere | ||
2563 | volume_id: linux_raid - fix logic for volumes with size == 0 | ||
2564 | vol_id: add --debug option | ||
2565 | udevadm: add --version --help options to man page, hide them as commands | ||
2566 | move udev_ctrl to libudev-private | ||
2567 | udev-test.pl: set udev_log="err" | ||
2568 | test-udev: cleanup libudev context and overridden rules file string | ||
2569 | test-udev: remove unused var | ||
2570 | add a bunch of private device properties to udev_device | ||
2571 | udevadm: monitor - use libudev for udev monitor | ||
2572 | libudev: monitor - add event properties to udev_device | ||
2573 | udevadm: log message if udevadm link is used | ||
2574 | udevd: remove max_childs_running logic | ||
2575 | libudev: monitor- add netlink uevent support | ||
2576 | udevadm: monitor - use libudev code to retrieve device data | ||
2577 | libudev: udev_device - read "driver" value | ||
2578 | libudev: rename enumerate function | ||
2579 | libudev: add selinux | ||
2580 | libudev: initialize selinux after logging | ||
2581 | volume_id: merge util.h in libvolume_id-private.h | ||
2582 | update file headers | ||
2583 | libudev: udev_device - add more properties | ||
2584 | libudev: do not use udev_db.c | ||
2585 | libudev: get rid of udev_sysfs.c | ||
2586 | libudev: get rid of udev_utils.c | ||
2587 | libudev: rename libudev-utils.c libudev-util.c | ||
2588 | libudev: do not use any udev source file | ||
2589 | extras: use libudev code | ||
2590 | convert to libudev and delete udev_utils_string.c | ||
2591 | get rid of udev_sysdeps.c | ||
2592 | use size definitions from libudev | ||
2593 | udevadm: info - use "udev_device" | ||
2594 | |||
2595 | |||
2596 | Summary of changes from v126 to v127 | ||
2597 | ============================================ | ||
2598 | |||
2599 | Karel Zak (2): | ||
2600 | build-sys: don't duplicate file names | ||
2601 | build-sys: remove non-POSIX variable names | ||
2602 | |||
2603 | Kay Sievers (26): | ||
2604 | add inotify dummy definitions if inotify is not available | ||
2605 | build: remove autopoint check | ||
2606 | udevadm: trigger - add missing attr filter to synthesized "subsystem" register events | ||
2607 | ignore duplicated rules file names | ||
2608 | fix .gitignore | ||
2609 | rules: delete all distro rules which do not use default rules | ||
2610 | rules: add nvram | ||
2611 | rules: add isdn rules | ||
2612 | rules: Gentoo update | ||
2613 | add missing includes | ||
2614 | add some warnings | ||
2615 | update .gitignore | ||
2616 | add missing 'v' for "make changelog" | ||
2617 | build: fix "make dist" | ||
2618 | vol_id: make the --offset= argument optional | ||
2619 | rules: optical drives - probe at last session offset, do not probe for raid | ||
2620 | libudev: add library to access udev information | ||
2621 | libudev: split source files | ||
2622 | update INSTALL | ||
2623 | libudev: add udev event monitor API | ||
2624 | volume_id: remove deprecated functions and bump major version | ||
2625 | volume_id: remove left-over fd close() | ||
2626 | split udev_device.c to leave out rules handling from libudev | ||
2627 | libudev: link against selinux if needed | ||
2628 | firmware.sh: lookup lookup kernel provided firmware directory | ||
2629 | libudev: require LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE | ||
2630 | |||
2631 | Michal Soltys (1): | ||
2632 | rules: fix md rules for partitioned devices | ||
2633 | |||
2634 | |||
2635 | Summary of changes from v125 to v126 | ||
2636 | ============================================ | ||
2637 | |||
2638 | Kay Sievers (9): | ||
2639 | delete all Makefiles and move udev source to udev/ | ||
2640 | use autotools | ||
2641 | rules: mode 0660 for group "disk" | ||
2642 | rules: update Fedora rules | ||
2643 | update ChangeLog | ||
2644 | INSTALL: --enable-selinux not --with-selinux | ||
2645 | volume_id: move static lib to $prefix | ||
2646 | volume_id: create relative links | ||
2647 | rules: run vol_id on opticals only if media is found | ||
2648 | |||
2649 | Marco d'Itri (1): | ||
2650 | rules: Debian update | ||
2651 | |||
2652 | Thomas Koeller (1): | ||
2653 | use proper directory lib/lib64 for libvolume_id | ||
2654 | |||
2655 | |||
2656 | Summary of changes from v124 to v125 | ||
2657 | ============================================ | ||
2658 | |||
2659 | John Huttley (1): | ||
2660 | rules: tape rules - add nst to usb and 1394 links | ||
2661 | |||
2662 | Karl O. Pinc (1): | ||
2663 | man: clarify $attr{} parent searching | ||
2664 | |||
2665 | Kay Sievers (14): | ||
2666 | collect: fix size_t printf | ||
2667 | path_id: suppress trailing '-' like 'ID_PATH=pci-0000:05:01.0-' | ||
2668 | rules: add v4l persistent links | ||
2669 | docs: update some docs and delete outdated stuff | ||
2670 | scsi_id: fix fallback to sg v3 for sg nodes | ||
2671 | rules: fix cciss rules for partition numbers > 9 | ||
2672 | udev.conf: udevcontrol -> udevadm control | ||
2673 | rules: use consistently OPTIONS+= | ||
2674 | scsi_id: the fallback fix broke error handling | ||
2675 | man: rebuild from xml | ||
2676 | do not touch node ownership and permissions, if already correct | ||
2677 | rules: tape rules - add nst to by-path/ links | ||
2678 | udevadm: info - add --export format to --device-id-of-file= | ||
2679 | move default rules from /etc/udev/rules.d/ to /lib/udev/rules.d/ | ||
2680 | |||
2681 | Marco d'Itri (7): | ||
2682 | rules_generator: net rules - do not print error if file is missing and ignore commented rules | ||
2683 | man: add link_priority default value | ||
2684 | scsi_id: man page fix | ||
2685 | udevadm: settle - add verbose output when running into timeout | ||
2686 | rules: Debian update | ||
2687 | rules: Debian update | ||
2688 | ignore rule with GOTO to a non-existent label | ||
2689 | |||
2690 | Thomas Koeller (1): | ||
2691 | scsi_id: include sys/stat.h | ||
2692 | |||
2693 | Tobias Klauser (1): | ||
2694 | collect: check realloc return value | ||
2695 | |||
2696 | |||
2697 | Summary of changes from v123 to v124 | ||
2698 | ============================================ | ||
2699 | |||
2700 | Kay Sievers (1): | ||
2701 | cdrom_id: fix recognition of blank media | ||
2702 | |||
2703 | |||
2704 | Summary of changes from v122 to v123 | ||
2705 | ============================================ | ||
2706 | |||
2707 | Erik van Konijnenburg (3): | ||
2708 | add substitution in MODE= field | ||
2709 | Makefile: use udevdir in "make install" | ||
2710 | volume_id: support for oracleasm | ||
2711 | |||
2712 | Harald Hoyer (1): | ||
2713 | scsi_id: retry open() on -EBUSY | ||
2714 | |||
2715 | Karel Zak (2): | ||
2716 | volume_id: remove unnecessary global variable | ||
2717 | volume_id: enable GFS probing code, add LABEL support | ||
2718 | |||
2719 | Kay Sievers (5): | ||
2720 | edd_id: call it only for sd* and hd* | ||
2721 | rename WAIT_FOR_SYSFS to WAIT_FOR and accept an absolute path | ||
2722 | rules: tape rules - use bsg device nodes for SG_IO | ||
2723 | rules: persistent net - handle "locally administered" ibmveth MAC addresses | ||
2724 | cdrom_id: export ID_CDROM_MEDIA_TRACK_COUNT_AUDIO=, ID_CDROM_MEDIA_TRACK_COUNT_DATA= | ||
2725 | |||
2726 | Michal Soltys (1): | ||
2727 | man: add NAME== match entry | ||
2728 | |||
2729 | Xinwei Hu (2): | ||
2730 | collect: realloc buffer, if needed | ||
2731 | udevd: export .udev/queue/$seqnum before .udev/uevent_seqnum | ||
2732 | |||
2733 | |||
2734 | Summary of changes from v121 to v122 | ||
2735 | ============================================ | ||
2736 | |||
2737 | Hannes Reinecke (2): | ||
2738 | scsi_id: remove all sysfs dependencies | ||
2739 | scsi_id: add SGv4 support | ||
2740 | |||
2741 | Karel Zak (1): | ||
2742 | volume_id: clean up linux_raid code | ||
2743 | |||
2744 | Kay Sievers (8): | ||
2745 | scsi_id: update man page | ||
2746 | scsi_id: remove bus_id option | ||
2747 | scsi_id: add --sg-version= option | ||
2748 | rules: adapt to new scsi_id | ||
2749 | rules: adapt tape rules to new scsi_id | ||
2750 | scsi_id: add bsg.h | ||
2751 | volume_id: bump version | ||
2752 | Makefile: do not create udevcontrol, udevtrigger symlinks | ||
2753 | |||
2754 | MUNEDA Takahiro (2): | ||
2755 | man: udevd- fix udev(8) reference | ||
2756 | man: scsi_id | ||
2757 | |||
2758 | Matthias Schwarzott (1): | ||
2759 | cdrom_id: fix segfault | ||
2760 | |||
2761 | |||
2762 | Summary of changes from v120 to v121 | ||
2763 | ============================================ | ||
2764 | |||
2765 | Damjan Georgievski (1): | ||
2766 | libvolume_id: recognize swap partitions with a tuxonice hibernate image | ||
2767 | |||
2768 | Daniel Drake (1): | ||
2769 | writing udev rules: fix rule typos | ||
2770 | |||
2771 | David Woodhouse (1): | ||
2772 | rules_generator: net rules - add "dev_id" value to generated rules | ||
2773 | |||
2774 | Harald Hoyer (1): | ||
2775 | selinux: more context settings | ||
2776 | |||
2777 | Kay Sievers (21): | ||
2778 | udevinfo: do not replace chars when printing ATTR== matches | ||
2779 | vol_id: add --offset option | ||
2780 | cdrom_id: replace with version which also exports media properties | ||
2781 | udevd: at startup write message including version number to kernel log | ||
2782 | rules_generator: net rules - always add KERNEL== match to generated rules | ||
2783 | selinux: fix missing includes | ||
2784 | allow setting of MODE="0000" | ||
2785 | path_id: remove subsystem whitelist | ||
2786 | logging: add trailing newline to all strings | ||
2787 | scsi_id: initialize serial strings | ||
2788 | persistent device naming: also read unpartitioned media | ||
2789 | cdrom_id: add more help text | ||
2790 | add $links substitution | ||
2791 | fstab_import: add program to IMPORT matching fstab entry | ||
2792 | add OPTIONS+="event_timeout=<seconds>" | ||
2793 | write "event_timeout" to db | ||
2794 | udevadm: trigger - add --env= option | ||
2795 | udevadm: control - fix --env key to accept --env=<KEY>=<value> | ||
2796 | udevadm: info - do not print ATTR{dev}== | ||
2797 | persistent device naming: update tape rules | ||
2798 | rules: update md rules | ||
2799 | |||
2800 | |||
2801 | Summary of changes from v119 to v120 | ||
2802 | ============================================ | ||
2803 | |||
2804 | Kay Sievers (9): | ||
2805 | test: remove duplicated EXTRA entry | ||
2806 | rules: remove last WAIT_FOR_SYSFS, load ppdev, switch scsi_device | ||
2807 | udevadm: trigger - option to synthesize events and pass them to a socket | ||
2808 | udevadm: info - resolve devpath if symlink is given | ||
2809 | udevadm: remove old man page links and compat links for debugging tools | ||
2810 | udevadm: trigger - fix broken socket option check | ||
2811 | udevadm: trigger - fix --socket== + --verbose | ||
2812 | also accept real socket files for RUN+="socket:<path>" | ||
2813 | persistent device naming: cleanup storage rules | ||
2814 | |||
2815 | Michael Kralka (1): | ||
2816 | udevd: serialize events if they refer to the same major:minor number | ||
2817 | |||
2818 | |||
2819 | Summary of changes from v118 to v119 | ||
2820 | ============================================ | ||
2821 | |||
2822 | Anthony L. Awtrey (1): | ||
2823 | do not skip RUN execution if device node removal fails | ||
2824 | |||
2825 | Harald Hoyer (2): | ||
2826 | rules: Fedora update | ||
2827 | rules: do not set GROUP="disk" for scanners | ||
2828 | |||
2829 | Jiri Slaby (1): | ||
2830 | rules_generator: add missing write_net_rules unlock | ||
2831 | |||
2832 | Karel Zak (2): | ||
2833 | volume_id: fix UUID raw buffer usage | ||
2834 | volume_id: fix typo in function documentation | ||
2835 | |||
2836 | Kay Sievers (10): | ||
2837 | switch mailing lists to linux-hotplug@vger.kernel.org | ||
2838 | rules: remove tty rule which can never run because of an earlier "last_rule" | ||
2839 | volume_id: update ext detection | ||
2840 | selinux: set context for real file name not the temp name | ||
2841 | hack to allow ATTR{block/*/uevent}="change" | ||
2842 | rules_generator: add KERNEL=="<netifname>*" to generated rules | ||
2843 | persistent device naming: also run on "change" event | ||
2844 | test: add "subsystem" links to all devices | ||
2845 | sysfs: depend on "subsystem" link | ||
2846 | extend hack to allow TEST=="*/start" | ||
2847 | |||
2848 | Matthias Schwarzott (1): | ||
2849 | volume_id: respect LDFLAGS | ||
2850 | |||
2851 | Neil Williams (1): | ||
2852 | volume_id: add prefix=, exec_prefix= | ||
2853 | |||
2854 | Roy Marples (1): | ||
2855 | Makefile: do not require GNU install | ||
2856 | |||
2857 | |||
2858 | Summary of changes from v117 to v118 | ||
2859 | ============================================ | ||
2860 | |||
2861 | Daniel Drake (1): | ||
2862 | doc: update "writing udev rules" | ||
2863 | |||
2864 | Hannes Reinecke (1): | ||
2865 | volume_id: LVM - add uuid | ||
2866 | |||
2867 | Kay Sievers (9): | ||
2868 | remove udevstart | ||
2869 | rules_generator: do not create rules with insufficient matches | ||
2870 | man: udevadm settle - mention 180 seconds default timeout | ||
2871 | libvolume_id: squashfs - add endianess support for LZMA compression | ||
2872 | rules: add AOE rule | ||
2873 | volume_id: md - add metadata minor version | ||
2874 | volume_id: run only once into a timeout for unreadable devices | ||
2875 | create_floppy_devices: fix logic for more than one floppy device | ||
2876 | volume_id: also add readable check to probe_all() | ||
2877 | |||
2878 | Matthias Schwarzott (1): | ||
2879 | rules: Gentoo update | ||
2880 | |||
2881 | Michael Prokop (1): | ||
2882 | libvolume_id: squashfs+LZMA compression detection | ||
2883 | |||
2884 | |||
2885 | Summary of changes from v116 to v117 | ||
2886 | ============================================ | ||
2887 | |||
2888 | Dan Nicholson (2): | ||
2889 | extras: ignore built and generated files | ||
2890 | volume_id: create relative symlink when $(libdir) = $(usrlibdir) | ||
2891 | |||
2892 | Kay Sievers (15): | ||
2893 | usb_id: fail if vendor/product can not be retrieved | ||
2894 | rules: SUSE update | ||
2895 | firmware: do not print error if logger is missing | ||
2896 | volume_id: vfat - allow all possible sector sizes | ||
2897 | volume_id: LUKS - export version | ||
2898 | volume_id: ntfs - rely on valid master file table | ||
2899 | volume_id: bump version | ||
2900 | udevinfo: exclude "uevent" file from --attribute-walk | ||
2901 | udevadm: merge all udev tools into a single binary | ||
2902 | udevadm: accept command as option, like --help, --version | ||
2903 | udevadm: add info option --device-id-of-file=<file> | ||
2904 | Makefile: fix bogus version number than got committed | ||
2905 | udevadm: also return major==0 results for --device-id-of-file | ||
2906 | man: udevd.8 - remove udevcontrol section | ||
2907 | udevadm: control - allow command to be passed as option | ||
2908 | |||
2909 | MUNEDA Takahiro (1): | ||
2910 | man: fix udevadm.8 typo | ||
2911 | |||
2912 | Matthias Schwarzott (2): | ||
2913 | firmware: remove hardcoded path to logger | ||
2914 | rules: Gentoo update | ||
2915 | |||
2916 | VMiklos (1): | ||
2917 | rules: Frugalware update | ||
2918 | |||
2919 | |||
2920 | Summary of changes from v115 to v116 | ||
2921 | ============================================ | ||
2922 | |||
2923 | Bryan Kadzban (1): | ||
2924 | rules: fix typos | ||
2925 | |||
2926 | Harald Hoyer (3): | ||
2927 | check line length after comment check and whitespace strip | ||
2928 | only install *.rules | ||
2929 | remove extra space from udevinfo symlink output | ||
2930 | |||
2931 | Kay Sievers (29): | ||
2932 | rules: fix two trivial typos | ||
2933 | rules: random and urandom are 0666 | ||
2934 | rules: add REMOVE_CMD rule | ||
2935 | track "move" events to rename database and failed files | ||
2936 | rules: Gentoo update | ||
2937 | rules: add i2o driver rule | ||
2938 | man: recreate man pages | ||
2939 | volume_id: fix linux_raid metadata version 1.0 detection | ||
2940 | add $name substitution | ||
2941 | do not delete the device node with ignore_remove, but handle the event | ||
2942 | print warning for invalid TEST operations | ||
2943 | rules: do not delete /lib/udev/devices/ nodes on "remove" | ||
2944 | rules: remove broken nvram group assignment without any permission | ||
2945 | add /dev/rtc symlink if new rtc drivers are used | ||
2946 | increase WAIT_FOR_SYSFS timeout to 10 seconds | ||
2947 | rules: put bsd nodes in /dev/bsd/ directory | ||
2948 | path_id: fix for stacked class devices | ||
2949 | ignore device node names while restoring symlinks from the stack | ||
2950 | use SEQNUM in /dev/.udev/queue/ instead of devpath | ||
2951 | rules: add memstick module loading | ||
2952 | udevinfo: simplify symlink printing logic | ||
2953 | prevent wrong symlink creation if database disagress with current rules | ||
2954 | fix wrong variable used in logged string | ||
2955 | update README | ||
2956 | rule_generator: move all policy from write_net_rules to the rules file | ||
2957 | rules: call usb_id only for SUBSYSTEMS=="usb" | ||
2958 | rules: split out and fix persistent tape rules | ||
2959 | fix debug output string | ||
2960 | rule_generator: always match netif type in generated rule | ||
2961 | |||
2962 | Matthias Schwarzott (3): | ||
2963 | rules: Gentoo update | ||
2964 | rules: Gentoo update | ||
2965 | rules: Gentoo update | ||
2966 | |||
2967 | Michael Morony (1): | ||
2968 | set buffer size if strlcpy/strlcat indicate truncation | ||
2969 | |||
2970 | maximilian attems (1): | ||
2971 | correct includes in udev_selinux.c | ||
2972 | |||
2973 | |||
2974 | Summary of changes from v114 to v115 | ||
2975 | ============================================ | ||
2976 | |||
2977 | Harald Hoyer (1): | ||
2978 | rules: fix typo in 80-drivers.rules | ||
2979 | |||
2980 | Kay Sievers (15): | ||
2981 | rules: add default rules | ||
2982 | rules: update SUSE rules | ||
2983 | rules: add packages rules | ||
2984 | rules: add ia64 rules | ||
2985 | rules: move md-raid rules to packages dir | ||
2986 | rules: run vol_id only for partitions | ||
2987 | rules: update Fedora rules | ||
2988 | edd_id: move persistent rules to its own file | ||
2989 | accept relative path for TEST | ||
2990 | rules: add iowarrior rule | ||
2991 | volume_id: fix sqashfs detection | ||
2992 | do not ignore dynamic rule if it is the last one in the list | ||
2993 | rule_generator: fix wrong DRIVERS!= logic | ||
2994 | rules: update Fedora | ||
2995 | Makefile: install default rules | ||
2996 | |||
2997 | Marco d'Itri (3): | ||
2998 | rules_generator: remove policy from write_cd_rules | ||
2999 | rules_generator: fix write_cd_rules when similar names exist in the root directory | ||
3000 | rules: Debian update | ||
3001 | |||
3002 | |||
3003 | Summary of changes from v113 to v114 | ||
3004 | ============================================ | ||
3005 | |||
3006 | Hannes Reinecke (3): | ||
3007 | collect: extra to synchronize actions across events | ||
3008 | add $driver subtitution | ||
3009 | rules_generator: add S/390 persistent network support | ||
3010 | |||
3011 | Kay Sievers (24): | ||
3012 | rules_generator: remove executable flag from include file | ||
3013 | always unlink temporary file before creating new one | ||
3014 | rules: SUSE update | ||
3015 | volume_id: ext4 detection | ||
3016 | udevtrigger: allow to specify action string | ||
3017 | add option to RUN key to ignore the return value of the program | ||
3018 | use global udev_log variable instead of parameter in run_program | ||
3019 | add udev_rules_run() to handle RUN list | ||
3020 | move udev_utils_run.c into udev_rules.c | ||
3021 | rules: SUSE update | ||
3022 | name_list: rename loop_name -> name_loop | ||
3023 | handle dynamic rules created in /dev/.udev/rules.d/ | ||
3024 | allow SYMLINK== match | ||
3025 | libvolume_id: use /usr/$libdir in pc file | ||
3026 | Makefile: add --as-needed flag to ld | ||
3027 | restore behavior of NAME== | ||
3028 | rules_generator: remove "installation" function | ||
3029 | udevtrigger: trigger "driver" events | ||
3030 | rules: update SUSE | ||
3031 | rules: Fedora update | ||
3032 | rules: add "do not edit" comment | ||
3033 | rules: Fedora update | ||
3034 | rules_generator: skip random MAC addresses | ||
3035 | write changed network interface names to the kernel log | ||
3036 | |||
3037 | Matthias Schwarzott (3): | ||
3038 | rules: Gentoo update | ||
3039 | fix inotify to work not only once | ||
3040 | rules: Gentoo update | ||
3041 | |||
3042 | Richard Hughes (1): | ||
3043 | Makefile: add "make dist" for nightly snapshots | ||
3044 | |||
3045 | |||
3046 | Summary of changes from v112 to v113 | ||
3047 | ============================================ | ||
3048 | |||
3049 | David Zeuthen (1): | ||
3050 | vol_id: do not fail if unable to drop privileges | ||
3051 | |||
3052 | Kay Sievers (12): | ||
3053 | add missing ChangeLog | ||
3054 | make ATTR{[$SUBSYSTEM/$KERNEL]<attr>}="<value>" working | ||
3055 | rules: recognize partitions and disk devices properly | ||
3056 | rules: SUSE update | ||
3057 | atomically replace existing nodes and symlinks | ||
3058 | do not try to create existing file | ||
3059 | info() for ignore_remove | ||
3060 | rules: SUSE update | ||
3061 | Makefile: check for missing ChangeLog or RELEASE-NOTES at release | ||
3062 | allow to disable the replacement of unusual characters | ||
3063 | no newline in log messages | ||
3064 | udevd: do not use syslog if --verbose (debugging) is used | ||
3065 | |||
3066 | Tobias Klauser (1): | ||
3067 | fix typo in udev_utils_run.c | ||
3068 | |||
3069 | |||
3070 | Summary of changes from v111 to v112 | ||
3071 | ============================================ | ||
3072 | |||
3073 | Fabio Massimo Di Nitto (1): | ||
3074 | rules: ignore partitons that span the entire disk | ||
3075 | |||
3076 | Hannes Reinecke (1): | ||
3077 | cciss device support | ||
3078 | |||
3079 | Kay Sievers (34): | ||
3080 | udevd: close /proc/meminfo after reading | ||
3081 | create_floppy_devices: remove dead "unlink" code | ||
3082 | volume_id: add function documentation | ||
3083 | udev_db: escape path names with \x00 instead of %00 | ||
3084 | udevsettle: use long options | ||
3085 | replace_chars: replace spaces in node name | ||
3086 | volume_id: add and export string encoding function | ||
3087 | vol_id: export encoded strings | ||
3088 | rules: use encoded strings instead of skipping characters | ||
3089 | udevtest: print message before log output | ||
3090 | volume_id: escape % character | ||
3091 | replace_chars: replace % character | ||
3092 | IMPORT: do not mangle whitespace | ||
3093 | scsi_id: do not install symlink in /sbin | ||
3094 | rules: SUSE update | ||
3095 | volume_id: terminate overlong label strings | ||
3096 | scsi_id: add long options | ||
3097 | rules: use long options for scsi_id | ||
3098 | path_id: skip subsystem directory | ||
3099 | rules: fix cciss rule | ||
3100 | rules: SUSE update | ||
3101 | scsi_id: fix typo in help text | ||
3102 | fix "do not access parent" warning for ATTR{} | ||
3103 | sysfs: add device lookup by $SUBSYSYTEM:$KERNEL | ||
3104 | events for "bus" and "class" registration must be matched as "subsystem" | ||
3105 | udevtest: add --subsystem option | ||
3106 | sysfs: change order of subsystem lookup | ||
3107 | add $sys substitution | ||
3108 | add TEST=="<file>" key | ||
3109 | add "[$SUBSYSTEM/$KERNEL]<attribute>" lookup | ||
3110 | sysfs: handle bus/class top-level directories | ||
3111 | sysfs: skip unknown sysfs directories | ||
3112 | rules: SUSE update | ||
3113 | release 112 | ||
3114 | |||
3115 | Miklos Vajna (2): | ||
3116 | create_floppy_devices: add man page | ||
3117 | path_id: remove on make uninstall | ||
3118 | |||
3119 | Ryan Lortie (1): | ||
3120 | volume_id: support for long-filename based labels | ||
3121 | |||
3122 | Scott James Remnant (2): | ||
3123 | replace_untrusted_chars: replace all whitespace with space | ||
3124 | run_program: log "info" not "error" if program is missing | ||
3125 | |||
3126 | |||
3127 | Summary of changes from v110 to v111 | ||
3128 | ============================================ | ||
3129 | |||
3130 | Kay Sievers (19): | ||
3131 | rules: SUSE update | ||
3132 | rules: Fedora update | ||
3133 | volume_id: use md native uuid format | ||
3134 | vol_id: use long options | ||
3135 | volume_id: add volume_id_get_* functions | ||
3136 | vol_id: use volume_id_get_* | ||
3137 | udevd: use fgets() to read /proc files | ||
3138 | volume_id: add internal UUID_STRING | ||
3139 | volume_id: add DDF support | ||
3140 | vol_id: README update | ||
3141 | volume_id: rename UUID_64BIT_LE/BE | ||
3142 | vol_id: add ID_FS_UUID_SAFE | ||
3143 | rules: use ID_FS_UUID_SAFE | ||
3144 | rules: SUSE update | ||
3145 | volume_id: give access to list of all available probers | ||
3146 | vol_id: use libvolume_id prober list for --probe-all | ||
3147 | volume_id: add remaining names for prober lookup by type | ||
3148 | rules: SUSE update | ||
3149 | volume_id: vol_id depends on libvolume_id | ||
3150 | |||
3151 | Matthias Schwarzott (2): | ||
3152 | volume_id: fix Makefile for parallel make | ||
3153 | rules: Gentoo update | ||
3154 | |||
3155 | |||
3156 | Summary of changes from v109 to v110 | ||
3157 | ============================================ | ||
3158 | |||
3159 | Harald Hoyer (1): | ||
3160 | udevcontrol: allow to set global variables in udevd | ||
3161 | |||
3162 | Kay Sievers (13): | ||
3163 | remove eventrecorder.sh | ||
3164 | update SUSE rules | ||
3165 | volume_id: add md metadata 1.0, 1.1, 1.2 support | ||
3166 | unset variable with ENV{VAR}="" | ||
3167 | delete copies of default rules in SUSE rules | ||
3168 | volume_id: ext - fix endianess in version number | ||
3169 | rules: Fedora update | ||
3170 | volume_id: old md metadata has only 32 bit for the uuid | ||
3171 | volume_id: minix version 3 support | ||
3172 | don't create $tempnode for devices without major | ||
3173 | usb_id: add <devpath> to help text | ||
3174 | ata_id: use getopt_long() | ||
3175 | rules: SUSE update | ||
3176 | |||
3177 | Matthias Schwarzott (3): | ||
3178 | Makefile: respect CFLAGS/LDFLAGS | ||
3179 | rules: Gentoo update | ||
3180 | ata_id: don't log error for libata devices on older kernels | ||
3181 | |||
3182 | |||
3183 | Summary of changes from v108 to v109 | ||
3184 | ============================================ | ||
3185 | |||
3186 | Harald Hoyer (1): | ||
3187 | create_floppy_devices: create nodes with correct selinux context | ||
3188 | |||
3189 | Kay Sievers (11): | ||
3190 | udevtest: export ACTION string if given as option | ||
3191 | update SUSE rules | ||
3192 | make ACTION!="add|change" working | ||
3193 | udevtest: import uevent variables if possible | ||
3194 | udevinfo: export all information stored in database | ||
3195 | default rules: add libata compat links | ||
3196 | create_path: don't fail if something else created the directory | ||
3197 | udevd: fix serialization of events | ||
3198 | path_id: remove broken example | ||
3199 | libvolume_id: do not install static library | ||
3200 | update SUSE rules | ||
3201 | |||
3202 | Matthias Schwarzott (2): | ||
3203 | update Gentoo rules | ||
3204 | persistent device naming: add joystick links | ||
3205 | |||
3206 | VMiklos (1): | ||
3207 | path_id: add man page | ||
3208 | |||
3209 | |||
3210 | Summary of changes from v107 to v108 | ||
3211 | ============================================ | ||
3212 | |||
3213 | Kay Sievers (3): | ||
3214 | udevinfo: relax check for the correct device if looked up by name | ||
3215 | don't write to sysfs files during test run | ||
3216 | finally remove the directory event-multiplexer crap | ||
3217 | |||
3218 | Matthias Schwarzott (2): | ||
3219 | write_cd_rules: set default link type to "by-id" for usb and ieee1394 devices | ||
3220 | update Gentoo rules | ||
3221 | |||
3222 | Pozsar Balazs (1): | ||
3223 | udevsettle: read udev not kernel seqnum first | ||
3224 | |||
3225 | |||
3226 | Summary of changes from v106 to v107 | ||
3227 | ============================================ | ||
3228 | |||
3229 | Jean Tourrilhes (1): | ||
3230 | udevtest: export UDEV_LOG if we changed it | ||
3231 | |||
3232 | Kay Sievers (33): | ||
3233 | man: add missing options to various man pages | ||
3234 | man: fix typo | ||
3235 | create_floppy_devices: apply specified mode without umask | ||
3236 | man: spelling fixes | ||
3237 | udevmonitor: add switch for kernel and udev events | ||
3238 | default rules: wait for 0:0:0:0 scsi devices only | ||
3239 | update Fedora rules | ||
3240 | delete dasd_id, it moved to s390-tools | ||
3241 | update Gentoo rules | ||
3242 | encode db-file names, instead of just replacing '/' | ||
3243 | update internal variables if we see $DEVPATH during IMPORT | ||
3244 | increase /proc/stat buffer | ||
3245 | maintain index over device-names to devpath relation | ||
3246 | restore overwritten symlinks when the device goes away | ||
3247 | store devpath with the usual leading slash | ||
3248 | add link_priority to rule options, and store it in database | ||
3249 | pick actual valid device in udev_db_lookup_name | ||
3250 | cleanup already existing db-entries and db-index on device update | ||
3251 | selinux: move selinux_exit() to the main programs | ||
3252 | remove old error message | ||
3253 | read list of devices from index, make index private to database | ||
3254 | priority based symlink handling | ||
3255 | volume_id: get rid of compiler warning | ||
3256 | udevinfo: remove -d option | ||
3257 | update %n on netif name change | ||
3258 | if a node goes away, possibly restore a waiting symlink | ||
3259 | update TODO | ||
3260 | man: add "link_priority" option | ||
3261 | update SUSE rules | ||
3262 | udevtest: add --force mode | ||
3263 | udevinfo: print link priority | ||
3264 | usb_id: append target:lun to storage device serial | ||
3265 | run_directory: add final warning before removal | ||
3266 | |||
3267 | Marco d'Itri (1): | ||
3268 | update Debian rules | ||
3269 | |||
3270 | Matthias Schwarzott (2): | ||
3271 | udevd: cleanup std{in,our,err} on startup | ||
3272 | udevmonitor: fix swapped event switch descriptions | ||
3273 | |||
3274 | |||
3275 | Summary of changes from v105 to v106 | ||
3276 | ============================================ | ||
3277 | |||
3278 | A. Costa (1): | ||
3279 | man: fix typos in scsi_id and udevd | ||
3280 | |||
3281 | Andrey Borzenkov (2): | ||
3282 | vol_id: add -L to print raw partition label | ||
3283 | vol_id: document -L | ||
3284 | |||
3285 | Jamie Wellnitz (1): | ||
3286 | persistent device naming: tape devices and medium changers | ||
3287 | |||
3288 | Kay Sievers (15): | ||
3289 | exclude parent devices from DRIVER== match | ||
3290 | volume_id: really fix endianess bug in linux_raid detection | ||
3291 | release 105 | ||
3292 | man: correct udevinfo --export-db | ||
3293 | path_id: append LUN to iSCSI path | ||
3294 | create_floppy_devices: add option for owner/group | ||
3295 | update example rules | ||
3296 | apply format chars to ATTR before writing to sysfs | ||
3297 | add (subsystem) to udevmonitor output | ||
3298 | update DRIVER== changes | ||
3299 | remove --version from the udevinfo man page | ||
3300 | add test for an attribute which contains an operator char | ||
3301 | man: add note about parent matching behavior | ||
3302 | scsi_id: accept tabs in /etc/scsi_id.conf | ||
3303 | remove dead rule in persistent tape rules | ||
3304 | |||
3305 | Matthias Schwarzott (4): | ||
3306 | correct typo in extras/scsi_id/scsi_id.conf | ||
3307 | fix retry-loop in netif-rename code | ||
3308 | add option --version to udevd | ||
3309 | rule_generator: fix for creating rules on read-only filesystem | ||
3310 | |||
3311 | Peter Breitenlohner (1): | ||
3312 | fix INSTALL_PROGRAM vs. INSTALL_SCRIPT | ||
3313 | |||
3314 | Sergey Vlasov (3): | ||
3315 | udevd: init signal pipe before daemonizing | ||
3316 | unlink old database file before creating a new one | ||
3317 | fix %c $string substitution | ||
3318 | |||
3319 | Theodoros V. Kalamatianos (1): | ||
3320 | fix udev attribute names with a colon | ||
3321 | |||
3322 | |||
3323 | Summary of changes from v104 to v105 | ||
3324 | ============================================ | ||
3325 | |||
3326 | A. Costa (1): | ||
3327 | man: fix typos in scsi_id and udevd | ||
3328 | |||
3329 | Andrey Borzenkov (2): | ||
3330 | vol_id: add -L to print raw partition label | ||
3331 | vol_id: document -L | ||
3332 | |||
3333 | Kay Sievers (2): | ||
3334 | exclude parent devices from DRIVER== match | ||
3335 | volume_id: really fix endianess bug in linux_raid detection | ||
3336 | |||
3337 | Matthias Schwarzott (2): | ||
3338 | correct typo in extras/scsi_id/scsi_id.conf | ||
3339 | fix retry-loop in netif-rename code | ||
3340 | |||
3341 | Peter Breitenlohner (1): | ||
3342 | fix INSTALL_PROGRAM vs. INSTALL_SCRIPT | ||
3343 | |||
3344 | Sergey Vlasov (3): | ||
3345 | udevd: init signal pipe before daemonizing | ||
3346 | unlink old database file before creating a new one | ||
3347 | fix %c $string substitution | ||
3348 | |||
3349 | |||
3350 | Summary of changes from v103 to v104 | ||
3351 | ============================================ | ||
3352 | |||
3353 | Kay Sievers (12): | ||
3354 | update Fedora rules | ||
3355 | update example rules | ||
3356 | update SUSE rules | ||
3357 | update SUSE rules | ||
3358 | volume_id: fix endianess bug in linux_raid detection | ||
3359 | man: fix udevmonitor text | ||
3360 | man: recreate from xml | ||
3361 | rename config "filename" to "dir" | ||
3362 | remove outdated documentation | ||
3363 | rename "udev.c" to "test-udev.c" - it is only for testing | ||
3364 | update Fedora rules | ||
3365 | use git-archive instead of git-tar-tree | ||
3366 | |||
3367 | Kazuhiro Inaoka (1): | ||
3368 | inotify syscall definitions for M32R | ||
3369 | |||
3370 | Marco d'Itri (2): | ||
3371 | write_cd_rules: identity-based persistence | ||
3372 | scsi_id: remove trailing garbage from ID_SERIAL_SHORT | ||
3373 | |||
3374 | Russell Coker (1): | ||
3375 | SELinux: label created symlink instead of node | ||
3376 | |||
3377 | |||
3378 | Summary of changes from v102 to v103 | ||
3379 | ============================================ | ||
3380 | |||
3381 | Kay Sievers: | ||
3382 | persistent storage rules: skip gnbd devices | ||
3383 | volume_id: add checksum check to via_raid | ||
3384 | volume_id: add comment about hfs uuid conversion | ||
3385 | update SUSE rules | ||
3386 | update Fedora rules | ||
3387 | |||
3388 | |||
3389 | Summary of changes from v101 to v102 | ||
3390 | ============================================ | ||
3391 | |||
3392 | Daniel Drake: | ||
3393 | writing_udev_rules: fix typo in example rule | ||
3394 | |||
3395 | Kay Sievers: | ||
3396 | create missing ChangeLog for version 101 | ||
3397 | update SUSE rules | ||
3398 | update default rules | ||
3399 | first try "subsystem" link at a parent device, before guessing | ||
3400 | if /sys/subsystem exists, skip class, bus, block scanning | ||
3401 | scsi_id: export ID_SERIAL_SHORT without vendor/product | ||
3402 | update SUSE rules | ||
3403 | |||
3404 | MUNEDA Takahiro: | ||
3405 | path_id: fix SAS disk handling | ||
3406 | |||
3407 | |||
3408 | Summary of changes from v100 to v101 | ||
3409 | ============================================ | ||
3410 | |||
3411 | Arjan Opmeer: | ||
3412 | fix udevinfo help text typo | ||
3413 | |||
3414 | Bryan Kadzban: | ||
3415 | cleanup default rules | ||
3416 | add IMPORT operations to the udev man page | ||
3417 | |||
3418 | Kay Sievers: | ||
3419 | remove Makefile magic for leading '0' in version | ||
3420 | udevd: use getopt_long() | ||
3421 | udevd: add --verbose option to log also to stdout | ||
3422 | udevd: add --debug-trace option | ||
3423 | rule_generator: improve net rule comment generation | ||
3424 | volume_id: correct iso9660 high sierra header | ||
3425 | warn if a PHYSEDV* key, the "device" link, or a parent attribute is used | ||
3426 | don't print PHYSDEV* warnings for old WAIT_FOR_SYSFS rules | ||
3427 | udevinfo: print error in --attribute-walk | ||
3428 | udev_sysfs: unify symlink resolving | ||
3429 | udevtrigger: trigger devices sorted by their dependency | ||
3430 | fix spelling in deprecation warning | ||
3431 | release 101 | ||
3432 | |||
3433 | Michał Bartoszkiewicz: | ||
3434 | udevtrigger: fix typo that prevents partition events | ||
3435 | |||
3436 | Miles Lane: | ||
3437 | clarify "specified user/group unknown" error | ||
3438 | |||
3439 | Piter PUNK: | ||
3440 | update slackware rules | ||
3441 | |||
3442 | VMiklos: | ||
3443 | update Frugalware rules | ||
3444 | |||
3445 | |||
3446 | Summary of changes from v099 to v100 | ||
3447 | ============================================ | ||
3448 | |||
3449 | Kay Sievers: | ||
3450 | update SUSE rules | ||
3451 | fix messed up ChangeLog from release 099 | ||
3452 | man: add $attr{} section about symlinks | ||
3453 | revert persistent-storage ata-serial '_' '-' replacement | ||
3454 | |||
3455 | |||
3456 | Summary of changes from v098 to v099 | ||
3457 | ============================================ | ||
3458 | |||
3459 | Greg KH: | ||
3460 | update Gentoo rules | ||
3461 | |||
3462 | Kay Sievers: | ||
3463 | udev_db.c: include <sys/stat.h> | ||
3464 | use fnmatch() instead of our own pattern match code | ||
3465 | rename major/minor variable to maj/min to avoid warning | ||
3466 | update source file headers | ||
3467 | udevtest: print header that ENV{} can't work | ||
3468 | update TODO | ||
3469 | udevtrigger: options to filter by subsystem and sysfs attribute | ||
3470 | udevtrigger: remove unused longindex | ||
3471 | udevinfo: use long options | ||
3472 | udevd: use files instead of symlinks for /dev/.udev/queue,failed | ||
3473 | udevtrigger: fix pattern match | ||
3474 | reorder options in udevinfo man page | ||
3475 | udevinfo: fix SUBSYTEMS spelling error | ||
3476 | fix ENV{TEST}="Test: $env{TEST}" | ||
3477 | let $attr{symlink} return the last element of the path | ||
3478 | cdrom_id: add rules file to call cdrom_id | ||
3479 | udevinfo: do not show symlinks as attributes in --attribute-walk | ||
3480 | remove broken name_cdrom.pl | ||
3481 | |||
3482 | Marco d'Itri: | ||
3483 | update Debian rules | ||
3484 | run_program: close pipe fd's which are connected to child process | ||
3485 | add persistent rules generator for net devices and optical drives | ||
3486 | |||
3487 | MUNEDA Takahiro: | ||
3488 | changes rules for ata disk from '_' to '-' | ||
3489 | |||
3490 | Sergey Vlasov: | ||
3491 | make struct option arrays static const | ||
3492 | fix "subsytem" typo | ||
3493 | |||
3494 | |||
3495 | Summary of changes from v097 to v098 | ||
3496 | ============================================ | ||
3497 | |||
3498 | Alex Merry: | ||
3499 | udevtest: allow /sys in the devpath paramter | ||
3500 | |||
3501 | Harald Hoyer: | ||
3502 | selinux: init once in the daemon, not in every event process | ||
3503 | |||
3504 | Kay Sievers: | ||
3505 | udevd: remove huge socket buffer on the control socket | ||
3506 | man page: fix typo | ||
3507 | rename udev_libc_wrapper -> udev_sysdeps | ||
3508 | db: store devpath - node relationship for all devices | ||
3509 | udevinfo: allow -a -n <node> | ||
3510 | udevinfo, udevtest: simplify '/sys' stripping from devpath argument | ||
3511 | lookup_user, lookup_group: report "unknown user" and "lookup failed" | ||
3512 | consistent key naming to match only the event device or include all parent devices | ||
3513 | skip rule, if too may keys of the same type are used | ||
3514 | introduce ATTR{file}="value" to set sysfs attributes | ||
3515 | update SUSE rules | ||
3516 | update default rules | ||
3517 | export DRIVER for older kernels as a replacement for PHYSDEVDRIVER | ||
3518 | fix typo in SUBSYSTEMS key parsing | ||
3519 | udevtrigger: add --retry-failed | ||
3520 | volume_id: add suspend partition detection | ||
3521 | vol_id: use primary group of 'nobody' instead of 'nogroup' | ||
3522 | remove built-in /etc/passwd /etc/group parser | ||
3523 | always expect KEY{value} on ATTR, ATTRS, ENV keys | ||
3524 | use new key names in test programs | ||
3525 | cleanup commandline argument handling | ||
3526 | db: don't create a db file for only a node name to store | ||
3527 | man: add ATTR{file}="value" assignment | ||
3528 | |||
3529 | Lennart Poettering: | ||
3530 | volume_id: fix fat32 cluster chain traversal | ||
3531 | |||
3532 | Marco d'Itri: | ||
3533 | fix 'unknow user' error from getpwnam/getgrnam | ||
3534 | fix rc when using udev --daemon | ||
3535 | update Debian rules | ||
3536 | |||
3537 | Michał Bartoszkiewicz: | ||
3538 | man pages: fix typos | ||
3539 | |||
3540 | |||
3541 | Summary of changes from v096 to v097 | ||
3542 | ============================================ | ||
3543 | |||
3544 | Anssi Hannula: | ||
3545 | add joystick support to persistent input rules | ||
3546 | |||
3547 | Kay Sievers: | ||
3548 | firmware.sh: remove needless '/' | ||
3549 | vol_id: add --skip-raid and --probe-all option | ||
3550 | switch uevent netlink socket to group 1 only | ||
3551 | increase /proc/stat read buffer | ||
3552 | use "change" instead of "online" events | ||
3553 | remove 'static' from local variable | ||
3554 | libvolume_id: add parameter 'size' to all probe functions | ||
3555 | man pages: replace 'device-path' by 'devpath' | ||
3556 | man pages: work around xmlto which tries to be smart | ||
3557 | refresh vol_id man page | ||
3558 | udevinfo: add DRIVER== | ||
3559 | Makefile: fix dependency | ||
3560 | libvolume_id: read ufs2 label | ||
3561 | switch ifdef __KLIBC__ to ifndef __GLIBC__ | ||
3562 | report failing getpwnam/getgrnam as error | ||
3563 | rename udevcontrol message types and variables | ||
3564 | initialize unused sockets to -1 | ||
3565 | udevd: remove useless udevinitsend parameter | ||
3566 | update README | ||
3567 | udevd: autotune max_childs/max_childs_running | ||
3568 | update frugalware rules | ||
3569 | update SUSE rules | ||
3570 | move default rules to etc/udev/rules.d/ | ||
3571 | add 'crypto' devices to persistent storage rules | ||
3572 | add late.rules to default rules | ||
3573 | update Fedora rules | ||
3574 | don't report an error on overlong comment lines | ||
3575 | update SUSE rules | ||
3576 | udevd: read DRIVER from the environment | ||
3577 | |||
3578 | Marco d'Itri: | ||
3579 | make rename_netif() error messages useful | ||
3580 | path_id: fix an harmless syntax error | ||
3581 | |||
3582 | Piter PUNK: | ||
3583 | update slackware rules | ||
3584 | |||
3585 | Richard Purdie: | ||
3586 | Fix inotify syscalls on ARM | ||
3587 | |||
3588 | |||
3589 | Summary of changes from v095 to v096 | ||
3590 | ============================================ | ||
3591 | |||
3592 | Kay Sievers: | ||
3593 | Makefiles: fix .PHONY for man page target | ||
3594 | allow longer devpath values | ||
3595 | path_id: prepare for new sysfs layout | ||
3596 | |||
3597 | |||
3598 | Summary of changes from v094 to v095 | ||
3599 | ============================================ | ||
3600 | |||
3601 | Kay Sievers: | ||
3602 | update SUSE rules | ||
3603 | don't remove symlinks if they are already there | ||
3604 | allow "online" events to create/update symlinks | ||
3605 | udevinfo: clarify parent device attribute use | ||
3606 | update SUSE rules | ||
3607 | netif rename: optimistic loop for the name to become free | ||
3608 | remove broken %e enumeration | ||
3609 | |||
3610 | Tobias Klauser: | ||
3611 | print usage of udevcontrol when no or invalid command is given | ||
3612 | |||
3613 | |||
3614 | Summary of changes from v093 to v094 | ||
3615 | ============================================ | ||
3616 | |||
3617 | Daniel Drake: | ||
3618 | update "writing udev rules" | ||
3619 | |||
3620 | Kay Sievers: | ||
3621 | libvolume_id: gfs + gfs2 support | ||
3622 | remove MODALIAS key and substitution | ||
3623 | add persistent-input.rules | ||
3624 | |||
3625 | Marco d'Itri: | ||
3626 | update Debian rules | ||
3627 | |||
3628 | |||
3629 | Summary of changes from v092 to v093 | ||
3630 | ============================================ | ||
3631 | |||
3632 | Hannes Reinecke: | ||
3633 | path_id: add support for iSCSI devices | ||
3634 | |||
3635 | Kay Sievers: | ||
3636 | libvolume_id: fat - check for signature at end of sector | ||
3637 | libvolume_id: add more software raid signatures | ||
3638 | update Fedora rules | ||
3639 | path_id: prevent endless loop for SAS devices on older kernels | ||
3640 | remove udevsend | ||
3641 | replace binary firmware helper with shell script | ||
3642 | skip device mapper devices for persistent links | ||
3643 | |||
3644 | |||
3645 | Summary of changes from v091 to v092 | ||
3646 | ============================================ | ||
3647 | |||
3648 | Kay Sievers: | ||
3649 | don't include stropts.h, some libc's don't like it | ||
3650 | udevd: create leading directories for /dev/.udev/uevent_seqnum | ||
3651 | vol_id: fix logging from libvolume_id's log function | ||
3652 | update SUSE rules | ||
3653 | update SUSE rules | ||
3654 | add more warnings for invalid key operations | ||
3655 | fix offsetof() build issue with recent glibc | ||
3656 | selinux: fix typo in block device node selection | ||
3657 | vol_id: add NetWare volume detection | ||
3658 | edd_id: fix "(null)" output if "mbr_signature" does not exist | ||
3659 | update Fedora rules | ||
3660 | libvolume_id: nss - use different uuid | ||
3661 | |||
3662 | Libor Klepac: | ||
3663 | path_id: add platform and serio support | ||
3664 | |||
3665 | Marco d'Itri: | ||
3666 | update Debian rules | ||
3667 | path_id: fix bashism | ||
3668 | |||
3669 | |||
3670 | Summary of changes from v090 to v091 | ||
3671 | ============================================ | ||
3672 | |||
3673 | Hannes Reinecke: | ||
3674 | path_id: fix SAS device path generation | ||
3675 | |||
3676 | Kay Sievers: | ||
3677 | udevtest: don't try to delete symlinks | ||
3678 | persistent rules: fix typo in dm rule | ||
3679 | allow NAME=="value" to check for already assigned value | ||
3680 | udevd: export initial sequence number on startup | ||
3681 | |||
3682 | |||
3683 | Summary of changes from v089 to v090 | ||
3684 | ============================================ | ||
3685 | |||
3686 | Kay Sievers: | ||
3687 | udevd: export current seqnum and add udevsettle | ||
3688 | volume_id: fix endianess conversion typo for FAT32 | ||
3689 | merge device event handling and make database content available on "remove" | ||
3690 | set default udevsettle timeout to 3 minutes | ||
3691 | export INTERFACE_OLD if we renamed a netif | ||
3692 | let udevmonitor show the possibly renamed devpath | ||
3693 | volume_id: move some debug to info level | ||
3694 | udevtrigger: fix event order | ||
3695 | usb_id: remove uneeded code | ||
3696 | remove old symlinks before creating current ones | ||
3697 | path_id: fix loop for SAS devices | ||
3698 | apply format char to variables exported by ENV | ||
3699 | |||
3700 | Marco d'Itri: | ||
3701 | add inotify support for hppa and MIPS and log if inotify is not available | ||
3702 | |||
3703 | Matt Kraai: | ||
3704 | fix typo in error message | ||
3705 | |||
3706 | |||
3707 | Summary of changes from v088 to v089 | ||
3708 | ============================================ | ||
3709 | |||
3710 | Hannes Reinecke: | ||
3711 | path_id: add bus to USB path | ||
3712 | |||
3713 | Kay Sievers: | ||
3714 | change rule to skip removable IDE devices | ||
3715 | don't create uuid/label links for raid members | ||
3716 | volume_id: provide library | ||
3717 | fix rule order for persistent tape links | ||
3718 | update man page | ||
3719 | volume_id: provide a custom debug function | ||
3720 | volume_id: rename subdirectory | ||
3721 | volume_id: use shared library by default | ||
3722 | because is better than cause | ||
3723 | volume_id: remove some global symbols | ||
3724 | volume_id: define exported symbols | ||
3725 | remove all stripping code | ||
3726 | man pages: mention udev(7) not udev(8) | ||
3727 | update Debian rules | ||
3728 | move all *_id programs to /lib/udev/ | ||
3729 | update Red Hat rules | ||
3730 | update SUSE rules | ||
3731 | pass CROSS_COMPILE to AR and RANLIB down to extras/ | ||
3732 | volume_id: update README | ||
3733 | volume_id: generate man page from xml source | ||
3734 | update README | ||
3735 | fix symlink targets in Makefiles | ||
3736 | |||
3737 | |||
3738 | Summary of changes from v087 to v088 | ||
3739 | ============================================ | ||
3740 | |||
3741 | Hannes Reinecke: | ||
3742 | persistent links: add scsi tape links and usb path support | ||
3743 | |||
3744 | Kay Sievers: | ||
3745 | volume_id: add squashfs detection | ||
3746 | reset signal handler in event process | ||
3747 | correct use of fcntl() | ||
3748 | add udevtrigger to request events for coldplug | ||
3749 | add ',' to trusted chars | ||
3750 | volume_id: remove partition table parsing code | ||
3751 | volume_id: remove all partition table support | ||
3752 | fix spelling error in debug string | ||
3753 | rename "persistent disk" to "persistent storage" | ||
3754 | fix output for USB path | ||
3755 | |||
3756 | |||
3757 | Summary of changes from v086 to v087 | ||
3758 | ============================================ | ||
3759 | |||
3760 | Hannes Reinecke: | ||
3761 | path_id: support SAS devices | ||
3762 | |||
3763 | Kay Sievers: | ||
3764 | fix persistent disk rules to exclude removable IDE drives | ||
3765 | warn about %e, MODALIAS, $modalias | ||
3766 | remove devfs rules and scripts | ||
3767 | |||
3768 | Masatake YAMATO: | ||
3769 | typo in debug text in udev_run_hotplugd.c | ||
3770 | |||
3771 | |||
3772 | Summary of changes from v085 to v086 | ||
3773 | ============================================ | ||
3774 | |||
3775 | Kay Sievers: | ||
3776 | volume_id: replace __packed__ by PACKED macro | ||
3777 | volume_id: split raid and filesystem detection | ||
3778 | volume_id: add missing return | ||
3779 | udevd: fix queue export for multiple events for the same device | ||
3780 | |||
3781 | Kyle McMartin: | ||
3782 | workaround missing kernel headers for some architectures | ||
3783 | |||
3784 | Nix: | ||
3785 | update to udev-084/doc/writing_udev_rules | ||
3786 | |||
3787 | |||
3788 | Summary of changes from v084 to v085 | ||
3789 | ============================================ | ||
3790 | |||
3791 | Andrey Borzenkov: | ||
3792 | Fix trivial spelling errors in RELEASE-NOTES | ||
3793 | |||
3794 | Jeroen Roovers: | ||
3795 | fix typo in parisc support to path_id | ||
3796 | |||
3797 | Kay Sievers: | ||
3798 | make WAIT_FOR_SYSFS usable in non "wait-only" rules | ||
3799 | fix typo in man page | ||
3800 | include sys/socket.h for klibc build | ||
3801 | cramfs detection for bigendian | ||
3802 | exit WAIT_FOR_SYSFS if the whole device goes away | ||
3803 | update SUSE rules | ||
3804 | update Red Hat rules | ||
3805 | update Gentoo rules | ||
3806 | include errno.h in udev_libc_wrapper.c | ||
3807 | |||
3808 | |||
3809 | Summary of changes from v083 to v084 | ||
3810 | ============================================ | ||
3811 | |||
3812 | Kay Sievers: | ||
3813 | update SUSE rules | ||
3814 | switch CROSS to CROSS_COMPILE | ||
3815 | replace fancy silent build program by simple kernel build like logic | ||
3816 | move manpages to top level | ||
3817 | remove UDEVD_UEVENT_INITSEND | ||
3818 | whitespace fixes | ||
3819 | scsi_id: remove dead files | ||
3820 | optimize sysfs device and attribute cache | ||
3821 | let SYSFS{} look at the device, not only the parent device | ||
3822 | add debug output to sysfs operations | ||
3823 | |||
3824 | |||
3825 | Summary of changes from v082 to v083 | ||
3826 | ============================================ | ||
3827 | |||
3828 | Andrey Borzenkov: | ||
3829 | man page: document when substitutions are applied for RUN and other keys | ||
3830 | check for ignore_device in loop looks redundant | ||
3831 | |||
3832 | Kay Sievers: | ||
3833 | udevstart: fix NAME="" which prevents RUN from being executed | ||
3834 | find programs in /lib/udev for IMPORT if {program} is not given | ||
3835 | don't add $SUBSYSTEM automatically as $1 to programs | ||
3836 | remove redundant substitution of RUN key | ||
3837 | |||
3838 | |||
3839 | Summary of changes from v081 to v082 | ||
3840 | ============================================ | ||
3841 | |||
3842 | Andrey Borzenkov: | ||
3843 | substitute format chars in RUN after rule matching | ||
3844 | |||
3845 | Kay Sievers: | ||
3846 | scsi_id, usb_id: request device parent by subsystem | ||
3847 | path_id: work with "all devices in /sys/devices" | ||
3848 | ignore all messages with missing devpath or action | ||
3849 | Makefile: remove dynamic config file generation | ||
3850 | path_id: handle fiber channel (Hannes Reinecke <hare@suse.de>) | ||
3851 | usb_id: don't fail on other subsytems than "scsi" | ||
3852 | don't do RUN if "ignore_device" is given | ||
3853 | increase kernel uevent buffer size | ||
3854 | move udev(8) manpage to udev(7) | ||
3855 | recreate man pages from xml source | ||
3856 | remove udev, udevstart, udevsend from the default installation | ||
3857 | update SUSE rules | ||
3858 | rename apply_format() cause it is public now | ||
3859 | udevtest: add udev_rules_apply_format() to RUN keys | ||
3860 | let "ignore_device" always return the event successfully | ||
3861 | |||
3862 | Olivier Blin: | ||
3863 | fixes udev build with -fpie | ||
3864 | |||
3865 | |||
3866 | Summary of changes from v080 to v081 | ||
3867 | ============================================ | ||
3868 | |||
3869 | Kay Sievers: | ||
3870 | add DEVLINKS to "remove" event | ||
3871 | better log text and comments | ||
3872 | vol_id: probe volume as user nobody | ||
3873 | fix BUS, ID, $id usage | ||
3874 | prepare moving of /sys/class devices to /sys/devices | ||
3875 | |||
3876 | |||
3877 | Summary of changes from v079 to v080 | ||
3878 | ============================================ | ||
3879 | |||
3880 | Brent Cook: | ||
3881 | fix dependency for make -j2 | ||
3882 | |||
3883 | coly: | ||
3884 | fix man page typos | ||
3885 | |||
3886 | Kay Sievers: | ||
3887 | update RELEASE-NOTES + TODO | ||
3888 | fix typo in man page | ||
3889 | update TODO | ||
3890 | update SUSE rules | ||
3891 | path_id: fix invalid character class | ||
3892 | replace libsysfs | ||
3893 | |||
3894 | Marco d'Itri: | ||
3895 | udev_selinux.c: include udev.h | ||
3896 | |||
3897 | |||
3898 | Summary of changes from v078 to v079 | ||
3899 | ============================================ | ||
3900 | |||
3901 | Kay Sievers: | ||
3902 | don't log error if database does not exist | ||
3903 | use udev_root instead of "/dev"in selinux matchpathcon_init_prefix() | ||
3904 | scsi_id: read page 0x80 with libata drives | ||
3905 | update SUSE rules | ||
3906 | remove %e from man page | ||
3907 | |||
3908 | |||
3909 | Summary of changes from v077 to v078 | ||
3910 | ============================================ | ||
3911 | |||
3912 | Greg Kroah-Hartman: | ||
3913 | Update Gentoo udev main rule file. | ||
3914 | add parisc support to path_id | ||
3915 | |||
3916 | Hannes Reinecke: | ||
3917 | scsi_id: -u fold multiple consecutive whitespace chars into single '_' | ||
3918 | |||
3919 | Harald Hoyer: | ||
3920 | optimize SELinux path match | ||
3921 | |||
3922 | Kay Sievers: | ||
3923 | update README | ||
3924 | allow C99 statements | ||
3925 | fix segfaulting create_floppy_devices | ||
3926 | update SUSE rules | ||
3927 | remove unused variables | ||
3928 | remove default settings in udev.conf | ||
3929 | clearenv() is now part of klibc | ||
3930 | add DEVLINKS to the event environment | ||
3931 | |||
3932 | Kurt Garloff: | ||
3933 | scsi_id: support pre-SPC3 page 83 format | ||
3934 | |||
3935 | |||
3936 | Summary of changes from v076 to v077 | ||
3937 | ============================================ | ||
3938 | |||
3939 | Kay Sievers: | ||
3940 | merge two consecutive static strlcat's | ||
3941 | don't return an error, if "ignore_device" is used | ||
3942 | remove outdated and misleading stuff | ||
3943 | move SEQNUM event skipping to udevsend | ||
3944 | update RELEASE-NOTES | ||
3945 | update SUSE rules | ||
3946 | allow programs in /lib/udev called without the path | ||
3947 | update SUSE rules | ||
3948 | add target to to generate ChangeLog section | ||
3949 | update Red Hat rules | ||
3950 | |||
3951 | Marco d'Itri: | ||
3952 | allow to overwrite the configured udev_root by exporting UDEV_ROOT | ||
3953 | let udevsend ignore events with SEQNUM set | ||
3954 | update Debian rules | ||
3955 | |||
3956 | |||
3957 | Summary of changes from v75 to v076 | ||
3958 | ============================================ | ||
3959 | |||
3960 | Kay Sievers: | ||
3961 | fix typo in eventrecorder | ||
3962 | volume_id: include stddef.h header | ||
3963 | remove misleading install instructions | ||
3964 | remove all built-in wait_for_sysfs logic | ||
3965 | add linux/types.h back, old glibc-kernel-headers want it | ||
3966 | volume_id: use glibc's byteswap | ||
3967 | udevd: ignore all messages without DEVPATH | ||
3968 | udevd: track exit status of event process | ||
3969 | udevd: export event queue and event state | ||
3970 | remove "udev_db" option from config file | ||
3971 | Makefile: remove exec_prefix and srcdir | ||
3972 | update README and RELEASE-NOTES | ||
3973 | udevd: track killed event processes as failed | ||
3974 | update README | ||
3975 | don't start udevd from udevsend | ||
3976 | udevd: add a missing return | ||
3977 | libvolume_id: fix weird fat volume recognition | ||
3978 | move some helpers from extras to /lib/udev | ||
3979 | |||
3980 | Scott James Remnant: | ||
3981 | move delete_path() to utils | ||
3982 | clean-up empty queue directories | ||
3983 | Makefile: fail, if submake fails | ||
3984 | |||
3985 | |||
3986 | Summary of changes from v74 to v075 | ||
3987 | ============================================ | ||
3988 | |||
3989 | Greg Kroah-Hartman: | ||
3990 | Make run_directory.c stat the place it is going to try to run. | ||
3991 | |||
3992 | Kay Sievers: | ||
3993 | forgot the ChangeLog for 074 | ||
3994 | volume_id: provide libvolume_id.a file | ||
3995 | remove our own copy of klibc | ||
3996 | remove outdated HOWTO | ||
3997 | update TODO | ||
3998 | update SUSE rules | ||
3999 | remove completely useless start script | ||
4000 | fix tests and remove no longer useful stuff | ||
4001 | replace udeveventrecorder by a shell script | ||
4002 | |||
4003 | |||
4004 | Summary of changes from v73 to v074 | ||
4005 | ============================================ | ||
4006 | |||
4007 | Kay Sievers: | ||
4008 | never queue events with TIMEOUT set | ||
4009 | let NAME="" supress node creation, but do RUN keys | ||
4010 | remove udevinitsend | ||
4011 | update .gitignore | ||
4012 | |||
4013 | Marco d'Itri: | ||
4014 | add strerror() to error logs | ||
4015 | move some logging from dbg() to info() | ||
4016 | |||
4017 | |||
4018 | Summary of changes from v72 to v073 | ||
4019 | ============================================ | ||
4020 | |||
4021 | Kay Sievers: | ||
4022 | udevd: depend on netlink and remove all sequence reorder logic | ||
4023 | print useconds in udevmonitor | ||
4024 | add RELEASE-NOTES, update TODO | ||
4025 | |||
4026 | |||
4027 | Summary of changes from v71 to v072 | ||
4028 | ============================================ | ||
4029 | |||
4030 | Ananth N Mavinakayanahalli: | ||
4031 | libsysfs: translate devpath of the symlinked class devices to its real path | ||
4032 | |||
4033 | Jan Luebbe: | ||
4034 | add man pages for *_id programs | ||
4035 | |||
4036 | Kay Sievers: | ||
4037 | volume_id: add OCFS Version 1 | ||
4038 | volume_id: add Veritas fs | ||
4039 | volume_id: check ext fs for valid blocksize, cause magic is only 2 bytes | ||
4040 | volume_id: move blocksize validation to fix jbd recognition | ||
4041 | volume_id: fix typo in ocfs | ||
4042 | volume_id: add vxfs include | ||
4043 | volume_id: make FAT32 recognition more robust | ||
4044 | volume_id: Version 051 | ||
4045 | volume_id: fix typo in ext blocksize check | ||
4046 | volume_id: Version 052 | ||
4047 | FAQ: remove confusing statement about module loading | ||
4048 | cleanup compiler/linker flags | ||
4049 | use DESTDIR on uninstall, no need to pass prefix to submake | ||
4050 | allow to pass STRIPCMD, to skip stripping of binaries | ||
4051 | cleanup make release | ||
4052 | fix the new warnings I asked for | ||
4053 | move rules parsing into daemon | ||
4054 | "make STRIPCMD=" will disable the stripping of binaries | ||
4055 | remove no longer working udevd-test program | ||
4056 | "STRIPCMD=" for the EXTRAS | ||
4057 | add dummy inotify syscalls on unsupported architecture | ||
4058 | remove no longer needed waiting for "dev" file | ||
4059 | revert the "read symlink as device patch" | ||
4060 | use libsysfs to translate the class linke to the device path | ||
4061 | libsysfs: remove brute-force "bus", "driver" searching for old kernels | ||
4062 | test: add "driver" and "bus" links to test sysfs tree | ||
4063 | update RELEASE-NOTES | ||
4064 | udevd: don't daemonize before initialization | ||
4065 | log to console if syslog is not available | ||
4066 | udevd: disable OOM | ||
4067 | remove precompiled rules option | ||
4068 | export DEVNAME on "remove" only if we really got a node to remove | ||
4069 | fix typo in umask() | ||
4070 | |||
4071 | |||
4072 | Summary of changes from v70 to v071 | ||
4073 | ============================================ | ||
4074 | |||
4075 | Greg Kroah-Hartman: | ||
4076 | Remove the udev.spec file as no one uses it anymore | ||
4077 | |||
4078 | John Hull: | ||
4079 | edd_id: check that EDD id is unique | ||
4080 | |||
4081 | Kay Sievers: | ||
4082 | ata_id: open volume O_NONBLOCK | ||
4083 | add "Persistent Device Naming" rules file for disks | ||
4084 | scsi_id: switch temporary node creation to /dev | ||
4085 | volume_id: set reiser instead of reiserfs for filesystem type | ||
4086 | update devfs rules header | ||
4087 | update Debian rules | ||
4088 | update Fedora rules | ||
4089 | update Debian rules | ||
4090 | remove no longer needed includes | ||
4091 | switch tools and volume_id from LGPL to GPLv2 | ||
4092 | add edd-*-part%n to the persistent.rules | ||
4093 | update Debian persistent rules | ||
4094 | clarify README | ||
4095 | udevd: fix initial timeout handling | ||
4096 | force event socket buffer size to 16MB | ||
4097 | udevd: move logging from err to info for non-hotplug uevent | ||
4098 | fix selinux compilation | ||
4099 | libsysfs: accept sysmlinks to directories instead of real directories | ||
4100 | |||
4101 | Marco d'Itri: | ||
4102 | run_directory: fix typo in "make install" | ||
4103 | |||
4104 | |||
4105 | Summary of changes from v069 to v070 | ||
4106 | ============================================ | ||
4107 | |||
4108 | Amir Shalem: | ||
4109 | udevd: fix udevd read() calls to leave room for null byte | ||
4110 | |||
4111 | Edward Goggin: | ||
4112 | scsi_id: derive a UID for a SCSI-2 not compliant with the page 83 | ||
4113 | |||
4114 | Greg Kroah-Hartman: | ||
4115 | fix nbd error messages with a gentoo rule hack | ||
4116 | fix scsi_id rule in gentoo config file | ||
4117 | |||
4118 | Jürg Billeter: | ||
4119 | EXTRAS/Makefile: fix install targets to match main Makefile | ||
4120 | |||
4121 | Kay Sievers: | ||
4122 | volume_id: fix error handling with failing read() | ||
4123 | EXTRAS: cleanup and sync all Makefiles | ||
4124 | add install test to 'make buildtest' | ||
4125 | update RELEASE-NOTES | ||
4126 | |||
4127 | Olivier Blin: | ||
4128 | fix a debug text typo in udev_rules.c | ||
4129 | |||
4130 | |||
4131 | Summary of changes from v068 to v069 | ||
4132 | ============================================ | ||
4133 | |||
4134 | Amir Shalem: | ||
4135 | fix typo in firmware_helper | ||
4136 | |||
4137 | Duncan Sands: | ||
4138 | firmware_helper: fix write count | ||
4139 | |||
4140 | Kay Sievers: | ||
4141 | *_id: fix zero length in set_str() | ||
4142 | add program name to logged error | ||
4143 | fix exit code of udevinitsend and udevmonitor | ||
4144 | udevd: keep the right order for messages without SEQNUM | ||
4145 | volume_id: don't probe for mac_partition_maps | ||
4146 | udevmonitor: cleanup on exit | ||
4147 | path_id: remove SUSE specific PATH | ||
4148 | update SUSE rules | ||
4149 | add pci_express to bus list | ||
4150 | update SUSE rules | ||
4151 | store ENV{key}="value" exported keys in the database | ||
4152 | fix lookup for name in the udevdb, it should return the devpath | ||
4153 | prepare for new HAL udevdb dump | ||
4154 | print persistent data with "udevinfo -q all" | ||
4155 | change parameter order of udev_db_search_name() | ||
4156 | add and use name_list_cleanup() for cleaning up the string lists | ||
4157 | don't store devpath in udevdb, we don't need it | ||
4158 | add uft8 validation for safe volume label exporting | ||
4159 | start to enforce plain ascii or valid utf8 | ||
4160 | use WRITE_END/READ_END for the pipe index | ||
4161 | remove not needed sig_flag for state of signal_pipe | ||
4162 | don't reenter get_udevd_msg() if message is ignored | ||
4163 | rename ...trailing_char() to ...trailing_chars() | ||
4164 | vol_id: ID_LABEL_SAFE will no longer contain fancy characters | ||
4165 | udevd: move some logging to "info" and "err" | ||
4166 | remove special TIMEOUT handling from incoming queue | ||
4167 | udev_test.pl: we replace untrusted chars with '_' | ||
4168 | check the udevdb before assigning a new %e | ||
4169 | update RELEASE-NOTES | ||
4170 | udevinfo: add database export | ||
4171 | write man page masters in DocBook XML | ||
4172 | udevinfo: rename dump() to export() | ||
4173 | test the automatic man page rebuild and checkin | ||
4174 | Makefile: remove all the duplicated rules | ||
4175 | all man pages rewritten to use DocBook XML | ||
4176 | add missing udevsend man page | ||
4177 | also forgot udevmonitor.8 | ||
4178 | udevinfo: restore -d option | ||
4179 | scsi_id: rename SYSFS to LIBSYSFS | ||
4180 | add edd_id tool to match BIOS EDD disk information | ||
4181 | move and update libsysfs.txt | ||
4182 | klibc: update to version 1.1.1 | ||
4183 | delete cdromsymlinks* - obsoleted by cdrom_id and IMPORT rules | ||
4184 | delete docs/persistent_naming - obsoleted by persistent disk names | ||
4185 | delete old Fedora html page | ||
4186 | add "totally outdated" header to docs/overview :) | ||
4187 | update SUSE rules | ||
4188 | fix useless but funny name_cdrom.pl script to work again | ||
4189 | update TODO | ||
4190 | Makefile: fix prerequisits for $(PROGRAMS) | ||
4191 | Makefile: cleanup install targets | ||
4192 | remove chassis_id program | ||
4193 | fic gcov use and move it into the Makefile | ||
4194 | FAQ: update things that have changed | ||
4195 | |||
4196 | Thierry Vignaud: | ||
4197 | switch to '==' in raid-devfs.sh | ||
4198 | |||
4199 | |||
4200 | Summary of changes from v067 to v068 | ||
4201 | ============================================ | ||
4202 | |||
4203 | Greg Kroah-Hartman: | ||
4204 | add EXTRAS documentation to the README file. | ||
4205 | Always open the cdrom drive in non-blocking mode in cdrom_id | ||
4206 | cdrom_id: change err() to info() to help with debugging problems | ||
4207 | |||
4208 | Kay Sievers: | ||
4209 | cleanup some debug output and move to info level + unify select() loops | ||
4210 | move udevmonitor to /usr/sbin | ||
4211 | ENV{TEST}=="1" compares and ENV{TEST}="1" sets the environment | ||
4212 | vol_id: fix sloppy error handling | ||
4213 | fix typo in cdrom_id syslog | ||
4214 | bring std(in|out|err) fd's in a sane state | ||
4215 | fix printed udevmonitor header | ||
4216 | |||
4217 | |||
4218 | Summary of changes from v066 to v067 | ||
4219 | ============================================ | ||
4220 | |||
4221 | Greg Kroah-Hartman: | ||
4222 | added the cdrom.h #defines directly into the cdrom_id.c file | ||
4223 | |||
4224 | Kay Sievers: | ||
4225 | update SUSE rules | ||
4226 | fix make install, as we don't provide a default rule set anymore | ||
4227 | fix more compiler warnings ... | ||
4228 | fix udevstart event ordering, we want /dev/null very early | ||
4229 | don't fail too bad, if /dev/null does not exist | ||
4230 | |||
4231 | |||
4232 | Summary of changes from v065 to v066 | ||
4233 | ============================================ | ||
4234 | |||
4235 | Greg Kroah-Hartman: | ||
4236 | update gentoo rule file. | ||
4237 | Created cdrom_id program to make it easier to determine cdrom types | ||
4238 | added cdrom_id to the build check | ||
4239 | updated gentoo rule file to handle removable ide devices. | ||
4240 | changed cdrom_id exports to be easier to understand and consistant with other _id programs. | ||
4241 | fix klibc build issue in cdrom_id.c | ||
4242 | Change the gentoo rules to use cdrom_id instead of cdsymlink.sh | ||
4243 | changed location of gentoo helper apps to be /sbin instead of in scripts dir | ||
4244 | tweak the gentoo rules some more. | ||
4245 | |||
4246 | Kay Sievers: | ||
4247 | add NETLINK define for the lazy distros | ||
4248 | read sysfs attribute also from parent class device | ||
4249 | switch some strlcpy's to memcpy | ||
4250 | allow clean shutdown of udevd | ||
4251 | add flag for reading of precompiled rules | ||
4252 | update distro rules files | ||
4253 | add SUSE rules | ||
4254 | update SUSE rules | ||
4255 | add firmware_helper to load firmware | ||
4256 | more distro rules updates | ||
4257 | update README | ||
4258 | remove example rules and put the dev.d stuff into the run_directory folder | ||
4259 | trivial text cleanups | ||
4260 | update SUSE rules | ||
4261 | split udev_util in several files | ||
4262 | update SUSE rules | ||
4263 | allow logging of all output from executed tools | ||
4264 | add Usage: to udevmonitor and udevcontrol | ||
4265 | move some logging to the info level | ||
4266 | |||
4267 | Thierry Vignaud: | ||
4268 | fix udevinfo output | ||
4269 | |||
4270 | |||
4271 | Summary of changes from v064 to v065 | ||
4272 | ============================================ | ||
4273 | |||
4274 | Greg Kroah-Hartman: | ||
4275 | Added persistent name rules for block devices to gentoo rule file. | ||
4276 | Added horrible (but fun) path_id script to extras. | ||
4277 | Update gentoo rules file. | ||
4278 | |||
4279 | Kay Sievers: | ||
4280 | update release notes for next version | ||
4281 | add udevmonitor, to debug netlink+udev events at the same time | ||
4282 | allow RUN to send the environment to a local socket | ||
4283 | fix GGC signed pointer warnings and switch volume_id to stdint | ||
4284 | |||
4285 | |||
4286 | Summary of changes from v063 to v064 | ||
4287 | ============================================ | ||
4288 | |||
4289 | Andre Masella: | ||
4290 | volume_id: add OCFS (Oracle Cluster File System) support | ||
4291 | |||
4292 | Hannes Reinecke: | ||
4293 | usb_id: fix typo | ||
4294 | add ID_BUS to *_id programs | ||
4295 | create_floppy_devices: add tool to create floppy nodes based on sysfs info | ||
4296 | |||
4297 | Kay Sievers: | ||
4298 | move code to its own files | ||
4299 | make SYSFS{} usable for all devices | ||
4300 | add padding to rules structure | ||
4301 | allow rules to have labels and skip to next label | ||
4302 | thread unknown ENV{key} match as empty value | ||
4303 | |||
4304 | |||
4305 | Summary of changes from v062 to v063 | ||
4306 | ============================================ | ||
4307 | |||
4308 | Anton Farygin: | ||
4309 | fix typo in GROUP value application | ||
4310 | |||
4311 | Greg Kroah-Hartman: | ||
4312 | add 'make tests' as I'm always typing that one wrong... | ||
4313 | Really commit the udev_run_devd changes... | ||
4314 | Fixed udev_run_devd to run the /etc/dev.d/DEVNAME/ files too | ||
4315 | fix position of raw rules in gentoo config file | ||
4316 | |||
4317 | Hannes Reinecke: | ||
4318 | dasd_id: add s390 disk-label prober | ||
4319 | fix usb_id and let scsi_id ignore "illegal request" | ||
4320 | |||
4321 | Kay Sievers: | ||
4322 | volume_id: remove s390 dasd handling, it is dasd_id now | ||
4323 | trivial fixes for *_id programs | ||
4324 | IMPORT: add {parent} to import the persistent data of the parent device | ||
4325 | allow multiple values to be matched with KEY=="value1|value2" | ||
4326 | udevd: set incoming socket buffer SO_RCVBUF to maximum | ||
4327 | remember mapped rules state | ||
4328 | ata_id: check for empty serial number | ||
4329 | compile dasd only on s390 | ||
4330 | |||
4331 | Ville Skyttä: | ||
4332 | correct default mode documentation in udev | ||
4333 | |||
4334 | |||
4335 | Summary of changes from v061 to v062 | ||
4336 | ============================================ | ||
4337 | |||
4338 | Kay Sievers: | ||
4339 | fix symlink values separated by multiple spaces | ||
4340 | update RELEASE-NOTES | ||
4341 | fix typo in group assignment | ||
4342 | fix default-name handling and NAME="" rules | ||
4343 | add WAIT_FOR_SYSFS key to loop until a file in sysfs arrives | ||
4344 | fix unquoted strings in udevinitsend | ||
4345 | |||
4346 | Summary of changes from v060 to v061 | ||
4347 | ============================================ | ||
4348 | |||
4349 | Greg Kroah-Hartman: | ||
4350 | Sync up the Debian rules files | ||
4351 | fix cdrom symlink problem in gentoo rules | ||
4352 | Fix ChangeLog titles | ||
4353 | |||
4354 | Kay Sievers: | ||
4355 | update RELEASE-NOTES | ||
4356 | we want to provide OPTFLAGS | ||
4357 | rename ALARM_TIMEOUT to UDEV_ALARM_TIMEOUT | ||
4358 | udevd: optimize env-key parsing | ||
4359 | don't resolve OWNER, GROUP on precompile if string contains %, $ | ||
4360 | set default device node to /dev | ||
4361 | create udevdb files only if somehting interesting happened | ||
4362 | pack parsed rules list | ||
4363 | replace useless defines by inline text | ||
4364 | move rule matches to function | ||
4365 | add usb_id program to generate usb-storage device identifiers | ||
4366 | add IEEE1394 rules to the gentoo rule file | ||
4367 | fake also kernel-name if we renamed a netif | ||
4368 | allow OPTIONS to be recognized for /sys/modules /sys/devices events | ||
4369 | switch gentoo rules to new operators | ||
4370 | |||
4371 | |||
4372 | Summary of changes from v059 to v060 | ||
4373 | ============================================ | ||
4374 | |||
4375 | Greg Kroah-Hartman: | ||
4376 | Fix the gentoo udev rules to allow the box to boot properly | ||
4377 | |||
4378 | Gustavo Zacarias: | ||
4379 | Udev doesn't properly build with $CROSS | ||
4380 | |||
4381 | Kay Sievers: | ||
4382 | Keep udevstart from skipping devices without a 'dev' file | ||
4383 | |||
4384 | Marco d'Itri: | ||
4385 | #define NETLINK_KOBJECT_UEVENT | ||
4386 | |||
4387 | |||
4388 | Summary of changes from v058 to v059 | ||
4389 | ============================================ | ||
4390 | |||
4391 | Greg Kroah-Hartman: | ||
4392 | Update the gentoo rule file | ||
4393 | Fix udevinfo for empty sysfs directories | ||
4394 | Fix makefile to allow 'make release' to work with git | ||
4395 | |||
4396 | Hannes Reinecke: | ||
4397 | udev: fix netdev RUN handling | ||
4398 | udevcontrol: fix exit code | ||
4399 | |||
4400 | Kay Sievers: | ||
4401 | prepare RELEASE-NOTES | ||
4402 | add ID_TYPE to the id probers | ||
4403 | add -x to scsi_id to export the queried values in env format | ||
4404 | store the imported device information in the udevdb | ||
4405 | rename udev_volume_id to vol_id and add --export option | ||
4406 | add ata_id to read serial numbers from ATA drives | ||
4407 | IMPORT allow to import program returned keys into the env | ||
4408 | unify execute_command() and execute_program() | ||
4409 | IMPORT=<file> allow to import a shell-var style config-file | ||
4410 | allow rules to be compiled to one binary file | ||
4411 | fix the fix and change the file to wait for to the "bus" link | ||
4412 | fix udevstart and let all events trvel trough udev | ||
4413 | prepare for module loading rules and add MODALIAS key | ||
4414 | remove device node, when type block/char has changed | ||
4415 | Makefile: remove dev.d/ hotplug.d/ from install target | ||
4416 | udevcontrol: add max_childs command | ||
4417 | udevd: control log-priority of the running daemon with udevcontrol | ||
4418 | udeveventrecorder: add small program that writes an event to disk | ||
4419 | klibc: add missing files | ||
4420 | udevinitsend: handle replay messages correctly | ||
4421 | udev man page: add operators | ||
4422 | udevd: allow starting of udevd with stopped exec-queue | ||
4423 | klibc: version 1.0.14 | ||
4424 | udev: handle all events - not only class and block devices | ||
4425 | volume_id: use udev-provided log-level | ||
4426 | udev: clear lists if a new value is assigned | ||
4427 | udev: move dev.d/ handling to external helper | ||
4428 | udev: allow final assignments := | ||
4429 | udevd: improve timeout handling | ||
4430 | Makefile: fix DESTDIR | ||
4431 | udevd: add initsend | ||
4432 | udevd: add udevcontrol | ||
4433 | udevd: listen for netlink events | ||
4434 | |||
4435 | Stefan Schweizer: | ||
4436 | Dialout group fix for capi devices in the gentoo rules file | ||
4437 | |||
4438 | Summary of changes from v057 to v058 | ||
4439 | ============================================ | ||
4440 | |||
4441 | Daniel Drake: | ||
4442 | o Writing udev rules docs update | ||
4443 | |||
4444 | Darren Salt: | ||
4445 | o update cdsymlinks to latest version | ||
4446 | |||
4447 | Greg Kroah-Hartman: | ||
4448 | o remove detach_state files from the sysfs test tree | ||
4449 | o Update permissions on test scripts so they will run properly now | ||
4450 | o hopefully fix up the symlinks in the test directory | ||
4451 | o Removed klibc/klibc.spec as it is autogenerated | ||
4452 | o Added symlinks thanks to Kay's script and git hacking | ||
4453 | o add Red Hat/Fedora html documenation | ||
4454 | o Update Red Hat default udev rules | ||
4455 | |||
4456 | Kay Sievers: | ||
4457 | o selinux: fix handling during creation of symlinks | ||
4458 | o Fedora udev.rules update | ||
4459 | o libsysfs: version 2.0 | ||
4460 | o klibc: version 1.0.7 | ||
4461 | |||
4462 | Masanao Igarashi: | ||
4463 | o Fix libsysfs issue with relying on the detach_state file to be | ||
4464 | |||
4465 | Summary of changes from v056 to v057 | ||
4466 | ============================================ | ||
4467 | |||
4468 | <tklauser:access.unizh.ch>: | ||
4469 | o fix stupid all_partitions bug | ||
4470 | |||
4471 | Kay Sievers: | ||
4472 | o add test for make -j4 to build-check | ||
4473 | o klibc: version 1.0.6 | ||
4474 | o update Debian rules | ||
4475 | o apply default permissions only for devices that will need it | ||
4476 | o adapt RELEASE-NOTES | ||
4477 | o udev_volume_id: fix endianess macros | ||
4478 | o udev-test.pl: add test for DEVNAME export to RUN environment | ||
4479 | o update the man page to reflect the recent changes | ||
4480 | o export DEVNAME to RUN-key executed programs | ||
4481 | o fix make -j4 and the local klibc-install | ||
4482 | o update RELEASE-NOTES | ||
4483 | o add RUN key to be able to run rule based notification | ||
4484 | o fix udevtest to print the error if logging is disabled | ||
4485 | o move execute_program to utils + add action to init_device | ||
4486 | o correct correction for error path for PROGRAM execution | ||
4487 | o correct error path for PROGRAM execution | ||
4488 | o klibc: version 1.0.5 | ||
4489 | o check for strlen()==0 before accessing strlen()-1 | ||
4490 | o allow to match against empty key values | ||
4491 | o read %s{}-sysfs values at any device in the chain | ||
4492 | o udev_rules.c: don't change sysfs_device while walking up the device chain | ||
4493 | o klibc: strlcpy/strlcat - don't alter destination if size == 0 | ||
4494 | o fix klibc's broken strlcpy/strlcat | ||
4495 | o udevinfo: print SYSFS attribute the same way we match it | ||
4496 | o remove untrusted chars read from sysfs-values or returned by PROGRAM | ||
4497 | o udevinfo: print errors to stderr instead of stdout | ||
4498 | o klibc: version 1.0.4 | ||
4499 | o support log-priority levels in udev.conf | ||
4500 | o test-suite: remove UDEV_TEST, it's not needed anymore | ||
4501 | o libsysfs: remove trailing slash on SYSFS_PATH override | ||
4502 | |||
4503 | |||
4504 | Summary of changes from v055 to v056 | ||
4505 | ============================================ | ||
4506 | |||
4507 | <tklauser:access.unizh.ch>: | ||
4508 | o fix header paths in udev_libc_wrapper.c | ||
4509 | |||
4510 | Kay Sievers: | ||
4511 | o udev-test.pl: use more common user/group names | ||
4512 | o klibc: remove SCCS directories from the temporary klibc install | ||
4513 | o udev-test.pl: add a test where the group cannot be found in /etc/passwd | ||
4514 | o udev-test.pl: add check for textual uid/gid | ||
4515 | o fix bad typo that prevents the GROUP to be applied | ||
4516 | o udevd: don't delay events with TIMEOUT in the environment | ||
4517 | o klibc: use klcc wrapper instead of our own Makefile | ||
4518 | o change call_foreach_file to return a list | ||
4519 | |||
4520 | |||
4521 | Summary of changes from v054 to v055 | ||
4522 | ============================================ | ||
4523 | |||
4524 | <jkluebs:luebsphoto.com>: | ||
4525 | o This patch causes the remove handler to check that each symlink actually points to the correct devnode and skip it if it does not. | ||
4526 | |||
4527 | <pebenito:gentoo.org>: | ||
4528 | o udev selinux fix | ||
4529 | |||
4530 | <tklauser:access.unizh.ch>: | ||
4531 | o The following patch fixes some warnings when compiling volume_id from udev with the -Wall compiler flag. Define _GNU_SOURCE for strnlen() and correct the path to logging.h | ||
4532 | o The following patch fixes a warning when compiling chassis_id from udev with the -Wall compiler flag. There are too much conversions in the format string of sscanf(). One %d can be dropped. | ||
4533 | |||
4534 | Greg Kroah-Hartman: | ||
4535 | o fix raid rules | ||
4536 | o added frugalware udev ruleset | ||
4537 | o merge selinux and Kay's symlink fixes together | ||
4538 | |||
4539 | Hannes Reinecke: | ||
4540 | o volume_id: Fix label/uuid reading for reiserfs | ||
4541 | |||
4542 | Kay Sievers: | ||
4543 | o add udevstart to the RELEASE-NOTES | ||
4544 | o volume_id: version 43 | ||
4545 | o clarify the shortcomings of %e | ||
4546 | o correct rule match for devices without a physical device | ||
4547 | o remove unneeded code, libsysfs does this for us | ||
4548 | o add final release note | ||
4549 | o add ENV{} key to match agains environment variables | ||
4550 | o simplify sysfs_pair handling | ||
4551 | o add a test and simplify debug statement | ||
4552 | o support =, ==, !=, += for the key match and assignment | ||
4553 | o add OPTION="last_rule" to skip any later rule | ||
4554 | o rename namedev_dev to udev_rule | ||
4555 | o correct enum device_type | ||
4556 | o remove udevstart on make clean | ||
4557 | o volume_id: version 42 | ||
4558 | o volume_id: version 41 | ||
4559 | o remove unneeded include | ||
4560 | o The path to dlist.h is not correct | ||
4561 | o udevinfo -d: use '=' as separator, cause ':' may be a part of the devpath | ||
4562 | o klibc: version 1.0.3 | ||
4563 | o add RELEASE-NOTES file | ||
4564 | o test suite: move "driver" link to physical device | ||
4565 | o remove PLACE key match | ||
4566 | o don't lookup "root" in the userdb | ||
4567 | o fix ia64 compile | ||
4568 | o fix segfaulting udev while DRIVER matching | ||
4569 | o cleanup list.h | ||
4570 | o klibc: version 0.214 | ||
4571 | o rename device_list->list to device_list->node | ||
4572 | o replace strncpy()/strncat() by strlcpy()/strlcat() | ||
4573 | o split udev and udevstart | ||
4574 | o udev_volume_id: version 39 | ||
4575 | o rename LOG to USE_LOG in all places | ||
4576 | o remove Makefile magic for klibc integration | ||
4577 | o klibc_fixups: remove no longer needed stuff | ||
4578 | o udev_volume_id: volume_id v38 | ||
4579 | o use numeric owner/group as default values to avoid parsing userdb | ||
4580 | o fix up segfaulting binaries with new klibc | ||
4581 | o udevinfo -d: speed-up device dump | ||
4582 | o klibc: version 0.211 | ||
4583 | o klibc_fixups: remove unneeded stuff | ||
4584 | o replace weird defines by real code | ||
4585 | o udev-test.pl: remove useless tests | ||
4586 | o allow unlimitied count of symlinks | ||
4587 | o unmap db-file after use | ||
4588 | o remove typedef for call_foreach_file() handler function | ||
4589 | o correct udev_init_device | ||
4590 | o rename attributes to options | ||
4591 | o kill stupid gcc4 warning | ||
4592 | o trivial clenaup of namedev code | ||
4593 | o klibc: check for gcc4 | ||
4594 | o klibc: update v0.205 | ||
4595 | |||
4596 | Thierry Vignaud: | ||
4597 | o gentoo rule update for raid devices | ||
4598 | |||
4599 | |||
4600 | Summary of changes from v053 to v054 | ||
4601 | ============================================ | ||
4602 | |||
4603 | <tklauser:access.unizh.ch>: | ||
4604 | o udev_volume_id: add Reiser4 support | ||
4605 | |||
4606 | Kay Sievers: | ||
4607 | o namedev: skip backslashes only if followed by newline | ||
4608 | o wait_for_sysfs: add joydev | ||
4609 | o udevinfo: print devpath -> node relationship for all devices | ||
4610 | o trivial rename of some variables | ||
4611 | o klibc v0.199 | ||
4612 | o big libsysfs diet (pre 2.0 version) | ||
4613 | o udev_volume_id: volume_id v35 | ||
4614 | o add "serio" to bus list | ||
4615 | o determine device type in udev_init_device() | ||
4616 | o move kernel name/number evaluation into udev_init_device() | ||
4617 | o detect NAME="" as ignore_device rule | ||
4618 | o trivial namedev cleanup | ||
4619 | o cleanup db functions | ||
4620 | o clean up match_place() | ||
4621 | o switch device type to enum | ||
4622 | o switch major/minor to dev_t | ||
4623 | o remove the device node only if the major/minor number matches | ||
4624 | o libsysfs: work around a klibc bug | ||
4625 | o introduce OPTIONS=ignore_device, ignore_remove, all_partitions" key | ||
4626 | o namedev: execute PROGRAM only once and not possibly for every physical device | ||
4627 | |||
4628 | Patrick Mansfield: | ||
4629 | o update scsi_id to work with libsysfs changes | ||
4630 | |||
4631 | |||
4632 | Summary of changes from v052 to v053 | ||
4633 | ============================================ | ||
4634 | |||
4635 | Greg Kroah-Hartman: | ||
4636 | o fix gentoo fb permission issue | ||
4637 | o allow simple-build-check.sh to go faster if MAKEOPTS is set | ||
4638 | o make the release tarballs have writable files in them | ||
4639 | o remove gentoo permission file as it's not valid anymore | ||
4640 | |||
4641 | Kay Sievers: | ||
4642 | o fix special file mode mask for temporary device node | ||
4643 | o udevstart: simplify "dev" file searching | ||
4644 | o udev_volume_id: remove temporary node creation and parent handling | ||
4645 | o add %P modifier to query the node name of the parent device | ||
4646 | o udev_volume_id: remove __packed__ from dasd structure as it does not work | ||
4647 | o create /block/*/range count of partitons for all_partitions | ||
4648 | |||
4649 | Patrick Mansfield: | ||
4650 | o scsi_id changes for use with udev %N and %p | ||
4651 | |||
4652 | |||
4653 | Summary of changes from v051 to v052 | ||
4654 | ============================================ | ||
4655 | |||
4656 | <md:linux.it>: | ||
4657 | o debian: update rules files | ||
4658 | o raid-devfs.sh: devfs names for hardware RAID controllers | ||
4659 | o scsi_id: when udevstart is started, /tmp is not writeable | ||
4660 | o cdsymlinks.sh: trivial fix, the variable is initialized to '', not 0 | ||
4661 | |||
4662 | <sschweizer:gmail.com>: | ||
4663 | o gentoo/udev.rules: add default permissions for sound devices | ||
4664 | |||
4665 | Greg Kroah-Hartman: | ||
4666 | o fix example comment in ide-devfs.sh | ||
4667 | o Add infiniband to gentoo rules | ||
4668 | o Another gentoo fix, adding dvb support | ||
4669 | o Fix gentoo bug #76056 (fb device group permissions.) | ||
4670 | o Fix gentoo bug #81102, device nodes for the pktcdvd device | ||
4671 | |||
4672 | Kay Sievers: | ||
4673 | o provide temporary device node for callouts to access the device | ||
4674 | o udev_volume_id: fix dasd disklabel reading with -l option | ||
4675 | o udev_volume_id: volume_id version 034 | ||
4676 | o udev_volume_id: rename probe_ibm into probe_dasd | ||
4677 | o udev_volume_id: volume_id version 032 | ||
4678 | o Makefile: add some more warnings and prepare for clean gcc4 compile | ||
4679 | o Makefile: cleanup conditional config option sections | ||
4680 | o fix -Wsign-compare warnings | ||
4681 | o chassis_id: clean compilation and fix bad function parameter passing | ||
4682 | o simple_build_check: make it possible to pass KERNEL_DIR | ||
4683 | o selinux: cleanup udev integration | ||
4684 | |||
4685 | Michael Buesch: | ||
4686 | o trivial: remove _all_ trailing slashes with no_trailing_slash() | ||
4687 | o trivial: fix signedness | ||
4688 | o namdev: allow symlink-only rules to specify node permissions | ||
4689 | o udevd: fix valgrind warning | ||
4690 | |||
4691 | |||
4692 | Summary of changes from v050 to v051 | ||
4693 | ============================================ | ||
4694 | |||
4695 | <roland:digitalvampire.org>: | ||
4696 | o This fixes a silly mistake in how udevinfo prints the major and minor numbers (right now it prints the minor next to "MAJOR" and the major next to "MINOR" ;) | ||
4697 | |||
4698 | <tklauser:access.unizh.chbk>: | ||
4699 | o I tried to compile udev 050plus with the GCC 4.0 snapshot 200412119 and got two errors about possibly uninitialized structs, so I fixed this. | ||
4700 | |||
4701 | Christian Bornträger: | ||
4702 | o udev_volume_id: fix -d option | ||
4703 | |||
4704 | Greg Kroah-Hartman: | ||
4705 | o gentoo fb permission fix | ||
4706 | o fix gcc 2.96 issue in libsysfs | ||
4707 | o remove the lfs startup script on request of the author | ||
4708 | o clean up the aoe char device rules, and delete the block one as it's not needed | ||
4709 | o add aoe block and char device rules to the gentoo rule file | ||
4710 | o fix udev_volume_id build error | ||
4711 | |||
4712 | Hannes Reinecke: | ||
4713 | o rearrange link order in Makefile | ||
4714 | |||
4715 | Kay Sievers: | ||
4716 | o udev_volume_id: new version of volume_id | ||
4717 | o klibc: update to version 0.198 | ||
4718 | o udev_volume_id: fix FAT label reading | ||
4719 | o klibc: update to version 0.196 | ||
4720 | o udevd: throttle the forking of processes | ||
4721 | o udevd: add possible initialization of expected_seqnum | ||
4722 | o udevd: it's obviously not the brightest idea to exit a device node manager if it doesn't find /dev/null | ||
4723 | o udevd: separate socket handling to prepare for other event sources | ||
4724 | o udevd: support -d switch to become a daemon | ||
4725 | o udev_volume_id: version 27 | ||
4726 | o udevd: split up message receiving an queueing | ||
4727 | o remove useless warning if udev.conf contains keys not read by udev itself | ||
4728 | o improve event sequence serialization | ||
4729 | o remove udevsend syslog noise on udevd startup | ||
4730 | o limit the initial timeout of the udevd event handling | ||
4731 | o correct detection of hotplug.d/ udevsend loop | ||
4732 | o correct log statement | ||
4733 | o remove default_* permissions from udev.conf file | ||
4734 | o update Fedora config files and add some more tests | ||
4735 | o allow permissions only rules | ||
4736 | o add SUBSYSTEM rule to catch all block devices and apply the disk permissions | ||
4737 | o update Fedora config files | ||
4738 | o handle renamed network interfaces properly if we manage hotplug.d/ | ||
4739 | o allow multiline rules by backslash at the end of the line | ||
4740 | o add OnStream tape drive rules | ||
4741 | o simplify rules file by setting default mode to 0660 | ||
4742 | o simplify permission application | ||
4743 | o I broke the extras/ again. Add simple build test script now | ||
4744 | o Merge vrfy.org:/home/kay/src/udev into vrfy.org:/home/kay/src/udev.kay | ||
4745 | o initial merge of fedora udev.permissions into udev.rules | ||
4746 | o remove permissions file mentioning from the udev man page | ||
4747 | o fix some typos in gentoo's udev.rules introduced by the merge | ||
4748 | |||
4749 | Michael Buesch: | ||
4750 | o The attached patch fixes the code path if namedev_name_device() fails | ||
4751 | |||
4752 | Summary of changes from v049 to v050 | ||
4753 | ============================================ | ||
4754 | |||
4755 | <harald:redhat.com>: | ||
4756 | o selinux patch | ||
4757 | |||
4758 | <tklauser:access.unizh.ch>: | ||
4759 | o I made some more changes to the manpage of udev including | ||
4760 | |||
4761 | Kay Sievers: | ||
4762 | o update libsysfs to CVS version and fix segfaulting attribute reading | ||
4763 | o klibc supports LOG_PID now, so remove our own implementation | ||
4764 | o avoid building klibc test programs and pass SUBDIRS= to klibc clean | ||
4765 | |||
4766 | |||
4767 | Summary of changes from v048 to v049 | ||
4768 | ============================================ | ||
4769 | |||
4770 | Greg Kroah-Hartman: | ||
4771 | o fix 'make clean' error in klibc | ||
4772 | |||
4773 | Kay Sievers: | ||
4774 | o update klibc to 0.194 | ||
4775 | o export DEVNAME regardless of the state of udev_dev_d | ||
4776 | o add class specific files for class/spi_transport and class/spi_host | ||
4777 | o udevd-test.pl: remove wrong date calculation | ||
4778 | o check earlier if we should run as udevstart | ||
4779 | o remove double initialization | ||
4780 | o include missing header to udevtest.c | ||
4781 | o add -V option to udev to print the version number | ||
4782 | o prevent udev node creatinon for "class" registration | ||
4783 | o udevd: serialization of the event sequence of a chain of devices | ||
4784 | o add a class/fc_host file to the list of what to wait for | ||
4785 | o udev_volume_id: links sysfs.a instead of all objects | ||
4786 | |||
4787 | Martin Schlemmer: | ||
4788 | o remove leftover from udevinfo's -d option | ||
4789 | |||
4790 | |||
4791 | Summary of changes from v047 to v048 | ||
4792 | ============================================ | ||
4793 | |||
4794 | Greg Kroah-Hartman: | ||
4795 | o fix udev_volume_id so it will now build properly | ||
4796 | o fix scsi_id build errors due to changes in the main udev makefile | ||
4797 | |||
4798 | |||
4799 | Summary of changes from v046 to v047 | ||
4800 | ============================================ | ||
4801 | |||
4802 | <klauser:access.unizh.ch>: | ||
4803 | o Various typos and other litte errors in udev.8.in | ||
4804 | |||
4805 | <sjoerd:spring.luon.net>: | ||
4806 | o DEVNAME on device removal | ||
4807 | |||
4808 | <sschweizer:gmail.com>: | ||
4809 | o Allow GROUP to have modifiers in it | ||
4810 | |||
4811 | Greg Kroah-Hartman: | ||
4812 | o add more debian rules files | ||
4813 | o move distro specific config files into their own directories | ||
4814 | o update debian rules files | ||
4815 | o added asterix rules to the gentoo file | ||
4816 | o use udevstart for udev.init.* files | ||
4817 | o delete a bunch of files no longer needed | ||
4818 | o fix gentoo scsi cdrom rule | ||
4819 | o Fix the multithreaded build again | ||
4820 | o merge | ||
4821 | o comment out ability to run udev-test.pl with valgrind | ||
4822 | o fix spurious valgrind warning in udev | ||
4823 | o fix udevinfo '-q path' option as it was not working | ||
4824 | o merge | ||
4825 | o fix parallel build error | ||
4826 | |||
4827 | Kay Sievers: | ||
4828 | o update Fedora dev.d/ example and remove unused conf.d/ directory | ||
4829 | o don't install distribution specific init script on "make install" | ||
4830 | o restore OWNER/GROUP assignment in rule coming from RESULT | ||
4831 | o make gcov compile scripts working with recent gcc | ||
4832 | o fix udev-test/udev-test.pl to work with again | ||
4833 | o add net/atml and class/ppdev to the wait_for_sysfs exception list | ||
4834 | o add net/nlv* devices to the exception list | ||
4835 | o add "pcmcia" and "fc_transport" to the wait_for_sysfs lists | ||
4836 | o remove unused timestamp field | ||
4837 | o simplify permission handling | ||
4838 | o handle /etc/hotplug.d/ only if the event comes from udevd | ||
4839 | o trivial cleanups and change some comments | ||
4840 | o remove unused variables | ||
4841 | o udevsend/udevd handle events without a subsystem | ||
4842 | o use blacklist on device "remove" and remove dev.d/ call code duplication | ||
4843 | o update the man pages and correct Usage: hints | ||
4844 | o don't call the hotplug scripts with a test run | ||
4845 | o don't call dev.d/ scripts twice, if directory = subsystem | ||
4846 | o remove archive file if we changed something | ||
4847 | o link archive insted of objects | ||
4848 | o rename udev_lib to udev_utils and dev_d to udev_multiplex | ||
4849 | o handle whole hotplug event with udevd/udev | ||
4850 | o integrate wait_for_sysfs in udev | ||
4851 | o make the searched multiplex directories conditionally | ||
4852 | o add MANAGED_EVENT to the forked udev environment | ||
4853 | o export DEVNAME on remove event | ||
4854 | o export udev_log flag to the environment | ||
4855 | o remove my test code | ||
4856 | o add support for /devices-devices without any file to wait for | ||
4857 | o Patch from Alex Riesen <raa.lkml@gmail.com> | ||
4858 | o add a bunch of busses to the list of what to wait for | ||
4859 | o close connection to syslog in forked udevd child | ||
4860 | o udevd exit path cleanup | ||
4861 | o fix network device naming bug | ||
4862 | |||
4863 | |||
4864 | Summary of changes from v045 to v046 | ||
4865 | ============================================ | ||
4866 | |||
4867 | Greg Kroah-Hartman: | ||
4868 | o make spotless for releases | ||
4869 | |||
4870 | Kay Sievers: | ||
4871 | o Don't try to print major/minor for devices without a dev file | ||
4872 | o remove get_device_type and merge that into udev_set_values() | ||
4873 | o prevent udevd crash if DEVPATH is not set | ||
4874 | o add ippp and bcrypt to the exception lists of wait_for_sysfs | ||
4875 | o let klibc add the trailing newline to syslog conditionally | ||
4876 | o disable logging for udevstart | ||
4877 | o add NAME{ignore_remove} attribute | ||
4878 | o remove historical SYSFS_attr="value" format | ||
4879 | o don't wait for sysfs if the kernel(2.6.10-rc2) tells us what not to expect | ||
4880 | o change key names in udevinfo sysfs walk to match the kernel | ||
4881 | o support DRIVER as a rule key | ||
4882 | o support SUBSYSTEM as a rule key | ||
4883 | o rename udevdb* to udev_db* | ||
4884 | o Make dev.d/ handling a separate processing stage | ||
4885 | o make the udev object available to more processing stages | ||
4886 | o remove udev_lib dependency from udevsend, which makes it smaller | ||
4887 | o add ACTION to udev object to expose it to the whole process | ||
4888 | o make udevinfo's -r option also workimg for symlink queries | ||
4889 | o let udev act as udevstart if argv[1] == "udevstart" | ||
4890 | o improve udevinfo sysfs info walk | ||
4891 | o add sysfs info walk to udevinfo | ||
4892 | o pass the whole event environment to udevd | ||
4893 | o replace tdb database by simple lockless file database | ||
4894 | |||
4895 | |||
4896 | Summary of changes from v044 to v045 | ||
4897 | ============================================ | ||
4898 | |||
4899 | Martin Schlemmer: | ||
4900 | o Some updates for Gentoo's udev rules | ||
4901 | |||
4902 | |||
4903 | Summary of changes from v043 to v044 | ||
4904 | ============================================ | ||
4905 | |||
4906 | Greg Kroah-Hartman: | ||
4907 | o add cdsymlinks.sh support to gentoo rules file | ||
4908 | o fix gentoo legacy tty rule | ||
4909 | o remove 'sudo' usage from the Makefile | ||
4910 | o make udev-test.pl test for root permissions before running | ||
4911 | |||
4912 | Kay Sievers: | ||
4913 | o reduce syslog noise of udevsend if multiple instances try to start udevd | ||
4914 | o add i2c-dev to the list of devices without a bus | ||
4915 | |||
4916 | |||
4917 | Summary of changes from v042 to v043 | ||
4918 | ============================================ | ||
4919 | |||
4920 | Greg Kroah-Hartman: | ||
4921 | o add test target to makefile | ||
4922 | o add dumb script to show all sysfs devices in the system | ||
4923 | |||
4924 | Kay Sievers: | ||
4925 | o Shut up wait_for_sysfs class/net failure messages, as it's not possible to | ||
4926 | get that right for all net devices. Kernels later than 2.6.10-rc1 will | ||
4927 | handle that by carrying the neccessary information in the hotplug event. | ||
4928 | o wait() for specific pid to return from fork() | ||
4929 | o Don't use any syslog() in signal handler, cause it may deadlock | ||
4930 | o Add support for highpoint ataraid to volume_id to suppress label reading on raid set members. | ||
4931 | o Add a bunch of devices without "device" symlinks | ||
4932 | o Exit, if udevtest cannot open the device (segfault) | ||
4933 | o Patches from Harald Hoyer <harald@redhat.com> | ||
4934 | o Apply the default permissions even if we found a entry in the permissions | ||
4935 | file. Correct one test, as the default is applied correctly now and the | ||
4936 | mode will no longer be 0000. | ||
4937 | o add test for format chars in multiple symlinks to replace | ||
4938 | o Add net/vmnet and class/zaptel to the list of devices without physical device | ||
4939 | |||
4940 | |||
4941 | Summary of changes from v040 to v042 | ||
4942 | ============================================ | ||
4943 | |||
4944 | Greg Kroah-Hartman: | ||
4945 | o add inotify to the rules for gentoo | ||
4946 | |||
4947 | Kay Sievers: | ||
4948 | o skip waiting for device if we get a bad event for class creation and not for a device underneath it | ||
4949 | o add net/pan and net/bnep handling | ||
4950 | o switch wait for bus_file to stat() instead of open() add net/tun device handling add ieee1394 device handling | ||
4951 | o Remove the last klibc specific line from the main udev code Move _KLIBC_HAS_ARCH_SIG_ATOMIC_T to the fixup file which is automatically included by the Makefile is we build with klibc | ||
4952 | o ignore *.rej files from failed patches | ||
4953 | o update to libsysfs 1.2.0 and add some stuff klib_fixup Now we have only the sysfs.h file different from the upstream version to map our dbg() macro. | ||
4954 | o improve klibc fixup integration | ||
4955 | o cleanup udevd/udevstart | ||
4956 | o expose sysfs functions for sharing it | ||
4957 | |||
4958 | |||
4959 | Summary of changes from v039 to v040 | ||
4960 | ============================================ | ||
4961 | |||
4962 | <jk:blackdown.de>: | ||
4963 | o wait_for_sysfs update for dm devices | ||
4964 | |||
4965 | Greg Kroah-Hartman: | ||
4966 | o sparse cleanups on the tree | ||
4967 | o fix stupid cut-and-paste error for msr devices on gentoo boxes | ||
4968 | o add *~ to bk ignore list | ||
4969 | o delete udevruler.c as per Kay's request | ||
4970 | o fix up the wait_for_sysfs_test script a bit | ||
4971 | |||
4972 | Kay Sievers: | ||
4973 | o fix debug in volume id / fix clashing global var name | ||
4974 | o volume_id fix | ||
4975 | o $local user | ||
4976 | o cleanup netif handling and netif-dev.d/ events | ||
4977 | o big cleanup of internal udev api | ||
4978 | o don't wait for dummy devices | ||
4979 | o close the syslog | ||
4980 | o Fix ppp net devices in wait_for_sysfs | ||
4981 | o Fix wait_for_sysfs messages (more debugging info) | ||
4982 | |||
4983 | |||
4984 | Summary of changes from v038 to v039 | ||
4985 | ============================================ | ||
4986 | |||
4987 | Greg Kroah-Hartman: | ||
4988 | o Hopefully fix the vcs issue in wait_for_sysfs | ||
4989 | o take out & from wait_for_sysfs_test that I previously missed | ||
4990 | o add very nice cdsymlinks scripts | ||
4991 | o add some helper scripts for dvb and input devices | ||
4992 | o add debian config files | ||
4993 | o let the extras/ programs build "pretty" also | ||
4994 | o tweak the ccdv program to handle files in subdirectories being built | ||
4995 | o crap, I messed up the 'sed' instances pretty badly, this fixes the config and man page mess | ||
4996 | o fix broken 'make -j5' functionality | ||
4997 | |||
4998 | Kay Sievers: | ||
4999 | o swich attribute open() to simple stat() | ||
5000 | o wait_for_sysfs update for /class/firmware and /class/net/irda devices | ||
5001 | o fix unusual sysfs behavior for pcmcia_socket | ||
5002 | o remove sleeps from udev as it is external now | ||
5003 | o delete udevruler? | ||
5004 | o Makefile fix | ||
5005 | |||
5006 | Patrick Mansfield: | ||
5007 | o update udev to scsi_id 0.7 | ||
5008 | o pass SYSFS setting down for extras builds | ||
5009 | o move assignments past local variables | ||
5010 | |||
5011 | |||
5012 | Summary of changes from v037 to v038 | ||
5013 | ============================================ | ||
5014 | |||
5015 | <andrew.patterson:hp.com>: | ||
5016 | o Re: Problem parsing %s in udev rules | ||
5017 | |||
5018 | Greg Kroah-Hartman: | ||
5019 | o fix up error in building extras and libsysfs | ||
5020 | |||
5021 | Summary of changes from v036 to v037 | ||
5022 | ============================================ | ||
5023 | |||
5024 | <md:linux.it>: | ||
5025 | o small udev patch | ||
5026 | |||
5027 | Greg Kroah-Hartman: | ||
5028 | o fix compilation warning in tdb log message | ||
5029 | o Fix build error with klibc due to recent changes | ||
5030 | o merge | ||
5031 | o add wait_for_sysfs test script to the tarball to help people debug their boxes | ||
5032 | o add ipsec to wait_for_sysfs ignore list | ||
5033 | o added ccdv to bk ignore list | ||
5034 | o a few more Makefile tweaks for the quiet feature | ||
5035 | o Make the build silent, thanks to a helper program from ncftp | ||
5036 | o rename files to have '_' instead of '-' in them | ||
5037 | o change max time to wait in wait_for_sysfs to 10 seconds to hopefully handle some slow machines | ||
5038 | o add support for class/raw/ to wait_for_sysfs | ||
5039 | o fix up Makefile for wait_for_sysfs udev_version.h dependancy | ||
5040 | o remove the debian specific file, as they don't want to share with the rest of the world :( | ||
5041 | |||
5042 | Kay Sievers: | ||
5043 | o prevent deadlocks on an corrupt udev database | ||
5044 | o wait_for_sysfs_update | ||
5045 | |||
5046 | Michael Buesch: | ||
5047 | o fix asmlinkage | ||
5048 | o fix incompatible pointer type warning | ||
5049 | |||
5050 | |||
5051 | Summary of changes from v035 to v036 | ||
5052 | ============================================ | ||
5053 | |||
5054 | Greg Kroah-Hartman: | ||
5055 | o add the error number to the error message in wait_for_sysfs to help out in debugging problems | ||
5056 | |||
5057 | Summary of changes from v034 to v035 | ||
5058 | ============================================ | ||
5059 | |||
5060 | Greg Kroah-Hartman: | ||
5061 | o added ieee1394 support to wait_for_sysfs | ||
5062 | o update wait_for_sysfs with a bunch more devices thanks to user reports | ||
5063 | |||
5064 | Summary of changes from v033 to v034 | ||
5065 | ============================================ | ||
5066 | |||
5067 | Kay Sievers: | ||
5068 | o wait_for_sysfs bluetooth class update | ||
5069 | |||
5070 | Greg Kroah-Hartman: | ||
5071 | o add comment in wait_for_sysfs to explain the structure better | ||
5072 | o Revert previous dev_d.c change, it's not what is causing HAL problems | ||
5073 | o hm, somethings odd with DEVPATH, see if this fixes it | ||
5074 | o 33_bk mark for the makefile | ||
5075 | o wait_for_sysfs: clean up the logic for the list of devices that we do not expect device symlinks for | ||
5076 | o get rid of annoying extra lines in the syslog for some libsysfs debug messages | ||
5077 | o added support for i2c devices in wait_for_sysfs.c | ||
5078 | o add support for i2c-adapter devices to wait_for_sysfs.c | ||
5079 | |||
5080 | Summary of changes from v032 to v033 | ||
5081 | ============================================ | ||
5082 | |||
5083 | <harald:redhat.com>: | ||
5084 | o udev close on exec | ||
5085 | o some cleanups and security fixes | ||
5086 | o some cleanups and security fixes | ||
5087 | o selinux for udev | ||
5088 | o cleanup PATCH for extras/chassis_id/Makefile | ||
5089 | |||
5090 | <kpfleming:backtobasicsmgmt.com>: | ||
5091 | o respect prefix= setting in built udev.conf (updated) | ||
5092 | |||
5093 | Greg Kroah-Hartman: | ||
5094 | o add support for usb interfaces to wait_for_sysfs to keep it quiet | ||
5095 | o enable native tdb spinlocks on i386 platforms | ||
5096 | o delete extras/multipath-tools as per the author's request | ||
5097 | o be paranoid in dev_d.c | ||
5098 | o add USE_SELINUX to README documentation so people have a chance to see what is going on | ||
5099 | o update the selinux.h file to start to look sane | ||
5100 | o update bk ignore list for the wait_for_sysfs binary | ||
5101 | o kdetv wants to see device nodes in /dev | ||
5102 | o update comments in scsi-devfs.sh | ||
5103 | o fix up Makefiles to get the klibc build working properly | ||
5104 | o update bk ignore list for new klibc generated files | ||
5105 | o oops forgot to add the new klibc/include directory | ||
5106 | o update klibc to version 0.181 | ||
5107 | |||
5108 | Kay Sievers: | ||
5109 | o fix problems with dev.d and udevstart | ||
5110 | o wait_for_sysfs debug cleanup | ||
5111 | o fix problems using scsi_id with udevstart | ||
5112 | o update volume_id | ||
5113 | o finally solve the bad sysfs-timing for all of us | ||
5114 | o volume-id build fix and update | ||
5115 | o switch udev's seqnum to u64 | ||
5116 | o add enum tests | ||
5117 | o fix udev segfaults with bad permissions file | ||
5118 | |||
5119 | Patrick Mansfield: | ||
5120 | o update udev to include scsi_id 0.6 | ||
5121 | |||
5122 | |||
5123 | Summary of changes from v031 to v032 | ||
5124 | ============================================ | ||
5125 | |||
5126 | <harald:redhat.com>: | ||
5127 | o udev parse bug | ||
5128 | |||
5129 | Kay Sievers: | ||
5130 | o handle only block and class devices | ||
5131 | o fix udevstart badly broken in udev 031 | ||
5132 | |||
5133 | |||
5134 | Summary of changes from v030 to v031 | ||
5135 | ============================================ | ||
5136 | |||
5137 | <arun:codemovers.org>: | ||
5138 | o udev - read long lines from config files overflow fix | ||
5139 | |||
5140 | <ballarin.marc:gmx.de>: | ||
5141 | o Update the FAQ with info about hardlink security | ||
5142 | |||
5143 | <david:fubar.dk>: | ||
5144 | o compatibility symlinks for udev | ||
5145 | |||
5146 | David Weinehall: | ||
5147 | o Minor POSIX-fixes for udev | ||
5148 | |||
5149 | Greg Kroah-Hartman: | ||
5150 | o add symlink for video rule | ||
5151 | o add a "first" list to udevstart and make it contain the class/mem/ devices | ||
5152 | o fix compiler warning in udevtest.c | ||
5153 | o Fix old-style pty breakage in rules file for tty device | ||
5154 | o add rules for i386 cpu devices | ||
5155 | o add permission for legotower usb devices | ||
5156 | |||
5157 | Kay Sievers: | ||
5158 | o Fix naming ethernet devices in udevstart | ||
5159 | o update udev_volume_id | ||
5160 | o let /sbin/hotplug execute udev earlier | ||
5161 | o pass SEQNUM trough udevd | ||
5162 | o fix manpages based on esr's spambot | ||
5163 | |||
5164 | Martin Schlemmer: | ||
5165 | o add microcode rule to permissions.gentoo file | ||
5166 | |||
5167 | Michael Buesch: | ||
5168 | o Try to provide a bit of security for hardlinks to /dev entries | ||
5169 | |||
5170 | Olaf Hering: | ||
5171 | o udevsend depends on udev_lib.o | ||
5172 | |||
5173 | Tom Rini: | ||
5174 | o fix UDEV_NO_SLEEP | ||
5175 | o clean up start_udev a bit | ||
5176 | o Make udev/udevstart be one binary | ||
5177 | o Add 'asmlinkage' to udev-030 | ||
5178 | |||
5179 | |||
5180 | Summary of changes from v029 to v030 | ||
5181 | ============================================ | ||
5182 | |||
5183 | Greg Kroah-Hartman: | ||
5184 | o fix stupid off-by-one bug that caused udevstart to die on x86-64 boxes | ||
5185 | |||
5186 | |||
5187 | Summary of changes from v028 to v029 | ||
5188 | ============================================ | ||
5189 | |||
5190 | Greg Kroah-Hartman: | ||
5191 | o add permission rule for jogdial device | ||
5192 | o fix dumb bug I added to udevstart | ||
5193 | o make a "last list" of devices for udevstart to operate on last | ||
5194 | o fix permission problem with input event and ts nodes for gentoo | ||
5195 | o change default perms of misc/rtc to be readable by anyone | ||
5196 | |||
5197 | Olaf Hering: | ||
5198 | o allow NAME_SIZE > SYSFS_PATH_MAX | ||
5199 | |||
5200 | |||
5201 | Summary of changes from v027 to v028 | ||
5202 | ============================================ | ||
5203 | |||
5204 | <atul.sabharwal:intel.com>: | ||
5205 | o Patch for chassis_id exras module | ||
5206 | |||
5207 | Daniel Drake: | ||
5208 | o Writing udev rules doc update | ||
5209 | |||
5210 | Greg Kroah-Hartman: | ||
5211 | o clean up block whitelist search logic a bit | ||
5212 | o reverse order of scanning of udevstart to look at class before block | ||
5213 | |||
5214 | Kay Sievers: | ||
5215 | o update udev_volume_id | ||
5216 | |||
5217 | Leann Ogasawara: | ||
5218 | o udevstart performance increase | ||
5219 | |||
5220 | Patrick Mansfield: | ||
5221 | o update udev scsi_id to scsi_id 0.5 | ||
5222 | |||
5223 | |||
5224 | Summary of changes from v026 to v027 | ||
5225 | ============================================ | ||
5226 | |||
5227 | <fork0:users.sf.net>: | ||
5228 | o fix handle leak in udev_lib.c | ||
5229 | |||
5230 | Greg Kroah-Hartman: | ||
5231 | o tweak the gentoo default permission rules as they are wrong for tty and misc devices | ||
5232 | |||
5233 | |||
5234 | Summary of changes from v025 to v026 | ||
5235 | ============================================ | ||
5236 | |||
5237 | Arnd Bergmann: | ||
5238 | o udev rpm fix | ||
5239 | |||
5240 | Greg Kroah-Hartman: | ||
5241 | o add test for ! in partition name | ||
5242 | o 025_bk mark | ||
5243 | o Update to version 117 of klibc (from version 108) | ||
5244 | o add volume_id ignore rule for bk | ||
5245 | o add volume_id support to the udev.spec file | ||
5246 | o remove dbus and selinux stuff from the udev.spec file | ||
5247 | o delete udev_selinux as it doesn't work properly and is the wrong way to do it | ||
5248 | o Deleted the udev_dbus extra as it didn't really work properly and HAL has a real solution now | ||
5249 | o add udev.permissions.slackware file | ||
5250 | o udevstart: close open directories | ||
5251 | |||
5252 | Kay Sievers: | ||
5253 | o fix udevd zombies | ||
5254 | o catchup with recent klibc | ||
5255 | o Re: udevsend fallback | ||
5256 | o udev_volume_id update | ||
5257 | o udev callout for reading filesystem labels | ||
5258 | o udev callout for reading filesystem labels | ||
5259 | o udev default config layout changes | ||
5260 | |||
5261 | Leann Ogasawara: | ||
5262 | o evaluate getenv() return value for udev_config.c | ||
5263 | |||
5264 | Summary of changes from v024 to v025 | ||
5265 | ============================================ | ||
5266 | |||
5267 | <md:linux.it>: | ||
5268 | o devfs.sh-ide-floppy | ||
5269 | |||
5270 | <sjoerd:spring.luon.net>: | ||
5271 | o DEVNODE -> DEVNAME transition fixes | ||
5272 | |||
5273 | Daniel Drake: | ||
5274 | o Update writing udev rules docs | ||
5275 | |||
5276 | Greg Kroah-Hartman: | ||
5277 | o make dev.d call each directory in the directory chain of the device name, instead of just the whole name | ||
5278 | o add devd_test script | ||
5279 | o add more permissions based on SuSE's recommendations | ||
5280 | o added rules for tun and raw devices | ||
5281 | o add udev conf.d file | ||
5282 | o Switch the default config to point to a directory for the rules and permission files | ||
5283 | o update the Red Hat .dev files to work on other distros | ||
5284 | o add dbus.dev, pam_console.dev and selinux.dev files for /etc/dev.d/default/ usage | ||
5285 | o add hints for red hat users from Leann Ogasawara <ogasawara@osdl.org> | ||
5286 | o add scripts to run gcov for udev from Leann Ogasawara <ogasawara@osdl.org> | ||
5287 | o change permissions on udevd test scripts | ||
5288 | o Fix build process for users who have LC_ALL set to a non-english language | ||
5289 | o Added expanded tests to the test framework from Leann Ogasawara <ogasawara@osdl.org> | ||
5290 | o added execelent "writing udev rules" document from Daniel Drake <dan@reactivated.net> | ||
5291 | o added rule to put USB printers in their proper places | ||
5292 | o added rules for CAPI devices | ||
5293 | o added a dev.d alsa script to help people out | ||
5294 | |||
5295 | Kay Sievers: | ||
5296 | o fix test regressions | ||
5297 | o udev_selinux changes | ||
5298 | o udevd test script | ||
5299 | o udev_dbus changes | ||
5300 | o fix devpath for netdev | ||
5301 | |||
5302 | Leann Ogasawara: | ||
5303 | o gcov for udev | ||
5304 | |||
5305 | |||
5306 | Summary of changes from v023 to v024 | ||
5307 | ============================================ | ||
5308 | |||
5309 | <atul.sabharwal:intel.com>: | ||
5310 | o Add README for chassis_id | ||
5311 | o Add chassis_id program to extras directory | ||
5312 | |||
5313 | <chris_friesen:sympatico.ca>: | ||
5314 | o udevd race conditions and performance, assorted cleanups | ||
5315 | |||
5316 | <hare:suse.de>: | ||
5317 | o fix SEGV in libsysfs/dlist.c | ||
5318 | |||
5319 | <maryedie:osdl.org>: | ||
5320 | o add OSDL documentation for persistent naming | ||
5321 | |||
5322 | <md:linux.it>: | ||
5323 | o small ide-devfs.sh fix | ||
5324 | |||
5325 | Greg Kroah-Hartman: | ||
5326 | o remove compiler warning from udevd.c | ||
5327 | o only generate udev.8 on the fly, not all other man pages | ||
5328 | o update bk ignore list some more | ||
5329 | o update bk ignore list | ||
5330 | o switch to generate the man pages during the normal build, not during the install | ||
5331 | o convert udev.8.in to use @udevdir@ macro for make install | ||
5332 | o first step of making man pages dynamically generated | ||
5333 | o add install and uninstall the etc/dev.d/net/hotplug.dev file to the Makefile | ||
5334 | o tweak net_test a bit | ||
5335 | o fix some segfaults when running udevtest for network devices | ||
5336 | o make a net_test test script using udevtest | ||
5337 | o handle the subsytem if provided in udevtest | ||
5338 | o add hotplug.dev script to handle renamed network devices | ||
5339 | o add a bunch of network class devices to the test sysfs tree | ||
5340 | o add udevruler to the bk ignore list | ||
5341 | o update RFC-dev.d docs due to DEVNODE to DEVNAME change | ||
5342 | o clean up chassis_id coding style | ||
5343 | o clean up the OSDL document formatting a bit | ||
5344 | o add netlink rules to devfs and gentoo rules files | ||
5345 | o added USB device rules to rules files | ||
5346 | o clean up the gentoo rules file a bit more, adding dri rules | ||
5347 | o fix up udev.rules to handle oss rules better | ||
5348 | o 023_bk mark | ||
5349 | o fix udev.spec file for where udevtest should be placed | ||
5350 | |||
5351 | Kay Sievers: | ||
5352 | o tweak node unlink handling | ||
5353 | o switch udevd's msg_dump() to #define | ||
5354 | o handle netdev in udevruler | ||
5355 | o man page cleanup | ||
5356 | o put config info in db for netdev | ||
5357 | o increase udevd event timeout | ||
5358 | o udevstart fix | ||
5359 | o put netdev handling and dev.d/ in manpages | ||
5360 | o DEVPATH for netdev | ||
5361 | o netdev - udevdb+dev.d changes | ||
5362 | o udevd race conditions and performance, assorted cleanups - take 2 | ||
5363 | o udevinfo patch | ||
5364 | o dev_d.c file sorting and cleanup | ||
5365 | o apply all_partitions rule to main block device only | ||
5366 | |||
5367 | |||
5368 | Summary of changes from v022 to v023 | ||
5369 | ============================================ | ||
5370 | |||
5371 | Kay Sievers: | ||
5372 | o hmm, handle net devices with udev? | ||
5373 | o correct apply_format() for symlink only rules | ||
5374 | o don't init namedev on remove | ||
5375 | o first stupid try for a rule compose gui | ||
5376 | o replace fgets() with mmap() and introduce udev_lib.[hc] | ||
5377 | o make udevtest a real program :) | ||
5378 | |||
5379 | Daniel E. F. Stekloff: | ||
5380 | o udevinfo patch | ||
5381 | |||
5382 | Greg Kroah-Hartman: | ||
5383 | o create the /etc/dev.d/ directories in 'make install' | ||
5384 | o actually have udev run files ending in .dev in the /etc/dev.d/ directory as documented | ||
5385 | o added RFC-dev.d document detailing how /etc/dev.d/ works | ||
5386 | o fixed up udev.spec to handle selinux stuff properly now | ||
5387 | o remove USE_DBUS and USE_SELINUX flags from the README as they are no longer present | ||
5388 | o remove selinux stuff from the main Makefile | ||
5389 | o move udev_selinux into extras/selinux | ||
5390 | o fix dbus build in the udev.spec file | ||
5391 | o remove dbus stuff from main Makefile | ||
5392 | o move udev_dbus to extras/dbus | ||
5393 | o udev_dbus can now compile properly, but linnking is another story | ||
5394 | o remove udev_dbus.h from Makefile | ||
5395 | o first cut at standalone udev_selinux program | ||
5396 | o remove selinux support from udev core as it's no longer needed | ||
5397 | o first cut at standalone udev_dbus program | ||
5398 | o add get_devnode() helper to udev_lib for udev_dbus program | ||
5399 | o remove dbus code from core udev code as it's no longer needed to be there | ||
5400 | o add /etc/dev.d/ support for udev add and remove events | ||
5401 | o fix build error in namedev.c caused by previous patch | ||
5402 | o 022_bk tag | ||
5403 | o fix 'make spotless' to really do that in klibc | ||
5404 | o add a question/answer about automounting usb devices to the FAQ | ||
5405 | o mark scsi-devfs.sh as executable | ||
5406 | o Increase the name size as requested by Richard Gooch <rgooch@ras.ucalgary.ca> | ||
5407 | o fix udevtest to build properly after the big udev_lib change | ||
5408 | |||
5409 | Olaf Hering: | ||
5410 | o uninitialized variable for mknod and friend | ||
5411 | |||
5412 | Richard Gooch: | ||
5413 | o SCSI logical and physical names for udev | ||
5414 | |||
5415 | Theodore Y. T'so: | ||
5416 | o Trivial man page typo fixes to udev | ||
5417 | |||
5418 | |||
5419 | Summary of changes from v021 to v022 | ||
5420 | ============================================ | ||
5421 | |||
5422 | <ananth:in.ibm.com>: | ||
5423 | o more Libsysfs updates | ||
5424 | o Libsysfs updates | ||
5425 | |||
5426 | <async:cc.gatech.edu>: | ||
5427 | o fix HOWTO-udev_for_dev for udevdir | ||
5428 | |||
5429 | Kay Sievers: | ||
5430 | o udev-test.pl cleanup | ||
5431 | o add dev node test to udev-test.pl | ||
5432 | o add permission tests | ||
5433 | o "symlink only" test | ||
5434 | o callout part selector tweak | ||
5435 | o cleanup callout fork | ||
5436 | o allow to specify node permissions in the rule | ||
5437 | o man page beauty | ||
5438 | o put symlink only rules to the man page | ||
5439 | o rename strn*() macros to strmax | ||
5440 | o conditional remove of trailing sysfs whitespace | ||
5441 | o clarify udevinfo text | ||
5442 | o better fix for NAME="foo-%c{N}" gets a truncated name | ||
5443 | o overall trivial trivial cleanup | ||
5444 | o fix NAME="foo-%c{N}" gets a truncated name | ||
5445 | o cleanup mult field string handling | ||
5446 | |||
5447 | <ken:cgi101.com>: | ||
5448 | o fix a type in docs/libsysfs.txt | ||
5449 | o Added line to udev.permissions.redhat | ||
5450 | o Include more examples in the docs area for gentoo and redhat | ||
5451 | |||
5452 | <md:linux.it>: | ||
5453 | o udevstart fixes | ||
5454 | |||
5455 | Greg Kroah-Hartman: | ||
5456 | o add big major tests to udev-test.pl | ||
5457 | o add a test for a minor over 255 | ||
5458 | o udev-test.pl: print out major:minor and perm test "ok" if is ok | ||
5459 | o make perm and major:minor test errors be reported properly | ||
5460 | o remove extra ; in namedev_parse.c | ||
5461 | o Added multipath-tools 0.1.1 release | ||
5462 | o deleted current extras/multipath directory | ||
5463 | o 021_bk mark | ||
5464 | o fix the build for older versions of gcc | ||
5465 | |||
5466 | Hanna V. Linder: | ||
5467 | o Small fix to remove extra "will" in man page | ||
5468 | |||
5469 | Olaf Hering: | ||
5470 | o make spotless | ||
5471 | o udev* segfaults with new klibc | ||
5472 | |||
5473 | Patrick Mansfield: | ||
5474 | o add tests for NAME="foo-%c{N}" | ||
5475 | |||
5476 | Summary of changes from v020 to v021 | ||
5477 | ============================================ | ||
5478 | |||
5479 | Kay Sievers: | ||
5480 | o install udevinfo in /usr/bin | ||
5481 | o blacklist pcmcia_socket | ||
5482 | |||
5483 | Greg Kroah-Hartman: | ||
5484 | o fix udev.spec to find udevinfo now that it has moved to /usr/bin | ||
5485 | o Fix another problem with Makefile installing initscript | ||
5486 | o fix the Makefile to install the init script into the proper directory | ||
5487 | o make spec file turn off selinux support by default | ||
5488 | |||
5489 | |||
5490 | Summary of changes from v019 to v020 | ||
5491 | ============================================ | ||
5492 | |||
5493 | <christophe.varoqui:free.fr>: | ||
5494 | o multipath update | ||
5495 | |||
5496 | Kay Sievers: | ||
5497 | o man page udevstart | ||
5498 | o cleanup udevstart | ||
5499 | o bugfix for local user | ||
5500 | o unlink bugfix | ||
5501 | o TODO update | ||
5502 | o clarify udevinfo device walk | ||
5503 | o udevinfo symlink reverse query | ||
5504 | o fix stroul endptr use | ||
5505 | o add $local user spport for permissions | ||
5506 | o udev - man page update | ||
5507 | o udev - fix debug info for multiple rule file config | ||
5508 | o udev - kill udevd on install | ||
5509 | o udev - activate formt length attribute | ||
5510 | o udev - safer sprintf() use | ||
5511 | |||
5512 | <md:linux.it>: | ||
5513 | o no error on enoent | ||
5514 | o escape dashes in man pages | ||
5515 | o remove usage of expr in ide-devfs.sh | ||
5516 | |||
5517 | <rml:ximian.com>: | ||
5518 | o automatically install correct initscript | ||
5519 | o update documetation for $local | ||
5520 | |||
5521 | Andrey Borzenkov: | ||
5522 | o Add symlink only rules support | ||
5523 | |||
5524 | Greg Kroah-Hartman: | ||
5525 | o update the TODO list as we already have a devfs config file | ||
5526 | o make start_udev use udevstart binary | ||
5527 | o install udevstart | ||
5528 | o Remove Debian permission files as the Debian maintainer doesn't seem to want to share :( | ||
5529 | o update the Gentoo rules files | ||
5530 | o Add Red Hat rules and permissions files | ||
5531 | o add udevstart to the ignore list | ||
5532 | o add udevstart program based on a old patch from Harald Hoyer <harald@redhat.com> | ||
5533 | o unlink the file before we try to create it | ||
5534 | o Merge greg@bucket:/home/greg/src/udev into kroah.com:/home/greg/src/udev | ||
5535 | |||
5536 | |||
5537 | Summary of changes from v018 to v019 | ||
5538 | ============================================ | ||
5539 | |||
5540 | Kay Sievers: | ||
5541 | o TODO update | ||
5542 | o udev - correct relative symlink | ||
5543 | o udev - safer string handling - part four | ||
5544 | o udev - safer string handling - part three | ||
5545 | o udev - safer string handling - part two | ||
5546 | o udev - man page update | ||
5547 | o udev - safer string handling all over the place | ||
5548 | o manpage update | ||
5549 | o udev - allow all files in a directory as the config | ||
5550 | o udev - simple klibc textual uid/gid handling | ||
5551 | |||
5552 | Andrey Borzenkov: | ||
5553 | o do not remove real .udev.tdb during RPM build | ||
5554 | |||
5555 | Greg Kroah-Hartman: | ||
5556 | o add new TODO item about local user permissions | ||
5557 | o Add initial SELinux support for udev | ||
5558 | o fix build for very old versions of make | ||
5559 | o remove limit of the number of args passed to PROGRAM | ||
5560 | o force udev to include the internal version of libsysfs and never the external one | ||
5561 | o fix up libsysfs header file usage to fix bug reports from users that have sysfsutils installed already | ||
5562 | o remove udevtest on 'make clean' | ||
5563 | o remove udevd priority TODO item, as it's not needed at all | ||
5564 | |||
5565 | Patrick Mansfield: | ||
5566 | o update udev scsi_id to scsi_id 0.4 | ||
5567 | |||
5568 | |||
5569 | Summary of changes from v017 to v018 | ||
5570 | ============================================ | ||
5571 | |||
5572 | <ext.devoteam.varoqui:sncf.fr>: | ||
5573 | o [PATCH] symlink dm-[0-9]* rule | ||
5574 | o update extras/multipath | ||
5575 | |||
5576 | <john-hotplug:fjellstad.org>: | ||
5577 | o init.d debian patch | ||
5578 | |||
5579 | Kay Sievers: | ||
5580 | o udev - TODO update | ||
5581 | o udev - add %s{filename} to man page | ||
5582 | o udev - udevd/udevsend man page | ||
5583 | o udev - switch callout part selector to {attribute} | ||
5584 | o udev - switch SYSFS_file to SYSFS{file} | ||
5585 | o udev - create all partitions of blockdevice | ||
5586 | o allow SYSFS{file} | ||
5587 | o Adding '%s' format specifier to NAME and SYMLINK | ||
5588 | |||
5589 | Greg Kroah-Hartman: | ||
5590 | o added some scsi_id files to the bk ignore file | ||
5591 | o added scsi_id and some more documentation to the udev.spec file | ||
5592 | o update udev.rules.gentoo with new config file format | ||
5593 | o Update the Gentoo udev.rules and udev.permissions files | ||
5594 | o Create a udev.rules.examples file to hold odd udev.rules | ||
5595 | o add udevd priority issue to the TODO list | ||
5596 | o more HOWTO cleanups | ||
5597 | o add HOWTO detailing how to use udev to manage /dev | ||
5598 | o mv libsysfs/libsysfs.h to libsysfs/sysfs/libsysfs.h to make it easier to use | ||
5599 | o add start_udev init script | ||
5600 | o add support for UDEV_NO_SLEEP env variable so Gentoo people will be happy | ||
5601 | o start up udevd ourselves in the init script to give it some good priorities | ||
5602 | o update the red hat init script to handle nodes that are not present | ||
5603 | o add a "old style" SYSFS_attribute test to udev-test.pl | ||
5604 | o Have udevsend report more info in debug mode | ||
5605 | o Have udevd report it's version in debug mode | ||
5606 | o fix up bug created for udevtest in previous partition creation patch | ||
5607 | o update the udev.spec to add udevtest and make some more Red Hat suggested changes | ||
5608 | o add ability to install udevtest to Makefile | ||
5609 | o 017_bk mark | ||
5610 | o Add another test to udev-test.pl and fix a bug when only running 1 test | ||
5611 | o Fix bug where we did not use the "converted" kernel name if we had no rule | ||
5612 | |||
5613 | Patrick Mansfield: | ||
5614 | o udev use new libsysfs header file location | ||
5615 | o udev add some ID tests | ||
5616 | |||
5617 | |||
5618 | Summary of changes from v016 to v017 | ||
5619 | ============================================ | ||
5620 | |||
5621 | <azarah:nosferatu.za.org>: | ||
5622 | o make logging a config option | ||
5623 | |||
5624 | <christophe.varoqui:free.fr>: | ||
5625 | o more udev-016/extras/multipath | ||
5626 | o more udev-016/extras/multipath | ||
5627 | o update extras/multipath | ||
5628 | |||
5629 | Kay Sievers: | ||
5630 | o udev - keep private data out of the database? | ||
5631 | o better credential patch | ||
5632 | o udevd - client access authorization | ||
5633 | o compile udevd with klibc | ||
5634 | o udev - fix "ignore method" | ||
5635 | o udev - fix cdrom symlink rule | ||
5636 | o convert udevsend/udevd to DGRAM and single-threaded | ||
5637 | o udevd - kill the lockfile | ||
5638 | o udevd - fix socket path length | ||
5639 | o udevd - switch socket path to abstract namespace | ||
5640 | o udevd - allow to bypass sequence number | ||
5641 | o include used function | ||
5642 | |||
5643 | Greg Kroah-Hartman: | ||
5644 | o add udev_log to the documentation | ||
5645 | o fix offsetof() define in klibc | ||
5646 | o add some .spec file changes from Red Hat | ||
5647 | o update the init.d udev script based on a patch from Red Hat | ||
5648 | o remove the .udev.tdb when installing or uninstalling to be safe | ||
5649 | o remove the database at startup | ||
5650 | o fix bug in permission handling | ||
5651 | o update klibc to version .107 | ||
5652 | o update the bitkeeper ignore file list | ||
5653 | o add udevtest program to build | ||
5654 | o fix problem where usb devices can be either the main device or the interface | ||
5655 | o more logging.h cleanups to be a bit more flexible | ||
5656 | o stop using mode_t as different libcs define it in different ways :( | ||
5657 | o remove some more KLIBC fixups that are no longer needed | ||
5658 | o let udev-test.pl run an individual test if you ask it to | ||
5659 | o Handle the '!' character that some block devices have | ||
5660 | o add a block device with a ! in the name, and a test for this | ||
5661 | o fix up 'make release' to use bk to build the export tree | ||
5662 | o fix log option code so that it actually works for all udev programs | ||
5663 | o finish syncing up with klibc | ||
5664 | o sync with latest version of klibc (0.107) | ||
5665 | o fix up Makefile dependancies for udev_version.h | ||
5666 | |||
5667 | Patrick Mansfield: | ||
5668 | o udev add wild card compare for ID | ||
5669 | o udev kill extra bus_id compares in match_id | ||
5670 | |||
5671 | |||
5672 | Summary of changes from v015 to v016 | ||
5673 | ============================================ | ||
5674 | |||
5675 | <elkropac:students.zcu.cz>: | ||
5676 | o get_dev_number() in extras/ide-devfs.sh | ||
5677 | |||
5678 | <rrm3:rrm3.org>: | ||
5679 | o FAQ udev.rules.devfs | ||
5680 | |||
5681 | Greg Kroah-Hartman: | ||
5682 | o add udevd and udevsend to the spec file | ||
5683 | o make /etc/hotplug.d/default/udev.hotplug symlink point to udevsend now | ||
5684 | o add KERNEL_DIR option so that the distros will be happy | ||
5685 | o make udevsend binary even smaller | ||
5686 | o udevsend now almost compiles with klibc, struct sockaddr_un is only problem now | ||
5687 | o fix up logging code so that it can be built without it being enabled | ||
5688 | o rework the logging code so that each program logs with the proper name in the syslog | ||
5689 | o remove logging.c as it's no longer needed | ||
5690 | o kill the last examples that contained the %D option | ||
5691 | o remove a __KLIBC__ tests in libsysfs, as klibc now supports getpagesize() | ||
5692 | o udevd - remove stupid locking error I wrote | ||
5693 | o update to klibc version 0.101, fixing the stdin bug | ||
5694 | o fix Makefile typo for USE_LSB install | ||
5695 | o allow dbus code to actually build again | ||
5696 | |||
5697 | Kay Sievers: | ||
5698 | o let udevsend build with klibc | ||
5699 | o udevd - config cleanup | ||
5700 | o udevd - cleanup and better timeout handling | ||
5701 | o fix possible buffer overflow | ||
5702 | o udevd - next round of fixes | ||
5703 | o udevinfo - missing options for man page | ||
5704 | o udev - trivial style cleanup | ||
5705 | |||
5706 | |||
5707 | Summary of changes from v014 to v015 | ||
5708 | ============================================ | ||
5709 | |||
5710 | <mbuesch:freenet.de>: | ||
5711 | o LFS init script update | ||
5712 | |||
5713 | Greg Kroah-Hartman: | ||
5714 | o update klibc to version 0.98 | ||
5715 | o clean up udevinfo on 'make clean' | ||
5716 | o add udevinfo man page to spec file | ||
5717 | o remove command line documentation from udev man page | ||
5718 | o create initial version of udevinfo man page | ||
5719 | o added URL to spec file | ||
5720 | o add udevinfo to udev.spec file | ||
5721 | o add udevinfo to install target of Makefile | ||
5722 | o rip out command line code from udev, now that we have udevinfo | ||
5723 | o udevinfo doesn't need to declare main_envp | ||
5724 | o move get_pair to udev_config.c because udevinfo doesn't need all of namedev.o | ||
5725 | o more makefile cleanups | ||
5726 | o move udevinfo into the main build and clean up the main Makefile a bit | ||
5727 | o clean up compiler warnings if building using klibc | ||
5728 | o make udevd only have one instance running at a time | ||
5729 | o new testd.block script for debugging | ||
5730 | o udevsnd : clean up message creation logic a bit | ||
5731 | o make bk ignore udevd and udevsend binaries | ||
5732 | o whitespace cleanups | ||
5733 | o remove TODO item about BUS value, as it is now done | ||
5734 | o add support for figuring out which device on the sysfs "chain" the rule applies to | ||
5735 | |||
5736 | Kay Sievers: | ||
5737 | o udevinfo - now a real program :) | ||
5738 | o udevd - cleanup and better timeout handling | ||
5739 | o udev - next round of udev event order daemon | ||
5740 | o fix udevd exec | ||
5741 | o udev - udevinfo with device chain walk | ||
5742 | o spilt udev into pieces | ||
5743 | |||
5744 | |||
5745 | Summary of changes from v013 to v014 | ||
5746 | ============================================ | ||
5747 | |||
5748 | <ananthmg:rediffmail.com>: | ||
5749 | o libsysfs update for refresh + namedev.c changes | ||
5750 | |||
5751 | <christophe.varoqui:free.fr>: | ||
5752 | o udev-013/extras/multipath update | ||
5753 | |||
5754 | <flamingice:sourmilk.net>: | ||
5755 | o minor patch for devfs rules | ||
5756 | |||
5757 | Kay Sievers: | ||
5758 | o udev - program to query all device attributes to build a rule | ||
5759 | o set default owner/group in db - update | ||
5760 | o udev - reverse user query options | ||
5761 | o udev - kill %D from udev-test.pl | ||
5762 | o add udev logging to info log | ||
5763 | o udev - mention format string escape char in man page | ||
5764 | |||
5765 | Greg Kroah-Hartman: | ||
5766 | o misc code cleanups | ||
5767 | o fixup logging.h to handle different logging options properly | ||
5768 | o clean up the logging patch a bit to make the option more like the other options | ||
5769 | o remove the %D modifier as it is not longer needed | ||
5770 | o remove unneeded keyboard rule | ||
5771 | o add usb_host and pci_bus to the class blacklist | ||
5772 | o added input device rules to udev.rules and udev.rules.devfs | ||
5773 | o 013_bk mark | ||
5774 | |||
5775 | Hanna V. Linder: | ||
5776 | o set default owner/group in db | ||
5777 | o small cut n paste error fix | ||
5778 | |||
5779 | Patrick Mansfield: | ||
5780 | o update udev scsi_id to scsi_id 0.3 | ||
5781 | |||
5782 | |||
5783 | Summary of changes from v012 to v013 | ||
5784 | ============================================ | ||
5785 | |||
5786 | <eike-hotplug:sf-tec.de>: | ||
5787 | o LSB init script and other stuff | ||
5788 | |||
5789 | <elkropac:students.zcu.cz>: | ||
5790 | o fix udev directory for Debian init script | ||
5791 | |||
5792 | <tiggi:infa.abo.fi>: | ||
5793 | o udev 012 old gcc fixup | ||
5794 | |||
5795 | Christophe Saout: | ||
5796 | o add IGNORE rule type | ||
5797 | o small cleanup | ||
5798 | |||
5799 | Greg Kroah-Hartman: | ||
5800 | o update TODO with some new, small items | ||
5801 | o Cset exclude: greg@kroah.com|ChangeSet|20040113010256|48515 | ||
5802 | o update the README in a few places | ||
5803 | o fix -d typo in the manpage update | ||
5804 | o Fix stupid gcc "optimization" of 1 character printk() calls.... Ick | ||
5805 | o oops, forgot to fix up the PROGRAM result from ID to RESULT in the config files | ||
5806 | o Add alsa device rules and a few other devfs rules | ||
5807 | o fix a few stale comments in namedev.c | ||
5808 | o convert the default rules files to the new format | ||
5809 | o convert the test shell scripts to the config file format | ||
5810 | o add bus test for usb-serial bus | ||
5811 | o Add some helpful messages if the user uses the older config file format | ||
5812 | o added dri rule to the default config file | ||
5813 | o added init.d udev script for debian | ||
5814 | o add a script that tests the IGNORE rule | ||
5815 | o add silly script that names cdrom drives based on the cd in them | ||
5816 | o add cdrom rule for ide cdrom | ||
5817 | o replace list_for_each with list_for_each_entry, saving a few lines of code | ||
5818 | o add a blacklist of class devices we do not want to look at | ||
5819 | |||
5820 | Kay Sievers: | ||
5821 | o fix klibc with printf() and gcc | ||
5822 | o udev - small script optimization | ||
5823 | o udev - introduce format escape char | ||
5824 | o udev - more CALLOUT is PROGRAM now | ||
5825 | o udev - CALLOUT is PROGRAM now | ||
5826 | o update documentation for new config file format | ||
5827 | o more advanced user query options | ||
5828 | o udev - simple debug tweak | ||
5829 | o udev - drop all methods :) | ||
5830 | o udev - advanced user query options | ||
5831 | o udev - Makefile error | ||
5832 | o udev - make exec_callout() reusable | ||
5833 | o udev - exec status fix for klibc | ||
5834 | o fix Silly udev script | ||
5835 | |||
5836 | |||
5837 | Summary of changes from v011 to v012 | ||
5838 | ============================================ | ||
5839 | |||
5840 | <azarah:nosferatu.za.org>: | ||
5841 | o make symlink work properly if there is already a file in its place | ||
5842 | o Fix udev gcc-2.95.4 compat | ||
5843 | |||
5844 | <christophe.varoqui:free.fr>: | ||
5845 | o extras multipath update | ||
5846 | o extras multipath update | ||
5847 | |||
5848 | Kay Sievers: | ||
5849 | o mention user callable udev + options in man page | ||
5850 | o make udev user callable to query the database | ||
5851 | o depend on all .h files | ||
5852 | o cleanup namedev_parse debug text | ||
5853 | o extend exec_program[] | ||
5854 | o ide-devfs.sh update | ||
5855 | o fix for apply_format() | ||
5856 | o check for empty symlink string | ||
5857 | o 'ide' missing in bus_files[] | ||
5858 | o small trivial cleanup of latest changes | ||
5859 | |||
5860 | <mbuesch:freenet.de>: | ||
5861 | o introduce signal handler | ||
5862 | |||
5863 | <rml:ximian.com>: | ||
5864 | o udev spec file update | ||
5865 | |||
5866 | Greg Kroah-Hartman: | ||
5867 | o minor grammer fixes for the udev_vs_devfs document | ||
5868 | o move the dbus config file to etc/dbus-1/system.d/ | ||
5869 | o move the config files to etc/udev to clean up main directory a bit | ||
5870 | o add Gentoo versions of the rules and permissions files | ||
5871 | o if using glibc, link dynamically, as no one like 500Kb udev binaries | ||
5872 | o minor change to udev_vs_devfs document | ||
5873 | o added udev vs devfs supid document to the tree | ||
5874 | o move the signal handling registration to after we have initialized enough stuff | ||
5875 | o make ide-devfs.sh executable in the tree | ||
5876 | o udev.permissions.debian - forgot the dm nodes | ||
5877 | o update the udev.permissions.debian file with new entries | ||
5878 | o added udev.init script for the Linux From Scratch project | ||
5879 | |||
5880 | |||
5881 | |||
5882 | Summary of changes from v010 to v011 | ||
5883 | ============================================ | ||
5884 | |||
5885 | <mbuesch:freenet.de>: | ||
5886 | o proper cleanup on udevdb_init() failure | ||
5887 | |||
5888 | <mh:nadir.org>: | ||
5889 | o patch udev 009-010 rpm spec file | ||
5890 | |||
5891 | <svetljo:gmx.de>: | ||
5892 | o fix udev sed Makefile usage | ||
5893 | |||
5894 | Greg Kroah-Hartman: | ||
5895 | o add documentation about the BUS key being optional for the LABEL rule | ||
5896 | o add tests for LABEL rule with a device that has no bus | ||
5897 | o Don't require the BUS value for the LABEL rule | ||
5898 | o If a LABEL rule has a BUS id, then we must check to see if the device is on a bus | ||
5899 | o add documentation about the BUS key being optional for the CALLOUT rule | ||
5900 | o If a CALLOUT rule has a BUS id, then we must check to see if the device is on a bus | ||
5901 | o Don't require the BUS value for the CALLOUT rule | ||
5902 | o add test for callout rule with a device that has no bus | ||
5903 | o 010_bk stamp | ||
5904 | o added different build options to the rpm udev.spec file | ||
5905 | o add pci to the bus_files list | ||
5906 | o check for empty line a bit better in the parser | ||
5907 | o more init script cleanups, the stop target now calls udev to cleanup instead of just removing the whole /udev directory | ||
5908 | o make udev init script run udev in the background to let startup go much faster | ||
5909 | o fix long delay for all devices in namedev | ||
5910 | |||
5911 | |||
5912 | Summary of changes from v009 to v010 | ||
5913 | ============================================ | ||
5914 | |||
5915 | <ananth:in.ibm.com>: | ||
5916 | o change pgsize | ||
5917 | |||
5918 | <christophe.varoqui:free.fr>: | ||
5919 | o extras multipath update | ||
5920 | o extras multipath update | ||
5921 | o extras multipath update | ||
5922 | o extras multipath update | ||
5923 | |||
5924 | Kay Sievers: | ||
5925 | o fix udev-test.pl | ||
5926 | o small cleanup udev-remove.c | ||
5927 | o experimental CALLOUT script for devfs ide node creation with cd, disc, part | ||
5928 | o add any valid device | ||
5929 | o introduce format char 'k' for kernel-name | ||
5930 | o trivial make fixes | ||
5931 | o don't overwrite old config on install | ||
5932 | o udev-remove.c cleanups | ||
5933 | o bug in udev-remove.c | ||
5934 | o trivial cleanup parser changes | ||
5935 | |||
5936 | <roman.kagan:itep.ru>: | ||
5937 | o fix comment and whitespace handling in config files | ||
5938 | |||
5939 | Adam Kropelin: | ||
5940 | o Allow build with empty EXTRAS | ||
5941 | |||
5942 | Daniel E. F. Stekloff: | ||
5943 | o libsysfs 0.4.0 patch | ||
5944 | o fix scsi_id segfault with udev-009 | ||
5945 | o add libsysfs docs | ||
5946 | |||
5947 | David T. Hollis: | ||
5948 | o mark config files as such in the rpm spec file | ||
5949 | |||
5950 | Greg Kroah-Hartman: | ||
5951 | o fix complier warning in namedev.c | ||
5952 | o add documentation for the new '%k' modifier (kernel name replacement) | ||
5953 | o add documentation about the multiple sysfs values that are now allowed for the LABEL rule | ||
5954 | o add tests for multi-file LABEL rules | ||
5955 | o add ability to have up to 5 SYSFS_ file/value pairs for the LABEL rule | ||
5956 | o Just live with a sleep(1) in namedev for now until libsysfs is fixed up | ||
5957 | o try to wait until the proper device file shows up in sysfs | ||
5958 | o remove unneeded TODO and FIXME entry | ||
5959 | o clean up the stand-alone tests to work properly on other people's machines | ||
5960 | o add tests to catch whitespace and comment config file parsing errors | ||
5961 | |||
5962 | |||
5963 | Summary of changes from v008 to v009 | ||
5964 | ============================================ | ||
5965 | |||
5966 | <christophe.varoqui:free.fr>: | ||
5967 | o more extras/multipath changes | ||
5968 | o and more extras/multipath updates | ||
5969 | o more extras/multipath updates | ||
5970 | o yet more extras/multipath | ||
5971 | o more extras/multipath updates | ||
5972 | o extras/multipath update | ||
5973 | |||
5974 | <david:fubar.dk>: | ||
5975 | o D-BUS patch for udev-008 | ||
5976 | |||
5977 | <eike-hotplug:sf-tec.de>: | ||
5978 | o add init.d/udev to "make install" | ||
5979 | o add init.d/udev to the spec file | ||
5980 | |||
5981 | Kay Sievers: | ||
5982 | o don't rely on field order in namedev_parse | ||
5983 | o get part of callout return string | ||
5984 | o remove '\n' from end of callout return | ||
5985 | o man-page mention multiple symlinks | ||
5986 | o allow multiple symlinks | ||
5987 | o cleanup man & remove symlink comment | ||
5988 | o experimental (very simple) SYMLINK creation | ||
5989 | o man page beauty | ||
5990 | o pattern match for label method | ||
5991 | o a bug in linefeed removal | ||
5992 | |||
5993 | <rml:ximian.com>: | ||
5994 | o remove udev from runlevels on uninstall | ||
5995 | o install initscript in udev rpm | ||
5996 | |||
5997 | Daniel E. F. Stekloff: | ||
5998 | o pre-libsysfs-0.4.0 patch | ||
5999 | |||
6000 | Greg Kroah-Hartman: | ||
6001 | o signal fixes due to klibc update | ||
6002 | o sync klibc with release 0.95 | ||
6003 | o add mol permissions to the debian permissions file | ||
6004 | o update the FAQ with info about bad modprobe events from the devfs scheme | ||
6005 | o some cleanups due to the need for LABEL rules to use "SYSFS_" now | ||
6006 | o Add restart target to the etc/init.d/udev script | ||
6007 | o tweak the config file generation portion of the Makefile a bit | ||
6008 | o change devfs disk name rule from 'disk' to 'disc' | ||
6009 | o add vc support to udev.rules.devfs | ||
6010 | o added a devfs udev config file from Marco d'Itri <md@Linux.IT> | ||
6011 | o set default mode to 0600 to be safer | ||
6012 | o Makefile tweaks for the DBUS build | ||
6013 | o update the FAQ due to the latest devfs mess on lkml and also due to symlinks now working | ||
6014 | o document the different Makefile config options that we have | ||
6015 | o change USE_DBUS to DBUS in Makefile, and disable it by default as it's still to hard to build on all systems | ||
6016 | o fix formatting of udev_dbus.c to use tabs. Also get it to build properly now | ||
6017 | o move all of the DBUS logic into one file and remove all of the #ifdef crud from the main code | ||
6018 | |||
6019 | Olaf Hering: | ||
6020 | o dump latest klibc into the udev build tree | ||
6021 | o use udevdir in udev.conf | ||
6022 | |||
6023 | Patrick Mansfield: | ||
6024 | o better allow builds of extras programs under udev | ||
6025 | o update udev extras/scsi_id to version 0.2 | ||
6026 | |||
6027 | |||
6028 | Summary of changes from v007 to v008 | ||
6029 | ============================================ | ||
6030 | |||
6031 | <azarah:nosferatu.za.org>: | ||
6032 | o more config file parsing robustness | ||
6033 | |||
6034 | <christophe.varoqui:free.fr>: | ||
6035 | o udev-007/extras/multipath update | ||
6036 | |||
6037 | Arnd Bergmann: | ||
6038 | o Build failure - missing linux/limits.h include? | ||
6039 | o Add format modifier for devfs like naming | ||
6040 | o klibc makefile fixes | ||
6041 | |||
6042 | Daniel E. F. Stekloff: | ||
6043 | o another patch for path problem | ||
6044 | o quick fix for libsysfs bus | ||
6045 | o libsysfs changes for sysfsutils 0.3.0 | ||
6046 | |||
6047 | Greg Kroah-Hartman: | ||
6048 | o fix up some duplicated function compiler warnings in libsysfs | ||
6049 | o fix some compiler warnings in the tdb code | ||
6050 | o Added Kay's name to the man page | ||
6051 | o update the wildcard documentation in the man page to show the new styles supported | ||
6052 | o fix permission handling logic | ||
6053 | o enable default_mode ability to actually build | ||
6054 | o add support for the default_mode variable, as it is documented | ||
6055 | o show permissions and groups in the label_test | ||
6056 | o remove some items off of the TODO list, as they are now done | ||
6057 | o fix up the tests to work without all of the environ variables | ||
6058 | o get rid of the majority of the debug environment variables | ||
6059 | o Update the man page to show the new config file, it's format, and how to use it | ||
6060 | o fix up the tests to support the rules file name change | ||
6061 | o add support for a main udev config file, udev.conf | ||
6062 | o turn debugging messages off by default | ||
6063 | o split out the namedev config parsing logic to namedev_parse.c | ||
6064 | o rename namedev's get_attr() to be main namedev_name_device() as that's what it really is | ||
6065 | o add devfs like tty rules as an example in the default config file | ||
6066 | o operate on the rules in the order they are in the config file (within the rule type) instead of operating on them backwards. | ||
6067 | o Cset exclude: dsteklof@us.ibm.com|ChangeSet|20031126173159|56255 | ||
6068 | o add test for checking the BUS value | ||
6069 | o fix problem where we were not looking at the BUS value | ||
6070 | o add scsi and pci bus links in the test sysfs tree | ||
6071 | o add test and documentation for new %D devfs format modifier | ||
6072 | o changed the default location of the database to /udev/.udev.tdb to be LSB compliant | ||
6073 | o get rid of functions in klibc_fixups that are now in klibc | ||
6074 | o sync up with the 0.84 version of klibc | ||
6075 | o fix udev init.d script to handle all class devices in sysfs | ||
6076 | o fix the test.block and test.tty scripts due to their moveing. Also add a test.all script | ||
6077 | o 007_bk version change to Makefile | ||
6078 | |||
6079 | Kay Sievers: | ||
6080 | o pattern matching for namedev | ||
6081 | o catch replace device by wildcard | ||
6082 | o udev.8 tweak numeric id text | ||
6083 | o udev-test.pl add subdir test | ||
6084 | o namedev.c strcat tweak | ||
6085 | o overall whitespace + debug text conditioning | ||
6086 | o udev-test.pl - tweaks | ||
6087 | |||
6088 | Martin Hicks: | ||
6089 | o Add -nodefaultlibs while compiling against klibc | ||
6090 | |||
6091 | Olaf Hering: | ||
6092 | o ARCH detection for ppc | ||
6093 | |||
6094 | Patrick Mansfield: | ||
6095 | o fix udev parallel builds with klibc | ||
6096 | |||
6097 | |||
6098 | Summary of changes from v006 to v007 | ||
6099 | ============================================ | ||
6100 | |||
6101 | <md:linux.it>: | ||
6102 | o fix segfault in parsing bad udev.permissions file | ||
6103 | |||
6104 | Greg Kroah-Hartman: | ||
6105 | o update default config file with a CALLOUT rule, and more documentation | ||
6106 | o updated the man page with the latest format specifier changes | ||
6107 | o added ability to put format specifiers in the CALLOUT program string | ||
6108 | o tweak udev-test.pl to report '0' errors if that's what happened | ||
6109 | o only build klibc_fixups.c if we are actually using klibc | ||
6110 | o add support for string group and string user names in udev.permissions | ||
6111 | o add getgrnam and getpwnam to klibc_fixups files | ||
6112 | o remove Makefile.klibc | ||
6113 | o add udev-test perl script from Kay Sievers <kay.sievers@vrfy.org> which blows away my puny shell scripts | ||
6114 | o added debian's version of udev.permissions | ||
6115 | o change to 006_bk version | ||
6116 | |||
6117 | Kay Sievers: | ||
6118 | o format char for CALLOUT output | ||
6119 | o more namedev whitespace cleanups | ||
6120 | o support arguments in callout exec | ||
6121 | o namedev.c - change order of fields in CALLOUT | ||
6122 | o namedev.c whitespace + debug text cleanup | ||
6123 | o man page with udev.permissions wildcard | ||
6124 | |||
6125 | Olaf Hering: | ||
6126 | o static klibc udev does not link against crt0.o | ||
6127 | |||
6128 | Summary of changes from v005 to v006 | ||
6129 | ============================================ | ||
6130 | |||
6131 | <chris_friesen:sympatico.ca>: | ||
6132 | o faster test scripts | ||
6133 | |||
6134 | Arnd Bergmann: | ||
6135 | o more robust config file parsing in namedev.c | ||
6136 | o add bus id modifier | ||
6137 | |||
6138 | Daniel E. F. Stekloff: | ||
6139 | o patch for libsysfs sysfs directory handling | ||
6140 | |||
6141 | Greg Kroah-Hartman: | ||
6142 | o add another line to udev.permissions in the proper format | ||
6143 | o tweak replace_test | ||
6144 | o fix permissions to work properly now | ||
6145 | o add real udev.permissions file to test directory | ||
6146 | o fix namedev.c to build with older version of gcc | ||
6147 | o add dumb test for all of the different modifiers | ||
6148 | o update the TODO list with more items that people can easily do | ||
6149 | o move the test.block and test.tty scripts to the test/ directory | ||
6150 | o add remove actions to the test scripts | ||
6151 | o turn DEBUG_PARSER off by default | ||
6152 | o add some documentation for the %b modifier to the default config file | ||
6153 | o fix make install rule for when the udev symlink is already there | ||
6154 | o change release target in makefile | ||
6155 | o change debug level on printf values for now | ||
6156 | o updated demo config file | ||
6157 | o add some documentation of the modifiers to the default config file | ||
6158 | o add demo config file | ||
6159 | o updated bk ignore list for klibc generated files | ||
6160 | o add printf option to label test to verify it works | ||
6161 | o fix up printf-like functionality due to previous changes | ||
6162 | o get the major/minor number before we name the device | ||
6163 | o add scsi_id "extra" program from Patrick Mansfield <patmans@us.ibm.com> | ||
6164 | o Add multipath "extra" program from Christophe Varoqui, <christophe.varoqui@free.fr> | ||
6165 | o trailing whitespace cleanups | ||
6166 | o splig LABEL and NUMBER into separate functions | ||
6167 | o add TOPO regression test | ||
6168 | o move TOPOLOGY rule to it's own function | ||
6169 | o fix bug where NUMBER and TOPOLOGY would not work for partitions | ||
6170 | o clean up the way we find the sysdevice for a block device for namedev | ||
6171 | o updated label test script (tests for partitions now.) | ||
6172 | o split REPLACE and CALLOUT into separate functions | ||
6173 | o add debug line for REPLACE call | ||
6174 | o add replace test | ||
6175 | o add more sysfs test tree files | ||
6176 | o change UDEV_SYSFS_PATH environment variable due to libsysfs change | ||
6177 | o fix bug in klibc's isspace function | ||
6178 | o fix udev-add.c to build properly with older versions of gcc | ||
6179 | o add prototype for ftruncate to klibc | ||
6180 | o Remove a few items from the TODO list that are already done | ||
6181 | o version number to 005_bk | ||
6182 | o pull some klibc stuff into the make Makefile to try to stay in sync | ||
6183 | o klibc build fixes | ||
6184 | |||
6185 | Kay Sievers: | ||
6186 | o apply permissions.conf support for wildcard and default name | ||
6187 | o man page with included placeholder list | ||
6188 | o implement printf-like placeholder support for NAME | ||
6189 | o more manpage tweaks | ||
6190 | o add support for subdirs | ||
6191 | o add uid/gid to nodes | ||
6192 | |||
6193 | Olaf Hering: | ||
6194 | o DESTDIR for udev | ||
6195 | |||
6196 | Paul Mundt: | ||
6197 | o Fixup path for kernel includes when building with klibc | ||
6198 | |||
6199 | Robert Love: | ||
6200 | o udev init script | ||
6201 | |||
6202 | |||
6203 | Summary of changes from v004 to v005 | ||
6204 | ============================================ | ||
6205 | |||
6206 | <kay:vrfy.org>: | ||
6207 | o namedev.c comments + debug patch | ||
6208 | o man page update | ||
6209 | |||
6210 | Greg Kroah-Hartman: | ||
6211 | o ignore the klibc/linux symlink | ||
6212 | o add klibc linux symlink info to the README | ||
6213 | o get 'make release' to work properly again | ||
6214 | o added README info for how to build using klibc | ||
6215 | o turn off debugging if we are building with klibc | ||
6216 | o turn off debugging in namedev | ||
6217 | o added vsyslog support to klibc | ||
6218 | o add ftruncate to klibc | ||
6219 | o klibc specific tweaks | ||
6220 | o libsysfs does not need mntent.h in it's header file | ||
6221 | o udev build tweaks to tdb's spinlock code | ||
6222 | o klibc makefile changes | ||
6223 | o build tdb and libsysfs from the same makefile as udev | ||
6224 | o udev-add build cleanups for other libc versions | ||
6225 | o tweak tdb to build within udev better | ||
6226 | o make libsysfs spit debug messages to the same place as the rest of udev | ||
6227 | o make libsysfs build cleanly | ||
6228 | o updated bk ignore list | ||
6229 | o added klibc version 0.82 (cvs tree) to the udev tree | ||
6230 | o makefile fix for now | ||
6231 | o Merge greg@bucket:/home/greg/src/udev into kroah.com:/home/greg/src/udev | ||
6232 | o hm, makefile bug with so many files... will fix later | ||
6233 | o regression tests starting to be added | ||
6234 | o fix LABEL bug for device files (not class files.) | ||
6235 | o more warning flags to the build | ||
6236 | o got rid of struct device_attr | ||
6237 | o rename namedev.permissions and namedev.config to udev.permissions and udev.config | ||
6238 | o fix dbg line in namedev.c | ||
6239 | o more overrides of config info with env variables if in test mode | ||
6240 | o Fix bug causing udev to sleep forever waiting for dev file to show up | ||
6241 | o change version to 004_bk | ||
6242 | o make config files, sysfs root, and udev root configurable from config variables | ||
6243 | |||
6244 | Robert Love: | ||
6245 | o udev: sleep_for_dev() bits | ||
6246 | o udev: another canidate for static | ||
6247 | |||
6248 | |||
6249 | Summary of changes from v003 to v004 | ||
6250 | ============================================ | ||
6251 | |||
6252 | Daniel E. F. Stekloff: | ||
6253 | o new version of libsysfs patch | ||
6254 | |||
6255 | Greg Kroah-Hartman: | ||
6256 | o 004 release | ||
6257 | o major database cleanups | ||
6258 | o Changed test.block and test.tty to take ACTION from the command line | ||
6259 | o don't sleep if 'dev' file is already present on device add | ||
6260 | o fix comment about how the "dev" file is made up | ||
6261 | o more database work. Now we only store the info we really need right now | ||
6262 | o add BUS= bug to TODO list so it will not get forgotten | ||
6263 | o spec file changes | ||
6264 | o test.block changes | ||
6265 | o ok, rpm likes the "_" character instead of "-" better | ||
6266 | o change the version to 003-bk to keep things sane with people using the bk tree | ||
6267 | o got "remove of named devices" working | ||
6268 | o fix segfaults when dealing with partitions | ||
6269 | |||
6270 | Kay Sievers: | ||
6271 | o man file update | ||
6272 | o man page update | ||
6273 | |||
6274 | Robert Love: | ||
6275 | o udev: mode should be mode_t | ||
6276 | o udev: trivial trivialities | ||
6277 | o udev: cool test scripts again | ||
6278 | o udev spec file symlink support | ||
6279 | o udev: cool test scripts | ||
6280 | o udev spec file bits | ||
6281 | |||
6282 | |||
6283 | Summary of changes from v0.2 to v003 | ||
6284 | ============================================ | ||
6285 | |||
6286 | Daniel E. F. Stekloff: | ||
6287 | o udevdb patch | ||
6288 | o udevdb prototype | ||
6289 | |||
6290 | Greg Kroah-Hartman: | ||
6291 | o update the spec file for the new version and install process | ||
6292 | o fix makefile release rule to not drop tdb.h file | ||
6293 | o Add FAQ for udev | ||
6294 | o removed AUTHORS and INSTALL files as they were pretty pointless | ||
6295 | o copyright updates | ||
6296 | o Add AUTHORS and INSTALL files | ||
6297 | o TODO updates | ||
6298 | o Updatd the README | ||
6299 | o updated the TODO list | ||
6300 | o add udev man page (basically just a place holder for now.) | ||
6301 | o added uninstall support | ||
6302 | o added install target for makefile so people don't have to do it by hand anymore | ||
6303 | o add version to debug log on startup | ||
6304 | o tell the user what mknod() we are trying to do | ||
6305 | o add dbg_parse() to cut down on parse file debugging statements | ||
6306 | o put config files and database in /etc/udev by default | ||
6307 | o add ols 2003 udev paper to docs/ | ||
6308 | o clean up some debugging stuff in namedev.c | ||
6309 | o do not build the tdb binary programs, only the objects | ||
6310 | o merge tdb into the build process | ||
6311 | o Added tdb code from latest cvs version in the samba tree | ||
6312 | o added my name to the .spec file | ||
6313 | o minor cleanups | ||
6314 | o cleanup the mknod code a bit | ||
6315 | o remove mknod callout | ||
6316 | o handle new major:minor format of dev files that showed up in 2.6.0-test2-bk3 or so | ||
6317 | o oops, everything was getting created as 000 mode, try to fix this up, but fail... | ||
6318 | o more test stuff | ||
6319 | |||
6320 | Olaf Hering: | ||
6321 | o print udev pid | ||
6322 | |||
6323 | Patrick Mansfield: | ||
6324 | o add callout config type to udev | ||
6325 | |||
6326 | Paul Mundt: | ||
6327 | o Fix TDB cross compilation | ||
6328 | o udev spec file | ||
6329 | o udev/libsysfs cross compile fixes | ||
6330 | |||
6331 | |||
6332 | Summary of changes from v0.1 to v0.2 | ||
6333 | ============================================ | ||
6334 | |||
6335 | Greg Kroah-Hartman: | ||
6336 | o more test stuff | ||
6337 | o removed unneeded stuff from udev.h | ||
6338 | o added 0.2 change log info | ||
6339 | o start working on label support, and fix some segfaults for block devices | ||
6340 | o test config file changes | ||
6341 | o add NUMBER support (basically same logic as TOPOLOGY, perhaps we should | ||
6342 | merge this...) | ||
6343 | o added topology support | ||
6344 | o got REPLACE to work properly | ||
6345 | o make struct config_device contain a struct device_attr instead of | ||
6346 | duplicating the mess | ||
6347 | o block test | ||
6348 | o split the tests up into different files | ||
6349 | o split udev main logic into udev-add and udev-remove | ||
6350 | o Clean up the namedev interface a bit, making the code smaller | ||
6351 | o bk: update ignore list | ||
6352 | o update the tests to handle block devices too | ||
6353 | o add initial libsysfs support | ||
6354 | o added libsysfs to the build | ||
6355 | o added libsysfs code from sysutils-0.1.1-071803 release | ||
6356 | o namedev config files are fully parsed | ||
6357 | o more permission tests | ||
6358 | o make log_message spit out warnings so I don't have to spend forever | ||
6359 | chasing down stupid bugs that aren't there... | ||
6360 | o added klibc makefile | ||
6361 | o Initial namedev parsing of config files | ||
6362 | o sleep for 2 seconds to give the kernel a chance to actually create the | ||
6363 | files we need | ||
6364 | o pick a better default UDEV_ROOT | ||
6365 | o fix up the test to actually work | ||
6366 | o added more documentation in README and TODO files | ||
6367 | |||
6368 | |||
6369 | Summary of changes up to v0.1 | ||
6370 | ============================================ | ||
6371 | |||
6372 | Greg Kroah-Hartman: | ||
6373 | o added more documentation in README and TODO files | ||
6374 | o updated the documentation | ||
6375 | o cleaned up the makefile a bit | ||
6376 | o remove now works! | ||
6377 | o restructure code to be able to actually get remove_node() to work | ||
6378 | o Creating nodes actually works | ||
6379 | o added stupid test script for debugging | ||
6380 | o added initial documentation and gpl license | ||
6381 | o enabled debugging | ||
6382 | o updated ignore list | ||
6383 | o added initial files | ||
6384 | o fixed up config | ||
6385 | o Initial repository create | ||
6386 | o BitKeeper file /home/greg/src/udev/udev/ChangeSet | ||
6387 | |||
diff --git a/src/udev/INSTALL b/src/udev/INSTALL new file mode 100644 index 000000000..0a34e77df --- /dev/null +++ b/src/udev/INSTALL | |||
@@ -0,0 +1,44 @@ | |||
1 | The options used usually look like: | ||
2 | %configure \ | ||
3 | --prefix=/usr \ | ||
4 | --sysconfdir=/etc \ | ||
5 | --bindir=/usr/bin \ | ||
6 | --libdir=/usr/lib64 \ | ||
7 | --libexecdir=/usr/lib \ | ||
8 | --with-systemdsystemunitdir=/usr/lib/systemd/system \ | ||
9 | --with-selinux | ||
10 | |||
11 | The options used in a RPM spec file look like: | ||
12 | %configure \ | ||
13 | --prefix=%{_prefix} \ | ||
14 | --sysconfdir=%{_sysconfdir} \ | ||
15 | --bindir=%{_bindir} \ | ||
16 | --libdir=%{_libdir} \ | ||
17 | --libexecdir=%{_prefix}/lib \ | ||
18 | --with-systemdsystemunitdir=%{_prefix}/lib/systemd/system \ | ||
19 | --with-selinux | ||
20 | |||
21 | The options to install udev in the rootfs instead of /usr, | ||
22 | and udevadm in /sbin: | ||
23 | --prefix=%{_prefix} \ | ||
24 | --with-rootprefix= \ | ||
25 | --sysconfdir=%{_sysconfdir} \ | ||
26 | --bindir=/sbin \ | ||
27 | --libdir=%{_libdir} \ | ||
28 | --with-rootlibdir=/lib64 \ | ||
29 | --libexecdir=/lib \ | ||
30 | --with-systemdsystemunitdir=/lib/systemd/system \ | ||
31 | --with-selinux | ||
32 | |||
33 | Some tools expect udevadm in 'sbin'. A symlink to udevadm in 'bin' | ||
34 | needs to be manually created if needed. | ||
35 | |||
36 | The defined location for scripts and binaries which are called | ||
37 | from rules is (/usr)/lib/udev/ on all systems and architectures. Any | ||
38 | other location will break other packages, who rightfully expect | ||
39 | the (/usr)/lib/udev/ directory, to install their rule helper and udev | ||
40 | rule files. | ||
41 | |||
42 | Default udev rules and persistent device naming rules may be required | ||
43 | by other software that depends on the data udev collects from the | ||
44 | devices. | ||
diff --git a/src/udev/Makefile.am b/src/udev/Makefile.am new file mode 100644 index 000000000..1c7f86b08 --- /dev/null +++ b/src/udev/Makefile.am | |||
@@ -0,0 +1,712 @@ | |||
1 | # Copyright (C) 2008-2012 Kay Sievers <kay.sievers@vrfy.org> | ||
2 | # Copyright (C) 2009 Diego Elio 'Flameeyes' Pettenò <flameeyes@gmail.com> | ||
3 | |||
4 | SUBDIRS = . | ||
5 | |||
6 | ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS} | ||
7 | |||
8 | AM_MAKEFLAGS = --no-print-directory | ||
9 | |||
10 | LIBUDEV_CURRENT=13 | ||
11 | LIBUDEV_REVISION=2 | ||
12 | LIBUDEV_AGE=13 | ||
13 | |||
14 | LIBGUDEV_CURRENT=1 | ||
15 | LIBGUDEV_REVISION=1 | ||
16 | LIBGUDEV_AGE=1 | ||
17 | |||
18 | AM_CPPFLAGS = \ | ||
19 | -include $(top_builddir)/config.h \ | ||
20 | -I$(top_srcdir)/src \ | ||
21 | -DSYSCONFDIR=\""$(sysconfdir)"\" \ | ||
22 | -DPKGLIBEXECDIR=\""$(libexecdir)/udev"\" | ||
23 | |||
24 | AM_CFLAGS = \ | ||
25 | ${my_CFLAGS} \ | ||
26 | -fvisibility=hidden \ | ||
27 | -ffunction-sections \ | ||
28 | -fdata-sections | ||
29 | |||
30 | AM_LDFLAGS = \ | ||
31 | -Wl,--gc-sections \ | ||
32 | -Wl,--as-needed | ||
33 | |||
34 | DISTCHECK_CONFIGURE_FLAGS = \ | ||
35 | --enable-debug \ | ||
36 | --enable-rule_generator \ | ||
37 | --enable-floppy \ | ||
38 | --with-selinux \ | ||
39 | --enable-gtk-doc \ | ||
40 | --with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir) | ||
41 | |||
42 | BUILT_SOURCES = | ||
43 | EXTRA_DIST = | ||
44 | CLEANFILES = | ||
45 | INSTALL_EXEC_HOOKS = | ||
46 | INSTALL_DATA_HOOKS = | ||
47 | UNINSTALL_EXEC_HOOKS = | ||
48 | DISTCHECK_HOOKS = | ||
49 | DISTCLEAN_LOCAL_HOOKS = | ||
50 | |||
51 | udevhomedir = $(libexecdir)/udev | ||
52 | udevhome_SCRIPTS = | ||
53 | dist_udevhome_SCRIPTS = | ||
54 | dist_udevhome_DATA = | ||
55 | dist_man_MANS = | ||
56 | |||
57 | SED_PROCESS = \ | ||
58 | $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(SED) \ | ||
59 | -e 's,@VERSION\@,$(VERSION),g' \ | ||
60 | -e 's,@prefix\@,$(prefix),g' \ | ||
61 | -e 's,@rootprefix\@,$(rootprefix),g' \ | ||
62 | -e 's,@exec_prefix\@,$(exec_prefix),g' \ | ||
63 | -e 's,@libdir\@,$(libdir),g' \ | ||
64 | -e 's,@includedir\@,$(includedir),g' \ | ||
65 | -e 's,@bindir\@,$(bindir),g' \ | ||
66 | -e 's,@pkglibexecdir\@,$(libexecdir)/udev,g' \ | ||
67 | < $< > $@ || rm $@ | ||
68 | |||
69 | %.pc: %.pc.in Makefile | ||
70 | $(SED_PROCESS) | ||
71 | |||
72 | %.rules: %.rules.in Makefile | ||
73 | $(SED_PROCESS) | ||
74 | |||
75 | %.service: %.service.in Makefile | ||
76 | $(SED_PROCESS) | ||
77 | |||
78 | %.sh: %.sh.in Makefile | ||
79 | $(SED_PROCESS) | ||
80 | $(AM_V_GEN)chmod +x $@ | ||
81 | |||
82 | %.pl: %.pl.in Makefile | ||
83 | $(SED_PROCESS) | ||
84 | $(AM_V_GEN)chmod +x $@ | ||
85 | |||
86 | # ------------------------------------------------------------------------------ | ||
87 | SUBDIRS += src/docs | ||
88 | |||
89 | include_HEADERS = src/libudev.h | ||
90 | lib_LTLIBRARIES = libudev.la | ||
91 | noinst_LTLIBRARIES = libudev-private.la | ||
92 | |||
93 | libudev_la_SOURCES =\ | ||
94 | src/libudev-private.h \ | ||
95 | src/libudev.c \ | ||
96 | src/libudev-list.c \ | ||
97 | src/libudev-util.c \ | ||
98 | src/libudev-device.c \ | ||
99 | src/libudev-enumerate.c \ | ||
100 | src/libudev-monitor.c \ | ||
101 | src/libudev-queue.c | ||
102 | |||
103 | libudev_la_LDFLAGS = \ | ||
104 | $(AM_LDFLAGS) \ | ||
105 | -version-info $(LIBUDEV_CURRENT):$(LIBUDEV_REVISION):$(LIBUDEV_AGE) | ||
106 | |||
107 | libudev_private_la_SOURCES =\ | ||
108 | $(libudev_la_SOURCES) \ | ||
109 | src/libudev-util-private.c \ | ||
110 | src/libudev-device-private.c \ | ||
111 | src/libudev-queue-private.c | ||
112 | |||
113 | if WITH_SELINUX | ||
114 | libudev_private_la_SOURCES += src/libudev-selinux-private.c | ||
115 | libudev_private_la_LIBADD = $(SELINUX_LIBS) | ||
116 | endif | ||
117 | |||
118 | pkgconfigdir = $(libdir)/pkgconfig | ||
119 | pkgconfig_DATA = src/libudev.pc | ||
120 | EXTRA_DIST += src/libudev.pc.in | ||
121 | CLEANFILES += src/libudev.pc | ||
122 | |||
123 | EXTRA_DIST += src/COPYING | ||
124 | # move lib from $(libdir) to $(rootlib_execdir) and update devel link, if needed | ||
125 | libudev-install-move-hook: | ||
126 | if test "$(libdir)" != "$(rootlib_execdir)"; then \ | ||
127 | mkdir -p $(DESTDIR)$(rootlib_execdir) && \ | ||
128 | so_img_name=$$(readlink $(DESTDIR)$(libdir)/libudev.so) && \ | ||
129 | so_img_rel_target_prefix=$$(echo $(libdir) | sed 's,\(^/\|\)[^/][^/]*,..,g') && \ | ||
130 | ln -sf $$so_img_rel_target_prefix$(rootlib_execdir)/$$so_img_name $(DESTDIR)$(libdir)/libudev.so && \ | ||
131 | mv $(DESTDIR)$(libdir)/libudev.so.* $(DESTDIR)$(rootlib_execdir); \ | ||
132 | fi | ||
133 | |||
134 | libudev-uninstall-move-hook: | ||
135 | rm -f $(DESTDIR)$(rootlib_execdir)/libudev.so* | ||
136 | |||
137 | INSTALL_EXEC_HOOKS += libudev-install-move-hook | ||
138 | UNINSTALL_EXEC_HOOKS += libudev-uninstall-move-hook | ||
139 | |||
140 | # ------------------------------------------------------------------------------ | ||
141 | udev-confdirs: | ||
142 | -mkdir -p $(DESTDIR)$(sysconfdir)/udev/rules.d | ||
143 | -mkdir -p $(DESTDIR)$(libexecdir)/udev/devices | ||
144 | |||
145 | INSTALL_DATA_HOOKS += udev-confdirs | ||
146 | |||
147 | udevrulesdir = $(libexecdir)/udev/rules.d | ||
148 | dist_udevrules_DATA = \ | ||
149 | rules/42-usb-hid-pm.rules \ | ||
150 | rules/50-udev-default.rules \ | ||
151 | rules/60-persistent-storage-tape.rules \ | ||
152 | rules/60-persistent-serial.rules \ | ||
153 | rules/60-persistent-input.rules \ | ||
154 | rules/60-persistent-alsa.rules \ | ||
155 | rules/60-persistent-storage.rules \ | ||
156 | rules/75-net-description.rules \ | ||
157 | rules/75-tty-description.rules \ | ||
158 | rules/78-sound-card.rules \ | ||
159 | rules/80-drivers.rules \ | ||
160 | rules/95-udev-late.rules | ||
161 | |||
162 | udevconfdir = $(sysconfdir)/udev | ||
163 | dist_udevconf_DATA = src/udev.conf | ||
164 | |||
165 | sharepkgconfigdir = $(datadir)/pkgconfig | ||
166 | sharepkgconfig_DATA = src/udev.pc | ||
167 | EXTRA_DIST += src/udev.pc.in | ||
168 | CLEANFILES += src/udev.pc | ||
169 | |||
170 | if WITH_SYSTEMD | ||
171 | dist_systemdsystemunit_DATA = \ | ||
172 | src/udev-control.socket \ | ||
173 | src/udev-kernel.socket | ||
174 | |||
175 | systemdsystemunit_DATA = \ | ||
176 | src/udev.service \ | ||
177 | src/udev-trigger.service \ | ||
178 | src/udev-settle.service | ||
179 | |||
180 | EXTRA_DIST += \ | ||
181 | src/udev.service.in \ | ||
182 | src/udev-trigger.service.in \ | ||
183 | src/udev-settle.service.in | ||
184 | |||
185 | CLEANFILES += \ | ||
186 | src/udev.service \ | ||
187 | src/udev-trigger.service \ | ||
188 | src/udev-settle.service | ||
189 | |||
190 | systemd-install-hook: | ||
191 | mkdir -p $(DESTDIR)$(systemdsystemunitdir)/sockets.target.wants | ||
192 | ln -sf ../udev-control.socket $(DESTDIR)$(systemdsystemunitdir)/sockets.target.wants/udev-control.socket | ||
193 | ln -sf ../udev-kernel.socket $(DESTDIR)$(systemdsystemunitdir)/sockets.target.wants/udev-kernel.socket | ||
194 | mkdir -p $(DESTDIR)$(systemdsystemunitdir)/basic.target.wants | ||
195 | ln -sf ../udev.service $(DESTDIR)$(systemdsystemunitdir)/basic.target.wants/udev.service | ||
196 | ln -sf ../udev-trigger.service $(DESTDIR)$(systemdsystemunitdir)/basic.target.wants/udev-trigger.service | ||
197 | |||
198 | INSTALL_DATA_HOOKS += systemd-install-hook | ||
199 | endif | ||
200 | |||
201 | bin_PROGRAMS = \ | ||
202 | udevadm | ||
203 | |||
204 | pkglibexec_PROGRAMS = \ | ||
205 | udevd | ||
206 | |||
207 | udev_common_sources = \ | ||
208 | src/udev.h \ | ||
209 | src/udev-event.c \ | ||
210 | src/udev-watch.c \ | ||
211 | src/udev-node.c \ | ||
212 | src/udev-rules.c \ | ||
213 | src/udev-ctrl.c \ | ||
214 | src/udev-builtin.c \ | ||
215 | src/udev-builtin-blkid.c \ | ||
216 | src/udev-builtin-firmware.c \ | ||
217 | src/udev-builtin-hwdb.c \ | ||
218 | src/udev-builtin-input_id.c \ | ||
219 | src/udev-builtin-kmod.c \ | ||
220 | src/udev-builtin-path_id.c \ | ||
221 | src/udev-builtin-usb_id.c | ||
222 | |||
223 | udev_common_CFLAGS = \ | ||
224 | $(BLKID_CFLAGS) \ | ||
225 | $(KMOD_CFLAGS) | ||
226 | |||
227 | udev_common_LDADD = \ | ||
228 | libudev-private.la \ | ||
229 | $(BLKID_LIBS) \ | ||
230 | $(KMOD_LIBS) | ||
231 | |||
232 | udev_common_CPPFLAGS = \ | ||
233 | $(AM_CPPFLAGS) \ | ||
234 | -DFIRMWARE_PATH="$(FIRMWARE_PATH)" \ | ||
235 | -DUSB_DATABASE=\"$(USB_DATABASE)\" -DPCI_DATABASE=\"$(PCI_DATABASE)\" | ||
236 | |||
237 | udevd_SOURCES = \ | ||
238 | $(udev_common_sources) \ | ||
239 | src/udevd.c \ | ||
240 | src/sd-daemon.h \ | ||
241 | src/sd-daemon.c | ||
242 | udevd_CFLAGS = $(udev_common_CFLAGS) | ||
243 | udevd_LDADD = $(udev_common_LDADD) | ||
244 | udevd_CPPFLAGS = $(udev_common_CPPFLAGS) | ||
245 | |||
246 | udevadm_SOURCES = \ | ||
247 | $(udev_common_sources) \ | ||
248 | src/udevadm.c \ | ||
249 | src/udevadm-info.c \ | ||
250 | src/udevadm-control.c \ | ||
251 | src/udevadm-monitor.c \ | ||
252 | src/udevadm-settle.c \ | ||
253 | src/udevadm-trigger.c \ | ||
254 | src/udevadm-test.c \ | ||
255 | src/udevadm-test-builtin.c | ||
256 | udevadm_CFLAGS = $(udev_common_CFLAGS) | ||
257 | udevadm_LDADD = $(udev_common_LDADD) | ||
258 | udevadm_CPPFLAGS = $(udev_common_CPPFLAGS) | ||
259 | |||
260 | # ------------------------------------------------------------------------------ | ||
261 | if ENABLE_MANPAGES | ||
262 | dist_man_MANS += \ | ||
263 | src/udev.7 \ | ||
264 | src/udevadm.8 \ | ||
265 | src/udevd.8 | ||
266 | endif | ||
267 | |||
268 | EXTRA_DIST += \ | ||
269 | src/udev.xml \ | ||
270 | src/udevadm.xml \ | ||
271 | src/udevd.xml | ||
272 | |||
273 | if HAVE_XSLTPROC | ||
274 | dist_noinst_DATA = \ | ||
275 | src/udev.html \ | ||
276 | src/udevadm.html \ | ||
277 | src/udevd.html | ||
278 | |||
279 | src/%.7 src/%.8 : src/%.xml | ||
280 | $(AM_V_GEN)$(XSLTPROC) -o $@ -nonet http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $< | ||
281 | |||
282 | src/%.html : src/%.xml | ||
283 | $(AM_V_GEN)$(XSLTPROC) -o $@ -nonet http://docbook.sourceforge.net/release/xsl/current/xhtml-1_1/docbook.xsl $< | ||
284 | endif | ||
285 | |||
286 | # ------------------------------------------------------------------------------ | ||
287 | TESTS = \ | ||
288 | test/udev-test.pl \ | ||
289 | test/rules-test.sh | ||
290 | |||
291 | check_PROGRAMS = \ | ||
292 | test-libudev \ | ||
293 | test-udev | ||
294 | |||
295 | test_libudev_SOURCES = src/test-libudev.c | ||
296 | test_libudev_LDADD = libudev.la | ||
297 | |||
298 | test_udev_SOURCES = \ | ||
299 | $(udev_common_sources) \ | ||
300 | src/test-udev.c | ||
301 | test_udev_CFLAGS = $(udev_common_CFLAGS) | ||
302 | test_udev_LDADD = $(udev_common_LDADD) | ||
303 | test_udev_CPPFLAGS = $(udev_common_CPPFLAGS) | ||
304 | test_udev_DEPENDENCIES = test/sys | ||
305 | |||
306 | # packed sysfs test tree | ||
307 | test/sys: | ||
308 | $(AM_V_GEN)mkdir -p test && tar -C test/ -xJf $(top_srcdir)/test/sys.tar.xz | ||
309 | |||
310 | test-sys-distclean: | ||
311 | -rm -rf test/sys | ||
312 | DISTCLEAN_LOCAL_HOOKS += test-sys-distclean | ||
313 | |||
314 | EXTRA_DIST += test/sys.tar.xz | ||
315 | |||
316 | # ------------------------------------------------------------------------------ | ||
317 | ata_id_SOURCES = src/ata_id/ata_id.c | ||
318 | ata_id_LDADD = libudev-private.la | ||
319 | pkglibexec_PROGRAMS += ata_id | ||
320 | |||
321 | # ------------------------------------------------------------------------------ | ||
322 | cdrom_id_SOURCES = src/cdrom_id/cdrom_id.c | ||
323 | cdrom_id_LDADD = libudev-private.la | ||
324 | pkglibexec_PROGRAMS += cdrom_id | ||
325 | dist_udevrules_DATA += src/cdrom_id/60-cdrom_id.rules | ||
326 | |||
327 | # ------------------------------------------------------------------------------ | ||
328 | collect_SOURCES = src/collect/collect.c | ||
329 | collect_LDADD = libudev-private.la | ||
330 | pkglibexec_PROGRAMS += collect | ||
331 | |||
332 | # ------------------------------------------------------------------------------ | ||
333 | scsi_id_SOURCES =\ | ||
334 | src/scsi_id/scsi_id.c \ | ||
335 | src/scsi_id/scsi_serial.c \ | ||
336 | src/scsi_id/scsi.h \ | ||
337 | src/scsi_id/scsi_id.h | ||
338 | scsi_id_LDADD = libudev-private.la | ||
339 | pkglibexec_PROGRAMS += scsi_id | ||
340 | dist_man_MANS += src/scsi_id/scsi_id.8 | ||
341 | EXTRA_DIST += src/scsi_id/README | ||
342 | |||
343 | # ------------------------------------------------------------------------------ | ||
344 | v4l_id_SOURCES = src/v4l_id/v4l_id.c | ||
345 | v4l_id_LDADD = libudev-private.la | ||
346 | pkglibexec_PROGRAMS += v4l_id | ||
347 | dist_udevrules_DATA += src/v4l_id/60-persistent-v4l.rules | ||
348 | |||
349 | # ------------------------------------------------------------------------------ | ||
350 | accelerometer_SOURCES = src/accelerometer/accelerometer.c | ||
351 | accelerometer_LDADD = libudev-private.la -lm | ||
352 | pkglibexec_PROGRAMS += accelerometer | ||
353 | dist_udevrules_DATA += src/accelerometer/61-accelerometer.rules | ||
354 | |||
355 | # ------------------------------------------------------------------------------ | ||
356 | if ENABLE_GUDEV | ||
357 | SUBDIRS += src/gudev/docs | ||
358 | |||
359 | libgudev_includedir=$(includedir)/gudev-1.0/gudev | ||
360 | libgudev_include_HEADERS = \ | ||
361 | src/gudev/gudev.h \ | ||
362 | src/gudev/gudevenums.h \ | ||
363 | src/gudev/gudevenumtypes.h \ | ||
364 | src/gudev/gudevtypes.h \ | ||
365 | src/gudev/gudevclient.h \ | ||
366 | src/gudev/gudevdevice.h \ | ||
367 | src/gudev/gudevenumerator.h | ||
368 | |||
369 | lib_LTLIBRARIES += libgudev-1.0.la | ||
370 | |||
371 | pkgconfig_DATA += src/gudev/gudev-1.0.pc | ||
372 | EXTRA_DIST += src/gudev/gudev-1.0.pc.in | ||
373 | CLEANFILES += src/gudev/gudev-1.0.pc | ||
374 | |||
375 | libgudev_1_0_la_SOURCES = \ | ||
376 | src/gudev/gudevenums.h \ | ||
377 | src/gudev/gudevenumtypes.h \ | ||
378 | src/gudev/gudevenumtypes.h\ | ||
379 | src/gudev/gudevtypes.h \ | ||
380 | src/gudev/gudevclient.h \ | ||
381 | src/gudev/gudevclient.c \ | ||
382 | src/gudev/gudevdevice.h \ | ||
383 | src/gudev/gudevdevice.c \ | ||
384 | src/gudev/gudevenumerator.h \ | ||
385 | src/gudev/gudevenumerator.c \ | ||
386 | src/gudev/gudevprivate.h | ||
387 | |||
388 | nodist_libgudev_1_0_la_SOURCES = \ | ||
389 | src/gudev/gudevmarshal.h \ | ||
390 | src/gudev/gudevmarshal.c \ | ||
391 | src/gudev/gudevenumtypes.h \ | ||
392 | src/gudev/gudevenumtypes.c | ||
393 | BUILT_SOURCES += $(nodist_libgudev_1_0_la_SOURCES) | ||
394 | |||
395 | libgudev_1_0_la_CPPFLAGS = \ | ||
396 | $(AM_CPPFLAGS) \ | ||
397 | -I$(top_builddir)/src\ | ||
398 | -I$(top_srcdir)/src\ | ||
399 | -I$(top_builddir)/src/gudev \ | ||
400 | -I$(top_srcdir)/src/gudev \ | ||
401 | -D_POSIX_PTHREAD_SEMANTICS -D_REENTRANT \ | ||
402 | -D_GUDEV_COMPILATION \ | ||
403 | -DG_LOG_DOMAIN=\"GUdev\" | ||
404 | |||
405 | libgudev_1_0_la_CFLAGS = \ | ||
406 | -fvisibility=default \ | ||
407 | $(GLIB_CFLAGS) | ||
408 | |||
409 | libgudev_1_0_la_LIBADD = libudev.la $(GLIB_LIBS) | ||
410 | |||
411 | libgudev_1_0_la_LDFLAGS = \ | ||
412 | -version-info $(LIBGUDEV_CURRENT):$(LIBGUDEV_REVISION):$(LIBGUDEV_AGE) \ | ||
413 | -export-dynamic -no-undefined \ | ||
414 | -export-symbols-regex '^g_udev_.*' | ||
415 | |||
416 | EXTRA_DIST += \ | ||
417 | src/gudev/COPYING \ | ||
418 | src/gudev/gudevmarshal.list \ | ||
419 | src/gudev/gudevenumtypes.h.template \ | ||
420 | src/gudev/gudevenumtypes.c.template \ | ||
421 | src/gudev/gjs-example.js \ | ||
422 | src/gudev/seed-example-enum.js \ | ||
423 | src/gudev/seed-example.js | ||
424 | |||
425 | src/gudev/gudevmarshal.h: src/gudev/gudevmarshal.list | ||
426 | $(AM_V_GEN)glib-genmarshal $< --prefix=g_udev_marshal --header > $@ | ||
427 | |||
428 | src/gudev/gudevmarshal.c: src/gudev/gudevmarshal.list | ||
429 | $(AM_V_GEN)echo "#include \"gudevmarshal.h\"" > $@ && \ | ||
430 | glib-genmarshal $< --prefix=g_udev_marshal --body >> $@ | ||
431 | |||
432 | src/gudev/gudevenumtypes.h: src/gudev/gudevenumtypes.h.template src/gudev/gudevenums.h | ||
433 | $(AM_V_GEN)glib-mkenums --template $^ > \ | ||
434 | $@.tmp && mv $@.tmp $@ | ||
435 | |||
436 | src/gudev/gudevenumtypes.c: src/gudev/gudevenumtypes.c.template src/gudev/gudevenums.h | ||
437 | $(AM_V_GEN)glib-mkenums --template $^ > \ | ||
438 | $@.tmp && mv $@.tmp $@ | ||
439 | |||
440 | if ENABLE_INTROSPECTION | ||
441 | src/gudev/GUdev-1.0.gir: libgudev-1.0.la $(G_IR_SCANNER) | ||
442 | $(AM_V_GEN)$(G_IR_SCANNER) -v \ | ||
443 | --warn-all \ | ||
444 | --namespace GUdev \ | ||
445 | --nsversion=1.0 \ | ||
446 | --include=GObject-2.0 \ | ||
447 | --library=gudev-1.0 \ | ||
448 | --library-path=$(top_builddir)/src \ | ||
449 | --library-path=$(top_builddir)/src/gudev \ | ||
450 | --output $@ \ | ||
451 | --pkg=glib-2.0 \ | ||
452 | --pkg=gobject-2.0 \ | ||
453 | --pkg-export=gudev-1.0 \ | ||
454 | --c-include=gudev/gudev.h \ | ||
455 | -I$(top_srcdir)/src/\ | ||
456 | -I$(top_builddir)/src/\ | ||
457 | -D_GUDEV_COMPILATION \ | ||
458 | -D_GUDEV_WORK_AROUND_DEV_T_BUG \ | ||
459 | $(top_srcdir)/src/gudev/gudev.h \ | ||
460 | $(top_srcdir)/src/gudev/gudevtypes.h \ | ||
461 | $(top_srcdir)/src/gudev/gudevenums.h \ | ||
462 | $(or $(wildcard $(top_builddir)/src/gudev/gudevenumtypes.h),$(top_srcdir)/src/gudev/gudevenumtypes.h) \ | ||
463 | $(top_srcdir)/src/gudev/gudevclient.h \ | ||
464 | $(top_srcdir)/src/gudev/gudevdevice.h \ | ||
465 | $(top_srcdir)/src/gudev/gudevenumerator.h \ | ||
466 | $(top_srcdir)/src/gudev/gudevclient.c \ | ||
467 | $(top_srcdir)/src/gudev/gudevdevice.c \ | ||
468 | $(top_srcdir)/src/gudev/gudevenumerator.c | ||
469 | |||
470 | src/gudev/GUdev-1.0.typelib: src/gudev/GUdev-1.0.gir $(G_IR_COMPILER) | ||
471 | $(AM_V_GEN)g-ir-compiler $< -o $@ | ||
472 | |||
473 | girdir = $(GIRDIR) | ||
474 | gir_DATA = src/gudev/GUdev-1.0.gir | ||
475 | |||
476 | typelibsdir = $(GIRTYPELIBDIR) | ||
477 | typelibs_DATA = src/gudev/GUdev-1.0.typelib | ||
478 | |||
479 | CLEANFILES += $(gir_DATA) $(typelibs_DATA) | ||
480 | endif # ENABLE_INTROSPECTION | ||
481 | |||
482 | # move lib from $(libdir) to $(rootlib_execdir) and update devel link, if needed | ||
483 | libgudev-install-move-hook: | ||
484 | if test "$(libdir)" != "$(rootlib_execdir)"; then \ | ||
485 | mkdir -p $(DESTDIR)$(rootlib_execdir) && \ | ||
486 | so_img_name=$$(readlink $(DESTDIR)$(libdir)/libgudev-1.0.so) && \ | ||
487 | so_img_rel_target_prefix=$$(echo $(libdir) | sed 's,\(^/\|\)[^/][^/]*,..,g') && \ | ||
488 | ln -sf $$so_img_rel_target_prefix$(rootlib_execdir)/$$so_img_name $(DESTDIR)$(libdir)/libgudev-1.0.so && \ | ||
489 | mv $(DESTDIR)$(libdir)/libgudev-1.0.so.* $(DESTDIR)$(rootlib_execdir); \ | ||
490 | fi | ||
491 | |||
492 | libgudev-uninstall-move-hook: | ||
493 | rm -f $(DESTDIR)$(rootlib_execdir)/libgudev-1.0.so* | ||
494 | |||
495 | INSTALL_EXEC_HOOKS += libgudev-install-move-hook | ||
496 | UNINSTALL_EXEC_HOOKS += libgudev-uninstall-move-hook | ||
497 | endif | ||
498 | |||
499 | # ------------------------------------------------------------------------------ | ||
500 | if ENABLE_KEYMAP | ||
501 | keymap_SOURCES = src/keymap/keymap.c | ||
502 | keymap_CPPFLAGS = $(AM_CPPFLAGS) -I src/keymap | ||
503 | nodist_keymap_SOURCES = \ | ||
504 | src/keymap/keys-from-name.h \ | ||
505 | src/keymap/keys-to-name.h | ||
506 | BUILT_SOURCES += $(nodist_keymap_SOURCES) | ||
507 | |||
508 | pkglibexec_PROGRAMS += keymap | ||
509 | dist_doc_DATA = src/keymap/README.keymap.txt | ||
510 | |||
511 | dist_udevrules_DATA += \ | ||
512 | src/keymap/95-keymap.rules \ | ||
513 | src/keymap/95-keyboard-force-release.rules | ||
514 | |||
515 | dist_udevhome_SCRIPTS += src/keymap/findkeyboards | ||
516 | udevhome_SCRIPTS += src/keymap/keyboard-force-release.sh | ||
517 | |||
518 | EXTRA_DIST += \ | ||
519 | src/keymap/check-keymaps.sh \ | ||
520 | src/keymap/keyboard-force-release.sh.in | ||
521 | |||
522 | CLEANFILES += \ | ||
523 | src/keymap/keys.txt \ | ||
524 | src/keymap/keys-from-name.gperf \ | ||
525 | src/keymap/keyboard-force-release.sh | ||
526 | |||
527 | udevkeymapdir = $(libexecdir)/udev/keymaps | ||
528 | dist_udevkeymap_DATA = \ | ||
529 | src/keymap/keymaps/acer \ | ||
530 | src/keymap/keymaps/acer-aspire_5720 \ | ||
531 | src/keymap/keymaps/acer-aspire_8930 \ | ||
532 | src/keymap/keymaps/acer-aspire_5920g \ | ||
533 | src/keymap/keymaps/acer-aspire_6920 \ | ||
534 | src/keymap/keymaps/acer-travelmate_c300 \ | ||
535 | src/keymap/keymaps/asus \ | ||
536 | src/keymap/keymaps/compaq-e_evo \ | ||
537 | src/keymap/keymaps/dell \ | ||
538 | src/keymap/keymaps/dell-latitude-xt2 \ | ||
539 | src/keymap/keymaps/everex-xt5000 \ | ||
540 | src/keymap/keymaps/fujitsu-amilo_li_2732 \ | ||
541 | src/keymap/keymaps/fujitsu-amilo_pa_2548 \ | ||
542 | src/keymap/keymaps/fujitsu-amilo_pro_edition_v3505 \ | ||
543 | src/keymap/keymaps/fujitsu-amilo_pro_v3205 \ | ||
544 | src/keymap/keymaps/fujitsu-amilo_si_1520 \ | ||
545 | src/keymap/keymaps/fujitsu-esprimo_mobile_v5 \ | ||
546 | src/keymap/keymaps/fujitsu-esprimo_mobile_v6 \ | ||
547 | src/keymap/keymaps/genius-slimstar-320 \ | ||
548 | src/keymap/keymaps/hewlett-packard \ | ||
549 | src/keymap/keymaps/hewlett-packard-2510p_2530p \ | ||
550 | src/keymap/keymaps/hewlett-packard-compaq_elitebook \ | ||
551 | src/keymap/keymaps/hewlett-packard-pavilion \ | ||
552 | src/keymap/keymaps/hewlett-packard-presario-2100 \ | ||
553 | src/keymap/keymaps/hewlett-packard-tablet \ | ||
554 | src/keymap/keymaps/hewlett-packard-tx2 \ | ||
555 | src/keymap/keymaps/ibm-thinkpad-usb-keyboard-trackpoint \ | ||
556 | src/keymap/keymaps/inventec-symphony_6.0_7.0 \ | ||
557 | src/keymap/keymaps/lenovo-3000 \ | ||
558 | src/keymap/keymaps/lenovo-ideapad \ | ||
559 | src/keymap/keymaps/lenovo-thinkpad-usb-keyboard-trackpoint \ | ||
560 | src/keymap/keymaps/lenovo-thinkpad_x6_tablet \ | ||
561 | src/keymap/keymaps/lenovo-thinkpad_x200_tablet \ | ||
562 | src/keymap/keymaps/lg-x110 \ | ||
563 | src/keymap/keymaps/logitech-wave \ | ||
564 | src/keymap/keymaps/logitech-wave-cordless \ | ||
565 | src/keymap/keymaps/logitech-wave-pro-cordless \ | ||
566 | src/keymap/keymaps/maxdata-pro_7000 \ | ||
567 | src/keymap/keymaps/medion-fid2060 \ | ||
568 | src/keymap/keymaps/medionnb-a555 \ | ||
569 | src/keymap/keymaps/micro-star \ | ||
570 | src/keymap/keymaps/module-asus-w3j \ | ||
571 | src/keymap/keymaps/module-ibm \ | ||
572 | src/keymap/keymaps/module-lenovo \ | ||
573 | src/keymap/keymaps/module-sony \ | ||
574 | src/keymap/keymaps/module-sony-old \ | ||
575 | src/keymap/keymaps/module-sony-vgn \ | ||
576 | src/keymap/keymaps/olpc-xo \ | ||
577 | src/keymap/keymaps/onkyo \ | ||
578 | src/keymap/keymaps/oqo-model2 \ | ||
579 | src/keymap/keymaps/samsung-other \ | ||
580 | src/keymap/keymaps/samsung-90x3a \ | ||
581 | src/keymap/keymaps/samsung-sq1us \ | ||
582 | src/keymap/keymaps/samsung-sx20s \ | ||
583 | src/keymap/keymaps/toshiba-satellite_a100 \ | ||
584 | src/keymap/keymaps/toshiba-satellite_a110 \ | ||
585 | src/keymap/keymaps/toshiba-satellite_m30x \ | ||
586 | src/keymap/keymaps/zepto-znote | ||
587 | |||
588 | udevkeymapforcereldir = $(libexecdir)/udev/keymaps/force-release | ||
589 | dist_udevkeymapforcerel_DATA = \ | ||
590 | src/keymap/force-release-maps/dell-touchpad \ | ||
591 | src/keymap/force-release-maps/hp-other \ | ||
592 | src/keymap/force-release-maps/samsung-other \ | ||
593 | src/keymap/force-release-maps/samsung-90x3a \ | ||
594 | src/keymap/force-release-maps/common-volume-keys | ||
595 | |||
596 | src/keymap/keys.txt: $(INCLUDE_PREFIX)/linux/input.h | ||
597 | $(AM_V_at)mkdir -p src/keymap | ||
598 | $(AM_V_GEN)$(AWK) '/^#define.*KEY_[^ ]+[ \t]+[0-9]/ { if ($$2 != "KEY_MAX") { print $$2 } }' < $< | sed 's/^KEY_COFFEE$$/KEY_SCREENLOCK/' > $@ | ||
599 | |||
600 | src/keymap/keys-from-name.gperf: src/keymap/keys.txt | ||
601 | $(AM_V_GEN)$(AWK) 'BEGIN{ print "struct key { const char* name; unsigned short id; };"; print "%null-strings"; print "%%";} { print $$1 ", " $$1 }' < $< > $@ | ||
602 | |||
603 | src/keymap/keys-from-name.h: src/keymap/keys-from-name.gperf Makefile | ||
604 | $(AM_V_GEN)$(GPERF) -L ANSI-C -t --ignore-case -N lookup_key -H hash_key_name -p -C < $< > $@ | ||
605 | |||
606 | src/keymap/keys-to-name.h: src/keymap/keys.txt Makefile | ||
607 | $(AM_V_GEN)$(AWK) 'BEGIN{ print "const char* const key_names[KEY_CNT] = { "} { print "[" $$1 "] = \"" $$1 "\"," } END{print "};"}' < $< > $@ | ||
608 | |||
609 | keymaps-distcheck-hook: src/keymap/keys.txt | ||
610 | $(top_srcdir)/src/keymap/check-keymaps.sh $(top_srcdir) $^ | ||
611 | DISTCHECK_HOOKS += keymaps-distcheck-hook | ||
612 | endif | ||
613 | |||
614 | if ENABLE_MTD_PROBE | ||
615 | # ------------------------------------------------------------------------------ | ||
616 | mtd_probe_SOURCES = \ | ||
617 | src/mtd_probe/mtd_probe.c \ | ||
618 | src/mtd_probe/mtd_probe.h \ | ||
619 | src/mtd_probe/probe_smartmedia.c | ||
620 | mtd_probe_CPPFLAGS = $(AM_CPPFLAGS) | ||
621 | dist_udevrules_DATA += src/mtd_probe/75-probe_mtd.rules | ||
622 | pkglibexec_PROGRAMS += mtd_probe | ||
623 | endif | ||
624 | |||
625 | # ------------------------------------------------------------------------------ | ||
626 | if ENABLE_RULE_GENERATOR | ||
627 | dist_udevhome_SCRIPTS += \ | ||
628 | src/rule_generator/write_cd_rules \ | ||
629 | src/rule_generator/write_net_rules | ||
630 | |||
631 | dist_udevhome_DATA += \ | ||
632 | src/rule_generator/rule_generator.functions | ||
633 | |||
634 | dist_udevrules_DATA += \ | ||
635 | src/rule_generator/75-cd-aliases-generator.rules \ | ||
636 | src/rule_generator/75-persistent-net-generator.rules | ||
637 | endif | ||
638 | |||
639 | # ------------------------------------------------------------------------------ | ||
640 | if ENABLE_FLOPPY | ||
641 | create_floppy_devices_SOURCES = src/floppy/create_floppy_devices.c | ||
642 | create_floppy_devices_LDADD = libudev-private.la | ||
643 | pkglibexec_PROGRAMS += create_floppy_devices | ||
644 | dist_udevrules_DATA += src/floppy/60-floppy.rules | ||
645 | endif | ||
646 | |||
647 | # ------------------------------------------------------------------------------ | ||
648 | clean-local: | ||
649 | rm -rf udev-test-install | ||
650 | |||
651 | distclean-local: | ||
652 | rm -rf autom4te.cache | ||
653 | |||
654 | EXTRA_DIST += \ | ||
655 | $(TESTS) \ | ||
656 | test/rule-syntax-check.py | ||
657 | |||
658 | CLEANFILES += \ | ||
659 | $(BUILT_SOURCES) | ||
660 | |||
661 | install-exec-hook: $(INSTALL_EXEC_HOOKS) | ||
662 | |||
663 | install-data-hook: $(INSTALL_DATA_HOOKS) | ||
664 | |||
665 | uninstall-hook: $(UNINSTALL_EXEC_HOOKS) | ||
666 | |||
667 | distcheck-hook: $(DISTCHECK_HOOKS) | ||
668 | |||
669 | distclean-local: $(DISTCLEAN_LOCAL_HOOKS) | ||
670 | |||
671 | # ------------------------------------------------------------------------------ | ||
672 | PREVIOUS_VERSION = `expr $(VERSION) - 1` | ||
673 | changelog: | ||
674 | @ head -1 ChangeLog | grep -q "to v$(PREVIOUS_VERSION)" | ||
675 | @ mv ChangeLog ChangeLog.tmp | ||
676 | @ echo "Summary of changes from v$(PREVIOUS_VERSION) to v$(VERSION)" >> ChangeLog | ||
677 | @ echo "============================================" >> ChangeLog | ||
678 | @ echo >> ChangeLog | ||
679 | @ git log --pretty=short $(PREVIOUS_VERSION)..HEAD | git shortlog >> ChangeLog | ||
680 | @ echo >> ChangeLog | ||
681 | @ cat ChangeLog | ||
682 | @ cat ChangeLog.tmp >> ChangeLog | ||
683 | @ rm ChangeLog.tmp | ||
684 | |||
685 | test-install: | ||
686 | rm -rf $(PWD)/udev-test-install/ | ||
687 | make DESTDIR=$(PWD)/udev-test-install install | ||
688 | tree $(PWD)/udev-test-install/ | ||
689 | |||
690 | git-release: | ||
691 | head -1 ChangeLog | grep -q "to v$(VERSION)" | ||
692 | head -1 NEWS | grep -q "udev $(VERSION)" | ||
693 | git commit -a -m "release $(VERSION)" | ||
694 | git tag -m "udev $(VERSION)" -s $(VERSION) | ||
695 | git gc --prune=0 | ||
696 | |||
697 | git-sync: | ||
698 | git push | ||
699 | git push --tags | ||
700 | |||
701 | tar-sync: | ||
702 | rm -f udev-$(VERSION).tar.sign | ||
703 | xz -d -c udev-$(VERSION).tar.xz | gpg --armor --detach-sign --output udev-$(VERSION).tar.sign | ||
704 | kup put udev-$(VERSION).tar.xz udev-$(VERSION).tar.sign /pub/linux/utils/kernel/hotplug/ | ||
705 | |||
706 | doc-sync: | ||
707 | for i in src/*.html; do rm -f $$i.sign; gpg --armor --detach-sign --output=$$i.sign $$i; done | ||
708 | for i in src/*.html; do echo $$i; kup put $$i $$i.sign /pub/linux/utils/kernel/hotplug/udev/; done | ||
709 | for i in src/docs/html/*.{html,css,png}; do rm -f $$i.sign; gpg --armor --detach-sign --output=$$i.sign $$i; done | ||
710 | for i in src/docs/html/*.{html,css,png}; do echo $$i; kup put $$i $$i.sign /pub/linux/utils/kernel/hotplug/libudev/; done | ||
711 | for i in src/gudev/docs/html/*.{html,css,png}; do rm -f $$i.sign; gpg --armor --detach-sign --output=$$i.sign $$i; done | ||
712 | for i in src/gudev/docs/html/*.{html,css,png}; do echo $$i; kup put $$i $$i.sign /pub/linux/utils/kernel/hotplug/gudev/; done | ||
diff --git a/src/udev/NEWS b/src/udev/NEWS new file mode 100644 index 000000000..f4f6f4e32 --- /dev/null +++ b/src/udev/NEWS | |||
@@ -0,0 +1,1735 @@ | |||
1 | udev 182 | ||
2 | ======== | ||
3 | Rules files in /etc/udev/rules.s/ with the same name as rules files in | ||
4 | /run/udev/rules.d/ now always have precedence. The stack of files is now: | ||
5 | /usr/lib (package), /run (runtime, auto-generated), /etc (admin), while | ||
6 | the later ones override the earlier ones. In other words: the admin has | ||
7 | always the last say. | ||
8 | |||
9 | USB auto-suspend is now enabled by default for some built-in USB HID | ||
10 | devices. | ||
11 | |||
12 | /dev/disk/by-path/ links are no longer created for ATA devices behind | ||
13 | an 'ATA transport class', the logic to extract predictable numbers does | ||
14 | not exist in the kernel at this moment. | ||
15 | |||
16 | /dev/disk/by-id/scsi-* compatibility links are no longer created for | ||
17 | ATA devices, they have their own ata-* prefix. | ||
18 | |||
19 | The s390 rule to set mode == 0666 for /dev/z90crypt is is removed from | ||
20 | the udev tree and will be part of s390utils (or alternatively could be | ||
21 | done by the kernel driver itself). | ||
22 | |||
23 | The udev-acl tool is no longer provided, it will be part of a future | ||
24 | ConsoleKit release. On systemd systems, advanced ConsoleKit and udev-acl | ||
25 | functionality are provided by systemd. | ||
26 | |||
27 | udev 181 | ||
28 | ======== | ||
29 | Require kmod version 5. | ||
30 | |||
31 | Provide /dev/cdrom symlink for /dev/sr0. | ||
32 | |||
33 | udev 180 | ||
34 | ======== | ||
35 | Fix for ID_PART_ENTRY_* property names, added by the blkid built-in. The | ||
36 | fix is needed for udisk2 to operate properly. | ||
37 | |||
38 | Fix for skipped rule execution when the kernel has removed the device | ||
39 | node in /dev again, before the event was even started. The fix is needed | ||
40 | to run device-mapper/LVM events properly. | ||
41 | |||
42 | Fix for the man page installation, which was skipped when xsltproc was not | ||
43 | installed. | ||
44 | |||
45 | udev 179 | ||
46 | ======== | ||
47 | Bugfix for $name resolution, which broke at least some keymap handling. | ||
48 | |||
49 | udev 178 | ||
50 | ======== | ||
51 | Bugfix for the firmware loading behavior with kernel modules which | ||
52 | try to load firmware in the module_init() path. The blocked event | ||
53 | runs into a timout now, which should allow the firmware to be loaded. | ||
54 | |||
55 | Bugfix for a wrong DEVNAME= export, which breaks at least the udev-acl | ||
56 | tool. | ||
57 | |||
58 | Bugfix for missing ID_ properties for GPT partitions. | ||
59 | |||
60 | The RUN+="socket:.." option is deprecated and should not be used. A warning | ||
61 | during rules parsing is printed now. Services which listen to udev events, | ||
62 | need to subscribe to the netlink messages with libudev and not let udev block | ||
63 | in the rules execution until the message is delivered. | ||
64 | |||
65 | udev 177 | ||
66 | ======== | ||
67 | Bugfix for rule_generator instalation. | ||
68 | |||
69 | udev 176 | ||
70 | ======== | ||
71 | The 'devtmpfs' filesystem is required now, udev will not create or delete | ||
72 | device nodes anymore, it only adjusts permissions and ownership of device | ||
73 | nodes and maintains additional symlinks. | ||
74 | |||
75 | A writable /run directory (ususally tmpfs) is required now for a fully | ||
76 | functional udev, there is no longer a fallback to /dev/.udev. | ||
77 | |||
78 | The default 'configure' install locations have changed. Packages for systems | ||
79 | with the historic / vs. /usr split need to be adapted, otherwise udev will | ||
80 | be installed in /usr and not work properly. Example configuration options | ||
81 | to install things the traditional way are in INSTALL. | ||
82 | |||
83 | The default install location of the 'udevadm' tool moved from 'sbin' | ||
84 | to /usr/bin. Some tools expect udevadm in 'sbin', a symlink to udevadm | ||
85 | needs to be manually created if needed, or --bindir=/sbin be specified. | ||
86 | |||
87 | The expected value of '--libexecdir=' has changed and must no longer contain | ||
88 | the 'udev' directory. | ||
89 | |||
90 | Kernel modules are now loaded directly by linking udev to 'libkmod'. The | ||
91 | 'modprobe' tool is no longer executed by udev. | ||
92 | |||
93 | The 'blkid' tool is no longer executed from udev rules. Udev links | ||
94 | directly to libblkid now. | ||
95 | |||
96 | Firmware is loaded natively by udev now, the external 'firmware' binary | ||
97 | is no longer used. | ||
98 | |||
99 | All built-in tools can be listed and tested with 'udevadm test-builtin'. | ||
100 | |||
101 | The 'udevadm control --reload-rules' option has been renamed to '--reload'. | ||
102 | It now also reloads the kernel module configuration. | ||
103 | |||
104 | The systemd socket files use PassCredentials=yes, which is available in | ||
105 | systemd version 38. | ||
106 | |||
107 | The udev build system only creates a .xz tarball now. | ||
108 | |||
109 | All tabs in the source code used for indentation are replaced by spaces now. :) | ||
110 | |||
111 | udev 175 | ||
112 | ======== | ||
113 | Bugfixes. | ||
114 | |||
115 | udev 174 | ||
116 | ======== | ||
117 | Bugfixes. | ||
118 | |||
119 | The udev daemon moved to /lib/udev/udevd. Non-systemd init systems | ||
120 | and non-dracut initramfs image generators need to change the init | ||
121 | scripts. Alternatively the udev build needs to move udevd back to | ||
122 | /sbin or create a symlink in /sbin, which is not done by default. | ||
123 | |||
124 | The path_id, usb_id, input_id tools are built-in commands now and | ||
125 | the stand-alone tools do not exist anymore. Static lists of file in | ||
126 | initramfs generators need to be updated. For testing, the commands | ||
127 | can still be executed standalone with 'udevadm test-builtin <cmd>'. | ||
128 | |||
129 | The fusectl filesystem is no longer mounted directly from udev. | ||
130 | Systemd systems will take care of mounting fusectl and configfs | ||
131 | now. Non-systemd systems need to ship their own rule if they | ||
132 | need these filesystems auto-mounted. | ||
133 | |||
134 | The long deprecated keys: SYSFS=, ID=, BUS= have been removed. | ||
135 | |||
136 | The support for 'udevadm trigger --type=failed, and the | ||
137 | RUN{fail_event_on_error} attribute was removed. | ||
138 | |||
139 | The udev control socket is now created in /run/udev/control | ||
140 | and no longer as an abstract namespace one. | ||
141 | |||
142 | The rules to create persistent network interface and cdrom link | ||
143 | rules automatically in /etc/udev/rules.d/ have been disabled by | ||
144 | default. Explicit configuration will be required for these use | ||
145 | cases, udev will no longer try to write any persistent system | ||
146 | configuration from a device hotplug path. | ||
147 | |||
148 | udev 173 | ||
149 | ======== | ||
150 | Bugfixes. | ||
151 | |||
152 | The udev-acl extra is no longer enabled by default now. To enable it, | ||
153 | --enable-udev_acl needs to be given at ./configure time. On systemd | ||
154 | systems, the udev-acl rules prevent it from running as the functionality | ||
155 | has moved to systemd. | ||
156 | |||
157 | udev 172 | ||
158 | ======== | ||
159 | Bugfixes. | ||
160 | |||
161 | Udev now enables kernel media-presence polling if available. Part | ||
162 | of udisks optical drive tray-handling moved to cdrom_id: The tray | ||
163 | is locked as soon as a media is detected to enable the receiving | ||
164 | of media-eject-request events. Media-eject-request events will | ||
165 | eject the media. | ||
166 | |||
167 | Libudev enumerate is now able to enumerate a subtree of a given | ||
168 | device. | ||
169 | |||
170 | The mobile-action-modeswitch modeswitch tool was deleted. The | ||
171 | functionality is provided by usb_modeswitch now. | ||
172 | |||
173 | udev 171 | ||
174 | ======== | ||
175 | Bugfixes. | ||
176 | |||
177 | The systemd service files require systemd version 28. The systemd | ||
178 | socket activation make it possible now to start 'udevd' and 'udevadm | ||
179 | trigger' in parallel. | ||
180 | |||
181 | udev 170 | ||
182 | ======== | ||
183 | Fix bug in control message handling, which can lead to a failing | ||
184 | udevadm control --exit. Thanks to Jürg Billeter for help tracking | ||
185 | it down. | ||
186 | |||
187 | udev 169 | ||
188 | ======== | ||
189 | Bugfixes. | ||
190 | |||
191 | We require at least Linux kernel 2.6.32 now. Some platforms might | ||
192 | require a later kernel that supports accept4() and similar, or | ||
193 | need to backport the trivial syscall wiring to the older kernels. | ||
194 | |||
195 | The hid2hci tool moved to the bluez package and was removed. | ||
196 | |||
197 | Many of the extras can be --enable/--disabled at ./configure | ||
198 | time. The --disable-extras option was removed. Some extras have | ||
199 | been disabled by default. The current options and their defaults | ||
200 | can be checked with './configure --help'. | ||
201 | |||
202 | udev 168 | ||
203 | ======== | ||
204 | Bugfixes. | ||
205 | |||
206 | Udev logs a warning now if /run is not writable at udevd | ||
207 | startup. It will still fall back to /dev/.udev, but this is | ||
208 | now considered a bug. | ||
209 | |||
210 | The running udev daemon can now cleanly shut down with: | ||
211 | udevadm control --exit | ||
212 | |||
213 | Udev in initramfs should clean the state of the udev database | ||
214 | with: udevadm info --cleanup-db which will remove all state left | ||
215 | behind from events/rules in initramfs. If initramfs uses | ||
216 | --cleanup-db and device-mapper/LVM, the rules in initramfs need | ||
217 | to add OPTIONS+="db_persist" for all dm devices. This will | ||
218 | prevent removal of the udev database for these devices. | ||
219 | |||
220 | Spawned programs by PROGRAM/IMPORT/RUN now have a hard timeout of | ||
221 | 120 seconds per process. If that timeout is reached the spawned | ||
222 | process will be killed. The event timeout can be overwritten with | ||
223 | udev rules. | ||
224 | |||
225 | If systemd is used, udev gets now activated by netlink data. | ||
226 | Systemd will bind the netlink socket which will buffer all data. | ||
227 | If needed, such setup allows a seemless update of the udev daemon, | ||
228 | where no event can be lost during a udevd update/restart. | ||
229 | Packages need to make sure to: systemctl stop udev.socket udev.service | ||
230 | or 'mask' udev.service during the upgrade to prevent any unwanted | ||
231 | auto-spawning of udevd. | ||
232 | This version of udev conflicts with systemd version below 25. The | ||
233 | unchanged service files will not wirk correctly. | ||
234 | |||
235 | udev 167 | ||
236 | ======== | ||
237 | Bugfixes. | ||
238 | |||
239 | The udev runtime data moved from /dev/.udev/ to /run/udev/. The | ||
240 | /run mountpoint is supposed to be a tmpfs mounted during early boot, | ||
241 | available and writable to for all tools at any time during bootup, | ||
242 | it replaces /var/run/, which should become a symlink some day. | ||
243 | |||
244 | If /run does not exist, or is not writable, udev will fall back using | ||
245 | /dev/.udev/. | ||
246 | |||
247 | On systemd systems with initramfs and LVM used, packagers must | ||
248 | make sure, that the systemd and initramfs versions match. The initramfs | ||
249 | needs to create the /run mountpoint for udev to store the data, and | ||
250 | mount this tmpfs to /run in the rootfs, so the that the udev database | ||
251 | is preserved for the udev version started in the rootfs. | ||
252 | |||
253 | The command 'udevadm info --convert-db' is gone. The udev daemon | ||
254 | itself, at startup, converts any old database version if necessary. | ||
255 | |||
256 | The systemd services files have been reorganized. The udev control | ||
257 | socket is bound by systemd and passed to the started udev daemon. | ||
258 | The udev-settle.service is no longer active by default. Services which | ||
259 | can not handle hotplug setups properly need to actively pull it in, to | ||
260 | act like a barrier. Alternatively the settle service can be unconditionally | ||
261 | 'systemctl'enabled, and act like a barrier for basic.target. | ||
262 | |||
263 | The fstab_import callout is no longer built or installed. Udev | ||
264 | should not be used to mount, does not watch changes to fstab, and | ||
265 | should not mirror fstab values in the udev database. | ||
266 | |||
267 | udev 166 | ||
268 | ======== | ||
269 | Bugfixes. | ||
270 | |||
271 | New and updated keymaps. | ||
272 | |||
273 | udev 165 | ||
274 | ======== | ||
275 | Bugfixes. | ||
276 | |||
277 | The udev database has changed, After installation of a new udev | ||
278 | version, 'udevadm info --convert-db' should be called, to let the new | ||
279 | udev/libudev version read the already stored data. | ||
280 | |||
281 | udevadm now supports quoting of property values, and prefixing of | ||
282 | key names: | ||
283 | $ udevadm info --export --export-prefix=MY_ --query=property -n sda | ||
284 | MY_MAJOR='259' | ||
285 | MY_MINOR='0' | ||
286 | MY_DEVNAME='/dev/sda' | ||
287 | MY_DEVTYPE='disk' | ||
288 | ... | ||
289 | |||
290 | libudev now supports: | ||
291 | udev_device_get_is_initialized() | ||
292 | udev_enumerate_add_match_is_initialized() | ||
293 | to be able to skip devices the kernel has created , but udev has | ||
294 | not already handled. | ||
295 | |||
296 | libudev now supports: | ||
297 | udev_device_get_usec_since_initialized() | ||
298 | to retrieve the "age" of a udev device record. | ||
299 | |||
300 | GUdev supports a more generic GUdevEnumerator class, udev TAG | ||
301 | handling, device initialization and timestamp now. | ||
302 | |||
303 | The counterpart of /sys/dev/{char,block}/$major:$minor, | ||
304 | /dev/{char,block}/$major:$minor symlinks are now unconditionally | ||
305 | created, even when no rule files exist. | ||
306 | |||
307 | New and updated keymaps. | ||
308 | |||
309 | udev 164 | ||
310 | ======== | ||
311 | Bugfixes. | ||
312 | |||
313 | GUdev moved from /usr to /. | ||
314 | |||
315 | udev 163 | ||
316 | ======== | ||
317 | Bugfixes. | ||
318 | |||
319 | udev 162 | ||
320 | ======== | ||
321 | Bugfixes. | ||
322 | |||
323 | Persistent network naming rules are disabled inside of Qemu/KVM now. | ||
324 | |||
325 | New and updated keymaps. | ||
326 | |||
327 | Udev gets unconditionally enabled on systemd installations now. There | ||
328 | is no longer the need to to run 'systemctl enable udev.service'. | ||
329 | |||
330 | udev 161 | ||
331 | ======== | ||
332 | Bugfixes. | ||
333 | |||
334 | udev 160 | ||
335 | ======== | ||
336 | Bugfixes. | ||
337 | |||
338 | udev 159 | ||
339 | ======== | ||
340 | Bugfixes. | ||
341 | |||
342 | New and fixed keymaps. | ||
343 | |||
344 | Install systemd service files if applicable. | ||
345 | |||
346 | udev 158 | ||
347 | ======== | ||
348 | Bugfixes. | ||
349 | |||
350 | All distribution specific rules are removed from the udev source tree, | ||
351 | most of them are no longer needed. The Gentoo rules which allow to support | ||
352 | older kernel versions, which are not covered by the default rules anymore | ||
353 | has moved to rules/misc/30-kernel-compat.rules. | ||
354 | |||
355 | udev 157 | ||
356 | ======== | ||
357 | Bugfixes. | ||
358 | |||
359 | The option --debug-trace and the environemnt variable UDEVD_MAX_CHILDS= | ||
360 | was removed from udevd. | ||
361 | |||
362 | Udevd now checks the kernel commandline for the following variables: | ||
363 | udev.log-priority=<syslog priority> | ||
364 | udev.children-max=<maximum number of workers> | ||
365 | udev.exec-delay=<seconds to delay the execution of RUN=> | ||
366 | to help debuging coldplug setups where the loading of a kernel | ||
367 | module crashes the system. | ||
368 | |||
369 | The subdirectory in the source tree rules/packages has been renamed to | ||
370 | rules/arch, anc contains only architecture specific rules now. | ||
371 | |||
372 | udev 156 | ||
373 | ======== | ||
374 | Bugfixes. | ||
375 | |||
376 | udev 155 | ||
377 | ======== | ||
378 | Bugfixes. | ||
379 | |||
380 | Now the udev daemon itself, does on startup: | ||
381 | - copy the content of /lib/udev/devices to /dev | ||
382 | - create the standard symlinks like /dev/std{in,out,err}, | ||
383 | /dev/core, /dev/fd, ... | ||
384 | - use static node information provided by kernel modules | ||
385 | and creates these nodes to allow module on-demand loading | ||
386 | - possibly apply permissions to all ststic nodes from udev | ||
387 | rules which are annotated to match a static node | ||
388 | |||
389 | The default mode for a device node is 0600 now to match the kernel | ||
390 | created devtmpfs defaults. If GROUP= is specified and no MODE= is | ||
391 | given the default will be 0660. | ||
392 | |||
393 | udev 154 | ||
394 | ======== | ||
395 | Bugfixes. | ||
396 | |||
397 | Udev now gradually starts to pass control over the primary device nodes | ||
398 | and their names to the kernel, and will in the end only manage the | ||
399 | permissions of the node, and possibly create additional symlinks. | ||
400 | As a first step NAME="" will be ignored, and NAME= setings with names | ||
401 | other than the kernel provided name will result in a logged warning. | ||
402 | Kernels that don't provide device names, or devtmpfs is not used, will | ||
403 | still work as they did before, but it is strongly recommended to use | ||
404 | only the same names for the primary device node as the recent kernel | ||
405 | provides for all devices. | ||
406 | |||
407 | udev 153 | ||
408 | ======== | ||
409 | Fix broken firmware loader search path. | ||
410 | |||
411 | udev 152 | ||
412 | ======== | ||
413 | Bugfixes. | ||
414 | |||
415 | "udevadm trigger" defaults to "change" events now instead of "add" | ||
416 | events. The "udev boot script" might need to add "--action=add" to | ||
417 | the trigger command if not already there, in case the initial coldplug | ||
418 | events are expected as "add" events. | ||
419 | |||
420 | The option "all_partitons" was removed from udev. This should not be | ||
421 | needed for usual hardware. Udev can not safely make assumptions | ||
422 | about non-existing partition major/minor numbers, and therefore no | ||
423 | longer provide this unreliable and unsafe option. | ||
424 | |||
425 | The option "ignore_remove" was removed from udev. With devtmpfs | ||
426 | udev passed control over device nodes to the kernel. This option | ||
427 | should not be needed, or can not work as advertised. Neither | ||
428 | udev nor the kernel will remove device nodes which are copied from | ||
429 | the /lib/udev/devices/ directory. | ||
430 | |||
431 | All "add|change" matches are replaced by "!remove" in the rules and | ||
432 | in the udev logic. All types of events will update possible symlinks | ||
433 | and permissions, only "remove" is handled special now. | ||
434 | |||
435 | The modem modeswitch extra was removed and the external usb_modeswitch | ||
436 | program should be used instead. | ||
437 | |||
438 | New and fixed keymaps. | ||
439 | |||
440 | udev 151 | ||
441 | ======== | ||
442 | Bugfixes. | ||
443 | |||
444 | udev 150 | ||
445 | ======== | ||
446 | Bugfixes. | ||
447 | |||
448 | Kernels with SYSFS_DEPRECATED=y are not supported since a while. Many users | ||
449 | depend on the current sysfs layout and the information not available in the | ||
450 | deprecated layout. All remaining support for the deprecated sysfs layout is | ||
451 | removed now. | ||
452 | |||
453 | udev 149 | ||
454 | ======== | ||
455 | Fix for a possible endless loop in the new input_id program. | ||
456 | |||
457 | udev 148 | ||
458 | ======== | ||
459 | Bugfixes. | ||
460 | |||
461 | The option "ignore_device" does no longer exist. There is no way to | ||
462 | ignore an event, as libudev events can not be suppressed by rules. | ||
463 | It only prevented RUN keys from being executed, which results in an | ||
464 | inconsistent behavior in current setups. | ||
465 | |||
466 | BUS=, SYSFS{}=, ID= are long deprecated and should be SUBSYSTEM(S)=, | ||
467 | ATTR(S){}=, KERNEL(S)=. It will cause a warning once for every rule | ||
468 | file from now on. | ||
469 | |||
470 | The support for the deprecated IDE devices has been removed from the | ||
471 | default set of rules. Distros who still care about non-libata drivers | ||
472 | need to add the rules to the compat rules file. | ||
473 | |||
474 | The ID_CLASS property on input devices has been replaced by the more accurate | ||
475 | set of flags ID_INPUT_{KEYBOARD,KEY,MOUSE,TOUCHPAD,TABLET,JOYSTICK}. These are | ||
476 | determined by the new "input_id" prober now. Some devices, such as touchpads, | ||
477 | can have several classes. So if you previously had custom udev rules which e. g. | ||
478 | checked for ENV{ID_CLASS}=="kbd", you need to replace this with | ||
479 | ENV{ID_INPUT_KEYBOARD}=="?*". | ||
480 | |||
481 | udev 147 | ||
482 | ======== | ||
483 | Bugfixes. | ||
484 | |||
485 | To support DEVPATH strings larger than the maximum file name length, the | ||
486 | private udev database format has changed. If some software still reads the | ||
487 | private files in /dev/.udev/, which it shouldn't, now it's time to fix it. | ||
488 | Please do not port anything to the new format again, everything in /dev/.udev | ||
489 | is and always was private to udev, and may and will change any time without | ||
490 | prior notice. | ||
491 | |||
492 | Multiple devices claiming the same names in /dev are limited to symlinks | ||
493 | only now. Mixing identical symlink names and node names is not supported. | ||
494 | This reduces the amount of data in the database significantly. | ||
495 | |||
496 | NAME="%k" causes a warning now. It's is and always was completely superfluous. | ||
497 | It will break kernel supplied DEVNAMEs and therefore it needs to be removed | ||
498 | from all rules. | ||
499 | |||
500 | Most NAME= instructions got removed. Kernel 2.6.31 supplies the needed names | ||
501 | if they are not the default. To support older kernels, the NAME= rules need to | ||
502 | be added to the compat rules file. | ||
503 | |||
504 | Symlinks to udevadm with the old command names are no longer resolved to | ||
505 | the udevadm commands. | ||
506 | |||
507 | The udev-acl tool got adopted to changes in ConsoleKit. Version 0.4.1 is | ||
508 | required now. | ||
509 | |||
510 | The option "last_rule" does no longer exist. Its use breaks too many | ||
511 | things which expect to be run from independent later rules, and is an idication | ||
512 | that something needs to be fixed properly instead. | ||
513 | |||
514 | The gudev API is no longer marked as experimental, | ||
515 | G_UDEV_API_IS_SUBJECT_TO_CHANGE is no longer needed. The gudev introspection | ||
516 | is enabled by default now. Various projects already depend on introspection | ||
517 | information to bind dynamic languages to the gudev interfaces. | ||
518 | |||
519 | udev 146 | ||
520 | ======== | ||
521 | Bugfixes. | ||
522 | |||
523 | The udevadm trigger "--retry-failed" option, which is replaced since quite | ||
524 | a while by "--type=failed" is removed. | ||
525 | |||
526 | The failed tracking was not working at all for a few releases. The RUN | ||
527 | option "ignore_error" is replaced by a "fail_event_on_error" option, and the | ||
528 | default is not to track any failing RUN executions. | ||
529 | |||
530 | New keymaps, new modem, hid2hci updated. | ||
531 | |||
532 | udev 145 | ||
533 | ======== | ||
534 | Fix possible crash in udevd when worker processes are busy, rules are | ||
535 | changed at the same time, and workers get killed to reload the rules. | ||
536 | |||
537 | udev 144 | ||
538 | ======== | ||
539 | Bugfixes. | ||
540 | |||
541 | Properties set with ENV{.FOO}="bar" are marked private by starting the | ||
542 | name with a '.'. They will not be stored in the database, and not be | ||
543 | exported with the event. | ||
544 | |||
545 | Firmware files are looked up in: | ||
546 | /lib/firmware/updates/$(uname -r) | ||
547 | /lib/firmware/updates | ||
548 | /lib/firmware/$(uname -r) | ||
549 | /lib/firmware" | ||
550 | now. | ||
551 | |||
552 | ATA devices switched the property from ID_BUS=scsi to ID_BUS=ata. | ||
553 | ata_id, instead of scsi_id, is the default tool now for ATA devices. | ||
554 | |||
555 | udev 143 | ||
556 | ======== | ||
557 | Bugfixes. | ||
558 | |||
559 | The configure options have changed because another library needs to be | ||
560 | installed in a different location. Instead of exec_prefix and udev_prefix, | ||
561 | libdir, rootlibdir and libexecdir are used. The Details are explained in | ||
562 | the README file. | ||
563 | |||
564 | Event processes now get re-used after they handled an event. This reduces | ||
565 | the number of forks and the pressure on the CPU significantly, because | ||
566 | cloned event processes no longer cause page faults in the main daemon. | ||
567 | After the events have settled, a few worker processes stay around for | ||
568 | future events, all others get cleaned up. | ||
569 | |||
570 | To be able to use signalfd(), udev depends on kernel version 2.6.25 now. | ||
571 | Also inotify support is mandatory now to run udev. | ||
572 | |||
573 | The format of the queue exported by the udev damon has changed. There is | ||
574 | no longer a /dev/.udev/queue/ directory. The current event queue can be | ||
575 | accessed with udevadm settle and libudedv. | ||
576 | |||
577 | Libudev does not have the unstable API header anymore. From now on, | ||
578 | incompatible changes will be handled by bumping the library major version. | ||
579 | |||
580 | To build udev from the git tree gtk-doc is needed now. The tarballs will | ||
581 | build without it and contain the pre-built documentation. An online copy | ||
582 | is available here: | ||
583 | http://www.kernel.org/pub/linux/utils/kernel/hotplug/libudev/ | ||
584 | |||
585 | The tools from the udev-extras repository have been merged into the main | ||
586 | udev repository. Some of the extras have larger external dependencies, and | ||
587 | they can be disabled with the configure switch --disable-extras. | ||
588 | |||
589 | udev 142 | ||
590 | ======== | ||
591 | Bugfixes. | ||
592 | |||
593 | The program vol_id and the library libvolume_id are removed from the | ||
594 | repository. Libvolume_id is merged with libblkid from the util-linux-ng | ||
595 | package. Persistent disk links for label and uuid depend on the | ||
596 | util-linux-ng version (2.15) of blkid now. Older versions of blkid | ||
597 | can not be used with udev. | ||
598 | |||
599 | Libudev allows to subscribe to udev events. To prevent unwanted messages | ||
600 | to be delivered, and waking up the subscribing process, a filter can be | ||
601 | installed, to drop messages inside a kernel socket filter. The filters | ||
602 | match on the <subsytem>:<devtype> properties of the device. | ||
603 | This is part of the ongoing effort to replace HAL, and switch current | ||
604 | users over to directly use libudev. | ||
605 | Libudev is still marked as experimental, and its interface might | ||
606 | eventually change if needed, but no major changes of the currently exported | ||
607 | interface are expected anymore, and a first stable release should happen | ||
608 | soon. | ||
609 | |||
610 | A too old kernel (2.6.21) or a kernel with CONFIG_SYSFS_DEPRECATED | ||
611 | is not supported since while and udevd will log an error message at | ||
612 | startup. It should still be able to boot-up, but advanced rules and system | ||
613 | services which depend on the information not available in the old sysfs | ||
614 | format will fail to work correctly. | ||
615 | |||
616 | DVB device naming is supplied by the kernel now. In case older kernels | ||
617 | need to be supported, the old shell script should be added to a compat | ||
618 | rules file. | ||
619 | |||
620 | udev 141 | ||
621 | ======== | ||
622 | Bugfixes. | ||
623 | |||
624 | The processed udev events get send back to the netlink socket. Libudev | ||
625 | provides access to these events. This is work-in-progress, to replace | ||
626 | the DeviceKit daemon functionality directly with libudev. There are | ||
627 | upcoming kernel changes to allow non-root users to subcribe to these | ||
628 | events. | ||
629 | |||
630 | udev 140 | ||
631 | ======== | ||
632 | Bugfixes. | ||
633 | |||
634 | "udevadm settle" now optionally accepts a range of events to wait for, | ||
635 | instead of waiting for "all" events. | ||
636 | |||
637 | udev 139 | ||
638 | ======== | ||
639 | Bugfixes. | ||
640 | |||
641 | The installed watch for block device metadata changes is now removed | ||
642 | during event hadling, because some (broken) tools may be called from udev | ||
643 | rules and (wrongly) open the device with write access. After the finished | ||
644 | event handling the watch is restored. | ||
645 | |||
646 | udev 138 | ||
647 | ======== | ||
648 | Bugfixes. | ||
649 | |||
650 | Device nodes can be watched for changes with inotify with OPTIONS="watch". | ||
651 | If closed after being opened for writing, a "change" uevent will occur. | ||
652 | /dev/disk/by-{label,uuid}/* symlinks will be automatically updated. | ||
653 | |||
654 | udev 137 | ||
655 | ======== | ||
656 | Bugfixes. | ||
657 | |||
658 | The udevadm test command has no longer a --force option, nodes and symlinks | ||
659 | are always updated with a test run now. | ||
660 | |||
661 | The udevd daemon can be started with --resolve-names=never to avoid all user | ||
662 | and group lookups (e.g. in cut-down systems) or --resolve-names=late to | ||
663 | lookup user and groups every time events are handled. | ||
664 | |||
665 | udev 136 | ||
666 | ======== | ||
667 | Bugfixes. | ||
668 | |||
669 | We are currently merging the Ubuntu rules in the udev default rules, | ||
670 | and get one step closer to provide a common Linux /dev setup, regarding | ||
671 | device names, symlinks, and default device permissions. On udev startup, | ||
672 | we now expect the following groups to be resolvable to their ids with | ||
673 | glibc's getgrnam(): | ||
674 | disk, cdrom, floppy, tape, audio, video, lp, tty, dialout, kmem. | ||
675 | LDAP setups need to make sure, that these groups are always resolvable at | ||
676 | bootup, with only the rootfs mounted, and without network access available. | ||
677 | |||
678 | Some systems may need to add some new, currently not used groups, or need | ||
679 | to add some users to new groups, but the cost of this change is minimal, | ||
680 | compared to the pain the current, rather random, differences between the | ||
681 | various distributions cause for upstream projects and third-party vendors. | ||
682 | |||
683 | In general, "normal" users who log into a machine should never be a member | ||
684 | of any such group, but the device-access should be managed by dynamic ACLs, | ||
685 | which get added and removed for the specific users on login/logout and | ||
686 | session activity/inactivity. These groups are only provided for custom setups, | ||
687 | and mainly system services, to allow proper privilege separation. | ||
688 | A video-streaming daemon uid would be a member of "audio" and "video", to get | ||
689 | access to the sound and video devices, but no "normal" user should ever belong | ||
690 | to the "audio" group, because he could listen to the built-in microphone with | ||
691 | any ssh-session established from the other side of the world. | ||
692 | |||
693 | /dev/serial/by-{id,path}/ now contains links for ttyUSB devices, | ||
694 | which do not depend on the kernel device name. As usual, unique | ||
695 | devices - only a single one per product connected, or a real | ||
696 | USB serial number in the device - are always found with the same | ||
697 | name in the by-id/ directory. | ||
698 | Completely identical devices may overwrite their names in by-id/ | ||
699 | and can only be found reliably in the by-path/ directory. Devices | ||
700 | specified by by-path/ must not change their connection, like the | ||
701 | USB port number they are plugged in, to keep their name. | ||
702 | |||
703 | To support some advanced features, Linux 2.6.22 is the oldest supported | ||
704 | version now. The kernel config with enabled SYSFS_DEPRECATED is no longer | ||
705 | supported. Older kernels should still work, and devices nodes should be | ||
706 | reliably created, but some rules and libudev will not work correctly because | ||
707 | the old kernels do not provide the expected information or interfaces. | ||
708 | |||
709 | udev 135 | ||
710 | ======== | ||
711 | Bugfixes. | ||
712 | |||
713 | Fix for a possible segfault while swapping network interface names in udev | ||
714 | versions 131-134. | ||
715 | |||
716 | udev 134 | ||
717 | ======== | ||
718 | Bugfixes. | ||
719 | |||
720 | The group "video" is part of the default rules now. | ||
721 | |||
722 | udev 133 | ||
723 | ======== | ||
724 | Bugfix for kernels using SYSFS_DEPRECATED* option and finding parent | ||
725 | block devices in some cases. No common distro uses this option anymore, | ||
726 | and we do not get enough testing for this and recent udev versions. If | ||
727 | this option is not needed to run some old distro with a new kernel, | ||
728 | it should be disabled in the kernel config. | ||
729 | |||
730 | Bugfix for the $links substitution variable, which may crash if no links | ||
731 | are created. This should not happen in usual setups because we always | ||
732 | create /dev/{block,char}/ links. | ||
733 | |||
734 | The strings of the parsed rules, which are kept in memory, no longer | ||
735 | contain duplicate entries, or duplicate tails of strings. This, and the | ||
736 | new rules parsing/matching code reduces the total in-memory size of | ||
737 | a huge distro rule sets to 0.08 MB, compared to the 1.2MB of udev | ||
738 | version 130. | ||
739 | |||
740 | The export of DEVTYPE=disk/partition got removed from the default | ||
741 | rules. This value is available from the kernel. The pnp shell script | ||
742 | modprobe hack is removed from the default rules. ACPI devices have _proper_ | ||
743 | modalias support and take care of the same functionality. | ||
744 | Installations which support old kernels, but install current default | ||
745 | udev rules may want to add that to the compat rules file. | ||
746 | |||
747 | Libvolume_id now always probes for all known filesystems, and does not | ||
748 | stop at the first match. Some filesystems are marked as "exclusive probe", | ||
749 | and if any other filesytem type matches at the same time, libvolume_id | ||
750 | will, by default, not return any probing result. This is intended to prevent | ||
751 | mis-detection with conflicting left-over signatures found from earlier | ||
752 | file system formats. That way, we no longer depend on the probe-order | ||
753 | in case of multiple competing signatures. In some setups the kernel allows | ||
754 | to mount a volume with just the old filesystem signature still in place. | ||
755 | This may damage the new filesystem and cause data-loss, just by mounting | ||
756 | it. Because volume_id can not decide which one the correct signature is, | ||
757 | the wrong signatures need to be removed manually from the volume, or the | ||
758 | volume needs to be reformatted, to enable filesystem detection and possible | ||
759 | auto-mounting. | ||
760 | |||
761 | udev 132 | ||
762 | ======== | ||
763 | Fix segfault if compiled without optimization and dbg() does not get | ||
764 | compiled out and uses variables which are not available. | ||
765 | |||
766 | udev 131 | ||
767 | ======== | ||
768 | Bugfixes. (And maybe new bugs. :)) | ||
769 | |||
770 | The rule matching engine got converted from a rule list to a token | ||
771 | array which reduced the in-memory rules representation of a full | ||
772 | featured distros with thousends of udev rules from 1.2MB to 0.12 MB. | ||
773 | Limits like 5 ENV and ATTR matches, and one single instance for most | ||
774 | other keys per rule are gone. | ||
775 | |||
776 | The NAME assignment is no longer special cased. If later rules assign | ||
777 | a NAME value again, the former value will be overwritten. As usual | ||
778 | for most other keys, the NAME value can be protected by doing a final | ||
779 | assignment with NAME:="<value>". | ||
780 | |||
781 | All udev code now uses libudev, which is also exported. The library | ||
782 | is still under development, marked as experimental, and its interface | ||
783 | may change as long as the DeviceKit integration is not finished. | ||
784 | |||
785 | Many thanks to Alan Jenkins for his continuous help, and finding and | ||
786 | optimizing some of the computing expensive parts. | ||
787 | |||
788 | udev 130 | ||
789 | ======== | ||
790 | Bugfixes. | ||
791 | |||
792 | Kernel devices and device nodes are connected now by reverse indizes in | ||
793 | /sys and /dev. A device number retrieved by a stat() or similar, the | ||
794 | kernel device directory can be found by looking up: | ||
795 | /sys/dev/{block,char}/<maj>:<min> | ||
796 | and the device node of the same device by looking up: | ||
797 | /dev/{block,char}/<maj>:<min> | ||
798 | |||
799 | udev 129 | ||
800 | ======== | ||
801 | Fix recently introduced bug, which caused a compilation without large | ||
802 | file support, where vol_id does not recognize raid signatures at the end | ||
803 | of a volume. | ||
804 | |||
805 | Firewire disks now create both, by-id/scsi-* and by-id/ieee-* links. | ||
806 | Seems some kernel versions prevent the creation of the ieee-* links, | ||
807 | so people used the scsi-* link which disappeared now. | ||
808 | |||
809 | More libudev work. Almost all udevadm functionality comes from libudev | ||
810 | now. | ||
811 | |||
812 | udevadm trigger has a new option --type, which allows to trigger events | ||
813 | for "devices", for "subsystems", or "failed" devices. The old option | ||
814 | --retry-failed" still works, but is no longer mentioned in the man page. | ||
815 | |||
816 | udev 128 | ||
817 | ======== | ||
818 | Bugfixes. | ||
819 | |||
820 | The udevadm info --device-id-of-file= output has changed to use | ||
821 | the obvious format. Possible current users should use the --export | ||
822 | option which is not affected. | ||
823 | |||
824 | The old udev commands symlinks to udevadm are not installed, if | ||
825 | these symlinks are used, a warning is printed. | ||
826 | |||
827 | udev 127 | ||
828 | ======== | ||
829 | Bugfixes. | ||
830 | |||
831 | Optical drive's media is no longer probed for raid signatures, | ||
832 | reading the end of the device causes some devices to malfunction. | ||
833 | Also the offset of the last session found is used now to probe | ||
834 | for the filesystem. | ||
835 | |||
836 | The volume_id library got a major version number update to 1, | ||
837 | some deprecated functions are removed. | ||
838 | |||
839 | A shared library "libudev" gets installed now to provide access | ||
840 | to udev device information. DeviceKit, the successor of HAL, will | ||
841 | need this library to access the udev database and search sysfs for | ||
842 | devices. | ||
843 | The library is currently in an experimental state, also the API is | ||
844 | expected to change, as long as the DeviceKit integration is not | ||
845 | finished. | ||
846 | |||
847 | udev 126 | ||
848 | ======== | ||
849 | We use ./configure now. See INSTALL for details. Current | ||
850 | options are: | ||
851 | --prefix= | ||
852 | "/usr" - prefix for man pages, include files | ||
853 | --exec-prefix= | ||
854 | "" - the root filesystem, prefix for libs and binaries | ||
855 | --sysconfdir= | ||
856 | "/etc" | ||
857 | --with-libdir-name= | ||
858 | "lib" - directory name for libraries, not a path name | ||
859 | multilib 64bit systems may use "lib64" instead of "lib" | ||
860 | --enable-debug | ||
861 | compile-in verbose debug messages | ||
862 | --disable-logging | ||
863 | disable all logging and compile-out all log strings | ||
864 | --with-selinux | ||
865 | link against SELInux libraries, to set the expected context | ||
866 | for created files | ||
867 | |||
868 | In the default rules, the group "disk" gets permissions 0660 instead | ||
869 | of 0640. One small step closer to unify distro rules. Some day, all | ||
870 | distros hopefully end up with the same set of rules. | ||
871 | |||
872 | No symlinks to udevadm are installed anymore, if they are still needed, | ||
873 | they should be provided by the package. | ||
874 | |||
875 | udev 125 | ||
876 | ======== | ||
877 | Bugfixes. | ||
878 | |||
879 | Default udev rules, which are not supposed to be edited by the user, should | ||
880 | be placed in /lib/udev/rules.d/ now, to make it clear that they are private to | ||
881 | the udev package and will be replaced with an update. Udev will pick up rule | ||
882 | files from: | ||
883 | /lib/udev/rules.d/ - default installed rules | ||
884 | /etc/udev/rules.d/ - user rules + on-the-fly generated rules | ||
885 | /dev/.udev/rules.d/ - temporary non-persistent rules created after bootup | ||
886 | It does not matter in which directory a rule file lives, all files are sorted | ||
887 | in lexical order. | ||
888 | |||
889 | To help creating /dev/root, we have now: | ||
890 | $ udevadm info --export --export-prefix="ROOT_" --device-id-of-file=/ | ||
891 | ROOT_MAJOR=8 | ||
892 | ROOT_MINOR=5 | ||
893 | In case the current --device-id-of-file is already used, please switch to | ||
894 | the --export format version, it saves the output parsing and the old | ||
895 | format will be changed to use ':' as a separator, like the format in the | ||
896 | sysfs 'dev' file. | ||
897 | |||
898 | udev 124 | ||
899 | ======== | ||
900 | Fix cdrom_id to properly recognize blank media. | ||
901 | |||
902 | udev 123 | ||
903 | ======== | ||
904 | Bugfixes. | ||
905 | |||
906 | Tape drive id-data is queried from /dev/bsg/* instead of the tape | ||
907 | nodes. This avoids rewinding tapes on open(). | ||
908 | |||
909 | udev 122 | ||
910 | ======== | ||
911 | Bugfixes. | ||
912 | |||
913 | The symlinks udevcontrol and udevtrigger are no longer installed by | ||
914 | the Makefile. | ||
915 | |||
916 | The scsi_id program does not depend on sysfs anymore. It can speak | ||
917 | SGv4 now, so /dev/bsg/* device nodes can be used, to query SCSI device | ||
918 | data, which should solve some old problems with tape devices, where | ||
919 | we better do not open all tape device nodes to identify the device. | ||
920 | |||
921 | udev 121 | ||
922 | ======== | ||
923 | Many bugfixes. | ||
924 | |||
925 | The cdrom_id program is replaced by an advanced version, which can | ||
926 | detect most common device types, and also properties of the inserted | ||
927 | media. This is part of moving some basic functionality from HAL into | ||
928 | udev (and the kernel). | ||
929 | |||
930 | udev 120 | ||
931 | ======== | ||
932 | Bugfixes. | ||
933 | |||
934 | The last WAIT_FOR_SYSFS rule is removed from the default rules. | ||
935 | |||
936 | The symlinks to udevadm for the debugging tools: udevmonitor and | ||
937 | udevtest are no longer created. | ||
938 | |||
939 | The symlinks to the udevadm man page for the old tool names are | ||
940 | no longer created. | ||
941 | |||
942 | Abstract namespace sockets paths in RUN+="socket:@<path>" rules, | ||
943 | should be prefixed with '@' to indicate that the path is not a | ||
944 | real file. | ||
945 | |||
946 | udev 119 | ||
947 | ======== | ||
948 | Bugfixes. | ||
949 | |||
950 | udev 118 | ||
951 | ======== | ||
952 | Bugfixes. | ||
953 | |||
954 | Udevstart is removed from the tree, it did not get installed for | ||
955 | a long time now, and is long replaced by trigger and settle. | ||
956 | |||
957 | udev 117 | ||
958 | ======== | ||
959 | Bugfixes. | ||
960 | |||
961 | All udev tools are merged into a single binary called udevadm. | ||
962 | The old names of the tools are built-in commands in udevadm now. | ||
963 | Symlinks to udevadm, with the names of the old tools, provide | ||
964 | the same functionality as the standalone tools. There is also | ||
965 | only a single udevadm.8 man page left for all tools. | ||
966 | |||
967 | Tools like mkinitramfs should be checked, if they need to include | ||
968 | udevadm in the list of files. | ||
969 | |||
970 | udev 116 | ||
971 | ======== | ||
972 | Bugfixes. | ||
973 | |||
974 | udev 115 | ||
975 | ======== | ||
976 | Bugfixes. | ||
977 | |||
978 | The etc/udev/rules.d/ directory now contains a default set of basic | ||
979 | udev rules. This initial version is the result of a rules file merge | ||
980 | of Fedora and openSUSE. For these both distros only a few specific | ||
981 | rules are left in their own file, named after the distro. Rules which | ||
982 | are optionally installed, because they are only valid for a specific | ||
983 | architecture, or rules for subsystems which are not always used are | ||
984 | in etc/udev/packages/. | ||
985 | |||
986 | udev 114 | ||
987 | ======== | ||
988 | Bugfixes. | ||
989 | |||
990 | Dynamic rules can be created in /dev/.udev/rules.d/ to trigger | ||
991 | actions by dynamically created rules. | ||
992 | |||
993 | SYMLINK=="<value>" matches agains the entries in the list of | ||
994 | currently defined symlinks. The links are not created in the | ||
995 | filesystem at that point in time, but the values can be matched. | ||
996 | |||
997 | RUN{ignore_error}+="<program>" will ignore any exit code from the | ||
998 | program and not record as a failed event. | ||
999 | |||
1000 | udev 113 | ||
1001 | ======== | ||
1002 | Bugfixes. | ||
1003 | |||
1004 | Final merge of patches/features from the Ubuntu package. | ||
1005 | |||
1006 | udev 112 | ||
1007 | ======== | ||
1008 | Bugfixes. | ||
1009 | |||
1010 | Control characters in filesystem label strings are no longer silenty | ||
1011 | removed, but hex-encoded, to be able to uniquely identify the device | ||
1012 | by its symlink in /dev/disk/by-label/. | ||
1013 | If libvolume_id is used by mount(8), LABEL= will work as expected, | ||
1014 | if slashes or other characters are used in the label string. | ||
1015 | |||
1016 | To test the existence of a file, TEST=="<file>" and TEST!="<file>" | ||
1017 | can be specified now. The TEST key accepts an optional mode mask | ||
1018 | TEST{0100}=="<is executable file>". | ||
1019 | |||
1020 | Scsi_id now supports a mode without expecting scsi-specific sysfs | ||
1021 | entries to allow the extraction of cciss-device persistent properties. | ||
1022 | |||
1023 | udev 111 | ||
1024 | ======== | ||
1025 | Bugfixes. | ||
1026 | |||
1027 | In the future, we may see uuid's which are just simple character | ||
1028 | strings (see the DDF Raid Specification). For that reason vol_id now | ||
1029 | exports ID_FS_UUID_SAFE, just like ID_FS_LABEL_SAFE. For things like | ||
1030 | the creation of symlinks, the *_SAFE values ensure, that no control | ||
1031 | or whitespace characters are used in the filename. | ||
1032 | |||
1033 | Possible users of libvolume_id, please use the volume_id_get_* functions. | ||
1034 | The public struct will go away in a future release of the library. | ||
1035 | |||
1036 | udev 110 | ||
1037 | ======== | ||
1038 | Bugfixes. | ||
1039 | |||
1040 | Removal of useless extras/eventrecorder.sh. | ||
1041 | |||
1042 | udev 109 | ||
1043 | ======== | ||
1044 | Bugfixes. | ||
1045 | |||
1046 | udev 108 | ||
1047 | ======== | ||
1048 | Bugfixes. | ||
1049 | |||
1050 | The directory multiplexer for dev.d/ and hotplug.d are finally removed | ||
1051 | from the udev package. | ||
1052 | |||
1053 | udev 107 | ||
1054 | ======== | ||
1055 | Bugfixes. | ||
1056 | |||
1057 | Symlinks can have priorities now, the priority is assigned to the device | ||
1058 | and specified with OPTIONS="link_priority=100". Devices with higher | ||
1059 | priorities overwrite the symlinks of devices with lower priorities. | ||
1060 | If the device that currently owns the link, goes away, the symlink | ||
1061 | will be removed, and recreated, pointing to the next device with the | ||
1062 | highest actual priority. This should make /dev/disk/by-{label,uuid,id} | ||
1063 | more reliable, if multiple devices contain the same metadata and overwrite | ||
1064 | these symlinks. | ||
1065 | |||
1066 | The dasd_id program is removed from the udev tree, and dasdinfo, with the | ||
1067 | needed rules, are part of the s390-tools now. | ||
1068 | |||
1069 | Please add KERNEL=="[0-9]*:[0-9]*" to the scsi wait-for-sysfs rule, | ||
1070 | we may get the scsi sysfs mess fixed some day, and this will only catch | ||
1071 | the devices we are looking for. | ||
1072 | |||
1073 | USB serial numbers for storage devices have the target:lun now appended, | ||
1074 | to make it possibble to distinguish broken multi-lun devices with all | ||
1075 | the same SCSI identifiers. | ||
1076 | |||
1077 | Note: The extra "run_directory" which searches and executes stuff in | ||
1078 | /etc/hotplug.d/ and /etc/dev.d/ is long deprecated, and will be removed | ||
1079 | with the next release. Make sure, that you don't use it anymore, or | ||
1080 | provides your own implementation of that inefficient stuff. | ||
1081 | We are tired of reports about a "slow udev", because these directories | ||
1082 | contain stuff, that runs with _every_ event, instead of using rules, | ||
1083 | that run programs only for the matching events. | ||
1084 | |||
1085 | udev 106 | ||
1086 | ======== | ||
1087 | Bugfixes. | ||
1088 | |||
1089 | udev 105 | ||
1090 | ======== | ||
1091 | Bugfixes. | ||
1092 | |||
1093 | DRIVER== will match only for devices that actually have a real | ||
1094 | driver. DRIVERS== must be used, if parent devices should be | ||
1095 | included in the match. | ||
1096 | |||
1097 | Libvolume_id's "linux_raid" detection needed another fix. | ||
1098 | |||
1099 | udev 104 | ||
1100 | ======== | ||
1101 | Bugfixes. | ||
1102 | |||
1103 | udev 103 | ||
1104 | ======== | ||
1105 | Add additional check to volume_id detection of via_raid, cause | ||
1106 | some company decided to put a matching pattern all over the empty | ||
1107 | storage area of their music players. | ||
1108 | |||
1109 | udev 102 | ||
1110 | ======== | ||
1111 | Fix path_id for SAS devices. | ||
1112 | |||
1113 | udev 101 | ||
1114 | ======== | ||
1115 | The udev daemon can be started with --debug-trace now, which will | ||
1116 | execute all events serialized to get a chance to catch a possible | ||
1117 | action that crashes the box. | ||
1118 | |||
1119 | A warning is logged, if PHYSDEV* keys, the "device" link, or a parent | ||
1120 | device attribute like $attr{../file} is used, only WAIT_FOR_SYSFS rules | ||
1121 | are excluded from the warning. Referencing parent attributes directly | ||
1122 | may break when something in the kernel driver model changes. Udev will | ||
1123 | just find the attribute by walking up the parent chain. | ||
1124 | |||
1125 | Udevtrigger now sorts the list of devices depending on the device | ||
1126 | dependency, so a "usb" device is triggered after the parent "pci" | ||
1127 | device. | ||
1128 | |||
1129 | udev 100 | ||
1130 | ======== | ||
1131 | Revert persistent-storage ata-serial '_' '-' replacement. | ||
1132 | |||
1133 | udev 099 | ||
1134 | ======== | ||
1135 | Bugfixes. | ||
1136 | |||
1137 | Udevtrigger can now filter the list of devices to be triggered. Matches | ||
1138 | for subsystems or sysfs attributes can be specified. | ||
1139 | |||
1140 | The entries in /dev/.udev/queue and /dev/.udev/failed have changed to | ||
1141 | zero-sized files to avoid pointing to /sys and confuse broken tools which | ||
1142 | scan the /dev directory. To retry failed events, udevtrigger --retry-failed | ||
1143 | should be used now. | ||
1144 | |||
1145 | The rules and scripts to create udev rules for persistent network | ||
1146 | devices and optical drives are in the extras/rules_generator directory | ||
1147 | now. If you use something similar, please consider replacing your own | ||
1148 | version with this, to share the support effort. The rule_generator | ||
1149 | installs its own rules into /etc/udev/rules.d. | ||
1150 | |||
1151 | The cdrom_id tool installs its own rule now in /etc/udev/rules.d, cause | ||
1152 | the rule_generator depends on cdrom_id to be called in an earlier rule. | ||
1153 | |||
1154 | udev 098 | ||
1155 | ======== | ||
1156 | Bugfixes. | ||
1157 | |||
1158 | Renaming of some key names (the old names still work): | ||
1159 | BUS -> SUBSYSTEMS, ID -> KERNELS, SYSFS -> ATTRS, DRIVER -> DRIVERS. | ||
1160 | (The behavior of the key DRIVER will change soon in one of the next | ||
1161 | releases, to match only the event device, please switch to DRIVERS | ||
1162 | instead. If DRIVER is used, it will behave like DRIVERS, but an error | ||
1163 | is logged. | ||
1164 | With the new key names, we have a more consistent and simpler scheme. | ||
1165 | We can match the properties of the event device only, with: KERNEL, | ||
1166 | SUBSYSTEM, ATTR, DRIVER. Or include all the parent devices in the match, | ||
1167 | with: KERNELS, SUBSYSTEMS, ATTRS, DRIVERS. ID, BUS, SYSFS, DRIVER are no | ||
1168 | longer mentioned in the man page and should be switched in the rule | ||
1169 | files. | ||
1170 | |||
1171 | ATTR{file}="value" can be used now, to write to a sysfs file of the | ||
1172 | event device. Instead of: | ||
1173 | ..., SYSFS{type}=="0|7|14", RUN+="/bin/sh -c 'echo 60 > /sys$$DEVPATH/timeout'" | ||
1174 | we now can do: | ||
1175 | ..., ATTR{type}=="0|7|14", ATTR{timeout}="60" | ||
1176 | |||
1177 | All the PHYSDEV* keys are deprecated and will be removed from a | ||
1178 | future kernel: | ||
1179 | PHYDEVPATH - is the path of a parent device and should not be | ||
1180 | needed at all. | ||
1181 | PHYSDEVBUS - is just a SUBSYSTEM value of a parent, and can be | ||
1182 | matched with SUBSYSTEMS== | ||
1183 | PHYSDEVDRIVER - for bus devices it is available as ENV{DRIVER}. | ||
1184 | Newer kernels will have DRIVER in the environment, | ||
1185 | for older kernels udev puts in. Class device will | ||
1186 | no longer carry this property of a parent and | ||
1187 | DRIVERS== can be used to match such a parent value. | ||
1188 | Note that ENV{DRIVER} is only available for a few bus devices, where | ||
1189 | the driver is already bound at device event time. On coldplug, the | ||
1190 | events for a lot devices are already bound to a driver, and they will have | ||
1191 | that value set. But on hotplug, at the time the kernel creates the device, | ||
1192 | it can't know what driver may claim the device after that, therefore | ||
1193 | in most cases it will be empty. | ||
1194 | |||
1195 | Failed events should now be re-triggered with: | ||
1196 | udevtrigger --retry-failed. | ||
1197 | Please switch to this command, so we keep the details of the /dev/.udev/failed/ | ||
1198 | files private to the udev tools. We may need to switch the current symlink | ||
1199 | target, cause some obviously broken tools try to scan all files in /dev | ||
1200 | including /dev/.udev/, find the links to /sys and end up stat()'ing sysfs files | ||
1201 | million times. This takes ages on slow boxes. | ||
1202 | |||
1203 | The udevinfo attribute walk (-a) now works with giving a device node | ||
1204 | name (-n) instead of a devpath (-p). The query now always works, also when | ||
1205 | no database file was created by udev. | ||
1206 | |||
1207 | The built-in /etc/passwd /etc/group parser is removed, we always depend on | ||
1208 | getpwnam() and getgrnam() now. One of the next releases will depend on | ||
1209 | fnmatch() and may use getopt_long(). | ||
1210 | |||
1211 | udev 097 | ||
1212 | ======== | ||
1213 | Bugfixes and small improvements. | ||
1214 | |||
1215 | udev 096 | ||
1216 | ======== | ||
1217 | Fix path_id for recent kernels. | ||
1218 | |||
1219 | udev 095 | ||
1220 | ======== | ||
1221 | %e is finally gone. | ||
1222 | |||
1223 | Added support for swapping network interface names, by temporarily | ||
1224 | renaming the device and wait for the target name to become free. | ||
1225 | |||
1226 | udev 094 | ||
1227 | ======== | ||
1228 | The built-in MODALIAS key and substitution is removed. | ||
1229 | |||
1230 | udev 093 | ||
1231 | ======== | ||
1232 | The binary firmware helper is replaced by the usual simple | ||
1233 | shell script. Udevsend is removed from the tree. | ||
1234 | |||
1235 | udev 092 | ||
1236 | ======== | ||
1237 | Bugfix release. | ||
1238 | |||
1239 | udev 091 | ||
1240 | ======== | ||
1241 | Some more keys require the correct use of '==' and '=' depending | ||
1242 | on the kind of operation beeing an assignment or a match. Rules | ||
1243 | with invalid operations are skipped and logged to syslog. Please | ||
1244 | test with udevtest if the parsing of your rules throws errors and | ||
1245 | fix possibly broken rules. | ||
1246 | |||
1247 | udev 090 | ||
1248 | ======== | ||
1249 | Provide "udevsettle" to wait for all current udev events to finish. | ||
1250 | It also watches the current kernel netlink queue by comparing the | ||
1251 | even sequence number to make sure that there are no current pending | ||
1252 | events that have not already arrived in the daemon. | ||
1253 | |||
1254 | udev 089 | ||
1255 | ======== | ||
1256 | Fix rule to skip persistent rules for removable IDE devices, which | ||
1257 | also skipped optical IDE drives. | ||
1258 | |||
1259 | All *_id program are installed in /lib/udev/ by default now. | ||
1260 | |||
1261 | No binary is stripped anymore as this should be done in the | ||
1262 | packaging process and not at build time. | ||
1263 | |||
1264 | libvolume_id is provided as a shared library now and vol_id is | ||
1265 | linked against it. Also one of the next HAL versions will require | ||
1266 | this library, and the HAL build process will also require the | ||
1267 | header file to be installed. The copy of the same code in HAL will | ||
1268 | be removed to have only a single copy left on the system. | ||
1269 | |||
1270 | udev 088 | ||
1271 | ======== | ||
1272 | Add persistent links for SCSI tapes. The rules file is renamed | ||
1273 | to 60-persistent-storage.rules. | ||
1274 | |||
1275 | Create persistent path for usb devices. Can be used for all sorts | ||
1276 | of devices that can't be distinguished by other properties like | ||
1277 | multiple identical keyboards and mice connected to the same box. | ||
1278 | |||
1279 | Provide "udevtrigger" program to request events on coldplug. The | ||
1280 | shell script is much too slow with thousends of devices. | ||
1281 | |||
1282 | udev 087 | ||
1283 | ======== | ||
1284 | Fix persistent disk rules to exclude removable IDE drives. | ||
1285 | |||
1286 | Warn if %e, $modalias or MODALIAS is used. | ||
1287 | |||
1288 | udev 086 | ||
1289 | ======== | ||
1290 | Fix queue export, which wasn't correct for subsequent add/remove | ||
1291 | events for the same device. | ||
1292 | |||
1293 | udev 085 | ||
1294 | ======== | ||
1295 | Fix cramfs detection on big endian. | ||
1296 | |||
1297 | Make WAIT_FOR_SYSFS usable in "normal" rules and silent if the whole | ||
1298 | device goes away. | ||
1299 | |||
1300 | udev 084 | ||
1301 | ======== | ||
1302 | If BUS== and SYSFS{}== have been used in the same rule, the sysfs | ||
1303 | attributes were only checked at the parent device that matched the | ||
1304 | by BUS requested subsystem. Fix it to also look at the device we | ||
1305 | received the event for. | ||
1306 | |||
1307 | Build variable CROSS has changed to CROSS_COMPILE to match the kernel | ||
1308 | build name. | ||
1309 | |||
1310 | udev 083 | ||
1311 | ======== | ||
1312 | Fix a bug where NAME="" would prevent RUN from beeing executed. | ||
1313 | |||
1314 | RUN="/bin/program" does not longer automatically add the subsystem | ||
1315 | as the first parameter. This is from the days of /sbin/hotplug | ||
1316 | which is dead now and it's just confusing to need to add a space at | ||
1317 | the end of the program name to prevent this. | ||
1318 | If you use rules that need the subsystem as the first parameter, | ||
1319 | like the old "udev_run_hotlugd" and "udev_run_devd", add the subsystem | ||
1320 | to the key like RUN+="/bin/program $env{SUBSYSTEM}". | ||
1321 | |||
1322 | udev 082 | ||
1323 | ======== | ||
1324 | The udev man page has moved to udev(7) as it does not describe a command | ||
1325 | anymore. The programs udev, udevstart and udevsend are no longer installed | ||
1326 | by default and must be copied manually, if they should be installed or | ||
1327 | included in a package. | ||
1328 | |||
1329 | Fix a bug where "ignore_device" could run earlier collected RUN keys before | ||
1330 | the ignore rule was applied. | ||
1331 | |||
1332 | More preparation for future sysfs changes. usb_id and scsi_id no longer | ||
1333 | depend on a magic order of devices in the /devices chain. Specific devices | ||
1334 | should be requested by their subsytem. | ||
1335 | |||
1336 | This will always find the scsi parent device without depending on a specific | ||
1337 | path position: | ||
1338 | dev = sysfs_device_get(devpath); | ||
1339 | dev_usb = sysfs_device_get_parent_with_subsystem(dev, "scsi"); | ||
1340 | |||
1341 | The "device" link in the current sysfs layout will be automatically | ||
1342 | _resolved_ as a parent and in the new sysfs layout it will just _be_ the | ||
1343 | parent in the devpath. If a device is requested by it's symlink, like all | ||
1344 | class devices in the new sysfs layout will look like, it gets automatically | ||
1345 | resolved and substituted with the real devpath and not the symlink path. | ||
1346 | |||
1347 | Note: | ||
1348 | A similar logic must be applied to _all_ sysfs users, including | ||
1349 | scripts, that search along parent devices in sysfs. The explicit use of | ||
1350 | the "device" link must be avoided. With the future sysfs layout all | ||
1351 | DEVPATH's will start with /devices/ and have a "subsystem" symlink poiting | ||
1352 | back to the "class" or the "bus". The layout of the parent devices in | ||
1353 | /devices is not necessarily expected to be stable across kernel releases and | ||
1354 | searching for parents by their subsystem should make sysfs users tolerant | ||
1355 | for changed parent chains. | ||
1356 | |||
1357 | udev 081 | ||
1358 | ======== | ||
1359 | Prepare udev to work with the experimental kernel patch, that moves | ||
1360 | /sys/class devices to /sys/devices and /sys/block to /sys/class/block. | ||
1361 | |||
1362 | Clarify BUS, ID, $id usage and fix $id behavior. This prepares for | ||
1363 | moving the class devices to /sys/devices. | ||
1364 | |||
1365 | Thanks again to Marco for help finding a hopefully nice compromise | ||
1366 | to make %b simpler and working again. | ||
1367 | |||
1368 | udev 080 | ||
1369 | ======== | ||
1370 | Complete removal of libsysfs, replaced by simple helper functions | ||
1371 | which are much simpler and a bit faster. The udev daemon operatesentirely | ||
1372 | on event parameters and does not use sysfs for simple rules anymore. | ||
1373 | Please report any new bugs/problems, that may be caused by this big | ||
1374 | change. They will be fixed immediately. | ||
1375 | |||
1376 | The enumeration format character '%e' is deprecated and will be | ||
1377 | removed sometimes from a future udev version. It never worked correctly | ||
1378 | outside of udevstart, so we can't use it with the new parallel | ||
1379 | coldplug. A simple enumeration is as useless as the devfs naming | ||
1380 | scheme, just get rid of both if you still use it. | ||
1381 | |||
1382 | MODALIAS and $modalias is not needed and will be removed from one of | ||
1383 | the next udev versions, replace it in all rules with ENV{MODALIAS} or | ||
1384 | the sysfs "modalias" value. | ||
1385 | |||
1386 | Thanks a lot to Marco for all his help on finding and fixing bugs. | ||
1387 | |||
1388 | udev 079 | ||
1389 | ======== | ||
1390 | Let scsi_id request libata drive serial numbers from page 0x80. | ||
1391 | |||
1392 | Renamed etc/udev/persistent.rules to persistent-disk.rules and | ||
1393 | added /dev/disk/by-name/* for device mapper device names. | ||
1394 | |||
1395 | Removed %e from the man page. It never worked reliably outside | ||
1396 | of udevstart and udevstart is no longer recommended to use. | ||
1397 | |||
1398 | udev 078 | ||
1399 | ======== | ||
1400 | Symlinks are now exported to the event environment. Hopefully it's no | ||
1401 | longer needed to run udevinfo from an event process, like it was | ||
1402 | mentioned on the hotplug list: | ||
1403 | UDEV [1134776873.702967] add@/block/sdb | ||
1404 | ... | ||
1405 | DEVNAME=/dev/sdb | ||
1406 | DEVLINKS=/dev/disk/by-id/usb-IBM_Memory_Key_0218B301030027E8 /dev/disk/by-path/usb-0218B301030027E8:0:0:0 | ||
1407 | |||
1408 | udev 077 | ||
1409 | ======== | ||
1410 | Fix a problem if udevsend is used as the hotplug handler and tries to use | ||
1411 | syslog, which causes a "vc" event loop. 2.6.15 will make udevsend obsolete | ||
1412 | and this kind of problems will hopefully go away soon. | ||
1413 | |||
1414 | udev 076 | ||
1415 | ======== | ||
1416 | All built-in logic to work around bad sysfs timing is removed with this | ||
1417 | version. The need to wait for sysfs files is almost fixed with a kernel | ||
1418 | version that doesn't work with this udev version anyway. Until we fix | ||
1419 | the timing of the "bus" link creation, the former integrated logic should | ||
1420 | be emulated by a rule placed before all other rules: | ||
1421 | ACTION=="add", DEVPATH=="/devices/*", ENV{PHYSDEVBUS}=="?*", WAIT_FOR_SYSFS="bus" | ||
1422 | |||
1423 | The option "udev_db" does no longer exist. All udev state will be in | ||
1424 | /$udev_root/.udev/ now, there is no longer an option to set this | ||
1425 | to anything else. | ||
1426 | If the init script or something else used this value, just depend on | ||
1427 | this hardcoded path. But remember _all_content_ of this directory is | ||
1428 | still private to udev and can change at any time. | ||
1429 | |||
1430 | Default location for rule sripts and helper programs is now: /lib/udev/. | ||
1431 | Everything that is not useful on the commandline should go into this | ||
1432 | directory. Some of the helpers in the extras folder are installed there | ||
1433 | now. The rules need to be changed, to find the helpers there. | ||
1434 | |||
1435 | Also /lib/udev/devices is recommended as a directory where packages or | ||
1436 | the user can place real device nodes, which get copied over to /dev at | ||
1437 | every boot. This should replace the various solutions with custom config | ||
1438 | files. | ||
1439 | |||
1440 | Udevsend does no longer start the udev daemon. This must be done with | ||
1441 | the init script that prepares /dev on tmpfs and creates the initial nodes, | ||
1442 | before starting the daemon. | ||
1443 | |||
1444 | udev 075 | ||
1445 | ======== | ||
1446 | Silent a too verbose error logging for the old hotplug.d/ dev.d/ | ||
1447 | emulation. | ||
1448 | |||
1449 | The copy of klibc is removed. A systemwide installed version of klibc | ||
1450 | should be used to build a klibc udev now. | ||
1451 | |||
1452 | udev 074 | ||
1453 | ======== | ||
1454 | NAME="" will not create any nodes, but execute RUN keys. To completely | ||
1455 | ignore an event the OPTION "ignore_device" should be used. | ||
1456 | |||
1457 | After removal of the reorder queue, events with a TIMEOUT can be executed | ||
1458 | without any queuing now. | ||
1459 | |||
1460 | udev 073 | ||
1461 | ======== | ||
1462 | Fixed bug in udevd, if inotify is not available. We depend on netlink | ||
1463 | uevents now, kernels without that event source will not work with that | ||
1464 | version of udev anymore. | ||
1465 | |||
1466 | udev 072 | ||
1467 | ======== | ||
1468 | The rule parsing happens now in the daemon once at startup, all udev | ||
1469 | event processes inherit the already parsed rules from the daemon. | ||
1470 | It is shipped with SUSE10.0 and reduces heavily the system load at | ||
1471 | startup. The option to save precompiled rules and let the udev process | ||
1472 | pick the them up is removed, as it's no longer needed. | ||
1473 | |||
1474 | Kernel 2.6.15 will have symlinks at /class/input pointing to the real | ||
1475 | device. Libsysfs is changed to "translate" the requested link into the | ||
1476 | real device path, as it would happen with the hotplug event. Otherwise | ||
1477 | device removal and the udev database will not work. | ||
1478 | |||
1479 | Using 'make STRIPCMD=' will leave the binaries unstripped for debugging | ||
1480 | and packaging. | ||
1481 | |||
1482 | A few improvements for vol_id, the filesytem probing code. | ||
1483 | |||
1484 | udev 071 | ||
1485 | ======== | ||
1486 | Fix a stupid typo in extras/run_directory for "make install". | ||
1487 | |||
1488 | scsi_id creates the temporary devnode now in /dev for usage with a | ||
1489 | non-writable /tmp directory. | ||
1490 | |||
1491 | The uevent kernel socket buffer can carry app. 50.000 events now, | ||
1492 | let's see who can break this again. :) | ||
1493 | |||
1494 | The upcoming kernel will have a new input driver core integration. | ||
1495 | Some class devices are now symlinks to the real device. libsysfs | ||
1496 | needs a fix for this to work correctly. Udevstart of older udev | ||
1497 | versions will _not_ create these devices! | ||
1498 | |||
1499 | udev 070 | ||
1500 | ======== | ||
1501 | Fix a 'install' target in the Makefile, that prevents EXTRAS from | ||
1502 | beeing installed. | ||
1503 | |||
1504 | udev 069 | ||
1505 | ======== | ||
1506 | A bunch of mostly trivial bugfixes. From now on no node name or | ||
1507 | symlink name can contain any character than plain whitelisted ascii | ||
1508 | characters or validated utf8 byte-streams. This is needed for the | ||
1509 | /dev/disk/by-label/* links, because we import untrusted data and | ||
1510 | export it to the filesystem. | ||
1511 | |||
1512 | udev 068 | ||
1513 | ======== | ||
1514 | More bugfixes. If udevd was started from the kernel, we don't | ||
1515 | have stdin/stdout/stderr, which broke the forked tools in some | ||
1516 | situations. | ||
1517 | |||
1518 | udev 067 | ||
1519 | ======== | ||
1520 | Bugfix. udevstart event ordering was broken for a long time. | ||
1521 | The new run_program() uncovered it, because /dev/null was not | ||
1522 | available while we try to run external programs. | ||
1523 | Now udevstart should create it before we run anything. | ||
1524 | |||
1525 | udev 066 | ||
1526 | ======== | ||
1527 | Minor bugfixes and some distro rules updates. If you don't have the | ||
1528 | persistent disk rules in /dev/disk/by-*/* on your distro, just | ||
1529 | grab it from here. :) | ||
1530 | |||
1531 | udev 065 | ||
1532 | ======== | ||
1533 | We can use socket communication now to pass events from udev to | ||
1534 | other programs: | ||
1535 | RUN+="socket:/org/freedesktop/hal/udev_event" | ||
1536 | will pass the whole udev event to the HAL daemon without the need | ||
1537 | for a forked helper. (See ChangeLog for udevmonitor, as an example) | ||
1538 | |||
1539 | udev 064 | ||
1540 | ======== | ||
1541 | Mostly bugfixes and see ChangeLog. | ||
1542 | |||
1543 | The test for the existence of an environment value should be | ||
1544 | switched from: | ||
1545 | ENV{KEY}=="*" to ENV{KEY}=="?*" | ||
1546 | because "*" will not fail anymore, if the key does not exist or | ||
1547 | is empty. | ||
1548 | |||
1549 | udev 063 | ||
1550 | ======== | ||
1551 | Bugfixes and a few tweaks described in the ChangeLog. | ||
1552 | |||
1553 | udev 062 | ||
1554 | ======== | ||
1555 | Mostly a Bugfix release. | ||
1556 | |||
1557 | Added WAIT_FOR_SYSFS="<attribute>" to be able to fight against the sysfs | ||
1558 | timing with custom rules. | ||
1559 | |||
1560 | udev 061 | ||
1561 | ======== | ||
1562 | We changed the internal rule storage format. Our large rule files took | ||
1563 | 2 MB of RAM, with the change we are down to 99kB. | ||
1564 | |||
1565 | If the device-node has been created with default name and no symlink or | ||
1566 | options are to remenber, it is not longer stored in the udevdb. HAL will | ||
1567 | need to be updated to work correctly with that change. | ||
1568 | |||
1569 | To overrride optimization flags, OPTFLAGS may be used now. | ||
1570 | |||
1571 | udev 060 | ||
1572 | ======== | ||
1573 | Bugfix release. | ||
1574 | |||
1575 | udev 059 | ||
1576 | ======== | ||
1577 | Major changes happened with this release. The goal is to take over the | ||
1578 | complete kernel-event handling and provide a more efficient way to dispatch | ||
1579 | kernel events. Replacing most of the current shell script logic and the | ||
1580 | kernel forked helper with a netlink-daemon and a rule-based event handling. | ||
1581 | |||
1582 | o udevd listens to netlink events now. The first valid netlink event | ||
1583 | will make udevd ignore any message from udevsend that contains a | ||
1584 | SEQNUM, to avoid duplicate events. The forked events can be disabled | ||
1585 | with: | ||
1586 | echo "" > /proc/sys/kernel/hotplug | ||
1587 | For full support, the broken input-subsytem needs to be fixed, not to | ||
1588 | bypass the driver core. | ||
1589 | |||
1590 | o /etc/dev.d/ + /etc/hotplug.d/ directory multiplexing is completely | ||
1591 | removed from udev itself and must be emulated by calling small | ||
1592 | helper binaries provided in the extras folder: | ||
1593 | make EXTRAS=extras/run_directory/ | ||
1594 | will build udev_run_devd and udev_run_hotplugd, which can be called | ||
1595 | from a rule if needed: | ||
1596 | RUN+="/sbin/udev_run_hotplugd" | ||
1597 | The recommended way to handle this is to convert all the calls from | ||
1598 | the directories to explicit udev rules and get completely rid of the | ||
1599 | multiplexing. (To catch a ttyUSB event, you now no longer need to | ||
1600 | fork and exit 300 tty script instances you are not interested in, it | ||
1601 | is just one rule that matches exactly the device.) | ||
1602 | |||
1603 | o udev handles now _all_ events not just events for class and block | ||
1604 | devices, this way it is possible to control the complete event | ||
1605 | behavior with udev rules. Especially useful for rules like: | ||
1606 | ACTION="add", DEVPATH="/devices/*", MODALIAS=="?*", RUN+="/sbin/modprobe $modalias" | ||
1607 | |||
1608 | o As used in the modalias rule, udev supports now textual | ||
1609 | substitution placeholder along with the usual format chars. This | ||
1610 | needs to be documented, for now it's only visible in udev_rules_parse.c. | ||
1611 | |||
1612 | o The rule keys support now more operations. This is documented in the | ||
1613 | man page. It is possible to add values to list-keys like the SYMLINK | ||
1614 | and RUN list with KEY+="value" and to clear the list by assigning KEY="". | ||
1615 | Also "final"-assignments are supported by using KEY:="value", which will | ||
1616 | prevent changing the key by any later rule. | ||
1617 | |||
1618 | o kernel 2.6.12 has the "detached_state" attribute removed from | ||
1619 | sysfs, which was used to recognize sysfs population. We switched that | ||
1620 | to wait for the "bus" link, which is only available in kernels after 2.6.11. | ||
1621 | Running this udev version on older kernels may cause a short delay for | ||
1622 | some events. | ||
1623 | |||
1624 | o To provide infrastructure for persistent device naming, the id programs: | ||
1625 | scsi_id, vol_id (former udev_volume_id), and ata_id (new) are able now | ||
1626 | to export the probed data in environment key format: | ||
1627 | pim:~ # /sbin/ata_id --export /dev/hda | ||
1628 | ID_MODEL=HTS726060M9AT00 | ||
1629 | ID_SERIAL=MRH401M4G6UM9B | ||
1630 | ID_REVISION=MH4OA6BA | ||
1631 | |||
1632 | The following rules: | ||
1633 | KERNEL="hd*[!0-9]", IMPORT="/sbin/ata_id --export $tempnode" | ||
1634 | KERNEL="hd*[!0-9]", ENV{ID_SERIAL}=="?*", SYMLINK+="disk/by-id/$env{ID_MODEL}_$env{ID_SERIAL}" | ||
1635 | |||
1636 | Will create: | ||
1637 | kay@pim:~> tree /dev/disk | ||
1638 | /dev/disk | ||
1639 | |-- by-id | ||
1640 | | |-- HTS726060M9AT00_MRH401M4G6UM9B -> ../../hda | ||
1641 | | `-- IBM-Memory_Key -> ../../sda | ||
1642 | |-- by-label | ||
1643 | | |-- swap -> ../../hda1 | ||
1644 | | |-- date -> ../../sda1 | ||
1645 | | `-- home -> ../../hda3 | ||
1646 | `-- by-uuid | ||
1647 | |-- 2E08712B0870F2E7 -> ../../hda3 | ||
1648 | |-- 9352cfef-7687-47bc-a2a3-34cf136f72e1 -> ../../hda1 | ||
1649 | |-- E845-7A89 -> ../../sda1 | ||
1650 | `-- b2a61681-3812-4f13-a4ff-920d70604299 -> ../../hda2 | ||
1651 | |||
1652 | The IMPORT= operation will import these keys in the environment and make | ||
1653 | it available for later PROGRAM= and RUN= executed programs. The keys are | ||
1654 | also stored in the udevdb and can be queried from there with one of the | ||
1655 | next udev versions. | ||
1656 | |||
1657 | o A few binaries are silently added to the repository, which can be used | ||
1658 | to replay kernel events from initramfs instead of using coldplug. udevd | ||
1659 | can be instructed now to queue-up events while the stored events from | ||
1660 | initramfs are filled into the udevd-queue. This code is still under | ||
1661 | development and there is no documentation now besides the code itself. | ||
1662 | The additional binaries get compiled, but are not installed by default. | ||
1663 | |||
1664 | o There is also a temporary fix for a performance problem where too many | ||
1665 | events happen in parallel and every event needs to parse the rules. | ||
1666 | udev can now read precompiled rules stored on disk. This is likely to be | ||
1667 | replaced by a more elegant solution in a future udev version. | ||
1668 | |||
1669 | udev 058 | ||
1670 | ======== | ||
1671 | With kernel version 2.6.12, the sysfs file "detached_state" was removed. | ||
1672 | Fix for libsysfs not to expect this file was added. | ||
1673 | |||
1674 | udev 057 | ||
1675 | ======== | ||
1676 | All rules are applied now, but only the first matching rule with a NAME-key | ||
1677 | will be applied. All later rules with NAME-key are completely ignored. This | ||
1678 | way system supplied symlinks or permissions gets applied to user-defined | ||
1679 | naming rules. | ||
1680 | |||
1681 | Note: | ||
1682 | Please check your rules setup, if you may need to add OPTIONS="last_rule" | ||
1683 | to some rules, to keep the old behavior. | ||
1684 | |||
1685 | The rules are read on "remove"-events too. That makes is possible to match | ||
1686 | with keys that are available on remove (KERNEL, SUBSYSTEM, ID, ENV, ...) to | ||
1687 | instruct udev to ignore an event (OPTIONS="ignore_device"). | ||
1688 | The new ACTION-key may be used to let a rule act only at a "remove"-event. | ||
1689 | |||
1690 | The new RUN-key supports rule-based execution of programs after device-node | ||
1691 | handling. This is meant as a general replacement for the dev.d/-directories | ||
1692 | to give fine grained control over the execution of programs. | ||
1693 | |||
1694 | The %s{}-sysfs format char replacement values are searched at any of the | ||
1695 | devices in the device chain now, not only at the class-device. | ||
1696 | |||
1697 | We support log priority levels now. The value udev_log in udev.conf is used | ||
1698 | to determine what is printed to syslog. This makes it possible to | ||
1699 | run a version with compiled-in debug messages in a production environment | ||
1700 | which is sometimes needed to find a bug. | ||
1701 | It is still possible to supress the inclusion of _any_ syslog usage with | ||
1702 | USE_LOG=false to create the smallest possible binaries if needed. | ||
1703 | The configured udev_log value can be overridden with the environment variable | ||
1704 | UDEV_LOG. | ||
1705 | |||
1706 | udev 056 | ||
1707 | ======== | ||
1708 | Possible use of a system-wide klibc: | ||
1709 | make USE_KLIBC=true KLCC=/usr/bin/klcc all | ||
1710 | will link against an external klibc and our own version will be ignored. | ||
1711 | |||
1712 | udev 055 | ||
1713 | ======== | ||
1714 | We support an unlimited count of symlinks now. | ||
1715 | |||
1716 | If USE_STATIC=true is passed to a glibc build, we link statically and use | ||
1717 | a built-in userdb parser to resolve user and group names. | ||
1718 | |||
1719 | The PLACE= key is gone. It can be replaced by an ID= for a long time, because | ||
1720 | we walk up the chain of physical devices to find a match. | ||
1721 | |||
1722 | The KEY="<value>" format supports '=', '==', '!=,' , '+=' now. This makes it | ||
1723 | easy to skip certain attribute matches without composing rules with weird | ||
1724 | character class negations like: | ||
1725 | KERNEL="[!s][!c][!d]*" | ||
1726 | this can now be replaced with: | ||
1727 | KERNEL!="scd*" | ||
1728 | The current simple '=' is still supported, and should work as it does today, | ||
1729 | but existing rules should be converted if possible, to be better readable. | ||
1730 | |||
1731 | We have new ENV{}== key now, to match against a maximum of 5 environment | ||
1732 | variables. | ||
1733 | |||
1734 | udevstart is its own binary again, because we don't need co carry this araound | ||
1735 | with every forked event. | ||
diff --git a/src/udev/README b/src/udev/README new file mode 100644 index 000000000..38459c6b2 --- /dev/null +++ b/src/udev/README | |||
@@ -0,0 +1,101 @@ | |||
1 | udev - Linux userspace device management | ||
2 | |||
3 | Integrating udev in the system has complex dependencies and may differ from | ||
4 | distribution to distribution. A system may not be able to boot up or work | ||
5 | reliably without a properly installed udev version. The upstream udev project | ||
6 | does not recommend replacing a distro's udev installation with the upstream | ||
7 | version. | ||
8 | |||
9 | The upstream udev project's set of default rules may require a most recent | ||
10 | kernel release to work properly. | ||
11 | |||
12 | Tools and rules shipped by udev are not public API and may change at any time. | ||
13 | Never call any private tool in /usr/lib/udev from any external application; it | ||
14 | might just go away in the next release. Access to udev information is only offered | ||
15 | by udevadm and libudev. Tools and rules in /usr/lib/udev and the entire contents | ||
16 | of the /run/udev directory are private to udev and do change whenever needed. | ||
17 | |||
18 | Requirements: | ||
19 | - Version 2.6.34 of the Linux kernel with sysfs, procfs, signalfd, inotify, | ||
20 | unix domain sockets, networking and hotplug enabled | ||
21 | |||
22 | - Some architectures might need a later kernel, that supports accept4(), | ||
23 | or need to backport the accept4() syscall wiring in the kernel. | ||
24 | |||
25 | - These options are required: | ||
26 | CONFIG_DEVTMPFS=y | ||
27 | CONFIG_HOTPLUG=y | ||
28 | CONFIG_INOTIFY_USER=y | ||
29 | CONFIG_NET=y | ||
30 | CONFIG_PROC_FS=y | ||
31 | CONFIG_SIGNALFD=y | ||
32 | CONFIG_SYSFS=y | ||
33 | CONFIG_SYSFS_DEPRECATED*=n | ||
34 | CONFIG_UEVENT_HELPER_PATH="" | ||
35 | |||
36 | - These options might be needed: | ||
37 | CONFIG_BLK_DEV_BSG=y (SCSI devices) | ||
38 | CONFIG_TMPFS_POSIX_ACL=y (user ACLs for device nodes) | ||
39 | |||
40 | - The /dev directory needs the 'devtmpfs' filesystem mounted. | ||
41 | Udev only manages the permissions and ownership of the | ||
42 | kernel-provided device nodes, and possibly creates additional symlinks. | ||
43 | |||
44 | - Udev requires /run to be writable, which is usually done by mounting a | ||
45 | 'tmpfs' filesystem. | ||
46 | |||
47 | - This version of udev does not work properly with the CONFIG_SYSFS_DEPRECATED* | ||
48 | option enabled. | ||
49 | |||
50 | - The deprecated hotplug helper /sbin/hotplug should be disabled in the | ||
51 | kernel configuration, it is not needed today, and may render the system | ||
52 | unusable because the kernel may create too many processes in parallel | ||
53 | so that the system runs out-of-memory. | ||
54 | |||
55 | - The proc filesystem must be mounted on /proc, and the sysfs filesystem must | ||
56 | be mounted at /sys. No other locations are supported by a standard | ||
57 | udev installation. | ||
58 | |||
59 | - The default rule sset requires the following group names resolvable at udev startup: | ||
60 | disk, cdrom, floppy, tape, audio, video, lp, tty, dialout, and kmem. | ||
61 | Especially in LDAP setups, it is required that getgrnam() be able to resolve | ||
62 | these group names with only the rootfs mounted and while no network is | ||
63 | available. | ||
64 | |||
65 | - Some udev extras have external dependencies like: | ||
66 | libglib2, usbutils, pciutils, and gperf. | ||
67 | All these extras can be disabled with configure options. | ||
68 | |||
69 | Setup: | ||
70 | - The udev daemon should be started to handle device events sent by the kernel. | ||
71 | During bootup, the events for already existing devices can be replayed, so | ||
72 | that they are configured by udev. The systemd service files contain the | ||
73 | needed commands to start the udev daemon and the coldplug sequence. | ||
74 | |||
75 | - Restarting the daemon never applies any rules to existing devices. | ||
76 | |||
77 | - New/changed rule files are picked up automatically; there is usually no | ||
78 | daemon restart or signal needed. | ||
79 | |||
80 | Operation: | ||
81 | - Based on events the kernel sends out on device creation/removal, udev | ||
82 | creates/removes device nodes and symlinks in the /dev directory. | ||
83 | |||
84 | - All kernel events are matched against a set of specified rules, which | ||
85 | possibly hook into the event processing and load required kernel | ||
86 | modules to set up devices. For all devices, the kernel exports a major/minor | ||
87 | number; if needed, udev creates a device node with the default kernel | ||
88 | device name. If specified, udev applies permissions/ownership to the device | ||
89 | node, creates additional symlinks pointing to the node, and executes | ||
90 | programs to handle the device. | ||
91 | |||
92 | - The events udev handles, and the information udev merges into its device | ||
93 | database, can be accessed with libudev: | ||
94 | http://www.kernel.org/pub/linux/utils/kernel/hotplug/libudev/ | ||
95 | http://www.kernel.org/pub/linux/utils/kernel/hotplug/gudev/ | ||
96 | |||
97 | For more details about udev and udev rules, see the udev man pages: | ||
98 | http://www.kernel.org/pub/linux/utils/kernel/hotplug/udev/ | ||
99 | |||
100 | Please direct any comment/question to the linux-hotplug mailing list at: | ||
101 | linux-hotplug@vger.kernel.org | ||
diff --git a/src/udev/TODO b/src/udev/TODO new file mode 100644 index 000000000..8b8b9c8f8 --- /dev/null +++ b/src/udev/TODO | |||
@@ -0,0 +1,22 @@ | |||
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 | - remove RUN+="socket:" | ||
17 | |||
18 | - libudev.so.1 | ||
19 | - symbol versioning | ||
20 | - return object with *_unref() | ||
21 | - udev_monitor_from_socket() | ||
22 | - udev_queue_get_failed_list_entry() | ||
diff --git a/src/udev/autogen.sh b/src/udev/autogen.sh new file mode 100755 index 000000000..55ee03afd --- /dev/null +++ b/src/udev/autogen.sh | |||
@@ -0,0 +1,44 @@ | |||
1 | #!/bin/sh -e | ||
2 | |||
3 | if [ -f .git/hooks/pre-commit.sample -a ! -f .git/hooks/pre-commit ] ; then | ||
4 | cp -p .git/hooks/pre-commit.sample .git/hooks/pre-commit && \ | ||
5 | chmod +x .git/hooks/pre-commit && \ | ||
6 | echo "Activated pre-commit hook." | ||
7 | fi | ||
8 | |||
9 | gtkdocize | ||
10 | autoreconf --install --symlink | ||
11 | |||
12 | libdir() { | ||
13 | echo $(cd $1/$(gcc -print-multi-os-directory); pwd) | ||
14 | } | ||
15 | |||
16 | args="$args \ | ||
17 | --prefix=/usr \ | ||
18 | --sysconfdir=/etc \ | ||
19 | --libdir=$(libdir /usr/lib) \ | ||
20 | --with-selinux \ | ||
21 | --enable-gtk-doc" | ||
22 | |||
23 | if [ -L /bin ]; then | ||
24 | args="$args \ | ||
25 | --libexecdir=/usr/lib \ | ||
26 | --with-systemdsystemunitdir=/usr/lib/systemd/system \ | ||
27 | " | ||
28 | else | ||
29 | args="$args \ | ||
30 | --with-rootprefix= \ | ||
31 | ---with-rootlibdir=$(libdir /lib) \ | ||
32 | --bindir=/sbin \ | ||
33 | --libexecdir=/lib \ | ||
34 | --with-systemdsystemunitdir=/lib/systemd/system \ | ||
35 | " | ||
36 | fi | ||
37 | |||
38 | echo | ||
39 | echo "----------------------------------------------------------------" | ||
40 | echo "Initialized build system. For a common configuration please run:" | ||
41 | echo "----------------------------------------------------------------" | ||
42 | echo | ||
43 | echo "./configure CFLAGS='-g -O1' $args" | ||
44 | echo | ||
diff --git a/src/udev/configure.ac b/src/udev/configure.ac new file mode 100644 index 000000000..b31b62f28 --- /dev/null +++ b/src/udev/configure.ac | |||
@@ -0,0 +1,242 @@ | |||
1 | AC_PREREQ(2.60) | ||
2 | AC_INIT([udev], | ||
3 | [182], | ||
4 | [linux-hotplug@vger.kernel.org], | ||
5 | [udev], | ||
6 | [http://www.kernel.org/pub/linux/utils/kernel/hotplug/udev.html]) | ||
7 | AC_CONFIG_SRCDIR([src/udevd.c]) | ||
8 | AC_CONFIG_AUX_DIR([build-aux]) | ||
9 | AM_INIT_AUTOMAKE([check-news foreign 1.11 -Wall -Wno-portability silent-rules tar-pax no-dist-gzip dist-xz subdir-objects]) | ||
10 | AC_USE_SYSTEM_EXTENSIONS | ||
11 | AC_SYS_LARGEFILE | ||
12 | AC_CONFIG_MACRO_DIR([m4]) | ||
13 | AM_SILENT_RULES([yes]) | ||
14 | LT_INIT([disable-static]) | ||
15 | AC_PROG_AWK | ||
16 | AC_PROG_SED | ||
17 | AC_PROG_MKDIR_P | ||
18 | GTK_DOC_CHECK(1.10) | ||
19 | AC_PREFIX_DEFAULT([/usr]) | ||
20 | |||
21 | AC_PATH_PROG([XSLTPROC], [xsltproc]) | ||
22 | AM_CONDITIONAL(HAVE_XSLTPROC, test x"$XSLTPROC" != x) | ||
23 | |||
24 | AC_SEARCH_LIBS([clock_gettime], [rt], [], [AC_MSG_ERROR([POSIX RT library not found])]) | ||
25 | |||
26 | PKG_CHECK_MODULES(BLKID, blkid >= 2.20) | ||
27 | |||
28 | PKG_CHECK_MODULES(KMOD, libkmod >= 5) | ||
29 | |||
30 | AC_ARG_WITH([rootprefix], | ||
31 | AS_HELP_STRING([--with-rootprefix=DIR], [rootfs directory prefix for config files and kernel modules]), | ||
32 | [], [with_rootprefix=${ac_default_prefix}]) | ||
33 | AC_SUBST([rootprefix], [$with_rootprefix]) | ||
34 | |||
35 | AC_ARG_WITH([rootlibdir], | ||
36 | AS_HELP_STRING([--with-rootlibdir=DIR], [rootfs directory to install shared libraries]), | ||
37 | [], [with_rootlibdir=$libdir]) | ||
38 | AC_SUBST([rootlib_execdir], [$with_rootlibdir]) | ||
39 | |||
40 | AC_ARG_WITH([selinux], | ||
41 | AS_HELP_STRING([--with-selinux], [enable SELinux support]), | ||
42 | [], [with_selinux=no]) | ||
43 | AS_IF([test "x$with_selinux" = "xyes"], [ | ||
44 | LIBS_save=$LIBS | ||
45 | AC_CHECK_LIB(selinux, getprevcon, | ||
46 | [], | ||
47 | AC_MSG_ERROR([SELinux selected but libselinux not found])) | ||
48 | LIBS=$LIBS_save | ||
49 | SELINUX_LIBS="-lselinux -lsepol" | ||
50 | AC_DEFINE(WITH_SELINUX, [1] ,[SELinux support.]) | ||
51 | ]) | ||
52 | AC_SUBST([SELINUX_LIBS]) | ||
53 | AM_CONDITIONAL(WITH_SELINUX, [test "x$with_selinux" = "xyes"]) | ||
54 | |||
55 | AC_ARG_ENABLE([debug], | ||
56 | AS_HELP_STRING([--enable-debug], [enable debug messages @<:@default=disabled@:>@]), | ||
57 | [], [enable_debug=no]) | ||
58 | AS_IF([test "x$enable_debug" = "xyes"], [ AC_DEFINE(ENABLE_DEBUG, [1], [Debug messages.]) ]) | ||
59 | |||
60 | AC_ARG_ENABLE([logging], | ||
61 | AS_HELP_STRING([--disable-logging], [disable system logging @<:@default=enabled@:>@]), | ||
62 | [], enable_logging=yes) | ||
63 | AS_IF([test "x$enable_logging" = "xyes"], [ AC_DEFINE(ENABLE_LOGGING, [1], [System logging.]) ]) | ||
64 | |||
65 | AC_ARG_ENABLE([manpages], | ||
66 | AS_HELP_STRING([--disable-manpages], [disable man pages @<:@default=enabled@:>@]), | ||
67 | [], enable_manpages=yes) | ||
68 | AM_CONDITIONAL([ENABLE_MANPAGES], [test "x$enable_manpages" = "xyes"]) | ||
69 | |||
70 | if test "x$cross_compiling" = "xno" ; then | ||
71 | AC_CHECK_FILES([/usr/share/pci.ids], [pciids=/usr/share/pci.ids]) | ||
72 | AC_CHECK_FILES([/usr/share/hwdata/pci.ids], [pciids=/usr/share/hwdata/pci.ids]) | ||
73 | AC_CHECK_FILES([/usr/share/misc/pci.ids], [pciids=/usr/share/misc/pci.ids]) | ||
74 | fi | ||
75 | |||
76 | AC_ARG_WITH(usb-ids-path, | ||
77 | [AS_HELP_STRING([--with-usb-ids-path=DIR], [Path to usb.ids file])], | ||
78 | [USB_DATABASE=${withval}], | ||
79 | [if test -n "$usbids" ; then | ||
80 | USB_DATABASE="$usbids" | ||
81 | else | ||
82 | PKG_CHECK_MODULES(USBUTILS, usbutils >= 0.82) | ||
83 | AC_SUBST([USB_DATABASE], [$($PKG_CONFIG --variable=usbids usbutils)]) | ||
84 | fi]) | ||
85 | AC_MSG_CHECKING([for USB database location]) | ||
86 | AC_MSG_RESULT([$USB_DATABASE]) | ||
87 | AC_SUBST(USB_DATABASE) | ||
88 | |||
89 | AC_ARG_WITH(pci-ids-path, | ||
90 | [AS_HELP_STRING([--with-pci-ids-path=DIR], [Path to pci.ids file])], | ||
91 | [PCI_DATABASE=${withval}], | ||
92 | [if test -n "$pciids" ; then | ||
93 | PCI_DATABASE="$pciids" | ||
94 | else | ||
95 | AC_MSG_ERROR([pci.ids not found, try --with-pci-ids-path=]) | ||
96 | fi]) | ||
97 | AC_MSG_CHECKING([for PCI database location]) | ||
98 | AC_MSG_RESULT([$PCI_DATABASE]) | ||
99 | AC_SUBST(PCI_DATABASE) | ||
100 | |||
101 | AC_ARG_WITH(firmware-path, | ||
102 | AS_HELP_STRING([--with-firmware-path=DIR[[[:DIR[...]]]]], | ||
103 | [Firmware search path (default=ROOTPREFIX/lib/firmware/updates:ROOTPREFIX/lib/firmware)]), | ||
104 | [], [with_firmware_path="$rootprefix/lib/firmware/updates:$rootprefix/lib/firmware"]) | ||
105 | OLD_IFS=$IFS | ||
106 | IFS=: | ||
107 | for i in $with_firmware_path; do | ||
108 | if test "x${FIRMWARE_PATH}" = "x"; then | ||
109 | FIRMWARE_PATH="\\\"${i}/\\\"" | ||
110 | else | ||
111 | FIRMWARE_PATH="${FIRMWARE_PATH}, \\\"${i}/\\\"" | ||
112 | fi | ||
113 | done | ||
114 | IFS=$OLD_IFS | ||
115 | AC_SUBST([FIRMWARE_PATH], [$FIRMWARE_PATH]) | ||
116 | |||
117 | AC_ARG_WITH([systemdsystemunitdir], | ||
118 | AS_HELP_STRING([--with-systemdsystemunitdir=DIR], [Directory for systemd service files]), | ||
119 | [], [with_systemdsystemunitdir=$($PKG_CONFIG --variable=systemdsystemunitdir systemd)]) | ||
120 | AS_IF([test "x$with_systemdsystemunitdir" != "xno"], [ AC_SUBST([systemdsystemunitdir], [$with_systemdsystemunitdir]) ]) | ||
121 | AM_CONDITIONAL(WITH_SYSTEMD, [test -n "$with_systemdsystemunitdir" -a "x$with_systemdsystemunitdir" != "xno" ]) | ||
122 | |||
123 | # ------------------------------------------------------------------------------ | ||
124 | # GUdev - libudev gobject interface | ||
125 | # ------------------------------------------------------------------------------ | ||
126 | AC_ARG_ENABLE([gudev], | ||
127 | AS_HELP_STRING([--disable-gudev], [disable Gobject libudev support @<:@default=enabled@:>@]), | ||
128 | [], [enable_gudev=yes]) | ||
129 | AS_IF([test "x$enable_gudev" = "xyes"], [ PKG_CHECK_MODULES([GLIB], [glib-2.0 >= 2.22.0 gobject-2.0 >= 2.22.0]) ]) | ||
130 | |||
131 | AC_ARG_ENABLE([introspection], | ||
132 | AS_HELP_STRING([--disable-introspection], [disable GObject introspection @<:@default=enabled@:>@]), | ||
133 | [], [enable_introspection=yes]) | ||
134 | AS_IF([test "x$enable_introspection" = "xyes"], [ | ||
135 | PKG_CHECK_MODULES([INTROSPECTION], [gobject-introspection-1.0 >= 0.6.2]) | ||
136 | AC_DEFINE([ENABLE_INTROSPECTION], [1], [enable GObject introspection support]) | ||
137 | AC_SUBST([G_IR_SCANNER], [$($PKG_CONFIG --variable=g_ir_scanner gobject-introspection-1.0)]) | ||
138 | AC_SUBST([G_IR_COMPILER], [$($PKG_CONFIG --variable=g_ir_compiler gobject-introspection-1.0)]) | ||
139 | AC_SUBST([G_IR_GENERATE], [$($PKG_CONFIG --variable=g_ir_generate gobject-introspection-1.0)]) | ||
140 | AC_SUBST([GIRDIR], [$($PKG_CONFIG --define-variable=datadir=${datadir} --variable=girdir gobject-introspection-1.0)]) | ||
141 | AC_SUBST([GIRTYPELIBDIR], [$($PKG_CONFIG --define-variable=libdir=${libdir} --variable=typelibdir gobject-introspection-1.0)]) | ||
142 | ]) | ||
143 | AM_CONDITIONAL([ENABLE_INTROSPECTION], [test "x$enable_introspection" = "xyes"]) | ||
144 | AM_CONDITIONAL([ENABLE_GUDEV], [test "x$enable_gudev" = "xyes"]) | ||
145 | |||
146 | # ------------------------------------------------------------------------------ | ||
147 | # keymap - map custom hardware's multimedia keys | ||
148 | # ------------------------------------------------------------------------------ | ||
149 | AC_ARG_ENABLE([keymap], | ||
150 | AS_HELP_STRING([--disable-keymap], [disable keymap fixup support @<:@default=enabled@:>@]), | ||
151 | [], [enable_keymap=yes]) | ||
152 | AS_IF([test "x$enable_keymap" = "xyes"], [ | ||
153 | AC_PATH_PROG([GPERF], [gperf]) | ||
154 | if test -z "$GPERF"; then | ||
155 | AC_MSG_ERROR([gperf is needed]) | ||
156 | fi | ||
157 | |||
158 | AC_CHECK_HEADER([linux/input.h], [:], AC_MSG_ERROR([kernel headers not found])) | ||
159 | AC_SUBST([INCLUDE_PREFIX], [$(echo '#include <linux/input.h>' | eval $ac_cpp -E - | sed -n '/linux\/input.h/ {s:.*"\(.*\)/linux/input.h".*:\1:; p; q}')]) | ||
160 | ]) | ||
161 | AM_CONDITIONAL([ENABLE_KEYMAP], [test "x$enable_keymap" = "xyes"]) | ||
162 | |||
163 | # ------------------------------------------------------------------------------ | ||
164 | # mtd_probe - autoloads FTL module for mtd devices | ||
165 | # ------------------------------------------------------------------------------ | ||
166 | AC_ARG_ENABLE([mtd_probe], | ||
167 | AS_HELP_STRING([--disable-mtd_probe], [disable MTD support @<:@default=enabled@:>@]), | ||
168 | [], [enable_mtd_probe=yes]) | ||
169 | AM_CONDITIONAL([ENABLE_MTD_PROBE], [test "x$enable_mtd_probe" = "xyes"]) | ||
170 | |||
171 | # ------------------------------------------------------------------------------ | ||
172 | # rule_generator - persistent network and optical device rule generator | ||
173 | # ------------------------------------------------------------------------------ | ||
174 | AC_ARG_ENABLE([rule_generator], | ||
175 | AS_HELP_STRING([--enable-rule_generator], [enable persistent network + cdrom links support @<:@default=disabled@:>@]), | ||
176 | [], [enable_rule_generator=no]) | ||
177 | AM_CONDITIONAL([ENABLE_RULE_GENERATOR], [test "x$enable_rule_generator" = "xyes"]) | ||
178 | |||
179 | # ------------------------------------------------------------------------------ | ||
180 | # create_floppy_devices - historical floppy kernel device nodes (/dev/fd0h1440, ...) | ||
181 | # ------------------------------------------------------------------------------ | ||
182 | AC_ARG_ENABLE([floppy], | ||
183 | AS_HELP_STRING([--enable-floppy], [enable legacy floppy support @<:@default=disabled@:>@]), | ||
184 | [], [enable_floppy=no]) | ||
185 | AM_CONDITIONAL([ENABLE_FLOPPY], [test "x$enable_floppy" = "xyes"]) | ||
186 | |||
187 | my_CFLAGS="-Wall \ | ||
188 | -Wmissing-declarations -Wmissing-prototypes \ | ||
189 | -Wnested-externs -Wpointer-arith \ | ||
190 | -Wpointer-arith -Wsign-compare -Wchar-subscripts \ | ||
191 | -Wstrict-prototypes -Wshadow \ | ||
192 | -Wformat-security -Wtype-limits" | ||
193 | AC_SUBST([my_CFLAGS]) | ||
194 | |||
195 | AC_CONFIG_HEADERS(config.h) | ||
196 | AC_CONFIG_FILES([ | ||
197 | Makefile | ||
198 | src/docs/Makefile | ||
199 | src/docs/version.xml | ||
200 | src/gudev/docs/Makefile | ||
201 | src/gudev/docs/version.xml | ||
202 | ]) | ||
203 | |||
204 | AC_OUTPUT | ||
205 | AC_MSG_RESULT([ | ||
206 | $PACKAGE $VERSION | ||
207 | ======== | ||
208 | |||
209 | prefix: ${prefix} | ||
210 | rootprefix: ${rootprefix} | ||
211 | sysconfdir: ${sysconfdir} | ||
212 | bindir: ${bindir} | ||
213 | libdir: ${libdir} | ||
214 | rootlibdir: ${rootlib_execdir} | ||
215 | libexecdir: ${libexecdir} | ||
216 | datarootdir: ${datarootdir} | ||
217 | mandir: ${mandir} | ||
218 | includedir: ${includedir} | ||
219 | include_prefix: ${INCLUDE_PREFIX} | ||
220 | systemdsystemunitdir: ${systemdsystemunitdir} | ||
221 | firmware path: ${FIRMWARE_PATH} | ||
222 | usb.ids: ${USB_DATABASE} | ||
223 | pci.ids: ${PCI_DATABASE} | ||
224 | |||
225 | compiler: ${CC} | ||
226 | cflags: ${CFLAGS} | ||
227 | ldflags: ${LDFLAGS} | ||
228 | xsltproc: ${XSLTPROC} | ||
229 | gperf: ${GPERF} | ||
230 | |||
231 | logging: ${enable_logging} | ||
232 | debug: ${enable_debug} | ||
233 | selinux: ${with_selinux} | ||
234 | |||
235 | man pages ${enable_manpages} | ||
236 | gudev: ${enable_gudev} | ||
237 | gintrospection: ${enable_introspection} | ||
238 | keymap: ${enable_keymap} | ||
239 | mtd_probe: ${enable_mtd_probe} | ||
240 | rule_generator: ${enable_rule_generator} | ||
241 | floppy: ${enable_floppy} | ||
242 | ]) | ||
diff --git a/src/udev/m4/.gitignore b/src/udev/m4/.gitignore new file mode 100644 index 000000000..0ca2c0372 --- /dev/null +++ b/src/udev/m4/.gitignore | |||
@@ -0,0 +1,4 @@ | |||
1 | libtool.m4 | ||
2 | lt*m4 | ||
3 | gtk-doc.m4 | ||
4 | |||
diff --git a/src/udev/rules/42-usb-hid-pm.rules b/src/udev/rules/42-usb-hid-pm.rules new file mode 100644 index 000000000..d5d5897c3 --- /dev/null +++ b/src/udev/rules/42-usb-hid-pm.rules | |||
@@ -0,0 +1,49 @@ | |||
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" | ||
diff --git a/src/udev/rules/50-udev-default.rules b/src/udev/rules/50-udev-default.rules new file mode 100644 index 000000000..5ad787fc7 --- /dev/null +++ b/src/udev/rules/50-udev-default.rules | |||
@@ -0,0 +1,107 @@ | |||
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" | ||
diff --git a/src/udev/rules/60-persistent-alsa.rules b/src/udev/rules/60-persistent-alsa.rules new file mode 100644 index 000000000..8154e2dbb --- /dev/null +++ b/src/udev/rules/60-persistent-alsa.rules | |||
@@ -0,0 +1,14 @@ | |||
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" | ||
diff --git a/src/udev/rules/60-persistent-input.rules b/src/udev/rules/60-persistent-input.rules new file mode 100644 index 000000000..fb798ddb0 --- /dev/null +++ b/src/udev/rules/60-persistent-input.rules | |||
@@ -0,0 +1,38 @@ | |||
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" | ||
diff --git a/src/udev/rules/60-persistent-serial.rules b/src/udev/rules/60-persistent-serial.rules new file mode 100644 index 000000000..2948200c5 --- /dev/null +++ b/src/udev/rules/60-persistent-serial.rules | |||
@@ -0,0 +1,20 @@ | |||
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" | ||
diff --git a/src/udev/rules/60-persistent-storage-tape.rules b/src/udev/rules/60-persistent-storage-tape.rules new file mode 100644 index 000000000..f2eabd92a --- /dev/null +++ b/src/udev/rules/60-persistent-storage-tape.rules | |||
@@ -0,0 +1,25 @@ | |||
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" | ||
diff --git a/src/udev/rules/60-persistent-storage.rules b/src/udev/rules/60-persistent-storage.rules new file mode 100644 index 000000000..b74821edd --- /dev/null +++ b/src/udev/rules/60-persistent-storage.rules | |||
@@ -0,0 +1,89 @@ | |||
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" | ||
diff --git a/src/udev/rules/75-net-description.rules b/src/udev/rules/75-net-description.rules new file mode 100644 index 000000000..ce57d48e8 --- /dev/null +++ b/src/udev/rules/75-net-description.rules | |||
@@ -0,0 +1,14 @@ | |||
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" | ||
diff --git a/src/udev/rules/75-tty-description.rules b/src/udev/rules/75-tty-description.rules new file mode 100644 index 000000000..2e63e140c --- /dev/null +++ b/src/udev/rules/75-tty-description.rules | |||
@@ -0,0 +1,14 @@ | |||
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" | ||
diff --git a/src/udev/rules/78-sound-card.rules b/src/udev/rules/78-sound-card.rules new file mode 100644 index 000000000..e56444189 --- /dev/null +++ b/src/udev/rules/78-sound-card.rules | |||
@@ -0,0 +1,89 @@ | |||
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" | ||
diff --git a/src/udev/rules/80-drivers.rules b/src/udev/rules/80-drivers.rules new file mode 100644 index 000000000..38ebfeb0e --- /dev/null +++ b/src/udev/rules/80-drivers.rules | |||
@@ -0,0 +1,12 @@ | |||
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" | ||
diff --git a/src/udev/rules/95-udev-late.rules b/src/udev/rules/95-udev-late.rules new file mode 100644 index 000000000..eca0faa5c --- /dev/null +++ b/src/udev/rules/95-udev-late.rules | |||
@@ -0,0 +1,4 @@ | |||
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}" | ||
diff --git a/src/udev/src/.gitignore b/src/udev/src/.gitignore new file mode 100644 index 000000000..beb8604bc --- /dev/null +++ b/src/udev/src/.gitignore | |||
@@ -0,0 +1,5 @@ | |||
1 | *.[78] | ||
2 | *.html | ||
3 | udev.pc | ||
4 | libudev.pc | ||
5 | udev*.service | ||
diff --git a/src/udev/src/COPYING b/src/udev/src/COPYING new file mode 100644 index 000000000..d2e31278b --- /dev/null +++ b/src/udev/src/COPYING | |||
@@ -0,0 +1,502 @@ | |||
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! | ||
diff --git a/src/udev/src/accelerometer/61-accelerometer.rules b/src/udev/src/accelerometer/61-accelerometer.rules new file mode 100644 index 000000000..a6a2bfd08 --- /dev/null +++ b/src/udev/src/accelerometer/61-accelerometer.rules | |||
@@ -0,0 +1,3 @@ | |||
1 | # do not edit this file, it will be overwritten on update | ||
2 | |||
3 | SUBSYSTEM=="input", ACTION!="remove", ENV{ID_INPUT_ACCELEROMETER}=="1", IMPORT{program}="accelerometer %p" | ||
diff --git a/src/udev/src/accelerometer/accelerometer.c b/src/udev/src/accelerometer/accelerometer.c new file mode 100644 index 000000000..bc9715b26 --- /dev/null +++ b/src/udev/src/accelerometer/accelerometer.c | |||
@@ -0,0 +1,357 @@ | |||
1 | /* | ||
2 | * accelerometer - exports device orientation through property | ||
3 | * | ||
4 | * When an "change" event is received on an accelerometer, | ||
5 | * open its device node, and from the value, as well as the previous | ||
6 | * value of the property, calculate the device's new orientation, | ||
7 | * and export it as ID_INPUT_ACCELEROMETER_ORIENTATION. | ||
8 | * | ||
9 | * Possible values are: | ||
10 | * undefined | ||
11 | * * normal | ||
12 | * * bottom-up | ||
13 | * * left-up | ||
14 | * * right-up | ||
15 | * | ||
16 | * The property will be persistent across sessions, and the new | ||
17 | * orientations can be deducted from the previous one (it allows | ||
18 | * for a threshold for switching between opposite ends of the | ||
19 | * orientation). | ||
20 | * | ||
21 | * Copyright (C) 2011 Red Hat, Inc. | ||
22 | * Author: | ||
23 | * Bastien Nocera <hadess@hadess.net> | ||
24 | * | ||
25 | * orientation_calc() from the sensorfw package | ||
26 | * Copyright (C) 2009-2010 Nokia Corporation | ||
27 | * Authors: | ||
28 | * Üstün Ergenoglu <ext-ustun.ergenoglu@nokia.com> | ||
29 | * Timo Rongas <ext-timo.2.rongas@nokia.com> | ||
30 | * Lihan Guo <lihan.guo@digia.com> | ||
31 | * | ||
32 | * This program is free software; you can redistribute it and/or modify it | ||
33 | * under the terms of the GNU General Public License as published by | ||
34 | * the Free Software Foundation; either version 2 of the License, or | ||
35 | * (at your option) any later version. | ||
36 | * | ||
37 | * This program is distributed in the hope that it will be useful, but | ||
38 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
39 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
40 | * General Public License for more details. | ||
41 | * | ||
42 | * You should have received a copy of the GNU General Public License | ||
43 | * along with keymap; if not, write to the Free Software Foundation, | ||
44 | * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. | ||
45 | */ | ||
46 | |||
47 | #include <stdio.h> | ||
48 | #include <string.h> | ||
49 | #include <math.h> | ||
50 | #include <sys/types.h> | ||
51 | #include <sys/stat.h> | ||
52 | #include <fcntl.h> | ||
53 | #include <stdlib.h> | ||
54 | #include <unistd.h> | ||
55 | #include <getopt.h> | ||
56 | #include <limits.h> | ||
57 | #include <linux/limits.h> | ||
58 | #include <linux/input.h> | ||
59 | |||
60 | #include "libudev.h" | ||
61 | #include "libudev-private.h" | ||
62 | |||
63 | /* we must use this kernel-compatible implementation */ | ||
64 | #define BITS_PER_LONG (sizeof(unsigned long) * 8) | ||
65 | #define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1) | ||
66 | #define OFF(x) ((x)%BITS_PER_LONG) | ||
67 | #define BIT(x) (1UL<<OFF(x)) | ||
68 | #define LONG(x) ((x)/BITS_PER_LONG) | ||
69 | #define test_bit(bit, array) ((array[LONG(bit)] >> OFF(bit)) & 1) | ||
70 | |||
71 | static int debug = 0; | ||
72 | |||
73 | static void log_fn(struct udev *udev, int priority, | ||
74 | const char *file, int line, const char *fn, | ||
75 | const char *format, va_list args) | ||
76 | { | ||
77 | if (debug) { | ||
78 | fprintf(stderr, "%s: ", fn); | ||
79 | vfprintf(stderr, format, args); | ||
80 | } else { | ||
81 | vsyslog(priority, format, args); | ||
82 | } | ||
83 | } | ||
84 | |||
85 | typedef enum { | ||
86 | ORIENTATION_UNDEFINED, | ||
87 | ORIENTATION_NORMAL, | ||
88 | ORIENTATION_BOTTOM_UP, | ||
89 | ORIENTATION_LEFT_UP, | ||
90 | ORIENTATION_RIGHT_UP | ||
91 | } OrientationUp; | ||
92 | |||
93 | static const char *orientations[] = { | ||
94 | "undefined", | ||
95 | "normal", | ||
96 | "bottom-up", | ||
97 | "left-up", | ||
98 | "right-up", | ||
99 | NULL | ||
100 | }; | ||
101 | |||
102 | #define ORIENTATION_UP_UP ORIENTATION_NORMAL | ||
103 | |||
104 | #define DEFAULT_THRESHOLD 250 | ||
105 | #define RADIANS_TO_DEGREES 180.0/M_PI | ||
106 | #define SAME_AXIS_LIMIT 5 | ||
107 | |||
108 | #define THRESHOLD_LANDSCAPE 25 | ||
109 | #define THRESHOLD_PORTRAIT 20 | ||
110 | |||
111 | static const char * | ||
112 | orientation_to_string (OrientationUp o) | ||
113 | { | ||
114 | return orientations[o]; | ||
115 | } | ||
116 | |||
117 | static OrientationUp | ||
118 | string_to_orientation (const char *orientation) | ||
119 | { | ||
120 | int i; | ||
121 | |||
122 | if (orientation == NULL) | ||
123 | return ORIENTATION_UNDEFINED; | ||
124 | for (i = 0; orientations[i] != NULL; i++) { | ||
125 | if (strcmp (orientation, orientations[i]) == 0) | ||
126 | return i; | ||
127 | } | ||
128 | return ORIENTATION_UNDEFINED; | ||
129 | } | ||
130 | |||
131 | static OrientationUp | ||
132 | orientation_calc (OrientationUp prev, | ||
133 | int x, int y, int z) | ||
134 | { | ||
135 | int rotation; | ||
136 | OrientationUp ret = prev; | ||
137 | |||
138 | /* Portrait check */ | ||
139 | rotation = round(atan((double) x / sqrt(y * y + z * z)) * RADIANS_TO_DEGREES); | ||
140 | |||
141 | if (abs(rotation) > THRESHOLD_PORTRAIT) { | ||
142 | ret = (rotation < 0) ? ORIENTATION_LEFT_UP : ORIENTATION_RIGHT_UP; | ||
143 | |||
144 | /* Some threshold to switching between portrait modes */ | ||
145 | if (prev == ORIENTATION_LEFT_UP || prev == ORIENTATION_RIGHT_UP) { | ||
146 | if (abs(rotation) < SAME_AXIS_LIMIT) { | ||
147 | ret = prev; | ||
148 | } | ||
149 | } | ||
150 | |||
151 | } else { | ||
152 | /* Landscape check */ | ||
153 | rotation = round(atan((double) y / sqrt(x * x + z * z)) * RADIANS_TO_DEGREES); | ||
154 | |||
155 | if (abs(rotation) > THRESHOLD_LANDSCAPE) { | ||
156 | ret = (rotation < 0) ? ORIENTATION_BOTTOM_UP : ORIENTATION_NORMAL; | ||
157 | |||
158 | /* Some threshold to switching between landscape modes */ | ||
159 | if (prev == ORIENTATION_BOTTOM_UP || prev == ORIENTATION_NORMAL) { | ||
160 | if (abs(rotation) < SAME_AXIS_LIMIT) { | ||
161 | ret = prev; | ||
162 | } | ||
163 | } | ||
164 | } | ||
165 | } | ||
166 | |||
167 | return ret; | ||
168 | } | ||
169 | |||
170 | static OrientationUp | ||
171 | get_prev_orientation(struct udev_device *dev) | ||
172 | { | ||
173 | const char *value; | ||
174 | |||
175 | value = udev_device_get_property_value(dev, "ID_INPUT_ACCELEROMETER_ORIENTATION"); | ||
176 | if (value == NULL) | ||
177 | return ORIENTATION_UNDEFINED; | ||
178 | return string_to_orientation(value); | ||
179 | } | ||
180 | |||
181 | #define SET_AXIS(axis, code_) if (ev[i].code == code_) { if (got_##axis == 0) { axis = ev[i].value; got_##axis = 1; } } | ||
182 | |||
183 | /* accelerometers */ | ||
184 | static void test_orientation(struct udev *udev, | ||
185 | struct udev_device *dev, | ||
186 | const char *devpath) | ||
187 | { | ||
188 | OrientationUp old, new; | ||
189 | int fd, r; | ||
190 | struct input_event ev[64]; | ||
191 | int got_syn = 0; | ||
192 | int got_x, got_y, got_z; | ||
193 | int x = 0, y = 0, z = 0; | ||
194 | char text[64]; | ||
195 | |||
196 | old = get_prev_orientation(dev); | ||
197 | |||
198 | if ((fd = open(devpath, O_RDONLY)) < 0) | ||
199 | return; | ||
200 | |||
201 | got_x = got_y = got_z = 0; | ||
202 | |||
203 | while (1) { | ||
204 | int i; | ||
205 | |||
206 | r = read(fd, ev, sizeof(struct input_event) * 64); | ||
207 | |||
208 | if (r < (int) sizeof(struct input_event)) | ||
209 | return; | ||
210 | |||
211 | for (i = 0; i < r / (int) sizeof(struct input_event); i++) { | ||
212 | if (got_syn == 1) { | ||
213 | if (ev[i].type == EV_ABS) { | ||
214 | SET_AXIS(x, ABS_X); | ||
215 | SET_AXIS(y, ABS_Y); | ||
216 | SET_AXIS(z, ABS_Z); | ||
217 | } | ||
218 | } | ||
219 | if (ev[i].type == EV_SYN && ev[i].code == SYN_REPORT) { | ||
220 | got_syn = 1; | ||
221 | } | ||
222 | if (got_x && got_y && got_z) | ||
223 | goto read_dev; | ||
224 | } | ||
225 | } | ||
226 | |||
227 | read_dev: | ||
228 | close(fd); | ||
229 | |||
230 | if (!got_x || !got_y || !got_z) | ||
231 | return; | ||
232 | |||
233 | new = orientation_calc(old, x, y, z); | ||
234 | snprintf(text, sizeof(text), "ID_INPUT_ACCELEROMETER_ORIENTATION=%s", orientation_to_string(new)); | ||
235 | puts(text); | ||
236 | } | ||
237 | |||
238 | static void help(void) | ||
239 | { | ||
240 | printf("Usage: accelerometer [options] <device path>\n" | ||
241 | " --debug debug to stderr\n" | ||
242 | " --help print this help text\n\n"); | ||
243 | } | ||
244 | |||
245 | int main (int argc, char** argv) | ||
246 | { | ||
247 | struct udev *udev; | ||
248 | struct udev_device *dev; | ||
249 | |||
250 | static const struct option options[] = { | ||
251 | { "debug", no_argument, NULL, 'd' }, | ||
252 | { "help", no_argument, NULL, 'h' }, | ||
253 | {} | ||
254 | }; | ||
255 | |||
256 | char devpath[PATH_MAX]; | ||
257 | char *devnode; | ||
258 | const char *id_path; | ||
259 | struct udev_enumerate *enumerate; | ||
260 | struct udev_list_entry *list_entry; | ||
261 | |||
262 | udev = udev_new(); | ||
263 | if (udev == NULL) | ||
264 | return 1; | ||
265 | |||
266 | udev_log_init("input_id"); | ||
267 | udev_set_log_fn(udev, log_fn); | ||
268 | |||
269 | /* CLI argument parsing */ | ||
270 | while (1) { | ||
271 | int option; | ||
272 | |||
273 | option = getopt_long(argc, argv, "dxh", options, NULL); | ||
274 | if (option == -1) | ||
275 | break; | ||
276 | |||
277 | switch (option) { | ||
278 | case 'd': | ||
279 | debug = 1; | ||
280 | if (udev_get_log_priority(udev) < LOG_INFO) | ||
281 | udev_set_log_priority(udev, LOG_INFO); | ||
282 | break; | ||
283 | case 'h': | ||
284 | help(); | ||
285 | exit(0); | ||
286 | default: | ||
287 | exit(1); | ||
288 | } | ||
289 | } | ||
290 | |||
291 | if (argv[optind] == NULL) { | ||
292 | help(); | ||
293 | exit(1); | ||
294 | } | ||
295 | |||
296 | /* get the device */ | ||
297 | snprintf(devpath, sizeof(devpath), "%s/%s", udev_get_sys_path(udev), argv[optind]); | ||
298 | dev = udev_device_new_from_syspath(udev, devpath); | ||
299 | if (dev == NULL) { | ||
300 | fprintf(stderr, "unable to access '%s'\n", devpath); | ||
301 | return 1; | ||
302 | } | ||
303 | |||
304 | id_path = udev_device_get_property_value(dev, "ID_PATH"); | ||
305 | if (id_path == NULL) { | ||
306 | fprintf (stderr, "unable to get property ID_PATH for '%s'", devpath); | ||
307 | return 0; | ||
308 | } | ||
309 | |||
310 | /* Get the children devices and find the devnode | ||
311 | * FIXME: use udev_enumerate_add_match_children() instead | ||
312 | * when it's available */ | ||
313 | devnode = NULL; | ||
314 | enumerate = udev_enumerate_new(udev); | ||
315 | udev_enumerate_add_match_property(enumerate, "ID_PATH", id_path); | ||
316 | udev_enumerate_add_match_subsystem(enumerate, "input"); | ||
317 | udev_enumerate_scan_devices(enumerate); | ||
318 | udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(enumerate)) { | ||
319 | struct udev_device *device; | ||
320 | const char *node; | ||
321 | |||
322 | device = udev_device_new_from_syspath(udev_enumerate_get_udev(enumerate), | ||
323 | udev_list_entry_get_name(list_entry)); | ||
324 | if (device == NULL) | ||
325 | continue; | ||
326 | /* Already found it */ | ||
327 | if (devnode != NULL) { | ||
328 | udev_device_unref(device); | ||
329 | continue; | ||
330 | } | ||
331 | |||
332 | node = udev_device_get_devnode(device); | ||
333 | if (node == NULL) { | ||
334 | udev_device_unref(device); | ||
335 | continue; | ||
336 | } | ||
337 | /* Use the event sub-device */ | ||
338 | if (strstr(node, "/event") == NULL) { | ||
339 | udev_device_unref(device); | ||
340 | continue; | ||
341 | } | ||
342 | |||
343 | devnode = strdup(node); | ||
344 | udev_device_unref(device); | ||
345 | } | ||
346 | |||
347 | if (devnode == NULL) { | ||
348 | fprintf(stderr, "unable to get device node for '%s'\n", devpath); | ||
349 | return 0; | ||
350 | } | ||
351 | |||
352 | info(udev, "Opening accelerometer device %s\n", devnode); | ||
353 | test_orientation(udev, dev, devnode); | ||
354 | free(devnode); | ||
355 | |||
356 | return 0; | ||
357 | } | ||
diff --git a/src/udev/src/ata_id/ata_id.c b/src/udev/src/ata_id/ata_id.c new file mode 100644 index 000000000..846a73b54 --- /dev/null +++ b/src/udev/src/ata_id/ata_id.c | |||
@@ -0,0 +1,721 @@ | |||
1 | /* | ||
2 | * ata_id - reads product/serial number from ATA drives | ||
3 | * | ||
4 | * Copyright (C) 2005-2008 Kay Sievers <kay.sievers@vrfy.org> | ||
5 | * Copyright (C) 2009 Lennart Poettering <lennart@poettering.net> | ||
6 | * Copyright (C) 2009-2010 David Zeuthen <zeuthen@gmail.com> | ||
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 <stdint.h> | ||
25 | #include <unistd.h> | ||
26 | #include <fcntl.h> | ||
27 | #include <ctype.h> | ||
28 | #include <assert.h> | ||
29 | #include <string.h> | ||
30 | #include <errno.h> | ||
31 | #include <getopt.h> | ||
32 | #include <scsi/scsi.h> | ||
33 | #include <scsi/sg.h> | ||
34 | #include <scsi/scsi_ioctl.h> | ||
35 | #include <sys/ioctl.h> | ||
36 | #include <sys/types.h> | ||
37 | #include <sys/stat.h> | ||
38 | #include <linux/types.h> | ||
39 | #include <linux/hdreg.h> | ||
40 | #include <linux/fs.h> | ||
41 | #include <linux/cdrom.h> | ||
42 | #include <linux/bsg.h> | ||
43 | #include <arpa/inet.h> | ||
44 | |||
45 | #include "libudev.h" | ||
46 | #include "libudev-private.h" | ||
47 | |||
48 | #define COMMAND_TIMEOUT_MSEC (30 * 1000) | ||
49 | |||
50 | static int disk_scsi_inquiry_command(int fd, | ||
51 | void *buf, | ||
52 | size_t buf_len) | ||
53 | { | ||
54 | struct sg_io_v4 io_v4; | ||
55 | uint8_t cdb[6]; | ||
56 | uint8_t sense[32]; | ||
57 | int ret; | ||
58 | |||
59 | /* | ||
60 | * INQUIRY, see SPC-4 section 6.4 | ||
61 | */ | ||
62 | memset(cdb, 0, sizeof(cdb)); | ||
63 | cdb[0] = 0x12; /* OPERATION CODE: INQUIRY */ | ||
64 | cdb[3] = (buf_len >> 8); /* ALLOCATION LENGTH */ | ||
65 | cdb[4] = (buf_len & 0xff); | ||
66 | |||
67 | memset(sense, 0, sizeof(sense)); | ||
68 | |||
69 | memset(&io_v4, 0, sizeof(struct sg_io_v4)); | ||
70 | io_v4.guard = 'Q'; | ||
71 | io_v4.protocol = BSG_PROTOCOL_SCSI; | ||
72 | io_v4.subprotocol = BSG_SUB_PROTOCOL_SCSI_CMD; | ||
73 | io_v4.request_len = sizeof (cdb); | ||
74 | io_v4.request = (uintptr_t) cdb; | ||
75 | io_v4.max_response_len = sizeof (sense); | ||
76 | io_v4.response = (uintptr_t) sense; | ||
77 | io_v4.din_xfer_len = buf_len; | ||
78 | io_v4.din_xferp = (uintptr_t) buf; | ||
79 | io_v4.timeout = COMMAND_TIMEOUT_MSEC; | ||
80 | |||
81 | ret = ioctl(fd, SG_IO, &io_v4); | ||
82 | if (ret != 0) { | ||
83 | /* could be that the driver doesn't do version 4, try version 3 */ | ||
84 | if (errno == EINVAL) { | ||
85 | struct sg_io_hdr io_hdr; | ||
86 | |||
87 | memset(&io_hdr, 0, sizeof(struct sg_io_hdr)); | ||
88 | io_hdr.interface_id = 'S'; | ||
89 | io_hdr.cmdp = (unsigned char*) cdb; | ||
90 | io_hdr.cmd_len = sizeof (cdb); | ||
91 | io_hdr.dxferp = buf; | ||
92 | io_hdr.dxfer_len = buf_len; | ||
93 | io_hdr.sbp = sense; | ||
94 | io_hdr.mx_sb_len = sizeof (sense); | ||
95 | io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; | ||
96 | io_hdr.timeout = COMMAND_TIMEOUT_MSEC; | ||
97 | |||
98 | ret = ioctl(fd, SG_IO, &io_hdr); | ||
99 | if (ret != 0) | ||
100 | goto out; | ||
101 | |||
102 | /* even if the ioctl succeeds, we need to check the return value */ | ||
103 | if (!(io_hdr.status == 0 && | ||
104 | io_hdr.host_status == 0 && | ||
105 | io_hdr.driver_status == 0)) { | ||
106 | errno = EIO; | ||
107 | ret = -1; | ||
108 | goto out; | ||
109 | } | ||
110 | } else { | ||
111 | goto out; | ||
112 | } | ||
113 | } | ||
114 | |||
115 | /* even if the ioctl succeeds, we need to check the return value */ | ||
116 | if (!(io_v4.device_status == 0 && | ||
117 | io_v4.transport_status == 0 && | ||
118 | io_v4.driver_status == 0)) { | ||
119 | errno = EIO; | ||
120 | ret = -1; | ||
121 | goto out; | ||
122 | } | ||
123 | |||
124 | out: | ||
125 | return ret; | ||
126 | } | ||
127 | |||
128 | static int disk_identify_command(int fd, | ||
129 | void *buf, | ||
130 | size_t buf_len) | ||
131 | { | ||
132 | struct sg_io_v4 io_v4; | ||
133 | uint8_t cdb[12]; | ||
134 | uint8_t sense[32]; | ||
135 | uint8_t *desc = sense+8; | ||
136 | int ret; | ||
137 | |||
138 | /* | ||
139 | * ATA Pass-Through 12 byte command, as described in | ||
140 | * | ||
141 | * T10 04-262r8 ATA Command Pass-Through | ||
142 | * | ||
143 | * from http://www.t10.org/ftp/t10/document.04/04-262r8.pdf | ||
144 | */ | ||
145 | memset(cdb, 0, sizeof(cdb)); | ||
146 | cdb[0] = 0xa1; /* OPERATION CODE: 12 byte pass through */ | ||
147 | cdb[1] = 4 << 1; /* PROTOCOL: PIO Data-in */ | ||
148 | cdb[2] = 0x2e; /* OFF_LINE=0, CK_COND=1, T_DIR=1, BYT_BLOK=1, T_LENGTH=2 */ | ||
149 | cdb[3] = 0; /* FEATURES */ | ||
150 | cdb[4] = 1; /* SECTORS */ | ||
151 | cdb[5] = 0; /* LBA LOW */ | ||
152 | cdb[6] = 0; /* LBA MID */ | ||
153 | cdb[7] = 0; /* LBA HIGH */ | ||
154 | cdb[8] = 0 & 0x4F; /* SELECT */ | ||
155 | cdb[9] = 0xEC; /* Command: ATA IDENTIFY DEVICE */; | ||
156 | memset(sense, 0, sizeof(sense)); | ||
157 | |||
158 | memset(&io_v4, 0, sizeof(struct sg_io_v4)); | ||
159 | io_v4.guard = 'Q'; | ||
160 | io_v4.protocol = BSG_PROTOCOL_SCSI; | ||
161 | io_v4.subprotocol = BSG_SUB_PROTOCOL_SCSI_CMD; | ||
162 | io_v4.request_len = sizeof (cdb); | ||
163 | io_v4.request = (uintptr_t) cdb; | ||
164 | io_v4.max_response_len = sizeof (sense); | ||
165 | io_v4.response = (uintptr_t) sense; | ||
166 | io_v4.din_xfer_len = buf_len; | ||
167 | io_v4.din_xferp = (uintptr_t) buf; | ||
168 | io_v4.timeout = COMMAND_TIMEOUT_MSEC; | ||
169 | |||
170 | ret = ioctl(fd, SG_IO, &io_v4); | ||
171 | if (ret != 0) { | ||
172 | /* could be that the driver doesn't do version 4, try version 3 */ | ||
173 | if (errno == EINVAL) { | ||
174 | struct sg_io_hdr io_hdr; | ||
175 | |||
176 | memset(&io_hdr, 0, sizeof(struct sg_io_hdr)); | ||
177 | io_hdr.interface_id = 'S'; | ||
178 | io_hdr.cmdp = (unsigned char*) cdb; | ||
179 | io_hdr.cmd_len = sizeof (cdb); | ||
180 | io_hdr.dxferp = buf; | ||
181 | io_hdr.dxfer_len = buf_len; | ||
182 | io_hdr.sbp = sense; | ||
183 | io_hdr.mx_sb_len = sizeof (sense); | ||
184 | io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; | ||
185 | io_hdr.timeout = COMMAND_TIMEOUT_MSEC; | ||
186 | |||
187 | ret = ioctl(fd, SG_IO, &io_hdr); | ||
188 | if (ret != 0) | ||
189 | goto out; | ||
190 | } else { | ||
191 | goto out; | ||
192 | } | ||
193 | } | ||
194 | |||
195 | if (!(sense[0] == 0x72 && desc[0] == 0x9 && desc[1] == 0x0c)) { | ||
196 | errno = EIO; | ||
197 | ret = -1; | ||
198 | goto out; | ||
199 | } | ||
200 | |||
201 | out: | ||
202 | return ret; | ||
203 | } | ||
204 | |||
205 | static int disk_identify_packet_device_command(int fd, | ||
206 | void *buf, | ||
207 | size_t buf_len) | ||
208 | { | ||
209 | struct sg_io_v4 io_v4; | ||
210 | uint8_t cdb[16]; | ||
211 | uint8_t sense[32]; | ||
212 | uint8_t *desc = sense+8; | ||
213 | int ret; | ||
214 | |||
215 | /* | ||
216 | * ATA Pass-Through 16 byte command, as described in | ||
217 | * | ||
218 | * T10 04-262r8 ATA Command Pass-Through | ||
219 | * | ||
220 | * from http://www.t10.org/ftp/t10/document.04/04-262r8.pdf | ||
221 | */ | ||
222 | memset(cdb, 0, sizeof(cdb)); | ||
223 | cdb[0] = 0x85; /* OPERATION CODE: 16 byte pass through */ | ||
224 | cdb[1] = 4 << 1; /* PROTOCOL: PIO Data-in */ | ||
225 | cdb[2] = 0x2e; /* OFF_LINE=0, CK_COND=1, T_DIR=1, BYT_BLOK=1, T_LENGTH=2 */ | ||
226 | cdb[3] = 0; /* FEATURES */ | ||
227 | cdb[4] = 0; /* FEATURES */ | ||
228 | cdb[5] = 0; /* SECTORS */ | ||
229 | cdb[6] = 1; /* SECTORS */ | ||
230 | cdb[7] = 0; /* LBA LOW */ | ||
231 | cdb[8] = 0; /* LBA LOW */ | ||
232 | cdb[9] = 0; /* LBA MID */ | ||
233 | cdb[10] = 0; /* LBA MID */ | ||
234 | cdb[11] = 0; /* LBA HIGH */ | ||
235 | cdb[12] = 0; /* LBA HIGH */ | ||
236 | cdb[13] = 0; /* DEVICE */ | ||
237 | cdb[14] = 0xA1; /* Command: ATA IDENTIFY PACKET DEVICE */; | ||
238 | cdb[15] = 0; /* CONTROL */ | ||
239 | memset(sense, 0, sizeof(sense)); | ||
240 | |||
241 | memset(&io_v4, 0, sizeof(struct sg_io_v4)); | ||
242 | io_v4.guard = 'Q'; | ||
243 | io_v4.protocol = BSG_PROTOCOL_SCSI; | ||
244 | io_v4.subprotocol = BSG_SUB_PROTOCOL_SCSI_CMD; | ||
245 | io_v4.request_len = sizeof (cdb); | ||
246 | io_v4.request = (uintptr_t) cdb; | ||
247 | io_v4.max_response_len = sizeof (sense); | ||
248 | io_v4.response = (uintptr_t) sense; | ||
249 | io_v4.din_xfer_len = buf_len; | ||
250 | io_v4.din_xferp = (uintptr_t) buf; | ||
251 | io_v4.timeout = COMMAND_TIMEOUT_MSEC; | ||
252 | |||
253 | ret = ioctl(fd, SG_IO, &io_v4); | ||
254 | if (ret != 0) { | ||
255 | /* could be that the driver doesn't do version 4, try version 3 */ | ||
256 | if (errno == EINVAL) { | ||
257 | struct sg_io_hdr io_hdr; | ||
258 | |||
259 | memset(&io_hdr, 0, sizeof(struct sg_io_hdr)); | ||
260 | io_hdr.interface_id = 'S'; | ||
261 | io_hdr.cmdp = (unsigned char*) cdb; | ||
262 | io_hdr.cmd_len = sizeof (cdb); | ||
263 | io_hdr.dxferp = buf; | ||
264 | io_hdr.dxfer_len = buf_len; | ||
265 | io_hdr.sbp = sense; | ||
266 | io_hdr.mx_sb_len = sizeof (sense); | ||
267 | io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; | ||
268 | io_hdr.timeout = COMMAND_TIMEOUT_MSEC; | ||
269 | |||
270 | ret = ioctl(fd, SG_IO, &io_hdr); | ||
271 | if (ret != 0) | ||
272 | goto out; | ||
273 | } else { | ||
274 | goto out; | ||
275 | } | ||
276 | } | ||
277 | |||
278 | if (!(sense[0] == 0x72 && desc[0] == 0x9 && desc[1] == 0x0c)) { | ||
279 | errno = EIO; | ||
280 | ret = -1; | ||
281 | goto out; | ||
282 | } | ||
283 | |||
284 | out: | ||
285 | return ret; | ||
286 | } | ||
287 | |||
288 | /** | ||
289 | * disk_identify_get_string: | ||
290 | * @identify: A block of IDENTIFY data | ||
291 | * @offset_words: Offset of the string to get, in words. | ||
292 | * @dest: Destination buffer for the string. | ||
293 | * @dest_len: Length of destination buffer, in bytes. | ||
294 | * | ||
295 | * Copies the ATA string from @identify located at @offset_words into @dest. | ||
296 | */ | ||
297 | static void disk_identify_get_string(uint8_t identify[512], | ||
298 | unsigned int offset_words, | ||
299 | char *dest, | ||
300 | size_t dest_len) | ||
301 | { | ||
302 | unsigned int c1; | ||
303 | unsigned int c2; | ||
304 | |||
305 | assert(identify != NULL); | ||
306 | assert(dest != NULL); | ||
307 | assert((dest_len & 1) == 0); | ||
308 | |||
309 | while (dest_len > 0) { | ||
310 | c1 = identify[offset_words * 2 + 1]; | ||
311 | c2 = identify[offset_words * 2]; | ||
312 | *dest = c1; | ||
313 | dest++; | ||
314 | *dest = c2; | ||
315 | dest++; | ||
316 | offset_words++; | ||
317 | dest_len -= 2; | ||
318 | } | ||
319 | } | ||
320 | |||
321 | static void disk_identify_fixup_string(uint8_t identify[512], | ||
322 | unsigned int offset_words, | ||
323 | size_t len) | ||
324 | { | ||
325 | disk_identify_get_string(identify, offset_words, | ||
326 | (char *) identify + offset_words * 2, len); | ||
327 | } | ||
328 | |||
329 | static void disk_identify_fixup_uint16 (uint8_t identify[512], unsigned int offset_words) | ||
330 | { | ||
331 | uint16_t *p; | ||
332 | |||
333 | p = (uint16_t *) identify; | ||
334 | p[offset_words] = le16toh (p[offset_words]); | ||
335 | } | ||
336 | |||
337 | /** | ||
338 | * disk_identify: | ||
339 | * @udev: The libudev context. | ||
340 | * @fd: File descriptor for the block device. | ||
341 | * @out_identify: Return location for IDENTIFY data. | ||
342 | * @out_is_packet_device: Return location for whether returned data is from a IDENTIFY PACKET DEVICE. | ||
343 | * | ||
344 | * Sends the IDENTIFY DEVICE or IDENTIFY PACKET DEVICE command to the | ||
345 | * device represented by @fd. If successful, then the result will be | ||
346 | * copied into @out_identify and @out_is_packet_device. | ||
347 | * | ||
348 | * This routine is based on code from libatasmart, Copyright 2008 | ||
349 | * Lennart Poettering, LGPL v2.1. | ||
350 | * | ||
351 | * Returns: 0 if the data was successfully obtained, otherwise | ||
352 | * non-zero with errno set. | ||
353 | */ | ||
354 | static int disk_identify(struct udev *udev, | ||
355 | int fd, | ||
356 | uint8_t out_identify[512], | ||
357 | int *out_is_packet_device) | ||
358 | { | ||
359 | int ret; | ||
360 | uint8_t inquiry_buf[36]; | ||
361 | int peripheral_device_type; | ||
362 | int all_nul_bytes; | ||
363 | int n; | ||
364 | int is_packet_device; | ||
365 | |||
366 | assert(out_identify != NULL); | ||
367 | |||
368 | /* init results */ | ||
369 | ret = -1; | ||
370 | memset(out_identify, '\0', 512); | ||
371 | is_packet_device = 0; | ||
372 | |||
373 | /* If we were to use ATA PASS_THROUGH (12) on an ATAPI device | ||
374 | * we could accidentally blank media. This is because MMC's BLANK | ||
375 | * command has the same op-code (0x61). | ||
376 | * | ||
377 | * To prevent this from happening we bail out if the device | ||
378 | * isn't a Direct Access Block Device, e.g. SCSI type 0x00 | ||
379 | * (CD/DVD devices are type 0x05). So we send a SCSI INQUIRY | ||
380 | * command first... libata is handling this via its SCSI | ||
381 | * emulation layer. | ||
382 | * | ||
383 | * This also ensures that we're actually dealing with a device | ||
384 | * that understands SCSI commands. | ||
385 | * | ||
386 | * (Yes, it is a bit perverse that we're tunneling the ATA | ||
387 | * command through SCSI and relying on the ATA driver | ||
388 | * emulating SCSI well-enough...) | ||
389 | * | ||
390 | * (See commit 160b069c25690bfb0c785994c7c3710289179107 for | ||
391 | * the original bug-fix and see http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=556635 | ||
392 | * for the original bug-report.) | ||
393 | */ | ||
394 | ret = disk_scsi_inquiry_command (fd, inquiry_buf, sizeof (inquiry_buf)); | ||
395 | if (ret != 0) | ||
396 | goto out; | ||
397 | |||
398 | /* SPC-4, section 6.4.2: Standard INQUIRY data */ | ||
399 | peripheral_device_type = inquiry_buf[0] & 0x1f; | ||
400 | if (peripheral_device_type == 0x05) | ||
401 | { | ||
402 | is_packet_device = 1; | ||
403 | ret = disk_identify_packet_device_command(fd, out_identify, 512); | ||
404 | goto check_nul_bytes; | ||
405 | } | ||
406 | if (peripheral_device_type != 0x00) { | ||
407 | ret = -1; | ||
408 | errno = EIO; | ||
409 | goto out; | ||
410 | } | ||
411 | |||
412 | /* OK, now issue the IDENTIFY DEVICE command */ | ||
413 | ret = disk_identify_command(fd, out_identify, 512); | ||
414 | if (ret != 0) | ||
415 | goto out; | ||
416 | |||
417 | check_nul_bytes: | ||
418 | /* Check if IDENTIFY data is all NUL bytes - if so, bail */ | ||
419 | all_nul_bytes = 1; | ||
420 | for (n = 0; n < 512; n++) { | ||
421 | if (out_identify[n] != '\0') { | ||
422 | all_nul_bytes = 0; | ||
423 | break; | ||
424 | } | ||
425 | } | ||
426 | |||
427 | if (all_nul_bytes) { | ||
428 | ret = -1; | ||
429 | errno = EIO; | ||
430 | goto out; | ||
431 | } | ||
432 | |||
433 | out: | ||
434 | if (out_is_packet_device != NULL) | ||
435 | *out_is_packet_device = is_packet_device; | ||
436 | return ret; | ||
437 | } | ||
438 | |||
439 | static void log_fn(struct udev *udev, int priority, | ||
440 | const char *file, int line, const char *fn, | ||
441 | const char *format, va_list args) | ||
442 | { | ||
443 | vsyslog(priority, format, args); | ||
444 | } | ||
445 | |||
446 | int main(int argc, char *argv[]) | ||
447 | { | ||
448 | struct udev *udev; | ||
449 | struct hd_driveid id; | ||
450 | uint8_t identify[512]; | ||
451 | uint16_t *identify_words; | ||
452 | char model[41]; | ||
453 | char model_enc[256]; | ||
454 | char serial[21]; | ||
455 | char revision[9]; | ||
456 | const char *node = NULL; | ||
457 | int export = 0; | ||
458 | int fd; | ||
459 | uint16_t word; | ||
460 | int rc = 0; | ||
461 | int is_packet_device = 0; | ||
462 | static const struct option options[] = { | ||
463 | { "export", no_argument, NULL, 'x' }, | ||
464 | { "help", no_argument, NULL, 'h' }, | ||
465 | {} | ||
466 | }; | ||
467 | |||
468 | udev = udev_new(); | ||
469 | if (udev == NULL) | ||
470 | goto exit; | ||
471 | |||
472 | udev_log_init("ata_id"); | ||
473 | udev_set_log_fn(udev, log_fn); | ||
474 | |||
475 | while (1) { | ||
476 | int option; | ||
477 | |||
478 | option = getopt_long(argc, argv, "xh", options, NULL); | ||
479 | if (option == -1) | ||
480 | break; | ||
481 | |||
482 | switch (option) { | ||
483 | case 'x': | ||
484 | export = 1; | ||
485 | break; | ||
486 | case 'h': | ||
487 | printf("Usage: ata_id [--export] [--help] <device>\n" | ||
488 | " --export print values as environment keys\n" | ||
489 | " --help print this help text\n\n"); | ||
490 | goto exit; | ||
491 | } | ||
492 | } | ||
493 | |||
494 | node = argv[optind]; | ||
495 | if (node == NULL) { | ||
496 | err(udev, "no node specified\n"); | ||
497 | rc = 1; | ||
498 | goto exit; | ||
499 | } | ||
500 | |||
501 | fd = open(node, O_RDONLY|O_NONBLOCK); | ||
502 | if (fd < 0) { | ||
503 | err(udev, "unable to open '%s'\n", node); | ||
504 | rc = 1; | ||
505 | goto exit; | ||
506 | } | ||
507 | |||
508 | if (disk_identify(udev, fd, identify, &is_packet_device) == 0) { | ||
509 | /* | ||
510 | * fix up only the fields from the IDENTIFY data that we are going to | ||
511 | * use and copy it into the hd_driveid struct for convenience | ||
512 | */ | ||
513 | disk_identify_fixup_string (identify, 10, 20); /* serial */ | ||
514 | disk_identify_fixup_string (identify, 23, 6); /* fwrev */ | ||
515 | disk_identify_fixup_string (identify, 27, 40); /* model */ | ||
516 | disk_identify_fixup_uint16 (identify, 0); /* configuration */ | ||
517 | disk_identify_fixup_uint16 (identify, 75); /* queue depth */ | ||
518 | disk_identify_fixup_uint16 (identify, 75); /* SATA capabilities */ | ||
519 | disk_identify_fixup_uint16 (identify, 82); /* command set supported */ | ||
520 | disk_identify_fixup_uint16 (identify, 83); /* command set supported */ | ||
521 | disk_identify_fixup_uint16 (identify, 84); /* command set supported */ | ||
522 | disk_identify_fixup_uint16 (identify, 85); /* command set supported */ | ||
523 | disk_identify_fixup_uint16 (identify, 86); /* command set supported */ | ||
524 | disk_identify_fixup_uint16 (identify, 87); /* command set supported */ | ||
525 | disk_identify_fixup_uint16 (identify, 89); /* time required for SECURITY ERASE UNIT */ | ||
526 | disk_identify_fixup_uint16 (identify, 90); /* time required for enhanced SECURITY ERASE UNIT */ | ||
527 | disk_identify_fixup_uint16 (identify, 91); /* current APM values */ | ||
528 | disk_identify_fixup_uint16 (identify, 94); /* current AAM value */ | ||
529 | disk_identify_fixup_uint16 (identify, 128); /* device lock function */ | ||
530 | disk_identify_fixup_uint16 (identify, 217); /* nominal media rotation rate */ | ||
531 | memcpy(&id, identify, sizeof id); | ||
532 | } else { | ||
533 | /* If this fails, then try HDIO_GET_IDENTITY */ | ||
534 | if (ioctl(fd, HDIO_GET_IDENTITY, &id) != 0) { | ||
535 | info(udev, "HDIO_GET_IDENTITY failed for '%s': %m\n", node); | ||
536 | rc = 2; | ||
537 | goto close; | ||
538 | } | ||
539 | } | ||
540 | identify_words = (uint16_t *) identify; | ||
541 | |||
542 | memcpy (model, id.model, 40); | ||
543 | model[40] = '\0'; | ||
544 | udev_util_encode_string(model, model_enc, sizeof(model_enc)); | ||
545 | util_replace_whitespace((char *) id.model, model, 40); | ||
546 | util_replace_chars(model, NULL); | ||
547 | util_replace_whitespace((char *) id.serial_no, serial, 20); | ||
548 | util_replace_chars(serial, NULL); | ||
549 | util_replace_whitespace((char *) id.fw_rev, revision, 8); | ||
550 | util_replace_chars(revision, NULL); | ||
551 | |||
552 | if (export) { | ||
553 | /* Set this to convey the disk speaks the ATA protocol */ | ||
554 | printf("ID_ATA=1\n"); | ||
555 | |||
556 | if ((id.config >> 8) & 0x80) { | ||
557 | /* This is an ATAPI device */ | ||
558 | switch ((id.config >> 8) & 0x1f) { | ||
559 | case 0: | ||
560 | printf("ID_TYPE=cd\n"); | ||
561 | break; | ||
562 | case 1: | ||
563 | printf("ID_TYPE=tape\n"); | ||
564 | break; | ||
565 | case 5: | ||
566 | printf("ID_TYPE=cd\n"); | ||
567 | break; | ||
568 | case 7: | ||
569 | printf("ID_TYPE=optical\n"); | ||
570 | break; | ||
571 | default: | ||
572 | printf("ID_TYPE=generic\n"); | ||
573 | break; | ||
574 | } | ||
575 | } else { | ||
576 | printf("ID_TYPE=disk\n"); | ||
577 | } | ||
578 | printf("ID_BUS=ata\n"); | ||
579 | printf("ID_MODEL=%s\n", model); | ||
580 | printf("ID_MODEL_ENC=%s\n", model_enc); | ||
581 | printf("ID_REVISION=%s\n", revision); | ||
582 | if (serial[0] != '\0') { | ||
583 | printf("ID_SERIAL=%s_%s\n", model, serial); | ||
584 | printf("ID_SERIAL_SHORT=%s\n", serial); | ||
585 | } else { | ||
586 | printf("ID_SERIAL=%s\n", model); | ||
587 | } | ||
588 | |||
589 | if (id.command_set_1 & (1<<5)) { | ||
590 | printf ("ID_ATA_WRITE_CACHE=1\n"); | ||
591 | printf ("ID_ATA_WRITE_CACHE_ENABLED=%d\n", (id.cfs_enable_1 & (1<<5)) ? 1 : 0); | ||
592 | } | ||
593 | if (id.command_set_1 & (1<<10)) { | ||
594 | printf("ID_ATA_FEATURE_SET_HPA=1\n"); | ||
595 | printf("ID_ATA_FEATURE_SET_HPA_ENABLED=%d\n", (id.cfs_enable_1 & (1<<10)) ? 1 : 0); | ||
596 | |||
597 | /* | ||
598 | * TODO: use the READ NATIVE MAX ADDRESS command to get the native max address | ||
599 | * so it is easy to check whether the protected area is in use. | ||
600 | */ | ||
601 | } | ||
602 | if (id.command_set_1 & (1<<3)) { | ||
603 | printf("ID_ATA_FEATURE_SET_PM=1\n"); | ||
604 | printf("ID_ATA_FEATURE_SET_PM_ENABLED=%d\n", (id.cfs_enable_1 & (1<<3)) ? 1 : 0); | ||
605 | } | ||
606 | if (id.command_set_1 & (1<<1)) { | ||
607 | printf("ID_ATA_FEATURE_SET_SECURITY=1\n"); | ||
608 | printf("ID_ATA_FEATURE_SET_SECURITY_ENABLED=%d\n", (id.cfs_enable_1 & (1<<1)) ? 1 : 0); | ||
609 | printf("ID_ATA_FEATURE_SET_SECURITY_ERASE_UNIT_MIN=%d\n", id.trseuc * 2); | ||
610 | if ((id.cfs_enable_1 & (1<<1))) /* enabled */ { | ||
611 | if (id.dlf & (1<<8)) | ||
612 | printf("ID_ATA_FEATURE_SET_SECURITY_LEVEL=maximum\n"); | ||
613 | else | ||
614 | printf("ID_ATA_FEATURE_SET_SECURITY_LEVEL=high\n"); | ||
615 | } | ||
616 | if (id.dlf & (1<<5)) | ||
617 | printf("ID_ATA_FEATURE_SET_SECURITY_ENHANCED_ERASE_UNIT_MIN=%d\n", id.trsEuc * 2); | ||
618 | if (id.dlf & (1<<4)) | ||
619 | printf("ID_ATA_FEATURE_SET_SECURITY_EXPIRE=1\n"); | ||
620 | if (id.dlf & (1<<3)) | ||
621 | printf("ID_ATA_FEATURE_SET_SECURITY_FROZEN=1\n"); | ||
622 | if (id.dlf & (1<<2)) | ||
623 | printf("ID_ATA_FEATURE_SET_SECURITY_LOCKED=1\n"); | ||
624 | } | ||
625 | if (id.command_set_1 & (1<<0)) { | ||
626 | printf("ID_ATA_FEATURE_SET_SMART=1\n"); | ||
627 | printf("ID_ATA_FEATURE_SET_SMART_ENABLED=%d\n", (id.cfs_enable_1 & (1<<0)) ? 1 : 0); | ||
628 | } | ||
629 | if (id.command_set_2 & (1<<9)) { | ||
630 | printf("ID_ATA_FEATURE_SET_AAM=1\n"); | ||
631 | printf("ID_ATA_FEATURE_SET_AAM_ENABLED=%d\n", (id.cfs_enable_2 & (1<<9)) ? 1 : 0); | ||
632 | printf("ID_ATA_FEATURE_SET_AAM_VENDOR_RECOMMENDED_VALUE=%d\n", id.acoustic >> 8); | ||
633 | printf("ID_ATA_FEATURE_SET_AAM_CURRENT_VALUE=%d\n", id.acoustic & 0xff); | ||
634 | } | ||
635 | if (id.command_set_2 & (1<<5)) { | ||
636 | printf("ID_ATA_FEATURE_SET_PUIS=1\n"); | ||
637 | printf("ID_ATA_FEATURE_SET_PUIS_ENABLED=%d\n", (id.cfs_enable_2 & (1<<5)) ? 1 : 0); | ||
638 | } | ||
639 | if (id.command_set_2 & (1<<3)) { | ||
640 | printf("ID_ATA_FEATURE_SET_APM=1\n"); | ||
641 | printf("ID_ATA_FEATURE_SET_APM_ENABLED=%d\n", (id.cfs_enable_2 & (1<<3)) ? 1 : 0); | ||
642 | if ((id.cfs_enable_2 & (1<<3))) | ||
643 | printf("ID_ATA_FEATURE_SET_APM_CURRENT_VALUE=%d\n", id.CurAPMvalues & 0xff); | ||
644 | } | ||
645 | if (id.command_set_2 & (1<<0)) | ||
646 | printf("ID_ATA_DOWNLOAD_MICROCODE=1\n"); | ||
647 | |||
648 | /* | ||
649 | * Word 76 indicates the capabilities of a SATA device. A PATA device shall set | ||
650 | * word 76 to 0000h or FFFFh. If word 76 is set to 0000h or FFFFh, then | ||
651 | * the device does not claim compliance with the Serial ATA specification and words | ||
652 | * 76 through 79 are not valid and shall be ignored. | ||
653 | */ | ||
654 | word = *((uint16_t *) identify + 76); | ||
655 | if (word != 0x0000 && word != 0xffff) { | ||
656 | printf("ID_ATA_SATA=1\n"); | ||
657 | /* | ||
658 | * If bit 2 of word 76 is set to one, then the device supports the Gen2 | ||
659 | * signaling rate of 3.0 Gb/s (see SATA 2.6). | ||
660 | * | ||
661 | * If bit 1 of word 76 is set to one, then the device supports the Gen1 | ||
662 | * signaling rate of 1.5 Gb/s (see SATA 2.6). | ||
663 | */ | ||
664 | if (word & (1<<2)) | ||
665 | printf("ID_ATA_SATA_SIGNAL_RATE_GEN2=1\n"); | ||
666 | if (word & (1<<1)) | ||
667 | printf("ID_ATA_SATA_SIGNAL_RATE_GEN1=1\n"); | ||
668 | } | ||
669 | |||
670 | /* Word 217 indicates the nominal media rotation rate of the device */ | ||
671 | word = *((uint16_t *) identify + 217); | ||
672 | if (word != 0x0000) { | ||
673 | if (word == 0x0001) { | ||
674 | printf ("ID_ATA_ROTATION_RATE_RPM=0\n"); /* non-rotating e.g. SSD */ | ||
675 | } else if (word >= 0x0401 && word <= 0xfffe) { | ||
676 | printf ("ID_ATA_ROTATION_RATE_RPM=%d\n", word); | ||
677 | } | ||
678 | } | ||
679 | |||
680 | /* | ||
681 | * Words 108-111 contain a mandatory World Wide Name (WWN) in the NAA IEEE Registered identifier | ||
682 | * format. Word 108 bits (15:12) shall contain 5h, indicating that the naming authority is IEEE. | ||
683 | * All other values are reserved. | ||
684 | */ | ||
685 | word = *((uint16_t *) identify + 108); | ||
686 | if ((word & 0xf000) == 0x5000) { | ||
687 | uint64_t wwwn; | ||
688 | |||
689 | wwwn = *((uint16_t *) identify + 108); | ||
690 | wwwn <<= 16; | ||
691 | wwwn |= *((uint16_t *) identify + 109); | ||
692 | wwwn <<= 16; | ||
693 | wwwn |= *((uint16_t *) identify + 110); | ||
694 | wwwn <<= 16; | ||
695 | wwwn |= *((uint16_t *) identify + 111); | ||
696 | printf("ID_WWN=0x%llx\n", (unsigned long long int) wwwn); | ||
697 | /* ATA devices have no vendor extension */ | ||
698 | printf("ID_WWN_WITH_EXTENSION=0x%llx\n", (unsigned long long int) wwwn); | ||
699 | } | ||
700 | |||
701 | /* from Linux's include/linux/ata.h */ | ||
702 | if (identify_words[0] == 0x848a || identify_words[0] == 0x844a) { | ||
703 | printf("ID_ATA_CFA=1\n"); | ||
704 | } else { | ||
705 | if ((identify_words[83] & 0xc004) == 0x4004) { | ||
706 | printf("ID_ATA_CFA=1\n"); | ||
707 | } | ||
708 | } | ||
709 | } else { | ||
710 | if (serial[0] != '\0') | ||
711 | printf("%s_%s\n", model, serial); | ||
712 | else | ||
713 | printf("%s\n", model); | ||
714 | } | ||
715 | close: | ||
716 | close(fd); | ||
717 | exit: | ||
718 | udev_unref(udev); | ||
719 | udev_log_close(); | ||
720 | return rc; | ||
721 | } | ||
diff --git a/src/udev/src/cdrom_id/60-cdrom_id.rules b/src/udev/src/cdrom_id/60-cdrom_id.rules new file mode 100644 index 000000000..6eaf76a72 --- /dev/null +++ b/src/udev/src/cdrom_id/60-cdrom_id.rules | |||
@@ -0,0 +1,20 @@ | |||
1 | # do not edit this file, it will be overwritten on update | ||
2 | |||
3 | ACTION=="remove", GOTO="cdrom_end" | ||
4 | SUBSYSTEM!="block", GOTO="cdrom_end" | ||
5 | KERNEL!="sr[0-9]*|xvd*", GOTO="cdrom_end" | ||
6 | ENV{DEVTYPE}!="disk", GOTO="cdrom_end" | ||
7 | |||
8 | # unconditionally tag device as CDROM | ||
9 | KERNEL=="sr[0-9]*", ENV{ID_CDROM}="1" | ||
10 | |||
11 | # media eject button pressed | ||
12 | ENV{DISK_EJECT_REQUEST}=="?*", RUN+="cdrom_id --eject-media $devnode", GOTO="cdrom_end" | ||
13 | |||
14 | # import device and media properties and lock tray to | ||
15 | # enable the receiving of media eject button events | ||
16 | IMPORT{program}="cdrom_id --lock-media $devnode" | ||
17 | |||
18 | KERNEL=="sr0", SYMLINK+="cdrom", OPTIONS+="link_priority=-100" | ||
19 | |||
20 | LABEL="cdrom_end" | ||
diff --git a/src/udev/src/cdrom_id/cdrom_id.c b/src/udev/src/cdrom_id/cdrom_id.c new file mode 100644 index 000000000..f90d52ec9 --- /dev/null +++ b/src/udev/src/cdrom_id/cdrom_id.c | |||
@@ -0,0 +1,1099 @@ | |||
1 | /* | ||
2 | * cdrom_id - optical drive and media information prober | ||
3 | * | ||
4 | * Copyright (C) 2008-2010 Kay Sievers <kay.sievers@vrfy.org> | ||
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 | #ifndef _GNU_SOURCE | ||
21 | #define _GNU_SOURCE 1 | ||
22 | #endif | ||
23 | |||
24 | #include <stdio.h> | ||
25 | #include <stddef.h> | ||
26 | #include <stdlib.h> | ||
27 | #include <unistd.h> | ||
28 | #include <string.h> | ||
29 | #include <limits.h> | ||
30 | #include <fcntl.h> | ||
31 | #include <errno.h> | ||
32 | #include <getopt.h> | ||
33 | #include <time.h> | ||
34 | #include <scsi/sg.h> | ||
35 | #include <sys/types.h> | ||
36 | #include <sys/stat.h> | ||
37 | #include <sys/time.h> | ||
38 | #include <sys/ioctl.h> | ||
39 | #include <linux/cdrom.h> | ||
40 | |||
41 | #include "libudev.h" | ||
42 | #include "libudev-private.h" | ||
43 | |||
44 | static bool debug; | ||
45 | |||
46 | static void log_fn(struct udev *udev, int priority, | ||
47 | const char *file, int line, const char *fn, | ||
48 | const char *format, va_list args) | ||
49 | { | ||
50 | if (debug) { | ||
51 | fprintf(stderr, "%s: ", fn); | ||
52 | vfprintf(stderr, format, args); | ||
53 | } else { | ||
54 | vsyslog(priority, format, args); | ||
55 | } | ||
56 | } | ||
57 | |||
58 | /* device info */ | ||
59 | static unsigned int cd_cd_rom; | ||
60 | static unsigned int cd_cd_r; | ||
61 | static unsigned int cd_cd_rw; | ||
62 | static unsigned int cd_dvd_rom; | ||
63 | static unsigned int cd_dvd_r; | ||
64 | static unsigned int cd_dvd_rw; | ||
65 | static unsigned int cd_dvd_ram; | ||
66 | static unsigned int cd_dvd_plus_r; | ||
67 | static unsigned int cd_dvd_plus_rw; | ||
68 | static unsigned int cd_dvd_plus_r_dl; | ||
69 | static unsigned int cd_dvd_plus_rw_dl; | ||
70 | static unsigned int cd_bd; | ||
71 | static unsigned int cd_bd_r; | ||
72 | static unsigned int cd_bd_re; | ||
73 | static unsigned int cd_hddvd; | ||
74 | static unsigned int cd_hddvd_r; | ||
75 | static unsigned int cd_hddvd_rw; | ||
76 | static unsigned int cd_mo; | ||
77 | static unsigned int cd_mrw; | ||
78 | static unsigned int cd_mrw_w; | ||
79 | |||
80 | /* media info */ | ||
81 | static unsigned int cd_media; | ||
82 | static unsigned int cd_media_cd_rom; | ||
83 | static unsigned int cd_media_cd_r; | ||
84 | static unsigned int cd_media_cd_rw; | ||
85 | static unsigned int cd_media_dvd_rom; | ||
86 | static unsigned int cd_media_dvd_r; | ||
87 | static unsigned int cd_media_dvd_rw; | ||
88 | static unsigned int cd_media_dvd_rw_ro; /* restricted overwrite mode */ | ||
89 | static unsigned int cd_media_dvd_rw_seq; /* sequential mode */ | ||
90 | static unsigned int cd_media_dvd_ram; | ||
91 | static unsigned int cd_media_dvd_plus_r; | ||
92 | static unsigned int cd_media_dvd_plus_rw; | ||
93 | static unsigned int cd_media_dvd_plus_r_dl; | ||
94 | static unsigned int cd_media_dvd_plus_rw_dl; | ||
95 | static unsigned int cd_media_bd; | ||
96 | static unsigned int cd_media_bd_r; | ||
97 | static unsigned int cd_media_bd_re; | ||
98 | static unsigned int cd_media_hddvd; | ||
99 | static unsigned int cd_media_hddvd_r; | ||
100 | static unsigned int cd_media_hddvd_rw; | ||
101 | static unsigned int cd_media_mo; | ||
102 | static unsigned int cd_media_mrw; | ||
103 | static unsigned int cd_media_mrw_w; | ||
104 | |||
105 | static const char *cd_media_state = NULL; | ||
106 | static unsigned int cd_media_session_next; | ||
107 | static unsigned int cd_media_session_count; | ||
108 | static unsigned int cd_media_track_count; | ||
109 | static unsigned int cd_media_track_count_data; | ||
110 | static unsigned int cd_media_track_count_audio; | ||
111 | static unsigned long long int cd_media_session_last_offset; | ||
112 | |||
113 | #define ERRCODE(s) ((((s)[2] & 0x0F) << 16) | ((s)[12] << 8) | ((s)[13])) | ||
114 | #define SK(errcode) (((errcode) >> 16) & 0xF) | ||
115 | #define ASC(errcode) (((errcode) >> 8) & 0xFF) | ||
116 | #define ASCQ(errcode) ((errcode) & 0xFF) | ||
117 | |||
118 | static bool is_mounted(const char *device) | ||
119 | { | ||
120 | struct stat statbuf; | ||
121 | FILE *fp; | ||
122 | int maj, min; | ||
123 | bool mounted = false; | ||
124 | |||
125 | if (stat(device, &statbuf) < 0) | ||
126 | return -ENODEV; | ||
127 | |||
128 | fp = fopen("/proc/self/mountinfo", "r"); | ||
129 | if (fp == NULL) | ||
130 | return -ENOSYS; | ||
131 | while (fscanf(fp, "%*s %*s %i:%i %*[^\n]", &maj, &min) == 2) { | ||
132 | if (makedev(maj, min) == statbuf.st_rdev) { | ||
133 | mounted = true; | ||
134 | break; | ||
135 | } | ||
136 | } | ||
137 | fclose(fp); | ||
138 | return mounted; | ||
139 | } | ||
140 | |||
141 | static void info_scsi_cmd_err(struct udev *udev, char *cmd, int err) | ||
142 | { | ||
143 | if (err == -1) { | ||
144 | info(udev, "%s failed\n", cmd); | ||
145 | return; | ||
146 | } | ||
147 | info(udev, "%s failed with SK=%Xh/ASC=%02Xh/ACQ=%02Xh\n", cmd, SK(err), ASC(err), ASCQ(err)); | ||
148 | } | ||
149 | |||
150 | struct scsi_cmd { | ||
151 | struct cdrom_generic_command cgc; | ||
152 | union { | ||
153 | struct request_sense s; | ||
154 | unsigned char u[18]; | ||
155 | } _sense; | ||
156 | struct sg_io_hdr sg_io; | ||
157 | }; | ||
158 | |||
159 | static void scsi_cmd_init(struct udev *udev, struct scsi_cmd *cmd) | ||
160 | { | ||
161 | memset(cmd, 0x00, sizeof(struct scsi_cmd)); | ||
162 | cmd->cgc.quiet = 1; | ||
163 | cmd->cgc.sense = &cmd->_sense.s; | ||
164 | cmd->sg_io.interface_id = 'S'; | ||
165 | cmd->sg_io.mx_sb_len = sizeof(cmd->_sense); | ||
166 | cmd->sg_io.cmdp = cmd->cgc.cmd; | ||
167 | cmd->sg_io.sbp = cmd->_sense.u; | ||
168 | cmd->sg_io.flags = SG_FLAG_LUN_INHIBIT | SG_FLAG_DIRECT_IO; | ||
169 | } | ||
170 | |||
171 | static void scsi_cmd_set(struct udev *udev, struct scsi_cmd *cmd, size_t i, unsigned char arg) | ||
172 | { | ||
173 | cmd->sg_io.cmd_len = i + 1; | ||
174 | cmd->cgc.cmd[i] = arg; | ||
175 | } | ||
176 | |||
177 | #define CHECK_CONDITION 0x01 | ||
178 | |||
179 | static int scsi_cmd_run(struct udev *udev, struct scsi_cmd *cmd, int fd, unsigned char *buf, size_t bufsize) | ||
180 | { | ||
181 | int ret = 0; | ||
182 | |||
183 | if (bufsize > 0) { | ||
184 | cmd->sg_io.dxferp = buf; | ||
185 | cmd->sg_io.dxfer_len = bufsize; | ||
186 | cmd->sg_io.dxfer_direction = SG_DXFER_FROM_DEV; | ||
187 | } else { | ||
188 | cmd->sg_io.dxfer_direction = SG_DXFER_NONE; | ||
189 | } | ||
190 | if (ioctl(fd, SG_IO, &cmd->sg_io)) | ||
191 | return -1; | ||
192 | |||
193 | if ((cmd->sg_io.info & SG_INFO_OK_MASK) != SG_INFO_OK) { | ||
194 | errno = EIO; | ||
195 | ret = -1; | ||
196 | if (cmd->sg_io.masked_status & CHECK_CONDITION) { | ||
197 | ret = ERRCODE(cmd->_sense.u); | ||
198 | if (ret == 0) | ||
199 | ret = -1; | ||
200 | } | ||
201 | } | ||
202 | return ret; | ||
203 | } | ||
204 | |||
205 | static int media_lock(struct udev *udev, int fd, bool lock) | ||
206 | { | ||
207 | int err; | ||
208 | |||
209 | /* disable the kernel's lock logic */ | ||
210 | err = ioctl(fd, CDROM_CLEAR_OPTIONS, CDO_LOCK); | ||
211 | if (err < 0) | ||
212 | info(udev, "CDROM_CLEAR_OPTIONS, CDO_LOCK failed\n"); | ||
213 | |||
214 | err = ioctl(fd, CDROM_LOCKDOOR, lock ? 1 : 0); | ||
215 | if (err < 0) | ||
216 | info(udev, "CDROM_LOCKDOOR failed\n"); | ||
217 | |||
218 | return err; | ||
219 | } | ||
220 | |||
221 | static int media_eject(struct udev *udev, int fd) | ||
222 | { | ||
223 | struct scsi_cmd sc; | ||
224 | int err; | ||
225 | |||
226 | scsi_cmd_init(udev, &sc); | ||
227 | scsi_cmd_set(udev, &sc, 0, 0x1b); | ||
228 | scsi_cmd_set(udev, &sc, 4, 0x02); | ||
229 | scsi_cmd_set(udev, &sc, 5, 0); | ||
230 | err = scsi_cmd_run(udev, &sc, fd, NULL, 0); | ||
231 | if ((err != 0)) { | ||
232 | info_scsi_cmd_err(udev, "START_STOP_UNIT", err); | ||
233 | return -1; | ||
234 | } | ||
235 | return 0; | ||
236 | } | ||
237 | |||
238 | static int cd_capability_compat(struct udev *udev, int fd) | ||
239 | { | ||
240 | int capability; | ||
241 | |||
242 | capability = ioctl(fd, CDROM_GET_CAPABILITY, NULL); | ||
243 | if (capability < 0) { | ||
244 | info(udev, "CDROM_GET_CAPABILITY failed\n"); | ||
245 | return -1; | ||
246 | } | ||
247 | |||
248 | if (capability & CDC_CD_R) | ||
249 | cd_cd_r = 1; | ||
250 | if (capability & CDC_CD_RW) | ||
251 | cd_cd_rw = 1; | ||
252 | if (capability & CDC_DVD) | ||
253 | cd_dvd_rom = 1; | ||
254 | if (capability & CDC_DVD_R) | ||
255 | cd_dvd_r = 1; | ||
256 | if (capability & CDC_DVD_RAM) | ||
257 | cd_dvd_ram = 1; | ||
258 | if (capability & CDC_MRW) | ||
259 | cd_mrw = 1; | ||
260 | if (capability & CDC_MRW_W) | ||
261 | cd_mrw_w = 1; | ||
262 | return 0; | ||
263 | } | ||
264 | |||
265 | static int cd_media_compat(struct udev *udev, int fd) | ||
266 | { | ||
267 | if (ioctl(fd, CDROM_DRIVE_STATUS, CDSL_CURRENT) != CDS_DISC_OK) { | ||
268 | info(udev, "CDROM_DRIVE_STATUS != CDS_DISC_OK\n"); | ||
269 | return -1; | ||
270 | } | ||
271 | cd_media = 1; | ||
272 | return 0; | ||
273 | } | ||
274 | |||
275 | static int cd_inquiry(struct udev *udev, int fd) | ||
276 | { | ||
277 | struct scsi_cmd sc; | ||
278 | unsigned char inq[128]; | ||
279 | int err; | ||
280 | |||
281 | scsi_cmd_init(udev, &sc); | ||
282 | scsi_cmd_set(udev, &sc, 0, 0x12); | ||
283 | scsi_cmd_set(udev, &sc, 4, 36); | ||
284 | scsi_cmd_set(udev, &sc, 5, 0); | ||
285 | err = scsi_cmd_run(udev, &sc, fd, inq, 36); | ||
286 | if ((err != 0)) { | ||
287 | info_scsi_cmd_err(udev, "INQUIRY", err); | ||
288 | return -1; | ||
289 | } | ||
290 | |||
291 | if ((inq[0] & 0x1F) != 5) { | ||
292 | info(udev, "not an MMC unit\n"); | ||
293 | return -1; | ||
294 | } | ||
295 | |||
296 | info(udev, "INQUIRY: [%.8s][%.16s][%.4s]\n", inq + 8, inq + 16, inq + 32); | ||
297 | return 0; | ||
298 | } | ||
299 | |||
300 | static void feature_profile_media(struct udev *udev, int cur_profile) | ||
301 | { | ||
302 | switch (cur_profile) { | ||
303 | case 0x03: | ||
304 | case 0x04: | ||
305 | case 0x05: | ||
306 | info(udev, "profile 0x%02x \n", cur_profile); | ||
307 | cd_media = 1; | ||
308 | cd_media_mo = 1; | ||
309 | break; | ||
310 | case 0x08: | ||
311 | info(udev, "profile 0x%02x media_cd_rom\n", cur_profile); | ||
312 | cd_media = 1; | ||
313 | cd_media_cd_rom = 1; | ||
314 | break; | ||
315 | case 0x09: | ||
316 | info(udev, "profile 0x%02x media_cd_r\n", cur_profile); | ||
317 | cd_media = 1; | ||
318 | cd_media_cd_r = 1; | ||
319 | break; | ||
320 | case 0x0a: | ||
321 | info(udev, "profile 0x%02x media_cd_rw\n", cur_profile); | ||
322 | cd_media = 1; | ||
323 | cd_media_cd_rw = 1; | ||
324 | break; | ||
325 | case 0x10: | ||
326 | info(udev, "profile 0x%02x media_dvd_ro\n", cur_profile); | ||
327 | cd_media = 1; | ||
328 | cd_media_dvd_rom = 1; | ||
329 | break; | ||
330 | case 0x11: | ||
331 | info(udev, "profile 0x%02x media_dvd_r\n", cur_profile); | ||
332 | cd_media = 1; | ||
333 | cd_media_dvd_r = 1; | ||
334 | break; | ||
335 | case 0x12: | ||
336 | info(udev, "profile 0x%02x media_dvd_ram\n", cur_profile); | ||
337 | cd_media = 1; | ||
338 | cd_media_dvd_ram = 1; | ||
339 | break; | ||
340 | case 0x13: | ||
341 | info(udev, "profile 0x%02x media_dvd_rw_ro\n", cur_profile); | ||
342 | cd_media = 1; | ||
343 | cd_media_dvd_rw = 1; | ||
344 | cd_media_dvd_rw_ro = 1; | ||
345 | break; | ||
346 | case 0x14: | ||
347 | info(udev, "profile 0x%02x media_dvd_rw_seq\n", cur_profile); | ||
348 | cd_media = 1; | ||
349 | cd_media_dvd_rw = 1; | ||
350 | cd_media_dvd_rw_seq = 1; | ||
351 | break; | ||
352 | case 0x1B: | ||
353 | info(udev, "profile 0x%02x media_dvd_plus_r\n", cur_profile); | ||
354 | cd_media = 1; | ||
355 | cd_media_dvd_plus_r = 1; | ||
356 | break; | ||
357 | case 0x1A: | ||
358 | info(udev, "profile 0x%02x media_dvd_plus_rw\n", cur_profile); | ||
359 | cd_media = 1; | ||
360 | cd_media_dvd_plus_rw = 1; | ||
361 | break; | ||
362 | case 0x2A: | ||
363 | info(udev, "profile 0x%02x media_dvd_plus_rw_dl\n", cur_profile); | ||
364 | cd_media = 1; | ||
365 | cd_media_dvd_plus_rw_dl = 1; | ||
366 | break; | ||
367 | case 0x2B: | ||
368 | info(udev, "profile 0x%02x media_dvd_plus_r_dl\n", cur_profile); | ||
369 | cd_media = 1; | ||
370 | cd_media_dvd_plus_r_dl = 1; | ||
371 | break; | ||
372 | case 0x40: | ||
373 | info(udev, "profile 0x%02x media_bd\n", cur_profile); | ||
374 | cd_media = 1; | ||
375 | cd_media_bd = 1; | ||
376 | break; | ||
377 | case 0x41: | ||
378 | case 0x42: | ||
379 | info(udev, "profile 0x%02x media_bd_r\n", cur_profile); | ||
380 | cd_media = 1; | ||
381 | cd_media_bd_r = 1; | ||
382 | break; | ||
383 | case 0x43: | ||
384 | info(udev, "profile 0x%02x media_bd_re\n", cur_profile); | ||
385 | cd_media = 1; | ||
386 | cd_media_bd_re = 1; | ||
387 | break; | ||
388 | case 0x50: | ||
389 | info(udev, "profile 0x%02x media_hddvd\n", cur_profile); | ||
390 | cd_media = 1; | ||
391 | cd_media_hddvd = 1; | ||
392 | break; | ||
393 | case 0x51: | ||
394 | info(udev, "profile 0x%02x media_hddvd_r\n", cur_profile); | ||
395 | cd_media = 1; | ||
396 | cd_media_hddvd_r = 1; | ||
397 | break; | ||
398 | case 0x52: | ||
399 | info(udev, "profile 0x%02x media_hddvd_rw\n", cur_profile); | ||
400 | cd_media = 1; | ||
401 | cd_media_hddvd_rw = 1; | ||
402 | break; | ||
403 | default: | ||
404 | info(udev, "profile 0x%02x <ignored>\n", cur_profile); | ||
405 | break; | ||
406 | } | ||
407 | } | ||
408 | |||
409 | static int feature_profiles(struct udev *udev, const unsigned char *profiles, size_t size) | ||
410 | { | ||
411 | unsigned int i; | ||
412 | |||
413 | for (i = 0; i+4 <= size; i += 4) { | ||
414 | int profile; | ||
415 | |||
416 | profile = profiles[i] << 8 | profiles[i+1]; | ||
417 | switch (profile) { | ||
418 | case 0x03: | ||
419 | case 0x04: | ||
420 | case 0x05: | ||
421 | info(udev, "profile 0x%02x mo\n", profile); | ||
422 | cd_mo = 1; | ||
423 | break; | ||
424 | case 0x08: | ||
425 | info(udev, "profile 0x%02x cd_rom\n", profile); | ||
426 | cd_cd_rom = 1; | ||
427 | break; | ||
428 | case 0x09: | ||
429 | info(udev, "profile 0x%02x cd_r\n", profile); | ||
430 | cd_cd_r = 1; | ||
431 | break; | ||
432 | case 0x0A: | ||
433 | info(udev, "profile 0x%02x cd_rw\n", profile); | ||
434 | cd_cd_rw = 1; | ||
435 | break; | ||
436 | case 0x10: | ||
437 | info(udev, "profile 0x%02x dvd_rom\n", profile); | ||
438 | cd_dvd_rom = 1; | ||
439 | break; | ||
440 | case 0x12: | ||
441 | info(udev, "profile 0x%02x dvd_ram\n", profile); | ||
442 | cd_dvd_ram = 1; | ||
443 | break; | ||
444 | case 0x13: | ||
445 | case 0x14: | ||
446 | info(udev, "profile 0x%02x dvd_rw\n", profile); | ||
447 | cd_dvd_rw = 1; | ||
448 | break; | ||
449 | case 0x1B: | ||
450 | info(udev, "profile 0x%02x dvd_plus_r\n", profile); | ||
451 | cd_dvd_plus_r = 1; | ||
452 | break; | ||
453 | case 0x1A: | ||
454 | info(udev, "profile 0x%02x dvd_plus_rw\n", profile); | ||
455 | cd_dvd_plus_rw = 1; | ||
456 | break; | ||
457 | case 0x2A: | ||
458 | info(udev, "profile 0x%02x dvd_plus_rw_dl\n", profile); | ||
459 | cd_dvd_plus_rw_dl = 1; | ||
460 | break; | ||
461 | case 0x2B: | ||
462 | info(udev, "profile 0x%02x dvd_plus_r_dl\n", profile); | ||
463 | cd_dvd_plus_r_dl = 1; | ||
464 | break; | ||
465 | case 0x40: | ||
466 | cd_bd = 1; | ||
467 | info(udev, "profile 0x%02x bd\n", profile); | ||
468 | break; | ||
469 | case 0x41: | ||
470 | case 0x42: | ||
471 | cd_bd_r = 1; | ||
472 | info(udev, "profile 0x%02x bd_r\n", profile); | ||
473 | break; | ||
474 | case 0x43: | ||
475 | cd_bd_re = 1; | ||
476 | info(udev, "profile 0x%02x bd_re\n", profile); | ||
477 | break; | ||
478 | case 0x50: | ||
479 | cd_hddvd = 1; | ||
480 | info(udev, "profile 0x%02x hddvd\n", profile); | ||
481 | break; | ||
482 | case 0x51: | ||
483 | cd_hddvd_r = 1; | ||
484 | info(udev, "profile 0x%02x hddvd_r\n", profile); | ||
485 | break; | ||
486 | case 0x52: | ||
487 | cd_hddvd_rw = 1; | ||
488 | info(udev, "profile 0x%02x hddvd_rw\n", profile); | ||
489 | break; | ||
490 | default: | ||
491 | info(udev, "profile 0x%02x <ignored>\n", profile); | ||
492 | break; | ||
493 | } | ||
494 | } | ||
495 | return 0; | ||
496 | } | ||
497 | |||
498 | /* returns 0 if media was detected */ | ||
499 | static int cd_profiles_old_mmc(struct udev *udev, int fd) | ||
500 | { | ||
501 | struct scsi_cmd sc; | ||
502 | int err; | ||
503 | |||
504 | unsigned char header[32]; | ||
505 | |||
506 | scsi_cmd_init(udev, &sc); | ||
507 | scsi_cmd_set(udev, &sc, 0, 0x51); | ||
508 | scsi_cmd_set(udev, &sc, 8, sizeof(header)); | ||
509 | scsi_cmd_set(udev, &sc, 9, 0); | ||
510 | err = scsi_cmd_run(udev, &sc, fd, header, sizeof(header)); | ||
511 | if ((err != 0)) { | ||
512 | info_scsi_cmd_err(udev, "READ DISC INFORMATION", err); | ||
513 | if (cd_media == 1) { | ||
514 | info(udev, "no current profile, but disc is present; assuming CD-ROM\n"); | ||
515 | cd_media_cd_rom = 1; | ||
516 | return 0; | ||
517 | } else { | ||
518 | info(udev, "no current profile, assuming no media\n"); | ||
519 | return -1; | ||
520 | } | ||
521 | }; | ||
522 | |||
523 | cd_media = 1; | ||
524 | |||
525 | if (header[2] & 16) { | ||
526 | cd_media_cd_rw = 1; | ||
527 | info(udev, "profile 0x0a media_cd_rw\n"); | ||
528 | } else if ((header[2] & 3) < 2 && cd_cd_r) { | ||
529 | cd_media_cd_r = 1; | ||
530 | info(udev, "profile 0x09 media_cd_r\n"); | ||
531 | } else { | ||
532 | cd_media_cd_rom = 1; | ||
533 | info(udev, "profile 0x08 media_cd_rom\n"); | ||
534 | } | ||
535 | return 0; | ||
536 | } | ||
537 | |||
538 | /* returns 0 if media was detected */ | ||
539 | static int cd_profiles(struct udev *udev, int fd) | ||
540 | { | ||
541 | struct scsi_cmd sc; | ||
542 | unsigned char features[65530]; | ||
543 | unsigned int cur_profile = 0; | ||
544 | unsigned int len; | ||
545 | unsigned int i; | ||
546 | int err; | ||
547 | int ret; | ||
548 | |||
549 | ret = -1; | ||
550 | |||
551 | /* First query the current profile */ | ||
552 | scsi_cmd_init(udev, &sc); | ||
553 | scsi_cmd_set(udev, &sc, 0, 0x46); | ||
554 | scsi_cmd_set(udev, &sc, 8, 8); | ||
555 | scsi_cmd_set(udev, &sc, 9, 0); | ||
556 | err = scsi_cmd_run(udev, &sc, fd, features, 8); | ||
557 | if ((err != 0)) { | ||
558 | info_scsi_cmd_err(udev, "GET CONFIGURATION", err); | ||
559 | /* handle pre-MMC2 drives which do not support GET CONFIGURATION */ | ||
560 | if (SK(err) == 0x5 && ASC(err) == 0x20) { | ||
561 | info(udev, "drive is pre-MMC2 and does not support 46h get configuration command\n"); | ||
562 | info(udev, "trying to work around the problem\n"); | ||
563 | ret = cd_profiles_old_mmc(udev, fd); | ||
564 | } | ||
565 | goto out; | ||
566 | } | ||
567 | |||
568 | cur_profile = features[6] << 8 | features[7]; | ||
569 | if (cur_profile > 0) { | ||
570 | info(udev, "current profile 0x%02x\n", cur_profile); | ||
571 | feature_profile_media (udev, cur_profile); | ||
572 | ret = 0; /* we have media */ | ||
573 | } else { | ||
574 | info(udev, "no current profile, assuming no media\n"); | ||
575 | } | ||
576 | |||
577 | len = features[0] << 24 | features[1] << 16 | features[2] << 8 | features[3]; | ||
578 | info(udev, "GET CONFIGURATION: size of features buffer 0x%04x\n", len); | ||
579 | |||
580 | if (len > sizeof(features)) { | ||
581 | info(udev, "can not get features in a single query, truncating\n"); | ||
582 | len = sizeof(features); | ||
583 | } else if (len <= 8) { | ||
584 | len = sizeof(features); | ||
585 | } | ||
586 | |||
587 | /* Now get the full feature buffer */ | ||
588 | scsi_cmd_init(udev, &sc); | ||
589 | scsi_cmd_set(udev, &sc, 0, 0x46); | ||
590 | scsi_cmd_set(udev, &sc, 7, ( len >> 8 ) & 0xff); | ||
591 | scsi_cmd_set(udev, &sc, 8, len & 0xff); | ||
592 | scsi_cmd_set(udev, &sc, 9, 0); | ||
593 | err = scsi_cmd_run(udev, &sc, fd, features, len); | ||
594 | if ((err != 0)) { | ||
595 | info_scsi_cmd_err(udev, "GET CONFIGURATION", err); | ||
596 | return -1; | ||
597 | } | ||
598 | |||
599 | /* parse the length once more, in case the drive decided to have other features suddenly :) */ | ||
600 | len = features[0] << 24 | features[1] << 16 | features[2] << 8 | features[3]; | ||
601 | info(udev, "GET CONFIGURATION: size of features buffer 0x%04x\n", len); | ||
602 | |||
603 | if (len > sizeof(features)) { | ||
604 | info(udev, "can not get features in a single query, truncating\n"); | ||
605 | len = sizeof(features); | ||
606 | } | ||
607 | |||
608 | /* device features */ | ||
609 | for (i = 8; i+4 < len; i += (4 + features[i+3])) { | ||
610 | unsigned int feature; | ||
611 | |||
612 | feature = features[i] << 8 | features[i+1]; | ||
613 | |||
614 | switch (feature) { | ||
615 | case 0x00: | ||
616 | info(udev, "GET CONFIGURATION: feature 'profiles', with %i entries\n", features[i+3] / 4); | ||
617 | feature_profiles(udev, &features[i]+4, features[i+3]); | ||
618 | break; | ||
619 | default: | ||
620 | info(udev, "GET CONFIGURATION: feature 0x%04x <ignored>, with 0x%02x bytes\n", feature, features[i+3]); | ||
621 | break; | ||
622 | } | ||
623 | } | ||
624 | out: | ||
625 | return ret; | ||
626 | } | ||
627 | |||
628 | static int cd_media_info(struct udev *udev, int fd) | ||
629 | { | ||
630 | struct scsi_cmd sc; | ||
631 | unsigned char header[32]; | ||
632 | static const char *media_status[] = { | ||
633 | "blank", | ||
634 | "appendable", | ||
635 | "complete", | ||
636 | "other" | ||
637 | }; | ||
638 | int err; | ||
639 | |||
640 | scsi_cmd_init(udev, &sc); | ||
641 | scsi_cmd_set(udev, &sc, 0, 0x51); | ||
642 | scsi_cmd_set(udev, &sc, 8, sizeof(header) & 0xff); | ||
643 | scsi_cmd_set(udev, &sc, 9, 0); | ||
644 | err = scsi_cmd_run(udev, &sc, fd, header, sizeof(header)); | ||
645 | if ((err != 0)) { | ||
646 | info_scsi_cmd_err(udev, "READ DISC INFORMATION", err); | ||
647 | return -1; | ||
648 | }; | ||
649 | |||
650 | cd_media = 1; | ||
651 | info(udev, "disk type %02x\n", header[8]); | ||
652 | info(udev, "hardware reported media status: %s\n", media_status[header[2] & 3]); | ||
653 | |||
654 | /* exclude plain CDROM, some fake cdroms return 0 for "blank" media here */ | ||
655 | if (!cd_media_cd_rom) | ||
656 | cd_media_state = media_status[header[2] & 3]; | ||
657 | |||
658 | /* fresh DVD-RW in restricted overwite mode reports itself as | ||
659 | * "appendable"; change it to "blank" to make it consistent with what | ||
660 | * gets reported after blanking, and what userspace expects */ | ||
661 | if (cd_media_dvd_rw_ro && (header[2] & 3) == 1) | ||
662 | cd_media_state = media_status[0]; | ||
663 | |||
664 | /* DVD+RW discs (and DVD-RW in restricted mode) once formatted are | ||
665 | * always "complete", DVD-RAM are "other" or "complete" if the disc is | ||
666 | * write protected; we need to check the contents if it is blank */ | ||
667 | if ((cd_media_dvd_rw_ro || cd_media_dvd_plus_rw || cd_media_dvd_plus_rw_dl || cd_media_dvd_ram) && (header[2] & 3) > 1) { | ||
668 | unsigned char buffer[32 * 2048]; | ||
669 | unsigned char result, len; | ||
670 | int block, offset; | ||
671 | |||
672 | if (cd_media_dvd_ram) { | ||
673 | /* a write protected dvd-ram may report "complete" status */ | ||
674 | |||
675 | unsigned char dvdstruct[8]; | ||
676 | unsigned char format[12]; | ||
677 | |||
678 | scsi_cmd_init(udev, &sc); | ||
679 | scsi_cmd_set(udev, &sc, 0, 0xAD); | ||
680 | scsi_cmd_set(udev, &sc, 7, 0xC0); | ||
681 | scsi_cmd_set(udev, &sc, 9, sizeof(dvdstruct)); | ||
682 | scsi_cmd_set(udev, &sc, 11, 0); | ||
683 | err = scsi_cmd_run(udev, &sc, fd, dvdstruct, sizeof(dvdstruct)); | ||
684 | if ((err != 0)) { | ||
685 | info_scsi_cmd_err(udev, "READ DVD STRUCTURE", err); | ||
686 | return -1; | ||
687 | } | ||
688 | if (dvdstruct[4] & 0x02) { | ||
689 | cd_media_state = media_status[2]; | ||
690 | info(udev, "write-protected DVD-RAM media inserted\n"); | ||
691 | goto determined; | ||
692 | } | ||
693 | |||
694 | /* let's make sure we don't try to read unformatted media */ | ||
695 | scsi_cmd_init(udev, &sc); | ||
696 | scsi_cmd_set(udev, &sc, 0, 0x23); | ||
697 | scsi_cmd_set(udev, &sc, 8, sizeof(format)); | ||
698 | scsi_cmd_set(udev, &sc, 9, 0); | ||
699 | err = scsi_cmd_run(udev, &sc, fd, format, sizeof(format)); | ||
700 | if ((err != 0)) { | ||
701 | info_scsi_cmd_err(udev, "READ DVD FORMAT CAPACITIES", err); | ||
702 | return -1; | ||
703 | } | ||
704 | |||
705 | len = format[3]; | ||
706 | if (len & 7 || len < 16) { | ||
707 | info(udev, "invalid format capacities length\n"); | ||
708 | return -1; | ||
709 | } | ||
710 | |||
711 | switch(format[8] & 3) { | ||
712 | case 1: | ||
713 | info(udev, "unformatted DVD-RAM media inserted\n"); | ||
714 | /* This means that last format was interrupted | ||
715 | * or failed, blank dvd-ram discs are factory | ||
716 | * formatted. Take no action here as it takes | ||
717 | * quite a while to reformat a dvd-ram and it's | ||
718 | * not automatically started */ | ||
719 | goto determined; | ||
720 | |||
721 | case 2: | ||
722 | info(udev, "formatted DVD-RAM media inserted\n"); | ||
723 | break; | ||
724 | |||
725 | case 3: | ||
726 | cd_media = 0; //return no media | ||
727 | info(udev, "format capacities returned no media\n"); | ||
728 | return -1; | ||
729 | } | ||
730 | } | ||
731 | |||
732 | /* Take a closer look at formatted media (unformatted DVD+RW | ||
733 | * has "blank" status", DVD-RAM was examined earlier) and check | ||
734 | * for ISO and UDF PVDs or a fs superblock presence and do it | ||
735 | * in one ioctl (we need just sectors 0 and 16) */ | ||
736 | scsi_cmd_init(udev, &sc); | ||
737 | scsi_cmd_set(udev, &sc, 0, 0x28); | ||
738 | scsi_cmd_set(udev, &sc, 5, 0); | ||
739 | scsi_cmd_set(udev, &sc, 8, 32); | ||
740 | scsi_cmd_set(udev, &sc, 9, 0); | ||
741 | err = scsi_cmd_run(udev, &sc, fd, buffer, sizeof(buffer)); | ||
742 | if ((err != 0)) { | ||
743 | cd_media = 0; | ||
744 | info_scsi_cmd_err(udev, "READ FIRST 32 BLOCKS", err); | ||
745 | return -1; | ||
746 | } | ||
747 | |||
748 | /* if any non-zero data is found in sector 16 (iso and udf) or | ||
749 | * eventually 0 (fat32 boot sector, ext2 superblock, etc), disc | ||
750 | * is assumed non-blank */ | ||
751 | result = 0; | ||
752 | |||
753 | for (block = 32768; block >= 0 && !result; block -= 32768) { | ||
754 | offset = block; | ||
755 | while (offset < (block + 2048) && !result) { | ||
756 | result = buffer [offset]; | ||
757 | offset++; | ||
758 | } | ||
759 | } | ||
760 | |||
761 | if (!result) { | ||
762 | cd_media_state = media_status[0]; | ||
763 | info(udev, "no data in blocks 0 or 16, assuming blank\n"); | ||
764 | } else { | ||
765 | info(udev, "data in blocks 0 or 16, assuming complete\n"); | ||
766 | } | ||
767 | } | ||
768 | |||
769 | determined: | ||
770 | /* "other" is e. g. DVD-RAM, can't append sessions there; DVDs in | ||
771 | * restricted overwrite mode can never append, only in sequential mode */ | ||
772 | if ((header[2] & 3) < 2 && !cd_media_dvd_rw_ro) | ||
773 | cd_media_session_next = header[10] << 8 | header[5]; | ||
774 | cd_media_session_count = header[9] << 8 | header[4]; | ||
775 | cd_media_track_count = header[11] << 8 | header[6]; | ||
776 | |||
777 | return 0; | ||
778 | } | ||
779 | |||
780 | static int cd_media_toc(struct udev *udev, int fd) | ||
781 | { | ||
782 | struct scsi_cmd sc; | ||
783 | unsigned char header[12]; | ||
784 | unsigned char toc[65536]; | ||
785 | unsigned int len, i, num_tracks; | ||
786 | unsigned char *p; | ||
787 | int err; | ||
788 | |||
789 | scsi_cmd_init(udev, &sc); | ||
790 | scsi_cmd_set(udev, &sc, 0, 0x43); | ||
791 | scsi_cmd_set(udev, &sc, 6, 1); | ||
792 | scsi_cmd_set(udev, &sc, 8, sizeof(header) & 0xff); | ||
793 | scsi_cmd_set(udev, &sc, 9, 0); | ||
794 | err = scsi_cmd_run(udev, &sc, fd, header, sizeof(header)); | ||
795 | if ((err != 0)) { | ||
796 | info_scsi_cmd_err(udev, "READ TOC", err); | ||
797 | return -1; | ||
798 | } | ||
799 | |||
800 | len = (header[0] << 8 | header[1]) + 2; | ||
801 | info(udev, "READ TOC: len: %d, start track: %d, end track: %d\n", len, header[2], header[3]); | ||
802 | if (len > sizeof(toc)) | ||
803 | return -1; | ||
804 | if (len < 2) | ||
805 | return -1; | ||
806 | /* 2: first track, 3: last track */ | ||
807 | num_tracks = header[3] - header[2] + 1; | ||
808 | |||
809 | /* empty media has no tracks */ | ||
810 | if (len < 8) | ||
811 | return 0; | ||
812 | |||
813 | scsi_cmd_init(udev, &sc); | ||
814 | scsi_cmd_set(udev, &sc, 0, 0x43); | ||
815 | scsi_cmd_set(udev, &sc, 6, header[2]); /* First Track/Session Number */ | ||
816 | scsi_cmd_set(udev, &sc, 7, (len >> 8) & 0xff); | ||
817 | scsi_cmd_set(udev, &sc, 8, len & 0xff); | ||
818 | scsi_cmd_set(udev, &sc, 9, 0); | ||
819 | err = scsi_cmd_run(udev, &sc, fd, toc, len); | ||
820 | if ((err != 0)) { | ||
821 | info_scsi_cmd_err(udev, "READ TOC (tracks)", err); | ||
822 | return -1; | ||
823 | } | ||
824 | |||
825 | /* Take care to not iterate beyond the last valid track as specified in | ||
826 | * the TOC, but also avoid going beyond the TOC length, just in case | ||
827 | * the last track number is invalidly large */ | ||
828 | for (p = toc+4, i = 4; i < len-8 && num_tracks > 0; i += 8, p += 8, --num_tracks) { | ||
829 | unsigned int block; | ||
830 | unsigned int is_data_track; | ||
831 | |||
832 | is_data_track = (p[1] & 0x04) != 0; | ||
833 | |||
834 | block = p[4] << 24 | p[5] << 16 | p[6] << 8 | p[7]; | ||
835 | info(udev, "track=%u info=0x%x(%s) start_block=%u\n", | ||
836 | p[2], p[1] & 0x0f, is_data_track ? "data":"audio", block); | ||
837 | |||
838 | if (is_data_track) | ||
839 | cd_media_track_count_data++; | ||
840 | else | ||
841 | cd_media_track_count_audio++; | ||
842 | } | ||
843 | |||
844 | scsi_cmd_init(udev, &sc); | ||
845 | scsi_cmd_set(udev, &sc, 0, 0x43); | ||
846 | scsi_cmd_set(udev, &sc, 2, 1); /* Session Info */ | ||
847 | scsi_cmd_set(udev, &sc, 8, sizeof(header)); | ||
848 | scsi_cmd_set(udev, &sc, 9, 0); | ||
849 | err = scsi_cmd_run(udev, &sc, fd, header, sizeof(header)); | ||
850 | if ((err != 0)) { | ||
851 | info_scsi_cmd_err(udev, "READ TOC (multi session)", err); | ||
852 | return -1; | ||
853 | } | ||
854 | len = header[4+4] << 24 | header[4+5] << 16 | header[4+6] << 8 | header[4+7]; | ||
855 | info(udev, "last track %u starts at block %u\n", header[4+2], len); | ||
856 | cd_media_session_last_offset = (unsigned long long int)len * 2048; | ||
857 | return 0; | ||
858 | } | ||
859 | |||
860 | int main(int argc, char *argv[]) | ||
861 | { | ||
862 | struct udev *udev; | ||
863 | static const struct option options[] = { | ||
864 | { "lock-media", no_argument, NULL, 'l' }, | ||
865 | { "unlock-media", no_argument, NULL, 'u' }, | ||
866 | { "eject-media", no_argument, NULL, 'e' }, | ||
867 | { "debug", no_argument, NULL, 'd' }, | ||
868 | { "help", no_argument, NULL, 'h' }, | ||
869 | {} | ||
870 | }; | ||
871 | bool eject = false; | ||
872 | bool lock = false; | ||
873 | bool unlock = false; | ||
874 | const char *node = NULL; | ||
875 | int fd = -1; | ||
876 | int cnt; | ||
877 | int rc = 0; | ||
878 | |||
879 | udev = udev_new(); | ||
880 | if (udev == NULL) | ||
881 | goto exit; | ||
882 | |||
883 | udev_log_init("cdrom_id"); | ||
884 | udev_set_log_fn(udev, log_fn); | ||
885 | |||
886 | while (1) { | ||
887 | int option; | ||
888 | |||
889 | option = getopt_long(argc, argv, "deluh", options, NULL); | ||
890 | if (option == -1) | ||
891 | break; | ||
892 | |||
893 | switch (option) { | ||
894 | case 'l': | ||
895 | lock = true; | ||
896 | break; | ||
897 | case 'u': | ||
898 | unlock = true; | ||
899 | break; | ||
900 | case 'e': | ||
901 | eject = true; | ||
902 | break; | ||
903 | case 'd': | ||
904 | debug = true; | ||
905 | if (udev_get_log_priority(udev) < LOG_INFO) | ||
906 | udev_set_log_priority(udev, LOG_INFO); | ||
907 | break; | ||
908 | case 'h': | ||
909 | printf("Usage: cdrom_id [options] <device>\n" | ||
910 | " --lock-media lock the media (to enable eject request events)\n" | ||
911 | " --unlock-media unlock the media\n" | ||
912 | " --eject-media eject the media\n" | ||
913 | " --debug debug to stderr\n" | ||
914 | " --help print this help text\n\n"); | ||
915 | goto exit; | ||
916 | default: | ||
917 | rc = 1; | ||
918 | goto exit; | ||
919 | } | ||
920 | } | ||
921 | |||
922 | node = argv[optind]; | ||
923 | if (!node) { | ||
924 | err(udev, "no device\n"); | ||
925 | fprintf(stderr, "no device\n"); | ||
926 | rc = 1; | ||
927 | goto exit; | ||
928 | } | ||
929 | |||
930 | srand((unsigned int)getpid()); | ||
931 | for (cnt = 20; cnt > 0; cnt--) { | ||
932 | struct timespec duration; | ||
933 | |||
934 | fd = open(node, O_RDONLY|O_NONBLOCK|(is_mounted(node) ? 0 : O_EXCL)); | ||
935 | if (fd >= 0 || errno != EBUSY) | ||
936 | break; | ||
937 | duration.tv_sec = 0; | ||
938 | duration.tv_nsec = (100 * 1000 * 1000) + (rand() % 100 * 1000 * 1000); | ||
939 | nanosleep(&duration, NULL); | ||
940 | } | ||
941 | if (fd < 0) { | ||
942 | info(udev, "unable to open '%s'\n", node); | ||
943 | fprintf(stderr, "unable to open '%s'\n", node); | ||
944 | rc = 1; | ||
945 | goto exit; | ||
946 | } | ||
947 | info(udev, "probing: '%s'\n", node); | ||
948 | |||
949 | /* same data as original cdrom_id */ | ||
950 | if (cd_capability_compat(udev, fd) < 0) { | ||
951 | rc = 1; | ||
952 | goto exit; | ||
953 | } | ||
954 | |||
955 | /* check for media - don't bail if there's no media as we still need to | ||
956 | * to read profiles */ | ||
957 | cd_media_compat(udev, fd); | ||
958 | |||
959 | /* check if drive talks MMC */ | ||
960 | if (cd_inquiry(udev, fd) < 0) | ||
961 | goto work; | ||
962 | |||
963 | /* read drive and possibly current profile */ | ||
964 | if (cd_profiles(udev, fd) != 0) | ||
965 | goto work; | ||
966 | |||
967 | /* at this point we are guaranteed to have media in the drive - find out more about it */ | ||
968 | |||
969 | /* get session/track info */ | ||
970 | cd_media_toc(udev, fd); | ||
971 | |||
972 | /* get writable media state */ | ||
973 | cd_media_info(udev, fd); | ||
974 | |||
975 | work: | ||
976 | /* lock the media, so we enable eject button events */ | ||
977 | if (lock && cd_media) { | ||
978 | info(udev, "PREVENT_ALLOW_MEDIUM_REMOVAL (lock)\n"); | ||
979 | media_lock(udev, fd, true); | ||
980 | } | ||
981 | |||
982 | if (unlock && cd_media) { | ||
983 | info(udev, "PREVENT_ALLOW_MEDIUM_REMOVAL (unlock)\n"); | ||
984 | media_lock(udev, fd, false); | ||
985 | } | ||
986 | |||
987 | if (eject) { | ||
988 | info(udev, "PREVENT_ALLOW_MEDIUM_REMOVAL (unlock)\n"); | ||
989 | media_lock(udev, fd, false); | ||
990 | info(udev, "START_STOP_UNIT (eject)\n"); | ||
991 | media_eject(udev, fd); | ||
992 | } | ||
993 | |||
994 | printf("ID_CDROM=1\n"); | ||
995 | if (cd_cd_rom) | ||
996 | printf("ID_CDROM_CD=1\n"); | ||
997 | if (cd_cd_r) | ||
998 | printf("ID_CDROM_CD_R=1\n"); | ||
999 | if (cd_cd_rw) | ||
1000 | printf("ID_CDROM_CD_RW=1\n"); | ||
1001 | if (cd_dvd_rom) | ||
1002 | printf("ID_CDROM_DVD=1\n"); | ||
1003 | if (cd_dvd_r) | ||
1004 | printf("ID_CDROM_DVD_R=1\n"); | ||
1005 | if (cd_dvd_rw) | ||
1006 | printf("ID_CDROM_DVD_RW=1\n"); | ||
1007 | if (cd_dvd_ram) | ||
1008 | printf("ID_CDROM_DVD_RAM=1\n"); | ||
1009 | if (cd_dvd_plus_r) | ||
1010 | printf("ID_CDROM_DVD_PLUS_R=1\n"); | ||
1011 | if (cd_dvd_plus_rw) | ||
1012 | printf("ID_CDROM_DVD_PLUS_RW=1\n"); | ||
1013 | if (cd_dvd_plus_r_dl) | ||
1014 | printf("ID_CDROM_DVD_PLUS_R_DL=1\n"); | ||
1015 | if (cd_dvd_plus_rw_dl) | ||
1016 | printf("ID_CDROM_DVD_PLUS_RW_DL=1\n"); | ||
1017 | if (cd_bd) | ||
1018 | printf("ID_CDROM_BD=1\n"); | ||
1019 | if (cd_bd_r) | ||
1020 | printf("ID_CDROM_BD_R=1\n"); | ||
1021 | if (cd_bd_re) | ||
1022 | printf("ID_CDROM_BD_RE=1\n"); | ||
1023 | if (cd_hddvd) | ||
1024 | printf("ID_CDROM_HDDVD=1\n"); | ||
1025 | if (cd_hddvd_r) | ||
1026 | printf("ID_CDROM_HDDVD_R=1\n"); | ||
1027 | if (cd_hddvd_rw) | ||
1028 | printf("ID_CDROM_HDDVD_RW=1\n"); | ||
1029 | if (cd_mo) | ||
1030 | printf("ID_CDROM_MO=1\n"); | ||
1031 | if (cd_mrw) | ||
1032 | printf("ID_CDROM_MRW=1\n"); | ||
1033 | if (cd_mrw_w) | ||
1034 | printf("ID_CDROM_MRW_W=1\n"); | ||
1035 | |||
1036 | if (cd_media) | ||
1037 | printf("ID_CDROM_MEDIA=1\n"); | ||
1038 | if (cd_media_mo) | ||
1039 | printf("ID_CDROM_MEDIA_MO=1\n"); | ||
1040 | if (cd_media_mrw) | ||
1041 | printf("ID_CDROM_MEDIA_MRW=1\n"); | ||
1042 | if (cd_media_mrw_w) | ||
1043 | printf("ID_CDROM_MEDIA_MRW_W=1\n"); | ||
1044 | if (cd_media_cd_rom) | ||
1045 | printf("ID_CDROM_MEDIA_CD=1\n"); | ||
1046 | if (cd_media_cd_r) | ||
1047 | printf("ID_CDROM_MEDIA_CD_R=1\n"); | ||
1048 | if (cd_media_cd_rw) | ||
1049 | printf("ID_CDROM_MEDIA_CD_RW=1\n"); | ||
1050 | if (cd_media_dvd_rom) | ||
1051 | printf("ID_CDROM_MEDIA_DVD=1\n"); | ||
1052 | if (cd_media_dvd_r) | ||
1053 | printf("ID_CDROM_MEDIA_DVD_R=1\n"); | ||
1054 | if (cd_media_dvd_ram) | ||
1055 | printf("ID_CDROM_MEDIA_DVD_RAM=1\n"); | ||
1056 | if (cd_media_dvd_rw) | ||
1057 | printf("ID_CDROM_MEDIA_DVD_RW=1\n"); | ||
1058 | if (cd_media_dvd_plus_r) | ||
1059 | printf("ID_CDROM_MEDIA_DVD_PLUS_R=1\n"); | ||
1060 | if (cd_media_dvd_plus_rw) | ||
1061 | printf("ID_CDROM_MEDIA_DVD_PLUS_RW=1\n"); | ||
1062 | if (cd_media_dvd_plus_rw_dl) | ||
1063 | printf("ID_CDROM_MEDIA_DVD_PLUS_RW_DL=1\n"); | ||
1064 | if (cd_media_dvd_plus_r_dl) | ||
1065 | printf("ID_CDROM_MEDIA_DVD_PLUS_R_DL=1\n"); | ||
1066 | if (cd_media_bd) | ||
1067 | printf("ID_CDROM_MEDIA_BD=1\n"); | ||
1068 | if (cd_media_bd_r) | ||
1069 | printf("ID_CDROM_MEDIA_BD_R=1\n"); | ||
1070 | if (cd_media_bd_re) | ||
1071 | printf("ID_CDROM_MEDIA_BD_RE=1\n"); | ||
1072 | if (cd_media_hddvd) | ||
1073 | printf("ID_CDROM_MEDIA_HDDVD=1\n"); | ||
1074 | if (cd_media_hddvd_r) | ||
1075 | printf("ID_CDROM_MEDIA_HDDVD_R=1\n"); | ||
1076 | if (cd_media_hddvd_rw) | ||
1077 | printf("ID_CDROM_MEDIA_HDDVD_RW=1\n"); | ||
1078 | |||
1079 | if (cd_media_state != NULL) | ||
1080 | printf("ID_CDROM_MEDIA_STATE=%s\n", cd_media_state); | ||
1081 | if (cd_media_session_next > 0) | ||
1082 | printf("ID_CDROM_MEDIA_SESSION_NEXT=%d\n", cd_media_session_next); | ||
1083 | if (cd_media_session_count > 0) | ||
1084 | printf("ID_CDROM_MEDIA_SESSION_COUNT=%d\n", cd_media_session_count); | ||
1085 | if (cd_media_session_count > 1 && cd_media_session_last_offset > 0) | ||
1086 | printf("ID_CDROM_MEDIA_SESSION_LAST_OFFSET=%llu\n", cd_media_session_last_offset); | ||
1087 | if (cd_media_track_count > 0) | ||
1088 | printf("ID_CDROM_MEDIA_TRACK_COUNT=%d\n", cd_media_track_count); | ||
1089 | if (cd_media_track_count_audio > 0) | ||
1090 | printf("ID_CDROM_MEDIA_TRACK_COUNT_AUDIO=%d\n", cd_media_track_count_audio); | ||
1091 | if (cd_media_track_count_data > 0) | ||
1092 | printf("ID_CDROM_MEDIA_TRACK_COUNT_DATA=%d\n", cd_media_track_count_data); | ||
1093 | exit: | ||
1094 | if (fd >= 0) | ||
1095 | close(fd); | ||
1096 | udev_unref(udev); | ||
1097 | udev_log_close(); | ||
1098 | return rc; | ||
1099 | } | ||
diff --git a/src/udev/src/collect/collect.c b/src/udev/src/collect/collect.c new file mode 100644 index 000000000..076fe479e --- /dev/null +++ b/src/udev/src/collect/collect.c | |||
@@ -0,0 +1,473 @@ | |||
1 | /* | ||
2 | * Collect variables across events. | ||
3 | * | ||
4 | * usage: collect [--add|--remove] <checkpoint> <id> <idlist> | ||
5 | * | ||
6 | * Adds ID <id> to the list governed by <checkpoint>. | ||
7 | * <id> must be part of the ID list <idlist>. | ||
8 | * If all IDs given by <idlist> are listed (ie collect has been | ||
9 | * invoked for each ID in <idlist>) collect returns 0, the | ||
10 | * number of missing IDs otherwise. | ||
11 | * A negative number is returned on error. | ||
12 | * | ||
13 | * Copyright(C) 2007, Hannes Reinecke <hare@suse.de> | ||
14 | * | ||
15 | * This program is free software: you can redistribute it and/or modify | ||
16 | * it under the terms of the GNU General Public License as published by | ||
17 | * the Free Software Foundation, either version 2 of the License, or | ||
18 | * (at your option) any later version. | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include <stdio.h> | ||
23 | #include <stdlib.h> | ||
24 | #include <stddef.h> | ||
25 | #include <unistd.h> | ||
26 | #include <signal.h> | ||
27 | #include <fcntl.h> | ||
28 | #include <errno.h> | ||
29 | #include <string.h> | ||
30 | #include <getopt.h> | ||
31 | #include <sys/types.h> | ||
32 | #include <sys/stat.h> | ||
33 | |||
34 | #include "libudev.h" | ||
35 | #include "libudev-private.h" | ||
36 | |||
37 | #define BUFSIZE 16 | ||
38 | #define UDEV_ALARM_TIMEOUT 180 | ||
39 | |||
40 | enum collect_state { | ||
41 | STATE_NONE, | ||
42 | STATE_OLD, | ||
43 | STATE_CONFIRMED, | ||
44 | }; | ||
45 | |||
46 | struct _mate { | ||
47 | struct udev_list_node node; | ||
48 | char *name; | ||
49 | enum collect_state state; | ||
50 | }; | ||
51 | |||
52 | static struct udev_list_node bunch; | ||
53 | static int debug; | ||
54 | |||
55 | /* This can increase dynamically */ | ||
56 | static size_t bufsize = BUFSIZE; | ||
57 | |||
58 | static struct _mate *node_to_mate(struct udev_list_node *node) | ||
59 | { | ||
60 | char *mate; | ||
61 | |||
62 | mate = (char *)node; | ||
63 | mate -= offsetof(struct _mate, node); | ||
64 | return (struct _mate *)mate; | ||
65 | } | ||
66 | |||
67 | static void sig_alrm(int signo) | ||
68 | { | ||
69 | exit(4); | ||
70 | } | ||
71 | |||
72 | static void usage(void) | ||
73 | { | ||
74 | printf("usage: collect [--add|--remove] [--debug] <checkpoint> <id> <idlist>\n" | ||
75 | "\n" | ||
76 | " Adds ID <id> to the list governed by <checkpoint>.\n" | ||
77 | " <id> must be part of the list <idlist>.\n" | ||
78 | " If all IDs given by <idlist> are listed (ie collect has been\n" | ||
79 | " invoked for each ID in <idlist>) collect returns 0, the\n" | ||
80 | " number of missing IDs otherwise.\n" | ||
81 | " On error a negative number is returned.\n" | ||
82 | "\n"); | ||
83 | } | ||
84 | |||
85 | /* | ||
86 | * prepare | ||
87 | * | ||
88 | * Prepares the database file | ||
89 | */ | ||
90 | static int prepare(char *dir, char *filename) | ||
91 | { | ||
92 | struct stat statbuf; | ||
93 | char buf[512]; | ||
94 | int fd; | ||
95 | |||
96 | if (stat(dir, &statbuf) < 0) | ||
97 | mkdir(dir, 0700); | ||
98 | |||
99 | sprintf(buf, "%s/%s", dir, filename); | ||
100 | |||
101 | fd = open(buf,O_RDWR|O_CREAT, S_IRUSR|S_IWUSR); | ||
102 | if (fd < 0) | ||
103 | fprintf(stderr, "Cannot open %s: %s\n", buf, strerror(errno)); | ||
104 | |||
105 | if (lockf(fd,F_TLOCK,0) < 0) { | ||
106 | if (debug) | ||
107 | fprintf(stderr, "Lock taken, wait for %d seconds\n", UDEV_ALARM_TIMEOUT); | ||
108 | if (errno == EAGAIN || errno == EACCES) { | ||
109 | alarm(UDEV_ALARM_TIMEOUT); | ||
110 | lockf(fd, F_LOCK, 0); | ||
111 | if (debug) | ||
112 | fprintf(stderr, "Acquired lock on %s\n", buf); | ||
113 | } else { | ||
114 | if (debug) | ||
115 | fprintf(stderr, "Could not get lock on %s: %s\n", buf, strerror(errno)); | ||
116 | } | ||
117 | } | ||
118 | |||
119 | return fd; | ||
120 | } | ||
121 | |||
122 | /* | ||
123 | * Read checkpoint file | ||
124 | * | ||
125 | * Tricky reading this. We allocate a buffer twice as large | ||
126 | * as we're going to read. Then we read into the upper half | ||
127 | * of that buffer and start parsing. | ||
128 | * Once we do _not_ find end-of-work terminator (whitespace | ||
129 | * character) we move the upper half to the lower half, | ||
130 | * adjust the read pointer and read the next bit. | ||
131 | * Quite clever methinks :-) | ||
132 | * I should become a programmer ... | ||
133 | * | ||
134 | * Yes, one could have used fgets() for this. But then we'd | ||
135 | * have to use freopen etc which I found quite tedious. | ||
136 | */ | ||
137 | static int checkout(int fd) | ||
138 | { | ||
139 | int len; | ||
140 | char *buf, *ptr, *word = NULL; | ||
141 | struct _mate *him; | ||
142 | |||
143 | restart: | ||
144 | len = bufsize >> 1; | ||
145 | buf = calloc(1,bufsize + 1); | ||
146 | if (!buf) { | ||
147 | fprintf(stderr, "Out of memory\n"); | ||
148 | return -1; | ||
149 | } | ||
150 | memset(buf, ' ', bufsize); | ||
151 | ptr = buf + len; | ||
152 | while ((read(fd, buf + len, len)) > 0) { | ||
153 | while (ptr && *ptr) { | ||
154 | word = ptr; | ||
155 | ptr = strpbrk(word," \n\t\r"); | ||
156 | if (!ptr && word < (buf + len)) { | ||
157 | bufsize = bufsize << 1; | ||
158 | if (debug) | ||
159 | fprintf(stderr, "ID overflow, restarting with size %zi\n", bufsize); | ||
160 | free(buf); | ||
161 | lseek(fd, 0, SEEK_SET); | ||
162 | goto restart; | ||
163 | } | ||
164 | if (ptr) { | ||
165 | *ptr = '\0'; | ||
166 | ptr++; | ||
167 | if (!strlen(word)) | ||
168 | continue; | ||
169 | |||
170 | if (debug) | ||
171 | fprintf(stderr, "Found word %s\n", word); | ||
172 | him = malloc(sizeof (struct _mate)); | ||
173 | him->name = strdup(word); | ||
174 | him->state = STATE_OLD; | ||
175 | udev_list_node_append(&him->node, &bunch); | ||
176 | word = NULL; | ||
177 | } | ||
178 | } | ||
179 | memcpy(buf, buf + len, len); | ||
180 | memset(buf + len, ' ', len); | ||
181 | |||
182 | if (!ptr) | ||
183 | ptr = word; | ||
184 | if (!ptr) | ||
185 | break; | ||
186 | ptr -= len; | ||
187 | } | ||
188 | |||
189 | free(buf); | ||
190 | return 0; | ||
191 | } | ||
192 | |||
193 | /* | ||
194 | * invite | ||
195 | * | ||
196 | * Adds a new ID 'us' to the internal list, | ||
197 | * marks it as confirmed. | ||
198 | */ | ||
199 | static void invite(char *us) | ||
200 | { | ||
201 | struct udev_list_node *him_node; | ||
202 | struct _mate *who = NULL; | ||
203 | |||
204 | if (debug) | ||
205 | fprintf(stderr, "Adding ID '%s'\n", us); | ||
206 | |||
207 | udev_list_node_foreach(him_node, &bunch) { | ||
208 | struct _mate *him = node_to_mate(him_node); | ||
209 | |||
210 | if (!strcmp(him->name, us)) { | ||
211 | him->state = STATE_CONFIRMED; | ||
212 | who = him; | ||
213 | } | ||
214 | } | ||
215 | if (debug && !who) | ||
216 | fprintf(stderr, "ID '%s' not in database\n", us); | ||
217 | |||
218 | } | ||
219 | |||
220 | /* | ||
221 | * reject | ||
222 | * | ||
223 | * Marks the ID 'us' as invalid, | ||
224 | * causing it to be removed when the | ||
225 | * list is written out. | ||
226 | */ | ||
227 | static void reject(char *us) | ||
228 | { | ||
229 | struct udev_list_node *him_node; | ||
230 | struct _mate *who = NULL; | ||
231 | |||
232 | if (debug) | ||
233 | fprintf(stderr, "Removing ID '%s'\n", us); | ||
234 | |||
235 | udev_list_node_foreach(him_node, &bunch) { | ||
236 | struct _mate *him = node_to_mate(him_node); | ||
237 | |||
238 | if (!strcmp(him->name, us)) { | ||
239 | him->state = STATE_NONE; | ||
240 | who = him; | ||
241 | } | ||
242 | } | ||
243 | if (debug && !who) | ||
244 | fprintf(stderr, "ID '%s' not in database\n", us); | ||
245 | } | ||
246 | |||
247 | /* | ||
248 | * kickout | ||
249 | * | ||
250 | * Remove all IDs in the internal list which are not part | ||
251 | * of the list passed via the commandline. | ||
252 | */ | ||
253 | static void kickout(void) | ||
254 | { | ||
255 | struct udev_list_node *him_node; | ||
256 | struct udev_list_node *tmp; | ||
257 | |||
258 | udev_list_node_foreach_safe(him_node, tmp, &bunch) { | ||
259 | struct _mate *him = node_to_mate(him_node); | ||
260 | |||
261 | if (him->state == STATE_OLD) { | ||
262 | udev_list_node_remove(&him->node); | ||
263 | free(him->name); | ||
264 | free(him); | ||
265 | } | ||
266 | } | ||
267 | } | ||
268 | |||
269 | /* | ||
270 | * missing | ||
271 | * | ||
272 | * Counts all missing IDs in the internal list. | ||
273 | */ | ||
274 | static int missing(int fd) | ||
275 | { | ||
276 | char *buf; | ||
277 | int ret = 0; | ||
278 | struct udev_list_node *him_node; | ||
279 | |||
280 | buf = malloc(bufsize); | ||
281 | if (!buf) | ||
282 | return -1; | ||
283 | |||
284 | udev_list_node_foreach(him_node, &bunch) { | ||
285 | struct _mate *him = node_to_mate(him_node); | ||
286 | |||
287 | if (him->state == STATE_NONE) { | ||
288 | ret++; | ||
289 | } else { | ||
290 | while (strlen(him->name)+1 >= bufsize) { | ||
291 | char *tmpbuf; | ||
292 | |||
293 | bufsize = bufsize << 1; | ||
294 | tmpbuf = realloc(buf, bufsize); | ||
295 | if (!tmpbuf) { | ||
296 | free(buf); | ||
297 | return -1; | ||
298 | } | ||
299 | buf = tmpbuf; | ||
300 | } | ||
301 | snprintf(buf, strlen(him->name)+2, "%s ", him->name); | ||
302 | write(fd, buf, strlen(buf)); | ||
303 | } | ||
304 | } | ||
305 | |||
306 | free(buf); | ||
307 | return ret; | ||
308 | } | ||
309 | |||
310 | /* | ||
311 | * everybody | ||
312 | * | ||
313 | * Prints out the status of the internal list. | ||
314 | */ | ||
315 | static void everybody(void) | ||
316 | { | ||
317 | struct udev_list_node *him_node; | ||
318 | const char *state = ""; | ||
319 | |||
320 | udev_list_node_foreach(him_node, &bunch) { | ||
321 | struct _mate *him = node_to_mate(him_node); | ||
322 | |||
323 | switch (him->state) { | ||
324 | case STATE_NONE: | ||
325 | state = "none"; | ||
326 | break; | ||
327 | case STATE_OLD: | ||
328 | state = "old"; | ||
329 | break; | ||
330 | case STATE_CONFIRMED: | ||
331 | state = "confirmed"; | ||
332 | break; | ||
333 | } | ||
334 | fprintf(stderr, "ID: %s=%s\n", him->name, state); | ||
335 | } | ||
336 | } | ||
337 | |||
338 | int main(int argc, char **argv) | ||
339 | { | ||
340 | struct udev *udev; | ||
341 | static const struct option options[] = { | ||
342 | { "add", no_argument, NULL, 'a' }, | ||
343 | { "remove", no_argument, NULL, 'r' }, | ||
344 | { "debug", no_argument, NULL, 'd' }, | ||
345 | { "help", no_argument, NULL, 'h' }, | ||
346 | {} | ||
347 | }; | ||
348 | int argi; | ||
349 | char *checkpoint, *us; | ||
350 | int fd; | ||
351 | int i; | ||
352 | int ret = EXIT_SUCCESS; | ||
353 | int prune = 0; | ||
354 | char tmpdir[UTIL_PATH_SIZE]; | ||
355 | |||
356 | udev = udev_new(); | ||
357 | if (udev == NULL) { | ||
358 | ret = EXIT_FAILURE; | ||
359 | goto exit; | ||
360 | } | ||
361 | |||
362 | while (1) { | ||
363 | int option; | ||
364 | |||
365 | option = getopt_long(argc, argv, "ardh", options, NULL); | ||
366 | if (option == -1) | ||
367 | break; | ||
368 | |||
369 | switch (option) { | ||
370 | case 'a': | ||
371 | prune = 0; | ||
372 | break; | ||
373 | case 'r': | ||
374 | prune = 1; | ||
375 | break; | ||
376 | case 'd': | ||
377 | debug = 1; | ||
378 | break; | ||
379 | case 'h': | ||
380 | usage(); | ||
381 | goto exit; | ||
382 | default: | ||
383 | ret = 1; | ||
384 | goto exit; | ||
385 | } | ||
386 | } | ||
387 | |||
388 | argi = optind; | ||
389 | if (argi + 2 > argc) { | ||
390 | printf("Missing parameter(s)\n"); | ||
391 | ret = 1; | ||
392 | goto exit; | ||
393 | } | ||
394 | checkpoint = argv[argi++]; | ||
395 | us = argv[argi++]; | ||
396 | |||
397 | if (signal(SIGALRM, sig_alrm) == SIG_ERR) { | ||
398 | fprintf(stderr, "Cannot set SIGALRM: %s\n", strerror(errno)); | ||
399 | ret = 2; | ||
400 | goto exit; | ||
401 | } | ||
402 | |||
403 | udev_list_node_init(&bunch); | ||
404 | |||
405 | if (debug) | ||
406 | fprintf(stderr, "Using checkpoint '%s'\n", checkpoint); | ||
407 | |||
408 | util_strscpyl(tmpdir, sizeof(tmpdir), udev_get_run_path(udev), "/collect", NULL); | ||
409 | fd = prepare(tmpdir, checkpoint); | ||
410 | if (fd < 0) { | ||
411 | ret = 3; | ||
412 | goto out; | ||
413 | } | ||
414 | |||
415 | if (checkout(fd) < 0) { | ||
416 | ret = 2; | ||
417 | goto out; | ||
418 | } | ||
419 | |||
420 | for (i = argi; i < argc; i++) { | ||
421 | struct udev_list_node *him_node; | ||
422 | struct _mate *who; | ||
423 | |||
424 | who = NULL; | ||
425 | udev_list_node_foreach(him_node, &bunch) { | ||
426 | struct _mate *him = node_to_mate(him_node); | ||
427 | |||
428 | if (!strcmp(him->name, argv[i])) | ||
429 | who = him; | ||
430 | } | ||
431 | if (!who) { | ||
432 | struct _mate *him; | ||
433 | |||
434 | if (debug) | ||
435 | fprintf(stderr, "ID %s: not in database\n", argv[i]); | ||
436 | him = malloc(sizeof (struct _mate)); | ||
437 | him->name = malloc(strlen(argv[i]) + 1); | ||
438 | strcpy(him->name, argv[i]); | ||
439 | him->state = STATE_NONE; | ||
440 | udev_list_node_append(&him->node, &bunch); | ||
441 | } else { | ||
442 | if (debug) | ||
443 | fprintf(stderr, "ID %s: found in database\n", argv[i]); | ||
444 | who->state = STATE_CONFIRMED; | ||
445 | } | ||
446 | } | ||
447 | |||
448 | if (prune) | ||
449 | reject(us); | ||
450 | else | ||
451 | invite(us); | ||
452 | |||
453 | if (debug) { | ||
454 | everybody(); | ||
455 | fprintf(stderr, "Prune lists\n"); | ||
456 | } | ||
457 | kickout(); | ||
458 | |||
459 | lseek(fd, 0, SEEK_SET); | ||
460 | ftruncate(fd, 0); | ||
461 | ret = missing(fd); | ||
462 | |||
463 | lockf(fd, F_ULOCK, 0); | ||
464 | close(fd); | ||
465 | out: | ||
466 | if (debug) | ||
467 | everybody(); | ||
468 | if (ret >= 0) | ||
469 | printf("COLLECT_%s=%d\n", checkpoint, ret); | ||
470 | exit: | ||
471 | udev_unref(udev); | ||
472 | return ret; | ||
473 | } | ||
diff --git a/src/udev/src/docs/.gitignore b/src/udev/src/docs/.gitignore new file mode 100644 index 000000000..dca700a99 --- /dev/null +++ b/src/udev/src/docs/.gitignore | |||
@@ -0,0 +1,17 @@ | |||
1 | libudev-overrides.txt | ||
2 | html/ | ||
3 | tmpl/ | ||
4 | xml/ | ||
5 | *.stamp | ||
6 | *.bak | ||
7 | version.xml | ||
8 | libudev-decl-list.txt | ||
9 | libudev-decl.txt | ||
10 | libudev-undeclared.txt | ||
11 | libudev-undocumented.txt | ||
12 | libudev-unused.txt | ||
13 | libudev.args | ||
14 | libudev.hierarchy | ||
15 | libudev.interfaces | ||
16 | libudev.prerequisites | ||
17 | libudev.signals | ||
diff --git a/src/udev/src/docs/Makefile.am b/src/udev/src/docs/Makefile.am new file mode 100644 index 000000000..07d06eb14 --- /dev/null +++ b/src/udev/src/docs/Makefile.am | |||
@@ -0,0 +1,99 @@ | |||
1 | ## Process this file with automake to produce Makefile.in | ||
2 | |||
3 | # We require automake 1.10 at least. | ||
4 | AUTOMAKE_OPTIONS = 1.10 | ||
5 | |||
6 | # This is a blank Makefile.am for using gtk-doc. | ||
7 | # Copy this to your project's API docs directory and modify the variables to | ||
8 | # suit your project. See the GTK+ Makefiles in gtk+/docs/reference for examples | ||
9 | # of using the various options. | ||
10 | |||
11 | # The name of the module, e.g. 'glib'. | ||
12 | DOC_MODULE=libudev | ||
13 | |||
14 | # Uncomment for versioned docs and specify the version of the module, e.g. '2'. | ||
15 | #DOC_MODULE_VERSION=2 | ||
16 | |||
17 | # The top-level SGML file. You can change this if you want to. | ||
18 | DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.xml | ||
19 | |||
20 | # The directory containing the source code. Relative to $(srcdir). | ||
21 | # gtk-doc will search all .c & .h files beneath here for inline comments | ||
22 | # documenting the functions and macros. | ||
23 | # e.g. DOC_SOURCE_DIR=../../../gtk | ||
24 | DOC_SOURCE_DIR=$(top_srcdir)/src | ||
25 | |||
26 | # Extra options to pass to gtkdoc-scangobj. Not normally needed. | ||
27 | SCANGOBJ_OPTIONS= | ||
28 | |||
29 | # Extra options to supply to gtkdoc-scan. | ||
30 | # e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED" | ||
31 | SCAN_OPTIONS= | ||
32 | |||
33 | # Extra options to supply to gtkdoc-mkdb. | ||
34 | # e.g. MKDB_OPTIONS=--sgml-mode --output-format=xml | ||
35 | MKDB_OPTIONS=--sgml-mode --output-format=xml --name-space udev | ||
36 | |||
37 | # Extra options to supply to gtkdoc-mktmpl | ||
38 | # e.g. MKTMPL_OPTIONS=--only-section-tmpl | ||
39 | MKTMPL_OPTIONS= | ||
40 | |||
41 | # Extra options to supply to gtkdoc-mkhtml | ||
42 | MKHTML_OPTIONS=--path=$(abs_srcdir) --path=$(abs_builddir) | ||
43 | |||
44 | # Extra options to supply to gtkdoc-fixref. Not normally needed. | ||
45 | # e.g. FIXXREF_OPTIONS=--extra-dir=../gdk-pixbuf/html --extra-dir=../gdk/html | ||
46 | FIXXREF_OPTIONS= | ||
47 | |||
48 | # Used for dependencies. The docs will be rebuilt if any of these change. | ||
49 | # e.g. HFILE_GLOB=$(top_srcdir)/gtk/*.h | ||
50 | # e.g. CFILE_GLOB=$(top_srcdir)/gtk/*.c | ||
51 | HFILE_GLOB=$(top_srcdir)/src/libudev*.h | ||
52 | CFILE_GLOB=$(top_srcdir)/src/libudev*.c | ||
53 | |||
54 | # Extra header to include when scanning, which are not under DOC_SOURCE_DIR | ||
55 | # e.g. EXTRA_HFILES=$(top_srcdir}/contrib/extra.h | ||
56 | EXTRA_HFILES= | ||
57 | |||
58 | # Header files to ignore when scanning. Use base file name, no paths | ||
59 | # e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h | ||
60 | IGNORE_HFILES= libudev-private.h | ||
61 | |||
62 | # Images to copy into HTML directory. | ||
63 | # e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png | ||
64 | HTML_IMAGES= | ||
65 | |||
66 | # Extra SGML files that are included by $(DOC_MAIN_SGML_FILE). | ||
67 | # e.g. content_files=running.sgml building.sgml changes-2.0.sgml | ||
68 | content_files = version.xml | ||
69 | |||
70 | # SGML files where gtk-doc abbrevations (#GtkWidget) are expanded | ||
71 | # These files must be listed here *and* in content_files | ||
72 | # e.g. expand_content_files=running.sgml | ||
73 | expand_content_files= | ||
74 | |||
75 | # CFLAGS and LDFLAGS for compiling gtkdoc-scangobj with your library. | ||
76 | # Only needed if you are using gtkdoc-scangobj to dynamically query widget | ||
77 | # signals and properties. | ||
78 | # e.g. GTKDOC_CFLAGS=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS) | ||
79 | # e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib) | ||
80 | GTKDOC_CFLAGS= | ||
81 | GTKDOC_LIBS= | ||
82 | |||
83 | # This includes the standard gtk-doc make rules, copied by gtkdocize. | ||
84 | include $(top_srcdir)/gtk-doc.make | ||
85 | |||
86 | # Other files to distribute | ||
87 | # e.g. EXTRA_DIST += version.xml.in | ||
88 | EXTRA_DIST += version.xml.in | ||
89 | |||
90 | # Files not to distribute | ||
91 | # for --rebuild-types in $(SCAN_OPTIONS), e.g. $(DOC_MODULE).types | ||
92 | # for --rebuild-sections in $(SCAN_OPTIONS) e.g. $(DOC_MODULE)-sections.txt | ||
93 | #DISTCLEANFILES += | ||
94 | |||
95 | # Comment this out if you want your docs-status tested during 'make check' | ||
96 | if ENABLE_GTK_DOC | ||
97 | #TESTS_ENVIRONMENT = cd $(srcsrc) | ||
98 | #TESTS = $(GTKDOC_CHECK) | ||
99 | endif | ||
diff --git a/src/udev/src/docs/libudev-docs.xml b/src/udev/src/docs/libudev-docs.xml new file mode 100644 index 000000000..b7feb4552 --- /dev/null +++ b/src/udev/src/docs/libudev-docs.xml | |||
@@ -0,0 +1,32 @@ | |||
1 | <?xml version="1.0"?> | ||
2 | <!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN" | ||
3 | "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" | ||
4 | [ | ||
5 | <!ENTITY version SYSTEM "version.xml"> | ||
6 | ]> | ||
7 | <book id="index" xmlns:xi="http://www.w3.org/2003/XInclude"> | ||
8 | <bookinfo> | ||
9 | <title>libudev Reference Manual</title> | ||
10 | <releaseinfo>for libudev version &version;</releaseinfo> | ||
11 | <copyright> | ||
12 | <year>2009-2011</year> | ||
13 | <holder>Kay Sievers <kay.sievers@vrfy.org></holder> | ||
14 | </copyright> | ||
15 | </bookinfo> | ||
16 | |||
17 | <chapter> | ||
18 | <title>libudev</title> | ||
19 | <xi:include href="xml/libudev.xml"/> | ||
20 | <xi:include href="xml/libudev-list.xml"/> | ||
21 | <xi:include href="xml/libudev-device.xml"/> | ||
22 | <xi:include href="xml/libudev-monitor.xml"/> | ||
23 | <xi:include href="xml/libudev-enumerate.xml"/> | ||
24 | <xi:include href="xml/libudev-queue.xml"/> | ||
25 | <xi:include href="xml/libudev-util.xml"/> | ||
26 | </chapter> | ||
27 | |||
28 | <index id="api-index-full"> | ||
29 | <title>API Index</title> | ||
30 | <xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include> | ||
31 | </index> | ||
32 | </book> | ||
diff --git a/src/udev/src/docs/libudev-sections.txt b/src/udev/src/docs/libudev-sections.txt new file mode 100644 index 000000000..15c3e934b --- /dev/null +++ b/src/udev/src/docs/libudev-sections.txt | |||
@@ -0,0 +1,127 @@ | |||
1 | <SECTION> | ||
2 | <FILE>libudev</FILE> | ||
3 | <TITLE>udev</TITLE> | ||
4 | udev | ||
5 | udev_ref | ||
6 | udev_unref | ||
7 | udev_new | ||
8 | udev_set_log_fn | ||
9 | udev_get_log_priority | ||
10 | udev_set_log_priority | ||
11 | udev_get_sys_path | ||
12 | udev_get_dev_path | ||
13 | udev_get_run_path | ||
14 | udev_get_userdata | ||
15 | udev_set_userdata | ||
16 | </SECTION> | ||
17 | |||
18 | <SECTION> | ||
19 | <FILE>libudev-list</FILE> | ||
20 | <TITLE>udev_list</TITLE> | ||
21 | udev_list_entry | ||
22 | udev_list_entry_get_next | ||
23 | udev_list_entry_get_by_name | ||
24 | udev_list_entry_get_name | ||
25 | udev_list_entry_get_value | ||
26 | udev_list_entry_foreach | ||
27 | </SECTION> | ||
28 | |||
29 | <SECTION> | ||
30 | <FILE>libudev-device</FILE> | ||
31 | <TITLE>udev_device</TITLE> | ||
32 | udev_device | ||
33 | udev_device_ref | ||
34 | udev_device_unref | ||
35 | udev_device_get_udev | ||
36 | udev_device_new_from_syspath | ||
37 | udev_device_new_from_devnum | ||
38 | udev_device_new_from_subsystem_sysname | ||
39 | udev_device_new_from_environment | ||
40 | udev_device_get_parent | ||
41 | udev_device_get_parent_with_subsystem_devtype | ||
42 | udev_device_get_devpath | ||
43 | udev_device_get_subsystem | ||
44 | udev_device_get_devtype | ||
45 | udev_device_get_syspath | ||
46 | udev_device_get_sysname | ||
47 | udev_device_get_sysnum | ||
48 | udev_device_get_devnode | ||
49 | udev_device_get_is_initialized | ||
50 | udev_device_get_devlinks_list_entry | ||
51 | udev_device_get_properties_list_entry | ||
52 | udev_device_get_tags_list_entry | ||
53 | udev_device_get_property_value | ||
54 | udev_device_get_driver | ||
55 | udev_device_get_devnum | ||
56 | udev_device_get_action | ||
57 | udev_device_get_sysattr_value | ||
58 | udev_device_get_sysattr_list_entry | ||
59 | udev_device_get_seqnum | ||
60 | udev_device_get_usec_since_initialized | ||
61 | udev_device_has_tag | ||
62 | </SECTION> | ||
63 | |||
64 | <SECTION> | ||
65 | <FILE>libudev-monitor</FILE> | ||
66 | <TITLE>udev_monitor</TITLE> | ||
67 | udev_monitor | ||
68 | udev_monitor_ref | ||
69 | udev_monitor_unref | ||
70 | udev_monitor_get_udev | ||
71 | udev_monitor_new_from_netlink | ||
72 | udev_monitor_new_from_socket | ||
73 | udev_monitor_enable_receiving | ||
74 | udev_monitor_set_receive_buffer_size | ||
75 | udev_monitor_get_fd | ||
76 | udev_monitor_receive_device | ||
77 | udev_monitor_filter_add_match_subsystem_devtype | ||
78 | udev_monitor_filter_add_match_tag | ||
79 | udev_monitor_filter_update | ||
80 | udev_monitor_filter_remove | ||
81 | </SECTION> | ||
82 | |||
83 | <SECTION> | ||
84 | <FILE>libudev-enumerate</FILE> | ||
85 | <TITLE>udev_enumerate</TITLE> | ||
86 | udev_enumerate | ||
87 | udev_enumerate_ref | ||
88 | udev_enumerate_unref | ||
89 | udev_enumerate_get_udev | ||
90 | udev_enumerate_new | ||
91 | udev_enumerate_add_match_subsystem | ||
92 | udev_enumerate_add_nomatch_subsystem | ||
93 | udev_enumerate_add_match_sysattr | ||
94 | udev_enumerate_add_nomatch_sysattr | ||
95 | udev_enumerate_add_match_property | ||
96 | udev_enumerate_add_match_tag | ||
97 | udev_enumerate_add_match_parent | ||
98 | udev_enumerate_add_match_is_initialized | ||
99 | udev_enumerate_add_match_sysname | ||
100 | udev_enumerate_add_syspath | ||
101 | udev_enumerate_scan_devices | ||
102 | udev_enumerate_scan_subsystems | ||
103 | udev_enumerate_get_list_entry | ||
104 | </SECTION> | ||
105 | |||
106 | <SECTION> | ||
107 | <FILE>libudev-queue</FILE> | ||
108 | <TITLE>udev_queue</TITLE> | ||
109 | udev_queue | ||
110 | udev_queue_ref | ||
111 | udev_queue_unref | ||
112 | udev_queue_get_udev | ||
113 | udev_queue_new | ||
114 | udev_queue_get_udev_is_active | ||
115 | udev_queue_get_queue_is_empty | ||
116 | udev_queue_get_seqnum_is_finished | ||
117 | udev_queue_get_seqnum_sequence_is_finished | ||
118 | udev_queue_get_queued_list_entry | ||
119 | udev_queue_get_kernel_seqnum | ||
120 | udev_queue_get_udev_seqnum | ||
121 | </SECTION> | ||
122 | |||
123 | <SECTION> | ||
124 | <FILE>libudev-util</FILE> | ||
125 | <TITLE>udev_util</TITLE> | ||
126 | udev_util_encode_string | ||
127 | </SECTION> | ||
diff --git a/src/udev/src/docs/libudev.types b/src/udev/src/docs/libudev.types new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/udev/src/docs/libudev.types | |||
diff --git a/src/udev/src/docs/version.xml.in b/src/udev/src/docs/version.xml.in new file mode 100644 index 000000000..d78bda934 --- /dev/null +++ b/src/udev/src/docs/version.xml.in | |||
@@ -0,0 +1 @@ | |||
@VERSION@ | |||
diff --git a/src/udev/src/floppy/60-floppy.rules b/src/udev/src/floppy/60-floppy.rules new file mode 100644 index 000000000..53e4a9e59 --- /dev/null +++ b/src/udev/src/floppy/60-floppy.rules | |||
@@ -0,0 +1,4 @@ | |||
1 | # do not edit this file, it will be overwritten on update | ||
2 | |||
3 | SUBSYSTEM=="block", KERNEL=="fd[0-9]", ACTION=="add", ATTRS{cmos}=="?*", ENV{CMOS_TYPE}="$attr{cmos}", \ | ||
4 | RUN+="create_floppy_devices -c -t $env{CMOS_TYPE} -m %M -M 0660 -G floppy $root/%k" | ||
diff --git a/src/udev/src/floppy/create_floppy_devices.c b/src/udev/src/floppy/create_floppy_devices.c new file mode 100644 index 000000000..f71ef0d80 --- /dev/null +++ b/src/udev/src/floppy/create_floppy_devices.c | |||
@@ -0,0 +1,177 @@ | |||
1 | /* | ||
2 | * Create all possible floppy device based on the CMOS type. | ||
3 | * Based upon code from drivers/block/floppy.c | ||
4 | * | ||
5 | * Copyright(C) 2005, SUSE Linux Products GmbH | ||
6 | * | ||
7 | * Author: Hannes Reinecke <hare@suse.de> | ||
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 <sys/types.h> | ||
26 | #include <sys/stat.h> | ||
27 | #include <fcntl.h> | ||
28 | #include <unistd.h> | ||
29 | #include <string.h> | ||
30 | #include <pwd.h> | ||
31 | #include <grp.h> | ||
32 | |||
33 | #include "libudev.h" | ||
34 | #include "libudev-private.h" | ||
35 | |||
36 | static char *table[] = { | ||
37 | "", "d360", "h1200", "u360", "u720", "h360", "h720", | ||
38 | "u1440", "u2880", "CompaQ", "h1440", "u1680", "h410", | ||
39 | "u820", "h1476", "u1722", "h420", "u830", "h1494", "u1743", | ||
40 | "h880", "u1040", "u1120", "h1600", "u1760", "u1920", | ||
41 | "u3200", "u3520", "u3840", "u1840", "u800", "u1600", | ||
42 | NULL | ||
43 | }; | ||
44 | |||
45 | static int t360[] = { 1, 0 }; | ||
46 | static int t1200[] = { 2, 5, 6, 10, 12, 14, 16, 18, 20, 23, 0 }; | ||
47 | static int t3in[] = { 8, 9, 26, 27, 28, 7, 11, 15, 19, 24, 25, 29, 31, 3, 4, 13, 17, 21, 22, 30, 0 }; | ||
48 | static int *table_sup[] = { NULL, t360, t1200, t3in+5+8, t3in+5, t3in, t3in }; | ||
49 | |||
50 | static void log_fn(struct udev *udev, int priority, | ||
51 | const char *file, int line, const char *fn, | ||
52 | const char *format, va_list args) | ||
53 | { | ||
54 | vsyslog(priority, format, args); | ||
55 | } | ||
56 | |||
57 | int main(int argc, char **argv) | ||
58 | { | ||
59 | struct udev *udev; | ||
60 | char *dev; | ||
61 | char *devname; | ||
62 | char node[64]; | ||
63 | int type = 0, i, fdnum, c; | ||
64 | int major = 2, minor; | ||
65 | uid_t uid = 0; | ||
66 | gid_t gid = 0; | ||
67 | mode_t mode = 0660; | ||
68 | int create_nodes = 0; | ||
69 | int print_nodes = 0; | ||
70 | int is_err = 0; | ||
71 | |||
72 | udev = udev_new(); | ||
73 | if (udev == NULL) | ||
74 | goto exit; | ||
75 | |||
76 | udev_log_init("create_floppy_devices"); | ||
77 | udev_set_log_fn(udev, log_fn); | ||
78 | udev_selinux_init(udev); | ||
79 | |||
80 | while ((c = getopt(argc, argv, "cudm:U:G:M:t:")) != -1) { | ||
81 | switch (c) { | ||
82 | case 'c': | ||
83 | create_nodes = 1; | ||
84 | break; | ||
85 | case 'd': | ||
86 | print_nodes = 1; | ||
87 | break; | ||
88 | case 'U': | ||
89 | uid = util_lookup_user(udev, optarg); | ||
90 | break; | ||
91 | case 'G': | ||
92 | gid = util_lookup_group(udev, optarg); | ||
93 | break; | ||
94 | case 'M': | ||
95 | mode = strtol(optarg, NULL, 0); | ||
96 | mode = mode & 0666; | ||
97 | break; | ||
98 | case 'm': | ||
99 | major = strtol(optarg, NULL, 0); | ||
100 | break; | ||
101 | case 't': | ||
102 | type = strtol(optarg, NULL, 0); | ||
103 | break; | ||
104 | default: | ||
105 | is_err++; | ||
106 | break; | ||
107 | } | ||
108 | } | ||
109 | |||
110 | if (is_err || optind >= argc) { | ||
111 | printf("Usage: %s [OPTION] device\n" | ||
112 | " -c create\n" | ||
113 | " -d debug\n" | ||
114 | " -m Major number\n" | ||
115 | " -t floppy type number\n" | ||
116 | " -U device node user ownership\n" | ||
117 | " -G device node group owner\n" | ||
118 | " -M device node mode\n" | ||
119 | "\n", argv[0]); | ||
120 | return 1; | ||
121 | } | ||
122 | |||
123 | dev = argv[optind]; | ||
124 | devname = strrchr(dev, '/'); | ||
125 | if (devname != NULL) | ||
126 | devname = &devname[1]; | ||
127 | else | ||
128 | devname = dev; | ||
129 | if (strncmp(devname, "fd", 2) != 0) { | ||
130 | fprintf(stderr,"Device '%s' is not a floppy device\n", dev); | ||
131 | return 1; | ||
132 | } | ||
133 | |||
134 | fdnum = strtol(&devname[2], NULL, 10); | ||
135 | if (fdnum < 0 || fdnum > 7) { | ||
136 | fprintf(stderr,"Floppy device number %d out of range (0-7)\n", fdnum); | ||
137 | return 1; | ||
138 | } | ||
139 | if (fdnum > 3) | ||
140 | fdnum += 124; | ||
141 | |||
142 | if (major < 1) { | ||
143 | fprintf(stderr,"Invalid major number %d\n", major); | ||
144 | return 1; | ||
145 | } | ||
146 | |||
147 | if (type < 0 || type >= (int) ARRAY_SIZE(table_sup)) { | ||
148 | fprintf(stderr,"Invalid CMOS type %d\n", type); | ||
149 | return 1; | ||
150 | } | ||
151 | |||
152 | if (type == 0) | ||
153 | return 0; | ||
154 | |||
155 | i = 0; | ||
156 | while (table_sup[type][i]) { | ||
157 | sprintf(node, "%s%s", dev, table[table_sup[type][i]]); | ||
158 | minor = (table_sup[type][i] << 2) + fdnum; | ||
159 | if (print_nodes) | ||
160 | printf("%s b %.4o %d %d\n", node, mode, major, minor); | ||
161 | if (create_nodes) { | ||
162 | unlink(node); | ||
163 | udev_selinux_setfscreatecon(udev, node, S_IFBLK | mode); | ||
164 | mknod(node, S_IFBLK | mode, makedev(major,minor)); | ||
165 | udev_selinux_resetfscreatecon(udev); | ||
166 | chown(node, uid, gid); | ||
167 | chmod(node, S_IFBLK | mode); | ||
168 | } | ||
169 | i++; | ||
170 | } | ||
171 | |||
172 | udev_selinux_exit(udev); | ||
173 | udev_unref(udev); | ||
174 | udev_log_close(); | ||
175 | exit: | ||
176 | return 0; | ||
177 | } | ||
diff --git a/src/udev/src/gudev/.gitignore b/src/udev/src/gudev/.gitignore new file mode 100644 index 000000000..d20fa523e --- /dev/null +++ b/src/udev/src/gudev/.gitignore | |||
@@ -0,0 +1,9 @@ | |||
1 | gtk-doc.make | ||
2 | docs/version.xml | ||
3 | gudev-1.0.pc | ||
4 | gudevenumtypes.c | ||
5 | gudevenumtypes.h | ||
6 | gudevmarshal.c | ||
7 | gudevmarshal.h | ||
8 | GUdev-1.0.gir | ||
9 | GUdev-1.0.typelib | ||
diff --git a/src/udev/src/gudev/COPYING b/src/udev/src/gudev/COPYING new file mode 100644 index 000000000..da97db2bd --- /dev/null +++ b/src/udev/src/gudev/COPYING | |||
@@ -0,0 +1,502 @@ | |||
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! | ||
diff --git a/src/udev/src/gudev/docs/.gitignore b/src/udev/src/gudev/docs/.gitignore new file mode 100644 index 000000000..8eada6d40 --- /dev/null +++ b/src/udev/src/gudev/docs/.gitignore | |||
@@ -0,0 +1,16 @@ | |||
1 | gudev-overrides.txt | ||
2 | gudev-decl-list.txt | ||
3 | gudev-decl.txt | ||
4 | gudev-undeclared.txt | ||
5 | gudev-undocumented.txt | ||
6 | gudev-unused.txt | ||
7 | gudev.args | ||
8 | gudev.hierarchy | ||
9 | gudev.interfaces | ||
10 | gudev.prerequisites | ||
11 | gudev.signals | ||
12 | html.stamp | ||
13 | html/* | ||
14 | xml/* | ||
15 | tmpl/* | ||
16 | *.stamp | ||
diff --git a/src/udev/src/gudev/docs/Makefile.am b/src/udev/src/gudev/docs/Makefile.am new file mode 100644 index 000000000..cfe696c50 --- /dev/null +++ b/src/udev/src/gudev/docs/Makefile.am | |||
@@ -0,0 +1,106 @@ | |||
1 | ## Process this file with automake to produce Makefile.in | ||
2 | |||
3 | # We require automake 1.10 at least. | ||
4 | AUTOMAKE_OPTIONS = 1.10 | ||
5 | |||
6 | # This is a blank Makefile.am for using gtk-doc. | ||
7 | # Copy this to your project's API docs directory and modify the variables to | ||
8 | # suit your project. See the GTK+ Makefiles in gtk+/docs/reference for examples | ||
9 | # of using the various options. | ||
10 | |||
11 | # The name of the module, e.g. 'glib'. | ||
12 | DOC_MODULE=gudev | ||
13 | |||
14 | # Uncomment for versioned docs and specify the version of the module, e.g. '2'. | ||
15 | #DOC_MODULE_VERSION=2 | ||
16 | |||
17 | # The top-level SGML file. You can change this if you want to. | ||
18 | DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.xml | ||
19 | |||
20 | # The directory containing the source code. Relative to $(srcdir). | ||
21 | # gtk-doc will search all .c & .h files beneath here for inline comments | ||
22 | # documenting the functions and macros. | ||
23 | # e.g. DOC_SOURCE_DIR=../../../gtk | ||
24 | DOC_SOURCE_DIR=$(top_srcdir)/src | ||
25 | |||
26 | # Extra options to pass to gtkdoc-scangobj. Not normally needed. | ||
27 | SCANGOBJ_OPTIONS= | ||
28 | |||
29 | # Extra options to supply to gtkdoc-scan. | ||
30 | # e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED" | ||
31 | SCAN_OPTIONS= | ||
32 | |||
33 | # Extra options to supply to gtkdoc-mkdb. | ||
34 | # e.g. MKDB_OPTIONS=--sgml-mode --output-format=xml | ||
35 | MKDB_OPTIONS=--sgml-mode --output-format=xml --name-space=g_udev | ||
36 | |||
37 | # Extra options to supply to gtkdoc-mktmpl | ||
38 | # e.g. MKTMPL_OPTIONS=--only-section-tmpl | ||
39 | MKTMPL_OPTIONS= | ||
40 | |||
41 | # Extra options to supply to gtkdoc-mkhtml | ||
42 | MKHTML_OPTIONS=--path=$(abs_srcdir) --path=$(abs_builddir) | ||
43 | |||
44 | # Extra options to supply to gtkdoc-fixref. Not normally needed. | ||
45 | # e.g. FIXXREF_OPTIONS=--extra-dir=../gdk-pixbuf/html --extra-dir=../gdk/html | ||
46 | FIXXREF_OPTIONS= | ||
47 | |||
48 | # Used for dependencies. The docs will be rebuilt if any of these change. | ||
49 | # e.g. HFILE_GLOB=$(top_srcdir)/gtk/*.h | ||
50 | # e.g. CFILE_GLOB=$(top_srcdir)/gtk/*.c | ||
51 | HFILE_GLOB=$(top_srcdir)/src/gudev/*.h | ||
52 | CFILE_GLOB=$(top_srcdir)/src/gudev/*.c | ||
53 | |||
54 | # Extra header to include when scanning, which are not under DOC_SOURCE_DIR | ||
55 | # e.g. EXTRA_HFILES=$(top_srcdir}/contrib/extra.h | ||
56 | EXTRA_HFILES= | ||
57 | |||
58 | # Header files to ignore when scanning. Use base file name, no paths | ||
59 | # e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h | ||
60 | IGNORE_HFILES= | ||
61 | |||
62 | # Images to copy into HTML directory. | ||
63 | # e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png | ||
64 | HTML_IMAGES= | ||
65 | |||
66 | # Extra SGML files that are included by $(DOC_MAIN_SGML_FILE). | ||
67 | # e.g. content_files=running.sgml building.sgml changes-2.0.sgml | ||
68 | content_files = version.xml | ||
69 | |||
70 | # SGML files where gtk-doc abbrevations (#GtkWidget) are expanded | ||
71 | # These files must be listed here *and* in content_files | ||
72 | # e.g. expand_content_files=running.sgml | ||
73 | expand_content_files= | ||
74 | |||
75 | # CFLAGS and LDFLAGS for compiling gtkdoc-scangobj with your library. | ||
76 | # Only needed if you are using gtkdoc-scangobj to dynamically query widget | ||
77 | # signals and properties. | ||
78 | # e.g. GTKDOC_CFLAGS=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS) | ||
79 | # e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib) | ||
80 | GTKDOC_CFLAGS = \ | ||
81 | $(DBUS_GLIB_CFLAGS) \ | ||
82 | $(GLIB_CFLAGS) \ | ||
83 | -I$(top_srcdir)/src/gudev \ | ||
84 | -I$(top_builddir)/src/gudev | ||
85 | |||
86 | GTKDOC_LIBS = \ | ||
87 | $(GLIB_LIBS) \ | ||
88 | $(top_builddir)/libgudev-1.0.la | ||
89 | |||
90 | # This includes the standard gtk-doc make rules, copied by gtkdocize. | ||
91 | include $(top_srcdir)/gtk-doc.make | ||
92 | |||
93 | # Other files to distribute | ||
94 | # e.g. EXTRA_DIST += version.xml.in | ||
95 | EXTRA_DIST += version.xml.in | ||
96 | |||
97 | # Files not to distribute | ||
98 | # for --rebuild-types in $(SCAN_OPTIONS), e.g. $(DOC_MODULE).types | ||
99 | # for --rebuild-sections in $(SCAN_OPTIONS) e.g. $(DOC_MODULE)-sections.txt | ||
100 | #DISTCLEANFILES += | ||
101 | |||
102 | # Comment this out if you want your docs-status tested during 'make check' | ||
103 | if ENABLE_GTK_DOC | ||
104 | #TESTS_ENVIRONMENT = cd $(srcsrc) | ||
105 | #TESTS = $(GTKDOC_CHECK) | ||
106 | endif | ||
diff --git a/src/udev/src/gudev/docs/gudev-docs.xml b/src/udev/src/gudev/docs/gudev-docs.xml new file mode 100644 index 000000000..f876c3bc0 --- /dev/null +++ b/src/udev/src/gudev/docs/gudev-docs.xml | |||
@@ -0,0 +1,93 @@ | |||
1 | <?xml version="1.0"?> | ||
2 | <!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN" | ||
3 | "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [ | ||
4 | <!ENTITY version SYSTEM "version.xml"> | ||
5 | ]> | ||
6 | <book id="index" xmlns:xi="http://www.w3.org/2003/XInclude"> | ||
7 | <bookinfo> | ||
8 | <title>GUDev Reference Manual</title> | ||
9 | <releaseinfo>For GUdev version &version;</releaseinfo> | ||
10 | <authorgroup> | ||
11 | <author> | ||
12 | <firstname>David</firstname> | ||
13 | <surname>Zeuthen</surname> | ||
14 | <affiliation> | ||
15 | <address> | ||
16 | <email>davidz@redhat.com</email> | ||
17 | </address> | ||
18 | </affiliation> | ||
19 | </author> | ||
20 | <author> | ||
21 | <firstname>Bastien</firstname> | ||
22 | <surname>Nocera</surname> | ||
23 | <affiliation> | ||
24 | <address> | ||
25 | <email>hadess@hadess.net</email> | ||
26 | </address> | ||
27 | </affiliation> | ||
28 | </author> | ||
29 | </authorgroup> | ||
30 | |||
31 | <copyright> | ||
32 | <year>2011</year> | ||
33 | <holder>The GUDev Authors</holder> | ||
34 | </copyright> | ||
35 | |||
36 | <legalnotice> | ||
37 | <para> | ||
38 | Permission is granted to copy, distribute and/or modify this | ||
39 | document under the terms of the <citetitle>GNU Free | ||
40 | Documentation License</citetitle>, Version 1.1 or any later | ||
41 | version published by the Free Software Foundation with no | ||
42 | Invariant Sections, no Front-Cover Texts, and no Back-Cover | ||
43 | Texts. You may obtain a copy of the <citetitle>GNU Free | ||
44 | Documentation License</citetitle> from the Free Software | ||
45 | Foundation by visiting <ulink type="http" | ||
46 | url="http://www.fsf.org">their Web site</ulink> or by writing | ||
47 | to: | ||
48 | |||
49 | <address> | ||
50 | The Free Software Foundation, Inc., | ||
51 | <street>59 Temple Place</street> - Suite 330, | ||
52 | <city>Boston</city>, <state>MA</state> <postcode>02111-1307</postcode>, | ||
53 | <country>USA</country> | ||
54 | </address> | ||
55 | </para> | ||
56 | |||
57 | <para> | ||
58 | Many of the names used by companies to distinguish their | ||
59 | products and services are claimed as trademarks. Where those | ||
60 | names appear in any freedesktop.org documentation, and those | ||
61 | trademarks are made aware to the members of the | ||
62 | freedesktop.org Project, the names have been printed in caps | ||
63 | or initial caps. | ||
64 | </para> | ||
65 | </legalnotice> | ||
66 | </bookinfo> | ||
67 | |||
68 | <reference id="ref-API"> | ||
69 | <title>API Reference</title> | ||
70 | <partintro> | ||
71 | <para> | ||
72 | This part presents the class and function reference for the | ||
73 | <literal>libgudev</literal> library. | ||
74 | </para> | ||
75 | </partintro> | ||
76 | <xi:include href="xml/gudevclient.xml"/> | ||
77 | <xi:include href="xml/gudevdevice.xml"/> | ||
78 | <xi:include href="xml/gudevenumerator.xml"/> | ||
79 | </reference> | ||
80 | |||
81 | <chapter id="gudev-hierarchy"> | ||
82 | <title>Object Hierarchy</title> | ||
83 | <xi:include href="xml/tree_index.sgml"/> | ||
84 | </chapter> | ||
85 | <index> | ||
86 | <title>Index</title> | ||
87 | </index> | ||
88 | <index role="165"> | ||
89 | <title>Index of new symbols in 165</title> | ||
90 | <xi:include href="xml/api-index-165.xml"><xi:fallback /></xi:include> | ||
91 | </index> | ||
92 | |||
93 | </book> | ||
diff --git a/src/udev/src/gudev/docs/gudev-sections.txt b/src/udev/src/gudev/docs/gudev-sections.txt new file mode 100644 index 000000000..213e1a746 --- /dev/null +++ b/src/udev/src/gudev/docs/gudev-sections.txt | |||
@@ -0,0 +1,113 @@ | |||
1 | <SECTION> | ||
2 | <FILE>gudevclient</FILE> | ||
3 | <TITLE>GUdevClient</TITLE> | ||
4 | GUdevClient | ||
5 | GUdevClientClass | ||
6 | GUdevDeviceType | ||
7 | GUdevDeviceNumber | ||
8 | g_udev_client_new | ||
9 | g_udev_client_query_by_subsystem | ||
10 | g_udev_client_query_by_device_number | ||
11 | g_udev_client_query_by_device_file | ||
12 | g_udev_client_query_by_sysfs_path | ||
13 | g_udev_client_query_by_subsystem_and_name | ||
14 | <SUBSECTION Standard> | ||
15 | G_UDEV_CLIENT | ||
16 | G_UDEV_IS_CLIENT | ||
17 | G_UDEV_TYPE_CLIENT | ||
18 | g_udev_client_get_type | ||
19 | G_UDEV_CLIENT_CLASS | ||
20 | G_UDEV_IS_CLIENT_CLASS | ||
21 | G_UDEV_CLIENT_GET_CLASS | ||
22 | <SUBSECTION Private> | ||
23 | GUdevClientPrivate | ||
24 | </SECTION> | ||
25 | |||
26 | <SECTION> | ||
27 | <FILE>gudevdevice</FILE> | ||
28 | <TITLE>GUdevDevice</TITLE> | ||
29 | GUdevDevice | ||
30 | GUdevDeviceClass | ||
31 | g_udev_device_get_subsystem | ||
32 | g_udev_device_get_devtype | ||
33 | g_udev_device_get_name | ||
34 | g_udev_device_get_number | ||
35 | g_udev_device_get_sysfs_path | ||
36 | g_udev_device_get_driver | ||
37 | g_udev_device_get_action | ||
38 | g_udev_device_get_seqnum | ||
39 | g_udev_device_get_device_type | ||
40 | g_udev_device_get_device_number | ||
41 | g_udev_device_get_device_file | ||
42 | g_udev_device_get_device_file_symlinks | ||
43 | g_udev_device_get_parent | ||
44 | g_udev_device_get_parent_with_subsystem | ||
45 | g_udev_device_get_tags | ||
46 | g_udev_device_get_is_initialized | ||
47 | g_udev_device_get_usec_since_initialized | ||
48 | g_udev_device_get_property_keys | ||
49 | g_udev_device_has_property | ||
50 | g_udev_device_get_property | ||
51 | g_udev_device_get_property_as_int | ||
52 | g_udev_device_get_property_as_uint64 | ||
53 | g_udev_device_get_property_as_double | ||
54 | g_udev_device_get_property_as_boolean | ||
55 | g_udev_device_get_property_as_strv | ||
56 | g_udev_device_get_sysfs_attr | ||
57 | g_udev_device_get_sysfs_attr_as_int | ||
58 | g_udev_device_get_sysfs_attr_as_uint64 | ||
59 | g_udev_device_get_sysfs_attr_as_double | ||
60 | g_udev_device_get_sysfs_attr_as_boolean | ||
61 | g_udev_device_get_sysfs_attr_as_strv | ||
62 | <SUBSECTION Standard> | ||
63 | G_UDEV_DEVICE | ||
64 | G_UDEV_IS_DEVICE | ||
65 | G_UDEV_TYPE_DEVICE | ||
66 | g_udev_device_get_type | ||
67 | G_UDEV_DEVICE_CLASS | ||
68 | G_UDEV_IS_DEVICE_CLASS | ||
69 | G_UDEV_DEVICE_GET_CLASS | ||
70 | <SUBSECTION Private> | ||
71 | GUdevDevicePrivate | ||
72 | </SECTION> | ||
73 | |||
74 | <SECTION> | ||
75 | <FILE>gudevenumerator</FILE> | ||
76 | <TITLE>GUdevEnumerator</TITLE> | ||
77 | GUdevEnumerator | ||
78 | GUdevEnumeratorClass | ||
79 | g_udev_enumerator_new | ||
80 | g_udev_enumerator_add_match_subsystem | ||
81 | g_udev_enumerator_add_nomatch_subsystem | ||
82 | g_udev_enumerator_add_match_sysfs_attr | ||
83 | g_udev_enumerator_add_nomatch_sysfs_attr | ||
84 | g_udev_enumerator_add_match_property | ||
85 | g_udev_enumerator_add_match_name | ||
86 | g_udev_enumerator_add_match_tag | ||
87 | g_udev_enumerator_add_match_is_initialized | ||
88 | g_udev_enumerator_add_sysfs_path | ||
89 | g_udev_enumerator_execute | ||
90 | <SUBSECTION Standard> | ||
91 | G_UDEV_ENUMERATOR | ||
92 | G_UDEV_IS_ENUMERATOR | ||
93 | G_UDEV_TYPE_ENUMERATOR | ||
94 | g_udev_enumerator_get_type | ||
95 | G_UDEV_ENUMERATOR_CLASS | ||
96 | G_UDEV_IS_ENUMERATOR_CLASS | ||
97 | G_UDEV_ENUMERATOR_GET_CLASS | ||
98 | <SUBSECTION Private> | ||
99 | GUdevEnumeratorPrivate | ||
100 | </SECTION> | ||
101 | |||
102 | <SECTION> | ||
103 | <FILE>gudevmarshal</FILE> | ||
104 | <SUBSECTION Private> | ||
105 | g_udev_marshal_VOID__STRING_OBJECT | ||
106 | </SECTION> | ||
107 | |||
108 | <SECTION> | ||
109 | <FILE>gudevenumtypes</FILE> | ||
110 | <SUBSECTION Private> | ||
111 | G_TYPE_UDEV_DEVICE_TYPE | ||
112 | g_udev_device_type_get_type | ||
113 | </SECTION> | ||
diff --git a/src/udev/src/gudev/docs/gudev.types b/src/udev/src/gudev/docs/gudev.types new file mode 100644 index 000000000..a89857a04 --- /dev/null +++ b/src/udev/src/gudev/docs/gudev.types | |||
@@ -0,0 +1,4 @@ | |||
1 | g_udev_device_type_get_type | ||
2 | g_udev_device_get_type | ||
3 | g_udev_client_get_type | ||
4 | g_udev_enumerator_get_type | ||
diff --git a/src/udev/src/gudev/docs/version.xml.in b/src/udev/src/gudev/docs/version.xml.in new file mode 100644 index 000000000..d78bda934 --- /dev/null +++ b/src/udev/src/gudev/docs/version.xml.in | |||
@@ -0,0 +1 @@ | |||
@VERSION@ | |||
diff --git a/src/udev/src/gudev/gjs-example.js b/src/udev/src/gudev/gjs-example.js new file mode 100755 index 000000000..5586fd6a6 --- /dev/null +++ b/src/udev/src/gudev/gjs-example.js | |||
@@ -0,0 +1,75 @@ | |||
1 | #!/usr/bin/env gjs-console | ||
2 | |||
3 | // This currently depends on the following patches to gjs | ||
4 | // | ||
5 | // http://bugzilla.gnome.org/show_bug.cgi?id=584558 | ||
6 | // http://bugzilla.gnome.org/show_bug.cgi?id=584560 | ||
7 | // http://bugzilla.gnome.org/show_bug.cgi?id=584568 | ||
8 | |||
9 | const GUdev = imports.gi.GUdev; | ||
10 | const Mainloop = imports.mainloop; | ||
11 | |||
12 | function print_device (device) { | ||
13 | print (" subsystem: " + device.get_subsystem ()); | ||
14 | print (" devtype: " + device.get_devtype ()); | ||
15 | print (" name: " + device.get_name ()); | ||
16 | print (" number: " + device.get_number ()); | ||
17 | print (" sysfs_path: " + device.get_sysfs_path ()); | ||
18 | print (" driver: " + device.get_driver ()); | ||
19 | print (" action: " + device.get_action ()); | ||
20 | print (" seqnum: " + device.get_seqnum ()); | ||
21 | print (" device type: " + device.get_device_type ()); | ||
22 | print (" device number: " + device.get_device_number ()); | ||
23 | print (" device file: " + device.get_device_file ()); | ||
24 | print (" device file symlinks: " + device.get_device_file_symlinks ()); | ||
25 | print (" foo: " + device.get_sysfs_attr_as_strv ("stat")); | ||
26 | var keys = device.get_property_keys (); | ||
27 | for (var n = 0; n < keys.length; n++) { | ||
28 | print (" " + keys[n] + "=" + device.get_property (keys[n])); | ||
29 | } | ||
30 | } | ||
31 | |||
32 | function on_uevent (client, action, device) { | ||
33 | print ("action " + action + " on device " + device.get_sysfs_path()); | ||
34 | print_device (device); | ||
35 | print (""); | ||
36 | } | ||
37 | |||
38 | var client = new GUdev.Client ({subsystems: ["block", "usb/usb_interface"]}); | ||
39 | client.connect ("uevent", on_uevent); | ||
40 | |||
41 | var block_devices = client.query_by_subsystem ("block"); | ||
42 | for (var n = 0; n < block_devices.length; n++) { | ||
43 | print ("block device: " + block_devices[n].get_device_file ()); | ||
44 | } | ||
45 | |||
46 | var d; | ||
47 | |||
48 | d = client.query_by_device_number (GUdev.DeviceType.BLOCK, 0x0810); | ||
49 | if (d == null) { | ||
50 | print ("query_by_device_number 0x810 -> null"); | ||
51 | } else { | ||
52 | print ("query_by_device_number 0x810 -> " + d.get_device_file ()); | ||
53 | var dd = d.get_parent_with_subsystem ("usb", null); | ||
54 | print_device (dd); | ||
55 | print ("--------------------------------------------------------------------------"); | ||
56 | while (d != null) { | ||
57 | print_device (d); | ||
58 | print (""); | ||
59 | d = d.get_parent (); | ||
60 | } | ||
61 | } | ||
62 | |||
63 | d = client.query_by_sysfs_path ("/sys/block/sda/sda1"); | ||
64 | print ("query_by_sysfs_path (\"/sys/block/sda1\") -> " + d.get_device_file ()); | ||
65 | |||
66 | d = client.query_by_subsystem_and_name ("block", "sda2"); | ||
67 | print ("query_by_subsystem_and_name (\"block\", \"sda2\") -> " + d.get_device_file ()); | ||
68 | |||
69 | d = client.query_by_device_file ("/dev/sda"); | ||
70 | print ("query_by_device_file (\"/dev/sda\") -> " + d.get_device_file ()); | ||
71 | |||
72 | d = client.query_by_device_file ("/dev/block/8:0"); | ||
73 | print ("query_by_device_file (\"/dev/block/8:0\") -> " + d.get_device_file ()); | ||
74 | |||
75 | Mainloop.run('udev-example'); | ||
diff --git a/src/udev/src/gudev/gudev-1.0.pc.in b/src/udev/src/gudev/gudev-1.0.pc.in new file mode 100644 index 000000000..058262d76 --- /dev/null +++ b/src/udev/src/gudev/gudev-1.0.pc.in | |||
@@ -0,0 +1,11 @@ | |||
1 | prefix=@prefix@ | ||
2 | exec_prefix=@exec_prefix@ | ||
3 | libdir=@libdir@ | ||
4 | includedir=@includedir@ | ||
5 | |||
6 | Name: gudev-1.0 | ||
7 | Description: GObject bindings for libudev | ||
8 | Version: @VERSION@ | ||
9 | Requires: glib-2.0, gobject-2.0 | ||
10 | Libs: -L${libdir} -lgudev-1.0 | ||
11 | Cflags: -I${includedir}/gudev-1.0 | ||
diff --git a/src/udev/src/gudev/gudev.h b/src/udev/src/gudev/gudev.h new file mode 100644 index 000000000..a31346081 --- /dev/null +++ b/src/udev/src/gudev/gudev.h | |||
@@ -0,0 +1,33 @@ | |||
1 | /* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- | ||
2 | * | ||
3 | * Copyright (C) 2008 David Zeuthen <davidz@redhat.com> | ||
4 | * | ||
5 | * This library is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU Lesser General Public | ||
7 | * License as published by the Free Software Foundation; either | ||
8 | * version 2 of the License, or (at your option) any later version. | ||
9 | * | ||
10 | * This library 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 GNU | ||
13 | * Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this library; if not, write to the | ||
17 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | * Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | #ifndef __G_UDEV_H__ | ||
22 | #define __G_UDEV_H__ | ||
23 | |||
24 | #define _GUDEV_INSIDE_GUDEV_H 1 | ||
25 | #include <gudev/gudevenums.h> | ||
26 | #include <gudev/gudevenumtypes.h> | ||
27 | #include <gudev/gudevtypes.h> | ||
28 | #include <gudev/gudevclient.h> | ||
29 | #include <gudev/gudevdevice.h> | ||
30 | #include <gudev/gudevenumerator.h> | ||
31 | #undef _GUDEV_INSIDE_GUDEV_H | ||
32 | |||
33 | #endif /* __G_UDEV_H__ */ | ||
diff --git a/src/udev/src/gudev/gudevclient.c b/src/udev/src/gudev/gudevclient.c new file mode 100644 index 000000000..2b94102ac --- /dev/null +++ b/src/udev/src/gudev/gudevclient.c | |||
@@ -0,0 +1,527 @@ | |||
1 | /* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- | ||
2 | * | ||
3 | * Copyright (C) 2008-2010 David Zeuthen <davidz@redhat.com> | ||
4 | * | ||
5 | * This library is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU Lesser General Public | ||
7 | * License as published by the Free Software Foundation; either | ||
8 | * version 2 of the License, or (at your option) any later version. | ||
9 | * | ||
10 | * This library 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 GNU | ||
13 | * Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this library; if not, write to the | ||
17 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | * Boston, MA 02111-1307, USA. | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #ifdef HAVE_CONFIG_H | ||
23 | # include "config.h" | ||
24 | #endif | ||
25 | |||
26 | #include <stdlib.h> | ||
27 | #include <string.h> | ||
28 | |||
29 | #include "gudevclient.h" | ||
30 | #include "gudevdevice.h" | ||
31 | #include "gudevmarshal.h" | ||
32 | #include "gudevprivate.h" | ||
33 | |||
34 | /** | ||
35 | * SECTION:gudevclient | ||
36 | * @short_description: Query devices and listen to uevents | ||
37 | * | ||
38 | * #GUdevClient is used to query information about devices on a Linux | ||
39 | * system from the Linux kernel and the udev device | ||
40 | * manager. | ||
41 | * | ||
42 | * Device information is retrieved from the kernel (through the | ||
43 | * <literal>sysfs</literal> filesystem) and the udev daemon (through a | ||
44 | * <literal>tmpfs</literal> filesystem) and presented through | ||
45 | * #GUdevDevice objects. This means that no blocking IO ever happens | ||
46 | * (in both cases, we are essentially just reading data from kernel | ||
47 | * memory) and as such there are no asynchronous versions of the | ||
48 | * provided methods. | ||
49 | * | ||
50 | * To get #GUdevDevice objects, use | ||
51 | * g_udev_client_query_by_subsystem(), | ||
52 | * g_udev_client_query_by_device_number(), | ||
53 | * g_udev_client_query_by_device_file(), | ||
54 | * g_udev_client_query_by_sysfs_path(), | ||
55 | * g_udev_client_query_by_subsystem_and_name() | ||
56 | * or the #GUdevEnumerator type. | ||
57 | * | ||
58 | * To listen to uevents, connect to the #GUdevClient::uevent signal. | ||
59 | */ | ||
60 | |||
61 | struct _GUdevClientPrivate | ||
62 | { | ||
63 | GSource *watch_source; | ||
64 | struct udev *udev; | ||
65 | struct udev_monitor *monitor; | ||
66 | |||
67 | gchar **subsystems; | ||
68 | }; | ||
69 | |||
70 | enum | ||
71 | { | ||
72 | PROP_0, | ||
73 | PROP_SUBSYSTEMS, | ||
74 | }; | ||
75 | |||
76 | enum | ||
77 | { | ||
78 | UEVENT_SIGNAL, | ||
79 | LAST_SIGNAL, | ||
80 | }; | ||
81 | |||
82 | static guint signals[LAST_SIGNAL] = { 0 }; | ||
83 | |||
84 | G_DEFINE_TYPE (GUdevClient, g_udev_client, G_TYPE_OBJECT) | ||
85 | |||
86 | /* ---------------------------------------------------------------------------------------------------- */ | ||
87 | |||
88 | static gboolean | ||
89 | monitor_event (GIOChannel *source, | ||
90 | GIOCondition condition, | ||
91 | gpointer data) | ||
92 | { | ||
93 | GUdevClient *client = (GUdevClient *) data; | ||
94 | GUdevDevice *device; | ||
95 | struct udev_device *udevice; | ||
96 | |||
97 | if (client->priv->monitor == NULL) | ||
98 | goto out; | ||
99 | udevice = udev_monitor_receive_device (client->priv->monitor); | ||
100 | if (udevice == NULL) | ||
101 | goto out; | ||
102 | |||
103 | device = _g_udev_device_new (udevice); | ||
104 | udev_device_unref (udevice); | ||
105 | g_signal_emit (client, | ||
106 | signals[UEVENT_SIGNAL], | ||
107 | 0, | ||
108 | g_udev_device_get_action (device), | ||
109 | device); | ||
110 | g_object_unref (device); | ||
111 | |||
112 | out: | ||
113 | return TRUE; | ||
114 | } | ||
115 | |||
116 | static void | ||
117 | g_udev_client_finalize (GObject *object) | ||
118 | { | ||
119 | GUdevClient *client = G_UDEV_CLIENT (object); | ||
120 | |||
121 | if (client->priv->watch_source != NULL) | ||
122 | { | ||
123 | g_source_destroy (client->priv->watch_source); | ||
124 | client->priv->watch_source = NULL; | ||
125 | } | ||
126 | |||
127 | if (client->priv->monitor != NULL) | ||
128 | { | ||
129 | udev_monitor_unref (client->priv->monitor); | ||
130 | client->priv->monitor = NULL; | ||
131 | } | ||
132 | |||
133 | if (client->priv->udev != NULL) | ||
134 | { | ||
135 | udev_unref (client->priv->udev); | ||
136 | client->priv->udev = NULL; | ||
137 | } | ||
138 | |||
139 | g_strfreev (client->priv->subsystems); | ||
140 | |||
141 | if (G_OBJECT_CLASS (g_udev_client_parent_class)->finalize != NULL) | ||
142 | G_OBJECT_CLASS (g_udev_client_parent_class)->finalize (object); | ||
143 | } | ||
144 | |||
145 | static void | ||
146 | g_udev_client_set_property (GObject *object, | ||
147 | guint prop_id, | ||
148 | const GValue *value, | ||
149 | GParamSpec *pspec) | ||
150 | { | ||
151 | GUdevClient *client = G_UDEV_CLIENT (object); | ||
152 | |||
153 | switch (prop_id) | ||
154 | { | ||
155 | case PROP_SUBSYSTEMS: | ||
156 | if (client->priv->subsystems != NULL) | ||
157 | g_strfreev (client->priv->subsystems); | ||
158 | client->priv->subsystems = g_strdupv (g_value_get_boxed (value)); | ||
159 | break; | ||
160 | |||
161 | default: | ||
162 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); | ||
163 | break; | ||
164 | } | ||
165 | } | ||
166 | |||
167 | static void | ||
168 | g_udev_client_get_property (GObject *object, | ||
169 | guint prop_id, | ||
170 | GValue *value, | ||
171 | GParamSpec *pspec) | ||
172 | { | ||
173 | GUdevClient *client = G_UDEV_CLIENT (object); | ||
174 | |||
175 | switch (prop_id) | ||
176 | { | ||
177 | case PROP_SUBSYSTEMS: | ||
178 | g_value_set_boxed (value, client->priv->subsystems); | ||
179 | break; | ||
180 | |||
181 | default: | ||
182 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); | ||
183 | break; | ||
184 | } | ||
185 | } | ||
186 | |||
187 | static void | ||
188 | g_udev_client_constructed (GObject *object) | ||
189 | { | ||
190 | GUdevClient *client = G_UDEV_CLIENT (object); | ||
191 | GIOChannel *channel; | ||
192 | guint n; | ||
193 | |||
194 | client->priv->udev = udev_new (); | ||
195 | |||
196 | /* connect to event source */ | ||
197 | client->priv->monitor = udev_monitor_new_from_netlink (client->priv->udev, "udev"); | ||
198 | |||
199 | //g_debug ("ss = %p", client->priv->subsystems); | ||
200 | |||
201 | if (client->priv->subsystems != NULL) | ||
202 | { | ||
203 | /* install subsystem filters to only wake up for certain events */ | ||
204 | for (n = 0; client->priv->subsystems[n] != NULL; n++) | ||
205 | { | ||
206 | gchar *subsystem; | ||
207 | gchar *devtype; | ||
208 | gchar *s; | ||
209 | |||
210 | subsystem = g_strdup (client->priv->subsystems[n]); | ||
211 | devtype = NULL; | ||
212 | |||
213 | //g_debug ("s = '%s'", subsystem); | ||
214 | |||
215 | s = strstr (subsystem, "/"); | ||
216 | if (s != NULL) | ||
217 | { | ||
218 | devtype = s + 1; | ||
219 | *s = '\0'; | ||
220 | } | ||
221 | |||
222 | if (client->priv->monitor != NULL) | ||
223 | udev_monitor_filter_add_match_subsystem_devtype (client->priv->monitor, subsystem, devtype); | ||
224 | |||
225 | g_free (subsystem); | ||
226 | } | ||
227 | |||
228 | /* listen to events, and buffer them */ | ||
229 | if (client->priv->monitor != NULL) | ||
230 | { | ||
231 | udev_monitor_enable_receiving (client->priv->monitor); | ||
232 | channel = g_io_channel_unix_new (udev_monitor_get_fd (client->priv->monitor)); | ||
233 | client->priv->watch_source = g_io_create_watch (channel, G_IO_IN); | ||
234 | g_io_channel_unref (channel); | ||
235 | g_source_set_callback (client->priv->watch_source, (GSourceFunc) monitor_event, client, NULL); | ||
236 | g_source_attach (client->priv->watch_source, g_main_context_get_thread_default ()); | ||
237 | g_source_unref (client->priv->watch_source); | ||
238 | } | ||
239 | else | ||
240 | { | ||
241 | client->priv->watch_source = NULL; | ||
242 | } | ||
243 | } | ||
244 | |||
245 | if (G_OBJECT_CLASS (g_udev_client_parent_class)->constructed != NULL) | ||
246 | G_OBJECT_CLASS (g_udev_client_parent_class)->constructed (object); | ||
247 | } | ||
248 | |||
249 | |||
250 | static void | ||
251 | g_udev_client_class_init (GUdevClientClass *klass) | ||
252 | { | ||
253 | GObjectClass *gobject_class = (GObjectClass *) klass; | ||
254 | |||
255 | gobject_class->constructed = g_udev_client_constructed; | ||
256 | gobject_class->set_property = g_udev_client_set_property; | ||
257 | gobject_class->get_property = g_udev_client_get_property; | ||
258 | gobject_class->finalize = g_udev_client_finalize; | ||
259 | |||
260 | /** | ||
261 | * GUdevClient:subsystems: | ||
262 | * | ||
263 | * The subsystems to listen for uevents on. | ||
264 | * | ||
265 | * To listen for only a specific DEVTYPE for a given SUBSYSTEM, use | ||
266 | * "subsystem/devtype". For example, to only listen for uevents | ||
267 | * where SUBSYSTEM is usb and DEVTYPE is usb_interface, use | ||
268 | * "usb/usb_interface". | ||
269 | * | ||
270 | * If this property is %NULL, then no events will be reported. If | ||
271 | * it's the empty array, events from all subsystems will be | ||
272 | * reported. | ||
273 | */ | ||
274 | g_object_class_install_property (gobject_class, | ||
275 | PROP_SUBSYSTEMS, | ||
276 | g_param_spec_boxed ("subsystems", | ||
277 | "The subsystems to listen for changes on", | ||
278 | "The subsystems to listen for changes on", | ||
279 | G_TYPE_STRV, | ||
280 | G_PARAM_CONSTRUCT_ONLY | | ||
281 | G_PARAM_READWRITE)); | ||
282 | |||
283 | /** | ||
284 | * GUdevClient::uevent: | ||
285 | * @client: The #GUdevClient receiving the event. | ||
286 | * @action: The action for the uevent e.g. "add", "remove", "change", "move", etc. | ||
287 | * @device: Details about the #GUdevDevice the event is for. | ||
288 | * | ||
289 | * Emitted when @client receives an uevent. | ||
290 | * | ||
291 | * This signal is emitted in the | ||
292 | * <link linkend="g-main-context-push-thread-default">thread-default main loop</link> | ||
293 | * of the thread that @client was created in. | ||
294 | */ | ||
295 | signals[UEVENT_SIGNAL] = g_signal_new ("uevent", | ||
296 | G_TYPE_FROM_CLASS (klass), | ||
297 | G_SIGNAL_RUN_LAST, | ||
298 | G_STRUCT_OFFSET (GUdevClientClass, uevent), | ||
299 | NULL, | ||
300 | NULL, | ||
301 | g_udev_marshal_VOID__STRING_OBJECT, | ||
302 | G_TYPE_NONE, | ||
303 | 2, | ||
304 | G_TYPE_STRING, | ||
305 | G_UDEV_TYPE_DEVICE); | ||
306 | |||
307 | g_type_class_add_private (klass, sizeof (GUdevClientPrivate)); | ||
308 | } | ||
309 | |||
310 | static void | ||
311 | g_udev_client_init (GUdevClient *client) | ||
312 | { | ||
313 | client->priv = G_TYPE_INSTANCE_GET_PRIVATE (client, | ||
314 | G_UDEV_TYPE_CLIENT, | ||
315 | GUdevClientPrivate); | ||
316 | } | ||
317 | |||
318 | /** | ||
319 | * g_udev_client_new: | ||
320 | * @subsystems: (array zero-terminated=1) (element-type utf8) (transfer none) (allow-none): A %NULL terminated string array of subsystems to listen for uevents on, %NULL to not listen on uevents at all, or an empty array to listen to uevents on all subsystems. See the documentation for the #GUdevClient:subsystems property for details on this parameter. | ||
321 | * | ||
322 | * Constructs a #GUdevClient object that can be used to query | ||
323 | * information about devices. Connect to the #GUdevClient::uevent | ||
324 | * signal to listen for uevents. Note that signals are emitted in the | ||
325 | * <link linkend="g-main-context-push-thread-default">thread-default main loop</link> | ||
326 | * of the thread that you call this constructor from. | ||
327 | * | ||
328 | * Returns: A new #GUdevClient object. Free with g_object_unref(). | ||
329 | */ | ||
330 | GUdevClient * | ||
331 | g_udev_client_new (const gchar * const *subsystems) | ||
332 | { | ||
333 | return G_UDEV_CLIENT (g_object_new (G_UDEV_TYPE_CLIENT, "subsystems", subsystems, NULL)); | ||
334 | } | ||
335 | |||
336 | /** | ||
337 | * g_udev_client_query_by_subsystem: | ||
338 | * @client: A #GUdevClient. | ||
339 | * @subsystem: (allow-none): The subsystem to get devices for or %NULL to get all devices. | ||
340 | * | ||
341 | * Gets all devices belonging to @subsystem. | ||
342 | * | ||
343 | * Returns: (element-type GUdevDevice) (transfer full): A list of #GUdevDevice objects. The caller should free the result by using g_object_unref() on each element in the list and then g_list_free() on the list. | ||
344 | */ | ||
345 | GList * | ||
346 | g_udev_client_query_by_subsystem (GUdevClient *client, | ||
347 | const gchar *subsystem) | ||
348 | { | ||
349 | struct udev_enumerate *enumerate; | ||
350 | struct udev_list_entry *l, *devices; | ||
351 | GList *ret; | ||
352 | |||
353 | g_return_val_if_fail (G_UDEV_IS_CLIENT (client), NULL); | ||
354 | |||
355 | ret = NULL; | ||
356 | |||
357 | /* prepare a device scan */ | ||
358 | enumerate = udev_enumerate_new (client->priv->udev); | ||
359 | |||
360 | /* filter for subsystem */ | ||
361 | if (subsystem != NULL) | ||
362 | udev_enumerate_add_match_subsystem (enumerate, subsystem); | ||
363 | /* retrieve the list */ | ||
364 | udev_enumerate_scan_devices (enumerate); | ||
365 | |||
366 | /* add devices to the list */ | ||
367 | devices = udev_enumerate_get_list_entry (enumerate); | ||
368 | for (l = devices; l != NULL; l = udev_list_entry_get_next (l)) | ||
369 | { | ||
370 | struct udev_device *udevice; | ||
371 | GUdevDevice *device; | ||
372 | |||
373 | udevice = udev_device_new_from_syspath (udev_enumerate_get_udev (enumerate), | ||
374 | udev_list_entry_get_name (l)); | ||
375 | if (udevice == NULL) | ||
376 | continue; | ||
377 | device = _g_udev_device_new (udevice); | ||
378 | udev_device_unref (udevice); | ||
379 | ret = g_list_prepend (ret, device); | ||
380 | } | ||
381 | udev_enumerate_unref (enumerate); | ||
382 | |||
383 | ret = g_list_reverse (ret); | ||
384 | |||
385 | return ret; | ||
386 | } | ||
387 | |||
388 | /** | ||
389 | * g_udev_client_query_by_device_number: | ||
390 | * @client: A #GUdevClient. | ||
391 | * @type: A value from the #GUdevDeviceType enumeration. | ||
392 | * @number: A device number. | ||
393 | * | ||
394 | * Looks up a device for a type and device number. | ||
395 | * | ||
396 | * Returns: (transfer full): A #GUdevDevice object or %NULL if the device was not found. Free with g_object_unref(). | ||
397 | */ | ||
398 | GUdevDevice * | ||
399 | g_udev_client_query_by_device_number (GUdevClient *client, | ||
400 | GUdevDeviceType type, | ||
401 | GUdevDeviceNumber number) | ||
402 | { | ||
403 | struct udev_device *udevice; | ||
404 | GUdevDevice *device; | ||
405 | |||
406 | g_return_val_if_fail (G_UDEV_IS_CLIENT (client), NULL); | ||
407 | |||
408 | device = NULL; | ||
409 | udevice = udev_device_new_from_devnum (client->priv->udev, type, number); | ||
410 | |||
411 | if (udevice == NULL) | ||
412 | goto out; | ||
413 | |||
414 | device = _g_udev_device_new (udevice); | ||
415 | udev_device_unref (udevice); | ||
416 | |||
417 | out: | ||
418 | return device; | ||
419 | } | ||
420 | |||
421 | /** | ||
422 | * g_udev_client_query_by_device_file: | ||
423 | * @client: A #GUdevClient. | ||
424 | * @device_file: A device file. | ||
425 | * | ||
426 | * Looks up a device for a device file. | ||
427 | * | ||
428 | * Returns: (transfer full): A #GUdevDevice object or %NULL if the device was not found. Free with g_object_unref(). | ||
429 | */ | ||
430 | GUdevDevice * | ||
431 | g_udev_client_query_by_device_file (GUdevClient *client, | ||
432 | const gchar *device_file) | ||
433 | { | ||
434 | struct stat stat_buf; | ||
435 | GUdevDevice *device; | ||
436 | |||
437 | g_return_val_if_fail (G_UDEV_IS_CLIENT (client), NULL); | ||
438 | g_return_val_if_fail (device_file != NULL, NULL); | ||
439 | |||
440 | device = NULL; | ||
441 | |||
442 | if (stat (device_file, &stat_buf) != 0) | ||
443 | goto out; | ||
444 | |||
445 | if (stat_buf.st_rdev == 0) | ||
446 | goto out; | ||
447 | |||
448 | if (S_ISBLK (stat_buf.st_mode)) | ||
449 | device = g_udev_client_query_by_device_number (client, G_UDEV_DEVICE_TYPE_BLOCK, stat_buf.st_rdev); | ||
450 | else if (S_ISCHR (stat_buf.st_mode)) | ||
451 | device = g_udev_client_query_by_device_number (client, G_UDEV_DEVICE_TYPE_CHAR, stat_buf.st_rdev); | ||
452 | |||
453 | out: | ||
454 | return device; | ||
455 | } | ||
456 | |||
457 | /** | ||
458 | * g_udev_client_query_by_sysfs_path: | ||
459 | * @client: A #GUdevClient. | ||
460 | * @sysfs_path: A sysfs path. | ||
461 | * | ||
462 | * Looks up a device for a sysfs path. | ||
463 | * | ||
464 | * Returns: (transfer full): A #GUdevDevice object or %NULL if the device was not found. Free with g_object_unref(). | ||
465 | */ | ||
466 | GUdevDevice * | ||
467 | g_udev_client_query_by_sysfs_path (GUdevClient *client, | ||
468 | const gchar *sysfs_path) | ||
469 | { | ||
470 | struct udev_device *udevice; | ||
471 | GUdevDevice *device; | ||
472 | |||
473 | g_return_val_if_fail (G_UDEV_IS_CLIENT (client), NULL); | ||
474 | g_return_val_if_fail (sysfs_path != NULL, NULL); | ||
475 | |||
476 | device = NULL; | ||
477 | udevice = udev_device_new_from_syspath (client->priv->udev, sysfs_path); | ||
478 | if (udevice == NULL) | ||
479 | goto out; | ||
480 | |||
481 | device = _g_udev_device_new (udevice); | ||
482 | udev_device_unref (udevice); | ||
483 | |||
484 | out: | ||
485 | return device; | ||
486 | } | ||
487 | |||
488 | /** | ||
489 | * g_udev_client_query_by_subsystem_and_name: | ||
490 | * @client: A #GUdevClient. | ||
491 | * @subsystem: A subsystem name. | ||
492 | * @name: The name of the device. | ||
493 | * | ||
494 | * Looks up a device for a subsystem and name. | ||
495 | * | ||
496 | * Returns: (transfer full): A #GUdevDevice object or %NULL if the device was not found. Free with g_object_unref(). | ||
497 | */ | ||
498 | GUdevDevice * | ||
499 | g_udev_client_query_by_subsystem_and_name (GUdevClient *client, | ||
500 | const gchar *subsystem, | ||
501 | const gchar *name) | ||
502 | { | ||
503 | struct udev_device *udevice; | ||
504 | GUdevDevice *device; | ||
505 | |||
506 | g_return_val_if_fail (G_UDEV_IS_CLIENT (client), NULL); | ||
507 | g_return_val_if_fail (subsystem != NULL, NULL); | ||
508 | g_return_val_if_fail (name != NULL, NULL); | ||
509 | |||
510 | device = NULL; | ||
511 | udevice = udev_device_new_from_subsystem_sysname (client->priv->udev, subsystem, name); | ||
512 | if (udevice == NULL) | ||
513 | goto out; | ||
514 | |||
515 | device = _g_udev_device_new (udevice); | ||
516 | udev_device_unref (udevice); | ||
517 | |||
518 | out: | ||
519 | return device; | ||
520 | } | ||
521 | |||
522 | struct udev * | ||
523 | _g_udev_client_get_udev (GUdevClient *client) | ||
524 | { | ||
525 | g_return_val_if_fail (G_UDEV_IS_CLIENT (client), NULL); | ||
526 | return client->priv->udev; | ||
527 | } | ||
diff --git a/src/udev/src/gudev/gudevclient.h b/src/udev/src/gudev/gudevclient.h new file mode 100644 index 000000000..b425d03d4 --- /dev/null +++ b/src/udev/src/gudev/gudevclient.h | |||
@@ -0,0 +1,100 @@ | |||
1 | /* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- | ||
2 | * | ||
3 | * Copyright (C) 2008 David Zeuthen <davidz@redhat.com> | ||
4 | * | ||
5 | * This library is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU Lesser General Public | ||
7 | * License as published by the Free Software Foundation; either | ||
8 | * version 2 of the License, or (at your option) any later version. | ||
9 | * | ||
10 | * This library 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 GNU | ||
13 | * Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this library; if not, write to the | ||
17 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | * Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | #if !defined (_GUDEV_COMPILATION) && !defined(_GUDEV_INSIDE_GUDEV_H) | ||
22 | #error "Only <gudev/gudev.h> can be included directly, this file may disappear or change contents." | ||
23 | #endif | ||
24 | |||
25 | #ifndef __G_UDEV_CLIENT_H__ | ||
26 | #define __G_UDEV_CLIENT_H__ | ||
27 | |||
28 | #include <gudev/gudevtypes.h> | ||
29 | |||
30 | G_BEGIN_DECLS | ||
31 | |||
32 | #define G_UDEV_TYPE_CLIENT (g_udev_client_get_type ()) | ||
33 | #define G_UDEV_CLIENT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_UDEV_TYPE_CLIENT, GUdevClient)) | ||
34 | #define G_UDEV_CLIENT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_UDEV_TYPE_CLIENT, GUdevClientClass)) | ||
35 | #define G_UDEV_IS_CLIENT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_UDEV_TYPE_CLIENT)) | ||
36 | #define G_UDEV_IS_CLIENT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_UDEV_TYPE_CLIENT)) | ||
37 | #define G_UDEV_CLIENT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_UDEV_TYPE_CLIENT, GUdevClientClass)) | ||
38 | |||
39 | typedef struct _GUdevClientClass GUdevClientClass; | ||
40 | typedef struct _GUdevClientPrivate GUdevClientPrivate; | ||
41 | |||
42 | /** | ||
43 | * GUdevClient: | ||
44 | * | ||
45 | * The #GUdevClient struct is opaque and should not be accessed directly. | ||
46 | */ | ||
47 | struct _GUdevClient | ||
48 | { | ||
49 | GObject parent; | ||
50 | |||
51 | /*< private >*/ | ||
52 | GUdevClientPrivate *priv; | ||
53 | }; | ||
54 | |||
55 | /** | ||
56 | * GUdevClientClass: | ||
57 | * @parent_class: Parent class. | ||
58 | * @uevent: Signal class handler for the #GUdevClient::uevent signal. | ||
59 | * | ||
60 | * Class structure for #GUdevClient. | ||
61 | */ | ||
62 | struct _GUdevClientClass | ||
63 | { | ||
64 | GObjectClass parent_class; | ||
65 | |||
66 | /* signals */ | ||
67 | void (*uevent) (GUdevClient *client, | ||
68 | const gchar *action, | ||
69 | GUdevDevice *device); | ||
70 | |||
71 | /*< private >*/ | ||
72 | /* Padding for future expansion */ | ||
73 | void (*reserved1) (void); | ||
74 | void (*reserved2) (void); | ||
75 | void (*reserved3) (void); | ||
76 | void (*reserved4) (void); | ||
77 | void (*reserved5) (void); | ||
78 | void (*reserved6) (void); | ||
79 | void (*reserved7) (void); | ||
80 | void (*reserved8) (void); | ||
81 | }; | ||
82 | |||
83 | GType g_udev_client_get_type (void) G_GNUC_CONST; | ||
84 | GUdevClient *g_udev_client_new (const gchar* const *subsystems); | ||
85 | GList *g_udev_client_query_by_subsystem (GUdevClient *client, | ||
86 | const gchar *subsystem); | ||
87 | GUdevDevice *g_udev_client_query_by_device_number (GUdevClient *client, | ||
88 | GUdevDeviceType type, | ||
89 | GUdevDeviceNumber number); | ||
90 | GUdevDevice *g_udev_client_query_by_device_file (GUdevClient *client, | ||
91 | const gchar *device_file); | ||
92 | GUdevDevice *g_udev_client_query_by_sysfs_path (GUdevClient *client, | ||
93 | const gchar *sysfs_path); | ||
94 | GUdevDevice *g_udev_client_query_by_subsystem_and_name (GUdevClient *client, | ||
95 | const gchar *subsystem, | ||
96 | const gchar *name); | ||
97 | |||
98 | G_END_DECLS | ||
99 | |||
100 | #endif /* __G_UDEV_CLIENT_H__ */ | ||
diff --git a/src/udev/src/gudev/gudevdevice.c b/src/udev/src/gudev/gudevdevice.c new file mode 100644 index 000000000..62a26f99b --- /dev/null +++ b/src/udev/src/gudev/gudevdevice.c | |||
@@ -0,0 +1,963 @@ | |||
1 | /* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- | ||
2 | * | ||
3 | * Copyright (C) 2008 David Zeuthen <davidz@redhat.com> | ||
4 | * | ||
5 | * This library is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU Lesser General Public | ||
7 | * License as published by the Free Software Foundation; either | ||
8 | * version 2 of the License, or (at your option) any later version. | ||
9 | * | ||
10 | * This library 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 GNU | ||
13 | * Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this library; if not, write to the | ||
17 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | * Boston, MA 02111-1307, USA. | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #ifdef HAVE_CONFIG_H | ||
23 | # include "config.h" | ||
24 | #endif | ||
25 | |||
26 | #include <stdlib.h> | ||
27 | #include <string.h> | ||
28 | |||
29 | #include "gudevdevice.h" | ||
30 | #include "gudevprivate.h" | ||
31 | |||
32 | /** | ||
33 | * SECTION:gudevdevice | ||
34 | * @short_description: Get information about a device | ||
35 | * | ||
36 | * The #GUdevDevice class is used to get information about a specific | ||
37 | * device. Note that you cannot instantiate a #GUdevDevice object | ||
38 | * yourself. Instead you must use #GUdevClient to obtain #GUdevDevice | ||
39 | * objects. | ||
40 | * | ||
41 | * To get basic information about a device, use | ||
42 | * g_udev_device_get_subsystem(), g_udev_device_get_devtype(), | ||
43 | * g_udev_device_get_name(), g_udev_device_get_number(), | ||
44 | * g_udev_device_get_sysfs_path(), g_udev_device_get_driver(), | ||
45 | * g_udev_device_get_action(), g_udev_device_get_seqnum(), | ||
46 | * g_udev_device_get_device_type(), g_udev_device_get_device_number(), | ||
47 | * g_udev_device_get_device_file(), | ||
48 | * g_udev_device_get_device_file_symlinks(). | ||
49 | * | ||
50 | * To navigate the device tree, use g_udev_device_get_parent() and | ||
51 | * g_udev_device_get_parent_with_subsystem(). | ||
52 | * | ||
53 | * To access udev properties for the device, use | ||
54 | * g_udev_device_get_property_keys(), | ||
55 | * g_udev_device_has_property(), | ||
56 | * g_udev_device_get_property(), | ||
57 | * g_udev_device_get_property_as_int(), | ||
58 | * g_udev_device_get_property_as_uint64(), | ||
59 | * g_udev_device_get_property_as_double(), | ||
60 | * g_udev_device_get_property_as_boolean() and | ||
61 | * g_udev_device_get_property_as_strv(). | ||
62 | * | ||
63 | * To access sysfs attributes for the device, use | ||
64 | * g_udev_device_get_sysfs_attr(), | ||
65 | * g_udev_device_get_sysfs_attr_as_int(), | ||
66 | * g_udev_device_get_sysfs_attr_as_uint64(), | ||
67 | * g_udev_device_get_sysfs_attr_as_double(), | ||
68 | * g_udev_device_get_sysfs_attr_as_boolean() and | ||
69 | * g_udev_device_get_sysfs_attr_as_strv(). | ||
70 | * | ||
71 | * Note that all getters on #GUdevDevice are non-reffing – returned | ||
72 | * values are owned by the object, should not be freed and are only | ||
73 | * valid as long as the object is alive. | ||
74 | * | ||
75 | * By design, #GUdevDevice will not react to changes for a device – it | ||
76 | * only contains a snapshot of information when the #GUdevDevice | ||
77 | * object was created. To work with changes, you typically connect to | ||
78 | * the #GUdevClient::uevent signal on a #GUdevClient and get a new | ||
79 | * #GUdevDevice whenever an event happens. | ||
80 | */ | ||
81 | |||
82 | struct _GUdevDevicePrivate | ||
83 | { | ||
84 | struct udev_device *udevice; | ||
85 | |||
86 | /* computed ondemand and cached */ | ||
87 | gchar **device_file_symlinks; | ||
88 | gchar **property_keys; | ||
89 | gchar **tags; | ||
90 | GHashTable *prop_strvs; | ||
91 | GHashTable *sysfs_attr_strvs; | ||
92 | }; | ||
93 | |||
94 | G_DEFINE_TYPE (GUdevDevice, g_udev_device, G_TYPE_OBJECT) | ||
95 | |||
96 | static void | ||
97 | g_udev_device_finalize (GObject *object) | ||
98 | { | ||
99 | GUdevDevice *device = G_UDEV_DEVICE (object); | ||
100 | |||
101 | g_strfreev (device->priv->device_file_symlinks); | ||
102 | g_strfreev (device->priv->property_keys); | ||
103 | g_strfreev (device->priv->tags); | ||
104 | |||
105 | if (device->priv->udevice != NULL) | ||
106 | udev_device_unref (device->priv->udevice); | ||
107 | |||
108 | if (device->priv->prop_strvs != NULL) | ||
109 | g_hash_table_unref (device->priv->prop_strvs); | ||
110 | |||
111 | if (device->priv->sysfs_attr_strvs != NULL) | ||
112 | g_hash_table_unref (device->priv->sysfs_attr_strvs); | ||
113 | |||
114 | if (G_OBJECT_CLASS (g_udev_device_parent_class)->finalize != NULL) | ||
115 | (* G_OBJECT_CLASS (g_udev_device_parent_class)->finalize) (object); | ||
116 | } | ||
117 | |||
118 | static void | ||
119 | g_udev_device_class_init (GUdevDeviceClass *klass) | ||
120 | { | ||
121 | GObjectClass *gobject_class = (GObjectClass *) klass; | ||
122 | |||
123 | gobject_class->finalize = g_udev_device_finalize; | ||
124 | |||
125 | g_type_class_add_private (klass, sizeof (GUdevDevicePrivate)); | ||
126 | } | ||
127 | |||
128 | static void | ||
129 | g_udev_device_init (GUdevDevice *device) | ||
130 | { | ||
131 | device->priv = G_TYPE_INSTANCE_GET_PRIVATE (device, | ||
132 | G_UDEV_TYPE_DEVICE, | ||
133 | GUdevDevicePrivate); | ||
134 | } | ||
135 | |||
136 | |||
137 | GUdevDevice * | ||
138 | _g_udev_device_new (struct udev_device *udevice) | ||
139 | { | ||
140 | GUdevDevice *device; | ||
141 | |||
142 | device = G_UDEV_DEVICE (g_object_new (G_UDEV_TYPE_DEVICE, NULL)); | ||
143 | device->priv->udevice = udev_device_ref (udevice); | ||
144 | |||
145 | return device; | ||
146 | } | ||
147 | |||
148 | /** | ||
149 | * g_udev_device_get_subsystem: | ||
150 | * @device: A #GUdevDevice. | ||
151 | * | ||
152 | * Gets the subsystem for @device. | ||
153 | * | ||
154 | * Returns: The subsystem for @device. | ||
155 | */ | ||
156 | const gchar * | ||
157 | g_udev_device_get_subsystem (GUdevDevice *device) | ||
158 | { | ||
159 | g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL); | ||
160 | return udev_device_get_subsystem (device->priv->udevice); | ||
161 | } | ||
162 | |||
163 | /** | ||
164 | * g_udev_device_get_devtype: | ||
165 | * @device: A #GUdevDevice. | ||
166 | * | ||
167 | * Gets the device type for @device. | ||
168 | * | ||
169 | * Returns: The devtype for @device. | ||
170 | */ | ||
171 | const gchar * | ||
172 | g_udev_device_get_devtype (GUdevDevice *device) | ||
173 | { | ||
174 | g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL); | ||
175 | return udev_device_get_devtype (device->priv->udevice); | ||
176 | } | ||
177 | |||
178 | /** | ||
179 | * g_udev_device_get_name: | ||
180 | * @device: A #GUdevDevice. | ||
181 | * | ||
182 | * Gets the name of @device, e.g. "sda3". | ||
183 | * | ||
184 | * Returns: The name of @device. | ||
185 | */ | ||
186 | const gchar * | ||
187 | g_udev_device_get_name (GUdevDevice *device) | ||
188 | { | ||
189 | g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL); | ||
190 | return udev_device_get_sysname (device->priv->udevice); | ||
191 | } | ||
192 | |||
193 | /** | ||
194 | * g_udev_device_get_number: | ||
195 | * @device: A #GUdevDevice. | ||
196 | * | ||
197 | * Gets the number of @device, e.g. "3" if g_udev_device_get_name() returns "sda3". | ||
198 | * | ||
199 | * Returns: The number of @device. | ||
200 | */ | ||
201 | const gchar * | ||
202 | g_udev_device_get_number (GUdevDevice *device) | ||
203 | { | ||
204 | g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL); | ||
205 | return udev_device_get_sysnum (device->priv->udevice); | ||
206 | } | ||
207 | |||
208 | /** | ||
209 | * g_udev_device_get_sysfs_path: | ||
210 | * @device: A #GUdevDevice. | ||
211 | * | ||
212 | * Gets the sysfs path for @device. | ||
213 | * | ||
214 | * Returns: The sysfs path for @device. | ||
215 | */ | ||
216 | const gchar * | ||
217 | g_udev_device_get_sysfs_path (GUdevDevice *device) | ||
218 | { | ||
219 | g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL); | ||
220 | return udev_device_get_syspath (device->priv->udevice); | ||
221 | } | ||
222 | |||
223 | /** | ||
224 | * g_udev_device_get_driver: | ||
225 | * @device: A #GUdevDevice. | ||
226 | * | ||
227 | * Gets the name of the driver used for @device. | ||
228 | * | ||
229 | * Returns: The name of the driver for @device or %NULL if unknown. | ||
230 | */ | ||
231 | const gchar * | ||
232 | g_udev_device_get_driver (GUdevDevice *device) | ||
233 | { | ||
234 | g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL); | ||
235 | return udev_device_get_driver (device->priv->udevice); | ||
236 | } | ||
237 | |||
238 | /** | ||
239 | * g_udev_device_get_action: | ||
240 | * @device: A #GUdevDevice. | ||
241 | * | ||
242 | * Gets the most recent action (e.g. "add", "remove", "change", etc.) for @device. | ||
243 | * | ||
244 | * Returns: An action string. | ||
245 | */ | ||
246 | const gchar * | ||
247 | g_udev_device_get_action (GUdevDevice *device) | ||
248 | { | ||
249 | g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL); | ||
250 | return udev_device_get_action (device->priv->udevice); | ||
251 | } | ||
252 | |||
253 | /** | ||
254 | * g_udev_device_get_seqnum: | ||
255 | * @device: A #GUdevDevice. | ||
256 | * | ||
257 | * Gets the most recent sequence number for @device. | ||
258 | * | ||
259 | * Returns: A sequence number. | ||
260 | */ | ||
261 | guint64 | ||
262 | g_udev_device_get_seqnum (GUdevDevice *device) | ||
263 | { | ||
264 | g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0); | ||
265 | return udev_device_get_seqnum (device->priv->udevice); | ||
266 | } | ||
267 | |||
268 | /** | ||
269 | * g_udev_device_get_device_type: | ||
270 | * @device: A #GUdevDevice. | ||
271 | * | ||
272 | * Gets the type of the device file, if any, for @device. | ||
273 | * | ||
274 | * Returns: The device number for @device or #G_UDEV_DEVICE_TYPE_NONE if the device does not have a device file. | ||
275 | */ | ||
276 | GUdevDeviceType | ||
277 | g_udev_device_get_device_type (GUdevDevice *device) | ||
278 | { | ||
279 | struct stat stat_buf; | ||
280 | const gchar *device_file; | ||
281 | GUdevDeviceType type; | ||
282 | |||
283 | g_return_val_if_fail (G_UDEV_IS_DEVICE (device), G_UDEV_DEVICE_TYPE_NONE); | ||
284 | |||
285 | type = G_UDEV_DEVICE_TYPE_NONE; | ||
286 | |||
287 | /* TODO: would be better to have support for this in libudev... */ | ||
288 | |||
289 | device_file = g_udev_device_get_device_file (device); | ||
290 | if (device_file == NULL) | ||
291 | goto out; | ||
292 | |||
293 | if (stat (device_file, &stat_buf) != 0) | ||
294 | goto out; | ||
295 | |||
296 | if (S_ISBLK (stat_buf.st_mode)) | ||
297 | type = G_UDEV_DEVICE_TYPE_BLOCK; | ||
298 | else if (S_ISCHR (stat_buf.st_mode)) | ||
299 | type = G_UDEV_DEVICE_TYPE_CHAR; | ||
300 | |||
301 | out: | ||
302 | return type; | ||
303 | } | ||
304 | |||
305 | /** | ||
306 | * g_udev_device_get_device_number: | ||
307 | * @device: A #GUdevDevice. | ||
308 | * | ||
309 | * Gets the device number, if any, for @device. | ||
310 | * | ||
311 | * Returns: The device number for @device or 0 if unknown. | ||
312 | */ | ||
313 | GUdevDeviceNumber | ||
314 | g_udev_device_get_device_number (GUdevDevice *device) | ||
315 | { | ||
316 | g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0); | ||
317 | return udev_device_get_devnum (device->priv->udevice); | ||
318 | } | ||
319 | |||
320 | /** | ||
321 | * g_udev_device_get_device_file: | ||
322 | * @device: A #GUdevDevice. | ||
323 | * | ||
324 | * Gets the device file for @device. | ||
325 | * | ||
326 | * Returns: The device file for @device or %NULL if no device file | ||
327 | * exists. | ||
328 | */ | ||
329 | const gchar * | ||
330 | g_udev_device_get_device_file (GUdevDevice *device) | ||
331 | { | ||
332 | g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL); | ||
333 | return udev_device_get_devnode (device->priv->udevice); | ||
334 | } | ||
335 | |||
336 | /** | ||
337 | * g_udev_device_get_device_file_symlinks: | ||
338 | * @device: A #GUdevDevice. | ||
339 | * | ||
340 | * Gets a list of symlinks (in <literal>/dev</literal>) that points to | ||
341 | * the device file for @device. | ||
342 | * | ||
343 | * Returns: (transfer none) (array zero-terminated=1) (element-type utf8): A %NULL terminated string array of symlinks. This array is owned by @device and should not be freed by the caller. | ||
344 | */ | ||
345 | const gchar * const * | ||
346 | g_udev_device_get_device_file_symlinks (GUdevDevice *device) | ||
347 | { | ||
348 | struct udev_list_entry *l; | ||
349 | GPtrArray *p; | ||
350 | |||
351 | g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL); | ||
352 | |||
353 | if (device->priv->device_file_symlinks != NULL) | ||
354 | goto out; | ||
355 | |||
356 | p = g_ptr_array_new (); | ||
357 | for (l = udev_device_get_devlinks_list_entry (device->priv->udevice); l != NULL; l = udev_list_entry_get_next (l)) | ||
358 | { | ||
359 | g_ptr_array_add (p, g_strdup (udev_list_entry_get_name (l))); | ||
360 | } | ||
361 | g_ptr_array_add (p, NULL); | ||
362 | device->priv->device_file_symlinks = (gchar **) g_ptr_array_free (p, FALSE); | ||
363 | |||
364 | out: | ||
365 | return (const gchar * const *) device->priv->device_file_symlinks; | ||
366 | } | ||
367 | |||
368 | /* ---------------------------------------------------------------------------------------------------- */ | ||
369 | |||
370 | /** | ||
371 | * g_udev_device_get_parent: | ||
372 | * @device: A #GUdevDevice. | ||
373 | * | ||
374 | * Gets the immediate parent of @device, if any. | ||
375 | * | ||
376 | * Returns: (transfer full): A #GUdevDevice or %NULL if @device has no parent. Free with g_object_unref(). | ||
377 | */ | ||
378 | GUdevDevice * | ||
379 | g_udev_device_get_parent (GUdevDevice *device) | ||
380 | { | ||
381 | GUdevDevice *ret; | ||
382 | struct udev_device *udevice; | ||
383 | |||
384 | g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL); | ||
385 | |||
386 | ret = NULL; | ||
387 | |||
388 | udevice = udev_device_get_parent (device->priv->udevice); | ||
389 | if (udevice == NULL) | ||
390 | goto out; | ||
391 | |||
392 | ret = _g_udev_device_new (udevice); | ||
393 | |||
394 | out: | ||
395 | return ret; | ||
396 | } | ||
397 | |||
398 | /** | ||
399 | * g_udev_device_get_parent_with_subsystem: | ||
400 | * @device: A #GUdevDevice. | ||
401 | * @subsystem: The subsystem of the parent to get. | ||
402 | * @devtype: (allow-none): The devtype of the parent to get or %NULL. | ||
403 | * | ||
404 | * Walks up the chain of parents of @device and returns the first | ||
405 | * device encountered where @subsystem and @devtype matches, if any. | ||
406 | * | ||
407 | * Returns: (transfer full): A #GUdevDevice or %NULL if @device has no parent with @subsystem and @devtype. Free with g_object_unref(). | ||
408 | */ | ||
409 | GUdevDevice * | ||
410 | g_udev_device_get_parent_with_subsystem (GUdevDevice *device, | ||
411 | const gchar *subsystem, | ||
412 | const gchar *devtype) | ||
413 | { | ||
414 | GUdevDevice *ret; | ||
415 | struct udev_device *udevice; | ||
416 | |||
417 | g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL); | ||
418 | g_return_val_if_fail (subsystem != NULL, NULL); | ||
419 | |||
420 | ret = NULL; | ||
421 | |||
422 | udevice = udev_device_get_parent_with_subsystem_devtype (device->priv->udevice, | ||
423 | subsystem, | ||
424 | devtype); | ||
425 | if (udevice == NULL) | ||
426 | goto out; | ||
427 | |||
428 | ret = _g_udev_device_new (udevice); | ||
429 | |||
430 | out: | ||
431 | return ret; | ||
432 | } | ||
433 | |||
434 | /* ---------------------------------------------------------------------------------------------------- */ | ||
435 | |||
436 | /** | ||
437 | * g_udev_device_get_property_keys: | ||
438 | * @device: A #GUdevDevice. | ||
439 | * | ||
440 | * Gets all keys for properties on @device. | ||
441 | * | ||
442 | * Returns: (transfer none) (array zero-terminated=1) (element-type utf8): A %NULL terminated string array of property keys. This array is owned by @device and should not be freed by the caller. | ||
443 | */ | ||
444 | const gchar* const * | ||
445 | g_udev_device_get_property_keys (GUdevDevice *device) | ||
446 | { | ||
447 | struct udev_list_entry *l; | ||
448 | GPtrArray *p; | ||
449 | |||
450 | g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL); | ||
451 | |||
452 | if (device->priv->property_keys != NULL) | ||
453 | goto out; | ||
454 | |||
455 | p = g_ptr_array_new (); | ||
456 | for (l = udev_device_get_properties_list_entry (device->priv->udevice); l != NULL; l = udev_list_entry_get_next (l)) | ||
457 | { | ||
458 | g_ptr_array_add (p, g_strdup (udev_list_entry_get_name (l))); | ||
459 | } | ||
460 | g_ptr_array_add (p, NULL); | ||
461 | device->priv->property_keys = (gchar **) g_ptr_array_free (p, FALSE); | ||
462 | |||
463 | out: | ||
464 | return (const gchar * const *) device->priv->property_keys; | ||
465 | } | ||
466 | |||
467 | |||
468 | /** | ||
469 | * g_udev_device_has_property: | ||
470 | * @device: A #GUdevDevice. | ||
471 | * @key: Name of property. | ||
472 | * | ||
473 | * Check if a the property with the given key exists. | ||
474 | * | ||
475 | * Returns: %TRUE only if the value for @key exist. | ||
476 | */ | ||
477 | gboolean | ||
478 | g_udev_device_has_property (GUdevDevice *device, | ||
479 | const gchar *key) | ||
480 | { | ||
481 | g_return_val_if_fail (G_UDEV_IS_DEVICE (device), FALSE); | ||
482 | g_return_val_if_fail (key != NULL, FALSE); | ||
483 | return udev_device_get_property_value (device->priv->udevice, key) != NULL; | ||
484 | } | ||
485 | |||
486 | /** | ||
487 | * g_udev_device_get_property: | ||
488 | * @device: A #GUdevDevice. | ||
489 | * @key: Name of property. | ||
490 | * | ||
491 | * Look up the value for @key on @device. | ||
492 | * | ||
493 | * Returns: The value for @key or %NULL if @key doesn't exist on @device. Do not free this string, it is owned by @device. | ||
494 | */ | ||
495 | const gchar * | ||
496 | g_udev_device_get_property (GUdevDevice *device, | ||
497 | const gchar *key) | ||
498 | { | ||
499 | g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL); | ||
500 | g_return_val_if_fail (key != NULL, NULL); | ||
501 | return udev_device_get_property_value (device->priv->udevice, key); | ||
502 | } | ||
503 | |||
504 | /** | ||
505 | * g_udev_device_get_property_as_int: | ||
506 | * @device: A #GUdevDevice. | ||
507 | * @key: Name of property. | ||
508 | * | ||
509 | * Look up the value for @key on @device and convert it to an integer | ||
510 | * using strtol(). | ||
511 | * | ||
512 | * Returns: The value for @key or 0 if @key doesn't exist or | ||
513 | * isn't an integer. | ||
514 | */ | ||
515 | gint | ||
516 | g_udev_device_get_property_as_int (GUdevDevice *device, | ||
517 | const gchar *key) | ||
518 | { | ||
519 | gint result; | ||
520 | const gchar *s; | ||
521 | |||
522 | g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0); | ||
523 | g_return_val_if_fail (key != NULL, 0); | ||
524 | |||
525 | result = 0; | ||
526 | s = g_udev_device_get_property (device, key); | ||
527 | if (s == NULL) | ||
528 | goto out; | ||
529 | |||
530 | result = strtol (s, NULL, 0); | ||
531 | out: | ||
532 | return result; | ||
533 | } | ||
534 | |||
535 | /** | ||
536 | * g_udev_device_get_property_as_uint64: | ||
537 | * @device: A #GUdevDevice. | ||
538 | * @key: Name of property. | ||
539 | * | ||
540 | * Look up the value for @key on @device and convert it to an unsigned | ||
541 | * 64-bit integer using g_ascii_strtoull(). | ||
542 | * | ||
543 | * Returns: The value for @key or 0 if @key doesn't exist or isn't a | ||
544 | * #guint64. | ||
545 | */ | ||
546 | guint64 | ||
547 | g_udev_device_get_property_as_uint64 (GUdevDevice *device, | ||
548 | const gchar *key) | ||
549 | { | ||
550 | guint64 result; | ||
551 | const gchar *s; | ||
552 | |||
553 | g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0); | ||
554 | g_return_val_if_fail (key != NULL, 0); | ||
555 | |||
556 | result = 0; | ||
557 | s = g_udev_device_get_property (device, key); | ||
558 | if (s == NULL) | ||
559 | goto out; | ||
560 | |||
561 | result = g_ascii_strtoull (s, NULL, 0); | ||
562 | out: | ||
563 | return result; | ||
564 | } | ||
565 | |||
566 | /** | ||
567 | * g_udev_device_get_property_as_double: | ||
568 | * @device: A #GUdevDevice. | ||
569 | * @key: Name of property. | ||
570 | * | ||
571 | * Look up the value for @key on @device and convert it to a double | ||
572 | * precision floating point number using strtod(). | ||
573 | * | ||
574 | * Returns: The value for @key or 0.0 if @key doesn't exist or isn't a | ||
575 | * #gdouble. | ||
576 | */ | ||
577 | gdouble | ||
578 | g_udev_device_get_property_as_double (GUdevDevice *device, | ||
579 | const gchar *key) | ||
580 | { | ||
581 | gdouble result; | ||
582 | const gchar *s; | ||
583 | |||
584 | g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0.0); | ||
585 | g_return_val_if_fail (key != NULL, 0.0); | ||
586 | |||
587 | result = 0.0; | ||
588 | s = g_udev_device_get_property (device, key); | ||
589 | if (s == NULL) | ||
590 | goto out; | ||
591 | |||
592 | result = strtod (s, NULL); | ||
593 | out: | ||
594 | return result; | ||
595 | } | ||
596 | |||
597 | /** | ||
598 | * g_udev_device_get_property_as_boolean: | ||
599 | * @device: A #GUdevDevice. | ||
600 | * @key: Name of property. | ||
601 | * | ||
602 | * Look up the value for @key on @device and convert it to an | ||
603 | * boolean. This is done by doing a case-insensitive string comparison | ||
604 | * on the string value against "1" and "true". | ||
605 | * | ||
606 | * Returns: The value for @key or %FALSE if @key doesn't exist or | ||
607 | * isn't a #gboolean. | ||
608 | */ | ||
609 | gboolean | ||
610 | g_udev_device_get_property_as_boolean (GUdevDevice *device, | ||
611 | const gchar *key) | ||
612 | { | ||
613 | gboolean result; | ||
614 | const gchar *s; | ||
615 | |||
616 | g_return_val_if_fail (G_UDEV_IS_DEVICE (device), FALSE); | ||
617 | g_return_val_if_fail (key != NULL, FALSE); | ||
618 | |||
619 | result = FALSE; | ||
620 | s = g_udev_device_get_property (device, key); | ||
621 | if (s == NULL) | ||
622 | goto out; | ||
623 | |||
624 | if (strcmp (s, "1") == 0 || g_ascii_strcasecmp (s, "true") == 0) | ||
625 | result = TRUE; | ||
626 | out: | ||
627 | return result; | ||
628 | } | ||
629 | |||
630 | static gchar ** | ||
631 | split_at_whitespace (const gchar *s) | ||
632 | { | ||
633 | gchar **result; | ||
634 | guint n; | ||
635 | guint m; | ||
636 | |||
637 | result = g_strsplit_set (s, " \v\t\r\n", 0); | ||
638 | |||
639 | /* remove empty strings, thanks GLib */ | ||
640 | for (n = 0; result[n] != NULL; n++) | ||
641 | { | ||
642 | if (strlen (result[n]) == 0) | ||
643 | { | ||
644 | g_free (result[n]); | ||
645 | for (m = n; result[m] != NULL; m++) | ||
646 | result[m] = result[m + 1]; | ||
647 | n--; | ||
648 | } | ||
649 | } | ||
650 | |||
651 | return result; | ||
652 | } | ||
653 | |||
654 | /** | ||
655 | * g_udev_device_get_property_as_strv: | ||
656 | * @device: A #GUdevDevice. | ||
657 | * @key: Name of property. | ||
658 | * | ||
659 | * Look up the value for @key on @device and return the result of | ||
660 | * splitting it into non-empty tokens split at white space (only space | ||
661 | * (' '), form-feed ('\f'), newline ('\n'), carriage return ('\r'), | ||
662 | * horizontal tab ('\t'), and vertical tab ('\v') are considered; the | ||
663 | * locale is not taken into account). | ||
664 | * | ||
665 | * Returns: (transfer none) (array zero-terminated=1) (element-type utf8): The value of @key on @device split into tokens or %NULL if @key doesn't exist. This array is owned by @device and should not be freed by the caller. | ||
666 | */ | ||
667 | const gchar* const * | ||
668 | g_udev_device_get_property_as_strv (GUdevDevice *device, | ||
669 | const gchar *key) | ||
670 | { | ||
671 | gchar **result; | ||
672 | const gchar *s; | ||
673 | |||
674 | g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL); | ||
675 | g_return_val_if_fail (key != NULL, NULL); | ||
676 | |||
677 | if (device->priv->prop_strvs != NULL) | ||
678 | { | ||
679 | result = g_hash_table_lookup (device->priv->prop_strvs, key); | ||
680 | if (result != NULL) | ||
681 | goto out; | ||
682 | } | ||
683 | |||
684 | result = NULL; | ||
685 | s = g_udev_device_get_property (device, key); | ||
686 | if (s == NULL) | ||
687 | goto out; | ||
688 | |||
689 | result = split_at_whitespace (s); | ||
690 | if (result == NULL) | ||
691 | goto out; | ||
692 | |||
693 | if (device->priv->prop_strvs == NULL) | ||
694 | device->priv->prop_strvs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_strfreev); | ||
695 | g_hash_table_insert (device->priv->prop_strvs, g_strdup (key), result); | ||
696 | |||
697 | out: | ||
698 | return (const gchar* const *) result; | ||
699 | } | ||
700 | |||
701 | /* ---------------------------------------------------------------------------------------------------- */ | ||
702 | |||
703 | /** | ||
704 | * g_udev_device_get_sysfs_attr: | ||
705 | * @device: A #GUdevDevice. | ||
706 | * @name: Name of the sysfs attribute. | ||
707 | * | ||
708 | * Look up the sysfs attribute with @name on @device. | ||
709 | * | ||
710 | * Returns: The value of the sysfs attribute or %NULL if there is no | ||
711 | * such attribute. Do not free this string, it is owned by @device. | ||
712 | */ | ||
713 | const gchar * | ||
714 | g_udev_device_get_sysfs_attr (GUdevDevice *device, | ||
715 | const gchar *name) | ||
716 | { | ||
717 | g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL); | ||
718 | g_return_val_if_fail (name != NULL, NULL); | ||
719 | return udev_device_get_sysattr_value (device->priv->udevice, name); | ||
720 | } | ||
721 | |||
722 | /** | ||
723 | * g_udev_device_get_sysfs_attr_as_int: | ||
724 | * @device: A #GUdevDevice. | ||
725 | * @name: Name of the sysfs attribute. | ||
726 | * | ||
727 | * Look up the sysfs attribute with @name on @device and convert it to an integer | ||
728 | * using strtol(). | ||
729 | * | ||
730 | * Returns: The value of the sysfs attribute or 0 if there is no such | ||
731 | * attribute. | ||
732 | */ | ||
733 | gint | ||
734 | g_udev_device_get_sysfs_attr_as_int (GUdevDevice *device, | ||
735 | const gchar *name) | ||
736 | { | ||
737 | gint result; | ||
738 | const gchar *s; | ||
739 | |||
740 | g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0); | ||
741 | g_return_val_if_fail (name != NULL, 0); | ||
742 | |||
743 | result = 0; | ||
744 | s = g_udev_device_get_sysfs_attr (device, name); | ||
745 | if (s == NULL) | ||
746 | goto out; | ||
747 | |||
748 | result = strtol (s, NULL, 0); | ||
749 | out: | ||
750 | return result; | ||
751 | } | ||
752 | |||
753 | /** | ||
754 | * g_udev_device_get_sysfs_attr_as_uint64: | ||
755 | * @device: A #GUdevDevice. | ||
756 | * @name: Name of the sysfs attribute. | ||
757 | * | ||
758 | * Look up the sysfs attribute with @name on @device and convert it to an unsigned | ||
759 | * 64-bit integer using g_ascii_strtoull(). | ||
760 | * | ||
761 | * Returns: The value of the sysfs attribute or 0 if there is no such | ||
762 | * attribute. | ||
763 | */ | ||
764 | guint64 | ||
765 | g_udev_device_get_sysfs_attr_as_uint64 (GUdevDevice *device, | ||
766 | const gchar *name) | ||
767 | { | ||
768 | guint64 result; | ||
769 | const gchar *s; | ||
770 | |||
771 | g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0); | ||
772 | g_return_val_if_fail (name != NULL, 0); | ||
773 | |||
774 | result = 0; | ||
775 | s = g_udev_device_get_sysfs_attr (device, name); | ||
776 | if (s == NULL) | ||
777 | goto out; | ||
778 | |||
779 | result = g_ascii_strtoull (s, NULL, 0); | ||
780 | out: | ||
781 | return result; | ||
782 | } | ||
783 | |||
784 | /** | ||
785 | * g_udev_device_get_sysfs_attr_as_double: | ||
786 | * @device: A #GUdevDevice. | ||
787 | * @name: Name of the sysfs attribute. | ||
788 | * | ||
789 | * Look up the sysfs attribute with @name on @device and convert it to a double | ||
790 | * precision floating point number using strtod(). | ||
791 | * | ||
792 | * Returns: The value of the sysfs attribute or 0.0 if there is no such | ||
793 | * attribute. | ||
794 | */ | ||
795 | gdouble | ||
796 | g_udev_device_get_sysfs_attr_as_double (GUdevDevice *device, | ||
797 | const gchar *name) | ||
798 | { | ||
799 | gdouble result; | ||
800 | const gchar *s; | ||
801 | |||
802 | g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0.0); | ||
803 | g_return_val_if_fail (name != NULL, 0.0); | ||
804 | |||
805 | result = 0.0; | ||
806 | s = g_udev_device_get_sysfs_attr (device, name); | ||
807 | if (s == NULL) | ||
808 | goto out; | ||
809 | |||
810 | result = strtod (s, NULL); | ||
811 | out: | ||
812 | return result; | ||
813 | } | ||
814 | |||
815 | /** | ||
816 | * g_udev_device_get_sysfs_attr_as_boolean: | ||
817 | * @device: A #GUdevDevice. | ||
818 | * @name: Name of the sysfs attribute. | ||
819 | * | ||
820 | * Look up the sysfs attribute with @name on @device and convert it to an | ||
821 | * boolean. This is done by doing a case-insensitive string comparison | ||
822 | * on the string value against "1" and "true". | ||
823 | * | ||
824 | * Returns: The value of the sysfs attribute or %FALSE if there is no such | ||
825 | * attribute. | ||
826 | */ | ||
827 | gboolean | ||
828 | g_udev_device_get_sysfs_attr_as_boolean (GUdevDevice *device, | ||
829 | const gchar *name) | ||
830 | { | ||
831 | gboolean result; | ||
832 | const gchar *s; | ||
833 | |||
834 | g_return_val_if_fail (G_UDEV_IS_DEVICE (device), FALSE); | ||
835 | g_return_val_if_fail (name != NULL, FALSE); | ||
836 | |||
837 | result = FALSE; | ||
838 | s = g_udev_device_get_sysfs_attr (device, name); | ||
839 | if (s == NULL) | ||
840 | goto out; | ||
841 | |||
842 | if (strcmp (s, "1") == 0 || g_ascii_strcasecmp (s, "true") == 0) | ||
843 | result = TRUE; | ||
844 | out: | ||
845 | return result; | ||
846 | } | ||
847 | |||
848 | /** | ||
849 | * g_udev_device_get_sysfs_attr_as_strv: | ||
850 | * @device: A #GUdevDevice. | ||
851 | * @name: Name of the sysfs attribute. | ||
852 | * | ||
853 | * Look up the sysfs attribute with @name on @device and return the result of | ||
854 | * splitting it into non-empty tokens split at white space (only space (' '), | ||
855 | * form-feed ('\f'), newline ('\n'), carriage return ('\r'), horizontal | ||
856 | * tab ('\t'), and vertical tab ('\v') are considered; the locale is | ||
857 | * not taken into account). | ||
858 | * | ||
859 | * Returns: (transfer none) (array zero-terminated=1) (element-type utf8): The value of the sysfs attribute split into tokens or %NULL if there is no such attribute. This array is owned by @device and should not be freed by the caller. | ||
860 | */ | ||
861 | const gchar * const * | ||
862 | g_udev_device_get_sysfs_attr_as_strv (GUdevDevice *device, | ||
863 | const gchar *name) | ||
864 | { | ||
865 | gchar **result; | ||
866 | const gchar *s; | ||
867 | |||
868 | g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL); | ||
869 | g_return_val_if_fail (name != NULL, NULL); | ||
870 | |||
871 | if (device->priv->sysfs_attr_strvs != NULL) | ||
872 | { | ||
873 | result = g_hash_table_lookup (device->priv->sysfs_attr_strvs, name); | ||
874 | if (result != NULL) | ||
875 | goto out; | ||
876 | } | ||
877 | |||
878 | result = NULL; | ||
879 | s = g_udev_device_get_sysfs_attr (device, name); | ||
880 | if (s == NULL) | ||
881 | goto out; | ||
882 | |||
883 | result = split_at_whitespace (s); | ||
884 | if (result == NULL) | ||
885 | goto out; | ||
886 | |||
887 | if (device->priv->sysfs_attr_strvs == NULL) | ||
888 | device->priv->sysfs_attr_strvs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_strfreev); | ||
889 | g_hash_table_insert (device->priv->sysfs_attr_strvs, g_strdup (name), result); | ||
890 | |||
891 | out: | ||
892 | return (const gchar* const *) result; | ||
893 | } | ||
894 | |||
895 | /** | ||
896 | * g_udev_device_get_tags: | ||
897 | * @device: A #GUdevDevice. | ||
898 | * | ||
899 | * Gets all tags for @device. | ||
900 | * | ||
901 | * Returns: (transfer none) (array zero-terminated=1) (element-type utf8): A %NULL terminated string array of tags. This array is owned by @device and should not be freed by the caller. | ||
902 | * | ||
903 | * Since: 165 | ||
904 | */ | ||
905 | const gchar* const * | ||
906 | g_udev_device_get_tags (GUdevDevice *device) | ||
907 | { | ||
908 | struct udev_list_entry *l; | ||
909 | GPtrArray *p; | ||
910 | |||
911 | g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL); | ||
912 | |||
913 | if (device->priv->tags != NULL) | ||
914 | goto out; | ||
915 | |||
916 | p = g_ptr_array_new (); | ||
917 | for (l = udev_device_get_tags_list_entry (device->priv->udevice); l != NULL; l = udev_list_entry_get_next (l)) | ||
918 | { | ||
919 | g_ptr_array_add (p, g_strdup (udev_list_entry_get_name (l))); | ||
920 | } | ||
921 | g_ptr_array_add (p, NULL); | ||
922 | device->priv->tags = (gchar **) g_ptr_array_free (p, FALSE); | ||
923 | |||
924 | out: | ||
925 | return (const gchar * const *) device->priv->tags; | ||
926 | } | ||
927 | |||
928 | /** | ||
929 | * g_udev_device_get_is_initialized: | ||
930 | * @device: A #GUdevDevice. | ||
931 | * | ||
932 | * Gets whether @device has been initalized. | ||
933 | * | ||
934 | * Returns: Whether @device has been initialized. | ||
935 | * | ||
936 | * Since: 165 | ||
937 | */ | ||
938 | gboolean | ||
939 | g_udev_device_get_is_initialized (GUdevDevice *device) | ||
940 | { | ||
941 | g_return_val_if_fail (G_UDEV_IS_DEVICE (device), FALSE); | ||
942 | return udev_device_get_is_initialized (device->priv->udevice); | ||
943 | } | ||
944 | |||
945 | /** | ||
946 | * g_udev_device_get_usec_since_initialized: | ||
947 | * @device: A #GUdevDevice. | ||
948 | * | ||
949 | * Gets number of micro-seconds since @device was initialized. | ||
950 | * | ||
951 | * This only works for devices with properties in the udev | ||
952 | * database. All other devices return 0. | ||
953 | * | ||
954 | * Returns: Number of micro-seconds since @device was initialized or 0 if unknown. | ||
955 | * | ||
956 | * Since: 165 | ||
957 | */ | ||
958 | guint64 | ||
959 | g_udev_device_get_usec_since_initialized (GUdevDevice *device) | ||
960 | { | ||
961 | g_return_val_if_fail (G_UDEV_IS_DEVICE (device), 0); | ||
962 | return udev_device_get_usec_since_initialized (device->priv->udevice); | ||
963 | } | ||
diff --git a/src/udev/src/gudev/gudevdevice.h b/src/udev/src/gudev/gudevdevice.h new file mode 100644 index 000000000..d4873bad0 --- /dev/null +++ b/src/udev/src/gudev/gudevdevice.h | |||
@@ -0,0 +1,128 @@ | |||
1 | /* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- | ||
2 | * | ||
3 | * Copyright (C) 2008 David Zeuthen <davidz@redhat.com> | ||
4 | * | ||
5 | * This library is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU Lesser General Public | ||
7 | * License as published by the Free Software Foundation; either | ||
8 | * version 2 of the License, or (at your option) any later version. | ||
9 | * | ||
10 | * This library 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 GNU | ||
13 | * Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this library; if not, write to the | ||
17 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | * Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | #if !defined (_GUDEV_COMPILATION) && !defined(_GUDEV_INSIDE_GUDEV_H) | ||
22 | #error "Only <gudev/gudev.h> can be included directly, this file may disappear or change contents." | ||
23 | #endif | ||
24 | |||
25 | #ifndef __G_UDEV_DEVICE_H__ | ||
26 | #define __G_UDEV_DEVICE_H__ | ||
27 | |||
28 | #include <gudev/gudevtypes.h> | ||
29 | |||
30 | G_BEGIN_DECLS | ||
31 | |||
32 | #define G_UDEV_TYPE_DEVICE (g_udev_device_get_type ()) | ||
33 | #define G_UDEV_DEVICE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_UDEV_TYPE_DEVICE, GUdevDevice)) | ||
34 | #define G_UDEV_DEVICE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_UDEV_TYPE_DEVICE, GUdevDeviceClass)) | ||
35 | #define G_UDEV_IS_DEVICE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_UDEV_TYPE_DEVICE)) | ||
36 | #define G_UDEV_IS_DEVICE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_UDEV_TYPE_DEVICE)) | ||
37 | #define G_UDEV_DEVICE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_UDEV_TYPE_DEVICE, GUdevDeviceClass)) | ||
38 | |||
39 | typedef struct _GUdevDeviceClass GUdevDeviceClass; | ||
40 | typedef struct _GUdevDevicePrivate GUdevDevicePrivate; | ||
41 | |||
42 | /** | ||
43 | * GUdevDevice: | ||
44 | * | ||
45 | * The #GUdevDevice struct is opaque and should not be accessed directly. | ||
46 | */ | ||
47 | struct _GUdevDevice | ||
48 | { | ||
49 | GObject parent; | ||
50 | |||
51 | /*< private >*/ | ||
52 | GUdevDevicePrivate *priv; | ||
53 | }; | ||
54 | |||
55 | /** | ||
56 | * GUdevDeviceClass: | ||
57 | * @parent_class: Parent class. | ||
58 | * | ||
59 | * Class structure for #GUdevDevice. | ||
60 | */ | ||
61 | struct _GUdevDeviceClass | ||
62 | { | ||
63 | GObjectClass parent_class; | ||
64 | |||
65 | /*< private >*/ | ||
66 | /* Padding for future expansion */ | ||
67 | void (*reserved1) (void); | ||
68 | void (*reserved2) (void); | ||
69 | void (*reserved3) (void); | ||
70 | void (*reserved4) (void); | ||
71 | void (*reserved5) (void); | ||
72 | void (*reserved6) (void); | ||
73 | void (*reserved7) (void); | ||
74 | void (*reserved8) (void); | ||
75 | }; | ||
76 | |||
77 | GType g_udev_device_get_type (void) G_GNUC_CONST; | ||
78 | gboolean g_udev_device_get_is_initialized (GUdevDevice *device); | ||
79 | guint64 g_udev_device_get_usec_since_initialized (GUdevDevice *device); | ||
80 | const gchar *g_udev_device_get_subsystem (GUdevDevice *device); | ||
81 | const gchar *g_udev_device_get_devtype (GUdevDevice *device); | ||
82 | const gchar *g_udev_device_get_name (GUdevDevice *device); | ||
83 | const gchar *g_udev_device_get_number (GUdevDevice *device); | ||
84 | const gchar *g_udev_device_get_sysfs_path (GUdevDevice *device); | ||
85 | const gchar *g_udev_device_get_driver (GUdevDevice *device); | ||
86 | const gchar *g_udev_device_get_action (GUdevDevice *device); | ||
87 | guint64 g_udev_device_get_seqnum (GUdevDevice *device); | ||
88 | GUdevDeviceType g_udev_device_get_device_type (GUdevDevice *device); | ||
89 | GUdevDeviceNumber g_udev_device_get_device_number (GUdevDevice *device); | ||
90 | const gchar *g_udev_device_get_device_file (GUdevDevice *device); | ||
91 | const gchar* const *g_udev_device_get_device_file_symlinks (GUdevDevice *device); | ||
92 | GUdevDevice *g_udev_device_get_parent (GUdevDevice *device); | ||
93 | GUdevDevice *g_udev_device_get_parent_with_subsystem (GUdevDevice *device, | ||
94 | const gchar *subsystem, | ||
95 | const gchar *devtype); | ||
96 | const gchar* const *g_udev_device_get_property_keys (GUdevDevice *device); | ||
97 | gboolean g_udev_device_has_property (GUdevDevice *device, | ||
98 | const gchar *key); | ||
99 | const gchar *g_udev_device_get_property (GUdevDevice *device, | ||
100 | const gchar *key); | ||
101 | gint g_udev_device_get_property_as_int (GUdevDevice *device, | ||
102 | const gchar *key); | ||
103 | guint64 g_udev_device_get_property_as_uint64 (GUdevDevice *device, | ||
104 | const gchar *key); | ||
105 | gdouble g_udev_device_get_property_as_double (GUdevDevice *device, | ||
106 | const gchar *key); | ||
107 | gboolean g_udev_device_get_property_as_boolean (GUdevDevice *device, | ||
108 | const gchar *key); | ||
109 | const gchar* const *g_udev_device_get_property_as_strv (GUdevDevice *device, | ||
110 | const gchar *key); | ||
111 | |||
112 | const gchar *g_udev_device_get_sysfs_attr (GUdevDevice *device, | ||
113 | const gchar *name); | ||
114 | gint g_udev_device_get_sysfs_attr_as_int (GUdevDevice *device, | ||
115 | const gchar *name); | ||
116 | guint64 g_udev_device_get_sysfs_attr_as_uint64 (GUdevDevice *device, | ||
117 | const gchar *name); | ||
118 | gdouble g_udev_device_get_sysfs_attr_as_double (GUdevDevice *device, | ||
119 | const gchar *name); | ||
120 | gboolean g_udev_device_get_sysfs_attr_as_boolean (GUdevDevice *device, | ||
121 | const gchar *name); | ||
122 | const gchar* const *g_udev_device_get_sysfs_attr_as_strv (GUdevDevice *device, | ||
123 | const gchar *name); | ||
124 | const gchar* const *g_udev_device_get_tags (GUdevDevice *device); | ||
125 | |||
126 | G_END_DECLS | ||
127 | |||
128 | #endif /* __G_UDEV_DEVICE_H__ */ | ||
diff --git a/src/udev/src/gudev/gudevenumerator.c b/src/udev/src/gudev/gudevenumerator.c new file mode 100644 index 000000000..db0907462 --- /dev/null +++ b/src/udev/src/gudev/gudevenumerator.c | |||
@@ -0,0 +1,431 @@ | |||
1 | /* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- | ||
2 | * | ||
3 | * Copyright (C) 2008-2010 David Zeuthen <davidz@redhat.com> | ||
4 | * | ||
5 | * This library is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU Lesser General Public | ||
7 | * License as published by the Free Software Foundation; either | ||
8 | * version 2 of the License, or (at your option) any later version. | ||
9 | * | ||
10 | * This library 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 GNU | ||
13 | * Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this library; if not, write to the | ||
17 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | * Boston, MA 02111-1307, USA. | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #ifdef HAVE_CONFIG_H | ||
23 | # include "config.h" | ||
24 | #endif | ||
25 | |||
26 | #include <stdlib.h> | ||
27 | #include <string.h> | ||
28 | |||
29 | #include "gudevclient.h" | ||
30 | #include "gudevenumerator.h" | ||
31 | #include "gudevdevice.h" | ||
32 | #include "gudevmarshal.h" | ||
33 | #include "gudevprivate.h" | ||
34 | |||
35 | /** | ||
36 | * SECTION:gudevenumerator | ||
37 | * @short_description: Lookup and sort devices | ||
38 | * | ||
39 | * #GUdevEnumerator is used to lookup and sort devices. | ||
40 | * | ||
41 | * Since: 165 | ||
42 | */ | ||
43 | |||
44 | struct _GUdevEnumeratorPrivate | ||
45 | { | ||
46 | GUdevClient *client; | ||
47 | struct udev_enumerate *e; | ||
48 | }; | ||
49 | |||
50 | enum | ||
51 | { | ||
52 | PROP_0, | ||
53 | PROP_CLIENT, | ||
54 | }; | ||
55 | |||
56 | G_DEFINE_TYPE (GUdevEnumerator, g_udev_enumerator, G_TYPE_OBJECT) | ||
57 | |||
58 | /* ---------------------------------------------------------------------------------------------------- */ | ||
59 | |||
60 | static void | ||
61 | g_udev_enumerator_finalize (GObject *object) | ||
62 | { | ||
63 | GUdevEnumerator *enumerator = G_UDEV_ENUMERATOR (object); | ||
64 | |||
65 | if (enumerator->priv->client != NULL) | ||
66 | { | ||
67 | g_object_unref (enumerator->priv->client); | ||
68 | enumerator->priv->client = NULL; | ||
69 | } | ||
70 | |||
71 | if (enumerator->priv->e != NULL) | ||
72 | { | ||
73 | udev_enumerate_unref (enumerator->priv->e); | ||
74 | enumerator->priv->e = NULL; | ||
75 | } | ||
76 | |||
77 | if (G_OBJECT_CLASS (g_udev_enumerator_parent_class)->finalize != NULL) | ||
78 | G_OBJECT_CLASS (g_udev_enumerator_parent_class)->finalize (object); | ||
79 | } | ||
80 | |||
81 | static void | ||
82 | g_udev_enumerator_set_property (GObject *object, | ||
83 | guint prop_id, | ||
84 | const GValue *value, | ||
85 | GParamSpec *pspec) | ||
86 | { | ||
87 | GUdevEnumerator *enumerator = G_UDEV_ENUMERATOR (object); | ||
88 | |||
89 | switch (prop_id) | ||
90 | { | ||
91 | case PROP_CLIENT: | ||
92 | if (enumerator->priv->client != NULL) | ||
93 | g_object_unref (enumerator->priv->client); | ||
94 | enumerator->priv->client = g_value_dup_object (value); | ||
95 | break; | ||
96 | |||
97 | default: | ||
98 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); | ||
99 | break; | ||
100 | } | ||
101 | } | ||
102 | |||
103 | static void | ||
104 | g_udev_enumerator_get_property (GObject *object, | ||
105 | guint prop_id, | ||
106 | GValue *value, | ||
107 | GParamSpec *pspec) | ||
108 | { | ||
109 | GUdevEnumerator *enumerator = G_UDEV_ENUMERATOR (object); | ||
110 | |||
111 | switch (prop_id) | ||
112 | { | ||
113 | case PROP_CLIENT: | ||
114 | g_value_set_object (value, enumerator->priv->client); | ||
115 | break; | ||
116 | |||
117 | default: | ||
118 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); | ||
119 | break; | ||
120 | } | ||
121 | } | ||
122 | |||
123 | static void | ||
124 | g_udev_enumerator_constructed (GObject *object) | ||
125 | { | ||
126 | GUdevEnumerator *enumerator = G_UDEV_ENUMERATOR (object); | ||
127 | |||
128 | g_assert (G_UDEV_IS_CLIENT (enumerator->priv->client)); | ||
129 | |||
130 | enumerator->priv->e = udev_enumerate_new (_g_udev_client_get_udev (enumerator->priv->client)); | ||
131 | |||
132 | if (G_OBJECT_CLASS (g_udev_enumerator_parent_class)->constructed != NULL) | ||
133 | G_OBJECT_CLASS (g_udev_enumerator_parent_class)->constructed (object); | ||
134 | } | ||
135 | |||
136 | static void | ||
137 | g_udev_enumerator_class_init (GUdevEnumeratorClass *klass) | ||
138 | { | ||
139 | GObjectClass *gobject_class = (GObjectClass *) klass; | ||
140 | |||
141 | gobject_class->finalize = g_udev_enumerator_finalize; | ||
142 | gobject_class->set_property = g_udev_enumerator_set_property; | ||
143 | gobject_class->get_property = g_udev_enumerator_get_property; | ||
144 | gobject_class->constructed = g_udev_enumerator_constructed; | ||
145 | |||
146 | /** | ||
147 | * GUdevEnumerator:client: | ||
148 | * | ||
149 | * The #GUdevClient to enumerate devices from. | ||
150 | * | ||
151 | * Since: 165 | ||
152 | */ | ||
153 | g_object_class_install_property (gobject_class, | ||
154 | PROP_CLIENT, | ||
155 | g_param_spec_object ("client", | ||
156 | "The client to enumerate devices from", | ||
157 | "The client to enumerate devices from", | ||
158 | G_UDEV_TYPE_CLIENT, | ||
159 | G_PARAM_CONSTRUCT_ONLY | | ||
160 | G_PARAM_READWRITE)); | ||
161 | |||
162 | g_type_class_add_private (klass, sizeof (GUdevEnumeratorPrivate)); | ||
163 | } | ||
164 | |||
165 | static void | ||
166 | g_udev_enumerator_init (GUdevEnumerator *enumerator) | ||
167 | { | ||
168 | enumerator->priv = G_TYPE_INSTANCE_GET_PRIVATE (enumerator, | ||
169 | G_UDEV_TYPE_ENUMERATOR, | ||
170 | GUdevEnumeratorPrivate); | ||
171 | } | ||
172 | |||
173 | /** | ||
174 | * g_udev_enumerator_new: | ||
175 | * @client: A #GUdevClient to enumerate devices from. | ||
176 | * | ||
177 | * Constructs a #GUdevEnumerator object that can be used to enumerate | ||
178 | * and sort devices. Use the add_match_*() and add_nomatch_*() methods | ||
179 | * and execute the query to get a list of devices with | ||
180 | * g_udev_enumerator_execute(). | ||
181 | * | ||
182 | * Returns: A new #GUdevEnumerator object. Free with g_object_unref(). | ||
183 | * | ||
184 | * Since: 165 | ||
185 | */ | ||
186 | GUdevEnumerator * | ||
187 | g_udev_enumerator_new (GUdevClient *client) | ||
188 | { | ||
189 | g_return_val_if_fail (G_UDEV_IS_CLIENT (client), NULL); | ||
190 | return G_UDEV_ENUMERATOR (g_object_new (G_UDEV_TYPE_ENUMERATOR, "client", client, NULL)); | ||
191 | } | ||
192 | |||
193 | |||
194 | /** | ||
195 | * g_udev_enumerator_add_match_subsystem: | ||
196 | * @enumerator: A #GUdevEnumerator. | ||
197 | * @subsystem: Wildcard for subsystem name e.g. 'scsi' or 'a*'. | ||
198 | * | ||
199 | * All returned devices will match the given @subsystem. | ||
200 | * | ||
201 | * Returns: (transfer none): The passed in @enumerator. | ||
202 | * | ||
203 | * Since: 165 | ||
204 | */ | ||
205 | GUdevEnumerator * | ||
206 | g_udev_enumerator_add_match_subsystem (GUdevEnumerator *enumerator, | ||
207 | const gchar *subsystem) | ||
208 | { | ||
209 | g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL); | ||
210 | g_return_val_if_fail (subsystem != NULL, NULL); | ||
211 | udev_enumerate_add_match_subsystem (enumerator->priv->e, subsystem); | ||
212 | return enumerator; | ||
213 | } | ||
214 | |||
215 | /** | ||
216 | * g_udev_enumerator_add_nomatch_subsystem: | ||
217 | * @enumerator: A #GUdevEnumerator. | ||
218 | * @subsystem: Wildcard for subsystem name e.g. 'scsi' or 'a*'. | ||
219 | * | ||
220 | * All returned devices will not match the given @subsystem. | ||
221 | * | ||
222 | * Returns: (transfer none): The passed in @enumerator. | ||
223 | * | ||
224 | * Since: 165 | ||
225 | */ | ||
226 | GUdevEnumerator * | ||
227 | g_udev_enumerator_add_nomatch_subsystem (GUdevEnumerator *enumerator, | ||
228 | const gchar *subsystem) | ||
229 | { | ||
230 | g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL); | ||
231 | g_return_val_if_fail (subsystem != NULL, NULL); | ||
232 | udev_enumerate_add_nomatch_subsystem (enumerator->priv->e, subsystem); | ||
233 | return enumerator; | ||
234 | } | ||
235 | |||
236 | /** | ||
237 | * g_udev_enumerator_add_match_sysfs_attr: | ||
238 | * @enumerator: A #GUdevEnumerator. | ||
239 | * @name: Wildcard filter for sysfs attribute key. | ||
240 | * @value: Wildcard filter for sysfs attribute value. | ||
241 | * | ||
242 | * All returned devices will have a sysfs attribute matching the given @name and @value. | ||
243 | * | ||
244 | * Returns: (transfer none): The passed in @enumerator. | ||
245 | * | ||
246 | * Since: 165 | ||
247 | */ | ||
248 | GUdevEnumerator * | ||
249 | g_udev_enumerator_add_match_sysfs_attr (GUdevEnumerator *enumerator, | ||
250 | const gchar *name, | ||
251 | const gchar *value) | ||
252 | { | ||
253 | g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL); | ||
254 | g_return_val_if_fail (name != NULL, NULL); | ||
255 | g_return_val_if_fail (value != NULL, NULL); | ||
256 | udev_enumerate_add_match_sysattr (enumerator->priv->e, name, value); | ||
257 | return enumerator; | ||
258 | } | ||
259 | |||
260 | /** | ||
261 | * g_udev_enumerator_add_nomatch_sysfs_attr: | ||
262 | * @enumerator: A #GUdevEnumerator. | ||
263 | * @name: Wildcard filter for sysfs attribute key. | ||
264 | * @value: Wildcard filter for sysfs attribute value. | ||
265 | * | ||
266 | * All returned devices will not have a sysfs attribute matching the given @name and @value. | ||
267 | * | ||
268 | * Returns: (transfer none): The passed in @enumerator. | ||
269 | * | ||
270 | * Since: 165 | ||
271 | */ | ||
272 | GUdevEnumerator * | ||
273 | g_udev_enumerator_add_nomatch_sysfs_attr (GUdevEnumerator *enumerator, | ||
274 | const gchar *name, | ||
275 | const gchar *value) | ||
276 | { | ||
277 | g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL); | ||
278 | g_return_val_if_fail (name != NULL, NULL); | ||
279 | g_return_val_if_fail (value != NULL, NULL); | ||
280 | udev_enumerate_add_nomatch_sysattr (enumerator->priv->e, name, value); | ||
281 | return enumerator; | ||
282 | } | ||
283 | |||
284 | /** | ||
285 | * g_udev_enumerator_add_match_property: | ||
286 | * @enumerator: A #GUdevEnumerator. | ||
287 | * @name: Wildcard filter for property name. | ||
288 | * @value: Wildcard filter for property value. | ||
289 | * | ||
290 | * All returned devices will have a property matching the given @name and @value. | ||
291 | * | ||
292 | * Returns: (transfer none): The passed in @enumerator. | ||
293 | * | ||
294 | * Since: 165 | ||
295 | */ | ||
296 | GUdevEnumerator * | ||
297 | g_udev_enumerator_add_match_property (GUdevEnumerator *enumerator, | ||
298 | const gchar *name, | ||
299 | const gchar *value) | ||
300 | { | ||
301 | g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL); | ||
302 | g_return_val_if_fail (name != NULL, NULL); | ||
303 | g_return_val_if_fail (value != NULL, NULL); | ||
304 | udev_enumerate_add_match_property (enumerator->priv->e, name, value); | ||
305 | return enumerator; | ||
306 | } | ||
307 | |||
308 | /** | ||
309 | * g_udev_enumerator_add_match_name: | ||
310 | * @enumerator: A #GUdevEnumerator. | ||
311 | * @name: Wildcard filter for kernel name e.g. "sda*". | ||
312 | * | ||
313 | * All returned devices will match the given @name. | ||
314 | * | ||
315 | * Returns: (transfer none): The passed in @enumerator. | ||
316 | * | ||
317 | * Since: 165 | ||
318 | */ | ||
319 | GUdevEnumerator * | ||
320 | g_udev_enumerator_add_match_name (GUdevEnumerator *enumerator, | ||
321 | const gchar *name) | ||
322 | { | ||
323 | g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL); | ||
324 | g_return_val_if_fail (name != NULL, NULL); | ||
325 | udev_enumerate_add_match_sysname (enumerator->priv->e, name); | ||
326 | return enumerator; | ||
327 | } | ||
328 | |||
329 | /** | ||
330 | * g_udev_enumerator_add_sysfs_path: | ||
331 | * @enumerator: A #GUdevEnumerator. | ||
332 | * @sysfs_path: A sysfs path, e.g. "/sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda" | ||
333 | * | ||
334 | * Add a device to the list of devices, to retrieve it back sorted in dependency order. | ||
335 | * | ||
336 | * Returns: (transfer none): The passed in @enumerator. | ||
337 | * | ||
338 | * Since: 165 | ||
339 | */ | ||
340 | GUdevEnumerator * | ||
341 | g_udev_enumerator_add_sysfs_path (GUdevEnumerator *enumerator, | ||
342 | const gchar *sysfs_path) | ||
343 | { | ||
344 | g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL); | ||
345 | g_return_val_if_fail (sysfs_path != NULL, NULL); | ||
346 | udev_enumerate_add_syspath (enumerator->priv->e, sysfs_path); | ||
347 | return enumerator; | ||
348 | } | ||
349 | |||
350 | /** | ||
351 | * g_udev_enumerator_add_match_tag: | ||
352 | * @enumerator: A #GUdevEnumerator. | ||
353 | * @tag: A udev tag e.g. "udev-acl". | ||
354 | * | ||
355 | * All returned devices will match the given @tag. | ||
356 | * | ||
357 | * Returns: (transfer none): The passed in @enumerator. | ||
358 | * | ||
359 | * Since: 165 | ||
360 | */ | ||
361 | GUdevEnumerator * | ||
362 | g_udev_enumerator_add_match_tag (GUdevEnumerator *enumerator, | ||
363 | const gchar *tag) | ||
364 | { | ||
365 | g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL); | ||
366 | g_return_val_if_fail (tag != NULL, NULL); | ||
367 | udev_enumerate_add_match_tag (enumerator->priv->e, tag); | ||
368 | return enumerator; | ||
369 | } | ||
370 | |||
371 | /** | ||
372 | * g_udev_enumerator_add_match_is_initialized: | ||
373 | * @enumerator: A #GUdevEnumerator. | ||
374 | * | ||
375 | * All returned devices will be initialized. | ||
376 | * | ||
377 | * Returns: (transfer none): The passed in @enumerator. | ||
378 | * | ||
379 | * Since: 165 | ||
380 | */ | ||
381 | GUdevEnumerator * | ||
382 | g_udev_enumerator_add_match_is_initialized (GUdevEnumerator *enumerator) | ||
383 | { | ||
384 | g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL); | ||
385 | udev_enumerate_add_match_is_initialized (enumerator->priv->e); | ||
386 | return enumerator; | ||
387 | } | ||
388 | |||
389 | /** | ||
390 | * g_udev_enumerator_execute: | ||
391 | * @enumerator: A #GUdevEnumerator. | ||
392 | * | ||
393 | * Executes the query in @enumerator. | ||
394 | * | ||
395 | * Returns: (element-type GUdevDevice) (transfer full): A list of #GUdevDevice objects. The caller should free the result by using g_object_unref() on each element in the list and then g_list_free() on the list. | ||
396 | * | ||
397 | * Since: 165 | ||
398 | */ | ||
399 | GList * | ||
400 | g_udev_enumerator_execute (GUdevEnumerator *enumerator) | ||
401 | { | ||
402 | GList *ret; | ||
403 | struct udev_list_entry *l, *devices; | ||
404 | |||
405 | g_return_val_if_fail (G_UDEV_IS_ENUMERATOR (enumerator), NULL); | ||
406 | |||
407 | ret = NULL; | ||
408 | |||
409 | /* retrieve the list */ | ||
410 | udev_enumerate_scan_devices (enumerator->priv->e); | ||
411 | |||
412 | devices = udev_enumerate_get_list_entry (enumerator->priv->e); | ||
413 | for (l = devices; l != NULL; l = udev_list_entry_get_next (l)) | ||
414 | { | ||
415 | struct udev_device *udevice; | ||
416 | GUdevDevice *device; | ||
417 | |||
418 | udevice = udev_device_new_from_syspath (udev_enumerate_get_udev (enumerator->priv->e), | ||
419 | udev_list_entry_get_name (l)); | ||
420 | if (udevice == NULL) | ||
421 | continue; | ||
422 | |||
423 | device = _g_udev_device_new (udevice); | ||
424 | udev_device_unref (udevice); | ||
425 | ret = g_list_prepend (ret, device); | ||
426 | } | ||
427 | |||
428 | ret = g_list_reverse (ret); | ||
429 | |||
430 | return ret; | ||
431 | } | ||
diff --git a/src/udev/src/gudev/gudevenumerator.h b/src/udev/src/gudev/gudevenumerator.h new file mode 100644 index 000000000..3fddccf57 --- /dev/null +++ b/src/udev/src/gudev/gudevenumerator.h | |||
@@ -0,0 +1,107 @@ | |||
1 | /* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- | ||
2 | * | ||
3 | * Copyright (C) 2008-2010 David Zeuthen <davidz@redhat.com> | ||
4 | * | ||
5 | * This library is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU Lesser General Public | ||
7 | * License as published by the Free Software Foundation; either | ||
8 | * version 2 of the License, or (at your option) any later version. | ||
9 | * | ||
10 | * This library 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 GNU | ||
13 | * Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this library; if not, write to the | ||
17 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | * Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | #if !defined (_GUDEV_COMPILATION) && !defined(_GUDEV_INSIDE_GUDEV_H) | ||
22 | #error "Only <gudev/gudev.h> can be included directly, this file may disappear or change contents." | ||
23 | #endif | ||
24 | |||
25 | #ifndef __G_UDEV_ENUMERATOR_H__ | ||
26 | #define __G_UDEV_ENUMERATOR_H__ | ||
27 | |||
28 | #include <gudev/gudevtypes.h> | ||
29 | |||
30 | G_BEGIN_DECLS | ||
31 | |||
32 | #define G_UDEV_TYPE_ENUMERATOR (g_udev_enumerator_get_type ()) | ||
33 | #define G_UDEV_ENUMERATOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_UDEV_TYPE_ENUMERATOR, GUdevEnumerator)) | ||
34 | #define G_UDEV_ENUMERATOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_UDEV_TYPE_ENUMERATOR, GUdevEnumeratorClass)) | ||
35 | #define G_UDEV_IS_ENUMERATOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_UDEV_TYPE_ENUMERATOR)) | ||
36 | #define G_UDEV_IS_ENUMERATOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_UDEV_TYPE_ENUMERATOR)) | ||
37 | #define G_UDEV_ENUMERATOR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_UDEV_TYPE_ENUMERATOR, GUdevEnumeratorClass)) | ||
38 | |||
39 | typedef struct _GUdevEnumeratorClass GUdevEnumeratorClass; | ||
40 | typedef struct _GUdevEnumeratorPrivate GUdevEnumeratorPrivate; | ||
41 | |||
42 | /** | ||
43 | * GUdevEnumerator: | ||
44 | * | ||
45 | * The #GUdevEnumerator struct is opaque and should not be accessed directly. | ||
46 | * | ||
47 | * Since: 165 | ||
48 | */ | ||
49 | struct _GUdevEnumerator | ||
50 | { | ||
51 | GObject parent; | ||
52 | |||
53 | /*< private >*/ | ||
54 | GUdevEnumeratorPrivate *priv; | ||
55 | }; | ||
56 | |||
57 | /** | ||
58 | * GUdevEnumeratorClass: | ||
59 | * @parent_class: Parent class. | ||
60 | * | ||
61 | * Class structure for #GUdevEnumerator. | ||
62 | * | ||
63 | * Since: 165 | ||
64 | */ | ||
65 | struct _GUdevEnumeratorClass | ||
66 | { | ||
67 | GObjectClass parent_class; | ||
68 | |||
69 | /*< private >*/ | ||
70 | /* Padding for future expansion */ | ||
71 | void (*reserved1) (void); | ||
72 | void (*reserved2) (void); | ||
73 | void (*reserved3) (void); | ||
74 | void (*reserved4) (void); | ||
75 | void (*reserved5) (void); | ||
76 | void (*reserved6) (void); | ||
77 | void (*reserved7) (void); | ||
78 | void (*reserved8) (void); | ||
79 | }; | ||
80 | |||
81 | GType g_udev_enumerator_get_type (void) G_GNUC_CONST; | ||
82 | GUdevEnumerator *g_udev_enumerator_new (GUdevClient *client); | ||
83 | GUdevEnumerator *g_udev_enumerator_add_match_subsystem (GUdevEnumerator *enumerator, | ||
84 | const gchar *subsystem); | ||
85 | GUdevEnumerator *g_udev_enumerator_add_nomatch_subsystem (GUdevEnumerator *enumerator, | ||
86 | const gchar *subsystem); | ||
87 | GUdevEnumerator *g_udev_enumerator_add_match_sysfs_attr (GUdevEnumerator *enumerator, | ||
88 | const gchar *name, | ||
89 | const gchar *value); | ||
90 | GUdevEnumerator *g_udev_enumerator_add_nomatch_sysfs_attr (GUdevEnumerator *enumerator, | ||
91 | const gchar *name, | ||
92 | const gchar *value); | ||
93 | GUdevEnumerator *g_udev_enumerator_add_match_property (GUdevEnumerator *enumerator, | ||
94 | const gchar *name, | ||
95 | const gchar *value); | ||
96 | GUdevEnumerator *g_udev_enumerator_add_match_name (GUdevEnumerator *enumerator, | ||
97 | const gchar *name); | ||
98 | GUdevEnumerator *g_udev_enumerator_add_match_tag (GUdevEnumerator *enumerator, | ||
99 | const gchar *tag); | ||
100 | GUdevEnumerator *g_udev_enumerator_add_match_is_initialized (GUdevEnumerator *enumerator); | ||
101 | GUdevEnumerator *g_udev_enumerator_add_sysfs_path (GUdevEnumerator *enumerator, | ||
102 | const gchar *sysfs_path); | ||
103 | GList *g_udev_enumerator_execute (GUdevEnumerator *enumerator); | ||
104 | |||
105 | G_END_DECLS | ||
106 | |||
107 | #endif /* __G_UDEV_ENUMERATOR_H__ */ | ||
diff --git a/src/udev/src/gudev/gudevenums.h b/src/udev/src/gudev/gudevenums.h new file mode 100644 index 000000000..c3a0aa874 --- /dev/null +++ b/src/udev/src/gudev/gudevenums.h | |||
@@ -0,0 +1,49 @@ | |||
1 | /* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- | ||
2 | * | ||
3 | * Copyright (C) 2008 David Zeuthen <davidz@redhat.com> | ||
4 | * | ||
5 | * This library is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU Lesser General Public | ||
7 | * License as published by the Free Software Foundation; either | ||
8 | * version 2 of the License, or (at your option) any later version. | ||
9 | * | ||
10 | * This library 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 GNU | ||
13 | * Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this library; if not, write to the | ||
17 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | * Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | #if !defined (_GUDEV_COMPILATION) && !defined(_GUDEV_INSIDE_GUDEV_H) | ||
22 | #error "Only <gudev/gudev.h> can be included directly, this file may disappear or change contents." | ||
23 | #endif | ||
24 | |||
25 | #ifndef __G_UDEV_ENUMS_H__ | ||
26 | #define __G_UDEV_ENUMS_H__ | ||
27 | |||
28 | #include <glib-object.h> | ||
29 | |||
30 | G_BEGIN_DECLS | ||
31 | |||
32 | /** | ||
33 | * GUdevDeviceType: | ||
34 | * @G_UDEV_DEVICE_TYPE_NONE: Device does not have a device file. | ||
35 | * @G_UDEV_DEVICE_TYPE_BLOCK: Device is a block device. | ||
36 | * @G_UDEV_DEVICE_TYPE_CHAR: Device is a character device. | ||
37 | * | ||
38 | * Enumeration used to specify a the type of a device. | ||
39 | */ | ||
40 | typedef enum | ||
41 | { | ||
42 | G_UDEV_DEVICE_TYPE_NONE = 0, | ||
43 | G_UDEV_DEVICE_TYPE_BLOCK = 'b', | ||
44 | G_UDEV_DEVICE_TYPE_CHAR = 'c', | ||
45 | } GUdevDeviceType; | ||
46 | |||
47 | G_END_DECLS | ||
48 | |||
49 | #endif /* __G_UDEV_ENUMS_H__ */ | ||
diff --git a/src/udev/src/gudev/gudevenumtypes.c.template b/src/udev/src/gudev/gudevenumtypes.c.template new file mode 100644 index 000000000..fc30b39e2 --- /dev/null +++ b/src/udev/src/gudev/gudevenumtypes.c.template | |||
@@ -0,0 +1,39 @@ | |||
1 | /*** BEGIN file-header ***/ | ||
2 | #include <gudev.h> | ||
3 | |||
4 | /*** END file-header ***/ | ||
5 | |||
6 | /*** BEGIN file-production ***/ | ||
7 | /* enumerations from "@filename@" */ | ||
8 | /*** END file-production ***/ | ||
9 | |||
10 | /*** BEGIN value-header ***/ | ||
11 | GType | ||
12 | @enum_name@_get_type (void) | ||
13 | { | ||
14 | static volatile gsize g_define_type_id__volatile = 0; | ||
15 | |||
16 | if (g_once_init_enter (&g_define_type_id__volatile)) | ||
17 | { | ||
18 | static const G@Type@Value values[] = { | ||
19 | /*** END value-header ***/ | ||
20 | |||
21 | /*** BEGIN value-production ***/ | ||
22 | { @VALUENAME@, "@VALUENAME@", "@valuenick@" }, | ||
23 | /*** END value-production ***/ | ||
24 | |||
25 | /*** BEGIN value-tail ***/ | ||
26 | { 0, NULL, NULL } | ||
27 | }; | ||
28 | GType g_define_type_id = | ||
29 | g_@type@_register_static (g_intern_static_string ("@EnumName@"), values); | ||
30 | g_once_init_leave (&g_define_type_id__volatile, g_define_type_id); | ||
31 | } | ||
32 | |||
33 | return g_define_type_id__volatile; | ||
34 | } | ||
35 | |||
36 | /*** END value-tail ***/ | ||
37 | |||
38 | /*** BEGIN file-tail ***/ | ||
39 | /*** END file-tail ***/ | ||
diff --git a/src/udev/src/gudev/gudevenumtypes.h.template b/src/udev/src/gudev/gudevenumtypes.h.template new file mode 100644 index 000000000..d0ab3393e --- /dev/null +++ b/src/udev/src/gudev/gudevenumtypes.h.template | |||
@@ -0,0 +1,24 @@ | |||
1 | /*** BEGIN file-header ***/ | ||
2 | #ifndef __GUDEV_ENUM_TYPES_H__ | ||
3 | #define __GUDEV_ENUM_TYPES_H__ | ||
4 | |||
5 | #include <glib-object.h> | ||
6 | |||
7 | G_BEGIN_DECLS | ||
8 | /*** END file-header ***/ | ||
9 | |||
10 | /*** BEGIN file-production ***/ | ||
11 | |||
12 | /* enumerations from "@filename@" */ | ||
13 | /*** END file-production ***/ | ||
14 | |||
15 | /*** BEGIN value-header ***/ | ||
16 | GType @enum_name@_get_type (void) G_GNUC_CONST; | ||
17 | #define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (@enum_name@_get_type ()) | ||
18 | /*** END value-header ***/ | ||
19 | |||
20 | /*** BEGIN file-tail ***/ | ||
21 | G_END_DECLS | ||
22 | |||
23 | #endif /* __GUDEV_ENUM_TYPES_H__ */ | ||
24 | /*** END file-tail ***/ | ||
diff --git a/src/udev/src/gudev/gudevmarshal.list b/src/udev/src/gudev/gudevmarshal.list new file mode 100644 index 000000000..7e665999e --- /dev/null +++ b/src/udev/src/gudev/gudevmarshal.list | |||
@@ -0,0 +1 @@ | |||
VOID:STRING,OBJECT | |||
diff --git a/src/udev/src/gudev/gudevprivate.h b/src/udev/src/gudev/gudevprivate.h new file mode 100644 index 000000000..8866f52b8 --- /dev/null +++ b/src/udev/src/gudev/gudevprivate.h | |||
@@ -0,0 +1,41 @@ | |||
1 | /* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- | ||
2 | * | ||
3 | * Copyright (C) 2008 David Zeuthen <davidz@redhat.com> | ||
4 | * | ||
5 | * This library is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU Lesser General Public | ||
7 | * License as published by the Free Software Foundation; either | ||
8 | * version 2 of the License, or (at your option) any later version. | ||
9 | * | ||
10 | * This library 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 GNU | ||
13 | * Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this library; if not, write to the | ||
17 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | * Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | #if !defined (_GUDEV_COMPILATION) && !defined(_GUDEV_INSIDE_GUDEV_H) | ||
22 | #error "Only <gudev/gudev.h> can be included directly, this file may disappear or change contents." | ||
23 | #endif | ||
24 | |||
25 | #ifndef __G_UDEV_PRIVATE_H__ | ||
26 | #define __G_UDEV_PRIVATE_H__ | ||
27 | |||
28 | #include <gudev/gudevtypes.h> | ||
29 | |||
30 | #include <libudev.h> | ||
31 | |||
32 | G_BEGIN_DECLS | ||
33 | |||
34 | GUdevDevice * | ||
35 | _g_udev_device_new (struct udev_device *udevice); | ||
36 | |||
37 | struct udev *_g_udev_client_get_udev (GUdevClient *client); | ||
38 | |||
39 | G_END_DECLS | ||
40 | |||
41 | #endif /* __G_UDEV_PRIVATE_H__ */ | ||
diff --git a/src/udev/src/gudev/gudevtypes.h b/src/udev/src/gudev/gudevtypes.h new file mode 100644 index 000000000..888482783 --- /dev/null +++ b/src/udev/src/gudev/gudevtypes.h | |||
@@ -0,0 +1,51 @@ | |||
1 | /* -*- Mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- | ||
2 | * | ||
3 | * Copyright (C) 2008 David Zeuthen <davidz@redhat.com> | ||
4 | * | ||
5 | * This library is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU Lesser General Public | ||
7 | * License as published by the Free Software Foundation; either | ||
8 | * version 2 of the License, or (at your option) any later version. | ||
9 | * | ||
10 | * This library 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 GNU | ||
13 | * Lesser General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Lesser General Public | ||
16 | * License along with this library; if not, write to the | ||
17 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | * Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | #if !defined (_GUDEV_COMPILATION) && !defined(_GUDEV_INSIDE_GUDEV_H) | ||
22 | #error "Only <gudev/gudev.h> can be included directly, this file may disappear or change contents." | ||
23 | #endif | ||
24 | |||
25 | #ifndef __G_UDEV_TYPES_H__ | ||
26 | #define __G_UDEV_TYPES_H__ | ||
27 | |||
28 | #include <gudev/gudevenums.h> | ||
29 | #include <sys/types.h> | ||
30 | |||
31 | G_BEGIN_DECLS | ||
32 | |||
33 | typedef struct _GUdevClient GUdevClient; | ||
34 | typedef struct _GUdevDevice GUdevDevice; | ||
35 | typedef struct _GUdevEnumerator GUdevEnumerator; | ||
36 | |||
37 | /** | ||
38 | * GUdevDeviceNumber: | ||
39 | * | ||
40 | * Corresponds to the standard #dev_t type as defined by POSIX (Until | ||
41 | * bug 584517 is resolved this work-around is needed). | ||
42 | */ | ||
43 | #ifdef _GUDEV_WORK_AROUND_DEV_T_BUG | ||
44 | typedef guint64 GUdevDeviceNumber; /* __UQUAD_TYPE */ | ||
45 | #else | ||
46 | typedef dev_t GUdevDeviceNumber; | ||
47 | #endif | ||
48 | |||
49 | G_END_DECLS | ||
50 | |||
51 | #endif /* __G_UDEV_TYPES_H__ */ | ||
diff --git a/src/udev/src/gudev/seed-example-enum.js b/src/udev/src/gudev/seed-example-enum.js new file mode 100755 index 000000000..66206ad80 --- /dev/null +++ b/src/udev/src/gudev/seed-example-enum.js | |||
@@ -0,0 +1,38 @@ | |||
1 | #!/usr/bin/env seed | ||
2 | |||
3 | const GLib = imports.gi.GLib; | ||
4 | const GUdev = imports.gi.GUdev; | ||
5 | |||
6 | function print_device(device) { | ||
7 | print(" initialized: " + device.get_is_initialized()); | ||
8 | print(" usec since initialized: " + device.get_usec_since_initialized()); | ||
9 | print(" subsystem: " + device.get_subsystem()); | ||
10 | print(" devtype: " + device.get_devtype()); | ||
11 | print(" name: " + device.get_name()); | ||
12 | print(" number: " + device.get_number()); | ||
13 | print(" sysfs_path: " + device.get_sysfs_path()); | ||
14 | print(" driver: " + device.get_driver()); | ||
15 | print(" action: " + device.get_action()); | ||
16 | print(" seqnum: " + device.get_seqnum()); | ||
17 | print(" device type: " + device.get_device_type()); | ||
18 | print(" device number: " + device.get_device_number()); | ||
19 | print(" device file: " + device.get_device_file()); | ||
20 | print(" device file symlinks: " + device.get_device_file_symlinks()); | ||
21 | print(" tags: " + device.get_tags()); | ||
22 | var keys = device.get_property_keys(); | ||
23 | for (var n = 0; n < keys.length; n++) { | ||
24 | print(" " + keys[n] + "=" + device.get_property(keys[n])); | ||
25 | } | ||
26 | } | ||
27 | |||
28 | var client = new GUdev.Client({subsystems: []}); | ||
29 | var enumerator = new GUdev.Enumerator({client: client}); | ||
30 | enumerator.add_match_subsystem('b*') | ||
31 | |||
32 | var devices = enumerator.execute(); | ||
33 | |||
34 | for (var n=0; n < devices.length; n++) { | ||
35 | var device = devices[n]; | ||
36 | print_device(device); | ||
37 | print(""); | ||
38 | } | ||
diff --git a/src/udev/src/gudev/seed-example.js b/src/udev/src/gudev/seed-example.js new file mode 100755 index 000000000..e2ac324d2 --- /dev/null +++ b/src/udev/src/gudev/seed-example.js | |||
@@ -0,0 +1,72 @@ | |||
1 | #!/usr/bin/env seed | ||
2 | |||
3 | // seed example | ||
4 | |||
5 | const GLib = imports.gi.GLib; | ||
6 | const GUdev = imports.gi.GUdev; | ||
7 | |||
8 | function print_device (device) { | ||
9 | print (" subsystem: " + device.get_subsystem ()); | ||
10 | print (" devtype: " + device.get_devtype ()); | ||
11 | print (" name: " + device.get_name ()); | ||
12 | print (" number: " + device.get_number ()); | ||
13 | print (" sysfs_path: " + device.get_sysfs_path ()); | ||
14 | print (" driver: " + device.get_driver ()); | ||
15 | print (" action: " + device.get_action ()); | ||
16 | print (" seqnum: " + device.get_seqnum ()); | ||
17 | print (" device type: " + device.get_device_type ()); | ||
18 | print (" device number: " + device.get_device_number ()); | ||
19 | print (" device file: " + device.get_device_file ()); | ||
20 | print (" device file symlinks: " + device.get_device_file_symlinks ()); | ||
21 | print (" foo: " + device.get_sysfs_attr_as_strv ("stat")); | ||
22 | var keys = device.get_property_keys (); | ||
23 | for (var n = 0; n < keys.length; n++) { | ||
24 | print (" " + keys[n] + "=" + device.get_property (keys[n])); | ||
25 | } | ||
26 | } | ||
27 | |||
28 | function on_uevent (client, action, device) { | ||
29 | print ("action " + action + " on device " + device.get_sysfs_path()); | ||
30 | print_device (device); | ||
31 | print (""); | ||
32 | } | ||
33 | |||
34 | var client = new GUdev.Client ({subsystems: ["block", "usb/usb_interface"]}); | ||
35 | client.signal.connect ("uevent", on_uevent); | ||
36 | |||
37 | var block_devices = client.query_by_subsystem ("block"); | ||
38 | for (var n = 0; n < block_devices.length; n++) { | ||
39 | print ("block device: " + block_devices[n].get_device_file ()); | ||
40 | } | ||
41 | |||
42 | var d; | ||
43 | |||
44 | d = client.query_by_device_number (GUdev.DeviceType.BLOCK, 0x0810); | ||
45 | if (d == null) { | ||
46 | print ("query_by_device_number 0x810 -> null"); | ||
47 | } else { | ||
48 | print ("query_by_device_number 0x810 -> " + d.get_device_file ()); | ||
49 | dd = d.get_parent_with_subsystem ("usb", null); | ||
50 | print_device (dd); | ||
51 | print ("--------------------------------------------------------------------------"); | ||
52 | while (d != null) { | ||
53 | print_device (d); | ||
54 | print (""); | ||
55 | d = d.get_parent (); | ||
56 | } | ||
57 | } | ||
58 | |||
59 | d = client.query_by_sysfs_path ("/sys/block/sda/sda1"); | ||
60 | print ("query_by_sysfs_path (\"/sys/block/sda1\") -> " + d.get_device_file ()); | ||
61 | |||
62 | d = client.query_by_subsystem_and_name ("block", "sda2"); | ||
63 | print ("query_by_subsystem_and_name (\"block\", \"sda2\") -> " + d.get_device_file ()); | ||
64 | |||
65 | d = client.query_by_device_file ("/dev/sda"); | ||
66 | print ("query_by_device_file (\"/dev/sda\") -> " + d.get_device_file ()); | ||
67 | |||
68 | d = client.query_by_device_file ("/dev/block/8:0"); | ||
69 | print ("query_by_device_file (\"/dev/block/8:0\") -> " + d.get_device_file ()); | ||
70 | |||
71 | var mainloop = GLib.main_loop_new (); | ||
72 | GLib.main_loop_run (mainloop); | ||
diff --git a/src/udev/src/keymap/.gitignore b/src/udev/src/keymap/.gitignore new file mode 100644 index 000000000..4567584f4 --- /dev/null +++ b/src/udev/src/keymap/.gitignore | |||
@@ -0,0 +1,5 @@ | |||
1 | keyboard-force-release.sh | ||
2 | keys-from-name.gperf | ||
3 | keys-from-name.h | ||
4 | keys-to-name.h | ||
5 | keys.txt | ||
diff --git a/src/udev/src/keymap/95-keyboard-force-release.rules b/src/udev/src/keymap/95-keyboard-force-release.rules new file mode 100644 index 000000000..03d56e8aa --- /dev/null +++ b/src/udev/src/keymap/95-keyboard-force-release.rules | |||
@@ -0,0 +1,54 @@ | |||
1 | # Set model specific atkbd force_release quirk | ||
2 | # | ||
3 | # Several laptops have hotkeys which don't generate release events, | ||
4 | # which can cause problems with software key repeat. | ||
5 | # The atkbd driver has a quirk handler for generating synthetic | ||
6 | # release events, which can be configured via sysfs since 2.6.32. | ||
7 | # Simply add a file with a list of scancodes for your laptop model | ||
8 | # in /usr/lib/udev/keymaps, and add a rule here. | ||
9 | # If the hotkeys also need a keymap assignment you can copy the | ||
10 | # scancodes from the keymap file, otherwise you can run | ||
11 | # /usr/lib/udev/keymap -i /dev/input/eventX | ||
12 | # on a Linux vt to find out. | ||
13 | |||
14 | ACTION=="remove", GOTO="force_release_end" | ||
15 | SUBSYSTEM!="serio", GOTO="force_release_end" | ||
16 | KERNEL!="serio*", GOTO="force_release_end" | ||
17 | DRIVER!="atkbd", GOTO="force_release_end" | ||
18 | |||
19 | ENV{DMI_VENDOR}="$attr{[dmi/id]sys_vendor}" | ||
20 | |||
21 | ENV{DMI_VENDOR}=="[sS][aA][mM][sS][uU][nN][gG]*", RUN+="keyboard-force-release.sh $devpath samsung-other" | ||
22 | ENV{DMI_VENDOR}=="[sS][aA][mM][sS][uU][nN][gG]*", ATTR{[dmi/id]product_name}=="*90X3A*", RUN+="keyboard-force-release.sh $devpath samsung-90x3a" | ||
23 | |||
24 | ENV{DMI_VENDOR}=="Dell Inc.", ATTR{[dmi/id]product_name}=="Studio 1557|Studio 1558", RUN+="keyboard-force-release.sh $devpath common-volume-keys" | ||
25 | ENV{DMI_VENDOR}=="Dell Inc.", ATTR{[dmi/id]product_name}=="Latitude E*|Precision M*", RUN+="keyboard-force-release.sh $devpath dell-touchpad" | ||
26 | |||
27 | ENV{DMI_VENDOR}=="FUJITSU SIEMENS", ATTR{[dmi/id]product_name}=="AMILO Si 1848+u|AMILO Xi 2428", RUN+="keyboard-force-release.sh $devpath common-volume-keys" | ||
28 | |||
29 | ENV{DMI_VENDOR}=="FOXCONN", ATTR{[dmi/id]product_name}=="QBOOK", RUN+="keyboard-force-release.sh $devpath common-volume-keys" | ||
30 | |||
31 | ENV{DMI_VENDOR}=="MTC", ATTR{[dmi/id]product_version}=="A0", RUN+="keyboard-force-release.sh $devpath common-volume-keys" | ||
32 | |||
33 | ENV{DMI_VENDOR}=="PEGATRON CORP.", ATTR{[dmi/id]product_name}=="Spring Peak", RUN+="keyboard-force-release.sh $devpath common-volume-keys" | ||
34 | |||
35 | ENV{DMI_VENDOR}=="TOSHIBA", ATTR{[dmi/id]product_name}=="Satellite [uU]300*|Satellite Pro [uU]300*|Satellite [uU]305*|SATELLITE [uU]500*", RUN+="keyboard-force-release.sh $devpath common-volume-keys" | ||
36 | |||
37 | ENV{DMI_VENDOR}=="Viooo Corporation", ATTR{[dmi/id]product_name}=="PT17", RUN+="keyboard-force-release.sh $devpath common-volume-keys" | ||
38 | |||
39 | # These are all the HP laptops that setup a touchpad toggle key | ||
40 | ENV{DMI_VENDOR}=="Hewlett-Packard*", ATTR{[dmi/id]product_name}=="*[pP][aA][vV][iI][lL][iI][oO][nN]*", RUN+="keyboard-force-release.sh $devpath hp-other" | ||
41 | ENV{DMI_VENDOR}=="Hewlett-Packard*", ATTR{[dmi/id]product_name}=="*[tT][xX]2*", RUN+="keyboard-force-release.sh $devpath hp-other" | ||
42 | ENV{DMI_VENDOR}=="Hewlett-Packard*", ATTR{[dmi/id]product_name}=="*2510p*|*2530p*|HP G60 Notebook PC", RUN+="keyboard-force-release.sh $devpath hp-other" | ||
43 | |||
44 | ENV{DMI_VENDOR}=="Zepto", ATTR{[dmi/id]product_name}=="Znote 6615WD", RUN+="keyboard-force-release.sh $devpath common-volume-keys" | ||
45 | |||
46 | ENV{DMI_VENDOR}=="Zepto", ATTR{[dmi/id]product_name}=="Znote", ATTR{[dmi/id]product_version}=="6625WD", RUN+="keyboard-force-release.sh $devpath common-volume-keys" | ||
47 | |||
48 | ENV{DMI_VENDOR}=="HANNspree", ATTR{[dmi/id]product_name}=="SN10E100", RUN+="keyboard-force-release.sh $devpath common-volume-keys" | ||
49 | |||
50 | ENV{DMI_VENDOR}=="GIGABYTE", ATTR{[dmi/id]product_name}=="i1520M", RUN+="keyboard-force-release.sh $devpath common-volume-keys" | ||
51 | |||
52 | ENV{DMI_VENDOR}=="BenQ", ATTR{[dmi/id]product_name}=="*nScreen*", RUN+="keyboard-force-release.sh $devpath common-volume-keys" | ||
53 | |||
54 | LABEL="force_release_end" | ||
diff --git a/src/udev/src/keymap/95-keymap.rules b/src/udev/src/keymap/95-keymap.rules new file mode 100644 index 000000000..bbf311a17 --- /dev/null +++ b/src/udev/src/keymap/95-keymap.rules | |||
@@ -0,0 +1,170 @@ | |||
1 | # Set model specific hotkey keycodes. | ||
2 | # | ||
3 | # Key map overrides can be specified by either giving scancode/keyname pairs | ||
4 | # directly as keymap arguments (if there are just one or two to change), or as | ||
5 | # a file name (in /usr/lib/udev/keymaps), which has to contain scancode/keyname | ||
6 | # pairs. | ||
7 | |||
8 | ACTION=="remove", GOTO="keyboard_end" | ||
9 | KERNEL!="event*", GOTO="keyboard_end" | ||
10 | ENV{ID_INPUT_KEY}=="", GOTO="keyboard_end" | ||
11 | SUBSYSTEMS=="bluetooth", GOTO="keyboard_end" | ||
12 | |||
13 | SUBSYSTEMS=="usb", IMPORT{builtin}="usb_id" | ||
14 | SUBSYSTEMS=="usb", GOTO="keyboard_usbcheck" | ||
15 | GOTO="keyboard_modulecheck" | ||
16 | |||
17 | # | ||
18 | # The following are external USB keyboards | ||
19 | # | ||
20 | |||
21 | LABEL="keyboard_usbcheck" | ||
22 | |||
23 | ENV{ID_VENDOR}=="Genius", ENV{ID_MODEL_ID}=="0708", ENV{ID_USB_INTERFACE_NUM}=="01", RUN+="keymap $name genius-slimstar-320" | ||
24 | ENV{ID_VENDOR}=="Logitech*", ATTRS{name}=="Logitech USB Multimedia Keyboard", RUN+="keymap $name logitech-wave" | ||
25 | ENV{ID_VENDOR}=="Logitech*", ATTRS{name}=="Logitech USB Receiver", RUN+="keymap $name logitech-wave-cordless" | ||
26 | # Logitech Cordless Wave Pro looks slightly weird; some hotkeys are coming through the mouse interface | ||
27 | ENV{ID_VENDOR_ID}=="046d", ENV{ID_MODEL_ID}=="c52[9b]", ATTRS{name}=="Logitech USB Receiver", RUN+="keymap $name logitech-wave-pro-cordless" | ||
28 | |||
29 | ENV{ID_VENDOR}=="Lite-On_Technology_Corp*", ATTRS{name}=="Lite-On Technology Corp. ThinkPad USB Keyboard with TrackPoint", RUN+="keymap $name lenovo-thinkpad-usb-keyboard-trackpoint" | ||
30 | ENV{ID_VENDOR_ID}=="04b3", ENV{ID_MODEL_ID}=="301[89]", RUN+="keymap $name ibm-thinkpad-usb-keyboard-trackpoint" | ||
31 | |||
32 | ENV{ID_VENDOR}=="Microsoft", ENV{ID_MODEL_ID}=="00db", RUN+="keymap $name 0xc022d zoomin 0xc022e zoomout" | ||
33 | |||
34 | GOTO="keyboard_end" | ||
35 | |||
36 | # | ||
37 | # The following are exposed as separate input devices with low key codes, thus | ||
38 | # we need to check their input device product name | ||
39 | # | ||
40 | |||
41 | LABEL="keyboard_modulecheck" | ||
42 | |||
43 | ENV{DMI_VENDOR}="$attr{[dmi/id]sys_vendor}" | ||
44 | ENV{DMI_VENDOR}=="", GOTO="keyboard_end" | ||
45 | |||
46 | ENV{DMI_VENDOR}=="LENOVO*", KERNELS=="input*", ATTRS{name}=="ThinkPad Extra Buttons", RUN+="keymap $name module-lenovo" | ||
47 | ENV{DMI_VENDOR}=="LENOVO*", KERNELS=="input*", ATTRS{name}=="Lenovo ThinkPad SL Series extra buttons", RUN+="keymap $name 0x0E bluetooth" | ||
48 | |||
49 | ENV{DMI_VENDOR}=="ASUS*", KERNELS=="input*", ATTRS{name}=="Asus Extra Buttons", ATTR{[dmi/id]product_name}=="W3J", RUN+="keymap $name module-asus-w3j" | ||
50 | ENV{DMI_VENDOR}=="ASUS*", KERNELS=="input*", ATTRS{name}=="Eee PC WMI hotkeys|Asus Laptop Support|Asus*WMI*", RUN+="keymap $name 0x6B f21" | ||
51 | ENV{DMI_VENDOR}=="ASUS*", KERNELS=="input*", ATTRS{name}=="Eee PC Hotkey Driver", RUN+="keymap $name 0x37 f21" | ||
52 | |||
53 | ENV{DMI_VENDOR}=="IBM*", KERNELS=="input*", ATTRS{name}=="ThinkPad Extra Buttons", RUN+="keymap $name module-ibm" | ||
54 | ENV{DMI_VENDOR}=="Sony*", KERNELS=="input*", ATTRS{name}=="Sony Vaio Keys", RUN+="keymap $name module-sony" | ||
55 | ENV{DMI_VENDOR}=="Acer*", KERNELS=="input*", ATTRS{name}=="Acer WMI hotkeys", RUN+="keymap $name 0x82 f21" | ||
56 | ENV{DMI_VENDOR}=="MICRO-STAR*|Micro-Star*", KERNELS=="input*", ATTRS{name}=="MSI Laptop hotkeys", RUN+="keymap $name 0x213 f22 0x214 f23" | ||
57 | |||
58 | # Older Vaios have some different keys | ||
59 | ENV{DMI_VENDOR}=="Sony*", ATTR{[dmi/id]product_name}=="*PCG-C1*|*PCG-K25*|*PCG-F1*|*PCG-F2*|*PCG-F3*|*PCG-F4*|*PCG-F5*|*PCG-F6*|*PCG-FX*|*PCG-FRV*|*PCG-GR*|*PCG-TR*|*PCG-NV*|*PCG-Z*|*VGN-S360*", ATTRS{name}=="Sony Vaio Keys", RUN+="keymap $name module-sony-old" | ||
60 | |||
61 | # Some Sony VGN models have yet another one | ||
62 | ENV{DMI_VENDOR}=="Sony*", ATTR{[dmi/id]product_name}=="VGN-AR71*|VGN-FW*|VGN-Z21*", ATTRS{name}=="Sony Vaio Keys", RUN+="keymap $name module-sony-vgn" | ||
63 | |||
64 | |||
65 | # | ||
66 | # The following rules belong to standard i8042 AT keyboard with high key codes. | ||
67 | # | ||
68 | |||
69 | DRIVERS=="atkbd", GOTO="keyboard_vendorcheck" | ||
70 | GOTO="keyboard_end" | ||
71 | |||
72 | LABEL="keyboard_vendorcheck" | ||
73 | |||
74 | ENV{DMI_VENDOR}=="Dell*", RUN+="keymap $name dell" | ||
75 | ENV{DMI_VENDOR}=="Dell*", ATTR{[dmi/id]product_name}=="Inspiron 910|Inspiron 1010|Inspiron 1011|Inspiron 1012|Inspiron 1110|Inspiron 1210", RUN+="keymap $name 0x84 wlan" | ||
76 | ENV{DMI_VENDOR}=="Dell*", ATTR{[dmi/id]product_name}=="Latitude XT2", RUN+="keymap $name dell-latitude-xt2" | ||
77 | |||
78 | ENV{DMI_VENDOR}=="Compaq*", ATTR{[dmi/id]product_name}=="*E500*|*Evo N*", RUN+="keymap $name compaq-e_evo" | ||
79 | |||
80 | ENV{DMI_VENDOR}=="LENOVO*", ATTR{[dmi/id]product_version}=="*3000*", RUN+="keymap $name lenovo-3000" | ||
81 | ENV{DMI_VENDOR}=="LENOVO*", ATTR{[dmi/id]product_version}=="ThinkPad X6*", ATTR{[dmi/id]product_version}=="* Tablet", RUN+="keymap $name lenovo-thinkpad_x6_tablet" | ||
82 | ENV{DMI_VENDOR}=="LENOVO*", ATTR{[dmi/id]product_version}=="ThinkPad X2[02]* Tablet*", ATTR{[dmi/id]product_version}=="* Tablet", RUN+="keymap $name lenovo-thinkpad_x200_tablet" | ||
83 | ENV{DMI_VENDOR}=="LENOVO*", ATTR{[dmi/id]product_version}=="*IdeaPad*", RUN+="keymap $name lenovo-ideapad" | ||
84 | ENV{DMI_VENDOR}=="LENOVO*", ATTR{[dmi/id]product_name}=="S10-*", RUN+="keymap $name lenovo-ideapad" | ||
85 | ENV{DMI_VENDOR}=="LENOVO", ATTR{[dmi/id]product_version}=="*IdeaPad Y550*", RUN+="keymap $name 0x95 media 0xA3 play" | ||
86 | |||
87 | ENV{DMI_VENDOR}=="Hewlett-Packard*", RUN+="keymap $name hewlett-packard" | ||
88 | ENV{DMI_VENDOR}=="Hewlett-Packard*", ATTR{[dmi/id]product_name}=="*[tT][aA][bB][lL][eE][tT]*", RUN+="keymap $name hewlett-packard-tablet" | ||
89 | ENV{DMI_VENDOR}=="Hewlett-Packard*", ATTR{[dmi/id]product_name}=="*[pP][aA][vV][iI][lL][iI][oO][nN]*", RUN+="keymap $name hewlett-packard-pavilion" | ||
90 | ENV{DMI_VENDOR}=="Hewlett-Packard*", ATTR{[dmi/id]product_name}=="*Compaq*|*EliteBook*|*2230s*", RUN+="keymap $name hewlett-packard-compaq_elitebook" | ||
91 | ENV{DMI_VENDOR}=="Hewlett-Packard*", ATTR{[dmi/id]product_name}=="*2510p*|*2530p*|HP G60 Notebook PC", RUN+="keymap $name hewlett-packard-2510p_2530p" | ||
92 | ENV{DMI_VENDOR}=="Hewlett-Packard*", ATTR{[dmi/id]product_name}=="*[tT][xX]2*", RUN+="keymap $name hewlett-packard-tx2" | ||
93 | ENV{DMI_VENDOR}=="Hewlett-Packard", ATTR{[dmi/id]product_name}=="Presario 2100*", RUN+="keymap $name hewlett-packard-presario-2100" | ||
94 | ENV{DMI_VENDOR}=="Hewlett-Packard", ATTR{[dmi/id]product_name}=="HP G62 Notebook PC", RUN+="keymap $name 0xB2 www" | ||
95 | ENV{DMI_VENDOR}=="Hewlett-Packard", ATTR{[dmi/id]product_name}=="HP ProBook*", RUN+="keymap $name 0xF8 rfkill" | ||
96 | # HP Pavillion dv6315ea has empty DMI_VENDOR | ||
97 | ATTR{[dmi/id]board_vendor}=="Quanta", ATTR{[dmi/id]board_name}=="30B7", ATTR{[dmi/id]board_version}=="65.2B", RUN+="keymap $name 0x88 media" # "quick play | ||
98 | |||
99 | # Gateway clone of Acer Aspire One AOA110/AOA150 | ||
100 | ENV{DMI_VENDOR}=="Gateway*", ATTR{[dmi/id]product_name}=="*AOA1*", RUN+="keymap $name acer" | ||
101 | |||
102 | ENV{DMI_VENDOR}=="Acer*", RUN+="keymap $name acer" | ||
103 | ENV{DMI_VENDOR}=="Acer*", ATTR{[dmi/id]product_name}=="Extensa*", ATTR{[dmi/id]product_name}=="*5210*|*5220*|*5610*|*5620*|*5720*", RUN+="keymap $name 0xEE screenlock" | ||
104 | ENV{DMI_VENDOR}=="Acer*", ATTR{[dmi/id]product_name}=="TravelMate*C3[01]0*", RUN+="keymap $name acer-travelmate_c300" | ||
105 | ENV{DMI_VENDOR}=="Acer*", ATTR{[dmi/id]product_name}=="TravelMate*6292*|TravelMate*8471*|TravelMate*4720*|TravelMate*7720*|Aspire 1810T*|AO751h|AO531h", RUN+="keymap $name 0xD9 bluetooth" | ||
106 | ENV{DMI_VENDOR}=="Acer*", ATTR{[dmi/id]product_name}=="TravelMate*4720*", RUN+="keymap $name 0xB2 www 0xEE screenlock" | ||
107 | ENV{DMI_VENDOR}=="Acer*", ATTR{[dmi/id]product_name}=="TravelMate 6593|Aspire 1640", RUN+="keymap $name 0xB2 www 0xEE screenlock" | ||
108 | ENV{DMI_VENDOR}=="Acer*", ATTR{[dmi/id]product_name}=="Aspire 6920", RUN+="keymap $name acer-aspire_6920" | ||
109 | ENV{DMI_VENDOR}=="Acer*", ATTR{[dmi/id]product_name}=="Aspire 5920G", RUN+="keymap $name acer-aspire_5920g" | ||
110 | ENV{DMI_VENDOR}=="Acer*", ATTR{[dmi/id]product_name}=="Aspire 5720*", RUN+="keymap $name acer-aspire_5720" | ||
111 | ENV{DMI_VENDOR}=="Acer*", ATTR{[dmi/id]product_name}=="Aspire 8930", RUN+="keymap $name acer-aspire_8930" | ||
112 | ENV{DMI_VENDOR}=="Acer*", ATTR{[dmi/id]product_serial}=="ZG8*", RUN+="keymap $name acer-aspire_5720" | ||
113 | |||
114 | ENV{DMI_VENDOR}=="*BenQ*", ATTR{[dmi/id]product_name}=="*Joybook R22*", RUN+="keymap $name 0x6E wlan" | ||
115 | |||
116 | ENV{DMI_VENDOR}=="FUJITSU*", ATTR{[dmi/id]product_name}=="*AMILO Pro V3205*", RUN+="keymap $name fujitsu-amilo_pro_v3205" | ||
117 | ENV{DMI_VENDOR}=="FUJITSU*", ATTR{[dmi/id]product_name}=="*AMILO Pa 2548*", RUN+="keymap $name fujitsu-amilo_pa_2548" | ||
118 | ENV{DMI_VENDOR}=="FUJITSU*", ATTR{[dmi/id]product_name}=="*ESPRIMO Mobile V5*", RUN+="keymap $name fujitsu-esprimo_mobile_v5" | ||
119 | ENV{DMI_VENDOR}=="FUJITSU*", ATTR{[dmi/id]product_name}=="*ESPRIMO Mobile V6*", RUN+="keymap $name fujitsu-esprimo_mobile_v6" | ||
120 | ENV{DMI_VENDOR}=="FUJITSU*", ATTR{[dmi/id]product_name}=="*AMILO Pro Edition V3505*", RUN+="keymap $name fujitsu-amilo_pro_edition_v3505" | ||
121 | ENV{DMI_VENDOR}=="FUJITSU*", ATTR{[dmi/id]product_name}=="*Amilo Si 1520*", RUN+="keymap $name fujitsu-amilo_si_1520" | ||
122 | ENV{DMI_VENDOR}=="FUJITSU*", ATTR{[dmi/id]product_name}=="AMILO*M*", RUN+="keymap $name 0x97 prog2 0x9F prog1" | ||
123 | ENV{DMI_VENDOR}=="FUJITSU*", ATTR{[dmi/id]product_name}=="Amilo Li 1718", RUN+="keymap $name 0xD6 wlan" | ||
124 | ENV{DMI_VENDOR}=="FUJITSU*", ATTR{[dmi/id]product_name}=="AMILO Li 2732", RUN+="keymap $name fujitsu-amilo_li_2732" | ||
125 | |||
126 | ENV{DMI_VENDOR}=="LG*", ATTR{[dmi/id]product_name}=="*X110*", RUN+="keymap $name lg-x110" | ||
127 | |||
128 | ENV{DMI_VENDOR}=="MEDION*", ATTR{[dmi/id]product_name}=="*FID2060*", RUN+="keymap $name medion-fid2060" | ||
129 | ENV{DMI_VENDOR}=="MEDIONNB", ATTR{[dmi/id]product_name}=="A555*", RUN+="keymap $name medionnb-a555" | ||
130 | |||
131 | ENV{DMI_VENDOR}=="MICRO-STAR*|Micro-Star*", RUN+="keymap $name micro-star" | ||
132 | |||
133 | # some MSI models generate ACPI/input events on the LNXVIDEO input devices, | ||
134 | # plus some extra synthesized ones on atkbd as an echo of actually changing the | ||
135 | # brightness; so ignore those atkbd ones, to avoid loops | ||
136 | ENV{DMI_VENDOR}=="MICRO-STAR*", ATTR{[dmi/id]product_name}=="*U-100*|*U100*|*N033", RUN+="keymap $name 0xF7 reserved 0xF8 reserved" | ||
137 | |||
138 | ENV{DMI_VENDOR}=="INVENTEC", ATTR{[dmi/id]product_name}=="SYMPHONY 6.0/7.0", RUN+="keymap $name inventec-symphony_6.0_7.0" | ||
139 | |||
140 | ENV{DMI_VENDOR}=="MAXDATA", ATTR{[dmi/id]product_name}=="Pro 7000*", RUN+="keymap $name maxdata-pro_7000" | ||
141 | |||
142 | ENV{DMI_VENDOR}=="[sS][aA][mM][sS][uU][nN][gG]*", RUN+="keymap $name samsung-other" | ||
143 | ENV{DMI_VENDOR}=="[sS][aA][mM][sS][uU][nN][gG]*", ATTR{[dmi/id]product_name}=="*SX20S*", RUN+="keymap $name samsung-sx20s" | ||
144 | ENV{DMI_VENDOR}=="[sS][aA][mM][sS][uU][nN][gG]*", ATTR{[dmi/id]product_name}=="SQ1US", RUN+="keymap $name samsung-sq1us" | ||
145 | ENV{DMI_VENDOR}=="[sS][aA][mM][sS][uU][nN][gG]*", ATTR{[dmi/id]product_name}=="*700Z*", RUN+="keymap $name 0xBA ejectcd 0x96 keyboardbrightnessup 0x97 keyboardbrightnessdown" | ||
146 | ENV{DMI_VENDOR}=="[sS][aA][mM][sS][uU][nN][gG]*", ATTR{[dmi/id]product_name}=="*90X3A*", RUN+="keymap $name samsung-90x3a" | ||
147 | |||
148 | ENV{DMI_VENDOR}=="TOSHIBA", ATTR{[dmi/id]product_name}=="SATELLITE A100", RUN+="keymap $name toshiba-satellite_a100" | ||
149 | ENV{DMI_VENDOR}=="TOSHIBA", ATTR{[dmi/id]product_name}=="Satellite A110", RUN+="keymap $name toshiba-satellite_a110" | ||
150 | ENV{DMI_VENDOR}=="TOSHIBA", ATTR{[dmi/id]product_name}=="Satellite M30X", RUN+="keymap $name toshiba-satellite_m30x" | ||
151 | |||
152 | ENV{DMI_VENDOR}=="OQO Inc.*", ATTR{[dmi/id]product_name}=="OQO Model 2*", RUN+="keymap $name oqo-model2" | ||
153 | |||
154 | ENV{DMI_VENDOR}=="ONKYO CORPORATION", ATTR{[dmi/id]product_name}=="ONKYOPC", RUN+="keymap $name onkyo" | ||
155 | |||
156 | ENV{DMI_VENDOR}=="ASUS", RUN+="keymap $name asus" | ||
157 | |||
158 | ENV{DMI_VENDOR}=="VIA", ATTR{[dmi/id]product_name}=="K8N800", ATTR{[dmi/id]product_version}=="VT8204B", RUN+="keymap $name 0x81 prog1" | ||
159 | |||
160 | ENV{DMI_VENDOR}=="Zepto", ATTR{[dmi/id]product_name}=="Znote", ATTR{[dmi/id]product_version}=="62*|63*", RUN+="keymap $name zepto-znote" | ||
161 | |||
162 | ENV{DMI_VENDOR}=="Everex", ATTR{[dmi/id]product_name}=="XT5000*", RUN+="keymap $name everex-xt5000" | ||
163 | |||
164 | ENV{DMI_VENDOR}=="COMPAL", ATTR{[dmi/id]product_name}=="HEL80I", RUN+="keymap $name 0x84 wlan" | ||
165 | |||
166 | ENV{DMI_VENDOR}=="OLPC", ATTR{[dmi/id]product_name}=="XO", RUN+="keymap $name olpc-xo" | ||
167 | |||
168 | ENV{DMI_VENDOR}=="Alienware*", ATTR{[dmi/id]product_name}=="M14xR1", RUN+="keymap $name 0x8A ejectcd" | ||
169 | |||
170 | LABEL="keyboard_end" | ||
diff --git a/src/udev/src/keymap/README.keymap.txt b/src/udev/src/keymap/README.keymap.txt new file mode 100644 index 000000000..52d50ed2d --- /dev/null +++ b/src/udev/src/keymap/README.keymap.txt | |||
@@ -0,0 +1,101 @@ | |||
1 | = The udev keymap tool = | ||
2 | |||
3 | == Introduction == | ||
4 | |||
5 | This udev extension configures computer model specific key mappings. This is | ||
6 | particularly necessary for the non-standard extra keys found on many laptops, | ||
7 | such as "brightness up", "next song", "www browser", or "suspend". Often these | ||
8 | are accessed with the Fn key. | ||
9 | |||
10 | Every key produces a "scan code", which is highly vendor/model specific for the | ||
11 | nonstandard keys. This tool maintains mappings for these scan codes to standard | ||
12 | "key codes", which denote the "meaning" of the key. The key codes are defined | ||
13 | in /usr/include/linux/input.h. | ||
14 | |||
15 | If some of your keys on your keyboard are not working at all, or produce the | ||
16 | wrong effect, then a very likely cause of this is that the scan code -> key | ||
17 | code mapping is incorrect on your computer. | ||
18 | |||
19 | == Structure == | ||
20 | |||
21 | udev-keymap consists of the following parts: | ||
22 | |||
23 | keymaps/*:: mappings of scan codes to key code names | ||
24 | |||
25 | 95-keymap.rules:: udev rules for mapping system vendor/product names and | ||
26 | input module names to one of the keymaps above | ||
27 | |||
28 | keymap:: manipulate an evdev input device: | ||
29 | * write a key map file into a device (used by udev rules) | ||
30 | * dump current scan → key code mapping | ||
31 | * interactively display scan and key codes of pressed keys | ||
32 | |||
33 | findkeyboards:: display evdev input devices which belong to actual keyboards, | ||
34 | i. e. those suitable for the keymap program | ||
35 | |||
36 | fdi2rules.py:: convert hal keymap FDIs into udev rules and key map files | ||
37 | (Please note that this is far from perfect, since the mapping between fdi and | ||
38 | udev rules is not straightforward, and impossible in some cases.) | ||
39 | |||
40 | == Fixing broken keys == | ||
41 | |||
42 | In order to make a broken key work on your system and send it back to upstream | ||
43 | for inclusion you need to do the following steps: | ||
44 | |||
45 | 1. Find the keyboard device. | ||
46 | |||
47 | Run /usr/lib/udev/findkeyboards. This should always give you an "AT | ||
48 | keyboard" and possibly a "module". Some laptops (notably Thinkpads, Sonys, and | ||
49 | Acers) have multimedia/function keys on a separate input device instead of the | ||
50 | primary keyboard. The keyboard device should have a name like "input/event3". | ||
51 | In the following commands, the name will be written as "input/eventX" (replace | ||
52 | X with the appropriate number). | ||
53 | |||
54 | 2. Find broken scan codes: | ||
55 | |||
56 | sudo /usr/lib/udev/keymap -i input/eventX | ||
57 | |||
58 | Press all multimedia/function keys and check if the key name that gets printed | ||
59 | out is plausible. If it is unknown or wrong, write down the scan code (looks | ||
60 | like "0x1E") and the intended functionality of this key. Look in | ||
61 | /usr/include/linux/input.h for an available KEY_XXXXX constant which most | ||
62 | closely approximates this functionality and write it down as the new key code. | ||
63 | |||
64 | For example, you might press a key labeled "web browser" which currently | ||
65 | produces "unknown". Note down this: | ||
66 | |||
67 | 0x1E www # Fn+F2 web browser | ||
68 | |||
69 | Repeat that for all other keys. Write the resulting list into a file. Look at | ||
70 | /usr/lib/udev/keymaps/ for existing key map files and make sure that you use the | ||
71 | same structure. | ||
72 | |||
73 | If the key only ever works once and then your keyboard (or the entire desktop) | ||
74 | gets stuck for a long time, then it is likely that the BIOS fails to send a | ||
75 | corresponding "key release" event after the key press event. Please note down | ||
76 | this case as well, as it can be worked around in | ||
77 | /usr/lib/udev/keymaps/95-keyboard-force-release.rules . | ||
78 | |||
79 | 3. Find out your system vendor and product: | ||
80 | |||
81 | cat /sys/class/dmi/id/sys_vendor | ||
82 | cat /sys/class/dmi/id/product_name | ||
83 | |||
84 | 4. Generate a device dump with "udevadm info --export-db > /tmp/udev-db.txt". | ||
85 | |||
86 | 6. Send the system vendor/product names, the key mapping from step 2, | ||
87 | and /tmp/udev-db.txt from step 4 to the linux-hotplug@vger.kernel.org mailing | ||
88 | list, so that they can be included in the next release. | ||
89 | |||
90 | For local testing, copy your map file to /usr/lib/udev/keymaps/ with an appropriate | ||
91 | name, and add an appropriate udev rule to /usr/lib/udev/rules.d/95-keymap.rules: | ||
92 | |||
93 | * If you selected an "AT keyboard", add the rule to the section after | ||
94 | 'LABEL="keyboard_vendorcheck"'. | ||
95 | |||
96 | * If you selected a "module", add the rule to the top section where the | ||
97 | "ThinkPad Extra Buttons" are. | ||
98 | |||
99 | == Author == | ||
100 | |||
101 | keymap is written and maintained by Martin Pitt <martin.pitt@ubuntu.com>. | ||
diff --git a/src/udev/src/keymap/check-keymaps.sh b/src/udev/src/keymap/check-keymaps.sh new file mode 100755 index 000000000..405168c66 --- /dev/null +++ b/src/udev/src/keymap/check-keymaps.sh | |||
@@ -0,0 +1,38 @@ | |||
1 | #!/bin/bash | ||
2 | |||
3 | # check that all key names in keymaps/* are known in <linux/input.h> | ||
4 | # and that all key maps listed in the rules are valid and present in | ||
5 | # Makefile.am | ||
6 | SRCDIR=${1:-.} | ||
7 | KEYLIST=${2:-src/keymap/keys.txt} | ||
8 | KEYMAPS_DIR=$SRCDIR/src/keymap/keymaps | ||
9 | RULES=$SRCDIR/src/keymap/95-keymap.rules | ||
10 | |||
11 | [ -e "$KEYLIST" ] || { | ||
12 | echo "need $KEYLIST please build first" >&2 | ||
13 | exit 1 | ||
14 | } | ||
15 | |||
16 | missing=$(join -v 2 <(awk '{print tolower(substr($1,5))}' $KEYLIST | sort -u) \ | ||
17 | <(grep -hv '^#' ${KEYMAPS_DIR}/*| awk '{print $2}' | sort -u)) | ||
18 | [ -z "$missing" ] || { | ||
19 | echo "ERROR: unknown key names in src/keymap/keymaps/*:" >&2 | ||
20 | echo "$missing" >&2 | ||
21 | exit 1 | ||
22 | } | ||
23 | |||
24 | # check that all maps referred to in $RULES exist | ||
25 | maps=$(sed -rn '/keymap \$name/ { s/^.*\$name ([^"[:space:]]+).*$/\1/; p }' $RULES) | ||
26 | for m in $maps; do | ||
27 | # ignore inline mappings | ||
28 | [ "$m" = "${m#0x}" ] || continue | ||
29 | |||
30 | [ -e ${KEYMAPS_DIR}/$m ] || { | ||
31 | echo "ERROR: unknown map name in $RULES: $m" >&2 | ||
32 | exit 1 | ||
33 | } | ||
34 | grep -q "src/keymap/keymaps/$m\>" $SRCDIR/Makefile.am || { | ||
35 | echo "ERROR: map file $m is not added to Makefile.am" >&2 | ||
36 | exit 1 | ||
37 | } | ||
38 | done | ||
diff --git a/src/udev/src/keymap/findkeyboards b/src/udev/src/keymap/findkeyboards new file mode 100755 index 000000000..9ce27429b --- /dev/null +++ b/src/udev/src/keymap/findkeyboards | |||
@@ -0,0 +1,68 @@ | |||
1 | #!/bin/sh -e | ||
2 | # Find "real" keyboard devices and print their device path. | ||
3 | # Author: Martin Pitt <martin.pitt@ubuntu.com> | ||
4 | # | ||
5 | # Copyright (C) 2009, Canonical Ltd. | ||
6 | # | ||
7 | # This program is free software; you can redistribute it and/or modify it | ||
8 | # 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, 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 | # returns OK if $1 contains $2 | ||
18 | strstr() { | ||
19 | [ "${1#*$2*}" != "$1" ] | ||
20 | } | ||
21 | |||
22 | # returns OK if $1 contains $2 at the beginning | ||
23 | str_starts() { | ||
24 | [ "${1#$2*}" != "$1" ] | ||
25 | } | ||
26 | |||
27 | str_line_starts() { | ||
28 | while read a; do str_starts "$a" "$1" && return 0;done | ||
29 | return 1; | ||
30 | } | ||
31 | |||
32 | # print a list of input devices which are keyboard-like | ||
33 | keyboard_devices() { | ||
34 | # standard AT keyboard | ||
35 | for dev in `udevadm trigger --dry-run --verbose --property-match=ID_INPUT_KEYBOARD=1`; do | ||
36 | walk=`udevadm info --attribute-walk --path=$dev` | ||
37 | env=`udevadm info --query=env --path=$dev` | ||
38 | # filter out non-event devices, such as the parent input devices which have no devnode | ||
39 | if ! echo "$env" | str_line_starts 'DEVNAME='; then | ||
40 | continue | ||
41 | fi | ||
42 | if strstr "$walk" 'DRIVERS=="atkbd"'; then | ||
43 | echo -n 'AT keyboard: ' | ||
44 | elif echo "$env" | str_line_starts 'ID_USB_DRIVER=usbhid'; then | ||
45 | echo -n 'USB keyboard: ' | ||
46 | else | ||
47 | echo -n 'Unknown type: ' | ||
48 | fi | ||
49 | udevadm info --query=name --path=$dev | ||
50 | done | ||
51 | |||
52 | # modules | ||
53 | module=$(udevadm trigger --verbose --dry-run --subsystem-match=input --attr-match=name='*Extra Buttons') | ||
54 | module="$module | ||
55 | $(udevadm trigger --verbose --dry-run --subsystem-match=input --attr-match=name='*extra buttons')" | ||
56 | module="$module | ||
57 | $(udevadm trigger --verbose --dry-run --subsystem-match=input --attr-match=name='Sony Vaio Keys')" | ||
58 | for m in $module; do | ||
59 | for evdev in $m/event*/dev; do | ||
60 | if [ -e "$evdev" ]; then | ||
61 | echo -n 'module: ' | ||
62 | udevadm info --query=name --path=${evdev%%/dev} | ||
63 | fi | ||
64 | done | ||
65 | done | ||
66 | } | ||
67 | |||
68 | keyboard_devices | ||
diff --git a/src/udev/src/keymap/force-release-maps/common-volume-keys b/src/udev/src/keymap/force-release-maps/common-volume-keys new file mode 100644 index 000000000..3a7654d73 --- /dev/null +++ b/src/udev/src/keymap/force-release-maps/common-volume-keys | |||
@@ -0,0 +1,3 @@ | |||
1 | 0xa0 #mute | ||
2 | 0xae #volume down | ||
3 | 0xb0 #volume up | ||
diff --git a/src/udev/src/keymap/force-release-maps/dell-touchpad b/src/udev/src/keymap/force-release-maps/dell-touchpad new file mode 100644 index 000000000..18e9bdee6 --- /dev/null +++ b/src/udev/src/keymap/force-release-maps/dell-touchpad | |||
@@ -0,0 +1 @@ | |||
0x9E | |||
diff --git a/src/udev/src/keymap/force-release-maps/hp-other b/src/udev/src/keymap/force-release-maps/hp-other new file mode 100644 index 000000000..662137009 --- /dev/null +++ b/src/udev/src/keymap/force-release-maps/hp-other | |||
@@ -0,0 +1,3 @@ | |||
1 | # list of scancodes (hex or decimal), optional comment | ||
2 | 0xd8 # Touchpad off | ||
3 | 0xd9 # Touchpad on | ||
diff --git a/src/udev/src/keymap/force-release-maps/samsung-90x3a b/src/udev/src/keymap/force-release-maps/samsung-90x3a new file mode 100644 index 000000000..65707effb --- /dev/null +++ b/src/udev/src/keymap/force-release-maps/samsung-90x3a | |||
@@ -0,0 +1,6 @@ | |||
1 | # list of scancodes (hex or decimal), optional comment | ||
2 | 0xCE # Fn+F8 keyboard backlit up | ||
3 | 0x8D # Fn+F7 keyboard backlit down | ||
4 | 0x97 # Fn+F12 wifi on/off | ||
5 | 0x96 # Fn+F1 performance mode (?) | ||
6 | 0xD5 # Fn+F6 battery life extender | ||
diff --git a/src/udev/src/keymap/force-release-maps/samsung-other b/src/udev/src/keymap/force-release-maps/samsung-other new file mode 100644 index 000000000..c51123a0b --- /dev/null +++ b/src/udev/src/keymap/force-release-maps/samsung-other | |||
@@ -0,0 +1,10 @@ | |||
1 | # list of scancodes (hex or decimal), optional comment | ||
2 | 0x82 # Fn+F4 CRT/LCD | ||
3 | 0x83 # Fn+F2 battery | ||
4 | 0x84 # Fn+F5 backlight on/off | ||
5 | 0x86 # Fn+F9 WLAN | ||
6 | 0x88 # Fn-Up brightness up | ||
7 | 0x89 # Fn-Down brightness down | ||
8 | 0xB3 # Fn+F8 switch power mode (battery/dynamic/performance) | ||
9 | 0xF7 # Fn+F10 Touchpad on | ||
10 | 0xF9 # Fn+F10 Touchpad off | ||
diff --git a/src/udev/src/keymap/keyboard-force-release.sh.in b/src/udev/src/keymap/keyboard-force-release.sh.in new file mode 100755 index 000000000..dd040cebc --- /dev/null +++ b/src/udev/src/keymap/keyboard-force-release.sh.in | |||
@@ -0,0 +1,22 @@ | |||
1 | #!@rootprefix@/bin/sh -e | ||
2 | # read list of scancodes, convert hex to decimal and | ||
3 | # append to the atkbd force_release sysfs attribute | ||
4 | # $1 sysfs devpath for serioX | ||
5 | # $2 file with scancode list (hex or dec) | ||
6 | |||
7 | case "$2" in | ||
8 | /*) scf="$2" ;; | ||
9 | *) scf="@pkglibexecdir@/keymaps/force-release/$2" ;; | ||
10 | esac | ||
11 | |||
12 | read attr <"/sys/$1/force_release" | ||
13 | while read scancode dummy; do | ||
14 | case "$scancode" in | ||
15 | \#*) ;; | ||
16 | *) | ||
17 | scancode=$(($scancode)) | ||
18 | attr="$attr${attr:+,}$scancode" | ||
19 | ;; | ||
20 | esac | ||
21 | done <"$scf" | ||
22 | echo "$attr" >"/sys/$1/force_release" | ||
diff --git a/src/udev/src/keymap/keymap.c b/src/udev/src/keymap/keymap.c new file mode 100644 index 000000000..92ec67b3a --- /dev/null +++ b/src/udev/src/keymap/keymap.c | |||
@@ -0,0 +1,447 @@ | |||
1 | /* | ||
2 | * keymap - dump keymap of an evdev device or set a new keymap from a file | ||
3 | * | ||
4 | * Based on keyfuzz by Lennart Poettering <mzqrovna@0pointer.net> | ||
5 | * Adapted for udev-extras by Martin Pitt <martin.pitt@ubuntu.com> | ||
6 | * | ||
7 | * Copyright (C) 2006, Lennart Poettering | ||
8 | * Copyright (C) 2009, Canonical Ltd. | ||
9 | * | ||
10 | * keymap is free software; you can redistribute it and/or modify it | ||
11 | * under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * keymap is distributed in the hope that it will be useful, but | ||
16 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
18 | * General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with keymap; if not, write to the Free Software Foundation, | ||
22 | * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. | ||
23 | */ | ||
24 | |||
25 | #include <stdio.h> | ||
26 | #include <stdlib.h> | ||
27 | #include <string.h> | ||
28 | #include <stdint.h> | ||
29 | #include <ctype.h> | ||
30 | #include <unistd.h> | ||
31 | #include <errno.h> | ||
32 | #include <limits.h> | ||
33 | #include <fcntl.h> | ||
34 | #include <getopt.h> | ||
35 | #include <sys/ioctl.h> | ||
36 | #include <linux/limits.h> | ||
37 | #include <linux/input.h> | ||
38 | |||
39 | const struct key* lookup_key (const char *str, unsigned int len); | ||
40 | |||
41 | #include "keys-from-name.h" | ||
42 | #include "keys-to-name.h" | ||
43 | |||
44 | #define MAX_SCANCODES 1024 | ||
45 | |||
46 | static int evdev_open(const char *dev) | ||
47 | { | ||
48 | int fd; | ||
49 | char fn[PATH_MAX]; | ||
50 | |||
51 | if (strncmp(dev, "/dev", 4) != 0) { | ||
52 | snprintf(fn, sizeof(fn), "/dev/%s", dev); | ||
53 | dev = fn; | ||
54 | } | ||
55 | |||
56 | if ((fd = open(dev, O_RDWR)) < 0) { | ||
57 | fprintf(stderr, "error open('%s'): %m\n", dev); | ||
58 | return -1; | ||
59 | } | ||
60 | return fd; | ||
61 | } | ||
62 | |||
63 | static int evdev_get_keycode(int fd, int scancode, int e) | ||
64 | { | ||
65 | int codes[2]; | ||
66 | |||
67 | codes[0] = scancode; | ||
68 | if (ioctl(fd, EVIOCGKEYCODE, codes) < 0) { | ||
69 | if (e && errno == EINVAL) { | ||
70 | return -2; | ||
71 | } else { | ||
72 | fprintf(stderr, "EVIOCGKEYCODE: %m\n"); | ||
73 | return -1; | ||
74 | } | ||
75 | } | ||
76 | return codes[1]; | ||
77 | } | ||
78 | |||
79 | static int evdev_set_keycode(int fd, int scancode, int keycode) | ||
80 | { | ||
81 | int codes[2]; | ||
82 | |||
83 | codes[0] = scancode; | ||
84 | codes[1] = keycode; | ||
85 | |||
86 | if (ioctl(fd, EVIOCSKEYCODE, codes) < 0) { | ||
87 | fprintf(stderr, "EVIOCSKEYCODE: %m\n"); | ||
88 | return -1; | ||
89 | } | ||
90 | return 0; | ||
91 | } | ||
92 | |||
93 | static int evdev_driver_version(int fd, char *v, size_t l) | ||
94 | { | ||
95 | int version; | ||
96 | |||
97 | if (ioctl(fd, EVIOCGVERSION, &version)) { | ||
98 | fprintf(stderr, "EVIOCGVERSION: %m\n"); | ||
99 | return -1; | ||
100 | } | ||
101 | |||
102 | snprintf(v, l, "%i.%i.%i.", version >> 16, (version >> 8) & 0xff, version & 0xff); | ||
103 | return 0; | ||
104 | } | ||
105 | |||
106 | static int evdev_device_name(int fd, char *n, size_t l) | ||
107 | { | ||
108 | if (ioctl(fd, EVIOCGNAME(l), n) < 0) { | ||
109 | fprintf(stderr, "EVIOCGNAME: %m\n"); | ||
110 | return -1; | ||
111 | } | ||
112 | return 0; | ||
113 | } | ||
114 | |||
115 | /* Return a lower-case string with KEY_ prefix removed */ | ||
116 | static const char* format_keyname(const char* key) { | ||
117 | static char result[101]; | ||
118 | const char* s; | ||
119 | int len; | ||
120 | |||
121 | for (s = key+4, len = 0; *s && len < 100; ++len, ++s) | ||
122 | result[len] = tolower(*s); | ||
123 | result[len] = '\0'; | ||
124 | return result; | ||
125 | } | ||
126 | |||
127 | static int dump_table(int fd) { | ||
128 | char version[256], name[256]; | ||
129 | int scancode, r = -1; | ||
130 | |||
131 | if (evdev_driver_version(fd, version, sizeof(version)) < 0) | ||
132 | goto fail; | ||
133 | |||
134 | if (evdev_device_name(fd, name, sizeof(name)) < 0) | ||
135 | goto fail; | ||
136 | |||
137 | printf("### evdev %s, driver '%s'\n", version, name); | ||
138 | |||
139 | r = 0; | ||
140 | for (scancode = 0; scancode < MAX_SCANCODES; scancode++) { | ||
141 | int keycode; | ||
142 | |||
143 | if ((keycode = evdev_get_keycode(fd, scancode, 1)) < 0) { | ||
144 | if (keycode == -2) | ||
145 | continue; | ||
146 | r = -1; | ||
147 | break; | ||
148 | } | ||
149 | |||
150 | if (keycode < KEY_MAX && key_names[keycode]) | ||
151 | printf("0x%03x %s\n", scancode, format_keyname(key_names[keycode])); | ||
152 | else | ||
153 | printf("0x%03x 0x%03x\n", scancode, keycode); | ||
154 | } | ||
155 | fail: | ||
156 | return r; | ||
157 | } | ||
158 | |||
159 | static void set_key(int fd, const char* scancode_str, const char* keyname) | ||
160 | { | ||
161 | unsigned scancode; | ||
162 | char *endptr; | ||
163 | char t[105] = "KEY_UNKNOWN"; | ||
164 | const struct key *k; | ||
165 | |||
166 | scancode = (unsigned) strtol(scancode_str, &endptr, 0); | ||
167 | if (*endptr != '\0') { | ||
168 | fprintf(stderr, "ERROR: Invalid scancode\n"); | ||
169 | exit(1); | ||
170 | } | ||
171 | |||
172 | snprintf(t, sizeof(t), "KEY_%s", keyname); | ||
173 | |||
174 | if (!(k = lookup_key(t, strlen(t)))) { | ||
175 | fprintf(stderr, "ERROR: Unknown key name '%s'\n", keyname); | ||
176 | exit(1); | ||
177 | } | ||
178 | |||
179 | if (evdev_set_keycode(fd, scancode, k->id) < 0) | ||
180 | fprintf(stderr, "setting scancode 0x%2X to key code %i failed\n", | ||
181 | scancode, k->id); | ||
182 | else | ||
183 | printf("setting scancode 0x%2X to key code %i\n", | ||
184 | scancode, k->id); | ||
185 | } | ||
186 | |||
187 | static int merge_table(int fd, FILE *f) { | ||
188 | int r = 0; | ||
189 | int line = 0; | ||
190 | |||
191 | while (!feof(f)) { | ||
192 | char s[256], *p; | ||
193 | int scancode, new_keycode, old_keycode; | ||
194 | |||
195 | if (!fgets(s, sizeof(s), f)) | ||
196 | break; | ||
197 | |||
198 | line++; | ||
199 | p = s+strspn(s, "\t "); | ||
200 | if (*p == '#' || *p == '\n') | ||
201 | continue; | ||
202 | |||
203 | if (sscanf(p, "%i %i", &scancode, &new_keycode) != 2) { | ||
204 | char t[105] = "KEY_UNKNOWN"; | ||
205 | const struct key *k; | ||
206 | |||
207 | if (sscanf(p, "%i %100s", &scancode, t+4) != 2) { | ||
208 | fprintf(stderr, "WARNING: Parse failure at line %i, ignoring.\n", line); | ||
209 | r = -1; | ||
210 | continue; | ||
211 | } | ||
212 | |||
213 | if (!(k = lookup_key(t, strlen(t)))) { | ||
214 | fprintf(stderr, "WARNING: Unknown key '%s' at line %i, ignoring.\n", t, line); | ||
215 | r = -1; | ||
216 | continue; | ||
217 | } | ||
218 | |||
219 | new_keycode = k->id; | ||
220 | } | ||
221 | |||
222 | |||
223 | if ((old_keycode = evdev_get_keycode(fd, scancode, 0)) < 0) { | ||
224 | r = -1; | ||
225 | goto fail; | ||
226 | } | ||
227 | |||
228 | if (evdev_set_keycode(fd, scancode, new_keycode) < 0) { | ||
229 | r = -1; | ||
230 | goto fail; | ||
231 | } | ||
232 | |||
233 | if (new_keycode != old_keycode) | ||
234 | fprintf(stderr, "Remapped scancode 0x%02x to 0x%02x (prior: 0x%02x)\n", | ||
235 | scancode, new_keycode, old_keycode); | ||
236 | } | ||
237 | fail: | ||
238 | fclose(f); | ||
239 | return r; | ||
240 | } | ||
241 | |||
242 | |||
243 | /* read one event; return 1 if valid */ | ||
244 | static int read_event(int fd, struct input_event* ev) | ||
245 | { | ||
246 | int ret; | ||
247 | ret = read(fd, ev, sizeof(struct input_event)); | ||
248 | |||
249 | if (ret < 0) { | ||
250 | perror("read"); | ||
251 | return 0; | ||
252 | } | ||
253 | if (ret != sizeof(struct input_event)) { | ||
254 | fprintf(stderr, "did not get enough data for event struct, aborting\n"); | ||
255 | return 0; | ||
256 | } | ||
257 | |||
258 | return 1; | ||
259 | } | ||
260 | |||
261 | static void print_key(uint32_t scancode, uint16_t keycode, int has_scan, int has_key) | ||
262 | { | ||
263 | const char *keyname; | ||
264 | |||
265 | /* ignore key release events */ | ||
266 | if (has_key == 1) | ||
267 | return; | ||
268 | |||
269 | if (has_key == 0 && has_scan != 0) { | ||
270 | fprintf(stderr, "got scan code event 0x%02X without a key code event\n", | ||
271 | scancode); | ||
272 | return; | ||
273 | } | ||
274 | |||
275 | if (has_scan != 0) | ||
276 | printf("scan code: 0x%02X ", scancode); | ||
277 | else | ||
278 | printf("(no scan code received) "); | ||
279 | |||
280 | keyname = key_names[keycode]; | ||
281 | if (keyname != NULL) | ||
282 | printf("key code: %s\n", format_keyname(keyname)); | ||
283 | else | ||
284 | printf("key code: %03X\n", keycode); | ||
285 | } | ||
286 | |||
287 | static void interactive(int fd) | ||
288 | { | ||
289 | struct input_event ev; | ||
290 | uint32_t last_scan = 0; | ||
291 | uint16_t last_key = 0; | ||
292 | int has_scan; /* boolean */ | ||
293 | int has_key; /* 0: none, 1: release, 2: press */ | ||
294 | |||
295 | /* grab input device */ | ||
296 | ioctl(fd, EVIOCGRAB, 1); | ||
297 | puts("Press ESC to finish, or Control-C if this device is not your primary keyboard"); | ||
298 | |||
299 | has_scan = has_key = 0; | ||
300 | while (read_event(fd, &ev)) { | ||
301 | /* Drivers usually send the scan code first, then the key code, | ||
302 | * then a SYN. Some drivers (like thinkpad_acpi) send the key | ||
303 | * code first, and some drivers might not send SYN events, so | ||
304 | * keep a robust state machine which can deal with any of those | ||
305 | */ | ||
306 | |||
307 | if (ev.type == EV_MSC && ev.code == MSC_SCAN) { | ||
308 | if (has_scan) { | ||
309 | fputs("driver did not send SYN event in between key events; previous event:\n", | ||
310 | stderr); | ||
311 | print_key(last_scan, last_key, has_scan, has_key); | ||
312 | has_key = 0; | ||
313 | } | ||
314 | |||
315 | last_scan = ev.value; | ||
316 | has_scan = 1; | ||
317 | /*printf("--- got scan %u; has scan %i key %i\n", last_scan, has_scan, has_key); */ | ||
318 | } | ||
319 | else if (ev.type == EV_KEY) { | ||
320 | if (has_key) { | ||
321 | fputs("driver did not send SYN event in between key events; previous event:\n", | ||
322 | stderr); | ||
323 | print_key(last_scan, last_key, has_scan, has_key); | ||
324 | has_scan = 0; | ||
325 | } | ||
326 | |||
327 | last_key = ev.code; | ||
328 | has_key = 1 + ev.value; | ||
329 | /*printf("--- got key %hu; has scan %i key %i\n", last_key, has_scan, has_key);*/ | ||
330 | |||
331 | /* Stop on ESC */ | ||
332 | if (ev.code == KEY_ESC && ev.value == 0) | ||
333 | break; | ||
334 | } | ||
335 | else if (ev.type == EV_SYN) { | ||
336 | /*printf("--- got SYN; has scan %i key %i\n", has_scan, has_key);*/ | ||
337 | print_key(last_scan, last_key, has_scan, has_key); | ||
338 | |||
339 | has_scan = has_key = 0; | ||
340 | } | ||
341 | |||
342 | } | ||
343 | |||
344 | /* release input device */ | ||
345 | ioctl(fd, EVIOCGRAB, 0); | ||
346 | } | ||
347 | |||
348 | static void help(int error) | ||
349 | { | ||
350 | const char* h = "Usage: keymap <event device> [<map file>]\n" | ||
351 | " keymap <event device> scancode keyname [...]\n" | ||
352 | " keymap -i <event device>\n"; | ||
353 | if (error) { | ||
354 | fputs(h, stderr); | ||
355 | exit(2); | ||
356 | } else { | ||
357 | fputs(h, stdout); | ||
358 | exit(0); | ||
359 | } | ||
360 | } | ||
361 | |||
362 | int main(int argc, char **argv) | ||
363 | { | ||
364 | static const struct option options[] = { | ||
365 | { "help", no_argument, NULL, 'h' }, | ||
366 | { "interactive", no_argument, NULL, 'i' }, | ||
367 | {} | ||
368 | }; | ||
369 | int fd = -1; | ||
370 | int opt_interactive = 0; | ||
371 | int i; | ||
372 | |||
373 | while (1) { | ||
374 | int option; | ||
375 | |||
376 | option = getopt_long(argc, argv, "hi", options, NULL); | ||
377 | if (option == -1) | ||
378 | break; | ||
379 | |||
380 | switch (option) { | ||
381 | case 'h': | ||
382 | help(0); | ||
383 | |||
384 | case 'i': | ||
385 | opt_interactive = 1; | ||
386 | break; | ||
387 | default: | ||
388 | return 1; | ||
389 | } | ||
390 | } | ||
391 | |||
392 | if (argc < optind+1) | ||
393 | help (1); | ||
394 | |||
395 | if ((fd = evdev_open(argv[optind])) < 0) | ||
396 | return 3; | ||
397 | |||
398 | /* one argument (device): dump or interactive */ | ||
399 | if (argc == optind+1) { | ||
400 | if (opt_interactive) | ||
401 | interactive(fd); | ||
402 | else | ||
403 | dump_table(fd); | ||
404 | return 0; | ||
405 | } | ||
406 | |||
407 | /* two arguments (device, mapfile): set map file */ | ||
408 | if (argc == optind+2) { | ||
409 | const char *filearg = argv[optind+1]; | ||
410 | if (strchr(filearg, '/')) { | ||
411 | /* Keymap file argument is a path */ | ||
412 | FILE *f = fopen(filearg, "r"); | ||
413 | if (f) | ||
414 | merge_table(fd, f); | ||
415 | else | ||
416 | perror(filearg); | ||
417 | } else { | ||
418 | /* Keymap file argument is a filename */ | ||
419 | /* Open override file if present, otherwise default file */ | ||
420 | char keymap_path[PATH_MAX]; | ||
421 | snprintf(keymap_path, sizeof(keymap_path), "%s%s", SYSCONFDIR "/udev/keymaps/", filearg); | ||
422 | FILE *f = fopen(keymap_path, "r"); | ||
423 | if (f) { | ||
424 | merge_table(fd, f); | ||
425 | } else { | ||
426 | snprintf(keymap_path, sizeof(keymap_path), "%s%s", PKGLIBEXECDIR "/keymaps/", filearg); | ||
427 | f = fopen(keymap_path, "r"); | ||
428 | if (f) | ||
429 | merge_table(fd, f); | ||
430 | else | ||
431 | perror(keymap_path); | ||
432 | } | ||
433 | } | ||
434 | return 0; | ||
435 | } | ||
436 | |||
437 | /* more arguments (device, scancode/keyname pairs): set keys directly */ | ||
438 | if ((argc - optind - 1) % 2 == 0) { | ||
439 | for (i = optind+1; i < argc; i += 2) | ||
440 | set_key(fd, argv[i], argv[i+1]); | ||
441 | return 0; | ||
442 | } | ||
443 | |||
444 | /* invalid number of arguments */ | ||
445 | help(1); | ||
446 | return 1; /* not reached */ | ||
447 | } | ||
diff --git a/src/udev/src/keymap/keymaps/acer b/src/udev/src/keymap/keymaps/acer new file mode 100644 index 000000000..4e7c297de --- /dev/null +++ b/src/udev/src/keymap/keymaps/acer | |||
@@ -0,0 +1,22 @@ | |||
1 | 0xA5 help # Fn+F1 | ||
2 | 0xA6 setup # Fn+F2 Acer eSettings | ||
3 | 0xA7 battery # Fn+F3 Power Management | ||
4 | 0xA9 switchvideomode # Fn+F5 | ||
5 | 0xB3 euro | ||
6 | 0xB4 dollar | ||
7 | 0xCE brightnessup # Fn+Right | ||
8 | 0xD4 bluetooth # (toggle) off-to-on | ||
9 | 0xD5 wlan # (toggle) on-to-off | ||
10 | 0xD6 wlan # (toggle) off-to-on | ||
11 | 0xD7 bluetooth # (toggle) on-to-off | ||
12 | 0xD8 bluetooth # (toggle) off-to-on | ||
13 | 0xD9 brightnessup # Fn+Right | ||
14 | 0xEE brightnessup # Fn+Right | ||
15 | 0xEF brightnessdown # Fn+Left | ||
16 | 0xF1 f22 # Fn+F7 Touchpad toggle (off-to-on) | ||
17 | 0xF2 f23 # Fn+F7 Touchpad toggle (on-to-off) | ||
18 | 0xF3 prog2 # "P2" programmable button | ||
19 | 0xF4 prog1 # "P1" programmable button | ||
20 | 0xF5 presentation | ||
21 | 0xF8 fn | ||
22 | 0xF9 f23 # Launch NTI shadow | ||
diff --git a/src/udev/src/keymap/keymaps/acer-aspire_5720 b/src/udev/src/keymap/keymaps/acer-aspire_5720 new file mode 100644 index 000000000..1496d63a5 --- /dev/null +++ b/src/udev/src/keymap/keymaps/acer-aspire_5720 | |||
@@ -0,0 +1,4 @@ | |||
1 | 0x84 bluetooth # sent when bluetooth module missing, and key pressed | ||
2 | 0x92 media # acer arcade | ||
3 | 0xD4 bluetooth # bluetooth on | ||
4 | 0xD9 bluetooth # bluetooth off | ||
diff --git a/src/udev/src/keymap/keymaps/acer-aspire_5920g b/src/udev/src/keymap/keymaps/acer-aspire_5920g new file mode 100644 index 000000000..633c4e854 --- /dev/null +++ b/src/udev/src/keymap/keymaps/acer-aspire_5920g | |||
@@ -0,0 +1,5 @@ | |||
1 | 0x8A media | ||
2 | 0x92 media | ||
3 | 0xA6 setup | ||
4 | 0xB2 www | ||
5 | 0xD9 bluetooth # (toggle) on-to-off | ||
diff --git a/src/udev/src/keymap/keymaps/acer-aspire_6920 b/src/udev/src/keymap/keymaps/acer-aspire_6920 new file mode 100644 index 000000000..699c954b4 --- /dev/null +++ b/src/udev/src/keymap/keymaps/acer-aspire_6920 | |||
@@ -0,0 +1,5 @@ | |||
1 | 0xD9 bluetooth # (toggle) on-to-off | ||
2 | 0x92 media | ||
3 | 0x9E back | ||
4 | 0x83 rewind | ||
5 | 0x89 fastforward | ||
diff --git a/src/udev/src/keymap/keymaps/acer-aspire_8930 b/src/udev/src/keymap/keymaps/acer-aspire_8930 new file mode 100644 index 000000000..fb27bfb4f --- /dev/null +++ b/src/udev/src/keymap/keymaps/acer-aspire_8930 | |||
@@ -0,0 +1,5 @@ | |||
1 | 0xCA prog3 # key 'HOLD' on cine dash media console | ||
2 | 0x83 rewind | ||
3 | 0x89 fastforward | ||
4 | 0x92 media # key 'ARCADE' on cine dash media console | ||
5 | 0x9E back | ||
diff --git a/src/udev/src/keymap/keymaps/acer-travelmate_c300 b/src/udev/src/keymap/keymaps/acer-travelmate_c300 new file mode 100644 index 000000000..bfef4cf86 --- /dev/null +++ b/src/udev/src/keymap/keymaps/acer-travelmate_c300 | |||
@@ -0,0 +1,5 @@ | |||
1 | 0x67 f24 # FIXME: rotate screen | ||
2 | 0x68 up | ||
3 | 0x69 down | ||
4 | 0x6B fn | ||
5 | 0x6C screenlock # FIXME: lock tablet device/buttons | ||
diff --git a/src/udev/src/keymap/keymaps/asus b/src/udev/src/keymap/keymaps/asus new file mode 100644 index 000000000..2a5995f98 --- /dev/null +++ b/src/udev/src/keymap/keymaps/asus | |||
@@ -0,0 +1,3 @@ | |||
1 | 0xED volumeup | ||
2 | 0xEE volumedown | ||
3 | 0xEF mute | ||
diff --git a/src/udev/src/keymap/keymaps/compaq-e_evo b/src/udev/src/keymap/keymaps/compaq-e_evo new file mode 100644 index 000000000..5fbc573aa --- /dev/null +++ b/src/udev/src/keymap/keymaps/compaq-e_evo | |||
@@ -0,0 +1,4 @@ | |||
1 | 0xA3 www # I key | ||
2 | 0x9A search | ||
3 | 0x9E email | ||
4 | 0x9F homepage | ||
diff --git a/src/udev/src/keymap/keymaps/dell b/src/udev/src/keymap/keymaps/dell new file mode 100644 index 000000000..4f907b3ee --- /dev/null +++ b/src/udev/src/keymap/keymaps/dell | |||
@@ -0,0 +1,29 @@ | |||
1 | 0x81 playpause # Play/Pause | ||
2 | 0x82 stopcd # Stop | ||
3 | 0x83 previoussong # Previous song | ||
4 | 0x84 nextsong # Next song | ||
5 | 0x85 brightnessdown # Fn+Down arrow Brightness Down | ||
6 | 0x86 brightnessup # Fn+Up arrow Brightness Up | ||
7 | 0x87 battery # Fn+F3 battery icon | ||
8 | 0x88 unknown # Fn+F2 Turn On/Off Wireless - handled in hardware | ||
9 | 0x89 ejectclosecd # Fn+F10 Eject CD | ||
10 | 0x8A suspend # Fn+F1 hibernate | ||
11 | 0x8B switchvideomode # Fn+F8 CRT/LCD (high keycode: "displaytoggle") | ||
12 | 0x8C f23 # Fn+Right arrow Auto Brightness | ||
13 | 0x8F switchvideomode # Fn+F7 aspect ratio | ||
14 | 0x90 previoussong # Front panel previous song | ||
15 | 0x91 prog1 # Wifi Catcher (DELL Specific) | ||
16 | 0x92 media # MediaDirect button (house icon) | ||
17 | 0x93 f23 # FIXME Fn+Left arrow Auto Brightness | ||
18 | 0x95 camera # Shutter button Takes a picture if optional camera available | ||
19 | 0x97 email # Tablet email button | ||
20 | 0x98 f21 # FIXME: Tablet screen rotatation | ||
21 | 0x99 nextsong # Front panel next song | ||
22 | 0x9A setup # Tablet tools button | ||
23 | 0x9B switchvideomode # Display Toggle button | ||
24 | 0x9E f21 #touchpad toggle | ||
25 | 0xA2 playpause # Front panel play/pause | ||
26 | 0xA4 stopcd # Front panel stop | ||
27 | 0xED media # MediaDirect button | ||
28 | 0xD8 screenlock # FIXME: Tablet lock button | ||
29 | 0xD9 f21 # touchpad toggle | ||
diff --git a/src/udev/src/keymap/keymaps/dell-latitude-xt2 b/src/udev/src/keymap/keymaps/dell-latitude-xt2 new file mode 100644 index 000000000..39872f559 --- /dev/null +++ b/src/udev/src/keymap/keymaps/dell-latitude-xt2 | |||
@@ -0,0 +1,4 @@ | |||
1 | 0x9B up # tablet rocker up | ||
2 | 0x9E enter # tablet rocker press | ||
3 | 0x9F back # tablet back | ||
4 | 0xA3 down # tablet rocker down | ||
diff --git a/src/udev/src/keymap/keymaps/everex-xt5000 b/src/udev/src/keymap/keymaps/everex-xt5000 new file mode 100644 index 000000000..4823a832f --- /dev/null +++ b/src/udev/src/keymap/keymaps/everex-xt5000 | |||
@@ -0,0 +1,7 @@ | |||
1 | 0x5C media | ||
2 | 0x65 f21 # Fn+F5 Touchpad toggle | ||
3 | 0x67 prog3 # Fan Speed Control button | ||
4 | 0x6F brightnessup | ||
5 | 0x7F brightnessdown | ||
6 | 0xB2 www | ||
7 | 0xEC mail | ||
diff --git a/src/udev/src/keymap/keymaps/fujitsu-amilo_li_2732 b/src/udev/src/keymap/keymaps/fujitsu-amilo_li_2732 new file mode 100644 index 000000000..9b8b36a17 --- /dev/null +++ b/src/udev/src/keymap/keymaps/fujitsu-amilo_li_2732 | |||
@@ -0,0 +1,3 @@ | |||
1 | 0xD9 brightnessdown # Fn+F8 brightness down | ||
2 | 0xEF brightnessup # Fn+F9 brightness up | ||
3 | 0xA9 switchvideomode # Fn+F10 Cycle between available video outputs | ||
diff --git a/src/udev/src/keymap/keymaps/fujitsu-amilo_pa_2548 b/src/udev/src/keymap/keymaps/fujitsu-amilo_pa_2548 new file mode 100644 index 000000000..f7b0c5244 --- /dev/null +++ b/src/udev/src/keymap/keymaps/fujitsu-amilo_pa_2548 | |||
@@ -0,0 +1,3 @@ | |||
1 | 0xE0 volumedown | ||
2 | 0xE1 volumeup | ||
3 | 0xE5 prog1 | ||
diff --git a/src/udev/src/keymap/keymaps/fujitsu-amilo_pro_edition_v3505 b/src/udev/src/keymap/keymaps/fujitsu-amilo_pro_edition_v3505 new file mode 100644 index 000000000..d2e38cbb2 --- /dev/null +++ b/src/udev/src/keymap/keymaps/fujitsu-amilo_pro_edition_v3505 | |||
@@ -0,0 +1,4 @@ | |||
1 | 0xA5 help # Fn-F1 | ||
2 | 0xA9 switchvideomode # Fn-F3 | ||
3 | 0xD9 brightnessdown # Fn-F8 | ||
4 | 0xE0 brightnessup # Fn-F9 | ||
diff --git a/src/udev/src/keymap/keymaps/fujitsu-amilo_pro_v3205 b/src/udev/src/keymap/keymaps/fujitsu-amilo_pro_v3205 new file mode 100644 index 000000000..43e3199d5 --- /dev/null +++ b/src/udev/src/keymap/keymaps/fujitsu-amilo_pro_v3205 | |||
@@ -0,0 +1,2 @@ | |||
1 | 0xF4 f21 # FIXME: silent-mode decrease CPU/GPU clock | ||
2 | 0xF7 switchvideomode # Fn+F3 | ||
diff --git a/src/udev/src/keymap/keymaps/fujitsu-amilo_si_1520 b/src/udev/src/keymap/keymaps/fujitsu-amilo_si_1520 new file mode 100644 index 000000000..1419bd9b5 --- /dev/null +++ b/src/udev/src/keymap/keymaps/fujitsu-amilo_si_1520 | |||
@@ -0,0 +1,6 @@ | |||
1 | 0xE1 wlan | ||
2 | 0xF3 wlan | ||
3 | 0xEE brightnessdown | ||
4 | 0xE0 brightnessup | ||
5 | 0xE2 bluetooth | ||
6 | 0xF7 video | ||
diff --git a/src/udev/src/keymap/keymaps/fujitsu-esprimo_mobile_v5 b/src/udev/src/keymap/keymaps/fujitsu-esprimo_mobile_v5 new file mode 100644 index 000000000..d3d056b36 --- /dev/null +++ b/src/udev/src/keymap/keymaps/fujitsu-esprimo_mobile_v5 | |||
@@ -0,0 +1,4 @@ | |||
1 | 0xA9 switchvideomode | ||
2 | 0xD9 brightnessdown | ||
3 | 0xDF sleep | ||
4 | 0xEF brightnessup | ||
diff --git a/src/udev/src/keymap/keymaps/fujitsu-esprimo_mobile_v6 b/src/udev/src/keymap/keymaps/fujitsu-esprimo_mobile_v6 new file mode 100644 index 000000000..52c70c50c --- /dev/null +++ b/src/udev/src/keymap/keymaps/fujitsu-esprimo_mobile_v6 | |||
@@ -0,0 +1,2 @@ | |||
1 | 0xCE brightnessup | ||
2 | 0xEF brightnessdown | ||
diff --git a/src/udev/src/keymap/keymaps/genius-slimstar-320 b/src/udev/src/keymap/keymaps/genius-slimstar-320 new file mode 100644 index 000000000..d0a3656dd --- /dev/null +++ b/src/udev/src/keymap/keymaps/genius-slimstar-320 | |||
@@ -0,0 +1,35 @@ | |||
1 | # Genius SlimStar 320 | ||
2 | # | ||
3 | # Only buttons which are not properly mapped yet are configured below | ||
4 | |||
5 | # "Scroll wheel", a circular up/down/left/right button. Aimed for scolling, | ||
6 | # but since there are no scrollleft/scrollright, let's map to back/forward. | ||
7 | 0x900f0 scrollup | ||
8 | 0x900f1 scrolldown | ||
9 | 0x900f3 back | ||
10 | 0x900f2 forward | ||
11 | |||
12 | # Multimedia buttons, left side (from left to right) | ||
13 | # [W] | ||
14 | 0x900f5 wordprocessor | ||
15 | # [Ex] | ||
16 | 0x900f6 spreadsheet | ||
17 | # [P] | ||
18 | 0x900f4 presentation | ||
19 | # Other five (calculator, playpause, stop, mute and eject) are OK | ||
20 | |||
21 | # Right side, from left to right | ||
22 | # [e] | ||
23 | 0xc0223 www | ||
24 | # "man" | ||
25 | 0x900f7 chat | ||
26 | # "Y" | ||
27 | 0x900fb prog1 | ||
28 | # [X] | ||
29 | 0x900f8 close | ||
30 | # "picture" | ||
31 | 0x900f9 graphicseditor | ||
32 | # "two windows" | ||
33 | 0x900fd scale | ||
34 | # "lock" | ||
35 | 0x900fc screenlock | ||
diff --git a/src/udev/src/keymap/keymaps/hewlett-packard b/src/udev/src/keymap/keymaps/hewlett-packard new file mode 100644 index 000000000..4461fa2ce --- /dev/null +++ b/src/udev/src/keymap/keymaps/hewlett-packard | |||
@@ -0,0 +1,12 @@ | |||
1 | 0x81 fn_esc | ||
2 | 0x89 battery # FnF8 | ||
3 | 0x8A screenlock # FnF6 | ||
4 | 0x8B camera | ||
5 | 0x8C media # music | ||
6 | 0x8E dvd | ||
7 | 0xB1 help | ||
8 | 0xB3 f23 # FIXME: Auto brightness | ||
9 | 0xD7 wlan | ||
10 | 0x92 brightnessdown # FnF7 (FnF9 on 6730b) | ||
11 | 0x97 brightnessup # FnF8 (FnF10 on 6730b) | ||
12 | 0xEE switchvideomode # FnF4 | ||
diff --git a/src/udev/src/keymap/keymaps/hewlett-packard-2510p_2530p b/src/udev/src/keymap/keymaps/hewlett-packard-2510p_2530p new file mode 100644 index 000000000..41ad2e9b5 --- /dev/null +++ b/src/udev/src/keymap/keymaps/hewlett-packard-2510p_2530p | |||
@@ -0,0 +1,2 @@ | |||
1 | 0xD8 f23 # touchpad off | ||
2 | 0xD9 f22 # touchpad on | ||
diff --git a/src/udev/src/keymap/keymaps/hewlett-packard-compaq_elitebook b/src/udev/src/keymap/keymaps/hewlett-packard-compaq_elitebook new file mode 100644 index 000000000..42007c548 --- /dev/null +++ b/src/udev/src/keymap/keymaps/hewlett-packard-compaq_elitebook | |||
@@ -0,0 +1,2 @@ | |||
1 | 0x88 presentation | ||
2 | 0xD9 help # I key (high keycode: "info") | ||
diff --git a/src/udev/src/keymap/keymaps/hewlett-packard-pavilion b/src/udev/src/keymap/keymaps/hewlett-packard-pavilion new file mode 100644 index 000000000..3d3cefc8e --- /dev/null +++ b/src/udev/src/keymap/keymaps/hewlett-packard-pavilion | |||
@@ -0,0 +1,3 @@ | |||
1 | 0x88 media # FIXME: quick play | ||
2 | 0xD8 f23 # touchpad off | ||
3 | 0xD9 f22 # touchpad on | ||
diff --git a/src/udev/src/keymap/keymaps/hewlett-packard-presario-2100 b/src/udev/src/keymap/keymaps/hewlett-packard-presario-2100 new file mode 100644 index 000000000..1df39dcbd --- /dev/null +++ b/src/udev/src/keymap/keymaps/hewlett-packard-presario-2100 | |||
@@ -0,0 +1,3 @@ | |||
1 | 0xF0 help | ||
2 | 0xF1 screenlock | ||
3 | 0xF3 search | ||
diff --git a/src/udev/src/keymap/keymaps/hewlett-packard-tablet b/src/udev/src/keymap/keymaps/hewlett-packard-tablet new file mode 100644 index 000000000..d19005ab9 --- /dev/null +++ b/src/udev/src/keymap/keymaps/hewlett-packard-tablet | |||
@@ -0,0 +1,6 @@ | |||
1 | 0x82 prog2 # Funny Key | ||
2 | 0x83 prog1 # Q | ||
3 | 0x84 tab | ||
4 | 0x85 esc | ||
5 | 0x86 pageup | ||
6 | 0x87 pagedown | ||
diff --git a/src/udev/src/keymap/keymaps/hewlett-packard-tx2 b/src/udev/src/keymap/keymaps/hewlett-packard-tx2 new file mode 100644 index 000000000..36a690fcf --- /dev/null +++ b/src/udev/src/keymap/keymaps/hewlett-packard-tx2 | |||
@@ -0,0 +1,3 @@ | |||
1 | 0xC2 media | ||
2 | 0xD8 f23 # Toggle touchpad button on tx2 (OFF) | ||
3 | 0xD9 f22 # Toggle touchpad button on tx2 (ON) | ||
diff --git a/src/udev/src/keymap/keymaps/ibm-thinkpad-usb-keyboard-trackpoint b/src/udev/src/keymap/keymaps/ibm-thinkpad-usb-keyboard-trackpoint new file mode 100644 index 000000000..027e50bf8 --- /dev/null +++ b/src/udev/src/keymap/keymaps/ibm-thinkpad-usb-keyboard-trackpoint | |||
@@ -0,0 +1,7 @@ | |||
1 | 0x900f0 screenlock | ||
2 | 0x900f1 wlan | ||
3 | 0x900f2 switchvideomode | ||
4 | 0x900f3 suspend | ||
5 | 0x900f4 brightnessup | ||
6 | 0x900f5 brightnessdown | ||
7 | 0x900f8 zoom | ||
diff --git a/src/udev/src/keymap/keymaps/inventec-symphony_6.0_7.0 b/src/udev/src/keymap/keymaps/inventec-symphony_6.0_7.0 new file mode 100644 index 000000000..4a8b4ba5a --- /dev/null +++ b/src/udev/src/keymap/keymaps/inventec-symphony_6.0_7.0 | |||
@@ -0,0 +1,2 @@ | |||
1 | 0xF3 prog2 | ||
2 | 0xF4 prog1 | ||
diff --git a/src/udev/src/keymap/keymaps/lenovo-3000 b/src/udev/src/keymap/keymaps/lenovo-3000 new file mode 100644 index 000000000..5bd165654 --- /dev/null +++ b/src/udev/src/keymap/keymaps/lenovo-3000 | |||
@@ -0,0 +1,5 @@ | |||
1 | 0x8B switchvideomode # Fn+F7 video | ||
2 | 0x96 wlan # Fn+F5 wireless | ||
3 | 0x97 sleep # Fn+F4 suspend | ||
4 | 0x98 suspend # Fn+F12 hibernate | ||
5 | 0xB4 prog1 # Lenovo Care | ||
diff --git a/src/udev/src/keymap/keymaps/lenovo-ideapad b/src/udev/src/keymap/keymaps/lenovo-ideapad new file mode 100644 index 000000000..fc339839f --- /dev/null +++ b/src/udev/src/keymap/keymaps/lenovo-ideapad | |||
@@ -0,0 +1,8 @@ | |||
1 | # Key codes observed on S10-3, assumed valid on other IdeaPad models | ||
2 | 0x81 rfkill # does nothing in BIOS | ||
3 | 0x83 display_off # BIOS toggles screen state | ||
4 | 0xB9 brightnessup # does nothing in BIOS | ||
5 | 0xBA brightnessdown # does nothing in BIOS | ||
6 | 0xF1 camera # BIOS toggles camera power | ||
7 | 0xf2 f21 # touchpad toggle (key alternately emits f2 and f3) | ||
8 | 0xf3 f21 | ||
diff --git a/src/udev/src/keymap/keymaps/lenovo-thinkpad-usb-keyboard-trackpoint b/src/udev/src/keymap/keymaps/lenovo-thinkpad-usb-keyboard-trackpoint new file mode 100644 index 000000000..47e8846a6 --- /dev/null +++ b/src/udev/src/keymap/keymaps/lenovo-thinkpad-usb-keyboard-trackpoint | |||
@@ -0,0 +1,13 @@ | |||
1 | 0x90012 screenlock # Fn+F2 | ||
2 | 0x90013 battery # Fn+F3 | ||
3 | 0x90014 wlan # Fn+F5 | ||
4 | 0x90016 switchvideomode # Fn+F7 | ||
5 | 0x90017 f21 # Fn+F8 touchpadtoggle | ||
6 | 0x90019 suspend # Fn+F12 | ||
7 | 0x9001A brightnessup # Fn+Home | ||
8 | 0x9001B brightnessdown # Fn+End | ||
9 | 0x9001D zoom # Fn+Space | ||
10 | 0x90011 prog1 # Thinkvantage button | ||
11 | |||
12 | 0x90015 camera # Fn+F6 headset/camera VoIP key ?? | ||
13 | 0x90010 micmute # Microphone mute button | ||
diff --git a/src/udev/src/keymap/keymaps/lenovo-thinkpad_x200_tablet b/src/udev/src/keymap/keymaps/lenovo-thinkpad_x200_tablet new file mode 100644 index 000000000..31ea3b2c7 --- /dev/null +++ b/src/udev/src/keymap/keymaps/lenovo-thinkpad_x200_tablet | |||
@@ -0,0 +1,6 @@ | |||
1 | 0x5D menu | ||
2 | 0x63 fn | ||
3 | 0x66 screenlock | ||
4 | 0x67 cyclewindows # bezel circular arrow | ||
5 | 0x68 setup # bezel setup / menu | ||
6 | 0x6c direction # rotate screen | ||
diff --git a/src/udev/src/keymap/keymaps/lenovo-thinkpad_x6_tablet b/src/udev/src/keymap/keymaps/lenovo-thinkpad_x6_tablet new file mode 100644 index 000000000..6fd16b566 --- /dev/null +++ b/src/udev/src/keymap/keymaps/lenovo-thinkpad_x6_tablet | |||
@@ -0,0 +1,8 @@ | |||
1 | 0x6C f21 # rotate | ||
2 | 0x68 screenlock # screenlock | ||
3 | 0x6B esc # escape | ||
4 | 0x6D right # right on d-pad | ||
5 | 0x6E left # left on d-pad | ||
6 | 0x71 up # up on d-pad | ||
7 | 0x6F down # down on d-pad | ||
8 | 0x69 enter # enter on d-pad | ||
diff --git a/src/udev/src/keymap/keymaps/lg-x110 b/src/udev/src/keymap/keymaps/lg-x110 new file mode 100644 index 000000000..ba08cba3f --- /dev/null +++ b/src/udev/src/keymap/keymaps/lg-x110 | |||
@@ -0,0 +1,12 @@ | |||
1 | 0xA0 mute # Fn-F9 | ||
2 | 0xAE volumedown # Fn-Left | ||
3 | 0xAF search # Fn-F3 | ||
4 | 0xB0 volumeup # Fn-Right | ||
5 | 0xB1 battery # Fn-F10 Info | ||
6 | 0xB3 suspend # Fn-F12 | ||
7 | 0xDF sleep # Fn-F4 | ||
8 | # 0xE2 bluetooth # satellite dish2 | ||
9 | 0xE4 f21 # Fn-F5 Touchpad disable | ||
10 | 0xF6 wlan # Fn-F6 | ||
11 | 0xF7 reserved # brightnessdown # Fn-Down | ||
12 | 0xF8 reserved # brightnessup # Fn-Up | ||
diff --git a/src/udev/src/keymap/keymaps/logitech-wave b/src/udev/src/keymap/keymaps/logitech-wave new file mode 100644 index 000000000..caa5d5d31 --- /dev/null +++ b/src/udev/src/keymap/keymaps/logitech-wave | |||
@@ -0,0 +1,16 @@ | |||
1 | 0x9001C scale #expo | ||
2 | 0x9001F zoomout #zoom out | ||
3 | 0x90020 zoomin #zoom in | ||
4 | 0x9003D prog1 #gadget | ||
5 | 0x90005 camera #camera | ||
6 | 0x90018 media #media center | ||
7 | 0x90041 wordprocessor #fn+f1 (word) | ||
8 | 0x90042 spreadsheet #fn+f2 (excel) | ||
9 | 0x90043 calendar #fn+f3 (calendar) | ||
10 | 0x90044 prog2 #fn+f4 (program a) | ||
11 | 0x90045 prog3 #fn+f5 (program b) | ||
12 | 0x90046 prog4 #fn+f6 (program c) | ||
13 | 0x90048 messenger #fn+f8 (msn messenger) | ||
14 | 0x9002D find #fn+f10 (search www) | ||
15 | 0x9004B search #fn+f11 (search pc) | ||
16 | 0x9004C ejectclosecd #fn+f12 (eject) | ||
diff --git a/src/udev/src/keymap/keymaps/logitech-wave-cordless b/src/udev/src/keymap/keymaps/logitech-wave-cordless new file mode 100644 index 000000000..a10dad5e4 --- /dev/null +++ b/src/udev/src/keymap/keymaps/logitech-wave-cordless | |||
@@ -0,0 +1,15 @@ | |||
1 | 0xD4 zoomin | ||
2 | 0xCC zoomout | ||
3 | 0xC0183 media | ||
4 | 0xC1005 camera | ||
5 | 0xC101F zoomout | ||
6 | 0xC1020 zoomin | ||
7 | 0xC1041 wordprocessor | ||
8 | 0xC1042 spreadsheet | ||
9 | 0xC1043 calendar | ||
10 | 0xC1044 prog2 #fn+f4 (program a) | ||
11 | 0xC1045 prog3 #fn+f5 (program b) | ||
12 | 0xC1046 prog4 #fn+f6 (program c) | ||
13 | 0xC1048 messenger | ||
14 | 0xC104A find #fn+f10 (search www) | ||
15 | 0xC104C ejectclosecd | ||
diff --git a/src/udev/src/keymap/keymaps/logitech-wave-pro-cordless b/src/udev/src/keymap/keymaps/logitech-wave-pro-cordless new file mode 100644 index 000000000..e7aa02206 --- /dev/null +++ b/src/udev/src/keymap/keymaps/logitech-wave-pro-cordless | |||
@@ -0,0 +1,12 @@ | |||
1 | 0xC01B6 camera | ||
2 | 0xC0183 media | ||
3 | 0xC0184 wordprocessor | ||
4 | 0xC0186 spreadsheet | ||
5 | 0xC018E calendar | ||
6 | 0xC0223 homepage | ||
7 | 0xC01BC messenger | ||
8 | 0xC018A mail | ||
9 | 0xC0221 search | ||
10 | 0xC00B8 ejectcd | ||
11 | 0xC022D zoomin | ||
12 | 0xC022E zoomout | ||
diff --git a/src/udev/src/keymap/keymaps/maxdata-pro_7000 b/src/udev/src/keymap/keymaps/maxdata-pro_7000 new file mode 100644 index 000000000..c0e4f77af --- /dev/null +++ b/src/udev/src/keymap/keymaps/maxdata-pro_7000 | |||
@@ -0,0 +1,9 @@ | |||
1 | 0x97 prog2 | ||
2 | 0x9F prog1 | ||
3 | 0xA0 mute # Fn-F5 | ||
4 | 0x82 www | ||
5 | 0xEC email | ||
6 | 0xAE volumedown # Fn-Down | ||
7 | 0xB0 volumeup # Fn-Up | ||
8 | 0xDF suspend # Fn+F2 | ||
9 | 0xF5 help | ||
diff --git a/src/udev/src/keymap/keymaps/medion-fid2060 b/src/udev/src/keymap/keymaps/medion-fid2060 new file mode 100644 index 000000000..5a76c7679 --- /dev/null +++ b/src/udev/src/keymap/keymaps/medion-fid2060 | |||
@@ -0,0 +1,2 @@ | |||
1 | 0x6B channeldown # Thottle Down | ||
2 | 0x6D channelup # Thottle Up | ||
diff --git a/src/udev/src/keymap/keymaps/medionnb-a555 b/src/udev/src/keymap/keymaps/medionnb-a555 new file mode 100644 index 000000000..c3b5dfa60 --- /dev/null +++ b/src/udev/src/keymap/keymaps/medionnb-a555 | |||
@@ -0,0 +1,4 @@ | |||
1 | 0x63 www # N button | ||
2 | 0x66 prog1 # link 1 button | ||
3 | 0x67 email # envelope button | ||
4 | 0x69 prog2 # link 2 button | ||
diff --git a/src/udev/src/keymap/keymaps/micro-star b/src/udev/src/keymap/keymaps/micro-star new file mode 100644 index 000000000..4a438698e --- /dev/null +++ b/src/udev/src/keymap/keymaps/micro-star | |||
@@ -0,0 +1,13 @@ | |||
1 | 0xA0 mute # Fn-F9 | ||
2 | 0xAE volumedown # Fn-F7 | ||
3 | 0xB0 volumeup # Fn-F8 | ||
4 | 0xB2 www # e button | ||
5 | 0xDF sleep # Fn-F12 | ||
6 | 0xE2 bluetooth # satellite dish2 | ||
7 | 0xE4 f21 # Fn-F3 Touchpad disable | ||
8 | 0xEC email # envelope button | ||
9 | 0xEE camera # Fn-F6 camera disable | ||
10 | 0xF6 wlan # satellite dish1 | ||
11 | 0xF7 brightnessdown # Fn-F4 | ||
12 | 0xF8 brightnessup # Fn-F5 | ||
13 | 0xF9 search | ||
diff --git a/src/udev/src/keymap/keymaps/module-asus-w3j b/src/udev/src/keymap/keymaps/module-asus-w3j new file mode 100644 index 000000000..773e0b3e8 --- /dev/null +++ b/src/udev/src/keymap/keymaps/module-asus-w3j | |||
@@ -0,0 +1,11 @@ | |||
1 | 0x41 nextsong | ||
2 | 0x45 playpause | ||
3 | 0x43 stopcd | ||
4 | 0x40 previoussong | ||
5 | 0x4C ejectclosecd | ||
6 | 0x32 mute | ||
7 | 0x31 volumedown | ||
8 | 0x30 volumeup | ||
9 | 0x5D wlan | ||
10 | 0x7E bluetooth | ||
11 | 0x8A media # high keycode: "tv" | ||
diff --git a/src/udev/src/keymap/keymaps/module-ibm b/src/udev/src/keymap/keymaps/module-ibm new file mode 100644 index 000000000..a92dfa250 --- /dev/null +++ b/src/udev/src/keymap/keymaps/module-ibm | |||
@@ -0,0 +1,16 @@ | |||
1 | 0x01 battery # Fn+F2 | ||
2 | 0x02 screenlock # Fn+F3 | ||
3 | 0x03 sleep # Fn+F4 | ||
4 | 0x04 wlan # Fn+F5 | ||
5 | 0x06 switchvideomode # Fn+F7 | ||
6 | 0x07 zoom # Fn+F8 screen expand | ||
7 | 0x08 f24 # Fn+F9 undock | ||
8 | 0x0B suspend # Fn+F12 | ||
9 | 0x0F brightnessup # Fn+Home | ||
10 | 0x10 brightnessdown # Fn+End | ||
11 | 0x11 kbdillumtoggle # Fn+PgUp - ThinkLight | ||
12 | 0x13 zoom # Fn+Space | ||
13 | 0x14 volumeup | ||
14 | 0x15 volumedown | ||
15 | 0x16 mute | ||
16 | 0x17 prog1 # ThinkPad/ThinkVantage button (high keycode: "vendor") | ||
diff --git a/src/udev/src/keymap/keymaps/module-lenovo b/src/udev/src/keymap/keymaps/module-lenovo new file mode 100644 index 000000000..8e3888309 --- /dev/null +++ b/src/udev/src/keymap/keymaps/module-lenovo | |||
@@ -0,0 +1,17 @@ | |||
1 | 0x1 screenlock # Fn+F2 | ||
2 | 0x2 battery # Fn+F3 | ||
3 | 0x3 sleep # Fn+F4 | ||
4 | 0x4 wlan # Fn+F5 | ||
5 | 0x6 switchvideomode # Fn+F7 | ||
6 | 0x7 f21 # Fn+F8 touchpadtoggle | ||
7 | 0x8 f24 # Fn+F9 undock | ||
8 | 0xB suspend # Fn+F12 | ||
9 | 0xF brightnessup # Fn+Home | ||
10 | 0x10 brightnessdown # Fn+End | ||
11 | 0x11 kbdillumtoggle # Fn+PgUp - ThinkLight | ||
12 | 0x13 zoom # Fn+Space | ||
13 | 0x14 volumeup | ||
14 | 0x15 volumedown | ||
15 | 0x16 mute | ||
16 | 0x17 prog1 # ThinkPad/ThinkVantage button (high keycode: "vendor") | ||
17 | 0x1A micmute # Microphone mute | ||
diff --git a/src/udev/src/keymap/keymaps/module-sony b/src/udev/src/keymap/keymaps/module-sony new file mode 100644 index 000000000..7c000131d --- /dev/null +++ b/src/udev/src/keymap/keymaps/module-sony | |||
@@ -0,0 +1,8 @@ | |||
1 | 0x06 mute # Fn+F2 | ||
2 | 0x07 volumedown # Fn+F3 | ||
3 | 0x08 volumeup # Fn+F4 | ||
4 | 0x09 brightnessdown # Fn+F5 | ||
5 | 0x0A brightnessup # Fn+F6 | ||
6 | 0x0B switchvideomode # Fn+F7 | ||
7 | 0x0E zoom # Fn+F10 | ||
8 | 0x10 suspend # Fn+F12 | ||
diff --git a/src/udev/src/keymap/keymaps/module-sony-old b/src/udev/src/keymap/keymaps/module-sony-old new file mode 100644 index 000000000..596a34258 --- /dev/null +++ b/src/udev/src/keymap/keymaps/module-sony-old | |||
@@ -0,0 +1,2 @@ | |||
1 | 0x06 battery | ||
2 | 0x07 mute | ||
diff --git a/src/udev/src/keymap/keymaps/module-sony-vgn b/src/udev/src/keymap/keymaps/module-sony-vgn new file mode 100644 index 000000000..c8ba00151 --- /dev/null +++ b/src/udev/src/keymap/keymaps/module-sony-vgn | |||
@@ -0,0 +1,8 @@ | |||
1 | 0x00 brightnessdown # Fn+F5 | ||
2 | 0x10 brightnessup # Fn+F6 | ||
3 | 0x11 switchvideomode # Fn+F7 | ||
4 | 0x12 zoomout | ||
5 | 0x14 zoomin | ||
6 | 0x15 suspend # Fn+F12 | ||
7 | 0x17 prog1 | ||
8 | 0x20 media | ||
diff --git a/src/udev/src/keymap/keymaps/olpc-xo b/src/udev/src/keymap/keymaps/olpc-xo new file mode 100644 index 000000000..34434a121 --- /dev/null +++ b/src/udev/src/keymap/keymaps/olpc-xo | |||
@@ -0,0 +1,74 @@ | |||
1 | 0x59 fn | ||
2 | 0x81 fn_esc | ||
3 | 0xF9 camera | ||
4 | 0xF8 sound # Fn-CAMERA = Mic | ||
5 | |||
6 | |||
7 | # Function key mappings, as per | ||
8 | # http://dev.laptop.org/ticket/10213#comment:20 | ||
9 | # | ||
10 | # Unmodified F1-F8 produce F1-F8, so no remap necessary. | ||
11 | # Unmodified F9-F12 control brightness and volume. | ||
12 | 0x43 brightnessdown | ||
13 | 0x44 brightnessup | ||
14 | 0x57 volumedown | ||
15 | 0x58 volumeup | ||
16 | |||
17 | # fn-modified fkeys all produce the unmodified version of the key. | ||
18 | 0xBB f1 | ||
19 | 0xBC f2 | ||
20 | 0xBD f3 | ||
21 | 0xBE f4 | ||
22 | 0xBF f5 | ||
23 | 0xC0 f6 | ||
24 | 0xC1 f7 | ||
25 | 0xC2 f8 | ||
26 | 0xC3 f9 | ||
27 | 0xC4 f10 | ||
28 | 0xD7 f11 | ||
29 | 0xD8 f12 | ||
30 | |||
31 | |||
32 | # Using F13-F21 for the .5 F keys right now. | ||
33 | 0xF7 f13 | ||
34 | 0xF6 f14 | ||
35 | 0xF5 f15 | ||
36 | 0xF4 f16 | ||
37 | 0xF3 f17 | ||
38 | 0xF2 f18 | ||
39 | 0xF1 f19 | ||
40 | 0xF0 f20 | ||
41 | 0xEF f21 | ||
42 | |||
43 | 0xEE chat | ||
44 | 0xE4 chat # Just mapping Fn-Chat to Chat for now | ||
45 | 0xDD menu # Frame | ||
46 | 0xDA prog1 # Fn-Frame | ||
47 | |||
48 | # The FN of some keys is other keys | ||
49 | 0xD3 delete | ||
50 | 0xD2 insert | ||
51 | 0xC9 pageup | ||
52 | 0xD1 pagedown | ||
53 | 0xC7 home | ||
54 | 0xCF end | ||
55 | |||
56 | # Language key - don't ask what they are doing as KEY_HP | ||
57 | 0x73 hp | ||
58 | 0x7E hp | ||
59 | |||
60 | 0xDB leftmeta # left grab | ||
61 | 0xDC rightmeta # right grab | ||
62 | 0x85 rightmeta # Right grab releases on a different scancode | ||
63 | 0xD6 kbdillumtoggle # Fn-space | ||
64 | 0x69 switchvideomode # Brightness key | ||
65 | |||
66 | # Game keys | ||
67 | 0x65 kp8 # up | ||
68 | 0x66 kp2 # down | ||
69 | 0x67 kp4 # left | ||
70 | 0x68 kp6 # right | ||
71 | 0xE5 kp9 # pgup | ||
72 | 0xE6 kp3 # pgdn | ||
73 | 0xE7 kp7 # home | ||
74 | 0xE8 kp1 # end | ||
diff --git a/src/udev/src/keymap/keymaps/onkyo b/src/udev/src/keymap/keymaps/onkyo new file mode 100644 index 000000000..ee864ade4 --- /dev/null +++ b/src/udev/src/keymap/keymaps/onkyo | |||
@@ -0,0 +1,14 @@ | |||
1 | 0xA0 mute # Fn+D | ||
2 | 0xAE volumedown # Fn+F | ||
3 | 0xB0 volumeup # Fn+G | ||
4 | 0xDF sleep # Fn+W | ||
5 | 0xE0 bluetooth # Fn+H | ||
6 | 0xE2 cyclewindows # Fn+Esc | ||
7 | 0xEE battery # Fn+Q | ||
8 | 0xF0 media # Fn+R | ||
9 | 0xF5 switchvideomode # Fn+E | ||
10 | 0xF6 camera # Fn+T | ||
11 | 0xF7 f21 # Fn+Y (touchpad toggle) | ||
12 | 0xF8 brightnessup # Fn+S | ||
13 | 0xF9 brightnessdown # Fn+A | ||
14 | 0xFB wlan # Fn+J | ||
diff --git a/src/udev/src/keymap/keymaps/oqo-model2 b/src/udev/src/keymap/keymaps/oqo-model2 new file mode 100644 index 000000000..b7f4851ab --- /dev/null +++ b/src/udev/src/keymap/keymaps/oqo-model2 | |||
@@ -0,0 +1,5 @@ | |||
1 | 0x8E wlan | ||
2 | 0xF0 switchvideomode | ||
3 | 0xF1 mute | ||
4 | 0xF2 volumedown | ||
5 | 0xF3 volumeup | ||
diff --git a/src/udev/src/keymap/keymaps/samsung-90x3a b/src/udev/src/keymap/keymaps/samsung-90x3a new file mode 100644 index 000000000..8b65eb6d0 --- /dev/null +++ b/src/udev/src/keymap/keymaps/samsung-90x3a | |||
@@ -0,0 +1,5 @@ | |||
1 | 0x96 kbdillumup # Fn+F8 keyboard backlit up | ||
2 | 0x97 kbdillumdown # Fn+F7 keyboard backlit down | ||
3 | 0xD5 wlan # Fn+F12 wifi on/off | ||
4 | 0xCE prog1 # Fn+F1 performance mode | ||
5 | 0x8D prog2 # Fn+F6 battery life extender | ||
diff --git a/src/udev/src/keymap/keymaps/samsung-other b/src/udev/src/keymap/keymaps/samsung-other new file mode 100644 index 000000000..3ac0c2f10 --- /dev/null +++ b/src/udev/src/keymap/keymaps/samsung-other | |||
@@ -0,0 +1,14 @@ | |||
1 | 0x74 prog1 # User key | ||
2 | 0x75 www | ||
3 | 0x78 mail | ||
4 | 0x82 switchvideomode # Fn+F4 CRT/LCD (high keycode: "displaytoggle") | ||
5 | 0x83 battery # Fn+F2 | ||
6 | 0x84 prog1 # Fn+F5 backlight on/off | ||
7 | 0x86 wlan # Fn+F9 | ||
8 | 0x88 brightnessup # Fn-Up | ||
9 | 0x89 brightnessdown # Fn-Down | ||
10 | 0xB1 prog2 # Fn+F7 run Samsung Magic Doctor (keypressed event is generated twice) | ||
11 | 0xB3 prog3 # Fn+F8 switch power mode (battery/dynamic/performance) | ||
12 | 0xB4 wlan # Fn+F9 (X60P) | ||
13 | 0xF7 f22 # Fn+F10 Touchpad on | ||
14 | 0xF9 f23 # Fn+F10 Touchpad off | ||
diff --git a/src/udev/src/keymap/keymaps/samsung-sq1us b/src/udev/src/keymap/keymaps/samsung-sq1us new file mode 100644 index 000000000..ea2141ef8 --- /dev/null +++ b/src/udev/src/keymap/keymaps/samsung-sq1us | |||
@@ -0,0 +1,7 @@ | |||
1 | 0xD4 menu | ||
2 | 0xD8 f1 | ||
3 | 0xD9 f10 | ||
4 | 0xD6 f3 | ||
5 | 0xD7 f9 | ||
6 | 0xE4 f5 | ||
7 | 0xEE f11 | ||
diff --git a/src/udev/src/keymap/keymaps/samsung-sx20s b/src/udev/src/keymap/keymaps/samsung-sx20s new file mode 100644 index 000000000..9d954ee41 --- /dev/null +++ b/src/udev/src/keymap/keymaps/samsung-sx20s | |||
@@ -0,0 +1,4 @@ | |||
1 | 0x74 mute | ||
2 | 0x75 mute | ||
3 | 0x77 f22 # Touchpad on | ||
4 | 0x79 f23 # Touchpad off | ||
diff --git a/src/udev/src/keymap/keymaps/toshiba-satellite_a100 b/src/udev/src/keymap/keymaps/toshiba-satellite_a100 new file mode 100644 index 000000000..22007be71 --- /dev/null +++ b/src/udev/src/keymap/keymaps/toshiba-satellite_a100 | |||
@@ -0,0 +1,2 @@ | |||
1 | 0xA4 stopcd | ||
2 | 0xB2 www | ||
diff --git a/src/udev/src/keymap/keymaps/toshiba-satellite_a110 b/src/udev/src/keymap/keymaps/toshiba-satellite_a110 new file mode 100644 index 000000000..142940935 --- /dev/null +++ b/src/udev/src/keymap/keymaps/toshiba-satellite_a110 | |||
@@ -0,0 +1,10 @@ | |||
1 | 0x92 stop | ||
2 | 0x93 www | ||
3 | 0x94 media | ||
4 | 0x9E f22 # Touchpad on | ||
5 | 0x9F f23 # Touchpad off | ||
6 | 0xB9 nextsong | ||
7 | 0xD9 brightnessup | ||
8 | 0xEE screenlock | ||
9 | 0xF4 previoussong | ||
10 | 0xF7 playpause | ||
diff --git a/src/udev/src/keymap/keymaps/toshiba-satellite_m30x b/src/udev/src/keymap/keymaps/toshiba-satellite_m30x new file mode 100644 index 000000000..ae8e34941 --- /dev/null +++ b/src/udev/src/keymap/keymaps/toshiba-satellite_m30x | |||
@@ -0,0 +1,6 @@ | |||
1 | 0xef brightnessdown | ||
2 | 0xd9 brightnessup | ||
3 | 0xee screenlock | ||
4 | 0x93 media | ||
5 | 0x9e f22 #touchpad_enable | ||
6 | 0x9f f23 #touchpad_disable | ||
diff --git a/src/udev/src/keymap/keymaps/zepto-znote b/src/udev/src/keymap/keymaps/zepto-znote new file mode 100644 index 000000000..cf72fda47 --- /dev/null +++ b/src/udev/src/keymap/keymaps/zepto-znote | |||
@@ -0,0 +1,11 @@ | |||
1 | 0x93 switchvideomode # Fn+F3 Toggle Video Output | ||
2 | 0x95 brightnessdown # Fn+F4 Brightness Down | ||
3 | 0x91 brightnessup # Fn+F5 Brightness Up | ||
4 | 0xA5 f23 # Fn+F6 Disable Touchpad | ||
5 | 0xA6 f22 # Fn+F6 Enable Touchpad | ||
6 | 0xA7 bluetooth # Fn+F10 Enable Bluetooth | ||
7 | 0XA9 bluetooth # Fn+F10 Disable Bluetooth | ||
8 | 0xF1 wlan # RF Switch Off | ||
9 | 0xF2 wlan # RF Switch On | ||
10 | 0xF4 prog1 # P1 Button | ||
11 | 0xF3 prog2 # P2 Button | ||
diff --git a/src/udev/src/libudev-device-private.c b/src/udev/src/libudev-device-private.c new file mode 100644 index 000000000..13fdb8eb5 --- /dev/null +++ b/src/udev/src/libudev-device-private.c | |||
@@ -0,0 +1,185 @@ | |||
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 | } | ||
diff --git a/src/udev/src/libudev-device.c b/src/udev/src/libudev-device.c new file mode 100644 index 000000000..10f28b8cd --- /dev/null +++ b/src/udev/src/libudev-device.c | |||
@@ -0,0 +1,1744 @@ | |||
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 | * Returns: the device major/minor number. | ||
140 | **/ | ||
141 | UDEV_EXPORT dev_t udev_device_get_devnum(struct udev_device *udev_device) | ||
142 | { | ||
143 | if (udev_device == NULL) | ||
144 | return makedev(0, 0); | ||
145 | if (!udev_device->info_loaded) | ||
146 | udev_device_read_uevent_file(udev_device); | ||
147 | return udev_device->devnum; | ||
148 | } | ||
149 | |||
150 | static int udev_device_set_devnum(struct udev_device *udev_device, dev_t devnum) | ||
151 | { | ||
152 | char num[32]; | ||
153 | |||
154 | udev_device->devnum = devnum; | ||
155 | |||
156 | snprintf(num, sizeof(num), "%u", major(devnum)); | ||
157 | udev_device_add_property(udev_device, "MAJOR", num); | ||
158 | snprintf(num, sizeof(num), "%u", minor(devnum)); | ||
159 | udev_device_add_property(udev_device, "MINOR", num); | ||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | const char *udev_device_get_devpath_old(struct udev_device *udev_device) | ||
164 | { | ||
165 | return udev_device->devpath_old; | ||
166 | } | ||
167 | |||
168 | static int udev_device_set_devpath_old(struct udev_device *udev_device, const char *devpath_old) | ||
169 | { | ||
170 | const char *pos; | ||
171 | |||
172 | free(udev_device->devpath_old); | ||
173 | udev_device->devpath_old = strdup(devpath_old); | ||
174 | if (udev_device->devpath_old == NULL) | ||
175 | return -ENOMEM; | ||
176 | udev_device_add_property(udev_device, "DEVPATH_OLD", udev_device->devpath_old); | ||
177 | |||
178 | pos = strrchr(udev_device->devpath_old, '/'); | ||
179 | if (pos == NULL) | ||
180 | return -EINVAL; | ||
181 | return 0; | ||
182 | } | ||
183 | |||
184 | /** | ||
185 | * udev_device_get_driver: | ||
186 | * @udev_device: udev device | ||
187 | * | ||
188 | * Returns: the driver string, or #NULL if there is no driver attached. | ||
189 | **/ | ||
190 | UDEV_EXPORT const char *udev_device_get_driver(struct udev_device *udev_device) | ||
191 | { | ||
192 | char driver[UTIL_NAME_SIZE]; | ||
193 | |||
194 | if (udev_device == NULL) | ||
195 | return NULL; | ||
196 | if (!udev_device->driver_set) { | ||
197 | udev_device->driver_set = true; | ||
198 | if (util_get_sys_core_link_value(udev_device->udev, "driver", udev_device->syspath, driver, sizeof(driver)) > 0) | ||
199 | udev_device->driver = strdup(driver); | ||
200 | } | ||
201 | return udev_device->driver; | ||
202 | } | ||
203 | |||
204 | static int udev_device_set_driver(struct udev_device *udev_device, const char *driver) | ||
205 | { | ||
206 | free(udev_device->driver); | ||
207 | udev_device->driver = strdup(driver); | ||
208 | if (udev_device->driver == NULL) | ||
209 | return -ENOMEM; | ||
210 | udev_device->driver_set = true; | ||
211 | udev_device_add_property(udev_device, "DRIVER", udev_device->driver); | ||
212 | return 0; | ||
213 | } | ||
214 | |||
215 | /** | ||
216 | * udev_device_get_devtype: | ||
217 | * @udev_device: udev device | ||
218 | * | ||
219 | * Retrieve the devtype string of the udev device. | ||
220 | * | ||
221 | * Returns: the devtype name of the udev device, or #NULL if it can not be determined | ||
222 | **/ | ||
223 | UDEV_EXPORT const char *udev_device_get_devtype(struct udev_device *udev_device) | ||
224 | { | ||
225 | if (udev_device == NULL) | ||
226 | return NULL; | ||
227 | if (!udev_device->devtype_set) { | ||
228 | udev_device->devtype_set = true; | ||
229 | udev_device_read_uevent_file(udev_device); | ||
230 | } | ||
231 | return udev_device->devtype; | ||
232 | } | ||
233 | |||
234 | static int udev_device_set_devtype(struct udev_device *udev_device, const char *devtype) | ||
235 | { | ||
236 | free(udev_device->devtype); | ||
237 | udev_device->devtype = strdup(devtype); | ||
238 | if (udev_device->devtype == NULL) | ||
239 | return -ENOMEM; | ||
240 | udev_device->devtype_set = true; | ||
241 | udev_device_add_property(udev_device, "DEVTYPE", udev_device->devtype); | ||
242 | return 0; | ||
243 | } | ||
244 | |||
245 | static int udev_device_set_subsystem(struct udev_device *udev_device, const char *subsystem) | ||
246 | { | ||
247 | free(udev_device->subsystem); | ||
248 | udev_device->subsystem = strdup(subsystem); | ||
249 | if (udev_device->subsystem == NULL) | ||
250 | return -ENOMEM; | ||
251 | udev_device->subsystem_set = true; | ||
252 | udev_device_add_property(udev_device, "SUBSYSTEM", udev_device->subsystem); | ||
253 | return 0; | ||
254 | } | ||
255 | |||
256 | /** | ||
257 | * udev_device_get_subsystem: | ||
258 | * @udev_device: udev device | ||
259 | * | ||
260 | * Retrieve the subsystem string of the udev device. The string does not | ||
261 | * contain any "/". | ||
262 | * | ||
263 | * Returns: the subsystem name of the udev device, or #NULL if it can not be determined | ||
264 | **/ | ||
265 | UDEV_EXPORT const char *udev_device_get_subsystem(struct udev_device *udev_device) | ||
266 | { | ||
267 | char subsystem[UTIL_NAME_SIZE]; | ||
268 | |||
269 | if (udev_device == NULL) | ||
270 | return NULL; | ||
271 | if (!udev_device->subsystem_set) { | ||
272 | udev_device->subsystem_set = true; | ||
273 | /* read "subsystem" link */ | ||
274 | if (util_get_sys_core_link_value(udev_device->udev, "subsystem", udev_device->syspath, subsystem, sizeof(subsystem)) > 0) { | ||
275 | udev_device_set_subsystem(udev_device, subsystem); | ||
276 | return udev_device->subsystem; | ||
277 | } | ||
278 | /* implicit names */ | ||
279 | if (strncmp(udev_device->devpath, "/module/", 8) == 0) { | ||
280 | udev_device_set_subsystem(udev_device, "module"); | ||
281 | return udev_device->subsystem; | ||
282 | } | ||
283 | if (strstr(udev_device->devpath, "/drivers/") != NULL) { | ||
284 | udev_device_set_subsystem(udev_device, "drivers"); | ||
285 | return udev_device->subsystem; | ||
286 | } | ||
287 | if (strncmp(udev_device->devpath, "/subsystem/", 11) == 0 || | ||
288 | strncmp(udev_device->devpath, "/class/", 7) == 0 || | ||
289 | strncmp(udev_device->devpath, "/bus/", 5) == 0) { | ||
290 | udev_device_set_subsystem(udev_device, "subsystem"); | ||
291 | return udev_device->subsystem; | ||
292 | } | ||
293 | } | ||
294 | return udev_device->subsystem; | ||
295 | } | ||
296 | |||
297 | mode_t udev_device_get_devnode_mode(struct udev_device *udev_device) | ||
298 | { | ||
299 | if (!udev_device->info_loaded) | ||
300 | udev_device_read_uevent_file(udev_device); | ||
301 | return udev_device->devnode_mode; | ||
302 | } | ||
303 | |||
304 | static int udev_device_set_devnode_mode(struct udev_device *udev_device, mode_t mode) | ||
305 | { | ||
306 | char num[32]; | ||
307 | |||
308 | udev_device->devnode_mode = mode; | ||
309 | snprintf(num, sizeof(num), "%#o", mode); | ||
310 | udev_device_add_property(udev_device, "DEVMODE", num); | ||
311 | return 0; | ||
312 | } | ||
313 | |||
314 | struct udev_list_entry *udev_device_add_property(struct udev_device *udev_device, const char *key, const char *value) | ||
315 | { | ||
316 | udev_device->envp_uptodate = false; | ||
317 | if (value == NULL) { | ||
318 | struct udev_list_entry *list_entry; | ||
319 | |||
320 | list_entry = udev_device_get_properties_list_entry(udev_device); | ||
321 | list_entry = udev_list_entry_get_by_name(list_entry, key); | ||
322 | if (list_entry != NULL) | ||
323 | udev_list_entry_delete(list_entry); | ||
324 | return NULL; | ||
325 | } | ||
326 | return udev_list_entry_add(&udev_device->properties_list, key, value); | ||
327 | } | ||
328 | |||
329 | static struct udev_list_entry *udev_device_add_property_from_string(struct udev_device *udev_device, const char *property) | ||
330 | { | ||
331 | char name[UTIL_LINE_SIZE]; | ||
332 | char *val; | ||
333 | |||
334 | util_strscpy(name, sizeof(name), property); | ||
335 | val = strchr(name, '='); | ||
336 | if (val == NULL) | ||
337 | return NULL; | ||
338 | val[0] = '\0'; | ||
339 | val = &val[1]; | ||
340 | if (val[0] == '\0') | ||
341 | val = NULL; | ||
342 | return udev_device_add_property(udev_device, name, val); | ||
343 | } | ||
344 | |||
345 | /* | ||
346 | * parse property string, and if needed, update internal values accordingly | ||
347 | * | ||
348 | * udev_device_add_property_from_string_parse_finish() needs to be | ||
349 | * called after adding properties, and its return value checked | ||
350 | * | ||
351 | * udev_device_set_info_loaded() needs to be set, to avoid trying | ||
352 | * to use a device without a DEVPATH set | ||
353 | */ | ||
354 | void udev_device_add_property_from_string_parse(struct udev_device *udev_device, const char *property) | ||
355 | { | ||
356 | if (strncmp(property, "DEVPATH=", 8) == 0) { | ||
357 | char path[UTIL_PATH_SIZE]; | ||
358 | |||
359 | util_strscpyl(path, sizeof(path), udev_get_sys_path(udev_device->udev), &property[8], NULL); | ||
360 | udev_device_set_syspath(udev_device, path); | ||
361 | } else if (strncmp(property, "SUBSYSTEM=", 10) == 0) { | ||
362 | udev_device_set_subsystem(udev_device, &property[10]); | ||
363 | } else if (strncmp(property, "DEVTYPE=", 8) == 0) { | ||
364 | udev_device_set_devtype(udev_device, &property[8]); | ||
365 | } else if (strncmp(property, "DEVNAME=", 8) == 0) { | ||
366 | udev_device_set_devnode(udev_device, &property[8]); | ||
367 | } else if (strncmp(property, "DEVLINKS=", 9) == 0) { | ||
368 | char devlinks[UTIL_PATH_SIZE]; | ||
369 | char *slink; | ||
370 | char *next; | ||
371 | |||
372 | util_strscpy(devlinks, sizeof(devlinks), &property[9]); | ||
373 | slink = devlinks; | ||
374 | next = strchr(slink, ' '); | ||
375 | while (next != NULL) { | ||
376 | next[0] = '\0'; | ||
377 | udev_device_add_devlink(udev_device, slink, 0); | ||
378 | slink = &next[1]; | ||
379 | next = strchr(slink, ' '); | ||
380 | } | ||
381 | if (slink[0] != '\0') | ||
382 | udev_device_add_devlink(udev_device, slink, 0); | ||
383 | } else if (strncmp(property, "TAGS=", 5) == 0) { | ||
384 | char tags[UTIL_PATH_SIZE]; | ||
385 | char *next; | ||
386 | |||
387 | util_strscpy(tags, sizeof(tags), &property[5]); | ||
388 | next = strchr(tags, ':'); | ||
389 | if (next != NULL) { | ||
390 | next++; | ||
391 | while (next[0] != '\0') { | ||
392 | char *tag; | ||
393 | |||
394 | tag = next; | ||
395 | next = strchr(tag, ':'); | ||
396 | if (next == NULL) | ||
397 | break; | ||
398 | next[0] = '\0'; | ||
399 | next++; | ||
400 | udev_device_add_tag(udev_device, tag); | ||
401 | } | ||
402 | } | ||
403 | } else if (strncmp(property, "USEC_INITIALIZED=", 19) == 0) { | ||
404 | udev_device_set_usec_initialized(udev_device, strtoull(&property[19], NULL, 10)); | ||
405 | } else if (strncmp(property, "DRIVER=", 7) == 0) { | ||
406 | udev_device_set_driver(udev_device, &property[7]); | ||
407 | } else if (strncmp(property, "ACTION=", 7) == 0) { | ||
408 | udev_device_set_action(udev_device, &property[7]); | ||
409 | } else if (strncmp(property, "MAJOR=", 6) == 0) { | ||
410 | udev_device->maj = strtoull(&property[6], NULL, 10); | ||
411 | } else if (strncmp(property, "MINOR=", 6) == 0) { | ||
412 | udev_device->min = strtoull(&property[6], NULL, 10); | ||
413 | } else if (strncmp(property, "DEVPATH_OLD=", 12) == 0) { | ||
414 | udev_device_set_devpath_old(udev_device, &property[12]); | ||
415 | } else if (strncmp(property, "SEQNUM=", 7) == 0) { | ||
416 | udev_device_set_seqnum(udev_device, strtoull(&property[7], NULL, 10)); | ||
417 | } else if (strncmp(property, "IFINDEX=", 8) == 0) { | ||
418 | udev_device_set_ifindex(udev_device, strtoull(&property[8], NULL, 10)); | ||
419 | } else if (strncmp(property, "DEVMODE=", 8) == 0) { | ||
420 | udev_device_set_devnode_mode(udev_device, strtoul(&property[8], NULL, 8)); | ||
421 | } else { | ||
422 | udev_device_add_property_from_string(udev_device, property); | ||
423 | } | ||
424 | } | ||
425 | |||
426 | int udev_device_add_property_from_string_parse_finish(struct udev_device *udev_device) | ||
427 | { | ||
428 | if (udev_device->maj > 0) | ||
429 | udev_device_set_devnum(udev_device, makedev(udev_device->maj, udev_device->min)); | ||
430 | udev_device->maj = 0; | ||
431 | udev_device->min = 0; | ||
432 | |||
433 | if (udev_device->devpath == NULL || udev_device->subsystem == NULL) | ||
434 | return -EINVAL; | ||
435 | return 0; | ||
436 | } | ||
437 | |||
438 | /** | ||
439 | * udev_device_get_property_value: | ||
440 | * @udev_device: udev device | ||
441 | * @key: property name | ||
442 | * | ||
443 | * Returns: the value of a device property, or #NULL if there is no such property. | ||
444 | **/ | ||
445 | UDEV_EXPORT const char *udev_device_get_property_value(struct udev_device *udev_device, const char *key) | ||
446 | { | ||
447 | struct udev_list_entry *list_entry; | ||
448 | |||
449 | if (udev_device == NULL) | ||
450 | return NULL; | ||
451 | if (key == NULL) | ||
452 | return NULL; | ||
453 | |||
454 | list_entry = udev_device_get_properties_list_entry(udev_device); | ||
455 | list_entry = udev_list_entry_get_by_name(list_entry, key); | ||
456 | return udev_list_entry_get_value(list_entry); | ||
457 | } | ||
458 | |||
459 | int udev_device_read_db(struct udev_device *udev_device, const char *dbfile) | ||
460 | { | ||
461 | char filename[UTIL_PATH_SIZE]; | ||
462 | char line[UTIL_LINE_SIZE]; | ||
463 | FILE *f; | ||
464 | |||
465 | /* providing a database file will always force-load it */ | ||
466 | if (dbfile == NULL) { | ||
467 | const char *id; | ||
468 | |||
469 | if (udev_device->db_loaded) | ||
470 | return 0; | ||
471 | udev_device->db_loaded = true; | ||
472 | |||
473 | id = udev_device_get_id_filename(udev_device); | ||
474 | if (id == NULL) | ||
475 | return -1; | ||
476 | util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev_device->udev), "/data/", id, NULL); | ||
477 | dbfile = filename; | ||
478 | } | ||
479 | |||
480 | f = fopen(dbfile, "re"); | ||
481 | if (f == NULL) { | ||
482 | info(udev_device->udev, "no db file to read %s: %m\n", dbfile); | ||
483 | return -1; | ||
484 | } | ||
485 | udev_device->is_initialized = true; | ||
486 | |||
487 | while (fgets(line, sizeof(line), f)) { | ||
488 | ssize_t len; | ||
489 | const char *val; | ||
490 | struct udev_list_entry *entry; | ||
491 | |||
492 | len = strlen(line); | ||
493 | if (len < 4) | ||
494 | break; | ||
495 | line[len-1] = '\0'; | ||
496 | val = &line[2]; | ||
497 | switch(line[0]) { | ||
498 | case 'S': | ||
499 | util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev_device->udev), "/", val, NULL); | ||
500 | udev_device_add_devlink(udev_device, filename, 0); | ||
501 | break; | ||
502 | case 'L': | ||
503 | udev_device_set_devlink_priority(udev_device, atoi(val)); | ||
504 | break; | ||
505 | case 'E': | ||
506 | entry = udev_device_add_property_from_string(udev_device, val); | ||
507 | udev_list_entry_set_num(entry, true); | ||
508 | break; | ||
509 | case 'G': | ||
510 | udev_device_add_tag(udev_device, val); | ||
511 | break; | ||
512 | case 'W': | ||
513 | udev_device_set_watch_handle(udev_device, atoi(val)); | ||
514 | break; | ||
515 | case 'I': | ||
516 | udev_device_set_usec_initialized(udev_device, strtoull(val, NULL, 10)); | ||
517 | break; | ||
518 | } | ||
519 | } | ||
520 | fclose(f); | ||
521 | |||
522 | info(udev_device->udev, "device %p filled with db file data\n", udev_device); | ||
523 | return 0; | ||
524 | } | ||
525 | |||
526 | int udev_device_read_uevent_file(struct udev_device *udev_device) | ||
527 | { | ||
528 | char filename[UTIL_PATH_SIZE]; | ||
529 | FILE *f; | ||
530 | char line[UTIL_LINE_SIZE]; | ||
531 | int maj = 0; | ||
532 | int min = 0; | ||
533 | |||
534 | if (udev_device->uevent_loaded) | ||
535 | return 0; | ||
536 | |||
537 | util_strscpyl(filename, sizeof(filename), udev_device->syspath, "/uevent", NULL); | ||
538 | f = fopen(filename, "re"); | ||
539 | if (f == NULL) | ||
540 | return -1; | ||
541 | udev_device->uevent_loaded = true; | ||
542 | |||
543 | while (fgets(line, sizeof(line), f)) { | ||
544 | char *pos; | ||
545 | |||
546 | pos = strchr(line, '\n'); | ||
547 | if (pos == NULL) | ||
548 | continue; | ||
549 | pos[0] = '\0'; | ||
550 | |||
551 | if (strncmp(line, "DEVTYPE=", 8) == 0) { | ||
552 | udev_device_set_devtype(udev_device, &line[8]); | ||
553 | continue; | ||
554 | } | ||
555 | if (strncmp(line, "IFINDEX=", 8) == 0) { | ||
556 | udev_device_set_ifindex(udev_device, strtoull(&line[8], NULL, 10)); | ||
557 | continue; | ||
558 | } | ||
559 | if (strncmp(line, "DEVNAME=", 8) == 0) { | ||
560 | udev_device_set_devnode(udev_device, &line[8]); | ||
561 | continue; | ||
562 | } | ||
563 | |||
564 | if (strncmp(line, "MAJOR=", 6) == 0) | ||
565 | maj = strtoull(&line[6], NULL, 10); | ||
566 | else if (strncmp(line, "MINOR=", 6) == 0) | ||
567 | min = strtoull(&line[6], NULL, 10); | ||
568 | else if (strncmp(line, "DEVMODE=", 8) == 0) | ||
569 | udev_device->devnode_mode = strtoul(&line[8], NULL, 8); | ||
570 | |||
571 | udev_device_add_property_from_string(udev_device, line); | ||
572 | } | ||
573 | |||
574 | udev_device->devnum = makedev(maj, min); | ||
575 | fclose(f); | ||
576 | return 0; | ||
577 | } | ||
578 | |||
579 | void udev_device_set_info_loaded(struct udev_device *device) | ||
580 | { | ||
581 | device->info_loaded = true; | ||
582 | } | ||
583 | |||
584 | struct udev_device *udev_device_new(struct udev *udev) | ||
585 | { | ||
586 | struct udev_device *udev_device; | ||
587 | struct udev_list_entry *list_entry; | ||
588 | |||
589 | if (udev == NULL) | ||
590 | return NULL; | ||
591 | |||
592 | udev_device = calloc(1, sizeof(struct udev_device)); | ||
593 | if (udev_device == NULL) | ||
594 | return NULL; | ||
595 | udev_device->refcount = 1; | ||
596 | udev_device->udev = udev; | ||
597 | udev_list_init(udev, &udev_device->devlinks_list, true); | ||
598 | udev_list_init(udev, &udev_device->properties_list, true); | ||
599 | udev_list_init(udev, &udev_device->sysattr_value_list, true); | ||
600 | udev_list_init(udev, &udev_device->sysattr_list, false); | ||
601 | udev_list_init(udev, &udev_device->tags_list, true); | ||
602 | udev_device->watch_handle = -1; | ||
603 | /* copy global properties */ | ||
604 | udev_list_entry_foreach(list_entry, udev_get_properties_list_entry(udev)) | ||
605 | udev_device_add_property(udev_device, | ||
606 | udev_list_entry_get_name(list_entry), | ||
607 | udev_list_entry_get_value(list_entry)); | ||
608 | dbg(udev_device->udev, "udev_device: %p created\n", udev_device); | ||
609 | return udev_device; | ||
610 | } | ||
611 | |||
612 | /** | ||
613 | * udev_device_new_from_syspath: | ||
614 | * @udev: udev library context | ||
615 | * @syspath: sys device path including sys directory | ||
616 | * | ||
617 | * Create new udev device, and fill in information from the sys | ||
618 | * device and the udev database entry. The syspath is the absolute | ||
619 | * path to the device, including the sys mount point. | ||
620 | * | ||
621 | * The initial refcount is 1, and needs to be decremented to | ||
622 | * release the resources of the udev device. | ||
623 | * | ||
624 | * Returns: a new udev device, or #NULL, if it does not exist | ||
625 | **/ | ||
626 | UDEV_EXPORT struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *syspath) | ||
627 | { | ||
628 | size_t len; | ||
629 | const char *subdir; | ||
630 | char path[UTIL_PATH_SIZE]; | ||
631 | char *pos; | ||
632 | struct stat statbuf; | ||
633 | struct udev_device *udev_device; | ||
634 | |||
635 | if (udev == NULL) | ||
636 | return NULL; | ||
637 | if (syspath == NULL) | ||
638 | return NULL; | ||
639 | |||
640 | /* path starts in sys */ | ||
641 | len = strlen(udev_get_sys_path(udev)); | ||
642 | if (strncmp(syspath, udev_get_sys_path(udev), len) != 0) { | ||
643 | info(udev, "not in sys :%s\n", syspath); | ||
644 | return NULL; | ||
645 | } | ||
646 | |||
647 | /* path is not a root directory */ | ||
648 | subdir = &syspath[len+1]; | ||
649 | pos = strrchr(subdir, '/'); | ||
650 | if (pos == NULL || pos[1] == '\0' || pos < &subdir[2]) { | ||
651 | dbg(udev, "not a subdir :%s\n", syspath); | ||
652 | return NULL; | ||
653 | } | ||
654 | |||
655 | /* resolve possible symlink to real path */ | ||
656 | util_strscpy(path, sizeof(path), syspath); | ||
657 | util_resolve_sys_link(udev, path, sizeof(path)); | ||
658 | |||
659 | if (strncmp(&path[len], "/devices/", 9) == 0) { | ||
660 | char file[UTIL_PATH_SIZE]; | ||
661 | |||
662 | /* all "devices" require a "uevent" file */ | ||
663 | util_strscpyl(file, sizeof(file), path, "/uevent", NULL); | ||
664 | if (stat(file, &statbuf) != 0) { | ||
665 | dbg(udev, "not a device: %s\n", syspath); | ||
666 | return NULL; | ||
667 | } | ||
668 | } else { | ||
669 | /* everything else just needs to be a directory */ | ||
670 | if (stat(path, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode)) { | ||
671 | dbg(udev, "directory not found: %s\n", syspath); | ||
672 | return NULL; | ||
673 | } | ||
674 | } | ||
675 | |||
676 | udev_device = udev_device_new(udev); | ||
677 | if (udev_device == NULL) | ||
678 | return NULL; | ||
679 | |||
680 | udev_device_set_syspath(udev_device, path); | ||
681 | info(udev, "device %p has devpath '%s'\n", udev_device, udev_device_get_devpath(udev_device)); | ||
682 | |||
683 | return udev_device; | ||
684 | } | ||
685 | |||
686 | /** | ||
687 | * udev_device_new_from_devnum: | ||
688 | * @udev: udev library context | ||
689 | * @type: char or block device | ||
690 | * @devnum: device major/minor number | ||
691 | * | ||
692 | * Create new udev device, and fill in information from the sys | ||
693 | * device and the udev database entry. The device is looked-up | ||
694 | * by its major/minor number and type. Character and block device | ||
695 | * numbers are not unique across the two types. | ||
696 | * | ||
697 | * The initial refcount is 1, and needs to be decremented to | ||
698 | * release the resources of the udev device. | ||
699 | * | ||
700 | * Returns: a new udev device, or #NULL, if it does not exist | ||
701 | **/ | ||
702 | UDEV_EXPORT struct udev_device *udev_device_new_from_devnum(struct udev *udev, char type, dev_t devnum) | ||
703 | { | ||
704 | char path[UTIL_PATH_SIZE]; | ||
705 | const char *type_str; | ||
706 | |||
707 | if (type == 'b') | ||
708 | type_str = "block"; | ||
709 | else if (type == 'c') | ||
710 | type_str = "char"; | ||
711 | else | ||
712 | return NULL; | ||
713 | |||
714 | /* use /sys/dev/{block,char}/<maj>:<min> link */ | ||
715 | snprintf(path, sizeof(path), "%s/dev/%s/%u:%u", | ||
716 | udev_get_sys_path(udev), type_str, major(devnum), minor(devnum)); | ||
717 | return udev_device_new_from_syspath(udev, path); | ||
718 | } | ||
719 | |||
720 | struct udev_device *udev_device_new_from_id_filename(struct udev *udev, char *id) | ||
721 | { | ||
722 | char type; | ||
723 | int maj, min; | ||
724 | char subsys[UTIL_PATH_SIZE]; | ||
725 | char *sysname; | ||
726 | |||
727 | switch(id[0]) { | ||
728 | case 'b': | ||
729 | case 'c': | ||
730 | if (sscanf(id, "%c%i:%i", &type, &maj, &min) != 3) | ||
731 | return NULL; | ||
732 | return udev_device_new_from_devnum(udev, type, makedev(maj, min)); | ||
733 | case 'n': { | ||
734 | int sk; | ||
735 | struct ifreq ifr; | ||
736 | struct udev_device *dev; | ||
737 | int ifindex; | ||
738 | |||
739 | ifindex = strtoul(&id[1], NULL, 10); | ||
740 | if (ifindex <= 0) | ||
741 | return NULL; | ||
742 | |||
743 | sk = socket(PF_INET, SOCK_DGRAM, 0); | ||
744 | if (sk < 0) | ||
745 | return NULL; | ||
746 | memset(&ifr, 0x00, sizeof(struct ifreq)); | ||
747 | ifr.ifr_ifindex = ifindex; | ||
748 | if (ioctl(sk, SIOCGIFNAME, &ifr) != 0) { | ||
749 | close(sk); | ||
750 | return NULL; | ||
751 | } | ||
752 | close(sk); | ||
753 | |||
754 | dev = udev_device_new_from_subsystem_sysname(udev, "net", ifr.ifr_name); | ||
755 | if (dev == NULL) | ||
756 | return NULL; | ||
757 | if (udev_device_get_ifindex(dev) == ifindex) | ||
758 | return dev; | ||
759 | udev_device_unref(dev); | ||
760 | return NULL; | ||
761 | } | ||
762 | case '+': | ||
763 | util_strscpy(subsys, sizeof(subsys), &id[1]); | ||
764 | sysname = strchr(subsys, ':'); | ||
765 | if (sysname == NULL) | ||
766 | return NULL; | ||
767 | sysname[0] = '\0'; | ||
768 | sysname = &sysname[1]; | ||
769 | return udev_device_new_from_subsystem_sysname(udev, subsys, sysname); | ||
770 | default: | ||
771 | return NULL; | ||
772 | } | ||
773 | } | ||
774 | |||
775 | /** | ||
776 | * udev_device_new_from_subsystem_sysname: | ||
777 | * @udev: udev library context | ||
778 | * @subsystem: the subsystem of the device | ||
779 | * @sysname: the name of the device | ||
780 | * | ||
781 | * Create new udev device, and fill in information from the sys device | ||
782 | * and the udev database entry. The device is looked up by the subsystem | ||
783 | * and name string of the device, like "mem" / "zero", or "block" / "sda". | ||
784 | * | ||
785 | * The initial refcount is 1, and needs to be decremented to | ||
786 | * release the resources of the udev device. | ||
787 | * | ||
788 | * Returns: a new udev device, or #NULL, if it does not exist | ||
789 | **/ | ||
790 | UDEV_EXPORT struct udev_device *udev_device_new_from_subsystem_sysname(struct udev *udev, const char *subsystem, const char *sysname) | ||
791 | { | ||
792 | char path_full[UTIL_PATH_SIZE]; | ||
793 | char *path; | ||
794 | size_t l; | ||
795 | struct stat statbuf; | ||
796 | |||
797 | path = path_full; | ||
798 | l = util_strpcpyl(&path, sizeof(path_full), udev_get_sys_path(udev), NULL); | ||
799 | |||
800 | if (strcmp(subsystem, "subsystem") == 0) { | ||
801 | util_strscpyl(path, l, "/subsystem/", sysname, NULL); | ||
802 | if (stat(path_full, &statbuf) == 0) | ||
803 | goto found; | ||
804 | |||
805 | util_strscpyl(path, l, "/bus/", sysname, NULL); | ||
806 | if (stat(path_full, &statbuf) == 0) | ||
807 | goto found; | ||
808 | |||
809 | util_strscpyl(path, l, "/class/", sysname, NULL); | ||
810 | if (stat(path_full, &statbuf) == 0) | ||
811 | goto found; | ||
812 | goto out; | ||
813 | } | ||
814 | |||
815 | if (strcmp(subsystem, "module") == 0) { | ||
816 | util_strscpyl(path, l, "/module/", sysname, NULL); | ||
817 | if (stat(path_full, &statbuf) == 0) | ||
818 | goto found; | ||
819 | goto out; | ||
820 | } | ||
821 | |||
822 | if (strcmp(subsystem, "drivers") == 0) { | ||
823 | char subsys[UTIL_NAME_SIZE]; | ||
824 | char *driver; | ||
825 | |||
826 | util_strscpy(subsys, sizeof(subsys), sysname); | ||
827 | driver = strchr(subsys, ':'); | ||
828 | if (driver != NULL) { | ||
829 | driver[0] = '\0'; | ||
830 | driver = &driver[1]; | ||
831 | |||
832 | util_strscpyl(path, l, "/subsystem/", subsys, "/drivers/", driver, NULL); | ||
833 | if (stat(path_full, &statbuf) == 0) | ||
834 | goto found; | ||
835 | |||
836 | util_strscpyl(path, l, "/bus/", subsys, "/drivers/", driver, NULL); | ||
837 | if (stat(path_full, &statbuf) == 0) | ||
838 | goto found; | ||
839 | } | ||
840 | goto out; | ||
841 | } | ||
842 | |||
843 | util_strscpyl(path, l, "/subsystem/", subsystem, "/devices/", sysname, NULL); | ||
844 | if (stat(path_full, &statbuf) == 0) | ||
845 | goto found; | ||
846 | |||
847 | util_strscpyl(path, l, "/bus/", subsystem, "/devices/", sysname, NULL); | ||
848 | if (stat(path_full, &statbuf) == 0) | ||
849 | goto found; | ||
850 | |||
851 | util_strscpyl(path, l, "/class/", subsystem, "/", sysname, NULL); | ||
852 | if (stat(path_full, &statbuf) == 0) | ||
853 | goto found; | ||
854 | out: | ||
855 | return NULL; | ||
856 | found: | ||
857 | return udev_device_new_from_syspath(udev, path_full); | ||
858 | } | ||
859 | |||
860 | /** | ||
861 | * udev_device_new_from_environment | ||
862 | * @udev: udev library context | ||
863 | * | ||
864 | * Create new udev device, and fill in information from the | ||
865 | * current process environment. This only works reliable if | ||
866 | * the process is called from a udev rule. It is usually used | ||
867 | * for tools executed from IMPORT= rules. | ||
868 | * | ||
869 | * The initial refcount is 1, and needs to be decremented to | ||
870 | * release the resources of the udev device. | ||
871 | * | ||
872 | * Returns: a new udev device, or #NULL, if it does not exist | ||
873 | **/ | ||
874 | UDEV_EXPORT struct udev_device *udev_device_new_from_environment(struct udev *udev) | ||
875 | { | ||
876 | int i; | ||
877 | struct udev_device *udev_device; | ||
878 | |||
879 | udev_device = udev_device_new(udev); | ||
880 | if (udev_device == NULL) | ||
881 | return NULL; | ||
882 | udev_device_set_info_loaded(udev_device); | ||
883 | |||
884 | for (i = 0; environ[i] != NULL; i++) | ||
885 | udev_device_add_property_from_string_parse(udev_device, environ[i]); | ||
886 | |||
887 | if (udev_device_add_property_from_string_parse_finish(udev_device) < 0) { | ||
888 | info(udev, "missing values, invalid device\n"); | ||
889 | udev_device_unref(udev_device); | ||
890 | udev_device = NULL; | ||
891 | } | ||
892 | |||
893 | return udev_device; | ||
894 | } | ||
895 | |||
896 | static struct udev_device *device_new_from_parent(struct udev_device *udev_device) | ||
897 | { | ||
898 | struct udev_device *udev_device_parent = NULL; | ||
899 | char path[UTIL_PATH_SIZE]; | ||
900 | const char *subdir; | ||
901 | |||
902 | util_strscpy(path, sizeof(path), udev_device->syspath); | ||
903 | subdir = &path[strlen(udev_get_sys_path(udev_device->udev))+1]; | ||
904 | for (;;) { | ||
905 | char *pos; | ||
906 | |||
907 | pos = strrchr(subdir, '/'); | ||
908 | if (pos == NULL || pos < &subdir[2]) | ||
909 | break; | ||
910 | pos[0] = '\0'; | ||
911 | udev_device_parent = udev_device_new_from_syspath(udev_device->udev, path); | ||
912 | if (udev_device_parent != NULL) | ||
913 | return udev_device_parent; | ||
914 | } | ||
915 | return NULL; | ||
916 | } | ||
917 | |||
918 | /** | ||
919 | * udev_device_get_parent: | ||
920 | * @udev_device: the device to start searching from | ||
921 | * | ||
922 | * Find the next parent device, and fill in information from the sys | ||
923 | * device and the udev database entry. | ||
924 | * | ||
925 | * The returned the device is not referenced. It is attached to the | ||
926 | * child device, and will be cleaned up when the child device | ||
927 | * is cleaned up. | ||
928 | * | ||
929 | * It is not necessarily just the upper level directory, empty or not | ||
930 | * recognized sys directories are ignored. | ||
931 | * | ||
932 | * It can be called as many times as needed, without caring about | ||
933 | * references. | ||
934 | * | ||
935 | * Returns: a new udev device, or #NULL, if it no parent exist. | ||
936 | **/ | ||
937 | UDEV_EXPORT struct udev_device *udev_device_get_parent(struct udev_device *udev_device) | ||
938 | { | ||
939 | if (udev_device == NULL) | ||
940 | return NULL; | ||
941 | if (!udev_device->parent_set) { | ||
942 | udev_device->parent_set = true; | ||
943 | udev_device->parent_device = device_new_from_parent(udev_device); | ||
944 | } | ||
945 | if (udev_device->parent_device != NULL) | ||
946 | dbg(udev_device->udev, "returning existing parent %p\n", udev_device->parent_device); | ||
947 | return udev_device->parent_device; | ||
948 | } | ||
949 | |||
950 | /** | ||
951 | * udev_device_get_parent_with_subsystem_devtype: | ||
952 | * @udev_device: udev device to start searching from | ||
953 | * @subsystem: the subsystem of the device | ||
954 | * @devtype: the type (DEVTYPE) of the device | ||
955 | * | ||
956 | * Find the next parent device, with a matching subsystem and devtype | ||
957 | * value, and fill in information from the sys device and the udev | ||
958 | * database entry. | ||
959 | * | ||
960 | * If devtype is #NULL, only subsystem is checked, and any devtype will | ||
961 | * match. | ||
962 | * | ||
963 | * The returned the device is not referenced. It is attached to the | ||
964 | * child device, and will be cleaned up when the child device | ||
965 | * is cleaned up. | ||
966 | * | ||
967 | * It can be called as many times as needed, without caring about | ||
968 | * references. | ||
969 | * | ||
970 | * Returns: a new udev device, or #NULL if no matching parent exists. | ||
971 | **/ | ||
972 | UDEV_EXPORT struct udev_device *udev_device_get_parent_with_subsystem_devtype(struct udev_device *udev_device, const char *subsystem, const char *devtype) | ||
973 | { | ||
974 | struct udev_device *parent; | ||
975 | |||
976 | if (subsystem == NULL) | ||
977 | return NULL; | ||
978 | |||
979 | parent = udev_device_get_parent(udev_device); | ||
980 | while (parent != NULL) { | ||
981 | const char *parent_subsystem; | ||
982 | const char *parent_devtype; | ||
983 | |||
984 | parent_subsystem = udev_device_get_subsystem(parent); | ||
985 | if (parent_subsystem != NULL && strcmp(parent_subsystem, subsystem) == 0) { | ||
986 | if (devtype == NULL) | ||
987 | break; | ||
988 | parent_devtype = udev_device_get_devtype(parent); | ||
989 | if (parent_devtype != NULL && strcmp(parent_devtype, devtype) == 0) | ||
990 | break; | ||
991 | } | ||
992 | parent = udev_device_get_parent(parent); | ||
993 | } | ||
994 | return parent; | ||
995 | } | ||
996 | |||
997 | /** | ||
998 | * udev_device_get_udev: | ||
999 | * @udev_device: udev device | ||
1000 | * | ||
1001 | * Retrieve the udev library context the device was created with. | ||
1002 | * | ||
1003 | * Returns: the udev library context | ||
1004 | **/ | ||
1005 | UDEV_EXPORT struct udev *udev_device_get_udev(struct udev_device *udev_device) | ||
1006 | { | ||
1007 | if (udev_device == NULL) | ||
1008 | return NULL; | ||
1009 | return udev_device->udev; | ||
1010 | } | ||
1011 | |||
1012 | /** | ||
1013 | * udev_device_ref: | ||
1014 | * @udev_device: udev device | ||
1015 | * | ||
1016 | * Take a reference of a udev device. | ||
1017 | * | ||
1018 | * Returns: the passed udev device | ||
1019 | **/ | ||
1020 | UDEV_EXPORT struct udev_device *udev_device_ref(struct udev_device *udev_device) | ||
1021 | { | ||
1022 | if (udev_device == NULL) | ||
1023 | return NULL; | ||
1024 | udev_device->refcount++; | ||
1025 | return udev_device; | ||
1026 | } | ||
1027 | |||
1028 | /** | ||
1029 | * udev_device_unref: | ||
1030 | * @udev_device: udev device | ||
1031 | * | ||
1032 | * Drop a reference of a udev device. If the refcount reaches zero, | ||
1033 | * the resources of the device will be released. | ||
1034 | * | ||
1035 | **/ | ||
1036 | UDEV_EXPORT void udev_device_unref(struct udev_device *udev_device) | ||
1037 | { | ||
1038 | if (udev_device == NULL) | ||
1039 | return; | ||
1040 | udev_device->refcount--; | ||
1041 | if (udev_device->refcount > 0) | ||
1042 | return; | ||
1043 | if (udev_device->parent_device != NULL) | ||
1044 | udev_device_unref(udev_device->parent_device); | ||
1045 | free(udev_device->syspath); | ||
1046 | free(udev_device->sysname); | ||
1047 | free(udev_device->devnode); | ||
1048 | free(udev_device->subsystem); | ||
1049 | free(udev_device->devtype); | ||
1050 | udev_list_cleanup(&udev_device->devlinks_list); | ||
1051 | udev_list_cleanup(&udev_device->properties_list); | ||
1052 | udev_list_cleanup(&udev_device->sysattr_value_list); | ||
1053 | udev_list_cleanup(&udev_device->sysattr_list); | ||
1054 | udev_list_cleanup(&udev_device->tags_list); | ||
1055 | free(udev_device->action); | ||
1056 | free(udev_device->driver); | ||
1057 | free(udev_device->devpath_old); | ||
1058 | free(udev_device->id_filename); | ||
1059 | free(udev_device->envp); | ||
1060 | free(udev_device->monitor_buf); | ||
1061 | dbg(udev_device->udev, "udev_device: %p released\n", udev_device); | ||
1062 | free(udev_device); | ||
1063 | } | ||
1064 | |||
1065 | /** | ||
1066 | * udev_device_get_devpath: | ||
1067 | * @udev_device: udev device | ||
1068 | * | ||
1069 | * Retrieve the kernel devpath value of the udev device. The path | ||
1070 | * does not contain the sys mount point, and starts with a '/'. | ||
1071 | * | ||
1072 | * Returns: the devpath of the udev device | ||
1073 | **/ | ||
1074 | UDEV_EXPORT const char *udev_device_get_devpath(struct udev_device *udev_device) | ||
1075 | { | ||
1076 | if (udev_device == NULL) | ||
1077 | return NULL; | ||
1078 | return udev_device->devpath; | ||
1079 | } | ||
1080 | |||
1081 | /** | ||
1082 | * udev_device_get_syspath: | ||
1083 | * @udev_device: udev device | ||
1084 | * | ||
1085 | * Retrieve the sys path of the udev device. The path is an | ||
1086 | * absolute path and starts with the sys mount point. | ||
1087 | * | ||
1088 | * Returns: the sys path of the udev device | ||
1089 | **/ | ||
1090 | UDEV_EXPORT const char *udev_device_get_syspath(struct udev_device *udev_device) | ||
1091 | { | ||
1092 | if (udev_device == NULL) | ||
1093 | return NULL; | ||
1094 | return udev_device->syspath; | ||
1095 | } | ||
1096 | |||
1097 | /** | ||
1098 | * udev_device_get_sysname: | ||
1099 | * @udev_device: udev device | ||
1100 | * | ||
1101 | * Returns: the sys name of the device device | ||
1102 | **/ | ||
1103 | UDEV_EXPORT const char *udev_device_get_sysname(struct udev_device *udev_device) | ||
1104 | { | ||
1105 | if (udev_device == NULL) | ||
1106 | return NULL; | ||
1107 | return udev_device->sysname; | ||
1108 | } | ||
1109 | |||
1110 | /** | ||
1111 | * udev_device_get_sysnum: | ||
1112 | * @udev_device: udev device | ||
1113 | * | ||
1114 | * Returns: the trailing number of of the device name | ||
1115 | **/ | ||
1116 | UDEV_EXPORT const char *udev_device_get_sysnum(struct udev_device *udev_device) | ||
1117 | { | ||
1118 | if (udev_device == NULL) | ||
1119 | return NULL; | ||
1120 | return udev_device->sysnum; | ||
1121 | } | ||
1122 | |||
1123 | /** | ||
1124 | * udev_device_get_devnode: | ||
1125 | * @udev_device: udev device | ||
1126 | * | ||
1127 | * Retrieve the device node file name belonging to the udev device. | ||
1128 | * The path is an absolute path, and starts with the device directory. | ||
1129 | * | ||
1130 | * Returns: the device node file name of the udev device, or #NULL if no device node exists | ||
1131 | **/ | ||
1132 | UDEV_EXPORT const char *udev_device_get_devnode(struct udev_device *udev_device) | ||
1133 | { | ||
1134 | if (udev_device == NULL) | ||
1135 | return NULL; | ||
1136 | if (udev_device->devnode != NULL) | ||
1137 | return udev_device->devnode; | ||
1138 | if (!udev_device->info_loaded) | ||
1139 | udev_device_read_uevent_file(udev_device); | ||
1140 | return udev_device->devnode; | ||
1141 | } | ||
1142 | |||
1143 | /** | ||
1144 | * udev_device_get_devlinks_list_entry: | ||
1145 | * @udev_device: udev device | ||
1146 | * | ||
1147 | * Retrieve the list of device links pointing to the device file of | ||
1148 | * the udev device. The next list entry can be retrieved with | ||
1149 | * udev_list_entry_next(), which returns #NULL if no more entries exist. | ||
1150 | * The devlink path can be retrieved from the list entry by | ||
1151 | * udev_list_entry_get_name(). The path is an absolute path, and starts with | ||
1152 | * the device directory. | ||
1153 | * | ||
1154 | * Returns: the first entry of the device node link list | ||
1155 | **/ | ||
1156 | UDEV_EXPORT struct udev_list_entry *udev_device_get_devlinks_list_entry(struct udev_device *udev_device) | ||
1157 | { | ||
1158 | if (udev_device == NULL) | ||
1159 | return NULL; | ||
1160 | if (!udev_device->info_loaded) | ||
1161 | udev_device_read_db(udev_device, NULL); | ||
1162 | return udev_list_get_entry(&udev_device->devlinks_list); | ||
1163 | } | ||
1164 | |||
1165 | void udev_device_cleanup_devlinks_list(struct udev_device *udev_device) | ||
1166 | { | ||
1167 | udev_device->devlinks_uptodate = false; | ||
1168 | udev_list_cleanup(&udev_device->devlinks_list); | ||
1169 | } | ||
1170 | |||
1171 | /** | ||
1172 | * udev_device_get_properties_list_entry: | ||
1173 | * @udev_device: udev device | ||
1174 | * | ||
1175 | * Retrieve the list of key/value device properties of the udev | ||
1176 | * device. The next list entry can be retrieved with udev_list_entry_next(), | ||
1177 | * which returns #NULL if no more entries exist. The property name | ||
1178 | * can be retrieved from the list entry by udev_list_get_name(), | ||
1179 | * the property value by udev_list_get_value(). | ||
1180 | * | ||
1181 | * Returns: the first entry of the property list | ||
1182 | **/ | ||
1183 | UDEV_EXPORT struct udev_list_entry *udev_device_get_properties_list_entry(struct udev_device *udev_device) | ||
1184 | { | ||
1185 | if (udev_device == NULL) | ||
1186 | return NULL; | ||
1187 | if (!udev_device->info_loaded) { | ||
1188 | udev_device_read_uevent_file(udev_device); | ||
1189 | udev_device_read_db(udev_device, NULL); | ||
1190 | } | ||
1191 | if (!udev_device->devlinks_uptodate) { | ||
1192 | char symlinks[UTIL_PATH_SIZE]; | ||
1193 | struct udev_list_entry *list_entry; | ||
1194 | |||
1195 | udev_device->devlinks_uptodate = true; | ||
1196 | list_entry = udev_device_get_devlinks_list_entry(udev_device); | ||
1197 | if (list_entry != NULL) { | ||
1198 | char *s; | ||
1199 | size_t l; | ||
1200 | |||
1201 | s = symlinks; | ||
1202 | l = util_strpcpyl(&s, sizeof(symlinks), udev_list_entry_get_name(list_entry), NULL); | ||
1203 | udev_list_entry_foreach(list_entry, udev_list_entry_get_next(list_entry)) | ||
1204 | l = util_strpcpyl(&s, l, " ", udev_list_entry_get_name(list_entry), NULL); | ||
1205 | udev_device_add_property(udev_device, "DEVLINKS", symlinks); | ||
1206 | } | ||
1207 | } | ||
1208 | if (!udev_device->tags_uptodate) { | ||
1209 | udev_device->tags_uptodate = true; | ||
1210 | if (udev_device_get_tags_list_entry(udev_device) != NULL) { | ||
1211 | char tags[UTIL_PATH_SIZE]; | ||
1212 | struct udev_list_entry *list_entry; | ||
1213 | char *s; | ||
1214 | size_t l; | ||
1215 | |||
1216 | s = tags; | ||
1217 | l = util_strpcpyl(&s, sizeof(tags), ":", NULL); | ||
1218 | udev_list_entry_foreach(list_entry, udev_device_get_tags_list_entry(udev_device)) | ||
1219 | l = util_strpcpyl(&s, l, udev_list_entry_get_name(list_entry), ":", NULL); | ||
1220 | udev_device_add_property(udev_device, "TAGS", tags); | ||
1221 | } | ||
1222 | } | ||
1223 | return udev_list_get_entry(&udev_device->properties_list); | ||
1224 | } | ||
1225 | |||
1226 | /** | ||
1227 | * udev_device_get_action: | ||
1228 | * @udev_device: udev device | ||
1229 | * | ||
1230 | * This is only valid if the device was received through a monitor. Devices read from | ||
1231 | * sys do not have an action string. Usual actions are: add, remove, change, online, | ||
1232 | * offline. | ||
1233 | * | ||
1234 | * Returns: the kernel action value, or #NULL if there is no action value available. | ||
1235 | **/ | ||
1236 | UDEV_EXPORT const char *udev_device_get_action(struct udev_device *udev_device) | ||
1237 | { | ||
1238 | if (udev_device == NULL) | ||
1239 | return NULL; | ||
1240 | return udev_device->action; | ||
1241 | } | ||
1242 | |||
1243 | /** | ||
1244 | * udev_device_get_usec_since_initialized: | ||
1245 | * @udev_device: udev device | ||
1246 | * | ||
1247 | * Return the number of microseconds passed since udev set up the | ||
1248 | * device for the first time. | ||
1249 | * | ||
1250 | * This is only implemented for devices with need to store properties | ||
1251 | * in the udev database. All other devices return 0 here. | ||
1252 | * | ||
1253 | * Returns: the number of microseconds since the device was first seen. | ||
1254 | **/ | ||
1255 | UDEV_EXPORT unsigned long long int udev_device_get_usec_since_initialized(struct udev_device *udev_device) | ||
1256 | { | ||
1257 | unsigned long long now; | ||
1258 | |||
1259 | if (udev_device == NULL) | ||
1260 | return 0; | ||
1261 | if (!udev_device->info_loaded) | ||
1262 | udev_device_read_db(udev_device, NULL); | ||
1263 | if (udev_device->usec_initialized == 0) | ||
1264 | return 0; | ||
1265 | now = now_usec(); | ||
1266 | if (now == 0) | ||
1267 | return 0; | ||
1268 | return now - udev_device->usec_initialized; | ||
1269 | } | ||
1270 | |||
1271 | unsigned long long udev_device_get_usec_initialized(struct udev_device *udev_device) | ||
1272 | { | ||
1273 | return udev_device->usec_initialized; | ||
1274 | } | ||
1275 | |||
1276 | void udev_device_set_usec_initialized(struct udev_device *udev_device, unsigned long long usec_initialized) | ||
1277 | { | ||
1278 | char num[32]; | ||
1279 | |||
1280 | udev_device->usec_initialized = usec_initialized; | ||
1281 | snprintf(num, sizeof(num), "%llu", usec_initialized); | ||
1282 | udev_device_add_property(udev_device, "USEC_INITIALIZED", num); | ||
1283 | } | ||
1284 | |||
1285 | /** | ||
1286 | * udev_device_get_sysattr_value: | ||
1287 | * @udev_device: udev device | ||
1288 | * @sysattr: attribute name | ||
1289 | * | ||
1290 | * The retrieved value is cached in the device. Repeated calls will return the same | ||
1291 | * value and not open the attribute again. | ||
1292 | * | ||
1293 | * Returns: the content of a sys attribute file, or #NULL if there is no sys attribute value. | ||
1294 | **/ | ||
1295 | UDEV_EXPORT const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const char *sysattr) | ||
1296 | { | ||
1297 | struct udev_list_entry *list_entry; | ||
1298 | char path[UTIL_PATH_SIZE]; | ||
1299 | char value[4096]; | ||
1300 | struct stat statbuf; | ||
1301 | int fd; | ||
1302 | ssize_t size; | ||
1303 | const char *val = NULL; | ||
1304 | |||
1305 | if (udev_device == NULL) | ||
1306 | return NULL; | ||
1307 | if (sysattr == NULL) | ||
1308 | return NULL; | ||
1309 | |||
1310 | /* look for possibly already cached result */ | ||
1311 | list_entry = udev_list_get_entry(&udev_device->sysattr_value_list); | ||
1312 | list_entry = udev_list_entry_get_by_name(list_entry, sysattr); | ||
1313 | if (list_entry != NULL) { | ||
1314 | dbg(udev_device->udev, "got '%s' (%s) from cache\n", | ||
1315 | sysattr, udev_list_entry_get_value(list_entry)); | ||
1316 | return udev_list_entry_get_value(list_entry); | ||
1317 | } | ||
1318 | |||
1319 | util_strscpyl(path, sizeof(path), udev_device_get_syspath(udev_device), "/", sysattr, NULL); | ||
1320 | if (lstat(path, &statbuf) != 0) { | ||
1321 | dbg(udev_device->udev, "no attribute '%s', keep negative entry\n", path); | ||
1322 | udev_list_entry_add(&udev_device->sysattr_value_list, sysattr, NULL); | ||
1323 | goto out; | ||
1324 | } | ||
1325 | |||
1326 | if (S_ISLNK(statbuf.st_mode)) { | ||
1327 | struct udev_device *dev; | ||
1328 | |||
1329 | /* | ||
1330 | * Some core links return only the last element of the target path, | ||
1331 | * these are just values, the paths should not be exposed. | ||
1332 | */ | ||
1333 | if (strcmp(sysattr, "driver") == 0 || | ||
1334 | strcmp(sysattr, "subsystem") == 0 || | ||
1335 | strcmp(sysattr, "module") == 0) { | ||
1336 | if (util_get_sys_core_link_value(udev_device->udev, sysattr, | ||
1337 | udev_device->syspath, value, sizeof(value)) < 0) | ||
1338 | return NULL; | ||
1339 | dbg(udev_device->udev, "cache '%s' with link value '%s'\n", sysattr, value); | ||
1340 | list_entry = udev_list_entry_add(&udev_device->sysattr_value_list, sysattr, value); | ||
1341 | val = udev_list_entry_get_value(list_entry); | ||
1342 | goto out; | ||
1343 | } | ||
1344 | |||
1345 | /* resolve link to a device and return its syspath */ | ||
1346 | util_strscpyl(path, sizeof(path), udev_device->syspath, "/", sysattr, NULL); | ||
1347 | dev = udev_device_new_from_syspath(udev_device->udev, path); | ||
1348 | if (dev != NULL) { | ||
1349 | list_entry = udev_list_entry_add(&udev_device->sysattr_value_list, sysattr, | ||
1350 | udev_device_get_syspath(dev)); | ||
1351 | val = udev_list_entry_get_value(list_entry); | ||
1352 | udev_device_unref(dev); | ||
1353 | } | ||
1354 | |||
1355 | goto out; | ||
1356 | } | ||
1357 | |||
1358 | /* skip directories */ | ||
1359 | if (S_ISDIR(statbuf.st_mode)) | ||
1360 | goto out; | ||
1361 | |||
1362 | /* skip non-readable files */ | ||
1363 | if ((statbuf.st_mode & S_IRUSR) == 0) | ||
1364 | goto out; | ||
1365 | |||
1366 | /* read attribute value */ | ||
1367 | fd = open(path, O_RDONLY|O_CLOEXEC); | ||
1368 | if (fd < 0) { | ||
1369 | dbg(udev_device->udev, "attribute '%s' can not be opened\n", path); | ||
1370 | goto out; | ||
1371 | } | ||
1372 | size = read(fd, value, sizeof(value)); | ||
1373 | close(fd); | ||
1374 | if (size < 0) | ||
1375 | goto out; | ||
1376 | if (size == sizeof(value)) | ||
1377 | goto out; | ||
1378 | |||
1379 | /* got a valid value, store it in cache and return it */ | ||
1380 | value[size] = '\0'; | ||
1381 | util_remove_trailing_chars(value, '\n'); | ||
1382 | dbg(udev_device->udev, "'%s' has attribute value '%s'\n", path, value); | ||
1383 | list_entry = udev_list_entry_add(&udev_device->sysattr_value_list, sysattr, value); | ||
1384 | val = udev_list_entry_get_value(list_entry); | ||
1385 | out: | ||
1386 | return val; | ||
1387 | } | ||
1388 | |||
1389 | static int udev_device_sysattr_list_read(struct udev_device *udev_device) | ||
1390 | { | ||
1391 | struct dirent *dent; | ||
1392 | DIR *dir; | ||
1393 | int num = 0; | ||
1394 | |||
1395 | if (udev_device == NULL) | ||
1396 | return -1; | ||
1397 | if (udev_device->sysattr_list_read) | ||
1398 | return 0; | ||
1399 | |||
1400 | dir = opendir(udev_device_get_syspath(udev_device)); | ||
1401 | if (!dir) { | ||
1402 | dbg(udev_device->udev, "sysfs dir '%s' can not be opened\n", | ||
1403 | udev_device_get_syspath(udev_device)); | ||
1404 | return -1; | ||
1405 | } | ||
1406 | |||
1407 | for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { | ||
1408 | char path[UTIL_PATH_SIZE]; | ||
1409 | struct stat statbuf; | ||
1410 | |||
1411 | /* only handle symlinks and regular files */ | ||
1412 | if (dent->d_type != DT_LNK && dent->d_type != DT_REG) | ||
1413 | continue; | ||
1414 | |||
1415 | util_strscpyl(path, sizeof(path), udev_device_get_syspath(udev_device), "/", dent->d_name, NULL); | ||
1416 | if (lstat(path, &statbuf) != 0) | ||
1417 | continue; | ||
1418 | if ((statbuf.st_mode & S_IRUSR) == 0) | ||
1419 | continue; | ||
1420 | |||
1421 | udev_list_entry_add(&udev_device->sysattr_list, dent->d_name, NULL); | ||
1422 | num++; | ||
1423 | } | ||
1424 | |||
1425 | closedir(dir); | ||
1426 | dbg(udev_device->udev, "found %d sysattrs for '%s'\n", num, udev_device_get_syspath(udev_device)); | ||
1427 | udev_device->sysattr_list_read = true; | ||
1428 | |||
1429 | return num; | ||
1430 | } | ||
1431 | |||
1432 | /** | ||
1433 | * udev_device_get_sysattr_list_entry: | ||
1434 | * @udev_device: udev device | ||
1435 | * | ||
1436 | * Retrieve the list of available sysattrs, with value being empty; | ||
1437 | * This just return all available sysfs attributes for a particular | ||
1438 | * device without reading their values. | ||
1439 | * | ||
1440 | * Returns: the first entry of the property list | ||
1441 | **/ | ||
1442 | UDEV_EXPORT struct udev_list_entry *udev_device_get_sysattr_list_entry(struct udev_device *udev_device) | ||
1443 | { | ||
1444 | if (!udev_device->sysattr_list_read) { | ||
1445 | int ret; | ||
1446 | ret = udev_device_sysattr_list_read(udev_device); | ||
1447 | if (0 > ret) | ||
1448 | return NULL; | ||
1449 | } | ||
1450 | |||
1451 | return udev_list_get_entry(&udev_device->sysattr_list); | ||
1452 | } | ||
1453 | |||
1454 | int udev_device_set_syspath(struct udev_device *udev_device, const char *syspath) | ||
1455 | { | ||
1456 | const char *pos; | ||
1457 | size_t len; | ||
1458 | |||
1459 | free(udev_device->syspath); | ||
1460 | udev_device->syspath = strdup(syspath); | ||
1461 | if (udev_device->syspath == NULL) | ||
1462 | return -ENOMEM; | ||
1463 | udev_device->devpath = &udev_device->syspath[strlen(udev_get_sys_path(udev_device->udev))]; | ||
1464 | udev_device_add_property(udev_device, "DEVPATH", udev_device->devpath); | ||
1465 | |||
1466 | pos = strrchr(udev_device->syspath, '/'); | ||
1467 | if (pos == NULL) | ||
1468 | return -EINVAL; | ||
1469 | udev_device->sysname = strdup(&pos[1]); | ||
1470 | if (udev_device->sysname == NULL) | ||
1471 | return -ENOMEM; | ||
1472 | |||
1473 | /* some devices have '!' in their name, change that to '/' */ | ||
1474 | len = 0; | ||
1475 | while (udev_device->sysname[len] != '\0') { | ||
1476 | if (udev_device->sysname[len] == '!') | ||
1477 | udev_device->sysname[len] = '/'; | ||
1478 | len++; | ||
1479 | } | ||
1480 | |||
1481 | /* trailing number */ | ||
1482 | while (len > 0 && isdigit(udev_device->sysname[--len])) | ||
1483 | udev_device->sysnum = &udev_device->sysname[len]; | ||
1484 | |||
1485 | /* sysname is completely numeric */ | ||
1486 | if (len == 0) | ||
1487 | udev_device->sysnum = NULL; | ||
1488 | |||
1489 | return 0; | ||
1490 | } | ||
1491 | |||
1492 | int udev_device_set_devnode(struct udev_device *udev_device, const char *devnode) | ||
1493 | { | ||
1494 | free(udev_device->devnode); | ||
1495 | if (devnode[0] != '/') { | ||
1496 | if (asprintf(&udev_device->devnode, "%s/%s", udev_get_dev_path(udev_device->udev), devnode) < 0) | ||
1497 | udev_device->devnode = NULL; | ||
1498 | } else { | ||
1499 | udev_device->devnode = strdup(devnode); | ||
1500 | } | ||
1501 | if (udev_device->devnode == NULL) | ||
1502 | return -ENOMEM; | ||
1503 | udev_device_add_property(udev_device, "DEVNAME", udev_device->devnode); | ||
1504 | return 0; | ||
1505 | } | ||
1506 | |||
1507 | int udev_device_add_devlink(struct udev_device *udev_device, const char *devlink, int unique) | ||
1508 | { | ||
1509 | struct udev_list_entry *list_entry; | ||
1510 | |||
1511 | udev_device->devlinks_uptodate = false; | ||
1512 | list_entry = udev_list_entry_add(&udev_device->devlinks_list, devlink, NULL); | ||
1513 | if (list_entry == NULL) | ||
1514 | return -ENOMEM; | ||
1515 | if (unique) | ||
1516 | udev_list_entry_set_num(list_entry, true); | ||
1517 | return 0; | ||
1518 | } | ||
1519 | |||
1520 | const char *udev_device_get_id_filename(struct udev_device *udev_device) | ||
1521 | { | ||
1522 | if (udev_device->id_filename == NULL) { | ||
1523 | if (udev_device_get_subsystem(udev_device) == NULL) | ||
1524 | return NULL; | ||
1525 | |||
1526 | if (major(udev_device_get_devnum(udev_device)) > 0) { | ||
1527 | /* use dev_t -- b259:131072, c254:0 */ | ||
1528 | if (asprintf(&udev_device->id_filename, "%c%u:%u", | ||
1529 | strcmp(udev_device_get_subsystem(udev_device), "block") == 0 ? 'b' : 'c', | ||
1530 | major(udev_device_get_devnum(udev_device)), | ||
1531 | minor(udev_device_get_devnum(udev_device))) < 0) | ||
1532 | udev_device->id_filename = NULL; | ||
1533 | } else if (udev_device_get_ifindex(udev_device) > 0) { | ||
1534 | /* use netdev ifindex -- n3 */ | ||
1535 | if (asprintf(&udev_device->id_filename, "n%u", udev_device_get_ifindex(udev_device)) < 0) | ||
1536 | udev_device->id_filename = NULL; | ||
1537 | } else { | ||
1538 | /* | ||
1539 | * use $subsys:$syname -- pci:0000:00:1f.2 | ||
1540 | * sysname() has '!' translated, get it from devpath | ||
1541 | */ | ||
1542 | const char *sysname; | ||
1543 | sysname = strrchr(udev_device->devpath, '/'); | ||
1544 | if (sysname == NULL) | ||
1545 | return NULL; | ||
1546 | sysname = &sysname[1]; | ||
1547 | if (asprintf(&udev_device->id_filename, "+%s:%s", udev_device_get_subsystem(udev_device), sysname) < 0) | ||
1548 | udev_device->id_filename = NULL; | ||
1549 | } | ||
1550 | } | ||
1551 | return udev_device->id_filename; | ||
1552 | } | ||
1553 | |||
1554 | /** | ||
1555 | * udev_device_get_is_initialized: | ||
1556 | * @udev_device: udev device | ||
1557 | * | ||
1558 | * Check if udev has already handled the device and has set up | ||
1559 | * device node permissions and context, or has renamed a network | ||
1560 | * device. | ||
1561 | * | ||
1562 | * This is only implemented for devices with a device node | ||
1563 | * or network interfaces. All other devices return 1 here. | ||
1564 | * | ||
1565 | * Returns: 1 if the device is set up. 0 otherwise. | ||
1566 | **/ | ||
1567 | UDEV_EXPORT int udev_device_get_is_initialized(struct udev_device *udev_device) | ||
1568 | { | ||
1569 | if (!udev_device->info_loaded) | ||
1570 | udev_device_read_db(udev_device, NULL); | ||
1571 | return udev_device->is_initialized; | ||
1572 | } | ||
1573 | |||
1574 | void udev_device_set_is_initialized(struct udev_device *udev_device) | ||
1575 | { | ||
1576 | udev_device->is_initialized = true; | ||
1577 | } | ||
1578 | |||
1579 | int udev_device_add_tag(struct udev_device *udev_device, const char *tag) | ||
1580 | { | ||
1581 | if (strchr(tag, ':') != NULL || strchr(tag, ' ') != NULL) | ||
1582 | return -EINVAL; | ||
1583 | udev_device->tags_uptodate = false; | ||
1584 | if (udev_list_entry_add(&udev_device->tags_list, tag, NULL) != NULL) | ||
1585 | return 0; | ||
1586 | return -ENOMEM; | ||
1587 | } | ||
1588 | |||
1589 | void udev_device_cleanup_tags_list(struct udev_device *udev_device) | ||
1590 | { | ||
1591 | udev_device->tags_uptodate = false; | ||
1592 | udev_list_cleanup(&udev_device->tags_list); | ||
1593 | } | ||
1594 | |||
1595 | /** | ||
1596 | * udev_device_get_tags_list_entry: | ||
1597 | * @udev_device: udev device | ||
1598 | * | ||
1599 | * Retrieve the list of tags attached to the udev device. The next | ||
1600 | * list entry can be retrieved with udev_list_entry_next(), | ||
1601 | * which returns #NULL if no more entries exist. The tag string | ||
1602 | * can be retrieved from the list entry by udev_list_get_name(). | ||
1603 | * | ||
1604 | * Returns: the first entry of the tag list | ||
1605 | **/ | ||
1606 | UDEV_EXPORT struct udev_list_entry *udev_device_get_tags_list_entry(struct udev_device *udev_device) | ||
1607 | { | ||
1608 | if (udev_device == NULL) | ||
1609 | return NULL; | ||
1610 | if (!udev_device->info_loaded) | ||
1611 | udev_device_read_db(udev_device, NULL); | ||
1612 | return udev_list_get_entry(&udev_device->tags_list); | ||
1613 | } | ||
1614 | |||
1615 | UDEV_EXPORT int udev_device_has_tag(struct udev_device *udev_device, const char *tag) | ||
1616 | { | ||
1617 | struct udev_list_entry *list_entry; | ||
1618 | |||
1619 | if (udev_device == NULL) | ||
1620 | return false; | ||
1621 | if (!udev_device->info_loaded) | ||
1622 | udev_device_read_db(udev_device, NULL); | ||
1623 | list_entry = udev_device_get_tags_list_entry(udev_device); | ||
1624 | if (udev_list_entry_get_by_name(list_entry, tag) != NULL) | ||
1625 | return true; | ||
1626 | return false; | ||
1627 | } | ||
1628 | |||
1629 | #define ENVP_SIZE 128 | ||
1630 | #define MONITOR_BUF_SIZE 4096 | ||
1631 | static int update_envp_monitor_buf(struct udev_device *udev_device) | ||
1632 | { | ||
1633 | struct udev_list_entry *list_entry; | ||
1634 | char *s; | ||
1635 | size_t l; | ||
1636 | unsigned int i; | ||
1637 | |||
1638 | /* monitor buffer of property strings */ | ||
1639 | free(udev_device->monitor_buf); | ||
1640 | udev_device->monitor_buf_len = 0; | ||
1641 | udev_device->monitor_buf = malloc(MONITOR_BUF_SIZE); | ||
1642 | if (udev_device->monitor_buf == NULL) | ||
1643 | return -ENOMEM; | ||
1644 | |||
1645 | /* envp array, strings will point into monitor buffer */ | ||
1646 | if (udev_device->envp == NULL) | ||
1647 | udev_device->envp = malloc(sizeof(char *) * ENVP_SIZE); | ||
1648 | if (udev_device->envp == NULL) | ||
1649 | return -ENOMEM; | ||
1650 | |||
1651 | i = 0; | ||
1652 | s = udev_device->monitor_buf; | ||
1653 | l = MONITOR_BUF_SIZE; | ||
1654 | udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(udev_device)) { | ||
1655 | const char *key; | ||
1656 | |||
1657 | key = udev_list_entry_get_name(list_entry); | ||
1658 | /* skip private variables */ | ||
1659 | if (key[0] == '.') | ||
1660 | continue; | ||
1661 | |||
1662 | /* add string to envp array */ | ||
1663 | udev_device->envp[i++] = s; | ||
1664 | if (i+1 >= ENVP_SIZE) | ||
1665 | return -EINVAL; | ||
1666 | |||
1667 | /* add property string to monitor buffer */ | ||
1668 | l = util_strpcpyl(&s, l, key, "=", udev_list_entry_get_value(list_entry), NULL); | ||
1669 | if (l == 0) | ||
1670 | return -EINVAL; | ||
1671 | /* advance past the trailing '\0' that util_strpcpyl() guarantees */ | ||
1672 | s++; | ||
1673 | l--; | ||
1674 | } | ||
1675 | udev_device->envp[i] = NULL; | ||
1676 | udev_device->monitor_buf_len = s - udev_device->monitor_buf; | ||
1677 | udev_device->envp_uptodate = true; | ||
1678 | dbg(udev_device->udev, "filled envp/monitor buffer, %u properties, %zu bytes\n", | ||
1679 | i, udev_device->monitor_buf_len); | ||
1680 | return 0; | ||
1681 | } | ||
1682 | |||
1683 | char **udev_device_get_properties_envp(struct udev_device *udev_device) | ||
1684 | { | ||
1685 | if (!udev_device->envp_uptodate) | ||
1686 | if (update_envp_monitor_buf(udev_device) != 0) | ||
1687 | return NULL; | ||
1688 | return udev_device->envp; | ||
1689 | } | ||
1690 | |||
1691 | ssize_t udev_device_get_properties_monitor_buf(struct udev_device *udev_device, const char **buf) | ||
1692 | { | ||
1693 | if (!udev_device->envp_uptodate) | ||
1694 | if (update_envp_monitor_buf(udev_device) != 0) | ||
1695 | return -EINVAL; | ||
1696 | *buf = udev_device->monitor_buf; | ||
1697 | return udev_device->monitor_buf_len; | ||
1698 | } | ||
1699 | |||
1700 | int udev_device_set_action(struct udev_device *udev_device, const char *action) | ||
1701 | { | ||
1702 | free(udev_device->action); | ||
1703 | udev_device->action = strdup(action); | ||
1704 | if (udev_device->action == NULL) | ||
1705 | return -ENOMEM; | ||
1706 | udev_device_add_property(udev_device, "ACTION", udev_device->action); | ||
1707 | return 0; | ||
1708 | } | ||
1709 | |||
1710 | int udev_device_get_devlink_priority(struct udev_device *udev_device) | ||
1711 | { | ||
1712 | if (!udev_device->info_loaded) | ||
1713 | udev_device_read_db(udev_device, NULL); | ||
1714 | return udev_device->devlink_priority; | ||
1715 | } | ||
1716 | |||
1717 | int udev_device_set_devlink_priority(struct udev_device *udev_device, int prio) | ||
1718 | { | ||
1719 | udev_device->devlink_priority = prio; | ||
1720 | return 0; | ||
1721 | } | ||
1722 | |||
1723 | int udev_device_get_watch_handle(struct udev_device *udev_device) | ||
1724 | { | ||
1725 | if (!udev_device->info_loaded) | ||
1726 | udev_device_read_db(udev_device, NULL); | ||
1727 | return udev_device->watch_handle; | ||
1728 | } | ||
1729 | |||
1730 | int udev_device_set_watch_handle(struct udev_device *udev_device, int handle) | ||
1731 | { | ||
1732 | udev_device->watch_handle = handle; | ||
1733 | return 0; | ||
1734 | } | ||
1735 | |||
1736 | bool udev_device_get_db_persist(struct udev_device *udev_device) | ||
1737 | { | ||
1738 | return udev_device->db_persist; | ||
1739 | } | ||
1740 | |||
1741 | void udev_device_set_db_persist(struct udev_device *udev_device) | ||
1742 | { | ||
1743 | udev_device->db_persist = true; | ||
1744 | } | ||
diff --git a/src/udev/src/libudev-enumerate.c b/src/udev/src/libudev-enumerate.c new file mode 100644 index 000000000..034d96feb --- /dev/null +++ b/src/udev/src/libudev-enumerate.c | |||
@@ -0,0 +1,947 @@ | |||
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 | * Returns: an enumeration context | ||
69 | **/ | ||
70 | UDEV_EXPORT struct udev_enumerate *udev_enumerate_new(struct udev *udev) | ||
71 | { | ||
72 | struct udev_enumerate *udev_enumerate; | ||
73 | |||
74 | udev_enumerate = calloc(1, sizeof(struct udev_enumerate)); | ||
75 | if (udev_enumerate == NULL) | ||
76 | return NULL; | ||
77 | udev_enumerate->refcount = 1; | ||
78 | udev_enumerate->udev = udev; | ||
79 | udev_list_init(udev, &udev_enumerate->sysattr_match_list, false); | ||
80 | udev_list_init(udev, &udev_enumerate->sysattr_nomatch_list, false); | ||
81 | udev_list_init(udev, &udev_enumerate->subsystem_match_list, true); | ||
82 | udev_list_init(udev, &udev_enumerate->subsystem_nomatch_list, true); | ||
83 | udev_list_init(udev, &udev_enumerate->sysname_match_list, true); | ||
84 | udev_list_init(udev, &udev_enumerate->properties_match_list, false); | ||
85 | udev_list_init(udev, &udev_enumerate->tags_match_list, true); | ||
86 | udev_list_init(udev, &udev_enumerate->devices_list, false); | ||
87 | return udev_enumerate; | ||
88 | } | ||
89 | |||
90 | /** | ||
91 | * udev_enumerate_ref: | ||
92 | * @udev_enumerate: context | ||
93 | * | ||
94 | * Take a reference of a enumeration context. | ||
95 | * | ||
96 | * Returns: the passed enumeration context | ||
97 | **/ | ||
98 | UDEV_EXPORT struct udev_enumerate *udev_enumerate_ref(struct udev_enumerate *udev_enumerate) | ||
99 | { | ||
100 | if (udev_enumerate == NULL) | ||
101 | return NULL; | ||
102 | udev_enumerate->refcount++; | ||
103 | return udev_enumerate; | ||
104 | } | ||
105 | |||
106 | /** | ||
107 | * udev_enumerate_unref: | ||
108 | * @udev_enumerate: context | ||
109 | * | ||
110 | * Drop a reference of an enumeration context. If the refcount reaches zero, | ||
111 | * all resources of the enumeration context will be released. | ||
112 | **/ | ||
113 | UDEV_EXPORT void udev_enumerate_unref(struct udev_enumerate *udev_enumerate) | ||
114 | { | ||
115 | unsigned int i; | ||
116 | |||
117 | if (udev_enumerate == NULL) | ||
118 | return; | ||
119 | udev_enumerate->refcount--; | ||
120 | if (udev_enumerate->refcount > 0) | ||
121 | return; | ||
122 | udev_list_cleanup(&udev_enumerate->sysattr_match_list); | ||
123 | udev_list_cleanup(&udev_enumerate->sysattr_nomatch_list); | ||
124 | udev_list_cleanup(&udev_enumerate->subsystem_match_list); | ||
125 | udev_list_cleanup(&udev_enumerate->subsystem_nomatch_list); | ||
126 | udev_list_cleanup(&udev_enumerate->sysname_match_list); | ||
127 | udev_list_cleanup(&udev_enumerate->properties_match_list); | ||
128 | udev_list_cleanup(&udev_enumerate->tags_match_list); | ||
129 | udev_device_unref(udev_enumerate->parent_match); | ||
130 | udev_list_cleanup(&udev_enumerate->devices_list); | ||
131 | for (i = 0; i < udev_enumerate->devices_cur; i++) | ||
132 | free(udev_enumerate->devices[i].syspath); | ||
133 | free(udev_enumerate->devices); | ||
134 | free(udev_enumerate); | ||
135 | } | ||
136 | |||
137 | /** | ||
138 | * udev_enumerate_get_udev: | ||
139 | * @udev_enumerate: context | ||
140 | * | ||
141 | * Returns: the udev library context. | ||
142 | */ | ||
143 | UDEV_EXPORT struct udev *udev_enumerate_get_udev(struct udev_enumerate *udev_enumerate) | ||
144 | { | ||
145 | if (udev_enumerate == NULL) | ||
146 | return NULL; | ||
147 | return udev_enumerate->udev; | ||
148 | } | ||
149 | |||
150 | static int syspath_add(struct udev_enumerate *udev_enumerate, const char *syspath) | ||
151 | { | ||
152 | char *path; | ||
153 | struct syspath *entry; | ||
154 | |||
155 | /* double array size if needed */ | ||
156 | if (udev_enumerate->devices_cur >= udev_enumerate->devices_max) { | ||
157 | struct syspath *buf; | ||
158 | unsigned int add; | ||
159 | |||
160 | add = udev_enumerate->devices_max; | ||
161 | if (add < 1024) | ||
162 | add = 1024; | ||
163 | buf = realloc(udev_enumerate->devices, (udev_enumerate->devices_max + add) * sizeof(struct syspath)); | ||
164 | if (buf == NULL) | ||
165 | return -ENOMEM; | ||
166 | udev_enumerate->devices = buf; | ||
167 | udev_enumerate->devices_max += add; | ||
168 | } | ||
169 | |||
170 | path = strdup(syspath); | ||
171 | if (path == NULL) | ||
172 | return -ENOMEM; | ||
173 | entry = &udev_enumerate->devices[udev_enumerate->devices_cur]; | ||
174 | entry->syspath = path; | ||
175 | entry->len = strlen(path); | ||
176 | udev_enumerate->devices_cur++; | ||
177 | udev_enumerate->devices_uptodate = false; | ||
178 | return 0; | ||
179 | } | ||
180 | |||
181 | static int syspath_cmp(const void *p1, const void *p2) | ||
182 | { | ||
183 | const struct syspath *path1 = p1; | ||
184 | const struct syspath *path2 = p2; | ||
185 | size_t len; | ||
186 | int ret; | ||
187 | |||
188 | len = MIN(path1->len, path2->len); | ||
189 | ret = memcmp(path1->syspath, path2->syspath, len); | ||
190 | if (ret == 0) { | ||
191 | if (path1->len < path2->len) | ||
192 | ret = -1; | ||
193 | else if (path1->len > path2->len) | ||
194 | ret = 1; | ||
195 | } | ||
196 | return ret; | ||
197 | } | ||
198 | |||
199 | /* For devices that should be moved to the absolute end of the list */ | ||
200 | static bool devices_delay_end(struct udev *udev, const char *syspath) | ||
201 | { | ||
202 | static const char *delay_device_list[] = { | ||
203 | "/block/md", | ||
204 | "/block/dm-", | ||
205 | NULL | ||
206 | }; | ||
207 | size_t len; | ||
208 | int i; | ||
209 | |||
210 | len = strlen(udev_get_sys_path(udev)); | ||
211 | for (i = 0; delay_device_list[i] != NULL; i++) { | ||
212 | if (strstr(&syspath[len], delay_device_list[i]) != NULL) { | ||
213 | dbg(udev, "delaying: %s\n", syspath); | ||
214 | return true; | ||
215 | } | ||
216 | } | ||
217 | return false; | ||
218 | } | ||
219 | |||
220 | /* For devices that should just be moved a little bit later, just | ||
221 | * before the point where some common path prefix changes. Returns the | ||
222 | * number of characters that make up that common prefix */ | ||
223 | static size_t devices_delay_later(struct udev *udev, const char *syspath) | ||
224 | { | ||
225 | const char *c; | ||
226 | |||
227 | /* For sound cards the control device must be enumerated last | ||
228 | * to make sure it's the final device node that gets ACLs | ||
229 | * applied. Applications rely on this fact and use ACL changes | ||
230 | * on the control node as an indicator that the ACL change of | ||
231 | * the entire sound card completed. The kernel makes this | ||
232 | * guarantee when creating those devices, and hence we should | ||
233 | * too when enumerating them. */ | ||
234 | |||
235 | if ((c = strstr(syspath, "/sound/card"))) { | ||
236 | c += 11; | ||
237 | c += strcspn(c, "/"); | ||
238 | |||
239 | if (strncmp(c, "/controlC", 9) == 0) | ||
240 | return c - syspath + 1; | ||
241 | } | ||
242 | |||
243 | return 0; | ||
244 | } | ||
245 | |||
246 | /** | ||
247 | * udev_enumerate_get_list_entry: | ||
248 | * @udev_enumerate: context | ||
249 | * | ||
250 | * Returns: the first entry of the sorted list of device paths. | ||
251 | */ | ||
252 | UDEV_EXPORT struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *udev_enumerate) | ||
253 | { | ||
254 | if (udev_enumerate == NULL) | ||
255 | return NULL; | ||
256 | if (!udev_enumerate->devices_uptodate) { | ||
257 | unsigned int i; | ||
258 | unsigned int max; | ||
259 | struct syspath *prev = NULL, *move_later = NULL; | ||
260 | size_t move_later_prefix = 0; | ||
261 | |||
262 | udev_list_cleanup(&udev_enumerate->devices_list); | ||
263 | qsort(udev_enumerate->devices, udev_enumerate->devices_cur, sizeof(struct syspath), syspath_cmp); | ||
264 | |||
265 | max = udev_enumerate->devices_cur; | ||
266 | for (i = 0; i < max; i++) { | ||
267 | struct syspath *entry = &udev_enumerate->devices[i]; | ||
268 | |||
269 | /* skip duplicated entries */ | ||
270 | if (prev != NULL && | ||
271 | entry->len == prev->len && | ||
272 | memcmp(entry->syspath, prev->syspath, entry->len) == 0) | ||
273 | continue; | ||
274 | prev = entry; | ||
275 | |||
276 | /* skip to be delayed devices, and add them to the end of the list */ | ||
277 | if (devices_delay_end(udev_enumerate->udev, entry->syspath)) { | ||
278 | syspath_add(udev_enumerate, entry->syspath); | ||
279 | /* need to update prev here for the case realloc() gives a different address */ | ||
280 | prev = &udev_enumerate->devices[i]; | ||
281 | continue; | ||
282 | } | ||
283 | |||
284 | /* skip to be delayed devices, and move the to | ||
285 | * the point where the prefix changes. We can | ||
286 | * only move one item at a time. */ | ||
287 | if (!move_later) { | ||
288 | move_later_prefix = devices_delay_later(udev_enumerate->udev, entry->syspath); | ||
289 | |||
290 | if (move_later_prefix > 0) { | ||
291 | move_later = entry; | ||
292 | continue; | ||
293 | } | ||
294 | } | ||
295 | |||
296 | if (move_later && | ||
297 | strncmp(entry->syspath, move_later->syspath, move_later_prefix) != 0) { | ||
298 | |||
299 | udev_list_entry_add(&udev_enumerate->devices_list, move_later->syspath, NULL); | ||
300 | move_later = NULL; | ||
301 | } | ||
302 | |||
303 | udev_list_entry_add(&udev_enumerate->devices_list, entry->syspath, NULL); | ||
304 | } | ||
305 | |||
306 | if (move_later) | ||
307 | udev_list_entry_add(&udev_enumerate->devices_list, move_later->syspath, NULL); | ||
308 | |||
309 | /* add and cleanup delayed devices from end of list */ | ||
310 | for (i = max; i < udev_enumerate->devices_cur; i++) { | ||
311 | struct syspath *entry = &udev_enumerate->devices[i]; | ||
312 | |||
313 | udev_list_entry_add(&udev_enumerate->devices_list, entry->syspath, NULL); | ||
314 | free(entry->syspath); | ||
315 | } | ||
316 | udev_enumerate->devices_cur = max; | ||
317 | |||
318 | udev_enumerate->devices_uptodate = true; | ||
319 | } | ||
320 | return udev_list_get_entry(&udev_enumerate->devices_list); | ||
321 | } | ||
322 | |||
323 | /** | ||
324 | * udev_enumerate_add_match_subsystem: | ||
325 | * @udev_enumerate: context | ||
326 | * @subsystem: filter for a subsystem of the device to include in the list | ||
327 | * | ||
328 | * Returns: 0 on success, otherwise a negative error value. | ||
329 | */ | ||
330 | UDEV_EXPORT int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem) | ||
331 | { | ||
332 | if (udev_enumerate == NULL) | ||
333 | return -EINVAL; | ||
334 | if (subsystem == NULL) | ||
335 | return 0; | ||
336 | if (udev_list_entry_add(&udev_enumerate->subsystem_match_list, subsystem, NULL) == NULL) | ||
337 | return -ENOMEM; | ||
338 | return 0; | ||
339 | } | ||
340 | |||
341 | /** | ||
342 | * udev_enumerate_add_nomatch_subsystem: | ||
343 | * @udev_enumerate: context | ||
344 | * @subsystem: filter for a subsystem of the device to exclude from the list | ||
345 | * | ||
346 | * Returns: 0 on success, otherwise a negative error value. | ||
347 | */ | ||
348 | UDEV_EXPORT int udev_enumerate_add_nomatch_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem) | ||
349 | { | ||
350 | if (udev_enumerate == NULL) | ||
351 | return -EINVAL; | ||
352 | if (subsystem == NULL) | ||
353 | return 0; | ||
354 | if (udev_list_entry_add(&udev_enumerate->subsystem_nomatch_list, subsystem, NULL) == NULL) | ||
355 | return -ENOMEM; | ||
356 | return 0; | ||
357 | } | ||
358 | |||
359 | /** | ||
360 | * udev_enumerate_add_match_sysattr: | ||
361 | * @udev_enumerate: context | ||
362 | * @sysattr: filter for a sys attribute at the device to include in the list | ||
363 | * @value: optional value of the sys attribute | ||
364 | * | ||
365 | * Returns: 0 on success, otherwise a negative error value. | ||
366 | */ | ||
367 | UDEV_EXPORT int udev_enumerate_add_match_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value) | ||
368 | { | ||
369 | if (udev_enumerate == NULL) | ||
370 | return -EINVAL; | ||
371 | if (sysattr == NULL) | ||
372 | return 0; | ||
373 | if (udev_list_entry_add(&udev_enumerate->sysattr_match_list, sysattr, value) == NULL) | ||
374 | return -ENOMEM; | ||
375 | return 0; | ||
376 | } | ||
377 | |||
378 | /** | ||
379 | * udev_enumerate_add_nomatch_sysattr: | ||
380 | * @udev_enumerate: context | ||
381 | * @sysattr: filter for a sys attribute at the device to exclude from the list | ||
382 | * @value: optional value of the sys attribute | ||
383 | * | ||
384 | * Returns: 0 on success, otherwise a negative error value. | ||
385 | */ | ||
386 | UDEV_EXPORT int udev_enumerate_add_nomatch_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value) | ||
387 | { | ||
388 | if (udev_enumerate == NULL) | ||
389 | return -EINVAL; | ||
390 | if (sysattr == NULL) | ||
391 | return 0; | ||
392 | if (udev_list_entry_add(&udev_enumerate->sysattr_nomatch_list, sysattr, value) == NULL) | ||
393 | return -ENOMEM; | ||
394 | return 0; | ||
395 | } | ||
396 | |||
397 | static int match_sysattr_value(struct udev_device *dev, const char *sysattr, const char *match_val) | ||
398 | { | ||
399 | const char *val = NULL; | ||
400 | bool match = false; | ||
401 | |||
402 | val = udev_device_get_sysattr_value(dev, sysattr); | ||
403 | if (val == NULL) | ||
404 | goto exit; | ||
405 | if (match_val == NULL) { | ||
406 | match = true; | ||
407 | goto exit; | ||
408 | } | ||
409 | if (fnmatch(match_val, val, 0) == 0) { | ||
410 | match = true; | ||
411 | goto exit; | ||
412 | } | ||
413 | exit: | ||
414 | return match; | ||
415 | } | ||
416 | |||
417 | /** | ||
418 | * udev_enumerate_add_match_property: | ||
419 | * @udev_enumerate: context | ||
420 | * @property: filter for a property of the device to include in the list | ||
421 | * @value: value of the property | ||
422 | * | ||
423 | * Returns: 0 on success, otherwise a negative error value. | ||
424 | */ | ||
425 | UDEV_EXPORT int udev_enumerate_add_match_property(struct udev_enumerate *udev_enumerate, const char *property, const char *value) | ||
426 | { | ||
427 | if (udev_enumerate == NULL) | ||
428 | return -EINVAL; | ||
429 | if (property == NULL) | ||
430 | return 0; | ||
431 | if (udev_list_entry_add(&udev_enumerate->properties_match_list, property, value) == NULL) | ||
432 | return -ENOMEM; | ||
433 | return 0; | ||
434 | } | ||
435 | |||
436 | /** | ||
437 | * udev_enumerate_add_match_tag: | ||
438 | * @udev_enumerate: context | ||
439 | * @tag: filter for a tag of the device to include in the list | ||
440 | * | ||
441 | * Returns: 0 on success, otherwise a negative error value. | ||
442 | */ | ||
443 | UDEV_EXPORT int udev_enumerate_add_match_tag(struct udev_enumerate *udev_enumerate, const char *tag) | ||
444 | { | ||
445 | if (udev_enumerate == NULL) | ||
446 | return -EINVAL; | ||
447 | if (tag == NULL) | ||
448 | return 0; | ||
449 | if (udev_list_entry_add(&udev_enumerate->tags_match_list, tag, NULL) == NULL) | ||
450 | return -ENOMEM; | ||
451 | return 0; | ||
452 | } | ||
453 | |||
454 | /** | ||
455 | * udev_enumerate_add_match_parent: | ||
456 | * @udev_enumerate: context | ||
457 | * @parent: parent device where to start searching | ||
458 | * | ||
459 | * Return the devices on the subtree of one given device. The parent | ||
460 | * itself is included in the list. | ||
461 | * | ||
462 | * A reference for the device is held until the udev_enumerate context | ||
463 | * is cleaned up. | ||
464 | * | ||
465 | * Returns: 0 on success, otherwise a negative error value. | ||
466 | */ | ||
467 | UDEV_EXPORT int udev_enumerate_add_match_parent(struct udev_enumerate *udev_enumerate, struct udev_device *parent) | ||
468 | { | ||
469 | if (udev_enumerate == NULL) | ||
470 | return -EINVAL; | ||
471 | if (parent == NULL) | ||
472 | return 0; | ||
473 | if (udev_enumerate->parent_match != NULL) | ||
474 | udev_device_unref(udev_enumerate->parent_match); | ||
475 | udev_enumerate->parent_match = udev_device_ref(parent); | ||
476 | return 0; | ||
477 | } | ||
478 | |||
479 | /** | ||
480 | * udev_enumerate_add_match_is_initialized: | ||
481 | * @udev_enumerate: context | ||
482 | * | ||
483 | * Match only devices which udev has set up already. This makes | ||
484 | * sure, that the device node permissions and context are properly set | ||
485 | * and that network devices are fully renamed. | ||
486 | * | ||
487 | * Usually, devices which are found in the kernel but not already | ||
488 | * handled by udev, have still pending events. Services should subscribe | ||
489 | * to monitor events and wait for these devices to become ready, instead | ||
490 | * of using uninitialized devices. | ||
491 | * | ||
492 | * For now, this will not affect devices which do not have a device node | ||
493 | * and are not network interfaces. | ||
494 | * | ||
495 | * Returns: 0 on success, otherwise a negative error value. | ||
496 | */ | ||
497 | UDEV_EXPORT int udev_enumerate_add_match_is_initialized(struct udev_enumerate *udev_enumerate) | ||
498 | { | ||
499 | if (udev_enumerate == NULL) | ||
500 | return -EINVAL; | ||
501 | udev_enumerate->match_is_initialized = true; | ||
502 | return 0; | ||
503 | } | ||
504 | |||
505 | /** | ||
506 | * udev_enumerate_add_match_sysname: | ||
507 | * @udev_enumerate: context | ||
508 | * @sysname: filter for the name of the device to include in the list | ||
509 | * | ||
510 | * Returns: 0 on success, otherwise a negative error value. | ||
511 | */ | ||
512 | UDEV_EXPORT int udev_enumerate_add_match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname) | ||
513 | { | ||
514 | if (udev_enumerate == NULL) | ||
515 | return -EINVAL; | ||
516 | if (sysname == NULL) | ||
517 | return 0; | ||
518 | if (udev_list_entry_add(&udev_enumerate->sysname_match_list, sysname, NULL) == NULL) | ||
519 | return -ENOMEM; | ||
520 | return 0; | ||
521 | } | ||
522 | |||
523 | static bool match_sysattr(struct udev_enumerate *udev_enumerate, struct udev_device *dev) | ||
524 | { | ||
525 | struct udev_list_entry *list_entry; | ||
526 | |||
527 | /* skip list */ | ||
528 | udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->sysattr_nomatch_list)) { | ||
529 | if (match_sysattr_value(dev, udev_list_entry_get_name(list_entry), | ||
530 | udev_list_entry_get_value(list_entry))) | ||
531 | return false; | ||
532 | } | ||
533 | /* include list */ | ||
534 | if (udev_list_get_entry(&udev_enumerate->sysattr_match_list) != NULL) { | ||
535 | udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->sysattr_match_list)) { | ||
536 | /* anything that does not match, will make it FALSE */ | ||
537 | if (!match_sysattr_value(dev, udev_list_entry_get_name(list_entry), | ||
538 | udev_list_entry_get_value(list_entry))) | ||
539 | return false; | ||
540 | } | ||
541 | return true; | ||
542 | } | ||
543 | return true; | ||
544 | } | ||
545 | |||
546 | static bool match_property(struct udev_enumerate *udev_enumerate, struct udev_device *dev) | ||
547 | { | ||
548 | struct udev_list_entry *list_entry; | ||
549 | bool match = false; | ||
550 | |||
551 | /* no match always matches */ | ||
552 | if (udev_list_get_entry(&udev_enumerate->properties_match_list) == NULL) | ||
553 | return true; | ||
554 | |||
555 | /* loop over matches */ | ||
556 | udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->properties_match_list)) { | ||
557 | const char *match_key = udev_list_entry_get_name(list_entry); | ||
558 | const char *match_value = udev_list_entry_get_value(list_entry); | ||
559 | struct udev_list_entry *property_entry; | ||
560 | |||
561 | /* loop over device properties */ | ||
562 | udev_list_entry_foreach(property_entry, udev_device_get_properties_list_entry(dev)) { | ||
563 | const char *dev_key = udev_list_entry_get_name(property_entry); | ||
564 | const char *dev_value = udev_list_entry_get_value(property_entry); | ||
565 | |||
566 | if (fnmatch(match_key, dev_key, 0) != 0) | ||
567 | continue; | ||
568 | if (match_value == NULL && dev_value == NULL) { | ||
569 | match = true; | ||
570 | goto out; | ||
571 | } | ||
572 | if (match_value == NULL || dev_value == NULL) | ||
573 | continue; | ||
574 | if (fnmatch(match_value, dev_value, 0) == 0) { | ||
575 | match = true; | ||
576 | goto out; | ||
577 | } | ||
578 | } | ||
579 | } | ||
580 | out: | ||
581 | return match; | ||
582 | } | ||
583 | |||
584 | static bool match_tag(struct udev_enumerate *udev_enumerate, struct udev_device *dev) | ||
585 | { | ||
586 | struct udev_list_entry *list_entry; | ||
587 | |||
588 | /* no match always matches */ | ||
589 | if (udev_list_get_entry(&udev_enumerate->tags_match_list) == NULL) | ||
590 | return true; | ||
591 | |||
592 | /* loop over matches */ | ||
593 | udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->tags_match_list)) | ||
594 | if (!udev_device_has_tag(dev, udev_list_entry_get_name(list_entry))) | ||
595 | return false; | ||
596 | |||
597 | return true; | ||
598 | } | ||
599 | |||
600 | static bool match_parent(struct udev_enumerate *udev_enumerate, struct udev_device *dev) | ||
601 | { | ||
602 | const char *parent; | ||
603 | |||
604 | if (udev_enumerate->parent_match == NULL) | ||
605 | return true; | ||
606 | |||
607 | parent = udev_device_get_devpath(udev_enumerate->parent_match); | ||
608 | return strncmp(parent, udev_device_get_devpath(dev), strlen(parent)) == 0; | ||
609 | } | ||
610 | |||
611 | static bool match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname) | ||
612 | { | ||
613 | struct udev_list_entry *list_entry; | ||
614 | |||
615 | if (udev_list_get_entry(&udev_enumerate->sysname_match_list) == NULL) | ||
616 | return true; | ||
617 | |||
618 | udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->sysname_match_list)) { | ||
619 | if (fnmatch(udev_list_entry_get_name(list_entry), sysname, 0) != 0) | ||
620 | continue; | ||
621 | return true; | ||
622 | } | ||
623 | return false; | ||
624 | } | ||
625 | |||
626 | static int scan_dir_and_add_devices(struct udev_enumerate *udev_enumerate, | ||
627 | const char *basedir, const char *subdir1, const char *subdir2) | ||
628 | { | ||
629 | struct udev *udev = udev_enumerate_get_udev(udev_enumerate); | ||
630 | char path[UTIL_PATH_SIZE]; | ||
631 | size_t l; | ||
632 | char *s; | ||
633 | DIR *dir; | ||
634 | struct dirent *dent; | ||
635 | |||
636 | s = path; | ||
637 | l = util_strpcpyl(&s, sizeof(path), udev_get_sys_path(udev), "/", basedir, NULL); | ||
638 | if (subdir1 != NULL) | ||
639 | l = util_strpcpyl(&s, l, "/", subdir1, NULL); | ||
640 | if (subdir2 != NULL) | ||
641 | util_strpcpyl(&s, l, "/", subdir2, NULL); | ||
642 | dir = opendir(path); | ||
643 | if (dir == NULL) | ||
644 | return -ENOENT; | ||
645 | for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { | ||
646 | char syspath[UTIL_PATH_SIZE]; | ||
647 | struct udev_device *dev; | ||
648 | |||
649 | if (dent->d_name[0] == '.') | ||
650 | continue; | ||
651 | |||
652 | if (!match_sysname(udev_enumerate, dent->d_name)) | ||
653 | continue; | ||
654 | |||
655 | util_strscpyl(syspath, sizeof(syspath), path, "/", dent->d_name, NULL); | ||
656 | dev = udev_device_new_from_syspath(udev_enumerate->udev, syspath); | ||
657 | if (dev == NULL) | ||
658 | continue; | ||
659 | |||
660 | if (udev_enumerate->match_is_initialized) { | ||
661 | /* | ||
662 | * All devices with a device node or network interfaces | ||
663 | * possibly need udev to adjust the device node permission | ||
664 | * or context, or rename the interface before it can be | ||
665 | * reliably used from other processes. | ||
666 | * | ||
667 | * For now, we can only check these types of devices, we | ||
668 | * might not store a database, and have no way to find out | ||
669 | * for all other types of devices. | ||
670 | */ | ||
671 | if (!udev_device_get_is_initialized(dev) && | ||
672 | (major(udev_device_get_devnum(dev)) > 0 || udev_device_get_ifindex(dev) > 0)) | ||
673 | goto nomatch; | ||
674 | } | ||
675 | if (!match_parent(udev_enumerate, dev)) | ||
676 | goto nomatch; | ||
677 | if (!match_tag(udev_enumerate, dev)) | ||
678 | goto nomatch; | ||
679 | if (!match_property(udev_enumerate, dev)) | ||
680 | goto nomatch; | ||
681 | if (!match_sysattr(udev_enumerate, dev)) | ||
682 | goto nomatch; | ||
683 | |||
684 | syspath_add(udev_enumerate, udev_device_get_syspath(dev)); | ||
685 | nomatch: | ||
686 | udev_device_unref(dev); | ||
687 | } | ||
688 | closedir(dir); | ||
689 | return 0; | ||
690 | } | ||
691 | |||
692 | static bool match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem) | ||
693 | { | ||
694 | struct udev_list_entry *list_entry; | ||
695 | |||
696 | udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->subsystem_nomatch_list)) { | ||
697 | if (fnmatch(udev_list_entry_get_name(list_entry), subsystem, 0) == 0) | ||
698 | return false; | ||
699 | } | ||
700 | if (udev_list_get_entry(&udev_enumerate->subsystem_match_list) != NULL) { | ||
701 | udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->subsystem_match_list)) { | ||
702 | if (fnmatch(udev_list_entry_get_name(list_entry), subsystem, 0) == 0) | ||
703 | return true; | ||
704 | } | ||
705 | return false; | ||
706 | } | ||
707 | return true; | ||
708 | } | ||
709 | |||
710 | static int scan_dir(struct udev_enumerate *udev_enumerate, const char *basedir, const char *subdir, const char *subsystem) | ||
711 | { | ||
712 | struct udev *udev = udev_enumerate_get_udev(udev_enumerate); | ||
713 | |||
714 | char path[UTIL_PATH_SIZE]; | ||
715 | DIR *dir; | ||
716 | struct dirent *dent; | ||
717 | |||
718 | util_strscpyl(path, sizeof(path), udev_get_sys_path(udev), "/", basedir, NULL); | ||
719 | dir = opendir(path); | ||
720 | if (dir == NULL) | ||
721 | return -1; | ||
722 | for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { | ||
723 | if (dent->d_name[0] == '.') | ||
724 | continue; | ||
725 | if (!match_subsystem(udev_enumerate, subsystem != NULL ? subsystem : dent->d_name)) | ||
726 | continue; | ||
727 | scan_dir_and_add_devices(udev_enumerate, basedir, dent->d_name, subdir); | ||
728 | } | ||
729 | closedir(dir); | ||
730 | return 0; | ||
731 | } | ||
732 | |||
733 | /** | ||
734 | * udev_enumerate_add_syspath: | ||
735 | * @udev_enumerate: context | ||
736 | * @syspath: path of a device | ||
737 | * | ||
738 | * Add a device to the list of devices, to retrieve it back sorted in dependency order. | ||
739 | * | ||
740 | * Returns: 0 on success, otherwise a negative error value. | ||
741 | */ | ||
742 | UDEV_EXPORT int udev_enumerate_add_syspath(struct udev_enumerate *udev_enumerate, const char *syspath) | ||
743 | { | ||
744 | struct udev_device *udev_device; | ||
745 | |||
746 | if (udev_enumerate == NULL) | ||
747 | return -EINVAL; | ||
748 | if (syspath == NULL) | ||
749 | return 0; | ||
750 | /* resolve to real syspath */ | ||
751 | udev_device = udev_device_new_from_syspath(udev_enumerate->udev, syspath); | ||
752 | if (udev_device == NULL) | ||
753 | return -EINVAL; | ||
754 | syspath_add(udev_enumerate, udev_device_get_syspath(udev_device)); | ||
755 | udev_device_unref(udev_device); | ||
756 | return 0; | ||
757 | } | ||
758 | |||
759 | static int scan_devices_tags(struct udev_enumerate *udev_enumerate) | ||
760 | { | ||
761 | struct udev *udev = udev_enumerate_get_udev(udev_enumerate); | ||
762 | struct udev_list_entry *list_entry; | ||
763 | |||
764 | /* scan only tagged devices, use tags reverse-index, instead of searching all devices in /sys */ | ||
765 | udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_enumerate->tags_match_list)) { | ||
766 | DIR *dir; | ||
767 | struct dirent *dent; | ||
768 | char path[UTIL_PATH_SIZE]; | ||
769 | |||
770 | util_strscpyl(path, sizeof(path), udev_get_run_path(udev), "/tags/", | ||
771 | udev_list_entry_get_name(list_entry), NULL); | ||
772 | dir = opendir(path); | ||
773 | if (dir == NULL) | ||
774 | continue; | ||
775 | for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { | ||
776 | struct udev_device *dev; | ||
777 | |||
778 | if (dent->d_name[0] == '.') | ||
779 | continue; | ||
780 | |||
781 | dev = udev_device_new_from_id_filename(udev_enumerate->udev, dent->d_name); | ||
782 | if (dev == NULL) | ||
783 | continue; | ||
784 | |||
785 | if (!match_subsystem(udev_enumerate, udev_device_get_subsystem(dev))) | ||
786 | goto nomatch; | ||
787 | if (!match_sysname(udev_enumerate, udev_device_get_sysname(dev))) | ||
788 | goto nomatch; | ||
789 | if (!match_parent(udev_enumerate, dev)) | ||
790 | goto nomatch; | ||
791 | if (!match_property(udev_enumerate, dev)) | ||
792 | goto nomatch; | ||
793 | if (!match_sysattr(udev_enumerate, dev)) | ||
794 | goto nomatch; | ||
795 | |||
796 | syspath_add(udev_enumerate, udev_device_get_syspath(dev)); | ||
797 | nomatch: | ||
798 | udev_device_unref(dev); | ||
799 | } | ||
800 | closedir(dir); | ||
801 | } | ||
802 | return 0; | ||
803 | } | ||
804 | |||
805 | static int parent_add_child(struct udev_enumerate *enumerate, const char *path) | ||
806 | { | ||
807 | struct udev_device *dev; | ||
808 | |||
809 | dev = udev_device_new_from_syspath(enumerate->udev, path); | ||
810 | if (dev == NULL) | ||
811 | return -ENODEV; | ||
812 | |||
813 | if (!match_subsystem(enumerate, udev_device_get_subsystem(dev))) | ||
814 | return 0; | ||
815 | if (!match_sysname(enumerate, udev_device_get_sysname(dev))) | ||
816 | return 0; | ||
817 | if (!match_property(enumerate, dev)) | ||
818 | return 0; | ||
819 | if (!match_sysattr(enumerate, dev)) | ||
820 | return 0; | ||
821 | |||
822 | syspath_add(enumerate, udev_device_get_syspath(dev)); | ||
823 | udev_device_unref(dev); | ||
824 | return 1; | ||
825 | } | ||
826 | |||
827 | static int parent_crawl_children(struct udev_enumerate *enumerate, const char *path, int maxdepth) | ||
828 | { | ||
829 | DIR *d; | ||
830 | struct dirent *dent; | ||
831 | |||
832 | d = opendir(path); | ||
833 | if (d == NULL) | ||
834 | return -errno; | ||
835 | |||
836 | for (dent = readdir(d); dent != NULL; dent = readdir(d)) { | ||
837 | char *child; | ||
838 | |||
839 | if (dent->d_name[0] == '.') | ||
840 | continue; | ||
841 | if (dent->d_type != DT_DIR) | ||
842 | continue; | ||
843 | if (asprintf(&child, "%s/%s", path, dent->d_name) < 0) | ||
844 | continue; | ||
845 | parent_add_child(enumerate, child); | ||
846 | if (maxdepth > 0) | ||
847 | parent_crawl_children(enumerate, child, maxdepth-1); | ||
848 | free(child); | ||
849 | } | ||
850 | |||
851 | closedir(d); | ||
852 | return 0; | ||
853 | } | ||
854 | |||
855 | static int scan_devices_children(struct udev_enumerate *enumerate) | ||
856 | { | ||
857 | const char *path; | ||
858 | |||
859 | path = udev_device_get_syspath(enumerate->parent_match); | ||
860 | parent_add_child(enumerate, path); | ||
861 | return parent_crawl_children(enumerate, path, 256); | ||
862 | } | ||
863 | |||
864 | static int scan_devices_all(struct udev_enumerate *udev_enumerate) | ||
865 | { | ||
866 | struct udev *udev = udev_enumerate_get_udev(udev_enumerate); | ||
867 | char base[UTIL_PATH_SIZE]; | ||
868 | struct stat statbuf; | ||
869 | |||
870 | util_strscpyl(base, sizeof(base), udev_get_sys_path(udev), "/subsystem", NULL); | ||
871 | if (stat(base, &statbuf) == 0) { | ||
872 | /* we have /subsystem/, forget all the old stuff */ | ||
873 | dbg(udev, "searching '/subsystem/*/devices/*' dir\n"); | ||
874 | scan_dir(udev_enumerate, "subsystem", "devices", NULL); | ||
875 | } else { | ||
876 | dbg(udev, "searching '/bus/*/devices/*' dir\n"); | ||
877 | scan_dir(udev_enumerate, "bus", "devices", NULL); | ||
878 | dbg(udev, "searching '/class/*' dir\n"); | ||
879 | scan_dir(udev_enumerate, "class", NULL, NULL); | ||
880 | } | ||
881 | return 0; | ||
882 | } | ||
883 | |||
884 | /** | ||
885 | * udev_enumerate_scan_devices: | ||
886 | * @udev_enumerate: udev enumeration context | ||
887 | * | ||
888 | * Returns: 0 on success, otherwise a negative error value. | ||
889 | **/ | ||
890 | UDEV_EXPORT int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate) | ||
891 | { | ||
892 | if (udev_enumerate == NULL) | ||
893 | return -EINVAL; | ||
894 | |||
895 | /* efficiently lookup tags only, we maintain a reverse-index */ | ||
896 | if (udev_list_get_entry(&udev_enumerate->tags_match_list) != NULL) | ||
897 | return scan_devices_tags(udev_enumerate); | ||
898 | |||
899 | /* walk the subtree of one parent device only */ | ||
900 | if (udev_enumerate->parent_match != NULL) | ||
901 | return scan_devices_children(udev_enumerate); | ||
902 | |||
903 | /* scan devices of all subsystems */ | ||
904 | return scan_devices_all(udev_enumerate); | ||
905 | } | ||
906 | |||
907 | /** | ||
908 | * udev_enumerate_scan_subsystems: | ||
909 | * @udev_enumerate: udev enumeration context | ||
910 | * | ||
911 | * Returns: 0 on success, otherwise a negative error value. | ||
912 | **/ | ||
913 | UDEV_EXPORT int udev_enumerate_scan_subsystems(struct udev_enumerate *udev_enumerate) | ||
914 | { | ||
915 | struct udev *udev = udev_enumerate_get_udev(udev_enumerate); | ||
916 | char base[UTIL_PATH_SIZE]; | ||
917 | struct stat statbuf; | ||
918 | const char *subsysdir; | ||
919 | |||
920 | if (udev_enumerate == NULL) | ||
921 | return -EINVAL; | ||
922 | |||
923 | /* all kernel modules */ | ||
924 | if (match_subsystem(udev_enumerate, "module")) { | ||
925 | dbg(udev, "searching 'modules/*' dir\n"); | ||
926 | scan_dir_and_add_devices(udev_enumerate, "module", NULL, NULL); | ||
927 | } | ||
928 | |||
929 | util_strscpyl(base, sizeof(base), udev_get_sys_path(udev), "/subsystem", NULL); | ||
930 | if (stat(base, &statbuf) == 0) | ||
931 | subsysdir = "subsystem"; | ||
932 | else | ||
933 | subsysdir = "bus"; | ||
934 | |||
935 | /* all subsystems (only buses support coldplug) */ | ||
936 | if (match_subsystem(udev_enumerate, "subsystem")) { | ||
937 | dbg(udev, "searching '%s/*' dir\n", subsysdir); | ||
938 | scan_dir_and_add_devices(udev_enumerate, subsysdir, NULL, NULL); | ||
939 | } | ||
940 | |||
941 | /* all subsystem drivers */ | ||
942 | if (match_subsystem(udev_enumerate, "drivers")) { | ||
943 | dbg(udev, "searching '%s/*/drivers/*' dir\n", subsysdir); | ||
944 | scan_dir(udev_enumerate, subsysdir, "drivers", "drivers"); | ||
945 | } | ||
946 | return 0; | ||
947 | } | ||
diff --git a/src/udev/src/libudev-list.c b/src/udev/src/libudev-list.c new file mode 100644 index 000000000..4bdef35ae --- /dev/null +++ b/src/udev/src/libudev-list.c | |||
@@ -0,0 +1,344 @@ | |||
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 | return NULL; | ||
197 | } | ||
198 | list->entries_max += add; | ||
199 | } | ||
200 | |||
201 | /* the negative i returned the insertion index */ | ||
202 | i = (-i)-1; | ||
203 | |||
204 | /* insert into sorted list */ | ||
205 | if ((unsigned int)i < list->entries_cur) | ||
206 | udev_list_entry_insert_before(entry, list->entries[i]); | ||
207 | else | ||
208 | udev_list_entry_append(entry, list); | ||
209 | |||
210 | /* insert into sorted array */ | ||
211 | memmove(&list->entries[i+1], &list->entries[i], | ||
212 | (list->entries_cur - i) * sizeof(struct udev_list_entry *)); | ||
213 | list->entries[i] = entry; | ||
214 | list->entries_cur++; | ||
215 | } else { | ||
216 | udev_list_entry_append(entry, list); | ||
217 | } | ||
218 | |||
219 | dbg(list->udev, "'%s=%s' added\n", entry->name, entry->value); | ||
220 | return entry; | ||
221 | } | ||
222 | |||
223 | void udev_list_entry_delete(struct udev_list_entry *entry) | ||
224 | { | ||
225 | if (entry->list->entries != NULL) { | ||
226 | int i; | ||
227 | struct udev_list *list = entry->list; | ||
228 | |||
229 | /* remove entry from sorted array */ | ||
230 | i = list_search(list, entry->name); | ||
231 | if (i >= 0) { | ||
232 | memmove(&list->entries[i], &list->entries[i+1], | ||
233 | ((list->entries_cur-1) - i) * sizeof(struct udev_list_entry *)); | ||
234 | list->entries_cur--; | ||
235 | } | ||
236 | } | ||
237 | |||
238 | udev_list_node_remove(&entry->node); | ||
239 | free(entry->name); | ||
240 | free(entry->value); | ||
241 | free(entry); | ||
242 | } | ||
243 | |||
244 | void udev_list_cleanup(struct udev_list *list) | ||
245 | { | ||
246 | struct udev_list_entry *entry_loop; | ||
247 | struct udev_list_entry *entry_tmp; | ||
248 | |||
249 | free(list->entries); | ||
250 | list->entries = NULL; | ||
251 | list->entries_cur = 0; | ||
252 | list->entries_max = 0; | ||
253 | udev_list_entry_foreach_safe(entry_loop, entry_tmp, udev_list_get_entry(list)) | ||
254 | udev_list_entry_delete(entry_loop); | ||
255 | } | ||
256 | |||
257 | struct udev_list_entry *udev_list_get_entry(struct udev_list *list) | ||
258 | { | ||
259 | if (udev_list_node_is_empty(&list->node)) | ||
260 | return NULL; | ||
261 | return list_node_to_entry(list->node.next); | ||
262 | } | ||
263 | |||
264 | /** | ||
265 | * udev_list_entry_get_next: | ||
266 | * @list_entry: current entry | ||
267 | * | ||
268 | * Returns: the next entry from the list, #NULL is no more entries are found. | ||
269 | */ | ||
270 | UDEV_EXPORT struct udev_list_entry *udev_list_entry_get_next(struct udev_list_entry *list_entry) | ||
271 | { | ||
272 | struct udev_list_node *next; | ||
273 | |||
274 | if (list_entry == NULL) | ||
275 | return NULL; | ||
276 | next = list_entry->node.next; | ||
277 | /* empty list or no more entries */ | ||
278 | if (next == &list_entry->list->node) | ||
279 | return NULL; | ||
280 | return list_node_to_entry(next); | ||
281 | } | ||
282 | |||
283 | /** | ||
284 | * udev_list_entry_get_by_name: | ||
285 | * @list_entry: current entry | ||
286 | * @name: name string to match | ||
287 | * | ||
288 | * Returns: the entry where @name matched, #NULL if no matching entry is found. | ||
289 | */ | ||
290 | UDEV_EXPORT struct udev_list_entry *udev_list_entry_get_by_name(struct udev_list_entry *list_entry, const char *name) | ||
291 | { | ||
292 | int i; | ||
293 | |||
294 | if (list_entry == NULL) | ||
295 | return NULL; | ||
296 | |||
297 | if (!list_entry->list->unique) | ||
298 | return NULL; | ||
299 | |||
300 | i = list_search(list_entry->list, name); | ||
301 | if (i < 0) | ||
302 | return NULL; | ||
303 | return list_entry->list->entries[i]; | ||
304 | } | ||
305 | |||
306 | /** | ||
307 | * udev_list_entry_get_name: | ||
308 | * @list_entry: current entry | ||
309 | * | ||
310 | * Returns: the name string of this entry. | ||
311 | */ | ||
312 | UDEV_EXPORT const char *udev_list_entry_get_name(struct udev_list_entry *list_entry) | ||
313 | { | ||
314 | if (list_entry == NULL) | ||
315 | return NULL; | ||
316 | return list_entry->name; | ||
317 | } | ||
318 | |||
319 | /** | ||
320 | * udev_list_entry_get_value: | ||
321 | * @list_entry: current entry | ||
322 | * | ||
323 | * Returns: the value string of this entry. | ||
324 | */ | ||
325 | UDEV_EXPORT const char *udev_list_entry_get_value(struct udev_list_entry *list_entry) | ||
326 | { | ||
327 | if (list_entry == NULL) | ||
328 | return NULL; | ||
329 | return list_entry->value; | ||
330 | } | ||
331 | |||
332 | int udev_list_entry_get_num(struct udev_list_entry *list_entry) | ||
333 | { | ||
334 | if (list_entry == NULL) | ||
335 | return -EINVAL; | ||
336 | return list_entry->num; | ||
337 | } | ||
338 | |||
339 | void udev_list_entry_set_num(struct udev_list_entry *list_entry, int num) | ||
340 | { | ||
341 | if (list_entry == NULL) | ||
342 | return; | ||
343 | list_entry->num = num; | ||
344 | } | ||
diff --git a/src/udev/src/libudev-monitor.c b/src/udev/src/libudev-monitor.c new file mode 100644 index 000000000..77dc55572 --- /dev/null +++ b/src/udev/src/libudev-monitor.c | |||
@@ -0,0 +1,874 @@ | |||
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 void udev_monitor_unref(struct udev_monitor *udev_monitor) | ||
478 | { | ||
479 | if (udev_monitor == NULL) | ||
480 | return; | ||
481 | udev_monitor->refcount--; | ||
482 | if (udev_monitor->refcount > 0) | ||
483 | return; | ||
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 | } | ||
491 | |||
492 | /** | ||
493 | * udev_monitor_get_udev: | ||
494 | * @udev_monitor: udev monitor | ||
495 | * | ||
496 | * Retrieve the udev library context the monitor was created with. | ||
497 | * | ||
498 | * Returns: the udev library context | ||
499 | **/ | ||
500 | UDEV_EXPORT struct udev *udev_monitor_get_udev(struct udev_monitor *udev_monitor) | ||
501 | { | ||
502 | if (udev_monitor == NULL) | ||
503 | return NULL; | ||
504 | return udev_monitor->udev; | ||
505 | } | ||
506 | |||
507 | /** | ||
508 | * udev_monitor_get_fd: | ||
509 | * @udev_monitor: udev monitor | ||
510 | * | ||
511 | * Retrieve the socket file descriptor associated with the monitor. | ||
512 | * | ||
513 | * Returns: the socket file descriptor | ||
514 | **/ | ||
515 | UDEV_EXPORT int udev_monitor_get_fd(struct udev_monitor *udev_monitor) | ||
516 | { | ||
517 | if (udev_monitor == NULL) | ||
518 | return -1; | ||
519 | return udev_monitor->sock; | ||
520 | } | ||
521 | |||
522 | static int passes_filter(struct udev_monitor *udev_monitor, struct udev_device *udev_device) | ||
523 | { | ||
524 | struct udev_list_entry *list_entry; | ||
525 | |||
526 | if (udev_list_get_entry(&udev_monitor->filter_subsystem_list) == NULL) | ||
527 | goto tag; | ||
528 | udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_subsystem_list)) { | ||
529 | const char *subsys = udev_list_entry_get_name(list_entry); | ||
530 | const char *dsubsys = udev_device_get_subsystem(udev_device); | ||
531 | const char *devtype; | ||
532 | const char *ddevtype; | ||
533 | |||
534 | if (strcmp(dsubsys, subsys) != 0) | ||
535 | continue; | ||
536 | |||
537 | devtype = udev_list_entry_get_value(list_entry); | ||
538 | if (devtype == NULL) | ||
539 | goto tag; | ||
540 | ddevtype = udev_device_get_devtype(udev_device); | ||
541 | if (ddevtype == NULL) | ||
542 | continue; | ||
543 | if (strcmp(ddevtype, devtype) == 0) | ||
544 | goto tag; | ||
545 | } | ||
546 | return 0; | ||
547 | |||
548 | tag: | ||
549 | if (udev_list_get_entry(&udev_monitor->filter_tag_list) == NULL) | ||
550 | return 1; | ||
551 | udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_monitor->filter_tag_list)) { | ||
552 | const char *tag = udev_list_entry_get_name(list_entry); | ||
553 | |||
554 | if (udev_device_has_tag(udev_device, tag)) | ||
555 | return 1; | ||
556 | } | ||
557 | return 0; | ||
558 | } | ||
559 | |||
560 | /** | ||
561 | * udev_monitor_receive_device: | ||
562 | * @udev_monitor: udev monitor | ||
563 | * | ||
564 | * Receive data from the udev monitor socket, allocate a new udev | ||
565 | * device, fill in the received data, and return the device. | ||
566 | * | ||
567 | * Only socket connections with uid=0 are accepted. | ||
568 | * | ||
569 | * The initial refcount is 1, and needs to be decremented to | ||
570 | * release the resources of the udev device. | ||
571 | * | ||
572 | * Returns: a new udev device, or #NULL, in case of an error | ||
573 | **/ | ||
574 | UDEV_EXPORT struct udev_device *udev_monitor_receive_device(struct udev_monitor *udev_monitor) | ||
575 | { | ||
576 | struct udev_device *udev_device; | ||
577 | struct msghdr smsg; | ||
578 | struct iovec iov; | ||
579 | char cred_msg[CMSG_SPACE(sizeof(struct ucred))]; | ||
580 | struct cmsghdr *cmsg; | ||
581 | struct sockaddr_nl snl; | ||
582 | struct ucred *cred; | ||
583 | char buf[8192]; | ||
584 | ssize_t buflen; | ||
585 | ssize_t bufpos; | ||
586 | struct udev_monitor_netlink_header *nlh; | ||
587 | |||
588 | retry: | ||
589 | if (udev_monitor == NULL) | ||
590 | return NULL; | ||
591 | iov.iov_base = &buf; | ||
592 | iov.iov_len = sizeof(buf); | ||
593 | memset (&smsg, 0x00, sizeof(struct msghdr)); | ||
594 | smsg.msg_iov = &iov; | ||
595 | smsg.msg_iovlen = 1; | ||
596 | smsg.msg_control = cred_msg; | ||
597 | smsg.msg_controllen = sizeof(cred_msg); | ||
598 | |||
599 | if (udev_monitor->snl.nl_family != 0) { | ||
600 | smsg.msg_name = &snl; | ||
601 | smsg.msg_namelen = sizeof(snl); | ||
602 | } | ||
603 | |||
604 | buflen = recvmsg(udev_monitor->sock, &smsg, 0); | ||
605 | if (buflen < 0) { | ||
606 | if (errno != EINTR) | ||
607 | info(udev_monitor->udev, "unable to receive message\n"); | ||
608 | return NULL; | ||
609 | } | ||
610 | |||
611 | if (buflen < 32 || (size_t)buflen >= sizeof(buf)) { | ||
612 | info(udev_monitor->udev, "invalid message length\n"); | ||
613 | return NULL; | ||
614 | } | ||
615 | |||
616 | if (udev_monitor->snl.nl_family != 0) { | ||
617 | if (snl.nl_groups == 0) { | ||
618 | /* unicast message, check if we trust the sender */ | ||
619 | if (udev_monitor->snl_trusted_sender.nl_pid == 0 || | ||
620 | snl.nl_pid != udev_monitor->snl_trusted_sender.nl_pid) { | ||
621 | info(udev_monitor->udev, "unicast netlink message ignored\n"); | ||
622 | return NULL; | ||
623 | } | ||
624 | } else if (snl.nl_groups == UDEV_MONITOR_KERNEL) { | ||
625 | if (snl.nl_pid > 0) { | ||
626 | info(udev_monitor->udev, "multicast kernel netlink message from pid %d ignored\n", | ||
627 | snl.nl_pid); | ||
628 | return NULL; | ||
629 | } | ||
630 | } | ||
631 | } | ||
632 | |||
633 | cmsg = CMSG_FIRSTHDR(&smsg); | ||
634 | if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) { | ||
635 | info(udev_monitor->udev, "no sender credentials received, message ignored\n"); | ||
636 | return NULL; | ||
637 | } | ||
638 | |||
639 | cred = (struct ucred *)CMSG_DATA(cmsg); | ||
640 | if (cred->uid != 0) { | ||
641 | info(udev_monitor->udev, "sender uid=%d, message ignored\n", cred->uid); | ||
642 | return NULL; | ||
643 | } | ||
644 | |||
645 | if (memcmp(buf, "libudev", 8) == 0) { | ||
646 | /* udev message needs proper version magic */ | ||
647 | nlh = (struct udev_monitor_netlink_header *) buf; | ||
648 | if (nlh->magic != htonl(UDEV_MONITOR_MAGIC)) { | ||
649 | err(udev_monitor->udev, "unrecognized message signature (%x != %x)\n", | ||
650 | nlh->magic, htonl(UDEV_MONITOR_MAGIC)); | ||
651 | return NULL; | ||
652 | } | ||
653 | if (nlh->properties_off+32 > buflen) | ||
654 | return NULL; | ||
655 | bufpos = nlh->properties_off; | ||
656 | } else { | ||
657 | /* kernel message with header */ | ||
658 | bufpos = strlen(buf) + 1; | ||
659 | if ((size_t)bufpos < sizeof("a@/d") || bufpos >= buflen) { | ||
660 | info(udev_monitor->udev, "invalid message length\n"); | ||
661 | return NULL; | ||
662 | } | ||
663 | |||
664 | /* check message header */ | ||
665 | if (strstr(buf, "@/") == NULL) { | ||
666 | info(udev_monitor->udev, "unrecognized message header\n"); | ||
667 | return NULL; | ||
668 | } | ||
669 | } | ||
670 | |||
671 | udev_device = udev_device_new(udev_monitor->udev); | ||
672 | if (udev_device == NULL) | ||
673 | return NULL; | ||
674 | udev_device_set_info_loaded(udev_device); | ||
675 | |||
676 | while (bufpos < buflen) { | ||
677 | char *key; | ||
678 | size_t keylen; | ||
679 | |||
680 | key = &buf[bufpos]; | ||
681 | keylen = strlen(key); | ||
682 | if (keylen == 0) | ||
683 | break; | ||
684 | bufpos += keylen + 1; | ||
685 | udev_device_add_property_from_string_parse(udev_device, key); | ||
686 | } | ||
687 | |||
688 | if (udev_device_add_property_from_string_parse_finish(udev_device) < 0) { | ||
689 | info(udev_monitor->udev, "missing values, invalid device\n"); | ||
690 | udev_device_unref(udev_device); | ||
691 | return NULL; | ||
692 | } | ||
693 | |||
694 | /* skip device, if it does not pass the current filter */ | ||
695 | if (!passes_filter(udev_monitor, udev_device)) { | ||
696 | struct pollfd pfd[1]; | ||
697 | int rc; | ||
698 | |||
699 | udev_device_unref(udev_device); | ||
700 | |||
701 | /* if something is queued, get next device */ | ||
702 | pfd[0].fd = udev_monitor->sock; | ||
703 | pfd[0].events = POLLIN; | ||
704 | rc = poll(pfd, 1, 0); | ||
705 | if (rc > 0) | ||
706 | goto retry; | ||
707 | return NULL; | ||
708 | } | ||
709 | |||
710 | return udev_device; | ||
711 | } | ||
712 | |||
713 | int udev_monitor_send_device(struct udev_monitor *udev_monitor, | ||
714 | struct udev_monitor *destination, struct udev_device *udev_device) | ||
715 | { | ||
716 | const char *buf; | ||
717 | ssize_t blen; | ||
718 | ssize_t count; | ||
719 | |||
720 | blen = udev_device_get_properties_monitor_buf(udev_device, &buf); | ||
721 | if (blen < 32) | ||
722 | return -EINVAL; | ||
723 | |||
724 | if (udev_monitor->sun.sun_family != 0) { | ||
725 | struct msghdr smsg; | ||
726 | struct iovec iov[2]; | ||
727 | const char *action; | ||
728 | char header[2048]; | ||
729 | char *s; | ||
730 | |||
731 | /* header <action>@<devpath> */ | ||
732 | action = udev_device_get_action(udev_device); | ||
733 | if (action == NULL) | ||
734 | return -EINVAL; | ||
735 | s = header; | ||
736 | if (util_strpcpyl(&s, sizeof(header), action, "@", udev_device_get_devpath(udev_device), NULL) == 0) | ||
737 | return -EINVAL; | ||
738 | iov[0].iov_base = header; | ||
739 | iov[0].iov_len = (s - header)+1; | ||
740 | |||
741 | /* add properties list */ | ||
742 | iov[1].iov_base = (char *)buf; | ||
743 | iov[1].iov_len = blen; | ||
744 | |||
745 | memset(&smsg, 0x00, sizeof(struct msghdr)); | ||
746 | smsg.msg_iov = iov; | ||
747 | smsg.msg_iovlen = 2; | ||
748 | smsg.msg_name = &udev_monitor->sun; | ||
749 | smsg.msg_namelen = udev_monitor->addrlen; | ||
750 | count = sendmsg(udev_monitor->sock, &smsg, 0); | ||
751 | info(udev_monitor->udev, "passed %zi bytes to socket monitor %p\n", count, udev_monitor); | ||
752 | return count; | ||
753 | } | ||
754 | |||
755 | if (udev_monitor->snl.nl_family != 0) { | ||
756 | struct msghdr smsg; | ||
757 | struct iovec iov[2]; | ||
758 | const char *val; | ||
759 | struct udev_monitor_netlink_header nlh; | ||
760 | struct udev_list_entry *list_entry; | ||
761 | uint64_t tag_bloom_bits; | ||
762 | |||
763 | /* add versioned header */ | ||
764 | memset(&nlh, 0x00, sizeof(struct udev_monitor_netlink_header)); | ||
765 | memcpy(nlh.prefix, "libudev", 8); | ||
766 | nlh.magic = htonl(UDEV_MONITOR_MAGIC); | ||
767 | nlh.header_size = sizeof(struct udev_monitor_netlink_header); | ||
768 | val = udev_device_get_subsystem(udev_device); | ||
769 | nlh.filter_subsystem_hash = htonl(util_string_hash32(val)); | ||
770 | val = udev_device_get_devtype(udev_device); | ||
771 | if (val != NULL) | ||
772 | nlh.filter_devtype_hash = htonl(util_string_hash32(val)); | ||
773 | iov[0].iov_base = &nlh; | ||
774 | iov[0].iov_len = sizeof(struct udev_monitor_netlink_header); | ||
775 | |||
776 | /* add tag bloom filter */ | ||
777 | tag_bloom_bits = 0; | ||
778 | udev_list_entry_foreach(list_entry, udev_device_get_tags_list_entry(udev_device)) | ||
779 | tag_bloom_bits |= util_string_bloom64(udev_list_entry_get_name(list_entry)); | ||
780 | if (tag_bloom_bits > 0) { | ||
781 | nlh.filter_tag_bloom_hi = htonl(tag_bloom_bits >> 32); | ||
782 | nlh.filter_tag_bloom_lo = htonl(tag_bloom_bits & 0xffffffff); | ||
783 | } | ||
784 | |||
785 | /* add properties list */ | ||
786 | nlh.properties_off = iov[0].iov_len; | ||
787 | nlh.properties_len = blen; | ||
788 | iov[1].iov_base = (char *)buf; | ||
789 | iov[1].iov_len = blen; | ||
790 | |||
791 | memset(&smsg, 0x00, sizeof(struct msghdr)); | ||
792 | smsg.msg_iov = iov; | ||
793 | smsg.msg_iovlen = 2; | ||
794 | /* | ||
795 | * Use custom address for target, or the default one. | ||
796 | * | ||
797 | * If we send to a multicast group, we will get | ||
798 | * ECONNREFUSED, which is expected. | ||
799 | */ | ||
800 | if (destination != NULL) | ||
801 | smsg.msg_name = &destination->snl; | ||
802 | else | ||
803 | smsg.msg_name = &udev_monitor->snl_destination; | ||
804 | smsg.msg_namelen = sizeof(struct sockaddr_nl); | ||
805 | count = sendmsg(udev_monitor->sock, &smsg, 0); | ||
806 | info(udev_monitor->udev, "passed %zi bytes to netlink monitor %p\n", count, udev_monitor); | ||
807 | return count; | ||
808 | } | ||
809 | |||
810 | return -EINVAL; | ||
811 | } | ||
812 | |||
813 | /** | ||
814 | * udev_monitor_filter_add_match_subsystem_devtype: | ||
815 | * @udev_monitor: the monitor | ||
816 | * @subsystem: the subsystem value to match the incoming devices against | ||
817 | * @devtype: the devtype value to match the incoming devices against | ||
818 | * | ||
819 | * This filter is efficiently executed inside the kernel, and libudev subscribers | ||
820 | * will usually not be woken up for devices which do not match. | ||
821 | * | ||
822 | * The filter must be installed before the monitor is switched to listening mode. | ||
823 | * | ||
824 | * Returns: 0 on success, otherwise a negative error value. | ||
825 | */ | ||
826 | UDEV_EXPORT int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_monitor, const char *subsystem, const char *devtype) | ||
827 | { | ||
828 | if (udev_monitor == NULL) | ||
829 | return -EINVAL; | ||
830 | if (subsystem == NULL) | ||
831 | return -EINVAL; | ||
832 | if (udev_list_entry_add(&udev_monitor->filter_subsystem_list, subsystem, devtype) == NULL) | ||
833 | return -ENOMEM; | ||
834 | return 0; | ||
835 | } | ||
836 | |||
837 | /** | ||
838 | * udev_monitor_filter_add_match_tag: | ||
839 | * @udev_monitor: the monitor | ||
840 | * @tag: the name of a tag | ||
841 | * | ||
842 | * This filter is efficiently executed inside the kernel, and libudev subscribers | ||
843 | * will usually not be woken up for devices which do not match. | ||
844 | * | ||
845 | * The filter must be installed before the monitor is switched to listening mode. | ||
846 | * | ||
847 | * Returns: 0 on success, otherwise a negative error value. | ||
848 | */ | ||
849 | UDEV_EXPORT int udev_monitor_filter_add_match_tag(struct udev_monitor *udev_monitor, const char *tag) | ||
850 | { | ||
851 | if (udev_monitor == NULL) | ||
852 | return -EINVAL; | ||
853 | if (tag == NULL) | ||
854 | return -EINVAL; | ||
855 | if (udev_list_entry_add(&udev_monitor->filter_tag_list, tag, NULL) == NULL) | ||
856 | return -ENOMEM; | ||
857 | return 0; | ||
858 | } | ||
859 | |||
860 | /** | ||
861 | * udev_monitor_filter_remove: | ||
862 | * @udev_monitor: monitor | ||
863 | * | ||
864 | * Remove all filters from monitor. | ||
865 | * | ||
866 | * Returns: 0 on success, otherwise a negative error value. | ||
867 | */ | ||
868 | UDEV_EXPORT int udev_monitor_filter_remove(struct udev_monitor *udev_monitor) | ||
869 | { | ||
870 | static struct sock_fprog filter = { 0, NULL }; | ||
871 | |||
872 | udev_list_cleanup(&udev_monitor->filter_subsystem_list); | ||
873 | return setsockopt(udev_monitor->sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)); | ||
874 | } | ||
diff --git a/src/udev/src/libudev-private.h b/src/udev/src/libudev-private.h new file mode 100644 index 000000000..5f5c64a63 --- /dev/null +++ b/src/udev/src/libudev-private.h | |||
@@ -0,0 +1,213 @@ | |||
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 | struct udev_device *udev_device_new_from_id_filename(struct udev *udev, char *id); | ||
72 | mode_t udev_device_get_devnode_mode(struct udev_device *udev_device); | ||
73 | int udev_device_set_syspath(struct udev_device *udev_device, const char *syspath); | ||
74 | int udev_device_set_devnode(struct udev_device *udev_device, const char *devnode); | ||
75 | int udev_device_add_devlink(struct udev_device *udev_device, const char *devlink, int unique); | ||
76 | void udev_device_cleanup_devlinks_list(struct udev_device *udev_device); | ||
77 | struct udev_list_entry *udev_device_add_property(struct udev_device *udev_device, const char *key, const char *value); | ||
78 | void udev_device_add_property_from_string_parse(struct udev_device *udev_device, const char *property); | ||
79 | int udev_device_add_property_from_string_parse_finish(struct udev_device *udev_device); | ||
80 | char **udev_device_get_properties_envp(struct udev_device *udev_device); | ||
81 | ssize_t udev_device_get_properties_monitor_buf(struct udev_device *udev_device, const char **buf); | ||
82 | int udev_device_read_db(struct udev_device *udev_device, const char *dbfile); | ||
83 | int udev_device_read_uevent_file(struct udev_device *udev_device); | ||
84 | int udev_device_set_action(struct udev_device *udev_device, const char *action); | ||
85 | const char *udev_device_get_devpath_old(struct udev_device *udev_device); | ||
86 | const char *udev_device_get_id_filename(struct udev_device *udev_device); | ||
87 | void udev_device_set_is_initialized(struct udev_device *udev_device); | ||
88 | int udev_device_add_tag(struct udev_device *udev_device, const char *tag); | ||
89 | void udev_device_cleanup_tags_list(struct udev_device *udev_device); | ||
90 | unsigned long long udev_device_get_usec_initialized(struct udev_device *udev_device); | ||
91 | void udev_device_set_usec_initialized(struct udev_device *udev_device, unsigned long long usec_initialized); | ||
92 | int udev_device_get_devlink_priority(struct udev_device *udev_device); | ||
93 | int udev_device_set_devlink_priority(struct udev_device *udev_device, int prio); | ||
94 | int udev_device_get_watch_handle(struct udev_device *udev_device); | ||
95 | int udev_device_set_watch_handle(struct udev_device *udev_device, int handle); | ||
96 | int udev_device_get_ifindex(struct udev_device *udev_device); | ||
97 | void udev_device_set_info_loaded(struct udev_device *device); | ||
98 | bool udev_device_get_db_persist(struct udev_device *udev_device); | ||
99 | void udev_device_set_db_persist(struct udev_device *udev_device); | ||
100 | |||
101 | /* libudev-device-private.c */ | ||
102 | int udev_device_update_db(struct udev_device *udev_device); | ||
103 | int udev_device_delete_db(struct udev_device *udev_device); | ||
104 | int udev_device_tag_index(struct udev_device *dev, struct udev_device *dev_old, bool add); | ||
105 | |||
106 | /* libudev-monitor.c - netlink/unix socket communication */ | ||
107 | int udev_monitor_disconnect(struct udev_monitor *udev_monitor); | ||
108 | int udev_monitor_allow_unicast_sender(struct udev_monitor *udev_monitor, struct udev_monitor *sender); | ||
109 | int udev_monitor_send_device(struct udev_monitor *udev_monitor, | ||
110 | struct udev_monitor *destination, struct udev_device *udev_device); | ||
111 | struct udev_monitor *udev_monitor_new_from_netlink_fd(struct udev *udev, const char *name, int fd); | ||
112 | |||
113 | /* libudev-list.c */ | ||
114 | struct udev_list_node { | ||
115 | struct udev_list_node *next, *prev; | ||
116 | }; | ||
117 | struct udev_list { | ||
118 | struct udev *udev; | ||
119 | struct udev_list_node node; | ||
120 | struct udev_list_entry **entries; | ||
121 | unsigned int entries_cur; | ||
122 | unsigned int entries_max; | ||
123 | bool unique; | ||
124 | }; | ||
125 | #define UDEV_LIST(list) struct udev_list_node list = { &(list), &(list) } | ||
126 | void udev_list_node_init(struct udev_list_node *list); | ||
127 | int udev_list_node_is_empty(struct udev_list_node *list); | ||
128 | void udev_list_node_append(struct udev_list_node *new, struct udev_list_node *list); | ||
129 | void udev_list_node_remove(struct udev_list_node *entry); | ||
130 | #define udev_list_node_foreach(node, list) \ | ||
131 | for (node = (list)->next; \ | ||
132 | node != list; \ | ||
133 | node = (node)->next) | ||
134 | #define udev_list_node_foreach_safe(node, tmp, list) \ | ||
135 | for (node = (list)->next, tmp = (node)->next; \ | ||
136 | node != list; \ | ||
137 | node = tmp, tmp = (tmp)->next) | ||
138 | void udev_list_init(struct udev *udev, struct udev_list *list, bool unique); | ||
139 | void udev_list_cleanup(struct udev_list *list); | ||
140 | struct udev_list_entry *udev_list_get_entry(struct udev_list *list); | ||
141 | struct udev_list_entry *udev_list_entry_add(struct udev_list *list, const char *name, const char *value); | ||
142 | void udev_list_entry_delete(struct udev_list_entry *entry); | ||
143 | void udev_list_entry_insert_before(struct udev_list_entry *new, struct udev_list_entry *entry); | ||
144 | void udev_list_entry_append(struct udev_list_entry *new, struct udev_list *list); | ||
145 | int udev_list_entry_get_num(struct udev_list_entry *list_entry); | ||
146 | void udev_list_entry_set_num(struct udev_list_entry *list_entry, int num); | ||
147 | #define udev_list_entry_foreach_safe(entry, tmp, first) \ | ||
148 | for (entry = first, tmp = udev_list_entry_get_next(entry); \ | ||
149 | entry != NULL; \ | ||
150 | entry = tmp, tmp = udev_list_entry_get_next(tmp)) | ||
151 | |||
152 | /* libudev-queue.c */ | ||
153 | unsigned long long int udev_get_kernel_seqnum(struct udev *udev); | ||
154 | int udev_queue_read_seqnum(FILE *queue_file, unsigned long long int *seqnum); | ||
155 | ssize_t udev_queue_read_devpath(FILE *queue_file, char *devpath, size_t size); | ||
156 | ssize_t udev_queue_skip_devpath(FILE *queue_file); | ||
157 | |||
158 | /* libudev-queue-private.c */ | ||
159 | struct udev_queue_export *udev_queue_export_new(struct udev *udev); | ||
160 | struct udev_queue_export *udev_queue_export_unref(struct udev_queue_export *udev_queue_export); | ||
161 | void udev_queue_export_cleanup(struct udev_queue_export *udev_queue_export); | ||
162 | int udev_queue_export_device_queued(struct udev_queue_export *udev_queue_export, struct udev_device *udev_device); | ||
163 | int udev_queue_export_device_finished(struct udev_queue_export *udev_queue_export, struct udev_device *udev_device); | ||
164 | |||
165 | /* libudev-util.c */ | ||
166 | #define UTIL_PATH_SIZE 1024 | ||
167 | #define UTIL_NAME_SIZE 512 | ||
168 | #define UTIL_LINE_SIZE 16384 | ||
169 | #define UDEV_ALLOWED_CHARS_INPUT "/ $%?," | ||
170 | ssize_t util_get_sys_core_link_value(struct udev *udev, const char *slink, const char *syspath, char *value, size_t size); | ||
171 | int util_resolve_sys_link(struct udev *udev, char *syspath, size_t size); | ||
172 | int util_log_priority(const char *priority); | ||
173 | size_t util_path_encode(const char *src, char *dest, size_t size); | ||
174 | size_t util_path_decode(char *s); | ||
175 | void util_remove_trailing_chars(char *path, char c); | ||
176 | size_t util_strpcpy(char **dest, size_t size, const char *src); | ||
177 | size_t util_strpcpyl(char **dest, size_t size, const char *src, ...) __attribute__((sentinel)); | ||
178 | size_t util_strscpy(char *dest, size_t size, const char *src); | ||
179 | size_t util_strscpyl(char *dest, size_t size, const char *src, ...) __attribute__((sentinel)); | ||
180 | int util_replace_whitespace(const char *str, char *to, size_t len); | ||
181 | int util_replace_chars(char *str, const char *white); | ||
182 | unsigned int util_string_hash32(const char *key); | ||
183 | uint64_t util_string_bloom64(const char *str); | ||
184 | |||
185 | /* libudev-util-private.c */ | ||
186 | int util_create_path(struct udev *udev, const char *path); | ||
187 | int util_create_path_selinux(struct udev *udev, const char *path); | ||
188 | int util_delete_path(struct udev *udev, const char *path); | ||
189 | uid_t util_lookup_user(struct udev *udev, const char *user); | ||
190 | gid_t util_lookup_group(struct udev *udev, const char *group); | ||
191 | int util_resolve_subsys_kernel(struct udev *udev, const char *string, | ||
192 | char *result, size_t maxsize, int read_value); | ||
193 | unsigned long long ts_usec(const struct timespec *ts); | ||
194 | unsigned long long now_usec(void); | ||
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 | ||
diff --git a/src/udev/src/libudev-queue-private.c b/src/udev/src/libudev-queue-private.c new file mode 100644 index 000000000..71771950a --- /dev/null +++ b/src/udev/src/libudev-queue-private.c | |||
@@ -0,0 +1,412 @@ | |||
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[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 | } | ||
diff --git a/src/udev/src/libudev-queue.c b/src/udev/src/libudev-queue.c new file mode 100644 index 000000000..0e82cb6ae --- /dev/null +++ b/src/udev/src/libudev-queue.c | |||
@@ -0,0 +1,474 @@ | |||
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 void udev_queue_unref(struct udev_queue *udev_queue) | ||
97 | { | ||
98 | if (udev_queue == NULL) | ||
99 | return; | ||
100 | udev_queue->refcount--; | ||
101 | if (udev_queue->refcount > 0) | ||
102 | return; | ||
103 | udev_list_cleanup(&udev_queue->queue_list); | ||
104 | free(udev_queue); | ||
105 | } | ||
106 | |||
107 | /** | ||
108 | * udev_queue_get_udev: | ||
109 | * @udev_queue: udev queue context | ||
110 | * | ||
111 | * Retrieve the udev library context the queue context was created with. | ||
112 | * | ||
113 | * Returns: the udev library context. | ||
114 | **/ | ||
115 | UDEV_EXPORT struct udev *udev_queue_get_udev(struct udev_queue *udev_queue) | ||
116 | { | ||
117 | if (udev_queue == NULL) | ||
118 | return NULL; | ||
119 | return udev_queue->udev; | ||
120 | } | ||
121 | |||
122 | unsigned long long int udev_get_kernel_seqnum(struct udev *udev) | ||
123 | { | ||
124 | char filename[UTIL_PATH_SIZE]; | ||
125 | unsigned long long int seqnum; | ||
126 | int fd; | ||
127 | char buf[32]; | ||
128 | ssize_t len; | ||
129 | |||
130 | util_strscpyl(filename, sizeof(filename), udev_get_sys_path(udev), "/kernel/uevent_seqnum", NULL); | ||
131 | fd = open(filename, O_RDONLY|O_CLOEXEC); | ||
132 | if (fd < 0) | ||
133 | return 0; | ||
134 | len = read(fd, buf, sizeof(buf)); | ||
135 | close(fd); | ||
136 | if (len <= 2) | ||
137 | return 0; | ||
138 | buf[len-1] = '\0'; | ||
139 | seqnum = strtoull(buf, NULL, 10); | ||
140 | return seqnum; | ||
141 | } | ||
142 | |||
143 | /** | ||
144 | * udev_queue_get_kernel_seqnum: | ||
145 | * @udev_queue: udev queue context | ||
146 | * | ||
147 | * Returns: the current kernel event sequence number. | ||
148 | **/ | ||
149 | UDEV_EXPORT unsigned long long int udev_queue_get_kernel_seqnum(struct udev_queue *udev_queue) | ||
150 | { | ||
151 | unsigned long long int seqnum; | ||
152 | |||
153 | if (udev_queue == NULL) | ||
154 | return -EINVAL; | ||
155 | |||
156 | seqnum = udev_get_kernel_seqnum(udev_queue->udev); | ||
157 | dbg(udev_queue->udev, "seqnum=%llu\n", seqnum); | ||
158 | return seqnum; | ||
159 | } | ||
160 | |||
161 | int udev_queue_read_seqnum(FILE *queue_file, unsigned long long int *seqnum) | ||
162 | { | ||
163 | if (fread(seqnum, sizeof(unsigned long long int), 1, queue_file) != 1) | ||
164 | return -1; | ||
165 | |||
166 | return 0; | ||
167 | } | ||
168 | |||
169 | ssize_t udev_queue_skip_devpath(FILE *queue_file) | ||
170 | { | ||
171 | unsigned short int len; | ||
172 | |||
173 | if (fread(&len, sizeof(unsigned short int), 1, queue_file) == 1) { | ||
174 | char devpath[len]; | ||
175 | |||
176 | /* use fread to skip, fseek might drop buffered data */ | ||
177 | if (fread(devpath, 1, len, queue_file) == len) | ||
178 | return len; | ||
179 | } | ||
180 | |||
181 | return -1; | ||
182 | } | ||
183 | |||
184 | ssize_t udev_queue_read_devpath(FILE *queue_file, char *devpath, size_t size) | ||
185 | { | ||
186 | unsigned short int read_bytes = 0; | ||
187 | unsigned short int len; | ||
188 | |||
189 | if (fread(&len, sizeof(unsigned short int), 1, queue_file) != 1) | ||
190 | return -1; | ||
191 | |||
192 | read_bytes = (len < size - 1) ? len : size - 1; | ||
193 | if (fread(devpath, 1, read_bytes, queue_file) != read_bytes) | ||
194 | return -1; | ||
195 | devpath[read_bytes] = '\0'; | ||
196 | |||
197 | /* if devpath was too long, skip unread characters */ | ||
198 | if (read_bytes != len) { | ||
199 | unsigned short int skip_bytes = len - read_bytes; | ||
200 | char buf[skip_bytes]; | ||
201 | |||
202 | if (fread(buf, 1, skip_bytes, queue_file) != skip_bytes) | ||
203 | return -1; | ||
204 | } | ||
205 | |||
206 | return read_bytes; | ||
207 | } | ||
208 | |||
209 | static FILE *open_queue_file(struct udev_queue *udev_queue, unsigned long long int *seqnum_start) | ||
210 | { | ||
211 | char filename[UTIL_PATH_SIZE]; | ||
212 | FILE *queue_file; | ||
213 | |||
214 | util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev_queue->udev), "/queue.bin", NULL); | ||
215 | queue_file = fopen(filename, "re"); | ||
216 | if (queue_file == NULL) | ||
217 | return NULL; | ||
218 | |||
219 | if (udev_queue_read_seqnum(queue_file, seqnum_start) < 0) { | ||
220 | err(udev_queue->udev, "corrupt queue file\n"); | ||
221 | fclose(queue_file); | ||
222 | return NULL; | ||
223 | } | ||
224 | |||
225 | return queue_file; | ||
226 | } | ||
227 | |||
228 | /** | ||
229 | * udev_queue_get_udev_seqnum: | ||
230 | * @udev_queue: udev queue context | ||
231 | * | ||
232 | * Returns: the last known udev event sequence number. | ||
233 | **/ | ||
234 | UDEV_EXPORT unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *udev_queue) | ||
235 | { | ||
236 | unsigned long long int seqnum_udev; | ||
237 | FILE *queue_file; | ||
238 | |||
239 | queue_file = open_queue_file(udev_queue, &seqnum_udev); | ||
240 | if (queue_file == NULL) | ||
241 | return 0; | ||
242 | |||
243 | for (;;) { | ||
244 | unsigned long long int seqnum; | ||
245 | ssize_t devpath_len; | ||
246 | |||
247 | if (udev_queue_read_seqnum(queue_file, &seqnum) < 0) | ||
248 | break; | ||
249 | devpath_len = udev_queue_skip_devpath(queue_file); | ||
250 | if (devpath_len < 0) | ||
251 | break; | ||
252 | if (devpath_len > 0) | ||
253 | seqnum_udev = seqnum; | ||
254 | } | ||
255 | |||
256 | fclose(queue_file); | ||
257 | return seqnum_udev; | ||
258 | } | ||
259 | |||
260 | /** | ||
261 | * udev_queue_get_udev_is_active: | ||
262 | * @udev_queue: udev queue context | ||
263 | * | ||
264 | * Returns: a flag indicating if udev is active. | ||
265 | **/ | ||
266 | UDEV_EXPORT int udev_queue_get_udev_is_active(struct udev_queue *udev_queue) | ||
267 | { | ||
268 | unsigned long long int seqnum_start; | ||
269 | FILE *queue_file; | ||
270 | |||
271 | queue_file = open_queue_file(udev_queue, &seqnum_start); | ||
272 | if (queue_file == NULL) | ||
273 | return 0; | ||
274 | |||
275 | fclose(queue_file); | ||
276 | return 1; | ||
277 | } | ||
278 | |||
279 | /** | ||
280 | * udev_queue_get_queue_is_empty: | ||
281 | * @udev_queue: udev queue context | ||
282 | * | ||
283 | * Returns: a flag indicating if udev is currently handling events. | ||
284 | **/ | ||
285 | UDEV_EXPORT int udev_queue_get_queue_is_empty(struct udev_queue *udev_queue) | ||
286 | { | ||
287 | unsigned long long int seqnum_kernel; | ||
288 | unsigned long long int seqnum_udev = 0; | ||
289 | int queued = 0; | ||
290 | int is_empty = 0; | ||
291 | FILE *queue_file; | ||
292 | |||
293 | if (udev_queue == NULL) | ||
294 | return -EINVAL; | ||
295 | queue_file = open_queue_file(udev_queue, &seqnum_udev); | ||
296 | if (queue_file == NULL) | ||
297 | return 1; | ||
298 | |||
299 | for (;;) { | ||
300 | unsigned long long int seqnum; | ||
301 | ssize_t devpath_len; | ||
302 | |||
303 | if (udev_queue_read_seqnum(queue_file, &seqnum) < 0) | ||
304 | break; | ||
305 | devpath_len = udev_queue_skip_devpath(queue_file); | ||
306 | if (devpath_len < 0) | ||
307 | break; | ||
308 | |||
309 | if (devpath_len > 0) { | ||
310 | queued++; | ||
311 | seqnum_udev = seqnum; | ||
312 | } else { | ||
313 | queued--; | ||
314 | } | ||
315 | } | ||
316 | |||
317 | if (queued > 0) { | ||
318 | dbg(udev_queue->udev, "queue is not empty\n"); | ||
319 | goto out; | ||
320 | } | ||
321 | |||
322 | seqnum_kernel = udev_queue_get_kernel_seqnum(udev_queue); | ||
323 | if (seqnum_udev < seqnum_kernel) { | ||
324 | dbg(udev_queue->udev, "queue is empty but kernel events still pending [%llu]<->[%llu]\n", | ||
325 | seqnum_kernel, seqnum_udev); | ||
326 | goto out; | ||
327 | } | ||
328 | |||
329 | dbg(udev_queue->udev, "queue is empty\n"); | ||
330 | is_empty = 1; | ||
331 | |||
332 | out: | ||
333 | fclose(queue_file); | ||
334 | return is_empty; | ||
335 | } | ||
336 | |||
337 | /** | ||
338 | * udev_queue_get_seqnum_sequence_is_finished: | ||
339 | * @udev_queue: udev queue context | ||
340 | * @start: first event sequence number | ||
341 | * @end: last event sequence number | ||
342 | * | ||
343 | * Returns: a flag indicating if any of the sequence numbers in the given range is currently active. | ||
344 | **/ | ||
345 | UDEV_EXPORT int udev_queue_get_seqnum_sequence_is_finished(struct udev_queue *udev_queue, | ||
346 | unsigned long long int start, unsigned long long int end) | ||
347 | { | ||
348 | unsigned long long int seqnum; | ||
349 | ssize_t devpath_len; | ||
350 | int unfinished; | ||
351 | FILE *queue_file; | ||
352 | |||
353 | if (udev_queue == NULL) | ||
354 | return -EINVAL; | ||
355 | queue_file = open_queue_file(udev_queue, &seqnum); | ||
356 | if (queue_file == NULL) | ||
357 | return 1; | ||
358 | if (start < seqnum) | ||
359 | start = seqnum; | ||
360 | if (start > end) { | ||
361 | fclose(queue_file); | ||
362 | return 1; | ||
363 | } | ||
364 | if (end - start > INT_MAX - 1) { | ||
365 | fclose(queue_file); | ||
366 | return -EOVERFLOW; | ||
367 | } | ||
368 | |||
369 | /* | ||
370 | * we might start with 0, and handle the initial seqnum | ||
371 | * only when we find an entry in the queue file | ||
372 | **/ | ||
373 | unfinished = end - start; | ||
374 | |||
375 | do { | ||
376 | if (udev_queue_read_seqnum(queue_file, &seqnum) < 0) | ||
377 | break; | ||
378 | devpath_len = udev_queue_skip_devpath(queue_file); | ||
379 | if (devpath_len < 0) | ||
380 | break; | ||
381 | |||
382 | /* | ||
383 | * we might start with an empty or re-build queue file, where | ||
384 | * the initial seqnum is not recorded as finished | ||
385 | */ | ||
386 | if (start == seqnum && devpath_len > 0) | ||
387 | unfinished++; | ||
388 | |||
389 | if (devpath_len == 0) { | ||
390 | if (seqnum >= start && seqnum <= end) | ||
391 | unfinished--; | ||
392 | } | ||
393 | } while (unfinished > 0); | ||
394 | |||
395 | fclose(queue_file); | ||
396 | |||
397 | return (unfinished == 0); | ||
398 | } | ||
399 | |||
400 | /** | ||
401 | * udev_queue_get_seqnum_is_finished: | ||
402 | * @udev_queue: udev queue context | ||
403 | * @seqnum: sequence number | ||
404 | * | ||
405 | * Returns: a flag indicating if the given sequence number is currently active. | ||
406 | **/ | ||
407 | UDEV_EXPORT int udev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, unsigned long long int seqnum) | ||
408 | { | ||
409 | if (!udev_queue_get_seqnum_sequence_is_finished(udev_queue, seqnum, seqnum)) | ||
410 | return 0; | ||
411 | |||
412 | dbg(udev_queue->udev, "seqnum: %llu finished\n", seqnum); | ||
413 | return 1; | ||
414 | } | ||
415 | |||
416 | /** | ||
417 | * udev_queue_get_queued_list_entry: | ||
418 | * @udev_queue: udev queue context | ||
419 | * | ||
420 | * Returns: the first entry of the list of queued events. | ||
421 | **/ | ||
422 | UDEV_EXPORT struct udev_list_entry *udev_queue_get_queued_list_entry(struct udev_queue *udev_queue) | ||
423 | { | ||
424 | unsigned long long int seqnum; | ||
425 | FILE *queue_file; | ||
426 | |||
427 | if (udev_queue == NULL) | ||
428 | return NULL; | ||
429 | udev_list_cleanup(&udev_queue->queue_list); | ||
430 | |||
431 | queue_file = open_queue_file(udev_queue, &seqnum); | ||
432 | if (queue_file == NULL) | ||
433 | return NULL; | ||
434 | |||
435 | for (;;) { | ||
436 | char syspath[UTIL_PATH_SIZE]; | ||
437 | char *s; | ||
438 | size_t l; | ||
439 | ssize_t len; | ||
440 | char seqnum_str[32]; | ||
441 | struct udev_list_entry *list_entry; | ||
442 | |||
443 | if (udev_queue_read_seqnum(queue_file, &seqnum) < 0) | ||
444 | break; | ||
445 | snprintf(seqnum_str, sizeof(seqnum_str), "%llu", seqnum); | ||
446 | |||
447 | s = syspath; | ||
448 | l = util_strpcpyl(&s, sizeof(syspath), udev_get_sys_path(udev_queue->udev), NULL); | ||
449 | len = udev_queue_read_devpath(queue_file, s, l); | ||
450 | if (len < 0) | ||
451 | break; | ||
452 | |||
453 | if (len > 0) { | ||
454 | udev_list_entry_add(&udev_queue->queue_list, syspath, seqnum_str); | ||
455 | } else { | ||
456 | udev_list_entry_foreach(list_entry, udev_list_get_entry(&udev_queue->queue_list)) { | ||
457 | if (strcmp(seqnum_str, udev_list_entry_get_value(list_entry)) == 0) { | ||
458 | udev_list_entry_delete(list_entry); | ||
459 | break; | ||
460 | } | ||
461 | } | ||
462 | } | ||
463 | } | ||
464 | fclose(queue_file); | ||
465 | |||
466 | return udev_list_get_entry(&udev_queue->queue_list); | ||
467 | } | ||
468 | |||
469 | struct udev_list_entry *udev_queue_get_failed_list_entry(struct udev_queue *udev_queue); | ||
470 | UDEV_EXPORT struct udev_list_entry *udev_queue_get_failed_list_entry(struct udev_queue *udev_queue) | ||
471 | { | ||
472 | errno = ENOSYS; | ||
473 | return NULL; | ||
474 | } | ||
diff --git a/src/udev/src/libudev-selinux-private.c b/src/udev/src/libudev-selinux-private.c new file mode 100644 index 000000000..0f2a617b1 --- /dev/null +++ b/src/udev/src/libudev-selinux-private.c | |||
@@ -0,0 +1,109 @@ | |||
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 <stdarg.h> | ||
16 | #include <unistd.h> | ||
17 | #include <selinux/selinux.h> | ||
18 | |||
19 | #include "libudev.h" | ||
20 | #include "libudev-private.h" | ||
21 | |||
22 | static int selinux_enabled; | ||
23 | security_context_t selinux_prev_scontext; | ||
24 | |||
25 | void udev_selinux_init(struct udev *udev) | ||
26 | { | ||
27 | /* record the present security context */ | ||
28 | selinux_enabled = (is_selinux_enabled() > 0); | ||
29 | info(udev, "selinux=%i\n", selinux_enabled); | ||
30 | if (!selinux_enabled) | ||
31 | return; | ||
32 | matchpathcon_init_prefix(NULL, udev_get_dev_path(udev)); | ||
33 | if (getfscreatecon(&selinux_prev_scontext) < 0) { | ||
34 | err(udev, "getfscreatecon failed\n"); | ||
35 | selinux_prev_scontext = NULL; | ||
36 | } | ||
37 | } | ||
38 | |||
39 | void udev_selinux_exit(struct udev *udev) | ||
40 | { | ||
41 | if (!selinux_enabled) | ||
42 | return; | ||
43 | freecon(selinux_prev_scontext); | ||
44 | selinux_prev_scontext = NULL; | ||
45 | } | ||
46 | |||
47 | void udev_selinux_lsetfilecon(struct udev *udev, const char *file, unsigned int mode) | ||
48 | { | ||
49 | security_context_t scontext = NULL; | ||
50 | |||
51 | if (!selinux_enabled) | ||
52 | return; | ||
53 | if (matchpathcon(file, mode, &scontext) < 0) { | ||
54 | err(udev, "matchpathcon(%s) failed\n", file); | ||
55 | return; | ||
56 | } | ||
57 | if (lsetfilecon(file, scontext) < 0) | ||
58 | err(udev, "setfilecon %s failed: %m\n", file); | ||
59 | freecon(scontext); | ||
60 | } | ||
61 | |||
62 | void udev_selinux_setfscreatecon(struct udev *udev, const char *file, unsigned int mode) | ||
63 | { | ||
64 | security_context_t scontext = NULL; | ||
65 | |||
66 | if (!selinux_enabled) | ||
67 | return; | ||
68 | |||
69 | if (matchpathcon(file, mode, &scontext) < 0) { | ||
70 | err(udev, "matchpathcon(%s) failed\n", file); | ||
71 | return; | ||
72 | } | ||
73 | if (setfscreatecon(scontext) < 0) | ||
74 | err(udev, "setfscreatecon %s failed: %m\n", file); | ||
75 | freecon(scontext); | ||
76 | } | ||
77 | |||
78 | void udev_selinux_resetfscreatecon(struct udev *udev) | ||
79 | { | ||
80 | if (!selinux_enabled) | ||
81 | return; | ||
82 | if (setfscreatecon(selinux_prev_scontext) < 0) | ||
83 | err(udev, "setfscreatecon failed: %m\n"); | ||
84 | } | ||
85 | |||
86 | void udev_selinux_setfscreateconat(struct udev *udev, int dfd, const char *file, unsigned int mode) | ||
87 | { | ||
88 | char filename[UTIL_PATH_SIZE]; | ||
89 | |||
90 | if (!selinux_enabled) | ||
91 | return; | ||
92 | |||
93 | /* resolve relative filename */ | ||
94 | if (file[0] != '/') { | ||
95 | char procfd[UTIL_PATH_SIZE]; | ||
96 | char target[UTIL_PATH_SIZE]; | ||
97 | ssize_t len; | ||
98 | |||
99 | snprintf(procfd, sizeof(procfd), "/proc/%u/fd/%u", getpid(), dfd); | ||
100 | len = readlink(procfd, target, sizeof(target)); | ||
101 | if (len <= 0 || len == sizeof(target)) | ||
102 | return; | ||
103 | target[len] = '\0'; | ||
104 | |||
105 | util_strscpyl(filename, sizeof(filename), target, "/", file, NULL); | ||
106 | file = filename; | ||
107 | } | ||
108 | udev_selinux_setfscreatecon(udev, file, mode); | ||
109 | } | ||
diff --git a/src/udev/src/libudev-util-private.c b/src/udev/src/libudev-util-private.c new file mode 100644 index 000000000..08f0ba222 --- /dev/null +++ b/src/udev/src/libudev-util-private.c | |||
@@ -0,0 +1,242 @@ | |||
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 | size_t buflen = sysconf(_SC_GETPW_R_SIZE_MAX); | ||
120 | char buf[buflen]; | ||
121 | struct passwd pwbuf; | ||
122 | struct passwd *pw; | ||
123 | uid_t uid; | ||
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 | size_t buflen = sysconf(_SC_GETGR_R_SIZE_MAX); | ||
145 | char *buf; | ||
146 | struct group grbuf; | ||
147 | struct group *gr; | ||
148 | gid_t gid = 0; | ||
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 | } | ||
diff --git a/src/udev/src/libudev-util.c b/src/udev/src/libudev-util.c new file mode 100644 index 000000000..7e345f0fb --- /dev/null +++ b/src/udev/src/libudev-util.c | |||
@@ -0,0 +1,570 @@ | |||
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 | } | ||
diff --git a/src/udev/src/libudev.c b/src/udev/src/libudev.c new file mode 100644 index 000000000..d954daef6 --- /dev/null +++ b/src/udev/src/libudev.c | |||
@@ -0,0 +1,457 @@ | |||
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[2], "%s/rules.d", udev->run_path) < 0) | ||
265 | goto err; | ||
266 | |||
267 | /* /etc/udev -- local administration rules */ | ||
268 | udev->rules_path[1] = strdup(SYSCONFDIR "/udev/rules.d"); | ||
269 | if (!udev->rules_path[1]) | ||
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 void udev_unref(struct udev *udev) | ||
316 | { | ||
317 | if (udev == NULL) | ||
318 | return; | ||
319 | udev->refcount--; | ||
320 | if (udev->refcount > 0) | ||
321 | return; | ||
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 | } | ||
332 | |||
333 | /** | ||
334 | * udev_set_log_fn: | ||
335 | * @udev: udev library context | ||
336 | * @log_fn: function to be called for logging messages | ||
337 | * | ||
338 | * The built-in logging writes to stderr. It can be | ||
339 | * overridden by a custom function, to plug log messages | ||
340 | * into the users' logging functionality. | ||
341 | * | ||
342 | **/ | ||
343 | UDEV_EXPORT void udev_set_log_fn(struct udev *udev, | ||
344 | void (*log_fn)(struct udev *udev, | ||
345 | int priority, const char *file, int line, const char *fn, | ||
346 | const char *format, va_list args)) | ||
347 | { | ||
348 | udev->log_fn = log_fn; | ||
349 | info(udev, "custom logging function %p registered\n", log_fn); | ||
350 | } | ||
351 | |||
352 | /** | ||
353 | * udev_get_log_priority: | ||
354 | * @udev: udev library context | ||
355 | * | ||
356 | * The initial logging priority is read from the udev config file | ||
357 | * at startup. | ||
358 | * | ||
359 | * Returns: the current logging priority | ||
360 | **/ | ||
361 | UDEV_EXPORT int udev_get_log_priority(struct udev *udev) | ||
362 | { | ||
363 | return udev->log_priority; | ||
364 | } | ||
365 | |||
366 | /** | ||
367 | * udev_set_log_priority: | ||
368 | * @udev: udev library context | ||
369 | * @priority: the new logging priority | ||
370 | * | ||
371 | * Set the current logging priority. The value controls which messages | ||
372 | * are logged. | ||
373 | **/ | ||
374 | UDEV_EXPORT void udev_set_log_priority(struct udev *udev, int priority) | ||
375 | { | ||
376 | char num[32]; | ||
377 | |||
378 | udev->log_priority = priority; | ||
379 | snprintf(num, sizeof(num), "%u", udev->log_priority); | ||
380 | udev_add_property(udev, "UDEV_LOG", num); | ||
381 | } | ||
382 | |||
383 | int udev_get_rules_path(struct udev *udev, char **path[], unsigned long long *stamp_usec[]) | ||
384 | { | ||
385 | *path = udev->rules_path; | ||
386 | if (stamp_usec) | ||
387 | *stamp_usec = udev->rules_path_ts; | ||
388 | return udev->rules_path_count; | ||
389 | } | ||
390 | |||
391 | /** | ||
392 | * udev_get_sys_path: | ||
393 | * @udev: udev library context | ||
394 | * | ||
395 | * Retrieve the sysfs mount point. The default is "/sys". For | ||
396 | * testing purposes, it can be overridden with udev_sys= | ||
397 | * in the udev configuration file. | ||
398 | * | ||
399 | * Returns: the sys mount point | ||
400 | **/ | ||
401 | UDEV_EXPORT const char *udev_get_sys_path(struct udev *udev) | ||
402 | { | ||
403 | if (udev == NULL) | ||
404 | return NULL; | ||
405 | return udev->sys_path; | ||
406 | } | ||
407 | |||
408 | /** | ||
409 | * udev_get_dev_path: | ||
410 | * @udev: udev library context | ||
411 | * | ||
412 | * Retrieve the device directory path. The default value is "/dev", | ||
413 | * the actual value may be overridden in the udev configuration | ||
414 | * file. | ||
415 | * | ||
416 | * Returns: the device directory path | ||
417 | **/ | ||
418 | UDEV_EXPORT const char *udev_get_dev_path(struct udev *udev) | ||
419 | { | ||
420 | if (udev == NULL) | ||
421 | return NULL; | ||
422 | return udev->dev_path; | ||
423 | } | ||
424 | |||
425 | /** | ||
426 | * udev_get_run_path: | ||
427 | * @udev: udev library context | ||
428 | * | ||
429 | * Retrieve the udev runtime directory path. The default is "/run/udev". | ||
430 | * | ||
431 | * Returns: the runtime directory path | ||
432 | **/ | ||
433 | UDEV_EXPORT const char *udev_get_run_path(struct udev *udev) | ||
434 | { | ||
435 | if (udev == NULL) | ||
436 | return NULL; | ||
437 | return udev->run_path; | ||
438 | } | ||
439 | |||
440 | struct udev_list_entry *udev_add_property(struct udev *udev, const char *key, const char *value) | ||
441 | { | ||
442 | if (value == NULL) { | ||
443 | struct udev_list_entry *list_entry; | ||
444 | |||
445 | list_entry = udev_get_properties_list_entry(udev); | ||
446 | list_entry = udev_list_entry_get_by_name(list_entry, key); | ||
447 | if (list_entry != NULL) | ||
448 | udev_list_entry_delete(list_entry); | ||
449 | return NULL; | ||
450 | } | ||
451 | return udev_list_entry_add(&udev->properties_list, key, value); | ||
452 | } | ||
453 | |||
454 | struct udev_list_entry *udev_get_properties_list_entry(struct udev *udev) | ||
455 | { | ||
456 | return udev_list_get_entry(&udev->properties_list); | ||
457 | } | ||
diff --git a/src/udev/src/libudev.h b/src/udev/src/libudev.h new file mode 100644 index 000000000..10e098d4f --- /dev/null +++ b/src/udev/src/libudev.h | |||
@@ -0,0 +1,189 @@ | |||
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 | void 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 | void 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_environment(struct udev *udev); | ||
80 | /* udev_device_get_parent_*() does not take a reference on the returned device, it is automatically unref'd with the parent */ | ||
81 | struct udev_device *udev_device_get_parent(struct udev_device *udev_device); | ||
82 | struct udev_device *udev_device_get_parent_with_subsystem_devtype(struct udev_device *udev_device, | ||
83 | const char *subsystem, const char *devtype); | ||
84 | /* retrieve device properties */ | ||
85 | const char *udev_device_get_devpath(struct udev_device *udev_device); | ||
86 | const char *udev_device_get_subsystem(struct udev_device *udev_device); | ||
87 | const char *udev_device_get_devtype(struct udev_device *udev_device); | ||
88 | const char *udev_device_get_syspath(struct udev_device *udev_device); | ||
89 | const char *udev_device_get_sysname(struct udev_device *udev_device); | ||
90 | const char *udev_device_get_sysnum(struct udev_device *udev_device); | ||
91 | const char *udev_device_get_devnode(struct udev_device *udev_device); | ||
92 | int udev_device_get_is_initialized(struct udev_device *udev_device); | ||
93 | struct udev_list_entry *udev_device_get_devlinks_list_entry(struct udev_device *udev_device); | ||
94 | struct udev_list_entry *udev_device_get_properties_list_entry(struct udev_device *udev_device); | ||
95 | struct udev_list_entry *udev_device_get_tags_list_entry(struct udev_device *udev_device); | ||
96 | struct udev_list_entry *udev_device_get_sysattr_list_entry(struct udev_device *udev_device); | ||
97 | const char *udev_device_get_property_value(struct udev_device *udev_device, const char *key); | ||
98 | const char *udev_device_get_driver(struct udev_device *udev_device); | ||
99 | dev_t udev_device_get_devnum(struct udev_device *udev_device); | ||
100 | const char *udev_device_get_action(struct udev_device *udev_device); | ||
101 | unsigned long long int udev_device_get_seqnum(struct udev_device *udev_device); | ||
102 | unsigned long long int udev_device_get_usec_since_initialized(struct udev_device *udev_device); | ||
103 | const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const char *sysattr); | ||
104 | int udev_device_has_tag(struct udev_device *udev_device, const char *tag); | ||
105 | |||
106 | /* | ||
107 | * udev_monitor | ||
108 | * | ||
109 | * access to kernel uevents and udev events | ||
110 | */ | ||
111 | struct udev_monitor; | ||
112 | struct udev_monitor *udev_monitor_ref(struct udev_monitor *udev_monitor); | ||
113 | void udev_monitor_unref(struct udev_monitor *udev_monitor); | ||
114 | struct udev *udev_monitor_get_udev(struct udev_monitor *udev_monitor); | ||
115 | /* kernel and udev generated events over netlink */ | ||
116 | struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, const char *name); | ||
117 | /* custom socket (use netlink and filters instead) */ | ||
118 | struct udev_monitor *udev_monitor_new_from_socket(struct udev *udev, const char *socket_path); | ||
119 | /* bind socket */ | ||
120 | int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor); | ||
121 | int udev_monitor_set_receive_buffer_size(struct udev_monitor *udev_monitor, int size); | ||
122 | int udev_monitor_get_fd(struct udev_monitor *udev_monitor); | ||
123 | struct udev_device *udev_monitor_receive_device(struct udev_monitor *udev_monitor); | ||
124 | /* in-kernel socket filters to select messages that get delivered to a listener */ | ||
125 | int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_monitor, | ||
126 | const char *subsystem, const char *devtype); | ||
127 | int udev_monitor_filter_add_match_tag(struct udev_monitor *udev_monitor, const char *tag); | ||
128 | int udev_monitor_filter_update(struct udev_monitor *udev_monitor); | ||
129 | int udev_monitor_filter_remove(struct udev_monitor *udev_monitor); | ||
130 | |||
131 | /* | ||
132 | * udev_enumerate | ||
133 | * | ||
134 | * search sysfs for specific devices and provide a sorted list | ||
135 | */ | ||
136 | struct udev_enumerate; | ||
137 | struct udev_enumerate *udev_enumerate_ref(struct udev_enumerate *udev_enumerate); | ||
138 | void udev_enumerate_unref(struct udev_enumerate *udev_enumerate); | ||
139 | struct udev *udev_enumerate_get_udev(struct udev_enumerate *udev_enumerate); | ||
140 | struct udev_enumerate *udev_enumerate_new(struct udev *udev); | ||
141 | /* device properties filter */ | ||
142 | int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem); | ||
143 | int udev_enumerate_add_nomatch_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem); | ||
144 | int udev_enumerate_add_match_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value); | ||
145 | int udev_enumerate_add_nomatch_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value); | ||
146 | int udev_enumerate_add_match_property(struct udev_enumerate *udev_enumerate, const char *property, const char *value); | ||
147 | int udev_enumerate_add_match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname); | ||
148 | int udev_enumerate_add_match_tag(struct udev_enumerate *udev_enumerate, const char *tag); | ||
149 | int udev_enumerate_add_match_parent(struct udev_enumerate *udev_enumerate, struct udev_device *parent); | ||
150 | int udev_enumerate_add_match_is_initialized(struct udev_enumerate *udev_enumerate); | ||
151 | int udev_enumerate_add_syspath(struct udev_enumerate *udev_enumerate, const char *syspath); | ||
152 | /* run enumeration with active filters */ | ||
153 | int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate); | ||
154 | int udev_enumerate_scan_subsystems(struct udev_enumerate *udev_enumerate); | ||
155 | /* return device list */ | ||
156 | struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *udev_enumerate); | ||
157 | |||
158 | /* | ||
159 | * udev_queue | ||
160 | * | ||
161 | * access to the currently running udev events | ||
162 | */ | ||
163 | struct udev_queue; | ||
164 | struct udev_queue *udev_queue_ref(struct udev_queue *udev_queue); | ||
165 | void udev_queue_unref(struct udev_queue *udev_queue); | ||
166 | struct udev *udev_queue_get_udev(struct udev_queue *udev_queue); | ||
167 | struct udev_queue *udev_queue_new(struct udev *udev); | ||
168 | unsigned long long int udev_queue_get_kernel_seqnum(struct udev_queue *udev_queue); | ||
169 | unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *udev_queue); | ||
170 | int udev_queue_get_udev_is_active(struct udev_queue *udev_queue); | ||
171 | int udev_queue_get_queue_is_empty(struct udev_queue *udev_queue); | ||
172 | int udev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, unsigned long long int seqnum); | ||
173 | int udev_queue_get_seqnum_sequence_is_finished(struct udev_queue *udev_queue, | ||
174 | unsigned long long int start, unsigned long long int end); | ||
175 | struct udev_list_entry *udev_queue_get_queued_list_entry(struct udev_queue *udev_queue); | ||
176 | |||
177 | /* | ||
178 | * udev_util | ||
179 | * | ||
180 | * udev specific utilities | ||
181 | */ | ||
182 | int udev_util_encode_string(const char *str, char *str_enc, size_t len); | ||
183 | |||
184 | |||
185 | #ifdef __cplusplus | ||
186 | } /* extern "C" */ | ||
187 | #endif | ||
188 | |||
189 | #endif | ||
diff --git a/src/udev/src/libudev.pc.in b/src/udev/src/libudev.pc.in new file mode 100644 index 000000000..c9a47fc9b --- /dev/null +++ b/src/udev/src/libudev.pc.in | |||
@@ -0,0 +1,11 @@ | |||
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} | ||
diff --git a/src/udev/src/mtd_probe/75-probe_mtd.rules b/src/udev/src/mtd_probe/75-probe_mtd.rules new file mode 100644 index 000000000..c0e083978 --- /dev/null +++ b/src/udev/src/mtd_probe/75-probe_mtd.rules | |||
@@ -0,0 +1,8 @@ | |||
1 | # do not edit this file, it will be overwritten on update | ||
2 | |||
3 | ACTION!="add", GOTO="mtd_probe_end" | ||
4 | |||
5 | KERNEL=="mtd*ro", IMPORT{program}="mtd_probe $devnode" | ||
6 | KERNEL=="mtd*ro", ENV{MTD_FTL}=="smartmedia", IMPORT{builtin}="kmod load sm_ftl" | ||
7 | |||
8 | LABEL="mtd_probe_end" | ||
diff --git a/src/udev/src/mtd_probe/mtd_probe.c b/src/udev/src/mtd_probe/mtd_probe.c new file mode 100644 index 000000000..1aa08d385 --- /dev/null +++ b/src/udev/src/mtd_probe/mtd_probe.c | |||
@@ -0,0 +1,51 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2010 - Maxim Levitsky | ||
3 | * | ||
4 | * mtd_probe 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 | * mtd_probe 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 mtd_probe; if not, write to the Free Software | ||
16 | * Foundation, Inc., 51 Franklin St, Fifth Floor, | ||
17 | * Boston, MA 02110-1301 USA | ||
18 | */ | ||
19 | #include "mtd_probe.h" | ||
20 | #include <stdio.h> | ||
21 | #include <sys/ioctl.h> | ||
22 | #include <mtd/mtd-user.h> | ||
23 | #include <sys/types.h> | ||
24 | #include <sys/stat.h> | ||
25 | #include <fcntl.h> | ||
26 | #include <unistd.h> | ||
27 | #include <stdlib.h> | ||
28 | |||
29 | int main(int argc, char** argv) | ||
30 | { | ||
31 | if (argc != 2) { | ||
32 | printf("usage: mtd_probe /dev/mtd[n]\n"); | ||
33 | return 1; | ||
34 | } | ||
35 | |||
36 | int mtd_fd = open(argv[1], O_RDONLY); | ||
37 | if (mtd_fd == -1) { | ||
38 | perror("open"); | ||
39 | exit(-1); | ||
40 | } | ||
41 | |||
42 | mtd_info_t mtd_info; | ||
43 | int error = ioctl(mtd_fd, MEMGETINFO, &mtd_info); | ||
44 | if (error == -1) { | ||
45 | perror("ioctl"); | ||
46 | exit(-1); | ||
47 | } | ||
48 | |||
49 | probe_smart_media(mtd_fd, &mtd_info); | ||
50 | return -1; | ||
51 | } | ||
diff --git a/src/udev/src/mtd_probe/mtd_probe.h b/src/udev/src/mtd_probe/mtd_probe.h new file mode 100644 index 000000000..2a37ede57 --- /dev/null +++ b/src/udev/src/mtd_probe/mtd_probe.h | |||
@@ -0,0 +1,49 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2010 - Maxim Levitsky | ||
3 | * | ||
4 | * mtd_probe 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 | * mtd_probe 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 mtd_probe; if not, write to the Free Software | ||
16 | * Foundation, Inc., 51 Franklin St, Fifth Floor, | ||
17 | * Boston, MA 02110-1301 USA | ||
18 | */ | ||
19 | |||
20 | #include <mtd/mtd-user.h> | ||
21 | |||
22 | /* Full oob structure as written on the flash */ | ||
23 | struct sm_oob { | ||
24 | uint32_t reserved; | ||
25 | uint8_t data_status; | ||
26 | uint8_t block_status; | ||
27 | uint8_t lba_copy1[2]; | ||
28 | uint8_t ecc2[3]; | ||
29 | uint8_t lba_copy2[2]; | ||
30 | uint8_t ecc1[3]; | ||
31 | } __attribute__((packed)); | ||
32 | |||
33 | |||
34 | /* one sector is always 512 bytes, but it can consist of two nand pages */ | ||
35 | #define SM_SECTOR_SIZE 512 | ||
36 | |||
37 | /* oob area is also 16 bytes, but might be from two pages */ | ||
38 | #define SM_OOB_SIZE 16 | ||
39 | |||
40 | /* This is maximum zone size, and all devices that have more that one zone | ||
41 | have this size */ | ||
42 | #define SM_MAX_ZONE_SIZE 1024 | ||
43 | |||
44 | /* support for small page nand */ | ||
45 | #define SM_SMALL_PAGE 256 | ||
46 | #define SM_SMALL_OOB_SIZE 8 | ||
47 | |||
48 | |||
49 | void probe_smart_media(int mtd_fd, mtd_info_t *info); | ||
diff --git a/src/udev/src/mtd_probe/probe_smartmedia.c b/src/udev/src/mtd_probe/probe_smartmedia.c new file mode 100644 index 000000000..b3cdefc63 --- /dev/null +++ b/src/udev/src/mtd_probe/probe_smartmedia.c | |||
@@ -0,0 +1,97 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2010 - Maxim Levitsky | ||
3 | * | ||
4 | * mtd_probe 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 | * mtd_probe 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 mtd_probe; if not, write to the Free Software | ||
16 | * Foundation, Inc., 51 Franklin St, Fifth Floor, | ||
17 | * Boston, MA 02110-1301 USA | ||
18 | */ | ||
19 | |||
20 | #include <stdio.h> | ||
21 | #include <stdlib.h> | ||
22 | #include <mtd/mtd-user.h> | ||
23 | #include <string.h> | ||
24 | #include <sys/types.h> | ||
25 | #include <sys/stat.h> | ||
26 | #include <fcntl.h> | ||
27 | #include <unistd.h> | ||
28 | #include <stdint.h> | ||
29 | #include <stdlib.h> | ||
30 | #include "mtd_probe.h" | ||
31 | |||
32 | static const uint8_t cis_signature[] = { | ||
33 | 0x01, 0x03, 0xD9, 0x01, 0xFF, 0x18, 0x02, 0xDF, 0x01, 0x20 | ||
34 | }; | ||
35 | |||
36 | |||
37 | void probe_smart_media(int mtd_fd, mtd_info_t* info) | ||
38 | { | ||
39 | char* cis_buffer = malloc(SM_SECTOR_SIZE); | ||
40 | |||
41 | if (!cis_buffer) | ||
42 | return; | ||
43 | |||
44 | if (info->type != MTD_NANDFLASH) | ||
45 | goto exit; | ||
46 | |||
47 | int sector_size = info->writesize; | ||
48 | int block_size = info->erasesize; | ||
49 | int size_in_megs = info->size / (1024 * 1024); | ||
50 | int spare_count; | ||
51 | |||
52 | |||
53 | if (sector_size != SM_SECTOR_SIZE && sector_size != SM_SMALL_PAGE) | ||
54 | goto exit; | ||
55 | |||
56 | switch(size_in_megs) { | ||
57 | case 1: | ||
58 | case 2: | ||
59 | spare_count = 6; | ||
60 | break; | ||
61 | case 4: | ||
62 | spare_count = 12; | ||
63 | break; | ||
64 | default: | ||
65 | spare_count = 24; | ||
66 | break; | ||
67 | } | ||
68 | |||
69 | |||
70 | int offset; | ||
71 | int cis_found = 0; | ||
72 | |||
73 | for (offset = 0 ; offset < block_size * spare_count ; | ||
74 | offset += sector_size) { | ||
75 | |||
76 | lseek(mtd_fd, SEEK_SET, offset); | ||
77 | if (read(mtd_fd, cis_buffer, SM_SECTOR_SIZE) == SM_SECTOR_SIZE){ | ||
78 | cis_found = 1; | ||
79 | break; | ||
80 | } | ||
81 | } | ||
82 | |||
83 | if (!cis_found) | ||
84 | goto exit; | ||
85 | |||
86 | if (memcmp(cis_buffer, cis_signature, sizeof(cis_signature)) != 0 && | ||
87 | (memcmp(cis_buffer + SM_SMALL_PAGE, cis_signature, | ||
88 | sizeof(cis_signature)) != 0)) | ||
89 | goto exit; | ||
90 | |||
91 | printf("MTD_FTL=smartmedia\n"); | ||
92 | free(cis_buffer); | ||
93 | exit(0); | ||
94 | exit: | ||
95 | free(cis_buffer); | ||
96 | return; | ||
97 | } | ||
diff --git a/src/udev/src/rule_generator/75-cd-aliases-generator.rules b/src/udev/src/rule_generator/75-cd-aliases-generator.rules new file mode 100644 index 000000000..e6da0101d --- /dev/null +++ b/src/udev/src/rule_generator/75-cd-aliases-generator.rules | |||
@@ -0,0 +1,9 @@ | |||
1 | # these rules generate rules for the /dev/{cdrom,dvd,...} symlinks | ||
2 | |||
3 | # the "path" of usb/ieee1394 devices changes frequently, use "id" | ||
4 | ACTION=="add", SUBSYSTEM=="block", SUBSYSTEMS=="usb|ieee1394", ENV{ID_CDROM}=="?*", ENV{GENERATED}!="?*", \ | ||
5 | PROGRAM="write_cd_rules by-id", SYMLINK+="%c", GOTO="persistent_cd_end" | ||
6 | |||
7 | ACTION=="add", SUBSYSTEM=="block", ENV{ID_CDROM}=="?*", ENV{GENERATED}!="?*", PROGRAM="write_cd_rules", SYMLINK+="%c" | ||
8 | |||
9 | LABEL="persistent_cd_end" | ||
diff --git a/src/udev/src/rule_generator/75-persistent-net-generator.rules b/src/udev/src/rule_generator/75-persistent-net-generator.rules new file mode 100644 index 000000000..4f8057347 --- /dev/null +++ b/src/udev/src/rule_generator/75-persistent-net-generator.rules | |||
@@ -0,0 +1,102 @@ | |||
1 | # do not edit this file, it will be overwritten on update | ||
2 | |||
3 | # these rules generate rules for persistent network device naming | ||
4 | # | ||
5 | # variables used to communicate: | ||
6 | # MATCHADDR MAC address used for the match | ||
7 | # MATCHID bus_id used for the match | ||
8 | # MATCHDRV driver name used for the match | ||
9 | # MATCHIFTYPE interface type match | ||
10 | # COMMENT comment to add to the generated rule | ||
11 | # INTERFACE_NAME requested name supplied by external tool | ||
12 | # INTERFACE_NEW new interface name returned by rule writer | ||
13 | |||
14 | ACTION!="add", GOTO="persistent_net_generator_end" | ||
15 | SUBSYSTEM!="net", GOTO="persistent_net_generator_end" | ||
16 | |||
17 | # ignore the interface if a name has already been set | ||
18 | NAME=="?*", GOTO="persistent_net_generator_end" | ||
19 | |||
20 | # device name whitelist | ||
21 | KERNEL!="eth*|ath*|wlan*[0-9]|msh*|ra*|sta*|ctc*|lcs*|hsi*", GOTO="persistent_net_generator_end" | ||
22 | |||
23 | # ignore Xen virtual interfaces | ||
24 | SUBSYSTEMS=="xen", GOTO="persistent_net_generator_end" | ||
25 | |||
26 | # read MAC address | ||
27 | ENV{MATCHADDR}="$attr{address}" | ||
28 | |||
29 | # match interface type | ||
30 | ENV{MATCHIFTYPE}="$attr{type}" | ||
31 | |||
32 | # ignore KVM virtual interfaces | ||
33 | ENV{MATCHADDR}=="52:54:00:*", GOTO="persistent_net_generator_end" | ||
34 | # ignore VMWare virtual interfaces | ||
35 | ENV{MATCHADDR}=="00:0c:29:*|00:50:56:*", GOTO="persistent_net_generator_end" | ||
36 | # ignore Hyper-V virtual interfaces | ||
37 | ENV{MATCHADDR}=="00:15:5d:*", GOTO="persistent_net_generator_end" | ||
38 | |||
39 | # These vendors are known to violate the local MAC address assignment scheme | ||
40 | # Interlan, DEC (UNIBUS or QBUS), Apollo, Cisco, Racal-Datacom | ||
41 | ENV{MATCHADDR}=="02:07:01:*", GOTO="globally_administered_whitelist" | ||
42 | # 3Com | ||
43 | ENV{MATCHADDR}=="02:60:60:*", GOTO="globally_administered_whitelist" | ||
44 | # 3Com IBM PC; Imagen; Valid; Cisco; Apple | ||
45 | ENV{MATCHADDR}=="02:60:8c:*", GOTO="globally_administered_whitelist" | ||
46 | # Intel | ||
47 | ENV{MATCHADDR}=="02:a0:c9:*", GOTO="globally_administered_whitelist" | ||
48 | # Olivetti | ||
49 | ENV{MATCHADDR}=="02:aa:3c:*", GOTO="globally_administered_whitelist" | ||
50 | # CMC Masscomp; Silicon Graphics; Prime EXL | ||
51 | ENV{MATCHADDR}=="02:cf:1f:*", GOTO="globally_administered_whitelist" | ||
52 | # Prominet Corporation Gigabit Ethernet Switch | ||
53 | ENV{MATCHADDR}=="02:e0:3b:*", GOTO="globally_administered_whitelist" | ||
54 | # BTI (Bus-Tech, Inc.) IBM Mainframes | ||
55 | ENV{MATCHADDR}=="02:e6:d3:*", GOTO="globally_administered_whitelist" | ||
56 | # Realtek | ||
57 | ENV{MATCHADDR}=="52:54:00:*", GOTO="globally_administered_whitelist" | ||
58 | # Novell 2000 | ||
59 | ENV{MATCHADDR}=="52:54:4c:*", GOTO="globally_administered_whitelist" | ||
60 | # Realtec | ||
61 | ENV{MATCHADDR}=="52:54:ab:*", GOTO="globally_administered_whitelist" | ||
62 | # Kingston Technologies | ||
63 | ENV{MATCHADDR}=="e2:0c:0f:*", GOTO="globally_administered_whitelist" | ||
64 | # Xensource | ||
65 | ENV{MATCHADDR}=="00:16:3e:*", GOTO="globally_administered_whitelist" | ||
66 | |||
67 | # match interface dev_id | ||
68 | ATTR{dev_id}=="?*", ENV{MATCHDEVID}="$attr{dev_id}" | ||
69 | |||
70 | # do not use "locally administered" MAC address | ||
71 | ENV{MATCHADDR}=="?[2367abef]:*", ENV{MATCHADDR}="" | ||
72 | |||
73 | # do not use empty address | ||
74 | ENV{MATCHADDR}=="00:00:00:00:00:00", ENV{MATCHADDR}="" | ||
75 | |||
76 | LABEL="globally_administered_whitelist" | ||
77 | |||
78 | # build comment line for generated rule: | ||
79 | SUBSYSTEMS=="pci", ENV{COMMENT}="PCI device $attr{vendor}:$attr{device} ($driver)" | ||
80 | SUBSYSTEMS=="usb", ATTRS{idVendor}=="?*", ENV{COMMENT}="USB device 0x$attr{idVendor}:0x$attr{idProduct} ($driver)" | ||
81 | SUBSYSTEMS=="pcmcia", ENV{COMMENT}="PCMCIA device $attr{card_id}:$attr{manf_id} ($driver)" | ||
82 | SUBSYSTEMS=="ieee1394", ENV{COMMENT}="Firewire device $attr{host_id})" | ||
83 | |||
84 | # ibmveth likes to use "locally administered" MAC addresses | ||
85 | DRIVERS=="ibmveth", ENV{MATCHADDR}="$attr{address}", ENV{COMMENT}="ibmveth ($id)" | ||
86 | |||
87 | # S/390 uses id matches only, do not use MAC address match | ||
88 | SUBSYSTEMS=="ccwgroup", ENV{COMMENT}="S/390 $driver device at $id", ENV{MATCHID}="$id", ENV{MATCHDRV}="$driver", ENV{MATCHADDR}="" | ||
89 | |||
90 | # see if we got enough data to create a rule | ||
91 | ENV{MATCHADDR}=="", ENV{MATCHID}=="", ENV{INTERFACE_NAME}=="", GOTO="persistent_net_generator_end" | ||
92 | |||
93 | # default comment | ||
94 | ENV{COMMENT}=="", ENV{COMMENT}="net device ($attr{driver})" | ||
95 | |||
96 | # write rule | ||
97 | DRIVERS=="?*", IMPORT{program}="write_net_rules" | ||
98 | |||
99 | # rename interface if needed | ||
100 | ENV{INTERFACE_NEW}=="?*", NAME="$env{INTERFACE_NEW}" | ||
101 | |||
102 | LABEL="persistent_net_generator_end" | ||
diff --git a/src/udev/src/rule_generator/rule_generator.functions b/src/udev/src/rule_generator/rule_generator.functions new file mode 100644 index 000000000..2eec1b6ab --- /dev/null +++ b/src/udev/src/rule_generator/rule_generator.functions | |||
@@ -0,0 +1,113 @@ | |||
1 | # functions used by the udev rule generator | ||
2 | |||
3 | # Copyright (C) 2006 Marco d'Itri <md@Linux.IT> | ||
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 | PATH='/usr/bin:/bin:/usr/sbin:/sbin' | ||
19 | |||
20 | # Read a single line from file $1 in the $DEVPATH directory. | ||
21 | # The function must not return an error even if the file does not exist. | ||
22 | sysread() { | ||
23 | local file="$1" | ||
24 | [ -e "/sys$DEVPATH/$file" ] || return 0 | ||
25 | local value | ||
26 | read value < "/sys$DEVPATH/$file" || return 0 | ||
27 | echo "$value" | ||
28 | } | ||
29 | |||
30 | sysreadlink() { | ||
31 | local file="$1" | ||
32 | [ -e "/sys$DEVPATH/$file" ] || return 0 | ||
33 | readlink -f /sys$DEVPATH/$file 2> /dev/null || true | ||
34 | } | ||
35 | |||
36 | # Return true if a directory is writeable. | ||
37 | writeable() { | ||
38 | if ln -s test-link $1/.is-writeable 2> /dev/null; then | ||
39 | rm -f $1/.is-writeable | ||
40 | return 0 | ||
41 | else | ||
42 | return 1 | ||
43 | fi | ||
44 | } | ||
45 | |||
46 | # Create a lock file for the current rules file. | ||
47 | lock_rules_file() { | ||
48 | RUNDIR=$(udevadm info --run) | ||
49 | [ -e "$RUNDIR" ] || return 0 | ||
50 | |||
51 | RULES_LOCK="$RUNDIR/.lock-${RULES_FILE##*/}" | ||
52 | |||
53 | retry=30 | ||
54 | while ! mkdir $RULES_LOCK 2> /dev/null; do | ||
55 | if [ $retry -eq 0 ]; then | ||
56 | echo "Cannot lock $RULES_FILE!" >&2 | ||
57 | exit 2 | ||
58 | fi | ||
59 | sleep 1 | ||
60 | retry=$(($retry - 1)) | ||
61 | done | ||
62 | } | ||
63 | |||
64 | unlock_rules_file() { | ||
65 | [ "$RULES_LOCK" ] || return 0 | ||
66 | rmdir $RULES_LOCK || true | ||
67 | } | ||
68 | |||
69 | # Choose the real rules file if it is writeable or a temporary file if not. | ||
70 | # Both files should be checked later when looking for existing rules. | ||
71 | choose_rules_file() { | ||
72 | RUNDIR=$(udevadm info --run) | ||
73 | local tmp_rules_file="$RUNDIR/tmp-rules--${RULES_FILE##*/}" | ||
74 | [ -e "$RULES_FILE" -o -e "$tmp_rules_file" ] || PRINT_HEADER=1 | ||
75 | |||
76 | if writeable ${RULES_FILE%/*}; then | ||
77 | RO_RULES_FILE='/dev/null' | ||
78 | else | ||
79 | RO_RULES_FILE=$RULES_FILE | ||
80 | RULES_FILE=$tmp_rules_file | ||
81 | fi | ||
82 | } | ||
83 | |||
84 | # Return the name of the first free device. | ||
85 | raw_find_next_available() { | ||
86 | local links="$1" | ||
87 | |||
88 | local basename=${links%%[ 0-9]*} | ||
89 | local max=-1 | ||
90 | for name in $links; do | ||
91 | local num=${name#$basename} | ||
92 | [ "$num" ] || num=0 | ||
93 | [ $num -gt $max ] && max=$num | ||
94 | done | ||
95 | |||
96 | local max=$(($max + 1)) | ||
97 | # "name0" actually is just "name" | ||
98 | [ $max -eq 0 ] && return | ||
99 | echo "$max" | ||
100 | } | ||
101 | |||
102 | # Find all rules matching a key (with action) and a pattern. | ||
103 | find_all_rules() { | ||
104 | local key="$1" | ||
105 | local linkre="$2" | ||
106 | local match="$3" | ||
107 | |||
108 | local search='.*[[:space:],]'"$key"'"('"$linkre"')".*' | ||
109 | echo $(sed -n -r -e 's/^#.*//' -e "${match}s/${search}/\1/p" \ | ||
110 | $RO_RULES_FILE \ | ||
111 | $([ -e $RULES_FILE ] && echo $RULES_FILE) \ | ||
112 | 2>/dev/null) | ||
113 | } | ||
diff --git a/src/udev/src/rule_generator/write_cd_rules b/src/udev/src/rule_generator/write_cd_rules new file mode 100644 index 000000000..645b9cd52 --- /dev/null +++ b/src/udev/src/rule_generator/write_cd_rules | |||
@@ -0,0 +1,126 @@ | |||
1 | #!/bin/sh -e | ||
2 | |||
3 | # This script is run if an optical drive lacks a rule for persistent naming. | ||
4 | # | ||
5 | # It adds symlinks for optical drives based on the device class determined | ||
6 | # by cdrom_id and used ID_PATH to identify the device. | ||
7 | |||
8 | # (C) 2006 Marco d'Itri <md@Linux.IT> | ||
9 | # | ||
10 | # This program is free software: you can redistribute it and/or modify | ||
11 | # it under the terms of the GNU General Public License as published by | ||
12 | # the Free Software Foundation, either version 2 of the License, or | ||
13 | # (at your option) any later version. | ||
14 | |||
15 | # This program is distributed in the hope that it will be useful, | ||
16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | # GNU General Public License for more details. | ||
19 | |||
20 | # You should have received a copy of the GNU General Public License | ||
21 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
22 | |||
23 | # debug, if UDEV_LOG=<debug> | ||
24 | if [ -n "$UDEV_LOG" ]; then | ||
25 | if [ "$UDEV_LOG" -ge 7 ]; then | ||
26 | set -x | ||
27 | fi | ||
28 | fi | ||
29 | |||
30 | RULES_FILE="/etc/udev/rules.d/70-persistent-cd.rules" | ||
31 | |||
32 | . /lib/udev/rule_generator.functions | ||
33 | |||
34 | find_next_available() { | ||
35 | raw_find_next_available "$(find_all_rules 'SYMLINK\+=' "$1")" | ||
36 | } | ||
37 | |||
38 | write_rule() { | ||
39 | local match="$1" | ||
40 | local link="$2" | ||
41 | local comment="$3" | ||
42 | |||
43 | { | ||
44 | if [ "$PRINT_HEADER" ]; then | ||
45 | PRINT_HEADER= | ||
46 | echo "# This file was automatically generated by the $0" | ||
47 | echo "# program, run by the cd-aliases-generator.rules rules file." | ||
48 | echo "#" | ||
49 | echo "# You can modify it, as long as you keep each rule on a single" | ||
50 | echo "# line, and set the \$GENERATED variable." | ||
51 | echo "" | ||
52 | fi | ||
53 | |||
54 | [ "$comment" ] && echo "# $comment" | ||
55 | echo "$match, SYMLINK+=\"$link\", ENV{GENERATED}=\"1\"" | ||
56 | } >> $RULES_FILE | ||
57 | SYMLINKS="$SYMLINKS $link" | ||
58 | } | ||
59 | |||
60 | if [ -z "$DEVPATH" ]; then | ||
61 | echo "Missing \$DEVPATH." >&2 | ||
62 | exit 1 | ||
63 | fi | ||
64 | if [ -z "$ID_CDROM" ]; then | ||
65 | echo "$DEVPATH is not a CD reader." >&2 | ||
66 | exit 1 | ||
67 | fi | ||
68 | |||
69 | if [ "$1" ]; then | ||
70 | METHOD="$1" | ||
71 | else | ||
72 | METHOD='by-path' | ||
73 | fi | ||
74 | |||
75 | case "$METHOD" in | ||
76 | by-path) | ||
77 | if [ -z "$ID_PATH" ]; then | ||
78 | echo "$DEVPATH not supported by path_id. by-id may work." >&2 | ||
79 | exit 1 | ||
80 | fi | ||
81 | RULE="ENV{ID_PATH}==\"$ID_PATH\"" | ||
82 | ;; | ||
83 | |||
84 | by-id) | ||
85 | if [ "$ID_SERIAL" ]; then | ||
86 | RULE="ENV{ID_SERIAL}==\"$ID_SERIAL\"" | ||
87 | elif [ "$ID_MODEL" -a "$ID_REVISION" ]; then | ||
88 | RULE="ENV{ID_MODEL}==\"$ID_MODEL\", ENV{ID_REVISION}==\"$ID_REVISION\"" | ||
89 | else | ||
90 | echo "$DEVPATH not supported by ata_id. by-path may work." >&2 | ||
91 | exit 1 | ||
92 | fi | ||
93 | ;; | ||
94 | |||
95 | *) | ||
96 | echo "Invalid argument (must be either by-path or by-id)." >&2 | ||
97 | exit 1 | ||
98 | ;; | ||
99 | esac | ||
100 | |||
101 | # Prevent concurrent processes from modifying the file at the same time. | ||
102 | lock_rules_file | ||
103 | |||
104 | # Check if the rules file is writeable. | ||
105 | choose_rules_file | ||
106 | |||
107 | link_num=$(find_next_available 'cdrom[0-9]*') | ||
108 | |||
109 | match="SUBSYSTEM==\"block\", ENV{ID_CDROM}==\"?*\", $RULE" | ||
110 | |||
111 | comment="$ID_MODEL ($ID_PATH)" | ||
112 | |||
113 | write_rule "$match" "cdrom$link_num" "$comment" | ||
114 | [ "$ID_CDROM_CD_R" -o "$ID_CDROM_CD_RW" ] && \ | ||
115 | write_rule "$match" "cdrw$link_num" | ||
116 | [ "$ID_CDROM_DVD" ] && \ | ||
117 | write_rule "$match" "dvd$link_num" | ||
118 | [ "$ID_CDROM_DVD_R" -o "$ID_CDROM_DVD_RW" -o "$ID_CDROM_DVD_RAM" ] && \ | ||
119 | write_rule "$match" "dvdrw$link_num" | ||
120 | echo >> $RULES_FILE | ||
121 | |||
122 | unlock_rules_file | ||
123 | |||
124 | echo $SYMLINKS | ||
125 | |||
126 | exit 0 | ||
diff --git a/src/udev/src/rule_generator/write_net_rules b/src/udev/src/rule_generator/write_net_rules new file mode 100644 index 000000000..bcea4b09d --- /dev/null +++ b/src/udev/src/rule_generator/write_net_rules | |||
@@ -0,0 +1,141 @@ | |||
1 | #!/bin/sh -e | ||
2 | |||
3 | # This script is run to create persistent network device naming rules | ||
4 | # based on properties of the device. | ||
5 | # If the interface needs to be renamed, INTERFACE_NEW=<name> will be printed | ||
6 | # on stdout to allow udev to IMPORT it. | ||
7 | |||
8 | # variables used to communicate: | ||
9 | # MATCHADDR MAC address used for the match | ||
10 | # MATCHID bus_id used for the match | ||
11 | # MATCHDEVID dev_id used for the match | ||
12 | # MATCHDRV driver name used for the match | ||
13 | # MATCHIFTYPE interface type match | ||
14 | # COMMENT comment to add to the generated rule | ||
15 | # INTERFACE_NAME requested name supplied by external tool | ||
16 | # INTERFACE_NEW new interface name returned by rule writer | ||
17 | |||
18 | # Copyright (C) 2006 Marco d'Itri <md@Linux.IT> | ||
19 | # Copyright (C) 2007 Kay Sievers <kay.sievers@vrfy.org> | ||
20 | # | ||
21 | # This program is free software: you can redistribute it and/or modify | ||
22 | # it under the terms of the GNU General Public License as published by | ||
23 | # the Free Software Foundation, either version 2 of the License, or | ||
24 | # (at your option) any later version. | ||
25 | # | ||
26 | # This program is distributed in the hope that it will be useful, | ||
27 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
28 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
29 | # GNU General Public License for more details. | ||
30 | # | ||
31 | # You should have received a copy of the GNU General Public License | ||
32 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
33 | |||
34 | # debug, if UDEV_LOG=<debug> | ||
35 | if [ -n "$UDEV_LOG" ]; then | ||
36 | if [ "$UDEV_LOG" -ge 7 ]; then | ||
37 | set -x | ||
38 | fi | ||
39 | fi | ||
40 | |||
41 | RULES_FILE='/etc/udev/rules.d/70-persistent-net.rules' | ||
42 | |||
43 | . /lib/udev/rule_generator.functions | ||
44 | |||
45 | interface_name_taken() { | ||
46 | local value="$(find_all_rules 'NAME=' $INTERFACE)" | ||
47 | if [ "$value" ]; then | ||
48 | return 0 | ||
49 | else | ||
50 | return 1 | ||
51 | fi | ||
52 | } | ||
53 | |||
54 | find_next_available() { | ||
55 | raw_find_next_available "$(find_all_rules 'NAME=' "$1")" | ||
56 | } | ||
57 | |||
58 | write_rule() { | ||
59 | local match="$1" | ||
60 | local name="$2" | ||
61 | local comment="$3" | ||
62 | |||
63 | { | ||
64 | if [ "$PRINT_HEADER" ]; then | ||
65 | PRINT_HEADER= | ||
66 | echo "# This file was automatically generated by the $0" | ||
67 | echo "# program, run by the persistent-net-generator.rules rules file." | ||
68 | echo "#" | ||
69 | echo "# You can modify it, as long as you keep each rule on a single" | ||
70 | echo "# line, and change only the value of the NAME= key." | ||
71 | fi | ||
72 | |||
73 | echo "" | ||
74 | [ "$comment" ] && echo "# $comment" | ||
75 | echo "SUBSYSTEM==\"net\", ACTION==\"add\"$match, NAME=\"$name\"" | ||
76 | } >> $RULES_FILE | ||
77 | } | ||
78 | |||
79 | if [ -z "$INTERFACE" ]; then | ||
80 | echo "missing \$INTERFACE" >&2 | ||
81 | exit 1 | ||
82 | fi | ||
83 | |||
84 | # Prevent concurrent processes from modifying the file at the same time. | ||
85 | lock_rules_file | ||
86 | |||
87 | # Check if the rules file is writeable. | ||
88 | choose_rules_file | ||
89 | |||
90 | # the DRIVERS key is needed to not match bridges and VLAN sub-interfaces | ||
91 | if [ "$MATCHADDR" ]; then | ||
92 | match="$match, DRIVERS==\"?*\", ATTR{address}==\"$MATCHADDR\"" | ||
93 | fi | ||
94 | |||
95 | if [ "$MATCHDRV" ]; then | ||
96 | match="$match, DRIVERS==\"$MATCHDRV\"" | ||
97 | fi | ||
98 | |||
99 | if [ "$MATCHDEVID" ]; then | ||
100 | match="$match, ATTR{dev_id}==\"$MATCHDEVID\"" | ||
101 | fi | ||
102 | |||
103 | if [ "$MATCHID" ]; then | ||
104 | match="$match, KERNELS==\"$MATCHID\"" | ||
105 | fi | ||
106 | |||
107 | if [ "$MATCHIFTYPE" ]; then | ||
108 | match="$match, ATTR{type}==\"$MATCHIFTYPE\"" | ||
109 | fi | ||
110 | |||
111 | if [ -z "$match" ]; then | ||
112 | echo "missing valid match" >&2 | ||
113 | unlock_rules_file | ||
114 | exit 1 | ||
115 | fi | ||
116 | |||
117 | basename=${INTERFACE%%[0-9]*} | ||
118 | match="$match, KERNEL==\"$basename*\"" | ||
119 | |||
120 | if [ "$INTERFACE_NAME" ]; then | ||
121 | # external tools may request a custom name | ||
122 | COMMENT="$COMMENT (custom name provided by external tool)" | ||
123 | if [ "$INTERFACE_NAME" != "$INTERFACE" ]; then | ||
124 | INTERFACE=$INTERFACE_NAME; | ||
125 | echo "INTERFACE_NEW=$INTERFACE" | ||
126 | fi | ||
127 | else | ||
128 | # if a rule using the current name already exists, find a new name | ||
129 | if interface_name_taken; then | ||
130 | INTERFACE="$basename$(find_next_available "$basename[0-9]*")" | ||
131 | # prevent INTERFACE from being "eth" instead of "eth0" | ||
132 | [ "$INTERFACE" = "${INTERFACE%%[ \[\]0-9]*}" ] && INTERFACE=${INTERFACE}0 | ||
133 | echo "INTERFACE_NEW=$INTERFACE" | ||
134 | fi | ||
135 | fi | ||
136 | |||
137 | write_rule "$match" "$INTERFACE" "$COMMENT" | ||
138 | |||
139 | unlock_rules_file | ||
140 | |||
141 | exit 0 | ||
diff --git a/src/udev/src/scsi_id/.gitignore b/src/udev/src/scsi_id/.gitignore new file mode 100644 index 000000000..6aebddd80 --- /dev/null +++ b/src/udev/src/scsi_id/.gitignore | |||
@@ -0,0 +1 @@ | |||
scsi_id_version.h | |||
diff --git a/src/udev/src/scsi_id/README b/src/udev/src/scsi_id/README new file mode 100644 index 000000000..9cfe73991 --- /dev/null +++ b/src/udev/src/scsi_id/README | |||
@@ -0,0 +1,4 @@ | |||
1 | scsi_id - generate a SCSI unique identifier for a given SCSI device | ||
2 | |||
3 | Please send questions, comments or patches to <patmans@us.ibm.com> or | ||
4 | <linux-hotplug-devel@lists.sourceforge.net>. | ||
diff --git a/src/udev/src/scsi_id/scsi.h b/src/udev/src/scsi_id/scsi.h new file mode 100644 index 000000000..c423cac57 --- /dev/null +++ b/src/udev/src/scsi_id/scsi.h | |||
@@ -0,0 +1,97 @@ | |||
1 | /* | ||
2 | * scsi.h | ||
3 | * | ||
4 | * General scsi and linux scsi specific defines and structs. | ||
5 | * | ||
6 | * Copyright (C) IBM Corp. 2003 | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation version 2 of the License. | ||
11 | */ | ||
12 | |||
13 | #include <scsi/scsi.h> | ||
14 | |||
15 | struct scsi_ioctl_command { | ||
16 | unsigned int inlen; /* excluding scsi command length */ | ||
17 | unsigned int outlen; | ||
18 | unsigned char data[1]; | ||
19 | /* on input, scsi command starts here then opt. data */ | ||
20 | }; | ||
21 | |||
22 | /* | ||
23 | * Default 5 second timeout | ||
24 | */ | ||
25 | #define DEF_TIMEOUT 5000 | ||
26 | |||
27 | #define SENSE_BUFF_LEN 32 | ||
28 | |||
29 | /* | ||
30 | * The request buffer size passed to the SCSI INQUIRY commands, use 254, | ||
31 | * as this is a nice value for some devices, especially some of the usb | ||
32 | * mass storage devices. | ||
33 | */ | ||
34 | #define SCSI_INQ_BUFF_LEN 254 | ||
35 | |||
36 | /* | ||
37 | * SCSI INQUIRY vendor and model (really product) lengths. | ||
38 | */ | ||
39 | #define VENDOR_LENGTH 8 | ||
40 | #define MODEL_LENGTH 16 | ||
41 | |||
42 | #define INQUIRY_CMD 0x12 | ||
43 | #define INQUIRY_CMDLEN 6 | ||
44 | |||
45 | /* | ||
46 | * INQUIRY VPD page 0x83 identifier descriptor related values. Reference the | ||
47 | * SCSI Primary Commands specification for details. | ||
48 | */ | ||
49 | |||
50 | /* | ||
51 | * id type values of id descriptors. These are assumed to fit in 4 bits. | ||
52 | */ | ||
53 | #define SCSI_ID_VENDOR_SPECIFIC 0 | ||
54 | #define SCSI_ID_T10_VENDOR 1 | ||
55 | #define SCSI_ID_EUI_64 2 | ||
56 | #define SCSI_ID_NAA 3 | ||
57 | #define SCSI_ID_RELPORT 4 | ||
58 | #define SCSI_ID_TGTGROUP 5 | ||
59 | #define SCSI_ID_LUNGROUP 6 | ||
60 | #define SCSI_ID_MD5 7 | ||
61 | #define SCSI_ID_NAME 8 | ||
62 | |||
63 | /* | ||
64 | * Supported NAA values. These fit in 4 bits, so the "don't care" value | ||
65 | * cannot conflict with real values. | ||
66 | */ | ||
67 | #define SCSI_ID_NAA_DONT_CARE 0xff | ||
68 | #define SCSI_ID_NAA_IEEE_REG 5 | ||
69 | #define SCSI_ID_NAA_IEEE_REG_EXTENDED 6 | ||
70 | |||
71 | /* | ||
72 | * Supported Code Set values. | ||
73 | */ | ||
74 | #define SCSI_ID_BINARY 1 | ||
75 | #define SCSI_ID_ASCII 2 | ||
76 | |||
77 | struct scsi_id_search_values { | ||
78 | u_char id_type; | ||
79 | u_char naa_type; | ||
80 | u_char code_set; | ||
81 | }; | ||
82 | |||
83 | /* | ||
84 | * Following are the "true" SCSI status codes. Linux has traditionally | ||
85 | * used a 1 bit right and masked version of these. So now CHECK_CONDITION | ||
86 | * and friends (in <scsi/scsi.h>) are deprecated. | ||
87 | */ | ||
88 | #define SCSI_CHECK_CONDITION 0x2 | ||
89 | #define SCSI_CONDITION_MET 0x4 | ||
90 | #define SCSI_BUSY 0x8 | ||
91 | #define SCSI_IMMEDIATE 0x10 | ||
92 | #define SCSI_IMMEDIATE_CONDITION_MET 0x14 | ||
93 | #define SCSI_RESERVATION_CONFLICT 0x18 | ||
94 | #define SCSI_COMMAND_TERMINATED 0x22 | ||
95 | #define SCSI_TASK_SET_FULL 0x28 | ||
96 | #define SCSI_ACA_ACTIVE 0x30 | ||
97 | #define SCSI_TASK_ABORTED 0x40 | ||
diff --git a/src/udev/src/scsi_id/scsi_id.8 b/src/udev/src/scsi_id/scsi_id.8 new file mode 100644 index 000000000..0d4dba914 --- /dev/null +++ b/src/udev/src/scsi_id/scsi_id.8 | |||
@@ -0,0 +1,119 @@ | |||
1 | .TH SCSI_ID 8 "December 2003" "" "Linux Administrator's Manual" | ||
2 | .SH NAME | ||
3 | scsi_id \- retrieve and generate a unique SCSI identifier | ||
4 | .SH SYNOPSIS | ||
5 | .BI scsi_id | ||
6 | [\fIoptions\fP] | ||
7 | .SH "DESCRIPTION" | ||
8 | .B scsi_id | ||
9 | queries a SCSI device via the SCSI INQUIRY vital product data (VPD) page 0x80 or | ||
10 | 0x83 and uses the resulting data to generate a value that is unique across | ||
11 | all SCSI devices that properly support page 0x80 or page 0x83. | ||
12 | |||
13 | If a result is generated it is sent to standard output, and the program | ||
14 | exits with a zero value. If no identifier is output, the program exits | ||
15 | with a non\-zero value. | ||
16 | |||
17 | \fBscsi_id\fP is primarily for use by other utilities such as \fBudev\fP | ||
18 | that require a unique SCSI identifier. | ||
19 | |||
20 | By default all devices are assumed black listed, the \fB\-\-whitelisted\fP option must | ||
21 | be specified on the command line or in the config file for any useful | ||
22 | behaviour. | ||
23 | |||
24 | SCSI commands are sent directly to the device via the SG_IO ioctl | ||
25 | interface. | ||
26 | |||
27 | In order to generate unique values for either page 0x80 or page 0x83, the | ||
28 | serial numbers or world wide names are prefixed as follows. | ||
29 | |||
30 | Identifiers based on page 0x80 are prefixed by the character 'S', the SCSI | ||
31 | vendor, the SCSI product (model) and then the the serial number returned | ||
32 | by page 0x80. For example: | ||
33 | |||
34 | .sp | ||
35 | .nf | ||
36 | # /usr/lib/udev/scsi_id \-\-page=0x80 \-\-whitelisted \-\-device=/dev/sda | ||
37 | SIBM 3542 1T05078453 | ||
38 | .fi | ||
39 | .P | ||
40 | |||
41 | Identifiers based on page 0x83 are prefixed by the identifier type | ||
42 | followed by the page 0x83 identifier. For example, a device with a NAA | ||
43 | (Name Address Authority) type of 3 (also in this case the page 0x83 | ||
44 | identifier starts with the NAA value of 6): | ||
45 | |||
46 | .sp | ||
47 | .nf | ||
48 | # /usr/lib/udev/scsi_id \-\-page=0x83 \-\-whitelisted \-\-device=/dev/sda | ||
49 | 3600a0b80000b174b000000d63efc5c8c | ||
50 | .fi | ||
51 | .P | ||
52 | |||
53 | .SH OPTIONS | ||
54 | .TP | ||
55 | .BI \-\-blacklisted | ||
56 | The default behaviour \- treat the device as black listed, and do nothing | ||
57 | unless a white listed device is found in the scsi_id config\-file. | ||
58 | .TP | ||
59 | .BI \-\-device=\| device\^ | ||
60 | Send SG_IO commands to \fBdevice\fP, such as \fB/dev/sdc\fP. | ||
61 | .TP | ||
62 | .BI \-\-config=\| config\-file | ||
63 | Read configuration and black/white list entries from | ||
64 | .B config\-file | ||
65 | rather than the default | ||
66 | .B /etc/scsi_id.config | ||
67 | file. | ||
68 | .TP | ||
69 | .BI \-\-whitelisted | ||
70 | Treat the device as white listed. The \fB\-\-whitelisted\fP option must be specified | ||
71 | on the command line or in the scsi_id configuration file for | ||
72 | .B scsi_id | ||
73 | to generate any output. | ||
74 | .TP | ||
75 | .BI \-\-page=\| 0x80 | 0x83 | pre-spc3-83 | ||
76 | Use SCSI INQUIRY VPD page code 0x80, 0x83, or pre-spc3-83. | ||
77 | .sp | ||
78 | The default | ||
79 | behaviour is to query the available VPD pages, and use page 0x83 if found, | ||
80 | else page 0x80 if found, else nothing. | ||
81 | .sp | ||
82 | Page pre-spc3-83 should only be utilized for those scsi devices which | ||
83 | are not compliant with the SPC-2 or SPC-3 format for page 83. While this | ||
84 | option is used for older model 4, 5, and 6 EMC Symmetrix devices, its | ||
85 | use with SPC-2 or SPC-3 compliant devices will fallback to the page 83 | ||
86 | format supported by these devices. | ||
87 | .TP | ||
88 | .BI \-\-replace-whitespace | ||
89 | Reformat the output : replace all whitespaces by underscores. | ||
90 | .TP | ||
91 | .BI \-\-export | ||
92 | Export all data in KEY=<value> format used to import in other programs. | ||
93 | .TP | ||
94 | .BI \-\-verbose | ||
95 | Generate verbose debugging output. | ||
96 | .TP | ||
97 | .BI \-\-version | ||
98 | Display version number and exit. | ||
99 | .RE | ||
100 | |||
101 | .SH "FILES" | ||
102 | .nf | ||
103 | .ft B | ||
104 | .ft | ||
105 | .TP | ||
106 | \fI/etc/scsi_id.config\fP | ||
107 | Configuration of black/white list entries and per device options: | ||
108 | # one config per line, short match strings match longer strings | ||
109 | # vendor=string[,model=string],options=<per-device scsi_id command line options> | ||
110 | vendor="ATA",options=-p 0x80 | ||
111 | .RE | ||
112 | .fi | ||
113 | .LP | ||
114 | .SH "SEE ALSO" | ||
115 | .BR udev (7) | ||
116 | .SH AUTHORS | ||
117 | Developed by Patrick Mansfield <patmans@us.ibm.com> based on SCSI ID | ||
118 | source included in earlier linux 2.5 kernels, sg_utils source, and SCSI | ||
119 | specifications. | ||
diff --git a/src/udev/src/scsi_id/scsi_id.c b/src/udev/src/scsi_id/scsi_id.c new file mode 100644 index 000000000..9bb0d7f53 --- /dev/null +++ b/src/udev/src/scsi_id/scsi_id.c | |||
@@ -0,0 +1,657 @@ | |||
1 | /* | ||
2 | * Copyright (C) IBM Corp. 2003 | ||
3 | * Copyright (C) SUSE Linux Products GmbH, 2006 | ||
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 <stdio.h> | ||
20 | #include <stdlib.h> | ||
21 | #include <unistd.h> | ||
22 | #include <signal.h> | ||
23 | #include <fcntl.h> | ||
24 | #include <errno.h> | ||
25 | #include <string.h> | ||
26 | #include <syslog.h> | ||
27 | #include <stdarg.h> | ||
28 | #include <ctype.h> | ||
29 | #include <getopt.h> | ||
30 | #include <sys/stat.h> | ||
31 | |||
32 | #include "libudev.h" | ||
33 | #include "libudev-private.h" | ||
34 | #include "scsi_id.h" | ||
35 | |||
36 | static const struct option options[] = { | ||
37 | { "device", required_argument, NULL, 'd' }, | ||
38 | { "config", required_argument, NULL, 'f' }, | ||
39 | { "page", required_argument, NULL, 'p' }, | ||
40 | { "blacklisted", no_argument, NULL, 'b' }, | ||
41 | { "whitelisted", no_argument, NULL, 'g' }, | ||
42 | { "replace-whitespace", no_argument, NULL, 'u' }, | ||
43 | { "sg-version", required_argument, NULL, 's' }, | ||
44 | { "verbose", no_argument, NULL, 'v' }, | ||
45 | { "version", no_argument, NULL, 'V' }, | ||
46 | { "export", no_argument, NULL, 'x' }, | ||
47 | { "help", no_argument, NULL, 'h' }, | ||
48 | {} | ||
49 | }; | ||
50 | |||
51 | static const char short_options[] = "d:f:ghip:uvVx"; | ||
52 | static const char dev_short_options[] = "bgp:"; | ||
53 | |||
54 | static int all_good; | ||
55 | static int dev_specified; | ||
56 | static char config_file[MAX_PATH_LEN] = SYSCONFDIR "/scsi_id.config"; | ||
57 | static enum page_code default_page_code; | ||
58 | static int sg_version = 4; | ||
59 | static int use_stderr; | ||
60 | static int debug; | ||
61 | static int reformat_serial; | ||
62 | static int export; | ||
63 | static char vendor_str[64]; | ||
64 | static char model_str[64]; | ||
65 | static char vendor_enc_str[256]; | ||
66 | static char model_enc_str[256]; | ||
67 | static char revision_str[16]; | ||
68 | static char type_str[16]; | ||
69 | |||
70 | static void log_fn(struct udev *udev, int priority, | ||
71 | const char *file, int line, const char *fn, | ||
72 | const char *format, va_list args) | ||
73 | { | ||
74 | vsyslog(priority, format, args); | ||
75 | } | ||
76 | |||
77 | static void set_type(const char *from, char *to, size_t len) | ||
78 | { | ||
79 | int type_num; | ||
80 | char *eptr; | ||
81 | char *type = "generic"; | ||
82 | |||
83 | type_num = strtoul(from, &eptr, 0); | ||
84 | if (eptr != from) { | ||
85 | switch (type_num) { | ||
86 | case 0: | ||
87 | type = "disk"; | ||
88 | break; | ||
89 | case 1: | ||
90 | type = "tape"; | ||
91 | break; | ||
92 | case 4: | ||
93 | type = "optical"; | ||
94 | break; | ||
95 | case 5: | ||
96 | type = "cd"; | ||
97 | break; | ||
98 | case 7: | ||
99 | type = "optical"; | ||
100 | break; | ||
101 | case 0xe: | ||
102 | type = "disk"; | ||
103 | break; | ||
104 | case 0xf: | ||
105 | type = "optical"; | ||
106 | break; | ||
107 | default: | ||
108 | break; | ||
109 | } | ||
110 | } | ||
111 | util_strscpy(to, len, type); | ||
112 | } | ||
113 | |||
114 | /* | ||
115 | * get_value: | ||
116 | * | ||
117 | * buf points to an '=' followed by a quoted string ("foo") or a string ending | ||
118 | * with a space or ','. | ||
119 | * | ||
120 | * Return a pointer to the NUL terminated string, returns NULL if no | ||
121 | * matches. | ||
122 | */ | ||
123 | static char *get_value(char **buffer) | ||
124 | { | ||
125 | static char *quote_string = "\"\n"; | ||
126 | static char *comma_string = ",\n"; | ||
127 | char *val; | ||
128 | char *end; | ||
129 | |||
130 | if (**buffer == '"') { | ||
131 | /* | ||
132 | * skip leading quote, terminate when quote seen | ||
133 | */ | ||
134 | (*buffer)++; | ||
135 | end = quote_string; | ||
136 | } else { | ||
137 | end = comma_string; | ||
138 | } | ||
139 | val = strsep(buffer, end); | ||
140 | if (val && end == quote_string) | ||
141 | /* | ||
142 | * skip trailing quote | ||
143 | */ | ||
144 | (*buffer)++; | ||
145 | |||
146 | while (isspace(**buffer)) | ||
147 | (*buffer)++; | ||
148 | |||
149 | return val; | ||
150 | } | ||
151 | |||
152 | static int argc_count(char *opts) | ||
153 | { | ||
154 | int i = 0; | ||
155 | while (*opts != '\0') | ||
156 | if (*opts++ == ' ') | ||
157 | i++; | ||
158 | return i; | ||
159 | } | ||
160 | |||
161 | /* | ||
162 | * get_file_options: | ||
163 | * | ||
164 | * If vendor == NULL, find a line in the config file with only "OPTIONS="; | ||
165 | * if vendor and model are set find the first OPTIONS line in the config | ||
166 | * file that matches. Set argc and argv to match the OPTIONS string. | ||
167 | * | ||
168 | * vendor and model can end in '\n'. | ||
169 | */ | ||
170 | static int get_file_options(struct udev *udev, | ||
171 | const char *vendor, const char *model, | ||
172 | int *argc, char ***newargv) | ||
173 | { | ||
174 | char *buffer; | ||
175 | FILE *fd; | ||
176 | char *buf; | ||
177 | char *str1; | ||
178 | char *vendor_in, *model_in, *options_in; /* read in from file */ | ||
179 | int lineno; | ||
180 | int c; | ||
181 | int retval = 0; | ||
182 | |||
183 | dbg(udev, "vendor='%s'; model='%s'\n", vendor, model); | ||
184 | fd = fopen(config_file, "r"); | ||
185 | if (fd == NULL) { | ||
186 | dbg(udev, "can't open %s\n", config_file); | ||
187 | if (errno == ENOENT) { | ||
188 | return 1; | ||
189 | } else { | ||
190 | err(udev, "can't open %s: %s\n", config_file, strerror(errno)); | ||
191 | return -1; | ||
192 | } | ||
193 | } | ||
194 | |||
195 | /* | ||
196 | * Allocate a buffer rather than put it on the stack so we can | ||
197 | * keep it around to parse any options (any allocated newargv | ||
198 | * points into this buffer for its strings). | ||
199 | */ | ||
200 | buffer = malloc(MAX_BUFFER_LEN); | ||
201 | if (!buffer) { | ||
202 | fclose(fd); | ||
203 | err(udev, "can't allocate memory\n"); | ||
204 | return -1; | ||
205 | } | ||
206 | |||
207 | *newargv = NULL; | ||
208 | lineno = 0; | ||
209 | while (1) { | ||
210 | vendor_in = model_in = options_in = NULL; | ||
211 | |||
212 | buf = fgets(buffer, MAX_BUFFER_LEN, fd); | ||
213 | if (buf == NULL) | ||
214 | break; | ||
215 | lineno++; | ||
216 | if (buf[strlen(buffer) - 1] != '\n') { | ||
217 | err(udev, "Config file line %d too long\n", lineno); | ||
218 | break; | ||
219 | } | ||
220 | |||
221 | while (isspace(*buf)) | ||
222 | buf++; | ||
223 | |||
224 | /* blank or all whitespace line */ | ||
225 | if (*buf == '\0') | ||
226 | continue; | ||
227 | |||
228 | /* comment line */ | ||
229 | if (*buf == '#') | ||
230 | continue; | ||
231 | |||
232 | dbg(udev, "lineno %d: '%s'\n", lineno, buf); | ||
233 | str1 = strsep(&buf, "="); | ||
234 | if (str1 && strcasecmp(str1, "VENDOR") == 0) { | ||
235 | str1 = get_value(&buf); | ||
236 | if (!str1) { | ||
237 | retval = -1; | ||
238 | break; | ||
239 | } | ||
240 | vendor_in = str1; | ||
241 | |||
242 | str1 = strsep(&buf, "="); | ||
243 | if (str1 && strcasecmp(str1, "MODEL") == 0) { | ||
244 | str1 = get_value(&buf); | ||
245 | if (!str1) { | ||
246 | retval = -1; | ||
247 | break; | ||
248 | } | ||
249 | model_in = str1; | ||
250 | str1 = strsep(&buf, "="); | ||
251 | } | ||
252 | } | ||
253 | |||
254 | if (str1 && strcasecmp(str1, "OPTIONS") == 0) { | ||
255 | str1 = get_value(&buf); | ||
256 | if (!str1) { | ||
257 | retval = -1; | ||
258 | break; | ||
259 | } | ||
260 | options_in = str1; | ||
261 | } | ||
262 | dbg(udev, "config file line %d:\n" | ||
263 | " vendor '%s'; model '%s'; options '%s'\n", | ||
264 | lineno, vendor_in, model_in, options_in); | ||
265 | /* | ||
266 | * Only allow: [vendor=foo[,model=bar]]options=stuff | ||
267 | */ | ||
268 | if (!options_in || (!vendor_in && model_in)) { | ||
269 | err(udev, "Error parsing config file line %d '%s'\n", lineno, buffer); | ||
270 | retval = -1; | ||
271 | break; | ||
272 | } | ||
273 | if (vendor == NULL) { | ||
274 | if (vendor_in == NULL) { | ||
275 | dbg(udev, "matched global option\n"); | ||
276 | break; | ||
277 | } | ||
278 | } else if ((vendor_in && strncmp(vendor, vendor_in, | ||
279 | strlen(vendor_in)) == 0) && | ||
280 | (!model_in || (strncmp(model, model_in, | ||
281 | strlen(model_in)) == 0))) { | ||
282 | /* | ||
283 | * Matched vendor and optionally model. | ||
284 | * | ||
285 | * Note: a short vendor_in or model_in can | ||
286 | * give a partial match (that is FOO | ||
287 | * matches FOOBAR). | ||
288 | */ | ||
289 | dbg(udev, "matched vendor/model\n"); | ||
290 | break; | ||
291 | } else { | ||
292 | dbg(udev, "no match\n"); | ||
293 | } | ||
294 | } | ||
295 | |||
296 | if (retval == 0) { | ||
297 | if (vendor_in != NULL || model_in != NULL || | ||
298 | options_in != NULL) { | ||
299 | /* | ||
300 | * Something matched. Allocate newargv, and store | ||
301 | * values found in options_in. | ||
302 | */ | ||
303 | strcpy(buffer, options_in); | ||
304 | c = argc_count(buffer) + 2; | ||
305 | *newargv = calloc(c, sizeof(**newargv)); | ||
306 | if (!*newargv) { | ||
307 | err(udev, "can't allocate memory\n"); | ||
308 | retval = -1; | ||
309 | } else { | ||
310 | *argc = c; | ||
311 | c = 0; | ||
312 | /* | ||
313 | * argv[0] at 0 is skipped by getopt, but | ||
314 | * store the buffer address there for | ||
315 | * later freeing | ||
316 | */ | ||
317 | (*newargv)[c] = buffer; | ||
318 | for (c = 1; c < *argc; c++) | ||
319 | (*newargv)[c] = strsep(&buffer, " \t"); | ||
320 | } | ||
321 | } else { | ||
322 | /* No matches */ | ||
323 | retval = 1; | ||
324 | } | ||
325 | } | ||
326 | if (retval != 0) | ||
327 | free(buffer); | ||
328 | fclose(fd); | ||
329 | return retval; | ||
330 | } | ||
331 | |||
332 | static int set_options(struct udev *udev, | ||
333 | int argc, char **argv, const char *short_opts, | ||
334 | char *maj_min_dev) | ||
335 | { | ||
336 | int option; | ||
337 | |||
338 | /* | ||
339 | * optind is a global extern used by getopt. Since we can call | ||
340 | * set_options twice (once for command line, and once for config | ||
341 | * file) we have to reset this back to 1. | ||
342 | */ | ||
343 | optind = 1; | ||
344 | while (1) { | ||
345 | option = getopt_long(argc, argv, short_opts, options, NULL); | ||
346 | if (option == -1) | ||
347 | break; | ||
348 | |||
349 | if (optarg) | ||
350 | dbg(udev, "option '%c' arg '%s'\n", option, optarg); | ||
351 | else | ||
352 | dbg(udev, "option '%c'\n", option); | ||
353 | |||
354 | switch (option) { | ||
355 | case 'b': | ||
356 | all_good = 0; | ||
357 | break; | ||
358 | |||
359 | case 'd': | ||
360 | dev_specified = 1; | ||
361 | util_strscpy(maj_min_dev, MAX_PATH_LEN, optarg); | ||
362 | break; | ||
363 | |||
364 | case 'e': | ||
365 | use_stderr = 1; | ||
366 | break; | ||
367 | |||
368 | case 'f': | ||
369 | util_strscpy(config_file, MAX_PATH_LEN, optarg); | ||
370 | break; | ||
371 | |||
372 | case 'g': | ||
373 | all_good = 1; | ||
374 | break; | ||
375 | |||
376 | case 'h': | ||
377 | printf("Usage: scsi_id OPTIONS <device>\n" | ||
378 | " --device= device node for SG_IO commands\n" | ||
379 | " --config= location of config file\n" | ||
380 | " --page=0x80|0x83|pre-spc3-83 SCSI page (0x80, 0x83, pre-spc3-83)\n" | ||
381 | " --sg-version=3|4 use SGv3 or SGv4\n" | ||
382 | " --blacklisted threat device as blacklisted\n" | ||
383 | " --whitelisted threat device as whitelisted\n" | ||
384 | " --replace-whitespace replace all whitespaces by underscores\n" | ||
385 | " --verbose verbose logging\n" | ||
386 | " --version print version\n" | ||
387 | " --export print values as environment keys\n" | ||
388 | " --help print this help text\n\n"); | ||
389 | exit(0); | ||
390 | |||
391 | case 'p': | ||
392 | if (strcmp(optarg, "0x80") == 0) { | ||
393 | default_page_code = PAGE_80; | ||
394 | } else if (strcmp(optarg, "0x83") == 0) { | ||
395 | default_page_code = PAGE_83; | ||
396 | } else if (strcmp(optarg, "pre-spc3-83") == 0) { | ||
397 | default_page_code = PAGE_83_PRE_SPC3; | ||
398 | } else { | ||
399 | err(udev, "Unknown page code '%s'\n", optarg); | ||
400 | return -1; | ||
401 | } | ||
402 | break; | ||
403 | |||
404 | case 's': | ||
405 | sg_version = atoi(optarg); | ||
406 | if (sg_version < 3 || sg_version > 4) { | ||
407 | err(udev, "Unknown SG version '%s'\n", optarg); | ||
408 | return -1; | ||
409 | } | ||
410 | break; | ||
411 | |||
412 | case 'u': | ||
413 | reformat_serial = 1; | ||
414 | break; | ||
415 | |||
416 | case 'x': | ||
417 | export = 1; | ||
418 | break; | ||
419 | |||
420 | case 'v': | ||
421 | debug++; | ||
422 | break; | ||
423 | |||
424 | case 'V': | ||
425 | printf("%s\n", VERSION); | ||
426 | exit(0); | ||
427 | break; | ||
428 | |||
429 | default: | ||
430 | exit(1); | ||
431 | } | ||
432 | } | ||
433 | if (optind < argc && !dev_specified) { | ||
434 | dev_specified = 1; | ||
435 | util_strscpy(maj_min_dev, MAX_PATH_LEN, argv[optind]); | ||
436 | } | ||
437 | return 0; | ||
438 | } | ||
439 | |||
440 | static int per_dev_options(struct udev *udev, | ||
441 | struct scsi_id_device *dev_scsi, int *good_bad, int *page_code) | ||
442 | { | ||
443 | int retval; | ||
444 | int newargc; | ||
445 | char **newargv = NULL; | ||
446 | int option; | ||
447 | |||
448 | *good_bad = all_good; | ||
449 | *page_code = default_page_code; | ||
450 | |||
451 | retval = get_file_options(udev, vendor_str, model_str, &newargc, &newargv); | ||
452 | |||
453 | optind = 1; /* reset this global extern */ | ||
454 | while (retval == 0) { | ||
455 | option = getopt_long(newargc, newargv, dev_short_options, options, NULL); | ||
456 | if (option == -1) | ||
457 | break; | ||
458 | |||
459 | if (optarg) | ||
460 | dbg(udev, "option '%c' arg '%s'\n", option, optarg); | ||
461 | else | ||
462 | dbg(udev, "option '%c'\n", option); | ||
463 | |||
464 | switch (option) { | ||
465 | case 'b': | ||
466 | *good_bad = 0; | ||
467 | break; | ||
468 | |||
469 | case 'g': | ||
470 | *good_bad = 1; | ||
471 | break; | ||
472 | |||
473 | case 'p': | ||
474 | if (strcmp(optarg, "0x80") == 0) { | ||
475 | *page_code = PAGE_80; | ||
476 | } else if (strcmp(optarg, "0x83") == 0) { | ||
477 | *page_code = PAGE_83; | ||
478 | } else if (strcmp(optarg, "pre-spc3-83") == 0) { | ||
479 | *page_code = PAGE_83_PRE_SPC3; | ||
480 | } else { | ||
481 | err(udev, "Unknown page code '%s'\n", optarg); | ||
482 | retval = -1; | ||
483 | } | ||
484 | break; | ||
485 | |||
486 | default: | ||
487 | err(udev, "Unknown or bad option '%c' (0x%x)\n", option, option); | ||
488 | retval = -1; | ||
489 | break; | ||
490 | } | ||
491 | } | ||
492 | |||
493 | if (newargv) { | ||
494 | free(newargv[0]); | ||
495 | free(newargv); | ||
496 | } | ||
497 | return retval; | ||
498 | } | ||
499 | |||
500 | static int set_inq_values(struct udev *udev, struct scsi_id_device *dev_scsi, const char *path) | ||
501 | { | ||
502 | int retval; | ||
503 | |||
504 | dev_scsi->use_sg = sg_version; | ||
505 | |||
506 | retval = scsi_std_inquiry(udev, dev_scsi, path); | ||
507 | if (retval) | ||
508 | return retval; | ||
509 | |||
510 | udev_util_encode_string(dev_scsi->vendor, vendor_enc_str, sizeof(vendor_enc_str)); | ||
511 | udev_util_encode_string(dev_scsi->model, model_enc_str, sizeof(model_enc_str)); | ||
512 | |||
513 | util_replace_whitespace(dev_scsi->vendor, vendor_str, sizeof(vendor_str)); | ||
514 | util_replace_chars(vendor_str, NULL); | ||
515 | util_replace_whitespace(dev_scsi->model, model_str, sizeof(model_str)); | ||
516 | util_replace_chars(model_str, NULL); | ||
517 | set_type(dev_scsi->type, type_str, sizeof(type_str)); | ||
518 | util_replace_whitespace(dev_scsi->revision, revision_str, sizeof(revision_str)); | ||
519 | util_replace_chars(revision_str, NULL); | ||
520 | return 0; | ||
521 | } | ||
522 | |||
523 | /* | ||
524 | * scsi_id: try to get an id, if one is found, printf it to stdout. | ||
525 | * returns a value passed to exit() - 0 if printed an id, else 1. | ||
526 | */ | ||
527 | static int scsi_id(struct udev *udev, char *maj_min_dev) | ||
528 | { | ||
529 | struct scsi_id_device dev_scsi; | ||
530 | int good_dev; | ||
531 | int page_code; | ||
532 | int retval = 0; | ||
533 | |||
534 | memset(&dev_scsi, 0x00, sizeof(struct scsi_id_device)); | ||
535 | |||
536 | if (set_inq_values(udev, &dev_scsi, maj_min_dev) < 0) { | ||
537 | retval = 1; | ||
538 | goto out; | ||
539 | } | ||
540 | |||
541 | /* get per device (vendor + model) options from the config file */ | ||
542 | per_dev_options(udev, &dev_scsi, &good_dev, &page_code); | ||
543 | dbg(udev, "per dev options: good %d; page code 0x%x\n", good_dev, page_code); | ||
544 | if (!good_dev) { | ||
545 | retval = 1; | ||
546 | goto out; | ||
547 | } | ||
548 | |||
549 | /* read serial number from mode pages (no values for optical drives) */ | ||
550 | scsi_get_serial(udev, &dev_scsi, maj_min_dev, page_code, MAX_SERIAL_LEN); | ||
551 | |||
552 | if (export) { | ||
553 | char serial_str[MAX_SERIAL_LEN]; | ||
554 | |||
555 | printf("ID_SCSI=1\n"); | ||
556 | printf("ID_VENDOR=%s\n", vendor_str); | ||
557 | printf("ID_VENDOR_ENC=%s\n", vendor_enc_str); | ||
558 | printf("ID_MODEL=%s\n", model_str); | ||
559 | printf("ID_MODEL_ENC=%s\n", model_enc_str); | ||
560 | printf("ID_REVISION=%s\n", revision_str); | ||
561 | printf("ID_TYPE=%s\n", type_str); | ||
562 | if (dev_scsi.serial[0] != '\0') { | ||
563 | util_replace_whitespace(dev_scsi.serial, serial_str, sizeof(serial_str)); | ||
564 | util_replace_chars(serial_str, NULL); | ||
565 | printf("ID_SERIAL=%s\n", serial_str); | ||
566 | util_replace_whitespace(dev_scsi.serial_short, serial_str, sizeof(serial_str)); | ||
567 | util_replace_chars(serial_str, NULL); | ||
568 | printf("ID_SERIAL_SHORT=%s\n", serial_str); | ||
569 | } | ||
570 | if (dev_scsi.wwn[0] != '\0') { | ||
571 | printf("ID_WWN=0x%s\n", dev_scsi.wwn); | ||
572 | if (dev_scsi.wwn_vendor_extension[0] != '\0') { | ||
573 | printf("ID_WWN_VENDOR_EXTENSION=0x%s\n", dev_scsi.wwn_vendor_extension); | ||
574 | printf("ID_WWN_WITH_EXTENSION=0x%s%s\n", dev_scsi.wwn, dev_scsi.wwn_vendor_extension); | ||
575 | } else { | ||
576 | printf("ID_WWN_WITH_EXTENSION=0x%s\n", dev_scsi.wwn); | ||
577 | } | ||
578 | } | ||
579 | if (dev_scsi.tgpt_group[0] != '\0') { | ||
580 | printf("ID_TARGET_PORT=%s\n", dev_scsi.tgpt_group); | ||
581 | } | ||
582 | if (dev_scsi.unit_serial_number[0] != '\0') { | ||
583 | printf("ID_SCSI_SERIAL=%s\n", dev_scsi.unit_serial_number); | ||
584 | } | ||
585 | goto out; | ||
586 | } | ||
587 | |||
588 | if (dev_scsi.serial[0] == '\0') { | ||
589 | retval = 1; | ||
590 | goto out; | ||
591 | } | ||
592 | |||
593 | if (reformat_serial) { | ||
594 | char serial_str[MAX_SERIAL_LEN]; | ||
595 | |||
596 | util_replace_whitespace(dev_scsi.serial, serial_str, sizeof(serial_str)); | ||
597 | util_replace_chars(serial_str, NULL); | ||
598 | printf("%s\n", serial_str); | ||
599 | goto out; | ||
600 | } | ||
601 | |||
602 | printf("%s\n", dev_scsi.serial); | ||
603 | out: | ||
604 | return retval; | ||
605 | } | ||
606 | |||
607 | int main(int argc, char **argv) | ||
608 | { | ||
609 | struct udev *udev; | ||
610 | int retval = 0; | ||
611 | char maj_min_dev[MAX_PATH_LEN]; | ||
612 | int newargc; | ||
613 | char **newargv; | ||
614 | |||
615 | udev = udev_new(); | ||
616 | if (udev == NULL) | ||
617 | goto exit; | ||
618 | |||
619 | udev_log_init("scsi_id"); | ||
620 | udev_set_log_fn(udev, log_fn); | ||
621 | |||
622 | /* | ||
623 | * Get config file options. | ||
624 | */ | ||
625 | newargv = NULL; | ||
626 | retval = get_file_options(udev, NULL, NULL, &newargc, &newargv); | ||
627 | if (retval < 0) { | ||
628 | retval = 1; | ||
629 | goto exit; | ||
630 | } | ||
631 | if (newargv && (retval == 0)) { | ||
632 | if (set_options(udev, newargc, newargv, short_options, maj_min_dev) < 0) { | ||
633 | retval = 2; | ||
634 | goto exit; | ||
635 | } | ||
636 | free(newargv); | ||
637 | } | ||
638 | |||
639 | /* | ||
640 | * Get command line options (overriding any config file settings). | ||
641 | */ | ||
642 | if (set_options(udev, argc, argv, short_options, maj_min_dev) < 0) | ||
643 | exit(1); | ||
644 | |||
645 | if (!dev_specified) { | ||
646 | err(udev, "no device specified\n"); | ||
647 | retval = 1; | ||
648 | goto exit; | ||
649 | } | ||
650 | |||
651 | retval = scsi_id(udev, maj_min_dev); | ||
652 | |||
653 | exit: | ||
654 | udev_unref(udev); | ||
655 | udev_log_close(); | ||
656 | return retval; | ||
657 | } | ||
diff --git a/src/udev/src/scsi_id/scsi_id.h b/src/udev/src/scsi_id/scsi_id.h new file mode 100644 index 000000000..828a98305 --- /dev/null +++ b/src/udev/src/scsi_id/scsi_id.h | |||
@@ -0,0 +1,73 @@ | |||
1 | /* | ||
2 | * Copyright (C) IBM Corp. 2003 | ||
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 | #define MAX_PATH_LEN 512 | ||
19 | |||
20 | /* | ||
21 | * MAX_ATTR_LEN: maximum length of the result of reading a sysfs | ||
22 | * attribute. | ||
23 | */ | ||
24 | #define MAX_ATTR_LEN 256 | ||
25 | |||
26 | /* | ||
27 | * MAX_SERIAL_LEN: the maximum length of the serial number, including | ||
28 | * added prefixes such as vendor and product (model) strings. | ||
29 | */ | ||
30 | #define MAX_SERIAL_LEN 256 | ||
31 | |||
32 | /* | ||
33 | * MAX_BUFFER_LEN: maximum buffer size and line length used while reading | ||
34 | * the config file. | ||
35 | */ | ||
36 | #define MAX_BUFFER_LEN 256 | ||
37 | |||
38 | struct scsi_id_device { | ||
39 | char vendor[9]; | ||
40 | char model[17]; | ||
41 | char revision[5]; | ||
42 | char type[33]; | ||
43 | char kernel[64]; | ||
44 | char serial[MAX_SERIAL_LEN]; | ||
45 | char serial_short[MAX_SERIAL_LEN]; | ||
46 | int use_sg; | ||
47 | |||
48 | /* Always from page 0x80 e.g. 'B3G1P8500RWT' - may not be unique */ | ||
49 | char unit_serial_number[MAX_SERIAL_LEN]; | ||
50 | |||
51 | /* NULs if not set - otherwise hex encoding using lower-case e.g. '50014ee0016eb572' */ | ||
52 | char wwn[17]; | ||
53 | |||
54 | /* NULs if not set - otherwise hex encoding using lower-case e.g. '0xe00000d80000' */ | ||
55 | char wwn_vendor_extension[17]; | ||
56 | |||
57 | /* NULs if not set - otherwise decimal number */ | ||
58 | char tgpt_group[8]; | ||
59 | }; | ||
60 | |||
61 | extern int scsi_std_inquiry(struct udev *udev, struct scsi_id_device *dev_scsi, const char *devname); | ||
62 | extern int scsi_get_serial (struct udev *udev, struct scsi_id_device *dev_scsi, const char *devname, | ||
63 | int page_code, int len); | ||
64 | |||
65 | /* | ||
66 | * Page code values. | ||
67 | */ | ||
68 | enum page_code { | ||
69 | PAGE_83_PRE_SPC3 = -0x83, | ||
70 | PAGE_UNSPECIFIED = 0x00, | ||
71 | PAGE_80 = 0x80, | ||
72 | PAGE_83 = 0x83, | ||
73 | }; | ||
diff --git a/src/udev/src/scsi_id/scsi_serial.c b/src/udev/src/scsi_id/scsi_serial.c new file mode 100644 index 000000000..f1d63f40c --- /dev/null +++ b/src/udev/src/scsi_id/scsi_serial.c | |||
@@ -0,0 +1,990 @@ | |||
1 | /* | ||
2 | * Copyright (C) IBM Corp. 2003 | ||
3 | * | ||
4 | * Author: Patrick Mansfield<patmans@us.ibm.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 <sys/ioctl.h> | ||
22 | #include <sys/stat.h> | ||
23 | #include <stdio.h> | ||
24 | #include <errno.h> | ||
25 | #include <string.h> | ||
26 | #include <fcntl.h> | ||
27 | #include <stdlib.h> | ||
28 | #include <unistd.h> | ||
29 | #include <syslog.h> | ||
30 | #include <time.h> | ||
31 | #include <inttypes.h> | ||
32 | #include <scsi/scsi.h> | ||
33 | #include <scsi/sg.h> | ||
34 | #include <linux/types.h> | ||
35 | #include <linux/bsg.h> | ||
36 | |||
37 | #include "libudev.h" | ||
38 | #include "libudev-private.h" | ||
39 | #include "scsi.h" | ||
40 | #include "scsi_id.h" | ||
41 | |||
42 | /* | ||
43 | * A priority based list of id, naa, and binary/ascii for the identifier | ||
44 | * descriptor in VPD page 0x83. | ||
45 | * | ||
46 | * Brute force search for a match starting with the first value in the | ||
47 | * following id_search_list. This is not a performance issue, since there | ||
48 | * is normally one or some small number of descriptors. | ||
49 | */ | ||
50 | static const struct scsi_id_search_values id_search_list[] = { | ||
51 | { SCSI_ID_TGTGROUP, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY }, | ||
52 | { SCSI_ID_NAA, SCSI_ID_NAA_IEEE_REG_EXTENDED, SCSI_ID_BINARY }, | ||
53 | { SCSI_ID_NAA, SCSI_ID_NAA_IEEE_REG_EXTENDED, SCSI_ID_ASCII }, | ||
54 | { SCSI_ID_NAA, SCSI_ID_NAA_IEEE_REG, SCSI_ID_BINARY }, | ||
55 | { SCSI_ID_NAA, SCSI_ID_NAA_IEEE_REG, SCSI_ID_ASCII }, | ||
56 | /* | ||
57 | * Devices already exist using NAA values that are now marked | ||
58 | * reserved. These should not conflict with other values, or it is | ||
59 | * a bug in the device. As long as we find the IEEE extended one | ||
60 | * first, we really don't care what other ones are used. Using | ||
61 | * don't care here means that a device that returns multiple | ||
62 | * non-IEEE descriptors in a random order will get different | ||
63 | * names. | ||
64 | */ | ||
65 | { SCSI_ID_NAA, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY }, | ||
66 | { SCSI_ID_NAA, SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII }, | ||
67 | { SCSI_ID_EUI_64, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY }, | ||
68 | { SCSI_ID_EUI_64, SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII }, | ||
69 | { SCSI_ID_T10_VENDOR, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY }, | ||
70 | { SCSI_ID_T10_VENDOR, SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII }, | ||
71 | { SCSI_ID_VENDOR_SPECIFIC, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY }, | ||
72 | { SCSI_ID_VENDOR_SPECIFIC, SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII }, | ||
73 | }; | ||
74 | |||
75 | static const char hex_str[]="0123456789abcdef"; | ||
76 | |||
77 | /* | ||
78 | * Values returned in the result/status, only the ones used by the code | ||
79 | * are used here. | ||
80 | */ | ||
81 | |||
82 | #define DID_NO_CONNECT 0x01 /* Unable to connect before timeout */ | ||
83 | #define DID_BUS_BUSY 0x02 /* Bus remain busy until timeout */ | ||
84 | #define DID_TIME_OUT 0x03 /* Timed out for some other reason */ | ||
85 | #define DRIVER_TIMEOUT 0x06 | ||
86 | #define DRIVER_SENSE 0x08 /* Sense_buffer has been set */ | ||
87 | |||
88 | /* The following "category" function returns one of the following */ | ||
89 | #define SG_ERR_CAT_CLEAN 0 /* No errors or other information */ | ||
90 | #define SG_ERR_CAT_MEDIA_CHANGED 1 /* interpreted from sense buffer */ | ||
91 | #define SG_ERR_CAT_RESET 2 /* interpreted from sense buffer */ | ||
92 | #define SG_ERR_CAT_TIMEOUT 3 | ||
93 | #define SG_ERR_CAT_RECOVERED 4 /* Successful command after recovered err */ | ||
94 | #define SG_ERR_CAT_NOTSUPPORTED 5 /* Illegal / unsupported command */ | ||
95 | #define SG_ERR_CAT_SENSE 98 /* Something else in the sense buffer */ | ||
96 | #define SG_ERR_CAT_OTHER 99 /* Some other error/warning */ | ||
97 | |||
98 | static int do_scsi_page80_inquiry(struct udev *udev, | ||
99 | struct scsi_id_device *dev_scsi, int fd, | ||
100 | char *serial, char *serial_short, int max_len); | ||
101 | |||
102 | static int sg_err_category_new(struct udev *udev, | ||
103 | int scsi_status, int msg_status, int | ||
104 | host_status, int driver_status, const | ||
105 | unsigned char *sense_buffer, int sb_len) | ||
106 | { | ||
107 | scsi_status &= 0x7e; | ||
108 | |||
109 | /* | ||
110 | * XXX change to return only two values - failed or OK. | ||
111 | */ | ||
112 | |||
113 | if (!scsi_status && !host_status && !driver_status) | ||
114 | return SG_ERR_CAT_CLEAN; | ||
115 | |||
116 | if ((scsi_status == SCSI_CHECK_CONDITION) || | ||
117 | (scsi_status == SCSI_COMMAND_TERMINATED) || | ||
118 | ((driver_status & 0xf) == DRIVER_SENSE)) { | ||
119 | if (sense_buffer && (sb_len > 2)) { | ||
120 | int sense_key; | ||
121 | unsigned char asc; | ||
122 | |||
123 | if (sense_buffer[0] & 0x2) { | ||
124 | sense_key = sense_buffer[1] & 0xf; | ||
125 | asc = sense_buffer[2]; | ||
126 | } else { | ||
127 | sense_key = sense_buffer[2] & 0xf; | ||
128 | asc = (sb_len > 12) ? sense_buffer[12] : 0; | ||
129 | } | ||
130 | |||
131 | if (sense_key == RECOVERED_ERROR) | ||
132 | return SG_ERR_CAT_RECOVERED; | ||
133 | else if (sense_key == UNIT_ATTENTION) { | ||
134 | if (0x28 == asc) | ||
135 | return SG_ERR_CAT_MEDIA_CHANGED; | ||
136 | if (0x29 == asc) | ||
137 | return SG_ERR_CAT_RESET; | ||
138 | } else if (sense_key == ILLEGAL_REQUEST) { | ||
139 | return SG_ERR_CAT_NOTSUPPORTED; | ||
140 | } | ||
141 | } | ||
142 | return SG_ERR_CAT_SENSE; | ||
143 | } | ||
144 | if (host_status) { | ||
145 | if ((host_status == DID_NO_CONNECT) || | ||
146 | (host_status == DID_BUS_BUSY) || | ||
147 | (host_status == DID_TIME_OUT)) | ||
148 | return SG_ERR_CAT_TIMEOUT; | ||
149 | } | ||
150 | if (driver_status) { | ||
151 | if (driver_status == DRIVER_TIMEOUT) | ||
152 | return SG_ERR_CAT_TIMEOUT; | ||
153 | } | ||
154 | return SG_ERR_CAT_OTHER; | ||
155 | } | ||
156 | |||
157 | static int sg_err_category3(struct udev *udev, struct sg_io_hdr *hp) | ||
158 | { | ||
159 | return sg_err_category_new(udev, | ||
160 | hp->status, hp->msg_status, | ||
161 | hp->host_status, hp->driver_status, | ||
162 | hp->sbp, hp->sb_len_wr); | ||
163 | } | ||
164 | |||
165 | static int sg_err_category4(struct udev *udev, struct sg_io_v4 *hp) | ||
166 | { | ||
167 | return sg_err_category_new(udev, hp->device_status, 0, | ||
168 | hp->transport_status, hp->driver_status, | ||
169 | (unsigned char *)(uintptr_t)hp->response, | ||
170 | hp->response_len); | ||
171 | } | ||
172 | |||
173 | static int scsi_dump_sense(struct udev *udev, | ||
174 | struct scsi_id_device *dev_scsi, | ||
175 | unsigned char *sense_buffer, int sb_len) | ||
176 | { | ||
177 | int s; | ||
178 | int code; | ||
179 | int sense_class; | ||
180 | int sense_key; | ||
181 | int asc, ascq; | ||
182 | #ifdef DUMP_SENSE | ||
183 | char out_buffer[256]; | ||
184 | int i, j; | ||
185 | #endif | ||
186 | |||
187 | /* | ||
188 | * Figure out and print the sense key, asc and ascq. | ||
189 | * | ||
190 | * If you want to suppress these for a particular drive model, add | ||
191 | * a black list entry in the scsi_id config file. | ||
192 | * | ||
193 | * XXX We probably need to: lookup the sense/asc/ascq in a retry | ||
194 | * table, and if found return 1 (after dumping the sense, asc, and | ||
195 | * ascq). So, if/when we get something like a power on/reset, | ||
196 | * we'll retry the command. | ||
197 | */ | ||
198 | |||
199 | dbg(udev, "got check condition\n"); | ||
200 | |||
201 | if (sb_len < 1) { | ||
202 | info(udev, "%s: sense buffer empty\n", dev_scsi->kernel); | ||
203 | return -1; | ||
204 | } | ||
205 | |||
206 | sense_class = (sense_buffer[0] >> 4) & 0x07; | ||
207 | code = sense_buffer[0] & 0xf; | ||
208 | |||
209 | if (sense_class == 7) { | ||
210 | /* | ||
211 | * extended sense data. | ||
212 | */ | ||
213 | s = sense_buffer[7] + 8; | ||
214 | if (sb_len < s) { | ||
215 | info(udev, "%s: sense buffer too small %d bytes, %d bytes too short\n", | ||
216 | dev_scsi->kernel, sb_len, s - sb_len); | ||
217 | return -1; | ||
218 | } | ||
219 | if ((code == 0x0) || (code == 0x1)) { | ||
220 | sense_key = sense_buffer[2] & 0xf; | ||
221 | if (s < 14) { | ||
222 | /* | ||
223 | * Possible? | ||
224 | */ | ||
225 | info(udev, "%s: sense result too" " small %d bytes\n", | ||
226 | dev_scsi->kernel, s); | ||
227 | return -1; | ||
228 | } | ||
229 | asc = sense_buffer[12]; | ||
230 | ascq = sense_buffer[13]; | ||
231 | } else if ((code == 0x2) || (code == 0x3)) { | ||
232 | sense_key = sense_buffer[1] & 0xf; | ||
233 | asc = sense_buffer[2]; | ||
234 | ascq = sense_buffer[3]; | ||
235 | } else { | ||
236 | info(udev, "%s: invalid sense code 0x%x\n", | ||
237 | dev_scsi->kernel, code); | ||
238 | return -1; | ||
239 | } | ||
240 | info(udev, "%s: sense key 0x%x ASC 0x%x ASCQ 0x%x\n", | ||
241 | dev_scsi->kernel, sense_key, asc, ascq); | ||
242 | } else { | ||
243 | if (sb_len < 4) { | ||
244 | info(udev, "%s: sense buffer too small %d bytes, %d bytes too short\n", | ||
245 | dev_scsi->kernel, sb_len, 4 - sb_len); | ||
246 | return -1; | ||
247 | } | ||
248 | |||
249 | if (sense_buffer[0] < 15) | ||
250 | info(udev, "%s: old sense key: 0x%x\n", dev_scsi->kernel, sense_buffer[0] & 0x0f); | ||
251 | else | ||
252 | info(udev, "%s: sense = %2x %2x\n", | ||
253 | dev_scsi->kernel, sense_buffer[0], sense_buffer[2]); | ||
254 | info(udev, "%s: non-extended sense class %d code 0x%0x\n", | ||
255 | dev_scsi->kernel, sense_class, code); | ||
256 | |||
257 | } | ||
258 | |||
259 | #ifdef DUMP_SENSE | ||
260 | for (i = 0, j = 0; (i < s) && (j < 254); i++) { | ||
261 | dbg(udev, "i %d, j %d\n", i, j); | ||
262 | out_buffer[j++] = hex_str[(sense_buffer[i] & 0xf0) >> 4]; | ||
263 | out_buffer[j++] = hex_str[sense_buffer[i] & 0x0f]; | ||
264 | out_buffer[j++] = ' '; | ||
265 | } | ||
266 | out_buffer[j] = '\0'; | ||
267 | info(udev, "%s: sense dump:\n", dev_scsi->kernel); | ||
268 | info(udev, "%s: %s\n", dev_scsi->kernel, out_buffer); | ||
269 | |||
270 | #endif | ||
271 | return -1; | ||
272 | } | ||
273 | |||
274 | static int scsi_dump(struct udev *udev, | ||
275 | struct scsi_id_device *dev_scsi, struct sg_io_hdr *io) | ||
276 | { | ||
277 | if (!io->status && !io->host_status && !io->msg_status && | ||
278 | !io->driver_status) { | ||
279 | /* | ||
280 | * Impossible, should not be called. | ||
281 | */ | ||
282 | info(udev, "%s: called with no error\n", __FUNCTION__); | ||
283 | return -1; | ||
284 | } | ||
285 | |||
286 | info(udev, "%s: sg_io failed status 0x%x 0x%x 0x%x 0x%x\n", | ||
287 | dev_scsi->kernel, io->driver_status, io->host_status, io->msg_status, io->status); | ||
288 | if (io->status == SCSI_CHECK_CONDITION) | ||
289 | return scsi_dump_sense(udev, dev_scsi, io->sbp, io->sb_len_wr); | ||
290 | else | ||
291 | return -1; | ||
292 | } | ||
293 | |||
294 | static int scsi_dump_v4(struct udev *udev, | ||
295 | struct scsi_id_device *dev_scsi, struct sg_io_v4 *io) | ||
296 | { | ||
297 | if (!io->device_status && !io->transport_status && | ||
298 | !io->driver_status) { | ||
299 | /* | ||
300 | * Impossible, should not be called. | ||
301 | */ | ||
302 | info(udev, "%s: called with no error\n", __FUNCTION__); | ||
303 | return -1; | ||
304 | } | ||
305 | |||
306 | info(udev, "%s: sg_io failed status 0x%x 0x%x 0x%x\n", | ||
307 | dev_scsi->kernel, io->driver_status, io->transport_status, | ||
308 | io->device_status); | ||
309 | if (io->device_status == SCSI_CHECK_CONDITION) | ||
310 | return scsi_dump_sense(udev, dev_scsi, (unsigned char *)(uintptr_t)io->response, | ||
311 | io->response_len); | ||
312 | else | ||
313 | return -1; | ||
314 | } | ||
315 | |||
316 | static int scsi_inquiry(struct udev *udev, | ||
317 | struct scsi_id_device *dev_scsi, int fd, | ||
318 | unsigned char evpd, unsigned char page, | ||
319 | unsigned char *buf, unsigned int buflen) | ||
320 | { | ||
321 | unsigned char inq_cmd[INQUIRY_CMDLEN] = | ||
322 | { INQUIRY_CMD, evpd, page, 0, buflen, 0 }; | ||
323 | unsigned char sense[SENSE_BUFF_LEN]; | ||
324 | void *io_buf; | ||
325 | struct sg_io_v4 io_v4; | ||
326 | struct sg_io_hdr io_hdr; | ||
327 | int retry = 3; /* rather random */ | ||
328 | int retval; | ||
329 | |||
330 | if (buflen > SCSI_INQ_BUFF_LEN) { | ||
331 | info(udev, "buflen %d too long\n", buflen); | ||
332 | return -1; | ||
333 | } | ||
334 | |||
335 | resend: | ||
336 | dbg(udev, "%s evpd %d, page 0x%x\n", dev_scsi->kernel, evpd, page); | ||
337 | |||
338 | if (dev_scsi->use_sg == 4) { | ||
339 | memset(&io_v4, 0, sizeof(struct sg_io_v4)); | ||
340 | io_v4.guard = 'Q'; | ||
341 | io_v4.protocol = BSG_PROTOCOL_SCSI; | ||
342 | io_v4.subprotocol = BSG_SUB_PROTOCOL_SCSI_CMD; | ||
343 | io_v4.request_len = sizeof(inq_cmd); | ||
344 | io_v4.request = (uintptr_t)inq_cmd; | ||
345 | io_v4.max_response_len = sizeof(sense); | ||
346 | io_v4.response = (uintptr_t)sense; | ||
347 | io_v4.din_xfer_len = buflen; | ||
348 | io_v4.din_xferp = (uintptr_t)buf; | ||
349 | io_buf = (void *)&io_v4; | ||
350 | } else { | ||
351 | memset(&io_hdr, 0, sizeof(struct sg_io_hdr)); | ||
352 | io_hdr.interface_id = 'S'; | ||
353 | io_hdr.cmd_len = sizeof(inq_cmd); | ||
354 | io_hdr.mx_sb_len = sizeof(sense); | ||
355 | io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; | ||
356 | io_hdr.dxfer_len = buflen; | ||
357 | io_hdr.dxferp = buf; | ||
358 | io_hdr.cmdp = inq_cmd; | ||
359 | io_hdr.sbp = sense; | ||
360 | io_hdr.timeout = DEF_TIMEOUT; | ||
361 | io_buf = (void *)&io_hdr; | ||
362 | } | ||
363 | |||
364 | retval = ioctl(fd, SG_IO, io_buf); | ||
365 | if (retval < 0) { | ||
366 | if ((errno == EINVAL || errno == ENOSYS) && dev_scsi->use_sg == 4) { | ||
367 | dev_scsi->use_sg = 3; | ||
368 | goto resend; | ||
369 | } | ||
370 | info(udev, "%s: ioctl failed: %s\n", dev_scsi->kernel, strerror(errno)); | ||
371 | goto error; | ||
372 | } | ||
373 | |||
374 | if (dev_scsi->use_sg == 4) | ||
375 | retval = sg_err_category4(udev, io_buf); | ||
376 | else | ||
377 | retval = sg_err_category3(udev, io_buf); | ||
378 | |||
379 | switch (retval) { | ||
380 | case SG_ERR_CAT_NOTSUPPORTED: | ||
381 | buf[1] = 0; | ||
382 | /* Fallthrough */ | ||
383 | case SG_ERR_CAT_CLEAN: | ||
384 | case SG_ERR_CAT_RECOVERED: | ||
385 | retval = 0; | ||
386 | break; | ||
387 | |||
388 | default: | ||
389 | if (dev_scsi->use_sg == 4) | ||
390 | retval = scsi_dump_v4(udev, dev_scsi, io_buf); | ||
391 | else | ||
392 | retval = scsi_dump(udev, dev_scsi, io_buf); | ||
393 | } | ||
394 | |||
395 | if (!retval) { | ||
396 | retval = buflen; | ||
397 | } else if (retval > 0) { | ||
398 | if (--retry > 0) { | ||
399 | dbg(udev, "%s: Retrying ...\n", dev_scsi->kernel); | ||
400 | goto resend; | ||
401 | } | ||
402 | retval = -1; | ||
403 | } | ||
404 | |||
405 | error: | ||
406 | if (retval < 0) | ||
407 | info(udev, "%s: Unable to get INQUIRY vpd %d page 0x%x.\n", | ||
408 | dev_scsi->kernel, evpd, page); | ||
409 | |||
410 | return retval; | ||
411 | } | ||
412 | |||
413 | /* Get list of supported EVPD pages */ | ||
414 | static int do_scsi_page0_inquiry(struct udev *udev, | ||
415 | struct scsi_id_device *dev_scsi, int fd, | ||
416 | unsigned char *buffer, unsigned int len) | ||
417 | { | ||
418 | int retval; | ||
419 | |||
420 | memset(buffer, 0, len); | ||
421 | retval = scsi_inquiry(udev, dev_scsi, fd, 1, 0x0, buffer, len); | ||
422 | if (retval < 0) | ||
423 | return 1; | ||
424 | |||
425 | if (buffer[1] != 0) { | ||
426 | info(udev, "%s: page 0 not available.\n", dev_scsi->kernel); | ||
427 | return 1; | ||
428 | } | ||
429 | if (buffer[3] > len) { | ||
430 | info(udev, "%s: page 0 buffer too long %d\n", dev_scsi->kernel, buffer[3]); | ||
431 | return 1; | ||
432 | } | ||
433 | |||
434 | /* | ||
435 | * Following check is based on code once included in the 2.5.x | ||
436 | * kernel. | ||
437 | * | ||
438 | * Some ill behaved devices return the standard inquiry here | ||
439 | * rather than the evpd data, snoop the data to verify. | ||
440 | */ | ||
441 | if (buffer[3] > MODEL_LENGTH) { | ||
442 | /* | ||
443 | * If the vendor id appears in the page assume the page is | ||
444 | * invalid. | ||
445 | */ | ||
446 | if (!strncmp((char *)&buffer[VENDOR_LENGTH], dev_scsi->vendor, VENDOR_LENGTH)) { | ||
447 | info(udev, "%s: invalid page0 data\n", dev_scsi->kernel); | ||
448 | return 1; | ||
449 | } | ||
450 | } | ||
451 | return 0; | ||
452 | } | ||
453 | |||
454 | /* | ||
455 | * The caller checks that serial is long enough to include the vendor + | ||
456 | * model. | ||
457 | */ | ||
458 | static int prepend_vendor_model(struct udev *udev, | ||
459 | struct scsi_id_device *dev_scsi, char *serial) | ||
460 | { | ||
461 | int ind; | ||
462 | |||
463 | strncpy(serial, dev_scsi->vendor, VENDOR_LENGTH); | ||
464 | strncat(serial, dev_scsi->model, MODEL_LENGTH); | ||
465 | ind = strlen(serial); | ||
466 | |||
467 | /* | ||
468 | * This is not a complete check, since we are using strncat/cpy | ||
469 | * above, ind will never be too large. | ||
470 | */ | ||
471 | if (ind != (VENDOR_LENGTH + MODEL_LENGTH)) { | ||
472 | info(udev, "%s: expected length %d, got length %d\n", | ||
473 | dev_scsi->kernel, (VENDOR_LENGTH + MODEL_LENGTH), ind); | ||
474 | return -1; | ||
475 | } | ||
476 | return ind; | ||
477 | } | ||
478 | |||
479 | /** | ||
480 | * check_fill_0x83_id - check the page 0x83 id, if OK allocate and fill | ||
481 | * serial number. | ||
482 | **/ | ||
483 | static int check_fill_0x83_id(struct udev *udev, | ||
484 | struct scsi_id_device *dev_scsi, | ||
485 | unsigned char *page_83, | ||
486 | const struct scsi_id_search_values | ||
487 | *id_search, char *serial, char *serial_short, | ||
488 | int max_len, char *wwn, | ||
489 | char *wwn_vendor_extension, char *tgpt_group) | ||
490 | { | ||
491 | int i, j, s, len; | ||
492 | |||
493 | /* | ||
494 | * ASSOCIATION must be with the device (value 0) | ||
495 | * or with the target port for SCSI_ID_TGTPORT | ||
496 | */ | ||
497 | if ((page_83[1] & 0x30) == 0x10) { | ||
498 | if (id_search->id_type != SCSI_ID_TGTGROUP) | ||
499 | return 1; | ||
500 | } else if ((page_83[1] & 0x30) != 0) { | ||
501 | return 1; | ||
502 | } | ||
503 | |||
504 | if ((page_83[1] & 0x0f) != id_search->id_type) | ||
505 | return 1; | ||
506 | |||
507 | /* | ||
508 | * Possibly check NAA sub-type. | ||
509 | */ | ||
510 | if ((id_search->naa_type != SCSI_ID_NAA_DONT_CARE) && | ||
511 | (id_search->naa_type != (page_83[4] & 0xf0) >> 4)) | ||
512 | return 1; | ||
513 | |||
514 | /* | ||
515 | * Check for matching code set - ASCII or BINARY. | ||
516 | */ | ||
517 | if ((page_83[0] & 0x0f) != id_search->code_set) | ||
518 | return 1; | ||
519 | |||
520 | /* | ||
521 | * page_83[3]: identifier length | ||
522 | */ | ||
523 | len = page_83[3]; | ||
524 | if ((page_83[0] & 0x0f) != SCSI_ID_ASCII) | ||
525 | /* | ||
526 | * If not ASCII, use two bytes for each binary value. | ||
527 | */ | ||
528 | len *= 2; | ||
529 | |||
530 | /* | ||
531 | * Add one byte for the NUL termination, and one for the id_type. | ||
532 | */ | ||
533 | len += 2; | ||
534 | if (id_search->id_type == SCSI_ID_VENDOR_SPECIFIC) | ||
535 | len += VENDOR_LENGTH + MODEL_LENGTH; | ||
536 | |||
537 | if (max_len < len) { | ||
538 | info(udev, "%s: length %d too short - need %d\n", | ||
539 | dev_scsi->kernel, max_len, len); | ||
540 | return 1; | ||
541 | } | ||
542 | |||
543 | if (id_search->id_type == SCSI_ID_TGTGROUP && tgpt_group != NULL) { | ||
544 | unsigned int group; | ||
545 | |||
546 | group = ((unsigned int)page_83[6] << 8) | page_83[7]; | ||
547 | sprintf(tgpt_group,"%x", group); | ||
548 | return 1; | ||
549 | } | ||
550 | |||
551 | serial[0] = hex_str[id_search->id_type]; | ||
552 | |||
553 | /* | ||
554 | * For SCSI_ID_VENDOR_SPECIFIC prepend the vendor and model before | ||
555 | * the id since it is not unique across all vendors and models, | ||
556 | * this differs from SCSI_ID_T10_VENDOR, where the vendor is | ||
557 | * included in the identifier. | ||
558 | */ | ||
559 | if (id_search->id_type == SCSI_ID_VENDOR_SPECIFIC) | ||
560 | if (prepend_vendor_model(udev, dev_scsi, &serial[1]) < 0) { | ||
561 | dbg(udev, "prepend failed\n"); | ||
562 | return 1; | ||
563 | } | ||
564 | |||
565 | i = 4; /* offset to the start of the identifier */ | ||
566 | s = j = strlen(serial); | ||
567 | if ((page_83[0] & 0x0f) == SCSI_ID_ASCII) { | ||
568 | /* | ||
569 | * ASCII descriptor. | ||
570 | */ | ||
571 | while (i < (4 + page_83[3])) | ||
572 | serial[j++] = page_83[i++]; | ||
573 | } else { | ||
574 | /* | ||
575 | * Binary descriptor, convert to ASCII, using two bytes of | ||
576 | * ASCII for each byte in the page_83. | ||
577 | */ | ||
578 | while (i < (4 + page_83[3])) { | ||
579 | serial[j++] = hex_str[(page_83[i] & 0xf0) >> 4]; | ||
580 | serial[j++] = hex_str[page_83[i] & 0x0f]; | ||
581 | i++; | ||
582 | } | ||
583 | } | ||
584 | |||
585 | strcpy(serial_short, &serial[s]); | ||
586 | |||
587 | if (id_search->id_type == SCSI_ID_NAA && wwn != NULL) { | ||
588 | strncpy(wwn, &serial[s], 16); | ||
589 | if (wwn_vendor_extension != NULL) { | ||
590 | strncpy(wwn_vendor_extension, &serial[s + 16], 16); | ||
591 | } | ||
592 | } | ||
593 | |||
594 | return 0; | ||
595 | } | ||
596 | |||
597 | /* Extract the raw binary from VPD 0x83 pre-SPC devices */ | ||
598 | static int check_fill_0x83_prespc3(struct udev *udev, | ||
599 | struct scsi_id_device *dev_scsi, | ||
600 | unsigned char *page_83, | ||
601 | const struct scsi_id_search_values | ||
602 | *id_search, char *serial, char *serial_short, int max_len) | ||
603 | { | ||
604 | int i, j; | ||
605 | |||
606 | dbg(udev, "using pre-spc3-83 for %s\n", dev_scsi->kernel); | ||
607 | serial[0] = hex_str[id_search->id_type]; | ||
608 | /* serial has been memset to zero before */ | ||
609 | j = strlen(serial); /* j = 1; */ | ||
610 | |||
611 | for (i = 0; (i < page_83[3]) && (j < max_len-3); ++i) { | ||
612 | serial[j++] = hex_str[(page_83[4+i] & 0xf0) >> 4]; | ||
613 | serial[j++] = hex_str[ page_83[4+i] & 0x0f]; | ||
614 | } | ||
615 | serial[max_len-1] = 0; | ||
616 | strncpy(serial_short, serial, max_len-1); | ||
617 | return 0; | ||
618 | } | ||
619 | |||
620 | |||
621 | /* Get device identification VPD page */ | ||
622 | static int do_scsi_page83_inquiry(struct udev *udev, | ||
623 | struct scsi_id_device *dev_scsi, int fd, | ||
624 | char *serial, char *serial_short, int len, | ||
625 | char *unit_serial_number, char *wwn, | ||
626 | char *wwn_vendor_extension, char *tgpt_group) | ||
627 | { | ||
628 | int retval; | ||
629 | unsigned int id_ind, j; | ||
630 | unsigned char page_83[SCSI_INQ_BUFF_LEN]; | ||
631 | |||
632 | /* also pick up the page 80 serial number */ | ||
633 | do_scsi_page80_inquiry(udev, dev_scsi, fd, NULL, unit_serial_number, MAX_SERIAL_LEN); | ||
634 | |||
635 | memset(page_83, 0, SCSI_INQ_BUFF_LEN); | ||
636 | retval = scsi_inquiry(udev, dev_scsi, fd, 1, PAGE_83, page_83, | ||
637 | SCSI_INQ_BUFF_LEN); | ||
638 | if (retval < 0) | ||
639 | return 1; | ||
640 | |||
641 | if (page_83[1] != PAGE_83) { | ||
642 | info(udev, "%s: Invalid page 0x83\n", dev_scsi->kernel); | ||
643 | return 1; | ||
644 | } | ||
645 | |||
646 | /* | ||
647 | * XXX Some devices (IBM 3542) return all spaces for an identifier if | ||
648 | * the LUN is not actually configured. This leads to identifiers of | ||
649 | * the form: "1 ". | ||
650 | */ | ||
651 | |||
652 | /* | ||
653 | * Model 4, 5, and (some) model 6 EMC Symmetrix devices return | ||
654 | * a page 83 reply according to SCSI-2 format instead of SPC-2/3. | ||
655 | * | ||
656 | * The SCSI-2 page 83 format returns an IEEE WWN in binary | ||
657 | * encoded hexi-decimal in the 16 bytes following the initial | ||
658 | * 4-byte page 83 reply header. | ||
659 | * | ||
660 | * Both the SPC-2 and SPC-3 formats return an IEEE WWN as part | ||
661 | * of an Identification descriptor. The 3rd byte of the first | ||
662 | * Identification descriptor is a reserved (BSZ) byte field. | ||
663 | * | ||
664 | * Reference the 7th byte of the page 83 reply to determine | ||
665 | * whether the reply is compliant with SCSI-2 or SPC-2/3 | ||
666 | * specifications. A zero value in the 7th byte indicates | ||
667 | * an SPC-2/3 conformant reply, (i.e., the reserved field of the | ||
668 | * first Identification descriptor). This byte will be non-zero | ||
669 | * for a SCSI-2 conformant page 83 reply from these EMC | ||
670 | * Symmetrix models since the 7th byte of the reply corresponds | ||
671 | * to the 4th and 5th nibbles of the 6-byte OUI for EMC, that is, | ||
672 | * 0x006048. | ||
673 | */ | ||
674 | |||
675 | if (page_83[6] != 0) | ||
676 | return check_fill_0x83_prespc3(udev, | ||
677 | dev_scsi, page_83, id_search_list, | ||
678 | serial, serial_short, len); | ||
679 | |||
680 | /* | ||
681 | * Search for a match in the prioritized id_search_list - since WWN ids | ||
682 | * come first we can pick up the WWN in check_fill_0x83_id(). | ||
683 | */ | ||
684 | for (id_ind = 0; | ||
685 | id_ind < sizeof(id_search_list)/sizeof(id_search_list[0]); | ||
686 | id_ind++) { | ||
687 | /* | ||
688 | * Examine each descriptor returned. There is normally only | ||
689 | * one or a small number of descriptors. | ||
690 | */ | ||
691 | for (j = 4; j <= (unsigned int)page_83[3] + 3; j += page_83[j + 3] + 4) { | ||
692 | retval = check_fill_0x83_id(udev, | ||
693 | dev_scsi, &page_83[j], | ||
694 | &id_search_list[id_ind], | ||
695 | serial, serial_short, len, | ||
696 | wwn, wwn_vendor_extension, | ||
697 | tgpt_group); | ||
698 | dbg(udev, "%s id desc %d/%d/%d\n", dev_scsi->kernel, | ||
699 | id_search_list[id_ind].id_type, | ||
700 | id_search_list[id_ind].naa_type, | ||
701 | id_search_list[id_ind].code_set); | ||
702 | if (!retval) { | ||
703 | dbg(udev, " used\n"); | ||
704 | return retval; | ||
705 | } else if (retval < 0) { | ||
706 | dbg(udev, " failed\n"); | ||
707 | return retval; | ||
708 | } else { | ||
709 | dbg(udev, " not used\n"); | ||
710 | } | ||
711 | } | ||
712 | } | ||
713 | return 1; | ||
714 | } | ||
715 | |||
716 | /* | ||
717 | * Get device identification VPD page for older SCSI-2 device which is not | ||
718 | * compliant with either SPC-2 or SPC-3 format. | ||
719 | * | ||
720 | * Return the hard coded error code value 2 if the page 83 reply is not | ||
721 | * conformant to the SCSI-2 format. | ||
722 | */ | ||
723 | static int do_scsi_page83_prespc3_inquiry(struct udev *udev, | ||
724 | struct scsi_id_device *dev_scsi, int fd, | ||
725 | char *serial, char *serial_short, int len) | ||
726 | { | ||
727 | int retval; | ||
728 | int i, j; | ||
729 | unsigned char page_83[SCSI_INQ_BUFF_LEN]; | ||
730 | |||
731 | memset(page_83, 0, SCSI_INQ_BUFF_LEN); | ||
732 | retval = scsi_inquiry(udev, dev_scsi, fd, 1, PAGE_83, page_83, SCSI_INQ_BUFF_LEN); | ||
733 | if (retval < 0) | ||
734 | return 1; | ||
735 | |||
736 | if (page_83[1] != PAGE_83) { | ||
737 | info(udev, "%s: Invalid page 0x83\n", dev_scsi->kernel); | ||
738 | return 1; | ||
739 | } | ||
740 | /* | ||
741 | * Model 4, 5, and (some) model 6 EMC Symmetrix devices return | ||
742 | * a page 83 reply according to SCSI-2 format instead of SPC-2/3. | ||
743 | * | ||
744 | * The SCSI-2 page 83 format returns an IEEE WWN in binary | ||
745 | * encoded hexi-decimal in the 16 bytes following the initial | ||
746 | * 4-byte page 83 reply header. | ||
747 | * | ||
748 | * Both the SPC-2 and SPC-3 formats return an IEEE WWN as part | ||
749 | * of an Identification descriptor. The 3rd byte of the first | ||
750 | * Identification descriptor is a reserved (BSZ) byte field. | ||
751 | * | ||
752 | * Reference the 7th byte of the page 83 reply to determine | ||
753 | * whether the reply is compliant with SCSI-2 or SPC-2/3 | ||
754 | * specifications. A zero value in the 7th byte indicates | ||
755 | * an SPC-2/3 conformant reply, (i.e., the reserved field of the | ||
756 | * first Identification descriptor). This byte will be non-zero | ||
757 | * for a SCSI-2 conformant page 83 reply from these EMC | ||
758 | * Symmetrix models since the 7th byte of the reply corresponds | ||
759 | * to the 4th and 5th nibbles of the 6-byte OUI for EMC, that is, | ||
760 | * 0x006048. | ||
761 | */ | ||
762 | if (page_83[6] == 0) | ||
763 | return 2; | ||
764 | |||
765 | serial[0] = hex_str[id_search_list[0].id_type]; | ||
766 | /* | ||
767 | * The first four bytes contain data, not a descriptor. | ||
768 | */ | ||
769 | i = 4; | ||
770 | j = strlen(serial); | ||
771 | /* | ||
772 | * Binary descriptor, convert to ASCII, | ||
773 | * using two bytes of ASCII for each byte | ||
774 | * in the page_83. | ||
775 | */ | ||
776 | while (i < (page_83[3]+4)) { | ||
777 | serial[j++] = hex_str[(page_83[i] & 0xf0) >> 4]; | ||
778 | serial[j++] = hex_str[page_83[i] & 0x0f]; | ||
779 | i++; | ||
780 | } | ||
781 | dbg(udev, "using pre-spc3-83 for %s\n", dev_scsi->kernel); | ||
782 | return 0; | ||
783 | } | ||
784 | |||
785 | /* Get unit serial number VPD page */ | ||
786 | static int do_scsi_page80_inquiry(struct udev *udev, | ||
787 | struct scsi_id_device *dev_scsi, int fd, | ||
788 | char *serial, char *serial_short, int max_len) | ||
789 | { | ||
790 | int retval; | ||
791 | int ser_ind; | ||
792 | int i; | ||
793 | int len; | ||
794 | unsigned char buf[SCSI_INQ_BUFF_LEN]; | ||
795 | |||
796 | memset(buf, 0, SCSI_INQ_BUFF_LEN); | ||
797 | retval = scsi_inquiry(udev, dev_scsi, fd, 1, PAGE_80, buf, SCSI_INQ_BUFF_LEN); | ||
798 | if (retval < 0) | ||
799 | return retval; | ||
800 | |||
801 | if (buf[1] != PAGE_80) { | ||
802 | info(udev, "%s: Invalid page 0x80\n", dev_scsi->kernel); | ||
803 | return 1; | ||
804 | } | ||
805 | |||
806 | len = 1 + VENDOR_LENGTH + MODEL_LENGTH + buf[3]; | ||
807 | if (max_len < len) { | ||
808 | info(udev, "%s: length %d too short - need %d\n", | ||
809 | dev_scsi->kernel, max_len, len); | ||
810 | return 1; | ||
811 | } | ||
812 | /* | ||
813 | * Prepend 'S' to avoid unlikely collision with page 0x83 vendor | ||
814 | * specific type where we prepend '0' + vendor + model. | ||
815 | */ | ||
816 | len = buf[3]; | ||
817 | if (serial != NULL) { | ||
818 | serial[0] = 'S'; | ||
819 | ser_ind = prepend_vendor_model(udev, dev_scsi, &serial[1]); | ||
820 | if (ser_ind < 0) | ||
821 | return 1; | ||
822 | for (i = 4; i < len + 4; i++, ser_ind++) | ||
823 | serial[ser_ind] = buf[i]; | ||
824 | } | ||
825 | if (serial_short != NULL) { | ||
826 | memcpy(serial_short, &buf[4], len); | ||
827 | serial_short[len] = '\0'; | ||
828 | } | ||
829 | return 0; | ||
830 | } | ||
831 | |||
832 | int scsi_std_inquiry(struct udev *udev, | ||
833 | struct scsi_id_device *dev_scsi, const char *devname) | ||
834 | { | ||
835 | int fd; | ||
836 | unsigned char buf[SCSI_INQ_BUFF_LEN]; | ||
837 | struct stat statbuf; | ||
838 | int err = 0; | ||
839 | |||
840 | dbg(udev, "opening %s\n", devname); | ||
841 | fd = open(devname, O_RDONLY | O_NONBLOCK); | ||
842 | if (fd < 0) { | ||
843 | info(udev, "scsi_id: cannot open %s: %s\n", | ||
844 | devname, strerror(errno)); | ||
845 | return 1; | ||
846 | } | ||
847 | |||
848 | if (fstat(fd, &statbuf) < 0) { | ||
849 | info(udev, "scsi_id: cannot stat %s: %s\n", | ||
850 | devname, strerror(errno)); | ||
851 | err = 2; | ||
852 | goto out; | ||
853 | } | ||
854 | sprintf(dev_scsi->kernel,"%d:%d", major(statbuf.st_rdev), | ||
855 | minor(statbuf.st_rdev)); | ||
856 | |||
857 | memset(buf, 0, SCSI_INQ_BUFF_LEN); | ||
858 | err = scsi_inquiry(udev, dev_scsi, fd, 0, 0, buf, SCSI_INQ_BUFF_LEN); | ||
859 | if (err < 0) | ||
860 | goto out; | ||
861 | |||
862 | err = 0; | ||
863 | memcpy(dev_scsi->vendor, buf + 8, 8); | ||
864 | dev_scsi->vendor[8] = '\0'; | ||
865 | memcpy(dev_scsi->model, buf + 16, 16); | ||
866 | dev_scsi->model[16] = '\0'; | ||
867 | memcpy(dev_scsi->revision, buf + 32, 4); | ||
868 | dev_scsi->revision[4] = '\0'; | ||
869 | sprintf(dev_scsi->type,"%x", buf[0] & 0x1f); | ||
870 | |||
871 | out: | ||
872 | close(fd); | ||
873 | return err; | ||
874 | } | ||
875 | |||
876 | int scsi_get_serial(struct udev *udev, | ||
877 | struct scsi_id_device *dev_scsi, const char *devname, | ||
878 | int page_code, int len) | ||
879 | { | ||
880 | unsigned char page0[SCSI_INQ_BUFF_LEN]; | ||
881 | int fd = -1; | ||
882 | int cnt; | ||
883 | int ind; | ||
884 | int retval; | ||
885 | |||
886 | memset(dev_scsi->serial, 0, len); | ||
887 | dbg(udev, "opening %s\n", devname); | ||
888 | srand((unsigned int)getpid()); | ||
889 | for (cnt = 20; cnt > 0; cnt--) { | ||
890 | struct timespec duration; | ||
891 | |||
892 | fd = open(devname, O_RDONLY | O_NONBLOCK); | ||
893 | if (fd >= 0 || errno != EBUSY) | ||
894 | break; | ||
895 | duration.tv_sec = 0; | ||
896 | duration.tv_nsec = (200 * 1000 * 1000) + (rand() % 100 * 1000 * 1000); | ||
897 | nanosleep(&duration, NULL); | ||
898 | } | ||
899 | if (fd < 0) | ||
900 | return 1; | ||
901 | |||
902 | if (page_code == PAGE_80) { | ||
903 | if (do_scsi_page80_inquiry(udev, dev_scsi, fd, dev_scsi->serial, dev_scsi->serial_short, len)) { | ||
904 | retval = 1; | ||
905 | goto completed; | ||
906 | } else { | ||
907 | retval = 0; | ||
908 | goto completed; | ||
909 | } | ||
910 | } else if (page_code == PAGE_83) { | ||
911 | if (do_scsi_page83_inquiry(udev, dev_scsi, fd, dev_scsi->serial, dev_scsi->serial_short, len, dev_scsi->unit_serial_number, dev_scsi->wwn, dev_scsi->wwn_vendor_extension, dev_scsi->tgpt_group)) { | ||
912 | retval = 1; | ||
913 | goto completed; | ||
914 | } else { | ||
915 | retval = 0; | ||
916 | goto completed; | ||
917 | } | ||
918 | } else if (page_code == PAGE_83_PRE_SPC3) { | ||
919 | retval = do_scsi_page83_prespc3_inquiry(udev, dev_scsi, fd, dev_scsi->serial, dev_scsi->serial_short, len); | ||
920 | if (retval) { | ||
921 | /* | ||
922 | * Fallback to servicing a SPC-2/3 compliant page 83 | ||
923 | * inquiry if the page 83 reply format does not | ||
924 | * conform to pre-SPC3 expectations. | ||
925 | */ | ||
926 | if (retval == 2) { | ||
927 | if (do_scsi_page83_inquiry(udev, dev_scsi, fd, dev_scsi->serial, dev_scsi->serial_short, len, dev_scsi->unit_serial_number, dev_scsi->wwn, dev_scsi->wwn_vendor_extension, dev_scsi->tgpt_group)) { | ||
928 | retval = 1; | ||
929 | goto completed; | ||
930 | } else { | ||
931 | retval = 0; | ||
932 | goto completed; | ||
933 | } | ||
934 | } | ||
935 | else { | ||
936 | retval = 1; | ||
937 | goto completed; | ||
938 | } | ||
939 | } else { | ||
940 | retval = 0; | ||
941 | goto completed; | ||
942 | } | ||
943 | } else if (page_code != 0x00) { | ||
944 | info(udev, "%s: unsupported page code 0x%d\n", dev_scsi->kernel, page_code); | ||
945 | return 1; | ||
946 | } | ||
947 | |||
948 | /* | ||
949 | * Get page 0, the page of the pages. By default, try from best to | ||
950 | * worst of supported pages: 0x83 then 0x80. | ||
951 | */ | ||
952 | if (do_scsi_page0_inquiry(udev, dev_scsi, fd, page0, SCSI_INQ_BUFF_LEN)) { | ||
953 | /* | ||
954 | * Don't try anything else. Black list if a specific page | ||
955 | * should be used for this vendor+model, or maybe have an | ||
956 | * optional fall-back to page 0x80 or page 0x83. | ||
957 | */ | ||
958 | retval = 1; | ||
959 | goto completed; | ||
960 | } | ||
961 | |||
962 | dbg(udev, "%s: Checking page0\n", dev_scsi->kernel); | ||
963 | |||
964 | for (ind = 4; ind <= page0[3] + 3; ind++) | ||
965 | if (page0[ind] == PAGE_83) | ||
966 | if (!do_scsi_page83_inquiry(udev, dev_scsi, fd, | ||
967 | dev_scsi->serial, dev_scsi->serial_short, len, dev_scsi->unit_serial_number, dev_scsi->wwn, dev_scsi->wwn_vendor_extension, dev_scsi->tgpt_group)) { | ||
968 | /* | ||
969 | * Success | ||
970 | */ | ||
971 | retval = 0; | ||
972 | goto completed; | ||
973 | } | ||
974 | |||
975 | for (ind = 4; ind <= page0[3] + 3; ind++) | ||
976 | if (page0[ind] == PAGE_80) | ||
977 | if (!do_scsi_page80_inquiry(udev, dev_scsi, fd, | ||
978 | dev_scsi->serial, dev_scsi->serial_short, len)) { | ||
979 | /* | ||
980 | * Success | ||
981 | */ | ||
982 | retval = 0; | ||
983 | goto completed; | ||
984 | } | ||
985 | retval = 1; | ||
986 | |||
987 | completed: | ||
988 | close(fd); | ||
989 | return retval; | ||
990 | } | ||
diff --git a/src/udev/src/sd-daemon.c b/src/udev/src/sd-daemon.c new file mode 100644 index 000000000..763e079b4 --- /dev/null +++ b/src/udev/src/sd-daemon.c | |||
@@ -0,0 +1,530 @@ | |||
1 | /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ | ||
2 | |||
3 | /*** | ||
4 | Copyright 2010 Lennart Poettering | ||
5 | |||
6 | Permission is hereby granted, free of charge, to any person | ||
7 | obtaining a copy of this software and associated documentation files | ||
8 | (the "Software"), to deal in the Software without restriction, | ||
9 | including without limitation the rights to use, copy, modify, merge, | ||
10 | publish, distribute, sublicense, and/or sell copies of the Software, | ||
11 | and to permit persons to whom the Software is furnished to do so, | ||
12 | subject to the following conditions: | ||
13 | |||
14 | The above copyright notice and this permission notice shall be | ||
15 | included in all copies or substantial portions of the Software. | ||
16 | |||
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
20 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
21 | BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
22 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
23 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
24 | SOFTWARE. | ||
25 | ***/ | ||
26 | |||
27 | #ifndef _GNU_SOURCE | ||
28 | #define _GNU_SOURCE | ||
29 | #endif | ||
30 | |||
31 | #include <sys/types.h> | ||
32 | #include <sys/stat.h> | ||
33 | #include <sys/socket.h> | ||
34 | #include <sys/un.h> | ||
35 | #ifdef __BIONIC__ | ||
36 | #include <linux/fcntl.h> | ||
37 | #else | ||
38 | #include <sys/fcntl.h> | ||
39 | #endif | ||
40 | #include <netinet/in.h> | ||
41 | #include <stdlib.h> | ||
42 | #include <errno.h> | ||
43 | #include <unistd.h> | ||
44 | #include <string.h> | ||
45 | #include <stdarg.h> | ||
46 | #include <stdio.h> | ||
47 | #include <stddef.h> | ||
48 | #include <limits.h> | ||
49 | |||
50 | #if defined(__linux__) | ||
51 | #include <mqueue.h> | ||
52 | #endif | ||
53 | |||
54 | #include "sd-daemon.h" | ||
55 | |||
56 | #if (__GNUC__ >= 4) | ||
57 | #ifdef SD_EXPORT_SYMBOLS | ||
58 | /* Export symbols */ | ||
59 | #define _sd_export_ __attribute__ ((visibility("default"))) | ||
60 | #else | ||
61 | /* Don't export the symbols */ | ||
62 | #define _sd_export_ __attribute__ ((visibility("hidden"))) | ||
63 | #endif | ||
64 | #else | ||
65 | #define _sd_export_ | ||
66 | #endif | ||
67 | |||
68 | _sd_export_ int sd_listen_fds(int unset_environment) { | ||
69 | |||
70 | #if defined(DISABLE_SYSTEMD) || !defined(__linux__) | ||
71 | return 0; | ||
72 | #else | ||
73 | int r, fd; | ||
74 | const char *e; | ||
75 | char *p = NULL; | ||
76 | unsigned long l; | ||
77 | |||
78 | if (!(e = getenv("LISTEN_PID"))) { | ||
79 | r = 0; | ||
80 | goto finish; | ||
81 | } | ||
82 | |||
83 | errno = 0; | ||
84 | l = strtoul(e, &p, 10); | ||
85 | |||
86 | if (errno != 0) { | ||
87 | r = -errno; | ||
88 | goto finish; | ||
89 | } | ||
90 | |||
91 | if (!p || *p || l <= 0) { | ||
92 | r = -EINVAL; | ||
93 | goto finish; | ||
94 | } | ||
95 | |||
96 | /* Is this for us? */ | ||
97 | if (getpid() != (pid_t) l) { | ||
98 | r = 0; | ||
99 | goto finish; | ||
100 | } | ||
101 | |||
102 | if (!(e = getenv("LISTEN_FDS"))) { | ||
103 | r = 0; | ||
104 | goto finish; | ||
105 | } | ||
106 | |||
107 | errno = 0; | ||
108 | l = strtoul(e, &p, 10); | ||
109 | |||
110 | if (errno != 0) { | ||
111 | r = -errno; | ||
112 | goto finish; | ||
113 | } | ||
114 | |||
115 | if (!p || *p) { | ||
116 | r = -EINVAL; | ||
117 | goto finish; | ||
118 | } | ||
119 | |||
120 | for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + (int) l; fd ++) { | ||
121 | int flags; | ||
122 | |||
123 | if ((flags = fcntl(fd, F_GETFD)) < 0) { | ||
124 | r = -errno; | ||
125 | goto finish; | ||
126 | } | ||
127 | |||
128 | if (flags & FD_CLOEXEC) | ||
129 | continue; | ||
130 | |||
131 | if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) { | ||
132 | r = -errno; | ||
133 | goto finish; | ||
134 | } | ||
135 | } | ||
136 | |||
137 | r = (int) l; | ||
138 | |||
139 | finish: | ||
140 | if (unset_environment) { | ||
141 | unsetenv("LISTEN_PID"); | ||
142 | unsetenv("LISTEN_FDS"); | ||
143 | } | ||
144 | |||
145 | return r; | ||
146 | #endif | ||
147 | } | ||
148 | |||
149 | _sd_export_ int sd_is_fifo(int fd, const char *path) { | ||
150 | struct stat st_fd; | ||
151 | |||
152 | if (fd < 0) | ||
153 | return -EINVAL; | ||
154 | |||
155 | memset(&st_fd, 0, sizeof(st_fd)); | ||
156 | if (fstat(fd, &st_fd) < 0) | ||
157 | return -errno; | ||
158 | |||
159 | if (!S_ISFIFO(st_fd.st_mode)) | ||
160 | return 0; | ||
161 | |||
162 | if (path) { | ||
163 | struct stat st_path; | ||
164 | |||
165 | memset(&st_path, 0, sizeof(st_path)); | ||
166 | if (stat(path, &st_path) < 0) { | ||
167 | |||
168 | if (errno == ENOENT || errno == ENOTDIR) | ||
169 | return 0; | ||
170 | |||
171 | return -errno; | ||
172 | } | ||
173 | |||
174 | return | ||
175 | st_path.st_dev == st_fd.st_dev && | ||
176 | st_path.st_ino == st_fd.st_ino; | ||
177 | } | ||
178 | |||
179 | return 1; | ||
180 | } | ||
181 | |||
182 | _sd_export_ int sd_is_special(int fd, const char *path) { | ||
183 | struct stat st_fd; | ||
184 | |||
185 | if (fd < 0) | ||
186 | return -EINVAL; | ||
187 | |||
188 | if (fstat(fd, &st_fd) < 0) | ||
189 | return -errno; | ||
190 | |||
191 | if (!S_ISREG(st_fd.st_mode) && !S_ISCHR(st_fd.st_mode)) | ||
192 | return 0; | ||
193 | |||
194 | if (path) { | ||
195 | struct stat st_path; | ||
196 | |||
197 | if (stat(path, &st_path) < 0) { | ||
198 | |||
199 | if (errno == ENOENT || errno == ENOTDIR) | ||
200 | return 0; | ||
201 | |||
202 | return -errno; | ||
203 | } | ||
204 | |||
205 | if (S_ISREG(st_fd.st_mode) && S_ISREG(st_path.st_mode)) | ||
206 | return | ||
207 | st_path.st_dev == st_fd.st_dev && | ||
208 | st_path.st_ino == st_fd.st_ino; | ||
209 | else if (S_ISCHR(st_fd.st_mode) && S_ISCHR(st_path.st_mode)) | ||
210 | return st_path.st_rdev == st_fd.st_rdev; | ||
211 | else | ||
212 | return 0; | ||
213 | } | ||
214 | |||
215 | return 1; | ||
216 | } | ||
217 | |||
218 | static int sd_is_socket_internal(int fd, int type, int listening) { | ||
219 | struct stat st_fd; | ||
220 | |||
221 | if (fd < 0 || type < 0) | ||
222 | return -EINVAL; | ||
223 | |||
224 | if (fstat(fd, &st_fd) < 0) | ||
225 | return -errno; | ||
226 | |||
227 | if (!S_ISSOCK(st_fd.st_mode)) | ||
228 | return 0; | ||
229 | |||
230 | if (type != 0) { | ||
231 | int other_type = 0; | ||
232 | socklen_t l = sizeof(other_type); | ||
233 | |||
234 | if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &other_type, &l) < 0) | ||
235 | return -errno; | ||
236 | |||
237 | if (l != sizeof(other_type)) | ||
238 | return -EINVAL; | ||
239 | |||
240 | if (other_type != type) | ||
241 | return 0; | ||
242 | } | ||
243 | |||
244 | if (listening >= 0) { | ||
245 | int accepting = 0; | ||
246 | socklen_t l = sizeof(accepting); | ||
247 | |||
248 | if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &accepting, &l) < 0) | ||
249 | return -errno; | ||
250 | |||
251 | if (l != sizeof(accepting)) | ||
252 | return -EINVAL; | ||
253 | |||
254 | if (!accepting != !listening) | ||
255 | return 0; | ||
256 | } | ||
257 | |||
258 | return 1; | ||
259 | } | ||
260 | |||
261 | union sockaddr_union { | ||
262 | struct sockaddr sa; | ||
263 | struct sockaddr_in in4; | ||
264 | struct sockaddr_in6 in6; | ||
265 | struct sockaddr_un un; | ||
266 | struct sockaddr_storage storage; | ||
267 | }; | ||
268 | |||
269 | _sd_export_ int sd_is_socket(int fd, int family, int type, int listening) { | ||
270 | int r; | ||
271 | |||
272 | if (family < 0) | ||
273 | return -EINVAL; | ||
274 | |||
275 | if ((r = sd_is_socket_internal(fd, type, listening)) <= 0) | ||
276 | return r; | ||
277 | |||
278 | if (family > 0) { | ||
279 | union sockaddr_union sockaddr; | ||
280 | socklen_t l; | ||
281 | |||
282 | memset(&sockaddr, 0, sizeof(sockaddr)); | ||
283 | l = sizeof(sockaddr); | ||
284 | |||
285 | if (getsockname(fd, &sockaddr.sa, &l) < 0) | ||
286 | return -errno; | ||
287 | |||
288 | if (l < sizeof(sa_family_t)) | ||
289 | return -EINVAL; | ||
290 | |||
291 | return sockaddr.sa.sa_family == family; | ||
292 | } | ||
293 | |||
294 | return 1; | ||
295 | } | ||
296 | |||
297 | _sd_export_ int sd_is_socket_inet(int fd, int family, int type, int listening, uint16_t port) { | ||
298 | union sockaddr_union sockaddr; | ||
299 | socklen_t l; | ||
300 | int r; | ||
301 | |||
302 | if (family != 0 && family != AF_INET && family != AF_INET6) | ||
303 | return -EINVAL; | ||
304 | |||
305 | if ((r = sd_is_socket_internal(fd, type, listening)) <= 0) | ||
306 | return r; | ||
307 | |||
308 | memset(&sockaddr, 0, sizeof(sockaddr)); | ||
309 | l = sizeof(sockaddr); | ||
310 | |||
311 | if (getsockname(fd, &sockaddr.sa, &l) < 0) | ||
312 | return -errno; | ||
313 | |||
314 | if (l < sizeof(sa_family_t)) | ||
315 | return -EINVAL; | ||
316 | |||
317 | if (sockaddr.sa.sa_family != AF_INET && | ||
318 | sockaddr.sa.sa_family != AF_INET6) | ||
319 | return 0; | ||
320 | |||
321 | if (family > 0) | ||
322 | if (sockaddr.sa.sa_family != family) | ||
323 | return 0; | ||
324 | |||
325 | if (port > 0) { | ||
326 | if (sockaddr.sa.sa_family == AF_INET) { | ||
327 | if (l < sizeof(struct sockaddr_in)) | ||
328 | return -EINVAL; | ||
329 | |||
330 | return htons(port) == sockaddr.in4.sin_port; | ||
331 | } else { | ||
332 | if (l < sizeof(struct sockaddr_in6)) | ||
333 | return -EINVAL; | ||
334 | |||
335 | return htons(port) == sockaddr.in6.sin6_port; | ||
336 | } | ||
337 | } | ||
338 | |||
339 | return 1; | ||
340 | } | ||
341 | |||
342 | _sd_export_ int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length) { | ||
343 | union sockaddr_union sockaddr; | ||
344 | socklen_t l; | ||
345 | int r; | ||
346 | |||
347 | if ((r = sd_is_socket_internal(fd, type, listening)) <= 0) | ||
348 | return r; | ||
349 | |||
350 | memset(&sockaddr, 0, sizeof(sockaddr)); | ||
351 | l = sizeof(sockaddr); | ||
352 | |||
353 | if (getsockname(fd, &sockaddr.sa, &l) < 0) | ||
354 | return -errno; | ||
355 | |||
356 | if (l < sizeof(sa_family_t)) | ||
357 | return -EINVAL; | ||
358 | |||
359 | if (sockaddr.sa.sa_family != AF_UNIX) | ||
360 | return 0; | ||
361 | |||
362 | if (path) { | ||
363 | if (length <= 0) | ||
364 | length = strlen(path); | ||
365 | |||
366 | if (length <= 0) | ||
367 | /* Unnamed socket */ | ||
368 | return l == offsetof(struct sockaddr_un, sun_path); | ||
369 | |||
370 | if (path[0]) | ||
371 | /* Normal path socket */ | ||
372 | return | ||
373 | (l >= offsetof(struct sockaddr_un, sun_path) + length + 1) && | ||
374 | memcmp(path, sockaddr.un.sun_path, length+1) == 0; | ||
375 | else | ||
376 | /* Abstract namespace socket */ | ||
377 | return | ||
378 | (l == offsetof(struct sockaddr_un, sun_path) + length) && | ||
379 | memcmp(path, sockaddr.un.sun_path, length) == 0; | ||
380 | } | ||
381 | |||
382 | return 1; | ||
383 | } | ||
384 | |||
385 | _sd_export_ int sd_is_mq(int fd, const char *path) { | ||
386 | #if !defined(__linux__) | ||
387 | return 0; | ||
388 | #else | ||
389 | struct mq_attr attr; | ||
390 | |||
391 | if (fd < 0) | ||
392 | return -EINVAL; | ||
393 | |||
394 | if (mq_getattr(fd, &attr) < 0) | ||
395 | return -errno; | ||
396 | |||
397 | if (path) { | ||
398 | char fpath[PATH_MAX]; | ||
399 | struct stat a, b; | ||
400 | |||
401 | if (path[0] != '/') | ||
402 | return -EINVAL; | ||
403 | |||
404 | if (fstat(fd, &a) < 0) | ||
405 | return -errno; | ||
406 | |||
407 | strncpy(stpcpy(fpath, "/dev/mqueue"), path, sizeof(fpath) - 12); | ||
408 | fpath[sizeof(fpath)-1] = 0; | ||
409 | |||
410 | if (stat(fpath, &b) < 0) | ||
411 | return -errno; | ||
412 | |||
413 | if (a.st_dev != b.st_dev || | ||
414 | a.st_ino != b.st_ino) | ||
415 | return 0; | ||
416 | } | ||
417 | |||
418 | return 1; | ||
419 | #endif | ||
420 | } | ||
421 | |||
422 | _sd_export_ int sd_notify(int unset_environment, const char *state) { | ||
423 | #if defined(DISABLE_SYSTEMD) || !defined(__linux__) || !defined(SOCK_CLOEXEC) | ||
424 | return 0; | ||
425 | #else | ||
426 | int fd = -1, r; | ||
427 | struct msghdr msghdr; | ||
428 | struct iovec iovec; | ||
429 | union sockaddr_union sockaddr; | ||
430 | const char *e; | ||
431 | |||
432 | if (!state) { | ||
433 | r = -EINVAL; | ||
434 | goto finish; | ||
435 | } | ||
436 | |||
437 | if (!(e = getenv("NOTIFY_SOCKET"))) | ||
438 | return 0; | ||
439 | |||
440 | /* Must be an abstract socket, or an absolute path */ | ||
441 | if ((e[0] != '@' && e[0] != '/') || e[1] == 0) { | ||
442 | r = -EINVAL; | ||
443 | goto finish; | ||
444 | } | ||
445 | |||
446 | if ((fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0)) < 0) { | ||
447 | r = -errno; | ||
448 | goto finish; | ||
449 | } | ||
450 | |||
451 | memset(&sockaddr, 0, sizeof(sockaddr)); | ||
452 | sockaddr.sa.sa_family = AF_UNIX; | ||
453 | strncpy(sockaddr.un.sun_path, e, sizeof(sockaddr.un.sun_path)); | ||
454 | |||
455 | if (sockaddr.un.sun_path[0] == '@') | ||
456 | sockaddr.un.sun_path[0] = 0; | ||
457 | |||
458 | memset(&iovec, 0, sizeof(iovec)); | ||
459 | iovec.iov_base = (char*) state; | ||
460 | iovec.iov_len = strlen(state); | ||
461 | |||
462 | memset(&msghdr, 0, sizeof(msghdr)); | ||
463 | msghdr.msg_name = &sockaddr; | ||
464 | msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(e); | ||
465 | |||
466 | if (msghdr.msg_namelen > sizeof(struct sockaddr_un)) | ||
467 | msghdr.msg_namelen = sizeof(struct sockaddr_un); | ||
468 | |||
469 | msghdr.msg_iov = &iovec; | ||
470 | msghdr.msg_iovlen = 1; | ||
471 | |||
472 | if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0) { | ||
473 | r = -errno; | ||
474 | goto finish; | ||
475 | } | ||
476 | |||
477 | r = 1; | ||
478 | |||
479 | finish: | ||
480 | if (unset_environment) | ||
481 | unsetenv("NOTIFY_SOCKET"); | ||
482 | |||
483 | if (fd >= 0) | ||
484 | close(fd); | ||
485 | |||
486 | return r; | ||
487 | #endif | ||
488 | } | ||
489 | |||
490 | _sd_export_ int sd_notifyf(int unset_environment, const char *format, ...) { | ||
491 | #if defined(DISABLE_SYSTEMD) || !defined(__linux__) | ||
492 | return 0; | ||
493 | #else | ||
494 | va_list ap; | ||
495 | char *p = NULL; | ||
496 | int r; | ||
497 | |||
498 | va_start(ap, format); | ||
499 | r = vasprintf(&p, format, ap); | ||
500 | va_end(ap); | ||
501 | |||
502 | if (r < 0 || !p) | ||
503 | return -ENOMEM; | ||
504 | |||
505 | r = sd_notify(unset_environment, p); | ||
506 | free(p); | ||
507 | |||
508 | return r; | ||
509 | #endif | ||
510 | } | ||
511 | |||
512 | _sd_export_ int sd_booted(void) { | ||
513 | #if defined(DISABLE_SYSTEMD) || !defined(__linux__) | ||
514 | return 0; | ||
515 | #else | ||
516 | |||
517 | struct stat a, b; | ||
518 | |||
519 | /* We simply test whether the systemd cgroup hierarchy is | ||
520 | * mounted */ | ||
521 | |||
522 | if (lstat("/sys/fs/cgroup", &a) < 0) | ||
523 | return 0; | ||
524 | |||
525 | if (lstat("/sys/fs/cgroup/systemd", &b) < 0) | ||
526 | return 0; | ||
527 | |||
528 | return a.st_dev != b.st_dev; | ||
529 | #endif | ||
530 | } | ||
diff --git a/src/udev/src/sd-daemon.h b/src/udev/src/sd-daemon.h new file mode 100644 index 000000000..fe51159ee --- /dev/null +++ b/src/udev/src/sd-daemon.h | |||
@@ -0,0 +1,282 @@ | |||
1 | /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ | ||
2 | |||
3 | #ifndef foosddaemonhfoo | ||
4 | #define foosddaemonhfoo | ||
5 | |||
6 | /*** | ||
7 | Copyright 2010 Lennart Poettering | ||
8 | |||
9 | Permission is hereby granted, free of charge, to any person | ||
10 | obtaining a copy of this software and associated documentation files | ||
11 | (the "Software"), to deal in the Software without restriction, | ||
12 | including without limitation the rights to use, copy, modify, merge, | ||
13 | publish, distribute, sublicense, and/or sell copies of the Software, | ||
14 | and to permit persons to whom the Software is furnished to do so, | ||
15 | subject to the following conditions: | ||
16 | |||
17 | The above copyright notice and this permission notice shall be | ||
18 | included in all copies or substantial portions of the Software. | ||
19 | |||
20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
21 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
22 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
23 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
24 | BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
25 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
26 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
27 | SOFTWARE. | ||
28 | ***/ | ||
29 | |||
30 | #include <sys/types.h> | ||
31 | #include <inttypes.h> | ||
32 | |||
33 | #ifdef __cplusplus | ||
34 | extern "C" { | ||
35 | #endif | ||
36 | |||
37 | /* | ||
38 | Reference implementation of a few systemd related interfaces for | ||
39 | writing daemons. These interfaces are trivial to implement. To | ||
40 | simplify porting we provide this reference implementation. | ||
41 | Applications are welcome to reimplement the algorithms described | ||
42 | here if they do not want to include these two source files. | ||
43 | |||
44 | The following functionality is provided: | ||
45 | |||
46 | - Support for logging with log levels on stderr | ||
47 | - File descriptor passing for socket-based activation | ||
48 | - Daemon startup and status notification | ||
49 | - Detection of systemd boots | ||
50 | |||
51 | You may compile this with -DDISABLE_SYSTEMD to disable systemd | ||
52 | support. This makes all those calls NOPs that are directly related to | ||
53 | systemd (i.e. only sd_is_xxx() will stay useful). | ||
54 | |||
55 | Since this is drop-in code we don't want any of our symbols to be | ||
56 | exported in any case. Hence we declare hidden visibility for all of | ||
57 | them. | ||
58 | |||
59 | You may find an up-to-date version of these source files online: | ||
60 | |||
61 | http://cgit.freedesktop.org/systemd/systemd/plain/src/systemd/sd-daemon.h | ||
62 | http://cgit.freedesktop.org/systemd/systemd/plain/src/sd-daemon.c | ||
63 | |||
64 | This should compile on non-Linux systems, too, but with the | ||
65 | exception of the sd_is_xxx() calls all functions will become NOPs. | ||
66 | |||
67 | See sd-daemon(7) for more information. | ||
68 | */ | ||
69 | |||
70 | #ifndef _sd_printf_attr_ | ||
71 | #if __GNUC__ >= 4 | ||
72 | #define _sd_printf_attr_(a,b) __attribute__ ((format (printf, a, b))) | ||
73 | #else | ||
74 | #define _sd_printf_attr_(a,b) | ||
75 | #endif | ||
76 | #endif | ||
77 | |||
78 | /* | ||
79 | Log levels for usage on stderr: | ||
80 | |||
81 | fprintf(stderr, SD_NOTICE "Hello World!\n"); | ||
82 | |||
83 | This is similar to printk() usage in the kernel. | ||
84 | */ | ||
85 | #define SD_EMERG "<0>" /* system is unusable */ | ||
86 | #define SD_ALERT "<1>" /* action must be taken immediately */ | ||
87 | #define SD_CRIT "<2>" /* critical conditions */ | ||
88 | #define SD_ERR "<3>" /* error conditions */ | ||
89 | #define SD_WARNING "<4>" /* warning conditions */ | ||
90 | #define SD_NOTICE "<5>" /* normal but significant condition */ | ||
91 | #define SD_INFO "<6>" /* informational */ | ||
92 | #define SD_DEBUG "<7>" /* debug-level messages */ | ||
93 | |||
94 | /* The first passed file descriptor is fd 3 */ | ||
95 | #define SD_LISTEN_FDS_START 3 | ||
96 | |||
97 | /* | ||
98 | Returns how many file descriptors have been passed, or a negative | ||
99 | errno code on failure. Optionally, removes the $LISTEN_FDS and | ||
100 | $LISTEN_PID file descriptors from the environment (recommended, but | ||
101 | problematic in threaded environments). If r is the return value of | ||
102 | this function you'll find the file descriptors passed as fds | ||
103 | SD_LISTEN_FDS_START to SD_LISTEN_FDS_START+r-1. Returns a negative | ||
104 | errno style error code on failure. This function call ensures that | ||
105 | the FD_CLOEXEC flag is set for the passed file descriptors, to make | ||
106 | sure they are not passed on to child processes. If FD_CLOEXEC shall | ||
107 | not be set, the caller needs to unset it after this call for all file | ||
108 | descriptors that are used. | ||
109 | |||
110 | See sd_listen_fds(3) for more information. | ||
111 | */ | ||
112 | int sd_listen_fds(int unset_environment); | ||
113 | |||
114 | /* | ||
115 | Helper call for identifying a passed file descriptor. Returns 1 if | ||
116 | the file descriptor is a FIFO in the file system stored under the | ||
117 | specified path, 0 otherwise. If path is NULL a path name check will | ||
118 | not be done and the call only verifies if the file descriptor | ||
119 | refers to a FIFO. Returns a negative errno style error code on | ||
120 | failure. | ||
121 | |||
122 | See sd_is_fifo(3) for more information. | ||
123 | */ | ||
124 | int sd_is_fifo(int fd, const char *path); | ||
125 | |||
126 | /* | ||
127 | Helper call for identifying a passed file descriptor. Returns 1 if | ||
128 | the file descriptor is a special character device on the file | ||
129 | system stored under the specified path, 0 otherwise. | ||
130 | If path is NULL a path name check will not be done and the call | ||
131 | only verifies if the file descriptor refers to a special character. | ||
132 | Returns a negative errno style error code on failure. | ||
133 | |||
134 | See sd_is_special(3) for more information. | ||
135 | */ | ||
136 | int sd_is_special(int fd, const char *path); | ||
137 | |||
138 | /* | ||
139 | Helper call for identifying a passed file descriptor. Returns 1 if | ||
140 | the file descriptor is a socket of the specified family (AF_INET, | ||
141 | ...) and type (SOCK_DGRAM, SOCK_STREAM, ...), 0 otherwise. If | ||
142 | family is 0 a socket family check will not be done. If type is 0 a | ||
143 | socket type check will not be done and the call only verifies if | ||
144 | the file descriptor refers to a socket. If listening is > 0 it is | ||
145 | verified that the socket is in listening mode. (i.e. listen() has | ||
146 | been called) If listening is == 0 it is verified that the socket is | ||
147 | not in listening mode. If listening is < 0 no listening mode check | ||
148 | is done. Returns a negative errno style error code on failure. | ||
149 | |||
150 | See sd_is_socket(3) for more information. | ||
151 | */ | ||
152 | int sd_is_socket(int fd, int family, int type, int listening); | ||
153 | |||
154 | /* | ||
155 | Helper call for identifying a passed file descriptor. Returns 1 if | ||
156 | the file descriptor is an Internet socket, of the specified family | ||
157 | (either AF_INET or AF_INET6) and the specified type (SOCK_DGRAM, | ||
158 | SOCK_STREAM, ...), 0 otherwise. If version is 0 a protocol version | ||
159 | check is not done. If type is 0 a socket type check will not be | ||
160 | done. If port is 0 a socket port check will not be done. The | ||
161 | listening flag is used the same way as in sd_is_socket(). Returns a | ||
162 | negative errno style error code on failure. | ||
163 | |||
164 | See sd_is_socket_inet(3) for more information. | ||
165 | */ | ||
166 | int sd_is_socket_inet(int fd, int family, int type, int listening, uint16_t port); | ||
167 | |||
168 | /* | ||
169 | Helper call for identifying a passed file descriptor. Returns 1 if | ||
170 | the file descriptor is an AF_UNIX socket of the specified type | ||
171 | (SOCK_DGRAM, SOCK_STREAM, ...) and path, 0 otherwise. If type is 0 | ||
172 | a socket type check will not be done. If path is NULL a socket path | ||
173 | check will not be done. For normal AF_UNIX sockets set length to | ||
174 | 0. For abstract namespace sockets set length to the length of the | ||
175 | socket name (including the initial 0 byte), and pass the full | ||
176 | socket path in path (including the initial 0 byte). The listening | ||
177 | flag is used the same way as in sd_is_socket(). Returns a negative | ||
178 | errno style error code on failure. | ||
179 | |||
180 | See sd_is_socket_unix(3) for more information. | ||
181 | */ | ||
182 | int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t length); | ||
183 | |||
184 | /* | ||
185 | Helper call for identifying a passed file descriptor. Returns 1 if | ||
186 | the file descriptor is a POSIX Message Queue of the specified name, | ||
187 | 0 otherwise. If path is NULL a message queue name check is not | ||
188 | done. Returns a negative errno style error code on failure. | ||
189 | */ | ||
190 | int sd_is_mq(int fd, const char *path); | ||
191 | |||
192 | /* | ||
193 | Informs systemd about changed daemon state. This takes a number of | ||
194 | newline separated environment-style variable assignments in a | ||
195 | string. The following variables are known: | ||
196 | |||
197 | READY=1 Tells systemd that daemon startup is finished (only | ||
198 | relevant for services of Type=notify). The passed | ||
199 | argument is a boolean "1" or "0". Since there is | ||
200 | little value in signaling non-readiness the only | ||
201 | value daemons should send is "READY=1". | ||
202 | |||
203 | STATUS=... Passes a single-line status string back to systemd | ||
204 | that describes the daemon state. This is free-from | ||
205 | and can be used for various purposes: general state | ||
206 | feedback, fsck-like programs could pass completion | ||
207 | percentages and failing programs could pass a human | ||
208 | readable error message. Example: "STATUS=Completed | ||
209 | 66% of file system check..." | ||
210 | |||
211 | ERRNO=... If a daemon fails, the errno-style error code, | ||
212 | formatted as string. Example: "ERRNO=2" for ENOENT. | ||
213 | |||
214 | BUSERROR=... If a daemon fails, the D-Bus error-style error | ||
215 | code. Example: "BUSERROR=org.freedesktop.DBus.Error.TimedOut" | ||
216 | |||
217 | MAINPID=... The main pid of a daemon, in case systemd did not | ||
218 | fork off the process itself. Example: "MAINPID=4711" | ||
219 | |||
220 | WATCHDOG=1 Tells systemd to update the watchdog timestamp. | ||
221 | Services using this feature should do this in | ||
222 | regular intervals. A watchdog framework can use the | ||
223 | timestamps to detect failed services. | ||
224 | |||
225 | Daemons can choose to send additional variables. However, it is | ||
226 | recommended to prefix variable names not listed above with X_. | ||
227 | |||
228 | Returns a negative errno-style error code on failure. Returns > 0 | ||
229 | if systemd could be notified, 0 if it couldn't possibly because | ||
230 | systemd is not running. | ||
231 | |||
232 | Example: When a daemon finished starting up, it could issue this | ||
233 | call to notify systemd about it: | ||
234 | |||
235 | sd_notify(0, "READY=1"); | ||
236 | |||
237 | See sd_notifyf() for more complete examples. | ||
238 | |||
239 | See sd_notify(3) for more information. | ||
240 | */ | ||
241 | int sd_notify(int unset_environment, const char *state); | ||
242 | |||
243 | /* | ||
244 | Similar to sd_notify() but takes a format string. | ||
245 | |||
246 | Example 1: A daemon could send the following after initialization: | ||
247 | |||
248 | sd_notifyf(0, "READY=1\n" | ||
249 | "STATUS=Processing requests...\n" | ||
250 | "MAINPID=%lu", | ||
251 | (unsigned long) getpid()); | ||
252 | |||
253 | Example 2: A daemon could send the following shortly before | ||
254 | exiting, on failure: | ||
255 | |||
256 | sd_notifyf(0, "STATUS=Failed to start up: %s\n" | ||
257 | "ERRNO=%i", | ||
258 | strerror(errno), | ||
259 | errno); | ||
260 | |||
261 | See sd_notifyf(3) for more information. | ||
262 | */ | ||
263 | int sd_notifyf(int unset_environment, const char *format, ...) _sd_printf_attr_(2,3); | ||
264 | |||
265 | /* | ||
266 | Returns > 0 if the system was booted with systemd. Returns < 0 on | ||
267 | error. Returns 0 if the system was not booted with systemd. Note | ||
268 | that all of the functions above handle non-systemd boots just | ||
269 | fine. You should NOT protect them with a call to this function. Also | ||
270 | note that this function checks whether the system, not the user | ||
271 | session is controlled by systemd. However the functions above work | ||
272 | for both user and system services. | ||
273 | |||
274 | See sd_booted(3) for more information. | ||
275 | */ | ||
276 | int sd_booted(void); | ||
277 | |||
278 | #ifdef __cplusplus | ||
279 | } | ||
280 | #endif | ||
281 | |||
282 | #endif | ||
diff --git a/src/udev/src/test-libudev.c b/src/udev/src/test-libudev.c new file mode 100644 index 000000000..6161fb3e3 --- /dev/null +++ b/src/udev/src/test-libudev.c | |||
@@ -0,0 +1,501 @@ | |||
1 | /* | ||
2 | * test-libudev | ||
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 <stdarg.h> | ||
14 | #include <stdlib.h> | ||
15 | #include <unistd.h> | ||
16 | #include <errno.h> | ||
17 | #include <string.h> | ||
18 | #include <getopt.h> | ||
19 | #include <syslog.h> | ||
20 | #include <fcntl.h> | ||
21 | #include <sys/epoll.h> | ||
22 | |||
23 | #include "libudev.h" | ||
24 | |||
25 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) | ||
26 | |||
27 | static void log_fn(struct udev *udev, | ||
28 | int priority, const char *file, int line, const char *fn, | ||
29 | const char *format, va_list args) | ||
30 | { | ||
31 | printf("test-libudev: %s %s:%d ", fn, file, line); | ||
32 | vprintf(format, args); | ||
33 | } | ||
34 | |||
35 | static void print_device(struct udev_device *device) | ||
36 | { | ||
37 | const char *str; | ||
38 | dev_t devnum; | ||
39 | int count; | ||
40 | struct udev_list_entry *list_entry; | ||
41 | |||
42 | printf("*** device: %p ***\n", device); | ||
43 | str = udev_device_get_action(device); | ||
44 | if (str != NULL) | ||
45 | printf("action: '%s'\n", str); | ||
46 | |||
47 | str = udev_device_get_syspath(device); | ||
48 | printf("syspath: '%s'\n", str); | ||
49 | |||
50 | str = udev_device_get_sysname(device); | ||
51 | printf("sysname: '%s'\n", str); | ||
52 | |||
53 | str = udev_device_get_sysnum(device); | ||
54 | if (str != NULL) | ||
55 | printf("sysnum: '%s'\n", str); | ||
56 | |||
57 | str = udev_device_get_devpath(device); | ||
58 | printf("devpath: '%s'\n", str); | ||
59 | |||
60 | str = udev_device_get_subsystem(device); | ||
61 | if (str != NULL) | ||
62 | printf("subsystem: '%s'\n", str); | ||
63 | |||
64 | str = udev_device_get_devtype(device); | ||
65 | if (str != NULL) | ||
66 | printf("devtype: '%s'\n", str); | ||
67 | |||
68 | str = udev_device_get_driver(device); | ||
69 | if (str != NULL) | ||
70 | printf("driver: '%s'\n", str); | ||
71 | |||
72 | str = udev_device_get_devnode(device); | ||
73 | if (str != NULL) | ||
74 | printf("devname: '%s'\n", str); | ||
75 | |||
76 | devnum = udev_device_get_devnum(device); | ||
77 | if (major(devnum) > 0) | ||
78 | printf("devnum: %u:%u\n", major(devnum), minor(devnum)); | ||
79 | |||
80 | count = 0; | ||
81 | udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(device)) { | ||
82 | printf("link: '%s'\n", udev_list_entry_get_name(list_entry)); | ||
83 | count++; | ||
84 | } | ||
85 | if (count > 0) | ||
86 | printf("found %i links\n", count); | ||
87 | |||
88 | count = 0; | ||
89 | udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(device)) { | ||
90 | printf("property: '%s=%s'\n", | ||
91 | udev_list_entry_get_name(list_entry), | ||
92 | udev_list_entry_get_value(list_entry)); | ||
93 | count++; | ||
94 | } | ||
95 | if (count > 0) | ||
96 | printf("found %i properties\n", count); | ||
97 | |||
98 | str = udev_device_get_property_value(device, "MAJOR"); | ||
99 | if (str != NULL) | ||
100 | printf("MAJOR: '%s'\n", str); | ||
101 | |||
102 | str = udev_device_get_sysattr_value(device, "dev"); | ||
103 | if (str != NULL) | ||
104 | printf("attr{dev}: '%s'\n", str); | ||
105 | |||
106 | printf("\n"); | ||
107 | } | ||
108 | |||
109 | static int test_device(struct udev *udev, const char *syspath) | ||
110 | { | ||
111 | struct udev_device *device; | ||
112 | |||
113 | printf("looking at device: %s\n", syspath); | ||
114 | device = udev_device_new_from_syspath(udev, syspath); | ||
115 | if (device == NULL) { | ||
116 | printf("no device found\n"); | ||
117 | return -1; | ||
118 | } | ||
119 | print_device(device); | ||
120 | udev_device_unref(device); | ||
121 | return 0; | ||
122 | } | ||
123 | |||
124 | static int test_device_parents(struct udev *udev, const char *syspath) | ||
125 | { | ||
126 | struct udev_device *device; | ||
127 | struct udev_device *device_parent; | ||
128 | |||
129 | printf("looking at device: %s\n", syspath); | ||
130 | device = udev_device_new_from_syspath(udev, syspath); | ||
131 | if (device == NULL) | ||
132 | return -1; | ||
133 | |||
134 | printf("looking at parents\n"); | ||
135 | device_parent = device; | ||
136 | do { | ||
137 | print_device(device_parent); | ||
138 | device_parent = udev_device_get_parent(device_parent); | ||
139 | } while (device_parent != NULL); | ||
140 | |||
141 | printf("looking at parents again\n"); | ||
142 | device_parent = device; | ||
143 | do { | ||
144 | print_device(device_parent); | ||
145 | device_parent = udev_device_get_parent(device_parent); | ||
146 | } while (device_parent != NULL); | ||
147 | udev_device_unref(device); | ||
148 | |||
149 | return 0; | ||
150 | } | ||
151 | |||
152 | static int test_device_devnum(struct udev *udev) | ||
153 | { | ||
154 | dev_t devnum = makedev(1, 3); | ||
155 | struct udev_device *device; | ||
156 | |||
157 | printf("looking up device: %u:%u\n", major(devnum), minor(devnum)); | ||
158 | device = udev_device_new_from_devnum(udev, 'c', devnum); | ||
159 | if (device == NULL) | ||
160 | return -1; | ||
161 | print_device(device); | ||
162 | udev_device_unref(device); | ||
163 | return 0; | ||
164 | } | ||
165 | |||
166 | static int test_device_subsys_name(struct udev *udev) | ||
167 | { | ||
168 | struct udev_device *device; | ||
169 | |||
170 | printf("looking up device: 'block':'sda'\n"); | ||
171 | device = udev_device_new_from_subsystem_sysname(udev, "block", "sda"); | ||
172 | if (device == NULL) | ||
173 | return -1; | ||
174 | print_device(device); | ||
175 | udev_device_unref(device); | ||
176 | |||
177 | printf("looking up device: 'subsystem':'pci'\n"); | ||
178 | device = udev_device_new_from_subsystem_sysname(udev, "subsystem", "pci"); | ||
179 | if (device == NULL) | ||
180 | return -1; | ||
181 | print_device(device); | ||
182 | udev_device_unref(device); | ||
183 | |||
184 | printf("looking up device: 'drivers':'scsi:sd'\n"); | ||
185 | device = udev_device_new_from_subsystem_sysname(udev, "drivers", "scsi:sd"); | ||
186 | if (device == NULL) | ||
187 | return -1; | ||
188 | print_device(device); | ||
189 | udev_device_unref(device); | ||
190 | |||
191 | printf("looking up device: 'module':'printk'\n"); | ||
192 | device = udev_device_new_from_subsystem_sysname(udev, "module", "printk"); | ||
193 | if (device == NULL) | ||
194 | return -1; | ||
195 | print_device(device); | ||
196 | udev_device_unref(device); | ||
197 | return 0; | ||
198 | } | ||
199 | |||
200 | static int test_enumerate_print_list(struct udev_enumerate *enumerate) | ||
201 | { | ||
202 | struct udev_list_entry *list_entry; | ||
203 | int count = 0; | ||
204 | |||
205 | udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(enumerate)) { | ||
206 | struct udev_device *device; | ||
207 | |||
208 | device = udev_device_new_from_syspath(udev_enumerate_get_udev(enumerate), | ||
209 | udev_list_entry_get_name(list_entry)); | ||
210 | if (device != NULL) { | ||
211 | printf("device: '%s' (%s)\n", | ||
212 | udev_device_get_syspath(device), | ||
213 | udev_device_get_subsystem(device)); | ||
214 | udev_device_unref(device); | ||
215 | count++; | ||
216 | } | ||
217 | } | ||
218 | printf("found %i devices\n\n", count); | ||
219 | return count; | ||
220 | } | ||
221 | |||
222 | static int test_monitor(struct udev *udev) | ||
223 | { | ||
224 | struct udev_monitor *udev_monitor = NULL; | ||
225 | int fd_ep; | ||
226 | int fd_udev = -1; | ||
227 | struct epoll_event ep_udev, ep_stdin; | ||
228 | |||
229 | fd_ep = epoll_create1(EPOLL_CLOEXEC); | ||
230 | if (fd_ep < 0) { | ||
231 | printf("error creating epoll fd: %m\n"); | ||
232 | goto out; | ||
233 | } | ||
234 | |||
235 | udev_monitor = udev_monitor_new_from_netlink(udev, "udev"); | ||
236 | if (udev_monitor == NULL) { | ||
237 | printf("no socket\n"); | ||
238 | goto out; | ||
239 | } | ||
240 | fd_udev = udev_monitor_get_fd(udev_monitor); | ||
241 | |||
242 | if (udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "block", NULL) < 0 || | ||
243 | udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "tty", NULL) < 0 || | ||
244 | udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "usb", "usb_device") < 0) { | ||
245 | printf("filter failed\n"); | ||
246 | goto out; | ||
247 | } | ||
248 | |||
249 | if (udev_monitor_enable_receiving(udev_monitor) < 0) { | ||
250 | printf("bind failed\n"); | ||
251 | goto out; | ||
252 | } | ||
253 | |||
254 | memset(&ep_udev, 0, sizeof(struct epoll_event)); | ||
255 | ep_udev.events = EPOLLIN; | ||
256 | ep_udev.data.fd = fd_udev; | ||
257 | if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_udev, &ep_udev) < 0) { | ||
258 | printf("fail to add fd to epoll: %m\n"); | ||
259 | goto out; | ||
260 | } | ||
261 | |||
262 | memset(&ep_stdin, 0, sizeof(struct epoll_event)); | ||
263 | ep_stdin.events = EPOLLIN; | ||
264 | ep_stdin.data.fd = STDIN_FILENO; | ||
265 | if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, STDIN_FILENO, &ep_stdin) < 0) { | ||
266 | printf("fail to add fd to epoll: %m\n"); | ||
267 | goto out; | ||
268 | } | ||
269 | |||
270 | for (;;) { | ||
271 | int fdcount; | ||
272 | struct epoll_event ev[4]; | ||
273 | struct udev_device *device; | ||
274 | int i; | ||
275 | |||
276 | printf("waiting for events from udev, press ENTER to exit\n"); | ||
277 | fdcount = epoll_wait(fd_ep, ev, ARRAY_SIZE(ev), -1); | ||
278 | printf("epoll fd count: %i\n", fdcount); | ||
279 | |||
280 | for (i = 0; i < fdcount; i++) { | ||
281 | if (ev[i].data.fd == fd_udev && ev[i].events & EPOLLIN) { | ||
282 | device = udev_monitor_receive_device(udev_monitor); | ||
283 | if (device == NULL) { | ||
284 | printf("no device from socket\n"); | ||
285 | continue; | ||
286 | } | ||
287 | print_device(device); | ||
288 | udev_device_unref(device); | ||
289 | } else if (ev[i].data.fd == STDIN_FILENO && ev[i].events & EPOLLIN) { | ||
290 | printf("exiting loop\n"); | ||
291 | goto out; | ||
292 | } | ||
293 | } | ||
294 | } | ||
295 | out: | ||
296 | if (fd_ep >= 0) | ||
297 | close(fd_ep); | ||
298 | udev_monitor_unref(udev_monitor); | ||
299 | return 0; | ||
300 | } | ||
301 | |||
302 | static int test_queue(struct udev *udev) | ||
303 | { | ||
304 | struct udev_queue *udev_queue; | ||
305 | unsigned long long int seqnum; | ||
306 | struct udev_list_entry *list_entry; | ||
307 | |||
308 | udev_queue = udev_queue_new(udev); | ||
309 | if (udev_queue == NULL) | ||
310 | return -1; | ||
311 | seqnum = udev_queue_get_kernel_seqnum(udev_queue); | ||
312 | printf("seqnum kernel: %llu\n", seqnum); | ||
313 | seqnum = udev_queue_get_udev_seqnum(udev_queue); | ||
314 | printf("seqnum udev : %llu\n", seqnum); | ||
315 | |||
316 | if (udev_queue_get_queue_is_empty(udev_queue)) | ||
317 | printf("queue is empty\n"); | ||
318 | printf("get queue list\n"); | ||
319 | udev_list_entry_foreach(list_entry, udev_queue_get_queued_list_entry(udev_queue)) | ||
320 | printf("queued: '%s' [%s]\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry)); | ||
321 | printf("\n"); | ||
322 | printf("get queue list again\n"); | ||
323 | udev_list_entry_foreach(list_entry, udev_queue_get_queued_list_entry(udev_queue)) | ||
324 | printf("queued: '%s' [%s]\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry)); | ||
325 | printf("\n"); | ||
326 | |||
327 | list_entry = udev_queue_get_queued_list_entry(udev_queue); | ||
328 | if (list_entry != NULL) { | ||
329 | printf("event [%llu] is queued\n", seqnum); | ||
330 | seqnum = strtoull(udev_list_entry_get_value(list_entry), NULL, 10); | ||
331 | if (udev_queue_get_seqnum_is_finished(udev_queue, seqnum)) | ||
332 | printf("event [%llu] is not finished\n", seqnum); | ||
333 | else | ||
334 | printf("event [%llu] is finished\n", seqnum); | ||
335 | } | ||
336 | printf("\n"); | ||
337 | udev_queue_unref(udev_queue); | ||
338 | return 0; | ||
339 | } | ||
340 | |||
341 | static int test_enumerate(struct udev *udev, const char *subsystem) | ||
342 | { | ||
343 | struct udev_enumerate *udev_enumerate; | ||
344 | |||
345 | printf("enumerate '%s'\n", subsystem == NULL ? "<all>" : subsystem); | ||
346 | udev_enumerate = udev_enumerate_new(udev); | ||
347 | if (udev_enumerate == NULL) | ||
348 | return -1; | ||
349 | udev_enumerate_add_match_subsystem(udev_enumerate, subsystem); | ||
350 | udev_enumerate_scan_devices(udev_enumerate); | ||
351 | test_enumerate_print_list(udev_enumerate); | ||
352 | udev_enumerate_unref(udev_enumerate); | ||
353 | |||
354 | printf("enumerate 'net' + duplicated scan + null + zero\n"); | ||
355 | udev_enumerate = udev_enumerate_new(udev); | ||
356 | if (udev_enumerate == NULL) | ||
357 | return -1; | ||
358 | udev_enumerate_add_match_subsystem(udev_enumerate, "net"); | ||
359 | udev_enumerate_scan_devices(udev_enumerate); | ||
360 | udev_enumerate_scan_devices(udev_enumerate); | ||
361 | udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/zero"); | ||
362 | udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/null"); | ||
363 | udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/zero"); | ||
364 | udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/null"); | ||
365 | udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/zero"); | ||
366 | udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/null"); | ||
367 | udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/null"); | ||
368 | udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/zero"); | ||
369 | udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/zero"); | ||
370 | udev_enumerate_scan_devices(udev_enumerate); | ||
371 | test_enumerate_print_list(udev_enumerate); | ||
372 | udev_enumerate_unref(udev_enumerate); | ||
373 | |||
374 | printf("enumerate 'block'\n"); | ||
375 | udev_enumerate = udev_enumerate_new(udev); | ||
376 | if (udev_enumerate == NULL) | ||
377 | return -1; | ||
378 | udev_enumerate_add_match_subsystem(udev_enumerate,"block"); | ||
379 | udev_enumerate_add_match_is_initialized(udev_enumerate); | ||
380 | udev_enumerate_scan_devices(udev_enumerate); | ||
381 | test_enumerate_print_list(udev_enumerate); | ||
382 | udev_enumerate_unref(udev_enumerate); | ||
383 | |||
384 | printf("enumerate 'not block'\n"); | ||
385 | udev_enumerate = udev_enumerate_new(udev); | ||
386 | if (udev_enumerate == NULL) | ||
387 | return -1; | ||
388 | udev_enumerate_add_nomatch_subsystem(udev_enumerate, "block"); | ||
389 | udev_enumerate_scan_devices(udev_enumerate); | ||
390 | test_enumerate_print_list(udev_enumerate); | ||
391 | udev_enumerate_unref(udev_enumerate); | ||
392 | |||
393 | printf("enumerate 'pci, mem, vc'\n"); | ||
394 | udev_enumerate = udev_enumerate_new(udev); | ||
395 | if (udev_enumerate == NULL) | ||
396 | return -1; | ||
397 | udev_enumerate_add_match_subsystem(udev_enumerate, "pci"); | ||
398 | udev_enumerate_add_match_subsystem(udev_enumerate, "mem"); | ||
399 | udev_enumerate_add_match_subsystem(udev_enumerate, "vc"); | ||
400 | udev_enumerate_scan_devices(udev_enumerate); | ||
401 | test_enumerate_print_list(udev_enumerate); | ||
402 | udev_enumerate_unref(udev_enumerate); | ||
403 | |||
404 | printf("enumerate 'subsystem'\n"); | ||
405 | udev_enumerate = udev_enumerate_new(udev); | ||
406 | if (udev_enumerate == NULL) | ||
407 | return -1; | ||
408 | udev_enumerate_scan_subsystems(udev_enumerate); | ||
409 | test_enumerate_print_list(udev_enumerate); | ||
410 | udev_enumerate_unref(udev_enumerate); | ||
411 | |||
412 | printf("enumerate 'property IF_FS_*=filesystem'\n"); | ||
413 | udev_enumerate = udev_enumerate_new(udev); | ||
414 | if (udev_enumerate == NULL) | ||
415 | return -1; | ||
416 | udev_enumerate_add_match_property(udev_enumerate, "ID_FS*", "filesystem"); | ||
417 | udev_enumerate_scan_devices(udev_enumerate); | ||
418 | test_enumerate_print_list(udev_enumerate); | ||
419 | udev_enumerate_unref(udev_enumerate); | ||
420 | return 0; | ||
421 | } | ||
422 | |||
423 | int main(int argc, char *argv[]) | ||
424 | { | ||
425 | struct udev *udev = NULL; | ||
426 | static const struct option options[] = { | ||
427 | { "syspath", required_argument, NULL, 'p' }, | ||
428 | { "subsystem", required_argument, NULL, 's' }, | ||
429 | { "debug", no_argument, NULL, 'd' }, | ||
430 | { "help", no_argument, NULL, 'h' }, | ||
431 | { "version", no_argument, NULL, 'V' }, | ||
432 | {} | ||
433 | }; | ||
434 | const char *syspath = "/devices/virtual/mem/null"; | ||
435 | const char *subsystem = NULL; | ||
436 | char path[1024]; | ||
437 | const char *str; | ||
438 | |||
439 | udev = udev_new(); | ||
440 | printf("context: %p\n", udev); | ||
441 | if (udev == NULL) { | ||
442 | printf("no context\n"); | ||
443 | return 1; | ||
444 | } | ||
445 | udev_set_log_fn(udev, log_fn); | ||
446 | printf("set log: %p\n", log_fn); | ||
447 | |||
448 | for (;;) { | ||
449 | int option; | ||
450 | |||
451 | option = getopt_long(argc, argv, "+p:s:dhV", options, NULL); | ||
452 | if (option == -1) | ||
453 | break; | ||
454 | |||
455 | switch (option) { | ||
456 | case 'p': | ||
457 | syspath = optarg; | ||
458 | break; | ||
459 | case 's': | ||
460 | subsystem = optarg; | ||
461 | break; | ||
462 | case 'd': | ||
463 | if (udev_get_log_priority(udev) < LOG_INFO) | ||
464 | udev_set_log_priority(udev, LOG_INFO); | ||
465 | break; | ||
466 | case 'h': | ||
467 | printf("--debug --syspath= --subsystem= --help\n"); | ||
468 | goto out; | ||
469 | case 'V': | ||
470 | printf("%s\n", VERSION); | ||
471 | goto out; | ||
472 | default: | ||
473 | goto out; | ||
474 | } | ||
475 | } | ||
476 | |||
477 | str = udev_get_sys_path(udev); | ||
478 | printf("sys_path: '%s'\n", str); | ||
479 | str = udev_get_dev_path(udev); | ||
480 | printf("dev_path: '%s'\n", str); | ||
481 | |||
482 | /* add sys path if needed */ | ||
483 | if (strncmp(syspath, udev_get_sys_path(udev), strlen(udev_get_sys_path(udev))) != 0) { | ||
484 | snprintf(path, sizeof(path), "%s%s", udev_get_sys_path(udev), syspath); | ||
485 | syspath = path; | ||
486 | } | ||
487 | |||
488 | test_device(udev, syspath); | ||
489 | test_device_devnum(udev); | ||
490 | test_device_subsys_name(udev); | ||
491 | test_device_parents(udev, syspath); | ||
492 | |||
493 | test_enumerate(udev, subsystem); | ||
494 | |||
495 | test_queue(udev); | ||
496 | |||
497 | test_monitor(udev); | ||
498 | out: | ||
499 | udev_unref(udev); | ||
500 | return 0; | ||
501 | } | ||
diff --git a/src/udev/src/test-udev.c b/src/udev/src/test-udev.c new file mode 100644 index 000000000..c9712e974 --- /dev/null +++ b/src/udev/src/test-udev.c | |||
@@ -0,0 +1,121 @@ | |||
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 <stdio.h> | ||
20 | #include <stddef.h> | ||
21 | #include <stdlib.h> | ||
22 | #include <string.h> | ||
23 | #include <fcntl.h> | ||
24 | #include <ctype.h> | ||
25 | #include <errno.h> | ||
26 | #include <unistd.h> | ||
27 | #include <syslog.h> | ||
28 | #include <grp.h> | ||
29 | #include <sys/signalfd.h> | ||
30 | |||
31 | #include "udev.h" | ||
32 | |||
33 | void udev_main_log(struct udev *udev, int priority, | ||
34 | const char *file, int line, const char *fn, | ||
35 | const char *format, va_list args) {} | ||
36 | |||
37 | int main(int argc, char *argv[]) | ||
38 | { | ||
39 | struct udev *udev; | ||
40 | struct udev_event *event = NULL; | ||
41 | struct udev_device *dev = NULL; | ||
42 | struct udev_rules *rules = NULL; | ||
43 | char syspath[UTIL_PATH_SIZE]; | ||
44 | const char *devpath; | ||
45 | const char *action; | ||
46 | sigset_t mask, sigmask_orig; | ||
47 | int err = -EINVAL; | ||
48 | |||
49 | udev = udev_new(); | ||
50 | if (udev == NULL) | ||
51 | exit(1); | ||
52 | info(udev, "version %s\n", VERSION); | ||
53 | udev_selinux_init(udev); | ||
54 | |||
55 | sigprocmask(SIG_SETMASK, NULL, &sigmask_orig); | ||
56 | |||
57 | action = argv[1]; | ||
58 | if (action == NULL) { | ||
59 | err(udev, "action missing\n"); | ||
60 | goto out; | ||
61 | } | ||
62 | |||
63 | devpath = argv[2]; | ||
64 | if (devpath == NULL) { | ||
65 | err(udev, "devpath missing\n"); | ||
66 | goto out; | ||
67 | } | ||
68 | |||
69 | rules = udev_rules_new(udev, 1); | ||
70 | |||
71 | util_strscpyl(syspath, sizeof(syspath), udev_get_sys_path(udev), devpath, NULL); | ||
72 | dev = udev_device_new_from_syspath(udev, syspath); | ||
73 | if (dev == NULL) { | ||
74 | info(udev, "unknown device '%s'\n", devpath); | ||
75 | goto out; | ||
76 | } | ||
77 | |||
78 | udev_device_set_action(dev, action); | ||
79 | event = udev_event_new(dev); | ||
80 | |||
81 | sigfillset(&mask); | ||
82 | sigprocmask(SIG_SETMASK, &mask, &sigmask_orig); | ||
83 | event->fd_signal = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC); | ||
84 | if (event->fd_signal < 0) { | ||
85 | fprintf(stderr, "error creating signalfd\n"); | ||
86 | goto out; | ||
87 | } | ||
88 | |||
89 | /* do what devtmpfs usually provides us */ | ||
90 | if (udev_device_get_devnode(dev) != NULL) { | ||
91 | mode_t mode; | ||
92 | |||
93 | if (strcmp(udev_device_get_subsystem(dev), "block") == 0) | ||
94 | mode |= S_IFBLK; | ||
95 | else | ||
96 | mode |= S_IFCHR; | ||
97 | |||
98 | if (strcmp(action, "remove") != 0) { | ||
99 | util_create_path(udev, udev_device_get_devnode(dev)); | ||
100 | mknod(udev_device_get_devnode(dev), mode, udev_device_get_devnum(dev)); | ||
101 | } else { | ||
102 | unlink(udev_device_get_devnode(dev)); | ||
103 | util_delete_path(udev, udev_device_get_devnode(dev)); | ||
104 | } | ||
105 | } | ||
106 | |||
107 | err = udev_event_execute_rules(event, rules, &sigmask_orig); | ||
108 | if (err == 0) | ||
109 | udev_event_execute_run(event, NULL); | ||
110 | out: | ||
111 | if (event != NULL && event->fd_signal >= 0) | ||
112 | close(event->fd_signal); | ||
113 | udev_event_unref(event); | ||
114 | udev_device_unref(dev); | ||
115 | udev_rules_unref(rules); | ||
116 | udev_selinux_exit(udev); | ||
117 | udev_unref(udev); | ||
118 | if (err != 0) | ||
119 | return 1; | ||
120 | return 0; | ||
121 | } | ||
diff --git a/src/udev/src/udev-builtin-blkid.c b/src/udev/src/udev-builtin-blkid.c new file mode 100644 index 000000000..e57f03e5a --- /dev/null +++ b/src/udev/src/udev-builtin-blkid.c | |||
@@ -0,0 +1,207 @@ | |||
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 | }; | ||
diff --git a/src/udev/src/udev-builtin-firmware.c b/src/udev/src/udev-builtin-firmware.c new file mode 100644 index 000000000..d212c64b4 --- /dev/null +++ b/src/udev/src/udev-builtin-firmware.c | |||
@@ -0,0 +1,168 @@ | |||
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 | }; | ||
diff --git a/src/udev/src/udev-builtin-hwdb.c b/src/udev/src/udev-builtin-hwdb.c new file mode 100644 index 000000000..aa996f375 --- /dev/null +++ b/src/udev/src/udev-builtin-hwdb.c | |||
@@ -0,0 +1,247 @@ | |||
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 | }; | ||
diff --git a/src/udev/src/udev-builtin-input_id.c b/src/udev/src/udev-builtin-input_id.c new file mode 100644 index 000000000..a062ef7c7 --- /dev/null +++ b/src/udev/src/udev-builtin-input_id.c | |||
@@ -0,0 +1,218 @@ | |||
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 | }; | ||
diff --git a/src/udev/src/udev-builtin-kmod.c b/src/udev/src/udev-builtin-kmod.c new file mode 100644 index 000000000..57e813f86 --- /dev/null +++ b/src/udev/src/udev-builtin-kmod.c | |||
@@ -0,0 +1,142 @@ | |||
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 | }; | ||
diff --git a/src/udev/src/udev-builtin-path_id.c b/src/udev/src/udev-builtin-path_id.c new file mode 100644 index 000000000..a8559d2dd --- /dev/null +++ b/src/udev/src/udev-builtin-path_id.c | |||
@@ -0,0 +1,498 @@ | |||
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 | out: | ||
60 | return err; | ||
61 | } | ||
62 | |||
63 | /* | ||
64 | ** Linux only supports 32 bit luns. | ||
65 | ** See drivers/scsi/scsi_scan.c::scsilun_to_int() for more details. | ||
66 | */ | ||
67 | static int format_lun_number(struct udev_device *dev, char **path) | ||
68 | { | ||
69 | unsigned long lun = strtoul(udev_device_get_sysnum(dev), NULL, 10); | ||
70 | |||
71 | /* address method 0, peripheral device addressing with bus id of zero */ | ||
72 | if (lun < 256) | ||
73 | return path_prepend(path, "lun-%d", lun); | ||
74 | /* handle all other lun addressing methods by using a variant of the original lun format */ | ||
75 | return path_prepend(path, "lun-0x%04x%04x00000000", (lun & 0xffff), (lun >> 16) & 0xffff); | ||
76 | } | ||
77 | |||
78 | static struct udev_device *skip_subsystem(struct udev_device *dev, const char *subsys) | ||
79 | { | ||
80 | struct udev_device *parent = dev; | ||
81 | |||
82 | while (parent != NULL) { | ||
83 | const char *subsystem; | ||
84 | |||
85 | subsystem = udev_device_get_subsystem(parent); | ||
86 | if (subsystem == NULL || strcmp(subsystem, subsys) != 0) | ||
87 | break; | ||
88 | dev = parent; | ||
89 | parent = udev_device_get_parent(parent); | ||
90 | } | ||
91 | return dev; | ||
92 | } | ||
93 | |||
94 | static struct udev_device *handle_scsi_fibre_channel(struct udev_device *parent, char **path) | ||
95 | { | ||
96 | struct udev *udev = udev_device_get_udev(parent); | ||
97 | struct udev_device *targetdev; | ||
98 | struct udev_device *fcdev = NULL; | ||
99 | const char *port; | ||
100 | char *lun = NULL;; | ||
101 | |||
102 | targetdev = udev_device_get_parent_with_subsystem_devtype(parent, "scsi", "scsi_target"); | ||
103 | if (targetdev == NULL) | ||
104 | return NULL; | ||
105 | |||
106 | fcdev = udev_device_new_from_subsystem_sysname(udev, "fc_transport", udev_device_get_sysname(targetdev)); | ||
107 | if (fcdev == NULL) | ||
108 | return NULL; | ||
109 | port = udev_device_get_sysattr_value(fcdev, "port_name"); | ||
110 | if (port == NULL) { | ||
111 | parent = NULL; | ||
112 | goto out; | ||
113 | } | ||
114 | |||
115 | format_lun_number(parent, &lun); | ||
116 | path_prepend(path, "fc-%s-%s", port, lun); | ||
117 | if (lun) | ||
118 | free(lun); | ||
119 | out: | ||
120 | udev_device_unref(fcdev); | ||
121 | return parent; | ||
122 | } | ||
123 | |||
124 | static struct udev_device *handle_scsi_sas(struct udev_device *parent, char **path) | ||
125 | { | ||
126 | struct udev *udev = udev_device_get_udev(parent); | ||
127 | struct udev_device *targetdev; | ||
128 | struct udev_device *target_parent; | ||
129 | struct udev_device *sasdev; | ||
130 | const char *sas_address; | ||
131 | char *lun = NULL; | ||
132 | |||
133 | targetdev = udev_device_get_parent_with_subsystem_devtype(parent, "scsi", "scsi_target"); | ||
134 | if (targetdev == NULL) | ||
135 | return NULL; | ||
136 | |||
137 | target_parent = udev_device_get_parent(targetdev); | ||
138 | if (target_parent == NULL) | ||
139 | return NULL; | ||
140 | |||
141 | sasdev = udev_device_new_from_subsystem_sysname(udev, "sas_device", | ||
142 | udev_device_get_sysname(target_parent)); | ||
143 | if (sasdev == NULL) | ||
144 | return NULL; | ||
145 | |||
146 | sas_address = udev_device_get_sysattr_value(sasdev, "sas_address"); | ||
147 | if (sas_address == NULL) { | ||
148 | parent = NULL; | ||
149 | goto out; | ||
150 | } | ||
151 | |||
152 | format_lun_number(parent, &lun); | ||
153 | path_prepend(path, "sas-%s-%s", sas_address, lun); | ||
154 | if (lun) | ||
155 | free(lun); | ||
156 | out: | ||
157 | udev_device_unref(sasdev); | ||
158 | return parent; | ||
159 | } | ||
160 | |||
161 | static struct udev_device *handle_scsi_iscsi(struct udev_device *parent, char **path) | ||
162 | { | ||
163 | struct udev *udev = udev_device_get_udev(parent); | ||
164 | struct udev_device *transportdev; | ||
165 | struct udev_device *sessiondev = NULL; | ||
166 | const char *target; | ||
167 | char *connname; | ||
168 | struct udev_device *conndev = NULL; | ||
169 | const char *addr; | ||
170 | const char *port; | ||
171 | char *lun = NULL; | ||
172 | |||
173 | /* find iscsi session */ | ||
174 | transportdev = parent; | ||
175 | for (;;) { | ||
176 | transportdev = udev_device_get_parent(transportdev); | ||
177 | if (transportdev == NULL) | ||
178 | return NULL; | ||
179 | if (strncmp(udev_device_get_sysname(transportdev), "session", 7) == 0) | ||
180 | break; | ||
181 | } | ||
182 | |||
183 | /* find iscsi session device */ | ||
184 | sessiondev = udev_device_new_from_subsystem_sysname(udev, "iscsi_session", udev_device_get_sysname(transportdev)); | ||
185 | if (sessiondev == NULL) | ||
186 | return NULL; | ||
187 | target = udev_device_get_sysattr_value(sessiondev, "targetname"); | ||
188 | if (target == NULL) { | ||
189 | parent = NULL; | ||
190 | goto out; | ||
191 | } | ||
192 | |||
193 | if (asprintf(&connname, "connection%s:0", udev_device_get_sysnum(transportdev)) < 0) { | ||
194 | parent = NULL; | ||
195 | goto out; | ||
196 | } | ||
197 | conndev = udev_device_new_from_subsystem_sysname(udev, "iscsi_connection", connname); | ||
198 | free(connname); | ||
199 | if (conndev == NULL) { | ||
200 | parent = NULL; | ||
201 | goto out; | ||
202 | } | ||
203 | addr = udev_device_get_sysattr_value(conndev, "persistent_address"); | ||
204 | port = udev_device_get_sysattr_value(conndev, "persistent_port"); | ||
205 | if (addr == NULL || port == NULL) { | ||
206 | parent = NULL; | ||
207 | goto out; | ||
208 | } | ||
209 | |||
210 | format_lun_number(parent, &lun); | ||
211 | path_prepend(path, "ip-%s:%s-iscsi-%s-%s", addr, port, target, lun); | ||
212 | if (lun) | ||
213 | free(lun); | ||
214 | out: | ||
215 | udev_device_unref(sessiondev); | ||
216 | udev_device_unref(conndev); | ||
217 | return parent; | ||
218 | } | ||
219 | |||
220 | static struct udev_device *handle_scsi_default(struct udev_device *parent, char **path) | ||
221 | { | ||
222 | struct udev_device *hostdev; | ||
223 | int host, bus, target, lun; | ||
224 | const char *name; | ||
225 | char *base; | ||
226 | char *pos; | ||
227 | DIR *dir; | ||
228 | struct dirent *dent; | ||
229 | int basenum; | ||
230 | |||
231 | hostdev = udev_device_get_parent_with_subsystem_devtype(parent, "scsi", "scsi_host"); | ||
232 | if (hostdev == NULL) | ||
233 | return NULL; | ||
234 | |||
235 | name = udev_device_get_sysname(parent); | ||
236 | if (sscanf(name, "%d:%d:%d:%d", &host, &bus, &target, &lun) != 4) | ||
237 | return NULL; | ||
238 | |||
239 | /* rebase host offset to get the local relative number */ | ||
240 | basenum = -1; | ||
241 | base = strdup(udev_device_get_syspath(hostdev)); | ||
242 | if (base == NULL) | ||
243 | return NULL; | ||
244 | pos = strrchr(base, '/'); | ||
245 | if (pos == NULL) { | ||
246 | parent = NULL; | ||
247 | goto out; | ||
248 | } | ||
249 | pos[0] = '\0'; | ||
250 | dir = opendir(base); | ||
251 | if (dir == NULL) { | ||
252 | parent = NULL; | ||
253 | goto out; | ||
254 | } | ||
255 | for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { | ||
256 | char *rest; | ||
257 | int i; | ||
258 | |||
259 | if (dent->d_name[0] == '.') | ||
260 | continue; | ||
261 | if (dent->d_type != DT_DIR && dent->d_type != DT_LNK) | ||
262 | continue; | ||
263 | if (strncmp(dent->d_name, "host", 4) != 0) | ||
264 | continue; | ||
265 | i = strtoul(&dent->d_name[4], &rest, 10); | ||
266 | if (rest[0] != '\0') | ||
267 | continue; | ||
268 | /* | ||
269 | * find the smallest number; the host really needs to export its | ||
270 | * own instance number per parent device; relying on the global host | ||
271 | * enumeration and plainly rebasing the numbers sounds unreliable | ||
272 | */ | ||
273 | if (basenum == -1 || i < basenum) | ||
274 | basenum = i; | ||
275 | } | ||
276 | closedir(dir); | ||
277 | if (basenum == -1) { | ||
278 | parent = NULL; | ||
279 | goto out; | ||
280 | } | ||
281 | host -= basenum; | ||
282 | |||
283 | path_prepend(path, "scsi-%u:%u:%u:%u", host, bus, target, lun); | ||
284 | out: | ||
285 | free(base); | ||
286 | return hostdev; | ||
287 | } | ||
288 | |||
289 | static struct udev_device *handle_scsi(struct udev_device *parent, char **path) | ||
290 | { | ||
291 | const char *devtype; | ||
292 | const char *name; | ||
293 | const char *id; | ||
294 | |||
295 | devtype = udev_device_get_devtype(parent); | ||
296 | if (devtype == NULL || strcmp(devtype, "scsi_device") != 0) | ||
297 | return parent; | ||
298 | |||
299 | /* firewire */ | ||
300 | id = udev_device_get_sysattr_value(parent, "ieee1394_id"); | ||
301 | if (id != NULL) { | ||
302 | parent = skip_subsystem(parent, "scsi"); | ||
303 | path_prepend(path, "ieee1394-0x%s", id); | ||
304 | goto out; | ||
305 | } | ||
306 | |||
307 | /* lousy scsi sysfs does not have a "subsystem" for the transport */ | ||
308 | name = udev_device_get_syspath(parent); | ||
309 | |||
310 | if (strstr(name, "/rport-") != NULL) { | ||
311 | parent = handle_scsi_fibre_channel(parent, path); | ||
312 | goto out; | ||
313 | } | ||
314 | |||
315 | if (strstr(name, "/end_device-") != NULL) { | ||
316 | parent = handle_scsi_sas(parent, path); | ||
317 | goto out; | ||
318 | } | ||
319 | |||
320 | if (strstr(name, "/session") != NULL) { | ||
321 | parent = handle_scsi_iscsi(parent, path); | ||
322 | goto out; | ||
323 | } | ||
324 | |||
325 | /* | ||
326 | * We do not support the ATA transport class, it creates duplicated link | ||
327 | * names as the fake SCSI host adapters are all separated, they are all | ||
328 | * re-based as host == 0. ATA should just stop faking two duplicated | ||
329 | * hierarchies for a single topology and leave the SCSI stuff alone; | ||
330 | * until that happens, there are no by-path/ links for ATA devices behind | ||
331 | * an ATA transport class. | ||
332 | */ | ||
333 | if (strstr(name, "/ata") != NULL) { | ||
334 | parent = NULL; | ||
335 | goto out; | ||
336 | } | ||
337 | |||
338 | parent = handle_scsi_default(parent, path); | ||
339 | out: | ||
340 | return parent; | ||
341 | } | ||
342 | |||
343 | static void handle_scsi_tape(struct udev_device *dev, char **path) | ||
344 | { | ||
345 | const char *name; | ||
346 | |||
347 | /* must be the last device in the syspath */ | ||
348 | if (*path != NULL) | ||
349 | return; | ||
350 | |||
351 | name = udev_device_get_sysname(dev); | ||
352 | if (strncmp(name, "nst", 3) == 0 && strchr("lma", name[3]) != NULL) | ||
353 | path_prepend(path, "nst%c", name[3]); | ||
354 | else if (strncmp(name, "st", 2) == 0 && strchr("lma", name[2]) != NULL) | ||
355 | path_prepend(path, "st%c", name[2]); | ||
356 | } | ||
357 | |||
358 | static struct udev_device *handle_usb(struct udev_device *parent, char **path) | ||
359 | { | ||
360 | const char *devtype; | ||
361 | const char *str; | ||
362 | const char *port; | ||
363 | |||
364 | devtype = udev_device_get_devtype(parent); | ||
365 | if (devtype == NULL) | ||
366 | return parent; | ||
367 | if (strcmp(devtype, "usb_interface") != 0 && strcmp(devtype, "usb_device") != 0) | ||
368 | return parent; | ||
369 | |||
370 | str = udev_device_get_sysname(parent); | ||
371 | port = strchr(str, '-'); | ||
372 | if (port == NULL) | ||
373 | return parent; | ||
374 | port++; | ||
375 | |||
376 | parent = skip_subsystem(parent, "usb"); | ||
377 | path_prepend(path, "usb-0:%s", port); | ||
378 | return parent; | ||
379 | } | ||
380 | |||
381 | static struct udev_device *handle_ccw(struct udev_device *parent, struct udev_device *dev, char **path) | ||
382 | { | ||
383 | struct udev_device *scsi_dev; | ||
384 | |||
385 | scsi_dev = udev_device_get_parent_with_subsystem_devtype(dev, "scsi", "scsi_device"); | ||
386 | if (scsi_dev != NULL) { | ||
387 | const char *wwpn; | ||
388 | const char *lun; | ||
389 | const char *hba_id; | ||
390 | |||
391 | hba_id = udev_device_get_sysattr_value(scsi_dev, "hba_id"); | ||
392 | wwpn = udev_device_get_sysattr_value(scsi_dev, "wwpn"); | ||
393 | lun = udev_device_get_sysattr_value(scsi_dev, "fcp_lun"); | ||
394 | if (hba_id != NULL && lun != NULL && wwpn != NULL) { | ||
395 | path_prepend(path, "ccw-%s-zfcp-%s:%s", hba_id, wwpn, lun); | ||
396 | goto out; | ||
397 | } | ||
398 | } | ||
399 | |||
400 | path_prepend(path, "ccw-%s", udev_device_get_sysname(parent)); | ||
401 | out: | ||
402 | parent = skip_subsystem(parent, "ccw"); | ||
403 | return parent; | ||
404 | } | ||
405 | |||
406 | static int builtin_path_id(struct udev_device *dev, int argc, char *argv[], bool test) | ||
407 | { | ||
408 | struct udev_device *parent; | ||
409 | char *path = NULL; | ||
410 | |||
411 | /* S390 ccw bus */ | ||
412 | parent = udev_device_get_parent_with_subsystem_devtype(dev, "ccw", NULL); | ||
413 | if (parent != NULL) { | ||
414 | handle_ccw(parent, dev, &path); | ||
415 | goto out; | ||
416 | } | ||
417 | |||
418 | /* walk up the chain of devices and compose path */ | ||
419 | parent = dev; | ||
420 | while (parent != NULL) { | ||
421 | const char *subsys; | ||
422 | |||
423 | subsys = udev_device_get_subsystem(parent); | ||
424 | if (subsys == NULL) { | ||
425 | ; | ||
426 | } else if (strcmp(subsys, "scsi_tape") == 0) { | ||
427 | handle_scsi_tape(parent, &path); | ||
428 | } else if (strcmp(subsys, "scsi") == 0) { | ||
429 | parent = handle_scsi(parent, &path); | ||
430 | } else if (strcmp(subsys, "usb") == 0) { | ||
431 | parent = handle_usb(parent, &path); | ||
432 | } else if (strcmp(subsys, "serio") == 0) { | ||
433 | path_prepend(&path, "serio-%s", udev_device_get_sysnum(parent)); | ||
434 | parent = skip_subsystem(parent, "serio"); | ||
435 | } else if (strcmp(subsys, "pci") == 0) { | ||
436 | path_prepend(&path, "pci-%s", udev_device_get_sysname(parent)); | ||
437 | parent = skip_subsystem(parent, "pci"); | ||
438 | } else if (strcmp(subsys, "platform") == 0) { | ||
439 | path_prepend(&path, "platform-%s", udev_device_get_sysname(parent)); | ||
440 | parent = skip_subsystem(parent, "platform"); | ||
441 | } else if (strcmp(subsys, "acpi") == 0) { | ||
442 | path_prepend(&path, "acpi-%s", udev_device_get_sysname(parent)); | ||
443 | parent = skip_subsystem(parent, "acpi"); | ||
444 | } else if (strcmp(subsys, "xen") == 0) { | ||
445 | path_prepend(&path, "xen-%s", udev_device_get_sysname(parent)); | ||
446 | parent = skip_subsystem(parent, "xen"); | ||
447 | } else if (strcmp(subsys, "virtio") == 0) { | ||
448 | path_prepend(&path, "virtio-pci-%s", udev_device_get_sysname(parent)); | ||
449 | parent = skip_subsystem(parent, "virtio"); | ||
450 | } | ||
451 | |||
452 | parent = udev_device_get_parent(parent); | ||
453 | } | ||
454 | out: | ||
455 | if (path != NULL) { | ||
456 | char tag[UTIL_NAME_SIZE]; | ||
457 | size_t i; | ||
458 | const char *p; | ||
459 | |||
460 | /* compose valid udev tag name */ | ||
461 | for (p = path, i = 0; *p; p++) { | ||
462 | if ((*p >= '0' && *p <= '9') || | ||
463 | (*p >= 'A' && *p <= 'Z') || | ||
464 | (*p >= 'a' && *p <= 'z') || | ||
465 | *p == '-') { | ||
466 | tag[i++] = *p; | ||
467 | continue; | ||
468 | } | ||
469 | |||
470 | /* skip all leading '_' */ | ||
471 | if (i == 0) | ||
472 | continue; | ||
473 | |||
474 | /* avoid second '_' */ | ||
475 | if (tag[i-1] == '_') | ||
476 | continue; | ||
477 | |||
478 | tag[i++] = '_'; | ||
479 | } | ||
480 | /* strip trailing '_' */ | ||
481 | while (i > 0 && tag[i-1] == '_') | ||
482 | i--; | ||
483 | tag[i] = '\0'; | ||
484 | |||
485 | udev_builtin_add_property(dev, test, "ID_PATH", path); | ||
486 | udev_builtin_add_property(dev, test, "ID_PATH_TAG", tag); | ||
487 | free(path); | ||
488 | return EXIT_SUCCESS; | ||
489 | } | ||
490 | return EXIT_FAILURE; | ||
491 | } | ||
492 | |||
493 | const struct udev_builtin udev_builtin_path_id = { | ||
494 | .name = "path_id", | ||
495 | .cmd = builtin_path_id, | ||
496 | .help = "compose persistent device path", | ||
497 | .run_once = true, | ||
498 | }; | ||
diff --git a/src/udev/src/udev-builtin-usb_id.c b/src/udev/src/udev-builtin-usb_id.c new file mode 100644 index 000000000..85828e32d --- /dev/null +++ b/src/udev/src/udev-builtin-usb_id.c | |||
@@ -0,0 +1,482 @@ | |||
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 | }; | ||
diff --git a/src/udev/src/udev-builtin.c b/src/udev/src/udev-builtin.c new file mode 100644 index 000000000..5bc5fa68f --- /dev/null +++ b/src/udev/src/udev-builtin.c | |||
@@ -0,0 +1,134 @@ | |||
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; | ||
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 | } | ||
diff --git a/src/udev/src/udev-control.socket b/src/udev/src/udev-control.socket new file mode 100644 index 000000000..f80f77442 --- /dev/null +++ b/src/udev/src/udev-control.socket | |||
@@ -0,0 +1,10 @@ | |||
1 | [Unit] | ||
2 | Description=udev Control Socket | ||
3 | DefaultDependencies=no | ||
4 | ConditionCapability=CAP_MKNOD | ||
5 | |||
6 | [Socket] | ||
7 | Service=udev.service | ||
8 | ListenSequentialPacket=/run/udev/control | ||
9 | SocketMode=0600 | ||
10 | PassCredentials=yes | ||
diff --git a/src/udev/src/udev-ctrl.c b/src/udev/src/udev-ctrl.c new file mode 100644 index 000000000..5556f1a77 --- /dev/null +++ b/src/udev/src/udev-ctrl.c | |||
@@ -0,0 +1,494 @@ | |||
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 | } | ||
diff --git a/src/udev/src/udev-event.c b/src/udev/src/udev-event.c new file mode 100644 index 000000000..45dd77ba2 --- /dev/null +++ b/src/udev/src/udev-event.c | |||
@@ -0,0 +1,1011 @@ | |||
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 void rename_netif_kernel_log(struct ifreq ifr) | ||
788 | { | ||
789 | int klog; | ||
790 | FILE *f; | ||
791 | |||
792 | klog = open("/dev/kmsg", O_WRONLY); | ||
793 | if (klog < 0) | ||
794 | return; | ||
795 | |||
796 | f = fdopen(klog, "w"); | ||
797 | if (f == NULL) { | ||
798 | close(klog); | ||
799 | return; | ||
800 | } | ||
801 | |||
802 | fprintf(f, "<30>udevd[%u]: renamed network interface %s to %s\n", | ||
803 | getpid(), ifr.ifr_name, ifr.ifr_newname); | ||
804 | fclose(f); | ||
805 | } | ||
806 | |||
807 | static int rename_netif(struct udev_event *event) | ||
808 | { | ||
809 | struct udev_device *dev = event->dev; | ||
810 | int sk; | ||
811 | struct ifreq ifr; | ||
812 | int loop; | ||
813 | int err; | ||
814 | |||
815 | info(event->udev, "changing net interface name from '%s' to '%s'\n", | ||
816 | udev_device_get_sysname(dev), event->name); | ||
817 | |||
818 | sk = socket(PF_INET, SOCK_DGRAM, 0); | ||
819 | if (sk < 0) { | ||
820 | err = -errno; | ||
821 | err(event->udev, "error opening socket: %m\n"); | ||
822 | return err; | ||
823 | } | ||
824 | |||
825 | memset(&ifr, 0x00, sizeof(struct ifreq)); | ||
826 | util_strscpy(ifr.ifr_name, IFNAMSIZ, udev_device_get_sysname(dev)); | ||
827 | util_strscpy(ifr.ifr_newname, IFNAMSIZ, event->name); | ||
828 | err = ioctl(sk, SIOCSIFNAME, &ifr); | ||
829 | if (err == 0) { | ||
830 | rename_netif_kernel_log(ifr); | ||
831 | goto out; | ||
832 | } | ||
833 | |||
834 | /* keep trying if the destination interface name already exists */ | ||
835 | err = -errno; | ||
836 | if (err != -EEXIST) | ||
837 | goto out; | ||
838 | |||
839 | /* free our own name, another process may wait for us */ | ||
840 | snprintf(ifr.ifr_newname, IFNAMSIZ, "rename%u", udev_device_get_ifindex(dev)); | ||
841 | err = ioctl(sk, SIOCSIFNAME, &ifr); | ||
842 | if (err < 0) { | ||
843 | err = -errno; | ||
844 | goto out; | ||
845 | } | ||
846 | |||
847 | /* log temporary name */ | ||
848 | rename_netif_kernel_log(ifr); | ||
849 | |||
850 | /* wait a maximum of 90 seconds for our target to become available */ | ||
851 | util_strscpy(ifr.ifr_name, IFNAMSIZ, ifr.ifr_newname); | ||
852 | util_strscpy(ifr.ifr_newname, IFNAMSIZ, event->name); | ||
853 | loop = 90 * 20; | ||
854 | while (loop--) { | ||
855 | const struct timespec duration = { 0, 1000 * 1000 * 1000 / 20 }; | ||
856 | |||
857 | dbg(event->udev, "wait for netif '%s' to become free, loop=%i\n", | ||
858 | event->name, (90 * 20) - loop); | ||
859 | nanosleep(&duration, NULL); | ||
860 | |||
861 | err = ioctl(sk, SIOCSIFNAME, &ifr); | ||
862 | if (err == 0) { | ||
863 | rename_netif_kernel_log(ifr); | ||
864 | break; | ||
865 | } | ||
866 | err = -errno; | ||
867 | if (err != -EEXIST) | ||
868 | break; | ||
869 | } | ||
870 | |||
871 | out: | ||
872 | if (err < 0) | ||
873 | err(event->udev, "error changing net interface name %s to %s: %m\n", ifr.ifr_name, ifr.ifr_newname); | ||
874 | close(sk); | ||
875 | return err; | ||
876 | } | ||
877 | |||
878 | int udev_event_execute_rules(struct udev_event *event, struct udev_rules *rules, const sigset_t *sigmask) | ||
879 | { | ||
880 | struct udev_device *dev = event->dev; | ||
881 | int err = 0; | ||
882 | |||
883 | if (udev_device_get_subsystem(dev) == NULL) | ||
884 | return -1; | ||
885 | |||
886 | if (strcmp(udev_device_get_action(dev), "remove") == 0) { | ||
887 | udev_device_read_db(dev, NULL); | ||
888 | udev_device_delete_db(dev); | ||
889 | udev_device_tag_index(dev, NULL, false); | ||
890 | |||
891 | if (major(udev_device_get_devnum(dev)) != 0) | ||
892 | udev_watch_end(event->udev, dev); | ||
893 | |||
894 | udev_rules_apply_to_event(rules, event, sigmask); | ||
895 | |||
896 | if (major(udev_device_get_devnum(dev)) != 0) | ||
897 | udev_node_remove(dev); | ||
898 | } else { | ||
899 | event->dev_db = udev_device_new_from_syspath(event->udev, udev_device_get_syspath(dev)); | ||
900 | if (event->dev_db != NULL) { | ||
901 | udev_device_read_db(event->dev_db, NULL); | ||
902 | udev_device_set_info_loaded(event->dev_db); | ||
903 | |||
904 | /* disable watch during event processing */ | ||
905 | if (major(udev_device_get_devnum(dev)) != 0) | ||
906 | udev_watch_end(event->udev, event->dev_db); | ||
907 | } | ||
908 | |||
909 | udev_rules_apply_to_event(rules, event, sigmask); | ||
910 | |||
911 | /* rename a new network interface, if needed */ | ||
912 | if (udev_device_get_ifindex(dev) > 0 && strcmp(udev_device_get_action(dev), "add") == 0 && | ||
913 | event->name != NULL && strcmp(event->name, udev_device_get_sysname(dev)) != 0) { | ||
914 | char syspath[UTIL_PATH_SIZE]; | ||
915 | char *pos; | ||
916 | |||
917 | err = rename_netif(event); | ||
918 | if (err == 0) { | ||
919 | info(event->udev, "renamed netif to '%s'\n", event->name); | ||
920 | |||
921 | /* remember old name */ | ||
922 | udev_device_add_property(dev, "INTERFACE_OLD", udev_device_get_sysname(dev)); | ||
923 | |||
924 | /* now change the devpath, because the kernel device name has changed */ | ||
925 | util_strscpy(syspath, sizeof(syspath), udev_device_get_syspath(dev)); | ||
926 | pos = strrchr(syspath, '/'); | ||
927 | if (pos != NULL) { | ||
928 | pos++; | ||
929 | util_strscpy(pos, sizeof(syspath) - (pos - syspath), event->name); | ||
930 | udev_device_set_syspath(event->dev, syspath); | ||
931 | udev_device_add_property(dev, "INTERFACE", udev_device_get_sysname(dev)); | ||
932 | info(event->udev, "changed devpath to '%s'\n", udev_device_get_devpath(dev)); | ||
933 | } | ||
934 | } | ||
935 | } | ||
936 | |||
937 | if (major(udev_device_get_devnum(dev)) > 0) { | ||
938 | /* remove/update possible left-over symlinks from old database entry */ | ||
939 | if (event->dev_db != NULL) | ||
940 | udev_node_update_old_links(dev, event->dev_db); | ||
941 | |||
942 | if (!event->mode_set) { | ||
943 | if (udev_device_get_devnode_mode(dev) > 0) { | ||
944 | /* kernel supplied value */ | ||
945 | event->mode = udev_device_get_devnode_mode(dev); | ||
946 | } else if (event->gid > 0) { | ||
947 | /* default 0660 if a group is assigned */ | ||
948 | event->mode = 0660; | ||
949 | } else { | ||
950 | /* default 0600 */ | ||
951 | event->mode = 0600; | ||
952 | } | ||
953 | } | ||
954 | |||
955 | udev_node_add(dev, event->mode, event->uid, event->gid); | ||
956 | } | ||
957 | |||
958 | /* preserve old, or get new initialization timestamp */ | ||
959 | if (event->dev_db != NULL && udev_device_get_usec_initialized(event->dev_db) > 0) | ||
960 | udev_device_set_usec_initialized(event->dev, udev_device_get_usec_initialized(event->dev_db)); | ||
961 | else if (udev_device_get_usec_initialized(event->dev) == 0) | ||
962 | udev_device_set_usec_initialized(event->dev, now_usec()); | ||
963 | |||
964 | /* (re)write database file */ | ||
965 | udev_device_update_db(dev); | ||
966 | udev_device_tag_index(dev, event->dev_db, true); | ||
967 | udev_device_set_is_initialized(dev); | ||
968 | |||
969 | udev_device_unref(event->dev_db); | ||
970 | event->dev_db = NULL; | ||
971 | } | ||
972 | out: | ||
973 | return err; | ||
974 | } | ||
975 | |||
976 | int udev_event_execute_run(struct udev_event *event, const sigset_t *sigmask) | ||
977 | { | ||
978 | struct udev_list_entry *list_entry; | ||
979 | int err = 0; | ||
980 | |||
981 | dbg(event->udev, "executing run list\n"); | ||
982 | udev_list_entry_foreach(list_entry, udev_list_get_entry(&event->run_list)) { | ||
983 | const char *cmd = udev_list_entry_get_name(list_entry); | ||
984 | |||
985 | if (strncmp(cmd, "socket:", strlen("socket:")) == 0) { | ||
986 | struct udev_monitor *monitor; | ||
987 | |||
988 | monitor = udev_monitor_new_from_socket(event->udev, &cmd[strlen("socket:")]); | ||
989 | if (monitor == NULL) | ||
990 | continue; | ||
991 | udev_monitor_send_device(monitor, NULL, event->dev); | ||
992 | udev_monitor_unref(monitor); | ||
993 | } else { | ||
994 | char program[UTIL_PATH_SIZE]; | ||
995 | char **envp; | ||
996 | |||
997 | if (event->exec_delay > 0) { | ||
998 | info(event->udev, "delay execution of '%s'\n", program); | ||
999 | sleep(event->exec_delay); | ||
1000 | } | ||
1001 | |||
1002 | udev_event_apply_format(event, cmd, program, sizeof(program)); | ||
1003 | envp = udev_device_get_properties_envp(event->dev); | ||
1004 | if (udev_event_spawn(event, program, envp, sigmask, NULL, 0) < 0) { | ||
1005 | if (udev_list_entry_get_num(list_entry)) | ||
1006 | err = -1; | ||
1007 | } | ||
1008 | } | ||
1009 | } | ||
1010 | return err; | ||
1011 | } | ||
diff --git a/src/udev/src/udev-kernel.socket b/src/udev/src/udev-kernel.socket new file mode 100644 index 000000000..23fa9d5e1 --- /dev/null +++ b/src/udev/src/udev-kernel.socket | |||
@@ -0,0 +1,10 @@ | |||
1 | [Unit] | ||
2 | Description=udev Kernel Socket | ||
3 | DefaultDependencies=no | ||
4 | ConditionCapability=CAP_MKNOD | ||
5 | |||
6 | [Socket] | ||
7 | Service=udev.service | ||
8 | ReceiveBuffer=134217728 | ||
9 | ListenNetlink=kobject-uevent 1 | ||
10 | PassCredentials=yes | ||
diff --git a/src/udev/src/udev-node.c b/src/udev/src/udev-node.c new file mode 100644 index 000000000..7a01a479e --- /dev/null +++ b/src/udev/src/udev-node.c | |||
@@ -0,0 +1,379 @@ | |||
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_id_filename(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 | } | ||
diff --git a/src/udev/src/udev-rules.c b/src/udev/src/udev-rules.c new file mode 100644 index 000000000..8a85eae71 --- /dev/null +++ b/src/udev/src/udev-rules.c | |||
@@ -0,0 +1,2767 @@ | |||
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 | if (strncmp(value, "socket:", 7) == 0) | ||
1455 | err(rules->udev, "RUN+=\"socket:...\" support will be removed from a future udev release. " | ||
1456 | "Please remove it from: %s:%u and use libudev to subscribe to events.\n", filename, lineno); | ||
1457 | rule_add_key(&rule_tmp, TK_A_RUN, op, value, NULL); | ||
1458 | continue; | ||
1459 | } | ||
1460 | |||
1461 | if (strcmp(key, "WAIT_FOR") == 0 || strcmp(key, "WAIT_FOR_SYSFS") == 0) { | ||
1462 | rule_add_key(&rule_tmp, TK_M_WAITFOR, 0, value, NULL); | ||
1463 | continue; | ||
1464 | } | ||
1465 | |||
1466 | if (strcmp(key, "LABEL") == 0) { | ||
1467 | rule_tmp.rule.rule.label_off = add_string(rules, value); | ||
1468 | continue; | ||
1469 | } | ||
1470 | |||
1471 | if (strcmp(key, "GOTO") == 0) { | ||
1472 | rule_add_key(&rule_tmp, TK_A_GOTO, 0, value, NULL); | ||
1473 | continue; | ||
1474 | } | ||
1475 | |||
1476 | if (strncmp(key, "NAME", sizeof("NAME")-1) == 0) { | ||
1477 | if (op < OP_MATCH_MAX) { | ||
1478 | rule_add_key(&rule_tmp, TK_M_NAME, op, value, NULL); | ||
1479 | } else { | ||
1480 | if (strcmp(value, "%k") == 0) { | ||
1481 | err(rules->udev, "NAME=\"%%k\" is ignored, because it breaks kernel supplied names, " | ||
1482 | "please remove it from %s:%u\n", filename, lineno); | ||
1483 | continue; | ||
1484 | } | ||
1485 | if (value[0] == '\0') { | ||
1486 | info(rules->udev, "NAME=\"\" is ignored, because udev will not delete any device nodes, " | ||
1487 | "please remove it from %s:%u\n", filename, lineno); | ||
1488 | continue; | ||
1489 | } | ||
1490 | rule_add_key(&rule_tmp, TK_A_NAME, op, value, NULL); | ||
1491 | } | ||
1492 | rule_tmp.rule.rule.can_set_name = true; | ||
1493 | continue; | ||
1494 | } | ||
1495 | |||
1496 | if (strncmp(key, "SYMLINK", sizeof("SYMLINK")-1) == 0) { | ||
1497 | if (op < OP_MATCH_MAX) { | ||
1498 | rule_add_key(&rule_tmp, TK_M_DEVLINK, op, value, NULL); | ||
1499 | } else { | ||
1500 | int flag = 0; | ||
1501 | |||
1502 | attr = get_key_attribute(rules->udev, key + sizeof("SYMLINK")-1); | ||
1503 | if (attr != NULL && strstr(attr, "unique") != NULL) | ||
1504 | flag = 1; | ||
1505 | rule_add_key(&rule_tmp, TK_A_DEVLINK, op, value, &flag); | ||
1506 | } | ||
1507 | rule_tmp.rule.rule.can_set_name = true; | ||
1508 | continue; | ||
1509 | } | ||
1510 | |||
1511 | if (strcmp(key, "OWNER") == 0) { | ||
1512 | uid_t uid; | ||
1513 | char *endptr; | ||
1514 | |||
1515 | uid = strtoul(value, &endptr, 10); | ||
1516 | if (endptr[0] == '\0') { | ||
1517 | rule_add_key(&rule_tmp, TK_A_OWNER_ID, op, NULL, &uid); | ||
1518 | } else if ((rules->resolve_names > 0) && strchr("$%", value[0]) == NULL) { | ||
1519 | uid = add_uid(rules, value); | ||
1520 | rule_add_key(&rule_tmp, TK_A_OWNER_ID, op, NULL, &uid); | ||
1521 | } else if (rules->resolve_names >= 0) { | ||
1522 | rule_add_key(&rule_tmp, TK_A_OWNER, op, value, NULL); | ||
1523 | } | ||
1524 | rule_tmp.rule.rule.can_set_name = true; | ||
1525 | continue; | ||
1526 | } | ||
1527 | |||
1528 | if (strcmp(key, "GROUP") == 0) { | ||
1529 | gid_t gid; | ||
1530 | char *endptr; | ||
1531 | |||
1532 | gid = strtoul(value, &endptr, 10); | ||
1533 | if (endptr[0] == '\0') { | ||
1534 | rule_add_key(&rule_tmp, TK_A_GROUP_ID, op, NULL, &gid); | ||
1535 | } else if ((rules->resolve_names > 0) && strchr("$%", value[0]) == NULL) { | ||
1536 | gid = add_gid(rules, value); | ||
1537 | rule_add_key(&rule_tmp, TK_A_GROUP_ID, op, NULL, &gid); | ||
1538 | } else if (rules->resolve_names >= 0) { | ||
1539 | rule_add_key(&rule_tmp, TK_A_GROUP, op, value, NULL); | ||
1540 | } | ||
1541 | rule_tmp.rule.rule.can_set_name = true; | ||
1542 | continue; | ||
1543 | } | ||
1544 | |||
1545 | if (strcmp(key, "MODE") == 0) { | ||
1546 | mode_t mode; | ||
1547 | char *endptr; | ||
1548 | |||
1549 | mode = strtol(value, &endptr, 8); | ||
1550 | if (endptr[0] == '\0') | ||
1551 | rule_add_key(&rule_tmp, TK_A_MODE_ID, op, NULL, &mode); | ||
1552 | else | ||
1553 | rule_add_key(&rule_tmp, TK_A_MODE, op, value, NULL); | ||
1554 | rule_tmp.rule.rule.can_set_name = true; | ||
1555 | continue; | ||
1556 | } | ||
1557 | |||
1558 | if (strcmp(key, "OPTIONS") == 0) { | ||
1559 | const char *pos; | ||
1560 | |||
1561 | pos = strstr(value, "link_priority="); | ||
1562 | if (pos != NULL) { | ||
1563 | int prio = atoi(&pos[strlen("link_priority=")]); | ||
1564 | |||
1565 | rule_add_key(&rule_tmp, TK_A_DEVLINK_PRIO, op, NULL, &prio); | ||
1566 | dbg(rules->udev, "link priority=%i\n", prio); | ||
1567 | } | ||
1568 | |||
1569 | pos = strstr(value, "event_timeout="); | ||
1570 | if (pos != NULL) { | ||
1571 | int tout = atoi(&pos[strlen("event_timeout=")]); | ||
1572 | |||
1573 | rule_add_key(&rule_tmp, TK_M_EVENT_TIMEOUT, op, NULL, &tout); | ||
1574 | dbg(rules->udev, "event timeout=%i\n", tout); | ||
1575 | } | ||
1576 | |||
1577 | pos = strstr(value, "string_escape="); | ||
1578 | if (pos != NULL) { | ||
1579 | pos = &pos[strlen("string_escape=")]; | ||
1580 | if (strncmp(pos, "none", strlen("none")) == 0) | ||
1581 | rule_add_key(&rule_tmp, TK_A_STRING_ESCAPE_NONE, op, NULL, NULL); | ||
1582 | else if (strncmp(pos, "replace", strlen("replace")) == 0) | ||
1583 | rule_add_key(&rule_tmp, TK_A_STRING_ESCAPE_REPLACE, op, NULL, NULL); | ||
1584 | } | ||
1585 | |||
1586 | pos = strstr(value, "db_persist"); | ||
1587 | if (pos != NULL) | ||
1588 | rule_add_key(&rule_tmp, TK_A_DB_PERSIST, op, NULL, NULL); | ||
1589 | |||
1590 | pos = strstr(value, "nowatch"); | ||
1591 | if (pos != NULL) { | ||
1592 | const int off = 0; | ||
1593 | |||
1594 | rule_add_key(&rule_tmp, TK_A_INOTIFY_WATCH, op, NULL, &off); | ||
1595 | dbg(rules->udev, "inotify watch of device disabled\n"); | ||
1596 | } else { | ||
1597 | pos = strstr(value, "watch"); | ||
1598 | if (pos != NULL) { | ||
1599 | const int on = 1; | ||
1600 | |||
1601 | rule_add_key(&rule_tmp, TK_A_INOTIFY_WATCH, op, NULL, &on); | ||
1602 | dbg(rules->udev, "inotify watch of device requested\n"); | ||
1603 | } | ||
1604 | } | ||
1605 | |||
1606 | pos = strstr(value, "static_node="); | ||
1607 | if (pos != NULL) { | ||
1608 | rule_add_key(&rule_tmp, TK_A_STATIC_NODE, op, &pos[strlen("static_node=")], NULL); | ||
1609 | rule_tmp.rule.rule.has_static_node = true; | ||
1610 | } | ||
1611 | |||
1612 | continue; | ||
1613 | } | ||
1614 | |||
1615 | err(rules->udev, "unknown key '%s' in %s:%u\n", key, filename, lineno); | ||
1616 | goto invalid; | ||
1617 | } | ||
1618 | |||
1619 | /* add rule token */ | ||
1620 | rule_tmp.rule.rule.token_count = 1 + rule_tmp.token_cur; | ||
1621 | if (add_token(rules, &rule_tmp.rule) != 0) | ||
1622 | goto invalid; | ||
1623 | |||
1624 | /* add tokens to list, sorted by type */ | ||
1625 | if (sort_token(rules, &rule_tmp) != 0) | ||
1626 | goto invalid; | ||
1627 | |||
1628 | return 0; | ||
1629 | invalid: | ||
1630 | err(rules->udev, "invalid rule '%s:%u'\n", filename, lineno); | ||
1631 | return -1; | ||
1632 | } | ||
1633 | |||
1634 | static int parse_file(struct udev_rules *rules, const char *filename, unsigned short filename_off) | ||
1635 | { | ||
1636 | FILE *f; | ||
1637 | unsigned int first_token; | ||
1638 | char line[UTIL_LINE_SIZE]; | ||
1639 | int line_nr = 0; | ||
1640 | unsigned int i; | ||
1641 | |||
1642 | info(rules->udev, "reading '%s' as rules file\n", filename); | ||
1643 | |||
1644 | f = fopen(filename, "r"); | ||
1645 | if (f == NULL) | ||
1646 | return -1; | ||
1647 | |||
1648 | first_token = rules->token_cur; | ||
1649 | |||
1650 | while (fgets(line, sizeof(line), f) != NULL) { | ||
1651 | char *key; | ||
1652 | size_t len; | ||
1653 | |||
1654 | /* skip whitespace */ | ||
1655 | line_nr++; | ||
1656 | key = line; | ||
1657 | while (isspace(key[0])) | ||
1658 | key++; | ||
1659 | |||
1660 | /* comment */ | ||
1661 | if (key[0] == '#') | ||
1662 | continue; | ||
1663 | |||
1664 | len = strlen(line); | ||
1665 | if (len < 3) | ||
1666 | continue; | ||
1667 | |||
1668 | /* continue reading if backslash+newline is found */ | ||
1669 | while (line[len-2] == '\\') { | ||
1670 | if (fgets(&line[len-2], (sizeof(line)-len)+2, f) == NULL) | ||
1671 | break; | ||
1672 | if (strlen(&line[len-2]) < 2) | ||
1673 | break; | ||
1674 | line_nr++; | ||
1675 | len = strlen(line); | ||
1676 | } | ||
1677 | |||
1678 | if (len+1 >= sizeof(line)) { | ||
1679 | err(rules->udev, "line too long '%s':%u, ignored\n", filename, line_nr); | ||
1680 | continue; | ||
1681 | } | ||
1682 | add_rule(rules, key, filename, filename_off, line_nr); | ||
1683 | } | ||
1684 | fclose(f); | ||
1685 | |||
1686 | /* link GOTOs to LABEL rules in this file to be able to fast-forward */ | ||
1687 | for (i = first_token+1; i < rules->token_cur; i++) { | ||
1688 | if (rules->tokens[i].type == TK_A_GOTO) { | ||
1689 | char *label = &rules->buf[rules->tokens[i].key.value_off]; | ||
1690 | unsigned int j; | ||
1691 | |||
1692 | for (j = i+1; j < rules->token_cur; j++) { | ||
1693 | if (rules->tokens[j].type != TK_RULE) | ||
1694 | continue; | ||
1695 | if (rules->tokens[j].rule.label_off == 0) | ||
1696 | continue; | ||
1697 | if (strcmp(label, &rules->buf[rules->tokens[j].rule.label_off]) != 0) | ||
1698 | continue; | ||
1699 | rules->tokens[i].key.rule_goto = j; | ||
1700 | break; | ||
1701 | } | ||
1702 | if (rules->tokens[i].key.rule_goto == 0) | ||
1703 | err(rules->udev, "GOTO '%s' has no matching label in: '%s'\n", label, filename); | ||
1704 | } | ||
1705 | } | ||
1706 | return 0; | ||
1707 | } | ||
1708 | |||
1709 | static int add_matching_files(struct udev *udev, struct udev_list *file_list, const char *dirname, const char *suffix) | ||
1710 | { | ||
1711 | DIR *dir; | ||
1712 | struct dirent *dent; | ||
1713 | char filename[UTIL_PATH_SIZE]; | ||
1714 | |||
1715 | dbg(udev, "open directory '%s'\n", dirname); | ||
1716 | dir = opendir(dirname); | ||
1717 | if (dir == NULL) { | ||
1718 | info(udev, "unable to open '%s': %m\n", dirname); | ||
1719 | return -1; | ||
1720 | } | ||
1721 | |||
1722 | for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) { | ||
1723 | if (dent->d_name[0] == '.') | ||
1724 | continue; | ||
1725 | |||
1726 | /* look for file matching with specified suffix */ | ||
1727 | if (suffix != NULL) { | ||
1728 | const char *ext; | ||
1729 | |||
1730 | ext = strrchr(dent->d_name, '.'); | ||
1731 | if (ext == NULL) | ||
1732 | continue; | ||
1733 | if (strcmp(ext, suffix) != 0) | ||
1734 | continue; | ||
1735 | } | ||
1736 | util_strscpyl(filename, sizeof(filename), dirname, "/", dent->d_name, NULL); | ||
1737 | dbg(udev, "put file '%s' into list\n", filename); | ||
1738 | /* | ||
1739 | * the basename is the key, the filename the value | ||
1740 | * identical basenames from different directories override each other | ||
1741 | * entries are sorted after basename | ||
1742 | */ | ||
1743 | udev_list_entry_add(file_list, dent->d_name, filename); | ||
1744 | } | ||
1745 | |||
1746 | closedir(dir); | ||
1747 | return 0; | ||
1748 | } | ||
1749 | |||
1750 | struct udev_rules *udev_rules_new(struct udev *udev, int resolve_names) | ||
1751 | { | ||
1752 | struct udev_rules *rules; | ||
1753 | struct udev_list file_list; | ||
1754 | struct udev_list_entry *file_loop; | ||
1755 | struct token end_token; | ||
1756 | char **s; | ||
1757 | |||
1758 | rules = calloc(1, sizeof(struct udev_rules)); | ||
1759 | if (rules == NULL) | ||
1760 | return NULL; | ||
1761 | rules->udev = udev; | ||
1762 | rules->resolve_names = resolve_names; | ||
1763 | udev_list_init(udev, &file_list, true); | ||
1764 | |||
1765 | /* init token array and string buffer */ | ||
1766 | rules->tokens = malloc(PREALLOC_TOKEN * sizeof(struct token)); | ||
1767 | if (rules->tokens == NULL) { | ||
1768 | free(rules); | ||
1769 | return NULL; | ||
1770 | } | ||
1771 | rules->token_max = PREALLOC_TOKEN; | ||
1772 | |||
1773 | rules->buf = malloc(PREALLOC_STRBUF); | ||
1774 | if (rules->buf == NULL) { | ||
1775 | free(rules->tokens); | ||
1776 | free(rules); | ||
1777 | return NULL; | ||
1778 | } | ||
1779 | rules->buf_max = PREALLOC_STRBUF; | ||
1780 | /* offset 0 is always '\0' */ | ||
1781 | rules->buf[0] = '\0'; | ||
1782 | rules->buf_cur = 1; | ||
1783 | dbg(udev, "prealloc %zu bytes tokens (%u * %zu bytes), %zu bytes buffer\n", | ||
1784 | rules->token_max * sizeof(struct token), rules->token_max, sizeof(struct token), rules->buf_max); | ||
1785 | |||
1786 | rules->trie_nodes = malloc(PREALLOC_TRIE * sizeof(struct trie_node)); | ||
1787 | if (rules->trie_nodes == NULL) { | ||
1788 | free(rules->buf); | ||
1789 | free(rules->tokens); | ||
1790 | free(rules); | ||
1791 | return NULL; | ||
1792 | } | ||
1793 | rules->trie_nodes_max = PREALLOC_TRIE; | ||
1794 | /* offset 0 is the trie root, with an empty string */ | ||
1795 | memset(rules->trie_nodes, 0x00, sizeof(struct trie_node)); | ||
1796 | rules->trie_nodes_cur = 1; | ||
1797 | |||
1798 | for (udev_get_rules_path(udev, &s, NULL); *s != NULL; s++) | ||
1799 | add_matching_files(udev, &file_list, *s, ".rules"); | ||
1800 | |||
1801 | /* add all filenames to the string buffer */ | ||
1802 | udev_list_entry_foreach(file_loop, udev_list_get_entry(&file_list)) { | ||
1803 | const char *filename = udev_list_entry_get_value(file_loop); | ||
1804 | unsigned int filename_off; | ||
1805 | |||
1806 | filename_off = add_string(rules, filename); | ||
1807 | /* the offset in the rule is limited to unsigned short */ | ||
1808 | if (filename_off < USHRT_MAX) | ||
1809 | udev_list_entry_set_num(file_loop, filename_off); | ||
1810 | } | ||
1811 | |||
1812 | /* parse all rules files */ | ||
1813 | udev_list_entry_foreach(file_loop, udev_list_get_entry(&file_list)) { | ||
1814 | const char *filename = udev_list_entry_get_value(file_loop); | ||
1815 | unsigned int filename_off = udev_list_entry_get_num(file_loop); | ||
1816 | struct stat st; | ||
1817 | |||
1818 | if (stat(filename, &st) != 0) { | ||
1819 | err(udev, "can not find '%s': %m\n", filename); | ||
1820 | continue; | ||
1821 | } | ||
1822 | if (S_ISREG(st.st_mode) && st.st_size <= 0) { | ||
1823 | info(udev, "ignore empty '%s'\n", filename); | ||
1824 | continue; | ||
1825 | } | ||
1826 | if (S_ISCHR(st.st_mode)) { | ||
1827 | info(udev, "ignore masked '%s'\n", filename); | ||
1828 | continue; | ||
1829 | } | ||
1830 | parse_file(rules, filename, filename_off); | ||
1831 | } | ||
1832 | udev_list_cleanup(&file_list); | ||
1833 | |||
1834 | memset(&end_token, 0x00, sizeof(struct token)); | ||
1835 | end_token.type = TK_END; | ||
1836 | add_token(rules, &end_token); | ||
1837 | |||
1838 | /* shrink allocated token and string buffer */ | ||
1839 | if (rules->token_cur < rules->token_max) { | ||
1840 | struct token *tokens; | ||
1841 | |||
1842 | tokens = realloc(rules->tokens, rules->token_cur * sizeof(struct token)); | ||
1843 | if (tokens != NULL || rules->token_cur == 0) { | ||
1844 | rules->tokens = tokens; | ||
1845 | rules->token_max = rules->token_cur; | ||
1846 | } | ||
1847 | } | ||
1848 | if (rules->buf_cur < rules->buf_max) { | ||
1849 | char *buf; | ||
1850 | |||
1851 | buf = realloc(rules->buf, rules->buf_cur); | ||
1852 | if (buf != NULL || rules->buf_cur == 0) { | ||
1853 | rules->buf = buf; | ||
1854 | rules->buf_max = rules->buf_cur; | ||
1855 | } | ||
1856 | } | ||
1857 | info(udev, "rules use %zu bytes tokens (%u * %zu bytes), %zu bytes buffer\n", | ||
1858 | rules->token_max * sizeof(struct token), rules->token_max, sizeof(struct token), rules->buf_max); | ||
1859 | info(udev, "temporary index used %zu bytes (%u * %zu bytes)\n", | ||
1860 | rules->trie_nodes_cur * sizeof(struct trie_node), | ||
1861 | rules->trie_nodes_cur, sizeof(struct trie_node)); | ||
1862 | |||
1863 | /* cleanup trie */ | ||
1864 | free(rules->trie_nodes); | ||
1865 | rules->trie_nodes = NULL; | ||
1866 | rules->trie_nodes_cur = 0; | ||
1867 | rules->trie_nodes_max = 0; | ||
1868 | |||
1869 | /* cleanup uid/gid cache */ | ||
1870 | free(rules->uids); | ||
1871 | rules->uids = NULL; | ||
1872 | rules->uids_cur = 0; | ||
1873 | rules->uids_max = 0; | ||
1874 | free(rules->gids); | ||
1875 | rules->gids = NULL; | ||
1876 | rules->gids_cur = 0; | ||
1877 | rules->gids_max = 0; | ||
1878 | |||
1879 | dump_rules(rules); | ||
1880 | return rules; | ||
1881 | } | ||
1882 | |||
1883 | struct udev_rules *udev_rules_unref(struct udev_rules *rules) | ||
1884 | { | ||
1885 | if (rules == NULL) | ||
1886 | return NULL; | ||
1887 | free(rules->tokens); | ||
1888 | free(rules->buf); | ||
1889 | free(rules->trie_nodes); | ||
1890 | free(rules->uids); | ||
1891 | free(rules->gids); | ||
1892 | free(rules); | ||
1893 | return NULL; | ||
1894 | } | ||
1895 | |||
1896 | static int match_key(struct udev_rules *rules, struct token *token, const char *val) | ||
1897 | { | ||
1898 | char *key_value = &rules->buf[token->key.value_off]; | ||
1899 | char *pos; | ||
1900 | bool match = false; | ||
1901 | |||
1902 | if (val == NULL) | ||
1903 | val = ""; | ||
1904 | |||
1905 | switch (token->key.glob) { | ||
1906 | case GL_PLAIN: | ||
1907 | match = (strcmp(key_value, val) == 0); | ||
1908 | break; | ||
1909 | case GL_GLOB: | ||
1910 | match = (fnmatch(key_value, val, 0) == 0); | ||
1911 | break; | ||
1912 | case GL_SPLIT: | ||
1913 | { | ||
1914 | const char *split; | ||
1915 | size_t len; | ||
1916 | |||
1917 | split = &rules->buf[token->key.value_off]; | ||
1918 | len = strlen(val); | ||
1919 | for (;;) { | ||
1920 | const char *next; | ||
1921 | |||
1922 | next = strchr(split, '|'); | ||
1923 | if (next != NULL) { | ||
1924 | size_t matchlen = (size_t)(next - split); | ||
1925 | |||
1926 | match = (matchlen == len && strncmp(split, val, matchlen) == 0); | ||
1927 | if (match) | ||
1928 | break; | ||
1929 | } else { | ||
1930 | match = (strcmp(split, val) == 0); | ||
1931 | break; | ||
1932 | } | ||
1933 | split = &next[1]; | ||
1934 | } | ||
1935 | break; | ||
1936 | } | ||
1937 | case GL_SPLIT_GLOB: | ||
1938 | { | ||
1939 | char value[UTIL_PATH_SIZE]; | ||
1940 | |||
1941 | util_strscpy(value, sizeof(value), &rules->buf[token->key.value_off]); | ||
1942 | key_value = value; | ||
1943 | while (key_value != NULL) { | ||
1944 | pos = strchr(key_value, '|'); | ||
1945 | if (pos != NULL) { | ||
1946 | pos[0] = '\0'; | ||
1947 | pos = &pos[1]; | ||
1948 | } | ||
1949 | dbg(rules->udev, "match %s '%s' <-> '%s'\n", token_str(token->type), key_value, val); | ||
1950 | match = (fnmatch(key_value, val, 0) == 0); | ||
1951 | if (match) | ||
1952 | break; | ||
1953 | key_value = pos; | ||
1954 | } | ||
1955 | break; | ||
1956 | } | ||
1957 | case GL_SOMETHING: | ||
1958 | match = (val[0] != '\0'); | ||
1959 | break; | ||
1960 | case GL_UNSET: | ||
1961 | return -1; | ||
1962 | } | ||
1963 | |||
1964 | if (match && (token->key.op == OP_MATCH)) { | ||
1965 | dbg(rules->udev, "%s is true (matching value)\n", token_str(token->type)); | ||
1966 | return 0; | ||
1967 | } | ||
1968 | if (!match && (token->key.op == OP_NOMATCH)) { | ||
1969 | dbg(rules->udev, "%s is true (non-matching value)\n", token_str(token->type)); | ||
1970 | return 0; | ||
1971 | } | ||
1972 | dbg(rules->udev, "%s is not true\n", token_str(token->type)); | ||
1973 | return -1; | ||
1974 | } | ||
1975 | |||
1976 | static int match_attr(struct udev_rules *rules, struct udev_device *dev, struct udev_event *event, struct token *cur) | ||
1977 | { | ||
1978 | const char *name; | ||
1979 | char nbuf[UTIL_NAME_SIZE]; | ||
1980 | const char *value; | ||
1981 | char vbuf[UTIL_NAME_SIZE]; | ||
1982 | size_t len; | ||
1983 | |||
1984 | name = &rules->buf[cur->key.attr_off]; | ||
1985 | switch (cur->key.attrsubst) { | ||
1986 | case SB_FORMAT: | ||
1987 | udev_event_apply_format(event, name, nbuf, sizeof(nbuf)); | ||
1988 | name = nbuf; | ||
1989 | /* fall through */ | ||
1990 | case SB_NONE: | ||
1991 | value = udev_device_get_sysattr_value(dev, name); | ||
1992 | if (value == NULL) | ||
1993 | return -1; | ||
1994 | break; | ||
1995 | case SB_SUBSYS: | ||
1996 | if (util_resolve_subsys_kernel(event->udev, name, vbuf, sizeof(vbuf), 1) != 0) | ||
1997 | return -1; | ||
1998 | value = vbuf; | ||
1999 | break; | ||
2000 | default: | ||
2001 | return -1; | ||
2002 | } | ||
2003 | |||
2004 | /* remove trailing whitespace, if not asked to match for it */ | ||
2005 | len = strlen(value); | ||
2006 | if (len > 0 && isspace(value[len-1])) { | ||
2007 | const char *key_value; | ||
2008 | size_t klen; | ||
2009 | |||
2010 | key_value = &rules->buf[cur->key.value_off]; | ||
2011 | klen = strlen(key_value); | ||
2012 | if (klen > 0 && !isspace(key_value[klen-1])) { | ||
2013 | if (value != vbuf) { | ||
2014 | util_strscpy(vbuf, sizeof(vbuf), value); | ||
2015 | value = vbuf; | ||
2016 | } | ||
2017 | while (len > 0 && isspace(vbuf[--len])) | ||
2018 | vbuf[len] = '\0'; | ||
2019 | dbg(rules->udev, "removed trailing whitespace from '%s'\n", value); | ||
2020 | } | ||
2021 | } | ||
2022 | |||
2023 | return match_key(rules, cur, value); | ||
2024 | } | ||
2025 | |||
2026 | enum escape_type { | ||
2027 | ESCAPE_UNSET, | ||
2028 | ESCAPE_NONE, | ||
2029 | ESCAPE_REPLACE, | ||
2030 | }; | ||
2031 | |||
2032 | int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event, const sigset_t *sigmask) | ||
2033 | { | ||
2034 | struct token *cur; | ||
2035 | struct token *rule; | ||
2036 | enum escape_type esc = ESCAPE_UNSET; | ||
2037 | bool can_set_name; | ||
2038 | |||
2039 | if (rules->tokens == NULL) | ||
2040 | return -1; | ||
2041 | |||
2042 | can_set_name = ((strcmp(udev_device_get_action(event->dev), "remove") != 0) && | ||
2043 | (major(udev_device_get_devnum(event->dev)) > 0 || | ||
2044 | udev_device_get_ifindex(event->dev) > 0)); | ||
2045 | |||
2046 | /* loop through token list, match, run actions or forward to next rule */ | ||
2047 | cur = &rules->tokens[0]; | ||
2048 | rule = cur; | ||
2049 | for (;;) { | ||
2050 | dump_token(rules, cur); | ||
2051 | switch (cur->type) { | ||
2052 | case TK_RULE: | ||
2053 | /* current rule */ | ||
2054 | rule = cur; | ||
2055 | /* possibly skip rules which want to set NAME, SYMLINK, OWNER, GROUP, MODE */ | ||
2056 | if (!can_set_name && rule->rule.can_set_name) | ||
2057 | goto nomatch; | ||
2058 | esc = ESCAPE_UNSET; | ||
2059 | break; | ||
2060 | case TK_M_ACTION: | ||
2061 | if (match_key(rules, cur, udev_device_get_action(event->dev)) != 0) | ||
2062 | goto nomatch; | ||
2063 | break; | ||
2064 | case TK_M_DEVPATH: | ||
2065 | if (match_key(rules, cur, udev_device_get_devpath(event->dev)) != 0) | ||
2066 | goto nomatch; | ||
2067 | break; | ||
2068 | case TK_M_KERNEL: | ||
2069 | if (match_key(rules, cur, udev_device_get_sysname(event->dev)) != 0) | ||
2070 | goto nomatch; | ||
2071 | break; | ||
2072 | case TK_M_DEVLINK: { | ||
2073 | size_t devlen = strlen(udev_get_dev_path(event->udev))+1; | ||
2074 | struct udev_list_entry *list_entry; | ||
2075 | bool match = false; | ||
2076 | |||
2077 | udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(event->dev)) { | ||
2078 | const char *devlink; | ||
2079 | |||
2080 | devlink = &udev_list_entry_get_name(list_entry)[devlen]; | ||
2081 | if (match_key(rules, cur, devlink) == 0) { | ||
2082 | match = true; | ||
2083 | break; | ||
2084 | } | ||
2085 | } | ||
2086 | if (!match) | ||
2087 | goto nomatch; | ||
2088 | break; | ||
2089 | } | ||
2090 | case TK_M_NAME: | ||
2091 | if (match_key(rules, cur, event->name) != 0) | ||
2092 | goto nomatch; | ||
2093 | break; | ||
2094 | case TK_M_ENV: { | ||
2095 | const char *key_name = &rules->buf[cur->key.attr_off]; | ||
2096 | const char *value; | ||
2097 | |||
2098 | value = udev_device_get_property_value(event->dev, key_name); | ||
2099 | if (value == NULL) { | ||
2100 | dbg(event->udev, "ENV{%s} is not set, treat as empty\n", key_name); | ||
2101 | value = ""; | ||
2102 | } | ||
2103 | if (match_key(rules, cur, value)) | ||
2104 | goto nomatch; | ||
2105 | break; | ||
2106 | } | ||
2107 | case TK_M_TAG: { | ||
2108 | struct udev_list_entry *list_entry; | ||
2109 | bool match = false; | ||
2110 | |||
2111 | udev_list_entry_foreach(list_entry, udev_device_get_tags_list_entry(event->dev)) { | ||
2112 | if (strcmp(&rules->buf[cur->key.value_off], udev_list_entry_get_name(list_entry)) == 0) { | ||
2113 | match = true; | ||
2114 | break; | ||
2115 | } | ||
2116 | } | ||
2117 | if (!match && (cur->key.op != OP_NOMATCH)) | ||
2118 | goto nomatch; | ||
2119 | break; | ||
2120 | } | ||
2121 | case TK_M_SUBSYSTEM: | ||
2122 | if (match_key(rules, cur, udev_device_get_subsystem(event->dev)) != 0) | ||
2123 | goto nomatch; | ||
2124 | break; | ||
2125 | case TK_M_DRIVER: | ||
2126 | if (match_key(rules, cur, udev_device_get_driver(event->dev)) != 0) | ||
2127 | goto nomatch; | ||
2128 | break; | ||
2129 | case TK_M_WAITFOR: { | ||
2130 | char filename[UTIL_PATH_SIZE]; | ||
2131 | int found; | ||
2132 | |||
2133 | udev_event_apply_format(event, &rules->buf[cur->key.value_off], filename, sizeof(filename)); | ||
2134 | found = (wait_for_file(event->dev, filename, 10) == 0); | ||
2135 | if (!found && (cur->key.op != OP_NOMATCH)) | ||
2136 | goto nomatch; | ||
2137 | break; | ||
2138 | } | ||
2139 | case TK_M_ATTR: | ||
2140 | if (match_attr(rules, event->dev, event, cur) != 0) | ||
2141 | goto nomatch; | ||
2142 | break; | ||
2143 | case TK_M_KERNELS: | ||
2144 | case TK_M_SUBSYSTEMS: | ||
2145 | case TK_M_DRIVERS: | ||
2146 | case TK_M_ATTRS: | ||
2147 | case TK_M_TAGS: { | ||
2148 | struct token *next; | ||
2149 | |||
2150 | /* get whole sequence of parent matches */ | ||
2151 | next = cur; | ||
2152 | while (next->type > TK_M_PARENTS_MIN && next->type < TK_M_PARENTS_MAX) | ||
2153 | next++; | ||
2154 | |||
2155 | /* loop over parents */ | ||
2156 | event->dev_parent = event->dev; | ||
2157 | for (;;) { | ||
2158 | struct token *key; | ||
2159 | |||
2160 | dbg(event->udev, "parent: '%s'\n", udev_device_get_syspath(event->dev_parent)); | ||
2161 | /* loop over sequence of parent match keys */ | ||
2162 | for (key = cur; key < next; key++ ) { | ||
2163 | dump_token(rules, key); | ||
2164 | switch(key->type) { | ||
2165 | case TK_M_KERNELS: | ||
2166 | if (match_key(rules, key, udev_device_get_sysname(event->dev_parent)) != 0) | ||
2167 | goto try_parent; | ||
2168 | break; | ||
2169 | case TK_M_SUBSYSTEMS: | ||
2170 | if (match_key(rules, key, udev_device_get_subsystem(event->dev_parent)) != 0) | ||
2171 | goto try_parent; | ||
2172 | break; | ||
2173 | case TK_M_DRIVERS: | ||
2174 | if (match_key(rules, key, udev_device_get_driver(event->dev_parent)) != 0) | ||
2175 | goto try_parent; | ||
2176 | break; | ||
2177 | case TK_M_ATTRS: | ||
2178 | if (match_attr(rules, event->dev_parent, event, key) != 0) | ||
2179 | goto try_parent; | ||
2180 | break; | ||
2181 | case TK_M_TAGS: { | ||
2182 | bool match = udev_device_has_tag(event->dev_parent, &rules->buf[cur->key.value_off]); | ||
2183 | |||
2184 | if (match && key->key.op == OP_NOMATCH) | ||
2185 | goto try_parent; | ||
2186 | if (!match && key->key.op == OP_MATCH) | ||
2187 | goto try_parent; | ||
2188 | break; | ||
2189 | } | ||
2190 | default: | ||
2191 | goto nomatch; | ||
2192 | } | ||
2193 | dbg(event->udev, "parent key matched\n"); | ||
2194 | } | ||
2195 | dbg(event->udev, "all parent keys matched\n"); | ||
2196 | break; | ||
2197 | |||
2198 | try_parent: | ||
2199 | event->dev_parent = udev_device_get_parent(event->dev_parent); | ||
2200 | if (event->dev_parent == NULL) | ||
2201 | goto nomatch; | ||
2202 | } | ||
2203 | /* move behind our sequence of parent match keys */ | ||
2204 | cur = next; | ||
2205 | continue; | ||
2206 | } | ||
2207 | case TK_M_TEST: { | ||
2208 | char filename[UTIL_PATH_SIZE]; | ||
2209 | struct stat statbuf; | ||
2210 | int match; | ||
2211 | |||
2212 | udev_event_apply_format(event, &rules->buf[cur->key.value_off], filename, sizeof(filename)); | ||
2213 | if (util_resolve_subsys_kernel(event->udev, filename, filename, sizeof(filename), 0) != 0) { | ||
2214 | if (filename[0] != '/') { | ||
2215 | char tmp[UTIL_PATH_SIZE]; | ||
2216 | |||
2217 | util_strscpy(tmp, sizeof(tmp), filename); | ||
2218 | util_strscpyl(filename, sizeof(filename), | ||
2219 | udev_device_get_syspath(event->dev), "/", tmp, NULL); | ||
2220 | } | ||
2221 | } | ||
2222 | attr_subst_subdir(filename, sizeof(filename)); | ||
2223 | |||
2224 | match = (stat(filename, &statbuf) == 0); | ||
2225 | dbg(event->udev, "'%s' %s", filename, match ? "exists\n" : "does not exist\n"); | ||
2226 | if (match && cur->key.mode > 0) { | ||
2227 | match = ((statbuf.st_mode & cur->key.mode) > 0); | ||
2228 | dbg(event->udev, "'%s' has mode=%#o and %s %#o\n", filename, statbuf.st_mode, | ||
2229 | match ? "matches" : "does not match", cur->key.mode); | ||
2230 | } | ||
2231 | if (match && cur->key.op == OP_NOMATCH) | ||
2232 | goto nomatch; | ||
2233 | if (!match && cur->key.op == OP_MATCH) | ||
2234 | goto nomatch; | ||
2235 | break; | ||
2236 | } | ||
2237 | case TK_M_EVENT_TIMEOUT: | ||
2238 | info(event->udev, "OPTIONS event_timeout=%u\n", cur->key.event_timeout); | ||
2239 | event->timeout_usec = cur->key.event_timeout * 1000 * 1000; | ||
2240 | break; | ||
2241 | case TK_M_PROGRAM: { | ||
2242 | char program[UTIL_PATH_SIZE]; | ||
2243 | char **envp; | ||
2244 | char result[UTIL_PATH_SIZE]; | ||
2245 | |||
2246 | free(event->program_result); | ||
2247 | event->program_result = NULL; | ||
2248 | udev_event_apply_format(event, &rules->buf[cur->key.value_off], program, sizeof(program)); | ||
2249 | envp = udev_device_get_properties_envp(event->dev); | ||
2250 | info(event->udev, "PROGRAM '%s' %s:%u\n", | ||
2251 | program, | ||
2252 | &rules->buf[rule->rule.filename_off], | ||
2253 | rule->rule.filename_line); | ||
2254 | |||
2255 | if (udev_event_spawn(event, program, envp, sigmask, result, sizeof(result)) < 0) { | ||
2256 | if (cur->key.op != OP_NOMATCH) | ||
2257 | goto nomatch; | ||
2258 | } else { | ||
2259 | int count; | ||
2260 | |||
2261 | util_remove_trailing_chars(result, '\n'); | ||
2262 | if (esc == ESCAPE_UNSET || esc == ESCAPE_REPLACE) { | ||
2263 | count = util_replace_chars(result, UDEV_ALLOWED_CHARS_INPUT); | ||
2264 | if (count > 0) | ||
2265 | info(event->udev, "%i character(s) replaced\n" , count); | ||
2266 | } | ||
2267 | event->program_result = strdup(result); | ||
2268 | dbg(event->udev, "storing result '%s'\n", event->program_result); | ||
2269 | if (cur->key.op == OP_NOMATCH) | ||
2270 | goto nomatch; | ||
2271 | } | ||
2272 | break; | ||
2273 | } | ||
2274 | case TK_M_IMPORT_FILE: { | ||
2275 | char import[UTIL_PATH_SIZE]; | ||
2276 | |||
2277 | udev_event_apply_format(event, &rules->buf[cur->key.value_off], import, sizeof(import)); | ||
2278 | if (import_file_into_properties(event->dev, import) != 0) | ||
2279 | if (cur->key.op != OP_NOMATCH) | ||
2280 | goto nomatch; | ||
2281 | break; | ||
2282 | } | ||
2283 | case TK_M_IMPORT_PROG: { | ||
2284 | char import[UTIL_PATH_SIZE]; | ||
2285 | |||
2286 | udev_event_apply_format(event, &rules->buf[cur->key.value_off], import, sizeof(import)); | ||
2287 | info(event->udev, "IMPORT '%s' %s:%u\n", | ||
2288 | import, | ||
2289 | &rules->buf[rule->rule.filename_off], | ||
2290 | rule->rule.filename_line); | ||
2291 | |||
2292 | if (import_program_into_properties(event, import, sigmask) != 0) | ||
2293 | if (cur->key.op != OP_NOMATCH) | ||
2294 | goto nomatch; | ||
2295 | break; | ||
2296 | } | ||
2297 | case TK_M_IMPORT_BUILTIN: { | ||
2298 | char command[UTIL_PATH_SIZE]; | ||
2299 | |||
2300 | if (udev_builtin_run_once(cur->key.builtin_cmd)) { | ||
2301 | /* check if we ran already */ | ||
2302 | if (event->builtin_run & (1 << cur->key.builtin_cmd)) { | ||
2303 | info(event->udev, "IMPORT builtin skip '%s' %s:%u\n", | ||
2304 | udev_builtin_name(cur->key.builtin_cmd), | ||
2305 | &rules->buf[rule->rule.filename_off], | ||
2306 | rule->rule.filename_line); | ||
2307 | /* return the result from earlier run */ | ||
2308 | if (event->builtin_ret & (1 << cur->key.builtin_cmd)) | ||
2309 | if (cur->key.op != OP_NOMATCH) | ||
2310 | goto nomatch; | ||
2311 | break; | ||
2312 | } | ||
2313 | /* mark as ran */ | ||
2314 | event->builtin_run |= (1 << cur->key.builtin_cmd); | ||
2315 | } | ||
2316 | |||
2317 | udev_event_apply_format(event, &rules->buf[cur->key.value_off], command, sizeof(command)); | ||
2318 | info(event->udev, "IMPORT builtin '%s' %s:%u\n", | ||
2319 | udev_builtin_name(cur->key.builtin_cmd), | ||
2320 | &rules->buf[rule->rule.filename_off], | ||
2321 | rule->rule.filename_line); | ||
2322 | |||
2323 | if (udev_builtin_run(event->dev, cur->key.builtin_cmd, command, false) != 0) { | ||
2324 | /* remember failure */ | ||
2325 | info(rules->udev, "IMPORT builtin '%s' returned non-zero\n", | ||
2326 | udev_builtin_name(cur->key.builtin_cmd)); | ||
2327 | event->builtin_ret |= (1 << cur->key.builtin_cmd); | ||
2328 | if (cur->key.op != OP_NOMATCH) | ||
2329 | goto nomatch; | ||
2330 | } | ||
2331 | break; | ||
2332 | } | ||
2333 | case TK_M_IMPORT_DB: { | ||
2334 | const char *key = &rules->buf[cur->key.value_off]; | ||
2335 | const char *value; | ||
2336 | |||
2337 | value = udev_device_get_property_value(event->dev_db, key); | ||
2338 | if (value != NULL) { | ||
2339 | struct udev_list_entry *entry; | ||
2340 | |||
2341 | entry = udev_device_add_property(event->dev, key, value); | ||
2342 | udev_list_entry_set_num(entry, true); | ||
2343 | } else { | ||
2344 | if (cur->key.op != OP_NOMATCH) | ||
2345 | goto nomatch; | ||
2346 | } | ||
2347 | break; | ||
2348 | } | ||
2349 | case TK_M_IMPORT_CMDLINE: { | ||
2350 | FILE *f; | ||
2351 | bool imported = false; | ||
2352 | |||
2353 | f = fopen("/proc/cmdline", "r"); | ||
2354 | if (f != NULL) { | ||
2355 | char cmdline[4096]; | ||
2356 | |||
2357 | if (fgets(cmdline, sizeof(cmdline), f) != NULL) { | ||
2358 | const char *key = &rules->buf[cur->key.value_off]; | ||
2359 | char *pos; | ||
2360 | |||
2361 | pos = strstr(cmdline, key); | ||
2362 | if (pos != NULL) { | ||
2363 | struct udev_list_entry *entry; | ||
2364 | |||
2365 | pos += strlen(key); | ||
2366 | if (pos[0] == '\0' || isspace(pos[0])) { | ||
2367 | /* we import simple flags as 'FLAG=1' */ | ||
2368 | entry = udev_device_add_property(event->dev, key, "1"); | ||
2369 | udev_list_entry_set_num(entry, true); | ||
2370 | imported = true; | ||
2371 | } else if (pos[0] == '=') { | ||
2372 | const char *value; | ||
2373 | |||
2374 | pos++; | ||
2375 | value = pos; | ||
2376 | while (pos[0] != '\0' && !isspace(pos[0])) | ||
2377 | pos++; | ||
2378 | pos[0] = '\0'; | ||
2379 | entry = udev_device_add_property(event->dev, key, value); | ||
2380 | udev_list_entry_set_num(entry, true); | ||
2381 | imported = true; | ||
2382 | } | ||
2383 | } | ||
2384 | } | ||
2385 | fclose(f); | ||
2386 | } | ||
2387 | if (!imported && cur->key.op != OP_NOMATCH) | ||
2388 | goto nomatch; | ||
2389 | break; | ||
2390 | } | ||
2391 | case TK_M_IMPORT_PARENT: { | ||
2392 | char import[UTIL_PATH_SIZE]; | ||
2393 | |||
2394 | udev_event_apply_format(event, &rules->buf[cur->key.value_off], import, sizeof(import)); | ||
2395 | if (import_parent_into_properties(event->dev, import) != 0) | ||
2396 | if (cur->key.op != OP_NOMATCH) | ||
2397 | goto nomatch; | ||
2398 | break; | ||
2399 | } | ||
2400 | case TK_M_RESULT: | ||
2401 | if (match_key(rules, cur, event->program_result) != 0) | ||
2402 | goto nomatch; | ||
2403 | break; | ||
2404 | case TK_A_STRING_ESCAPE_NONE: | ||
2405 | esc = ESCAPE_NONE; | ||
2406 | break; | ||
2407 | case TK_A_STRING_ESCAPE_REPLACE: | ||
2408 | esc = ESCAPE_REPLACE; | ||
2409 | break; | ||
2410 | case TK_A_DB_PERSIST: | ||
2411 | udev_device_set_db_persist(event->dev); | ||
2412 | break; | ||
2413 | case TK_A_INOTIFY_WATCH: | ||
2414 | if (event->inotify_watch_final) | ||
2415 | break; | ||
2416 | if (cur->key.op == OP_ASSIGN_FINAL) | ||
2417 | event->inotify_watch_final = true; | ||
2418 | event->inotify_watch = cur->key.watch; | ||
2419 | break; | ||
2420 | case TK_A_DEVLINK_PRIO: | ||
2421 | udev_device_set_devlink_priority(event->dev, cur->key.devlink_prio); | ||
2422 | break; | ||
2423 | case TK_A_OWNER: { | ||
2424 | char owner[UTIL_NAME_SIZE]; | ||
2425 | |||
2426 | if (event->owner_final) | ||
2427 | break; | ||
2428 | if (cur->key.op == OP_ASSIGN_FINAL) | ||
2429 | event->owner_final = true; | ||
2430 | udev_event_apply_format(event, &rules->buf[cur->key.value_off], owner, sizeof(owner)); | ||
2431 | event->uid = util_lookup_user(event->udev, owner); | ||
2432 | info(event->udev, "OWNER %u %s:%u\n", | ||
2433 | event->uid, | ||
2434 | &rules->buf[rule->rule.filename_off], | ||
2435 | rule->rule.filename_line); | ||
2436 | break; | ||
2437 | } | ||
2438 | case TK_A_GROUP: { | ||
2439 | char group[UTIL_NAME_SIZE]; | ||
2440 | |||
2441 | if (event->group_final) | ||
2442 | break; | ||
2443 | if (cur->key.op == OP_ASSIGN_FINAL) | ||
2444 | event->group_final = true; | ||
2445 | udev_event_apply_format(event, &rules->buf[cur->key.value_off], group, sizeof(group)); | ||
2446 | event->gid = util_lookup_group(event->udev, group); | ||
2447 | info(event->udev, "GROUP %u %s:%u\n", | ||
2448 | event->gid, | ||
2449 | &rules->buf[rule->rule.filename_off], | ||
2450 | rule->rule.filename_line); | ||
2451 | break; | ||
2452 | } | ||
2453 | case TK_A_MODE: { | ||
2454 | char mode_str[UTIL_NAME_SIZE]; | ||
2455 | mode_t mode; | ||
2456 | char *endptr; | ||
2457 | |||
2458 | if (event->mode_final) | ||
2459 | break; | ||
2460 | udev_event_apply_format(event, &rules->buf[cur->key.value_off], mode_str, sizeof(mode_str)); | ||
2461 | mode = strtol(mode_str, &endptr, 8); | ||
2462 | if (endptr[0] != '\0') { | ||
2463 | err(event->udev, "ignoring invalid mode '%s'\n", mode_str); | ||
2464 | break; | ||
2465 | } | ||
2466 | if (cur->key.op == OP_ASSIGN_FINAL) | ||
2467 | event->mode_final = true; | ||
2468 | event->mode_set = true; | ||
2469 | event->mode = mode; | ||
2470 | info(event->udev, "MODE %#o %s:%u\n", | ||
2471 | event->mode, | ||
2472 | &rules->buf[rule->rule.filename_off], | ||
2473 | rule->rule.filename_line); | ||
2474 | break; | ||
2475 | } | ||
2476 | case TK_A_OWNER_ID: | ||
2477 | if (event->owner_final) | ||
2478 | break; | ||
2479 | if (cur->key.op == OP_ASSIGN_FINAL) | ||
2480 | event->owner_final = true; | ||
2481 | event->uid = cur->key.uid; | ||
2482 | info(event->udev, "OWNER %u %s:%u\n", | ||
2483 | event->uid, | ||
2484 | &rules->buf[rule->rule.filename_off], | ||
2485 | rule->rule.filename_line); | ||
2486 | break; | ||
2487 | case TK_A_GROUP_ID: | ||
2488 | if (event->group_final) | ||
2489 | break; | ||
2490 | if (cur->key.op == OP_ASSIGN_FINAL) | ||
2491 | event->group_final = true; | ||
2492 | event->gid = cur->key.gid; | ||
2493 | info(event->udev, "GROUP %u %s:%u\n", | ||
2494 | event->gid, | ||
2495 | &rules->buf[rule->rule.filename_off], | ||
2496 | rule->rule.filename_line); | ||
2497 | break; | ||
2498 | case TK_A_MODE_ID: | ||
2499 | if (event->mode_final) | ||
2500 | break; | ||
2501 | if (cur->key.op == OP_ASSIGN_FINAL) | ||
2502 | event->mode_final = true; | ||
2503 | event->mode_set = true; | ||
2504 | event->mode = cur->key.mode; | ||
2505 | info(event->udev, "MODE %#o %s:%u\n", | ||
2506 | event->mode, | ||
2507 | &rules->buf[rule->rule.filename_off], | ||
2508 | rule->rule.filename_line); | ||
2509 | break; | ||
2510 | case TK_A_ENV: { | ||
2511 | const char *name = &rules->buf[cur->key.attr_off]; | ||
2512 | char *value = &rules->buf[cur->key.value_off]; | ||
2513 | |||
2514 | if (value[0] != '\0') { | ||
2515 | char temp_value[UTIL_NAME_SIZE]; | ||
2516 | struct udev_list_entry *entry; | ||
2517 | |||
2518 | udev_event_apply_format(event, value, temp_value, sizeof(temp_value)); | ||
2519 | entry = udev_device_add_property(event->dev, name, temp_value); | ||
2520 | /* store in db, skip private keys */ | ||
2521 | if (name[0] != '.') | ||
2522 | udev_list_entry_set_num(entry, true); | ||
2523 | } else { | ||
2524 | udev_device_add_property(event->dev, name, NULL); | ||
2525 | } | ||
2526 | break; | ||
2527 | } | ||
2528 | case TK_A_TAG: { | ||
2529 | char tag[UTIL_PATH_SIZE]; | ||
2530 | const char *p; | ||
2531 | |||
2532 | udev_event_apply_format(event, &rules->buf[cur->key.value_off], tag, sizeof(tag)); | ||
2533 | if (cur->key.op == OP_ASSIGN || cur->key.op == OP_ASSIGN_FINAL) | ||
2534 | udev_device_cleanup_tags_list(event->dev); | ||
2535 | for (p = tag; *p != '\0'; p++) { | ||
2536 | if ((*p >= 'a' && *p <= 'z') || | ||
2537 | (*p >= 'A' && *p <= 'Z') || | ||
2538 | (*p >= '0' && *p <= '9') || | ||
2539 | *p == '-' || *p == '_') | ||
2540 | continue; | ||
2541 | err(event->udev, "ignoring invalid tag name '%s'\n", tag); | ||
2542 | break; | ||
2543 | } | ||
2544 | udev_device_add_tag(event->dev, tag); | ||
2545 | break; | ||
2546 | } | ||
2547 | case TK_A_NAME: { | ||
2548 | const char *name = &rules->buf[cur->key.value_off]; | ||
2549 | |||
2550 | char name_str[UTIL_PATH_SIZE]; | ||
2551 | int count; | ||
2552 | |||
2553 | if (event->name_final) | ||
2554 | break; | ||
2555 | if (cur->key.op == OP_ASSIGN_FINAL) | ||
2556 | event->name_final = true; | ||
2557 | udev_event_apply_format(event, name, name_str, sizeof(name_str)); | ||
2558 | if (esc == ESCAPE_UNSET || esc == ESCAPE_REPLACE) { | ||
2559 | count = util_replace_chars(name_str, "/"); | ||
2560 | if (count > 0) | ||
2561 | info(event->udev, "%i character(s) replaced\n", count); | ||
2562 | } | ||
2563 | if (major(udev_device_get_devnum(event->dev))) { | ||
2564 | size_t devlen = strlen(udev_get_dev_path(event->udev))+1; | ||
2565 | |||
2566 | if (strcmp(name_str, &udev_device_get_devnode(event->dev)[devlen]) != 0) { | ||
2567 | err(event->udev, "NAME=\"%s\" ignored, kernel device nodes " | ||
2568 | "can not be renamed; please fix it in %s:%u\n", name, | ||
2569 | &rules->buf[rule->rule.filename_off], rule->rule.filename_line); | ||
2570 | break; | ||
2571 | } | ||
2572 | } | ||
2573 | free(event->name); | ||
2574 | event->name = strdup(name_str); | ||
2575 | info(event->udev, "NAME '%s' %s:%u\n", | ||
2576 | event->name, | ||
2577 | &rules->buf[rule->rule.filename_off], | ||
2578 | rule->rule.filename_line); | ||
2579 | break; | ||
2580 | } | ||
2581 | case TK_A_DEVLINK: { | ||
2582 | char temp[UTIL_PATH_SIZE]; | ||
2583 | char filename[UTIL_PATH_SIZE]; | ||
2584 | char *pos, *next; | ||
2585 | int count = 0; | ||
2586 | |||
2587 | if (event->devlink_final) | ||
2588 | break; | ||
2589 | if (major(udev_device_get_devnum(event->dev)) == 0) | ||
2590 | break; | ||
2591 | if (cur->key.op == OP_ASSIGN_FINAL) | ||
2592 | event->devlink_final = true; | ||
2593 | if (cur->key.op == OP_ASSIGN || cur->key.op == OP_ASSIGN_FINAL) | ||
2594 | udev_device_cleanup_devlinks_list(event->dev); | ||
2595 | |||
2596 | /* allow multiple symlinks separated by spaces */ | ||
2597 | udev_event_apply_format(event, &rules->buf[cur->key.value_off], temp, sizeof(temp)); | ||
2598 | if (esc == ESCAPE_UNSET) | ||
2599 | count = util_replace_chars(temp, "/ "); | ||
2600 | else if (esc == ESCAPE_REPLACE) | ||
2601 | count = util_replace_chars(temp, "/"); | ||
2602 | if (count > 0) | ||
2603 | info(event->udev, "%i character(s) replaced\n" , count); | ||
2604 | dbg(event->udev, "rule applied, added symlink(s) '%s'\n", temp); | ||
2605 | pos = temp; | ||
2606 | while (isspace(pos[0])) | ||
2607 | pos++; | ||
2608 | next = strchr(pos, ' '); | ||
2609 | while (next != NULL) { | ||
2610 | next[0] = '\0'; | ||
2611 | info(event->udev, "LINK '%s' %s:%u\n", pos, | ||
2612 | &rules->buf[rule->rule.filename_off], rule->rule.filename_line); | ||
2613 | util_strscpyl(filename, sizeof(filename), udev_get_dev_path(event->udev), "/", pos, NULL); | ||
2614 | udev_device_add_devlink(event->dev, filename, cur->key.devlink_unique); | ||
2615 | while (isspace(next[1])) | ||
2616 | next++; | ||
2617 | pos = &next[1]; | ||
2618 | next = strchr(pos, ' '); | ||
2619 | } | ||
2620 | if (pos[0] != '\0') { | ||
2621 | info(event->udev, "LINK '%s' %s:%u\n", pos, | ||
2622 | &rules->buf[rule->rule.filename_off], rule->rule.filename_line); | ||
2623 | util_strscpyl(filename, sizeof(filename), udev_get_dev_path(event->udev), "/", pos, NULL); | ||
2624 | udev_device_add_devlink(event->dev, filename, cur->key.devlink_unique); | ||
2625 | } | ||
2626 | break; | ||
2627 | } | ||
2628 | case TK_A_ATTR: { | ||
2629 | const char *key_name = &rules->buf[cur->key.attr_off]; | ||
2630 | char attr[UTIL_PATH_SIZE]; | ||
2631 | char value[UTIL_NAME_SIZE]; | ||
2632 | FILE *f; | ||
2633 | |||
2634 | if (util_resolve_subsys_kernel(event->udev, key_name, attr, sizeof(attr), 0) != 0) | ||
2635 | util_strscpyl(attr, sizeof(attr), udev_device_get_syspath(event->dev), "/", key_name, NULL); | ||
2636 | attr_subst_subdir(attr, sizeof(attr)); | ||
2637 | |||
2638 | udev_event_apply_format(event, &rules->buf[cur->key.value_off], value, sizeof(value)); | ||
2639 | info(event->udev, "ATTR '%s' writing '%s' %s:%u\n", attr, value, | ||
2640 | &rules->buf[rule->rule.filename_off], | ||
2641 | rule->rule.filename_line); | ||
2642 | f = fopen(attr, "w"); | ||
2643 | if (f != NULL) { | ||
2644 | if (fprintf(f, "%s", value) <= 0) | ||
2645 | err(event->udev, "error writing ATTR{%s}: %m\n", attr); | ||
2646 | fclose(f); | ||
2647 | } else { | ||
2648 | err(event->udev, "error opening ATTR{%s} for writing: %m\n", attr); | ||
2649 | } | ||
2650 | break; | ||
2651 | } | ||
2652 | case TK_A_RUN: { | ||
2653 | if (cur->key.op == OP_ASSIGN || cur->key.op == OP_ASSIGN_FINAL) | ||
2654 | udev_list_cleanup(&event->run_list); | ||
2655 | info(event->udev, "RUN '%s' %s:%u\n", | ||
2656 | &rules->buf[cur->key.value_off], | ||
2657 | &rules->buf[rule->rule.filename_off], | ||
2658 | rule->rule.filename_line); | ||
2659 | udev_list_entry_add(&event->run_list, &rules->buf[cur->key.value_off], NULL); | ||
2660 | break; | ||
2661 | } | ||
2662 | case TK_A_GOTO: | ||
2663 | if (cur->key.rule_goto == 0) | ||
2664 | break; | ||
2665 | cur = &rules->tokens[cur->key.rule_goto]; | ||
2666 | continue; | ||
2667 | case TK_END: | ||
2668 | return 0; | ||
2669 | |||
2670 | case TK_M_PARENTS_MIN: | ||
2671 | case TK_M_PARENTS_MAX: | ||
2672 | case TK_M_MAX: | ||
2673 | case TK_UNSET: | ||
2674 | err(rules->udev, "wrong type %u\n", cur->type); | ||
2675 | goto nomatch; | ||
2676 | } | ||
2677 | |||
2678 | cur++; | ||
2679 | continue; | ||
2680 | nomatch: | ||
2681 | /* fast-forward to next rule */ | ||
2682 | cur = rule + rule->rule.token_count; | ||
2683 | dbg(rules->udev, "forward to rule: %u\n", | ||
2684 | (unsigned int) (cur - rules->tokens)); | ||
2685 | } | ||
2686 | } | ||
2687 | |||
2688 | void udev_rules_apply_static_dev_perms(struct udev_rules *rules) | ||
2689 | { | ||
2690 | struct token *cur; | ||
2691 | struct token *rule; | ||
2692 | uid_t uid = 0; | ||
2693 | gid_t gid = 0; | ||
2694 | mode_t mode = 0; | ||
2695 | |||
2696 | if (rules->tokens == NULL) | ||
2697 | return; | ||
2698 | |||
2699 | cur = &rules->tokens[0]; | ||
2700 | rule = cur; | ||
2701 | for (;;) { | ||
2702 | switch (cur->type) { | ||
2703 | case TK_RULE: | ||
2704 | /* current rule */ | ||
2705 | rule = cur; | ||
2706 | |||
2707 | /* skip rules without a static_node tag */ | ||
2708 | if (!rule->rule.has_static_node) | ||
2709 | goto next; | ||
2710 | |||
2711 | uid = 0; | ||
2712 | gid = 0; | ||
2713 | mode = 0; | ||
2714 | break; | ||
2715 | case TK_A_OWNER_ID: | ||
2716 | uid = cur->key.uid; | ||
2717 | break; | ||
2718 | case TK_A_GROUP_ID: | ||
2719 | gid = cur->key.gid; | ||
2720 | break; | ||
2721 | case TK_A_MODE_ID: | ||
2722 | mode = cur->key.mode; | ||
2723 | break; | ||
2724 | case TK_A_STATIC_NODE: { | ||
2725 | char filename[UTIL_PATH_SIZE]; | ||
2726 | struct stat stats; | ||
2727 | |||
2728 | /* we assure, that the permissions tokens are sorted before the static token */ | ||
2729 | if (mode == 0 && uid == 0 && gid == 0) | ||
2730 | goto next; | ||
2731 | util_strscpyl(filename, sizeof(filename), udev_get_dev_path(rules->udev), "/", | ||
2732 | &rules->buf[cur->key.value_off], NULL); | ||
2733 | if (stat(filename, &stats) != 0) | ||
2734 | goto next; | ||
2735 | if (!S_ISBLK(stats.st_mode) && !S_ISCHR(stats.st_mode)) | ||
2736 | goto next; | ||
2737 | if (mode == 0) { | ||
2738 | if (gid > 0) | ||
2739 | mode = 0660; | ||
2740 | else | ||
2741 | mode = 0600; | ||
2742 | } | ||
2743 | if (mode != (stats.st_mode & 01777)) { | ||
2744 | chmod(filename, mode); | ||
2745 | info(rules->udev, "chmod '%s' %#o\n", filename, mode); | ||
2746 | } | ||
2747 | |||
2748 | if ((uid != 0 && uid != stats.st_uid) || (gid != 0 && gid != stats.st_gid)) { | ||
2749 | chown(filename, uid, gid); | ||
2750 | info(rules->udev, "chown '%s' %u %u\n", filename, uid, gid); | ||
2751 | } | ||
2752 | |||
2753 | utimensat(AT_FDCWD, filename, NULL, 0); | ||
2754 | break; | ||
2755 | } | ||
2756 | case TK_END: | ||
2757 | return; | ||
2758 | } | ||
2759 | |||
2760 | cur++; | ||
2761 | continue; | ||
2762 | next: | ||
2763 | /* fast-forward to next rule */ | ||
2764 | cur = rule + rule->rule.token_count; | ||
2765 | continue; | ||
2766 | } | ||
2767 | } | ||
diff --git a/src/udev/src/udev-settle.service.in b/src/udev/src/udev-settle.service.in new file mode 100644 index 000000000..b0a4964f7 --- /dev/null +++ b/src/udev/src/udev-settle.service.in | |||
@@ -0,0 +1,25 @@ | |||
1 | # This service is usually not enabled by default. If enabled, it | ||
2 | # acts as a barrier for basic.target -- so all later services will | ||
3 | # wait for udev completely finishing its coldplug run. | ||
4 | # | ||
5 | # If needed, to work around broken or non-hotplug-aware services, | ||
6 | # it might be enabled unconditionally, or pulled-in on-demand by | ||
7 | # the services that assume a fully populated /dev at startup. It | ||
8 | # should not be used or pulled-in ever on systems without such | ||
9 | # legacy services running. | ||
10 | |||
11 | [Unit] | ||
12 | Description=udev Wait for Complete Device Initialization | ||
13 | DefaultDependencies=no | ||
14 | Wants=udev.service | ||
15 | After=udev-trigger.service | ||
16 | Before=basic.target | ||
17 | |||
18 | [Service] | ||
19 | Type=oneshot | ||
20 | TimeoutSec=180 | ||
21 | RemainAfterExit=yes | ||
22 | ExecStart=@bindir@/udevadm settle | ||
23 | |||
24 | [Install] | ||
25 | WantedBy=basic.target | ||
diff --git a/src/udev/src/udev-trigger.service.in b/src/udev/src/udev-trigger.service.in new file mode 100644 index 000000000..cd81945c8 --- /dev/null +++ b/src/udev/src/udev-trigger.service.in | |||
@@ -0,0 +1,10 @@ | |||
1 | [Unit] | ||
2 | Description=udev Coldplug all Devices | ||
3 | Wants=udev.service | ||
4 | After=udev-kernel.socket udev-control.socket | ||
5 | DefaultDependencies=no | ||
6 | |||
7 | [Service] | ||
8 | Type=oneshot | ||
9 | RemainAfterExit=yes | ||
10 | ExecStart=@bindir@/udevadm trigger --type=subsystems --action=add ; @bindir@/udevadm trigger --type=devices --action=add | ||
diff --git a/src/udev/src/udev-watch.c b/src/udev/src/udev-watch.c new file mode 100644 index 000000000..228d18fed --- /dev/null +++ b/src/udev/src/udev-watch.c | |||
@@ -0,0 +1,170 @@ | |||
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_id_filename(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_id_filename(udev, s); | ||
170 | } | ||
diff --git a/src/udev/src/udev.conf b/src/udev/src/udev.conf new file mode 100644 index 000000000..f39253eb6 --- /dev/null +++ b/src/udev/src/udev.conf | |||
@@ -0,0 +1,3 @@ | |||
1 | # see udev(7) for details | ||
2 | |||
3 | #udev_log="info" | ||
diff --git a/src/udev/src/udev.h b/src/udev/src/udev.h new file mode 100644 index 000000000..bc051c9b6 --- /dev/null +++ b/src/udev/src/udev.h | |||
@@ -0,0 +1,188 @@ | |||
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 | int udev_builtin_add_property(struct udev_device *dev, bool test, const char *key, const char *val); | ||
168 | |||
169 | /* udev logging */ | ||
170 | void udev_main_log(struct udev *udev, int priority, | ||
171 | const char *file, int line, const char *fn, | ||
172 | const char *format, va_list args); | ||
173 | |||
174 | /* udevadm commands */ | ||
175 | struct udevadm_cmd { | ||
176 | const char *name; | ||
177 | int (*cmd)(struct udev *udev, int argc, char *argv[]); | ||
178 | const char *help; | ||
179 | int debug; | ||
180 | }; | ||
181 | extern const struct udevadm_cmd udevadm_info; | ||
182 | extern const struct udevadm_cmd udevadm_trigger; | ||
183 | extern const struct udevadm_cmd udevadm_settle; | ||
184 | extern const struct udevadm_cmd udevadm_control; | ||
185 | extern const struct udevadm_cmd udevadm_monitor; | ||
186 | extern const struct udevadm_cmd udevadm_test; | ||
187 | extern const struct udevadm_cmd udevadm_test_builtin; | ||
188 | #endif | ||
diff --git a/src/udev/src/udev.pc.in b/src/udev/src/udev.pc.in new file mode 100644 index 000000000..0b04c02ef --- /dev/null +++ b/src/udev/src/udev.pc.in | |||
@@ -0,0 +1,5 @@ | |||
1 | Name: udev | ||
2 | Description: udev | ||
3 | Version: @VERSION@ | ||
4 | |||
5 | udevdir=@pkglibexecdir@ | ||
diff --git a/src/udev/src/udev.service.in b/src/udev/src/udev.service.in new file mode 100644 index 000000000..c27eb1baf --- /dev/null +++ b/src/udev/src/udev.service.in | |||
@@ -0,0 +1,14 @@ | |||
1 | [Unit] | ||
2 | Description=udev Kernel Device Manager | ||
3 | Wants=udev-control.socket udev-kernel.socket | ||
4 | After=udev-control.socket udev-kernel.socket | ||
5 | Before=basic.target | ||
6 | DefaultDependencies=no | ||
7 | ConditionCapability=CAP_MKNOD | ||
8 | |||
9 | [Service] | ||
10 | Type=notify | ||
11 | OOMScoreAdjust=-1000 | ||
12 | Sockets=udev-control.socket udev-kernel.socket | ||
13 | Restart=on-failure | ||
14 | ExecStart=@pkglibexecdir@/udevd | ||
diff --git a/src/udev/src/udev.xml b/src/udev/src/udev.xml new file mode 100644 index 000000000..8eb583a82 --- /dev/null +++ b/src/udev/src/udev.xml | |||
@@ -0,0 +1,695 @@ | |||
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> | ||
diff --git a/src/udev/src/udevadm-control.c b/src/udev/src/udevadm-control.c new file mode 100644 index 000000000..cafa21494 --- /dev/null +++ b/src/udev/src/udevadm-control.c | |||
@@ -0,0 +1,175 @@ | |||
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 | }; | ||
diff --git a/src/udev/src/udevadm-info.c b/src/udev/src/udevadm-info.c new file mode 100644 index 000000000..ee9b59fea --- /dev/null +++ b/src/udev/src/udevadm-info.c | |||
@@ -0,0 +1,568 @@ | |||
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 int uinfo(struct udev *udev, int argc, char *argv[]) | ||
283 | { | ||
284 | struct udev_device *device = NULL; | ||
285 | bool root = 0; | ||
286 | bool export = 0; | ||
287 | const char *export_prefix = NULL; | ||
288 | char path[UTIL_PATH_SIZE]; | ||
289 | char name[UTIL_PATH_SIZE]; | ||
290 | struct udev_list_entry *list_entry; | ||
291 | int rc = 0; | ||
292 | |||
293 | static const struct option options[] = { | ||
294 | { "name", required_argument, NULL, 'n' }, | ||
295 | { "path", required_argument, NULL, 'p' }, | ||
296 | { "query", required_argument, NULL, 'q' }, | ||
297 | { "attribute-walk", no_argument, NULL, 'a' }, | ||
298 | { "cleanup-db", no_argument, NULL, 'c' }, | ||
299 | { "export-db", no_argument, NULL, 'e' }, | ||
300 | { "root", no_argument, NULL, 'r' }, | ||
301 | { "run", no_argument, NULL, 'R' }, | ||
302 | { "device-id-of-file", required_argument, NULL, 'd' }, | ||
303 | { "export", no_argument, NULL, 'x' }, | ||
304 | { "export-prefix", required_argument, NULL, 'P' }, | ||
305 | { "version", no_argument, NULL, 'V' }, | ||
306 | { "help", no_argument, NULL, 'h' }, | ||
307 | {} | ||
308 | }; | ||
309 | |||
310 | enum action_type { | ||
311 | ACTION_NONE, | ||
312 | ACTION_QUERY, | ||
313 | ACTION_ATTRIBUTE_WALK, | ||
314 | ACTION_ROOT, | ||
315 | ACTION_DEVICE_ID_FILE, | ||
316 | } action = ACTION_NONE; | ||
317 | |||
318 | enum query_type { | ||
319 | QUERY_NONE, | ||
320 | QUERY_NAME, | ||
321 | QUERY_PATH, | ||
322 | QUERY_SYMLINK, | ||
323 | QUERY_PROPERTY, | ||
324 | QUERY_ALL, | ||
325 | } query = QUERY_NONE; | ||
326 | |||
327 | for (;;) { | ||
328 | int option; | ||
329 | struct stat statbuf; | ||
330 | |||
331 | option = getopt_long(argc, argv, "aced:n:p:q:rxP:RVh", options, NULL); | ||
332 | if (option == -1) | ||
333 | break; | ||
334 | |||
335 | dbg(udev, "option '%c'\n", option); | ||
336 | switch (option) { | ||
337 | case 'n': | ||
338 | if (device != NULL) { | ||
339 | fprintf(stderr, "device already specified\n"); | ||
340 | rc = 2; | ||
341 | goto exit; | ||
342 | } | ||
343 | /* remove /dev if given */ | ||
344 | if (strncmp(optarg, udev_get_dev_path(udev), strlen(udev_get_dev_path(udev))) != 0) | ||
345 | util_strscpyl(name, sizeof(name), udev_get_dev_path(udev), "/", optarg, NULL); | ||
346 | else | ||
347 | util_strscpy(name, sizeof(name), optarg); | ||
348 | util_remove_trailing_chars(name, '/'); | ||
349 | if (stat(name, &statbuf) < 0) { | ||
350 | fprintf(stderr, "device node not found\n"); | ||
351 | rc = 2; | ||
352 | goto exit; | ||
353 | } else { | ||
354 | char type; | ||
355 | |||
356 | if (S_ISBLK(statbuf.st_mode)) { | ||
357 | type = 'b'; | ||
358 | } else if (S_ISCHR(statbuf.st_mode)) { | ||
359 | type = 'c'; | ||
360 | } else { | ||
361 | fprintf(stderr, "device node has wrong file type\n"); | ||
362 | rc = 2; | ||
363 | goto exit; | ||
364 | } | ||
365 | device = udev_device_new_from_devnum(udev, type, statbuf.st_rdev); | ||
366 | if (device == NULL) { | ||
367 | fprintf(stderr, "device node not found\n"); | ||
368 | rc = 2; | ||
369 | goto exit; | ||
370 | } | ||
371 | } | ||
372 | break; | ||
373 | case 'p': | ||
374 | if (device != NULL) { | ||
375 | fprintf(stderr, "device already specified\n"); | ||
376 | rc = 2; | ||
377 | goto exit; | ||
378 | } | ||
379 | /* add sys dir if needed */ | ||
380 | if (strncmp(optarg, udev_get_sys_path(udev), strlen(udev_get_sys_path(udev))) != 0) | ||
381 | util_strscpyl(path, sizeof(path), udev_get_sys_path(udev), optarg, NULL); | ||
382 | else | ||
383 | util_strscpy(path, sizeof(path), optarg); | ||
384 | util_remove_trailing_chars(path, '/'); | ||
385 | device = udev_device_new_from_syspath(udev, path); | ||
386 | if (device == NULL) { | ||
387 | fprintf(stderr, "device path not found\n"); | ||
388 | rc = 2; | ||
389 | goto exit; | ||
390 | } | ||
391 | break; | ||
392 | case 'q': | ||
393 | action = ACTION_QUERY; | ||
394 | if (strcmp(optarg, "property") == 0 || strcmp(optarg, "env") == 0) { | ||
395 | query = QUERY_PROPERTY; | ||
396 | } else if (strcmp(optarg, "name") == 0) { | ||
397 | query = QUERY_NAME; | ||
398 | } else if (strcmp(optarg, "symlink") == 0) { | ||
399 | query = QUERY_SYMLINK; | ||
400 | } else if (strcmp(optarg, "path") == 0) { | ||
401 | query = QUERY_PATH; | ||
402 | } else if (strcmp(optarg, "all") == 0) { | ||
403 | query = QUERY_ALL; | ||
404 | } else { | ||
405 | fprintf(stderr, "unknown query type\n"); | ||
406 | rc = 3; | ||
407 | goto exit; | ||
408 | } | ||
409 | break; | ||
410 | case 'r': | ||
411 | if (action == ACTION_NONE) | ||
412 | action = ACTION_ROOT; | ||
413 | root = true; | ||
414 | break; | ||
415 | case 'R': | ||
416 | printf("%s\n", udev_get_run_path(udev)); | ||
417 | goto exit; | ||
418 | case 'd': | ||
419 | action = ACTION_DEVICE_ID_FILE; | ||
420 | util_strscpy(name, sizeof(name), optarg); | ||
421 | break; | ||
422 | case 'a': | ||
423 | action = ACTION_ATTRIBUTE_WALK; | ||
424 | break; | ||
425 | case 'e': | ||
426 | export_devices(udev); | ||
427 | goto exit; | ||
428 | case 'c': | ||
429 | cleanup_db(udev); | ||
430 | goto exit; | ||
431 | case 'x': | ||
432 | export = true; | ||
433 | break; | ||
434 | case 'P': | ||
435 | export_prefix = optarg; | ||
436 | break; | ||
437 | case 'V': | ||
438 | printf("%s\n", VERSION); | ||
439 | goto exit; | ||
440 | case 'h': | ||
441 | printf("Usage: udevadm info OPTIONS\n" | ||
442 | " --query=<type> query device information:\n" | ||
443 | " name name of device node\n" | ||
444 | " symlink pointing to node\n" | ||
445 | " path sys device path\n" | ||
446 | " property the device properties\n" | ||
447 | " all all values\n" | ||
448 | " --path=<syspath> sys device path used for query or attribute walk\n" | ||
449 | " --name=<name> node or symlink name used for query or attribute walk\n" | ||
450 | " --root prepend dev directory to path names\n" | ||
451 | " --attribute-walk print all key matches while walking along the chain\n" | ||
452 | " of parent devices\n" | ||
453 | " --device-id-of-file=<file> print major:minor of device containing this file\n" | ||
454 | " --export export key/value pairs\n" | ||
455 | " --export-prefix export the key name with a prefix\n" | ||
456 | " --export-db export the content of the udev database\n" | ||
457 | " --cleanup-db cleanup the udev database\n" | ||
458 | " --help\n\n"); | ||
459 | goto exit; | ||
460 | default: | ||
461 | rc = 1; | ||
462 | goto exit; | ||
463 | } | ||
464 | } | ||
465 | |||
466 | switch (action) { | ||
467 | case ACTION_QUERY: | ||
468 | if (device == NULL) { | ||
469 | fprintf(stderr, "query needs a valid device specified by --path= or --name=\n"); | ||
470 | rc = 4; | ||
471 | goto exit; | ||
472 | } | ||
473 | |||
474 | switch(query) { | ||
475 | case QUERY_NAME: { | ||
476 | const char *node = udev_device_get_devnode(device); | ||
477 | |||
478 | if (node == NULL) { | ||
479 | fprintf(stderr, "no device node found\n"); | ||
480 | rc = 5; | ||
481 | goto exit; | ||
482 | } | ||
483 | |||
484 | if (root) { | ||
485 | printf("%s\n", udev_device_get_devnode(device)); | ||
486 | } else { | ||
487 | size_t len = strlen(udev_get_dev_path(udev)); | ||
488 | |||
489 | printf("%s\n", &udev_device_get_devnode(device)[len+1]); | ||
490 | } | ||
491 | break; | ||
492 | } | ||
493 | case QUERY_SYMLINK: | ||
494 | list_entry = udev_device_get_devlinks_list_entry(device); | ||
495 | while (list_entry != NULL) { | ||
496 | if (root) { | ||
497 | printf("%s", udev_list_entry_get_name(list_entry)); | ||
498 | } else { | ||
499 | size_t len; | ||
500 | |||
501 | len = strlen(udev_get_dev_path(udev_device_get_udev(device))); | ||
502 | printf("%s", &udev_list_entry_get_name(list_entry)[len+1]); | ||
503 | } | ||
504 | list_entry = udev_list_entry_get_next(list_entry); | ||
505 | if (list_entry != NULL) | ||
506 | printf(" "); | ||
507 | } | ||
508 | printf("\n"); | ||
509 | break; | ||
510 | case QUERY_PATH: | ||
511 | printf("%s\n", udev_device_get_devpath(device)); | ||
512 | goto exit; | ||
513 | case QUERY_PROPERTY: | ||
514 | list_entry = udev_device_get_properties_list_entry(device); | ||
515 | while (list_entry != NULL) { | ||
516 | if (export) { | ||
517 | const char *prefix = export_prefix; | ||
518 | |||
519 | if (prefix == NULL) | ||
520 | prefix = ""; | ||
521 | printf("%s%s='%s'\n", prefix, | ||
522 | udev_list_entry_get_name(list_entry), | ||
523 | udev_list_entry_get_value(list_entry)); | ||
524 | } else { | ||
525 | printf("%s=%s\n", udev_list_entry_get_name(list_entry), udev_list_entry_get_value(list_entry)); | ||
526 | } | ||
527 | list_entry = udev_list_entry_get_next(list_entry); | ||
528 | } | ||
529 | break; | ||
530 | case QUERY_ALL: | ||
531 | print_record(device); | ||
532 | break; | ||
533 | default: | ||
534 | fprintf(stderr, "unknown query type\n"); | ||
535 | break; | ||
536 | } | ||
537 | break; | ||
538 | case ACTION_ATTRIBUTE_WALK: | ||
539 | if (device == NULL) { | ||
540 | fprintf(stderr, "query needs a valid device specified by --path= or --name=\n"); | ||
541 | rc = 4; | ||
542 | goto exit; | ||
543 | } | ||
544 | print_device_chain(device); | ||
545 | break; | ||
546 | case ACTION_DEVICE_ID_FILE: | ||
547 | if (stat_device(name, export, export_prefix) != 0) | ||
548 | rc = 1; | ||
549 | break; | ||
550 | case ACTION_ROOT: | ||
551 | printf("%s\n", udev_get_dev_path(udev)); | ||
552 | break; | ||
553 | default: | ||
554 | fprintf(stderr, "missing option\n"); | ||
555 | rc = 1; | ||
556 | break; | ||
557 | } | ||
558 | |||
559 | exit: | ||
560 | udev_device_unref(device); | ||
561 | return rc; | ||
562 | } | ||
563 | |||
564 | const struct udevadm_cmd udevadm_info = { | ||
565 | .name = "info", | ||
566 | .cmd = uinfo, | ||
567 | .help = "query sysfs or the udev database", | ||
568 | }; | ||
diff --git a/src/udev/src/udevadm-monitor.c b/src/udev/src/udevadm-monitor.c new file mode 100644 index 000000000..5997dd8e1 --- /dev/null +++ b/src/udev/src/udevadm-monitor.c | |||
@@ -0,0 +1,297 @@ | |||
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 | }; | ||
diff --git a/src/udev/src/udevadm-settle.c b/src/udev/src/udevadm-settle.c new file mode 100644 index 000000000..b168defd9 --- /dev/null +++ b/src/udev/src/udevadm-settle.c | |||
@@ -0,0 +1,235 @@ | |||
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 | }; | ||
diff --git a/src/udev/src/udevadm-test-builtin.c b/src/udev/src/udevadm-test-builtin.c new file mode 100644 index 000000000..3a49f7ce9 --- /dev/null +++ b/src/udev/src/udevadm-test-builtin.c | |||
@@ -0,0 +1,128 @@ | |||
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 | }; | ||
diff --git a/src/udev/src/udevadm-test.c b/src/udev/src/udevadm-test.c new file mode 100644 index 000000000..6275cff89 --- /dev/null +++ b/src/udev/src/udevadm-test.c | |||
@@ -0,0 +1,173 @@ | |||
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 | }; | ||
diff --git a/src/udev/src/udevadm-trigger.c b/src/udev/src/udevadm-trigger.c new file mode 100644 index 000000000..3cce23dfb --- /dev/null +++ b/src/udev/src/udevadm-trigger.c | |||
@@ -0,0 +1,232 @@ | |||
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 | }; | ||
diff --git a/src/udev/src/udevadm.c b/src/udev/src/udevadm.c new file mode 100644 index 000000000..224ece0bb --- /dev/null +++ b/src/udev/src/udevadm.c | |||
@@ -0,0 +1,165 @@ | |||
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 | } | ||
diff --git a/src/udev/src/udevadm.xml b/src/udev/src/udevadm.xml new file mode 100644 index 000000000..455ce80ca --- /dev/null +++ b/src/udev/src/udevadm.xml | |||
@@ -0,0 +1,472 @@ | |||
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> | ||
diff --git a/src/udev/src/udevd.c b/src/udev/src/udevd.c new file mode 100644 index 000000000..170221790 --- /dev/null +++ b/src/udev/src/udevd.c | |||
@@ -0,0 +1,1746 @@ | |||
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 | #include "sd-daemon.h" | ||
49 | |||
50 | static bool debug; | ||
51 | |||
52 | void udev_main_log(struct udev *udev, int priority, | ||
53 | const char *file, int line, const char *fn, | ||
54 | const char *format, va_list args) | ||
55 | { | ||
56 | if (debug) { | ||
57 | char buf[1024]; | ||
58 | struct timespec ts; | ||
59 | |||
60 | vsnprintf(buf, sizeof(buf), format, args); | ||
61 | clock_gettime(CLOCK_MONOTONIC, &ts); | ||
62 | fprintf(stderr, "[%llu.%06u] [%u] %s: %s", | ||
63 | (unsigned long long) ts.tv_sec, (unsigned int) ts.tv_nsec/1000, | ||
64 | (int) getpid(), fn, buf); | ||
65 | } else { | ||
66 | vsyslog(priority, format, args); | ||
67 | } | ||
68 | } | ||
69 | |||
70 | static struct udev_rules *rules; | ||
71 | static struct udev_queue_export *udev_queue_export; | ||
72 | static struct udev_ctrl *udev_ctrl; | ||
73 | static struct udev_monitor *monitor; | ||
74 | static int worker_watch[2] = { -1, -1 }; | ||
75 | static int fd_signal = -1; | ||
76 | static int fd_ep = -1; | ||
77 | static int fd_inotify = -1; | ||
78 | static bool stop_exec_queue; | ||
79 | static bool reload; | ||
80 | static int children; | ||
81 | static int children_max; | ||
82 | static int exec_delay; | ||
83 | static sigset_t sigmask_orig; | ||
84 | static UDEV_LIST(event_list); | ||
85 | static UDEV_LIST(worker_list); | ||
86 | static bool udev_exit; | ||
87 | |||
88 | enum event_state { | ||
89 | EVENT_UNDEF, | ||
90 | EVENT_QUEUED, | ||
91 | EVENT_RUNNING, | ||
92 | }; | ||
93 | |||
94 | struct event { | ||
95 | struct udev_list_node node; | ||
96 | struct udev *udev; | ||
97 | struct udev_device *dev; | ||
98 | enum event_state state; | ||
99 | int exitcode; | ||
100 | unsigned long long int delaying_seqnum; | ||
101 | unsigned long long int seqnum; | ||
102 | const char *devpath; | ||
103 | size_t devpath_len; | ||
104 | const char *devpath_old; | ||
105 | dev_t devnum; | ||
106 | bool is_block; | ||
107 | int ifindex; | ||
108 | }; | ||
109 | |||
110 | static struct event *node_to_event(struct udev_list_node *node) | ||
111 | { | ||
112 | char *event; | ||
113 | |||
114 | event = (char *)node; | ||
115 | event -= offsetof(struct event, node); | ||
116 | return (struct event *)event; | ||
117 | } | ||
118 | |||
119 | static void event_queue_cleanup(struct udev *udev, enum event_state type); | ||
120 | |||
121 | enum worker_state { | ||
122 | WORKER_UNDEF, | ||
123 | WORKER_RUNNING, | ||
124 | WORKER_IDLE, | ||
125 | WORKER_KILLED, | ||
126 | }; | ||
127 | |||
128 | struct worker { | ||
129 | struct udev_list_node node; | ||
130 | struct udev *udev; | ||
131 | int refcount; | ||
132 | pid_t pid; | ||
133 | struct udev_monitor *monitor; | ||
134 | enum worker_state state; | ||
135 | struct event *event; | ||
136 | unsigned long long event_start_usec; | ||
137 | }; | ||
138 | |||
139 | /* passed from worker to main process */ | ||
140 | struct worker_message { | ||
141 | pid_t pid; | ||
142 | int exitcode; | ||
143 | }; | ||
144 | |||
145 | static struct worker *node_to_worker(struct udev_list_node *node) | ||
146 | { | ||
147 | char *worker; | ||
148 | |||
149 | worker = (char *)node; | ||
150 | worker -= offsetof(struct worker, node); | ||
151 | return (struct worker *)worker; | ||
152 | } | ||
153 | |||
154 | static void event_queue_delete(struct event *event, bool export) | ||
155 | { | ||
156 | udev_list_node_remove(&event->node); | ||
157 | |||
158 | if (export) { | ||
159 | udev_queue_export_device_finished(udev_queue_export, event->dev); | ||
160 | info(event->udev, "seq %llu done with %i\n", udev_device_get_seqnum(event->dev), event->exitcode); | ||
161 | } | ||
162 | udev_device_unref(event->dev); | ||
163 | free(event); | ||
164 | } | ||
165 | |||
166 | static struct worker *worker_ref(struct worker *worker) | ||
167 | { | ||
168 | worker->refcount++; | ||
169 | return worker; | ||
170 | } | ||
171 | |||
172 | static void worker_cleanup(struct worker *worker) | ||
173 | { | ||
174 | udev_list_node_remove(&worker->node); | ||
175 | udev_monitor_unref(worker->monitor); | ||
176 | children--; | ||
177 | free(worker); | ||
178 | } | ||
179 | |||
180 | static void worker_unref(struct worker *worker) | ||
181 | { | ||
182 | worker->refcount--; | ||
183 | if (worker->refcount > 0) | ||
184 | return; | ||
185 | info(worker->udev, "worker [%u] cleaned up\n", worker->pid); | ||
186 | worker_cleanup(worker); | ||
187 | } | ||
188 | |||
189 | static void worker_list_cleanup(struct udev *udev) | ||
190 | { | ||
191 | struct udev_list_node *loop, *tmp; | ||
192 | |||
193 | udev_list_node_foreach_safe(loop, tmp, &worker_list) { | ||
194 | struct worker *worker = node_to_worker(loop); | ||
195 | |||
196 | worker_cleanup(worker); | ||
197 | } | ||
198 | } | ||
199 | |||
200 | static void worker_new(struct event *event) | ||
201 | { | ||
202 | struct udev *udev = event->udev; | ||
203 | struct worker *worker; | ||
204 | struct udev_monitor *worker_monitor; | ||
205 | pid_t pid; | ||
206 | |||
207 | /* listen for new events */ | ||
208 | worker_monitor = udev_monitor_new_from_netlink(udev, NULL); | ||
209 | if (worker_monitor == NULL) | ||
210 | return; | ||
211 | /* allow the main daemon netlink address to send devices to the worker */ | ||
212 | udev_monitor_allow_unicast_sender(worker_monitor, monitor); | ||
213 | udev_monitor_enable_receiving(worker_monitor); | ||
214 | |||
215 | worker = calloc(1, sizeof(struct worker)); | ||
216 | if (worker == NULL) { | ||
217 | udev_monitor_unref(worker_monitor); | ||
218 | return; | ||
219 | } | ||
220 | /* worker + event reference */ | ||
221 | worker->refcount = 2; | ||
222 | worker->udev = udev; | ||
223 | |||
224 | pid = fork(); | ||
225 | switch (pid) { | ||
226 | case 0: { | ||
227 | struct udev_device *dev = NULL; | ||
228 | int fd_monitor; | ||
229 | struct epoll_event ep_signal, ep_monitor; | ||
230 | sigset_t mask; | ||
231 | int rc = EXIT_SUCCESS; | ||
232 | |||
233 | /* take initial device from queue */ | ||
234 | dev = event->dev; | ||
235 | event->dev = NULL; | ||
236 | |||
237 | free(worker); | ||
238 | worker_list_cleanup(udev); | ||
239 | event_queue_cleanup(udev, EVENT_UNDEF); | ||
240 | udev_queue_export_unref(udev_queue_export); | ||
241 | udev_monitor_unref(monitor); | ||
242 | udev_ctrl_unref(udev_ctrl); | ||
243 | close(fd_signal); | ||
244 | close(fd_ep); | ||
245 | close(worker_watch[READ_END]); | ||
246 | |||
247 | sigfillset(&mask); | ||
248 | fd_signal = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC); | ||
249 | if (fd_signal < 0) { | ||
250 | err(udev, "error creating signalfd %m\n"); | ||
251 | rc = 2; | ||
252 | goto out; | ||
253 | } | ||
254 | |||
255 | fd_ep = epoll_create1(EPOLL_CLOEXEC); | ||
256 | if (fd_ep < 0) { | ||
257 | err(udev, "error creating epoll fd: %m\n"); | ||
258 | rc = 3; | ||
259 | goto out; | ||
260 | } | ||
261 | |||
262 | memset(&ep_signal, 0, sizeof(struct epoll_event)); | ||
263 | ep_signal.events = EPOLLIN; | ||
264 | ep_signal.data.fd = fd_signal; | ||
265 | |||
266 | fd_monitor = udev_monitor_get_fd(worker_monitor); | ||
267 | memset(&ep_monitor, 0, sizeof(struct epoll_event)); | ||
268 | ep_monitor.events = EPOLLIN; | ||
269 | ep_monitor.data.fd = fd_monitor; | ||
270 | |||
271 | if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_signal, &ep_signal) < 0 || | ||
272 | epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_monitor, &ep_monitor) < 0) { | ||
273 | err(udev, "fail to add fds to epoll: %m\n"); | ||
274 | rc = 4; | ||
275 | goto out; | ||
276 | } | ||
277 | |||
278 | /* request TERM signal if parent exits */ | ||
279 | prctl(PR_SET_PDEATHSIG, SIGTERM); | ||
280 | |||
281 | for (;;) { | ||
282 | struct udev_event *udev_event; | ||
283 | struct worker_message msg; | ||
284 | int err; | ||
285 | |||
286 | info(udev, "seq %llu running\n", udev_device_get_seqnum(dev)); | ||
287 | udev_event = udev_event_new(dev); | ||
288 | if (udev_event == NULL) { | ||
289 | rc = 5; | ||
290 | goto out; | ||
291 | } | ||
292 | |||
293 | /* needed for SIGCHLD/SIGTERM in spawn() */ | ||
294 | udev_event->fd_signal = fd_signal; | ||
295 | |||
296 | if (exec_delay > 0) | ||
297 | udev_event->exec_delay = exec_delay; | ||
298 | |||
299 | /* apply rules, create node, symlinks */ | ||
300 | err = udev_event_execute_rules(udev_event, rules, &sigmask_orig); | ||
301 | |||
302 | if (err == 0) | ||
303 | udev_event_execute_run(udev_event, &sigmask_orig); | ||
304 | |||
305 | /* apply/restore inotify watch */ | ||
306 | if (err == 0 && udev_event->inotify_watch) { | ||
307 | udev_watch_begin(udev, dev); | ||
308 | udev_device_update_db(dev); | ||
309 | } | ||
310 | |||
311 | /* send processed event back to libudev listeners */ | ||
312 | udev_monitor_send_device(worker_monitor, NULL, dev); | ||
313 | |||
314 | /* send udevd the result of the event execution */ | ||
315 | memset(&msg, 0, sizeof(struct worker_message)); | ||
316 | if (err != 0) | ||
317 | msg.exitcode = err; | ||
318 | msg.pid = getpid(); | ||
319 | send(worker_watch[WRITE_END], &msg, sizeof(struct worker_message), 0); | ||
320 | |||
321 | info(udev, "seq %llu processed with %i\n", udev_device_get_seqnum(dev), err); | ||
322 | |||
323 | udev_device_unref(dev); | ||
324 | dev = NULL; | ||
325 | |||
326 | if (udev_event->sigterm) { | ||
327 | udev_event_unref(udev_event); | ||
328 | goto out; | ||
329 | } | ||
330 | |||
331 | udev_event_unref(udev_event); | ||
332 | |||
333 | /* wait for more device messages from main udevd, or term signal */ | ||
334 | while (dev == NULL) { | ||
335 | struct epoll_event ev[4]; | ||
336 | int fdcount; | ||
337 | int i; | ||
338 | |||
339 | fdcount = epoll_wait(fd_ep, ev, ARRAY_SIZE(ev), -1); | ||
340 | if (fdcount < 0) { | ||
341 | if (errno == EINTR) | ||
342 | continue; | ||
343 | err = -errno; | ||
344 | err(udev, "failed to poll: %m\n"); | ||
345 | goto out; | ||
346 | } | ||
347 | |||
348 | for (i = 0; i < fdcount; i++) { | ||
349 | if (ev[i].data.fd == fd_monitor && ev[i].events & EPOLLIN) { | ||
350 | dev = udev_monitor_receive_device(worker_monitor); | ||
351 | break; | ||
352 | } else if (ev[i].data.fd == fd_signal && ev[i].events & EPOLLIN) { | ||
353 | struct signalfd_siginfo fdsi; | ||
354 | ssize_t size; | ||
355 | |||
356 | size = read(fd_signal, &fdsi, sizeof(struct signalfd_siginfo)); | ||
357 | if (size != sizeof(struct signalfd_siginfo)) | ||
358 | continue; | ||
359 | switch (fdsi.ssi_signo) { | ||
360 | case SIGTERM: | ||
361 | goto out; | ||
362 | } | ||
363 | } | ||
364 | } | ||
365 | } | ||
366 | } | ||
367 | out: | ||
368 | udev_device_unref(dev); | ||
369 | if (fd_signal >= 0) | ||
370 | close(fd_signal); | ||
371 | if (fd_ep >= 0) | ||
372 | close(fd_ep); | ||
373 | close(fd_inotify); | ||
374 | close(worker_watch[WRITE_END]); | ||
375 | udev_rules_unref(rules); | ||
376 | udev_builtin_exit(udev); | ||
377 | udev_monitor_unref(worker_monitor); | ||
378 | udev_unref(udev); | ||
379 | udev_log_close(); | ||
380 | exit(rc); | ||
381 | } | ||
382 | case -1: | ||
383 | udev_monitor_unref(worker_monitor); | ||
384 | event->state = EVENT_QUEUED; | ||
385 | free(worker); | ||
386 | err(udev, "fork of child failed: %m\n"); | ||
387 | break; | ||
388 | default: | ||
389 | /* close monitor, but keep address around */ | ||
390 | udev_monitor_disconnect(worker_monitor); | ||
391 | worker->monitor = worker_monitor; | ||
392 | worker->pid = pid; | ||
393 | worker->state = WORKER_RUNNING; | ||
394 | worker->event_start_usec = now_usec(); | ||
395 | worker->event = event; | ||
396 | event->state = EVENT_RUNNING; | ||
397 | udev_list_node_append(&worker->node, &worker_list); | ||
398 | children++; | ||
399 | info(udev, "seq %llu forked new worker [%u]\n", udev_device_get_seqnum(event->dev), pid); | ||
400 | break; | ||
401 | } | ||
402 | } | ||
403 | |||
404 | static void event_run(struct event *event) | ||
405 | { | ||
406 | struct udev_list_node *loop; | ||
407 | |||
408 | udev_list_node_foreach(loop, &worker_list) { | ||
409 | struct worker *worker = node_to_worker(loop); | ||
410 | ssize_t count; | ||
411 | |||
412 | if (worker->state != WORKER_IDLE) | ||
413 | continue; | ||
414 | |||
415 | count = udev_monitor_send_device(monitor, worker->monitor, event->dev); | ||
416 | if (count < 0) { | ||
417 | err(event->udev, "worker [%u] did not accept message %zi (%m), kill it\n", worker->pid, count); | ||
418 | kill(worker->pid, SIGKILL); | ||
419 | worker->state = WORKER_KILLED; | ||
420 | continue; | ||
421 | } | ||
422 | worker_ref(worker); | ||
423 | worker->event = event; | ||
424 | worker->state = WORKER_RUNNING; | ||
425 | worker->event_start_usec = now_usec(); | ||
426 | event->state = EVENT_RUNNING; | ||
427 | return; | ||
428 | } | ||
429 | |||
430 | if (children >= children_max) { | ||
431 | if (children_max > 1) | ||
432 | info(event->udev, "maximum number (%i) of children reached\n", children); | ||
433 | return; | ||
434 | } | ||
435 | |||
436 | /* start new worker and pass initial device */ | ||
437 | worker_new(event); | ||
438 | } | ||
439 | |||
440 | static int event_queue_insert(struct udev_device *dev) | ||
441 | { | ||
442 | struct event *event; | ||
443 | |||
444 | event = calloc(1, sizeof(struct event)); | ||
445 | if (event == NULL) | ||
446 | return -1; | ||
447 | |||
448 | event->udev = udev_device_get_udev(dev); | ||
449 | event->dev = dev; | ||
450 | event->seqnum = udev_device_get_seqnum(dev); | ||
451 | event->devpath = udev_device_get_devpath(dev); | ||
452 | event->devpath_len = strlen(event->devpath); | ||
453 | event->devpath_old = udev_device_get_devpath_old(dev); | ||
454 | event->devnum = udev_device_get_devnum(dev); | ||
455 | event->is_block = (strcmp("block", udev_device_get_subsystem(dev)) == 0); | ||
456 | event->ifindex = udev_device_get_ifindex(dev); | ||
457 | |||
458 | udev_queue_export_device_queued(udev_queue_export, dev); | ||
459 | info(event->udev, "seq %llu queued, '%s' '%s'\n", udev_device_get_seqnum(dev), | ||
460 | udev_device_get_action(dev), udev_device_get_subsystem(dev)); | ||
461 | |||
462 | event->state = EVENT_QUEUED; | ||
463 | udev_list_node_append(&event->node, &event_list); | ||
464 | return 0; | ||
465 | } | ||
466 | |||
467 | static void worker_kill(struct udev *udev, int retain) | ||
468 | { | ||
469 | struct udev_list_node *loop; | ||
470 | int max; | ||
471 | |||
472 | if (children <= retain) | ||
473 | return; | ||
474 | |||
475 | max = children - retain; | ||
476 | |||
477 | udev_list_node_foreach(loop, &worker_list) { | ||
478 | struct worker *worker = node_to_worker(loop); | ||
479 | |||
480 | if (max-- <= 0) | ||
481 | break; | ||
482 | |||
483 | if (worker->state == WORKER_KILLED) | ||
484 | continue; | ||
485 | |||
486 | worker->state = WORKER_KILLED; | ||
487 | kill(worker->pid, SIGTERM); | ||
488 | } | ||
489 | } | ||
490 | |||
491 | /* lookup event for identical, parent, child device */ | ||
492 | static bool is_devpath_busy(struct event *event) | ||
493 | { | ||
494 | struct udev_list_node *loop; | ||
495 | size_t common; | ||
496 | |||
497 | /* check if queue contains events we depend on */ | ||
498 | udev_list_node_foreach(loop, &event_list) { | ||
499 | struct event *loop_event = node_to_event(loop); | ||
500 | |||
501 | /* we already found a later event, earlier can not block us, no need to check again */ | ||
502 | if (loop_event->seqnum < event->delaying_seqnum) | ||
503 | continue; | ||
504 | |||
505 | /* event we checked earlier still exists, no need to check again */ | ||
506 | if (loop_event->seqnum == event->delaying_seqnum) | ||
507 | return true; | ||
508 | |||
509 | /* found ourself, no later event can block us */ | ||
510 | if (loop_event->seqnum >= event->seqnum) | ||
511 | break; | ||
512 | |||
513 | /* check major/minor */ | ||
514 | if (major(event->devnum) != 0 && event->devnum == loop_event->devnum && event->is_block == loop_event->is_block) | ||
515 | return true; | ||
516 | |||
517 | /* check network device ifindex */ | ||
518 | if (event->ifindex != 0 && event->ifindex == loop_event->ifindex) | ||
519 | return true; | ||
520 | |||
521 | /* check our old name */ | ||
522 | if (event->devpath_old != NULL && strcmp(loop_event->devpath, event->devpath_old) == 0) { | ||
523 | event->delaying_seqnum = loop_event->seqnum; | ||
524 | return true; | ||
525 | } | ||
526 | |||
527 | /* compare devpath */ | ||
528 | common = MIN(loop_event->devpath_len, event->devpath_len); | ||
529 | |||
530 | /* one devpath is contained in the other? */ | ||
531 | if (memcmp(loop_event->devpath, event->devpath, common) != 0) | ||
532 | continue; | ||
533 | |||
534 | /* identical device event found */ | ||
535 | if (loop_event->devpath_len == event->devpath_len) { | ||
536 | /* devices names might have changed/swapped in the meantime */ | ||
537 | if (major(event->devnum) != 0 && (event->devnum != loop_event->devnum || event->is_block != loop_event->is_block)) | ||
538 | continue; | ||
539 | if (event->ifindex != 0 && event->ifindex != loop_event->ifindex) | ||
540 | continue; | ||
541 | event->delaying_seqnum = loop_event->seqnum; | ||
542 | return true; | ||
543 | } | ||
544 | |||
545 | /* parent device event found */ | ||
546 | if (event->devpath[common] == '/') { | ||
547 | event->delaying_seqnum = loop_event->seqnum; | ||
548 | return true; | ||
549 | } | ||
550 | |||
551 | /* child device event found */ | ||
552 | if (loop_event->devpath[common] == '/') { | ||
553 | event->delaying_seqnum = loop_event->seqnum; | ||
554 | return true; | ||
555 | } | ||
556 | |||
557 | /* no matching device */ | ||
558 | continue; | ||
559 | } | ||
560 | |||
561 | return false; | ||
562 | } | ||
563 | |||
564 | static void event_queue_start(struct udev *udev) | ||
565 | { | ||
566 | struct udev_list_node *loop; | ||
567 | |||
568 | udev_list_node_foreach(loop, &event_list) { | ||
569 | struct event *event = node_to_event(loop); | ||
570 | |||
571 | if (event->state != EVENT_QUEUED) | ||
572 | continue; | ||
573 | |||
574 | /* do not start event if parent or child event is still running */ | ||
575 | if (is_devpath_busy(event)) { | ||
576 | dbg(udev, "delay seq %llu (%s)\n", event->seqnum, event->devpath); | ||
577 | continue; | ||
578 | } | ||
579 | |||
580 | event_run(event); | ||
581 | } | ||
582 | } | ||
583 | |||
584 | static void event_queue_cleanup(struct udev *udev, enum event_state match_type) | ||
585 | { | ||
586 | struct udev_list_node *loop, *tmp; | ||
587 | |||
588 | udev_list_node_foreach_safe(loop, tmp, &event_list) { | ||
589 | struct event *event = node_to_event(loop); | ||
590 | |||
591 | if (match_type != EVENT_UNDEF && match_type != event->state) | ||
592 | continue; | ||
593 | |||
594 | event_queue_delete(event, false); | ||
595 | } | ||
596 | } | ||
597 | |||
598 | static void worker_returned(int fd_worker) | ||
599 | { | ||
600 | for (;;) { | ||
601 | struct worker_message msg; | ||
602 | ssize_t size; | ||
603 | struct udev_list_node *loop; | ||
604 | |||
605 | size = recv(fd_worker, &msg, sizeof(struct worker_message), MSG_DONTWAIT); | ||
606 | if (size != sizeof(struct worker_message)) | ||
607 | break; | ||
608 | |||
609 | /* lookup worker who sent the signal */ | ||
610 | udev_list_node_foreach(loop, &worker_list) { | ||
611 | struct worker *worker = node_to_worker(loop); | ||
612 | |||
613 | if (worker->pid != msg.pid) | ||
614 | continue; | ||
615 | |||
616 | /* worker returned */ | ||
617 | if (worker->event) { | ||
618 | worker->event->exitcode = msg.exitcode; | ||
619 | event_queue_delete(worker->event, true); | ||
620 | worker->event = NULL; | ||
621 | } | ||
622 | if (worker->state != WORKER_KILLED) | ||
623 | worker->state = WORKER_IDLE; | ||
624 | worker_unref(worker); | ||
625 | break; | ||
626 | } | ||
627 | } | ||
628 | } | ||
629 | |||
630 | /* receive the udevd message from userspace */ | ||
631 | static struct udev_ctrl_connection *handle_ctrl_msg(struct udev_ctrl *uctrl) | ||
632 | { | ||
633 | struct udev *udev = udev_ctrl_get_udev(uctrl); | ||
634 | struct udev_ctrl_connection *ctrl_conn; | ||
635 | struct udev_ctrl_msg *ctrl_msg = NULL; | ||
636 | const char *str; | ||
637 | int i; | ||
638 | |||
639 | ctrl_conn = udev_ctrl_get_connection(uctrl); | ||
640 | if (ctrl_conn == NULL) | ||
641 | goto out; | ||
642 | |||
643 | ctrl_msg = udev_ctrl_receive_msg(ctrl_conn); | ||
644 | if (ctrl_msg == NULL) | ||
645 | goto out; | ||
646 | |||
647 | i = udev_ctrl_get_set_log_level(ctrl_msg); | ||
648 | if (i >= 0) { | ||
649 | info(udev, "udevd message (SET_LOG_PRIORITY) received, log_priority=%i\n", i); | ||
650 | udev_set_log_priority(udev, i); | ||
651 | worker_kill(udev, 0); | ||
652 | } | ||
653 | |||
654 | if (udev_ctrl_get_stop_exec_queue(ctrl_msg) > 0) { | ||
655 | info(udev, "udevd message (STOP_EXEC_QUEUE) received\n"); | ||
656 | stop_exec_queue = true; | ||
657 | } | ||
658 | |||
659 | if (udev_ctrl_get_start_exec_queue(ctrl_msg) > 0) { | ||
660 | info(udev, "udevd message (START_EXEC_QUEUE) received\n"); | ||
661 | stop_exec_queue = false; | ||
662 | } | ||
663 | |||
664 | if (udev_ctrl_get_reload(ctrl_msg) > 0) { | ||
665 | info(udev, "udevd message (RELOAD) received\n"); | ||
666 | reload = true; | ||
667 | } | ||
668 | |||
669 | str = udev_ctrl_get_set_env(ctrl_msg); | ||
670 | if (str != NULL) { | ||
671 | char *key; | ||
672 | |||
673 | key = strdup(str); | ||
674 | if (key != NULL) { | ||
675 | char *val; | ||
676 | |||
677 | val = strchr(key, '='); | ||
678 | if (val != NULL) { | ||
679 | val[0] = '\0'; | ||
680 | val = &val[1]; | ||
681 | if (val[0] == '\0') { | ||
682 | info(udev, "udevd message (ENV) received, unset '%s'\n", key); | ||
683 | udev_add_property(udev, key, NULL); | ||
684 | } else { | ||
685 | info(udev, "udevd message (ENV) received, set '%s=%s'\n", key, val); | ||
686 | udev_add_property(udev, key, val); | ||
687 | } | ||
688 | } else { | ||
689 | err(udev, "wrong key format '%s'\n", key); | ||
690 | } | ||
691 | free(key); | ||
692 | } | ||
693 | worker_kill(udev, 0); | ||
694 | } | ||
695 | |||
696 | i = udev_ctrl_get_set_children_max(ctrl_msg); | ||
697 | if (i >= 0) { | ||
698 | info(udev, "udevd message (SET_MAX_CHILDREN) received, children_max=%i\n", i); | ||
699 | children_max = i; | ||
700 | } | ||
701 | |||
702 | if (udev_ctrl_get_ping(ctrl_msg) > 0) | ||
703 | info(udev, "udevd message (SYNC) received\n"); | ||
704 | |||
705 | if (udev_ctrl_get_exit(ctrl_msg) > 0) { | ||
706 | info(udev, "udevd message (EXIT) received\n"); | ||
707 | udev_exit = true; | ||
708 | /* keep reference to block the client until we exit */ | ||
709 | udev_ctrl_connection_ref(ctrl_conn); | ||
710 | } | ||
711 | out: | ||
712 | udev_ctrl_msg_unref(ctrl_msg); | ||
713 | return udev_ctrl_connection_unref(ctrl_conn); | ||
714 | } | ||
715 | |||
716 | /* read inotify messages */ | ||
717 | static int handle_inotify(struct udev *udev) | ||
718 | { | ||
719 | int nbytes, pos; | ||
720 | char *buf; | ||
721 | struct inotify_event *ev; | ||
722 | |||
723 | if ((ioctl(fd_inotify, FIONREAD, &nbytes) < 0) || (nbytes <= 0)) | ||
724 | return 0; | ||
725 | |||
726 | buf = malloc(nbytes); | ||
727 | if (buf == NULL) { | ||
728 | err(udev, "error getting buffer for inotify\n"); | ||
729 | return -1; | ||
730 | } | ||
731 | |||
732 | nbytes = read(fd_inotify, buf, nbytes); | ||
733 | |||
734 | for (pos = 0; pos < nbytes; pos += sizeof(struct inotify_event) + ev->len) { | ||
735 | struct udev_device *dev; | ||
736 | |||
737 | ev = (struct inotify_event *)(buf + pos); | ||
738 | dev = udev_watch_lookup(udev, ev->wd); | ||
739 | if (dev != NULL) { | ||
740 | info(udev, "inotify event: %x for %s\n", ev->mask, udev_device_get_devnode(dev)); | ||
741 | if (ev->mask & IN_CLOSE_WRITE) { | ||
742 | char filename[UTIL_PATH_SIZE]; | ||
743 | int fd; | ||
744 | |||
745 | info(udev, "device %s closed, synthesising 'change'\n", udev_device_get_devnode(dev)); | ||
746 | util_strscpyl(filename, sizeof(filename), udev_device_get_syspath(dev), "/uevent", NULL); | ||
747 | fd = open(filename, O_WRONLY); | ||
748 | if (fd >= 0) { | ||
749 | if (write(fd, "change", 6) < 0) | ||
750 | info(udev, "error writing uevent: %m\n"); | ||
751 | close(fd); | ||
752 | } | ||
753 | } | ||
754 | if (ev->mask & IN_IGNORED) | ||
755 | udev_watch_end(udev, dev); | ||
756 | |||
757 | udev_device_unref(dev); | ||
758 | } | ||
759 | |||
760 | } | ||
761 | |||
762 | free(buf); | ||
763 | return 0; | ||
764 | } | ||
765 | |||
766 | static void handle_signal(struct udev *udev, int signo) | ||
767 | { | ||
768 | switch (signo) { | ||
769 | case SIGINT: | ||
770 | case SIGTERM: | ||
771 | udev_exit = true; | ||
772 | break; | ||
773 | case SIGCHLD: | ||
774 | for (;;) { | ||
775 | pid_t pid; | ||
776 | int status; | ||
777 | struct udev_list_node *loop, *tmp; | ||
778 | |||
779 | pid = waitpid(-1, &status, WNOHANG); | ||
780 | if (pid <= 0) | ||
781 | break; | ||
782 | |||
783 | udev_list_node_foreach_safe(loop, tmp, &worker_list) { | ||
784 | struct worker *worker = node_to_worker(loop); | ||
785 | |||
786 | if (worker->pid != pid) | ||
787 | continue; | ||
788 | info(udev, "worker [%u] exit\n", pid); | ||
789 | |||
790 | if (WIFEXITED(status)) { | ||
791 | if (WEXITSTATUS(status) != 0) | ||
792 | err(udev, "worker [%u] exit with return code %i\n", pid, WEXITSTATUS(status)); | ||
793 | } else if (WIFSIGNALED(status)) { | ||
794 | err(udev, "worker [%u] terminated by signal %i (%s)\n", | ||
795 | pid, WTERMSIG(status), strsignal(WTERMSIG(status))); | ||
796 | } else if (WIFSTOPPED(status)) { | ||
797 | err(udev, "worker [%u] stopped\n", pid); | ||
798 | } else if (WIFCONTINUED(status)) { | ||
799 | err(udev, "worker [%u] continued\n", pid); | ||
800 | } else { | ||
801 | err(udev, "worker [%u] exit with status 0x%04x\n", pid, status); | ||
802 | } | ||
803 | |||
804 | if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { | ||
805 | if (worker->event) { | ||
806 | err(udev, "worker [%u] failed while handling '%s'\n", | ||
807 | pid, worker->event->devpath); | ||
808 | worker->event->exitcode = -32; | ||
809 | event_queue_delete(worker->event, true); | ||
810 | /* drop reference taken for state 'running' */ | ||
811 | worker_unref(worker); | ||
812 | } | ||
813 | } | ||
814 | worker_unref(worker); | ||
815 | break; | ||
816 | } | ||
817 | } | ||
818 | break; | ||
819 | case SIGHUP: | ||
820 | reload = true; | ||
821 | break; | ||
822 | } | ||
823 | } | ||
824 | |||
825 | static void static_dev_create_from_modules(struct udev *udev) | ||
826 | { | ||
827 | struct utsname kernel; | ||
828 | char modules[UTIL_PATH_SIZE]; | ||
829 | char buf[4096]; | ||
830 | FILE *f; | ||
831 | |||
832 | uname(&kernel); | ||
833 | util_strscpyl(modules, sizeof(modules), "/lib/modules/", kernel.release, "/modules.devname", NULL); | ||
834 | f = fopen(modules, "r"); | ||
835 | if (f == NULL) | ||
836 | return; | ||
837 | |||
838 | while (fgets(buf, sizeof(buf), f) != NULL) { | ||
839 | char *s; | ||
840 | const char *modname; | ||
841 | const char *devname; | ||
842 | const char *devno; | ||
843 | int maj, min; | ||
844 | char type; | ||
845 | mode_t mode; | ||
846 | char filename[UTIL_PATH_SIZE]; | ||
847 | |||
848 | if (buf[0] == '#') | ||
849 | continue; | ||
850 | |||
851 | modname = buf; | ||
852 | s = strchr(modname, ' '); | ||
853 | if (s == NULL) | ||
854 | continue; | ||
855 | s[0] = '\0'; | ||
856 | |||
857 | devname = &s[1]; | ||
858 | s = strchr(devname, ' '); | ||
859 | if (s == NULL) | ||
860 | continue; | ||
861 | s[0] = '\0'; | ||
862 | |||
863 | devno = &s[1]; | ||
864 | s = strchr(devno, ' '); | ||
865 | if (s == NULL) | ||
866 | s = strchr(devno, '\n'); | ||
867 | if (s != NULL) | ||
868 | s[0] = '\0'; | ||
869 | if (sscanf(devno, "%c%u:%u", &type, &maj, &min) != 3) | ||
870 | continue; | ||
871 | |||
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 | f = fopen("/dev/kmsg", "w"); | ||
1051 | if (f != NULL) { | ||
1052 | fprintf(f, "<30>udevd[%u]: converting old udev database\n", getpid()); | ||
1053 | fclose(f); | ||
1054 | } | ||
1055 | |||
1056 | udev_enumerate = udev_enumerate_new(udev); | ||
1057 | if (udev_enumerate == NULL) | ||
1058 | return -1; | ||
1059 | udev_enumerate_scan_devices(udev_enumerate); | ||
1060 | udev_list_entry_foreach(list_entry, udev_enumerate_get_list_entry(udev_enumerate)) { | ||
1061 | struct udev_device *device; | ||
1062 | |||
1063 | device = udev_device_new_from_syspath(udev, udev_list_entry_get_name(list_entry)); | ||
1064 | if (device == NULL) | ||
1065 | continue; | ||
1066 | |||
1067 | /* try to find the old database for devices without a current one */ | ||
1068 | if (udev_device_read_db(device, NULL) < 0) { | ||
1069 | bool have_db; | ||
1070 | const char *id; | ||
1071 | struct stat stats; | ||
1072 | char devpath[UTIL_PATH_SIZE]; | ||
1073 | char from[UTIL_PATH_SIZE]; | ||
1074 | |||
1075 | have_db = false; | ||
1076 | |||
1077 | /* find database in old location */ | ||
1078 | id = udev_device_get_id_filename(device); | ||
1079 | util_strscpyl(from, sizeof(from), udev_get_dev_path(udev), "/.udev/db/", id, NULL); | ||
1080 | if (lstat(from, &stats) == 0) { | ||
1081 | if (!have_db) { | ||
1082 | udev_device_read_db(device, from); | ||
1083 | have_db = true; | ||
1084 | } | ||
1085 | unlink(from); | ||
1086 | } | ||
1087 | |||
1088 | /* find old database with $subsys:$sysname name */ | ||
1089 | util_strscpyl(from, sizeof(from), udev_get_dev_path(udev), | ||
1090 | "/.udev/db/", udev_device_get_subsystem(device), ":", | ||
1091 | udev_device_get_sysname(device), NULL); | ||
1092 | if (lstat(from, &stats) == 0) { | ||
1093 | if (!have_db) { | ||
1094 | udev_device_read_db(device, from); | ||
1095 | have_db = true; | ||
1096 | } | ||
1097 | unlink(from); | ||
1098 | } | ||
1099 | |||
1100 | /* find old database with the encoded devpath name */ | ||
1101 | util_path_encode(udev_device_get_devpath(device), devpath, sizeof(devpath)); | ||
1102 | util_strscpyl(from, sizeof(from), udev_get_dev_path(udev), "/.udev/db/", devpath, NULL); | ||
1103 | if (lstat(from, &stats) == 0) { | ||
1104 | if (!have_db) { | ||
1105 | udev_device_read_db(device, from); | ||
1106 | have_db = true; | ||
1107 | } | ||
1108 | unlink(from); | ||
1109 | } | ||
1110 | |||
1111 | /* write out new database */ | ||
1112 | if (have_db) | ||
1113 | udev_device_update_db(device); | ||
1114 | } | ||
1115 | udev_device_unref(device); | ||
1116 | } | ||
1117 | udev_enumerate_unref(udev_enumerate); | ||
1118 | return 0; | ||
1119 | } | ||
1120 | |||
1121 | static int systemd_fds(struct udev *udev, int *rctrl, int *rnetlink) | ||
1122 | { | ||
1123 | int ctrl = -1, netlink = -1; | ||
1124 | int fd, n; | ||
1125 | |||
1126 | n = sd_listen_fds(true); | ||
1127 | if (n <= 0) | ||
1128 | return -1; | ||
1129 | |||
1130 | for (fd = SD_LISTEN_FDS_START; fd < n + SD_LISTEN_FDS_START; fd++) { | ||
1131 | if (sd_is_socket(fd, AF_LOCAL, SOCK_SEQPACKET, -1)) { | ||
1132 | if (ctrl >= 0) | ||
1133 | return -1; | ||
1134 | ctrl = fd; | ||
1135 | continue; | ||
1136 | } | ||
1137 | |||
1138 | if (sd_is_socket(fd, AF_NETLINK, SOCK_RAW, -1)) { | ||
1139 | if (netlink >= 0) | ||
1140 | return -1; | ||
1141 | netlink = fd; | ||
1142 | continue; | ||
1143 | } | ||
1144 | |||
1145 | return -1; | ||
1146 | } | ||
1147 | |||
1148 | if (ctrl < 0 || netlink < 0) | ||
1149 | return -1; | ||
1150 | |||
1151 | info(udev, "ctrl=%i netlink=%i\n", ctrl, netlink); | ||
1152 | *rctrl = ctrl; | ||
1153 | *rnetlink = netlink; | ||
1154 | return 0; | ||
1155 | } | ||
1156 | |||
1157 | static bool check_rules_timestamp(struct udev *udev) | ||
1158 | { | ||
1159 | char **p; | ||
1160 | unsigned long long *stamp_usec; | ||
1161 | int i, n; | ||
1162 | bool changed = false; | ||
1163 | |||
1164 | n = udev_get_rules_path(udev, &p, &stamp_usec); | ||
1165 | for (i = 0; i < n; i++) { | ||
1166 | struct stat stats; | ||
1167 | |||
1168 | if (stat(p[i], &stats) < 0) | ||
1169 | continue; | ||
1170 | |||
1171 | if (stamp_usec[i] == ts_usec(&stats.st_mtim)) | ||
1172 | continue; | ||
1173 | |||
1174 | /* first check */ | ||
1175 | if (stamp_usec[i] != 0) { | ||
1176 | info(udev, "reload - timestamp of '%s' changed\n", p[i]); | ||
1177 | changed = true; | ||
1178 | } | ||
1179 | |||
1180 | /* update timestamp */ | ||
1181 | stamp_usec[i] = ts_usec(&stats.st_mtim); | ||
1182 | } | ||
1183 | |||
1184 | return changed; | ||
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 | /* | ||
1276 | * read the kernel commandline, in case we need to get into debug mode | ||
1277 | * udev.log-priority=<level> syslog priority | ||
1278 | * udev.children-max=<number of workers> events are fully serialized if set to 1 | ||
1279 | * | ||
1280 | */ | ||
1281 | f = fopen("/proc/cmdline", "r"); | ||
1282 | if (f != NULL) { | ||
1283 | char cmdline[4096]; | ||
1284 | |||
1285 | if (fgets(cmdline, sizeof(cmdline), f) != NULL) { | ||
1286 | char *pos; | ||
1287 | |||
1288 | pos = strstr(cmdline, "udev.log-priority="); | ||
1289 | if (pos != NULL) { | ||
1290 | pos += strlen("udev.log-priority="); | ||
1291 | udev_set_log_priority(udev, util_log_priority(pos)); | ||
1292 | } | ||
1293 | |||
1294 | pos = strstr(cmdline, "udev.children-max="); | ||
1295 | if (pos != NULL) { | ||
1296 | pos += strlen("udev.children-max="); | ||
1297 | children_max = strtoul(pos, NULL, 0); | ||
1298 | } | ||
1299 | |||
1300 | pos = strstr(cmdline, "udev.exec-delay="); | ||
1301 | if (pos != NULL) { | ||
1302 | pos += strlen("udev.exec-delay="); | ||
1303 | exec_delay = strtoul(pos, NULL, 0); | ||
1304 | } | ||
1305 | } | ||
1306 | fclose(f); | ||
1307 | } | ||
1308 | |||
1309 | if (getuid() != 0) { | ||
1310 | fprintf(stderr, "root privileges required\n"); | ||
1311 | err(udev, "root privileges required\n"); | ||
1312 | goto exit; | ||
1313 | } | ||
1314 | |||
1315 | /* set umask before creating any file/directory */ | ||
1316 | chdir("/"); | ||
1317 | umask(022); | ||
1318 | |||
1319 | /* /run/udev */ | ||
1320 | mkdir(udev_get_run_path(udev), 0755); | ||
1321 | |||
1322 | /* create standard links, copy static nodes, create nodes from modules */ | ||
1323 | static_dev_create(udev); | ||
1324 | static_dev_create_from_modules(udev); | ||
1325 | |||
1326 | /* before opening new files, make sure std{in,out,err} fds are in a sane state */ | ||
1327 | if (daemonize) { | ||
1328 | int fd; | ||
1329 | |||
1330 | fd = open("/dev/null", O_RDWR); | ||
1331 | if (fd >= 0) { | ||
1332 | if (write(STDOUT_FILENO, 0, 0) < 0) | ||
1333 | dup2(fd, STDOUT_FILENO); | ||
1334 | if (write(STDERR_FILENO, 0, 0) < 0) | ||
1335 | dup2(fd, STDERR_FILENO); | ||
1336 | if (fd > STDERR_FILENO) | ||
1337 | close(fd); | ||
1338 | } else { | ||
1339 | fprintf(stderr, "cannot open /dev/null\n"); | ||
1340 | err(udev, "cannot open /dev/null\n"); | ||
1341 | } | ||
1342 | } | ||
1343 | |||
1344 | if (systemd_fds(udev, &fd_ctrl, &fd_netlink) >= 0) { | ||
1345 | /* get control and netlink socket from from systemd */ | ||
1346 | udev_ctrl = udev_ctrl_new_from_fd(udev, fd_ctrl); | ||
1347 | if (udev_ctrl == NULL) { | ||
1348 | err(udev, "error taking over udev control socket"); | ||
1349 | rc = 1; | ||
1350 | goto exit; | ||
1351 | } | ||
1352 | |||
1353 | monitor = udev_monitor_new_from_netlink_fd(udev, "kernel", fd_netlink); | ||
1354 | if (monitor == NULL) { | ||
1355 | err(udev, "error taking over netlink socket\n"); | ||
1356 | rc = 3; | ||
1357 | goto exit; | ||
1358 | } | ||
1359 | } else { | ||
1360 | /* open control and netlink socket */ | ||
1361 | udev_ctrl = udev_ctrl_new(udev); | ||
1362 | if (udev_ctrl == NULL) { | ||
1363 | fprintf(stderr, "error initializing udev control socket"); | ||
1364 | err(udev, "error initializing udev control socket"); | ||
1365 | rc = 1; | ||
1366 | goto exit; | ||
1367 | } | ||
1368 | fd_ctrl = udev_ctrl_get_fd(udev_ctrl); | ||
1369 | |||
1370 | monitor = udev_monitor_new_from_netlink(udev, "kernel"); | ||
1371 | if (monitor == NULL) { | ||
1372 | fprintf(stderr, "error initializing netlink socket\n"); | ||
1373 | err(udev, "error initializing netlink socket\n"); | ||
1374 | rc = 3; | ||
1375 | goto exit; | ||
1376 | } | ||
1377 | fd_netlink = udev_monitor_get_fd(monitor); | ||
1378 | } | ||
1379 | |||
1380 | if (udev_monitor_enable_receiving(monitor) < 0) { | ||
1381 | fprintf(stderr, "error binding netlink socket\n"); | ||
1382 | err(udev, "error binding netlink socket\n"); | ||
1383 | rc = 3; | ||
1384 | goto exit; | ||
1385 | } | ||
1386 | |||
1387 | if (udev_ctrl_enable_receiving(udev_ctrl) < 0) { | ||
1388 | fprintf(stderr, "error binding udev control socket\n"); | ||
1389 | err(udev, "error binding udev control socket\n"); | ||
1390 | rc = 1; | ||
1391 | goto exit; | ||
1392 | } | ||
1393 | |||
1394 | udev_monitor_set_receive_buffer_size(monitor, 128*1024*1024); | ||
1395 | |||
1396 | /* create queue file before signalling 'ready', to make sure we block 'settle' */ | ||
1397 | udev_queue_export = udev_queue_export_new(udev); | ||
1398 | if (udev_queue_export == NULL) { | ||
1399 | err(udev, "error creating queue file\n"); | ||
1400 | goto exit; | ||
1401 | } | ||
1402 | |||
1403 | if (daemonize) { | ||
1404 | pid_t pid; | ||
1405 | int fd; | ||
1406 | |||
1407 | pid = fork(); | ||
1408 | switch (pid) { | ||
1409 | case 0: | ||
1410 | break; | ||
1411 | case -1: | ||
1412 | err(udev, "fork of daemon failed: %m\n"); | ||
1413 | rc = 4; | ||
1414 | goto exit; | ||
1415 | default: | ||
1416 | rc = EXIT_SUCCESS; | ||
1417 | goto exit_daemonize; | ||
1418 | } | ||
1419 | |||
1420 | setsid(); | ||
1421 | |||
1422 | fd = open("/proc/self/oom_score_adj", O_RDWR); | ||
1423 | if (fd < 0) { | ||
1424 | /* Fallback to old interface */ | ||
1425 | fd = open("/proc/self/oom_adj", O_RDWR); | ||
1426 | if (fd < 0) { | ||
1427 | err(udev, "error disabling OOM: %m\n"); | ||
1428 | } else { | ||
1429 | /* OOM_DISABLE == -17 */ | ||
1430 | write(fd, "-17", 3); | ||
1431 | close(fd); | ||
1432 | } | ||
1433 | } else { | ||
1434 | write(fd, "-1000", 5); | ||
1435 | close(fd); | ||
1436 | } | ||
1437 | } else { | ||
1438 | sd_notify(1, "READY=1"); | ||
1439 | } | ||
1440 | |||
1441 | f = fopen("/dev/kmsg", "w"); | ||
1442 | if (f != NULL) { | ||
1443 | fprintf(f, "<30>udevd[%u]: starting version " VERSION "\n", getpid()); | ||
1444 | fclose(f); | ||
1445 | } | ||
1446 | |||
1447 | if (!debug) { | ||
1448 | int fd; | ||
1449 | |||
1450 | fd = open("/dev/null", O_RDWR); | ||
1451 | if (fd >= 0) { | ||
1452 | dup2(fd, STDIN_FILENO); | ||
1453 | dup2(fd, STDOUT_FILENO); | ||
1454 | dup2(fd, STDERR_FILENO); | ||
1455 | close(fd); | ||
1456 | } | ||
1457 | } | ||
1458 | |||
1459 | fd_inotify = udev_watch_init(udev); | ||
1460 | if (fd_inotify < 0) { | ||
1461 | fprintf(stderr, "error initializing inotify\n"); | ||
1462 | err(udev, "error initializing inotify\n"); | ||
1463 | rc = 4; | ||
1464 | goto exit; | ||
1465 | } | ||
1466 | udev_watch_restore(udev); | ||
1467 | |||
1468 | /* block and listen to all signals on signalfd */ | ||
1469 | sigfillset(&mask); | ||
1470 | sigprocmask(SIG_SETMASK, &mask, &sigmask_orig); | ||
1471 | fd_signal = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC); | ||
1472 | if (fd_signal < 0) { | ||
1473 | fprintf(stderr, "error creating signalfd\n"); | ||
1474 | err(udev, "error creating signalfd\n"); | ||
1475 | rc = 5; | ||
1476 | goto exit; | ||
1477 | } | ||
1478 | |||
1479 | /* unnamed socket from workers to the main daemon */ | ||
1480 | if (socketpair(AF_LOCAL, SOCK_DGRAM|SOCK_CLOEXEC, 0, worker_watch) < 0) { | ||
1481 | fprintf(stderr, "error creating socketpair\n"); | ||
1482 | err(udev, "error creating socketpair\n"); | ||
1483 | rc = 6; | ||
1484 | goto exit; | ||
1485 | } | ||
1486 | fd_worker = worker_watch[READ_END]; | ||
1487 | |||
1488 | udev_builtin_init(udev); | ||
1489 | |||
1490 | rules = udev_rules_new(udev, resolve_names); | ||
1491 | if (rules == NULL) { | ||
1492 | err(udev, "error reading rules\n"); | ||
1493 | goto exit; | ||
1494 | } | ||
1495 | |||
1496 | memset(&ep_ctrl, 0, sizeof(struct epoll_event)); | ||
1497 | ep_ctrl.events = EPOLLIN; | ||
1498 | ep_ctrl.data.fd = fd_ctrl; | ||
1499 | |||
1500 | memset(&ep_inotify, 0, sizeof(struct epoll_event)); | ||
1501 | ep_inotify.events = EPOLLIN; | ||
1502 | ep_inotify.data.fd = fd_inotify; | ||
1503 | |||
1504 | memset(&ep_signal, 0, sizeof(struct epoll_event)); | ||
1505 | ep_signal.events = EPOLLIN; | ||
1506 | ep_signal.data.fd = fd_signal; | ||
1507 | |||
1508 | memset(&ep_netlink, 0, sizeof(struct epoll_event)); | ||
1509 | ep_netlink.events = EPOLLIN; | ||
1510 | ep_netlink.data.fd = fd_netlink; | ||
1511 | |||
1512 | memset(&ep_worker, 0, sizeof(struct epoll_event)); | ||
1513 | ep_worker.events = EPOLLIN; | ||
1514 | ep_worker.data.fd = fd_worker; | ||
1515 | |||
1516 | fd_ep = epoll_create1(EPOLL_CLOEXEC); | ||
1517 | if (fd_ep < 0) { | ||
1518 | err(udev, "error creating epoll fd: %m\n"); | ||
1519 | goto exit; | ||
1520 | } | ||
1521 | if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_ctrl, &ep_ctrl) < 0 || | ||
1522 | epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_inotify, &ep_inotify) < 0 || | ||
1523 | epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_signal, &ep_signal) < 0 || | ||
1524 | epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_netlink, &ep_netlink) < 0 || | ||
1525 | epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_worker, &ep_worker) < 0) { | ||
1526 | err(udev, "fail to add fds to epoll: %m\n"); | ||
1527 | goto exit; | ||
1528 | } | ||
1529 | |||
1530 | /* if needed, convert old database from earlier udev version */ | ||
1531 | convert_db(udev); | ||
1532 | |||
1533 | if (children_max <= 0) { | ||
1534 | int memsize = mem_size_mb(); | ||
1535 | |||
1536 | /* set value depending on the amount of RAM */ | ||
1537 | if (memsize > 0) | ||
1538 | children_max = 128 + (memsize / 8); | ||
1539 | else | ||
1540 | children_max = 128; | ||
1541 | } | ||
1542 | info(udev, "set children_max to %u\n", children_max); | ||
1543 | |||
1544 | udev_rules_apply_static_dev_perms(rules); | ||
1545 | |||
1546 | udev_list_node_init(&event_list); | ||
1547 | udev_list_node_init(&worker_list); | ||
1548 | |||
1549 | for (;;) { | ||
1550 | static unsigned long long last_usec; | ||
1551 | struct epoll_event ev[8]; | ||
1552 | int fdcount; | ||
1553 | int timeout; | ||
1554 | bool is_worker, is_signal, is_inotify, is_netlink, is_ctrl; | ||
1555 | int i; | ||
1556 | |||
1557 | if (udev_exit) { | ||
1558 | /* close sources of new events and discard buffered events */ | ||
1559 | if (fd_ctrl >= 0) { | ||
1560 | epoll_ctl(fd_ep, EPOLL_CTL_DEL, fd_ctrl, NULL); | ||
1561 | fd_ctrl = -1; | ||
1562 | } | ||
1563 | if (monitor != NULL) { | ||
1564 | epoll_ctl(fd_ep, EPOLL_CTL_DEL, fd_netlink, NULL); | ||
1565 | udev_monitor_unref(monitor); | ||
1566 | monitor = NULL; | ||
1567 | } | ||
1568 | if (fd_inotify >= 0) { | ||
1569 | epoll_ctl(fd_ep, EPOLL_CTL_DEL, fd_inotify, NULL); | ||
1570 | close(fd_inotify); | ||
1571 | fd_inotify = -1; | ||
1572 | } | ||
1573 | |||
1574 | /* discard queued events and kill workers */ | ||
1575 | event_queue_cleanup(udev, EVENT_QUEUED); | ||
1576 | worker_kill(udev, 0); | ||
1577 | |||
1578 | /* exit after all has cleaned up */ | ||
1579 | if (udev_list_node_is_empty(&event_list) && udev_list_node_is_empty(&worker_list)) | ||
1580 | break; | ||
1581 | |||
1582 | /* timeout at exit for workers to finish */ | ||
1583 | timeout = 30 * 1000; | ||
1584 | } else if (udev_list_node_is_empty(&event_list) && children <= 2) { | ||
1585 | /* we are idle */ | ||
1586 | timeout = -1; | ||
1587 | } else { | ||
1588 | /* kill idle or hanging workers */ | ||
1589 | timeout = 3 * 1000; | ||
1590 | } | ||
1591 | fdcount = epoll_wait(fd_ep, ev, ARRAY_SIZE(ev), timeout); | ||
1592 | if (fdcount < 0) | ||
1593 | continue; | ||
1594 | |||
1595 | if (fdcount == 0) { | ||
1596 | struct udev_list_node *loop; | ||
1597 | |||
1598 | /* timeout */ | ||
1599 | if (udev_exit) { | ||
1600 | err(udev, "timeout, giving up waiting for workers to finish\n"); | ||
1601 | break; | ||
1602 | } | ||
1603 | |||
1604 | /* kill idle workers */ | ||
1605 | if (udev_list_node_is_empty(&event_list)) { | ||
1606 | info(udev, "cleanup idle workers\n"); | ||
1607 | worker_kill(udev, 2); | ||
1608 | } | ||
1609 | |||
1610 | /* check for hanging events */ | ||
1611 | udev_list_node_foreach(loop, &worker_list) { | ||
1612 | struct worker *worker = node_to_worker(loop); | ||
1613 | |||
1614 | if (worker->state != WORKER_RUNNING) | ||
1615 | continue; | ||
1616 | |||
1617 | if ((now_usec() - worker->event_start_usec) > 30 * 1000 * 1000) { | ||
1618 | err(udev, "worker [%u] timeout, kill it\n", worker->pid, | ||
1619 | worker->event ? worker->event->devpath : "<idle>"); | ||
1620 | kill(worker->pid, SIGKILL); | ||
1621 | worker->state = WORKER_KILLED; | ||
1622 | /* drop reference taken for state 'running' */ | ||
1623 | worker_unref(worker); | ||
1624 | if (worker->event) { | ||
1625 | err(udev, "seq %llu '%s' killed\n", | ||
1626 | udev_device_get_seqnum(worker->event->dev), worker->event->devpath); | ||
1627 | worker->event->exitcode = -64; | ||
1628 | event_queue_delete(worker->event, true); | ||
1629 | worker->event = NULL; | ||
1630 | } | ||
1631 | } | ||
1632 | } | ||
1633 | |||
1634 | } | ||
1635 | |||
1636 | is_worker = is_signal = is_inotify = is_netlink = is_ctrl = false; | ||
1637 | for (i = 0; i < fdcount; i++) { | ||
1638 | if (ev[i].data.fd == fd_worker && ev[i].events & EPOLLIN) | ||
1639 | is_worker = true; | ||
1640 | else if (ev[i].data.fd == fd_netlink && ev[i].events & EPOLLIN) | ||
1641 | is_netlink = true; | ||
1642 | else if (ev[i].data.fd == fd_signal && ev[i].events & EPOLLIN) | ||
1643 | is_signal = true; | ||
1644 | else if (ev[i].data.fd == fd_inotify && ev[i].events & EPOLLIN) | ||
1645 | is_inotify = true; | ||
1646 | else if (ev[i].data.fd == fd_ctrl && ev[i].events & EPOLLIN) | ||
1647 | is_ctrl = true; | ||
1648 | } | ||
1649 | |||
1650 | /* check for changed config, every 3 seconds at most */ | ||
1651 | if ((now_usec() - last_usec) > 3 * 1000 * 1000) { | ||
1652 | if (check_rules_timestamp(udev)) | ||
1653 | reload = true; | ||
1654 | if (udev_builtin_validate(udev)) | ||
1655 | reload = true; | ||
1656 | |||
1657 | last_usec = now_usec(); | ||
1658 | } | ||
1659 | |||
1660 | /* reload requested, HUP signal received, rules changed, builtin changed */ | ||
1661 | if (reload) { | ||
1662 | worker_kill(udev, 0); | ||
1663 | rules = udev_rules_unref(rules); | ||
1664 | udev_builtin_exit(udev); | ||
1665 | reload = 0; | ||
1666 | } | ||
1667 | |||
1668 | /* event has finished */ | ||
1669 | if (is_worker) | ||
1670 | worker_returned(fd_worker); | ||
1671 | |||
1672 | if (is_netlink) { | ||
1673 | struct udev_device *dev; | ||
1674 | |||
1675 | dev = udev_monitor_receive_device(monitor); | ||
1676 | if (dev != NULL) { | ||
1677 | udev_device_set_usec_initialized(dev, now_usec()); | ||
1678 | if (event_queue_insert(dev) < 0) | ||
1679 | udev_device_unref(dev); | ||
1680 | } | ||
1681 | } | ||
1682 | |||
1683 | /* start new events */ | ||
1684 | if (!udev_list_node_is_empty(&event_list) && !udev_exit && !stop_exec_queue) { | ||
1685 | if (rules == NULL) | ||
1686 | rules = udev_rules_new(udev, resolve_names); | ||
1687 | if (rules != NULL) | ||
1688 | event_queue_start(udev); | ||
1689 | } | ||
1690 | |||
1691 | if (is_signal) { | ||
1692 | struct signalfd_siginfo fdsi; | ||
1693 | ssize_t size; | ||
1694 | |||
1695 | size = read(fd_signal, &fdsi, sizeof(struct signalfd_siginfo)); | ||
1696 | if (size == sizeof(struct signalfd_siginfo)) | ||
1697 | handle_signal(udev, fdsi.ssi_signo); | ||
1698 | } | ||
1699 | |||
1700 | /* we are shutting down, the events below are not handled anymore */ | ||
1701 | if (udev_exit) | ||
1702 | continue; | ||
1703 | |||
1704 | /* device node watch */ | ||
1705 | if (is_inotify) | ||
1706 | handle_inotify(udev); | ||
1707 | |||
1708 | /* | ||
1709 | * This needs to be after the inotify handling, to make sure, | ||
1710 | * that the ping is send back after the possibly generated | ||
1711 | * "change" events by the inotify device node watch. | ||
1712 | * | ||
1713 | * A single time we may receive a client connection which we need to | ||
1714 | * keep open to block the client. It will be closed right before we | ||
1715 | * exit. | ||
1716 | */ | ||
1717 | if (is_ctrl) | ||
1718 | ctrl_conn = handle_ctrl_msg(udev_ctrl); | ||
1719 | } | ||
1720 | |||
1721 | rc = EXIT_SUCCESS; | ||
1722 | exit: | ||
1723 | udev_queue_export_cleanup(udev_queue_export); | ||
1724 | udev_ctrl_cleanup(udev_ctrl); | ||
1725 | exit_daemonize: | ||
1726 | if (fd_ep >= 0) | ||
1727 | close(fd_ep); | ||
1728 | worker_list_cleanup(udev); | ||
1729 | event_queue_cleanup(udev, EVENT_UNDEF); | ||
1730 | udev_rules_unref(rules); | ||
1731 | udev_builtin_exit(udev); | ||
1732 | if (fd_signal >= 0) | ||
1733 | close(fd_signal); | ||
1734 | if (worker_watch[READ_END] >= 0) | ||
1735 | close(worker_watch[READ_END]); | ||
1736 | if (worker_watch[WRITE_END] >= 0) | ||
1737 | close(worker_watch[WRITE_END]); | ||
1738 | udev_monitor_unref(monitor); | ||
1739 | udev_queue_export_unref(udev_queue_export); | ||
1740 | udev_ctrl_connection_unref(ctrl_conn); | ||
1741 | udev_ctrl_unref(udev_ctrl); | ||
1742 | udev_selinux_exit(udev); | ||
1743 | udev_unref(udev); | ||
1744 | udev_log_close(); | ||
1745 | return rc; | ||
1746 | } | ||
diff --git a/src/udev/src/udevd.xml b/src/udev/src/udevd.xml new file mode 100644 index 000000000..c516eb979 --- /dev/null +++ b/src/udev/src/udevd.xml | |||
@@ -0,0 +1,151 @@ | |||
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> | ||
diff --git a/src/udev/src/v4l_id/60-persistent-v4l.rules b/src/udev/src/v4l_id/60-persistent-v4l.rules new file mode 100644 index 000000000..93c5ee8c2 --- /dev/null +++ b/src/udev/src/v4l_id/60-persistent-v4l.rules | |||
@@ -0,0 +1,20 @@ | |||
1 | # do not edit this file, it will be overwritten on update | ||
2 | |||
3 | ACTION=="remove", GOTO="persistent_v4l_end" | ||
4 | SUBSYSTEM!="video4linux", GOTO="persistent_v4l_end" | ||
5 | ENV{MAJOR}=="", GOTO="persistent_v4l_end" | ||
6 | |||
7 | IMPORT{program}="v4l_id $devnode" | ||
8 | |||
9 | SUBSYSTEMS=="usb", IMPORT{builtin}="usb_id" | ||
10 | KERNEL=="video*", ENV{ID_SERIAL}=="?*", SYMLINK+="v4l/by-id/$env{ID_BUS}-$env{ID_SERIAL}-video-index$attr{index}" | ||
11 | |||
12 | # check for valid "index" number | ||
13 | TEST!="index", GOTO="persistent_v4l_end" | ||
14 | ATTR{index}!="?*", GOTO="persistent_v4l_end" | ||
15 | |||
16 | IMPORT{builtin}="path_id" | ||
17 | ENV{ID_PATH}=="?*", KERNEL=="video*|vbi*", SYMLINK+="v4l/by-path/$env{ID_PATH}-video-index$attr{index}" | ||
18 | ENV{ID_PATH}=="?*", KERNEL=="audio*", SYMLINK+="v4l/by-path/$env{ID_PATH}-audio-index$attr{index}" | ||
19 | |||
20 | LABEL="persistent_v4l_end" | ||
diff --git a/src/udev/src/v4l_id/v4l_id.c b/src/udev/src/v4l_id/v4l_id.c new file mode 100644 index 000000000..a2a80b5f4 --- /dev/null +++ b/src/udev/src/v4l_id/v4l_id.c | |||
@@ -0,0 +1,87 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009 Kay Sievers <kay.sievers@vrfy.org> | ||
3 | * Copyright (c) 2009 Filippo Argiolas <filippo.argiolas@gmail.com> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public License as | ||
7 | * published by the Free Software Foundation; either version 2 of the | ||
8 | * License, or (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details: | ||
14 | */ | ||
15 | |||
16 | #include <stdio.h> | ||
17 | #include <errno.h> | ||
18 | #include <string.h> | ||
19 | #include <ctype.h> | ||
20 | #include <stdlib.h> | ||
21 | #include <stdio.h> | ||
22 | #include <stdlib.h> | ||
23 | #include <string.h> | ||
24 | #include <unistd.h> | ||
25 | #include <errno.h> | ||
26 | #include <fcntl.h> | ||
27 | #include <getopt.h> | ||
28 | #include <sys/types.h> | ||
29 | #include <sys/time.h> | ||
30 | #include <sys/ioctl.h> | ||
31 | #include <linux/videodev2.h> | ||
32 | |||
33 | int main (int argc, char *argv[]) | ||
34 | { | ||
35 | static const struct option options[] = { | ||
36 | { "help", no_argument, NULL, 'h' }, | ||
37 | {} | ||
38 | }; | ||
39 | int fd; | ||
40 | char *device; | ||
41 | struct v4l2_capability v2cap; | ||
42 | |||
43 | while (1) { | ||
44 | int option; | ||
45 | |||
46 | option = getopt_long(argc, argv, "h", options, NULL); | ||
47 | if (option == -1) | ||
48 | break; | ||
49 | |||
50 | switch (option) { | ||
51 | case 'h': | ||
52 | printf("Usage: v4l_id [--help] <device file>\n\n"); | ||
53 | return 0; | ||
54 | default: | ||
55 | return 1; | ||
56 | } | ||
57 | } | ||
58 | device = argv[optind]; | ||
59 | |||
60 | if (device == NULL) | ||
61 | return 2; | ||
62 | fd = open (device, O_RDONLY); | ||
63 | if (fd < 0) | ||
64 | return 3; | ||
65 | |||
66 | if (ioctl (fd, VIDIOC_QUERYCAP, &v2cap) == 0) { | ||
67 | printf("ID_V4L_VERSION=2\n"); | ||
68 | printf("ID_V4L_PRODUCT=%s\n", v2cap.card); | ||
69 | printf("ID_V4L_CAPABILITIES=:"); | ||
70 | if ((v2cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) > 0) | ||
71 | printf("capture:"); | ||
72 | if ((v2cap.capabilities & V4L2_CAP_VIDEO_OUTPUT) > 0) | ||
73 | printf("video_output:"); | ||
74 | if ((v2cap.capabilities & V4L2_CAP_VIDEO_OVERLAY) > 0) | ||
75 | printf("video_overlay:"); | ||
76 | if ((v2cap.capabilities & V4L2_CAP_AUDIO) > 0) | ||
77 | printf("audio:"); | ||
78 | if ((v2cap.capabilities & V4L2_CAP_TUNER) > 0) | ||
79 | printf("tuner:"); | ||
80 | if ((v2cap.capabilities & V4L2_CAP_RADIO) > 0) | ||
81 | printf("radio:"); | ||
82 | printf("\n"); | ||
83 | } | ||
84 | |||
85 | close (fd); | ||
86 | return 0; | ||
87 | } | ||
diff --git a/src/udev/test/.gitignore b/src/udev/test/.gitignore new file mode 100644 index 000000000..98fa88653 --- /dev/null +++ b/src/udev/test/.gitignore | |||
@@ -0,0 +1 @@ | |||
/sys | |||
diff --git a/src/udev/test/rule-syntax-check.py b/src/udev/test/rule-syntax-check.py new file mode 100755 index 000000000..ff1b63d07 --- /dev/null +++ b/src/udev/test/rule-syntax-check.py | |||
@@ -0,0 +1,64 @@ | |||
1 | #!/usr/bin/python | ||
2 | # Simple udev rules syntax checker | ||
3 | # | ||
4 | # (C) 2010 Canonical Ltd. | ||
5 | # Author: Martin Pitt <martin.pitt@ubuntu.com> | ||
6 | # | ||
7 | # This program is free software; you can redistribute it and/or modify it | ||
8 | # 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, 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 | # You should have received a copy of the GNU General Public License | ||
18 | # along with this program; if not, write to the Free Software Foundation, | ||
19 | # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. | ||
20 | |||
21 | import re | ||
22 | import sys | ||
23 | |||
24 | if len(sys.argv) < 2: | ||
25 | print >> sys.stderr, 'Usage: %s <rules file> [...]' % sys.argv[0] | ||
26 | sys.exit(2) | ||
27 | |||
28 | no_args_tests = re.compile('(ACTION|DEVPATH|KERNELS?|NAME|SYMLINK|SUBSYSTEMS?|DRIVERS?|TAG|RESULT|TEST)\s*(?:=|!)=\s*"([^"]*)"$') | ||
29 | args_tests = re.compile('(ATTRS?|ENV|TEST){([a-zA-Z0-9/_.*%-]+)}\s*(?:=|!)=\s*"([^"]*)"$') | ||
30 | no_args_assign = re.compile('(NAME|SYMLINK|OWNER|GROUP|MODE|TAG|PROGRAM|RUN|LABEL|GOTO|WAIT_FOR|OPTIONS|IMPORT)\s*(?:\+=|:=|=)\s*"([^"]*)"$') | ||
31 | args_assign = re.compile('(ATTR|ENV|IMPORT){([a-zA-Z0-9/_.*%-]+)}\s*=\s*"([^"]*)"$') | ||
32 | |||
33 | result = 0 | ||
34 | buffer = '' | ||
35 | for path in sys.argv[1:]: | ||
36 | lineno = 0 | ||
37 | for line in open(path): | ||
38 | lineno += 1 | ||
39 | |||
40 | # handle line continuation | ||
41 | if line.endswith('\\\n'): | ||
42 | buffer += line[:-2] | ||
43 | continue | ||
44 | else: | ||
45 | line = buffer + line | ||
46 | buffer = '' | ||
47 | |||
48 | # filter out comments and empty lines | ||
49 | line = line.strip() | ||
50 | if not line or line.startswith('#'): | ||
51 | continue | ||
52 | |||
53 | for clause in line.split(','): | ||
54 | clause = clause.strip() | ||
55 | if not (no_args_tests.match(clause) or args_tests.match(clause) or | ||
56 | no_args_assign.match(clause) or args_assign.match(clause)): | ||
57 | |||
58 | print('Invalid line %s:%i: %s' % (path, lineno, line)) | ||
59 | print(' clause:', clause) | ||
60 | print() | ||
61 | result = 1 | ||
62 | break | ||
63 | |||
64 | sys.exit(result) | ||
diff --git a/src/udev/test/rules-test.sh b/src/udev/test/rules-test.sh new file mode 100755 index 000000000..1e224ff8b --- /dev/null +++ b/src/udev/test/rules-test.sh | |||
@@ -0,0 +1,15 @@ | |||
1 | #!/bin/sh | ||
2 | # Call the udev rule syntax checker on all rules that we ship | ||
3 | # | ||
4 | # (C) 2010 Canonical Ltd. | ||
5 | # Author: Martin Pitt <martin.pitt@ubuntu.com> | ||
6 | |||
7 | [ -n "$srcdir" ] || srcdir=`dirname $0`/.. | ||
8 | |||
9 | # skip if we don't have python | ||
10 | type python >/dev/null 2>&1 || { | ||
11 | echo "$0: No python installed, skipping udev rule syntax check" | ||
12 | exit 0 | ||
13 | } | ||
14 | |||
15 | $srcdir/test/rule-syntax-check.py `find $srcdir/rules -name '*.rules'` | ||
diff --git a/src/udev/test/sys.tar.xz b/src/udev/test/sys.tar.xz new file mode 100644 index 000000000..49ee8027b --- /dev/null +++ b/src/udev/test/sys.tar.xz | |||
Binary files differ | |||
diff --git a/src/udev/test/udev-test.pl b/src/udev/test/udev-test.pl new file mode 100755 index 000000000..0b379b0d9 --- /dev/null +++ b/src/udev/test/udev-test.pl | |||
@@ -0,0 +1,1560 @@ | |||
1 | #!/usr/bin/perl | ||
2 | |||
3 | # udev test | ||
4 | # | ||
5 | # Provides automated testing of the udev binary. | ||
6 | # The whole test is self contained in this file, except the matching sysfs tree. | ||
7 | # Simply extend the @tests array, to add a new test variant. | ||
8 | # | ||
9 | # Every test is driven by its own temporary config file. | ||
10 | # This program prepares the environment, creates the config and calls udev. | ||
11 | # | ||
12 | # udev parses the rules, looks at the provided sysfs and | ||
13 | # first creates and then removes the device node. | ||
14 | # After creation and removal the result is checked against the | ||
15 | # expected value and the result is printed. | ||
16 | # | ||
17 | # Copyright (C) 2004-2011 Kay Sievers <kay.sievers@vrfy.org> | ||
18 | # Copyright (C) 2004 Leann Ogasawara <ogasawara@osdl.org> | ||
19 | |||
20 | use warnings; | ||
21 | use strict; | ||
22 | |||
23 | my $PWD = $ENV{PWD}; | ||
24 | my $sysfs = "test/sys"; | ||
25 | my $udev_bin = "./test-udev"; | ||
26 | my $valgrind = 0; | ||
27 | my $udev_bin_valgrind = "valgrind --tool=memcheck --leak-check=yes --quiet $udev_bin"; | ||
28 | my $udev_root = "udev-root"; | ||
29 | my $udev_conf = "udev-test.conf"; | ||
30 | my $udev_rules = "udev-test.rules"; | ||
31 | |||
32 | my @tests = ( | ||
33 | { | ||
34 | desc => "no rules", | ||
35 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", | ||
36 | exp_name => "sda" , | ||
37 | exp_rem_error => "yes", | ||
38 | rules => <<EOF | ||
39 | # | ||
40 | EOF | ||
41 | }, | ||
42 | { | ||
43 | desc => "label test of scsi disc", | ||
44 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", | ||
45 | exp_name => "boot_disk" , | ||
46 | rules => <<EOF | ||
47 | SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", SYMLINK+="boot_disk%n" | ||
48 | KERNEL=="ttyACM0", SYMLINK+="modem" | ||
49 | EOF | ||
50 | }, | ||
51 | { | ||
52 | desc => "label test of scsi disc", | ||
53 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", | ||
54 | exp_name => "boot_disk" , | ||
55 | rules => <<EOF | ||
56 | SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", SYMLINK+="boot_disk%n" | ||
57 | KERNEL=="ttyACM0", SYMLINK+="modem" | ||
58 | EOF | ||
59 | }, | ||
60 | { | ||
61 | desc => "label test of scsi disc", | ||
62 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", | ||
63 | exp_name => "boot_disk" , | ||
64 | rules => <<EOF | ||
65 | SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", SYMLINK+="boot_disk%n" | ||
66 | KERNEL=="ttyACM0", SYMLINK+="modem" | ||
67 | EOF | ||
68 | }, | ||
69 | { | ||
70 | desc => "label test of scsi partition", | ||
71 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1", | ||
72 | exp_name => "boot_disk1" , | ||
73 | rules => <<EOF | ||
74 | SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", SYMLINK+="boot_disk%n" | ||
75 | EOF | ||
76 | }, | ||
77 | { | ||
78 | desc => "label test of pattern match", | ||
79 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1", | ||
80 | exp_name => "boot_disk1" , | ||
81 | rules => <<EOF | ||
82 | SUBSYSTEMS=="scsi", ATTRS{vendor}=="?ATA", SYMLINK+="boot_disk%n-1" | ||
83 | SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA?", SYMLINK+="boot_disk%n-2" | ||
84 | SUBSYSTEMS=="scsi", ATTRS{vendor}=="A??", SYMLINK+="boot_disk%n" | ||
85 | SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATAS", SYMLINK+="boot_disk%n-3" | ||
86 | EOF | ||
87 | }, | ||
88 | { | ||
89 | desc => "label test of multiple sysfs files", | ||
90 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1", | ||
91 | exp_name => "boot_disk1" , | ||
92 | rules => <<EOF | ||
93 | SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS X ", SYMLINK+="boot_diskX%n" | ||
94 | SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", SYMLINK+="boot_disk%n" | ||
95 | EOF | ||
96 | }, | ||
97 | { | ||
98 | desc => "label test of max sysfs files (skip invalid rule)", | ||
99 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1", | ||
100 | exp_name => "boot_disk1" , | ||
101 | rules => <<EOF | ||
102 | SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", ATTRS{scsi_level}=="6", ATTRS{rev}=="4.06", ATTRS{type}=="0", ATTRS{queue_depth}=="32", SYMLINK+="boot_diskXX%n" | ||
103 | SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", ATTRS{scsi_level}=="6", ATTRS{rev}=="4.06", ATTRS{type}=="0", SYMLINK+="boot_disk%n" | ||
104 | EOF | ||
105 | }, | ||
106 | { | ||
107 | desc => "catch device by *", | ||
108 | devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", | ||
109 | exp_name => "modem/0" , | ||
110 | rules => <<EOF | ||
111 | KERNEL=="ttyACM*", SYMLINK+="modem/%n" | ||
112 | EOF | ||
113 | }, | ||
114 | { | ||
115 | desc => "catch device by * - take 2", | ||
116 | devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", | ||
117 | exp_name => "modem/0" , | ||
118 | rules => <<EOF | ||
119 | KERNEL=="*ACM1", SYMLINK+="bad" | ||
120 | KERNEL=="*ACM0", SYMLINK+="modem/%n" | ||
121 | EOF | ||
122 | }, | ||
123 | { | ||
124 | desc => "catch device by ?", | ||
125 | devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", | ||
126 | exp_name => "modem/0" , | ||
127 | rules => <<EOF | ||
128 | KERNEL=="ttyACM??*", SYMLINK+="modem/%n-1" | ||
129 | KERNEL=="ttyACM??", SYMLINK+="modem/%n-2" | ||
130 | KERNEL=="ttyACM?", SYMLINK+="modem/%n" | ||
131 | EOF | ||
132 | }, | ||
133 | { | ||
134 | desc => "catch device by character class", | ||
135 | devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", | ||
136 | exp_name => "modem/0" , | ||
137 | rules => <<EOF | ||
138 | KERNEL=="ttyACM[A-Z]*", SYMLINK+="modem/%n-1" | ||
139 | KERNEL=="ttyACM?[0-9]", SYMLINK+="modem/%n-2" | ||
140 | KERNEL=="ttyACM[0-9]*", SYMLINK+="modem/%n" | ||
141 | EOF | ||
142 | }, | ||
143 | { | ||
144 | desc => "replace kernel name", | ||
145 | devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", | ||
146 | exp_name => "modem" , | ||
147 | rules => <<EOF | ||
148 | KERNEL=="ttyACM0", SYMLINK+="modem" | ||
149 | EOF | ||
150 | }, | ||
151 | { | ||
152 | desc => "Handle comment lines in config file (and replace kernel name)", | ||
153 | devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", | ||
154 | exp_name => "modem" , | ||
155 | rules => <<EOF | ||
156 | # this is a comment | ||
157 | KERNEL=="ttyACM0", SYMLINK+="modem" | ||
158 | |||
159 | EOF | ||
160 | }, | ||
161 | { | ||
162 | desc => "Handle comment lines in config file with whitespace (and replace kernel name)", | ||
163 | devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", | ||
164 | exp_name => "modem" , | ||
165 | rules => <<EOF | ||
166 | # this is a comment with whitespace before the comment | ||
167 | KERNEL=="ttyACM0", SYMLINK+="modem" | ||
168 | |||
169 | EOF | ||
170 | }, | ||
171 | { | ||
172 | desc => "Handle whitespace only lines (and replace kernel name)", | ||
173 | devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", | ||
174 | exp_name => "whitespace" , | ||
175 | rules => <<EOF | ||
176 | |||
177 | |||
178 | |||
179 | # this is a comment with whitespace before the comment | ||
180 | KERNEL=="ttyACM0", SYMLINK+="whitespace" | ||
181 | |||
182 | |||
183 | |||
184 | EOF | ||
185 | }, | ||
186 | { | ||
187 | desc => "Handle empty lines in config file (and replace kernel name)", | ||
188 | devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", | ||
189 | exp_name => "modem" , | ||
190 | rules => <<EOF | ||
191 | |||
192 | KERNEL=="ttyACM0", SYMLINK+="modem" | ||
193 | |||
194 | EOF | ||
195 | }, | ||
196 | { | ||
197 | desc => "Handle backslashed multi lines in config file (and replace kernel name)", | ||
198 | devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", | ||
199 | exp_name => "modem" , | ||
200 | rules => <<EOF | ||
201 | KERNEL=="ttyACM0", \\ | ||
202 | SYMLINK+="modem" | ||
203 | |||
204 | EOF | ||
205 | }, | ||
206 | { | ||
207 | desc => "preserve backslashes, if they are not for a newline", | ||
208 | devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", | ||
209 | exp_name => "aaa", | ||
210 | rules => <<EOF | ||
211 | KERNEL=="ttyACM0", PROGRAM=="/bin/echo -e \\101", RESULT=="A", SYMLINK+="aaa" | ||
212 | EOF | ||
213 | }, | ||
214 | { | ||
215 | desc => "Handle stupid backslashed multi lines in config file (and replace kernel name)", | ||
216 | devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", | ||
217 | exp_name => "modem" , | ||
218 | rules => <<EOF | ||
219 | |||
220 | # | ||
221 | \\ | ||
222 | |||
223 | \\ | ||
224 | |||
225 | #\\ | ||
226 | |||
227 | KERNEL=="ttyACM0", \\ | ||
228 | SYMLINK+="modem" | ||
229 | |||
230 | EOF | ||
231 | }, | ||
232 | { | ||
233 | desc => "subdirectory handling", | ||
234 | devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", | ||
235 | exp_name => "sub/direct/ory/modem" , | ||
236 | rules => <<EOF | ||
237 | KERNEL=="ttyACM0", SYMLINK+="sub/direct/ory/modem" | ||
238 | EOF | ||
239 | }, | ||
240 | { | ||
241 | desc => "parent device name match of scsi partition", | ||
242 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5", | ||
243 | exp_name => "first_disk5" , | ||
244 | rules => <<EOF | ||
245 | SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", SYMLINK+="first_disk%n" | ||
246 | EOF | ||
247 | }, | ||
248 | { | ||
249 | desc => "test substitution chars", | ||
250 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5", | ||
251 | exp_name => "Major:8:minor:5:kernelnumber:5:id:0:0:0:0" , | ||
252 | rules => <<EOF | ||
253 | SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", SYMLINK+="Major:%M:minor:%m:kernelnumber:%n:id:%b" | ||
254 | EOF | ||
255 | }, | ||
256 | { | ||
257 | desc => "import of shell-value file", | ||
258 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", | ||
259 | exp_name => "subdir/err/node" , | ||
260 | rules => <<EOF | ||
261 | SUBSYSTEMS=="scsi", IMPORT{file}="udev-test.conf", SYMLINK+="subdir/%E{udev_log}/node" | ||
262 | KERNEL=="ttyACM0", SYMLINK+="modem" | ||
263 | EOF | ||
264 | }, | ||
265 | { | ||
266 | desc => "import of shell-value returned from program", | ||
267 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", | ||
268 | exp_name => "node12345678", | ||
269 | rules => <<EOF | ||
270 | SUBSYSTEMS=="scsi", IMPORT{program}="/bin/echo -e \' TEST_KEY=12345678\\n TEST_key2=98765\'", SYMLINK+="node\$env{TEST_KEY}" | ||
271 | KERNEL=="ttyACM0", SYMLINK+="modem" | ||
272 | EOF | ||
273 | }, | ||
274 | { | ||
275 | desc => "sustitution of sysfs value (%s{file})", | ||
276 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", | ||
277 | exp_name => "disk-ATA-sda" , | ||
278 | rules => <<EOF | ||
279 | SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", SYMLINK+="disk-%s{vendor}-%k" | ||
280 | KERNEL=="ttyACM0", SYMLINK+="modem" | ||
281 | EOF | ||
282 | }, | ||
283 | { | ||
284 | desc => "program result substitution", | ||
285 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5", | ||
286 | exp_name => "special-device-5" , | ||
287 | not_exp_name => "not" , | ||
288 | rules => <<EOF | ||
289 | SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n special-device", RESULT=="-special-*", SYMLINK+="not" | ||
290 | SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n special-device", RESULT=="special-*", SYMLINK+="%c-%n" | ||
291 | EOF | ||
292 | }, | ||
293 | { | ||
294 | desc => "program result substitution (newline removal)", | ||
295 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5", | ||
296 | exp_name => "newline_removed" , | ||
297 | rules => <<EOF | ||
298 | SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo test", RESULT=="test", SYMLINK+="newline_removed" | ||
299 | EOF | ||
300 | }, | ||
301 | { | ||
302 | desc => "program result substitution", | ||
303 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5", | ||
304 | exp_name => "test-0:0:0:0" , | ||
305 | rules => <<EOF | ||
306 | SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n test-%b", RESULT=="test-0:0*", SYMLINK+="%c" | ||
307 | EOF | ||
308 | }, | ||
309 | { | ||
310 | desc => "program with lots of arguments", | ||
311 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5", | ||
312 | exp_name => "foo9" , | ||
313 | rules => <<EOF | ||
314 | SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n foo3 foo4 foo5 foo6 foo7 foo8 foo9", KERNEL=="sda5", SYMLINK+="%c{7}" | ||
315 | EOF | ||
316 | }, | ||
317 | { | ||
318 | desc => "program with subshell", | ||
319 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5", | ||
320 | exp_name => "bar9" , | ||
321 | rules => <<EOF | ||
322 | SUBSYSTEMS=="scsi", PROGRAM=="/bin/sh -c 'echo foo3 foo4 foo5 foo6 foo7 foo8 foo9 | sed s/foo9/bar9/'", KERNEL=="sda5", SYMLINK+="%c{7}" | ||
323 | EOF | ||
324 | }, | ||
325 | { | ||
326 | desc => "program arguments combined with apostrophes", | ||
327 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5", | ||
328 | exp_name => "foo7" , | ||
329 | rules => <<EOF | ||
330 | SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n 'foo3 foo4' 'foo5 foo6 foo7 foo8'", KERNEL=="sda5", SYMLINK+="%c{5}" | ||
331 | EOF | ||
332 | }, | ||
333 | { | ||
334 | desc => "characters before the %c{N} substitution", | ||
335 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5", | ||
336 | exp_name => "my-foo9" , | ||
337 | rules => <<EOF | ||
338 | SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n foo3 foo4 foo5 foo6 foo7 foo8 foo9", KERNEL=="sda5", SYMLINK+="my-%c{7}" | ||
339 | EOF | ||
340 | }, | ||
341 | { | ||
342 | desc => "substitute the second to last argument", | ||
343 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5", | ||
344 | exp_name => "my-foo8" , | ||
345 | rules => <<EOF | ||
346 | SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n foo3 foo4 foo5 foo6 foo7 foo8 foo9", KERNEL=="sda5", SYMLINK+="my-%c{6}" | ||
347 | EOF | ||
348 | }, | ||
349 | { | ||
350 | desc => "test substitution by variable name", | ||
351 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5", | ||
352 | exp_name => "Major:8-minor:5-kernelnumber:5-id:0:0:0:0", | ||
353 | rules => <<EOF | ||
354 | SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", SYMLINK+="Major:\$major-minor:\$minor-kernelnumber:\$number-id:\$id" | ||
355 | EOF | ||
356 | }, | ||
357 | { | ||
358 | desc => "test substitution by variable name 2", | ||
359 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5", | ||
360 | exp_name => "Major:8-minor:5-kernelnumber:5-id:0:0:0:0", | ||
361 | rules => <<EOF | ||
362 | SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", DEVPATH=="*/sda/*", SYMLINK+="Major:\$major-minor:%m-kernelnumber:\$number-id:\$id" | ||
363 | EOF | ||
364 | }, | ||
365 | { | ||
366 | desc => "test substitution by variable name 3", | ||
367 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5", | ||
368 | exp_name => "850:0:0:05" , | ||
369 | rules => <<EOF | ||
370 | SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", DEVPATH=="*/sda/*", SYMLINK+="%M%m%b%n" | ||
371 | EOF | ||
372 | }, | ||
373 | { | ||
374 | desc => "test substitution by variable name 4", | ||
375 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5", | ||
376 | exp_name => "855" , | ||
377 | rules => <<EOF | ||
378 | SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", DEVPATH=="*/sda/*", SYMLINK+="\$major\$minor\$number" | ||
379 | EOF | ||
380 | }, | ||
381 | { | ||
382 | desc => "test substitution by variable name 5", | ||
383 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5", | ||
384 | exp_name => "8550:0:0:0" , | ||
385 | rules => <<EOF | ||
386 | SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", DEVPATH=="*/sda/*", SYMLINK+="\$major%m%n\$id" | ||
387 | EOF | ||
388 | }, | ||
389 | { | ||
390 | desc => "non matching SUBSYSTEMS for device with no parent", | ||
391 | devpath => "/devices/virtual/tty/console", | ||
392 | exp_name => "TTY", | ||
393 | rules => <<EOF | ||
394 | SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n foo", RESULT=="foo", SYMLINK+="foo" | ||
395 | KERNEL=="console", SYMLINK+="TTY" | ||
396 | EOF | ||
397 | }, | ||
398 | { | ||
399 | desc => "non matching SUBSYSTEMS", | ||
400 | devpath => "/devices/virtual/tty/console", | ||
401 | exp_name => "TTY" , | ||
402 | rules => <<EOF | ||
403 | SUBSYSTEMS=="foo", ATTRS{dev}=="5:1", SYMLINK+="foo" | ||
404 | KERNEL=="console", SYMLINK+="TTY" | ||
405 | EOF | ||
406 | }, | ||
407 | { | ||
408 | desc => "ATTRS match", | ||
409 | devpath => "/devices/virtual/tty/console", | ||
410 | exp_name => "foo" , | ||
411 | rules => <<EOF | ||
412 | KERNEL=="console", SYMLINK+="TTY" | ||
413 | ATTRS{dev}=="5:1", SYMLINK+="foo" | ||
414 | EOF | ||
415 | }, | ||
416 | { | ||
417 | desc => "ATTR (empty file)", | ||
418 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", | ||
419 | exp_name => "empty" , | ||
420 | rules => <<EOF | ||
421 | KERNEL=="sda", ATTR{test_empty_file}=="?*", SYMLINK+="something" | ||
422 | KERNEL=="sda", ATTR{test_empty_file}!="", SYMLINK+="not-empty" | ||
423 | KERNEL=="sda", ATTR{test_empty_file}=="", SYMLINK+="empty" | ||
424 | KERNEL=="sda", ATTR{test_empty_file}!="?*", SYMLINK+="not-something" | ||
425 | EOF | ||
426 | }, | ||
427 | { | ||
428 | desc => "ATTR (non-existent file)", | ||
429 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", | ||
430 | exp_name => "non-existent" , | ||
431 | rules => <<EOF | ||
432 | KERNEL=="sda", ATTR{nofile}=="?*", SYMLINK+="something" | ||
433 | KERNEL=="sda", ATTR{nofile}!="", SYMLINK+="not-empty" | ||
434 | KERNEL=="sda", ATTR{nofile}=="", SYMLINK+="empty" | ||
435 | KERNEL=="sda", ATTR{nofile}!="?*", SYMLINK+="not-something" | ||
436 | KERNEL=="sda", TEST!="nofile", SYMLINK+="non-existent" | ||
437 | KERNEL=="sda", SYMLINK+="wrong" | ||
438 | EOF | ||
439 | }, | ||
440 | { | ||
441 | desc => "program and bus type match", | ||
442 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", | ||
443 | exp_name => "scsi-0:0:0:0" , | ||
444 | rules => <<EOF | ||
445 | SUBSYSTEMS=="usb", PROGRAM=="/bin/echo -n usb-%b", SYMLINK+="%c" | ||
446 | SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n scsi-%b", SYMLINK+="%c" | ||
447 | SUBSYSTEMS=="foo", PROGRAM=="/bin/echo -n foo-%b", SYMLINK+="%c" | ||
448 | EOF | ||
449 | }, | ||
450 | { | ||
451 | desc => "sysfs parent hierarchy", | ||
452 | devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", | ||
453 | exp_name => "modem" , | ||
454 | rules => <<EOF | ||
455 | ATTRS{idProduct}=="007b", SYMLINK+="modem" | ||
456 | EOF | ||
457 | }, | ||
458 | { | ||
459 | desc => "name test with ! in the name", | ||
460 | devpath => "/devices/virtual/block/fake!blockdev0", | ||
461 | exp_name => "is/a/fake/blockdev0" , | ||
462 | rules => <<EOF | ||
463 | SUBSYSTEMS=="scsi", SYMLINK+="is/not/a/%k" | ||
464 | SUBSYSTEM=="block", SYMLINK+="is/a/%k" | ||
465 | KERNEL=="ttyACM0", SYMLINK+="modem" | ||
466 | EOF | ||
467 | }, | ||
468 | { | ||
469 | desc => "name test with ! in the name, but no matching rule", | ||
470 | devpath => "/devices/virtual/block/fake!blockdev0", | ||
471 | exp_name => "fake/blockdev0" , | ||
472 | exp_rem_error => "yes", | ||
473 | rules => <<EOF | ||
474 | KERNEL=="ttyACM0", SYMLINK+="modem" | ||
475 | EOF | ||
476 | }, | ||
477 | { | ||
478 | desc => "KERNELS rule", | ||
479 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", | ||
480 | exp_name => "scsi-0:0:0:0", | ||
481 | rules => <<EOF | ||
482 | SUBSYSTEMS=="usb", KERNELS=="0:0:0:0", SYMLINK+="not-scsi" | ||
483 | SUBSYSTEMS=="scsi", KERNELS=="0:0:0:1", SYMLINK+="no-match" | ||
484 | SUBSYSTEMS=="scsi", KERNELS==":0", SYMLINK+="short-id" | ||
485 | SUBSYSTEMS=="scsi", KERNELS=="/0:0:0:0", SYMLINK+="no-match" | ||
486 | SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", SYMLINK+="scsi-0:0:0:0" | ||
487 | EOF | ||
488 | }, | ||
489 | { | ||
490 | desc => "KERNELS wildcard all", | ||
491 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", | ||
492 | exp_name => "scsi-0:0:0:0", | ||
493 | rules => <<EOF | ||
494 | SUBSYSTEMS=="scsi", KERNELS=="*:1", SYMLINK+="no-match" | ||
495 | SUBSYSTEMS=="scsi", KERNELS=="*:0:1", SYMLINK+="no-match" | ||
496 | SUBSYSTEMS=="scsi", KERNELS=="*:0:0:1", SYMLINK+="no-match" | ||
497 | SUBSYSTEMS=="scsi", KERNEL=="0:0:0:0", SYMLINK+="before" | ||
498 | SUBSYSTEMS=="scsi", KERNELS=="*", SYMLINK+="scsi-0:0:0:0" | ||
499 | EOF | ||
500 | }, | ||
501 | { | ||
502 | desc => "KERNELS wildcard partial", | ||
503 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", | ||
504 | exp_name => "scsi-0:0:0:0", | ||
505 | rules => <<EOF | ||
506 | SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", SYMLINK+="before" | ||
507 | SUBSYSTEMS=="scsi", KERNELS=="*:0", SYMLINK+="scsi-0:0:0:0" | ||
508 | EOF | ||
509 | }, | ||
510 | { | ||
511 | desc => "KERNELS wildcard partial 2", | ||
512 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", | ||
513 | exp_name => "scsi-0:0:0:0", | ||
514 | rules => <<EOF | ||
515 | SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", SYMLINK+="before" | ||
516 | SUBSYSTEMS=="scsi", KERNELS=="*:0:0:0", SYMLINK+="scsi-0:0:0:0" | ||
517 | EOF | ||
518 | }, | ||
519 | { | ||
520 | desc => "substitute attr with link target value (first match)", | ||
521 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", | ||
522 | exp_name => "driver-is-sd", | ||
523 | rules => <<EOF | ||
524 | SUBSYSTEMS=="scsi", SYMLINK+="driver-is-\$attr{driver}" | ||
525 | EOF | ||
526 | }, | ||
527 | { | ||
528 | desc => "substitute attr with link target value (currently selected device)", | ||
529 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", | ||
530 | exp_name => "driver-is-ahci", | ||
531 | rules => <<EOF | ||
532 | SUBSYSTEMS=="pci", SYMLINK+="driver-is-\$attr{driver}" | ||
533 | EOF | ||
534 | }, | ||
535 | { | ||
536 | desc => "ignore ATTRS attribute whitespace", | ||
537 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", | ||
538 | exp_name => "ignored", | ||
539 | rules => <<EOF | ||
540 | SUBSYSTEMS=="scsi", ATTRS{whitespace_test}=="WHITE SPACE", SYMLINK+="ignored" | ||
541 | EOF | ||
542 | }, | ||
543 | { | ||
544 | desc => "do not ignore ATTRS attribute whitespace", | ||
545 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", | ||
546 | exp_name => "matched-with-space", | ||
547 | rules => <<EOF | ||
548 | SUBSYSTEMS=="scsi", ATTRS{whitespace_test}=="WHITE SPACE ", SYMLINK+="wrong-to-ignore" | ||
549 | SUBSYSTEMS=="scsi", ATTRS{whitespace_test}=="WHITE SPACE ", SYMLINK+="matched-with-space" | ||
550 | EOF | ||
551 | }, | ||
552 | { | ||
553 | desc => "permissions USER=bad GROUP=name", | ||
554 | devpath => "/devices/virtual/tty/tty33", | ||
555 | exp_name => "tty33", | ||
556 | exp_perms => "0:0:0600", | ||
557 | rules => <<EOF | ||
558 | KERNEL=="tty33", SYMLINK+="tty33", OWNER="bad", GROUP="name" | ||
559 | EOF | ||
560 | }, | ||
561 | { | ||
562 | desc => "permissions OWNER=5000", | ||
563 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", | ||
564 | exp_name => "node", | ||
565 | exp_perms => "5000::0600", | ||
566 | rules => <<EOF | ||
567 | SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", OWNER="5000" | ||
568 | EOF | ||
569 | }, | ||
570 | { | ||
571 | desc => "permissions GROUP=100", | ||
572 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", | ||
573 | exp_name => "node", | ||
574 | exp_perms => ":100:0660", | ||
575 | rules => <<EOF | ||
576 | SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", GROUP="100" | ||
577 | EOF | ||
578 | }, | ||
579 | { | ||
580 | desc => "textual user id", | ||
581 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", | ||
582 | exp_name => "node", | ||
583 | exp_perms => "nobody::0600", | ||
584 | rules => <<EOF | ||
585 | SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", OWNER="nobody" | ||
586 | EOF | ||
587 | }, | ||
588 | { | ||
589 | desc => "textual group id", | ||
590 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", | ||
591 | exp_name => "node", | ||
592 | exp_perms => ":daemon:0660", | ||
593 | rules => <<EOF | ||
594 | SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", GROUP="daemon" | ||
595 | EOF | ||
596 | }, | ||
597 | { | ||
598 | desc => "textual user/group id", | ||
599 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", | ||
600 | exp_name => "node", | ||
601 | exp_perms => "root:mail:0660", | ||
602 | rules => <<EOF | ||
603 | SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", OWNER="root", GROUP="mail" | ||
604 | EOF | ||
605 | }, | ||
606 | { | ||
607 | desc => "permissions MODE=0777", | ||
608 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", | ||
609 | exp_name => "node", | ||
610 | exp_perms => "::0777", | ||
611 | rules => <<EOF | ||
612 | SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", MODE="0777" | ||
613 | EOF | ||
614 | }, | ||
615 | { | ||
616 | desc => "permissions OWNER=5000 GROUP=100 MODE=0777", | ||
617 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", | ||
618 | exp_name => "node", | ||
619 | exp_perms => "5000:100:0777", | ||
620 | rules => <<EOF | ||
621 | SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", OWNER="5000", GROUP="100", MODE="0777" | ||
622 | EOF | ||
623 | }, | ||
624 | { | ||
625 | desc => "permissions OWNER to 5000", | ||
626 | devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", | ||
627 | exp_name => "ttyACM0", | ||
628 | exp_perms => "5000::", | ||
629 | rules => <<EOF | ||
630 | KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", OWNER="5000" | ||
631 | EOF | ||
632 | }, | ||
633 | { | ||
634 | desc => "permissions GROUP to 100", | ||
635 | devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", | ||
636 | exp_name => "ttyACM0", | ||
637 | exp_perms => ":100:0660", | ||
638 | rules => <<EOF | ||
639 | KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", GROUP="100" | ||
640 | EOF | ||
641 | }, | ||
642 | { | ||
643 | desc => "permissions MODE to 0060", | ||
644 | devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", | ||
645 | exp_name => "ttyACM0", | ||
646 | exp_perms => "::0060", | ||
647 | rules => <<EOF | ||
648 | KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", MODE="0060" | ||
649 | EOF | ||
650 | }, | ||
651 | { | ||
652 | desc => "permissions OWNER, GROUP, MODE", | ||
653 | devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", | ||
654 | exp_name => "ttyACM0", | ||
655 | exp_perms => "5000:100:0777", | ||
656 | rules => <<EOF | ||
657 | KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", OWNER="5000", GROUP="100", MODE="0777" | ||
658 | EOF | ||
659 | }, | ||
660 | { | ||
661 | desc => "permissions only rule", | ||
662 | devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", | ||
663 | exp_name => "ttyACM0", | ||
664 | exp_perms => "5000:100:0777", | ||
665 | rules => <<EOF | ||
666 | KERNEL=="ttyACM[0-9]*", OWNER="5000", GROUP="100", MODE="0777" | ||
667 | KERNEL=="ttyUSX[0-9]*", OWNER="5001", GROUP="101", MODE="0444" | ||
668 | KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n" | ||
669 | EOF | ||
670 | }, | ||
671 | { | ||
672 | desc => "multiple permissions only rule", | ||
673 | devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", | ||
674 | exp_name => "ttyACM0", | ||
675 | exp_perms => "3000:4000:0777", | ||
676 | rules => <<EOF | ||
677 | SUBSYSTEM=="tty", OWNER="3000" | ||
678 | SUBSYSTEM=="tty", GROUP="4000" | ||
679 | SUBSYSTEM=="tty", MODE="0777" | ||
680 | KERNEL=="ttyUSX[0-9]*", OWNER="5001", GROUP="101", MODE="0444" | ||
681 | KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n" | ||
682 | EOF | ||
683 | }, | ||
684 | { | ||
685 | desc => "permissions only rule with override at SYMLINK+ rule", | ||
686 | devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", | ||
687 | exp_name => "ttyACM0", | ||
688 | exp_perms => "3000:8000:0777", | ||
689 | rules => <<EOF | ||
690 | SUBSYSTEM=="tty", OWNER="3000" | ||
691 | SUBSYSTEM=="tty", GROUP="4000" | ||
692 | SUBSYSTEM=="tty", MODE="0777" | ||
693 | KERNEL=="ttyUSX[0-9]*", OWNER="5001", GROUP="101", MODE="0444" | ||
694 | KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", GROUP="8000" | ||
695 | EOF | ||
696 | }, | ||
697 | { | ||
698 | desc => "major/minor number test", | ||
699 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", | ||
700 | exp_name => "node", | ||
701 | exp_majorminor => "8:0", | ||
702 | rules => <<EOF | ||
703 | SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node" | ||
704 | EOF | ||
705 | }, | ||
706 | { | ||
707 | desc => "big major number test", | ||
708 | devpath => "/devices/virtual/misc/misc-fake1", | ||
709 | exp_name => "node", | ||
710 | exp_majorminor => "4095:1", | ||
711 | rules => <<EOF | ||
712 | KERNEL=="misc-fake1", SYMLINK+="node" | ||
713 | EOF | ||
714 | }, | ||
715 | { | ||
716 | desc => "big major and big minor number test", | ||
717 | devpath => "/devices/virtual/misc/misc-fake89999", | ||
718 | exp_name => "node", | ||
719 | exp_majorminor => "4095:89999", | ||
720 | rules => <<EOF | ||
721 | KERNEL=="misc-fake89999", SYMLINK+="node" | ||
722 | EOF | ||
723 | }, | ||
724 | { | ||
725 | desc => "multiple symlinks with format char", | ||
726 | devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", | ||
727 | exp_name => "symlink2-ttyACM0", | ||
728 | rules => <<EOF | ||
729 | KERNEL=="ttyACM[0-9]*", SYMLINK="symlink1-%n symlink2-%k symlink3-%b" | ||
730 | EOF | ||
731 | }, | ||
732 | { | ||
733 | desc => "multiple symlinks with a lot of s p a c e s", | ||
734 | devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", | ||
735 | exp_name => "one", | ||
736 | not_exp_name => " ", | ||
737 | rules => <<EOF | ||
738 | KERNEL=="ttyACM[0-9]*", SYMLINK=" one two " | ||
739 | EOF | ||
740 | }, | ||
741 | { | ||
742 | desc => "symlink creation (same directory)", | ||
743 | devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", | ||
744 | exp_name => "modem0", | ||
745 | rules => <<EOF | ||
746 | KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", SYMLINK="modem%n" | ||
747 | EOF | ||
748 | }, | ||
749 | { | ||
750 | desc => "multiple symlinks", | ||
751 | devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", | ||
752 | exp_name => "second-0" , | ||
753 | rules => <<EOF | ||
754 | KERNEL=="ttyACM0", SYMLINK="first-%n second-%n third-%n" | ||
755 | EOF | ||
756 | }, | ||
757 | { | ||
758 | desc => "symlink name '.'", | ||
759 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", | ||
760 | exp_name => ".", | ||
761 | exp_add_error => "yes", | ||
762 | exp_rem_error => "yes", | ||
763 | rules => <<EOF | ||
764 | SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="." | ||
765 | EOF | ||
766 | }, | ||
767 | { | ||
768 | desc => "symlink node to itself", | ||
769 | devpath => "/devices/virtual/tty/tty0", | ||
770 | exp_name => "link", | ||
771 | exp_add_error => "yes", | ||
772 | exp_rem_error => "yes", | ||
773 | option => "clean", | ||
774 | rules => <<EOF | ||
775 | KERNEL=="tty0", SYMLINK+="tty0" | ||
776 | EOF | ||
777 | }, | ||
778 | { | ||
779 | desc => "symlink %n substitution", | ||
780 | devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", | ||
781 | exp_name => "symlink0", | ||
782 | rules => <<EOF | ||
783 | KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", SYMLINK+="symlink%n" | ||
784 | EOF | ||
785 | }, | ||
786 | { | ||
787 | desc => "symlink %k substitution", | ||
788 | devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", | ||
789 | exp_name => "symlink-ttyACM0", | ||
790 | rules => <<EOF | ||
791 | KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", SYMLINK+="symlink-%k" | ||
792 | EOF | ||
793 | }, | ||
794 | { | ||
795 | desc => "symlink %M:%m substitution", | ||
796 | devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", | ||
797 | exp_name => "major-166:0", | ||
798 | rules => <<EOF | ||
799 | KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", SYMLINK+="major-%M:%m" | ||
800 | EOF | ||
801 | }, | ||
802 | { | ||
803 | desc => "symlink %b substitution", | ||
804 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", | ||
805 | exp_name => "symlink-0:0:0:0", | ||
806 | rules => <<EOF | ||
807 | SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="symlink-%b" | ||
808 | EOF | ||
809 | }, | ||
810 | { | ||
811 | desc => "symlink %c substitution", | ||
812 | devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", | ||
813 | exp_name => "test", | ||
814 | rules => <<EOF | ||
815 | KERNEL=="ttyACM[0-9]*", PROGRAM=="/bin/echo test", SYMLINK+="%c" | ||
816 | EOF | ||
817 | }, | ||
818 | { | ||
819 | desc => "symlink %c{N} substitution", | ||
820 | devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", | ||
821 | exp_name => "test", | ||
822 | rules => <<EOF | ||
823 | KERNEL=="ttyACM[0-9]*", PROGRAM=="/bin/echo symlink test this", SYMLINK+="%c{2}" | ||
824 | EOF | ||
825 | }, | ||
826 | { | ||
827 | desc => "symlink %c{N+} substitution", | ||
828 | devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", | ||
829 | exp_name => "this", | ||
830 | rules => <<EOF | ||
831 | KERNEL=="ttyACM[0-9]*", PROGRAM=="/bin/echo symlink test this", SYMLINK+="%c{2+}" | ||
832 | EOF | ||
833 | }, | ||
834 | { | ||
835 | desc => "symlink only rule with %c{N+}", | ||
836 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", | ||
837 | exp_name => "test", | ||
838 | rules => <<EOF | ||
839 | SUBSYSTEMS=="scsi", KERNEL=="sda", PROGRAM=="/bin/echo link test this" SYMLINK+="%c{2+}" | ||
840 | EOF | ||
841 | }, | ||
842 | { | ||
843 | desc => "symlink %s{filename} substitution", | ||
844 | devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", | ||
845 | exp_name => "166:0", | ||
846 | rules => <<EOF | ||
847 | KERNEL=="ttyACM[0-9]*", SYMLINK+="%s{dev}" | ||
848 | EOF | ||
849 | }, | ||
850 | { | ||
851 | desc => "program result substitution (numbered part of)", | ||
852 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5", | ||
853 | exp_name => "link1", | ||
854 | rules => <<EOF | ||
855 | SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n node link1 link2", RESULT=="node *", SYMLINK+="%c{2} %c{3}" | ||
856 | EOF | ||
857 | }, | ||
858 | { | ||
859 | desc => "program result substitution (numbered part of+)", | ||
860 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5", | ||
861 | exp_name => "link4", | ||
862 | rules => <<EOF | ||
863 | SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n node link1 link2 link3 link4", RESULT=="node *", SYMLINK+="%c{2+}" | ||
864 | EOF | ||
865 | }, | ||
866 | { | ||
867 | desc => "SUBSYSTEM match test", | ||
868 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", | ||
869 | exp_name => "node", | ||
870 | rules => <<EOF | ||
871 | SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="should_not_match", SUBSYSTEM=="vc" | ||
872 | SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", SUBSYSTEM=="block" | ||
873 | SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="should_not_match2", SUBSYSTEM=="vc" | ||
874 | EOF | ||
875 | }, | ||
876 | { | ||
877 | desc => "DRIVERS match test", | ||
878 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", | ||
879 | exp_name => "node", | ||
880 | rules => <<EOF | ||
881 | SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="should_not_match", DRIVERS=="sd-wrong" | ||
882 | SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", DRIVERS=="sd" | ||
883 | EOF | ||
884 | }, | ||
885 | { | ||
886 | desc => "devnode substitution test", | ||
887 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", | ||
888 | exp_name => "node", | ||
889 | rules => <<EOF | ||
890 | SUBSYSTEMS=="scsi", KERNEL=="sda", PROGRAM=="/usr/bin/test -b %N" SYMLINK+="node" | ||
891 | EOF | ||
892 | }, | ||
893 | { | ||
894 | desc => "parent node name substitution test", | ||
895 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1", | ||
896 | exp_name => "sda-part-1", | ||
897 | rules => <<EOF | ||
898 | SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="%P-part-1" | ||
899 | EOF | ||
900 | }, | ||
901 | { | ||
902 | desc => "udev_root substitution", | ||
903 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1", | ||
904 | exp_name => "start-udev-root-end", | ||
905 | rules => <<EOF | ||
906 | SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="start-%r-end" | ||
907 | EOF | ||
908 | }, | ||
909 | { | ||
910 | desc => "last_rule option", | ||
911 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1", | ||
912 | exp_name => "last", | ||
913 | rules => <<EOF | ||
914 | SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="last", OPTIONS="last_rule" | ||
915 | SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="very-last" | ||
916 | EOF | ||
917 | }, | ||
918 | { | ||
919 | desc => "negation KERNEL!=", | ||
920 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1", | ||
921 | exp_name => "match", | ||
922 | rules => <<EOF | ||
923 | SUBSYSTEMS=="scsi", KERNEL!="sda1", SYMLINK+="matches-but-is-negated" | ||
924 | SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="before" | ||
925 | SUBSYSTEMS=="scsi", KERNEL!="xsda1", SYMLINK+="match" | ||
926 | EOF | ||
927 | }, | ||
928 | { | ||
929 | desc => "negation SUBSYSTEM!=", | ||
930 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1", | ||
931 | exp_name => "not-anything", | ||
932 | rules => <<EOF | ||
933 | SUBSYSTEMS=="scsi", SUBSYSTEM=="block", KERNEL!="sda1", SYMLINK+="matches-but-is-negated" | ||
934 | SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="before" | ||
935 | SUBSYSTEMS=="scsi", SUBSYSTEM!="anything", SYMLINK+="not-anything" | ||
936 | EOF | ||
937 | }, | ||
938 | { | ||
939 | desc => "negation PROGRAM!= exit code", | ||
940 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1", | ||
941 | exp_name => "nonzero-program", | ||
942 | rules => <<EOF | ||
943 | SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="before" | ||
944 | KERNEL=="sda1", PROGRAM!="/bin/false", SYMLINK+="nonzero-program" | ||
945 | EOF | ||
946 | }, | ||
947 | { | ||
948 | desc => "test for whitespace between the operator", | ||
949 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1", | ||
950 | exp_name => "true", | ||
951 | rules => <<EOF | ||
952 | SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="before" | ||
953 | KERNEL == "sda1" , SYMLINK+ = "true" | ||
954 | EOF | ||
955 | }, | ||
956 | { | ||
957 | desc => "ENV{} test", | ||
958 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1", | ||
959 | exp_name => "true", | ||
960 | rules => <<EOF | ||
961 | ENV{ENV_KEY_TEST}="test" | ||
962 | SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ENV_KEY_TEST}=="go", SYMLINK+="wrong" | ||
963 | SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ENV_KEY_TEST}=="test", SYMLINK+="true" | ||
964 | SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ENV_KEY_TEST}=="bad", SYMLINK+="bad" | ||
965 | EOF | ||
966 | }, | ||
967 | { | ||
968 | desc => "ENV{} test", | ||
969 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1", | ||
970 | exp_name => "true", | ||
971 | rules => <<EOF | ||
972 | ENV{ENV_KEY_TEST}="test" | ||
973 | SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ENV_KEY_TEST}=="go", SYMLINK+="wrong" | ||
974 | SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ENV_KEY_TEST}=="yes", ENV{ACTION}=="add", ENV{DEVPATH}=="*/block/sda/sdax1", SYMLINK+="no" | ||
975 | SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ENV_KEY_TEST}=="test", ENV{ACTION}=="add", ENV{DEVPATH}=="*/block/sda/sda1", SYMLINK+="true" | ||
976 | SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ENV_KEY_TEST}=="bad", SYMLINK+="bad" | ||
977 | EOF | ||
978 | }, | ||
979 | { | ||
980 | desc => "ENV{} test (assign)", | ||
981 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1", | ||
982 | exp_name => "true", | ||
983 | rules => <<EOF | ||
984 | SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ASSIGN}="true" | ||
985 | SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ASSIGN}=="yes", SYMLINK+="no" | ||
986 | SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="before" | ||
987 | SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ASSIGN}=="true", SYMLINK+="true" | ||
988 | EOF | ||
989 | }, | ||
990 | { | ||
991 | desc => "ENV{} test (assign 2 times)", | ||
992 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1", | ||
993 | exp_name => "true", | ||
994 | rules => <<EOF | ||
995 | SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ASSIGN}="true" | ||
996 | SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ASSIGN}="absolutely-\$env{ASSIGN}" | ||
997 | SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="before" | ||
998 | SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ASSIGN}=="yes", SYMLINK+="no" | ||
999 | SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ASSIGN}=="absolutely-true", SYMLINK+="true" | ||
1000 | EOF | ||
1001 | }, | ||
1002 | { | ||
1003 | desc => "ENV{} test (assign2)", | ||
1004 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1", | ||
1005 | exp_name => "part", | ||
1006 | rules => <<EOF | ||
1007 | SUBSYSTEM=="block", KERNEL=="*[0-9]", ENV{PARTITION}="true", ENV{MAINDEVICE}="false" | ||
1008 | SUBSYSTEM=="block", KERNEL=="*[!0-9]", ENV{PARTITION}="false", ENV{MAINDEVICE}="true" | ||
1009 | ENV{MAINDEVICE}=="true", SYMLINK+="disk" | ||
1010 | SUBSYSTEM=="block", SYMLINK+="before" | ||
1011 | ENV{PARTITION}=="true", SYMLINK+="part" | ||
1012 | EOF | ||
1013 | }, | ||
1014 | { | ||
1015 | desc => "untrusted string sanitize", | ||
1016 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1", | ||
1017 | exp_name => "sane", | ||
1018 | rules => <<EOF | ||
1019 | SUBSYSTEMS=="scsi", KERNEL=="sda1", PROGRAM=="/bin/echo -e name; (/usr/bin/badprogram)", RESULT=="name_ _/usr/bin/badprogram_", SYMLINK+="sane" | ||
1020 | EOF | ||
1021 | }, | ||
1022 | { | ||
1023 | desc => "untrusted string sanitize (don't replace utf8)", | ||
1024 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1", | ||
1025 | exp_name => "uber", | ||
1026 | rules => <<EOF | ||
1027 | SUBSYSTEMS=="scsi", KERNEL=="sda1", PROGRAM=="/bin/echo -e \\xc3\\xbcber" RESULT=="\xc3\xbcber", SYMLINK+="uber" | ||
1028 | EOF | ||
1029 | }, | ||
1030 | { | ||
1031 | desc => "untrusted string sanitize (replace invalid utf8)", | ||
1032 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1", | ||
1033 | exp_name => "replaced", | ||
1034 | rules => <<EOF | ||
1035 | SUBSYSTEMS=="scsi", KERNEL=="sda1", PROGRAM=="/bin/echo -e \\xef\\xe8garbage", RESULT=="__garbage", SYMLINK+="replaced" | ||
1036 | EOF | ||
1037 | }, | ||
1038 | { | ||
1039 | desc => "read sysfs value from parent device", | ||
1040 | devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", | ||
1041 | exp_name => "serial-354172020305000", | ||
1042 | rules => <<EOF | ||
1043 | KERNEL=="ttyACM*", ATTRS{serial}=="?*", SYMLINK+="serial-%s{serial}" | ||
1044 | EOF | ||
1045 | }, | ||
1046 | { | ||
1047 | desc => "match against empty key string", | ||
1048 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", | ||
1049 | exp_name => "ok", | ||
1050 | rules => <<EOF | ||
1051 | KERNEL=="sda", ATTRS{nothing}!="", SYMLINK+="not-1-ok" | ||
1052 | KERNEL=="sda", ATTRS{nothing}=="", SYMLINK+="not-2-ok" | ||
1053 | KERNEL=="sda", ATTRS{vendor}!="", SYMLINK+="ok" | ||
1054 | KERNEL=="sda", ATTRS{vendor}=="", SYMLINK+="not-3-ok" | ||
1055 | EOF | ||
1056 | }, | ||
1057 | { | ||
1058 | desc => "check ACTION value", | ||
1059 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", | ||
1060 | exp_name => "ok", | ||
1061 | rules => <<EOF | ||
1062 | ACTION=="unknown", KERNEL=="sda", SYMLINK+="unknown-not-ok" | ||
1063 | ACTION=="add", KERNEL=="sda", SYMLINK+="ok" | ||
1064 | EOF | ||
1065 | }, | ||
1066 | { | ||
1067 | desc => "final assignment", | ||
1068 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", | ||
1069 | exp_name => "ok", | ||
1070 | exp_perms => "root:tty:0640", | ||
1071 | rules => <<EOF | ||
1072 | KERNEL=="sda", GROUP:="tty" | ||
1073 | KERNEL=="sda", GROUP="not-ok", MODE="0640", SYMLINK+="ok" | ||
1074 | EOF | ||
1075 | }, | ||
1076 | { | ||
1077 | desc => "final assignment 2", | ||
1078 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", | ||
1079 | exp_name => "ok", | ||
1080 | exp_perms => "root:tty:0640", | ||
1081 | rules => <<EOF | ||
1082 | KERNEL=="sda", GROUP:="tty" | ||
1083 | SUBSYSTEM=="block", MODE:="640" | ||
1084 | KERNEL=="sda", GROUP="not-ok", MODE="0666", SYMLINK+="ok" | ||
1085 | EOF | ||
1086 | }, | ||
1087 | { | ||
1088 | desc => "env substitution", | ||
1089 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", | ||
1090 | exp_name => "node-add-me", | ||
1091 | rules => <<EOF | ||
1092 | KERNEL=="sda", MODE="0666", SYMLINK+="node-\$env{ACTION}-me" | ||
1093 | EOF | ||
1094 | }, | ||
1095 | { | ||
1096 | desc => "reset list to current value", | ||
1097 | devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", | ||
1098 | exp_name => "three", | ||
1099 | not_exp_name => "two", | ||
1100 | rules => <<EOF | ||
1101 | KERNEL=="ttyACM[0-9]*", SYMLINK+="one" | ||
1102 | KERNEL=="ttyACM[0-9]*", SYMLINK+="two" | ||
1103 | KERNEL=="ttyACM[0-9]*", SYMLINK="three" | ||
1104 | EOF | ||
1105 | }, | ||
1106 | { | ||
1107 | desc => "test empty SYMLINK+ (empty override)", | ||
1108 | devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", | ||
1109 | exp_name => "right", | ||
1110 | not_exp_name => "wrong", | ||
1111 | rules => <<EOF | ||
1112 | KERNEL=="ttyACM[0-9]*", SYMLINK+="wrong" | ||
1113 | KERNEL=="ttyACM[0-9]*", SYMLINK="" | ||
1114 | KERNEL=="ttyACM[0-9]*", SYMLINK+="right" | ||
1115 | EOF | ||
1116 | }, | ||
1117 | { | ||
1118 | desc => "test multi matches", | ||
1119 | devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", | ||
1120 | exp_name => "right", | ||
1121 | rules => <<EOF | ||
1122 | KERNEL=="ttyACM*", SYMLINK+="before" | ||
1123 | KERNEL=="ttyACM*|nothing", SYMLINK+="right" | ||
1124 | EOF | ||
1125 | }, | ||
1126 | { | ||
1127 | desc => "test multi matches 2", | ||
1128 | devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", | ||
1129 | exp_name => "right", | ||
1130 | rules => <<EOF | ||
1131 | KERNEL=="dontknow*|*nothing", SYMLINK+="nomatch" | ||
1132 | KERNEL=="ttyACM*", SYMLINK+="before" | ||
1133 | KERNEL=="dontknow*|ttyACM*|nothing*", SYMLINK+="right" | ||
1134 | EOF | ||
1135 | }, | ||
1136 | { | ||
1137 | desc => "test multi matches 3", | ||
1138 | devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", | ||
1139 | exp_name => "right", | ||
1140 | rules => <<EOF | ||
1141 | KERNEL=="dontknow|nothing", SYMLINK+="nomatch" | ||
1142 | KERNEL=="dontknow|ttyACM0a|nothing|attyACM0", SYMLINK+="wrong1" | ||
1143 | KERNEL=="X|attyACM0|dontknow|ttyACM0a|nothing|attyACM0", SYMLINK+="wrong2" | ||
1144 | KERNEL=="dontknow|ttyACM0|nothing", SYMLINK+="right" | ||
1145 | EOF | ||
1146 | }, | ||
1147 | { | ||
1148 | desc => "test multi matches 4", | ||
1149 | devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0", | ||
1150 | exp_name => "right", | ||
1151 | rules => <<EOF | ||
1152 | KERNEL=="dontknow|nothing", SYMLINK+="nomatch" | ||
1153 | KERNEL=="dontknow|ttyACM0a|nothing|attyACM0", SYMLINK+="wrong1" | ||
1154 | KERNEL=="X|attyACM0|dontknow|ttyACM0a|nothing|attyACM0", SYMLINK+="wrong2" | ||
1155 | KERNEL=="all|dontknow|ttyACM0", SYMLINK+="right" | ||
1156 | KERNEL=="ttyACM0a|nothing", SYMLINK+="wrong3" | ||
1157 | EOF | ||
1158 | }, | ||
1159 | { | ||
1160 | desc => "IMPORT parent test sequence 1/2 (keep)", | ||
1161 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", | ||
1162 | exp_name => "parent", | ||
1163 | option => "keep", | ||
1164 | rules => <<EOF | ||
1165 | KERNEL=="sda", IMPORT{program}="/bin/echo -e \'PARENT_KEY=parent_right\\nWRONG_PARENT_KEY=parent_wrong'" | ||
1166 | KERNEL=="sda", SYMLINK+="parent" | ||
1167 | EOF | ||
1168 | }, | ||
1169 | { | ||
1170 | desc => "IMPORT parent test sequence 2/2 (keep)", | ||
1171 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1", | ||
1172 | exp_name => "parentenv-parent_right", | ||
1173 | option => "clean", | ||
1174 | rules => <<EOF | ||
1175 | KERNEL=="sda1", IMPORT{parent}="PARENT*", SYMLINK+="parentenv-\$env{PARENT_KEY}\$env{WRONG_PARENT_KEY}" | ||
1176 | EOF | ||
1177 | }, | ||
1178 | { | ||
1179 | desc => "GOTO test", | ||
1180 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1", | ||
1181 | exp_name => "right", | ||
1182 | rules => <<EOF | ||
1183 | KERNEL=="sda1", GOTO="TEST" | ||
1184 | KERNEL=="sda1", SYMLINK+="wrong" | ||
1185 | KERNEL=="sda1", GOTO="BAD" | ||
1186 | KERNEL=="sda1", SYMLINK+="", LABEL="NO" | ||
1187 | KERNEL=="sda1", SYMLINK+="right", LABEL="TEST", GOTO="end" | ||
1188 | KERNEL=="sda1", SYMLINK+="wrong2", LABEL="BAD" | ||
1189 | LABEL="end" | ||
1190 | EOF | ||
1191 | }, | ||
1192 | { | ||
1193 | desc => "GOTO label does not exist", | ||
1194 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1", | ||
1195 | exp_name => "right", | ||
1196 | rules => <<EOF | ||
1197 | KERNEL=="sda1", GOTO="does-not-exist" | ||
1198 | KERNEL=="sda1", SYMLINK+="right", | ||
1199 | LABEL="exists" | ||
1200 | EOF | ||
1201 | }, | ||
1202 | { | ||
1203 | desc => "SYMLINK+ compare test", | ||
1204 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1", | ||
1205 | exp_name => "right", | ||
1206 | not_exp_name => "wrong", | ||
1207 | rules => <<EOF | ||
1208 | KERNEL=="sda1", SYMLINK+="link" | ||
1209 | KERNEL=="sda1", SYMLINK=="link*", SYMLINK+="right" | ||
1210 | KERNEL=="sda1", SYMLINK=="nolink*", SYMLINK+="wrong" | ||
1211 | EOF | ||
1212 | }, | ||
1213 | { | ||
1214 | desc => "invalid key operation", | ||
1215 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1", | ||
1216 | exp_name => "yes", | ||
1217 | rules => <<EOF | ||
1218 | KERNEL="sda1", SYMLINK+="no" | ||
1219 | KERNEL=="sda1", SYMLINK+="yes" | ||
1220 | EOF | ||
1221 | }, | ||
1222 | { | ||
1223 | desc => "operator chars in attribute", | ||
1224 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", | ||
1225 | exp_name => "yes", | ||
1226 | rules => <<EOF | ||
1227 | KERNEL=="sda", ATTR{test:colon+plus}=="?*", SYMLINK+="yes" | ||
1228 | EOF | ||
1229 | }, | ||
1230 | { | ||
1231 | desc => "overlong comment line", | ||
1232 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1", | ||
1233 | exp_name => "yes", | ||
1234 | rules => <<EOF | ||
1235 | # 012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 | ||
1236 | # 012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 | ||
1237 | KERNEL=="sda1", SYMLINK+=="no" | ||
1238 | KERNEL=="sda1", SYMLINK+="yes" | ||
1239 | EOF | ||
1240 | }, | ||
1241 | { | ||
1242 | desc => "magic subsys/kernel lookup", | ||
1243 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", | ||
1244 | exp_name => "00:16:41:e2:8d:ff", | ||
1245 | rules => <<EOF | ||
1246 | KERNEL=="sda", SYMLINK+="\$attr{[net/eth0]address}" | ||
1247 | EOF | ||
1248 | }, | ||
1249 | { | ||
1250 | desc => "TEST absolute path", | ||
1251 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", | ||
1252 | exp_name => "there", | ||
1253 | rules => <<EOF | ||
1254 | TEST=="/etc/hosts", SYMLINK+="there" | ||
1255 | TEST!="/etc/hosts", SYMLINK+="notthere" | ||
1256 | EOF | ||
1257 | }, | ||
1258 | { | ||
1259 | desc => "TEST subsys/kernel lookup", | ||
1260 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", | ||
1261 | exp_name => "yes", | ||
1262 | rules => <<EOF | ||
1263 | KERNEL=="sda", TEST=="[net/eth0]", SYMLINK+="yes" | ||
1264 | EOF | ||
1265 | }, | ||
1266 | { | ||
1267 | desc => "TEST relative path", | ||
1268 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", | ||
1269 | exp_name => "relative", | ||
1270 | rules => <<EOF | ||
1271 | KERNEL=="sda", TEST=="size", SYMLINK+="relative" | ||
1272 | EOF | ||
1273 | }, | ||
1274 | { | ||
1275 | desc => "TEST wildcard substitution (find queue/nr_requests)", | ||
1276 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", | ||
1277 | exp_name => "found-subdir", | ||
1278 | rules => <<EOF | ||
1279 | KERNEL=="sda", TEST=="*/nr_requests", SYMLINK+="found-subdir" | ||
1280 | EOF | ||
1281 | }, | ||
1282 | { | ||
1283 | desc => "TEST MODE=0000", | ||
1284 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", | ||
1285 | exp_name => "sda", | ||
1286 | exp_perms => "0:0:0000", | ||
1287 | exp_rem_error => "yes", | ||
1288 | rules => <<EOF | ||
1289 | KERNEL=="sda", MODE="0000" | ||
1290 | EOF | ||
1291 | }, | ||
1292 | { | ||
1293 | desc => "TEST PROGRAM feeds OWNER, GROUP, MODE", | ||
1294 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", | ||
1295 | exp_name => "sda", | ||
1296 | exp_perms => "5000:100:0400", | ||
1297 | exp_rem_error => "yes", | ||
1298 | rules => <<EOF | ||
1299 | KERNEL=="sda", MODE="666" | ||
1300 | KERNEL=="sda", PROGRAM=="/bin/echo 5000 100 0400", OWNER="%c{1}", GROUP="%c{2}", MODE="%c{3}" | ||
1301 | EOF | ||
1302 | }, | ||
1303 | { | ||
1304 | desc => "TEST PROGRAM feeds MODE with overflow", | ||
1305 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", | ||
1306 | exp_name => "sda", | ||
1307 | exp_perms => "0:0:0440", | ||
1308 | exp_rem_error => "yes", | ||
1309 | rules => <<EOF | ||
1310 | KERNEL=="sda", MODE="440" | ||
1311 | KERNEL=="sda", PROGRAM=="/bin/echo 0 0 0400letsdoabuffferoverflow0123456789012345789012345678901234567890", OWNER="%c{1}", GROUP="%c{2}", MODE="%c{3}" | ||
1312 | EOF | ||
1313 | }, | ||
1314 | { | ||
1315 | desc => "magic [subsys/sysname] attribute substitution", | ||
1316 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", | ||
1317 | exp_name => "sda-8741C4G-end", | ||
1318 | exp_perms => "0:0:0600", | ||
1319 | rules => <<EOF | ||
1320 | KERNEL=="sda", PROGRAM="/bin/true create-envp" | ||
1321 | KERNEL=="sda", ENV{TESTENV}="change-envp" | ||
1322 | KERNEL=="sda", SYMLINK+="%k-%s{[dmi/id]product_name}-end" | ||
1323 | EOF | ||
1324 | }, | ||
1325 | { | ||
1326 | desc => "builtin path_id", | ||
1327 | devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda", | ||
1328 | exp_name => "disk/by-path/pci-0000:00:1f.2-scsi-0:0:0:0", | ||
1329 | rules => <<EOF | ||
1330 | KERNEL=="sda", IMPORT{builtin}="path_id" | ||
1331 | KERNEL=="sda", ENV{ID_PATH}=="?*", SYMLINK+="disk/by-path/\$env{ID_PATH}" | ||
1332 | EOF | ||
1333 | }, | ||
1334 | ); | ||
1335 | |||
1336 | # set env | ||
1337 | $ENV{UDEV_CONFIG_FILE} = $udev_conf; | ||
1338 | |||
1339 | sub udev { | ||
1340 | my ($action, $devpath, $rules) = @_; | ||
1341 | |||
1342 | # create temporary rules | ||
1343 | open CONF, ">$udev_rules" || die "unable to create rules file: $udev_rules"; | ||
1344 | print CONF $$rules; | ||
1345 | close CONF; | ||
1346 | |||
1347 | if ($valgrind > 0) { | ||
1348 | system("$udev_bin_valgrind $action $devpath"); | ||
1349 | } else { | ||
1350 | system("$udev_bin $action $devpath"); | ||
1351 | } | ||
1352 | } | ||
1353 | |||
1354 | my $error = 0; | ||
1355 | |||
1356 | sub permissions_test { | ||
1357 | my($rules, $uid, $gid, $mode) = @_; | ||
1358 | |||
1359 | my $wrong = 0; | ||
1360 | my $userid; | ||
1361 | my $groupid; | ||
1362 | |||
1363 | $rules->{exp_perms} =~ m/^(.*):(.*):(.*)$/; | ||
1364 | if ($1 ne "") { | ||
1365 | if (defined(getpwnam($1))) { | ||
1366 | $userid = int(getpwnam($1)); | ||
1367 | } else { | ||
1368 | $userid = $1; | ||
1369 | } | ||
1370 | if ($uid != $userid) { $wrong = 1; } | ||
1371 | } | ||
1372 | if ($2 ne "") { | ||
1373 | if (defined(getgrnam($2))) { | ||
1374 | $groupid = int(getgrnam($2)); | ||
1375 | } else { | ||
1376 | $groupid = $2; | ||
1377 | } | ||
1378 | if ($gid != $groupid) { $wrong = 1; } | ||
1379 | } | ||
1380 | if ($3 ne "") { | ||
1381 | if (($mode & 07777) != oct($3)) { $wrong = 1; }; | ||
1382 | } | ||
1383 | if ($wrong == 0) { | ||
1384 | print "permissions: ok\n"; | ||
1385 | } else { | ||
1386 | printf " expected permissions are: %s:%s:%#o\n", $1, $2, oct($3); | ||
1387 | printf " created permissions are : %i:%i:%#o\n", $uid, $gid, $mode & 07777; | ||
1388 | print "permissions: error\n"; | ||
1389 | $error++; | ||
1390 | sleep(1); | ||
1391 | } | ||
1392 | } | ||
1393 | |||
1394 | sub major_minor_test { | ||
1395 | my($rules, $rdev) = @_; | ||
1396 | |||
1397 | my $major = ($rdev >> 8) & 0xfff; | ||
1398 | my $minor = ($rdev & 0xff) | (($rdev >> 12) & 0xfff00); | ||
1399 | my $wrong = 0; | ||
1400 | |||
1401 | $rules->{exp_majorminor} =~ m/^(.*):(.*)$/; | ||
1402 | if ($1 ne "") { | ||
1403 | if ($major != $1) { $wrong = 1; }; | ||
1404 | } | ||
1405 | if ($2 ne "") { | ||
1406 | if ($minor != $2) { $wrong = 1; }; | ||
1407 | } | ||
1408 | if ($wrong == 0) { | ||
1409 | print "major:minor: ok\n"; | ||
1410 | } else { | ||
1411 | printf " expected major:minor is: %i:%i\n", $1, $2; | ||
1412 | printf " created major:minor is : %i:%i\n", $major, $minor; | ||
1413 | print "major:minor: error\n"; | ||
1414 | $error++; | ||
1415 | sleep(1); | ||
1416 | } | ||
1417 | } | ||
1418 | |||
1419 | sub make_udev_root { | ||
1420 | system("rm -rf $udev_root"); | ||
1421 | mkdir($udev_root) || die "unable to create udev_root: $udev_root\n"; | ||
1422 | # setting group and mode of udev_root ensures the tests work | ||
1423 | # even if the parent directory has setgid bit enabled. | ||
1424 | chown (0, 0, $udev_root) || die "unable to chown $udev_root\n"; | ||
1425 | chmod (0755, $udev_root) || die "unable to chmod $udev_root\n"; | ||
1426 | } | ||
1427 | |||
1428 | sub run_test { | ||
1429 | my ($rules, $number) = @_; | ||
1430 | |||
1431 | print "TEST $number: $rules->{desc}\n"; | ||
1432 | print "device \'$rules->{devpath}\' expecting node/link \'$rules->{exp_name}\'\n"; | ||
1433 | |||
1434 | udev("add", $rules->{devpath}, \$rules->{rules}); | ||
1435 | if (defined($rules->{not_exp_name})) { | ||
1436 | if ((-e "$PWD/$udev_root/$rules->{not_exp_name}") || | ||
1437 | (-l "$PWD/$udev_root/$rules->{not_exp_name}")) { | ||
1438 | print "nonexistent: error \'$rules->{not_exp_name}\' not expected to be there\n"; | ||
1439 | $error++; | ||
1440 | sleep(1); | ||
1441 | } | ||
1442 | } | ||
1443 | |||
1444 | if ((-e "$PWD/$udev_root/$rules->{exp_name}") || | ||
1445 | (-l "$PWD/$udev_root/$rules->{exp_name}")) { | ||
1446 | |||
1447 | my ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size, | ||
1448 | $atime, $mtime, $ctime, $blksize, $blocks) = stat("$PWD/$udev_root/$rules->{exp_name}"); | ||
1449 | |||
1450 | if (defined($rules->{exp_perms})) { | ||
1451 | permissions_test($rules, $uid, $gid, $mode); | ||
1452 | } | ||
1453 | if (defined($rules->{exp_majorminor})) { | ||
1454 | major_minor_test($rules, $rdev); | ||
1455 | } | ||
1456 | print "add: ok\n"; | ||
1457 | } else { | ||
1458 | print "add: error"; | ||
1459 | if ($rules->{exp_add_error}) { | ||
1460 | print " as expected\n"; | ||
1461 | } else { | ||
1462 | print "\n"; | ||
1463 | system("tree $udev_root"); | ||
1464 | print "\n"; | ||
1465 | $error++; | ||
1466 | sleep(1); | ||
1467 | } | ||
1468 | } | ||
1469 | |||
1470 | if (defined($rules->{option}) && $rules->{option} eq "keep") { | ||
1471 | print "\n\n"; | ||
1472 | return; | ||
1473 | } | ||
1474 | |||
1475 | udev("remove", $rules->{devpath}, \$rules->{rules}); | ||
1476 | if ((-e "$PWD/$udev_root/$rules->{exp_name}") || | ||
1477 | (-l "$PWD/$udev_root/$rules->{exp_name}")) { | ||
1478 | print "remove: error"; | ||
1479 | if ($rules->{exp_rem_error}) { | ||
1480 | print " as expected\n"; | ||
1481 | } else { | ||
1482 | print "\n"; | ||
1483 | system("tree $udev_root"); | ||
1484 | print "\n"; | ||
1485 | $error++; | ||
1486 | sleep(1); | ||
1487 | } | ||
1488 | } else { | ||
1489 | print "remove: ok\n"; | ||
1490 | } | ||
1491 | |||
1492 | print "\n"; | ||
1493 | |||
1494 | if (defined($rules->{option}) && $rules->{option} eq "clean") { | ||
1495 | make_udev_root(); | ||
1496 | } | ||
1497 | |||
1498 | } | ||
1499 | |||
1500 | # only run if we have root permissions | ||
1501 | # due to mknod restrictions | ||
1502 | if (!($<==0)) { | ||
1503 | print "Must have root permissions to run properly.\n"; | ||
1504 | exit; | ||
1505 | } | ||
1506 | |||
1507 | # prepare | ||
1508 | make_udev_root(); | ||
1509 | |||
1510 | # create config file | ||
1511 | open CONF, ">$udev_conf" || die "unable to create config file: $udev_conf"; | ||
1512 | print CONF "udev_root=\"$udev_root\"\n"; | ||
1513 | print CONF "udev_run=\"$udev_root/.udev\"\n"; | ||
1514 | print CONF "udev_sys=\"$sysfs\"\n"; | ||
1515 | print CONF "udev_rules=\"$PWD\"\n"; | ||
1516 | print CONF "udev_log=\"err\"\n"; | ||
1517 | close CONF; | ||
1518 | |||
1519 | my $test_num = 1; | ||
1520 | my @list; | ||
1521 | |||
1522 | foreach my $arg (@ARGV) { | ||
1523 | if ($arg =~ m/--valgrind/) { | ||
1524 | $valgrind = 1; | ||
1525 | printf("using valgrind\n"); | ||
1526 | } else { | ||
1527 | push(@list, $arg); | ||
1528 | } | ||
1529 | } | ||
1530 | |||
1531 | if ($list[0]) { | ||
1532 | foreach my $arg (@list) { | ||
1533 | if (defined($tests[$arg-1]->{desc})) { | ||
1534 | print "udev-test will run test number $arg:\n\n"; | ||
1535 | run_test($tests[$arg-1], $arg); | ||
1536 | } else { | ||
1537 | print "test does not exist.\n"; | ||
1538 | } | ||
1539 | } | ||
1540 | } else { | ||
1541 | # test all | ||
1542 | print "\nudev-test will run ".($#tests + 1)." tests:\n\n"; | ||
1543 | |||
1544 | foreach my $rules (@tests) { | ||
1545 | run_test($rules, $test_num); | ||
1546 | $test_num++; | ||
1547 | } | ||
1548 | } | ||
1549 | |||
1550 | print "$error errors occured\n\n"; | ||
1551 | |||
1552 | # cleanup | ||
1553 | system("rm -rf $udev_root"); | ||
1554 | unlink($udev_rules); | ||
1555 | unlink($udev_conf); | ||
1556 | |||
1557 | if ($error > 0) { | ||
1558 | exit(1); | ||
1559 | } | ||
1560 | exit(0); | ||