1
0
mirror of https://github.com/systemd/systemd.git synced 2025-01-27 18:04:05 +03:00

[PATCH] support =, ==, !=, += for the key match and assignment

This commit is contained in:
kay.sievers@vrfy.org 2005-03-13 05:46:31 +01:00 committed by Greg KH
parent 3b6ed8bb06
commit 28ce66de17
8 changed files with 541 additions and 337 deletions

View File

@ -8,3 +8,13 @@ a built-in userdb parser to resolve user and group names.
THE PLACE= key is gone. It can be replaced by an ID= for a long time, cause THE PLACE= key is gone. It can be replaced by an ID= for a long time, cause
we walk up the chain of physical devices to find a match. we walk up the chain of physical devices to find a match.
The KEY="<value>" format supports '=', '==', '!=,' , '+=' now. This makes it
easier to skip certain devices without composing rules with weird character
class negations like:
KERNEL="[!s][!c][!d]*"
this can be replaced by:
KERNEL!="scd*"
The simple '=' is still supported, but the rules should be converted if
possible, to be better human-readable.

View File

@ -39,8 +39,8 @@ my @tests = (
devpath => "/block/sda", devpath => "/block/sda",
exp_name => "boot_disk" , exp_name => "boot_disk" ,
conf => <<EOF conf => <<EOF
BUS="scsi", SYSFS{vendor}="IBM-ESXS", NAME="boot_disk%n" BUS=="scsi", SYSFS{vendor}=="IBM-ESXS", NAME="boot_disk%n"
KERNEL="ttyUSB0", NAME="visor" KERNEL=="ttyUSB0", NAME="visor"
EOF EOF
}, },
{ {
@ -49,7 +49,7 @@ EOF
devpath => "/block/sda/sda1", devpath => "/block/sda/sda1",
exp_name => "boot_disk1" , exp_name => "boot_disk1" ,
conf => <<EOF conf => <<EOF
BUS="scsi", SYSFS{vendor}="IBM-ESXS", NAME="boot_disk%n" BUS=="scsi", SYSFS{vendor}=="IBM-ESXS", NAME="boot_disk%n"
EOF EOF
}, },
{ {
@ -58,10 +58,10 @@ EOF
devpath => "/block/sda/sda1", devpath => "/block/sda/sda1",
exp_name => "boot_disk1" , exp_name => "boot_disk1" ,
conf => <<EOF conf => <<EOF
BUS="scsi", SYSFS{vendor}="?IBM-ESXS", NAME="boot_disk%n-1" BUS=="scsi", SYSFS{vendor}=="?IBM-ESXS", NAME="boot_disk%n-1"
BUS="scsi", SYSFS{vendor}="IBM-ESXS?", NAME="boot_disk%n-2" BUS=="scsi", SYSFS{vendor}=="IBM-ESXS?", NAME="boot_disk%n-2"
BUS="scsi", SYSFS{vendor}="IBM-ES??", NAME="boot_disk%n" BUS=="scsi", SYSFS{vendor}=="IBM-ES??", NAME="boot_disk%n"
BUS="scsi", SYSFS{vendor}="IBM-ESXSS", NAME="boot_disk%n-3" BUS=="scsi", SYSFS{vendor}=="IBM-ESXSS", NAME="boot_disk%n-3"
EOF EOF
}, },
{ {
@ -70,8 +70,8 @@ EOF
devpath => "/block/sda/sda1", devpath => "/block/sda/sda1",
exp_name => "boot_disk1" , exp_name => "boot_disk1" ,
conf => <<EOF conf => <<EOF
BUS="scsi", SYSFS{vendor}="IBM-ESXS", SYSFS{model}="ST336605LW !#", NAME="boot_diskX%n" BUS=="scsi", SYSFS{vendor}=="IBM-ESXS", SYSFS{model}=="ST336605LW !#", NAME="boot_diskX%n"
BUS="scsi", SYSFS{vendor}="IBM-ESXS", SYSFS{model}="ST336605LW !#", NAME="boot_disk%n" BUS=="scsi", SYSFS{vendor}=="IBM-ESXS", SYSFS{model}=="ST336605LW !#", NAME="boot_disk%n"
EOF EOF
}, },
{ {
@ -80,8 +80,8 @@ EOF
devpath => "/block/sda/sda1", devpath => "/block/sda/sda1",
exp_name => "boot_disk1" , exp_name => "boot_disk1" ,
conf => <<EOF conf => <<EOF
BUS="scsi", SYSFS{vendor}="IBM-ESXS", SYSFS{model}="ST336605LW !#", SYSFS{scsi_level}="4", SYSFS{rev}="B245", SYSFS{type}="2", SYSFS{queue_depth}="32", NAME="boot_diskXX%n" BUS=="scsi", SYSFS{vendor}=="IBM-ESXS", SYSFS{model}=="ST336605LW !#", SYSFS{scsi_level}=="4", SYSFS{rev}=="B245", SYSFS{type}=="2", SYSFS{queue_depth}=="32", NAME="boot_diskXX%n"
BUS="scsi", SYSFS{vendor}="IBM-ESXS", SYSFS{model}="ST336605LW !#", SYSFS{scsi_level}="4", SYSFS{rev}="B245", SYSFS{type}="0", NAME="boot_disk%n" BUS=="scsi", SYSFS{vendor}=="IBM-ESXS", SYSFS{model}=="ST336605LW !#", SYSFS{scsi_level}=="4", SYSFS{rev}=="B245", SYSFS{type}=="0", NAME="boot_disk%n"
EOF EOF
}, },
{ {
@ -90,7 +90,7 @@ EOF
devpath => "/class/tty/ttyUSB0", devpath => "/class/tty/ttyUSB0",
exp_name => "visor/0" , exp_name => "visor/0" ,
conf => <<EOF conf => <<EOF
KERNEL="ttyUSB*", NAME="visor/%n" KERNEL=="ttyUSB*", NAME="visor/%n"
EOF EOF
}, },
{ {
@ -99,8 +99,8 @@ EOF
devpath => "/class/tty/ttyUSB0", devpath => "/class/tty/ttyUSB0",
exp_name => "visor/0" , exp_name => "visor/0" ,
conf => <<EOF conf => <<EOF
KERNEL="*USB1", NAME="bad" KERNEL=="*USB1", NAME="bad"
KERNEL="*USB0", NAME="visor/%n" KERNEL=="*USB0", NAME="visor/%n"
EOF EOF
}, },
{ {
@ -109,9 +109,9 @@ EOF
devpath => "/class/tty/ttyUSB0", devpath => "/class/tty/ttyUSB0",
exp_name => "visor/0" , exp_name => "visor/0" ,
conf => <<EOF conf => <<EOF
KERNEL="ttyUSB??*", NAME="visor/%n-1" KERNEL=="ttyUSB??*", NAME="visor/%n-1"
KERNEL="ttyUSB??", NAME="visor/%n-2" KERNEL=="ttyUSB??", NAME="visor/%n-2"
KERNEL="ttyUSB?", NAME="visor/%n" KERNEL=="ttyUSB?", NAME="visor/%n"
EOF EOF
}, },
{ {
@ -120,9 +120,9 @@ EOF
devpath => "/class/tty/ttyUSB0", devpath => "/class/tty/ttyUSB0",
exp_name => "visor/0" , exp_name => "visor/0" ,
conf => <<EOF conf => <<EOF
KERNEL="ttyUSB[A-Z]*", NAME="visor/%n-1" KERNEL=="ttyUSB[A-Z]*", NAME="visor/%n-1"
KERNEL="ttyUSB?[0-9]", NAME="visor/%n-2" KERNEL=="ttyUSB?[0-9]", NAME="visor/%n-2"
KERNEL="ttyUSB[0-9]*", NAME="visor/%n" KERNEL=="ttyUSB[0-9]*", NAME="visor/%n"
EOF EOF
}, },
{ {
@ -131,7 +131,7 @@ EOF
devpath => "/class/tty/ttyUSB0", devpath => "/class/tty/ttyUSB0",
exp_name => "visor" , exp_name => "visor" ,
conf => <<EOF conf => <<EOF
KERNEL="ttyUSB0", NAME="visor" KERNEL=="ttyUSB0", NAME="visor"
EOF EOF
}, },
{ {
@ -141,7 +141,7 @@ EOF
exp_name => "visor" , exp_name => "visor" ,
conf => <<EOF conf => <<EOF
# this is a comment # this is a comment
KERNEL="ttyUSB0", NAME="visor" KERNEL=="ttyUSB0", NAME="visor"
EOF EOF
}, },
@ -152,7 +152,7 @@ EOF
exp_name => "visor" , exp_name => "visor" ,
conf => <<EOF conf => <<EOF
# this is a comment with whitespace before the comment # this is a comment with whitespace before the comment
KERNEL="ttyUSB0", NAME="visor" KERNEL=="ttyUSB0", NAME="visor"
EOF EOF
}, },
@ -166,7 +166,7 @@ EOF
# this is a comment with whitespace before the comment # this is a comment with whitespace before the comment
KERNEL="ttyUSB0", NAME="whitespace" KERNEL=="ttyUSB0", NAME="whitespace"
@ -179,7 +179,7 @@ EOF
exp_name => "visor" , exp_name => "visor" ,
conf => <<EOF conf => <<EOF
KERNEL="ttyUSB0", NAME="visor" KERNEL=="ttyUSB0", NAME="visor"
EOF EOF
}, },
@ -189,7 +189,7 @@ EOF
devpath => "/class/tty/ttyUSB0", devpath => "/class/tty/ttyUSB0",
exp_name => "visor" , exp_name => "visor" ,
conf => <<EOF conf => <<EOF
KERNEL="ttyUSB0", \\ KERNEL=="ttyUSB0", \\
NAME="visor" NAME="visor"
EOF EOF
@ -200,7 +200,7 @@ EOF
devpath => "/class/tty/ttyUSB0", devpath => "/class/tty/ttyUSB0",
exp_name => "aaa", exp_name => "aaa",
conf => <<EOF conf => <<EOF
KERNEL="ttyUSB0", PROGRAM="/bin/echo -e \\101", RESULT="A", NAME="aaa" KERNEL=="ttyUSB0", PROGRAM=="/bin/echo -e \\101", RESULT=="A", NAME="aaa"
EOF EOF
}, },
{ {
@ -217,7 +217,7 @@ EOF
#\\ #\\
KERNEL="ttyUSB0", \\ KERNEL=="ttyUSB0", \\
NAME="visor" NAME="visor"
EOF EOF
@ -228,7 +228,7 @@ EOF
devpath => "/class/tty/ttyUSB0", devpath => "/class/tty/ttyUSB0",
exp_name => "sub/direct/ory/visor" , exp_name => "sub/direct/ory/visor" ,
conf => <<EOF conf => <<EOF
KERNEL="ttyUSB0", NAME="sub/direct/ory/visor" KERNEL=="ttyUSB0", NAME="sub/direct/ory/visor"
EOF EOF
}, },
{ {
@ -237,7 +237,7 @@ EOF
devpath => "/block/sda/sda3", devpath => "/block/sda/sda3",
exp_name => "first_disk3" , exp_name => "first_disk3" ,
conf => <<EOF conf => <<EOF
BUS="scsi", ID="0:0:0:0", NAME="first_disk%n" BUS=="scsi", ID=="0:0:0:0", NAME="first_disk%n"
EOF EOF
}, },
{ {
@ -246,7 +246,7 @@ EOF
devpath => "/block/sda/sda3", devpath => "/block/sda/sda3",
exp_name => "Major:8:minor:3:kernelnumber:3:bus:0:0:0:0" , exp_name => "Major:8:minor:3:kernelnumber:3:bus:0:0:0:0" ,
conf => <<EOF conf => <<EOF
BUS="scsi", ID="0:0:0:0", NAME="Major:%M:minor:%m:kernelnumber:%n:bus:%b" BUS=="scsi", ID=="0:0:0:0", NAME="Major:%M:minor:%m:kernelnumber:%n:bus:%b"
EOF EOF
}, },
{ {
@ -255,7 +255,7 @@ EOF
devpath => "/block/sda/sda3", devpath => "/block/sda/sda3",
exp_name => "M8-m3-n3-b0:0-sIBM" , exp_name => "M8-m3-n3-b0:0-sIBM" ,
conf => <<EOF conf => <<EOF
BUS="scsi", ID="0:0:0:0", NAME="M%M-m%m-n%n-b%3b-s%3s{vendor}" BUS=="scsi", ID=="0:0:0:0", NAME="M%M-m%m-n%n-b%3b-s%3s{vendor}"
EOF EOF
}, },
{ {
@ -264,7 +264,7 @@ EOF
devpath => "/block/sda", devpath => "/block/sda",
exp_name => "good" , exp_name => "good" ,
conf => <<EOF conf => <<EOF
BUS="scsi", SYSFS_vendor="IBM-ESXS", NAME="good" BUS=="scsi", SYSFS_vendor=="IBM-ESXS", NAME="good"
EOF EOF
}, },
{ {
@ -273,8 +273,8 @@ EOF
devpath => "/block/sda", devpath => "/block/sda",
exp_name => "disk-IBM-ESXS-sda" , exp_name => "disk-IBM-ESXS-sda" ,
conf => <<EOF conf => <<EOF
BUS="scsi", SYSFS{vendor}="IBM-ESXS", NAME="disk-%s{vendor}-%k" BUS=="scsi", SYSFS{vendor}=="IBM-ESXS", NAME="disk-%s{vendor}-%k"
KERNEL="ttyUSB0", NAME="visor" KERNEL=="ttyUSB0", NAME="visor"
EOF EOF
}, },
{ {
@ -283,11 +283,11 @@ EOF
devpath => "/block/sda/sda3", devpath => "/block/sda/sda3",
exp_name => "special-device-3" , exp_name => "special-device-3" ,
conf => <<EOF conf => <<EOF
BUS="scsi", PROGRAM="/bin/echo -n special-device", RESULT="-special-*", NAME="%c-1-%n" BUS=="scsi", PROGRAM=="/bin/echo -n special-device", RESULT=="-special-*", NAME="%c-1-%n"
BUS="scsi", PROGRAM="/bin/echo -n special-device", RESULT="special--*", NAME="%c-2-%n" BUS=="scsi", PROGRAM=="/bin/echo -n special-device", RESULT=="special--*", NAME="%c-2-%n"
BUS="scsi", PROGRAM="/bin/echo -n special-device", RESULT="special-device-", NAME="%c-3-%n" BUS=="scsi", PROGRAM=="/bin/echo -n special-device", RESULT=="special-device-", NAME="%c-3-%n"
BUS="scsi", PROGRAM="/bin/echo -n special-device", RESULT="special-devic", NAME="%c-4-%n" BUS=="scsi", PROGRAM=="/bin/echo -n special-device", RESULT=="special-devic", NAME="%c-4-%n"
BUS="scsi", PROGRAM="/bin/echo -n special-device", RESULT="special-*", NAME="%c-%n" BUS=="scsi", PROGRAM=="/bin/echo -n special-device", RESULT=="special-*", NAME="%c-%n"
EOF EOF
}, },
{ {
@ -296,7 +296,7 @@ EOF
devpath => "/block/sda/sda3", devpath => "/block/sda/sda3",
exp_name => "subsys_block" , exp_name => "subsys_block" ,
conf => <<EOF conf => <<EOF
BUS="scsi", PROGRAM="/bin/echo", RESULT="block", NAME="subsys_block" BUS=="scsi", PROGRAM=="/bin/echo", RESULT=="block", NAME="subsys_block"
EOF EOF
}, },
{ {
@ -305,7 +305,7 @@ EOF
devpath => "/block/sda/sda3", devpath => "/block/sda/sda3",
exp_name => "newline_removed" , exp_name => "newline_removed" ,
conf => <<EOF conf => <<EOF
BUS="scsi", PROGRAM="/bin/echo test", RESULT="test", NAME="newline_removed" BUS=="scsi", PROGRAM=="/bin/echo test", RESULT=="test", NAME="newline_removed"
EOF EOF
}, },
{ {
@ -314,7 +314,7 @@ EOF
devpath => "/block/sda/sda3", devpath => "/block/sda/sda3",
exp_name => "test-0:0:0:0" , exp_name => "test-0:0:0:0" ,
conf => <<EOF conf => <<EOF
BUS="scsi", PROGRAM="/bin/echo -n test-%b", RESULT="test-0:0*", NAME="%c" BUS=="scsi", PROGRAM=="/bin/echo -n test-%b", RESULT=="test-0:0*", NAME="%c"
EOF EOF
}, },
{ {
@ -323,7 +323,7 @@ EOF
devpath => "/block/sda/sda3", devpath => "/block/sda/sda3",
exp_name => "escape-3" , exp_name => "escape-3" ,
conf => <<EOF conf => <<EOF
BUS="scsi", PROGRAM="/bin/echo -n escape-%%n", KERNEL="sda3", NAME="%c" BUS=="scsi", PROGRAM=="/bin/echo -n escape-%%n", KERNEL=="sda3", NAME="%c"
EOF EOF
}, },
{ {
@ -332,7 +332,7 @@ EOF
devpath => "/block/sda/sda3", devpath => "/block/sda/sda3",
exp_name => "foo9" , exp_name => "foo9" ,
conf => <<EOF conf => <<EOF
BUS="scsi", PROGRAM="/bin/echo -n foo3 foo4 foo5 foo6 foo7 foo8 foo9", KERNEL="sda3", NAME="%c{7}" BUS=="scsi", PROGRAM=="/bin/echo -n foo3 foo4 foo5 foo6 foo7 foo8 foo9", KERNEL=="sda3", NAME="%c{7}"
EOF EOF
}, },
{ {
@ -341,7 +341,7 @@ EOF
devpath => "/block/sda/sda3", devpath => "/block/sda/sda3",
exp_name => "bar9" , exp_name => "bar9" ,
conf => <<EOF conf => <<EOF
BUS="scsi", PROGRAM="/bin/sh -c 'echo foo3 foo4 foo5 foo6 foo7 foo8 foo9 | sed s/foo9/bar9/'", KERNEL="sda3", NAME="%c{7}" BUS=="scsi", PROGRAM=="/bin/sh -c 'echo foo3 foo4 foo5 foo6 foo7 foo8 foo9 | sed s/foo9/bar9/'", KERNEL=="sda3", NAME="%c{7}"
EOF EOF
}, },
{ {
@ -350,7 +350,7 @@ EOF
devpath => "/block/sda/sda3", devpath => "/block/sda/sda3",
exp_name => "foo7" , exp_name => "foo7" ,
conf => <<EOF conf => <<EOF
BUS="scsi", PROGRAM="/bin/echo -n 'foo3 foo4' 'foo5 foo6 foo7 foo8'", KERNEL="sda3", NAME="%c{5}" BUS=="scsi", PROGRAM=="/bin/echo -n 'foo3 foo4' 'foo5 foo6 foo7 foo8'", KERNEL=="sda3", NAME="%c{5}"
EOF EOF
}, },
{ {
@ -359,7 +359,7 @@ EOF
devpath => "/block/sda/sda3", devpath => "/block/sda/sda3",
exp_name => "my-foo9" , exp_name => "my-foo9" ,
conf => <<EOF conf => <<EOF
BUS="scsi", PROGRAM="/bin/echo -n foo3 foo4 foo5 foo6 foo7 foo8 foo9", KERNEL="sda3", NAME="my-%c{7}" BUS=="scsi", PROGRAM=="/bin/echo -n foo3 foo4 foo5 foo6 foo7 foo8 foo9", KERNEL=="sda3", NAME="my-%c{7}"
EOF EOF
}, },
{ {
@ -368,7 +368,7 @@ EOF
devpath => "/block/sda/sda3", devpath => "/block/sda/sda3",
exp_name => "my-foo8" , exp_name => "my-foo8" ,
conf => <<EOF conf => <<EOF
BUS="scsi", PROGRAM="/bin/echo -n foo3 foo4 foo5 foo6 foo7 foo8 foo9", KERNEL="sda3", NAME="my-%c{6}" BUS=="scsi", PROGRAM=="/bin/echo -n foo3 foo4 foo5 foo6 foo7 foo8 foo9", KERNEL=="sda3", NAME="my-%c{6}"
EOF EOF
}, },
{ {
@ -377,8 +377,8 @@ EOF
devpath => "/class/tty/console", devpath => "/class/tty/console",
exp_name => "TTY" , exp_name => "TTY" ,
conf => <<EOF conf => <<EOF
BUS="scsi", PROGRAM="/bin/echo -n foo", RESULT="foo", NAME="foo" BUS=="scsi", PROGRAM=="/bin/echo -n foo", RESULT=="foo", NAME="foo"
KERNEL="console", NAME="TTY" KERNEL=="console", NAME="TTY"
EOF EOF
}, },
{ {
@ -387,8 +387,8 @@ EOF
devpath => "/class/tty/console", devpath => "/class/tty/console",
exp_name => "foo" , exp_name => "foo" ,
conf => <<EOF conf => <<EOF
PROGRAM="/bin/echo -n foo", RESULT="foo", NAME="foo" PROGRAM=="/bin/echo -n foo", RESULT=="foo", NAME="foo"
KERNEL="console", NAME="TTY" KERNEL=="console", NAME="TTY"
EOF EOF
}, },
{ {
@ -397,8 +397,8 @@ EOF
devpath => "/class/tty/console", devpath => "/class/tty/console",
exp_name => "TTY" , exp_name => "TTY" ,
conf => <<EOF conf => <<EOF
BUS="foo", SYSFS{dev}="5:1", NAME="foo" BUS=="foo", SYSFS{dev}=="5:1", NAME="foo"
KERNEL="console", NAME="TTY" KERNEL=="console", NAME="TTY"
EOF EOF
}, },
{ {
@ -407,8 +407,8 @@ EOF
devpath => "/class/tty/console", devpath => "/class/tty/console",
exp_name => "foo" , exp_name => "foo" ,
conf => <<EOF conf => <<EOF
SYSFS{dev}="5:1", NAME="foo" SYSFS{dev}=="5:1", NAME="foo"
KERNEL="console", NAME="TTY" KERNEL=="console", NAME="TTY"
EOF EOF
}, },
{ {
@ -417,9 +417,9 @@ EOF
devpath => "/block/sda", devpath => "/block/sda",
exp_name => "scsi-0:0:0:0" , exp_name => "scsi-0:0:0:0" ,
conf => <<EOF conf => <<EOF
BUS="usb", PROGRAM="/bin/echo -n usb-%b", NAME="%c" BUS=="usb", PROGRAM=="/bin/echo -n usb-%b", NAME="%c"
BUS="scsi", PROGRAM="/bin/echo -n scsi-%b", NAME="%c" BUS=="scsi", PROGRAM=="/bin/echo -n scsi-%b", NAME="%c"
BUS="foo", PROGRAM="/bin/echo -n foo-%b", NAME="%c" BUS=="foo", PROGRAM=="/bin/echo -n foo-%b", NAME="%c"
EOF EOF
}, },
{ {
@ -428,7 +428,7 @@ EOF
devpath => "/block/sda", devpath => "/block/sda",
exp_name => "boot_disk15" , exp_name => "boot_disk15" ,
conf => <<EOF conf => <<EOF
BUS="scsi", SYSFS{vendor}="IBM-ESXS", NAME{all_partitions}="boot_disk" BUS=="scsi", SYSFS{vendor}=="IBM-ESXS", NAME{all_partitions}="boot_disk"
EOF EOF
}, },
{ {
@ -437,7 +437,7 @@ EOF
devpath => "/class/tty/ttyUSB0", devpath => "/class/tty/ttyUSB0",
exp_name => "visor" , exp_name => "visor" ,
conf => <<EOF conf => <<EOF
SYSFS{idProduct}="2008", NAME="visor" SYSFS{idProduct}=="2008", NAME="visor"
EOF EOF
}, },
{ {
@ -446,8 +446,8 @@ EOF
devpath => "/block/rd!c0d0", devpath => "/block/rd!c0d0",
exp_name => "rd/c0d0" , exp_name => "rd/c0d0" ,
conf => <<EOF conf => <<EOF
BUS="scsi", NAME="%k" BUS=="scsi", NAME="%k"
KERNEL="ttyUSB0", NAME="visor" KERNEL=="ttyUSB0", NAME="visor"
EOF EOF
}, },
{ {
@ -456,7 +456,7 @@ EOF
devpath => "/block/rd!c0d0", devpath => "/block/rd!c0d0",
exp_name => "rd/c0d0" , exp_name => "rd/c0d0" ,
conf => <<EOF conf => <<EOF
KERNEL="ttyUSB0", NAME="visor" KERNEL=="ttyUSB0", NAME="visor"
EOF EOF
}, },
{ {
@ -465,8 +465,8 @@ EOF
devpath => "/block/cciss!c0d0/cciss!c0d0p1", devpath => "/block/cciss!c0d0/cciss!c0d0p1",
exp_name => "cciss/c0d0p1" , exp_name => "cciss/c0d0p1" ,
conf => <<EOF conf => <<EOF
BUS="scsi", NAME="%k" BUS=="scsi", NAME="%k"
KERNEL="ttyUSB0", NAME="visor" KERNEL=="ttyUSB0", NAME="visor"
EOF EOF
}, },
{ {
@ -475,11 +475,11 @@ EOF
devpath => "/block/sda", devpath => "/block/sda",
exp_name => "scsi-0:0:0:0", exp_name => "scsi-0:0:0:0",
conf => <<EOF conf => <<EOF
BUS="usb", ID="0:0:0:0", NAME="not-scsi" BUS=="usb", ID=="0:0:0:0", NAME="not-scsi"
BUS="scsi", ID="0:0:0:1", NAME="no-match" BUS=="scsi", ID=="0:0:0:1", NAME="no-match"
BUS="scsi", ID=":0", NAME="short-id" BUS=="scsi", ID==":0", NAME="short-id"
BUS="scsi", ID="/0:0:0:0", NAME="no-match" BUS=="scsi", ID=="/0:0:0:0", NAME="no-match"
BUS="scsi", ID="0:0:0:0", NAME="scsi-0:0:0:0" BUS=="scsi", ID=="0:0:0:0", NAME="scsi-0:0:0:0"
EOF EOF
}, },
{ {
@ -488,11 +488,11 @@ EOF
devpath => "/block/sda", devpath => "/block/sda",
exp_name => "scsi-0:0:0:0", exp_name => "scsi-0:0:0:0",
conf => <<EOF conf => <<EOF
BUS="scsi", ID="*:1", NAME="no-match" BUS=="scsi", ID=="*:1", NAME="no-match"
BUS="scsi", ID="*:0:1", NAME="no-match" BUS=="scsi", ID=="*:0:1", NAME="no-match"
BUS="scsi", ID="*:0:0:1", NAME="no-match" BUS=="scsi", ID=="*:0:0:1", NAME="no-match"
BUS="scsi", ID="*", NAME="scsi-0:0:0:0" BUS=="scsi", ID=="*", NAME="scsi-0:0:0:0"
BUS="scsi", ID="0:0:0:0", NAME="bad" BUS=="scsi", ID=="0:0:0:0", NAME="bad"
EOF EOF
}, },
{ {
@ -501,8 +501,8 @@ EOF
devpath => "/block/sda", devpath => "/block/sda",
exp_name => "scsi-0:0:0:0", exp_name => "scsi-0:0:0:0",
conf => <<EOF conf => <<EOF
BUS="scsi", ID="*:0", NAME="scsi-0:0:0:0" BUS=="scsi", ID=="*:0", NAME="scsi-0:0:0:0"
BUS="scsi", ID="0:0:0:0", NAME="bad" BUS=="scsi", ID=="0:0:0:0", NAME="bad"
EOF EOF
}, },
{ {
@ -511,8 +511,8 @@ EOF
devpath => "/block/sda", devpath => "/block/sda",
exp_name => "scsi-0:0:0:0", exp_name => "scsi-0:0:0:0",
conf => <<EOF conf => <<EOF
BUS="scsi", ID="*:0:0:0", NAME="scsi-0:0:0:0" BUS=="scsi", ID=="*:0:0:0", NAME="scsi-0:0:0:0"
BUS="scsi", ID="0:0:0:0", NAME="bad" BUS=="scsi", ID=="0:0:0:0", NAME="bad"
EOF EOF
}, },
{ {
@ -521,7 +521,7 @@ EOF
devpath => "/block/sda", devpath => "/block/sda",
exp_name => "ignored", exp_name => "ignored",
conf => <<EOF conf => <<EOF
BUS="scsi", SYSFS{whitespace_test}="WHITE SPACE", NAME="ignored" BUS=="scsi", SYSFS{whitespace_test}=="WHITE SPACE", NAME="ignored"
EOF EOF
}, },
{ {
@ -530,8 +530,8 @@ EOF
devpath => "/block/sda", devpath => "/block/sda",
exp_name => "matched-with-space", exp_name => "matched-with-space",
conf => <<EOF conf => <<EOF
BUS="scsi", SYSFS{whitespace_test}="WHITE SPACE ", NAME="wrong-to-ignore" BUS=="scsi", SYSFS{whitespace_test}=="WHITE SPACE ", NAME="wrong-to-ignore"
BUS="scsi", SYSFS{whitespace_test}="WHITE SPACE ", NAME="matched-with-space" BUS=="scsi", SYSFS{whitespace_test}=="WHITE SPACE ", NAME="matched-with-space"
EOF EOF
}, },
{ {
@ -541,7 +541,7 @@ EOF
exp_name => "tty33", exp_name => "tty33",
exp_perms => "0:0:0660", exp_perms => "0:0:0660",
conf => <<EOF conf => <<EOF
KERNEL="tty33", NAME="tty33", OWNER="bad", GROUP="name" KERNEL=="tty33", NAME="tty33", OWNER="bad", GROUP="name"
EOF EOF
}, },
{ {
@ -551,7 +551,7 @@ EOF
exp_name => "node", exp_name => "node",
exp_perms => "5000::0660", exp_perms => "5000::0660",
conf => <<EOF conf => <<EOF
BUS="scsi", KERNEL="sda", NAME="node", OWNER="5000" BUS=="scsi", KERNEL=="sda", NAME="node", OWNER="5000"
EOF EOF
}, },
{ {
@ -561,7 +561,7 @@ EOF
exp_name => "node", exp_name => "node",
exp_perms => ":100:0660", exp_perms => ":100:0660",
conf => <<EOF conf => <<EOF
BUS="scsi", KERNEL="sda", NAME="node", GROUP="100" BUS=="scsi", KERNEL=="sda", NAME="node", GROUP="100"
EOF EOF
}, },
{ {
@ -571,7 +571,7 @@ EOF
exp_name => "node", exp_name => "node",
exp_perms => "::0777", exp_perms => "::0777",
conf => <<EOF conf => <<EOF
BUS="scsi", KERNEL="sda", NAME="node", MODE="0777" BUS=="scsi", KERNEL=="sda", NAME="node", MODE="0777"
EOF EOF
}, },
{ {
@ -581,7 +581,7 @@ EOF
exp_name => "node", exp_name => "node",
exp_perms => "5000:100:0777", exp_perms => "5000:100:0777",
conf => <<EOF conf => <<EOF
BUS="scsi", KERNEL="sda", NAME="node", OWNER="5000", GROUP="100", MODE="0777" BUS=="scsi", KERNEL=="sda", NAME="node", OWNER="5000", GROUP="100", MODE="0777"
EOF EOF
}, },
{ {
@ -591,7 +591,7 @@ EOF
exp_name => "ttyUSB0", exp_name => "ttyUSB0",
exp_perms => "5000::", exp_perms => "5000::",
conf => <<EOF conf => <<EOF
KERNEL="ttyUSB[0-9]*", NAME="ttyUSB%n", OWNER="5000" KERNEL=="ttyUSB[0-9]*", NAME="ttyUSB%n", OWNER="5000"
EOF EOF
}, },
{ {
@ -601,7 +601,7 @@ EOF
exp_name => "ttyUSB0", exp_name => "ttyUSB0",
exp_perms => ":100:0660", exp_perms => ":100:0660",
conf => <<EOF conf => <<EOF
KERNEL="ttyUSB[0-9]*", NAME="ttyUSB%n", GROUP="100" KERNEL=="ttyUSB[0-9]*", NAME="ttyUSB%n", GROUP="100"
EOF EOF
}, },
{ {
@ -611,7 +611,7 @@ EOF
exp_name => "ttyUSB0", exp_name => "ttyUSB0",
exp_perms => "::0060", exp_perms => "::0060",
conf => <<EOF conf => <<EOF
KERNEL="ttyUSB[0-9]*", NAME="ttyUSB%n", MODE="0060" KERNEL=="ttyUSB[0-9]*", NAME="ttyUSB%n", MODE="0060"
EOF EOF
}, },
{ {
@ -621,7 +621,7 @@ EOF
exp_name => "ttyUSB0", exp_name => "ttyUSB0",
exp_perms => "5000:100:0777", exp_perms => "5000:100:0777",
conf => <<EOF conf => <<EOF
KERNEL="ttyUSB[0-9]*", NAME="ttyUSB%n", OWNER="5000", GROUP="100", MODE="0777" KERNEL=="ttyUSB[0-9]*", NAME="ttyUSB%n", OWNER="5000", GROUP="100", MODE="0777"
EOF EOF
}, },
{ {
@ -631,9 +631,9 @@ EOF
exp_name => "ttyUSB0", exp_name => "ttyUSB0",
exp_perms => "5000:100:0777", exp_perms => "5000:100:0777",
conf => <<EOF conf => <<EOF
KERNEL="ttyUSB[0-9]*", OWNER="5000", GROUP="100", MODE="0777" KERNEL=="ttyUSB[0-9]*", OWNER="5000", GROUP="100", MODE="0777"
KERNEL="ttyUSX[0-9]*", OWNER="5001", GROUP="101", MODE="0444" KERNEL=="ttyUSX[0-9]*", OWNER="5001", GROUP="101", MODE="0444"
KERNEL="ttyUSB[0-9]*", NAME="ttyUSB%n" KERNEL=="ttyUSB[0-9]*", NAME="ttyUSB%n"
EOF EOF
}, },
{ {
@ -643,11 +643,11 @@ EOF
exp_name => "ttyUSB0", exp_name => "ttyUSB0",
exp_perms => "3000:4000:0777", exp_perms => "3000:4000:0777",
conf => <<EOF conf => <<EOF
SUBSYSTEM="tty", OWNER="3000" SUBSYSTEM=="tty", OWNER="3000"
SUBSYSTEM="tty", GROUP="4000" SUBSYSTEM=="tty", GROUP="4000"
SUBSYSTEM="tty", MODE="0777" SUBSYSTEM=="tty", MODE="0777"
KERNEL="ttyUSX[0-9]*", OWNER="5001", GROUP="101", MODE="0444" KERNEL=="ttyUSX[0-9]*", OWNER="5001", GROUP="101", MODE="0444"
KERNEL="ttyUSB[0-9]*", NAME="ttyUSB%n" KERNEL=="ttyUSB[0-9]*", NAME="ttyUSB%n"
EOF EOF
}, },
{ {
@ -657,11 +657,11 @@ EOF
exp_name => "ttyUSB0", exp_name => "ttyUSB0",
exp_perms => "3000:8000:0777", exp_perms => "3000:8000:0777",
conf => <<EOF conf => <<EOF
SUBSYSTEM="tty", OWNER="3000" SUBSYSTEM=="tty", OWNER="3000"
SUBSYSTEM="tty", GROUP="4000" SUBSYSTEM=="tty", GROUP="4000"
SUBSYSTEM="tty", MODE="0777" SUBSYSTEM=="tty", MODE="0777"
KERNEL="ttyUSX[0-9]*", OWNER="5001", GROUP="101", MODE="0444" KERNEL=="ttyUSX[0-9]*", OWNER="5001", GROUP="101", MODE="0444"
KERNEL="ttyUSB[0-9]*", NAME="ttyUSB%n", GROUP="8000" KERNEL=="ttyUSB[0-9]*", NAME="ttyUSB%n", GROUP="8000"
EOF EOF
}, },
{ {
@ -671,7 +671,7 @@ EOF
exp_name => "node", exp_name => "node",
exp_majorminor => "8:0", exp_majorminor => "8:0",
conf => <<EOF conf => <<EOF
BUS="scsi", KERNEL="sda", NAME="node" BUS=="scsi", KERNEL=="sda", NAME="node"
EOF EOF
}, },
{ {
@ -681,7 +681,7 @@ EOF
exp_name => "node", exp_name => "node",
exp_majorminor => "89:300", exp_majorminor => "89:300",
conf => <<EOF conf => <<EOF
KERNEL="i2c-300", NAME="node" KERNEL=="i2c-300", NAME="node"
EOF EOF
}, },
{ {
@ -691,7 +691,7 @@ EOF
exp_name => "node", exp_name => "node",
exp_majorminor => "4095:1", exp_majorminor => "4095:1",
conf => <<EOF conf => <<EOF
KERNEL="i2c-fake1", NAME="node" KERNEL=="i2c-fake1", NAME="node"
EOF EOF
}, },
{ {
@ -701,7 +701,7 @@ EOF
exp_name => "node", exp_name => "node",
exp_majorminor => "4094:89999", exp_majorminor => "4094:89999",
conf => <<EOF conf => <<EOF
KERNEL="i2c-fake2", NAME="node" KERNEL=="i2c-fake2", NAME="node"
EOF EOF
}, },
{ {
@ -711,7 +711,7 @@ EOF
exp_name => "symlink2-ttyUSB0", exp_name => "symlink2-ttyUSB0",
exp_target => "ttyUSB0", exp_target => "ttyUSB0",
conf => <<EOF conf => <<EOF
KERNEL="ttyUSB[0-9]*", NAME="ttyUSB%n", SYMLINK="symlink1-%n symlink2-%k symlink3-%b" KERNEL=="ttyUSB[0-9]*", NAME="ttyUSB%n", SYMLINK="symlink1-%n symlink2-%k symlink3-%b"
EOF EOF
}, },
{ {
@ -721,7 +721,7 @@ EOF
exp_name => "visor0", exp_name => "visor0",
exp_target => "ttyUSB0", exp_target => "ttyUSB0",
conf => <<EOF conf => <<EOF
KERNEL="ttyUSB[0-9]*", NAME="ttyUSB%n", SYMLINK="visor%n" KERNEL=="ttyUSB[0-9]*", NAME="ttyUSB%n", SYMLINK="visor%n"
EOF EOF
}, },
{ {
@ -731,7 +731,7 @@ EOF
exp_name => "1/2/symlink" , exp_name => "1/2/symlink" ,
exp_target => "a/b/node", exp_target => "a/b/node",
conf => <<EOF conf => <<EOF
BUS="scsi", SYSFS{vendor}="IBM-ESXS", NAME="1/2/a/b/node", SYMLINK="1/2/symlink" BUS=="scsi", SYSFS{vendor}=="IBM-ESXS", NAME="1/2/a/b/node", SYMLINK="1/2/symlink"
EOF EOF
}, },
{ {
@ -741,7 +741,7 @@ EOF
exp_name => "1/2/c/d/symlink" , exp_name => "1/2/c/d/symlink" ,
exp_target => "../../a/b/node", exp_target => "../../a/b/node",
conf => <<EOF conf => <<EOF
BUS="scsi", SYSFS{vendor}="IBM-ESXS", NAME="1/2/a/b/node", SYMLINK="1/2/c/d/symlink" BUS=="scsi", SYSFS{vendor}=="IBM-ESXS", NAME="1/2/a/b/node", SYMLINK="1/2/c/d/symlink"
EOF EOF
}, },
{ {
@ -751,7 +751,7 @@ EOF
exp_name => "second-0" , exp_name => "second-0" ,
exp_target => "visor" , exp_target => "visor" ,
conf => <<EOF conf => <<EOF
KERNEL="ttyUSB0", NAME="visor", SYMLINK="first-%n second-%n third-%n" KERNEL=="ttyUSB0", NAME="visor", SYMLINK="first-%n second-%n third-%n"
EOF EOF
}, },
{ {
@ -761,9 +761,9 @@ EOF
exp_name => "symlink-only2", exp_name => "symlink-only2",
exp_target => "link", exp_target => "link",
conf => <<EOF conf => <<EOF
BUS="scsi", KERNEL="sda", SYMLINK="symlink-only1" BUS=="scsi", KERNEL=="sda", SYMLINK="symlink-only1"
BUS="scsi", KERNEL="sda", SYMLINK="symlink-only2" BUS=="scsi", KERNEL=="sda", SYMLINK="symlink-only2"
BUS="scsi", KERNEL="sda", NAME="link", SYMLINK="symlink0" BUS=="scsi", KERNEL=="sda", NAME="link", SYMLINK="symlink0"
EOF EOF
}, },
{ {
@ -775,7 +775,7 @@ EOF
exp_add_error => "yes", exp_add_error => "yes",
exp_rem_error => "yes", exp_rem_error => "yes",
conf => <<EOF conf => <<EOF
BUS="scsi", KERNEL="sda", NAME="link", SYMLINK="." BUS=="scsi", KERNEL=="sda", NAME="link", SYMLINK="."
EOF EOF
}, },
{ {
@ -787,7 +787,7 @@ EOF
exp_rem_error => "yes", exp_rem_error => "yes",
option => "clear", option => "clear",
conf => <<EOF conf => <<EOF
KERNEL="tty0", NAME="link", SYMLINK="link" KERNEL=="tty0", NAME="link", SYMLINK="link"
EOF EOF
}, },
{ {
@ -797,7 +797,7 @@ EOF
exp_name => "symlink0", exp_name => "symlink0",
exp_target => "ttyUSB0", exp_target => "ttyUSB0",
conf => <<EOF conf => <<EOF
KERNEL="ttyUSB[0-9]*", NAME="ttyUSB%n", SYMLINK="symlink%n" KERNEL=="ttyUSB[0-9]*", NAME="ttyUSB%n", SYMLINK="symlink%n"
EOF EOF
}, },
{ {
@ -807,7 +807,7 @@ EOF
exp_name => "symlink-ttyUSB0", exp_name => "symlink-ttyUSB0",
exp_target => "ttyUSB0", exp_target => "ttyUSB0",
conf => <<EOF conf => <<EOF
KERNEL="ttyUSB[0-9]*", NAME="ttyUSB%n", SYMLINK="symlink-%k" KERNEL=="ttyUSB[0-9]*", NAME="ttyUSB%n", SYMLINK="symlink-%k"
EOF EOF
}, },
{ {
@ -817,7 +817,7 @@ EOF
exp_name => "major-188:0", exp_name => "major-188:0",
exp_target => "ttyUSB0", exp_target => "ttyUSB0",
conf => <<EOF conf => <<EOF
KERNEL="ttyUSB[0-9]*", NAME="ttyUSB%n", SYMLINK="major-%M:%m" KERNEL=="ttyUSB[0-9]*", NAME="ttyUSB%n", SYMLINK="major-%M:%m"
EOF EOF
}, },
{ {
@ -827,7 +827,7 @@ EOF
exp_name => "symlink-0:0:0:0", exp_name => "symlink-0:0:0:0",
exp_target => "node", exp_target => "node",
conf => <<EOF conf => <<EOF
BUS="scsi", KERNEL="sda", NAME="node", SYMLINK="symlink-%b" BUS=="scsi", KERNEL=="sda", NAME="node", SYMLINK="symlink-%b"
EOF EOF
}, },
{ {
@ -837,7 +837,7 @@ EOF
exp_name => "test", exp_name => "test",
exp_target => "ttyUSB0", exp_target => "ttyUSB0",
conf => <<EOF conf => <<EOF
KERNEL="ttyUSB[0-9]*", PROGRAM="/bin/echo test" NAME="ttyUSB%n", SYMLINK="%c" KERNEL=="ttyUSB[0-9]*", PROGRAM=="/bin/echo test" NAME="ttyUSB%n", SYMLINK="%c"
EOF EOF
}, },
{ {
@ -847,7 +847,7 @@ EOF
exp_name => "test", exp_name => "test",
exp_target => "ttyUSB0", exp_target => "ttyUSB0",
conf => <<EOF conf => <<EOF
KERNEL="ttyUSB[0-9]*", PROGRAM="/bin/echo symlink test this" NAME="ttyUSB%n", SYMLINK="%c{2}" KERNEL=="ttyUSB[0-9]*", PROGRAM=="/bin/echo symlink test this" NAME="ttyUSB%n", SYMLINK="%c{2}"
EOF EOF
}, },
{ {
@ -857,7 +857,7 @@ EOF
exp_name => "this", exp_name => "this",
exp_target => "ttyUSB0", exp_target => "ttyUSB0",
conf => <<EOF conf => <<EOF
KERNEL="ttyUSB[0-9]*", PROGRAM="/bin/echo symlink test this" NAME="ttyUSB%n", SYMLINK="%c{2+}" KERNEL=="ttyUSB[0-9]*", PROGRAM=="/bin/echo symlink test this" NAME="ttyUSB%n", SYMLINK="%c{2+}"
EOF EOF
}, },
{ {
@ -867,8 +867,8 @@ EOF
exp_name => "test", exp_name => "test",
exp_target => "link", exp_target => "link",
conf => <<EOF conf => <<EOF
BUS="scsi", KERNEL="sda", PROGRAM="/bin/echo link test this" SYMLINK="%c{2+}" BUS=="scsi", KERNEL=="sda", PROGRAM=="/bin/echo link test this" SYMLINK="%c{2+}"
BUS="scsi", KERNEL="sda", NAME="link", SYMLINK="symlink0" BUS=="scsi", KERNEL=="sda", NAME="link", SYMLINK="symlink0"
EOF EOF
}, },
{ {
@ -878,7 +878,7 @@ EOF
exp_name => "188:0", exp_name => "188:0",
exp_target => "ttyUSB0", exp_target => "ttyUSB0",
conf => <<EOF conf => <<EOF
KERNEL="ttyUSB[0-9]*", NAME="ttyUSB%n", SYMLINK="%s{dev}" KERNEL=="ttyUSB[0-9]*", NAME="ttyUSB%n", SYMLINK="%s{dev}"
EOF EOF
}, },
{ {
@ -888,7 +888,7 @@ EOF
exp_name => "188", exp_name => "188",
exp_target => "ttyUSB0", exp_target => "ttyUSB0",
conf => <<EOF conf => <<EOF
KERNEL="ttyUSB[0-9]*", NAME="ttyUSB%n", SYMLINK="%3s{dev}" KERNEL=="ttyUSB[0-9]*", NAME="ttyUSB%n", SYMLINK="%3s{dev}"
EOF EOF
}, },
{ {
@ -898,7 +898,7 @@ EOF
exp_name => "percent%sign", exp_name => "percent%sign",
exp_target => "ttyUSB0", exp_target => "ttyUSB0",
conf => <<EOF conf => <<EOF
KERNEL="ttyUSB[0-9]*", NAME="ttyUSB%n", SYMLINK="percent%%sign" KERNEL=="ttyUSB[0-9]*", NAME="ttyUSB%n", SYMLINK="percent%%sign"
EOF EOF
}, },
{ {
@ -908,7 +908,7 @@ EOF
exp_name => "%ttyUSB0_name", exp_name => "%ttyUSB0_name",
exp_target => "ttyUSB0", exp_target => "ttyUSB0",
conf => <<EOF conf => <<EOF
KERNEL="ttyUSB[0-9]*", NAME="ttyUSB%n", SYMLINK="%%%k_name" KERNEL=="ttyUSB[0-9]*", NAME="ttyUSB%n", SYMLINK="%%%k_name"
EOF EOF
}, },
{ {
@ -918,7 +918,7 @@ EOF
exp_name => "link1", exp_name => "link1",
exp_target => "node", exp_target => "node",
conf => <<EOF conf => <<EOF
BUS="scsi", PROGRAM="/bin/echo -n node link1 link2", RESULT="node *", NAME="%c{1}", SYMLINK="%c{2} %c{3}" BUS=="scsi", PROGRAM=="/bin/echo -n node link1 link2", RESULT=="node *", NAME="%c{1}", SYMLINK="%c{2} %c{3}"
EOF EOF
}, },
{ {
@ -928,7 +928,7 @@ EOF
exp_name => "link4", exp_name => "link4",
exp_target => "node", exp_target => "node",
conf => <<EOF conf => <<EOF
BUS="scsi", PROGRAM="/bin/echo -n node link1 link2 link3 link4", RESULT="node *", NAME="%c{1}", SYMLINK="%c{2+}" BUS=="scsi", PROGRAM=="/bin/echo -n node link1 link2 link3 link4", RESULT=="node *", NAME="%c{1}", SYMLINK="%c{2+}"
EOF EOF
}, },
{ {
@ -937,7 +937,7 @@ EOF
devpath => "/block/sda", devpath => "/block/sda",
exp_name => "cdrom", exp_name => "cdrom",
conf => <<EOF conf => <<EOF
KERNEL="sda", NAME="cdrom%e" KERNEL=="sda", NAME="cdrom%e"
EOF EOF
}, },
{ {
@ -947,7 +947,7 @@ EOF
exp_name => "cdrom", exp_name => "cdrom",
option => "keep", option => "keep",
conf => <<EOF conf => <<EOF
KERNEL="sda", NAME="cdrom%e" KERNEL=="sda", NAME="cdrom%e"
EOF EOF
}, },
{ {
@ -957,7 +957,7 @@ EOF
exp_name => "enum", exp_name => "enum",
option => "keep", option => "keep",
conf => <<EOF conf => <<EOF
KERNEL="sda1", NAME="enum%e" KERNEL=="sda1", NAME="enum%e"
EOF EOF
}, },
{ {
@ -967,7 +967,7 @@ EOF
exp_name => "cdrom1", exp_name => "cdrom1",
option => "keep", option => "keep",
conf => <<EOF conf => <<EOF
KERNEL="sda2", NAME="cdrom%e" KERNEL=="sda2", NAME="cdrom%e"
EOF EOF
}, },
{ {
@ -977,7 +977,7 @@ EOF
exp_name => "enum1", exp_name => "enum1",
option => "keep", option => "keep",
conf => <<EOF conf => <<EOF
KERNEL="sda3", NAME="enum%e" KERNEL=="sda3", NAME="enum%e"
EOF EOF
}, },
{ {
@ -987,7 +987,7 @@ EOF
exp_name => "cdrom2", exp_name => "cdrom2",
option => "clear", option => "clear",
conf => <<EOF conf => <<EOF
KERNEL="sda4", NAME="cdrom%e" KERNEL=="sda4", NAME="cdrom%e"
EOF EOF
}, },
{ {
@ -996,7 +996,7 @@ EOF
devpath => "/block/sda", devpath => "/block/sda",
exp_name => "cdrom", exp_name => "cdrom",
conf => <<EOF conf => <<EOF
KERNEL="sda", NAME="cdrom%e" KERNEL=="sda", NAME="cdrom%e"
EOF EOF
}, },
{ {
@ -1006,7 +1006,7 @@ EOF
exp_name => "node", exp_name => "node",
exp_add_error => "yes", exp_add_error => "yes",
conf => <<EOF conf => <<EOF
BUS="scsi", KERNEL="sda", NAME="node", OPTIONS="ignore" BUS=="scsi", KERNEL=="sda", NAME="node", OPTIONS="ignore"
EOF EOF
}, },
{ {
@ -1015,8 +1015,8 @@ EOF
devpath => "/block/sda", devpath => "/block/sda",
exp_name => "node6", exp_name => "node6",
conf => <<EOF conf => <<EOF
SUBSYSTEM="block", OPTIONS="all_partitions" SUBSYSTEM=="block", OPTIONS="all_partitions"
BUS="scsi", KERNEL="sda", NAME="node" BUS=="scsi", KERNEL=="sda", NAME="node"
EOF EOF
}, },
{ {
@ -1026,8 +1026,8 @@ EOF
exp_name => "node6", exp_name => "node6",
exp_add_error => "yes", exp_add_error => "yes",
conf => <<EOF conf => <<EOF
SUBSYSTEM="block", OPTIONS="all_partitions" SUBSYSTEM=="block", OPTIONS="all_partitions"
BUS="scsi", KERNEL="sda", NAME="node" BUS=="scsi", KERNEL=="sda", NAME="node"
EOF EOF
}, },
{ {
@ -1037,7 +1037,7 @@ EOF
exp_name => "node", exp_name => "node",
exp_rem_error => "yes", exp_rem_error => "yes",
conf => <<EOF conf => <<EOF
BUS="scsi", KERNEL="sda", NAME="node", OPTIONS="ignore_remove" BUS=="scsi", KERNEL=="sda", NAME="node", OPTIONS="ignore_remove"
EOF EOF
}, },
{ {
@ -1048,7 +1048,7 @@ EOF
exp_rem_error => "yes", exp_rem_error => "yes",
option => "clear", option => "clear",
conf => <<EOF conf => <<EOF
BUS="scsi", KERNEL="sda", NAME="node", OPTIONS="ignore_remove, all_partitions" BUS=="scsi", KERNEL=="sda", NAME="node", OPTIONS="ignore_remove, all_partitions"
EOF EOF
}, },
{ {
@ -1057,9 +1057,9 @@ EOF
devpath => "/block/sda", devpath => "/block/sda",
exp_name => "node", exp_name => "node",
conf => <<EOF conf => <<EOF
BUS="scsi", KERNEL="sda", NAME="should_not_match", SUBSYSTEM="vc" BUS=="scsi", KERNEL=="sda", NAME="should_not_match", SUBSYSTEM=="vc"
BUS="scsi", KERNEL="sda", NAME="node", SUBSYSTEM="block" BUS=="scsi", KERNEL=="sda", NAME="node", SUBSYSTEM=="block"
BUS="scsi", KERNEL="sda", NAME="should_not_match2", SUBSYSTEM="vc" BUS=="scsi", KERNEL=="sda", NAME="should_not_match2", SUBSYSTEM=="vc"
EOF EOF
}, },
{ {
@ -1068,8 +1068,8 @@ EOF
devpath => "/block/sda", devpath => "/block/sda",
exp_name => "node", exp_name => "node",
conf => <<EOF conf => <<EOF
BUS="scsi", KERNEL="sda", NAME="should_not_match", DRIVER="sd-wrong" BUS=="scsi", KERNEL=="sda", NAME="should_not_match", DRIVER=="sd-wrong"
BUS="scsi", KERNEL="sda", NAME="node", DRIVER="sd" BUS=="scsi", KERNEL=="sda", NAME="node", DRIVER=="sd"
EOF EOF
}, },
{ {
@ -1078,7 +1078,7 @@ EOF
devpath => "/block/sda", devpath => "/block/sda",
exp_name => "node", exp_name => "node",
conf => <<EOF conf => <<EOF
BUS="scsi", KERNEL="sda", PROGRAM="/usr/bin/test -b %N" NAME="node" BUS=="scsi", KERNEL=="sda", PROGRAM=="/usr/bin/test -b %N" NAME="node"
EOF EOF
}, },
{ {
@ -1087,7 +1087,7 @@ EOF
devpath => "/block/sda", devpath => "/block/sda",
exp_name => "sda", exp_name => "sda",
conf => <<EOF conf => <<EOF
BUS="scsi", KERNEL="sda", PROGRAM="/bin/echo %p", RESULT="/block/sda" NAME="%k" BUS=="scsi", KERNEL=="sda", PROGRAM=="/bin/echo %p", RESULT=="/block/sda" NAME="%k"
EOF EOF
}, },
{ {
@ -1097,7 +1097,7 @@ EOF
exp_name => "main_device", exp_name => "main_device",
option => "keep", option => "keep",
conf => <<EOF conf => <<EOF
BUS="scsi", KERNEL="sda", NAME="main_device" BUS=="scsi", KERNEL=="sda", NAME="main_device"
EOF EOF
}, },
{ {
@ -1107,7 +1107,7 @@ EOF
exp_name => "main_device-part-1", exp_name => "main_device-part-1",
option => "clean", option => "clean",
conf => <<EOF conf => <<EOF
BUS="scsi", KERNEL="sda1", NAME="%P-part-1" BUS=="scsi", KERNEL=="sda1", NAME="%P-part-1"
EOF EOF
}, },
{ {
@ -1116,7 +1116,7 @@ EOF
devpath => "/block/sda/sda1", devpath => "/block/sda/sda1",
exp_name => "start-udev-root-end", exp_name => "start-udev-root-end",
conf => <<EOF conf => <<EOF
BUS="scsi", KERNEL="sda1", NAME="start-%r-end" BUS=="scsi", KERNEL=="sda1", NAME="start-%r-end"
EOF EOF
}, },
{ {
@ -1125,8 +1125,40 @@ EOF
devpath => "/block/sda/sda1", devpath => "/block/sda/sda1",
exp_name => "last", exp_name => "last",
conf => <<EOF conf => <<EOF
BUS="scsi", KERNEL="sda1", SYMLINK="last", OPTIONS="last_rule" BUS=="scsi", KERNEL=="sda1", SYMLINK="last", OPTIONS="last_rule"
BUS="scsi", KERNEL="sda1", NAME="very-last" BUS=="scsi", KERNEL=="sda1", NAME="very-last"
EOF
},
{
desc => "negation KERNEL!=",
subsys => "block",
devpath => "/block/sda/sda1",
exp_name => "match",
conf => <<EOF
BUS=="scsi", KERNEL!="sda1", NAME="matches-but-is-negated"
BUS=="scsi", KERNEL!="xsda1", NAME="match"
BUS=="scsi", KERNEL=="sda1", NAME="wrong"
EOF
},
{
desc => "negation SUBSYSTEM!=",
subsys => "block",
devpath => "/block/sda/sda1",
exp_name => "not-anything",
conf => <<EOF
BUS=="scsi", SUBSYSTEM=="block", KERNEL!="sda1", NAME="matches-but-is-negated"
BUS=="scsi", SUBSYSTEM!="anything", NAME="not-anything"
BUS=="scsi", KERNEL=="sda1", NAME="wrong"
EOF
},
{
desc => "negation PROGRAM!= exit code",
subsys => "block",
devpath => "/block/sda/sda1",
exp_name => "nonzero-program",
conf => <<EOF
KERNEL=="sda1", PROGRAM!="/bin/false", NAME="nonzero-program"
BUS=="scsi", KERNEL=="sda1", NAME="wrong"
EOF EOF
}, },
); );

View File

@ -92,11 +92,11 @@ the name is used to name the device file or the network interface.
.br .br
If no matching rule is found, the default kernel device name is used. If no matching rule is found, the default kernel device name is used.
.P .P
Every rule consists of a list of comma separated fields: Every rule consists of a list of comma separated key value fields:
.sp .sp
.IR "key " ,[ "key " ,...] " name " [, " symlink" ] .IR "key " ,[ "key " ,...]
.sp .P
where fields are: The following key names can be used to match against device properties:
.TP .TP
.B BUS .B BUS
Match the bus type of the device. Match the bus type of the device.
@ -126,18 +126,20 @@ the key doesn't have any trailing whitespace characters by itself.
Call external program. This key is valid if the program returns successful. Call external program. This key is valid if the program returns successful.
The environment variables of The environment variables of
.B udev .B udev
are also available for the program. are also available to the program.
.br .br
The string returned by the program may be additionally matched with the The string returned by the program may be additionally matched with the
.B RESULT .B RESULT
key. key in the same or any later rule.
.TP .TP
.B RESULT .B RESULT
Match the returned string of the last Match the returned string of the last
.B PROGRAM .B PROGRAM
call. This key may be used in any following rule after a call. This key can be used in the same or in any later rule after a
.B PROGRAM .B PROGRAM
call. call.
.P
The following keys can get values assigned:
.TP .TP
.B NAME .B NAME
The name of the node to be created, or the name, the network interface The name of the node to be created, or the name, the network interface
@ -162,6 +164,10 @@ The permissions for the device node. Every specified value overwrites the
compiled-in default value. compiled-in default value.
.TP .TP
.B OPTIONS .B OPTIONS
.B last_rule
will be the last rule applied. No later rules will have any effect.
.sp
.B OPTIONS
.B ignore_device .B ignore_device
will ignore this device. No node will be created. will ignore this device. No node will be created.
.sp .sp
@ -240,31 +246,31 @@ the first three characters of the sysfs attribute.
.sp .sp
.nf .nf
# if /sbin/scsi_id returns "OEM 0815", the device will be called disk1 # if /sbin/scsi_id returns "OEM 0815", the device will be called disk1
BUS="scsi", PROGRAM="/sbin/scsi_id", RESULT="OEM 0815", NAME="disk1" BUS=="scsi", PROGRAM=="/sbin/scsi_id", RESULT=="OEM 0815", NAME="disk1"
# USB printer to be called lp_color # USB printer to be called lp_color
BUS="usb", SYSFS{serial}="W09090207101241330", NAME="lp_color" BUS=="usb", SYSFS{serial}=="W09090207101241330", NAME="lp_color"
# SCSI disk with a specific vendor and model number will be called boot # SCSI disk with a specific vendor and model number will be called boot
BUS="scsi", SYSFS{vendor}="IBM", SYSFS{model}="ST336", NAME="boot%n" BUS=="scsi", SYSFS{vendor}=="IBM", SYSFS{model}=="ST336", NAME="boot%n"
# sound card with PCI bus id 00:0b.0 to be called dsp # sound card with PCI bus id 00:0b.0 to be called dsp
BUS="pci", ID="00:0b.0", NAME="dsp" BUS=="pci", ID=="00:0b.0", NAME="dsp"
# USB mouse at third port of the second hub to be called mouse1 # USB mouse at third port of the second hub to be called mouse1
BUS="usb", ID="2.3", NAME="mouse1" BUS=="usb", ID=="2.3", NAME="mouse1"
# ttyUSB1 should always be called pda with two additional symlinks # ttyUSB1 should always be called pda with two additional symlinks
KERNEL="ttyUSB1", NAME="pda", SYMLINK="palmtop handheld" KERNEL=="ttyUSB1", NAME="pda", SYMLINK="palmtop handheld"
# multiple USB webcams with symlinks to be called webcam0, webcam1, ... # multiple USB webcams with symlinks to be called webcam0, webcam1, ...
BUS="usb", SYSFS{model}="XV3", NAME="video%n", SYMLINK="webcam%n" BUS=="usb", SYSFS{model}=="XV3", NAME=="video%n", SYMLINK="webcam%n"
# grouping of optical drives from multiple kernel subsystems # grouping of optical drives from multiple kernel subsystems
KERNEL="sr*", NAME="%k", SYMLINK="cdrom%e" KERNEL=="sr*", NAME="%k", SYMLINK="cdrom%e"
KERNEL="scd*", NAME="%k", SYMLINK="cdrom%e" KERNEL=="scd*", NAME="%k", SYMLINK="cdrom%e"
KERNEL="pcd*", NAME="%k", SYMLINK="cdrom%e" KERNEL=="pcd*", NAME="%k", SYMLINK="cdrom%e"
KERNEL="hd[a-z]", PROGRAM="/bin/cat /proc/ide/%k/media", RESULT="cdrom", KERNEL=="hd[a-z]", PROGRAM=="/bin/cat /proc/ide/%k/media", RESULT=="cdrom",
NAME="%k", SYMLINK="cdrom%e" NAME="%k", SYMLINK="cdrom%e"
.fi .fi
.P .P

View File

@ -59,6 +59,54 @@ static int string_is_true(const char *str)
return 0; return 0;
} }
static int get_key(char **line, char **key, char **value)
{
char *linepos;
char *temp;
linepos = *line;
if (!linepos)
return -1;
/* skip whitespace */
while (isspace(linepos[0]))
linepos++;
/* get the key */
*key = linepos;
while (1) {
linepos++;
if (linepos[0] == '\0')
return -1;
if (isspace(linepos[0]))
break;
if (linepos[0] == '=')
break;
}
/* terminate key */
linepos[0] = '\0';
linepos++;
/* skip whitespace */
while (isspace(linepos[0]))
linepos++;
/* get the value*/
if (linepos[0] == '"')
linepos++;
else
return -1;
*value = linepos;
temp = strchr(linepos, '"');
if (!temp)
return -1;
temp[0] = '\0';
return 0;
}
static void init_variables(void) static void init_variables(void)
{ {
const char *env; const char *env;
@ -86,7 +134,7 @@ static int parse_config_file(void)
{ {
char line[LINE_SIZE]; char line[LINE_SIZE];
char *bufline; char *bufline;
char *temp; char *linepos;
char *variable; char *variable;
char *value; char *value;
char *buf; char *buf;
@ -130,13 +178,14 @@ static int parse_config_file(void)
continue; continue;
strlcpy(line, bufline, count); strlcpy(line, bufline, count);
temp = line; dbg("read '%s'", line);
dbg("read '%s'", temp);
retval = parse_get_pair(&temp, &variable, &value); linepos = line;
if (retval != 0) retval = get_key(&linepos, &variable, &value);
info("%s:%d:%Zd: error parsing '%s'", if (retval != 0) {
udev_config_filename, lineno, temp-line, temp); info("error parsing %s, line %d:%d", udev_config_filename, lineno, (int) (linepos-line));
continue;
}
dbg("variable='%s', value='%s'", variable, value); dbg("variable='%s', value='%s'", variable, value);
@ -168,17 +217,16 @@ static int parse_config_file(void)
return retval; return retval;
} }
static void get_dirs(void) void udev_init_config(void)
{ {
char *temp;
int retval;
retval = sysfs_get_mnt_path(sysfs_path, sizeof(sysfs_path)); init_variables();
if (retval) sysfs_get_mnt_path(sysfs_path, sizeof(sysfs_path));
dbg("sysfs_get_mnt_path failed");
/* see if we should try to override any of the default values */ /* see if we should try to override any of the default values */
if (getenv("UDEV_TEST") != NULL) { if (getenv("UDEV_TEST") != NULL) {
char *temp;
temp = getenv("SYSFS_PATH"); temp = getenv("SYSFS_PATH");
if (temp != NULL) { if (temp != NULL) {
strlcpy(sysfs_path, temp, sizeof(sysfs_path)); strlcpy(sysfs_path, temp, sizeof(sysfs_path));
@ -198,9 +246,3 @@ static void get_dirs(void)
dbg("udev_rules_filename='%s'", udev_rules_filename); dbg("udev_rules_filename='%s'", udev_rules_filename);
dbg("udev_log=%d", udev_log); dbg("udev_log=%d", udev_log);
} }
void udev_init_config(void)
{
init_variables();
get_dirs();
}

View File

@ -390,7 +390,7 @@ static int execute_program(struct udevice *udev, const char *path, char *value,
dup2(fds[1], STDOUT_FILENO); dup2(fds[1], STDOUT_FILENO);
retval = execv(arg, argv); retval = execv(arg, argv);
info(FIELD_PROGRAM " execution of '%s' failed", path); info(KEY_PROGRAM " execution of '%s' failed", path);
exit(1); exit(1);
case -1: case -1:
dbg("fork failed"); dbg("fork failed");
@ -508,8 +508,13 @@ static int match_sysfs_pairs(struct udev_rule *rule, struct sysfs_class_device *
if ((pair->file[0] == '\0') || (pair->value[0] == '\0')) if ((pair->file[0] == '\0') || (pair->value[0] == '\0'))
break; break;
if (compare_sysfs_attribute(class_dev, sysfs_device, pair) != 0) { if (compare_sysfs_attribute(class_dev, sysfs_device, pair) != 0) {
dbg("sysfs attribute doesn't match"); dbg("sysfs pair #%u does not match", i);
return -ENODEV; if (pair->operation != KEY_OP_NOMATCH)
return -1;
} else {
dbg("sysfs pair #%u matches", i);
if (pair->operation == KEY_OP_NOMATCH)
return -1;
} }
} }
@ -535,23 +540,33 @@ static int match_rule(struct udevice *udev, struct udev_rule *rule,
struct sysfs_class_device *class_dev, struct sysfs_device *sysfs_device) struct sysfs_class_device *class_dev, struct sysfs_device *sysfs_device)
{ {
if (rule->kernel[0] != '\0') { if (rule->kernel[0] != '\0') {
dbg("check for " FIELD_KERNEL " rule->kernel='%s' class_dev->name='%s'", dbg("check for " KEY_KERNEL " rule->kernel='%s' class_dev->name='%s'",
rule->kernel, class_dev->name); rule->kernel, class_dev->name);
if (strcmp_pattern(rule->kernel, class_dev->name) != 0) { if (strcmp_pattern(rule->kernel, class_dev->name) != 0) {
dbg(FIELD_KERNEL " is not matching"); dbg(KEY_KERNEL " is not matching");
goto exit; if (rule->kernel_operation != KEY_OP_NOMATCH)
goto exit;
} else {
dbg(KEY_KERNEL " matches");
if (rule->kernel_operation == KEY_OP_NOMATCH)
goto exit;
} }
dbg(FIELD_KERNEL " matches"); dbg(KEY_KERNEL " key is true");
} }
if (rule->subsystem[0] != '\0') { if (rule->subsystem[0] != '\0') {
dbg("check for " FIELD_SUBSYSTEM " rule->subsystem='%s' class_dev->name='%s'", dbg("check for " KEY_SUBSYSTEM " rule->subsystem='%s' class_dev->name='%s'",
rule->subsystem, class_dev->name); rule->subsystem, class_dev->name);
if (strcmp_pattern(rule->subsystem, udev->subsystem) != 0) { if (strcmp_pattern(rule->subsystem, udev->subsystem) != 0) {
dbg(FIELD_SUBSYSTEM " is not matching"); dbg(KEY_SUBSYSTEM " is not matching");
goto exit; if (rule->subsystem_operation != KEY_OP_NOMATCH)
goto exit;
} else {
dbg(KEY_SUBSYSTEM " matches");
if (rule->subsystem_operation == KEY_OP_NOMATCH)
goto exit;
} }
dbg(FIELD_SUBSYSTEM " matches"); dbg(KEY_SUBSYSTEM " key is true");
} }
/* walk up the chain of physical devices and find a match */ /* walk up the chain of physical devices and find a match */
@ -562,13 +577,18 @@ static int match_rule(struct udevice *udev, struct udev_rule *rule,
dbg("device has no sysfs_device"); dbg("device has no sysfs_device");
goto try_parent; goto try_parent;
} }
dbg("check for " FIELD_DRIVER " rule->driver='%s' sysfs_device->driver_name='%s'", dbg("check for " KEY_DRIVER " rule->driver='%s' sysfs_device->driver_name='%s'",
rule->driver, sysfs_device->driver_name); rule->driver, sysfs_device->driver_name);
if (strcmp_pattern(rule->driver, sysfs_device->driver_name) != 0) { if (strcmp_pattern(rule->driver, sysfs_device->driver_name) != 0) {
dbg(FIELD_DRIVER " is not matching"); dbg(KEY_DRIVER " is not matching");
goto try_parent; if (rule->driver_operation != KEY_OP_NOMATCH)
goto try_parent;
} else {
dbg(KEY_DRIVER " matches");
if (rule->driver_operation == KEY_OP_NOMATCH)
goto try_parent;
} }
dbg(FIELD_DRIVER " matches"); dbg(KEY_DRIVER " key is true");
} }
/* check for matching bus value */ /* check for matching bus value */
@ -577,13 +597,18 @@ static int match_rule(struct udevice *udev, struct udev_rule *rule,
dbg("device has no sysfs_device"); dbg("device has no sysfs_device");
goto try_parent; goto try_parent;
} }
dbg("check for " FIELD_BUS " rule->bus='%s' sysfs_device->bus='%s'", dbg("check for " KEY_BUS " rule->bus='%s' sysfs_device->bus='%s'",
rule->bus, sysfs_device->bus); rule->bus, sysfs_device->bus);
if (strcmp_pattern(rule->bus, sysfs_device->bus) != 0) { if (strcmp_pattern(rule->bus, sysfs_device->bus) != 0) {
dbg(FIELD_BUS " is not matching"); dbg(KEY_BUS " is not matching");
goto try_parent; if (rule->bus_operation != KEY_OP_NOMATCH)
goto try_parent;
} else {
dbg(KEY_BUS " matches");
if (rule->bus_operation == KEY_OP_NOMATCH)
goto try_parent;
} }
dbg(FIELD_BUS " matches"); dbg(KEY_BUS " key is true");
} }
/* check for matching bus id */ /* check for matching bus id */
@ -592,22 +617,27 @@ static int match_rule(struct udevice *udev, struct udev_rule *rule,
dbg("device has no sysfs_device"); dbg("device has no sysfs_device");
goto try_parent; goto try_parent;
} }
dbg("check " FIELD_ID); dbg("check " KEY_ID);
if (match_id(rule, sysfs_device) != 0) { if (match_id(rule, sysfs_device) != 0) {
dbg(FIELD_ID " is not matching"); dbg(KEY_ID " is not matching");
goto try_parent; if (rule->id_operation != KEY_OP_NOMATCH)
goto try_parent;
} else {
dbg(KEY_ID " matches");
if (rule->id_operation == KEY_OP_NOMATCH)
goto try_parent;
} }
dbg(FIELD_ID " matches"); dbg(KEY_ID " key is true");
} }
/* check for matching sysfs pairs */ /* check for matching sysfs pairs */
if (rule->sysfs_pair[0].file[0] != '\0') { if (rule->sysfs_pair[0].file[0] != '\0') {
dbg("check " FIELD_SYSFS " pairs"); dbg("check " KEY_SYSFS " pairs");
if (match_sysfs_pairs(rule, class_dev, sysfs_device) != 0) { if (match_sysfs_pairs(rule, class_dev, sysfs_device) != 0) {
dbg(FIELD_SYSFS " is not matching"); dbg(KEY_SYSFS " is not matching");
goto try_parent; goto try_parent;
} }
dbg(FIELD_SYSFS " matches"); dbg(KEY_SYSFS " keys are true");
} }
/* found matching physical device */ /* found matching physical device */
@ -625,25 +655,35 @@ try_parent:
if (rule->program[0] != '\0') { if (rule->program[0] != '\0') {
char program[PATH_SIZE]; char program[PATH_SIZE];
dbg("check " FIELD_PROGRAM); dbg("check " KEY_PROGRAM);
strlcpy(program, rule->program, sizeof(program)); strlcpy(program, rule->program, sizeof(program));
apply_format(udev, program, sizeof(program), class_dev, sysfs_device); apply_format(udev, program, sizeof(program), class_dev, sysfs_device);
if (execute_program(udev, program, udev->program_result, sizeof(udev->program_result)) != 0) { if (execute_program(udev, program, udev->program_result, sizeof(udev->program_result)) != 0) {
dbg(FIELD_PROGRAM " returned nonzero"); dbg(KEY_PROGRAM " returned nonzero");
goto try_parent; if (rule->program_operation != KEY_OP_NOMATCH)
goto exit;
} else {
dbg(KEY_PROGRAM " returned successful");
if (rule->program_operation == KEY_OP_NOMATCH)
goto exit;
} }
dbg(FIELD_PROGRAM " returned successful"); dbg(KEY_PROGRAM " key is true");
} }
/* check for matching result of external program */ /* check for matching result of external program */
if (rule->result[0] != '\0') { if (rule->result[0] != '\0') {
dbg("check for " FIELD_RESULT "rule->result='%s', udev->program_result='%s'", dbg("check for " KEY_RESULT " rule->result='%s', udev->program_result='%s'",
rule->result, udev->program_result); rule->result, udev->program_result);
if (strcmp_pattern(rule->result, udev->program_result) != 0) { if (strcmp_pattern(rule->result, udev->program_result) != 0) {
dbg(FIELD_RESULT " is not matching"); dbg(KEY_RESULT " is not matching");
goto try_parent; if (rule->result_operation != KEY_OP_NOMATCH)
goto exit;
} else {
dbg(KEY_RESULT " matches");
if (rule->result_operation == KEY_OP_NOMATCH)
goto exit;
} }
dbg(FIELD_RESULT " matches"); dbg(KEY_RESULT " key is true");
} }
/* rule matches */ /* rule matches */

View File

@ -28,20 +28,20 @@
#include "list.h" #include "list.h"
#define FIELD_KERNEL "KERNEL" #define KEY_KERNEL "KERNEL"
#define FIELD_SUBSYSTEM "SUBSYSTEM" #define KEY_SUBSYSTEM "SUBSYSTEM"
#define FIELD_BUS "BUS" #define KEY_BUS "BUS"
#define FIELD_SYSFS "SYSFS" #define KEY_SYSFS "SYSFS"
#define FIELD_ID "ID" #define KEY_ID "ID"
#define FIELD_PROGRAM "PROGRAM" #define KEY_PROGRAM "PROGRAM"
#define FIELD_RESULT "RESULT" #define KEY_RESULT "RESULT"
#define FIELD_DRIVER "DRIVER" #define KEY_DRIVER "DRIVER"
#define FIELD_NAME "NAME" #define KEY_NAME "NAME"
#define FIELD_SYMLINK "SYMLINK" #define KEY_SYMLINK "SYMLINK"
#define FIELD_OWNER "OWNER" #define KEY_OWNER "OWNER"
#define FIELD_GROUP "GROUP" #define KEY_GROUP "GROUP"
#define FIELD_MODE "MODE" #define KEY_MODE "MODE"
#define FIELD_OPTIONS "OPTIONS" #define KEY_OPTIONS "OPTIONS"
#define OPTION_LAST_RULE "last_rule" #define OPTION_LAST_RULE "last_rule"
#define OPTION_IGNORE_DEVICE "ignore_device" #define OPTION_IGNORE_DEVICE "ignore_device"
@ -52,25 +52,41 @@
#define RULEFILE_SUFFIX ".rules" #define RULEFILE_SUFFIX ".rules"
enum key_operation {
KEY_OP_UNKNOWN,
KEY_OP_MATCH,
KEY_OP_NOMATCH,
KEY_OP_ADD,
KEY_OP_ASSIGN,
};
struct sysfs_pair { struct sysfs_pair {
char file[PATH_SIZE]; char file[PATH_SIZE];
char value[VALUE_SIZE]; char value[VALUE_SIZE];
enum key_operation operation;
}; };
struct udev_rule { struct udev_rule {
struct list_head node; struct list_head node;
char kernel[NAME_SIZE]; char kernel[NAME_SIZE];
enum key_operation kernel_operation;
char subsystem[NAME_SIZE]; char subsystem[NAME_SIZE];
enum key_operation subsystem_operation;
char bus[NAME_SIZE]; char bus[NAME_SIZE];
enum key_operation bus_operation;
char id[NAME_SIZE]; char id[NAME_SIZE];
struct sysfs_pair sysfs_pair[MAX_SYSFS_PAIRS]; enum key_operation id_operation;
char program[PATH_SIZE];
char result[PATH_SIZE];
char driver[NAME_SIZE]; char driver[NAME_SIZE];
enum key_operation driver_operation;
char program[PATH_SIZE];
enum key_operation program_operation;
char result[PATH_SIZE];
enum key_operation result_operation;
struct sysfs_pair sysfs_pair[MAX_SYSFS_PAIRS];
char name[PATH_SIZE]; char name[PATH_SIZE];
char symlink[PATH_SIZE]; char symlink[PATH_SIZE];
char owner[USER_SIZE]; char owner[USER_SIZE];
char group[USER_SIZE]; char group[USER_SIZE];
mode_t mode; mode_t mode;

View File

@ -73,6 +73,90 @@ void udev_rule_list_dump(void)
udev_rule_dump(rule); udev_rule_dump(rule);
} }
static int get_key(char **line, char **key, enum key_operation *operation, char **value)
{
char *linepos;
char *temp;
linepos = *line;
if (!linepos)
return -1;
/* skip whitespace */
while (isspace(linepos[0]) || linepos[0] == ',')
linepos++;
/* get the key */
*key = linepos;
while (1) {
linepos++;
if (linepos[0] == '\0')
return -1;
if (isspace(linepos[0]))
break;
if (linepos[0] == '=')
break;
if (linepos[0] == '+')
break;
if (linepos[0] == '!')
break;
}
/* remember end of key */
temp = linepos;
/* skip whitespace after key */
while (isspace(linepos[0]))
linepos++;
/* get operation type */
if (linepos[0] == '=' && linepos[1] == '=') {
*operation = KEY_OP_MATCH;
linepos += 2;
dbg("operator=match");
} else if (linepos[0] == '!' && linepos[1] == '=') {
*operation = KEY_OP_NOMATCH;
linepos += 2;
dbg("operator=nomatch");
} else if (linepos[0] == '+' && linepos[1] == '=') {
*operation = KEY_OP_ADD;
linepos += 2;
dbg("operator=add");
} else if (linepos[0] == '=') {
*operation = KEY_OP_ASSIGN;
linepos++;
dbg("operator=assign");
} else
return -1;
/* terminate key */
temp[0] = '\0';
dbg("key='%s'", *key);
/* skip whitespace after operator */
while (isspace(linepos[0]))
linepos++;
/* get the value*/
if (linepos[0] == '"')
linepos++;
else
return -1;
*value = linepos;
temp = strchr(linepos, '"');
if (!temp)
return -1;
temp[0] = '\0';
temp++;
dbg("value='%s'", *value);
/* move line to next key */
*line = temp;
return 0;
}
/* extract possible KEY{attr} */ /* extract possible KEY{attr} */
static char *get_key_attribute(char *str) static char *get_key_attribute(char *str)
{ {
@ -100,9 +184,7 @@ static int rules_parse(struct udevice *udev, const char *filename)
char line[LINE_SIZE]; char line[LINE_SIZE];
char *bufline; char *bufline;
int lineno; int lineno;
char *temp; char *linepos;
char *temp2;
char *temp3;
char *attr; char *attr;
char *buf; char *buf;
size_t bufsize; size_t bufsize;
@ -113,12 +195,11 @@ static int rules_parse(struct udevice *udev, const char *filename)
int retval = 0; int retval = 0;
struct udev_rule rule; struct udev_rule rule;
if (file_map(filename, &buf, &bufsize) == 0) { if (file_map(filename, &buf, &bufsize) != 0) {
dbg("reading '%s' as rules file", filename);
} else {
dbg("can't open '%s' as rules file", filename); dbg("can't open '%s' as rules file", filename);
return -1; return -1;
} }
dbg("reading '%s' as rules file", filename);
/* loop through the whole file */ /* loop through the whole file */
cur = 0; cur = 0;
@ -160,39 +241,47 @@ static int rules_parse(struct udevice *udev, const char *filename)
/* get all known keys */ /* get all known keys */
memset(&rule, 0x00, sizeof(struct udev_rule)); memset(&rule, 0x00, sizeof(struct udev_rule));
temp = line; linepos = line;
valid = 0; valid = 0;
while (1) { while (1) {
retval = parse_get_pair(&temp, &temp2, &temp3); char *key;
char *value;
enum key_operation operation = KEY_OP_UNKNOWN;
retval = get_key(&linepos, &key, &operation, &value);
if (retval) if (retval)
break; break;
if (strcasecmp(temp2, FIELD_KERNEL) == 0) { if (strcasecmp(key, KEY_KERNEL) == 0) {
strlcpy(rule.kernel, temp3, sizeof(rule.kernel)); strlcpy(rule.kernel, value, sizeof(rule.kernel));
rule.kernel_operation = operation;
valid = 1; valid = 1;
continue; continue;
} }
if (strcasecmp(temp2, FIELD_SUBSYSTEM) == 0) { if (strcasecmp(key, KEY_SUBSYSTEM) == 0) {
strlcpy(rule.subsystem, temp3, sizeof(rule.subsystem)); strlcpy(rule.subsystem, value, sizeof(rule.subsystem));
rule.subsystem_operation = operation;
valid = 1; valid = 1;
continue; continue;
} }
if (strcasecmp(temp2, FIELD_BUS) == 0) { if (strcasecmp(key, KEY_BUS) == 0) {
strlcpy(rule.bus, temp3, sizeof(rule.bus)); strlcpy(rule.bus, value, sizeof(rule.bus));
rule.bus_operation = operation;
valid = 1; valid = 1;
continue; continue;
} }
if (strcasecmp(temp2, FIELD_ID) == 0) { if (strcasecmp(key, KEY_ID) == 0) {
strlcpy(rule.id, temp3, sizeof(rule.id)); strlcpy(rule.id, value, sizeof(rule.id));
rule.id_operation = operation;
valid = 1; valid = 1;
continue; continue;
} }
if (strncasecmp(temp2, FIELD_SYSFS, sizeof(FIELD_SYSFS)-1) == 0) { if (strncasecmp(key, KEY_SYSFS, sizeof(KEY_SYSFS)-1) == 0) {
struct sysfs_pair *pair = &rule.sysfs_pair[0]; struct sysfs_pair *pair = &rule.sysfs_pair[0];
int sysfs_pair_num = 0; int sysfs_pair_num = 0;
@ -206,39 +295,43 @@ static int rules_parse(struct udevice *udev, const char *filename)
++pair; ++pair;
} }
if (pair) { if (pair) {
attr = get_key_attribute(temp2 + sizeof(FIELD_SYSFS)-1); attr = get_key_attribute(key + sizeof(KEY_SYSFS)-1);
if (attr == NULL) { if (attr == NULL) {
dbg("error parsing " FIELD_SYSFS " attribute"); dbg("error parsing " KEY_SYSFS " attribute");
continue; continue;
} }
strlcpy(pair->file, attr, sizeof(pair->file)); strlcpy(pair->file, attr, sizeof(pair->file));
strlcpy(pair->value, temp3, sizeof(pair->value)); strlcpy(pair->value, value, sizeof(pair->value));
pair->operation = operation;
valid = 1; valid = 1;
} }
continue; continue;
} }
if (strcasecmp(temp2, FIELD_DRIVER) == 0) { if (strcasecmp(key, KEY_DRIVER) == 0) {
strlcpy(rule.driver, temp3, sizeof(rule.driver)); strlcpy(rule.driver, value, sizeof(rule.driver));
rule.driver_operation = operation;
valid = 1; valid = 1;
continue; continue;
} }
if (strcasecmp(temp2, FIELD_PROGRAM) == 0) { if (strcasecmp(key, KEY_RESULT) == 0) {
strlcpy(rule.result, value, sizeof(rule.result));
rule.result_operation = operation;
valid = 1;
continue;
}
if (strcasecmp(key, KEY_PROGRAM) == 0) {
strlcpy(rule.program, value, sizeof(rule.program));
rule.program_operation = operation;
program_given = 1; program_given = 1;
strlcpy(rule.program, temp3, sizeof(rule.program));
valid = 1; valid = 1;
continue; continue;
} }
if (strcasecmp(temp2, FIELD_RESULT) == 0) { if (strncasecmp(key, KEY_NAME, sizeof(KEY_NAME)-1) == 0) {
strlcpy(rule.result, temp3, sizeof(rule.result)); attr = get_key_attribute(key + sizeof(KEY_NAME)-1);
valid = 1;
continue;
}
if (strncasecmp(temp2, FIELD_NAME, sizeof(FIELD_NAME)-1) == 0) {
attr = get_key_attribute(temp2 + sizeof(FIELD_NAME)-1);
/* FIXME: remove old style options and make OPTIONS= mandatory */ /* FIXME: remove old style options and make OPTIONS= mandatory */
if (attr != NULL) { if (attr != NULL) {
if (strstr(attr, OPTION_PARTITIONS) != NULL) { if (strstr(attr, OPTION_PARTITIONS) != NULL) {
@ -250,52 +343,52 @@ static int rules_parse(struct udevice *udev, const char *filename)
rule.ignore_remove = 1; rule.ignore_remove = 1;
} }
} }
if (temp3[0] != '\0') if (value[0] != '\0')
strlcpy(rule.name, temp3, sizeof(rule.name)); strlcpy(rule.name, value, sizeof(rule.name));
else else
rule.ignore_device = 1; rule.ignore_device = 1;
valid = 1; valid = 1;
continue; continue;
} }
if (strcasecmp(temp2, FIELD_SYMLINK) == 0) { if (strcasecmp(key, KEY_SYMLINK) == 0) {
strlcpy(rule.symlink, temp3, sizeof(rule.symlink)); strlcpy(rule.symlink, value, sizeof(rule.symlink));
valid = 1; valid = 1;
continue; continue;
} }
if (strcasecmp(temp2, FIELD_OWNER) == 0) { if (strcasecmp(key, KEY_OWNER) == 0) {
strlcpy(rule.owner, temp3, sizeof(rule.owner)); strlcpy(rule.owner, value, sizeof(rule.owner));
valid = 1; valid = 1;
continue; continue;
} }
if (strcasecmp(temp2, FIELD_GROUP) == 0) { if (strcasecmp(key, KEY_GROUP) == 0) {
strlcpy(rule.group, temp3, sizeof(rule.group)); strlcpy(rule.group, value, sizeof(rule.group));
valid = 1; valid = 1;
continue; continue;
} }
if (strcasecmp(temp2, FIELD_MODE) == 0) { if (strcasecmp(key, KEY_MODE) == 0) {
rule.mode = strtol(temp3, NULL, 8); rule.mode = strtol(value, NULL, 8);
valid = 1; valid = 1;
continue; continue;
} }
if (strcasecmp(temp2, FIELD_OPTIONS) == 0) { if (strcasecmp(key, KEY_OPTIONS) == 0) {
if (strstr(temp3, OPTION_LAST_RULE) != NULL) { if (strstr(value, OPTION_LAST_RULE) != NULL) {
dbg("last rule to be applied"); dbg("last rule to be applied");
rule.last_rule = 1; rule.last_rule = 1;
} }
if (strstr(temp3, OPTION_IGNORE_DEVICE) != NULL) { if (strstr(value, OPTION_IGNORE_DEVICE) != NULL) {
dbg("device should be ignored"); dbg("device should be ignored");
rule.ignore_device = 1; rule.ignore_device = 1;
} }
if (strstr(temp3, OPTION_IGNORE_REMOVE) != NULL) { if (strstr(value, OPTION_IGNORE_REMOVE) != NULL) {
dbg("remove event should be ignored"); dbg("remove event should be ignored");
rule.ignore_remove = 1; rule.ignore_remove = 1;
} }
if (strstr(temp3, OPTION_PARTITIONS) != NULL) { if (strstr(value, OPTION_PARTITIONS) != NULL) {
dbg("creation of partition nodes requested"); dbg("creation of partition nodes requested");
rule.partitions = DEFAULT_PARTITIONS_COUNT; rule.partitions = DEFAULT_PARTITIONS_COUNT;
} }
@ -303,7 +396,7 @@ static int rules_parse(struct udevice *udev, const char *filename)
continue; continue;
} }
dbg("unknown type of field '%s'", temp2); dbg("unknown key '%s'", key);
goto error; goto error;
} }
@ -314,13 +407,13 @@ static int rules_parse(struct udevice *udev, const char *filename)
/* simple plausibility checks for given keys */ /* simple plausibility checks for given keys */
if ((rule.sysfs_pair[0].file[0] == '\0') ^ if ((rule.sysfs_pair[0].file[0] == '\0') ^
(rule.sysfs_pair[0].value[0] == '\0')) { (rule.sysfs_pair[0].value[0] == '\0')) {
info("inconsistency in " FIELD_SYSFS " key"); info("inconsistency in " KEY_SYSFS " key");
goto error; goto error;
} }
if ((rule.result[0] != '\0') && (program_given == 0)) { if ((rule.result[0] != '\0') && (program_given == 0)) {
info(FIELD_RESULT " is only useful when " info(KEY_RESULT " is only useful when "
FIELD_PROGRAM " is called in any rule before"); KEY_PROGRAM " is called in any rule before");
goto error; goto error;
} }
@ -332,7 +425,7 @@ static int rules_parse(struct udevice *udev, const char *filename)
continue; continue;
error: error:
info("parse error %s, line %d:%d, rule skipped", info("parse error %s, line %d:%d, rule skipped",
filename, lineno, (int) (temp - line)); filename, lineno, (int) (linepos - line));
} }
} }

View File

@ -177,41 +177,6 @@ int unlink_secure(const char *filename)
return retval; return retval;
} }
int parse_get_pair(char **orig_string, char **left, char **right)
{
char *temp;
char *string = *orig_string;
if (!string)
return -ENODEV;
/* eat any whitespace */
while (isspace(*string) || *string == ',')
++string;
/* split based on '=' */
temp = strsep(&string, "=");
*left = temp;
if (!string)
return -ENODEV;
/* take the right side and strip off the '"' */
while (isspace(string[0]))
++string;
if (string[0] == '"')
++string;
else
return -ENODEV;
temp = strsep(&string, "\"");
if (!string || temp[0] == '\0')
return -ENODEV;
*right = temp;
*orig_string = string;
return 0;
}
int file_map(const char *filename, char **buf, size_t *bufsize) int file_map(const char *filename, char **buf, size_t *bufsize)
{ {
struct stat stats; struct stat stats;