Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

757 lines
19 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. CtlCode.c
  5. Abstract:
  6. A user mode app that breaks down a CTL_CODE (from IOCTL Irp)
  7. Into its component parts of BASE, #, Method, and Access.
  8. Environment:
  9. User mode only
  10. Revision History:
  11. 07-14-98 : Created by henrygab
  12. --*/
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <stdarg.h>
  16. #include <string.h>
  17. #include <math.h>
  18. #include <winerror.h>
  19. #include <strsafe.h>
  20. #include "CtlCode.h"
  21. #if DBG
  22. #define DEBUG_BUFFER_LENGTH 1000
  23. ULONG DebugLevel = 0;
  24. UCHAR DebugBuffer[DEBUG_BUFFER_LENGTH];
  25. VOID
  26. __cdecl
  27. CtlCodeDebugPrint(
  28. ULONG DebugPrintLevel,
  29. PCCHAR DebugMessage,
  30. ...
  31. )
  32. {
  33. if ((DebugPrintLevel <= (DebugLevel & 0x0000ffff)) ||
  34. ((1 << (DebugPrintLevel + 15)) & DebugLevel)
  35. ) {
  36. HRESULT hr;
  37. va_list ap;
  38. va_start(ap, DebugMessage);
  39. hr = StringCchVPrintf(DebugBuffer,
  40. DEBUG_BUFFER_LENGTH,
  41. DebugMessage,
  42. ap);
  43. if ((HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER) || SUCCEEDED(hr)) {
  44. fprintf(stderr, DebugBuffer);
  45. }
  46. va_end(ap);
  47. }
  48. }
  49. #define DebugPrint(x) CtlCodeDebugPrint x
  50. #else
  51. #define DebugPrint(x)
  52. #endif // DBG
  53. VOID
  54. DecodeIoctl(
  55. PCTL_CODE CtlCode
  56. );
  57. BOOLEAN
  58. IsHexNumber(
  59. const char *szExpression
  60. );
  61. BOOLEAN
  62. IsDecNumber(
  63. const char *szExpression
  64. );
  65. //
  66. // List of commands
  67. // all command names are case sensitive
  68. // arguments are passed into command routines
  69. // list must be terminated with NULL command
  70. // command will not be listed in help if description == NULL
  71. //
  72. ULONG32 ListCommand();
  73. //
  74. // prints an attenuation table based off cdrom standard volume
  75. //
  76. ULONG32 AttenuateCommand( int argc, char *argv[]);
  77. VOID FindCommand(int argc, char *argv[]);
  78. ULONG32 DecodeCommand(int argc, char *argv[]);
  79. ULONG32 EncodeCommand(int argc, char *argv[]);
  80. int __cdecl main(int argc, char *argv[])
  81. /*++
  82. Routine Description:
  83. Parses input, showing help or calling function requested appropriately
  84. Return Value:
  85. 0 - success
  86. -1 - insufficient arguments
  87. -2 - error opening device (DNE?)
  88. --*/
  89. {
  90. int i = 0;
  91. DebugPrint((3, "main => entering\n"));
  92. if (argc < 2 ||
  93. !strcmp(argv[1], "-?") ||
  94. !strcmp(argv[1], "-h") ||
  95. !strcmp(argv[1], "/?") ||
  96. !strcmp(argv[1], "/h")
  97. ) {
  98. DebugPrint((3, "main => Help requested...\n"));
  99. ListCommand();
  100. return -1;
  101. }
  102. if (argc != 2 && argc != 5) {
  103. DebugPrint((3, "main => bad argc: %x, printing help\n", argc));
  104. printf("Usage: ctl_code [parameters]\n");
  105. return ListCommand();
  106. }
  107. if (argc == 5) {
  108. DebugPrint((3, "main => encoding four args to one ioctl\n"));
  109. EncodeCommand((argc - 1), &(argv[1]));
  110. } else if (!IsHexNumber(argv[1])) {
  111. //
  112. // probably a string, so find matches?
  113. //
  114. DebugPrint((3, "main => non-hex argument, searching for matches\n"));
  115. FindCommand((argc - 1), &(argv[1]));
  116. } else {
  117. //
  118. // only one number passed in, so decode it
  119. //
  120. DebugPrint((3, "main => one hex argument, decoding\n"));
  121. DecodeCommand((argc - 1), &(argv[1]));
  122. }
  123. return 0;
  124. }
  125. ULONG32 ListCommand()
  126. /*++
  127. Routine Description:
  128. Prints out the command list (help)
  129. Arguments:
  130. argc - unused
  131. argv - unused
  132. Return Value:
  133. STATUS_SUCCESS
  134. --*/
  135. {
  136. printf("\n"
  137. "CtlCode encodes/decodes ioctls into their four parts\n"
  138. "(device type, function, method, access) and prints them out\n"
  139. "symbolically. If encoding an ioctl, symbolic names can be\n"
  140. "used for many inputs:\n"
  141. "\tDevice Type (can drop the FILE_DEVICE prefix)\n"
  142. "\tFunction (not applicable)\n"
  143. "\tMethods (can drop the METHOD_ prefix)\n"
  144. "\tAccess (can drop the FILE_ prefix and/or _ACCESS postfix)\n"
  145. "\n"
  146. "Also, any search string with only one match will give\n"
  147. "full information. The following two commands are\n"
  148. "equivalent if no other ioctl has the substring 'UNLOAD':\n"
  149. "\tCtlCode.exe IOCTL_CDROM_UNLOAD_DRIVER\n"
  150. "\tCtlCode.exe UNLOAD\n"
  151. "\n"
  152. "All input and output is in hexadecimal"
  153. " string - prints all matches\n"
  154. " # - decodes the ioctl\n"
  155. " # # # # - encodes the ioctl base/#/method/access\n"
  156. );
  157. return 0;
  158. }
  159. VOID FindCommand(int argc, char *argv[])
  160. {
  161. char * currentPosition;
  162. size_t arglen;
  163. BOOLEAN found;
  164. LONG i;
  165. LONG j;
  166. LONG numberOfMatches;
  167. LONG lastMatch;
  168. DebugPrint((3, "Find => entering\n"));
  169. if (argc != 1) {
  170. DebugPrint((0,
  171. "Find !! Programming error !!\n"
  172. "Find !! should only pass in one string !!\n"
  173. "Find !! to match against. Passed in %2x !!\n",
  174. argc + 1
  175. ));
  176. return;
  177. }
  178. numberOfMatches = 0;
  179. //
  180. // for each name in the table
  181. //
  182. for (j=0;TableIoctlValue[j].Name != NULL;j++) {
  183. currentPosition = TableIoctlValue[j].Name;
  184. found = FALSE;
  185. //
  186. // see if we can match it to any argument
  187. //
  188. DebugPrint((3, "Find => matching against table entry %x\n", j));
  189. arglen = strlen(argv[0]);
  190. //
  191. // accept partial matches to any substring
  192. //
  193. while (*currentPosition != 0) {
  194. if (_strnicmp(argv[0],
  195. currentPosition,
  196. arglen)==0) {
  197. found = TRUE;
  198. break; // out of while loop
  199. }
  200. currentPosition++;
  201. }
  202. //
  203. // if found, print it.
  204. //
  205. if (found) {
  206. if (numberOfMatches == 0) {
  207. //
  208. // don't print the first match right away,
  209. // as it may be the only match, which should
  210. // then be decoded
  211. //
  212. DebugPrint((3, "Find => First Match (%x) found\n", j));
  213. lastMatch = j;
  214. } else if (numberOfMatches == 1) {
  215. //
  216. // if this is the second match, print the header
  217. // and previous match info also
  218. //
  219. DebugPrint((3, "Find => Second Match (%x) found\n", j));
  220. printf("Found the following matches:\n");
  221. printf("\t%-40s - %16x\n",
  222. TableIoctlValue[lastMatch].Name,
  223. TableIoctlValue[lastMatch].Code);
  224. printf("\t%-40s - %16x\n",
  225. TableIoctlValue[j].Name,
  226. TableIoctlValue[j].Code);
  227. } else {
  228. DebugPrint((3, "Find => Another Match (%x) found\n", j));
  229. printf("\t%-40s - %16x\n",
  230. TableIoctlValue[j].Name,
  231. TableIoctlValue[j].Code);
  232. }
  233. numberOfMatches++;
  234. } // end if (found) {}
  235. } // end of loop through table
  236. DebugPrint((2, "Find => Found %x matches total\n", numberOfMatches));
  237. //
  238. // if didn't find any matches, tell them so.
  239. //
  240. if (numberOfMatches == 0) {
  241. printf("No matches found.\n");
  242. } else if (numberOfMatches == 1) {
  243. DebugPrint((2, "Find => Decoding ioctl at index (%x)\n", lastMatch));
  244. DecodeIoctl((PVOID)&(TableIoctlValue[lastMatch].Code));
  245. }
  246. }
  247. ULONG32 EncodeCommand(int argc, char *argv[])
  248. /*++
  249. Routine Description:
  250. Change four components into a Ctl_Code
  251. Arguments:
  252. argc - the number of additional arguments. prompt if zero
  253. argv - the additional arguments
  254. Return Value:
  255. STATUS_SUCCESS if successful
  256. --*/
  257. {
  258. CTL_CODE maxValues;
  259. CTL_CODE encoded;
  260. ULONG temp;
  261. encoded.Code = 0;
  262. maxValues.Code = -1; // all 1's
  263. DebugPrint((3, "Encode => entering\n"));
  264. // device type
  265. if (IsHexNumber(argv[0])) {
  266. //
  267. // read and verify the hex number
  268. //
  269. DebugPrint((3, "Encode => arg 1 is hex\n"));
  270. temp = strtol(argv[0], (char**)NULL, 0x10);
  271. if (temp > maxValues.DeviceType) {
  272. printf("Max Device Type: %x\n", maxValues.DeviceType);
  273. return STATUS_SUCCESS;
  274. }
  275. encoded.DeviceType = temp;
  276. } else {
  277. //
  278. // read and match the device type
  279. //
  280. DebugPrint((3, "Encode => arg 1 is non-hex, attempting "
  281. "string match\n"));
  282. for (temp = 0; temp < MAX_IOCTL_DEVICE_TYPE; temp++) {
  283. if (_stricmp(TableIoctlDeviceType[temp].Name, argv[0]) == 0) {
  284. DebugPrint((2, "Encode => arg 1 matched index %x (full)\n",
  285. temp));
  286. encoded.DeviceType = TableIoctlDeviceType[temp].Value;
  287. break;
  288. }
  289. //
  290. // no need to have common prefixes
  291. //
  292. if ((strlen(TableIoctlDeviceType[temp].Name) > strlen("FILE_DEVICE_"))
  293. &&
  294. (_stricmp(TableIoctlDeviceType[temp].Name + strlen("FILE_DEVICE_"),argv[0]) == 0)
  295. ) {
  296. DebugPrint((2, "Encode => arg 1 matched index %x "
  297. "(dropped prefix)\n", temp));
  298. encoded.DeviceType = TableIoctlDeviceType[temp].Value;
  299. break;
  300. }
  301. }
  302. if (temp == MAX_IOCTL_DEVICE_TYPE) {
  303. printf("Device Type unknown. Known Device Types:\n");
  304. for (temp = 0; temp < MAX_IOCTL_DEVICE_TYPE; temp++) {
  305. printf("\t%s\n", TableIoctlDeviceType[temp].Name);
  306. }
  307. return STATUS_SUCCESS;
  308. }
  309. DebugPrint((3, "Encode => arg 1 matched string index %x\n", temp));
  310. }
  311. // function number
  312. if (IsHexNumber(argv[1])) {
  313. DebugPrint((3, "Encode => arg 2 is hex\n"));
  314. //
  315. // read and verify the hex number
  316. //
  317. temp = strtol(argv[1], (char**)NULL, 0x10);
  318. if (temp > maxValues.Function) {
  319. printf("Max Function: %x\n", maxValues.Function);
  320. return STATUS_SUCCESS;
  321. }
  322. encoded.Function = temp;
  323. } else {
  324. printf("Function: must be a hex number\n");
  325. return STATUS_SUCCESS;
  326. }
  327. // method
  328. if (IsHexNumber(argv[2])) {
  329. DebugPrint((3, "Encode => arg 3 is hex\n"));
  330. //
  331. // read and verify the hex number
  332. //
  333. temp = strtol(argv[2], (char**)NULL, 0x10);
  334. if (temp > maxValues.Method) {
  335. printf("Max Method: %x\n", maxValues.Method);
  336. return STATUS_SUCCESS;
  337. }
  338. encoded.Method = temp;
  339. } else {
  340. DebugPrint((3, "Encode => arg 3 is non-hex, attempting string "
  341. "match\n"));
  342. //
  343. // read and match the method
  344. //
  345. for (temp = 0; temp < MAX_IOCTL_METHOD; temp++) {
  346. if (_stricmp(TableIoctlMethod[temp].Name, argv[2]) == 0) {
  347. DebugPrint((2, "Encode => arg 3 matched index %x\n", temp));
  348. encoded.Method = TableIoctlMethod[temp].Value;
  349. break;
  350. }
  351. //
  352. // no need to have common prefixes
  353. //
  354. if ((strlen(TableIoctlMethod[temp].Name) > strlen("METHOD_"))
  355. &&
  356. (_stricmp(TableIoctlMethod[temp].Name + strlen("METHOD_"),argv[2]) == 0)
  357. ) {
  358. DebugPrint((2, "Encode => arg 3 matched index %x "
  359. "(dropped prefix)\n", temp));
  360. encoded.Method = TableIoctlMethod[temp].Value;
  361. break;
  362. }
  363. } // end ioctl_method loop
  364. if (temp == MAX_IOCTL_METHOD) {
  365. printf("Method %s unknown. Known methods:\n", argv[2]);
  366. for (temp = 0; temp < MAX_IOCTL_METHOD; temp++) {
  367. printf("\t%s\n", TableIoctlMethod[temp].Name);
  368. }
  369. return STATUS_SUCCESS;
  370. }
  371. }
  372. // access
  373. if (IsHexNumber(argv[3])) {
  374. //
  375. // read and verify the hex number
  376. //
  377. DebugPrint((3, "Encode => arg 4 is hex\n"));
  378. temp = strtol(argv[3], (char**)NULL, 0x10);
  379. if (temp > maxValues.Access) {
  380. printf("Max Device Type: %x\n", maxValues.Access);
  381. return STATUS_SUCCESS;
  382. }
  383. encoded.Access = temp;
  384. } else {
  385. DebugPrint((3, "Encode => arg 4 is non-hex, attempting to "
  386. "match strings\n", temp));
  387. //
  388. // read and match the access type
  389. //
  390. DebugPrint((4, "Encode => Trying to match %s\n", argv[3]));
  391. for (temp = 0; temp < MAX_IOCTL_ACCESS; temp++) {
  392. int tLen;
  393. size_t tDrop;
  394. char *string;
  395. char *match;
  396. //
  397. // match the whole string?
  398. //
  399. string = argv[3];
  400. match = TableIoctlAccess[temp].Name;
  401. DebugPrint((4, "Encode ?? test match against %s\n", match));
  402. if (_stricmp(match, string) == 0) {
  403. DebugPrint((2, "Encode => arg 4 matched index %x (full)\n",
  404. temp));
  405. encoded.Access = TableIoctlAccess[temp].Value;
  406. break;
  407. }
  408. //
  409. // maybe match without the trailing _ACCESS?
  410. //
  411. tLen = strlen(match) - strlen("_ACCESS");
  412. DebugPrint((4, "Encode ?? test match against %s (%x chars)\n",
  413. match, tLen));
  414. if (_strnicmp(match, string, tLen) == 0) {
  415. DebugPrint((2, "Encode => arg 4 matched index %x "
  416. "(dropped postfix)\n", temp));
  417. encoded.Access = TableIoctlAccess[temp].Value;
  418. break;
  419. }
  420. //
  421. // no need to have common prefixes
  422. //
  423. match += strlen("FILE_");
  424. DebugPrint((4, "Encode ?? test match against %s\n", match));
  425. if (_stricmp(match, string) == 0) {
  426. DebugPrint((2, "Encode => arg 4 matched index %x "
  427. "(dropped prefix)\n", temp));
  428. encoded.Access = TableIoctlAccess[temp].Value;
  429. break;
  430. }
  431. tLen = strlen(match) - strlen("_ACCESS");
  432. //
  433. // maybe match without prefix or suffix?
  434. //
  435. DebugPrint((4, "Encode ?? test match against %s (%x chars)\n",
  436. match, tLen));
  437. if (_strnicmp(match, string, tLen) == 0) {
  438. DebugPrint((2, "Encode => arg 4 matched index %x "
  439. "(dropped prefix and postfix)\n", temp));
  440. encoded.Access = TableIoctlAccess[temp].Value;
  441. break;
  442. }
  443. } // end ioctl_access loop
  444. if (temp == MAX_IOCTL_ACCESS) {
  445. printf("Access %s unknown. Known Access Types:\n", argv[3]);
  446. for (temp = 0; temp < MAX_IOCTL_ACCESS; temp++) {
  447. printf("\t%s\n", TableIoctlAccess[temp].Name);
  448. }
  449. return STATUS_SUCCESS;
  450. }
  451. }
  452. DecodeIoctl(&encoded);
  453. //
  454. // file type of 0 == unknown type
  455. //
  456. return STATUS_SUCCESS;
  457. }
  458. ULONG32 DecodeCommand(int argc, char *argv[])
  459. /*++
  460. Routine Description:
  461. Change a Ctl_Code into four components
  462. Arguments:
  463. argc - the number of additional arguments. prompt if zero
  464. argv - the additional arguments
  465. Return Value:
  466. STATUS_SUCCESS if successful
  467. --*/
  468. {
  469. CTL_CODE ctlCode;
  470. ULONG i;
  471. DebugPrint((3, "Decode => Entering\n"));
  472. ctlCode.Code = strtoul(argv[0], (char**)NULL, 0x10);
  473. DecodeIoctl(&ctlCode);
  474. return STATUS_SUCCESS;
  475. }
  476. VOID
  477. DecodeIoctl(
  478. PCTL_CODE CtlCode
  479. )
  480. {
  481. ULONG i;
  482. for (i = 0; TableIoctlValue[i].Name != NULL; i++) {
  483. if (TableIoctlValue[i].Code == CtlCode->Code) break;
  484. }
  485. printf(" Ioctl: %08x %s\n",
  486. CtlCode->Code,
  487. (TableIoctlValue[i].Name ? TableIoctlValue[i].Name : "Unknown")
  488. );
  489. printf("DeviceType: %04x - ", CtlCode->DeviceType);
  490. if (CtlCode->DeviceType > MAX_IOCTL_DEVICE_TYPE) {
  491. printf("Unknown\n");
  492. } else {
  493. printf("%s\n", TableIoctlDeviceType[ CtlCode->DeviceType ].Name);
  494. }
  495. printf(" Function: %04x \n", CtlCode->Function);
  496. printf(" Method: %04x - %s\n",
  497. CtlCode->Method,
  498. TableIoctlMethod[CtlCode->Method].Name
  499. );
  500. printf(" Access: %04x - %s\n",
  501. CtlCode->Access,
  502. TableIoctlAccess[CtlCode->Access].Name
  503. );
  504. return;
  505. }
  506. ULONG32 AttenuateCommand( int argc, char *argv[])
  507. {
  508. LONG32 i;
  509. LONG32 j;
  510. long double val[] = {
  511. 0xff, 0xf0, 0xe0, 0xc0,
  512. 0x80, 0x40, 0x20, 0x10,
  513. 0x0f, 0x0e, 0x0c, 0x08,
  514. 0x04, 0x02, 0x01, 0x00
  515. };
  516. long double temp;
  517. printf( "\nATTENUATION AttenuationTable[] = {\n" );
  518. for ( i=0; i < sizeof(val)/sizeof(val[0]); i++ ) {
  519. temp = val[i];
  520. temp = 20 * log10( temp / 256.0 );
  521. temp = temp * 65536;
  522. printf( " { 0x%08x, 0x%02x },\n", (LONG)temp, (LONG)val[i] );
  523. }
  524. printf( "};\n" );
  525. return STATUS_SUCCESS;
  526. }
  527. BOOLEAN
  528. IsHexNumber(
  529. const char *szExpression
  530. )
  531. {
  532. if (!szExpression[0]) {
  533. return FALSE ;
  534. }
  535. for(;*szExpression; szExpression++) {
  536. if ((*szExpression)< '0') { return FALSE ; }
  537. else if ((*szExpression)> 'f') { return FALSE ; }
  538. else if ((*szExpression)>='a') { continue ; }
  539. else if ((*szExpression)> 'F') { return FALSE ; }
  540. else if ((*szExpression)<='9') { continue ; }
  541. else if ((*szExpression)>='A') { continue ; }
  542. else { return FALSE ; }
  543. }
  544. return TRUE ;
  545. }
  546. BOOLEAN
  547. IsDecNumber(
  548. const char *szExpression
  549. )
  550. {
  551. if (!szExpression[0]) {
  552. return FALSE ;
  553. }
  554. while(*szExpression) {
  555. if ((*szExpression)<'0') { return FALSE ; }
  556. else if ((*szExpression)>'9') { return FALSE ; }
  557. szExpression ++ ;
  558. }
  559. return TRUE ;
  560. }