401 lines
11 KiB
C
401 lines
11 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1989 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
event.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module contains the event handling routines for SAC.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Sean Selitrennikoff (v-seans) - Jan 22, 1999
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "sac.h"
|
|||
|
|
|||
|
//
|
|||
|
// Definitions for this file.
|
|||
|
//
|
|||
|
|
|||
|
#define RESPONSE_BUFFER_SIZE (80 + sizeof(HEADLESS_RSP_GET_LINE) - sizeof(UCHAR))
|
|||
|
UCHAR ResponseBuffer[RESPONSE_BUFFER_SIZE];
|
|||
|
|
|||
|
//
|
|||
|
// Forward declarations for this file.
|
|||
|
//
|
|||
|
VOID
|
|||
|
ProcessInputLine(
|
|||
|
VOID
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
WorkerProcessEvents(
|
|||
|
IN PSAC_DEVICE_CONTEXT DeviceContext
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This is the routine for the worker thread. It blocks on an event, when
|
|||
|
the event is signalled, then that indicates a request is ready to be processed.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceContext - A pointer to this device.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
NTSTATUS Status;
|
|||
|
KIRQL OldIrql;
|
|||
|
|
|||
|
IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC WorkerProcessEvents: Entering.\n")));
|
|||
|
|
|||
|
//
|
|||
|
// Loop forever.
|
|||
|
//
|
|||
|
while (1) {
|
|||
|
|
|||
|
//
|
|||
|
// Block until there is work to do.
|
|||
|
//
|
|||
|
Status = KeWaitForSingleObject((PVOID)&(DeviceContext->ProcessEvent), Executive, KernelMode, FALSE, NULL);
|
|||
|
|
|||
|
if (DeviceContext->UnloadDeferred) {
|
|||
|
CancelIPIoRequest();
|
|||
|
SacPutSimpleMessage(SAC_ENTER);
|
|||
|
SacPutSimpleMessage(SAC_UNLOADED);
|
|||
|
SacPutSimpleMessage(SAC_ENTER);
|
|||
|
KeSetEvent(&(DeviceContext->UnloadEvent), DeviceContext->PriorityBoost, FALSE);
|
|||
|
IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC WorkerProcessEvents: Terminating.\n")));
|
|||
|
PsTerminateSystemThread(STATUS_SUCCESS);
|
|||
|
}
|
|||
|
switch ( ProcessingType ){
|
|||
|
|
|||
|
case SAC_PROCESS_INPUT:
|
|||
|
//
|
|||
|
// Process the input line.
|
|||
|
//
|
|||
|
ProcessInputLine();
|
|||
|
|
|||
|
//
|
|||
|
// Put the next command prompt
|
|||
|
//
|
|||
|
SacPutSimpleMessage(SAC_PROMPT);
|
|||
|
break;
|
|||
|
|
|||
|
case SAC_SUBMIT_IOCTL:
|
|||
|
if ( !IoctlSubmitted ) {
|
|||
|
// submit the notify request with the
|
|||
|
// IP driver. This procedure will also
|
|||
|
// ensure that it is done only once in
|
|||
|
// the lifetime of the driver.
|
|||
|
SubmitIPIoRequest();
|
|||
|
}
|
|||
|
break;
|
|||
|
default:
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Unset the processing flag
|
|||
|
//
|
|||
|
KeAcquireSpinLock(&(DeviceContext->SpinLock), &OldIrql);
|
|||
|
|
|||
|
DeviceContext->Processing = FALSE;
|
|||
|
|
|||
|
KeReleaseSpinLock(&(DeviceContext->SpinLock), OldIrql);
|
|||
|
|
|||
|
//
|
|||
|
// If there is any stuff that got delayed, process it.
|
|||
|
//
|
|||
|
DoDeferred(DeviceContext);
|
|||
|
}
|
|||
|
|
|||
|
ASSERT(0);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
DoDeferred(
|
|||
|
IN PSAC_DEVICE_CONTEXT DeviceContext
|
|||
|
)
|
|||
|
{
|
|||
|
IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE_LOUD, KdPrint(("SAC DoDeferred: Entering.\n")));
|
|||
|
|
|||
|
if (DeviceContext->UnloadDeferred) {
|
|||
|
|
|||
|
KeSetEvent(&(DeviceContext->UnloadEvent), DeviceContext->PriorityBoost, FALSE);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE_LOUD, KdPrint(("SAC DoDeferred: Exiting.\n")));
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
TimerDpcRoutine(
|
|||
|
IN struct _KDPC *Dpc,
|
|||
|
IN PVOID DeferredContext,
|
|||
|
IN PVOID SystemArgument1,
|
|||
|
IN PVOID SystemArgument2
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This is a DPC routine that is queue'd by DriverEntry. It is used to check for any
|
|||
|
user input and then processes them.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeferredContext - A pointer to the device context.
|
|||
|
|
|||
|
All other parameters are unused.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
{
|
|||
|
PSAC_DEVICE_CONTEXT DeviceContext = (PSAC_DEVICE_CONTEXT)DeferredContext;
|
|||
|
KIRQL OldIrql;
|
|||
|
SIZE_T i;
|
|||
|
PHEADLESS_RSP_GET_LINE Response;
|
|||
|
NTSTATUS Status;
|
|||
|
|
|||
|
IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE_LOUD, KdPrint(("SAC TimerDpcRoutine: Entering.\n")));
|
|||
|
|
|||
|
UNREFERENCED_PARAMETER(Dpc);
|
|||
|
UNREFERENCED_PARAMETER(SystemArgument1);
|
|||
|
UNREFERENCED_PARAMETER(SystemArgument2);
|
|||
|
|
|||
|
KeAcquireSpinLock(&(DeviceContext->SpinLock), &OldIrql);
|
|||
|
|
|||
|
//
|
|||
|
// If we are processing, then move on.
|
|||
|
//
|
|||
|
if (DeviceContext->Processing) {
|
|||
|
KeReleaseSpinLock(&(DeviceContext->SpinLock), OldIrql);
|
|||
|
IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE_LOUD, KdPrint(("SAC TimerDpcRoutine: Exiting.\n")));
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
DeviceContext->Processing = TRUE;
|
|||
|
|
|||
|
KeReleaseSpinLock(&(DeviceContext->SpinLock), OldIrql);
|
|||
|
|
|||
|
//
|
|||
|
// Check for user input
|
|||
|
//
|
|||
|
i = RESPONSE_BUFFER_SIZE;
|
|||
|
Response = (PHEADLESS_RSP_GET_LINE)ResponseBuffer;
|
|||
|
Status = HeadlessDispatch(HeadlessCmdGetLine,
|
|||
|
NULL,
|
|||
|
0,
|
|||
|
Response,
|
|||
|
&i
|
|||
|
);
|
|||
|
|
|||
|
if (NT_SUCCESS(Status) && Response->LineComplete) {
|
|||
|
|
|||
|
//
|
|||
|
// Lower case all the characters. We do not use strlwr() or the like, so that
|
|||
|
// the SAC (expecting ASCII always) doesn't accidently get DBCS or the like
|
|||
|
// translation of the UCHAR stream.
|
|||
|
//
|
|||
|
Response->Buffer[(RESPONSE_BUFFER_SIZE - sizeof(HEADLESS_RSP_GET_LINE)) / sizeof(UCHAR)] = '\0';
|
|||
|
|
|||
|
for (i = 0; Response->Buffer[i] != '\0'; i++) {
|
|||
|
if ((Response->Buffer[i] >= 'A') && (Response->Buffer[i] <= 'Z')) {
|
|||
|
Response->Buffer[i] = Response->Buffer[i] - 'A' + 'a';
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Fire off the worker thread to do the line. It will unset the processing
|
|||
|
// flag when it is done.
|
|||
|
//
|
|||
|
ProcessingType = SAC_PROCESS_INPUT;
|
|||
|
|
|||
|
KeSetEvent(&(DeviceContext->ProcessEvent), DeviceContext->PriorityBoost, FALSE);
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
if ( !IoctlSubmitted ) {
|
|||
|
|
|||
|
// We Still need to try and submit the notify IOCTL
|
|||
|
|
|||
|
if(Attempts == 0){
|
|||
|
|
|||
|
ProcessingType = SAC_SUBMIT_IOCTL;
|
|||
|
|
|||
|
Attempts = SAC_RETRY_GAP;
|
|||
|
|
|||
|
KeSetEvent(&(DeviceContext->ProcessEvent), DeviceContext->PriorityBoost, FALSE);
|
|||
|
|
|||
|
|
|||
|
IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE_LOUD, KdPrint(("SAC TimerDpcRoutine: Exiting.\n")));
|
|||
|
|
|||
|
return;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
Attempts --;
|
|||
|
}
|
|||
|
}
|
|||
|
KeAcquireSpinLock(&(DeviceContext->SpinLock), &OldIrql);
|
|||
|
|
|||
|
DeviceContext->Processing = FALSE;
|
|||
|
|
|||
|
KeReleaseSpinLock(&(DeviceContext->SpinLock), OldIrql);
|
|||
|
|
|||
|
//
|
|||
|
// If there is any, process it.
|
|||
|
//
|
|||
|
DoDeferred(DeviceContext);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE_LOUD, KdPrint(("SAC TimerDpcRoutine: Exiting.\n")));
|
|||
|
}
|
|||
|
|
|||
|
VOID
|
|||
|
ProcessInputLine(
|
|||
|
VOID
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is called to process an input line.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
HEADLESS_CMD_DISPLAY_LOG Command;
|
|||
|
PUCHAR InputLine;
|
|||
|
BOOLEAN CommandFound = FALSE;
|
|||
|
|
|||
|
InputLine = &(((PHEADLESS_RSP_GET_LINE)ResponseBuffer)->Buffer[0]);
|
|||
|
|
|||
|
if (!strcmp((LPSTR)InputLine, TLIST_COMMAND_STRING)) {
|
|||
|
DoTlistCommand();
|
|||
|
CommandFound = TRUE;
|
|||
|
} else if ((!strcmp((LPSTR)InputLine, HELP1_COMMAND_STRING)) ||
|
|||
|
(!strcmp((LPSTR)InputLine, HELP2_COMMAND_STRING))) {
|
|||
|
DoHelpCommand();
|
|||
|
CommandFound = TRUE;
|
|||
|
} else if (!strcmp((LPSTR)InputLine, DUMP_COMMAND_STRING)) {
|
|||
|
|
|||
|
Command.Paging = GlobalPagingNeeded;
|
|||
|
HeadlessDispatch(HeadlessCmdDisplayLog,
|
|||
|
&Command,
|
|||
|
sizeof(HEADLESS_CMD_DISPLAY_LOG),
|
|||
|
NULL,
|
|||
|
NULL
|
|||
|
);
|
|||
|
CommandFound = TRUE;
|
|||
|
|
|||
|
} else if (!strcmp((LPSTR)InputLine, FULLINFO_COMMAND_STRING)) {
|
|||
|
DoFullInfoCommand();
|
|||
|
CommandFound = TRUE;
|
|||
|
} else if (!strcmp((LPSTR)InputLine, PAGING_COMMAND_STRING)) {
|
|||
|
DoPagingCommand();
|
|||
|
CommandFound = TRUE;
|
|||
|
} else if (!strcmp((LPSTR)InputLine, REBOOT_COMMAND_STRING)) {
|
|||
|
DoRebootCommand(TRUE);
|
|||
|
CommandFound = TRUE;
|
|||
|
} else if (!strcmp((LPSTR)InputLine, SHUTDOWN_COMMAND_STRING)) {
|
|||
|
DoRebootCommand(FALSE);
|
|||
|
CommandFound = TRUE;
|
|||
|
} else if (!strcmp((LPSTR)InputLine, CRASH_COMMAND_STRING)) {
|
|||
|
CommandFound = TRUE;
|
|||
|
DoCrashCommand(); // this call does not return
|
|||
|
} else if (!strncmp((LPSTR)InputLine,
|
|||
|
KILL_COMMAND_STRING,
|
|||
|
sizeof(KILL_COMMAND_STRING) - sizeof(UCHAR))) {
|
|||
|
if ((strlen((LPSTR)InputLine) > 1) && (InputLine[1] == ' ')) {
|
|||
|
DoKillCommand(InputLine);
|
|||
|
CommandFound = TRUE;
|
|||
|
}
|
|||
|
} else if (!strncmp((LPSTR)InputLine,
|
|||
|
LOWER_COMMAND_STRING,
|
|||
|
sizeof(LOWER_COMMAND_STRING) - sizeof(UCHAR))) {
|
|||
|
if ((strlen((LPSTR)InputLine) > 1) && (InputLine[1] == ' ')) {
|
|||
|
DoLowerPriorityCommand(InputLine);
|
|||
|
CommandFound = TRUE;
|
|||
|
}
|
|||
|
} else if (!strncmp((LPSTR)InputLine,
|
|||
|
RAISE_COMMAND_STRING,
|
|||
|
sizeof(RAISE_COMMAND_STRING) - sizeof(UCHAR))) {
|
|||
|
if ((strlen((LPSTR)InputLine) > 1) && (InputLine[1] == ' ')) {
|
|||
|
DoRaisePriorityCommand(InputLine);
|
|||
|
CommandFound = TRUE;
|
|||
|
}
|
|||
|
} else if (!strncmp((LPSTR)InputLine,
|
|||
|
LIMIT_COMMAND_STRING,
|
|||
|
sizeof(LIMIT_COMMAND_STRING) - sizeof(UCHAR))) {
|
|||
|
if ((strlen((LPSTR)InputLine) > 1) && (InputLine[1] == ' ')) {
|
|||
|
DoLimitMemoryCommand(InputLine);
|
|||
|
CommandFound = TRUE;
|
|||
|
}
|
|||
|
} else if (!strncmp((LPSTR)InputLine,
|
|||
|
TIME_COMMAND_STRING,
|
|||
|
sizeof(TIME_COMMAND_STRING) - sizeof(UCHAR))) {
|
|||
|
if (((strlen((LPSTR)InputLine) > 1) && (InputLine[1] == ' ')) ||
|
|||
|
(strlen((LPSTR)InputLine) == 1)) {
|
|||
|
DoSetTimeCommand(InputLine);
|
|||
|
CommandFound = TRUE;
|
|||
|
}
|
|||
|
} else if (!strcmp((LPSTR)InputLine, INFORMATION_COMMAND_STRING)) {
|
|||
|
DoMachineInformationCommand();
|
|||
|
CommandFound = TRUE;
|
|||
|
} else if (!strncmp((LPSTR)InputLine,
|
|||
|
SETIP_COMMAND_STRING,
|
|||
|
sizeof(SETIP_COMMAND_STRING) - sizeof(UCHAR))) {
|
|||
|
if (((strlen((LPSTR)InputLine) > 1) && (InputLine[1] == ' ')) ||
|
|||
|
(strlen((LPSTR)InputLine) == 1)) {
|
|||
|
DoSetIpAddressCommand(InputLine);
|
|||
|
CommandFound = TRUE;
|
|||
|
}
|
|||
|
} else if ((InputLine[0] == '\n') || (InputLine[0] == '\0')) {
|
|||
|
CommandFound = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
if( !CommandFound ) {
|
|||
|
//
|
|||
|
// We don't know what this is.
|
|||
|
//
|
|||
|
SacPutSimpleMessage(SAC_UNKNOWN_COMMAND);
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|