X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=namedev.c;h=942788b2a2a83519ec785f209eaf589d84b597a4;hb=896e5aa9aa6ea467a34b53d5053621b9cfc58548;hp=6685596479ac14102246ab40c555b51886ceb303;hpb=8a08e4b1906eef5d5cb585b125612cce8d565e5c;p=elogind.git diff --git a/namedev.c b/namedev.c index 668559647..942788b2a 100644 --- a/namedev.c +++ b/namedev.c @@ -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); @@ -112,7 +114,7 @@ int add_perm_dev(struct perm_device *new_dev) /* update the values if we already have the device */ list_for_each_entry(dev, &perm_device_list, node) { - if (strcmp_pattern(new_dev->name, dev->name)) + if (strcmp(new_dev->name, dev->name)) continue; copy_var(dev, new_dev, mode); copy_string(dev, new_dev, owner); @@ -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,96 +217,114 @@ 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) { + 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); + tail = temp; + } else { + break; + } + dbg("format=%c, string='%s', tail='%s'",c , string, tail); - 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); + attr = get_format_attribute(&tail); + + switch (c) { + case 'b': + if (strlen(udev->bus_id) == 0) break; - case 'k': - if (strlen(udev->kernel_name) == 0) - break; - strcat(pos, udev->kernel_name); - dbg("substitute kernel name '%s'", udev->kernel_name); + strcat(pos, udev->bus_id); + dbg("substitute bus_id '%s'", udev->bus_id); + break; + case 'k': + if (strlen(udev->kernel_name) == 0) break; - case 'n': - if (strlen(udev->kernel_number) == 0) - break; - strcat(pos, udev->kernel_number); - dbg("substitute kernel number '%s'", udev->kernel_number); + strcat(pos, udev->kernel_name); + dbg("substitute kernel name '%s'", udev->kernel_name); + break; + case 'n': + if (strlen(udev->kernel_number) == 0) break; - case 'm': - sprintf(pos, "%u", udev->minor); - dbg("substitute minor number '%u'", udev->minor); + 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); + sprintf(pos, "%u", udev->major); + dbg("substitute major number '%u'", udev->major); + break; + case 'c': + if (strlen(udev->program_result) == 0) 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 (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 '%': - strcat(pos, "%"); - pos++; - break; - default: - dbg("unknown substitution type '%%%c'", pos[1]); - 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"); } - strcat(string, temp); - } else break; + case '%': + strcat(pos, "%"); + break; + default: + dbg("unknown substitution type '%%%c'", c); + break; + } + strcat(pos, tail); } } +/* + * Note, we can have multiple files for different busses in here due + * to the mess that USB has for its device tree... + */ static struct bus_file { char *bus; char *file; } bus_files[] = { { .bus = "scsi", .file = "vendor" }, { .bus = "usb", .file = "idVendor" }, + { .bus = "usb", .file = "iInterface" }, { .bus = "usb-serial", .file = "detach_state" }, { .bus = "ide", .file = "detach_state" }, { .bus = "pci", .file = "vendor" }, @@ -285,34 +344,52 @@ static void wait_for_device_to_initialize(struct sysfs_device *sysfs_device) */ struct bus_file *b = &bus_files[0]; struct sysfs_attribute *tmpattr; - int loop; + int found = 0; + int loop = SECONDS_TO_WAIT_FOR_FILE; while (1) { - if (b->bus == NULL) - break; + if (b->bus == NULL) { + if (!found) + break; + /* sleep to give the kernel a chance to create the file */ + sleep(1); + --loop; + if (loop == 0) + break; + b = &bus_files[0]; + } if (strcmp(sysfs_device->bus, b->bus) == 0) { - tmpattr = NULL; - loop = SECONDS_TO_WAIT_FOR_FILE; - while (loop--) { - dbg("looking for file '%s' on bus '%s'", b->file, b->bus); - tmpattr = sysfs_get_device_attr(sysfs_device, b->file); - if (tmpattr) { - /* found it! */ - goto exit; - } - /* sleep to give the kernel a chance to create the file */ - sleep(1); + found = 1; + dbg("looking for file '%s' on bus '%s'", b->file, b->bus); + tmpattr = sysfs_get_device_attr(sysfs_device, b->file); + if (tmpattr) { + /* found it! */ + goto exit; } - dbg("timed out waiting for '%s' file, continuing on anyway...", b->file); - goto exit; + dbg("can't find '%s' file", b->file); } - b++; + ++b; } - dbg("did not find bus type '%s' on list of bus_id_files, contact greg@kroah.com", sysfs_device->bus); + if (!found) + dbg("did not find bus type '%s' on list of bus_id_files, " + "contact greg@kroah.com", sysfs_device->bus); exit: return; /* here to prevent compiler warning... */ } +static void fix_kernel_name(struct udevice *udev) +{ + char *temp = udev->kernel_name; + + while (*temp != 0x00) { + /* Some block devices have a ! in their name, + * we need to change that to / */ + if (*temp == '!') + *temp = '/'; + ++temp; + } +} + static int execute_program(char *path, char *value, int len) { int retval; @@ -399,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) @@ -456,32 +547,20 @@ static int match_sysfs_pairs(struct config_device *dev, struct sysfs_class_devic static int match_id(struct config_device *dev, struct sysfs_class_device *class_dev, struct sysfs_device *sysfs_device) { char path[SYSFS_PATH_MAX]; - int found; char *temp = NULL; /* we have to have a sysfs device for ID to work */ if (!sysfs_device) return -ENODEV; - found = 0; strfieldcpy(path, sysfs_device->path); temp = strrchr(path, '/'); + temp++; dbg("search '%s' in '%s', path='%s'", dev->id, temp, path); - if (strstr(temp, dev->id) != NULL) { - found = 1; - } else { - *temp = 0x00; - temp = strrchr(path, '/'); - dbg("search '%s' in '%s', path='%s'", dev->id, temp, path); - if (strstr(temp, dev->id) != NULL) - found = 1; - } - if (!found) { - dbg("id doesn't match"); + if (strcmp_pattern(dev->id, temp) != 0) return -ENODEV; - } - - return 0; + else + return 0; } static int match_place(struct config_device *dev, struct sysfs_class_device *class_dev, struct sysfs_device *sysfs_device) @@ -589,12 +668,12 @@ static int match_rule(struct config_device *dev, struct sysfs_class_device *clas if (dev->bus[0] != '\0') { if (sysfs_device == NULL) { dbg("device has no bus"); - goto no_good; + goto try_parent; } dbg("check for " FIELD_BUS " dev->bus='%s' sysfs_device->bus='%s'", dev->bus, sysfs_device->bus); if (strcmp_pattern(dev->bus, sysfs_device->bus) != 0) { dbg(FIELD_BUS " is not matching"); - goto no_good; + goto try_parent; } else { dbg(FIELD_BUS " matches"); } @@ -605,7 +684,7 @@ static int match_rule(struct config_device *dev, struct sysfs_class_device *clas dbg("check for " FIELD_KERNEL " dev->kernel='%s' class_dev->name='%s'", dev->kernel, class_dev->name); if (strcmp_pattern(dev->kernel, class_dev->name) != 0) { dbg(FIELD_KERNEL " is not matching"); - goto no_good; + goto try_parent; } else { dbg(FIELD_KERNEL " matches"); } @@ -616,7 +695,7 @@ static int match_rule(struct config_device *dev, struct sysfs_class_device *clas dbg("check " FIELD_ID); if (match_id(dev, class_dev, sysfs_device) != 0) { dbg(FIELD_ID " is not matching"); - goto no_good; + goto try_parent; } else { dbg(FIELD_ID " matches"); } @@ -627,7 +706,7 @@ static int match_rule(struct config_device *dev, struct sysfs_class_device *clas dbg("check " FIELD_PLACE); if (match_place(dev, class_dev, sysfs_device) != 0) { dbg(FIELD_PLACE " is not matching"); - goto no_good; + goto try_parent; } else { dbg(FIELD_PLACE " matches"); } @@ -638,7 +717,7 @@ static int match_rule(struct config_device *dev, struct sysfs_class_device *clas dbg("check " FIELD_SYSFS " pairs"); if (match_sysfs_pairs(dev, class_dev, sysfs_device) != 0) { dbg(FIELD_SYSFS " is not matching"); - goto no_good; + goto try_parent; } else { dbg(FIELD_SYSFS " matches"); } @@ -647,10 +726,10 @@ 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 no_good; + goto try_parent; } else { dbg(FIELD_PROGRAM " returned successful"); } @@ -663,22 +742,17 @@ static int match_rule(struct config_device *dev, struct sysfs_class_device *clas dev->result, udev->program_result); if (strcmp_pattern(dev->result, udev->program_result) != 0) { dbg(FIELD_RESULT " is not matching"); - goto no_good; + goto try_parent; } else { dbg(FIELD_RESULT " matches"); } } - /* check if we are instructed to ignore this device */ - if (dev->name[0] == '\0') { - dbg("instructed to ignore this device"); - return -1; - } - /* Yeah, we matched! */ return 0; -no_good: +try_parent: + dbg("try parent sysfs device"); sysfs_device = sysfs_get_device_parent(sysfs_device); if (sysfs_device == NULL) return -ENODEV; @@ -706,11 +780,12 @@ int namedev_name_device(struct sysfs_class_device *class_dev, struct udevice *ud dbg("sysfs_device->bus='%s'", sysfs_device->bus); strfieldcpy(udev->bus_id, sysfs_device->bus_id); wait_for_device_to_initialize(sysfs_device); - } else { - dbg("class_dev->name = '%s'", class_dev->name); } + dbg("class_dev->name = '%s'", class_dev->name); strfieldcpy(udev->kernel_name, class_dev->name); + fix_kernel_name(udev); + dbg("udev->kernel_name = '%s'", udev->kernel_name); /* get kernel number */ pos = class_dev->name + strlen(class_dev->name); @@ -722,11 +797,15 @@ int namedev_name_device(struct sysfs_class_device *class_dev, struct udevice *ud /* look for a matching rule to apply */ list_for_each_entry(dev, &config_device_list, node) { dbg("process rule"); - if (match_rule(dev, class_dev, udev, sysfs_device) == 0) { - /* Yup, this rule belongs to us! */ + if (dev->name[0] == '\0') { + info("configured rule in '%s' at line %i applied, '%s' is ignored", + udev_rules_filename, dev->config_line, udev->kernel_name); + return -1; + } + info("configured rule in '%s' at line %i applied, '%s' becomes '%s'", - udev_rules_filename, dev->config_line, udev->kernel_name, dev->name); + udev_rules_filename, dev->config_line, udev->kernel_name, dev->name); strfieldcpy(udev->name, dev->name); strfieldcpy(udev->symlink, dev->symlink); goto found; @@ -734,14 +813,14 @@ int namedev_name_device(struct sysfs_class_device *class_dev, struct udevice *ud } /* no rule was found so we use the kernel name */ - strfieldcpy(udev->name, class_dev->name); + strfieldcpy(udev->name, udev->kernel_name); goto done; 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); + udev->partitions = dev->partitions; done: perm = find_perm(udev->name); if (perm) {