Sync with trunk r63383 .
[reactos.git] / base / system / services / config.c
1 /*
2 * PROJECT: ReactOS Service Control Manager
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: base/system/services/config.c
5 * PURPOSE: Service configuration interface
6 * COPYRIGHT: Copyright 2005 Eric Kohl
7 *
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #include "services.h"
13
14 #define NDEBUG
15 #include <debug.h>
16
17 /* FUNCTIONS *****************************************************************/
18
19
20 DWORD
21 ScmOpenServiceKey(LPWSTR lpServiceName,
22 REGSAM samDesired,
23 PHKEY phKey)
24 {
25 HKEY hServicesKey = NULL;
26 DWORD dwError;
27
28 *phKey = NULL;
29
30 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
31 L"System\\CurrentControlSet\\Services",
32 0,
33 KEY_READ,
34 &hServicesKey);
35 if (dwError != ERROR_SUCCESS)
36 return dwError;
37
38 dwError = RegOpenKeyExW(hServicesKey,
39 lpServiceName,
40 0,
41 samDesired,
42 phKey);
43
44 RegCloseKey(hServicesKey);
45
46 return dwError;
47 }
48
49
50 DWORD
51 ScmCreateServiceKey(LPCWSTR lpServiceName,
52 REGSAM samDesired,
53 PHKEY phKey)
54 {
55 HKEY hServicesKey = NULL;
56 DWORD dwDisposition;
57 DWORD dwError;
58
59 *phKey = NULL;
60
61 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
62 L"System\\CurrentControlSet\\Services",
63 0,
64 KEY_READ | KEY_CREATE_SUB_KEY,
65 &hServicesKey);
66 if (dwError != ERROR_SUCCESS)
67 return dwError;
68
69 dwError = RegCreateKeyExW(hServicesKey,
70 lpServiceName,
71 0,
72 NULL,
73 REG_OPTION_NON_VOLATILE,
74 samDesired,
75 NULL,
76 phKey,
77 &dwDisposition);
78 #if 0
79 if ((dwError == ERROR_SUCCESS) &&
80 (dwDisposition == REG_OPENED_EXISTING_KEY))
81 {
82 RegCloseKey(*phKey);
83 *phKey = NULL;
84 dwError = ERROR_SERVICE_EXISTS;
85 }
86 #endif
87
88 RegCloseKey(hServicesKey);
89
90 return dwError;
91 }
92
93
94
95 DWORD
96 ScmWriteDependencies(HKEY hServiceKey,
97 LPCWSTR lpDependencies,
98 DWORD dwDependenciesLength)
99 {
100 DWORD dwError = ERROR_SUCCESS;
101 SIZE_T cchGroupLength = 0;
102 SIZE_T cchServiceLength = 0;
103 SIZE_T cchLength;
104 LPWSTR lpGroupDeps;
105 LPWSTR lpServiceDeps;
106 LPCWSTR lpSrc;
107 LPWSTR lpDst;
108
109 if (*lpDependencies == 0)
110 {
111 RegDeleteValueW(hServiceKey,
112 L"DependOnService");
113 RegDeleteValueW(hServiceKey,
114 L"DependOnGroup");
115 }
116 else
117 {
118 lpGroupDeps = HeapAlloc(GetProcessHeap(),
119 HEAP_ZERO_MEMORY,
120 (dwDependenciesLength + 2) * sizeof(WCHAR));
121 if (lpGroupDeps == NULL)
122 return ERROR_NOT_ENOUGH_MEMORY;
123
124 lpSrc = lpDependencies;
125 lpDst = lpGroupDeps;
126 while (*lpSrc != 0)
127 {
128 cchLength = wcslen(lpSrc) + 1;
129 if (*lpSrc == SC_GROUP_IDENTIFIERW)
130 {
131 lpSrc++;
132 cchGroupLength += cchLength;
133 wcscpy(lpDst, lpSrc);
134 lpDst = lpDst + cchLength;
135 }
136
137 lpSrc = lpSrc + cchLength;
138 }
139 *lpDst = 0;
140 lpDst++;
141 cchGroupLength++;
142
143 lpSrc = lpDependencies;
144 lpServiceDeps = lpDst;
145 while (*lpSrc != 0)
146 {
147 cchLength = wcslen(lpSrc) + 1;
148 if (*lpSrc != SC_GROUP_IDENTIFIERW)
149 {
150 cchServiceLength += cchLength;
151 wcscpy(lpDst, lpSrc);
152 lpDst = lpDst + cchLength;
153 }
154
155 lpSrc = lpSrc + cchLength;
156 }
157 *lpDst = 0;
158 cchServiceLength++;
159
160 if (cchGroupLength > 1)
161 {
162 dwError = RegSetValueExW(hServiceKey,
163 L"DependOnGroup",
164 0,
165 REG_MULTI_SZ,
166 (LPBYTE)lpGroupDeps,
167 (DWORD)(cchGroupLength * sizeof(WCHAR)));
168 }
169 else
170 {
171 RegDeleteValueW(hServiceKey,
172 L"DependOnGroup");
173 }
174
175 if (dwError == ERROR_SUCCESS)
176 {
177 if (cchServiceLength > 1)
178 {
179 dwError = RegSetValueExW(hServiceKey,
180 L"DependOnService",
181 0,
182 REG_MULTI_SZ,
183 (LPBYTE)lpServiceDeps,
184 (DWORD)(cchServiceLength * sizeof(WCHAR)));
185 }
186 else
187 {
188 RegDeleteValueW(hServiceKey,
189 L"DependOnService");
190 }
191 }
192
193 HeapFree(GetProcessHeap(), 0, lpGroupDeps);
194 }
195
196 return dwError;
197 }
198
199
200 DWORD
201 ScmMarkServiceForDelete(PSERVICE pService)
202 {
203 HKEY hServiceKey = NULL;
204 DWORD dwValue = 1;
205 DWORD dwError;
206
207 DPRINT("ScmMarkServiceForDelete() called\n");
208
209 dwError = ScmOpenServiceKey(pService->lpServiceName,
210 KEY_WRITE,
211 &hServiceKey);
212 if (dwError != ERROR_SUCCESS)
213 return dwError;
214
215 dwError = RegSetValueExW(hServiceKey,
216 L"DeleteFlag",
217 0,
218 REG_DWORD,
219 (LPBYTE)&dwValue,
220 sizeof(DWORD));
221
222 RegCloseKey(hServiceKey);
223
224 return dwError;
225 }
226
227
228 BOOL
229 ScmIsDeleteFlagSet(HKEY hServiceKey)
230 {
231 DWORD dwError;
232 DWORD dwType;
233 DWORD dwFlag;
234 DWORD dwSize = sizeof(DWORD);
235
236 dwError = RegQueryValueExW(hServiceKey,
237 L"DeleteFlag",
238 0,
239 &dwType,
240 (LPBYTE)&dwFlag,
241 &dwSize);
242
243 return (dwError == ERROR_SUCCESS);
244 }
245
246
247 DWORD
248 ScmReadString(HKEY hServiceKey,
249 LPCWSTR lpValueName,
250 LPWSTR *lpValue)
251 {
252 DWORD dwError = 0;
253 DWORD dwSize = 0;
254 DWORD dwType = 0;
255 LPWSTR ptr = NULL;
256 LPWSTR expanded = NULL;
257
258 *lpValue = NULL;
259
260 dwError = RegQueryValueExW(hServiceKey,
261 lpValueName,
262 0,
263 &dwType,
264 NULL,
265 &dwSize);
266 if (dwError != ERROR_SUCCESS)
267 return dwError;
268
269 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize);
270 if (ptr == NULL)
271 return ERROR_NOT_ENOUGH_MEMORY;
272
273 dwError = RegQueryValueExW(hServiceKey,
274 lpValueName,
275 0,
276 &dwType,
277 (LPBYTE)ptr,
278 &dwSize);
279 if (dwError != ERROR_SUCCESS)
280 {
281 HeapFree(GetProcessHeap(), 0, ptr);
282 return dwError;
283 }
284
285 if (dwType == REG_EXPAND_SZ)
286 {
287 /* Expand the value... */
288 dwSize = ExpandEnvironmentStringsW(ptr, NULL, 0);
289 if (dwSize > 0)
290 {
291 expanded = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize * sizeof(WCHAR));
292 if (expanded)
293 {
294 if (dwSize == ExpandEnvironmentStringsW(ptr, expanded, dwSize))
295 {
296 *lpValue = expanded;
297 dwError = ERROR_SUCCESS;
298 }
299 else
300 {
301 dwError = GetLastError();
302 HeapFree(GetProcessHeap(), 0, expanded);
303 }
304 }
305 else
306 {
307 dwError = ERROR_NOT_ENOUGH_MEMORY;
308 }
309 }
310 else
311 {
312 dwError = GetLastError();
313 }
314
315 HeapFree(GetProcessHeap(), 0, ptr);
316 }
317 else
318 {
319 *lpValue = ptr;
320 }
321
322 return dwError;
323 }
324
325
326 DWORD
327 ScmReadDependencies(HKEY hServiceKey,
328 LPWSTR *lpDependencies,
329 DWORD *lpdwDependenciesLength)
330 {
331 LPWSTR lpGroups = NULL;
332 LPWSTR lpServices = NULL;
333 SIZE_T cchGroupsLength = 0;
334 SIZE_T cchServicesLength = 0;
335 LPWSTR lpSrc;
336 LPWSTR lpDest;
337 SIZE_T cchLength;
338 SIZE_T cchTotalLength;
339
340 *lpDependencies = NULL;
341 *lpdwDependenciesLength = 0;
342
343 /* Read the dependency values */
344 ScmReadString(hServiceKey,
345 L"DependOnGroup",
346 &lpGroups);
347
348 ScmReadString(hServiceKey,
349 L"DependOnService",
350 &lpServices);
351
352 /* Leave, if there are no dependencies */
353 if (lpGroups == NULL && lpServices == NULL)
354 return ERROR_SUCCESS;
355
356 /* Determine the total buffer size for the dependencies */
357 if (lpGroups)
358 {
359 DPRINT("Groups:\n");
360 lpSrc = lpGroups;
361 while (*lpSrc != 0)
362 {
363 DPRINT(" %S\n", lpSrc);
364
365 cchLength = wcslen(lpSrc) + 1;
366 cchGroupsLength += cchLength + 1;
367
368 lpSrc = lpSrc + cchLength;
369 }
370 }
371
372 if (lpServices)
373 {
374 DPRINT("Services:\n");
375 lpSrc = lpServices;
376 while (*lpSrc != 0)
377 {
378 DPRINT(" %S\n", lpSrc);
379
380 cchLength = wcslen(lpSrc) + 1;
381 cchServicesLength += cchLength;
382
383 lpSrc = lpSrc + cchLength;
384 }
385 }
386
387 cchTotalLength = cchGroupsLength + cchServicesLength + 1;
388 DPRINT("cchTotalLength: %lu\n", cchTotalLength);
389
390 /* Allocate the common buffer for the dependencies */
391 *lpDependencies = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cchTotalLength * sizeof(WCHAR));
392 if (*lpDependencies == NULL)
393 {
394 if (lpGroups)
395 HeapFree(GetProcessHeap(), 0, lpGroups);
396
397 if (lpServices)
398 HeapFree(GetProcessHeap(), 0, lpServices);
399
400 return ERROR_NOT_ENOUGH_MEMORY;
401 }
402
403 /* Return the allocated buffer length in characters */
404 *lpdwDependenciesLength = (DWORD)cchTotalLength;
405
406 /* Copy the service dependencies into the common buffer */
407 lpDest = *lpDependencies;
408 if (lpServices)
409 {
410 memcpy(lpDest,
411 lpServices,
412 cchServicesLength * sizeof(WCHAR));
413
414 lpDest = lpDest + cchServicesLength;
415 }
416
417 /* Copy the group dependencies into the common buffer */
418 if (lpGroups)
419 {
420 lpSrc = lpGroups;
421 while (*lpSrc != 0)
422 {
423 cchLength = wcslen(lpSrc) + 1;
424
425 *lpDest = SC_GROUP_IDENTIFIERW;
426 lpDest++;
427
428 wcscpy(lpDest, lpSrc);
429
430 lpDest = lpDest + cchLength;
431 lpSrc = lpSrc + cchLength;
432 }
433 }
434
435 /* Free the temporary buffers */
436 if (lpGroups)
437 HeapFree(GetProcessHeap(), 0, lpGroups);
438
439 if (lpServices)
440 HeapFree(GetProcessHeap(), 0, lpServices);
441
442 return ERROR_SUCCESS;
443 }
444
445 /* EOF */