]> git.cworth.org Git - apitrace/commitdiff
Abstract execv().
authorJosé Fonseca <jose.r.fonseca@gmail.com>
Fri, 11 Nov 2011 14:56:42 +0000 (14:56 +0000)
committerJosé Fonseca <jose.r.fonseca@gmail.com>
Fri, 11 Nov 2011 20:14:05 +0000 (20:14 +0000)
cli/cli_diff.cpp
cli/cli_diff_state.cpp
common/os_posix.cpp
common/os_process.hpp [new file with mode: 0644]
common/os_win32.cpp
common/trace_tools_trace.cpp

index 11399a16b4c191f07c0372470b3a359ae2bfe6bb..4d249739e373fd4e6213db4a828c2fad89ccc325 100644 (file)
@@ -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 = {
index e58bd1d270172a14e964771f32af9a993bf1a41b..5dd0fbe4897decd52b4a5f5b31989a77d3c47ad6 100644 (file)
@@ -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<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 = {
index 586ad84ed5ced202736957d3c28b645bdc16f9af..da7878311a72f970a309fd11a3f3c5cf90fddc58 100644 (file)
@@ -31,6 +31,7 @@
 
 #include <unistd.h>
 #include <sys/time.h>
+#include <sys/wait.h>
 #include <pthread.h>
 #include <sys/stat.h>
 #include <fcntl.h>
@@ -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 (file)
index 0000000..f1dd517
--- /dev/null
@@ -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_ */
index 74d911cadc6e294049408db6ea3cafc88e5cf151..e156c77b8be8a99c32e74dcaff8d466e96d23e8b 100644 (file)
@@ -29,6 +29,8 @@
 #include <string.h>
 #include <stdio.h>
 
+#include <string>
+
 #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<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, ...)
 {
index d1d64833f61bff5e635fe45d46d22b23888d12a6..146f19f650ec159f44cfd75433a35b70ccd18868 100644 (file)
@@ -31,6 +31,7 @@
 #include <iostream>
 
 #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;
 }