+#include <unistd.h>
+#include <sys/select.h>
+
#include "process.h"
#include "debug.h"
-int child_count = 0;
+static int child_count = 0;
+static int parent_count = 0;
+
+int get_child_count(void)
+{
+ return child_count;
+}
+
+int get_parent_count(void)
+{
+ return parent_count;
+}
int do_fork(void)
{
/* reset child's child count */
child_count = 0;
- return 0;
-}
-
-int run(const char *cmd, char *const argv[])
-{
- int child, error;
- if ((child = do_fork()))
- return child;
-
- execvp(cmd, argv);
- error = errno;
- pr_err("Failed to execv command %s: %s\n", cmd, strerror(error));
- exit(1);
+ parent_count++;
return 0;
}
*
* Returns the pid of the executed process
*/
-int run_piped(const char *cmd, char *const argv[], int *readfd, int *writefd)
+int run_piped(const char *cmd, char *const argv[],
+ int *stdinfd, int *stdoutfd, int *stderrfd)
{
- int rfd[2], wfd[2], error, pid;
+ int ifd[2], ofd[2], efd[2], error, pid;
- if (pipe(rfd)) {
+ if (stdinfd && pipe(ifd)) {
error = errno;
pr_err("pipe() failed: %s\n", strerror(error));
return -1;
}
- if (pipe(wfd)) {
+ if (stdoutfd && pipe(ofd)) {
+ error = errno;
+ pr_err("pipe() failed: %s\n", strerror(error));
+ return -1;
+ }
+
+ if (stderrfd && pipe(efd)) {
error = errno;
pr_err("pipe() failed: %s\n", strerror(error));
return -1;
}
pid = do_fork();
- if (pid) {
- close(rfd[1]);
- close(wfd[0]);
- *readfd = rfd[0];
- *writefd = wfd[1];
+ if (pid) { /* Parent side */
+ if (stdinfd) {
+ close(ifd[0]);
+ *stdinfd = ifd[0];
+ }
+
+ if (stdoutfd) {
+ close(ofd[1]);
+ *stdoutfd = ofd[0];
+ }
+
+ if (stderrfd) {
+ close(efd[1]);
+ *stderrfd = efd[0];
+ }
+
return pid;
}
- close(rfd[0]);
- close(wfd[1]);
- dup2(wfd[0], STDIN_FILENO);
- dup2(rfd[1], STDOUT_FILENO);
+ if (stdinfd) {
+ close(ifd[1]);
+ dup2(ifd[0], STDIN_FILENO);
+ }
- /* Now we have redirected both stdin and stdout to parent process */
+ if (stdoutfd) {
+ close(ofd[0]);
+ dup2(ofd[1], STDOUT_FILENO);
+ }
+
+ if (stderrfd) {
+ close(efd[0]);
+ dup2(efd[1], STDERR_FILENO);
+ }
+
+ /* Now we have redirected standard streams to parent process */
execvp(cmd, argv);
error = errno;
pr_err("Failed to execv command %s: %s\n", cmd, strerror(error));
exit(1);
+
return 0;
}
* Returns the pid of the executed process
*/
int run_piped_stream(const char *cmd, char *const argv[],
- FILE **readf, FILE **writef)
+ FILE **stdinf, FILE **stdoutf, FILE **stderrf)
{
- int rfd, wfd, pid, error;
+ int ifd, ofd, efd, pid, error;
+ int *i, *o, *e;
- pid = run_piped(cmd, argv, &rfd, &wfd);
+ if (stdinf)
+ i = &ifd;
+ else
+ i = 0;
+ if (stdoutf)
+ o = &ofd;
+ else
+ o = 0;
+ if (stderrf)
+ e = &efd;
+ else
+ e = 0;
- if (readf) {
- *readf = fdopen(rfd, "r");
- if (*readf == NULL) {
+ pid = run_piped(cmd, argv, i, o, e);
+
+ if (stdinf) {
+ *stdinf = fdopen(ifd, "r");
+ if (*stdinf == NULL) {
+ error = errno;
+ pr_err("Error opening file stream for fd %d: %s\n",
+ ifd, strerror(error));
+ return -1;
+ }
+ }
+
+ if (stdoutf) {
+ *stdoutf = fdopen(ofd, "w");
+ if (*stdoutf == NULL) {
error = errno;
pr_err("Error opening file stream for fd %d: %s\n",
- rfd, strerror(error));
+ ofd, strerror(error));
return -1;
}
}
- if (writef) {
- *writef = fdopen(wfd, "w");
- if (*writef == NULL) {
+ if (stderrf) {
+ *stderrf = fdopen(efd, "w");
+ if (*stderrf == NULL) {
error = errno;
pr_err("Error opening file stream for fd %d: %s\n",
- wfd, strerror(error));
+ efd, strerror(error));
return -1;
}
}
return pid;
}
+
+/*
+ * Forks a child and executes a command to run on parallel
+ */
+
+#define max(a,b) (a) < (b) ? (b) : (a)
+#define BUF_SIZE (128*1024)
+int run(const char *cmd, char *const argv[])
+{
+ int child, error;
+ int ofd, efd;
+ fd_set rfds;
+ int maxfd;
+ char stdoutstr[32], stderrstr[16];
+
+ if ((child = do_fork()))
+ return child;
+
+ child = run_piped(cmd, argv, NULL, &ofd, &efd);
+ snprintf(stdoutstr, 32, "%sstdout", green_color);
+ snprintf(stderrstr, 32, "%sstderr", red_color);
+
+ FD_ZERO(&rfds);
+ FD_SET(ofd, &rfds);
+ FD_SET(efd, &rfds);
+
+ while (1) {
+ char *sptr , *eptr;
+ char rbuf[BUF_SIZE], indent[16] = { ' ' };
+ int bytes;
+ char *typestr;
+
+ indent[get_parent_count()] = 0;
+
+ maxfd = max(ofd, efd);
+ error = select(maxfd, &rfds, NULL, NULL, NULL);
+
+ if (FD_ISSET(ofd, &rfds)) {
+ typestr = stdoutstr;
+ bytes = read(ofd, rbuf, BUF_SIZE);
+ goto print;
+ }
+
+ if (FD_ISSET(efd, &rfds)) {
+ typestr = stderrstr;
+ bytes = read(efd, rbuf, BUF_SIZE);
+ goto print;
+ }
+
+ pr_err("select() returned unknown fd\n");
+ break;
+
+print:
+ if (bytes < 0) {
+ error = errno;
+ pr_err("read() failed: %s\n", strerror(error));
+ break;
+ }
+ if (bytes == 0)
+ break;
+
+ sptr = eptr = rbuf;
+ while(bytes--) {
+ if (*eptr == '\n') {
+ *eptr = 0;
+ printf("%s[%5d %s] %s: %s%s\n", indent,
+ child, cmd, typestr, sptr, normal_color);
+ sptr = eptr;
+ }
+ eptr++;
+ }
+ }
+
+ harvest_zombies(child);
+
+ exit(1);
+ return 0;
+}