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