]> git.ipfire.org Git - thirdparty/systemd.git/blob - test/udev-test.pl
test/udev-test.pl: use computed devnode name
[thirdparty/systemd.git] / test / udev-test.pl
1 #!/usr/bin/env 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 © 2004 Leann Ogasawara <ogasawara@osdl.org>
18
19 use warnings;
20 use strict;
21 use POSIX qw(WIFEXITED WEXITSTATUS);
22 use IPC::SysV qw(IPC_PRIVATE S_IRUSR S_IWUSR IPC_CREAT);
23 use IPC::Semaphore;
24 use Time::HiRes qw(usleep);
25
26 my $udev_bin = "./test-udev";
27 my $valgrind = 0;
28 my $gdb = 0;
29 my $strace = 0;
30 my $udev_bin_valgrind = "valgrind --tool=memcheck --leak-check=yes --track-origins=yes --quiet $udev_bin";
31 my $udev_bin_gdb = "gdb --args $udev_bin";
32 my $udev_bin_strace = "strace -efile $udev_bin";
33 my $udev_run = "test/run";
34 my $udev_tmpfs = "test/tmpfs";
35 my $udev_sys = "${udev_tmpfs}/sys";
36 my $udev_dev = "${udev_tmpfs}/dev";
37 my $udev_rules_dir = "$udev_run/udev/rules.d";
38 my $udev_rules = "$udev_rules_dir/udev-test.rules";
39 my $EXIT_TEST_SKIP = 77;
40
41 my $rules_10k_tags = "";
42 for (my $i = 1; $i <= 10000; ++$i) {
43 $rules_10k_tags .= 'KERNEL=="sda", TAG+="test' . $i . "\"\n";
44 }
45
46 my $rules_10k_tags_continuation = "KERNEL==\"sda\", \\\n";
47 for (my $i = 1; $i < 10000; ++$i) {
48 $rules_10k_tags_continuation .= 'TAG+="test' . $i . "\",\\\n";
49 }
50 $rules_10k_tags_continuation .= "TAG+=\"test10000\"\\n";
51
52 my @tests = (
53 {
54 desc => "no rules",
55 devices => [
56 {
57 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
58 exp_rem_error => "yes",
59 },
60 {
61 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
62 exp_rem_error => "yes",
63 }],
64 rules => <<EOF
65 #
66 EOF
67 },
68 {
69 desc => "label test of scsi disc",
70 devices => [
71 {
72 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
73 exp_name => "boot_disk" ,
74 }],
75 rules => <<EOF
76 SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", SYMLINK+="boot_disk%n"
77 KERNEL=="ttyACM0", SYMLINK+="modem"
78 EOF
79 },
80 {
81 desc => "label test of scsi disc",
82 devices => [
83 {
84 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
85 exp_name => "boot_disk" ,
86 }],
87 rules => <<EOF
88 SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", SYMLINK+="boot_disk%n"
89 KERNEL=="ttyACM0", SYMLINK+="modem"
90 EOF
91 },
92 {
93 desc => "label test of scsi disc",
94 devices => [
95 {
96 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
97 exp_name => "boot_disk" ,
98 }],
99 rules => <<EOF
100 SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", SYMLINK+="boot_disk%n"
101 KERNEL=="ttyACM0", SYMLINK+="modem"
102 EOF
103 },
104 {
105 desc => "label test of scsi partition",
106 devices => [
107 {
108 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
109 exp_name => "boot_disk1" ,
110 }],
111 rules => <<EOF
112 SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", SYMLINK+="boot_disk%n"
113 EOF
114 },
115 {
116 desc => "label test of pattern match",
117 devices => [
118 {
119 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
120 exp_name => "boot_disk1" ,
121 }],
122 rules => <<EOF
123 SUBSYSTEMS=="scsi", ATTRS{vendor}=="?ATA", SYMLINK+="boot_disk%n-1"
124 SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA?", SYMLINK+="boot_disk%n-2"
125 SUBSYSTEMS=="scsi", ATTRS{vendor}=="A??", SYMLINK+="boot_disk%n"
126 SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATAS", SYMLINK+="boot_disk%n-3"
127 EOF
128 },
129 {
130 desc => "label test of multiple sysfs files",
131 devices => [
132 {
133 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
134 exp_name => "boot_disk1" ,
135 }],
136 rules => <<EOF
137 SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS X ", SYMLINK+="boot_diskX%n"
138 SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", SYMLINK+="boot_disk%n"
139 EOF
140 },
141 {
142 desc => "label test of max sysfs files (skip invalid rule)",
143 devices => [
144 {
145 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
146 exp_name => "boot_disk1" ,
147 }],
148 rules => <<EOF
149 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"
150 SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", ATTRS{scsi_level}=="6", ATTRS{rev}=="4.06", ATTRS{type}=="0", SYMLINK+="boot_disk%n"
151 EOF
152 },
153 {
154 desc => "catch device by *",
155 devices => [
156 {
157 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
158 exp_name => "modem/0" ,
159 }],
160 rules => <<EOF
161 KERNEL=="ttyACM*", SYMLINK+="modem/%n"
162 EOF
163 },
164 {
165 desc => "catch device by * - take 2",
166 devices => [
167 {
168 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
169 exp_name => "modem/0" ,
170 }],
171 rules => <<EOF
172 KERNEL=="*ACM1", SYMLINK+="bad"
173 KERNEL=="*ACM0", SYMLINK+="modem/%n"
174 EOF
175 },
176 {
177 desc => "catch device by ?",
178 devices => [
179 {
180 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
181 exp_name => "modem/0" ,
182 }],
183 rules => <<EOF
184 KERNEL=="ttyACM??*", SYMLINK+="modem/%n-1"
185 KERNEL=="ttyACM??", SYMLINK+="modem/%n-2"
186 KERNEL=="ttyACM?", SYMLINK+="modem/%n"
187 EOF
188 },
189 {
190 desc => "catch device by character class",
191 devices => [
192 {
193 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
194 exp_name => "modem/0" ,
195 }],
196 rules => <<EOF
197 KERNEL=="ttyACM[A-Z]*", SYMLINK+="modem/%n-1"
198 KERNEL=="ttyACM?[0-9]", SYMLINK+="modem/%n-2"
199 KERNEL=="ttyACM[0-9]*", SYMLINK+="modem/%n"
200 EOF
201 },
202 {
203 desc => "replace kernel name",
204 devices => [
205 {
206 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
207 exp_name => "modem" ,
208 }],
209 rules => <<EOF
210 KERNEL=="ttyACM0", SYMLINK+="modem"
211 EOF
212 },
213 {
214 desc => "Handle comment lines in config file (and replace kernel name)",
215 devices => [
216 {
217 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
218 exp_name => "modem" ,
219 }],
220 rules => <<EOF
221 # this is a comment
222 KERNEL=="ttyACM0", SYMLINK+="modem"
223
224 EOF
225 },
226 {
227 desc => "Handle comment lines in config file with whitespace (and replace kernel name)",
228 devices => [
229 {
230 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
231 exp_name => "modem" ,
232 }],
233 rules => <<EOF
234 # this is a comment with whitespace before the comment
235 KERNEL=="ttyACM0", SYMLINK+="modem"
236
237 EOF
238 },
239 {
240 desc => "Handle whitespace only lines (and replace kernel name)",
241 devices => [
242 {
243 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
244 exp_name => "whitespace" ,
245 }],
246 rules => <<EOF
247
248
249
250 # this is a comment with whitespace before the comment
251 KERNEL=="ttyACM0", SYMLINK+="whitespace"
252
253
254
255 EOF
256 },
257 {
258 desc => "Handle empty lines in config file (and replace kernel name)",
259 devices => [
260 {
261 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
262 exp_name => "modem" ,
263 }],
264 rules => <<EOF
265
266 KERNEL=="ttyACM0", SYMLINK+="modem"
267
268 EOF
269 },
270 {
271 desc => "Handle backslashed multi lines in config file (and replace kernel name)",
272 devices => [
273 {
274 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
275 exp_name => "modem" ,
276 }],
277 rules => <<EOF
278 KERNEL=="ttyACM0", \\
279 SYMLINK+="modem"
280
281 EOF
282 },
283 {
284 desc => "preserve backslashes, if they are not for a newline",
285 devices => [
286 {
287 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
288 exp_name => "aaa",
289 }],
290 rules => <<EOF
291 KERNEL=="ttyACM0", PROGRAM=="/bin/echo -e \\101", RESULT=="A", SYMLINK+="aaa"
292 EOF
293 },
294 {
295 desc => "Handle stupid backslashed multi lines in config file (and replace kernel name)",
296 devices => [
297 {
298 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
299 exp_name => "modem" ,
300 }],
301 rules => <<EOF
302
303 #
304 \\
305
306 \\
307
308 #\\
309
310 KERNEL=="ttyACM0", \\
311 SYMLINK+="modem"
312
313 EOF
314 },
315 {
316 desc => "subdirectory handling",
317 devices => [
318 {
319 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
320 exp_name => "sub/direct/ory/modem" ,
321 }],
322 rules => <<EOF
323 KERNEL=="ttyACM0", SYMLINK+="sub/direct/ory/modem"
324 EOF
325 },
326 {
327 desc => "parent device name match of scsi partition",
328 devices => [
329 {
330 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
331 exp_name => "first_disk5" ,
332 }],
333 rules => <<EOF
334 SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", SYMLINK+="first_disk%n"
335 EOF
336 },
337 {
338 desc => "test substitution chars",
339 devices => [
340 {
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 }],
344 rules => <<EOF
345 SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", SYMLINK+="Major:%M:minor:%m:kernelnumber:%n:id:%b"
346 EOF
347 },
348 {
349 desc => "import of shell-value returned from program",
350 devices => [
351 {
352 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
353 exp_name => "node12345678",
354 }],
355 rules => <<EOF
356 SUBSYSTEMS=="scsi", IMPORT{program}="/bin/echo -e \' TEST_KEY=12345678\\n TEST_key2=98765\'", SYMLINK+="node\$env{TEST_KEY}"
357 KERNEL=="ttyACM0", SYMLINK+="modem"
358 EOF
359 },
360 {
361 desc => "sustitution of sysfs value (%s{file})",
362 devices => [
363 {
364 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
365 exp_name => "disk-ATA-sda" ,
366 }],
367 rules => <<EOF
368 SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", SYMLINK+="disk-%s{vendor}-%k"
369 KERNEL=="ttyACM0", SYMLINK+="modem"
370 EOF
371 },
372 {
373 desc => "program result substitution",
374 devices => [
375 {
376 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
377 exp_name => "special-device-5" ,
378 not_exp_name => "not" ,
379 }],
380 rules => <<EOF
381 SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n special-device", RESULT=="-special-*", SYMLINK+="not"
382 SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n special-device", RESULT=="special-*", SYMLINK+="%c-%n"
383 EOF
384 },
385 {
386 desc => "program result substitution (newline removal)",
387 devices => [
388 {
389 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
390 exp_name => "newline_removed" ,
391 }],
392 rules => <<EOF
393 SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo test", RESULT=="test", SYMLINK+="newline_removed"
394 EOF
395 },
396 {
397 desc => "program result substitution",
398 devices => [
399 {
400 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
401 exp_name => "test-0:0:0:0" ,
402 }],
403 rules => <<EOF
404 SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n test-%b", RESULT=="test-0:0*", SYMLINK+="%c"
405 EOF
406 },
407 {
408 desc => "program with lots of arguments",
409 devices => [
410 {
411 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
412 exp_name => "foo9" ,
413 }],
414 rules => <<EOF
415 SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n foo3 foo4 foo5 foo6 foo7 foo8 foo9", KERNEL=="sda5", SYMLINK+="%c{7}"
416 EOF
417 },
418 {
419 desc => "program with subshell",
420 devices => [
421 {
422 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
423 exp_name => "bar9" ,
424 }],
425 rules => <<EOF
426 SUBSYSTEMS=="scsi", PROGRAM=="/bin/sh -c 'echo foo3 foo4 foo5 foo6 foo7 foo8 foo9 | sed s/foo9/bar9/'", KERNEL=="sda5", SYMLINK+="%c{7}"
427 EOF
428 },
429 {
430 desc => "program arguments combined with apostrophes",
431 devices => [
432 {
433 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
434 exp_name => "foo7" ,
435 }],
436 rules => <<EOF
437 SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n 'foo3 foo4' 'foo5 foo6 foo7 foo8'", KERNEL=="sda5", SYMLINK+="%c{5}"
438 EOF
439 },
440 {
441 desc => "program arguments combined with escaped double quotes, part 1",
442 devices => [
443 {
444 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
445 exp_name => "foo2" ,
446 }],
447 rules => <<EOF
448 SUBSYSTEMS=="scsi", PROGRAM=="/bin/sh -c 'printf %%s \\\"foo1 foo2\\\" | grep \\\"foo1 foo2\\\"'", KERNEL=="sda5", SYMLINK+="%c{2}"
449 EOF
450 },
451 {
452 desc => "program arguments combined with escaped double quotes, part 2",
453 devices => [
454 {
455 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
456 exp_name => "foo2" ,
457 }],
458 rules => <<EOF
459 SUBSYSTEMS=="scsi", PROGRAM=="/bin/sh -c \\\"printf %%s 'foo1 foo2' | grep 'foo1 foo2'\\\"", KERNEL=="sda5", SYMLINK+="%c{2}"
460 EOF
461 },
462 {
463 desc => "program arguments combined with escaped double quotes, part 3",
464 devices => [
465 {
466 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
467 exp_name => "foo2" ,
468 }],
469 rules => <<EOF
470 SUBSYSTEMS=="scsi", PROGRAM=="/bin/sh -c 'printf \\\"%%s %%s\\\" \\\"foo1 foo2\\\" \\\"foo3\\\"| grep \\\"foo1 foo2\\\"'", KERNEL=="sda5", SYMLINK+="%c{2}"
471 EOF
472 },
473 {
474 desc => "characters before the %c{N} substitution",
475 devices => [
476 {
477 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
478 exp_name => "my-foo9" ,
479 }],
480 rules => <<EOF
481 SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n foo3 foo4 foo5 foo6 foo7 foo8 foo9", KERNEL=="sda5", SYMLINK+="my-%c{7}"
482 EOF
483 },
484 {
485 desc => "substitute the second to last argument",
486 devices => [
487 {
488 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
489 exp_name => "my-foo8" ,
490 }],
491 rules => <<EOF
492 SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n foo3 foo4 foo5 foo6 foo7 foo8 foo9", KERNEL=="sda5", SYMLINK+="my-%c{6}"
493 EOF
494 },
495 {
496 desc => "test substitution by variable name",
497 devices => [
498 {
499 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
500 exp_name => "Major:8-minor:5-kernelnumber:5-id:0:0:0:0",
501 }],
502 rules => <<EOF
503 SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", SYMLINK+="Major:\$major-minor:\$minor-kernelnumber:\$number-id:\$id"
504 EOF
505 },
506 {
507 desc => "test substitution by variable name 2",
508 devices => [
509 {
510 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
511 exp_name => "Major:8-minor:5-kernelnumber:5-id:0:0:0:0",
512 }],
513 rules => <<EOF
514 SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", DEVPATH=="*/sda/*", SYMLINK+="Major:\$major-minor:%m-kernelnumber:\$number-id:\$id"
515 EOF
516 },
517 {
518 desc => "test substitution by variable name 3",
519 devices => [
520 {
521 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
522 exp_name => "850:0:0:05" ,
523 }],
524 rules => <<EOF
525 SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", DEVPATH=="*/sda/*", SYMLINK+="%M%m%b%n"
526 EOF
527 },
528 {
529 desc => "test substitution by variable name 4",
530 devices => [
531 {
532 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
533 exp_name => "855" ,
534 }],
535 rules => <<EOF
536 SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", DEVPATH=="*/sda/*", SYMLINK+="\$major\$minor\$number"
537 EOF
538 },
539 {
540 desc => "test substitution by variable name 5",
541 devices => [
542 {
543 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
544 exp_name => "8550:0:0:0" ,
545 }],
546 rules => <<EOF
547 SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", DEVPATH=="*/sda/*", SYMLINK+="\$major%m%n\$id"
548 EOF
549 },
550 {
551 desc => "non matching SUBSYSTEMS for device with no parent",
552 devices => [
553 {
554 devpath => "/devices/virtual/tty/console",
555 exp_name => "TTY",
556 }],
557 rules => <<EOF
558 SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n foo", RESULT=="foo", SYMLINK+="foo"
559 KERNEL=="console", SYMLINK+="TTY"
560 EOF
561 },
562 {
563 desc => "non matching SUBSYSTEMS",
564 devices => [
565 {
566 devpath => "/devices/virtual/tty/console",
567 exp_name => "TTY" ,
568 }],
569 rules => <<EOF
570 SUBSYSTEMS=="foo", ATTRS{dev}=="5:1", SYMLINK+="foo"
571 KERNEL=="console", SYMLINK+="TTY"
572 EOF
573 },
574 {
575 desc => "ATTRS match",
576 devices => [
577 {
578 devpath => "/devices/virtual/tty/console",
579 exp_name => "foo" ,
580 }],
581 rules => <<EOF
582 KERNEL=="console", SYMLINK+="TTY"
583 ATTRS{dev}=="5:1", SYMLINK+="foo"
584 EOF
585 },
586 {
587 desc => "ATTR (empty file)",
588 devices => [
589 {
590 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
591 exp_name => "empty" ,
592 }],
593 rules => <<EOF
594 KERNEL=="sda", ATTR{test_empty_file}=="?*", SYMLINK+="something"
595 KERNEL=="sda", ATTR{test_empty_file}!="", SYMLINK+="not-empty"
596 KERNEL=="sda", ATTR{test_empty_file}=="", SYMLINK+="empty"
597 KERNEL=="sda", ATTR{test_empty_file}!="?*", SYMLINK+="not-something"
598 EOF
599 },
600 {
601 desc => "ATTR (non-existent file)",
602 devices => [
603 {
604 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
605 exp_name => "non-existent" ,
606 }],
607 rules => <<EOF
608 KERNEL=="sda", ATTR{nofile}=="?*", SYMLINK+="something"
609 KERNEL=="sda", ATTR{nofile}!="", SYMLINK+="not-empty"
610 KERNEL=="sda", ATTR{nofile}=="", SYMLINK+="empty"
611 KERNEL=="sda", ATTR{nofile}!="?*", SYMLINK+="not-something"
612 KERNEL=="sda", TEST!="nofile", SYMLINK+="non-existent"
613 KERNEL=="sda", SYMLINK+="wrong"
614 EOF
615 },
616 {
617 desc => "program and bus type match",
618 devices => [
619 {
620 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
621 exp_name => "scsi-0:0:0:0" ,
622 }],
623 rules => <<EOF
624 SUBSYSTEMS=="usb", PROGRAM=="/bin/echo -n usb-%b", SYMLINK+="%c"
625 SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n scsi-%b", SYMLINK+="%c"
626 SUBSYSTEMS=="foo", PROGRAM=="/bin/echo -n foo-%b", SYMLINK+="%c"
627 EOF
628 },
629 {
630 desc => "sysfs parent hierarchy",
631 devices => [
632 {
633 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
634 exp_name => "modem" ,
635 }],
636 rules => <<EOF
637 ATTRS{idProduct}=="007b", SYMLINK+="modem"
638 EOF
639 },
640 {
641 desc => "name test with ! in the name",
642 devices => [
643 {
644 devpath => "/devices/virtual/block/fake!blockdev0",
645 devnode => "fake/blockdev0",
646 exp_name => "is/a/fake/blockdev0" ,
647 }],
648 rules => <<EOF
649 SUBSYSTEMS=="scsi", SYMLINK+="is/not/a/%k"
650 SUBSYSTEM=="block", SYMLINK+="is/a/%k"
651 KERNEL=="ttyACM0", SYMLINK+="modem"
652 EOF
653 },
654 {
655 desc => "name test with ! in the name, but no matching rule",
656 devices => [
657 {
658 devpath => "/devices/virtual/block/fake!blockdev0",
659 devnode => "fake/blockdev0",
660 exp_rem_error => "yes",
661 }],
662 rules => <<EOF
663 KERNEL=="ttyACM0", SYMLINK+="modem"
664 EOF
665 },
666 {
667 desc => "KERNELS rule",
668 devices => [
669 {
670 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
671 exp_name => "scsi-0:0:0:0",
672 }],
673 rules => <<EOF
674 SUBSYSTEMS=="usb", KERNELS=="0:0:0:0", SYMLINK+="not-scsi"
675 SUBSYSTEMS=="scsi", KERNELS=="0:0:0:1", SYMLINK+="no-match"
676 SUBSYSTEMS=="scsi", KERNELS==":0", SYMLINK+="short-id"
677 SUBSYSTEMS=="scsi", KERNELS=="/0:0:0:0", SYMLINK+="no-match"
678 SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", SYMLINK+="scsi-0:0:0:0"
679 EOF
680 },
681 {
682 desc => "KERNELS wildcard all",
683 devices => [
684 {
685 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
686 exp_name => "scsi-0:0:0:0",
687 }],
688 rules => <<EOF
689 SUBSYSTEMS=="scsi", KERNELS=="*:1", SYMLINK+="no-match"
690 SUBSYSTEMS=="scsi", KERNELS=="*:0:1", SYMLINK+="no-match"
691 SUBSYSTEMS=="scsi", KERNELS=="*:0:0:1", SYMLINK+="no-match"
692 SUBSYSTEMS=="scsi", KERNEL=="0:0:0:0", SYMLINK+="before"
693 SUBSYSTEMS=="scsi", KERNELS=="*", SYMLINK+="scsi-0:0:0:0"
694 EOF
695 },
696 {
697 desc => "KERNELS wildcard partial",
698 devices => [
699 {
700 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
701 exp_name => "scsi-0:0:0:0",
702 }],
703 rules => <<EOF
704 SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", SYMLINK+="before"
705 SUBSYSTEMS=="scsi", KERNELS=="*:0", SYMLINK+="scsi-0:0:0:0"
706 EOF
707 },
708 {
709 desc => "KERNELS wildcard partial 2",
710 devices => [
711 {
712 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
713 exp_name => "scsi-0:0:0:0",
714 }],
715 rules => <<EOF
716 SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", SYMLINK+="before"
717 SUBSYSTEMS=="scsi", KERNELS=="*:0:0:0", SYMLINK+="scsi-0:0:0:0"
718 EOF
719 },
720 {
721 desc => "substitute attr with link target value (first match)",
722 devices => [
723 {
724 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
725 exp_name => "driver-is-sd",
726 }],
727 rules => <<EOF
728 SUBSYSTEMS=="scsi", SYMLINK+="driver-is-\$attr{driver}"
729 EOF
730 },
731 {
732 desc => "substitute attr with link target value (currently selected device)",
733 devices => [
734 {
735 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
736 exp_name => "driver-is-ahci",
737 }],
738 rules => <<EOF
739 SUBSYSTEMS=="pci", SYMLINK+="driver-is-\$attr{driver}"
740 EOF
741 },
742 {
743 desc => "ignore ATTRS attribute whitespace",
744 devices => [
745 {
746 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
747 exp_name => "ignored",
748 }],
749 rules => <<EOF
750 SUBSYSTEMS=="scsi", ATTRS{whitespace_test}=="WHITE SPACE", SYMLINK+="ignored"
751 EOF
752 },
753 {
754 desc => "do not ignore ATTRS attribute whitespace",
755 devices => [
756 {
757 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
758 exp_name => "matched-with-space",
759 }],
760 rules => <<EOF
761 SUBSYSTEMS=="scsi", ATTRS{whitespace_test}=="WHITE SPACE ", SYMLINK+="wrong-to-ignore"
762 SUBSYSTEMS=="scsi", ATTRS{whitespace_test}=="WHITE SPACE ", SYMLINK+="matched-with-space"
763 EOF
764 },
765 {
766 desc => "permissions USER=bad GROUP=name",
767 devices => [
768 {
769 devpath => "/devices/virtual/tty/tty33",
770 exp_perms => "0:0:0600",
771 }],
772 rules => <<EOF
773 KERNEL=="tty33", OWNER="bad", GROUP="name"
774 EOF
775 },
776 {
777 desc => "permissions OWNER=1",
778 devices => [
779 {
780 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
781 exp_name => "node",
782 exp_perms => "1::0600",
783 }],
784 rules => <<EOF
785 SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", OWNER="1"
786 EOF
787 },
788 {
789 desc => "permissions GROUP=1",
790 devices => [
791 {
792 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
793 exp_name => "node",
794 exp_perms => ":1:0660",
795 }],
796 rules => <<EOF
797 SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", GROUP="1"
798 EOF
799 },
800 {
801 desc => "textual user id",
802 devices => [
803 {
804 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
805 exp_name => "node",
806 exp_perms => "daemon::0600",
807 }],
808 rules => <<EOF
809 SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", OWNER="daemon"
810 EOF
811 },
812 {
813 desc => "textual group id",
814 devices => [
815 {
816 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
817 exp_name => "node",
818 exp_perms => ":daemon:0660",
819 }],
820 rules => <<EOF
821 SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", GROUP="daemon"
822 EOF
823 },
824 {
825 desc => "textual user/group id",
826 devices => [
827 {
828 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
829 exp_name => "node",
830 exp_perms => "root:audio:0660",
831 }],
832 rules => <<EOF
833 SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", OWNER="root", GROUP="audio"
834 EOF
835 },
836 {
837 desc => "permissions MODE=0777",
838 devices => [
839 {
840 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
841 exp_name => "node",
842 exp_perms => "::0777",
843 }],
844 rules => <<EOF
845 SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", MODE="0777"
846 EOF
847 },
848 {
849 desc => "permissions OWNER=1 GROUP=1 MODE=0777",
850 devices => [
851 {
852 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
853 exp_name => "node",
854 exp_perms => "1:1:0777",
855 }],
856 rules => <<EOF
857 SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", OWNER="1", GROUP="1", MODE="0777"
858 EOF
859 },
860 {
861 desc => "permissions OWNER to 1",
862 devices => [
863 {
864 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
865 exp_perms => "1::",
866 }],
867 rules => <<EOF
868 KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", OWNER="1"
869 EOF
870 },
871 {
872 desc => "permissions GROUP to 1",
873 devices => [
874 {
875 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
876 exp_perms => ":1:0660",
877 }],
878 rules => <<EOF
879 KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", GROUP="1"
880 EOF
881 },
882 {
883 desc => "permissions MODE to 0060",
884 devices => [
885 {
886 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
887 exp_perms => "::0060",
888 }],
889 rules => <<EOF
890 KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", MODE="0060"
891 EOF
892 },
893 {
894 desc => "permissions OWNER, GROUP, MODE",
895 devices => [
896 {
897 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
898 exp_perms => "1:1:0777",
899 }],
900 rules => <<EOF
901 KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", OWNER="1", GROUP="1", MODE="0777"
902 EOF
903 },
904 {
905 desc => "permissions only rule",
906 devices => [
907 {
908 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
909 exp_perms => "1:1:0777",
910 }],
911 rules => <<EOF
912 KERNEL=="ttyACM[0-9]*", OWNER="1", GROUP="1", MODE="0777"
913 KERNEL=="ttyUSX[0-9]*", OWNER="2", GROUP="2", MODE="0444"
914 KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n"
915 EOF
916 },
917 {
918 desc => "multiple permissions only rule",
919 devices => [
920 {
921 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
922 exp_perms => "1:1:0777",
923 }],
924 rules => <<EOF
925 SUBSYSTEM=="tty", OWNER="1"
926 SUBSYSTEM=="tty", GROUP="1"
927 SUBSYSTEM=="tty", MODE="0777"
928 KERNEL=="ttyUSX[0-9]*", OWNER="2", GROUP="2", MODE="0444"
929 KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n"
930 EOF
931 },
932 {
933 desc => "permissions only rule with override at SYMLINK+ rule",
934 devices => [
935 {
936 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
937 exp_perms => "1:2:0777",
938 }],
939 rules => <<EOF
940 SUBSYSTEM=="tty", OWNER="1"
941 SUBSYSTEM=="tty", GROUP="1"
942 SUBSYSTEM=="tty", MODE="0777"
943 KERNEL=="ttyUSX[0-9]*", OWNER="2", GROUP="2", MODE="0444"
944 KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", GROUP="2"
945 EOF
946 },
947 {
948 desc => "major/minor number test",
949 devices => [
950 {
951 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
952 exp_name => "node",
953 exp_majorminor => "8:0",
954 }],
955 rules => <<EOF
956 SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node"
957 EOF
958 },
959 {
960 desc => "big major number test",
961 devices => [
962 {
963 devpath => "/devices/virtual/misc/misc-fake1",
964 exp_name => "node",
965 exp_majorminor => "4095:1",
966 }],
967 rules => <<EOF
968 KERNEL=="misc-fake1", SYMLINK+="node"
969 EOF
970 },
971 {
972 desc => "big major and big minor number test",
973 devices => [
974 {
975 devpath => "/devices/virtual/misc/misc-fake89999",
976 exp_name => "node",
977 exp_majorminor => "4095:89999",
978 }],
979 rules => <<EOF
980 KERNEL=="misc-fake89999", SYMLINK+="node"
981 EOF
982 },
983 {
984 desc => "multiple symlinks with format char",
985 devices => [
986 {
987 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
988 exp_name => "symlink2-ttyACM0",
989 }],
990 rules => <<EOF
991 KERNEL=="ttyACM[0-9]*", SYMLINK="symlink1-%n symlink2-%k symlink3-%b"
992 EOF
993 },
994 {
995 desc => "multiple symlinks with a lot of s p a c e s",
996 devices => [
997 {
998 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
999 exp_name => "one",
1000 not_exp_name => " ",
1001 }],
1002 rules => <<EOF
1003 KERNEL=="ttyACM[0-9]*", SYMLINK=" one two "
1004 EOF
1005 },
1006 {
1007 desc => "symlink with spaces in substituted variable",
1008 devices => [
1009 {
1010 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1011 exp_name => "name-one_two_three-end",
1012 not_exp_name => " ",
1013 }],
1014 rules => <<EOF
1015 ENV{WITH_WS}="one two three"
1016 SYMLINK="name-\$env{WITH_WS}-end"
1017 EOF
1018 },
1019 {
1020 desc => "symlink with leading space in substituted variable",
1021 devices => [
1022 {
1023 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1024 exp_name => "name-one_two_three-end",
1025 not_exp_name => " ",
1026 }],
1027 rules => <<EOF
1028 ENV{WITH_WS}=" one two three"
1029 SYMLINK="name-\$env{WITH_WS}-end"
1030 EOF
1031 },
1032 {
1033 desc => "symlink with trailing space in substituted variable",
1034 devices => [
1035 {
1036 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1037 exp_name => "name-one_two_three-end",
1038 not_exp_name => " ",
1039 }],
1040 rules => <<EOF
1041 ENV{WITH_WS}="one two three "
1042 SYMLINK="name-\$env{WITH_WS}-end"
1043 EOF
1044 },
1045 {
1046 desc => "symlink with lots of space in substituted variable",
1047 devices => [
1048 {
1049 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1050 exp_name => "name-one_two_three-end",
1051 not_exp_name => " ",
1052 }],
1053 rules => <<EOF
1054 ENV{WITH_WS}=" one two three "
1055 SYMLINK="name-\$env{WITH_WS}-end"
1056 EOF
1057 },
1058 {
1059 desc => "symlink with multiple spaces in substituted variable",
1060 devices => [
1061 {
1062 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1063 exp_name => "name-one_two_three-end",
1064 not_exp_name => " ",
1065 }],
1066 rules => <<EOF
1067 ENV{WITH_WS}=" one two three "
1068 SYMLINK="name-\$env{WITH_WS}-end"
1069 EOF
1070 },
1071 {
1072 desc => "symlink with space and var with space, part 1",
1073 devices => [
1074 {
1075 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1076 exp_name => "first",
1077 not_exp_name => " ",
1078 }],
1079 rules => <<EOF
1080 ENV{WITH_WS}=" one two three "
1081 SYMLINK=" first name-\$env{WITH_WS}-end another_symlink a b c "
1082 EOF
1083 },
1084 {
1085 desc => "symlink with space and var with space, part 2",
1086 devices => [
1087 {
1088 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1089 exp_name => "name-one_two_three-end",
1090 not_exp_name => " ",
1091 }],
1092 rules => <<EOF
1093 ENV{WITH_WS}=" one two three "
1094 SYMLINK=" first name-\$env{WITH_WS}-end another_symlink a b c "
1095 EOF
1096 },
1097 {
1098 desc => "symlink with space and var with space, part 3",
1099 devices => [
1100 {
1101 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1102 exp_name => "another_symlink",
1103 not_exp_name => " ",
1104 }],
1105 rules => <<EOF
1106 ENV{WITH_WS}=" one two three "
1107 SYMLINK=" first name-\$env{WITH_WS}-end another_symlink a b c "
1108 EOF
1109 },
1110 {
1111 desc => "symlink creation (same directory)",
1112 devices => [
1113 {
1114 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1115 exp_name => "modem0",
1116 }],
1117 rules => <<EOF
1118 KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", SYMLINK="modem%n"
1119 EOF
1120 },
1121 {
1122 desc => "multiple symlinks",
1123 devices => [
1124 {
1125 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1126 exp_name => "second-0" ,
1127 }],
1128 rules => <<EOF
1129 KERNEL=="ttyACM0", SYMLINK="first-%n second-%n third-%n"
1130 EOF
1131 },
1132 {
1133 desc => "symlink name '.'",
1134 devices => [
1135 {
1136 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1137 exp_name => ".",
1138 exp_add_error => "yes",
1139 exp_rem_error => "yes",
1140 }],
1141 rules => <<EOF
1142 SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="."
1143 EOF
1144 },
1145 {
1146 desc => "symlink node to itself",
1147 devices => [
1148 {
1149 devpath => "/devices/virtual/tty/tty0",
1150 exp_name => "link",
1151 exp_add_error => "yes",
1152 exp_rem_error => "yes",
1153 }],
1154 option => "clean",
1155 rules => <<EOF
1156 KERNEL=="tty0", SYMLINK+="tty0"
1157 EOF
1158 },
1159 {
1160 desc => "symlink %n substitution",
1161 devices => [
1162 {
1163 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1164 exp_name => "symlink0",
1165 }],
1166 rules => <<EOF
1167 KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", SYMLINK+="symlink%n"
1168 EOF
1169 },
1170 {
1171 desc => "symlink %k substitution",
1172 devices => [
1173 {
1174 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1175 exp_name => "symlink-ttyACM0",
1176 }],
1177 rules => <<EOF
1178 KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", SYMLINK+="symlink-%k"
1179 EOF
1180 },
1181 {
1182 desc => "symlink %M:%m substitution",
1183 devices => [
1184 {
1185 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1186 exp_name => "major-166:0",
1187 }],
1188 rules => <<EOF
1189 KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", SYMLINK+="major-%M:%m"
1190 EOF
1191 },
1192 {
1193 desc => "symlink %b substitution",
1194 devices => [
1195 {
1196 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1197 exp_name => "symlink-0:0:0:0",
1198 }],
1199 rules => <<EOF
1200 SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="symlink-%b"
1201 EOF
1202 },
1203 {
1204 desc => "symlink %c substitution",
1205 devices => [
1206 {
1207 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1208 exp_name => "test",
1209 }],
1210 rules => <<EOF
1211 KERNEL=="ttyACM[0-9]*", PROGRAM=="/bin/echo test", SYMLINK+="%c"
1212 EOF
1213 },
1214 {
1215 desc => "symlink %c{N} substitution",
1216 devices => [
1217 {
1218 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1219 exp_name => "test",
1220 }],
1221 rules => <<EOF
1222 KERNEL=="ttyACM[0-9]*", PROGRAM=="/bin/echo symlink test this", SYMLINK+="%c{2}"
1223 EOF
1224 },
1225 {
1226 desc => "symlink %c{N+} substitution",
1227 devices => [
1228 {
1229 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1230 exp_name => "this",
1231 }],
1232 rules => <<EOF
1233 KERNEL=="ttyACM[0-9]*", PROGRAM=="/bin/echo symlink test this", SYMLINK+="%c{2+}"
1234 EOF
1235 },
1236 {
1237 desc => "symlink only rule with %c{N+}",
1238 devices => [
1239 {
1240 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1241 exp_name => "test",
1242 }],
1243 rules => <<EOF
1244 SUBSYSTEMS=="scsi", KERNEL=="sda", PROGRAM=="/bin/echo link test this" SYMLINK+="%c{2+}"
1245 EOF
1246 },
1247 {
1248 desc => "symlink %s{filename} substitution",
1249 devices => [
1250 {
1251 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1252 exp_name => "166:0",
1253 }],
1254 rules => <<EOF
1255 KERNEL=="ttyACM[0-9]*", SYMLINK+="%s{dev}"
1256 EOF
1257 },
1258 {
1259 desc => "program result substitution (numbered part of)",
1260 devices => [
1261 {
1262 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
1263 exp_name => "link1",
1264 }],
1265 rules => <<EOF
1266 SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n node link1 link2", RESULT=="node *", SYMLINK+="%c{2} %c{3}"
1267 EOF
1268 },
1269 {
1270 desc => "program result substitution (numbered part of+)",
1271 devices => [
1272 {
1273 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
1274 exp_name => "link4",
1275 }],
1276 rules => <<EOF
1277 SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n node link1 link2 link3 link4", RESULT=="node *", SYMLINK+="%c{2+}"
1278 EOF
1279 },
1280 {
1281 desc => "SUBSYSTEM match test",
1282 devices => [
1283 {
1284 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1285 exp_name => "node",
1286 }],
1287 rules => <<EOF
1288 SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="should_not_match", SUBSYSTEM=="vc"
1289 SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", SUBSYSTEM=="block"
1290 SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="should_not_match2", SUBSYSTEM=="vc"
1291 EOF
1292 },
1293 {
1294 desc => "DRIVERS match test",
1295 devices => [
1296 {
1297 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1298 exp_name => "node",
1299 }],
1300 rules => <<EOF
1301 SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="should_not_match", DRIVERS=="sd-wrong"
1302 SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", DRIVERS=="sd"
1303 EOF
1304 },
1305 {
1306 desc => "devnode substitution test",
1307 devices => [
1308 {
1309 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1310 exp_name => "node",
1311 }],
1312 rules => <<EOF
1313 SUBSYSTEMS=="scsi", KERNEL=="sda", PROGRAM=="/usr/bin/test -b %N" SYMLINK+="node"
1314 EOF
1315 },
1316 {
1317 desc => "parent node name substitution test",
1318 devices => [
1319 {
1320 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
1321 exp_name => "sda-part-1",
1322 }],
1323 rules => <<EOF
1324 SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="%P-part-1"
1325 EOF
1326 },
1327 {
1328 desc => "udev_root substitution",
1329 devices => [
1330 {
1331 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
1332 exp_name => "start-/dev-end",
1333 }],
1334 rules => <<EOF
1335 SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="start-%r-end"
1336 EOF
1337 },
1338 {
1339 desc => "last_rule option",
1340 devices => [
1341 {
1342 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
1343 exp_name => "last",
1344 }],
1345 rules => <<EOF
1346 SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="last", OPTIONS="last_rule"
1347 SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="very-last"
1348 EOF
1349 },
1350 {
1351 desc => "negation KERNEL!=",
1352 devices => [
1353 {
1354 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
1355 exp_name => "match",
1356 }],
1357 rules => <<EOF
1358 SUBSYSTEMS=="scsi", KERNEL!="sda1", SYMLINK+="matches-but-is-negated"
1359 SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="before"
1360 SUBSYSTEMS=="scsi", KERNEL!="xsda1", SYMLINK+="match"
1361 EOF
1362 },
1363 {
1364 desc => "negation SUBSYSTEM!=",
1365 devices => [
1366 {
1367 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
1368 exp_name => "not-anything",
1369 }],
1370 rules => <<EOF
1371 SUBSYSTEMS=="scsi", SUBSYSTEM=="block", KERNEL!="sda1", SYMLINK+="matches-but-is-negated"
1372 SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="before"
1373 SUBSYSTEMS=="scsi", SUBSYSTEM!="anything", SYMLINK+="not-anything"
1374 EOF
1375 },
1376 {
1377 desc => "negation PROGRAM!= exit code",
1378 devices => [
1379 {
1380 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
1381 exp_name => "nonzero-program",
1382 }],
1383 rules => <<EOF
1384 SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="before"
1385 KERNEL=="sda1", PROGRAM!="/bin/false", SYMLINK+="nonzero-program"
1386 EOF
1387 },
1388 {
1389 desc => "ENV{} test",
1390 devices => [
1391 {
1392 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
1393 exp_name => "true",
1394 }],
1395 rules => <<EOF
1396 ENV{ENV_KEY_TEST}="test"
1397 SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ENV_KEY_TEST}=="go", SYMLINK+="wrong"
1398 SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ENV_KEY_TEST}=="test", SYMLINK+="true"
1399 SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ENV_KEY_TEST}=="bad", SYMLINK+="bad"
1400 EOF
1401 },
1402 {
1403 desc => "ENV{} test",
1404 devices => [
1405 {
1406 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
1407 exp_name => "true",
1408 }],
1409 rules => <<EOF
1410 ENV{ENV_KEY_TEST}="test"
1411 SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ENV_KEY_TEST}=="go", SYMLINK+="wrong"
1412 SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ENV_KEY_TEST}=="yes", ENV{ACTION}=="add", ENV{DEVPATH}=="*/block/sda/sdax1", SYMLINK+="no"
1413 SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ENV_KEY_TEST}=="test", ENV{ACTION}=="add", ENV{DEVPATH}=="*/block/sda/sda1", SYMLINK+="true"
1414 SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ENV_KEY_TEST}=="bad", SYMLINK+="bad"
1415 EOF
1416 },
1417 {
1418 desc => "ENV{} test (assign)",
1419 devices => [
1420 {
1421 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
1422 exp_name => "true",
1423 }],
1424 rules => <<EOF
1425 SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ASSIGN}="true"
1426 SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ASSIGN}=="yes", SYMLINK+="no"
1427 SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="before"
1428 SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ASSIGN}=="true", SYMLINK+="true"
1429 EOF
1430 },
1431 {
1432 desc => "ENV{} test (assign 2 times)",
1433 devices => [
1434 {
1435 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
1436 exp_name => "true",
1437 }],
1438 rules => <<EOF
1439 SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ASSIGN}="true"
1440 SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ASSIGN}="absolutely-\$env{ASSIGN}"
1441 SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="before"
1442 SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ASSIGN}=="yes", SYMLINK+="no"
1443 SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ASSIGN}=="absolutely-true", SYMLINK+="true"
1444 EOF
1445 },
1446 {
1447 desc => "ENV{} test (assign2)",
1448 devices => [
1449 {
1450 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
1451 exp_name => "part",
1452 }],
1453 rules => <<EOF
1454 SUBSYSTEM=="block", KERNEL=="*[0-9]", ENV{PARTITION}="true", ENV{MAINDEVICE}="false"
1455 SUBSYSTEM=="block", KERNEL=="*[!0-9]", ENV{PARTITION}="false", ENV{MAINDEVICE}="true"
1456 ENV{MAINDEVICE}=="true", SYMLINK+="disk"
1457 SUBSYSTEM=="block", SYMLINK+="before"
1458 ENV{PARTITION}=="true", SYMLINK+="part"
1459 EOF
1460 },
1461 {
1462 desc => "untrusted string sanitize",
1463 devices => [
1464 {
1465 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
1466 exp_name => "sane",
1467 }],
1468 rules => <<EOF
1469 SUBSYSTEMS=="scsi", KERNEL=="sda1", PROGRAM=="/bin/echo -e name; (/usr/bin/badprogram)", RESULT=="name_ _/usr/bin/badprogram_", SYMLINK+="sane"
1470 EOF
1471 },
1472 {
1473 desc => "untrusted string sanitize (don't replace utf8)",
1474 devices => [
1475 {
1476 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
1477 exp_name => "uber",
1478 }],
1479 rules => <<EOF
1480 SUBSYSTEMS=="scsi", KERNEL=="sda1", PROGRAM=="/bin/echo -e \\xc3\\xbcber" RESULT=="\xc3\xbcber", SYMLINK+="uber"
1481 EOF
1482 },
1483 {
1484 desc => "untrusted string sanitize (replace invalid utf8)",
1485 devices => [
1486 {
1487 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
1488 exp_name => "replaced",
1489 }],
1490 rules => <<EOF
1491 SUBSYSTEMS=="scsi", KERNEL=="sda1", PROGRAM=="/bin/echo -e \\xef\\xe8garbage", RESULT=="__garbage", SYMLINK+="replaced"
1492 EOF
1493 },
1494 {
1495 desc => "read sysfs value from parent device",
1496 devices => [
1497 {
1498 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1499 exp_name => "serial-354172020305000",
1500 }],
1501 rules => <<EOF
1502 KERNEL=="ttyACM*", ATTRS{serial}=="?*", SYMLINK+="serial-%s{serial}"
1503 EOF
1504 },
1505 {
1506 desc => "match against empty key string",
1507 devices => [
1508 {
1509 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1510 exp_name => "ok",
1511 }],
1512 rules => <<EOF
1513 KERNEL=="sda", ATTRS{nothing}!="", SYMLINK+="not-1-ok"
1514 KERNEL=="sda", ATTRS{nothing}=="", SYMLINK+="not-2-ok"
1515 KERNEL=="sda", ATTRS{vendor}!="", SYMLINK+="ok"
1516 KERNEL=="sda", ATTRS{vendor}=="", SYMLINK+="not-3-ok"
1517 EOF
1518 },
1519 {
1520 desc => "check ACTION value",
1521 devices => [
1522 {
1523 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1524 exp_name => "ok",
1525 }],
1526 rules => <<EOF
1527 ACTION=="unknown", KERNEL=="sda", SYMLINK+="unknown-not-ok"
1528 ACTION=="add", KERNEL=="sda", SYMLINK+="ok"
1529 EOF
1530 },
1531 {
1532 desc => "final assignment",
1533 devices => [
1534 {
1535 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1536 exp_name => "ok",
1537 exp_perms => "root:tty:0640",
1538 }],
1539 rules => <<EOF
1540 KERNEL=="sda", GROUP:="tty"
1541 KERNEL=="sda", GROUP="not-ok", MODE="0640", SYMLINK+="ok"
1542 EOF
1543 },
1544 {
1545 desc => "final assignment 2",
1546 devices => [
1547 {
1548 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1549 exp_name => "ok",
1550 exp_perms => "root:tty:0640",
1551 }],
1552 rules => <<EOF
1553 KERNEL=="sda", GROUP:="tty"
1554 SUBSYSTEM=="block", MODE:="640"
1555 KERNEL=="sda", GROUP="not-ok", MODE="0666", SYMLINK+="ok"
1556 EOF
1557 },
1558 {
1559 desc => "env substitution",
1560 devices => [
1561 {
1562 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1563 exp_name => "node-add-me",
1564 }],
1565 rules => <<EOF
1566 KERNEL=="sda", MODE="0666", SYMLINK+="node-\$env{ACTION}-me"
1567 EOF
1568 },
1569 {
1570 desc => "reset list to current value",
1571 devices => [
1572 {
1573 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1574 exp_name => "three",
1575 not_exp_name => "two",
1576 }],
1577 rules => <<EOF
1578 KERNEL=="ttyACM[0-9]*", SYMLINK+="one"
1579 KERNEL=="ttyACM[0-9]*", SYMLINK+="two"
1580 KERNEL=="ttyACM[0-9]*", SYMLINK="three"
1581 EOF
1582 },
1583 {
1584 desc => "test empty SYMLINK+ (empty override)",
1585 devices => [
1586 {
1587 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1588 exp_name => "right",
1589 not_exp_name => "wrong",
1590 }],
1591 rules => <<EOF
1592 KERNEL=="ttyACM[0-9]*", SYMLINK+="wrong"
1593 KERNEL=="ttyACM[0-9]*", SYMLINK=""
1594 KERNEL=="ttyACM[0-9]*", SYMLINK+="right"
1595 EOF
1596 },
1597 {
1598 desc => "test multi matches",
1599 devices => [
1600 {
1601 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1602 exp_name => "right",
1603 }],
1604 rules => <<EOF
1605 KERNEL=="ttyACM*", SYMLINK+="before"
1606 KERNEL=="ttyACM*|nothing", SYMLINK+="right"
1607 EOF
1608 },
1609 {
1610 desc => "test multi matches 2",
1611 devices => [
1612 {
1613 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1614 exp_name => "right",
1615 }],
1616 rules => <<EOF
1617 KERNEL=="dontknow*|*nothing", SYMLINK+="nomatch"
1618 KERNEL=="ttyACM*", SYMLINK+="before"
1619 KERNEL=="dontknow*|ttyACM*|nothing*", SYMLINK+="right"
1620 EOF
1621 },
1622 {
1623 desc => "test multi matches 3",
1624 devices => [
1625 {
1626 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1627 exp_name => "right",
1628 }],
1629 rules => <<EOF
1630 KERNEL=="dontknow|nothing", SYMLINK+="nomatch"
1631 KERNEL=="dontknow|ttyACM0a|nothing|attyACM0", SYMLINK+="wrong1"
1632 KERNEL=="X|attyACM0|dontknow|ttyACM0a|nothing|attyACM0", SYMLINK+="wrong2"
1633 KERNEL=="dontknow|ttyACM0|nothing", SYMLINK+="right"
1634 EOF
1635 },
1636 {
1637 desc => "test multi matches 4",
1638 devices => [
1639 {
1640 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1641 exp_name => "right",
1642 }],
1643 rules => <<EOF
1644 KERNEL=="dontknow|nothing", SYMLINK+="nomatch"
1645 KERNEL=="dontknow|ttyACM0a|nothing|attyACM0", SYMLINK+="wrong1"
1646 KERNEL=="X|attyACM0|dontknow|ttyACM0a|nothing|attyACM0", SYMLINK+="wrong2"
1647 KERNEL=="all|dontknow|ttyACM0", SYMLINK+="right"
1648 KERNEL=="ttyACM0a|nothing", SYMLINK+="wrong3"
1649 EOF
1650 },
1651 {
1652 desc => "test multi matches 5",
1653 devices => [
1654 {
1655 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1656 exp_name => "found",
1657 not_exp_name => "bad",
1658 }],
1659 rules => <<EOF
1660 KERNEL=="sda", TAG="foo"
1661 TAGS=="|foo", SYMLINK+="found"
1662 TAGS=="|aaa", SYMLINK+="bad"
1663 EOF
1664 },
1665 {
1666 desc => "test multi matches 6",
1667 devices => [
1668 {
1669 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1670 exp_name => "found",
1671 not_exp_name => "bad",
1672 }],
1673 rules => <<EOF
1674 KERNEL=="sda", TAG=""
1675 TAGS=="|foo", SYMLINK+="found"
1676 TAGS=="aaa|bbb", SYMLINK+="bad"
1677 EOF
1678 },
1679 {
1680 desc => "test multi matches 7",
1681 devices => [
1682 {
1683 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1684 exp_name => "found",
1685 not_exp_name => "bad",
1686 }],
1687 rules => <<EOF
1688 KERNEL=="sda", TAG="foo"
1689 TAGS=="foo||bar", SYMLINK+="found"
1690 TAGS=="aaa||bbb", SYMLINK+="bad"
1691 EOF
1692 },
1693 {
1694 desc => "test multi matches 8",
1695 devices => [
1696 {
1697 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1698 exp_name => "found",
1699 not_exp_name => "bad",
1700 }],
1701 rules => <<EOF
1702 KERNEL=="sda", TAG=""
1703 TAGS=="foo||bar", SYMLINK+="found"
1704 TAGS=="aaa|bbb", SYMLINK+="bad"
1705 EOF
1706 },
1707 {
1708 desc => "test multi matches 9",
1709 devices => [
1710 {
1711 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1712 exp_name => "found",
1713 not_exp_name => "bad",
1714 }],
1715 rules => <<EOF
1716 KERNEL=="sda", TAG="foo"
1717 TAGS=="foo|", SYMLINK+="found"
1718 TAGS=="aaa|", SYMLINK+="bad"
1719 EOF
1720 },
1721 {
1722 desc => "test multi matches 10",
1723 devices => [
1724 {
1725 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1726 exp_name => "found",
1727 not_exp_name => "bad",
1728 }],
1729 rules => <<EOF
1730 KERNEL=="sda", TAG=""
1731 TAGS=="foo|", SYMLINK+="found"
1732 TAGS=="aaa|bbb", SYMLINK+="bad"
1733 EOF
1734 },
1735 {
1736 desc => "test multi matches 11",
1737 devices => [
1738 {
1739 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1740 exp_name => "found",
1741 not_exp_name => "bad",
1742 }],
1743 rules => <<EOF
1744 KERNEL=="sda", TAG="c"
1745 TAGS=="foo||bar||c", SYMLINK+="found"
1746 TAGS=="aaa||bbb||ccc", SYMLINK+="bad"
1747 EOF
1748 },
1749 {
1750 desc => "IMPORT parent test sequence 1/2 (keep)",
1751 devices => [
1752 {
1753 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1754 exp_name => "parent",
1755 }],
1756 option => "keep",
1757 rules => <<EOF
1758 KERNEL=="sda", IMPORT{program}="/bin/echo -e \'PARENT_KEY=parent_right\\nWRONG_PARENT_KEY=parent_wrong'"
1759 KERNEL=="sda", SYMLINK+="parent"
1760 EOF
1761 },
1762 {
1763 desc => "IMPORT parent test sequence 2/2 (keep)",
1764 devices => [
1765 {
1766 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
1767 exp_name => "parentenv-parent_right",
1768 }],
1769 option => "clean",
1770 rules => <<EOF
1771 KERNEL=="sda1", IMPORT{parent}="PARENT*", SYMLINK+="parentenv-\$env{PARENT_KEY}\$env{WRONG_PARENT_KEY}"
1772 EOF
1773 },
1774 {
1775 desc => "GOTO test",
1776 devices => [
1777 {
1778 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
1779 exp_name => "right",
1780 }],
1781 rules => <<EOF
1782 KERNEL=="sda1", GOTO="TEST"
1783 KERNEL=="sda1", SYMLINK+="wrong"
1784 KERNEL=="sda1", GOTO="BAD"
1785 KERNEL=="sda1", SYMLINK+="", LABEL="NO"
1786 KERNEL=="sda1", SYMLINK+="right", LABEL="TEST", GOTO="end"
1787 KERNEL=="sda1", SYMLINK+="wrong2", LABEL="BAD"
1788 LABEL="end"
1789 EOF
1790 },
1791 {
1792 desc => "GOTO label does not exist",
1793 devices => [
1794 {
1795 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
1796 exp_name => "right",
1797 }],
1798 rules => <<EOF
1799 KERNEL=="sda1", GOTO="does-not-exist"
1800 KERNEL=="sda1", SYMLINK+="right",
1801 LABEL="exists"
1802 EOF
1803 },
1804 {
1805 desc => "SYMLINK+ compare test",
1806 devices => [
1807 {
1808 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
1809 exp_name => "right",
1810 not_exp_name => "wrong",
1811 }],
1812 rules => <<EOF
1813 KERNEL=="sda1", SYMLINK+="link"
1814 KERNEL=="sda1", SYMLINK=="link*", SYMLINK+="right"
1815 KERNEL=="sda1", SYMLINK=="nolink*", SYMLINK+="wrong"
1816 EOF
1817 },
1818 {
1819 desc => "invalid key operation",
1820 devices => [
1821 {
1822 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
1823 exp_name => "yes",
1824 }],
1825 rules => <<EOF
1826 KERNEL="sda1", SYMLINK+="no"
1827 KERNEL=="sda1", SYMLINK+="yes"
1828 EOF
1829 },
1830 {
1831 desc => "operator chars in attribute",
1832 devices => [
1833 {
1834 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1835 exp_name => "yes",
1836 }],
1837 rules => <<EOF
1838 KERNEL=="sda", ATTR{test:colon+plus}=="?*", SYMLINK+="yes"
1839 EOF
1840 },
1841 {
1842 desc => "overlong comment line",
1843 devices => [
1844 {
1845 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
1846 exp_name => "yes",
1847 }],
1848 rules => <<EOF
1849 # 012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
1850 # 012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
1851 KERNEL=="sda1", SYMLINK+=="no"
1852 KERNEL=="sda1", SYMLINK+="yes"
1853 EOF
1854 },
1855 {
1856 desc => "magic subsys/kernel lookup",
1857 devices => [
1858 {
1859 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1860 exp_name => "00:16:41:e2:8d:ff",
1861 }],
1862 rules => <<EOF
1863 KERNEL=="sda", SYMLINK+="\$attr{[net/eth0]address}"
1864 EOF
1865 },
1866 {
1867 desc => "TEST absolute path",
1868 devices => [
1869 {
1870 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1871 exp_name => "there",
1872 }],
1873 rules => <<EOF
1874 TEST=="/etc/machine-id", SYMLINK+="there"
1875 TEST!="/etc/machine-id", SYMLINK+="notthere"
1876 EOF
1877 },
1878 {
1879 desc => "TEST subsys/kernel lookup",
1880 devices => [
1881 {
1882 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1883 exp_name => "yes",
1884 }],
1885 rules => <<EOF
1886 KERNEL=="sda", TEST=="[net/eth0]", SYMLINK+="yes"
1887 EOF
1888 },
1889 {
1890 desc => "TEST relative path",
1891 devices => [
1892 {
1893 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1894 exp_name => "relative",
1895 }],
1896 rules => <<EOF
1897 KERNEL=="sda", TEST=="size", SYMLINK+="relative"
1898 EOF
1899 },
1900 {
1901 desc => "TEST wildcard substitution (find queue/nr_requests)",
1902 devices => [
1903 {
1904 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1905 exp_name => "found-subdir",
1906 }],
1907 rules => <<EOF
1908 KERNEL=="sda", TEST=="*/nr_requests", SYMLINK+="found-subdir"
1909 EOF
1910 },
1911 {
1912 desc => "TEST MODE=0000",
1913 devices => [
1914 {
1915 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1916 exp_perms => "0:0:0000",
1917 exp_rem_error => "yes",
1918 }],
1919 rules => <<EOF
1920 KERNEL=="sda", MODE="0000"
1921 EOF
1922 },
1923 {
1924 desc => "TEST PROGRAM feeds OWNER, GROUP, MODE",
1925 devices => [
1926 {
1927 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1928 exp_perms => "1:1:0400",
1929 exp_rem_error => "yes",
1930 }],
1931 rules => <<EOF
1932 KERNEL=="sda", MODE="666"
1933 KERNEL=="sda", PROGRAM=="/bin/echo 1 1 0400", OWNER="%c{1}", GROUP="%c{2}", MODE="%c{3}"
1934 EOF
1935 },
1936 {
1937 desc => "TEST PROGRAM feeds MODE with overflow",
1938 devices => [
1939 {
1940 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1941 exp_perms => "0:0:0440",
1942 exp_rem_error => "yes",
1943 }],
1944 rules => <<EOF
1945 KERNEL=="sda", MODE="440"
1946 KERNEL=="sda", PROGRAM=="/bin/echo 0 0 0400letsdoabuffferoverflow0123456789012345789012345678901234567890", OWNER="%c{1}", GROUP="%c{2}", MODE="%c{3}"
1947 EOF
1948 },
1949 {
1950 desc => "magic [subsys/sysname] attribute substitution",
1951 devices => [
1952 {
1953 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1954 exp_name => "sda-8741C4G-end",
1955 exp_perms => "0:0:0600",
1956 }],
1957 rules => <<EOF
1958 KERNEL=="sda", PROGRAM="/bin/true create-envp"
1959 KERNEL=="sda", ENV{TESTENV}="change-envp"
1960 KERNEL=="sda", SYMLINK+="%k-%s{[dmi/id]product_name}-end"
1961 EOF
1962 },
1963 {
1964 desc => "builtin path_id",
1965 devices => [
1966 {
1967 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1968 exp_name => "disk/by-path/pci-0000:00:1f.2-scsi-0:0:0:0",
1969 }],
1970 rules => <<EOF
1971 KERNEL=="sda", IMPORT{builtin}="path_id"
1972 KERNEL=="sda", ENV{ID_PATH}=="?*", SYMLINK+="disk/by-path/\$env{ID_PATH}"
1973 EOF
1974 },
1975 {
1976 desc => "add and match tag",
1977 devices => [
1978 {
1979 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1980 exp_name => "found",
1981 not_exp_name => "bad" ,
1982 }],
1983 rules => <<EOF
1984 SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", TAG+="green"
1985 TAGS=="green", SYMLINK+="found"
1986 TAGS=="blue", SYMLINK+="bad"
1987 EOF
1988 },
1989 {
1990 desc => "don't crash with lots of tags",
1991 devices => [
1992 {
1993 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1994 exp_name => "found",
1995 }],
1996 rules => $rules_10k_tags . <<EOF
1997 TAGS=="test1", TAGS=="test500", TAGS=="test1234", TAGS=="test9999", TAGS=="test10000", SYMLINK+="found"
1998 EOF
1999 },
2000 {
2001 desc => "continuations",
2002 devices => [
2003 {
2004 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
2005 exp_name => "found",
2006 not_exp_name => "bad",
2007 }],
2008 rules => $rules_10k_tags_continuation . <<EOF
2009 TAGS=="test1", TAGS=="test500", TAGS=="test1234", TAGS=="test9999", TAGS=="test10000", SYMLINK+="bad"
2010 KERNEL=="sda",\\
2011 # comment in continuation
2012 TAG+="hoge1",\\
2013 # space before comment
2014 TAG+="hoge2",\\
2015 # spaces before and after token are dropped
2016 TAG+="hoge3", \\
2017 \\
2018 \\
2019 TAG+="hoge4"
2020 TAGS=="hoge1", TAGS=="hoge2", TAGS=="hoge3", TAGS=="hoge4", SYMLINK+="found"
2021 EOF
2022 },
2023 {
2024 desc => "continuations with empty line",
2025 devices => [
2026 {
2027 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
2028 exp_name => "found",
2029 not_exp_name => "bad",
2030
2031 }],
2032 rules => <<EOF
2033 # empty line finishes continuation
2034 KERNEL=="sda", TAG+="foo" \\
2035
2036 KERNEL=="sdb", TAG+="hoge"
2037 KERNEL=="sda", TAG+="aaa" \\
2038 KERNEL=="sdb", TAG+="bbb"
2039 TAGS=="foo", SYMLINK+="found"
2040 TAGS=="aaa", SYMLINK+="bad"
2041 EOF
2042 },
2043 {
2044 desc => "continuations with white only line",
2045 devices => [
2046 {
2047 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
2048 exp_name => "found",
2049 not_exp_name => "bad",
2050 }],
2051 rules => <<EOF
2052 # space only line finishes continuation
2053 KERNEL=="sda", TAG+="foo" \\
2054 \t
2055 KERNEL=="sdb", TAG+="hoge"
2056 KERNEL=="sda", TAG+="aaa" \\
2057 KERNEL=="sdb", TAG+="bbb"
2058 TAGS=="foo", SYMLINK+="found"
2059 TAGS=="aaa", SYMLINK+="bad"
2060 EOF
2061 },
2062 );
2063
2064 sub create_rules {
2065 my ($rules) = @_;
2066
2067 # create temporary rules
2068 system("mkdir", "-p", "$udev_rules_dir");
2069 open CONF, ">$udev_rules" || die "unable to create rules file: $udev_rules";
2070 print CONF $$rules;
2071 close CONF;
2072 }
2073
2074 sub udev {
2075 my ($action, $devpath) = @_;
2076
2077 if ($valgrind > 0) {
2078 return system("$udev_bin_valgrind $action $devpath");
2079 } elsif ($gdb > 0) {
2080 return system("$udev_bin_gdb $action $devpath");
2081 } elsif ($strace > 0) {
2082 return system("$udev_bin_strace $action $devpath");
2083 } else {
2084 return system("$udev_bin", "$action", "$devpath");
2085 }
2086 }
2087
2088 my $error = 0;
2089
2090 sub permissions_test {
2091 my($rules, $uid, $gid, $mode) = @_;
2092
2093 my $wrong = 0;
2094 my $userid;
2095 my $groupid;
2096
2097 $rules->{exp_perms} =~ m/^(.*):(.*):(.*)$/;
2098 if ($1 ne "") {
2099 if (defined(getpwnam($1))) {
2100 $userid = int(getpwnam($1));
2101 } else {
2102 $userid = $1;
2103 }
2104 if ($uid != $userid) { $wrong = 1; }
2105 }
2106 if ($2 ne "") {
2107 if (defined(getgrnam($2))) {
2108 $groupid = int(getgrnam($2));
2109 } else {
2110 $groupid = $2;
2111 }
2112 if ($gid != $groupid) { $wrong = 1; }
2113 }
2114 if ($3 ne "") {
2115 if (($mode & 07777) != oct($3)) { $wrong = 1; };
2116 }
2117 if ($wrong == 0) {
2118 print "permissions: ok\n";
2119 } else {
2120 printf " expected permissions are: %s:%s:%#o\n", $1, $2, oct($3);
2121 printf " created permissions are : %i:%i:%#o\n", $uid, $gid, $mode & 07777;
2122 print "permissions: error\n";
2123 $error++;
2124 sleep(1);
2125 }
2126 }
2127
2128 sub major_minor_test {
2129 my($rules, $rdev) = @_;
2130
2131 my $major = ($rdev >> 8) & 0xfff;
2132 my $minor = ($rdev & 0xff) | (($rdev >> 12) & 0xfff00);
2133 my $wrong = 0;
2134
2135 $rules->{exp_majorminor} =~ m/^(.*):(.*)$/;
2136 if ($1 ne "") {
2137 if ($major != $1) { $wrong = 1; };
2138 }
2139 if ($2 ne "") {
2140 if ($minor != $2) { $wrong = 1; };
2141 }
2142 if ($wrong == 0) {
2143 print "major:minor: ok\n";
2144 } else {
2145 printf " expected major:minor is: %i:%i\n", $1, $2;
2146 printf " created major:minor is : %i:%i\n", $major, $minor;
2147 print "major:minor: error\n";
2148 $error++;
2149 sleep(1);
2150 }
2151 }
2152
2153 sub udev_setup {
2154 system("umount", $udev_tmpfs);
2155 rmdir($udev_tmpfs);
2156 mkdir($udev_tmpfs) || die "unable to create udev_tmpfs: $udev_tmpfs\n";
2157
2158 if (system("mount", "-o", "rw,mode=755,nosuid,noexec", "-t", "tmpfs", "tmpfs", $udev_tmpfs)) {
2159 warn "unable to mount tmpfs";
2160 return 0;
2161 }
2162
2163 mkdir($udev_dev) || die "unable to create udev_dev: $udev_dev\n";
2164 # setting group and mode of udev_dev ensures the tests work
2165 # even if the parent directory has setgid bit enabled.
2166 chown (0, 0, $udev_dev) || die "unable to chown $udev_dev\n";
2167 chmod (0755, $udev_dev) || die "unable to chmod $udev_dev\n";
2168
2169 if (system("mknod", $udev_dev . "/null", "c", "1", "3")) {
2170 warn "unable to create $udev_dev/null";
2171 return 0;
2172 }
2173
2174 # check if we are permitted to create block device nodes
2175 my $block_device_filename = $udev_dev . "/sda";
2176 if (system("mknod", $block_device_filename, "b", "8", "0")) {
2177 warn "unable to create $block_device_filename";
2178 return 0;
2179 }
2180 unlink $block_device_filename;
2181
2182 system("cp", "-r", "test/sys/", $udev_sys) && die "unable to copy test/sys";
2183
2184 system("rm", "-rf", "$udev_run");
2185
2186 if (!mkdir($udev_run)) {
2187 warn "unable to create directory $udev_run";
2188 return 0;
2189 }
2190
2191 return 1;
2192 }
2193
2194 sub get_devnode {
2195 my ($device) = @_;
2196 my $devnode;
2197
2198 if (defined($device->{devnode})) {
2199 $devnode = "$udev_dev/$device->{devnode}";
2200 } else {
2201 $devnode = "$device->{devpath}";
2202 $devnode =~ s!.*/!$udev_dev/!;
2203 }
2204 return $devnode;
2205 }
2206
2207 sub check_devnode {
2208 my ($device) = @_;
2209 my $devnode = get_devnode($device);
2210
2211 my @st = lstat("$devnode");
2212 if (! (-b _ || -c _)) {
2213 print "add $devnode: error\n";
2214 system("tree", "$udev_dev");
2215 $error++;
2216 return undef;
2217 }
2218
2219 my ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size,
2220 $atime, $mtime, $ctime, $blksize, $blocks) = @st;
2221
2222 if (defined($device->{exp_perms})) {
2223 permissions_test($device, $uid, $gid, $mode);
2224 }
2225 if (defined($device->{exp_majorminor})) {
2226 major_minor_test($device, $rdev);
2227 }
2228 print "add $devnode: ok\n";
2229 return $devnode;
2230 }
2231
2232 sub check_add {
2233 my ($device) = @_;
2234
2235 if (defined($device->{not_exp_name})) {
2236 if ((-e "$udev_dev/$device->{not_exp_name}") ||
2237 (-l "$udev_dev/$device->{not_exp_name}")) {
2238 print "nonexistent: error \'$device->{not_exp_name}\' not expected to be there\n";
2239 $error++;
2240 sleep(1);
2241 }
2242 }
2243
2244 my $devnode = check_devnode($device);
2245
2246 print "device \'$device->{devpath}\' expecting node/link \'$device->{exp_name}\'\n";
2247 return if (!defined($device->{exp_name}));
2248
2249 if ((-e "$udev_dev/$device->{exp_name}") ||
2250 (-l "$udev_dev/$device->{exp_name}")) {
2251 print "add $device->{devpath}: ok\n";
2252 } else {
2253 print "add $device->{devpath}: error";
2254 if ($device->{exp_add_error}) {
2255 print " as expected\n";
2256 } else {
2257 print "\n";
2258 system("tree", "$udev_dev");
2259 print "\n";
2260 $error++;
2261 sleep(1);
2262 }
2263 }
2264 }
2265
2266 sub check_remove_devnode {
2267 my ($device) = @_;
2268 my $devnode = get_devnode($device);
2269
2270 if (-e "$devnode") {
2271 print "remove $devnode: error";
2272 print "\n";
2273 system("tree", "$udev_dev");
2274 print "\n";
2275 $error++;
2276 sleep(1);
2277 } else {
2278 print "remove $devnode: ok\n";
2279 }
2280 }
2281
2282 sub check_remove {
2283 my ($device) = @_;
2284
2285 check_remove_devnode($device);
2286
2287 return if (!defined($device->{exp_name}));
2288
2289 if ((-e "$udev_dev/$device->{exp_name}") ||
2290 (-l "$udev_dev/$device->{exp_name}")) {
2291 print "remove $device->{exp_name}: error";
2292 if ($device->{exp_rem_error}) {
2293 print " as expected\n";
2294 } else {
2295 print "\n";
2296 system("tree", "$udev_dev");
2297 print "\n";
2298 $error++;
2299 sleep(1);
2300 }
2301 } else {
2302 print "remove $device->{exp_name}: ok\n";
2303 }
2304 }
2305
2306 sub run_udev {
2307 my ($action, $dev, $sleep_us, $sema) = @_;
2308
2309 # Notify main process that this worker has started
2310 $sema->op(0, 1, 0);
2311
2312 # Wait for start
2313 $sema->op(0, 0, 0);
2314 usleep($sleep_us) if defined ($sleep_us);
2315 my $rc = udev($action, $dev->{devpath});
2316 exit $rc;
2317 }
2318
2319 sub fork_and_run_udev {
2320 my ($action, $rules, $sema) = @_;
2321 my @devices = @{$rules->{devices}};
2322 my $dev;
2323 my $k = 0;
2324
2325 $sema->setval(0, 1);
2326 foreach $dev (@devices) {
2327 my $pid = fork();
2328
2329 if (!$pid) {
2330 run_udev($action, $dev,
2331 defined($rules->{sleep_us}) ? $k * $rules->{sleep_us} : undef,
2332 $sema);
2333 } else {
2334 $dev->{pid} = $pid;
2335 }
2336 $k++;
2337 }
2338
2339 # This operation waits for all workers to become ready, and
2340 # starts them off when that's the case.
2341 $sema->op(0, -($#devices + 2), 0);
2342
2343 foreach $dev (@devices) {
2344 my $rc;
2345 my $pid;
2346
2347 $pid = waitpid($dev->{pid}, 0);
2348 if ($pid == -1) {
2349 print "error waiting for pid dev->{pid}\n";
2350 $error += 1;
2351 }
2352 if (WIFEXITED($?)) {
2353 $rc = WEXITSTATUS($?);
2354
2355 if ($rc) {
2356 print "$udev_bin $action for $dev->{devpath} failed with code $rc\n";
2357 $error += 1;
2358 }
2359 }
2360 }
2361 }
2362
2363 sub run_test {
2364 my ($rules, $number, $sema) = @_;
2365 my $rc;
2366 my @devices = @{$rules->{devices}};
2367
2368 print "TEST $number: $rules->{desc}\n";
2369 create_rules(\$rules->{rules});
2370
2371 fork_and_run_udev("add", $rules, $sema);
2372
2373 foreach my $dev (@devices) {
2374 check_add($dev);
2375 }
2376
2377 if (defined($rules->{option}) && $rules->{option} eq "keep") {
2378 print "\n\n";
2379 return;
2380 }
2381
2382 fork_and_run_udev("remove", $rules, $sema);
2383
2384 foreach my $dev (@devices) {
2385 check_remove($dev);
2386 }
2387
2388 print "\n";
2389
2390 if (defined($rules->{option}) && $rules->{option} eq "clean") {
2391 udev_setup();
2392 }
2393
2394 }
2395
2396 sub cleanup {
2397 system("rm", "-rf", "$udev_run");
2398 system("umount", "$udev_tmpfs");
2399 rmdir($udev_tmpfs);
2400 }
2401
2402 # only run if we have root permissions
2403 # due to mknod restrictions
2404 if (!($<==0)) {
2405 print "Must have root permissions to run properly.\n";
2406 exit($EXIT_TEST_SKIP);
2407 }
2408
2409 # skip the test when running in a chroot
2410 system("systemd-detect-virt", "-r", "-q");
2411 if ($? >> 8 == 0) {
2412 print "Running in a chroot, skipping the test.\n";
2413 exit($EXIT_TEST_SKIP);
2414 }
2415
2416 if (!udev_setup()) {
2417 warn "Failed to set up the environment, skipping the test";
2418 cleanup();
2419 exit($EXIT_TEST_SKIP);
2420 }
2421
2422 if (system($udev_bin, "check")) {
2423 warn "$udev_bin failed to set up the environment, skipping the test";
2424 cleanup();
2425 exit($EXIT_TEST_SKIP);
2426 }
2427
2428 my $test_num = 1;
2429 my @list;
2430
2431 foreach my $arg (@ARGV) {
2432 if ($arg =~ m/--valgrind/) {
2433 $valgrind = 1;
2434 printf("using valgrind\n");
2435 } elsif ($arg =~ m/--gdb/) {
2436 $gdb = 1;
2437 printf("using gdb\n");
2438 } elsif ($arg =~ m/--strace/) {
2439 $strace = 1;
2440 printf("using strace\n");
2441 } else {
2442 push(@list, $arg);
2443 }
2444 }
2445 my $sema = IPC::Semaphore->new(IPC_PRIVATE, 1, S_IRUSR | S_IWUSR | IPC_CREAT);
2446
2447 if ($list[0]) {
2448 foreach my $arg (@list) {
2449 if (defined($tests[$arg-1]->{desc})) {
2450 print "udev-test will run test number $arg:\n\n";
2451 run_test($tests[$arg-1], $arg, $sema);
2452 } else {
2453 print "test does not exist.\n";
2454 }
2455 }
2456 } else {
2457 # test all
2458 print "\nudev-test will run ".($#tests + 1)." tests:\n\n";
2459
2460 foreach my $rules (@tests) {
2461 run_test($rules, $test_num, $sema);
2462 $test_num++;
2463 }
2464 }
2465
2466 $sema->remove;
2467 print "$error errors occurred\n\n";
2468
2469 cleanup();
2470
2471 if ($error > 0) {
2472 exit(1);
2473 }
2474 exit(0);