blocxx

Exec.hpp

Go to the documentation of this file.
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