exp_name => "M8-m3-n3-b0:0-sIBM" ,
conf => <<EOF
BUS=="scsi", ID=="0:0:0:0", NAME="M%M-m%m-n%n-b%3b-s%3s{vendor}"
-EOF
- },
- {
- desc => "old style SYSFS_ attribute",
- subsys => "block",
- devpath => "/block/sda",
- exp_name => "good" ,
- conf => <<EOF
-BUS=="scsi", SYSFS_vendor=="IBM-ESXS", NAME="good"
EOF
},
{
conf => <<EOF
KERNEL == "sda1" , NAME = "true"
BUS=="scsi", KERNEL=="sda1", NAME="wrong"
+EOF
+ },
+ {
+ desc => "ENV{} test",
+ subsys => "block",
+ devpath => "/block/sda/sda1",
+ exp_name => "true",
+ conf => <<EOF
+BUS=="scsi", KERNEL=="sda1", ENV{UDEV_TEST}=="go", NAME="wrong"
+BUS=="scsi", KERNEL=="sda1", ENV{UDEV_TEST}=="yes", NAME="true"
+BUS=="scsi", KERNEL=="sda1", ENV{UDEV_TEST}=="bad", NAME="bad"
+EOF
+ },
+ {
+ desc => "ENV{} test",
+ subsys => "block",
+ devpath => "/block/sda/sda1",
+ exp_name => "true",
+ conf => <<EOF
+BUS=="scsi", KERNEL=="sda1", ENV{UDEV_TEST}=="go", NAME="wrong"
+BUS=="scsi", KERNEL=="sda1", ENV{UDEV_TEST}=="yes", ENV{ACTION}=="add", ENV{DEVPATH}=="/block/sda/sdax1", NAME="no"
+BUS=="scsi", KERNEL=="sda1", ENV{UDEV_TEST}=="yes", ENV{ACTION}=="add", ENV{DEVPATH}=="/block/sda/sda1", NAME="true"
+BUS=="scsi", KERNEL=="sda1", ENV{UDEV_TEST}=="bad", NAME="bad"
EOF
},
);
Match the device number on the bus, like PCI bus id.
.TP
.BI SYSFS{ filename }
-Match sysfs device attribute like label, vendor, USB serial number, SCSI UUID
-or file system label. Up to 5 different sysfs files can be checked, with
-all of the values being required to match the rule.
+Match sysfs device attribute like vendor and product id's, USB serial number
+or the SCSI disk model number. Up to 5 different sysfs files can be checked,
+with all of the values being required to match the rule.
.br
Trailing whitespace characters in the sysfs attribute value are ignored, if
the key doesn't have any trailing whitespace characters by itself.
.TP
+.BI ENV{ variable }
+Match an environment variable. Up to 5 different environment variables can be
+checked, with all of the values being required to match the rule.
+.TP
.B PROGRAM
Call external program. This key is valid if the program returns successful.
The environment variables of
return 0;
}
-static int match_sysfs_pairs(struct udev_rule *rule, struct sysfs_class_device *class_dev, struct sysfs_device *sysfs_device)
-{
- int i;
-
- for (i = 0; i < rule->sysfs_pair_count; i++) {
- struct key_pair *pair;
-
- pair = &rule->sysfs_pair[i];
- if ((pair->name[0] == '\0') || (pair->value[0] == '\0'))
- break;
- if (compare_sysfs_attribute(class_dev, sysfs_device, pair) != 0) {
- dbg("sysfs pair #%u does not match", i);
- if (pair->operation != KEY_OP_NOMATCH)
- return -1;
- } else {
- dbg("sysfs pair #%u matches", i);
- if (pair->operation == KEY_OP_NOMATCH)
- return -1;
- }
- }
-
- return 0;
-}
-
static int match_id(struct udev_rule *rule, struct sysfs_device *sysfs_device)
{
char path[PATH_SIZE];
dbg(KEY_SUBSYSTEM " key is true");
}
+ if (rule->env_pair_count) {
+ int i;
+
+ dbg("check for " KEY_ENV " pairs");
+ for (i = 0; i < rule->env_pair_count; i++) {
+ struct key_pair *pair;
+ const char *value;
+
+ pair = &rule->env_pair[i];
+ value = getenv(pair->name);
+ if (!value) {
+ dbg(KEY_ENV "{'%s'} is not found", pair->name);
+ goto exit;
+ }
+ if (strcmp_pattern(pair->value, value) != 0) {
+ dbg(KEY_ENV "{'%s'} is not matching", pair->name);
+ if (pair->operation != KEY_OP_NOMATCH)
+ goto exit;
+ } else {
+ dbg(KEY_ENV "{'%s'} matches", pair->name);
+ if (pair->operation == KEY_OP_NOMATCH)
+ goto exit;
+ }
+ }
+ dbg(KEY_ENV " key is true");
+ }
+
/* walk up the chain of physical devices and find a match */
while (1) {
/* check for matching driver */
}
/* check for matching sysfs pairs */
- if (rule->sysfs_pair[0].name[0] != '\0') {
+ if (rule->sysfs_pair_count) {
+ int i;
+
dbg("check " KEY_SYSFS " pairs");
- if (match_sysfs_pairs(rule, class_dev, sysfs_device) != 0) {
- dbg(KEY_SYSFS " is not matching");
- goto try_parent;
+ for (i = 0; i < rule->sysfs_pair_count; i++) {
+ struct key_pair *pair;
+
+ pair = &rule->sysfs_pair[i];
+ if (compare_sysfs_attribute(class_dev, sysfs_device, pair) != 0) {
+ dbg(KEY_SYSFS "{'%s'} is not matching", pair->name);
+ if (pair->operation != KEY_OP_NOMATCH)
+ goto try_parent;
+ } else {
+ dbg(KEY_SYSFS "{'%s'} matches", pair->name);
+ if (pair->operation == KEY_OP_NOMATCH)
+ goto try_parent;
+ }
}
dbg(KEY_SYSFS " keys are true");
}
#define KEY_KERNEL "KERNEL"
#define KEY_SUBSYSTEM "SUBSYSTEM"
#define KEY_BUS "BUS"
-#define KEY_SYSFS "SYSFS"
#define KEY_ID "ID"
#define KEY_PROGRAM "PROGRAM"
#define KEY_RESULT "RESULT"
#define KEY_DRIVER "DRIVER"
+#define KEY_SYSFS "SYSFS"
+#define KEY_ENV "ENV"
#define KEY_NAME "NAME"
#define KEY_SYMLINK "SYMLINK"
#define KEY_OWNER "OWNER"
#define OPTION_PARTITIONS "all_partitions"
#define KEY_SYSFS_PAIRS_MAX 5
+#define KEY_ENV_PAIRS_MAX 5
#define RULEFILE_SUFFIX ".rules"
enum key_operation result_operation;
struct key_pair sysfs_pair[KEY_SYSFS_PAIRS_MAX];
int sysfs_pair_count;
+ struct key_pair env_pair[KEY_ENV_PAIRS_MAX];
+ int env_pair_count;
char name[PATH_SIZE];
char symlink[PATH_SIZE];
goto error;
}
pair = &rule.sysfs_pair[rule.sysfs_pair_count];
- rule.sysfs_pair_count++;
-
attr = get_key_attribute(key + sizeof(KEY_SYSFS)-1);
if (attr == NULL) {
dbg("error parsing " KEY_SYSFS " attribute");
+ goto error;
+ }
+ strlcpy(pair->name, attr, sizeof(pair->name));
+ strlcpy(pair->value, value, sizeof(pair->value));
+ pair->operation = operation;
+ rule.sysfs_pair_count++;
+ valid = 1;
+ continue;
+ }
+
+ if (strncasecmp(key, KEY_ENV, sizeof(KEY_ENV)-1) == 0) {
+ struct key_pair *pair;
+
+ if (rule.env_pair_count >= KEY_ENV_PAIRS_MAX) {
+ dbg("skip rule, to many " KEY_ENV " keys in a single rule");
+ goto error;
+ }
+ pair = &rule.env_pair[rule.env_pair_count];
+ attr = get_key_attribute(key + sizeof(KEY_ENV)-1);
+ if (attr == NULL) {
+ dbg("error parsing " KEY_ENV " attribute");
continue;
}
strlcpy(pair->name, attr, sizeof(pair->name));
strlcpy(pair->value, value, sizeof(pair->value));
pair->operation = operation;
+ rule.env_pair_count++;
valid = 1;
continue;
}