Hide most ExecCmd internals

--HG--
branch : WINDOWSPORT
This commit is contained in:
Jean-Francois Dockes 2015-09-04 10:12:17 +02:00
parent b0dcda09b6
commit 649a893d1b
3 changed files with 181 additions and 136 deletions

View File

@ -16,6 +16,8 @@
*/ */
#include "autoconfig.h" #include "autoconfig.h"
#include <signal.h>
#include <QMessageBox> #include <QMessageBox>
#include <QTimer> #include <QTimer>

View File

@ -57,9 +57,7 @@ using namespace std;
extern char **environ; extern char **environ;
bool ExecCmd::o_useVfork = false; #ifdef BUILDING_RECOLL
#ifdef RECOLL_DATADIR
#include "debuglog.h" #include "debuglog.h"
#include "smallut.h" #include "smallut.h"
@ -114,6 +112,85 @@ static void stringToTokens(const string& str, vector<string>& tokens,
} }
#endif // RECOLL_DATADIR #endif // RECOLL_DATADIR
class ExecCmd::Internal {
public:
Internal()
: m_advise(0), m_provide(0), m_timeoutMs(1000),
m_rlimit_as_mbytes(0) {
}
static bool o_useVfork;
std::vector<std::string> m_env;
ExecCmdAdvise *m_advise;
ExecCmdProvide *m_provide;
bool m_killRequest;
int m_timeoutMs;
int m_rlimit_as_mbytes;
std::string m_stderrFile;
// Pipe for data going to the command
int m_pipein[2];
NetconP m_tocmd;
// Pipe for data coming out
int m_pipeout[2];
NetconP m_fromcmd;
// Subprocess id
pid_t m_pid;
// Saved sigmask
sigset_t m_blkcld;
// Reset internal state indicators. Any resources should have been
// previously freed
void reset() {
m_killRequest = false;
m_pipein[0] = m_pipein[1] = m_pipeout[0] = m_pipeout[1] = -1;
m_pid = -1;
sigemptyset(&m_blkcld);
}
// Child process code
inline void dochild(const std::string &cmd, const char **argv,
const char **envv, bool has_input, bool has_output);
};
bool ExecCmd::Internal::o_useVfork = false;
ExecCmd::ExecCmd()
{
m = new Internal();
if (m)
m->reset();
}
void ExecCmd::setAdvise(ExecCmdAdvise *adv)
{
m->m_advise = adv;
}
void ExecCmd::setProvide(ExecCmdProvide *p)
{
m->m_provide = p;
}
void ExecCmd::setTimeout(int mS)
{
if (mS > 30)
m->m_timeoutMs = mS;
}
void ExecCmd::setStderr(const std::string &stderrFile)
{
m->m_stderrFile = stderrFile;
}
pid_t ExecCmd::getChildPid()
{
return m->m_pid;
}
void ExecCmd::setKill()
{
m->m_killRequest = true;
}
void ExecCmd::zapChild()
{
setKill();
(void)wait();
}
/* From FreeBSD's which command */ /* From FreeBSD's which command */
static bool exec_is_there(const char *candidate) static bool exec_is_there(const char *candidate)
{ {
@ -174,12 +251,12 @@ void ExecCmd::useVfork(bool on)
// an executable file, we have a problem. // an executable file, we have a problem.
const char *argv[] = {"/", 0}; const char *argv[] = {"/", 0};
execve("/", (char *const *)argv, environ); execve("/", (char *const *)argv, environ);
o_useVfork = on; Internal::o_useVfork = on;
} }
void ExecCmd::putenv(const string &ea) void ExecCmd::putenv(const string &ea)
{ {
m_env.push_back(ea); m->m_env.push_back(ea);
} }
void ExecCmd::putenv(const string &name, const string& value) void ExecCmd::putenv(const string &name, const string& value)
@ -209,34 +286,34 @@ public:
LOGDEB1(("~ExecCmdRsrc: working. mypid: %d\n", (int)getpid())); LOGDEB1(("~ExecCmdRsrc: working. mypid: %d\n", (int)getpid()));
// Better to close the descs first in case the child is waiting in read // Better to close the descs first in case the child is waiting in read
if (m_parent->m_pipein[0] >= 0) if (m_parent->m->m_pipein[0] >= 0)
close(m_parent->m_pipein[0]); close(m_parent->m->m_pipein[0]);
if (m_parent->m_pipein[1] >= 0) if (m_parent->m->m_pipein[1] >= 0)
close(m_parent->m_pipein[1]); close(m_parent->m->m_pipein[1]);
if (m_parent->m_pipeout[0] >= 0) if (m_parent->m->m_pipeout[0] >= 0)
close(m_parent->m_pipeout[0]); close(m_parent->m->m_pipeout[0]);
if (m_parent->m_pipeout[1] >= 0) if (m_parent->m->m_pipeout[1] >= 0)
close(m_parent->m_pipeout[1]); close(m_parent->m->m_pipeout[1]);
// It's apparently possible for m_pid to be > 0 and getpgid to fail. In // It's apparently possible for m_pid to be > 0 and getpgid to fail. In
// this case, we have to conclude that the child process does // this case, we have to conclude that the child process does
// not exist. Not too sure what causes this, but the previous code // not exist. Not too sure what causes this, but the previous code
// definitely tried to call killpg(-1,) from time to time. // definitely tried to call killpg(-1,) from time to time.
pid_t grp; pid_t grp;
if (m_parent->m_pid > 0 && (grp = getpgid(m_parent->m_pid)) > 0) { if (m_parent->m->m_pid > 0 && (grp = getpgid(m_parent->m->m_pid)) > 0) {
LOGDEB(("ExecCmd: killpg(%d, SIGTERM)\n", grp)); LOGDEB(("ExecCmd: killpg(%d, SIGTERM)\n", grp));
int ret = killpg(grp, SIGTERM); int ret = killpg(grp, SIGTERM);
if (ret == 0) { if (ret == 0) {
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
msleep(i == 0 ? 5 : (i == 1 ? 100 : 2000)); msleep(i == 0 ? 5 : (i == 1 ? 100 : 2000));
int status; int status;
(void)waitpid(m_parent->m_pid, &status, WNOHANG); (void)waitpid(m_parent->m->m_pid, &status, WNOHANG);
if (kill(m_parent->m_pid, 0) != 0) if (kill(m_parent->m->m_pid, 0) != 0)
break; break;
if (i == 2) { if (i == 2) {
LOGDEB(("ExecCmd: killpg(%d, SIGKILL)\n", grp)); LOGDEB(("ExecCmd: killpg(%d, SIGKILL)\n", grp));
killpg(grp, SIGKILL); killpg(grp, SIGKILL);
(void)waitpid(m_parent->m_pid, &status, WNOHANG); (void)waitpid(m_parent->m->m_pid, &status, WNOHANG);
} }
} }
} else { } else {
@ -244,10 +321,10 @@ public:
grp, errno)); grp, errno));
} }
} }
m_parent->m_tocmd.reset(); m_parent->m->m_tocmd.reset();
m_parent->m_fromcmd.reset(); m_parent->m->m_fromcmd.reset();
pthread_sigmask(SIG_UNBLOCK, &m_parent->m_blkcld, 0); pthread_sigmask(SIG_UNBLOCK, &m_parent->m->m_blkcld, 0);
m_parent->reset(); m_parent->m->reset();
} }
private: private:
ExecCmd *m_parent; ExecCmd *m_parent;
@ -257,6 +334,8 @@ private:
ExecCmd::~ExecCmd() ExecCmd::~ExecCmd()
{ {
ExecCmdRsrc(this); ExecCmdRsrc(this);
if (m)
delete m;
} }
// In child process. Set up pipes and exec command. // In child process. Set up pipes and exec command.
@ -272,9 +351,9 @@ ExecCmd::~ExecCmd()
// If one of the calls block, the problem manifests itself by 20mn // If one of the calls block, the problem manifests itself by 20mn
// (filter timeout) of looping on "ExecCmd::doexec: selectloop // (filter timeout) of looping on "ExecCmd::doexec: selectloop
// returned 1', because the father is waiting on the read descriptor // returned 1', because the father is waiting on the read descriptor
inline void ExecCmd::dochild(const string &cmd, const char **argv, inline void ExecCmd::Internal::dochild(const string &cmd, const char **argv,
const char **envv, const char **envv,
bool has_input, bool has_output) bool has_input, bool has_output)
{ {
// Start our own process group // Start our own process group
if (setpgid(0, getpid())) { if (setpgid(0, getpid())) {
@ -384,7 +463,7 @@ inline void ExecCmd::dochild(const string &cmd, const char **argv,
void ExecCmd::setrlimit_as(int mbytes) void ExecCmd::setrlimit_as(int mbytes)
{ {
m_rlimit_as_mbytes = mbytes; m->m_rlimit_as_mbytes = mbytes;
} }
int ExecCmd::startExec(const string &cmd, const vector<string>& args, int ExecCmd::startExec(const string &cmd, const vector<string>& args,
@ -403,11 +482,11 @@ int ExecCmd::startExec(const string &cmd, const vector<string>& args,
// The resource manager ensures resources are freed if we return early // The resource manager ensures resources are freed if we return early
ExecCmdRsrc e(this); ExecCmdRsrc e(this);
if (has_input && pipe(m_pipein) < 0) { if (has_input && pipe(m->m_pipein) < 0) {
LOGERR(("ExecCmd::startExec: pipe(2) failed. errno %d\n", errno)); LOGERR(("ExecCmd::startExec: pipe(2) failed. errno %d\n", errno));
return -1; return -1;
} }
if (has_output && pipe(m_pipeout) < 0) { if (has_output && pipe(m->m_pipeout) < 0) {
LOGERR(("ExecCmd::startExec: pipe(2) failed. errno %d\n", errno)); LOGERR(("ExecCmd::startExec: pipe(2) failed. errno %d\n", errno));
return -1; return -1;
} }
@ -441,7 +520,7 @@ int ExecCmd::startExec(const string &cmd, const vector<string>& args,
for (envsize = 0; ; envsize++) for (envsize = 0; ; envsize++)
if (environ[envsize] == 0) if (environ[envsize] == 0)
break; break;
envv = (Ccharp *)malloc((envsize + m_env.size() + 2) * sizeof(char *)); envv = (Ccharp *)malloc((envsize + m->m_env.size() + 2) * sizeof(char *));
if (envv == 0) { if (envv == 0) {
LOGERR(("ExecCmd::doexec: malloc() failed. errno %d\n", errno)); LOGERR(("ExecCmd::doexec: malloc() failed. errno %d\n", errno));
free(argv); free(argv);
@ -450,8 +529,8 @@ int ExecCmd::startExec(const string &cmd, const vector<string>& args,
int eidx; int eidx;
for (eidx = 0; eidx < envsize; eidx++) for (eidx = 0; eidx < envsize; eidx++)
envv[eidx] = environ[eidx]; envv[eidx] = environ[eidx];
for (vector<string>::const_iterator it = m_env.begin(); for (vector<string>::const_iterator it = m->m_env.begin();
it != m_env.end(); it++) { it != m->m_env.end(); it++) {
envv[eidx++] = it->c_str(); envv[eidx++] = it->c_str();
} }
envv[eidx] = 0; envv[eidx] = 0;
@ -495,27 +574,27 @@ int ExecCmd::startExec(const string &cmd, const vector<string>& args,
posix_spawn_file_actions_init(&facts); posix_spawn_file_actions_init(&facts);
if (has_input) { if (has_input) {
posix_spawn_file_actions_addclose(&facts, m_pipein[1]); posix_spawn_file_actions_addclose(&facts, m->m_pipein[1]);
if (m_pipein[0] != 0) { if (m->m_pipein[0] != 0) {
posix_spawn_file_actions_adddup2(&facts, m_pipein[0], 0); posix_spawn_file_actions_adddup2(&facts, m->m_pipein[0], 0);
posix_spawn_file_actions_addclose(&facts, m_pipein[0]); posix_spawn_file_actions_addclose(&facts, m->m_pipein[0]);
} }
} }
if (has_output) { if (has_output) {
posix_spawn_file_actions_addclose(&facts, m_pipeout[0]); posix_spawn_file_actions_addclose(&facts, m->m_pipeout[0]);
if (m_pipeout[1] != 1) { if (m->m_pipeout[1] != 1) {
posix_spawn_file_actions_adddup2(&facts, m_pipeout[1], 1); posix_spawn_file_actions_adddup2(&facts, m->m_pipeout[1], 1);
posix_spawn_file_actions_addclose(&facts, m_pipeout[1]); posix_spawn_file_actions_addclose(&facts, m->m_pipeout[1]);
} }
} }
// Do we need to redirect stderr ? // Do we need to redirect stderr ?
if (!m_stderrFile.empty()) { if (!m->m_stderrFile.empty()) {
int oflags = O_WRONLY|O_CREAT; int oflags = O_WRONLY|O_CREAT;
#ifdef O_APPEND #ifdef O_APPEND
oflags |= O_APPEND; oflags |= O_APPEND;
#endif #endif
posix_spawn_file_actions_addopen(&facts, 2, m_stderrFile.c_str(), posix_spawn_file_actions_addopen(&facts, 2, m->m_stderrFile.c_str(),
oflags, 0600); oflags, 0600);
} }
LOGDEB1(("using SPAWN\n")); LOGDEB1(("using SPAWN\n"));
@ -527,7 +606,7 @@ int ExecCmd::startExec(const string &cmd, const vector<string>& args,
posix_spawn_file_actions_addclose(&facts, i); posix_spawn_file_actions_addclose(&facts, i);
} }
int ret = posix_spawn(&m_pid, exe.c_str(), &facts, &attrs, int ret = posix_spawn(&m->m_pid, exe.c_str(), &facts, &attrs,
(char *const *)argv, (char *const *)envv); (char *const *)argv, (char *const *)envv);
posix_spawnattr_destroy(&attrs); posix_spawnattr_destroy(&attrs);
posix_spawn_file_actions_destroy(&facts); posix_spawn_file_actions_destroy(&facts);
@ -539,22 +618,22 @@ int ExecCmd::startExec(const string &cmd, const vector<string>& args,
} }
#else #else
if (o_useVfork) { if (Internal::o_useVfork) {
LOGDEB1(("using VFORK\n")); LOGDEB1(("using VFORK\n"));
m_pid = vfork(); m->m_pid = vfork();
} else { } else {
LOGDEB1(("using FORK\n")); LOGDEB1(("using FORK\n"));
m_pid = fork(); m->m_pid = fork();
} }
if (m_pid < 0) { if (m->m_pid < 0) {
LOGERR(("ExecCmd::startExec: fork(2) failed. errno %d\n", errno)); LOGERR(("ExecCmd::startExec: fork(2) failed. errno %d\n", errno));
return -1; return -1;
} }
if (m_pid == 0) { if (m->m_pid == 0) {
// e.inactivate() is not needed. As we do not return, the call // e.inactivate() is not needed. As we do not return, the call
// stack won't be unwound and destructors of local objects // stack won't be unwound and destructors of local objects
// won't be called. // won't be called.
dochild(exe, argv, envv, has_input, has_output); m->dochild(exe, argv, envv, has_input, has_output);
// dochild does not return. Just in case... // dochild does not return. Just in case...
_exit(1); _exit(1);
} }
@ -570,30 +649,30 @@ int ExecCmd::startExec(const string &cmd, const vector<string>& args,
// Set the process group for the child. This is also done in the // Set the process group for the child. This is also done in the
// child process see wikipedia(Process_group) // child process see wikipedia(Process_group)
if (setpgid(m_pid, m_pid)) { if (setpgid(m->m_pid, m->m_pid)) {
// This can fail with EACCES if the son has already done execve // This can fail with EACCES if the son has already done execve
// (linux at least) // (linux at least)
LOGDEB2(("ExecCmd: father setpgid(son)(%d,%d) errno %d (ok)\n", LOGDEB2(("ExecCmd: father setpgid(son)(%d,%d) errno %d (ok)\n",
m_pid, m_pid, errno)); m->m_pid, m->m_pid, errno));
} }
sigemptyset(&m_blkcld); sigemptyset(&m->m_blkcld);
sigaddset(&m_blkcld, SIGCHLD); sigaddset(&m->m_blkcld, SIGCHLD);
pthread_sigmask(SIG_BLOCK, &m_blkcld, 0); pthread_sigmask(SIG_BLOCK, &m->m_blkcld, 0);
if (has_input) { if (has_input) {
close(m_pipein[0]); close(m->m_pipein[0]);
m_pipein[0] = -1; m->m_pipein[0] = -1;
NetconCli *iclicon = new NetconCli(); NetconCli *iclicon = new NetconCli();
iclicon->setconn(m_pipein[1]); iclicon->setconn(m->m_pipein[1]);
m_tocmd = NetconP(iclicon); m->m_tocmd = NetconP(iclicon);
} }
if (has_output) { if (has_output) {
close(m_pipeout[1]); close(m->m_pipeout[1]);
m_pipeout[1] = -1; m->m_pipeout[1] = -1;
NetconCli *oclicon = new NetconCli(); NetconCli *oclicon = new NetconCli();
oclicon->setconn(m_pipeout[0]); oclicon->setconn(m->m_pipeout[0]);
m_fromcmd = NetconP(oclicon); m->m_fromcmd = NetconP(oclicon);
} }
/* Don't want to undo what we just did ! */ /* Don't want to undo what we just did ! */
@ -685,57 +764,57 @@ int ExecCmd::doexec(const string &cmd, const vector<string>& args,
if (input || output) { if (input || output) {
// Setup output // Setup output
if (output) { if (output) {
NetconCli *oclicon = dynamic_cast<NetconCli *>(m_fromcmd.get()); NetconCli *oclicon = dynamic_cast<NetconCli *>(m->m_fromcmd.get());
if (!oclicon) { if (!oclicon) {
LOGERR(("ExecCmd::doexec: no connection from command\n")); LOGERR(("ExecCmd::doexec: no connection from command\n"));
return -1; return -1;
} }
oclicon->setcallback(STD_SHARED_PTR<NetconWorker> oclicon->setcallback(STD_SHARED_PTR<NetconWorker>
(new ExecReader(output, m_advise))); (new ExecReader(output, m->m_advise)));
myloop.addselcon(m_fromcmd, Netcon::NETCONPOLL_READ); myloop.addselcon(m->m_fromcmd, Netcon::NETCONPOLL_READ);
// Give up ownership // Give up ownership
m_fromcmd.reset(); m->m_fromcmd.reset();
} }
// Setup input // Setup input
if (input) { if (input) {
NetconCli *iclicon = dynamic_cast<NetconCli *>(m_tocmd.get()); NetconCli *iclicon = dynamic_cast<NetconCli *>(m->m_tocmd.get());
if (!iclicon) { if (!iclicon) {
LOGERR(("ExecCmd::doexec: no connection from command\n")); LOGERR(("ExecCmd::doexec: no connection from command\n"));
return -1; return -1;
} }
iclicon->setcallback(STD_SHARED_PTR<NetconWorker> iclicon->setcallback(STD_SHARED_PTR<NetconWorker>
(new ExecWriter(input, m_provide))); (new ExecWriter(input, m->m_provide)));
myloop.addselcon(m_tocmd, Netcon::NETCONPOLL_WRITE); myloop.addselcon(m->m_tocmd, Netcon::NETCONPOLL_WRITE);
// Give up ownership // Give up ownership
m_tocmd.reset(); m->m_tocmd.reset();
} }
// Do the actual reading/writing/waiting // Do the actual reading/writing/waiting
myloop.setperiodichandler(0, 0, m_timeoutMs); myloop.setperiodichandler(0, 0, m->m_timeoutMs);
while ((ret = myloop.doLoop()) > 0) { while ((ret = myloop.doLoop()) > 0) {
LOGDEB(("ExecCmd::doexec: selectloop returned %d\n", ret)); LOGDEB(("ExecCmd::doexec: selectloop returned %d\n", ret));
if (m_advise) if (m->m_advise)
m_advise->newData(0); m->m_advise->newData(0);
if (m_killRequest) { if (m->m_killRequest) {
LOGINFO(("ExecCmd::doexec: cancel request\n")); LOGINFO(("ExecCmd::doexec: cancel request\n"));
break; break;
} }
} }
LOGDEB0(("ExecCmd::doexec: selectloop returned %d\n", ret)); LOGDEB0(("ExecCmd::doexec: selectloop returned %d\n", ret));
// Check for interrupt request: we won't want to waitpid() // Check for interrupt request: we won't want to waitpid()
if (m_advise) if (m->m_advise)
m_advise->newData(0); m->m_advise->newData(0);
// The netcons don't take ownership of the fds: we have to close them // The netcons don't take ownership of the fds: we have to close them
// (have to do it before wait, this may be the signal the child is // (have to do it before wait, this may be the signal the child is
// waiting for exiting). // waiting for exiting).
if (input) { if (input) {
close(m_pipein[1]); close(m->m_pipein[1]);
m_pipein[1] = -1; m->m_pipein[1] = -1;
} }
if (output) { if (output) {
close(m_pipeout[0]); close(m->m_pipeout[0]);
m_pipeout[0] = -1; m->m_pipeout[0] = -1;
} }
} }
@ -750,14 +829,14 @@ int ExecCmd::doexec(const string &cmd, const vector<string>& args,
int ExecCmd::send(const string& data) int ExecCmd::send(const string& data)
{ {
NetconCli *con = dynamic_cast<NetconCli *>(m_tocmd.get()); NetconCli *con = dynamic_cast<NetconCli *>(m->m_tocmd.get());
if (con == 0) { if (con == 0) {
LOGERR(("ExecCmd::send: outpipe is closed\n")); LOGERR(("ExecCmd::send: outpipe is closed\n"));
return -1; return -1;
} }
unsigned int nwritten = 0; unsigned int nwritten = 0;
while (nwritten < data.length()) { while (nwritten < data.length()) {
if (m_killRequest) if (m->m_killRequest)
break; break;
int n = con->send(data.c_str() + nwritten, data.length() - nwritten); int n = con->send(data.c_str() + nwritten, data.length() - nwritten);
if (n < 0) { if (n < 0) {
@ -771,7 +850,7 @@ int ExecCmd::send(const string& data)
int ExecCmd::receive(string& data, int cnt) int ExecCmd::receive(string& data, int cnt)
{ {
NetconCli *con = dynamic_cast<NetconCli *>(m_fromcmd.get()); NetconCli *con = dynamic_cast<NetconCli *>(m->m_fromcmd.get());
if (con == 0) { if (con == 0) {
LOGERR(("ExecCmd::receive: inpipe is closed\n")); LOGERR(("ExecCmd::receive: inpipe is closed\n"));
return -1; return -1;
@ -798,7 +877,7 @@ int ExecCmd::receive(string& data, int cnt)
int ExecCmd::getline(string& data) int ExecCmd::getline(string& data)
{ {
NetconCli *con = dynamic_cast<NetconCli *>(m_fromcmd.get()); NetconCli *con = dynamic_cast<NetconCli *>(m->m_fromcmd.get());
if (con == 0) { if (con == 0) {
LOGERR(("ExecCmd::receive: inpipe is closed\n")); LOGERR(("ExecCmd::receive: inpipe is closed\n"));
return -1; return -1;
@ -821,13 +900,13 @@ int ExecCmd::wait()
{ {
ExecCmdRsrc e(this); ExecCmdRsrc e(this);
int status = -1; int status = -1;
if (!m_killRequest && m_pid > 0) { if (!m->m_killRequest && m->m_pid > 0) {
if (waitpid(m_pid, &status, 0) < 0) { if (waitpid(m->m_pid, &status, 0) < 0) {
LOGERR(("ExecCmd::waitpid: returned -1 errno %d\n", errno)); LOGERR(("ExecCmd::waitpid: returned -1 errno %d\n", errno));
status = -1; status = -1;
} }
LOGDEB(("ExecCmd::wait: got status 0x%x\n", status)); LOGDEB(("ExecCmd::wait: got status 0x%x\n", status));
m_pid = -1; m->m_pid = -1;
} }
// Let the ExecCmdRsrc cleanup // Let the ExecCmdRsrc cleanup
return status; return status;
@ -838,15 +917,15 @@ bool ExecCmd::maybereap(int *status)
ExecCmdRsrc e(this); ExecCmdRsrc e(this);
*status = -1; *status = -1;
if (m_pid <= 0) { if (m->m_pid <= 0) {
// Already waited for ?? // Already waited for ??
return true; return true;
} }
pid_t pid = waitpid(m_pid, status, WNOHANG); pid_t pid = waitpid(m->m_pid, status, WNOHANG);
if (pid < 0) { if (pid < 0) {
LOGERR(("ExecCmd::maybereap: returned -1 errno %d\n", errno)); LOGERR(("ExecCmd::maybereap: returned -1 errno %d\n", errno));
m_pid = -1; m->m_pid = -1;
return true; return true;
} else if (pid == 0) { } else if (pid == 0) {
LOGDEB1(("ExecCmd::maybereap: not exited yet\n")); LOGDEB1(("ExecCmd::maybereap: not exited yet\n"));
@ -854,7 +933,7 @@ bool ExecCmd::maybereap(int *status)
return false; return false;
} else { } else {
LOGDEB(("ExecCmd::maybereap: got status 0x%x\n", status)); LOGDEB(("ExecCmd::maybereap: got status 0x%x\n", status));
m_pid = -1; m->m_pid = -1;
return true; return true;
} }
} }

View File

@ -17,14 +17,11 @@
#ifndef _EXECMD_H_INCLUDED_ #ifndef _EXECMD_H_INCLUDED_
#define _EXECMD_H_INCLUDED_ #define _EXECMD_H_INCLUDED_
#ifndef _WIN32 #ifndef _WIN32
#include <signal.h>
#include <string> #include <string>
#include <vector> #include <vector>
#include <stack> #include <stack>
#include "netcon.h"
/** /**
* Callback function object to advise of new data arrival, or just periodic * Callback function object to advise of new data arrival, or just periodic
* heartbeat if cnt is 0. * heartbeat if cnt is 0.
@ -96,15 +93,15 @@ class ExecCmd {
* select timeout / whenever new data is needed to send. Must be called * select timeout / whenever new data is needed to send. Must be called
* before doexec() * before doexec()
*/ */
void setAdvise(ExecCmdAdvise *adv) {m_advise = adv;} void setAdvise(ExecCmdAdvise *adv);
void setProvide(ExecCmdProvide *p) {m_provide = p;} void setProvide(ExecCmdProvide *p);
/** /**
* Set select timeout in milliseconds. The default is 1 S. * Set select timeout in milliseconds. The default is 1 S.
* This is NOT a time after which an error will occur, but the period of * This is NOT a time after which an error will occur, but the period of
* the calls to the cancellation check routine. * the calls to the cancellation check routine.
*/ */
void setTimeout(int mS) {if (mS > 30) m_timeoutMs = mS;} void setTimeout(int mS);
/** /**
* Set destination for stderr data. The default is to let it alone (will * Set destination for stderr data. The default is to let it alone (will
@ -113,7 +110,7 @@ class ExecCmd {
* If the parameter can't be opened for writing, the command's * If the parameter can't be opened for writing, the command's
* stderr will be closed. * stderr will be closed.
*/ */
void setStderr(const std::string &stderrFile) {m_stderrFile = stderrFile;} void setStderr(const std::string &stderrFile);
/** /**
* Execute command. * Execute command.
@ -151,25 +148,21 @@ class ExecCmd {
@param O: status, the wait(2) call's status value */ @param O: status, the wait(2) call's status value */
bool maybereap(int *status); bool maybereap(int *status);
pid_t getChildPid() {return m_pid;} pid_t getChildPid();
/** /**
* Cancel/kill command. This can be called from another thread or * Cancel/kill command. This can be called from another thread or
* from the advise callback, which could also raise an exception to * from the advise callback, which could also raise an exception to
* accomplish the same thing * accomplish the same thing
*/ */
void setKill() {m_killRequest = true;} void setKill();
/** /**
* Get rid of current process (become ready for start). * Get rid of current process (become ready for start).
*/ */
void zapChild() {setKill(); (void)wait();} void zapChild();
ExecCmd() ExecCmd();
: m_advise(0), m_provide(0), m_timeoutMs(1000), m_rlimit_as_mbytes(0)
{
reset();
}
~ExecCmd(); ~ExecCmd();
/** /**
@ -192,38 +185,9 @@ class ExecCmd {
friend class ExecCmdRsrc; friend class ExecCmdRsrc;
private: private:
static bool o_useVfork; class Internal;
Internal *m;
std::vector<std::string> m_env; /* Copyconst and assignment are private and forbidden */
ExecCmdAdvise *m_advise;
ExecCmdProvide *m_provide;
bool m_killRequest;
int m_timeoutMs;
int m_rlimit_as_mbytes;
std::string m_stderrFile;
// Pipe for data going to the command
int m_pipein[2];
NetconP m_tocmd;
// Pipe for data coming out
int m_pipeout[2];
NetconP m_fromcmd;
// Subprocess id
pid_t m_pid;
// Saved sigmask
sigset_t m_blkcld;
// Reset internal state indicators. Any resources should have been
// previously freed
void reset() {
m_killRequest = false;
m_pipein[0] = m_pipein[1] = m_pipeout[0] = m_pipeout[1] = -1;
m_pid = -1;
sigemptyset(&m_blkcld);
}
// Child process code
inline void dochild(const std::string &cmd, const char **argv,
const char **envv, bool has_input, bool has_output);
/* Copyconst and assignment private and forbidden */
ExecCmd(const ExecCmd &) {} ExecCmd(const ExecCmd &) {}
ExecCmd& operator=(const ExecCmd &) {return *this;}; ExecCmd& operator=(const ExecCmd &) {return *this;};
}; };