execmd uses netcon

This commit is contained in:
dockes 2009-09-26 09:30:17 +00:00
parent 29dd3fdf3d
commit 6f483ea1dd
6 changed files with 190 additions and 150 deletions

View File

@ -6,8 +6,8 @@ LIBS = librcl.a
all: $(LIBS)
OBJS = rclaspell.o rclconfig.o rclinit.o textsplit.o unacpp.o csguess.o indexer.o mimetype.o htmlparse.o myhtmlparse.o mimehandler.o internfile.o mh_exec.o mh_html.o mh_mail.o mh_mbox.o mh_text.o docseq.o docseqdb.o docseqhist.o filtseq.o history.o plaintorich.o recollq.o reslistpager.o sortseq.o wasastringtoquery.o wasatorcl.o rcldb.o rcldoc.o rclquery.o searchdata.o stemdb.o stoplist.o base64.o conftree.o copyfile.o debuglog.o execmd.o fstreewalk.o idfile.o fileudi.o md5.o mimeparse.o pathut.o pxattr.o readfile.o smallut.o transcode.o wipedir.o x11mon.o mime-getpart.o mime-parsefull.o mime-parseonlyheader.o mime-printbody.o mime-printdoc.o mime-printheader.o mime.o convert.o iodevice.o iofactory.o
DEPS = rclaspell.dep.stamp rclconfig.dep.stamp rclinit.dep.stamp textsplit.dep.stamp unacpp.dep.stamp csguess.dep.stamp indexer.dep.stamp mimetype.dep.stamp htmlparse.dep.stamp myhtmlparse.dep.stamp mimehandler.dep.stamp internfile.dep.stamp mh_exec.dep.stamp mh_html.dep.stamp mh_mail.dep.stamp mh_mbox.dep.stamp mh_text.dep.stamp docseq.dep.stamp docseqdb.dep.stamp docseqhist.dep.stamp filtseq.dep.stamp history.dep.stamp plaintorich.dep.stamp recollq.dep.stamp reslistpager.dep.stamp sortseq.dep.stamp wasastringtoquery.dep.stamp wasatorcl.dep.stamp rcldb.dep.stamp rcldoc.dep.stamp rclquery.dep.stamp searchdata.dep.stamp stemdb.dep.stamp stoplist.dep.stamp base64.dep.stamp conftree.dep.stamp copyfile.dep.stamp debuglog.dep.stamp execmd.dep.stamp fstreewalk.dep.stamp idfile.dep.stamp fileudi.dep.stamp md5.dep.stamp mimeparse.dep.stamp pathut.dep.stamp pxattr.dep.stamp readfile.dep.stamp smallut.dep.stamp transcode.dep.stamp wipedir.dep.stamp x11mon.dep.stamp mime-getpart.dep.stamp mime-parsefull.dep.stamp mime-parseonlyheader.dep.stamp mime-printbody.dep.stamp mime-printdoc.dep.stamp mime-printheader.dep.stamp mime.dep.stamp convert.dep.stamp iodevice.dep.stamp iofactory.dep.stamp
OBJS = rclaspell.o rclconfig.o rclinit.o textsplit.o unacpp.o csguess.o indexer.o mimetype.o htmlparse.o myhtmlparse.o mimehandler.o internfile.o mh_exec.o mh_html.o mh_mail.o mh_mbox.o mh_text.o docseq.o docseqdb.o docseqhist.o filtseq.o history.o plaintorich.o recollq.o reslistpager.o sortseq.o wasastringtoquery.o wasatorcl.o rcldb.o rcldoc.o rclquery.o searchdata.o stemdb.o stoplist.o base64.o conftree.o copyfile.o debuglog.o execmd.o fstreewalk.o idfile.o fileudi.o md5.o mimeparse.o netcon.o pathut.o pxattr.o readfile.o smallut.o transcode.o wipedir.o x11mon.o mime-getpart.o mime-parsefull.o mime-parseonlyheader.o mime-printbody.o mime-printdoc.o mime-printheader.o mime.o convert.o iodevice.o iofactory.o
DEPS = rclaspell.dep.stamp rclconfig.dep.stamp rclinit.dep.stamp textsplit.dep.stamp unacpp.dep.stamp csguess.dep.stamp indexer.dep.stamp mimetype.dep.stamp htmlparse.dep.stamp myhtmlparse.dep.stamp mimehandler.dep.stamp internfile.dep.stamp mh_exec.dep.stamp mh_html.dep.stamp mh_mail.dep.stamp mh_mbox.dep.stamp mh_text.dep.stamp docseq.dep.stamp docseqdb.dep.stamp docseqhist.dep.stamp filtseq.dep.stamp history.dep.stamp plaintorich.dep.stamp recollq.dep.stamp reslistpager.dep.stamp sortseq.dep.stamp wasastringtoquery.dep.stamp wasatorcl.dep.stamp rcldb.dep.stamp rcldoc.dep.stamp rclquery.dep.stamp searchdata.dep.stamp stemdb.dep.stamp stoplist.dep.stamp base64.dep.stamp conftree.dep.stamp copyfile.dep.stamp debuglog.dep.stamp execmd.dep.stamp fstreewalk.dep.stamp idfile.dep.stamp fileudi.dep.stamp md5.dep.stamp mimeparse.dep.stamp netcon.dep.stamp pathut.dep.stamp pxattr.dep.stamp readfile.dep.stamp smallut.dep.stamp transcode.dep.stamp wipedir.dep.stamp x11mon.dep.stamp mime-getpart.dep.stamp mime-parsefull.dep.stamp mime-parseonlyheader.dep.stamp mime-printbody.dep.stamp mime-printdoc.dep.stamp mime-printheader.dep.stamp mime.dep.stamp convert.dep.stamp iodevice.dep.stamp iofactory.dep.stamp
librcl.a : $(DEPS) $(OBJS) unac.o
ar ru librcl.a $(OBJS) unac.o
@ -103,6 +103,8 @@ md5.o : ../utils/md5.cpp
$(CXX) $(ALL_CXXFLAGS) -c ../utils/md5.cpp
mimeparse.o : ../utils/mimeparse.cpp
$(CXX) $(ALL_CXXFLAGS) -c ../utils/mimeparse.cpp
netcon.o : ../utils/netcon.cpp
$(CXX) $(ALL_CXXFLAGS) -c ../utils/netcon.cpp
pathut.o : ../utils/pathut.cpp
$(CXX) $(ALL_CXXFLAGS) -c ../utils/pathut.cpp
pxattr.o : ../utils/pxattr.cpp
@ -275,6 +277,9 @@ md5.dep.stamp : ../utils/md5.cpp
mimeparse.dep.stamp : ../utils/mimeparse.cpp
$(CXX) -M $(ALL_CXXFLAGS) ../utils/mimeparse.cpp > mimeparse.dep
touch mimeparse.dep.stamp
netcon.dep.stamp : ../utils/netcon.cpp
$(CXX) -M $(ALL_CXXFLAGS) ../utils/netcon.cpp > netcon.dep
touch netcon.dep.stamp
pathut.dep.stamp : ../utils/pathut.cpp
$(CXX) -M $(ALL_CXXFLAGS) ../utils/pathut.cpp > pathut.dep
touch pathut.dep.stamp
@ -340,6 +345,7 @@ include idfile.dep
include fileudi.dep
include md5.dep
include mimeparse.dep
include netcon.dep
include pathut.dep
include pxattr.dep
include readfile.dep

View File

@ -48,6 +48,7 @@ ${depth}/utils/idfile.cpp \
${depth}/utils/fileudi.cpp \
${depth}/utils/md5.cpp \
${depth}/utils/mimeparse.cpp \
${depth}/utils/netcon.cpp \
${depth}/utils/pathut.cpp \
${depth}/utils/pxattr.cpp \
${depth}/utils/readfile.cpp \

View File

@ -45,6 +45,7 @@ static char rcsid[] = "@(#$Id: execmd.cpp,v 1.27 2008-10-06 06:22:47 dockes Exp
#include "pathut.h"
#include "debuglog.h"
#include "smallut.h"
#include "netcon.h"
#ifndef NO_NAMESPACES
using namespace std;
@ -145,6 +146,8 @@ public:
close(m_parent->m_pipeout[0]);
if (m_parent->m_pipeout[1] >= 0)
close(m_parent->m_pipeout[1]);
m_parent->m_tocmd.release();
m_parent->m_fromcmd.release();
pthread_sigmask(SIG_UNBLOCK, &m_parent->m_blkcld, 0);
m_parent->reset();
}
@ -152,11 +155,10 @@ private:
ExecCmd *m_parent;
bool m_active;
};
ExecCmd::~ExecCmd()
{
{
ExecCmdRsrc(this);
}
ExecCmdRsrc(this);
}
int ExecCmd::startExec(const string &cmd, const list<string>& args,
@ -171,6 +173,8 @@ int ExecCmd::startExec(const string &cmd, const list<string>& args,
LOGDEB(("ExecCmd::startExec: (%d|%d) %s\n",
has_input, has_output, command.c_str()));
}
// The resource manager ensures resources are freed if we return early
ExecCmdRsrc e(this);
if (has_input && pipe(m_pipein) < 0) {
@ -202,128 +206,166 @@ int ExecCmd::startExec(const string &cmd, const list<string>& args,
if (has_input) {
close(m_pipein[0]);
m_pipein[0] = -1;
fcntl(m_pipein[1], F_SETFL, O_NONBLOCK);
NetconCli *iclicon = new NetconCli();
iclicon->setconn(m_pipein[1]);
m_tocmd = NetconP(iclicon);
m_pipein[1] = 0;
}
if (has_output) {
close(m_pipeout[1]);
m_pipeout[1] = -1;
fcntl(m_pipeout[0], F_SETFL, O_NONBLOCK);
NetconCli *oclicon = new NetconCli();
oclicon->setconn(m_pipeout[0]);
m_fromcmd = NetconP(oclicon);
m_pipeout[0] = -1;
}
/* Don't want to undo what we just did ! */
e.inactivate();
return 0;
}
// Netcon callback. Send data to the command's input
class ExecWriter : public NetconWorker {
public:
ExecWriter(const string *input, ExecCmdProvide *provide)
: m_input(input), m_cnt(0), m_provide(provide)
{}
virtual int data(NetconData *con, Netcon::Event reason)
{
if (!m_input) return -1;
LOGDEB(("ExecWriter: input m_cnt %d input length %d\n", m_cnt,
m_input->length()));
if (m_cnt >= m_input->length()) {
// Fd ready for more but we got none.
if (m_provide) {
m_provide->newData();
if (m_input->empty()) {
return 0;
} else {
m_cnt = 0;
}
LOGDEB2(("ExecWriter: provide m_cnt %d input length %d\n",
m_cnt, m_input->length()));
} else {
return 0;
}
}
int ret = con->send(m_input->c_str() + m_cnt,
m_input->length() - m_cnt);
LOGDEB2(("ExecWriter: wrote %d to command\n", ret));
if (ret <= 0) {
LOGERR(("ExecWriter: data: can't write\n"));
return -1;
}
m_cnt += ret;
return ret;
}
private:
const string *m_input;
unsigned int m_cnt; // Current offset inside m_input
ExecCmdProvide *m_provide;
};
// Netcon callback. Get data from the command output.
class ExecReader : public NetconWorker {
public:
ExecReader(string *output, ExecCmdAdvise *advise)
: m_output(output), m_advise(advise)
{}
virtual int data(NetconData *con, Netcon::Event reason)
{
char buf[8192];
int n = con->receive(buf, 8192);
LOGDEB(("ExecReader: got %d from command\n", n));
if (n < 0) {
LOGERR(("ExecCmd::doexec: receive failed. errno %d\n", errno));
} else if (n > 0) {
m_output->append(buf, n);
if (m_advise)
m_advise->newData(n);
} // else n == 0, just return
return n;
}
private:
string *m_output;
ExecCmdAdvise *m_advise;
};
int ExecCmd::doexec(const string &cmd, const list<string>& args,
const string *inputstring, string *output)
const string *input, string *output)
{
if (startExec(cmd, args, inputstring != 0, output != 0) < 0) {
if (startExec(cmd, args, input != 0, output != 0) < 0) {
return -1;
}
// Need something to take note of my own errors (apart from the command's)
bool haderror = false;
const char *input = inputstring ? inputstring->data() : 0;
unsigned int inputlen = inputstring ? inputstring->length() : 0;
// Cleanup in case we return early
ExecCmdRsrc e(this);
int ret = 0;
if (input || output) {
unsigned int nwritten = 0;
int nfds = MAX(m_pipein[1], m_pipeout[0]) + 1;
fd_set readfds, writefds;
struct timeval tv;
tv.tv_sec = m_timeoutMs / 1000;
tv.tv_usec = 1000 * (m_timeoutMs % 1000);
for(; nfds > 0;) {
if (m_cancelRequest)
break;
// Setup output
if (output) {
NetconCli *oclicon = dynamic_cast<NetconCli *>(m_fromcmd.getptr());
if (!oclicon) {
LOGERR(("ExecCmd::doexec: no connection from command\n"));
return -1;
}
oclicon->setcallback(RefCntr<NetconWorker>
(new ExecReader(output, m_advise)));
Netcon::addselcon(m_fromcmd, Netcon::NETCONPOLL_READ);
// Give up ownership
m_fromcmd.release();
}
// Setup input
if (input) {
NetconCli *iclicon = dynamic_cast<NetconCli *>(m_tocmd.getptr());
if (!iclicon) {
LOGERR(("ExecCmd::doexec: no connection from command\n"));
return -1;
}
iclicon->setcallback(RefCntr<NetconWorker>
(new ExecWriter(input, m_provide)));
Netcon::addselcon(m_tocmd, Netcon::NETCONPOLL_WRITE);
// Give up ownership
m_tocmd.release();
}
FD_ZERO(&writefds);
FD_ZERO(&readfds);
if (m_pipein[1] >= 0)
FD_SET(m_pipein[1], &writefds);
if (m_pipeout[0] >= 0)
FD_SET(m_pipeout[0], &readfds);
nfds = MAX(m_pipein[1], m_pipeout[0]) + 1;
//struct timeval to; to.tv_sec = 1;to.tv_usec=0;
//cerr << "m_pipein[1] "<< m_pipein[1] << " m_pipeout[0] " <<
//m_pipeout[0] << " nfds " << nfds << endl;
int ss;
if ((ss = select(nfds, &readfds, &writefds, 0, &tv)) <= 0) {
if (ss == 0) {
// Timeout, is ok.
if (m_advise)
m_advise->newData(0);
continue;
}
LOGERR(("ExecCmd::doexec: select(2) failed. errno %d\n",
errno));
haderror = true;
// Do the actual reading/writing/waiting
Netcon::setperiodichandler(0, 0, m_timeoutMs);
while ((ret = Netcon::selectloop()) > 0) {
LOGDEB(("ExecCmd::doexec: selectloop returned %d\n", ret));
if (m_advise)
m_advise->newData(0);
if (m_cancelRequest) {
LOGINFO(("ExecCmd::doexec: cancel request\n"));
break;
}
if (m_pipein[1] >= 0 && FD_ISSET(m_pipein[1], &writefds)) {
int n = write(m_pipein[1], input + nwritten,
inputlen - nwritten);
if (n < 0) {
LOGERR(("ExecCmd::doexec: write(2) failed. errno %d\n",
errno));
haderror = true;
goto out;
}
nwritten += n;
if (nwritten == inputlen) {
if (m_provide) {
m_provide->newData();
if (inputstring->empty()) {
close(m_pipein[1]);
m_pipein[1] = -1;
} else {
input = inputstring->data();
inputlen = inputstring->length();
nwritten = 0;
}
} else {
// cerr << "Closing output" << endl;
close(m_pipein[1]);
m_pipein[1] = -1;
}
}
}
if (m_pipeout[0] > 0 && FD_ISSET(m_pipeout[0], &readfds)) {
char buf[8192];
int n = read(m_pipeout[0], buf, 8192);
if (n == 0) {
goto out;
} else if (n < 0) {
LOGERR(("ExecCmd::doexec: read(2) failed. errno %d\n",
errno));
haderror = true;
goto out;
} else if (n > 0) {
// cerr << "READ: " << n << endl;
output->append(buf, n);
if (m_advise)
m_advise->newData(n);
}
}
}
LOGDEB(("ExecCmd::doexec: selectloop returned %d\n", ret));
}
out:
// Normal return: deactivate cleaner, wait() will do the cleanup
e.inactivate();
return wait(haderror);
return ExecCmd::wait(ret);
}
int ExecCmd::send(const string& data)
{
NetconCli *con = dynamic_cast<NetconCli *>(m_tocmd.getptr());
if (con == 0) {
LOGERR(("ExecCmd::send: outpipe is closed\n"));
return -1;
}
unsigned int nwritten = 0;
while (nwritten < data.length()) {
if (m_cancelRequest)
break;
int n = write(m_pipein[1], data.c_str() + nwritten,
data.length() - nwritten);
int n = con->send(data.c_str() + nwritten, data.length() - nwritten);
if (n < 0) {
LOGERR(("ExecCmd::doexec: write(2) failed. errno %d\n", errno));
LOGERR(("ExecCmd::doexec: send failed\n"));
return -1;
}
nwritten += n;
@ -333,51 +375,29 @@ int ExecCmd::send(const string& data)
int ExecCmd::receive(string& data)
{
if (m_pipeout[0] < 0) {
LOGERR(("ExecCmd::receive: pipe is closed\n"));
return -1;
}
int nfds = m_pipeout[0] + 1;
fd_set readfds;
struct timeval tv;
tv.tv_sec = m_timeoutMs / 1000;
tv.tv_usec = 1000 * (m_timeoutMs % 1000);
FD_ZERO(&readfds);
FD_SET(m_pipeout[0], &readfds);
int ss;
if ((ss = select(nfds, &readfds, 0, 0, &tv)) <= 0) {
if (ss == 0) {
// timeout
return 0;
}
LOGERR(("ExecCmd::receive: select(2) failed. errno %d\n", errno));
return -1;
}
if (!FD_ISSET(m_pipeout[0], &readfds)) {
LOGERR(("ExecCmd::receive: fd not ready after select ??\n"));
NetconCli *con = dynamic_cast<NetconCli *>(m_fromcmd.getptr());
if (con == 0) {
LOGERR(("ExecCmd::receive: outpipe is closed\n"));
return -1;
}
char buf[8192];
int n = read(m_pipeout[0], buf, 8192);
if (n == 0) {
return 0;
} else if (n < 0) {
LOGERR(("ExecCmd::doexec: read(2) failed. errno %d\n", errno));
return -1;
} else {
// cerr << "READ: " << n << endl;
data.assign(buf, n);
int n = con->receive(buf, 8192);
if (n < 0) {
LOGERR(("ExecCmd::receive: error\n"));
} else if (n > 0) {
data.append(buf, n);
}
return n;
}
// Wait for command status and clean up all resources.
int ExecCmd::wait(bool haderror)
{
ExecCmdRsrc e(this);
int status = -1;
if (!m_cancelRequest) {
(void)waitpid(m_pid, &status, 0);
if (waitpid(m_pid, &status, 0) < 0)
status = -1;
m_pid = -1;
}
LOGDEB(("ExecCmd::wait: got status 0x%x\n", status));
@ -479,11 +499,23 @@ using namespace std;
#include "execmd.h"
static int op_flags;
#define OPT_MOINS 0x1
#define OPT_b 0x4
#define OPT_w 0x8
#define OPT_c 0x10
const char *data = "Une ligne de donnees\n";
class MEAdv : public ExecCmdAdvise {
public:
ExecCmd *cmd;
void newData(int cnt) {
if (op_flags & OPT_c) {
static int callcnt;
if (callcnt++ == 3) {
throw CancelExcept();
}
}
cerr << "newData(" << cnt << ")" << endl;
// CancelCheck::instance().setCancel();
// CancelCheck::instance().checkCancel();
@ -517,8 +549,9 @@ public:
static char *thisprog;
static char usage [] =
"execmd cmd [arg1 arg2 ...]\n"
" \n\n"
"trexecmd [-c] cmd [arg1 arg2 ...]\n"
" -c : test cancellation (ie: trexecmd -c sleep 1000)\n"
"trexecmd -w cmd : do the which thing\n"
;
static void Usage(void)
{
@ -526,14 +559,8 @@ static void Usage(void)
exit(1);
}
static int op_flags;
#define OPT_MOINS 0x1
#define OPT_s 0x2
#define OPT_b 0x4
#define OPT_w 0x8
int main(int argc, char **argv)
{
int count = 10;
thisprog = argv[0];
argc--; argv++;
@ -544,13 +571,8 @@ int main(int argc, char **argv)
Usage();
while (**argv)
switch (*(*argv)++) {
case 'b': op_flags |= OPT_b; if (argc < 2) Usage();
if ((sscanf(*(++argv), "%d", &count)) != 1)
Usage();
argc--;
goto b1;
case 's': op_flags |= OPT_s; break;
case 'w': op_flags |= OPT_w; break;
case 'c': op_flags |= OPT_c; break;
default: Usage(); break;
}
b1: argc--; argv++;
@ -567,7 +589,7 @@ int main(int argc, char **argv)
DebugLog::getdbl()->setloglevel(DEBDEB1);
DebugLog::setfilename("stderr");
signal(SIGPIPE, SIG_IGN);
if (op_flags & OPT_w) {
string path;
if (ExecCmd::which(cmd, path)) {
@ -580,7 +602,7 @@ int main(int argc, char **argv)
MEAdv adv;
adv.cmd = &mexec;
mexec.setAdvise(&adv);
mexec.setTimeout(500);
mexec.setTimeout(5);
mexec.setStderr("/tmp/trexecStderr");
mexec.putenv("TESTVARIABLE1=TESTVALUE1");
mexec.putenv("TESTVARIABLE2=TESTVALUE2");
@ -598,11 +620,11 @@ int main(int argc, char **argv)
try {
status = mexec.doexec(cmd, l, ip, &output);
} catch (CancelExcept) {
cerr << "CANCELED" << endl;
cerr << "CANCELLED" << endl;
}
fprintf(stderr, "Status: 0x%x\n", status);
cout << "Output:[" << output << "]" << endl;
cout << output;
exit (status >> 8);
}
#endif // TEST

View File

@ -27,12 +27,15 @@ using std::string;
using std::vector;
#endif
#include "netcon.h"
/**
* Callback function object to advise of new data arrival, or just periodic
* heartbeat if cnt is 0.
*
* The code using ExeCmd should raise an exception inside newData()
* (and catch it doexec's caller) to interrupt the command.
* To interrupt the command, the code using ExecCmd should either
* raise an exception inside newData() (and catch it in doexec's caller), or
* call ExecCmd::setCancel()
*
*/
class ExecCmdAdvise {
@ -75,7 +78,7 @@ class ExecCmd {
* Add/replace environment variable before executing command. This must
* be called before doexec() to have an effect (possibly multiple
* times for several variables).
* @param envassign an environment assignment string (name=value)
* @param envassign an environment assignment string ("name=value")
*/
void putenv(const string &envassign);
@ -124,6 +127,10 @@ class ExecCmd {
const string *input = 0,
string *output = 0);
/*
* The next four methods can be used when a Q/A dialog needs to be
* performed with the command
*/
int startExec(const string &cmd, const list<string>& args,
bool has_input, bool has_output);
int send(const string& data);
@ -152,8 +159,7 @@ class ExecCmd {
* @param path exec seach path to use instead of getenv(PATH)
* @return true if found
*/
static bool which(const string& cmd, string& exepath,
const char* path = 0);
static bool which(const string& cmd, string& exe, const char* path = 0);
friend class ExecCmdRsrc;
private:
@ -165,14 +171,17 @@ class ExecCmd {
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 execution state
// Reset internal state indicators. Any resources should have been
// previously freed
void reset() {
m_cancelRequest = false;
m_pipein[0] = m_pipein[1] = m_pipeout[0] = m_pipeout[1] = -1;

1
src/utils/netcon.cpp Symbolic link
View File

@ -0,0 +1 @@
../../../../docklib/netcon.cpp

1
src/utils/netcon.h Symbolic link
View File

@ -0,0 +1 @@
../../../../docklib/netcon.h