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