blob: 745cf399fdf6cdc43c688cff92d6a8da3d97e368 [file] [log] [blame]
//
// 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 <iostream>
#include <dlfcn.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
namespace angle
{
namespace
{
std::string GetModulePath(void *moduleOrSymbol)
{
Dl_info dlInfo;
if (dladdr(moduleOrSymbol, &dlInfo) == 0)
{
return "";
}
return dlInfo.dli_fname;
}
} // 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 *GetPathSeparatorForEnvironmentVar()
{
return ":";
}
std::string GetModuleDirectory()
{
std::string directory;
static int placeholderSymbol = 0;
std::string moduleName = GetModulePath(&placeholderSymbol);
if (!moduleName.empty())
{
directory = moduleName.substr(0, moduleName.find_last_of('/') + 1);
}
// Ensure we return the full path to the module, not the relative path
Optional<std::string> cwd = GetCWD();
if (cwd.valid() && !IsFullPath(directory))
{
directory = ConcatenatePath(cwd.value(), directory);
}
return directory;
}
class PosixLibrary : public Library
{
public:
PosixLibrary(const std::string &fullPath, int extraFlags)
: mModule(dlopen(fullPath.c_str(), RTLD_NOW | extraFlags))
{}
~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; }
std::string getPath() const override
{
if (!mModule)
{
return "";
}
return GetModulePath(mModule);
}
private:
void *mModule = nullptr;
};
Library *OpenSharedLibrary(const char *libraryName, SearchType searchType)
{
std::string libraryWithExtension = std::string(libraryName) + "." + GetSharedLibraryExtension();
return OpenSharedLibraryWithExtension(libraryWithExtension.c_str(), searchType);
}
Library *OpenSharedLibraryWithExtension(const char *libraryName, SearchType searchType)
{
std::string directory;
if (searchType == SearchType::ModuleDir)
{
#if ANGLE_PLATFORM_IOS
// On iOS, shared libraries must be loaded from within the app bundle.
directory = GetExecutableDirectory() + "/Frameworks/";
#else
directory = GetModuleDirectory();
#endif
}
int extraFlags = 0;
if (searchType == SearchType::AlreadyLoaded)
{
extraFlags = RTLD_NOLOAD;
}
std::string fullPath = directory + libraryName;
#if ANGLE_PLATFORM_IOS
// On iOS, dlopen needs a suffix on the framework name to work.
fullPath = fullPath + "/" + libraryName;
#endif
return new PosixLibrary(fullPath, extraFlags);
}
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();
}
const char *GetExecutableExtension()
{
return "";
}
char GetPathSeparator()
{
return '/';
}
std::string GetRootDirectory()
{
return "/";
}
} // namespace angle