* Sync with recent trunk (r52637).
[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 LPWSTR lpDependencies,
98 DWORD dwDependenciesLength)
99 {
100 DWORD dwError = ERROR_SUCCESS;
101 DWORD dwGroupLength = 0;
102 DWORD dwServiceLength = 0;
103 DWORD dwLength;
104 LPWSTR lpGroupDeps;
105 LPWSTR lpServiceDeps;
106 LPWSTR 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 dwLength = wcslen(lpSrc) + 1;
129 if (*lpSrc == SC_GROUP_IDENTIFIERW)
130 {
131 lpSrc++;
132 dwGroupLength += dwLength;
133 wcscpy(lpDst, lpSrc);
134 lpDst = lpDst + dwLength;
135 }
136
137 lpSrc = lpSrc + dwLength;
138 }
139 *lpDst = 0;
140 lpDst++;
141 dwGroupLength++;
142
143 lpSrc = lpDependencies;
144 lpServiceDeps = lpDst;
145 while (*lpSrc != 0)
146 {
147 dwLength = wcslen(lpSrc) + 1;
148 if (*lpSrc != SC_GROUP_IDENTIFIERW)
149 {
150 dwServiceLength += dwLength;
151 wcscpy(lpDst, lpSrc);
152 lpDst = lpDst + dwLength;
153 }
154
155 lpSrc = lpSrc + dwLength;
156 }
157 *lpDst = 0;
158 dwServiceLength++;
159
160 if (dwGroupLength > 1)
161 {
162 dwError = RegSetValueExW(hServiceKey,
163 L"DependOnGroup",
164 0,
165 REG_MULTI_SZ,
166 (LPBYTE)lpGroupDeps,
167 dwGroupLength * sizeof(WCHAR));
168 }
169 else
170 {
171 RegDeleteValueW(hServiceKey,
172 L"DependOnGroup");
173 }
174
175 if (dwError == ERROR_SUCCESS)
176 {
177 if (dwServiceLength > 1)
178 {
179 dwError = RegSetValueExW(hServiceKey,
180 L"DependOnService",
181 0,
182 REG_MULTI_SZ,
183 (LPBYTE)lpServiceDeps,
184 dwServiceLength * 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 LPWSTR lpValueName,
250 LPWSTR *lpValue)
251 {
252 DWORD dwError;
253 DWORD dwSize;
254 DWORD dwType;
255 DWORD dwSizeNeeded;
256 LPWSTR expanded = NULL;
257 LPWSTR ptr = NULL;
258
259 *lpValue = NULL;
260
261 dwSize = 0;
262 dwError = RegQueryValueExW(hServiceKey,
263 lpValueName,
264 0,
265 &dwType,
266 NULL,
267 &dwSize);
268 if (dwError != ERROR_SUCCESS)
269 return dwError;
270
271 ptr = HeapAlloc(GetProcessHeap(), 0, dwSize);
272 if (ptr == NULL)
273 return ERROR_NOT_ENOUGH_MEMORY;
274
275 dwError = RegQueryValueExW(hServiceKey,
276 lpValueName,
277 0,
278 &dwType,
279 (LPBYTE)ptr,
280 &dwSize);
281 if (dwError != ERROR_SUCCESS)
282 goto done;
283
284 if (dwType == REG_EXPAND_SZ)
285 {
286 /* Expand the value... */
287 dwSizeNeeded = ExpandEnvironmentStringsW((LPCWSTR)ptr, NULL, 0);
288 if (dwSizeNeeded == 0)
289 {
290 dwError = GetLastError();
291 goto done;
292 }
293 expanded = HeapAlloc(GetProcessHeap(), 0, dwSizeNeeded * sizeof(WCHAR));
294 if (dwSizeNeeded < ExpandEnvironmentStringsW((LPCWSTR)ptr, expanded, dwSizeNeeded))
295 {
296 dwError = GetLastError();
297 goto done;
298 }
299 *lpValue = expanded;
300 HeapFree(GetProcessHeap(), 0, ptr);
301 dwError = ERROR_SUCCESS;
302 }
303 else
304 {
305 *lpValue = ptr;
306 }
307
308 done:
309 if (dwError != ERROR_SUCCESS)
310 {
311 HeapFree(GetProcessHeap(), 0, ptr);
312 if (expanded)
313 HeapFree(GetProcessHeap(), 0, expanded);
314 }
315
316 return dwError;
317 }
318
319
320 DWORD
321 ScmReadDependencies(HKEY hServiceKey,
322 LPWSTR *lpDependencies,
323 DWORD *lpdwDependenciesLength)
324 {
325 LPWSTR lpGroups = NULL;
326 LPWSTR lpServices = NULL;
327 DWORD dwGroupsLength = 0;
328 DWORD dwServicesLength = 0;
329 LPWSTR lpSrc;
330 LPWSTR lpDest;
331 DWORD len;
332 DWORD dwTotalLength;
333
334 *lpDependencies = NULL;
335 *lpdwDependenciesLength = 0;
336
337 /* Read the dependency values */
338 ScmReadString(hServiceKey,
339 L"DependOnGroup",
340 &lpGroups);
341
342 ScmReadString(hServiceKey,
343 L"DependOnService",
344 &lpServices);
345
346 /* Leave, if there are no dependencies */
347 if (lpGroups == NULL && lpServices == NULL)
348 return ERROR_SUCCESS;
349
350 /* Determine the total buffer size for the dependencies */
351 if (lpGroups)
352 {
353 DPRINT("Groups:\n");
354 lpSrc = lpGroups;
355 while (*lpSrc != 0)
356 {
357 DPRINT(" %S\n", lpSrc);
358
359 len = wcslen(lpSrc) + 1;
360 dwGroupsLength += len + 1;
361
362 lpSrc = lpSrc + len;
363 }
364 }
365
366 if (lpServices)
367 {
368 DPRINT("Services:\n");
369 lpSrc = lpServices;
370 while (*lpSrc != 0)
371 {
372 DPRINT(" %S\n", lpSrc);
373
374 len = wcslen(lpSrc) + 1;
375 dwServicesLength += len;
376
377 lpSrc = lpSrc + len;
378 }
379 }
380
381 dwTotalLength = dwGroupsLength + dwServicesLength + 1;
382 DPRINT("dwTotalLength: %lu\n", dwTotalLength);
383
384 /* Allocate the common buffer for the dependencies */
385 *lpDependencies = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwTotalLength * sizeof(WCHAR));
386 if (*lpDependencies == NULL)
387 {
388 if (lpGroups)
389 HeapFree(GetProcessHeap(), 0, lpGroups);
390
391 if (lpServices)
392 HeapFree(GetProcessHeap(), 0, lpServices);
393
394 return ERROR_NOT_ENOUGH_MEMORY;
395 }
396
397 /* Return the allocated buffer length in characters */
398 *lpdwDependenciesLength = dwTotalLength;
399
400 /* Copy the service dependencies into the common buffer */
401 lpDest = *lpDependencies;
402 if (lpServices)
403 {
404 memcpy(lpDest,
405 lpServices,
406 dwServicesLength * sizeof(WCHAR));
407
408 lpDest = lpDest + dwServicesLength;
409 }
410
411 /* Copy the group dependencies into the common buffer */
412 if (lpGroups)
413 {
414 lpSrc = lpGroups;
415 while (*lpSrc != 0)
416 {
417 len = wcslen(lpSrc) + 1;
418
419 *lpDest = SC_GROUP_IDENTIFIERW;
420 lpDest++;
421
422 wcscpy(lpDest, lpSrc);
423
424 lpDest = lpDest + len;
425 lpSrc = lpSrc + len;
426 }
427 }
428
429 /* Free the temporary buffers */
430 if (lpGroups)
431 HeapFree(GetProcessHeap(), 0, lpGroups);
432
433 if (lpServices)
434 HeapFree(GetProcessHeap(), 0, lpServices);
435
436 return ERROR_SUCCESS;
437 }
438
439 /* EOF */