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
63#ifdef BLOCXX_HAVE_UNISTD_H
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)
190class 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);
231class 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[],
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[],
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
417 int numOpenPipes(procs.
size() * 2);
420 for (
size_t i = 0;
i < processStates.
size(); ++
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);
#define BLOCXX_DEFINE_EXCEPTION_WITH_ID(NAME)
Define a new exception class named <NAME>Exception that derives from Exception.
#define BLOCXX_THROW(exType, msg)
Throw an exception using FILE and LINE.
#define BLOCXX_DEFINE_EXCEPTION_WITH_BASE_AND_ID(NAME, BASE)
Define a new exception class named <NAME>Exception that derives from <BASE>.
#define BLOCXX_THROW_ERRNO_MSG(exType, msg)
Throw an exception using FILE, LINE, errno and strerror(errno)
#define BLOCXX_GLOBAL_PTR_INIT
This macro is provided to abstract the details of GlobalPtr.
Array<> wraps std::vector<> in COWReference<> adding ref counting and copy on write capability.
void push_back(const T &x)
Append an element to the end of the Array.
iterator erase(iterator position)
Remove an element of the Array specified with an iterator.
virtual void doHandleData(const char *data, size_t dataLen, EOutputSource outputSource, const ProcessRef &theProc, size_t streamIndex, Array< char > &inputBuffer)=0
virtual ~OutputCallback()
void handleData(const char *data, size_t dataLen, EOutputSource outputSource, const ProcessRef &theProc, size_t streamIndex, Array< char > &inputBuffer)
This class is used to specify what spawn() should do between fork and exec.
This class can be used to store a global pointer.
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.
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.
int getPOSIXwaitpidStatus() const
Get the result from waitpid()
This String class is an abstract data type that represents as NULL terminated string of characters.
A timeout can be absolute, which means that it will happen at the specified DateTime.
static Timeout relativeWithReset(float seconds)
static Timeout relative(float seconds)
A TimeoutTimer is used by an algorithm to determine when a timeout has expired.
bool expired() const
Indicates whether the last loop time has exceeded the timeout.
void start()
Meant to be called by timeout functions which loop.
void loop()
Meant to be called by timeout functions which loop, but don't want to reset the interval.
Timeout asRelativeTimeout() const
void resetOnLoop()
Meant to be called by timeout functions which loop, and that want to reset the interval.
unsigned const BLOCXX_OUT
unsigned const BLOCXX_NPIPE
void close_child_ends(UnnamedPipeRef ppipe[BLOCXX_NPIPE])
unsigned const BLOCXX_EXEC_ERR
unsigned const BLOCXX_SERR
int safeSystem(const Array< String > &command, const char *const envp[])
This is deprecated.
ProcessRef spawnImpl(char const *exec_path, char const *const argv[], char const *const envp[], PreExec &pre_exec)
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 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...
void processInputOutput(OutputCallback &output, Array< ProcessRef > &procs, InputCallback &input, const Timeout &timeout)
Send input and wait for output from child processes.
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.
::BLOCXX_NAMESPACE::GlobalPtr< ExecMockObject, Impl::NullFactory > g_execMockObject
Process::Status system(const Array< String > &command, const char *const envp[], const Timeout &timeout)
Execute a command.
void gatherOutput(String &output, const ProcessRef &proc, int timeoutSecs, int outputLimit)
ProcessRef spawnImpl(char const *exec_path, char const *const argv[], char const *const envp[], Exec::PreExec &pre_exec)
const int SELECT_TIMEOUT
The value returned from select when the timeout value has expired.
int selectRW(SelectObjectArray &selarray, UInt32 ms)
const int SELECT_ERROR
The value returned from select when any error occurs other than timeout.
BLOCXX_COMMON_API ProcessRef spawnProcess(char const *exec_path, char const *const argv[], char const *const envp[], Exec::PreExec &pre_exec)
BLOCXX_COMMON_API bool shouldUseWaitpidThreadFix()
ProcessRef spawnImpl(char const *exec_path, char const *const argv[], char const *const envp[], Exec::PreExec &pre_exec)
IntrusiveReference< Process > ProcessRef
bool waitForRead
Input parameter. Set it to true to indicate that waiting for read availability on s is desired.
bool waitForWrite
Input parameter. Set it to true to indicate that waiting for write availability on s is desired.