xref: /reactos/base/applications/sc/misc.c (revision 58588b76)
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
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
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
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