[PATCH] don't rely on field order in namedev_parse

o change the parsing to get a key from the rule and sort it
    into our list of known keys instead of expecting a special order
  o the key to match a sysfs file must be prependend by 'SYSFS_' now
    to match with the new parsing.
    (The config must be changed, but it's a bit more descriptive too.)
  o put names of fields in define's, like the name of the methods
  o update all tests and the man page
This commit is contained in:
kay.sievers@vrfy.org 2003-12-16 23:36:19 -08:00 committed by Greg KH
parent 600ee7f73e
commit d94df23242
6 changed files with 145 additions and 193 deletions

View File

@ -49,6 +49,16 @@ enum config_type {
#define TYPE_TOPOLOGY "TOPOLOGY"
#define TYPE_REPLACE "REPLACE"
#define TYPE_CALLOUT "CALLOUT"
#define FIELD_BUS "BUS"
#define FIELD_ID "ID"
#define FIELD_SYSFS "SYSFS_"
#define FIELD_PLACE "PLACE"
#define FIELD_PROGRAM "PROGRAM"
#define FIELD_KERNEL "KERNEL"
#define FIELD_NAME "NAME"
#define FIELD_SYMLINK "SYMLINK"
#define CALLOUT_MAXARG 8
struct config_device {

View File

@ -45,7 +45,7 @@ int get_pair(char **orig_string, char **left, char **right)
return -ENODEV;
/* eat any whitespace */
while (isspace(*string))
while (isspace(*string) || *string == ',')
++string;
/* split based on '=' */
@ -71,19 +71,6 @@ int get_pair(char **orig_string, char **left, char **right)
return 0;
}
static int get_value(const char *left, char **orig_string, char **ret_string)
{
int retval;
char *left_string;
retval = get_pair(orig_string, &left_string, ret_string);
if (retval)
return retval;
if (strcasecmp(left_string, left) != 0)
return -ENODEV;
return 0;
}
void dump_config_dev(struct config_device *dev)
{
switch (dev->type) {
@ -169,13 +156,8 @@ int namedev_init_rules(void)
if (temp == NULL)
goto exit;
lineno++;
dbg_parse("read '%s'", temp);
/* eat the whitespace at the beginning of the line */
while (isspace(*temp))
++temp;
/* empty line? */
if (*temp == 0x00)
continue;
@ -184,199 +166,160 @@ int namedev_init_rules(void)
if (*temp == COMMENT_CHARACTER)
continue;
/* eat the whitespace */
while (isspace(*temp))
++temp;
memset(&dev, 0x00, sizeof(struct config_device));
/* parse the line */
/* get the method */
temp2 = strsep(&temp, ",");
if (strcasecmp(temp2, TYPE_LABEL) == 0) {
/* label type */
dev.type = LABEL;
goto keys;
}
/* BUS="bus" */
retval = get_value("BUS", &temp, &temp3);
if (retval)
break;
strfieldcpy(dev.bus, temp3);
if (strcasecmp(temp2, TYPE_NUMBER) == 0) {
dev.type = NUMBER;
goto keys;
}
/* file="value" */
temp2 = strsep(&temp, ",");
if (strcasecmp(temp2, TYPE_TOPOLOGY) == 0) {
dev.type = TOPOLOGY;
goto keys;
}
if (strcasecmp(temp2, TYPE_REPLACE) == 0) {
dev.type = REPLACE;
goto keys;
}
if (strcasecmp(temp2, TYPE_CALLOUT) == 0) {
dev.type = CALLOUT;
goto keys;
}
dbg_parse("unknown type of method '%s'", temp2);
goto error;
keys:
/* get all known keys */
while (1) {
retval = get_pair(&temp, &temp2, &temp3);
if (retval)
break;
strfieldcpy(dev.sysfs_file, temp2);
strfieldcpy(dev.sysfs_value, temp3);
/* NAME="new_name" */
temp2 = strsep(&temp, ",");
retval = get_value("NAME", &temp, &temp3);
if (retval)
break;
strfieldcpy(dev.name, temp3);
if (strcasecmp(temp2, FIELD_BUS) == 0) {
strfieldcpy(dev.bus, temp3);
continue;
}
/* SYMLINK="name" */
temp2 = strsep(&temp, ",");
retval = get_value("SYMLINK", &temp, &temp3);
if (retval == 0)
if (strcasecmp(temp2, FIELD_ID) == 0) {
strfieldcpy(dev.id, temp3);
continue;
}
if (strcasecmp(temp2, FIELD_PLACE) == 0) {
strfieldcpy(dev.place, temp3);
continue;
}
if (strncasecmp(temp2, FIELD_SYSFS, sizeof(FIELD_SYSFS)-1) == 0) {
/* remove prepended 'SYSFS_' */
strfieldcpy(dev.sysfs_file, temp2 + sizeof(FIELD_SYSFS)-1);
strfieldcpy(dev.sysfs_value, temp3);
continue;
}
if (strcasecmp(temp2, FIELD_KERNEL) == 0) {
strfieldcpy(dev.kernel_name, temp3);
continue;
}
if (strcasecmp(temp2, FIELD_PROGRAM) == 0) {
strfieldcpy(dev.exec_program, temp3);
continue;
}
if (strcasecmp(temp2, FIELD_NAME) == 0) {
strfieldcpy(dev.name, temp3);
continue;
}
if (strcasecmp(temp2, FIELD_SYMLINK) == 0) {
strfieldcpy(dev.symlink, temp3);
continue;
}
dbg_parse("unknown type of field '%s'", temp2);
}
/* check presence of keys according to method type */
switch (dev.type) {
case LABEL:
dbg_parse("LABEL name='%s', bus='%s', "
"sysfs_file='%s', sysfs_value='%s', symlink='%s'",
dev.name, dev.bus, dev.sysfs_file,
dev.sysfs_value, dev.symlink);
}
if (strcasecmp(temp2, TYPE_NUMBER) == 0) {
/* number type */
dev.type = NUMBER;
/* BUS="bus" */
retval = get_value("BUS", &temp, &temp3);
if (retval)
break;
strfieldcpy(dev.bus, temp3);
/* ID="id" */
temp2 = strsep(&temp, ",");
retval = get_value("ID", &temp, &temp3);
if (retval)
break;
strfieldcpy(dev.id, temp3);
/* NAME="new_name" */
temp2 = strsep(&temp, ",");
retval = get_value("NAME", &temp, &temp3);
if (retval)
break;
strfieldcpy(dev.name, temp3);
/* SYMLINK="name" */
temp2 = strsep(&temp, ",");
retval = get_value("SYMLINK", &temp, &temp3);
if (retval == 0)
strfieldcpy(dev.symlink, temp3);
if ((*dev.name == '\0') ||
(*dev.bus == '\0') ||
(*dev.sysfs_file == '\0') ||
(*dev.sysfs_value == '\0'))
goto error;
break;
case NUMBER:
dbg_parse("NUMBER name='%s', bus='%s', id='%s', symlink='%s'",
dev.name, dev.bus, dev.id, dev.symlink);
}
if (strcasecmp(temp2, TYPE_TOPOLOGY) == 0) {
/* number type */
dev.type = TOPOLOGY;
/* BUS="bus" */
retval = get_value("BUS", &temp, &temp3);
if (retval)
break;
strfieldcpy(dev.bus, temp3);
/* PLACE="place" */
temp2 = strsep(&temp, ",");
retval = get_value("PLACE", &temp, &temp3);
if (retval)
break;
strfieldcpy(dev.place, temp3);
/* NAME="new_name" */
temp2 = strsep(&temp, ",");
retval = get_value("NAME", &temp, &temp3);
if (retval)
break;
strfieldcpy(dev.name, temp3);
/* SYMLINK="name" */
temp2 = strsep(&temp, ",");
retval = get_value("SYMLINK", &temp, &temp3);
if (retval == 0)
strfieldcpy(dev.symlink, temp3);
if ((*dev.name == '\0') ||
(*dev.bus == '\0') ||
(*dev.id == '\0'))
goto error;
break;
case TOPOLOGY:
dbg_parse("TOPOLOGY name='%s', bus='%s', "
"place='%s', symlink='%s'",
dev.name, dev.bus, dev.place, dev.symlink);
}
if (strcasecmp(temp2, TYPE_REPLACE) == 0) {
/* number type */
dev.type = REPLACE;
/* KERNEL="kernel_name" */
retval = get_value("KERNEL", &temp, &temp3);
if (retval)
break;
strfieldcpy(dev.kernel_name, temp3);
/* NAME="new_name" */
temp2 = strsep(&temp, ",");
retval = get_value("NAME", &temp, &temp3);
if (retval)
break;
strfieldcpy(dev.name, temp3);
/* SYMLINK="name" */
temp2 = strsep(&temp, ",");
retval = get_value("SYMLINK", &temp, &temp3);
if (retval == 0)
strfieldcpy(dev.symlink, temp3);
if ((*dev.name == '\0') ||
(*dev.bus == '\0') ||
(*dev.place == '\0'))
goto error;
break;
case REPLACE:
dbg_parse("REPLACE name='%s', kernel_name='%s', symlink='%s'",
dev.name, dev.kernel_name, dev.symlink);
}
if (strcasecmp(temp2, TYPE_CALLOUT) == 0) {
/* number type */
dev.type = CALLOUT;
/* BUS="bus" */
retval = get_value("BUS", &temp, &temp3);
if (retval)
break;
strfieldcpy(dev.bus, temp3);
/* PROGRAM="executable" */
temp2 = strsep(&temp, ",");
retval = get_value("PROGRAM", &temp, &temp3);
if (retval)
break;
strfieldcpy(dev.exec_program, temp3);
/* ID="id" */
temp2 = strsep(&temp, ",");
retval = get_value("ID", &temp, &temp3);
if (retval)
break;
strfieldcpy(dev.id, temp3);
/* NAME="new_name" */
temp2 = strsep(&temp, ",");
retval = get_value("NAME", &temp, &temp3);
if (retval)
break;
strfieldcpy(dev.name, temp3);
/* SYMLINK="name" */
temp2 = strsep(&temp, ",");
retval = get_value("SYMLINK", &temp, &temp3);
if (retval == 0)
strfieldcpy(dev.symlink, temp3);
if ((*dev.name == '\0') ||
(*dev.kernel_name == '\0'))
goto error;
break;
case CALLOUT:
dbg_parse("CALLOUT name='%s', bus='%s', program='%s', "
"id='%s', symlink='%s'",
dev.name, dev.bus, dev.exec_program,
dev.id, dev.symlink);
if ((*dev.name == '\0') ||
(*dev.bus == '\0') ||
(*dev.id == '\0') ||
(*dev.exec_program == '\0'))
goto error;
break;
default:
dbg_parse("xxx default method");
goto error;
}
retval = add_config_dev(&dev);
if (retval) {
dbg("add_config_dev returned with error %d", retval);
goto exit;
continue;
}
}
dbg_parse("%s:%d:%Zd: error parsing '%s'", udev_rules_filename,
lineno, temp - line, temp);
error:
dbg_parse("%s:%d:%Zd: field missing or parse error", udev_rules_filename,
lineno, temp - line);
exit:
fclose(fd);
return retval;
}
}
int namedev_init_permissions(void)
{

View File

@ -8,7 +8,7 @@ export SYSFS_PATH=$PWD/sys/
export UDEV_CONFIG_FILE=$PWD/$CONFIG
cat > $RULES << EOF
LABEL, BUS="scsi", vendor="IBM-ESXS", NAME="boot_disk%n"
LABEL, BUS="scsi", SYSFS_vendor="IBM-ESXS", NAME="boot_disk%n"
EOF
cat > $CONFIG << EOF

View File

@ -38,7 +38,7 @@ my @tests = (
devpath => "block/sda",
expected => "boot_disk" ,
conf => <<EOF
LABEL, BUS="scsi", vendor="IBM-ESXS", NAME="boot_disk%n"
LABEL, BUS="scsi", SYSFS_vendor="IBM-ESXS", NAME="boot_disk%n"
REPLACE, KERNEL="ttyUSB0", NAME="visor"
EOF
},
@ -48,7 +48,7 @@ EOF
devpath => "block/sda/sda1",
expected => "boot_disk1" ,
conf => <<EOF
LABEL, BUS="scsi", vendor="IBM-ESXS", NAME="boot_disk%n"
LABEL, BUS="scsi", SYSFS_vendor="IBM-ESXS", NAME="boot_disk%n"
EOF
},
{
@ -57,10 +57,10 @@ EOF
devpath => "block/sda/sda1",
expected => "boot_disk1" ,
conf => <<EOF
LABEL, BUS="scsi", vendor="?IBM-ESXS", NAME="boot_disk%n-1"
LABEL, BUS="scsi", vendor="IBM-ESXS?", NAME="boot_disk%n-2"
LABEL, BUS="scsi", vendor="IBM-ES??", NAME="boot_disk%n"
LABEL, BUS="scsi", vendor="IBM-ESXSS", NAME="boot_disk%n-3"
LABEL, BUS="scsi", SYSFS_vendor="?IBM-ESXS", NAME="boot_disk%n-1"
LABEL, BUS="scsi", SYSFS_vendor="IBM-ESXS?", NAME="boot_disk%n-2"
LABEL, BUS="scsi", SYSFS_vendor="IBM-ES??", NAME="boot_disk%n"
LABEL, BUS="scsi", SYSFS_vendor="IBM-ESXSS", NAME="boot_disk%n-3"
EOF
},
{
@ -167,7 +167,7 @@ EOF
devpath => "block/sda",
expected => "lun0/disc" ,
conf => <<EOF
LABEL, BUS="scsi", vendor="IBM-ESXS", NAME="lun0/%D"
LABEL, BUS="scsi", SYSFS_vendor="IBM-ESXS", NAME="lun0/%D"
EOF
},
{
@ -176,7 +176,7 @@ EOF
devpath => "block/sda/sda2",
expected => "lun0/part2" ,
conf => <<EOF
LABEL, BUS="scsi", vendor="IBM-ESXS", NAME="lun0/%D"
LABEL, BUS="scsi", SYSFS_vendor="IBM-ESXS", NAME="lun0/%D"
EOF
},
{
@ -205,7 +205,7 @@ EOF
devpath => "block/sda/sda2",
expected => "1/2/a/b/symlink" ,
conf => <<EOF
LABEL, BUS="scsi", vendor="IBM-ESXS", NAME="1/2/node", SYMLINK="1/2/a/b/symlink"
LABEL, BUS="scsi", SYSFS_vendor="IBM-ESXS", NAME="1/2/node", SYMLINK="1/2/a/b/symlink"
EOF
},
{
@ -214,7 +214,7 @@ EOF
devpath => "block/sda/sda2",
expected => "1/2/symlink" ,
conf => <<EOF
LABEL, BUS="scsi", vendor="IBM-ESXS", NAME="1/2/a/b/node", SYMLINK="1/2/symlink"
LABEL, BUS="scsi", SYSFS_vendor="IBM-ESXS", NAME="1/2/a/b/node", SYMLINK="1/2/symlink"
EOF
},
{
@ -223,7 +223,7 @@ EOF
devpath => "block/sda/sda2",
expected => "1/2/c/d/symlink" ,
conf => <<EOF
LABEL, BUS="scsi", vendor="IBM-ESXS", NAME="1/2/a/b/node", SYMLINK="1/2/c/d/symlink"
LABEL, BUS="scsi", SYSFS_vendor="IBM-ESXS", NAME="1/2/a/b/node", SYMLINK="1/2/c/d/symlink"
EOF
},
{

11
udev.8
View File

@ -18,7 +18,7 @@ On device creation,
.B udev
reads the sysfs directory of the given device to collect device attributes
like label, serial number or bus device number.
These attributes are treated as a key
These attributes are treated as a key
to determine a unique name for device file creation.
.B udev
maintains a database for devices present on the system.
@ -87,7 +87,7 @@ The rules for udev to use when naming devices may specified at
.I /etc/udev/udev.rules
or specified by the
.I udev_rules
value in the
value in the
.I /etc/udev/udev.conf
file.
.P
@ -114,8 +114,7 @@ calling external program, that returns a string to match
device label or serial number, like USB serial number, SCSI UUID or
file system label
.br
.RB "keys: " BUS ", "
.I sysfs_attribute
.RB "keys: " BUS ", " SYSFS_
.TP
.B NUMBER
device number on the bus, like PCI bus id
@ -130,7 +129,7 @@ device position on bus, like physical port of USB device
.B REPLACE
string replacement of the kernel device name
.br
.RB "key: " KERNEL_NAME
.RB "key: " KERNEL
.P
The methods are applied in the following order:
.BR CALLOUT ", " LABEL ", " NUMBER ", " TOPOLOGY ", " REPLACE "."
@ -167,7 +166,7 @@ If this is not a partition, it will result in 'disc'.
CALLOUT, BUS="scsi", PROGRAM="/sbin/scsi_id", ID="OEM 0815", NAME="disk1"
# USB printer to be called lp_color
LABEL, BUS="usb", serial="W09090207101241330", NAME="lp_color"
LABEL, BUS="usb", SYSFS_serial="W09090207101241330", NAME="lp_color"
# sound card with PCI bus id 00:0b.0 to be called dsp
NUMBER, BUS="pci", ID="00:0b.0", NAME="dsp"

View File

@ -1,8 +1,8 @@
# USB camera from Fuji to be named "camera"
LABEL, BUS="usb", vendor="FUJIFILM", NAME="camera%n"
LABEL, BUS="usb", SYSFS_vendor="FUJIFILM", NAME="camera%n"
# USB device plugged into the fourth port of the second hub to be called gps_device
TOPOLOGY, BUS="usb", place="2.4", NAME="gps_device"
TOPOLOGY, BUS="usb", PLACE="2.4", NAME="gps_device"
# ttyUSB1 should always be called visor
REPLACE, KERNEL="ttyUSB1", NAME="visor"