Bug 1457999: Part 1 - Move command line argument utils and safe mode checks into a common header file; r=jimm

--HG--
extra : rebase_source : 368d45d026ddc658ba732b6f58fcd976c48ff7d4
This commit is contained in:
Aaron Klotz 2018-04-19 17:22:41 -06:00
Родитель 63e8594df2
Коммит d6661abc54
7 изменённых файлов: 566 добавлений и 374 удалений

Просмотреть файл

@ -0,0 +1,385 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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 https://mozilla.org/MPL/2.0/. */
#ifndef mozilla_CmdLineAndEnvUtils_h
#define mozilla_CmdLineAndEnvUtils_h
// NB: This code may be used outside of xul and thus must not depend on XPCOM
#if defined(MOZILLA_INTERNAL_API)
#include "prenv.h"
#include <string.h>
#elif defined(XP_WIN)
#include <stdlib.h>
#endif
#if defined(XP_WIN)
#include "mozilla/Move.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/Vector.h"
#include <wchar.h>
#endif // defined(XP_WIN)
#include "mozilla/TypedEnumBits.h"
#include <ctype.h>
namespace mozilla {
enum ArgResult {
ARG_NONE = 0,
ARG_FOUND = 1,
ARG_BAD = 2 // you wanted a param, but there isn't one
};
template <typename CharT>
inline void
RemoveArg(int& argc, CharT **argv)
{
do {
*argv = *(argv + 1);
++argv;
} while (*argv);
--argc;
}
namespace internal {
template <typename FuncT, typename CharT>
inline bool
strimatch(FuncT aToLowerFn, const CharT* lowerstr, const CharT* mixedstr)
{
while(*lowerstr) {
if (!*mixedstr) return false; // mixedstr is shorter
if (aToLowerFn(*mixedstr) != *lowerstr) return false; // no match
++lowerstr;
++mixedstr;
}
if (*mixedstr) return false; // lowerstr is shorter
return true;
}
} // namespace internal
inline bool
strimatch(const char* lowerstr, const char* mixedstr)
{
return internal::strimatch(&tolower, lowerstr, mixedstr);
}
inline bool
strimatch(const wchar_t* lowerstr, const wchar_t* mixedstr)
{
return internal::strimatch(&towlower, lowerstr, mixedstr);
}
enum class FlagLiteral
{
osint,
safemode
};
template <typename CharT, FlagLiteral Literal>
inline const CharT* GetLiteral();
#define DECLARE_FLAG_LITERAL(enum_name, literal) \
template <> inline \
const char* GetLiteral<char, FlagLiteral::##enum_name>() \
{ \
return literal; \
} \
\
template <> inline \
const wchar_t* GetLiteral<wchar_t, FlagLiteral::##enum_name>() \
{ \
return L##literal; \
}
DECLARE_FLAG_LITERAL(osint, "osint")
DECLARE_FLAG_LITERAL(safemode, "safe-mode")
enum class CheckArgFlag : uint32_t
{
None = 0,
CheckOSInt = (1 << 0), // Retrun ARG_BAD if osint arg is also present.
RemoveArg = (1 << 1) // Remove the argument from the argv array.
};
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(CheckArgFlag)
/**
* Check for a commandline flag. If the flag takes a parameter, the
* parameter is returned in aParam. Flags may be in the form -arg or
* --arg (or /arg on win32).
*
* @param aArgc The argc value.
* @param aArgv The original argv.
* @param aArg the parameter to check. Must be lowercase.
* @param aParam if non-null, the -arg <data> will be stored in this pointer.
* This is *not* allocated, but rather a pointer to the argv data.
* @param aFlags Flags @see CheckArgFlag
*/
template <typename CharT>
inline ArgResult
CheckArg(int& aArgc, CharT** aArgv, const CharT* aArg, const CharT **aParam,
CheckArgFlag aFlags)
{
MOZ_ASSERT(aArgv && aArg);
CharT **curarg = aArgv + 1; // skip argv[0]
ArgResult ar = ARG_NONE;
while (*curarg) {
CharT *arg = curarg[0];
if (arg[0] == '-'
#if defined(XP_WIN)
|| *arg == '/'
#endif
) {
++arg;
if (*arg == '-') {
++arg;
}
if (strimatch(aArg, arg)) {
if (aFlags & CheckArgFlag::RemoveArg) {
RemoveArg(aArgc, curarg);
} else {
++curarg;
}
if (!aParam) {
ar = ARG_FOUND;
break;
}
if (*curarg) {
if (**curarg == '-'
#if defined(XP_WIN)
|| **curarg == '/'
#endif
) {
return ARG_BAD;
}
*aParam = *curarg;
if (aFlags & CheckArgFlag::RemoveArg) {
RemoveArg(aArgc, curarg);
}
ar = ARG_FOUND;
break;
}
return ARG_BAD;
}
}
++curarg;
}
if ((aFlags & CheckArgFlag::CheckOSInt) && ar == ARG_FOUND) {
ArgResult arOSInt = CheckArg(aArgc, aArgv,
GetLiteral<CharT, FlagLiteral::osint>(),
reinterpret_cast<const CharT**>(nullptr),
CheckArgFlag::None);
if (arOSInt == ARG_FOUND) {
ar = ARG_BAD;
#if defined(MOZILLA_INTERNAL_API)
PR_fprintf(PR_STDERR, "Error: argument --osint is invalid\n");
#endif // defined(MOZILLA_INTERNAL_API)
}
}
return ar;
}
#if defined(XP_WIN)
namespace internal {
/**
* Get the length that the string will take and takes into account the
* additional length if the string needs to be quoted and if characters need to
* be escaped.
*/
inline int
ArgStrLen(const wchar_t *s)
{
int backslashes = 0;
int i = wcslen(s);
bool hasDoubleQuote = wcschr(s, L'"') != nullptr;
// Only add doublequotes if the string contains a space or a tab
bool addDoubleQuotes = wcspbrk(s, L" \t") != nullptr;
if (addDoubleQuotes) {
i += 2; // initial and final duoblequote
}
if (hasDoubleQuote) {
while (*s) {
if (*s == '\\') {
++backslashes;
} else {
if (*s == '"') {
// Escape the doublequote and all backslashes preceding the doublequote
i += backslashes + 1;
}
backslashes = 0;
}
++s;
}
}
return i;
}
/**
* Copy string "s" to string "d", quoting the argument as appropriate and
* escaping doublequotes along with any backslashes that immediately precede
* doublequotes.
* The CRT parses this to retrieve the original argc/argv that we meant,
* see STDARGV.C in the MSVC CRT sources.
*
* @return the end of the string
*/
inline wchar_t*
ArgToString(wchar_t *d, const wchar_t *s)
{
int backslashes = 0;
bool hasDoubleQuote = wcschr(s, L'"') != nullptr;
// Only add doublequotes if the string contains a space or a tab
bool addDoubleQuotes = wcspbrk(s, L" \t") != nullptr;
if (addDoubleQuotes) {
*d = '"'; // initial doublequote
++d;
}
if (hasDoubleQuote) {
int i;
while (*s) {
if (*s == '\\') {
++backslashes;
} else {
if (*s == '"') {
// Escape the doublequote and all backslashes preceding the doublequote
for (i = 0; i <= backslashes; ++i) {
*d = '\\';
++d;
}
}
backslashes = 0;
}
*d = *s;
++d; ++s;
}
} else {
wcscpy(d, s);
d += wcslen(s);
}
if (addDoubleQuotes) {
*d = '"'; // final doublequote
++d;
}
return d;
}
} // namespace internal
/**
* Creates a command line from a list of arguments.
*/
inline UniquePtr<wchar_t[]>
MakeCommandLine(int argc, wchar_t **argv)
{
int i;
int len = 0;
// The + 1 of the last argument handles the allocation for null termination
for (i = 0; i < argc; ++i) {
len += internal::ArgStrLen(argv[i]) + 1;
}
// Protect against callers that pass 0 arguments
if (len == 0) {
len = 1;
}
auto s = MakeUnique<wchar_t[]>(len);
if (!s) {
return nullptr;
}
wchar_t *c = s.get();
for (i = 0; i < argc; ++i) {
c = internal::ArgToString(c, argv[i]);
if (i + 1 != argc) {
*c = ' ';
++c;
}
}
*c = '\0';
return Move(s);
}
#endif // defined(XP_WIN)
// Save literal putenv string to environment variable.
inline void
SaveToEnv(const char *aEnvString)
{
#if defined(MOZILLA_INTERNAL_API)
char *expr = strdup(aEnvString);
if (expr) {
PR_SetEnv(expr);
}
// We intentionally leak |expr| here since it is required by PR_SetEnv.
MOZ_LSAN_INTENTIONALLY_LEAK_OBJECT(expr);
#elif defined(XP_WIN)
// This is the same as the NSPR implementation
// (Note that we don't need to do a strdup for this case; the CRT makes a copy)
_putenv(aEnvString);
#else
#error "Not implemented for this configuration"
#endif
}
inline bool
EnvHasValue(const char* aVarName)
{
#if defined(MOZILLA_INTERNAL_API)
const char* val = PR_GetEnv(aVarName);
return val && *val;
#elif defined(XP_WIN)
// This is the same as the NSPR implementation
const char* val = getenv(aVarName);
return val && *val;
#else
#error "Not implemented for this configuration"
#endif
}
} // namespace mozilla
#endif // mozilla_CmdLineAndEnvUtils_h

Просмотреть файл

@ -0,0 +1,46 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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 https://mozilla.org/MPL/2.0/. */
#ifndef mozilla_PolicyChecks_h
#define mozilla_PolicyChecks_h
#if defined(XP_WIN)
#include <windows.h>
// NB: This code must be able to run apart from XPCOM
namespace mozilla {
inline bool
PolicyHasRegValue(HKEY aKey, LPCWSTR aName, DWORD* aValue)
{
DWORD len = sizeof(DWORD);
LONG ret = ::RegGetValueW(aKey, L"SOFTWARE\\Policies\\Mozilla\\Firefox", aName,
RRF_RT_DWORD, nullptr, aValue, &len);
return ret == ERROR_SUCCESS;
}
inline bool
PolicyCheckBoolean(LPCWSTR aPolicyName)
{
DWORD value;
if (PolicyHasRegValue(HKEY_LOCAL_MACHINE, aPolicyName, &value)) {
return value == 1;
}
if (PolicyHasRegValue(HKEY_CURRENT_USER, aPolicyName, &value)) {
return value == 1;
}
return false;
}
} // namespace mozilla
#endif // defined(XP_WIN)
#endif // mozilla_PolicyChecks_h

90
toolkit/xre/SafeMode.h Normal file
Просмотреть файл

@ -0,0 +1,90 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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 https://mozilla.org/MPL/2.0/. */
#ifndef mozilla_SafeMode_h
#define mozilla_SafeMode_h
// NB: This code must be able to run apart from XPCOM
#include "mozilla/CmdLineAndEnvUtils.h"
#include "mozilla/Maybe.h"
#if defined(XP_WIN)
#include "mozilla/PolicyChecks.h"
#include <windows.h>
#endif // defined(XP_WIN)
namespace mozilla {
enum class SafeModeFlag : uint32_t
{
None = 0,
Unset = (1 << 0)
};
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(SafeModeFlag)
template <typename CharT>
inline Maybe<bool>
IsSafeModeRequested(int& aArgc, CharT* aArgv[],
const SafeModeFlag aFlags = SafeModeFlag::Unset)
{
CheckArgFlag checkArgFlags = CheckArgFlag::CheckOSInt;
if (aFlags & SafeModeFlag::Unset) {
checkArgFlags |= CheckArgFlag::RemoveArg;
}
ArgResult ar = CheckArg(aArgc, aArgv,
GetLiteral<CharT, FlagLiteral::safemode>(),
reinterpret_cast<const CharT**>(nullptr),
checkArgFlags);
if (ar == ARG_BAD) {
return Nothing();
}
bool result = ar == ARG_FOUND;
#if defined(XP_WIN)
// If the shift key is pressed and the ctrl and / or alt keys are not pressed
// during startup, start in safe mode. GetKeyState returns a short and the high
// order bit will be 1 if the key is pressed. By masking the returned short
// with 0x8000 the result will be 0 if the key is not pressed and non-zero
// otherwise.
if ((GetKeyState(VK_SHIFT) & 0x8000) &&
!(GetKeyState(VK_CONTROL) & 0x8000) &&
!(GetKeyState(VK_MENU) & 0x8000) &&
!EnvHasValue("MOZ_DISABLE_SAFE_MODE_KEY")) {
result = true;
}
if (result && PolicyCheckBoolean(L"DisableSafeMode")) {
result = false;
}
#endif // defined(XP_WIN)
#if defined(XP_MACOSX)
if ((GetCurrentEventKeyModifiers() & optionKey) &&
!EnvHasValue("MOZ_DISABLE_SAFE_MODE_KEY")) {
result = true;
}
#endif // defined(XP_MACOSX)
// The Safe Mode Policy should not be enforced for the env var case
// (used by updater and crash-recovery).
if (EnvHasValue("MOZ_SAFE_MODE_RESTART")) {
result = true;
if (aFlags & SafeModeFlag::Unset) {
// unset the env variable
SaveToEnv("MOZ_SAFE_MODE_RESTART=");
}
}
return Some(result);
}
} // namespace mozilla
#endif // mozilla_SafeMode_h

Просмотреть файл

@ -30,13 +30,19 @@ EXPORTS += [
'nsIAppStartupNotifier.h',
]
EXPORTS.mozilla += ['AutoSQLiteLifetime.h', 'Bootstrap.h']
EXPORTS.mozilla += [
'AutoSQLiteLifetime.h',
'Bootstrap.h',
'CmdLineAndEnvUtils.h',
'SafeMode.h',
]
if CONFIG['MOZ_INSTRUMENT_EVENT_LOOP']:
EXPORTS += ['EventTracer.h']
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
EXPORTS.mozilla += [
'PolicyChecks.h',
'WinDllServices.h',
]
SOURCES += [

Просмотреть файл

@ -10,6 +10,7 @@
#include "mozilla/ArrayUtils.h"
#include "mozilla/Attributes.h"
#include "mozilla/ChaosMode.h"
#include "mozilla/CmdLineAndEnvUtils.h"
#include "mozilla/IOInterposer.h"
#include "mozilla/Likely.h"
#include "mozilla/MemoryChecking.h"
@ -232,6 +233,7 @@
#endif
#include "mozilla/mozalloc_oom.h"
#include "SafeMode.h"
extern uint32_t gRestartMode;
extern void InstallSignalHandlers(const char *ProgramName);
@ -306,25 +308,6 @@ using mozilla::dom::ContentParent;
using mozilla::dom::ContentChild;
using mozilla::intl::LocaleService;
// Save literal putenv string to environment variable.
static void
SaveToEnv(const char *putenv)
{
char *expr = strdup(putenv);
if (expr)
PR_SetEnv(expr);
// We intentionally leak |expr| here since it is required by PR_SetEnv.
MOZ_LSAN_INTENTIONALLY_LEAK_OBJECT(expr);
}
// Tests that an environment variable exists and has a value
static bool
EnvHasValue(const char *name)
{
const char *val = PR_GetEnv(name);
return (val && *val);
}
// Save the given word to the specified environment variable.
static void
SaveWordToEnv(const char *name, const nsACString & word)
@ -400,22 +383,6 @@ SaveFileToEnvIfUnset(const char *name, nsIFile *file)
SaveFileToEnv(name, file);
}
static bool
strimatch(const char* lowerstr, const char* mixedstr)
{
while(*lowerstr) {
if (!*mixedstr) return false; // mixedstr is shorter
if (tolower(*mixedstr) != *lowerstr) return false; // no match
++lowerstr;
++mixedstr;
}
if (*mixedstr) return false; // lowerstr is shorter
return true;
}
static bool gIsExpectedExit = false;
void MozExpectedExit() {
@ -482,94 +449,22 @@ enum RemoteResult {
REMOTE_ARG_BAD = 2
};
enum ArgResult {
ARG_NONE = 0,
ARG_FOUND = 1,
ARG_BAD = 2 // you wanted a param, but there isn't one
};
static void RemoveArg(char **argv)
{
do {
*argv = *(argv + 1);
++argv;
} while (*argv);
--gArgc;
}
/**
* Check for a commandline flag. If the flag takes a parameter, the
* parameter is returned in aParam. Flags may be in the form -arg or
* --arg (or /arg on win32).
*
* @param aArg the parameter to check. Must be lowercase.
* @param aCheckOSInt if true returns ARG_BAD if the osint argument is present
* when aArg is also present.
* @param aParam if non-null, the -arg <data> will be stored in this pointer.
* This is *not* allocated, but rather a pointer to the argv data.
* @param aRemArg if true, the argument is removed from the gArgv array.
* @param aFlags flags @see CheckArgFlag
*/
static ArgResult
CheckArg(const char* aArg, bool aCheckOSInt = false, const char **aParam = nullptr, bool aRemArg = true)
CheckArg(const char* aArg, const char** aParam = nullptr,
CheckArgFlag aFlags = CheckArgFlag::RemoveArg)
{
MOZ_ASSERT(gArgv, "gArgv must be initialized before CheckArg()");
char **curarg = gArgv + 1; // skip argv[0]
ArgResult ar = ARG_NONE;
while (*curarg) {
char *arg = curarg[0];
if (arg[0] == '-'
#if defined(XP_WIN)
|| *arg == '/'
#endif
) {
++arg;
if (*arg == '-')
++arg;
if (strimatch(aArg, arg)) {
if (aRemArg)
RemoveArg(curarg);
else
++curarg;
if (!aParam) {
ar = ARG_FOUND;
break;
}
if (*curarg) {
if (**curarg == '-'
#if defined(XP_WIN)
|| **curarg == '/'
#endif
)
return ARG_BAD;
*aParam = *curarg;
if (aRemArg)
RemoveArg(curarg);
ar = ARG_FOUND;
break;
}
return ARG_BAD;
}
}
++curarg;
}
if (aCheckOSInt && ar == ARG_FOUND) {
ArgResult arOSInt = CheckArg("osint");
if (arOSInt == ARG_FOUND) {
ar = ARG_BAD;
PR_fprintf(PR_STDERR, "Error: argument --osint is invalid\n");
}
}
return ar;
return CheckArg(gArgc, gArgv, aArg, aParam, aFlags);
}
/**
@ -582,38 +477,7 @@ CheckArg(const char* aArg, bool aCheckOSInt = false, const char **aParam = nullp
static ArgResult
CheckArgExists(const char* aArg)
{
char **curarg = gArgv + 1; // skip argv[0]
while (*curarg) {
char *arg = curarg[0];
if (arg[0] == '-'
#if defined(XP_WIN)
|| *arg == '/'
#endif
) {
++arg;
if (*arg == '-')
++arg;
char delimiter = '=';
#if defined(XP_WIN)
delimiter = ':';
#endif
int i;
for (i = 0; arg[i] && arg[i] != delimiter; i++) {}
char tmp = arg[i];
arg[i] = '\0';
bool found = strimatch(aArg, arg);
arg[i] = tmp;
if (found) {
return ARG_FOUND;
}
}
++curarg;
}
return ARG_NONE;
return CheckArg(aArg, nullptr, CheckArgFlag::None);
}
#if defined(XP_WIN)
@ -1799,14 +1663,14 @@ ParseRemoteCommandLine(nsCString& program,
{
ArgResult ar;
ar = CheckArg("p", false, profile, false);
ar = CheckArg("p", profile, CheckArgFlag::None);
if (ar == ARG_BAD) {
// Leave it to the normal command line handling to handle this situation.
return REMOTE_NOT_FOUND;
}
const char *temp = nullptr;
ar = CheckArg("a", true, &temp);
ar = CheckArg("a", &temp, CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg);
if (ar == ARG_BAD) {
PR_fprintf(PR_STDERR, "Error: argument -a requires an application name\n");
return REMOTE_ARG_BAD;
@ -1815,7 +1679,7 @@ ParseRemoteCommandLine(nsCString& program,
program.Assign(temp);
}
ar = CheckArg("u", true, username);
ar = CheckArg("u", username, CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg);
if (ar == ARG_BAD) {
PR_fprintf(PR_STDERR, "Error: argument -u requires a username\n");
return REMOTE_ARG_BAD;
@ -2322,7 +2186,7 @@ SelectProfile(nsIProfileLock* *aResult, nsIToolkitProfileService* aProfileSvc, n
*aResult = nullptr;
*aStartOffline = false;
ar = CheckArg("offline", true);
ar = CheckArg("offline", nullptr, CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg);
if (ar == ARG_BAD) {
PR_fprintf(PR_STDERR, "Error: argument --offline is invalid when argument --osint is specified\n");
return NS_ERROR_FAILURE;
@ -2344,7 +2208,7 @@ SelectProfile(nsIProfileLock* *aResult, nsIToolkitProfileService* aProfileSvc, n
}
// reset-profile and migration args need to be checked before any profiles are chosen below.
ar = CheckArg("reset-profile", true);
ar = CheckArg("reset-profile", nullptr, CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg);
if (ar == ARG_BAD) {
PR_fprintf(PR_STDERR, "Error: argument --reset-profile is invalid when argument --osint is specified\n");
return NS_ERROR_FAILURE;
@ -2353,7 +2217,7 @@ SelectProfile(nsIProfileLock* *aResult, nsIToolkitProfileService* aProfileSvc, n
gDoProfileReset = true;
}
ar = CheckArg("migration", true);
ar = CheckArg("migration", nullptr, CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg);
if (ar == ARG_BAD) {
PR_fprintf(PR_STDERR, "Error: argument --migration is invalid when argument --osint is specified\n");
return NS_ERROR_FAILURE;
@ -2380,8 +2244,8 @@ SelectProfile(nsIProfileLock* *aResult, nsIToolkitProfileService* aProfileSvc, n
// Clear out flags that we handled (or should have handled!) last startup.
const char *dummy;
CheckArg("p", false, &dummy);
CheckArg("profile", false, &dummy);
CheckArg("p", &dummy);
CheckArg("profile", &dummy);
CheckArg("profilemanager");
if (gDoProfileReset) {
@ -2410,7 +2274,7 @@ SelectProfile(nsIProfileLock* *aResult, nsIToolkitProfileService* aProfileSvc, n
return NS_LockProfilePath(lf, localDir, nullptr, aResult);
}
ar = CheckArg("profile", true, &arg);
ar = CheckArg("profile", &arg, CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg);
if (ar == ARG_BAD) {
PR_fprintf(PR_STDERR, "Error: argument --profile requires a path\n");
return NS_ERROR_FAILURE;
@ -2444,7 +2308,7 @@ SelectProfile(nsIProfileLock* *aResult, nsIToolkitProfileService* aProfileSvc, n
return ProfileLockedDialog(lf, lf, unlocker, aNative, aResult);
}
ar = CheckArg("createprofile", true, &arg);
ar = CheckArg("createprofile", &arg, CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg);
if (ar == ARG_BAD) {
PR_fprintf(PR_STDERR, "Error: argument --createprofile requires a profile name\n");
return NS_ERROR_FAILURE;
@ -2500,7 +2364,7 @@ SelectProfile(nsIProfileLock* *aResult, nsIToolkitProfileService* aProfileSvc, n
rv = aProfileSvc->GetProfileCount(&count);
NS_ENSURE_SUCCESS(rv, rv);
ar = CheckArg("p", false, &arg);
ar = CheckArg("p", &arg);
if (ar == ARG_BAD) {
ar = CheckArg("osint");
if (ar == ARG_FOUND) {
@ -2565,7 +2429,7 @@ SelectProfile(nsIProfileLock* *aResult, nsIToolkitProfileService* aProfileSvc, n
}
}
ar = CheckArg("profilemanager", true);
ar = CheckArg("profilemanager", nullptr, CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg);
if (ar == ARG_BAD) {
PR_fprintf(PR_STDERR, "Error: argument --profilemanager is invalid when argument --osint is specified\n");
return NS_ERROR_FAILURE;
@ -3161,33 +3025,6 @@ public:
#endif
};
#ifdef XP_WIN
namespace {
bool PolicyHasRegValue(HKEY aKey, LPCWSTR aName, DWORD* aValue)
{
DWORD len = sizeof(DWORD);
LONG ret = ::RegGetValueW(aKey, L"SOFTWARE\\Policies\\Mozilla\\Firefox", aName,
RRF_RT_DWORD, nullptr, aValue, &len);
return ret == ERROR_SUCCESS;
}
bool SafeModeBlockedByPolicy()
{
LPCTSTR policyName = L"DisableSafeMode";
DWORD value;
if (PolicyHasRegValue(HKEY_LOCAL_MACHINE, policyName, &value)) {
return value == 1;
}
if (PolicyHasRegValue(HKEY_CURRENT_USER, policyName, &value)) {
return value == 1;
}
return false;
}
} // anonymous namespace
#endif // XP_WIN
#if defined(XP_UNIX) && !defined(ANDROID)
static SmprintfPointer
FormatUid(uid_t aId)
@ -3366,7 +3203,7 @@ XREMain::XRE_mainInit(bool* aExitFlag)
// Check for application.ini overrides
const char* override = nullptr;
ar = CheckArg("override", true, &override);
ar = CheckArg("override", &override, CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg);
if (ar == ARG_BAD) {
Output(true, "Incorrect number of arguments passed to --override");
return 1;
@ -3586,49 +3423,12 @@ XREMain::XRE_mainInit(bool* aExitFlag)
gRestartArgv[gRestartArgc] = nullptr;
ar = CheckArg("safe-mode", true);
if (ar == ARG_BAD) {
PR_fprintf(PR_STDERR, "Error: argument --safe-mode is invalid when argument --osint is specified\n");
Maybe<bool> safeModeRequested = IsSafeModeRequested(gArgc, gArgv);
if (!safeModeRequested) {
return 1;
}
if (ar == ARG_FOUND) {
gSafeMode = true;
}
#ifdef XP_WIN
// If the shift key is pressed and the ctrl and / or alt keys are not pressed
// during startup start in safe mode. GetKeyState returns a short and the high
// order bit will be 1 if the key is pressed. By masking the returned short
// with 0x8000 the result will be 0 if the key is not pressed and non-zero
// otherwise.
if ((GetKeyState(VK_SHIFT) & 0x8000) &&
!(GetKeyState(VK_CONTROL) & 0x8000) &&
!(GetKeyState(VK_MENU) & 0x8000) &&
!EnvHasValue("MOZ_DISABLE_SAFE_MODE_KEY")) {
gSafeMode = true;
}
#endif
#ifdef XP_MACOSX
if ((GetCurrentEventKeyModifiers() & optionKey) &&
!EnvHasValue("MOZ_DISABLE_SAFE_MODE_KEY"))
gSafeMode = true;
#endif
#ifdef XP_WIN
if (gSafeMode && SafeModeBlockedByPolicy()) {
gSafeMode = false;
}
#endif
// The Safe Mode Policy should not be enforced for the env var case
// (used by updater and crash-recovery).
if (EnvHasValue("MOZ_SAFE_MODE_RESTART")) {
gSafeMode = true;
// unset the env variable
SaveToEnv("MOZ_SAFE_MODE_RESTART=");
}
gSafeMode = safeModeRequested.value();
#ifdef XP_WIN
{
@ -3681,7 +3481,7 @@ if (gSafeMode && SafeModeBlockedByPolicy()) {
// Handle --no-remote and --new-instance command line arguments. Setup
// the environment to better accommodate other components and various
// restart scenarios.
ar = CheckArg("no-remote", true);
ar = CheckArg("no-remote", nullptr, CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg);
if (ar == ARG_BAD) {
PR_fprintf(PR_STDERR, "Error: argument --no-remote is invalid when argument --osint is specified\n");
return 1;
@ -3690,7 +3490,7 @@ if (gSafeMode && SafeModeBlockedByPolicy()) {
SaveToEnv("MOZ_NO_REMOTE=1");
}
ar = CheckArg("new-instance", true);
ar = CheckArg("new-instance", nullptr, CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg);
if (ar == ARG_BAD) {
PR_fprintf(PR_STDERR, "Error: argument --new-instance is invalid when argument --osint is specified\n");
return 1;
@ -3717,7 +3517,7 @@ if (gSafeMode && SafeModeBlockedByPolicy()) {
NS_ENSURE_SUCCESS(rv, 1);
// Check for --register, which registers chrome and then exits immediately.
ar = CheckArg("register", true);
ar = CheckArg("register", nullptr, CheckArgFlag::CheckOSInt | CheckArgFlag::RemoveArg);
if (ar == ARG_BAD) {
PR_fprintf(PR_STDERR, "Error: argument --register is invalid when argument --osint is specified\n");
return 1;
@ -4253,7 +4053,7 @@ XREMain::XRE_mainStartup(bool* aExitFlag)
// to make sure that the maintenance service successfully launches the
// callback application.
const char *logFile = nullptr;
if (ARG_FOUND == CheckArg("dump-args", false, &logFile)) {
if (ARG_FOUND == CheckArg("dump-args", &logFile)) {
FILE* logFP = fopen(logFile, "wb");
if (logFP) {
for (int i = 1; i < gRestartArgc; ++i) {
@ -5108,7 +4908,7 @@ XRE_InitCommandLine(int aArgc, char* aArgv[])
#endif
const char *path = nullptr;
ArgResult ar = CheckArg("greomni", false, &path);
ArgResult ar = CheckArg("greomni", &path);
if (ar == ARG_BAD) {
PR_fprintf(PR_STDERR, "Error: argument --greomni requires a path argument\n");
return NS_ERROR_FAILURE;
@ -5124,7 +4924,7 @@ XRE_InitCommandLine(int aArgc, char* aArgv[])
return rv;
}
ar = CheckArg("appomni", false, &path);
ar = CheckArg("appomni", &path);
if (ar == ARG_BAD) {
PR_fprintf(PR_STDERR, "Error: argument --appomni requires a path argument\n");
return NS_ERROR_FAILURE;

Просмотреть файл

@ -11,6 +11,7 @@
#define nsWindowsRestart_cpp
#endif
#include "mozilla/CmdLineAndEnvUtils.h"
#include "nsUTF8Utils.h"
#include <shellapi.h>
@ -19,135 +20,6 @@
#include <userenv.h>
#pragma comment(lib, "userenv.lib")
/**
* Get the length that the string will take and takes into account the
* additional length if the string needs to be quoted and if characters need to
* be escaped.
*/
static int ArgStrLen(const wchar_t *s)
{
int backslashes = 0;
int i = wcslen(s);
BOOL hasDoubleQuote = wcschr(s, L'"') != nullptr;
// Only add doublequotes if the string contains a space or a tab
BOOL addDoubleQuotes = wcspbrk(s, L" \t") != nullptr;
if (addDoubleQuotes) {
i += 2; // initial and final duoblequote
}
if (hasDoubleQuote) {
while (*s) {
if (*s == '\\') {
++backslashes;
} else {
if (*s == '"') {
// Escape the doublequote and all backslashes preceding the doublequote
i += backslashes + 1;
}
backslashes = 0;
}
++s;
}
}
return i;
}
/**
* Copy string "s" to string "d", quoting the argument as appropriate and
* escaping doublequotes along with any backslashes that immediately precede
* doublequotes.
* The CRT parses this to retrieve the original argc/argv that we meant,
* see STDARGV.C in the MSVC CRT sources.
*
* @return the end of the string
*/
static wchar_t* ArgToString(wchar_t *d, const wchar_t *s)
{
int backslashes = 0;
BOOL hasDoubleQuote = wcschr(s, L'"') != nullptr;
// Only add doublequotes if the string contains a space or a tab
BOOL addDoubleQuotes = wcspbrk(s, L" \t") != nullptr;
if (addDoubleQuotes) {
*d = '"'; // initial doublequote
++d;
}
if (hasDoubleQuote) {
int i;
while (*s) {
if (*s == '\\') {
++backslashes;
} else {
if (*s == '"') {
// Escape the doublequote and all backslashes preceding the doublequote
for (i = 0; i <= backslashes; ++i) {
*d = '\\';
++d;
}
}
backslashes = 0;
}
*d = *s;
++d; ++s;
}
} else {
wcscpy(d, s);
d += wcslen(s);
}
if (addDoubleQuotes) {
*d = '"'; // final doublequote
++d;
}
return d;
}
/**
* Creates a command line from a list of arguments. The returned
* string is allocated with "malloc" and should be "free"d.
*
* argv is UTF8
*/
wchar_t*
MakeCommandLine(int argc, wchar_t **argv)
{
int i;
int len = 0;
// The + 1 of the last argument handles the allocation for null termination
for (i = 0; i < argc; ++i)
len += ArgStrLen(argv[i]) + 1;
// Protect against callers that pass 0 arguments
if (len == 0)
len = 1;
wchar_t *s = (wchar_t*) malloc(len * sizeof(wchar_t));
if (!s)
return nullptr;
wchar_t *c = s;
for (i = 0; i < argc; ++i) {
c = ArgToString(c, argv[i]);
if (i + 1 != argc) {
*c = ' ';
++c;
}
}
*c = '\0';
return s;
}
/**
* Convert UTF8 to UTF16 without using the normal XPCOM goop, which we
* can't link to updater.exe.
@ -222,10 +94,9 @@ WinLaunchChild(const wchar_t *exePath,
HANDLE userToken,
HANDLE *hProcess)
{
wchar_t *cl;
BOOL ok;
cl = MakeCommandLine(argc, argv);
mozilla::UniquePtr<wchar_t[]> cl(mozilla::MakeCommandLine(argc, argv));
if (!cl) {
return FALSE;
}
@ -237,7 +108,7 @@ WinLaunchChild(const wchar_t *exePath,
if (userToken == nullptr) {
ok = CreateProcessW(exePath,
cl,
cl.get(),
nullptr, // no special security attributes
nullptr, // no special thread attributes
FALSE, // don't inherit filehandles
@ -256,7 +127,7 @@ WinLaunchChild(const wchar_t *exePath,
ok = CreateProcessAsUserW(userToken,
exePath,
cl,
cl.get(),
nullptr, // no special security attributes
nullptr, // no special thread attributes
FALSE, // don't inherit filehandles
@ -294,7 +165,5 @@ WinLaunchChild(const wchar_t *exePath,
LocalFree(lpMsgBuf);
}
free(cl);
return ok;
}

Просмотреть файл

@ -69,10 +69,10 @@ verifyCmdLineCreation(wchar_t *inCmdLine,
wcscat(inCmdLineNew, inCmdLine);
LPWSTR *inArgv = CommandLineToArgvW(inCmdLineNew, &inArgc);
wchar_t *outCmdLine = MakeCommandLine(inArgc - 1, inArgv + 1);
wchar_t *outCmdLineNew = (wchar_t *) malloc((wcslen(DUMMY_ARG1) + wcslen(outCmdLine) + 1) * sizeof(wchar_t));
auto outCmdLine = mozilla::MakeCommandLine(inArgc - 1, inArgv + 1);
wchar_t *outCmdLineNew = (wchar_t *) malloc((wcslen(DUMMY_ARG1) + wcslen(outCmdLine.get()) + 1) * sizeof(wchar_t));
wcscpy(outCmdLineNew, DUMMY_ARG1);
wcscat(outCmdLineNew, outCmdLine);
wcscat(outCmdLineNew, outCmdLine.get());
LPWSTR *outArgv = CommandLineToArgvW(outCmdLineNew, &outArgc);
if (VERBOSE) {
@ -80,7 +80,7 @@ verifyCmdLineCreation(wchar_t *inCmdLine,
wprintf(L"Verbose Output\n");
wprintf(L"--------------\n");
wprintf(L"Input command line : >%s<\n", inCmdLine);
wprintf(L"MakeComandLine output: >%s<\n", outCmdLine);
wprintf(L"MakeComandLine output: >%s<\n", outCmdLine.get());
wprintf(L"Expected command line: >%s<\n", compareCmdLine);
wprintf(L"input argc : %d\n", inArgc - 1);
@ -107,7 +107,6 @@ verifyCmdLineCreation(wchar_t *inCmdLine,
LocalFree(outArgv);
free(inCmdLineNew);
free(outCmdLineNew);
free(outCmdLine);
return rv;
}
@ -123,12 +122,11 @@ verifyCmdLineCreation(wchar_t *inCmdLine,
LocalFree(outArgv);
free(inCmdLineNew);
free(outCmdLineNew);
free(outCmdLine);
return rv;
}
}
isEqual = (wcscmp(outCmdLine, compareCmdLine) == 0);
isEqual = (wcscmp(outCmdLine.get(), compareCmdLine) == 0);
if (!isEqual) {
wprintf(L"TEST-%s-FAIL | %s | Command Line Comparison (check %2d)\n",
passes ? L"UNEXPECTED" : L"KNOWN", TEST_NAME, testNum);
@ -139,7 +137,6 @@ verifyCmdLineCreation(wchar_t *inCmdLine,
LocalFree(outArgv);
free(inCmdLineNew);
free(outCmdLineNew);
free(outCmdLine);
return rv;
}
@ -156,7 +153,6 @@ verifyCmdLineCreation(wchar_t *inCmdLine,
LocalFree(outArgv);
free(inCmdLineNew);
free(outCmdLineNew);
free(outCmdLine);
return rv;
}