[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:
committed by
Greg KH
parent
e68582be4a
commit
a27cd06c6d
@@ -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);
|
||||
|
||||
@@ -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
|
||||
},
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user