blocxx
|
00001 /******************************************************************************* 00002 * Copyright (C) 2005, Quest Software, Inc. All rights reserved. 00003 * Copyright (C) 2006, Novell, Inc. All rights reserved. 00004 * 00005 * Redistribution and use in source and binary forms, with or without 00006 * modification, are permitted provided that the following conditions are met: 00007 * 00008 * * Redistributions of source code must retain the above copyright notice, 00009 * this list of conditions and the following disclaimer. 00010 * * Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * * Neither the name of 00014 * Quest Software, Inc., 00015 * nor Novell, Inc., 00016 * nor the names of its contributors or employees may be used to 00017 * endorse or promote products derived from this software without 00018 * specific prior written permission. 00019 * 00020 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00021 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00022 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00023 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 00024 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00025 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 00026 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00027 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00028 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 00029 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00030 * POSSIBILITY OF SUCH DAMAGE. 00031 *******************************************************************************/ 00032 00033 00038 #ifndef BLOCXX_EXEC_HPP_INCLUDE_GUARD_ 00039 #define BLOCXX_EXEC_HPP_INCLUDE_GUARD_ 00040 00041 #include "blocxx/BLOCXX_config.h" 00042 #include "blocxx/CommonFwd.hpp" 00043 #include "blocxx/EnvVars.hpp" 00044 #include "blocxx/Process.hpp" 00045 #ifdef BLOCXX_ENABLE_TEST_HOOKS 00046 #include "blocxx/GlobalPtr.hpp" 00047 #endif 00048 00049 namespace BLOCXX_NAMESPACE 00050 { 00051 00052 BLOCXX_DECLARE_APIEXCEPTION(ExecError, BLOCXX_COMMON_API); 00053 BLOCXX_DECLARE_APIEXCEPTION2(ExecTimeout, ExecErrorException, BLOCXX_COMMON_API); 00054 BLOCXX_DECLARE_APIEXCEPTION2(ExecBufferFull, ExecErrorException, BLOCXX_COMMON_API); 00055 00057 namespace Exec 00058 { 00084 BLOCXX_COMMON_API Process::Status system(const Array<String>& command, 00085 const char* const envp[] = 0, const Timeout& = Timeout::infinite); 00086 00087 template <typename SA1, typename SA2> 00088 Process::Status system(const SA1& command, 00089 const SA2& envVars, const Timeout& timeout = Timeout::infinite) 00090 { 00091 Cstr::CstrArr<SA1> sa_command(command); 00092 Cstr::CstrArr<SA2> sa_envVars(envVars); 00093 return system(sa_command.sarr, sa_envVars.sarr, timeout); 00094 } 00095 00097 BLOCXX_COMMON_API int safeSystem(const Array<String>& command, 00098 const char* const envp[] = 0) BLOCXX_DEPRECATED; 00099 00100 00105 class BLOCXX_COMMON_API PreExec 00106 { 00107 public: 00108 typedef ::BLOCXX_NAMESPACE::UnnamedPipe* pipe_pointer_t; 00109 00110 PreExec(bool precompute_max_descriptors = false); 00111 00112 virtual ~PreExec(); 00113 00122 virtual bool keepStd(int d) const = 0; 00123 00124 struct Error 00125 { 00126 enum { MAX_MSG_LEN = 64 }; 00127 char message[MAX_MSG_LEN + 1]; // must be null-terminated 00128 int error_num; // errno value; 0 means no errno value 00129 }; 00130 00134 struct DontCatch 00135 { 00136 virtual ~DontCatch(); 00137 }; 00138 00158 virtual void call(pipe_pointer_t const pparr[]) = 0; 00159 00166 void closeDescriptorsOnExec(std::vector<bool> const & keep); 00167 00172 static void resetSignals(); 00173 00180 static void closePipesOnExec(pipe_pointer_t const pparr[]); 00181 00189 static void setupStandardDescriptors(pipe_pointer_t const pparr[]); 00190 00197 static void setNewProcessGroup(); 00198 00199 protected: 00200 long m_max_descriptors; 00201 }; 00202 00205 static char const * const * const currentEnvironment = 0; 00206 00229 BLOCXX_COMMON_API ProcessRef spawn( 00230 char const * exec_path, 00231 char const * const argv[], char const * const envp[], 00232 PreExec & pre_exec 00233 ); 00234 00246 template <typename S, typename SA1, typename SA2> 00247 ProcessRef spawn( 00248 S const & exec_path, SA1 const & argv, SA2 const & envp, 00249 PreExec & pre_exec 00250 ) 00251 { 00252 Cstr::CstrArr<SA1> sa_argv(argv); 00253 Cstr::CstrArr<SA2> sa_envp(envp); 00254 char const * s_exec_path = Cstr::to_char_ptr(exec_path); 00255 return spawn(s_exec_path, sa_argv.sarr, sa_envp.sarr, pre_exec); 00256 } 00257 00259 // 00260 BLOCXX_COMMON_API ProcessRef spawn( 00261 char const * const argv[], char const * const envp[] 00262 ); 00263 00271 template <typename SA1, typename SA2> 00272 ProcessRef spawn( 00273 SA1 const & argv, SA2 const & envp 00274 ) 00275 { 00276 Cstr::CstrArr<SA1> sa_argv(argv); 00277 Cstr::CstrArr<SA2> sa_envp(envp); 00278 return spawn(sa_argv.sarr, sa_envp.sarr); 00279 } 00280 00281 template <typename SA1> 00282 ProcessRef spawn( 00283 SA1 const & argv 00284 ) 00285 { 00286 return spawn(argv, Exec::currentEnvironment); 00287 } 00288 00316 BLOCXX_COMMON_API void gatherOutput(String& output, const ProcessRef& proc, const Timeout& timeout = Timeout::infinite, int outputlimit = -1); 00317 00318 enum EOutputSource 00319 { 00320 E_STDOUT, 00321 E_STDERR 00322 }; 00323 00324 class BLOCXX_COMMON_API OutputCallback 00325 { 00326 public: 00327 virtual ~OutputCallback(); 00328 void handleData(const char* data, size_t dataLen, EOutputSource outputSource, const ProcessRef& theProc, size_t streamIndex, Array<char>& inputBuffer); 00329 private: 00334 virtual void doHandleData(const char* data, size_t dataLen, EOutputSource outputSource, const ProcessRef& theProc, size_t streamIndex, Array<char>& inputBuffer) = 0; 00335 }; 00336 00337 class BLOCXX_COMMON_API InputCallback 00338 { 00339 public: 00340 virtual ~InputCallback(); 00341 void getData(Array<char>& inputBuffer, const ProcessRef& theProc, size_t streamIndex); 00342 private: 00343 virtual void doGetData(Array<char>& inputBuffer, const ProcessRef& theProc, size_t streamIndex) = 0; 00344 }; 00345 #if 0 00346 enum EProcessRunning 00347 { 00348 E_PROCESS_RUNNING, 00349 E_PROCESS_EXITED 00350 }; 00351 00352 // class invariant: if m_running == E_PROCESS_RUNNING, then m_status == 0. 00353 class ProcessStatus 00354 { 00355 public: 00356 ProcessStatus() 00357 : m_running(E_PROCESS_RUNNING) 00358 , m_status(0) 00359 { 00360 } 00361 00362 explicit ProcessStatus(int status) 00363 : m_running(E_PROCESS_EXITED) 00364 , m_status(status) 00365 { 00366 } 00367 00368 bool hasExited() const 00369 { 00370 return m_running == E_PROCESS_EXITED; 00371 } 00372 00373 const int& getStatus() const 00374 { 00375 return m_status; 00376 } 00377 private: 00378 EProcessRunning m_running; 00379 int m_status; 00380 }; 00381 #endif 00382 00407 BLOCXX_COMMON_API void processInputOutput(OutputCallback& output, Array<ProcessRef>& procs, 00408 InputCallback& input, const Timeout& timeout = Timeout::infinite); 00409 00410 00411 BLOCXX_COMMON_API void processInputOutput(const String& input, String& output, const ProcessRef& process, 00412 const Timeout& timeout = Timeout::infinite, int outputlimit = -1); 00413 00449 BLOCXX_COMMON_API Process::Status feedProcessAndGatherOutput( 00450 ProcessRef const & proc, String & output, 00451 Timeout const & timeout = Timeout::infinite, int outputlimit = -1, 00452 String const & input = String()); 00453 00492 BLOCXX_COMMON_API Process::Status feedProcessAndGatherOutput( 00493 ProcessRef const & proc, String & output, 00494 String & erroutput, Timeout const & timeout = Timeout::infinite, 00495 int outputLimit = -1, 00496 String const & input = String()); 00497 00528 BLOCXX_COMMON_API Process::Status executeProcessAndGatherOutput( 00529 char const * const command[], String& output, char const * const envVars[], 00530 const Timeout& timeout = Timeout::infinite, int outputlimit = -1, 00531 char const * input = 0); 00532 00565 BLOCXX_COMMON_API Process::Status executeProcessAndGatherOutput( 00566 char const * const command[], String& output, String& erroutput, 00567 char const * const envVars[], 00568 const Timeout& timeout = Timeout::infinite, int outputLimit = -1, 00569 char const * input = 0); 00570 00575 template <typename SA1, typename S1, typename S2> 00576 Process::Status executeProcessAndGatherOutput( 00577 SA1 const & command, S1& output, 00578 const Timeout& timeout, int outputlimit, S2 const& input) 00579 { 00580 Cstr::CstrArr<SA1> sa_command(command); 00581 String tmpOutput; 00582 char const * sInput = Cstr::to_char_ptr(input); 00583 Process::Status res; 00584 try 00585 { 00586 res = executeProcessAndGatherOutput(sa_command.sarr, tmpOutput, 00587 currentEnvironment, timeout, outputlimit, sInput); 00588 } 00589 catch(...) 00590 { 00591 output = tmpOutput.c_str(); 00592 throw; 00593 } 00594 output = tmpOutput.c_str(); 00595 return res; 00596 } 00597 00603 template <typename SA1, typename S1, typename S2> 00604 Process::Status executeProcessAndGatherOutput( 00605 SA1 const & command, S1& output, S1& erroutput, 00606 const Timeout& timeout, int outputlimit, S2 const& input) 00607 { 00608 Cstr::CstrArr<SA1> sa_command(command); 00609 String tmpOutput, tmpErrOut; 00610 char const * sInput = Cstr::to_char_ptr(input); 00611 Process::Status res; 00612 try 00613 { 00614 res = executeProcessAndGatherOutput(sa_command.sarr, tmpOutput, 00615 tmpErrOut, currentEnvironment, timeout, outputlimit, sInput); 00616 } 00617 catch(...) 00618 { 00619 output = tmpOutput.c_str(); 00620 erroutput = tmpErrOut.c_str(); 00621 throw; 00622 } 00623 output = tmpOutput.c_str(); 00624 erroutput = tmpErrOut.c_str(); 00625 return res; 00626 } 00627 00632 template <typename SA1, typename S1> 00633 Process::Status executeProcessAndGatherOutput( 00634 SA1 const & command, S1& output, 00635 const Timeout& timeout = Timeout::infinite, int outputlimit = -1) 00636 { 00637 Cstr::CstrArr<SA1> sa_command(command); 00638 String tmpOutput; 00639 Process::Status res; 00640 try 00641 { 00642 res = executeProcessAndGatherOutput(sa_command.sarr, tmpOutput, 00643 currentEnvironment, timeout, outputlimit, (char const*)0); 00644 } 00645 catch(...) 00646 { 00647 output = tmpOutput.c_str(); 00648 throw; 00649 } 00650 output = tmpOutput.c_str(); 00651 return res; 00652 } 00653 00659 template <typename SA1, typename S1> 00660 Process::Status executeProcessAndGatherOutput( 00661 SA1 const & command, S1& output, S1& erroutput, 00662 const Timeout& timeout = Timeout::infinite, int outputlimit = -1) 00663 { 00664 Cstr::CstrArr<SA1> sa_command(command); 00665 String tmpOutput, tmpErrOut; 00666 Process::Status res; 00667 try 00668 { 00669 res = executeProcessAndGatherOutput(sa_command.sarr, tmpOutput, 00670 tmpErrOut, currentEnvironment, timeout, outputlimit, 00671 (char const*)0); 00672 } 00673 catch(...) 00674 { 00675 output = tmpOutput.c_str(); 00676 erroutput = tmpErrOut.c_str(); 00677 throw; 00678 } 00679 output = tmpOutput.c_str(); 00680 erroutput = tmpErrOut.c_str(); 00681 return res; 00682 } 00683 00697 template <typename SA1, typename S1, typename SA2, typename S2> 00698 Process::Status executeProcessAndGatherOutput( 00699 SA1 const & command, S1& output, SA2 const & envp, 00700 const Timeout& timeout, int outputlimit, S2 const& input) 00701 { 00702 Cstr::CstrArr<SA1> sa_command(command); 00703 Cstr::CstrArr<SA2> sa_envp(envp); 00704 String tmpOutput; 00705 char const * sInput = Cstr::to_char_ptr(input); 00706 Process::Status res; 00707 try 00708 { 00709 res = executeProcessAndGatherOutput(sa_command.sarr, tmpOutput, sa_envp.sarr, 00710 timeout, outputlimit, sInput); 00711 } 00712 catch(...) 00713 { 00714 output = tmpOutput.c_str(); 00715 throw; 00716 } 00717 output = tmpOutput.c_str(); 00718 return res; 00719 } 00720 00735 template <typename SA1, typename S1, typename SA2, typename S2> 00736 Process::Status executeProcessAndGatherOutput( 00737 SA1 const & command, S1& output, S1& erroutput, SA2 const & envp, 00738 const Timeout& timeout, int outputlimit, S2 const& input) 00739 { 00740 Cstr::CstrArr<SA1> sa_command(command); 00741 Cstr::CstrArr<SA2> sa_envp(envp); 00742 String tmpOutput, tmpErrOut; 00743 char const * sInput = Cstr::to_char_ptr(input); 00744 Process::Status res; 00745 try 00746 { 00747 res = executeProcessAndGatherOutput(sa_command.sarr, tmpOutput, 00748 tmpErrOut, sa_envp.sarr, timeout, outputlimit, sInput); 00749 } 00750 catch(...) 00751 { 00752 output = tmpOutput.c_str(); 00753 erroutput = tmpErrOut.c_str(); 00754 throw; 00755 } 00756 output = tmpOutput.c_str(); 00757 erroutput = tmpErrOut.c_str(); 00758 return res; 00759 } 00760 00765 template <typename SA1, typename S1, typename SA2> 00766 Process::Status executeProcessAndGatherOutput( 00767 SA1 const & command, S1& output, S1& erroutput, SA2 const & envp, 00768 const Timeout& timeout = Timeout::infinite, int outputlimit = -1) 00769 { 00770 return executeProcessAndGatherOutput(command, output, erroutput, envp, 00771 timeout, outputlimit, String()); 00772 } 00773 00774 00775 BLOCXX_COMMON_API void executeProcessAndGatherOutput( 00776 const Array<String>& command, 00777 String& output, int& processstatus, 00778 int timeoutsecs = -1, int outputlimit = -1, 00779 const String& input = String()) BLOCXX_DEPRECATED; 00780 00781 namespace Impl 00782 { 00783 // internal implementation details, not meant for use outside of *Exec.?pp files. 00784 unsigned const BLOCXX_IN = 0; 00785 unsigned const BLOCXX_OUT = 1; 00786 unsigned const BLOCXX_SERR = 2; 00787 unsigned const BLOCXX_EXEC_ERR = 3; 00788 unsigned const BLOCXX_NPIPE = 4; 00789 void close_child_ends(UnnamedPipeRef ppipe[BLOCXX_NPIPE]); 00790 00791 struct NullFactory 00792 { 00793 static void* create() 00794 { 00795 return 0; 00796 } 00797 }; 00798 } // end namespace Impl 00799 00800 #ifdef BLOCXX_ENABLE_TEST_HOOKS 00801 typedef GlobalPtr<ExecMockObject, Impl::NullFactory> ExecMockObject_t; 00808 extern ExecMockObject_t g_execMockObject; 00809 #endif 00810 } // end namespace Exec 00811 00812 } // end namespace BLOCXX_NAMESPACE 00813 00814 #endif