Line data Source code
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 <sys/stat.h>
17 : #include <string.h>
18 : #endif
19 : #include "mozilla/UniquePtr.h"
20 : #include "mozilla/UniquePtrExtensions.h"
21 :
22 : #ifdef MOZILLA_INTERNAL_API
23 : #include "nsCOMPtr.h"
24 : #include "nsIFile.h"
25 : #include "nsString.h"
26 : #endif
27 :
28 : namespace mozilla {
29 :
30 : class BinaryPath
31 : {
32 : public:
33 : #ifdef XP_WIN
34 : static nsresult Get(const char* argv0, char aResult[MAXPATHLEN])
35 : {
36 : wchar_t wide_path[MAXPATHLEN];
37 : nsresult rv = GetW(argv0, wide_path);
38 : if (NS_FAILED(rv)) {
39 : return rv;
40 : }
41 : WideCharToMultiByte(CP_UTF8, 0, wide_path, -1,
42 : aResult, MAXPATHLEN, nullptr, nullptr);
43 : return NS_OK;
44 : }
45 :
46 : static nsresult GetLong(wchar_t aResult[MAXPATHLEN])
47 : {
48 : static bool cached = false;
49 : static wchar_t exeLongPath[MAXPATHLEN] = L"";
50 :
51 : if (!cached) {
52 : nsresult rv = GetW(nullptr, exeLongPath);
53 :
54 : if (NS_FAILED(rv)) {
55 : return rv;
56 : }
57 :
58 : if (!::GetLongPathNameW(exeLongPath, exeLongPath, MAXPATHLEN)) {
59 : return NS_ERROR_FAILURE;
60 : }
61 :
62 : cached = true;
63 : }
64 :
65 : if (wcscpy_s(aResult, MAXPATHLEN, exeLongPath)) {
66 : return NS_ERROR_FAILURE;
67 : }
68 :
69 : return NS_OK;
70 : }
71 :
72 : private:
73 : static nsresult GetW(const char* argv0, wchar_t aResult[MAXPATHLEN])
74 : {
75 : static bool cached = false;
76 : static wchar_t moduleFileName[MAXPATHLEN] = L"";
77 :
78 : if (!cached) {
79 : if (!::GetModuleFileNameW(0, moduleFileName, MAXPATHLEN)) {
80 : return NS_ERROR_FAILURE;
81 : }
82 :
83 : cached = true;
84 : }
85 :
86 : if (wcscpy_s(aResult, MAXPATHLEN, moduleFileName)) {
87 : return NS_ERROR_FAILURE;
88 : }
89 :
90 : return NS_OK;
91 : }
92 :
93 : #elif defined(XP_MACOSX)
94 : static nsresult Get(const char* argv0, char aResult[MAXPATHLEN])
95 : {
96 : // Works even if we're not bundled.
97 : CFBundleRef appBundle = CFBundleGetMainBundle();
98 : if (!appBundle) {
99 : return NS_ERROR_FAILURE;
100 : }
101 :
102 : CFURLRef executableURL = CFBundleCopyExecutableURL(appBundle);
103 : if (!executableURL) {
104 : return NS_ERROR_FAILURE;
105 : }
106 :
107 : nsresult rv;
108 : if (CFURLGetFileSystemRepresentation(executableURL, false, (UInt8*)aResult,
109 : MAXPATHLEN)) {
110 : // Sanitize path in case the app was launched from Terminal via
111 : // './firefox' for example.
112 : size_t readPos = 0;
113 : size_t writePos = 0;
114 : while (aResult[readPos] != '\0') {
115 : if (aResult[readPos] == '.' && aResult[readPos + 1] == '/') {
116 : readPos += 2;
117 : } else {
118 : aResult[writePos] = aResult[readPos];
119 : readPos++;
120 : writePos++;
121 : }
122 : }
123 : aResult[writePos] = '\0';
124 : rv = NS_OK;
125 : } else {
126 : rv = NS_ERROR_FAILURE;
127 : }
128 :
129 : CFRelease(executableURL);
130 : return rv;
131 : }
132 :
133 : #elif defined(ANDROID)
134 : static nsresult Get(const char* argv0, char aResult[MAXPATHLEN])
135 : {
136 : // On Android, we use the GRE_HOME variable that is set by the Java
137 : // bootstrap code.
138 : const char* greHome = getenv("GRE_HOME");
139 : #if defined(MOZ_WIDGET_GONK)
140 : if (!greHome) {
141 : greHome = "/system/b2g";
142 : }
143 : #endif
144 :
145 : if (!greHome) {
146 : return NS_ERROR_FAILURE;
147 : }
148 :
149 : snprintf(aResult, MAXPATHLEN, "%s/%s", greHome, "dummy");
150 : aResult[MAXPATHLEN - 1] = '\0';
151 : return NS_OK;
152 : }
153 :
154 : #elif defined(XP_UNIX)
155 13 : static nsresult Get(const char* aArgv0, char aResult[MAXPATHLEN])
156 : {
157 : struct stat fileStat;
158 : // on unix, there is no official way to get the path of the current binary.
159 : // instead of using the MOZILLA_FIVE_HOME hack, which doesn't scale to
160 : // multiple applications, we will try a series of techniques:
161 : //
162 : // 1) use realpath() on argv[0], which works unless we're loaded from the
163 : // PATH. Only do so if argv[0] looks like a path (contains a /).
164 : // 2) manually walk through the PATH and look for ourself
165 : // 3) give up
166 26 : if (strchr(aArgv0, '/') && realpath(aArgv0, aResult) &&
167 13 : stat(aResult, &fileStat) == 0) {
168 13 : return NS_OK;
169 : }
170 :
171 0 : const char* path = getenv("PATH");
172 0 : if (!path) {
173 0 : return NS_ERROR_FAILURE;
174 : }
175 :
176 0 : char* pathdup = strdup(path);
177 0 : if (!pathdup) {
178 0 : return NS_ERROR_OUT_OF_MEMORY;
179 : }
180 :
181 0 : bool found = false;
182 0 : char* token = strtok(pathdup, ":");
183 0 : while (token) {
184 : char tmpPath[MAXPATHLEN];
185 0 : sprintf(tmpPath, "%s/%s", token, aArgv0);
186 0 : if (realpath(tmpPath, aResult) && stat(aResult, &fileStat) == 0) {
187 0 : found = true;
188 0 : break;
189 : }
190 0 : token = strtok(nullptr, ":");
191 : }
192 0 : free(pathdup);
193 0 : if (found) {
194 0 : return NS_OK;
195 : }
196 0 : return NS_ERROR_FAILURE;
197 : }
198 :
199 : #else
200 : #error Oops, you need platform-specific code here
201 : #endif
202 :
203 : public:
204 3 : static UniqueFreePtr<char> Get(const char *aArgv0)
205 : {
206 : char path[MAXPATHLEN];
207 3 : if (NS_FAILED(Get(aArgv0, path))) {
208 0 : return nullptr;
209 : }
210 6 : UniqueFreePtr<char> result;
211 3 : result.reset(strdup(path));
212 3 : return result;
213 : }
214 :
215 : #ifdef MOZILLA_INTERNAL_API
216 10 : static nsresult GetFile(const char* aArgv0, nsIFile** aResult)
217 : {
218 20 : nsCOMPtr<nsIFile> lf;
219 : #ifdef XP_WIN
220 : wchar_t exePath[MAXPATHLEN];
221 : nsresult rv = GetW(aArgv0, exePath);
222 : #else
223 : char exePath[MAXPATHLEN];
224 10 : nsresult rv = Get(aArgv0, exePath);
225 : #endif
226 10 : if (NS_FAILED(rv)) {
227 0 : return rv;
228 : }
229 : #ifdef XP_WIN
230 : rv = NS_NewLocalFile(nsDependentString(exePath), true,
231 : getter_AddRefs(lf));
232 : #else
233 20 : rv = NS_NewNativeLocalFile(nsDependentCString(exePath), true,
234 30 : getter_AddRefs(lf));
235 : #endif
236 10 : if (NS_FAILED(rv)) {
237 0 : return rv;
238 : }
239 10 : NS_ADDREF(*aResult = lf);
240 10 : return NS_OK;
241 : }
242 : #endif
243 : };
244 :
245 : } // namespace mozilla
246 :
247 : #endif /* mozilla_BinaryPath_h */
|