| |
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
| |
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
| |
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
| |
4 |
| |
5 #ifndef mozilla_BinaryPath_h |
| |
6 #define mozilla_BinaryPath_h |
| |
7 |
| |
8 #include "nsXPCOMPrivate.h" // for MAXPATHLEN |
| |
9 #ifdef XP_WIN |
| |
10 #include <windows.h> |
| |
11 #elif defined(XP_MACOSX) |
| |
12 #include <CoreFoundation/CoreFoundation.h> |
| |
13 #elif defined(XP_UNIX) |
| |
14 #include <sys/stat.h> |
| |
15 #include <string.h> |
| |
16 #endif |
| |
17 |
| |
18 namespace mozilla { |
| |
19 |
| |
20 class BinaryPath { |
| |
21 public: |
| |
22 #ifdef XP_WIN |
| |
23 static nsresult Get(const char *argv0, char aResult[MAXPATHLEN]) |
| |
24 { |
| |
25 wchar_t wide_path[MAXPATHLEN]; |
| |
26 nsresult rv = GetW(argv0, wide_path); |
| |
27 if (NS_FAILED(rv)) |
| |
28 return rv; |
| |
29 WideCharToMultiByte(CP_UTF8, 0, wide_path, -1, |
| |
30 aResult, MAXPATHLEN, nullptr, nullptr); |
| |
31 return NS_OK; |
| |
32 } |
| |
33 |
| |
34 private: |
| |
35 static nsresult GetW(const char *argv0, wchar_t aResult[MAXPATHLEN]) |
| |
36 { |
| |
37 if (::GetModuleFileNameW(0, aResult, MAXPATHLEN)) |
| |
38 return NS_OK; |
| |
39 return NS_ERROR_FAILURE; |
| |
40 } |
| |
41 |
| |
42 #elif defined(XP_MACOSX) |
| |
43 static nsresult Get(const char *argv0, char aResult[MAXPATHLEN]) |
| |
44 { |
| |
45 // Works even if we're not bundled. |
| |
46 CFBundleRef appBundle = CFBundleGetMainBundle(); |
| |
47 if (!appBundle) |
| |
48 return NS_ERROR_FAILURE; |
| |
49 |
| |
50 CFURLRef executableURL = CFBundleCopyExecutableURL(appBundle); |
| |
51 if (!executableURL) |
| |
52 return NS_ERROR_FAILURE; |
| |
53 |
| |
54 nsresult rv; |
| |
55 if (CFURLGetFileSystemRepresentation(executableURL, false, (UInt8 *)aResult, MAXPATHLEN)) |
| |
56 rv = NS_OK; |
| |
57 else |
| |
58 rv = NS_ERROR_FAILURE; |
| |
59 CFRelease(executableURL); |
| |
60 return rv; |
| |
61 } |
| |
62 |
| |
63 #elif defined(ANDROID) |
| |
64 static nsresult Get(const char *argv0, char aResult[MAXPATHLEN]) |
| |
65 { |
| |
66 // On Android, we use the GRE_HOME variable that is set by the Java |
| |
67 // bootstrap code. |
| |
68 const char *greHome = getenv("GRE_HOME"); |
| |
69 #if defined(MOZ_WIDGET_GONK) |
| |
70 if (!greHome) |
| |
71 greHome = "/system/b2g"; |
| |
72 #endif |
| |
73 |
| |
74 if (!greHome) |
| |
75 return NS_ERROR_FAILURE; |
| |
76 |
| |
77 snprintf(aResult, MAXPATHLEN, "%s/%s", greHome, "dummy"); |
| |
78 aResult[MAXPATHLEN-1] = '\0'; |
| |
79 return NS_OK; |
| |
80 } |
| |
81 |
| |
82 #elif defined(XP_UNIX) |
| |
83 static nsresult Get(const char *argv0, char aResult[MAXPATHLEN]) |
| |
84 { |
| |
85 struct stat fileStat; |
| |
86 // on unix, there is no official way to get the path of the current binary. |
| |
87 // instead of using the MOZILLA_FIVE_HOME hack, which doesn't scale to |
| |
88 // multiple applications, we will try a series of techniques: |
| |
89 // |
| |
90 // 1) use realpath() on argv[0], which works unless we're loaded from the |
| |
91 // PATH. Only do so if argv[0] looks like a path (contains a /). |
| |
92 // 2) manually walk through the PATH and look for ourself |
| |
93 // 3) give up |
| |
94 if (strchr(argv0, '/') && realpath(argv0, aResult) && |
| |
95 stat(aResult, &fileStat) == 0) |
| |
96 return NS_OK; |
| |
97 |
| |
98 const char *path = getenv("PATH"); |
| |
99 if (!path) |
| |
100 return NS_ERROR_FAILURE; |
| |
101 |
| |
102 char *pathdup = strdup(path); |
| |
103 if (!pathdup) |
| |
104 return NS_ERROR_OUT_OF_MEMORY; |
| |
105 |
| |
106 bool found = false; |
| |
107 char *token = strtok(pathdup, ":"); |
| |
108 while (token) { |
| |
109 char tmpPath[MAXPATHLEN]; |
| |
110 sprintf(tmpPath, "%s/%s", token, argv0); |
| |
111 if (realpath(tmpPath, aResult) && stat(aResult, &fileStat) == 0) { |
| |
112 found = true; |
| |
113 break; |
| |
114 } |
| |
115 token = strtok(nullptr, ":"); |
| |
116 } |
| |
117 free(pathdup); |
| |
118 if (found) |
| |
119 return NS_OK; |
| |
120 return NS_ERROR_FAILURE; |
| |
121 } |
| |
122 |
| |
123 #else |
| |
124 #error Oops, you need platform-specific code here |
| |
125 #endif |
| |
126 |
| |
127 public: |
| |
128 static nsresult GetFile(const char *argv0, nsIFile* *aResult) |
| |
129 { |
| |
130 nsCOMPtr<nsIFile> lf; |
| |
131 #ifdef XP_WIN |
| |
132 wchar_t exePath[MAXPATHLEN]; |
| |
133 nsresult rv = GetW(argv0, exePath); |
| |
134 #else |
| |
135 char exePath[MAXPATHLEN]; |
| |
136 nsresult rv = Get(argv0, exePath); |
| |
137 #endif |
| |
138 if (NS_FAILED(rv)) |
| |
139 return rv; |
| |
140 #ifdef XP_WIN |
| |
141 rv = NS_NewLocalFile(nsDependentString(exePath), true, |
| |
142 getter_AddRefs(lf)); |
| |
143 #else |
| |
144 rv = NS_NewNativeLocalFile(nsDependentCString(exePath), true, |
| |
145 getter_AddRefs(lf)); |
| |
146 #endif |
| |
147 if (NS_FAILED(rv)) |
| |
148 return rv; |
| |
149 NS_ADDREF(*aResult = lf); |
| |
150 return NS_OK; |
| |
151 } |
| |
152 }; |
| |
153 |
| |
154 } |
| |
155 |
| |
156 #endif /* mozilla_BinaryPath_h */ |