#include "cli.hpp"
#include "os_path.hpp"
+#include "os_process.hpp"
#include "trace_tools.hpp"
static const char *synopsis = "Identify differences between two traces.";
#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 = {
#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.";
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<char *>("python");
+ args[1] = const_cast<char *>(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 = {
#include <unistd.h>
#include <sys/time.h>
+#include <sys/wait.h>
#include <pthread.h>
#include <sys/stat.h>
#include <fcntl.h>
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, ...)
{
--- /dev/null
+/**************************************************************************
+ *
+ * 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_ */
#include <string.h>
#include <stdio.h>
+#include <string>
+
#include "os.hpp"
#include "os_path.hpp"
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<char *>(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, ...)
{
#include <iostream>
#include "os_path.hpp"
+#include "os_process.hpp"
#include "trace_tools.hpp"
APITRACE_WRAPPER_INSTALL_DIR "\n"
"to the directory with the application to trace, then run the application.\n";
+ return 1;
+
#else
#if defined(__APPLE__)
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;
}