blocxx

PosixExec.cpp

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 #include "blocxx/BLOCXX_config.h"
00039 
00040 #if !defined(BLOCXX_WIN32) 
00041 
00042 #include "blocxx/PosixExec.hpp"
00043 #include "blocxx/Format.hpp"
00044 #include "blocxx/SafeCString.hpp"
00045 #include "blocxx/Assertion.hpp"
00046 #include "blocxx/PosixUnnamedPipe.hpp"
00047 #include "blocxx/Paths.hpp"
00048 #include "blocxx/TimeoutTimer.hpp"
00049 #include "blocxx/Select.hpp"
00050 
00051 extern "C"
00052 {
00053 #ifdef BLOCXX_HAVE_SYS_RESOURCE_H
00054 #include <sys/resource.h>
00055 #endif
00056 #ifdef BLOCXX_HAVE_SYS_TYPES_H
00057 #include <sys/types.h>
00058 #endif
00059 #ifdef BLOCXX_HAVE_UNISTD_H
00060 #include <unistd.h>
00061 #endif
00062 
00063 #include <sys/wait.h>
00064 #include <fcntl.h>
00065 #include <errno.h>
00066 #include <stdio.h> // for perror
00067 #include <signal.h>
00068 }
00069 
00070 // NSIG may be defined by signal.h, otherwise 64 should be plenty.
00071 #ifndef NSIG
00072 #define NSIG 64
00073 #endif
00074 
00075 #if defined(sigemptyset)
00076 // We want to use the function instead of the macro (for scoping reasons).
00077 #undef sigemptyset
00078 #endif // sigemptyset
00079 
00080 #ifdef BLOCXX_NCR
00081 #if defined(sigaction)
00082 #undef sigaction
00083 #endif
00084 #undef SIG_DFL
00085 #define  SIG_DFL  (void(*)())0
00086 #endif
00087 
00088 namespace BLOCXX_NAMESPACE
00089 {
00090 
00091 namespace // anonymous
00092 {
00093 
00094    void throw_child_error(Exec::PreExec::Error const & err, const String& process_path)
00095    {
00096       Format msg("Exec::spawn(%1): child startup failed: %2", process_path, err.message);
00097       if (err.error_num != 0)
00098       {
00099          BLOCXX_THROW_ERRNO_MSG1(
00100             ExecErrorException,  msg.c_str(), err.error_num);
00101       }
00102       else
00103       {
00104          BLOCXX_THROW(ExecErrorException, msg.c_str());
00105       }
00106    }
00107 
00108    void check(bool b, char const * message, bool use_errno = true)
00109    {
00110       if (!b)
00111       {
00112          Exec::PreExec::Error x;
00113          SafeCString::strcpy_trunc(x.message, message);
00114          x.error_num = use_errno ? errno : 0;
00115          throw x;
00116       }
00117    }
00118 
00119    void parent_check(bool b, char const * msg)
00120    {
00121       if (!b)
00122       {
00123          BLOCXX_THROW(ExecErrorException, msg);
00124       }
00125    }
00126 
00127    void close_on_exec(Descriptor descr, bool may_be_bad)
00128    {
00129       int e = ::fcntl(descr, F_SETFD, FD_CLOEXEC);
00130       check(e == 0 || may_be_bad && errno == EBADF, "fcntl");
00131    }
00132 
00133    void handle_child_error(int rc, Exec::PreExec::Error const & ce, Process & proc, const String& process_path)
00134    {
00135       if (rc < 0) // read of error status from child failed
00136       {
00137          int errnum = errno;
00138          // For some reason child initialization failed; kill it.
00139          proc.waitCloseTerm(Timeout::relative(0.0), Timeout::relative(0.0), Timeout::relative(0.0));
00140          if (errnum == ETIMEDOUT)
00141          {
00142             BLOCXX_THROW(ExecErrorException,
00143                Format("Exec::spawn(%1): timed out waiting for child to exec()",process_path).c_str());
00144          }
00145          BLOCXX_THROW_ERRNO_MSG1(ExecErrorException,
00146             Format("Exec::spawn(%1): error reading init status from child",process_path).c_str(), errnum);
00147       }
00148       if (rc > 0) // child sent an initialization error message
00149       {
00150          throw_child_error(ce, process_path);
00151       }
00152       // If rc == 0, initialization succeeded
00153    }
00154 
00155    long getMaxOpenFiles()
00156    {
00157       long sysconfValue = sysconf(_SC_OPEN_MAX);
00158       long maxOpen = sysconfValue;
00159       rlimit rl;
00160       rl.rlim_cur = rlim_t(0);
00161       if( getrlimit(RLIMIT_NOFILE, &rl) != -1 )
00162       {
00163          if( sysconfValue < 0 )
00164          {
00165             maxOpen = rl.rlim_cur;
00166          }
00167          else
00168          {
00169             maxOpen = std::min<rlim_t>(rl.rlim_cur, sysconfValue);
00170          }
00171       }
00172       // Check for a value of maxOpen that really is reasonable.
00173       // This checks the maximum value to make sure it will fit in an int
00174       // (required for close).
00175       BLOCXX_ASSERT( (maxOpen > 2) && (maxOpen <= long(std::numeric_limits<int>::max())) );
00176       return maxOpen;
00177    }
00178 
00179    void init_child(char const * exec_path, 
00180       char const * const argv[], char const * const envp[],
00181       Exec::PreExec & pre_exec, UnnamedPipe* ppipe[Exec::Impl::BLOCXX_NPIPE])
00182    {
00183       // This code must be careful not to allocate memory, as this can
00184       // cause a deadlock on some platforms when there are multiple
00185       // threads running at the time of the fork().
00186 
00187       int exec_err_desc = -1;
00188       Exec::PreExec::Error err;
00189       err.error_num = 0;      // should be unnecessary, but just in case...
00190       err.message[0] = '\0';  // should be unnecessary, but just in case...
00191       try
00192       {
00193          int rc;
00194          exec_err_desc = ppipe[Exec::Impl::BLOCXX_EXEC_ERR]->getOutputDescriptor();
00195          pre_exec.call(ppipe);
00196 
00197          int rval = 0;
00198          char * const * cc_argv = const_cast<char * const *>(argv);
00199          char * const * cc_envp = const_cast<char * const *>(envp);
00200          if (envp)
00201          {
00202             check(::execve(exec_path, cc_argv, cc_envp) != -1, "execve");
00203          }
00204          else
00205          {
00206             check(::execv(exec_path, cc_argv) != -1, "execv");
00207          }
00208       }
00209       catch (Exec::PreExec::Error & e)
00210       {
00211          err = e;
00212       }
00213       catch (std::exception & e)
00214       {
00215          SafeCString::strcpy_trunc(err.message, e.what());
00216          err.error_num = 0;
00217       }
00218       catch (Exec::PreExec::DontCatch & e)
00219       {
00220          throw;
00221       }
00222       catch (...)
00223       {
00224          SafeCString::strcpy_trunc(err.message, "unknown exception");
00225          err.error_num = 0;
00226       }
00227       ssize_t rv = ::write(exec_err_desc, &err, sizeof(err));
00228       ::_exit(127);
00229    }
00230 
00231 } // end anonymous namespace
00232 
00233 namespace Exec
00234 {
00235 
00236 using namespace Impl;
00237 
00239 //  PreExec methods
00240 //
00241 void PreExec::resetSignals()
00242 {
00243    /*
00244    according to susv3:
00245 
00246    This  volume  of  IEEE Std 1003.1-2001  specifies  that signals set to
00247    SIG_IGN remain set to SIG_IGN, and that  the  process  signal  mask be
00248    unchanged across an exec. This is consistent with historical implemen-
00249    tations, and it permits some useful functionality, such  as  the nohup
00250    command.  However,  it should be noted that many existing applications
00251    wrongly assume that they start with certain signals set to the default
00252    action  and/or  unblocked.  In particular, applications written with a
00253    simpler signal model that does not include blocking of signals, such as
00254    the one in the ISO C standard, may not behave properly if invoked with
00255    some signals blocked. Therefore, it is best not to block or ignore sig-
00256    nals across execs without explicit reason to do so, and especially not
00257    to block signals across execs of arbitrary (not  closely co-operating)
00258    programs.
00259 
00260    so we'll reset the signal mask and all signal handlers to SIG_DFL.
00261    We set them all just in case the current handlers may misbehave now
00262    that we've fork()ed.
00263    */
00264    int rc;
00265    ::sigset_t emptymask;
00266    check(::sigemptyset(&emptymask) == 0, "sigemptyset");
00267    check(::sigprocmask(SIG_SETMASK, &emptymask, 0) == 0, "sigprocmask");
00268 
00269    for (std::size_t sig = 1; sig <= NSIG; ++sig)
00270    {
00271       if (sig == SIGKILL || sig == SIGSTOP)
00272       {
00273          continue;
00274       }
00275       struct sigaction temp;
00276       int e = ::sigaction(sig, 0, &temp);
00277       check(e == 0 || errno == EINVAL, "sigaction [1]");
00278       if (e == 0 && temp.sa_handler != SIG_DFL) // valid signal
00279       {
00280          temp.sa_handler = SIG_DFL;
00281          // note that we don't check the return value because there are signals 
00282          // (e.g. SIGGFAULT on HP-UX), which are gettable, but not settable.
00283          ::sigaction(sig, &temp, 0);
00284       }
00285    }
00286 }
00287 
00288 void PreExec::closeDescriptorsOnExec(std::vector<bool> const & keep)
00289 {
00290    long numd = m_max_descriptors ? m_max_descriptors : getMaxOpenFiles();
00291    for (int d = 3; d < int(numd); ++d) // Don't close standard descriptors
00292    {
00293       if (size_t(d) >= keep.size() || !keep[d])
00294       {
00295          close_on_exec(d, true);
00296       }
00297    }
00298 }
00299 
00300 void PreExec::setupStandardDescriptors(pipe_pointer_t const ppipe[])
00301 {
00302    int nulld = 0;
00303    if (!(ppipe[0] && ppipe[1] && ppipe[2]))
00304    {
00305       nulld = ::open(_PATH_DEVNULL, O_RDWR);
00306       check(nulld >= 0, "open");
00307       close_on_exec(nulld, false);
00308    }
00309    for (unsigned d = 0; d < 3; ++d)
00310    {
00311       PosixUnnamedPipe * p = dynamic_cast<PosixUnnamedPipe*>(ppipe[d]);
00312       int ddup =
00313          !p ? nulld : d==BLOCXX_IN ? p->getInputHandle() : p->getOutputHandle();
00314       check(::dup2(ddup, d) != -1, "dup2");
00315    }
00316 }
00317 
00318 void PreExec::closePipesOnExec(pipe_pointer_t const ppipe[])
00319 {
00320    for (unsigned d = 0; d < BLOCXX_NPIPE; ++d)
00321    {
00322       UnnamedPipe* p = ppipe[d];
00323       if (p)
00324       {
00325          close_on_exec(p->getInputDescriptor(), false);
00326          close_on_exec(p->getOutputDescriptor(), false);
00327       }
00328    }
00329 }
00330 
00331 void PreExec::setNewProcessGroup()
00332 {
00333    int pgidrv = setpgid(0, 0);
00334    BLOCXX_ASSERT(pgidrv == 0);
00335 }
00336 
00337 PreExec::PreExec(bool precompute_max_descriptors)
00338    : m_max_descriptors(precompute_max_descriptors ? getMaxOpenFiles() : 0)
00339 {
00340 }
00341 
00342 PreExec::~PreExec()
00343 {
00344 }
00345 
00346 PreExec::DontCatch::~DontCatch()
00347 {
00348 }
00349 
00350 } // end Exec namespace
00351 
00352 namespace PosixExec
00353 {
00354 //----------- Standard PreExec -------------
00355 //------------------------------------------
00356 StandardPreExec::StandardPreExec() : PreExec(true)
00357 {
00358 }
00359 
00360 bool StandardPreExec::keepStd(int) const
00361 {
00362    return true;
00363 }
00364 
00365 void StandardPreExec::call(pipe_pointer_t const pparr[])
00366 {
00367    std::vector<bool> empty;
00368    PreExec::resetSignals();
00369    PreExec::setNewProcessGroup();
00370    PreExec::setupStandardDescriptors(pparr);
00371    PreExec::closeDescriptorsOnExec(empty);
00372 }
00373 
00374 //----------- System PreExec ---------------
00375 //------------------------------------------
00376 SystemPreExec::SystemPreExec() : PreExec(true) 
00377 { 
00378 }
00379 
00380 bool SystemPreExec::keepStd(int d) const 
00381 {
00382    return true; // want them all unchanged
00383 }
00384 
00385 void SystemPreExec::call(pipe_pointer_t const pparr[])
00386 {
00387    std::vector<bool> empty;
00388    PreExec::resetSignals();
00389    PreExec::setNewProcessGroup();
00390    PreExec::closeDescriptorsOnExec(empty);
00391 }
00392 
00393 ProcessRef spawnImpl(char const * exec_path, char const * const argv[], char const * const envp[],
00394                 Exec::PreExec & pre_exec)
00395 {
00396    // It's important that this code be exception-safe (proper release
00397    // of resources when exception thrown), as at least one caller
00398    // (the monitor code) relies on being able to throw a DontCatch-derived
00399    // exception from pre_exec.call() in the child process and have
00400    // it propagate out of the spawn call.
00401    //
00402    parent_check(exec_path, "Exec::spawn: null exec_path");
00403    char const * default_argv[2] = { exec_path, 0 };
00404    if (!argv || !*argv)
00405    {
00406       argv = default_argv;
00407    }
00408 
00409    // Check this here so that any exceptions or core files caused by it can
00410    // be traced to a real problem instead of the child processes just
00411    // failing for an unreportable reason.
00412    getMaxOpenFiles();
00413 
00414    UnnamedPipeRef upipe[Exec::BLOCXX_NPIPE];
00415    UnnamedPipe* ppipe[Exec::BLOCXX_NPIPE] = {0};
00416 
00417    for (unsigned i = 0; i < Exec::BLOCXX_NPIPE; ++i)
00418    {
00419       if (i == Exec::BLOCXX_EXEC_ERR || pre_exec.keepStd(i))
00420       {
00421          upipe[i] = UnnamedPipe::createUnnamedPipe();
00422          ppipe[i] = upipe[i].getPtr();
00423       }
00424    }
00425 
00426 
00427    ::pid_t child_pid = ::fork();
00428    if (child_pid == 0) // child process
00429    {
00430       init_child(exec_path, argv, envp, pre_exec, ppipe); // never returns
00431    }
00432 
00433    parent_check(child_pid >= 0, Format("Exec::spawn(%1): fork() failed", exec_path).c_str());
00434 
00435    Exec::close_child_ends(upipe);
00436 
00437    // 10 seconds should be plenty for the child to go from fork() to execv()
00438    const Timeout SECONDS_TO_WAIT_FOR_CHILD_TO_EXEC = Timeout::relative(10);
00439    upipe[Exec::BLOCXX_EXEC_ERR]->setReadTimeout(SECONDS_TO_WAIT_FOR_CHILD_TO_EXEC);
00440 
00441    ProcessRef retval(new Process(upipe[0], upipe[1], upipe[2], child_pid));
00442 
00443 
00444    Exec::PreExec::Error child_error;
00445    int nread = upipe[Exec::BLOCXX_EXEC_ERR]->read(&child_error, sizeof(child_error));
00446    handle_child_error(nread, child_error, *retval, exec_path);
00447 
00448    return retval;
00449 }
00450 
00451 } // end PosixExec namespace
00452 
00453 } // end BLOCXX_NAMESPACE
00454 
00455 #endif