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.

1496 lines
41 KiB

  1. /****************************************************************************
  2. Copyright (c) Microsoft Corporation 1997
  3. All rights reserved
  4. ***************************************************************************/
  5. #include <nt.h>
  6. #include <ntrtl.h>
  7. #include <nturtl.h>
  8. #include <windows.h>
  9. #include <assert.h>
  10. #include <stdio.h>
  11. #include <string.h>
  12. #include <ctype.h>
  13. #include <time.h>
  14. #include <winsock2.h>
  15. #include <ntexapi.h>
  16. #include <devioctl.h>
  17. #include <stdlib.h>
  18. #include <rccxport.h>
  19. #include "rcclib.h"
  20. #include "error.h"
  21. ULONG GlobalBufferCurrentSize;
  22. char *GlobalBuffer = NULL;
  23. ULONG GlobalCommandLineSize;
  24. char *GlobalCommandLine = NULL;
  25. ULONG GlobalReadIndex;
  26. BOOL GlobalPagingNeeded = TRUE;
  27. BOOL GlobalDoThreads = TRUE;
  28. UCHAR *StateTable[] = {
  29. "Initialized",
  30. "Ready",
  31. "Running",
  32. "Standby",
  33. "Terminated",
  34. "Wait:",
  35. "Transition",
  36. "Unknown",
  37. "Unknown",
  38. "Unknown",
  39. "Unknown",
  40. "Unknown"
  41. };
  42. UCHAR *WaitTable[] = {
  43. "Executive",
  44. "FreePage",
  45. "PageIn",
  46. "PoolAllocation",
  47. "DelayExecution",
  48. "Suspended",
  49. "UserRequest",
  50. "Executive",
  51. "FreePage",
  52. "PageIn",
  53. "PoolAllocation",
  54. "DelayExecution",
  55. "Suspended",
  56. "UserRequest",
  57. "EventPairHigh",
  58. "EventPairLow",
  59. "LpcReceive",
  60. "LpcReply",
  61. "VirtualMemory",
  62. "PageOut",
  63. "Spare1",
  64. "Spare2",
  65. "Spare3",
  66. "Spare4",
  67. "Spare5",
  68. "Spare6",
  69. "Spare7",
  70. "Unknown",
  71. "Unknown",
  72. "Unknown"
  73. };
  74. UCHAR *Empty = " ";
  75. DWORD
  76. RCCSrvReportEventA(
  77. DWORD EventID,
  78. DWORD EventType,
  79. DWORD NumStrings,
  80. DWORD DataLength,
  81. LPSTR *Strings,
  82. LPVOID Data
  83. );
  84. DWORD
  85. RCCSrvGetCommandLine(
  86. IN HANDLE ComPortHandle,
  87. OUT PBOOL ControlC
  88. );
  89. DWORD
  90. RCCSrvPrintMsg(
  91. IN HANDLE ComPortHandle,
  92. IN DWORD MessageId,
  93. IN DWORD SystemErrorCode
  94. );
  95. DWORD
  96. RCCSrvPrint(
  97. IN HANDLE ComPortHandle,
  98. IN PUCHAR Buffer,
  99. IN DWORD BufferSize
  100. );
  101. VOID
  102. RCCSrvPrintTListInfo(
  103. IN HANDLE ComPortHandle,
  104. IN PRCC_RSP_TLIST Buffer
  105. );
  106. VOID
  107. RCCSrvPutMore(
  108. IN HANDLE ComPortHandle,
  109. OUT PBOOL ControlC
  110. );
  111. BOOL
  112. AreYouSure(
  113. IN HANDLE ComPortHandle
  114. );
  115. //
  116. //
  117. // Main routine
  118. //
  119. //
  120. int
  121. __cdecl
  122. main(
  123. int argc,
  124. char *argv[]
  125. )
  126. {
  127. NTSTATUS Status;
  128. HANDLE ComPortHandle;
  129. HANDLE RCCHandle = NULL;
  130. DWORD Error;
  131. DWORD BytesReturned;
  132. DWORD ProcessId;
  133. DWORD PrintMessage = 0;
  134. char *NewBuffer;
  135. DWORD ThisProcessId;
  136. DWORD MemoryLimit;
  137. DWORD DataLength;
  138. PUCHAR ComPort;
  139. DCB Dcb;
  140. char *pch;
  141. char *pTemp;
  142. char Command;
  143. BOOL Abort;
  144. STRING String1, String2;
  145. //
  146. // Init the library
  147. //
  148. Error = RCCLibInit(&GlobalBuffer, &GlobalBufferCurrentSize);
  149. if (Error != ERROR_SUCCESS) {
  150. PrintMessage = ERROR_RCCSRV_LIB_INIT_FAILED;
  151. goto Exit;
  152. }
  153. //
  154. // Check for arguments
  155. //
  156. if ((argc > 3) ||
  157. ((argc > 1) && ((argv[1][0] == '-') || (argv[1][0] == '/')))) {
  158. PrintMessage = MSG_RCCSRV_USAGE;
  159. goto Exit;
  160. }
  161. //
  162. // Allocate memory for the command line
  163. //
  164. GlobalCommandLine = VirtualAlloc(NULL,
  165. 80 * sizeof(char),
  166. MEM_COMMIT,
  167. PAGE_READWRITE | PAGE_NOCACHE
  168. );
  169. if (GlobalCommandLine == NULL) {
  170. //
  171. // Log an error!
  172. //
  173. RCCSrvReportEventA(ERROR_RCCSRV_INITIAL_ALLOC_FAILED,
  174. EVENTLOG_ERROR_TYPE,
  175. 0,
  176. 0,
  177. NULL,
  178. NULL
  179. );
  180. PrintMessage = MSG_RCCSRV_GENERAL_FAILURE;
  181. goto Exit;
  182. }
  183. GlobalCommandLineSize = 80 * sizeof(char);
  184. //
  185. // Remember our process ID, so people cannot kill us.
  186. //
  187. ThisProcessId = GetCurrentProcessId();
  188. //
  189. // Open the Remote Command Console driver
  190. //
  191. RCCHandle = CreateFile("\\\\.\\RCC",
  192. GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
  193. FILE_SHARE_READ | FILE_SHARE_WRITE,
  194. NULL,
  195. OPEN_EXISTING, // create disposition.
  196. 0,
  197. 0
  198. );
  199. if (RCCHandle == INVALID_HANDLE_VALUE) {
  200. RCCHandle = NULL;
  201. Error = GetLastError();
  202. RCCSrvReportEventA(ERROR_RCCSRV_OPEN_RCCDRIVER_FAILED,
  203. EVENTLOG_ERROR_TYPE,
  204. 0,
  205. 0,
  206. NULL,
  207. NULL
  208. );
  209. }
  210. //
  211. // Open the serial port
  212. //
  213. if (argc > 1) {
  214. ComPort = argv[1];
  215. } else {
  216. ComPort = "COM1";
  217. }
  218. ComPortHandle = CreateFile(ComPort,
  219. GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
  220. 0,
  221. NULL,
  222. OPEN_EXISTING, // create disposition.
  223. 0,
  224. 0
  225. );
  226. if (ComPortHandle == INVALID_HANDLE_VALUE) {
  227. //
  228. // Log an error!
  229. //
  230. Error = GetLastError();
  231. RCCSrvReportEventA(ERROR_RCCSRV_OPEN_COMPORT_FAILED,
  232. EVENTLOG_ERROR_TYPE,
  233. 0,
  234. 0,
  235. NULL,
  236. NULL
  237. );
  238. PrintMessage = MSG_RCCSRV_GENERAL_FAILURE;
  239. goto Exit;
  240. }
  241. //
  242. // Set the serial port line characteristics
  243. //
  244. Dcb.DCBlength = sizeof(DCB);
  245. if (!GetCommState(ComPortHandle, &Dcb)) {
  246. //
  247. // Log an error!
  248. //
  249. Error = GetLastError();
  250. RCCSrvReportEventA(ERROR_RCCSRV_OPEN_COMPORT_FAILED,
  251. EVENTLOG_ERROR_TYPE,
  252. 0,
  253. 0,
  254. NULL,
  255. NULL
  256. );
  257. PrintMessage = MSG_RCCSRV_GENERAL_FAILURE;
  258. goto Exit;
  259. }
  260. if (argc > 2) {
  261. Dcb.BaudRate = atoi(argv[2]);
  262. } else {
  263. Dcb.BaudRate = 9600;
  264. }
  265. Dcb.ByteSize = 8;
  266. Dcb.Parity = NOPARITY;
  267. Dcb.StopBits = ONESTOPBIT;
  268. if (!SetCommState(ComPortHandle, &Dcb)) {
  269. //
  270. // Log an error!
  271. //
  272. Error = GetLastError();
  273. RCCSrvReportEventA(ERROR_RCCSRV_OPEN_COMPORT_FAILED,
  274. EVENTLOG_ERROR_TYPE,
  275. 0,
  276. 0,
  277. NULL,
  278. NULL
  279. );
  280. PrintMessage = MSG_RCCSRV_GENERAL_FAILURE;
  281. goto Exit;
  282. }
  283. while (1) {
  284. //
  285. // Write the prompt
  286. //
  287. Error = RCCSrvPrintMsg(ComPortHandle, MSG_RCCSRV_PROMPT, 0);
  288. if (Error != ERROR_SUCCESS) {
  289. RCCSrvReportEventA(ERROR_RCCSRV_SEND_FAILED,
  290. EVENTLOG_ERROR_TYPE,
  291. 0,
  292. sizeof(DWORD),
  293. NULL,
  294. &Error
  295. );
  296. goto Exit;
  297. }
  298. //
  299. // Get any response.
  300. //
  301. Error = RCCSrvGetCommandLine(ComPortHandle, &Abort);
  302. if (Error != ERROR_SUCCESS) {
  303. RCCSrvReportEventA(ERROR_RCCSRV_RCV_FAILED,
  304. EVENTLOG_ERROR_TYPE,
  305. 0,
  306. sizeof(DWORD),
  307. NULL,
  308. &Error
  309. );
  310. goto Exit;
  311. }
  312. if (Abort) {
  313. continue;
  314. }
  315. //
  316. // It completed, so we have data in the buffer - verify it and process the message.
  317. //
  318. pch = GlobalCommandLine;
  319. while (((*pch == ' ') || (*pch == '\t')) &&
  320. (pch < (GlobalCommandLine + GlobalCommandLineSize))) {
  321. pch++;
  322. }
  323. if (pch >= (GlobalCommandLine + GlobalCommandLineSize)) {
  324. continue;
  325. }
  326. Command = *pch;
  327. switch (Command) {
  328. case 'c':
  329. case 'C':
  330. //
  331. // Compare the command
  332. //
  333. pTemp = pch;
  334. while ((*pch != '\0') && (*pch != ' ') &&
  335. (pch < (GlobalCommandLine + GlobalCommandLineSize))) {
  336. pch++;
  337. }
  338. if (pch >= (GlobalCommandLine + GlobalCommandLineSize)) {
  339. continue;
  340. }
  341. *pch = '\0';
  342. RtlInitString(&String1, "crashdump");
  343. RtlInitString(&String2, pTemp);
  344. if (!RtlEqualString(&String1, &String2, TRUE)) {
  345. RCCSrvPrintMsg(ComPortHandle, MSG_RCCSRV_HELP, 0);
  346. continue;
  347. }
  348. if (RCCHandle == NULL) {
  349. RCCSrvPrintMsg(ComPortHandle, ERROR_RCCSRV_OPEN_RCCDRIVER_FAILED, 0);
  350. } else {
  351. //
  352. // Send back an acknowledgement that we got the command before starting the crash.
  353. //
  354. if (AreYouSure(ComPortHandle)) {
  355. RCCSrvPrintMsg(ComPortHandle, MSG_RCCSRV_CRASHING, 0);
  356. if (!DeviceIoControl(RCCHandle,
  357. CTL_CODE(FILE_DEVICE_NETWORK, 0x3, METHOD_NEITHER, FILE_ANY_ACCESS),
  358. NULL,
  359. 0,
  360. NULL,
  361. 0,
  362. &BytesReturned,
  363. NULL
  364. )) {
  365. RCCSrvPrintMsg(ComPortHandle, ERROR_RCCSRV_CRASH_FAILED, 0);
  366. }
  367. }
  368. }
  369. break;
  370. case 'f':
  371. case 'F':
  372. //
  373. // Toggle paging
  374. //
  375. GlobalDoThreads = !GlobalDoThreads;
  376. if (GlobalDoThreads) {
  377. RCCSrvPrintMsg(ComPortHandle, MSG_RCCSRV_THREADS_ENABLED, 0);
  378. } else {
  379. RCCSrvPrintMsg(ComPortHandle, MSG_RCCSRV_THREADS_DISABLED, 0);
  380. }
  381. break;
  382. case 'k':
  383. case 'K':
  384. //
  385. // Skip to next argument (process id)
  386. //
  387. while ((*pch != ' ') &&
  388. (pch < (GlobalCommandLine + GlobalCommandLineSize))) {
  389. pch++;
  390. }
  391. if (pch >= (GlobalCommandLine + GlobalCommandLineSize)) {
  392. continue;
  393. }
  394. while ((*pch == ' ') &&
  395. (pch < (GlobalCommandLine + GlobalCommandLineSize))) {
  396. pch++;
  397. }
  398. if (pch >= (GlobalCommandLine + GlobalCommandLineSize)) {
  399. continue;
  400. }
  401. ProcessId = atoi(pch);
  402. if (ProcessId != ThisProcessId) {
  403. Error = RCCLibKillProcess(ProcessId);
  404. } else {
  405. Error = ERROR_INVALID_PARAMETER;
  406. }
  407. if (Error == ERROR_SUCCESS) {
  408. RCCSrvPrintMsg(ComPortHandle, MSG_RCCSRV_RESULT_SUCCESS, 0);
  409. } else {
  410. RCCSrvPrintMsg(ComPortHandle, MSG_RCCSRV_RESULT_FAILURE, Error);
  411. }
  412. break;
  413. case 'l':
  414. case 'L':
  415. //
  416. // Skip to next argument (process id)
  417. //
  418. while ((*pch != ' ') &&
  419. (pch < (GlobalCommandLine + GlobalCommandLineSize))) {
  420. pch++;
  421. }
  422. if (pch >= (GlobalCommandLine + GlobalCommandLineSize)) {
  423. continue;
  424. }
  425. while ((*pch == ' ') &&
  426. (pch < (GlobalCommandLine + GlobalCommandLineSize))) {
  427. pch++;
  428. }
  429. if (pch >= (GlobalCommandLine + GlobalCommandLineSize)) {
  430. continue;
  431. }
  432. ProcessId = atoi(pch);
  433. if (ProcessId != ThisProcessId) {
  434. Error = RCCLibLowerProcessPriority(ProcessId);
  435. } else {
  436. Error = ERROR_INVALID_PARAMETER;
  437. }
  438. if (Error == ERROR_SUCCESS) {
  439. RCCSrvPrintMsg(ComPortHandle, MSG_RCCSRV_RESULT_SUCCESS, 0);
  440. } else {
  441. RCCSrvPrintMsg(ComPortHandle, MSG_RCCSRV_RESULT_FAILURE, Error);
  442. }
  443. break;
  444. case 'm':
  445. case 'M':
  446. //
  447. // Skip to next argument (process id)
  448. //
  449. while ((*pch != ' ') &&
  450. (pch < (GlobalCommandLine + GlobalCommandLineSize))) {
  451. pch++;
  452. }
  453. if (pch >= (GlobalCommandLine + GlobalCommandLineSize)) {
  454. continue;
  455. }
  456. while ((*pch == ' ') &&
  457. (pch < (GlobalCommandLine + GlobalCommandLineSize))) {
  458. pch++;
  459. }
  460. if (pch >= (GlobalCommandLine + GlobalCommandLineSize)) {
  461. continue;
  462. }
  463. ProcessId = atoi(pch);
  464. //
  465. // Skip to next argument (kb-allowed)
  466. //
  467. while ((*pch != ' ') &&
  468. (pch < (GlobalCommandLine + GlobalCommandLineSize))) {
  469. pch++;
  470. }
  471. if (pch >= (GlobalCommandLine + GlobalCommandLineSize)) {
  472. continue;
  473. }
  474. while ((*pch == ' ') &&
  475. (pch < (GlobalCommandLine + GlobalCommandLineSize))) {
  476. pch++;
  477. }
  478. if (pch >= (GlobalCommandLine + GlobalCommandLineSize)) {
  479. continue;
  480. }
  481. MemoryLimit = atoi(pch);
  482. if (ProcessId != ThisProcessId) {
  483. Error = RCCLibLimitProcessMemory(ProcessId, MemoryLimit);
  484. } else {
  485. Error = ERROR_INVALID_PARAMETER;
  486. }
  487. if (Error == ERROR_SUCCESS) {
  488. RCCSrvPrintMsg(ComPortHandle, MSG_RCCSRV_RESULT_SUCCESS, 0);
  489. } else {
  490. RCCSrvPrintMsg(ComPortHandle, MSG_RCCSRV_RESULT_FAILURE, Error);
  491. }
  492. break;
  493. case 'p':
  494. case 'P':
  495. //
  496. // Toggle paging
  497. //
  498. GlobalPagingNeeded = !GlobalPagingNeeded;
  499. if (GlobalPagingNeeded) {
  500. RCCSrvPrintMsg(ComPortHandle, MSG_RCCSRV_PAGING_ENABLED, 0);
  501. } else {
  502. RCCSrvPrintMsg(ComPortHandle, MSG_RCCSRV_PAGING_DISABLED, 0);
  503. }
  504. break;
  505. case 'r':
  506. case 'R':
  507. //
  508. // Compare the command
  509. //
  510. pTemp = pch;
  511. while ((*pch != '\0') && (*pch != ' ') &&
  512. (pch < (GlobalCommandLine + GlobalCommandLineSize))) {
  513. pch++;
  514. }
  515. if (pch >= (GlobalCommandLine + GlobalCommandLineSize)) {
  516. continue;
  517. }
  518. *pch = '\0';
  519. RtlInitString(&String1, "reboot");
  520. RtlInitString(&String2, pTemp);
  521. if (!RtlEqualString(&String1, &String2, TRUE)) {
  522. RCCSrvPrintMsg(ComPortHandle, MSG_RCCSRV_HELP, 0);
  523. continue;
  524. }
  525. //
  526. // Send back an acknowledgement that we got the command before starting the reboot.
  527. //
  528. if (AreYouSure(ComPortHandle)) {
  529. RCCSrvPrintMsg(ComPortHandle, MSG_RCCSRV_SHUTTING_DOWN, 0);
  530. NtShutdownSystem(ShutdownReboot);
  531. }
  532. break;
  533. case 's':
  534. case 'S':
  535. //
  536. // Compare the command
  537. //
  538. RtlInitString(&String1, "shutdown");
  539. pTemp = pch;
  540. while ((*pch != '\0') && (*pch != ' ') &&
  541. (pch < (GlobalCommandLine + GlobalCommandLineSize))) {
  542. pch++;
  543. }
  544. if (pch >= (GlobalCommandLine + GlobalCommandLineSize)) {
  545. continue;
  546. }
  547. *pch = '\0';
  548. RtlInitString(&String2, pTemp);
  549. if (!RtlEqualString(&String1, &String2, TRUE)) {
  550. RCCSrvPrintMsg(ComPortHandle, MSG_RCCSRV_HELP, 0);
  551. continue;
  552. }
  553. //
  554. // Send back an acknowledgement that we got the command before starting the reboot.
  555. //
  556. if (AreYouSure(ComPortHandle)) {
  557. RCCSrvPrintMsg(ComPortHandle, MSG_RCCSRV_SHUTTING_DOWN, 0);
  558. NtShutdownSystem(ShutdownNoReboot);
  559. }
  560. break;
  561. case 't':
  562. case 'T':
  563. RetryTList:
  564. Error = RCCLibGetTListInfo((PRCC_RSP_TLIST)GlobalBuffer,
  565. (LONG)GlobalBufferCurrentSize,
  566. &DataLength
  567. );
  568. //
  569. // Try to get more memory, if not available, then just fail without out of memory error.
  570. //
  571. if (Error == ERROR_OUTOFMEMORY) {
  572. Error = RCCLibIncreaseMemory(&GlobalBuffer, &GlobalBufferCurrentSize);
  573. if (Error == ERROR_SUCCESS) {
  574. goto RetryTList;
  575. }
  576. RCCSrvPrintMsg(ComPortHandle, MSG_RCCSRV_OUT_OF_MEMORY, 0);
  577. break;
  578. }
  579. RCCSrvPrintTListInfo(ComPortHandle, (PRCC_RSP_TLIST)GlobalBuffer);
  580. break;
  581. //
  582. // Help
  583. //
  584. case '?':
  585. RCCSrvPrintMsg(ComPortHandle, MSG_RCCSRV_HELP, 0);
  586. break;
  587. default:
  588. RCCSrvPrintMsg(ComPortHandle, MSG_RCCSRV_INVALID_COMMAND, 0);
  589. break;
  590. }
  591. }
  592. Exit:
  593. if (PrintMessage != 0) {
  594. BytesReturned = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
  595. FORMAT_MESSAGE_FROM_HMODULE |
  596. FORMAT_MESSAGE_ARGUMENT_ARRAY,
  597. NULL,
  598. PrintMessage,
  599. 0,
  600. (LPTSTR)&NewBuffer,
  601. 0,
  602. (va_list *)&Error
  603. );
  604. if (BytesReturned != 0) {
  605. printf(NewBuffer);
  606. LocalFree(NewBuffer);
  607. }
  608. }
  609. RCCLibExit(GlobalBuffer, GlobalBufferCurrentSize);
  610. if (GlobalCommandLine != NULL) {
  611. VirtualFree(GlobalCommandLine, GlobalCommandLineSize, MEM_DECOMMIT);
  612. }
  613. if (RCCHandle != NULL) {
  614. NtClose(RCCHandle);
  615. }
  616. return 0;
  617. }
  618. DWORD
  619. RCCSrvReportEventA(
  620. DWORD EventID,
  621. DWORD EventType,
  622. DWORD NumStrings,
  623. DWORD DataLength,
  624. LPSTR *Strings,
  625. LPVOID Data
  626. )
  627. /*++
  628. Routine Description:
  629. This function writes the specified (EventID) log at the end of the
  630. eventlog.
  631. Arguments:
  632. EventID - The specific event identifier. This identifies the
  633. message that goes with this event.
  634. EventType - Specifies the type of event being logged. This
  635. parameter can have one of the following
  636. values:
  637. Value Meaning
  638. EVENTLOG_ERROR_TYPE Error event
  639. EVENTLOG_WARNING_TYPE Warning event
  640. EVENTLOG_INFORMATION_TYPE Information event
  641. NumStrings - Specifies the number of strings that are in the array
  642. at 'Strings'. A value of zero indicates no strings
  643. are present.
  644. DataLength - Specifies the number of bytes of event-specific raw
  645. (binary) data to write to the log. If cbData is
  646. zero, no event-specific data is present.
  647. Strings - Points to a buffer containing an array of null-terminated
  648. strings that are merged into the message before
  649. displaying to the user. This parameter must be a valid
  650. pointer (or NULL), even if cStrings is zero.
  651. Data - Buffer containing the raw data. This parameter must be a
  652. valid pointer (or NULL), even if cbData is zero.
  653. Return Value:
  654. Returns the WIN32 extended error obtained by GetLastError().
  655. NOTE : This function works slow since it calls the open and close
  656. eventlog source everytime.
  657. --*/
  658. {
  659. HANDLE EventlogHandle;
  660. DWORD ReturnCode;
  661. //
  662. // open eventlog section.
  663. //
  664. EventlogHandle = RegisterEventSourceW(NULL, L"RCCSer");
  665. if (EventlogHandle == NULL) {
  666. ReturnCode = GetLastError();
  667. goto Cleanup;
  668. }
  669. //
  670. // Log the error code specified
  671. //
  672. if(!ReportEventA(EventlogHandle,
  673. (WORD)EventType,
  674. 0, // event category
  675. EventID,
  676. NULL,
  677. (WORD)NumStrings,
  678. DataLength,
  679. Strings,
  680. Data
  681. )) {
  682. ReturnCode = GetLastError();
  683. goto Cleanup;
  684. }
  685. ReturnCode = ERROR_SUCCESS;
  686. Cleanup:
  687. if (EventlogHandle != NULL) {
  688. DeregisterEventSource(EventlogHandle);
  689. }
  690. return ReturnCode;
  691. }
  692. DWORD
  693. RCCSrvGetCommandLine(
  694. IN HANDLE ComPortHandle,
  695. OUT PBOOL ControlC
  696. )
  697. {
  698. DWORD Bytes;
  699. DWORD i;
  700. GlobalReadIndex = 0;
  701. *ControlC = FALSE;
  702. do {
  703. if (GlobalReadIndex == GlobalCommandLineSize) {
  704. GlobalReadIndex--;
  705. }
  706. //
  707. // Read a (possibly) partial command line.
  708. //
  709. if (!ReadFile(ComPortHandle,
  710. &(GlobalCommandLine[GlobalReadIndex]),
  711. 1,
  712. &Bytes,
  713. NULL
  714. )) {
  715. return GetLastError();
  716. }
  717. if (GlobalCommandLine[GlobalReadIndex] == 0x3) {
  718. *ControlC = TRUE;
  719. return ERROR_SUCCESS;
  720. }
  721. if ((GlobalCommandLine[GlobalReadIndex] == 0x8) || // backspace (^h)
  722. (GlobalCommandLine[GlobalReadIndex] == 0x7F)) { // delete
  723. if (GlobalReadIndex > 0) {
  724. WriteFile(ComPortHandle,
  725. &(GlobalCommandLine[GlobalReadIndex]),
  726. 1,
  727. &Bytes,
  728. NULL
  729. );
  730. GlobalReadIndex--;
  731. }
  732. } else {
  733. WriteFile(ComPortHandle,
  734. &(GlobalCommandLine[GlobalReadIndex]),
  735. 1,
  736. &Bytes,
  737. NULL
  738. );
  739. GlobalReadIndex++;
  740. }
  741. } while ((GlobalReadIndex == 0) || (GlobalCommandLine[GlobalReadIndex - 1] != '\r'));
  742. GlobalCommandLine[GlobalReadIndex - 1] = '\0';
  743. RCCSrvPrint(ComPortHandle, "\n", sizeof("\n") - 1);
  744. return ERROR_SUCCESS;
  745. }
  746. DWORD
  747. RCCSrvPrintMsg(
  748. IN HANDLE ComPortHandle,
  749. IN DWORD MessageId,
  750. IN DWORD SystemErrorCode
  751. )
  752. {
  753. DWORD Bytes;
  754. UCHAR OutBuffer[512];
  755. Bytes = FormatMessageA(FORMAT_MESSAGE_FROM_HMODULE,
  756. NULL,
  757. MessageId,
  758. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  759. OutBuffer,
  760. ARRAYSIZE(OutBuffer)),
  761. NULL
  762. );
  763. ASSERT(Bytes != 0);
  764. if (MessageId == MSG_RCCSRV_PROMPT) {
  765. Bytes -= 2; // remove the \r\n that get added in .mc files
  766. }
  767. RCCSrvPrint(ComPortHandle, OutBuffer, Bytes);
  768. if (SystemErrorCode != 0) {
  769. Bytes = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM,
  770. NULL,
  771. SystemErrorCode,
  772. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  773. OutBuffer,
  774. ARRAYSIZE(OutBuffer),
  775. NULL
  776. );
  777. if (Bytes == 0) {
  778. Bytes = FormatMessageA(FORMAT_MESSAGE_FROM_HMODULE,
  779. NULL,
  780. MSG_RCCSRV_ERROR_NOT_DEFINED,
  781. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  782. OutBuffer,
  783. ARRAYSIZE(OutBuffer),
  784. (LPVOID)&SystemErrorCode
  785. );
  786. ASSERT(Bytes != 0);
  787. }
  788. RCCSrvPrint(ComPortHandle, OutBuffer, Bytes);
  789. RCCSrvPrint(ComPortHandle, "\r\n\r\n", sizeof("\r\n\r\n") - 1);
  790. }
  791. return ERROR_SUCCESS;
  792. }
  793. DWORD
  794. RCCSrvPrint(
  795. IN HANDLE ComPortHandle,
  796. IN PUCHAR Buffer,
  797. IN DWORD BufferSize
  798. )
  799. {
  800. DWORD BytesWritten;
  801. if (!WriteFile(ComPortHandle, Buffer, BufferSize, &BytesWritten, NULL)) {
  802. return GetLastError();
  803. }
  804. return ERROR_SUCCESS;
  805. }
  806. VOID
  807. RCCSrvPrintTListInfo(
  808. IN HANDLE ComPortHandle,
  809. IN PRCC_RSP_TLIST Buffer
  810. )
  811. {
  812. LARGE_INTEGER Time;
  813. TIME_FIELDS UserTime;
  814. TIME_FIELDS KernelTime;
  815. TIME_FIELDS UpTime;
  816. ULONG TotalOffset;
  817. SIZE_T SumCommit;
  818. SIZE_T SumWorkingSet;
  819. PSYSTEM_PROCESS_INFORMATION ProcessInfo;
  820. PSYSTEM_THREAD_INFORMATION ThreadInfo;
  821. PSYSTEM_PAGEFILE_INFORMATION PageFileInfo;
  822. ULONG i;
  823. PUCHAR ProcessInfoStart;
  824. PUCHAR BufferStart = (PUCHAR)Buffer;
  825. ANSI_STRING pname;
  826. ULONG LineNumber = 0;
  827. UCHAR OutputBuffer[200]; // should never be more than 80, but just to be safe....
  828. BOOL Stop;
  829. Time.QuadPart = Buffer->TimeOfDayInfo.CurrentTime.QuadPart - Buffer->TimeOfDayInfo.BootTime.QuadPart;
  830. RtlTimeToElapsedTimeFields(&Time, &UpTime);
  831. sprintf(OutputBuffer,
  832. "memory: %4ld kb uptime:%3ld %2ld:%02ld:%02ld.%03ld \r\n\r\n",
  833. Buffer->BasicInfo.NumberOfPhysicalPages * (Buffer->BasicInfo.PageSize / 1024),
  834. UpTime.Day,
  835. UpTime.Hour,
  836. UpTime.Minute,
  837. UpTime.Second,
  838. UpTime.Milliseconds
  839. );
  840. RCCSrvPrint(ComPortHandle, OutputBuffer, strlen(OutputBuffer));
  841. LineNumber += 2;
  842. PageFileInfo = (PSYSTEM_PAGEFILE_INFORMATION)(BufferStart + Buffer->PagefileInfoOffset);
  843. //
  844. // Print out the page file information.
  845. //
  846. if (Buffer->PagefileInfoOffset == 0) {
  847. sprintf(OutputBuffer, "no page files in use\r\n");
  848. RCCSrvPrint(ComPortHandle, OutputBuffer, strlen(OutputBuffer));
  849. LineNumber++;
  850. } else {
  851. for (; ; ) {
  852. PageFileInfo->PageFileName.Buffer = (PWCHAR)(((PUCHAR)BufferStart) +
  853. (ULONG_PTR)(PageFileInfo->PageFileName.Buffer));
  854. sprintf(OutputBuffer, "PageFile: %wZ\r\n", &PageFileInfo->PageFileName);
  855. RCCSrvPrint(ComPortHandle, OutputBuffer, strlen(OutputBuffer));
  856. LineNumber++;
  857. sprintf(OutputBuffer, "\tCurrent Size: %6ld kb Total Used: %6ld kb Peak Used %6ld kb\r\n",
  858. PageFileInfo->TotalSize * (Buffer->BasicInfo.PageSize/1024),
  859. PageFileInfo->TotalInUse * (Buffer->BasicInfo.PageSize/1024),
  860. PageFileInfo->PeakUsage * (Buffer->BasicInfo.PageSize/1024)
  861. );
  862. RCCSrvPrint(ComPortHandle, OutputBuffer, strlen(OutputBuffer));
  863. LineNumber++;
  864. if (PageFileInfo->NextEntryOffset == 0) {
  865. break;
  866. }
  867. PageFileInfo = (PSYSTEM_PAGEFILE_INFORMATION)((PCHAR)PageFileInfo + PageFileInfo->NextEntryOffset);
  868. }
  869. }
  870. //
  871. // display pmon style process output, then detailed output that includes
  872. // per thread stuff
  873. //
  874. if (Buffer->ProcessInfoOffset == 0) {
  875. return;
  876. }
  877. TotalOffset = 0;
  878. SumCommit = 0;
  879. SumWorkingSet = 0;
  880. ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)(BufferStart + Buffer->ProcessInfoOffset);
  881. ProcessInfoStart = (PUCHAR)ProcessInfo;
  882. while (TRUE) {
  883. SumCommit += ProcessInfo->PrivatePageCount / 1024;
  884. SumWorkingSet += ProcessInfo->WorkingSetSize / 1024;
  885. if (ProcessInfo->NextEntryOffset == 0) {
  886. break;
  887. }
  888. TotalOffset += ProcessInfo->NextEntryOffset;
  889. ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)(ProcessInfoStart +TotalOffset);
  890. }
  891. SumWorkingSet += Buffer->FileCache.CurrentSize/1024;
  892. if (LineNumber > 17) {
  893. RCCSrvPutMore(ComPortHandle, &Stop);
  894. if (Stop) {
  895. return;
  896. }
  897. LineNumber = 0;
  898. }
  899. sprintf(OutputBuffer,
  900. "\r\n Memory:%7ldK Avail:%7ldK TotalWs:%7ldK InRam Kernel:%5ldK P:%5ldK\r\n",
  901. Buffer->BasicInfo.NumberOfPhysicalPages * (Buffer->BasicInfo.PageSize/1024),
  902. Buffer->PerfInfo.AvailablePages * (Buffer->BasicInfo.PageSize/1024),
  903. SumWorkingSet,
  904. (Buffer->PerfInfo.ResidentSystemCodePage + Buffer->PerfInfo.ResidentSystemDriverPage) *
  905. (Buffer->BasicInfo.PageSize/1024),
  906. (Buffer->PerfInfo.ResidentPagedPoolPage) * (Buffer->BasicInfo.PageSize/1024)
  907. );
  908. RCCSrvPrint(ComPortHandle, OutputBuffer, strlen(OutputBuffer));
  909. LineNumber += 2;
  910. if (LineNumber > 18) {
  911. RCCSrvPutMore(ComPortHandle, &Stop);
  912. if (Stop) {
  913. return;
  914. }
  915. LineNumber = 0;
  916. }
  917. sprintf(OutputBuffer,
  918. " Commit:%7ldK/%7ldK Limit:%7ldK Peak:%7ldK Pool N:%5ldK P:%5ldK\r\n",
  919. Buffer->PerfInfo.CommittedPages * (Buffer->BasicInfo.PageSize/1024),
  920. SumCommit,
  921. Buffer->PerfInfo.CommitLimit * (Buffer->BasicInfo.PageSize/1024),
  922. Buffer->PerfInfo.PeakCommitment * (Buffer->BasicInfo.PageSize/1024),
  923. Buffer->PerfInfo.NonPagedPoolPages * (Buffer->BasicInfo.PageSize/1024),
  924. Buffer->PerfInfo.PagedPoolPages * (Buffer->BasicInfo.PageSize/1024)
  925. );
  926. RCCSrvPrint(ComPortHandle, OutputBuffer, strlen(OutputBuffer));
  927. LineNumber++;
  928. if (LineNumber > 18) {
  929. RCCSrvPutMore(ComPortHandle, &Stop);
  930. if (Stop) {
  931. return;
  932. }
  933. LineNumber = 0;
  934. }
  935. sprintf(OutputBuffer, "\r\n");
  936. RCCSrvPrint(ComPortHandle, OutputBuffer, strlen(OutputBuffer));
  937. RCCSrvPutMore(ComPortHandle, &Stop);
  938. if (Stop) {
  939. return;
  940. }
  941. LineNumber = 0;
  942. sprintf(OutputBuffer, " User Time Kernel Time Ws Faults Commit Pri Hnd Thd Pid Name\r\n");
  943. RCCSrvPrint(ComPortHandle, OutputBuffer, strlen(OutputBuffer));
  944. LineNumber++;
  945. sprintf(OutputBuffer,
  946. " %6ld %8ld %s\r\n",
  947. Buffer->FileCache.CurrentSize/1024,
  948. Buffer->FileCache.PageFaultCount,
  949. "File Cache"
  950. );
  951. RCCSrvPrint(ComPortHandle, OutputBuffer, strlen(OutputBuffer));
  952. LineNumber++;
  953. TotalOffset = 0;
  954. ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)(BufferStart + Buffer->ProcessInfoOffset);
  955. while (TRUE) {
  956. pname.Buffer = NULL;
  957. if (ProcessInfo->ImageName.Buffer) {
  958. ProcessInfo->ImageName.Buffer = (PWCHAR)(BufferStart + (ULONG_PTR)(ProcessInfo->ImageName.Buffer));
  959. RtlUnicodeStringToAnsiString(&pname,(PUNICODE_STRING)&ProcessInfo->ImageName,TRUE);
  960. }
  961. RtlTimeToElapsedTimeFields(&ProcessInfo->UserTime, &UserTime);
  962. RtlTimeToElapsedTimeFields(&ProcessInfo->KernelTime, &KernelTime);
  963. sprintf(OutputBuffer,
  964. "%3ld:%02ld:%02ld.%03ld %3ld:%02ld:%02ld.%03ld",
  965. UserTime.Hour,
  966. UserTime.Minute,
  967. UserTime.Second,
  968. UserTime.Milliseconds,
  969. KernelTime.Hour,
  970. KernelTime.Minute,
  971. KernelTime.Second,
  972. KernelTime.Milliseconds
  973. );
  974. RCCSrvPrint(ComPortHandle, OutputBuffer, strlen(OutputBuffer));
  975. sprintf(OutputBuffer,
  976. "%6ld %8ld %7ld",
  977. ProcessInfo->WorkingSetSize / 1024,
  978. ProcessInfo->PageFaultCount,
  979. ProcessInfo->PrivatePageCount / 1024
  980. );
  981. RCCSrvPrint(ComPortHandle, OutputBuffer, strlen(OutputBuffer));
  982. sprintf(OutputBuffer,
  983. " %2ld %4ld %3ld %3ld %s\r\n",
  984. ProcessInfo->BasePriority,
  985. ProcessInfo->HandleCount,
  986. ProcessInfo->NumberOfThreads,
  987. HandleToUlong(ProcessInfo->UniqueProcessId),
  988. ProcessInfo->UniqueProcessId == 0 ?
  989. "Idle Process" :
  990. (ProcessInfo->ImageName.Buffer ? pname.Buffer : "System")
  991. );
  992. RCCSrvPrint(ComPortHandle, OutputBuffer, strlen(OutputBuffer));
  993. LineNumber++;
  994. if (LineNumber > 18) {
  995. RCCSrvPutMore(ComPortHandle, &Stop);
  996. if (Stop) {
  997. return;
  998. }
  999. LineNumber = 0;
  1000. if (GlobalPagingNeeded) {
  1001. sprintf(OutputBuffer, " User Time Kernel Time Ws Faults Commit Pri Hnd Thd Pid Name\r\n");
  1002. RCCSrvPrint(ComPortHandle, OutputBuffer, strlen(OutputBuffer));
  1003. }
  1004. LineNumber++;
  1005. }
  1006. if (pname.Buffer) {
  1007. RtlFreeAnsiString(&pname);
  1008. }
  1009. if (ProcessInfo->NextEntryOffset == 0) {
  1010. break;
  1011. }
  1012. TotalOffset += ProcessInfo->NextEntryOffset;
  1013. ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)(ProcessInfoStart + TotalOffset);
  1014. }
  1015. if (!GlobalDoThreads) {
  1016. return;
  1017. }
  1018. //
  1019. // Beginning of normal old style pstat output
  1020. //
  1021. TotalOffset = 0;
  1022. ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)(BufferStart + Buffer->ProcessInfoOffset);
  1023. RCCSrvPutMore(ComPortHandle, &Stop);
  1024. if (Stop) {
  1025. return;
  1026. }
  1027. LineNumber = 0;
  1028. sprintf(OutputBuffer, "\r\n");
  1029. RCCSrvPrint(ComPortHandle, OutputBuffer, strlen(OutputBuffer));
  1030. LineNumber++;
  1031. while (TRUE) {
  1032. pname.Buffer = NULL;
  1033. if (ProcessInfo->ImageName.Buffer) {
  1034. RtlUnicodeStringToAnsiString(&pname,(PUNICODE_STRING)&ProcessInfo->ImageName,TRUE);
  1035. }
  1036. sprintf(OutputBuffer,
  1037. "pid:%3lx pri:%2ld Hnd:%5ld Pf:%7ld Ws:%7ldK %s\r\n",
  1038. HandleToUlong(ProcessInfo->UniqueProcessId),
  1039. ProcessInfo->BasePriority,
  1040. ProcessInfo->HandleCount,
  1041. ProcessInfo->PageFaultCount,
  1042. ProcessInfo->WorkingSetSize / 1024,
  1043. ProcessInfo->UniqueProcessId == 0 ? "Idle Process" : (
  1044. ProcessInfo->ImageName.Buffer ? pname.Buffer : "System")
  1045. );
  1046. RCCSrvPrint(ComPortHandle, OutputBuffer, strlen(OutputBuffer));
  1047. LineNumber++;
  1048. if (LineNumber > 18) {
  1049. RCCSrvPutMore(ComPortHandle, &Stop);
  1050. if (Stop) {
  1051. return;
  1052. }
  1053. LineNumber = 0;
  1054. }
  1055. if (pname.Buffer) {
  1056. RtlFreeAnsiString(&pname);
  1057. }
  1058. i = 0;
  1059. ThreadInfo = (PSYSTEM_THREAD_INFORMATION)(ProcessInfo + 1);
  1060. if (ProcessInfo->NumberOfThreads) {
  1061. if ((LineNumber < 18) || !GlobalPagingNeeded) {
  1062. sprintf(OutputBuffer, " tid pri Ctx Swtch StrtAddr User Time Kernel Time State\r\n");
  1063. RCCSrvPrint(ComPortHandle, OutputBuffer, strlen(OutputBuffer));
  1064. LineNumber++;
  1065. } else {
  1066. RCCSrvPutMore(ComPortHandle, &Stop);
  1067. if (Stop) {
  1068. return;
  1069. }
  1070. LineNumber = 0;
  1071. }
  1072. }
  1073. while (i < ProcessInfo->NumberOfThreads) {
  1074. RtlTimeToElapsedTimeFields ( &ThreadInfo->UserTime, &UserTime);
  1075. RtlTimeToElapsedTimeFields ( &ThreadInfo->KernelTime, &KernelTime);
  1076. sprintf(OutputBuffer,
  1077. " %3lx %2ld %9ld %p",
  1078. ProcessInfo->UniqueProcessId == 0 ? 0 : HandleToUlong(ThreadInfo->ClientId.UniqueThread),
  1079. ProcessInfo->UniqueProcessId == 0 ? 0 : ThreadInfo->Priority,
  1080. ThreadInfo->ContextSwitches,
  1081. ProcessInfo->UniqueProcessId == 0 ? 0 : ThreadInfo->StartAddress
  1082. );
  1083. RCCSrvPrint(ComPortHandle, OutputBuffer, strlen(OutputBuffer));
  1084. sprintf(OutputBuffer,
  1085. " %2ld:%02ld:%02ld.%03ld %2ld:%02ld:%02ld.%03ld",
  1086. UserTime.Hour,
  1087. UserTime.Minute,
  1088. UserTime.Second,
  1089. UserTime.Milliseconds,
  1090. KernelTime.Hour,
  1091. KernelTime.Minute,
  1092. KernelTime.Second,
  1093. KernelTime.Milliseconds
  1094. );
  1095. RCCSrvPrint(ComPortHandle, OutputBuffer, strlen(OutputBuffer));
  1096. sprintf(OutputBuffer,
  1097. " %s%s\r\n",
  1098. StateTable[ThreadInfo->ThreadState],
  1099. (ThreadInfo->ThreadState == 5) ? WaitTable[ThreadInfo->WaitReason] : Empty
  1100. );
  1101. RCCSrvPrint(ComPortHandle, OutputBuffer, strlen(OutputBuffer));
  1102. LineNumber++;
  1103. if (LineNumber > 18) {
  1104. RCCSrvPutMore(ComPortHandle, &Stop);
  1105. if (Stop) {
  1106. return;
  1107. }
  1108. LineNumber = 0;
  1109. if (GlobalPagingNeeded) {
  1110. sprintf(OutputBuffer, " tid pri Ctx Swtch StrtAddr User Time Kernel Time State\r\n");
  1111. RCCSrvPrint(ComPortHandle, OutputBuffer, strlen(OutputBuffer));
  1112. }
  1113. LineNumber++;
  1114. }
  1115. ThreadInfo += 1;
  1116. i += 1;
  1117. }
  1118. if (ProcessInfo->NextEntryOffset == 0) {
  1119. break;
  1120. }
  1121. TotalOffset += ProcessInfo->NextEntryOffset;
  1122. ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)(ProcessInfoStart + TotalOffset);
  1123. sprintf(OutputBuffer, "\r\n");
  1124. RCCSrvPrint(ComPortHandle, OutputBuffer, strlen(OutputBuffer));
  1125. LineNumber++;
  1126. if (LineNumber > 18) {
  1127. RCCSrvPutMore(ComPortHandle, &Stop);
  1128. if (Stop) {
  1129. return;
  1130. }
  1131. LineNumber = 0;
  1132. }
  1133. }
  1134. }
  1135. VOID
  1136. RCCSrvPutMore(
  1137. IN HANDLE ComPortHandle,
  1138. OUT PBOOL Stop
  1139. )
  1140. {
  1141. if (GlobalPagingNeeded) {
  1142. RCCSrvPrintMsg(ComPortHandle, MSG_RCCSRV_MORE, 0);
  1143. RCCSrvGetCommandLine(ComPortHandle, Stop);
  1144. } else {
  1145. *Stop = FALSE;
  1146. }
  1147. }
  1148. BOOL
  1149. AreYouSure(
  1150. IN HANDLE ComPortHandle
  1151. )
  1152. {
  1153. BOOL Stop;
  1154. RCCSrvPrintMsg(ComPortHandle, MSG_RCCSRV_ARE_YOU_SURE, 0);
  1155. RCCSrvGetCommandLine(ComPortHandle, &Stop);
  1156. if (!Stop && ((GlobalCommandLine[0] == 'y') || (GlobalCommandLine[0] == 'Y'))) {
  1157. return TRUE;
  1158. }
  1159. return FALSE;
  1160. }