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