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