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.
9 # Every test is driven by its own temporary config file.
10 # This program prepares the environment, creates the config and calls udev.
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.
17 # Copyright © 2004 Leann Ogasawara <ogasawara@osdl.org>
23 my $EXIT_TEST_SKIP = 77;
25 unless (eval "use POSIX qw(WIFEXITED WEXITSTATUS);
26 use Cwd
qw(getcwd abs_path);
28 use IPC
::SysV
qw(IPC_PRIVATE S_IRUSR S_IWUSR IPC_CREAT);
29 use Time
::HiRes
qw(usleep); 1") {
30 warn "Failed to import dependencies
, skipping the test
: $@
";
31 exit($EXIT_TEST_SKIP);
35 my $udev_bin = "./test
-udev
";
39 my $udev_bin_valgrind = "valgrind
--tool
=memcheck
--leak
-check
=yes
--track
-origins
=yes
--quiet
$udev_bin";
40 my $udev_bin_gdb = "gdb
--args
$udev_bin";
41 my $udev_bin_strace = "strace
-efile
$udev_bin";
42 my $udev_run = "test
/run
";
43 my $udev_tmpfs = "test
/tmpfs
";
44 my $udev_sys = "${udev_tmpfs
}/sys
";
45 my $udev_dev = "${udev_tmpfs
}/dev
";
46 my $udev_rules_dir = "$udev_run/udev/rules
.d
";
47 my $udev_rules = "$udev_rules_dir/udev
-test
.rules
";
48 my $EXIT_TEST_SKIP = 77;
50 my $rules_10k_tags = "";
51 for (my $i = 1; $i <= 10000; ++$i) {
52 $rules_10k_tags .= 'KERNEL=="sda
", TAG+="test
' . $i . "\"\n";
55 my $rules_10k_tags_continuation = "KERNEL==\"sda\", \\\n";
56 for (my $i = 1; $i < 10000; ++$i) {
57 $rules_10k_tags_continuation .= 'TAG
+="test' . $i . "\",\\\n";
59 $rules_10k_tags_continuation .= "TAG
+=\"test10000
\"\\n
";
61 # Create a device list with all block devices under /sys
62 # (except virtual devices and cd-roms)
63 # the optional argument exp_func returns expected and non-expected
64 # symlinks for the device.
69 foreach my $bd (glob "$udev_sys/dev
/block
/*") {
70 my $tgt = readlink($bd);
71 my ($exp, $notexp) = (undef, undef);
73 next if ($tgt =~ m!/virtual/! || $tgt =~ m!/sr[0-9]*$!);
75 $tgt =~ s!^\.\./\.\.!!;
76 ($exp, $notexp) = $exp_func->($tgt) if defined($exp_func);
80 not_exp_links => $notexp,
82 push(@devices, $device);
87 # This generator returns a suitable exp_func for use with
90 my ($pattern, $links, $donot) = @_;
94 if ($name =~ /$pattern/) {
95 return ($links, undef);
97 return (undef, $links);
99 return (undef, undef);
110 devpath => "/devices/pci0000:00/0000:00:1f.2/host0
/target0:0:0/0:0:0:0/block/sda",
111 exp_rem_error => "yes
",
114 devpath => "/devices/pci0000:00/0000:00:1f.2/host0
/target0:0:0/0:0:0:0/block/sda/sda1
",
115 exp_rem_error => "yes
",
122 desc
=> "label test of scsi disc",
125 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
126 exp_links
=> ["boot_disk"],
129 SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", SYMLINK+="boot_disk%n"
130 KERNEL=="ttyACM0", SYMLINK+="modem"
134 desc
=> "label test of scsi disc",
137 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
138 exp_links
=> ["boot_disk"],
141 SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", SYMLINK+="boot_disk%n"
142 KERNEL=="ttyACM0", SYMLINK+="modem"
146 desc
=> "label test of scsi disc",
149 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
150 exp_links
=> ["boot_disk"],
153 SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", SYMLINK+="boot_disk%n"
154 KERNEL=="ttyACM0", SYMLINK+="modem"
158 desc
=> "label test of scsi partition",
161 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
162 exp_links
=> ["boot_disk1"],
165 SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", SYMLINK+="boot_disk%n"
169 desc
=> "label test of pattern match",
172 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
173 exp_links
=> ["boot_disk1", "boot_disk1-4", "boot_disk1-5"],
174 not_exp_links
=> ["boot_disk1-1", "boot_disk1-2", "boot_disk1-3"]
177 SUBSYSTEMS=="scsi", ATTRS{vendor}=="?ATA", SYMLINK+="boot_disk%n-1"
178 SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA?", SYMLINK+="boot_disk%n-2"
179 SUBSYSTEMS=="scsi", ATTRS{vendor}=="A??", SYMLINK+="boot_disk%n"
180 SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATAS", SYMLINK+="boot_disk%n-3"
181 SUBSYSTEMS=="scsi", ATTRS{vendor}=="AT?", SYMLINK+="boot_disk%n-4"
182 SUBSYSTEMS=="scsi", ATTRS{vendor}=="??A", SYMLINK+="boot_disk%n-5"
186 desc
=> "label test of multiple sysfs files",
189 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
190 exp_links
=> ["boot_disk1"],
191 not_exp_links
=> ["boot_diskX1"],
194 SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS X ", SYMLINK+="boot_diskX%n"
195 SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", SYMLINK+="boot_disk%n"
199 desc
=> "label test of max sysfs files (skip invalid rule)",
202 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
203 exp_links
=> ["boot_disk1", "boot_diskXY1"],
204 not_exp_links
=> ["boot_diskXX1"],
207 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"
208 SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", ATTRS{scsi_level}=="6", ATTRS{rev}=="4.06", ATTRS{type}=="0", ATTRS{queue_depth}=="1", SYMLINK+="boot_diskXY%n"
209 SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", ATTRS{scsi_level}=="6", ATTRS{rev}=="4.06", ATTRS{type}=="0", SYMLINK+="boot_disk%n"
213 desc
=> "catch device by *",
216 devpath
=> "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
217 exp_links
=> ["modem/0", "catch-all"],
220 KERNEL=="ttyACM*", SYMLINK+="modem/%n"
221 KERNEL=="*", SYMLINK+="catch-all"
226 desc
=> "catch device by * - take 2",
229 devpath
=> "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
230 exp_links
=> ["modem/0"],
231 not_exp_links
=> ["bad"],
234 KERNEL=="*ACM1", SYMLINK+="bad"
235 KERNEL=="*ACM0", SYMLINK+="modem/%n"
239 desc
=> "catch device by ?",
242 devpath
=> "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
243 exp_links
=> ["modem/0"],
244 not_exp_links
=> ["modem/0-1", "modem/0-2"],
247 KERNEL=="ttyACM??*", SYMLINK+="modem/%n-1"
248 KERNEL=="ttyACM??", SYMLINK+="modem/%n-2"
249 KERNEL=="ttyACM?", SYMLINK+="modem/%n"
253 desc
=> "catch device by character class",
256 devpath
=> "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
257 exp_links
=> ["modem/0"],
258 not_exp_links
=> ["modem/0-1", "modem/0-2"],
261 KERNEL=="ttyACM[A-Z]*", SYMLINK+="modem/%n-1"
262 KERNEL=="ttyACM?[0-9]", SYMLINK+="modem/%n-2"
263 KERNEL=="ttyACM[0-9]*", SYMLINK+="modem/%n"
267 desc
=> "don't replace kernel name",
270 devpath
=> "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
271 exp_links
=> ["modem"],
274 KERNEL=="ttyACM0", SYMLINK+="modem"
278 desc
=> "Handle comment lines in config file (and don't replace kernel name)",
281 devpath
=> "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
282 exp_links
=> ["modem"],
286 KERNEL=="ttyACM0", SYMLINK+="modem"
291 desc
=> "Handle comment lines in config file with whitespace (and don't replace kernel name)",
294 devpath
=> "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
295 exp_links
=> ["modem"],
298 # this is a comment with whitespace before the comment
299 KERNEL=="ttyACM0", SYMLINK+="modem"
304 desc
=> "Handle whitespace only lines (and don't replace kernel name)",
307 devpath
=> "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
308 exp_links
=> ["whitespace"],
314 # this is a comment with whitespace before the comment
315 KERNEL=="ttyACM0", SYMLINK+="whitespace"
322 desc
=> "Handle empty lines in config file (and don't replace kernel name)",
325 devpath
=> "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
326 exp_links
=> ["modem"],
330 KERNEL=="ttyACM0", SYMLINK+="modem"
335 desc
=> "Handle backslashed multi lines in config file (and don't replace kernel name)",
338 devpath
=> "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
339 exp_links
=> ["modem"],
342 KERNEL=="ttyACM0", \\
348 desc
=> "preserve backslashes, if they are not for a newline",
351 devpath
=> "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
352 exp_links
=> ["aaa"],
355 KERNEL=="ttyACM0", PROGRAM=="/bin/echo -e \\101", RESULT=="A", SYMLINK+="aaa"
360 desc
=> "Handle stupid backslashed multi lines in config file (and don't replace kernel name)",
363 devpath
=> "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
364 exp_links
=> ["modem"],
375 KERNEL=="ttyACM0", \\
381 desc
=> "subdirectory handling",
384 devpath
=> "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
385 exp_links
=> ["sub/direct/ory/modem"],
388 KERNEL=="ttyACM0", SYMLINK+="sub/direct/ory/modem"
392 desc
=> "parent device name match of scsi partition",
395 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
396 exp_links
=> ["first_disk5"],
399 SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", SYMLINK+="first_disk%n"
403 desc
=> "test substitution chars",
406 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
407 exp_links
=> ["Major:8:minor:5:kernelnumber:5:id:0:0:0:0"],
410 SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", SYMLINK+="Major:%M:minor:%m:kernelnumber:%n:id:%b"
414 desc
=> "import of shell-value returned from program",
417 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
418 exp_links
=> ["node12345678"],
421 SUBSYSTEMS=="scsi", IMPORT{program}="/bin/echo -e \' TEST_KEY=12345678\\n TEST_key2=98765\'", SYMLINK+="node\$env{TEST_KEY}"
422 KERNEL=="ttyACM0", SYMLINK+="modem"
426 desc
=> "substitution of sysfs value (%s{file})",
429 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
430 exp_links
=> ["disk-ATA-sda"],
431 not_exp_links
=> ["modem"],
434 SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", SYMLINK+="disk-%s{vendor}-%k"
435 KERNEL=="ttyACM0", SYMLINK+="modem"
439 desc
=> "program result substitution",
442 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
443 exp_links
=> ["special-device-5"],
444 not_exp_links
=> ["not"],
447 SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n special-device", RESULT=="-special-*", SYMLINK+="not"
448 SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n special-device", RESULT=="special-*", SYMLINK+="%c-%n"
452 desc
=> "program result substitution (newline removal)",
455 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
456 exp_links
=> ["newline_removed"],
459 SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo test", RESULT=="test", SYMLINK+="newline_removed"
463 desc
=> "program result substitution",
466 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
467 exp_links
=> ["test-0:0:0:0"],
470 SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n test-%b", RESULT=="test-0:0*", SYMLINK+="%c"
474 desc
=> "program with lots of arguments",
477 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
478 exp_links
=> ["foo9"],
479 not_exp_links
=> ["foo3", "foo4", "foo5", "foo6", "foo7", "foo8"],
482 SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n foo3 foo4 foo5 foo6 foo7 foo8 foo9", KERNEL=="sda5", SYMLINK+="%c{7}"
486 desc
=> "program with subshell",
489 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
490 exp_links
=> ["bar9"],
491 not_exp_links
=> ["foo3", "foo4", "foo5", "foo6", "foo7", "foo8"],
494 SUBSYSTEMS=="scsi", PROGRAM=="/bin/sh -c 'echo foo3 foo4 foo5 foo6 foo7 foo8 foo9 | sed s/foo9/bar9/'", KERNEL=="sda5", SYMLINK+="%c{7}"
498 desc
=> "program arguments combined with apostrophes",
501 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
502 exp_links
=> ["foo7"],
503 not_exp_links
=> ["foo3", "foo4", "foo5", "foo6", "foo8"],
506 SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n 'foo3 foo4' 'foo5 foo6 foo7 foo8'", KERNEL=="sda5", SYMLINK+="%c{5}"
510 desc
=> "program arguments combined with escaped double quotes, part 1",
513 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
514 exp_links
=> ["foo2"],
515 not_exp_links
=> ["foo1"],
518 SUBSYSTEMS=="scsi", PROGRAM=="/bin/sh -c 'printf %%s \\\"foo1 foo2\\\" | grep \\\"foo1 foo2\\\"'", KERNEL=="sda5", SYMLINK+="%c{2}"
522 desc
=> "program arguments combined with escaped double quotes, part 2",
525 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
526 exp_links
=> ["foo2"],
527 not_exp_links
=> ["foo1"],
530 SUBSYSTEMS=="scsi", PROGRAM=="/bin/sh -c \\\"printf %%s 'foo1 foo2' | grep 'foo1 foo2'\\\"", KERNEL=="sda5", SYMLINK+="%c{2}"
534 desc
=> "program arguments combined with escaped double quotes, part 3",
537 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
538 exp_links
=> ["foo2"],
539 not_exp_links
=> ["foo1", "foo3"],
542 SUBSYSTEMS=="scsi", PROGRAM=="/bin/sh -c 'printf \\\"%%s %%s\\\" \\\"foo1 foo2\\\" \\\"foo3\\\"| grep \\\"foo1 foo2\\\"'", KERNEL=="sda5", SYMLINK+="%c{2}"
546 desc
=> "characters before the %c{N} substitution",
549 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
550 exp_links
=> ["my-foo9"],
553 SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n foo3 foo4 foo5 foo6 foo7 foo8 foo9", KERNEL=="sda5", SYMLINK+="my-%c{7}"
557 desc
=> "substitute the second to last argument",
560 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
561 exp_links
=> ["my-foo8"],
562 not_exp_links
=> ["my-foo3", "my-foo4", "my-foo5", "my-foo6", "my-foo7", "my-foo9"],
565 SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n foo3 foo4 foo5 foo6 foo7 foo8 foo9", KERNEL=="sda5", SYMLINK+="my-%c{6}"
569 desc
=> "test substitution by variable name",
572 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
573 exp_links
=> ["Major:8-minor:5-kernelnumber:5-id:0:0:0:0"],
576 SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", SYMLINK+="Major:\$major-minor:\$minor-kernelnumber:\$number-id:\$id"
580 desc
=> "test substitution by variable name 2",
583 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
584 exp_links
=> ["Major:8-minor:5-kernelnumber:5-id:0:0:0:0"],
587 SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", DEVPATH=="*/sda/*", SYMLINK+="Major:\$major-minor:%m-kernelnumber:\$number-id:\$id"
591 desc
=> "test substitution by variable name 3",
594 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
595 exp_links
=> ["850:0:0:05"],
598 SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", DEVPATH=="*/sda/*", SYMLINK+="%M%m%b%n"
602 desc
=> "test substitution by variable name 4",
605 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
606 exp_links
=> ["855"],
609 SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", DEVPATH=="*/sda/*", SYMLINK+="\$major\$minor\$number"
613 desc
=> "test substitution by variable name 5",
616 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
617 exp_links
=> ["8550:0:0:0"],
620 SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", DEVPATH=="*/sda/*", SYMLINK+="\$major%m%n\$id"
624 desc
=> "non matching SUBSYSTEMS for device with no parent",
627 devpath
=> "/devices/virtual/tty/console",
628 exp_links
=> ["TTY"],
629 not_exp_links
=> ["foo"],
632 SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n foo", RESULT=="foo", SYMLINK+="foo"
633 KERNEL=="console", SYMLINK+="TTY"
637 desc
=> "non matching SUBSYSTEMS",
640 devpath
=> "/devices/virtual/tty/console",
641 exp_links
=> ["TTY"],
642 not_exp_links
=> ["foo"],
645 SUBSYSTEMS=="foo", ATTRS{dev}=="5:1", SYMLINK+="foo"
646 KERNEL=="console", SYMLINK+="TTY"
650 desc
=> "ATTRS match",
653 devpath
=> "/devices/virtual/tty/console",
654 exp_links
=> ["foo", "TTY"],
657 KERNEL=="console", SYMLINK+="TTY"
658 ATTRS{dev}=="5:1", SYMLINK+="foo"
662 desc
=> "ATTR (empty file)",
665 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
666 exp_links
=> ["empty", "not-something"],
667 not_exp_links
=> ["something", "not-empty"],
670 KERNEL=="sda", ATTR{test_empty_file}=="?*", SYMLINK+="something"
671 KERNEL=="sda", ATTR{test_empty_file}!="", SYMLINK+="not-empty"
672 KERNEL=="sda", ATTR{test_empty_file}=="", SYMLINK+="empty"
673 KERNEL=="sda", ATTR{test_empty_file}!="?*", SYMLINK+="not-something"
677 desc
=> "ATTR (non-existent file)",
680 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
681 exp_links
=> ["non-existent", "wrong"],
682 not_exp_links
=> ["something", "empty", "not-empty",
683 "not-something", "something"],
686 KERNEL=="sda", ATTR{nofile}=="?*", SYMLINK+="something"
687 KERNEL=="sda", ATTR{nofile}!="", SYMLINK+="not-empty"
688 KERNEL=="sda", ATTR{nofile}=="", SYMLINK+="empty"
689 KERNEL=="sda", ATTR{nofile}!="?*", SYMLINK+="not-something"
690 KERNEL=="sda", TEST!="nofile", SYMLINK+="non-existent"
691 KERNEL=="sda", SYMLINK+="wrong"
695 desc
=> "program and bus type match",
698 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
699 exp_links
=> ["scsi-0:0:0:0"],
702 SUBSYSTEMS=="usb", PROGRAM=="/bin/echo -n usb-%b", SYMLINK+="%c"
703 SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n scsi-%b", SYMLINK+="%c"
704 SUBSYSTEMS=="foo", PROGRAM=="/bin/echo -n foo-%b", SYMLINK+="%c"
708 desc
=> "sysfs parent hierarchy",
711 devpath
=> "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
712 exp_links
=> ["modem"],
715 ATTRS{idProduct}=="007b", SYMLINK+="modem"
719 desc
=> "name test with ! in the name",
722 devpath
=> "/devices/virtual/block/fake!blockdev0",
723 devnode
=> "fake/blockdev0",
724 exp_links
=> ["is/a/fake/blockdev0"],
725 not_exp_links
=> ["is/not/a/fake/blockdev0", "modem"],
728 SUBSYSTEMS=="scsi", SYMLINK+="is/not/a/%k"
729 SUBSYSTEM=="block", SYMLINK+="is/a/%k"
730 KERNEL=="ttyACM0", SYMLINK+="modem"
734 desc
=> "name test with ! in the name, but no matching rule",
737 devpath
=> "/devices/virtual/block/fake!blockdev0",
738 devnode
=> "fake/blockdev0",
739 not_exp_links
=> ["modem"],
742 KERNEL=="ttyACM0", SYMLINK+="modem"
746 desc
=> "KERNELS rule",
749 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
750 exp_links
=> ["scsi-0:0:0:0"],
751 not_exp_links
=> ["no-match", "short-id", "not-scsi"],
754 SUBSYSTEMS=="usb", KERNELS=="0:0:0:0", SYMLINK+="not-scsi"
755 SUBSYSTEMS=="scsi", KERNELS=="0:0:0:1", SYMLINK+="no-match"
756 SUBSYSTEMS=="scsi", KERNELS==":0", SYMLINK+="short-id"
757 SUBSYSTEMS=="scsi", KERNELS=="/0:0:0:0", SYMLINK+="no-match"
758 SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", SYMLINK+="scsi-0:0:0:0"
762 desc
=> "KERNELS wildcard all",
765 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
766 exp_links
=> ["scsi-0:0:0:0"],
767 not_exp_links
=> ["no-match", "before"],
770 SUBSYSTEMS=="scsi", KERNELS=="*:1", SYMLINK+="no-match"
771 SUBSYSTEMS=="scsi", KERNELS=="*:0:1", SYMLINK+="no-match"
772 SUBSYSTEMS=="scsi", KERNELS=="*:0:0:1", SYMLINK+="no-match"
773 SUBSYSTEMS=="scsi", KERNEL=="0:0:0:0", SYMLINK+="before"
774 SUBSYSTEMS=="scsi", KERNELS=="*", SYMLINK+="scsi-0:0:0:0"
778 desc
=> "KERNELS wildcard partial",
781 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
782 exp_links
=> ["scsi-0:0:0:0", "before"],
785 SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", SYMLINK+="before"
786 SUBSYSTEMS=="scsi", KERNELS=="*:0", SYMLINK+="scsi-0:0:0:0"
790 desc
=> "KERNELS wildcard partial 2",
793 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
794 exp_links
=> ["scsi-0:0:0:0", "before"],
797 SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", SYMLINK+="before"
798 SUBSYSTEMS=="scsi", KERNELS=="*:0:0:0", SYMLINK+="scsi-0:0:0:0"
802 desc
=> "substitute attr with link target value (first match)",
805 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
806 exp_links
=> ["driver-is-sd"],
809 SUBSYSTEMS=="scsi", SYMLINK+="driver-is-\$attr{driver}"
813 desc
=> "substitute attr with link target value (currently selected device)",
816 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
817 exp_links
=> ["driver-is-ahci"],
820 SUBSYSTEMS=="pci", SYMLINK+="driver-is-\$attr{driver}"
824 desc
=> "ignore ATTRS attribute whitespace",
827 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
828 exp_links
=> ["ignored"],
831 SUBSYSTEMS=="scsi", ATTRS{whitespace_test}=="WHITE SPACE", SYMLINK+="ignored"
835 desc
=> "do not ignore ATTRS attribute whitespace",
838 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
839 exp_links
=> ["matched-with-space"],
840 not_exp_links
=> ["wrong-to-ignore"],
843 SUBSYSTEMS=="scsi", ATTRS{whitespace_test}=="WHITE SPACE ", SYMLINK+="wrong-to-ignore"
844 SUBSYSTEMS=="scsi", ATTRS{whitespace_test}=="WHITE SPACE ", SYMLINK+="matched-with-space"
848 desc
=> "permissions USER=bad GROUP=name",
851 devpath
=> "/devices/virtual/tty/tty33",
852 exp_perms
=> "0:0:0600",
855 KERNEL=="tty33", OWNER="bad", GROUP="name"
859 desc
=> "permissions OWNER=1",
862 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
863 exp_links
=> ["node"],
864 exp_perms
=> "1::0600",
867 SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", OWNER="1"
871 desc
=> "permissions GROUP=1",
874 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
875 exp_links
=> ["node"],
876 exp_perms
=> ":1:0660",
879 SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", GROUP="1"
883 desc
=> "textual user id",
886 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
887 exp_links
=> ["node"],
888 exp_perms
=> "daemon::0600",
891 SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", OWNER="daemon"
895 desc
=> "textual group id",
898 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
899 exp_links
=> ["node"],
900 exp_perms
=> ":daemon:0660",
903 SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", GROUP="daemon"
907 desc
=> "textual user/group id",
910 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
911 exp_links
=> ["node"],
912 exp_perms
=> "root:audio:0660",
915 SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", OWNER="root", GROUP="audio"
919 desc
=> "permissions MODE=0777",
922 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
923 exp_links
=> ["node"],
924 exp_perms
=> "::0777",
927 SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", MODE="0777"
931 desc
=> "permissions OWNER=1 GROUP=1 MODE=0777",
934 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
935 exp_links
=> ["node"],
936 exp_perms
=> "1:1:0777",
939 SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", OWNER="1", GROUP="1", MODE="0777"
943 desc
=> "permissions OWNER to 1",
946 devpath
=> "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
950 KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", OWNER="1"
954 desc
=> "permissions GROUP to 1",
957 devpath
=> "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
958 exp_perms
=> ":1:0660",
961 KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", GROUP="1"
965 desc
=> "permissions MODE to 0060",
968 devpath
=> "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
969 exp_perms
=> "::0060",
972 KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", MODE="0060"
976 desc
=> "permissions OWNER, GROUP, MODE",
979 devpath
=> "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
980 exp_perms
=> "1:1:0777",
983 KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", OWNER="1", GROUP="1", MODE="0777"
987 desc
=> "permissions only rule",
990 devpath
=> "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
991 exp_perms
=> "1:1:0777",
994 KERNEL=="ttyACM[0-9]*", OWNER="1", GROUP="1", MODE="0777"
995 KERNEL=="ttyUSX[0-9]*", OWNER="2", GROUP="2", MODE="0444"
996 KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n"
1000 desc
=> "multiple permissions only rule",
1003 devpath
=> "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1004 exp_perms
=> "1:1:0777",
1007 SUBSYSTEM=="tty", OWNER="1"
1008 SUBSYSTEM=="tty", GROUP="1"
1009 SUBSYSTEM=="tty", MODE="0777"
1010 KERNEL=="ttyUSX[0-9]*", OWNER="2", GROUP="2", MODE="0444"
1011 KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n"
1015 desc
=> "permissions only rule with override at SYMLINK+ rule",
1018 devpath
=> "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1019 exp_perms
=> "1:2:0777",
1022 SUBSYSTEM=="tty", OWNER="1"
1023 SUBSYSTEM=="tty", GROUP="1"
1024 SUBSYSTEM=="tty", MODE="0777"
1025 KERNEL=="ttyUSX[0-9]*", OWNER="2", GROUP="2", MODE="0444"
1026 KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", GROUP="2"
1030 desc
=> "major/minor number test",
1033 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1034 exp_links
=> ["node"],
1035 exp_majorminor
=> "8:0",
1038 SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node"
1042 desc
=> "big major number test",
1045 devpath
=> "/devices/virtual/misc/misc-fake1",
1046 exp_links
=> ["node"],
1047 exp_majorminor
=> "4095:1",
1050 KERNEL=="misc-fake1", SYMLINK+="node"
1054 desc
=> "big major and big minor number test",
1057 devpath
=> "/devices/virtual/misc/misc-fake89999",
1058 exp_links
=> ["node"],
1059 exp_majorminor
=> "4095:89999",
1062 KERNEL=="misc-fake89999", SYMLINK+="node"
1066 desc
=> "multiple symlinks with format char",
1069 devpath
=> "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1070 exp_links
=> ["symlink1-0", "symlink2-ttyACM0", "symlink3-"],
1073 KERNEL=="ttyACM[0-9]*", SYMLINK="symlink1-%n symlink2-%k symlink3-%b"
1077 desc
=> "multiple symlinks with a lot of s p a c e s",
1080 devpath
=> "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1081 exp_links
=> ["one", "two"],
1082 not_exp_links
=> [" "],
1085 KERNEL=="ttyACM[0-9]*", SYMLINK=" one two "
1089 desc
=> "symlink with spaces in substituted variable",
1092 devpath
=> "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1093 exp_links
=> ["name-one_two_three-end"],
1094 not_exp_links
=> [" "],
1097 ENV{WITH_WS}="one two three"
1098 SYMLINK="name-\$env{WITH_WS}-end"
1102 desc
=> "symlink with leading space in substituted variable",
1105 devpath
=> "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1106 exp_links
=> ["name-one_two_three-end"],
1107 not_exp_links
=> [" "],
1110 ENV{WITH_WS}=" one two three"
1111 SYMLINK="name-\$env{WITH_WS}-end"
1115 desc
=> "symlink with trailing space in substituted variable",
1118 devpath
=> "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1119 exp_links
=> ["name-one_two_three-end"],
1120 not_exp_links
=> [" "],
1123 ENV{WITH_WS}="one two three "
1124 SYMLINK="name-\$env{WITH_WS}-end"
1128 desc
=> "symlink with lots of space in substituted variable",
1131 devpath
=> "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1132 exp_links
=> ["name-one_two_three-end"],
1133 not_exp_links
=> [" "],
1136 ENV{WITH_WS}=" one two three "
1137 SYMLINK="name-\$env{WITH_WS}-end"
1141 desc
=> "symlink with multiple spaces in substituted variable",
1144 devpath
=> "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1145 exp_links
=> ["name-one_two_three-end"],
1146 not_exp_links
=> [" "],
1149 ENV{WITH_WS}=" one two three "
1150 SYMLINK="name-\$env{WITH_WS}-end"
1154 desc
=> "symlink with space and var with space",
1157 devpath
=> "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1158 exp_links
=> ["first", "name-one_two_three-end",
1159 "another_symlink", "a", "b", "c"],
1160 not_exp_links
=> [" "],
1163 ENV{WITH_WS}=" one two three "
1164 SYMLINK=" first name-\$env{WITH_WS}-end another_symlink a b c "
1168 desc
=> "symlink creation (same directory)",
1171 devpath
=> "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1172 exp_links
=> ["modem0"],
1175 KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", SYMLINK="modem%n"
1179 desc
=> "multiple symlinks",
1182 devpath
=> "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1183 exp_links
=> ["first-0", "second-0", "third-0"],
1186 KERNEL=="ttyACM0", SYMLINK="first-%n second-%n third-%n"
1190 desc
=> "symlink name '.'",
1193 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1195 exp_add_error
=> "yes",
1196 exp_rem_error
=> "yes",
1199 SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="."
1203 desc
=> "symlink node to itself",
1206 devpath
=> "/devices/virtual/tty/tty0",
1207 exp_links
=> ["link"],
1208 exp_add_error
=> "yes",
1209 exp_rem_error
=> "yes",
1213 KERNEL=="tty0", SYMLINK+="tty0"
1217 desc
=> "symlink %n substitution",
1220 devpath
=> "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1221 exp_links
=> ["symlink0"],
1224 KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", SYMLINK+="symlink%n"
1228 desc
=> "symlink %k substitution",
1231 devpath
=> "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1232 exp_links
=> ["symlink-ttyACM0"],
1235 KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", SYMLINK+="symlink-%k"
1239 desc
=> "symlink %M:%m substitution",
1242 devpath
=> "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1243 exp_links
=> ["major-166:0"],
1246 KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", SYMLINK+="major-%M:%m"
1250 desc
=> "symlink %b substitution",
1253 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1254 exp_links
=> ["symlink-0:0:0:0"],
1257 SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="symlink-%b"
1261 desc
=> "symlink %c substitution",
1264 devpath
=> "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1265 exp_links
=> ["test"],
1268 KERNEL=="ttyACM[0-9]*", PROGRAM=="/bin/echo test", SYMLINK+="%c"
1272 desc
=> "symlink %c{N} substitution",
1275 devpath
=> "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1276 exp_links
=> ["test"],
1277 not_exp_links
=> ["symlink", "this"],
1280 KERNEL=="ttyACM[0-9]*", PROGRAM=="/bin/echo symlink test this", SYMLINK+="%c{2}"
1284 desc
=> "symlink %c{N+} substitution",
1287 devpath
=> "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1288 exp_links
=> ["test", "this"],
1289 not_exp_links
=> ["symlink"],
1292 KERNEL=="ttyACM[0-9]*", PROGRAM=="/bin/echo symlink test this", SYMLINK+="%c{2+}"
1296 desc
=> "symlink only rule with %c{N+}",
1299 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1300 exp_links
=> ["test", "this"],
1301 not_exp_links
=> ["symlink"],
1304 SUBSYSTEMS=="scsi", KERNEL=="sda", PROGRAM=="/bin/echo link test this" SYMLINK+="%c{2+}"
1308 desc
=> "symlink %s{filename} substitution",
1311 devpath
=> "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1312 exp_links
=> ["166:0"],
1315 KERNEL=="ttyACM[0-9]*", SYMLINK+="%s{dev}"
1319 desc
=> "program result substitution (numbered part of)",
1322 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
1323 exp_links
=> ["link1", "link2"],
1324 not_exp_links
=> ["node"],
1327 SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n node link1 link2", RESULT=="node *", SYMLINK+="%c{2} %c{3}"
1331 desc
=> "program result substitution (numbered part of+)",
1334 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
1335 exp_links
=> ["link1", "link2", "link3", "link4"],
1336 not_exp_links
=> ["node"],
1339 SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n node link1 link2 link3 link4", RESULT=="node *", SYMLINK+="%c{2+}"
1343 desc
=> "SUBSYSTEM match test",
1346 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1347 exp_links
=> ["node"],
1348 not_exp_links
=> ["should_not_match", "should_not_match2"],
1351 SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="should_not_match", SUBSYSTEM=="vc"
1352 SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", SUBSYSTEM=="block"
1353 SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="should_not_match2", SUBSYSTEM=="vc"
1357 desc
=> "DRIVERS match test",
1360 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1361 exp_links
=> ["node"],
1362 not_exp_links
=> ["should_not_match"]
1365 SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="should_not_match", DRIVERS=="sd-wrong"
1366 SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", DRIVERS=="sd"
1370 desc
=> "devnode substitution test",
1373 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1374 exp_links
=> ["node"],
1377 SUBSYSTEMS=="scsi", KERNEL=="sda", PROGRAM=="/usr/bin/test -b %N" SYMLINK+="node"
1381 desc
=> "parent node name substitution test",
1384 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
1385 exp_links
=> ["sda-part-1"],
1388 SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="%P-part-%n"
1392 desc
=> "udev_root substitution",
1395 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
1396 exp_links
=> ["start-/dev-end"],
1399 SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="start-%r-end"
1403 # This is not supported any more
1404 desc
=> "last_rule option",
1407 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
1408 exp_links
=> ["last"],
1409 not_exp_links
=> ["very-last"],
1410 exp_nodev_error
=> "yes",
1413 SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="last", OPTIONS="last_rule"
1414 SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="very-last"
1418 desc
=> "negation KERNEL!=",
1421 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
1422 exp_links
=> ["match", "before"],
1423 not_exp_links
=> ["matches-but-is-negated"],
1426 SUBSYSTEMS=="scsi", KERNEL!="sda1", SYMLINK+="matches-but-is-negated"
1427 SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="before"
1428 SUBSYSTEMS=="scsi", KERNEL!="xsda1", SYMLINK+="match"
1432 desc
=> "negation SUBSYSTEM!=",
1435 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
1436 exp_links
=> ["before", "not-anything"],
1437 not_exp_links
=> ["matches-but-is-negated"],
1440 SUBSYSTEMS=="scsi", SUBSYSTEM=="block", KERNEL!="sda1", SYMLINK+="matches-but-is-negated"
1441 SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="before"
1442 SUBSYSTEMS=="scsi", SUBSYSTEM!="anything", SYMLINK+="not-anything"
1446 desc
=> "negation PROGRAM!= exit code",
1449 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
1450 exp_links
=> ["before", "nonzero-program"],
1453 SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="before"
1454 KERNEL=="sda1", PROGRAM!="/bin/false", SYMLINK+="nonzero-program"
1458 desc
=> "ENV{} test",
1461 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
1462 exp_links
=> ["true"],
1463 not_exp_links
=> ["bad", "wrong"],
1466 ENV{ENV_KEY_TEST}="test"
1467 SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ENV_KEY_TEST}=="go", SYMLINK+="wrong"
1468 SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ENV_KEY_TEST}=="test", SYMLINK+="true"
1469 SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ENV_KEY_TEST}=="bad", SYMLINK+="bad"
1473 desc
=> "ENV{} test",
1476 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
1477 exp_links
=> ["true"],
1478 not_exp_links
=> ["bad", "wrong", "no"],
1481 ENV{ENV_KEY_TEST}="test"
1482 SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ENV_KEY_TEST}=="go", SYMLINK+="wrong"
1483 SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ENV_KEY_TEST}=="yes", ENV{ACTION}=="add", ENV{DEVPATH}=="*/block/sda/sdax1", SYMLINK+="no"
1484 SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ENV_KEY_TEST}=="test", ENV{ACTION}=="add", ENV{DEVPATH}=="*/block/sda/sda1", SYMLINK+="true"
1485 SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ENV_KEY_TEST}=="bad", SYMLINK+="bad"
1489 desc
=> "ENV{} test (assign)",
1492 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
1493 exp_links
=> ["true", "before"],
1494 not_exp_links
=> ["no"],
1497 SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ASSIGN}="true"
1498 SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ASSIGN}=="yes", SYMLINK+="no"
1499 SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="before"
1500 SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ASSIGN}=="true", SYMLINK+="true"
1504 desc
=> "ENV{} test (assign 2 times)",
1507 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
1508 exp_links
=> ["true", "before"],
1509 not_exp_links
=> ["no", "bad"],
1512 SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ASSIGN}="true"
1513 SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ASSIGN}="absolutely-\$env{ASSIGN}"
1514 SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="before"
1515 SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ASSIGN}=="yes", SYMLINK+="no"
1516 SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ASSIGN}=="true", SYMLINK+="bad"
1517 SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ASSIGN}=="absolutely-true", SYMLINK+="true"
1521 desc
=> "ENV{} test (assign2)",
1524 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
1525 exp_links
=> ["part"],
1526 not_exp_links
=> ["disk"],
1529 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1530 exp_links
=> ["disk"],
1531 not_exp_links
=> ["part"],
1535 SUBSYSTEM=="block", KERNEL=="*[0-9]", ENV{PARTITION}="true", ENV{MAINDEVICE}="false"
1536 SUBSYSTEM=="block", KERNEL=="*[!0-9]", ENV{PARTITION}="false", ENV{MAINDEVICE}="true"
1537 ENV{MAINDEVICE}=="true", SYMLINK+="disk"
1538 SUBSYSTEM=="block", SYMLINK+="before"
1539 ENV{PARTITION}=="true", SYMLINK+="part"
1543 desc
=> "untrusted string sanitize",
1546 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
1547 exp_links
=> ["sane"],
1550 SUBSYSTEMS=="scsi", KERNEL=="sda1", PROGRAM=="/bin/echo -e name; (/usr/bin/badprogram)", RESULT=="name_ _/usr/bin/badprogram_", SYMLINK+="sane"
1554 desc
=> "untrusted string sanitize (don't replace utf8)",
1557 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
1558 exp_links
=> ["uber"],
1561 SUBSYSTEMS=="scsi", KERNEL=="sda1", PROGRAM=="/bin/echo -e \\xc3\\xbcber" RESULT=="\xc3\xbcber", SYMLINK+="uber"
1565 desc
=> "untrusted string sanitize (replace invalid utf8)",
1568 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
1569 exp_links
=> ["replaced"],
1572 SUBSYSTEMS=="scsi", KERNEL=="sda1", PROGRAM=="/bin/echo -e \\xef\\xe8garbage", RESULT=="__garbage", SYMLINK+="replaced"
1576 desc
=> "read sysfs value from parent device",
1579 devpath
=> "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1580 exp_links
=> ["serial-354172020305000"],
1583 KERNEL=="ttyACM*", ATTRS{serial}=="?*", SYMLINK+="serial-%s{serial}"
1587 desc
=> "match against empty key string",
1590 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1591 exp_links
=> ["ok"],
1592 not_exp_links
=> ["not-1-ok", "not-2-ok", "not-3-ok"],
1595 KERNEL=="sda", ATTRS{nothing}!="", SYMLINK+="not-1-ok"
1596 KERNEL=="sda", ATTRS{nothing}=="", SYMLINK+="not-2-ok"
1597 KERNEL=="sda", ATTRS{vendor}!="", SYMLINK+="ok"
1598 KERNEL=="sda", ATTRS{vendor}=="", SYMLINK+="not-3-ok"
1602 desc
=> "check ACTION value",
1605 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1606 exp_links
=> ["ok"],
1607 not_exp_links
=> ["unknown-not-ok"],
1610 ACTION=="unknown", KERNEL=="sda", SYMLINK+="unknown-not-ok"
1611 ACTION=="add", KERNEL=="sda", SYMLINK+="ok"
1615 desc
=> "final assignment",
1618 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1619 exp_links
=> ["ok"],
1620 exp_perms
=> "root:tty:0640",
1623 KERNEL=="sda", GROUP:="tty"
1624 KERNEL=="sda", GROUP="root", MODE="0640", SYMLINK+="ok"
1628 desc
=> "final assignment 2",
1631 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1632 exp_links
=> ["ok"],
1633 exp_perms
=> "root:tty:0640",
1636 KERNEL=="sda", GROUP:="tty"
1637 SUBSYSTEM=="block", MODE:="640"
1638 KERNEL=="sda", GROUP="root", MODE="0666", SYMLINK+="ok"
1642 desc
=> "env substitution",
1645 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1646 exp_links
=> ["node-add-me"],
1649 KERNEL=="sda", MODE="0666", SYMLINK+="node-\$env{ACTION}-me"
1653 desc
=> "reset list to current value",
1656 devpath
=> "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1657 exp_links
=> ["three"],
1658 not_exp_links
=> ["two", "one"],
1661 KERNEL=="ttyACM[0-9]*", SYMLINK+="one"
1662 KERNEL=="ttyACM[0-9]*", SYMLINK+="two"
1663 KERNEL=="ttyACM[0-9]*", SYMLINK="three"
1667 desc
=> "test empty SYMLINK+ (empty override)",
1670 devpath
=> "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1671 exp_links
=> ["right"],
1672 not_exp_links
=> ["wrong"],
1675 KERNEL=="ttyACM[0-9]*", SYMLINK+="wrong"
1676 KERNEL=="ttyACM[0-9]*", SYMLINK=""
1677 KERNEL=="ttyACM[0-9]*", SYMLINK+="right"
1681 desc
=> "test multi matches",
1684 devpath
=> "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1685 exp_links
=> ["right", "before"],
1688 KERNEL=="ttyACM*", SYMLINK+="before"
1689 KERNEL=="ttyACM*|nothing", SYMLINK+="right"
1693 desc
=> "test multi matches 2",
1696 devpath
=> "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1697 exp_links
=> ["right", "before"],
1698 not_exp_links
=> ["nomatch"],
1701 KERNEL=="dontknow*|*nothing", SYMLINK+="nomatch"
1702 KERNEL=="ttyACM*", SYMLINK+="before"
1703 KERNEL=="dontknow*|ttyACM*|nothing*", SYMLINK+="right"
1707 desc
=> "test multi matches 3",
1710 devpath
=> "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1711 exp_links
=> ["right"],
1712 not_exp_links
=> ["nomatch", "wrong1", "wrong2"],
1715 KERNEL=="dontknow|nothing", SYMLINK+="nomatch"
1716 KERNEL=="dontknow|ttyACM0a|nothing|attyACM0", SYMLINK+="wrong1"
1717 KERNEL=="X|attyACM0|dontknow|ttyACM0a|nothing|attyACM0", SYMLINK+="wrong2"
1718 KERNEL=="dontknow|ttyACM0|nothing", SYMLINK+="right"
1722 desc
=> "test multi matches 4",
1725 devpath
=> "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1726 exp_links
=> ["right"],
1727 not_exp_links
=> ["nomatch", "wrong1", "wrong2", "wrong3"],
1730 KERNEL=="dontknow|nothing", SYMLINK+="nomatch"
1731 KERNEL=="dontknow|ttyACM0a|nothing|attyACM0", SYMLINK+="wrong1"
1732 KERNEL=="X|attyACM0|dontknow|ttyACM0a|nothing|attyACM0", SYMLINK+="wrong2"
1733 KERNEL=="all|dontknow|ttyACM0", SYMLINK+="right"
1734 KERNEL=="ttyACM0a|nothing", SYMLINK+="wrong3"
1738 desc
=> "test multi matches 5",
1741 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1742 exp_links
=> ["found"],
1743 not_exp_name
=> "bad",
1746 KERNEL=="sda", TAG="foo"
1747 TAGS=="|foo", SYMLINK+="found"
1748 TAGS=="|aaa", SYMLINK+="bad"
1752 desc
=> "test multi matches 6",
1755 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1756 exp_links
=> ["found"],
1757 not_exp_name
=> "bad",
1760 KERNEL=="sda", TAG=""
1761 TAGS=="|foo", SYMLINK+="found"
1762 TAGS=="aaa|bbb", SYMLINK+="bad"
1766 desc
=> "test multi matches 7",
1769 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1770 exp_links
=> ["found"],
1771 not_exp_name
=> "bad",
1774 KERNEL=="sda", TAG="foo"
1775 TAGS=="foo||bar", SYMLINK+="found"
1776 TAGS=="aaa||bbb", SYMLINK+="bad"
1780 desc
=> "test multi matches 8",
1783 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1784 exp_links
=> ["found"],
1785 not_exp_name
=> "bad",
1788 KERNEL=="sda", TAG=""
1789 TAGS=="foo||bar", SYMLINK+="found"
1790 TAGS=="aaa|bbb", SYMLINK+="bad"
1794 desc
=> "test multi matches 9",
1797 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1798 exp_links
=> ["found"],
1799 not_exp_name
=> "bad",
1802 KERNEL=="sda", TAG="foo"
1803 TAGS=="foo|", SYMLINK+="found"
1804 TAGS=="aaa|", SYMLINK+="bad"
1808 desc
=> "test multi matches 10",
1811 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1812 exp_links
=> ["found"],
1813 not_exp_name
=> "bad",
1816 KERNEL=="sda", TAG=""
1817 TAGS=="foo|", SYMLINK+="found"
1818 TAGS=="aaa|bbb", SYMLINK+="bad"
1822 desc
=> "test multi matches 11",
1825 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1826 exp_links
=> ["found"],
1827 not_exp_name
=> "bad",
1830 KERNEL=="sda", TAG="c"
1831 TAGS=="foo||bar||c", SYMLINK+="found"
1832 TAGS=="aaa||bbb||ccc", SYMLINK+="bad"
1836 desc
=> "IMPORT parent test",
1839 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1840 exp_links
=> ["parent"],
1843 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
1844 exp_links
=> ["parentenv-parent_right"],
1846 sleep_us
=> 500000, # Serialized! We need to sleep here after adding sda
1848 KERNEL=="sda1", IMPORT{parent}="PARENT*", SYMLINK+="parentenv-\$env{PARENT_KEY}\$env{WRONG_PARENT_KEY}"
1849 KERNEL=="sda", IMPORT{program}="/bin/echo -e \'PARENT_KEY=parent_right\\nWRONG_PARENT_KEY=parent_wrong'"
1850 KERNEL=="sda", SYMLINK+="parent"
1854 desc
=> "GOTO test",
1857 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
1858 exp_links
=> ["right"],
1859 not_exp_test
=> ["wrong", "wrong2"],
1862 KERNEL=="sda1", GOTO="TEST"
1863 KERNEL=="sda1", SYMLINK+="wrong"
1864 KERNEL=="sda1", GOTO="BAD"
1865 KERNEL=="sda1", SYMLINK+="", LABEL="NO"
1866 KERNEL=="sda1", SYMLINK+="right", LABEL="TEST", GOTO="end"
1867 KERNEL=="sda1", SYMLINK+="wrong2", LABEL="BAD"
1872 desc
=> "GOTO label does not exist",
1875 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
1876 exp_links
=> ["right"],
1879 KERNEL=="sda1", GOTO="does-not-exist"
1880 KERNEL=="sda1", SYMLINK+="right",
1885 desc
=> "SYMLINK+ compare test",
1888 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
1889 exp_links
=> ["right", "link"],
1890 not_exp_links
=> ["wrong"],
1893 KERNEL=="sda1", SYMLINK+="link"
1894 KERNEL=="sda1", SYMLINK=="link*", SYMLINK+="right"
1895 KERNEL=="sda1", SYMLINK=="nolink*", SYMLINK+="wrong"
1899 desc
=> "invalid key operation",
1902 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
1903 exp_links
=> ["yes"],
1904 not_exp_links
=> ["no"],
1907 KERNEL="sda1", SYMLINK+="no"
1908 KERNEL=="sda1", SYMLINK+="yes"
1912 desc
=> "operator chars in attribute",
1915 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1916 exp_links
=> ["yes"],
1919 KERNEL=="sda", ATTR{test:colon+plus}=="?*", SYMLINK+="yes"
1923 desc
=> "overlong comment line",
1926 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
1927 exp_links
=> ["yes"],
1928 not_exp_links
=> ["no"],
1931 # 012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
1932 # 012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
1933 KERNEL=="sda1", SYMLINK+=="no"
1934 KERNEL=="sda1", SYMLINK+="yes"
1938 desc
=> "magic subsys/kernel lookup",
1941 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1942 exp_links
=> ["00:16:41:e2:8d:ff"],
1945 KERNEL=="sda", SYMLINK+="\$attr{[net/eth0]address}"
1949 desc
=> "TEST absolute path",
1952 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1953 exp_links
=> ["there"],
1954 not_exp_links
=> ["notthere"],
1957 TEST=="/etc/machine-id", SYMLINK+="there"
1958 TEST!="/etc/machine-id", SYMLINK+="notthere"
1962 desc
=> "TEST subsys/kernel lookup",
1965 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1966 exp_links
=> ["yes"],
1969 KERNEL=="sda", TEST=="[net/eth0]", SYMLINK+="yes"
1973 desc
=> "TEST relative path",
1976 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1977 exp_links
=> ["relative"],
1980 KERNEL=="sda", TEST=="size", SYMLINK+="relative"
1984 desc
=> "TEST wildcard substitution (find queue/nr_requests)",
1987 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1988 exp_links
=> ["found-subdir"],
1991 KERNEL=="sda", TEST=="*/nr_requests", SYMLINK+="found-subdir"
1995 desc
=> "TEST MODE=0000",
1998 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1999 exp_perms
=> "0:0:0000",
2000 exp_rem_error
=> "yes",
2003 KERNEL=="sda", MODE="0000"
2007 desc
=> "TEST PROGRAM feeds OWNER, GROUP, MODE",
2010 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
2011 exp_perms
=> "1:1:0400",
2014 KERNEL=="sda", MODE="666"
2015 KERNEL=="sda", PROGRAM=="/bin/echo 1 1 0400", OWNER="%c{1}", GROUP="%c{2}", MODE="%c{3}"
2019 desc
=> "TEST PROGRAM feeds MODE with overflow",
2022 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
2023 exp_perms
=> "0:0:0440",
2024 exp_rem_error
=> "yes",
2027 KERNEL=="sda", MODE="440"
2028 KERNEL=="sda", PROGRAM=="/bin/echo 0 0 0400letsdoabuffferoverflow0123456789012345789012345678901234567890", OWNER="%c{1}", GROUP="%c{2}", MODE="%c{3}"
2032 desc
=> "magic [subsys/sysname] attribute substitution",
2035 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
2036 exp_links
=> ["sda-8741C4G-end"],
2037 exp_perms
=> "0:0:0600",
2040 KERNEL=="sda", SYMLINK+="%k-%s{[dmi/id]product_name}-end"
2044 desc
=> "builtin path_id",
2047 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
2048 exp_links
=> ["disk/by-path/pci-0000:00:1f.2-scsi-0:0:0:0"],
2051 KERNEL=="sda", IMPORT{builtin}="path_id"
2052 KERNEL=="sda", ENV{ID_PATH}=="?*", SYMLINK+="disk/by-path/\$env{ID_PATH}"
2056 desc
=> "add and match tag",
2059 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
2060 exp_links
=> ["found"],
2061 not_exp_links
=> ["bad"],
2064 SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", TAG+="green"
2065 TAGS=="green", SYMLINK+="found"
2066 TAGS=="blue", SYMLINK+="bad"
2070 desc
=> "don't crash with lots of tags",
2073 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
2074 exp_links
=> ["found"],
2076 rules
=> $rules_10k_tags . <<EOF
2077 TAGS=="test1", TAGS=="test500", TAGS=="test1234", TAGS=="test9999", TAGS=="test10000", SYMLINK+="found"
2081 desc
=> "continuations",
2084 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
2085 exp_links
=> ["found"],
2086 not_exp_name
=> "bad",
2088 rules
=> $rules_10k_tags_continuation . <<EOF
2089 TAGS=="test1", TAGS=="test500", TAGS=="test1234", TAGS=="test9999", TAGS=="test10000", SYMLINK+="bad"
2091 # comment in continuation
2093 # space before comment
2095 # spaces before and after token are dropped
2100 TAGS=="hoge1", TAGS=="hoge2", TAGS=="hoge3", TAGS=="hoge4", SYMLINK+="found"
2104 desc
=> "continuations with empty line",
2107 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
2108 exp_links
=> ["found"],
2109 not_exp_name
=> "bad",
2113 # empty line finishes continuation
2114 KERNEL=="sda", TAG+="foo" \\
2116 KERNEL=="sdb", TAG+="hoge"
2117 KERNEL=="sda", TAG+="aaa" \\
2118 KERNEL=="sdb", TAG+="bbb"
2119 TAGS=="foo", SYMLINK+="found"
2120 TAGS=="aaa", SYMLINK+="bad"
2124 desc
=> "continuations with white only line",
2127 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
2128 exp_links
=> ["found"],
2129 not_exp_name
=> "bad",
2132 # space only line finishes continuation
2133 KERNEL=="sda", TAG+="foo" \\
2135 KERNEL=="sdb", TAG+="hoge"
2136 KERNEL=="sda", TAG+="aaa" \\
2137 KERNEL=="sdb", TAG+="bbb"
2138 TAGS=="foo", SYMLINK+="found"
2139 TAGS=="aaa", SYMLINK+="bad"
2143 desc
=> "multiple devices",
2146 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
2147 exp_links
=> ["part-1"],
2150 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
2151 exp_links
=> ["part-5"],
2154 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda6",
2155 exp_links
=> ["part-6"],
2158 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda7",
2159 exp_links
=> ["part-7"],
2162 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda8",
2163 exp_links
=> ["part-8"],
2166 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda9",
2167 exp_links
=> ["part-9"],
2170 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda10",
2171 exp_links
=> ["part-10"],
2175 SUBSYSTEM=="block", SUBSYSTEMS=="scsi", KERNEL=="sda?*", ENV{DEVTYPE}=="partition", SYMLINK+="part-%n"
2179 desc
=> "multiple devices, same link name, positive prio",
2183 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
2184 exp_links
=> ["part-1"],
2185 not_exp_links
=> ["partition"],
2188 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
2189 exp_links
=> ["part-5"],
2190 not_exp_links
=> ["partition"],
2193 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda6",
2194 not_exp_links
=> ["partition"],
2195 exp_links
=> ["part-6"],
2198 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda7",
2199 exp_links
=> ["part-7", "partition"],
2202 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda8",
2203 not_exp_links
=> ["partition"],
2204 exp_links
=> ["part-8"],
2207 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda9",
2208 not_exp_links
=> ["partition"],
2209 exp_links
=> ["part-9"],
2212 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda10",
2213 not_exp_links
=> ["partition"],
2214 exp_links
=> ["part-10"],
2218 SUBSYSTEM=="block", SUBSYSTEMS=="scsi", KERNEL=="sda?*", ENV{DEVTYPE}=="partition", SYMLINK+="part-%n"
2219 SUBSYSTEM=="block", SUBSYSTEMS=="scsi", KERNEL=="sda?*", ENV{DEVTYPE}=="partition", SYMLINK+="partition"
2220 KERNEL=="*7", OPTIONS+="link_priority=10"
2224 desc
=> "multiple devices, same link name, negative prio",
2227 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
2228 exp_links
=> ["part-1"],
2229 not_exp_links
=> ["partition"],
2232 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
2233 exp_links
=> ["part-5"],
2234 not_exp_links
=> ["partition"],
2237 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda6",
2238 not_exp_links
=> ["partition"],
2239 exp_links
=> ["part-6"],
2242 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda7",
2243 exp_links
=> ["part-7", "partition"],
2246 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda8",
2247 not_exp_links
=> ["partition"],
2248 exp_links
=> ["part-8"],
2251 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda9",
2252 not_exp_links
=> ["partition"],
2253 exp_links
=> ["part-9"],
2256 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda10",
2257 not_exp_links
=> ["partition"],
2258 exp_links
=> ["part-10"],
2262 SUBSYSTEM=="block", SUBSYSTEMS=="scsi", KERNEL=="sda?*", ENV{DEVTYPE}=="partition", SYMLINK+="part-%n"
2263 SUBSYSTEM=="block", SUBSYSTEMS=="scsi", KERNEL=="sda?*", ENV{DEVTYPE}=="partition", SYMLINK+="partition"
2264 KERNEL!="*7", OPTIONS+="link_priority=-10"
2268 desc
=> "multiple devices, same link name, positive prio, sleep",
2271 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
2272 exp_links
=> ["part-1"],
2273 not_exp_links
=> ["partition"],
2276 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
2277 exp_links
=> ["part-5"],
2278 not_exp_links
=> ["partition"],
2281 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda6",
2282 not_exp_links
=> ["partition"],
2283 exp_links
=> ["part-6"],
2286 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda7",
2287 exp_links
=> ["part-7", "partition"],
2290 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda8",
2291 not_exp_links
=> ["partition"],
2292 exp_links
=> ["part-8"],
2295 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda9",
2296 not_exp_links
=> ["partition"],
2297 exp_links
=> ["part-9"],
2300 devpath
=> "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda10",
2301 not_exp_links
=> ["partition"],
2302 exp_links
=> ["part-10"],
2307 SUBSYSTEM=="block", SUBSYSTEMS=="scsi", KERNEL=="sda?*", ENV{DEVTYPE}=="partition", SYMLINK+="part-%n"
2308 SUBSYSTEM=="block", SUBSYSTEMS=="scsi", KERNEL=="sda?*", ENV{DEVTYPE}=="partition", SYMLINK+="partition"
2309 KERNEL=="*7", OPTIONS+="link_priority=10"
2313 desc
=> 'all_block_devs',
2314 generator
=> expect_for_some
("\\/sda6\$", ["blockdev"]),
2317 SUBSYSTEM=="block", SUBSYSTEMS=="scsi", KERNEL=="sd*", SYMLINK+="blockdev"
2318 KERNEL=="sda6", OPTIONS+="link_priority=10"
2326 # create temporary rules
2327 system("mkdir", "-p", "$udev_rules_dir");
2328 open CONF
, ">$udev_rules" || die "unable to create rules file: $udev_rules";
2334 my ($action, $devpath) = @_;
2336 if ($valgrind > 0) {
2337 return system("$udev_bin_valgrind $action $devpath");
2338 } elsif ($gdb > 0) {
2339 return system("$udev_bin_gdb $action $devpath");
2340 } elsif ($strace > 0) {
2341 return system("$udev_bin_strace $action $devpath");
2343 return system("$udev_bin", "$action", "$devpath");
2351 sub permissions_test
{
2352 my($rules, $uid, $gid, $mode) = @_;
2358 $rules->{exp_perms
} =~ m/^(.*):(.*):(.*)$/;
2360 if (defined(getpwnam($1))) {
2361 $userid = int(getpwnam($1));
2365 if ($uid != $userid) { $wrong = 1; }
2368 if (defined(getgrnam($2))) {
2369 $groupid = int(getgrnam($2));
2373 if ($gid != $groupid) { $wrong = 1; }
2376 if (($mode & 07777) != oct($3)) { $wrong = 1; };
2379 print "permissions: ok\n";
2382 printf " expected permissions are: %s:%s:%#o\n", $1, $2, oct($3);
2383 printf " created permissions are : %i:%i:%#o\n", $uid, $gid, $mode & 07777;
2384 print "permissions: error\n";
2390 sub major_minor_test
{
2391 my($rules, $rdev) = @_;
2393 my $major = ($rdev >> 8) & 0xfff;
2394 my $minor = ($rdev & 0xff) | (($rdev >> 12) & 0xfff00);
2397 $rules->{exp_majorminor
} =~ m/^(.*):(.*)$/;
2399 if ($major != $1) { $wrong = 1; };
2402 if ($minor != $2) { $wrong = 1; };
2405 print "major:minor: ok\n";
2408 printf " expected major:minor is: %i:%i\n", $1, $2;
2409 printf " created major:minor is : %i:%i\n", $major, $minor;
2410 print "major:minor: error\n";
2417 system("umount \"$udev_tmpfs\" 2>/dev/null");
2419 mkdir($udev_tmpfs) || die "unable to create udev_tmpfs: $udev_tmpfs\n";
2421 if (system("mount", "-o", "rw,mode=755,nosuid,noexec", "-t", "tmpfs", "tmpfs", $udev_tmpfs)) {
2422 warn "unable to mount tmpfs";
2426 mkdir($udev_dev) || die "unable to create udev_dev: $udev_dev\n";
2427 # setting group and mode of udev_dev ensures the tests work
2428 # even if the parent directory has setgid bit enabled.
2429 chown (0, 0, $udev_dev) || die "unable to chown $udev_dev\n";
2430 chmod (0755, $udev_dev) || die "unable to chmod $udev_dev\n";
2432 if (system("mknod", $udev_dev . "/null", "c", "1", "3")) {
2433 warn "unable to create $udev_dev/null";
2437 # check if we are permitted to create block device nodes
2438 my $block_device_filename = $udev_dev . "/sda";
2439 if (system("mknod", $block_device_filename, "b", "8", "0")) {
2440 warn "unable to create $block_device_filename";
2443 unlink $block_device_filename;
2445 system("cp", "-r", "test/sys/", $udev_sys) && die "unable to copy test/sys";
2447 system("rm", "-rf", "$udev_run");
2449 if (!mkdir($udev_run)) {
2450 warn "unable to create directory $udev_run";
2461 if (defined($device->{devnode
})) {
2462 $devnode = "$udev_dev/$device->{devnode}";
2464 $devnode = "$device->{devpath}";
2465 $devnode =~ s!.*/!$udev_dev/!;
2472 my $devnode = get_devnode
($device);
2474 my @st = lstat("$devnode");
2475 if (! (-b _
|| -c _
)) {
2476 print "add $devnode: error\n";
2477 system("tree", "$udev_dev");
2482 my ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size,
2483 $atime, $mtime, $ctime, $blksize, $blocks) = @st;
2485 if (defined($device->{exp_perms
})) {
2486 permissions_test
($device, $uid, $gid, $mode);
2488 if (defined($device->{exp_majorminor
})) {
2489 major_minor_test
($device, $rdev);
2491 print "add $devnode: ok\n";
2496 sub get_link_target
{
2500 my $dir = "$udev_dev/$link";
2501 my $tgt = readlink("$udev_dev/$link");
2502 $dir =~ s!/[^/]*$!!;
2503 $tgt = abs_path
("$dir/$tgt");
2508 sub check_link_add
{
2509 my ($link, $devnode, $err_expected) = @_;
2511 my @st = lstat("$udev_dev/$link");
2513 my $tgt = get_link_target
($link);
2515 if ($tgt ne $devnode) {
2516 print "symlink $link: error, found -> $tgt\n";
2518 system("tree", "$udev_dev");
2520 print "symlink $link: ok\n";
2524 print "symlink $link: error";
2525 if ($err_expected) {
2526 print " as expected\n";
2530 system("tree", "$udev_dev");
2538 sub check_link_nonexistent
{
2539 my ($link, $devnode, $err_expected) = @_;
2541 if ((-e
"$udev_dev/$link") || (-l
"$udev_dev/$link")) {
2542 my $tgt = get_link_target
($link);
2544 if ($tgt ne $devnode) {
2545 print "nonexistent: '$link' points to other device (ok)\n";
2548 print "nonexistent: error \'$link\' should not be there";
2549 if ($err_expected) {
2550 print " (as expected)\n";
2554 system("tree", "$udev_dev");
2561 print "nonexistent $link: ok\n";
2568 my $devnode = check_devnode
($device);
2570 if (defined($device->{exp_links
})) {
2571 foreach my $link (@
{$device->{exp_links
}}) {
2572 check_link_add
($link, $devnode,
2573 $device->{exp_add_error
});
2576 if (defined $device->{not_exp_links
}) {
2577 foreach my $link (@
{$device->{not_exp_links
}}) {
2578 check_link_nonexistent
($link, $devnode,
2579 $device->{exp_nodev_error
});
2584 sub check_remove_devnode
{
2586 my $devnode = get_devnode
($device);
2588 if (-e
"$devnode") {
2589 print "remove $devnode: error";
2591 system("tree", "$udev_dev");
2596 print "remove $devnode: ok\n";
2601 sub check_link_remove
{
2602 my ($link, $err_expected) = @_;
2604 if ((-e
"$udev_dev/$link") ||
2605 (-l
"$udev_dev/$link")) {
2606 print "remove $link: error";
2607 if ($err_expected) {
2608 print " as expected\n";
2612 system("tree", "$udev_dev");
2618 print "remove $link: ok\n";
2626 check_remove_devnode
($device);
2628 return if (!defined($device->{exp_links
}));
2630 foreach my $link (@
{$device->{exp_links
}}) {
2631 check_link_remove
($link, $device->{exp_rem_error
});
2636 my ($action, $dev, $sleep_us, $sema) = @_;
2638 # Notify main process that this worker has started
2643 usleep
($sleep_us) if defined ($sleep_us);
2644 my $rc = udev
($action, $dev->{devpath
});
2648 sub fork_and_run_udev
{
2649 my ($action, $rules, $sema) = @_;
2650 my @devices = @
{$rules->{devices
}};
2654 $sema->setval(0, 1);
2655 foreach $dev (@devices) {
2659 run_udev
($action, $dev,
2660 defined($rules->{sleep_us
}) ?
$k * $rules->{sleep_us
} : undef,
2668 # This operation waits for all workers to become ready, and
2669 # starts them off when that's the case.
2670 $sema->op(0, -($#devices + 2), 0);
2672 foreach $dev (@devices) {
2676 $pid = waitpid($dev->{pid
}, 0);
2678 print "error waiting for pid dev->{pid}\n";
2680 if (WIFEXITED
($?
)) {
2681 $rc = WEXITSTATUS
($?
);
2684 print "$udev_bin $action for $dev->{devpath} failed with code $rc\n";
2694 my ($rules, $number, $sema) = @_;
2698 my $cur_good = $good;
2699 my $cur_error = $error;
2701 if (!defined $rules->{devices
}) {
2702 $rules->{devices
} = all_block_devs
($rules->{generator
});
2704 @devices = @
{$rules->{devices
}};
2705 # For each device: exit status and devnode test for add & remove
2706 $ntests += 4 * ($#devices + 1);
2708 foreach my $dev (@devices) {
2709 $ntests += 2 * ($#{$dev->{exp_links}} + 1)
2710 + ($#{$dev->{not_exp_links}} + 1)
2711 + (defined $dev->{exp_perms
} ?
1 : 0)
2712 + (defined $dev->{exp_majorminor
} ?
1 : 0);
2714 if (defined $rules->{repeat
}) {
2715 $ntests *= $rules->{repeat
};
2717 $exp_good += $ntests;
2718 print "TEST $number: $rules->{desc}\n";
2719 create_rules
(\
$rules->{rules
});
2722 fork_and_run_udev
("add", $rules, $sema);
2724 foreach my $dev (@devices) {
2728 if (defined($rules->{option
}) && $rules->{option
} eq "keep") {
2733 fork_and_run_udev
("remove", $rules, $sema);
2735 foreach my $dev (@devices) {
2739 if (defined($rules->{repeat
}) && --($rules->{repeat
}) > 0) {
2742 printf "TEST $number: errors: %d good: %d/%d\n\n", $error-$cur_error,
2743 $good-$cur_good, $ntests;
2745 if (defined($rules->{option
}) && $rules->{option
} eq "clean") {
2752 system("rm", "-rf", "$udev_run");
2753 system("umount", "$udev_tmpfs");
2757 # only run if we have root permissions
2758 # due to mknod restrictions
2760 print "Must have root permissions to run properly.\n";
2761 exit($EXIT_TEST_SKIP);
2764 # skip the test when running in a chroot
2765 system("systemd-detect-virt", "-r", "-q");
2767 print "Running in a chroot, skipping the test.\n";
2768 exit($EXIT_TEST_SKIP);
2771 if (!udev_setup
()) {
2772 warn "Failed to set up the environment, skipping the test";
2774 exit($EXIT_TEST_SKIP);
2777 if (system($udev_bin, "check")) {
2778 warn "$udev_bin failed to set up the environment, skipping the test";
2780 exit($EXIT_TEST_SKIP);
2786 foreach my $arg (@ARGV) {
2787 if ($arg =~ m/--valgrind/) {
2789 printf("using valgrind\n");
2790 } elsif ($arg =~ m/--gdb/) {
2792 printf("using gdb\n");
2793 } elsif ($arg =~ m/--strace/) {
2795 printf("using strace\n");
2800 my $sema = IPC
::Semaphore
->new(IPC_PRIVATE
, 1, S_IRUSR
| S_IWUSR
| IPC_CREAT
);
2803 foreach my $arg (@list) {
2804 if (defined($tests[$arg-1]->{desc
})) {
2805 print "udev-test will run test number $arg:\n\n";
2806 run_test
($tests[$arg-1], $arg, $sema);
2808 print "test does not exist.\n";
2813 print "\nudev-test will run ".($#tests + 1)." tests:\n\n";
2815 foreach my $rules (@tests) {
2816 run_test
($rules, $test_num, $sema);
2822 print "$error errors occurred. $good/$exp_good good results.\n\n";