[PATCH] Adding '%s' format specifier to NAME and SYMLINK
On Thu, Feb 12, 2004 at 05:34:57PM -0800, Greg KH wrote: > On Tue, Feb 10, 2004 at 09:14:20AM +0100, Hannes Reinecke wrote: > > Hi all, > > > > this patch makes the format for NAME and SYMLINK a bit more flexible: > > I've added a new format specifier '%s{<SYSFS_var>}', which allows for > > the value of any sysfs entry found for this device to be inserted. > > Example (for our S/390 fcp adapter): > > > > BUS="ccw", SYSFS_devtype="1732/03", NAME="%k" \ > > SYMLINK="zfcp-%s{hba_id}-%s{wwpn}:%s{fcp_lun}" > > > > I know this could also be done with an external program, but having this > > incorporated into udev makes life easier, especially if run from > > initramfs. Plus it makes the rules easier to follow, as the result is > > directly visible and need not to be looked up in some external program. > > > > Comments etc. welcome. > > Oops, sorry I missed this for the 017 release. I'll look at it tomorrow > and get back to you. At first glance it looks like a good thing. > > Oh, you forgot to update the documentation, that's important to do if > you want this change to make it in :) I took a part of the code and made a version that uses already implemented attribute finding logic. The parsing of the format length '%3x' and the '%x{attribute}' is a fuction now, maybe there are more possible users in the future. I've also added the test to udev-test.pl.
This commit is contained in:
parent
e68582be4a
commit
a27cd06c6d
250
namedev.c
250
namedev.c
|
@ -41,6 +41,8 @@
|
||||||
#include "libsysfs/libsysfs.h"
|
#include "libsysfs/libsysfs.h"
|
||||||
#include "klibc_fixups.h"
|
#include "klibc_fixups.h"
|
||||||
|
|
||||||
|
static struct sysfs_attribute *find_sysfs_attribute(struct sysfs_class_device *class_dev, struct sysfs_device *sysfs_device, char *attr);
|
||||||
|
|
||||||
LIST_HEAD(config_device_list);
|
LIST_HEAD(config_device_list);
|
||||||
LIST_HEAD(perm_device_list);
|
LIST_HEAD(perm_device_list);
|
||||||
|
|
||||||
|
@ -168,7 +170,46 @@ static char *get_default_group(void)
|
||||||
return default_group_str;
|
return default_group_str;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void apply_format(struct udevice *udev, unsigned char *string)
|
/* extract possible {attr} and move str behind it */
|
||||||
|
static char *get_format_attribute(char **str)
|
||||||
|
{
|
||||||
|
char *pos;
|
||||||
|
char *attr = NULL;
|
||||||
|
|
||||||
|
if (*str[0] == '{') {
|
||||||
|
pos = strchr(*str, '}');
|
||||||
|
if (pos == NULL) {
|
||||||
|
dbg("missing closing brace for format");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
pos[0] = '\0';
|
||||||
|
attr = *str+1;
|
||||||
|
*str = pos+1;
|
||||||
|
dbg("attribute='%s', str='%s'", attr, *str);
|
||||||
|
}
|
||||||
|
return attr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* extract possible format length and move str behind it*/
|
||||||
|
static int get_format_len(char **str)
|
||||||
|
{
|
||||||
|
int num;
|
||||||
|
char *tail;
|
||||||
|
|
||||||
|
if (isdigit(*str[0])) {
|
||||||
|
num = (int) strtoul(*str, &tail, 10);
|
||||||
|
if (tail != NULL) {
|
||||||
|
*str = tail;
|
||||||
|
dbg("format length=%i", num);
|
||||||
|
return num;
|
||||||
|
} else {
|
||||||
|
dbg("format parsing error '%s'", *str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void apply_format(struct udevice *udev, unsigned char *string, struct sysfs_class_device *class_dev, struct sysfs_device *sysfs_device)
|
||||||
{
|
{
|
||||||
char temp[NAME_SIZE];
|
char temp[NAME_SIZE];
|
||||||
char temp1[NAME_SIZE];
|
char temp1[NAME_SIZE];
|
||||||
|
@ -176,87 +217,100 @@ static void apply_format(struct udevice *udev, unsigned char *string)
|
||||||
char *pos;
|
char *pos;
|
||||||
char *pos2;
|
char *pos2;
|
||||||
char *pos3;
|
char *pos3;
|
||||||
|
char *attr;
|
||||||
int num;
|
int num;
|
||||||
|
char c;
|
||||||
|
struct sysfs_attribute *tmpattr;
|
||||||
|
|
||||||
pos = string;
|
pos = string;
|
||||||
while (1) {
|
|
||||||
num = 0;
|
|
||||||
pos = strchr(pos, '%');
|
|
||||||
|
|
||||||
if (pos) {
|
while (1) {
|
||||||
|
pos = strchr(pos, '%');
|
||||||
|
if (pos != NULL) {
|
||||||
pos[0] = '\0';
|
pos[0] = '\0';
|
||||||
tail = pos+1;
|
tail = pos+1;
|
||||||
if (isdigit(tail[0])) {
|
num = get_format_len(&tail);
|
||||||
num = (int) strtoul(&pos[1], &tail, 10);
|
c = tail[0];
|
||||||
if (tail == NULL) {
|
|
||||||
dbg("format parsing error '%s'", pos+1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
strfieldcpy(temp, tail+1);
|
strfieldcpy(temp, tail+1);
|
||||||
|
tail = temp;
|
||||||
switch (tail[0]) {
|
} else {
|
||||||
case 'b':
|
|
||||||
if (strlen(udev->bus_id) == 0)
|
|
||||||
break;
|
|
||||||
strcat(pos, udev->bus_id);
|
|
||||||
dbg("substitute bus_id '%s'", udev->bus_id);
|
|
||||||
break;
|
|
||||||
case 'k':
|
|
||||||
if (strlen(udev->kernel_name) == 0)
|
|
||||||
break;
|
|
||||||
strcat(pos, udev->kernel_name);
|
|
||||||
dbg("substitute kernel name '%s'", udev->kernel_name);
|
|
||||||
break;
|
|
||||||
case 'n':
|
|
||||||
if (strlen(udev->kernel_number) == 0)
|
|
||||||
break;
|
|
||||||
strcat(pos, udev->kernel_number);
|
|
||||||
dbg("substitute kernel number '%s'", udev->kernel_number);
|
|
||||||
break;
|
|
||||||
case 'm':
|
|
||||||
sprintf(pos, "%u", udev->minor);
|
|
||||||
dbg("substitute minor number '%u'", udev->minor);
|
|
||||||
break;
|
|
||||||
case 'M':
|
|
||||||
sprintf(pos, "%u", udev->major);
|
|
||||||
dbg("substitute major number '%u'", udev->major);
|
|
||||||
break;
|
|
||||||
case 'c':
|
|
||||||
if (strlen(udev->program_result) == 0)
|
|
||||||
break;
|
|
||||||
if (num) {
|
|
||||||
/* get part of return string */
|
|
||||||
strncpy(temp1, udev->program_result, sizeof(temp1));
|
|
||||||
pos2 = temp1;
|
|
||||||
while (num) {
|
|
||||||
num--;
|
|
||||||
pos3 = strsep(&pos2, " ");
|
|
||||||
if (pos3 == NULL) {
|
|
||||||
dbg("requested part of result string not found");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (pos3) {
|
|
||||||
strcat(pos, pos3);
|
|
||||||
dbg("substitute part of result string '%s'", pos3);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
strcat(pos, udev->program_result);
|
|
||||||
dbg("substitute result string '%s'", udev->program_result);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case '%':
|
|
||||||
strcat(pos, "%");
|
|
||||||
pos++;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
dbg("unknown substitution type '%%%c'", pos[1]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
strcat(string, temp);
|
|
||||||
} else
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
dbg("format=%c, string='%s', tail='%s'",c , string, tail);
|
||||||
|
|
||||||
|
attr = get_format_attribute(&tail);
|
||||||
|
|
||||||
|
switch (c) {
|
||||||
|
case 'b':
|
||||||
|
if (strlen(udev->bus_id) == 0)
|
||||||
|
break;
|
||||||
|
strcat(pos, udev->bus_id);
|
||||||
|
dbg("substitute bus_id '%s'", udev->bus_id);
|
||||||
|
break;
|
||||||
|
case 'k':
|
||||||
|
if (strlen(udev->kernel_name) == 0)
|
||||||
|
break;
|
||||||
|
strcat(pos, udev->kernel_name);
|
||||||
|
dbg("substitute kernel name '%s'", udev->kernel_name);
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
if (strlen(udev->kernel_number) == 0)
|
||||||
|
break;
|
||||||
|
strcat(pos, udev->kernel_number);
|
||||||
|
dbg("substitute kernel number '%s'", udev->kernel_number);
|
||||||
|
break;
|
||||||
|
case 'm':
|
||||||
|
sprintf(pos, "%u", udev->minor);
|
||||||
|
dbg("substitute minor number '%u'", udev->minor);
|
||||||
|
break;
|
||||||
|
case 'M':
|
||||||
|
sprintf(pos, "%u", udev->major);
|
||||||
|
dbg("substitute major number '%u'", udev->major);
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
if (strlen(udev->program_result) == 0)
|
||||||
|
break;
|
||||||
|
if (num > 0) {
|
||||||
|
strncpy(temp1, udev->program_result, sizeof(temp1));
|
||||||
|
pos2 = temp1;
|
||||||
|
while (num) {
|
||||||
|
num--;
|
||||||
|
pos3 = strsep(&pos2, " ");
|
||||||
|
if (pos3 == NULL) {
|
||||||
|
dbg("requested part of result string not found");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pos3) {
|
||||||
|
strcat(pos, pos3);
|
||||||
|
dbg("substitute part of result string '%s'", pos3);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
strcat(pos, udev->program_result);
|
||||||
|
dbg("substitute result string '%s'", udev->program_result);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
if (attr != NULL) {
|
||||||
|
tmpattr = find_sysfs_attribute(class_dev, sysfs_device, attr);
|
||||||
|
if (tmpattr == NULL) {
|
||||||
|
dbg("sysfa attribute '%s' not found", attr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
strcpy(pos, tmpattr->value);
|
||||||
|
dbg("substitute sysfs value '%s'", tmpattr->value);
|
||||||
|
} else {
|
||||||
|
dbg("missing attribute");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '%':
|
||||||
|
strcat(pos, "%");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
dbg("unknown substitution type '%%%c'", c);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
strcat(pos, tail);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -422,32 +476,46 @@ static int execute_program(char *path, char *value, int len)
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int compare_sysfs_attribute(struct sysfs_class_device *class_dev, struct sysfs_device *sysfs_device, struct sysfs_pair *pair)
|
static struct sysfs_attribute *find_sysfs_attribute(struct sysfs_class_device *class_dev, struct sysfs_device *sysfs_device, char *attr)
|
||||||
{
|
{
|
||||||
struct sysfs_attribute *tmpattr = NULL;
|
struct sysfs_attribute *tmpattr = NULL;
|
||||||
char *c;
|
char *c;
|
||||||
|
|
||||||
if ((pair == NULL) || (pair->file[0] == '\0') || (pair->value == '\0'))
|
dbg("look for device attribute '%s'", attr);
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
dbg("look for device attribute '%s'", pair->file);
|
|
||||||
/* try to find the attribute in the class device directory */
|
/* try to find the attribute in the class device directory */
|
||||||
tmpattr = sysfs_get_classdev_attr(class_dev, pair->file);
|
tmpattr = sysfs_get_classdev_attr(class_dev, attr);
|
||||||
if (tmpattr)
|
if (tmpattr)
|
||||||
goto label_found;
|
goto attr_found;
|
||||||
|
|
||||||
/* look in the class device directory if present */
|
/* look in the class device directory if present */
|
||||||
if (sysfs_device) {
|
if (sysfs_device) {
|
||||||
tmpattr = sysfs_get_device_attr(sysfs_device, pair->file);
|
tmpattr = sysfs_get_device_attr(sysfs_device, attr);
|
||||||
if (tmpattr)
|
if (tmpattr)
|
||||||
goto label_found;
|
goto attr_found;
|
||||||
}
|
}
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
label_found:
|
return NULL;
|
||||||
c = tmpattr->value + strlen(tmpattr->value)-1;
|
|
||||||
if (*c == '\n')
|
attr_found:
|
||||||
*c = 0x00;
|
c = strchr(tmpattr->value, '\n');
|
||||||
|
if (c != NULL)
|
||||||
|
c[0] = '\0';
|
||||||
|
|
||||||
|
dbg("found attribute '%s'", tmpattr->path);
|
||||||
|
return tmpattr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int compare_sysfs_attribute(struct sysfs_class_device *class_dev, struct sysfs_device *sysfs_device, struct sysfs_pair *pair)
|
||||||
|
{
|
||||||
|
struct sysfs_attribute *tmpattr;
|
||||||
|
|
||||||
|
if ((pair == NULL) || (pair->file[0] == '\0') || (pair->value == '\0'))
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
tmpattr = find_sysfs_attribute(class_dev, sysfs_device, pair->file);
|
||||||
|
if (tmpattr == NULL)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
dbg("compare attribute '%s' value '%s' with '%s'",
|
dbg("compare attribute '%s' value '%s' with '%s'",
|
||||||
pair->file, tmpattr->value, pair->value);
|
pair->file, tmpattr->value, pair->value);
|
||||||
if (strcmp_pattern(pair->value, tmpattr->value) != 0)
|
if (strcmp_pattern(pair->value, tmpattr->value) != 0)
|
||||||
|
@ -658,7 +726,7 @@ static int match_rule(struct config_device *dev, struct sysfs_class_device *clas
|
||||||
/* execute external program */
|
/* execute external program */
|
||||||
if (dev->program[0] != '\0') {
|
if (dev->program[0] != '\0') {
|
||||||
dbg("check " FIELD_PROGRAM);
|
dbg("check " FIELD_PROGRAM);
|
||||||
apply_format(udev, dev->program);
|
apply_format(udev, dev->program, class_dev, sysfs_device);
|
||||||
if (execute_program(dev->program, udev->program_result, NAME_SIZE) != 0) {
|
if (execute_program(dev->program, udev->program_result, NAME_SIZE) != 0) {
|
||||||
dbg(FIELD_PROGRAM " returned nozero");
|
dbg(FIELD_PROGRAM " returned nozero");
|
||||||
goto try_parent;
|
goto try_parent;
|
||||||
|
@ -750,8 +818,8 @@ int namedev_name_device(struct sysfs_class_device *class_dev, struct udevice *ud
|
||||||
|
|
||||||
found:
|
found:
|
||||||
/* substitute placeholder */
|
/* substitute placeholder */
|
||||||
apply_format(udev, udev->name);
|
apply_format(udev, udev->name, class_dev, sysfs_device);
|
||||||
apply_format(udev, udev->symlink);
|
apply_format(udev, udev->symlink, class_dev, sysfs_device);
|
||||||
|
|
||||||
done:
|
done:
|
||||||
perm = find_perm(udev->name);
|
perm = find_perm(udev->name);
|
||||||
|
|
|
@ -191,6 +191,16 @@ EOF
|
||||||
expected => "Major:8:minor:3:kernelnumber:3:bus:0:0:0:0" ,
|
expected => "Major:8:minor:3:kernelnumber:3:bus:0:0:0:0" ,
|
||||||
conf => <<EOF
|
conf => <<EOF
|
||||||
BUS="scsi", PLACE="0:0:0:0", NAME="Major:%M:minor:%m:kernelnumber:%n:bus:%b"
|
BUS="scsi", PLACE="0:0:0:0", NAME="Major:%M:minor:%m:kernelnumber:%n:bus:%b"
|
||||||
|
EOF
|
||||||
|
},
|
||||||
|
{
|
||||||
|
desc => "sustitution of sysfs value (%s{file})",
|
||||||
|
subsys => "block",
|
||||||
|
devpath => "block/sda",
|
||||||
|
expected => "disk-IBM-ESXS-sda" ,
|
||||||
|
conf => <<EOF
|
||||||
|
BUS="scsi", SYSFS_vendor="IBM-ESXS", NAME="disk-%s{vendor}-%k"
|
||||||
|
KERNEL="ttyUSB0", NAME="visor"
|
||||||
EOF
|
EOF
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue