chiark / gitweb /
test: udev - add gdb support
[elogind.git] / test / udev-test.pl
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-2012 Kay Sievers <kay@vrfy.org>
18 # Copyright (C) 2004 Leann Ogasawara <ogasawara@osdl.org>
19
20 use warnings;
21 use strict;
22
23 my $udev_bin            = "./test-udev";
24 my $valgrind            = 0;
25 my $gdb                 = 0;
26 my $udev_bin_valgrind   = "valgrind --tool=memcheck --leak-check=yes --quiet $udev_bin";
27 my $udev_bin_gdb        = "gdb --args $udev_bin";
28 my $udev_dev            = "test/dev";
29 my $udev_run            = "test/run";
30 my $udev_rules_dir      = "$udev_run/udev/rules.d";
31 my $udev_rules          = "$udev_rules_dir/udev-test.rules";
32 my $EXIT_TEST_SKIP      = 77;
33
34 my @tests = (
35         {
36                 desc            => "no rules",
37                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
38                 exp_name        => "sda" ,
39                 exp_rem_error   => "yes",
40                 rules           => <<EOF
41 #
42 EOF
43         },
44         {
45                 desc            => "label test of scsi disc",
46                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
47                 exp_name        => "boot_disk" ,
48                 rules           => <<EOF
49 SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", SYMLINK+="boot_disk%n"
50 KERNEL=="ttyACM0", SYMLINK+="modem"
51 EOF
52         },
53         {
54                 desc            => "label test of scsi disc",
55                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
56                 exp_name        => "boot_disk" ,
57                 rules           => <<EOF
58 SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", SYMLINK+="boot_disk%n"
59 KERNEL=="ttyACM0", SYMLINK+="modem"
60 EOF
61         },
62         {
63                 desc            => "label test of scsi disc",
64                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
65                 exp_name        => "boot_disk" ,
66                 rules           => <<EOF
67 SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", SYMLINK+="boot_disk%n"
68 KERNEL=="ttyACM0", SYMLINK+="modem"
69 EOF
70         },
71         {
72                 desc            => "label test of scsi partition",
73                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
74                 exp_name        => "boot_disk1" ,
75                 rules           => <<EOF
76 SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", SYMLINK+="boot_disk%n"
77 EOF
78         },
79         {
80                 desc            => "label test of pattern match",
81                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
82                 exp_name        => "boot_disk1" ,
83                 rules           => <<EOF
84 SUBSYSTEMS=="scsi", ATTRS{vendor}=="?ATA", SYMLINK+="boot_disk%n-1"
85 SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA?", SYMLINK+="boot_disk%n-2"
86 SUBSYSTEMS=="scsi", ATTRS{vendor}=="A??", SYMLINK+="boot_disk%n"
87 SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATAS", SYMLINK+="boot_disk%n-3"
88 EOF
89         },
90         {
91                 desc            => "label test of multiple sysfs files",
92                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
93                 exp_name        => "boot_disk1" ,
94                 rules           => <<EOF
95 SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS X ", SYMLINK+="boot_diskX%n"
96 SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", SYMLINK+="boot_disk%n"
97 EOF
98         },
99         {
100                 desc            => "label test of max sysfs files (skip invalid rule)",
101                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
102                 exp_name        => "boot_disk1" ,
103                 rules           => <<EOF
104 SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", ATTRS{scsi_level}=="6", ATTRS{rev}=="4.06", ATTRS{type}=="0", ATTRS{queue_depth}=="32", SYMLINK+="boot_diskXX%n"
105 SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", ATTRS{scsi_level}=="6", ATTRS{rev}=="4.06", ATTRS{type}=="0", SYMLINK+="boot_disk%n"
106 EOF
107         },
108         {
109                 desc            => "catch device by *",
110                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
111                 exp_name        => "modem/0" ,
112                 rules           => <<EOF
113 KERNEL=="ttyACM*", SYMLINK+="modem/%n"
114 EOF
115         },
116         {
117                 desc            => "catch device by * - take 2",
118                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
119                 exp_name        => "modem/0" ,
120                 rules           => <<EOF
121 KERNEL=="*ACM1", SYMLINK+="bad"
122 KERNEL=="*ACM0", SYMLINK+="modem/%n"
123 EOF
124         },
125         {
126                 desc            => "catch device by ?",
127                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
128                 exp_name        => "modem/0" ,
129                 rules           => <<EOF
130 KERNEL=="ttyACM??*", SYMLINK+="modem/%n-1"
131 KERNEL=="ttyACM??", SYMLINK+="modem/%n-2"
132 KERNEL=="ttyACM?", SYMLINK+="modem/%n"
133 EOF
134         },
135         {
136                 desc            => "catch device by character class",
137                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
138                 exp_name        => "modem/0" ,
139                 rules           => <<EOF
140 KERNEL=="ttyACM[A-Z]*", SYMLINK+="modem/%n-1"
141 KERNEL=="ttyACM?[0-9]", SYMLINK+="modem/%n-2"
142 KERNEL=="ttyACM[0-9]*", SYMLINK+="modem/%n"
143 EOF
144         },
145         {
146                 desc            => "replace kernel name",
147                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
148                 exp_name        => "modem" ,
149                 rules           => <<EOF
150 KERNEL=="ttyACM0", SYMLINK+="modem"
151 EOF
152         },
153         {
154                 desc            => "Handle comment lines in config file (and replace kernel name)",
155                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
156                 exp_name        => "modem" ,
157                 rules           => <<EOF
158 # this is a comment
159 KERNEL=="ttyACM0", SYMLINK+="modem"
160
161 EOF
162         },
163         {
164                 desc            => "Handle comment lines in config file with whitespace (and replace kernel name)",
165                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
166                 exp_name        => "modem" ,
167                 rules           => <<EOF
168  # this is a comment with whitespace before the comment
169 KERNEL=="ttyACM0", SYMLINK+="modem"
170
171 EOF
172         },
173         {
174                 desc            => "Handle whitespace only lines (and replace kernel name)",
175                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
176                 exp_name        => "whitespace" ,
177                 rules           => <<EOF
178
179
180
181  # this is a comment with whitespace before the comment
182 KERNEL=="ttyACM0", SYMLINK+="whitespace"
183
184
185
186 EOF
187         },
188         {
189                 desc            => "Handle empty lines in config file (and replace kernel name)",
190                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
191                 exp_name        => "modem" ,
192                 rules           => <<EOF
193
194 KERNEL=="ttyACM0", SYMLINK+="modem"
195
196 EOF
197         },
198         {
199                 desc            => "Handle backslashed multi lines in config file (and replace kernel name)",
200                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
201                 exp_name        => "modem" ,
202                 rules           => <<EOF
203 KERNEL=="ttyACM0", \\
204 SYMLINK+="modem"
205
206 EOF
207         },
208         {
209                 desc            => "preserve backslashes, if they are not for a newline",
210                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
211                 exp_name        => "aaa",
212                 rules           => <<EOF
213 KERNEL=="ttyACM0", PROGRAM=="/bin/echo -e \\101", RESULT=="A", SYMLINK+="aaa"
214 EOF
215         },
216         {
217                 desc            => "Handle stupid backslashed multi lines in config file (and replace kernel name)",
218                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
219                 exp_name        => "modem" ,
220                 rules           => <<EOF
221
222 #
223 \\
224
225 \\
226
227 #\\
228
229 KERNEL=="ttyACM0", \\
230         SYMLINK+="modem"
231
232 EOF
233         },
234         {
235                 desc            => "subdirectory handling",
236                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
237                 exp_name        => "sub/direct/ory/modem" ,
238                 rules           => <<EOF
239 KERNEL=="ttyACM0", SYMLINK+="sub/direct/ory/modem"
240 EOF
241         },
242         {
243                 desc            => "parent device name match of scsi partition",
244                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
245                 exp_name        => "first_disk5" ,
246                 rules           => <<EOF
247 SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", SYMLINK+="first_disk%n"
248 EOF
249         },
250         {
251                 desc            => "test substitution chars",
252                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
253                 exp_name        => "Major:8:minor:5:kernelnumber:5:id:0:0:0:0" ,
254                 rules           => <<EOF
255 SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", SYMLINK+="Major:%M:minor:%m:kernelnumber:%n:id:%b"
256 EOF
257         },
258         {
259                 desc            => "import of shell-value returned from program",
260                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
261                 exp_name        => "node12345678",
262                 rules           => <<EOF
263 SUBSYSTEMS=="scsi", IMPORT{program}="/bin/echo -e \' TEST_KEY=12345678\\n  TEST_key2=98765\'", SYMLINK+="node\$env{TEST_KEY}"
264 KERNEL=="ttyACM0", SYMLINK+="modem"
265 EOF
266         },
267         {
268                 desc            => "sustitution of sysfs value (%s{file})",
269                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
270                 exp_name        => "disk-ATA-sda" ,
271                 rules           => <<EOF
272 SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", SYMLINK+="disk-%s{vendor}-%k"
273 KERNEL=="ttyACM0", SYMLINK+="modem"
274 EOF
275         },
276         {
277                 desc            => "program result substitution",
278                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
279                 exp_name        => "special-device-5" ,
280                 not_exp_name    => "not" ,
281                 rules           => <<EOF
282 SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n special-device", RESULT=="-special-*", SYMLINK+="not"
283 SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n special-device", RESULT=="special-*", SYMLINK+="%c-%n"
284 EOF
285         },
286         {
287                 desc            => "program result substitution (newline removal)",
288                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
289                 exp_name        => "newline_removed" ,
290                 rules           => <<EOF
291 SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo test", RESULT=="test", SYMLINK+="newline_removed"
292 EOF
293         },
294         {
295                 desc            => "program result substitution",
296                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
297                 exp_name        => "test-0:0:0:0" ,
298                 rules           => <<EOF
299 SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n test-%b", RESULT=="test-0:0*", SYMLINK+="%c"
300 EOF
301         },
302         {
303                 desc            => "program with lots of arguments",
304                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
305                 exp_name        => "foo9" ,
306                 rules           => <<EOF
307 SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n foo3 foo4 foo5 foo6 foo7 foo8 foo9", KERNEL=="sda5", SYMLINK+="%c{7}"
308 EOF
309         },
310         {
311                 desc            => "program with subshell",
312                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
313                 exp_name        => "bar9" ,
314                 rules           => <<EOF
315 SUBSYSTEMS=="scsi", PROGRAM=="/bin/sh -c 'echo foo3 foo4 foo5 foo6 foo7 foo8 foo9 | sed  s/foo9/bar9/'", KERNEL=="sda5", SYMLINK+="%c{7}"
316 EOF
317         },
318         {
319                 desc            => "program arguments combined with apostrophes",
320                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
321                 exp_name        => "foo7" ,
322                 rules           => <<EOF
323 SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n 'foo3 foo4'   'foo5   foo6   foo7 foo8'", KERNEL=="sda5", SYMLINK+="%c{5}"
324 EOF
325         },
326         {
327                 desc            => "characters before the %c{N} substitution",
328                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
329                 exp_name        => "my-foo9" ,
330                 rules           => <<EOF
331 SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n foo3 foo4 foo5 foo6 foo7 foo8 foo9", KERNEL=="sda5", SYMLINK+="my-%c{7}"
332 EOF
333         },
334         {
335                 desc            => "substitute the second to last argument",
336                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
337                 exp_name        => "my-foo8" ,
338                 rules           => <<EOF
339 SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n foo3 foo4 foo5 foo6 foo7 foo8 foo9", KERNEL=="sda5", SYMLINK+="my-%c{6}"
340 EOF
341         },
342         {
343                 desc            => "test substitution by variable name",
344                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
345                 exp_name        => "Major:8-minor:5-kernelnumber:5-id:0:0:0:0",
346                 rules           => <<EOF
347 SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", SYMLINK+="Major:\$major-minor:\$minor-kernelnumber:\$number-id:\$id"
348 EOF
349         },
350         {
351                 desc            => "test substitution by variable name 2",
352                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
353                 exp_name        => "Major:8-minor:5-kernelnumber:5-id:0:0:0:0",
354                 rules           => <<EOF
355 SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", DEVPATH=="*/sda/*", SYMLINK+="Major:\$major-minor:%m-kernelnumber:\$number-id:\$id"
356 EOF
357         },
358         {
359                 desc            => "test substitution by variable name 3",
360                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
361                 exp_name        => "850:0:0:05" ,
362                 rules           => <<EOF
363 SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", DEVPATH=="*/sda/*", SYMLINK+="%M%m%b%n"
364 EOF
365         },
366         {
367                 desc            => "test substitution by variable name 4",
368                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
369                 exp_name        => "855" ,
370                 rules           => <<EOF
371 SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", DEVPATH=="*/sda/*", SYMLINK+="\$major\$minor\$number"
372 EOF
373         },
374         {
375                 desc            => "test substitution by variable name 5",
376                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
377                 exp_name        => "8550:0:0:0" ,
378                 rules           => <<EOF
379 SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", DEVPATH=="*/sda/*", SYMLINK+="\$major%m%n\$id"
380 EOF
381         },
382         {
383                 desc            => "non matching SUBSYSTEMS for device with no parent",
384                 devpath         => "/devices/virtual/tty/console",
385                 exp_name        => "TTY",
386                 rules           => <<EOF
387 SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n foo", RESULT=="foo", SYMLINK+="foo"
388 KERNEL=="console", SYMLINK+="TTY"
389 EOF
390         },
391         {
392                 desc            => "non matching SUBSYSTEMS",
393                 devpath         => "/devices/virtual/tty/console",
394                 exp_name        => "TTY" ,
395                 rules                => <<EOF
396 SUBSYSTEMS=="foo", ATTRS{dev}=="5:1", SYMLINK+="foo"
397 KERNEL=="console", SYMLINK+="TTY"
398 EOF
399         },
400         {
401                 desc            => "ATTRS match",
402                 devpath         => "/devices/virtual/tty/console",
403                 exp_name        => "foo" ,
404                 rules           => <<EOF
405 KERNEL=="console", SYMLINK+="TTY"
406 ATTRS{dev}=="5:1", SYMLINK+="foo"
407 EOF
408         },
409         {
410                 desc            => "ATTR (empty file)",
411                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
412                 exp_name        => "empty" ,
413                 rules           => <<EOF
414 KERNEL=="sda", ATTR{test_empty_file}=="?*", SYMLINK+="something"
415 KERNEL=="sda", ATTR{test_empty_file}!="", SYMLINK+="not-empty"
416 KERNEL=="sda", ATTR{test_empty_file}=="", SYMLINK+="empty"
417 KERNEL=="sda", ATTR{test_empty_file}!="?*", SYMLINK+="not-something"
418 EOF
419         },
420         {
421                 desc            => "ATTR (non-existent file)",
422                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
423                 exp_name        => "non-existent" ,
424                 rules           => <<EOF
425 KERNEL=="sda", ATTR{nofile}=="?*", SYMLINK+="something"
426 KERNEL=="sda", ATTR{nofile}!="", SYMLINK+="not-empty"
427 KERNEL=="sda", ATTR{nofile}=="", SYMLINK+="empty"
428 KERNEL=="sda", ATTR{nofile}!="?*", SYMLINK+="not-something"
429 KERNEL=="sda", TEST!="nofile", SYMLINK+="non-existent"
430 KERNEL=="sda", SYMLINK+="wrong"
431 EOF
432         },
433         {
434                 desc            => "program and bus type match",
435                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
436                 exp_name        => "scsi-0:0:0:0" ,
437                 rules           => <<EOF
438 SUBSYSTEMS=="usb", PROGRAM=="/bin/echo -n usb-%b", SYMLINK+="%c"
439 SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n scsi-%b", SYMLINK+="%c"
440 SUBSYSTEMS=="foo", PROGRAM=="/bin/echo -n foo-%b", SYMLINK+="%c"
441 EOF
442         },
443         {
444                 desc            => "sysfs parent hierarchy",
445                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
446                 exp_name        => "modem" ,
447                 rules           => <<EOF
448 ATTRS{idProduct}=="007b", SYMLINK+="modem"
449 EOF
450         },
451         {
452                 desc            => "name test with ! in the name",
453                 devpath         => "/devices/virtual/block/fake!blockdev0",
454                 exp_name        => "is/a/fake/blockdev0" ,
455                 rules           => <<EOF
456 SUBSYSTEMS=="scsi", SYMLINK+="is/not/a/%k"
457 SUBSYSTEM=="block", SYMLINK+="is/a/%k"
458 KERNEL=="ttyACM0", SYMLINK+="modem"
459 EOF
460         },
461         {
462                 desc            => "name test with ! in the name, but no matching rule",
463                 devpath         => "/devices/virtual/block/fake!blockdev0",
464                 exp_name        => "fake/blockdev0" ,
465                 exp_rem_error   => "yes",
466                 rules           => <<EOF
467 KERNEL=="ttyACM0", SYMLINK+="modem"
468 EOF
469         },
470         {
471                 desc            => "KERNELS rule",
472                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
473                 exp_name        => "scsi-0:0:0:0",
474                 rules           => <<EOF
475 SUBSYSTEMS=="usb", KERNELS=="0:0:0:0", SYMLINK+="not-scsi"
476 SUBSYSTEMS=="scsi", KERNELS=="0:0:0:1", SYMLINK+="no-match"
477 SUBSYSTEMS=="scsi", KERNELS==":0", SYMLINK+="short-id"
478 SUBSYSTEMS=="scsi", KERNELS=="/0:0:0:0", SYMLINK+="no-match"
479 SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", SYMLINK+="scsi-0:0:0:0"
480 EOF
481         },
482         {
483                 desc            => "KERNELS wildcard all",
484                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
485                 exp_name        => "scsi-0:0:0:0",
486                 rules           => <<EOF
487 SUBSYSTEMS=="scsi", KERNELS=="*:1", SYMLINK+="no-match"
488 SUBSYSTEMS=="scsi", KERNELS=="*:0:1", SYMLINK+="no-match"
489 SUBSYSTEMS=="scsi", KERNELS=="*:0:0:1", SYMLINK+="no-match"
490 SUBSYSTEMS=="scsi", KERNEL=="0:0:0:0", SYMLINK+="before"
491 SUBSYSTEMS=="scsi", KERNELS=="*", SYMLINK+="scsi-0:0:0:0"
492 EOF
493         },
494         {
495                 desc            => "KERNELS wildcard partial",
496                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
497                 exp_name        => "scsi-0:0:0:0",
498                 rules           => <<EOF
499 SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", SYMLINK+="before"
500 SUBSYSTEMS=="scsi", KERNELS=="*:0", SYMLINK+="scsi-0:0:0:0"
501 EOF
502         },
503         {
504                 desc            => "KERNELS wildcard partial 2",
505                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
506                 exp_name        => "scsi-0:0:0:0",
507                 rules                => <<EOF
508 SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", SYMLINK+="before"
509 SUBSYSTEMS=="scsi", KERNELS=="*:0:0:0", SYMLINK+="scsi-0:0:0:0"
510 EOF
511         },
512         {
513                 desc            => "substitute attr with link target value (first match)",
514                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
515                 exp_name        => "driver-is-sd",
516                 rules           => <<EOF
517 SUBSYSTEMS=="scsi", SYMLINK+="driver-is-\$attr{driver}"
518 EOF
519         },
520         {
521                 desc            => "substitute attr with link target value (currently selected device)",
522                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
523                 exp_name        => "driver-is-ahci",
524                 rules           => <<EOF
525 SUBSYSTEMS=="pci", SYMLINK+="driver-is-\$attr{driver}"
526 EOF
527         },
528         {
529                 desc            => "ignore ATTRS attribute whitespace",
530                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
531                 exp_name        => "ignored",
532                 rules           => <<EOF
533 SUBSYSTEMS=="scsi", ATTRS{whitespace_test}=="WHITE  SPACE", SYMLINK+="ignored"
534 EOF
535         },
536         {
537                 desc            => "do not ignore ATTRS attribute whitespace",
538                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
539                 exp_name        => "matched-with-space",
540                 rules           => <<EOF
541 SUBSYSTEMS=="scsi", ATTRS{whitespace_test}=="WHITE  SPACE ", SYMLINK+="wrong-to-ignore"
542 SUBSYSTEMS=="scsi", ATTRS{whitespace_test}=="WHITE  SPACE   ", SYMLINK+="matched-with-space"
543 EOF
544         },
545         {
546                 desc            => "permissions USER=bad GROUP=name",
547                 devpath         => "/devices/virtual/tty/tty33",
548                 exp_name        => "tty33",
549                 exp_perms       => "0:0:0600",
550                 rules           => <<EOF
551 KERNEL=="tty33", OWNER="bad", GROUP="name"
552 EOF
553         },
554         {
555                 desc            => "permissions OWNER=1",
556                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
557                 exp_name        => "node",
558                 exp_perms       => "1::0600",
559                 rules           => <<EOF
560 SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", OWNER="1"
561 EOF
562         },
563         {
564                 desc            => "permissions GROUP=1",
565                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
566                 exp_name        => "node",
567                 exp_perms       => ":1:0660",
568                 rules           => <<EOF
569 SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", GROUP="1"
570 EOF
571         },
572         {
573                 desc            => "textual user id",
574                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
575                 exp_name        => "node",
576                 exp_perms       => "nobody::0600",
577                 rules           => <<EOF
578 SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", OWNER="nobody"
579 EOF
580         },
581         {
582                 desc            => "textual group id",
583                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
584                 exp_name        => "node",
585                 exp_perms       => ":daemon:0660",
586                 rules           => <<EOF
587 SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", GROUP="daemon"
588 EOF
589         },
590         {
591                 desc            => "textual user/group id",
592                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
593                 exp_name        => "node",
594                 exp_perms       => "root:mail:0660",
595                 rules           => <<EOF
596 SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", OWNER="root", GROUP="mail"
597 EOF
598         },
599         {
600                 desc            => "permissions MODE=0777",
601                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
602                 exp_name        => "node",
603                 exp_perms       => "::0777",
604                 rules           => <<EOF
605 SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", MODE="0777"
606 EOF
607         },
608         {
609                 desc            => "permissions OWNER=1 GROUP=1 MODE=0777",
610                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
611                 exp_name        => "node",
612                 exp_perms       => "1:1:0777",
613                 rules           => <<EOF
614 SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", OWNER="1", GROUP="1", MODE="0777"
615 EOF
616         },
617         {
618                 desc            => "permissions OWNER to 1",
619                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
620                 exp_name        => "ttyACM0",
621                 exp_perms       => "1::",
622                 rules           => <<EOF
623 KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", OWNER="1"
624 EOF
625         },
626         {
627                 desc            => "permissions GROUP to 1",
628                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
629                 exp_name        => "ttyACM0",
630                 exp_perms       => ":1:0660",
631                 rules           => <<EOF
632 KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", GROUP="1"
633 EOF
634         },
635         {
636                 desc            => "permissions MODE to 0060",
637                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
638                 exp_name        => "ttyACM0",
639                 exp_perms       => "::0060",
640                 rules           => <<EOF
641 KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", MODE="0060"
642 EOF
643         },
644         {
645                 desc            => "permissions OWNER, GROUP, MODE",
646                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
647                 exp_name        => "ttyACM0",
648                 exp_perms       => "1:1:0777",
649                 rules           => <<EOF
650 KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", OWNER="1", GROUP="1", MODE="0777"
651 EOF
652         },
653         {
654                 desc            => "permissions only rule",
655                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
656                 exp_name        => "ttyACM0",
657                 exp_perms       => "1:1:0777",
658                 rules           => <<EOF
659 KERNEL=="ttyACM[0-9]*", OWNER="1", GROUP="1", MODE="0777"
660 KERNEL=="ttyUSX[0-9]*", OWNER="2", GROUP="2", MODE="0444"
661 KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n"
662 EOF
663         },
664         {
665                 desc            => "multiple permissions only rule",
666                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
667                 exp_name        => "ttyACM0",
668                 exp_perms       => "1:1:0777",
669                 rules           => <<EOF
670 SUBSYSTEM=="tty", OWNER="1"
671 SUBSYSTEM=="tty", GROUP="1"
672 SUBSYSTEM=="tty", MODE="0777"
673 KERNEL=="ttyUSX[0-9]*", OWNER="2", GROUP="2", MODE="0444"
674 KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n"
675 EOF
676         },
677         {
678                 desc            => "permissions only rule with override at SYMLINK+ rule",
679                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
680                 exp_name        => "ttyACM0",
681                 exp_perms       => "1:2:0777",
682                 rules           => <<EOF
683 SUBSYSTEM=="tty", OWNER="1"
684 SUBSYSTEM=="tty", GROUP="1"
685 SUBSYSTEM=="tty", MODE="0777"
686 KERNEL=="ttyUSX[0-9]*", OWNER="2", GROUP="2", MODE="0444"
687 KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", GROUP="2"
688 EOF
689         },
690         {
691                 desc            => "major/minor number test",
692                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
693                 exp_name        => "node",
694                 exp_majorminor  => "8:0",
695                 rules           => <<EOF
696 SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node"
697 EOF
698         },
699         {
700                 desc            => "big major number test",
701                 devpath         => "/devices/virtual/misc/misc-fake1",
702                 exp_name        => "node",
703                 exp_majorminor  => "4095:1",
704                 rules                => <<EOF
705 KERNEL=="misc-fake1", SYMLINK+="node"
706 EOF
707         },
708         {
709                 desc            => "big major and big minor number test",
710                 devpath         => "/devices/virtual/misc/misc-fake89999",
711                 exp_name        => "node",
712                 exp_majorminor  => "4095:89999",
713                 rules           => <<EOF
714 KERNEL=="misc-fake89999", SYMLINK+="node"
715 EOF
716         },
717         {
718                 desc            => "multiple symlinks with format char",
719                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
720                 exp_name        => "symlink2-ttyACM0",
721                 rules           => <<EOF
722 KERNEL=="ttyACM[0-9]*", SYMLINK="symlink1-%n symlink2-%k symlink3-%b"
723 EOF
724         },
725         {
726                 desc            => "multiple symlinks with a lot of s p a c e s",
727                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
728                 exp_name        => "one",
729                 not_exp_name        => " ",
730                 rules           => <<EOF
731 KERNEL=="ttyACM[0-9]*", SYMLINK="  one     two        "
732 EOF
733         },
734         {
735                 desc            => "symlink creation (same directory)",
736                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
737                 exp_name        => "modem0",
738                 rules           => <<EOF
739 KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", SYMLINK="modem%n"
740 EOF
741         },
742         {
743                 desc            => "multiple symlinks",
744                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
745                 exp_name        => "second-0" ,
746                 rules           => <<EOF
747 KERNEL=="ttyACM0", SYMLINK="first-%n second-%n third-%n"
748 EOF
749         },
750         {
751                 desc            => "symlink name '.'",
752                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
753                 exp_name        => ".",
754                 exp_add_error        => "yes",
755                 exp_rem_error        => "yes",
756                 rules           => <<EOF
757 SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="."
758 EOF
759         },
760         {
761                 desc            => "symlink node to itself",
762                 devpath         => "/devices/virtual/tty/tty0",
763                 exp_name        => "link",
764                 exp_add_error        => "yes",
765                 exp_rem_error        => "yes",
766                 option                => "clean",
767                 rules           => <<EOF
768 KERNEL=="tty0", SYMLINK+="tty0"
769 EOF
770         },
771         {
772                 desc            => "symlink %n substitution",
773                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
774                 exp_name        => "symlink0",
775                 rules           => <<EOF
776 KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", SYMLINK+="symlink%n"
777 EOF
778         },
779         {
780                 desc            => "symlink %k substitution",
781                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
782                 exp_name        => "symlink-ttyACM0",
783                 rules           => <<EOF
784 KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", SYMLINK+="symlink-%k"
785 EOF
786         },
787         {
788                 desc            => "symlink %M:%m substitution",
789                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
790                 exp_name        => "major-166:0",
791                 rules           => <<EOF
792 KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", SYMLINK+="major-%M:%m"
793 EOF
794         },
795         {
796                 desc            => "symlink %b substitution",
797                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
798                 exp_name        => "symlink-0:0:0:0",
799                 rules           => <<EOF
800 SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="symlink-%b"
801 EOF
802         },
803         {
804                 desc            => "symlink %c substitution",
805                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
806                 exp_name        => "test",
807                 rules           => <<EOF
808 KERNEL=="ttyACM[0-9]*", PROGRAM=="/bin/echo test", SYMLINK+="%c"
809 EOF
810         },
811         {
812                 desc            => "symlink %c{N} substitution",
813                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
814                 exp_name        => "test",
815                 rules           => <<EOF
816 KERNEL=="ttyACM[0-9]*", PROGRAM=="/bin/echo symlink test this", SYMLINK+="%c{2}"
817 EOF
818         },
819         {
820                 desc            => "symlink %c{N+} substitution",
821                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
822                 exp_name        => "this",
823                 rules           => <<EOF
824 KERNEL=="ttyACM[0-9]*", PROGRAM=="/bin/echo symlink test this", SYMLINK+="%c{2+}"
825 EOF
826         },
827         {
828                 desc            => "symlink only rule with %c{N+}",
829                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
830                 exp_name        => "test",
831                 rules           => <<EOF
832 SUBSYSTEMS=="scsi", KERNEL=="sda", PROGRAM=="/bin/echo link test this" SYMLINK+="%c{2+}"
833 EOF
834         },
835         {
836                 desc            => "symlink %s{filename} substitution",
837                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
838                 exp_name        => "166:0",
839                 rules           => <<EOF
840 KERNEL=="ttyACM[0-9]*", SYMLINK+="%s{dev}"
841 EOF
842         },
843         {
844                 desc            => "program result substitution (numbered part of)",
845                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
846                 exp_name        => "link1",
847                 rules           => <<EOF
848 SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n node link1 link2", RESULT=="node *", SYMLINK+="%c{2} %c{3}"
849 EOF
850         },
851         {
852                 desc            => "program result substitution (numbered part of+)",
853                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
854                 exp_name        => "link4",
855                 rules           => <<EOF
856 SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n node link1 link2 link3 link4", RESULT=="node *", SYMLINK+="%c{2+}"
857 EOF
858         },
859         {
860                 desc            => "SUBSYSTEM match test",
861                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
862                 exp_name        => "node",
863                 rules           => <<EOF
864 SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="should_not_match", SUBSYSTEM=="vc"
865 SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", SUBSYSTEM=="block"
866 SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="should_not_match2", SUBSYSTEM=="vc"
867 EOF
868         },
869         {
870                 desc            => "DRIVERS match test",
871                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
872                 exp_name        => "node",
873                 rules           => <<EOF
874 SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="should_not_match", DRIVERS=="sd-wrong"
875 SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", DRIVERS=="sd"
876 EOF
877         },
878         {
879                 desc            => "devnode substitution test",
880                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
881                 exp_name        => "node",
882                 rules           => <<EOF
883 SUBSYSTEMS=="scsi", KERNEL=="sda", PROGRAM=="/usr/bin/test -b %N" SYMLINK+="node"
884 EOF
885         },
886         {
887                 desc            => "parent node name substitution test",
888                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
889                 exp_name        => "sda-part-1",
890                 rules           => <<EOF
891 SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="%P-part-1"
892 EOF
893         },
894         {
895                 desc            => "udev_root substitution",
896                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
897                 exp_name        => "start-/dev-end",
898                 rules           => <<EOF
899 SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="start-%r-end"
900 EOF
901         },
902         {
903                 desc            => "last_rule option",
904                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
905                 exp_name        => "last",
906                 rules           => <<EOF
907 SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="last", OPTIONS="last_rule"
908 SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="very-last"
909 EOF
910         },
911         {
912                 desc            => "negation KERNEL!=",
913                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
914                 exp_name        => "match",
915                 rules           => <<EOF
916 SUBSYSTEMS=="scsi", KERNEL!="sda1", SYMLINK+="matches-but-is-negated"
917 SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="before"
918 SUBSYSTEMS=="scsi", KERNEL!="xsda1", SYMLINK+="match"
919 EOF
920         },
921         {
922                 desc            => "negation SUBSYSTEM!=",
923                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
924                 exp_name        => "not-anything",
925                 rules           => <<EOF
926 SUBSYSTEMS=="scsi", SUBSYSTEM=="block", KERNEL!="sda1", SYMLINK+="matches-but-is-negated"
927 SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="before"
928 SUBSYSTEMS=="scsi", SUBSYSTEM!="anything", SYMLINK+="not-anything"
929 EOF
930         },
931         {
932                 desc            => "negation PROGRAM!= exit code",
933                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
934                 exp_name        => "nonzero-program",
935                 rules           => <<EOF
936 SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="before"
937 KERNEL=="sda1", PROGRAM!="/bin/false", SYMLINK+="nonzero-program"
938 EOF
939         },
940         {
941                 desc            => "ENV{} test",
942                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
943                 exp_name        => "true",
944                 rules           => <<EOF
945 ENV{ENV_KEY_TEST}="test"
946 SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ENV_KEY_TEST}=="go", SYMLINK+="wrong"
947 SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ENV_KEY_TEST}=="test", SYMLINK+="true"
948 SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ENV_KEY_TEST}=="bad", SYMLINK+="bad"
949 EOF
950         },
951         {
952                 desc            => "ENV{} test",
953                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
954                 exp_name        => "true",
955                 rules           => <<EOF
956 ENV{ENV_KEY_TEST}="test"
957 SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ENV_KEY_TEST}=="go", SYMLINK+="wrong"
958 SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ENV_KEY_TEST}=="yes", ENV{ACTION}=="add", ENV{DEVPATH}=="*/block/sda/sdax1", SYMLINK+="no"
959 SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ENV_KEY_TEST}=="test", ENV{ACTION}=="add", ENV{DEVPATH}=="*/block/sda/sda1", SYMLINK+="true"
960 SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ENV_KEY_TEST}=="bad", SYMLINK+="bad"
961 EOF
962         },
963         {
964                 desc            => "ENV{} test (assign)",
965                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
966                 exp_name        => "true",
967                 rules           => <<EOF
968 SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ASSIGN}="true"
969 SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ASSIGN}=="yes", SYMLINK+="no"
970 SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="before"
971 SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ASSIGN}=="true", SYMLINK+="true"
972 EOF
973         },
974         {
975                 desc            => "ENV{} test (assign 2 times)",
976                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
977                 exp_name        => "true",
978                 rules           => <<EOF
979 SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ASSIGN}="true"
980 SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ASSIGN}="absolutely-\$env{ASSIGN}"
981 SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="before"
982 SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ASSIGN}=="yes", SYMLINK+="no"
983 SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ASSIGN}=="absolutely-true", SYMLINK+="true"
984 EOF
985         },
986         {
987                 desc            => "ENV{} test (assign2)",
988                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
989                 exp_name        => "part",
990                 rules           => <<EOF
991 SUBSYSTEM=="block", KERNEL=="*[0-9]", ENV{PARTITION}="true", ENV{MAINDEVICE}="false"
992 SUBSYSTEM=="block", KERNEL=="*[!0-9]", ENV{PARTITION}="false", ENV{MAINDEVICE}="true"
993 ENV{MAINDEVICE}=="true", SYMLINK+="disk"
994 SUBSYSTEM=="block", SYMLINK+="before"
995 ENV{PARTITION}=="true", SYMLINK+="part"
996 EOF
997         },
998         {
999                 desc            => "untrusted string sanitize",
1000                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
1001                 exp_name        => "sane",
1002                 rules           => <<EOF
1003 SUBSYSTEMS=="scsi", KERNEL=="sda1", PROGRAM=="/bin/echo -e name; (/usr/bin/badprogram)", RESULT=="name_ _/usr/bin/badprogram_", SYMLINK+="sane"
1004 EOF
1005         },
1006         {
1007                 desc            => "untrusted string sanitize (don't replace utf8)",
1008                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
1009                 exp_name        => "uber",
1010                 rules           => <<EOF
1011 SUBSYSTEMS=="scsi", KERNEL=="sda1", PROGRAM=="/bin/echo -e \\xc3\\xbcber" RESULT=="\xc3\xbcber", SYMLINK+="uber"
1012 EOF
1013         },
1014         {
1015                 desc            => "untrusted string sanitize (replace invalid utf8)",
1016                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
1017                 exp_name        => "replaced",
1018                 rules           => <<EOF
1019 SUBSYSTEMS=="scsi", KERNEL=="sda1", PROGRAM=="/bin/echo -e \\xef\\xe8garbage", RESULT=="__garbage", SYMLINK+="replaced"
1020 EOF
1021         },
1022         {
1023                 desc            => "read sysfs value from parent device",
1024                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1025                 exp_name        => "serial-354172020305000",
1026                 rules           => <<EOF
1027 KERNEL=="ttyACM*", ATTRS{serial}=="?*", SYMLINK+="serial-%s{serial}"
1028 EOF
1029         },
1030         {
1031                 desc            => "match against empty key string",
1032                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1033                 exp_name        => "ok",
1034                 rules           => <<EOF
1035 KERNEL=="sda", ATTRS{nothing}!="", SYMLINK+="not-1-ok"
1036 KERNEL=="sda", ATTRS{nothing}=="", SYMLINK+="not-2-ok"
1037 KERNEL=="sda", ATTRS{vendor}!="", SYMLINK+="ok"
1038 KERNEL=="sda", ATTRS{vendor}=="", SYMLINK+="not-3-ok"
1039 EOF
1040         },
1041         {
1042                 desc            => "check ACTION value",
1043                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1044                 exp_name        => "ok",
1045                 rules           => <<EOF
1046 ACTION=="unknown", KERNEL=="sda", SYMLINK+="unknown-not-ok"
1047 ACTION=="add", KERNEL=="sda", SYMLINK+="ok"
1048 EOF
1049         },
1050         {
1051                 desc            => "final assignment",
1052                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1053                 exp_name        => "ok",
1054                 exp_perms       => "root:tty:0640",
1055                 rules           => <<EOF
1056 KERNEL=="sda", GROUP:="tty"
1057 KERNEL=="sda", GROUP="not-ok", MODE="0640", SYMLINK+="ok"
1058 EOF
1059         },
1060         {
1061                 desc            => "final assignment 2",
1062                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1063                 exp_name        => "ok",
1064                 exp_perms       => "root:tty:0640",
1065                 rules           => <<EOF
1066 KERNEL=="sda", GROUP:="tty"
1067 SUBSYSTEM=="block", MODE:="640"
1068 KERNEL=="sda", GROUP="not-ok", MODE="0666", SYMLINK+="ok"
1069 EOF
1070         },
1071         {
1072                 desc            => "env substitution",
1073                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1074                 exp_name        => "node-add-me",
1075                 rules           => <<EOF
1076 KERNEL=="sda", MODE="0666", SYMLINK+="node-\$env{ACTION}-me"
1077 EOF
1078         },
1079         {
1080                 desc            => "reset list to current value",
1081                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1082                 exp_name        => "three",
1083                 not_exp_name    => "two",
1084                 rules           => <<EOF
1085 KERNEL=="ttyACM[0-9]*", SYMLINK+="one"
1086 KERNEL=="ttyACM[0-9]*", SYMLINK+="two"
1087 KERNEL=="ttyACM[0-9]*", SYMLINK="three"
1088 EOF
1089         },
1090         {
1091                 desc            => "test empty SYMLINK+ (empty override)",
1092                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1093                 exp_name        => "right",
1094                 not_exp_name    => "wrong",
1095                 rules           => <<EOF
1096 KERNEL=="ttyACM[0-9]*", SYMLINK+="wrong"
1097 KERNEL=="ttyACM[0-9]*", SYMLINK=""
1098 KERNEL=="ttyACM[0-9]*", SYMLINK+="right"
1099 EOF
1100         },
1101         {
1102                 desc            => "test multi matches",
1103                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1104                 exp_name        => "right",
1105                 rules           => <<EOF
1106 KERNEL=="ttyACM*", SYMLINK+="before"
1107 KERNEL=="ttyACM*|nothing", SYMLINK+="right"
1108 EOF
1109         },
1110         {
1111                 desc            => "test multi matches 2",
1112                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1113                 exp_name        => "right",
1114                 rules           => <<EOF
1115 KERNEL=="dontknow*|*nothing", SYMLINK+="nomatch"
1116 KERNEL=="ttyACM*", SYMLINK+="before"
1117 KERNEL=="dontknow*|ttyACM*|nothing*", SYMLINK+="right"
1118 EOF
1119         },
1120         {
1121                 desc            => "test multi matches 3",
1122                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1123                 exp_name        => "right",
1124                 rules           => <<EOF
1125 KERNEL=="dontknow|nothing", SYMLINK+="nomatch"
1126 KERNEL=="dontknow|ttyACM0a|nothing|attyACM0", SYMLINK+="wrong1"
1127 KERNEL=="X|attyACM0|dontknow|ttyACM0a|nothing|attyACM0", SYMLINK+="wrong2"
1128 KERNEL=="dontknow|ttyACM0|nothing", SYMLINK+="right"
1129 EOF
1130         },
1131         {
1132                 desc            => "test multi matches 4",
1133                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1134                 exp_name        => "right",
1135                 rules           => <<EOF
1136 KERNEL=="dontknow|nothing", SYMLINK+="nomatch"
1137 KERNEL=="dontknow|ttyACM0a|nothing|attyACM0", SYMLINK+="wrong1"
1138 KERNEL=="X|attyACM0|dontknow|ttyACM0a|nothing|attyACM0", SYMLINK+="wrong2"
1139 KERNEL=="all|dontknow|ttyACM0", SYMLINK+="right"
1140 KERNEL=="ttyACM0a|nothing", SYMLINK+="wrong3"
1141 EOF
1142         },
1143         {
1144                 desc            => "IMPORT parent test sequence 1/2 (keep)",
1145                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1146                 exp_name        => "parent",
1147                 option          => "keep",
1148                 rules           => <<EOF
1149 KERNEL=="sda", IMPORT{program}="/bin/echo -e \'PARENT_KEY=parent_right\\nWRONG_PARENT_KEY=parent_wrong'"
1150 KERNEL=="sda", SYMLINK+="parent"
1151 EOF
1152         },
1153         {
1154                 desc            => "IMPORT parent test sequence 2/2 (keep)",
1155                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
1156                 exp_name        => "parentenv-parent_right",
1157                 option          => "clean",
1158                 rules           => <<EOF
1159 KERNEL=="sda1", IMPORT{parent}="PARENT*", SYMLINK+="parentenv-\$env{PARENT_KEY}\$env{WRONG_PARENT_KEY}"
1160 EOF
1161         },
1162         {
1163                 desc            => "GOTO test",
1164                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
1165                 exp_name        => "right",
1166                 rules           => <<EOF
1167 KERNEL=="sda1", GOTO="TEST"
1168 KERNEL=="sda1", SYMLINK+="wrong"
1169 KERNEL=="sda1", GOTO="BAD"
1170 KERNEL=="sda1", SYMLINK+="", LABEL="NO"
1171 KERNEL=="sda1", SYMLINK+="right", LABEL="TEST", GOTO="end"
1172 KERNEL=="sda1", SYMLINK+="wrong2", LABEL="BAD"
1173 LABEL="end"
1174 EOF
1175         },
1176         {
1177                 desc            => "GOTO label does not exist",
1178                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
1179                 exp_name        => "right",
1180                 rules           => <<EOF
1181 KERNEL=="sda1", GOTO="does-not-exist"
1182 KERNEL=="sda1", SYMLINK+="right",
1183 LABEL="exists"
1184 EOF
1185         },
1186         {
1187                 desc            => "SYMLINK+ compare test",
1188                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
1189                 exp_name        => "right",
1190                 not_exp_name    => "wrong",
1191                 rules           => <<EOF
1192 KERNEL=="sda1", SYMLINK+="link"
1193 KERNEL=="sda1", SYMLINK=="link*", SYMLINK+="right"
1194 KERNEL=="sda1", SYMLINK=="nolink*", SYMLINK+="wrong"
1195 EOF
1196         },
1197         {
1198                 desc            => "invalid key operation",
1199                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
1200                 exp_name        => "yes",
1201                 rules           => <<EOF
1202 KERNEL="sda1", SYMLINK+="no"
1203 KERNEL=="sda1", SYMLINK+="yes"
1204 EOF
1205         },
1206         {
1207                 desc            => "operator chars in attribute",
1208                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1209                 exp_name        => "yes",
1210                 rules           => <<EOF
1211 KERNEL=="sda", ATTR{test:colon+plus}=="?*", SYMLINK+="yes"
1212 EOF
1213         },
1214         {
1215                 desc            => "overlong comment line",
1216                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
1217                 exp_name        => "yes",
1218                 rules           => <<EOF
1219 # 012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
1220    # 012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
1221 KERNEL=="sda1", SYMLINK+=="no"
1222 KERNEL=="sda1", SYMLINK+="yes"
1223 EOF
1224         },
1225         {
1226                 desc            => "magic subsys/kernel lookup",
1227                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1228                 exp_name        => "00:16:41:e2:8d:ff",
1229                 rules           => <<EOF
1230 KERNEL=="sda", SYMLINK+="\$attr{[net/eth0]address}"
1231 EOF
1232         },
1233         {
1234                 desc            => "TEST absolute path",
1235                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1236                 exp_name        => "there",
1237                 rules           => <<EOF
1238 TEST=="/etc/machine-id", SYMLINK+="there"
1239 TEST!="/etc/machine-id", SYMLINK+="notthere"
1240 EOF
1241         },
1242         {
1243                 desc            => "TEST subsys/kernel lookup",
1244                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1245                 exp_name        => "yes",
1246                 rules           => <<EOF
1247 KERNEL=="sda", TEST=="[net/eth0]", SYMLINK+="yes"
1248 EOF
1249         },
1250         {
1251                 desc            => "TEST relative path",
1252                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1253                 exp_name        => "relative",
1254                 rules           => <<EOF
1255 KERNEL=="sda", TEST=="size", SYMLINK+="relative"
1256 EOF
1257         },
1258         {
1259                 desc            => "TEST wildcard substitution (find queue/nr_requests)",
1260                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1261                 exp_name        => "found-subdir",
1262                 rules           => <<EOF
1263 KERNEL=="sda", TEST=="*/nr_requests", SYMLINK+="found-subdir"
1264 EOF
1265         },
1266         {
1267                 desc            => "TEST MODE=0000",
1268                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1269                 exp_name        => "sda",
1270                 exp_perms       => "0:0:0000",
1271                 exp_rem_error   => "yes",
1272                 rules           => <<EOF
1273 KERNEL=="sda", MODE="0000"
1274 EOF
1275         },
1276         {
1277                 desc            => "TEST PROGRAM feeds OWNER, GROUP, MODE",
1278                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1279                 exp_name        => "sda",
1280                 exp_perms       => "1:1:0400",
1281                 exp_rem_error   => "yes",
1282                 rules           => <<EOF
1283 KERNEL=="sda", MODE="666"
1284 KERNEL=="sda", PROGRAM=="/bin/echo 1 1 0400", OWNER="%c{1}", GROUP="%c{2}", MODE="%c{3}"
1285 EOF
1286         },
1287         {
1288                 desc            => "TEST PROGRAM feeds MODE with overflow",
1289                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1290                 exp_name        => "sda",
1291                 exp_perms       => "0:0:0440",
1292                 exp_rem_error   => "yes",
1293                 rules           => <<EOF
1294 KERNEL=="sda", MODE="440"
1295 KERNEL=="sda", PROGRAM=="/bin/echo 0 0 0400letsdoabuffferoverflow0123456789012345789012345678901234567890", OWNER="%c{1}", GROUP="%c{2}", MODE="%c{3}"
1296 EOF
1297         },
1298         {
1299                 desc            => "magic [subsys/sysname] attribute substitution",
1300                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1301                 exp_name        => "sda-8741C4G-end",
1302                 exp_perms       => "0:0:0600",
1303                 rules           => <<EOF
1304 KERNEL=="sda", PROGRAM="/bin/true create-envp"
1305 KERNEL=="sda", ENV{TESTENV}="change-envp"
1306 KERNEL=="sda", SYMLINK+="%k-%s{[dmi/id]product_name}-end"
1307 EOF
1308         },
1309         {
1310                 desc            => "builtin path_id",
1311                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1312                 exp_name        => "disk/by-path/pci-0000:00:1f.2-scsi-0:0:0:0",
1313                 rules           => <<EOF
1314 KERNEL=="sda", IMPORT{builtin}="path_id"
1315 KERNEL=="sda", ENV{ID_PATH}=="?*", SYMLINK+="disk/by-path/\$env{ID_PATH}"
1316 EOF
1317         },
1318 );
1319
1320 sub udev {
1321         my ($action, $devpath, $rules) = @_;
1322
1323         # create temporary rules
1324         system("mkdir", "-p", "$udev_rules_dir");
1325         open CONF, ">$udev_rules" || die "unable to create rules file: $udev_rules";
1326         print CONF $$rules;
1327         close CONF;
1328
1329         if ($valgrind > 0) {
1330                 system("$udev_bin_valgrind $action $devpath");
1331         } elsif ($gdb > 0) {
1332                 system("$udev_bin_gdb $action $devpath");
1333         } else {
1334                 system("$udev_bin", "$action", "$devpath");
1335         }
1336 }
1337
1338 my $error = 0;
1339
1340 sub permissions_test {
1341         my($rules, $uid, $gid, $mode) = @_;
1342
1343         my $wrong = 0;
1344         my $userid;
1345         my $groupid;
1346
1347         $rules->{exp_perms} =~ m/^(.*):(.*):(.*)$/;
1348         if ($1 ne "") {
1349                 if (defined(getpwnam($1))) {
1350                         $userid = int(getpwnam($1));
1351                 } else {
1352                         $userid = $1;
1353                 }
1354                 if ($uid != $userid) { $wrong = 1; }
1355         }
1356         if ($2 ne "") {
1357                 if (defined(getgrnam($2))) {
1358                         $groupid = int(getgrnam($2));
1359                 } else {
1360                         $groupid = $2;
1361                 }
1362                 if ($gid != $groupid) { $wrong = 1; }
1363         }
1364         if ($3 ne "") {
1365                 if (($mode & 07777) != oct($3)) { $wrong = 1; };
1366         }
1367         if ($wrong == 0) {
1368                 print "permissions: ok\n";
1369         } else {
1370                 printf "  expected permissions are: %s:%s:%#o\n", $1, $2, oct($3);
1371                 printf "  created permissions are : %i:%i:%#o\n", $uid, $gid, $mode & 07777;
1372                 print "permissions: error\n";
1373                 $error++;
1374                 sleep(1);
1375         }
1376 }
1377
1378 sub major_minor_test {
1379         my($rules, $rdev) = @_;
1380
1381         my $major = ($rdev >> 8) & 0xfff;
1382         my $minor = ($rdev & 0xff) | (($rdev >> 12) & 0xfff00);
1383         my $wrong = 0;
1384
1385         $rules->{exp_majorminor} =~ m/^(.*):(.*)$/;
1386         if ($1 ne "") {
1387                 if ($major != $1) { $wrong = 1; };
1388         }
1389         if ($2 ne "") {
1390                 if ($minor != $2) { $wrong = 1; };
1391         }
1392         if ($wrong == 0) {
1393                 print "major:minor: ok\n";
1394         } else {
1395                 printf "  expected major:minor is: %i:%i\n", $1, $2;
1396                 printf "  created major:minor is : %i:%i\n", $major, $minor;
1397                 print "major:minor: error\n";
1398                 $error++;
1399                 sleep(1);
1400         }
1401 }
1402
1403 sub udev_setup {
1404         system("rm", "-rf", "$udev_dev");
1405         mkdir($udev_dev) || die "unable to create udev_dev: $udev_dev\n";
1406         # setting group and mode of udev_dev ensures the tests work
1407         # even if the parent directory has setgid bit enabled.
1408         chown (0, 0, $udev_dev) || die "unable to chown $udev_dev\n";
1409         chmod (0755, $udev_dev) || die "unable to chmod $udev_dev\n";
1410
1411         system("rm", "-rf", "$udev_run");
1412 }
1413
1414 sub run_test {
1415         my ($rules, $number) = @_;
1416
1417         print "TEST $number: $rules->{desc}\n";
1418         print "device \'$rules->{devpath}\' expecting node/link \'$rules->{exp_name}\'\n";
1419
1420         udev("add", $rules->{devpath}, \$rules->{rules});
1421         if (defined($rules->{not_exp_name})) {
1422                 if ((-e "$udev_dev/$rules->{not_exp_name}") ||
1423                     (-l "$udev_dev/$rules->{not_exp_name}")) {
1424                         print "nonexistent: error \'$rules->{not_exp_name}\' not expected to be there\n";
1425                         $error++;
1426                         sleep(1);
1427                 }
1428         }
1429
1430         if ((-e "$udev_dev/$rules->{exp_name}") ||
1431             (-l "$udev_dev/$rules->{exp_name}")) {
1432
1433                 my ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size,
1434                     $atime, $mtime, $ctime, $blksize, $blocks) = stat("$udev_dev/$rules->{exp_name}");
1435
1436                 if (defined($rules->{exp_perms})) {
1437                         permissions_test($rules, $uid, $gid, $mode);
1438                 }
1439                 if (defined($rules->{exp_majorminor})) {
1440                         major_minor_test($rules, $rdev);
1441                 }
1442                 print "add:         ok\n";
1443         } else {
1444                 print "add:         error";
1445                 if ($rules->{exp_add_error}) {
1446                         print " as expected\n";
1447                 } else {
1448                         print "\n";
1449                         system("tree", "$udev_dev");
1450                         print "\n";
1451                         $error++;
1452                         sleep(1);
1453                 }
1454         }
1455
1456         if (defined($rules->{option}) && $rules->{option} eq "keep") {
1457                 print "\n\n";
1458                 return;
1459         }
1460
1461         udev("remove", $rules->{devpath}, \$rules->{rules});
1462         if ((-e "$udev_dev/$rules->{exp_name}") ||
1463             (-l "$udev_dev/$rules->{exp_name}")) {
1464                 print "remove:      error";
1465                 if ($rules->{exp_rem_error}) {
1466                         print " as expected\n";
1467                 } else {
1468                         print "\n";
1469                         system("tree", "$udev_dev");
1470                         print "\n";
1471                         $error++;
1472                         sleep(1);
1473                 }
1474         } else {
1475                 print "remove:      ok\n";
1476         }
1477
1478         print "\n";
1479
1480         if (defined($rules->{option}) && $rules->{option} eq "clean") {
1481                 udev_setup();
1482         }
1483
1484 }
1485
1486 # only run if we have root permissions
1487 # due to mknod restrictions
1488 if (!($<==0)) {
1489         print "Must have root permissions to run properly.\n";
1490         exit;
1491 }
1492
1493 # skip the test when running in a container
1494 system("systemd-detect-virt", "-c", "-q");
1495 if ($? >> 8 == 0) {
1496     print "Running in a container, skipping the test.\n";
1497     exit($EXIT_TEST_SKIP);
1498 }
1499
1500 udev_setup();
1501
1502 my $test_num = 1;
1503 my @list;
1504
1505 foreach my $arg (@ARGV) {
1506         if ($arg =~ m/--valgrind/) {
1507                 $valgrind = 1;
1508                 printf("using valgrind\n");
1509         } elsif ($arg =~ m/--gdb/) {
1510                 $gdb = 1;
1511                 printf("using gdb\n");
1512         } else {
1513                 push(@list, $arg);
1514         }
1515 }
1516
1517 if ($list[0]) {
1518         foreach my $arg (@list) {
1519                 if (defined($tests[$arg-1]->{desc})) {
1520                         print "udev-test will run test number $arg:\n\n";
1521                         run_test($tests[$arg-1], $arg);
1522                 } else {
1523                         print "test does not exist.\n";
1524                 }
1525         }
1526 } else {
1527         # test all
1528         print "\nudev-test will run ".($#tests + 1)." tests:\n\n";
1529
1530         foreach my $rules (@tests) {
1531                 run_test($rules, $test_num);
1532                 $test_num++;
1533         }
1534 }
1535
1536 print "$error errors occurred\n\n";
1537
1538 # cleanup
1539 system("rm", "-rf", "$udev_dev");
1540 system("rm", "-rf", "$udev_run");
1541
1542 if ($error > 0) {
1543     exit(1);
1544 }
1545 exit(0);