363 lines
9 KiB
C
363 lines
9 KiB
C
/*++
|
||
|
||
Copyright (c) 1991 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
bootvrfy.c
|
||
|
||
Abstract:
|
||
|
||
This is a small service that simply calls NotifyBootConfigStatus to
|
||
indicate that the boot is acceptable. This service is to go at the
|
||
end of the service dependency list.
|
||
|
||
The assumption is that if we got far enough to start this service, the
|
||
the boot must be ok.
|
||
|
||
|
||
Author:
|
||
|
||
Dan Lafferty (danl) 06 May-1991
|
||
|
||
Environment:
|
||
|
||
User Mode -Win32
|
||
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
//
|
||
// Includes
|
||
//
|
||
|
||
#include <nt.h> // DbgPrint prototype
|
||
#include <ntrtl.h> // DbgPrint prototype
|
||
#include <windef.h>
|
||
#include <nturtl.h> // needed for winbase.h
|
||
#include <winbase.h>
|
||
|
||
#include <winsvc.h>
|
||
|
||
#include <tstr.h> // Unicode string macros
|
||
|
||
//
|
||
// Defines
|
||
//
|
||
|
||
#define SERVICE_WAIT_TIME 0xffffffff // infinite
|
||
|
||
#define BV_SERVICE_NAME L"BootVerification"
|
||
|
||
//
|
||
// DEBUG MACROS
|
||
//
|
||
//
|
||
// The following allow debug print syntax to look like:
|
||
//
|
||
// BV_LOG(DEBUG_TRACE, "An error occured %x\n",status)
|
||
//
|
||
|
||
#if DBG
|
||
|
||
#define STATIC
|
||
#define BV_LOG0(level, string) \
|
||
KdPrintEx((DPFLTR_BOOTVRFY_ID, \
|
||
DEBUG_##level, \
|
||
"[BootVrfy]" string))
|
||
|
||
#define BV_LOG1(level, string, var1) \
|
||
KdPrintEx((DPFLTR_BOOTVRFY_ID, \
|
||
DEBUG_##level, \
|
||
"[BootVrfy]" string, \
|
||
var1))
|
||
|
||
#define BV_LOG2(level, string, var1, var2) \
|
||
KdPrintEx((DPFLTR_BOOTVRFY_ID, \
|
||
DEBUG_##level, \
|
||
"[BootVrfy]" string, \
|
||
var1, \
|
||
var2))
|
||
|
||
#else
|
||
|
||
#define STATIC static
|
||
#define BV_LOG0(level, string)
|
||
#define BV_LOG1(level, string, var)
|
||
#define BV_LOG2(level, string, var1, var2)
|
||
|
||
#endif
|
||
|
||
//
|
||
// Debug output is filtered at two levels: A global level and a component
|
||
// specific level.
|
||
//
|
||
// Each debug output request specifies a component id and a filter level
|
||
// or mask. These variables are used to access the debug print filter
|
||
// database maintained by the system. The component id selects a 32-bit
|
||
// mask value and the level either specified a bit within that mask or is
|
||
// as mask value itself.
|
||
//
|
||
// If any of the bits specified by the level or mask are set in either the
|
||
// component mask or the global mask, then the debug output is permitted.
|
||
// Otherwise, the debug output is filtered and not printed.
|
||
//
|
||
// The component mask for filtering the debug output of this component is
|
||
// Kd_BOOTVRFY_Mask and may be set via the registry or the kernel debugger.
|
||
//
|
||
// The global mask for filtering the debug output of all components is
|
||
// Kd_WIN2000_Mask and may be set via the registry or the kernel debugger.
|
||
//
|
||
// The registry key for setting the mask value for this component is:
|
||
//
|
||
// HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\
|
||
// Session Manager\Debug Print Filter\BOOTVRFY
|
||
//
|
||
// The key "Debug Print Filter" may have to be created in order to create
|
||
// the component key.
|
||
//
|
||
// The following levels are used to filter debug output.
|
||
//
|
||
|
||
#define DEBUG_ERROR (0x00000001 | DPFLTR_MASK)
|
||
#define DEBUG_TRACE (0x00000004 | DPFLTR_MASK)
|
||
|
||
#define DEBUG_ALL (0xffffffff | DPFLTR_MASK)
|
||
|
||
//
|
||
// Globals
|
||
//
|
||
|
||
SERVICE_STATUS BootVerificationStatus;
|
||
|
||
HANDLE BootVerificationDoneEvent;
|
||
|
||
SERVICE_STATUS_HANDLE BootVerificationStatusHandle;
|
||
|
||
//
|
||
// Function Prototypes
|
||
//
|
||
|
||
STATIC VOID
|
||
BootVerificationStart (
|
||
DWORD argc,
|
||
LPWSTR *argv
|
||
);
|
||
|
||
STATIC VOID
|
||
BootVerificationCtrlHandler (
|
||
IN DWORD opcode
|
||
);
|
||
|
||
|
||
/****************************************************************************/
|
||
VOID __cdecl
|
||
main(void)
|
||
{
|
||
DWORD status;
|
||
|
||
SERVICE_TABLE_ENTRYW DispatchTable[] = {
|
||
{ BV_SERVICE_NAME, BootVerificationStart },
|
||
{ NULL, NULL }
|
||
};
|
||
|
||
status = StartServiceCtrlDispatcherW( DispatchTable);
|
||
|
||
BV_LOG0(TRACE,"The Service Process is Terminating....\n");
|
||
|
||
ExitProcess(0);
|
||
|
||
}
|
||
|
||
|
||
/****************************************************************************/
|
||
|
||
//
|
||
// BootVerification will take a long time to respond to pause
|
||
//
|
||
//
|
||
|
||
VOID
|
||
BootVerificationStart (
|
||
DWORD argc,
|
||
LPWSTR *argv
|
||
)
|
||
{
|
||
DWORD status;
|
||
SC_HANDLE hScManager;
|
||
SC_HANDLE hService;
|
||
SERVICE_STATUS ServiceStatus;
|
||
|
||
|
||
BV_LOG0(TRACE,"Inside the BootVerification Service Thread\n");
|
||
|
||
BootVerificationDoneEvent = CreateEvent (NULL, TRUE, FALSE,NULL);
|
||
|
||
//
|
||
// Fill in this services status structure
|
||
//
|
||
|
||
BootVerificationStatus.dwServiceType = SERVICE_WIN32;
|
||
BootVerificationStatus.dwCurrentState = SERVICE_RUNNING;
|
||
BootVerificationStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
|
||
BootVerificationStatus.dwWin32ExitCode = 0;
|
||
BootVerificationStatus.dwServiceSpecificExitCode = 0;
|
||
BootVerificationStatus.dwCheckPoint = 0;
|
||
BootVerificationStatus.dwWaitHint = 0;
|
||
|
||
//
|
||
// Register the Control Handler routine.
|
||
//
|
||
|
||
BV_LOG0(TRACE,"Getting Ready to call RegisterServiceCtrlHandler\n");
|
||
|
||
BootVerificationStatusHandle = RegisterServiceCtrlHandlerW(
|
||
BV_SERVICE_NAME,
|
||
BootVerificationCtrlHandler);
|
||
|
||
if (BootVerificationStatusHandle == (SERVICE_STATUS_HANDLE)0) {
|
||
BV_LOG1(ERROR,"RegisterServiceCtrlHandlerW failed %d\n", GetLastError());
|
||
}
|
||
|
||
//
|
||
// Return the status
|
||
//
|
||
|
||
if (!SetServiceStatus (BootVerificationStatusHandle, &BootVerificationStatus)) {
|
||
status = GetLastError();
|
||
BV_LOG1(ERROR,"SetServiceStatus error %ld\n",status);
|
||
}
|
||
|
||
//
|
||
// Tell Service Controller that the Boot is OK.
|
||
//
|
||
|
||
BV_LOG0(TRACE,"Tell Service Controller that the boot is ok\n");
|
||
if (!NotifyBootConfigStatus(TRUE)) {
|
||
BV_LOG0(ERROR,"NotifyBootConfigStatus Failed\n");
|
||
}
|
||
|
||
////////////////////////////////////////////////////////////////////////
|
||
//
|
||
// Tell the Service Controller that we want to shut down now.
|
||
//
|
||
// If anything fails along the way, just exit process, and allow
|
||
// the service controller to clean up.
|
||
//
|
||
|
||
BV_LOG0(TRACE,"Send Control to Service Controller to shut down BOOTVFY\n");
|
||
|
||
|
||
hScManager = OpenSCManagerW(
|
||
NULL,
|
||
NULL,
|
||
SC_MANAGER_CONNECT);
|
||
|
||
if (hScManager == NULL) {
|
||
status = GetLastError();
|
||
BV_LOG1(ERROR,"OpenSCManager failed %d\n",status);
|
||
BootVerificationStatus.dwWin32ExitCode = status;
|
||
SetServiceStatus (BootVerificationStatusHandle, &BootVerificationStatus);
|
||
ExitProcess(0);
|
||
}
|
||
|
||
hService = OpenServiceW(
|
||
hScManager,
|
||
BV_SERVICE_NAME,
|
||
SERVICE_STOP);
|
||
|
||
if (hService == NULL) {
|
||
status = GetLastError();
|
||
BV_LOG1(ERROR,"OpenService failed %d\n",status);
|
||
BootVerificationStatus.dwWin32ExitCode = status;
|
||
SetServiceStatus (BootVerificationStatusHandle, &BootVerificationStatus);
|
||
ExitProcess(0);
|
||
}
|
||
|
||
if (!ControlService (hService,SERVICE_CONTROL_STOP,&ServiceStatus)) {
|
||
status = GetLastError();
|
||
BV_LOG1(ERROR,"OpenService failed %d\n",status);
|
||
BootVerificationStatus.dwWin32ExitCode = status;
|
||
SetServiceStatus (BootVerificationStatusHandle, &BootVerificationStatus);
|
||
ExitProcess(0);
|
||
}
|
||
|
||
|
||
////////////////////////////////////////////////////////////////////////
|
||
//
|
||
// Wait forever until we are told to terminate.
|
||
//
|
||
|
||
status = WaitForSingleObject (
|
||
BootVerificationDoneEvent,
|
||
SERVICE_WAIT_TIME);
|
||
|
||
|
||
BV_LOG0(TRACE,"Leaving the BootVerification service\n");
|
||
|
||
|
||
BootVerificationStatus.dwWin32ExitCode = 0;
|
||
BootVerificationStatus.dwCurrentState = SERVICE_STOPPED;
|
||
if (!SetServiceStatus (BootVerificationStatusHandle, &BootVerificationStatus)) {
|
||
status = GetLastError();
|
||
BV_LOG1(ERROR,"SetServiceStatus error %ld\n",status);
|
||
}
|
||
|
||
ExitThread(NO_ERROR);
|
||
return;
|
||
}
|
||
|
||
|
||
/****************************************************************************/
|
||
VOID
|
||
BootVerificationCtrlHandler (
|
||
IN DWORD Opcode
|
||
)
|
||
{
|
||
|
||
DWORD status;
|
||
|
||
BV_LOG1(TRACE,"opcode = %ld\n", Opcode);
|
||
|
||
//
|
||
// Find and operate on the request.
|
||
//
|
||
|
||
switch(Opcode) {
|
||
case SERVICE_CONTROL_PAUSE:
|
||
break;
|
||
|
||
case SERVICE_CONTROL_CONTINUE:
|
||
break;
|
||
|
||
case SERVICE_CONTROL_STOP:
|
||
|
||
BootVerificationStatus.dwWin32ExitCode = 0;
|
||
BootVerificationStatus.dwCurrentState = SERVICE_STOP_PENDING;
|
||
|
||
SetEvent(BootVerificationDoneEvent);
|
||
break;
|
||
|
||
case SERVICE_CONTROL_INTERROGATE:
|
||
|
||
break;
|
||
|
||
default:
|
||
BV_LOG1(ERROR,"Unrecognized opcode %ld\n", Opcode);
|
||
}
|
||
|
||
//
|
||
// Send a status response.
|
||
//
|
||
|
||
if (!SetServiceStatus (BootVerificationStatusHandle, &BootVerificationStatus)) {
|
||
status = GetLastError();
|
||
BV_LOG1(ERROR,"SetServiceStatus error %ld\n",status);
|
||
}
|
||
return;
|
||
}
|
||
|
||
|