diff options
Diffstat (limited to 'gfx/angle/checkout/src/common/system_utils_posix.cpp')
-rw-r--r-- | gfx/angle/checkout/src/common/system_utils_posix.cpp | 276 |
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 |