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