/** * Main entry point when running as a service. */ void WINAPI SvcMain(DWORD argc, LPWSTR *argv) { // Setup logging, and backup the old logs WCHAR updatePath[MAX_PATH + 1]; if (GetLogDirectoryPath(updatePath)) { BackupOldLogs(updatePath, LOGS_TO_KEEP); LogInit(updatePath, L"maintenanceservice.log"); } // Disable every privilege we don't need. Processes started using // CreateProcess will use the same token as this process. UACHelper::DisablePrivileges(NULL); // Register the handler function for the service gSvcStatusHandle = RegisterServiceCtrlHandlerW(SVC_NAME, SvcCtrlHandler); if (!gSvcStatusHandle) { LOG(("RegisterServiceCtrlHandler failed (%d)\n", GetLastError())); ExecuteServiceCommand(argc, argv); LogFinish(); exit(1); } // These values will be re-used later in calls involving gSvcStatus gSvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; gSvcStatus.dwServiceSpecificExitCode = 0; // Report initial status to the SCM ReportSvcStatus(SERVICE_START_PENDING, NO_ERROR, 3000); // This event will be used to tell the SvcCtrlHandler when the work is // done for when a stop comamnd is manually issued. gWorkDoneEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (!gWorkDoneEvent) { ReportSvcStatus(SERVICE_STOPPED, 1, 0); StartTerminationThread(); return; } // Initialization complete and we're about to start working on // the actual command. Report the service state as running to the SCM. ReportSvcStatus(SERVICE_RUNNING, NO_ERROR, 0); // The service command was executed, stop logging and set an event // to indicate the work is done in case someone is waiting on a // service stop operation. ExecuteServiceCommand(argc, argv); LogFinish(); SetEvent(gWorkDoneEvent); // If we aren't already in a stopping state then tell the SCM we're stopped // now. If we are already in a stopping state then the SERVICE_STOPPED state // will be set by the SvcCtrlHandler. if (!gServiceControlStopping) { ReportSvcStatus(SERVICE_STOPPED, NO_ERROR, 0); StartTerminationThread(); } }
int NS_main(int argc, NS_tchar **argv) { // The updater command line consists of the directory path containing the // updater.mar file to process followed by the PID of the calling process. // The updater will wait on the parent process to exit if the PID is non- // zero. This is leveraged on platforms such as Windows where it is // necessary for the parent process to exit before its executable image may // be altered. //for (int i = 0; i < argc; ++i) { // NS_tfprintf(stderr, NS_T("arg[%d]=%s\n"), i, argv[i]); //} if (argc < 3) { fprintf(stderr, "Usage: updater <dir-path> <parent-pid> [working-dir callback args...]\n"); return 1; } int pid = NS_tatoi(argv[2]); if (pid) { #ifdef XP_WIN HANDLE parent = OpenProcess(SYNCHRONIZE, FALSE, (DWORD) pid); // May return NULL if the parent process has already gone away. // Otherwise, wait for the parent process to exit before starting the // update. if (parent) { DWORD result = WaitForSingleObject(parent, 5000); CloseHandle(parent); if (result != WAIT_OBJECT_0) return 1; // The process may be signaled before it releases the executable image. // This is a terrible hack, but it'll have to do for now :-( Sleep(50); } #else int status; waitpid(pid, &status, 0); #endif } LogInit(argv[1]); DoUpdate(argv[1]); LogFinish(); return 0; }
int wmain(int argc, WCHAR **argv) { // If command-line parameter is "install", install the service // or upgrade if already installed // If command line parameter is "forceinstall", install the service // even if it is older than what is already installed. // If command-line parameter is "upgrade", upgrade the service // but do not install it if it is not already installed. // If command line parameter is "uninstall", uninstall the service. // Otherwise, the service is probably being started by the SCM. bool forceInstall = !lstrcmpi(argv[1], L"forceinstall"); if (!lstrcmpi(argv[1], L"install") || forceInstall) { WCHAR updatePath[MAX_PATH + 1]; if (GetLogDirectoryPath(updatePath)) { LogInit(updatePath, L"maintenanceservice-install.log"); } LOG(("Installing service")); SvcInstallAction action = InstallSvc; if (forceInstall) { action = ForceInstallSvc; LOG((" with force specified")); } LOG(("...\n")); if (!SvcInstall(action)) { LOG(("Could not install service (%d)\n", GetLastError())); LogFinish(); return 1; } LOG(("The service was installed successfully\n")); LogFinish(); return 0; } if (!lstrcmpi(argv[1], L"upgrade")) { WCHAR updatePath[MAX_PATH + 1]; if (GetLogDirectoryPath(updatePath)) { LogInit(updatePath, L"maintenanceservice-install.log"); } LOG(("Upgrading service if installed...\n")); if (!SvcInstall(UpgradeSvc)) { LOG(("Could not upgrade service (%d)\n", GetLastError())); LogFinish(); return 1; } LOG(("The service was upgraded successfully\n")); LogFinish(); return 0; } if (!lstrcmpi(argv[1], L"uninstall")) { WCHAR updatePath[MAX_PATH + 1]; if (GetLogDirectoryPath(updatePath)) { LogInit(updatePath, L"maintenanceservice-uninstall.log"); } LOG(("Uninstalling service...\n")); if (!SvcUninstall()) { LOG(("Could not uninstall service (%d)\n", GetLastError())); LogFinish(); return 1; } LOG(("The service was uninstalled successfully\n")); LogFinish(); return 0; } SERVICE_TABLE_ENTRYW DispatchTable[] = { { SVC_NAME, (LPSERVICE_MAIN_FUNCTIONW) SvcMain }, { NULL, NULL } }; // This call returns when the service has stopped. // The process should simply terminate when the call returns. if (!StartServiceCtrlDispatcherW(DispatchTable)) { LOG(("StartServiceCtrlDispatcher failed (%d)\n", GetLastError())); } return 0; }