forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			320 lines
		
	
	
	
		
			8.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			320 lines
		
	
	
	
		
			8.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | |
| /* This Source Code Form is subject to the terms of the Mozilla Public
 | |
|  * License, v. 2.0. If a copy of the MPL was not distributed with this
 | |
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | |
| 
 | |
| #include "nsXULAppAPI.h"
 | |
| #include "mozilla/XREAppData.h"
 | |
| #include "application.ini.h"
 | |
| #include "mozilla/Bootstrap.h"
 | |
| #if defined(XP_WIN)
 | |
| #include <windows.h>
 | |
| #include <stdlib.h>
 | |
| #elif defined(XP_UNIX)
 | |
| #include <sys/resource.h>
 | |
| #include <unistd.h>
 | |
| #endif
 | |
| 
 | |
| #include <stdio.h>
 | |
| #include <stdarg.h>
 | |
| #include <time.h>
 | |
| 
 | |
| #include "nsCOMPtr.h"
 | |
| #include "nsIFile.h"
 | |
| 
 | |
| #ifdef XP_WIN
 | |
| #define XRE_WANT_ENVIRON
 | |
| #define strcasecmp _stricmp
 | |
| #ifdef MOZ_SANDBOX
 | |
| #include "mozilla/sandboxing/SandboxInitialization.h"
 | |
| #endif
 | |
| #endif
 | |
| #include "BinaryPath.h"
 | |
| 
 | |
| #include "nsXPCOMPrivate.h" // for MAXPATHLEN and XPCOM_DLL
 | |
| 
 | |
| #include "mozilla/Sprintf.h"
 | |
| #include "mozilla/StartupTimeline.h"
 | |
| #include "mozilla/WindowsDllBlocklist.h"
 | |
| 
 | |
| #ifdef LIBFUZZER
 | |
| #include "FuzzerDefs.h"
 | |
| #endif
 | |
| 
 | |
| #ifdef MOZ_LINUX_32_SSE2_STARTUP_ERROR
 | |
| #include <cpuid.h>
 | |
| #include "mozilla/Unused.h"
 | |
| 
 | |
| static bool
 | |
| IsSSE2Available()
 | |
| {
 | |
|   // The rest of the app has been compiled to assume that SSE2 is present
 | |
|   // unconditionally, so we can't use the normal copy of SSE.cpp here.
 | |
|   // Since SSE.cpp caches the results and we need them only transiently,
 | |
|   // instead of #including SSE.cpp here, let's just inline the specific check
 | |
|   // that's needed.
 | |
|   unsigned int level = 1u;
 | |
|   unsigned int eax, ebx, ecx, edx;
 | |
|   unsigned int bits = (1u<<26);
 | |
|   unsigned int max = __get_cpuid_max(0, nullptr);
 | |
|   if (level > max) {
 | |
|     return false;
 | |
|   }
 | |
|   __cpuid_count(level, 0, eax, ebx, ecx, edx);
 | |
|   return (edx & bits) == bits;
 | |
| }
 | |
| 
 | |
| static const char sSSE2Message[] =
 | |
|     "This browser version requires a processor with the SSE2 instruction "
 | |
|     "set extension.\nYou may be able to obtain a version that does not "
 | |
|     "require SSE2 from your Linux distribution.\n";
 | |
| 
 | |
| __attribute__((constructor))
 | |
| static void
 | |
| SSE2Check()
 | |
| {
 | |
|   if (IsSSE2Available()) {
 | |
|     return;
 | |
|   }
 | |
|   // Using write() in order to avoid jemalloc-based buffering. Ignoring return
 | |
|   // values, since there isn't much we could do on failure and there is no
 | |
|   // point in trying to recover from errors.
 | |
|   MOZ_UNUSED(write(STDERR_FILENO,
 | |
|                    sSSE2Message,
 | |
|                    MOZ_ARRAY_LENGTH(sSSE2Message) - 1));
 | |
|   // _exit() instead of exit() to avoid running the usual "at exit" code.
 | |
|   _exit(255);
 | |
| }
 | |
| #endif
 | |
| 
 | |
| #if !defined(MOZ_WIDGET_COCOA) && !defined(MOZ_WIDGET_ANDROID)
 | |
| #define MOZ_BROWSER_CAN_BE_CONTENTPROC
 | |
| #include "../../ipc/contentproc/plugin-container.cpp"
 | |
| #endif
 | |
| 
 | |
| using namespace mozilla;
 | |
| 
 | |
| #ifdef XP_MACOSX
 | |
| #define kOSXResourcesFolder "Resources"
 | |
| #endif
 | |
| #define kDesktopFolder "browser"
 | |
| 
 | |
| static MOZ_FORMAT_PRINTF(1, 2) void Output(const char *fmt, ... )
 | |
| {
 | |
|   va_list ap;
 | |
|   va_start(ap, fmt);
 | |
| 
 | |
| #ifndef XP_WIN
 | |
|   vfprintf(stderr, fmt, ap);
 | |
| #else
 | |
|   char msg[2048];
 | |
|   vsnprintf_s(msg, _countof(msg), _TRUNCATE, fmt, ap);
 | |
| 
 | |
|   wchar_t wide_msg[2048];
 | |
|   MultiByteToWideChar(CP_UTF8,
 | |
|                       0,
 | |
|                       msg,
 | |
|                       -1,
 | |
|                       wide_msg,
 | |
|                       _countof(wide_msg));
 | |
| #if MOZ_WINCONSOLE
 | |
|   fwprintf_s(stderr, wide_msg);
 | |
| #else
 | |
|   // Linking user32 at load-time interferes with the DLL blocklist (bug 932100).
 | |
|   // This is a rare codepath, so we can load user32 at run-time instead.
 | |
|   HMODULE user32 = LoadLibraryW(L"user32.dll");
 | |
|   if (user32) {
 | |
|     decltype(MessageBoxW)* messageBoxW =
 | |
|       (decltype(MessageBoxW)*) GetProcAddress(user32, "MessageBoxW");
 | |
|     if (messageBoxW) {
 | |
|       messageBoxW(nullptr, wide_msg, L"Firefox", MB_OK
 | |
|                                                | MB_ICONERROR
 | |
|                                                | MB_SETFOREGROUND);
 | |
|     }
 | |
|     FreeLibrary(user32);
 | |
|   }
 | |
| #endif
 | |
| #endif
 | |
| 
 | |
|   va_end(ap);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Return true if |arg| matches the given argument name.
 | |
|  */
 | |
| static bool IsArg(const char* arg, const char* s)
 | |
| {
 | |
|   if (*arg == '-')
 | |
|   {
 | |
|     if (*++arg == '-')
 | |
|       ++arg;
 | |
|     return !strcasecmp(arg, s);
 | |
|   }
 | |
| 
 | |
| #if defined(XP_WIN)
 | |
|   if (*arg == '/')
 | |
|     return !strcasecmp(++arg, s);
 | |
| #endif
 | |
| 
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| Bootstrap::UniquePtr gBootstrap;
 | |
| 
 | |
| static int do_main(int argc, char* argv[], char* envp[])
 | |
| {
 | |
|   // Allow firefox.exe to launch XULRunner apps via -app <application.ini>
 | |
|   // Note that -app must be the *first* argument.
 | |
|   const char *appDataFile = getenv("XUL_APP_FILE");
 | |
|   if ((!appDataFile || !*appDataFile) &&
 | |
|       (argc > 1 && IsArg(argv[1], "app"))) {
 | |
|     if (argc == 2) {
 | |
|       Output("Incorrect number of arguments passed to -app");
 | |
|       return 255;
 | |
|     }
 | |
|     appDataFile = argv[2];
 | |
| 
 | |
|     char appEnv[MAXPATHLEN];
 | |
|     SprintfLiteral(appEnv, "XUL_APP_FILE=%s", argv[2]);
 | |
|     if (putenv(strdup(appEnv))) {
 | |
|       Output("Couldn't set %s.\n", appEnv);
 | |
|       return 255;
 | |
|     }
 | |
|     argv[2] = argv[0];
 | |
|     argv += 2;
 | |
|     argc -= 2;
 | |
|   } else if (argc > 1 && IsArg(argv[1], "xpcshell")) {
 | |
|     for (int i = 1; i < argc; i++) {
 | |
|       argv[i] = argv[i + 1];
 | |
|     }
 | |
| 
 | |
|     XREShellData shellData;
 | |
| #if defined(XP_WIN) && defined(MOZ_SANDBOX)
 | |
|     shellData.sandboxBrokerServices =
 | |
|       sandboxing::GetInitializedBrokerServices();
 | |
| #endif
 | |
| 
 | |
|     return gBootstrap->XRE_XPCShellMain(--argc, argv, envp, &shellData);
 | |
|   }
 | |
| 
 | |
|   BootstrapConfig config;
 | |
| 
 | |
|   if (appDataFile && *appDataFile) {
 | |
|     config.appData = nullptr;
 | |
|     config.appDataPath = appDataFile;
 | |
|   } else {
 | |
|     // no -app flag so we use the compiled-in app data
 | |
|     config.appData = &sAppData;
 | |
|     config.appDataPath = kDesktopFolder;
 | |
|   }
 | |
| 
 | |
| #if defined(XP_WIN) && defined(MOZ_SANDBOX)
 | |
|   sandbox::BrokerServices* brokerServices =
 | |
|     sandboxing::GetInitializedBrokerServices();
 | |
|   sandboxing::PermissionsService* permissionsService =
 | |
|     sandboxing::GetPermissionsService();
 | |
| #if defined(MOZ_CONTENT_SANDBOX)
 | |
|   if (!brokerServices) {
 | |
|     Output("Couldn't initialize the broker services.\n");
 | |
|     return 255;
 | |
|   }
 | |
| #endif
 | |
|   config.sandboxBrokerServices = brokerServices;
 | |
|   config.sandboxPermissionsService = permissionsService;
 | |
| #endif
 | |
| 
 | |
| #ifdef LIBFUZZER
 | |
|   if (getenv("LIBFUZZER"))
 | |
|     gBootstrap->XRE_LibFuzzerSetDriver(fuzzer::FuzzerDriver);
 | |
| #endif
 | |
| 
 | |
|   return gBootstrap->XRE_main(argc, argv, config);
 | |
| }
 | |
| 
 | |
| static nsresult
 | |
| InitXPCOMGlue()
 | |
| {
 | |
|   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");
 | |
|     return NS_ERROR_FAILURE;
 | |
|   }
 | |
| 
 | |
|   // This will set this thread as the main thread.
 | |
|   gBootstrap->NS_LogInit();
 | |
| 
 | |
|   return NS_OK;
 | |
| }
 | |
| 
 | |
| int main(int argc, char* argv[], char* envp[])
 | |
| {
 | |
|   mozilla::TimeStamp start = mozilla::TimeStamp::Now();
 | |
| 
 | |
| #ifdef MOZ_BROWSER_CAN_BE_CONTENTPROC
 | |
|   // We are launching as a content process, delegate to the appropriate
 | |
|   // main
 | |
|   if (argc > 1 && IsArg(argv[1], "contentproc")) {
 | |
| #ifdef HAS_DLL_BLOCKLIST
 | |
|     DllBlocklist_Initialize(eDllBlocklistInitFlagIsChildProcess);
 | |
| #endif
 | |
| #if defined(XP_WIN) && defined(MOZ_SANDBOX)
 | |
|     // 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();
 | |
|     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();
 | |
| 
 | |
|     return result;
 | |
|   }
 | |
| #endif
 | |
| 
 | |
| #ifdef HAS_DLL_BLOCKLIST
 | |
|   DllBlocklist_Initialize();
 | |
| #endif
 | |
| 
 | |
|   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();
 | |
| #endif
 | |
| 
 | |
|   int result = do_main(argc, argv, envp);
 | |
| 
 | |
|   gBootstrap->NS_LogTerm();
 | |
| 
 | |
| #ifdef XP_MACOSX
 | |
|   // Allow writes again. While we would like to catch writes from static
 | |
|   // destructors to allow early exits to use _exit, we know that there is
 | |
|   // at least one such write that we don't control (see bug 826029). For
 | |
|   // now we enable writes again and early exits will have to use exit instead
 | |
|   // of _exit.
 | |
|   gBootstrap->XRE_StopLateWriteChecks();
 | |
| #endif
 | |
| 
 | |
|   gBootstrap.reset();
 | |
| 
 | |
|   return result;
 | |
| }
 | 
