This commit is contained in:
Jean-Francois Dockes 2016-03-22 13:50:49 +01:00
parent 90afc535a4
commit ae2962a41c
6 changed files with 785 additions and 703 deletions

View file

@ -121,9 +121,10 @@ bool ExecCmd::Internal::o_useVfork = false;
ExecCmd::ExecCmd(int) ExecCmd::ExecCmd(int)
{ {
m = new Internal(); m = new Internal();
if (m) if (m) {
m->reset(); m->reset();
} }
}
void ExecCmd::setAdvise(ExecCmdAdvise *adv) void ExecCmd::setAdvise(ExecCmdAdvise *adv)
{ {
m->m_advise = adv; m->m_advise = adv;
@ -134,9 +135,10 @@ void ExecCmd::setProvide(ExecCmdProvide *p)
} }
void ExecCmd::setTimeout(int mS) void ExecCmd::setTimeout(int mS)
{ {
if (mS > 30) if (mS > 30) {
m->m_timeoutMs = mS; m->m_timeoutMs = mS;
} }
}
void ExecCmd::setStderr(const std::string& stderrFile) void ExecCmd::setStderr(const std::string& stderrFile)
{ {
m->m_stderrFile = stderrFile; m->m_stderrFile = stderrFile;
@ -158,9 +160,10 @@ void ExecCmd::zapChild()
bool ExecCmd::requestChildExit() bool ExecCmd::requestChildExit()
{ {
if (m->m_pid > 0) { if (m->m_pid > 0) {
if (kill(m->m_pid, SIGTERM) == 0) if (kill(m->m_pid, SIGTERM) == 0) {
return true; return true;
} }
}
return false; return false;
} }
@ -182,8 +185,9 @@ static bool exec_is_there(const char *candidate)
bool ExecCmd::which(const string& cmd, string& exepath, const char* path) bool ExecCmd::which(const string& cmd, string& exepath, const char* path)
{ {
if (cmd.empty()) if (cmd.empty()) {
return false; return false;
}
if (cmd[0] == '/') { if (cmd[0] == '/') {
if (exec_is_there(cmd.c_str())) { if (exec_is_there(cmd.c_str())) {
exepath = cmd; exepath = cmd;
@ -199,14 +203,16 @@ bool ExecCmd::which(const string& cmd, string& exepath, const char* path)
} else { } else {
pp = getenv("PATH"); pp = getenv("PATH");
} }
if (pp == 0) if (pp == 0) {
return false; return false;
}
vector<string> pels; vector<string> pels;
stringToTokens(pp, pels, ":"); stringToTokens(pp, pels, ":");
for (vector<string>::iterator it = pels.begin(); it != pels.end(); it++) { for (vector<string>::iterator it = pels.begin(); it != pels.end(); it++) {
if (it->empty()) if (it->empty()) {
*it = "."; *it = ".";
}
string candidate = (it->empty() ? string(".") : *it) + "/" + cmd; string candidate = (it->empty() ? string(".") : *it) + "/" + cmd;
if (exec_is_there(candidate.c_str())) { if (exec_is_there(candidate.c_str())) {
exepath = candidate; exepath = candidate;
@ -258,19 +264,24 @@ public:
m_active = false; m_active = false;
} }
~ExecCmdRsrc() { ~ExecCmdRsrc() {
if (!m_active || !m_parent) if (!m_active || !m_parent) {
return; return;
}
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_pipein[0] >= 0) {
close(m_parent->m_pipein[0]); close(m_parent->m_pipein[0]);
if (m_parent->m_pipein[1] >= 0) }
if (m_parent->m_pipein[1] >= 0) {
close(m_parent->m_pipein[1]); close(m_parent->m_pipein[1]);
if (m_parent->m_pipeout[0] >= 0) }
if (m_parent->m_pipeout[0] >= 0) {
close(m_parent->m_pipeout[0]); close(m_parent->m_pipeout[0]);
if (m_parent->m_pipeout[1] >= 0) }
if (m_parent->m_pipeout[1] >= 0) {
close(m_parent->m_pipeout[1]); close(m_parent->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
@ -285,8 +296,9 @@ public:
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_pid, &status, WNOHANG);
if (kill(m_parent->m_pid, 0) != 0) if (kill(m_parent->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);
@ -311,9 +323,10 @@ private:
ExecCmd::~ExecCmd() ExecCmd::~ExecCmd()
{ {
ExecCmdRsrc(this->m); ExecCmdRsrc(this->m);
if (m) if (m) {
delete m; delete m;
} }
}
// In child process. Set up pipes and exec command. // In child process. Set up pipes and exec command.
// This must not return. _exit() on error. // This must not return. _exit() on error.
@ -446,7 +459,8 @@ void ExecCmd::setrlimit_as(int mbytes)
int ExecCmd::startExec(const string& cmd, const vector<string>& args, int ExecCmd::startExec(const string& cmd, const vector<string>& args,
bool has_input, bool has_output) bool has_input, bool has_output)
{ {
{ // Debug and logging {
// Debug and logging
string command = cmd + " "; string command = cmd + " ";
for (vector<string>::const_iterator it = args.begin(); for (vector<string>::const_iterator it = args.begin();
it != args.end(); it++) { it != args.end(); it++) {
@ -495,8 +509,9 @@ int ExecCmd::startExec(const string &cmd, const vector<string>& args,
Ccharp *envv; Ccharp *envv;
int envsize; int envsize;
for (envsize = 0; ; envsize++) for (envsize = 0; ; envsize++)
if (environ[envsize] == 0) if (environ[envsize] == 0) {
break; break;
}
envv = (Ccharp *)malloc((envsize + m->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));
@ -504,8 +519,9 @@ int ExecCmd::startExec(const string &cmd, const vector<string>& args,
return -1; return -1;
} }
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->m_env.begin(); for (vector<string>::const_iterator it = m->m_env.begin();
it != m->m_env.end(); it++) { it != m->m_env.end(); it++) {
envv[eidx++] = it->c_str(); envv[eidx++] = it->c_str();
@ -670,10 +686,10 @@ public:
m_cmd->m_pipein[1] = -1; m_cmd->m_pipein[1] = -1;
m_cmd->m_tocmd.reset(); m_cmd->m_tocmd.reset();
} }
virtual int data(NetconData *con, Netcon::Event reason) virtual int data(NetconData *con, Netcon::Event reason) {
{ if (!m_input) {
if (!m_input)
return -1; return -1;
}
LOGDEB1(("ExecWriter: input m_cnt %d input length %d\n", m_cnt, LOGDEB1(("ExecWriter: input m_cnt %d input length %d\n", m_cnt,
m_input->length())); m_input->length()));
if (m_cnt >= m_input->length()) { if (m_cnt >= m_input->length()) {
@ -715,10 +731,9 @@ private:
class ExecReader : public NetconWorker { class ExecReader : public NetconWorker {
public: public:
ExecReader(string *output, ExecCmdAdvise *advise) ExecReader(string *output, ExecCmdAdvise *advise)
: m_output(output), m_advise(advise) : m_output(output), m_advise(advise) {
{} }
virtual int data(NetconData *con, Netcon::Event reason) virtual int data(NetconData *con, Netcon::Event reason) {
{
char buf[8192]; char buf[8192];
int n = con->receive(buf, 8192); int n = con->receive(buf, 8192);
LOGDEB1(("ExecReader: got %d from command\n", n)); LOGDEB1(("ExecReader: got %d from command\n", n));
@ -726,8 +741,9 @@ public:
LOGERR(("ExecCmd::doexec: receive failed. errno %d\n", errno)); LOGERR(("ExecCmd::doexec: receive failed. errno %d\n", errno));
} else if (n > 0) { } else if (n > 0) {
m_output->append(buf, n); m_output->append(buf, n);
if (m_advise) if (m_advise) {
m_advise->newData(n); m_advise->newData(n);
}
} // else n == 0, just return } // else n == 0, just return
return n; return n;
} }
@ -781,8 +797,9 @@ int ExecCmd::doexec(const string &cmd, const vector<string>& args,
myloop.setperiodichandler(0, 0, m->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->m_advise) if (m->m_advise) {
m->m_advise->newData(0); m->m_advise->newData(0);
}
if (m->m_killRequest) { if (m->m_killRequest) {
LOGINFO(("ExecCmd::doexec: cancel request\n")); LOGINFO(("ExecCmd::doexec: cancel request\n"));
break; break;
@ -790,8 +807,9 @@ int ExecCmd::doexec(const string &cmd, const vector<string>& args,
} }
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->m_advise) if (m->m_advise) {
m->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
@ -810,8 +828,9 @@ int ExecCmd::doexec(const string &cmd, const vector<string>& args,
e.inactivate(); e.inactivate();
int ret1 = ExecCmd::wait(); int ret1 = ExecCmd::wait();
if (ret) if (ret) {
return -1; return -1;
}
return ret1; return ret1;
} }
@ -824,8 +843,9 @@ int ExecCmd::send(const string& data)
} }
unsigned int nwritten = 0; unsigned int nwritten = 0;
while (nwritten < data.length()) { while (nwritten < data.length()) {
if (m->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) {
LOGERR(("ExecCmd::send: send failed\n")); LOGERR(("ExecCmd::send: send failed\n"));
@ -873,8 +893,9 @@ int ExecCmd::getline(string& data)
const int BS = 1024; const int BS = 1024;
char buf[BS]; char buf[BS];
int timeosecs = m->m_timeoutMs / 1000; int timeosecs = m->m_timeoutMs / 1000;
if (timeosecs == 0) if (timeosecs == 0) {
timeosecs = 1; timeosecs = 1;
}
// Note that we only go once through here, except in case of // Note that we only go once through here, except in case of
// timeout, which is why I think that the goto is more expressive // timeout, which is why I think that the goto is more expressive
@ -884,8 +905,9 @@ again:
if (n < 0) { if (n < 0) {
if (con->timedout()) { if (con->timedout()) {
LOGDEB(("ExecCmd::getline: timeout\n")); LOGDEB(("ExecCmd::getline: timeout\n"));
if (m->m_advise) if (m->m_advise) {
m->m_advise->newData(0); m->m_advise->newData(0);
}
goto again; goto again;
} }
LOGERR(("ExecCmd::getline: error\n")); LOGERR(("ExecCmd::getline: error\n"));
@ -1006,8 +1028,9 @@ void ReExec::init(int argc, char *args[])
} }
m_cfd = open(".", 0); m_cfd = open(".", 0);
char *cd = getcwd(0, 0); char *cd = getcwd(0, 0);
if (cd) if (cd) {
m_curdir = cd; m_curdir = cd;
}
free(cd); free(cd);
} }
@ -1037,9 +1060,10 @@ void ReExec::insertArgs(const vector<string>& args, int idx)
break; break;
} }
} }
if (allsame) if (allsame) {
return; return;
} }
}
m_argv.insert(it, args.begin(), args.end()); m_argv.insert(it, args.begin(), args.end());
} }
@ -1048,10 +1072,11 @@ void ReExec::removeArg(const string& arg)
{ {
for (vector<string>::iterator it = m_argv.begin(); for (vector<string>::iterator it = m_argv.begin();
it != m_argv.end(); it++) { it != m_argv.end(); it++) {
if (*it == arg) if (*it == arg) {
it = m_argv.erase(it); it = m_argv.erase(it);
} }
} }
}
// Reexecute myself, as close as possible to the initial exec // Reexecute myself, as close as possible to the initial exec
void ReExec::reexec() void ReExec::reexec()
@ -1217,8 +1242,9 @@ bool exercise_mhexecm(const string& cmdstr, const string& mimetype,
} }
// Empty element: end of message // Empty element: end of message
if (name.empty()) if (name.empty()) {
break; break;
}
cerr << "Got name: [" << name << "] data [" << data << "]\n"; cerr << "Got name: [" << name << "] data [" << data << "]\n";
} }
} }
@ -1285,14 +1311,14 @@ public:
FILE *m_fp; FILE *m_fp;
string *m_input; string *m_input;
MEPv(string *i) MEPv(string *i)
: m_input(i) : m_input(i) {
{
m_fp = fopen("/etc/group", "r"); m_fp = fopen("/etc/group", "r");
} }
~MEPv() { ~MEPv() {
if (m_fp) if (m_fp) {
fclose(m_fp); fclose(m_fp);
} }
}
void newData() { void newData() {
char line[1024]; char line[1024];
if (m_fp && fgets(line, 1024, m_fp)) { if (m_fp && fgets(line, 1024, m_fp)) {
@ -1322,36 +1348,59 @@ int main(int argc, char *argv[])
} }
thisprog = argv[0]; thisprog = argv[0];
argc--; argv++; argc--;
argv++;
while (argc > 0 && **argv == '-') { while (argc > 0 && **argv == '-') {
(*argv)++; (*argv)++;
if (!(**argv)) if (!(**argv))
/* Cas du "adb - core" */ /* Cas du "adb - core" */
{
Usage(); Usage();
}
while (**argv) while (**argv)
switch (*(*argv)++) { switch (*(*argv)++) {
case 'c': op_flags |= OPT_c; break; case 'c':
case 'r': op_flags |= OPT_r; break; op_flags |= OPT_c;
case 'w': op_flags |= OPT_w; break; break;
case 'r':
op_flags |= OPT_r;
break;
case 'w':
op_flags |= OPT_w;
break;
#ifdef BUILDING_RECOLL #ifdef BUILDING_RECOLL
case 'm': op_flags |= OPT_m; break; case 'm':
op_flags |= OPT_m;
break;
#endif #endif
case 'i': op_flags |= OPT_i; break; case 'i':
case 'l': op_flags |= OPT_l; break; op_flags |= OPT_i;
case 'o': op_flags |= OPT_o; break; break;
default: Usage(); break; case 'l':
} op_flags |= OPT_l;
argc--; argv++; break;
} case 'o':
op_flags |= OPT_o;
if (argc < 1) break;
default:
Usage(); Usage();
break;
}
argc--;
argv++;
}
string arg1 = *argv++; argc--; if (argc < 1) {
Usage();
}
string arg1 = *argv++;
argc--;
vector<string> l; vector<string> l;
while (argc > 0) { while (argc > 0) {
l.push_back(*argv++); argc--; l.push_back(*argv++);
argc--;
} }
#ifdef BUILDING_RECOLL #ifdef BUILDING_RECOLL
@ -1384,8 +1433,9 @@ int main(int argc, char *argv[])
return 1; return 1;
#ifdef BUILDING_RECOLL #ifdef BUILDING_RECOLL
} else if (op_flags & OPT_m) { } else if (op_flags & OPT_m) {
if (l.size() < 2) if (l.size() < 2) {
Usage(); Usage();
}
string mimetype = l[0]; string mimetype = l[0];
l.erase(l.begin()); l.erase(l.begin());
return exercise_mhexecm(arg1, mimetype, l) ? 0 : 1; return exercise_mhexecm(arg1, mimetype, l) ? 0 : 1;

View file

@ -141,8 +141,9 @@ class ExecCmd {
int doexec1(const std::vector<std::string>& args, int doexec1(const std::vector<std::string>& args,
const std::string *input = 0, const std::string *input = 0,
std::string *output = 0) { std::string *output = 0) {
if (args.empty()) if (args.empty()) {
return -1; return -1;
}
return doexec(args[0], return doexec(args[0],
std::vector<std::string>(args.begin() + 1, args.end()), std::vector<std::string>(args.begin() + 1, args.end()),
input, output); input, output);
@ -225,7 +226,9 @@ class ExecCmd {
Internal *m; Internal *m;
/* Copyconst and assignment are private and forbidden */ /* Copyconst and assignment are private and forbidden */
ExecCmd(const ExecCmd&) {} ExecCmd(const ExecCmd&) {}
ExecCmd& operator=(const ExecCmd &) {return *this;}; ExecCmd& operator=(const ExecCmd&) {
return *this;
};
}; };
@ -259,13 +262,14 @@ public:
ReExec() {} ReExec() {}
ReExec(int argc, char *argv[]); ReExec(int argc, char *argv[]);
void init(int argc, char *argv[]); void init(int argc, char *argv[]);
int atexit(void (*function)(void)) int atexit(void (*function)(void)) {
{
m_atexitfuncs.push(function); m_atexitfuncs.push(function);
return 0; return 0;
} }
void reexec(); void reexec();
const std::string& getreason() {return m_reason;} const std::string& getreason() {
return m_reason;
}
// Insert new args into the initial argv. idx designates the place // Insert new args into the initial argv. idx designates the place
// before which the new args are inserted (the default of 1 // before which the new args are inserted (the default of 1
// inserts after argv[0] which would probably be an appropriate // inserts after argv[0] which would probably be an appropriate

View file

@ -22,12 +22,16 @@
#endif #endif
#include <errno.h> #include <errno.h>
#include "safefcntl.h"
#include <sys/types.h> #include <sys/types.h>
#ifdef _WIN32
#include "safefcntl.h"
#include "safesysstat.h" #include "safesysstat.h"
#include "safeunistd.h" #include "safeunistd.h"
#ifndef _WIN32 #else
#define O_BINARY 0 #define O_BINARY 0
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#endif #endif
#include <string> #include <string>
@ -41,8 +45,9 @@ public:
FileToString(string& data) : m_data(data) {} FileToString(string& data) : m_data(data) {}
string& m_data; string& m_data;
bool init(size_t size, string *reason) { bool init(size_t size, string *reason) {
if (size > 0) if (size > 0) {
m_data.reserve(size); m_data.reserve(size);
}
return true; return true;
} }
bool data(const char *buf, int cnt, string *reason) { bool data(const char *buf, int cnt, string *reason) {
@ -141,25 +146,29 @@ bool file_scan(const string &fn, FileScanDo* doer, off_t startoffs,
catstrerror(reason, "read", errno); catstrerror(reason, "read", errno);
goto out; goto out;
} }
if (n == 0) if (n == 0) {
break; break;
}
curoffs += n; curoffs += n;
if (curoffs - n < startoffs) if (curoffs - n < startoffs) {
continue; continue;
}
if (!doer->data(buf, n, reason)) { if (!doer->data(buf, n, reason)) {
goto out; goto out;
} }
totread += n; totread += n;
if (cnttoread > 0 && totread >= cnttoread) if (cnttoread > 0 && totread >= cnttoread) {
break; break;
} }
}
ret = true; ret = true;
out: out:
if (fd >= 0 && !noclosing) if (fd >= 0 && !noclosing) {
close(fd); close(fd);
}
return ret; return ret;
} }
@ -184,8 +193,7 @@ class myCB : public FsTreeWalkerCB {
public: public:
FsTreeWalker::Status processone(const string& path, FsTreeWalker::Status processone(const string& path,
const struct stat *st, const struct stat *st,
FsTreeWalker::CbFlag flg) FsTreeWalker::CbFlag flg) {
{
if (flg == FsTreeWalker::FtwDirEnter) { if (flg == FsTreeWalker::FtwDirEnter) {
//cout << "[Entering " << path << "]" << endl; //cout << "[Entering " << path << "]" << endl;
} else if (flg == FsTreeWalker::FtwDirReturn) { } else if (flg == FsTreeWalker::FtwDirReturn) {
@ -228,29 +236,48 @@ int main(int argc, const char **argv)
off_t offs = 0; off_t offs = 0;
size_t cnt = size_t(-1); size_t cnt = size_t(-1);
thisprog = argv[0]; thisprog = argv[0];
argc--; argv++; argc--;
argv++;
while (argc > 0 && **argv == '-') { while (argc > 0 && **argv == '-') {
(*argv)++; (*argv)++;
if (!(**argv)) if (!(**argv))
/* Cas du "adb - core" */ /* Cas du "adb - core" */
{
Usage(); Usage();
}
while (**argv) while (**argv)
switch (*(*argv)++) { switch (*(*argv)++) {
case 'c': op_flags |= OPT_c; if (argc < 2) Usage(); case 'c':
cnt = atoll(*(++argv)); argc--; op_flags |= OPT_c;
goto b1; if (argc < 2) {
case 'o': op_flags |= OPT_o; if (argc < 2) Usage(); Usage();
offs = strtoull(*(++argv), 0, 0); argc--;
goto b1;
default: Usage(); break;
} }
b1: argc--; argv++; cnt = atoll(*(++argv));
argc--;
goto b1;
case 'o':
op_flags |= OPT_o;
if (argc < 2) {
Usage();
}
offs = strtoull(*(++argv), 0, 0);
argc--;
goto b1;
default:
Usage();
break;
}
b1:
argc--;
argv++;
} }
if (argc != 1) if (argc != 1) {
Usage(); Usage();
string top = *argv++;argc--; }
string top = *argv++;
argc--;
cerr << "filename " << top << " offs " << offs << " cnt " << cnt << endl; cerr << "filename " << top << " offs " << offs << " cnt " << cnt << endl;
struct stat st; struct stat st;
@ -262,8 +289,9 @@ int main(int argc, const char **argv)
FsTreeWalker walker; FsTreeWalker walker;
myCB cb; myCB cb;
walker.walk(top, cb); walker.walk(top, cb);
if (walker.getErrCnt() > 0) if (walker.getErrCnt() > 0) {
cout << walker.getReason(); cout << walker.getReason();
}
} else { } else {
string s, reason; string s, reason;
if (!file_to_string(top, s, offs, cnt, &reason)) { if (!file_to_string(top, s, offs, cnt, &reason)) {