[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:
kay.sievers@vrfy.org 2004-02-16 21:36:34 -08:00 committed by Greg KH
parent e68582be4a
commit a27cd06c6d
2 changed files with 169 additions and 91 deletions

250
namedev.c
View File

@ -41,6 +41,8 @@
#include "libsysfs/libsysfs.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(perm_device_list);
@ -168,7 +170,46 @@ static char *get_default_group(void)
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 temp1[NAME_SIZE];
@ -176,87 +217,100 @@ static void apply_format(struct udevice *udev, unsigned char *string)
char *pos;
char *pos2;
char *pos3;
char *attr;
int num;
char c;
struct sysfs_attribute *tmpattr;
pos = string;
while (1) {
num = 0;
pos = strchr(pos, '%');
if (pos) {
while (1) {
pos = strchr(pos, '%');
if (pos != NULL) {
pos[0] = '\0';
tail = pos+1;
if (isdigit(tail[0])) {
num = (int) strtoul(&pos[1], &tail, 10);
if (tail == NULL) {
dbg("format parsing error '%s'", pos+1);
break;
}
}
num = get_format_len(&tail);
c = tail[0];
strfieldcpy(temp, tail+1);
switch (tail[0]) {
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
tail = temp;
} else {
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;
}
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;
char *c;
if ((pair == NULL) || (pair->file[0] == '\0') || (pair->value == '\0'))
return -ENODEV;
dbg("look for device attribute '%s'", pair->file);
dbg("look for device attribute '%s'", attr);
/* 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)
goto label_found;
goto attr_found;
/* look in the class device directory if present */
if (sysfs_device) {
tmpattr = sysfs_get_device_attr(sysfs_device, pair->file);
tmpattr = sysfs_get_device_attr(sysfs_device, attr);
if (tmpattr)
goto label_found;
goto attr_found;
}
return -ENODEV;
label_found:
c = tmpattr->value + strlen(tmpattr->value)-1;
if (*c == '\n')
*c = 0x00;
return NULL;
attr_found:
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'",
pair->file, tmpattr->value, pair->value);
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 */
if (dev->program[0] != '\0') {
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) {
dbg(FIELD_PROGRAM " returned nozero");
goto try_parent;
@ -750,8 +818,8 @@ int namedev_name_device(struct sysfs_class_device *class_dev, struct udevice *ud
found:
/* substitute placeholder */
apply_format(udev, udev->name);
apply_format(udev, udev->symlink);
apply_format(udev, udev->name, class_dev, sysfs_device);
apply_format(udev, udev->symlink, class_dev, sysfs_device);
done:
perm = find_perm(udev->name);

View File

@ -191,6 +191,16 @@ EOF
expected => "Major:8:minor:3:kernelnumber:3:bus:0:0:0:0" ,
conf => <<EOF
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
},
{