Sync with trunk r58687.
[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 #define NDEBUG
16 #include <debug.h>
17
18 int WINAPI RegisterServicesProcess(DWORD ServicesProcessId);
19
20 /* GLOBALS ******************************************************************/
21
22 #define PIPE_BUFSIZE 1024
23 #define PIPE_TIMEOUT 1000
24
25 /* Defined in include/reactos/services/services.h */
26 // #define SCM_START_EVENT L"SvcctrlStartEvent_A3752DX"
27 #define SCM_AUTOSTARTCOMPLETE_EVENT L"SC_AutoStartComplete"
28 #define LSA_RPC_SERVER_ACTIVE L"LSA_RPC_SERVER_ACTIVE"
29
30 BOOL ScmInitialize = FALSE;
31 BOOL ScmShutdown = FALSE;
32 static HANDLE hScmShutdownEvent = 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
53 VOID
54 ScmLogError(DWORD dwEventId,
55 WORD wStrings,
56 LPCWSTR *lpStrings)
57 {
58 HANDLE hLog;
59
60 hLog = RegisterEventSourceW(NULL,
61 L"Service Control Manager");
62 if (hLog == NULL)
63 {
64 DPRINT1("ScmLogEvent: RegisterEventSourceW failed %lu\n", GetLastError());
65 return;
66 }
67
68 if (!ReportEventW(hLog,
69 EVENTLOG_ERROR_TYPE,
70 0,
71 dwEventId,
72 NULL, // Sid,
73 wStrings,
74 0,
75 lpStrings,
76 NULL))
77 {
78 DPRINT1("ScmLogEvent: ReportEventW failed %lu\n", GetLastError());
79 }
80
81 DeregisterEventSource(hLog);
82 }
83
84
85 BOOL
86 ScmCreateControlEvent(PHANDLE Event,
87 LPCWSTR Name,
88 DWORD dwDesiredAccess)
89 {
90 /*
91 * This function creates a generic non-inheritable event
92 * and return a handle to the caller. The caller must
93 * close this handle afterwards.
94 */
95
96 HANDLE hEvent;
97
98 hEvent = CreateEventW(NULL, TRUE, FALSE, Name);
99 if (hEvent == NULL)
100 {
101 if (GetLastError() == ERROR_ALREADY_EXISTS)
102 {
103 hEvent = OpenEventW(dwDesiredAccess, FALSE, Name);
104 }
105 }
106
107 if (hEvent)
108 {
109 DPRINT("SERVICES: Created event %S with handle %x\n", Name, hEvent);
110 *Event = hEvent;
111 return TRUE;
112 }
113 else
114 {
115 DPRINT1("SERVICES: Failed to create event %S (Error %lu)\n", Name, GetLastError());
116 return FALSE;
117 }
118 }
119
120
121 VOID
122 ScmWaitForLsa(VOID)
123 {
124 HANDLE hEvent;
125
126 if (!ScmCreateControlEvent(&hEvent,
127 LSA_RPC_SERVER_ACTIVE,
128 SYNCHRONIZE))
129 {
130 DPRINT1("Failed to create the notification event (Error %lu)\n", GetLastError());
131 }
132 else
133 {
134 DPRINT("Wait for the LSA server!\n");
135 WaitForSingleObject(hEvent, INFINITE);
136 DPRINT("LSA server running!\n");
137
138 CloseHandle(hEvent);
139 }
140
141 DPRINT("ScmWaitForLsa() done\n");
142 }
143
144
145 BOOL
146 ScmNamedPipeHandleRequest(PVOID Request,
147 DWORD RequestSize,
148 PVOID Reply,
149 LPDWORD ReplySize)
150 {
151 DbgPrint("SCM READ: %p\n", Request);
152
153 *ReplySize = 0;
154 return FALSE;
155 }
156
157
158 DWORD WINAPI
159 ScmNamedPipeThread(LPVOID Context)
160 {
161 CHAR chRequest[PIPE_BUFSIZE];
162 CHAR chReply[PIPE_BUFSIZE];
163 DWORD cbReplyBytes;
164 DWORD cbBytesRead;
165 DWORD cbWritten;
166 BOOL bSuccess;
167 HANDLE hPipe;
168
169 hPipe = (HANDLE)Context;
170
171 DPRINT("ScmNamedPipeThread(%p) - Accepting SCM commands through named pipe\n", hPipe);
172
173 for (;;)
174 {
175 bSuccess = ReadFile(hPipe,
176 &chRequest,
177 PIPE_BUFSIZE,
178 &cbBytesRead,
179 NULL);
180 if (!bSuccess || cbBytesRead == 0)
181 {
182 break;
183 }
184
185 if (ScmNamedPipeHandleRequest(&chRequest, cbBytesRead, &chReply, &cbReplyBytes))
186 {
187 bSuccess = WriteFile(hPipe,
188 &chReply,
189 cbReplyBytes,
190 &cbWritten,
191 NULL);
192 if (!bSuccess || cbReplyBytes != cbWritten)
193 {
194 break;
195 }
196 }
197 }
198
199 DPRINT("ScmNamedPipeThread(%p) - Disconnecting named pipe connection\n", hPipe);
200
201 FlushFileBuffers(hPipe);
202 DisconnectNamedPipe(hPipe);
203 CloseHandle(hPipe);
204
205 DPRINT("ScmNamedPipeThread(%p) - Done.\n", hPipe);
206
207 return ERROR_SUCCESS;
208 }
209
210
211 BOOL
212 ScmCreateNamedPipe(VOID)
213 {
214 DWORD dwThreadId;
215 BOOL bConnected;
216 HANDLE hThread;
217 HANDLE hPipe;
218
219 DPRINT("ScmCreateNamedPipe() - CreateNamedPipe(\"\\\\.\\pipe\\Ntsvcs\")\n");
220
221 hPipe = CreateNamedPipeW(L"\\\\.\\pipe\\Ntsvcs",
222 PIPE_ACCESS_DUPLEX,
223 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
224 PIPE_UNLIMITED_INSTANCES,
225 PIPE_BUFSIZE,
226 PIPE_BUFSIZE,
227 PIPE_TIMEOUT,
228 NULL);
229 if (hPipe == INVALID_HANDLE_VALUE)
230 {
231 DPRINT("CreateNamedPipe() failed (%lu)\n", GetLastError());
232 return FALSE;
233 }
234
235 DPRINT("CreateNamedPipe() - calling ConnectNamedPipe(%p)\n", hPipe);
236 bConnected = ConnectNamedPipe(hPipe,
237 NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
238 DPRINT("CreateNamedPipe() - ConnectNamedPipe() returned %d\n", bConnected);
239
240 if (bConnected)
241 {
242 DPRINT("Pipe connected\n");
243 hThread = CreateThread(NULL,
244 0,
245 ScmNamedPipeThread,
246 (LPVOID)hPipe,
247 0,
248 &dwThreadId);
249 if (!hThread)
250 {
251 DPRINT("Could not create thread (%lu)\n", GetLastError());
252 DisconnectNamedPipe(hPipe);
253 CloseHandle(hPipe);
254 DPRINT("CreateNamedPipe() - returning FALSE\n");
255 return FALSE;
256 }
257
258 CloseHandle(hThread);
259 }
260 else
261 {
262 DPRINT("Pipe not connected\n");
263 CloseHandle(hPipe);
264 DPRINT("CreateNamedPipe() - returning FALSE\n");
265 return FALSE;
266 }
267 DPRINT("CreateNamedPipe() - returning TRUE\n");
268 return TRUE;
269 }
270
271
272 DWORD WINAPI
273 ScmNamedPipeListenerThread(LPVOID Context)
274 {
275 // HANDLE hPipe;
276 DPRINT("ScmNamedPipeListenerThread(%p) - aka SCM.\n", Context);
277
278 // hPipe = (HANDLE)Context;
279 for (;;)
280 {
281 DPRINT("SCM: Waiting for new connection on named pipe...\n");
282 /* Create named pipe */
283 if (!ScmCreateNamedPipe())
284 {
285 DPRINT1("\nSCM: Failed to create named pipe\n");
286 break;
287 //ExitThread(0);
288 }
289 DPRINT("\nSCM: named pipe session created.\n");
290 Sleep(10);
291 }
292 DPRINT("\n\nWARNING: ScmNamedPipeListenerThread(%p) - Aborted.\n\n", Context);
293 return ERROR_SUCCESS;
294 }
295
296
297 BOOL
298 StartScmNamedPipeThreadListener(VOID)
299 {
300 DWORD dwThreadId;
301 HANDLE hThread;
302
303 hThread = CreateThread(NULL,
304 0,
305 ScmNamedPipeListenerThread,
306 NULL, /*(LPVOID)hPipe,*/
307 0,
308 &dwThreadId);
309 if (!hThread)
310 {
311 DPRINT1("SERVICES: Could not create thread (Status %lx)\n", GetLastError());
312 return FALSE;
313 }
314
315 CloseHandle(hThread);
316
317 return TRUE;
318 }
319
320
321 BOOL WINAPI
322 ShutdownHandlerRoutine(DWORD dwCtrlType)
323 {
324 DPRINT1("ShutdownHandlerRoutine() called\n");
325
326 if (dwCtrlType & (CTRL_SHUTDOWN_EVENT | CTRL_LOGOFF_EVENT))
327 {
328 DPRINT1("Shutdown event received!\n");
329 ScmShutdown = TRUE;
330
331 ScmAutoShutdownServices();
332 ScmShutdownServiceDatabase();
333
334 /* Set the shutdwon event */
335 SetEvent(hScmShutdownEvent);
336 }
337
338 return TRUE;
339 }
340
341
342 int WINAPI
343 wWinMain(HINSTANCE hInstance,
344 HINSTANCE hPrevInstance,
345 LPWSTR lpCmdLine,
346 int nShowCmd)
347 {
348 HANDLE hScmStartEvent = NULL;
349 HANDLE hScmAutoStartCompleteEvent = NULL;
350 SC_RPC_LOCK Lock = NULL;
351 BOOL bCanDeleteNamedPipeCriticalSection = FALSE;
352 DWORD dwError;
353
354 DPRINT("SERVICES: Service Control Manager\n");
355
356 /* We are initializing ourselves */
357 ScmInitialize = TRUE;
358
359 /* Create the start event */
360 if (!ScmCreateControlEvent(&hScmStartEvent,
361 SCM_START_EVENT,
362 EVENT_ALL_ACCESS))
363 {
364 DPRINT1("SERVICES: Failed to create the start event\n");
365 goto done;
366 }
367 DPRINT("SERVICES: Created start event with handle %p.\n", hScmStartEvent);
368
369 /* Create the auto-start complete event */
370 if (!ScmCreateControlEvent(&hScmAutoStartCompleteEvent,
371 SCM_AUTOSTARTCOMPLETE_EVENT,
372 EVENT_ALL_ACCESS))
373 {
374 DPRINT1("SERVICES: Failed to create the auto-start complete event\n");
375 goto done;
376 }
377 DPRINT("SERVICES: created auto-start complete event with handle %p.\n", hScmAutoStartCompleteEvent);
378
379 /* Create the shutdown event */
380 hScmShutdownEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
381 if (hScmShutdownEvent == NULL)
382 {
383 DPRINT1("SERVICES: Failed to create shutdown event\n");
384 goto done;
385 }
386
387 /* Initialize our communication named pipe's critical section */
388 ScmInitNamedPipeCriticalSection();
389 bCanDeleteNamedPipeCriticalSection = TRUE;
390
391 // ScmInitThreadManager();
392
393 /* FIXME: more initialization */
394
395 /* Read the control set values */
396 if (!ScmGetControlSetValues())
397 {
398 DPRINT1("SERVICES: Failed to read the control set values\n");
399 goto done;
400 }
401
402 /* Create the services database */
403 dwError = ScmCreateServiceDatabase();
404 if (dwError != ERROR_SUCCESS)
405 {
406 DPRINT1("SERVICES: Failed to create SCM database (Error %lu)\n", dwError);
407 goto done;
408 }
409
410 /* Wait for the LSA server */
411 ScmWaitForLsa();
412
413 /* Update the services database */
414 ScmGetBootAndSystemDriverState();
415
416 /* Register the Service Control Manager process with the ReactOS Subsystem */
417 if (!RegisterServicesProcess(GetCurrentProcessId()))
418 {
419 DPRINT1("SERVICES: Could not register SCM process\n");
420 goto done;
421 }
422
423 /*
424 * Acquire the user service start lock until
425 * auto-start services have been started.
426 */
427 dwError = ScmAcquireServiceStartLock(TRUE, &Lock);
428 if (dwError != ERROR_SUCCESS)
429 {
430 DPRINT1("SERVICES: Failed to acquire the service start lock (Error %lu)\n", dwError);
431 goto done;
432 }
433
434 /* Start the RPC server */
435 ScmStartRpcServer();
436
437 /* Signal start event */
438 SetEvent(hScmStartEvent);
439
440 DPRINT("SERVICES: Initialized.\n");
441
442 /* Register event handler (used for system shutdown) */
443 SetConsoleCtrlHandler(ShutdownHandlerRoutine, TRUE);
444
445 /* Start auto-start services */
446 ScmAutoStartServices();
447
448 /* Signal auto-start complete event */
449 SetEvent(hScmAutoStartCompleteEvent);
450
451 /* FIXME: more to do ? */
452
453 /* Release the service start lock */
454 ScmReleaseServiceStartLock(&Lock);
455
456 /* Initialization finished */
457 ScmInitialize = FALSE;
458
459 DPRINT("SERVICES: Running.\n");
460
461 /* Wait until the shutdown event gets signaled */
462 WaitForSingleObject(hScmShutdownEvent, INFINITE);
463
464 done:
465 /* Delete our communication named pipe's critical section */
466 if (bCanDeleteNamedPipeCriticalSection == TRUE)
467 ScmDeleteNamedPipeCriticalSection();
468
469 /* Close the shutdown event */
470 if (hScmShutdownEvent != NULL)
471 CloseHandle(hScmShutdownEvent);
472
473 /* Close the auto-start complete event */
474 if (hScmAutoStartCompleteEvent != NULL)
475 CloseHandle(hScmAutoStartCompleteEvent);
476
477 /* Close the start event */
478 if (hScmStartEvent != NULL)
479 CloseHandle(hScmStartEvent);
480
481 DPRINT("SERVICES: Finished.\n");
482
483 ExitThread(0);
484 return 0;
485 }
486
487 /* EOF */