ENH: Added SetPipeFile method to allow the process pipeline stdin, stdout, and stderr to be redirected from/to files.
This commit is contained in:
parent
dc96992e56
commit
1f40a4205b
|
@ -33,6 +33,7 @@
|
|||
#define kwsysProcess_AddCommand kwsys(Process_AddCommand)
|
||||
#define kwsysProcess_SetTimeout kwsys(Process_SetTimeout)
|
||||
#define kwsysProcess_SetWorkingDirectory kwsys(Process_SetWorkingDirectory)
|
||||
#define kwsysProcess_SetPipeFile kwsys(Process_SetPipeFile)
|
||||
#define kwsysProcess_Option_HideWindow kwsys(Process_Option_HideWindow)
|
||||
#define kwsysProcess_GetOption kwsys(Process_GetOption)
|
||||
#define kwsysProcess_SetOption kwsys(Process_SetOption)
|
||||
|
@ -61,6 +62,7 @@
|
|||
#define kwsysProcess_WaitForData kwsys(Process_WaitForData)
|
||||
#define kwsysProcess_Pipes_e kwsys(Process_Pipes_e)
|
||||
#define kwsysProcess_Pipe_None kwsys(Process_Pipe_None)
|
||||
#define kwsysProcess_Pipe_STDIN kwsys(Process_Pipe_STDIN)
|
||||
#define kwsysProcess_Pipe_STDOUT kwsys(Process_Pipe_STDOUT)
|
||||
#define kwsysProcess_Pipe_STDERR kwsys(Process_Pipe_STDERR)
|
||||
#define kwsysProcess_Pipe_Timeout kwsys(Process_Pipe_Timeout)
|
||||
|
@ -118,9 +120,17 @@ kwsysEXPORT void kwsysProcess_SetTimeout(kwsysProcess* cp, double timeout);
|
|||
/**
|
||||
* Set the working directory for the child process. The working
|
||||
* directory can be absolute or relative to the current directory.
|
||||
* Returns 1 for success and 0 for failure.
|
||||
*/
|
||||
kwsysEXPORT void kwsysProcess_SetWorkingDirectory(kwsysProcess* cp,
|
||||
const char* dir);
|
||||
kwsysEXPORT int kwsysProcess_SetWorkingDirectory(kwsysProcess* cp,
|
||||
const char* dir);
|
||||
|
||||
/**
|
||||
* Set the name of a file to be attached to the given pipe. Returns 1
|
||||
* for success and 0 for failure.
|
||||
*/
|
||||
kwsysEXPORT int kwsysProcess_SetPipeFile(kwsysProcess* cp, int pipe,
|
||||
const char* file);
|
||||
|
||||
/**
|
||||
* Get/Set a platform-specific option. Possible options are:
|
||||
|
@ -243,6 +253,7 @@ kwsysEXPORT int kwsysProcess_WaitForData(kwsysProcess* cp, char** data,
|
|||
enum kwsysProcess_Pipes_e
|
||||
{
|
||||
kwsysProcess_Pipe_None,
|
||||
kwsysProcess_Pipe_STDIN,
|
||||
kwsysProcess_Pipe_STDOUT,
|
||||
kwsysProcess_Pipe_STDERR,
|
||||
kwsysProcess_Pipe_Timeout=255
|
||||
|
@ -292,6 +303,7 @@ kwsysEXPORT void kwsysProcess_Kill(kwsysProcess* cp);
|
|||
# undef kwsysProcess_AddCommand
|
||||
# undef kwsysProcess_SetTimeout
|
||||
# undef kwsysProcess_SetWorkingDirectory
|
||||
# undef kwsysProcess_SetPipeFile
|
||||
# undef kwsysProcess_Option_HideWindow
|
||||
# undef kwsysProcess_GetOption
|
||||
# undef kwsysProcess_SetOption
|
||||
|
@ -320,6 +332,7 @@ kwsysEXPORT void kwsysProcess_Kill(kwsysProcess* cp);
|
|||
# undef kwsysProcess_WaitForData
|
||||
# undef kwsysProcess_Pipes_e
|
||||
# undef kwsysProcess_Pipe_None
|
||||
# undef kwsysProcess_Pipe_STDIN
|
||||
# undef kwsysProcess_Pipe_STDOUT
|
||||
# undef kwsysProcess_Pipe_STDERR
|
||||
# undef kwsysProcess_Pipe_Timeout
|
||||
|
|
|
@ -86,6 +86,7 @@ static void kwsysProcessCleanup(kwsysProcess* cp, int error);
|
|||
static void kwsysProcessCleanupDescriptor(int* pfd);
|
||||
static int kwsysProcessCreate(kwsysProcess* cp, int index,
|
||||
kwsysProcessCreateInformation* si, int* readEnd);
|
||||
static int kwsysProcessSetupOutputPipeFile(int* p, const char* name);
|
||||
static int kwsysProcessGetTimeoutTime(kwsysProcess* cp, double* userTimeout,
|
||||
kwsysProcessTime* timeoutTime);
|
||||
static int kwsysProcessGetTimeoutLeft(kwsysProcessTime* timeoutTime,
|
||||
|
@ -164,6 +165,15 @@ struct kwsysProcess_s
|
|||
|
||||
/* The exit codes of each child process in the pipeline. */
|
||||
int* CommandExitCodes;
|
||||
|
||||
/* Name of files to which stdin and stdout pipes are attached. */
|
||||
char* PipeFileSTDIN;
|
||||
char* PipeFileSTDOUT;
|
||||
char* PipeFileSTDERR;
|
||||
|
||||
/* The real working directory of this process. */
|
||||
int RealWorkingDirectoryLength;
|
||||
char* RealWorkingDirectory;
|
||||
};
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
@ -198,6 +208,9 @@ void kwsysProcess_Delete(kwsysProcess* cp)
|
|||
/* Free memory. */
|
||||
kwsysProcess_SetCommand(cp, 0);
|
||||
kwsysProcess_SetWorkingDirectory(cp, 0);
|
||||
kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDIN, 0);
|
||||
kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDOUT, 0);
|
||||
kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDERR, 0);
|
||||
if(cp->CommandExitCodes)
|
||||
{
|
||||
free(cp->CommandExitCodes);
|
||||
|
@ -322,19 +335,19 @@ void kwsysProcess_SetTimeout(kwsysProcess* cp, double timeout)
|
|||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
void kwsysProcess_SetWorkingDirectory(kwsysProcess* cp, const char* dir)
|
||||
int kwsysProcess_SetWorkingDirectory(kwsysProcess* cp, const char* dir)
|
||||
{
|
||||
if(!cp)
|
||||
{
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
if(cp->WorkingDirectory == dir)
|
||||
{
|
||||
return;
|
||||
return 1;
|
||||
}
|
||||
if(cp->WorkingDirectory && dir && strcmp(cp->WorkingDirectory, dir) == 0)
|
||||
{
|
||||
return;
|
||||
return 1;
|
||||
}
|
||||
if(cp->WorkingDirectory)
|
||||
{
|
||||
|
@ -344,8 +357,45 @@ void kwsysProcess_SetWorkingDirectory(kwsysProcess* cp, const char* dir)
|
|||
if(dir)
|
||||
{
|
||||
cp->WorkingDirectory = (char*)malloc(strlen(dir) + 1);
|
||||
if(!cp->WorkingDirectory)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
strcpy(cp->WorkingDirectory, dir);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
int kwsysProcess_SetPipeFile(kwsysProcess* cp, int pipe, const char* file)
|
||||
{
|
||||
char** pfile;
|
||||
if(!cp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
switch(pipe)
|
||||
{
|
||||
case kwsysProcess_Pipe_STDIN: pfile = &cp->PipeFileSTDIN; break;
|
||||
case kwsysProcess_Pipe_STDOUT: pfile = &cp->PipeFileSTDOUT; break;
|
||||
case kwsysProcess_Pipe_STDERR: pfile = &cp->PipeFileSTDERR; break;
|
||||
default: return 0;
|
||||
}
|
||||
if(*pfile)
|
||||
{
|
||||
free(*pfile);
|
||||
*pfile = 0;
|
||||
}
|
||||
if(file)
|
||||
{
|
||||
*pfile = malloc(strlen(file)+1);
|
||||
if(!*pfile)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
strcpy(*pfile, file);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
@ -423,6 +473,27 @@ void kwsysProcess_Execute(kwsysProcess* cp)
|
|||
return;
|
||||
}
|
||||
|
||||
/* Save the real working directory of this process and change to
|
||||
the working directory for the child processes. This is needed
|
||||
to make pipe file paths evaluate correctly. */
|
||||
if(cp->WorkingDirectory)
|
||||
{
|
||||
int r;
|
||||
if(!getcwd(cp->RealWorkingDirectory, cp->RealWorkingDirectoryLength))
|
||||
{
|
||||
kwsysProcessCleanup(cp, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Some platforms specify that the chdir call may be
|
||||
interrupted. Repeat the call until it finishes. */
|
||||
while(((r = chdir(cp->WorkingDirectory)) < 0) && (errno == EINTR));
|
||||
if(r < 0)
|
||||
{
|
||||
kwsysProcessCleanup(cp, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* We want no special handling of SIGCHLD. Repeat call until it is
|
||||
not interrupted. */
|
||||
memset(&newSigChldAction, 0, sizeof(struct sigaction));
|
||||
|
@ -463,6 +534,20 @@ void kwsysProcess_Execute(kwsysProcess* cp)
|
|||
}
|
||||
}
|
||||
|
||||
/* Replace the stderr pipe with a file if requested. In this case
|
||||
the select call will report that stderr is closed immediately. */
|
||||
if(cp->PipeFileSTDERR)
|
||||
{
|
||||
if(!kwsysProcessSetupOutputPipeFile(&si.StdErr, cp->PipeFileSTDERR))
|
||||
{
|
||||
kwsysProcessCleanup(cp, 1);
|
||||
kwsysProcessCleanupDescriptor(&si.StdErr);
|
||||
kwsysProcessCleanupDescriptor(&si.TermPipe);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* The timeout period starts now. */
|
||||
cp->StartTime = kwsysProcessTimeGetCurrent();
|
||||
cp->TimeoutTime.tv_sec = -1;
|
||||
|
@ -479,11 +564,11 @@ void kwsysProcess_Execute(kwsysProcess* cp)
|
|||
|
||||
/* Release resources that may have been allocated for this
|
||||
process before an error occurred. */
|
||||
kwsysProcessCleanupDescriptor(&readEnd);
|
||||
if(i > 0)
|
||||
if(i > 0 || si.StdIn > 0)
|
||||
{
|
||||
kwsysProcessCleanupDescriptor(&si.StdIn);
|
||||
}
|
||||
kwsysProcessCleanupDescriptor(&readEnd);
|
||||
kwsysProcessCleanupDescriptor(&si.StdOut);
|
||||
kwsysProcessCleanupDescriptor(&si.StdErr);
|
||||
kwsysProcessCleanupDescriptor(&si.TermPipe);
|
||||
|
@ -500,6 +585,16 @@ void kwsysProcess_Execute(kwsysProcess* cp)
|
|||
kwsysProcessCleanupDescriptor(&si.StdErr);
|
||||
kwsysProcessCleanupDescriptor(&si.TermPipe);
|
||||
|
||||
/* Restore the working directory. */
|
||||
if(cp->RealWorkingDirectory)
|
||||
{
|
||||
/* Some platforms specify that the chdir call may be
|
||||
interrupted. Repeat the call until it finishes. */
|
||||
while((chdir(cp->RealWorkingDirectory) < 0) && (errno == EINTR));
|
||||
free(cp->RealWorkingDirectory);
|
||||
cp->RealWorkingDirectory = 0;
|
||||
}
|
||||
|
||||
/* All the pipes are now open. */
|
||||
cp->PipesLeft = KWSYSPE_PIPE_COUNT;
|
||||
|
||||
|
@ -895,6 +990,22 @@ static int kwsysProcessInitialize(kwsysProcess* cp)
|
|||
}
|
||||
memset(cp->CommandExitCodes, 0, sizeof(int)*cp->NumberOfCommands);
|
||||
|
||||
/* Allocate memory to save the real working directory. */
|
||||
{
|
||||
#if defined(MAXPATHLEN)
|
||||
cp->RealWorkingDirectoryLength = MAXPATHLEN;
|
||||
#elif defined(PATH_MAX)
|
||||
cp->RealWorkingDirectoryLength = PATH_MAX;
|
||||
#else
|
||||
cp->RealWorkingDirectoryLength = 4096;
|
||||
#endif
|
||||
cp->RealWorkingDirectory = malloc(cp->RealWorkingDirectoryLength);
|
||||
if(!cp->RealWorkingDirectory)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -928,6 +1039,12 @@ static void kwsysProcessCleanup(kwsysProcess* cp, int error)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Restore the working directory. */
|
||||
if(cp->RealWorkingDirectory)
|
||||
{
|
||||
while((chdir(cp->RealWorkingDirectory) < 0) && (errno == EINTR));
|
||||
}
|
||||
}
|
||||
|
||||
/* Restore the SIGCHLD handler. */
|
||||
|
@ -940,6 +1057,11 @@ static void kwsysProcessCleanup(kwsysProcess* cp, int error)
|
|||
free(cp->ForkPIDs);
|
||||
cp->ForkPIDs = 0;
|
||||
}
|
||||
if(cp->RealWorkingDirectory)
|
||||
{
|
||||
free(cp->RealWorkingDirectory);
|
||||
cp->RealWorkingDirectory = 0;
|
||||
}
|
||||
|
||||
/* Close pipe handles. */
|
||||
for(i=0; i < KWSYSPE_PIPE_COUNT; ++i)
|
||||
|
@ -971,6 +1093,21 @@ static int kwsysProcessCreate(kwsysProcess* cp, int index,
|
|||
si->StdIn = *readEnd;
|
||||
*readEnd = 0;
|
||||
}
|
||||
else if(cp->PipeFileSTDIN)
|
||||
{
|
||||
/* Open a file for the child's stdin to read. */
|
||||
si->StdIn = open(cp->PipeFileSTDIN, O_RDONLY);
|
||||
if(si->StdIn < 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Set close-on-exec flag on the pipe's end. */
|
||||
if(fcntl(si->StdIn, F_SETFD, FD_CLOEXEC) < 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
si->StdIn = 0;
|
||||
|
@ -995,6 +1132,16 @@ static int kwsysProcessCreate(kwsysProcess* cp, int index,
|
|||
}
|
||||
}
|
||||
|
||||
/* Replace the stdout pipe with a file if requested. In this case
|
||||
the select call will report that stdout is closed immediately. */
|
||||
if(index == cp->NumberOfCommands-1 && cp->PipeFileSTDOUT)
|
||||
{
|
||||
if(!kwsysProcessSetupOutputPipeFile(&si->StdOut, cp->PipeFileSTDOUT))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Create the error reporting pipe. */
|
||||
if(pipe(si->ErrorPipe) < 0)
|
||||
{
|
||||
|
@ -1020,7 +1167,7 @@ static int kwsysProcessCreate(kwsysProcess* cp, int index,
|
|||
close(si->ErrorPipe[0]);
|
||||
|
||||
/* Setup the stdin, stdout, and stderr pipes. */
|
||||
if(index > 0)
|
||||
if(index > 0 || si->StdIn > 0)
|
||||
{
|
||||
dup2(si->StdIn, 0);
|
||||
}
|
||||
|
@ -1038,20 +1185,6 @@ static int kwsysProcessCreate(kwsysProcess* cp, int index,
|
|||
/* Restore all default signal handlers. */
|
||||
kwsysProcessRestoreDefaultSignalHandlers();
|
||||
|
||||
/* Change to the working directory specified, if any. */
|
||||
if(cp->WorkingDirectory)
|
||||
{
|
||||
/* Some platforms specify that the chdir call may be
|
||||
interrupted. Repeat the call until it finishes. */
|
||||
int r;
|
||||
while(((r = chdir(cp->WorkingDirectory)) < 0) && (errno == EINTR));
|
||||
if(r < 0)
|
||||
{
|
||||
/* Failure. Report error to parent and terminate. */
|
||||
kwsysProcessChildErrorExit(si->ErrorPipe[1]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Execute the real process. If successful, this does not return. */
|
||||
execvp(cp->Commands[index][0], cp->Commands[index]);
|
||||
|
||||
|
@ -1091,7 +1224,7 @@ static int kwsysProcessCreate(kwsysProcess* cp, int index,
|
|||
}
|
||||
|
||||
/* Successfully created this child process. */
|
||||
if(index > 0)
|
||||
if(index > 0 || si->StdIn > 0)
|
||||
{
|
||||
/* The parent process does not need the input pipe read end. */
|
||||
kwsysProcessCleanupDescriptor(&si->StdIn);
|
||||
|
@ -1103,6 +1236,36 @@ static int kwsysProcessCreate(kwsysProcess* cp, int index,
|
|||
return 1;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
static int kwsysProcessSetupOutputPipeFile(int* p, const char* name)
|
||||
{
|
||||
int fout;
|
||||
if(!name)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Close the existing descriptor. */
|
||||
kwsysProcessCleanupDescriptor(p);
|
||||
|
||||
/* Open a file for the pipe to write (permissions 644). */
|
||||
if((fout = open(name, O_WRONLY | O_CREAT | O_TRUNC,
|
||||
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Set close-on-exec flag on the pipe's end. */
|
||||
if(fcntl(fout, F_SETFD, FD_CLOEXEC) < 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Assign the replacement descriptor. */
|
||||
*p = fout;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* Get the time at which either the process or user timeout will
|
||||
expire. Returns 1 if the user timeout is first, and 0 otherwise. */
|
||||
|
|
|
@ -80,6 +80,7 @@ static int kwsysProcessCreate(kwsysProcess* cp, int index,
|
|||
kwsysProcessCreateInformation* si,
|
||||
PHANDLE readEnd);
|
||||
static void kwsysProcessDestroy(kwsysProcess* cp, int event);
|
||||
static int kwsysProcessSetupOutputPipeFile(PHANDLE handle, const char* name);
|
||||
static void kwsysProcessCleanupHandle(PHANDLE h);
|
||||
static void kwsysProcessCleanup(kwsysProcess* cp, int error);
|
||||
static void kwsysProcessCleanErrorMessage(kwsysProcess* cp);
|
||||
|
@ -181,6 +182,11 @@ struct kwsysProcess_s
|
|||
/* Data specific to each pipe and its thread. */
|
||||
kwsysProcessPipeData Pipe[KWSYSPE_PIPE_COUNT];
|
||||
|
||||
/* Name of files to which stdin and stdout pipes are attached. */
|
||||
char* PipeFileSTDIN;
|
||||
char* PipeFileSTDOUT;
|
||||
char* PipeFileSTDERR;
|
||||
|
||||
/* ------------- Data managed per call to Execute ------------- */
|
||||
|
||||
/* The exceptional behavior that terminated the process, if any. */
|
||||
|
@ -229,6 +235,10 @@ struct kwsysProcess_s
|
|||
/* Data and process termination events for which to wait. */
|
||||
PHANDLE ProcessEvents;
|
||||
int ProcessEventsLength;
|
||||
|
||||
/* Real working directory of our own process. */
|
||||
DWORD RealWorkingDirectoryLength;
|
||||
char* RealWorkingDirectory;
|
||||
};
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
@ -456,6 +466,9 @@ void kwsysProcess_Delete(kwsysProcess* cp)
|
|||
/* Free memory. */
|
||||
kwsysProcess_SetCommand(cp, 0);
|
||||
kwsysProcess_SetWorkingDirectory(cp, 0);
|
||||
kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDIN, 0);
|
||||
kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDOUT, 0);
|
||||
kwsysProcess_SetPipeFile(cp, kwsysProcess_Pipe_STDERR, 0);
|
||||
if(cp->CommandExitCodes)
|
||||
{
|
||||
free(cp->CommandExitCodes);
|
||||
|
@ -715,11 +728,11 @@ void kwsysProcess_SetTimeout(kwsysProcess* cp, double timeout)
|
|||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
void kwsysProcess_SetWorkingDirectory(kwsysProcess* cp, const char* dir)
|
||||
int kwsysProcess_SetWorkingDirectory(kwsysProcess* cp, const char* dir)
|
||||
{
|
||||
if(!cp)
|
||||
{
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
if(cp->WorkingDirectory)
|
||||
{
|
||||
|
@ -733,13 +746,51 @@ void kwsysProcess_SetWorkingDirectory(kwsysProcess* cp, const char* dir)
|
|||
if(length > 0)
|
||||
{
|
||||
cp->WorkingDirectory = (char*)malloc(length);
|
||||
if(!cp->WorkingDirectory)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if(!GetFullPathName(dir, length, cp->WorkingDirectory, 0))
|
||||
{
|
||||
free(cp->WorkingDirectory);
|
||||
cp->WorkingDirectory = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
int kwsysProcess_SetPipeFile(kwsysProcess* cp, int pipe, const char* file)
|
||||
{
|
||||
char** pfile;
|
||||
if(!cp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
switch(pipe)
|
||||
{
|
||||
case kwsysProcess_Pipe_STDIN: pfile = &cp->PipeFileSTDIN; break;
|
||||
case kwsysProcess_Pipe_STDOUT: pfile = &cp->PipeFileSTDOUT; break;
|
||||
case kwsysProcess_Pipe_STDERR: pfile = &cp->PipeFileSTDERR; break;
|
||||
default: return 0;
|
||||
}
|
||||
if(*pfile)
|
||||
{
|
||||
free(*pfile);
|
||||
*pfile = 0;
|
||||
}
|
||||
if(file)
|
||||
{
|
||||
*pfile = malloc(strlen(file)+1);
|
||||
if(!*pfile)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
strcpy(*pfile, file);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
@ -832,6 +883,20 @@ void kwsysProcess_Execute(kwsysProcess* cp)
|
|||
return;
|
||||
}
|
||||
|
||||
/* Save the real working directory of this process and change to
|
||||
the working directory for the child processes. This is needed
|
||||
to make pipe file paths evaluate correctly. */
|
||||
if(cp->WorkingDirectory)
|
||||
{
|
||||
if(!GetCurrentDirectory(cp->RealWorkingDirectoryLength,
|
||||
cp->RealWorkingDirectory))
|
||||
{
|
||||
kwsysProcessCleanup(cp, 1);
|
||||
return;
|
||||
}
|
||||
SetCurrentDirectory(cp->WorkingDirectory);
|
||||
}
|
||||
|
||||
/* Reset the Win9x resume and kill events. */
|
||||
if(cp->Win9x)
|
||||
{
|
||||
|
@ -880,6 +945,19 @@ void kwsysProcess_Execute(kwsysProcess* cp)
|
|||
return;
|
||||
}
|
||||
|
||||
/* Replace the stderr pipe with a file if requested. In this case
|
||||
the pipe thread will still run but never report data. */
|
||||
if(cp->PipeFileSTDERR)
|
||||
{
|
||||
if(!kwsysProcessSetupOutputPipeFile(&si.StartupInfo.hStdError,
|
||||
cp->PipeFileSTDERR))
|
||||
{
|
||||
kwsysProcessCleanup(cp, 1);
|
||||
kwsysProcessCleanupHandle(&si.StartupInfo.hStdError);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Create the pipeline of processes. */
|
||||
{
|
||||
HANDLE readEnd = 0;
|
||||
|
@ -916,6 +994,14 @@ void kwsysProcess_Execute(kwsysProcess* cp)
|
|||
processes in the pipeline. */
|
||||
kwsysProcessCleanupHandle(&si.StartupInfo.hStdError);
|
||||
|
||||
/* Restore the working directory. */
|
||||
if(cp->RealWorkingDirectory)
|
||||
{
|
||||
SetCurrentDirectory(cp->RealWorkingDirectory);
|
||||
free(cp->RealWorkingDirectory);
|
||||
cp->RealWorkingDirectory = 0;
|
||||
}
|
||||
|
||||
/* The timeout period starts now. */
|
||||
cp->StartTime = kwsysProcessTimeGetCurrent();
|
||||
cp->TimeoutTime = kwsysProcessTimeFromDouble(-1);
|
||||
|
@ -1372,6 +1458,20 @@ int kwsysProcessInitialize(kwsysProcess* cp)
|
|||
cp->ProcessEvents[0] = cp->Full;
|
||||
cp->ProcessEventsLength = cp->NumberOfCommands+1;
|
||||
|
||||
/* Allocate space to save the real working directory of this process. */
|
||||
if(cp->WorkingDirectory)
|
||||
{
|
||||
cp->RealWorkingDirectoryLength = GetCurrentDirectory(0, 0);
|
||||
if(cp->RealWorkingDirectoryLength > 0)
|
||||
{
|
||||
cp->RealWorkingDirectory = malloc(cp->RealWorkingDirectoryLength);
|
||||
if(!cp->RealWorkingDirectory)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -1398,6 +1498,26 @@ int kwsysProcessCreate(kwsysProcess* cp, int index,
|
|||
/* This function is done with this handle. */
|
||||
*readEnd = 0;
|
||||
}
|
||||
else if(cp->PipeFileSTDIN)
|
||||
{
|
||||
/* Create a handle to read a file for stdin. */
|
||||
HANDLE fin = CreateFile(cp->PipeFileSTDIN, GENERIC_READ,
|
||||
FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
|
||||
if(fin == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
/* Create an inherited duplicate of the handle. This also closes
|
||||
the non-inherited version. */
|
||||
if(!DuplicateHandle(GetCurrentProcess(), fin,
|
||||
GetCurrentProcess(), &fin,
|
||||
0, TRUE, (DUPLICATE_CLOSE_SOURCE |
|
||||
DUPLICATE_SAME_ACCESS)))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
si->StartupInfo.hStdInput = fin;
|
||||
}
|
||||
else
|
||||
{
|
||||
si->StartupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
|
||||
|
@ -1424,13 +1544,25 @@ int kwsysProcessCreate(kwsysProcess* cp, int index,
|
|||
maybeClose = 0;
|
||||
}
|
||||
if(!DuplicateHandle(GetCurrentProcess(), writeEnd,
|
||||
GetCurrentProcess(), &si->StartupInfo.hStdOutput,
|
||||
GetCurrentProcess(), &writeEnd,
|
||||
0, TRUE, (maybeClose | DUPLICATE_SAME_ACCESS)))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
si->StartupInfo.hStdOutput = writeEnd;
|
||||
}
|
||||
|
||||
/* Replace the stdout pipe with a file if requested. In this case
|
||||
the pipe thread will still run but never report data. */
|
||||
if(index == cp->NumberOfCommands-1 && cp->PipeFileSTDOUT)
|
||||
{
|
||||
if(!kwsysProcessSetupOutputPipeFile(&si->StartupInfo.hStdOutput,
|
||||
cp->PipeFileSTDOUT))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Create the child process. */
|
||||
{
|
||||
BOOL r;
|
||||
|
@ -1473,9 +1605,8 @@ int kwsysProcessCreate(kwsysProcess* cp, int index,
|
|||
/* Create the child in a suspended state so we can wait until all
|
||||
children have been created before running any one. */
|
||||
r = CreateProcess(0, realCommand, 0, 0, TRUE,
|
||||
cp->Win9x? 0 : CREATE_SUSPENDED, 0,
|
||||
cp->WorkingDirectory, &si->StartupInfo,
|
||||
&cp->ProcessInformation[index]);
|
||||
cp->Win9x? 0 : CREATE_SUSPENDED, 0, 0,
|
||||
&si->StartupInfo, &cp->ProcessInformation[index]);
|
||||
|
||||
if(cp->Win9x)
|
||||
{
|
||||
|
@ -1581,6 +1712,41 @@ void kwsysProcessDestroy(kwsysProcess* cp, int event)
|
|||
}
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
int kwsysProcessSetupOutputPipeFile(PHANDLE phandle, const char* name)
|
||||
{
|
||||
HANDLE fout;
|
||||
if(!name)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Close the existing inherited handle. */
|
||||
kwsysProcessCleanupHandle(phandle);
|
||||
|
||||
/* Create a handle to write a file for the pipe. */
|
||||
fout = CreateFile(name, GENERIC_WRITE, FILE_SHARE_READ, 0,
|
||||
CREATE_ALWAYS, 0, 0);
|
||||
if(fout == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Create an inherited duplicate of the handle. This also closes
|
||||
the non-inherited version. */
|
||||
if(!DuplicateHandle(GetCurrentProcess(), fout,
|
||||
GetCurrentProcess(), &fout,
|
||||
0, TRUE, (DUPLICATE_CLOSE_SOURCE |
|
||||
DUPLICATE_SAME_ACCESS)))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Assign the replacement handle. */
|
||||
*phandle = fout;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/* Close the given handle if it is open. Reset its value to 0. */
|
||||
|
@ -1652,6 +1818,12 @@ void kwsysProcessCleanup(kwsysProcess* cp, int error)
|
|||
kwsysProcessCleanupHandle(&cp->ProcessInformation[i].hProcess);
|
||||
}
|
||||
}
|
||||
|
||||
/* Restore the working directory. */
|
||||
if(cp->RealWorkingDirectory)
|
||||
{
|
||||
SetCurrentDirectory(cp->RealWorkingDirectory);
|
||||
}
|
||||
}
|
||||
|
||||
/* Free memory. */
|
||||
|
@ -1665,6 +1837,11 @@ void kwsysProcessCleanup(kwsysProcess* cp, int error)
|
|||
free(cp->ProcessEvents);
|
||||
cp->ProcessEvents = 0;
|
||||
}
|
||||
if(cp->RealWorkingDirectory)
|
||||
{
|
||||
free(cp->RealWorkingDirectory);
|
||||
cp->RealWorkingDirectory = 0;
|
||||
}
|
||||
|
||||
/* Close each pipe. */
|
||||
for(i=0; i < KWSYSPE_PIPE_COUNT; ++i)
|
||||
|
|
Loading…
Reference in New Issue