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