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. Run the program 'progName' with arguments argArray[] (terminated by NULL element). That includes arg0. -----------------------------------------------------------------------------*/ /* 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. 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 this process, and then this process runs 'stdoutAccepter' to read the data from that pipe. But if 'stdoutFeeder' is NULL, we just run the shell in this process. So there can be 1, 2, or 3 processes involved depending on parameters. */ int shellStdinFd; pid_t feederPid; if (stdinFeeder) createPipeFeeder(stdinFeeder, feederParm, &shellStdinFd, &feederPid); else { shellStdinFd = STDIN; feederPid = 0; } if (stdoutAccepter) { int shellStdoutFd; pid_t processorPid; /* Make a child process to run the shell and pipe back to us its Standard Output */ spawnProcessor(shellCommand, shellStdinFd, &shellStdoutFd, &processorPid); /* The shell process has cloned our 'shellStdinFd'; we have no more use for our copy. */ close(shellStdinFd); /* Dispose of the stdout from that shell */ (*stdoutAccepter)(shellStdoutFd, accepterParm); close(shellStdoutFd); cleanupProcessorProcess(processorPid); } else { /* Run a child process for the shell that sends its Standard Output to our Standard Output */ int const stdinSaveFd = dup(STDIN); int rc; dup2(shellStdinFd, STDIN); rc = system(shellCommand); close(STDIN); dup2(stdinSaveFd, STDIN); 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); } if (feederPid) cleanupFeederProcess(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) { /*---------------------------------------------------------------------------- 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 program our own Standard Input. And if 'stdoutFeeder' is NULL, just send its Standard Output to our own Standard Output. Run the program 'progName' with arguments argArray[] (terminated by NULL element). That includes arg0. -----------------------------------------------------------------------------*/ /* If 'stdinFeeder' is non-NULL, we create a child process to run 'stdinFeeder' and create a pipe from that process as the program's Standard Input. 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 tell the program process to write to the current process' Standard Output. So there are two processes when stdinFeeder is NULL and three when stdinFeeder is non-null. */ int progStdinFd; pid_t feederPid; pid_t processorPid; if (stdinFeeder) createPipeFeeder(stdinFeeder, feederParm, &progStdinFd, &feederPid); else { progStdinFd = STDIN; feederPid = 0; } if (stdoutAccepter) { int progStdoutFd; /* Make a child process to run the program and pipe back to us its Standard Output */ spawnProcessor(progName, argArray, progStdinFd, &progStdoutFd, &processorPid); /* The child process has cloned our 'progStdinFd'; we have no more use for our copy. */ close(progStdinFd); /* Dispose of the stdout from that child */ (*stdoutAccepter)(progStdoutFd, accepterParm); close(progStdoutFd); } else { /* Run a child process for the program that sends its Standard Output to our Standard Output */ spawnProcessor(progName, argArray, progStdinFd, NULL, &processorPid); } cleanupProcessorProcess(processorPid); if (feederPid) cleanupFeederProcess(feederPid); }