/* * PROJECT: ReactOS Services * LICENSE: GPL - See COPYING in the top level directory * FILE: base/applications/sc/misc.c * PURPOSE: Various functions * COPYRIGHT: Copyright 2005 - 2006 Ged Murphy * Roel Messiant */ #include "sc.h" typedef struct { LPCTSTR lpOption; DWORD dwValue; } OPTION_INFO; static const OPTION_INFO TypeOpts[] = { { _T("own"), SERVICE_WIN32_OWN_PROCESS }, { _T("share"), SERVICE_WIN32_SHARE_PROCESS }, { _T("interact"), SERVICE_INTERACTIVE_PROCESS }, { _T("kernel"), SERVICE_KERNEL_DRIVER }, { _T("filesys"), SERVICE_FILE_SYSTEM_DRIVER }, { _T("rec"), SERVICE_RECOGNIZER_DRIVER } }; static const OPTION_INFO StartOpts[] = { { _T("boot"), SERVICE_BOOT_START }, { _T("system"), SERVICE_SYSTEM_START }, { _T("auto"), SERVICE_AUTO_START }, { _T("demand"), SERVICE_DEMAND_START }, { _T("disabled"), SERVICE_DISABLED } }; static const OPTION_INFO ErrorOpts[] = { { _T("normal"), SERVICE_ERROR_NORMAL }, { _T("severe"), SERVICE_ERROR_SEVERE }, { _T("critical"), SERVICE_ERROR_CRITICAL }, { _T("ignore"), SERVICE_ERROR_IGNORE } }; static const OPTION_INFO TagOpts[] = { { _T("yes"), TRUE }, { _T("no"), FALSE } }; BOOL ParseCreateConfigArguments( LPCTSTR *ServiceArgs, INT ArgCount, BOOL bChangeService, OUT LPSERVICE_CREATE_INFO lpServiceInfo) { INT i, ArgIndex = 1; if (ArgCount < 1) return FALSE; ZeroMemory(lpServiceInfo, sizeof(SERVICE_CREATE_INFO)); if (bChangeService) { lpServiceInfo->dwServiceType = SERVICE_NO_CHANGE; lpServiceInfo->dwStartType = SERVICE_NO_CHANGE; lpServiceInfo->dwErrorControl = SERVICE_NO_CHANGE; } lpServiceInfo->lpServiceName = ServiceArgs[0]; ArgCount--; while (ArgCount > 1) { if (!lstrcmpi(ServiceArgs[ArgIndex], _T("type="))) { for (i = 0; i < sizeof(TypeOpts) / sizeof(TypeOpts[0]); i++) if (!lstrcmpi(ServiceArgs[ArgIndex + 1], TypeOpts[i].lpOption)) { if (lpServiceInfo->dwServiceType == SERVICE_NO_CHANGE) lpServiceInfo->dwServiceType = TypeOpts[i].dwValue; else lpServiceInfo->dwServiceType |= TypeOpts[i].dwValue; break; } if (i == sizeof(TypeOpts) / sizeof(TypeOpts[0])) break; } else if (!lstrcmpi(ServiceArgs[ArgIndex], _T("start="))) { for (i = 0; i < sizeof(StartOpts) / sizeof(StartOpts[0]); i++) if (!lstrcmpi(ServiceArgs[ArgIndex + 1], StartOpts[i].lpOption)) { lpServiceInfo->dwStartType = StartOpts[i].dwValue; break; } if (i == sizeof(StartOpts) / sizeof(StartOpts[0])) break; } else if (!lstrcmpi(ServiceArgs[ArgIndex], _T("error="))) { for (i = 0; i < sizeof(ErrorOpts) / sizeof(ErrorOpts[0]); i++) if (!lstrcmpi(ServiceArgs[ArgIndex + 1], ErrorOpts[i].lpOption)) { lpServiceInfo->dwErrorControl = ErrorOpts[i].dwValue; break; } if (i == sizeof(ErrorOpts) / sizeof(ErrorOpts[0])) break; } else if (!lstrcmpi(ServiceArgs[ArgIndex], _T("tag="))) { for (i = 0; i < sizeof(TagOpts) / sizeof(TagOpts[0]); i++) if (!lstrcmpi(ServiceArgs[ArgIndex + 1], TagOpts[i].lpOption)) { lpServiceInfo->bTagId = TagOpts[i].dwValue; break; } if (i == sizeof(TagOpts) / sizeof(TagOpts[0])) break; } else if (!lstrcmpi(ServiceArgs[ArgIndex], _T("binpath="))) { lpServiceInfo->lpBinaryPathName = ServiceArgs[ArgIndex + 1]; } else if (!lstrcmpi(ServiceArgs[ArgIndex], _T("group="))) { lpServiceInfo->lpLoadOrderGroup = ServiceArgs[ArgIndex + 1]; } else if (!lstrcmpi(ServiceArgs[ArgIndex], _T("depend="))) { lpServiceInfo->lpDependencies = ServiceArgs[ArgIndex + 1]; } else if (!lstrcmpi(ServiceArgs[ArgIndex], _T("obj="))) { lpServiceInfo->lpServiceStartName = ServiceArgs[ArgIndex + 1]; } else if (!lstrcmpi(ServiceArgs[ArgIndex], _T("displayname="))) { lpServiceInfo->lpDisplayName = ServiceArgs[ArgIndex + 1]; } else if (!lstrcmpi(ServiceArgs[ArgIndex], _T("password="))) { lpServiceInfo->lpPassword = ServiceArgs[ArgIndex + 1]; } ArgIndex += 2; ArgCount -= 2; } return (ArgCount == 0); } BOOL ParseFailureActions( IN LPCTSTR lpActions, OUT DWORD *pcActions, OUT SC_ACTION **ppActions) { SC_ACTION *pActions = NULL; LPTSTR pStringBuffer = NULL; LPTSTR p; INT_PTR nLength; INT nCount = 0; *pcActions = 0; *ppActions = NULL; nLength = _tcslen(lpActions); /* Allocate the string buffer */ pStringBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (nLength + 2) * sizeof(TCHAR)); if (pStringBuffer == NULL) { return FALSE; } /* Copy the actions string into the string buffer */ CopyMemory(pStringBuffer, lpActions, nLength * sizeof(TCHAR)); /* Replace all slashes by null characters */ p = pStringBuffer; while (*p != _T('\0')) { if (*p == _T('/')) *p = _T('\0'); p++; } /* Count the arguments in the buffer */ p = pStringBuffer; while (*p != _T('\0')) { nCount++; nLength = _tcslen(p); p = (LPTSTR)((LONG_PTR)p + ((nLength + 1) * sizeof(TCHAR))); } /* Allocate the actions buffer */ pActions = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nCount / 2 * sizeof(SC_ACTION)); if (pActions == NULL) { HeapFree(GetProcessHeap(), 0, pStringBuffer); return FALSE; } /* Parse the string buffer */ nCount = 0; p = pStringBuffer; while (*p != _T('\0')) { nLength = _tcslen(p); if (nCount % 2 == 0) { /* Action */ if (!lstrcmpi(p, _T("reboot"))) pActions[nCount / 2].Type = SC_ACTION_REBOOT; else if (!lstrcmpi(p, _T("restart"))) pActions[nCount / 2].Type = SC_ACTION_RESTART; else if (!lstrcmpi(p, _T("run"))) pActions[nCount / 2].Type = SC_ACTION_RUN_COMMAND; else break; } else { /* Delay */ pActions[nCount / 2].Delay = _tcstoul(p, NULL, 10); if (pActions[nCount / 2].Delay == 0 && errno == ERANGE) break; } p = (LPTSTR)((LONG_PTR)p + ((nLength + 1) * sizeof(TCHAR))); nCount++; } /* Free the string buffer */ HeapFree(GetProcessHeap(), 0, pStringBuffer); *pcActions = nCount / 2; *ppActions = pActions; return TRUE; } BOOL ParseFailureArguments( IN LPCTSTR *ServiceArgs, IN INT ArgCount, OUT LPCTSTR *ppServiceName, OUT LPSERVICE_FAILURE_ACTIONS pFailureActions) { INT ArgIndex = 1; LPCTSTR lpActions = NULL; LPCTSTR lpReset = NULL; if (ArgCount < 1) return FALSE; ZeroMemory(pFailureActions, sizeof(SERVICE_FAILURE_ACTIONS)); *ppServiceName = ServiceArgs[0]; ArgCount--; while (ArgCount > 1) { if (!lstrcmpi(ServiceArgs[ArgIndex], _T("actions="))) { lpActions = (LPTSTR)ServiceArgs[ArgIndex + 1]; } else if (!lstrcmpi(ServiceArgs[ArgIndex], _T("command="))) { pFailureActions->lpCommand = (LPTSTR)ServiceArgs[ArgIndex + 1]; } else if (!lstrcmpi(ServiceArgs[ArgIndex], _T("reboot="))) { pFailureActions->lpRebootMsg = (LPTSTR)ServiceArgs[ArgIndex + 1]; } else if (!lstrcmpi(ServiceArgs[ArgIndex], _T("reset="))) { lpReset = (LPTSTR)ServiceArgs[ArgIndex + 1]; } ArgIndex += 2; ArgCount -= 2; } if ((lpReset == NULL && lpActions != NULL) || (lpReset != NULL && lpActions == NULL)) { _tprintf(_T("ERROR: The reset and actions options must be used simultaneously.\n\n")); return FALSE; } if (lpReset != NULL) { if (!lstrcmpi(lpReset, _T("infinite"))) pFailureActions->dwResetPeriod = INFINITE; else pFailureActions->dwResetPeriod = _ttoi(lpReset); } if (lpActions != NULL) { if (!ParseFailureActions(lpActions, &pFailureActions->cActions, &pFailureActions->lpsaActions)) { return FALSE; } } return (ArgCount == 0); }