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