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 
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 
49 namespace BLOCXX_NAMESPACE
50 {
51 
52 BLOCXX_DECLARE_APIEXCEPTION(ExecError, BLOCXX_COMMON_API);
53 BLOCXX_DECLARE_APIEXCEPTION2(ExecTimeout, ExecErrorException, BLOCXX_COMMON_API);
54 BLOCXX_DECLARE_APIEXCEPTION2(ExecBufferFull, ExecErrorException, BLOCXX_COMMON_API);
55 
57 namespace 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:
108  typedef ::BLOCXX_NAMESPACE::UnnamedPipe* pipe_pointer_t;
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 
134  struct DontCatch
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 
319  {
322  };
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;
789  void close_child_ends(UnnamedPipeRef ppipe[BLOCXX_NPIPE]);
790 
791  struct NullFactory
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