diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 9b83f149f..aed9bfee7 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -34,13 +34,13 @@ set(common_sources dns_utils.cpp download.cpp error.cpp - exec.cpp expect.cpp util.cpp i18n.cpp notify.cpp password.cpp perf_timer.cpp + spawn.cpp threadpool.cpp updates.cpp aligned.c) @@ -60,7 +60,6 @@ set(common_private_headers dns_utils.h download.h error.h - exec.h expect.h http_connection.h int-util.h @@ -74,6 +73,7 @@ set(common_private_headers i18n.h password.h perf_timer.h + spawn.h stack_trace.h threadpool.h updates.h diff --git a/src/common/notify.cpp b/src/common/notify.cpp index b7869ad84..cadc68ea7 100644 --- a/src/common/notify.cpp +++ b/src/common/notify.cpp @@ -29,12 +29,17 @@ #include #include "misc_log_ex.h" #include "file_io_utils.h" -#include "exec.h" +#include "spawn.h" #include "notify.h" namespace tools { +/* + TODO: + - Improve tokenization to handle paths containing whitespaces, quotes, etc. + - Windows unicode support (implies implementing unicode command line parsing code) +*/ Notify::Notify(const char *spec) { CHECK_AND_ASSERT_THROW_MES(spec, "Null spec"); @@ -51,11 +56,7 @@ int Notify::notify(const char *parameter) for (std::string &s: margs) boost::replace_all(s, "%s", parameter); - char **cargs = (char**)alloca(sizeof(char*) * (margs.size() + 1)); - for (size_t n = 0; n < margs.size(); ++n) - cargs[n] = (char*)margs[n].c_str(); - cargs[margs.size()] = NULL; - return tools::exec(filename.c_str(), cargs, false); + return tools::spawn(filename.c_str(), margs, false); } } diff --git a/src/common/exec.cpp b/src/common/spawn.cpp similarity index 64% rename from src/common/exec.cpp rename to src/common/spawn.cpp index 41b8f1378..59f11675c 100644 --- a/src/common/exec.cpp +++ b/src/common/spawn.cpp @@ -29,16 +29,68 @@ #include #include #include +#ifdef _WIN32 +#include +#include +#include +#else #include +#endif #include "misc_log_ex.h" -#include "exec.h" +#include "spawn.h" namespace tools { -int exec(const char *filename, char * const argv[], bool wait) +int spawn(const char *filename, const std::vector& args, bool wait) { +#ifdef _WIN32 + std::string joined = boost::algorithm::join(args, " "); + char *commandLine = !joined.empty() ? &joined[0] : nullptr; + STARTUPINFOA si = {}; + si.cb = sizeof(si); + PROCESS_INFORMATION pi; + if (!CreateProcessA(filename, commandLine, nullptr, nullptr, false, 0, nullptr, nullptr, &si, &pi)) + { + MERROR("CreateProcess failed. Error code " << GetLastError()); + return -1; + } + + BOOST_SCOPE_EXIT(&pi) + { + CloseHandle(pi.hThread); + CloseHandle(pi.hProcess); + } + BOOST_SCOPE_EXIT_END + + if (!wait) + { + return 0; + } + + DWORD result = WaitForSingleObject(pi.hProcess, INFINITE); + if (result != WAIT_OBJECT_0) + { + MERROR("WaitForSingleObject failed. Result " << result << ", error code " << GetLastError()); + return -1; + } + + DWORD exitCode; + if (!GetExitCodeProcess(pi.hProcess, &exitCode)) + { + MERROR("GetExitCodeProcess failed. Error code " << GetLastError()); + return -1; + } + + MINFO("Child exited with " << exitCode); + return static_cast(exitCode); +#else + char **argv = (char**)alloca(sizeof(char*) * (args.size() + 1)); + for (size_t n = 0; n < args.size(); ++n) + argv[n] = (char*)args[n].c_str(); + argv[args.size()] = NULL; + pid_t pid = fork(); if (pid < 0) { @@ -83,6 +135,7 @@ int exec(const char *filename, char * const argv[], bool wait) } MERROR("Secret passage found"); return -1; +#endif } } diff --git a/src/common/exec.h b/src/common/spawn.h similarity index 95% rename from src/common/exec.h rename to src/common/spawn.h index 4d2037798..c90a0f790 100644 --- a/src/common/exec.h +++ b/src/common/spawn.h @@ -31,6 +31,6 @@ namespace tools { -int exec(const char *filename, char * const argv[], bool wait); +int spawn(const char *filename, const std::vector& args, bool wait); }