migrate substitution keywords to SVN
[reactos.git] / reactos / subsys / system / services / services.c
1 /* $Id$
2 *
3 * service control manager
4 *
5 * ReactOS Operating System
6 *
7 * --------------------------------------------------------------------
8 *
9 * This software is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of the
12 * License, or (at your option) any later version.
13 *
14 * This software is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this software; see the file COPYING.LIB. If not, write
21 * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
22 * MA 02139, USA.
23 *
24 */
25
26 /* NOTE:
27 * - Services.exe is NOT a native application, it is a GUI app.
28 */
29
30 /* INCLUDES *****************************************************************/
31
32 #define NTOS_MODE_USER
33 #include <ntos.h>
34 #include <stdio.h>
35 #include <windows.h>
36
37 #include "services.h"
38
39 #define NDEBUG
40 #include <debug.h>
41
42
43
44 /* GLOBALS ******************************************************************/
45
46 #define PIPE_BUFSIZE 1024
47 #define PIPE_TIMEOUT 1000
48
49
50 /* FUNCTIONS *****************************************************************/
51
52 void
53 PrintString(char* fmt,...)
54 {
55 #ifdef DBG
56 char buffer[512];
57 va_list ap;
58
59 va_start(ap, fmt);
60 vsprintf(buffer, fmt, ap);
61 va_end(ap);
62
63 OutputDebugStringA(buffer);
64 #endif
65 }
66
67
68 BOOL
69 ScmCreateStartEvent(PHANDLE StartEvent)
70 {
71 HANDLE hEvent;
72
73 hEvent = CreateEvent(NULL,
74 TRUE,
75 FALSE,
76 _T("SvcctrlStartEvent_A3725DX"));
77 if (hEvent == NULL) {
78 if (GetLastError() == ERROR_ALREADY_EXISTS) {
79 hEvent = OpenEvent(EVENT_ALL_ACCESS,
80 FALSE,
81 _T("SvcctrlStartEvent_A3725DX"));
82 if (hEvent == NULL) {
83 return FALSE;
84 }
85 } else {
86 return FALSE;
87 }
88 }
89 *StartEvent = hEvent;
90 return TRUE;
91 }
92
93
94 BOOL
95 ScmNamedPipeHandleRequest(
96 PVOID Request,
97 DWORD RequestSize,
98 PVOID Reply,
99 LPDWORD ReplySize)
100 {
101 DbgPrint("SCM READ: %s\n", Request);
102
103 *ReplySize = 0;
104 return FALSE;
105 }
106
107
108 DWORD
109 WINAPI
110 ScmNamedPipeThread(LPVOID Context)
111 {
112 CHAR chRequest[PIPE_BUFSIZE];
113 CHAR chReply[PIPE_BUFSIZE];
114 DWORD cbReplyBytes;
115 DWORD cbBytesRead;
116 DWORD cbWritten;
117 BOOL fSuccess;
118 HANDLE hPipe;
119
120 hPipe = (HANDLE)Context;
121
122 DPRINT("ScmNamedPipeThread(%x) - Accepting SCM commands through named pipe\n", hPipe);
123
124 for (;;) {
125 fSuccess = ReadFile(hPipe,
126 &chRequest,
127 PIPE_BUFSIZE,
128 &cbBytesRead,
129 NULL);
130 if (!fSuccess || cbBytesRead == 0) {
131 break;
132 }
133 if (ScmNamedPipeHandleRequest(&chRequest, cbBytesRead, &chReply, &cbReplyBytes)) {
134 fSuccess = WriteFile(hPipe,
135 &chReply,
136 cbReplyBytes,
137 &cbWritten,
138 NULL);
139 if (!fSuccess || cbReplyBytes != cbWritten) {
140 break;
141 }
142 }
143 }
144 DPRINT("ScmNamedPipeThread(%x) - Disconnecting named pipe connection\n", hPipe);
145 FlushFileBuffers(hPipe);
146 DisconnectNamedPipe(hPipe);
147 CloseHandle(hPipe);
148 DPRINT("ScmNamedPipeThread(%x) - Done.\n", hPipe);
149 return ERROR_SUCCESS;
150 }
151
152 BOOL ScmCreateNamedPipe(VOID)
153 {
154 DWORD dwThreadId;
155 BOOL fConnected;
156 HANDLE hThread;
157 HANDLE hPipe;
158
159 DPRINT("ScmCreateNamedPipe() - CreateNamedPipe(\"\\\\.\\pipe\\Ntsvcs\")\n");
160
161 hPipe = CreateNamedPipe("\\\\.\\pipe\\Ntsvcs",
162 PIPE_ACCESS_DUPLEX,
163 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
164 PIPE_UNLIMITED_INSTANCES,
165 PIPE_BUFSIZE,
166 PIPE_BUFSIZE,
167 PIPE_TIMEOUT,
168 NULL);
169 if (hPipe == INVALID_HANDLE_VALUE) {
170 DPRINT("CreateNamedPipe() failed (%d)\n", GetLastError());
171 return FALSE;
172 }
173
174 DPRINT("CreateNamedPipe() - calling ConnectNamedPipe(%x)\n", hPipe);
175 fConnected = ConnectNamedPipe(hPipe,
176 NULL) ? TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
177 DPRINT("CreateNamedPipe() - ConnectNamedPipe() returned %d\n", fConnected);
178
179 if (fConnected) {
180 DPRINT("Pipe connected\n");
181 hThread = CreateThread(NULL,
182 0,
183 ScmNamedPipeThread,
184 (LPVOID)hPipe,
185 0,
186 &dwThreadId);
187 if (!hThread) {
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 } else {
195 DPRINT("Pipe not connected\n");
196 CloseHandle(hPipe);
197 DPRINT("CreateNamedPipe() - returning FALSE\n");
198 return FALSE;
199 }
200 DPRINT("CreateNamedPipe() - returning TRUE\n");
201 return TRUE;
202 }
203
204 DWORD
205 WINAPI
206 ScmNamedPipeListenerThread(LPVOID Context)
207 {
208 // HANDLE hPipe;
209 DPRINT("ScmNamedPipeListenerThread(%x) - aka SCM.\n", Context);
210
211 // hPipe = (HANDLE)Context;
212 for (;;) {
213 DPRINT("SCM: Waiting for new connection on named pipe...\n");
214 /* Create named pipe */
215 if (!ScmCreateNamedPipe()) {
216 DPRINT1("\nSCM: Failed to create named pipe\n");
217 break;
218 //ExitThread(0);
219 }
220 DPRINT("\nSCM: named pipe session created.\n");
221 Sleep(10);
222 }
223 DPRINT("\n\nWARNING: ScmNamedPipeListenerThread(%x) - Aborted.\n\n", Context);
224 return ERROR_SUCCESS;
225 }
226
227 BOOL StartScmNamedPipeThreadListener(void)
228 {
229 DWORD dwThreadId;
230 HANDLE hThread;
231
232 hThread = CreateThread(NULL,
233 0,
234 ScmNamedPipeListenerThread,
235 NULL, /*(LPVOID)hPipe,*/
236 0,
237 &dwThreadId);
238
239 if (!hThread) {
240 DPRINT1("SERVICES: Could not create thread (Status %lx)\n", GetLastError());
241 return FALSE;
242 }
243 return TRUE;
244 }
245
246 VOID FASTCALL
247 AcquireLoadDriverPrivilege(VOID)
248 {
249 HANDLE hToken;
250 TOKEN_PRIVILEGES tkp;
251
252 /* Get a token for this process. */
253 if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
254 /* Get the LUID for the debug privilege. */
255 LookupPrivilegeValue(NULL, SE_LOAD_DRIVER_NAME, &tkp.Privileges[0].Luid);
256
257 tkp.PrivilegeCount = 1; /* one privilege to set */
258 tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
259
260 /* Get the debug privilege for this process. */
261 AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0);
262 }
263 }
264
265 int STDCALL
266 WinMain(HINSTANCE hInstance,
267 HINSTANCE hPrevInstance,
268 LPSTR lpCmdLine,
269 int nShowCmd)
270 {
271 HANDLE hScmStartEvent;
272 HANDLE hEvent;
273 NTSTATUS Status;
274
275 DPRINT("SERVICES: Service Control Manager\n");
276
277 /* Acquire privileges to load drivers */
278 AcquireLoadDriverPrivilege();
279
280 /* Create start event */
281 if (!ScmCreateStartEvent(&hScmStartEvent))
282 {
283 DPRINT1("SERVICES: Failed to create start event\n");
284 ExitThread(0);
285 }
286
287 DPRINT("SERVICES: created start event with handle %x.\n", hScmStartEvent);
288
289 /* FIXME: more initialization */
290
291
292 /* Create the service database */
293 Status = ScmCreateServiceDataBase();
294 if (!NT_SUCCESS(Status))
295 {
296 DPRINT1("SERVICES: failed to create SCM database (Status %lx)\n", Status);
297 ExitThread(0);
298 }
299
300 /* Update service database */
301 ScmGetBootAndSystemDriverState();
302
303 #if 0
304 DPRINT("SERVICES: Attempting to create named pipe...\n");
305 /* Create named pipe */
306 if (!ScmCreateNamedPipe()) {
307 DPRINT1("SERVICES: Failed to create named pipe\n");
308 ExitThread(0);
309 }
310 DPRINT("SERVICES: named pipe created successfully.\n");
311 #else
312 DPRINT("SERVICES: Attempting to create named pipe listener...\n");
313 if (!StartScmNamedPipeThreadListener()) {
314 DPRINT1("SERVICES: Failed to create named pipe listener thread.\n");
315 ExitThread(0);
316 }
317 DPRINT("SERVICES: named pipe listener thread created.\n");
318 #endif
319 /* FIXME: create listener thread for pipe */
320
321
322 /* Register service process with CSRSS */
323 RegisterServicesProcess(GetCurrentProcessId());
324
325 DPRINT("SERVICES: Initialized.\n");
326
327 /* Signal start event */
328 SetEvent(hScmStartEvent);
329
330 /* FIXME: register event handler (used for system shutdown) */
331 // SetConsoleCtrlHandler(...);
332
333
334 /* Start auto-start services */
335 ScmAutoStartServices();
336
337 /* FIXME: more to do ? */
338
339
340 DPRINT("SERVICES: Running.\n");
341
342 #if 1
343 hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
344 WaitForSingleObject(hEvent, INFINITE);
345 #else
346 for (;;)
347 {
348 NtYieldExecution();
349 }
350 #endif
351
352 DPRINT("SERVICES: Finished.\n");
353
354 ExitThread(0);
355 return(0);
356 }
357
358 /* EOF */