38 #include "blocxx/BLOCXX_config.h"
40 #if !defined(BLOCXX_WIN32)
53 #ifdef BLOCXX_HAVE_SYS_RESOURCE_H
54 #include <sys/resource.h>
56 #ifdef BLOCXX_HAVE_SYS_TYPES_H
57 #include <sys/types.h>
59 #ifdef BLOCXX_HAVE_UNISTD_H
75 #if defined(sigemptyset)
81 #if defined(sigaction)
85 #define SIG_DFL (void(*)())0
88 namespace BLOCXX_NAMESPACE
94 void throw_child_error(Exec::PreExec::Error
const & err,
const String& process_path)
96 Format msg(
"Exec::spawn(%1): child startup failed: %2", process_path, err.message);
97 if (err.error_num != 0)
100 ExecErrorException, msg.c_str(), err.error_num);
108 void check(
bool b,
char const * message,
bool use_errno =
true)
112 Exec::PreExec::Error x;
114 x.error_num = use_errno ? errno : 0;
119 void parent_check(
bool b,
char const * msg)
127 void close_on_exec(
Descriptor descr,
bool may_be_bad)
129 int e = ::fcntl(descr, F_SETFD, FD_CLOEXEC);
130 check(e == 0 || may_be_bad && errno == EBADF,
"fcntl");
133 void handle_child_error(
int rc, Exec::PreExec::Error
const & ce, Process & proc,
const String& process_path)
143 Format(
"Exec::spawn(%1): timed out waiting for child to exec()",process_path).c_str());
146 Format(
"Exec::spawn(%1): error reading init status from child",process_path).c_str(), errnum);
150 throw_child_error(ce, process_path);
155 long getMaxOpenFiles()
157 long sysconfValue = sysconf(_SC_OPEN_MAX);
158 long maxOpen = sysconfValue;
160 rl.rlim_cur = rlim_t(0);
161 if( getrlimit(RLIMIT_NOFILE, &rl) != -1 )
163 if( sysconfValue < 0 )
165 maxOpen = rl.rlim_cur;
169 maxOpen = std::min<rlim_t>(rl.rlim_cur, sysconfValue);
175 BLOCXX_ASSERT( (maxOpen > 2) && (maxOpen <=
long(std::numeric_limits<int>::max())) );
179 void init_child(
char const * exec_path,
180 char const *
const argv[],
char const *
const envp[],
187 int exec_err_desc = -1;
188 Exec::PreExec::Error err;
190 err.message[0] =
'\0';
195 pre_exec.call(ppipe);
198 char *
const * cc_argv =
const_cast<char *
const *
>(argv);
199 char *
const * cc_envp =
const_cast<char *
const *
>(envp);
202 check(::execve(exec_path, cc_argv, cc_envp) != -1,
"execve");
206 check(::execv(exec_path, cc_argv) != -1,
"execv");
209 catch (Exec::PreExec::Error & e)
213 catch (std::exception & e)
218 catch (Exec::PreExec::DontCatch & e)
227 ssize_t rv =
::write(exec_err_desc, &err,
sizeof(err));
236 using namespace Impl;
265 ::sigset_t emptymask;
266 check(::sigemptyset(&emptymask) == 0,
"sigemptyset");
267 check(::sigprocmask(SIG_SETMASK, &emptymask, 0) == 0,
"sigprocmask");
271 if (
sig == SIGKILL ||
sig == SIGSTOP)
275 struct sigaction temp;
276 int e = ::sigaction(
sig, 0, &temp);
277 check(e == 0 || errno == EINVAL,
"sigaction [1]");
278 if (e == 0 && temp.sa_handler != SIG_DFL)
280 temp.sa_handler = SIG_DFL;
283 ::sigaction(
sig, &temp, 0);
290 long numd = m_max_descriptors ? m_max_descriptors : getMaxOpenFiles();
291 for (
int d = 3; d < int(numd); ++d)
293 if (
size_t(d) >= keep.size() || !keep[d])
295 close_on_exec(d,
true);
303 if (!(ppipe[0] && ppipe[1] && ppipe[2]))
306 check(nulld >= 0,
"open");
307 close_on_exec(nulld,
false);
309 for (
unsigned d = 0; d < 3; ++d)
314 check(::dup2(ddup, d) != -1,
"dup2");
333 int pgidrv = setpgid(0, 0);
338 : m_max_descriptors(precompute_max_descriptors ? getMaxOpenFiles() : 0)
356 StandardPreExec::StandardPreExec() : PreExec(true)
367 std::vector<bool> empty;
368 PreExec::resetSignals();
369 PreExec::setNewProcessGroup();
370 PreExec::setupStandardDescriptors(pparr);
371 PreExec::closeDescriptorsOnExec(empty);
387 std::vector<bool> empty;
388 PreExec::resetSignals();
389 PreExec::setNewProcessGroup();
390 PreExec::closeDescriptorsOnExec(empty);
402 parent_check(exec_path,
"Exec::spawn: null exec_path");
403 char const * default_argv[2] = { exec_path, 0 };
427 ::pid_t child_pid = ::fork();
430 init_child(exec_path, argv, envp, pre_exec, ppipe);
433 parent_check(child_pid >= 0,
Format(
"Exec::spawn(%1): fork() failed", exec_path).c_str());
446 handle_child_error(nread, child_error, *retval, exec_path);