bootloader: usability improvements
- add "edit" menu option, to edit menu commands before executing them; - add "menu" boot command, to return to the menu from the prompt; - provide more line editing features when getting input; - fix a few potential buffer overflows as a side effect.
This commit is contained in:
parent
52cf951fdc
commit
9733fcdb43
8 changed files with 202 additions and 22 deletions
|
@ -4,4 +4,5 @@ default=2
|
||||||
menu=Start MINIX 3:load_mods /boot/minix_default/mod*;multiboot /boot/minix_default/kernel rootdevname=$rootdevname
|
menu=Start MINIX 3:load_mods /boot/minix_default/mod*;multiboot /boot/minix_default/kernel rootdevname=$rootdevname
|
||||||
menu=Start latest MINIX 3:load_mods /boot/minix_latest/mod*;multiboot /boot/minix_latest/kernel rootdevname=$rootdevname
|
menu=Start latest MINIX 3:load_mods /boot/minix_latest/mod*;multiboot /boot/minix_latest/kernel rootdevname=$rootdevname
|
||||||
menu=Start latest MINIX 3 in single user mode:load_mods /boot/minix_latest/mod*;multiboot /boot/minix_latest/kernel rootdevname=$rootdevname bootopts=-s
|
menu=Start latest MINIX 3 in single user mode:load_mods /boot/minix_latest/mod*;multiboot /boot/minix_latest/kernel rootdevname=$rootdevname bootopts=-s
|
||||||
|
menu=Edit menu option:edit
|
||||||
menu=Drop to boot prompt:prompt
|
menu=Drop to boot prompt:prompt
|
||||||
|
|
|
@ -130,6 +130,9 @@ Each command is executed just as though the user had typed it in
|
||||||
and so can be any valid command that would be accepted at the
|
and so can be any valid command that would be accepted at the
|
||||||
normal boot prompt.
|
normal boot prompt.
|
||||||
In addition,
|
In addition,
|
||||||
|
.Dq Ic edit
|
||||||
|
can be used to put the menu in editing mode, allowing the user to modify the
|
||||||
|
next selected option before executing it, and
|
||||||
.Dq Ic prompt
|
.Dq Ic prompt
|
||||||
can be used to drop to the normal boot prompt.
|
can be used to drop to the normal boot prompt.
|
||||||
.It Sy timeout
|
.It Sy timeout
|
||||||
|
|
|
@ -61,6 +61,7 @@ banner=Welcome to the MINIX 3 installation CD
|
||||||
banner================================================================================
|
banner================================================================================
|
||||||
banner=
|
banner=
|
||||||
menu=Regular MINIX 3:multiboot /kernel bootcd=1 cdproberoot=1 rootdevname=ram disable=inet
|
menu=Regular MINIX 3:multiboot /kernel bootcd=1 cdproberoot=1 rootdevname=ram disable=inet
|
||||||
|
menu=Edit menu option:edit
|
||||||
menu=Drop to boot prompt:prompt
|
menu=Drop to boot prompt:prompt
|
||||||
clear=1
|
clear=1
|
||||||
timeout=10
|
timeout=10
|
||||||
|
@ -106,6 +107,7 @@ hdemu_root_changes()
|
||||||
|
|
||||||
cat >$RELEASEMNTDIR/boot.cfg <<END_BOOT_CFG
|
cat >$RELEASEMNTDIR/boot.cfg <<END_BOOT_CFG
|
||||||
menu=Regular MINIX 3:load_mods /boot/minix_default/mod*;multiboot /boot/minix_default/kernel bootcd=2 disable=inet bios_wini=yes bios_remap_first=1 ramimagedev=c0d7p0s0
|
menu=Regular MINIX 3:load_mods /boot/minix_default/mod*;multiboot /boot/minix_default/kernel bootcd=2 disable=inet bios_wini=yes bios_remap_first=1 ramimagedev=c0d7p0s0
|
||||||
|
menu=Edit menu option:edit
|
||||||
menu=Drop to boot prompt:prompt
|
menu=Drop to boot prompt:prompt
|
||||||
clear=1
|
clear=1
|
||||||
timeout=10
|
timeout=10
|
||||||
|
@ -120,6 +122,7 @@ usb_root_changes()
|
||||||
echo \
|
echo \
|
||||||
cat >$RELEASEMNTDIR/boot.cfg <<END_BOOT_CFG
|
cat >$RELEASEMNTDIR/boot.cfg <<END_BOOT_CFG
|
||||||
menu=Regular MINIX 3:load_mods /boot/minix_default/mod*;multiboot /boot/minix_default/kernel bios_wini=yes bios_remap_first=1 rootdevname=c0d7p0s0
|
menu=Regular MINIX 3:load_mods /boot/minix_default/mod*;multiboot /boot/minix_default/kernel bios_wini=yes bios_remap_first=1 rootdevname=c0d7p0s0
|
||||||
|
menu=Edit menu option:edit
|
||||||
menu=Drop to boot prompt:prompt
|
menu=Drop to boot prompt:prompt
|
||||||
clear=1
|
clear=1
|
||||||
timeout=10
|
timeout=10
|
||||||
|
|
|
@ -297,11 +297,10 @@ getchoicefrominput(char *input, int def)
|
||||||
return choice;
|
return choice;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static void
|
||||||
doboottypemenu(void)
|
showmenu(void)
|
||||||
{
|
{
|
||||||
int choice;
|
int choice;
|
||||||
char input[80], *ic, *oc;
|
|
||||||
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
/* Display menu */
|
/* Display menu */
|
||||||
|
@ -317,19 +316,31 @@ doboottypemenu(void)
|
||||||
choice + 1,
|
choice + 1,
|
||||||
bootconf.desc[choice]);
|
bootconf.desc[choice]);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
doboottypemenu(void)
|
||||||
|
{
|
||||||
|
int choice, editing;
|
||||||
|
char input[256], *ic, *oc;
|
||||||
|
|
||||||
|
showmenu();
|
||||||
choice = -1;
|
choice = -1;
|
||||||
|
editing = 0;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
input[0] = '\0';
|
input[0] = '\0';
|
||||||
|
|
||||||
if (bootconf.timeout < 0) {
|
if (bootconf.timeout < 0) {
|
||||||
if (bootconf.menuformat == MENUFORMAT_LETTER)
|
if (bootconf.menuformat == MENUFORMAT_LETTER)
|
||||||
printf("\nOption: [%c]:",
|
printf("\nOption%s: [%c]:",
|
||||||
|
editing ? " (edit)" : "",
|
||||||
bootconf.def + 'A');
|
bootconf.def + 'A');
|
||||||
else
|
else
|
||||||
printf("\nOption: [%d]:",
|
printf("\nOption%s: [%d]:",
|
||||||
|
editing ? " (edit)" : "",
|
||||||
bootconf.def + 1);
|
bootconf.def + 1);
|
||||||
|
|
||||||
gets(input);
|
editline(input, sizeof(input), NULL);
|
||||||
choice = getchoicefrominput(input, bootconf.def);
|
choice = getchoicefrominput(input, bootconf.def);
|
||||||
} else if (bootconf.timeout == 0)
|
} else if (bootconf.timeout == 0)
|
||||||
choice = bootconf.def;
|
choice = bootconf.def;
|
||||||
|
@ -351,27 +362,45 @@ doboottypemenu(void)
|
||||||
}
|
}
|
||||||
if (choice < 0)
|
if (choice < 0)
|
||||||
continue;
|
continue;
|
||||||
if (!strcmp(bootconf.command[choice], "prompt") &&
|
ic = bootconf.command[choice];
|
||||||
|
if (editing) {
|
||||||
|
printf("> ");
|
||||||
|
editline(input, sizeof(input), ic);
|
||||||
|
ic = input;
|
||||||
|
}
|
||||||
|
if (!strcmp(ic, "edit") &&
|
||||||
((boot_params.bp_flags & X86_BP_FLAGS_PASSWORD) == 0 ||
|
((boot_params.bp_flags & X86_BP_FLAGS_PASSWORD) == 0 ||
|
||||||
check_password((char *)boot_params.bp_password))) {
|
check_password((char *)boot_params.bp_password))) {
|
||||||
printf("type \"?\" or \"help\" for help.\n");
|
editing = 1;
|
||||||
bootmenu(); /* does not return */
|
bootconf.timeout = -1;
|
||||||
|
} else if (!strcmp(ic, "prompt") &&
|
||||||
|
((boot_params.bp_flags & X86_BP_FLAGS_PASSWORD) == 0 ||
|
||||||
|
check_password((char *)boot_params.bp_password))) {
|
||||||
|
printf("type \"?\" or \"help\" for help, "
|
||||||
|
"or \"menu\" to return to the menu.\n");
|
||||||
|
prompt(1);
|
||||||
|
showmenu();
|
||||||
|
editing = 0;
|
||||||
|
bootconf.timeout = -1;
|
||||||
} else {
|
} else {
|
||||||
ic = bootconf.command[choice];
|
|
||||||
/* Split command string at ; into separate commands */
|
/* Split command string at ; into separate commands */
|
||||||
do {
|
do {
|
||||||
|
/*
|
||||||
|
* This must support inline editing, since ic
|
||||||
|
* may also point to input.
|
||||||
|
*/
|
||||||
oc = input;
|
oc = input;
|
||||||
/* Look for ; separator */
|
/* Look for ; separator */
|
||||||
for (; *ic && *ic != COMMAND_SEPARATOR; ic++)
|
for (; *ic && *ic != COMMAND_SEPARATOR; ic++)
|
||||||
*oc++ = *ic;
|
*oc++ = *ic;
|
||||||
if (*input == '\0')
|
if (*ic == COMMAND_SEPARATOR)
|
||||||
|
ic++;
|
||||||
|
if (oc == input)
|
||||||
continue;
|
continue;
|
||||||
/* Strip out any trailing spaces */
|
/* Strip out any trailing spaces */
|
||||||
oc--;
|
oc--;
|
||||||
for (; *oc == ' ' && oc > input; oc--);
|
for (; *oc == ' ' && oc > input; oc--);
|
||||||
*++oc = '\0';
|
*++oc = '\0';
|
||||||
if (*ic == COMMAND_SEPARATOR)
|
|
||||||
ic++;
|
|
||||||
/* Stop silly command strings like ;;; */
|
/* Stop silly command strings like ;;; */
|
||||||
if (*input != '\0')
|
if (*input != '\0')
|
||||||
docommand(input);
|
docommand(input);
|
||||||
|
|
|
@ -45,9 +45,30 @@ ENTRY(conputc)
|
||||||
call _C_LABEL(prot_to_real) # enter real mode
|
call _C_LABEL(prot_to_real) # enter real mode
|
||||||
.code16
|
.code16
|
||||||
|
|
||||||
|
cmp $0x08, %al # backspace?
|
||||||
|
jne print_char
|
||||||
|
|
||||||
|
# Multiline backspace support.
|
||||||
|
push %ax
|
||||||
|
movb $0x3, %ah # get cursor position
|
||||||
|
xorw %bx, %bx
|
||||||
|
int $0x10
|
||||||
|
pop %ax
|
||||||
|
testb %dl, %dl # cursor on first column?
|
||||||
|
jnz print_char
|
||||||
|
testb %dh, %dh # cursor not on first row?
|
||||||
|
jz print_char
|
||||||
|
decb %dh # move up one row
|
||||||
|
movb $0x4f, %dl # move to last column
|
||||||
|
xorw %bx, %bx
|
||||||
|
movb $0x02, %ah # set cursor position
|
||||||
|
jmp do_int
|
||||||
|
|
||||||
|
print_char:
|
||||||
movw $1,%bx
|
movw $1,%bx
|
||||||
movb $0x0e,%ah
|
movb $0x0e,%ah # print character
|
||||||
movb %al, %cl
|
movb %al, %cl
|
||||||
|
do_int:
|
||||||
int $0x10
|
int $0x10
|
||||||
|
|
||||||
calll _C_LABEL(real_to_prot) # back to protected mode
|
calll _C_LABEL(real_to_prot) # back to protected mode
|
||||||
|
@ -68,12 +89,12 @@ ENTRY(congetc)
|
||||||
|
|
||||||
movb $0x0,%ah
|
movb $0x0,%ah
|
||||||
int $0x16
|
int $0x16
|
||||||
movb %al,%bl
|
movw %ax,%bx
|
||||||
|
|
||||||
calll _C_LABEL(real_to_prot) # back to protected mode
|
calll _C_LABEL(real_to_prot) # back to protected mode
|
||||||
.code32
|
.code32
|
||||||
|
|
||||||
movb %bl, 28(%esp)
|
movw %bx, 28(%esp)
|
||||||
|
|
||||||
popa
|
popa
|
||||||
ret
|
ret
|
||||||
|
|
|
@ -91,7 +91,9 @@ struct bootblk_command {
|
||||||
void (*c_fn)(char *);
|
void (*c_fn)(char *);
|
||||||
};
|
};
|
||||||
void bootmenu(void);
|
void bootmenu(void);
|
||||||
|
void prompt(int);
|
||||||
void docommand(char *);
|
void docommand(char *);
|
||||||
|
void editline(char *, size_t, char *);
|
||||||
|
|
||||||
/* in "user code": */
|
/* in "user code": */
|
||||||
void command_help(char *);
|
void command_help(char *);
|
||||||
|
@ -114,6 +116,8 @@ int coniskey(void);
|
||||||
__compactcall void conputc(int);
|
__compactcall void conputc(int);
|
||||||
void conclr(void);
|
void conclr(void);
|
||||||
|
|
||||||
|
int getchar_ex(void);
|
||||||
|
|
||||||
int getextmem2(int *);
|
int getextmem2(int *);
|
||||||
__compactcall int getextmemps2(void *);
|
__compactcall int getextmemps2(void *);
|
||||||
int getmementry(int *, int *);
|
int getmementry(int *, int *);
|
||||||
|
|
|
@ -62,23 +62,136 @@ docommand(char *arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
bootmenu(void)
|
prompt(int allowreturn)
|
||||||
{
|
{
|
||||||
char input[80];
|
char input[80];
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
char *c = input;
|
char *c = input;
|
||||||
|
|
||||||
input[0] = '\0';
|
|
||||||
printf("> ");
|
printf("> ");
|
||||||
gets(input);
|
editline(input, sizeof(input), NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Skip leading whitespace.
|
* Skip leading whitespace.
|
||||||
*/
|
*/
|
||||||
while (*c == ' ')
|
while (*c == ' ')
|
||||||
c++;
|
c++;
|
||||||
|
if (allowreturn && !strcmp(c, "menu"))
|
||||||
|
break;
|
||||||
if (*c)
|
if (*c)
|
||||||
docommand(c);
|
docommand(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
bootmenu(void)
|
||||||
|
{
|
||||||
|
prompt(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Derived from libsa gets(). */
|
||||||
|
void
|
||||||
|
editline(char *buf, size_t size, char *input)
|
||||||
|
{
|
||||||
|
int c, i, pos, len = 0;
|
||||||
|
|
||||||
|
/* If an initial input has been given, copy and print this first. */
|
||||||
|
if (input != NULL) {
|
||||||
|
while (*input && len < size - 1)
|
||||||
|
putchar(buf[len++] = *input++);
|
||||||
|
}
|
||||||
|
pos = len;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
c = getchar_ex();
|
||||||
|
switch (c & 0177) {
|
||||||
|
case '\0':
|
||||||
|
switch (c) {
|
||||||
|
case 0x4b00: /* Left arrow: move cursor to left. */
|
||||||
|
if (pos > 0) {
|
||||||
|
putchar('\b');
|
||||||
|
pos--;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x4d00: /* Right arrow: move cursor to right. */
|
||||||
|
if (pos < len) putchar(buf[pos++]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'b' & 037: /* Ctrl+B: move cursor to left. */
|
||||||
|
if (pos > 0) {
|
||||||
|
putchar('\b');
|
||||||
|
pos--;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'f' & 037: /* Ctrl+F: move cursor to right. */
|
||||||
|
if (pos < len) putchar(buf[pos++]);
|
||||||
|
break;
|
||||||
|
case 'a' & 037: /* Ctrl+A: move cursor to start of line. */
|
||||||
|
for ( ; pos > 0; pos--) putchar('\b');
|
||||||
|
break;
|
||||||
|
case 'e' & 037: /* Ctrl+E: move cursor to end of line. */
|
||||||
|
for ( ; pos < len; pos++) putchar(buf[pos]);
|
||||||
|
break;
|
||||||
|
case '\n': /* Enter: return line. */
|
||||||
|
case '\r':
|
||||||
|
for ( ; pos < len; pos++) putchar(buf[pos]);
|
||||||
|
buf[len] = '\0';
|
||||||
|
putchar('\n');
|
||||||
|
return;
|
||||||
|
#if HASH_ERASE
|
||||||
|
case '#':
|
||||||
|
#endif
|
||||||
|
case '\b': /* Backspace: erase character before cursor. */
|
||||||
|
case '\177':
|
||||||
|
if (pos > 0) {
|
||||||
|
pos--;
|
||||||
|
len--;
|
||||||
|
putchar('\b');
|
||||||
|
for (i = pos; i < len; i++)
|
||||||
|
putchar(buf[i] = buf[i + 1]);
|
||||||
|
putchar(' ');
|
||||||
|
for (i = pos; i < len; i++) putchar('\b');
|
||||||
|
putchar('\b');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'r' & 037: /* Ctrl+R: reprint line. */
|
||||||
|
putchar('\n');
|
||||||
|
for (i = 0; i < len; i++) putchar(buf[i]);
|
||||||
|
for (i = len; i > pos; i--) putchar('\b');
|
||||||
|
break;
|
||||||
|
#if AT_ERASE
|
||||||
|
case '@':
|
||||||
|
#endif
|
||||||
|
case 'u' & 037: /* Ctrl+U: clear entire line. */
|
||||||
|
case 'w' & 037:
|
||||||
|
for ( ; pos > 0; pos--) putchar('\b');
|
||||||
|
for ( ; pos < len; pos++) putchar(' ');
|
||||||
|
for ( ; pos > 0; pos--) putchar('\b');
|
||||||
|
len = 0;
|
||||||
|
break;
|
||||||
|
case '\a': /* Ctrl+G: sound bell but do not store character. */
|
||||||
|
putchar(c);
|
||||||
|
break;
|
||||||
|
case '\t': /* Tab: convert to single space. */
|
||||||
|
c = ' ';
|
||||||
|
/*FALLTHROUGH*/
|
||||||
|
default: /* Insert character at cursor position. */
|
||||||
|
if (len < size - 1) {
|
||||||
|
for (i = len; i > pos; i--)
|
||||||
|
buf[i] = buf[i - 1];
|
||||||
|
buf[pos] = c;
|
||||||
|
pos++;
|
||||||
|
len++;
|
||||||
|
putchar(c);
|
||||||
|
for (i = pos; i < len; i++) putchar(buf[i]);
|
||||||
|
for (i = pos; i < len; i++) putchar('\b');
|
||||||
|
} else {
|
||||||
|
putchar('\a');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*NOTREACHED*/
|
||||||
|
}
|
||||||
|
|
|
@ -259,7 +259,7 @@ putchar(int c)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
getchar(void)
|
getchar_ex(void)
|
||||||
{
|
{
|
||||||
int c;
|
int c;
|
||||||
#ifdef SUPPORT_SERIAL
|
#ifdef SUPPORT_SERIAL
|
||||||
|
@ -272,9 +272,9 @@ getchar(void)
|
||||||
c = congetc();
|
c = congetc();
|
||||||
#ifdef CONSOLE_KEYMAP
|
#ifdef CONSOLE_KEYMAP
|
||||||
{
|
{
|
||||||
char *cp = strchr(CONSOLE_KEYMAP, c);
|
char *cp = strchr(CONSOLE_KEYMAP, c & 0xff);
|
||||||
if (cp != 0 && cp[1] != 0)
|
if (cp != 0 && cp[1] != 0)
|
||||||
c = cp[1];
|
c = cp[1] | (c & 0xff00);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return c;
|
return c;
|
||||||
|
@ -302,6 +302,12 @@ getchar(void)
|
||||||
#endif /* SUPPORT_SERIAL */
|
#endif /* SUPPORT_SERIAL */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
getchar(void)
|
||||||
|
{
|
||||||
|
return getchar_ex() & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
iskey(int intr)
|
iskey(int intr)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue