[2/6] lib/process: Allow process output to be retrieved on each event
diff mbox

Message ID 20161025034448.28723-2-sam@mendozajonas.com
State Superseded
Headers show

Commit Message

Samuel Mendoza-Jonas Oct. 25, 2016, 3:44 a.m. UTC
Allow a custom callback function to be set when registering the IO
waiter for asynchronous processes.

To allow output from processes to be parsed as it is received, add
process_stdout_custom() which passes a new "line" parameter to
process_read_stdout_once() in order to consume output as it appears.
process_read_stdout_once() duplicates the latest output and passes the
"line" pointer back to the caller.

Users of a custom IO callback will only have access to the process_info
struct which is internal to process.c - the function
procinfo_get_process() is added to allow these callers to access process
information.

Signed-off-by: Samuel Mendoza-Jonas <sam@mendozajonas.com>
---
 lib/process/process.c | 42 +++++++++++++++++++++++++++++++++++++-----
 lib/process/process.h |  6 ++++++
 2 files changed, 43 insertions(+), 5 deletions(-)

Patch
diff mbox

diff --git a/lib/process/process.c b/lib/process/process.c
index 6e143e0..e1bcd24 100644
--- a/lib/process/process.c
+++ b/lib/process/process.c
@@ -60,15 +60,22 @@  static struct process_info *get_info(struct process *process)
 	return container_of(process, struct process_info, process);
 }
 
+struct process *procinfo_get_process(struct process_info *procinfo)
+{
+	return &procinfo->process;
+}
+
 /* Read as much as possible into the currently-allocated stdout buffer, and
  * possibly realloc it for the next read
+ * If the line pointer is not NULL, it is set to a duplicate of the latest
+ * output.
  *
  * 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)
+static int process_read_stdout_once(struct process_info *procinfo, char **line)
 {
 	struct process *process = &procinfo->process;
 	int rc, fd, max_len;
@@ -89,6 +96,10 @@  static int process_read_stdout_once(struct process_info *procinfo)
 		return rc;
 	}
 
+	if (line)
+		*line = talloc_strndup(process,
+			       process->stdout_buf + process->stdout_len, rc);
+
 	process->stdout_len += rc;
 	if (process->stdout_len == procinfo->stdout_buf_len - 1) {
 		procinfo->stdout_buf_len *= 2;
@@ -157,7 +168,7 @@  static int process_read_stdout(struct process_info *procinfo)
 		return 0;
 
 	do {
-		rc = process_read_stdout_once(procinfo);
+		rc = process_read_stdout_once(procinfo, NULL);
 	} while (rc > 0);
 
 	process_finish_stdout(procinfo);
@@ -170,7 +181,27 @@  static int process_stdout_cb(void *arg)
 	struct process_info *procinfo = arg;
 	int rc;
 
-	rc = process_read_stdout_once(procinfo);
+	rc = process_read_stdout_once(procinfo, NULL);
+
+	/* if we're going to signal to the waitset that we're done (ie, non-zero
+	 * return value), then the waiters will remove us, so we drop the
+	 * reference */
+	if (rc < 0) {
+		talloc_unlink(procset, procinfo);
+		procinfo->stdout_waiter = NULL;
+		rc = -1;
+	} else {
+		rc = 0;
+	}
+
+	return rc;
+}
+
+int process_stdout_custom(struct process_info *procinfo, char **line)
+{
+	int rc;
+
+	rc = process_read_stdout_once(procinfo, line);
 
 	/* if we're going to signal to the waitset that we're done (ie, non-zero
 	 * return value), then the waiters will remove us, so we drop the
@@ -387,6 +418,7 @@  int process_run_sync(struct process *process)
 int process_run_async(struct process *process)
 {
 	struct process_info *procinfo = get_info(process);
+	waiter_cb stdout_cb;
 	int rc;
 
 	rc = process_run_common(procinfo);
@@ -394,10 +426,10 @@  int process_run_async(struct process *process)
 		return rc;
 
 	if (process->keep_stdout) {
+		stdout_cb = process->custom_stdout_cb ?: process_stdout_cb;
 		procinfo->stdout_waiter = waiter_register_io(procset->waitset,
 						procinfo->stdout_pipe[0],
-						WAIT_IN, process_stdout_cb,
-						procinfo);
+						WAIT_IN, stdout_cb, procinfo);
 		talloc_reference(procset, procinfo);
 	}
 
diff --git a/lib/process/process.h b/lib/process/process.h
index f75f197..30640d8 100644
--- a/lib/process/process.h
+++ b/lib/process/process.h
@@ -23,6 +23,7 @@ 
 
 struct process;
 struct procset;
+struct process_info;
 
 typedef void	(*process_exit_cb)(struct process *);
 
@@ -34,6 +35,7 @@  struct process {
 	bool			add_stderr;
 	process_exit_cb		exit_cb;
 	void			*data;
+	waiter_cb		custom_stdout_cb;
 
 	/* runtime data */
 	pid_t			pid;
@@ -79,4 +81,8 @@  void process_stop_async(struct process *process);
  * exit status */
 bool process_exit_ok(struct process *process);
 
+/* Functions to assist callers using a custom stdout callback */
+struct process *procinfo_get_process(struct process_info *procinfo);
+int process_stdout_custom(struct process_info *procinfo, char **line);
+
 #endif /* PROCESS_H */