about summary refs log tree commit diff
path: root/lib
diff options
context:
space:
mode:
authorgiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2016-05-07 16:52:08 +0000
committergiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2016-05-07 16:52:08 +0000
commitd4c3d5293371216acaf2236cc3e49003204d175f (patch)
tree8ef6987b4e5a268c8f18cd0b8998dbe36f40a458 /lib
parent47a0786034bdfc849bb5aacd55640862252d9bb4 (diff)
downloadnetpbm-mirror-d4c3d5293371216acaf2236cc3e49003204d175f.tar.gz
netpbm-mirror-d4c3d5293371216acaf2236cc3e49003204d175f.tar.xz
netpbm-mirror-d4c3d5293371216acaf2236cc3e49003204d175f.zip
Add pm_system2(), pm_system2_lp(), pm_system2_vp()
git-svn-id: http://svn.code.sf.net/p/netpbm/code/trunk@2759 9d0c8265-081b-0410-96cb-a4ca84ce46f8
Diffstat (limited to 'lib')
-rw-r--r--lib/libsystem.c259
-rw-r--r--lib/pm_system.h47
2 files changed, 260 insertions, 46 deletions
diff --git a/lib/libsystem.c b/lib/libsystem.c
index 80f51256..e13a20ac 100644
--- a/lib/libsystem.c
+++ b/lib/libsystem.c
@@ -1,12 +1,17 @@
 /*=============================================================================
                                  pm_system
 ===============================================================================
-   This is the library subroutine pm_system().  It is just like Standard C
-   Library system(), except that you can supply routines for it to run to
-   generate the Standard Input for the executed shell command and to accept
-   the Standard Output from it.  system(), by contrast, always sets up the
-   current Standard Input and Standard Output as the Standard Input and
-   Standard Output of the shell command.
+   This is the pm_system() family of subroutines.
+
+   pm_system() is just like Standard C Library system(), except that you can
+   supply routines for it to run to generate the Standard Input for the
+   executed shell command and to accept the Standard Output from it.
+   system(), by contrast, always sets up the current Standard Input and
+   Standard Output as the Standard Input and Standard Output of the shell
+   command.
+
+   pm_system_lp() and pm_system_vp() are similar, but exec an OS-level program
+   (i.e. exec a program) rather than run a shell command.
 
    By Bryan Henderson, San Jose CA  2002.12.14.
 
@@ -26,6 +31,7 @@
 
 #include "netpbm/pm_c_util.h"
 #include "netpbm/mallocvar.h"
+#include "netpbm/nstring.h"
 #include "pm.h"
 #include "pm_system.h"
 
@@ -164,7 +170,7 @@ spawnProcessor(const char *  const progName,
 /*----------------------------------------------------------------------------
    Create a process to run program 'progName' with arguments
    argArray[] (terminated by NULL element).  Pass file descriptor
-   'stdinFd' to the shell as Standard Input.
+   'stdinFd' to the process as Standard Input.
 
    if 'stdoutFdP' is NULL, have that process write its Standard Output to
    the current process' Standard Output.
@@ -313,26 +319,32 @@ signalName(unsigned int const signalClass) {
 
 
 
-static void
-cleanupProcessorProcess(pid_t const processorPid) {
-
-    int terminationStatus;
-    waitpid(processorPid, &terminationStatus, 0);
+const char *
+pm_termStatusDesc(int const termStatus) {
+/*----------------------------------------------------------------------------
+   English description of  process termination status 'termStatus'.
+-----------------------------------------------------------------------------*/
+    const char * retval;
 
-    if (WIFEXITED(terminationStatus)) {
-        int const exitStatus = WEXITSTATUS(terminationStatus);
+    if (WIFEXITED(termStatus)) {
+        int const exitStatus = WEXITSTATUS(termStatus);
 
-        if (exitStatus != 0)
-            pm_message("Shell process exited with abnormal exit status %u.  ",
-                       exitStatus);
-    } else if (WIFSIGNALED(terminationStatus)) {
-        pm_message("Shell process was killed by a Class %u (%s) signal.",
-                   WTERMSIG(terminationStatus),
-                   signalName(WTERMSIG(terminationStatus)));
+        if (exitStatus == 0)
+            pm_asprintf(&retval, "Process exited normally");
+        else
+            pm_asprintf(&retval,
+                        "Process exited with abnormal exit status %u.  ",
+                        exitStatus);
+    } else if (WIFSIGNALED(termStatus)) {
+        pm_asprintf(&retval, "Process was killed by a Class %u (%s) signal.",
+                    WTERMSIG(termStatus),
+                    signalName(WTERMSIG(termStatus)));
     } else {
-        pm_message("Shell process died, but its termination status "
-                   "0x%x  doesn't make sense", terminationStatus);
+        pm_asprintf(&retval, "Process died, but its termination status "
+                    "0x%x  doesn't make sense", termStatus);
     }
+
+    return retval;
 }
 
 
@@ -347,7 +359,7 @@ cleanupFeederProcess(pid_t const feederPid) {
         if (WTERMSIG(status) == SIGPIPE)
             pm_message("WARNING: "
                        "Standard Input feeder process was terminated by a "
-                       "SIGPIPE signal because the shell command closed its "
+                       "SIGPIPE signal because the program closed its "
                        "Standard Input before the Standard Input feeder was "
                        "through feeding it.");
         else
@@ -369,12 +381,13 @@ cleanupFeederProcess(pid_t const feederPid) {
 
 
 void
-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) {
+pm_system2_vp(const char *    const progName,
+              const char **   const argArray,
+              void stdinFeeder(int, void *),
+              void *          const feederParm,
+              void stdoutAccepter(int, void *),
+              void *          const accepterParm,
+              int *           const termStatusP) {
 /*----------------------------------------------------------------------------
    Run a program in a child process.  Feed its Standard Input with a
    pipe, which is fed by the routine 'stdinFeeder' with parameter
@@ -387,6 +400,9 @@ pm_system_vp(const char *    const progName,
 
    Run the program 'progName' with arguments argArray[] (terminated by NULL
    element).  That includes arg0.
+
+   Return as *termStatusP the termination status of the processor process
+   (the one running the program named 'progName').
 -----------------------------------------------------------------------------*/
     /* If 'stdinFeeder' is non-NULL, we create a child process to run
        'stdinFeeder' and create a pipe from that process as the
@@ -409,6 +425,7 @@ pm_system_vp(const char *    const progName,
     int progStdinFd;
     pid_t feederPid;
     pid_t processorPid;
+    int termStatus;
 
     if (stdinFeeder) 
         createPipeFeeder(stdinFeeder, feederParm, &progStdinFd, &feederPid);
@@ -440,10 +457,118 @@ pm_system_vp(const char *    const progName,
         spawnProcessor(progName, argArray, progStdinFd, NULL, &processorPid);
     }
 
-    cleanupProcessorProcess(processorPid);
+    waitpid(processorPid, &termStatus, 0);
 
     if (feederPid) 
         cleanupFeederProcess(feederPid);
+
+    *termStatusP = termStatus;
+}
+
+
+
+void
+pm_system2_lp(const char *    const progName,
+              void stdinFeeder(int, void *),
+              void *          const feederParm,
+              void stdoutAccepter(int, void *),
+              void *          const accepterParm,
+              int *           const termStatusP,
+              ...) {
+/*----------------------------------------------------------------------------
+  Same as pm_system_vp() except with arguments as variable arguments
+  instead of an array.
+
+  N.B. the first variable argument is the program's arg 0; the last
+  variable argument must be NULL.
+-----------------------------------------------------------------------------*/
+    va_list args;
+    bool endOfArgs;
+    const char ** argArray;
+    unsigned int n;
+
+    va_start(args, termStatusP);
+
+    endOfArgs = FALSE;
+    argArray = NULL;
+
+    for (endOfArgs = FALSE, argArray = NULL, n = 0;
+         !endOfArgs;
+        ) {
+        const char * const arg = va_arg(args, const char *);
+        
+        REALLOCARRAY(argArray, n+1);
+
+        argArray[n++] = arg;
+
+        if (!arg)
+            endOfArgs = TRUE;
+    }
+
+    va_end(args);
+
+    pm_system2_vp(progName, argArray,
+                  stdinFeeder, feederParm, stdoutAccepter, accepterParm,
+                  termStatusP);
+
+    free(argArray);
+}
+
+
+
+void
+pm_system2(void stdinFeeder(int, void *),
+           void *          const feederParm,
+           void stdoutAccepter(int, void *),
+           void *          const accepterParm,
+           const char *    const shellCommand,
+           int *           const termStatusP) {
+/*----------------------------------------------------------------------------
+   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.
+
+   Return as *termStatusP the termination status of the processor process
+   (the one running the program named 'progName').
+-----------------------------------------------------------------------------*/
+    pm_system2_lp("/bin/sh", 
+                  stdinFeeder, feederParm, stdoutAccepter, accepterParm,
+                  termStatusP,
+                  "sh", "-c", shellCommand, NULL);
+}
+
+
+
+void
+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) {
+/*----------------------------------------------------------------------------
+   Same as pm_system2_vp(), except instead of returning the termination
+   status, we just issue a message (pm_message) describing it.
+-----------------------------------------------------------------------------*/
+    int termStatus;
+
+    pm_system2_vp(progName, argArray,
+                  stdinFeeder, feederParm,
+                  stdoutAccepter, accepterParm,
+                  &termStatus);
+
+    if (termStatus != 0) {
+        const char * const msg = pm_termStatusDesc(termStatus);
+
+        pm_message("%s", msg);
+
+        pm_strfree(msg);
+    }
 }
 
 
@@ -502,19 +627,62 @@ pm_system(void stdinFeeder(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.
+   Same as pm_system2(), except instead of returning the termination status,
+   we just issue a message (pm_message) describing it.
 -----------------------------------------------------------------------------*/
+    int termStatus;
+
+    pm_system2(stdinFeeder, feederParm, stdoutAccepter, accepterParm,
+               shellCommand,
+               &termStatus);
+
+    if (termStatus != 0) {
+        const char * const msg = pm_termStatusDesc(termStatus);
+
+        pm_message("%s", msg);
+
+        pm_strfree(msg);
+    }
+}
+
+
+
+void
+pm_feed_null(int    const pipeToFeedFd,
+             void * const feederParm) {
+
+}
 
-    pm_system_lp("/bin/sh", 
-                 stdinFeeder, feederParm, stdoutAccepter, accepterParm,
-                 "sh", "-c", shellCommand, NULL);
+
+
+void
+pm_accept_null(int    const pipetosuckFd,
+               void * const accepterParm ) {
+
+    size_t const bufferSize = 4096;
+
+    unsigned char * buffer;
+
+    MALLOCARRAY(buffer, bufferSize);
+
+    if (buffer) {
+        bool eof;
+
+        for (eof = false; !eof; ) {
+            ssize_t rc;
+
+            rc = read(pipetosuckFd, buffer, bufferSize);
+
+            if (rc < 0) {
+                /* No way to report the problem; just say we're done */
+                eof = true;
+            } else if (rc == 0)
+                /* eof */
+                eof = true;
+        }
+        free(buffer);
+    }
+    close(pipetosuckFd);
 }
 
 
@@ -523,7 +691,7 @@ void
 pm_feed_from_memory(int    const pipeToFeedFd,
                     void * const feederParm) {
 
-    struct bufferDesc * const inputBufferP = feederParm;
+    pm_bufferDesc * const inputBufferP = feederParm;
     
     FILE * const outFileP = fdopen(pipeToFeedFd, "w");
     
@@ -547,7 +715,7 @@ void
 pm_accept_to_memory(int             const pipetosuckFd,
                     void *          const accepterParm ) {
 
-    struct bufferDesc * const outputBufferP = accepterParm;
+    pm_bufferDesc * const outputBufferP = accepterParm;
     
     FILE * const inFileP = fdopen(pipetosuckFd, "r");
 
@@ -561,3 +729,6 @@ pm_accept_to_memory(int             const pipetosuckFd,
     if (outputBufferP->bytesTransferredP)
         *(outputBufferP->bytesTransferredP) = bytesTransferred;
 }
+
+
+
diff --git a/lib/pm_system.h b/lib/pm_system.h
index a7560f48..dfcd5b3f 100644
--- a/lib/pm_system.h
+++ b/lib/pm_system.h
@@ -10,6 +10,32 @@ extern "C" {
 
 
 void
+pm_system2_vp(const char *    const progName,
+              const char **   const argArray,
+              void stdinFeeder(int, void *),
+              void *          const feederParm,
+              void stdoutAccepter(int, void *),
+              void *          const accepterParm,
+              int *           const termStatusP);
+
+void
+pm_system2_lp(const char *    const progName,
+              void stdinFeeder(int, void *),
+              void *          const feederParm,
+              void stdoutAccepter(int, void *),
+              void *          const accepterParm,
+              int *           const termStatusP,
+              ...);
+
+void
+pm_system2(void                  stdinFeeder(int, void *),
+           void *          const feederParm,
+           void                  stdoutAccepter(int, void *),
+           void *          const accepterParm,
+           const char *    const shellCommand,
+           int *           const termStatusP);
+
+void
 pm_system_vp(const char *    const progName,
              const char **   const argArray,
              void stdinFeeder(int, void *),
@@ -32,6 +58,21 @@ pm_system(void                  stdinFeeder(int, void *),
           void *          const accepterParm,
           const char *    const shellCommand);
 
+const char *
+pm_termStatusDesc(int const termStatus);
+
+
+/* The following are Standard Input feeders and Standard Output accepters
+   for pm_system() etc.
+*/
+void
+pm_feed_null(int    const pipeToFeedFd,
+             void * const feederParm);
+
+void
+pm_accept_null(int    const pipetosuckFd,
+               void * const accepterParm);
+
 struct bufferDesc {
     /* This is just a parameter for the routines below */
     unsigned int    size;
@@ -40,9 +81,11 @@ struct bufferDesc {
 };
 
 
-/* The following are a Standard Input feeder and a Standard Output accepter
-   for pm_system().  
+/* The struct name "bufferDesc", without the "pm" namespace, is an unfortunate
+   historical accident.
 */
+typedef struct bufferDesc pm_bufferDesc;
+
 void
 pm_feed_from_memory(int    const pipeToFeedFd,
                     void * const feederParm);