]> git.itanic.dy.fi Git - rrdd/commitdiff
Improve piped process executing
authorTimo Kokkonen <kaapeli@ee.oulu.fi>
Sun, 18 May 2008 17:07:18 +0000 (20:07 +0300)
committerTimo Kokkonen <kaapeli@ee.oulu.fi>
Sun, 18 May 2008 17:07:18 +0000 (20:07 +0300)
Allow all standard streams to be piped back to the parent
process. Modifies also the run() function to print the pid of the
process which printed the output.

parser.c
process.c
process.h

index 9476494f9d120493c39d52ae97065a6ac181a419..0cb616e91b89ab45f0afd82ffea68ba58e6a4986 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -111,12 +111,12 @@ int digitemp_parser(char *data)
 {
        const char digitemp_cmd[] = "/usr/bin/digitemp";
        char *const digitemp_args[] = { "", "-o2", "-a", "-q", 0 };
-       FILE *readf, *writef;
+       FILE *readf;
        int pid;
        char buf[1024], *bptr = buf;
        float t1, t2, t3;
 
-       pid = run_piped_stream(digitemp_cmd, digitemp_args, &readf, &writef);
+       pid = run_piped_stream(digitemp_cmd, digitemp_args, 0, &readf, 0);
        if (pid < 0) {
                pr_err("Failed to parse digitemp");
                sprintf(data, "U:U");
index 3c0f1190c6b91e087a7b2986fd2cbc7eceece7ed..068550f4abaf15d349541db0e1033caf780082da 100644 (file)
--- a/process.c
+++ b/process.c
@@ -1,7 +1,21 @@
+#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)
 {
@@ -21,19 +35,7 @@ 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;
 }
 
@@ -69,41 +71,70 @@ int harvest_zombies(int pid)
  *
  * 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;
 }
 
@@ -114,31 +145,133 @@ int run_piped(const char *cmd, char *const argv[], int *readfd, int *writefd)
  * 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;
+}
index 3782d84550701e9e28eb35cad183bba936f4b657..9b8e40c0f272d6b5c41976c1eab93a8dee130392 100644 (file)
--- a/process.h
+++ b/process.h
@@ -9,11 +9,16 @@
 #include <error.h>
 #include <errno.h>
 
+int get_child_count(void);
+int get_parent_count(void);
+
 int do_fork(void);
 int run(const char *p, char *const argv[]);
 int harvest_zombies(int pid);
-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 run_piped_stream(const char *cmd, char *const argv[],
-                    FILE **readf, FILE **writef);
+                    FILE **stdinf, FILE **stdoutf, FILE **stderrf);
+
 
 #endif