/src/mozilla-central/xpcom/build/BinaryPath.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
3 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | #ifndef mozilla_BinaryPath_h |
8 | | #define mozilla_BinaryPath_h |
9 | | |
10 | | #include "nsXPCOMPrivate.h" // for MAXPATHLEN |
11 | | #ifdef XP_WIN |
12 | | #include <windows.h> |
13 | | #elif defined(XP_MACOSX) |
14 | | #include <CoreFoundation/CoreFoundation.h> |
15 | | #elif defined(XP_UNIX) |
16 | | #include <unistd.h> |
17 | | #include <stdlib.h> |
18 | | #include <string.h> |
19 | | #endif |
20 | | #if defined(__FreeBSD__) || defined(__DragonFly__) || \ |
21 | | defined(__FreeBSD_kernel__) || defined(__NetBSD__) || \ |
22 | | defined(__OpenBSD__) |
23 | | #include <sys/sysctl.h> |
24 | | #endif |
25 | | #if defined(__OpenBSD__) |
26 | | #include <sys/stat.h> |
27 | | #endif |
28 | | #include "mozilla/UniquePtr.h" |
29 | | #include "mozilla/UniquePtrExtensions.h" |
30 | | |
31 | | #ifdef MOZILLA_INTERNAL_API |
32 | | #include "nsCOMPtr.h" |
33 | | #include "nsIFile.h" |
34 | | #include "nsString.h" |
35 | | #endif |
36 | | |
37 | | namespace mozilla { |
38 | | |
39 | | class BinaryPath |
40 | | { |
41 | | public: |
42 | | #ifdef XP_WIN |
43 | | static nsresult Get(char aResult[MAXPATHLEN]) |
44 | | { |
45 | | wchar_t wide_path[MAXPATHLEN]; |
46 | | nsresult rv = GetW(wide_path); |
47 | | if (NS_FAILED(rv)) { |
48 | | return rv; |
49 | | } |
50 | | WideCharToMultiByte(CP_UTF8, 0, wide_path, -1, |
51 | | aResult, MAXPATHLEN, nullptr, nullptr); |
52 | | return NS_OK; |
53 | | } |
54 | | |
55 | | static nsresult GetLong(wchar_t aResult[MAXPATHLEN]) |
56 | | { |
57 | | static bool cached = false; |
58 | | static wchar_t exeLongPath[MAXPATHLEN] = L""; |
59 | | |
60 | | if (!cached) { |
61 | | nsresult rv = GetW(exeLongPath); |
62 | | |
63 | | if (NS_FAILED(rv)) { |
64 | | return rv; |
65 | | } |
66 | | |
67 | | if (!::GetLongPathNameW(exeLongPath, exeLongPath, MAXPATHLEN)) { |
68 | | return NS_ERROR_FAILURE; |
69 | | } |
70 | | |
71 | | cached = true; |
72 | | } |
73 | | |
74 | | if (wcscpy_s(aResult, MAXPATHLEN, exeLongPath)) { |
75 | | return NS_ERROR_FAILURE; |
76 | | } |
77 | | |
78 | | return NS_OK; |
79 | | } |
80 | | |
81 | | private: |
82 | | static nsresult GetW(wchar_t aResult[MAXPATHLEN]) |
83 | | { |
84 | | static bool cached = false; |
85 | | static wchar_t moduleFileName[MAXPATHLEN] = L""; |
86 | | |
87 | | if (!cached) { |
88 | | if (!::GetModuleFileNameW(0, moduleFileName, MAXPATHLEN)) { |
89 | | return NS_ERROR_FAILURE; |
90 | | } |
91 | | |
92 | | cached = true; |
93 | | } |
94 | | |
95 | | if (wcscpy_s(aResult, MAXPATHLEN, moduleFileName)) { |
96 | | return NS_ERROR_FAILURE; |
97 | | } |
98 | | |
99 | | return NS_OK; |
100 | | } |
101 | | |
102 | | #elif defined(XP_MACOSX) |
103 | | static nsresult Get(char aResult[MAXPATHLEN]) |
104 | | { |
105 | | // Works even if we're not bundled. |
106 | | CFBundleRef appBundle = CFBundleGetMainBundle(); |
107 | | if (!appBundle) { |
108 | | return NS_ERROR_FAILURE; |
109 | | } |
110 | | |
111 | | CFURLRef executableURL = CFBundleCopyExecutableURL(appBundle); |
112 | | if (!executableURL) { |
113 | | return NS_ERROR_FAILURE; |
114 | | } |
115 | | |
116 | | nsresult rv; |
117 | | if (CFURLGetFileSystemRepresentation(executableURL, false, (UInt8*)aResult, |
118 | | MAXPATHLEN)) { |
119 | | // Sanitize path in case the app was launched from Terminal via |
120 | | // './firefox' for example. |
121 | | size_t readPos = 0; |
122 | | size_t writePos = 0; |
123 | | while (aResult[readPos] != '\0') { |
124 | | if (aResult[readPos] == '.' && aResult[readPos + 1] == '/') { |
125 | | readPos += 2; |
126 | | } else { |
127 | | aResult[writePos] = aResult[readPos]; |
128 | | readPos++; |
129 | | writePos++; |
130 | | } |
131 | | } |
132 | | aResult[writePos] = '\0'; |
133 | | rv = NS_OK; |
134 | | } else { |
135 | | rv = NS_ERROR_FAILURE; |
136 | | } |
137 | | |
138 | | CFRelease(executableURL); |
139 | | return rv; |
140 | | } |
141 | | |
142 | | #elif defined(ANDROID) |
143 | | static nsresult Get(char aResult[MAXPATHLEN]) |
144 | | { |
145 | | // On Android, we use the GRE_HOME variable that is set by the Java |
146 | | // bootstrap code. |
147 | | const char* greHome = getenv("GRE_HOME"); |
148 | | if (!greHome) { |
149 | | return NS_ERROR_FAILURE; |
150 | | } |
151 | | |
152 | | snprintf(aResult, MAXPATHLEN, "%s/%s", greHome, "dummy"); |
153 | | aResult[MAXPATHLEN - 1] = '\0'; |
154 | | return NS_OK; |
155 | | } |
156 | | |
157 | | #elif defined(XP_LINUX) || defined(XP_SOLARIS) |
158 | | static nsresult Get(char aResult[MAXPATHLEN]) |
159 | 48 | { |
160 | | # if defined(XP_SOLARIS) |
161 | | const char path[] = "/proc/self/path/a.out"; |
162 | | # else |
163 | | const char path[] = "/proc/self/exe"; |
164 | 48 | # endif |
165 | 48 | |
166 | 48 | ssize_t len = readlink(path, aResult, MAXPATHLEN - 1); |
167 | 48 | if (len < 0) { |
168 | 0 | return NS_ERROR_FAILURE; |
169 | 0 | } |
170 | 48 | aResult[len] = '\0'; |
171 | 48 | return NS_OK; |
172 | 48 | } mozilla::BinaryPath::Get(char*) Line | Count | Source | 159 | 24 | { | 160 | | # if defined(XP_SOLARIS) | 161 | | const char path[] = "/proc/self/path/a.out"; | 162 | | # else | 163 | | const char path[] = "/proc/self/exe"; | 164 | 24 | # endif | 165 | 24 | | 166 | 24 | ssize_t len = readlink(path, aResult, MAXPATHLEN - 1); | 167 | 24 | if (len < 0) { | 168 | 0 | return NS_ERROR_FAILURE; | 169 | 0 | } | 170 | 24 | aResult[len] = '\0'; | 171 | 24 | return NS_OK; | 172 | 24 | } |
mozilla::BinaryPath::Get(char*) Line | Count | Source | 159 | 24 | { | 160 | | # if defined(XP_SOLARIS) | 161 | | const char path[] = "/proc/self/path/a.out"; | 162 | | # else | 163 | | const char path[] = "/proc/self/exe"; | 164 | 24 | # endif | 165 | 24 | | 166 | 24 | ssize_t len = readlink(path, aResult, MAXPATHLEN - 1); | 167 | 24 | if (len < 0) { | 168 | 0 | return NS_ERROR_FAILURE; | 169 | 0 | } | 170 | 24 | aResult[len] = '\0'; | 171 | 24 | return NS_OK; | 172 | 24 | } |
|
173 | | |
174 | | #elif defined(__FreeBSD__) || defined(__DragonFly__) || \ |
175 | | defined(__FreeBSD_kernel__) || defined(__NetBSD__) |
176 | | static nsresult Get(char aResult[MAXPATHLEN]) |
177 | | { |
178 | | int mib[4]; |
179 | | mib[0] = CTL_KERN; |
180 | | #ifdef __NetBSD__ |
181 | | mib[1] = KERN_PROC_ARGS; |
182 | | mib[2] = -1; |
183 | | mib[3] = KERN_PROC_PATHNAME; |
184 | | #else |
185 | | mib[1] = KERN_PROC; |
186 | | mib[2] = KERN_PROC_PATHNAME; |
187 | | mib[3] = -1; |
188 | | #endif |
189 | | |
190 | | size_t len = MAXPATHLEN; |
191 | | if (sysctl(mib, 4, aResult, &len, nullptr, 0) < 0) { |
192 | | return NS_ERROR_FAILURE; |
193 | | } |
194 | | |
195 | | return NS_OK; |
196 | | } |
197 | | |
198 | | #elif defined(__OpenBSD__) |
199 | | static nsresult Get(char aResult[MAXPATHLEN]) |
200 | | { |
201 | | int mib[4]; |
202 | | mib[0] = CTL_KERN; |
203 | | mib[1] = KERN_PROC_ARGS; |
204 | | mib[2] = getpid(); |
205 | | mib[3] = KERN_PROC_ARGV; |
206 | | |
207 | | size_t len = 0; |
208 | | if (sysctl(mib, 4, nullptr, &len, nullptr, 0) < 0) { |
209 | | return NS_ERROR_FAILURE; |
210 | | } |
211 | | |
212 | | auto argv = MakeUnique<const char*[]>(len / sizeof(const char*)); |
213 | | if (sysctl(mib, 4, argv.get(), &len, nullptr, 0) < 0) { |
214 | | return NS_ERROR_FAILURE; |
215 | | } |
216 | | |
217 | | return GetFromArgv0(argv[0], aResult); |
218 | | } |
219 | | |
220 | | static nsresult GetFromArgv0(const char* aArgv0, char aResult[MAXPATHLEN]) |
221 | | { |
222 | | struct stat fileStat; |
223 | | // 1) use realpath() on argv[0], which works unless we're loaded from the |
224 | | // PATH. Only do so if argv[0] looks like a path (contains a /). |
225 | | // 2) manually walk through the PATH and look for ourself |
226 | | // 3) give up |
227 | | if (strchr(aArgv0, '/') && realpath(aArgv0, aResult) && |
228 | | stat(aResult, &fileStat) == 0) { |
229 | | return NS_OK; |
230 | | } |
231 | | |
232 | | const char* path = getenv("PATH"); |
233 | | if (!path) { |
234 | | return NS_ERROR_FAILURE; |
235 | | } |
236 | | |
237 | | char* pathdup = strdup(path); |
238 | | if (!pathdup) { |
239 | | return NS_ERROR_OUT_OF_MEMORY; |
240 | | } |
241 | | |
242 | | bool found = false; |
243 | | char* token = strtok(pathdup, ":"); |
244 | | while (token) { |
245 | | char tmpPath[MAXPATHLEN]; |
246 | | sprintf(tmpPath, "%s/%s", token, aArgv0); |
247 | | if (realpath(tmpPath, aResult) && stat(aResult, &fileStat) == 0) { |
248 | | found = true; |
249 | | break; |
250 | | } |
251 | | token = strtok(nullptr, ":"); |
252 | | } |
253 | | free(pathdup); |
254 | | if (found) { |
255 | | return NS_OK; |
256 | | } |
257 | | return NS_ERROR_FAILURE; |
258 | | } |
259 | | |
260 | | #else |
261 | | #error Oops, you need platform-specific code here |
262 | | #endif |
263 | | |
264 | | public: |
265 | | static UniqueFreePtr<char> Get() |
266 | 3 | { |
267 | 3 | char path[MAXPATHLEN]; |
268 | 3 | if (NS_FAILED(Get(path))) { |
269 | 0 | return nullptr; |
270 | 0 | } |
271 | 3 | UniqueFreePtr<char> result; |
272 | 3 | result.reset(strdup(path)); |
273 | 3 | return result; |
274 | 3 | } |
275 | | |
276 | | #ifdef MOZILLA_INTERNAL_API |
277 | | static nsresult GetFile(nsIFile** aResult) |
278 | 21 | { |
279 | 21 | nsCOMPtr<nsIFile> lf; |
280 | | #ifdef XP_WIN |
281 | | wchar_t exePath[MAXPATHLEN]; |
282 | | nsresult rv = GetW(exePath); |
283 | | #else |
284 | | char exePath[MAXPATHLEN]; |
285 | 21 | nsresult rv = Get(exePath); |
286 | 21 | #endif |
287 | 21 | if (NS_FAILED(rv)) { |
288 | 0 | return rv; |
289 | 0 | } |
290 | | #ifdef XP_WIN |
291 | | rv = NS_NewLocalFile(nsDependentString(exePath), true, |
292 | | getter_AddRefs(lf)); |
293 | | #else |
294 | 21 | rv = NS_NewNativeLocalFile(nsDependentCString(exePath), true, |
295 | 21 | getter_AddRefs(lf)); |
296 | 21 | #endif |
297 | 21 | if (NS_FAILED(rv)) { |
298 | 0 | return rv; |
299 | 0 | } |
300 | 21 | NS_ADDREF(*aResult = lf); |
301 | 21 | return NS_OK; |
302 | 21 | } |
303 | | #endif |
304 | | }; |
305 | | |
306 | | } // namespace mozilla |
307 | | |
308 | | #endif /* mozilla_BinaryPath_h */ |