• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 The Dawn Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "common/SystemUtils.h"
16 
17 #include "common/Assert.h"
18 #include "common/Log.h"
19 
20 #if defined(DAWN_PLATFORM_WINDOWS)
21 #    include <Windows.h>
22 #    include <vector>
23 #elif defined(DAWN_PLATFORM_LINUX)
24 #    include <dlfcn.h>
25 #    include <limits.h>
26 #    include <unistd.h>
27 #    include <cstdlib>
28 #elif defined(DAWN_PLATFORM_MACOS) || defined(DAWN_PLATFORM_IOS)
29 #    include <dlfcn.h>
30 #    include <mach-o/dyld.h>
31 #    include <vector>
32 #endif
33 
34 #include <array>
35 
36 #if defined(DAWN_PLATFORM_WINDOWS)
GetPathSeparator()37 const char* GetPathSeparator() {
38     return "\\";
39 }
40 
GetEnvironmentVar(const char * variableName)41 std::pair<std::string, bool> GetEnvironmentVar(const char* variableName) {
42     // First pass a size of 0 to get the size of variable value.
43     DWORD sizeWithNullTerminator = GetEnvironmentVariableA(variableName, nullptr, 0);
44     if (sizeWithNullTerminator == 0) {
45         DWORD err = GetLastError();
46         if (err != ERROR_ENVVAR_NOT_FOUND) {
47             dawn::WarningLog() << "GetEnvironmentVariableA failed with code " << err;
48         }
49         return std::make_pair(std::string(), false);
50     }
51 
52     // Then get variable value with its actual size.
53     std::vector<char> buffer(sizeWithNullTerminator);
54     DWORD sizeStored =
55         GetEnvironmentVariableA(variableName, buffer.data(), static_cast<DWORD>(buffer.size()));
56     if (sizeStored + 1 != sizeWithNullTerminator) {
57         DWORD err = GetLastError();
58         if (err) {
59             dawn::WarningLog() << "GetEnvironmentVariableA failed with code " << err;
60         }
61         return std::make_pair(std::string(), false);
62     }
63     return std::make_pair(std::string(buffer.data(), sizeStored), true);
64 }
65 
SetEnvironmentVar(const char * variableName,const char * value)66 bool SetEnvironmentVar(const char* variableName, const char* value) {
67     return SetEnvironmentVariableA(variableName, value) == TRUE;
68 }
69 #elif defined(DAWN_PLATFORM_POSIX)
GetPathSeparator()70 const char* GetPathSeparator() {
71     return "/";
72 }
73 
GetEnvironmentVar(const char * variableName)74 std::pair<std::string, bool> GetEnvironmentVar(const char* variableName) {
75     char* value = getenv(variableName);
76     return value == nullptr ? std::make_pair(std::string(), false)
77                             : std::make_pair(std::string(value), true);
78 }
79 
SetEnvironmentVar(const char * variableName,const char * value)80 bool SetEnvironmentVar(const char* variableName, const char* value) {
81     if (value == nullptr) {
82         return unsetenv(variableName) == 0;
83     }
84     return setenv(variableName, value, 1) == 0;
85 }
86 #else
87 #    error "Implement Get/SetEnvironmentVar for your platform."
88 #endif
89 
90 #if defined(DAWN_PLATFORM_WINDOWS)
GetExecutablePath()91 std::string GetExecutablePath() {
92     std::array<char, MAX_PATH> executableFileBuf;
93     DWORD executablePathLen = GetModuleFileNameA(nullptr, executableFileBuf.data(),
94                                                  static_cast<DWORD>(executableFileBuf.size()));
95     return executablePathLen > 0 ? std::string(executableFileBuf.data()) : "";
96 }
97 #elif defined(DAWN_PLATFORM_LINUX)
GetExecutablePath()98 std::string GetExecutablePath() {
99     std::array<char, PATH_MAX> path;
100     ssize_t result = readlink("/proc/self/exe", path.data(), PATH_MAX - 1);
101     if (result < 0 || static_cast<size_t>(result) >= PATH_MAX - 1) {
102         return "";
103     }
104 
105     path[result] = '\0';
106     return path.data();
107 }
108 #elif defined(DAWN_PLATFORM_MACOS) || defined(DAWN_PLATFORM_IOS)
GetExecutablePath()109 std::string GetExecutablePath() {
110     uint32_t size = 0;
111     _NSGetExecutablePath(nullptr, &size);
112 
113     std::vector<char> buffer(size + 1);
114     if (_NSGetExecutablePath(buffer.data(), &size) != 0) {
115         return "";
116     }
117 
118     buffer[size] = '\0';
119     return buffer.data();
120 }
121 #elif defined(DAWN_PLATFORM_FUCHSIA)
GetExecutablePath()122 std::string GetExecutablePath() {
123     // TODO: Implement on Fuchsia
124     return "";
125 }
126 #elif defined(DAWN_PLATFORM_EMSCRIPTEN)
GetExecutablePath()127 std::string GetExecutablePath() {
128     UNREACHABLE();
129     return "";
130 }
131 #else
132 #    error "Implement GetExecutablePath for your platform."
133 #endif
134 
GetExecutableDirectory()135 std::string GetExecutableDirectory() {
136     std::string exePath = GetExecutablePath();
137     size_t lastPathSepLoc = exePath.find_last_of(GetPathSeparator());
138     return lastPathSepLoc != std::string::npos ? exePath.substr(0, lastPathSepLoc + 1) : "";
139 }
140 
141 #if defined(DAWN_PLATFORM_LINUX) || defined(DAWN_PLATFORM_MACOS) || defined(DAWN_PLATFORM_IOS)
GetModulePath()142 std::string GetModulePath() {
143     static int placeholderSymbol = 0;
144     Dl_info dlInfo;
145     if (dladdr(&placeholderSymbol, &dlInfo) == 0) {
146         return "";
147     }
148 
149     std::array<char, PATH_MAX> absolutePath;
150     if (realpath(dlInfo.dli_fname, absolutePath.data()) == NULL) {
151         return "";
152     }
153     return absolutePath.data();
154 }
155 #elif defined(DAWN_PLATFORM_WINDOWS)
GetModulePath()156 std::string GetModulePath() {
157     UNREACHABLE();
158     return "";
159 }
160 #elif defined(DAWN_PLATFORM_FUCHSIA)
GetModulePath()161 std::string GetModulePath() {
162     UNREACHABLE();
163     return "";
164 }
165 #elif defined(DAWN_PLATFORM_EMSCRIPTEN)
GetModulePath()166 std::string GetModulePath() {
167     UNREACHABLE();
168     return "";
169 }
170 #else
171 #    error "Implement GetModulePath for your platform."
172 #endif
173 
GetModuleDirectory()174 std::string GetModuleDirectory() {
175     std::string modPath = GetModulePath();
176     size_t lastPathSepLoc = modPath.find_last_of(GetPathSeparator());
177     return lastPathSepLoc != std::string::npos ? modPath.substr(0, lastPathSepLoc + 1) : "";
178 }
179 
180 // ScopedEnvironmentVar
181 
ScopedEnvironmentVar(const char * variableName,const char * value)182 ScopedEnvironmentVar::ScopedEnvironmentVar(const char* variableName, const char* value)
183     : mName(variableName),
184       mOriginalValue(GetEnvironmentVar(variableName)),
185       mIsSet(SetEnvironmentVar(variableName, value)) {
186 }
187 
~ScopedEnvironmentVar()188 ScopedEnvironmentVar::~ScopedEnvironmentVar() {
189     if (mIsSet) {
190         bool success = SetEnvironmentVar(
191             mName.c_str(), mOriginalValue.second ? mOriginalValue.first.c_str() : nullptr);
192         // If we set the environment variable in the constructor, we should never fail restoring it.
193         ASSERT(success);
194     }
195 }
196 
Set(const char * variableName,const char * value)197 bool ScopedEnvironmentVar::Set(const char* variableName, const char* value) {
198     ASSERT(!mIsSet);
199     mName = variableName;
200     mOriginalValue = GetEnvironmentVar(variableName);
201     mIsSet = SetEnvironmentVar(variableName, value);
202     return mIsSet;
203 }
204