[SERVICES] When autostart services are up, signal an event.
[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 /* 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
31
32 /* FUNCTIONS *****************************************************************/
33
34 VOID
35 PrintString(LPCSTR fmt, ...)
36 {
37 #if DBG
38 CHAR buffer[512];
39 va_list ap;
40
41 va_start(ap, fmt);
42 vsprintf(buffer, fmt, ap);
43 va_end(ap);
44
45 OutputDebugStringA(buffer);
46 #endif
47 }
48
49
50 BOOL
51 ScmCreateEvent(PHANDLE Event,
52 LPCWSTR Name)
53 {
54 HANDLE hEvent;
55
56 hEvent = CreateEventW(NULL,
57 TRUE,
58 FALSE,
59 Name);
60 if (hEvent == NULL)
61 {
62 if (GetLastError() == ERROR_ALREADY_EXISTS)
63 {
64 hEvent = OpenEventW(EVENT_ALL_ACCESS,
65 FALSE,
66 Name);
67 }
68 }
69
70 if (hEvent)
71 {
72 DPRINT("SERVICES: created event %S with handle %x\n", Name, hEvent);
73 *Event = hEvent;
74 return TRUE;
75 }
76
77 DPRINT1("SERVICES: Failed to create event %S\n", Name);
78 return FALSE;
79 }
80
81
82 BOOL
83 ScmNamedPipeHandleRequest(PVOID Request,
84 DWORD RequestSize,
85 PVOID Reply,
86 LPDWORD ReplySize)
87 {
88 DbgPrint("SCM READ: %s\n", Request);
89
90 *ReplySize = 0;
91 return FALSE;
92 }
93
94
95 DWORD WINAPI
96 ScmNamedPipeThread(LPVOID Context)
97 {
98 CHAR chRequest[PIPE_BUFSIZE];
99 CHAR chReply[PIPE_BUFSIZE];
100 DWORD cbReplyBytes;
101 DWORD cbBytesRead;
102 DWORD cbWritten;
103 BOOL bSuccess;
104 HANDLE hPipe;
105
106 hPipe = (HANDLE)Context;
107
108 DPRINT("ScmNamedPipeThread(%x) - Accepting SCM commands through named pipe\n", hPipe);
109
110 for (;;)
111 {
112 bSuccess = ReadFile(hPipe,
113 &chRequest,
114 PIPE_BUFSIZE,
115 &cbBytesRead,
116 NULL);
117 if (!bSuccess || cbBytesRead == 0)
118 {
119 break;
120 }
121
122 if (ScmNamedPipeHandleRequest(&chRequest, cbBytesRead, &chReply, &cbReplyBytes))
123 {
124 bSuccess = WriteFile(hPipe,
125 &chReply,
126 cbReplyBytes,
127 &cbWritten,
128 NULL);
129 if (!bSuccess || cbReplyBytes != cbWritten)
130 {
131 break;
132 }
133 }
134 }
135
136 DPRINT("ScmNamedPipeThread(%x) - Disconnecting named pipe connection\n", hPipe);
137
138 FlushFileBuffers(hPipe);
139 DisconnectNamedPipe(hPipe);
140 CloseHandle(hPipe);
141
142 DPRINT("ScmNamedPipeThread(%x) - Done.\n", hPipe);
143
144 return ERROR_SUCCESS;
145 }
146
147
148 BOOL
149 ScmCreateNamedPipe(VOID)
150 {
151 DWORD dwThreadId;
152 BOOL bConnected;
153 HANDLE hThread;
154 HANDLE hPipe;
155
156 DPRINT("ScmCreateNamedPipe() - CreateNamedPipe(\"\\\\.\\pipe\\Ntsvcs\")\n");
157
158 hPipe = CreateNamedPipe(TEXT("\\\\.\\pipe\\Ntsvcs"),
159 PIPE_ACCESS_DUPLEX,
160 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
161 PIPE_UNLIMITED_INSTANCES,
162 PIPE_BUFSIZE,
163 PIPE_BUFSIZE,
164 PIPE_TIMEOUT,
165 NULL);
166 if (hPipe == INVALID_HANDLE_VALUE)
167 {
168 DPRINT("CreateNamedPipe() failed (%d)\n", GetLastError());
169 return FALSE;
170 }
171
172 DPRINT("CreateNamedPipe() - calling ConnectNamedPipe(%x)\n", hPipe);
173 bConnected = ConnectNamedPipe(hPipe,
174 NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
175 DPRINT("CreateNamedPipe() - ConnectNamedPipe() returned %d\n", bConnected);
176
177 if (bConnected)
178 {
179 DPRINT("Pipe connected\n");
180 hThread = CreateThread(NULL,
181 0,
182 ScmNamedPipeThread,
183 (LPVOID)hPipe,
184 0,
185 &dwThreadId);
186 if (!hThread)
187 {
188 DPRINT("Could not create thread (%d)\n", GetLastError());
189 DisconnectNamedPipe(hPipe);
190 CloseHandle(hPipe);
191 DPRINT("CreateNamedPipe() - returning FALSE\n");
192 return FALSE;
193 }
194 }
195 else
196 {
197 DPRINT("Pipe not connected\n");
198 CloseHandle(hPipe);
199 DPRINT("CreateNamedPipe() - returning FALSE\n");
200 return FALSE;
201 }
202 DPRINT("CreateNamedPipe() - returning TRUE\n");
203 return TRUE;
204 }
205
206
207 DWORD WINAPI
208 ScmNamedPipeListenerThread(LPVOID Context)
209 {
210 // HANDLE hPipe;
211 DPRINT("ScmNamedPipeListenerThread(%x) - aka SCM.\n", Context);
212
213 // hPipe = (HANDLE)Context;
214 for (;;)
215 {
216 DPRINT("SCM: Waiting for new connection on named pipe...\n");
217 /* Create named pipe */
218 if (!ScmCreateNamedPipe())
219 {
220 DPRINT1("\nSCM: Failed to create named pipe\n");
221 break;
222 //ExitThread(0);
223 }
224 DPRINT("\nSCM: named pipe session created.\n");
225 Sleep(10);
226 }
227 DPRINT("\n\nWARNING: ScmNamedPipeListenerThread(%x) - Aborted.\n\n", Context);
228 return ERROR_SUCCESS;
229 }
230
231
232 BOOL
233 StartScmNamedPipeThreadListener(VOID)
234 {
235 DWORD dwThreadId;
236 HANDLE hThread;
237
238 hThread = CreateThread(NULL,
239 0,
240 ScmNamedPipeListenerThread,
241 NULL, /*(LPVOID)hPipe,*/
242 0,
243 &dwThreadId);
244 if (!hThread)
245 {
246 DPRINT1("SERVICES: Could not create thread (Status %lx)\n", GetLastError());
247 return FALSE;
248 }
249
250 return TRUE;
251 }
252
253
254 VOID FASTCALL
255 AcquireLoadDriverPrivilege(VOID)
256 {
257 HANDLE hToken;
258 TOKEN_PRIVILEGES tkp;
259
260 /* Get a token for this process */
261 if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
262 {
263 /* Get the LUID for the debug privilege */
264 LookupPrivilegeValue(NULL, SE_LOAD_DRIVER_NAME, &tkp.Privileges[0].Luid);
265
266 /* One privilege to set */
267 tkp.PrivilegeCount = 1;
268 tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
269
270 /* Get the debug privilege for this process */
271 AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0);
272 }
273 }
274
275
276 BOOL WINAPI
277 ShutdownHandlerRoutine(DWORD dwCtrlType)
278 {
279 DPRINT1("ShutdownHandlerRoutine() called\n");
280
281 if (dwCtrlType == CTRL_SHUTDOWN_EVENT)
282 {
283 DPRINT1("Shutdown event received!\n");
284 ScmShutdown = TRUE;
285
286 ScmAutoShutdownServices();
287 ScmShutdownServiceDatabase();
288 }
289
290 return TRUE;
291 }
292
293
294 int WINAPI
295 wWinMain(HINSTANCE hInstance,
296 HINSTANCE hPrevInstance,
297 LPWSTR lpCmdLine,
298 int nShowCmd)
299 {
300 HANDLE hScmStartEvent;
301 HANDLE hScmAutoStartCompleteEvent;
302 HANDLE hEvent;
303 DWORD dwError;
304
305 DPRINT("SERVICES: Service Control Manager\n");
306
307 /* Acquire privileges to load drivers */
308 AcquireLoadDriverPrivilege();
309
310 /* Create events */
311 if (!ScmCreateEvent(&hScmAutoStartCompleteEvent, L"SC_AutoStartComplete"))
312 {
313 ExitThread(0);
314 }
315
316 if (!ScmCreateEvent(&hScmStartEvent, L"SvcctrlStartEvent_A3752DX"))
317 {
318 ExitThread(0);
319 }
320
321 // ScmInitThreadManager();
322
323 /* FIXME: more initialization */
324
325
326 /* Create the service database */
327 dwError = ScmCreateServiceDatabase();
328 if (dwError != ERROR_SUCCESS)
329 {
330 DPRINT1("SERVICES: failed to create SCM database (Error %lu)\n", dwError);
331 ExitThread(0);
332 }
333
334 /* Update service database */
335 ScmGetBootAndSystemDriverState();
336
337 /* Start the RPC server */
338 ScmStartRpcServer();
339
340 /* Register service process with CSRSS */
341 RegisterServicesProcess(GetCurrentProcessId());
342
343 DPRINT("SERVICES: Initialized.\n");
344
345 /* Signal start event */
346 SetEvent(hScmStartEvent);
347
348 /* Register event handler (used for system shutdown) */
349 SetConsoleCtrlHandler(ShutdownHandlerRoutine, TRUE);
350
351 /* Start auto-start services */
352 ScmAutoStartServices();
353
354 /* FIXME: more to do ? */
355
356
357 DPRINT("SERVICES: Running.\n");
358
359 /* Signal complete event */
360 SetEvent(hScmAutoStartCompleteEvent);
361
362 #if 1
363 hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
364 if (hEvent)
365 WaitForSingleObject(hEvent, INFINITE);
366 #else
367 for (;;)
368 {
369 NtYieldExecution();
370 }
371 #endif
372
373 CloseHandle(hScmStartEvent);
374
375 DPRINT("SERVICES: Finished.\n");
376
377 ExitThread(0);
378
379 return 0;
380 }
381
382 /* EOF */