summaryrefslogtreecommitdiffstats
path: root/gfx/angle/checkout/src/common/system_utils_posix.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/angle/checkout/src/common/system_utils_posix.cpp')
-rw-r--r--gfx/angle/checkout/src/common/system_utils_posix.cpp276
1 files changed, 276 insertions, 0 deletions
diff --git a/gfx/angle/checkout/src/common/system_utils_posix.cpp b/gfx/angle/checkout/src/common/system_utils_posix.cpp
new file mode 100644
index 0000000000..26501eb2a6
--- /dev/null
+++ b/gfx/angle/checkout/src/common/system_utils_posix.cpp
@@ -0,0 +1,276 @@
+//
+// Copyright 2018 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+// system_utils_posix.cpp: Implementation of POSIX OS-specific functions.
+
+#include "system_utils.h"
+
+#include <array>
+
+#include <dlfcn.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+namespace angle
+{
+
+namespace
+{
+struct ScopedPipe
+{
+ ~ScopedPipe()
+ {
+ closeEndPoint(0);
+ closeEndPoint(1);
+ }
+ void closeEndPoint(int index)
+ {
+ if (fds[index] >= 0)
+ {
+ close(fds[index]);
+ fds[index] = -1;
+ }
+ }
+ int fds[2] = {
+ -1,
+ -1,
+ };
+};
+
+void ReadEntireFile(int fd, std::string *out)
+{
+ out->clear();
+
+ while (true)
+ {
+ char buffer[256];
+ ssize_t bytesRead = read(fd, buffer, sizeof(buffer));
+
+ // If interrupted, retry.
+ if (bytesRead < 0 && errno == EINTR)
+ {
+ continue;
+ }
+
+ // If failed, or nothing to read, we are done.
+ if (bytesRead <= 0)
+ {
+ break;
+ }
+
+ out->append(buffer, bytesRead);
+ }
+}
+} // anonymous namespace
+
+Optional<std::string> GetCWD()
+{
+ std::array<char, 4096> pathBuf;
+ char *result = getcwd(pathBuf.data(), pathBuf.size());
+ if (result == nullptr)
+ {
+ return Optional<std::string>::Invalid();
+ }
+ return std::string(pathBuf.data());
+}
+
+bool SetCWD(const char *dirName)
+{
+ return (chdir(dirName) == 0);
+}
+
+bool UnsetEnvironmentVar(const char *variableName)
+{
+ return (unsetenv(variableName) == 0);
+}
+
+bool SetEnvironmentVar(const char *variableName, const char *value)
+{
+ return (setenv(variableName, value, 1) == 0);
+}
+
+std::string GetEnvironmentVar(const char *variableName)
+{
+ const char *value = getenv(variableName);
+ return (value == nullptr ? std::string() : std::string(value));
+}
+
+const char *GetPathSeparator()
+{
+ return ":";
+}
+
+bool RunApp(const std::vector<const char *> &args,
+ std::string *stdoutOut,
+ std::string *stderrOut,
+ int *exitCodeOut)
+{
+ if (args.size() == 0 || args.back() != nullptr)
+ {
+ return false;
+ }
+
+ ScopedPipe stdoutPipe;
+ ScopedPipe stderrPipe;
+
+ // Create pipes for stdout and stderr.
+ if (stdoutOut && pipe(stdoutPipe.fds) != 0)
+ {
+ return false;
+ }
+ if (stderrOut && pipe(stderrPipe.fds) != 0)
+ {
+ return false;
+ }
+
+ pid_t pid = fork();
+ if (pid < 0)
+ {
+ return false;
+ }
+
+ if (pid == 0)
+ {
+ // Child. Execute the application.
+
+ // Redirect stdout and stderr to the pipe fds.
+ if (stdoutOut)
+ {
+ if (dup2(stdoutPipe.fds[1], STDOUT_FILENO) < 0)
+ {
+ _exit(errno);
+ }
+ }
+ if (stderrOut)
+ {
+ if (dup2(stderrPipe.fds[1], STDERR_FILENO) < 0)
+ {
+ _exit(errno);
+ }
+ }
+
+ // Execute the application, which doesn't return unless failed. Note: execv takes argv as
+ // `char * const *` for historical reasons. It is safe to const_cast it:
+ //
+ // http://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html
+ //
+ // > The statement about argv[] and envp[] being constants is included to make explicit to
+ // future writers of language bindings that these objects are completely constant. Due to a
+ // limitation of the ISO C standard, it is not possible to state that idea in standard C.
+ // Specifying two levels of const- qualification for the argv[] and envp[] parameters for
+ // the exec functions may seem to be the natural choice, given that these functions do not
+ // modify either the array of pointers or the characters to which the function points, but
+ // this would disallow existing correct code. Instead, only the array of pointers is noted
+ // as constant.
+ execv(args[0], const_cast<char *const *>(args.data()));
+ _exit(errno);
+ }
+
+ // Parent. Read child output from the pipes and clean it up.
+
+ // Close the write end of the pipes, so EOF can be generated when child exits.
+ stdoutPipe.closeEndPoint(1);
+ stderrPipe.closeEndPoint(1);
+
+ // Read back the output of the child.
+ if (stdoutOut)
+ {
+ ReadEntireFile(stdoutPipe.fds[0], stdoutOut);
+ }
+ if (stderrOut)
+ {
+ ReadEntireFile(stderrPipe.fds[0], stderrOut);
+ }
+
+ // Cleanup the child.
+ int status = 0;
+ do
+ {
+ pid_t changedPid = waitpid(pid, &status, 0);
+ if (changedPid < 0 && errno == EINTR)
+ {
+ continue;
+ }
+ if (changedPid < 0)
+ {
+ return false;
+ }
+ } while (!WIFEXITED(status) && !WIFSIGNALED(status));
+
+ // Retrieve the error code.
+ if (exitCodeOut)
+ {
+ *exitCodeOut = WEXITSTATUS(status);
+ }
+
+ return true;
+}
+
+class PosixLibrary : public Library
+{
+ public:
+ PosixLibrary(const char *libraryName)
+ {
+ char buffer[1000];
+ int ret = snprintf(buffer, 1000, "%s.%s", libraryName, GetSharedLibraryExtension());
+ if (ret > 0 && ret < 1000)
+ {
+ mModule = dlopen(buffer, RTLD_NOW);
+ }
+ }
+
+ ~PosixLibrary() override
+ {
+ if (mModule)
+ {
+ dlclose(mModule);
+ }
+ }
+
+ void *getSymbol(const char *symbolName) override
+ {
+ if (!mModule)
+ {
+ return nullptr;
+ }
+
+ return dlsym(mModule, symbolName);
+ }
+
+ void *getNative() const override { return mModule; }
+
+ private:
+ void *mModule = nullptr;
+};
+
+Library *OpenSharedLibrary(const char *libraryName, SearchType searchType)
+{
+ return new PosixLibrary(libraryName);
+}
+
+bool IsDirectory(const char *filename)
+{
+ struct stat st;
+ int result = stat(filename, &st);
+ return result == 0 && ((st.st_mode & S_IFDIR) == S_IFDIR);
+}
+
+bool IsDebuggerAttached()
+{
+ // This could have a fuller implementation.
+ // See https://cs.chromium.org/chromium/src/base/debug/debugger_posix.cc
+ return false;
+}
+
+void BreakDebugger()
+{
+ // This could have a fuller implementation.
+ // See https://cs.chromium.org/chromium/src/base/debug/debugger_posix.cc
+ abort();
+}
+} // namespace angle