migrate substitution keywords to SVN
[reactos.git] / reactos / lib / advapi32 / service / sctrl.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS system libraries
5 * FILE: lib/advapi32/service/sctrl.c
6 * PURPOSE: Service control manager functions
7 * PROGRAMMER: Emanuele Aliberti
8 * UPDATE HISTORY:
9 * 19990413 EA created
10 * 19990515 EA
11 */
12
13 /* INCLUDES ******************************************************************/
14
15 #include "advapi32.h"
16 #define NDEBUG
17 #include <debug.h>
18
19
20 /* TYPES *********************************************************************/
21
22 typedef struct
23 {
24 DWORD ThreadId;
25 UNICODE_STRING ServiceName;
26 LPSERVICE_MAIN_FUNCTIONW MainFunction;
27 LPHANDLER_FUNCTION HandlerFunction;
28 SERVICE_STATUS ServiceStatus;
29 } ACTIVE_SERVICE, *PACTIVE_SERVICE;
30
31 /* GLOBALS *******************************************************************/
32
33 static ULONG ActiveServiceCount;
34 static PACTIVE_SERVICE ActiveServices;
35 /* static PHANDLE ActiveServicesThreadHandles; */ /* uncomment when in use */
36
37 /* FUNCTIONS *****************************************************************/
38
39
40 static PACTIVE_SERVICE
41 ScLookupServiceByServiceName(LPWSTR lpServiceName)
42 {
43 DWORD i;
44
45 for (i = 0; i < ActiveServiceCount; i++)
46 {
47 if (_wcsicmp(ActiveServices[i].ServiceName.Buffer, lpServiceName) == 0)
48 {
49 return(&ActiveServices[i]);
50 }
51 }
52
53 SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
54
55 return(NULL);
56 }
57
58
59 static PACTIVE_SERVICE
60 ScLookupServiceByThreadId(DWORD ThreadId)
61 {
62 DWORD i;
63
64 for (i = 0; i < ActiveServiceCount; i++)
65 {
66 if (ActiveServices[i].ThreadId == ThreadId)
67 {
68 return(&ActiveServices[i]);
69 }
70 }
71
72 SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
73
74 return(NULL);
75 }
76
77
78 static DWORD
79 ScConnectControlPipe(HANDLE *hPipe)
80 {
81 DWORD dwBytesWritten;
82 DWORD dwProcessId;
83 DWORD dwState;
84
85 WaitNamedPipeW(L"\\\\.\\pipe\\net\\NtControlPipe",
86 15000);
87
88 *hPipe = CreateFileW(L"\\\\.\\pipe\\net\\NtControlPipe",
89 GENERIC_READ | GENERIC_WRITE,
90 FILE_SHARE_READ | FILE_SHARE_WRITE,
91 NULL,
92 OPEN_EXISTING,
93 FILE_ATTRIBUTE_NORMAL,
94 NULL);
95 if (*hPipe == INVALID_HANDLE_VALUE)
96 return(ERROR_FAILED_SERVICE_CONTROLLER_CONNECT);
97
98 dwState = PIPE_READMODE_MESSAGE;
99 if (!SetNamedPipeHandleState(*hPipe, &dwState, NULL, NULL))
100 {
101 CloseHandle(hPipe);
102 *hPipe = INVALID_HANDLE_VALUE;
103 return(ERROR_FAILED_SERVICE_CONTROLLER_CONNECT);
104 }
105
106 dwProcessId = GetCurrentProcessId();
107 WriteFile(*hPipe,
108 &dwProcessId,
109 sizeof(DWORD),
110 &dwBytesWritten,
111 NULL);
112
113 return(ERROR_SUCCESS);
114 }
115
116
117 static VOID
118 ScServiceDispatcher(HANDLE hPipe, PVOID p1, PVOID p2)
119 {
120 DPRINT1("ScDispatcherLoop() called\n");
121
122 #if 0
123 while (TRUE)
124 {
125 /* Read command from the control pipe */
126
127 /* Execute command */
128
129 }
130 #endif
131 }
132
133
134 DWORD WINAPI
135 ScServiceMainStub(LPVOID Context)
136 {
137 LPSERVICE_MAIN_FUNCTIONW lpServiceProc = (LPSERVICE_MAIN_FUNCTIONW)Context;
138
139 /* FIXME: Send argc and argv (from command line) as arguments */
140
141 (lpServiceProc)(0, NULL);
142
143 return ERROR_SUCCESS;
144 }
145
146
147 /**********************************************************************
148 * RegisterServiceCtrlHandlerA
149 *
150 * @implemented
151 */
152 SERVICE_STATUS_HANDLE STDCALL
153 RegisterServiceCtrlHandlerA(LPCSTR lpServiceName,
154 LPHANDLER_FUNCTION lpHandlerProc)
155 {
156 ANSI_STRING ServiceNameA;
157 UNICODE_STRING ServiceNameU;
158 SERVICE_STATUS_HANDLE SHandle;
159
160 RtlInitAnsiString(&ServiceNameA, (LPSTR)lpServiceName);
161 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ServiceNameU, &ServiceNameA, TRUE)))
162 {
163 SetLastError(ERROR_OUTOFMEMORY);
164 return((SERVICE_STATUS_HANDLE)0);
165 }
166
167 SHandle = RegisterServiceCtrlHandlerW(ServiceNameU.Buffer,
168 lpHandlerProc);
169
170 RtlFreeUnicodeString(&ServiceNameU);
171
172 return(SHandle);
173 }
174
175
176 /**********************************************************************
177 * RegisterServiceCtrlHandlerW
178 *
179 * @implemented
180 */
181 SERVICE_STATUS_HANDLE STDCALL
182 RegisterServiceCtrlHandlerW(LPCWSTR lpServiceName,
183 LPHANDLER_FUNCTION lpHandlerProc)
184 {
185 PACTIVE_SERVICE Service;
186
187 Service = ScLookupServiceByServiceName((LPWSTR)lpServiceName);
188 if (Service == NULL)
189 {
190 return((SERVICE_STATUS_HANDLE)NULL);
191 }
192
193 Service->HandlerFunction = lpHandlerProc;
194
195 return((SERVICE_STATUS_HANDLE)Service->ThreadId);
196 }
197
198
199 /**********************************************************************
200 * SetServiceBits
201 *
202 * @unimplemented
203 */
204 BOOL STDCALL
205 SetServiceBits(SERVICE_STATUS_HANDLE hServiceStatus,
206 DWORD dwServiceBits,
207 BOOL bSetBitsOn,
208 BOOL bUpdateImmediately)
209 {
210 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
211 return(FALSE);
212 }
213
214
215 /**********************************************************************
216 * SetServiceObjectSecurity
217 *
218 * @unimplemented
219 */
220 BOOL STDCALL
221 SetServiceObjectSecurity(SC_HANDLE hService,
222 SECURITY_INFORMATION dwSecurityInformation,
223 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
224 {
225 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
226 return FALSE;
227 }
228
229
230 /**********************************************************************
231 * SetServiceStatus
232 *
233 * @implemented
234 */
235 BOOL STDCALL
236 SetServiceStatus(SERVICE_STATUS_HANDLE hServiceStatus,
237 LPSERVICE_STATUS lpServiceStatus)
238 {
239 PACTIVE_SERVICE Service;
240
241 Service = ScLookupServiceByThreadId((DWORD)hServiceStatus);
242 if (!Service)
243 {
244 SetLastError(ERROR_INVALID_HANDLE);
245 return(FALSE);
246 }
247
248 RtlCopyMemory(&Service->ServiceStatus,
249 lpServiceStatus,
250 sizeof(SERVICE_STATUS));
251
252 return(TRUE);
253 }
254
255
256 /**********************************************************************
257 * StartServiceCtrlDispatcherA
258 *
259 * @unimplemented
260 */
261 BOOL STDCALL
262 StartServiceCtrlDispatcherA(LPSERVICE_TABLE_ENTRYA lpServiceStartTable)
263 {
264 // FIXME how to deal with diffs between ANSI/UNICODE
265 #if 0
266 LPSERVICE_TABLE_ENTRYW ServiceStartTableW;
267 ANSI_STRING ServiceNameA;
268 UNICODE_STRING ServiceNameW;
269 ULONG i, j;
270 ULONG Count;
271 BOOL b;
272
273 i = 0;
274 while (lpServiceStartTable[i].lpServiceProc != NULL)
275 {
276 i++;
277 }
278 Count = i;
279
280 ServiceStartTableW = RtlAllocateHeap(RtlGetProcessHeap(),
281 HEAP_ZERO_MEMORY,
282 sizeof(SERVICE_TABLE_ENTRYW) * Count);
283 for (i = 0; i < Count; i++)
284 {
285 RtlInitAnsiString(
286 &ServiceNameA,
287 lpServiceStartTable[i].lpServiceName);
288 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(
289 &ServiceNameW,
290 &ServiceNameA,
291 TRUE)))
292 {
293 for (j = 0; j < i; j++)
294 {
295 RtlInitUnicodeString(
296 &ServiceNameW,
297 ServiceStartTableW[j].lpServiceName);
298 RtlFreeUnicodeString(&ServiceNameW);
299 }
300 RtlFreeHeap(RtlGetProcessHeap(), 0, ServiceStartTableW);
301 SetLastError(ERROR_OUTOFMEMORY);
302 return FALSE;
303 }
304 ServiceStartTableW[i].lpServiceName = ServiceNameW.Buffer;
305 ServiceStartTableW[i].lpServiceProc =
306 lpServiceStartTable[i].lpServiceProc;
307 }
308
309 b = StartServiceCtrlDispatcherW(ServiceStartTableW);
310
311 for (i = 0; i < Count; i++)
312 {
313 RtlFreeHeap(RtlGetProcessHeap(), 0, ServiceStartTableW[i].lpServiceName);
314 }
315
316 RtlFreeHeap(RtlGetProcessHeap(), 0, ServiceStartTableW);
317
318 return b;
319 #else
320 UNIMPLEMENTED;
321 return 0;
322 #endif
323 }
324
325
326 /**********************************************************************
327 * StartServiceCtrlDispatcherW
328 *
329 * @unimplemented
330 */
331 BOOL STDCALL
332 StartServiceCtrlDispatcherW(LPSERVICE_TABLE_ENTRYW lpServiceStartTable)
333 {
334 ULONG i;
335 HANDLE hPipe;
336 DWORD dwError;
337
338 DPRINT("StartServiceCtrlDispatcherW() called\n");
339
340 i = 0;
341 while (lpServiceStartTable[i].lpServiceProc != NULL)
342 {
343 i++;
344 }
345
346 ActiveServiceCount = i;
347 ActiveServices = RtlAllocateHeap(RtlGetProcessHeap(),
348 HEAP_ZERO_MEMORY,
349 ActiveServiceCount * sizeof(ACTIVE_SERVICE));
350 if (ActiveServices == NULL)
351 {
352 return(FALSE);
353 }
354
355 /* Copy service names and start procedure */
356 for (i = 0; i < ActiveServiceCount; i++)
357 {
358 RtlCreateUnicodeString(&ActiveServices[i].ServiceName,
359 lpServiceStartTable[i].lpServiceName);
360 ActiveServices[i].MainFunction = lpServiceStartTable[i].lpServiceProc;
361 }
362
363 dwError = ScConnectControlPipe(&hPipe);
364 if (dwError == ERROR_SUCCESS)
365 {
366 /* FIXME: free the service table */
367 return(FALSE);
368 }
369
370 ScServiceDispatcher(hPipe, NULL, NULL);
371 CloseHandle(hPipe);
372
373 /* FIXME: free the service table */
374
375 return(TRUE);
376
377 #if 0
378 ActiveServicesThreadHandles = RtlAllocateHeap(RtlGetProcessHeap(),
379 HEAP_ZERO_MEMORY,
380 (ActiveServiceCount + 1) * sizeof(HANDLE));
381 if (!ActiveServicesThreadHandles)
382 {
383 RtlFreeHeap(RtlGetProcessHeap(), 0, ActiveServices);
384 ActiveServices = NULL;
385 return(FALSE);
386 }
387
388 for (i = 0; i<ActiveServiceCount; i++)
389 {
390 h = CreateThread(
391 NULL,
392 0,
393 ScServiceMainStub,
394 lpServiceStartTable[i].lpServiceProc,
395 0,
396 &Tid);
397 if (h == INVALID_HANDLE_VALUE)
398 {
399 RtlFreeHeap(RtlGetProcessHeap(), 0, ActiveServicesThreadHandles);
400 ActiveServicesThreadHandles = NULL;
401 RtlFreeHeap(RtlGetProcessHeap(), 0, ActiveServices);
402 ActiveServices = NULL;
403 return(FALSE);
404 }
405 ActiveServicesThreadHandles[i + 1] = h;
406 ActiveServices[i].ThreadId = Tid;
407 }
408
409 while (ActiveServiceCount > 0)
410 {
411 r = WaitForMultipleObjects(
412 ActiveServiceCount + 1,
413 ActiveServicesThreadHandles,
414 FALSE,
415 INFINITE);
416 if (r == WAIT_OBJECT_0)
417 {
418 /* Received message from the scm */
419 }
420 else if (r > WAIT_OBJECT_0 && r < (WAIT_OBJECT_0 + ActiveServiceCount))
421 {
422 /* A service died */
423
424 ActiveServiceCount--;
425 ActiveServicesThreadHandles[r - WAIT_OBJECT_0 - 1] =
426 ActiveServicesThreadHandles[ActiveServiceCount + 1];
427 RtlCopyMemory(
428 &ActiveServices[r - WAIT_OBJECT_0 - 2],
429 &ActiveServices[ActiveServiceCount],
430 sizeof(ACTIVE_SERVICE));
431 }
432 else
433 {
434 /* Bail */
435 }
436 }
437 return TRUE;
438 #endif
439 }
440
441 /* EOF */