More svchost stub, end-of-the-day checkin.
[reactos.git] / reactos / base / services / svchost / svchost.c
1 /*
2 * PROJECT: ReactOS SvcHost
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: /base/services/svchost/svchost.c
5 * PURPOSE: Provide dll service loader
6 * PROGRAMMERS: Gregor Brunmar (gregor.brunmar@home.se)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include "svchost.h"
12 #include <debug.h>
13
14 #ifdef _MSC_VER
15 #undef DPRINT1
16 #define DPRINT1
17 #endif
18
19 /* DEFINES *******************************************************************/
20
21 static LPCTSTR SVCHOST_REG_KEY = _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\SvcHost");
22 static LPCTSTR SERVICE_KEY = _T("SYSTEM\\CurrentControlSet\\Services\\");
23 static LPCTSTR PARAMETERS_KEY = _T("\\Parameters");
24
25 #define SERVICE_KEY_LENGTH _tcslen(SERVICE_KEY);
26 #define REG_MAX_DATA_SIZE 2048
27
28 static PSERVICE FirstService = NULL;
29
30 /* FUNCTIONS *****************************************************************/
31
32 BOOL PrepareService(LPCTSTR ServiceName)
33 {
34 HKEY hServiceKey;
35 TCHAR ServiceKeyBuffer[MAX_PATH + 1];
36 DWORD LeftOfBuffer = sizeof(ServiceKeyBuffer) / sizeof(ServiceKeyBuffer[0]);
37 DWORD KeyType;
38 PTSTR Buffer = NULL;
39 DWORD BufferSize = MAX_PATH + 1;
40 LONG RetVal;
41 HINSTANCE hServiceDll;
42 TCHAR DllPath[MAX_PATH + 2]; /* See MSDN on ExpandEnvironmentStrings() for ANSI strings for more details on + 2 */
43 LPSERVICE_MAIN_FUNCTION ServiceMainFunc;
44 PSERVICE Service;
45
46 /* Compose the registry path to the service's "Parameter" key */
47 _tcsncpy(ServiceKeyBuffer, SERVICE_KEY, LeftOfBuffer);
48 LeftOfBuffer -= _tcslen(SERVICE_KEY);
49 _tcsncat(ServiceKeyBuffer, ServiceName, LeftOfBuffer);
50 LeftOfBuffer -= _tcslen(ServiceName);
51 _tcsncat(ServiceKeyBuffer, PARAMETERS_KEY, LeftOfBuffer);
52 LeftOfBuffer -= _tcslen(PARAMETERS_KEY);
53
54 if (LeftOfBuffer < 0)
55 {
56 DPRINT1("Buffer overflow for service name: '%s'\n", ServiceName);
57 return FALSE;
58 }
59
60 /* Open the service registry key to find the dll name */
61 if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, ServiceKeyBuffer, 0, KEY_READ, &hServiceKey))
62 {
63 DPRINT1("Could not open service key (%s)\n", ServiceKeyBuffer);
64 return FALSE;
65 }
66
67 do
68 {
69 if (Buffer)
70 HeapFree(GetProcessHeap(), 0, Buffer);
71
72 Buffer = HeapAlloc(GetProcessHeap(), 0, BufferSize);
73 if (NULL == Buffer)
74 {
75 DPRINT1("Not enough memory for service: %s\n", ServiceName);
76 return FALSE;
77 }
78
79 RetVal = RegQueryValueEx(hServiceKey, _T("ServiceDll"), NULL, &KeyType, (LPBYTE)Buffer, &BufferSize);
80
81 } while (ERROR_MORE_DATA == RetVal);
82
83
84 RegCloseKey(hServiceKey);
85
86 if (ERROR_SUCCESS != RetVal || 0 == BufferSize)
87 {
88 DPRINT1("Could not read 'ServiceDll' value from service: %s, ErrorCode: 0x%x\n", ServiceName, RetVal);
89 HeapFree(GetProcessHeap(), 0, Buffer);
90 return FALSE;
91 }
92
93 /* Convert possible %SystemRoot% to a real path */
94 BufferSize = ExpandEnvironmentStrings(Buffer, DllPath, sizeof(DllPath));
95 if (0 == BufferSize)
96 {
97 DPRINT1("Invalid ServiceDll path: %s\n", Buffer);
98 HeapFree(GetProcessHeap(), 0, Buffer);
99 return FALSE;
100 }
101
102 HeapFree(GetProcessHeap(), 0, Buffer);
103
104 /* Load the service dll */
105 hServiceDll = LoadLibrary(DllPath);
106
107 if (NULL == hServiceDll)
108 {
109 DPRINT1("Unable to load ServiceDll: %s\n", DllPath);
110 return FALSE;
111 }
112
113 ServiceMainFunc = (LPSERVICE_MAIN_FUNCTION)GetProcAddress(hServiceDll, "ServiceMain");
114
115 /* Allocate a service node in the linked list */
116 Service = HeapAlloc(GetProcessHeap(), 0, sizeof(SERVICE));
117 if (NULL == Service)
118 {
119 DPRINT1("Not enough memory for service: %s\n", ServiceName);
120 return FALSE;
121 }
122
123 memset(Service, 0, sizeof(SERVICE));
124 Service->Name = HeapAlloc(GetProcessHeap(), 0, _tcslen(ServiceName) + sizeof(TCHAR));
125 if (NULL == Service->Name)
126 {
127 DPRINT1("Not enough memory for service: %s\n", ServiceName);
128 HeapFree(GetProcessHeap(), 0, Service);
129 return FALSE;
130 }
131 _tcscpy(Service->Name, ServiceName);
132
133 Service->hServiceDll = hServiceDll;
134 Service->ServiceMainFunc = ServiceMainFunc;
135
136 Service->Next = FirstService;
137 FirstService = Service;
138
139 return TRUE;
140 }
141
142 VOID FreeServices()
143 {
144 while (FirstService)
145 {
146 PSERVICE Service = FirstService;
147 FirstService = Service->Next;
148
149 FreeLibrary(Service->hServiceDll);
150
151 HeapFree(GetProcessHeap(), 0, Service->Name);
152 HeapFree(GetProcessHeap(), 0, Service);
153 }
154 }
155
156 /*
157 * Returns the number of services successfully loaded from the category
158 */
159 DWORD LoadServiceCategory(LPCTSTR ServiceCategory)
160 {
161 HKEY hServicesKey;
162 DWORD KeyType;
163 DWORD BufferSize = REG_MAX_DATA_SIZE;
164 TCHAR Buffer[REG_MAX_DATA_SIZE];
165 LPCTSTR ServiceName;
166 DWORD BufferIndex = 0;
167 DWORD NrOfServices = 0;
168
169 /* Get all the services in this category */
170 if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, SVCHOST_REG_KEY, 0, KEY_READ, &hServicesKey))
171 {
172 DPRINT1("Could not open service category: %s\n", ServiceCategory);
173 return 0;
174 }
175
176 if (ERROR_SUCCESS != RegQueryValueEx(hServicesKey, ServiceCategory, NULL, &KeyType, (LPBYTE)Buffer, &BufferSize))
177 {
178 DPRINT1("Could not open service category (2): %s\n", ServiceCategory);
179 RegCloseKey(hServicesKey);
180 return 0;
181 }
182
183 /* Clean up */
184 RegCloseKey(hServicesKey);
185
186 /* Load services in the category */
187 ServiceName = Buffer;
188 while (_T('\0') != ServiceName[0])
189 {
190 size_t Length;
191
192 Length = _tcslen(ServiceName);
193 if (0 == Length)
194 break;
195
196 if (TRUE == PrepareService(ServiceName))
197 ++NrOfServices;
198
199 BufferIndex += (Length + 1) * sizeof(TCHAR);
200
201 ServiceName = &Buffer[BufferIndex];
202 }
203
204 return NrOfServices;
205 }
206
207 int _tmain (int argc, LPTSTR argv [])
208 {
209 DWORD NrOfServices;
210 LPSERVICE_TABLE_ENTRY ServiceTable;
211 DWORD i;
212
213 if (argc < 3)
214 {
215 /* MS svchost.exe doesn't seem to print help, should we? */
216 return 1;
217 }
218
219 if (_tcscmp(argv[1], _T("-k")) != 0)
220 {
221 /* For now, we only handle "-k" */
222 return 1;
223 }
224
225 NrOfServices = LoadServiceCategory(argv[2]);
226
227 if (0 == NrOfServices)
228 return 1;
229
230 ServiceTable = HeapAlloc(GetProcessHeap(), 0, sizeof(SERVICE_TABLE_ENTRY) * (NrOfServices + 1));
231
232 if (NULL != ServiceTable)
233 {
234 PSERVICE Service = FirstService;
235
236 for (i = 0; i < NrOfServices; ++i)
237 {
238 ServiceTable[i].lpServiceName = Service->Name;
239 ServiceTable[i].lpServiceProc = Service->ServiceMainFunc;
240 Service = Service->Next;
241 }
242
243 StartServiceCtrlDispatcher(ServiceTable);
244
245 HeapFree(GetProcessHeap(), 0, ServiceTable);
246 }
247 else
248 {
249 DPRINT1("Not enough memory for the service table, trying to allocate %u bytes\n", sizeof(SERVICE_TABLE_ENTRY) * (NrOfServices + 1));
250 }
251
252 FreeServices();
253
254 return 0;
255 }
256
257 /* EOF */