mirror of
https://github.com/reactos/reactos.git
synced 2024-08-26 13:18:51 +00:00
328 lines
9 KiB
C
328 lines
9 KiB
C
/*
|
|
* 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 <gedmurphy@gmail.com>
|
|
* Roel Messiant <roelmessiant@gmail.com>
|
|
*/
|
|
|
|
#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);
|
|
}
|