1 /* 2 * PROJECT: ReactOS Service Control Manager 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: base/system/services/services.c 5 * PURPOSE: Main SCM controller 6 * COPYRIGHT: Copyright 2001-2005 Eric Kohl 7 * Copyright 2007 Ged Murphy <gedmurphy@reactos.org> 8 * 9 */ 10 11 /* INCLUDES *****************************************************************/ 12 13 #include "services.h" 14 15 #include <wincon.h> 16 17 #define NDEBUG 18 #include <debug.h> 19 20 int WINAPI RegisterServicesProcess(DWORD ServicesProcessId); 21 22 /* GLOBALS ******************************************************************/ 23 24 /* Defined in include/reactos/services/services.h */ 25 // #define SCM_START_EVENT L"SvcctrlStartEvent_A3752DX" 26 #define SCM_AUTOSTARTCOMPLETE_EVENT L"SC_AutoStartComplete" 27 28 BOOL ScmInitialize = FALSE; 29 BOOL ScmShutdown = FALSE; 30 BOOL ScmLiveSetup = FALSE; 31 static HANDLE hScmShutdownEvent = NULL; 32 static HANDLE hScmSecurityServicesEvent = NULL; 33 34 35 /* FUNCTIONS *****************************************************************/ 36 37 VOID 38 PrintString(LPCSTR fmt, ...) 39 { 40 #if DBG 41 CHAR buffer[512]; 42 va_list ap; 43 44 va_start(ap, fmt); 45 vsprintf(buffer, fmt, ap); 46 va_end(ap); 47 48 OutputDebugStringA(buffer); 49 #endif 50 } 51 52 DWORD 53 CheckForLiveCD(VOID) 54 { 55 WCHAR CommandLine[MAX_PATH]; 56 HKEY hSetupKey; 57 DWORD dwSetupType; 58 DWORD dwType; 59 DWORD dwSize; 60 DWORD dwError; 61 62 DPRINT1("CheckSetup()\n"); 63 64 /* Open the Setup key */ 65 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 66 L"SYSTEM\\Setup", 67 0, 68 KEY_QUERY_VALUE, 69 &hSetupKey); 70 if (dwError != ERROR_SUCCESS) 71 return dwError; 72 73 /* Read the SetupType value */ 74 dwSize = sizeof(DWORD); 75 dwError = RegQueryValueExW(hSetupKey, 76 L"SetupType", 77 NULL, 78 &dwType, 79 (LPBYTE)&dwSetupType, 80 &dwSize); 81 82 if (dwError != ERROR_SUCCESS || 83 dwType != REG_DWORD || 84 dwSize != sizeof(DWORD) || 85 dwSetupType == 0) 86 goto done; 87 88 /* Read the CmdLine value */ 89 dwSize = sizeof(CommandLine); 90 dwError = RegQueryValueExW(hSetupKey, 91 L"CmdLine", 92 NULL, 93 &dwType, 94 (LPBYTE)CommandLine, 95 &dwSize); 96 97 if (dwError != ERROR_SUCCESS || 98 (dwType != REG_SZ && 99 dwType != REG_EXPAND_SZ && 100 dwType != REG_MULTI_SZ)) 101 goto done; 102 103 /* Check for the '-mini' option */ 104 if (wcsstr(CommandLine, L" -mini") != NULL) 105 { 106 DPRINT1("Running on LiveCD!\n"); 107 ScmLiveSetup = TRUE; 108 } 109 110 done: 111 RegCloseKey(hSetupKey); 112 113 return dwError; 114 } 115 116 117 DWORD 118 SetSecurityServicesEvent(VOID) 119 { 120 DWORD dwError; 121 122 if (hScmSecurityServicesEvent != NULL) 123 return ERROR_SUCCESS; 124 125 /* Create or open the SECURITY_SERVICES_STARTED event */ 126 hScmSecurityServicesEvent = CreateEventW(NULL, 127 TRUE, 128 FALSE, 129 L"SECURITY_SERVICES_STARTED"); 130 if (hScmSecurityServicesEvent == NULL) 131 { 132 dwError = GetLastError(); 133 if (dwError != ERROR_ALREADY_EXISTS) 134 return dwError; 135 136 hScmSecurityServicesEvent = OpenEventW(EVENT_MODIFY_STATE, 137 FALSE, 138 L"SECURITY_SERVICES_STARTED"); 139 if (hScmSecurityServicesEvent == NULL) 140 return GetLastError(); 141 } 142 143 SetEvent(hScmSecurityServicesEvent); 144 145 return ERROR_SUCCESS; 146 } 147 148 149 VOID 150 ScmLogEvent(DWORD dwEventId, 151 WORD wType, 152 WORD wStrings, 153 LPCWSTR *lpStrings) 154 { 155 HANDLE hLog; 156 157 hLog = RegisterEventSourceW(NULL, 158 L"Service Control Manager"); 159 if (hLog == NULL) 160 { 161 DPRINT1("ScmLogEvent: RegisterEventSourceW failed %lu\n", GetLastError()); 162 return; 163 } 164 165 if (!ReportEventW(hLog, 166 wType, 167 0, 168 dwEventId, 169 NULL, 170 wStrings, 171 0, 172 lpStrings, 173 NULL)) 174 { 175 DPRINT1("ScmLogEvent: ReportEventW failed %lu\n", GetLastError()); 176 } 177 178 DeregisterEventSource(hLog); 179 } 180 181 182 VOID 183 ScmWaitForLsa(VOID) 184 { 185 HANDLE hEvent = CreateEventW(NULL, TRUE, FALSE, L"LSA_RPC_SERVER_ACTIVE"); 186 if (hEvent == NULL) 187 { 188 DPRINT1("Failed to create or open the notification event (Error %lu)\n", GetLastError()); 189 } 190 else 191 { 192 DPRINT("Wait for the LSA server!\n"); 193 WaitForSingleObject(hEvent, INFINITE); 194 DPRINT("LSA server running!\n"); 195 CloseHandle(hEvent); 196 } 197 198 DPRINT("ScmWaitForLsa() done\n"); 199 } 200 201 202 BOOL WINAPI 203 ShutdownHandlerRoutine(DWORD dwCtrlType) 204 { 205 DPRINT1("ShutdownHandlerRoutine() called\n"); 206 207 if (dwCtrlType & (CTRL_SHUTDOWN_EVENT | CTRL_LOGOFF_EVENT)) 208 { 209 DPRINT1("Shutdown event received!\n"); 210 ScmShutdown = TRUE; 211 212 ScmAutoShutdownServices(); 213 ScmShutdownServiceDatabase(); 214 215 /* Set the shutdown event */ 216 SetEvent(hScmShutdownEvent); 217 } 218 219 return TRUE; 220 } 221 222 223 int WINAPI 224 wWinMain(HINSTANCE hInstance, 225 HINSTANCE hPrevInstance, 226 LPWSTR lpCmdLine, 227 int nShowCmd) 228 { 229 HANDLE hScmStartEvent = NULL; 230 HANDLE hScmAutoStartCompleteEvent = NULL; 231 SC_RPC_LOCK Lock = NULL; 232 BOOL bCanDeleteNamedPipeCriticalSection = FALSE; 233 DWORD dwError; 234 235 DPRINT("SERVICES: Service Control Manager\n"); 236 237 dwError = CheckForLiveCD(); 238 if (dwError != ERROR_SUCCESS) 239 { 240 DPRINT1("SERVICES: Failed to check for LiveCD (Error %lu)\n", dwError); 241 goto done; 242 } 243 244 /* Make us critical */ 245 RtlSetProcessIsCritical(TRUE, NULL, TRUE); 246 247 /* We are initializing ourselves */ 248 ScmInitialize = TRUE; 249 250 /* Create the start event */ 251 hScmStartEvent = CreateEventW(NULL, TRUE, FALSE, SCM_START_EVENT); 252 if (hScmStartEvent == NULL) 253 { 254 DPRINT1("SERVICES: Failed to create the start event\n"); 255 goto done; 256 } 257 DPRINT("SERVICES: Created start event with handle %p.\n", hScmStartEvent); 258 259 /* Create the auto-start complete event */ 260 hScmAutoStartCompleteEvent = CreateEventW(NULL, TRUE, FALSE, SCM_AUTOSTARTCOMPLETE_EVENT); 261 if (hScmAutoStartCompleteEvent == NULL) 262 { 263 DPRINT1("SERVICES: Failed to create the auto-start complete event\n"); 264 goto done; 265 } 266 DPRINT("SERVICES: created auto-start complete event with handle %p.\n", hScmAutoStartCompleteEvent); 267 268 /* Create the shutdown event */ 269 hScmShutdownEvent = CreateEventW(NULL, TRUE, FALSE, NULL); 270 if (hScmShutdownEvent == NULL) 271 { 272 DPRINT1("SERVICES: Failed to create the shutdown event\n"); 273 goto done; 274 } 275 276 /* Initialize our communication named pipe's critical section */ 277 ScmInitNamedPipeCriticalSection(); 278 bCanDeleteNamedPipeCriticalSection = TRUE; 279 280 // ScmInitThreadManager(); 281 282 ScmInitializeSecurity(); 283 284 /* FIXME: more initialization */ 285 286 /* Create the 'Last Known Good' control set */ 287 dwError = ScmCreateLastKnownGoodControlSet(); 288 if (dwError != ERROR_SUCCESS) 289 { 290 DPRINT1("SERVICES: Failed to create the 'Last Known Good' control set (Error %lu)\n", dwError); 291 goto done; 292 } 293 294 /* Create the services database */ 295 dwError = ScmCreateServiceDatabase(); 296 if (dwError != ERROR_SUCCESS) 297 { 298 DPRINT1("SERVICES: Failed to create SCM database (Error %lu)\n", dwError); 299 goto done; 300 } 301 302 /* Update the services database */ 303 ScmGetBootAndSystemDriverState(); 304 305 /* Register the Service Control Manager process with the ReactOS Subsystem */ 306 if (!RegisterServicesProcess(GetCurrentProcessId())) 307 { 308 DPRINT1("SERVICES: Could not register SCM process\n"); 309 goto done; 310 } 311 312 /* 313 * Acquire the user service start lock until 314 * auto-start services have been started. 315 */ 316 dwError = ScmAcquireServiceStartLock(TRUE, &Lock); 317 if (dwError != ERROR_SUCCESS) 318 { 319 DPRINT1("SERVICES: Failed to acquire the service start lock (Error %lu)\n", dwError); 320 goto done; 321 } 322 323 /* Start the RPC server */ 324 ScmStartRpcServer(); 325 326 /* Signal start event */ 327 SetEvent(hScmStartEvent); 328 329 DPRINT("SERVICES: Initialized.\n"); 330 331 /* Register event handler (used for system shutdown) */ 332 SetConsoleCtrlHandler(ShutdownHandlerRoutine, TRUE); 333 334 /* 335 * Set our shutdown parameters: we want to shutdown after the maintained 336 * services (that inherit the default shutdown level of 640). 337 */ 338 SetProcessShutdownParameters(480, SHUTDOWN_NORETRY); 339 340 /* Start auto-start services */ 341 ScmAutoStartServices(); 342 343 /* Signal auto-start complete event */ 344 SetEvent(hScmAutoStartCompleteEvent); 345 346 /* FIXME: more to do ? */ 347 348 /* Release the service start lock */ 349 ScmReleaseServiceStartLock(&Lock); 350 351 /* Initialization finished */ 352 ScmInitialize = FALSE; 353 354 DPRINT("SERVICES: Running.\n"); 355 356 /* Wait until the shutdown event gets signaled */ 357 WaitForSingleObject(hScmShutdownEvent, INFINITE); 358 359 done: 360 ScmShutdownSecurity(); 361 362 /* Delete our communication named pipe's critical section */ 363 if (bCanDeleteNamedPipeCriticalSection != FALSE) 364 ScmDeleteNamedPipeCriticalSection(); 365 366 if (hScmSecurityServicesEvent != NULL) 367 CloseHandle(hScmSecurityServicesEvent); 368 369 /* Close the shutdown event */ 370 if (hScmShutdownEvent != NULL) 371 CloseHandle(hScmShutdownEvent); 372 373 /* Close the auto-start complete event */ 374 if (hScmAutoStartCompleteEvent != NULL) 375 CloseHandle(hScmAutoStartCompleteEvent); 376 377 /* Close the start event */ 378 if (hScmStartEvent != NULL) 379 CloseHandle(hScmStartEvent); 380 381 DPRINT("SERVICES: Finished.\n"); 382 383 ExitThread(0); 384 return 0; 385 } 386 387 /* EOF */ 388