]> git.ipfire.org Git - thirdparty/systemd.git/blame - test/udev-test.pl
udev-test: add more testcases for SYMLINK
[thirdparty/systemd.git] / test / udev-test.pl
CommitLineData
2a5fcfae 1#!/usr/bin/env perl
8f5bcd61 2# SPDX-License-Identifier: LGPL-2.1-or-later
a367f04e 3
438d4c3c 4# udev test
a367f04e
GKH
5#
6# Provides automated testing of the udev binary.
7# The whole test is self contained in this file, except the matching sysfs tree.
8# Simply extend the @tests array, to add a new test variant.
9#
10# Every test is driven by its own temporary config file.
11# This program prepares the environment, creates the config and calls udev.
12#
65005a7f 13# udev parses the rules, looks at the provided sysfs and
a367f04e
GKH
14# first creates and then removes the device node.
15# After creation and removal the result is checked against the
16# expected value and the result is printed.
17#
810adae9 18# Copyright © 2004 Leann Ogasawara <ogasawara@osdl.org>
a367f04e
GKH
19
20use warnings;
21use strict;
d4076383
ZJS
22
23BEGIN {
24 my $EXIT_TEST_SKIP = 77;
25
26 unless (eval "use POSIX qw(WIFEXITED WEXITSTATUS);
27 use Cwd qw(getcwd abs_path);
28 use IPC::Semaphore;
29 use IPC::SysV qw(IPC_PRIVATE S_IRUSR S_IWUSR IPC_CREAT);
30 use Time::HiRes qw(usleep); 1") {
31 warn "Failed to import dependencies, skipping the test: $@";
32 exit($EXIT_TEST_SKIP);
33 }
34}
a367f04e 35
a7910612
LP
36# Relax sd-device's sysfs verification, since we want to provide a fake sysfs
37# here that actually is a tmpfs.
38$ENV{"SYSTEMD_DEVICE_VERIFY_SYSFS"}="0";
39
9b80f05f 40my $udev_bin = "./test-udev";
912541b0 41my $valgrind = 0;
333e07b7 42my $gdb = 0;
587751eb 43my $strace = 0;
b3f24900 44my $udev_bin_valgrind = "valgrind --tool=memcheck --leak-check=yes --track-origins=yes --quiet $udev_bin";
333e07b7 45my $udev_bin_gdb = "gdb --args $udev_bin";
587751eb 46my $udev_bin_strace = "strace -efile $udev_bin";
6ada823a 47my $udev_run = "test/run";
2ce8d27b 48my $udev_tmpfs = "test/tmpfs";
21d9e3f3
EV
49my $udev_sys = "${udev_tmpfs}/sys";
50my $udev_dev = "${udev_tmpfs}/dev";
6ada823a
KS
51my $udev_rules_dir = "$udev_run/udev/rules.d";
52my $udev_rules = "$udev_rules_dir/udev-test.rules";
0eb3cc88 53my $EXIT_TEST_SKIP = 77;
a367f04e 54
bf8f7583
MP
55my $rules_10k_tags = "";
56for (my $i = 1; $i <= 10000; ++$i) {
d3fc8bf4 57 $rules_10k_tags .= 'KERNEL=="sda", TAG+="test' . $i . "\"\n";
bf8f7583
MP
58}
59
e37a5d90
YW
60my $rules_10k_tags_continuation = "KERNEL==\"sda\", \\\n";
61for (my $i = 1; $i < 10000; ++$i) {
62 $rules_10k_tags_continuation .= 'TAG+="test' . $i . "\",\\\n";
1e797cf5 63}
e37a5d90 64$rules_10k_tags_continuation .= "TAG+=\"test10000\"\\n";
1e797cf5 65
eb44d715
MW
66# Create a device list with all block devices under /sys
67# (except virtual devices and cd-roms)
68# the optional argument exp_func returns expected and non-expected
69# symlinks for the device.
70sub all_block_devs {
71 my ($exp_func) = @_;
72 my @devices;
73
74 foreach my $bd (glob "$udev_sys/dev/block/*") {
75 my $tgt = readlink($bd);
76 my ($exp, $notexp) = (undef, undef);
77
78 next if ($tgt =~ m!/virtual/! || $tgt =~ m!/sr[0-9]*$!);
79
80 $tgt =~ s!^\.\./\.\.!!;
81 ($exp, $notexp) = $exp_func->($tgt) if defined($exp_func);
82 my $device = {
83 devpath => $tgt,
84 exp_links => $exp,
85 not_exp_links => $notexp,
86 };
87 push(@devices, $device);
88 }
89 return \@devices;
90}
91
92# This generator returns a suitable exp_func for use with
93# all_block_devs().
94sub expect_for_some {
95 my ($pattern, $links, $donot) = @_;
96 my $_expect = sub {
97 my ($name) = @_;
98
99 if ($name =~ /$pattern/) {
100 return ($links, undef);
101 } elsif ($donot) {
102 return (undef, $links);
103 } else {
104 return (undef, undef);
105 }
106 };
107 return $_expect;
108}
109
a367f04e 110my @tests = (
912541b0
KS
111 {
112 desc => "no rules",
255c05b7
MW
113 devices => [
114 {
115 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
255c05b7
MW
116 exp_rem_error => "yes",
117 },
118 {
119 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
255c05b7
MW
120 exp_rem_error => "yes",
121 }],
912541b0 122 rules => <<EOF
5754e74c 123#
bcf44d55 124EOF
912541b0
KS
125 },
126 {
127 desc => "label test of scsi disc",
255c05b7
MW
128 devices => [
129 {
130 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
e62acc31 131 exp_links => ["boot_disk"],
255c05b7 132 }],
912541b0 133 rules => <<EOF
0f52fdee 134SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", SYMLINK+="boot_disk%n"
5754e74c 135KERNEL=="ttyACM0", SYMLINK+="modem"
c4edd0ad 136EOF
912541b0
KS
137 },
138 {
139 desc => "label test of scsi disc",
255c05b7
MW
140 devices => [
141 {
142 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
e62acc31 143 exp_links => ["boot_disk"],
255c05b7 144 }],
912541b0 145 rules => <<EOF
5754e74c
KS
146SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", SYMLINK+="boot_disk%n"
147KERNEL=="ttyACM0", SYMLINK+="modem"
c4edd0ad 148EOF
912541b0
KS
149 },
150 {
151 desc => "label test of scsi disc",
255c05b7
MW
152 devices => [
153 {
154 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
e62acc31 155 exp_links => ["boot_disk"],
255c05b7 156 }],
912541b0 157 rules => <<EOF
5754e74c
KS
158SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", SYMLINK+="boot_disk%n"
159KERNEL=="ttyACM0", SYMLINK+="modem"
a367f04e 160EOF
912541b0
KS
161 },
162 {
163 desc => "label test of scsi partition",
255c05b7
MW
164 devices => [
165 {
166 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
e62acc31 167 exp_links => ["boot_disk1"],
255c05b7 168 }],
912541b0 169 rules => <<EOF
5754e74c 170SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", SYMLINK+="boot_disk%n"
83be97ba 171EOF
912541b0
KS
172 },
173 {
174 desc => "label test of pattern match",
255c05b7
MW
175 devices => [
176 {
177 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
e62acc31 178 exp_links => ["boot_disk1", "boot_disk1-4", "boot_disk1-5"],
d94802e9 179 not_exp_links => ["boot_disk1-1", "boot_disk1-2", "boot_disk1-3", "boot_disk1-6", "boot_disk1-7"]
255c05b7 180 }],
912541b0 181 rules => <<EOF
5754e74c
KS
182SUBSYSTEMS=="scsi", ATTRS{vendor}=="?ATA", SYMLINK+="boot_disk%n-1"
183SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA?", SYMLINK+="boot_disk%n-2"
184SUBSYSTEMS=="scsi", ATTRS{vendor}=="A??", SYMLINK+="boot_disk%n"
185SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATAS", SYMLINK+="boot_disk%n-3"
e62acc31
MW
186SUBSYSTEMS=="scsi", ATTRS{vendor}=="AT?", SYMLINK+="boot_disk%n-4"
187SUBSYSTEMS=="scsi", ATTRS{vendor}=="??A", SYMLINK+="boot_disk%n-5"
d94802e9
YW
188SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", GOTO="skip-6"
189SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", SYMLINK+="boot_disk%n-6"
190LABEL="skip-6"
191SUBSYSTEMS=="scsi", GOTO="skip-7"
192SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", SYMLINK+="boot_disk%n-7"
193LABEL="skip-7"
358c8c20 194EOF
912541b0
KS
195 },
196 {
197 desc => "label test of multiple sysfs files",
255c05b7
MW
198 devices => [
199 {
200 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
e62acc31
MW
201 exp_links => ["boot_disk1"],
202 not_exp_links => ["boot_diskX1"],
255c05b7 203 }],
912541b0 204 rules => <<EOF
5754e74c
KS
205SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS X ", SYMLINK+="boot_diskX%n"
206SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", SYMLINK+="boot_disk%n"
358c8c20 207EOF
912541b0
KS
208 },
209 {
210 desc => "label test of max sysfs files (skip invalid rule)",
255c05b7
MW
211 devices => [
212 {
213 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
e62acc31 214 exp_links => ["boot_disk1", "boot_diskXY1"],
2c5f119c 215 not_exp_links => ["boot_diskXX1"],
255c05b7 216 }],
912541b0 217 rules => <<EOF
5754e74c 218SUBSYSTEMS=="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"
e62acc31 219SUBSYSTEMS=="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"
2c5f119c
YW
220SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", ATTRS{scsi_level}=="6", ATTRS{rev}=="4.06", ATTRS{type}=="0", SYMLINK+="boot_disk%n"
221EOF
222 },
223 {
224 desc => "SYMLINK tests",
225 devices => [
226 {
227 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
228 exp_links => ["link1", "link2/foo", "link3/aaa/bbb",
7e430500 229 "abs1", "abs2/foo", "abs3/aaa/bbb",
2c5f119c
YW
230 "default___replace_test/foo_aaa",
231 "string_escape___replace/foo_bbb",
232 "env_with_space",
233 "default/replace/mode_foo__hoge",
234 "replace_env_harder_foo__hoge"],
7e430500 235 not_exp_links => ["removed1", "removed2", "removed3", "unsafe/../../path", "/nondev/path/will/be/refused"],
2c5f119c
YW
236 }],
237 rules => <<EOF
7e430500
YW
238SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", SYMLINK+="removed1"
239SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", SYMLINK-="removed1"
240SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", SYMLINK+="/./dev///removed2"
241SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", SYMLINK-="removed2"
242SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", SYMLINK+="././removed3"
243SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", SYMLINK-="/dev//./removed3/./"
2c5f119c 244SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", SYMLINK+="unsafe/../../path"
7e430500
YW
245SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", SYMLINK+="/nondev/path/will/be/refused"
246SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", SYMLINK+="link1 .///link2/././/foo//./ .///link3/aaa/bbb"
247SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", SYMLINK+="/dev/abs1 /dev//./abs2///foo/./ ////dev/abs3/aaa/bbb"
2c5f119c
YW
248SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", SYMLINK+="default?;;replace%%test/foo'aaa"
249SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", OPTIONS="string_escape=replace", SYMLINK+="string_escape replace/foo%%bbb"
250SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", ENV{.HOGE}="env with space", SYMLINK+="%E{.HOGE}"
251SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", ENV{.HOGE}="default/replace/mode?foo;;hoge", SYMLINK+="%E{.HOGE}"
252SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", OPTIONS="string_escape=replace", ENV{.HOGE}="replace/env/harder?foo;;hoge", SYMLINK+="%E{.HOGE}"
0db6d4cc 253EOF
912541b0
KS
254 },
255 {
256 desc => "catch device by *",
255c05b7
MW
257 devices => [
258 {
259 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
e62acc31 260 exp_links => ["modem/0", "catch-all"],
255c05b7 261 }],
912541b0 262 rules => <<EOF
5754e74c 263KERNEL=="ttyACM*", SYMLINK+="modem/%n"
e62acc31 264KERNEL=="*", SYMLINK+="catch-all"
2e317184 265EOF
912541b0 266 },
e62acc31 267 # 10
912541b0
KS
268 {
269 desc => "catch device by * - take 2",
255c05b7
MW
270 devices => [
271 {
272 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
e62acc31
MW
273 exp_links => ["modem/0"],
274 not_exp_links => ["bad"],
255c05b7 275 }],
912541b0 276 rules => <<EOF
5754e74c
KS
277KERNEL=="*ACM1", SYMLINK+="bad"
278KERNEL=="*ACM0", SYMLINK+="modem/%n"
9f1da361 279EOF
912541b0
KS
280 },
281 {
282 desc => "catch device by ?",
255c05b7
MW
283 devices => [
284 {
285 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
e62acc31
MW
286 exp_links => ["modem/0"],
287 not_exp_links => ["modem/0-1", "modem/0-2"],
255c05b7 288 }],
912541b0 289 rules => <<EOF
5754e74c
KS
290KERNEL=="ttyACM??*", SYMLINK+="modem/%n-1"
291KERNEL=="ttyACM??", SYMLINK+="modem/%n-2"
292KERNEL=="ttyACM?", SYMLINK+="modem/%n"
9f1da361 293EOF
912541b0
KS
294 },
295 {
296 desc => "catch device by character class",
255c05b7
MW
297 devices => [
298 {
299 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
e62acc31
MW
300 exp_links => ["modem/0"],
301 not_exp_links => ["modem/0-1", "modem/0-2"],
255c05b7 302 }],
912541b0 303 rules => <<EOF
5754e74c
KS
304KERNEL=="ttyACM[A-Z]*", SYMLINK+="modem/%n-1"
305KERNEL=="ttyACM?[0-9]", SYMLINK+="modem/%n-2"
306KERNEL=="ttyACM[0-9]*", SYMLINK+="modem/%n"
a367f04e 307EOF
912541b0
KS
308 },
309 {
46bc71b2 310 desc => "don't replace kernel name",
255c05b7
MW
311 devices => [
312 {
313 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
e62acc31 314 exp_links => ["modem"],
255c05b7 315 }],
912541b0 316 rules => <<EOF
5754e74c 317KERNEL=="ttyACM0", SYMLINK+="modem"
281ff00a 318EOF
912541b0
KS
319 },
320 {
46bc71b2 321 desc => "Handle comment lines in config file (and don't replace kernel name)",
255c05b7
MW
322 devices => [
323 {
324 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
e62acc31 325 exp_links => ["modem"],
255c05b7 326 }],
912541b0 327 rules => <<EOF
281ff00a 328# this is a comment
5754e74c 329KERNEL=="ttyACM0", SYMLINK+="modem"
281ff00a
GKH
330
331EOF
912541b0
KS
332 },
333 {
46bc71b2 334 desc => "Handle comment lines in config file with whitespace (and don't replace kernel name)",
255c05b7
MW
335 devices => [
336 {
337 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
e62acc31 338 exp_links => ["modem"],
255c05b7 339 }],
912541b0 340 rules => <<EOF
d914e445 341 # this is a comment with whitespace before the comment
5754e74c 342KERNEL=="ttyACM0", SYMLINK+="modem"
281ff00a 343
3db7fa27 344EOF
912541b0
KS
345 },
346 {
46bc71b2 347 desc => "Handle whitespace only lines (and don't replace kernel name)",
255c05b7
MW
348 devices => [
349 {
350 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
e62acc31 351 exp_links => ["whitespace"],
255c05b7 352 }],
912541b0 353 rules => <<EOF
3db7fa27 354
3db7fa27 355
d914e445
KS
356
357 # this is a comment with whitespace before the comment
5754e74c 358KERNEL=="ttyACM0", SYMLINK+="whitespace"
3db7fa27 359
d914e445 360
3db7fa27 361
281ff00a 362EOF
912541b0
KS
363 },
364 {
46bc71b2 365 desc => "Handle empty lines in config file (and don't replace kernel name)",
255c05b7
MW
366 devices => [
367 {
368 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
e62acc31 369 exp_links => ["modem"],
255c05b7 370 }],
912541b0 371 rules => <<EOF
281ff00a 372
5754e74c 373KERNEL=="ttyACM0", SYMLINK+="modem"
281ff00a 374
9f8dfa19 375EOF
912541b0
KS
376 },
377 {
46bc71b2 378 desc => "Handle backslashed multi lines in config file (and don't replace kernel name)",
255c05b7
MW
379 devices => [
380 {
381 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
e62acc31 382 exp_links => ["modem"],
255c05b7 383 }],
912541b0 384 rules => <<EOF
c7fcba1b 385KERNEL=="ttyACM0", \\
5754e74c 386SYMLINK+="modem"
9f8dfa19 387
77313cd0 388EOF
912541b0
KS
389 },
390 {
391 desc => "preserve backslashes, if they are not for a newline",
255c05b7
MW
392 devices => [
393 {
394 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
e62acc31 395 exp_links => ["aaa"],
255c05b7 396 }],
912541b0 397 rules => <<EOF
d914e445 398KERNEL=="ttyACM0", PROGRAM=="/bin/echo -e \\101", RESULT=="A", SYMLINK+="aaa"
9f8dfa19 399EOF
912541b0 400 },
46bc71b2 401 # 20
912541b0 402 {
46bc71b2 403 desc => "Handle stupid backslashed multi lines in config file (and don't replace kernel name)",
255c05b7
MW
404 devices => [
405 {
406 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
e62acc31 407 exp_links => ["modem"],
255c05b7 408 }],
912541b0 409 rules => <<EOF
9f8dfa19
KS
410
411#
412\\
413
d960ad15 414\\
9f8dfa19
KS
415
416#\\
417
c7fcba1b 418KERNEL=="ttyACM0", \\
912541b0 419 SYMLINK+="modem"
9f8dfa19 420
5499d319 421EOF
912541b0
KS
422 },
423 {
424 desc => "subdirectory handling",
255c05b7
MW
425 devices => [
426 {
427 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
e62acc31 428 exp_links => ["sub/direct/ory/modem"],
255c05b7 429 }],
912541b0 430 rules => <<EOF
5754e74c 431KERNEL=="ttyACM0", SYMLINK+="sub/direct/ory/modem"
a367f04e 432EOF
912541b0
KS
433 },
434 {
435 desc => "parent device name match of scsi partition",
255c05b7
MW
436 devices => [
437 {
438 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
e62acc31 439 exp_links => ["first_disk5"],
255c05b7 440 }],
912541b0 441 rules => <<EOF
5754e74c 442SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", SYMLINK+="first_disk%n"
c4edd0ad 443EOF
912541b0
KS
444 },
445 {
446 desc => "test substitution chars",
255c05b7
MW
447 devices => [
448 {
449 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
e62acc31 450 exp_links => ["Major:8:minor:5:kernelnumber:5:id:0:0:0:0"],
255c05b7 451 }],
912541b0 452 rules => <<EOF
5754e74c 453SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", SYMLINK+="Major:%M:minor:%m:kernelnumber:%n:id:%b"
319c6700 454EOF
912541b0
KS
455 },
456 {
457 desc => "import of shell-value returned from program",
255c05b7
MW
458 devices => [
459 {
460 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
e62acc31 461 exp_links => ["node12345678"],
255c05b7 462 }],
912541b0 463 rules => <<EOF
d914e445 464SUBSYSTEMS=="scsi", IMPORT{program}="/bin/echo -e \' TEST_KEY=12345678\\n TEST_key2=98765\'", SYMLINK+="node\$env{TEST_KEY}"
5754e74c 465KERNEL=="ttyACM0", SYMLINK+="modem"
a27cd06c 466EOF
912541b0
KS
467 },
468 {
d3f044dd 469 desc => "substitution of sysfs value (%s{file})",
255c05b7
MW
470 devices => [
471 {
472 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
e62acc31
MW
473 exp_links => ["disk-ATA-sda"],
474 not_exp_links => ["modem"],
255c05b7 475 }],
912541b0 476 rules => <<EOF
5754e74c
KS
477SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", SYMLINK+="disk-%s{vendor}-%k"
478KERNEL=="ttyACM0", SYMLINK+="modem"
a367f04e 479EOF
912541b0
KS
480 },
481 {
482 desc => "program result substitution",
255c05b7
MW
483 devices => [
484 {
485 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
e62acc31
MW
486 exp_links => ["special-device-5"],
487 not_exp_links => ["not"],
255c05b7 488 }],
912541b0 489 rules => <<EOF
d914e445
KS
490SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n special-device", RESULT=="-special-*", SYMLINK+="not"
491SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n special-device", RESULT=="special-*", SYMLINK+="%c-%n"
bbbe503e 492EOF
912541b0
KS
493 },
494 {
495 desc => "program result substitution (newline removal)",
255c05b7
MW
496 devices => [
497 {
498 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
e62acc31 499 exp_links => ["newline_removed"],
255c05b7 500 }],
912541b0 501 rules => <<EOF
d914e445 502SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo test", RESULT=="test", SYMLINK+="newline_removed"
f3b04a2e 503EOF
912541b0
KS
504 },
505 {
506 desc => "program result substitution",
255c05b7
MW
507 devices => [
508 {
509 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
e62acc31 510 exp_links => ["test-0:0:0:0"],
255c05b7 511 }],
912541b0 512 rules => <<EOF
d914e445 513SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n test-%b", RESULT=="test-0:0*", SYMLINK+="%c"
dde05ccb 514EOF
912541b0
KS
515 },
516 {
517 desc => "program with lots of arguments",
255c05b7
MW
518 devices => [
519 {
520 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
e62acc31
MW
521 exp_links => ["foo9"],
522 not_exp_links => ["foo3", "foo4", "foo5", "foo6", "foo7", "foo8"],
255c05b7 523 }],
912541b0 524 rules => <<EOF
d914e445 525SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n foo3 foo4 foo5 foo6 foo7 foo8 foo9", KERNEL=="sda5", SYMLINK+="%c{7}"
35b38379 526EOF
912541b0
KS
527 },
528 {
529 desc => "program with subshell",
255c05b7
MW
530 devices => [
531 {
532 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
e62acc31
MW
533 exp_links => ["bar9"],
534 not_exp_links => ["foo3", "foo4", "foo5", "foo6", "foo7", "foo8"],
255c05b7 535 }],
912541b0 536 rules => <<EOF
d914e445 537SUBSYSTEMS=="scsi", PROGRAM=="/bin/sh -c 'echo foo3 foo4 foo5 foo6 foo7 foo8 foo9 | sed s/foo9/bar9/'", KERNEL=="sda5", SYMLINK+="%c{7}"
35b38379 538EOF
912541b0
KS
539 },
540 {
541 desc => "program arguments combined with apostrophes",
255c05b7
MW
542 devices => [
543 {
544 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
e62acc31
MW
545 exp_links => ["foo7"],
546 not_exp_links => ["foo3", "foo4", "foo5", "foo6", "foo8"],
255c05b7 547 }],
912541b0 548 rules => <<EOF
d914e445 549SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n 'foo3 foo4' 'foo5 foo6 foo7 foo8'", KERNEL=="sda5", SYMLINK+="%c{5}"
7e760b79
FB
550EOF
551 },
552 {
553 desc => "program arguments combined with escaped double quotes, part 1",
255c05b7
MW
554 devices => [
555 {
556 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
e62acc31
MW
557 exp_links => ["foo2"],
558 not_exp_links => ["foo1"],
255c05b7 559 }],
7e760b79
FB
560 rules => <<EOF
561SUBSYSTEMS=="scsi", PROGRAM=="/bin/sh -c 'printf %%s \\\"foo1 foo2\\\" | grep \\\"foo1 foo2\\\"'", KERNEL=="sda5", SYMLINK+="%c{2}"
562EOF
563 },
564 {
565 desc => "program arguments combined with escaped double quotes, part 2",
255c05b7
MW
566 devices => [
567 {
568 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
e62acc31
MW
569 exp_links => ["foo2"],
570 not_exp_links => ["foo1"],
255c05b7 571 }],
7e760b79
FB
572 rules => <<EOF
573SUBSYSTEMS=="scsi", PROGRAM=="/bin/sh -c \\\"printf %%s 'foo1 foo2' | grep 'foo1 foo2'\\\"", KERNEL=="sda5", SYMLINK+="%c{2}"
574EOF
575 },
576 {
577 desc => "program arguments combined with escaped double quotes, part 3",
255c05b7
MW
578 devices => [
579 {
580 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
e62acc31
MW
581 exp_links => ["foo2"],
582 not_exp_links => ["foo1", "foo3"],
255c05b7 583 }],
7e760b79
FB
584 rules => <<EOF
585SUBSYSTEMS=="scsi", PROGRAM=="/bin/sh -c 'printf \\\"%%s %%s\\\" \\\"foo1 foo2\\\" \\\"foo3\\\"| grep \\\"foo1 foo2\\\"'", KERNEL=="sda5", SYMLINK+="%c{2}"
56c963dc 586EOF
912541b0
KS
587 },
588 {
589 desc => "characters before the %c{N} substitution",
255c05b7
MW
590 devices => [
591 {
592 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
e62acc31 593 exp_links => ["my-foo9"],
255c05b7 594 }],
912541b0 595 rules => <<EOF
d914e445 596SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n foo3 foo4 foo5 foo6 foo7 foo8 foo9", KERNEL=="sda5", SYMLINK+="my-%c{7}"
56c963dc 597EOF
912541b0
KS
598 },
599 {
600 desc => "substitute the second to last argument",
255c05b7
MW
601 devices => [
602 {
603 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
e62acc31
MW
604 exp_links => ["my-foo8"],
605 not_exp_links => ["my-foo3", "my-foo4", "my-foo5", "my-foo6", "my-foo7", "my-foo9"],
255c05b7 606 }],
912541b0 607 rules => <<EOF
d914e445 608SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n foo3 foo4 foo5 foo6 foo7 foo8 foo9", KERNEL=="sda5", SYMLINK+="my-%c{6}"
bf5d2964 609EOF
912541b0
KS
610 },
611 {
612 desc => "test substitution by variable name",
255c05b7
MW
613 devices => [
614 {
615 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
e62acc31 616 exp_links => ["Major:8-minor:5-kernelnumber:5-id:0:0:0:0"],
255c05b7 617 }],
912541b0 618 rules => <<EOF
5754e74c 619SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", SYMLINK+="Major:\$major-minor:\$minor-kernelnumber:\$number-id:\$id"
bf5d2964 620EOF
912541b0
KS
621 },
622 {
623 desc => "test substitution by variable name 2",
255c05b7
MW
624 devices => [
625 {
626 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
e62acc31 627 exp_links => ["Major:8-minor:5-kernelnumber:5-id:0:0:0:0"],
255c05b7 628 }],
912541b0 629 rules => <<EOF
5754e74c 630SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", DEVPATH=="*/sda/*", SYMLINK+="Major:\$major-minor:%m-kernelnumber:\$number-id:\$id"
bf5d2964 631EOF
912541b0
KS
632 },
633 {
634 desc => "test substitution by variable name 3",
255c05b7
MW
635 devices => [
636 {
637 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
e62acc31 638 exp_links => ["850:0:0:05"],
255c05b7 639 }],
912541b0 640 rules => <<EOF
5754e74c 641SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", DEVPATH=="*/sda/*", SYMLINK+="%M%m%b%n"
bf5d2964 642EOF
912541b0
KS
643 },
644 {
645 desc => "test substitution by variable name 4",
255c05b7
MW
646 devices => [
647 {
648 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
e62acc31 649 exp_links => ["855"],
255c05b7 650 }],
912541b0 651 rules => <<EOF
5754e74c 652SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", DEVPATH=="*/sda/*", SYMLINK+="\$major\$minor\$number"
bf5d2964 653EOF
912541b0
KS
654 },
655 {
656 desc => "test substitution by variable name 5",
255c05b7
MW
657 devices => [
658 {
659 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
e62acc31 660 exp_links => ["8550:0:0:0"],
255c05b7 661 }],
912541b0 662 rules => <<EOF
5754e74c 663SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", DEVPATH=="*/sda/*", SYMLINK+="\$major%m%n\$id"
8ff8bbba 664EOF
912541b0
KS
665 },
666 {
667 desc => "non matching SUBSYSTEMS for device with no parent",
255c05b7
MW
668 devices => [
669 {
670 devpath => "/devices/virtual/tty/console",
e62acc31
MW
671 exp_links => ["TTY"],
672 not_exp_links => ["foo"],
255c05b7 673 }],
912541b0 674 rules => <<EOF
d914e445 675SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n foo", RESULT=="foo", SYMLINK+="foo"
5754e74c 676KERNEL=="console", SYMLINK+="TTY"
1d936fbc 677EOF
912541b0
KS
678 },
679 {
680 desc => "non matching SUBSYSTEMS",
255c05b7
MW
681 devices => [
682 {
683 devpath => "/devices/virtual/tty/console",
e62acc31
MW
684 exp_links => ["TTY"],
685 not_exp_links => ["foo"],
255c05b7 686 }],
912541b0 687 rules => <<EOF
5754e74c
KS
688SUBSYSTEMS=="foo", ATTRS{dev}=="5:1", SYMLINK+="foo"
689KERNEL=="console", SYMLINK+="TTY"
64682333 690EOF
912541b0
KS
691 },
692 {
693 desc => "ATTRS match",
255c05b7
MW
694 devices => [
695 {
696 devpath => "/devices/virtual/tty/console",
e62acc31 697 exp_links => ["foo", "TTY"],
255c05b7 698 }],
912541b0 699 rules => <<EOF
5754e74c
KS
700KERNEL=="console", SYMLINK+="TTY"
701ATTRS{dev}=="5:1", SYMLINK+="foo"
a402404f 702EOF
912541b0
KS
703 },
704 {
705 desc => "ATTR (empty file)",
255c05b7
MW
706 devices => [
707 {
708 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
e62acc31
MW
709 exp_links => ["empty", "not-something"],
710 not_exp_links => ["something", "not-empty"],
255c05b7 711 }],
912541b0 712 rules => <<EOF
5754e74c
KS
713KERNEL=="sda", ATTR{test_empty_file}=="?*", SYMLINK+="something"
714KERNEL=="sda", ATTR{test_empty_file}!="", SYMLINK+="not-empty"
715KERNEL=="sda", ATTR{test_empty_file}=="", SYMLINK+="empty"
716KERNEL=="sda", ATTR{test_empty_file}!="?*", SYMLINK+="not-something"
a402404f 717EOF
912541b0
KS
718 },
719 {
720 desc => "ATTR (non-existent file)",
255c05b7
MW
721 devices => [
722 {
723 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
e62acc31
MW
724 exp_links => ["non-existent", "wrong"],
725 not_exp_links => ["something", "empty", "not-empty",
726 "not-something", "something"],
255c05b7 727 }],
912541b0 728 rules => <<EOF
5754e74c
KS
729KERNEL=="sda", ATTR{nofile}=="?*", SYMLINK+="something"
730KERNEL=="sda", ATTR{nofile}!="", SYMLINK+="not-empty"
731KERNEL=="sda", ATTR{nofile}=="", SYMLINK+="empty"
732KERNEL=="sda", ATTR{nofile}!="?*", SYMLINK+="not-something"
733KERNEL=="sda", TEST!="nofile", SYMLINK+="non-existent"
734KERNEL=="sda", SYMLINK+="wrong"
772558f4 735EOF
912541b0
KS
736 },
737 {
738 desc => "program and bus type match",
255c05b7
MW
739 devices => [
740 {
741 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
e62acc31 742 exp_links => ["scsi-0:0:0:0"],
255c05b7 743 }],
912541b0 744 rules => <<EOF
d914e445
KS
745SUBSYSTEMS=="usb", PROGRAM=="/bin/echo -n usb-%b", SYMLINK+="%c"
746SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n scsi-%b", SYMLINK+="%c"
747SUBSYSTEMS=="foo", PROGRAM=="/bin/echo -n foo-%b", SYMLINK+="%c"
50e5de03 748EOF
912541b0
KS
749 },
750 {
751 desc => "sysfs parent hierarchy",
255c05b7
MW
752 devices => [
753 {
754 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
e62acc31 755 exp_links => ["modem"],
255c05b7 756 }],
912541b0 757 rules => <<EOF
5754e74c 758ATTRS{idProduct}=="007b", SYMLINK+="modem"
f0142622 759EOF
912541b0
KS
760 },
761 {
762 desc => "name test with ! in the name",
255c05b7
MW
763 devices => [
764 {
765 devpath => "/devices/virtual/block/fake!blockdev0",
f0dccf01 766 devnode => "fake/blockdev0",
e62acc31
MW
767 exp_links => ["is/a/fake/blockdev0"],
768 not_exp_links => ["is/not/a/fake/blockdev0", "modem"],
255c05b7 769 }],
912541b0 770 rules => <<EOF
5754e74c
KS
771SUBSYSTEMS=="scsi", SYMLINK+="is/not/a/%k"
772SUBSYSTEM=="block", SYMLINK+="is/a/%k"
773KERNEL=="ttyACM0", SYMLINK+="modem"
b9fc973b 774EOF
912541b0
KS
775 },
776 {
777 desc => "name test with ! in the name, but no matching rule",
255c05b7
MW
778 devices => [
779 {
780 devpath => "/devices/virtual/block/fake!blockdev0",
f0dccf01 781 devnode => "fake/blockdev0",
e62acc31 782 not_exp_links => ["modem"],
255c05b7 783 }],
912541b0 784 rules => <<EOF
5754e74c 785KERNEL=="ttyACM0", SYMLINK+="modem"
93656247 786EOF
912541b0
KS
787 },
788 {
789 desc => "KERNELS rule",
255c05b7
MW
790 devices => [
791 {
792 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
e62acc31
MW
793 exp_links => ["scsi-0:0:0:0"],
794 not_exp_links => ["no-match", "short-id", "not-scsi"],
255c05b7 795 }],
912541b0 796 rules => <<EOF
5754e74c
KS
797SUBSYSTEMS=="usb", KERNELS=="0:0:0:0", SYMLINK+="not-scsi"
798SUBSYSTEMS=="scsi", KERNELS=="0:0:0:1", SYMLINK+="no-match"
799SUBSYSTEMS=="scsi", KERNELS==":0", SYMLINK+="short-id"
800SUBSYSTEMS=="scsi", KERNELS=="/0:0:0:0", SYMLINK+="no-match"
801SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", SYMLINK+="scsi-0:0:0:0"
93656247 802EOF
912541b0
KS
803 },
804 {
805 desc => "KERNELS wildcard all",
255c05b7
MW
806 devices => [
807 {
808 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
e62acc31
MW
809 exp_links => ["scsi-0:0:0:0"],
810 not_exp_links => ["no-match", "before"],
255c05b7 811 }],
912541b0 812 rules => <<EOF
5754e74c
KS
813SUBSYSTEMS=="scsi", KERNELS=="*:1", SYMLINK+="no-match"
814SUBSYSTEMS=="scsi", KERNELS=="*:0:1", SYMLINK+="no-match"
815SUBSYSTEMS=="scsi", KERNELS=="*:0:0:1", SYMLINK+="no-match"
816SUBSYSTEMS=="scsi", KERNEL=="0:0:0:0", SYMLINK+="before"
817SUBSYSTEMS=="scsi", KERNELS=="*", SYMLINK+="scsi-0:0:0:0"
93656247 818EOF
912541b0
KS
819 },
820 {
821 desc => "KERNELS wildcard partial",
255c05b7
MW
822 devices => [
823 {
824 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
e62acc31 825 exp_links => ["scsi-0:0:0:0", "before"],
255c05b7 826 }],
912541b0 827 rules => <<EOF
5754e74c
KS
828SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", SYMLINK+="before"
829SUBSYSTEMS=="scsi", KERNELS=="*:0", SYMLINK+="scsi-0:0:0:0"
93656247 830EOF
912541b0
KS
831 },
832 {
833 desc => "KERNELS wildcard partial 2",
255c05b7
MW
834 devices => [
835 {
836 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
e62acc31 837 exp_links => ["scsi-0:0:0:0", "before"],
255c05b7
MW
838 }],
839 rules => <<EOF
5754e74c
KS
840SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", SYMLINK+="before"
841SUBSYSTEMS=="scsi", KERNELS=="*:0:0:0", SYMLINK+="scsi-0:0:0:0"
eef54479 842EOF
912541b0
KS
843 },
844 {
845 desc => "substitute attr with link target value (first match)",
255c05b7
MW
846 devices => [
847 {
848 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
e62acc31 849 exp_links => ["driver-is-sd"],
255c05b7 850 }],
912541b0 851 rules => <<EOF
5754e74c 852SUBSYSTEMS=="scsi", SYMLINK+="driver-is-\$attr{driver}"
eef54479 853EOF
912541b0
KS
854 },
855 {
856 desc => "substitute attr with link target value (currently selected device)",
255c05b7
MW
857 devices => [
858 {
859 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
e62acc31 860 exp_links => ["driver-is-ahci"],
255c05b7 861 }],
912541b0 862 rules => <<EOF
5754e74c 863SUBSYSTEMS=="pci", SYMLINK+="driver-is-\$attr{driver}"
d5f91372 864EOF
912541b0
KS
865 },
866 {
867 desc => "ignore ATTRS attribute whitespace",
255c05b7
MW
868 devices => [
869 {
870 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
e62acc31 871 exp_links => ["ignored"],
255c05b7 872 }],
912541b0 873 rules => <<EOF
5754e74c 874SUBSYSTEMS=="scsi", ATTRS{whitespace_test}=="WHITE SPACE", SYMLINK+="ignored"
d5f91372 875EOF
912541b0
KS
876 },
877 {
878 desc => "do not ignore ATTRS attribute whitespace",
255c05b7
MW
879 devices => [
880 {
881 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
e62acc31
MW
882 exp_links => ["matched-with-space"],
883 not_exp_links => ["wrong-to-ignore"],
255c05b7 884 }],
912541b0 885 rules => <<EOF
5754e74c
KS
886SUBSYSTEMS=="scsi", ATTRS{whitespace_test}=="WHITE SPACE ", SYMLINK+="wrong-to-ignore"
887SUBSYSTEMS=="scsi", ATTRS{whitespace_test}=="WHITE SPACE ", SYMLINK+="matched-with-space"
0a5417a0 888EOF
912541b0
KS
889 },
890 {
891 desc => "permissions USER=bad GROUP=name",
255c05b7
MW
892 devices => [
893 {
894 devpath => "/devices/virtual/tty/tty33",
255c05b7
MW
895 exp_perms => "0:0:0600",
896 }],
912541b0 897 rules => <<EOF
6ada823a 898KERNEL=="tty33", OWNER="bad", GROUP="name"
b8669191 899EOF
912541b0
KS
900 },
901 {
9158d03e 902 desc => "permissions OWNER=1",
255c05b7
MW
903 devices => [
904 {
905 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
e62acc31 906 exp_links => ["node"],
255c05b7
MW
907 exp_perms => "1::0600",
908 }],
912541b0 909 rules => <<EOF
9158d03e 910SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", OWNER="1"
b8669191 911EOF
912541b0
KS
912 },
913 {
9158d03e 914 desc => "permissions GROUP=1",
255c05b7
MW
915 devices => [
916 {
917 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
e62acc31 918 exp_links => ["node"],
255c05b7
MW
919 exp_perms => ":1:0660",
920 }],
912541b0 921 rules => <<EOF
9158d03e 922SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", GROUP="1"
9b434de1 923EOF
912541b0
KS
924 },
925 {
926 desc => "textual user id",
255c05b7
MW
927 devices => [
928 {
929 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
e62acc31 930 exp_links => ["node"],
255c05b7
MW
931 exp_perms => "daemon::0600",
932 }],
912541b0 933 rules => <<EOF
24a01950 934SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", OWNER="daemon"
9b434de1 935EOF
912541b0
KS
936 },
937 {
938 desc => "textual group id",
255c05b7
MW
939 devices => [
940 {
941 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
e62acc31 942 exp_links => ["node"],
255c05b7
MW
943 exp_perms => ":daemon:0660",
944 }],
912541b0 945 rules => <<EOF
5754e74c 946SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", GROUP="daemon"
c8278763 947EOF
912541b0
KS
948 },
949 {
950 desc => "textual user/group id",
255c05b7
MW
951 devices => [
952 {
953 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
e62acc31 954 exp_links => ["node"],
255c05b7
MW
955 exp_perms => "root:audio:0660",
956 }],
912541b0 957 rules => <<EOF
a9030b81 958SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", OWNER="root", GROUP="audio"
b8669191 959EOF
912541b0
KS
960 },
961 {
962 desc => "permissions MODE=0777",
255c05b7
MW
963 devices => [
964 {
965 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
e62acc31 966 exp_links => ["node"],
255c05b7
MW
967 exp_perms => "::0777",
968 }],
912541b0 969 rules => <<EOF
5754e74c 970SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", MODE="0777"
b8669191 971EOF
912541b0
KS
972 },
973 {
9158d03e 974 desc => "permissions OWNER=1 GROUP=1 MODE=0777",
255c05b7
MW
975 devices => [
976 {
977 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
e62acc31 978 exp_links => ["node"],
255c05b7
MW
979 exp_perms => "1:1:0777",
980 }],
912541b0 981 rules => <<EOF
9158d03e 982SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", OWNER="1", GROUP="1", MODE="0777"
b8669191 983EOF
912541b0
KS
984 },
985 {
9158d03e 986 desc => "permissions OWNER to 1",
255c05b7
MW
987 devices => [
988 {
989 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
255c05b7
MW
990 exp_perms => "1::",
991 }],
912541b0 992 rules => <<EOF
9158d03e 993KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", OWNER="1"
b8669191 994EOF
912541b0
KS
995 },
996 {
9158d03e 997 desc => "permissions GROUP to 1",
255c05b7
MW
998 devices => [
999 {
1000 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
255c05b7
MW
1001 exp_perms => ":1:0660",
1002 }],
912541b0 1003 rules => <<EOF
9158d03e 1004KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", GROUP="1"
b8669191 1005EOF
912541b0
KS
1006 },
1007 {
1008 desc => "permissions MODE to 0060",
255c05b7
MW
1009 devices => [
1010 {
1011 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
255c05b7
MW
1012 exp_perms => "::0060",
1013 }],
912541b0 1014 rules => <<EOF
5754e74c 1015KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", MODE="0060"
b8669191 1016EOF
912541b0
KS
1017 },
1018 {
1019 desc => "permissions OWNER, GROUP, MODE",
255c05b7
MW
1020 devices => [
1021 {
1022 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
255c05b7
MW
1023 exp_perms => "1:1:0777",
1024 }],
912541b0 1025 rules => <<EOF
9158d03e 1026KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", OWNER="1", GROUP="1", MODE="0777"
e9390146 1027EOF
912541b0
KS
1028 },
1029 {
1030 desc => "permissions only rule",
255c05b7
MW
1031 devices => [
1032 {
1033 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
255c05b7
MW
1034 exp_perms => "1:1:0777",
1035 }],
912541b0 1036 rules => <<EOF
9158d03e
TG
1037KERNEL=="ttyACM[0-9]*", OWNER="1", GROUP="1", MODE="0777"
1038KERNEL=="ttyUSX[0-9]*", OWNER="2", GROUP="2", MODE="0444"
5754e74c 1039KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n"
eb870090 1040EOF
912541b0
KS
1041 },
1042 {
1043 desc => "multiple permissions only rule",
255c05b7
MW
1044 devices => [
1045 {
1046 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
255c05b7
MW
1047 exp_perms => "1:1:0777",
1048 }],
912541b0 1049 rules => <<EOF
9158d03e
TG
1050SUBSYSTEM=="tty", OWNER="1"
1051SUBSYSTEM=="tty", GROUP="1"
28ce66de 1052SUBSYSTEM=="tty", MODE="0777"
9158d03e 1053KERNEL=="ttyUSX[0-9]*", OWNER="2", GROUP="2", MODE="0444"
5754e74c 1054KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n"
eb870090 1055EOF
912541b0
KS
1056 },
1057 {
1058 desc => "permissions only rule with override at SYMLINK+ rule",
255c05b7
MW
1059 devices => [
1060 {
1061 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
255c05b7
MW
1062 exp_perms => "1:2:0777",
1063 }],
912541b0 1064 rules => <<EOF
9158d03e
TG
1065SUBSYSTEM=="tty", OWNER="1"
1066SUBSYSTEM=="tty", GROUP="1"
28ce66de 1067SUBSYSTEM=="tty", MODE="0777"
9158d03e
TG
1068KERNEL=="ttyUSX[0-9]*", OWNER="2", GROUP="2", MODE="0444"
1069KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", GROUP="2"
fa19f181 1070EOF
912541b0
KS
1071 },
1072 {
1073 desc => "major/minor number test",
255c05b7
MW
1074 devices => [
1075 {
1076 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
e62acc31 1077 exp_links => ["node"],
255c05b7
MW
1078 exp_majorminor => "8:0",
1079 }],
912541b0 1080 rules => <<EOF
5754e74c 1081SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node"
7d12d4e1 1082EOF
912541b0
KS
1083 },
1084 {
1085 desc => "big major number test",
255c05b7
MW
1086 devices => [
1087 {
1088 devpath => "/devices/virtual/misc/misc-fake1",
e62acc31 1089 exp_links => ["node"],
255c05b7
MW
1090 exp_majorminor => "4095:1",
1091 }],
1092 rules => <<EOF
5754e74c 1093KERNEL=="misc-fake1", SYMLINK+="node"
7d12d4e1 1094EOF
912541b0
KS
1095 },
1096 {
1097 desc => "big major and big minor number test",
255c05b7
MW
1098 devices => [
1099 {
1100 devpath => "/devices/virtual/misc/misc-fake89999",
e62acc31 1101 exp_links => ["node"],
255c05b7
MW
1102 exp_majorminor => "4095:89999",
1103 }],
912541b0 1104 rules => <<EOF
5754e74c 1105KERNEL=="misc-fake89999", SYMLINK+="node"
2b0f835c 1106EOF
912541b0
KS
1107 },
1108 {
1109 desc => "multiple symlinks with format char",
255c05b7
MW
1110 devices => [
1111 {
1112 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
e62acc31 1113 exp_links => ["symlink1-0", "symlink2-ttyACM0", "symlink3-"],
255c05b7 1114 }],
912541b0 1115 rules => <<EOF
5754e74c 1116KERNEL=="ttyACM[0-9]*", SYMLINK="symlink1-%n symlink2-%k symlink3-%b"
7b2bdb4b 1117EOF
912541b0
KS
1118 },
1119 {
1120 desc => "multiple symlinks with a lot of s p a c e s",
255c05b7
MW
1121 devices => [
1122 {
1123 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
e62acc31
MW
1124 exp_links => ["one", "two"],
1125 not_exp_links => [" "],
255c05b7 1126 }],
912541b0 1127 rules => <<EOF
5754e74c 1128KERNEL=="ttyACM[0-9]*", SYMLINK=" one two "
9cd7b128
DS
1129EOF
1130 },
1131 {
1132 desc => "symlink with spaces in substituted variable",
255c05b7
MW
1133 devices => [
1134 {
1135 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
e62acc31
MW
1136 exp_links => ["name-one_two_three-end"],
1137 not_exp_links => [" "],
255c05b7 1138 }],
9cd7b128
DS
1139 rules => <<EOF
1140ENV{WITH_WS}="one two three"
1141SYMLINK="name-\$env{WITH_WS}-end"
1142EOF
1143 },
1144 {
1145 desc => "symlink with leading space in substituted variable",
255c05b7
MW
1146 devices => [
1147 {
1148 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
e62acc31
MW
1149 exp_links => ["name-one_two_three-end"],
1150 not_exp_links => [" "],
255c05b7 1151 }],
9cd7b128
DS
1152 rules => <<EOF
1153ENV{WITH_WS}=" one two three"
1154SYMLINK="name-\$env{WITH_WS}-end"
1155EOF
1156 },
1157 {
1158 desc => "symlink with trailing space in substituted variable",
255c05b7
MW
1159 devices => [
1160 {
1161 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
e62acc31
MW
1162 exp_links => ["name-one_two_three-end"],
1163 not_exp_links => [" "],
255c05b7 1164 }],
9cd7b128
DS
1165 rules => <<EOF
1166ENV{WITH_WS}="one two three "
1167SYMLINK="name-\$env{WITH_WS}-end"
1168EOF
1169 },
1170 {
1171 desc => "symlink with lots of space in substituted variable",
255c05b7
MW
1172 devices => [
1173 {
1174 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
e62acc31
MW
1175 exp_links => ["name-one_two_three-end"],
1176 not_exp_links => [" "],
255c05b7 1177 }],
9cd7b128
DS
1178 rules => <<EOF
1179ENV{WITH_WS}=" one two three "
1180SYMLINK="name-\$env{WITH_WS}-end"
1181EOF
1182 },
1183 {
1184 desc => "symlink with multiple spaces in substituted variable",
255c05b7
MW
1185 devices => [
1186 {
1187 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
e62acc31
MW
1188 exp_links => ["name-one_two_three-end"],
1189 not_exp_links => [" "],
255c05b7 1190 }],
9cd7b128
DS
1191 rules => <<EOF
1192ENV{WITH_WS}=" one two three "
1193SYMLINK="name-\$env{WITH_WS}-end"
1194EOF
1195 },
1196 {
e62acc31 1197 desc => "symlink with space and var with space",
255c05b7
MW
1198 devices => [
1199 {
1200 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
2084fe0d
MW
1201 exp_links => ["first", "name-one_two_three-end",
1202 "another_symlink", "a", "b", "c"],
1203 not_exp_links => [" "],
255c05b7 1204 }],
9cd7b128
DS
1205 rules => <<EOF
1206ENV{WITH_WS}=" one two three "
1207SYMLINK=" first name-\$env{WITH_WS}-end another_symlink a b c "
33989b96
YW
1208EOF
1209 },
1210 {
1211 desc => "symlink with env which contain slash (see #19309)",
1212 devices => [
1213 {
1214 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
1215 exp_links => ["first", "name-aaa_bbb_ccc-end",
1216 "another_symlink", "a", "b", "c"],
1217 not_exp_links => ["ame-aaa/bbb/ccc-end"],
1218 }],
1219 rules => <<EOF
1220ENV{WITH_SLASH}="aaa/bbb/ccc"
1221OPTIONS="string_escape=replace", ENV{REPLACED}="\$env{WITH_SLASH}"
1222SYMLINK=" first name-\$env{REPLACED}-end another_symlink a b c "
b8669191 1223EOF
912541b0
KS
1224 },
1225 {
1226 desc => "symlink creation (same directory)",
255c05b7
MW
1227 devices => [
1228 {
1229 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
e62acc31 1230 exp_links => ["modem0"],
255c05b7 1231 }],
912541b0 1232 rules => <<EOF
5754e74c 1233KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", SYMLINK="modem%n"
b8669191 1234EOF
912541b0
KS
1235 },
1236 {
1237 desc => "multiple symlinks",
255c05b7
MW
1238 devices => [
1239 {
1240 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
e62acc31 1241 exp_links => ["first-0", "second-0", "third-0"],
255c05b7 1242 }],
912541b0 1243 rules => <<EOF
5754e74c 1244KERNEL=="ttyACM0", SYMLINK="first-%n second-%n third-%n"
b8669191 1245EOF
912541b0
KS
1246 },
1247 {
1248 desc => "symlink name '.'",
255c05b7
MW
1249 devices => [
1250 {
1251 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
e62acc31 1252 exp_links => ["."],
255c05b7
MW
1253 exp_add_error => "yes",
1254 exp_rem_error => "yes",
1255 }],
912541b0 1256 rules => <<EOF
5754e74c 1257SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="."
b8669191 1258EOF
912541b0
KS
1259 },
1260 {
1261 desc => "symlink node to itself",
255c05b7
MW
1262 devices => [
1263 {
1264 devpath => "/devices/virtual/tty/tty0",
e62acc31 1265 exp_links => ["link"],
255c05b7
MW
1266 exp_add_error => "yes",
1267 exp_rem_error => "yes",
1268 }],
1269 option => "clean",
912541b0 1270 rules => <<EOF
5754e74c 1271KERNEL=="tty0", SYMLINK+="tty0"
b8669191 1272EOF
912541b0
KS
1273 },
1274 {
1275 desc => "symlink %n substitution",
255c05b7
MW
1276 devices => [
1277 {
1278 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
e62acc31 1279 exp_links => ["symlink0"],
255c05b7 1280 }],
912541b0 1281 rules => <<EOF
5754e74c 1282KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", SYMLINK+="symlink%n"
b8669191 1283EOF
912541b0
KS
1284 },
1285 {
1286 desc => "symlink %k substitution",
255c05b7
MW
1287 devices => [
1288 {
1289 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
e62acc31 1290 exp_links => ["symlink-ttyACM0"],
255c05b7 1291 }],
912541b0 1292 rules => <<EOF
5754e74c 1293KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", SYMLINK+="symlink-%k"
b8669191 1294EOF
912541b0
KS
1295 },
1296 {
1297 desc => "symlink %M:%m substitution",
255c05b7
MW
1298 devices => [
1299 {
1300 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
e62acc31 1301 exp_links => ["major-166:0"],
255c05b7 1302 }],
912541b0 1303 rules => <<EOF
5754e74c 1304KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", SYMLINK+="major-%M:%m"
b8669191 1305EOF
912541b0
KS
1306 },
1307 {
1308 desc => "symlink %b substitution",
255c05b7
MW
1309 devices => [
1310 {
1311 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
e62acc31 1312 exp_links => ["symlink-0:0:0:0"],
255c05b7 1313 }],
912541b0 1314 rules => <<EOF
220893b3 1315SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="symlink-%b"
b8669191 1316EOF
912541b0
KS
1317 },
1318 {
1319 desc => "symlink %c substitution",
255c05b7
MW
1320 devices => [
1321 {
1322 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
e62acc31 1323 exp_links => ["test"],
255c05b7 1324 }],
912541b0 1325 rules => <<EOF
d914e445 1326KERNEL=="ttyACM[0-9]*", PROGRAM=="/bin/echo test", SYMLINK+="%c"
b8669191 1327EOF
912541b0
KS
1328 },
1329 {
1330 desc => "symlink %c{N} substitution",
255c05b7
MW
1331 devices => [
1332 {
1333 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
e62acc31
MW
1334 exp_links => ["test"],
1335 not_exp_links => ["symlink", "this"],
255c05b7 1336 }],
912541b0 1337 rules => <<EOF
d914e445 1338KERNEL=="ttyACM[0-9]*", PROGRAM=="/bin/echo symlink test this", SYMLINK+="%c{2}"
b8669191 1339EOF
912541b0
KS
1340 },
1341 {
1342 desc => "symlink %c{N+} substitution",
255c05b7
MW
1343 devices => [
1344 {
1345 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
e62acc31
MW
1346 exp_links => ["test", "this"],
1347 not_exp_links => ["symlink"],
255c05b7 1348 }],
912541b0 1349 rules => <<EOF
d914e445 1350KERNEL=="ttyACM[0-9]*", PROGRAM=="/bin/echo symlink test this", SYMLINK+="%c{2+}"
b8669191 1351EOF
912541b0
KS
1352 },
1353 {
1354 desc => "symlink only rule with %c{N+}",
255c05b7
MW
1355 devices => [
1356 {
1357 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
e62acc31
MW
1358 exp_links => ["test", "this"],
1359 not_exp_links => ["symlink"],
255c05b7 1360 }],
912541b0 1361 rules => <<EOF
d914e445 1362SUBSYSTEMS=="scsi", KERNEL=="sda", PROGRAM=="/bin/echo link test this" SYMLINK+="%c{2+}"
b8669191 1363EOF
912541b0
KS
1364 },
1365 {
1366 desc => "symlink %s{filename} substitution",
255c05b7
MW
1367 devices => [
1368 {
1369 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
e62acc31 1370 exp_links => ["166:0"],
255c05b7 1371 }],
912541b0 1372 rules => <<EOF
5754e74c 1373KERNEL=="ttyACM[0-9]*", SYMLINK+="%s{dev}"
b8669191 1374EOF
912541b0
KS
1375 },
1376 {
1377 desc => "program result substitution (numbered part of)",
255c05b7
MW
1378 devices => [
1379 {
1380 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
e62acc31
MW
1381 exp_links => ["link1", "link2"],
1382 not_exp_links => ["node"],
255c05b7 1383 }],
912541b0 1384 rules => <<EOF
d914e445 1385SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n node link1 link2", RESULT=="node *", SYMLINK+="%c{2} %c{3}"
b8669191 1386EOF
912541b0
KS
1387 },
1388 {
1389 desc => "program result substitution (numbered part of+)",
255c05b7
MW
1390 devices => [
1391 {
1392 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
e62acc31
MW
1393 exp_links => ["link1", "link2", "link3", "link4"],
1394 not_exp_links => ["node"],
255c05b7 1395 }],
912541b0 1396 rules => <<EOF
d914e445 1397SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n node link1 link2 link3 link4", RESULT=="node *", SYMLINK+="%c{2+}"
7efa217d 1398EOF
912541b0
KS
1399 },
1400 {
1401 desc => "SUBSYSTEM match test",
255c05b7
MW
1402 devices => [
1403 {
1404 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
e62acc31
MW
1405 exp_links => ["node"],
1406 not_exp_links => ["should_not_match", "should_not_match2"],
255c05b7 1407 }],
912541b0 1408 rules => <<EOF
5754e74c
KS
1409SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="should_not_match", SUBSYSTEM=="vc"
1410SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", SUBSYSTEM=="block"
1411SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="should_not_match2", SUBSYSTEM=="vc"
2092fbcd 1412EOF
912541b0
KS
1413 },
1414 {
1415 desc => "DRIVERS match test",
255c05b7
MW
1416 devices => [
1417 {
1418 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
e62acc31
MW
1419 exp_links => ["node"],
1420 not_exp_links => ["should_not_match"]
255c05b7 1421 }],
912541b0 1422 rules => <<EOF
5754e74c
KS
1423SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="should_not_match", DRIVERS=="sd-wrong"
1424SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", DRIVERS=="sd"
c1ab0461 1425EOF
912541b0
KS
1426 },
1427 {
1428 desc => "devnode substitution test",
255c05b7
MW
1429 devices => [
1430 {
1431 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
e62acc31 1432 exp_links => ["node"],
255c05b7 1433 }],
912541b0 1434 rules => <<EOF
220893b3 1435SUBSYSTEMS=="scsi", KERNEL=="sda", PROGRAM=="/usr/bin/test -b %N" SYMLINK+="node"
69aa6dfb 1436EOF
912541b0
KS
1437 },
1438 {
1439 desc => "parent node name substitution test",
255c05b7
MW
1440 devices => [
1441 {
1442 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
e62acc31 1443 exp_links => ["sda-part-1"],
255c05b7 1444 }],
912541b0 1445 rules => <<EOF
06d4d4e2 1446SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="%P-part-%n"
69aa6dfb 1447EOF
912541b0
KS
1448 },
1449 {
1450 desc => "udev_root substitution",
255c05b7
MW
1451 devices => [
1452 {
1453 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
e62acc31 1454 exp_links => ["start-/dev-end"],
255c05b7 1455 }],
912541b0 1456 rules => <<EOF
5754e74c 1457SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="start-%r-end"
3b6ed8bb 1458EOF
912541b0
KS
1459 },
1460 {
17cce031 1461 # This is not supported any more
912541b0 1462 desc => "last_rule option",
255c05b7
MW
1463 devices => [
1464 {
1465 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
e62acc31 1466 exp_links => ["last"],
17cce031
MW
1467 not_exp_links => ["very-last"],
1468 exp_nodev_error => "yes",
255c05b7 1469 }],
912541b0 1470 rules => <<EOF
c4edd0ad 1471SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="last", OPTIONS="last_rule"
5754e74c 1472SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="very-last"
28ce66de 1473EOF
912541b0
KS
1474 },
1475 {
1476 desc => "negation KERNEL!=",
255c05b7
MW
1477 devices => [
1478 {
1479 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
e62acc31
MW
1480 exp_links => ["match", "before"],
1481 not_exp_links => ["matches-but-is-negated"],
255c05b7 1482 }],
912541b0 1483 rules => <<EOF
5754e74c
KS
1484SUBSYSTEMS=="scsi", KERNEL!="sda1", SYMLINK+="matches-but-is-negated"
1485SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="before"
1486SUBSYSTEMS=="scsi", KERNEL!="xsda1", SYMLINK+="match"
28ce66de 1487EOF
912541b0
KS
1488 },
1489 {
1490 desc => "negation SUBSYSTEM!=",
255c05b7
MW
1491 devices => [
1492 {
1493 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
e62acc31
MW
1494 exp_links => ["before", "not-anything"],
1495 not_exp_links => ["matches-but-is-negated"],
255c05b7 1496 }],
912541b0 1497 rules => <<EOF
5754e74c
KS
1498SUBSYSTEMS=="scsi", SUBSYSTEM=="block", KERNEL!="sda1", SYMLINK+="matches-but-is-negated"
1499SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="before"
1500SUBSYSTEMS=="scsi", SUBSYSTEM!="anything", SYMLINK+="not-anything"
28ce66de 1501EOF
912541b0
KS
1502 },
1503 {
1504 desc => "negation PROGRAM!= exit code",
255c05b7
MW
1505 devices => [
1506 {
1507 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
e62acc31 1508 exp_links => ["before", "nonzero-program"],
255c05b7 1509 }],
912541b0 1510 rules => <<EOF
5754e74c 1511SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="before"
d914e445 1512KERNEL=="sda1", PROGRAM!="/bin/false", SYMLINK+="nonzero-program"
3e5958de 1513EOF
912541b0
KS
1514 },
1515 {
1516 desc => "ENV{} test",
255c05b7
MW
1517 devices => [
1518 {
1519 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
e62acc31
MW
1520 exp_links => ["true"],
1521 not_exp_links => ["bad", "wrong"],
255c05b7 1522 }],
912541b0 1523 rules => <<EOF
a1af6b04 1524ENV{ENV_KEY_TEST}="test"
5754e74c
KS
1525SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ENV_KEY_TEST}=="go", SYMLINK+="wrong"
1526SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ENV_KEY_TEST}=="test", SYMLINK+="true"
1527SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ENV_KEY_TEST}=="bad", SYMLINK+="bad"
3e5958de 1528EOF
912541b0
KS
1529 },
1530 {
1531 desc => "ENV{} test",
255c05b7
MW
1532 devices => [
1533 {
1534 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
e62acc31
MW
1535 exp_links => ["true"],
1536 not_exp_links => ["bad", "wrong", "no"],
255c05b7 1537 }],
912541b0 1538 rules => <<EOF
a1af6b04 1539ENV{ENV_KEY_TEST}="test"
5754e74c
KS
1540SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ENV_KEY_TEST}=="go", SYMLINK+="wrong"
1541SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ENV_KEY_TEST}=="yes", ENV{ACTION}=="add", ENV{DEVPATH}=="*/block/sda/sdax1", SYMLINK+="no"
1542SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ENV_KEY_TEST}=="test", ENV{ACTION}=="add", ENV{DEVPATH}=="*/block/sda/sda1", SYMLINK+="true"
1543SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ENV_KEY_TEST}=="bad", SYMLINK+="bad"
5618b561 1544EOF
912541b0
KS
1545 },
1546 {
1547 desc => "ENV{} test (assign)",
255c05b7
MW
1548 devices => [
1549 {
1550 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
e62acc31
MW
1551 exp_links => ["true", "before"],
1552 not_exp_links => ["no"],
255c05b7 1553 }],
912541b0 1554 rules => <<EOF
c4edd0ad 1555SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ASSIGN}="true"
5754e74c
KS
1556SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ASSIGN}=="yes", SYMLINK+="no"
1557SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="before"
1558SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ASSIGN}=="true", SYMLINK+="true"
ac528431 1559EOF
912541b0
KS
1560 },
1561 {
1562 desc => "ENV{} test (assign 2 times)",
255c05b7
MW
1563 devices => [
1564 {
1565 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
e62acc31
MW
1566 exp_links => ["true", "before"],
1567 not_exp_links => ["no", "bad"],
255c05b7 1568 }],
912541b0 1569 rules => <<EOF
ac528431
KS
1570SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ASSIGN}="true"
1571SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ASSIGN}="absolutely-\$env{ASSIGN}"
5754e74c
KS
1572SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="before"
1573SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ASSIGN}=="yes", SYMLINK+="no"
06d4d4e2 1574SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ASSIGN}=="true", SYMLINK+="bad"
5754e74c 1575SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ASSIGN}=="absolutely-true", SYMLINK+="true"
5618b561 1576EOF
912541b0
KS
1577 },
1578 {
1579 desc => "ENV{} test (assign2)",
255c05b7
MW
1580 devices => [
1581 {
1582 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
e62acc31
MW
1583 exp_links => ["part"],
1584 not_exp_links => ["disk"],
1585 },
06d4d4e2
MW
1586 {
1587 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1588 exp_links => ["disk"],
1589 not_exp_links => ["part"],
1590 },
e62acc31 1591 ],
912541b0 1592 rules => <<EOF
d59c84ef
KS
1593SUBSYSTEM=="block", KERNEL=="*[0-9]", ENV{PARTITION}="true", ENV{MAINDEVICE}="false"
1594SUBSYSTEM=="block", KERNEL=="*[!0-9]", ENV{PARTITION}="false", ENV{MAINDEVICE}="true"
5754e74c
KS
1595ENV{MAINDEVICE}=="true", SYMLINK+="disk"
1596SUBSYSTEM=="block", SYMLINK+="before"
1597ENV{PARTITION}=="true", SYMLINK+="part"
18614ab2 1598EOF
912541b0
KS
1599 },
1600 {
1601 desc => "untrusted string sanitize",
255c05b7
MW
1602 devices => [
1603 {
1604 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
e62acc31 1605 exp_links => ["sane"],
255c05b7 1606 }],
912541b0 1607 rules => <<EOF
d914e445 1608SUBSYSTEMS=="scsi", KERNEL=="sda1", PROGRAM=="/bin/echo -e name; (/usr/bin/badprogram)", RESULT=="name_ _/usr/bin/badprogram_", SYMLINK+="sane"
764ce7f2 1609EOF
912541b0
KS
1610 },
1611 {
1612 desc => "untrusted string sanitize (don't replace utf8)",
255c05b7
MW
1613 devices => [
1614 {
1615 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
e62acc31 1616 exp_links => ["uber"],
255c05b7 1617 }],
912541b0 1618 rules => <<EOF
d914e445 1619SUBSYSTEMS=="scsi", KERNEL=="sda1", PROGRAM=="/bin/echo -e \\xc3\\xbcber" RESULT=="\xc3\xbcber", SYMLINK+="uber"
764ce7f2 1620EOF
912541b0
KS
1621 },
1622 {
1623 desc => "untrusted string sanitize (replace invalid utf8)",
255c05b7
MW
1624 devices => [
1625 {
1626 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
e62acc31 1627 exp_links => ["replaced"],
255c05b7 1628 }],
912541b0 1629 rules => <<EOF
d914e445 1630SUBSYSTEMS=="scsi", KERNEL=="sda1", PROGRAM=="/bin/echo -e \\xef\\xe8garbage", RESULT=="__garbage", SYMLINK+="replaced"
98bbc835 1631EOF
912541b0
KS
1632 },
1633 {
1634 desc => "read sysfs value from parent device",
255c05b7
MW
1635 devices => [
1636 {
1637 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
e62acc31 1638 exp_links => ["serial-354172020305000"],
255c05b7 1639 }],
912541b0 1640 rules => <<EOF
5754e74c 1641KERNEL=="ttyACM*", ATTRS{serial}=="?*", SYMLINK+="serial-%s{serial}"
db949b02 1642EOF
912541b0
KS
1643 },
1644 {
1645 desc => "match against empty key string",
255c05b7
MW
1646 devices => [
1647 {
1648 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
e62acc31
MW
1649 exp_links => ["ok"],
1650 not_exp_links => ["not-1-ok", "not-2-ok", "not-3-ok"],
255c05b7 1651 }],
912541b0 1652 rules => <<EOF
5754e74c
KS
1653KERNEL=="sda", ATTRS{nothing}!="", SYMLINK+="not-1-ok"
1654KERNEL=="sda", ATTRS{nothing}=="", SYMLINK+="not-2-ok"
1655KERNEL=="sda", ATTRS{vendor}!="", SYMLINK+="ok"
1656KERNEL=="sda", ATTRS{vendor}=="", SYMLINK+="not-3-ok"
821d0ec8 1657EOF
912541b0
KS
1658 },
1659 {
1660 desc => "check ACTION value",
255c05b7
MW
1661 devices => [
1662 {
1663 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
e62acc31
MW
1664 exp_links => ["ok"],
1665 not_exp_links => ["unknown-not-ok"],
255c05b7 1666 }],
912541b0 1667 rules => <<EOF
5754e74c
KS
1668ACTION=="unknown", KERNEL=="sda", SYMLINK+="unknown-not-ok"
1669ACTION=="add", KERNEL=="sda", SYMLINK+="ok"
c974742b 1670EOF
912541b0
KS
1671 },
1672 {
1673 desc => "final assignment",
255c05b7
MW
1674 devices => [
1675 {
1676 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
e62acc31 1677 exp_links => ["ok"],
255c05b7
MW
1678 exp_perms => "root:tty:0640",
1679 }],
912541b0 1680 rules => <<EOF
d960ad15 1681KERNEL=="sda", GROUP:="tty"
06d4d4e2 1682KERNEL=="sda", GROUP="root", MODE="0640", SYMLINK+="ok"
c974742b 1683EOF
912541b0
KS
1684 },
1685 {
1686 desc => "final assignment 2",
255c05b7
MW
1687 devices => [
1688 {
1689 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
e62acc31 1690 exp_links => ["ok"],
255c05b7
MW
1691 exp_perms => "root:tty:0640",
1692 }],
912541b0 1693 rules => <<EOF
d960ad15 1694KERNEL=="sda", GROUP:="tty"
c974742b 1695SUBSYSTEM=="block", MODE:="640"
06d4d4e2 1696KERNEL=="sda", GROUP="root", MODE="0666", SYMLINK+="ok"
bd0ed2ff 1697EOF
912541b0
KS
1698 },
1699 {
1700 desc => "env substitution",
255c05b7
MW
1701 devices => [
1702 {
1703 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
e62acc31 1704 exp_links => ["node-add-me"],
255c05b7 1705 }],
912541b0 1706 rules => <<EOF
5754e74c 1707KERNEL=="sda", MODE="0666", SYMLINK+="node-\$env{ACTION}-me"
995aec87 1708EOF
912541b0
KS
1709 },
1710 {
1711 desc => "reset list to current value",
255c05b7
MW
1712 devices => [
1713 {
1714 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
e62acc31
MW
1715 exp_links => ["three"],
1716 not_exp_links => ["two", "one"],
255c05b7 1717 }],
912541b0 1718 rules => <<EOF
c7fcba1b
KS
1719KERNEL=="ttyACM[0-9]*", SYMLINK+="one"
1720KERNEL=="ttyACM[0-9]*", SYMLINK+="two"
1721KERNEL=="ttyACM[0-9]*", SYMLINK="three"
647f7c49 1722EOF
912541b0
KS
1723 },
1724 {
1725 desc => "test empty SYMLINK+ (empty override)",
255c05b7
MW
1726 devices => [
1727 {
1728 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
e62acc31
MW
1729 exp_links => ["right"],
1730 not_exp_links => ["wrong"],
255c05b7 1731 }],
912541b0 1732 rules => <<EOF
5754e74c
KS
1733KERNEL=="ttyACM[0-9]*", SYMLINK+="wrong"
1734KERNEL=="ttyACM[0-9]*", SYMLINK=""
1735KERNEL=="ttyACM[0-9]*", SYMLINK+="right"
0cd4ac47 1736EOF
912541b0
KS
1737 },
1738 {
1739 desc => "test multi matches",
255c05b7
MW
1740 devices => [
1741 {
1742 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
e62acc31 1743 exp_links => ["right", "before"],
255c05b7 1744 }],
912541b0 1745 rules => <<EOF
5754e74c
KS
1746KERNEL=="ttyACM*", SYMLINK+="before"
1747KERNEL=="ttyACM*|nothing", SYMLINK+="right"
0cd4ac47 1748EOF
912541b0
KS
1749 },
1750 {
1751 desc => "test multi matches 2",
255c05b7
MW
1752 devices => [
1753 {
1754 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
e62acc31
MW
1755 exp_links => ["right", "before"],
1756 not_exp_links => ["nomatch"],
255c05b7 1757 }],
912541b0 1758 rules => <<EOF
5754e74c
KS
1759KERNEL=="dontknow*|*nothing", SYMLINK+="nomatch"
1760KERNEL=="ttyACM*", SYMLINK+="before"
1761KERNEL=="dontknow*|ttyACM*|nothing*", SYMLINK+="right"
91a75e4a 1762EOF
912541b0
KS
1763 },
1764 {
1765 desc => "test multi matches 3",
255c05b7
MW
1766 devices => [
1767 {
1768 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
e62acc31
MW
1769 exp_links => ["right"],
1770 not_exp_links => ["nomatch", "wrong1", "wrong2"],
255c05b7 1771 }],
912541b0 1772 rules => <<EOF
5754e74c
KS
1773KERNEL=="dontknow|nothing", SYMLINK+="nomatch"
1774KERNEL=="dontknow|ttyACM0a|nothing|attyACM0", SYMLINK+="wrong1"
1775KERNEL=="X|attyACM0|dontknow|ttyACM0a|nothing|attyACM0", SYMLINK+="wrong2"
1776KERNEL=="dontknow|ttyACM0|nothing", SYMLINK+="right"
91a75e4a 1777EOF
912541b0
KS
1778 },
1779 {
1780 desc => "test multi matches 4",
255c05b7
MW
1781 devices => [
1782 {
1783 devpath => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
e62acc31
MW
1784 exp_links => ["right"],
1785 not_exp_links => ["nomatch", "wrong1", "wrong2", "wrong3"],
255c05b7 1786 }],
912541b0 1787 rules => <<EOF
5754e74c
KS
1788KERNEL=="dontknow|nothing", SYMLINK+="nomatch"
1789KERNEL=="dontknow|ttyACM0a|nothing|attyACM0", SYMLINK+="wrong1"
1790KERNEL=="X|attyACM0|dontknow|ttyACM0a|nothing|attyACM0", SYMLINK+="wrong2"
1791KERNEL=="all|dontknow|ttyACM0", SYMLINK+="right"
1792KERNEL=="ttyACM0a|nothing", SYMLINK+="wrong3"
48d26c90
YW
1793EOF
1794 },
1795 {
255c05b7
MW
1796 desc => "test multi matches 5",
1797 devices => [
1798 {
1799 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
e62acc31 1800 exp_links => ["found"],
255c05b7
MW
1801 not_exp_name => "bad",
1802 }],
48d26c90
YW
1803 rules => <<EOF
1804KERNEL=="sda", TAG="foo"
1805TAGS=="|foo", SYMLINK+="found"
1806TAGS=="|aaa", SYMLINK+="bad"
1807EOF
1808 },
1809 {
1810 desc => "test multi matches 6",
255c05b7
MW
1811 devices => [
1812 {
1813 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
e62acc31 1814 exp_links => ["found"],
255c05b7
MW
1815 not_exp_name => "bad",
1816 }],
48d26c90 1817 rules => <<EOF
0b4c70b4
YW
1818KERNEL=="sda", ENV{HOGE}=""
1819ENV{HOGE}=="|foo", SYMLINK+="found"
1820ENV{HOGE}=="aaa|bbb", SYMLINK+="bad"
48d26c90
YW
1821EOF
1822 },
1823 {
1824 desc => "test multi matches 7",
255c05b7
MW
1825 devices => [
1826 {
1827 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
e62acc31 1828 exp_links => ["found"],
255c05b7
MW
1829 not_exp_name => "bad",
1830 }],
48d26c90
YW
1831 rules => <<EOF
1832KERNEL=="sda", TAG="foo"
1833TAGS=="foo||bar", SYMLINK+="found"
1834TAGS=="aaa||bbb", SYMLINK+="bad"
1835EOF
1836 },
1837 {
1838 desc => "test multi matches 8",
255c05b7
MW
1839 devices => [
1840 {
1841 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
e62acc31 1842 exp_links => ["found"],
255c05b7
MW
1843 not_exp_name => "bad",
1844 }],
48d26c90 1845 rules => <<EOF
0b4c70b4
YW
1846KERNEL=="sda", ENV{HOGE}=""
1847ENV{HOGE}=="foo||bar", SYMLINK+="found"
1848ENV{HOGE}=="aaa|bbb", SYMLINK+="bad"
48d26c90
YW
1849EOF
1850 },
1851 {
1852 desc => "test multi matches 9",
255c05b7
MW
1853 devices => [
1854 {
1855 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
e62acc31 1856 exp_links => ["found"],
255c05b7
MW
1857 not_exp_name => "bad",
1858 }],
48d26c90
YW
1859 rules => <<EOF
1860KERNEL=="sda", TAG="foo"
1861TAGS=="foo|", SYMLINK+="found"
1862TAGS=="aaa|", SYMLINK+="bad"
1863EOF
1864 },
1865 {
1866 desc => "test multi matches 10",
255c05b7
MW
1867 devices => [
1868 {
1869 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
e62acc31 1870 exp_links => ["found"],
255c05b7
MW
1871 not_exp_name => "bad",
1872 }],
48d26c90 1873 rules => <<EOF
0b4c70b4
YW
1874KERNEL=="sda", ENV{HOGE}=""
1875ENV{HOGE}=="foo|", SYMLINK+="found"
1876ENV{HOGE}=="aaa|bbb", SYMLINK+="bad"
0d3a8bc7
YG
1877EOF
1878 },
1879 {
1880 desc => "test multi matches 11",
255c05b7
MW
1881 devices => [
1882 {
1883 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
e62acc31 1884 exp_links => ["found"],
255c05b7
MW
1885 not_exp_name => "bad",
1886 }],
0d3a8bc7
YG
1887 rules => <<EOF
1888KERNEL=="sda", TAG="c"
1889TAGS=="foo||bar||c", SYMLINK+="found"
1890TAGS=="aaa||bbb||ccc", SYMLINK+="bad"
0b4c70b4
YW
1891EOF
1892 },
1893 {
1894 desc => "TAG refuses invalid string",
1895 devices => [
1896 {
1897 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
1898 exp_links => ["valid", "found"],
1899 not_exp_links => ["empty", "invalid_char", "path", "bad", "bad2"],
1900 }],
1901 rules => <<EOF
1902KERNEL=="sda", TAG+="", TAG+="invalid.char", TAG+="path/is/also/invalid", TAG+="valid"
1903TAGS=="", SYMLINK+="empty"
1904TAGS=="invalid.char", SYMLINK+="invalid_char"
1905TAGS=="path/is/also/invalid", SYMLINK+="path"
1906TAGS=="valid", SYMLINK+="valid"
1907TAGS=="valid|", SYMLINK+="found"
1908TAGS=="aaa|", SYMLINK+="bad"
1909TAGS=="aaa|bbb", SYMLINK+="bad2"
0bfb84e1 1910EOF
912541b0
KS
1911 },
1912 {
a96cd21d 1913 desc => "IMPORT parent test",
255c05b7
MW
1914 devices => [
1915 {
1916 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
e62acc31 1917 exp_links => ["parent"],
a96cd21d 1918 },
255c05b7
MW
1919 {
1920 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
e62acc31 1921 exp_links => ["parentenv-parent_right"],
255c05b7 1922 }],
a96cd21d 1923 sleep_us => 500000, # Serialized! We need to sleep here after adding sda
912541b0 1924 rules => <<EOF
5754e74c 1925KERNEL=="sda1", IMPORT{parent}="PARENT*", SYMLINK+="parentenv-\$env{PARENT_KEY}\$env{WRONG_PARENT_KEY}"
a96cd21d
MW
1926KERNEL=="sda", IMPORT{program}="/bin/echo -e \'PARENT_KEY=parent_right\\nWRONG_PARENT_KEY=parent_wrong'"
1927KERNEL=="sda", SYMLINK+="parent"
594dd610 1928EOF
912541b0
KS
1929 },
1930 {
1931 desc => "GOTO test",
255c05b7
MW
1932 devices => [
1933 {
1934 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
e62acc31
MW
1935 exp_links => ["right"],
1936 not_exp_test => ["wrong", "wrong2"],
255c05b7 1937 }],
912541b0 1938 rules => <<EOF
594dd610 1939KERNEL=="sda1", GOTO="TEST"
5754e74c 1940KERNEL=="sda1", SYMLINK+="wrong"
6880b25d 1941KERNEL=="sda1", GOTO="BAD"
5754e74c
KS
1942KERNEL=="sda1", SYMLINK+="", LABEL="NO"
1943KERNEL=="sda1", SYMLINK+="right", LABEL="TEST", GOTO="end"
1944KERNEL=="sda1", SYMLINK+="wrong2", LABEL="BAD"
9dae0e89 1945LABEL="end"
0c377989 1946EOF
912541b0
KS
1947 },
1948 {
1949 desc => "GOTO label does not exist",
255c05b7
MW
1950 devices => [
1951 {
1952 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
e62acc31 1953 exp_links => ["right"],
255c05b7 1954 }],
912541b0 1955 rules => <<EOF
0c377989 1956KERNEL=="sda1", GOTO="does-not-exist"
5754e74c 1957KERNEL=="sda1", SYMLINK+="right",
0c377989 1958LABEL="exists"
d59c84ef 1959EOF
912541b0
KS
1960 },
1961 {
1962 desc => "SYMLINK+ compare test",
255c05b7
MW
1963 devices => [
1964 {
1965 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
e62acc31
MW
1966 exp_links => ["right", "link"],
1967 not_exp_links => ["wrong"],
255c05b7 1968 }],
912541b0 1969 rules => <<EOF
5754e74c
KS
1970KERNEL=="sda1", SYMLINK+="link"
1971KERNEL=="sda1", SYMLINK=="link*", SYMLINK+="right"
1972KERNEL=="sda1", SYMLINK=="nolink*", SYMLINK+="wrong"
d59c84ef 1973EOF
912541b0
KS
1974 },
1975 {
1976 desc => "invalid key operation",
255c05b7
MW
1977 devices => [
1978 {
1979 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
e62acc31
MW
1980 exp_links => ["yes"],
1981 not_exp_links => ["no"],
255c05b7 1982 }],
912541b0 1983 rules => <<EOF
5754e74c
KS
1984KERNEL="sda1", SYMLINK+="no"
1985KERNEL=="sda1", SYMLINK+="yes"
864b9b5e 1986EOF
912541b0
KS
1987 },
1988 {
1989 desc => "operator chars in attribute",
255c05b7
MW
1990 devices => [
1991 {
1992 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
e62acc31 1993 exp_links => ["yes"],
255c05b7 1994 }],
912541b0 1995 rules => <<EOF
5754e74c 1996KERNEL=="sda", ATTR{test:colon+plus}=="?*", SYMLINK+="yes"
d4ae9925 1997EOF
912541b0
KS
1998 },
1999 {
2000 desc => "overlong comment line",
255c05b7
MW
2001 devices => [
2002 {
2003 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
e62acc31
MW
2004 exp_links => ["yes"],
2005 not_exp_links => ["no"],
255c05b7 2006 }],
912541b0 2007 rules => <<EOF
d4ae9925 2008# 012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
d960ad15 2009 # 012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
5754e74c
KS
2010KERNEL=="sda1", SYMLINK+=="no"
2011KERNEL=="sda1", SYMLINK+="yes"
4ad47b2d 2012EOF
912541b0
KS
2013 },
2014 {
2015 desc => "magic subsys/kernel lookup",
255c05b7
MW
2016 devices => [
2017 {
2018 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
e62acc31 2019 exp_links => ["00:16:41:e2:8d:ff"],
255c05b7 2020 }],
912541b0 2021 rules => <<EOF
5754e74c 2022KERNEL=="sda", SYMLINK+="\$attr{[net/eth0]address}"
03f65fe6 2023EOF
912541b0
KS
2024 },
2025 {
2026 desc => "TEST absolute path",
255c05b7
MW
2027 devices => [
2028 {
2029 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
e62acc31
MW
2030 exp_links => ["there"],
2031 not_exp_links => ["notthere"],
255c05b7 2032 }],
912541b0 2033 rules => <<EOF
f0289577
LB
2034TEST=="/etc/passwd", SYMLINK+="there"
2035TEST!="/etc/passwd", SYMLINK+="notthere"
03f65fe6 2036EOF
912541b0
KS
2037 },
2038 {
2039 desc => "TEST subsys/kernel lookup",
255c05b7
MW
2040 devices => [
2041 {
2042 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
e62acc31 2043 exp_links => ["yes"],
255c05b7 2044 }],
912541b0 2045 rules => <<EOF
5754e74c 2046KERNEL=="sda", TEST=="[net/eth0]", SYMLINK+="yes"
03f65fe6 2047EOF
912541b0
KS
2048 },
2049 {
2050 desc => "TEST relative path",
255c05b7
MW
2051 devices => [
2052 {
2053 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
e62acc31 2054 exp_links => ["relative"],
255c05b7 2055 }],
912541b0 2056 rules => <<EOF
5754e74c 2057KERNEL=="sda", TEST=="size", SYMLINK+="relative"
0ea5e96e 2058EOF
912541b0
KS
2059 },
2060 {
2061 desc => "TEST wildcard substitution (find queue/nr_requests)",
255c05b7
MW
2062 devices => [
2063 {
2064 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
e62acc31 2065 exp_links => ["found-subdir"],
255c05b7 2066 }],
912541b0 2067 rules => <<EOF
5754e74c 2068KERNEL=="sda", TEST=="*/nr_requests", SYMLINK+="found-subdir"
cf100ca7 2069EOF
912541b0
KS
2070 },
2071 {
2072 desc => "TEST MODE=0000",
255c05b7
MW
2073 devices => [
2074 {
2075 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
255c05b7
MW
2076 exp_perms => "0:0:0000",
2077 exp_rem_error => "yes",
2078 }],
912541b0 2079 rules => <<EOF
cf100ca7 2080KERNEL=="sda", MODE="0000"
a367f04e 2081EOF
912541b0
KS
2082 },
2083 {
2084 desc => "TEST PROGRAM feeds OWNER, GROUP, MODE",
255c05b7
MW
2085 devices => [
2086 {
2087 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
255c05b7 2088 exp_perms => "1:1:0400",
255c05b7 2089 }],
912541b0 2090 rules => <<EOF
6880b25d 2091KERNEL=="sda", MODE="666"
9158d03e 2092KERNEL=="sda", PROGRAM=="/bin/echo 1 1 0400", OWNER="%c{1}", GROUP="%c{2}", MODE="%c{3}"
ff94cec3 2093EOF
912541b0
KS
2094 },
2095 {
2096 desc => "TEST PROGRAM feeds MODE with overflow",
255c05b7
MW
2097 devices => [
2098 {
2099 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
255c05b7
MW
2100 exp_perms => "0:0:0440",
2101 exp_rem_error => "yes",
2102 }],
912541b0 2103 rules => <<EOF
6880b25d 2104KERNEL=="sda", MODE="440"
d914e445 2105KERNEL=="sda", PROGRAM=="/bin/echo 0 0 0400letsdoabuffferoverflow0123456789012345789012345678901234567890", OWNER="%c{1}", GROUP="%c{2}", MODE="%c{3}"
dc4c7e46 2106EOF
912541b0
KS
2107 },
2108 {
2109 desc => "magic [subsys/sysname] attribute substitution",
255c05b7
MW
2110 devices => [
2111 {
2112 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
e62acc31 2113 exp_links => ["sda-8741C4G-end"],
255c05b7
MW
2114 exp_perms => "0:0:0600",
2115 }],
912541b0 2116 rules => <<EOF
0f52fdee 2117KERNEL=="sda", SYMLINK+="%k-%s{[dmi/id]product_name}-end"
d7867b31 2118EOF
912541b0
KS
2119 },
2120 {
2121 desc => "builtin path_id",
255c05b7
MW
2122 devices => [
2123 {
2124 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
e62acc31 2125 exp_links => ["disk/by-path/pci-0000:00:1f.2-scsi-0:0:0:0"],
255c05b7 2126 }],
912541b0 2127 rules => <<EOF
d7867b31
KS
2128KERNEL=="sda", IMPORT{builtin}="path_id"
2129KERNEL=="sda", ENV{ID_PATH}=="?*", SYMLINK+="disk/by-path/\$env{ID_PATH}"
bf8f7583
MP
2130EOF
2131 },
2132 {
2133 desc => "add and match tag",
255c05b7
MW
2134 devices => [
2135 {
2136 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
e62acc31
MW
2137 exp_links => ["found"],
2138 not_exp_links => ["bad"],
255c05b7 2139 }],
bf8f7583
MP
2140 rules => <<EOF
2141SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", TAG+="green"
2142TAGS=="green", SYMLINK+="found"
2143TAGS=="blue", SYMLINK+="bad"
2144EOF
2145 },
2146 {
2147 desc => "don't crash with lots of tags",
255c05b7
MW
2148 devices => [
2149 {
2150 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
e62acc31 2151 exp_links => ["found"],
255c05b7 2152 }],
bf8f7583
MP
2153 rules => $rules_10k_tags . <<EOF
2154TAGS=="test1", TAGS=="test500", TAGS=="test1234", TAGS=="test9999", TAGS=="test10000", SYMLINK+="found"
1e797cf5
YW
2155EOF
2156 },
2157 {
d35976c6 2158 desc => "continuations",
255c05b7
MW
2159 devices => [
2160 {
2161 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
e62acc31 2162 exp_links => ["found"],
255c05b7
MW
2163 not_exp_name => "bad",
2164 }],
1e797cf5
YW
2165 rules => $rules_10k_tags_continuation . <<EOF
2166TAGS=="test1", TAGS=="test500", TAGS=="test1234", TAGS=="test9999", TAGS=="test10000", SYMLINK+="bad"
d35976c6
YW
2167KERNEL=="sda",\\
2168# comment in continuation
2169TAG+="hoge1",\\
2170 # space before comment
2171TAG+="hoge2",\\
2172# spaces before and after token are dropped
2173 TAG+="hoge3", \\
84a0819c
YW
2174\\
2175 \\
d35976c6
YW
2176TAG+="hoge4"
2177TAGS=="hoge1", TAGS=="hoge2", TAGS=="hoge3", TAGS=="hoge4", SYMLINK+="found"
84a0819c
YW
2178EOF
2179 },
2180 {
2181 desc => "continuations with empty line",
255c05b7
MW
2182 devices => [
2183 {
2184 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
e62acc31 2185 exp_links => ["found"],
255c05b7
MW
2186 not_exp_name => "bad",
2187
2188 }],
84a0819c
YW
2189 rules => <<EOF
2190# empty line finishes continuation
2191KERNEL=="sda", TAG+="foo" \\
2192
2193KERNEL=="sdb", TAG+="hoge"
2194KERNEL=="sda", TAG+="aaa" \\
2195KERNEL=="sdb", TAG+="bbb"
2196TAGS=="foo", SYMLINK+="found"
2197TAGS=="aaa", SYMLINK+="bad"
255c05b7 2198 EOF
84a0819c
YW
2199 },
2200 {
adc5b982 2201 desc => "continuations with space only line",
255c05b7
MW
2202 devices => [
2203 {
2204 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
e62acc31 2205 exp_links => ["found"],
255c05b7
MW
2206 not_exp_name => "bad",
2207 }],
84a0819c
YW
2208 rules => <<EOF
2209# space only line finishes continuation
2210KERNEL=="sda", TAG+="foo" \\
2211 \t
2212KERNEL=="sdb", TAG+="hoge"
2213KERNEL=="sda", TAG+="aaa" \\
2214KERNEL=="sdb", TAG+="bbb"
2215TAGS=="foo", SYMLINK+="found"
2216TAGS=="aaa", SYMLINK+="bad"
4a0ec82d
MW
2217EOF
2218 },
2219 {
2220 desc => "multiple devices",
2221 devices => [
2222 {
2223 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
2224 exp_links => ["part-1"],
2225 },
2226 {
2227 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
2228 exp_links => ["part-5"],
2229 },
2230 {
2231 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda6",
2232 exp_links => ["part-6"],
2233 },
2234 {
2235 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda7",
2236 exp_links => ["part-7"],
2237 },
2238 {
2239 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda8",
2240 exp_links => ["part-8"],
2241 },
2242 {
2243 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda9",
2244 exp_links => ["part-9"],
2245 },
2246 {
2247 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda10",
2248 exp_links => ["part-10"],
2249 },
2250 ],
2251 rules => <<EOF
2252SUBSYSTEM=="block", SUBSYSTEMS=="scsi", KERNEL=="sda?*", ENV{DEVTYPE}=="partition", SYMLINK+="part-%n"
2253EOF
2254 },
2255 {
2256 desc => "multiple devices, same link name, positive prio",
2ab0a8d0 2257 repeat => 100,
4a0ec82d
MW
2258 devices => [
2259 {
2260 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
2261 exp_links => ["part-1"],
2262 not_exp_links => ["partition"],
2263 },
2264 {
2265 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
2266 exp_links => ["part-5"],
2267 not_exp_links => ["partition"],
2268 },
2269 {
2270 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda6",
2271 not_exp_links => ["partition"],
2272 exp_links => ["part-6"],
2273 },
2274 {
2275 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda7",
2276 exp_links => ["part-7", "partition"],
2277 },
2278 {
2279 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda8",
2280 not_exp_links => ["partition"],
2281 exp_links => ["part-8"],
2282 },
2283 {
2284 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda9",
2285 not_exp_links => ["partition"],
2286 exp_links => ["part-9"],
2287 },
2288 {
2289 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda10",
2290 not_exp_links => ["partition"],
2291 exp_links => ["part-10"],
2292 },
2293 ],
2294 rules => <<EOF
2295SUBSYSTEM=="block", SUBSYSTEMS=="scsi", KERNEL=="sda?*", ENV{DEVTYPE}=="partition", SYMLINK+="part-%n"
2296SUBSYSTEM=="block", SUBSYSTEMS=="scsi", KERNEL=="sda?*", ENV{DEVTYPE}=="partition", SYMLINK+="partition"
2297KERNEL=="*7", OPTIONS+="link_priority=10"
2298EOF
2299 },
2300 {
2301 desc => "multiple devices, same link name, negative prio",
2302 devices => [
2303 {
2304 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
2305 exp_links => ["part-1"],
2306 not_exp_links => ["partition"],
2307 },
2308 {
2309 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
2310 exp_links => ["part-5"],
2311 not_exp_links => ["partition"],
2312 },
2313 {
2314 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda6",
2315 not_exp_links => ["partition"],
2316 exp_links => ["part-6"],
2317 },
2318 {
2319 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda7",
2320 exp_links => ["part-7", "partition"],
2321 },
2322 {
2323 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda8",
2324 not_exp_links => ["partition"],
2325 exp_links => ["part-8"],
2326 },
2327 {
2328 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda9",
2329 not_exp_links => ["partition"],
2330 exp_links => ["part-9"],
2331 },
2332 {
2333 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda10",
2334 not_exp_links => ["partition"],
2335 exp_links => ["part-10"],
2336 },
2337 ],
2338 rules => <<EOF
2339SUBSYSTEM=="block", SUBSYSTEMS=="scsi", KERNEL=="sda?*", ENV{DEVTYPE}=="partition", SYMLINK+="part-%n"
2340SUBSYSTEM=="block", SUBSYSTEMS=="scsi", KERNEL=="sda?*", ENV{DEVTYPE}=="partition", SYMLINK+="partition"
2341KERNEL!="*7", OPTIONS+="link_priority=-10"
2342EOF
2343 },
2344 {
2345 desc => "multiple devices, same link name, positive prio, sleep",
2346 devices => [
2347 {
2348 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
2349 exp_links => ["part-1"],
2350 not_exp_links => ["partition"],
2351 },
2352 {
2353 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
2354 exp_links => ["part-5"],
2355 not_exp_links => ["partition"],
2356 },
2357 {
2358 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda6",
2359 not_exp_links => ["partition"],
2360 exp_links => ["part-6"],
2361 },
2362 {
2363 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda7",
2364 exp_links => ["part-7", "partition"],
2365 },
2366 {
2367 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda8",
2368 not_exp_links => ["partition"],
2369 exp_links => ["part-8"],
2370 },
2371 {
2372 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda9",
2373 not_exp_links => ["partition"],
2374 exp_links => ["part-9"],
2375 },
2376 {
2377 devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda10",
2378 not_exp_links => ["partition"],
2379 exp_links => ["part-10"],
2380 },
2381 ],
2382 sleep_us => 10000,
2383 rules => <<EOF
2384SUBSYSTEM=="block", SUBSYSTEMS=="scsi", KERNEL=="sda?*", ENV{DEVTYPE}=="partition", SYMLINK+="part-%n"
2385SUBSYSTEM=="block", SUBSYSTEMS=="scsi", KERNEL=="sda?*", ENV{DEVTYPE}=="partition", SYMLINK+="partition"
2386KERNEL=="*7", OPTIONS+="link_priority=10"
ff94cec3 2387EOF
912541b0 2388 },
eb44d715
MW
2389 {
2390 desc => 'all_block_devs',
2391 generator => expect_for_some("\\/sda6\$", ["blockdev"]),
2392 repeat => 10,
2393 rules => <<EOF
2394SUBSYSTEM=="block", SUBSYSTEMS=="scsi", KERNEL=="sd*", SYMLINK+="blockdev"
2395KERNEL=="sda6", OPTIONS+="link_priority=10"
2396EOF
2397 }
a367f04e
GKH
2398);
2399
af7ee3ea
MW
2400sub create_rules {
2401 my ($rules) = @_;
a367f04e 2402
912541b0 2403 # create temporary rules
6ada823a 2404 system("mkdir", "-p", "$udev_rules_dir");
912541b0
KS
2405 open CONF, ">$udev_rules" || die "unable to create rules file: $udev_rules";
2406 print CONF $$rules;
2407 close CONF;
af7ee3ea
MW
2408}
2409
2410sub udev {
2411 my ($action, $devpath) = @_;
a367f04e 2412
912541b0 2413 if ($valgrind > 0) {
efc9f703 2414 return system("$udev_bin_valgrind $action $devpath");
333e07b7 2415 } elsif ($gdb > 0) {
efc9f703 2416 return system("$udev_bin_gdb $action $devpath");
587751eb 2417 } elsif ($strace > 0) {
efc9f703 2418 return system("$udev_bin_strace $action $devpath");
912541b0 2419 } else {
efc9f703 2420 return system("$udev_bin", "$action", "$devpath");
912541b0 2421 }
a367f04e
GKH
2422}
2423
e5fbfe0a 2424my $error = 0;
b95c4398 2425my $good = 0;
cbeb23d8 2426my $exp_good = 0;
72ffa78d 2427
b8669191 2428sub permissions_test {
912541b0 2429 my($rules, $uid, $gid, $mode) = @_;
b8669191 2430
912541b0
KS
2431 my $wrong = 0;
2432 my $userid;
2433 my $groupid;
9b434de1 2434
912541b0
KS
2435 $rules->{exp_perms} =~ m/^(.*):(.*):(.*)$/;
2436 if ($1 ne "") {
2437 if (defined(getpwnam($1))) {
2438 $userid = int(getpwnam($1));
2439 } else {
2440 $userid = $1;
2441 }
2442 if ($uid != $userid) { $wrong = 1; }
2443 }
2444 if ($2 ne "") {
2445 if (defined(getgrnam($2))) {
2446 $groupid = int(getgrnam($2));
2447 } else {
2448 $groupid = $2;
2449 }
2450 if ($gid != $groupid) { $wrong = 1; }
2451 }
2452 if ($3 ne "") {
2453 if (($mode & 07777) != oct($3)) { $wrong = 1; };
2454 }
2455 if ($wrong == 0) {
2456 print "permissions: ok\n";
b95c4398 2457 $good++;
912541b0
KS
2458 } else {
2459 printf " expected permissions are: %s:%s:%#o\n", $1, $2, oct($3);
2460 printf " created permissions are : %i:%i:%#o\n", $uid, $gid, $mode & 07777;
2461 print "permissions: error\n";
2462 $error++;
2463 sleep(1);
2464 }
b8669191
GKH
2465}
2466
2467sub major_minor_test {
912541b0 2468 my($rules, $rdev) = @_;
b8669191 2469
912541b0
KS
2470 my $major = ($rdev >> 8) & 0xfff;
2471 my $minor = ($rdev & 0xff) | (($rdev >> 12) & 0xfff00);
2472 my $wrong = 0;
b8669191 2473
912541b0
KS
2474 $rules->{exp_majorminor} =~ m/^(.*):(.*)$/;
2475 if ($1 ne "") {
2476 if ($major != $1) { $wrong = 1; };
2477 }
2478 if ($2 ne "") {
2479 if ($minor != $2) { $wrong = 1; };
2480 }
2481 if ($wrong == 0) {
2482 print "major:minor: ok\n";
b95c4398 2483 $good++;
912541b0
KS
2484 } else {
2485 printf " expected major:minor is: %i:%i\n", $1, $2;
2486 printf " created major:minor is : %i:%i\n", $major, $minor;
2487 print "major:minor: error\n";
2488 $error++;
2489 sleep(1);
2490 }
b8669191
GKH
2491}
2492
6ada823a 2493sub udev_setup {
f1cb0860 2494 system("umount \"$udev_tmpfs\" 2>/dev/null");
21d9e3f3
EV
2495 rmdir($udev_tmpfs);
2496 mkdir($udev_tmpfs) || die "unable to create udev_tmpfs: $udev_tmpfs\n";
110a1320 2497
9f563f27 2498 if (system("mount", "-o", "rw,mode=0755,nosuid,noexec", "-t", "tmpfs", "tmpfs", $udev_tmpfs)) {
110a1320
EV
2499 warn "unable to mount tmpfs";
2500 return 0;
2501 }
21d9e3f3 2502
6ada823a
KS
2503 mkdir($udev_dev) || die "unable to create udev_dev: $udev_dev\n";
2504 # setting group and mode of udev_dev ensures the tests work
912541b0 2505 # even if the parent directory has setgid bit enabled.
6ada823a
KS
2506 chown (0, 0, $udev_dev) || die "unable to chown $udev_dev\n";
2507 chmod (0755, $udev_dev) || die "unable to chmod $udev_dev\n";
110a1320
EV
2508
2509 if (system("mknod", $udev_dev . "/null", "c", "1", "3")) {
2510 warn "unable to create $udev_dev/null";
2511 return 0;
2512 }
6ada823a 2513
dbfbc6c4
AB
2514 # check if we are permitted to create block device nodes
2515 my $block_device_filename = $udev_dev . "/sda";
2516 if (system("mknod", $block_device_filename, "b", "8", "0")) {
2517 warn "unable to create $block_device_filename";
2518 return 0;
2519 }
2520 unlink $block_device_filename;
2521
21d9e3f3 2522 system("cp", "-r", "test/sys/", $udev_sys) && die "unable to copy test/sys";
2ce8d27b 2523
6ada823a 2524 system("rm", "-rf", "$udev_run");
110a1320 2525
1e5548c0
AB
2526 if (!mkdir($udev_run)) {
2527 warn "unable to create directory $udev_run";
2528 return 0;
2529 }
2530
110a1320 2531 return 1;
ff94cec3
EK
2532}
2533
f0dccf01
MW
2534sub get_devnode {
2535 my ($device) = @_;
2536 my $devnode;
2537
2538 if (defined($device->{devnode})) {
2539 $devnode = "$udev_dev/$device->{devnode}";
2540 } else {
2541 $devnode = "$device->{devpath}";
2542 $devnode =~ s!.*/!$udev_dev/!;
2543 }
2544 return $devnode;
2545}
2546
2547sub check_devnode {
2548 my ($device) = @_;
2549 my $devnode = get_devnode($device);
2550
2551 my @st = lstat("$devnode");
2552 if (! (-b _ || -c _)) {
2553 print "add $devnode: error\n";
2554 system("tree", "$udev_dev");
2555 $error++;
2556 return undef;
2557 }
2558
2559 my ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size,
2560 $atime, $mtime, $ctime, $blksize, $blocks) = @st;
2561
2562 if (defined($device->{exp_perms})) {
2563 permissions_test($device, $uid, $gid, $mode);
2564 }
2565 if (defined($device->{exp_majorminor})) {
2566 major_minor_test($device, $rdev);
2567 }
2568 print "add $devnode: ok\n";
b95c4398 2569 $good++;
f0dccf01
MW
2570 return $devnode;
2571}
2572
e62acc31
MW
2573sub get_link_target {
2574 my ($link) = @_;
09a4062d 2575
e62acc31
MW
2576 my $cwd = getcwd();
2577 my $dir = "$udev_dev/$link";
2578 my $tgt = readlink("$udev_dev/$link");
2579 $dir =~ s!/[^/]*$!!;
2580 $tgt = abs_path("$dir/$tgt");
2581 $tgt =~ s!^$cwd/!!;
2582 return $tgt;
2583}
f0dccf01 2584
e62acc31
MW
2585sub check_link_add {
2586 my ($link, $devnode, $err_expected) = @_;
f0dccf01 2587
e62acc31 2588 my @st = lstat("$udev_dev/$link");
997683c8 2589 if (-l _) {
e62acc31 2590 my $tgt = get_link_target($link);
997683c8
MW
2591
2592 if ($tgt ne $devnode) {
e62acc31 2593 print "symlink $link: error, found -> $tgt\n";
997683c8
MW
2594 $error++;
2595 system("tree", "$udev_dev");
2596 } else {
e62acc31 2597 print "symlink $link: ok\n";
b95c4398 2598 $good++;
997683c8 2599 }
912541b0 2600 } else {
e62acc31
MW
2601 print "symlink $link: error";
2602 if ($err_expected) {
912541b0 2603 print " as expected\n";
b95c4398 2604 $good++;
912541b0
KS
2605 } else {
2606 print "\n";
6ada823a 2607 system("tree", "$udev_dev");
912541b0
KS
2608 print "\n";
2609 $error++;
2610 sleep(1);
2611 }
2612 }
255c05b7 2613}
a367f04e 2614
e62acc31
MW
2615sub check_link_nonexistent {
2616 my ($link, $devnode, $err_expected) = @_;
2617
2618 if ((-e "$udev_dev/$link") || (-l "$udev_dev/$link")) {
2619 my $tgt = get_link_target($link);
2620
2621 if ($tgt ne $devnode) {
2622 print "nonexistent: '$link' points to other device (ok)\n";
b95c4398 2623 $good++;
e62acc31
MW
2624 } else {
2625 print "nonexistent: error \'$link\' should not be there";
2626 if ($err_expected) {
2627 print " (as expected)\n";
b95c4398 2628 $good++;
e62acc31
MW
2629 } else {
2630 print "\n";
2631 system("tree", "$udev_dev");
2632 print "\n";
2633 $error++;
2634 sleep(1);
2635 }
2636 }
2637 } else {
2638 print "nonexistent $link: ok\n";
b95c4398 2639 $good++;
e62acc31
MW
2640 }
2641}
2642
2643sub check_add {
2644 my ($device) = @_;
2645 my $devnode = check_devnode($device);
2646
2647 if (defined($device->{exp_links})) {
2648 foreach my $link (@{$device->{exp_links}}) {
2649 check_link_add($link, $devnode,
2650 $device->{exp_add_error});
2651 }
2652 }
2653 if (defined $device->{not_exp_links}) {
2654 foreach my $link (@{$device->{not_exp_links}}) {
2655 check_link_nonexistent($link, $devnode,
2656 $device->{exp_nodev_error});
2657 }
2658 }
2659}
2660
f0dccf01
MW
2661sub check_remove_devnode {
2662 my ($device) = @_;
2663 my $devnode = get_devnode($device);
2664
2665 if (-e "$devnode") {
2666 print "remove $devnode: error";
2667 print "\n";
2668 system("tree", "$udev_dev");
2669 print "\n";
2670 $error++;
2671 sleep(1);
2672 } else {
2673 print "remove $devnode: ok\n";
b95c4398 2674 $good++;
f0dccf01
MW
2675 }
2676}
2677
e62acc31
MW
2678sub check_link_remove {
2679 my ($link, $err_expected) = @_;
f0dccf01 2680
e62acc31
MW
2681 if ((-e "$udev_dev/$link") ||
2682 (-l "$udev_dev/$link")) {
2683 print "remove $link: error";
2684 if ($err_expected) {
912541b0 2685 print " as expected\n";
b95c4398 2686 $good++;
912541b0
KS
2687 } else {
2688 print "\n";
6ada823a 2689 system("tree", "$udev_dev");
912541b0
KS
2690 print "\n";
2691 $error++;
2692 sleep(1);
2693 }
2694 } else {
e62acc31 2695 print "remove $link: ok\n";
b95c4398 2696 $good++;
e62acc31
MW
2697 }
2698}
2699
2700sub check_remove {
2701 my ($device) = @_;
2702
2703 check_remove_devnode($device);
2704
2705 return if (!defined($device->{exp_links}));
2706
2707 foreach my $link (@{$device->{exp_links}}) {
2708 check_link_remove($link, $device->{exp_rem_error});
255c05b7
MW
2709 }
2710}
2711
09a4062d
MW
2712sub run_udev {
2713 my ($action, $dev, $sleep_us, $sema) = @_;
2714
2715 # Notify main process that this worker has started
2716 $sema->op(0, 1, 0);
2717
2718 # Wait for start
2719 $sema->op(0, 0, 0);
2720 usleep($sleep_us) if defined ($sleep_us);
2721 my $rc = udev($action, $dev->{devpath});
2722 exit $rc;
2723}
2724
2725sub fork_and_run_udev {
2726 my ($action, $rules, $sema) = @_;
2727 my @devices = @{$rules->{devices}};
2728 my $dev;
2729 my $k = 0;
2730
2731 $sema->setval(0, 1);
2732 foreach $dev (@devices) {
2733 my $pid = fork();
2734
2735 if (!$pid) {
2736 run_udev($action, $dev,
2737 defined($rules->{sleep_us}) ? $k * $rules->{sleep_us} : undef,
2738 $sema);
2739 } else {
2740 $dev->{pid} = $pid;
2741 }
2742 $k++;
2743 }
2744
2745 # This operation waits for all workers to become ready, and
2746 # starts them off when that's the case.
2747 $sema->op(0, -($#devices + 2), 0);
2748
2749 foreach $dev (@devices) {
2750 my $rc;
2751 my $pid;
2752
2753 $pid = waitpid($dev->{pid}, 0);
2754 if ($pid == -1) {
2755 print "error waiting for pid dev->{pid}\n";
09a4062d
MW
2756 }
2757 if (WIFEXITED($?)) {
2758 $rc = WEXITSTATUS($?);
2759
2760 if ($rc) {
2761 print "$udev_bin $action for $dev->{devpath} failed with code $rc\n";
2762 $error += 1;
b95c4398
MW
2763 } else {
2764 $good++;
09a4062d
MW
2765 }
2766 }
2767 }
2768}
2769
255c05b7 2770sub run_test {
09a4062d 2771 my ($rules, $number, $sema) = @_;
255c05b7 2772 my $rc;
eb44d715 2773 my @devices;
cbeb23d8
MW
2774 my $ntests;
2775 my $cur_good = $good;
2776 my $cur_error = $error;
eb44d715
MW
2777
2778 if (!defined $rules->{devices}) {
2779 $rules->{devices} = all_block_devs($rules->{generator});
2780 }
2781 @devices = @{$rules->{devices}};
cbeb23d8
MW
2782 # For each device: exit status and devnode test for add & remove
2783 $ntests += 4 * ($#devices + 1);
255c05b7 2784
cbeb23d8
MW
2785 foreach my $dev (@devices) {
2786 $ntests += 2 * ($#{$dev->{exp_links}} + 1)
2787 + ($#{$dev->{not_exp_links}} + 1)
2788 + (defined $dev->{exp_perms} ? 1 : 0)
2789 + (defined $dev->{exp_majorminor} ? 1 : 0);
2790 }
2791 if (defined $rules->{repeat}) {
2792 $ntests *= $rules->{repeat};
2793 }
2794 $exp_good += $ntests;
255c05b7 2795 print "TEST $number: $rules->{desc}\n";
af7ee3ea 2796 create_rules(\$rules->{rules});
09a4062d 2797
2ab0a8d0 2798 REPEAT:
09a4062d 2799 fork_and_run_udev("add", $rules, $sema);
255c05b7
MW
2800
2801 foreach my $dev (@devices) {
2802 check_add($dev);
2803 }
2804
2805 if (defined($rules->{option}) && $rules->{option} eq "keep") {
2806 print "\n\n";
2807 return;
2808 }
2809
09a4062d
MW
2810 fork_and_run_udev("remove", $rules, $sema);
2811
255c05b7
MW
2812 foreach my $dev (@devices) {
2813 check_remove($dev);
912541b0 2814 }
0345b862 2815
2ab0a8d0
MW
2816 if (defined($rules->{repeat}) && --($rules->{repeat}) > 0) {
2817 goto REPEAT;
2818 }
cbeb23d8
MW
2819 printf "TEST $number: errors: %d good: %d/%d\n\n", $error-$cur_error,
2820 $good-$cur_good, $ntests;
9b434de1 2821
912541b0 2822 if (defined($rules->{option}) && $rules->{option} eq "clean") {
6ada823a 2823 udev_setup();
912541b0 2824 }
0345b862 2825
a367f04e
GKH
2826}
2827
abb9cc50
DS
2828sub cleanup {
2829 system("rm", "-rf", "$udev_run");
2830 system("umount", "$udev_tmpfs");
2831 rmdir($udev_tmpfs);
2832}
2833
800ab95b
GKH
2834# only run if we have root permissions
2835# due to mknod restrictions
2836if (!($<==0)) {
912541b0 2837 print "Must have root permissions to run properly.\n";
4d55fc5b 2838 exit($EXIT_TEST_SKIP);
800ab95b
GKH
2839}
2840
e4d214ef
DC
2841# skip the test when running in a chroot
2842system("systemd-detect-virt", "-r", "-q");
2843if ($? >> 8 == 0) {
ce5fcc69
ZJS
2844 print "Running in a chroot, skipping the test.\n";
2845 exit($EXIT_TEST_SKIP);
e4d214ef
DC
2846}
2847
110a1320
EV
2848if (!udev_setup()) {
2849 warn "Failed to set up the environment, skipping the test";
abb9cc50 2850 cleanup();
110a1320
EV
2851 exit($EXIT_TEST_SKIP);
2852}
2853
7935dae5 2854if (system($udev_bin, "check")) {
110a1320 2855 warn "$udev_bin failed to set up the environment, skipping the test";
abb9cc50 2856 cleanup();
110a1320
EV
2857 exit($EXIT_TEST_SKIP);
2858}
2e317184
GKH
2859
2860my $test_num = 1;
e08109cb 2861my @list;
2e317184 2862
e08109cb 2863foreach my $arg (@ARGV) {
912541b0
KS
2864 if ($arg =~ m/--valgrind/) {
2865 $valgrind = 1;
2866 printf("using valgrind\n");
333e07b7
TG
2867 } elsif ($arg =~ m/--gdb/) {
2868 $gdb = 1;
2869 printf("using gdb\n");
587751eb
ZJS
2870 } elsif ($arg =~ m/--strace/) {
2871 $strace = 1;
2872 printf("using strace\n");
912541b0
KS
2873 } else {
2874 push(@list, $arg);
2875 }
e08109cb 2876}
09a4062d 2877my $sema = IPC::Semaphore->new(IPC_PRIVATE, 1, S_IRUSR | S_IWUSR | IPC_CREAT);
e08109cb
KS
2878
2879if ($list[0]) {
912541b0
KS
2880 foreach my $arg (@list) {
2881 if (defined($tests[$arg-1]->{desc})) {
2882 print "udev-test will run test number $arg:\n\n";
09a4062d 2883 run_test($tests[$arg-1], $arg, $sema);
912541b0
KS
2884 } else {
2885 print "test does not exist.\n";
2886 }
2887 }
2e317184 2888} else {
912541b0
KS
2889 # test all
2890 print "\nudev-test will run ".($#tests + 1)." tests:\n\n";
2e317184 2891
912541b0 2892 foreach my $rules (@tests) {
09a4062d 2893 run_test($rules, $test_num, $sema);
912541b0
KS
2894 $test_num++;
2895 }
2e317184
GKH
2896}
2897
09a4062d 2898$sema->remove;
cbeb23d8 2899print "$error errors occurred. $good/$exp_good good results.\n\n";
a367f04e 2900
abb9cc50 2901cleanup();
a367f04e 2902
034b37c8 2903if ($error > 0) {
d3fc8bf4 2904 exit(1);
034b37c8
AJ
2905}
2906exit(0);