+
+int execute_program(const char *command, const char *subsystem,
+ char *result, size_t ressize, size_t *reslen)
+{
+ int retval = 0;
+ 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;
+ size_t len;
+
+ 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]);
+ }
+
+ if (result) {
+ if (pipe(pipefds) != 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);
+ if (!result)
+ dup2(devnull, STDOUT_FILENO);
+ dup2(devnull, STDERR_FILENO);
+ close(devnull);
+ }
+ if (result)
+ dup2(pipefds[1], STDOUT_FILENO);
+ execv(arg, argv);
+ err("exec of program failed");
+ _exit(1);
+ case -1:
+ err("fork of '%s' failed", arg);
+ return -1;
+ default:
+ /* 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 %ld too short", (long)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 retval;
+}