Separate program running from waiting

Until now run_program2() was a replacement for system() so it always
waited for the process to end before returning. To make this function
more useful move the waiting code into a separate function and add a
mechanism to expect a specific exit code.

Signed-off-by: Andrew Price <anprice@redhat.com>
diff --git a/blkparse.c b/blkparse.c
index 1555845..447d14c 100644
--- a/blkparse.c
+++ b/blkparse.c
@@ -801,7 +801,7 @@
 		argv[i++] = tl->name;
 	}
 
-	err = run_program2(argc, argv);
+	err = run_program2(argc, argv, 0, NULL);
 	free(argv);
 	return err;
 }
diff --git a/tracers.c b/tracers.c
index f42958b..12efb4e 100644
--- a/tracers.c
+++ b/tracers.c
@@ -36,6 +36,7 @@
 #include "plot.h"
 #include "blkparse.h"
 #include "list.h"
+#include "tracers.h"
 
 extern char **environ;
 
@@ -178,33 +179,47 @@
 	return 0;
 }
 
-int run_program2(int argc, char **argv)
+int wait_program(pid_t pid, const char *pname, int expexit)
+{
+	int status;
+	int ret = 0;
+
+	waitpid(pid, &status, 0);
+	if (WIFEXITED(status)) {
+		ret = WEXITSTATUS(status);
+		if (ret == 127) /* spawnp failed after forking */
+			fprintf(stderr, "Failed to run '%s'\n", pname);
+		else if (ret != expexit)
+			fprintf(stderr, "'%s' exit status %d, expected %d\n",
+			        pname, ret, expexit);
+	} else if (WIFSIGNALED(status)) {
+		fprintf(stderr, "'%s' killed by signal %d\n", pname, WTERMSIG(status));
+		ret = -1;
+	}
+	return ret;
+}
+
+int run_program2(int argc, char **argv, int expexit, pid_t *pid)
 {
 	int i;
 	int err;
-	int status;
-	pid_t pid;
+	pid_t _pid;
 
 	fprintf(stderr, "running");
 	for (i = 0; i < argc; i++)
 		fprintf(stderr, " '%s'", argv[i]);
 	fprintf(stderr, "\n");
 
-	err = posix_spawnp(&pid, argv[0], NULL, NULL, argv, environ);
+	err = posix_spawnp(&_pid, argv[0], NULL, NULL, argv, environ);
 	if (err != 0) {
 		fprintf(stderr, "Could not run '%s': %s\n", argv[0], strerror(err));
-		return -err;
-	}
-	waitpid(pid, &status, 0);
-	if (WIFEXITED(status)) {
-		err = WEXITSTATUS(status);
-		if (err == 127) /* spawnp failed after forking */
-			fprintf(stderr, "Failed to run '%s'\n", argv[0]);
-		else if (err)
-			fprintf(stderr, "'%s' failed with exit status %d\n", argv[0], err);
-	} else if (WIFSIGNALED(status)) {
-		fprintf(stderr, "'%s' killed by signal %d\n", argv[0], WTERMSIG(status));
-		return 1;
+	} else if (expexit >= 0) {
+		err = wait_program(_pid, argv[0], expexit);
+	} else if (!pid) {
+		fprintf(stderr, "Warning: %s (%ld): Not saving pid and not waiting for it.\n",
+		        argv[0], (long)_pid);
+	} else {
+		*pid = _pid;
 	}
 	return err;
 }
diff --git a/tracers.h b/tracers.h
index 0db19b4..d0b8b6b 100644
--- a/tracers.h
+++ b/tracers.h
@@ -18,7 +18,8 @@
 #ifndef __IOWATCH_TRACERS
 #define __IOWATCH_TRACERS
 int run_program(char *str);
-int run_program2(int argc, char **argv);
+int run_program2(int argc, char **argv, int expexit, pid_t *pid);
+int wait_program(pid_t pid, const char *pname, int expexit);
 int stop_blktrace(void);
 int start_blktrace(char **devices, int num_devices, char *trace_name, char *dest);
 int start_mpstat(char *trace_name);