execmd uses netcon
This commit is contained in:
parent
29dd3fdf3d
commit
6f483ea1dd
@ -6,8 +6,8 @@ LIBS = librcl.a
|
|||||||
|
|
||||||
all: $(LIBS)
|
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
|
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 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
|
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
|
librcl.a : $(DEPS) $(OBJS) unac.o
|
||||||
ar ru librcl.a $(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
|
$(CXX) $(ALL_CXXFLAGS) -c ../utils/md5.cpp
|
||||||
mimeparse.o : ../utils/mimeparse.cpp
|
mimeparse.o : ../utils/mimeparse.cpp
|
||||||
$(CXX) $(ALL_CXXFLAGS) -c ../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
|
pathut.o : ../utils/pathut.cpp
|
||||||
$(CXX) $(ALL_CXXFLAGS) -c ../utils/pathut.cpp
|
$(CXX) $(ALL_CXXFLAGS) -c ../utils/pathut.cpp
|
||||||
pxattr.o : ../utils/pxattr.cpp
|
pxattr.o : ../utils/pxattr.cpp
|
||||||
@ -275,6 +277,9 @@ md5.dep.stamp : ../utils/md5.cpp
|
|||||||
mimeparse.dep.stamp : ../utils/mimeparse.cpp
|
mimeparse.dep.stamp : ../utils/mimeparse.cpp
|
||||||
$(CXX) -M $(ALL_CXXFLAGS) ../utils/mimeparse.cpp > mimeparse.dep
|
$(CXX) -M $(ALL_CXXFLAGS) ../utils/mimeparse.cpp > mimeparse.dep
|
||||||
touch mimeparse.dep.stamp
|
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
|
pathut.dep.stamp : ../utils/pathut.cpp
|
||||||
$(CXX) -M $(ALL_CXXFLAGS) ../utils/pathut.cpp > pathut.dep
|
$(CXX) -M $(ALL_CXXFLAGS) ../utils/pathut.cpp > pathut.dep
|
||||||
touch pathut.dep.stamp
|
touch pathut.dep.stamp
|
||||||
@ -340,6 +345,7 @@ include idfile.dep
|
|||||||
include fileudi.dep
|
include fileudi.dep
|
||||||
include md5.dep
|
include md5.dep
|
||||||
include mimeparse.dep
|
include mimeparse.dep
|
||||||
|
include netcon.dep
|
||||||
include pathut.dep
|
include pathut.dep
|
||||||
include pxattr.dep
|
include pxattr.dep
|
||||||
include readfile.dep
|
include readfile.dep
|
||||||
|
|||||||
@ -48,6 +48,7 @@ ${depth}/utils/idfile.cpp \
|
|||||||
${depth}/utils/fileudi.cpp \
|
${depth}/utils/fileudi.cpp \
|
||||||
${depth}/utils/md5.cpp \
|
${depth}/utils/md5.cpp \
|
||||||
${depth}/utils/mimeparse.cpp \
|
${depth}/utils/mimeparse.cpp \
|
||||||
|
${depth}/utils/netcon.cpp \
|
||||||
${depth}/utils/pathut.cpp \
|
${depth}/utils/pathut.cpp \
|
||||||
${depth}/utils/pxattr.cpp \
|
${depth}/utils/pxattr.cpp \
|
||||||
${depth}/utils/readfile.cpp \
|
${depth}/utils/readfile.cpp \
|
||||||
|
|||||||
@ -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 "pathut.h"
|
||||||
#include "debuglog.h"
|
#include "debuglog.h"
|
||||||
#include "smallut.h"
|
#include "smallut.h"
|
||||||
|
#include "netcon.h"
|
||||||
|
|
||||||
#ifndef NO_NAMESPACES
|
#ifndef NO_NAMESPACES
|
||||||
using namespace std;
|
using namespace std;
|
||||||
@ -145,6 +146,8 @@ public:
|
|||||||
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]);
|
||||||
|
m_parent->m_tocmd.release();
|
||||||
|
m_parent->m_fromcmd.release();
|
||||||
pthread_sigmask(SIG_UNBLOCK, &m_parent->m_blkcld, 0);
|
pthread_sigmask(SIG_UNBLOCK, &m_parent->m_blkcld, 0);
|
||||||
m_parent->reset();
|
m_parent->reset();
|
||||||
}
|
}
|
||||||
@ -152,11 +155,10 @@ private:
|
|||||||
ExecCmd *m_parent;
|
ExecCmd *m_parent;
|
||||||
bool m_active;
|
bool m_active;
|
||||||
};
|
};
|
||||||
|
|
||||||
ExecCmd::~ExecCmd()
|
ExecCmd::~ExecCmd()
|
||||||
{
|
{
|
||||||
{
|
ExecCmdRsrc(this);
|
||||||
ExecCmdRsrc(this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int ExecCmd::startExec(const string &cmd, const list<string>& args,
|
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",
|
LOGDEB(("ExecCmd::startExec: (%d|%d) %s\n",
|
||||||
has_input, has_output, command.c_str()));
|
has_input, has_output, command.c_str()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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_pipein) < 0) {
|
||||||
@ -202,128 +206,166 @@ int ExecCmd::startExec(const string &cmd, const list<string>& args,
|
|||||||
if (has_input) {
|
if (has_input) {
|
||||||
close(m_pipein[0]);
|
close(m_pipein[0]);
|
||||||
m_pipein[0] = -1;
|
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) {
|
if (has_output) {
|
||||||
close(m_pipeout[1]);
|
close(m_pipeout[1]);
|
||||||
m_pipeout[1] = -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();
|
e.inactivate();
|
||||||
|
|
||||||
return 0;
|
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,
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Need something to take note of my own errors (apart from the command's)
|
// Cleanup in case we return early
|
||||||
bool haderror = false;
|
|
||||||
const char *input = inputstring ? inputstring->data() : 0;
|
|
||||||
unsigned int inputlen = inputstring ? inputstring->length() : 0;
|
|
||||||
ExecCmdRsrc e(this);
|
ExecCmdRsrc e(this);
|
||||||
|
|
||||||
|
int ret = 0;
|
||||||
if (input || output) {
|
if (input || output) {
|
||||||
unsigned int nwritten = 0;
|
// Setup output
|
||||||
int nfds = MAX(m_pipein[1], m_pipeout[0]) + 1;
|
if (output) {
|
||||||
fd_set readfds, writefds;
|
NetconCli *oclicon = dynamic_cast<NetconCli *>(m_fromcmd.getptr());
|
||||||
struct timeval tv;
|
if (!oclicon) {
|
||||||
tv.tv_sec = m_timeoutMs / 1000;
|
LOGERR(("ExecCmd::doexec: no connection from command\n"));
|
||||||
tv.tv_usec = 1000 * (m_timeoutMs % 1000);
|
return -1;
|
||||||
for(; nfds > 0;) {
|
}
|
||||||
if (m_cancelRequest)
|
oclicon->setcallback(RefCntr<NetconWorker>
|
||||||
break;
|
(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);
|
// Do the actual reading/writing/waiting
|
||||||
FD_ZERO(&readfds);
|
Netcon::setperiodichandler(0, 0, m_timeoutMs);
|
||||||
if (m_pipein[1] >= 0)
|
while ((ret = Netcon::selectloop()) > 0) {
|
||||||
FD_SET(m_pipein[1], &writefds);
|
LOGDEB(("ExecCmd::doexec: selectloop returned %d\n", ret));
|
||||||
if (m_pipeout[0] >= 0)
|
if (m_advise)
|
||||||
FD_SET(m_pipeout[0], &readfds);
|
m_advise->newData(0);
|
||||||
nfds = MAX(m_pipein[1], m_pipeout[0]) + 1;
|
if (m_cancelRequest) {
|
||||||
//struct timeval to; to.tv_sec = 1;to.tv_usec=0;
|
LOGINFO(("ExecCmd::doexec: cancel request\n"));
|
||||||
//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;
|
|
||||||
break;
|
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();
|
e.inactivate();
|
||||||
return wait(haderror);
|
|
||||||
|
return ExecCmd::wait(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ExecCmd::send(const string& data)
|
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;
|
unsigned int nwritten = 0;
|
||||||
while (nwritten < data.length()) {
|
while (nwritten < data.length()) {
|
||||||
if (m_cancelRequest)
|
if (m_cancelRequest)
|
||||||
break;
|
break;
|
||||||
int n = write(m_pipein[1], data.c_str() + nwritten,
|
int n = con->send(data.c_str() + nwritten, data.length() - nwritten);
|
||||||
data.length() - nwritten);
|
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
LOGERR(("ExecCmd::doexec: write(2) failed. errno %d\n", errno));
|
LOGERR(("ExecCmd::doexec: send failed\n"));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
nwritten += n;
|
nwritten += n;
|
||||||
@ -333,51 +375,29 @@ int ExecCmd::send(const string& data)
|
|||||||
|
|
||||||
int ExecCmd::receive(string& data)
|
int ExecCmd::receive(string& data)
|
||||||
{
|
{
|
||||||
if (m_pipeout[0] < 0) {
|
NetconCli *con = dynamic_cast<NetconCli *>(m_fromcmd.getptr());
|
||||||
LOGERR(("ExecCmd::receive: pipe is closed\n"));
|
if (con == 0) {
|
||||||
return -1;
|
LOGERR(("ExecCmd::receive: outpipe is closed\n"));
|
||||||
}
|
|
||||||
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"));
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
char buf[8192];
|
char buf[8192];
|
||||||
int n = read(m_pipeout[0], buf, 8192);
|
int n = con->receive(buf, 8192);
|
||||||
if (n == 0) {
|
if (n < 0) {
|
||||||
return 0;
|
LOGERR(("ExecCmd::receive: error\n"));
|
||||||
} else if (n < 0) {
|
} else if (n > 0) {
|
||||||
LOGERR(("ExecCmd::doexec: read(2) failed. errno %d\n", errno));
|
data.append(buf, n);
|
||||||
return -1;
|
|
||||||
} else {
|
|
||||||
// cerr << "READ: " << n << endl;
|
|
||||||
data.assign(buf, n);
|
|
||||||
}
|
}
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Wait for command status and clean up all resources.
|
||||||
int ExecCmd::wait(bool haderror)
|
int ExecCmd::wait(bool haderror)
|
||||||
{
|
{
|
||||||
ExecCmdRsrc e(this);
|
ExecCmdRsrc e(this);
|
||||||
int status = -1;
|
int status = -1;
|
||||||
if (!m_cancelRequest) {
|
if (!m_cancelRequest) {
|
||||||
(void)waitpid(m_pid, &status, 0);
|
if (waitpid(m_pid, &status, 0) < 0)
|
||||||
|
status = -1;
|
||||||
m_pid = -1;
|
m_pid = -1;
|
||||||
}
|
}
|
||||||
LOGDEB(("ExecCmd::wait: got status 0x%x\n", status));
|
LOGDEB(("ExecCmd::wait: got status 0x%x\n", status));
|
||||||
@ -479,11 +499,23 @@ using namespace std;
|
|||||||
|
|
||||||
#include "execmd.h"
|
#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";
|
const char *data = "Une ligne de donnees\n";
|
||||||
class MEAdv : public ExecCmdAdvise {
|
class MEAdv : public ExecCmdAdvise {
|
||||||
public:
|
public:
|
||||||
ExecCmd *cmd;
|
ExecCmd *cmd;
|
||||||
void newData(int cnt) {
|
void newData(int cnt) {
|
||||||
|
if (op_flags & OPT_c) {
|
||||||
|
static int callcnt;
|
||||||
|
if (callcnt++ == 3) {
|
||||||
|
throw CancelExcept();
|
||||||
|
}
|
||||||
|
}
|
||||||
cerr << "newData(" << cnt << ")" << endl;
|
cerr << "newData(" << cnt << ")" << endl;
|
||||||
// CancelCheck::instance().setCancel();
|
// CancelCheck::instance().setCancel();
|
||||||
// CancelCheck::instance().checkCancel();
|
// CancelCheck::instance().checkCancel();
|
||||||
@ -517,8 +549,9 @@ public:
|
|||||||
|
|
||||||
static char *thisprog;
|
static char *thisprog;
|
||||||
static char usage [] =
|
static char usage [] =
|
||||||
"execmd cmd [arg1 arg2 ...]\n"
|
"trexecmd [-c] cmd [arg1 arg2 ...]\n"
|
||||||
" \n\n"
|
" -c : test cancellation (ie: trexecmd -c sleep 1000)\n"
|
||||||
|
"trexecmd -w cmd : do the which thing\n"
|
||||||
;
|
;
|
||||||
static void Usage(void)
|
static void Usage(void)
|
||||||
{
|
{
|
||||||
@ -526,14 +559,8 @@ static void Usage(void)
|
|||||||
exit(1);
|
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 main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int count = 10;
|
|
||||||
thisprog = argv[0];
|
thisprog = argv[0];
|
||||||
argc--; argv++;
|
argc--; argv++;
|
||||||
|
|
||||||
@ -544,13 +571,8 @@ int main(int argc, char **argv)
|
|||||||
Usage();
|
Usage();
|
||||||
while (**argv)
|
while (**argv)
|
||||||
switch (*(*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 'w': op_flags |= OPT_w; break;
|
||||||
|
case 'c': op_flags |= OPT_c; break;
|
||||||
default: Usage(); break;
|
default: Usage(); break;
|
||||||
}
|
}
|
||||||
b1: argc--; argv++;
|
b1: argc--; argv++;
|
||||||
@ -567,7 +589,7 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
DebugLog::getdbl()->setloglevel(DEBDEB1);
|
DebugLog::getdbl()->setloglevel(DEBDEB1);
|
||||||
DebugLog::setfilename("stderr");
|
DebugLog::setfilename("stderr");
|
||||||
|
signal(SIGPIPE, SIG_IGN);
|
||||||
if (op_flags & OPT_w) {
|
if (op_flags & OPT_w) {
|
||||||
string path;
|
string path;
|
||||||
if (ExecCmd::which(cmd, path)) {
|
if (ExecCmd::which(cmd, path)) {
|
||||||
@ -580,7 +602,7 @@ int main(int argc, char **argv)
|
|||||||
MEAdv adv;
|
MEAdv adv;
|
||||||
adv.cmd = &mexec;
|
adv.cmd = &mexec;
|
||||||
mexec.setAdvise(&adv);
|
mexec.setAdvise(&adv);
|
||||||
mexec.setTimeout(500);
|
mexec.setTimeout(5);
|
||||||
mexec.setStderr("/tmp/trexecStderr");
|
mexec.setStderr("/tmp/trexecStderr");
|
||||||
mexec.putenv("TESTVARIABLE1=TESTVALUE1");
|
mexec.putenv("TESTVARIABLE1=TESTVALUE1");
|
||||||
mexec.putenv("TESTVARIABLE2=TESTVALUE2");
|
mexec.putenv("TESTVARIABLE2=TESTVALUE2");
|
||||||
@ -598,11 +620,11 @@ int main(int argc, char **argv)
|
|||||||
try {
|
try {
|
||||||
status = mexec.doexec(cmd, l, ip, &output);
|
status = mexec.doexec(cmd, l, ip, &output);
|
||||||
} catch (CancelExcept) {
|
} catch (CancelExcept) {
|
||||||
cerr << "CANCELED" << endl;
|
cerr << "CANCELLED" << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(stderr, "Status: 0x%x\n", status);
|
fprintf(stderr, "Status: 0x%x\n", status);
|
||||||
cout << "Output:[" << output << "]" << endl;
|
cout << output;
|
||||||
exit (status >> 8);
|
exit (status >> 8);
|
||||||
}
|
}
|
||||||
#endif // TEST
|
#endif // TEST
|
||||||
|
|||||||
@ -27,12 +27,15 @@ using std::string;
|
|||||||
using std::vector;
|
using std::vector;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#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.
|
||||||
*
|
*
|
||||||
* The code using ExeCmd should raise an exception inside newData()
|
* To interrupt the command, the code using ExecCmd should either
|
||||||
* (and catch it doexec's caller) to interrupt the command.
|
* raise an exception inside newData() (and catch it in doexec's caller), or
|
||||||
|
* call ExecCmd::setCancel()
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class ExecCmdAdvise {
|
class ExecCmdAdvise {
|
||||||
@ -75,7 +78,7 @@ class ExecCmd {
|
|||||||
* Add/replace environment variable before executing command. This must
|
* Add/replace environment variable before executing command. This must
|
||||||
* be called before doexec() to have an effect (possibly multiple
|
* be called before doexec() to have an effect (possibly multiple
|
||||||
* times for several variables).
|
* 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);
|
void putenv(const string &envassign);
|
||||||
|
|
||||||
@ -124,6 +127,10 @@ class ExecCmd {
|
|||||||
const string *input = 0,
|
const string *input = 0,
|
||||||
string *output = 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,
|
int startExec(const string &cmd, const list<string>& args,
|
||||||
bool has_input, bool has_output);
|
bool has_input, bool has_output);
|
||||||
int send(const string& data);
|
int send(const string& data);
|
||||||
@ -152,8 +159,7 @@ class ExecCmd {
|
|||||||
* @param path exec seach path to use instead of getenv(PATH)
|
* @param path exec seach path to use instead of getenv(PATH)
|
||||||
* @return true if found
|
* @return true if found
|
||||||
*/
|
*/
|
||||||
static bool which(const string& cmd, string& exepath,
|
static bool which(const string& cmd, string& exe, const char* path = 0);
|
||||||
const char* path = 0);
|
|
||||||
|
|
||||||
friend class ExecCmdRsrc;
|
friend class ExecCmdRsrc;
|
||||||
private:
|
private:
|
||||||
@ -165,14 +171,17 @@ class ExecCmd {
|
|||||||
string m_stderrFile;
|
string m_stderrFile;
|
||||||
// Pipe for data going to the command
|
// Pipe for data going to the command
|
||||||
int m_pipein[2];
|
int m_pipein[2];
|
||||||
|
NetconP m_tocmd;
|
||||||
// Pipe for data coming out
|
// Pipe for data coming out
|
||||||
int m_pipeout[2];
|
int m_pipeout[2];
|
||||||
|
NetconP m_fromcmd;
|
||||||
// Subprocess id
|
// Subprocess id
|
||||||
pid_t m_pid;
|
pid_t m_pid;
|
||||||
// Saved sigmask
|
// Saved sigmask
|
||||||
sigset_t m_blkcld;
|
sigset_t m_blkcld;
|
||||||
|
|
||||||
// Reset internal execution state
|
// Reset internal state indicators. Any resources should have been
|
||||||
|
// previously freed
|
||||||
void reset() {
|
void reset() {
|
||||||
m_cancelRequest = false;
|
m_cancelRequest = false;
|
||||||
m_pipein[0] = m_pipein[1] = m_pipeout[0] = m_pipeout[1] = -1;
|
m_pipein[0] = m_pipein[1] = m_pipeout[0] = m_pipeout[1] = -1;
|
||||||
|
|||||||
1
src/utils/netcon.cpp
Symbolic link
1
src/utils/netcon.cpp
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../../../../docklib/netcon.cpp
|
||||||
1
src/utils/netcon.h
Symbolic link
1
src/utils/netcon.h
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../../../../docklib/netcon.h
|
||||||
Loading…
x
Reference in New Issue
Block a user