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