ENH: Added SetPipeShared method to allow stdout and stderr pipes to be shared with the parent process.

This commit is contained in:
Brad King 2003-12-16 17:20:01 -05:00
parent ab0a30e2b3
commit 802601b606
3 changed files with 171 additions and 15 deletions

View File

@ -31,6 +31,7 @@
#define kwsysProcess_SetTimeout kwsys(Process_SetTimeout) #define kwsysProcess_SetTimeout kwsys(Process_SetTimeout)
#define kwsysProcess_SetWorkingDirectory kwsys(Process_SetWorkingDirectory) #define kwsysProcess_SetWorkingDirectory kwsys(Process_SetWorkingDirectory)
#define kwsysProcess_SetPipeFile kwsys(Process_SetPipeFile) #define kwsysProcess_SetPipeFile kwsys(Process_SetPipeFile)
#define kwsysProcess_SetPipeShared kwsys(Process_SetPipeShared)
#define kwsysProcess_Option_HideWindow kwsys(Process_Option_HideWindow) #define kwsysProcess_Option_HideWindow kwsys(Process_Option_HideWindow)
#define kwsysProcess_GetOption kwsys(Process_GetOption) #define kwsysProcess_GetOption kwsys(Process_GetOption)
#define kwsysProcess_SetOption kwsys(Process_SetOption) #define kwsysProcess_SetOption kwsys(Process_SetOption)
@ -129,6 +130,14 @@ kwsysEXPORT int kwsysProcess_SetWorkingDirectory(kwsysProcess* cp,
kwsysEXPORT int kwsysProcess_SetPipeFile(kwsysProcess* cp, int pipe, kwsysEXPORT int kwsysProcess_SetPipeFile(kwsysProcess* cp, int pipe,
const char* file); 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: * Get/Set a platform-specific option. Possible options are:
* *
@ -301,6 +310,7 @@ kwsysEXPORT void kwsysProcess_Kill(kwsysProcess* cp);
# undef kwsysProcess_SetTimeout # undef kwsysProcess_SetTimeout
# undef kwsysProcess_SetWorkingDirectory # undef kwsysProcess_SetWorkingDirectory
# undef kwsysProcess_SetPipeFile # undef kwsysProcess_SetPipeFile
# undef kwsysProcess_SetPipeShared
# undef kwsysProcess_Option_HideWindow # undef kwsysProcess_Option_HideWindow
# undef kwsysProcess_GetOption # undef kwsysProcess_GetOption
# undef kwsysProcess_SetOption # undef kwsysProcess_SetOption

View File

@ -169,6 +169,11 @@ struct kwsysProcess_s
char* PipeFileSTDOUT; char* PipeFileSTDOUT;
char* PipeFileSTDERR; char* PipeFileSTDERR;
/* Whether each pipe is shared with the parent process. */
int PipeSharedSTDIN;
int PipeSharedSTDOUT;
int PipeSharedSTDERR;
/* The real working directory of this process. */ /* The real working directory of this process. */
int RealWorkingDirectoryLength; int RealWorkingDirectoryLength;
char* RealWorkingDirectory; char* RealWorkingDirectory;
@ -184,7 +189,13 @@ kwsysProcess* kwsysProcess_New()
return 0; return 0;
} }
memset(cp, 0, sizeof(kwsysProcess)); memset(cp, 0, sizeof(kwsysProcess));
/* Share stdin with the parent process by default. */
cp->PipeSharedSTDIN = 1;
/* Set initial status. */
cp->State = kwsysProcess_State_Starting; cp->State = kwsysProcess_State_Starting;
return cp; return cp;
} }
@ -393,9 +404,38 @@ int kwsysProcess_SetPipeFile(kwsysProcess* cp, int pipe, const char* file)
} }
strcpy(*pfile, file); strcpy(*pfile, file);
} }
/* If we are redirecting the pipe, do not share it. */
if(*pfile)
{
kwsysProcess_SetPipeShared(cp, pipe, 0);
}
return 1; 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) 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. */ /* The timeout period starts now. */
cp->StartTime = kwsysProcessTimeGetCurrent(); cp->StartTime = kwsysProcessTimeGetCurrent();
@ -553,7 +601,7 @@ void kwsysProcess_Execute(kwsysProcess* cp)
/* Create the pipeline of processes. */ /* Create the pipeline of processes. */
{ {
int readEnd = 0; int readEnd = -1;
for(i=0; i < cp->NumberOfCommands; ++i) for(i=0; i < cp->NumberOfCommands; ++i)
{ {
if(!kwsysProcessCreate(cp, i, &si, &readEnd)) if(!kwsysProcessCreate(cp, i, &si, &readEnd))
@ -562,13 +610,19 @@ void kwsysProcess_Execute(kwsysProcess* cp)
/* Release resources that may have been allocated for this /* Release resources that may have been allocated for this
process before an error occurred. */ process before an error occurred. */
if(i > 0 || si.StdIn > 0) kwsysProcessCleanupDescriptor(&readEnd);
if(si.StdIn != 0)
{ {
kwsysProcessCleanupDescriptor(&si.StdIn); kwsysProcessCleanupDescriptor(&si.StdIn);
} }
kwsysProcessCleanupDescriptor(&readEnd); if(si.StdOut != 1)
kwsysProcessCleanupDescriptor(&si.StdOut); {
kwsysProcessCleanupDescriptor(&si.StdErr); kwsysProcessCleanupDescriptor(&si.StdOut);
}
if(si.StdErr != 2)
{
kwsysProcessCleanupDescriptor(&si.StdErr);
}
kwsysProcessCleanupDescriptor(&si.TermPipe); kwsysProcessCleanupDescriptor(&si.TermPipe);
kwsysProcessCleanupDescriptor(&si.ErrorPipe[0]); kwsysProcessCleanupDescriptor(&si.ErrorPipe[0]);
kwsysProcessCleanupDescriptor(&si.ErrorPipe[1]); kwsysProcessCleanupDescriptor(&si.ErrorPipe[1]);
@ -1106,10 +1160,14 @@ static int kwsysProcessCreate(kwsysProcess* cp, int index,
return 0; return 0;
} }
} }
else else if(cp->PipeSharedSTDIN)
{ {
si->StdIn = 0; si->StdIn = 0;
} }
else
{
si->StdIn = -1;
}
/* Setup the process's stdout. */ /* 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. */ /* Create the error reporting pipe. */
if(pipe(si->ErrorPipe) < 0) if(pipe(si->ErrorPipe) < 0)
{ {
@ -1165,12 +1232,22 @@ static int kwsysProcessCreate(kwsysProcess* cp, int index,
close(si->ErrorPipe[0]); close(si->ErrorPipe[0]);
/* Setup the stdin, stdout, and stderr pipes. */ /* Setup the stdin, stdout, and stderr pipes. */
if(index > 0 || si->StdIn > 0) if(si->StdIn > 0)
{ {
dup2(si->StdIn, 0); dup2(si->StdIn, 0);
} }
dup2(si->StdOut, 1); else if(si->StdIn < 0)
dup2(si->StdErr, 2); {
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. /* Clear the close-on-exec flag for stdin, stdout, and stderr.
Also clear it for the termination pipe. All other pipe handles Also clear it for the termination pipe. All other pipe handles

View File

@ -184,6 +184,11 @@ struct kwsysProcess_s
char* PipeFileSTDOUT; char* PipeFileSTDOUT;
char* PipeFileSTDERR; 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 to automatically delete the Win9x forwarding executable. */
HANDLE Win9xHandle; HANDLE Win9xHandle;
@ -264,6 +269,9 @@ kwsysProcess* kwsysProcess_New()
} }
ZeroMemory(cp, sizeof(*cp)); ZeroMemory(cp, sizeof(*cp));
/* Share stdin with the parent process by default. */
cp->PipeSharedSTDIN = 1;
/* Set initial status. */ /* Set initial status. */
cp->State = kwsysProcess_State_Starting; cp->State = kwsysProcess_State_Starting;
@ -805,9 +813,39 @@ int kwsysProcess_SetPipeFile(kwsysProcess* cp, int pipe, const char* file)
} }
strcpy(*pfile, file); strcpy(*pfile, file);
} }
/* If we are redirecting the pipe, do not share it. */
if(*pfile)
{
kwsysProcess_SetPipeShared(cp, pipe, 0);
}
return 1; 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) 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. */ /* Create the pipeline of processes. */
{ {
HANDLE readEnd = 0; HANDLE readEnd = 0;
@ -989,12 +1036,18 @@ void kwsysProcess_Execute(kwsysProcess* cp)
/* Release resources that may have been allocated for this /* Release resources that may have been allocated for this
process before an error occurred. */ process before an error occurred. */
kwsysProcessCleanupHandle(&readEnd); kwsysProcessCleanupHandle(&readEnd);
if(i > 0) if(si.StartupInfo.hStdInput != GetStdHandle(STD_INPUT_HANDLE))
{ {
kwsysProcessCleanupHandle(&si.StartupInfo.hStdInput); kwsysProcessCleanupHandle(&si.StartupInfo.hStdInput);
} }
kwsysProcessCleanupHandle(&si.StartupInfo.hStdOutput); if(si.StartupInfo.hStdOutput != GetStdHandle(STD_OUTPUT_HANDLE))
kwsysProcessCleanupHandle(&si.StartupInfo.hStdError); {
kwsysProcessCleanupHandle(&si.StartupInfo.hStdOutput);
}
if(si.StartupInfo.hStdOutput != GetStdHandle(STD_ERROR_HANDLE))
{
kwsysProcessCleanupHandle(&si.StartupInfo.hStdError);
}
kwsysProcessCleanupHandle(&si.ErrorPipeRead); kwsysProcessCleanupHandle(&si.ErrorPipeRead);
kwsysProcessCleanupHandle(&si.ErrorPipeWrite); kwsysProcessCleanupHandle(&si.ErrorPipeWrite);
return; return;
@ -1533,10 +1586,14 @@ int kwsysProcessCreate(kwsysProcess* cp, int index,
} }
si->StartupInfo.hStdInput = fin; si->StartupInfo.hStdInput = fin;
} }
else else if(cp->PipeSharedSTDIN)
{ {
si->StartupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE); si->StartupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
} }
else
{
si->StartupInfo.hStdInput = INVALID_HANDLE_VALUE;
}
/* Setup the process's stdout. */ /* 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. */ /* Create the child process. */
{ {
BOOL r; BOOL r;
@ -1678,8 +1744,11 @@ int kwsysProcessCreate(kwsysProcess* cp, int index,
kwsysProcessCleanupHandle(&si->StartupInfo.hStdInput); kwsysProcessCleanupHandle(&si->StartupInfo.hStdInput);
} }
/* The parent process does not need the inhertied pipe write end. */ if(si->StartupInfo.hStdOutput != GetStdHandle(STD_OUTPUT_HANDLE))
kwsysProcessCleanupHandle(&si->StartupInfo.hStdOutput); {
/* The parent process does not need the inhertied pipe write end. */
kwsysProcessCleanupHandle(&si->StartupInfo.hStdOutput);
}
return 1; return 1;
} }