00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
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>
00067 #include <signal.h>
00068 }
00069
00070
00071 #ifndef NSIG
00072 #define NSIG 64
00073 #endif
00074
00075 #if defined(sigemptyset)
00076
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
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)
00136 {
00137 int errnum = errno;
00138
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)
00149 {
00150 throw_child_error(ce, process_path);
00151 }
00152
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
00173
00174
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
00184
00185
00186
00187 int exec_err_desc = -1;
00188 Exec::PreExec::Error err;
00189 err.error_num = 0;
00190 err.message[0] = '\0';
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 }
00232
00233 namespace Exec
00234 {
00235
00236 using namespace Impl;
00237
00239
00240
00241 void PreExec::resetSignals()
00242 {
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
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)
00279 {
00280 temp.sa_handler = SIG_DFL;
00281
00282
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)
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 }
00351
00352 namespace PosixExec
00353 {
00354
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
00375
00376 SystemPreExec::SystemPreExec() : PreExec(true)
00377 {
00378 }
00379
00380 bool SystemPreExec::keepStd(int d) const
00381 {
00382 return true;
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
00397
00398
00399
00400
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
00410
00411
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)
00429 {
00430 init_child(exec_path, argv, envp, pre_exec, ppipe);
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
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 }
00452
00453 }
00454
00455 #endif