2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS text-mode setup
4 * FILE: subsys/system/usetup/cmdcons.c
5 * PURPOSE: Recovery console
6 * PROGRAMMER: Eric Kohl
15 //#define FEATURE_HISTORY
17 typedef struct _CONSOLE_STATE
23 } CONSOLE_STATE
, *PCONSOLE_STATE
;
25 typedef struct tagCOMMAND
29 INT (*func
)(PCONSOLE_STATE
, LPSTR
);
30 } COMMAND
, *LPCOMMAND
;
60 {"cls", 0, CommandCls
},
61 {"dumpsector", 0, CommandDumpSector
},
62 {"exit", 0, CommandExit
},
63 {"help", 0, CommandHelp
},
80 RtlFreeHeap(ProcessHeap
, 0, *q
++);
82 RtlFreeHeap(ProcessHeap
, 0, p
);
112 q
= RtlAllocateHeap(ProcessHeap
, 0, strlen(entry
) + 1);
118 *arg
= RtlReAllocateHeap(ProcessHeap
, 0, oldarg
, (*ac
+ 2) * sizeof(LPSTR
));
121 RtlFreeHeap(ProcessHeap
, 0, q
);
128 (*arg
)[++(*ac
)] = NULL
;
146 arg
= RtlAllocateHeap(ProcessHeap
, 0 , sizeof(LPTSTR
));
157 /* skip leading spaces */
158 while (*s
&& (isspace(*s
) || iscntrl(*s
)))
163 /* the first character can be '/' */
167 /* skip to next word delimiter or start of next option */
170 /* if quote (") then set bQuoted */
171 bQuoted
^= (*s
== '\"');
173 /* Check if we have unquoted text */
176 /* check for separators */
177 if (isspace(*s
) || (*s
== '/'))
179 /* Make length at least one character */
189 /* a word was found */
193 q
= RtlAllocateHeap(ProcessHeap
, 0, len
+ 1);
200 memcpy(q
, start
, len
);
205 if (!add_entry(&ac
, &arg
, q
))
207 RtlFreeHeap(ProcessHeap
, 0, q
);
212 RtlFreeHeap(ProcessHeap
, 0, q
);
225 PCONSOLE_STATE State
,
234 if (!strncmp(param
, "/?", 2))
236 ConOutResPaging(TRUE
,STRING_CLS_HELP
);
244 hOutput
= GetStdHandle(STD_OUTPUT_HANDLE
);
245 FillConsoleOutputAttribute(hOutput
, csbi
.wAttributes
,
246 State
->maxx
* State
->maxy
,
248 FillConsoleOutputCharacter(hOutput
, ' ',
249 State
->maxx
* State
->maxy
,
251 SetConsoleCursorPosition(hOutput
, coPos
);
254 CONSOLE_ClearScreen();
255 CONSOLE_SetCursorXY(0, 0);
261 void HexDump(PUCHAR buffer
, ULONG size
)
266 while (offset
< (size
& ~15))
268 ptr
= (PUCHAR
)((ULONG_PTR
)buffer
+ offset
);
269 CONSOLE_ConOutPrintf("%04lx %02hx %02hx %02hx %02hx %02hx %02hx %02hx %02hx %02hx %02hx %02hx %02hx %02hx %02hx %02hx %02hx\n",
292 ptr
= (PUCHAR
)((ULONG_PTR
)buffer
+ offset
);
293 CONSOLE_ConOutPrintf("%04lx ", offset
);
294 while (offset
< size
)
296 CONSOLE_ConOutPrintf(" %02hx", *ptr
);
301 CONSOLE_ConOutPrintf("\n");
304 CONSOLE_ConOutPrintf("\n");
310 PCONSOLE_STATE State
,
313 OBJECT_ATTRIBUTES ObjectAttributes
;
314 IO_STATUS_BLOCK IoStatusBlock
;
315 UNICODE_STRING PathName
;
317 DISK_GEOMETRY DiskGeometry
;
325 LARGE_INTEGER Sector
, SectorCount
, Offset
;
326 PUCHAR Buffer
= NULL
;
328 DPRINT1("param: %s\n", param
);
330 if (!strncmp(param
, "/?", 2))
332 CONSOLE_ConOutPrintf("DUMPSECT DiskNumber Sector\n\nDumps a disk sector to the screen.\n\n");
336 argv
= split(param
, &argc
);
338 DPRINT1("argc: %d\n", argc
);
339 DPRINT1("argv: %p\n", argv
);
346 DPRINT1("Device: %s\n", argv
[0]);
347 DPRINT1("Sector: %s\n", argv
[1]);
349 ulDrive
= strtoul(argv
[0], NULL
, 0);
350 // ulSector = strtoul(argv[1], NULL, 0);
351 Sector
.QuadPart
= _atoi64(argv
[1]);
353 /* Build full drive name */
354 // swprintf(DriveName, L"\\\\.\\PHYSICALDRIVE%lu", ulDrive);
355 swprintf(DriveName
, L
"\\Device\\Harddisk%lu\\Partition0", ulDrive
);
357 RtlInitUnicodeString(&PathName
,
360 InitializeObjectAttributes(&ObjectAttributes
,
362 OBJ_CASE_INSENSITIVE
| OBJ_INHERIT
,
366 Status
= NtOpenFile(&hDisk
,
367 GENERIC_READ
| SYNCHRONIZE
,
371 FILE_SYNCHRONOUS_IO_NONALERT
| FILE_NON_DIRECTORY_FILE
| FILE_RANDOM_ACCESS
);
372 if (!NT_SUCCESS(Status
))
374 DPRINT1("NtCreateFile failed (Status 0x%08lx)\n", Status
);
378 Status
= NtDeviceIoControlFile(hDisk
,
383 IOCTL_DISK_GET_DRIVE_GEOMETRY
,
387 sizeof(DISK_GEOMETRY
));
388 if (!NT_SUCCESS(Status
))
390 DPRINT1("NtDeviceIoControlFile failed (Status 0x%08lx)\n", Status
);
394 DPRINT1("Drive number: %lu\n", ulDrive
);
395 DPRINT1("Cylinders: %I64u\nMediaType: %x\nTracksPerCylinder: %lu\n"
396 "SectorsPerTrack: %lu\nBytesPerSector: %lu\n\n",
397 DiskGeometry
.Cylinders
.QuadPart
,
398 DiskGeometry
.MediaType
,
399 DiskGeometry
.TracksPerCylinder
,
400 DiskGeometry
.SectorsPerTrack
,
401 DiskGeometry
.BytesPerSector
);
403 DPRINT1("Sector: %I64u\n", Sector
.QuadPart
);
405 SectorCount
.QuadPart
= DiskGeometry
.Cylinders
.QuadPart
*
406 DiskGeometry
.TracksPerCylinder
,
407 DiskGeometry
.SectorsPerTrack
;
408 if (Sector
.QuadPart
>= SectorCount
.QuadPart
)
410 CONSOLE_ConOutPrintf("Invalid sector number! Valid range: [0 - %I64u]\n", SectorCount
.QuadPart
- 1);
414 Buffer
= RtlAllocateHeap(ProcessHeap
, 0, DiskGeometry
.BytesPerSector
);
417 DPRINT1("Buffer allocation failed\n");
422 Offset
.QuadPart
= Sector
.QuadPart
* DiskGeometry
.BytesPerSector
;
423 DPRINT1("Offset: %I64u\n", Offset
.QuadPart
);
425 Status
= NtReadFile(hDisk
,
431 DiskGeometry
.BytesPerSector
,
434 if (!NT_SUCCESS(Status
))
436 DPRINT1("NtReadFile failed (Status 0x%08lx)\n", Status
);
440 HexDump(Buffer
, DiskGeometry
.BytesPerSector
);
444 RtlFreeHeap(ProcessHeap
, 0, Buffer
);
458 PCONSOLE_STATE State
,
462 if (!strncmp(param
, "/?", 2))
464 ConOutResPaging(TRUE
,STRING_EXIT_HELP
);
481 PCONSOLE_STATE State
,
484 CONSOLE_ConOutPrintf("CLS\n");
485 CONSOLE_ConOutPrintf("DUMPSECTOR\n");
486 CONSOLE_ConOutPrintf("EXIT\n");
487 CONSOLE_ConOutPrintf("HELP\n");
488 CONSOLE_ConOutPrintf("\n");
504 CONSOLE_SetCursorXY(orgx
, orgy
);
505 for (count
= 0; count
< (INT
)strlen(str
); count
++)
506 CONSOLE_ConOutChar(' ');
507 memset(str
, 0, maxlen
);
508 CONSOLE_SetCursorXY(orgx
, orgy
);
515 PCONSOLE_STATE State
,
519 SHORT orgx
; /* origin x/y */
521 SHORT curx
; /*current x/y cursor position*/
524 INT count
; /*used in some for loops*/
525 INT current
= 0; /*the position of the cursor in the string (str)*/
526 INT charcount
= 0;/*chars in the string (str)*/
529 BOOL bReturn
= FALSE
;
531 #ifdef FEATURE_HISTORY
532 //BOOL bContinue=FALSE;/*is TRUE the second case will not be executed*/
537 CONSOLE_GetCursorXY(&orgx
, &orgy
);
541 memset(str
, 0, maxlen
* sizeof(CHAR
));
543 CONSOLE_SetCursorType(State
->bInsert
, TRUE
);
548 CONSOLE_ConInKey(&ir
);
550 if (ir
.Event
.KeyEvent
.dwControlKeyState
&
551 (RIGHT_ALT_PRESSED
|LEFT_ALT_PRESSED
|
552 RIGHT_CTRL_PRESSED
|LEFT_CTRL_PRESSED
) )
554 switch (ir
.Event
.KeyEvent
.wVirtualKeyCode
)
556 #ifdef FEATURE_HISTORY
558 /*add the current command line to the history*/
559 if (ir
.Event
.KeyEvent
.dwControlKeyState
&
560 (LEFT_CTRL_PRESSED
|RIGHT_CTRL_PRESSED
))
565 ClearCommandLine (str
, maxlen
, orgx
, orgy
);
566 current
= charcount
= 0;
574 /*delete current history entry*/
575 if (ir
.Event
.KeyEvent
.dwControlKeyState
&
576 (LEFT_CTRL_PRESSED
|RIGHT_CTRL_PRESSED
))
578 ClearCommandLine (str
, maxlen
, orgx
, orgy
);
579 History_del_current_entry(str
);
580 current
= charcount
= strlen (str
);
581 ConOutPrintf("%s", str
);
582 GetCursorXY(&curx
, &cury
);
587 #endif /*FEATURE_HISTORY*/
593 switch (ir
.Event
.KeyEvent
.wVirtualKeyCode
)
596 /* <BACKSPACE> - delete character to left of cursor */
597 if (current
> 0 && charcount
> 0)
599 if (current
== charcount
)
601 /* if at end of line */
602 str
[current
- 1] = L
'\0';
603 if (CONSOLE_GetCursorX () != 0)
605 CONSOLE_ConOutPrintf("\b \b");
610 CONSOLE_SetCursorXY((SHORT
)(State
->maxx
- 1), (SHORT
)(CONSOLE_GetCursorY () - 1));
611 CONSOLE_ConOutChar(' ');
612 CONSOLE_SetCursorXY((SHORT
)(State
->maxx
- 1), (SHORT
)(CONSOLE_GetCursorY () - 1));
614 curx
= State
->maxx
- 1;
619 for (count
= current
- 1; count
< charcount
; count
++)
620 str
[count
] = str
[count
+ 1];
621 if (CONSOLE_GetCursorX () != 0)
623 CONSOLE_SetCursorXY ((SHORT
)(CONSOLE_GetCursorX () - 1), CONSOLE_GetCursorY ());
628 CONSOLE_SetCursorXY ((SHORT
)(State
->maxx
- 1), (SHORT
)(CONSOLE_GetCursorY () - 1));
630 curx
= State
->maxx
- 1;
632 CONSOLE_GetCursorXY(&curx
, &cury
);
633 CONSOLE_ConOutPrintf("%s ", &str
[current
- 1]);
634 CONSOLE_SetCursorXY(curx
, cury
);
642 /* toggle insert/overstrike mode */
643 State
->bInsert
^= TRUE
;
644 CONSOLE_SetCursorType(State
->bInsert
, TRUE
);
648 /* delete character under cursor */
649 if (current
!= charcount
&& charcount
> 0)
651 for (count
= current
; count
< charcount
; count
++)
652 str
[count
] = str
[count
+ 1];
654 CONSOLE_GetCursorXY(&curx
, &cury
);
655 CONSOLE_ConOutPrintf("%s ", &str
[current
]);
656 CONSOLE_SetCursorXY(curx
, cury
);
661 /* goto beginning of string */
664 CONSOLE_SetCursorXY(orgx
, orgy
);
672 /* goto end of string */
673 if (current
!= charcount
)
675 CONSOLE_SetCursorXY(orgx
, orgy
);
676 CONSOLE_ConOutPrintf("%s", str
);
677 CONSOLE_GetCursorXY(&curx
, &cury
);
684 /* ^M does the same as return */
686 if (!(ir
.Event
.KeyEvent
.dwControlKeyState
&
687 (RIGHT_CTRL_PRESSED
|LEFT_CTRL_PRESSED
)))
693 /* end input, return to main */
694 #ifdef FEATURE_HISTORY
695 /* add to the history */
699 str
[charcount
++] = '\n';
700 str
[charcount
] = '\0';
701 CONSOLE_ConOutChar('\n');
706 /* clear str Make this callable! */
707 ClearCommandLine (str
, maxlen
, orgx
, orgy
);
710 current
= charcount
= 0;
713 #ifdef FEATURE_HISTORY
715 History_move_to_bottom();
718 #ifdef FEATURE_HISTORY
719 /* get previous command from buffer */
720 ClearCommandLine (str
, maxlen
, orgx
, orgy
);
722 current
= charcount
= strlen (str
);
723 if (((charcount
+ orgx
) / maxx
) + orgy
> maxy
- 1)
724 orgy
+= maxy
- ((charcount
+ orgx
) / maxx
+ orgy
+ 1);
725 CONSOLE_ConOutPrintf("%s", str
);
726 CONSOLE_GetCursorXY(&curx
, &cury
);
731 #ifdef FEATURE_HISTORY
732 /* get next command from buffer */
733 ClearCommandLine (str
, maxlen
, orgx
, orgy
);
735 current
= charcount
= strlen (str
);
736 if (((charcount
+ orgx
) / maxx
) + orgy
> maxy
- 1)
737 orgy
+= maxy
- ((charcount
+ orgx
) / maxx
+ orgy
+ 1);
738 CONSOLE_ConOutPrintf("%s", str
);
739 CONSOLE_GetCursorXY(&curx
, &cury
);
744 /* move cursor left */
748 if (CONSOLE_GetCursorX() == 0)
750 CONSOLE_SetCursorXY((SHORT
)(State
->maxx
- 1), (SHORT
)(CONSOLE_GetCursorY () - 1));
751 curx
= State
->maxx
- 1;
756 CONSOLE_SetCursorXY((SHORT
)(CONSOLE_GetCursorX () - 1), CONSOLE_GetCursorY ());
763 /* move cursor right */
764 if (current
!= charcount
)
767 if (CONSOLE_GetCursorX() == State
->maxx
- 1)
769 CONSOLE_SetCursorXY(0, (SHORT
)(CONSOLE_GetCursorY () + 1));
775 CONSOLE_SetCursorXY((SHORT
)(CONSOLE_GetCursorX () + 1), CONSOLE_GetCursorY ());
779 #ifdef FEATURE_HISTORY
782 LPCSTR last
= PeekHistory(-1);
783 if (last
&& charcount
< (INT
)strlen (last
))
785 PreviousChar
= last
[current
];
786 CONSOLE_ConOutChar(PreviousChar
);
787 CONSOLE_GetCursorXY(&curx
, &cury
);
788 str
[current
++] = PreviousChar
;
796 /* This input is just a normal char */
801 ch
= ir
.Event
.KeyEvent
.uChar
.UnicodeChar
;
802 if (ch
>= 32 && (charcount
!= (maxlen
- 2)) && bCharInput
)
804 /* insert character into string... */
805 if (State
->bInsert
&& current
!= charcount
)
807 /* If this character insertion will cause screen scrolling,
808 * adjust the saved origin of the command prompt. */
809 tempscreen
= strlen(str
+ current
) + curx
;
810 if ((tempscreen
% State
->maxx
) == (State
->maxx
- 1) &&
811 (tempscreen
/ State
->maxx
) + cury
== (State
->maxy
- 1))
817 for (count
= charcount
; count
> current
; count
--)
818 str
[count
] = str
[count
- 1];
820 if (curx
== State
->maxx
- 1)
824 CONSOLE_ConOutPrintf("%s", &str
[current
- 1]);
825 CONSOLE_SetCursorXY(curx
, cury
);
830 if (current
== charcount
)
833 if (CONSOLE_GetCursorX () == State
->maxx
- 1 && CONSOLE_GetCursorY () == State
->maxy
- 1)
835 if (CONSOLE_GetCursorX () == State
->maxx
- 1)
839 CONSOLE_ConOutChar(ch
);
845 CONSOLE_SetCursorType(State
->bInsert
, TRUE
);
856 return (c
== '/' || c
== '=' || c
== '\0' || isspace(c
));
863 PCONSOLE_STATE State
,
866 CHAR com
[MAX_PATH
]; /* the first word in the command */
869 LPSTR rest
= line
; /* pointer to the rest of the command line */
873 DPRINT1("DoCommand: (\'%s\')\n", line
);
875 /* Skip over initial white space */
876 while (isspace(*rest
))
881 /* Anything to do ? */
884 /* Copy over 1st word as lower case */
885 while (!IsDelimiter(*rest
))
886 *cp
++ = tolower(*rest
++);
888 /* Terminate first word */
891 /* Skip over whitespace to rest of line */
892 while (isspace (*rest
))
895 /* Scan internal command table */
896 for (cmdptr
= Commands
; ; cmdptr
++)
898 /* If end of table execute ext cmd */
899 if (cmdptr
->name
== NULL
)
901 CONSOLE_ConOutPuts("Unknown command. Enter HELP to get a list of commands.");
905 if (strcmp(com
, cmdptr
->name
) == 0)
907 cmdptr
->func(State
, rest
);
912 /* The following code handles the case of commands like CD which
913 * are recognised even when the command name and parameter are
914 * not space separated.
920 /* Get length of command name */
921 cl
= strlen(cmdptr
->name
);
923 if ((cmdptr
->flags
& CMD_SPECIAL
) &&
924 (!strncmp (cmdptr
->name
, com
, cl
)) &&
925 (strchr("\\.-", *(com
+ cl
))))
927 /* OK its one of the specials...*/
929 /* Call with new rest */
930 cmdptr
->func(State
, cstart
+ cl
);
940 RecoveryConsole(VOID
)
942 CHAR szInputBuffer
[256];
943 CONSOLE_SCREEN_BUFFER_INFO csbi
;
946 GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE
), &csbi
);
948 /* get screen size */
949 State
.maxx
= csbi
.dwSize
.X
;
950 State
.maxy
= csbi
.dwSize
.Y
;
951 State
.bInsert
= TRUE
;
954 CONSOLE_ClearScreen();
955 CONSOLE_SetCursorXY(0, 0);
957 CONSOLE_ConOutPrintf("ReactOS Recovery Console\n\nEnter HELP to get a list of commands.\n\n");
962 CONSOLE_ConOutPrintf(">");
964 ReadCommand(&State
, szInputBuffer
, 256);
965 DPRINT1("%s\n", szInputBuffer
);
967 DoCommand(&State
, szInputBuffer
);
969 // Cmd = ParseCommand(NULL);
973 // ExecuteCommand(Cmd);