Bug 1403366 - Stop requiring argv[0] for XRE_GetBinaryPath and the underlying BinaryPath::Get. r?froydnj draft
authorMike Hommey <mh+mozilla@glandium.org>
Thu, 28 Sep 2017 10:37:27 +0900
changeset 674064 5fdcd7c4abb417292a6f7f51a0d04d1c3c74c0ff
parent 674063 a2f9d45c2d3bccb64e5174e5858668e41e551614
child 674065 6f85deb33dc0d0da195bd82361155865f3569181
push id82722
push userbmo:mh+mozilla@glandium.org
push dateTue, 03 Oct 2017 06:57:08 +0000
reviewersfroydnj
bugs1403366
milestone58.0a1
Bug 1403366 - Stop requiring argv[0] for XRE_GetBinaryPath and the underlying BinaryPath::Get. r?froydnj
browser/app/nsBrowserApp.cpp
ipc/glue/ScopedXREEmbed.cpp
js/xpconnect/src/XPCShellImpl.cpp
toolkit/xre/nsAppRunner.cpp
toolkit/xre/nsUpdateDriver.cpp
toolkit/xre/nsXREDirProvider.cpp
xpcom/build/BinaryPath.h
xpcom/build/nsXULAppAPI.h
--- a/browser/app/nsBrowserApp.cpp
+++ b/browser/app/nsBrowserApp.cpp
@@ -227,19 +227,19 @@ static int do_main(int argc, char* argv[
   if (getenv("LIBFUZZER"))
     gBootstrap->XRE_LibFuzzerSetDriver(fuzzer::FuzzerDriver);
 #endif
 
   return gBootstrap->XRE_main(argc, argv, config);
 }
 
 static nsresult
-InitXPCOMGlue(const char *argv0)
+InitXPCOMGlue()
 {
-  UniqueFreePtr<char> exePath = BinaryPath::Get(argv0);
+  UniqueFreePtr<char> exePath = BinaryPath::Get();
   if (!exePath) {
     Output("Couldn't find the application directory.\n");
     return NS_ERROR_FAILURE;
   }
 
   gBootstrap = mozilla::GetBootstrap(exePath.get());
   if (!gBootstrap) {
     Output("Couldn't load XPCOM.\n");
@@ -267,17 +267,17 @@ int main(int argc, char* argv[], char* e
     // We need to initialize the sandbox TargetServices before InitXPCOMGlue
     // because we might need the sandbox broker to give access to some files.
     if (IsSandboxedProcess() && !sandboxing::GetInitializedTargetServices()) {
       Output("Failed to initialize the sandbox target services.");
       return 255;
     }
 #endif
 
-    nsresult rv = InitXPCOMGlue(argv[0]);
+    nsresult rv = InitXPCOMGlue();
     if (NS_FAILED(rv)) {
       return 255;
     }
 
     int result = content_process_main(gBootstrap.get(), argc, argv);
 
     // InitXPCOMGlue calls NS_LogInit, so we need to balance it here.
     gBootstrap->NS_LogTerm();
@@ -285,17 +285,17 @@ int main(int argc, char* argv[], char* e
     return result;
   }
 #endif
 
 #ifdef HAS_DLL_BLOCKLIST
   DllBlocklist_Initialize();
 #endif
 
-  nsresult rv = InitXPCOMGlue(argv[0]);
+  nsresult rv = InitXPCOMGlue();
   if (NS_FAILED(rv)) {
     return 255;
   }
 
   gBootstrap->XRE_StartupTimelineRecord(mozilla::StartupTimeline::START, start);
 
 #ifdef MOZ_BROWSER_CAN_BE_CONTENTPROC
   gBootstrap->XRE_EnableSameExecutableForContentProc();
--- a/ipc/glue/ScopedXREEmbed.cpp
+++ b/ipc/glue/ScopedXREEmbed.cpp
@@ -41,27 +41,18 @@ ScopedXREEmbed::SetAppDir(const nsACStri
     NS_WARNING("Invalid application directory passed to content process.");
     mAppDir = nullptr;
   }
 }
 
 void
 ScopedXREEmbed::Start()
 {
-  std::string path;
-#if defined(OS_WIN)
-  path = WideToUTF8(CommandLine::ForCurrentProcess()->program());
-#elif defined(OS_POSIX)
-  path = CommandLine::ForCurrentProcess()->argv()[0];
-#else
-#  error Sorry
-#endif
-
   nsCOMPtr<nsIFile> localFile;
-  nsresult rv = XRE_GetBinaryPath(path.c_str(), getter_AddRefs(localFile));
+  nsresult rv = XRE_GetBinaryPath(getter_AddRefs(localFile));
   if (NS_FAILED(rv))
     return;
 
   nsCOMPtr<nsIFile> parent;
   rv = localFile->GetParent(getter_AddRefs(parent));
   if (NS_FAILED(rv))
     return;
 
--- a/js/xpconnect/src/XPCShellImpl.cpp
+++ b/js/xpconnect/src/XPCShellImpl.cpp
@@ -1110,17 +1110,17 @@ XRE_XPCShellMain(int argc, char** argv, 
         printf_stderr("*** You are running in chaos test mode. See ChaosMode.h. ***\n");
     }
 
     // The provider needs to outlive the call to shutting down XPCOM.
     XPCShellDirProvider dirprovider;
 
     { // Start scoping nsCOMPtrs
         nsCOMPtr<nsIFile> appFile;
-        rv = XRE_GetBinaryPath(argv[0], getter_AddRefs(appFile));
+        rv = XRE_GetBinaryPath(getter_AddRefs(appFile));
         if (NS_FAILED(rv)) {
             printf("Couldn't find application file.\n");
             return 1;
         }
         nsCOMPtr<nsIFile> appDir;
         rv = appFile->GetParent(getter_AddRefs(appDir));
         if (NS_FAILED(rv)) {
             printf("Couldn't get application directory.\n");
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -1870,19 +1870,19 @@ StartRemoteClient(const char* aDesktopSt
 
 void
 XRE_InitOmnijar(nsIFile* greOmni, nsIFile* appOmni)
 {
   mozilla::Omnijar::Init(greOmni, appOmni);
 }
 
 nsresult
-XRE_GetBinaryPath(const char* argv0, nsIFile* *aResult)
+XRE_GetBinaryPath(nsIFile* *aResult)
 {
-  return mozilla::BinaryPath::GetFile(argv0, aResult);
+  return mozilla::BinaryPath::GetFile(aResult);
 }
 
 #ifdef XP_WIN
 #include "nsWindowsRestart.cpp"
 #include <shellapi.h>
 
 typedef BOOL (WINAPI* SetProcessDEPPolicyFunc)(DWORD dwFlags);
 #endif
@@ -1911,17 +1911,17 @@ static nsresult LaunchChild(nsINativeApp
   SaveToEnv("MOZ_LAUNCHED_CHILD=1");
 
 #if !defined(MOZ_WIDGET_ANDROID) // Android has separate restart code.
 #if defined(XP_MACOSX)
   CommandLineServiceMac::SetupMacCommandLine(gRestartArgc, gRestartArgv, true);
   LaunchChildMac(gRestartArgc, gRestartArgv);
 #else
   nsCOMPtr<nsIFile> lf;
-  nsresult rv = XRE_GetBinaryPath(gArgv[0], getter_AddRefs(lf));
+  nsresult rv = XRE_GetBinaryPath(getter_AddRefs(lf));
   if (NS_FAILED(rv))
     return rv;
 
 #if defined(XP_WIN)
   nsAutoString exePath;
   rv = lf->GetPath(exePath);
   if (NS_FAILED(rv))
     return rv;
@@ -4780,25 +4780,25 @@ XREMain::XRE_main(int argc, char* argv[]
 
   if (!mAppData->remotingName) {
     mAppData->remotingName = mAppData->name;
   }
   // used throughout this file
   gAppData = mAppData.get();
 
   nsCOMPtr<nsIFile> binFile;
-  rv = XRE_GetBinaryPath(argv[0], getter_AddRefs(binFile));
+  rv = XRE_GetBinaryPath(getter_AddRefs(binFile));
   NS_ENSURE_SUCCESS(rv, 1);
 
   rv = binFile->GetPath(gAbsoluteArgv0Path);
   NS_ENSURE_SUCCESS(rv, 1);
 
   if (!mAppData->xreDirectory) {
     nsCOMPtr<nsIFile> lf;
-    rv = XRE_GetBinaryPath(gArgv[0], getter_AddRefs(lf));
+    rv = XRE_GetBinaryPath(getter_AddRefs(lf));
     if (NS_FAILED(rv))
       return 2;
 
     nsCOMPtr<nsIFile> greDir;
     rv = lf->GetParent(getter_AddRefs(greDir));
     if (NS_FAILED(rv))
       return 2;
 
@@ -4971,17 +4971,17 @@ XRE_InitCommandLine(int aArgc, char* aAr
   CommandLine::Init(aArgc, aArgv);
 #else
 
   // these leak on error, but that's OK: we'll just exit()
   char** canonArgs = new char*[aArgc];
 
   // get the canonical version of the binary's path
   nsCOMPtr<nsIFile> binFile;
-  rv = XRE_GetBinaryPath(aArgv[0], getter_AddRefs(binFile));
+  rv = XRE_GetBinaryPath(getter_AddRefs(binFile));
   if (NS_FAILED(rv))
     return NS_ERROR_FAILURE;
 
   nsAutoCString canonBinPath;
   rv = binFile->GetNativePath(canonBinPath);
   if (NS_FAILED(rv))
     return NS_ERROR_FAILURE;
 
--- a/toolkit/xre/nsUpdateDriver.cpp
+++ b/toolkit/xre/nsUpdateDriver.cpp
@@ -503,17 +503,17 @@ ApplyUpdate(nsIFile *greDir, nsIFile *up
     rv = GetCurrentWorkingDir(workingDirPath, sizeof(workingDirPath));
     if (NS_FAILED(rv)) {
       return;
     }
 
     // Get the application file path used by the updater to restart the
     // application after the update has finished.
     nsCOMPtr<nsIFile> appFile;
-    XRE_GetBinaryPath(appArgv[0], getter_AddRefs(appFile));
+    XRE_GetBinaryPath(getter_AddRefs(appFile));
     if (!appFile) {
       return;
     }
 
 #if defined(XP_WIN)
     nsAutoString appFilePathW;
     rv = appFile->GetPath(appFilePathW);
     if (NS_FAILED(rv)) {
--- a/toolkit/xre/nsXREDirProvider.cpp
+++ b/toolkit/xre/nsXREDirProvider.cpp
@@ -421,19 +421,19 @@ nsXREDirProvider::GetFile(const char* aP
       rv = file->AppendNative(NS_LITERAL_CSTRING(APP_REGISTRY_NAME));
   }
   else if (!strcmp(aProperty, NS_APP_USER_PROFILES_ROOT_DIR)) {
     rv = GetUserProfilesRootDir(getter_AddRefs(file), nullptr, nullptr, nullptr);
   }
   else if (!strcmp(aProperty, NS_APP_USER_PROFILES_LOCAL_ROOT_DIR)) {
     rv = GetUserProfilesLocalDir(getter_AddRefs(file), nullptr, nullptr, nullptr);
   }
-  else if (!strcmp(aProperty, XRE_EXECUTABLE_FILE) && gArgv[0]) {
+  else if (!strcmp(aProperty, XRE_EXECUTABLE_FILE)) {
     nsCOMPtr<nsIFile> lf;
-    rv = XRE_GetBinaryPath(gArgv[0], getter_AddRefs(lf));
+    rv = XRE_GetBinaryPath(getter_AddRefs(lf));
     if (NS_SUCCEEDED(rv))
       file = lf;
   }
 
   else if (!strcmp(aProperty, NS_APP_PROFILE_DIR_STARTUP) && mProfileDir) {
     return mProfileDir->Clone(aFile);
   }
   else if (!strcmp(aProperty, NS_APP_PROFILE_LOCAL_DIR_STARTUP)) {
@@ -923,17 +923,17 @@ nsXREDirProvider::GetFilesInternal(const
 
     rv = NS_NewArrayEnumerator(aResult, directories);
   }
   else if (!strcmp(aProperty, NS_APP_PLUGINS_DIR_LIST)) {
     nsCOMArray<nsIFile> directories;
 
     if (mozilla::Preferences::GetBool("plugins.load_appdir_plugins", false)) {
       nsCOMPtr<nsIFile> appdir;
-      rv = XRE_GetBinaryPath(gArgv[0], getter_AddRefs(appdir));
+      rv = XRE_GetBinaryPath(getter_AddRefs(appdir));
       if (NS_SUCCEEDED(rv)) {
         appdir->SetNativeLeafName(NS_LITERAL_CSTRING("plugins"));
         directories.AppendObject(appdir);
       }
     }
 
     static const char *const kAppendPlugins[] = { "plugins", nullptr };
 
--- a/xpcom/build/BinaryPath.h
+++ b/xpcom/build/BinaryPath.h
@@ -8,53 +8,62 @@
 #define mozilla_BinaryPath_h
 
 #include "nsXPCOMPrivate.h" // for MAXPATHLEN
 #ifdef XP_WIN
 #include <windows.h>
 #elif defined(XP_MACOSX)
 #include <CoreFoundation/CoreFoundation.h>
 #elif defined(XP_UNIX)
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#endif
+#if defined(__FreeBSD__) || defined(__DragonFly__) || \
+    defined(__FreeBSD_kernel__) || defined(__NetBSD__) || \
+    defined(__OpenBSD__)
+#include <sys/sysctl.h>
+#endif
+#if defined(__OpenBSD__)
 #include <sys/stat.h>
-#include <string.h>
 #endif
 #include "mozilla/UniquePtr.h"
 #include "mozilla/UniquePtrExtensions.h"
 
 #ifdef MOZILLA_INTERNAL_API
 #include "nsCOMPtr.h"
 #include "nsIFile.h"
 #include "nsString.h"
 #endif
 
 namespace mozilla {
 
 class BinaryPath
 {
 public:
 #ifdef XP_WIN
-  static nsresult Get(const char* argv0, char aResult[MAXPATHLEN])
+  static nsresult Get(char aResult[MAXPATHLEN])
   {
     wchar_t wide_path[MAXPATHLEN];
-    nsresult rv = GetW(argv0, wide_path);
+    nsresult rv = GetW(wide_path);
     if (NS_FAILED(rv)) {
       return rv;
     }
     WideCharToMultiByte(CP_UTF8, 0, wide_path, -1,
                         aResult, MAXPATHLEN, nullptr, nullptr);
     return NS_OK;
   }
 
   static nsresult GetLong(wchar_t aResult[MAXPATHLEN])
   {
     static bool cached = false;
     static wchar_t exeLongPath[MAXPATHLEN] = L"";
 
     if (!cached) {
-      nsresult rv = GetW(nullptr, exeLongPath);
+      nsresult rv = GetW(exeLongPath);
 
       if (NS_FAILED(rv)) {
         return rv;
       }
 
       if (!::GetLongPathNameW(exeLongPath, exeLongPath, MAXPATHLEN)) {
         return NS_ERROR_FAILURE;
       }
@@ -65,17 +74,17 @@ public:
     if (wcscpy_s(aResult, MAXPATHLEN, exeLongPath)) {
       return NS_ERROR_FAILURE;
     }
 
     return NS_OK;
   }
 
 private:
-  static nsresult GetW(const char* argv0, wchar_t aResult[MAXPATHLEN])
+  static nsresult GetW(wchar_t aResult[MAXPATHLEN])
   {
     static bool cached = false;
     static wchar_t moduleFileName[MAXPATHLEN] = L"";
 
     if (!cached) {
       if (!::GetModuleFileNameW(0, moduleFileName, MAXPATHLEN)) {
         return NS_ERROR_FAILURE;
       }
@@ -86,17 +95,17 @@ private:
     if (wcscpy_s(aResult, MAXPATHLEN, moduleFileName)) {
       return NS_ERROR_FAILURE;
     }
 
     return NS_OK;
   }
 
 #elif defined(XP_MACOSX)
-  static nsresult Get(const char* argv0, char aResult[MAXPATHLEN])
+  static nsresult Get(char aResult[MAXPATHLEN])
   {
     // Works even if we're not bundled.
     CFBundleRef appBundle = CFBundleGetMainBundle();
     if (!appBundle) {
       return NS_ERROR_FAILURE;
     }
 
     CFURLRef executableURL = CFBundleCopyExecutableURL(appBundle);
@@ -126,38 +135,96 @@ private:
       rv = NS_ERROR_FAILURE;
     }
 
     CFRelease(executableURL);
     return rv;
   }
 
 #elif defined(ANDROID)
-  static nsresult Get(const char* argv0, char aResult[MAXPATHLEN])
+  static nsresult Get(char aResult[MAXPATHLEN])
   {
     // On Android, we use the GRE_HOME variable that is set by the Java
     // bootstrap code.
     const char* greHome = getenv("GRE_HOME");
     if (!greHome) {
       return NS_ERROR_FAILURE;
     }
 
     snprintf(aResult, MAXPATHLEN, "%s/%s", greHome, "dummy");
     aResult[MAXPATHLEN - 1] = '\0';
     return NS_OK;
   }
 
-#elif defined(XP_UNIX)
-  static nsresult Get(const char* aArgv0, char aResult[MAXPATHLEN])
+#elif defined(XP_LINUX) || defined(XP_SOLARIS)
+  static nsresult Get(char aResult[MAXPATHLEN])
+  {
+#  if defined(XP_SOLARIS)
+    const char path[] = "/proc/self/path/a.out";
+#  else
+    const char path[] = "/proc/self/exe";
+#  endif
+
+    ssize_t len = readlink(path, aResult, MAXPATHLEN - 1);
+    if (len < 0) {
+      return NS_ERROR_FAILURE;
+    }
+    aResult[len] = '\0';
+    return NS_OK;
+  }
+
+#elif defined(__FreeBSD__) || defined(__DragonFly__) || \
+      defined(__FreeBSD_kernel__) || defined(__NetBSD__)
+  static nsresult Get(char aResult[MAXPATHLEN])
+  {
+    int mib[4];
+    mib[0] = CTL_KERN;
+#ifdef __NetBSD__
+    mib[1] = KERN_PROC_ARGS;
+    mib[2] = -1;
+    mib[3] = KERN_PROC_PATHNAME;
+#else
+    mib[1] = KERN_PROC;
+    mib[2] = KERN_PROC_PATHNAME;
+    mib[3] = -1;
+#endif
+
+    size_t len = MAXPATHLEN;
+    if (sysctl(mib, 4, aResult, &len, nullptr, 0) < 0) {
+      return NS_ERROR_FAILURE;
+    }
+
+    return NS_OK;
+  }
+
+#elif defined(__OpenBSD__)
+  static nsresult Get(char aResult[MAXPATHLEN])
+  {
+    int mib[4];
+    mib[0] = CTL_KERN;
+    mib[1] = KERN_PROC_ARGS;
+    mib[2] = getpid();
+    mib[3] = KERN_PROC_ARGV;
+
+    size_t len = 0;
+    if (sysctl(mib, 4, nullptr, &len, nullptr, 0) < 0) {
+      return NS_ERROR_FAILURE;
+    }
+
+    auto argv = MakeUnique<const char*[]>(len / sizeof(const char*));
+    if (sysctl(mib, 4, argv.get(), &len, nullptr, 0) < 0) {
+      return NS_ERROR_FAILURE;
+    }
+
+    return GetFromArgv0(argv[0], aResult);
+  }
+
+  static nsresult GetFromArgv0(const char* aArgv0, char aResult[MAXPATHLEN])
   {
     struct stat fileStat;
-    // on unix, there is no official way to get the path of the current binary.
-    // instead of using the MOZILLA_FIVE_HOME hack, which doesn't scale to
-    // multiple applications, we will try a series of techniques:
-    //
     // 1) use realpath() on argv[0], which works unless we're loaded from the
     //    PATH. Only do so if argv[0] looks like a path (contains a /).
     // 2) manually walk through the PATH and look for ourself
     // 3) give up
     if (strchr(aArgv0, '/') && realpath(aArgv0, aResult) &&
         stat(aResult, &fileStat) == 0) {
       return NS_OK;
     }
@@ -190,37 +257,37 @@ private:
     return NS_ERROR_FAILURE;
   }
 
 #else
 #error Oops, you need platform-specific code here
 #endif
 
 public:
-  static UniqueFreePtr<char> Get(const char *aArgv0)
+  static UniqueFreePtr<char> Get()
   {
     char path[MAXPATHLEN];
-    if (NS_FAILED(Get(aArgv0, path))) {
+    if (NS_FAILED(Get(path))) {
       return nullptr;
     }
     UniqueFreePtr<char> result;
     result.reset(strdup(path));
     return result;
   }
 
 #ifdef MOZILLA_INTERNAL_API
-  static nsresult GetFile(const char* aArgv0, nsIFile** aResult)
+  static nsresult GetFile(nsIFile** aResult)
   {
     nsCOMPtr<nsIFile> lf;
 #ifdef XP_WIN
     wchar_t exePath[MAXPATHLEN];
-    nsresult rv = GetW(aArgv0, exePath);
+    nsresult rv = GetW(exePath);
 #else
     char exePath[MAXPATHLEN];
-    nsresult rv = Get(aArgv0, exePath);
+    nsresult rv = Get(exePath);
 #endif
     if (NS_FAILED(rv)) {
       return rv;
     }
 #ifdef XP_WIN
     rv = NS_NewLocalFile(nsDependentString(exePath), true,
                          getter_AddRefs(lf));
 #else
--- a/xpcom/build/nsXULAppAPI.h
+++ b/xpcom/build/nsXULAppAPI.h
@@ -200,22 +200,19 @@ XRE_API(int,
  *
  * @note Pass UTF8 strings on Windows... native charset on other platforms.
  */
 XRE_API(nsresult,
         XRE_GetFileFromPath, (const char* aPath, nsIFile** aResult))
 
 /**
  * Get the path of the running application binary and store it in aResult.
- * @param aArgv0  The value passed as argv[0] of main(). This value is only
- *                used on *nix, and only when other methods of determining
- *                the binary path have failed.
  */
 XRE_API(nsresult,
-        XRE_GetBinaryPath, (const char* aArgv0, nsIFile** aResult))
+        XRE_GetBinaryPath, (nsIFile** aResult))
 
 /**
  * Get the static module built in to libxul.
  */
 XRE_API(const mozilla::Module*,
         XRE_GetStaticModule, ())
 
 /**