From ef4bb2f4cace797fb31d0adf3f78193a7d1c7b64 Mon Sep 17 00:00:00 2001 From: Jean-Francois Dockes Date: Tue, 8 Sep 2015 15:49:13 +0200 Subject: [PATCH] Windows: 'trexecmd -o env' sort of works, but waits for timeout at end of input --HG-- branch : WINDOWSPORT --- src/utils/execmd.h | 1 + src/utils/pathut.cpp | 2 +- src/windows/Win32ProjectRecoll.vcxproj | 3 +- .../Win32ProjectRecoll.vcxproj.filters | 3 + src/windows/execmd_w.cpp | 394 ++++++++++++------ src/windows/trexecmd.cpp | 146 +++---- 6 files changed, 340 insertions(+), 209 deletions(-) diff --git a/src/utils/execmd.h b/src/utils/execmd.h index 1dbae326..0cf295df 100644 --- a/src/utils/execmd.h +++ b/src/utils/execmd.h @@ -16,6 +16,7 @@ */ #ifndef _EXECMD_H_INCLUDED_ #define _EXECMD_H_INCLUDED_ +#include "autoconfig.h" #include #include diff --git a/src/utils/pathut.cpp b/src/utils/pathut.cpp index b9bf6c2c..76ab04ee 100644 --- a/src/utils/pathut.cpp +++ b/src/utils/pathut.cpp @@ -116,7 +116,7 @@ string path_tchartoutf8(TCHAR *text) } return string(&buffer[0]); #else - path = text; + return text; #endif } diff --git a/src/windows/Win32ProjectRecoll.vcxproj b/src/windows/Win32ProjectRecoll.vcxproj index 321b2a11..2e98600f 100644 --- a/src/windows/Win32ProjectRecoll.vcxproj +++ b/src/windows/Win32ProjectRecoll.vcxproj @@ -42,7 +42,7 @@ StaticLibrary true v140 - Unicode + MultiByte StaticLibrary @@ -236,6 +236,7 @@ + diff --git a/src/windows/Win32ProjectRecoll.vcxproj.filters b/src/windows/Win32ProjectRecoll.vcxproj.filters index cfafda99..3ec1a77e 100644 --- a/src/windows/Win32ProjectRecoll.vcxproj.filters +++ b/src/windows/Win32ProjectRecoll.vcxproj.filters @@ -293,6 +293,9 @@ Source Files + + Source Files + diff --git a/src/windows/execmd_w.cpp b/src/windows/execmd_w.cpp index eb9fc55d..bddf2373 100644 --- a/src/windows/execmd_w.cpp +++ b/src/windows/execmd_w.cpp @@ -5,39 +5,60 @@ #include #include +#include "debuglog.h" + using namespace std; +static void printError(const string& text) +{ + DWORD err = GetLastError(); + LOGERR(("%s : err: %d\n", text.c_str(), err)); +} + class ExecCmd::Internal { public: Internal() - : m_advise(0), m_provide(0), m_timeoutMs(1000), - m_pid(-1), m_hOutputRead(NULL), m_hInputWrite(NULL) { + : advise(0), provide(0), timeoutMs(1000), + hOutputRead(NULL), hInputWrite(NULL) { } std::vector m_env; - ExecCmdAdvise *m_advise; - ExecCmdProvide *m_provide; - bool m_killRequest; - int m_timeoutMs; - string m_stderrFile; + ExecCmdAdvise *advise; + ExecCmdProvide *provide; + bool killRequest; + int timeoutMs; + string stderrFile; // Subprocess id - pid_t m_pid; - HANDLE m_hOutputRead; - HANDLE m_hInputWrite; - OVERLAPPED m_oOutputRead; // Do these need resource control? - OVERLAPPED m_oInputWrite; - PROCESS_INFORMATION m_piProcInfo; + HANDLE hOutputRead; + HANDLE hInputWrite; + OVERLAPPED oOutputRead; // Do these need resource control? + OVERLAPPED oInputWrite; + PROCESS_INFORMATION piProcInfo; // Reset internal state indicators. Any resources should have been // previously freed void reset() { - m_killRequest = false; - m_hOutputRead = NULL; - m_hInputWrite = NULL; - memset(&m_oOutputRead, 0, sizeof(m_oOutputRead)); - memset(&m_oInputWrite, 0, sizeof(m_oInputWrite)); - m_pid = -1; + killRequest = false; + hOutputRead = NULL; + hInputWrite = NULL; + memset(&oOutputRead, 0, sizeof(oOutputRead)); + memset(&oInputWrite, 0, sizeof(oInputWrite)); + ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION)); } + void releaseResources() { + if (hOutputRead) + CloseHandle(hOutputRead); + if (hInputWrite) + CloseHandle(hInputWrite); + if (oOutputRead.hEvent) + CloseHandle(oOutputRead.hEvent); + if (oInputWrite.hEvent) + CloseHandle(oInputWrite.hEvent); + reset(); + } + bool PreparePipes(bool has_input, HANDLE *hChildInput, + bool has_output, HANDLE *hChildOutput, + HANDLE *hChildError); }; ExecCmd::ExecCmd() @@ -47,38 +68,57 @@ ExecCmd::ExecCmd() m->reset(); } } +ExecCmd::~ExecCmd() +{ + if (m) + m->releaseResources(); +} + +bool ExecCmd::which(const string& cmd, string& exe, const char* path) +{ + return false; +} void ExecCmd::setAdvise(ExecCmdAdvise *adv) { - m->m_advise = adv; + m->advise = adv; } void ExecCmd::setProvide(ExecCmdProvide *p) { - m->m_provide = p; + m->provide = p; } void ExecCmd::setTimeout(int mS) { if (mS > 30) { - m->m_timeoutMs = mS; + m->timeoutMs = mS; } } void ExecCmd::setStderr(const std::string& stderrFile) { - m->m_stderrFile = stderrFile; + m->stderrFile = stderrFile; } pid_t ExecCmd::getChildPid() { - return m->m_pid; + return m->piProcInfo.dwProcessId; } void ExecCmd::setKill() { - m->m_killRequest = true; + m->killRequest = true; } void ExecCmd::zapChild() { setKill(); (void)wait(); } +void ExecCmd::putenv(const string &envassign) +{ + m->m_env.push_back(envassign); +} +void ExecCmd::putenv(const string &name, const string& value) +{ + string ea = name + "=" + value; + putenv(ea); +} bool ExecCmd::Internal::PreparePipes(bool has_input,HANDLE *hChildInput, @@ -90,43 +130,48 @@ bool ExecCmd::Internal::PreparePipes(bool has_input,HANDLE *hChildInput, HANDLE hOutputWrite = NULL; HANDLE hErrorWrite = NULL; HANDLE hInputRead = NULL; - m_hOutputRead = NULL; - m_hInputWrite = NULL; - memset(&m_oOutputRead, 0, sizeof(m_oOutputRead)); - memset(&m_oInputWrite, 0, sizeof(m_oInputWrite)); + hOutputRead = NULL; + hInputWrite = NULL; + memset(&oOutputRead, 0, sizeof(oOutputRead)); + memset(&oInputWrite, 0, sizeof(oInputWrite)); // manual reset event - m_oOutputRead.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - if (m_oOutputRead.hEvent == INVALID_HANDLE_VALUE) { + oOutputRead.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if (oOutputRead.hEvent == INVALID_HANDLE_VALUE) { + LOGERR(("ExecCmd::PreparePipes: CreateEvent failed\n")); goto errout; } // manual reset event - m_oInputWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - if (m_oInputWrite.hEvent == INVALID_HANDLE_VALUE) { + oInputWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if (oInputWrite.hEvent == INVALID_HANDLE_VALUE) { + LOGERR(("ExecCmd::PreparePipes: CreateEvent failed\n")); goto errout; } + SECURITY_ATTRIBUTES sa; + // Set up the security attributes struct. + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.bInheritHandle = TRUE; // this is the critical bit + sa.lpSecurityDescriptor = NULL; + if (has_output) { + LOGDEB(("ExecCmd::preparePipes: has output\n")); // src for this code: https://www.daniweb.com/software-development/cpp/threads/295780/using-named-pipes-with-asynchronous-io-redirection-to-winapi // ONLY IMPORTANT CHANGE // set inheritance flag to TRUE in CreateProcess // you need this for the client to inherit the handles - SECURITY_ATTRIBUTES sa; - // Set up the security attributes struct. - sa.nLength = sizeof(SECURITY_ATTRIBUTES); - sa.bInheritHandle = TRUE; // this is the critical bit - sa.lpSecurityDescriptor = NULL; - + // Create the child output named pipe. // This creates a inheritable, one-way handle for the server to read hOutputReadTmp = CreateNamedPipe( TEXT("\\\\.\\pipe\\outstreamPipe"), PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED, - PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, + PIPE_WAIT, 1, 4096, 4096, 0, &sa); if (hOutputReadTmp == INVALID_HANDLE_VALUE) { + printError("preparePipes: CreateNamedPipe(out tmp)"); goto errout; } @@ -143,7 +188,10 @@ bool ExecCmd::Internal::PreparePipes(bool has_input,HANDLE *hChildInput, 0, &sa, OPEN_EXISTING, // very important flag! FILE_ATTRIBUTE_NORMAL, 0 // no template file for OPEN_EXISTING ); - + if (hOutputWrite == INVALID_HANDLE_VALUE) { + printError("preparePipes: CreateFile(outputWrite)"); + goto errout; + } // All is well? not quite. Our main server-side handle was // created shareable. @@ -156,9 +204,10 @@ bool ExecCmd::Internal::PreparePipes(bool has_input,HANDLE *hChildInput, // the child inherits the properties and, as a result, // non-closeable handles to the pipes are created. if (!DuplicateHandle(GetCurrentProcess(), hOutputReadTmp, - GetCurrentProcess(), &m_hOutputRead, + GetCurrentProcess(), &hOutputRead, 0, FALSE, // Make it uninheritable. DUPLICATE_SAME_ACCESS)) { + printError("preparePipes: DuplicateHandle(readtmp->outputread)"); goto errout; } // now we kill the original, inheritable server-side handle. That @@ -166,30 +215,44 @@ bool ExecCmd::Internal::PreparePipes(bool has_input,HANDLE *hChildInput, // getting it. Child-proofing. Close inheritable copies of the // handles you do not want to be inherited. if (!CloseHandle(hOutputReadTmp)) { + printError("preparePipes: CloseHandle(readtmp)"); goto errout; } hOutputReadTmp = NULL; - } - - -#if 0 // Nope, can't do this, we certainly don't want to mix stdout and stderr - // Have to take the give stderr output file instead - if (!m->m_stderrFile.empty()) { - // Open the file and make the handle inheritable } else { - // Duplicate our own stderr. Does passing NULL work for this ? + // Not using child output. Let the child have our standard output. + HANDLE hstd = GetStdHandle(STD_OUTPUT_HANDLE); + if (hstd == INVALID_HANDLE_VALUE) { + printError("preparePipes: GetStdHandle(stdout)"); + goto errout; + } + if (!DuplicateHandle(GetCurrentProcess(), hstd, + GetCurrentProcess(), &hOutputWrite, + 0, TRUE, + DUPLICATE_SAME_ACCESS)) { + printError("preparePipes: DuplicateHandle(stdout)"); + goto errout; + } } - // we're going to give the same pipe for stderr, so duplicate for that: - // Create a duplicate of the output write handle for the std error - // write handle. This is necessary in case the child application - // closes one of its std output handles. - if (!DuplicateHandle(GetCurrentProcess(), hOutputWrite, - GetCurrentProcess(), &hErrorWrite, - 0, TRUE, DUPLICATE_SAME_ACCESS)) { - goto errout; + // Have to take the give stderr output file instead + if (!stderrFile.empty()) { + // Open the file set up the child handle: TBD + } else { + // Let the child inherit our standard input + HANDLE hstd = GetStdHandle(STD_ERROR_HANDLE); + if (hstd == INVALID_HANDLE_VALUE) { + printError("preparePipes: GetStdHandle(stderr)"); + goto errout; + } + if (!DuplicateHandle(GetCurrentProcess(), hstd, + GetCurrentProcess(), &hErrorWrite, + 0, TRUE, + DUPLICATE_SAME_ACCESS)) { + printError("preparePipes: DuplicateHandle(stderr)"); + goto errout; + } } -#endif if (has_input) { // now same procedure for input pipe @@ -200,6 +263,7 @@ bool ExecCmd::Internal::PreparePipes(bool has_input,HANDLE *hChildInput, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 1, 4096, 4096, 0, &sa); if (hInputWriteTmp == INVALID_HANDLE_VALUE) { + printError("preparePipes: CreateNamedPipe(inputWTmp)"); goto errout; } @@ -209,17 +273,37 @@ bool ExecCmd::Internal::PreparePipes(bool has_input,HANDLE *hChildInput, 0, &sa, OPEN_EXISTING, // very important flag! FILE_ATTRIBUTE_NORMAL, 0 // no template file for OPEN_EXISTING ); - + if (hInputRead == INVALID_HANDLE_VALUE) { + printError("preparePipes: CreateFile(inputRead)"); + goto errout; + } + if (!DuplicateHandle(GetCurrentProcess(), hInputWriteTmp, - GetCurrentProcess(), &m_hInputWrite, + GetCurrentProcess(), &hInputWrite, 0, FALSE, // Make it uninheritable. DUPLICATE_SAME_ACCESS)) { + printError("preparePipes: DuplicateHandle(inputWTmp->inputW)"); goto errout; } if (!CloseHandle(hInputWriteTmp)) { + printError("preparePipes: CloseHandle(inputWTmp)"); goto errout; } hInputWriteTmp = NULL; + } else { + // Let the child inherit our standard input + HANDLE hstd = GetStdHandle(STD_INPUT_HANDLE); + if (hstd == INVALID_HANDLE_VALUE) { + printError("preparePipes: GetStdHandle(stdin)"); + goto errout; + } + if (!DuplicateHandle(GetCurrentProcess(), hstd, + GetCurrentProcess(), &hInputRead, + 0, TRUE, + DUPLICATE_SAME_ACCESS)) { + printError("preparePipes: DuplicateHandle(stdin)"); + goto errout; + } } *hChildInput = hInputRead; @@ -228,41 +312,35 @@ bool ExecCmd::Internal::PreparePipes(bool has_input,HANDLE *hChildInput, return true; errout: - if (hInputWriteTmp) - CloseHandle(hInputWriteTmp); - if (hOutputReadTmp) - CloseHandle(hOutputReadTmp); - if (m_hOutputRead) - CloseHandle(m_hOutputRead); - if (m_hInputWrite) - CloseHandle(m_hInputWrite); - if (m_oOutputRead.hEvent) - CloseHandle(m_oOutputRead.hEvent); - if (m_oInputWrite.hEvent) - CloseHandle(m_oInputWrite.hEvent); + releaseResources(); if (hOutputWrite) CloseHandle(hOutputWrite); if (hInputRead) CloseHandle(hInputRead); if (hErrorWrite) CloseHandle(hErrorWrite); + if (hInputWriteTmp) + CloseHandle(hInputWriteTmp); + if (hOutputReadTmp) + CloseHandle(hOutputReadTmp); + return false; } /** - This routine appends the given argument to a command line such - that CommandLineToArgvW will return the argument string unchanged. - Arguments in a command line should be separated by spaces; this - function does not add these spaces. The caller must append spaces - between calls. + This routine appends the given argument to a command line such + that CommandLineToArgvW will return the argument string unchanged. + Arguments in a command line should be separated by spaces; this + function does not add these spaces. The caller must append spaces + between calls. - @param arg Supplies the argument to encode. + @param arg Supplies the argument to encode. - @param cmdLine Supplies the command line to which we append - the encoded argument string. + @param cmdLine Supplies the command line to which we append + the encoded argument string. - @force Supplies an indication of whether we should quote - the argument even if it does not contain any characters that - would ordinarily require quoting. + @force Supplies an indication of whether we should quote + the argument even if it does not contain any characters that + would ordinarily require quoting. */ static void argQuote(const string& arg, string& cmdLine, @@ -318,28 +396,27 @@ static string argvToCmdLine(const string& cmd, const vector& args) // Create a child process int ExecCmd::startExec(const string &cmd, const vector& args, - bool has_input, bool has_output) + bool has_input, bool has_output) { { // Debug and logging - string command = cmd + " "; - for (vector::const_iterator it = args.begin(); + string command = cmd + " "; + for (vector::const_iterator it = args.begin(); it != args.end(); it++) { - command += "{" + *it + "} "; - } - LOGDEB(("ExecCmd::startExec: (%d|%d) %s\n", - has_input, has_output, command.c_str())); + command += "{" + *it + "} "; + } + LOGDEB(("ExecCmd::startExec: (%d|%d) %s\n", + has_input, has_output, command.c_str())); } string cmdline = argvToCmdLine(cmd, args); - // The resource manager ensures resources are freed if we return early - //ExecCmdRsrc e(this->m); - HANDLE hInputRead; HANDLE hOutputWrite; HANDLE hErrorWrite; if (!m->PreparePipes(has_input, &hInputRead, has_output, &hOutputWrite, &hErrorWrite)) { + LOGERR(("ExecCmd::startExec: preparePipes failed\n")); + m->releaseResources(); return false; } @@ -347,12 +424,10 @@ int ExecCmd::startExec(const string &cmd, const vector& args, BOOL bSuccess = FALSE; // Set up members of the PROCESS_INFORMATION structure. - - ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION)); + ZeroMemory(&m->piProcInfo, sizeof(PROCESS_INFORMATION)); // Set up members of the STARTUPINFO structure. // This structure specifies the STDIN and STDOUT handles for redirection. - ZeroMemory(&siStartInfo, sizeof(STARTUPINFO)); siStartInfo.cb = sizeof(STARTUPINFO); siStartInfo.dwFlags |= STARTF_USESTDHANDLES; @@ -361,8 +436,12 @@ int ExecCmd::startExec(const string &cmd, const vector& args, siStartInfo.hStdError = hErrorWrite; // Create the child process. + // Need a writable buffer for the command line, for some reason. + LPSTR buf = (LPSTR)malloc(cmdline.size() + 1); + memcpy(buf, cmdline.c_str(), cmdline.size()); + buf[cmdline.size()] = 0; bSuccess = CreateProcess(NULL, - cmdline.c_str(), // command line + buf, // command line NULL, // process security attributes NULL, // primary thread security attrs TRUE, // handles are inherited @@ -370,25 +449,50 @@ int ExecCmd::startExec(const string &cmd, const vector& args, NULL, // use parent's environment NULL, // use parent's current directory &siStartInfo, // STARTUPINFO pointer - &piProcInfo); // receives PROCESS_INFORMATION + &m->piProcInfo); // receives PROCESS_INFORMATION + free(buf); if (!bSuccess) { + printError("ExecCmd::doexec: CreateProcess"); + m->releaseResources(); return false; } - m->pid = piProcInfo.dwProcessId; return true; } +enum WaitResult { + Ok, Quit, Timeout +}; + +static WaitResult Wait(HANDLE hdl, int timeout) +{ + //HANDLE hdls[2] = { hdl, eQuit }; + HANDLE hdls[1] = { hdl}; + LOGDEB(("ExecCmd::Wait\n")); + DWORD res = WaitForMultipleObjects(1, hdls, FALSE, timeout); + if (res == WAIT_OBJECT_0) { + LOGDEB(("ExecCmd::Wait: returning Ok\n")); + return Ok; + } else if (res == (WAIT_OBJECT_0 + 1)) { + LOGDEB(("ExecCmd::Wait: returning Quit\n")); + return Quit; + } else if (res == WAIT_TIMEOUT) { + LOGDEB(("ExecCmd::Wait: returning Timeout\n")); + return Timeout; + } + printError("Wait: WaitForMultipleObjects: unknown, returning Timout\n"); + return Timeout; +} // Read from a file and write its contents to the pipe for the child's // STDIN. Stop when there is no more data. int ExecCmd::send(const string& data) { - DWORD dwRead, dwWritten; + DWORD dwWritten; BOOL bSuccess = false; - bSuccess = WriteFile(m->m_hInputWrite, data.c_str(), data.size(), - NULL, &m->m_oInputWrite); + bSuccess = WriteFile(m->hInputWrite, data.c_str(), (DWORD)data.size(), + NULL, &m->oInputWrite); DWORD err = GetLastError(); // TODO: some more decision, either the operation completes immediately @@ -396,96 +500,116 @@ int ExecCmd::send(const string& data) // and ERROR_IO_PENDING // in the first case bytes read/written parameter can be used directly if (!bSuccess && err != ERROR_IO_PENDING) { - return; + return -1; } - WaitResult waitRes = Wait(oInputWrite.hEvent, 5000); + WaitResult waitRes = Wait(m->oInputWrite.hEvent, 5000); if (waitRes == Ok) { - if (!GetOverlappedResult(m->m_hInputWrite, - &m->m_oInputWrite, &dwWritten, TRUE)) { - ErrorExit("GetOverlappedResult"); + if (!GetOverlappedResult(m->hInputWrite, + &m->oInputWrite, &dwWritten, TRUE)) { + printError("GetOverlappedResult"); + return -1; } } else if (waitRes == Quit) { - if (!CancelIo(hInputWrite)) - ErrorExit("CancelIo"); - return; + if (!CancelIo(m->hInputWrite)) { + printError("CancelIo"); + } + return -1; } else if (waitRes == Timeout) { - if (!CancelIo(hInputWrite)) - ErrorExit("CancelIo"); - return; + if (!CancelIo(m->hInputWrite)) { + printError("CancelIo"); + } + return -1; } + return dwWritten; } +#ifndef MIN +#define MIN(A,B) ((A)<(B)?(A):(B)) +#endif + // Read output from the child process's pipe for STDOUT // and write to cout in this programme // Stop when there is no more data. // @arg cnt count to read, -1 means read to end of data. -int ExecCmd::receive(const string& data, int cnt) +int ExecCmd::receive(string& data, int cnt) { DWORD dwRead; const int BUFSIZE = 8192; CHAR chBuf[BUFSIZE]; BOOL bSuccess = FALSE; int totread = 0; - + LOGDEB(("ExecCmd::receive: cnt %d\n", cnt)); while (true) { int toread = cnt > 0 ? MIN(cnt - totread, BUFSIZE) : BUFSIZE; - bSuccess = ReadFile(m->m_hOutputRead, chBuf, toread, - NULL, &m->m_oOutputRead); + LOGDEB(("ExecCmd::receive: calling ReadFile with cnt %d\n", toread)) + bSuccess = ReadFile(m->hOutputRead, chBuf, toread, + NULL, &m->oOutputRead); DWORD err = GetLastError(); - if (!bSuccess && err != ERROR_IO_PENDING) + if (!bSuccess && err != ERROR_IO_PENDING) { + LOGERR(("ExecCmd::receive: ReadFile error: %d\n", int(err))); break; + } - WaitResult waitRes = Wait(oOutputRead.hEvent, 5000); + WaitResult waitRes = Wait(m->oOutputRead.hEvent, 5000); if (waitRes == Ok) { - if (!GetOverlappedResult(hOutputRead, &oOutputRead, &dwRead, TRUE)) { - ErrorExit("GetOverlappedResult"); + if (!GetOverlappedResult(m->hOutputRead, &m->oOutputRead, &dwRead, TRUE)) { + printError("GetOverlappedResult"); + return -1; } + LOGDEB(("ExecCmd::receive: got %d bytes\n", int(dwRead))); totread += dwRead; - data.append(buf, dwRead); + data.append(chBuf, dwRead); } else if (waitRes == Quit) { - if (!CancelIo(hOutputRead)) - ErrorExit("CancelIo"); + if (!CancelIo(m->hOutputRead)) { + printError("CancelIo"); + } break; } else if (waitRes == Timeout) { - if (!CancelIo(hOutputRead)) - ErrorExit("CancelIo"); + if (!CancelIo(m->hOutputRead)) { + printError("CancelIo"); + } break; } } return totread; } +int ExecCmd::getline(std::string& data) +{ + return -1; +} + int ExecCmd::wait() { // Wait until child process exits. - WaitForSingleObject(m->m_piProcInfo.hProcess, INFINITE); + WaitForSingleObject(m->piProcInfo.hProcess, INFINITE); // Get exit code DWORD exit_code = 0; - GetExitCodeProcess(m->m_piProcInfo.hProcess, &exit_code); + GetExitCodeProcess(m->piProcInfo.hProcess, &exit_code); // Close handles to the child process and its primary thread. - CloseHandle(m->m_piProcInfo.hProcess); - CloseHandle(m->m_piProcInfo.hThread); + CloseHandle(m->piProcInfo.hProcess); + CloseHandle(m->piProcInfo.hThread); return (int)exit_code; } int ExecCmd::doexec(const string &cmd, const vector& args, - const string *input, string *output) + const string *input, string *output) { if (input && output) { LOGERR(("ExecCmd::doexec: can't do both input and output\n")); return -1; } if (startExec(cmd, args, input != 0, output != 0) < 0) { - return -1; + return -1; } if (input) { - receive(*input); + send(*input); } else if (output) { - send(*output); + receive(*output); } return wait(); } diff --git a/src/windows/trexecmd.cpp b/src/windows/trexecmd.cpp index c1aa1a83..2b32247d 100644 --- a/src/windows/trexecmd.cpp +++ b/src/windows/trexecmd.cpp @@ -1,11 +1,12 @@ +#include "autoconfig.h" + #include "execmd.h" #include #include -#include +#include "safeunistd.h" #include -#include #include #include @@ -31,8 +32,8 @@ bool exercise_mhexecm(const string& cmdstr, const string& mimetype, vector myparams; if (cmd.startExec(cmdstr, myparams, 1, 1) < 0) { - cerr << "startExec " << cmdstr << " failed. Missing command?\n"; - return false; + cerr << "startExec " << cmdstr << " failed. Missing command?\n"; + return false; } for (vector::const_iterator it = files.begin(); @@ -115,22 +116,22 @@ bool exercise_mhexecm(const string& cmdstr, const string& mimetype, static char *thisprog; static char usage [] = -"trexecmd [-c -r -i -o] cmd [arg1 arg2 ...]\n" -" -c : test cancellation (ie: trexecmd -c sleep 1000)\n" -" -r : run reexec. Must be separate option.\n" -" -i : command takes input\n" -" -o : command produces output\n" -" If -i is set, we send /etc/group contents to whatever command is run\n" -" If -o is set, we print whatever comes out\n" -"trexecmd -m [file ...]: test execm:\n" -" should be the path to an execm filter\n" -" the type of the file parameters\n" -"trexecmd -w cmd : do the 'which' thing\n" -; + "trexecmd [-c -r -i -o] cmd [arg1 arg2 ...]\n" + " -c : test cancellation (ie: trexecmd -c sleep 1000)\n" + " -r : run reexec. Must be separate option.\n" + " -i : command takes input\n" + " -o : command produces output\n" + " If -i is set, we send /etc/group contents to whatever command is run\n" + " If -o is set, we print whatever comes out\n" + "trexecmd -m [file ...]: test execm:\n" + " should be the path to an execm filter\n" + " the type of the file parameters\n" + "trexecmd -w cmd : do the 'which' thing\n" + ; -static void Usage(void) +static void Usage(FILE *fp = stderr) { - fprintf(stderr, "%s: usage:\n%s", thisprog, usage); + fprintf(fp, "%s: usage:\n%s", thisprog, usage); exit(1); } @@ -148,17 +149,17 @@ static int op_flags; class MEAdv : public ExecCmdAdvise { public: void newData(int cnt) { - if (op_flags & OPT_c) { - static int callcnt; - if (callcnt++ == 10) { + if (op_flags & OPT_c) { + static int callcnt; + if (callcnt++ == 10) { // Just sets the cancellation flag - CancelCheck::instance().setCancel(); + CancelCheck::instance().setCancel(); // Would be called from somewhere else and throws an // exception. We call it here for simplicity CancelCheck::instance().checkCancel(); - } - } - cerr << "newData(" << cnt << ")" << endl; + } + } + cerr << "newData(" << cnt << ")" << endl; } }; @@ -168,21 +169,21 @@ public: FILE *m_fp; string *m_input; MEPv(string *i) - : m_input(i) - { - m_fp = fopen("/etc/group", "r"); - } + : m_input(i) + { + m_fp = fopen("/etc/group", "r"); + } ~MEPv() { - if (m_fp) - fclose(m_fp); + if (m_fp) + fclose(m_fp); } void newData() { - char line[1024]; - if (m_fp && fgets(line, 1024, m_fp)) { - m_input->assign((const char *)line); - } else { - m_input->erase(); - } + char line[1024]; + if (m_fp && fgets(line, 1024, m_fp)) { + m_input->assign((const char *)line); + } else { + m_input->erase(); + } } }; @@ -195,14 +196,14 @@ int main(int argc, char *argv[]) reexec.init(argc, argv); if (0) { - // Disabled: For testing reexec arg handling - vector newargs; - newargs.push_back("newarg"); - newargs.push_back("newarg1"); - newargs.push_back("newarg2"); - newargs.push_back("newarg3"); - newargs.push_back("newarg4"); - reexec.insertArgs(newargs, 2); + // Disabled: For testing reexec arg handling + vector newargs; + newargs.push_back("newarg"); + newargs.push_back("newarg1"); + newargs.push_back("newarg2"); + newargs.push_back("newarg3"); + newargs.push_back("newarg4"); + reexec.insertArgs(newargs, 2); } #endif @@ -210,30 +211,31 @@ int main(int argc, char *argv[]) argc--; argv++; while (argc > 0 && **argv == '-') { - (*argv)++; - if (!(**argv)) - /* Cas du "adb - core" */ - Usage(); - while (**argv) - switch (*(*argv)++) { - case 'c': op_flags |= OPT_c; break; - case 'r': op_flags |= OPT_r; break; - case 'w': op_flags |= OPT_w; break; - case 'm': op_flags |= OPT_m; break; - case 'i': op_flags |= OPT_i; break; - case 'o': op_flags |= OPT_o; break; - default: Usage(); break; - } + (*argv)++; + if (!(**argv)) + /* Cas du "adb - core" */ + Usage(); + while (**argv) + switch (*(*argv)++) { + case 'c': op_flags |= OPT_c; break; + case 'r': op_flags |= OPT_r; break; + case 'w': op_flags |= OPT_w; break; + case 'm': op_flags |= OPT_m; break; + case 'i': op_flags |= OPT_i; break; + case 'o': op_flags |= OPT_o; break; + case'h': Usage(stdout); + default: Usage(); break; + } b1: argc--; argv++; } if (argc < 1) - Usage(); + Usage(); string arg1 = *argv++; argc--; vector l; while (argc > 0) { - l.push_back(*argv++); argc--; + l.push_back(*argv++); argc--; } DebugLog::getdbl()->setloglevel(DEBDEB1); @@ -243,19 +245,19 @@ int main(int argc, char *argv[]) #endif if (op_flags & OPT_w) { - // Test "which" method - string path; - if (ExecCmd::which(arg1, path)) { - cout << path << endl; + // Test "which" method + string path; + if (ExecCmd::which(arg1, path)) { + cout << path << endl; return 0; - } - return 1; + } + return 1; } else if (op_flags & OPT_m) { if (l.size() < 2) Usage(); string mimetype = l[0]; l.erase(l.begin()); - return exercise_mhexecm(arg1, mimetype, l) ? 0 : 1; + return exercise_mhexecm(arg1, mimetype, l) ? 0 : 1; } else { // Default: execute command line arguments ExecCmd mexec; @@ -263,13 +265,13 @@ int main(int argc, char *argv[]) // Set callback to be called whenever there is new data // available and at a periodic interval, to check for // cancellation +#ifdef LATER MEAdv adv; mexec.setAdvise(&adv); mexec.setTimeout(5); - // Stderr output goes there - mexec.setStderr("/tmp/trexecStderr"); - + mexec.setStderr("/tmp/trexecStderr"); +#endif // A few environment variables. Check with trexecmd env mexec.putenv("TESTVARIABLE1=TESTVALUE1"); mexec.putenv("TESTVARIABLE2=TESTVALUE2"); @@ -297,7 +299,7 @@ int main(int argc, char *argv[]) fprintf(stderr, "Status: 0x%x\n", status); if (op_flags & OPT_o) { - cout << output; + cout << "data received: [" << output <<"]\n"; } exit (status >> 8); }