]> git.ozlabs.org Git - petitboot/blobdiff - lib/process/process.c
lib/process: Don't abort stdout reads on EINTR
[petitboot] / lib / process / process.c
index e1a158b0799519e391aa310228a3c8670cad7e47..081a48ca36ba27ac37eb1a83888eaec281d635b0 100644 (file)
@@ -29,6 +29,7 @@ struct procset {
        struct list             async_list;
        int                     sigchld_pipe[2];
        struct waiter           *sigchld_waiter;
+       bool                    dry_run;
 };
 
 /* Internal data type for process handling
@@ -60,7 +61,13 @@ static struct process_info *get_info(struct process *process)
 }
 
 /* Read as much as possible into the currently-allocated stdout buffer, and
- * possibly realloc it for the next read */
+ * possibly realloc it for the next read
+ *
+ * Returns:
+ *  > 0 on success (even though no bytes may have been read)
+ *    0 on EOF (no error, but no more reads can be performed)
+ *  < 0 on error
+ **/
 static int process_read_stdout_once(struct process_info *procinfo)
 {
        struct process *process = &procinfo->process;
@@ -73,8 +80,14 @@ static int process_read_stdout_once(struct process_info *procinfo)
        max_len =  procinfo->stdout_buf_len - process->stdout_len - 1;
 
        rc = read(fd, process->stdout_buf + process->stdout_len, max_len);
-       if (rc <= 0)
+       if (rc == 0)
+               return 0;
+       if (rc < 0) {
+               if (errno == EINTR)
+                       return 1;
+               pb_log("%s: read failed: %s\n", __func__, strerror(errno));
                return rc;
+       }
 
        process->stdout_len += rc;
        if (process->stdout_len == procinfo->stdout_buf_len - 1) {
@@ -84,7 +97,7 @@ static int process_read_stdout_once(struct process_info *procinfo)
                                procinfo->stdout_buf_len);
        }
 
-       return rc;
+       return 1;
 }
 
 static int process_setup_stdout_pipe(struct process_info *procinfo)
@@ -124,7 +137,10 @@ static void process_setup_stdout_child(struct process_info *procinfo)
        else
                dup2(log, STDOUT_FILENO);
 
-       dup2(log, STDERR_FILENO);
+       if (procinfo->process.keep_stdout && procinfo->process.add_stderr)
+               dup2(procinfo->stdout_pipe[1], STDERR_FILENO);
+       else
+               dup2(log, STDERR_FILENO);
 }
 
 static void process_finish_stdout(struct process_info *procinfo)
@@ -245,13 +261,14 @@ static int process_fini(void *p)
        return 0;
 }
 
-struct procset *process_init(void *ctx, struct waitset *set)
+struct procset *process_init(void *ctx, struct waitset *set, bool dry_run)
 {
        struct sigaction sa;
        int rc;
 
        procset = talloc(ctx, struct procset);
        procset->waitset = set;
+       procset->dry_run = dry_run;
        list_init(&procset->async_list);
 
        rc = pipe(procset->sigchld_pipe);
@@ -330,6 +347,8 @@ static int process_run_common(struct process_info *procinfo)
 
        if (pid == 0) {
                process_setup_stdout_child(procinfo);
+               if (procset->dry_run)
+                       exit(EXIT_SUCCESS);
                execvp(process->path, (char * const *)process->argv);
                exit(EXIT_FAILURE);
        }
@@ -351,8 +370,13 @@ int process_run_sync(struct process *process)
 
        process_read_stdout(procinfo);
 
-       rc = waitpid(process->pid, &process->exit_status, 0);
-       if (rc == -1) {
+       for (;;) {
+               rc = waitpid(process->pid, &process->exit_status, 0);
+               if (rc >= 0)
+                       break;
+               if (errno == EINTR)
+                       continue;
+
                pb_log("%s: waitpid failed: %s\n", __func__, strerror(errno));
                return rc;
        }
@@ -435,3 +459,9 @@ int process_run_simple(void *ctx, const char *name, ...)
 
        return rc;
 }
+
+bool process_exit_ok(struct process *process)
+{
+       return WIFEXITED(process->exit_status) &&
+               WEXITSTATUS(process->exit_status) == 0;
+}