summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKay Sievers <kay.sievers@vrfy.org>2012-04-03 21:08:04 +0200
committerKay Sievers <kay.sievers@vrfy.org>2012-04-03 21:08:04 +0200
commit19c5f19d69bb5f520fa7213239490c55de06d99d (patch)
tree0066ff6b95da3b86812f72f771fd09bab25d4e7a
parent3eff4208ffecedd778fec260f0d4b18e94dab443 (diff)
parent4db539b27021dcaa716828cbb689f591adb5af23 (diff)
import udev repository
-rw-r--r--src/udev/.gitignore40
-rw-r--r--src/udev/.vimrc4
-rw-r--r--src/udev/COPYING339
-rw-r--r--src/udev/ChangeLog6387
-rw-r--r--src/udev/INSTALL44
-rw-r--r--src/udev/Makefile.am712
-rw-r--r--src/udev/NEWS1735
-rw-r--r--src/udev/README101
-rw-r--r--src/udev/TODO22
-rwxr-xr-xsrc/udev/autogen.sh44
-rw-r--r--src/udev/configure.ac242
-rw-r--r--src/udev/m4/.gitignore4
-rw-r--r--src/udev/rules/42-usb-hid-pm.rules49
-rw-r--r--src/udev/rules/50-udev-default.rules107
-rw-r--r--src/udev/rules/60-persistent-alsa.rules14
-rw-r--r--src/udev/rules/60-persistent-input.rules38
-rw-r--r--src/udev/rules/60-persistent-serial.rules20
-rw-r--r--src/udev/rules/60-persistent-storage-tape.rules25
-rw-r--r--src/udev/rules/60-persistent-storage.rules89
-rw-r--r--src/udev/rules/75-net-description.rules14
-rw-r--r--src/udev/rules/75-tty-description.rules14
-rw-r--r--src/udev/rules/78-sound-card.rules89
-rw-r--r--src/udev/rules/80-drivers.rules12
-rw-r--r--src/udev/rules/95-udev-late.rules4
-rw-r--r--src/udev/src/.gitignore5
-rw-r--r--src/udev/src/COPYING502
-rw-r--r--src/udev/src/accelerometer/61-accelerometer.rules3
-rw-r--r--src/udev/src/accelerometer/accelerometer.c357
-rw-r--r--src/udev/src/ata_id/ata_id.c721
-rw-r--r--src/udev/src/cdrom_id/60-cdrom_id.rules20
-rw-r--r--src/udev/src/cdrom_id/cdrom_id.c1099
-rw-r--r--src/udev/src/collect/collect.c473
-rw-r--r--src/udev/src/docs/.gitignore17
-rw-r--r--src/udev/src/docs/Makefile.am99
-rw-r--r--src/udev/src/docs/libudev-docs.xml32
-rw-r--r--src/udev/src/docs/libudev-sections.txt127
-rw-r--r--src/udev/src/docs/libudev.types0
-rw-r--r--src/udev/src/docs/version.xml.in1
-rw-r--r--src/udev/src/floppy/60-floppy.rules4
-rw-r--r--src/udev/src/floppy/create_floppy_devices.c177
-rw-r--r--src/udev/src/gudev/.gitignore9
-rw-r--r--src/udev/src/gudev/COPYING502
-rw-r--r--src/udev/src/gudev/docs/.gitignore16
-rw-r--r--src/udev/src/gudev/docs/Makefile.am106
-rw-r--r--src/udev/src/gudev/docs/gudev-docs.xml93
-rw-r--r--src/udev/src/gudev/docs/gudev-sections.txt113
-rw-r--r--src/udev/src/gudev/docs/gudev.types4
-rw-r--r--src/udev/src/gudev/docs/version.xml.in1
-rwxr-xr-xsrc/udev/src/gudev/gjs-example.js75
-rw-r--r--src/udev/src/gudev/gudev-1.0.pc.in11
-rw-r--r--src/udev/src/gudev/gudev.h33
-rw-r--r--src/udev/src/gudev/gudevclient.c527
-rw-r--r--src/udev/src/gudev/gudevclient.h100
-rw-r--r--src/udev/src/gudev/gudevdevice.c963
-rw-r--r--src/udev/src/gudev/gudevdevice.h128
-rw-r--r--src/udev/src/gudev/gudevenumerator.c431
-rw-r--r--src/udev/src/gudev/gudevenumerator.h107
-rw-r--r--src/udev/src/gudev/gudevenums.h49
-rw-r--r--src/udev/src/gudev/gudevenumtypes.c.template39
-rw-r--r--src/udev/src/gudev/gudevenumtypes.h.template24
-rw-r--r--src/udev/src/gudev/gudevmarshal.list1
-rw-r--r--src/udev/src/gudev/gudevprivate.h41
-rw-r--r--src/udev/src/gudev/gudevtypes.h51
-rwxr-xr-xsrc/udev/src/gudev/seed-example-enum.js38
-rwxr-xr-xsrc/udev/src/gudev/seed-example.js72
-rw-r--r--src/udev/src/keymap/.gitignore5
-rw-r--r--src/udev/src/keymap/95-keyboard-force-release.rules54
-rw-r--r--src/udev/src/keymap/95-keymap.rules170
-rw-r--r--src/udev/src/keymap/README.keymap.txt101
-rwxr-xr-xsrc/udev/src/keymap/check-keymaps.sh38
-rwxr-xr-xsrc/udev/src/keymap/findkeyboards68
-rw-r--r--src/udev/src/keymap/force-release-maps/common-volume-keys3
-rw-r--r--src/udev/src/keymap/force-release-maps/dell-touchpad1
-rw-r--r--src/udev/src/keymap/force-release-maps/hp-other3
-rw-r--r--src/udev/src/keymap/force-release-maps/samsung-90x3a6
-rw-r--r--src/udev/src/keymap/force-release-maps/samsung-other10
-rwxr-xr-xsrc/udev/src/keymap/keyboard-force-release.sh.in22
-rw-r--r--src/udev/src/keymap/keymap.c447
-rw-r--r--src/udev/src/keymap/keymaps/acer22
-rw-r--r--src/udev/src/keymap/keymaps/acer-aspire_57204
-rw-r--r--src/udev/src/keymap/keymaps/acer-aspire_5920g5
-rw-r--r--src/udev/src/keymap/keymaps/acer-aspire_69205
-rw-r--r--src/udev/src/keymap/keymaps/acer-aspire_89305
-rw-r--r--src/udev/src/keymap/keymaps/acer-travelmate_c3005
-rw-r--r--src/udev/src/keymap/keymaps/asus3
-rw-r--r--src/udev/src/keymap/keymaps/compaq-e_evo4
-rw-r--r--src/udev/src/keymap/keymaps/dell29
-rw-r--r--src/udev/src/keymap/keymaps/dell-latitude-xt24
-rw-r--r--src/udev/src/keymap/keymaps/everex-xt50007
-rw-r--r--src/udev/src/keymap/keymaps/fujitsu-amilo_li_27323
-rw-r--r--src/udev/src/keymap/keymaps/fujitsu-amilo_pa_25483
-rw-r--r--src/udev/src/keymap/keymaps/fujitsu-amilo_pro_edition_v35054
-rw-r--r--src/udev/src/keymap/keymaps/fujitsu-amilo_pro_v32052
-rw-r--r--src/udev/src/keymap/keymaps/fujitsu-amilo_si_15206
-rw-r--r--src/udev/src/keymap/keymaps/fujitsu-esprimo_mobile_v54
-rw-r--r--src/udev/src/keymap/keymaps/fujitsu-esprimo_mobile_v62
-rw-r--r--src/udev/src/keymap/keymaps/genius-slimstar-32035
-rw-r--r--src/udev/src/keymap/keymaps/hewlett-packard12
-rw-r--r--src/udev/src/keymap/keymaps/hewlett-packard-2510p_2530p2
-rw-r--r--src/udev/src/keymap/keymaps/hewlett-packard-compaq_elitebook2
-rw-r--r--src/udev/src/keymap/keymaps/hewlett-packard-pavilion3
-rw-r--r--src/udev/src/keymap/keymaps/hewlett-packard-presario-21003
-rw-r--r--src/udev/src/keymap/keymaps/hewlett-packard-tablet6
-rw-r--r--src/udev/src/keymap/keymaps/hewlett-packard-tx23
-rw-r--r--src/udev/src/keymap/keymaps/ibm-thinkpad-usb-keyboard-trackpoint7
-rw-r--r--src/udev/src/keymap/keymaps/inventec-symphony_6.0_7.02
-rw-r--r--src/udev/src/keymap/keymaps/lenovo-30005
-rw-r--r--src/udev/src/keymap/keymaps/lenovo-ideapad8
-rw-r--r--src/udev/src/keymap/keymaps/lenovo-thinkpad-usb-keyboard-trackpoint13
-rw-r--r--src/udev/src/keymap/keymaps/lenovo-thinkpad_x200_tablet6
-rw-r--r--src/udev/src/keymap/keymaps/lenovo-thinkpad_x6_tablet8
-rw-r--r--src/udev/src/keymap/keymaps/lg-x11012
-rw-r--r--src/udev/src/keymap/keymaps/logitech-wave16
-rw-r--r--src/udev/src/keymap/keymaps/logitech-wave-cordless15
-rw-r--r--src/udev/src/keymap/keymaps/logitech-wave-pro-cordless12
-rw-r--r--src/udev/src/keymap/keymaps/maxdata-pro_70009
-rw-r--r--src/udev/src/keymap/keymaps/medion-fid20602
-rw-r--r--src/udev/src/keymap/keymaps/medionnb-a5554
-rw-r--r--src/udev/src/keymap/keymaps/micro-star13
-rw-r--r--src/udev/src/keymap/keymaps/module-asus-w3j11
-rw-r--r--src/udev/src/keymap/keymaps/module-ibm16
-rw-r--r--src/udev/src/keymap/keymaps/module-lenovo17
-rw-r--r--src/udev/src/keymap/keymaps/module-sony8
-rw-r--r--src/udev/src/keymap/keymaps/module-sony-old2
-rw-r--r--src/udev/src/keymap/keymaps/module-sony-vgn8
-rw-r--r--src/udev/src/keymap/keymaps/olpc-xo74
-rw-r--r--src/udev/src/keymap/keymaps/onkyo14
-rw-r--r--src/udev/src/keymap/keymaps/oqo-model25
-rw-r--r--src/udev/src/keymap/keymaps/samsung-90x3a5
-rw-r--r--src/udev/src/keymap/keymaps/samsung-other14
-rw-r--r--src/udev/src/keymap/keymaps/samsung-sq1us7
-rw-r--r--src/udev/src/keymap/keymaps/samsung-sx20s4
-rw-r--r--src/udev/src/keymap/keymaps/toshiba-satellite_a1002
-rw-r--r--src/udev/src/keymap/keymaps/toshiba-satellite_a11010
-rw-r--r--src/udev/src/keymap/keymaps/toshiba-satellite_m30x6
-rw-r--r--src/udev/src/keymap/keymaps/zepto-znote11
-rw-r--r--src/udev/src/libudev-device-private.c185
-rw-r--r--src/udev/src/libudev-device.c1744
-rw-r--r--src/udev/src/libudev-enumerate.c947
-rw-r--r--src/udev/src/libudev-list.c344
-rw-r--r--src/udev/src/libudev-monitor.c874
-rw-r--r--src/udev/src/libudev-private.h213
-rw-r--r--src/udev/src/libudev-queue-private.c412
-rw-r--r--src/udev/src/libudev-queue.c474
-rw-r--r--src/udev/src/libudev-selinux-private.c109
-rw-r--r--src/udev/src/libudev-util-private.c242
-rw-r--r--src/udev/src/libudev-util.c570
-rw-r--r--src/udev/src/libudev.c457
-rw-r--r--src/udev/src/libudev.h189
-rw-r--r--src/udev/src/libudev.pc.in11
-rw-r--r--src/udev/src/mtd_probe/75-probe_mtd.rules8
-rw-r--r--src/udev/src/mtd_probe/mtd_probe.c51
-rw-r--r--src/udev/src/mtd_probe/mtd_probe.h49
-rw-r--r--src/udev/src/mtd_probe/probe_smartmedia.c97
-rw-r--r--src/udev/src/rule_generator/75-cd-aliases-generator.rules9
-rw-r--r--src/udev/src/rule_generator/75-persistent-net-generator.rules102
-rw-r--r--src/udev/src/rule_generator/rule_generator.functions113
-rw-r--r--src/udev/src/rule_generator/write_cd_rules126
-rw-r--r--src/udev/src/rule_generator/write_net_rules141
-rw-r--r--src/udev/src/scsi_id/.gitignore1
-rw-r--r--src/udev/src/scsi_id/README4
-rw-r--r--src/udev/src/scsi_id/scsi.h97
-rw-r--r--src/udev/src/scsi_id/scsi_id.8119
-rw-r--r--src/udev/src/scsi_id/scsi_id.c657
-rw-r--r--src/udev/src/scsi_id/scsi_id.h73
-rw-r--r--src/udev/src/scsi_id/scsi_serial.c990
-rw-r--r--src/udev/src/sd-daemon.c530
-rw-r--r--src/udev/src/sd-daemon.h282
-rw-r--r--src/udev/src/test-libudev.c501
-rw-r--r--src/udev/src/test-udev.c121
-rw-r--r--src/udev/src/udev-builtin-blkid.c207
-rw-r--r--src/udev/src/udev-builtin-firmware.c168
-rw-r--r--src/udev/src/udev-builtin-hwdb.c247
-rw-r--r--src/udev/src/udev-builtin-input_id.c218
-rw-r--r--src/udev/src/udev-builtin-kmod.c142
-rw-r--r--src/udev/src/udev-builtin-path_id.c498
-rw-r--r--src/udev/src/udev-builtin-usb_id.c482
-rw-r--r--src/udev/src/udev-builtin.c134
-rw-r--r--src/udev/src/udev-control.socket10
-rw-r--r--src/udev/src/udev-ctrl.c494
-rw-r--r--src/udev/src/udev-event.c1011
-rw-r--r--src/udev/src/udev-kernel.socket10
-rw-r--r--src/udev/src/udev-node.c379
-rw-r--r--src/udev/src/udev-rules.c2767
-rw-r--r--src/udev/src/udev-settle.service.in25
-rw-r--r--src/udev/src/udev-trigger.service.in10
-rw-r--r--src/udev/src/udev-watch.c170
-rw-r--r--src/udev/src/udev.conf3
-rw-r--r--src/udev/src/udev.h188
-rw-r--r--src/udev/src/udev.pc.in5
-rw-r--r--src/udev/src/udev.service.in14
-rw-r--r--src/udev/src/udev.xml695
-rw-r--r--src/udev/src/udevadm-control.c175
-rw-r--r--src/udev/src/udevadm-info.c568
-rw-r--r--src/udev/src/udevadm-monitor.c297
-rw-r--r--src/udev/src/udevadm-settle.c235
-rw-r--r--src/udev/src/udevadm-test-builtin.c128
-rw-r--r--src/udev/src/udevadm-test.c173
-rw-r--r--src/udev/src/udevadm-trigger.c232
-rw-r--r--src/udev/src/udevadm.c165
-rw-r--r--src/udev/src/udevadm.xml472
-rw-r--r--src/udev/src/udevd.c1746
-rw-r--r--src/udev/src/udevd.xml151
-rw-r--r--src/udev/src/v4l_id/60-persistent-v4l.rules20
-rw-r--r--src/udev/src/v4l_id/v4l_id.c87
-rw-r--r--src/udev/test/.gitignore1
-rwxr-xr-xsrc/udev/test/rule-syntax-check.py64
-rwxr-xr-xsrc/udev/test/rules-test.sh15
-rw-r--r--src/udev/test/sys.tar.xzbin0 -> 165116 bytes
-rwxr-xr-xsrc/udev/test/udev-test.pl1560
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
9Makefile
10Makefile.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
2set tabstop=8
3set shiftwidth=8
4set 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
12freedom to share and change it. By contrast, the GNU General Public
13License is intended to guarantee your freedom to share and change free
14software--to make sure the software is free for all its users. This
15General Public License applies to most of the Free Software
16Foundation's software and to any other program whose authors commit to
17using it. (Some other Free Software Foundation software is covered by
18the GNU Lesser General Public License instead.) You can apply it to
19your programs, too.
20
21 When we speak of free software, we are referring to freedom, not
22price. Our General Public Licenses are designed to make sure that you
23have the freedom to distribute copies of free software (and charge for
24this service if you wish), that you receive source code or can get it
25if you want it, that you can change the software or use pieces of it
26in 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
29anyone to deny you these rights or to ask you to surrender the rights.
30These restrictions translate to certain responsibilities for you if you
31distribute copies of the software, or if you modify it.
32
33 For example, if you distribute copies of such a program, whether
34gratis or for a fee, you must give the recipients all the rights that
35you have. You must make sure that they, too, receive or can get the
36source code. And you must show them these terms so they know their
37rights.
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,
41distribute and/or modify the software.
42
43 Also, for each author's protection and ours, we want to make certain
44that everyone understands that there is no warranty for this free
45software. If the software is modified by someone else and passed on, we
46want its recipients to know that what they have is not the original, so
47that any problems introduced by others will not reflect on the original
48authors' reputations.
49
50 Finally, any free program is threatened constantly by software
51patents. We wish to avoid the danger that redistributors of a free
52program will individually obtain patent licenses, in effect making the
53program proprietary. To prevent this, we have made it clear that any
54patent must be licensed for everyone's free use or not licensed at all.
55
56 The precise terms and conditions for copying, distribution and
57modification 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
63a notice placed by the copyright holder saying it may be distributed
64under the terms of this General Public License. The "Program", below,
65refers to any such program or work, and a "work based on the Program"
66means either the Program or any derivative work under copyright law:
67that is to say, a work containing the Program or a portion of it,
68either verbatim or with modifications and/or translated into another
69language. (Hereinafter, translation is included without limitation in
70the term "modification".) Each licensee is addressed as "you".
71
72Activities other than copying, distribution and modification are not
73covered by this License; they are outside its scope. The act of
74running the Program is not restricted, and the output from the Program
75is covered only if its contents constitute a work based on the
76Program (independent of having been made by running the Program).
77Whether that is true depends on what the Program does.
78
79 1. You may copy and distribute verbatim copies of the Program's
80source code as you receive it, in any medium, provided that you
81conspicuously and appropriately publish on each copy an appropriate
82copyright notice and disclaimer of warranty; keep intact all the
83notices that refer to this License and to the absence of any warranty;
84and give any other recipients of the Program a copy of this License
85along with the Program.
86
87You may charge a fee for the physical act of transferring a copy, and
88you 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
91of it, thus forming a work based on the Program, and copy and
92distribute such modifications or work under the terms of Section 1
93above, 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
114These requirements apply to the modified work as a whole. If
115identifiable sections of that work are not derived from the Program,
116and can be reasonably considered independent and separate works in
117themselves, then this License, and its terms, do not apply to those
118sections when you distribute them as separate works. But when you
119distribute the same sections as part of a whole which is a work based
120on the Program, the distribution of the whole must be on the terms of
121this License, whose permissions for other licensees extend to the
122entire whole, and thus to each and every part regardless of who wrote it.
123
124Thus, it is not the intent of this section to claim rights or contest
125your rights to work written entirely by you; rather, the intent is to
126exercise the right to control the distribution of derivative or
127collective works based on the Program.
128
129In addition, mere aggregation of another work not based on the Program
130with the Program (or with a work based on the Program) on a volume of
131a storage or distribution medium does not bring the other work under
132the scope of this License.
133
134 3. You may copy and distribute the Program (or a work based on it,
135under Section 2) in object code or executable form under the terms of
136Sections 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
155The source code for a work means the preferred form of the work for
156making modifications to it. For an executable work, complete source
157code means all the source code for all modules it contains, plus any
158associated interface definition files, plus the scripts used to
159control compilation and installation of the executable. However, as a
160special exception, the source code distributed need not include
161anything that is normally distributed (in either source or binary
162form) with the major components (compiler, kernel, and so on) of the
163operating system on which the executable runs, unless that component
164itself accompanies the executable.
165
166If distribution of executable or object code is made by offering
167access to copy from a designated place, then offering equivalent
168access to copy the source code from the same place counts as
169distribution of the source code, even though third parties are not
170compelled to copy the source along with the object code.
171
172 4. You may not copy, modify, sublicense, or distribute the Program
173except as expressly provided under this License. Any attempt
174otherwise to copy, modify, sublicense or distribute the Program is
175void, and will automatically terminate your rights under this License.
176However, parties who have received copies, or rights, from you under
177this License will not have their licenses terminated so long as such
178parties remain in full compliance.
179
180 5. You are not required to accept this License, since you have not
181signed it. However, nothing else grants you permission to modify or
182distribute the Program or its derivative works. These actions are
183prohibited by law if you do not accept this License. Therefore, by
184modifying or distributing the Program (or any work based on the
185Program), you indicate your acceptance of this License to do so, and
186all its terms and conditions for copying, distributing or modifying
187the Program or works based on it.
188
189 6. Each time you redistribute the Program (or any work based on the
190Program), the recipient automatically receives a license from the
191original licensor to copy, distribute or modify the Program subject to
192these terms and conditions. You may not impose any further
193restrictions on the recipients' exercise of the rights granted herein.
194You are not responsible for enforcing compliance by third parties to
195this License.
196
197 7. If, as a consequence of a court judgment or allegation of patent
198infringement or for any other reason (not limited to patent issues),
199conditions are imposed on you (whether by court order, agreement or
200otherwise) that contradict the conditions of this License, they do not
201excuse you from the conditions of this License. If you cannot
202distribute so as to satisfy simultaneously your obligations under this
203License and any other pertinent obligations, then as a consequence you
204may not distribute the Program at all. For example, if a patent
205license would not permit royalty-free redistribution of the Program by
206all those who receive copies directly or indirectly through you, then
207the only way you could satisfy both it and this License would be to
208refrain entirely from distribution of the Program.
209
210If any portion of this section is held invalid or unenforceable under
211any particular circumstance, the balance of the section is intended to
212apply and the section as a whole is intended to apply in other
213circumstances.
214
215It is not the purpose of this section to induce you to infringe any
216patents or other property right claims or to contest validity of any
217such claims; this section has the sole purpose of protecting the
218integrity of the free software distribution system, which is
219implemented by public license practices. Many people have made
220generous contributions to the wide range of software distributed
221through that system in reliance on consistent application of that
222system; it is up to the author/donor to decide if he or she is willing
223to distribute software through any other system and a licensee cannot
224impose that choice.
225
226This section is intended to make thoroughly clear what is believed to
227be a consequence of the rest of this License.
228
229 8. If the distribution and/or use of the Program is restricted in
230certain countries either by patents or by copyrighted interfaces, the
231original copyright holder who places the Program under this License
232may add an explicit geographical distribution limitation excluding
233those countries, so that distribution is permitted only in or among
234countries not thus excluded. In such case, this License incorporates
235the limitation as if written in the body of this License.
236
237 9. The Free Software Foundation may publish revised and/or new versions
238of the General Public License from time to time. Such new versions will
239be similar in spirit to the present version, but may differ in detail to
240address new problems or concerns.
241
242Each version is given a distinguishing version number. If the Program
243specifies a version number of this License which applies to it and "any
244later version", you have the option of following the terms and conditions
245either of that version or of any later version published by the Free
246Software Foundation. If the Program does not specify a version number of
247this License, you may choose any version ever published by the Free Software
248Foundation.
249
250 10. If you wish to incorporate parts of the Program into other free
251programs whose distribution conditions are different, write to the author
252to ask for permission. For software which is copyrighted by the Free
253Software Foundation, write to the Free Software Foundation; we sometimes
254make exceptions for this. Our decision will be guided by the two goals
255of preserving the free status of all derivatives of our free software and
256of 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
261FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268REPAIR OR CORRECTION.
269
270 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278POSSIBILITY 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
285possible use to the public, the best way to achieve this is to make it
286free 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
289to attach them to the start of each source file to most effectively
290convey the exclusion of warranty; and each file should have at least
291the "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
310Also add information on how to contact you by electronic and paper mail.
311
312If the program is interactive, make it output a short notice like this
313when 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
320The hypothetical commands `show w' and `show c' should show the appropriate
321parts of the General Public License. Of course, the commands you use may
322be called something other than `show w' and `show c'; they could even be
323mouse-clicks or menu items--whatever suits your program.
324
325You should also get your employer (if you work as a programmer) or your
326school, if any, to sign a "copyright disclaimer" for the program, if
327necessary. 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
335This General Public License does not permit incorporating your program into
336proprietary programs. If your program is a subroutine library, you may
337consider it more useful to permit linking proprietary applications with the
338library. If this is what you want to do, use the GNU Lesser General
339Public 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 @@
1Summary of changes from v181 to v182
2============================================
3
4Kay 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
28Matthew Garrett (1):
29 rules: Enable USB autosuspend on more USB HID devices
30
31
32Summary of changes from v180 to v181
33============================================
34
35Andreas Schwab (1):
36 ata_id: fix identify string fixup
37
38Bruno Redondi (1):
39 keymap: Add Fujitsu Siemens Amilo Li 2732
40
41James M. Leddy (1):
42 keymap: Fix touchpad toggle button on Lenovo Ideapad
43
44Kay 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
50Lucas De Marchi (1):
51 builtin: kmod - depend on libkmod >= 5
52
53
54Summary of changes from v179 to v180
55============================================
56
57Kay 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
64Summary of changes from v178 to v179
65============================================
66
67Kay 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
78Summary of changes from v177 to v178
79============================================
80
81Evan Nemerson (1):
82 gudev: several minor introspection fixes
83
84Kay 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
93Martin 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
100Summary of changes from v176 to v177
101============================================
102
103Kay 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
109Summary of changes from v175 to v176
110============================================
111
112Alan Stern (1):
113 [PATCH[ udev: ata_id: Fix length of INQUIRY command
114
115Kay 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
178Lucas De Marchi (1):
179 builtin: kmod - log if modules are blacklisted
180
181Luis Felipe Strano Moraes (1):
182 Switch spawn_read to void and remove useless stores there.
183
184Martin Pitt (1):
185 75-persistent-net-generator.rules: Add Xen
186
187Mike Frysinger (1):
188 hwdb: drop useless line freeing
189
190Sjoerd Simons (1):
191 keymap: Add Lenovo Thinkpad X220 Tablet
192
193Ville Skyttä (1):
194 man: spelling fix
195
196
197Summary of changes from v174 to v175
198============================================
199
200David Zeuthen (2):
201 gudev: Use strtoul to parse unsigned 64-bit integers
202 gudev: Use g_ascii_strtoull() instead of strtoul()
203
204Harald Hoyer (1):
205 extras/keymap/findkeyboards: beautify shell code and get rid of grep
206
207Jerone Young (1):
208 keymap: Fix micmute remap for Lenovo Thinkpads
209
210Kay 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
219Martin 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
230Summary of changes from v173 to v174
231============================================
232
233David Zeuthen (1):
234 ata_id: Check for Compact Flash card
235
236Jerone Young (1):
237 Add mic mute keycode support for Lenovo Thinkpad USB keyboard
238
239Kay 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
275Kir Kolyshkin (1):
276 keymap: add Genius SlimStar 320
277
278Martin Pitt (1):
279 keymap: Update Acer Aspire 5920g
280
281Matthias Clasen (1):
282 make: allow to pass ${ACLOCAL_FLAGS}
283
284Paul Fox (1):
285 keymap: update the OLPC keymap for correct function key behavior
286
287Petr Uzel (1):
288 udevadm: settle - return failure if unknown option is given
289
290Steve Langasek (1):
291 udevd: exit - process events before signals in worker
292
293Thomas 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
298Summary of changes from v172 to v173
299============================================
300
301Allin Cottrell (1):
302 configure: allow to disable mtd_probe
303
304Kay 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
321Martin 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
328Summary of changes from v171 to v172
329============================================
330
331Bastien Nocera (3):
332 accelerometer: add orientation property
333 udev-acl: fix memleak
334 accelerometer: add documentation
335
336Harald Hoyer (2):
337 udevadm-*.c: return != 0, if unknown option given
338 udev/udevadm-monitor.c: fixed misplaced brace
339
340Kay 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
375Keshav P.R (1):
376 rules: support for gpt partition uuid/label
377
378Lee, Chun-Yi (1):
379 Support more MSI notebook by using asterisk on dmi vendor name
380
381Marco d'Itri (1):
382 Add missing commas to 95-keymap.rules
383
384Martin 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
389Peter Jones (1):
390 ata_id: show the error message when HDIO_GET_IDENTITY fails
391
392
393Summary of changes from v170 to v171
394============================================
395
396Kay 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
415Scott James Remnant (1):
416 configure: allow usb.ids location to be specified
417
418
419Summary of changes from v169 to v170
420============================================
421
422Kay Sievers (1):
423 libudev: ctrl - properly wait for incoming message after connect
424
425Michal Soltys (1):
426 configure.ac: fixes for rule_generator and modeswitch
427
428
429Summary of changes from v168 to v169
430============================================
431
432Kay 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
460Koen Kooi (1):
461 configure: reintroduce introspection flags to fix crosscompilation
462
463Michael 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
501Nix (1):
502 libudev: queue - accept NULL passed into udev_queue_export_cleanup()
503
504
505Summary of changes from v167 to v168
506============================================
507
508David Zeuthen (1):
509 Run ata_id on non-removable USB devices
510
511Harald Hoyer (1):
512 udevd: clarify worker exit status
513
514Kay 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
551Lee, Chun-Yi (1):
552 Add rule for Acer Aspire One ZG8 to use acer-aspire_5720 keymap
553
554Leonid Antonenkov (1):
555 rule-generator: net - ignore Hyper-V virtual interfaces
556
557Martin 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
562Michael Reed (1):
563 path_id: rework SAS device handling
564
565Michael 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
579Seth Forshee (1):
580 keymap: Support Dell Latitude XT2 tablet-mode navigation keys
581
582Thomas Egerer (1):
583 udevd: add 'N:' to optstring in getopt_long
584
585
586Summary of changes from v166 to v167
587============================================
588
589Andrey Borzenkov (1):
590 udev-acl: add /dev/sgX nodes for CD-ROM
591
592David Zeuthen (1):
593 cdrom_id: Don't ignore profiles when there is no media available
594
595Harald 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
599Kay 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
630Kei Tokunaga (1):
631 udevadm: enumerate - update prev pointer properly
632
633Lee, 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
637Martin 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
651Seth Forshee (1):
652 keymap: continue reading keymap after invalid scancodes
653
654Thomas 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
660Summary of changes from v165 to v166
661============================================
662
663Chris Bagwell (1):
664 Remap Eee PC touchpad toggle key to F21 used by X
665
666Gerd Hoffmann (1):
667 extras: add rules for qemu guests
668
669Jürgen Kaiser (1):
670 keymap: Add Acer Aspire 8930
671
672Kay 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
681Martin 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
689Matthew Garrett (1):
690 keymap: Remove wlan from Dell
691
692
693Summary of changes from v164 to v165
694============================================
695
696Andy Whitcroft (1):
697 keymap: Add release quirks for two Zepto Znote models and AMILO Xi 2428
698
699Bastien Nocera (2):
700 keymap: Add force release for HP touchpad off
701 extras/keymap: Make touchpad buttons consistent
702
703David Henningsson (1):
704 Add ACLs for FFADO supported sound cards
705
706David 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
714Harald Hoyer (2):
715 udev-rules.c: change import property buffer to 16384 bytes
716 70-acl.rules: add ACLs for ID_PDA devices
717
718Jakub Wilk (1):
719 man: udev - workaraound -> workaround
720
721Jan Drzewiecki (1):
722 cdrom_id: Fix media state for unreadable DVDs
723
724Kay 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
745Martin 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
752Michal Soltys (1):
753 udevd: create static nodes before /dev/null is needed
754
755
756Summary of changes from v163 to v164
757============================================
758
759David Zeuthen (1):
760 Install libgudev-1.0.so in prefix / instead of prefix /usr
761
762Harald Hoyer (1):
763 cdrom_id: request the drive profile features with a dynamic length
764
765Kay 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
771Martin Pitt (2):
772 keymap: Apply force-release rules to all Samsung models.
773 keymap: Add Toshiba Satellite U500
774
775
776Summary of changes from v162 to v163
777============================================
778
779David Zeuthen (2):
780 gudev: Deliver ::uevent signal in the thread-default main loop
781 Bump required GLib version to 2.22
782
783Hannes Reinecke (1):
784 scsi_id: export target port group
785
786Kay 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
793Lee, Chun-Yi (1):
794 keymap: Add alternate MSI vendor name
795
796Martin 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
806Torsten Schoenfeld (1):
807 gudev: add a few annotations that newer gobject-introspection versions demand
808
809
810Summary of changes from v161 to v162
811============================================
812
813David Woodhouse (1):
814 Add keymap for Lenovo IdeaPad S10-3
815
816Jan Drzewiecki (2):
817 cdrom_id: Drop MEDIA_SESSION_NEXT for DVD-RW-RO
818 cdrom_id: Fix DVD blank detection for sloppy firmware
819
820Kay 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
832Luca Tettamanti (1):
833 Add support for oom_score_adj
834
835Marco 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
839Martin 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
853Michael Forney (1):
854 Don't install systemd scripts with --without-systemdsystemunitdir
855
856Michal Soltys (1):
857 ChangeLog fix
858
859
860Summary of changes from v160 to v161
861============================================
862
863Fortunato Ventre (1):
864 keymap: Add force-release quirks for a lot more Samsung models
865
866Harald 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
871Jan 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
878Jerone Young (1):
879 Fix volume keys not releasing on Mivvy G310
880
881Kay 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
895Marco 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
900Martin Pitt (1):
901 keymap: Generalize Samsung keymaps
902
903Michal Schmidt (1):
904 udev-acl: really fix ACL assignment in CK events
905
906Richard Hughes (1):
907 udev-acl: add DDC_DEVICE to the types that are managed
908
909Stefan Richter (1):
910 rules: add more FireWire IDs: Point Grey IIDC; AV/C + vendor unique
911
912Yin 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
922Summary of changes from v159 to v160
923============================================
924
925Harald 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
929Kay 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
935Lennart Poettering (1):
936 systemd: make service files readable by GKeyFile
937
938Martin Pitt (2):
939 keymap: Find alternate Lenovo module
940 keymap: Add Lenovo ThinkPad SL Series extra buttons
941
942
943Summary of changes from v158 to v159
944============================================
945
946Jerone Young (1):
947 Fix stuck volume key presses for Toshiba Satellite U300 & U305models
948
949Kay 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
956Lennart Poettering (1):
957 systemd: update service files for newly introduced DefaultDependencies= option
958
959Martin Pitt (1):
960 keymap: Add Logitech Cordless Wave Pro
961
962Matthew Garrett (1):
963 keymap: Add support for IBM-branded USB devices
964
965Michael Meeks (1):
966 gudev: respect possibly given LD_LIBRARY_PATH
967
968Ryan Harper (2):
969 Add virtio-blk support to path_id
970 Add virtio-blk by-id rules based on 'serial' attribute
971
972
973Summary of changes from v157 to v158
974============================================
975
976Harald Hoyer (1):
977 extras/keymap: add Samsung N210 to keymap rules
978
979Kay 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
988Martin 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
994Maxim Levitsky (1):
995 mtd_probe: add autodetection for xD cards
996
997Paul Bender (1):
998 configure.ac: fix cross compilation
999
1000
1001Summary of changes from v156 to v157
1002============================================
1003
1004Harald Hoyer (1):
1005 40-redhat.rules: removed file
1006
1007Jerone 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
1012Kay 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
1040Summary of changes from v155 to v156
1041============================================
1042
1043Bryan Kadzban (1):
1044 udevd: fix typo /proc/fd -> /proc/self/fd
1045
1046Kay 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
1053Summary of changes from v154 to v155
1054============================================
1055
1056Kay 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
1070Summary of changes from v153 to v154
1071============================================
1072
1073Harald Hoyer (2):
1074 Makefile.am: add LGPL COPYING file to EXTRA_DIST
1075 cdrom_id: only mark sr[0-9]* as ID_CDROM
1076
1077Jerone Young (1):
1078 Fix volume keys not releasing for Pegatron platform
1079
1080Kay 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
1105Martin Pitt (1):
1106 keymap: Fix Bluetooth key on Acer TravelMate 4720
1107
1108Mathias Nyman (1):
1109 remove buffer-overrun risk in readlink call
1110
1111Matthias Schwarzott (1):
1112 rules: Gentoo - remove old devfs compat rules
1113
1114Michael Thayer (1):
1115 fix device node deletion
1116
1117Robby Workman (1):
1118 configure.ac: move firmware-path setting out of extras section
1119
1120Yin 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
1125Summary of changes from v152 to v153
1126============================================
1127
1128Kay Sievers (1):
1129 configure.ac: version bump
1130
1131Robby Workman (1):
1132 configure.ac: fix broken firmware search path in configure.ac
1133
1134
1135Summary of changes from v151 to v152
1136============================================
1137
1138Adrian Bunk (1):
1139 udev needs automake 1.10
1140
1141Amit 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
1145Andy Whitcroft (2):
1146 keymap: Add Samsung Q210/P210 force-release quirk
1147 keymap: Add Fujitsu Amilo 1848+u force-release quirk
1148
1149Dan Williams (1):
1150 modeswitch: morph into tool that only switches Mobile Action cables
1151
1152David 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
1157Harald Hoyer (1):
1158 cdrom_id: remove debugging code
1159
1160Jerone 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
1168Kamal 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
1173Kay 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
1218Marco 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
1223Martin 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
1237Mike Brudevold (1):
1238 cdrom_id: add missing profiles to feature_profiles
1239
1240Robert Hooker (1):
1241 keymap: Add support for Gateway AOA110/AOA150 clones.
1242
1243Scott James Remnant (2):
1244 libudev: export udev_monitor_set_receive_buffer_size()
1245 udevadm monitor: increase netlink buffer size
1246
1247Thomas Bächler (1):
1248 firmware: fix error reporting on missing firmware files
1249
1250Yury 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
1256Summary of changes from v150 to v151
1257============================================
1258
1259Amit Shah (1):
1260 rules: Add symlink rule for virtio ports
1261
1262Bryan Kadzban (1):
1263 Fix reverted floppy-device permissions
1264
1265Egbert Eich (1):
1266 rulews: suse - add do-not-load-KMS-modules rules
1267
1268Frederic Crozat (1):
1269 rules: acl - add COLOR_MEASUREMENT_DEVICE match
1270
1271Kay 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
1284Marco d'Itri (2):
1285 writing_udev_rules: update rules files names
1286 keymap: support for the Samsung N140 keyboard
1287
1288Martin 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
1295Summary of changes from v149 to v150
1296============================================
1297
1298Clemens Buchacher (2):
1299 add Samsung R70/R71 keymap
1300 keymap: Samsung R70/R71 force-release quirk
1301
1302Daniel Drake (2):
1303 keymap: Add OLPC XO key mappings
1304 keymap: Fix typo in compal rules
1305
1306Daniel Elstner (1):
1307 libudev: wrap in extern "C" block for C++
1308
1309David Zeuthen (1):
1310 Export ID_WWN_VENDOR_EXTENSION and ID_WWN_WITH_EXTENSION
1311
1312Jerone Young (1):
1313 keymap: Lenovo Thinkpad USB Keyboard with Tracepoint
1314
1315Johannes Stezenbach (2):
1316 keymap: add Samsung N130
1317 keymap: handle atkbd force_release quirk
1318
1319Kay 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
1336Marco d'Itri (2):
1337 build: keymap - create subdir
1338 rules: udev-acl - add firewire video devices
1339
1340Martin 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
1354Piter PUNK (1):
1355 firmware: convert shell script to C
1356
1357Scott James Remnant (1):
1358 70-acl.rules: ACL manage Android G1 dev phones
1359
1360Thomas de Grenier de Latour (1):
1361 libudev: enumerate - fix move_later logic
1362
1363
1364Summary of changes from v148 to v149
1365============================================
1366
1367Daniel Elstner (1):
1368 really fix both in-tree and out-of-tree builds
1369
1370Dmitry Torokhov (1):
1371 input-id: identify touchscreens
1372
1373Kay 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
1379Martin 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
1388Summary of changes from v147 to v148
1389============================================
1390
1391Dan 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
1396Daniel Mierswa (1):
1397 Fix typo in NEWS, ConsoleKit-0.4.11 -> 0.4.1
1398
1399David 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
1405Dmitry Torokhov (1):
1406 extras/input_id: Correctly identify touchpads
1407
1408Harald Hoyer (1):
1409 modem-modeswitch: add a device
1410
1411Kay 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
1421Martin 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
1428Scott James Remnant (1):
1429 Fix out-of-tree builds
1430
1431
1432Summary of changes from v146 to v147
1433============================================
1434
1435Alan Jenkins (1):
1436 udevd: queue-export - remove retry loop
1437
1438Andrew Church (1):
1439 fix wrong parameter size on ioctl FIONREAD
1440
1441Daniel Mierswa (2):
1442 don't compare a non-existing function with NULL
1443 use nanosleep() instead of usleep()
1444
1445David 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
1451Florian 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
1463Harald Hoyer (2):
1464 scsi_id: prevent buffer overflow in check_fill_0x83_prespc3()
1465 rename interfaces to <iface>_rename if rename fails
1466
1467Jeremy Kerr (1):
1468 util_run_program: restore signal mask before executing event RUN commands
1469
1470Kay 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
1517Lennart 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
1524Marco 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
1532Mario Limonciello (1):
1533 hid2hci: remove superfluous bmAttributes match
1534
1535Martin 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
1561Matthias Schwarzott (2):
1562 rules: Gentoo update
1563 rules: Gentoo update
1564
1565Maxim Levitsky (1):
1566 keymap for Acer Aspire 5720
1567
1568Peter Rajnoha (1):
1569 libudev: allow to store negative values in the udev database
1570
1571Scott James Remnant (1):
1572 util_run_program: *really* restore signal mask before executing event RUN commands
1573
1574William Jon McCann (1):
1575 udev-acl: catch up with ConsoleKit 0.4.1
1576
1577
1578Summary of changes from v145 to v146
1579============================================
1580
1581Alan Jenkins (3):
1582 man: fix unused, inaccurate metadata
1583 man: SYMLINK can be matched as well as assigned
1584 fix spelling
1585
1586Anssi Hannula (2):
1587 rules: exclude digitizers from joystick class
1588 udev-acl: add joystick devices
1589
1590Diego 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
1613Eric W. Biederman (1):
1614 fix util_lookup_group to handle large groups
1615
1616Erik Forsberg (1):
1617 extras/modem-modeswitch: Add Huawei E1550 GSM modem
1618
1619Kay 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
1639Lennart Poettering (1):
1640 enumeration: move ALSA control devices to the end of the enumerated devices of each card
1641
1642Mario 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
1646Martin 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
1666Summary of changes from v144 to v145
1667============================================
1668
1669Ian Campbell (1):
1670 scsi_id: correct error handling in prepend_vendor_model
1671
1672Kay 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
1685Summary of changes from v143 to v144
1686============================================
1687
1688Jon Masters (1):
1689 firmware: search for third party or sysadmin supplied firmware updates
1690
1691Kay 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
1712Martin Pitt (2):
1713 hid2hci: narrow matches to real HCI devices
1714 extras/udev-acl: add smartcard readers
1715
1716Stefan Richter (1):
1717 rules: set group ownership of new firewire driver device files
1718
1719
1720Summary of changes from v142 to v143
1721============================================
1722
1723Alan 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
1730Benjamin Gilbert (1):
1731 test: check string substitutions in OWNER and GROUP
1732
1733Dan Williams (2):
1734 rules: tty/net - move from udev-extras
1735 extras/modem-modeswitch: move from udev-extras
1736
1737David Zeuthen (1):
1738 gudev: move from udev-extras
1739
1740Kay 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
1837Lennart Poettering (2):
1838 rules: sound - move from udev-extra
1839 usb-db: move from udev-extras
1840
1841Marcel Holtmann (1):
1842 rules: make RFKILL control device world readable
1843
1844Mario Limonciello (1):
1845 hid2hci: move from udev-extras
1846
1847Martin 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
1854Matthias Schwarzott (3):
1855 rules: Gentoo update
1856 rules: Gentoo update
1857 rules: Gentoo update
1858
1859Scott James Remnant (1):
1860 OWNER/GROUP: fix if logic
1861
1862
1863Summary of changes from v141 to v142
1864============================================
1865
1866Andre Przywara (1):
1867 rules: create /dev/cpu/<n>/cpuid world readable
1868
1869Ian Campbell (1):
1870 path_id: support identification of Xen virtual block devices
1871
1872John Wright (1):
1873 edd_id: add cciss devices
1874
1875Kay 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
1922Lubomir Rintel (1):
1923 rule-generator: net - whitelist NICs that violate MAC local scheme
1924
1925
1926Summary of changes from v140 to v141
1927============================================
1928
1929Adam 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
1935Alan Jenkins (1):
1936 avoid leaking netlink socket fd to external programs
1937
1938Borislav Petkov (1):
1939 rules: rename ide-floppy to ide-gd
1940
1941David Brownell (1):
1942 rules: exclude mtd* from persistent disk links
1943
1944Kay 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
1961Michal Soltys (1):
1962 rules: md-raid.rules fix
1963
1964Robby Workman (1):
1965 udevadm: trigger - add "--action" to --help
1966
1967Scott James Remnant (1):
1968 libudev: monitor - ignore messages from unusual sources
1969
1970
1971Summary of changes from v139 to v140
1972============================================
1973
1974Harald Hoyer (1):
1975 libvolume_id: bump age
1976
1977Kay 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
1991Michael Prokop (1):
1992 fix compile error in debug mode
1993
1994Scott James Remnant (1):
1995 udevadm: settle - synchronise with the udev daemon
1996
1997
1998Summary of changes from v138 to v139
1999============================================
2000
2001Kay 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
2014Scott 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
2027Summary of changes from v137 to v138
2028============================================
2029
2030David Zeuthen (1):
2031 *_id: add model/vendor enc strings
2032
2033Karel Zak (2):
2034 vol_id: fix ddf version string
2035 vol_id: add missing id->type to swap0
2036
2037Kay 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
2052Matthias Schwarzott (1):
2053 rules: Gentoo update
2054
2055Miklos Vajna (1):
2056 doc: writing udev rules - refer to 'udevadm info' instead of 'udevinfo'
2057
2058Scott James Remnant (2):
2059 udevd: optionally watch device nodes with inotify
2060 rules: update persistent storage rules to use inotify watches
2061
2062
2063Summary of changes from v136 to v137
2064============================================
2065
2066Alan Jenkins (2):
2067 man: typo fixes
2068 remove stray initializer
2069
2070Kay 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
2089Lennart Poettering (1):
2090 fix naming for tape nst devices in /dev/tape/by-path/
2091
2092Olaf Kirch (2):
2093 udevd: use ppoll instead of signal pipes
2094 reap children faster
2095
2096Scott James Remnant (2):
2097 Allow user and group lookup to be disabled.
2098 Expose delayed name resolution
2099
2100Sven Jost (1):
2101 volume_id: support via raid version 2
2102
2103
2104Summary of changes from v135 to v136
2105============================================
2106
2107Adam Buchbinder (1):
2108 extras: fix mis-spelling of "environment"
2109
2110Harald Hoyer (1):
2111 rule_generator: fix enumeration for write_cd_rules
2112
2113Jeremy Higdon (1):
2114 path_id: rework SAS persistent names
2115
2116Karel Zak (1):
2117 volume_id: HPFS code clean up
2118
2119Kay 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
2175Marcel 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
2180Michal Soltys (1):
2181 man: udev - update NAME assignment
2182
2183Ryan Thomas (1):
2184 rules: add rules for AoE devices
2185
2186
2187Summary of changes from v134 to v135
2188============================================
2189
2190Kay 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
2198Marcel Holtmann (1):
2199 usb_id: fix switch statement for video type
2200
2201Piter PUNK (2):
2202 rules: /dev/null -> X0R
2203 rules: add usb device nodes
2204
2205
2206Summary of changes from v133 to v134
2207============================================
2208
2209Gabor Z. Papp (1):
2210 include errno.h in sysdeps.h
2211
2212Harald Hoyer (1):
2213 rules: add persistent rules for memory stick block devices
2214
2215Kay 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
2236Matthias Schwarzott (1):
2237 rules: Gentoo update
2238
2239Peter Breitenlohner (2):
2240 man: fix typos
2241 floppy: fix array bounds check and minor calculation
2242
2243
2244Summary of changes from v132 to v133
2245============================================
2246
2247Alan Jenkins (2):
2248 udevd: de-duplicate strings in rules
2249 scsi_id: we don't use DEVPATH env var anymore, update man page
2250
2251Karel Zak (1):
2252 volume_id: fat - move check for msdos signature (0x55 0xaa)
2253
2254Kay 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
2278Sergey Vlasov (1):
2279 udevadm: fix option parsing breakage with klibc
2280
2281
2282Summary of changes from v131 to v132
2283============================================
2284
2285Kay Sievers (2):
2286 fix size_t compiler warning on 32 bit platforms
2287 convert debug string arrays to functions
2288
2289
2290Summary of changes from v130 to v131
2291============================================
2292
2293Alan 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
2312Kay 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
2427Matthias Koenig (1):
2428 volume_id: swap - larger PAGE_SIZE support
2429
2430Steven Whitehouse (1):
2431 volume_id: support for GFS2 UUIDs
2432
2433
2434Summary of changes from v129 to v130
2435============================================
2436
2437Kay 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
2466Summary of changes from v128 to v129
2467============================================
2468
2469Alan 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
2478Kay 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
2527Summary of changes from v127 to v128
2528============================================
2529
2530Alan 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
2540Kay 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
2596Summary of changes from v126 to v127
2597============================================
2598
2599Karel Zak (2):
2600 build-sys: don't duplicate file names
2601 build-sys: remove non-POSIX variable names
2602
2603Kay 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
2631Michal Soltys (1):
2632 rules: fix md rules for partitioned devices
2633
2634
2635Summary of changes from v125 to v126
2636============================================
2637
2638Kay 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
2649Marco d'Itri (1):
2650 rules: Debian update
2651
2652Thomas Koeller (1):
2653 use proper directory lib/lib64 for libvolume_id
2654
2655
2656Summary of changes from v124 to v125
2657============================================
2658
2659John Huttley (1):
2660 rules: tape rules - add nst to usb and 1394 links
2661
2662Karl O. Pinc (1):
2663 man: clarify $attr{} parent searching
2664
2665Kay 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
2681Marco 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
2690Thomas Koeller (1):
2691 scsi_id: include sys/stat.h
2692
2693Tobias Klauser (1):
2694 collect: check realloc return value
2695
2696
2697Summary of changes from v123 to v124
2698============================================
2699
2700Kay Sievers (1):
2701 cdrom_id: fix recognition of blank media
2702
2703
2704Summary of changes from v122 to v123
2705============================================
2706
2707Erik van Konijnenburg (3):
2708 add substitution in MODE= field
2709 Makefile: use udevdir in "make install"
2710 volume_id: support for oracleasm
2711
2712Harald Hoyer (1):
2713 scsi_id: retry open() on -EBUSY
2714
2715Karel Zak (2):
2716 volume_id: remove unnecessary global variable
2717 volume_id: enable GFS probing code, add LABEL support
2718
2719Kay 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
2726Michal Soltys (1):
2727 man: add NAME== match entry
2728
2729Xinwei Hu (2):
2730 collect: realloc buffer, if needed
2731 udevd: export .udev/queue/$seqnum before .udev/uevent_seqnum
2732
2733
2734Summary of changes from v121 to v122
2735============================================
2736
2737Hannes Reinecke (2):
2738 scsi_id: remove all sysfs dependencies
2739 scsi_id: add SGv4 support
2740
2741Karel Zak (1):
2742 volume_id: clean up linux_raid code
2743
2744Kay 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
2754MUNEDA Takahiro (2):
2755 man: udevd- fix udev(8) reference
2756 man: scsi_id
2757
2758Matthias Schwarzott (1):
2759 cdrom_id: fix segfault
2760
2761
2762Summary of changes from v120 to v121
2763============================================
2764
2765Damjan Georgievski (1):
2766 libvolume_id: recognize swap partitions with a tuxonice hibernate image
2767
2768Daniel Drake (1):
2769 writing udev rules: fix rule typos
2770
2771David Woodhouse (1):
2772 rules_generator: net rules - add "dev_id" value to generated rules
2773
2774Harald Hoyer (1):
2775 selinux: more context settings
2776
2777Kay 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
2801Summary of changes from v119 to v120
2802============================================
2803
2804Kay 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
2815Michael Kralka (1):
2816 udevd: serialize events if they refer to the same major:minor number
2817
2818
2819Summary of changes from v118 to v119
2820============================================
2821
2822Anthony L. Awtrey (1):
2823 do not skip RUN execution if device node removal fails
2824
2825Harald Hoyer (2):
2826 rules: Fedora update
2827 rules: do not set GROUP="disk" for scanners
2828
2829Jiri Slaby (1):
2830 rules_generator: add missing write_net_rules unlock
2831
2832Karel Zak (2):
2833 volume_id: fix UUID raw buffer usage
2834 volume_id: fix typo in function documentation
2835
2836Kay 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
2848Matthias Schwarzott (1):
2849 volume_id: respect LDFLAGS
2850
2851Neil Williams (1):
2852 volume_id: add prefix=, exec_prefix=
2853
2854Roy Marples (1):
2855 Makefile: do not require GNU install
2856
2857
2858Summary of changes from v117 to v118
2859============================================
2860
2861Daniel Drake (1):
2862 doc: update "writing udev rules"
2863
2864Hannes Reinecke (1):
2865 volume_id: LVM - add uuid
2866
2867Kay 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
2878Matthias Schwarzott (1):
2879 rules: Gentoo update
2880
2881Michael Prokop (1):
2882 libvolume_id: squashfs+LZMA compression detection
2883
2884
2885Summary of changes from v116 to v117
2886============================================
2887
2888Dan Nicholson (2):
2889 extras: ignore built and generated files
2890 volume_id: create relative symlink when $(libdir) = $(usrlibdir)
2891
2892Kay 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
2909MUNEDA Takahiro (1):
2910 man: fix udevadm.8 typo
2911
2912Matthias Schwarzott (2):
2913 firmware: remove hardcoded path to logger
2914 rules: Gentoo update
2915
2916VMiklos (1):
2917 rules: Frugalware update
2918
2919
2920Summary of changes from v115 to v116
2921============================================
2922
2923Bryan Kadzban (1):
2924 rules: fix typos
2925
2926Harald 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
2931Kay 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
2962Matthias Schwarzott (3):
2963 rules: Gentoo update
2964 rules: Gentoo update
2965 rules: Gentoo update
2966
2967Michael Morony (1):
2968 set buffer size if strlcpy/strlcat indicate truncation
2969
2970maximilian attems (1):
2971 correct includes in udev_selinux.c
2972
2973
2974Summary of changes from v114 to v115
2975============================================
2976
2977Harald Hoyer (1):
2978 rules: fix typo in 80-drivers.rules
2979
2980Kay 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
2997Marco 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
3003Summary of changes from v113 to v114
3004============================================
3005
3006Hannes Reinecke (3):
3007 collect: extra to synchronize actions across events
3008 add $driver subtitution
3009 rules_generator: add S/390 persistent network support
3010
3011Kay 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
3037Matthias Schwarzott (3):
3038 rules: Gentoo update
3039 fix inotify to work not only once
3040 rules: Gentoo update
3041
3042Richard Hughes (1):
3043 Makefile: add "make dist" for nightly snapshots
3044
3045
3046Summary of changes from v112 to v113
3047============================================
3048
3049David Zeuthen (1):
3050 vol_id: do not fail if unable to drop privileges
3051
3052Kay 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
3066Tobias Klauser (1):
3067 fix typo in udev_utils_run.c
3068
3069
3070Summary of changes from v111 to v112
3071============================================
3072
3073Fabio Massimo Di Nitto (1):
3074 rules: ignore partitons that span the entire disk
3075
3076Hannes Reinecke (1):
3077 cciss device support
3078
3079Kay 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
3115Miklos Vajna (2):
3116 create_floppy_devices: add man page
3117 path_id: remove on make uninstall
3118
3119Ryan Lortie (1):
3120 volume_id: support for long-filename based labels
3121
3122Scott 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
3127Summary of changes from v110 to v111
3128============================================
3129
3130Kay 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
3151Matthias Schwarzott (2):
3152 volume_id: fix Makefile for parallel make
3153 rules: Gentoo update
3154
3155
3156Summary of changes from v109 to v110
3157============================================
3158
3159Harald Hoyer (1):
3160 udevcontrol: allow to set global variables in udevd
3161
3162Kay 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
3177Matthias 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
3183Summary of changes from v108 to v109
3184============================================
3185
3186Harald Hoyer (1):
3187 create_floppy_devices: create nodes with correct selinux context
3188
3189Kay 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
3202Matthias Schwarzott (2):
3203 update Gentoo rules
3204 persistent device naming: add joystick links
3205
3206VMiklos (1):
3207 path_id: add man page
3208
3209
3210Summary of changes from v107 to v108
3211============================================
3212
3213Kay 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
3218Matthias Schwarzott (2):
3219 write_cd_rules: set default link type to "by-id" for usb and ieee1394 devices
3220 update Gentoo rules
3221
3222Pozsar Balazs (1):
3223 udevsettle: read udev not kernel seqnum first
3224
3225
3226Summary of changes from v106 to v107
3227============================================
3228
3229Jean Tourrilhes (1):
3230 udevtest: export UDEV_LOG if we changed it
3231
3232Kay 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
3267Marco d'Itri (1):
3268 update Debian rules
3269
3270Matthias Schwarzott (2):
3271 udevd: cleanup std{in,our,err} on startup
3272 udevmonitor: fix swapped event switch descriptions
3273
3274
3275Summary of changes from v105 to v106
3276============================================
3277
3278A. Costa (1):
3279 man: fix typos in scsi_id and udevd
3280
3281Andrey Borzenkov (2):
3282 vol_id: add -L to print raw partition label
3283 vol_id: document -L
3284
3285Jamie Wellnitz (1):
3286 persistent device naming: tape devices and medium changers
3287
3288Kay 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
3305Matthias 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
3311Peter Breitenlohner (1):
3312 fix INSTALL_PROGRAM vs. INSTALL_SCRIPT
3313
3314Sergey 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
3319Theodoros V. Kalamatianos (1):
3320 fix udev attribute names with a colon
3321
3322
3323Summary of changes from v104 to v105
3324============================================
3325
3326A. Costa (1):
3327 man: fix typos in scsi_id and udevd
3328
3329Andrey Borzenkov (2):
3330 vol_id: add -L to print raw partition label
3331 vol_id: document -L
3332
3333Kay Sievers (2):
3334 exclude parent devices from DRIVER== match
3335 volume_id: really fix endianess bug in linux_raid detection
3336
3337Matthias Schwarzott (2):
3338 correct typo in extras/scsi_id/scsi_id.conf
3339 fix retry-loop in netif-rename code
3340
3341Peter Breitenlohner (1):
3342 fix INSTALL_PROGRAM vs. INSTALL_SCRIPT
3343
3344Sergey 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
3350Summary of changes from v103 to v104
3351============================================
3352
3353Kay 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
3367Kazuhiro Inaoka (1):
3368 inotify syscall definitions for M32R
3369
3370Marco d'Itri (2):
3371 write_cd_rules: identity-based persistence
3372 scsi_id: remove trailing garbage from ID_SERIAL_SHORT
3373
3374Russell Coker (1):
3375 SELinux: label created symlink instead of node
3376
3377
3378Summary of changes from v102 to v103
3379============================================
3380
3381Kay 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
3389Summary of changes from v101 to v102
3390============================================
3391
3392Daniel Drake:
3393 writing_udev_rules: fix typo in example rule
3394
3395Kay 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
3404MUNEDA Takahiro:
3405 path_id: fix SAS disk handling
3406
3407
3408Summary of changes from v100 to v101
3409============================================
3410
3411Arjan Opmeer:
3412 fix udevinfo help text typo
3413
3414Bryan Kadzban:
3415 cleanup default rules
3416 add IMPORT operations to the udev man page
3417
3418Kay 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
3433Michał Bartoszkiewicz:
3434 udevtrigger: fix typo that prevents partition events
3435
3436Miles Lane:
3437 clarify "specified user/group unknown" error
3438
3439Piter PUNK:
3440 update slackware rules
3441
3442VMiklos:
3443 update Frugalware rules
3444
3445
3446Summary of changes from v099 to v100
3447============================================
3448
3449Kay 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
3456Summary of changes from v098 to v099
3457============================================
3458
3459Greg KH:
3460 update Gentoo rules
3461
3462Kay 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
3482Marco 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
3487MUNEDA Takahiro:
3488 changes rules for ata disk from '_' to '-'
3489
3490Sergey Vlasov:
3491 make struct option arrays static const
3492 fix "subsytem" typo
3493
3494
3495Summary of changes from v097 to v098
3496============================================
3497
3498Alex Merry:
3499 udevtest: allow /sys in the devpath paramter
3500
3501Harald Hoyer:
3502 selinux: init once in the daemon, not in every event process
3503
3504Kay 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
3529Lennart Poettering:
3530 volume_id: fix fat32 cluster chain traversal
3531
3532Marco d'Itri:
3533 fix 'unknow user' error from getpwnam/getgrnam
3534 fix rc when using udev --daemon
3535 update Debian rules
3536
3537Michał Bartoszkiewicz:
3538 man pages: fix typos
3539
3540
3541Summary of changes from v096 to v097
3542============================================
3543
3544Anssi Hannula:
3545 add joystick support to persistent input rules
3546
3547Kay 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
3578Marco d'Itri:
3579 make rename_netif() error messages useful
3580 path_id: fix an harmless syntax error
3581
3582Piter PUNK:
3583 update slackware rules
3584
3585Richard Purdie:
3586 Fix inotify syscalls on ARM
3587
3588
3589Summary of changes from v095 to v096
3590============================================
3591
3592Kay Sievers:
3593 Makefiles: fix .PHONY for man page target
3594 allow longer devpath values
3595 path_id: prepare for new sysfs layout
3596
3597
3598Summary of changes from v094 to v095
3599============================================
3600
3601Kay 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
3610Tobias Klauser:
3611 print usage of udevcontrol when no or invalid command is given
3612
3613
3614Summary of changes from v093 to v094
3615============================================
3616
3617Daniel Drake:
3618 update "writing udev rules"
3619
3620Kay Sievers:
3621 libvolume_id: gfs + gfs2 support
3622 remove MODALIAS key and substitution
3623 add persistent-input.rules
3624
3625Marco d'Itri:
3626 update Debian rules
3627
3628
3629Summary of changes from v092 to v093
3630============================================
3631
3632Hannes Reinecke:
3633 path_id: add support for iSCSI devices
3634
3635Kay 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
3645Summary of changes from v091 to v092
3646============================================
3647
3648Kay 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
3662Libor Klepac:
3663 path_id: add platform and serio support
3664
3665Marco d'Itri:
3666 update Debian rules
3667 path_id: fix bashism
3668
3669
3670Summary of changes from v090 to v091
3671============================================
3672
3673Hannes Reinecke:
3674 path_id: fix SAS device path generation
3675
3676Kay 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
3683Summary of changes from v089 to v090
3684============================================
3685
3686Kay 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
3700Marco d'Itri:
3701 add inotify support for hppa and MIPS and log if inotify is not available
3702
3703Matt Kraai:
3704 fix typo in error message
3705
3706
3707Summary of changes from v088 to v089
3708============================================
3709
3710Hannes Reinecke:
3711 path_id: add bus to USB path
3712
3713Kay 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
3738Summary of changes from v087 to v088
3739============================================
3740
3741Hannes Reinecke:
3742 persistent links: add scsi tape links and usb path support
3743
3744Kay 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
3757Summary of changes from v086 to v087
3758============================================
3759
3760Hannes Reinecke:
3761 path_id: support SAS devices
3762
3763Kay Sievers:
3764 fix persistent disk rules to exclude removable IDE drives
3765 warn about %e, MODALIAS, $modalias
3766 remove devfs rules and scripts
3767
3768Masatake YAMATO:
3769 typo in debug text in udev_run_hotplugd.c
3770
3771
3772Summary of changes from v085 to v086
3773============================================
3774
3775Kay 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
3781Kyle McMartin:
3782 workaround missing kernel headers for some architectures
3783
3784Nix:
3785 update to udev-084/doc/writing_udev_rules
3786
3787
3788Summary of changes from v084 to v085
3789============================================
3790
3791Andrey Borzenkov:
3792 Fix trivial spelling errors in RELEASE-NOTES
3793
3794Jeroen Roovers:
3795 fix typo in parisc support to path_id
3796
3797Kay 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
3809Summary of changes from v083 to v084
3810============================================
3811
3812Kay 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
3825Summary of changes from v082 to v083
3826============================================
3827
3828Andrey Borzenkov:
3829 man page: document when substitutions are applied for RUN and other keys
3830 check for ignore_device in loop looks redundant
3831
3832Kay 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
3839Summary of changes from v081 to v082
3840============================================
3841
3842Andrey Borzenkov:
3843 substitute format chars in RUN after rule matching
3844
3845Kay 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
3862Olivier Blin:
3863 fixes udev build with -fpie
3864
3865
3866Summary of changes from v080 to v081
3867============================================
3868
3869Kay 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
3877Summary of changes from v079 to v080
3878============================================
3879
3880Brent Cook:
3881 fix dependency for make -j2
3882
3883coly:
3884 fix man page typos
3885
3886Kay 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
3894Marco d'Itri:
3895 udev_selinux.c: include udev.h
3896
3897
3898Summary of changes from v078 to v079
3899============================================
3900
3901Kay 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
3909Summary of changes from v077 to v078
3910============================================
3911
3912Greg Kroah-Hartman:
3913 Update Gentoo udev main rule file.
3914 add parisc support to path_id
3915
3916Hannes Reinecke:
3917 scsi_id: -u fold multiple consecutive whitespace chars into single '_'
3918
3919Harald Hoyer:
3920 optimize SELinux path match
3921
3922Kay 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
3932Kurt Garloff:
3933 scsi_id: support pre-SPC3 page 83 format
3934
3935
3936Summary of changes from v076 to v077
3937============================================
3938
3939Kay 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
3951Marco 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
3957Summary of changes from v75 to v076
3958============================================
3959
3960Kay 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
3980Scott James Remnant:
3981 move delete_path() to utils
3982 clean-up empty queue directories
3983 Makefile: fail, if submake fails
3984
3985
3986Summary of changes from v74 to v075
3987============================================
3988
3989Greg Kroah-Hartman:
3990 Make run_directory.c stat the place it is going to try to run.
3991
3992Kay 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
4004Summary of changes from v73 to v074
4005============================================
4006
4007Kay 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
4013Marco d'Itri:
4014 add strerror() to error logs
4015 move some logging from dbg() to info()
4016
4017
4018Summary of changes from v72 to v073
4019============================================
4020
4021Kay 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
4027Summary of changes from v71 to v072
4028============================================
4029
4030Ananth N Mavinakayanahalli:
4031 libsysfs: translate devpath of the symlinked class devices to its real path
4032
4033Jan Luebbe:
4034 add man pages for *_id programs
4035
4036Kay 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
4072Summary of changes from v70 to v071
4073============================================
4074
4075Greg Kroah-Hartman:
4076 Remove the udev.spec file as no one uses it anymore
4077
4078John Hull:
4079 edd_id: check that EDD id is unique
4080
4081Kay 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
4101Marco d'Itri:
4102 run_directory: fix typo in "make install"
4103
4104
4105Summary of changes from v069 to v070
4106============================================
4107
4108Amir Shalem:
4109 udevd: fix udevd read() calls to leave room for null byte
4110
4111Edward Goggin:
4112 scsi_id: derive a UID for a SCSI-2 not compliant with the page 83
4113
4114Greg Kroah-Hartman:
4115 fix nbd error messages with a gentoo rule hack
4116 fix scsi_id rule in gentoo config file
4117
4118Jürg Billeter:
4119 EXTRAS/Makefile: fix install targets to match main Makefile
4120
4121Kay 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
4127Olivier Blin:
4128 fix a debug text typo in udev_rules.c
4129
4130
4131Summary of changes from v068 to v069
4132============================================
4133
4134Amir Shalem:
4135 fix typo in firmware_helper
4136
4137Duncan Sands:
4138 firmware_helper: fix write count
4139
4140Kay 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
4196Thierry Vignaud:
4197 switch to '==' in raid-devfs.sh
4198
4199
4200Summary of changes from v067 to v068
4201============================================
4202
4203Greg 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
4208Kay 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
4218Summary of changes from v066 to v067
4219============================================
4220
4221Greg Kroah-Hartman:
4222 added the cdrom.h #defines directly into the cdrom_id.c file
4223
4224Kay 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
4232Summary of changes from v065 to v066
4233============================================
4234
4235Greg 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
4246Kay 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
4267Thierry Vignaud:
4268 fix udevinfo output
4269
4270
4271Summary of changes from v064 to v065
4272============================================
4273
4274Greg 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
4279Kay 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
4286Summary of changes from v063 to v064
4287============================================
4288
4289Andre Masella:
4290 volume_id: add OCFS (Oracle Cluster File System) support
4291
4292Hannes 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
4297Kay 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
4305Summary of changes from v062 to v063
4306============================================
4307
4308Anton Farygin:
4309 fix typo in GROUP value application
4310
4311Greg 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
4317Hannes Reinecke:
4318 dasd_id: add s390 disk-label prober
4319 fix usb_id and let scsi_id ignore "illegal request"
4320
4321Kay 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
4331Ville Skyttä:
4332 correct default mode documentation in udev
4333
4334
4335Summary of changes from v061 to v062
4336============================================
4337
4338Kay 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
4346Summary of changes from v060 to v061
4347============================================
4348
4349Greg Kroah-Hartman:
4350 Sync up the Debian rules files
4351 fix cdrom symlink problem in gentoo rules
4352 Fix ChangeLog titles
4353
4354Kay 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
4372Summary of changes from v059 to v060
4373============================================
4374
4375Greg Kroah-Hartman:
4376 Fix the gentoo udev rules to allow the box to boot properly
4377
4378Gustavo Zacarias:
4379 Udev doesn't properly build with $CROSS
4380
4381Kay Sievers:
4382 Keep udevstart from skipping devices without a 'dev' file
4383
4384Marco d'Itri:
4385 #define NETLINK_KOBJECT_UEVENT
4386
4387
4388Summary of changes from v058 to v059
4389============================================
4390
4391Greg 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
4396Hannes Reinecke:
4397 udev: fix netdev RUN handling
4398 udevcontrol: fix exit code
4399
4400Kay 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
4435Stefan Schweizer:
4436 Dialout group fix for capi devices in the gentoo rules file
4437
4438Summary of changes from v057 to v058
4439============================================
4440
4441Daniel Drake:
4442 o Writing udev rules docs update
4443
4444Darren Salt:
4445 o update cdsymlinks to latest version
4446
4447Greg 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
4456Kay 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
4462Masanao Igarashi:
4463 o Fix libsysfs issue with relying on the detach_state file to be
4464
4465Summary of changes from v056 to v057
4466============================================
4467
4468<tklauser:access.unizh.ch>:
4469 o fix stupid all_partitions bug
4470
4471Kay 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
4504Summary of changes from v055 to v056
4505============================================
4506
4507<tklauser:access.unizh.ch>:
4508 o fix header paths in udev_libc_wrapper.c
4509
4510Kay 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
4521Summary 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
4534Greg Kroah-Hartman:
4535 o fix raid rules
4536 o added frugalware udev ruleset
4537 o merge selinux and Kay's symlink fixes together
4538
4539Hannes Reinecke:
4540 o volume_id: Fix label/uuid reading for reiserfs
4541
4542Kay 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
4596Thierry Vignaud:
4597 o gentoo rule update for raid devices
4598
4599
4600Summary of changes from v053 to v054
4601============================================
4602
4603<tklauser:access.unizh.ch>:
4604 o udev_volume_id: add Reiser4 support
4605
4606Kay 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
4628Patrick Mansfield:
4629 o update scsi_id to work with libsysfs changes
4630
4631
4632Summary of changes from v052 to v053
4633============================================
4634
4635Greg 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
4641Kay 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
4649Patrick Mansfield:
4650 o scsi_id changes for use with udev %N and %p
4651
4652
4653Summary 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
4665Greg 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
4672Kay 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
4685Michael 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
4692Summary 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
4701Christian Bornträger:
4702 o udev_volume_id: fix -d option
4703
4704Greg 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
4712Hannes Reinecke:
4713 o rearrange link order in Makefile
4714
4715Kay 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
4749Michael Buesch:
4750 o The attached patch fixes the code path if namedev_name_device() fails
4751
4752Summary 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
4761Kay 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
4767Summary of changes from v048 to v049
4768============================================
4769
4770Greg Kroah-Hartman:
4771 o fix 'make clean' error in klibc
4772
4773Kay 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
4787Martin Schlemmer:
4788 o remove leftover from udevinfo's -d option
4789
4790
4791Summary of changes from v047 to v048
4792============================================
4793
4794Greg 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
4799Summary 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
4811Greg 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
4827Kay 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
4864Summary of changes from v045 to v046
4865============================================
4866
4867Greg Kroah-Hartman:
4868 o make spotless for releases
4869
4870Kay 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
4896Summary of changes from v044 to v045
4897============================================
4898
4899Martin Schlemmer:
4900 o Some updates for Gentoo's udev rules
4901
4902
4903Summary of changes from v043 to v044
4904============================================
4905
4906Greg 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
4912Kay 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
4917Summary of changes from v042 to v043
4918============================================
4919
4920Greg Kroah-Hartman:
4921 o add test target to makefile
4922 o add dumb script to show all sysfs devices in the system
4923
4924Kay 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
4941Summary of changes from v040 to v042
4942============================================
4943
4944Greg Kroah-Hartman:
4945 o add inotify to the rules for gentoo
4946
4947Kay 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
4959Summary of changes from v039 to v040
4960============================================
4961
4962<jk:blackdown.de>:
4963 o wait_for_sysfs update for dm devices
4964
4965Greg 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
4972Kay 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
4984Summary of changes from v038 to v039
4985============================================
4986
4987Greg 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
4998Kay 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
5006Patrick 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
5012Summary of changes from v037 to v038
5013============================================
5014
5015<andrew.patterson:hp.com>:
5016 o Re: Problem parsing %s in udev rules
5017
5018Greg Kroah-Hartman:
5019 o fix up error in building extras and libsysfs
5020
5021Summary of changes from v036 to v037
5022============================================
5023
5024<md:linux.it>:
5025 o small udev patch
5026
5027Greg 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
5042Kay Sievers:
5043 o prevent deadlocks on an corrupt udev database
5044 o wait_for_sysfs_update
5045
5046Michael Buesch:
5047 o fix asmlinkage
5048 o fix incompatible pointer type warning
5049
5050
5051Summary of changes from v035 to v036
5052============================================
5053
5054Greg Kroah-Hartman:
5055 o add the error number to the error message in wait_for_sysfs to help out in debugging problems
5056
5057Summary of changes from v034 to v035
5058============================================
5059
5060Greg 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
5064Summary of changes from v033 to v034
5065============================================
5066
5067Kay Sievers:
5068 o wait_for_sysfs bluetooth class update
5069
5070Greg 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
5080Summary 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
5093Greg 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
5108Kay 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
5119Patrick Mansfield:
5120 o update udev to include scsi_id 0.6
5121
5122
5123Summary of changes from v031 to v032
5124============================================
5125
5126<harald:redhat.com>:
5127 o udev parse bug
5128
5129Kay Sievers:
5130 o handle only block and class devices
5131 o fix udevstart badly broken in udev 031
5132
5133
5134Summary 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
5146David Weinehall:
5147 o Minor POSIX-fixes for udev
5148
5149Greg 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
5157Kay 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
5164Martin Schlemmer:
5165 o add microcode rule to permissions.gentoo file
5166
5167Michael Buesch:
5168 o Try to provide a bit of security for hardlinks to /dev entries
5169
5170Olaf Hering:
5171 o udevsend depends on udev_lib.o
5172
5173Tom 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
5180Summary of changes from v029 to v030
5181============================================
5182
5183Greg Kroah-Hartman:
5184 o fix stupid off-by-one bug that caused udevstart to die on x86-64 boxes
5185
5186
5187Summary of changes from v028 to v029
5188============================================
5189
5190Greg 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
5197Olaf Hering:
5198 o allow NAME_SIZE > SYSFS_PATH_MAX
5199
5200
5201Summary of changes from v027 to v028
5202============================================
5203
5204<atul.sabharwal:intel.com>:
5205 o Patch for chassis_id exras module
5206
5207Daniel Drake:
5208 o Writing udev rules doc update
5209
5210Greg 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
5214Kay Sievers:
5215 o update udev_volume_id
5216
5217Leann Ogasawara:
5218 o udevstart performance increase
5219
5220Patrick Mansfield:
5221 o update udev scsi_id to scsi_id 0.5
5222
5223
5224Summary of changes from v026 to v027
5225============================================
5226
5227<fork0:users.sf.net>:
5228 o fix handle leak in udev_lib.c
5229
5230Greg Kroah-Hartman:
5231 o tweak the gentoo default permission rules as they are wrong for tty and misc devices
5232
5233
5234Summary of changes from v025 to v026
5235============================================
5236
5237Arnd Bergmann:
5238 o udev rpm fix
5239
5240Greg 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
5252Kay 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
5261Leann Ogasawara:
5262 o evaluate getenv() return value for udev_config.c
5263
5264Summary 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
5273Daniel Drake:
5274 o Update writing udev rules docs
5275
5276Greg 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
5295Kay 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
5302Leann Ogasawara:
5303 o gcov for udev
5304
5305
5306Summary 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
5325Greg 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
5351Kay 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
5368Summary of changes from v022 to v023
5369============================================
5370
5371Kay 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
5379Daniel E. F. Stekloff:
5380 o udevinfo patch
5381
5382Greg 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
5409Olaf Hering:
5410 o uninitialized variable for mknod and friend
5411
5412Richard Gooch:
5413 o SCSI logical and physical names for udev
5414
5415Theodore Y. T'so:
5416 o Trivial man page typo fixes to udev
5417
5418
5419Summary 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
5429Kay 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
5455Greg 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
5466Hanna V. Linder:
5467 o Small fix to remove extra "will" in man page
5468
5469Olaf Hering:
5470 o make spotless
5471 o udev* segfaults with new klibc
5472
5473Patrick Mansfield:
5474 o add tests for NAME="foo-%c{N}"
5475
5476Summary of changes from v020 to v021
5477============================================
5478
5479Kay Sievers:
5480 o install udevinfo in /usr/bin
5481 o blacklist pcmcia_socket
5482
5483Greg 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
5490Summary of changes from v019 to v020
5491============================================
5492
5493<christophe.varoqui:free.fr>:
5494 o multipath update
5495
5496Kay 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
5521Andrey Borzenkov:
5522 o Add symlink only rules support
5523
5524Greg 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
5537Summary of changes from v018 to v019
5538============================================
5539
5540Kay 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
5552Andrey Borzenkov:
5553 o do not remove real .udev.tdb during RPM build
5554
5555Greg 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
5565Patrick Mansfield:
5566 o update udev scsi_id to scsi_id 0.4
5567
5568
5569Summary 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
5579Kay 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
5589Greg 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
5613Patrick Mansfield:
5614 o udev use new libsysfs header file location
5615 o udev add some ID tests
5616
5617
5618Summary 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
5629Kay 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
5643Greg 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
5667Patrick Mansfield:
5668 o udev add wild card compare for ID
5669 o udev kill extra bus_id compares in match_id
5670
5671
5672Summary 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
5681Greg 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
5697Kay 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
5707Summary of changes from v014 to v015
5708============================================
5709
5710<mbuesch:freenet.de>:
5711 o LFS init script update
5712
5713Greg 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
5736Kay 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
5745Summary 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
5757Kay 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
5765Greg 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
5775Hanna V. Linder:
5776 o set default owner/group in db
5777 o small cut n paste error fix
5778
5779Patrick Mansfield:
5780 o update udev scsi_id to scsi_id 0.3
5781
5782
5783Summary 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
5795Christophe Saout:
5796 o add IGNORE rule type
5797 o small cleanup
5798
5799Greg 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
5820Kay 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
5837Summary 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
5848Kay 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
5866Greg 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
5882Summary 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
5894Greg 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
5912Summary 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
5924Kay 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
5939Adam Kropelin:
5940 o Allow build with empty EXTRAS
5941
5942Daniel 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
5947David T. Hollis:
5948 o mark config files as such in the rpm spec file
5949
5950Greg 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
5963Summary 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
5981Kay 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
5997Daniel E. F. Stekloff:
5998 o pre-libsysfs-0.4.0 patch
5999
6000Greg 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
6019Olaf Hering:
6020 o dump latest klibc into the udev build tree
6021 o use udevdir in udev.conf
6022
6023Patrick Mansfield:
6024 o better allow builds of extras programs under udev
6025 o update udev extras/scsi_id to version 0.2
6026
6027
6028Summary 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
6037Arnd 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
6042Daniel 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
6047Greg 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
6079Kay 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
6088Martin Hicks:
6089 o Add -nodefaultlibs while compiling against klibc
6090
6091Olaf Hering:
6092 o ARCH detection for ppc
6093
6094Patrick Mansfield:
6095 o fix udev parallel builds with klibc
6096
6097
6098Summary of changes from v006 to v007
6099============================================
6100
6101<md:linux.it>:
6102 o fix segfault in parsing bad udev.permissions file
6103
6104Greg 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
6117Kay 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
6125Olaf Hering:
6126 o static klibc udev does not link against crt0.o
6127
6128Summary of changes from v005 to v006
6129============================================
6130
6131<chris_friesen:sympatico.ca>:
6132 o faster test scripts
6133
6134Arnd Bergmann:
6135 o more robust config file parsing in namedev.c
6136 o add bus id modifier
6137
6138Daniel E. F. Stekloff:
6139 o patch for libsysfs sysfs directory handling
6140
6141Greg 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
6185Kay 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
6193Olaf Hering:
6194 o DESTDIR for udev
6195
6196Paul Mundt:
6197 o Fixup path for kernel includes when building with klibc
6198
6199Robert Love:
6200 o udev init script
6201
6202
6203Summary 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
6210Greg 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
6244Robert Love:
6245 o udev: sleep_for_dev() bits
6246 o udev: another canidate for static
6247
6248
6249Summary of changes from v003 to v004
6250============================================
6251
6252Daniel E. F. Stekloff:
6253 o new version of libsysfs patch
6254
6255Greg 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
6270Kay Sievers:
6271 o man file update
6272 o man page update
6273
6274Robert 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
6283Summary of changes from v0.2 to v003
6284============================================
6285
6286Daniel E. F. Stekloff:
6287 o udevdb patch
6288 o udevdb prototype
6289
6290Greg 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
6320Olaf Hering:
6321 o print udev pid
6322
6323Patrick Mansfield:
6324 o add callout config type to udev
6325
6326Paul Mundt:
6327 o Fix TDB cross compilation
6328 o udev spec file
6329 o udev/libsysfs cross compile fixes
6330
6331
6332Summary of changes from v0.1 to v0.2
6333============================================
6334
6335Greg 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
6369Summary of changes up to v0.1
6370============================================
6371
6372Greg 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 @@
1The 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
11The 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
21The options to install udev in the rootfs instead of /usr,
22and 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
33Some tools expect udevadm in 'sbin'. A symlink to udevadm in 'bin'
34needs to be manually created if needed.
35
36The defined location for scripts and binaries which are called
37from rules is (/usr)/lib/udev/ on all systems and architectures. Any
38other location will break other packages, who rightfully expect
39the (/usr)/lib/udev/ directory, to install their rule helper and udev
40rule files.
41
42Default udev rules and persistent device naming rules may be required
43by other software that depends on the data udev collects from the
44devices.
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
4SUBDIRS = .
5
6ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}
7
8AM_MAKEFLAGS = --no-print-directory
9
10LIBUDEV_CURRENT=13
11LIBUDEV_REVISION=2
12LIBUDEV_AGE=13
13
14LIBGUDEV_CURRENT=1
15LIBGUDEV_REVISION=1
16LIBGUDEV_AGE=1
17
18AM_CPPFLAGS = \
19 -include $(top_builddir)/config.h \
20 -I$(top_srcdir)/src \
21 -DSYSCONFDIR=\""$(sysconfdir)"\" \
22 -DPKGLIBEXECDIR=\""$(libexecdir)/udev"\"
23
24AM_CFLAGS = \
25 ${my_CFLAGS} \
26 -fvisibility=hidden \
27 -ffunction-sections \
28 -fdata-sections
29
30AM_LDFLAGS = \
31 -Wl,--gc-sections \
32 -Wl,--as-needed
33
34DISTCHECK_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
42BUILT_SOURCES =
43EXTRA_DIST =
44CLEANFILES =
45INSTALL_EXEC_HOOKS =
46INSTALL_DATA_HOOKS =
47UNINSTALL_EXEC_HOOKS =
48DISTCHECK_HOOKS =
49DISTCLEAN_LOCAL_HOOKS =
50
51udevhomedir = $(libexecdir)/udev
52udevhome_SCRIPTS =
53dist_udevhome_SCRIPTS =
54dist_udevhome_DATA =
55dist_man_MANS =
56
57SED_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# ------------------------------------------------------------------------------
87SUBDIRS += src/docs
88
89include_HEADERS = src/libudev.h
90lib_LTLIBRARIES = libudev.la
91noinst_LTLIBRARIES = libudev-private.la
92
93libudev_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
103libudev_la_LDFLAGS = \
104 $(AM_LDFLAGS) \
105 -version-info $(LIBUDEV_CURRENT):$(LIBUDEV_REVISION):$(LIBUDEV_AGE)
106
107libudev_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
113if WITH_SELINUX
114libudev_private_la_SOURCES += src/libudev-selinux-private.c
115libudev_private_la_LIBADD = $(SELINUX_LIBS)
116endif
117
118pkgconfigdir = $(libdir)/pkgconfig
119pkgconfig_DATA = src/libudev.pc
120EXTRA_DIST += src/libudev.pc.in
121CLEANFILES += src/libudev.pc
122
123EXTRA_DIST += src/COPYING
124# move lib from $(libdir) to $(rootlib_execdir) and update devel link, if needed
125libudev-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
134libudev-uninstall-move-hook:
135 rm -f $(DESTDIR)$(rootlib_execdir)/libudev.so*
136
137INSTALL_EXEC_HOOKS += libudev-install-move-hook
138UNINSTALL_EXEC_HOOKS += libudev-uninstall-move-hook
139
140# ------------------------------------------------------------------------------
141udev-confdirs:
142 -mkdir -p $(DESTDIR)$(sysconfdir)/udev/rules.d
143 -mkdir -p $(DESTDIR)$(libexecdir)/udev/devices
144
145INSTALL_DATA_HOOKS += udev-confdirs
146
147udevrulesdir = $(libexecdir)/udev/rules.d
148dist_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
162udevconfdir = $(sysconfdir)/udev
163dist_udevconf_DATA = src/udev.conf
164
165sharepkgconfigdir = $(datadir)/pkgconfig
166sharepkgconfig_DATA = src/udev.pc
167EXTRA_DIST += src/udev.pc.in
168CLEANFILES += src/udev.pc
169
170if WITH_SYSTEMD
171dist_systemdsystemunit_DATA = \
172 src/udev-control.socket \
173 src/udev-kernel.socket
174
175systemdsystemunit_DATA = \
176 src/udev.service \
177 src/udev-trigger.service \
178 src/udev-settle.service
179
180EXTRA_DIST += \
181 src/udev.service.in \
182 src/udev-trigger.service.in \
183 src/udev-settle.service.in
184
185CLEANFILES += \
186 src/udev.service \
187 src/udev-trigger.service \
188 src/udev-settle.service
189
190systemd-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
198INSTALL_DATA_HOOKS += systemd-install-hook
199endif
200
201bin_PROGRAMS = \
202 udevadm
203
204pkglibexec_PROGRAMS = \
205 udevd
206
207udev_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
223udev_common_CFLAGS = \
224 $(BLKID_CFLAGS) \
225 $(KMOD_CFLAGS)
226
227udev_common_LDADD = \
228 libudev-private.la \
229 $(BLKID_LIBS) \
230 $(KMOD_LIBS)
231
232udev_common_CPPFLAGS = \
233 $(AM_CPPFLAGS) \
234 -DFIRMWARE_PATH="$(FIRMWARE_PATH)" \
235 -DUSB_DATABASE=\"$(USB_DATABASE)\" -DPCI_DATABASE=\"$(PCI_DATABASE)\"
236
237udevd_SOURCES = \
238 $(udev_common_sources) \
239 src/udevd.c \
240 src/sd-daemon.h \
241 src/sd-daemon.c
242udevd_CFLAGS = $(udev_common_CFLAGS)
243udevd_LDADD = $(udev_common_LDADD)
244udevd_CPPFLAGS = $(udev_common_CPPFLAGS)
245
246udevadm_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
256udevadm_CFLAGS = $(udev_common_CFLAGS)
257udevadm_LDADD = $(udev_common_LDADD)
258udevadm_CPPFLAGS = $(udev_common_CPPFLAGS)
259
260# ------------------------------------------------------------------------------
261if ENABLE_MANPAGES
262dist_man_MANS += \
263 src/udev.7 \
264 src/udevadm.8 \
265 src/udevd.8
266endif
267
268EXTRA_DIST += \
269 src/udev.xml \
270 src/udevadm.xml \
271 src/udevd.xml
272
273if HAVE_XSLTPROC
274dist_noinst_DATA = \
275 src/udev.html \
276 src/udevadm.html \
277 src/udevd.html
278
279src/%.7 src/%.8 : src/%.xml
280 $(AM_V_GEN)$(XSLTPROC) -o $@ -nonet http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $<
281
282src/%.html : src/%.xml
283 $(AM_V_GEN)$(XSLTPROC) -o $@ -nonet http://docbook.sourceforge.net/release/xsl/current/xhtml-1_1/docbook.xsl $<
284endif
285
286# ------------------------------------------------------------------------------
287TESTS = \
288 test/udev-test.pl \
289 test/rules-test.sh
290
291check_PROGRAMS = \
292 test-libudev \
293 test-udev
294
295test_libudev_SOURCES = src/test-libudev.c
296test_libudev_LDADD = libudev.la
297
298test_udev_SOURCES = \
299 $(udev_common_sources) \
300 src/test-udev.c
301test_udev_CFLAGS = $(udev_common_CFLAGS)
302test_udev_LDADD = $(udev_common_LDADD)
303test_udev_CPPFLAGS = $(udev_common_CPPFLAGS)
304test_udev_DEPENDENCIES = test/sys
305
306# packed sysfs test tree
307test/sys:
308 $(AM_V_GEN)mkdir -p test && tar -C test/ -xJf $(top_srcdir)/test/sys.tar.xz
309
310test-sys-distclean:
311 -rm -rf test/sys
312DISTCLEAN_LOCAL_HOOKS += test-sys-distclean
313
314EXTRA_DIST += test/sys.tar.xz
315
316# ------------------------------------------------------------------------------
317ata_id_SOURCES = src/ata_id/ata_id.c
318ata_id_LDADD = libudev-private.la
319pkglibexec_PROGRAMS += ata_id
320
321# ------------------------------------------------------------------------------
322cdrom_id_SOURCES = src/cdrom_id/cdrom_id.c
323cdrom_id_LDADD = libudev-private.la
324pkglibexec_PROGRAMS += cdrom_id
325dist_udevrules_DATA += src/cdrom_id/60-cdrom_id.rules
326
327# ------------------------------------------------------------------------------
328collect_SOURCES = src/collect/collect.c
329collect_LDADD = libudev-private.la
330pkglibexec_PROGRAMS += collect
331
332# ------------------------------------------------------------------------------
333scsi_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
338scsi_id_LDADD = libudev-private.la
339pkglibexec_PROGRAMS += scsi_id
340dist_man_MANS += src/scsi_id/scsi_id.8
341EXTRA_DIST += src/scsi_id/README
342
343# ------------------------------------------------------------------------------
344v4l_id_SOURCES = src/v4l_id/v4l_id.c
345v4l_id_LDADD = libudev-private.la
346pkglibexec_PROGRAMS += v4l_id
347dist_udevrules_DATA += src/v4l_id/60-persistent-v4l.rules
348
349# ------------------------------------------------------------------------------
350accelerometer_SOURCES = src/accelerometer/accelerometer.c
351accelerometer_LDADD = libudev-private.la -lm
352pkglibexec_PROGRAMS += accelerometer
353dist_udevrules_DATA += src/accelerometer/61-accelerometer.rules
354
355# ------------------------------------------------------------------------------
356if ENABLE_GUDEV
357SUBDIRS += src/gudev/docs
358
359libgudev_includedir=$(includedir)/gudev-1.0/gudev
360libgudev_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
369lib_LTLIBRARIES += libgudev-1.0.la
370
371pkgconfig_DATA += src/gudev/gudev-1.0.pc
372EXTRA_DIST += src/gudev/gudev-1.0.pc.in
373CLEANFILES += src/gudev/gudev-1.0.pc
374
375libgudev_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
388nodist_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
393BUILT_SOURCES += $(nodist_libgudev_1_0_la_SOURCES)
394
395libgudev_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
405libgudev_1_0_la_CFLAGS = \
406 -fvisibility=default \
407 $(GLIB_CFLAGS)
408
409libgudev_1_0_la_LIBADD = libudev.la $(GLIB_LIBS)
410
411libgudev_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
416EXTRA_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
425src/gudev/gudevmarshal.h: src/gudev/gudevmarshal.list
426 $(AM_V_GEN)glib-genmarshal $< --prefix=g_udev_marshal --header > $@
427
428src/gudev/gudevmarshal.c: src/gudev/gudevmarshal.list
429 $(AM_V_GEN)echo "#include \"gudevmarshal.h\"" > $@ && \
430 glib-genmarshal $< --prefix=g_udev_marshal --body >> $@
431
432src/gudev/gudevenumtypes.h: src/gudev/gudevenumtypes.h.template src/gudev/gudevenums.h
433 $(AM_V_GEN)glib-mkenums --template $^ > \
434 $@.tmp && mv $@.tmp $@
435
436src/gudev/gudevenumtypes.c: src/gudev/gudevenumtypes.c.template src/gudev/gudevenums.h
437 $(AM_V_GEN)glib-mkenums --template $^ > \
438 $@.tmp && mv $@.tmp $@
439
440if ENABLE_INTROSPECTION
441src/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
470src/gudev/GUdev-1.0.typelib: src/gudev/GUdev-1.0.gir $(G_IR_COMPILER)
471 $(AM_V_GEN)g-ir-compiler $< -o $@
472
473girdir = $(GIRDIR)
474gir_DATA = src/gudev/GUdev-1.0.gir
475
476typelibsdir = $(GIRTYPELIBDIR)
477typelibs_DATA = src/gudev/GUdev-1.0.typelib
478
479CLEANFILES += $(gir_DATA) $(typelibs_DATA)
480endif # ENABLE_INTROSPECTION
481
482# move lib from $(libdir) to $(rootlib_execdir) and update devel link, if needed
483libgudev-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
492libgudev-uninstall-move-hook:
493 rm -f $(DESTDIR)$(rootlib_execdir)/libgudev-1.0.so*
494
495INSTALL_EXEC_HOOKS += libgudev-install-move-hook
496UNINSTALL_EXEC_HOOKS += libgudev-uninstall-move-hook
497endif
498
499# ------------------------------------------------------------------------------
500if ENABLE_KEYMAP
501keymap_SOURCES = src/keymap/keymap.c
502keymap_CPPFLAGS = $(AM_CPPFLAGS) -I src/keymap
503nodist_keymap_SOURCES = \
504 src/keymap/keys-from-name.h \
505 src/keymap/keys-to-name.h
506BUILT_SOURCES += $(nodist_keymap_SOURCES)
507
508pkglibexec_PROGRAMS += keymap
509dist_doc_DATA = src/keymap/README.keymap.txt
510
511dist_udevrules_DATA += \
512 src/keymap/95-keymap.rules \
513 src/keymap/95-keyboard-force-release.rules
514
515dist_udevhome_SCRIPTS += src/keymap/findkeyboards
516udevhome_SCRIPTS += src/keymap/keyboard-force-release.sh
517
518EXTRA_DIST += \
519 src/keymap/check-keymaps.sh \
520 src/keymap/keyboard-force-release.sh.in
521
522CLEANFILES += \
523 src/keymap/keys.txt \
524 src/keymap/keys-from-name.gperf \
525 src/keymap/keyboard-force-release.sh
526
527udevkeymapdir = $(libexecdir)/udev/keymaps
528dist_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
588udevkeymapforcereldir = $(libexecdir)/udev/keymaps/force-release
589dist_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
596src/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
600src/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
603src/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
606src/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
609keymaps-distcheck-hook: src/keymap/keys.txt
610 $(top_srcdir)/src/keymap/check-keymaps.sh $(top_srcdir) $^
611DISTCHECK_HOOKS += keymaps-distcheck-hook
612endif
613
614if ENABLE_MTD_PROBE
615# ------------------------------------------------------------------------------
616mtd_probe_SOURCES = \
617 src/mtd_probe/mtd_probe.c \
618 src/mtd_probe/mtd_probe.h \
619 src/mtd_probe/probe_smartmedia.c
620mtd_probe_CPPFLAGS = $(AM_CPPFLAGS)
621dist_udevrules_DATA += src/mtd_probe/75-probe_mtd.rules
622pkglibexec_PROGRAMS += mtd_probe
623endif
624
625# ------------------------------------------------------------------------------
626if ENABLE_RULE_GENERATOR
627dist_udevhome_SCRIPTS += \
628 src/rule_generator/write_cd_rules \
629 src/rule_generator/write_net_rules
630
631dist_udevhome_DATA += \
632 src/rule_generator/rule_generator.functions
633
634dist_udevrules_DATA += \
635 src/rule_generator/75-cd-aliases-generator.rules \
636 src/rule_generator/75-persistent-net-generator.rules
637endif
638
639# ------------------------------------------------------------------------------
640if ENABLE_FLOPPY
641create_floppy_devices_SOURCES = src/floppy/create_floppy_devices.c
642create_floppy_devices_LDADD = libudev-private.la
643pkglibexec_PROGRAMS += create_floppy_devices
644dist_udevrules_DATA += src/floppy/60-floppy.rules
645endif
646
647# ------------------------------------------------------------------------------
648clean-local:
649 rm -rf udev-test-install
650
651distclean-local:
652 rm -rf autom4te.cache
653
654EXTRA_DIST += \
655 $(TESTS) \
656 test/rule-syntax-check.py
657
658CLEANFILES += \
659 $(BUILT_SOURCES)
660
661install-exec-hook: $(INSTALL_EXEC_HOOKS)
662
663install-data-hook: $(INSTALL_DATA_HOOKS)
664
665uninstall-hook: $(UNINSTALL_EXEC_HOOKS)
666
667distcheck-hook: $(DISTCHECK_HOOKS)
668
669distclean-local: $(DISTCLEAN_LOCAL_HOOKS)
670
671# ------------------------------------------------------------------------------
672PREVIOUS_VERSION = `expr $(VERSION) - 1`
673changelog:
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
685test-install:
686 rm -rf $(PWD)/udev-test-install/
687 make DESTDIR=$(PWD)/udev-test-install install
688 tree $(PWD)/udev-test-install/
689
690git-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
697git-sync:
698 git push
699 git push --tags
700
701tar-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
706doc-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 @@
1udev 182
2========
3Rules 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
6the later ones override the earlier ones. In other words: the admin has
7always the last say.
8
9USB auto-suspend is now enabled by default for some built-in USB HID
10devices.
11
12/dev/disk/by-path/ links are no longer created for ATA devices behind
13an 'ATA transport class', the logic to extract predictable numbers does
14not exist in the kernel at this moment.
15
16/dev/disk/by-id/scsi-* compatibility links are no longer created for
17ATA devices, they have their own ata-* prefix.
18
19The s390 rule to set mode == 0666 for /dev/z90crypt is is removed from
20the udev tree and will be part of s390utils (or alternatively could be
21done by the kernel driver itself).
22
23The udev-acl tool is no longer provided, it will be part of a future
24ConsoleKit release. On systemd systems, advanced ConsoleKit and udev-acl
25functionality are provided by systemd.
26
27udev 181
28========
29Require kmod version 5.
30
31Provide /dev/cdrom symlink for /dev/sr0.
32
33udev 180
34========
35Fix for ID_PART_ENTRY_* property names, added by the blkid built-in. The
36fix is needed for udisk2 to operate properly.
37
38Fix for skipped rule execution when the kernel has removed the device
39node in /dev again, before the event was even started. The fix is needed
40to run device-mapper/LVM events properly.
41
42Fix for the man page installation, which was skipped when xsltproc was not
43installed.
44
45udev 179
46========
47Bugfix for $name resolution, which broke at least some keymap handling.
48
49udev 178
50========
51Bugfix for the firmware loading behavior with kernel modules which
52try to load firmware in the module_init() path. The blocked event
53runs into a timout now, which should allow the firmware to be loaded.
54
55Bugfix for a wrong DEVNAME= export, which breaks at least the udev-acl
56tool.
57
58Bugfix for missing ID_ properties for GPT partitions.
59
60The RUN+="socket:.." option is deprecated and should not be used. A warning
61during rules parsing is printed now. Services which listen to udev events,
62need to subscribe to the netlink messages with libudev and not let udev block
63in the rules execution until the message is delivered.
64
65udev 177
66========
67Bugfix for rule_generator instalation.
68
69udev 176
70========
71The 'devtmpfs' filesystem is required now, udev will not create or delete
72device nodes anymore, it only adjusts permissions and ownership of device
73nodes and maintains additional symlinks.
74
75A writable /run directory (ususally tmpfs) is required now for a fully
76functional udev, there is no longer a fallback to /dev/.udev.
77
78The default 'configure' install locations have changed. Packages for systems
79with the historic / vs. /usr split need to be adapted, otherwise udev will
80be installed in /usr and not work properly. Example configuration options
81to install things the traditional way are in INSTALL.
82
83The default install location of the 'udevadm' tool moved from 'sbin'
84to /usr/bin. Some tools expect udevadm in 'sbin', a symlink to udevadm
85needs to be manually created if needed, or --bindir=/sbin be specified.
86
87The expected value of '--libexecdir=' has changed and must no longer contain
88the 'udev' directory.
89
90Kernel modules are now loaded directly by linking udev to 'libkmod'. The
91'modprobe' tool is no longer executed by udev.
92
93The 'blkid' tool is no longer executed from udev rules. Udev links
94directly to libblkid now.
95
96Firmware is loaded natively by udev now, the external 'firmware' binary
97is no longer used.
98
99All built-in tools can be listed and tested with 'udevadm test-builtin'.
100
101The 'udevadm control --reload-rules' option has been renamed to '--reload'.
102It now also reloads the kernel module configuration.
103
104The systemd socket files use PassCredentials=yes, which is available in
105systemd version 38.
106
107The udev build system only creates a .xz tarball now.
108
109All tabs in the source code used for indentation are replaced by spaces now. :)
110
111udev 175
112========
113Bugfixes.
114
115udev 174
116========
117Bugfixes.
118
119The udev daemon moved to /lib/udev/udevd. Non-systemd init systems
120and non-dracut initramfs image generators need to change the init
121scripts. 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
124The path_id, usb_id, input_id tools are built-in commands now and
125the stand-alone tools do not exist anymore. Static lists of file in
126initramfs generators need to be updated. For testing, the commands
127can still be executed standalone with 'udevadm test-builtin <cmd>'.
128
129The fusectl filesystem is no longer mounted directly from udev.
130Systemd systems will take care of mounting fusectl and configfs
131now. Non-systemd systems need to ship their own rule if they
132need these filesystems auto-mounted.
133
134The long deprecated keys: SYSFS=, ID=, BUS= have been removed.
135
136The support for 'udevadm trigger --type=failed, and the
137RUN{fail_event_on_error} attribute was removed.
138
139The udev control socket is now created in /run/udev/control
140and no longer as an abstract namespace one.
141
142The rules to create persistent network interface and cdrom link
143rules automatically in /etc/udev/rules.d/ have been disabled by
144default. Explicit configuration will be required for these use
145cases, udev will no longer try to write any persistent system
146configuration from a device hotplug path.
147
148udev 173
149========
150Bugfixes.
151
152The 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
154systems, the udev-acl rules prevent it from running as the functionality
155has moved to systemd.
156
157udev 172
158========
159Bugfixes.
160
161Udev now enables kernel media-presence polling if available. Part
162of udisks optical drive tray-handling moved to cdrom_id: The tray
163is locked as soon as a media is detected to enable the receiving
164of media-eject-request events. Media-eject-request events will
165eject the media.
166
167Libudev enumerate is now able to enumerate a subtree of a given
168device.
169
170The mobile-action-modeswitch modeswitch tool was deleted. The
171functionality is provided by usb_modeswitch now.
172
173udev 171
174========
175Bugfixes.
176
177The systemd service files require systemd version 28. The systemd
178socket activation make it possible now to start 'udevd' and 'udevadm
179trigger' in parallel.
180
181udev 170
182========
183Fix bug in control message handling, which can lead to a failing
184udevadm control --exit. Thanks to Jürg Billeter for help tracking
185it down.
186
187udev 169
188========
189Bugfixes.
190
191We require at least Linux kernel 2.6.32 now. Some platforms might
192require a later kernel that supports accept4() and similar, or
193need to backport the trivial syscall wiring to the older kernels.
194
195The hid2hci tool moved to the bluez package and was removed.
196
197Many of the extras can be --enable/--disabled at ./configure
198time. The --disable-extras option was removed. Some extras have
199been disabled by default. The current options and their defaults
200can be checked with './configure --help'.
201
202udev 168
203========
204Bugfixes.
205
206Udev logs a warning now if /run is not writable at udevd
207startup. It will still fall back to /dev/.udev, but this is
208now considered a bug.
209
210The running udev daemon can now cleanly shut down with:
211 udevadm control --exit
212
213Udev in initramfs should clean the state of the udev database
214with: udevadm info --cleanup-db which will remove all state left
215behind from events/rules in initramfs. If initramfs uses
216--cleanup-db and device-mapper/LVM, the rules in initramfs need
217to add OPTIONS+="db_persist" for all dm devices. This will
218prevent removal of the udev database for these devices.
219
220Spawned programs by PROGRAM/IMPORT/RUN now have a hard timeout of
221120 seconds per process. If that timeout is reached the spawned
222process will be killed. The event timeout can be overwritten with
223udev rules.
224
225If systemd is used, udev gets now activated by netlink data.
226Systemd will bind the netlink socket which will buffer all data.
227If needed, such setup allows a seemless update of the udev daemon,
228where no event can be lost during a udevd update/restart.
229Packages need to make sure to: systemctl stop udev.socket udev.service
230or 'mask' udev.service during the upgrade to prevent any unwanted
231auto-spawning of udevd.
232This version of udev conflicts with systemd version below 25. The
233unchanged service files will not wirk correctly.
234
235udev 167
236========
237Bugfixes.
238
239The udev runtime data moved from /dev/.udev/ to /run/udev/. The
240/run mountpoint is supposed to be a tmpfs mounted during early boot,
241available and writable to for all tools at any time during bootup,
242it replaces /var/run/, which should become a symlink some day.
243
244If /run does not exist, or is not writable, udev will fall back using
245/dev/.udev/.
246
247On systemd systems with initramfs and LVM used, packagers must
248make sure, that the systemd and initramfs versions match. The initramfs
249needs to create the /run mountpoint for udev to store the data, and
250mount this tmpfs to /run in the rootfs, so the that the udev database
251is preserved for the udev version started in the rootfs.
252
253The command 'udevadm info --convert-db' is gone. The udev daemon
254itself, at startup, converts any old database version if necessary.
255
256The systemd services files have been reorganized. The udev control
257socket is bound by systemd and passed to the started udev daemon.
258The udev-settle.service is no longer active by default. Services which
259can not handle hotplug setups properly need to actively pull it in, to
260act like a barrier. Alternatively the settle service can be unconditionally
261'systemctl'enabled, and act like a barrier for basic.target.
262
263The fstab_import callout is no longer built or installed. Udev
264should not be used to mount, does not watch changes to fstab, and
265should not mirror fstab values in the udev database.
266
267udev 166
268========
269Bugfixes.
270
271New and updated keymaps.
272
273udev 165
274========
275Bugfixes.
276
277The udev database has changed, After installation of a new udev
278version, 'udevadm info --convert-db' should be called, to let the new
279udev/libudev version read the already stored data.
280
281udevadm now supports quoting of property values, and prefixing of
282key 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
290libudev now supports:
291 udev_device_get_is_initialized()
292 udev_enumerate_add_match_is_initialized()
293to be able to skip devices the kernel has created , but udev has
294not already handled.
295
296libudev now supports:
297 udev_device_get_usec_since_initialized()
298to retrieve the "age" of a udev device record.
299
300GUdev supports a more generic GUdevEnumerator class, udev TAG
301handling, device initialization and timestamp now.
302
303The counterpart of /sys/dev/{char,block}/$major:$minor,
304/dev/{char,block}/$major:$minor symlinks are now unconditionally
305created, even when no rule files exist.
306
307New and updated keymaps.
308
309udev 164
310========
311Bugfixes.
312
313GUdev moved from /usr to /.
314
315udev 163
316========
317Bugfixes.
318
319udev 162
320========
321Bugfixes.
322
323Persistent network naming rules are disabled inside of Qemu/KVM now.
324
325New and updated keymaps.
326
327Udev gets unconditionally enabled on systemd installations now. There
328is no longer the need to to run 'systemctl enable udev.service'.
329
330udev 161
331========
332Bugfixes.
333
334udev 160
335========
336Bugfixes.
337
338udev 159
339========
340Bugfixes.
341
342New and fixed keymaps.
343
344Install systemd service files if applicable.
345
346udev 158
347========
348Bugfixes.
349
350All distribution specific rules are removed from the udev source tree,
351most of them are no longer needed. The Gentoo rules which allow to support
352older kernel versions, which are not covered by the default rules anymore
353has moved to rules/misc/30-kernel-compat.rules.
354
355udev 157
356========
357Bugfixes.
358
359The option --debug-trace and the environemnt variable UDEVD_MAX_CHILDS=
360was removed from udevd.
361
362Udevd 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=>
366to help debuging coldplug setups where the loading of a kernel
367module crashes the system.
368
369The subdirectory in the source tree rules/packages has been renamed to
370rules/arch, anc contains only architecture specific rules now.
371
372udev 156
373========
374Bugfixes.
375
376udev 155
377========
378Bugfixes.
379
380Now 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
389The default mode for a device node is 0600 now to match the kernel
390created devtmpfs defaults. If GROUP= is specified and no MODE= is
391given the default will be 0660.
392
393udev 154
394========
395Bugfixes.
396
397Udev now gradually starts to pass control over the primary device nodes
398and their names to the kernel, and will in the end only manage the
399permissions of the node, and possibly create additional symlinks.
400As a first step NAME="" will be ignored, and NAME= setings with names
401other than the kernel provided name will result in a logged warning.
402Kernels that don't provide device names, or devtmpfs is not used, will
403still work as they did before, but it is strongly recommended to use
404only the same names for the primary device node as the recent kernel
405provides for all devices.
406
407udev 153
408========
409Fix broken firmware loader search path.
410
411udev 152
412========
413Bugfixes.
414
415"udevadm trigger" defaults to "change" events now instead of "add"
416events. The "udev boot script" might need to add "--action=add" to
417the trigger command if not already there, in case the initial coldplug
418events are expected as "add" events.
419
420The option "all_partitons" was removed from udev. This should not be
421needed for usual hardware. Udev can not safely make assumptions
422about non-existing partition major/minor numbers, and therefore no
423longer provide this unreliable and unsafe option.
424
425The option "ignore_remove" was removed from udev. With devtmpfs
426udev passed control over device nodes to the kernel. This option
427should not be needed, or can not work as advertised. Neither
428udev nor the kernel will remove device nodes which are copied from
429the /lib/udev/devices/ directory.
430
431All "add|change" matches are replaced by "!remove" in the rules and
432in the udev logic. All types of events will update possible symlinks
433and permissions, only "remove" is handled special now.
434
435The modem modeswitch extra was removed and the external usb_modeswitch
436program should be used instead.
437
438New and fixed keymaps.
439
440udev 151
441========
442Bugfixes.
443
444udev 150
445========
446Bugfixes.
447
448Kernels with SYSFS_DEPRECATED=y are not supported since a while. Many users
449depend on the current sysfs layout and the information not available in the
450deprecated layout. All remaining support for the deprecated sysfs layout is
451removed now.
452
453udev 149
454========
455Fix for a possible endless loop in the new input_id program.
456
457udev 148
458========
459Bugfixes.
460
461The option "ignore_device" does no longer exist. There is no way to
462ignore an event, as libudev events can not be suppressed by rules.
463It only prevented RUN keys from being executed, which results in an
464inconsistent behavior in current setups.
465
466BUS=, SYSFS{}=, ID= are long deprecated and should be SUBSYSTEM(S)=,
467ATTR(S){}=, KERNEL(S)=. It will cause a warning once for every rule
468file from now on.
469
470The support for the deprecated IDE devices has been removed from the
471default set of rules. Distros who still care about non-libata drivers
472need to add the rules to the compat rules file.
473
474The ID_CLASS property on input devices has been replaced by the more accurate
475set of flags ID_INPUT_{KEYBOARD,KEY,MOUSE,TOUCHPAD,TABLET,JOYSTICK}. These are
476determined by the new "input_id" prober now. Some devices, such as touchpads,
477can have several classes. So if you previously had custom udev rules which e. g.
478checked for ENV{ID_CLASS}=="kbd", you need to replace this with
479ENV{ID_INPUT_KEYBOARD}=="?*".
480
481udev 147
482========
483Bugfixes.
484
485To support DEVPATH strings larger than the maximum file name length, the
486private udev database format has changed. If some software still reads the
487private files in /dev/.udev/, which it shouldn't, now it's time to fix it.
488Please do not port anything to the new format again, everything in /dev/.udev
489is and always was private to udev, and may and will change any time without
490prior notice.
491
492Multiple devices claiming the same names in /dev are limited to symlinks
493only now. Mixing identical symlink names and node names is not supported.
494This reduces the amount of data in the database significantly.
495
496NAME="%k" causes a warning now. It's is and always was completely superfluous.
497It will break kernel supplied DEVNAMEs and therefore it needs to be removed
498from all rules.
499
500Most NAME= instructions got removed. Kernel 2.6.31 supplies the needed names
501if they are not the default. To support older kernels, the NAME= rules need to
502be added to the compat rules file.
503
504Symlinks to udevadm with the old command names are no longer resolved to
505the udevadm commands.
506
507The udev-acl tool got adopted to changes in ConsoleKit. Version 0.4.1 is
508required now.
509
510The option "last_rule" does no longer exist. Its use breaks too many
511things which expect to be run from independent later rules, and is an idication
512that something needs to be fixed properly instead.
513
514The gudev API is no longer marked as experimental,
515G_UDEV_API_IS_SUBJECT_TO_CHANGE is no longer needed. The gudev introspection
516is enabled by default now. Various projects already depend on introspection
517information to bind dynamic languages to the gudev interfaces.
518
519udev 146
520========
521Bugfixes.
522
523The udevadm trigger "--retry-failed" option, which is replaced since quite
524a while by "--type=failed" is removed.
525
526The failed tracking was not working at all for a few releases. The RUN
527option "ignore_error" is replaced by a "fail_event_on_error" option, and the
528default is not to track any failing RUN executions.
529
530New keymaps, new modem, hid2hci updated.
531
532udev 145
533========
534Fix possible crash in udevd when worker processes are busy, rules are
535changed at the same time, and workers get killed to reload the rules.
536
537udev 144
538========
539Bugfixes.
540
541Properties set with ENV{.FOO}="bar" are marked private by starting the
542name with a '.'. They will not be stored in the database, and not be
543exported with the event.
544
545Firmware files are looked up in:
546 /lib/firmware/updates/$(uname -r)
547 /lib/firmware/updates
548 /lib/firmware/$(uname -r)
549 /lib/firmware"
550now.
551
552ATA devices switched the property from ID_BUS=scsi to ID_BUS=ata.
553ata_id, instead of scsi_id, is the default tool now for ATA devices.
554
555udev 143
556========
557Bugfixes.
558
559The configure options have changed because another library needs to be
560installed in a different location. Instead of exec_prefix and udev_prefix,
561libdir, rootlibdir and libexecdir are used. The Details are explained in
562the README file.
563
564Event processes now get re-used after they handled an event. This reduces
565the number of forks and the pressure on the CPU significantly, because
566cloned event processes no longer cause page faults in the main daemon.
567After the events have settled, a few worker processes stay around for
568future events, all others get cleaned up.
569
570To be able to use signalfd(), udev depends on kernel version 2.6.25 now.
571Also inotify support is mandatory now to run udev.
572
573The format of the queue exported by the udev damon has changed. There is
574no longer a /dev/.udev/queue/ directory. The current event queue can be
575accessed with udevadm settle and libudedv.
576
577Libudev does not have the unstable API header anymore. From now on,
578incompatible changes will be handled by bumping the library major version.
579
580To build udev from the git tree gtk-doc is needed now. The tarballs will
581build without it and contain the pre-built documentation. An online copy
582is available here:
583 http://www.kernel.org/pub/linux/utils/kernel/hotplug/libudev/
584
585The tools from the udev-extras repository have been merged into the main
586udev repository. Some of the extras have larger external dependencies, and
587they can be disabled with the configure switch --disable-extras.
588
589udev 142
590========
591Bugfixes.
592
593The program vol_id and the library libvolume_id are removed from the
594repository. Libvolume_id is merged with libblkid from the util-linux-ng
595package. Persistent disk links for label and uuid depend on the
596util-linux-ng version (2.15) of blkid now. Older versions of blkid
597can not be used with udev.
598
599Libudev allows to subscribe to udev events. To prevent unwanted messages
600to be delivered, and waking up the subscribing process, a filter can be
601installed, to drop messages inside a kernel socket filter. The filters
602match on the <subsytem>:<devtype> properties of the device.
603 This is part of the ongoing effort to replace HAL, and switch current
604users over to directly use libudev.
605 Libudev is still marked as experimental, and its interface might
606eventually change if needed, but no major changes of the currently exported
607interface are expected anymore, and a first stable release should happen
608soon.
609
610A too old kernel (2.6.21) or a kernel with CONFIG_SYSFS_DEPRECATED
611is not supported since while and udevd will log an error message at
612startup. It should still be able to boot-up, but advanced rules and system
613services which depend on the information not available in the old sysfs
614format will fail to work correctly.
615
616DVB device naming is supplied by the kernel now. In case older kernels
617need to be supported, the old shell script should be added to a compat
618rules file.
619
620udev 141
621========
622Bugfixes.
623
624The processed udev events get send back to the netlink socket. Libudev
625provides access to these events. This is work-in-progress, to replace
626the DeviceKit daemon functionality directly with libudev. There are
627upcoming kernel changes to allow non-root users to subcribe to these
628events.
629
630udev 140
631========
632Bugfixes.
633
634"udevadm settle" now optionally accepts a range of events to wait for,
635instead of waiting for "all" events.
636
637udev 139
638========
639Bugfixes.
640
641The installed watch for block device metadata changes is now removed
642during event hadling, because some (broken) tools may be called from udev
643rules and (wrongly) open the device with write access. After the finished
644event handling the watch is restored.
645
646udev 138
647========
648Bugfixes.
649
650Device nodes can be watched for changes with inotify with OPTIONS="watch".
651If closed after being opened for writing, a "change" uevent will occur.
652/dev/disk/by-{label,uuid}/* symlinks will be automatically updated.
653
654udev 137
655========
656Bugfixes.
657
658The udevadm test command has no longer a --force option, nodes and symlinks
659are always updated with a test run now.
660
661The udevd daemon can be started with --resolve-names=never to avoid all user
662and group lookups (e.g. in cut-down systems) or --resolve-names=late to
663lookup user and groups every time events are handled.
664
665udev 136
666========
667Bugfixes.
668
669We are currently merging the Ubuntu rules in the udev default rules,
670and get one step closer to provide a common Linux /dev setup, regarding
671device names, symlinks, and default device permissions. On udev startup,
672we now expect the following groups to be resolvable to their ids with
673glibc's getgrnam():
674 disk, cdrom, floppy, tape, audio, video, lp, tty, dialout, kmem.
675LDAP setups need to make sure, that these groups are always resolvable at
676bootup, with only the rootfs mounted, and without network access available.
677
678Some systems may need to add some new, currently not used groups, or need
679to add some users to new groups, but the cost of this change is minimal,
680compared to the pain the current, rather random, differences between the
681various distributions cause for upstream projects and third-party vendors.
682
683In general, "normal" users who log into a machine should never be a member
684of any such group, but the device-access should be managed by dynamic ACLs,
685which get added and removed for the specific users on login/logout and
686session activity/inactivity. These groups are only provided for custom setups,
687and mainly system services, to allow proper privilege separation.
688A video-streaming daemon uid would be a member of "audio" and "video", to get
689access to the sound and video devices, but no "normal" user should ever belong
690to the "audio" group, because he could listen to the built-in microphone with
691any ssh-session established from the other side of the world.
692
693/dev/serial/by-{id,path}/ now contains links for ttyUSB devices,
694which do not depend on the kernel device name. As usual, unique
695devices - only a single one per product connected, or a real
696USB serial number in the device - are always found with the same
697name in the by-id/ directory.
698Completely identical devices may overwrite their names in by-id/
699and can only be found reliably in the by-path/ directory. Devices
700specified by by-path/ must not change their connection, like the
701USB port number they are plugged in, to keep their name.
702
703To support some advanced features, Linux 2.6.22 is the oldest supported
704version now. The kernel config with enabled SYSFS_DEPRECATED is no longer
705supported. Older kernels should still work, and devices nodes should be
706reliably created, but some rules and libudev will not work correctly because
707the old kernels do not provide the expected information or interfaces.
708
709udev 135
710========
711Bugfixes.
712
713Fix for a possible segfault while swapping network interface names in udev
714versions 131-134.
715
716udev 134
717========
718Bugfixes.
719
720The group "video" is part of the default rules now.
721
722udev 133
723========
724Bugfix for kernels using SYSFS_DEPRECATED* option and finding parent
725block devices in some cases. No common distro uses this option anymore,
726and we do not get enough testing for this and recent udev versions. If
727this option is not needed to run some old distro with a new kernel,
728it should be disabled in the kernel config.
729
730Bugfix for the $links substitution variable, which may crash if no links
731are created. This should not happen in usual setups because we always
732create /dev/{block,char}/ links.
733
734The strings of the parsed rules, which are kept in memory, no longer
735contain duplicate entries, or duplicate tails of strings. This, and the
736new rules parsing/matching code reduces the total in-memory size of
737a huge distro rule sets to 0.08 MB, compared to the 1.2MB of udev
738version 130.
739
740The export of DEVTYPE=disk/partition got removed from the default
741rules. This value is available from the kernel. The pnp shell script
742modprobe hack is removed from the default rules. ACPI devices have _proper_
743modalias support and take care of the same functionality.
744Installations which support old kernels, but install current default
745udev rules may want to add that to the compat rules file.
746
747Libvolume_id now always probes for all known filesystems, and does not
748stop at the first match. Some filesystems are marked as "exclusive probe",
749and if any other filesytem type matches at the same time, libvolume_id
750will, by default, not return any probing result. This is intended to prevent
751mis-detection with conflicting left-over signatures found from earlier
752file system formats. That way, we no longer depend on the probe-order
753in case of multiple competing signatures. In some setups the kernel allows
754to mount a volume with just the old filesystem signature still in place.
755This may damage the new filesystem and cause data-loss, just by mounting
756it. Because volume_id can not decide which one the correct signature is,
757the wrong signatures need to be removed manually from the volume, or the
758volume needs to be reformatted, to enable filesystem detection and possible
759auto-mounting.
760
761udev 132
762========
763Fix segfault if compiled without optimization and dbg() does not get
764compiled out and uses variables which are not available.
765
766udev 131
767========
768Bugfixes. (And maybe new bugs. :))
769
770The rule matching engine got converted from a rule list to a token
771array which reduced the in-memory rules representation of a full
772featured distros with thousends of udev rules from 1.2MB to 0.12 MB.
773Limits like 5 ENV and ATTR matches, and one single instance for most
774other keys per rule are gone.
775
776The NAME assignment is no longer special cased. If later rules assign
777a NAME value again, the former value will be overwritten. As usual
778for most other keys, the NAME value can be protected by doing a final
779assignment with NAME:="<value>".
780
781All udev code now uses libudev, which is also exported. The library
782is still under development, marked as experimental, and its interface
783may change as long as the DeviceKit integration is not finished.
784
785Many thanks to Alan Jenkins for his continuous help, and finding and
786optimizing some of the computing expensive parts.
787
788udev 130
789========
790Bugfixes.
791
792Kernel 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
794kernel device directory can be found by looking up:
795 /sys/dev/{block,char}/<maj>:<min>
796and the device node of the same device by looking up:
797 /dev/{block,char}/<maj>:<min>
798
799udev 129
800========
801Fix recently introduced bug, which caused a compilation without large
802file support, where vol_id does not recognize raid signatures at the end
803of a volume.
804
805Firewire disks now create both, by-id/scsi-* and by-id/ieee-* links.
806Seems some kernel versions prevent the creation of the ieee-* links,
807so people used the scsi-* link which disappeared now.
808
809More libudev work. Almost all udevadm functionality comes from libudev
810now.
811
812udevadm trigger has a new option --type, which allows to trigger events
813for "devices", for "subsystems", or "failed" devices. The old option
814--retry-failed" still works, but is no longer mentioned in the man page.
815
816udev 128
817========
818Bugfixes.
819
820The udevadm info --device-id-of-file= output has changed to use
821the obvious format. Possible current users should use the --export
822option which is not affected.
823
824The old udev commands symlinks to udevadm are not installed, if
825these symlinks are used, a warning is printed.
826
827udev 127
828========
829Bugfixes.
830
831Optical drive's media is no longer probed for raid signatures,
832reading the end of the device causes some devices to malfunction.
833Also the offset of the last session found is used now to probe
834for the filesystem.
835
836The volume_id library got a major version number update to 1,
837some deprecated functions are removed.
838
839A shared library "libudev" gets installed now to provide access
840to udev device information. DeviceKit, the successor of HAL, will
841need this library to access the udev database and search sysfs for
842devices.
843The library is currently in an experimental state, also the API is
844expected to change, as long as the DeviceKit integration is not
845finished.
846
847udev 126
848========
849We use ./configure now. See INSTALL for details. Current
850options 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
868In the default rules, the group "disk" gets permissions 0660 instead
869of 0640. One small step closer to unify distro rules. Some day, all
870distros hopefully end up with the same set of rules.
871
872No symlinks to udevadm are installed anymore, if they are still needed,
873they should be provided by the package.
874
875udev 125
876========
877Bugfixes.
878
879Default udev rules, which are not supposed to be edited by the user, should
880be placed in /lib/udev/rules.d/ now, to make it clear that they are private to
881the udev package and will be replaced with an update. Udev will pick up rule
882files 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
886It does not matter in which directory a rule file lives, all files are sorted
887in lexical order.
888
889To 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
893In case the current --device-id-of-file is already used, please switch to
894the --export format version, it saves the output parsing and the old
895format will be changed to use ':' as a separator, like the format in the
896sysfs 'dev' file.
897
898udev 124
899========
900Fix cdrom_id to properly recognize blank media.
901
902udev 123
903========
904Bugfixes.
905
906Tape drive id-data is queried from /dev/bsg/* instead of the tape
907nodes. This avoids rewinding tapes on open().
908
909udev 122
910========
911Bugfixes.
912
913The symlinks udevcontrol and udevtrigger are no longer installed by
914the Makefile.
915
916The scsi_id program does not depend on sysfs anymore. It can speak
917SGv4 now, so /dev/bsg/* device nodes can be used, to query SCSI device
918data, which should solve some old problems with tape devices, where
919we better do not open all tape device nodes to identify the device.
920
921udev 121
922========
923Many bugfixes.
924
925The cdrom_id program is replaced by an advanced version, which can
926detect most common device types, and also properties of the inserted
927media. This is part of moving some basic functionality from HAL into
928udev (and the kernel).
929
930udev 120
931========
932Bugfixes.
933
934The last WAIT_FOR_SYSFS rule is removed from the default rules.
935
936The symlinks to udevadm for the debugging tools: udevmonitor and
937udevtest are no longer created.
938
939The symlinks to the udevadm man page for the old tool names are
940no longer created.
941
942Abstract namespace sockets paths in RUN+="socket:@<path>" rules,
943should be prefixed with '@' to indicate that the path is not a
944real file.
945
946udev 119
947========
948Bugfixes.
949
950udev 118
951========
952Bugfixes.
953
954Udevstart is removed from the tree, it did not get installed for
955a long time now, and is long replaced by trigger and settle.
956
957udev 117
958========
959Bugfixes.
960
961All udev tools are merged into a single binary called udevadm.
962The old names of the tools are built-in commands in udevadm now.
963Symlinks to udevadm, with the names of the old tools, provide
964the same functionality as the standalone tools. There is also
965only a single udevadm.8 man page left for all tools.
966
967Tools like mkinitramfs should be checked, if they need to include
968udevadm in the list of files.
969
970udev 116
971========
972Bugfixes.
973
974udev 115
975========
976Bugfixes.
977
978The etc/udev/rules.d/ directory now contains a default set of basic
979udev rules. This initial version is the result of a rules file merge
980of Fedora and openSUSE. For these both distros only a few specific
981rules are left in their own file, named after the distro. Rules which
982are optionally installed, because they are only valid for a specific
983architecture, or rules for subsystems which are not always used are
984in etc/udev/packages/.
985
986udev 114
987========
988Bugfixes.
989
990Dynamic rules can be created in /dev/.udev/rules.d/ to trigger
991actions by dynamically created rules.
992
993SYMLINK=="<value>" matches agains the entries in the list of
994currently defined symlinks. The links are not created in the
995filesystem at that point in time, but the values can be matched.
996
997RUN{ignore_error}+="<program>" will ignore any exit code from the
998program and not record as a failed event.
999
1000udev 113
1001========
1002Bugfixes.
1003
1004Final merge of patches/features from the Ubuntu package.
1005
1006udev 112
1007========
1008Bugfixes.
1009
1010Control characters in filesystem label strings are no longer silenty
1011removed, but hex-encoded, to be able to uniquely identify the device
1012by its symlink in /dev/disk/by-label/.
1013If libvolume_id is used by mount(8), LABEL= will work as expected,
1014if slashes or other characters are used in the label string.
1015
1016To test the existence of a file, TEST=="<file>" and TEST!="<file>"
1017can be specified now. The TEST key accepts an optional mode mask
1018TEST{0100}=="<is executable file>".
1019
1020Scsi_id now supports a mode without expecting scsi-specific sysfs
1021entries to allow the extraction of cciss-device persistent properties.
1022
1023udev 111
1024========
1025Bugfixes.
1026
1027In the future, we may see uuid's which are just simple character
1028strings (see the DDF Raid Specification). For that reason vol_id now
1029exports ID_FS_UUID_SAFE, just like ID_FS_LABEL_SAFE. For things like
1030the creation of symlinks, the *_SAFE values ensure, that no control
1031or whitespace characters are used in the filename.
1032
1033Possible users of libvolume_id, please use the volume_id_get_* functions.
1034The public struct will go away in a future release of the library.
1035
1036udev 110
1037========
1038Bugfixes.
1039
1040Removal of useless extras/eventrecorder.sh.
1041
1042udev 109
1043========
1044Bugfixes.
1045
1046udev 108
1047========
1048Bugfixes.
1049
1050The directory multiplexer for dev.d/ and hotplug.d are finally removed
1051from the udev package.
1052
1053udev 107
1054========
1055Bugfixes.
1056
1057Symlinks can have priorities now, the priority is assigned to the device
1058and specified with OPTIONS="link_priority=100". Devices with higher
1059priorities overwrite the symlinks of devices with lower priorities.
1060If the device that currently owns the link, goes away, the symlink
1061will be removed, and recreated, pointing to the next device with the
1062highest actual priority. This should make /dev/disk/by-{label,uuid,id}
1063more reliable, if multiple devices contain the same metadata and overwrite
1064these symlinks.
1065
1066The dasd_id program is removed from the udev tree, and dasdinfo, with the
1067needed rules, are part of the s390-tools now.
1068
1069Please add KERNEL=="[0-9]*:[0-9]*" to the scsi wait-for-sysfs rule,
1070we may get the scsi sysfs mess fixed some day, and this will only catch
1071the devices we are looking for.
1072
1073USB serial numbers for storage devices have the target:lun now appended,
1074to make it possibble to distinguish broken multi-lun devices with all
1075the same SCSI identifiers.
1076
1077Note: 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
1079with the next release. Make sure, that you don't use it anymore, or
1080provides your own implementation of that inefficient stuff.
1081We are tired of reports about a "slow udev", because these directories
1082contain stuff, that runs with _every_ event, instead of using rules,
1083that run programs only for the matching events.
1084
1085udev 106
1086========
1087Bugfixes.
1088
1089udev 105
1090========
1091Bugfixes.
1092
1093DRIVER== will match only for devices that actually have a real
1094driver. DRIVERS== must be used, if parent devices should be
1095included in the match.
1096
1097Libvolume_id's "linux_raid" detection needed another fix.
1098
1099udev 104
1100========
1101Bugfixes.
1102
1103udev 103
1104========
1105Add additional check to volume_id detection of via_raid, cause
1106some company decided to put a matching pattern all over the empty
1107storage area of their music players.
1108
1109udev 102
1110========
1111Fix path_id for SAS devices.
1112
1113udev 101
1114========
1115The udev daemon can be started with --debug-trace now, which will
1116execute all events serialized to get a chance to catch a possible
1117action that crashes the box.
1118
1119A warning is logged, if PHYSDEV* keys, the "device" link, or a parent
1120device attribute like $attr{../file} is used, only WAIT_FOR_SYSFS rules
1121are excluded from the warning. Referencing parent attributes directly
1122may break when something in the kernel driver model changes. Udev will
1123just find the attribute by walking up the parent chain.
1124
1125Udevtrigger now sorts the list of devices depending on the device
1126dependency, so a "usb" device is triggered after the parent "pci"
1127device.
1128
1129udev 100
1130========
1131Revert persistent-storage ata-serial '_' '-' replacement.
1132
1133udev 099
1134========
1135Bugfixes.
1136
1137Udevtrigger can now filter the list of devices to be triggered. Matches
1138for subsystems or sysfs attributes can be specified.
1139
1140The entries in /dev/.udev/queue and /dev/.udev/failed have changed to
1141zero-sized files to avoid pointing to /sys and confuse broken tools which
1142scan the /dev directory. To retry failed events, udevtrigger --retry-failed
1143should be used now.
1144
1145The rules and scripts to create udev rules for persistent network
1146devices and optical drives are in the extras/rules_generator directory
1147now. If you use something similar, please consider replacing your own
1148version with this, to share the support effort. The rule_generator
1149installs its own rules into /etc/udev/rules.d.
1150
1151The cdrom_id tool installs its own rule now in /etc/udev/rules.d, cause
1152the rule_generator depends on cdrom_id to be called in an earlier rule.
1153
1154udev 098
1155========
1156Bugfixes.
1157
1158Renaming of some key names (the old names still work):
1159BUS -> SUBSYSTEMS, ID -> KERNELS, SYSFS -> ATTRS, DRIVER -> DRIVERS.
1160(The behavior of the key DRIVER will change soon in one of the next
1161releases, to match only the event device, please switch to DRIVERS
1162instead. If DRIVER is used, it will behave like DRIVERS, but an error
1163is logged.
1164With the new key names, we have a more consistent and simpler scheme.
1165We can match the properties of the event device only, with: KERNEL,
1166SUBSYSTEM, ATTR, DRIVER. Or include all the parent devices in the match,
1167with: KERNELS, SUBSYSTEMS, ATTRS, DRIVERS. ID, BUS, SYSFS, DRIVER are no
1168longer mentioned in the man page and should be switched in the rule
1169files.
1170
1171ATTR{file}="value" can be used now, to write to a sysfs file of the
1172event device. Instead of:
1173 ..., SYSFS{type}=="0|7|14", RUN+="/bin/sh -c 'echo 60 > /sys$$DEVPATH/timeout'"
1174we now can do:
1175 ..., ATTR{type}=="0|7|14", ATTR{timeout}="60"
1176
1177All the PHYSDEV* keys are deprecated and will be removed from a
1178future 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.
1188Note that ENV{DRIVER} is only available for a few bus devices, where
1189the driver is already bound at device event time. On coldplug, the
1190events for a lot devices are already bound to a driver, and they will have
1191that value set. But on hotplug, at the time the kernel creates the device,
1192it can't know what driver may claim the device after that, therefore
1193in most cases it will be empty.
1194
1195Failed events should now be re-triggered with:
1196 udevtrigger --retry-failed.
1197Please switch to this command, so we keep the details of the /dev/.udev/failed/
1198files private to the udev tools. We may need to switch the current symlink
1199target, cause some obviously broken tools try to scan all files in /dev
1200including /dev/.udev/, find the links to /sys and end up stat()'ing sysfs files
1201million times. This takes ages on slow boxes.
1202
1203The udevinfo attribute walk (-a) now works with giving a device node
1204name (-n) instead of a devpath (-p). The query now always works, also when
1205no database file was created by udev.
1206
1207The built-in /etc/passwd /etc/group parser is removed, we always depend on
1208getpwnam() and getgrnam() now. One of the next releases will depend on
1209fnmatch() and may use getopt_long().
1210
1211udev 097
1212========
1213Bugfixes and small improvements.
1214
1215udev 096
1216========
1217Fix path_id for recent kernels.
1218
1219udev 095
1220========
1221%e is finally gone.
1222
1223Added support for swapping network interface names, by temporarily
1224renaming the device and wait for the target name to become free.
1225
1226udev 094
1227========
1228The built-in MODALIAS key and substitution is removed.
1229
1230udev 093
1231========
1232The binary firmware helper is replaced by the usual simple
1233shell script. Udevsend is removed from the tree.
1234
1235udev 092
1236========
1237Bugfix release.
1238
1239udev 091
1240========
1241Some more keys require the correct use of '==' and '=' depending
1242on the kind of operation beeing an assignment or a match. Rules
1243with invalid operations are skipped and logged to syslog. Please
1244test with udevtest if the parsing of your rules throws errors and
1245fix possibly broken rules.
1246
1247udev 090
1248========
1249Provide "udevsettle" to wait for all current udev events to finish.
1250It also watches the current kernel netlink queue by comparing the
1251even sequence number to make sure that there are no current pending
1252events that have not already arrived in the daemon.
1253
1254udev 089
1255========
1256Fix rule to skip persistent rules for removable IDE devices, which
1257also skipped optical IDE drives.
1258
1259All *_id program are installed in /lib/udev/ by default now.
1260
1261No binary is stripped anymore as this should be done in the
1262packaging process and not at build time.
1263
1264libvolume_id is provided as a shared library now and vol_id is
1265linked against it. Also one of the next HAL versions will require
1266this library, and the HAL build process will also require the
1267header file to be installed. The copy of the same code in HAL will
1268be removed to have only a single copy left on the system.
1269
1270udev 088
1271========
1272Add persistent links for SCSI tapes. The rules file is renamed
1273to 60-persistent-storage.rules.
1274
1275Create persistent path for usb devices. Can be used for all sorts
1276of devices that can't be distinguished by other properties like
1277multiple identical keyboards and mice connected to the same box.
1278
1279Provide "udevtrigger" program to request events on coldplug. The
1280shell script is much too slow with thousends of devices.
1281
1282udev 087
1283========
1284Fix persistent disk rules to exclude removable IDE drives.
1285
1286Warn if %e, $modalias or MODALIAS is used.
1287
1288udev 086
1289========
1290Fix queue export, which wasn't correct for subsequent add/remove
1291events for the same device.
1292
1293udev 085
1294========
1295Fix cramfs detection on big endian.
1296
1297Make WAIT_FOR_SYSFS usable in "normal" rules and silent if the whole
1298device goes away.
1299
1300udev 084
1301========
1302If BUS== and SYSFS{}== have been used in the same rule, the sysfs
1303attributes were only checked at the parent device that matched the
1304by BUS requested subsystem. Fix it to also look at the device we
1305received the event for.
1306
1307Build variable CROSS has changed to CROSS_COMPILE to match the kernel
1308build name.
1309
1310udev 083
1311========
1312Fix a bug where NAME="" would prevent RUN from beeing executed.
1313
1314RUN="/bin/program" does not longer automatically add the subsystem
1315as the first parameter. This is from the days of /sbin/hotplug
1316which is dead now and it's just confusing to need to add a space at
1317the end of the program name to prevent this.
1318If you use rules that need the subsystem as the first parameter,
1319like the old "udev_run_hotlugd" and "udev_run_devd", add the subsystem
1320to the key like RUN+="/bin/program $env{SUBSYSTEM}".
1321
1322udev 082
1323========
1324The udev man page has moved to udev(7) as it does not describe a command
1325anymore. The programs udev, udevstart and udevsend are no longer installed
1326by default and must be copied manually, if they should be installed or
1327included in a package.
1328
1329Fix a bug where "ignore_device" could run earlier collected RUN keys before
1330the ignore rule was applied.
1331
1332More preparation for future sysfs changes. usb_id and scsi_id no longer
1333depend on a magic order of devices in the /devices chain. Specific devices
1334should be requested by their subsytem.
1335
1336This will always find the scsi parent device without depending on a specific
1337path position:
1338 dev = sysfs_device_get(devpath);
1339 dev_usb = sysfs_device_get_parent_with_subsystem(dev, "scsi");
1340
1341The "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
1343parent in the devpath. If a device is requested by it's symlink, like all
1344class devices in the new sysfs layout will look like, it gets automatically
1345resolved and substituted with the real devpath and not the symlink path.
1346
1347Note:
1348A similar logic must be applied to _all_ sysfs users, including
1349scripts, that search along parent devices in sysfs. The explicit use of
1350the "device" link must be avoided. With the future sysfs layout all
1351DEVPATH's will start with /devices/ and have a "subsystem" symlink poiting
1352back 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
1354searching for parents by their subsystem should make sysfs users tolerant
1355for changed parent chains.
1356
1357udev 081
1358========
1359Prepare 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
1362Clarify BUS, ID, $id usage and fix $id behavior. This prepares for
1363moving the class devices to /sys/devices.
1364
1365Thanks again to Marco for help finding a hopefully nice compromise
1366to make %b simpler and working again.
1367
1368udev 080
1369========
1370Complete removal of libsysfs, replaced by simple helper functions
1371which are much simpler and a bit faster. The udev daemon operatesentirely
1372on event parameters and does not use sysfs for simple rules anymore.
1373Please report any new bugs/problems, that may be caused by this big
1374change. They will be fixed immediately.
1375
1376The enumeration format character '%e' is deprecated and will be
1377removed sometimes from a future udev version. It never worked correctly
1378outside of udevstart, so we can't use it with the new parallel
1379coldplug. A simple enumeration is as useless as the devfs naming
1380scheme, just get rid of both if you still use it.
1381
1382MODALIAS and $modalias is not needed and will be removed from one of
1383the next udev versions, replace it in all rules with ENV{MODALIAS} or
1384the sysfs "modalias" value.
1385
1386Thanks a lot to Marco for all his help on finding and fixing bugs.
1387
1388udev 079
1389========
1390Let scsi_id request libata drive serial numbers from page 0x80.
1391
1392Renamed etc/udev/persistent.rules to persistent-disk.rules and
1393added /dev/disk/by-name/* for device mapper device names.
1394
1395Removed %e from the man page. It never worked reliably outside
1396of udevstart and udevstart is no longer recommended to use.
1397
1398udev 078
1399========
1400Symlinks are now exported to the event environment. Hopefully it's no
1401longer needed to run udevinfo from an event process, like it was
1402mentioned 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
1408udev 077
1409========
1410Fix a problem if udevsend is used as the hotplug handler and tries to use
1411syslog, which causes a "vc" event loop. 2.6.15 will make udevsend obsolete
1412and this kind of problems will hopefully go away soon.
1413
1414udev 076
1415========
1416All built-in logic to work around bad sysfs timing is removed with this
1417version. The need to wait for sysfs files is almost fixed with a kernel
1418version that doesn't work with this udev version anyway. Until we fix
1419the timing of the "bus" link creation, the former integrated logic should
1420be emulated by a rule placed before all other rules:
1421 ACTION=="add", DEVPATH=="/devices/*", ENV{PHYSDEVBUS}=="?*", WAIT_FOR_SYSFS="bus"
1422
1423The 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
1425to anything else.
1426If the init script or something else used this value, just depend on
1427this hardcoded path. But remember _all_content_ of this directory is
1428still private to udev and can change at any time.
1429
1430Default location for rule sripts and helper programs is now: /lib/udev/.
1431Everything that is not useful on the commandline should go into this
1432directory. Some of the helpers in the extras folder are installed there
1433now. The rules need to be changed, to find the helpers there.
1434
1435Also /lib/udev/devices is recommended as a directory where packages or
1436the user can place real device nodes, which get copied over to /dev at
1437every boot. This should replace the various solutions with custom config
1438files.
1439
1440Udevsend does no longer start the udev daemon. This must be done with
1441the init script that prepares /dev on tmpfs and creates the initial nodes,
1442before starting the daemon.
1443
1444udev 075
1445========
1446Silent a too verbose error logging for the old hotplug.d/ dev.d/
1447emulation.
1448
1449The copy of klibc is removed. A systemwide installed version of klibc
1450should be used to build a klibc udev now.
1451
1452udev 074
1453========
1454NAME="" will not create any nodes, but execute RUN keys. To completely
1455ignore an event the OPTION "ignore_device" should be used.
1456
1457After removal of the reorder queue, events with a TIMEOUT can be executed
1458without any queuing now.
1459
1460udev 073
1461========
1462Fixed bug in udevd, if inotify is not available. We depend on netlink
1463uevents now, kernels without that event source will not work with that
1464version of udev anymore.
1465
1466udev 072
1467========
1468The rule parsing happens now in the daemon once at startup, all udev
1469event processes inherit the already parsed rules from the daemon.
1470It is shipped with SUSE10.0 and reduces heavily the system load at
1471startup. The option to save precompiled rules and let the udev process
1472pick the them up is removed, as it's no longer needed.
1473
1474Kernel 2.6.15 will have symlinks at /class/input pointing to the real
1475device. Libsysfs is changed to "translate" the requested link into the
1476real device path, as it would happen with the hotplug event. Otherwise
1477device removal and the udev database will not work.
1478
1479Using 'make STRIPCMD=' will leave the binaries unstripped for debugging
1480and packaging.
1481
1482A few improvements for vol_id, the filesytem probing code.
1483
1484udev 071
1485========
1486Fix a stupid typo in extras/run_directory for "make install".
1487
1488scsi_id creates the temporary devnode now in /dev for usage with a
1489non-writable /tmp directory.
1490
1491The uevent kernel socket buffer can carry app. 50.000 events now,
1492let's see who can break this again. :)
1493
1494The upcoming kernel will have a new input driver core integration.
1495Some class devices are now symlinks to the real device. libsysfs
1496needs a fix for this to work correctly. Udevstart of older udev
1497versions will _not_ create these devices!
1498
1499udev 070
1500========
1501Fix a 'install' target in the Makefile, that prevents EXTRAS from
1502beeing installed.
1503
1504udev 069
1505========
1506A bunch of mostly trivial bugfixes. From now on no node name or
1507symlink name can contain any character than plain whitelisted ascii
1508characters or validated utf8 byte-streams. This is needed for the
1509/dev/disk/by-label/* links, because we import untrusted data and
1510export it to the filesystem.
1511
1512udev 068
1513========
1514More bugfixes. If udevd was started from the kernel, we don't
1515have stdin/stdout/stderr, which broke the forked tools in some
1516situations.
1517
1518udev 067
1519========
1520Bugfix. udevstart event ordering was broken for a long time.
1521The new run_program() uncovered it, because /dev/null was not
1522available while we try to run external programs.
1523Now udevstart should create it before we run anything.
1524
1525udev 066
1526========
1527Minor bugfixes and some distro rules updates. If you don't have the
1528persistent disk rules in /dev/disk/by-*/* on your distro, just
1529grab it from here. :)
1530
1531udev 065
1532========
1533We can use socket communication now to pass events from udev to
1534other programs:
1535 RUN+="socket:/org/freedesktop/hal/udev_event"
1536will pass the whole udev event to the HAL daemon without the need
1537for a forked helper. (See ChangeLog for udevmonitor, as an example)
1538
1539udev 064
1540========
1541Mostly bugfixes and see ChangeLog.
1542
1543The test for the existence of an environment value should be
1544switched from:
1545 ENV{KEY}=="*" to ENV{KEY}=="?*"
1546because "*" will not fail anymore, if the key does not exist or
1547is empty.
1548
1549udev 063
1550========
1551Bugfixes and a few tweaks described in the ChangeLog.
1552
1553udev 062
1554========
1555Mostly a Bugfix release.
1556
1557Added WAIT_FOR_SYSFS="<attribute>" to be able to fight against the sysfs
1558timing with custom rules.
1559
1560udev 061
1561========
1562We changed the internal rule storage format. Our large rule files took
15632 MB of RAM, with the change we are down to 99kB.
1564
1565If the device-node has been created with default name and no symlink or
1566options are to remenber, it is not longer stored in the udevdb. HAL will
1567need to be updated to work correctly with that change.
1568
1569To overrride optimization flags, OPTFLAGS may be used now.
1570
1571udev 060
1572========
1573Bugfix release.
1574
1575udev 059
1576========
1577Major changes happened with this release. The goal is to take over the
1578complete kernel-event handling and provide a more efficient way to dispatch
1579kernel events. Replacing most of the current shell script logic and the
1580kernel forked helper with a netlink-daemon and a rule-based event handling.
1581
1582o 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
1590o /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
1603o 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
1608o 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
1612o 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
1618o 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
1624o 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
1657o 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
1664o 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
1669udev 058
1670========
1671With kernel version 2.6.12, the sysfs file "detached_state" was removed.
1672Fix for libsysfs not to expect this file was added.
1673
1674udev 057
1675========
1676All rules are applied now, but only the first matching rule with a NAME-key
1677will be applied. All later rules with NAME-key are completely ignored. This
1678way system supplied symlinks or permissions gets applied to user-defined
1679naming rules.
1680
1681Note:
1682Please check your rules setup, if you may need to add OPTIONS="last_rule"
1683to some rules, to keep the old behavior.
1684
1685The rules are read on "remove"-events too. That makes is possible to match
1686with keys that are available on remove (KERNEL, SUBSYSTEM, ID, ENV, ...) to
1687instruct udev to ignore an event (OPTIONS="ignore_device").
1688The new ACTION-key may be used to let a rule act only at a "remove"-event.
1689
1690The new RUN-key supports rule-based execution of programs after device-node
1691handling. This is meant as a general replacement for the dev.d/-directories
1692to give fine grained control over the execution of programs.
1693
1694The %s{}-sysfs format char replacement values are searched at any of the
1695devices in the device chain now, not only at the class-device.
1696
1697We support log priority levels now. The value udev_log in udev.conf is used
1698to determine what is printed to syslog. This makes it possible to
1699run a version with compiled-in debug messages in a production environment
1700which is sometimes needed to find a bug.
1701It is still possible to supress the inclusion of _any_ syslog usage with
1702USE_LOG=false to create the smallest possible binaries if needed.
1703The configured udev_log value can be overridden with the environment variable
1704UDEV_LOG.
1705
1706udev 056
1707========
1708Possible use of a system-wide klibc:
1709 make USE_KLIBC=true KLCC=/usr/bin/klcc all
1710will link against an external klibc and our own version will be ignored.
1711
1712udev 055
1713========
1714We support an unlimited count of symlinks now.
1715
1716If USE_STATIC=true is passed to a glibc build, we link statically and use
1717a built-in userdb parser to resolve user and group names.
1718
1719The PLACE= key is gone. It can be replaced by an ID= for a long time, because
1720we walk up the chain of physical devices to find a match.
1721
1722The KEY="<value>" format supports '=', '==', '!=,' , '+=' now. This makes it
1723easy to skip certain attribute matches without composing rules with weird
1724character class negations like:
1725 KERNEL="[!s][!c][!d]*"
1726this can now be replaced with:
1727 KERNEL!="scd*"
1728The current simple '=' is still supported, and should work as it does today,
1729but existing rules should be converted if possible, to be better readable.
1730
1731We have new ENV{}== key now, to match against a maximum of 5 environment
1732variables.
1733
1734udevstart is its own binary again, because we don't need co carry this araound
1735with 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 @@
1udev - Linux userspace device management
2
3Integrating udev in the system has complex dependencies and may differ from
4distribution to distribution. A system may not be able to boot up or work
5reliably without a properly installed udev version. The upstream udev project
6does not recommend replacing a distro's udev installation with the upstream
7version.
8
9The upstream udev project's set of default rules may require a most recent
10kernel release to work properly.
11
12Tools and rules shipped by udev are not public API and may change at any time.
13Never call any private tool in /usr/lib/udev from any external application; it
14might just go away in the next release. Access to udev information is only offered
15by udevadm and libudev. Tools and rules in /usr/lib/udev and the entire contents
16of the /run/udev directory are private to udev and do change whenever needed.
17
18Requirements:
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
69Setup:
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
80Operation:
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
97For more details about udev and udev rules, see the udev man pages:
98 http://www.kernel.org/pub/linux/utils/kernel/hotplug/udev/
99
100Please 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
3if [ -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."
7fi
8
9gtkdocize
10autoreconf --install --symlink
11
12libdir() {
13 echo $(cd $1/$(gcc -print-multi-os-directory); pwd)
14}
15
16args="$args \
17--prefix=/usr \
18--sysconfdir=/etc \
19--libdir=$(libdir /usr/lib) \
20--with-selinux \
21--enable-gtk-doc"
22
23if [ -L /bin ]; then
24args="$args \
25--libexecdir=/usr/lib \
26--with-systemdsystemunitdir=/usr/lib/systemd/system \
27"
28else
29args="$args \
30--with-rootprefix= \
31---with-rootlibdir=$(libdir /lib) \
32--bindir=/sbin \
33--libexecdir=/lib \
34--with-systemdsystemunitdir=/lib/systemd/system \
35"
36fi
37
38echo
39echo "----------------------------------------------------------------"
40echo "Initialized build system. For a common configuration please run:"
41echo "----------------------------------------------------------------"
42echo
43echo "./configure CFLAGS='-g -O1' $args"
44echo
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 @@
1AC_PREREQ(2.60)
2AC_INIT([udev],
3 [182],
4 [linux-hotplug@vger.kernel.org],
5 [udev],
6 [http://www.kernel.org/pub/linux/utils/kernel/hotplug/udev.html])
7AC_CONFIG_SRCDIR([src/udevd.c])
8AC_CONFIG_AUX_DIR([build-aux])
9AM_INIT_AUTOMAKE([check-news foreign 1.11 -Wall -Wno-portability silent-rules tar-pax no-dist-gzip dist-xz subdir-objects])
10AC_USE_SYSTEM_EXTENSIONS
11AC_SYS_LARGEFILE
12AC_CONFIG_MACRO_DIR([m4])
13AM_SILENT_RULES([yes])
14LT_INIT([disable-static])
15AC_PROG_AWK
16AC_PROG_SED
17AC_PROG_MKDIR_P
18GTK_DOC_CHECK(1.10)
19AC_PREFIX_DEFAULT([/usr])
20
21AC_PATH_PROG([XSLTPROC], [xsltproc])
22AM_CONDITIONAL(HAVE_XSLTPROC, test x"$XSLTPROC" != x)
23
24AC_SEARCH_LIBS([clock_gettime], [rt], [], [AC_MSG_ERROR([POSIX RT library not found])])
25
26PKG_CHECK_MODULES(BLKID, blkid >= 2.20)
27
28PKG_CHECK_MODULES(KMOD, libkmod >= 5)
29
30AC_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}])
33AC_SUBST([rootprefix], [$with_rootprefix])
34
35AC_ARG_WITH([rootlibdir],
36 AS_HELP_STRING([--with-rootlibdir=DIR], [rootfs directory to install shared libraries]),
37 [], [with_rootlibdir=$libdir])
38AC_SUBST([rootlib_execdir], [$with_rootlibdir])
39
40AC_ARG_WITH([selinux],
41 AS_HELP_STRING([--with-selinux], [enable SELinux support]),
42 [], [with_selinux=no])
43AS_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])
52AC_SUBST([SELINUX_LIBS])
53AM_CONDITIONAL(WITH_SELINUX, [test "x$with_selinux" = "xyes"])
54
55AC_ARG_ENABLE([debug],
56 AS_HELP_STRING([--enable-debug], [enable debug messages @<:@default=disabled@:>@]),
57 [], [enable_debug=no])
58AS_IF([test "x$enable_debug" = "xyes"], [ AC_DEFINE(ENABLE_DEBUG, [1], [Debug messages.]) ])
59
60AC_ARG_ENABLE([logging],
61 AS_HELP_STRING([--disable-logging], [disable system logging @<:@default=enabled@:>@]),
62 [], enable_logging=yes)
63AS_IF([test "x$enable_logging" = "xyes"], [ AC_DEFINE(ENABLE_LOGGING, [1], [System logging.]) ])
64
65AC_ARG_ENABLE([manpages],
66 AS_HELP_STRING([--disable-manpages], [disable man pages @<:@default=enabled@:>@]),
67 [], enable_manpages=yes)
68AM_CONDITIONAL([ENABLE_MANPAGES], [test "x$enable_manpages" = "xyes"])
69
70if 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])
74fi
75
76AC_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])
85AC_MSG_CHECKING([for USB database location])
86AC_MSG_RESULT([$USB_DATABASE])
87AC_SUBST(USB_DATABASE)
88
89AC_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])
97AC_MSG_CHECKING([for PCI database location])
98AC_MSG_RESULT([$PCI_DATABASE])
99AC_SUBST(PCI_DATABASE)
100
101AC_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"])
105OLD_IFS=$IFS
106IFS=:
107for 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
113done
114IFS=$OLD_IFS
115AC_SUBST([FIRMWARE_PATH], [$FIRMWARE_PATH])
116
117AC_ARG_WITH([systemdsystemunitdir],
118 AS_HELP_STRING([--with-systemdsystemunitdir=DIR], [Directory for systemd service files]),
119 [], [with_systemdsystemunitdir=$($PKG_CONFIG --variable=systemdsystemunitdir systemd)])
120AS_IF([test "x$with_systemdsystemunitdir" != "xno"], [ AC_SUBST([systemdsystemunitdir], [$with_systemdsystemunitdir]) ])
121AM_CONDITIONAL(WITH_SYSTEMD, [test -n "$with_systemdsystemunitdir" -a "x$with_systemdsystemunitdir" != "xno" ])
122
123# ------------------------------------------------------------------------------
124# GUdev - libudev gobject interface
125# ------------------------------------------------------------------------------
126AC_ARG_ENABLE([gudev],
127 AS_HELP_STRING([--disable-gudev], [disable Gobject libudev support @<:@default=enabled@:>@]),
128 [], [enable_gudev=yes])
129AS_IF([test "x$enable_gudev" = "xyes"], [ PKG_CHECK_MODULES([GLIB], [glib-2.0 >= 2.22.0 gobject-2.0 >= 2.22.0]) ])
130
131AC_ARG_ENABLE([introspection],
132 AS_HELP_STRING([--disable-introspection], [disable GObject introspection @<:@default=enabled@:>@]),
133 [], [enable_introspection=yes])
134AS_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])
143AM_CONDITIONAL([ENABLE_INTROSPECTION], [test "x$enable_introspection" = "xyes"])
144AM_CONDITIONAL([ENABLE_GUDEV], [test "x$enable_gudev" = "xyes"])
145
146# ------------------------------------------------------------------------------
147# keymap - map custom hardware's multimedia keys
148# ------------------------------------------------------------------------------
149AC_ARG_ENABLE([keymap],
150 AS_HELP_STRING([--disable-keymap], [disable keymap fixup support @<:@default=enabled@:>@]),
151 [], [enable_keymap=yes])
152AS_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])
161AM_CONDITIONAL([ENABLE_KEYMAP], [test "x$enable_keymap" = "xyes"])
162
163# ------------------------------------------------------------------------------
164# mtd_probe - autoloads FTL module for mtd devices
165# ------------------------------------------------------------------------------
166AC_ARG_ENABLE([mtd_probe],
167 AS_HELP_STRING([--disable-mtd_probe], [disable MTD support @<:@default=enabled@:>@]),
168 [], [enable_mtd_probe=yes])
169AM_CONDITIONAL([ENABLE_MTD_PROBE], [test "x$enable_mtd_probe" = "xyes"])
170
171# ------------------------------------------------------------------------------
172# rule_generator - persistent network and optical device rule generator
173# ------------------------------------------------------------------------------
174AC_ARG_ENABLE([rule_generator],
175 AS_HELP_STRING([--enable-rule_generator], [enable persistent network + cdrom links support @<:@default=disabled@:>@]),
176 [], [enable_rule_generator=no])
177AM_CONDITIONAL([ENABLE_RULE_GENERATOR], [test "x$enable_rule_generator" = "xyes"])
178
179# ------------------------------------------------------------------------------
180# create_floppy_devices - historical floppy kernel device nodes (/dev/fd0h1440, ...)
181# ------------------------------------------------------------------------------
182AC_ARG_ENABLE([floppy],
183 AS_HELP_STRING([--enable-floppy], [enable legacy floppy support @<:@default=disabled@:>@]),
184 [], [enable_floppy=no])
185AM_CONDITIONAL([ENABLE_FLOPPY], [test "x$enable_floppy" = "xyes"])
186
187my_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"
193AC_SUBST([my_CFLAGS])
194
195AC_CONFIG_HEADERS(config.h)
196AC_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
204AC_OUTPUT
205AC_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 @@
1libtool.m4
2lt*m4
3gtk-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
11ACTION=="add", SUBSYSTEM=="usb", ATTR{product}=="QEMU USB Mouse", ATTR{serial}=="42", TEST=="power/control", ATTR{power/control}="auto"
12ACTION=="add", SUBSYSTEM=="usb", ATTR{product}=="QEMU USB Tablet", ATTR{serial}=="42", TEST=="power/control", ATTR{power/control}="auto"
13ACTION=="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
22ACTION=="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#
28ACTION=="add", SUBSYSTEM=="usb", ATTRS{idVendor}=="0624", ATTR{bInterfaceClass}=="03", TEST=="../power/control", ATTR{../power/control}="auto"
29
30# Dell DRAC 4
31ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="413c", ATTR{idProduct}=="2500", TEST=="power/control", ATTR{power/control}="auto"
32
33# Dell DRAC 5
34ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="413c", ATTR{idProduct}=="0000", TEST=="power/control", ATTR{power/control}="auto"
35
36# Hewlett Packard iLO
37ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="03f0", ATTR{idProduct}=="7029", TEST=="power/control", ATTR{power/control}="auto"
38ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="03f0", ATTR{idProduct}=="1027", TEST=="power/control", ATTR{power/control}="auto"
39
40# IBM remote access
41ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="04b3", ATTR{idProduct}=="4001", TEST=="power/control", ATTR{power/control}="auto"
42ACTION=="add", SUBSYSTEM=="usb", ATTR{idVendor}=="04b3", ATTR{idProduct}=="4002", TEST=="power/control", ATTR{power/control}="auto"
43ACTION=="add", SUBSYSTEM=="usb", ATTRS{idVendor}=="04b3", ATTR{idProduct}=="4012", TEST=="power/control", ATTR{power/control}="auto"
44
45# Raritan Computer, Inc KVM.
46ACTION=="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
49ACTION=="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
3KERNEL=="pty[pqrstuvwxyzabcdef][0123456789abcdef]", GROUP="tty", MODE="0660"
4KERNEL=="tty[pqrstuvwxyzabcdef][0123456789abcdef]", GROUP="tty", MODE="0660"
5KERNEL=="ptmx", GROUP="tty", MODE="0666"
6KERNEL=="tty", GROUP="tty", MODE="0666"
7KERNEL=="tty[0-9]*", GROUP="tty", MODE="0620"
8KERNEL=="vcs|vcs[0-9]*|vcsa|vcsa[0-9]*", GROUP="tty"
9
10# serial
11KERNEL=="tty[A-Z]*[0-9]|pppox[0-9]*|ircomm[0-9]*|noz[0-9]*|rfcomm[0-9]*", GROUP="dialout"
12KERNEL=="mwave", GROUP="dialout"
13KERNEL=="hvc*|hvsi*", GROUP="dialout"
14
15# virtio serial / console ports
16KERNEL=="vport*", ATTR{name}=="?*", SYMLINK+="virtio-ports/$attr{name}"
17
18# mem
19KERNEL=="null|zero|full|random|urandom", MODE="0666"
20KERNEL=="mem|kmem|port|nvram", GROUP="kmem", MODE="0640"
21
22# input
23SUBSYSTEM=="input", ENV{ID_INPUT}=="", IMPORT{builtin}="input_id"
24KERNEL=="mouse*|mice|event*", MODE="0640"
25KERNEL=="ts[0-9]*|uinput", MODE="0640"
26KERNEL=="js[0-9]*", MODE="0644"
27
28# video4linux
29SUBSYSTEM=="video4linux", GROUP="video"
30KERNEL=="vttuner*", GROUP="video"
31KERNEL=="vtx*|vbi*", GROUP="video"
32KERNEL=="winradio*", GROUP="video"
33
34# graphics
35KERNEL=="agpgart", GROUP="video"
36KERNEL=="pmu", GROUP="video"
37KERNEL=="nvidia*|nvidiactl*", GROUP="video"
38SUBSYSTEM=="graphics", GROUP="video"
39SUBSYSTEM=="drm", GROUP="video"
40
41# sound
42SUBSYSTEM=="sound", GROUP="audio", \
43 OPTIONS+="static_node=snd/seq", OPTIONS+="static_node=snd/timer"
44
45# DVB (video)
46SUBSYSTEM=="dvb", GROUP="video"
47
48# FireWire (firewire-core driver: IIDC devices, AV/C devices)
49SUBSYSTEM=="firewire", ATTR{units}=="*0x00a02d:0x00010*", GROUP="video"
50SUBSYSTEM=="firewire", ATTR{units}=="*0x00b09d:0x00010*", GROUP="video"
51SUBSYSTEM=="firewire", ATTR{units}=="*0x00a02d:0x010001*", GROUP="video"
52SUBSYSTEM=="firewire", ATTR{units}=="*0x00a02d:0x014001*", GROUP="video"
53
54# 'libusb' device nodes
55SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", MODE="0664"
56SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", IMPORT{builtin}="usb_id"
57
58# printer
59KERNEL=="parport[0-9]*", GROUP="lp"
60SUBSYSTEM=="printer", KERNEL=="lp*", GROUP="lp"
61SUBSYSTEM=="ppdev", GROUP="lp"
62KERNEL=="lp[0-9]*", GROUP="lp"
63KERNEL=="irlpt[0-9]*", GROUP="lp"
64SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{ID_USB_INTERFACES}=="*:0701??:*", GROUP="lp"
65
66# block
67SUBSYSTEM=="block", GROUP="disk"
68
69# floppy
70SUBSYSTEM=="block", KERNEL=="fd[0-9]", GROUP="floppy"
71
72# cdrom
73SUBSYSTEM=="block", KERNEL=="sr[0-9]*", GROUP="cdrom"
74SUBSYSTEM=="scsi_generic", SUBSYSTEMS=="scsi", ATTRS{type}=="4|5", GROUP="cdrom"
75KERNEL=="pktcdvd[0-9]*", GROUP="cdrom"
76KERNEL=="pktcdvd", GROUP="cdrom"
77
78# tape
79KERNEL=="ht[0-9]*|nht[0-9]*", GROUP="tape"
80KERNEL=="pt[0-9]*|npt[0-9]*|pht[0-9]*", GROUP="tape"
81SUBSYSTEM=="scsi_generic|scsi_tape", SUBSYSTEMS=="scsi", ATTRS{type}=="1|8", GROUP="tape"
82
83# block-related
84KERNEL=="sch[0-9]*", GROUP="disk"
85SUBSYSTEM=="scsi_generic", SUBSYSTEMS=="scsi", ATTRS{type}=="0", GROUP="disk"
86KERNEL=="pg[0-9]*", GROUP="disk"
87KERNEL=="qft[0-9]*|nqft[0-9]*|zqft[0-9]*|nzqft[0-9]*|rawqft[0-9]*|nrawqft[0-9]*", GROUP="disk"
88KERNEL=="rawctl", GROUP="disk"
89SUBSYSTEM=="raw", KERNEL=="raw[0-9]*", GROUP="disk"
90SUBSYSTEM=="aoe", GROUP="disk", MODE="0220"
91SUBSYSTEM=="aoe", KERNEL=="err", MODE="0440"
92
93# network
94KERNEL=="tun", MODE="0666", OPTIONS+="static_node=net/tun"
95KERNEL=="rfkill", MODE="0644"
96
97# CPU
98KERNEL=="cpu[0-9]*", MODE="0444"
99
100KERNEL=="fuse", ACTION=="add", MODE="0666", OPTIONS+="static_node=fuse"
101
102SUBSYSTEM=="rtc", ATTR{hctosys}=="1", SYMLINK+="rtc"
103KERNEL=="mmtimer", MODE="0644"
104KERNEL=="rflash[0-9]*", MODE="0400"
105KERNEL=="rrom[0-9]*", MODE="0400"
106
107SUBSYSTEM=="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
3ACTION=="remove", GOTO="persistent_alsa_end"
4SUBSYSTEM!="sound", GOTO="persistent_alsa_end"
5KERNEL!="controlC[0-9]*", GOTO="persistent_alsa_end"
6
7SUBSYSTEMS=="usb", ENV{ID_MODEL}=="", IMPORT{builtin}="usb_id"
8ENV{ID_SERIAL}=="?*", ENV{ID_USB_INTERFACE_NUM}=="?*", SYMLINK+="snd/by-id/$env{ID_BUS}-$env{ID_SERIAL}-$env{ID_USB_INTERFACE_NUM}"
9ENV{ID_SERIAL}=="?*", ENV{ID_USB_INTERFACE_NUM}=="", SYMLINK+="snd/by-id/$env{ID_BUS}-$env{ID_SERIAL}"
10
11IMPORT{builtin}="path_id"
12ENV{ID_PATH}=="?*", SYMLINK+="snd/by-path/$env{ID_PATH}"
13
14LABEL="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
3ACTION=="remove", GOTO="persistent_input_end"
4SUBSYSTEM!="input", GOTO="persistent_input_end"
5SUBSYSTEMS=="bluetooth", GOTO="persistent_input_end"
6
7SUBSYSTEMS=="usb", ENV{ID_BUS}=="", IMPORT{builtin}="usb_id"
8
9# determine class name for persistent symlinks
10ENV{ID_INPUT_KEYBOARD}=="?*", ENV{.INPUT_CLASS}="kbd"
11ENV{ID_INPUT_MOUSE}=="?*", ENV{.INPUT_CLASS}="mouse"
12ENV{ID_INPUT_TOUCHPAD}=="?*", ENV{.INPUT_CLASS}="mouse"
13ENV{ID_INPUT_TABLET}=="?*", ENV{.INPUT_CLASS}="mouse"
14ENV{ID_INPUT_JOYSTICK}=="?*", ENV{.INPUT_CLASS}="joystick"
15DRIVERS=="pcspkr", ENV{.INPUT_CLASS}="spkr"
16ATTRS{name}=="*dvb*|*DVB*|* IR *", ENV{.INPUT_CLASS}="ir"
17
18# fill empty serial number
19ENV{.INPUT_CLASS}=="?*", ENV{ID_SERIAL}=="", ENV{ID_SERIAL}="noserial"
20
21# by-id links
22KERNEL=="mouse*|js*", ENV{ID_BUS}=="?*", ENV{.INPUT_CLASS}=="?*", SYMLINK+="input/by-id/$env{ID_BUS}-$env{ID_SERIAL}-$env{.INPUT_CLASS}"
23KERNEL=="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}"
24KERNEL=="event*", ENV{ID_BUS}=="?*", ENV{.INPUT_CLASS}=="?*", SYMLINK+="input/by-id/$env{ID_BUS}-$env{ID_SERIAL}-event-$env{.INPUT_CLASS}"
25KERNEL=="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
27SUBSYSTEMS=="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
31SUBSYSTEMS=="pci|usb|platform|acpi", IMPORT{builtin}="path_id"
32ENV{ID_PATH}=="?*", KERNEL=="mouse*|js*", ENV{.INPUT_CLASS}=="?*", SYMLINK+="input/by-path/$env{ID_PATH}-$env{.INPUT_CLASS}"
33ENV{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
35SUBSYSTEMS=="usb|platform", ENV{ID_PATH}=="?*", KERNEL=="event*", ENV{.INPUT_CLASS}=="", \
36 SYMLINK+="input/by-path/$env{ID_PATH}-event"
37
38LABEL="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
3ACTION=="remove", GOTO="persistent_serial_end"
4SUBSYSTEM!="tty", GOTO="persistent_serial_end"
5KERNEL!="ttyUSB[0-9]*|ttyACM[0-9]*", GOTO="persistent_serial_end"
6
7SUBSYSTEMS=="usb-serial", ENV{.ID_PORT}="$attr{port_number}"
8
9IMPORT{builtin}="path_id"
10ENV{ID_PATH}=="?*", ENV{.ID_PORT}=="", SYMLINK+="serial/by-path/$env{ID_PATH}"
11ENV{ID_PATH}=="?*", ENV{.ID_PORT}=="?*", SYMLINK+="serial/by-path/$env{ID_PATH}-port$env{.ID_PORT}"
12
13IMPORT{builtin}="usb_id"
14ENV{ID_SERIAL}=="", GOTO="persistent_serial_end"
15SUBSYSTEMS=="usb", ENV{ID_USB_INTERFACE_NUM}="$attr{bInterfaceNumber}"
16ENV{ID_USB_INTERFACE_NUM}=="", GOTO="persistent_serial_end"
17ENV{.ID_PORT}=="", SYMLINK+="serial/by-id/$env{ID_BUS}-$env{ID_SERIAL}-if$env{ID_USB_INTERFACE_NUM}"
18ENV{.ID_PORT}=="?*", SYMLINK+="serial/by-id/$env{ID_BUS}-$env{ID_SERIAL}-if$env{ID_USB_INTERFACE_NUM}-port$env{.ID_PORT}"
19
20LABEL="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
5ACTION=="remove", GOTO="persistent_storage_tape_end"
6
7# type 8 devices are "Medium Changers"
8SUBSYSTEM=="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
11SUBSYSTEM!="scsi_tape", GOTO="persistent_storage_tape_end"
12
13KERNEL=="st*[0-9]|nst*[0-9]", ATTRS{ieee1394_id}=="?*", ENV{ID_SERIAL}="$attr{ieee1394_id}", ENV{ID_BUS}="ieee1394"
14KERNEL=="st*[0-9]|nst*[0-9]", ENV{ID_SERIAL}!="?*", SUBSYSTEMS=="usb", IMPORT{builtin}="usb_id"
15KERNEL=="st*[0-9]|nst*[0-9]", ENV{ID_SERIAL}!="?*", SUBSYSTEMS=="scsi", KERNELS=="[0-9]*:*[0-9]", ENV{.BSG_DEV}="$root/bsg/$id"
16KERNEL=="st*[0-9]|nst*[0-9]", ENV{ID_SERIAL}!="?*", IMPORT{program}="scsi_id --whitelisted --export --device=$env{.BSG_DEV}", ENV{ID_BUS}="scsi"
17KERNEL=="st*[0-9]", ENV{ID_SERIAL}=="?*", SYMLINK+="tape/by-id/$env{ID_BUS}-$env{ID_SERIAL}"
18KERNEL=="nst*[0-9]", ENV{ID_SERIAL}=="?*", SYMLINK+="tape/by-id/$env{ID_BUS}-$env{ID_SERIAL}-nst"
19
20# by-path (parent device path)
21KERNEL=="st*[0-9]|nst*[0-9]", IMPORT{builtin}="path_id"
22KERNEL=="st*[0-9]", ENV{ID_PATH}=="?*", SYMLINK+="tape/by-path/$env{ID_PATH}"
23KERNEL=="nst*[0-9]", ENV{ID_PATH}=="?*", SYMLINK+="tape/by-path/$env{ID_PATH}-nst"
24
25LABEL="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
7ACTION=="change", SUBSYSTEM=="scsi", ENV{DEVTYPE}=="scsi_device", TEST=="block", ATTR{block/*/uevent}="change"
8
9ACTION=="remove", GOTO="persistent_storage_end"
10
11# enable in-kernel media-presence polling
12ACTION=="add", SUBSYSTEM=="module", KERNEL=="block", ATTR{parameters/events_dfl_poll_msecs}=="0", ATTR{parameters/events_dfl_poll_msecs}="2000"
13
14SUBSYSTEM!="block", GOTO="persistent_storage_end"
15
16# skip rules for inappropriate block devices
17KERNEL=="fd*|mtd*|nbd*|gnbd*|btibm*|dm-*|md*", GOTO="persistent_storage_end"
18
19# ignore partitions that span the entire disk
20TEST=="whole_disk", GOTO="persistent_storage_end"
21
22# for partitions import parent information
23ENV{DEVTYPE}=="partition", IMPORT{parent}="ID_*"
24
25# virtio-blk
26KERNEL=="vd*[!0-9]", ATTRS{serial}=="?*", ENV{ID_SERIAL}="$attr{serial}", SYMLINK+="disk/by-id/virtio-$env{ID_SERIAL}"
27KERNEL=="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
30KERNEL=="sd*[!0-9]|sr*", ENV{ID_SERIAL}!="?*", SUBSYSTEMS=="ata", IMPORT{program}="ata_id --export $devnode"
31# ATA devices using the "scsi" subsystem
32KERNEL=="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
34KERNEL=="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)
37KERNEL=="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
39KERNEL=="sd*[!0-9]|sr*", ENV{ID_SERIAL}!="?*", SUBSYSTEMS=="usb", IMPORT{builtin}="usb_id"
40
41# scsi devices
42KERNEL=="sd*[!0-9]|sr*", ENV{ID_SERIAL}!="?*", IMPORT{program}="scsi_id --export --whitelisted -d $devnode", ENV{ID_BUS}="scsi"
43KERNEL=="cciss*", ENV{DEVTYPE}=="disk", ENV{ID_SERIAL}!="?*", IMPORT{program}="scsi_id --export --whitelisted -d $devnode", ENV{ID_BUS}="cciss"
44KERNEL=="sd*|sr*|cciss*", ENV{DEVTYPE}=="disk", ENV{ID_SERIAL}=="?*", SYMLINK+="disk/by-id/$env{ID_BUS}-$env{ID_SERIAL}"
45KERNEL=="sd*|cciss*", ENV{DEVTYPE}=="partition", ENV{ID_SERIAL}=="?*", SYMLINK+="disk/by-id/$env{ID_BUS}-$env{ID_SERIAL}-part%n"
46
47# firewire
48KERNEL=="sd*[!0-9]|sr*", ATTRS{ieee1394_id}=="?*", SYMLINK+="disk/by-id/ieee1394-$attr{ieee1394_id}"
49KERNEL=="sd*[0-9]", ATTRS{ieee1394_id}=="?*", SYMLINK+="disk/by-id/ieee1394-$attr{ieee1394_id}-part%n"
50
51KERNEL=="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}"
52KERNEL=="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"
53KERNEL=="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}"
54KERNEL=="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)
57ENV{DEVTYPE}=="disk", DEVPATH!="*/virtual/*", IMPORT{builtin}="path_id"
58ENV{DEVTYPE}=="disk", ENV{ID_PATH}=="?*", SYMLINK+="disk/by-path/$env{ID_PATH}"
59ENV{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
62ENV{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
65KERNEL=="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
68KERNEL=="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
72KERNEL!="sr*", IMPORT{builtin}="blkid"
73
74# watch metadata changes by tools closing the device after writing
75KERNEL!="sr*", OPTIONS+="watch"
76
77# by-label/by-uuid links (filesystem metadata)
78ENV{ID_FS_USAGE}=="filesystem|other|crypto", ENV{ID_FS_UUID_ENC}=="?*", SYMLINK+="disk/by-uuid/$env{ID_FS_UUID_ENC}"
79ENV{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)
82ENV{DEVTYPE}=="disk", ENV{ID_WWN_WITH_EXTENSION}=="?*", SYMLINK+="disk/by-id/wwn-$env{ID_WWN_WITH_EXTENSION}"
83ENV{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)
86ENV{ID_PART_ENTRY_SCHEME}=="gpt", ENV{ID_PART_ENTRY_UUID}=="?*", SYMLINK+="disk/by-partuuid/$env{ID_PART_ENTRY_UUID}"
87ENV{ID_PART_ENTRY_SCHEME}=="gpt", ENV{ID_PART_ENTRY_NAME}=="?*", SYMLINK+="disk/by-partlabel/$env{ID_PART_ENTRY_NAME}"
88
89LABEL="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
3ACTION=="remove", GOTO="net_end"
4SUBSYSTEM!="net", GOTO="net_end"
5
6SUBSYSTEMS=="usb", ENV{ID_MODEL}=="", IMPORT{builtin}="usb_id"
7SUBSYSTEMS=="usb", IMPORT{builtin}="usb-db"
8SUBSYSTEMS=="usb", ATTRS{idVendor}!="", ATTRS{idProduct}!="", ENV{ID_VENDOR_ID}="$attr{idVendor}", ENV{ID_MODEL_ID}="$attr{idProduct}"
9SUBSYSTEMS=="usb", GOTO="net_end"
10
11SUBSYSTEMS=="pci", IMPORT{builtin}="pci-db"
12SUBSYSTEMS=="pci", ENV{ID_BUS}="pci", ENV{ID_VENDOR_ID}="$attr{vendor}", ENV{ID_MODEL_ID}="$attr{device}"
13
14LABEL="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
3ACTION=="remove", GOTO="tty_end"
4SUBSYSTEM!="tty", GOTO="tty_end"
5
6SUBSYSTEMS=="usb", ENV{ID_MODEL}=="", IMPORT{builtin}="usb_id"
7SUBSYSTEMS=="usb", IMPORT{builtin}="usb-db"
8SUBSYSTEMS=="usb", ATTRS{idVendor}!="", ATTRS{idProduct}!="", ENV{ID_VENDOR_ID}="$attr{idVendor}", ENV{ID_MODEL_ID}="$attr{idProduct}"
9SUBSYSTEMS=="usb", GOTO="tty_end"
10
11SUBSYSTEMS=="pci", IMPORT{builtin}="pci-db"
12SUBSYSTEMS=="pci", ENV{ID_BUS}="pci", ENV{ID_VENDOR_ID}="$attr{vendor}", ENV{ID_MODEL_ID}="$attr{device}"
13
14LABEL="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
3SUBSYSTEM!="sound", GOTO="sound_end"
4
5ACTION=="add|change", KERNEL=="controlC*", ATTR{../uevent}="change"
6ACTION!="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
36KERNEL!="card*", GOTO="sound_end"
37
38ENV{SOUND_INITIALIZED}="1"
39
40SUBSYSTEMS=="usb", IMPORT{builtin}="usb_id"
41SUBSYSTEMS=="usb", IMPORT{builtin}="usb-db"
42SUBSYSTEMS=="usb", GOTO="skip_pci"
43
44SUBSYSTEMS=="firewire", ATTRS{vendor_name}=="?*", ATTRS{model_name}=="?*", \
45 ENV{ID_BUS}="firewire", ENV{ID_VENDOR}="$attr{vendor_name}", ENV{ID_MODEL}="$attr{model_name}"
46SUBSYSTEMS=="firewire", ATTRS{guid}=="?*", ENV{ID_ID}="firewire-$attr{guid}"
47SUBSYSTEMS=="firewire", GOTO="skip_pci"
48
49
50SUBSYSTEMS=="pci", IMPORT{builtin}="pci-db"
51SUBSYSTEMS=="pci", ENV{ID_BUS}="pci", ENV{ID_VENDOR_ID}="$attr{vendor}", ENV{ID_MODEL_ID}="$attr{device}"
52
53LABEL="skip_pci"
54
55ENV{ID_SERIAL}=="?*", ENV{ID_USB_INTERFACE_NUM}=="?*", ENV{ID_ID}="$env{ID_BUS}-$env{ID_SERIAL}-$env{ID_USB_INTERFACE_NUM}-$attr{id}"
56ENV{ID_SERIAL}=="?*", ENV{ID_USB_INTERFACE_NUM}=="", ENV{ID_ID}="$env{ID_BUS}-$env{ID_SERIAL}-$attr{id}"
57
58IMPORT{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
65ATTR{pcmC%nD0p/pcm_class}=="modem", ENV{SOUND_CLASS}="modem", GOTO="sound_end"
66
67# Identify cards on the internal PCI bus as internal
68SUBSYSTEMS=="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
71SUBSYSTEMS=="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
74ENV{ID_MODEL}=="*[Ss]peaker*", ENV{SOUND_FORM_FACTOR}="speaker", GOTO="sound_end"
75ENV{ID_MODEL_FROM_DATABASE}=="*[Ss]peaker*", ENV{SOUND_FORM_FACTOR}="speaker", GOTO="sound_end"
76
77ENV{ID_MODEL}=="*[Hh]eadphone*", ENV{SOUND_FORM_FACTOR}="headphone", GOTO="sound_end"
78ENV{ID_MODEL_FROM_DATABASE}=="*[Hh]eadphone*", ENV{SOUND_FORM_FACTOR}="headphone", GOTO="sound_end"
79
80ENV{ID_MODEL}=="*[Hh]eadset*", ENV{SOUND_FORM_FACTOR}="headset", GOTO="sound_end"
81ENV{ID_MODEL_FROM_DATABASE}=="*[Hh]eadset*", ENV{SOUND_FORM_FACTOR}="headset", GOTO="sound_end"
82
83ENV{ID_MODEL}=="*[Hh]andset*", ENV{SOUND_FORM_FACTOR}="handset", GOTO="sound_end"
84ENV{ID_MODEL_FROM_DATABASE}=="*[Hh]andset*", ENV{SOUND_FORM_FACTOR}="handset", GOTO="sound_end"
85
86ENV{ID_MODEL}=="*[Mm]icrophone*", ENV{SOUND_FORM_FACTOR}="microphone", GOTO="sound_end"
87ENV{ID_MODEL_FROM_DATABASE}=="*[Mm]icrophone*", ENV{SOUND_FORM_FACTOR}="microphone", GOTO="sound_end"
88
89LABEL="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
3ACTION=="remove", GOTO="drivers_end"
4
5DRIVER!="?*", ENV{MODALIAS}=="?*", IMPORT{builtin}="kmod load $env{MODALIAS}"
6SUBSYSTEM=="tifm", ENV{TIFM_CARD_TYPE}=="SD", IMPORT{builtin}="kmod load tifm_sd"
7SUBSYSTEM=="tifm", ENV{TIFM_CARD_TYPE}=="MS", IMPORT{builtin}="kmod load tifm_ms"
8SUBSYSTEM=="memstick", IMPORT{builtin}="kmod load ms_block mspro_block"
9SUBSYSTEM=="i2o", IMPORT{builtin}="kmod load i2o_block"
10SUBSYSTEM=="module", KERNEL=="parport_pc", IMPORT{builtin}="kmod load ppdev"
11
12LABEL="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
4ACTION=="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
3udev.pc
4libudev.pc
5udev*.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
16freedom to share and change it. By contrast, the GNU General Public
17Licenses are intended to guarantee your freedom to share and change
18free software--to make sure the software is free for all its users.
19
20 This license, the Lesser General Public License, applies to some
21specially designated software packages--typically libraries--of the
22Free Software Foundation and other authors who decide to use it. You
23can use it too, but we suggest you first think carefully about whether
24this license or the ordinary General Public License is the better
25strategy 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,
28not price. Our General Public Licenses are designed to make sure that
29you have the freedom to distribute copies of free software (and charge
30for this service if you wish); that you receive source code or can get
31it if you want it; that you can change the software and use pieces of
32it in new free programs; and that you are informed that you can do
33these things.
34
35 To protect your rights, we need to make restrictions that forbid
36distributors to deny you these rights or to ask you to surrender these
37rights. These restrictions translate to certain responsibilities for
38you 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
41or for a fee, you must give the recipients all the rights that we gave
42you. You must make sure that they, too, receive or can get the source
43code. If you link other code with the library, you must provide
44complete object files to the recipients, so that they can relink them
45with the library after making changes to the library and recompiling
46it. 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
49library, and (2) we offer you this license, which gives you legal
50permission to copy, distribute and/or modify the library.
51
52 To protect each distributor, we want to make it very clear that
53there is no warranty for the free library. Also, if the library is
54modified by someone else and passed on, the recipients should know
55that what they have is not the original version, so that the original
56author's reputation will not be affected by problems that might be
57introduced by others.
58
59 Finally, software patents pose a constant threat to the existence of
60any free program. We wish to make sure that a company cannot
61effectively restrict the users of a free program by obtaining a
62restrictive license from a patent holder. Therefore, we insist that
63any patent license obtained for a version of the library must be
64consistent with the full freedom of use specified in this license.
65
66 Most GNU software, including some libraries, is covered by the
67ordinary GNU General Public License. This license, the GNU Lesser
68General Public License, applies to certain designated libraries, and
69is quite different from the ordinary General Public License. We use
70this license for certain libraries in order to permit linking those
71libraries into non-free programs.
72
73 When a program is linked with a library, whether statically or using
74a shared library, the combination of the two is legally speaking a
75combined work, a derivative of the original library. The ordinary
76General Public License therefore permits such linking only if the
77entire combination fits its criteria of freedom. The Lesser General
78Public License permits more lax criteria for linking other code with
79the library.
80
81 We call this license the "Lesser" General Public License because it
82does Less to protect the user's freedom than the ordinary General
83Public License. It also provides other free software developers Less
84of an advantage over competing non-free programs. These disadvantages
85are the reason we use the ordinary General Public License for many
86libraries. However, the Lesser license provides advantages in certain
87special circumstances.
88
89 For example, on rare occasions, there may be a special need to
90encourage the widest possible use of a certain library, so that it becomes
91a de-facto standard. To achieve this, non-free programs must be
92allowed to use the library. A more frequent case is that a free
93library does the same job as widely used non-free libraries. In this
94case, there is little to gain by limiting the free library to free
95software only, so we use the Lesser General Public License.
96
97 In other cases, permission to use a particular library in non-free
98programs enables a greater number of people to use a large body of
99free software. For example, permission to use the GNU C Library in
100non-free programs enables many more people to use the whole GNU
101operating system, as well as its variant, the GNU/Linux operating
102system.
103
104 Although the Lesser General Public License is Less protective of the
105users' freedom, it does ensure that the user of a program that is
106linked with the Library has the freedom and the wherewithal to run
107that program using a modified version of the Library.
108
109 The precise terms and conditions for copying, distribution and
110modification follow. Pay close attention to the difference between a
111"work based on the library" and a "work that uses the library". The
112former contains code derived from the library, whereas the latter must
113be 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
119program which contains a notice placed by the copyright holder or
120other authorized party saying it may be distributed under the terms of
121this Lesser General Public License (also called "this License").
122Each licensee is addressed as "you".
123
124 A "library" means a collection of software functions and/or data
125prepared 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
129which has been distributed under these terms. A "work based on the
130Library" means either the Library or any derivative work under
131copyright law: that is to say, a work containing the Library or a
132portion of it, either verbatim or with modifications and/or translated
133straightforwardly into another language. (Hereinafter, translation is
134included without limitation in the term "modification".)
135
136 "Source code" for a work means the preferred form of the work for
137making modifications to it. For a library, complete source code means
138all the source code for all modules it contains, plus any associated
139interface definition files, plus the scripts used to control compilation
140and installation of the library.
141
142 Activities other than copying, distribution and modification are not
143covered by this License; they are outside its scope. The act of
144running a program using the Library is not restricted, and output from
145such a program is covered only if its contents constitute a work based
146on the Library (independent of the use of the Library in a tool for
147writing it). Whether that is true depends on what the Library does
148and what the program that uses the Library does.
149
150 1. You may copy and distribute verbatim copies of the Library's
151complete source code as you receive it, in any medium, provided that
152you conspicuously and appropriately publish on each copy an
153appropriate copyright notice and disclaimer of warranty; keep intact
154all the notices that refer to this License and to the absence of any
155warranty; and distribute a copy of this License along with the
156Library.
157
158 You may charge a fee for the physical act of transferring a copy,
159and you may at your option offer warranty protection in exchange for a
160fee.
161
162 2. You may modify your copy or copies of the Library or any portion
163of it, thus forming a work based on the Library, and copy and
164distribute such modifications or work under the terms of Section 1
165above, 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
190These requirements apply to the modified work as a whole. If
191identifiable sections of that work are not derived from the Library,
192and can be reasonably considered independent and separate works in
193themselves, then this License, and its terms, do not apply to those
194sections when you distribute them as separate works. But when you
195distribute the same sections as part of a whole which is a work based
196on the Library, the distribution of the whole must be on the terms of
197this License, whose permissions for other licensees extend to the
198entire whole, and thus to each and every part regardless of who wrote
199it.
200
201Thus, it is not the intent of this section to claim rights or contest
202your rights to work written entirely by you; rather, the intent is to
203exercise the right to control the distribution of derivative or
204collective works based on the Library.
205
206In addition, mere aggregation of another work not based on the Library
207with the Library (or with a work based on the Library) on a volume of
208a storage or distribution medium does not bring the other work under
209the scope of this License.
210
211 3. You may opt to apply the terms of the ordinary GNU General Public
212License instead of this License to a given copy of the Library. To do
213this, you must alter all the notices that refer to this License, so
214that they refer to the ordinary GNU General Public License, version 2,
215instead of to this License. (If a newer version than version 2 of the
216ordinary GNU General Public License has appeared, then you can specify
217that version instead if you wish.) Do not make any other change in
218these notices.
219
220 Once this change is made in a given copy, it is irreversible for
221that copy, so the ordinary GNU General Public License applies to all
222subsequent copies and derivative works made from that copy.
223
224 This option is useful when you wish to copy part of the code of
225the Library into a program that is not a library.
226
227 4. You may copy and distribute the Library (or a portion or
228derivative of it, under Section 2) in object code or executable form
229under the terms of Sections 1 and 2 above provided that you accompany
230it with the complete corresponding machine-readable source code, which
231must be distributed under the terms of Sections 1 and 2 above on a
232medium customarily used for software interchange.
233
234 If distribution of object code is made by offering access to copy
235from a designated place, then offering equivalent access to copy the
236source code from the same place satisfies the requirement to
237distribute the source code, even though third parties are not
238compelled to copy the source along with the object code.
239
240 5. A program that contains no derivative of any portion of the
241Library, but is designed to work with the Library by being compiled or
242linked with it, is called a "work that uses the Library". Such a
243work, in isolation, is not a derivative work of the Library, and
244therefore falls outside the scope of this License.
245
246 However, linking a "work that uses the Library" with the Library
247creates an executable that is a derivative of the Library (because it
248contains portions of the Library), rather than a "work that uses the
249library". The executable is therefore covered by this License.
250Section 6 states terms for distribution of such executables.
251
252 When a "work that uses the Library" uses material from a header file
253that is part of the Library, the object code for the work may be a
254derivative work of the Library even though the source code is not.
255Whether this is true is especially significant if the work can be
256linked without the Library, or if the work is itself a library. The
257threshold for this to be true is not precisely defined by law.
258
259 If such an object file uses only numerical parameters, data
260structure layouts and accessors, and small macros and small inline
261functions (ten lines or less in length), then the use of the object
262file is unrestricted, regardless of whether it is legally a derivative
263work. (Executables containing this object code plus portions of the
264Library will still fall under Section 6.)
265
266 Otherwise, if the work is a derivative of the Library, you may
267distribute the object code for the work under the terms of Section 6.
268Any executables containing that work also fall under Section 6,
269whether 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
272link a "work that uses the Library" with the Library to produce a
273work containing portions of the Library, and distribute that work
274under terms of your choice, provided that the terms permit
275modification of the work for the customer's own use and reverse
276engineering for debugging such modifications.
277
278 You must give prominent notice with each copy of the work that the
279Library is used in it and that the Library and its use are covered by
280this License. You must supply a copy of this License. If the work
281during execution displays copyright notices, you must include the
282copyright notice for the Library among them, as well as a reference
283directing the user to the copy of this License. Also, you must do one
284of 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
319Library" must include any data and utility programs needed for
320reproducing the executable from it. However, as a special exception,
321the materials to be distributed need not include anything that is
322normally distributed (in either source or binary form) with the major
323components (compiler, kernel, and so on) of the operating system on
324which the executable runs, unless that component itself accompanies
325the executable.
326
327 It may happen that this requirement contradicts the license
328restrictions of other proprietary libraries that do not normally
329accompany the operating system. Such a contradiction means you cannot
330use both them and the Library together in an executable that you
331distribute.
332
333 7. You may place library facilities that are a work based on the
334Library side-by-side in a single library together with other library
335facilities not covered by this License, and distribute such a combined
336library, provided that the separate distribution of the work based on
337the Library and of the other library facilities is otherwise
338permitted, 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
350the Library except as expressly provided under this License. Any
351attempt otherwise to copy, modify, sublicense, link with, or
352distribute the Library is void, and will automatically terminate your
353rights under this License. However, parties who have received copies,
354or rights, from you under this License will not have their licenses
355terminated so long as such parties remain in full compliance.
356
357 9. You are not required to accept this License, since you have not
358signed it. However, nothing else grants you permission to modify or
359distribute the Library or its derivative works. These actions are
360prohibited by law if you do not accept this License. Therefore, by
361modifying or distributing the Library (or any work based on the
362Library), you indicate your acceptance of this License to do so, and
363all its terms and conditions for copying, distributing or modifying
364the Library or works based on it.
365
366 10. Each time you redistribute the Library (or any work based on the
367Library), the recipient automatically receives a license from the
368original licensor to copy, distribute, link with or modify the Library
369subject to these terms and conditions. You may not impose any further
370restrictions on the recipients' exercise of the rights granted herein.
371You are not responsible for enforcing compliance by third parties with
372this License.
373
374 11. If, as a consequence of a court judgment or allegation of patent
375infringement or for any other reason (not limited to patent issues),
376conditions are imposed on you (whether by court order, agreement or
377otherwise) that contradict the conditions of this License, they do not
378excuse you from the conditions of this License. If you cannot
379distribute so as to satisfy simultaneously your obligations under this
380License and any other pertinent obligations, then as a consequence you
381may not distribute the Library at all. For example, if a patent
382license would not permit royalty-free redistribution of the Library by
383all those who receive copies directly or indirectly through you, then
384the only way you could satisfy both it and this License would be to
385refrain entirely from distribution of the Library.
386
387If any portion of this section is held invalid or unenforceable under any
388particular circumstance, the balance of the section is intended to apply,
389and the section as a whole is intended to apply in other circumstances.
390
391It is not the purpose of this section to induce you to infringe any
392patents or other property right claims or to contest validity of any
393such claims; this section has the sole purpose of protecting the
394integrity of the free software distribution system which is
395implemented by public license practices. Many people have made
396generous contributions to the wide range of software distributed
397through that system in reliance on consistent application of that
398system; it is up to the author/donor to decide if he or she is willing
399to distribute software through any other system and a licensee cannot
400impose that choice.
401
402This section is intended to make thoroughly clear what is believed to
403be a consequence of the rest of this License.
404
405 12. If the distribution and/or use of the Library is restricted in
406certain countries either by patents or by copyrighted interfaces, the
407original copyright holder who places the Library under this License may add
408an explicit geographical distribution limitation excluding those countries,
409so that distribution is permitted only in or among countries not thus
410excluded. In such case, this License incorporates the limitation as if
411written in the body of this License.
412
413 13. The Free Software Foundation may publish revised and/or new
414versions of the Lesser General Public License from time to time.
415Such new versions will be similar in spirit to the present version,
416but may differ in detail to address new problems or concerns.
417
418Each version is given a distinguishing version number. If the Library
419specifies a version number of this License which applies to it and
420"any later version", you have the option of following the terms and
421conditions either of that version or of any later version published by
422the Free Software Foundation. If the Library does not specify a
423license version number, you may choose any version ever published by
424the Free Software Foundation.
425
426 14. If you wish to incorporate parts of the Library into other free
427programs whose distribution conditions are incompatible with these,
428write to the author to ask for permission. For software which is
429copyrighted by the Free Software Foundation, write to the Free
430Software Foundation; we sometimes make exceptions for this. Our
431decision will be guided by the two goals of preserving the free status
432of all derivatives of our free software and of promoting the sharing
433and reuse of software generally.
434
435 NO WARRANTY
436
437 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
438WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
439EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
440OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
441KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
442IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
443PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
444LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
445THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
446
447 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
448WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
449AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
450FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
451CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
452LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
453RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
454FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
455SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
456DAMAGES.
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
463possible use to the public, we recommend making it free software that
464everyone can redistribute and change. You can do so by permitting
465redistribution under these terms (or, alternatively, under the terms of the
466ordinary General Public License).
467
468 To apply these terms, attach the following notices to the library. It is
469safest to attach them to the start of each source file to most effectively
470convey 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
490Also add information on how to contact you by electronic and paper mail.
491
492You should also get your employer (if you work as a programmer) or your
493school, if any, to sign a "copyright disclaimer" for the library, if
494necessary. 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
502That'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
3SUBSYSTEM=="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
71static int debug = 0;
72
73static 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
85typedef enum {
86 ORIENTATION_UNDEFINED,
87 ORIENTATION_NORMAL,
88 ORIENTATION_BOTTOM_UP,
89 ORIENTATION_LEFT_UP,
90 ORIENTATION_RIGHT_UP
91} OrientationUp;
92
93static 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
111static const char *
112orientation_to_string (OrientationUp o)
113{
114 return orientations[o];
115}
116
117static OrientationUp
118string_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
131static OrientationUp
132orientation_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
170static OrientationUp
171get_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 */
184static 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
227read_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
238static 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
245int 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
50static 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
128static 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
205static 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 */
297static 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
321static 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
329static 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 */
354static 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
433out:
434 if (out_is_packet_device != NULL)
435 *out_is_packet_device = is_packet_device;
436 return ret;
437}
438
439static 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
446int 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 }
715close:
716 close(fd);
717exit:
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
3ACTION=="remove", GOTO="cdrom_end"
4SUBSYSTEM!="block", GOTO="cdrom_end"
5KERNEL!="sr[0-9]*|xvd*", GOTO="cdrom_end"
6ENV{DEVTYPE}!="disk", GOTO="cdrom_end"
7
8# unconditionally tag device as CDROM
9KERNEL=="sr[0-9]*", ENV{ID_CDROM}="1"
10
11# media eject button pressed
12ENV{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
16IMPORT{program}="cdrom_id --lock-media $devnode"
17
18KERNEL=="sr0", SYMLINK+="cdrom", OPTIONS+="link_priority=-100"
19
20LABEL="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
44static bool debug;
45
46static 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 */
59static unsigned int cd_cd_rom;
60static unsigned int cd_cd_r;
61static unsigned int cd_cd_rw;
62static unsigned int cd_dvd_rom;
63static unsigned int cd_dvd_r;
64static unsigned int cd_dvd_rw;
65static unsigned int cd_dvd_ram;
66static unsigned int cd_dvd_plus_r;
67static unsigned int cd_dvd_plus_rw;
68static unsigned int cd_dvd_plus_r_dl;
69static unsigned int cd_dvd_plus_rw_dl;
70static unsigned int cd_bd;
71static unsigned int cd_bd_r;
72static unsigned int cd_bd_re;
73static unsigned int cd_hddvd;
74static unsigned int cd_hddvd_r;
75static unsigned int cd_hddvd_rw;
76static unsigned int cd_mo;
77static unsigned int cd_mrw;
78static unsigned int cd_mrw_w;
79
80/* media info */
81static unsigned int cd_media;
82static unsigned int cd_media_cd_rom;
83static unsigned int cd_media_cd_r;
84static unsigned int cd_media_cd_rw;
85static unsigned int cd_media_dvd_rom;
86static unsigned int cd_media_dvd_r;
87static unsigned int cd_media_dvd_rw;
88static unsigned int cd_media_dvd_rw_ro; /* restricted overwrite mode */
89static unsigned int cd_media_dvd_rw_seq; /* sequential mode */
90static unsigned int cd_media_dvd_ram;
91static unsigned int cd_media_dvd_plus_r;
92static unsigned int cd_media_dvd_plus_rw;
93static unsigned int cd_media_dvd_plus_r_dl;
94static unsigned int cd_media_dvd_plus_rw_dl;
95static unsigned int cd_media_bd;
96static unsigned int cd_media_bd_r;
97static unsigned int cd_media_bd_re;
98static unsigned int cd_media_hddvd;
99static unsigned int cd_media_hddvd_r;
100static unsigned int cd_media_hddvd_rw;
101static unsigned int cd_media_mo;
102static unsigned int cd_media_mrw;
103static unsigned int cd_media_mrw_w;
104
105static const char *cd_media_state = NULL;
106static unsigned int cd_media_session_next;
107static unsigned int cd_media_session_count;
108static unsigned int cd_media_track_count;
109static unsigned int cd_media_track_count_data;
110static unsigned int cd_media_track_count_audio;
111static 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
118static 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
141static 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
150struct 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
159static 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
171static 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
179static 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
205static 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
221static 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
238static 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
265static 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
275static 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
300static 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
409static 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 */
499static 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 */
539static 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 }
624out:
625 return ret;
626}
627
628static 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
769determined:
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
780static 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
860int 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
975work:
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);
1093exit:
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
40enum collect_state {
41 STATE_NONE,
42 STATE_OLD,
43 STATE_CONFIRMED,
44};
45
46struct _mate {
47 struct udev_list_node node;
48 char *name;
49 enum collect_state state;
50};
51
52static struct udev_list_node bunch;
53static int debug;
54
55/* This can increase dynamically */
56static size_t bufsize = BUFSIZE;
57
58static 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
67static void sig_alrm(int signo)
68{
69 exit(4);
70}
71
72static 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 */
90static 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 */
137static 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 */
199static 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 */
227static 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 */
253static 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 */
274static 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 */
315static 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
338int 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);
465out:
466 if (debug)
467 everybody();
468 if (ret >= 0)
469 printf("COLLECT_%s=%d\n", checkpoint, ret);
470exit:
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 @@
1libudev-overrides.txt
2html/
3tmpl/
4xml/
5*.stamp
6*.bak
7version.xml
8libudev-decl-list.txt
9libudev-decl.txt
10libudev-undeclared.txt
11libudev-undocumented.txt
12libudev-unused.txt
13libudev.args
14libudev.hierarchy
15libudev.interfaces
16libudev.prerequisites
17libudev.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.
4AUTOMAKE_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'.
12DOC_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.
18DOC_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
24DOC_SOURCE_DIR=$(top_srcdir)/src
25
26# Extra options to pass to gtkdoc-scangobj. Not normally needed.
27SCANGOBJ_OPTIONS=
28
29# Extra options to supply to gtkdoc-scan.
30# e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED"
31SCAN_OPTIONS=
32
33# Extra options to supply to gtkdoc-mkdb.
34# e.g. MKDB_OPTIONS=--sgml-mode --output-format=xml
35MKDB_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
39MKTMPL_OPTIONS=
40
41# Extra options to supply to gtkdoc-mkhtml
42MKHTML_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
46FIXXREF_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
51HFILE_GLOB=$(top_srcdir)/src/libudev*.h
52CFILE_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
56EXTRA_HFILES=
57
58# Header files to ignore when scanning. Use base file name, no paths
59# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h
60IGNORE_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
64HTML_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
68content_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
73expand_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)
80GTKDOC_CFLAGS=
81GTKDOC_LIBS=
82
83# This includes the standard gtk-doc make rules, copied by gtkdocize.
84include $(top_srcdir)/gtk-doc.make
85
86# Other files to distribute
87# e.g. EXTRA_DIST += version.xml.in
88EXTRA_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'
96if ENABLE_GTK_DOC
97#TESTS_ENVIRONMENT = cd $(srcsrc)
98#TESTS = $(GTKDOC_CHECK)
99endif
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 &lt;kay.sievers@vrfy.org&gt;</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>
4udev
5udev_ref
6udev_unref
7udev_new
8udev_set_log_fn
9udev_get_log_priority
10udev_set_log_priority
11udev_get_sys_path
12udev_get_dev_path
13udev_get_run_path
14udev_get_userdata
15udev_set_userdata
16</SECTION>
17
18<SECTION>
19<FILE>libudev-list</FILE>
20<TITLE>udev_list</TITLE>
21udev_list_entry
22udev_list_entry_get_next
23udev_list_entry_get_by_name
24udev_list_entry_get_name
25udev_list_entry_get_value
26udev_list_entry_foreach
27</SECTION>
28
29<SECTION>
30<FILE>libudev-device</FILE>
31<TITLE>udev_device</TITLE>
32udev_device
33udev_device_ref
34udev_device_unref
35udev_device_get_udev
36udev_device_new_from_syspath
37udev_device_new_from_devnum
38udev_device_new_from_subsystem_sysname
39udev_device_new_from_environment
40udev_device_get_parent
41udev_device_get_parent_with_subsystem_devtype
42udev_device_get_devpath
43udev_device_get_subsystem
44udev_device_get_devtype
45udev_device_get_syspath
46udev_device_get_sysname
47udev_device_get_sysnum
48udev_device_get_devnode
49udev_device_get_is_initialized
50udev_device_get_devlinks_list_entry
51udev_device_get_properties_list_entry
52udev_device_get_tags_list_entry
53udev_device_get_property_value
54udev_device_get_driver
55udev_device_get_devnum
56udev_device_get_action
57udev_device_get_sysattr_value
58udev_device_get_sysattr_list_entry
59udev_device_get_seqnum
60udev_device_get_usec_since_initialized
61udev_device_has_tag
62</SECTION>
63
64<SECTION>
65<FILE>libudev-monitor</FILE>
66<TITLE>udev_monitor</TITLE>
67udev_monitor
68udev_monitor_ref
69udev_monitor_unref
70udev_monitor_get_udev
71udev_monitor_new_from_netlink
72udev_monitor_new_from_socket
73udev_monitor_enable_receiving
74udev_monitor_set_receive_buffer_size
75udev_monitor_get_fd
76udev_monitor_receive_device
77udev_monitor_filter_add_match_subsystem_devtype
78udev_monitor_filter_add_match_tag
79udev_monitor_filter_update
80udev_monitor_filter_remove
81</SECTION>
82
83<SECTION>
84<FILE>libudev-enumerate</FILE>
85<TITLE>udev_enumerate</TITLE>
86udev_enumerate
87udev_enumerate_ref
88udev_enumerate_unref
89udev_enumerate_get_udev
90udev_enumerate_new
91udev_enumerate_add_match_subsystem
92udev_enumerate_add_nomatch_subsystem
93udev_enumerate_add_match_sysattr
94udev_enumerate_add_nomatch_sysattr
95udev_enumerate_add_match_property
96udev_enumerate_add_match_tag
97udev_enumerate_add_match_parent
98udev_enumerate_add_match_is_initialized
99udev_enumerate_add_match_sysname
100udev_enumerate_add_syspath
101udev_enumerate_scan_devices
102udev_enumerate_scan_subsystems
103udev_enumerate_get_list_entry
104</SECTION>
105
106<SECTION>
107<FILE>libudev-queue</FILE>
108<TITLE>udev_queue</TITLE>
109udev_queue
110udev_queue_ref
111udev_queue_unref
112udev_queue_get_udev
113udev_queue_new
114udev_queue_get_udev_is_active
115udev_queue_get_queue_is_empty
116udev_queue_get_seqnum_is_finished
117udev_queue_get_seqnum_sequence_is_finished
118udev_queue_get_queued_list_entry
119udev_queue_get_kernel_seqnum
120udev_queue_get_udev_seqnum
121</SECTION>
122
123<SECTION>
124<FILE>libudev-util</FILE>
125<TITLE>udev_util</TITLE>
126udev_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
3SUBSYSTEM=="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
36static 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
45static int t360[] = { 1, 0 };
46static int t1200[] = { 2, 5, 6, 10, 12, 14, 16, 18, 20, 23, 0 };
47static int t3in[] = { 8, 9, 26, 27, 28, 7, 11, 15, 19, 24, 25, 29, 31, 3, 4, 13, 17, 21, 22, 30, 0 };
48static int *table_sup[] = { NULL, t360, t1200, t3in+5+8, t3in+5, t3in, t3in };
49
50static 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
57int 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();
175exit:
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 @@
1gtk-doc.make
2docs/version.xml
3gudev-1.0.pc
4gudevenumtypes.c
5gudevenumtypes.h
6gudevmarshal.c
7gudevmarshal.h
8GUdev-1.0.gir
9GUdev-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
16freedom to share and change it. By contrast, the GNU General Public
17Licenses are intended to guarantee your freedom to share and change
18free software--to make sure the software is free for all its users.
19
20 This license, the Lesser General Public License, applies to some
21specially designated software packages--typically libraries--of the
22Free Software Foundation and other authors who decide to use it. You
23can use it too, but we suggest you first think carefully about whether
24this license or the ordinary General Public License is the better
25strategy 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,
28not price. Our General Public Licenses are designed to make sure that
29you have the freedom to distribute copies of free software (and charge
30for this service if you wish); that you receive source code or can get
31it if you want it; that you can change the software and use pieces of
32it in new free programs; and that you are informed that you can do
33these things.
34
35 To protect your rights, we need to make restrictions that forbid
36distributors to deny you these rights or to ask you to surrender these
37rights. These restrictions translate to certain responsibilities for
38you 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
41or for a fee, you must give the recipients all the rights that we gave
42you. You must make sure that they, too, receive or can get the source
43code. If you link other code with the library, you must provide
44complete object files to the recipients, so that they can relink them
45with the library after making changes to the library and recompiling
46it. 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
49library, and (2) we offer you this license, which gives you legal
50permission to copy, distribute and/or modify the library.
51
52 To protect each distributor, we want to make it very clear that
53there is no warranty for the free library. Also, if the library is
54modified by someone else and passed on, the recipients should know
55that what they have is not the original version, so that the original
56author's reputation will not be affected by problems that might be
57introduced by others.
58
59 Finally, software patents pose a constant threat to the existence of
60any free program. We wish to make sure that a company cannot
61effectively restrict the users of a free program by obtaining a
62restrictive license from a patent holder. Therefore, we insist that
63any patent license obtained for a version of the library must be
64consistent with the full freedom of use specified in this license.
65
66 Most GNU software, including some libraries, is covered by the
67ordinary GNU General Public License. This license, the GNU Lesser
68General Public License, applies to certain designated libraries, and
69is quite different from the ordinary General Public License. We use
70this license for certain libraries in order to permit linking those
71libraries into non-free programs.
72
73 When a program is linked with a library, whether statically or using
74a shared library, the combination of the two is legally speaking a
75combined work, a derivative of the original library. The ordinary
76General Public License therefore permits such linking only if the
77entire combination fits its criteria of freedom. The Lesser General
78Public License permits more lax criteria for linking other code with
79the library.
80
81 We call this license the "Lesser" General Public License because it
82does Less to protect the user's freedom than the ordinary General
83Public License. It also provides other free software developers Less
84of an advantage over competing non-free programs. These disadvantages
85are the reason we use the ordinary General Public License for many
86libraries. However, the Lesser license provides advantages in certain
87special circumstances.
88
89 For example, on rare occasions, there may be a special need to
90encourage the widest possible use of a certain library, so that it becomes
91a de-facto standard. To achieve this, non-free programs must be
92allowed to use the library. A more frequent case is that a free
93library does the same job as widely used non-free libraries. In this
94case, there is little to gain by limiting the free library to free
95software only, so we use the Lesser General Public License.
96
97 In other cases, permission to use a particular library in non-free
98programs enables a greater number of people to use a large body of
99free software. For example, permission to use the GNU C Library in
100non-free programs enables many more people to use the whole GNU
101operating system, as well as its variant, the GNU/Linux operating
102system.
103
104 Although the Lesser General Public License is Less protective of the
105users' freedom, it does ensure that the user of a program that is
106linked with the Library has the freedom and the wherewithal to run
107that program using a modified version of the Library.
108
109 The precise terms and conditions for copying, distribution and
110modification follow. Pay close attention to the difference between a
111"work based on the library" and a "work that uses the library". The
112former contains code derived from the library, whereas the latter must
113be 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
119program which contains a notice placed by the copyright holder or
120other authorized party saying it may be distributed under the terms of
121this Lesser General Public License (also called "this License").
122Each licensee is addressed as "you".
123
124 A "library" means a collection of software functions and/or data
125prepared 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
129which has been distributed under these terms. A "work based on the
130Library" means either the Library or any derivative work under
131copyright law: that is to say, a work containing the Library or a
132portion of it, either verbatim or with modifications and/or translated
133straightforwardly into another language. (Hereinafter, translation is
134included without limitation in the term "modification".)
135
136 "Source code" for a work means the preferred form of the work for
137making modifications to it. For a library, complete source code means
138all the source code for all modules it contains, plus any associated
139interface definition files, plus the scripts used to control compilation
140and installation of the library.
141
142 Activities other than copying, distribution and modification are not
143covered by this License; they are outside its scope. The act of
144running a program using the Library is not restricted, and output from
145such a program is covered only if its contents constitute a work based
146on the Library (independent of the use of the Library in a tool for
147writing it). Whether that is true depends on what the Library does
148and what the program that uses the Library does.
149
150 1. You may copy and distribute verbatim copies of the Library's
151complete source code as you receive it, in any medium, provided that
152you conspicuously and appropriately publish on each copy an
153appropriate copyright notice and disclaimer of warranty; keep intact
154all the notices that refer to this License and to the absence of any
155warranty; and distribute a copy of this License along with the
156Library.
157
158 You may charge a fee for the physical act of transferring a copy,
159and you may at your option offer warranty protection in exchange for a
160fee.
161
162 2. You may modify your copy or copies of the Library or any portion
163of it, thus forming a work based on the Library, and copy and
164distribute such modifications or work under the terms of Section 1
165above, 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
190These requirements apply to the modified work as a whole. If
191identifiable sections of that work are not derived from the Library,
192and can be reasonably considered independent and separate works in
193themselves, then this License, and its terms, do not apply to those
194sections when you distribute them as separate works. But when you
195distribute the same sections as part of a whole which is a work based
196on the Library, the distribution of the whole must be on the terms of
197this License, whose permissions for other licensees extend to the
198entire whole, and thus to each and every part regardless of who wrote
199it.
200
201Thus, it is not the intent of this section to claim rights or contest
202your rights to work written entirely by you; rather, the intent is to
203exercise the right to control the distribution of derivative or
204collective works based on the Library.
205
206In addition, mere aggregation of another work not based on the Library
207with the Library (or with a work based on the Library) on a volume of
208a storage or distribution medium does not bring the other work under
209the scope of this License.
210
211 3. You may opt to apply the terms of the ordinary GNU General Public
212License instead of this License to a given copy of the Library. To do
213this, you must alter all the notices that refer to this License, so
214that they refer to the ordinary GNU General Public License, version 2,
215instead of to this License. (If a newer version than version 2 of the
216ordinary GNU General Public License has appeared, then you can specify
217that version instead if you wish.) Do not make any other change in
218these notices.
219
220 Once this change is made in a given copy, it is irreversible for
221that copy, so the ordinary GNU General Public License applies to all
222subsequent copies and derivative works made from that copy.
223
224 This option is useful when you wish to copy part of the code of
225the Library into a program that is not a library.
226
227 4. You may copy and distribute the Library (or a portion or
228derivative of it, under Section 2) in object code or executable form
229under the terms of Sections 1 and 2 above provided that you accompany
230it with the complete corresponding machine-readable source code, which
231must be distributed under the terms of Sections 1 and 2 above on a
232medium customarily used for software interchange.
233
234 If distribution of object code is made by offering access to copy
235from a designated place, then offering equivalent access to copy the
236source code from the same place satisfies the requirement to
237distribute the source code, even though third parties are not
238compelled to copy the source along with the object code.
239
240 5. A program that contains no derivative of any portion of the
241Library, but is designed to work with the Library by being compiled or
242linked with it, is called a "work that uses the Library". Such a
243work, in isolation, is not a derivative work of the Library, and
244therefore falls outside the scope of this License.
245
246 However, linking a "work that uses the Library" with the Library
247creates an executable that is a derivative of the Library (because it
248contains portions of the Library), rather than a "work that uses the
249library". The executable is therefore covered by this License.
250Section 6 states terms for distribution of such executables.
251
252 When a "work that uses the Library" uses material from a header file
253that is part of the Library, the object code for the work may be a
254derivative work of the Library even though the source code is not.
255Whether this is true is especially significant if the work can be
256linked without the Library, or if the work is itself a library. The
257threshold for this to be true is not precisely defined by law.
258
259 If such an object file uses only numerical parameters, data
260structure layouts and accessors, and small macros and small inline
261functions (ten lines or less in length), then the use of the object
262file is unrestricted, regardless of whether it is legally a derivative
263work. (Executables containing this object code plus portions of the
264Library will still fall under Section 6.)
265
266 Otherwise, if the work is a derivative of the Library, you may
267distribute the object code for the work under the terms of Section 6.
268Any executables containing that work also fall under Section 6,
269whether 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
272link a "work that uses the Library" with the Library to produce a
273work containing portions of the Library, and distribute that work
274under terms of your choice, provided that the terms permit
275modification of the work for the customer's own use and reverse
276engineering for debugging such modifications.
277
278 You must give prominent notice with each copy of the work that the
279Library is used in it and that the Library and its use are covered by
280this License. You must supply a copy of this License. If the work
281during execution displays copyright notices, you must include the
282copyright notice for the Library among them, as well as a reference
283directing the user to the copy of this License. Also, you must do one
284of 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
319Library" must include any data and utility programs needed for
320reproducing the executable from it. However, as a special exception,
321the materials to be distributed need not include anything that is
322normally distributed (in either source or binary form) with the major
323components (compiler, kernel, and so on) of the operating system on
324which the executable runs, unless that component itself accompanies
325the executable.
326
327 It may happen that this requirement contradicts the license
328restrictions of other proprietary libraries that do not normally
329accompany the operating system. Such a contradiction means you cannot
330use both them and the Library together in an executable that you
331distribute.
332
333 7. You may place library facilities that are a work based on the
334Library side-by-side in a single library together with other library
335facilities not covered by this License, and distribute such a combined
336library, provided that the separate distribution of the work based on
337the Library and of the other library facilities is otherwise
338permitted, 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
350the Library except as expressly provided under this License. Any
351attempt otherwise to copy, modify, sublicense, link with, or
352distribute the Library is void, and will automatically terminate your
353rights under this License. However, parties who have received copies,
354or rights, from you under this License will not have their licenses
355terminated so long as such parties remain in full compliance.
356
357 9. You are not required to accept this License, since you have not
358signed it. However, nothing else grants you permission to modify or
359distribute the Library or its derivative works. These actions are
360prohibited by law if you do not accept this License. Therefore, by
361modifying or distributing the Library (or any work based on the
362Library), you indicate your acceptance of this License to do so, and
363all its terms and conditions for copying, distributing or modifying
364the Library or works based on it.
365
366 10. Each time you redistribute the Library (or any work based on the
367Library), the recipient automatically receives a license from the
368original licensor to copy, distribute, link with or modify the Library
369subject to these terms and conditions. You may not impose any further
370restrictions on the recipients' exercise of the rights granted herein.
371You are not responsible for enforcing compliance by third parties with
372this License.
373
374 11. If, as a consequence of a court judgment or allegation of patent
375infringement or for any other reason (not limited to patent issues),
376conditions are imposed on you (whether by court order, agreement or
377otherwise) that contradict the conditions of this License, they do not
378excuse you from the conditions of this License. If you cannot
379distribute so as to satisfy simultaneously your obligations under this
380License and any other pertinent obligations, then as a consequence you
381may not distribute the Library at all. For example, if a patent
382license would not permit royalty-free redistribution of the Library by
383all those who receive copies directly or indirectly through you, then
384the only way you could satisfy both it and this License would be to
385refrain entirely from distribution of the Library.
386
387If any portion of this section is held invalid or unenforceable under any
388particular circumstance, the balance of the section is intended to apply,
389and the section as a whole is intended to apply in other circumstances.
390
391It is not the purpose of this section to induce you to infringe any
392patents or other property right claims or to contest validity of any
393such claims; this section has the sole purpose of protecting the
394integrity of the free software distribution system which is
395implemented by public license practices. Many people have made
396generous contributions to the wide range of software distributed
397through that system in reliance on consistent application of that
398system; it is up to the author/donor to decide if he or she is willing
399to distribute software through any other system and a licensee cannot
400impose that choice.
401
402This section is intended to make thoroughly clear what is believed to
403be a consequence of the rest of this License.
404
405 12. If the distribution and/or use of the Library is restricted in
406certain countries either by patents or by copyrighted interfaces, the
407original copyright holder who places the Library under this License may add
408an explicit geographical distribution limitation excluding those countries,
409so that distribution is permitted only in or among countries not thus
410excluded. In such case, this License incorporates the limitation as if
411written in the body of this License.
412
413 13. The Free Software Foundation may publish revised and/or new
414versions of the Lesser General Public License from time to time.
415Such new versions will be similar in spirit to the present version,
416but may differ in detail to address new problems or concerns.
417
418Each version is given a distinguishing version number. If the Library
419specifies a version number of this License which applies to it and
420"any later version", you have the option of following the terms and
421conditions either of that version or of any later version published by
422the Free Software Foundation. If the Library does not specify a
423license version number, you may choose any version ever published by
424the Free Software Foundation.
425
426 14. If you wish to incorporate parts of the Library into other free
427programs whose distribution conditions are incompatible with these,
428write to the author to ask for permission. For software which is
429copyrighted by the Free Software Foundation, write to the Free
430Software Foundation; we sometimes make exceptions for this. Our
431decision will be guided by the two goals of preserving the free status
432of all derivatives of our free software and of promoting the sharing
433and reuse of software generally.
434
435 NO WARRANTY
436
437 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
438WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
439EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
440OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
441KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
442IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
443PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
444LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
445THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
446
447 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
448WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
449AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
450FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
451CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
452LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
453RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
454FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
455SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
456DAMAGES.
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
463possible use to the public, we recommend making it free software that
464everyone can redistribute and change. You can do so by permitting
465redistribution under these terms (or, alternatively, under the terms of the
466ordinary General Public License).
467
468 To apply these terms, attach the following notices to the library. It is
469safest to attach them to the start of each source file to most effectively
470convey 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
490Also add information on how to contact you by electronic and paper mail.
491
492You should also get your employer (if you work as a programmer) or your
493school, if any, to sign a "copyright disclaimer" for the library, if
494necessary. 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
502That'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 @@
1gudev-overrides.txt
2gudev-decl-list.txt
3gudev-decl.txt
4gudev-undeclared.txt
5gudev-undocumented.txt
6gudev-unused.txt
7gudev.args
8gudev.hierarchy
9gudev.interfaces
10gudev.prerequisites
11gudev.signals
12html.stamp
13html/*
14xml/*
15tmpl/*
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.
4AUTOMAKE_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'.
12DOC_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.
18DOC_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
24DOC_SOURCE_DIR=$(top_srcdir)/src
25
26# Extra options to pass to gtkdoc-scangobj. Not normally needed.
27SCANGOBJ_OPTIONS=
28
29# Extra options to supply to gtkdoc-scan.
30# e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED"
31SCAN_OPTIONS=
32
33# Extra options to supply to gtkdoc-mkdb.
34# e.g. MKDB_OPTIONS=--sgml-mode --output-format=xml
35MKDB_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
39MKTMPL_OPTIONS=
40
41# Extra options to supply to gtkdoc-mkhtml
42MKHTML_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
46FIXXREF_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
51HFILE_GLOB=$(top_srcdir)/src/gudev/*.h
52CFILE_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
56EXTRA_HFILES=
57
58# Header files to ignore when scanning. Use base file name, no paths
59# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h
60IGNORE_HFILES=
61
62# Images to copy into HTML directory.
63# e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png
64HTML_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
68content_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
73expand_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)
80GTKDOC_CFLAGS = \
81 $(DBUS_GLIB_CFLAGS) \
82 $(GLIB_CFLAGS) \
83 -I$(top_srcdir)/src/gudev \
84 -I$(top_builddir)/src/gudev
85
86GTKDOC_LIBS = \
87 $(GLIB_LIBS) \
88 $(top_builddir)/libgudev-1.0.la
89
90# This includes the standard gtk-doc make rules, copied by gtkdocize.
91include $(top_srcdir)/gtk-doc.make
92
93# Other files to distribute
94# e.g. EXTRA_DIST += version.xml.in
95EXTRA_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'
103if ENABLE_GTK_DOC
104#TESTS_ENVIRONMENT = cd $(srcsrc)
105#TESTS = $(GTKDOC_CHECK)
106endif
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>
4GUdevClient
5GUdevClientClass
6GUdevDeviceType
7GUdevDeviceNumber
8g_udev_client_new
9g_udev_client_query_by_subsystem
10g_udev_client_query_by_device_number
11g_udev_client_query_by_device_file
12g_udev_client_query_by_sysfs_path
13g_udev_client_query_by_subsystem_and_name
14<SUBSECTION Standard>
15G_UDEV_CLIENT
16G_UDEV_IS_CLIENT
17G_UDEV_TYPE_CLIENT
18g_udev_client_get_type
19G_UDEV_CLIENT_CLASS
20G_UDEV_IS_CLIENT_CLASS
21G_UDEV_CLIENT_GET_CLASS
22<SUBSECTION Private>
23GUdevClientPrivate
24</SECTION>
25
26<SECTION>
27<FILE>gudevdevice</FILE>
28<TITLE>GUdevDevice</TITLE>
29GUdevDevice
30GUdevDeviceClass
31g_udev_device_get_subsystem
32g_udev_device_get_devtype
33g_udev_device_get_name
34g_udev_device_get_number
35g_udev_device_get_sysfs_path
36g_udev_device_get_driver
37g_udev_device_get_action
38g_udev_device_get_seqnum
39g_udev_device_get_device_type
40g_udev_device_get_device_number
41g_udev_device_get_device_file
42g_udev_device_get_device_file_symlinks
43g_udev_device_get_parent
44g_udev_device_get_parent_with_subsystem
45g_udev_device_get_tags
46g_udev_device_get_is_initialized
47g_udev_device_get_usec_since_initialized
48g_udev_device_get_property_keys
49g_udev_device_has_property
50g_udev_device_get_property
51g_udev_device_get_property_as_int
52g_udev_device_get_property_as_uint64
53g_udev_device_get_property_as_double
54g_udev_device_get_property_as_boolean
55g_udev_device_get_property_as_strv
56g_udev_device_get_sysfs_attr
57g_udev_device_get_sysfs_attr_as_int
58g_udev_device_get_sysfs_attr_as_uint64
59g_udev_device_get_sysfs_attr_as_double
60g_udev_device_get_sysfs_attr_as_boolean
61g_udev_device_get_sysfs_attr_as_strv
62<SUBSECTION Standard>
63G_UDEV_DEVICE
64G_UDEV_IS_DEVICE
65G_UDEV_TYPE_DEVICE
66g_udev_device_get_type
67G_UDEV_DEVICE_CLASS
68G_UDEV_IS_DEVICE_CLASS
69G_UDEV_DEVICE_GET_CLASS
70<SUBSECTION Private>
71GUdevDevicePrivate
72</SECTION>
73
74<SECTION>
75<FILE>gudevenumerator</FILE>
76<TITLE>GUdevEnumerator</TITLE>
77GUdevEnumerator
78GUdevEnumeratorClass
79g_udev_enumerator_new
80g_udev_enumerator_add_match_subsystem
81g_udev_enumerator_add_nomatch_subsystem
82g_udev_enumerator_add_match_sysfs_attr
83g_udev_enumerator_add_nomatch_sysfs_attr
84g_udev_enumerator_add_match_property
85g_udev_enumerator_add_match_name
86g_udev_enumerator_add_match_tag
87g_udev_enumerator_add_match_is_initialized
88g_udev_enumerator_add_sysfs_path
89g_udev_enumerator_execute
90<SUBSECTION Standard>
91G_UDEV_ENUMERATOR
92G_UDEV_IS_ENUMERATOR
93G_UDEV_TYPE_ENUMERATOR
94g_udev_enumerator_get_type
95G_UDEV_ENUMERATOR_CLASS
96G_UDEV_IS_ENUMERATOR_CLASS
97G_UDEV_ENUMERATOR_GET_CLASS
98<SUBSECTION Private>
99GUdevEnumeratorPrivate
100</SECTION>
101
102<SECTION>
103<FILE>gudevmarshal</FILE>
104<SUBSECTION Private>
105g_udev_marshal_VOID__STRING_OBJECT
106</SECTION>
107
108<SECTION>
109<FILE>gudevenumtypes</FILE>
110<SUBSECTION Private>
111G_TYPE_UDEV_DEVICE_TYPE
112g_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 @@
1g_udev_device_type_get_type
2g_udev_device_get_type
3g_udev_client_get_type
4g_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
9const GUdev = imports.gi.GUdev;
10const Mainloop = imports.mainloop;
11
12function 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
32function on_uevent (client, action, device) {
33 print ("action " + action + " on device " + device.get_sysfs_path());
34 print_device (device);
35 print ("");
36}
37
38var client = new GUdev.Client ({subsystems: ["block", "usb/usb_interface"]});
39client.connect ("uevent", on_uevent);
40
41var block_devices = client.query_by_subsystem ("block");
42for (var n = 0; n < block_devices.length; n++) {
43 print ("block device: " + block_devices[n].get_device_file ());
44}
45
46var d;
47
48d = client.query_by_device_number (GUdev.DeviceType.BLOCK, 0x0810);
49if (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
63d = client.query_by_sysfs_path ("/sys/block/sda/sda1");
64print ("query_by_sysfs_path (\"/sys/block/sda1\") -> " + d.get_device_file ());
65
66d = client.query_by_subsystem_and_name ("block", "sda2");
67print ("query_by_subsystem_and_name (\"block\", \"sda2\") -> " + d.get_device_file ());
68
69d = client.query_by_device_file ("/dev/sda");
70print ("query_by_device_file (\"/dev/sda\") -> " + d.get_device_file ());
71
72d = client.query_by_device_file ("/dev/block/8:0");
73print ("query_by_device_file (\"/dev/block/8:0\") -> " + d.get_device_file ());
74
75Mainloop.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 @@
1prefix=@prefix@
2exec_prefix=@exec_prefix@
3libdir=@libdir@
4includedir=@includedir@
5
6Name: gudev-1.0
7Description: GObject bindings for libudev
8Version: @VERSION@
9Requires: glib-2.0, gobject-2.0
10Libs: -L${libdir} -lgudev-1.0
11Cflags: -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
61struct _GUdevClientPrivate
62{
63 GSource *watch_source;
64 struct udev *udev;
65 struct udev_monitor *monitor;
66
67 gchar **subsystems;
68};
69
70enum
71{
72 PROP_0,
73 PROP_SUBSYSTEMS,
74};
75
76enum
77{
78 UEVENT_SIGNAL,
79 LAST_SIGNAL,
80};
81
82static guint signals[LAST_SIGNAL] = { 0 };
83
84G_DEFINE_TYPE (GUdevClient, g_udev_client, G_TYPE_OBJECT)
85
86/* ---------------------------------------------------------------------------------------------------- */
87
88static gboolean
89monitor_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
116static void
117g_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
145static void
146g_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
167static void
168g_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
187static void
188g_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
250static void
251g_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
310static void
311g_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 */
330GUdevClient *
331g_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 */
345GList *
346g_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 */
398GUdevDevice *
399g_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 */
430GUdevDevice *
431g_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 */
466GUdevDevice *
467g_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 */
498GUdevDevice *
499g_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
522struct 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
30G_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
39typedef struct _GUdevClientClass GUdevClientClass;
40typedef struct _GUdevClientPrivate GUdevClientPrivate;
41
42/**
43 * GUdevClient:
44 *
45 * The #GUdevClient struct is opaque and should not be accessed directly.
46 */
47struct _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 */
62struct _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
83GType g_udev_client_get_type (void) G_GNUC_CONST;
84GUdevClient *g_udev_client_new (const gchar* const *subsystems);
85GList *g_udev_client_query_by_subsystem (GUdevClient *client,
86 const gchar *subsystem);
87GUdevDevice *g_udev_client_query_by_device_number (GUdevClient *client,
88 GUdevDeviceType type,
89 GUdevDeviceNumber number);
90GUdevDevice *g_udev_client_query_by_device_file (GUdevClient *client,
91 const gchar *device_file);
92GUdevDevice *g_udev_client_query_by_sysfs_path (GUdevClient *client,
93 const gchar *sysfs_path);
94GUdevDevice *g_udev_client_query_by_subsystem_and_name (GUdevClient *client,
95 const gchar *subsystem,
96 const gchar *name);
97
98G_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
82struct _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
94G_DEFINE_TYPE (GUdevDevice, g_udev_device, G_TYPE_OBJECT)
95
96static void
97g_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
118static void
119g_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
128static void
129g_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
137GUdevDevice *
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 */
156const gchar *
157g_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 */
171const gchar *
172g_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 */
186const gchar *
187g_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 */
201const gchar *
202g_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 */
216const gchar *
217g_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 */
231const gchar *
232g_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 */
246const gchar *
247g_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 */
261guint64
262g_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 */
276GUdevDeviceType
277g_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 */
313GUdevDeviceNumber
314g_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 */
329const gchar *
330g_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 */
345const gchar * const *
346g_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 */
378GUdevDevice *
379g_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 */
409GUdevDevice *
410g_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 */
444const gchar* const *
445g_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 */
477gboolean
478g_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 */
495const gchar *
496g_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 */
515gint
516g_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);
531out:
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 */
546guint64
547g_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);
562out:
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 */
577gdouble
578g_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);
593out:
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 */
609gboolean
610g_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
630static gchar **
631split_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 */
667const gchar* const *
668g_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
697out:
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 */
713const gchar *
714g_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 */
733gint
734g_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);
749out:
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 */
764guint64
765g_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);
780out:
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 */
795gdouble
796g_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);
811out:
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 */
827gboolean
828g_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 */
861const gchar * const *
862g_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
891out:
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 */
905const gchar* const *
906g_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 */
938gboolean
939g_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 */
958guint64
959g_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
30G_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
39typedef struct _GUdevDeviceClass GUdevDeviceClass;
40typedef struct _GUdevDevicePrivate GUdevDevicePrivate;
41
42/**
43 * GUdevDevice:
44 *
45 * The #GUdevDevice struct is opaque and should not be accessed directly.
46 */
47struct _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 */
61struct _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
77GType g_udev_device_get_type (void) G_GNUC_CONST;
78gboolean g_udev_device_get_is_initialized (GUdevDevice *device);
79guint64 g_udev_device_get_usec_since_initialized (GUdevDevice *device);
80const gchar *g_udev_device_get_subsystem (GUdevDevice *device);
81const gchar *g_udev_device_get_devtype (GUdevDevice *device);
82const gchar *g_udev_device_get_name (GUdevDevice *device);
83const gchar *g_udev_device_get_number (GUdevDevice *device);
84const gchar *g_udev_device_get_sysfs_path (GUdevDevice *device);
85const gchar *g_udev_device_get_driver (GUdevDevice *device);
86const gchar *g_udev_device_get_action (GUdevDevice *device);
87guint64 g_udev_device_get_seqnum (GUdevDevice *device);
88GUdevDeviceType g_udev_device_get_device_type (GUdevDevice *device);
89GUdevDeviceNumber g_udev_device_get_device_number (GUdevDevice *device);
90const gchar *g_udev_device_get_device_file (GUdevDevice *device);
91const gchar* const *g_udev_device_get_device_file_symlinks (GUdevDevice *device);
92GUdevDevice *g_udev_device_get_parent (GUdevDevice *device);
93GUdevDevice *g_udev_device_get_parent_with_subsystem (GUdevDevice *device,
94 const gchar *subsystem,
95 const gchar *devtype);
96const gchar* const *g_udev_device_get_property_keys (GUdevDevice *device);
97gboolean g_udev_device_has_property (GUdevDevice *device,
98 const gchar *key);
99const gchar *g_udev_device_get_property (GUdevDevice *device,
100 const gchar *key);
101gint g_udev_device_get_property_as_int (GUdevDevice *device,
102 const gchar *key);
103guint64 g_udev_device_get_property_as_uint64 (GUdevDevice *device,
104 const gchar *key);
105gdouble g_udev_device_get_property_as_double (GUdevDevice *device,
106 const gchar *key);
107gboolean g_udev_device_get_property_as_boolean (GUdevDevice *device,
108 const gchar *key);
109const gchar* const *g_udev_device_get_property_as_strv (GUdevDevice *device,
110 const gchar *key);
111
112const gchar *g_udev_device_get_sysfs_attr (GUdevDevice *device,
113 const gchar *name);
114gint g_udev_device_get_sysfs_attr_as_int (GUdevDevice *device,
115 const gchar *name);
116guint64 g_udev_device_get_sysfs_attr_as_uint64 (GUdevDevice *device,
117 const gchar *name);
118gdouble g_udev_device_get_sysfs_attr_as_double (GUdevDevice *device,
119 const gchar *name);
120gboolean g_udev_device_get_sysfs_attr_as_boolean (GUdevDevice *device,
121 const gchar *name);
122const gchar* const *g_udev_device_get_sysfs_attr_as_strv (GUdevDevice *device,
123 const gchar *name);
124const gchar* const *g_udev_device_get_tags (GUdevDevice *device);
125
126G_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
44struct _GUdevEnumeratorPrivate
45{
46 GUdevClient *client;
47 struct udev_enumerate *e;
48};
49
50enum
51{
52 PROP_0,
53 PROP_CLIENT,
54};
55
56G_DEFINE_TYPE (GUdevEnumerator, g_udev_enumerator, G_TYPE_OBJECT)
57
58/* ---------------------------------------------------------------------------------------------------- */
59
60static void
61g_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
81static void
82g_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
103static void
104g_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
123static void
124g_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
136static void
137g_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
165static void
166g_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 */
186GUdevEnumerator *
187g_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 */
205GUdevEnumerator *
206g_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 */
226GUdevEnumerator *
227g_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 */
248GUdevEnumerator *
249g_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 */
272GUdevEnumerator *
273g_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 */
296GUdevEnumerator *
297g_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 */
319GUdevEnumerator *
320g_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 */
340GUdevEnumerator *
341g_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 */
361GUdevEnumerator *
362g_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 */
381GUdevEnumerator *
382g_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 */
399GList *
400g_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
30G_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
39typedef struct _GUdevEnumeratorClass GUdevEnumeratorClass;
40typedef 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 */
49struct _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 */
65struct _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
81GType g_udev_enumerator_get_type (void) G_GNUC_CONST;
82GUdevEnumerator *g_udev_enumerator_new (GUdevClient *client);
83GUdevEnumerator *g_udev_enumerator_add_match_subsystem (GUdevEnumerator *enumerator,
84 const gchar *subsystem);
85GUdevEnumerator *g_udev_enumerator_add_nomatch_subsystem (GUdevEnumerator *enumerator,
86 const gchar *subsystem);
87GUdevEnumerator *g_udev_enumerator_add_match_sysfs_attr (GUdevEnumerator *enumerator,
88 const gchar *name,
89 const gchar *value);
90GUdevEnumerator *g_udev_enumerator_add_nomatch_sysfs_attr (GUdevEnumerator *enumerator,
91 const gchar *name,
92 const gchar *value);
93GUdevEnumerator *g_udev_enumerator_add_match_property (GUdevEnumerator *enumerator,
94 const gchar *name,
95 const gchar *value);
96GUdevEnumerator *g_udev_enumerator_add_match_name (GUdevEnumerator *enumerator,
97 const gchar *name);
98GUdevEnumerator *g_udev_enumerator_add_match_tag (GUdevEnumerator *enumerator,
99 const gchar *tag);
100GUdevEnumerator *g_udev_enumerator_add_match_is_initialized (GUdevEnumerator *enumerator);
101GUdevEnumerator *g_udev_enumerator_add_sysfs_path (GUdevEnumerator *enumerator,
102 const gchar *sysfs_path);
103GList *g_udev_enumerator_execute (GUdevEnumerator *enumerator);
104
105G_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
30G_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 */
40typedef 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
47G_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 ***/
11GType
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
7G_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 ***/
16GType @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 ***/
21G_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
32G_BEGIN_DECLS
33
34GUdevDevice *
35_g_udev_device_new (struct udev_device *udevice);
36
37struct udev *_g_udev_client_get_udev (GUdevClient *client);
38
39G_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
31G_BEGIN_DECLS
32
33typedef struct _GUdevClient GUdevClient;
34typedef struct _GUdevDevice GUdevDevice;
35typedef 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
44typedef guint64 GUdevDeviceNumber; /* __UQUAD_TYPE */
45#else
46typedef dev_t GUdevDeviceNumber;
47#endif
48
49G_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
3const GLib = imports.gi.GLib;
4const GUdev = imports.gi.GUdev;
5
6function 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
28var client = new GUdev.Client({subsystems: []});
29var enumerator = new GUdev.Enumerator({client: client});
30enumerator.add_match_subsystem('b*')
31
32var devices = enumerator.execute();
33
34for (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
5const GLib = imports.gi.GLib;
6const GUdev = imports.gi.GUdev;
7
8function 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
28function on_uevent (client, action, device) {
29 print ("action " + action + " on device " + device.get_sysfs_path());
30 print_device (device);
31 print ("");
32}
33
34var client = new GUdev.Client ({subsystems: ["block", "usb/usb_interface"]});
35client.signal.connect ("uevent", on_uevent);
36
37var block_devices = client.query_by_subsystem ("block");
38for (var n = 0; n < block_devices.length; n++) {
39 print ("block device: " + block_devices[n].get_device_file ());
40}
41
42var d;
43
44d = client.query_by_device_number (GUdev.DeviceType.BLOCK, 0x0810);
45if (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
59d = client.query_by_sysfs_path ("/sys/block/sda/sda1");
60print ("query_by_sysfs_path (\"/sys/block/sda1\") -> " + d.get_device_file ());
61
62d = client.query_by_subsystem_and_name ("block", "sda2");
63print ("query_by_subsystem_and_name (\"block\", \"sda2\") -> " + d.get_device_file ());
64
65d = client.query_by_device_file ("/dev/sda");
66print ("query_by_device_file (\"/dev/sda\") -> " + d.get_device_file ());
67
68d = client.query_by_device_file ("/dev/block/8:0");
69print ("query_by_device_file (\"/dev/block/8:0\") -> " + d.get_device_file ());
70
71var mainloop = GLib.main_loop_new ();
72GLib.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 @@
1keyboard-force-release.sh
2keys-from-name.gperf
3keys-from-name.h
4keys-to-name.h
5keys.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
14ACTION=="remove", GOTO="force_release_end"
15SUBSYSTEM!="serio", GOTO="force_release_end"
16KERNEL!="serio*", GOTO="force_release_end"
17DRIVER!="atkbd", GOTO="force_release_end"
18
19ENV{DMI_VENDOR}="$attr{[dmi/id]sys_vendor}"
20
21ENV{DMI_VENDOR}=="[sS][aA][mM][sS][uU][nN][gG]*", RUN+="keyboard-force-release.sh $devpath samsung-other"
22ENV{DMI_VENDOR}=="[sS][aA][mM][sS][uU][nN][gG]*", ATTR{[dmi/id]product_name}=="*90X3A*", RUN+="keyboard-force-release.sh $devpath samsung-90x3a"
23
24ENV{DMI_VENDOR}=="Dell Inc.", ATTR{[dmi/id]product_name}=="Studio 1557|Studio 1558", RUN+="keyboard-force-release.sh $devpath common-volume-keys"
25ENV{DMI_VENDOR}=="Dell Inc.", ATTR{[dmi/id]product_name}=="Latitude E*|Precision M*", RUN+="keyboard-force-release.sh $devpath dell-touchpad"
26
27ENV{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
29ENV{DMI_VENDOR}=="FOXCONN", ATTR{[dmi/id]product_name}=="QBOOK", RUN+="keyboard-force-release.sh $devpath common-volume-keys"
30
31ENV{DMI_VENDOR}=="MTC", ATTR{[dmi/id]product_version}=="A0", RUN+="keyboard-force-release.sh $devpath common-volume-keys"
32
33ENV{DMI_VENDOR}=="PEGATRON CORP.", ATTR{[dmi/id]product_name}=="Spring Peak", RUN+="keyboard-force-release.sh $devpath common-volume-keys"
34
35ENV{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
37ENV{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
40ENV{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"
41ENV{DMI_VENDOR}=="Hewlett-Packard*", ATTR{[dmi/id]product_name}=="*[tT][xX]2*", RUN+="keyboard-force-release.sh $devpath hp-other"
42ENV{DMI_VENDOR}=="Hewlett-Packard*", ATTR{[dmi/id]product_name}=="*2510p*|*2530p*|HP G60 Notebook PC", RUN+="keyboard-force-release.sh $devpath hp-other"
43
44ENV{DMI_VENDOR}=="Zepto", ATTR{[dmi/id]product_name}=="Znote 6615WD", RUN+="keyboard-force-release.sh $devpath common-volume-keys"
45
46ENV{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
48ENV{DMI_VENDOR}=="HANNspree", ATTR{[dmi/id]product_name}=="SN10E100", RUN+="keyboard-force-release.sh $devpath common-volume-keys"
49
50ENV{DMI_VENDOR}=="GIGABYTE", ATTR{[dmi/id]product_name}=="i1520M", RUN+="keyboard-force-release.sh $devpath common-volume-keys"
51
52ENV{DMI_VENDOR}=="BenQ", ATTR{[dmi/id]product_name}=="*nScreen*", RUN+="keyboard-force-release.sh $devpath common-volume-keys"
53
54LABEL="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
8ACTION=="remove", GOTO="keyboard_end"
9KERNEL!="event*", GOTO="keyboard_end"
10ENV{ID_INPUT_KEY}=="", GOTO="keyboard_end"
11SUBSYSTEMS=="bluetooth", GOTO="keyboard_end"
12
13SUBSYSTEMS=="usb", IMPORT{builtin}="usb_id"
14SUBSYSTEMS=="usb", GOTO="keyboard_usbcheck"
15GOTO="keyboard_modulecheck"
16
17#
18# The following are external USB keyboards
19#
20
21LABEL="keyboard_usbcheck"
22
23ENV{ID_VENDOR}=="Genius", ENV{ID_MODEL_ID}=="0708", ENV{ID_USB_INTERFACE_NUM}=="01", RUN+="keymap $name genius-slimstar-320"
24ENV{ID_VENDOR}=="Logitech*", ATTRS{name}=="Logitech USB Multimedia Keyboard", RUN+="keymap $name logitech-wave"
25ENV{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
27ENV{ID_VENDOR_ID}=="046d", ENV{ID_MODEL_ID}=="c52[9b]", ATTRS{name}=="Logitech USB Receiver", RUN+="keymap $name logitech-wave-pro-cordless"
28
29ENV{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"
30ENV{ID_VENDOR_ID}=="04b3", ENV{ID_MODEL_ID}=="301[89]", RUN+="keymap $name ibm-thinkpad-usb-keyboard-trackpoint"
31
32ENV{ID_VENDOR}=="Microsoft", ENV{ID_MODEL_ID}=="00db", RUN+="keymap $name 0xc022d zoomin 0xc022e zoomout"
33
34GOTO="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
41LABEL="keyboard_modulecheck"
42
43ENV{DMI_VENDOR}="$attr{[dmi/id]sys_vendor}"
44ENV{DMI_VENDOR}=="", GOTO="keyboard_end"
45
46ENV{DMI_VENDOR}=="LENOVO*", KERNELS=="input*", ATTRS{name}=="ThinkPad Extra Buttons", RUN+="keymap $name module-lenovo"
47ENV{DMI_VENDOR}=="LENOVO*", KERNELS=="input*", ATTRS{name}=="Lenovo ThinkPad SL Series extra buttons", RUN+="keymap $name 0x0E bluetooth"
48
49ENV{DMI_VENDOR}=="ASUS*", KERNELS=="input*", ATTRS{name}=="Asus Extra Buttons", ATTR{[dmi/id]product_name}=="W3J", RUN+="keymap $name module-asus-w3j"
50ENV{DMI_VENDOR}=="ASUS*", KERNELS=="input*", ATTRS{name}=="Eee PC WMI hotkeys|Asus Laptop Support|Asus*WMI*", RUN+="keymap $name 0x6B f21"
51ENV{DMI_VENDOR}=="ASUS*", KERNELS=="input*", ATTRS{name}=="Eee PC Hotkey Driver", RUN+="keymap $name 0x37 f21"
52
53ENV{DMI_VENDOR}=="IBM*", KERNELS=="input*", ATTRS{name}=="ThinkPad Extra Buttons", RUN+="keymap $name module-ibm"
54ENV{DMI_VENDOR}=="Sony*", KERNELS=="input*", ATTRS{name}=="Sony Vaio Keys", RUN+="keymap $name module-sony"
55ENV{DMI_VENDOR}=="Acer*", KERNELS=="input*", ATTRS{name}=="Acer WMI hotkeys", RUN+="keymap $name 0x82 f21"
56ENV{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
59ENV{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
62ENV{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
69DRIVERS=="atkbd", GOTO="keyboard_vendorcheck"
70GOTO="keyboard_end"
71
72LABEL="keyboard_vendorcheck"
73
74ENV{DMI_VENDOR}=="Dell*", RUN+="keymap $name dell"
75ENV{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"
76ENV{DMI_VENDOR}=="Dell*", ATTR{[dmi/id]product_name}=="Latitude XT2", RUN+="keymap $name dell-latitude-xt2"
77
78ENV{DMI_VENDOR}=="Compaq*", ATTR{[dmi/id]product_name}=="*E500*|*Evo N*", RUN+="keymap $name compaq-e_evo"
79
80ENV{DMI_VENDOR}=="LENOVO*", ATTR{[dmi/id]product_version}=="*3000*", RUN+="keymap $name lenovo-3000"
81ENV{DMI_VENDOR}=="LENOVO*", ATTR{[dmi/id]product_version}=="ThinkPad X6*", ATTR{[dmi/id]product_version}=="* Tablet", RUN+="keymap $name lenovo-thinkpad_x6_tablet"
82ENV{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"
83ENV{DMI_VENDOR}=="LENOVO*", ATTR{[dmi/id]product_version}=="*IdeaPad*", RUN+="keymap $name lenovo-ideapad"
84ENV{DMI_VENDOR}=="LENOVO*", ATTR{[dmi/id]product_name}=="S10-*", RUN+="keymap $name lenovo-ideapad"
85ENV{DMI_VENDOR}=="LENOVO", ATTR{[dmi/id]product_version}=="*IdeaPad Y550*", RUN+="keymap $name 0x95 media 0xA3 play"
86
87ENV{DMI_VENDOR}=="Hewlett-Packard*", RUN+="keymap $name hewlett-packard"
88ENV{DMI_VENDOR}=="Hewlett-Packard*", ATTR{[dmi/id]product_name}=="*[tT][aA][bB][lL][eE][tT]*", RUN+="keymap $name hewlett-packard-tablet"
89ENV{DMI_VENDOR}=="Hewlett-Packard*", ATTR{[dmi/id]product_name}=="*[pP][aA][vV][iI][lL][iI][oO][nN]*", RUN+="keymap $name hewlett-packard-pavilion"
90ENV{DMI_VENDOR}=="Hewlett-Packard*", ATTR{[dmi/id]product_name}=="*Compaq*|*EliteBook*|*2230s*", RUN+="keymap $name hewlett-packard-compaq_elitebook"
91ENV{DMI_VENDOR}=="Hewlett-Packard*", ATTR{[dmi/id]product_name}=="*2510p*|*2530p*|HP G60 Notebook PC", RUN+="keymap $name hewlett-packard-2510p_2530p"
92ENV{DMI_VENDOR}=="Hewlett-Packard*", ATTR{[dmi/id]product_name}=="*[tT][xX]2*", RUN+="keymap $name hewlett-packard-tx2"
93ENV{DMI_VENDOR}=="Hewlett-Packard", ATTR{[dmi/id]product_name}=="Presario 2100*", RUN+="keymap $name hewlett-packard-presario-2100"
94ENV{DMI_VENDOR}=="Hewlett-Packard", ATTR{[dmi/id]product_name}=="HP G62 Notebook PC", RUN+="keymap $name 0xB2 www"
95ENV{DMI_VENDOR}=="Hewlett-Packard", ATTR{[dmi/id]product_name}=="HP ProBook*", RUN+="keymap $name 0xF8 rfkill"
96# HP Pavillion dv6315ea has empty DMI_VENDOR
97ATTR{[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
100ENV{DMI_VENDOR}=="Gateway*", ATTR{[dmi/id]product_name}=="*AOA1*", RUN+="keymap $name acer"
101
102ENV{DMI_VENDOR}=="Acer*", RUN+="keymap $name acer"
103ENV{DMI_VENDOR}=="Acer*", ATTR{[dmi/id]product_name}=="Extensa*", ATTR{[dmi/id]product_name}=="*5210*|*5220*|*5610*|*5620*|*5720*", RUN+="keymap $name 0xEE screenlock"
104ENV{DMI_VENDOR}=="Acer*", ATTR{[dmi/id]product_name}=="TravelMate*C3[01]0*", RUN+="keymap $name acer-travelmate_c300"
105ENV{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"
106ENV{DMI_VENDOR}=="Acer*", ATTR{[dmi/id]product_name}=="TravelMate*4720*", RUN+="keymap $name 0xB2 www 0xEE screenlock"
107ENV{DMI_VENDOR}=="Acer*", ATTR{[dmi/id]product_name}=="TravelMate 6593|Aspire 1640", RUN+="keymap $name 0xB2 www 0xEE screenlock"
108ENV{DMI_VENDOR}=="Acer*", ATTR{[dmi/id]product_name}=="Aspire 6920", RUN+="keymap $name acer-aspire_6920"
109ENV{DMI_VENDOR}=="Acer*", ATTR{[dmi/id]product_name}=="Aspire 5920G", RUN+="keymap $name acer-aspire_5920g"
110ENV{DMI_VENDOR}=="Acer*", ATTR{[dmi/id]product_name}=="Aspire 5720*", RUN+="keymap $name acer-aspire_5720"
111ENV{DMI_VENDOR}=="Acer*", ATTR{[dmi/id]product_name}=="Aspire 8930", RUN+="keymap $name acer-aspire_8930"
112ENV{DMI_VENDOR}=="Acer*", ATTR{[dmi/id]product_serial}=="ZG8*", RUN+="keymap $name acer-aspire_5720"
113
114ENV{DMI_VENDOR}=="*BenQ*", ATTR{[dmi/id]product_name}=="*Joybook R22*", RUN+="keymap $name 0x6E wlan"
115
116ENV{DMI_VENDOR}=="FUJITSU*", ATTR{[dmi/id]product_name}=="*AMILO Pro V3205*", RUN+="keymap $name fujitsu-amilo_pro_v3205"
117ENV{DMI_VENDOR}=="FUJITSU*", ATTR{[dmi/id]product_name}=="*AMILO Pa 2548*", RUN+="keymap $name fujitsu-amilo_pa_2548"
118ENV{DMI_VENDOR}=="FUJITSU*", ATTR{[dmi/id]product_name}=="*ESPRIMO Mobile V5*", RUN+="keymap $name fujitsu-esprimo_mobile_v5"
119ENV{DMI_VENDOR}=="FUJITSU*", ATTR{[dmi/id]product_name}=="*ESPRIMO Mobile V6*", RUN+="keymap $name fujitsu-esprimo_mobile_v6"
120ENV{DMI_VENDOR}=="FUJITSU*", ATTR{[dmi/id]product_name}=="*AMILO Pro Edition V3505*", RUN+="keymap $name fujitsu-amilo_pro_edition_v3505"
121ENV{DMI_VENDOR}=="FUJITSU*", ATTR{[dmi/id]product_name}=="*Amilo Si 1520*", RUN+="keymap $name fujitsu-amilo_si_1520"
122ENV{DMI_VENDOR}=="FUJITSU*", ATTR{[dmi/id]product_name}=="AMILO*M*", RUN+="keymap $name 0x97 prog2 0x9F prog1"
123ENV{DMI_VENDOR}=="FUJITSU*", ATTR{[dmi/id]product_name}=="Amilo Li 1718", RUN+="keymap $name 0xD6 wlan"
124ENV{DMI_VENDOR}=="FUJITSU*", ATTR{[dmi/id]product_name}=="AMILO Li 2732", RUN+="keymap $name fujitsu-amilo_li_2732"
125
126ENV{DMI_VENDOR}=="LG*", ATTR{[dmi/id]product_name}=="*X110*", RUN+="keymap $name lg-x110"
127
128ENV{DMI_VENDOR}=="MEDION*", ATTR{[dmi/id]product_name}=="*FID2060*", RUN+="keymap $name medion-fid2060"
129ENV{DMI_VENDOR}=="MEDIONNB", ATTR{[dmi/id]product_name}=="A555*", RUN+="keymap $name medionnb-a555"
130
131ENV{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
136ENV{DMI_VENDOR}=="MICRO-STAR*", ATTR{[dmi/id]product_name}=="*U-100*|*U100*|*N033", RUN+="keymap $name 0xF7 reserved 0xF8 reserved"
137
138ENV{DMI_VENDOR}=="INVENTEC", ATTR{[dmi/id]product_name}=="SYMPHONY 6.0/7.0", RUN+="keymap $name inventec-symphony_6.0_7.0"
139
140ENV{DMI_VENDOR}=="MAXDATA", ATTR{[dmi/id]product_name}=="Pro 7000*", RUN+="keymap $name maxdata-pro_7000"
141
142ENV{DMI_VENDOR}=="[sS][aA][mM][sS][uU][nN][gG]*", RUN+="keymap $name samsung-other"
143ENV{DMI_VENDOR}=="[sS][aA][mM][sS][uU][nN][gG]*", ATTR{[dmi/id]product_name}=="*SX20S*", RUN+="keymap $name samsung-sx20s"
144ENV{DMI_VENDOR}=="[sS][aA][mM][sS][uU][nN][gG]*", ATTR{[dmi/id]product_name}=="SQ1US", RUN+="keymap $name samsung-sq1us"
145ENV{DMI_VENDOR}=="[sS][aA][mM][sS][uU][nN][gG]*", ATTR{[dmi/id]product_name}=="*700Z*", RUN+="keymap $name 0xBA ejectcd 0x96 keyboardbrightnessup 0x97 keyboardbrightnessdown"
146ENV{DMI_VENDOR}=="[sS][aA][mM][sS][uU][nN][gG]*", ATTR{[dmi/id]product_name}=="*90X3A*", RUN+="keymap $name samsung-90x3a"
147
148ENV{DMI_VENDOR}=="TOSHIBA", ATTR{[dmi/id]product_name}=="SATELLITE A100", RUN+="keymap $name toshiba-satellite_a100"
149ENV{DMI_VENDOR}=="TOSHIBA", ATTR{[dmi/id]product_name}=="Satellite A110", RUN+="keymap $name toshiba-satellite_a110"
150ENV{DMI_VENDOR}=="TOSHIBA", ATTR{[dmi/id]product_name}=="Satellite M30X", RUN+="keymap $name toshiba-satellite_m30x"
151
152ENV{DMI_VENDOR}=="OQO Inc.*", ATTR{[dmi/id]product_name}=="OQO Model 2*", RUN+="keymap $name oqo-model2"
153
154ENV{DMI_VENDOR}=="ONKYO CORPORATION", ATTR{[dmi/id]product_name}=="ONKYOPC", RUN+="keymap $name onkyo"
155
156ENV{DMI_VENDOR}=="ASUS", RUN+="keymap $name asus"
157
158ENV{DMI_VENDOR}=="VIA", ATTR{[dmi/id]product_name}=="K8N800", ATTR{[dmi/id]product_version}=="VT8204B", RUN+="keymap $name 0x81 prog1"
159
160ENV{DMI_VENDOR}=="Zepto", ATTR{[dmi/id]product_name}=="Znote", ATTR{[dmi/id]product_version}=="62*|63*", RUN+="keymap $name zepto-znote"
161
162ENV{DMI_VENDOR}=="Everex", ATTR{[dmi/id]product_name}=="XT5000*", RUN+="keymap $name everex-xt5000"
163
164ENV{DMI_VENDOR}=="COMPAL", ATTR{[dmi/id]product_name}=="HEL80I", RUN+="keymap $name 0x84 wlan"
165
166ENV{DMI_VENDOR}=="OLPC", ATTR{[dmi/id]product_name}=="XO", RUN+="keymap $name olpc-xo"
167
168ENV{DMI_VENDOR}=="Alienware*", ATTR{[dmi/id]product_name}=="M14xR1", RUN+="keymap $name 0x8A ejectcd"
169
170LABEL="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
5This udev extension configures computer model specific key mappings. This is
6particularly necessary for the non-standard extra keys found on many laptops,
7such as "brightness up", "next song", "www browser", or "suspend". Often these
8are accessed with the Fn key.
9
10Every key produces a "scan code", which is highly vendor/model specific for the
11nonstandard 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
13in /usr/include/linux/input.h.
14
15If some of your keys on your keyboard are not working at all, or produce the
16wrong effect, then a very likely cause of this is that the scan code -> key
17code mapping is incorrect on your computer.
18
19== Structure ==
20
21udev-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
42In order to make a broken key work on your system and send it back to upstream
43for 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
90For local testing, copy your map file to /usr/lib/udev/keymaps/ with an appropriate
91name, 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
101keymap 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
6SRCDIR=${1:-.}
7KEYLIST=${2:-src/keymap/keys.txt}
8KEYMAPS_DIR=$SRCDIR/src/keymap/keymaps
9RULES=$SRCDIR/src/keymap/95-keymap.rules
10
11[ -e "$KEYLIST" ] || {
12 echo "need $KEYLIST please build first" >&2
13 exit 1
14}
15
16missing=$(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
25maps=$(sed -rn '/keymap \$name/ { s/^.*\$name ([^"[:space:]]+).*$/\1/; p }' $RULES)
26for 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 }
38done
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
18strstr() {
19 [ "${1#*$2*}" != "$1" ]
20}
21
22# returns OK if $1 contains $2 at the beginning
23str_starts() {
24 [ "${1#$2*}" != "$1" ]
25}
26
27str_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
33keyboard_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
68keyboard_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 @@
10xa0 #mute
20xae #volume down
30xb0 #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
20xd8 # Touchpad off
30xd9 # 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
20xCE # Fn+F8 keyboard backlit up
30x8D # Fn+F7 keyboard backlit down
40x97 # Fn+F12 wifi on/off
50x96 # Fn+F1 performance mode (?)
60xD5 # 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
20x82 # Fn+F4 CRT/LCD
30x83 # Fn+F2 battery
40x84 # Fn+F5 backlight on/off
50x86 # Fn+F9 WLAN
60x88 # Fn-Up brightness up
70x89 # Fn-Down brightness down
80xB3 # Fn+F8 switch power mode (battery/dynamic/performance)
90xF7 # Fn+F10 Touchpad on
100xF9 # 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
7case "$2" in
8 /*) scf="$2" ;;
9 *) scf="@pkglibexecdir@/keymaps/force-release/$2" ;;
10esac
11
12read attr <"/sys/$1/force_release"
13while read scancode dummy; do
14 case "$scancode" in
15 \#*) ;;
16 *)
17 scancode=$(($scancode))
18 attr="$attr${attr:+,}$scancode"
19 ;;
20 esac
21done <"$scf"
22echo "$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
39const 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
46static 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
63static 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
79static 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
93static 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
106static 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 */
116static 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
127static 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 }
155fail:
156 return r;
157}
158
159static 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
187static 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 }
237fail:
238 fclose(f);
239 return r;
240}
241
242
243/* read one event; return 1 if valid */
244static 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
261static 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
287static 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
348static 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
362int 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 @@
10xA5 help # Fn+F1
20xA6 setup # Fn+F2 Acer eSettings
30xA7 battery # Fn+F3 Power Management
40xA9 switchvideomode # Fn+F5
50xB3 euro
60xB4 dollar
70xCE brightnessup # Fn+Right
80xD4 bluetooth # (toggle) off-to-on
90xD5 wlan # (toggle) on-to-off
100xD6 wlan # (toggle) off-to-on
110xD7 bluetooth # (toggle) on-to-off
120xD8 bluetooth # (toggle) off-to-on
130xD9 brightnessup # Fn+Right
140xEE brightnessup # Fn+Right
150xEF brightnessdown # Fn+Left
160xF1 f22 # Fn+F7 Touchpad toggle (off-to-on)
170xF2 f23 # Fn+F7 Touchpad toggle (on-to-off)
180xF3 prog2 # "P2" programmable button
190xF4 prog1 # "P1" programmable button
200xF5 presentation
210xF8 fn
220xF9 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 @@
10x84 bluetooth # sent when bluetooth module missing, and key pressed
20x92 media # acer arcade
30xD4 bluetooth # bluetooth on
40xD9 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 @@
10x8A media
20x92 media
30xA6 setup
40xB2 www
50xD9 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 @@
10xD9 bluetooth # (toggle) on-to-off
20x92 media
30x9E back
40x83 rewind
50x89 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 @@
10xCA prog3 # key 'HOLD' on cine dash media console
20x83 rewind
30x89 fastforward
40x92 media # key 'ARCADE' on cine dash media console
50x9E 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 @@
10x67 f24 # FIXME: rotate screen
20x68 up
30x69 down
40x6B fn
50x6C 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 @@
10xED volumeup
20xEE volumedown
30xEF 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 @@
10xA3 www # I key
20x9A search
30x9E email
40x9F 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 @@
10x81 playpause # Play/Pause
20x82 stopcd # Stop
30x83 previoussong # Previous song
40x84 nextsong # Next song
50x85 brightnessdown # Fn+Down arrow Brightness Down
60x86 brightnessup # Fn+Up arrow Brightness Up
70x87 battery # Fn+F3 battery icon
80x88 unknown # Fn+F2 Turn On/Off Wireless - handled in hardware
90x89 ejectclosecd # Fn+F10 Eject CD
100x8A suspend # Fn+F1 hibernate
110x8B switchvideomode # Fn+F8 CRT/LCD (high keycode: "displaytoggle")
120x8C f23 # Fn+Right arrow Auto Brightness
130x8F switchvideomode # Fn+F7 aspect ratio
140x90 previoussong # Front panel previous song
150x91 prog1 # Wifi Catcher (DELL Specific)
160x92 media # MediaDirect button (house icon)
170x93 f23 # FIXME Fn+Left arrow Auto Brightness
180x95 camera # Shutter button Takes a picture if optional camera available
190x97 email # Tablet email button
200x98 f21 # FIXME: Tablet screen rotatation
210x99 nextsong # Front panel next song
220x9A setup # Tablet tools button
230x9B switchvideomode # Display Toggle button
240x9E f21 #touchpad toggle
250xA2 playpause # Front panel play/pause
260xA4 stopcd # Front panel stop
270xED media # MediaDirect button
280xD8 screenlock # FIXME: Tablet lock button
290xD9 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 @@
10x9B up # tablet rocker up
20x9E enter # tablet rocker press
30x9F back # tablet back
40xA3 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 @@
10x5C media
20x65 f21 # Fn+F5 Touchpad toggle
30x67 prog3 # Fan Speed Control button
40x6F brightnessup
50x7F brightnessdown
60xB2 www
70xEC 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 @@
10xD9 brightnessdown # Fn+F8 brightness down
20xEF brightnessup # Fn+F9 brightness up
30xA9 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 @@
10xE0 volumedown
20xE1 volumeup
30xE5 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 @@
10xA5 help # Fn-F1
20xA9 switchvideomode # Fn-F3
30xD9 brightnessdown # Fn-F8
40xE0 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 @@
10xF4 f21 # FIXME: silent-mode decrease CPU/GPU clock
20xF7 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 @@
10xE1 wlan
20xF3 wlan
30xEE brightnessdown
40xE0 brightnessup
50xE2 bluetooth
60xF7 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 @@
10xA9 switchvideomode
20xD9 brightnessdown
30xDF sleep
40xEF 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 @@
10xCE brightnessup
20xEF 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.
70x900f0 scrollup
80x900f1 scrolldown
90x900f3 back
100x900f2 forward
11
12# Multimedia buttons, left side (from left to right)
13# [W]
140x900f5 wordprocessor
15# [Ex]
160x900f6 spreadsheet
17# [P]
180x900f4 presentation
19# Other five (calculator, playpause, stop, mute and eject) are OK
20
21# Right side, from left to right
22# [e]
230xc0223 www
24# "man"
250x900f7 chat
26# "Y"
270x900fb prog1
28# [X]
290x900f8 close
30# "picture"
310x900f9 graphicseditor
32# "two windows"
330x900fd scale
34# "lock"
350x900fc 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 @@
10x81 fn_esc
20x89 battery # FnF8
30x8A screenlock # FnF6
40x8B camera
50x8C media # music
60x8E dvd
70xB1 help
80xB3 f23 # FIXME: Auto brightness
90xD7 wlan
100x92 brightnessdown # FnF7 (FnF9 on 6730b)
110x97 brightnessup # FnF8 (FnF10 on 6730b)
120xEE 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 @@
10xD8 f23 # touchpad off
20xD9 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 @@
10x88 presentation
20xD9 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 @@
10x88 media # FIXME: quick play
20xD8 f23 # touchpad off
30xD9 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 @@
10xF0 help
20xF1 screenlock
30xF3 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 @@
10x82 prog2 # Funny Key
20x83 prog1 # Q
30x84 tab
40x85 esc
50x86 pageup
60x87 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 @@
10xC2 media
20xD8 f23 # Toggle touchpad button on tx2 (OFF)
30xD9 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 @@
10x900f0 screenlock
20x900f1 wlan
30x900f2 switchvideomode
40x900f3 suspend
50x900f4 brightnessup
60x900f5 brightnessdown
70x900f8 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 @@
10xF3 prog2
20xF4 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 @@
10x8B switchvideomode # Fn+F7 video
20x96 wlan # Fn+F5 wireless
30x97 sleep # Fn+F4 suspend
40x98 suspend # Fn+F12 hibernate
50xB4 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
20x81 rfkill # does nothing in BIOS
30x83 display_off # BIOS toggles screen state
40xB9 brightnessup # does nothing in BIOS
50xBA brightnessdown # does nothing in BIOS
60xF1 camera # BIOS toggles camera power
70xf2 f21 # touchpad toggle (key alternately emits f2 and f3)
80xf3 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 @@
10x90012 screenlock # Fn+F2
20x90013 battery # Fn+F3
30x90014 wlan # Fn+F5
40x90016 switchvideomode # Fn+F7
50x90017 f21 # Fn+F8 touchpadtoggle
60x90019 suspend # Fn+F12
70x9001A brightnessup # Fn+Home
80x9001B brightnessdown # Fn+End
90x9001D zoom # Fn+Space
100x90011 prog1 # Thinkvantage button
11
120x90015 camera # Fn+F6 headset/camera VoIP key ??
130x90010 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 @@
10x5D menu
20x63 fn
30x66 screenlock
40x67 cyclewindows # bezel circular arrow
50x68 setup # bezel setup / menu
60x6c 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 @@
10x6C f21 # rotate
20x68 screenlock # screenlock
30x6B esc # escape
40x6D right # right on d-pad
50x6E left # left on d-pad
60x71 up # up on d-pad
70x6F down # down on d-pad
80x69 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 @@
10xA0 mute # Fn-F9
20xAE volumedown # Fn-Left
30xAF search # Fn-F3
40xB0 volumeup # Fn-Right
50xB1 battery # Fn-F10 Info
60xB3 suspend # Fn-F12
70xDF sleep # Fn-F4
8# 0xE2 bluetooth # satellite dish2
90xE4 f21 # Fn-F5 Touchpad disable
100xF6 wlan # Fn-F6
110xF7 reserved # brightnessdown # Fn-Down
120xF8 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 @@
10x9001C scale #expo
20x9001F zoomout #zoom out
30x90020 zoomin #zoom in
40x9003D prog1 #gadget
50x90005 camera #camera
60x90018 media #media center
70x90041 wordprocessor #fn+f1 (word)
80x90042 spreadsheet #fn+f2 (excel)
90x90043 calendar #fn+f3 (calendar)
100x90044 prog2 #fn+f4 (program a)
110x90045 prog3 #fn+f5 (program b)
120x90046 prog4 #fn+f6 (program c)
130x90048 messenger #fn+f8 (msn messenger)
140x9002D find #fn+f10 (search www)
150x9004B search #fn+f11 (search pc)
160x9004C 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 @@
10xD4 zoomin
20xCC zoomout
30xC0183 media
40xC1005 camera
50xC101F zoomout
60xC1020 zoomin
70xC1041 wordprocessor
80xC1042 spreadsheet
90xC1043 calendar
100xC1044 prog2 #fn+f4 (program a)
110xC1045 prog3 #fn+f5 (program b)
120xC1046 prog4 #fn+f6 (program c)
130xC1048 messenger
140xC104A find #fn+f10 (search www)
150xC104C 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 @@
10xC01B6 camera
20xC0183 media
30xC0184 wordprocessor
40xC0186 spreadsheet
50xC018E calendar
60xC0223 homepage
70xC01BC messenger
80xC018A mail
90xC0221 search
100xC00B8 ejectcd
110xC022D zoomin
120xC022E 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 @@
10x97 prog2
20x9F prog1
30xA0 mute # Fn-F5
40x82 www
50xEC email
60xAE volumedown # Fn-Down
70xB0 volumeup # Fn-Up
80xDF suspend # Fn+F2
90xF5 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 @@
10x6B channeldown # Thottle Down
20x6D 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 @@
10x63 www # N button
20x66 prog1 # link 1 button
30x67 email # envelope button
40x69 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 @@
10xA0 mute # Fn-F9
20xAE volumedown # Fn-F7
30xB0 volumeup # Fn-F8
40xB2 www # e button
50xDF sleep # Fn-F12
60xE2 bluetooth # satellite dish2
70xE4 f21 # Fn-F3 Touchpad disable
80xEC email # envelope button
90xEE camera # Fn-F6 camera disable
100xF6 wlan # satellite dish1
110xF7 brightnessdown # Fn-F4
120xF8 brightnessup # Fn-F5
130xF9 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 @@
10x41 nextsong
20x45 playpause
30x43 stopcd
40x40 previoussong
50x4C ejectclosecd
60x32 mute
70x31 volumedown
80x30 volumeup
90x5D wlan
100x7E bluetooth
110x8A 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 @@
10x01 battery # Fn+F2
20x02 screenlock # Fn+F3
30x03 sleep # Fn+F4
40x04 wlan # Fn+F5
50x06 switchvideomode # Fn+F7
60x07 zoom # Fn+F8 screen expand
70x08 f24 # Fn+F9 undock
80x0B suspend # Fn+F12
90x0F brightnessup # Fn+Home
100x10 brightnessdown # Fn+End
110x11 kbdillumtoggle # Fn+PgUp - ThinkLight
120x13 zoom # Fn+Space
130x14 volumeup
140x15 volumedown
150x16 mute
160x17 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 @@
10x1 screenlock # Fn+F2
20x2 battery # Fn+F3
30x3 sleep # Fn+F4
40x4 wlan # Fn+F5
50x6 switchvideomode # Fn+F7
60x7 f21 # Fn+F8 touchpadtoggle
70x8 f24 # Fn+F9 undock
80xB suspend # Fn+F12
90xF brightnessup # Fn+Home
100x10 brightnessdown # Fn+End
110x11 kbdillumtoggle # Fn+PgUp - ThinkLight
120x13 zoom # Fn+Space
130x14 volumeup
140x15 volumedown
150x16 mute
160x17 prog1 # ThinkPad/ThinkVantage button (high keycode: "vendor")
170x1A 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 @@
10x06 mute # Fn+F2
20x07 volumedown # Fn+F3
30x08 volumeup # Fn+F4
40x09 brightnessdown # Fn+F5
50x0A brightnessup # Fn+F6
60x0B switchvideomode # Fn+F7
70x0E zoom # Fn+F10
80x10 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 @@
10x06 battery
20x07 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 @@
10x00 brightnessdown # Fn+F5
20x10 brightnessup # Fn+F6
30x11 switchvideomode # Fn+F7
40x12 zoomout
50x14 zoomin
60x15 suspend # Fn+F12
70x17 prog1
80x20 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 @@
10x59 fn
20x81 fn_esc
30xF9 camera
40xF8 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.
120x43 brightnessdown
130x44 brightnessup
140x57 volumedown
150x58 volumeup
16
17# fn-modified fkeys all produce the unmodified version of the key.
180xBB f1
190xBC f2
200xBD f3
210xBE f4
220xBF f5
230xC0 f6
240xC1 f7
250xC2 f8
260xC3 f9
270xC4 f10
280xD7 f11
290xD8 f12
30
31
32# Using F13-F21 for the .5 F keys right now.
330xF7 f13
340xF6 f14
350xF5 f15
360xF4 f16
370xF3 f17
380xF2 f18
390xF1 f19
400xF0 f20
410xEF f21
42
430xEE chat
440xE4 chat # Just mapping Fn-Chat to Chat for now
450xDD menu # Frame
460xDA prog1 # Fn-Frame
47
48# The FN of some keys is other keys
490xD3 delete
500xD2 insert
510xC9 pageup
520xD1 pagedown
530xC7 home
540xCF end
55
56# Language key - don't ask what they are doing as KEY_HP
570x73 hp
580x7E hp
59
600xDB leftmeta # left grab
610xDC rightmeta # right grab
620x85 rightmeta # Right grab releases on a different scancode
630xD6 kbdillumtoggle # Fn-space
640x69 switchvideomode # Brightness key
65
66# Game keys
670x65 kp8 # up
680x66 kp2 # down
690x67 kp4 # left
700x68 kp6 # right
710xE5 kp9 # pgup
720xE6 kp3 # pgdn
730xE7 kp7 # home
740xE8 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 @@
10xA0 mute # Fn+D
20xAE volumedown # Fn+F
30xB0 volumeup # Fn+G
40xDF sleep # Fn+W
50xE0 bluetooth # Fn+H
60xE2 cyclewindows # Fn+Esc
70xEE battery # Fn+Q
80xF0 media # Fn+R
90xF5 switchvideomode # Fn+E
100xF6 camera # Fn+T
110xF7 f21 # Fn+Y (touchpad toggle)
120xF8 brightnessup # Fn+S
130xF9 brightnessdown # Fn+A
140xFB 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 @@
10x8E wlan
20xF0 switchvideomode
30xF1 mute
40xF2 volumedown
50xF3 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 @@
10x96 kbdillumup         # Fn+F8 keyboard backlit up
20x97 kbdillumdown       # Fn+F7 keyboard backlit down
30xD5 wlan               # Fn+F12 wifi on/off
40xCE prog1              # Fn+F1 performance mode
50x8D 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 @@
10x74 prog1 # User key
20x75 www
30x78 mail
40x82 switchvideomode # Fn+F4 CRT/LCD (high keycode: "displaytoggle")
50x83 battery # Fn+F2
60x84 prog1 # Fn+F5 backlight on/off
70x86 wlan # Fn+F9
80x88 brightnessup # Fn-Up
90x89 brightnessdown # Fn-Down
100xB1 prog2 # Fn+F7 run Samsung Magic Doctor (keypressed event is generated twice)
110xB3 prog3 # Fn+F8 switch power mode (battery/dynamic/performance)
120xB4 wlan # Fn+F9 (X60P)
130xF7 f22 # Fn+F10 Touchpad on
140xF9 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 @@
10xD4 menu
20xD8 f1
30xD9 f10
40xD6 f3
50xD7 f9
60xE4 f5
70xEE 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 @@
10x74 mute
20x75 mute
30x77 f22 # Touchpad on
40x79 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 @@
10xA4 stopcd
20xB2 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 @@
10x92 stop
20x93 www
30x94 media
40x9E f22 # Touchpad on
50x9F f23 # Touchpad off
60xB9 nextsong
70xD9 brightnessup
80xEE screenlock
90xF4 previoussong
100xF7 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 @@
10xef brightnessdown
20xd9 brightnessup
30xee screenlock
40x93 media
50x9e f22 #touchpad_enable
60x9f 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 @@
10x93 switchvideomode # Fn+F3 Toggle Video Output
20x95 brightnessdown # Fn+F4 Brightness Down
30x91 brightnessup # Fn+F5 Brightness Up
40xA5 f23 # Fn+F6 Disable Touchpad
50xA6 f22 # Fn+F6 Enable Touchpad
60xA7 bluetooth # Fn+F10 Enable Bluetooth
70XA9 bluetooth # Fn+F10 Disable Bluetooth
80xF1 wlan # RF Switch Off
90xF2 wlan # RF Switch On
100xF4 prog1 # P1 Button
110xF3 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
25static 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
48int 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
79static 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
97int 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
173int 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 */
46struct 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 **/
101UDEV_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
108static 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
118int 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
125static 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 **/
141UDEV_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
150static 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
163const char *udev_device_get_devpath_old(struct udev_device *udev_device)
164{
165 return udev_device->devpath_old;
166}
167
168static 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 **/
190UDEV_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
204static 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 **/
223UDEV_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
234static 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
245static 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 **/
265UDEV_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
297mode_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
304static 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
314struct 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
329static 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 */
354void 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
426int 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 **/
445UDEV_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
459int 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
526int 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
579void udev_device_set_info_loaded(struct udev_device *device)
580{
581 device->info_loaded = true;
582}
583
584struct 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 **/
626UDEV_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 **/
702UDEV_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
720struct 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 **/
790UDEV_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;
854out:
855 return NULL;
856found:
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 **/
874UDEV_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
896static 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 **/
937UDEV_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 **/
972UDEV_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 **/
1005UDEV_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 **/
1020UDEV_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 **/
1036UDEV_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 **/
1074UDEV_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 **/
1090UDEV_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 **/
1103UDEV_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 **/
1116UDEV_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 **/
1132UDEV_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 **/
1156UDEV_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
1165void 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 **/
1183UDEV_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 **/
1236UDEV_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 **/
1255UDEV_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
1271unsigned long long udev_device_get_usec_initialized(struct udev_device *udev_device)
1272{
1273 return udev_device->usec_initialized;
1274}
1275
1276void 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 **/
1295UDEV_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);
1385out:
1386 return val;
1387}
1388
1389static 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 **/
1442UDEV_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
1454int 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
1492int 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
1507int 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
1520const 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 **/
1567UDEV_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
1574void udev_device_set_is_initialized(struct udev_device *udev_device)
1575{
1576 udev_device->is_initialized = true;
1577}
1578
1579int 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
1589void 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 **/
1606UDEV_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
1615UDEV_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
1631static 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
1683char **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
1691ssize_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
1700int 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
1710int 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
1717int udev_device_set_devlink_priority(struct udev_device *udev_device, int prio)
1718{
1719 udev_device->devlink_priority = prio;
1720 return 0;
1721}
1722
1723int 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
1730int udev_device_set_watch_handle(struct udev_device *udev_device, int handle)
1731{
1732 udev_device->watch_handle = handle;
1733 return 0;
1734}
1735
1736bool udev_device_get_db_persist(struct udev_device *udev_device)
1737{
1738 return udev_device->db_persist;
1739}
1740
1741void 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
35struct 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 */
45struct 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 **/
70UDEV_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 **/
98UDEV_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 **/
113UDEV_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 */
143UDEV_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
150static 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
181static 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 */
200static 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 */
223static 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 */
252UDEV_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 */
330UDEV_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 */
348UDEV_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 */
367UDEV_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 */
386UDEV_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
397static 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 }
413exit:
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 */
425UDEV_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 */
443UDEV_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 */
467UDEV_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 */
497UDEV_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 */
512UDEV_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
523static 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
546static 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 }
580out:
581 return match;
582}
583
584static 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
600static 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
611static 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
626static 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));
685nomatch:
686 udev_device_unref(dev);
687 }
688 closedir(dir);
689 return 0;
690}
691
692static 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
710static 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 */
742UDEV_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
759static 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));
797nomatch:
798 udev_device_unref(dev);
799 }
800 closedir(dir);
801 }
802 return 0;
803}
804
805static 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
827static 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
855static 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
864static 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 **/
890UDEV_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 **/
913UDEV_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 */
35struct 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 */
44void udev_list_node_init(struct udev_list_node *list)
45{
46 list->next = list;
47 list->prev = list;
48}
49
50int udev_list_node_is_empty(struct udev_list_node *list)
51{
52 return list->next == list;
53}
54
55static 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
65void 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
70void 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 */
83static 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
92void 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 */
101void 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 */
109void 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 */
116static 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
140struct 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
223void 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
244void 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
257struct 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 */
270UDEV_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 */
290UDEV_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 */
312UDEV_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 */
325UDEV_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
332int 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
339void 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 */
42struct 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
56enum udev_monitor_netlink_group {
57 UDEV_MONITOR_NONE,
58 UDEV_MONITOR_KERNEL,
59 UDEV_MONITOR_UDEV,
60};
61
62#define UDEV_MONITOR_MAGIC 0xfeedcafe
63struct 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
86static 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 **/
125UDEV_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
164struct 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 **/
230UDEV_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
235static 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
245static 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 */
267UDEV_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
366int 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 */
379UDEV_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 */
436UDEV_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
443int 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 **/
460UDEV_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 **/
477UDEV_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 **/
500UDEV_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 **/
515UDEV_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
522static 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
548tag:
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 **/
574UDEV_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
588retry:
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
713int 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 */
826UDEV_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 */
849UDEV_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 */
868UDEV_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
25static inline void __attribute__((always_inline, format(printf, 2, 3)))
26udev_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
50static inline void udev_log_init(const char *program_name)
51{
52 openlog(program_name, LOG_PID | LOG_CONS, LOG_DAEMON);
53}
54
55static inline void udev_log_close(void)
56{
57 closelog();
58}
59
60/* libudev.c */
61void 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)));
65int udev_get_rules_path(struct udev *udev, char **path[], unsigned long long *ts_usec[]);
66struct udev_list_entry *udev_add_property(struct udev *udev, const char *key, const char *value);
67struct udev_list_entry *udev_get_properties_list_entry(struct udev *udev);
68
69/* libudev-device.c */
70struct udev_device *udev_device_new(struct udev *udev);
71struct udev_device *udev_device_new_from_id_filename(struct udev *udev, char *id);
72mode_t udev_device_get_devnode_mode(struct udev_device *udev_device);
73int udev_device_set_syspath(struct udev_device *udev_device, const char *syspath);
74int udev_device_set_devnode(struct udev_device *udev_device, const char *devnode);
75int udev_device_add_devlink(struct udev_device *udev_device, const char *devlink, int unique);
76void udev_device_cleanup_devlinks_list(struct udev_device *udev_device);
77struct udev_list_entry *udev_device_add_property(struct udev_device *udev_device, const char *key, const char *value);
78void udev_device_add_property_from_string_parse(struct udev_device *udev_device, const char *property);
79int udev_device_add_property_from_string_parse_finish(struct udev_device *udev_device);
80char **udev_device_get_properties_envp(struct udev_device *udev_device);
81ssize_t udev_device_get_properties_monitor_buf(struct udev_device *udev_device, const char **buf);
82int udev_device_read_db(struct udev_device *udev_device, const char *dbfile);
83int udev_device_read_uevent_file(struct udev_device *udev_device);
84int udev_device_set_action(struct udev_device *udev_device, const char *action);
85const char *udev_device_get_devpath_old(struct udev_device *udev_device);
86const char *udev_device_get_id_filename(struct udev_device *udev_device);
87void udev_device_set_is_initialized(struct udev_device *udev_device);
88int udev_device_add_tag(struct udev_device *udev_device, const char *tag);
89void udev_device_cleanup_tags_list(struct udev_device *udev_device);
90unsigned long long udev_device_get_usec_initialized(struct udev_device *udev_device);
91void udev_device_set_usec_initialized(struct udev_device *udev_device, unsigned long long usec_initialized);
92int udev_device_get_devlink_priority(struct udev_device *udev_device);
93int udev_device_set_devlink_priority(struct udev_device *udev_device, int prio);
94int udev_device_get_watch_handle(struct udev_device *udev_device);
95int udev_device_set_watch_handle(struct udev_device *udev_device, int handle);
96int udev_device_get_ifindex(struct udev_device *udev_device);
97void udev_device_set_info_loaded(struct udev_device *device);
98bool udev_device_get_db_persist(struct udev_device *udev_device);
99void udev_device_set_db_persist(struct udev_device *udev_device);
100
101/* libudev-device-private.c */
102int udev_device_update_db(struct udev_device *udev_device);
103int udev_device_delete_db(struct udev_device *udev_device);
104int udev_device_tag_index(struct udev_device *dev, struct udev_device *dev_old, bool add);
105
106/* libudev-monitor.c - netlink/unix socket communication */
107int udev_monitor_disconnect(struct udev_monitor *udev_monitor);
108int udev_monitor_allow_unicast_sender(struct udev_monitor *udev_monitor, struct udev_monitor *sender);
109int udev_monitor_send_device(struct udev_monitor *udev_monitor,
110 struct udev_monitor *destination, struct udev_device *udev_device);
111struct udev_monitor *udev_monitor_new_from_netlink_fd(struct udev *udev, const char *name, int fd);
112
113/* libudev-list.c */
114struct udev_list_node {
115 struct udev_list_node *next, *prev;
116};
117struct 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) }
126void udev_list_node_init(struct udev_list_node *list);
127int udev_list_node_is_empty(struct udev_list_node *list);
128void udev_list_node_append(struct udev_list_node *new, struct udev_list_node *list);
129void 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)
138void udev_list_init(struct udev *udev, struct udev_list *list, bool unique);
139void udev_list_cleanup(struct udev_list *list);
140struct udev_list_entry *udev_list_get_entry(struct udev_list *list);
141struct udev_list_entry *udev_list_entry_add(struct udev_list *list, const char *name, const char *value);
142void udev_list_entry_delete(struct udev_list_entry *entry);
143void udev_list_entry_insert_before(struct udev_list_entry *new, struct udev_list_entry *entry);
144void udev_list_entry_append(struct udev_list_entry *new, struct udev_list *list);
145int udev_list_entry_get_num(struct udev_list_entry *list_entry);
146void 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 */
153unsigned long long int udev_get_kernel_seqnum(struct udev *udev);
154int udev_queue_read_seqnum(FILE *queue_file, unsigned long long int *seqnum);
155ssize_t udev_queue_read_devpath(FILE *queue_file, char *devpath, size_t size);
156ssize_t udev_queue_skip_devpath(FILE *queue_file);
157
158/* libudev-queue-private.c */
159struct udev_queue_export *udev_queue_export_new(struct udev *udev);
160struct udev_queue_export *udev_queue_export_unref(struct udev_queue_export *udev_queue_export);
161void udev_queue_export_cleanup(struct udev_queue_export *udev_queue_export);
162int udev_queue_export_device_queued(struct udev_queue_export *udev_queue_export, struct udev_device *udev_device);
163int 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 "/ $%?,"
170ssize_t util_get_sys_core_link_value(struct udev *udev, const char *slink, const char *syspath, char *value, size_t size);
171int util_resolve_sys_link(struct udev *udev, char *syspath, size_t size);
172int util_log_priority(const char *priority);
173size_t util_path_encode(const char *src, char *dest, size_t size);
174size_t util_path_decode(char *s);
175void util_remove_trailing_chars(char *path, char c);
176size_t util_strpcpy(char **dest, size_t size, const char *src);
177size_t util_strpcpyl(char **dest, size_t size, const char *src, ...) __attribute__((sentinel));
178size_t util_strscpy(char *dest, size_t size, const char *src);
179size_t util_strscpyl(char *dest, size_t size, const char *src, ...) __attribute__((sentinel));
180int util_replace_whitespace(const char *str, char *to, size_t len);
181int util_replace_chars(char *str, const char *white);
182unsigned int util_string_hash32(const char *key);
183uint64_t util_string_bloom64(const char *str);
184
185/* libudev-util-private.c */
186int util_create_path(struct udev *udev, const char *path);
187int util_create_path_selinux(struct udev *udev, const char *path);
188int util_delete_path(struct udev *udev, const char *path);
189uid_t util_lookup_user(struct udev *udev, const char *user);
190gid_t util_lookup_group(struct udev *udev, const char *group);
191int util_resolve_subsys_kernel(struct udev *udev, const char *string,
192 char *result, size_t maxsize, int read_value);
193unsigned long long ts_usec(const struct timespec *ts);
194unsigned long long now_usec(void);
195
196/* libudev-selinux-private.c */
197#ifndef WITH_SELINUX
198static inline void udev_selinux_init(struct udev *udev) {}
199static inline void udev_selinux_exit(struct udev *udev) {}
200static inline void udev_selinux_lsetfilecon(struct udev *udev, const char *file, unsigned int mode) {}
201static inline void udev_selinux_setfscreatecon(struct udev *udev, const char *file, unsigned int mode) {}
202static inline void udev_selinux_setfscreateconat(struct udev *udev, int dfd, const char *file, unsigned int mode) {}
203static inline void udev_selinux_resetfscreatecon(struct udev *udev) {}
204#else
205void udev_selinux_init(struct udev *udev);
206void udev_selinux_exit(struct udev *udev);
207void udev_selinux_lsetfilecon(struct udev *udev, const char *file, unsigned int mode);
208void udev_selinux_setfscreatecon(struct udev *udev, const char *file, unsigned int mode);
209void udev_selinux_setfscreateconat(struct udev *udev, int dfd, const char *file, unsigned int mode);
210void 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
55static int rebuild_queue_file(struct udev_queue_export *udev_queue_export);
56
57struct 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
66struct 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
92struct 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
102void 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
114static 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
131struct 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 */
141static 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
194read_error:
195 err(udev_queue_export->udev, "queue file corrupted\n");
196 free(devpaths);
197 return NULL;
198}
199
200static 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
270error:
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
290static 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
317write_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
327enum device_state {
328 DEVICE_QUEUED,
329 DEVICE_FINISHED,
330};
331
332static 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
337static 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
395static 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
404int 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
409int 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 */
42struct 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 **/
57UDEV_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 **/
81UDEV_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 **/
96UDEV_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 **/
115UDEV_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
122unsigned 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 **/
149UDEV_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
161int 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
169ssize_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
184ssize_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
209static 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 **/
234UDEV_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 **/
266UDEV_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 **/
285UDEV_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
332out:
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 **/
345UDEV_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 **/
407UDEV_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 **/
422UDEV_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
469struct udev_list_entry *udev_queue_get_failed_list_entry(struct udev_queue *udev_queue);
470UDEV_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
22static int selinux_enabled;
23security_context_t selinux_prev_scontext;
24
25void 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
39void 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
47void 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
62void 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
78void 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
86void 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
27static 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
74int util_create_path(struct udev *udev, const char *path)
75{
76 return create_path(udev, path, false);
77}
78
79int util_create_path_selinux(struct udev *udev, const char *path)
80{
81 return create_path(udev, path, true);
82}
83
84int 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
116uid_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
141gid_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 */
182int 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
32ssize_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
52int 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
83int 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
100size_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
132size_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
152void 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 */
168size_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 */
189size_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 */
204size_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 */
213size_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 */
230static 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 */
250static 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 */
290static 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 */
306static 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 */
320static 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
352int 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
380static 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 */
392int 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 **/
446UDEV_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;
479err:
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 */
490static 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
537unsigned 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 */
543uint64_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
557unsigned 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
563unsigned 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 */
38struct 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
54void 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
65static 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 **/
82UDEV_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 **/
96UDEV_EXPORT void udev_set_userdata(struct udev *udev, void *userdata)
97{
98 if (udev == NULL)
99 return;
100 udev->userdata = userdata;
101}
102
103static 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 **/
122UDEV_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;
284err:
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 **/
299UDEV_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 **/
315UDEV_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 **/
343UDEV_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 **/
361UDEV_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 **/
374UDEV_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
383int 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 **/
401UDEV_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 **/
418UDEV_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 **/
433UDEV_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
440struct 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
454struct 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
20extern "C" {
21#endif
22
23/*
24 * udev - library context
25 *
26 * reads the udev config and system environment
27 * allows custom logging
28 */
29struct udev;
30struct udev *udev_ref(struct udev *udev);
31void udev_unref(struct udev *udev);
32struct udev *udev_new(void);
33void 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));
37int udev_get_log_priority(struct udev *udev);
38void udev_set_log_priority(struct udev *udev, int priority);
39const char *udev_get_sys_path(struct udev *udev);
40const char *udev_get_dev_path(struct udev *udev);
41const char *udev_get_run_path(struct udev *udev);
42void *udev_get_userdata(struct udev *udev);
43void udev_set_userdata(struct udev *udev, void *userdata);
44
45/*
46 * udev_list
47 *
48 * access to libudev generated lists
49 */
50struct udev_list_entry;
51struct udev_list_entry *udev_list_entry_get_next(struct udev_list_entry *list_entry);
52struct udev_list_entry *udev_list_entry_get_by_name(struct udev_list_entry *list_entry, const char *name);
53const char *udev_list_entry_get_name(struct udev_list_entry *list_entry);
54const 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 */
72struct udev_device;
73struct udev_device *udev_device_ref(struct udev_device *udev_device);
74void udev_device_unref(struct udev_device *udev_device);
75struct udev *udev_device_get_udev(struct udev_device *udev_device);
76struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *syspath);
77struct udev_device *udev_device_new_from_devnum(struct udev *udev, char type, dev_t devnum);
78struct udev_device *udev_device_new_from_subsystem_sysname(struct udev *udev, const char *subsystem, const char *sysname);
79struct 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 */
81struct udev_device *udev_device_get_parent(struct udev_device *udev_device);
82struct 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 */
85const char *udev_device_get_devpath(struct udev_device *udev_device);
86const char *udev_device_get_subsystem(struct udev_device *udev_device);
87const char *udev_device_get_devtype(struct udev_device *udev_device);
88const char *udev_device_get_syspath(struct udev_device *udev_device);
89const char *udev_device_get_sysname(struct udev_device *udev_device);
90const char *udev_device_get_sysnum(struct udev_device *udev_device);
91const char *udev_device_get_devnode(struct udev_device *udev_device);
92int udev_device_get_is_initialized(struct udev_device *udev_device);
93struct udev_list_entry *udev_device_get_devlinks_list_entry(struct udev_device *udev_device);
94struct udev_list_entry *udev_device_get_properties_list_entry(struct udev_device *udev_device);
95struct udev_list_entry *udev_device_get_tags_list_entry(struct udev_device *udev_device);
96struct udev_list_entry *udev_device_get_sysattr_list_entry(struct udev_device *udev_device);
97const char *udev_device_get_property_value(struct udev_device *udev_device, const char *key);
98const char *udev_device_get_driver(struct udev_device *udev_device);
99dev_t udev_device_get_devnum(struct udev_device *udev_device);
100const char *udev_device_get_action(struct udev_device *udev_device);
101unsigned long long int udev_device_get_seqnum(struct udev_device *udev_device);
102unsigned long long int udev_device_get_usec_since_initialized(struct udev_device *udev_device);
103const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const char *sysattr);
104int 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 */
111struct udev_monitor;
112struct udev_monitor *udev_monitor_ref(struct udev_monitor *udev_monitor);
113void udev_monitor_unref(struct udev_monitor *udev_monitor);
114struct udev *udev_monitor_get_udev(struct udev_monitor *udev_monitor);
115/* kernel and udev generated events over netlink */
116struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, const char *name);
117/* custom socket (use netlink and filters instead) */
118struct udev_monitor *udev_monitor_new_from_socket(struct udev *udev, const char *socket_path);
119/* bind socket */
120int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor);
121int udev_monitor_set_receive_buffer_size(struct udev_monitor *udev_monitor, int size);
122int udev_monitor_get_fd(struct udev_monitor *udev_monitor);
123struct 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 */
125int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_monitor,
126 const char *subsystem, const char *devtype);
127int udev_monitor_filter_add_match_tag(struct udev_monitor *udev_monitor, const char *tag);
128int udev_monitor_filter_update(struct udev_monitor *udev_monitor);
129int 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 */
136struct udev_enumerate;
137struct udev_enumerate *udev_enumerate_ref(struct udev_enumerate *udev_enumerate);
138void udev_enumerate_unref(struct udev_enumerate *udev_enumerate);
139struct udev *udev_enumerate_get_udev(struct udev_enumerate *udev_enumerate);
140struct udev_enumerate *udev_enumerate_new(struct udev *udev);
141/* device properties filter */
142int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem);
143int udev_enumerate_add_nomatch_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem);
144int udev_enumerate_add_match_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value);
145int udev_enumerate_add_nomatch_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value);
146int udev_enumerate_add_match_property(struct udev_enumerate *udev_enumerate, const char *property, const char *value);
147int udev_enumerate_add_match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname);
148int udev_enumerate_add_match_tag(struct udev_enumerate *udev_enumerate, const char *tag);
149int udev_enumerate_add_match_parent(struct udev_enumerate *udev_enumerate, struct udev_device *parent);
150int udev_enumerate_add_match_is_initialized(struct udev_enumerate *udev_enumerate);
151int udev_enumerate_add_syspath(struct udev_enumerate *udev_enumerate, const char *syspath);
152/* run enumeration with active filters */
153int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate);
154int udev_enumerate_scan_subsystems(struct udev_enumerate *udev_enumerate);
155/* return device list */
156struct 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 */
163struct udev_queue;
164struct udev_queue *udev_queue_ref(struct udev_queue *udev_queue);
165void udev_queue_unref(struct udev_queue *udev_queue);
166struct udev *udev_queue_get_udev(struct udev_queue *udev_queue);
167struct udev_queue *udev_queue_new(struct udev *udev);
168unsigned long long int udev_queue_get_kernel_seqnum(struct udev_queue *udev_queue);
169unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *udev_queue);
170int udev_queue_get_udev_is_active(struct udev_queue *udev_queue);
171int udev_queue_get_queue_is_empty(struct udev_queue *udev_queue);
172int udev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, unsigned long long int seqnum);
173int udev_queue_get_seqnum_sequence_is_finished(struct udev_queue *udev_queue,
174 unsigned long long int start, unsigned long long int end);
175struct 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 */
182int 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 @@
1prefix=@prefix@
2exec_prefix=@exec_prefix@
3libdir=@libdir@
4includedir=@includedir@
5
6Name: libudev
7Description: Library to access udev device information
8Version: @VERSION@
9Libs: -L${libdir} -ludev -lrt
10Libs.private:
11Cflags: -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
3ACTION!="add", GOTO="mtd_probe_end"
4
5KERNEL=="mtd*ro", IMPORT{program}="mtd_probe $devnode"
6KERNEL=="mtd*ro", ENV{MTD_FTL}=="smartmedia", IMPORT{builtin}="kmod load sm_ftl"
7
8LABEL="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
29int 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 */
23struct 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
49void 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
32static const uint8_t cis_signature[] = {
33 0x01, 0x03, 0xD9, 0x01, 0xFF, 0x18, 0x02, 0xDF, 0x01, 0x20
34};
35
36
37void 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);
94exit:
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"
4ACTION=="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
7ACTION=="add", SUBSYSTEM=="block", ENV{ID_CDROM}=="?*", ENV{GENERATED}!="?*", PROGRAM="write_cd_rules", SYMLINK+="%c"
8
9LABEL="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
14ACTION!="add", GOTO="persistent_net_generator_end"
15SUBSYSTEM!="net", GOTO="persistent_net_generator_end"
16
17# ignore the interface if a name has already been set
18NAME=="?*", GOTO="persistent_net_generator_end"
19
20# device name whitelist
21KERNEL!="eth*|ath*|wlan*[0-9]|msh*|ra*|sta*|ctc*|lcs*|hsi*", GOTO="persistent_net_generator_end"
22
23# ignore Xen virtual interfaces
24SUBSYSTEMS=="xen", GOTO="persistent_net_generator_end"
25
26# read MAC address
27ENV{MATCHADDR}="$attr{address}"
28
29# match interface type
30ENV{MATCHIFTYPE}="$attr{type}"
31
32# ignore KVM virtual interfaces
33ENV{MATCHADDR}=="52:54:00:*", GOTO="persistent_net_generator_end"
34# ignore VMWare virtual interfaces
35ENV{MATCHADDR}=="00:0c:29:*|00:50:56:*", GOTO="persistent_net_generator_end"
36# ignore Hyper-V virtual interfaces
37ENV{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
41ENV{MATCHADDR}=="02:07:01:*", GOTO="globally_administered_whitelist"
42# 3Com
43ENV{MATCHADDR}=="02:60:60:*", GOTO="globally_administered_whitelist"
44# 3Com IBM PC; Imagen; Valid; Cisco; Apple
45ENV{MATCHADDR}=="02:60:8c:*", GOTO="globally_administered_whitelist"
46# Intel
47ENV{MATCHADDR}=="02:a0:c9:*", GOTO="globally_administered_whitelist"
48# Olivetti
49ENV{MATCHADDR}=="02:aa:3c:*", GOTO="globally_administered_whitelist"
50# CMC Masscomp; Silicon Graphics; Prime EXL
51ENV{MATCHADDR}=="02:cf:1f:*", GOTO="globally_administered_whitelist"
52# Prominet Corporation Gigabit Ethernet Switch
53ENV{MATCHADDR}=="02:e0:3b:*", GOTO="globally_administered_whitelist"
54# BTI (Bus-Tech, Inc.) IBM Mainframes
55ENV{MATCHADDR}=="02:e6:d3:*", GOTO="globally_administered_whitelist"
56# Realtek
57ENV{MATCHADDR}=="52:54:00:*", GOTO="globally_administered_whitelist"
58# Novell 2000
59ENV{MATCHADDR}=="52:54:4c:*", GOTO="globally_administered_whitelist"
60# Realtec
61ENV{MATCHADDR}=="52:54:ab:*", GOTO="globally_administered_whitelist"
62# Kingston Technologies
63ENV{MATCHADDR}=="e2:0c:0f:*", GOTO="globally_administered_whitelist"
64# Xensource
65ENV{MATCHADDR}=="00:16:3e:*", GOTO="globally_administered_whitelist"
66
67# match interface dev_id
68ATTR{dev_id}=="?*", ENV{MATCHDEVID}="$attr{dev_id}"
69
70# do not use "locally administered" MAC address
71ENV{MATCHADDR}=="?[2367abef]:*", ENV{MATCHADDR}=""
72
73# do not use empty address
74ENV{MATCHADDR}=="00:00:00:00:00:00", ENV{MATCHADDR}=""
75
76LABEL="globally_administered_whitelist"
77
78# build comment line for generated rule:
79SUBSYSTEMS=="pci", ENV{COMMENT}="PCI device $attr{vendor}:$attr{device} ($driver)"
80SUBSYSTEMS=="usb", ATTRS{idVendor}=="?*", ENV{COMMENT}="USB device 0x$attr{idVendor}:0x$attr{idProduct} ($driver)"
81SUBSYSTEMS=="pcmcia", ENV{COMMENT}="PCMCIA device $attr{card_id}:$attr{manf_id} ($driver)"
82SUBSYSTEMS=="ieee1394", ENV{COMMENT}="Firewire device $attr{host_id})"
83
84# ibmveth likes to use "locally administered" MAC addresses
85DRIVERS=="ibmveth", ENV{MATCHADDR}="$attr{address}", ENV{COMMENT}="ibmveth ($id)"
86
87# S/390 uses id matches only, do not use MAC address match
88SUBSYSTEMS=="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
91ENV{MATCHADDR}=="", ENV{MATCHID}=="", ENV{INTERFACE_NAME}=="", GOTO="persistent_net_generator_end"
92
93# default comment
94ENV{COMMENT}=="", ENV{COMMENT}="net device ($attr{driver})"
95
96# write rule
97DRIVERS=="?*", IMPORT{program}="write_net_rules"
98
99# rename interface if needed
100ENV{INTERFACE_NEW}=="?*", NAME="$env{INTERFACE_NEW}"
101
102LABEL="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
18PATH='/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.
22sysread() {
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
30sysreadlink() {
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.
37writeable() {
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.
47lock_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
64unlock_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.
71choose_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.
85raw_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.
103find_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>
24if [ -n "$UDEV_LOG" ]; then
25 if [ "$UDEV_LOG" -ge 7 ]; then
26 set -x
27 fi
28fi
29
30RULES_FILE="/etc/udev/rules.d/70-persistent-cd.rules"
31
32. /lib/udev/rule_generator.functions
33
34find_next_available() {
35 raw_find_next_available "$(find_all_rules 'SYMLINK\+=' "$1")"
36}
37
38write_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
60if [ -z "$DEVPATH" ]; then
61 echo "Missing \$DEVPATH." >&2
62 exit 1
63fi
64if [ -z "$ID_CDROM" ]; then
65 echo "$DEVPATH is not a CD reader." >&2
66 exit 1
67fi
68
69if [ "$1" ]; then
70 METHOD="$1"
71else
72 METHOD='by-path'
73fi
74
75case "$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 ;;
99esac
100
101# Prevent concurrent processes from modifying the file at the same time.
102lock_rules_file
103
104# Check if the rules file is writeable.
105choose_rules_file
106
107link_num=$(find_next_available 'cdrom[0-9]*')
108
109match="SUBSYSTEM==\"block\", ENV{ID_CDROM}==\"?*\", $RULE"
110
111comment="$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"
120echo >> $RULES_FILE
121
122unlock_rules_file
123
124echo $SYMLINKS
125
126exit 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>
35if [ -n "$UDEV_LOG" ]; then
36 if [ "$UDEV_LOG" -ge 7 ]; then
37 set -x
38 fi
39fi
40
41RULES_FILE='/etc/udev/rules.d/70-persistent-net.rules'
42
43. /lib/udev/rule_generator.functions
44
45interface_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
54find_next_available() {
55 raw_find_next_available "$(find_all_rules 'NAME=' "$1")"
56}
57
58write_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
79if [ -z "$INTERFACE" ]; then
80 echo "missing \$INTERFACE" >&2
81 exit 1
82fi
83
84# Prevent concurrent processes from modifying the file at the same time.
85lock_rules_file
86
87# Check if the rules file is writeable.
88choose_rules_file
89
90# the DRIVERS key is needed to not match bridges and VLAN sub-interfaces
91if [ "$MATCHADDR" ]; then
92 match="$match, DRIVERS==\"?*\", ATTR{address}==\"$MATCHADDR\""
93fi
94
95if [ "$MATCHDRV" ]; then
96 match="$match, DRIVERS==\"$MATCHDRV\""
97fi
98
99if [ "$MATCHDEVID" ]; then
100 match="$match, ATTR{dev_id}==\"$MATCHDEVID\""
101fi
102
103if [ "$MATCHID" ]; then
104 match="$match, KERNELS==\"$MATCHID\""
105fi
106
107if [ "$MATCHIFTYPE" ]; then
108 match="$match, ATTR{type}==\"$MATCHIFTYPE\""
109fi
110
111if [ -z "$match" ]; then
112 echo "missing valid match" >&2
113 unlock_rules_file
114 exit 1
115fi
116
117basename=${INTERFACE%%[0-9]*}
118match="$match, KERNEL==\"$basename*\""
119
120if [ "$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
127else
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
135fi
136
137write_rule "$match" "$INTERFACE" "$COMMENT"
138
139unlock_rules_file
140
141exit 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 @@
1scsi_id - generate a SCSI unique identifier for a given SCSI device
2
3Please 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
15struct 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
77struct 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
3scsi_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
9queries a SCSI device via the SCSI INQUIRY vital product data (VPD) page 0x80 or
100x83 and uses the resulting data to generate a value that is unique across
11all SCSI devices that properly support page 0x80 or page 0x83.
12
13If a result is generated it is sent to standard output, and the program
14exits with a zero value. If no identifier is output, the program exits
15with a non\-zero value.
16
17\fBscsi_id\fP is primarily for use by other utilities such as \fBudev\fP
18that require a unique SCSI identifier.
19
20By default all devices are assumed black listed, the \fB\-\-whitelisted\fP option must
21be specified on the command line or in the config file for any useful
22behaviour.
23
24SCSI commands are sent directly to the device via the SG_IO ioctl
25interface.
26
27In order to generate unique values for either page 0x80 or page 0x83, the
28serial numbers or world wide names are prefixed as follows.
29
30Identifiers based on page 0x80 are prefixed by the character 'S', the SCSI
31vendor, the SCSI product (model) and then the the serial number returned
32by page 0x80. For example:
33
34.sp
35.nf
36# /usr/lib/udev/scsi_id \-\-page=0x80 \-\-whitelisted \-\-device=/dev/sda
37SIBM 3542 1T05078453
38.fi
39.P
40
41Identifiers based on page 0x83 are prefixed by the identifier type
42followed 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
44identifier starts with the NAA value of 6):
45
46.sp
47.nf
48# /usr/lib/udev/scsi_id \-\-page=0x83 \-\-whitelisted \-\-device=/dev/sda
493600a0b80000b174b000000d63efc5c8c
50.fi
51.P
52
53.SH OPTIONS
54.TP
55.BI \-\-blacklisted
56The default behaviour \- treat the device as black listed, and do nothing
57unless a white listed device is found in the scsi_id config\-file.
58.TP
59.BI \-\-device=\| device\^
60Send SG_IO commands to \fBdevice\fP, such as \fB/dev/sdc\fP.
61.TP
62.BI \-\-config=\| config\-file
63Read configuration and black/white list entries from
64.B config\-file
65rather than the default
66.B /etc/scsi_id.config
67file.
68.TP
69.BI \-\-whitelisted
70Treat the device as white listed. The \fB\-\-whitelisted\fP option must be specified
71on the command line or in the scsi_id configuration file for
72.B scsi_id
73to generate any output.
74.TP
75.BI \-\-page=\| 0x80 | 0x83 | pre-spc3-83
76Use SCSI INQUIRY VPD page code 0x80, 0x83, or pre-spc3-83.
77.sp
78The default
79behaviour is to query the available VPD pages, and use page 0x83 if found,
80else page 0x80 if found, else nothing.
81.sp
82Page pre-spc3-83 should only be utilized for those scsi devices which
83are not compliant with the SPC-2 or SPC-3 format for page 83. While this
84option is used for older model 4, 5, and 6 EMC Symmetrix devices, its
85use with SPC-2 or SPC-3 compliant devices will fallback to the page 83
86format supported by these devices.
87.TP
88.BI \-\-replace-whitespace
89Reformat the output : replace all whitespaces by underscores.
90.TP
91.BI \-\-export
92Export all data in KEY=<value> format used to import in other programs.
93.TP
94.BI \-\-verbose
95Generate verbose debugging output.
96.TP
97.BI \-\-version
98Display 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
107Configuration 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>
110vendor="ATA",options=-p 0x80
111.RE
112.fi
113.LP
114.SH "SEE ALSO"
115.BR udev (7)
116.SH AUTHORS
117Developed by Patrick Mansfield <patmans@us.ibm.com> based on SCSI ID
118source included in earlier linux 2.5 kernels, sg_utils source, and SCSI
119specifications.
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
36static 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
51static const char short_options[] = "d:f:ghip:uvVx";
52static const char dev_short_options[] = "bgp:";
53
54static int all_good;
55static int dev_specified;
56static char config_file[MAX_PATH_LEN] = SYSCONFDIR "/scsi_id.config";
57static enum page_code default_page_code;
58static int sg_version = 4;
59static int use_stderr;
60static int debug;
61static int reformat_serial;
62static int export;
63static char vendor_str[64];
64static char model_str[64];
65static char vendor_enc_str[256];
66static char model_enc_str[256];
67static char revision_str[16];
68static char type_str[16];
69
70static 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
77static 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 */
123static 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
152static 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 */
170static 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
332static 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
440static 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
500static 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 */
527static 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);
603out:
604 return retval;
605}
606
607int 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
653exit:
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
38struct 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
61extern int scsi_std_inquiry(struct udev *udev, struct scsi_id_device *dev_scsi, const char *devname);
62extern 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 */
68enum 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 */
50static 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
75static 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
98static 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
102static 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
157static 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
165static 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
173static 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
274static 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
294static 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
316static 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
335resend:
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
405error:
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 */
414static 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 */
458static 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 **/
483static 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 */
598static 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 */
622static 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 */
723static 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 */
786static 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
832int 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
871out:
872 close(fd);
873 return err;
874}
875
876int 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
987completed:
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
139finish:
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
218static 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
261union 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
479finish:
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
34extern "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*/
112int 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*/
124int 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*/
136int 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*/
152int 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*/
166int 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*/
182int 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*/
190int 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*/
241int 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*/
263int 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*/
276int 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
27static 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
35static 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
109static 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
124static 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
152static 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
166static 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
200static 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
222static 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 }
295out:
296 if (fd_ep >= 0)
297 close(fd_ep);
298 udev_monitor_unref(udev_monitor);
299 return 0;
300}
301
302static 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
341static 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
423int 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);
498out:
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
33void 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
37int 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);
110out:
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
34static 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
84static 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
116static 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);
194out:
195 if (fd > 0)
196 close(fd);
197 if (err < 0)
198 return EXIT_FAILURE;
199 return EXIT_SUCCESS;
200}
201
202const 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
30static 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
44static 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;
68exit:
69 if (ftarget != NULL)
70 fclose(ftarget);
71 if (fsource != NULL)
72 fclose(fsource);
73 free(buf);
74 return ret;
75}
76
77static 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");
157exit:
158 if (fwfile)
159 fclose(fwfile);
160 return rc;
161}
162
163const 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
30static 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
55static 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
75static 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"
84static 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
156finish:
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
170static 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;
188try_parent:
189 return udev_device_get_parent_with_subsystem_devtype(dev, subsys, devtype);
190}
191
192
193static 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
219finish:
220 free(vendor);
221 free(product);
222 return 0;
223}
224
225static 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
230static 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
235const 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
242const 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 */
47static 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 */
92static 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 */
141static 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
184static 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
214const 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
34static struct kmod_ctx *ctx;
35
36static 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
67static 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 */
74static 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 */
103static 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 */
119static 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 */
126static 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
134const 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
35static 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 }
59out:
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*/
67static 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
78static 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
94static 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);
119out:
120 udev_device_unref(fcdev);
121 return parent;
122}
123
124static 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);
156out:
157 udev_device_unref(sasdev);
158 return parent;
159}
160
161static 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);
214out:
215 udev_device_unref(sessiondev);
216 udev_device_unref(conndev);
217 return parent;
218}
219
220static 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);
284out:
285 free(base);
286 return hostdev;
287}
288
289static 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);
339out:
340 return parent;
341}
342
343static 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
358static 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
381static 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));
401out:
402 parent = skip_subsystem(parent, "ccw");
403 return parent;
404}
405
406static 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 }
454out:
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
493const 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
34static 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
85static 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
118static 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
152static 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 }
220out:
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 */
242static 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
390fallback:
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
477const 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
28static 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
39int 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
54void 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
63bool 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
75void 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
83const char *udev_builtin_name(enum udev_builtin_cmd cmd)
84{
85 return builtins[cmd]->name;
86}
87
88bool udev_builtin_run_once(enum udev_builtin_cmd cmd)
89{
90 return builtins[cmd]->run_once;
91}
92
93enum 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
109int 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
121int 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]
2Description=udev Control Socket
3DefaultDependencies=no
4ConditionCapability=CAP_MKNOD
5
6[Socket]
7Service=udev.service
8ListenSequentialPacket=/run/udev/control
9SocketMode=0600
10PassCredentials=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
28enum 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
40struct 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
50struct udev_ctrl_msg {
51 int refcount;
52 struct udev_ctrl_connection *conn;
53 struct udev_ctrl_msg_wire ctrl_msg_wire;
54};
55
56struct 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
67struct udev_ctrl_connection {
68 int refcount;
69 struct udev_ctrl *uctrl;
70 int sock;
71};
72
73struct 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
102struct udev_ctrl *udev_ctrl_new(struct udev *udev)
103{
104 return udev_ctrl_new_from_fd(udev, -1);
105}
106
107int 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
137struct udev *udev_ctrl_get_udev(struct udev_ctrl *uctrl)
138{
139 return uctrl->udev;
140}
141
142struct 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
150struct 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
163int 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
172int udev_ctrl_get_fd(struct udev_ctrl *uctrl)
173{
174 if (uctrl == NULL)
175 return -EINVAL;
176 return uctrl->sock;
177}
178
179struct 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;
214err:
215 if (conn->sock >= 0)
216 close(conn->sock);
217 free(conn);
218 return NULL;
219}
220
221struct 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
229struct 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
243static 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 }
294out:
295 return err;
296}
297
298int 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
303int 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
308int 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
313int udev_ctrl_send_reload(struct udev_ctrl *uctrl, int timeout)
314{
315 return ctrl_send(uctrl, UDEV_CTRL_RELOAD, 0, NULL, timeout);
316}
317
318int 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
323int 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
328int udev_ctrl_send_ping(struct udev_ctrl *uctrl, int timeout)
329{
330 return ctrl_send(uctrl, UDEV_CTRL_PING, 0, NULL, timeout);
331}
332
333int udev_ctrl_send_exit(struct udev_ctrl *uctrl, int timeout)
334{
335 return ctrl_send(uctrl, UDEV_CTRL_EXIT, 0, NULL, timeout);
336}
337
338struct 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;
414err:
415 udev_ctrl_msg_unref(uctrl_msg);
416 return NULL;
417}
418
419struct 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
427struct 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
440int 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
447int 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
454int 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
461int 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
468const 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
475int 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
482int 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
489int 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
39struct 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
57void 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
68size_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 }
163copy:
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;
174subst:
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
404out:
405 s[0] = '\0';
406 dbg(event->udev, "'%s' -> '%s' (%zu)\n", src, dest, l);
407 return l;
408}
409
410static 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
456static 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 }
576out:
577 if (fd_ep >= 0)
578 close(fd_ep);
579}
580
581static 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 }
657out:
658 return err;
659}
660
661int 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 }
689out:
690 argv[i] = NULL;
691 if (argc)
692 *argc = i;
693 return 0;
694}
695
696int 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
775out:
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
787static 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
807static 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
871out:
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
878int 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 }
972out:
973 return err;
974}
975
976int 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]
2Description=udev Kernel Socket
3DefaultDependencies=no
4ConditionCapability=CAP_MKNOD
5
6[Socket]
7Service=udev.service
8ReceiveBuffer=134217728
9ListenNetlink=kobject-uevent 1
10PassCredentials=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
36static 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 }
140exit:
141 return err;
142}
143
144/* find device node of device with highest priority */
145static 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 */
201static 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
251void 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
281static 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);
326out:
327 return err;
328}
329
330void 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
360void 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
39struct uid_gid {
40 unsigned int name_off;
41 union {
42 uid_t uid;
43 gid_t gid;
44 };
45};
46
47struct 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
59struct 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:="" */
89enum 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
101enum 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
110enum 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 */
118enum 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 */
178struct 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
215struct 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
223static 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
239static 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
253static 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
317static 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
426static 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
439static inline const char *operation_str(enum operation_type type) { return NULL; }
440static inline const char *token_str(enum token_type type) { return NULL; }
441static inline void dump_token(struct udev_rules *rules, struct token *token) {}
442static inline void dump_rules(struct udev_rules *rules) {}
443#endif /* ENABLE_DEBUG */
444
445static 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
473static 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
560static 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
584static 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
627static 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
670static 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
747static 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
761static 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
789static 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
818static 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
856static 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
894static 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} */
983static 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
1003static 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
1152static 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
1187static 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;
1629invalid:
1630 err(rules->udev, "invalid rule '%s:%u'\n", filename, lineno);
1631 return -1;
1632}
1633
1634static 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
1709static 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
1750struct 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
1883struct 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
1896static 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
1976static 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
2026enum escape_type {
2027 ESCAPE_UNSET,
2028 ESCAPE_NONE,
2029 ESCAPE_REPLACE,
2030};
2031
2032int 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
2688void 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;
2762next:
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]
12Description=udev Wait for Complete Device Initialization
13DefaultDependencies=no
14Wants=udev.service
15After=udev-trigger.service
16Before=basic.target
17
18[Service]
19Type=oneshot
20TimeoutSec=180
21RemainAfterExit=yes
22ExecStart=@bindir@/udevadm settle
23
24[Install]
25WantedBy=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]
2Description=udev Coldplug all Devices
3Wants=udev.service
4After=udev-kernel.socket udev-control.socket
5DefaultDependencies=no
6
7[Service]
8Type=oneshot
9RemainAfterExit=yes
10ExecStart=@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
33static 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 */
39int 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 */
50void 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);
93unlink:
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
105void 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
129void 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
150struct 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
29struct 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
58struct udev_watch {
59 struct udev_list_node node;
60 int handle;
61 char *name;
62};
63
64/* udev-rules.c */
65struct udev_rules;
66struct udev_rules *udev_rules_new(struct udev *udev, int resolve_names);
67struct udev_rules *udev_rules_unref(struct udev_rules *rules);
68int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event, const sigset_t *sigmask);
69void udev_rules_apply_static_dev_perms(struct udev_rules *rules);
70
71/* udev-event.c */
72struct udev_event *udev_event_new(struct udev_device *dev);
73void udev_event_unref(struct udev_event *event);
74size_t udev_event_apply_format(struct udev_event *event, const char *src, char *dest, size_t size);
75int udev_event_apply_subsys_kernel(struct udev_event *event, const char *string,
76 char *result, size_t maxsize, int read_value);
77int udev_event_spawn(struct udev_event *event,
78 const char *cmd, char **envp, const sigset_t *sigmask,
79 char *result, size_t ressize);
80int udev_event_execute_rules(struct udev_event *event, struct udev_rules *rules, const sigset_t *sigset);
81int udev_event_execute_run(struct udev_event *event, const sigset_t *sigset);
82int udev_build_argv(struct udev *udev, char *cmd, int *argc, char *argv[]);
83
84/* udev-watch.c */
85int udev_watch_init(struct udev *udev);
86void udev_watch_restore(struct udev *udev);
87void udev_watch_begin(struct udev *udev, struct udev_device *dev);
88void udev_watch_end(struct udev *udev, struct udev_device *dev);
89struct udev_device *udev_watch_lookup(struct udev *udev, int wd);
90
91/* udev-node.c */
92void udev_node_add(struct udev_device *dev, mode_t mode, uid_t uid, gid_t gid);
93void udev_node_remove(struct udev_device *dev);
94void udev_node_update_old_links(struct udev_device *dev, struct udev_device *dev_old);
95
96/* udev-ctrl.c */
97struct udev_ctrl;
98struct udev_ctrl *udev_ctrl_new(struct udev *udev);
99struct udev_ctrl *udev_ctrl_new_from_fd(struct udev *udev, int fd);
100int udev_ctrl_enable_receiving(struct udev_ctrl *uctrl);
101struct udev_ctrl *udev_ctrl_ref(struct udev_ctrl *uctrl);
102struct udev_ctrl *udev_ctrl_unref(struct udev_ctrl *uctrl);
103int udev_ctrl_cleanup(struct udev_ctrl *uctrl);
104struct udev *udev_ctrl_get_udev(struct udev_ctrl *uctrl);
105int udev_ctrl_get_fd(struct udev_ctrl *uctrl);
106int udev_ctrl_send_set_log_level(struct udev_ctrl *uctrl, int priority, int timeout);
107int udev_ctrl_send_stop_exec_queue(struct udev_ctrl *uctrl, int timeout);
108int udev_ctrl_send_start_exec_queue(struct udev_ctrl *uctrl, int timeout);
109int udev_ctrl_send_reload(struct udev_ctrl *uctrl, int timeout);
110int udev_ctrl_send_ping(struct udev_ctrl *uctrl, int timeout);
111int udev_ctrl_send_exit(struct udev_ctrl *uctrl, int timeout);
112int udev_ctrl_send_set_env(struct udev_ctrl *uctrl, const char *key, int timeout);
113int udev_ctrl_send_set_children_max(struct udev_ctrl *uctrl, int count, int timeout);
114struct udev_ctrl_connection;
115struct udev_ctrl_connection *udev_ctrl_get_connection(struct udev_ctrl *uctrl);
116struct udev_ctrl_connection *udev_ctrl_connection_ref(struct udev_ctrl_connection *conn);
117struct udev_ctrl_connection *udev_ctrl_connection_unref(struct udev_ctrl_connection *conn);
118struct udev_ctrl_msg;
119struct udev_ctrl_msg *udev_ctrl_receive_msg(struct udev_ctrl_connection *conn);
120struct udev_ctrl_msg *udev_ctrl_msg_ref(struct udev_ctrl_msg *ctrl_msg);
121struct udev_ctrl_msg *udev_ctrl_msg_unref(struct udev_ctrl_msg *ctrl_msg);
122int udev_ctrl_get_set_log_level(struct udev_ctrl_msg *ctrl_msg);
123int udev_ctrl_get_stop_exec_queue(struct udev_ctrl_msg *ctrl_msg);
124int udev_ctrl_get_start_exec_queue(struct udev_ctrl_msg *ctrl_msg);
125int udev_ctrl_get_reload(struct udev_ctrl_msg *ctrl_msg);
126int udev_ctrl_get_ping(struct udev_ctrl_msg *ctrl_msg);
127int udev_ctrl_get_exit(struct udev_ctrl_msg *ctrl_msg);
128const char *udev_ctrl_get_set_env(struct udev_ctrl_msg *ctrl_msg);
129int udev_ctrl_get_set_children_max(struct udev_ctrl_msg *ctrl_msg);
130
131/* built-in commands */
132enum 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};
143struct 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};
152extern const struct udev_builtin udev_builtin_blkid;
153extern const struct udev_builtin udev_builtin_firmware;
154extern const struct udev_builtin udev_builtin_input_id;
155extern const struct udev_builtin udev_builtin_kmod;
156extern const struct udev_builtin udev_builtin_path_id;
157extern const struct udev_builtin udev_builtin_pci_db;
158extern const struct udev_builtin udev_builtin_usb_db;
159extern const struct udev_builtin udev_builtin_usb_id;
160int udev_builtin_init(struct udev *udev);
161void udev_builtin_exit(struct udev *udev);
162enum udev_builtin_cmd udev_builtin_lookup(const char *command);
163const char *udev_builtin_name(enum udev_builtin_cmd cmd);
164bool udev_builtin_run_once(enum udev_builtin_cmd cmd);
165int udev_builtin_run(struct udev_device *dev, enum udev_builtin_cmd cmd, const char *command, bool test);
166void udev_builtin_list(struct udev *udev);
167int udev_builtin_add_property(struct udev_device *dev, bool test, const char *key, const char *val);
168
169/* udev logging */
170void 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 */
175struct udevadm_cmd {
176 const char *name;
177 int (*cmd)(struct udev *udev, int argc, char *argv[]);
178 const char *help;
179 int debug;
180};
181extern const struct udevadm_cmd udevadm_info;
182extern const struct udevadm_cmd udevadm_trigger;
183extern const struct udevadm_cmd udevadm_settle;
184extern const struct udevadm_cmd udevadm_control;
185extern const struct udevadm_cmd udevadm_monitor;
186extern const struct udevadm_cmd udevadm_test;
187extern 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 @@
1Name: udev
2Description: udev
3Version: @VERSION@
4
5udevdir=@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]
2Description=udev Kernel Device Manager
3Wants=udev-control.socket udev-kernel.socket
4After=udev-control.socket udev-kernel.socket
5Before=basic.target
6DefaultDependencies=no
7ConditionCapability=CAP_MKNOD
8
9[Service]
10Type=notify
11OOMScoreAdjust=-1000
12Sockets=udev-control.socket udev-kernel.socket
13Restart=on-failure
14ExecStart=@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
30static 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
44static 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");
166out:
167 udev_ctrl_unref(uctrl);
168 return rc;
169}
170
171const 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
34static 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
53static 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
90static 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
136static 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
166static 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
185static 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
207static 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
238static 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
282static 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
559exit:
560 udev_device_unref(device);
561 return rc;
562}
563
564const 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
37static bool udev_exit;
38
39static void sig_handler(int signum)
40{
41 if (signum == SIGINT || signum == SIGTERM)
42 udev_exit = true;
43}
44
45static 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
67static 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 }
283out:
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
293const 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
39static 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 }
224out:
225 if (pfd[0].fd >= 0)
226 close(pfd[0].fd);
227 udev_queue_unref(udev_queue);
228 return rc;
229}
230
231const 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
37static 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
45static 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 }
117out:
118 udev_device_unref(dev);
119 udev_builtin_exit(udev);
120 return rc;
121}
122
123const 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
34static 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 }
158out:
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
168const 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
36static int verbose;
37static int dry_run;
38
39static 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
64static 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
78static 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 }
223exit:
224 udev_enumerate_unref(udev_enumerate);
225 return rc;
226}
227
228const 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
28static bool debug;
29
30void 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
47static int adm_version(struct udev *udev, int argc, char *argv[])
48{
49 printf("%s\n", VERSION);
50 return 0;
51}
52static const struct udevadm_cmd udevadm_version = {
53 .name = "version",
54 .cmd = adm_version,
55};
56
57static int adm_help(struct udev *udev, int argc, char *argv[]);
58static const struct udevadm_cmd udevadm_help = {
59 .name = "help",
60 .cmd = adm_help,
61};
62
63static 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
75static 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
87static 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
98int 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;
160out:
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
50static bool debug;
51
52void 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
70static struct udev_rules *rules;
71static struct udev_queue_export *udev_queue_export;
72static struct udev_ctrl *udev_ctrl;
73static struct udev_monitor *monitor;
74static int worker_watch[2] = { -1, -1 };
75static int fd_signal = -1;
76static int fd_ep = -1;
77static int fd_inotify = -1;
78static bool stop_exec_queue;
79static bool reload;
80static int children;
81static int children_max;
82static int exec_delay;
83static sigset_t sigmask_orig;
84static UDEV_LIST(event_list);
85static UDEV_LIST(worker_list);
86static bool udev_exit;
87
88enum event_state {
89 EVENT_UNDEF,
90 EVENT_QUEUED,
91 EVENT_RUNNING,
92};
93
94struct 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
110static 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
119static void event_queue_cleanup(struct udev *udev, enum event_state type);
120
121enum worker_state {
122 WORKER_UNDEF,
123 WORKER_RUNNING,
124 WORKER_IDLE,
125 WORKER_KILLED,
126};
127
128struct 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 */
140struct worker_message {
141 pid_t pid;
142 int exitcode;
143};
144
145static 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
154static 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
166static struct worker *worker_ref(struct worker *worker)
167{
168 worker->refcount++;
169 return worker;
170}
171
172static 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
180static 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
189static 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
200static 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 }
367out:
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
404static 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
440static 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
467static 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 */
492static 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
564static 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
584static 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
598static 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 */
631static 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 }
711out:
712 udev_ctrl_msg_unref(ctrl_msg);
713 return udev_ctrl_connection_unref(ctrl_conn);
714}
715
716/* read inotify messages */
717static 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
766static 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
825static 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
891static 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
954static 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
981static 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
992static 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
1006static 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
1029static 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
1121static 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
1157static 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
1187int 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;
1722exit:
1723 udev_queue_export_cleanup(udev_queue_export);
1724 udev_ctrl_cleanup(udev_ctrl);
1725exit_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
3ACTION=="remove", GOTO="persistent_v4l_end"
4SUBSYSTEM!="video4linux", GOTO="persistent_v4l_end"
5ENV{MAJOR}=="", GOTO="persistent_v4l_end"
6
7IMPORT{program}="v4l_id $devnode"
8
9SUBSYSTEMS=="usb", IMPORT{builtin}="usb_id"
10KERNEL=="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
13TEST!="index", GOTO="persistent_v4l_end"
14ATTR{index}!="?*", GOTO="persistent_v4l_end"
15
16IMPORT{builtin}="path_id"
17ENV{ID_PATH}=="?*", KERNEL=="video*|vbi*", SYMLINK+="v4l/by-path/$env{ID_PATH}-video-index$attr{index}"
18ENV{ID_PATH}=="?*", KERNEL=="audio*", SYMLINK+="v4l/by-path/$env{ID_PATH}-audio-index$attr{index}"
19
20LABEL="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
33int 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
21import re
22import sys
23
24if len(sys.argv) < 2:
25 print >> sys.stderr, 'Usage: %s <rules file> [...]' % sys.argv[0]
26 sys.exit(2)
27
28no_args_tests = re.compile('(ACTION|DEVPATH|KERNELS?|NAME|SYMLINK|SUBSYSTEMS?|DRIVERS?|TAG|RESULT|TEST)\s*(?:=|!)=\s*"([^"]*)"$')
29args_tests = re.compile('(ATTRS?|ENV|TEST){([a-zA-Z0-9/_.*%-]+)}\s*(?:=|!)=\s*"([^"]*)"$')
30no_args_assign = re.compile('(NAME|SYMLINK|OWNER|GROUP|MODE|TAG|PROGRAM|RUN|LABEL|GOTO|WAIT_FOR|OPTIONS|IMPORT)\s*(?:\+=|:=|=)\s*"([^"]*)"$')
31args_assign = re.compile('(ATTR|ENV|IMPORT){([a-zA-Z0-9/_.*%-]+)}\s*=\s*"([^"]*)"$')
32
33result = 0
34buffer = ''
35for 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
64sys.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
10type 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
20use warnings;
21use strict;
22
23my $PWD = $ENV{PWD};
24my $sysfs = "test/sys";
25my $udev_bin = "./test-udev";
26my $valgrind = 0;
27my $udev_bin_valgrind = "valgrind --tool=memcheck --leak-check=yes --quiet $udev_bin";
28my $udev_root = "udev-root";
29my $udev_conf = "udev-test.conf";
30my $udev_rules = "udev-test.rules";
31
32my @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#
40EOF
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
47SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", SYMLINK+="boot_disk%n"
48KERNEL=="ttyACM0", SYMLINK+="modem"
49EOF
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
56SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", SYMLINK+="boot_disk%n"
57KERNEL=="ttyACM0", SYMLINK+="modem"
58EOF
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
65SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", SYMLINK+="boot_disk%n"
66KERNEL=="ttyACM0", SYMLINK+="modem"
67EOF
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
74SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", SYMLINK+="boot_disk%n"
75EOF
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
82SUBSYSTEMS=="scsi", ATTRS{vendor}=="?ATA", SYMLINK+="boot_disk%n-1"
83SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA?", SYMLINK+="boot_disk%n-2"
84SUBSYSTEMS=="scsi", ATTRS{vendor}=="A??", SYMLINK+="boot_disk%n"
85SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATAS", SYMLINK+="boot_disk%n-3"
86EOF
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
93SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS X ", SYMLINK+="boot_diskX%n"
94SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", SYMLINK+="boot_disk%n"
95EOF
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
102SUBSYSTEMS=="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"
103SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", ATTRS{scsi_level}=="6", ATTRS{rev}=="4.06", ATTRS{type}=="0", SYMLINK+="boot_disk%n"
104EOF
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
111KERNEL=="ttyACM*", SYMLINK+="modem/%n"
112EOF
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
119KERNEL=="*ACM1", SYMLINK+="bad"
120KERNEL=="*ACM0", SYMLINK+="modem/%n"
121EOF
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
128KERNEL=="ttyACM??*", SYMLINK+="modem/%n-1"
129KERNEL=="ttyACM??", SYMLINK+="modem/%n-2"
130KERNEL=="ttyACM?", SYMLINK+="modem/%n"
131EOF
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
138KERNEL=="ttyACM[A-Z]*", SYMLINK+="modem/%n-1"
139KERNEL=="ttyACM?[0-9]", SYMLINK+="modem/%n-2"
140KERNEL=="ttyACM[0-9]*", SYMLINK+="modem/%n"
141EOF
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
148KERNEL=="ttyACM0", SYMLINK+="modem"
149EOF
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
157KERNEL=="ttyACM0", SYMLINK+="modem"
158
159EOF
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
167KERNEL=="ttyACM0", SYMLINK+="modem"
168
169EOF
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
180KERNEL=="ttyACM0", SYMLINK+="whitespace"
181
182
183
184EOF
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
192KERNEL=="ttyACM0", SYMLINK+="modem"
193
194EOF
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
201KERNEL=="ttyACM0", \\
202SYMLINK+="modem"
203
204EOF
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
211KERNEL=="ttyACM0", PROGRAM=="/bin/echo -e \\101", RESULT=="A", SYMLINK+="aaa"
212EOF
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
227KERNEL=="ttyACM0", \\
228 SYMLINK+="modem"
229
230EOF
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
237KERNEL=="ttyACM0", SYMLINK+="sub/direct/ory/modem"
238EOF
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
245SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", SYMLINK+="first_disk%n"
246EOF
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
253SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", SYMLINK+="Major:%M:minor:%m:kernelnumber:%n:id:%b"
254EOF
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
261SUBSYSTEMS=="scsi", IMPORT{file}="udev-test.conf", SYMLINK+="subdir/%E{udev_log}/node"
262KERNEL=="ttyACM0", SYMLINK+="modem"
263EOF
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
270SUBSYSTEMS=="scsi", IMPORT{program}="/bin/echo -e \' TEST_KEY=12345678\\n TEST_key2=98765\'", SYMLINK+="node\$env{TEST_KEY}"
271KERNEL=="ttyACM0", SYMLINK+="modem"
272EOF
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
279SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", SYMLINK+="disk-%s{vendor}-%k"
280KERNEL=="ttyACM0", SYMLINK+="modem"
281EOF
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
289SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n special-device", RESULT=="-special-*", SYMLINK+="not"
290SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n special-device", RESULT=="special-*", SYMLINK+="%c-%n"
291EOF
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
298SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo test", RESULT=="test", SYMLINK+="newline_removed"
299EOF
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
306SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n test-%b", RESULT=="test-0:0*", SYMLINK+="%c"
307EOF
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
314SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n foo3 foo4 foo5 foo6 foo7 foo8 foo9", KERNEL=="sda5", SYMLINK+="%c{7}"
315EOF
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
322SUBSYSTEMS=="scsi", PROGRAM=="/bin/sh -c 'echo foo3 foo4 foo5 foo6 foo7 foo8 foo9 | sed s/foo9/bar9/'", KERNEL=="sda5", SYMLINK+="%c{7}"
323EOF
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
330SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n 'foo3 foo4' 'foo5 foo6 foo7 foo8'", KERNEL=="sda5", SYMLINK+="%c{5}"
331EOF
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
338SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n foo3 foo4 foo5 foo6 foo7 foo8 foo9", KERNEL=="sda5", SYMLINK+="my-%c{7}"
339EOF
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
346SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n foo3 foo4 foo5 foo6 foo7 foo8 foo9", KERNEL=="sda5", SYMLINK+="my-%c{6}"
347EOF
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
354SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", SYMLINK+="Major:\$major-minor:\$minor-kernelnumber:\$number-id:\$id"
355EOF
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
362SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", DEVPATH=="*/sda/*", SYMLINK+="Major:\$major-minor:%m-kernelnumber:\$number-id:\$id"
363EOF
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
370SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", DEVPATH=="*/sda/*", SYMLINK+="%M%m%b%n"
371EOF
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
378SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", DEVPATH=="*/sda/*", SYMLINK+="\$major\$minor\$number"
379EOF
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
386SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", DEVPATH=="*/sda/*", SYMLINK+="\$major%m%n\$id"
387EOF
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
394SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n foo", RESULT=="foo", SYMLINK+="foo"
395KERNEL=="console", SYMLINK+="TTY"
396EOF
397 },
398 {
399 desc => "non matching SUBSYSTEMS",
400 devpath => "/devices/virtual/tty/console",
401 exp_name => "TTY" ,
402 rules => <<EOF
403SUBSYSTEMS=="foo", ATTRS{dev}=="5:1", SYMLINK+="foo"
404KERNEL=="console", SYMLINK+="TTY"
405EOF
406 },
407 {
408 desc => "ATTRS match",
409 devpath => "/devices/virtual/tty/console",
410 exp_name => "foo" ,
411 rules => <<EOF
412KERNEL=="console", SYMLINK+="TTY"
413ATTRS{dev}=="5:1", SYMLINK+="foo"
414EOF
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
421KERNEL=="sda", ATTR{test_empty_file}=="?*", SYMLINK+="something"
422KERNEL=="sda", ATTR{test_empty_file}!="", SYMLINK+="not-empty"
423KERNEL=="sda", ATTR{test_empty_file}=="", SYMLINK+="empty"
424KERNEL=="sda", ATTR{test_empty_file}!="?*", SYMLINK+="not-something"
425EOF
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
432KERNEL=="sda", ATTR{nofile}=="?*", SYMLINK+="something"
433KERNEL=="sda", ATTR{nofile}!="", SYMLINK+="not-empty"
434KERNEL=="sda", ATTR{nofile}=="", SYMLINK+="empty"
435KERNEL=="sda", ATTR{nofile}!="?*", SYMLINK+="not-something"
436KERNEL=="sda", TEST!="nofile", SYMLINK+="non-existent"
437KERNEL=="sda", SYMLINK+="wrong"
438EOF
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
445SUBSYSTEMS=="usb", PROGRAM=="/bin/echo -n usb-%b", SYMLINK+="%c"
446SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n scsi-%b", SYMLINK+="%c"
447SUBSYSTEMS=="foo", PROGRAM=="/bin/echo -n foo-%b", SYMLINK+="%c"
448EOF
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
455ATTRS{idProduct}=="007b", SYMLINK+="modem"
456EOF
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
463SUBSYSTEMS=="scsi", SYMLINK+="is/not/a/%k"
464SUBSYSTEM=="block", SYMLINK+="is/a/%k"
465KERNEL=="ttyACM0", SYMLINK+="modem"
466EOF
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
474KERNEL=="ttyACM0", SYMLINK+="modem"
475EOF
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
482SUBSYSTEMS=="usb", KERNELS=="0:0:0:0", SYMLINK+="not-scsi"
483SUBSYSTEMS=="scsi", KERNELS=="0:0:0:1", SYMLINK+="no-match"
484SUBSYSTEMS=="scsi", KERNELS==":0", SYMLINK+="short-id"
485SUBSYSTEMS=="scsi", KERNELS=="/0:0:0:0", SYMLINK+="no-match"
486SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", SYMLINK+="scsi-0:0:0:0"
487EOF
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
494SUBSYSTEMS=="scsi", KERNELS=="*:1", SYMLINK+="no-match"
495SUBSYSTEMS=="scsi", KERNELS=="*:0:1", SYMLINK+="no-match"
496SUBSYSTEMS=="scsi", KERNELS=="*:0:0:1", SYMLINK+="no-match"
497SUBSYSTEMS=="scsi", KERNEL=="0:0:0:0", SYMLINK+="before"
498SUBSYSTEMS=="scsi", KERNELS=="*", SYMLINK+="scsi-0:0:0:0"
499EOF
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
506SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", SYMLINK+="before"
507SUBSYSTEMS=="scsi", KERNELS=="*:0", SYMLINK+="scsi-0:0:0:0"
508EOF
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
515SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", SYMLINK+="before"
516SUBSYSTEMS=="scsi", KERNELS=="*:0:0:0", SYMLINK+="scsi-0:0:0:0"
517EOF
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
524SUBSYSTEMS=="scsi", SYMLINK+="driver-is-\$attr{driver}"
525EOF
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
532SUBSYSTEMS=="pci", SYMLINK+="driver-is-\$attr{driver}"
533EOF
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
540SUBSYSTEMS=="scsi", ATTRS{whitespace_test}=="WHITE SPACE", SYMLINK+="ignored"
541EOF
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
548SUBSYSTEMS=="scsi", ATTRS{whitespace_test}=="WHITE SPACE ", SYMLINK+="wrong-to-ignore"
549SUBSYSTEMS=="scsi", ATTRS{whitespace_test}=="WHITE SPACE ", SYMLINK+="matched-with-space"
550EOF
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
558KERNEL=="tty33", SYMLINK+="tty33", OWNER="bad", GROUP="name"
559EOF
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
567SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", OWNER="5000"
568EOF
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
576SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", GROUP="100"
577EOF
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
585SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", OWNER="nobody"
586EOF
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
594SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", GROUP="daemon"
595EOF
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
603SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", OWNER="root", GROUP="mail"
604EOF
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
612SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", MODE="0777"
613EOF
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
621SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", OWNER="5000", GROUP="100", MODE="0777"
622EOF
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
630KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", OWNER="5000"
631EOF
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
639KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", GROUP="100"
640EOF
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
648KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", MODE="0060"
649EOF
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
657KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", OWNER="5000", GROUP="100", MODE="0777"
658EOF
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
666KERNEL=="ttyACM[0-9]*", OWNER="5000", GROUP="100", MODE="0777"
667KERNEL=="ttyUSX[0-9]*", OWNER="5001", GROUP="101", MODE="0444"
668KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n"
669EOF
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
677SUBSYSTEM=="tty", OWNER="3000"
678SUBSYSTEM=="tty", GROUP="4000"
679SUBSYSTEM=="tty", MODE="0777"
680KERNEL=="ttyUSX[0-9]*", OWNER="5001", GROUP="101", MODE="0444"
681KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n"
682EOF
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
690SUBSYSTEM=="tty", OWNER="3000"
691SUBSYSTEM=="tty", GROUP="4000"
692SUBSYSTEM=="tty", MODE="0777"
693KERNEL=="ttyUSX[0-9]*", OWNER="5001", GROUP="101", MODE="0444"
694KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", GROUP="8000"
695EOF
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
703SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node"
704EOF
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
712KERNEL=="misc-fake1", SYMLINK+="node"
713EOF
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
721KERNEL=="misc-fake89999", SYMLINK+="node"
722EOF
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
729KERNEL=="ttyACM[0-9]*", SYMLINK="symlink1-%n symlink2-%k symlink3-%b"
730EOF
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
738KERNEL=="ttyACM[0-9]*", SYMLINK=" one two "
739EOF
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
746KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", SYMLINK="modem%n"
747EOF
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
754KERNEL=="ttyACM0", SYMLINK="first-%n second-%n third-%n"
755EOF
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
764SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="."
765EOF
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
775KERNEL=="tty0", SYMLINK+="tty0"
776EOF
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
783KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", SYMLINK+="symlink%n"
784EOF
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
791KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", SYMLINK+="symlink-%k"
792EOF
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
799KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", SYMLINK+="major-%M:%m"
800EOF
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
807SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="symlink-%b"
808EOF
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
815KERNEL=="ttyACM[0-9]*", PROGRAM=="/bin/echo test", SYMLINK+="%c"
816EOF
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
823KERNEL=="ttyACM[0-9]*", PROGRAM=="/bin/echo symlink test this", SYMLINK+="%c{2}"
824EOF
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
831KERNEL=="ttyACM[0-9]*", PROGRAM=="/bin/echo symlink test this", SYMLINK+="%c{2+}"
832EOF
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
839SUBSYSTEMS=="scsi", KERNEL=="sda", PROGRAM=="/bin/echo link test this" SYMLINK+="%c{2+}"
840EOF
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
847KERNEL=="ttyACM[0-9]*", SYMLINK+="%s{dev}"
848EOF
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
855SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n node link1 link2", RESULT=="node *", SYMLINK+="%c{2} %c{3}"
856EOF
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
863SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n node link1 link2 link3 link4", RESULT=="node *", SYMLINK+="%c{2+}"
864EOF
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
871SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="should_not_match", SUBSYSTEM=="vc"
872SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", SUBSYSTEM=="block"
873SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="should_not_match2", SUBSYSTEM=="vc"
874EOF
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
881SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="should_not_match", DRIVERS=="sd-wrong"
882SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", DRIVERS=="sd"
883EOF
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
890SUBSYSTEMS=="scsi", KERNEL=="sda", PROGRAM=="/usr/bin/test -b %N" SYMLINK+="node"
891EOF
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
898SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="%P-part-1"
899EOF
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
906SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="start-%r-end"
907EOF
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
914SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="last", OPTIONS="last_rule"
915SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="very-last"
916EOF
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
923SUBSYSTEMS=="scsi", KERNEL!="sda1", SYMLINK+="matches-but-is-negated"
924SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="before"
925SUBSYSTEMS=="scsi", KERNEL!="xsda1", SYMLINK+="match"
926EOF
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
933SUBSYSTEMS=="scsi", SUBSYSTEM=="block", KERNEL!="sda1", SYMLINK+="matches-but-is-negated"
934SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="before"
935SUBSYSTEMS=="scsi", SUBSYSTEM!="anything", SYMLINK+="not-anything"
936EOF
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
943SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="before"
944KERNEL=="sda1", PROGRAM!="/bin/false", SYMLINK+="nonzero-program"
945EOF
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
952SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="before"
953KERNEL == "sda1" , SYMLINK+ = "true"
954EOF
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
961ENV{ENV_KEY_TEST}="test"
962SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ENV_KEY_TEST}=="go", SYMLINK+="wrong"
963SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ENV_KEY_TEST}=="test", SYMLINK+="true"
964SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ENV_KEY_TEST}=="bad", SYMLINK+="bad"
965EOF
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
972ENV{ENV_KEY_TEST}="test"
973SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ENV_KEY_TEST}=="go", SYMLINK+="wrong"
974SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ENV_KEY_TEST}=="yes", ENV{ACTION}=="add", ENV{DEVPATH}=="*/block/sda/sdax1", SYMLINK+="no"
975SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ENV_KEY_TEST}=="test", ENV{ACTION}=="add", ENV{DEVPATH}=="*/block/sda/sda1", SYMLINK+="true"
976SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ENV_KEY_TEST}=="bad", SYMLINK+="bad"
977EOF
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
984SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ASSIGN}="true"
985SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ASSIGN}=="yes", SYMLINK+="no"
986SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="before"
987SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ASSIGN}=="true", SYMLINK+="true"
988EOF
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
995SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ASSIGN}="true"
996SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ASSIGN}="absolutely-\$env{ASSIGN}"
997SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="before"
998SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ASSIGN}=="yes", SYMLINK+="no"
999SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ASSIGN}=="absolutely-true", SYMLINK+="true"
1000EOF
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
1007SUBSYSTEM=="block", KERNEL=="*[0-9]", ENV{PARTITION}="true", ENV{MAINDEVICE}="false"
1008SUBSYSTEM=="block", KERNEL=="*[!0-9]", ENV{PARTITION}="false", ENV{MAINDEVICE}="true"
1009ENV{MAINDEVICE}=="true", SYMLINK+="disk"
1010SUBSYSTEM=="block", SYMLINK+="before"
1011ENV{PARTITION}=="true", SYMLINK+="part"
1012EOF
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
1019SUBSYSTEMS=="scsi", KERNEL=="sda1", PROGRAM=="/bin/echo -e name; (/usr/bin/badprogram)", RESULT=="name_ _/usr/bin/badprogram_", SYMLINK+="sane"
1020EOF
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
1027SUBSYSTEMS=="scsi", KERNEL=="sda1", PROGRAM=="/bin/echo -e \\xc3\\xbcber" RESULT=="\xc3\xbcber", SYMLINK+="uber"
1028EOF
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
1035SUBSYSTEMS=="scsi", KERNEL=="sda1", PROGRAM=="/bin/echo -e \\xef\\xe8garbage", RESULT=="__garbage", SYMLINK+="replaced"
1036EOF
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
1043KERNEL=="ttyACM*", ATTRS{serial}=="?*", SYMLINK+="serial-%s{serial}"
1044EOF
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
1051KERNEL=="sda", ATTRS{nothing}!="", SYMLINK+="not-1-ok"
1052KERNEL=="sda", ATTRS{nothing}=="", SYMLINK+="not-2-ok"
1053KERNEL=="sda", ATTRS{vendor}!="", SYMLINK+="ok"
1054KERNEL=="sda", ATTRS{vendor}=="", SYMLINK+="not-3-ok"
1055EOF
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
1062ACTION=="unknown", KERNEL=="sda", SYMLINK+="unknown-not-ok"
1063ACTION=="add", KERNEL=="sda", SYMLINK+="ok"
1064EOF
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
1072KERNEL=="sda", GROUP:="tty"
1073KERNEL=="sda", GROUP="not-ok", MODE="0640", SYMLINK+="ok"
1074EOF
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
1082KERNEL=="sda", GROUP:="tty"
1083SUBSYSTEM=="block", MODE:="640"
1084KERNEL=="sda", GROUP="not-ok", MODE="0666", SYMLINK+="ok"
1085EOF
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
1092KERNEL=="sda", MODE="0666", SYMLINK+="node-\$env{ACTION}-me"
1093EOF
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
1101KERNEL=="ttyACM[0-9]*", SYMLINK+="one"
1102KERNEL=="ttyACM[0-9]*", SYMLINK+="two"
1103KERNEL=="ttyACM[0-9]*", SYMLINK="three"
1104EOF
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
1112KERNEL=="ttyACM[0-9]*", SYMLINK+="wrong"
1113KERNEL=="ttyACM[0-9]*", SYMLINK=""
1114KERNEL=="ttyACM[0-9]*", SYMLINK+="right"
1115EOF
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
1122KERNEL=="ttyACM*", SYMLINK+="before"
1123KERNEL=="ttyACM*|nothing", SYMLINK+="right"
1124EOF
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
1131KERNEL=="dontknow*|*nothing", SYMLINK+="nomatch"
1132KERNEL=="ttyACM*", SYMLINK+="before"
1133KERNEL=="dontknow*|ttyACM*|nothing*", SYMLINK+="right"
1134EOF
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
1141KERNEL=="dontknow|nothing", SYMLINK+="nomatch"
1142KERNEL=="dontknow|ttyACM0a|nothing|attyACM0", SYMLINK+="wrong1"
1143KERNEL=="X|attyACM0|dontknow|ttyACM0a|nothing|attyACM0", SYMLINK+="wrong2"
1144KERNEL=="dontknow|ttyACM0|nothing", SYMLINK+="right"
1145EOF
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
1152KERNEL=="dontknow|nothing", SYMLINK+="nomatch"
1153KERNEL=="dontknow|ttyACM0a|nothing|attyACM0", SYMLINK+="wrong1"
1154KERNEL=="X|attyACM0|dontknow|ttyACM0a|nothing|attyACM0", SYMLINK+="wrong2"
1155KERNEL=="all|dontknow|ttyACM0", SYMLINK+="right"
1156KERNEL=="ttyACM0a|nothing", SYMLINK+="wrong3"
1157EOF
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
1165KERNEL=="sda", IMPORT{program}="/bin/echo -e \'PARENT_KEY=parent_right\\nWRONG_PARENT_KEY=parent_wrong'"
1166KERNEL=="sda", SYMLINK+="parent"
1167EOF
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
1175KERNEL=="sda1", IMPORT{parent}="PARENT*", SYMLINK+="parentenv-\$env{PARENT_KEY}\$env{WRONG_PARENT_KEY}"
1176EOF
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
1183KERNEL=="sda1", GOTO="TEST"
1184KERNEL=="sda1", SYMLINK+="wrong"
1185KERNEL=="sda1", GOTO="BAD"
1186KERNEL=="sda1", SYMLINK+="", LABEL="NO"
1187KERNEL=="sda1", SYMLINK+="right", LABEL="TEST", GOTO="end"
1188KERNEL=="sda1", SYMLINK+="wrong2", LABEL="BAD"
1189LABEL="end"
1190EOF
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
1197KERNEL=="sda1", GOTO="does-not-exist"
1198KERNEL=="sda1", SYMLINK+="right",
1199LABEL="exists"
1200EOF
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
1208KERNEL=="sda1", SYMLINK+="link"
1209KERNEL=="sda1", SYMLINK=="link*", SYMLINK+="right"
1210KERNEL=="sda1", SYMLINK=="nolink*", SYMLINK+="wrong"
1211EOF
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
1218KERNEL="sda1", SYMLINK+="no"
1219KERNEL=="sda1", SYMLINK+="yes"
1220EOF
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
1227KERNEL=="sda", ATTR{test:colon+plus}=="?*", SYMLINK+="yes"
1228EOF
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
1237KERNEL=="sda1", SYMLINK+=="no"
1238KERNEL=="sda1", SYMLINK+="yes"
1239EOF
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
1246KERNEL=="sda", SYMLINK+="\$attr{[net/eth0]address}"
1247EOF
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
1254TEST=="/etc/hosts", SYMLINK+="there"
1255TEST!="/etc/hosts", SYMLINK+="notthere"
1256EOF
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
1263KERNEL=="sda", TEST=="[net/eth0]", SYMLINK+="yes"
1264EOF
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
1271KERNEL=="sda", TEST=="size", SYMLINK+="relative"
1272EOF
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
1279KERNEL=="sda", TEST=="*/nr_requests", SYMLINK+="found-subdir"
1280EOF
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
1289KERNEL=="sda", MODE="0000"
1290EOF
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
1299KERNEL=="sda", MODE="666"
1300KERNEL=="sda", PROGRAM=="/bin/echo 5000 100 0400", OWNER="%c{1}", GROUP="%c{2}", MODE="%c{3}"
1301EOF
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
1310KERNEL=="sda", MODE="440"
1311KERNEL=="sda", PROGRAM=="/bin/echo 0 0 0400letsdoabuffferoverflow0123456789012345789012345678901234567890", OWNER="%c{1}", GROUP="%c{2}", MODE="%c{3}"
1312EOF
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
1320KERNEL=="sda", PROGRAM="/bin/true create-envp"
1321KERNEL=="sda", ENV{TESTENV}="change-envp"
1322KERNEL=="sda", SYMLINK+="%k-%s{[dmi/id]product_name}-end"
1323EOF
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
1330KERNEL=="sda", IMPORT{builtin}="path_id"
1331KERNEL=="sda", ENV{ID_PATH}=="?*", SYMLINK+="disk/by-path/\$env{ID_PATH}"
1332EOF
1333 },
1334);
1335
1336# set env
1337$ENV{UDEV_CONFIG_FILE} = $udev_conf;
1338
1339sub 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
1354my $error = 0;
1355
1356sub 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
1394sub 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
1419sub 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
1428sub 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
1502if (!($<==0)) {
1503 print "Must have root permissions to run properly.\n";
1504 exit;
1505}
1506
1507# prepare
1508make_udev_root();
1509
1510# create config file
1511open CONF, ">$udev_conf" || die "unable to create config file: $udev_conf";
1512print CONF "udev_root=\"$udev_root\"\n";
1513print CONF "udev_run=\"$udev_root/.udev\"\n";
1514print CONF "udev_sys=\"$sysfs\"\n";
1515print CONF "udev_rules=\"$PWD\"\n";
1516print CONF "udev_log=\"err\"\n";
1517close CONF;
1518
1519my $test_num = 1;
1520my @list;
1521
1522foreach 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
1531if ($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
1550print "$error errors occured\n\n";
1551
1552# cleanup
1553system("rm -rf $udev_root");
1554unlink($udev_rules);
1555unlink($udev_conf);
1556
1557if ($error > 0) {
1558 exit(1);
1559}
1560exit(0);