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