blocxx
Exec.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2 * Copyright (C) 2005, Quest Software, Inc. All rights reserved.
3 * Copyright (C) 2006, Novell, Inc. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of
14 * Quest Software, Inc.,
15 * nor Novell, Inc.,
16 * nor the names of its contributors or employees may be used to
17 * endorse or promote products derived from this software without
18 * specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 *******************************************************************************/
32 
33 
38 #include "blocxx/BLOCXX_config.h"
39 #include "blocxx/Exec.hpp"
40 #include "blocxx/Select.hpp"
41 #include "blocxx/ExceptionIds.hpp"
42 #include "blocxx/TimeoutTimer.hpp"
44 #include "blocxx/GlobalPtr.hpp"
46 
47 #if !defined(BLOCXX_WIN32)
49 #include "blocxx/PosixExec.hpp"
50 #else
51 #include "blocxx/UnnamedPipe.hpp"
52 #include "blocxx/WinExec.hpp"
53 #endif
54 
55 extern "C"
56 {
57 #ifdef BLOCXX_HAVE_SYS_RESOURCE_H
58 #include <sys/resource.h>
59 #endif
60 #ifdef BLOCXX_HAVE_SYS_TYPES_H
61 #include <sys/types.h>
62 #endif
63 #ifdef BLOCXX_HAVE_UNISTD_H
64 #include <unistd.h>
65 #endif
66 #ifndef BLOCXX_WIN32
67 #include <sys/wait.h>
68 #include <fcntl.h>
69 #endif
70 }
71 
72 #ifdef BLOCXX_NCR
73 #if defined(sigaction)
74 #undef sigaction
75 #endif
76 #undef SIG_DFL
77 #define SIG_DFL (void(*)())0
78 #endif
79 
80 namespace BLOCXX_NAMESPACE
81 {
85 
86 
88 namespace Exec
89 {
91 
94 system(const Array<String>& command, const char* const envp[], const Timeout& timeout)
95 {
96 
97 #ifndef BLOCXX_WIN32
99 #else
101 #endif
102 
103  ProcessRef proc = Exec::spawn(command[0], command, envp, spe);
104 
105  proc->waitCloseTerm(Timeout::relative(0), timeout, Timeout::relative(0));
106  return proc->processStatus();
107 }
108 
109 
111 int
112 safeSystem(const Array<String>& command, const char* const envp[])
113 {
114  Process::Status ps = system(command, envp);
115  return ps.getPOSIXwaitpidStatus();
116 }
117 
120  char const * exec_path,
121  char const * const argv[], char const * const envp[],
122  PreExec & pre_exec
123 )
124 {
125 #ifdef BLOCXX_WIN32
126  return WinExec::spawnImpl(exec_path, argv, envp, pre_exec);
127 #else
128  return PosixExec::spawnImpl(exec_path, argv, envp, pre_exec);
129 #endif
130 }
131 
134  char const * exec_path,
135  char const * const argv[], char const * const envp[],
136  PreExec & pre_exec
137 )
138 {
140  {
141  return WaitpidThreadFix::spawnProcess(exec_path, argv, envp, pre_exec);
142  }
143  return spawnImpl(exec_path, argv, envp, pre_exec);
144 }
145 
148  char const * const argv[], char const * const envp[]
149 )
150 {
151 
152 #ifdef BLOCXX_WIN32
154 #else
156 #endif
157 
158  return spawn(argv[0], argv, envp, pre_exec);
159 }
160 
161 namespace Impl
162 {
164 {
165  // prevent the parent from using the child's end of the pipes.
166  if (ppipe[BLOCXX_IN])
167  {
168  ppipe[BLOCXX_IN]->closeInputHandle();
169  }
170  if (ppipe[BLOCXX_OUT])
171  {
172  ppipe[BLOCXX_OUT]->closeOutputHandle();
173  }
174  if (ppipe[BLOCXX_SERR])
175  {
176  ppipe[BLOCXX_SERR]->closeOutputHandle();
177  }
178  ppipe[BLOCXX_EXEC_ERR]->closeOutputHandle();
179 }
180 } // end namespace Impl
181 
182 namespace
183 {
184 
185 #ifndef BLOCXX_MIN
186 #define BLOCXX_MIN(x, y) (x) < (y) ? (x) : (y)
187 #endif
188 
190 class StringOutputGatherer : public OutputCallback
191 {
192 public:
193  StringOutputGatherer(String& stdoutput, String& erroutput, int outputLimit)
194  : m_output(stdoutput)
195  , m_erroutput(erroutput)
196  , m_outputLimit(outputLimit)
197  {
198  }
199  StringOutputGatherer(String& stdoutput, int outputLimit)
200  : m_output(stdoutput)
201  , m_erroutput(stdoutput)
202  , m_outputLimit(outputLimit)
203  {
204  }
205 private:
206  virtual void doHandleData(const char* data, size_t dataLen,
207  EOutputSource outputSource, const ProcessRef& theProc,
208  size_t streamIndex, Array<char>& inputBuffer)
209  {
210  String& output = (outputSource == E_STDOUT) ? m_output : m_erroutput;
211  if (m_outputLimit >= 0 && output.length() + dataLen > static_cast<size_t>(m_outputLimit))
212  {
213  // the process output too much, so just copy what we can and return error
214  int lentocopy = BLOCXX_MIN(m_outputLimit - output.length(), dataLen);
215  if (lentocopy >= 0)
216  {
217  output += String(data, lentocopy);
218  }
219  BLOCXX_THROW(ExecBufferFullException,
220  "Exec::StringOutputGatherer::doHandleData(): buffer full");
221  }
222 
223  output += String(data, dataLen);
224  }
225  String& m_output;
226  String& m_erroutput;
228 };
229 
231 class SingleStringInputCallback : public InputCallback
232 {
233 public:
234  SingleStringInputCallback(const String& s)
235  : m_s(s)
236  {
237  }
238 private:
239  virtual void doGetData(Array<char>& inputBuffer, const ProcessRef& theProc, size_t streamIndex)
240  {
241  if (m_s.length() > 0)
242  {
243  inputBuffer.insert(inputBuffer.end(), m_s.c_str(), m_s.c_str() + m_s.length());
244  m_s.erase();
245  }
246  else if (theProc->in()->isOpen())
247  {
248  theProc->in()->close();
249  }
250  }
251  String m_s;
252 };
253 
254 }// end anonymous namespace
255 
258  char const * const command[],
259  String& output,
260  char const * const envVars[],
261  const Timeout& timeout,
262  int outputLimit,
263  char const * input)
264 {
265  if (g_execMockObject.get())
266  {
267  return g_execMockObject.get()->executeProcessAndGatherOutput(command, output, envVars, timeout, outputLimit, input);
268  }
269  return feedProcessAndGatherOutput(spawn(command, envVars),
270  output, timeout, outputLimit, input);
271 }
272 
275  char const * const command[],
276  String& output,
277  String& erroutput,
278  char const * const envVars[],
279  const Timeout& timeout,
280  int outputLimit,
281  char const * input)
282 {
283  if (g_execMockObject.get())
284  {
285  return g_execMockObject.get()->executeProcessAndGatherOutput2(command, output,
286  erroutput, envVars, timeout, outputLimit, input);
287  }
288 
289  return feedProcessAndGatherOutput(spawn(command, envVars),
290  output, erroutput, timeout, outputLimit, input);
291 }
292 
294 BLOCXX_COMMON_API void executeProcessAndGatherOutput(
295  const Array<String>& command,
296  String& output, int& processstatus,
297  int timeoutsecs, int outputlimit,
298  const String& input)
299 {
300  Timeout timeout = Timeout::infinite;
301  if (timeoutsecs != -1)
302  {
303  timeout = Timeout::relative(timeoutsecs);
304  }
306  output,
307  timeout,
308  outputlimit, input);
309 
310  processstatus = ps.getPOSIXwaitpidStatus();
311 }
312 
315  ProcessRef const & proc,
316  String & output,
317  Timeout const & timeout,
318  int outputLimit,
319  String const & input)
320 {
321  Array<ProcessRef> procarr(1, proc);
322  SingleStringInputCallback singleStringInputCallback(input);
323 
324  StringOutputGatherer gatherer(output, outputLimit);
325  processInputOutput(gatherer, procarr, singleStringInputCallback, timeout);
326  proc->waitCloseTerm();
327  return proc->processStatus();
328 }
329 
332  ProcessRef const & proc,
333  String & output,
334  String & erroutput,
335  Timeout const & timeout,
336  int outputLimit,
337  String const & input)
338 {
339  Array<ProcessRef> procarr(1, proc);
340  SingleStringInputCallback singleStringInputCallback(input);
341 
342  StringOutputGatherer gatherer(output, erroutput, outputLimit);
343  processInputOutput(gatherer, procarr, singleStringInputCallback, timeout);
344  proc->waitCloseTerm();
345  return proc->processStatus();
346 }
347 
349 void
350 gatherOutput(String& output, const ProcessRef& proc, int timeoutSecs, int outputLimit)
351 {
352  gatherOutput(output, proc, Timeout::relativeWithReset(timeoutSecs), outputLimit);
353 }
355 void
356 gatherOutput(String& output, const ProcessRef& proc, const Timeout& timeout, int outputLimit)
357 {
358  Array<ProcessRef> procs(1, proc);
359 
360  StringOutputGatherer gatherer(output, outputLimit);
361  SingleStringInputCallback singleStringInputCallback = SingleStringInputCallback(String());
362  processInputOutput(gatherer, procs, singleStringInputCallback, timeout);
363 }
364 
367 {
368 
369 }
370 
372 void
373 OutputCallback::handleData(const char* data, size_t dataLen, EOutputSource outputSource, const ProcessRef& theProc, size_t streamIndex, Array<char>& inputBuffer)
374 {
375  doHandleData(data, dataLen, outputSource, theProc, streamIndex, inputBuffer);
376 }
377 
380 {
381 }
382 
384 void
385 InputCallback::getData(Array<char>& inputBuffer, const ProcessRef& theProc, size_t streamIndex)
386 {
387  doGetData(inputBuffer, theProc, streamIndex);
388 }
389 
390 namespace
391 {
392  struct ProcessOutputState
393  {
394  bool inIsOpen;
395  bool outIsOpen;
396  bool errIsOpen;
398 
399  ProcessOutputState()
400  : inIsOpen(true)
401  , outIsOpen(true)
402  , errIsOpen(true)
403  , availableDataLen(0)
404  {
405  }
406  };
407 
408 }
409 
411 void
413 {
414  TimeoutTimer timer(timeout);
415 
416  Array<ProcessOutputState> processStates(procs.size());
417  int numOpenPipes(procs.size() * 2); // count of stdout & stderr. Ignore stdin for purposes of algorithm termination.
418 
419  Array<Array<char> > inputs(processStates.size());
420  for (size_t i = 0; i < processStates.size(); ++i)
421  {
422  input.getData(inputs[i], procs[i], i);
423  processStates[i].availableDataLen = inputs[i].size();
424  if (!procs[i]->out()->isOpen())
425  {
426  processStates[i].outIsOpen = false;
427  }
428  if (!procs[i]->err()->isOpen())
429  {
430  processStates[i].errIsOpen = false;
431  }
432  if (!procs[i]->in()->isOpen())
433  {
434  processStates[i].inIsOpen = false;
435  }
436 
437  }
438 
439  timer.start();
440 
441  while (numOpenPipes > 0)
442  {
443  Select::SelectObjectArray selObjs;
444  std::map<int, int> inputIndexProcessIndex;
445  std::map<int, int> outputIndexProcessIndex;
446  for (size_t i = 0; i < procs.size(); ++i)
447  {
448  if (processStates[i].outIsOpen)
449  {
450  Select::SelectObject selObj(procs[i]->out()->getReadSelectObj());
451  selObj.waitForRead = true;
452  selObjs.push_back(selObj);
453  inputIndexProcessIndex[selObjs.size() - 1] = i;
454  }
455  if (processStates[i].errIsOpen)
456  {
457  Select::SelectObject selObj(procs[i]->err()->getReadSelectObj());
458  selObj.waitForRead = true;
459  selObjs.push_back(selObj);
460  inputIndexProcessIndex[selObjs.size() - 1] = i;
461  }
462  if (processStates[i].inIsOpen && processStates[i].availableDataLen > 0)
463  {
464  Select::SelectObject selObj(procs[i]->in()->getWriteSelectObj());
465  selObj.waitForWrite = true;
466  selObjs.push_back(selObj);
467  outputIndexProcessIndex[selObjs.size() - 1] = i;
468  }
469 
470  }
471 
472  int selectrval = Select::selectRW(selObjs, timer.asRelativeTimeout());
473  switch (selectrval)
474  {
476  {
477  BLOCXX_THROW_ERRNO_MSG(ExecErrorException, "Exec::gatherOutput: error selecting on stdout and stderr");
478  }
479  break;
481  {
482  timer.loop();
483  if (timer.expired())
484  {
485  BLOCXX_THROW(ExecTimeoutException, "Exec::gatherOutput: timedout");
486  }
487  }
488  break;
489  default:
490  {
491  int availableToFind = selectrval;
492 
493  // reset the timeout counter
494  timer.resetOnLoop();
495 
496  for (size_t i = 0; i < selObjs.size() && availableToFind > 0; ++i)
497  {
498  if (!selObjs[i].readAvailable)
499  {
500  continue;
501  }
502  else
503  {
504  --availableToFind;
505  }
506  int streamIndex = inputIndexProcessIndex[i];
507  UnnamedPipeRef readstream;
508  if (processStates[streamIndex].outIsOpen)
509  {
510  if (procs[streamIndex]->out()->getReadSelectObj() == selObjs[i].s)
511  {
512  readstream = procs[streamIndex]->out();
513  }
514  }
515 
516  if (!readstream && processStates[streamIndex].errIsOpen)
517  {
518  if (procs[streamIndex]->err()->getReadSelectObj() == selObjs[i].s)
519  {
520  readstream = procs[streamIndex]->err();
521  }
522  }
523 
524  if (!readstream)
525  {
526  continue; // for loop
527  }
528 
529  char buff[1024];
530  int readrc = readstream->read(buff, sizeof(buff) - 1);
531  if (readrc == 0)
532  {
533  if (readstream == procs[streamIndex]->out())
534  {
535  processStates[streamIndex].outIsOpen = false;
536  procs[streamIndex]->out()->close();
537  }
538  else
539  {
540  processStates[streamIndex].errIsOpen = false;
541  procs[streamIndex]->err()->close();
542  }
543  --numOpenPipes;
544  }
545  else if (readrc == -1)
546  {
547  BLOCXX_THROW_ERRNO_MSG(ExecErrorException, "Exec::gatherOutput: read error");
548  }
549  else
550  {
551  buff[readrc] = '\0';
552  output.handleData(
553  buff,
554  readrc,
555  readstream == procs[streamIndex]->out() ? E_STDOUT : E_STDERR,
556  procs[streamIndex],
557  streamIndex, inputs[streamIndex]);
558  }
559  }
560 
561  // handle stdin for all processes which have data to send to them.
562  for (size_t i = 0; i < selObjs.size() && availableToFind > 0; ++i)
563  {
564  if (!selObjs[i].writeAvailable)
565  {
566  continue;
567  }
568  else
569  {
570  --availableToFind;
571  }
572  int streamIndex = outputIndexProcessIndex[i];
573  UnnamedPipeRef writestream;
574  if (processStates[streamIndex].inIsOpen)
575  {
576  writestream = procs[streamIndex]->in();
577  }
578 
579  if (!writestream)
580  {
581  continue; // for loop
582  }
583 
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)
587  {
588  processStates[streamIndex].inIsOpen = false;
589  procs[streamIndex]->in()->close();
590  }
591  else if (writerc == -1)
592  {
593  BLOCXX_THROW_ERRNO_MSG(ExecErrorException, "Exec::gatherOutput: write error");
594  }
595  else if (writerc != 0)
596  {
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();
600  }
601  }
602  }
603  break;
604  }
605  }
606 }
607 
608 void processInputOutput(const String& input, String& output, const ProcessRef& process,
609  const Timeout& timeout, int outputLimit)
610 {
611  Array<ProcessRef> procs;
612  procs.push_back(process);
613 
614  StringOutputGatherer gatherer(output, outputLimit);
615  SingleStringInputCallback singleStringInputCallback = SingleStringInputCallback(input);
616  processInputOutput(gatherer, procs, singleStringInputCallback, timeout);
617 }
618 
619 
620 } // end namespace Exec
621 
622 } // end namespace BLOCXX_NAMESPACE
623 
unsigned const BLOCXX_IN
Definition: Exec.hpp:784
unsigned const BLOCXX_OUT
Definition: Exec.hpp:785
String m_s
Definition: Exec.cpp:251
A TimeoutTimer is used by an algorithm to determine when a timeout has expired.
String & m_output
Definition: Exec.cpp:225
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...
Definition: Select.hpp:105
void getData(Array< char > &inputBuffer, const ProcessRef &theProc, size_t streamIndex)
Definition: Exec.cpp:385
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...
Definition: Exec.cpp:133
ProcessRef spawnImpl(char const *exec_path, char const *const argv[], char const *const envp[], Exec::PreExec &pre_exec)
Definition: Exec.cpp:119
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
Definition: Exec.hpp:786
size_t availableDataLen
Definition: Exec.cpp:397
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.
Definition: GlobalPtr.hpp:146
String & m_erroutput
Definition: Exec.cpp:226
::BLOCXX_NAMESPACE::GlobalPtr< ExecMockObject, Impl::NullFactory > g_execMockObject
Definition: Exec.cpp:90
This String class is an abstract data type that represents as NULL terminated string of characters...
Definition: String.hpp:66
void gatherOutput(String &output, const ProcessRef &proc, int timeoutSecs, int outputLimit)
Definition: Exec.cpp:350
void handleData(const char *data, size_t dataLen, EOutputSource outputSource, const ProcessRef &theProc, size_t streamIndex, Array< char > &inputBuffer)
Definition: Exec.cpp:373
virtual void doGetData(Array< char > &inputBuffer, const ProcessRef &theProc, size_t streamIndex)=0
#define BLOCXX_DEFINE_EXCEPTION_WITH_ID(NAME)
Define a new exception class named <NAME>Exception that derives from Exception.
Definition: Exception.hpp:449
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.
bool expired() const
Indicates whether the last loop time has exceeded the timeout.
bool errIsOpen
Definition: Exec.cpp:396
unsigned const BLOCXX_NPIPE
Definition: Exec.hpp:788
BLOCXX_COMMON_API bool shouldUseWaitpidThreadFix()
bool inIsOpen
Definition: Exec.cpp:394
This class is used to specify what spawn() should do between fork and exec.
Definition: Exec.hpp:105
#define BLOCXX_DEFINE_EXCEPTION_WITH_BASE_AND_ID(NAME, BASE)
Define a new exception class named <NAME>Exception that derives from <BASE>.
Definition: Exception.hpp:460
static Timeout relative(float seconds)
Definition: Timeout.cpp:58
const int SELECT_ERROR
The value returned from select when any error occurs other than timeout.
Definition: Select.hpp:63
bool outIsOpen
Definition: Exec.cpp:395
void processInputOutput(OutputCallback &output, Array< ProcessRef > &procs, InputCallback &input, const Timeout &timeout)
Send input and wait for output from child processes.
Definition: Exec.cpp:412
const int SELECT_TIMEOUT
The value returned from select when the timeout value has expired.
Definition: Select.hpp:59
Process::Status system(const Array< String > &command, const char *const envp[], const Timeout &timeout)
Execute a command.
Definition: Exec.cpp:94
unsigned const BLOCXX_EXEC_ERR
Definition: Exec.hpp:787
Portable process status.
Definition: Process.hpp:122
int m_outputLimit
Definition: Exec.cpp:227
virtual void doHandleData(const char *data, size_t dataLen, EOutputSource outputSource, const ProcessRef &theProc, size_t streamIndex, Array< char > &inputBuffer)=0
A timeout can be absolute, which means that it will happen at the specified DateTime.
Definition: Timeout.hpp:55
void start()
Meant to be called by timeout functions which loop.
#define BLOCXX_MIN(x, y)
Definition: Exec.cpp:186
bool waitForRead
Input parameter. Set it to true to indicate that waiting for read availability on s is desired...
Definition: Select.hpp:103
static Timeout infinite
Definition: Timeout.hpp:62
int getPOSIXwaitpidStatus() const
Get the result from waitpid()
Definition: Process.cpp:191
void push_back(const T &x)
Append an element to the end of the Array.
Definition: ArrayImpl.hpp:251
int safeSystem(const Array< String > &command, const char *const envp[])
This is deprecated.
Definition: Exec.cpp:112
Timeout asRelativeTimeout() const
#define BLOCXX_THROW(exType, msg)
Throw an exception using FILE and LINE.
Definition: Exception.hpp:263
static Timeout relativeWithReset(float seconds)
Definition: Timeout.cpp:66
void close_child_ends(UnnamedPipeRef ppipe[BLOCXX_NPIPE])
Definition: Exec.cpp:163
int selectRW(SelectObjectArray &selarray, UInt32 ms)
Definition: Select.cpp:92
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)
Definition: PosixExec.cpp:393
IntrusiveReference< Process > ProcessRef
Definition: CommonFwd.hpp:159
#define BLOCXX_THROW_ERRNO_MSG(exType, msg)
Throw an exception using FILE, LINE, errno and strerror(errno)
Definition: Exception.hpp:312
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.
Definition: Exec.cpp:257
ProcessRef spawnImpl(char const *exec_path, char const *const argv[], char const *const envp[], PreExec &pre_exec)
Definition: Exec.cpp:119
size_type size() const
Definition: ArrayImpl.hpp:160
This class can be used to store a global pointer.
Definition: GlobalPtr.hpp:83
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.
Definition: Exec.cpp:314