about summary refs log tree commit diff
path: root/lib/libsystem.c
diff options
context:
space:
mode:
authorgiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2007-08-25 22:42:49 +0000
committergiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2007-08-25 22:42:49 +0000
commita7df43157443608716ad22badc18e5ba5f26e0f3 (patch)
treea0f53c4aecc1555c16a4a8376362a25636395069 /lib/libsystem.c
parentc16ec0e052580f85d9241f48580ce6e7183abca9 (diff)
downloadnetpbm-mirror-a7df43157443608716ad22badc18e5ba5f26e0f3.tar.gz
netpbm-mirror-a7df43157443608716ad22badc18e5ba5f26e0f3.tar.xz
netpbm-mirror-a7df43157443608716ad22badc18e5ba5f26e0f3.zip
Add pm_system_lp(), pm_system_vp()
git-svn-id: http://svn.code.sf.net/p/netpbm/code/trunk@383 9d0c8265-081b-0410-96cb-a4ca84ce46f8
Diffstat (limited to 'lib/libsystem.c')
-rw-r--r--lib/libsystem.c242
1 files changed, 163 insertions, 79 deletions
diff --git a/lib/libsystem.c b/lib/libsystem.c
index 59e05a5f..f0a1996a 100644
--- a/lib/libsystem.c
+++ b/lib/libsystem.c
@@ -14,6 +14,7 @@
 =============================================================================*/
 #define _XOPEN_SOURCE
 
+#include <stdarg.h>
 #include <unistd.h>
 #include <stdlib.h>
 #include <stdio.h>
@@ -22,6 +23,8 @@
 #include <signal.h>
 #include <sys/wait.h>
 
+#include "pm_c_util.h"
+#include "mallocvar.h"
 #include "pm.h"
 #include "pm_system.h"
 
@@ -30,21 +33,25 @@
 
 
 static void
-execProgram(const char * const shellCommand,
-            int          const inputPipeFd,
-            int          const outputPipeFd) {
+execProgram(const char *  const progName,
+            const char ** const argArray,
+            int           const stdinFd,
+            int           const stdoutFd) {
 /*----------------------------------------------------------------------------
-   Run the shell command 'shellCommand', supplying to the shell
-   'inputPipeFd' as its Standard Input and 'outputPipeFd' as its 
+   Run the program 'progName' with arguments argArray[], in a child process
+   with 'stdinFd' as its Standard Input and 'stdoutFd' as its
    Standard Output.
 
    But leave Standard Input and Standard Output as we found them.
+
+   Note that stdinFd or stdoutFd may actually be Standard Input and
+   Standard Output already.
 -----------------------------------------------------------------------------*/
     int stdinSaveFd, stdoutSaveFd;
     int rc;
 
-    /* Make inputPipeFd Standard Input.
-       Make outputPipeFd Standard Output.
+    /* Make stdinFd Standard Input.
+       Make stdoutFd Standard Output.
     */
     stdinSaveFd = dup(STDIN);
     stdoutSaveFd = dup(STDOUT);
@@ -52,10 +59,10 @@ execProgram(const char * const shellCommand,
     close(STDIN);
     close(STDOUT);
 
-    dup2(inputPipeFd, STDIN);
-    dup2(outputPipeFd, STDOUT);
+    dup2(stdinFd, STDIN);
+    dup2(stdoutFd, STDOUT);
 
-    rc = execl("/bin/sh", "sh", "-c", shellCommand, NULL);
+    rc = execvp(progName, (char **)argArray);
 
     close(STDIN);
     close(STDOUT);
@@ -65,10 +72,12 @@ execProgram(const char * const shellCommand,
     close(stdoutSaveFd);
 
     if (rc < 0)
-        pm_error("Unable to exec the shell.  Errno=%d (%s)",
-                 errno, strerror(errno));
+        pm_error("Unable to exec '%s' "
+                 "(i.e. the program did not run at all).  "
+                 "execvp() errno=%d (%s)",
+                 progName, errno, strerror(errno));
     else
-        pm_error("INTERNAL ERROR.  execl() returns, but does not fail.");
+        pm_error("INTERNAL ERROR.  execvp() returns, but does not fail.");
 }
 
 
@@ -108,31 +117,47 @@ createPipeFeeder(void          pipeFeederRtn(int, void *),
 
 
 static void
-spawnProcessor(const char * const shellCommand, 
-               int          const stdinFd,
-               int *        const stdoutFdP,
-               pid_t *      const pidP) {
+spawnProcessor(const char *  const progName,
+               const char ** const argArray,
+               int           const stdinFd,
+               int *         const stdoutFdP,
+               pid_t *       const pidP) {
 /*----------------------------------------------------------------------------
-   Create a process to run a shell that runs command 'shellCommand'.
-   Pass file descriptor 'stdinFd' to the shell as Standard Input.
-   Set up a pipe and pass it to the shell as Standard Output.  Return
-   as *stdoutFdP the file descriptor of the other end of that pipe,
-   from which Caller can suck the shell's Standard Output.
+   Create a process to run program 'progName' with arguments
+   argArray[] (terminated by NULL element).  Pass file descriptor
+   'stdinFd' to the shell as Standard Input.
+
+   if 'stdoutFdP' is NULL, have that process write its Standard Output to
+   the current process' Standard Output.
+
+   If 'stdoutFdP' is non-NULL, set up a pipe and pass it to the new
+   process as Standard Output.  Return as *stdoutFdP the file
+   descriptor of the other end of that pipe, from which Caller can
+   suck the program's Standard Output.
 -----------------------------------------------------------------------------*/
+    bool const pipeStdout = !stdoutFdP;
     int stdoutpipe[2];
     pid_t rc;
-        
-    pipe(stdoutpipe);
+
+    if (pipeStdout)
+        pipe(stdoutpipe);
 
     rc = fork();
     if (rc < 0) {
         pm_error("fork() of processor process failed.  errno=%d (%s)\n", 
                  errno, strerror(errno));
     } else if (rc == 0) {
-        /* The second child */
-        close(stdoutpipe[0]);
+        /* The program child */
+
+        int stdoutFd;
+        
+        if (pipeStdout) {
+            close(stdoutpipe[0]);
+            stdoutFd = stdoutpipe[1];
+        } else
+            stdoutFd = STDOUT;
 
-        execProgram(shellCommand, stdinFd, stdoutpipe[1]);
+        execProgram(progName, argArray, stdinFd, stdoutFd);
 
         close(stdinFd);
         close(stdoutpipe[1]);
@@ -140,8 +165,11 @@ spawnProcessor(const char * const shellCommand,
     } else {
         /* The parent */
         pid_t const processorpid = rc;
-        close(stdoutpipe[1]);
-        *stdoutFdP = stdoutpipe[0];
+
+        if (pipeStdout) {
+            close(stdoutpipe[1]);
+            *stdoutFdP = stdoutpipe[0];
+        }
         *pidP = processorpid;
     }
 }
@@ -191,94 +219,150 @@ cleanupFeederProcess(pid_t const feederPid) {
 
 
 void
-pm_system(void stdinFeeder(int, void *),
-          void *          const feederParm,
-          void stdoutAccepter(int, void *),
-          void *          const accepterParm,
-          const char *    const shellCommand) {
+pm_system_vp(const char *    const progName,
+             const char **   const argArray,
+             void stdinFeeder(int, void *),
+             void *          const feederParm,
+             void stdoutAccepter(int, void *),
+             void *          const accepterParm) {
 /*----------------------------------------------------------------------------
-   Run a shell and have it run command 'shellCommand'.  Feed its
-   Standard Input with a pipe, which is fed by the routine
-   'stdinFeeder' with parameter 'feederParm'.  Process its Standard
-   Output with the routine 'stdoutAccepter' with parameter 'accepterParm'.
+   Run a program in a child process.  Feed its Standard Input with a
+   pipe, which is fed by the routine 'stdinFeeder' with parameter
+   'feederParm'.  Process its Standard Output with the routine
+   'stdoutAccepter' with parameter 'accepterParm'.
 
-   But if 'stdinFeeder' is NULL, just feed the shell our own Standard
+   But if 'stdinFeeder' is NULL, just feed the program our own Standard
    Input.  And if 'stdoutFeeder' is NULL, just send its Standard Output
    to our own Standard Output.
 -----------------------------------------------------------------------------*/
 
     /* If 'stdinFeeder' is non-NULL, we create a child process to run
-       'stdinFeeder' and create a pipe between from that process as the
-       shell's Standard Input.
+       'stdinFeeder' and create a pipe from that process as the
+       program's Standard Input.
 
-       If 'stdoutFeeder' is non-NULL, we create a child process to run
-       the shell and create a pipe between the shell's Standard Output
-       and the current process, and then the current process runs
-       'stdoutAccepter' to read the data from that pipe.
+       We create another child process to run the program.
+
+       If 'stdoutFeeder' is non-NULL, we create a pipe between the
+       program process and the current process and have the program
+       write its Standard Output to that pipe.  The current process
+       runs 'stdoutAccepter' to read the data from that pipe.
        
-       But if 'stdoutFeeder' is NULL, we just run the shell in the
-       current process.
+       But if 'stdoutFeeder' is NULL, we just tell the program process
+       to write to the current process' Standard Output.
 
-       So there can be 1, 2, or 3 processes involved depending on 
-       parameters.
+       So there are two processes when stdinFeeder is NULL and three when
+       stdinFeeder is non-null.
     */
     
-    int shellStdinFd;
+    int progStdinFd;
     pid_t feederPid;
+    pid_t processorPid;
 
     if (stdinFeeder) 
-        createPipeFeeder(stdinFeeder, feederParm, &shellStdinFd, &feederPid);
+        createPipeFeeder(stdinFeeder, feederParm, &progStdinFd, &feederPid);
     else {
-        shellStdinFd = STDIN;
+        progStdinFd = STDIN;
         feederPid = 0;
     }
 
     if (stdoutAccepter) {
-        int shellStdoutFd;
-        pid_t processorPid;
+        int progStdoutFd;
 
-        /* Make a child process to run the shell and pipe back to us its
+        /* Make a child process to run the program and pipe back to us its
            Standard Output 
         */
-        spawnProcessor(shellCommand, shellStdinFd, 
-                       &shellStdoutFd, &processorPid);
+        spawnProcessor(progName, argArray, progStdinFd, 
+                       &progStdoutFd, &processorPid);
 
-        /* The shell process has cloned our 'shellStdinFd'; we have no
+        /* The child process has cloned our 'progStdinFd'; we have no
            more use for our copy.
         */
-        close(shellStdinFd);
-        /* Dispose of the stdout from that shell */
-        (*stdoutAccepter)(shellStdoutFd, accepterParm);
-        close(shellStdoutFd);
-
-        cleanupProcessorProcess(processorPid);
+        close(progStdinFd);
+        /* Dispose of the stdout from that child */
+        (*stdoutAccepter)(progStdoutFd, accepterParm);
+        close(progStdoutFd);
     } else {
-        /* Run a child process for the shell that sends its Standard Output
+        /* Run a child process for the program that sends its Standard Output
            to our Standard Output
         */
-        int const stdinSaveFd = dup(STDIN);
-        int rc;
+        spawnProcessor(progName, argArray, STDIN, NULL, &processorPid);
+    }
 
-        dup2(shellStdinFd, STDIN);
-        
-        rc = system(shellCommand);
+    cleanupProcessorProcess(processorPid);
+
+    if (feederPid) 
+        cleanupFeederProcess(feederPid);
+}
+
+
+
+void
+pm_system_lp(const char *    const progName,
+             void stdinFeeder(int, void *),
+             void *          const feederParm,
+             void stdoutAccepter(int, void *),
+             void *          const accepterParm,
+             ...) {
+/*----------------------------------------------------------------------------
+  same as pm_system_vp() except with arguments as variable arguments
+  instead of an array.
+-----------------------------------------------------------------------------*/
+    va_list args;
+    bool endOfArgs;
+    const char ** argArray;
+    unsigned int n;
+
+    va_start(args, accepterParm);
 
-        close(STDIN);
-        dup2(stdinSaveFd, STDIN);
+    endOfArgs = FALSE;
+    argArray = NULL;
+
+    for (endOfArgs = FALSE, argArray = NULL, n = 0;
+         !endOfArgs;
+        ) {
+        const char * const arg = va_arg(args, const char *);
         
-        if (rc < 0)
-            pm_error("Unable to invoke the shell.  Errno=%d (%s)",
-                     errno, strerror(errno));
-        else if (rc != 0)
-            pm_message("WARNING: Shell process completion code = %d", rc);
+        REALLOCARRAY(argArray, n+1);
+
+        argArray[n++] = arg;
+
+        if (!arg)
+            endOfArgs = TRUE;
     }
 
-    if (feederPid) 
-        cleanupFeederProcess(feederPid);
+    va_end(args);
+
+    pm_system_vp(progName, argArray,
+                 stdinFeeder, feederParm, stdoutAccepter, accepterParm);
+
+    free(argArray);
 }
 
 
 
+void
+pm_system(void stdinFeeder(int, void *),
+          void *          const feederParm,
+          void stdoutAccepter(int, void *),
+          void *          const accepterParm,
+          const char *    const shellCommand) {
+/*----------------------------------------------------------------------------
+   Run a shell and have it run command 'shellCommand'.  Feed its
+   Standard Input with a pipe, which is fed by the routine
+   'stdinFeeder' with parameter 'feederParm'.  Process its Standard
+   Output with the routine 'stdoutAccepter' with parameter 'accepterParm'.
+
+   But if 'stdinFeeder' is NULL, just feed the shell our own Standard
+   Input.  And if 'stdoutFeeder' is NULL, just send its Standard Output
+   to our own Standard Output.
+-----------------------------------------------------------------------------*/
+
+    pm_system_lp("/bin/sh", 
+                 stdinFeeder, feederParm, stdoutAccepter, accepterParm,
+                 "sh", "-c", shellCommand, NULL);
+}
+
+
 
 void
 pm_feed_from_memory(int    const pipeToFeedFd,