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/. */
7 #ifndef mozilla_BinaryPath_h
8 #define mozilla_BinaryPath_h
10 #include "nsXPCOMPrivate.h" // for MAXPATHLEN
13 #elif defined(XP_MACOSX)
14 # include <CoreFoundation/CoreFoundation.h>
15 #elif defined(XP_UNIX)
20 #if defined(__FreeBSD__) || defined(__DragonFly__) || \
21 defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__)
22 # include <sys/sysctl.h>
24 #if defined(__OpenBSD__)
25 # include <sys/stat.h>
27 #include "mozilla/UniquePtr.h"
28 #include "mozilla/UniquePtrExtensions.h"
30 #ifdef MOZILLA_INTERNAL_API
31 # include "nsCOMPtr.h"
33 # include "nsString.h"
41 static nsresult
Get(char aResult
[MAXPATHLEN
]) {
42 wchar_t wide_path
[MAXPATHLEN
];
43 nsresult rv
= GetW(wide_path
);
47 WideCharToMultiByte(CP_UTF8
, 0, wide_path
, -1, aResult
, MAXPATHLEN
, nullptr,
52 static nsresult
GetLong(wchar_t aResult
[MAXPATHLEN
]) {
53 static bool cached
= false;
54 static wchar_t exeLongPath
[MAXPATHLEN
] = L
"";
57 nsresult rv
= GetW(exeLongPath
);
63 if (!::GetLongPathNameW(exeLongPath
, exeLongPath
, MAXPATHLEN
)) {
64 return NS_ERROR_FAILURE
;
70 if (wcscpy_s(aResult
, MAXPATHLEN
, exeLongPath
)) {
71 return NS_ERROR_FAILURE
;
78 static nsresult
GetW(wchar_t aResult
[MAXPATHLEN
]) {
79 static bool cached
= false;
80 static wchar_t moduleFileName
[MAXPATHLEN
] = L
"";
83 if (!::GetModuleFileNameW(0, moduleFileName
, MAXPATHLEN
)) {
84 return NS_ERROR_FAILURE
;
90 if (wcscpy_s(aResult
, MAXPATHLEN
, moduleFileName
)) {
91 return NS_ERROR_FAILURE
;
97 #elif defined(XP_MACOSX)
98 static nsresult
Get(char aResult
[MAXPATHLEN
]) {
99 // Works even if we're not bundled.
100 CFBundleRef appBundle
= CFBundleGetMainBundle();
102 return NS_ERROR_FAILURE
;
105 CFURLRef executableURL
= CFBundleCopyExecutableURL(appBundle
);
106 if (!executableURL
) {
107 return NS_ERROR_FAILURE
;
111 if (CFURLGetFileSystemRepresentation(executableURL
, false, (UInt8
*)aResult
,
113 // Sanitize path in case the app was launched from Terminal via
114 // './firefox' for example.
117 while (aResult
[readPos
] != '\0') {
118 if (aResult
[readPos
] == '.' && aResult
[readPos
+ 1] == '/') {
121 aResult
[writePos
] = aResult
[readPos
];
126 aResult
[writePos
] = '\0';
129 rv
= NS_ERROR_FAILURE
;
132 CFRelease(executableURL
);
136 #elif defined(ANDROID)
137 static nsresult
Get(char aResult
[MAXPATHLEN
]) {
138 // On Android, we use the MOZ_ANDROID_LIBDIR variable that is set by the
139 // Java bootstrap code.
140 const char* libDir
= getenv("MOZ_ANDROID_LIBDIR");
142 return NS_ERROR_FAILURE
;
145 snprintf(aResult
, MAXPATHLEN
, "%s/%s", libDir
, "dummy");
146 aResult
[MAXPATHLEN
- 1] = '\0';
150 #elif defined(XP_LINUX) || defined(XP_SOLARIS)
151 static nsresult
Get(char aResult
[MAXPATHLEN
]) {
152 # if defined(XP_SOLARIS)
153 const char path
[] = "/proc/self/path/a.out";
155 const char path
[] = "/proc/self/exe";
158 ssize_t len
= readlink(path
, aResult
, MAXPATHLEN
- 1);
160 return NS_ERROR_FAILURE
;
163 # if defined(XP_LINUX)
164 // Removing suffix " (deleted)" from the binary path
165 const char suffix
[] = " (deleted)";
166 const ssize_t suffix_len
= sizeof(suffix
);
167 if (len
>= suffix_len
) {
168 char* result_end
= &aResult
[len
- (suffix_len
- 1)];
169 if (memcmp(result_end
, suffix
, suffix_len
) == 0) {
177 #elif defined(__FreeBSD__) || defined(__DragonFly__) || \
178 defined(__FreeBSD_kernel__) || defined(__NetBSD__)
179 static nsresult
Get(char aResult
[MAXPATHLEN
]) {
183 mib
[1] = KERN_PROC_ARGS
;
185 mib
[3] = KERN_PROC_PATHNAME
;
188 mib
[2] = KERN_PROC_PATHNAME
;
192 size_t len
= MAXPATHLEN
;
193 if (sysctl(mib
, 4, aResult
, &len
, nullptr, 0) < 0) {
194 return NS_ERROR_FAILURE
;
200 #elif defined(__OpenBSD__)
201 static nsresult
Get(char aResult
[MAXPATHLEN
]) {
202 static bool cached
= false;
203 static char cachedPath
[MAXPATHLEN
];
207 if (strlcpy(aResult
, cachedPath
, MAXPATHLEN
) >= MAXPATHLEN
) {
208 return NS_ERROR_FAILURE
;
213 mib
[1] = KERN_PROC_ARGS
;
215 mib
[3] = KERN_PROC_ARGV
;
218 if (sysctl(mib
, 4, nullptr, &len
, nullptr, 0) < 0) {
219 return NS_ERROR_FAILURE
;
222 auto argv
= MakeUnique
<const char*[]>(len
/ sizeof(const char*));
223 if (sysctl(mib
, 4, argv
.get(), &len
, nullptr, 0) < 0) {
224 return NS_ERROR_FAILURE
;
227 r
= GetFromArgv0(argv
[0], aResult
);
228 if (NS_SUCCEEDED(r
)) {
229 if (strlcpy(cachedPath
, aResult
, MAXPATHLEN
) >= MAXPATHLEN
) {
230 return NS_ERROR_FAILURE
;
237 static nsresult
GetFromArgv0(const char* aArgv0
, char aResult
[MAXPATHLEN
]) {
238 struct stat fileStat
;
239 // 1) use realpath() on argv[0], which works unless we're loaded from the
240 // PATH. Only do so if argv[0] looks like a path (contains a /).
241 // 2) manually walk through the PATH and look for ourself
243 if (strchr(aArgv0
, '/') && realpath(aArgv0
, aResult
) &&
244 stat(aResult
, &fileStat
) == 0) {
248 const char* path
= getenv("PATH");
250 return NS_ERROR_FAILURE
;
253 char* pathdup
= strdup(path
);
255 return NS_ERROR_OUT_OF_MEMORY
;
259 char* token
= strtok(pathdup
, ":");
261 char tmpPath
[MAXPATHLEN
];
262 sprintf(tmpPath
, "%s/%s", token
, aArgv0
);
263 if (realpath(tmpPath
, aResult
) && stat(aResult
, &fileStat
) == 0) {
267 token
= strtok(nullptr, ":");
273 return NS_ERROR_FAILURE
;
277 # error Oops, you need platform-specific code here
281 static UniqueFreePtr
<char> Get() {
282 char path
[MAXPATHLEN
];
283 if (NS_FAILED(Get(path
))) {
286 UniqueFreePtr
<char> result
;
287 result
.reset(strdup(path
));
291 #ifdef MOZILLA_INTERNAL_API
292 static nsresult
GetFile(nsIFile
** aResult
) {
293 nsCOMPtr
<nsIFile
> lf
;
295 wchar_t exePath
[MAXPATHLEN
];
296 nsresult rv
= GetW(exePath
);
298 char exePath
[MAXPATHLEN
];
299 nsresult rv
= Get(exePath
);
305 rv
= NS_NewLocalFile(nsDependentString(exePath
), true, getter_AddRefs(lf
));
307 rv
= NS_NewNativeLocalFile(nsDependentCString(exePath
), true,
313 NS_ADDREF(*aResult
= lf
);
319 } // namespace mozilla
321 #endif /* mozilla_BinaryPath_h */