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