int MSHelp2(const char *Keyword, const char *FileName, char *Error) { char CommandLine[2048]; if (Keyword) MakeCommandLine(CommandLine,PathToViewer,KeywordSearch,FileName,Keyword); else MakeCommandLine(CommandLine,PathToViewer,OpenContents,FileName,Keyword); STARTUPINFO si={0}; si.cb=sizeof(si); PROCESS_INFORMATION pi; int ret = CreateProcess(NULL,CommandLine,NULL,NULL,TRUE,0,NULL,NULL,&si,&pi); if (!ret) { LPSTR MessageBuffer; DWORD dwFormatFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_FROM_SYSTEM; DWORD dwBufferLength = FormatMessageA(dwFormatFlags,NULL,GetLastError(),MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),(LPSTR)&MessageBuffer,0,NULL); lstrcpyn(Error,MessageBuffer,dwBufferLength>128?128:dwBufferLength); CharToOem(Error,Error); } else { CloseHandle(pi.hProcess); CloseHandle(pi.hThread); } return ret; }
BOOL WinLaunchChild(const PRUnichar *exePath, int argc, PRUnichar **argv, int needElevation) { PRUnichar *cl; BOOL ok; if (needElevation > 0) { cl = MakeCommandLine(argc - 1, argv + 1); if (!cl) return FALSE; ok = ShellExecuteW(NULL, // no special UI window NULL, // use default verb exePath, cl, NULL, // use my current directory SW_SHOWDEFAULT) > (HINSTANCE)32; free(cl); return ok; } cl = MakeCommandLine(argc, argv); if (!cl) return FALSE; if (needElevation < 0) { // try to launch as a normal user first ok = LaunchAsNormalUser(exePath, cl); // if it fails, fallback to normal launching if (!ok) needElevation = 0; } if (needElevation == 0) { STARTUPINFOW si = {sizeof(si), 0}; PROCESS_INFORMATION pi = {0}; ok = CreateProcessW(exePath, cl, NULL, // no special security attributes NULL, // no special thread attributes FALSE, // don't inherit filehandles 0, // No special process creation flags NULL, // inherit my environment NULL, // use my current directory &si, &pi); if (ok) { CloseHandle(pi.hProcess); CloseHandle(pi.hThread); } } free(cl); return ok; }
int ExternalFilter(const char *Command, const char *Keyword, const char *Output, char *Error) { char CommandLine[2048]; lstrcpy(CommandLine,"%COMSPEC% /C "); FSF.ExpandEnvironmentStr(CommandLine,CommandLine,sizeof(CommandLine)); MakeCommandLine(CommandLine+lstrlen(CommandLine),Command,Keyword,Output); STARTUPINFO si={0}; si.cb=sizeof(si); PROCESS_INFORMATION pi; int ret = CreateProcess(NULL,CommandLine,NULL,NULL,TRUE,0,NULL,NULL,&si,&pi); if (!ret) { LPSTR MessageBuffer; DWORD dwFormatFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_FROM_SYSTEM; DWORD dwBufferLength = FormatMessageA(dwFormatFlags,NULL,GetLastError(),MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),(LPSTR)&MessageBuffer,0,NULL); lstrcpyn(Error,MessageBuffer,dwBufferLength>128?128:dwBufferLength); CharToOem(Error,Error); } else { WaitForSingleObject(pi.hProcess,INFINITE); CloseHandle(pi.hProcess); CloseHandle(pi.hThread); } return ret; }
CXTranslationUnit ClangWorkerThread::DoCreateTU(CXIndex index, ClangThreadRequest* task, bool reparse) { wxFileName fn(task->GetFileName()); DoSetStatusMsg(wxString::Format(wxT("clang: parsing file %s..."), fn.GetFullName().c_str())); FileExtManager::FileType type = FileExtManager::GetType(task->GetFileName()); int argc(0); char** argv = MakeCommandLine(task, argc, type); for(int i = 0; i < argc; i++) { CL_DEBUG(wxT("Command Line Argument: %s"), wxString(argv[i], wxConvUTF8).c_str()); } std::string c_filename = task->GetFileName().mb_str(wxConvUTF8).data(); CL_DEBUG(wxT("Calling clang_parseTranslationUnit...")); // First time, need to create it unsigned flags; if(reparse) { flags = CXTranslationUnit_CacheCompletionResults | CXTranslationUnit_PrecompiledPreamble | CXTranslationUnit_Incomplete | CXTranslationUnit_DetailedPreprocessingRecord | CXTranslationUnit_CXXChainedPCH; } else { flags = CXTranslationUnit_Incomplete | #if HAS_LIBCLANG_BRIEFCOMMENTS CXTranslationUnit_SkipFunctionBodies | #endif CXTranslationUnit_DetailedPreprocessingRecord; } CXTranslationUnit TU = clang_parseTranslationUnit(index, c_filename.c_str(), argv, argc, NULL, 0, flags); CL_DEBUG(wxT("Calling clang_parseTranslationUnit... done")); ClangUtils::FreeArgv(argv, argc); DoSetStatusMsg(wxString::Format(wxT("clang: parsing file %s...done"), fn.GetFullName().c_str())); if(TU && reparse) { CL_DEBUG(wxT("Calling clang_reparseTranslationUnit...")); if(clang_reparseTranslationUnit(TU, 0, NULL, clang_defaultReparseOptions(TU)) == 0) { CL_DEBUG(wxT("Calling clang_reparseTranslationUnit... done")); return TU; } else { CL_DEBUG(wxT("An error occured during reparsing of the TU for file %s. TU: %p"), task->GetFileName().c_str(), (void*)TU); // The only thing that left to be done here, is to dispose the TU clang_disposeTranslationUnit(TU); PostEvent(wxEVT_CLANG_TU_CREATE_ERROR, task->GetFileName()); return NULL; } } return TU; }
static int ProgramMode(int adx, int argc, FChS * argv[]) { FAssert(adx < argc); FObject nam = MakeStringS(argv[adx]); adx += 1; R.CommandLine = MakePair(MakeInvocation(adx, argv), MakeCommandLine(argc - adx, argv + adx)); FObject port; { FDontWait dw; port = OpenInputFile(nam); if (TextualPortP(port) == 0) { #ifdef FOMENT_WINDOWS printf("error: unable to open program: %S\n", argv[adx - 1]); #endif // FOMENT_WINDOWS #ifdef FOMENT_UNIX printf("error: unable to open program: %s\n", argv[adx - 1]); #endif // FOMENT_UNIX return(Usage()); } } FCh ch; // Skip #!/usr/local/bin/foment if (PeekCh(port, &ch) && ch == '#') ReadLine(port); FObject proc = CompileProgram(nam, port); ExecuteThunk(proc); ExitFoment(); return(0); }
/** * Runs an update process as the service using the SYSTEM account. * * @param argc The number of arguments in argv * @param argv The arguments normally passed to updater.exe * argv[0] must be the path to updater.exe * @param processStarted Set to TRUE if the process was started. * @return TRUE if the update process was run had a return code of 0. */ BOOL StartUpdateProcess(int argc, LPWSTR *argv, BOOL &processStarted) { LOG(("Starting update process as the service in session 0.\n")); STARTUPINFO si = {0}; si.cb = sizeof(STARTUPINFO); si.lpDesktop = L"winsta0\\Default"; PROCESS_INFORMATION pi = {0}; // The updater command line is of the form: // updater.exe update-dir apply [wait-pid [callback-dir callback-path args]] LPWSTR cmdLine = MakeCommandLine(argc, argv); // If we're about to start the update process from session 0, // then we should not show a GUI. This only really needs to be done // on Vista and higher, but it's better to keep everything consistent // across all OS if it's of no harm. if (argc >= 2 ) { // Setting the desktop to blank will ensure no GUI is displayed si.lpDesktop = L""; si.dwFlags |= STARTF_USESHOWWINDOW; si.wShowWindow = SW_HIDE; } // We move the updater.ini file out of the way because we will handle // executing PostUpdate through the service. We handle PostUpdate from // the service because there are some per user things that happen that // can't run in session 0 which we run updater.exe in. // Once we are done running updater.exe we rename updater.ini back so // that if there were any errors the next updater.exe will run correctly. WCHAR updaterINI[MAX_PATH + 1]; WCHAR updaterINITemp[MAX_PATH + 1]; BOOL selfHandlePostUpdate = FALSE; // We use the updater.ini from the same directory as the updater.exe // because of background updates. if (PathGetSiblingFilePath(updaterINI, argv[0], L"updater.ini") && PathGetSiblingFilePath(updaterINITemp, argv[0], L"updater.tmp")) { selfHandlePostUpdate = MoveFileExW(updaterINI, updaterINITemp, MOVEFILE_REPLACE_EXISTING); } // Add an env var for MOZ_USING_SERVICE so the updater.exe can // do anything special that it needs to do for service updates. // Search in updater.cpp for more info on MOZ_USING_SERVICE. putenv(const_cast<char*>("MOZ_USING_SERVICE=1")); LOG(("Starting service with cmdline: %ls\n", cmdLine)); processStarted = CreateProcessW(argv[0], cmdLine, NULL, NULL, FALSE, CREATE_DEFAULT_ERROR_MODE, NULL, NULL, &si, &pi); // Empty value on putenv is how you remove an env variable in Windows putenv(const_cast<char*>("MOZ_USING_SERVICE=")); BOOL updateWasSuccessful = FALSE; if (processStarted) { // Wait for the updater process to finish LOG(("Process was started... waiting on result.\n")); DWORD waitRes = WaitForSingleObject(pi.hProcess, TIME_TO_WAIT_ON_UPDATER); if (WAIT_TIMEOUT == waitRes) { // We waited a long period of time for updater.exe and it never finished // so kill it. TerminateProcess(pi.hProcess, 1); } else { // Check the return code of updater.exe to make sure we get 0 DWORD returnCode; if (GetExitCodeProcess(pi.hProcess, &returnCode)) { LOG(("Process finished with return code %d.\n", returnCode)); // updater returns 0 if successful. updateWasSuccessful = (returnCode == 0); } else { LOG(("Process finished but could not obtain return code.\n")); } } CloseHandle(pi.hProcess); CloseHandle(pi.hThread); // Check just in case updater.exe didn't change the status from // applying. If this is the case we report an error. BOOL isApplying = FALSE; if (IsStatusApplying(argv[1], isApplying) && isApplying) { if (updateWasSuccessful) { LOG(("update.status is still applying even know update " " was successful.\n")); if (!WriteStatusFailure(argv[1], SERVICE_STILL_APPLYING_ON_SUCCESS)) { LOG(("Could not write update.status still applying on" " success error.\n")); } // Since we still had applying we know updater.exe didn't do its // job correctly. updateWasSuccessful = FALSE; } else { LOG(("update.status is still applying and update was not successful.\n")); if (!WriteStatusFailure(argv[1], SERVICE_STILL_APPLYING_ON_FAILURE)) { LOG(("Could not write update.status still applying on" " success error.\n")); } } } } else { DWORD lastError = GetLastError(); LOG(("Could not create process as current user, " "updaterPath: %ls; cmdLine: %l. (%d)\n", argv[0], cmdLine, lastError)); } // Now that we're done with the update, restore back the updater.ini file // We use it ourselves, and also we want it back in case we had any type // of error so that the normal update process can use it. if (selfHandlePostUpdate) { MoveFileExW(updaterINITemp, updaterINI, MOVEFILE_REPLACE_EXISTING); // Only run the PostUpdate if the update was successful if (updateWasSuccessful && argc > 2) { LPCWSTR installationDir = argv[2]; LPCWSTR updateInfoDir = argv[1]; // Launch the PostProcess with admin access in session 0. This is // actually launching the post update process but it takes in the // callback app path to figure out where to apply to. // The PostUpdate process with user only access will be done inside // the unelevated updater.exe after the update process is complete // from the service. We don't know here which session to start // the user PostUpdate process from. LOG(("Launching post update process as the service in session 0.\n")); if (!LaunchWinPostProcess(installationDir, updateInfoDir, true, NULL)) { LOG(("The post update process could not be launched.\n")); } } } free(cmdLine); return updateWasSuccessful; }
BOOL WinLaunchChild(const wchar_t *exePath, int argc, wchar_t **argv, HANDLE userToken, HANDLE *hProcess) { wchar_t *cl; BOOL ok; cl = MakeCommandLine(argc, argv); if (!cl) { return FALSE; } STARTUPINFOW si = {0}; si.cb = sizeof(STARTUPINFOW); si.lpDesktop = L"winsta0\\Default"; PROCESS_INFORMATION pi = {0}; if (userToken == nullptr) { ok = CreateProcessW(exePath, cl, nullptr, // no special security attributes nullptr, // no special thread attributes FALSE, // don't inherit filehandles 0, // creation flags nullptr, // inherit my environment nullptr, // use my current directory &si, &pi); } else { // Create an environment block for the process we're about to start using // the user's token. LPVOID environmentBlock = nullptr; if (!CreateEnvironmentBlock(&environmentBlock, userToken, TRUE)) { environmentBlock = nullptr; } ok = CreateProcessAsUserW(userToken, exePath, cl, nullptr, // no special security attributes nullptr, // no special thread attributes FALSE, // don't inherit filehandles 0, // creation flags environmentBlock, nullptr, // use my current directory &si, &pi); if (environmentBlock) { DestroyEnvironmentBlock(environmentBlock); } } if (ok) { if (hProcess) { *hProcess = pi.hProcess; // the caller now owns the HANDLE } else { CloseHandle(pi.hProcess); } CloseHandle(pi.hThread); } else { LPVOID lpMsgBuf = nullptr; FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, nullptr); wprintf(L"Error restarting: %s\n", lpMsgBuf ? static_cast<const wchar_t*>(lpMsgBuf) : L"(null)"); if (lpMsgBuf) LocalFree(lpMsgBuf); } free(cl); return ok; }
int main(int argc, char * argv[]) #endif // FOMENT_UNIX { int_t pdx = 0; int adx = 1; while (adx < argc) { if (StringCompareS(argv[adx], "-A") == 0) adx += 2; else if (StringCompareS(argv[adx], "-I") == 0) adx += 2; else if (StringCompareS(argv[adx], "-X") == 0) adx += 2; else if (argv[adx][0] != '-') { pdx = adx; break; } else if (StringCompareS(argv[adx], "-no-inline-procedures") == 0) { InlineProcedures = 0; adx += 1; } else if (StringCompareS(argv[adx], "-no-inline-imports") == 0) { InlineImports = 0; adx += 1; } else if (StringCompareS(argv[adx], "--validate-heap") == 0) { ValidateHeap = 1; adx += 1; } #ifdef FOMENT_WINDOWS else if (StringCompareS(argv[adx], "--section-table") == 0) { adx += 1; if (adx < argc) { #ifdef FOMENT_32BIT SectionTableBase = (void *) wcstol(argv[adx], 0, 16); #endif // FOMENT_32BIT #ifdef FOMENT_64BIT SectionTableBase = (void *) _wcstoui64(argv[adx], 0, 16); #endif // FOMENT_64BIT adx += 1; } } #endif // FOMENT_WINDOWS else if (StringCompareS(argv[adx], "--random-seed") == 0) { adx += 1; if (adx < argc) { RandomSeed = StringToInt(argv[adx]); adx += 1; } } else break; } FThreadState ts; try { SetupFoment(&ts); if (pdx > 0) { AddToLibraryPath(argv[pdx]); } } catch (FObject obj) { printf("Unexpected exception: SetupFoment: %p\n", obj); WriteSimple(R.StandardOutput, obj, 0); if (ValidateHeap) { FailedGC(); FailedExecute(); } return(1); } FAssert(argc >= 1); try { int adx = 1; while (adx < argc) { if (StringCompareS(argv[adx], "-A") == 0) { adx += 1; if (adx == argc) return(MissingArgument(argv[adx - 1])); FObject lp = R.LibraryPath; for (;;) { FAssert(PairP(lp)); if (Rest(lp) == EmptyListObject) break; lp = Rest(lp); } // AsPair(lp)->Rest = MakePair(MakeStringS(argv[adx]), EmptyListObject); SetRest(lp, MakePair(MakeStringS(argv[adx]), EmptyListObject)); adx += 1; } else if (StringCompareS(argv[adx], "-I") == 0) { adx += 1; if (adx == argc) return(MissingArgument(argv[adx - 1])); R.LibraryPath = MakePair(MakeStringS(argv[adx]), R.LibraryPath); adx += 1; } else if (StringCompareS(argv[adx], "-X") == 0) { adx += 1; if (adx == argc) return(MissingArgument(argv[adx - 1])); R.LibraryExtensions = MakePair(MakeStringS(argv[adx]), R.LibraryExtensions); adx += 1; } else if (StringCompareS(argv[adx], "-no-inline-procedures") == 0 || StringCompareS(argv[adx], "-no-inline-imports") == 0 || StringCompareS(argv[adx], "--validate-heap") == 0) adx += 1; #ifdef FOMENT_WINDOWS else if (StringCompareS(argv[adx], "--section-table") == 0) adx += 2; #endif // FOMENT_WINDOWS else if (StringCompareS(argv[adx], "--random-seed") == 0) adx += 2; else if (argv[adx][0] != '-') return(ProgramMode(adx, argc, argv)); else break; } R.LibraryPath = ReverseListModify(MakePair(MakeStringC("."), R.LibraryPath)); R.CommandLine = MakePair(MakeInvocation(adx, argv), MakeCommandLine(argc - adx, argv + adx)); ExecuteThunk(R.InteractiveThunk); ExitFoment(); return(0); // return(RunRepl(GetInteractionEnv())); } catch (FObject obj) { if (ExceptionP(obj) == 0) WriteStringC(R.StandardOutput, "exception: "); WriteSimple(R.StandardOutput, obj, 0); WriteCh(R.StandardOutput, '\n'); if (ValidateHeap) { FailedGC(); FailedExecute(); } return(-1); } }
bool LaunchUnelevated(int aArgc, wchar_t* aArgv[]) { // We require a single-threaded apartment to talk to Explorer. mscom::STARegion sta; if (!sta.IsValid()) { return false; } // NB: Explorer is a local server, not an inproc server RefPtr<IShellWindows> shellWindows; HRESULT hr = ::CoCreateInstance(CLSID_ShellWindows, nullptr, CLSCTX_LOCAL_SERVER, IID_IShellWindows, getter_AddRefs(shellWindows)); if (FAILED(hr)) { return false; } // 1. Find the shell view for the desktop. _variant_t loc(CSIDL_DESKTOP); _variant_t empty; long hwnd; RefPtr<IDispatch> dispDesktop; hr = shellWindows->FindWindowSW(&loc, &empty, SWC_DESKTOP, &hwnd, SWFO_NEEDDISPATCH, getter_AddRefs(dispDesktop)); if (FAILED(hr)) { return false; } RefPtr<IServiceProvider> servProv; hr = dispDesktop->QueryInterface(IID_IServiceProvider, getter_AddRefs(servProv)); if (FAILED(hr)) { return false; } RefPtr<IShellBrowser> browser; hr = servProv->QueryService(SID_STopLevelBrowser, IID_IShellBrowser, getter_AddRefs(browser)); if (FAILED(hr)) { return false; } RefPtr<IShellView> activeShellView; hr = browser->QueryActiveShellView(getter_AddRefs(activeShellView)); if (FAILED(hr)) { return false; } // 2. Get the automation object for the desktop. RefPtr<IDispatch> dispView; hr = activeShellView->GetItemObject(SVGIO_BACKGROUND, IID_IDispatch, getter_AddRefs(dispView)); if (FAILED(hr)) { return false; } RefPtr<IShellFolderViewDual> folderView; hr = dispView->QueryInterface(IID_IShellFolderViewDual, getter_AddRefs(folderView)); if (FAILED(hr)) { return false; } // 3. Get the interface to IShellDispatch2 RefPtr<IDispatch> dispShell; hr = folderView->get_Application(getter_AddRefs(dispShell)); if (FAILED(hr)) { return false; } RefPtr<IShellDispatch2> shellDisp; hr = dispShell->QueryInterface(IID_IShellDispatch2, getter_AddRefs(shellDisp)); if (FAILED(hr)) { return false; } // 4. Now call IShellDispatch2::ShellExecute to ask Explorer to re-launch us. // Omit argv[0] because ShellExecute doesn't need it in params UniquePtr<wchar_t[]> cmdLine(MakeCommandLine(aArgc - 1, aArgv + 1)); if (!cmdLine) { return false; } _bstr_t exe(aArgv[0]); _variant_t args(cmdLine.get()); _variant_t operation(L"open"); _variant_t directory; _variant_t showCmd(SW_SHOWNORMAL); hr = shellDisp->ShellExecute(exe, args, operation, directory, showCmd); return SUCCEEDED(hr); }
int LauncherMain(int argc, wchar_t* argv[]) { // Make sure that the launcher process itself has image load policies set if (IsWin10AnniversaryUpdateOrLater()) { const DynamicallyLinkedFunctionPtr<decltype(&SetProcessMitigationPolicy)> pSetProcessMitigationPolicy(L"kernel32.dll", "SetProcessMitigationPolicy"); if (pSetProcessMitigationPolicy) { PROCESS_MITIGATION_IMAGE_LOAD_POLICY imgLoadPol = {}; imgLoadPol.PreferSystem32Images = 1; DebugOnly<BOOL> setOk = pSetProcessMitigationPolicy(ProcessImageLoadPolicy, &imgLoadPol, sizeof(imgLoadPol)); MOZ_ASSERT(setOk); } } if (!SetArgv0ToFullBinaryPath(argv)) { ShowError(); return 1; } LauncherFlags flags = ProcessCmdLine(argc, argv); nsAutoHandle mediumIlToken; Maybe<ElevationState> elevationState = GetElevationState(flags, mediumIlToken); if (!elevationState) { return 1; } // If we're elevated, we should relaunch ourselves as a normal user. // Note that we only call LaunchUnelevated when we don't need to wait for the // browser process. if (elevationState.value() == ElevationState::eElevated && !(flags & (LauncherFlags::eWaitForBrowser | LauncherFlags::eNoDeelevate)) && !mediumIlToken.get()) { return !LaunchUnelevated(argc, argv); } // Now proceed with setting up the parameters for process creation UniquePtr<wchar_t[]> cmdLine(MakeCommandLine(argc, argv)); if (!cmdLine) { return 1; } const Maybe<bool> isSafeMode = IsSafeModeRequested(argc, argv, SafeModeFlag::NoKeyPressCheck); if (!isSafeMode) { ShowError(ERROR_INVALID_PARAMETER); return 1; } ProcThreadAttributes attrs; SetMitigationPolicies(attrs, isSafeMode.value()); HANDLE stdHandles[] = { ::GetStdHandle(STD_INPUT_HANDLE), ::GetStdHandle(STD_OUTPUT_HANDLE), ::GetStdHandle(STD_ERROR_HANDLE) }; attrs.AddInheritableHandles(stdHandles); DWORD creationFlags = CREATE_SUSPENDED | CREATE_UNICODE_ENVIRONMENT; STARTUPINFOEXW siex; Maybe<bool> attrsOk = attrs.AssignTo(siex); if (!attrsOk) { ShowError(); return 1; } BOOL inheritHandles = FALSE; if (attrsOk.value()) { creationFlags |= EXTENDED_STARTUPINFO_PRESENT; if (attrs.HasInheritableHandles()) { siex.StartupInfo.dwFlags |= STARTF_USESTDHANDLES; siex.StartupInfo.hStdInput = stdHandles[0]; siex.StartupInfo.hStdOutput = stdHandles[1]; siex.StartupInfo.hStdError = stdHandles[2]; // Since attrsOk == true, we have successfully set the handle inheritance // whitelist policy, so only the handles added to attrs will be inherited. inheritHandles = TRUE; } } PROCESS_INFORMATION pi = {}; BOOL createOk; if (mediumIlToken.get()) { createOk = ::CreateProcessAsUserW(mediumIlToken.get(), argv[0], cmdLine.get(), nullptr, nullptr, inheritHandles, creationFlags, nullptr, nullptr, &siex.StartupInfo, &pi); } else { createOk = ::CreateProcessW(argv[0], cmdLine.get(), nullptr, nullptr, inheritHandles, creationFlags, nullptr, nullptr, &siex.StartupInfo, &pi); } if (!createOk) { ShowError(); return 1; } nsAutoHandle process(pi.hProcess); nsAutoHandle mainThread(pi.hThread); if (!PostCreationSetup(process.get(), mainThread.get(), isSafeMode.value()) || ::ResumeThread(mainThread.get()) == static_cast<DWORD>(-1)) { ShowError(); ::TerminateProcess(process.get(), 1); return 1; } if (flags & LauncherFlags::eWaitForBrowser) { DWORD exitCode; if (::WaitForSingleObject(process.get(), INFINITE) == WAIT_OBJECT_0 && ::GetExitCodeProcess(process.get(), &exitCode)) { // Propagate the browser process's exit code as our exit code. return static_cast<int>(exitCode); } } else { const DWORD timeout = ::IsDebuggerPresent() ? INFINITE : kWaitForInputIdleTimeoutMS; // Keep the current process around until the callback process has created // its message queue, to avoid the launched process's windows being forced // into the background. mozilla::WaitForInputIdle(process.get(), timeout); } return 0; }
/** * Runs an update process as the service using the SYSTEM account. * * @param argc The number of arguments in argv * @param argv The arguments normally passed to updater.exe * argv[0] must be the path to updater.exe * @param processStarted Set to TRUE if the process was started. * @return TRUE if the update process was run had a return code of 0. */ BOOL StartUpdateProcess(int argc, LPWSTR *argv, LPCWSTR installDir, BOOL &processStarted) { LOG(("Starting update process as the service in session 0.")); STARTUPINFO si = {0}; si.cb = sizeof(STARTUPINFO); si.lpDesktop = L"winsta0\\Default"; PROCESS_INFORMATION pi = {0}; // The updater command line is of the form: // updater.exe update-dir apply [wait-pid [callback-dir callback-path args]] LPWSTR cmdLine = MakeCommandLine(argc, argv); int index = 3; if (IsOldCommandline(argc, argv)) { index = 2; } // If we're about to start the update process from session 0, // then we should not show a GUI. This only really needs to be done // on Vista and higher, but it's better to keep everything consistent // across all OS if it's of no harm. if (argc >= index) { // Setting the desktop to blank will ensure no GUI is displayed si.lpDesktop = L""; si.dwFlags |= STARTF_USESHOWWINDOW; si.wShowWindow = SW_HIDE; } // Add an env var for MOZ_USING_SERVICE so the updater.exe can // do anything special that it needs to do for service updates. // Search in updater.cpp for more info on MOZ_USING_SERVICE. putenv(const_cast<char*>("MOZ_USING_SERVICE=1")); LOG(("Starting service with cmdline: %ls", cmdLine)); processStarted = CreateProcessW(argv[0], cmdLine, nullptr, nullptr, FALSE, CREATE_DEFAULT_ERROR_MODE, nullptr, nullptr, &si, &pi); BOOL updateWasSuccessful = FALSE; if (processStarted) { // Wait for the updater process to finish LOG(("Process was started... waiting on result.")); DWORD waitRes = WaitForSingleObject(pi.hProcess, TIME_TO_WAIT_ON_UPDATER); if (WAIT_TIMEOUT == waitRes) { // We waited a long period of time for updater.exe and it never finished // so kill it. TerminateProcess(pi.hProcess, 1); } else { // Check the return code of updater.exe to make sure we get 0 DWORD returnCode; if (GetExitCodeProcess(pi.hProcess, &returnCode)) { LOG(("Process finished with return code %d.", returnCode)); // updater returns 0 if successful. updateWasSuccessful = (returnCode == 0); } else { LOG_WARN(("Process finished but could not obtain return code.")); } } CloseHandle(pi.hProcess); CloseHandle(pi.hThread); // Check just in case updater.exe didn't change the status from // applying. If this is the case we report an error. BOOL isApplying = FALSE; if (IsStatusApplying(argv[1], isApplying) && isApplying) { if (updateWasSuccessful) { LOG(("update.status is still applying even know update " " was successful.")); if (!WriteStatusFailure(argv[1], SERVICE_STILL_APPLYING_ON_SUCCESS)) { LOG_WARN(("Could not write update.status still applying on" " success error.")); } // Since we still had applying we know updater.exe didn't do its // job correctly. updateWasSuccessful = FALSE; } else { LOG_WARN(("update.status is still applying and update was not successful.")); if (!WriteStatusFailure(argv[1], SERVICE_STILL_APPLYING_ON_FAILURE)) { LOG_WARN(("Could not write update.status still applying on" " success error.")); } } } } else { DWORD lastError = GetLastError(); LOG_WARN(("Could not create process as current user, " "updaterPath: %ls; cmdLine: %ls. (%d)", argv[0], cmdLine, lastError)); } // Empty value on putenv is how you remove an env variable in Windows putenv(const_cast<char*>("MOZ_USING_SERVICE=")); free(cmdLine); return updateWasSuccessful; }
// Compares compareCmdLine with the output of MakeCommandLine. This is // accomplished by converting inCmdLine to an argument list with // CommandLineToArgvW and converting it back to a command line with // MakeCommandLine. static int verifyCmdLineCreation(PRUnichar *inCmdLine, PRUnichar *compareCmdLine, bool passes, int testNum) { int rv = 0; int i; int inArgc; int outArgc; bool isEqual; // When debugging with command lines containing Unicode characters greater // than 255 you can set the mode for stdout to Unicode so the console will // receive the correct characters though it won't display them properly unless // the console's font has been set to one that can display the characters. You // can also redirect the console output to a file that has been saved as Unicode // to view the characters. // _setmode(_fileno(stdout), _O_WTEXT); // Prepend an additional argument to the command line. CommandLineToArgvW // handles argv[0] differently than other arguments since argv[0] is the path // to the binary being executed and MakeCommandLine only handles argv[1] and // larger. PRUnichar *inCmdLineNew = (PRUnichar *) malloc((wcslen(DUMMY_ARG1) + wcslen(inCmdLine) + 1) * sizeof(PRUnichar)); wcscpy(inCmdLineNew, DUMMY_ARG1); wcscat(inCmdLineNew, inCmdLine); LPWSTR *inArgv = CommandLineToArgvW(inCmdLineNew, &inArgc); PRUnichar *outCmdLine = MakeCommandLine(inArgc - 1, inArgv + 1); PRUnichar *outCmdLineNew = (PRUnichar *) malloc((wcslen(DUMMY_ARG1) + wcslen(outCmdLine) + 1) * sizeof(PRUnichar)); wcscpy(outCmdLineNew, DUMMY_ARG1); wcscat(outCmdLineNew, outCmdLine); LPWSTR *outArgv = CommandLineToArgvW(outCmdLineNew, &outArgc); if (VERBOSE) { wprintf(L"\n"); 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"Expected command line: >%s<\n", compareCmdLine); wprintf(L"input argc : %d\n", inArgc - 1); wprintf(L"output argc: %d\n", outArgc - 1); for (i = 1; i < inArgc; ++i) { wprintf(L"input argv[%d] : >%s<\n", i - 1, inArgv[i]); } for (i = 1; i < outArgc; ++i) { wprintf(L"output argv[%d]: >%s<\n", i - 1, outArgv[i]); } wprintf(L"\n"); } isEqual = (inArgc == outArgc); if (!isEqual) { wprintf(L"TEST-%s-FAIL | %s | ARGC Comparison (check %2d)\n", passes ? L"UNEXPECTED" : L"KNOWN", TEST_NAME, testNum); if (passes) { rv = 1; } LocalFree(inArgv); LocalFree(outArgv); free(inCmdLineNew); free(outCmdLineNew); free(outCmdLine); return rv; } for (i = 1; i < inArgc; ++i) { isEqual = (wcscmp(inArgv[i], outArgv[i]) == 0); if (!isEqual) { wprintf(L"TEST-%s-FAIL | %s | ARGV Comparison (check %2d)\n", passes ? L"UNEXPECTED" : L"KNOWN", TEST_NAME, testNum); if (passes) { rv = 1; } LocalFree(inArgv); LocalFree(outArgv); free(inCmdLineNew); free(outCmdLineNew); free(outCmdLine); return rv; } } isEqual = (wcscmp(outCmdLine, compareCmdLine) == 0); if (!isEqual) { wprintf(L"TEST-%s-FAIL | %s | Command Line Comparison (check %2d)\n", passes ? L"UNEXPECTED" : L"KNOWN", TEST_NAME, testNum); if (passes) { rv = 1; } LocalFree(inArgv); LocalFree(outArgv); free(inCmdLineNew); free(outCmdLineNew); free(outCmdLine); return rv; } if (rv == 0) { if (passes) { wprintf(L"TEST-PASS | %s | check %2d\n", TEST_NAME, testNum); } else { wprintf(L"TEST-UNEXPECTED-PASS | %s | check %2d\n", TEST_NAME, testNum); rv = 1; } } LocalFree(inArgv); LocalFree(outArgv); free(inCmdLineNew); free(outCmdLineNew); free(outCmdLine); return rv; }