Added ExecCmd::which + fix member variable names

--HG--
branch : WINDOWSPORT
This commit is contained in:
Jean-Francois Dockes 2015-09-09 09:00:20 +02:00
parent e0dbadddc2
commit 40671020e4
4 changed files with 205 additions and 95 deletions

View File

@ -202,7 +202,11 @@ RclConfig *recollinit(RclInitFlags flags,
// Init smallut and pathut static values // Init smallut and pathut static values
pathut_init_mt(); pathut_init_mt();
smallut_init_mt(); smallut_init_mt();
// Init execmd.h static PATH and PATHELT splitting
{string bogus;
ExecCmd::which("nosuchcmd", bogus);
}
// Init Unac translation exceptions // Init Unac translation exceptions
string unacex; string unacex;
if (config->getConfParam("unac_except_trans", unacex) && !unacex.empty()) if (config->getConfParam("unac_except_trans", unacex) && !unacex.empty())

View File

@ -373,20 +373,29 @@ bool TempDir::wipe()
return true; return true;
} }
void path_catslash(string &s) { void path_catslash(string &s)
{
#ifdef WIN32
path_slashize(s);
#endif
if (s.empty() || s[s.length() - 1] != '/') if (s.empty() || s[s.length() - 1] != '/')
s += '/'; s += '/';
} }
string path_cat(const string &s1, const string &s2) { string path_cat(const string &s1, const string &s2)
{
string res = s1; string res = s1;
path_catslash(res); path_catslash(res);
res += s2; res += s2;
return res; return res;
} }
string path_getfather(const string &s) { string path_getfather(const string &s)
{
string father = s; string father = s;
#ifdef WIN32
path_slashize(father);
#endif
// ?? // ??
if (father.empty()) if (father.empty())
@ -409,8 +418,12 @@ string path_getfather(const string &s) {
return father; return father;
} }
string path_getsimple(const string &s) { string path_getsimple(const string &s)
{
string simple = s; string simple = s;
#ifdef WIN32
path_slashize(simple);
#endif
if (simple.empty()) if (simple.empty())
return simple; return simple;
@ -508,6 +521,10 @@ string path_tildexpand(const string &s)
if (s.empty() || s[0] != '~') if (s.empty() || s[0] != '~')
return s; return s;
string o = s; string o = s;
#ifdef WIN32
path_slashize(o);
#endif
if (s.length() == 1) { if (s.length() == 1) {
o.replace(0, 1, path_home()); o.replace(0, 1, path_home());
} else if (s[1] == '/') { } else if (s[1] == '/') {
@ -532,7 +549,8 @@ bool path_isroot(const string& path)
if (path.size() == 1 && path[0] == '/') if (path.size() == 1 && path[0] == '/')
return true; return true;
#ifdef _WIN32 #ifdef _WIN32
if (path.size() == 3 && isalpha(path[0]) && path[1] == ':' && path[2] == '/') if (path.size() == 3 && isalpha(path[0]) && path[1] == ':' &&
(path[2] == '/' || path[2] == '\\'))
return true; return true;
#endif #endif
return false; return false;
@ -555,12 +573,15 @@ string path_absolute(const string &is)
if (is.length() == 0) if (is.length() == 0)
return is; return is;
string s = is; string s = is;
if (s[0] != '/') { if (!path_isabsolute(s)) {
char buf[MAXPATHLEN]; char buf[MAXPATHLEN];
if (!getcwd(buf, MAXPATHLEN)) { if (!getcwd(buf, MAXPATHLEN)) {
return string(); return string();
} }
s = path_cat(string(buf), s); s = path_cat(string(buf), s);
#ifdef _WIN32
path_slashize(s);
#endif
} }
return s; return s;
} }

View File

@ -1,3 +1,4 @@
#include "autoconfig.h"
#include "execmd.h" #include "execmd.h"
@ -6,6 +7,10 @@
#include <string> #include <string>
#include "debuglog.h" #include "debuglog.h"
#include "safesysstat.h"
#include "safeunistd.h"
#include "smallut.h"
#include "pathut.h"
using namespace std; using namespace std;
@ -18,49 +23,50 @@ static void printError(const string& text)
class ExecCmd::Internal { class ExecCmd::Internal {
public: public:
Internal() Internal()
: advise(0), provide(0), timeoutMs(1000), : m_advise(0), m_provide(0), m_timeoutMs(1000),
hOutputRead(NULL), hInputWrite(NULL) { m_hOutputRead(NULL), m_hInputWrite(NULL) {
} }
std::vector<std::string> m_env; vector<string> m_env;
ExecCmdAdvise *advise; ExecCmdAdvise *m_advise;
ExecCmdProvide *provide; ExecCmdProvide *m_provide;
bool killRequest;
int timeoutMs; bool m_killRequest;
string stderrFile; int m_timeoutMs;
string m_stderrFile;
// Subprocess id // Subprocess id
HANDLE hOutputRead; HANDLE m_hOutputRead;
HANDLE hInputWrite; HANDLE m_hInputWrite;
OVERLAPPED oOutputRead; // Do these need resource control? OVERLAPPED m_oOutputRead; // Do these need resource control?
OVERLAPPED oInputWrite; OVERLAPPED m_oInputWrite;
PROCESS_INFORMATION piProcInfo; PROCESS_INFORMATION m_piProcInfo;
// Reset internal state indicators. Any resources should have been // Reset internal state indicators. Any resources should have been
// previously freed // previously freed
void reset() { void reset() {
killRequest = false; m_killRequest = false;
hOutputRead = NULL; m_hOutputRead = NULL;
hInputWrite = NULL; m_hInputWrite = NULL;
memset(&oOutputRead, 0, sizeof(oOutputRead)); memset(&m_oOutputRead, 0, sizeof(m_oOutputRead));
memset(&oInputWrite, 0, sizeof(oInputWrite)); memset(&m_oInputWrite, 0, sizeof(m_oInputWrite));
ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION)); ZeroMemory(&m_piProcInfo, sizeof(PROCESS_INFORMATION));
} }
void releaseResources() { void releaseResources() {
if (piProcInfo.hProcess) if (m_piProcInfo.hProcess)
CloseHandle(piProcInfo.hProcess); CloseHandle(m_piProcInfo.hProcess);
if (piProcInfo.hThread) if (m_piProcInfo.hThread)
CloseHandle(piProcInfo.hThread); CloseHandle(m_piProcInfo.hThread);
if (hOutputRead) if (m_hOutputRead)
CloseHandle(hOutputRead); CloseHandle(m_hOutputRead);
if (hInputWrite) if (m_hInputWrite)
CloseHandle(hInputWrite); CloseHandle(m_hInputWrite);
if (oOutputRead.hEvent) if (m_oOutputRead.hEvent)
CloseHandle(oOutputRead.hEvent); CloseHandle(m_oOutputRead.hEvent);
if (oInputWrite.hEvent) if (m_oInputWrite.hEvent)
CloseHandle(oInputWrite.hEvent); CloseHandle(m_oInputWrite.hEvent);
reset(); reset();
} }
bool PreparePipes(bool has_input, HANDLE *hChildInput, bool preparePipes(bool has_input, HANDLE *hChildInput,
bool has_output, HANDLE *hChildOutput, bool has_output, HANDLE *hChildOutput,
HANDLE *hChildError); HANDLE *hChildError);
}; };
@ -78,36 +84,111 @@ ExecCmd::~ExecCmd()
m->releaseResources(); m->releaseResources();
} }
// In mt programs the static vector computations below needs a call
// from main before going mt. This is done by rclinit and saves having
// to take a lock on every call
static bool is_exe(const string& path)
{
struct stat st;
if (access(path.c_str(), X_OK) == 0 && stat(path.c_str(), &st) == 0 &&
S_ISREG(st.st_mode)) {
return true;
}
return false;
}
static bool is_exe_base(const string& path)
{
static vector<string> exts;
if (exts.empty()) {
const char *ep = getenv("PATHEXT");
if (!ep || !*ep) {
ep = ".com;.exe;.bat;.cmd";
}
string eps(ep);
trimstring(eps, ";");
stringToTokens(eps, exts, ";");
}
if (is_exe(path))
return true;
for (auto it = exts.begin(); it != exts.end(); it++) {
if (is_exe(path + *it))
return true;
}
return false;
}
static void make_path_vec(const char *ep, vector<string>& vec)
{
if (ep && *ep) {
string eps(ep);
trimstring(eps, ";");
stringToTokens(eps, vec, ";");
}
vec.insert(vec.begin(), ".\\");
}
bool ExecCmd::which(const string& cmd, string& exe, const char* path) bool ExecCmd::which(const string& cmd, string& exe, const char* path)
{ {
static vector<string> s_pathelts;
vector<string> pathelts;
vector<string> *pep;
if (path) {
make_path_vec(path, pathelts);
pep = &pathelts;
} else {
if (s_pathelts.empty()) {
const char *ep = getenv("PATH");
make_path_vec(ep, s_pathelts);
}
pep = &s_pathelts;
}
if (cmd.find_first_of("/\\") != string::npos) {
if (is_exe_base(cmd)) {
exe = cmd;
return true;
}
exe.clear();
return false;
}
for (auto it = pep->begin(); it != pep->end(); it++) {
exe = path_cat(*it, cmd);
if (is_exe_base(exe)) {
return true;
}
}
exe.clear();
return false; return false;
} }
void ExecCmd::setAdvise(ExecCmdAdvise *adv) void ExecCmd::setAdvise(ExecCmdAdvise *adv)
{ {
m->advise = adv; m->m_advise = adv;
} }
void ExecCmd::setProvide(ExecCmdProvide *p) void ExecCmd::setProvide(ExecCmdProvide *p)
{ {
m->provide = p; m->m_provide = p;
} }
void ExecCmd::setTimeout(int mS) void ExecCmd::setTimeout(int mS)
{ {
if (mS > 30) { if (mS > 30) {
m->timeoutMs = mS; m->m_timeoutMs = mS;
} }
} }
void ExecCmd::setStderr(const std::string& stderrFile) void ExecCmd::setStderr(const std::string& stderrFile)
{ {
m->stderrFile = stderrFile; m->m_stderrFile = stderrFile;
} }
pid_t ExecCmd::getChildPid() pid_t ExecCmd::getChildPid()
{ {
return m->piProcInfo.dwProcessId; return m->m_piProcInfo.dwProcessId;
} }
void ExecCmd::setKill() void ExecCmd::setKill()
{ {
m->killRequest = true; m->m_killRequest = true;
} }
void ExecCmd::zapChild() void ExecCmd::zapChild()
{ {
@ -125,7 +206,7 @@ void ExecCmd::putenv(const string &name, const string& value)
} }
bool ExecCmd::Internal::PreparePipes(bool has_input,HANDLE *hChildInput, bool ExecCmd::Internal::preparePipes(bool has_input,HANDLE *hChildInput,
bool has_output, HANDLE *hChildOutput, bool has_output, HANDLE *hChildOutput,
HANDLE *hChildError) HANDLE *hChildError)
{ {
@ -134,22 +215,22 @@ bool ExecCmd::Internal::PreparePipes(bool has_input,HANDLE *hChildInput,
HANDLE hOutputWrite = NULL; HANDLE hOutputWrite = NULL;
HANDLE hErrorWrite = NULL; HANDLE hErrorWrite = NULL;
HANDLE hInputRead = NULL; HANDLE hInputRead = NULL;
hOutputRead = NULL; m_hOutputRead = NULL;
hInputWrite = NULL; m_hInputWrite = NULL;
memset(&oOutputRead, 0, sizeof(oOutputRead)); memset(&m_oOutputRead, 0, sizeof(m_oOutputRead));
memset(&oInputWrite, 0, sizeof(oInputWrite)); memset(&m_oInputWrite, 0, sizeof(m_oInputWrite));
// manual reset event // manual reset event
oOutputRead.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); m_oOutputRead.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (oOutputRead.hEvent == INVALID_HANDLE_VALUE) { if (m_oOutputRead.hEvent == INVALID_HANDLE_VALUE) {
LOGERR(("ExecCmd::PreparePipes: CreateEvent failed\n")); LOGERR(("ExecCmd::preparePipes: CreateEvent failed\n"));
goto errout; goto errout;
} }
// manual reset event // manual reset event
oInputWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); m_oInputWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (oInputWrite.hEvent == INVALID_HANDLE_VALUE) { if (m_oInputWrite.hEvent == INVALID_HANDLE_VALUE) {
LOGERR(("ExecCmd::PreparePipes: CreateEvent failed\n")); LOGERR(("ExecCmd::preparePipes: CreateEvent failed\n"));
goto errout; goto errout;
} }
@ -193,7 +274,6 @@ bool ExecCmd::Internal::PreparePipes(bool has_input,HANDLE *hChildInput,
printError("preparePipes: CreateFile(outputWrite)"); printError("preparePipes: CreateFile(outputWrite)");
goto errout; goto errout;
} }
// All is well? not quite. Our main server-side handle was // All is well? not quite. Our main server-side handle was
// created shareable. // created shareable.
// That means the client will receive it, and we have a // That means the client will receive it, and we have a
@ -205,7 +285,7 @@ bool ExecCmd::Internal::PreparePipes(bool has_input,HANDLE *hChildInput,
// the child inherits the properties and, as a result, // the child inherits the properties and, as a result,
// non-closeable handles to the pipes are created. // non-closeable handles to the pipes are created.
if (!DuplicateHandle(GetCurrentProcess(), hOutputReadTmp, if (!DuplicateHandle(GetCurrentProcess(), hOutputReadTmp,
GetCurrentProcess(), &hOutputRead, GetCurrentProcess(), &m_hOutputRead,
0, FALSE, // Make it uninheritable. 0, FALSE, // Make it uninheritable.
DUPLICATE_SAME_ACCESS)) { DUPLICATE_SAME_ACCESS)) {
printError("preparePipes: DuplicateHandle(readtmp->outputread)"); printError("preparePipes: DuplicateHandle(readtmp->outputread)");
@ -238,7 +318,7 @@ bool ExecCmd::Internal::PreparePipes(bool has_input,HANDLE *hChildInput,
// Stderr: output to file or inherit. We don't support the file thing // Stderr: output to file or inherit. We don't support the file thing
// for the moment // for the moment
if (false && !stderrFile.empty()) { if (false && !m_stderrFile.empty()) {
// Open the file set up the child handle: TBD // Open the file set up the child handle: TBD
} else { } else {
// Let the child inherit our standard input // Let the child inherit our standard input
@ -259,12 +339,12 @@ bool ExecCmd::Internal::PreparePipes(bool has_input,HANDLE *hChildInput,
if (has_input) { if (has_input) {
// now same procedure for input pipe // now same procedure for input pipe
HANDLE hInputWriteTmp = CreateNamedPipe( HANDLE m_hInputWriteTmp = CreateNamedPipe(
TEXT("\\\\.\\pipe\\instreamPipe"), TEXT("\\\\.\\pipe\\instreamPipe"),
PIPE_ACCESS_OUTBOUND | FILE_FLAG_OVERLAPPED, PIPE_ACCESS_OUTBOUND | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
1, 4096, 4096, 0, &sa); 1, 4096, 4096, 0, &sa);
if (hInputWriteTmp == INVALID_HANDLE_VALUE) { if (m_hInputWriteTmp == INVALID_HANDLE_VALUE) {
printError("preparePipes: CreateNamedPipe(inputWTmp)"); printError("preparePipes: CreateNamedPipe(inputWTmp)");
goto errout; goto errout;
} }
@ -280,18 +360,18 @@ bool ExecCmd::Internal::PreparePipes(bool has_input,HANDLE *hChildInput,
goto errout; goto errout;
} }
if (!DuplicateHandle(GetCurrentProcess(), hInputWriteTmp, if (!DuplicateHandle(GetCurrentProcess(), m_hInputWriteTmp,
GetCurrentProcess(), &hInputWrite, GetCurrentProcess(), &m_hInputWrite,
0, FALSE, // Make it uninheritable. 0, FALSE, // Make it uninheritable.
DUPLICATE_SAME_ACCESS)) { DUPLICATE_SAME_ACCESS)) {
printError("preparePipes: DuplicateHandle(inputWTmp->inputW)"); printError("preparePipes: DuplicateHandle(inputWTmp->inputW)");
goto errout; goto errout;
} }
if (!CloseHandle(hInputWriteTmp)) { if (!CloseHandle(m_hInputWriteTmp)) {
printError("preparePipes: CloseHandle(inputWTmp)"); printError("preparePipes: CloseHandle(inputWTmp)");
goto errout; goto errout;
} }
hInputWriteTmp = NULL; m_hInputWriteTmp = NULL;
} else { } else {
// Let the child inherit our standard input // Let the child inherit our standard input
HANDLE hstd = GetStdHandle(STD_INPUT_HANDLE); HANDLE hstd = GetStdHandle(STD_INPUT_HANDLE);
@ -412,7 +492,7 @@ int ExecCmd::startExec(const string &cmd, const vector<string>& args,
HANDLE hInputRead; HANDLE hInputRead;
HANDLE hOutputWrite; HANDLE hOutputWrite;
HANDLE hErrorWrite; HANDLE hErrorWrite;
if (!m->PreparePipes(has_input, &hInputRead, has_output, if (!m->preparePipes(has_input, &hInputRead, has_output,
&hOutputWrite, &hErrorWrite)) { &hOutputWrite, &hErrorWrite)) {
LOGERR(("ExecCmd::startExec: preparePipes failed\n")); LOGERR(("ExecCmd::startExec: preparePipes failed\n"));
m->releaseResources(); m->releaseResources();
@ -423,7 +503,7 @@ int ExecCmd::startExec(const string &cmd, const vector<string>& args,
BOOL bSuccess = FALSE; BOOL bSuccess = FALSE;
// Set up members of the PROCESS_INFORMATION structure. // Set up members of the PROCESS_INFORMATION structure.
ZeroMemory(&m->piProcInfo, sizeof(PROCESS_INFORMATION)); ZeroMemory(&m->m_piProcInfo, sizeof(PROCESS_INFORMATION));
// Set up members of the STARTUPINFO structure. // Set up members of the STARTUPINFO structure.
// This structure specifies the STDIN and STDOUT handles for redirection. // This structure specifies the STDIN and STDOUT handles for redirection.
@ -448,7 +528,7 @@ int ExecCmd::startExec(const string &cmd, const vector<string>& args,
NULL, // use parent's environment NULL, // use parent's environment
NULL, // use parent's current directory NULL, // use parent's current directory
&siStartInfo, // STARTUPINFO pointer &siStartInfo, // STARTUPINFO pointer
&m->piProcInfo); // receives PROCESS_INFORMATION &m->m_piProcInfo); // receives PROCESS_INFORMATION
if (!bSuccess) { if (!bSuccess) {
printError("ExecCmd::doexec: CreateProcess"); printError("ExecCmd::doexec: CreateProcess");
} else { } else {
@ -500,8 +580,8 @@ int ExecCmd::send(const string& data)
DWORD dwWritten; DWORD dwWritten;
BOOL bSuccess = false; BOOL bSuccess = false;
bSuccess = WriteFile(m->hInputWrite, data.c_str(), (DWORD)data.size(), bSuccess = WriteFile(m->m_hInputWrite, data.c_str(), (DWORD)data.size(),
NULL, &m->oInputWrite); NULL, &m->m_oInputWrite);
DWORD err = GetLastError(); DWORD err = GetLastError();
// TODO: some more decision, either the operation completes immediately // TODO: some more decision, either the operation completes immediately
@ -512,20 +592,20 @@ int ExecCmd::send(const string& data)
return -1; return -1;
} }
WaitResult waitRes = Wait(m->oInputWrite.hEvent, m->timeoutMs); WaitResult waitRes = Wait(m->m_oInputWrite.hEvent, m->m_timeoutMs);
if (waitRes == Ok) { if (waitRes == Ok) {
if (!GetOverlappedResult(m->hInputWrite, if (!GetOverlappedResult(m->m_hInputWrite,
&m->oInputWrite, &dwWritten, TRUE)) { &m->m_oInputWrite, &dwWritten, TRUE)) {
printError("GetOverlappedResult"); printError("GetOverlappedResult");
return -1; return -1;
} }
} else if (waitRes == Quit) { } else if (waitRes == Quit) {
if (!CancelIo(m->hInputWrite)) { if (!CancelIo(m->m_hInputWrite)) {
printError("CancelIo"); printError("CancelIo");
} }
return -1; return -1;
} else if (waitRes == Timeout) { } else if (waitRes == Timeout) {
if (!CancelIo(m->hInputWrite)) { if (!CancelIo(m->m_hInputWrite)) {
printError("CancelIo"); printError("CancelIo");
} }
return -1; return -1;
@ -549,8 +629,8 @@ int ExecCmd::receive(string& data, int cnt)
const int BUFSIZE = 8192; const int BUFSIZE = 8192;
CHAR chBuf[BUFSIZE]; CHAR chBuf[BUFSIZE];
int toread = cnt > 0 ? MIN(cnt - totread, BUFSIZE) : BUFSIZE; int toread = cnt > 0 ? MIN(cnt - totread, BUFSIZE) : BUFSIZE;
BOOL bSuccess = ReadFile(m->hOutputRead, chBuf, toread, BOOL bSuccess = ReadFile(m->m_hOutputRead, chBuf, toread,
NULL, &m->oOutputRead); NULL, &m->m_oOutputRead);
DWORD err = GetLastError(); DWORD err = GetLastError();
LOGDEB1(("receive: ReadFile: success %d err %d\n", LOGDEB1(("receive: ReadFile: success %d err %d\n",
int(bSuccess), int(err))); int(bSuccess), int(err)));
@ -559,35 +639,35 @@ int ExecCmd::receive(string& data, int cnt)
break; break;
} }
WaitResult waitRes = Wait(m->oOutputRead.hEvent, 1000); WaitResult waitRes = Wait(m->m_oOutputRead.hEvent, 1000);
if (waitRes == Ok) { if (waitRes == Ok) {
DWORD dwRead; DWORD dwRead;
if (!GetOverlappedResult(m->hOutputRead, &m->oOutputRead, if (!GetOverlappedResult(m->m_hOutputRead, &m->m_oOutputRead,
&dwRead, TRUE)) { &dwRead, TRUE)) {
printError("GetOverlappedResult"); printError("GetOverlappedResult");
return -1; return -1;
} }
totread += dwRead; totread += dwRead;
data.append(chBuf, dwRead); data.append(chBuf, dwRead);
if (m->advise) if (m->m_advise)
m->advise->newData(dwRead); m->m_advise->newData(dwRead);
LOGDEB(("ExecCmd::receive: got %d bytes\n", int(dwRead))); LOGDEB(("ExecCmd::receive: got %d bytes\n", int(dwRead)));
} else if (waitRes == Quit) { } else if (waitRes == Quit) {
if (!CancelIo(m->hOutputRead)) { if (!CancelIo(m->m_hOutputRead)) {
printError("CancelIo"); printError("CancelIo");
} }
break; break;
} else if (waitRes == Timeout) { } else if (waitRes == Timeout) {
// We only want to cancel if m_advise says so here. Is the io still // We only want to cancel if m_advise says so here. Is the io still
// valid at this point ? Should we catch a possible exception to CancelIo? // valid at this point ? Should we catch a possible exception to CancelIo?
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"));
if (!CancelIo(m->hOutputRead)) { if (!CancelIo(m->m_hOutputRead)) {
printError("CancelIo"); printError("CancelIo");
} }
break; break;
} }
} }
} }
@ -603,11 +683,11 @@ int ExecCmd::getline(std::string& data)
int ExecCmd::wait() int ExecCmd::wait()
{ {
// Wait until child process exits. // Wait until child process exits.
WaitForSingleObject(m->piProcInfo.hProcess, INFINITE); WaitForSingleObject(m->m_piProcInfo.hProcess, INFINITE);
// Get exit code // Get exit code
DWORD exit_code = 0; DWORD exit_code = 0;
GetExitCodeProcess(m->piProcInfo.hProcess, &exit_code); GetExitCodeProcess(m->m_piProcInfo.hProcess, &exit_code);
// Release all resources // Release all resources
m->releaseResources(); m->releaseResources();

View File

@ -27,9 +27,14 @@ using namespace std;
bool exercise_mhexecm(const string& cmdstr, const string& mimetype, bool exercise_mhexecm(const string& cmdstr, const string& mimetype,
vector<string>& files) vector<string>& files)
{ {
ExecCmd cmd; if (files.empty())
return false;
vector<string> myparams; ExecCmd cmd;
vector<string> myparams;
// Hack for windows: the command is always "Python somescript"
myparams.push_back(files[0]);
files.erase(files.begin());
if (cmd.startExec(cmdstr, myparams, 1, 1) < 0) { if (cmd.startExec(cmdstr, myparams, 1, 1) < 0) {
cerr << "startExec " << cmdstr << " failed. Missing command?\n"; cerr << "startExec " << cmdstr << " failed. Missing command?\n";
@ -228,7 +233,7 @@ int main(int argc, char *argv[])
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
cout << "MESSAGE " << i << " FROM TREXECMD\n"; cout << "MESSAGE " << i << " FROM TREXECMD\n";
cout.flush(); cout.flush();
sleep(1); //sleep(1);
} }
return 0; return 0;
default: Usage(); break; default: Usage(); break;