update for HEAD-2003021201
[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_FUNCTION 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_FUNCTION lpServiceProc = (LPSERVICE_MAIN_FUNCTION)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 SERVICE_STATUS_HANDLE STDCALL
156 RegisterServiceCtrlHandlerA(LPCSTR lpServiceName,
157                             LPHANDLER_FUNCTION lpHandlerProc)
158 {
159   ANSI_STRING ServiceNameA;
160   UNICODE_STRING ServiceNameU;
161   SERVICE_STATUS_HANDLE SHandle;
162
163   RtlInitAnsiString(&ServiceNameA, (LPSTR)lpServiceName);
164   if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ServiceNameU, &ServiceNameA, TRUE)))
165     {
166       SetLastError(ERROR_OUTOFMEMORY);
167       return((SERVICE_STATUS_HANDLE)0);
168     }
169
170   SHandle = RegisterServiceCtrlHandlerW(ServiceNameU.Buffer,
171                                         lpHandlerProc);
172
173   RtlFreeUnicodeString(&ServiceNameU);
174
175   return(SHandle);
176 }
177
178
179 /**********************************************************************
180  *      RegisterServiceCtrlHandlerW
181  */
182 SERVICE_STATUS_HANDLE STDCALL
183 RegisterServiceCtrlHandlerW(LPCWSTR lpServiceName,
184                             LPHANDLER_FUNCTION lpHandlerProc)
185 {
186   PACTIVE_SERVICE Service;
187
188   Service = ScLookupServiceByServiceName((LPWSTR)lpServiceName);
189   if (Service == NULL)
190     {
191       return((SERVICE_STATUS_HANDLE)NULL);
192     }
193
194   Service->HandlerFunction = lpHandlerProc;
195
196   return((SERVICE_STATUS_HANDLE)Service->ThreadId);
197 }
198
199
200 /**********************************************************************
201  *      SetServiceBits
202  */
203 BOOL STDCALL
204 SetServiceBits(SERVICE_STATUS_HANDLE hServiceStatus,
205                DWORD dwServiceBits,
206                BOOL bSetBitsOn,
207                BOOL bUpdateImmediately)
208 {
209   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
210   return(FALSE);
211 }
212
213
214 /**********************************************************************
215  *      SetServiceObjectSecurity
216  */
217 WINBOOL STDCALL
218 SetServiceObjectSecurity(SC_HANDLE hService,
219                          SECURITY_INFORMATION dwSecurityInformation,
220                          PSECURITY_DESCRIPTOR lpSecurityDescriptor)
221 {
222   SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
223   return FALSE;
224 }
225
226
227 /**********************************************************************
228  *      SetServiceStatus
229  */
230 BOOL STDCALL
231 SetServiceStatus(SERVICE_STATUS_HANDLE hServiceStatus,
232                  LPSERVICE_STATUS lpServiceStatus)
233 {
234   PACTIVE_SERVICE Service;
235
236   Service = ScLookupServiceByThreadId((DWORD)hServiceStatus);
237   if (!Service)
238     {
239       SetLastError(ERROR_INVALID_HANDLE);
240       return(FALSE);
241     }
242
243   RtlCopyMemory(&Service->ServiceStatus,
244                 lpServiceStatus,
245                 sizeof(SERVICE_STATUS));
246
247   return(TRUE);
248 }
249
250
251 /**********************************************************************
252  *      StartServiceCtrlDispatcherA
253  */
254 BOOL STDCALL
255 StartServiceCtrlDispatcherA(LPSERVICE_TABLE_ENTRYA lpServiceStartTable)
256 {
257   LPSERVICE_TABLE_ENTRYW ServiceStartTableW;
258   ANSI_STRING ServiceNameA;
259   UNICODE_STRING ServiceNameW;
260   ULONG i, j;
261   ULONG Count;
262   BOOL b;
263
264   i = 0;
265   while (lpServiceStartTable[i].lpServiceProc != NULL)
266     {
267       i++;
268     }
269   Count = i;
270
271   ServiceStartTableW = RtlAllocateHeap(RtlGetProcessHeap(),
272                                        HEAP_ZERO_MEMORY,
273                                        sizeof(SERVICE_TABLE_ENTRYW) * Count);
274   for (i = 0; i < Count; i++)
275   {
276     RtlInitAnsiString(
277       &ServiceNameA,
278           lpServiceStartTable[i].lpServiceName);
279     if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(
280       &ServiceNameW,
281           &ServiceNameA,
282                 TRUE)))
283     {
284       for (j = 0; j < i; j++)
285       {
286         RtlInitUnicodeString(
287           &ServiceNameW,
288             ServiceStartTableW[j].lpServiceName);
289         RtlFreeUnicodeString(&ServiceNameW);
290       }
291       RtlFreeHeap(RtlGetProcessHeap(), 0, ServiceStartTableW);
292       SetLastError(ERROR_OUTOFMEMORY);
293           return FALSE;
294     }
295     ServiceStartTableW[i].lpServiceName = ServiceNameW.Buffer;
296     ServiceStartTableW[i].lpServiceProc = 
297       lpServiceStartTable[i].lpServiceProc;
298   }
299
300   b = StartServiceCtrlDispatcherW(ServiceStartTableW);
301
302   for (i = 0; i < Count; i++)
303     {
304       RtlFreeHeap(RtlGetProcessHeap(), 0, ServiceStartTableW[i].lpServiceName);
305     }
306
307   RtlFreeHeap(RtlGetProcessHeap(), 0, ServiceStartTableW);
308
309   return b;
310 }
311
312
313 /**********************************************************************
314  *      StartServiceCtrlDispatcherW
315  */
316 BOOL STDCALL
317 StartServiceCtrlDispatcherW(LPSERVICE_TABLE_ENTRYW lpServiceStartTable)
318 {
319   ULONG i;
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 */