blocxx
Exec.hpp
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
37
38#ifndef BLOCXX_EXEC_HPP_INCLUDE_GUARD_
39#define BLOCXX_EXEC_HPP_INCLUDE_GUARD_
40
41#include "blocxx/BLOCXX_config.h"
42#include "blocxx/CommonFwd.hpp"
43#include "blocxx/EnvVars.hpp"
44#include "blocxx/Process.hpp"
45#ifdef BLOCXX_ENABLE_TEST_HOOKS
46#include "blocxx/GlobalPtr.hpp"
47#endif
48
49namespace BLOCXX_NAMESPACE
50{
51
52BLOCXX_DECLARE_APIEXCEPTION(ExecError, BLOCXX_COMMON_API);
53BLOCXX_DECLARE_APIEXCEPTION2(ExecTimeout, ExecErrorException, BLOCXX_COMMON_API);
54BLOCXX_DECLARE_APIEXCEPTION2(ExecBufferFull, ExecErrorException, BLOCXX_COMMON_API);
55
57namespace Exec
58{
84 BLOCXX_COMMON_API Process::Status system(const Array<String>& command,
85 const char* const envp[] = 0, const Timeout& = Timeout::infinite);
86
87 template <typename SA1, typename SA2>
88 Process::Status system(const SA1& command,
89 const SA2& envVars, const Timeout& timeout = Timeout::infinite)
90 {
91 Cstr::CstrArr<SA1> sa_command(command);
92 Cstr::CstrArr<SA2> sa_envVars(envVars);
93 return system(sa_command.sarr, sa_envVars.sarr, timeout);
94 }
95
97 BLOCXX_COMMON_API int safeSystem(const Array<String>& command,
98 const char* const envp[] = 0) BLOCXX_DEPRECATED;
99
100
105 class BLOCXX_COMMON_API PreExec
106 {
107 public:
109
110 PreExec(bool precompute_max_descriptors = false);
111
112 virtual ~PreExec();
113
122 virtual bool keepStd(int d) const = 0;
123
124 struct Error
125 {
126 enum { MAX_MSG_LEN = 64 };
127 char message[MAX_MSG_LEN + 1]; // must be null-terminated
128 int error_num; // errno value; 0 means no errno value
129 };
130
135 {
136 virtual ~DontCatch();
137 };
138
158 virtual void call(pipe_pointer_t const pparr[]) = 0;
159
166 void closeDescriptorsOnExec(std::vector<bool> const & keep);
167
172 static void resetSignals();
173
180 static void closePipesOnExec(pipe_pointer_t const pparr[]);
181
189 static void setupStandardDescriptors(pipe_pointer_t const pparr[]);
190
197 static void setNewProcessGroup();
198
199 protected:
201 };
202
205 static char const * const * const currentEnvironment = 0;
206
229 BLOCXX_COMMON_API ProcessRef spawn(
230 char const * exec_path,
231 char const * const argv[], char const * const envp[],
232 PreExec & pre_exec
233 );
234
246 template <typename S, typename SA1, typename SA2>
248 S const & exec_path, SA1 const & argv, SA2 const & envp,
249 PreExec & pre_exec
250 )
251 {
252 Cstr::CstrArr<SA1> sa_argv(argv);
253 Cstr::CstrArr<SA2> sa_envp(envp);
254 char const * s_exec_path = Cstr::to_char_ptr(exec_path);
255 return spawn(s_exec_path, sa_argv.sarr, sa_envp.sarr, pre_exec);
256 }
257
259 //
260 BLOCXX_COMMON_API ProcessRef spawn(
261 char const * const argv[], char const * const envp[]
262 );
263
271 template <typename SA1, typename SA2>
273 SA1 const & argv, SA2 const & envp
274 )
275 {
276 Cstr::CstrArr<SA1> sa_argv(argv);
277 Cstr::CstrArr<SA2> sa_envp(envp);
278 return spawn(sa_argv.sarr, sa_envp.sarr);
279 }
280
281 template <typename SA1>
283 SA1 const & argv
284 )
285 {
286 return spawn(argv, Exec::currentEnvironment);
287 }
288
316 BLOCXX_COMMON_API void gatherOutput(String& output, const ProcessRef& proc, const Timeout& timeout = Timeout::infinite, int outputlimit = -1);
317
323
324 class BLOCXX_COMMON_API OutputCallback
325 {
326 public:
327 virtual ~OutputCallback();
328 void handleData(const char* data, size_t dataLen, EOutputSource outputSource, const ProcessRef& theProc, size_t streamIndex, Array<char>& inputBuffer);
329 private:
334 virtual void doHandleData(const char* data, size_t dataLen, EOutputSource outputSource, const ProcessRef& theProc, size_t streamIndex, Array<char>& inputBuffer) = 0;
335 };
336
337 class BLOCXX_COMMON_API InputCallback
338 {
339 public:
340 virtual ~InputCallback();
341 void getData(Array<char>& inputBuffer, const ProcessRef& theProc, size_t streamIndex);
342 private:
343 virtual void doGetData(Array<char>& inputBuffer, const ProcessRef& theProc, size_t streamIndex) = 0;
344 };
345#if 0
346 enum EProcessRunning
347 {
348 E_PROCESS_RUNNING,
349 E_PROCESS_EXITED
350 };
351
352 // class invariant: if m_running == E_PROCESS_RUNNING, then m_status == 0.
353 class ProcessStatus
354 {
355 public:
356 ProcessStatus()
357 : m_running(E_PROCESS_RUNNING)
358 , m_status(0)
359 {
360 }
361
362 explicit ProcessStatus(int status)
363 : m_running(E_PROCESS_EXITED)
364 , m_status(status)
365 {
366 }
367
368 bool hasExited() const
369 {
370 return m_running == E_PROCESS_EXITED;
371 }
372
373 const int& getStatus() const
374 {
375 return m_status;
376 }
377 private:
378 EProcessRunning m_running;
379 int m_status;
380 };
381#endif
382
407 BLOCXX_COMMON_API void processInputOutput(OutputCallback& output, Array<ProcessRef>& procs,
408 InputCallback& input, const Timeout& timeout = Timeout::infinite);
409
410
411 BLOCXX_COMMON_API void processInputOutput(const String& input, String& output, const ProcessRef& process,
412 const Timeout& timeout = Timeout::infinite, int outputlimit = -1);
413
449 BLOCXX_COMMON_API Process::Status feedProcessAndGatherOutput(
450 ProcessRef const & proc, String & output,
451 Timeout const & timeout = Timeout::infinite, int outputlimit = -1,
452 String const & input = String());
453
492 BLOCXX_COMMON_API Process::Status feedProcessAndGatherOutput(
493 ProcessRef const & proc, String & output,
494 String & erroutput, Timeout const & timeout = Timeout::infinite,
495 int outputLimit = -1,
496 String const & input = String());
497
528 BLOCXX_COMMON_API Process::Status executeProcessAndGatherOutput(
529 char const * const command[], String& output, char const * const envVars[],
530 const Timeout& timeout = Timeout::infinite, int outputlimit = -1,
531 char const * input = 0);
532
565 BLOCXX_COMMON_API Process::Status executeProcessAndGatherOutput(
566 char const * const command[], String& output, String& erroutput,
567 char const * const envVars[],
568 const Timeout& timeout = Timeout::infinite, int outputLimit = -1,
569 char const * input = 0);
570
575 template <typename SA1, typename S1, typename S2>
577 SA1 const & command, S1& output,
578 const Timeout& timeout, int outputlimit, S2 const& input)
579 {
580 Cstr::CstrArr<SA1> sa_command(command);
581 String tmpOutput;
582 char const * sInput = Cstr::to_char_ptr(input);
583 Process::Status res;
584 try
585 {
586 res = executeProcessAndGatherOutput(sa_command.sarr, tmpOutput,
587 currentEnvironment, timeout, outputlimit, sInput);
588 }
589 catch(...)
590 {
591 output = tmpOutput.c_str();
592 throw;
593 }
594 output = tmpOutput.c_str();
595 return res;
596 }
597
603 template <typename SA1, typename S1, typename S2>
605 SA1 const & command, S1& output, S1& erroutput,
606 const Timeout& timeout, int outputlimit, S2 const& input)
607 {
608 Cstr::CstrArr<SA1> sa_command(command);
609 String tmpOutput, tmpErrOut;
610 char const * sInput = Cstr::to_char_ptr(input);
611 Process::Status res;
612 try
613 {
614 res = executeProcessAndGatherOutput(sa_command.sarr, tmpOutput,
615 tmpErrOut, currentEnvironment, timeout, outputlimit, sInput);
616 }
617 catch(...)
618 {
619 output = tmpOutput.c_str();
620 erroutput = tmpErrOut.c_str();
621 throw;
622 }
623 output = tmpOutput.c_str();
624 erroutput = tmpErrOut.c_str();
625 return res;
626 }
627
632 template <typename SA1, typename S1>
634 SA1 const & command, S1& output,
635 const Timeout& timeout = Timeout::infinite, int outputlimit = -1)
636 {
637 Cstr::CstrArr<SA1> sa_command(command);
638 String tmpOutput;
639 Process::Status res;
640 try
641 {
642 res = executeProcessAndGatherOutput(sa_command.sarr, tmpOutput,
643 currentEnvironment, timeout, outputlimit, (char const*)0);
644 }
645 catch(...)
646 {
647 output = tmpOutput.c_str();
648 throw;
649 }
650 output = tmpOutput.c_str();
651 return res;
652 }
653
659 template <typename SA1, typename S1>
661 SA1 const & command, S1& output, S1& erroutput,
662 const Timeout& timeout = Timeout::infinite, int outputlimit = -1)
663 {
664 Cstr::CstrArr<SA1> sa_command(command);
665 String tmpOutput, tmpErrOut;
666 Process::Status res;
667 try
668 {
669 res = executeProcessAndGatherOutput(sa_command.sarr, tmpOutput,
670 tmpErrOut, currentEnvironment, timeout, outputlimit,
671 (char const*)0);
672 }
673 catch(...)
674 {
675 output = tmpOutput.c_str();
676 erroutput = tmpErrOut.c_str();
677 throw;
678 }
679 output = tmpOutput.c_str();
680 erroutput = tmpErrOut.c_str();
681 return res;
682 }
683
697 template <typename SA1, typename S1, typename SA2, typename S2>
699 SA1 const & command, S1& output, SA2 const & envp,
700 const Timeout& timeout, int outputlimit, S2 const& input)
701 {
702 Cstr::CstrArr<SA1> sa_command(command);
703 Cstr::CstrArr<SA2> sa_envp(envp);
704 String tmpOutput;
705 char const * sInput = Cstr::to_char_ptr(input);
706 Process::Status res;
707 try
708 {
709 res = executeProcessAndGatherOutput(sa_command.sarr, tmpOutput, sa_envp.sarr,
710 timeout, outputlimit, sInput);
711 }
712 catch(...)
713 {
714 output = tmpOutput.c_str();
715 throw;
716 }
717 output = tmpOutput.c_str();
718 return res;
719 }
720
735 template <typename SA1, typename S1, typename SA2, typename S2>
737 SA1 const & command, S1& output, S1& erroutput, SA2 const & envp,
738 const Timeout& timeout, int outputlimit, S2 const& input)
739 {
740 Cstr::CstrArr<SA1> sa_command(command);
741 Cstr::CstrArr<SA2> sa_envp(envp);
742 String tmpOutput, tmpErrOut;
743 char const * sInput = Cstr::to_char_ptr(input);
744 Process::Status res;
745 try
746 {
747 res = executeProcessAndGatherOutput(sa_command.sarr, tmpOutput,
748 tmpErrOut, sa_envp.sarr, timeout, outputlimit, sInput);
749 }
750 catch(...)
751 {
752 output = tmpOutput.c_str();
753 erroutput = tmpErrOut.c_str();
754 throw;
755 }
756 output = tmpOutput.c_str();
757 erroutput = tmpErrOut.c_str();
758 return res;
759 }
760
765 template <typename SA1, typename S1, typename SA2>
767 SA1 const & command, S1& output, S1& erroutput, SA2 const & envp,
768 const Timeout& timeout = Timeout::infinite, int outputlimit = -1)
769 {
770 return executeProcessAndGatherOutput(command, output, erroutput, envp,
771 timeout, outputlimit, String());
772 }
773
774
775 BLOCXX_COMMON_API void executeProcessAndGatherOutput(
776 const Array<String>& command,
777 String& output, int& processstatus,
778 int timeoutsecs = -1, int outputlimit = -1,
779 const String& input = String()) BLOCXX_DEPRECATED;
780
781 namespace Impl
782 {
783 // internal implementation details, not meant for use outside of *Exec.?pp files.
784 unsigned const BLOCXX_IN = 0;
785 unsigned const BLOCXX_OUT = 1;
786 unsigned const BLOCXX_SERR = 2;
787 unsigned const BLOCXX_EXEC_ERR = 3;
788 unsigned const BLOCXX_NPIPE = 4;
790
792 {
793 static void* create()
794 {
795 return 0;
796 }
797 };
798 } // end namespace Impl
799
800#ifdef BLOCXX_ENABLE_TEST_HOOKS
801 typedef GlobalPtr<ExecMockObject, Impl::NullFactory> ExecMockObject_t;
808 extern ExecMockObject_t g_execMockObject;
809#endif
810} // end namespace Exec
811
812} // end namespace BLOCXX_NAMESPACE
813
814#endif
#define BLOCXX_DECLARE_APIEXCEPTION(NAME, LINKAGE_SPEC)
Declare a new exception class named <NAME>Exception that derives from Exception This macro is typical...
#define BLOCXX_DECLARE_APIEXCEPTION2(NAME, BASE, LINKAGE_SPEC)
Declare a new exception class named <NAME>Exception that derives from <BASE>.
Array<> wraps std::vector<> in COWReference<> adding ref counting and copy on write capability.
Definition ArrayFwd.hpp:46
virtual void doGetData(Array< char > &inputBuffer, const ProcessRef &theProc, size_t streamIndex)=0
void getData(Array< char > &inputBuffer, const ProcessRef &theProc, size_t streamIndex)
Definition Exec.cpp:385
virtual void doHandleData(const char *data, size_t dataLen, EOutputSource outputSource, const ProcessRef &theProc, size_t streamIndex, Array< char > &inputBuffer)=0
void handleData(const char *data, size_t dataLen, EOutputSource outputSource, const ProcessRef &theProc, size_t streamIndex, Array< char > &inputBuffer)
Definition Exec.cpp:373
This class is used to specify what spawn() should do between fork and exec.
Definition Exec.hpp:106
::BLOCXX_NAMESPACE::UnnamedPipe * pipe_pointer_t
Definition Exec.hpp:108
static void setupStandardDescriptors(pipe_pointer_t const pparr[])
For calling from PreExec::call.
static void resetSignals()
For calling from PreExec::call.
void closeDescriptorsOnExec(std::vector< bool > const &keep)
For calling from PreExec::call.
virtual void call(pipe_pointer_t const pparr[])=0
This function is called between fork and exec in the spawn() function.
PreExec(bool precompute_max_descriptors=false)
static void setNewProcessGroup()
For calling from PreExec::call().
static void closePipesOnExec(pipe_pointer_t const pparr[])
For calling from PreExec::call.
virtual bool keepStd(int d) const =0
ExecErrorException(const char *file, int line, const char *msg, int errorCode=::BLOCXX_NAMESPACE::Exception::UNKNOWN_ERROR_CODE, const Exception *otherException=0, int subClassId=::BLOCXX_NAMESPACE::Exception::UNKNOWN_SUBCLASS_ID)
Definition Exec.cpp:84
This class can be used to store a global pointer.
Definition GlobalPtr.hpp:84
Portable process status.
Definition Process.hpp:123
This String class is an abstract data type that represents as NULL terminated string of characters.
Definition String.hpp:67
const char * c_str() const
Definition String.cpp:905
A timeout can be absolute, which means that it will happen at the specified DateTime.
Definition Timeout.hpp:56
static Timeout infinite
Definition Timeout.hpp:62
Abstract interface for an UnnamedPipe.
char const * to_char_ptr(S const &s)
Definition Cstr.hpp:111
unsigned const BLOCXX_OUT
Definition Exec.hpp:785
unsigned const BLOCXX_NPIPE
Definition Exec.hpp:788
unsigned const BLOCXX_IN
Definition Exec.hpp:784
void close_child_ends(UnnamedPipeRef ppipe[BLOCXX_NPIPE])
Definition Exec.cpp:163
unsigned const BLOCXX_EXEC_ERR
Definition Exec.hpp:787
unsigned const BLOCXX_SERR
Definition Exec.hpp:786
int safeSystem(const Array< String > &command, const char *const envp[])
This is deprecated.
Definition Exec.cpp:112
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 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
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
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
static char const *const *const currentEnvironment
Intended to be used as a parameter to spawn() to indicate that the current environment will be used f...
Definition Exec.hpp:205
::BLOCXX_NAMESPACE::GlobalPtr< ExecMockObject, Impl::NullFactory > g_execMockObject
Definition Exec.cpp:90
Process::Status system(const Array< String > &command, const char *const envp[], const Timeout &timeout)
Execute a command.
Definition Exec.cpp:94
void gatherOutput(String &output, const ProcessRef &proc, int timeoutSecs, int outputLimit)
Definition Exec.cpp:350
Taken from RFC 1321.
IntrusiveReference< UnnamedPipe > UnnamedPipeRef
IntrusiveReference< Process > ProcessRef
Class for converting values of type S into char const * const *.
Definition Cstr.hpp:131
char const *const * sarr
Converted value.
Definition Cstr.hpp:133
Use this class to allow call() to throw an exception.
Definition Exec.hpp:135