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