summaryrefslogtreecommitdiffstats
path: root/Source/kwsys/ProcessUNIX.c
diff options
context:
space:
mode:
Diffstat (limited to 'Source/kwsys/ProcessUNIX.c')
-rw-r--r--Source/kwsys/ProcessUNIX.c154
1 files changed, 142 insertions, 12 deletions
diff --git a/Source/kwsys/ProcessUNIX.c b/Source/kwsys/ProcessUNIX.c
index ea257b0..d4b8749 100644
--- a/Source/kwsys/ProcessUNIX.c
+++ b/Source/kwsys/ProcessUNIX.c
@@ -47,6 +47,7 @@ do.
*/
+#include <stddef.h> /* ptrdiff_t */
#include <stdio.h> /* snprintf */
#include <stdlib.h> /* malloc, free */
#include <string.h> /* strdup, strerror, memset */
@@ -62,6 +63,18 @@ do.
#include <dirent.h> /* DIR, dirent */
#include <ctype.h> /* isspace */
+#if defined(KWSYS_C_HAS_PTRDIFF_T) && KWSYS_C_HAS_PTRDIFF_T
+typedef ptrdiff_t kwsysProcess_ptrdiff_t;
+#else
+typedef int kwsysProcess_ptrdiff_t;
+#endif
+
+#if defined(KWSYS_C_HAS_SSIZE_T) && KWSYS_C_HAS_SSIZE_T
+typedef ssize_t kwsysProcess_ssize_t;
+#else
+typedef int kwsysProcess_ssize_t;
+#endif
+
/* The number of pipes for the child's output. The standard stdout
and stderr pipes are the first two. One more pipe is used to
detect when the child process has terminated. The third pipe is
@@ -102,6 +115,7 @@ static int kwsysProcessCreate(kwsysProcess* cp, int prIndex,
kwsysProcessCreateInformation* si, int* readEnd);
static void kwsysProcessDestroy(kwsysProcess* cp);
static int kwsysProcessSetupOutputPipeFile(int* p, const char* name);
+static int kwsysProcessSetupOutputPipeNative(int* p, int des[2]);
static int kwsysProcessGetTimeoutTime(kwsysProcess* cp, double* userTimeout,
kwsysProcessTime* timeoutTime);
static int kwsysProcessGetTimeoutLeft(kwsysProcessTime* timeoutTime,
@@ -217,6 +231,11 @@ struct kwsysProcess_s
int PipeSharedSTDOUT;
int PipeSharedSTDERR;
+ /* Native pipes provided by the user. */
+ int PipeNativeSTDIN[2];
+ int PipeNativeSTDOUT[2];
+ int PipeNativeSTDERR[2];
+
/* The real working directory of this process. */
int RealWorkingDirectoryLength;
char* RealWorkingDirectory;
@@ -236,6 +255,14 @@ kwsysProcess* kwsysProcess_New(void)
/* Share stdin with the parent process by default. */
cp->PipeSharedSTDIN = 1;
+ /* No native pipes by default. */
+ cp->PipeNativeSTDIN[0] = -1;
+ cp->PipeNativeSTDIN[1] = -1;
+ cp->PipeNativeSTDOUT[0] = -1;
+ cp->PipeNativeSTDOUT[1] = -1;
+ cp->PipeNativeSTDERR[0] = -1;
+ cp->PipeNativeSTDERR[1] = -1;
+
/* Set initial status. */
cp->State = kwsysProcess_State_Starting;
@@ -354,8 +381,8 @@ int kwsysProcess_AddCommand(kwsysProcess* cp, char const* const* command)
{
/* Copy each argument string individually. */
char const* const* c = command;
- int n = 0;
- int i = 0;
+ kwsysProcess_ptrdiff_t n = 0;
+ kwsysProcess_ptrdiff_t i = 0;
while(*c++);
n = c - command - 1;
newCommands[cp->NumberOfCommands] = (char**)malloc((n+1)*sizeof(char*));
@@ -470,9 +497,11 @@ int kwsysProcess_SetPipeFile(kwsysProcess* cp, int prPipe, const char* file)
strcpy(*pfile, file);
}
- /* If we are redirecting the pipe, do not share it. */
+ /* If we are redirecting the pipe, do not share it or use a native
+ pipe. */
if(*pfile)
{
+ kwsysProcess_SetPipeNative(cp, prPipe, 0);
kwsysProcess_SetPipeShared(cp, prPipe, 0);
}
return 1;
@@ -494,10 +523,51 @@ void kwsysProcess_SetPipeShared(kwsysProcess* cp, int prPipe, int shared)
default: return;
}
- /* If we are sharing the pipe, do not redirect it to a file. */
+ /* If we are sharing the pipe, do not redirect it to a file or use a
+ native pipe. */
if(shared)
{
kwsysProcess_SetPipeFile(cp, prPipe, 0);
+ kwsysProcess_SetPipeNative(cp, prPipe, 0);
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+void kwsysProcess_SetPipeNative(kwsysProcess* cp, int prPipe, int p[2])
+{
+ int* pPipeNative = 0;
+
+ if(!cp)
+ {
+ return;
+ }
+
+ switch(prPipe)
+ {
+ case kwsysProcess_Pipe_STDIN: pPipeNative = cp->PipeNativeSTDIN; break;
+ case kwsysProcess_Pipe_STDOUT: pPipeNative = cp->PipeNativeSTDOUT; break;
+ case kwsysProcess_Pipe_STDERR: pPipeNative = cp->PipeNativeSTDERR; break;
+ default: return;
+ }
+
+ /* Copy the native pipe descriptors provided. */
+ if(p)
+ {
+ pPipeNative[0] = p[0];
+ pPipeNative[1] = p[1];
+ }
+ else
+ {
+ pPipeNative[0] = -1;
+ pPipeNative[1] = -1;
+ }
+
+ /* If we are using a native pipe, do not share it or redirect it to
+ a file. */
+ if(p)
+ {
+ kwsysProcess_SetPipeFile(cp, prPipe, 0);
+ kwsysProcess_SetPipeShared(cp, prPipe, 0);
}
}
@@ -684,6 +754,19 @@ void kwsysProcess_Execute(kwsysProcess* cp)
si.StdErr = 2;
}
+ /* Replace the stderr pipe with the native pipe provided if any. In
+ this case the select call will report that stderr is closed
+ immediately. */
+ if(cp->PipeNativeSTDERR[1] >= 0)
+ {
+ if(!kwsysProcessSetupOutputPipeNative(&si.StdErr, cp->PipeNativeSTDERR))
+ {
+ kwsysProcessCleanup(cp, 1);
+ kwsysProcessCleanupDescriptor(&si.StdErr);
+ return;
+ }
+ }
+
/* The timeout period starts now. */
cp->StartTime = kwsysProcessTimeGetCurrent();
cp->TimeoutTime.tv_sec = -1;
@@ -834,7 +917,7 @@ int kwsysProcess_WaitForData(kwsysProcess* cp, char** data, int* length,
if(cp->PipeReadEnds[i] >= 0 &&
FD_ISSET(cp->PipeReadEnds[i], &cp->PipeSet))
{
- int n;
+ kwsysProcess_ssize_t n;
/* We are handling this pipe now. Remove it from the set. */
FD_CLR(cp->PipeReadEnds[i], &cp->PipeSet);
@@ -1297,6 +1380,19 @@ static int kwsysProcessCreate(kwsysProcess* cp, int prIndex,
{
si->StdIn = 0;
}
+ else if(cp->PipeNativeSTDIN[0] >= 0)
+ {
+ si->StdIn = cp->PipeNativeSTDIN[0];
+
+ /* Set close-on-exec flag on the pipe's ends. The read end will
+ be dup2-ed into the stdin descriptor after the fork but before
+ the exec. */
+ if((fcntl(cp->PipeNativeSTDIN[0], F_SETFD, FD_CLOEXEC) < 0) ||
+ (fcntl(cp->PipeNativeSTDIN[1], F_SETFD, FD_CLOEXEC) < 0))
+ {
+ return 0;
+ }
+ }
else
{
si->StdIn = -1;
@@ -1340,6 +1436,17 @@ static int kwsysProcessCreate(kwsysProcess* cp, int prIndex,
si->StdOut = 1;
}
+ /* Replace the stdout pipe with the native pipe provided if any. In
+ this case the select call will report that stdout is closed
+ immediately. */
+ if(prIndex == cp->NumberOfCommands-1 && cp->PipeNativeSTDOUT[1] >= 0)
+ {
+ if(!kwsysProcessSetupOutputPipeNative(&si->StdOut, cp->PipeNativeSTDOUT))
+ {
+ return 0;
+ }
+ }
+
/* Create the error reporting pipe. */
if(pipe(si->ErrorPipe) < 0)
{
@@ -1407,8 +1514,8 @@ static int kwsysProcessCreate(kwsysProcess* cp, int prIndex,
/* Block until the child's exec call succeeds and closes the error
pipe or writes data to the pipe to report an error. */
{
- int total = 0;
- int n = 1;
+ kwsysProcess_ssize_t total = 0;
+ kwsysProcess_ssize_t n = 1;
/* Read the entire error message up to the length of our buffer. */
while(total < KWSYSPE_PIPE_BUFFER_SIZE && n > 0)
{
@@ -1520,6 +1627,26 @@ static int kwsysProcessSetupOutputPipeFile(int* p, const char* name)
}
/*--------------------------------------------------------------------------*/
+static int kwsysProcessSetupOutputPipeNative(int* p, int des[2])
+{
+ /* Close the existing descriptor. */
+ kwsysProcessCleanupDescriptor(p);
+
+ /* Set close-on-exec flag on the pipe's ends. The proper end will
+ be dup2-ed into the standard descriptor number after fork but
+ before exec. */
+ if((fcntl(des[0], F_SETFD, FD_CLOEXEC) < 0) ||
+ (fcntl(des[1], F_SETFD, FD_CLOEXEC) < 0))
+ {
+ return 0;
+ }
+
+ /* Assign the replacement descriptor. */
+ *p = des[1];
+ 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. */
static int kwsysProcessGetTimeoutTime(kwsysProcess* cp, double* userTimeout,
@@ -2201,7 +2328,10 @@ static int kwsysProcessesAdd(kwsysProcess* cp)
struct sigaction newSigChldAction;
memset(&newSigChldAction, 0, sizeof(struct sigaction));
newSigChldAction.sa_sigaction = kwsysProcessesSignalHandler;
- newSigChldAction.sa_flags = SA_NOCLDSTOP | SA_RESTART | SA_SIGINFO;
+ newSigChldAction.sa_flags = SA_NOCLDSTOP | SA_SIGINFO;
+#ifdef SA_RESTART
+ newSigChldAction.sa_flags |= SA_RESTART;
+#endif
while((sigaction(SIGCHLD, &newSigChldAction,
&kwsysProcessesOldSigChldAction) < 0) &&
(errno == EINTR));
@@ -2287,7 +2417,7 @@ static int kwsysProcessAppendByte(char* local,
/* Allocate space for the character. */
if((*end - *begin) >= *size)
{
- int length = *end - *begin;
+ kwsysProcess_ptrdiff_t length = *end - *begin;
char* newBuffer = (char*)malloc(*size*2);
if(!newBuffer)
{
@@ -2325,7 +2455,7 @@ static int kwsysProcessAppendArgument(char** local,
/* Allocate space for the argument pointer. */
if((*end - *begin) >= *size)
{
- int length = *end - *begin;
+ kwsysProcess_ptrdiff_t length = *end - *begin;
char** newPointers = (char**)malloc(*size*2*sizeof(char*));
if(!newPointers)
{
@@ -2498,14 +2628,14 @@ static char** kwsysProcessParseVerbatimCommand(const char* command)
buffer. */
if(!failed)
{
- int n = pointer_end - pointer_begin;
+ kwsysProcess_ptrdiff_t n = pointer_end - pointer_begin;
newCommand = (char**)malloc((n+1)*sizeof(char*));
}
if(newCommand)
{
/* Copy the arguments into the new command buffer. */
- int n = pointer_end - pointer_begin;
+ kwsysProcess_ptrdiff_t n = pointer_end - pointer_begin;
memcpy(newCommand, pointer_begin, sizeof(char*)*n);
newCommand[n] = 0;
}