X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=namedev.c;h=dfeadee18a7e5100b1e3ff35ac67ec1e41cafc55;hp=219cb8a4b84406b63f7cfcf8917eb08fcb9eee66;hb=d5f91372dd3241f8b4bbe2a99aaaeda541a76bad;hpb=c472e3c89b9aaad90ad6398c0d2ff5dcf5a9d238 diff --git a/namedev.c b/namedev.c index 219cb8a4b..dfeadee18 100644 --- a/namedev.c +++ b/namedev.c @@ -198,7 +198,7 @@ static int get_format_len(char **str) if (isdigit(*str[0])) { num = (int) strtoul(*str, &tail, 10); - if (tail != NULL) { + if (num > 0) { *str = tail; dbg("format length=%i", num); return num; @@ -209,28 +209,30 @@ static int get_format_len(char **str) return -1; } -static void apply_format(struct udevice *udev, unsigned char *string, struct sysfs_class_device *class_dev, struct sysfs_device *sysfs_device) +static void apply_format(struct udevice *udev, char *string, size_t maxsize, + struct sysfs_class_device *class_dev, + struct sysfs_device *sysfs_device) { char temp[NAME_SIZE]; - char temp1[NAME_SIZE]; + char temp2[NAME_SIZE]; char *tail; char *pos; - char *pos2; - char *pos3; char *attr; - int num; + int len; int i; char c; + char *spos; + int slen; struct sysfs_attribute *tmpattr; pos = string; while (1) { - pos = strchr(pos, '%'); + pos = strchr(string, '%'); if (pos != NULL) { pos[0] = '\0'; tail = pos+1; - num = get_format_len(&tail); + len = get_format_len(&tail); c = tail[0]; strfieldcpy(temp, tail+1); tail = temp; @@ -245,53 +247,51 @@ static void apply_format(struct udevice *udev, unsigned char *string, struct sys case 'b': if (strlen(udev->bus_id) == 0) break; - strcat(pos, udev->bus_id); + strnfieldcat(string, udev->bus_id, maxsize); dbg("substitute bus_id '%s'", udev->bus_id); break; case 'k': if (strlen(udev->kernel_name) == 0) break; - strcat(pos, udev->kernel_name); + strnfieldcat(string, udev->kernel_name, maxsize); dbg("substitute kernel name '%s'", udev->kernel_name); break; case 'n': if (strlen(udev->kernel_number) == 0) break; - strcat(pos, udev->kernel_number); + strnfieldcat(string, udev->kernel_number, maxsize); dbg("substitute kernel number '%s'", udev->kernel_number); break; case 'm': - sprintf(pos, "%u", udev->minor); + strnintcat(string, udev->minor, maxsize); dbg("substitute minor number '%u'", udev->minor); break; - case 'M': - sprintf(pos, "%u", udev->major); + case 'M': + strnintcat(string, udev->major, maxsize); dbg("substitute major number '%u'", udev->major); break; case 'c': if (strlen(udev->program_result) == 0) break; /* get part part of the result string */ - i = num; /* num syntax is deprecated and will be removed */ + i = 0; if (attr != NULL) i = atoi(attr); if (i > 0) { - strfieldcpy(temp1, udev->program_result); - pos2 = temp1; - while (i) { + foreach_strpart(udev->program_result, " \n\r", spos, slen) { i--; - pos3 = strsep(&pos2, " "); - if (pos3 == NULL) { - dbg("requested part of result string not found"); + if (i == 0) break; - } } - if (pos3) { - strcat(pos, pos3); - dbg("substitute part of result string '%s'", pos3); + if (i > 0) { + dbg("requested part of result string not found"); + break; } + strnfieldcpy(temp2, spos, slen+1); + strnfieldcat(string, temp2, maxsize); + dbg("substitute part of result string '%s'", temp2); } else { - strcat(pos, udev->program_result); + strnfieldcat(string, udev->program_result, maxsize); dbg("substitute result string '%s'", udev->program_result); } break; @@ -302,20 +302,24 @@ static void apply_format(struct udevice *udev, unsigned char *string, struct sys dbg("sysfa attribute '%s' not found", attr); break; } - strcpy(pos, tmpattr->value); + strnfieldcat(string, tmpattr->value, maxsize); dbg("substitute sysfs value '%s'", tmpattr->value); } else { dbg("missing attribute"); } break; case '%': - strcat(pos, "%"); + strnfieldcat(string, "%", maxsize); break; default: dbg("unknown substitution type '%%%c'", c); break; } - strcat(pos, tail); + /* truncate to specified length */ + if (len > 0) + pos[len] = '\0'; + + strnfieldcat(string, tail, maxsize); } } @@ -403,7 +407,7 @@ static int execute_program(char *path, char *value, int len) int fds[2]; pid_t pid; int value_set = 0; - char buffer[256]; + char buffer[255]; char *pos; char *args[PROGRAM_MAXARG]; int i; @@ -419,7 +423,13 @@ static int execute_program(char *path, char *value, int len) case 0: /* child */ close(STDOUT_FILENO); - dup(fds[1]); /* dup write side of pipe to STDOUT */ + + /* dup write side of pipe to STDOUT */ + dup(fds[1]); + + /* copy off our path to use incase we have too many args */ + strnfieldcpy(buffer, path, sizeof(buffer)); + if (strchr(path, ' ')) { /* exec with arguments */ pos = path; @@ -429,14 +439,16 @@ static int execute_program(char *path, char *value, int len) break; } if (args[i]) { - dbg("too many args - %d", i); - args[i] = NULL; + dbg("too many args - %d, using subshell instead '%s'", i, buffer); + retval = execl("/bin/sh", "sh", "-c", buffer, NULL); + } else { + dbg("execute program '%s'", path); + retval = execv(args[0], args); } - retval = execv(args[0], args); } else { retval = execv(path, main_argv); } - dbg("child execve failed"); + info(FIELD_PROGRAM " execution of '%s' failed", path); exit(1); case -1: dbg("fork failed"); @@ -462,7 +474,7 @@ static int execute_program(char *path, char *value, int len) strncpy(value, buffer, len); pos = value + strlen(value)-1; if (pos[0] == '\n') - pos[0] = '\0'; + pos[0] = '\0'; dbg("result is '%s'", value); } } @@ -513,6 +525,8 @@ attr_found: static int compare_sysfs_attribute(struct sysfs_class_device *class_dev, struct sysfs_device *sysfs_device, struct sysfs_pair *pair) { struct sysfs_attribute *tmpattr; + int i; + int len; if ((pair == NULL) || (pair->file[0] == '\0') || (pair->value == '\0')) return -ENODEV; @@ -521,6 +535,18 @@ static int compare_sysfs_attribute(struct sysfs_class_device *class_dev, struct if (tmpattr == NULL) return -ENODEV; + /* strip trailing whitespace of value, if not asked to match for it */ + if (! isspace(pair->value[strlen(pair->value)-1])) { + i = len = strlen(tmpattr->value); + while (i > 0 && isspace(tmpattr->value[i-1])) + i--; + if (i < len) { + tmpattr->value[i] = '\0'; + dbg("remove %i trailing whitespace chars from '%s'", + len - i, tmpattr->value); + } + } + dbg("compare attribute '%s' value '%s' with '%s'", pair->file, tmpattr->value, pair->value); if (strcmp_pattern(pair->value, tmpattr->value) != 0) @@ -733,7 +759,8 @@ 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, class_dev, sysfs_device); + apply_format(udev, dev->program, sizeof(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; @@ -805,17 +832,31 @@ int namedev_name_device(struct sysfs_class_device *class_dev, struct udevice *ud list_for_each_entry(dev, &config_device_list, node) { dbg("process rule"); if (match_rule(dev, class_dev, udev, sysfs_device) == 0) { - if (dev->name[0] == '\0') { + if (dev->name[0] == '\0' && dev->symlink[0] == '\0') { info("configured rule in '%s' at line %i applied, '%s' is ignored", - udev_rules_filename, dev->config_line, udev->kernel_name); + dev->config_file, 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); - strfieldcpy(udev->name, dev->name); - strfieldcpy(udev->symlink, dev->symlink); - goto found; + if (dev->symlink[0] != '\0') { + char temp[NAME_MAX]; + + info("configured rule in '%s' at line %i applied, added symlink '%s'", + dev->config_file, dev->config_line, dev->symlink); + /* do not clobber dev */ + strfieldcpy(temp, dev->symlink); + apply_format(udev, temp, sizeof(temp), + class_dev, sysfs_device); + strfieldcat(udev->symlink, temp); + strfieldcat(udev->symlink, " "); + } + + if (dev->name[0] != '\0') { + info("configured rule in '%s' at line %i applied, '%s' becomes '%s'", + dev->config_file, dev->config_line, udev->kernel_name, dev->name); + strfieldcpy(udev->name, dev->name); + goto found; + } } } @@ -825,8 +866,8 @@ int namedev_name_device(struct sysfs_class_device *class_dev, struct udevice *ud found: /* substitute placeholder */ - apply_format(udev, udev->name, class_dev, sysfs_device); - apply_format(udev, udev->symlink, class_dev, sysfs_device); + apply_format(udev, udev->name, sizeof(udev->name), + class_dev, sysfs_device); udev->partitions = dev->partitions; done: perm = find_perm(udev->name);