Hide most ExecCmd internals
--HG-- branch : WINDOWSPORT
This commit is contained in:
parent
b0dcda09b6
commit
649a893d1b
@ -16,6 +16,8 @@
|
||||
*/
|
||||
#include "autoconfig.h"
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <QTimer>
|
||||
|
||||
|
||||
@ -57,9 +57,7 @@ using namespace std;
|
||||
|
||||
extern char **environ;
|
||||
|
||||
bool ExecCmd::o_useVfork = false;
|
||||
|
||||
#ifdef RECOLL_DATADIR
|
||||
#ifdef BUILDING_RECOLL
|
||||
#include "debuglog.h"
|
||||
#include "smallut.h"
|
||||
|
||||
@ -114,6 +112,85 @@ static void stringToTokens(const string& str, vector<string>& tokens,
|
||||
}
|
||||
#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 */
|
||||
static bool exec_is_there(const char *candidate)
|
||||
{
|
||||
@ -174,12 +251,12 @@ void ExecCmd::useVfork(bool on)
|
||||
// an executable file, we have a problem.
|
||||
const char *argv[] = {"/", 0};
|
||||
execve("/", (char *const *)argv, environ);
|
||||
o_useVfork = on;
|
||||
Internal::o_useVfork = on;
|
||||
}
|
||||
|
||||
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)
|
||||
@ -209,34 +286,34 @@ public:
|
||||
LOGDEB1(("~ExecCmdRsrc: working. mypid: %d\n", (int)getpid()));
|
||||
|
||||
// Better to close the descs first in case the child is waiting in read
|
||||
if (m_parent->m_pipein[0] >= 0)
|
||||
close(m_parent->m_pipein[0]);
|
||||
if (m_parent->m_pipein[1] >= 0)
|
||||
close(m_parent->m_pipein[1]);
|
||||
if (m_parent->m_pipeout[0] >= 0)
|
||||
close(m_parent->m_pipeout[0]);
|
||||
if (m_parent->m_pipeout[1] >= 0)
|
||||
close(m_parent->m_pipeout[1]);
|
||||
if (m_parent->m->m_pipein[0] >= 0)
|
||||
close(m_parent->m->m_pipein[0]);
|
||||
if (m_parent->m->m_pipein[1] >= 0)
|
||||
close(m_parent->m->m_pipein[1]);
|
||||
if (m_parent->m->m_pipeout[0] >= 0)
|
||||
close(m_parent->m->m_pipeout[0]);
|
||||
if (m_parent->m->m_pipeout[1] >= 0)
|
||||
close(m_parent->m->m_pipeout[1]);
|
||||
|
||||
// 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
|
||||
// not exist. Not too sure what causes this, but the previous code
|
||||
// definitely tried to call killpg(-1,) from time to time.
|
||||
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));
|
||||
int ret = killpg(grp, SIGTERM);
|
||||
if (ret == 0) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
msleep(i == 0 ? 5 : (i == 1 ? 100 : 2000));
|
||||
int status;
|
||||
(void)waitpid(m_parent->m_pid, &status, WNOHANG);
|
||||
if (kill(m_parent->m_pid, 0) != 0)
|
||||
(void)waitpid(m_parent->m->m_pid, &status, WNOHANG);
|
||||
if (kill(m_parent->m->m_pid, 0) != 0)
|
||||
break;
|
||||
if (i == 2) {
|
||||
LOGDEB(("ExecCmd: killpg(%d, SIGKILL)\n", grp));
|
||||
killpg(grp, SIGKILL);
|
||||
(void)waitpid(m_parent->m_pid, &status, WNOHANG);
|
||||
(void)waitpid(m_parent->m->m_pid, &status, WNOHANG);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -244,10 +321,10 @@ public:
|
||||
grp, errno));
|
||||
}
|
||||
}
|
||||
m_parent->m_tocmd.reset();
|
||||
m_parent->m_fromcmd.reset();
|
||||
pthread_sigmask(SIG_UNBLOCK, &m_parent->m_blkcld, 0);
|
||||
m_parent->reset();
|
||||
m_parent->m->m_tocmd.reset();
|
||||
m_parent->m->m_fromcmd.reset();
|
||||
pthread_sigmask(SIG_UNBLOCK, &m_parent->m->m_blkcld, 0);
|
||||
m_parent->m->reset();
|
||||
}
|
||||
private:
|
||||
ExecCmd *m_parent;
|
||||
@ -257,6 +334,8 @@ private:
|
||||
ExecCmd::~ExecCmd()
|
||||
{
|
||||
ExecCmdRsrc(this);
|
||||
if (m)
|
||||
delete m;
|
||||
}
|
||||
|
||||
// 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
|
||||
// (filter timeout) of looping on "ExecCmd::doexec: selectloop
|
||||
// returned 1', because the father is waiting on the read descriptor
|
||||
inline void ExecCmd::dochild(const string &cmd, const char **argv,
|
||||
const char **envv,
|
||||
bool has_input, bool has_output)
|
||||
inline void ExecCmd::Internal::dochild(const string &cmd, const char **argv,
|
||||
const char **envv,
|
||||
bool has_input, bool has_output)
|
||||
{
|
||||
// Start our own process group
|
||||
if (setpgid(0, getpid())) {
|
||||
@ -384,7 +463,7 @@ inline void ExecCmd::dochild(const string &cmd, const char **argv,
|
||||
|
||||
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,
|
||||
@ -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
|
||||
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));
|
||||
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));
|
||||
return -1;
|
||||
}
|
||||
@ -441,7 +520,7 @@ int ExecCmd::startExec(const string &cmd, const vector<string>& args,
|
||||
for (envsize = 0; ; envsize++)
|
||||
if (environ[envsize] == 0)
|
||||
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) {
|
||||
LOGERR(("ExecCmd::doexec: malloc() failed. errno %d\n", errno));
|
||||
free(argv);
|
||||
@ -450,8 +529,8 @@ int ExecCmd::startExec(const string &cmd, const vector<string>& args,
|
||||
int eidx;
|
||||
for (eidx = 0; eidx < envsize; eidx++)
|
||||
envv[eidx] = environ[eidx];
|
||||
for (vector<string>::const_iterator it = m_env.begin();
|
||||
it != m_env.end(); it++) {
|
||||
for (vector<string>::const_iterator it = m->m_env.begin();
|
||||
it != m->m_env.end(); it++) {
|
||||
envv[eidx++] = it->c_str();
|
||||
}
|
||||
envv[eidx] = 0;
|
||||
@ -495,27 +574,27 @@ int ExecCmd::startExec(const string &cmd, const vector<string>& args,
|
||||
posix_spawn_file_actions_init(&facts);
|
||||
|
||||
if (has_input) {
|
||||
posix_spawn_file_actions_addclose(&facts, m_pipein[1]);
|
||||
if (m_pipein[0] != 0) {
|
||||
posix_spawn_file_actions_adddup2(&facts, m_pipein[0], 0);
|
||||
posix_spawn_file_actions_addclose(&facts, m_pipein[0]);
|
||||
posix_spawn_file_actions_addclose(&facts, m->m_pipein[1]);
|
||||
if (m->m_pipein[0] != 0) {
|
||||
posix_spawn_file_actions_adddup2(&facts, m->m_pipein[0], 0);
|
||||
posix_spawn_file_actions_addclose(&facts, m->m_pipein[0]);
|
||||
}
|
||||
}
|
||||
if (has_output) {
|
||||
posix_spawn_file_actions_addclose(&facts, m_pipeout[0]);
|
||||
if (m_pipeout[1] != 1) {
|
||||
posix_spawn_file_actions_adddup2(&facts, m_pipeout[1], 1);
|
||||
posix_spawn_file_actions_addclose(&facts, m_pipeout[1]);
|
||||
posix_spawn_file_actions_addclose(&facts, m->m_pipeout[0]);
|
||||
if (m->m_pipeout[1] != 1) {
|
||||
posix_spawn_file_actions_adddup2(&facts, m->m_pipeout[1], 1);
|
||||
posix_spawn_file_actions_addclose(&facts, m->m_pipeout[1]);
|
||||
}
|
||||
}
|
||||
|
||||
// Do we need to redirect stderr ?
|
||||
if (!m_stderrFile.empty()) {
|
||||
if (!m->m_stderrFile.empty()) {
|
||||
int oflags = O_WRONLY|O_CREAT;
|
||||
#ifdef O_APPEND
|
||||
oflags |= O_APPEND;
|
||||
#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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
posix_spawnattr_destroy(&attrs);
|
||||
posix_spawn_file_actions_destroy(&facts);
|
||||
@ -539,22 +618,22 @@ int ExecCmd::startExec(const string &cmd, const vector<string>& args,
|
||||
}
|
||||
|
||||
#else
|
||||
if (o_useVfork) {
|
||||
if (Internal::o_useVfork) {
|
||||
LOGDEB1(("using VFORK\n"));
|
||||
m_pid = vfork();
|
||||
m->m_pid = vfork();
|
||||
} else {
|
||||
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));
|
||||
return -1;
|
||||
}
|
||||
if (m_pid == 0) {
|
||||
if (m->m_pid == 0) {
|
||||
// e.inactivate() is not needed. As we do not return, the call
|
||||
// stack won't be unwound and destructors of local objects
|
||||
// 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...
|
||||
_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
|
||||
// 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
|
||||
// (linux at least)
|
||||
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);
|
||||
sigaddset(&m_blkcld, SIGCHLD);
|
||||
pthread_sigmask(SIG_BLOCK, &m_blkcld, 0);
|
||||
sigemptyset(&m->m_blkcld);
|
||||
sigaddset(&m->m_blkcld, SIGCHLD);
|
||||
pthread_sigmask(SIG_BLOCK, &m->m_blkcld, 0);
|
||||
|
||||
if (has_input) {
|
||||
close(m_pipein[0]);
|
||||
m_pipein[0] = -1;
|
||||
close(m->m_pipein[0]);
|
||||
m->m_pipein[0] = -1;
|
||||
NetconCli *iclicon = new NetconCli();
|
||||
iclicon->setconn(m_pipein[1]);
|
||||
m_tocmd = NetconP(iclicon);
|
||||
iclicon->setconn(m->m_pipein[1]);
|
||||
m->m_tocmd = NetconP(iclicon);
|
||||
}
|
||||
if (has_output) {
|
||||
close(m_pipeout[1]);
|
||||
m_pipeout[1] = -1;
|
||||
close(m->m_pipeout[1]);
|
||||
m->m_pipeout[1] = -1;
|
||||
NetconCli *oclicon = new NetconCli();
|
||||
oclicon->setconn(m_pipeout[0]);
|
||||
m_fromcmd = NetconP(oclicon);
|
||||
oclicon->setconn(m->m_pipeout[0]);
|
||||
m->m_fromcmd = NetconP(oclicon);
|
||||
}
|
||||
|
||||
/* 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) {
|
||||
// Setup output
|
||||
if (output) {
|
||||
NetconCli *oclicon = dynamic_cast<NetconCli *>(m_fromcmd.get());
|
||||
NetconCli *oclicon = dynamic_cast<NetconCli *>(m->m_fromcmd.get());
|
||||
if (!oclicon) {
|
||||
LOGERR(("ExecCmd::doexec: no connection from command\n"));
|
||||
return -1;
|
||||
}
|
||||
oclicon->setcallback(STD_SHARED_PTR<NetconWorker>
|
||||
(new ExecReader(output, m_advise)));
|
||||
myloop.addselcon(m_fromcmd, Netcon::NETCONPOLL_READ);
|
||||
(new ExecReader(output, m->m_advise)));
|
||||
myloop.addselcon(m->m_fromcmd, Netcon::NETCONPOLL_READ);
|
||||
// Give up ownership
|
||||
m_fromcmd.reset();
|
||||
m->m_fromcmd.reset();
|
||||
}
|
||||
// Setup input
|
||||
if (input) {
|
||||
NetconCli *iclicon = dynamic_cast<NetconCli *>(m_tocmd.get());
|
||||
NetconCli *iclicon = dynamic_cast<NetconCli *>(m->m_tocmd.get());
|
||||
if (!iclicon) {
|
||||
LOGERR(("ExecCmd::doexec: no connection from command\n"));
|
||||
return -1;
|
||||
}
|
||||
iclicon->setcallback(STD_SHARED_PTR<NetconWorker>
|
||||
(new ExecWriter(input, m_provide)));
|
||||
myloop.addselcon(m_tocmd, Netcon::NETCONPOLL_WRITE);
|
||||
(new ExecWriter(input, m->m_provide)));
|
||||
myloop.addselcon(m->m_tocmd, Netcon::NETCONPOLL_WRITE);
|
||||
// Give up ownership
|
||||
m_tocmd.reset();
|
||||
m->m_tocmd.reset();
|
||||
}
|
||||
|
||||
// Do the actual reading/writing/waiting
|
||||
myloop.setperiodichandler(0, 0, m_timeoutMs);
|
||||
myloop.setperiodichandler(0, 0, m->m_timeoutMs);
|
||||
while ((ret = myloop.doLoop()) > 0) {
|
||||
LOGDEB(("ExecCmd::doexec: selectloop returned %d\n", ret));
|
||||
if (m_advise)
|
||||
m_advise->newData(0);
|
||||
if (m_killRequest) {
|
||||
if (m->m_advise)
|
||||
m->m_advise->newData(0);
|
||||
if (m->m_killRequest) {
|
||||
LOGINFO(("ExecCmd::doexec: cancel request\n"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
LOGDEB0(("ExecCmd::doexec: selectloop returned %d\n", ret));
|
||||
// Check for interrupt request: we won't want to waitpid()
|
||||
if (m_advise)
|
||||
m_advise->newData(0);
|
||||
if (m->m_advise)
|
||||
m->m_advise->newData(0);
|
||||
|
||||
// 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
|
||||
// waiting for exiting).
|
||||
if (input) {
|
||||
close(m_pipein[1]);
|
||||
m_pipein[1] = -1;
|
||||
close(m->m_pipein[1]);
|
||||
m->m_pipein[1] = -1;
|
||||
}
|
||||
if (output) {
|
||||
close(m_pipeout[0]);
|
||||
m_pipeout[0] = -1;
|
||||
close(m->m_pipeout[0]);
|
||||
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)
|
||||
{
|
||||
NetconCli *con = dynamic_cast<NetconCli *>(m_tocmd.get());
|
||||
NetconCli *con = dynamic_cast<NetconCli *>(m->m_tocmd.get());
|
||||
if (con == 0) {
|
||||
LOGERR(("ExecCmd::send: outpipe is closed\n"));
|
||||
return -1;
|
||||
}
|
||||
unsigned int nwritten = 0;
|
||||
while (nwritten < data.length()) {
|
||||
if (m_killRequest)
|
||||
if (m->m_killRequest)
|
||||
break;
|
||||
int n = con->send(data.c_str() + nwritten, data.length() - nwritten);
|
||||
if (n < 0) {
|
||||
@ -771,7 +850,7 @@ int ExecCmd::send(const string& data)
|
||||
|
||||
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) {
|
||||
LOGERR(("ExecCmd::receive: inpipe is closed\n"));
|
||||
return -1;
|
||||
@ -798,7 +877,7 @@ int ExecCmd::receive(string& data, int cnt)
|
||||
|
||||
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) {
|
||||
LOGERR(("ExecCmd::receive: inpipe is closed\n"));
|
||||
return -1;
|
||||
@ -821,13 +900,13 @@ int ExecCmd::wait()
|
||||
{
|
||||
ExecCmdRsrc e(this);
|
||||
int status = -1;
|
||||
if (!m_killRequest && m_pid > 0) {
|
||||
if (waitpid(m_pid, &status, 0) < 0) {
|
||||
if (!m->m_killRequest && m->m_pid > 0) {
|
||||
if (waitpid(m->m_pid, &status, 0) < 0) {
|
||||
LOGERR(("ExecCmd::waitpid: returned -1 errno %d\n", errno));
|
||||
status = -1;
|
||||
}
|
||||
LOGDEB(("ExecCmd::wait: got status 0x%x\n", status));
|
||||
m_pid = -1;
|
||||
m->m_pid = -1;
|
||||
}
|
||||
// Let the ExecCmdRsrc cleanup
|
||||
return status;
|
||||
@ -838,15 +917,15 @@ bool ExecCmd::maybereap(int *status)
|
||||
ExecCmdRsrc e(this);
|
||||
*status = -1;
|
||||
|
||||
if (m_pid <= 0) {
|
||||
if (m->m_pid <= 0) {
|
||||
// Already waited for ??
|
||||
return true;
|
||||
}
|
||||
|
||||
pid_t pid = waitpid(m_pid, status, WNOHANG);
|
||||
pid_t pid = waitpid(m->m_pid, status, WNOHANG);
|
||||
if (pid < 0) {
|
||||
LOGERR(("ExecCmd::maybereap: returned -1 errno %d\n", errno));
|
||||
m_pid = -1;
|
||||
m->m_pid = -1;
|
||||
return true;
|
||||
} else if (pid == 0) {
|
||||
LOGDEB1(("ExecCmd::maybereap: not exited yet\n"));
|
||||
@ -854,7 +933,7 @@ bool ExecCmd::maybereap(int *status)
|
||||
return false;
|
||||
} else {
|
||||
LOGDEB(("ExecCmd::maybereap: got status 0x%x\n", status));
|
||||
m_pid = -1;
|
||||
m->m_pid = -1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,14 +17,11 @@
|
||||
#ifndef _EXECMD_H_INCLUDED_
|
||||
#define _EXECMD_H_INCLUDED_
|
||||
#ifndef _WIN32
|
||||
#include <signal.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <stack>
|
||||
|
||||
#include "netcon.h"
|
||||
|
||||
/**
|
||||
* Callback function object to advise of new data arrival, or just periodic
|
||||
* heartbeat if cnt is 0.
|
||||
@ -96,15 +93,15 @@ class ExecCmd {
|
||||
* select timeout / whenever new data is needed to send. Must be called
|
||||
* before doexec()
|
||||
*/
|
||||
void setAdvise(ExecCmdAdvise *adv) {m_advise = adv;}
|
||||
void setProvide(ExecCmdProvide *p) {m_provide = p;}
|
||||
void setAdvise(ExecCmdAdvise *adv);
|
||||
void setProvide(ExecCmdProvide *p);
|
||||
|
||||
/**
|
||||
* 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
|
||||
* 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
|
||||
@ -113,7 +110,7 @@ class ExecCmd {
|
||||
* If the parameter can't be opened for writing, the command's
|
||||
* stderr will be closed.
|
||||
*/
|
||||
void setStderr(const std::string &stderrFile) {m_stderrFile = stderrFile;}
|
||||
void setStderr(const std::string &stderrFile);
|
||||
|
||||
/**
|
||||
* Execute command.
|
||||
@ -151,25 +148,21 @@ class ExecCmd {
|
||||
@param O: status, the wait(2) call's status value */
|
||||
bool maybereap(int *status);
|
||||
|
||||
pid_t getChildPid() {return m_pid;}
|
||||
pid_t getChildPid();
|
||||
|
||||
/**
|
||||
* Cancel/kill command. This can be called from another thread or
|
||||
* from the advise callback, which could also raise an exception to
|
||||
* accomplish the same thing
|
||||
*/
|
||||
void setKill() {m_killRequest = true;}
|
||||
void setKill();
|
||||
|
||||
/**
|
||||
* Get rid of current process (become ready for start).
|
||||
*/
|
||||
void zapChild() {setKill(); (void)wait();}
|
||||
void zapChild();
|
||||
|
||||
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;
|
||||
private:
|
||||
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);
|
||||
/* Copyconst and assignment private and forbidden */
|
||||
class Internal;
|
||||
Internal *m;
|
||||
/* Copyconst and assignment are private and forbidden */
|
||||
ExecCmd(const ExecCmd &) {}
|
||||
ExecCmd& operator=(const ExecCmd &) {return *this;};
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user