diff --git a/udev.c b/udev.c index 36ff21d5b71..1c55ec14b87 100644 --- a/udev.c +++ b/udev.c @@ -214,7 +214,7 @@ run: dbg("executing run list"); list_for_each_entry(name_loop, &udev.run_list, node) - execute_command(name_loop->name, udev.subsystem); + execute_program(name_loop->name, udev.subsystem, NULL, 0, NULL); } cleanup: diff --git a/udev_rules.c b/udev_rules.c index 6ed67c2672e..aa66c7ad30a 100644 --- a/udev_rules.c +++ b/udev_rules.c @@ -200,24 +200,16 @@ static int get_key(char **line, char **key, char **value) return 0; } -static int import_file_into_env(const char *filename) +static int import_keys_into_env(const char *buf, size_t bufsize) { char line[LINE_SIZE]; - char *bufline; + const char *bufline; char *linepos; char *variable; char *value; - char *buf; - size_t bufsize; size_t cur; size_t count; int lineno; - int retval = 0; - - if (file_map(filename, &buf, &bufsize) != 0) { - err("can't open '%s'", filename); - return -1; - } /* loop through the whole file */ lineno = 0; @@ -254,8 +246,22 @@ static int import_file_into_env(const char *filename) } } + return 0; +} + +static int import_file_into_env(const char *filename) +{ + char *buf; + size_t bufsize; + + if (file_map(filename, &buf, &bufsize) != 0) { + err("can't open '%s'", filename); + return -1; + } + import_keys_into_env(buf, bufsize); file_unmap(buf, bufsize); - return retval; + + return 0; } /** Finds the lowest positive N such that N isn't present in @@ -576,117 +582,10 @@ found: head[len] = '\0'; dbg("truncate to %i chars, subtitution string becomes '%s'", len, head); } - strlcat(string, temp, maxsize); } } -static int execute_program_pipe(const char *command, const char *subsystem, char *value, int len) -{ - int retval; - int count; - int status; - int pipefds[2]; - pid_t pid; - char *pos; - char arg[PATH_SIZE]; - char *argv[(sizeof(arg) / 2) + 1]; - int devnull; - int i; - - strlcpy(arg, command, sizeof(arg)); - i = 0; - if (strchr(arg, ' ')) { - pos = arg; - while (pos != NULL) { - if (pos[0] == '\'') { - /* don't separate if in apostrophes */ - pos++; - argv[i] = strsep(&pos, "\'"); - while (pos && pos[0] == ' ') - pos++; - } else { - argv[i] = strsep(&pos, " "); - } - dbg("arg[%i] '%s'", i, argv[i]); - i++; - } - argv[i] = NULL; - dbg("execute '%s' with parsed arguments", arg); - } else { - argv[0] = arg; - argv[1] = (char *) subsystem; - argv[2] = NULL; - dbg("execute '%s' with subsystem '%s' argument", arg, argv[1]); - } - - retval = pipe(pipefds); - if (retval != 0) { - err("pipe failed"); - return -1; - } - - pid = fork(); - switch(pid) { - case 0: - /* child dup2 write side of pipe to STDOUT */ - devnull = open("/dev/null", O_RDWR); - if (devnull >= 0) { - dup2(devnull, STDIN_FILENO); - dup2(devnull, STDERR_FILENO); - close(devnull); - } - dup2(pipefds[1], STDOUT_FILENO); - retval = execv(arg, argv); - err("exec of program failed"); - _exit(1); - case -1: - err("fork of '%s' failed", arg); - retval = -1; - break; - default: - /* parent reads from pipefds[0] */ - close(pipefds[1]); - retval = 0; - i = 0; - while (1) { - count = read(pipefds[0], value + i, len - i-1); - if (count < 0) { - err("read failed with '%s'", strerror(errno)); - retval = -1; - } - - if (count == 0) - break; - - i += count; - if (i >= len-1) { - err("result len %d too short", len); - retval = -1; - break; - } - } - value[i] = '\0'; - - close(pipefds[0]); - waitpid(pid, &status, 0); - - if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0)) { - dbg("exec program status 0x%x", status); - retval = -1; - } - } - - if (!retval) { - remove_trailing_char(value, '\n'); - dbg("result is '%s'", value); - replace_untrusted_chars(value); - } else - value[0] = '\0'; - - return retval; -} - static int match_rule(struct udevice *udev, struct udev_rule *rule, struct sysfs_class_device *class_dev, struct sysfs_device *sysfs_device) { @@ -909,34 +808,40 @@ try_parent: dbg("look at sysfs_device->bus_id='%s'", parent_device->bus_id); } + /* import variables from file into environment */ if (rule->import_operation != KEY_OP_UNSET) { char import[PATH_SIZE]; strlcpy(import, rule->import, sizeof(import)); apply_format(udev, import, sizeof(import), class_dev, sysfs_device); dbg("check for " KEY_IMPORT " import='%s", import); - if (import_file_into_env(import) == 0) { - dbg(KEY_IMPORT " file '%s' imported", rule->import); - if (rule->import_operation == KEY_OP_NOMATCH) + if (import_file_into_env(import) != 0) { + dbg(KEY_IMPORT " failed"); + if (rule->import_operation != KEY_OP_NOMATCH) goto exit; } else - goto exit; + dbg(KEY_IMPORT " file '%s' imported", rule->import); dbg(KEY_IMPORT " key is true"); } /* execute external program */ if (rule->program_operation != KEY_OP_UNSET) { char program[PATH_SIZE]; + char result[PATH_SIZE]; strlcpy(program, rule->program, sizeof(program)); apply_format(udev, program, sizeof(program), class_dev, sysfs_device); dbg("check for " KEY_PROGRAM " program='%s", program); - if (execute_program_pipe(program, udev->subsystem, - udev->program_result, sizeof(udev->program_result)) != 0) { - dbg(KEY_PROGRAM " returned nonzero"); + if (execute_program(program, udev->subsystem, result, sizeof(result), NULL) != 0) { + dbg(KEY_PROGRAM " is not matching"); if (rule->program_operation != KEY_OP_NOMATCH) goto exit; } else { + dbg(KEY_PROGRAM " matches"); + remove_trailing_char(result, '\n'); + replace_untrusted_chars(result); + dbg("result is '%s'", result); + strlcpy(udev->program_result, result, sizeof(udev->program_result)); dbg(KEY_PROGRAM " returned successful"); if (rule->program_operation == KEY_OP_NOMATCH) goto exit; diff --git a/udev_utils.c b/udev_utils.c index c35b287881a..9e2e1527635 100644 --- a/udev_utils.c +++ b/udev_utils.c @@ -361,15 +361,20 @@ int add_matching_files(struct list_head *name_list, const char *dirname, const c return 0; } -int execute_command(const char *command, const char *subsystem) +int execute_program(const char *command, const char *subsystem, + char *result, size_t ressize, size_t *reslen) { - int retval; + int retval = 0; + int count; + int status; + int pipefds[2]; pid_t pid; - char arg[PATH_SIZE]; - char *argv[(PATH_SIZE / 2) + 1]; char *pos; + char arg[PATH_SIZE]; + char *argv[(sizeof(arg) / 2) + 1]; int devnull; int i; + size_t len; strlcpy(arg, command, sizeof(arg)); i = 0; @@ -397,27 +402,68 @@ int execute_command(const char *command, const char *subsystem) dbg("execute '%s' with subsystem '%s' argument", arg, argv[1]); } + if (result) { + if (pipe(pipefds) != 0) { + err("pipe failed"); + return -1; + } + } + pid = fork(); - switch (pid) { + switch(pid) { case 0: - /* child */ + /* child dup2 write side of pipe to STDOUT */ devnull = open("/dev/null", O_RDWR); if (devnull >= 0) { dup2(devnull, STDIN_FILENO); - dup2(devnull, STDOUT_FILENO); + if (!result) + dup2(devnull, STDOUT_FILENO); dup2(devnull, STDERR_FILENO); close(devnull); } - retval = execv(arg, argv); - err("exec of child '%s' failed", command); + if (result) + dup2(pipefds[1], STDOUT_FILENO); + execv(arg, argv); + err("exec of program failed"); _exit(1); case -1: - dbg("fork of child '%s' failed", command); - break; + err("fork of '%s' failed", arg); return -1; default: - waitpid(pid, NULL, 0); + /* parent reads from pipefds[0] */ + if (result) { + close(pipefds[1]); + len = 0; + while (1) { + count = read(pipefds[0], result + len, ressize - len-1); + if (count < 0) { + err("read failed with '%s'", strerror(errno)); + retval = -1; + break; + } + + if (count == 0) + break; + + len += count; + if (len >= ressize-1) { + err("ressize %d too short", ressize); + retval = -1; + break; + } + } + result[len] = '\0'; + close(pipefds[0]); + if (reslen) + *reslen = len; + } + waitpid(pid, &status, 0); + + if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0)) { + dbg("exec program status 0x%x", status); + retval = -1; + } } - return 0; + return retval; } diff --git a/udev_utils.h b/udev_utils.h index 3e372dd9480..999a4fcf55c 100644 --- a/udev_utils.h +++ b/udev_utils.h @@ -45,6 +45,7 @@ extern void remove_trailing_char(char *path, char c); extern void replace_untrusted_chars(char *string); extern int name_list_add(struct list_head *name_list, const char *name, int sort); extern int add_matching_files(struct list_head *name_list, const char *dirname, const char *suffix); -extern int execute_command(const char *command, const char *subsystem); +extern int execute_program(const char *command, const char *subsystem, + char *result, size_t ressize, size_t *reslen); #endif diff --git a/udevstart.c b/udevstart.c index bd91e96f6af..b65a28aab69 100644 --- a/udevstart.c +++ b/udevstart.c @@ -146,7 +146,7 @@ run: dbg("executing run list"); list_for_each_entry(name_loop, &udev.run_list, node) - execute_command(name_loop->name, udev.subsystem); + execute_program(name_loop->name, udev.subsystem, NULL, 0, NULL); } exit: sysfs_close_class_device(class_dev);