From: Kay Sievers Date: Sat, 18 Oct 2008 13:25:05 +0000 (+0200) Subject: move run_program to util X-Git-Tag: 174~1421 X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d0db192fa5a50eee27bce3e92c89f3ec1294638d;p=systemd move run_program to util --- diff --git a/udev/udev-rules.c b/udev/udev-rules.c index 6d7e3f4f..62624bbc 100644 --- a/udev/udev-rules.c +++ b/udev/udev-rules.c @@ -24,13 +24,8 @@ #include #include #include -#include #include #include -#include -#include -#include -#include #include "udev.h" @@ -234,223 +229,6 @@ static int get_format_len(struct udev *udev, char **str) return -1; } -static int run_program(struct udev_device *dev, const char *command, - char *result, size_t ressize, size_t *reslen) -{ - struct udev *udev = udev_device_get_udev(dev); - int status; - char **envp; - int outpipe[2] = {-1, -1}; - int errpipe[2] = {-1, -1}; - pid_t pid; - char arg[UTIL_PATH_SIZE]; - char program[UTIL_PATH_SIZE]; - char *argv[(sizeof(arg) / 2) + 1]; - int devnull; - int i; - int err = 0; - - /* build argv from command */ - util_strlcpy(arg, command, sizeof(arg)); - i = 0; - if (strchr(arg, ' ') != NULL) { - char *pos = arg; - - while (pos != NULL && pos[0] != '\0') { - if (pos[0] == '\'') { - /* do not separate quotes */ - pos++; - argv[i] = strsep(&pos, "\'"); - while (pos != NULL && pos[0] == ' ') - pos++; - } else { - argv[i] = strsep(&pos, " "); - } - dbg(udev, "arg[%i] '%s'\n", i, argv[i]); - i++; - } - argv[i] = NULL; - } else { - argv[0] = arg; - argv[1] = NULL; - } - info(udev, "'%s'\n", command); - - /* prepare pipes from child to parent */ - if (result != NULL || udev_get_log_priority(udev) >= LOG_INFO) { - if (pipe(outpipe) != 0) { - err(udev, "pipe failed: %m\n"); - return -1; - } - } - if (udev_get_log_priority(udev) >= LOG_INFO) { - if (pipe(errpipe) != 0) { - err(udev, "pipe failed: %m\n"); - return -1; - } - } - - /* allow programs in /lib/udev/ to be called without the path */ - if (strchr(argv[0], '/') == NULL) { - util_strlcpy(program, UDEV_PREFIX "/lib/udev/", sizeof(program)); - util_strlcat(program, argv[0], sizeof(program)); - argv[0] = program; - } - - envp = udev_device_get_properties_envp(dev); - - pid = fork(); - switch(pid) { - case 0: - /* child closes parent ends of pipes */ - if (outpipe[READ_END] > 0) - close(outpipe[READ_END]); - if (errpipe[READ_END] > 0) - close(errpipe[READ_END]); - - /* discard child output or connect to pipe */ - devnull = open("/dev/null", O_RDWR); - if (devnull > 0) { - dup2(devnull, STDIN_FILENO); - if (outpipe[WRITE_END] < 0) - dup2(devnull, STDOUT_FILENO); - if (errpipe[WRITE_END] < 0) - dup2(devnull, STDERR_FILENO); - close(devnull); - } else - err(udev, "open /dev/null failed: %m\n"); - if (outpipe[WRITE_END] > 0) { - dup2(outpipe[WRITE_END], STDOUT_FILENO); - close(outpipe[WRITE_END]); - } - if (errpipe[WRITE_END] > 0) { - dup2(errpipe[WRITE_END], STDERR_FILENO); - close(errpipe[WRITE_END]); - } - execve(argv[0], argv, envp); - if (errno == ENOENT || errno == ENOTDIR) { - /* may be on a filesytem which is not mounted right now */ - info(udev, "program '%s' not found\n", argv[0]); - } else { - /* other problems */ - err(udev, "exec of program '%s' failed\n", argv[0]); - } - _exit(1); - case -1: - err(udev, "fork of '%s' failed: %m\n", argv[0]); - return -1; - default: - /* read from child if requested */ - if (outpipe[READ_END] > 0 || errpipe[READ_END] > 0) { - ssize_t count; - size_t respos = 0; - - /* parent closes child ends of pipes */ - if (outpipe[WRITE_END] > 0) - close(outpipe[WRITE_END]); - if (errpipe[WRITE_END] > 0) - close(errpipe[WRITE_END]); - - /* read child output */ - while (outpipe[READ_END] > 0 || errpipe[READ_END] > 0) { - int fdcount; - fd_set readfds; - - FD_ZERO(&readfds); - if (outpipe[READ_END] > 0) - FD_SET(outpipe[READ_END], &readfds); - if (errpipe[READ_END] > 0) - FD_SET(errpipe[READ_END], &readfds); - fdcount = select(UDEV_MAX(outpipe[READ_END], errpipe[READ_END])+1, &readfds, NULL, NULL, NULL); - if (fdcount < 0) { - if (errno == EINTR) - continue; - err = -1; - break; - } - - /* get stdout */ - if (outpipe[READ_END] > 0 && FD_ISSET(outpipe[READ_END], &readfds)) { - char inbuf[1024]; - char *pos; - char *line; - - count = read(outpipe[READ_END], inbuf, sizeof(inbuf)-1); - if (count <= 0) { - close(outpipe[READ_END]); - outpipe[READ_END] = -1; - if (count < 0) { - err(udev, "stdin read failed: %m\n"); - err = -1; - } - continue; - } - inbuf[count] = '\0'; - - /* store result for rule processing */ - if (result) { - if (respos + count < ressize) { - memcpy(&result[respos], inbuf, count); - respos += count; - } else { - err(udev, "ressize %ld too short\n", (long)ressize); - err = -1; - } - } - pos = inbuf; - while ((line = strsep(&pos, "\n"))) - if (pos || line[0] != '\0') - info(udev, "'%s' (stdout) '%s'\n", argv[0], line); - } - - /* get stderr */ - if (errpipe[READ_END] > 0 && FD_ISSET(errpipe[READ_END], &readfds)) { - char errbuf[1024]; - char *pos; - char *line; - - count = read(errpipe[READ_END], errbuf, sizeof(errbuf)-1); - if (count <= 0) { - close(errpipe[READ_END]); - errpipe[READ_END] = -1; - if (count < 0) - err(udev, "stderr read failed: %m\n"); - continue; - } - errbuf[count] = '\0'; - pos = errbuf; - while ((line = strsep(&pos, "\n"))) - if (pos || line[0] != '\0') - info(udev, "'%s' (stderr) '%s'\n", argv[0], line); - } - } - if (outpipe[READ_END] > 0) - close(outpipe[READ_END]); - if (errpipe[READ_END] > 0) - close(errpipe[READ_END]); - - /* return the childs stdout string */ - if (result) { - result[respos] = '\0'; - dbg(udev, "result='%s'\n", result); - if (reslen) - *reslen = respos; - } - } - waitpid(pid, &status, 0); - if (WIFEXITED(status)) { - info(udev, "'%s' returned with status %i\n", argv[0], WEXITSTATUS(status)); - if (WEXITSTATUS(status) != 0) - err = -1; - } else { - err(udev, "'%s' abnormal exit\n", argv[0]); - err = -1; - } - } - - return err; -} - static int import_property_from_string(struct udev_device *dev, char *line) { struct udev *udev = udev_device_get_udev(dev); @@ -544,11 +322,14 @@ static int import_file_into_env(struct udev_device *dev, const char *filename) static int import_program_into_env(struct udev_device *dev, const char *program) { + struct udev *udev = udev_device_get_udev(dev); + char **envp; char result[2048]; size_t reslen; char *line; - if (run_program(dev, program, result, sizeof(result), &reslen) != 0) + envp = udev_device_get_properties_envp(dev); + if (run_program(udev, program, envp, result, sizeof(result), &reslen) != 0) return -1; line = result; @@ -612,10 +393,12 @@ int udev_rules_run(struct udev_event *event) udev_monitor_unref(monitor); } else { char program[UTIL_PATH_SIZE]; + char **envp; util_strlcpy(program, cmd, sizeof(program)); udev_rules_apply_format(event, program, sizeof(program)); - if (run_program(event->dev, program, NULL, 0, NULL) != 0) { + envp = udev_device_get_properties_envp(event->dev); + if (run_program(event->udev, program, envp, NULL, 0, NULL) != 0) { if (!udev_list_entry_get_flag(list_entry)) err = -1; } @@ -1372,11 +1155,13 @@ try_parent: /* execute external program */ if (rule->program.operation != KEY_OP_UNSET) { char program[UTIL_PATH_SIZE]; + char **envp; char result[UTIL_PATH_SIZE]; util_strlcpy(program, key_val(rule, &rule->program), sizeof(program)); udev_rules_apply_format(event, program, sizeof(program)); - if (run_program(event->dev, program, result, sizeof(result), NULL) != 0) { + envp = udev_device_get_properties_envp(dev); + if (run_program(event->udev, program, envp, result, sizeof(result), NULL) != 0) { dbg(event->udev, "PROGRAM is false\n"); event->program_result[0] = '\0'; if (rule->program.operation != KEY_OP_NOMATCH) diff --git a/udev/udev-util.c b/udev/udev-util.c index 59c4d194..d17a1519 100644 --- a/udev/udev-util.c +++ b/udev/udev-util.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "udev.h" @@ -158,3 +159,215 @@ extern gid_t lookup_group(struct udev *udev, const char *group) return gid; } + +int run_program(struct udev *udev, const char *command, char **envp, + char *result, size_t ressize, size_t *reslen) +{ + int status; + int outpipe[2] = {-1, -1}; + int errpipe[2] = {-1, -1}; + pid_t pid; + char arg[UTIL_PATH_SIZE]; + char program[UTIL_PATH_SIZE]; + char *argv[(sizeof(arg) / 2) + 1]; + int devnull; + int i; + int err = 0; + + /* build argv from command */ + util_strlcpy(arg, command, sizeof(arg)); + i = 0; + if (strchr(arg, ' ') != NULL) { + char *pos = arg; + + while (pos != NULL && pos[0] != '\0') { + if (pos[0] == '\'') { + /* do not separate quotes */ + pos++; + argv[i] = strsep(&pos, "\'"); + while (pos != NULL && pos[0] == ' ') + pos++; + } else { + argv[i] = strsep(&pos, " "); + } + dbg(udev, "arg[%i] '%s'\n", i, argv[i]); + i++; + } + argv[i] = NULL; + } else { + argv[0] = arg; + argv[1] = NULL; + } + info(udev, "'%s'\n", command); + + /* prepare pipes from child to parent */ + if (result != NULL || udev_get_log_priority(udev) >= LOG_INFO) { + if (pipe(outpipe) != 0) { + err(udev, "pipe failed: %m\n"); + return -1; + } + } + if (udev_get_log_priority(udev) >= LOG_INFO) { + if (pipe(errpipe) != 0) { + err(udev, "pipe failed: %m\n"); + return -1; + } + } + + /* allow programs in /lib/udev/ to be called without the path */ + if (strchr(argv[0], '/') == NULL) { + util_strlcpy(program, UDEV_PREFIX "/lib/udev/", sizeof(program)); + util_strlcat(program, argv[0], sizeof(program)); + argv[0] = program; + } + + pid = fork(); + switch(pid) { + case 0: + /* child closes parent ends of pipes */ + if (outpipe[READ_END] > 0) + close(outpipe[READ_END]); + if (errpipe[READ_END] > 0) + close(errpipe[READ_END]); + + /* discard child output or connect to pipe */ + devnull = open("/dev/null", O_RDWR); + if (devnull > 0) { + dup2(devnull, STDIN_FILENO); + if (outpipe[WRITE_END] < 0) + dup2(devnull, STDOUT_FILENO); + if (errpipe[WRITE_END] < 0) + dup2(devnull, STDERR_FILENO); + close(devnull); + } else + err(udev, "open /dev/null failed: %m\n"); + if (outpipe[WRITE_END] > 0) { + dup2(outpipe[WRITE_END], STDOUT_FILENO); + close(outpipe[WRITE_END]); + } + if (errpipe[WRITE_END] > 0) { + dup2(errpipe[WRITE_END], STDERR_FILENO); + close(errpipe[WRITE_END]); + } + execve(argv[0], argv, envp); + if (errno == ENOENT || errno == ENOTDIR) { + /* may be on a filesytem which is not mounted right now */ + info(udev, "program '%s' not found\n", argv[0]); + } else { + /* other problems */ + err(udev, "exec of program '%s' failed\n", argv[0]); + } + _exit(1); + case -1: + err(udev, "fork of '%s' failed: %m\n", argv[0]); + return -1; + default: + /* read from child if requested */ + if (outpipe[READ_END] > 0 || errpipe[READ_END] > 0) { + ssize_t count; + size_t respos = 0; + + /* parent closes child ends of pipes */ + if (outpipe[WRITE_END] > 0) + close(outpipe[WRITE_END]); + if (errpipe[WRITE_END] > 0) + close(errpipe[WRITE_END]); + + /* read child output */ + while (outpipe[READ_END] > 0 || errpipe[READ_END] > 0) { + int fdcount; + fd_set readfds; + + FD_ZERO(&readfds); + if (outpipe[READ_END] > 0) + FD_SET(outpipe[READ_END], &readfds); + if (errpipe[READ_END] > 0) + FD_SET(errpipe[READ_END], &readfds); + fdcount = select(UDEV_MAX(outpipe[READ_END], errpipe[READ_END])+1, &readfds, NULL, NULL, NULL); + if (fdcount < 0) { + if (errno == EINTR) + continue; + err = -1; + break; + } + + /* get stdout */ + if (outpipe[READ_END] > 0 && FD_ISSET(outpipe[READ_END], &readfds)) { + char inbuf[1024]; + char *pos; + char *line; + + count = read(outpipe[READ_END], inbuf, sizeof(inbuf)-1); + if (count <= 0) { + close(outpipe[READ_END]); + outpipe[READ_END] = -1; + if (count < 0) { + err(udev, "stdin read failed: %m\n"); + err = -1; + } + continue; + } + inbuf[count] = '\0'; + + /* store result for rule processing */ + if (result) { + if (respos + count < ressize) { + memcpy(&result[respos], inbuf, count); + respos += count; + } else { + err(udev, "ressize %ld too short\n", (long)ressize); + err = -1; + } + } + pos = inbuf; + while ((line = strsep(&pos, "\n"))) + if (pos || line[0] != '\0') + info(udev, "'%s' (stdout) '%s'\n", argv[0], line); + } + + /* get stderr */ + if (errpipe[READ_END] > 0 && FD_ISSET(errpipe[READ_END], &readfds)) { + char errbuf[1024]; + char *pos; + char *line; + + count = read(errpipe[READ_END], errbuf, sizeof(errbuf)-1); + if (count <= 0) { + close(errpipe[READ_END]); + errpipe[READ_END] = -1; + if (count < 0) + err(udev, "stderr read failed: %m\n"); + continue; + } + errbuf[count] = '\0'; + pos = errbuf; + while ((line = strsep(&pos, "\n"))) + if (pos || line[0] != '\0') + info(udev, "'%s' (stderr) '%s'\n", argv[0], line); + } + } + if (outpipe[READ_END] > 0) + close(outpipe[READ_END]); + if (errpipe[READ_END] > 0) + close(errpipe[READ_END]); + + /* return the childs stdout string */ + if (result) { + result[respos] = '\0'; + dbg(udev, "result='%s'\n", result); + if (reslen) + *reslen = respos; + } + } + waitpid(pid, &status, 0); + if (WIFEXITED(status)) { + info(udev, "'%s' returned with status %i\n", argv[0], WEXITSTATUS(status)); + if (WEXITSTATUS(status) != 0) + err = -1; + } else { + err(udev, "'%s' abnormal exit\n", argv[0]); + err = -1; + } + } + return err; +} diff --git a/udev/udev.h b/udev/udev.h index eb020cd3..be76fe3c 100644 --- a/udev/udev.h +++ b/udev/udev.h @@ -111,6 +111,8 @@ extern int delete_path(struct udev *udev, const char *path); extern int unlink_secure(struct udev *udev, const char *filename); extern uid_t lookup_user(struct udev *udev, const char *user); extern gid_t lookup_group(struct udev *udev, const char *group); +extern int run_program(struct udev *udev, const char *command, char **envp, + char *result, size_t ressize, size_t *reslen); /* udev_utils_file.c */ extern int file_map(const char *filename, char **buf, size_t *bufsize);