Source code of Windows XP (NT5)
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.

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