diff --git a/reactos/base/applications/sc/CMakeLists.txt b/reactos/base/applications/sc/CMakeLists.txt index adaa05e1d47..3b5252d86d8 100644 --- a/reactos/base/applications/sc/CMakeLists.txt +++ b/reactos/base/applications/sc/CMakeLists.txt @@ -6,6 +6,9 @@ list(APPEND SOURCE create.c delete.c print.c + qc.c + qdescription.c + qfailure.c query.c sc.c sdset.c diff --git a/reactos/base/applications/sc/qc.c b/reactos/base/applications/sc/qc.c new file mode 100644 index 00000000000..b54cf5f67ff --- /dev/null +++ b/reactos/base/applications/sc/qc.c @@ -0,0 +1,190 @@ +/* + * PROJECT: ReactOS Services + * LICENSE: GPL - See COPYING in the top level directory + * FILE: base/applications/sc/qc.c + * PURPOSE: Show the service configuration + * COPYRIGHT: Copyright 2016 Eric Kohl + * + */ + +#include "sc.h" + +BOOL QueryConfig(LPCTSTR ServiceName) +{ + SC_HANDLE hManager = NULL; + SC_HANDLE hService = NULL; + BOOL bResult = TRUE; + DWORD cbBytesNeeded = 0; + LPQUERY_SERVICE_CONFIG pServiceConfig = NULL; + LPWSTR lpPtr; + INT nLen, i; + +#ifdef SCDBG + _tprintf(_T("service to show configuration - %s\n\n"), ServiceName); +#endif + + hManager = OpenSCManager(NULL, + NULL, + SC_MANAGER_CONNECT); + if (hManager == NULL) + { + bResult = FALSE; + goto done; + } + + hService = OpenService(hManager, ServiceName, SERVICE_QUERY_CONFIG); + if (hService == NULL) + { + bResult = FALSE; + goto done; + } + + if (!QueryServiceConfig(hService, + NULL, + 0, + &cbBytesNeeded)) + { + if (cbBytesNeeded == 0) + { + bResult = FALSE; + goto done; + } + } + + pServiceConfig = HeapAlloc(GetProcessHeap(), 0, cbBytesNeeded); + if (pServiceConfig == NULL) + { + SetLastError(ERROR_OUTOFMEMORY); + bResult = FALSE; + goto done; + } + + if (!QueryServiceConfig(hService, + pServiceConfig, + cbBytesNeeded, + &cbBytesNeeded)) + { + bResult = FALSE; + goto done; + } + + _tprintf(_T("SERVICE_NAME: %s\n"), ServiceName); + _tprintf(_T(" TYPE : %-3lx "), pServiceConfig->dwServiceType); + switch (pServiceConfig->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(" START_TYPE : %-3lx "), pServiceConfig->dwStartType); + switch (pServiceConfig->dwStartType) + { + case SERVICE_BOOT_START: + _tprintf(_T("BOOT_START\n")); + break; + + case SERVICE_SYSTEM_START: + _tprintf(_T("SYSTEM_START\n")); + break; + + case SERVICE_AUTO_START: + _tprintf(_T("AUTO_START\n")); + break; + + case SERVICE_DEMAND_START: + _tprintf(_T("DEMAND_START\n")); + break; + + case SERVICE_DISABLED: + _tprintf(_T("DISABLED\n")); + break; + + default: + _tprintf(_T("\n")); + break; + } + + _tprintf(_T(" ERROR_CONTROL : %-3lx "), pServiceConfig->dwErrorControl); + switch (pServiceConfig->dwErrorControl) + { + case SERVICE_ERROR_IGNORE: + _tprintf(_T("IGNORE\n")); + break; + + case SERVICE_ERROR_NORMAL: + _tprintf(_T("NORMAL\n")); + break; + + case SERVICE_ERROR_SEVERE: + _tprintf(_T("SEVERE\n")); + break; + + case SERVICE_ERROR_CRITICAL: + _tprintf(_T("CRITICAL\n")); + break; + + default: + _tprintf(_T("\n")); + break; + } + + _tprintf(_T(" BINARY_PATH_NAME : %s\n"), pServiceConfig->lpBinaryPathName); + _tprintf(_T(" LOAD_ORDER_GROUP : %s\n"), pServiceConfig->lpLoadOrderGroup); + _tprintf(_T(" TAG : %lu\n"), pServiceConfig->dwTagId); + _tprintf(_T(" DISPLAY_NAME : %s\n"), pServiceConfig->lpDisplayName); + _tprintf(_T(" DEPENDENCIES : ")); + lpPtr = pServiceConfig->lpDependencies; + i = 0; + while (*lpPtr != _T('\0')) + { + nLen = _tcslen(lpPtr); + if (i != 0) + _tprintf(_T("\n : ")); + _tprintf(_T("%s"), lpPtr); + lpPtr = lpPtr + nLen + 1; + i++; + } + _tprintf(_T("\n")); + + _tprintf(_T(" SERVICE_START_NAME : %s\n"), pServiceConfig->lpServiceStartName); + +done: + if (bResult == FALSE) + ReportLastError(); + + if (pServiceConfig != NULL) + HeapFree(GetProcessHeap(), 0, pServiceConfig); + + if (hService) + CloseServiceHandle(hService); + + if (hManager) + CloseServiceHandle(hManager); + + return bResult; +} diff --git a/reactos/base/applications/sc/qdescription.c b/reactos/base/applications/sc/qdescription.c new file mode 100644 index 00000000000..321347a8a9a --- /dev/null +++ b/reactos/base/applications/sc/qdescription.c @@ -0,0 +1,88 @@ +/* + * PROJECT: ReactOS Services + * LICENSE: GPL - See COPYING in the top level directory + * FILE: base/applications/sc/qdescription.c + * PURPOSE: Show the service description + * COPYRIGHT: Copyright 2016 Eric Kohl + * + */ + +#include "sc.h" + +BOOL QueryDescription(LPCTSTR ServiceName) +{ + SC_HANDLE hManager = NULL; + SC_HANDLE hService = NULL; + BOOL bResult = TRUE; + DWORD cbBytesNeeded = 0; + LPSERVICE_DESCRIPTION pServiceDescription = NULL; + +#ifdef SCDBG + _tprintf(_T("service to show description - %s\n\n"), ServiceName); +#endif + + hManager = OpenSCManager(NULL, + NULL, + SC_MANAGER_CONNECT); + if (hManager == NULL) + { + bResult = FALSE; + goto done; + } + + hService = OpenService(hManager, ServiceName, SERVICE_QUERY_CONFIG); + if (hService == NULL) + { + bResult = FALSE; + goto done; + } + + if (!QueryServiceConfig2(hService, + SERVICE_CONFIG_DESCRIPTION, + NULL, + 0, + &cbBytesNeeded)) + { + if (cbBytesNeeded == 0) + { + bResult = FALSE; + goto done; + } + } + + pServiceDescription = HeapAlloc(GetProcessHeap(), 0, cbBytesNeeded); + if (pServiceDescription == NULL) + { + SetLastError(ERROR_OUTOFMEMORY); + bResult = FALSE; + goto done; + } + + if (!QueryServiceConfig2(hService, + SERVICE_CONFIG_DESCRIPTION, + (LPBYTE)pServiceDescription, + cbBytesNeeded, + &cbBytesNeeded)) + { + bResult = FALSE; + goto done; + } + + _tprintf(_T("SERVICE_NAME: %s\n"), ServiceName); + _tprintf(_T(" DESCRIPTION : %s\n"), pServiceDescription->lpDescription); + +done: + if (bResult == FALSE) + ReportLastError(); + + if (pServiceDescription != NULL) + HeapFree(GetProcessHeap(), 0, pServiceDescription); + + if (hService) + CloseServiceHandle(hService); + + if (hManager) + CloseServiceHandle(hManager); + + return bResult; +} diff --git a/reactos/base/applications/sc/qfailure.c b/reactos/base/applications/sc/qfailure.c new file mode 100644 index 00000000000..d0bc557deed --- /dev/null +++ b/reactos/base/applications/sc/qfailure.c @@ -0,0 +1,118 @@ +/* + * PROJECT: ReactOS Services + * LICENSE: GPL - See COPYING in the top level directory + * FILE: base/applications/sc/qfailure.c + * PURPOSE: Show the service failure action + * COPYRIGHT: Copyright 2016 Eric Kohl + * + */ + +#include "sc.h" + +BOOL QueryFailure(LPCTSTR ServiceName) +{ + SC_HANDLE hManager = NULL; + SC_HANDLE hService = NULL; + BOOL bResult = TRUE; + DWORD cbBytesNeeded = 0; + LPSERVICE_FAILURE_ACTIONS pServiceFailure = NULL; + INT i; + +#ifdef SCDBG + _tprintf(_T("service to show failure action - %s\n\n"), ServiceName); +#endif + + hManager = OpenSCManager(NULL, + NULL, + SC_MANAGER_CONNECT); + if (hManager == NULL) + { + bResult = FALSE; + goto done; + } + + hService = OpenService(hManager, ServiceName, SERVICE_QUERY_CONFIG); + if (hService == NULL) + { + bResult = FALSE; + goto done; + } + + if (!QueryServiceConfig2(hService, + SERVICE_CONFIG_FAILURE_ACTIONS, + NULL, + 0, + &cbBytesNeeded)) + { + if (cbBytesNeeded == 0) + { + bResult = FALSE; + goto done; + } + } + + pServiceFailure = HeapAlloc(GetProcessHeap(), 0, cbBytesNeeded); + if (pServiceFailure == NULL) + { + SetLastError(ERROR_OUTOFMEMORY); + bResult = FALSE; + goto done; + } + + if (!QueryServiceConfig2(hService, + SERVICE_CONFIG_FAILURE_ACTIONS, + (LPBYTE)pServiceFailure, + cbBytesNeeded, + &cbBytesNeeded)) + { + bResult = FALSE; + goto done; + } + + _tprintf(_T("SERVICE_NAME: %s\n"), ServiceName); + _tprintf(_T(" RESET_PERIOD : %lu seconds\n"), pServiceFailure->dwResetPeriod); + _tprintf(_T(" REBOOT_MESSAGE : %s\n"), (pServiceFailure->lpRebootMsg) ? pServiceFailure->lpRebootMsg : _T("")); + _tprintf(_T(" COMMAND_LINE : %s\n"), (pServiceFailure->lpCommand) ? pServiceFailure->lpCommand : _T("")); + _tprintf(_T(" FAILURE_ACTIONS : ")); + for (i = 0; i < pServiceFailure->cActions; i++) + { + if (i != 0) + _tprintf(_T(" ")); + switch (pServiceFailure->lpsaActions[i].Type) + { + case SC_ACTION_NONE: + continue; + + case SC_ACTION_RESTART: + _tprintf(_T("RESTART -- Delay = %lu milliseconds.\n"), pServiceFailure->lpsaActions[i].Delay); + break; + + case SC_ACTION_REBOOT: + _tprintf(_T("REBOOT -- Delay = %lu milliseconds.\n"), pServiceFailure->lpsaActions[i].Delay); + break; + + case SC_ACTION_RUN_COMMAND: + _tprintf(_T("RUN_COMMAND -- Delay = %lu milliseconds.\n"), pServiceFailure->lpsaActions[i].Delay); + break; + + default: + _tprintf(_T("\n")); + break; + } + } + +done: + if (bResult == FALSE) + ReportLastError(); + + if (pServiceFailure != NULL) + HeapFree(GetProcessHeap(), 0, pServiceFailure); + + if (hService) + CloseServiceHandle(hService); + + if (hManager) + CloseServiceHandle(hManager); + + return bResult; +} diff --git a/reactos/base/applications/sc/sc.c b/reactos/base/applications/sc/sc.c index 762a3bf97ad..787ea268820 100644 --- a/reactos/base/applications/sc/sc.c +++ b/reactos/base/applications/sc/sc.c @@ -208,6 +208,42 @@ ScControl(LPCTSTR Server, // remote machine name else SdSetUsage(); } + else if (!lstrcmpi(Command, _T("qc"))) + { + if (ArgCount > 0) + { + ServiceName = *ServiceArgs++; + ArgCount--; + + QueryConfig(ServiceName); + } + else + QueryConfigUsage(); + } + else if (!lstrcmpi(Command, _T("qdescription"))) + { + if (ArgCount > 0) + { + ServiceName = *ServiceArgs++; + ArgCount--; + + QueryDescription(ServiceName); + } + else + QueryDescriptionUsage(); + } + else if (!lstrcmpi(Command, _T("qfailure"))) + { + if (ArgCount > 0) + { + ServiceName = *ServiceArgs++; + ArgCount--; + + QueryFailure(ServiceName); + } + else + QueryFailureUsage(); + } else { MainUsage(); diff --git a/reactos/base/applications/sc/sc.h b/reactos/base/applications/sc/sc.h index 6ce60a27493..f7d3703ac90 100644 --- a/reactos/base/applications/sc/sc.h +++ b/reactos/base/applications/sc/sc.h @@ -21,6 +21,9 @@ BOOL Query(LPCTSTR *ServiceArgs, DWORD ArgCount, BOOL bExtended); LPSERVICE_STATUS_PROCESS QueryService(LPCTSTR ServiceName); BOOL SdShow(LPCTSTR ServiceName); BOOL SdSet(LPCTSTR ServiceName, LPCTSTR SecurityDescriptor); +BOOL QueryConfig(LPCTSTR ServiceName); +BOOL QueryDescription(LPCTSTR ServiceName); +BOOL QueryFailure(LPCTSTR ServiceName); /* print and error functions */ VOID PrintService(LPCTSTR ServiceName, LPSERVICE_STATUS_PROCESS pStatus, BOOL bExtended); @@ -40,5 +43,8 @@ VOID CreateUsage(VOID); VOID ControlUsage(VOID); VOID SdShowUsage(VOID); VOID SdSetUsage(VOID); +VOID QueryConfigUsage(VOID); +VOID QueryDescriptionUsage(VOID); +VOID QueryFailureUsage(VOID); #endif /* _SC_PCH_ */ diff --git a/reactos/base/applications/sc/usage.c b/reactos/base/applications/sc/usage.c index be7c60ff2c5..18062d93c56 100644 --- a/reactos/base/applications/sc/usage.c +++ b/reactos/base/applications/sc/usage.c @@ -36,9 +36,9 @@ VOID MainUsage(VOID) // "\t config : Changes the configuration of a service (persistant).\n" // "\t description : Changes the description of a service.\n" // "\t failure : Changes the actions taken by a service upon failure.\n" -// "\t qc : Queries the configuration information for a service.\n" -// "\t qdescription : Queries the description for a service.\n" -// "\t qfailure : Queries the actions taken by a service upon failure.\n" + _T("\t qc : Queries the configuration information for a service.\n") + _T("\t qdescription : Queries the description for a service.\n") + _T("\t qfailure : Queries the actions taken by a service upon failure.\n") _T("\t delete : Deletes a service (from the registry).\n") _T("\t create : Creates a service. (adds it to the registry).\n") _T("\t control : Sends a control to a service.\n") @@ -194,15 +194,39 @@ VOID ControlUsage(VOID) VOID SdShowUsage(VOID) { _tprintf(_T("DESCRIPTION:\n") - _T(" Displays a service's security descriptor in SDDL format.\n") - _T("USAGE:\n") - _T(" sc sdshow \n")); + _T(" Displays a service's security descriptor in SDDL format.\n") + _T("USAGE:\n") + _T(" sc sdshow \n")); } VOID SdSetUsage(VOID) { _tprintf(_T("DESCRIPTION:\n") - _T(" Sets a service's security descriptor.\n") - _T("USAGE:\n") - _T(" sc sdset \n")); + _T(" Sets a service's security descriptor.\n") + _T("USAGE:\n") + _T(" sc sdset \n")); +} + +VOID QueryConfigUsage(VOID) +{ + _tprintf(_T("DESCRIPTION:\n") + _T(" Queries the configuration information for a service.\n") + _T("USAGE:\n") + _T(" sc qc [service name] \n")); +} + +VOID QueryDescriptionUsage(VOID) +{ + _tprintf(_T("DESCRIPTION:\n") + _T(" Retrieves the description string of a service.\n") + _T("USAGE:\n") + _T(" sc qdescription [service name] \n")); +} + +VOID QueryFailureUsage(VOID) +{ + _tprintf(_T("DESCRIPTION:\n") + _T(" Retrieves the actions performed on service failure.\n") + _T("USAGE:\n") + _T(" sc qfailure [service name] \n")); }