From d4c3d5293371216acaf2236cc3e49003204d175f Mon Sep 17 00:00:00 2001 From: giraffedata Date: Sat, 7 May 2016 16:52:08 +0000 Subject: 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 --- lib/libsystem.c | 259 ++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 215 insertions(+), 44 deletions(-) (limited to 'lib/libsystem.c') 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; } + + + -- cgit 1.4.1