1 /*
2 * PROJECT: ReactOS Services
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: base/applications/sc/misc.c
5 * PURPOSE: Various functions
6 * COPYRIGHT: Copyright 2005 - 2006 Ged Murphy <gedmurphy@gmail.com>
7 * Roel Messiant <roelmessiant@gmail.com>
8 */
9
10 #include "sc.h"
11
12 typedef struct
13 {
14 LPCTSTR lpOption;
15 DWORD dwValue;
16 } OPTION_INFO;
17
18 static const OPTION_INFO TypeOpts[] =
19 {
20 { _T("own"), SERVICE_WIN32_OWN_PROCESS },
21 { _T("share"), SERVICE_WIN32_SHARE_PROCESS },
22 { _T("interact"), SERVICE_INTERACTIVE_PROCESS },
23 { _T("kernel"), SERVICE_KERNEL_DRIVER },
24 { _T("filesys"), SERVICE_FILE_SYSTEM_DRIVER },
25 { _T("rec"), SERVICE_RECOGNIZER_DRIVER }
26 };
27
28 static const OPTION_INFO StartOpts[] =
29 {
30 { _T("boot"), SERVICE_BOOT_START },
31 { _T("system"), SERVICE_SYSTEM_START },
32 { _T("auto"), SERVICE_AUTO_START },
33 { _T("demand"), SERVICE_DEMAND_START },
34 { _T("disabled"), SERVICE_DISABLED }
35 };
36
37 static const OPTION_INFO ErrorOpts[] =
38 {
39 { _T("normal"), SERVICE_ERROR_NORMAL },
40 { _T("severe"), SERVICE_ERROR_SEVERE },
41 { _T("critical"), SERVICE_ERROR_CRITICAL },
42 { _T("ignore"), SERVICE_ERROR_IGNORE }
43 };
44
45 static const OPTION_INFO TagOpts[] =
46 {
47 { _T("yes"), TRUE },
48 { _T("no"), FALSE }
49 };
50
51
52 BOOL
ParseCreateConfigArguments(LPCTSTR * ServiceArgs,INT ArgCount,BOOL bChangeService,OUT LPSERVICE_CREATE_INFO lpServiceInfo)53 ParseCreateConfigArguments(
54 LPCTSTR *ServiceArgs,
55 INT ArgCount,
56 BOOL bChangeService,
57 OUT LPSERVICE_CREATE_INFO lpServiceInfo)
58 {
59 INT i, ArgIndex = 1;
60
61 if (ArgCount < 1)
62 return FALSE;
63
64 ZeroMemory(lpServiceInfo, sizeof(SERVICE_CREATE_INFO));
65
66 if (bChangeService)
67 {
68 lpServiceInfo->dwServiceType = SERVICE_NO_CHANGE;
69 lpServiceInfo->dwStartType = SERVICE_NO_CHANGE;
70 lpServiceInfo->dwErrorControl = SERVICE_NO_CHANGE;
71 }
72
73 lpServiceInfo->lpServiceName = ServiceArgs[0];
74
75 ArgCount--;
76
77 while (ArgCount > 1)
78 {
79 if (!lstrcmpi(ServiceArgs[ArgIndex], _T("type=")))
80 {
81 for (i = 0; i < sizeof(TypeOpts) / sizeof(TypeOpts[0]); i++)
82 if (!lstrcmpi(ServiceArgs[ArgIndex + 1], TypeOpts[i].lpOption))
83 {
84 if (lpServiceInfo->dwServiceType == SERVICE_NO_CHANGE)
85 lpServiceInfo->dwServiceType = TypeOpts[i].dwValue;
86 else
87 lpServiceInfo->dwServiceType |= TypeOpts[i].dwValue;
88 break;
89 }
90
91 if (i == sizeof(TypeOpts) / sizeof(TypeOpts[0]))
92 break;
93 }
94 else if (!lstrcmpi(ServiceArgs[ArgIndex], _T("start=")))
95 {
96 for (i = 0; i < sizeof(StartOpts) / sizeof(StartOpts[0]); i++)
97 if (!lstrcmpi(ServiceArgs[ArgIndex + 1], StartOpts[i].lpOption))
98 {
99 lpServiceInfo->dwStartType = StartOpts[i].dwValue;
100 break;
101 }
102
103 if (i == sizeof(StartOpts) / sizeof(StartOpts[0]))
104 break;
105 }
106 else if (!lstrcmpi(ServiceArgs[ArgIndex], _T("error=")))
107 {
108 for (i = 0; i < sizeof(ErrorOpts) / sizeof(ErrorOpts[0]); i++)
109 if (!lstrcmpi(ServiceArgs[ArgIndex + 1], ErrorOpts[i].lpOption))
110 {
111 lpServiceInfo->dwErrorControl = ErrorOpts[i].dwValue;
112 break;
113 }
114
115 if (i == sizeof(ErrorOpts) / sizeof(ErrorOpts[0]))
116 break;
117 }
118 else if (!lstrcmpi(ServiceArgs[ArgIndex], _T("tag=")))
119 {
120 for (i = 0; i < sizeof(TagOpts) / sizeof(TagOpts[0]); i++)
121 if (!lstrcmpi(ServiceArgs[ArgIndex + 1], TagOpts[i].lpOption))
122 {
123 lpServiceInfo->bTagId = TagOpts[i].dwValue;
124 break;
125 }
126
127 if (i == sizeof(TagOpts) / sizeof(TagOpts[0]))
128 break;
129 }
130 else if (!lstrcmpi(ServiceArgs[ArgIndex], _T("binpath=")))
131 {
132 lpServiceInfo->lpBinaryPathName = ServiceArgs[ArgIndex + 1];
133 }
134 else if (!lstrcmpi(ServiceArgs[ArgIndex], _T("group=")))
135 {
136 lpServiceInfo->lpLoadOrderGroup = ServiceArgs[ArgIndex + 1];
137 }
138 else if (!lstrcmpi(ServiceArgs[ArgIndex], _T("depend=")))
139 {
140 lpServiceInfo->lpDependencies = ServiceArgs[ArgIndex + 1];
141 }
142 else if (!lstrcmpi(ServiceArgs[ArgIndex], _T("obj=")))
143 {
144 lpServiceInfo->lpServiceStartName = ServiceArgs[ArgIndex + 1];
145 }
146 else if (!lstrcmpi(ServiceArgs[ArgIndex], _T("displayname=")))
147 {
148 lpServiceInfo->lpDisplayName = ServiceArgs[ArgIndex + 1];
149 }
150 else if (!lstrcmpi(ServiceArgs[ArgIndex], _T("password=")))
151 {
152 lpServiceInfo->lpPassword = ServiceArgs[ArgIndex + 1];
153 }
154
155 ArgIndex += 2;
156 ArgCount -= 2;
157 }
158
159 return (ArgCount == 0);
160 }
161
162
163 BOOL
ParseFailureActions(IN LPCTSTR lpActions,OUT DWORD * pcActions,OUT SC_ACTION ** ppActions)164 ParseFailureActions(
165 IN LPCTSTR lpActions,
166 OUT DWORD *pcActions,
167 OUT SC_ACTION **ppActions)
168 {
169 SC_ACTION *pActions = NULL;
170 LPTSTR pStringBuffer = NULL;
171 LPTSTR p;
172 INT_PTR nLength;
173 INT nCount = 0;
174
175 *pcActions = 0;
176 *ppActions = NULL;
177
178 nLength = _tcslen(lpActions);
179
180 /* Allocate the string buffer */
181 pStringBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (nLength + 2) * sizeof(TCHAR));
182 if (pStringBuffer == NULL)
183 {
184 return FALSE;
185 }
186
187 /* Copy the actions string into the string buffer */
188 CopyMemory(pStringBuffer, lpActions, nLength * sizeof(TCHAR));
189
190 /* Replace all slashes by null characters */
191 p = pStringBuffer;
192 while (*p != _T('\0'))
193 {
194 if (*p == _T('/'))
195 *p = _T('\0');
196 p++;
197 }
198
199 /* Count the arguments in the buffer */
200 p = pStringBuffer;
201 while (*p != _T('\0'))
202 {
203 nCount++;
204
205 nLength = _tcslen(p);
206 p = (LPTSTR)((LONG_PTR)p + ((nLength + 1) * sizeof(TCHAR)));
207 }
208
209 /* Allocate the actions buffer */
210 pActions = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nCount / 2 * sizeof(SC_ACTION));
211 if (pActions == NULL)
212 {
213 HeapFree(GetProcessHeap(), 0, pStringBuffer);
214 return FALSE;
215 }
216
217 /* Parse the string buffer */
218 nCount = 0;
219 p = pStringBuffer;
220 while (*p != _T('\0'))
221 {
222 nLength = _tcslen(p);
223
224 if (nCount % 2 == 0)
225 {
226 /* Action */
227 if (!lstrcmpi(p, _T("reboot")))
228 pActions[nCount / 2].Type = SC_ACTION_REBOOT;
229 else if (!lstrcmpi(p, _T("restart")))
230 pActions[nCount / 2].Type = SC_ACTION_RESTART;
231 else if (!lstrcmpi(p, _T("run")))
232 pActions[nCount / 2].Type = SC_ACTION_RUN_COMMAND;
233 else
234 break;
235 }
236 else
237 {
238 /* Delay */
239 pActions[nCount / 2].Delay = _tcstoul(p, NULL, 10);
240 if (pActions[nCount / 2].Delay == 0 && errno == ERANGE)
241 break;
242 }
243
244 p = (LPTSTR)((LONG_PTR)p + ((nLength + 1) * sizeof(TCHAR)));
245 nCount++;
246 }
247
248 /* Free the string buffer */
249 HeapFree(GetProcessHeap(), 0, pStringBuffer);
250
251 *pcActions = nCount / 2;
252 *ppActions = pActions;
253
254 return TRUE;
255 }
256
257
258 BOOL
ParseFailureArguments(IN LPCTSTR * ServiceArgs,IN INT ArgCount,OUT LPCTSTR * ppServiceName,OUT LPSERVICE_FAILURE_ACTIONS pFailureActions)259 ParseFailureArguments(
260 IN LPCTSTR *ServiceArgs,
261 IN INT ArgCount,
262 OUT LPCTSTR *ppServiceName,
263 OUT LPSERVICE_FAILURE_ACTIONS pFailureActions)
264 {
265 INT ArgIndex = 1;
266 LPCTSTR lpActions = NULL;
267 LPCTSTR lpReset = NULL;
268
269 if (ArgCount < 1)
270 return FALSE;
271
272 ZeroMemory(pFailureActions, sizeof(SERVICE_FAILURE_ACTIONS));
273
274 *ppServiceName = ServiceArgs[0];
275
276 ArgCount--;
277
278 while (ArgCount > 1)
279 {
280 if (!lstrcmpi(ServiceArgs[ArgIndex], _T("actions=")))
281 {
282 lpActions = (LPTSTR)ServiceArgs[ArgIndex + 1];
283 }
284 else if (!lstrcmpi(ServiceArgs[ArgIndex], _T("command=")))
285 {
286 pFailureActions->lpCommand = (LPTSTR)ServiceArgs[ArgIndex + 1];
287 }
288 else if (!lstrcmpi(ServiceArgs[ArgIndex], _T("reboot=")))
289 {
290 pFailureActions->lpRebootMsg = (LPTSTR)ServiceArgs[ArgIndex + 1];
291 }
292 else if (!lstrcmpi(ServiceArgs[ArgIndex], _T("reset=")))
293 {
294 lpReset = (LPTSTR)ServiceArgs[ArgIndex + 1];
295 }
296
297 ArgIndex += 2;
298 ArgCount -= 2;
299 }
300
301 if ((lpReset == NULL && lpActions != NULL) ||
302 (lpReset != NULL && lpActions == NULL))
303 {
304 _tprintf(_T("ERROR: The reset and actions options must be used simultaneously.\n\n"));
305 return FALSE;
306 }
307
308 if (lpReset != NULL)
309 {
310 if (!lstrcmpi(lpReset, _T("infinite")))
311 pFailureActions->dwResetPeriod = INFINITE;
312 else
313 pFailureActions->dwResetPeriod = _ttoi(lpReset);
314 }
315
316 if (lpActions != NULL)
317 {
318 if (!ParseFailureActions(lpActions,
319 &pFailureActions->cActions,
320 &pFailureActions->lpsaActions))
321 {
322 return FALSE;
323 }
324 }
325
326 return (ArgCount == 0);
327 }
328