diff --git a/reactos/base/applications/sc/CMakeLists.txt b/reactos/base/applications/sc/CMakeLists.txt index 531109215f0..e9aa7add0c3 100644 --- a/reactos/base/applications/sc/CMakeLists.txt +++ b/reactos/base/applications/sc/CMakeLists.txt @@ -6,6 +6,7 @@ list(APPEND SOURCE control.c create.c delete.c + depend.c description.c failure.c misc.c diff --git a/reactos/base/applications/sc/depend.c b/reactos/base/applications/sc/depend.c new file mode 100644 index 00000000000..67035332cbd --- /dev/null +++ b/reactos/base/applications/sc/depend.c @@ -0,0 +1,100 @@ +/* + * PROJECT: ReactOS Services + * LICENSE: GPL - See COPYING in the top level directory + * FILE: base/applications/sc/depend.c + * PURPOSE: + * COPYRIGHT: Copyright 2016 Eric Kohl + * + */ + +#include "sc.h" + +BOOL EnumDepend(LPCTSTR ServiceName) +{ + SC_HANDLE hManager = NULL; + SC_HANDLE hService = NULL; + BOOL bResult = TRUE; + DWORD BufferSize = 0; + DWORD EntriesRead = 0; + LPENUM_SERVICE_STATUS pBuffer = NULL; + DWORD i; + + hManager = OpenSCManager(NULL, + NULL, + SC_MANAGER_CONNECT); + if (hManager == NULL) + { + _tprintf(_T("[SC] OpenSCManager FAILED %lu:\n\n"), GetLastError()); + bResult = FALSE; + goto done; + } + + hService = OpenService(hManager, ServiceName, SERVICE_ENUMERATE_DEPENDENTS); + if (hService == NULL) + { + _tprintf(_T("[SC] OpenService FAILED %lu:\n\n"), GetLastError()); + bResult = FALSE; + goto done; + } + + if (!EnumDependentServices(hService, + SERVICE_STATE_ALL, + NULL, + 0, + &BufferSize, + &EntriesRead)) + { + if (BufferSize == 0) + { + _tprintf(_T("[SC] EnumDependentServices FAILED %lu:\n\n"), GetLastError()); + bResult = FALSE; + goto done; + } + } + + pBuffer = HeapAlloc(GetProcessHeap(), 0, BufferSize); + if (pBuffer == NULL) + { + SetLastError(ERROR_OUTOFMEMORY); + _tprintf(_T("[SC] HeapAlloc FAILED %lu:\n\n"), GetLastError()); + bResult = FALSE; + goto done; + } + + if (!EnumDependentServices(hService, + SERVICE_STATE_ALL, + pBuffer, + BufferSize, + &BufferSize, + &EntriesRead)) + { + _tprintf(_T("[SC] EnumDependentServices FAILED %lu:\n\n"), GetLastError()); + bResult = FALSE; + goto done; + } + + _tprintf(_T("Enum: entriesRead = %lu\n"), EntriesRead); + + for (i = 0; i < EntriesRead; i++) + { + _tprintf(_T("\n")); + _tprintf(_T("SERVICE_NAME: %s\n"), pBuffer[i].lpServiceName); + _tprintf(_T("DISPLAY_NAME: %s\n"), pBuffer[i].lpDisplayName); + PrintServiceStatus(&pBuffer[i].ServiceStatus); + } + +done: + if (bResult == FALSE) + ReportLastError(); + + if (pBuffer != NULL) + HeapFree(GetProcessHeap(), 0, pBuffer); + + if (hService) + CloseServiceHandle(hService); + + if (hManager) + CloseServiceHandle(hManager); + + return bResult; +} diff --git a/reactos/base/applications/sc/print.c b/reactos/base/applications/sc/print.c index ad04be847fc..7c3a26a2fd2 100644 --- a/reactos/base/applications/sc/print.c +++ b/reactos/base/applications/sc/print.c @@ -102,3 +102,85 @@ PrintService(LPCTSTR lpServiceName, _tprintf(_T("\n")); } + + +VOID +PrintServiceStatus( + LPSERVICE_STATUS pStatus) +{ + _tprintf(_T("\tTYPE : %x "), + (unsigned int)pStatus->dwServiceType); + switch (pStatus->dwServiceType) + { + case SERVICE_KERNEL_DRIVER: + _tprintf(_T("KERNEL_DRIVER\n")); + break; + + case SERVICE_FILE_SYSTEM_DRIVER: + _tprintf(_T("FILE_SYSTEM_DRIVER\n")); + break; + + case SERVICE_WIN32_OWN_PROCESS: + _tprintf(_T("WIN32_OWN_PROCESS\n")); + break; + + case SERVICE_WIN32_SHARE_PROCESS: + _tprintf(_T("WIN32_SHARE_PROCESS\n")); + break; + + case SERVICE_WIN32_OWN_PROCESS + SERVICE_INTERACTIVE_PROCESS: + _tprintf(_T("WIN32_OWN_PROCESS (interactive)\n")); + break; + + case SERVICE_WIN32_SHARE_PROCESS + SERVICE_INTERACTIVE_PROCESS: + _tprintf(_T("WIN32_SHARE_PROCESS (interactive)\n")); + break; + + default : _tprintf(_T("\n")); break; + } + + _tprintf(_T("\tSTATE : %x "), + (unsigned int)pStatus->dwCurrentState); + + switch (pStatus->dwCurrentState) + { + case 1 : _tprintf(_T("STOPPED\n")); break; + case 2 : _tprintf(_T("START_PENDING\n")); break; + case 3 : _tprintf(_T("STOP_PENDING\n")); break; + case 4 : _tprintf(_T("RUNNING\n")); break; + case 5 : _tprintf(_T("CONTINUE_PENDING\n")); break; + case 6 : _tprintf(_T("PAUSE_PENDING\n")); break; + case 7 : _tprintf(_T("PAUSED\n")); break; + default : _tprintf(_T("\n")); break; + } + + _tprintf(_T("\t\t\t\t(")); + + if (pStatus->dwControlsAccepted & SERVICE_ACCEPT_STOP) + _tprintf(_T("STOPPABLE,")); + else + _tprintf(_T("NOT_STOPPABLE,")); + + if (pStatus->dwControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE) + _tprintf(_T("PAUSABLE,")); + else + _tprintf(_T("NOT_PAUSABLE,")); + + if (pStatus->dwControlsAccepted & SERVICE_ACCEPT_SHUTDOWN) + _tprintf(_T("ACCEPTS_SHUTDOWN")); + else + _tprintf(_T("IGNORES_SHUTDOWN")); + + _tprintf(_T(")\n")); + + _tprintf(_T("\tWIN32_EXIT_CODE : %u (0x%x)\n"), + (unsigned int)pStatus->dwWin32ExitCode, + (unsigned int)pStatus->dwWin32ExitCode); + _tprintf(_T("\tSERVICE_EXIT_CODE : %u (0x%x)\n"), + (unsigned int)pStatus->dwServiceSpecificExitCode, + (unsigned int)pStatus->dwServiceSpecificExitCode); + _tprintf(_T("\tCHECKPOINT : 0x%x\n"), + (unsigned int)pStatus->dwCheckPoint); + _tprintf(_T("\tWAIT_HINT : 0x%x\n"), + (unsigned int)pStatus->dwWaitHint); +} \ No newline at end of file diff --git a/reactos/base/applications/sc/sc.c b/reactos/base/applications/sc/sc.c index f58982c2242..e2b75083e6c 100644 --- a/reactos/base/applications/sc/sc.c +++ b/reactos/base/applications/sc/sc.c @@ -296,6 +296,18 @@ ScControl(LPCTSTR Server, // remote machine name else GetKeyNameUsage(); } + else if (!lstrcmpi(Command, _T("EnumDepend"))) + { + if (ArgCount > 0) + { + ServiceName = *ServiceArgs++; + ArgCount--; + + EnumDepend(ServiceName); + } + else + EnumDependUsage(); + } else { MainUsage(); diff --git a/reactos/base/applications/sc/sc.h b/reactos/base/applications/sc/sc.h index a3f163666d4..496734ec6ae 100644 --- a/reactos/base/applications/sc/sc.h +++ b/reactos/base/applications/sc/sc.h @@ -47,9 +47,11 @@ BOOL QueryFailure(LPCTSTR ServiceName); BOOL SetFailure(LPCTSTR *ServiceArgs, INT ArgCount); BOOL GetDisplayName(LPCTSTR ServiceName); BOOL GetKeyName(LPCTSTR ServiceName); +BOOL EnumDepend(LPCTSTR ServiceName); /* print and error functions */ VOID PrintService(LPCTSTR ServiceName, LPSERVICE_STATUS_PROCESS pStatus, BOOL bExtended); +VOID PrintServiceStatus(LPSERVICE_STATUS pStatus); VOID ReportLastError(VOID); /* misc.c */ @@ -87,5 +89,6 @@ VOID SetConfigUsage(VOID); VOID SetFailureUsage(VOID); VOID GetDisplayNameUsage(VOID); VOID GetKeyNameUsage(VOID); +VOID EnumDependUsage(VOID); #endif /* _SC_PCH_ */ diff --git a/reactos/base/applications/sc/usage.c b/reactos/base/applications/sc/usage.c index 405892e95aa..445863df49a 100644 --- a/reactos/base/applications/sc/usage.c +++ b/reactos/base/applications/sc/usage.c @@ -45,8 +45,8 @@ VOID MainUsage(VOID) _T("\t sdshow : Displays a service's security descriptor.\n") _T("\t sdset : Sets a service's security descriptor.\n") _T("\t GetDisplayName : Gets the DisplayName for a service.\n") - _T("\t GetKeyName : Gets the ServiceKeyName for a service.\n")); -// "\t EnumDepend : Enumerates Service Dependencies.\n") + _T("\t GetKeyName : Gets the ServiceKeyName for a service.\n") + _T("\t EnumDepend : Enumerates Service Dependencies.\n")); // "\n") // "\tService Name Independant Commands:\n") // "\t boot : (ok | bad) Indicates whether the last boot should\n") @@ -279,3 +279,11 @@ VOID GetKeyNameUsage(VOID) _T("USAGE:\n") _T(" sc GetKeyName \n")); } + +VOID EnumDependUsage(VOID) +{ + _tprintf(_T("DESCRIPTION:\n") + _T(" Enumerates te Services that are dependent on this one.\n") + _T("USAGE:\n") + _T(" sc EnumDepend \n")); +}