38 #include "blocxx/BLOCXX_config.h" 47 #if !defined(BLOCXX_WIN32) 57 #ifdef BLOCXX_HAVE_SYS_RESOURCE_H 58 #include <sys/resource.h> 60 #ifdef BLOCXX_HAVE_SYS_TYPES_H 61 #include <sys/types.h> 63 #ifdef BLOCXX_HAVE_UNISTD_H 73 #if defined(sigaction) 77 #define SIG_DFL (void(*)())0 106 return proc->processStatus();
120 char const * exec_path,
121 char const *
const argv[],
char const *
const envp[],
134 char const * exec_path,
135 char const *
const argv[],
char const *
const envp[],
143 return spawnImpl(exec_path, argv, envp, pre_exec);
148 char const *
const argv[],
char const *
const envp[]
158 return spawn(argv[0], argv, envp, pre_exec);
186 #define BLOCXX_MIN(x, y) (x) < (y) ? (x) : (y) 190 class StringOutputGatherer :
public OutputCallback
193 StringOutputGatherer(String& stdoutput, String& erroutput,
int outputLimit)
199 StringOutputGatherer(String& stdoutput,
int outputLimit)
206 virtual void doHandleData(
const char* data,
size_t dataLen,
208 size_t streamIndex, Array<char>& inputBuffer)
217 output += String(data, lentocopy);
220 "Exec::StringOutputGatherer::doHandleData(): buffer full");
223 output += String(data, dataLen);
231 class SingleStringInputCallback :
public InputCallback
234 SingleStringInputCallback(
const String& s)
239 virtual void doGetData(Array<char>& inputBuffer,
const ProcessRef& theProc,
size_t streamIndex)
241 if (
m_s.length() > 0)
243 inputBuffer.insert(inputBuffer.end(),
m_s.c_str(),
m_s.c_str() +
m_s.length());
246 else if (theProc->in()->isOpen())
248 theProc->in()->close();
258 char const *
const command[],
260 char const *
const envVars[],
265 if (g_execMockObject.
get())
267 return g_execMockObject.
get()->executeProcessAndGatherOutput(command, output, envVars, timeout, outputLimit, input);
270 output, timeout, outputLimit, input);
275 char const *
const command[],
278 char const *
const envVars[],
283 if (g_execMockObject.
get())
285 return g_execMockObject.
get()->executeProcessAndGatherOutput2(command, output,
286 erroutput, envVars, timeout, outputLimit, input);
290 output, erroutput, timeout, outputLimit, input);
296 String& output,
int& processstatus,
297 int timeoutsecs,
int outputlimit,
301 if (timeoutsecs != -1)
322 SingleStringInputCallback singleStringInputCallback(input);
324 StringOutputGatherer gatherer(output, outputLimit);
326 proc->waitCloseTerm();
327 return proc->processStatus();
340 SingleStringInputCallback singleStringInputCallback(input);
342 StringOutputGatherer gatherer(output, erroutput, outputLimit);
344 proc->waitCloseTerm();
345 return proc->processStatus();
360 StringOutputGatherer gatherer(output, outputLimit);
361 SingleStringInputCallback singleStringInputCallback = SingleStringInputCallback(
String());
375 doHandleData(data, dataLen, outputSource, theProc, streamIndex, inputBuffer);
387 doGetData(inputBuffer, theProc, streamIndex);
392 struct ProcessOutputState
403 , availableDataLen(0)
417 int numOpenPipes(procs.
size() * 2);
420 for (
size_t i = 0;
i < processStates.size(); ++
i)
422 input.
getData(inputs[
i], procs[i], i);
423 processStates[
i].availableDataLen = inputs[
i].size();
424 if (!procs[i]->out()->isOpen())
426 processStates[
i].outIsOpen =
false;
428 if (!procs[i]->err()->isOpen())
430 processStates[
i].errIsOpen =
false;
432 if (!procs[i]->in()->isOpen())
434 processStates[
i].inIsOpen =
false;
441 while (numOpenPipes > 0)
444 std::map<int, int> inputIndexProcessIndex;
445 std::map<int, int> outputIndexProcessIndex;
446 for (
size_t i = 0;
i < procs.
size(); ++
i)
453 inputIndexProcessIndex[selObjs.
size() - 1] =
i;
460 inputIndexProcessIndex[selObjs.
size() - 1] =
i;
467 outputIndexProcessIndex[selObjs.
size() - 1] =
i;
491 int availableToFind = selectrval;
496 for (
size_t i = 0;
i < selObjs.
size() && availableToFind > 0; ++
i)
498 if (!selObjs[
i].readAvailable)
506 int streamIndex = inputIndexProcessIndex[
i];
508 if (processStates[streamIndex].
outIsOpen)
510 if (procs[streamIndex]->out()->getReadSelectObj() == selObjs[
i].s)
512 readstream = procs[streamIndex]->out();
516 if (!readstream && processStates[streamIndex].
errIsOpen)
518 if (procs[streamIndex]->err()->getReadSelectObj() == selObjs[
i].s)
520 readstream = procs[streamIndex]->err();
530 int readrc = readstream->
read(buff,
sizeof(buff) - 1);
533 if (readstream == procs[streamIndex]->out())
535 processStates[streamIndex].outIsOpen =
false;
536 procs[streamIndex]->out()->close();
540 processStates[streamIndex].errIsOpen =
false;
541 procs[streamIndex]->err()->close();
545 else if (readrc == -1)
557 streamIndex, inputs[streamIndex]);
562 for (
size_t i = 0;
i < selObjs.
size() && availableToFind > 0; ++
i)
564 if (!selObjs[
i].writeAvailable)
572 int streamIndex = outputIndexProcessIndex[
i];
574 if (processStates[streamIndex].
inIsOpen)
576 writestream = procs[streamIndex]->in();
584 size_t offset = inputs[streamIndex].
size() - processStates[streamIndex].availableDataLen;
585 int writerc = writestream->
write(&inputs[streamIndex][offset], processStates[streamIndex].
availableDataLen);
586 if (writerc == -1 && errno == EPIPE)
588 processStates[streamIndex].inIsOpen =
false;
589 procs[streamIndex]->in()->close();
591 else if (writerc == -1)
595 else if (writerc != 0)
597 inputs[streamIndex].erase(inputs[streamIndex].begin(), inputs[streamIndex].begin() + writerc);
598 input.
getData(inputs[streamIndex], procs[streamIndex], streamIndex);
599 processStates[streamIndex].availableDataLen = inputs[streamIndex].size();
609 const Timeout& timeout,
int outputLimit)
614 StringOutputGatherer gatherer(output, outputLimit);
615 SingleStringInputCallback singleStringInputCallback = SingleStringInputCallback(input);
unsigned const BLOCXX_OUT
A TimeoutTimer is used by an algorithm to determine when a timeout has expired.
void loop()
Meant to be called by timeout functions which loop, but don't want to reset the interval.
bool waitForWrite
Input parameter. Set it to true to indicate that waiting for write availability on s is desired...
ProcessRef spawn(char const *exec_path, char const *const argv[], char const *const envp[], PreExec &pre_exec)
Run the executable exec_path in a child process, with argv for the program arguments and envp for the...
ProcessRef spawnImpl(char const *exec_path, char const *const argv[], char const *const envp[], Exec::PreExec &pre_exec)
BLOCXX_COMMON_API ProcessRef spawnProcess(char const *exec_path, char const *const argv[], char const *const envp[], Exec::PreExec &pre_exec)
unsigned const BLOCXX_SERR
virtual int write(const void *dataOut, int dataOutLen, ErrorAction errorAsException=E_RETURN_ON_ERROR)=0
Write a specified number of bytes to the device that is exposing the IOIFC interface.
#define BLOCXX_GLOBAL_PTR_INIT
This macro is provided to abstract the details of GlobalPtr.
::BLOCXX_NAMESPACE::GlobalPtr< ExecMockObject, Impl::NullFactory > g_execMockObject
This String class is an abstract data type that represents as NULL terminated string of characters...
Timeout asRelativeTimeout() const
void gatherOutput(String &output, const ProcessRef &proc, int timeoutSecs, int outputLimit)
void handleData(const char *data, size_t dataLen, EOutputSource outputSource, const ProcessRef &theProc, size_t streamIndex, Array< char > &inputBuffer)
int getPOSIXwaitpidStatus() const
Get the result from waitpid()
#define BLOCXX_DEFINE_EXCEPTION_WITH_ID(NAME)
Define a new exception class named <NAME>Exception that derives from Exception.
virtual int read(void *dataIn, int dataInLen, ErrorAction errorAsException=E_RETURN_ON_ERROR)=0
Read a specified number of bytes from the device that is exposing the IOIFC interface.
unsigned const BLOCXX_NPIPE
BLOCXX_COMMON_API bool shouldUseWaitpidThreadFix()
This class is used to specify what spawn() should do between fork and exec.
#define BLOCXX_DEFINE_EXCEPTION_WITH_BASE_AND_ID(NAME, BASE)
Define a new exception class named <NAME>Exception that derives from <BASE>.
static Timeout relative(float seconds)
const int SELECT_ERROR
The value returned from select when any error occurs other than timeout.
void processInputOutput(OutputCallback &output, Array< ProcessRef > &procs, InputCallback &input, const Timeout &timeout)
Send input and wait for output from child processes.
const int SELECT_TIMEOUT
The value returned from select when the timeout value has expired.
Process::Status system(const Array< String > &command, const char *const envp[], const Timeout &timeout)
Execute a command.
unsigned const BLOCXX_EXEC_ERR
A timeout can be absolute, which means that it will happen at the specified DateTime.
void start()
Meant to be called by timeout functions which loop.
bool waitForRead
Input parameter. Set it to true to indicate that waiting for read availability on s is desired...
void push_back(const T &x)
Append an element to the end of the Array.
int safeSystem(const Array< String > &command, const char *const envp[])
This is deprecated.
#define BLOCXX_THROW(exType, msg)
Throw an exception using FILE and LINE.
static Timeout relativeWithReset(float seconds)
void close_child_ends(UnnamedPipeRef ppipe[BLOCXX_NPIPE])
int selectRW(SelectObjectArray &selarray, UInt32 ms)
void resetOnLoop()
Meant to be called by timeout functions which loop, and that want to reset the interval.
ProcessRef spawnImpl(char const *exec_path, char const *const argv[], char const *const envp[], Exec::PreExec &pre_exec)
T * get() const
Gets the current value of the pointer.
IntrusiveReference< Process > ProcessRef
#define BLOCXX_THROW_ERRNO_MSG(exType, msg)
Throw an exception using FILE, LINE, errno and strerror(errno)
virtual ~OutputCallback()
Process::Status executeProcessAndGatherOutput(char const *const command[], String &output, char const *const envVars[], const Timeout &timeout, int outputLimit, char const *input)
Execute a command and run feedProcessAndGatherOutput() on the process.
ProcessRef spawnImpl(char const *exec_path, char const *const argv[], char const *const envp[], PreExec &pre_exec)
This class can be used to store a global pointer.
Process::Status feedProcessAndGatherOutput(ProcessRef const &proc, String &output, Timeout const &timeout, int outputLimit, String const &input)
Send input to a process, collect the output, and wait for it to exit.
bool expired() const
Indicates whether the last loop time has exceeded the timeout.