From 03c5d3d41dc219051cbbb8b84ea505e15ff433c4 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jos=C3=A9=20Fonseca?= Date: Fri, 11 Nov 2011 14:56:42 +0000 Subject: [PATCH] Abstract execv(). --- cli/cli_diff.cpp | 8 +-- cli/cli_diff_state.cpp | 22 +++---- common/os_posix.cpp | 21 +++++++ common/os_process.hpp | 45 ++++++++++++++ common/os_win32.cpp | 112 +++++++++++++++++++++++++++++++++++ common/trace_tools_trace.cpp | 10 ++-- 6 files changed, 195 insertions(+), 23 deletions(-) create mode 100644 common/os_process.hpp diff --git a/cli/cli_diff.cpp b/cli/cli_diff.cpp index 11399a1..4d24973 100644 --- a/cli/cli_diff.cpp +++ b/cli/cli_diff.cpp @@ -30,6 +30,7 @@ #include "cli.hpp" #include "os_path.hpp" +#include "os_process.hpp" #include "trace_tools.hpp" static const char *synopsis = "Identify differences between two traces."; @@ -95,16 +96,13 @@ command(int argc, char *argv[]) #ifdef _WIN32 std::cerr << "The 'apitrace diff' command is not yet supported on this O/S.\n"; + return 1; #else os::Path apitrace = os::getProcessName(); setenv("APITRACE", apitrace.str(), 1); - execv(command.str(), args); + return os::execute(args); #endif - - std::cerr << "Error: Failed to execute " << argv[0] << "\n"; - - return 1; } const Command diff_command = { diff --git a/cli/cli_diff_state.cpp b/cli/cli_diff_state.cpp index e58bd1d..5dd0fbe 100644 --- a/cli/cli_diff_state.cpp +++ b/cli/cli_diff_state.cpp @@ -30,6 +30,7 @@ #include "cli.hpp" #include "os_path.hpp" +#include "os_process.hpp" #include "trace_tools.hpp" static const char *synopsis = "Identify differences between two state dumps."; @@ -86,22 +87,15 @@ command(int argc, char *argv[]) APITRACE_SCRIPTS_INSTALL_DIR "/" CLI_DIFF_STATE_COMMAND, true); - char* args[4]; + char *args[5]; - args[0] = (char *) command.str(); - args[1] = file1; - args[2] = file2; - args[3] = NULL; + args[0] = const_cast("python"); + args[1] = const_cast(command.str()); + args[2] = file1; + args[3] = file2; + args[4] = NULL; -#ifdef _WIN32 - std::cerr << "The 'apitrace diff-state' command is not yet supported on this O/S.\n"; -#else - execv(command.str(), args); -#endif - - std::cerr << "Error: Failed to execute " << argv[0] << "\n"; - - return 1; + return os::execute(args); } const Command diff_state_command = { diff --git a/common/os_posix.cpp b/common/os_posix.cpp index 586ad84..da78783 100644 --- a/common/os_posix.cpp +++ b/common/os_posix.cpp @@ -31,6 +31,7 @@ #include #include +#include #include #include #include @@ -143,6 +144,26 @@ Path::exists(void) const return true; } +int execute(char * const * args) +{ + pid_t pid = fork(); + if (pid == 0) { + // child + execvp(args[0], args); + fprintf(stderr, "error: failed to execute %s\n", args[0]); + exit(-1); + } else { + // parent + if (pid == -1) { + fprintf(stderr, "error: failed to fork\n"); + return -1; + } + int status = -1; + waitpid(pid, &status, 0); + return status; + } +} + void log(const char *format, ...) { diff --git a/common/os_process.hpp b/common/os_process.hpp new file mode 100644 index 0000000..f1dd517 --- /dev/null +++ b/common/os_process.hpp @@ -0,0 +1,45 @@ +/************************************************************************** + * + * Copyright 2011 Jose Fonseca + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + **************************************************************************/ + +/* + * Sub-process abstraction. + */ + +#ifndef _OS_PROCESS_HPP_ +#define _OS_PROCESS_HPP_ + + +#include "os.hpp" + + +namespace os { + + +int execute(char * const * args); + + +} /* namespace os */ + +#endif /* _OS_PROCESS_HPP_ */ diff --git a/common/os_win32.cpp b/common/os_win32.cpp index 74d911c..e156c77 100644 --- a/common/os_win32.cpp +++ b/common/os_win32.cpp @@ -29,6 +29,8 @@ #include #include +#include + #include "os.hpp" #include "os_path.hpp" @@ -97,6 +99,116 @@ Path::exists(void) const return attrs != INVALID_FILE_ATTRIBUTES; } +/** + * Determine whether an argument should be quoted. + */ +static bool +needsQuote(const char *arg) +{ + char c; + while (true) { + c = *arg++; + if (c == '\0') { + break; + } + if (c == ' ' || c == '\t' || c == '\"') { + return true; + } + if (c == '\\') { + c = *arg++; + if (c == '\0') { + break; + } + if (c == '"') { + return true; + } + } + } + return false; +} + +static void +quoteArg(std::string &s, const char *arg) +{ + char c; + unsigned backslashes = 0; + + s.push_back('"'); + while (true) { + c = *arg++; + switch (c) + if (c == '\0') { + break; + } else if (c == '"') { + while (backslashes) { + s.push_back('\\'); + --backslashes; + } + s.push_back('\\'); + } else { + if (c == '\\') { + ++backslashes; + } else { + backslashes = 0; + } + } + s.push_back(c); + } + s.push_back('"'); +} + +int execute(char * const * args) +{ + std::string commandLine; + + const char *arg0 = *args; + const char *arg; + char sep = 0; + while ((arg = *args++) != NULL) { + if (sep) { + commandLine.push_back(sep); + } + + if (needsQuote(arg)) { + quoteArg(commandLine, arg); + } else { + commandLine.append(arg); + } + + sep = ' '; + } + + STARTUPINFO startupInfo; + memset(&startupInfo, 0, sizeof(startupInfo)); + startupInfo.cb = sizeof(startupInfo); + + PROCESS_INFORMATION processInformation; + + if (!CreateProcessA(NULL, + const_cast(commandLine.c_str()), // only modified by CreateProcessW + 0, // process attributes + 0, // thread attributes + FALSE, // inherit handles + 0, // creation flags, + NULL, // environment + NULL, // current directory + &startupInfo, + &processInformation + )) { + log("error: failed to execute %s\n", arg0); + } + + WaitForSingleObject(processInformation.hProcess, INFINITE); + + DWORD exitCode = ~0; + GetExitCodeProcess(processInformation.hProcess, &exitCode); + + CloseHandle(processInformation.hProcess); + CloseHandle(processInformation.hThread); + + return (int)exitCode; +} + void log(const char *format, ...) { diff --git a/common/trace_tools_trace.cpp b/common/trace_tools_trace.cpp index d1d6483..146f19f 100644 --- a/common/trace_tools_trace.cpp +++ b/common/trace_tools_trace.cpp @@ -31,6 +31,7 @@ #include #include "os_path.hpp" +#include "os_process.hpp" #include "trace_tools.hpp" @@ -127,6 +128,8 @@ traceProgram(API api, APITRACE_WRAPPER_INSTALL_DIR "\n" "to the directory with the application to trace, then run the application.\n"; + return 1; + #else #if defined(__APPLE__) @@ -155,17 +158,16 @@ traceProgram(API api, std::cerr << "\n"; } - execvp(argv[0], argv); + int status = os::execute(argv); unsetenv(TRACE_VARIABLE); if (output) { unsetenv("TRACE_FILE"); } - - std::cerr << "error: Failed to execute " << argv[0] << "\n"; + + return status; #endif - return 1; } -- 2.43.0