Coverage Report

Created: 2018-09-25 14:53

/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 */