758 lines
18 KiB
C
758 lines
18 KiB
C
/*++
|
||
|
||
Copyright (c) 1995 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
CtlCode.c
|
||
|
||
Abstract:
|
||
|
||
A user mode app that breaks down a CTL_CODE (from IOCTL Irp)
|
||
Into its component parts of BASE, #, Method, and Access.
|
||
|
||
Environment:
|
||
|
||
User mode only
|
||
|
||
Revision History:
|
||
|
||
07-14-98 : Created by henrygab
|
||
|
||
--*/
|
||
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <stdarg.h>
|
||
#include <string.h>
|
||
#include <math.h>
|
||
#include <winerror.h>
|
||
#include <strsafe.h>
|
||
|
||
#include "CtlCode.h"
|
||
|
||
#if DBG
|
||
#define DEBUG_BUFFER_LENGTH 1000
|
||
ULONG DebugLevel = 0;
|
||
UCHAR DebugBuffer[DEBUG_BUFFER_LENGTH];
|
||
|
||
VOID
|
||
__cdecl
|
||
CtlCodeDebugPrint(
|
||
ULONG DebugPrintLevel,
|
||
PCCHAR DebugMessage,
|
||
...
|
||
)
|
||
{
|
||
if ((DebugPrintLevel <= (DebugLevel & 0x0000ffff)) ||
|
||
((1 << (DebugPrintLevel + 15)) & DebugLevel)
|
||
) {
|
||
HRESULT hr;
|
||
va_list ap;
|
||
|
||
va_start(ap, DebugMessage);
|
||
hr = StringCchVPrintf(DebugBuffer,
|
||
DEBUG_BUFFER_LENGTH,
|
||
DebugMessage,
|
||
ap);
|
||
if ((HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER) || SUCCEEDED(hr)) {
|
||
fprintf(stderr, DebugBuffer);
|
||
}
|
||
va_end(ap);
|
||
}
|
||
}
|
||
|
||
#define DebugPrint(x) CtlCodeDebugPrint x
|
||
#else
|
||
#define DebugPrint(x)
|
||
#endif // DBG
|
||
|
||
|
||
VOID
|
||
DecodeIoctl(
|
||
PCTL_CODE CtlCode
|
||
);
|
||
BOOLEAN
|
||
IsHexNumber(
|
||
const char *szExpression
|
||
);
|
||
BOOLEAN
|
||
IsDecNumber(
|
||
const char *szExpression
|
||
);
|
||
|
||
//
|
||
// List of commands
|
||
// all command names are case sensitive
|
||
// arguments are passed into command routines
|
||
// list must be terminated with NULL command
|
||
// command will not be listed in help if description == NULL
|
||
//
|
||
|
||
ULONG32 ListCommand();
|
||
|
||
//
|
||
// prints an attenuation table based off cdrom standard volume
|
||
//
|
||
|
||
ULONG32 AttenuateCommand( int argc, char *argv[]);
|
||
|
||
VOID FindCommand(int argc, char *argv[]);
|
||
ULONG32 DecodeCommand(int argc, char *argv[]);
|
||
ULONG32 EncodeCommand(int argc, char *argv[]);
|
||
|
||
|
||
|
||
int __cdecl main(int argc, char *argv[])
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Parses input, showing help or calling function requested appropriately
|
||
|
||
Return Value:
|
||
|
||
0 - success
|
||
-1 - insufficient arguments
|
||
-2 - error opening device (DNE?)
|
||
|
||
--*/
|
||
{
|
||
int i = 0;
|
||
|
||
DebugPrint((3, "main => entering\n"));
|
||
|
||
if (argc < 2 ||
|
||
!strcmp(argv[1], "-?") ||
|
||
!strcmp(argv[1], "-h") ||
|
||
!strcmp(argv[1], "/?") ||
|
||
!strcmp(argv[1], "/h")
|
||
) {
|
||
|
||
DebugPrint((3, "main => Help requested...\n"));
|
||
ListCommand();
|
||
return -1;
|
||
|
||
}
|
||
|
||
if (argc != 2 && argc != 5) {
|
||
|
||
DebugPrint((3, "main => bad argc: %x, printing help\n", argc));
|
||
printf("Usage: ctl_code [parameters]\n");
|
||
return ListCommand();
|
||
}
|
||
|
||
if (argc == 5) {
|
||
|
||
DebugPrint((3, "main => encoding four args to one ioctl\n"));
|
||
EncodeCommand((argc - 1), &(argv[1]));
|
||
|
||
} else if (!IsHexNumber(argv[1])) {
|
||
|
||
//
|
||
// probably a string, so find matches?
|
||
//
|
||
|
||
DebugPrint((3, "main => non-hex argument, searching for matches\n"));
|
||
FindCommand((argc - 1), &(argv[1]));
|
||
|
||
} else {
|
||
|
||
//
|
||
// only one number passed in, so decode it
|
||
//
|
||
|
||
DebugPrint((3, "main => one hex argument, decoding\n"));
|
||
DecodeCommand((argc - 1), &(argv[1]));
|
||
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
|
||
ULONG32 ListCommand()
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Prints out the command list (help)
|
||
|
||
Arguments:
|
||
|
||
argc - unused
|
||
argv - unused
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS
|
||
|
||
--*/
|
||
|
||
{
|
||
printf("\n"
|
||
"CtlCode encodes/decodes ioctls into their four parts\n"
|
||
"(device type, function, method, access) and prints them out\n"
|
||
"symbolically. If encoding an ioctl, symbolic names can be\n"
|
||
"used for many inputs:\n"
|
||
"\tDevice Type (can drop the FILE_DEVICE prefix)\n"
|
||
"\tFunction (not applicable)\n"
|
||
"\tMethods (can drop the METHOD_ prefix)\n"
|
||
"\tAccess (can drop the FILE_ prefix and/or _ACCESS postfix)\n"
|
||
"\n"
|
||
"Also, any search string with only one match will give\n"
|
||
"full information. The following two commands are\n"
|
||
"equivalent if no other ioctl has the substring 'UNLOAD':\n"
|
||
"\tCtlCode.exe IOCTL_CDROM_UNLOAD_DRIVER\n"
|
||
"\tCtlCode.exe UNLOAD\n"
|
||
"\n"
|
||
"All input and output is in hexadecimal"
|
||
" string - prints all matches\n"
|
||
" # - decodes the ioctl\n"
|
||
" # # # # - encodes the ioctl base/#/method/access\n"
|
||
);
|
||
return 0;
|
||
}
|
||
|
||
VOID FindCommand(int argc, char *argv[])
|
||
{
|
||
char * currentPosition;
|
||
size_t arglen;
|
||
BOOLEAN found;
|
||
LONG i;
|
||
LONG j;
|
||
LONG numberOfMatches;
|
||
LONG lastMatch;
|
||
|
||
DebugPrint((3, "Find => entering\n"));
|
||
|
||
if (argc != 1) {
|
||
DebugPrint((0,
|
||
"Find !! Programming error !!\n"
|
||
"Find !! should only pass in one string !!\n"
|
||
"Find !! to match against. Passed in %2x !!\n",
|
||
argc + 1
|
||
));
|
||
return;
|
||
}
|
||
|
||
numberOfMatches = 0;
|
||
|
||
//
|
||
// for each name in the table
|
||
//
|
||
|
||
for (j=0;TableIoctlValue[j].Name != NULL;j++) {
|
||
|
||
currentPosition = TableIoctlValue[j].Name;
|
||
found = FALSE;
|
||
|
||
//
|
||
// see if we can match it to any argument
|
||
//
|
||
DebugPrint((3, "Find => matching against table entry %x\n", j));
|
||
|
||
arglen = strlen(argv[0]);
|
||
|
||
//
|
||
// accept partial matches to any substring
|
||
//
|
||
while (*currentPosition != 0) {
|
||
|
||
if (_strnicmp(argv[0],
|
||
currentPosition,
|
||
arglen)==0) {
|
||
found = TRUE;
|
||
break; // out of while loop
|
||
}
|
||
currentPosition++;
|
||
|
||
}
|
||
|
||
//
|
||
// if found, print it.
|
||
//
|
||
if (found) {
|
||
|
||
if (numberOfMatches == 0) {
|
||
|
||
//
|
||
// don't print the first match right away,
|
||
// as it may be the only match, which should
|
||
// then be decoded
|
||
//
|
||
|
||
DebugPrint((3, "Find => First Match (%x) found\n", j));
|
||
lastMatch = j;
|
||
|
||
} else if (numberOfMatches == 1) {
|
||
|
||
//
|
||
// if this is the second match, print the header
|
||
// and previous match info also
|
||
//
|
||
|
||
DebugPrint((3, "Find => Second Match (%x) found\n", j));
|
||
printf("Found the following matches:\n");
|
||
printf("\t%-40s - %16x\n",
|
||
TableIoctlValue[lastMatch].Name,
|
||
TableIoctlValue[lastMatch].Code);
|
||
printf("\t%-40s - %16x\n",
|
||
TableIoctlValue[j].Name,
|
||
TableIoctlValue[j].Code);
|
||
} else {
|
||
|
||
DebugPrint((3, "Find => Another Match (%x) found\n", j));
|
||
printf("\t%-40s - %16x\n",
|
||
TableIoctlValue[j].Name,
|
||
TableIoctlValue[j].Code);
|
||
|
||
}
|
||
|
||
numberOfMatches++;
|
||
} // end if (found) {}
|
||
|
||
} // end of loop through table
|
||
|
||
DebugPrint((2, "Find => Found %x matches total\n", numberOfMatches));
|
||
|
||
//
|
||
// if didn't find any matches, tell them so.
|
||
//
|
||
if (numberOfMatches == 0) {
|
||
printf("No matches found.\n");
|
||
} else if (numberOfMatches == 1) {
|
||
DebugPrint((2, "Find => Decoding ioctl at index (%x)\n", lastMatch));
|
||
DecodeIoctl((PVOID)&(TableIoctlValue[lastMatch].Code));
|
||
}
|
||
|
||
}
|
||
ULONG32 EncodeCommand(int argc, char *argv[])
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Change four components into a Ctl_Code
|
||
|
||
Arguments:
|
||
|
||
argc - the number of additional arguments. prompt if zero
|
||
argv - the additional arguments
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS if successful
|
||
|
||
--*/
|
||
{
|
||
CTL_CODE maxValues;
|
||
CTL_CODE encoded;
|
||
ULONG temp;
|
||
|
||
encoded.Code = 0;
|
||
maxValues.Code = -1; // all 1's
|
||
|
||
DebugPrint((3, "Encode => entering\n"));
|
||
|
||
// device type
|
||
if (IsHexNumber(argv[0])) {
|
||
|
||
//
|
||
// read and verify the hex number
|
||
//
|
||
DebugPrint((3, "Encode => arg 1 is hex\n"));
|
||
|
||
temp = strtol(argv[0], (char**)NULL, 0x10);
|
||
if (temp > maxValues.DeviceType) {
|
||
printf("Max Device Type: %x\n", maxValues.DeviceType);
|
||
return STATUS_SUCCESS;
|
||
}
|
||
encoded.DeviceType = temp;
|
||
|
||
} else {
|
||
|
||
//
|
||
// read and match the device type
|
||
//
|
||
|
||
DebugPrint((3, "Encode => arg 1 is non-hex, attempting "
|
||
"string match\n"));
|
||
|
||
for (temp = 0; temp < MAX_IOCTL_DEVICE_TYPE; temp++) {
|
||
|
||
if (_stricmp(TableIoctlDeviceType[temp].Name, argv[0]) == 0) {
|
||
DebugPrint((2, "Encode => arg 1 matched index %x (full)\n",
|
||
temp));
|
||
encoded.DeviceType = TableIoctlDeviceType[temp].Value;
|
||
break;
|
||
}
|
||
|
||
//
|
||
// no need to have common prefixes
|
||
//
|
||
if ((strlen(TableIoctlDeviceType[temp].Name) > strlen("FILE_DEVICE_"))
|
||
&&
|
||
(_stricmp(TableIoctlDeviceType[temp].Name + strlen("FILE_DEVICE_"),argv[0]) == 0)
|
||
) {
|
||
DebugPrint((2, "Encode => arg 1 matched index %x "
|
||
"(dropped prefix)\n", temp));
|
||
encoded.DeviceType = TableIoctlDeviceType[temp].Value;
|
||
break;
|
||
}
|
||
|
||
}
|
||
|
||
if (temp == MAX_IOCTL_DEVICE_TYPE) {
|
||
printf("Device Type unknown. Known Device Types:\n");
|
||
for (temp = 0; temp < MAX_IOCTL_DEVICE_TYPE; temp++) {
|
||
printf("\t%s\n", TableIoctlDeviceType[temp].Name);
|
||
}
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
DebugPrint((3, "Encode => arg 1 matched string index %x\n", temp));
|
||
|
||
}
|
||
|
||
// function number
|
||
if (IsHexNumber(argv[1])) {
|
||
|
||
DebugPrint((3, "Encode => arg 2 is hex\n"));
|
||
|
||
//
|
||
// read and verify the hex number
|
||
//
|
||
|
||
temp = strtol(argv[1], (char**)NULL, 0x10);
|
||
if (temp > maxValues.Function) {
|
||
printf("Max Function: %x\n", maxValues.Function);
|
||
return STATUS_SUCCESS;
|
||
}
|
||
encoded.Function = temp;
|
||
|
||
} else {
|
||
|
||
printf("Function: must be a hex number\n");
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
// method
|
||
if (IsHexNumber(argv[2])) {
|
||
|
||
DebugPrint((3, "Encode => arg 3 is hex\n"));
|
||
|
||
//
|
||
// read and verify the hex number
|
||
//
|
||
|
||
temp = strtol(argv[2], (char**)NULL, 0x10);
|
||
if (temp > maxValues.Method) {
|
||
printf("Max Method: %x\n", maxValues.Method);
|
||
return STATUS_SUCCESS;
|
||
}
|
||
encoded.Method = temp;
|
||
|
||
} else {
|
||
|
||
|
||
DebugPrint((3, "Encode => arg 3 is non-hex, attempting string "
|
||
"match\n"));
|
||
|
||
//
|
||
// read and match the method
|
||
//
|
||
|
||
for (temp = 0; temp < MAX_IOCTL_METHOD; temp++) {
|
||
|
||
if (_stricmp(TableIoctlMethod[temp].Name, argv[2]) == 0) {
|
||
DebugPrint((2, "Encode => arg 3 matched index %x\n", temp));
|
||
encoded.Method = TableIoctlMethod[temp].Value;
|
||
break;
|
||
}
|
||
|
||
//
|
||
// no need to have common prefixes
|
||
//
|
||
if ((strlen(TableIoctlMethod[temp].Name) > strlen("METHOD_"))
|
||
&&
|
||
(_stricmp(TableIoctlMethod[temp].Name + strlen("METHOD_"),argv[2]) == 0)
|
||
) {
|
||
DebugPrint((2, "Encode => arg 3 matched index %x "
|
||
"(dropped prefix)\n", temp));
|
||
encoded.Method = TableIoctlMethod[temp].Value;
|
||
break;
|
||
}
|
||
|
||
|
||
} // end ioctl_method loop
|
||
|
||
if (temp == MAX_IOCTL_METHOD) {
|
||
printf("Method %s unknown. Known methods:\n", argv[2]);
|
||
for (temp = 0; temp < MAX_IOCTL_METHOD; temp++) {
|
||
printf("\t%s\n", TableIoctlMethod[temp].Name);
|
||
}
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
}
|
||
|
||
// access
|
||
if (IsHexNumber(argv[3])) {
|
||
|
||
//
|
||
// read and verify the hex number
|
||
//
|
||
|
||
DebugPrint((3, "Encode => arg 4 is hex\n"));
|
||
|
||
temp = strtol(argv[3], (char**)NULL, 0x10);
|
||
if (temp > maxValues.Access) {
|
||
printf("Max Device Type: %x\n", maxValues.Access);
|
||
return STATUS_SUCCESS;
|
||
}
|
||
encoded.Access = temp;
|
||
|
||
} else {
|
||
|
||
DebugPrint((3, "Encode => arg 4 is non-hex, attempting to "
|
||
"match strings\n", temp));
|
||
|
||
|
||
//
|
||
// read and match the access type
|
||
//
|
||
|
||
DebugPrint((4, "Encode => Trying to match %s\n", argv[3]));
|
||
|
||
for (temp = 0; temp < MAX_IOCTL_ACCESS; temp++) {
|
||
|
||
int tLen;
|
||
size_t tDrop;
|
||
char *string;
|
||
char *match;
|
||
|
||
//
|
||
// match the whole string?
|
||
//
|
||
|
||
string = argv[3];
|
||
match = TableIoctlAccess[temp].Name;
|
||
|
||
DebugPrint((4, "Encode ?? test match against %s\n", match));
|
||
|
||
if (_stricmp(match, string) == 0) {
|
||
DebugPrint((2, "Encode => arg 4 matched index %x (full)\n",
|
||
temp));
|
||
encoded.Access = TableIoctlAccess[temp].Value;
|
||
break;
|
||
}
|
||
|
||
//
|
||
// maybe match without the trailing _ACCESS?
|
||
//
|
||
|
||
tLen = strlen(match) - strlen("_ACCESS");
|
||
|
||
DebugPrint((4, "Encode ?? test match against %s (%x chars)\n",
|
||
match, tLen));
|
||
|
||
if (_strnicmp(match, string, tLen) == 0) {
|
||
DebugPrint((2, "Encode => arg 4 matched index %x "
|
||
"(dropped postfix)\n", temp));
|
||
encoded.Access = TableIoctlAccess[temp].Value;
|
||
break;
|
||
}
|
||
|
||
//
|
||
// no need to have common prefixes
|
||
//
|
||
|
||
match += strlen("FILE_");
|
||
|
||
DebugPrint((4, "Encode ?? test match against %s\n", match));
|
||
|
||
if (_stricmp(match, string) == 0) {
|
||
DebugPrint((2, "Encode => arg 4 matched index %x "
|
||
"(dropped prefix)\n", temp));
|
||
encoded.Access = TableIoctlAccess[temp].Value;
|
||
break;
|
||
}
|
||
|
||
tLen = strlen(match) - strlen("_ACCESS");
|
||
|
||
//
|
||
// maybe match without prefix or suffix?
|
||
//
|
||
|
||
DebugPrint((4, "Encode ?? test match against %s (%x chars)\n",
|
||
match, tLen));
|
||
|
||
if (_strnicmp(match, string, tLen) == 0) {
|
||
DebugPrint((2, "Encode => arg 4 matched index %x "
|
||
"(dropped prefix and postfix)\n", temp));
|
||
encoded.Access = TableIoctlAccess[temp].Value;
|
||
break;
|
||
}
|
||
|
||
} // end ioctl_access loop
|
||
|
||
|
||
if (temp == MAX_IOCTL_ACCESS) {
|
||
printf("Access %s unknown. Known Access Types:\n", argv[3]);
|
||
for (temp = 0; temp < MAX_IOCTL_ACCESS; temp++) {
|
||
printf("\t%s\n", TableIoctlAccess[temp].Name);
|
||
}
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
}
|
||
|
||
DecodeIoctl(&encoded);
|
||
|
||
//
|
||
// file type of 0 == unknown type
|
||
//
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
ULONG32 DecodeCommand(int argc, char *argv[])
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Change a Ctl_Code into four components
|
||
|
||
Arguments:
|
||
|
||
argc - the number of additional arguments. prompt if zero
|
||
argv - the additional arguments
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS if successful
|
||
|
||
--*/
|
||
{
|
||
CTL_CODE ctlCode;
|
||
ULONG i;
|
||
|
||
DebugPrint((3, "Decode => Entering\n"));
|
||
|
||
ctlCode.Code = strtoul(argv[0], (char**)NULL, 0x10);
|
||
|
||
DecodeIoctl(&ctlCode);
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
VOID
|
||
DecodeIoctl(
|
||
PCTL_CODE CtlCode
|
||
)
|
||
{
|
||
ULONG i;
|
||
|
||
for (i = 0; TableIoctlValue[i].Name != NULL; i++) {
|
||
if (TableIoctlValue[i].Code == CtlCode->Code) break;
|
||
}
|
||
|
||
printf(" Ioctl: %08x %s\n",
|
||
CtlCode->Code,
|
||
(TableIoctlValue[i].Name ? TableIoctlValue[i].Name : "Unknown")
|
||
);
|
||
|
||
printf("DeviceType: %04x - ", CtlCode->DeviceType);
|
||
if (CtlCode->DeviceType > MAX_IOCTL_DEVICE_TYPE) {
|
||
printf("Unknown\n");
|
||
} else {
|
||
printf("%s\n", TableIoctlDeviceType[ CtlCode->DeviceType ].Name);
|
||
}
|
||
|
||
printf(" Function: %04x \n", CtlCode->Function);
|
||
|
||
printf(" Method: %04x - %s\n",
|
||
CtlCode->Method,
|
||
TableIoctlMethod[CtlCode->Method].Name
|
||
);
|
||
|
||
printf(" Access: %04x - %s\n",
|
||
CtlCode->Access,
|
||
TableIoctlAccess[CtlCode->Access].Name
|
||
);
|
||
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
ULONG32 AttenuateCommand( int argc, char *argv[])
|
||
{
|
||
LONG32 i;
|
||
LONG32 j;
|
||
long double val[] = {
|
||
0xff, 0xf0, 0xe0, 0xc0,
|
||
0x80, 0x40, 0x20, 0x10,
|
||
0x0f, 0x0e, 0x0c, 0x08,
|
||
0x04, 0x02, 0x01, 0x00
|
||
};
|
||
long double temp;
|
||
|
||
printf( "\nATTENUATION AttenuationTable[] = {\n" );
|
||
|
||
for ( i=0; i < sizeof(val)/sizeof(val[0]); i++ ) {
|
||
temp = val[i];
|
||
temp = 20 * log10( temp / 256.0 );
|
||
temp = temp * 65536;
|
||
printf( " { 0x%08x, 0x%02x },\n", (LONG)temp, (LONG)val[i] );
|
||
|
||
}
|
||
printf( "};\n" );
|
||
|
||
return STATUS_SUCCESS;
|
||
|
||
}
|
||
|
||
BOOLEAN
|
||
IsHexNumber(
|
||
const char *szExpression
|
||
)
|
||
{
|
||
if (!szExpression[0]) {
|
||
return FALSE ;
|
||
}
|
||
|
||
for(;*szExpression; szExpression++) {
|
||
|
||
if ((*szExpression)< '0') { return FALSE ; }
|
||
else if ((*szExpression)> 'f') { return FALSE ; }
|
||
else if ((*szExpression)>='a') { continue ; }
|
||
else if ((*szExpression)> 'F') { return FALSE ; }
|
||
else if ((*szExpression)<='9') { continue ; }
|
||
else if ((*szExpression)>='A') { continue ; }
|
||
else { return FALSE ; }
|
||
}
|
||
return TRUE ;
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
IsDecNumber(
|
||
const char *szExpression
|
||
)
|
||
{
|
||
if (!szExpression[0]) {
|
||
return FALSE ;
|
||
}
|
||
|
||
while(*szExpression) {
|
||
|
||
if ((*szExpression)<'0') { return FALSE ; }
|
||
else if ((*szExpression)>'9') { return FALSE ; }
|
||
szExpression ++ ;
|
||
}
|
||
return TRUE ;
|
||
}
|
||
|