355 lines
12 KiB
C++
355 lines
12 KiB
C++
#include "pch.h"
|
|
#pragma hdrstop
|
|
#include <winsvc.h>
|
|
#include <winsock.h>
|
|
#include <nspapi.h>
|
|
#include <tchar.h>
|
|
|
|
#define PROCESS_SIZE 16
|
|
|
|
INT InetStartService( LPCTSTR lpServiceName );
|
|
|
|
TCHAR gServicesWhichMustBeRestarted[20][PROCESS_SIZE];
|
|
int gServicesWhichMustBeRestarted_nextuse;
|
|
int gServicesWhichMustBeRestarted_total;
|
|
|
|
int ServicesRestartList_EntryExists(LPCTSTR szServiceName)
|
|
{
|
|
int iFoundMatch = FALSE;
|
|
|
|
// loop thru the whole list
|
|
for(int i=0; i < gServicesWhichMustBeRestarted_total;i++)
|
|
{
|
|
if (_tcsicmp(gServicesWhichMustBeRestarted[i], szServiceName) == 0)
|
|
{
|
|
iFoundMatch = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return iFoundMatch;
|
|
}
|
|
|
|
|
|
int ServicesRestartList_Add(LPCTSTR szServiceName)
|
|
{
|
|
DbgPrint(("ServicesRestartList_Add() on Service %S"), szServiceName);
|
|
|
|
// check if this value already exists in the globalarary
|
|
if (ServicesRestartList_EntryExists(szServiceName)) {return FALSE;}
|
|
|
|
// move info into global array
|
|
if (gServicesWhichMustBeRestarted_nextuse <= 20)
|
|
{
|
|
_tcscpy(gServicesWhichMustBeRestarted[gServicesWhichMustBeRestarted_nextuse],szServiceName);
|
|
// increment counter to array
|
|
// increment next use space
|
|
++gServicesWhichMustBeRestarted_total;
|
|
++gServicesWhichMustBeRestarted_nextuse;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
int ServicesRestartList_RestartServices(void)
|
|
{
|
|
int iReturn = FALSE;
|
|
INT err = 0;
|
|
|
|
|
|
// loop thru the whole list and restart the services in reverse
|
|
// order from how they were entered?
|
|
if (gServicesWhichMustBeRestarted_total >= 1)
|
|
{
|
|
DbgPrint(("RestartServices() Start."));
|
|
for(int i=0; i < gServicesWhichMustBeRestarted_total;i++)
|
|
{
|
|
err = InetStartService(gServicesWhichMustBeRestarted[i]);
|
|
DbgPrint(("Start service %S. err=%x"), gServicesWhichMustBeRestarted[i], err);
|
|
}
|
|
DbgPrint(("RestartServices() End."));
|
|
}
|
|
|
|
return iReturn;
|
|
}
|
|
|
|
|
|
|
|
INT InetStartService( LPCTSTR lpServiceName )
|
|
{
|
|
INT err = 0;
|
|
const DWORD dwSvcSleepInterval = 500 ;
|
|
const DWORD dwSvcMaxSleep = 180000 ;
|
|
SC_HANDLE hScManager = NULL;
|
|
SC_HANDLE hService = NULL;
|
|
|
|
DbgPrint(("Starting %S service..."), lpServiceName);
|
|
|
|
do {
|
|
// set up the service first
|
|
if ((hScManager = OpenSCManager( NULL, NULL, GENERIC_ALL )) == NULL ||
|
|
(hService = ::OpenService( hScManager, lpServiceName, GENERIC_ALL )) == NULL )
|
|
{
|
|
err = GetLastError();
|
|
break;
|
|
}
|
|
|
|
SERVICE_STATUS svcStatus;
|
|
if ( !QueryServiceStatus( hService, &svcStatus ))
|
|
{
|
|
err = ::GetLastError();
|
|
break;
|
|
}
|
|
|
|
if ( svcStatus.dwCurrentState == SERVICE_RUNNING )
|
|
break; // service already started and running
|
|
|
|
if ( !::StartService( hService, 0, NULL ))
|
|
{
|
|
err = ::GetLastError();
|
|
break;
|
|
}
|
|
|
|
// Wait for the service to attain "running" status; but
|
|
// wait no more than 3 minute.
|
|
DWORD dwSleepTotal;
|
|
for ( dwSleepTotal = 0 ; dwSleepTotal < dwSvcMaxSleep
|
|
&& (QueryServiceStatus( hService, &svcStatus ))
|
|
//&& svcStatus.dwCurrentState == SERVICE_START_PENDING ;
|
|
&& svcStatus.dwCurrentState != SERVICE_RUNNING ;
|
|
dwSleepTotal += dwSvcSleepInterval )
|
|
{
|
|
::Sleep( dwSvcSleepInterval ) ;
|
|
}
|
|
|
|
if ( svcStatus.dwCurrentState != SERVICE_RUNNING )
|
|
{
|
|
err = dwSleepTotal > dwSvcMaxSleep ?
|
|
ERROR_SERVICE_REQUEST_TIMEOUT :
|
|
svcStatus.dwWin32ExitCode;
|
|
break;
|
|
}
|
|
|
|
} while ( FALSE );
|
|
|
|
if (hService)
|
|
CloseServiceHandle(hService);
|
|
if (hScManager)
|
|
CloseServiceHandle(hScManager);
|
|
|
|
DbgPrint(("Service started with 0x%x"), err);
|
|
|
|
return(err);
|
|
}
|
|
|
|
|
|
//
|
|
//Routine Description:
|
|
// Stop the named service and all those services which depend upon it.
|
|
// And if the service is hung and can't be stopped, then kill the darn thing.
|
|
//
|
|
//Arguments:
|
|
// ServiceName (Name of service to stop)
|
|
//
|
|
//Return Status:
|
|
// TRUE - Indicates service successfully stopped
|
|
// FALSE - Timeout occurred.
|
|
//
|
|
int StopServiceAndDependencies(LPCTSTR ServiceName, int AddToRestartList)
|
|
{
|
|
DbgPrint(("StopServiceAndDependencies():%S Service"), ServiceName);
|
|
|
|
int Err = 0;
|
|
int iBeforeServiceStatus = 0;
|
|
SC_HANDLE ScManagerHandle = NULL;
|
|
SC_HANDLE ServiceHandle = NULL;
|
|
SERVICE_STATUS ServiceStatus;
|
|
DWORD Timeout;
|
|
DWORD TimeoutMaxSecs = 60 * 10; //10mins -- iisadmin may take a long time
|
|
int iReturn = FALSE;
|
|
|
|
//
|
|
// Open a handle to the Service.
|
|
//
|
|
ScManagerHandle = OpenSCManager(NULL,NULL,SC_MANAGER_CONNECT );
|
|
if (ScManagerHandle == NULL)
|
|
{
|
|
Err = GetLastError();
|
|
DbgPrint(("StopServiceAndDependencies():OpenSCManager: Err on Service %S Err=0x%x FAILED"), ServiceName, Err);
|
|
goto Cleanup;
|
|
}
|
|
|
|
ServiceHandle = OpenService(ScManagerHandle,ServiceName,SERVICE_QUERY_STATUS | SERVICE_INTERROGATE | SERVICE_ENUMERATE_DEPENDENTS | SERVICE_STOP | SERVICE_QUERY_CONFIG );
|
|
if ( ServiceHandle == NULL )
|
|
{
|
|
Err = GetLastError();
|
|
if (Err == ERROR_SERVICE_DOES_NOT_EXIST)
|
|
{
|
|
iReturn = TRUE;
|
|
DbgPrint(("StopServiceAndDependencies():%S Service does not exist."), ServiceName);
|
|
}
|
|
else
|
|
{
|
|
DbgPrint(("StopServiceAndDependencies():OpenService: Err on Service %S Err=0x%x FAILED"), ServiceName, Err);
|
|
}
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Get the before service status.
|
|
if (QueryServiceStatus(ServiceHandle, &ServiceStatus))
|
|
{
|
|
iBeforeServiceStatus = ServiceStatus.dwCurrentState;
|
|
}
|
|
|
|
//
|
|
// Ask the service to stop.
|
|
//
|
|
if ( !ControlService( ServiceHandle, SERVICE_CONTROL_STOP, &ServiceStatus) )
|
|
{
|
|
Err = GetLastError();
|
|
// If there are dependent services running,
|
|
// determine their names and stop them.
|
|
if ( Err == ERROR_DEPENDENT_SERVICES_RUNNING )
|
|
{
|
|
BYTE ConfigBuffer[4096];
|
|
LPENUM_SERVICE_STATUS ServiceConfig = (LPENUM_SERVICE_STATUS) &ConfigBuffer;
|
|
DWORD BytesNeeded;
|
|
DWORD ServiceCount;
|
|
DWORD ServiceIndex;
|
|
|
|
//
|
|
// Get the names of the dependent services.
|
|
//
|
|
if ( !EnumDependentServices( ServiceHandle,SERVICE_ACTIVE,ServiceConfig,sizeof(ConfigBuffer),&BytesNeeded,&ServiceCount ) )
|
|
{
|
|
Err = GetLastError();
|
|
DbgPrint(("StopServiceAndDependencies():EnumDependentServices: Err on Service %S Err=0x%x FAILED"), ServiceName, Err);
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Stop those services.
|
|
//
|
|
for ( ServiceIndex=0; ServiceIndex<ServiceCount; ServiceIndex++ )
|
|
{
|
|
StopServiceAndDependencies( ServiceConfig[ServiceIndex].lpServiceName, AddToRestartList);
|
|
}
|
|
|
|
//
|
|
// Ask the original service to stop.
|
|
//
|
|
if ( !ControlService( ServiceHandle, SERVICE_CONTROL_STOP, &ServiceStatus) )
|
|
{
|
|
Err = GetLastError();
|
|
|
|
// check if the service is already stopped..
|
|
if ( Err == ERROR_SERVICE_CANNOT_ACCEPT_CTRL || Err == ERROR_SERVICE_NOT_ACTIVE)
|
|
{
|
|
// check if the service is alread stopped.
|
|
if (QueryServiceStatus( ServiceHandle, &ServiceStatus ))
|
|
{
|
|
if ( ServiceStatus.dwCurrentState == SERVICE_STOPPED || ServiceStatus.dwCurrentState == SERVICE_STOP_PENDING)
|
|
{
|
|
iReturn = TRUE;
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// The service must be in a hung mode. Let's kill it.
|
|
// Todo: NYI
|
|
DbgPrint(("StopServiceAndDependencies():'%S' Service must be in a hung mode. unable to stop it."), ServiceName);
|
|
//KillService(ServiceHandle);
|
|
//goto WaitLoop;
|
|
}
|
|
|
|
goto Cleanup;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
// check if the service is already stopped..
|
|
if ( Err == ERROR_SERVICE_CANNOT_ACCEPT_CTRL || Err == ERROR_SERVICE_NOT_ACTIVE)
|
|
{
|
|
// check if the service is alread stopped.
|
|
if (QueryServiceStatus( ServiceHandle, &ServiceStatus ))
|
|
{
|
|
if ( ServiceStatus.dwCurrentState == SERVICE_STOPPED || ServiceStatus.dwCurrentState == SERVICE_STOP_PENDING)
|
|
{
|
|
Err = ServiceStatus.dwCurrentState;
|
|
iReturn = TRUE;
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// The service must be in a hung mode. Let's kill it.
|
|
DbgPrint(("StopServiceAndDependencies():'%S' Service must be in a hung mode."), ServiceName);
|
|
//KillService(ServiceHandle);
|
|
//goto WaitLoop;
|
|
}
|
|
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// We successfully asked the service to stop...
|
|
}
|
|
|
|
|
|
// Loop waiting for the service to stop.
|
|
for ( Timeout=0; Timeout<TimeoutMaxSecs; Timeout++ )
|
|
{
|
|
// Return or continue waiting depending on the state of the service.
|
|
if ( ServiceStatus.dwCurrentState == SERVICE_STOPPED )
|
|
{
|
|
// The service successfully stopped.
|
|
DbgPrint(("StopServiceAndDependencies(): %S Service stopped."), ServiceName);
|
|
iReturn = TRUE;
|
|
goto Cleanup;
|
|
}
|
|
|
|
// Wait a second for the service to finish stopping.
|
|
Sleep( 1000 );
|
|
|
|
// Query the status of the service again.
|
|
if (! QueryServiceStatus( ServiceHandle, &ServiceStatus ))
|
|
{
|
|
Err = GetLastError();
|
|
DbgPrint(("StopServiceAndDependencies():QueryServiceStatus: Err on Service %S Err=0x%x FAILED"), ServiceName, Err);
|
|
goto Cleanup;
|
|
}
|
|
|
|
#if 0
|
|
// if the service we are trying to stop is a driver,
|
|
// then heck we should just get out of here..
|
|
if (TRUE == IsThisServiceADriver(ServiceName))
|
|
{
|
|
DbgPrint(("StopServiceAndDependencies(): %S service is a driver, and can only be removed upon reboot."), ServiceName);
|
|
goto Cleanup;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// if we get here then the service failed to stop.
|
|
DbgPrint(("StopServiceAndDependencies(): failed to stop %S service."), ServiceName);
|
|
|
|
Cleanup:
|
|
if ( ScManagerHandle != NULL ) {(VOID) CloseServiceHandle(ScManagerHandle);}
|
|
if ( ServiceHandle != NULL ) {(VOID) CloseServiceHandle(ServiceHandle);}
|
|
|
|
// if we successfully stopped this service, then
|
|
// add it to the restart service list
|
|
if (iReturn == TRUE)
|
|
{
|
|
if (iBeforeServiceStatus == SERVICE_RUNNING)
|
|
{
|
|
if (AddToRestartList) {ServicesRestartList_Add(ServiceName);}
|
|
}
|
|
}
|
|
return iReturn;
|
|
}
|