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