From 7b494e5fe8f43b64215d3528dc4394bc52049d26 Mon Sep 17 00:00:00 2001 From: Ged Murphy Date: Thu, 27 Oct 2005 22:16:52 +0000 Subject: [PATCH] Add the beginnings of sc.exe Very early stages and completley untested. Not adding to build. Putting in SVN for the sole reason of keeping a development log svn path=/trunk/; revision=18812 --- reactos/subsys/system/sc/manage.c | 121 ++++++++++++++++++++++++++ reactos/subsys/system/sc/query.c | 107 +++++++++++++++++++++++ reactos/subsys/system/sc/sc.c | 138 ++++++++++++++++++++++++++++++ reactos/subsys/system/sc/sc.h | 21 +++++ reactos/subsys/system/sc/sc.rc | 4 + reactos/subsys/system/sc/sc.xml | 10 +++ reactos/subsys/system/sc/usage.c | 116 +++++++++++++++++++++++++ 7 files changed, 517 insertions(+) create mode 100644 reactos/subsys/system/sc/manage.c create mode 100644 reactos/subsys/system/sc/query.c create mode 100644 reactos/subsys/system/sc/sc.c create mode 100644 reactos/subsys/system/sc/sc.h create mode 100644 reactos/subsys/system/sc/sc.rc create mode 100644 reactos/subsys/system/sc/sc.xml create mode 100644 reactos/subsys/system/sc/usage.c diff --git a/reactos/subsys/system/sc/manage.c b/reactos/subsys/system/sc/manage.c new file mode 100644 index 00000000000..51d60639813 --- /dev/null +++ b/reactos/subsys/system/sc/manage.c @@ -0,0 +1,121 @@ +#include "sc.h" + +extern SC_HANDLE hSCManager; // declared in sc.c + +BOOL Start(INT ArgCount, TCHAR **Args) +{ + SC_HANDLE hSc; + LPCTSTR ServiceName = *Args++; + LPCTSTR *ServiceArgs = &*Args; + + hSc = OpenService(hSCManager, ServiceName, SERVICE_ALL_ACCESS); + + if (hSc == NULL) + { + dprintf("openService failed\n"); + ReportLastError(); + return FALSE; + } + + if (! StartService(hSc, ArgCount, ServiceArgs)) + { + dprintf("DeleteService failed\n"); + ReportLastError(); + return FALSE; + } + + CloseServiceHandle(hSc); + return TRUE; + +} + + +BOOL Create(TCHAR **Args) +{ + SC_HANDLE hSc; + LPCTSTR Name = *Args; + LPCTSTR BinaryPathName = *++Args; + + + hSc = CreateService(hSCManager, + Name, + Name, + SERVICE_ALL_ACCESS, + SERVICE_WIN32_OWN_PROCESS, + SERVICE_DEMAND_START, + SERVICE_ERROR_NORMAL, + BinaryPathName, + NULL, + NULL, + NULL, + NULL, + NULL); + + if (hSc == NULL) + { + dprintf("CreateService failed (%d)\n"); + ReportLastError(); + return FALSE; + } + else + { + CloseServiceHandle(hSc); + return TRUE; + } +} + +BOOL Delete(TCHAR **Args) +{ + SC_HANDLE hSc; + LPCTSTR ServiceName = *Args; + + hSc = OpenService(hSCManager, ServiceName, DELETE); + + if (hSc == NULL) + { + dprintf("openService failed\n"); + ReportLastError(); + return FALSE; + } + + if (! DeleteService(hSc)) + { + dprintf("DeleteService failed\n"); + ReportLastError(); + return FALSE; + } + + CloseServiceHandle(hSc); + return TRUE; +} + + +BOOL Control(DWORD Control, TCHAR **Args) +{ + SC_HANDLE hSc; + SERVICE_STATUS Status; + LPCTSTR ServiceName = *Args; + + + hSc = OpenService(hSCManager, ServiceName, DELETE); + + if (hSc == NULL) + { + dprintf("openService failed\n"); + ReportLastError(); + return FALSE; + } + + if (! ControlService(hSc, Control, &Status)) + { + dprintf("controlService failed\n"); + ReportLastError(); + return FALSE; + } + + CloseServiceHandle(hSc); + return TRUE; + +} + + diff --git a/reactos/subsys/system/sc/query.c b/reactos/subsys/system/sc/query.c new file mode 100644 index 00000000000..c9ea1ac8388 --- /dev/null +++ b/reactos/subsys/system/sc/query.c @@ -0,0 +1,107 @@ +#include "sc.h" + +extern SC_HANDLE hSCManager; /* declared in sc.c */ + +BOOL +Query(TCHAR **Args, BOOL bExtended) +{ + SC_HANDLE hSc; + ENUM_SERVICE_STATUS_PROCESS *pServiceStatus = NULL; + DWORD BufSize = 0; + DWORD BytesNeeded; + DWORD NumServices; + DWORD ResumeHandle; + INT i; + + /* determine required buffer size */ + EnumServicesStatusEx(hSCManager, + SC_ENUM_PROCESS_INFO, + SERVICE_DRIVER | SERVICE_WIN32, + SERVICE_STATE_ALL, + (LPBYTE)pServiceStatus, + BufSize, + &BytesNeeded, + &NumServices, + &ResumeHandle, + 0); + + /* exit on failure */ + if (GetLastError() != ERROR_MORE_DATA) + { + ReportLastError(); + return FALSE; + } + + /* reserve memory for service info array */ + pServiceStatus = (ENUM_SERVICE_STATUS_PROCESS *) malloc(BytesNeeded); + + /* fill array with service info */ + if (! EnumServicesStatusEx(hSCManager, + SC_ENUM_PROCESS_INFO, + SERVICE_DRIVER | SERVICE_WIN32, + SERVICE_STATE_ALL, + (LPBYTE)pServiceStatus, + BufSize, + &BytesNeeded, + &NumServices, + &ResumeHandle, + 0)) + { + dprintf("Call to EnumServicesStatusEx failed : "); + ReportLastError(); + return FALSE; + } +/* + for (i=0; idwServiceType == SERVICE_WIN32 && + pServiceStatus[i]->dwServiceState == SERVICE_ACTIVE) + PrintService(pServiceStatus[i], bExtended); + continue; + } + + if(_tcsicmp(Args[0], _T("type=")) + + else if(_tcsicmp(Args[0], _T("state=")) + + else if(_tcsicmp(Args[0], _T("bufsize=")) + + else if(_tcsicmp(Args[0], _T("ri=")) + + else if(_tcsicmp(Args[0], _T("group=")) + +*/ + + +} + + +VOID +PrintService(ENUM_SERVICE_STATUS_PROCESS *pServiceStatus, + BOOL bExtended) +{ + dprintf("SERVICE_NAME: %s\n", pServiceStatus->lpServiceName); + dprintf("DISPLAY_NAME: %s\n", pServiceStatus->lpDisplayName); + dprintf("TYPE : %lu\n", + pServiceStatus->ServiceStatusProcess.dwServiceType); + dprintf("STATE : %lu\n", + pServiceStatus->ServiceStatusProcess.dwCurrentState); + // (STOPPABLE,NOT_PAUSABLE,ACCEPTS_SHUTDOWN) + dprintf("WIN32_EXIT_CODE : %lu \n", + pServiceStatus->ServiceStatusProcess.dwWin32ExitCode); + dprintf("SERVICE_EXIT_CODE : %lu \n", + pServiceStatus->ServiceStatusProcess.dwServiceSpecificExitCode); + dprintf("CHECKPOINT : %lu\n", + pServiceStatus->ServiceStatusProcess.dwCheckPoint); + dprintf("WAIT_HINT : %lu\n", + pServiceStatus->ServiceStatusProcess.dwWaitHint); + if (bExtended) + { + dprintf("PID : %lu\n", + pServiceStatus->ServiceStatusProcess.dwProcessId); + dprintf("FLAGS : %lu\n", + pServiceStatus->ServiceStatusProcess.dwServiceFlags); + } +} diff --git a/reactos/subsys/system/sc/sc.c b/reactos/subsys/system/sc/sc.c new file mode 100644 index 00000000000..dd44f5cbf8f --- /dev/null +++ b/reactos/subsys/system/sc/sc.c @@ -0,0 +1,138 @@ +#include "sc.h" + +HANDLE OutputHandle; +HANDLE InputHandle; + +SC_HANDLE hSCManager; + +VOID dprintf(TCHAR* fmt, ...) +{ + va_list args; + char buffer[255]; + + va_start(args, fmt); + wvsprintfA(buffer, fmt, args); + WriteConsole(OutputHandle, buffer, lstrlenA(buffer), NULL, NULL); + va_end(args); +} + +DWORD ReportLastError(VOID) +{ + LPVOID lpMsgBuf; + DWORD RetVal; + + DWORD ErrorCode = GetLastError(); + if (ErrorCode != ERROR_SUCCESS) + { + if ((RetVal = FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + ErrorCode, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */ + (LPTSTR) &lpMsgBuf, + 0, + NULL ))) + { + _tprintf(_T("%s"), (LPTSTR)lpMsgBuf); + + LocalFree(lpMsgBuf); + /* return number of TCHAR's stored in output buffer + * excluding '\0' - as FormatMessage does*/ + return RetVal; + } + } + return 0; +} + + +INT ScControl(LPTSTR MachineName, LPCTSTR Command, TCHAR **Args) +{ + + if (MachineName) + { + dprintf("Remote service control is not yet implemented\n"); + return 2; + } + + hSCManager = OpenSCManager(MachineName, NULL, SC_MANAGER_ALL_ACCESS); + if (hSCManager == NULL) + { + dprintf("[SC] OpenSCManager FAILED \n"); + ReportLastError(); + return -1; + } + + + if (_tcsicmp(Command, _T("query")) == 0) + Query(Args, FALSE); + + else if (_tcsicmp(Command, _T("queryex")) == 0) + Query(Args, TRUE); + + else if (_tcsicmp(Command, _T("start")) == 0) + { + /*if (! **Args) + StartUsage(); + else + Start(Args);*/ + } + else if (_tcsicmp(Command, _T("pause")) == 0) + Control(SERVICE_CONTROL_PAUSE, ++Args); + + else if (_tcsicmp(Command, _T("interrogate")) == 0) + Control(SERVICE_CONTROL_INTERROGATE, ++Args); + + else if (_tcsicmp(Command, _T("interrogate")) == 0) + Control(SERVICE_CONTROL_INTERROGATE, ++Args); + + else if (_tcsicmp(Command, _T("continue")) == 0) + Control(SERVICE_CONTROL_CONTINUE, ++Args); + + else if (_tcsicmp(Command, _T("delete")) == 0) + Delete(Args); + + else if (_tcsicmp(Command, _T("create")) == 0) + Create(Args); + + else if (_tcsicmp(Command, _T("control")) == 0) + Control((DWORD)NULL, Args); + + return 0; +} + + +int main(int argc, char* argv[]) +{ + LPTSTR MachineName = NULL; // remote machine + LPCTSTR Command = argv[1]; // sc command + TCHAR **Args = NULL; // rest of args + + /* initialize standard input / output and get handles */ + AllocConsole(); + InputHandle = GetStdHandle(STD_INPUT_HANDLE); + OutputHandle = GetStdHandle(STD_OUTPUT_HANDLE); + + if (argc < 2) + return MainUsage(); + + /* get server name */ + if ((argv[1][0] == '\\') && (argv[1][1] == '\\')) + { + if (argc < 3) + return MainUsage(); + + _tcscpy(MachineName, argv[1]); + Command = argv[2]; + Args = &argv[3]; + return ScControl(MachineName, Command, Args); + } + else + { + Args = &argv[2]; + return ScControl(MachineName, Command, Args); + } + + return MainUsage(); +} diff --git a/reactos/subsys/system/sc/sc.h b/reactos/subsys/system/sc/sc.h new file mode 100644 index 00000000000..c88a05b12c9 --- /dev/null +++ b/reactos/subsys/system/sc/sc.h @@ -0,0 +1,21 @@ +#include +#include +#include + +DWORD ReportLastError(VOID); +VOID dprintf(TCHAR* fmt, ...); + +INT MainUsage(VOID); +INT StartUsage(VOID); +INT PauseUsage(VOID); +INT InterrogateUsage(VOID); +INT ContinueUsage(VOID); +INT StopUsage(VOID); +INT ConfigUsage(VOID); +INT DescriptionUsage(VOID); + +BOOL Query(TCHAR **Args, BOOL bExtended); +BOOL Start(INT ArgCount, TCHAR **Args); +BOOL Create(TCHAR **Args); +BOOL Delete(TCHAR **Args); +BOOL Control(DWORD Control, TCHAR **Args); diff --git a/reactos/subsys/system/sc/sc.rc b/reactos/subsys/system/sc/sc.rc new file mode 100644 index 00000000000..86777430848 --- /dev/null +++ b/reactos/subsys/system/sc/sc.rc @@ -0,0 +1,4 @@ +#define REACTOS_STR_FILE_DESCRIPTION "Services control application\0" +#define REACTOS_STR_INTERNAL_NAME "sc\0" +#define REACTOS_STR_ORIGINAL_FILENAME "sc.exe\0" +#include diff --git a/reactos/subsys/system/sc/sc.xml b/reactos/subsys/system/sc/sc.xml new file mode 100644 index 00000000000..7f0dad68622 --- /dev/null +++ b/reactos/subsys/system/sc/sc.xml @@ -0,0 +1,10 @@ + + + + kernel32 + sc.c + manage.c + query.c + usage.c + sc.rc + diff --git a/reactos/subsys/system/sc/usage.c b/reactos/subsys/system/sc/usage.c new file mode 100644 index 00000000000..f4d61a4d15d --- /dev/null +++ b/reactos/subsys/system/sc/usage.c @@ -0,0 +1,116 @@ +#include "sc.h" + +INT MainUsage(VOID) +{ + dprintf("DESCRIPTION:\n"); + dprintf("\tSC is a command line program used for communicating with\n"); + dprintf("\tthe Service Control Manager and its services.\n"); + dprintf("USAGE:\n"); + dprintf("\tsc [command] [service name] ...\n"); + + dprintf("\tThe optional parameter has the form \"\\ServerName\"\n"); + dprintf("\tFurther help on commands can be obtained by typing: \"sc [command]\"\n"); + dprintf("\tService Commands:\n"); + dprintf("\t query : Queries the status for a service, or\n"); + dprintf("\t enumerates the status for types of services.\n"); + dprintf("\t queryex : Queries the extended status for a service, or\n"); +// dprintf("\t enumerates the status for types of services.\n"); + dprintf("\t start : Starts a service.\n"); + dprintf("\t pause : Sends a PAUSE control request to a service.\n"); + dprintf("\t interrogate : Sends a INTERROGATE control request to a service.\n"); +// dprintf("\t continue : Sends a CONTINUE control request to a service.\n"); + dprintf("\t stop : Sends a STOP request to a service.\n"); +// dprintf("\t config : Changes the configuration of a service (persistant).\n"); +// dprintf("\t description : Changes the description of a service.\n"); +// dprintf("\t failure : Changes the actions taken by a service upon failure.\n"); +// dprintf("\t qc : Queries the configuration information for a service.\n"); +// dprintf("\t qdescription : Queries the description for a service.\n"); +// dprintf("\t qfailure : Queries the actions taken by a service upon failure.\n"); + dprintf("\t delete : Deletes a service (from the registry).\n"); + dprintf("\t create : Creates a service. (adds it to the registry).\n"); + dprintf("\t control : Sends a control to a service.\n"); +// dprintf("\t sdshow : Displays a service's security descriptor.\n"); +// dprintf("\t sdset : Sets a service's security descriptor.\n"); +// dprintf("\t GetDisplayName : Gets the DisplayName for a service.\n"); +// dprintf("\t GetKeyName : Gets the ServiceKeyName for a service.\n"); +// dprintf("\t EnumDepend : Enumerates Service Dependencies.\n"); +// dprintf("\n"); +// dprintf("\tService Name Independant Commands:\n"); +// dprintf("\t boot : (ok | bad) Indicates whether the last boot should\n"); +// dprintf("\t be saved as the last-known-good boot configuration\n"); +// dprintf("\t Lock : Locks the SCM Database\n"); +// dprintf("\t QueryLock : Queries the LockStatus for the SCM Database\n"); + + return 0; +} + + +INT StartUsage(VOID) +{ + dprintf("DESCRIPTION:\n"); + dprintf(" Starts a service running.\n"); + dprintf("USAGE:\n"); + dprintf(" sc start [service name] ...\n"); + + return 0; +} + + +INT PauseUsage(VOID) +{ + dprintf("DESCRIPTION:\n"); + dprintf(" Sends a PAUSE control request to a service.\n"); + dprintf("USAGE:\n"); + dprintf(" sc pause [service name]\n"); + + return 0; +} + +INT InterrogateUsage(VOID) +{ + dprintf("DESCRIPTION:\n"); + dprintf(" Sends an INTERROGATE control request to a service.\n"); + dprintf("USAGE:\n"); + dprintf(" sc interrogate [service name]\n"); + + return 0; +} + + +INT ContinueUsage(VOID) +{ + dprintf("DESCRIPTION:\n"); + dprintf(" Sends an CONTINUE control request to a service.\n"); + dprintf("USAGE:\n"); + dprintf(" sc continue [service name]\n"); + + return 0; +} + +INT StopUsage(VOID) +{ + dprintf("DESCRIPTION:\n"); + dprintf(" Sends an STOP control request to a service.\n"); + dprintf("USAGE:\n"); + dprintf(" sc stop [service name]\n"); + + return 0; +} + +INT ConfigUsage(VOID) +{ + dprintf("not yet implemented\n"); + + return 0; +} + + +INT DescriptionUsage(VOID) +{ + dprintf("DESCRIPTION:\n"); + dprintf(" Sets the description string for a service.\n"); + dprintf("USAGE:\n"); + dprintf(" sc description [service name]\n"); + + return 0; +} -- 2.17.1