From 802601b6067198e175b34cb7a5133f5b491b4f2f Mon Sep 17 00:00:00 2001 From: Brad King Date: Tue, 16 Dec 2003 17:20:01 -0500 Subject: [PATCH] ENH: Added SetPipeShared method to allow stdout and stderr pipes to be shared with the parent process. --- Source/kwsys/Process.h.in | 10 ++++ Source/kwsys/ProcessUNIX.c | 95 +++++++++++++++++++++++++++++++++---- Source/kwsys/ProcessWin32.c | 81 ++++++++++++++++++++++++++++--- 3 files changed, 171 insertions(+), 15 deletions(-) diff --git a/Source/kwsys/Process.h.in b/Source/kwsys/Process.h.in index 944d92c9c..83e3060aa 100644 --- a/Source/kwsys/Process.h.in +++ b/Source/kwsys/Process.h.in @@ -31,6 +31,7 @@ #define kwsysProcess_SetTimeout kwsys(Process_SetTimeout) #define kwsysProcess_SetWorkingDirectory kwsys(Process_SetWorkingDirectory) #define kwsysProcess_SetPipeFile kwsys(Process_SetPipeFile) +#define kwsysProcess_SetPipeShared kwsys(Process_SetPipeShared) #define kwsysProcess_Option_HideWindow kwsys(Process_Option_HideWindow) #define kwsysProcess_GetOption kwsys(Process_GetOption) #define kwsysProcess_SetOption kwsys(Process_SetOption) @@ -129,6 +130,14 @@ kwsysEXPORT int kwsysProcess_SetWorkingDirectory(kwsysProcess* cp, kwsysEXPORT int kwsysProcess_SetPipeFile(kwsysProcess* cp, int pipe, const char* file); +/** + * Set whether the given pipe in the child is shared with the parent + * process. The default is no for Pipe_STDOUT and Pipe_STDERR and yes + * for Pipe_STDIN. + */ +kwsysEXPORT void kwsysProcess_SetPipeShared(kwsysProcess* cp, int pipe, + int shared); + /** * Get/Set a platform-specific option. Possible options are: * @@ -301,6 +310,7 @@ kwsysEXPORT void kwsysProcess_Kill(kwsysProcess* cp); # undef kwsysProcess_SetTimeout # undef kwsysProcess_SetWorkingDirectory # undef kwsysProcess_SetPipeFile +# undef kwsysProcess_SetPipeShared # undef kwsysProcess_Option_HideWindow # undef kwsysProcess_GetOption # undef kwsysProcess_SetOption diff --git a/Source/kwsys/ProcessUNIX.c b/Source/kwsys/ProcessUNIX.c index ec1e9f815..2abc8e1ef 100644 --- a/Source/kwsys/ProcessUNIX.c +++ b/Source/kwsys/ProcessUNIX.c @@ -169,6 +169,11 @@ struct kwsysProcess_s char* PipeFileSTDOUT; char* PipeFileSTDERR; + /* Whether each pipe is shared with the parent process. */ + int PipeSharedSTDIN; + int PipeSharedSTDOUT; + int PipeSharedSTDERR; + /* The real working directory of this process. */ int RealWorkingDirectoryLength; char* RealWorkingDirectory; @@ -184,7 +189,13 @@ kwsysProcess* kwsysProcess_New() return 0; } memset(cp, 0, sizeof(kwsysProcess)); + + /* Share stdin with the parent process by default. */ + cp->PipeSharedSTDIN = 1; + + /* Set initial status. */ cp->State = kwsysProcess_State_Starting; + return cp; } @@ -393,9 +404,38 @@ int kwsysProcess_SetPipeFile(kwsysProcess* cp, int pipe, const char* file) } strcpy(*pfile, file); } + + /* If we are redirecting the pipe, do not share it. */ + if(*pfile) + { + kwsysProcess_SetPipeShared(cp, pipe, 0); + } return 1; } +/*--------------------------------------------------------------------------*/ +void kwsysProcess_SetPipeShared(kwsysProcess* cp, int pipe, int shared) +{ + if(!cp) + { + return; + } + + switch(pipe) + { + case kwsysProcess_Pipe_STDIN: cp->PipeSharedSTDIN = shared?1:0; break; + case kwsysProcess_Pipe_STDOUT: cp->PipeSharedSTDOUT = shared?1:0; break; + case kwsysProcess_Pipe_STDERR: cp->PipeSharedSTDERR = shared?1:0; break; + default: return; + } + + /* If we are sharing the pipe, do not redirect it to a file. */ + if(shared) + { + kwsysProcess_SetPipeFile(cp, pipe, 0); + } +} + /*--------------------------------------------------------------------------*/ int kwsysProcess_GetOption(kwsysProcess* cp, int optionId) { @@ -545,6 +585,14 @@ void kwsysProcess_Execute(kwsysProcess* cp) } } + /* Replace the stderr pipe with the parent's if requested. In this + case the select call will report that stderr is closed + immediately. */ + if(cp->PipeSharedSTDERR) + { + kwsysProcessCleanupDescriptor(&si.StdErr); + si.StdErr = 2; + } /* The timeout period starts now. */ cp->StartTime = kwsysProcessTimeGetCurrent(); @@ -553,7 +601,7 @@ void kwsysProcess_Execute(kwsysProcess* cp) /* Create the pipeline of processes. */ { - int readEnd = 0; + int readEnd = -1; for(i=0; i < cp->NumberOfCommands; ++i) { if(!kwsysProcessCreate(cp, i, &si, &readEnd)) @@ -562,13 +610,19 @@ void kwsysProcess_Execute(kwsysProcess* cp) /* Release resources that may have been allocated for this process before an error occurred. */ - if(i > 0 || si.StdIn > 0) + kwsysProcessCleanupDescriptor(&readEnd); + if(si.StdIn != 0) { kwsysProcessCleanupDescriptor(&si.StdIn); } - kwsysProcessCleanupDescriptor(&readEnd); - kwsysProcessCleanupDescriptor(&si.StdOut); - kwsysProcessCleanupDescriptor(&si.StdErr); + if(si.StdOut != 1) + { + kwsysProcessCleanupDescriptor(&si.StdOut); + } + if(si.StdErr != 2) + { + kwsysProcessCleanupDescriptor(&si.StdErr); + } kwsysProcessCleanupDescriptor(&si.TermPipe); kwsysProcessCleanupDescriptor(&si.ErrorPipe[0]); kwsysProcessCleanupDescriptor(&si.ErrorPipe[1]); @@ -1106,10 +1160,14 @@ static int kwsysProcessCreate(kwsysProcess* cp, int index, return 0; } } - else + else if(cp->PipeSharedSTDIN) { si->StdIn = 0; } + else + { + si->StdIn = -1; + } /* Setup the process's stdout. */ { @@ -1140,6 +1198,15 @@ static int kwsysProcessCreate(kwsysProcess* cp, int index, } } + /* Replace the stdout pipe with the parent's if requested. In this + case the select call will report that stderr is closed + immediately. */ + if(index == cp->NumberOfCommands-1 && cp->PipeSharedSTDOUT) + { + kwsysProcessCleanupDescriptor(&si->StdOut); + si->StdOut = 1; + } + /* Create the error reporting pipe. */ if(pipe(si->ErrorPipe) < 0) { @@ -1165,12 +1232,22 @@ static int kwsysProcessCreate(kwsysProcess* cp, int index, close(si->ErrorPipe[0]); /* Setup the stdin, stdout, and stderr pipes. */ - if(index > 0 || si->StdIn > 0) + if(si->StdIn > 0) { dup2(si->StdIn, 0); } - dup2(si->StdOut, 1); - dup2(si->StdErr, 2); + else if(si->StdIn < 0) + { + close(0); + } + if(si->StdOut != 1) + { + dup2(si->StdOut, 1); + } + if(si->StdErr != 2) + { + dup2(si->StdErr, 2); + } /* Clear the close-on-exec flag for stdin, stdout, and stderr. Also clear it for the termination pipe. All other pipe handles diff --git a/Source/kwsys/ProcessWin32.c b/Source/kwsys/ProcessWin32.c index d1d3c5ef8..c710fac64 100644 --- a/Source/kwsys/ProcessWin32.c +++ b/Source/kwsys/ProcessWin32.c @@ -184,6 +184,11 @@ struct kwsysProcess_s char* PipeFileSTDOUT; char* PipeFileSTDERR; + /* Whether each pipe is shared with the parent process. */ + int PipeSharedSTDIN; + int PipeSharedSTDOUT; + int PipeSharedSTDERR; + /* Handle to automatically delete the Win9x forwarding executable. */ HANDLE Win9xHandle; @@ -264,6 +269,9 @@ kwsysProcess* kwsysProcess_New() } ZeroMemory(cp, sizeof(*cp)); + /* Share stdin with the parent process by default. */ + cp->PipeSharedSTDIN = 1; + /* Set initial status. */ cp->State = kwsysProcess_State_Starting; @@ -805,9 +813,39 @@ int kwsysProcess_SetPipeFile(kwsysProcess* cp, int pipe, const char* file) } strcpy(*pfile, file); } + + /* If we are redirecting the pipe, do not share it. */ + if(*pfile) + { + kwsysProcess_SetPipeShared(cp, pipe, 0); + } + return 1; } +/*--------------------------------------------------------------------------*/ +void kwsysProcess_SetPipeShared(kwsysProcess* cp, int pipe, int shared) +{ + if(!cp) + { + return; + } + + switch(pipe) + { + case kwsysProcess_Pipe_STDIN: cp->PipeSharedSTDIN = shared?1:0; break; + case kwsysProcess_Pipe_STDOUT: cp->PipeSharedSTDOUT = shared?1:0; break; + case kwsysProcess_Pipe_STDERR: cp->PipeSharedSTDERR = shared?1:0; break; + default: return; + } + + /* If we are sharing the pipe, do not redirect it to a file. */ + if(shared) + { + kwsysProcess_SetPipeFile(cp, pipe, 0); + } +} + /*--------------------------------------------------------------------------*/ int kwsysProcess_GetOption(kwsysProcess* cp, int optionId) { @@ -973,6 +1011,15 @@ void kwsysProcess_Execute(kwsysProcess* cp) } } + /* Replace the stderr pipe with the parent process's if requested. + In this case the pipe thread will still run but never report + data. */ + if(cp->PipeSharedSTDERR) + { + kwsysProcessCleanupHandle(&si.StartupInfo.hStdError); + si.StartupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE); + } + /* Create the pipeline of processes. */ { HANDLE readEnd = 0; @@ -989,12 +1036,18 @@ void kwsysProcess_Execute(kwsysProcess* cp) /* Release resources that may have been allocated for this process before an error occurred. */ kwsysProcessCleanupHandle(&readEnd); - if(i > 0) + if(si.StartupInfo.hStdInput != GetStdHandle(STD_INPUT_HANDLE)) { kwsysProcessCleanupHandle(&si.StartupInfo.hStdInput); } - kwsysProcessCleanupHandle(&si.StartupInfo.hStdOutput); - kwsysProcessCleanupHandle(&si.StartupInfo.hStdError); + if(si.StartupInfo.hStdOutput != GetStdHandle(STD_OUTPUT_HANDLE)) + { + kwsysProcessCleanupHandle(&si.StartupInfo.hStdOutput); + } + if(si.StartupInfo.hStdOutput != GetStdHandle(STD_ERROR_HANDLE)) + { + kwsysProcessCleanupHandle(&si.StartupInfo.hStdError); + } kwsysProcessCleanupHandle(&si.ErrorPipeRead); kwsysProcessCleanupHandle(&si.ErrorPipeWrite); return; @@ -1533,10 +1586,14 @@ int kwsysProcessCreate(kwsysProcess* cp, int index, } si->StartupInfo.hStdInput = fin; } - else + else if(cp->PipeSharedSTDIN) { si->StartupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE); } + else + { + si->StartupInfo.hStdInput = INVALID_HANDLE_VALUE; + } /* Setup the process's stdout. */ { @@ -1578,6 +1635,15 @@ int kwsysProcessCreate(kwsysProcess* cp, int index, } } + /* Replace the stdout pipe with the parent process's if requested. + In this case the pipe thread will still run but never report + data. */ + if(index == cp->NumberOfCommands-1 && cp->PipeSharedSTDOUT) + { + kwsysProcessCleanupHandle(&si->StartupInfo.hStdOutput); + si->StartupInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); + } + /* Create the child process. */ { BOOL r; @@ -1678,8 +1744,11 @@ int kwsysProcessCreate(kwsysProcess* cp, int index, kwsysProcessCleanupHandle(&si->StartupInfo.hStdInput); } - /* The parent process does not need the inhertied pipe write end. */ - kwsysProcessCleanupHandle(&si->StartupInfo.hStdOutput); + if(si->StartupInfo.hStdOutput != GetStdHandle(STD_OUTPUT_HANDLE)) + { + /* The parent process does not need the inhertied pipe write end. */ + kwsysProcessCleanupHandle(&si->StartupInfo.hStdOutput); + } return 1; }