From 6608e1b9e21b183a876bc44ae6b7cfef435a7556 Mon Sep 17 00:00:00 2001 From: okuji Date: Sun, 5 Sep 1999 05:54:33 +0000 Subject: [PATCH] The internal of the command handling is heavily modified, and a new command help is added. --- ChangeLog | 82 +++ NEWS | 3 + stage1/stage1.S | 2 +- stage1/stage1_lba.S | 2 +- stage2/Makefile.am | 12 +- stage2/Makefile.in | 201 ++++--- stage2/boot.c | 44 +- stage2/builtins.c | 1398 +++++++++++++++++++++++++++++++++++++++++++ stage2/char_io.c | 96 +-- stage2/cmdline.c | 763 ++++------------------- stage2/shared.h | 72 ++- stage2/size_test | 2 +- stage2/stage2.c | 353 ++++++----- 13 files changed, 2026 insertions(+), 1004 deletions(-) create mode 100644 stage2/builtins.c diff --git a/ChangeLog b/ChangeLog index 34df1f590..398aafcdc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,85 @@ +1999-09-05 OKUJI Yoshinori + + The internal of the command handling is heavily modified, and + a new command "help" is added. + + * stage1/stage1.S: Set the number of sectors for Stage 2 to 110. + * stage1/stage1_lba.S: Likewise. + * stage2/builtins.c: New file. + * stage2/Makefile.am (libgrub_a_SOURCES): Added builtins.c. + (stage2_exec_SOURCES): Likewise. + * stage2/boot.c (load_image): Return kernel_t instead int. + (bsd_boot): Change the type of the first argument to kernel_t. + * stage2/char_io.c (get_cmdline): Do not accept the argument + COMMANDS and accept the argument COMPLETION. + Print completions only if COMPLETION is non-zero. + Print the list of short docs when the command is completed. + * stage2/cmdline.c [GRUB_UTIL]: Do not include apic.h and + smp-imps.h. + (fallback): Deleted. + (password): Likewise. + (debug): Likewise. + (normal_color): Likewise. + (highlight_color): Likewise. + (print_cmdline_message): New function. + (commands): Deleted. + (debug_fs_print_func): Likewise. + (installaddr): Likewise. + (installlist): Likewise. + (installsect): Likewise. + (debug_fs_blocklist_func): Likewise. + (find_command): New function. + (init_cmdline): Initialize the data for the command-line + interface. The function to print the message is moved to + print_cmdline_message. + (enter_cmdline): Rewritten from scratch. Now deal with only the + pure command-line and the function to deal with a menu entry is + moved to run_script. + (run_script): New function. + * stage2/shared.h (PASSWORD_BUF): New macro. + (PASSWORD_BUFLEN): Likewise. + (CMDLINE_BUF): Likewise. + (CMDLINE_BUFLEN): Likewise. + (MENU_BUF): Likewise. + (MENU_BUFLEN): Likewise. + (fallback): Deleted. + (fallback_entry): Declared. + (default_entry): Likewise. + (BUILTIN_CMDLINE): New macro. + (BUILTIN_MENU): Likewise. + (BUILTIN_TITLE): Likewise. + (struct builtin): New tag. + (builtin_table): Declared. + (cmdline_t): Deleted. + (kernel_t): New type. + (kernel_type): Declared. + (grub_timeout): Likewise. + (init_builtins): Likewise. + (init_config): Likewise. + (find_command): Likewise. + (print_cmdline_message): Likewise. + (run_script): Likewise. + [!STAGE1_5] (bsd_boot): Deleted. + [!STAGE1_5] (load_image): Likewise. + [!STAGE1_5] (load_module): Likewise. + [!STAGE1_5] (load_initrd): Likewise. + * stage2/size_test: Set the maximum size of Stage 2 to 56320. + * stage2/stage2.c (grub_timeout): Deleted. + (menu_t): Likewise. + (run_menu): Changed the return type to void. + Use FALLBACK_ENTRY instead of FALLBACK. + Do not check the return value of enter_cmdline. + (run_menu) [GRUB_UTIL]: Call stop instead of returning + MENU_ABORT. + (cmain): Set MENU_ENTRIES to MENU_BUF. + Call init_config instead of clearing the variables directly. + Use CMDLINE_BUF for the command-line buffer instead of the + stack. + Adapted the analysis routine for the configuration file to the + new builtin commands interface. + Run enter_cmdline forever. + If run_menu returns, restart the loop. + 1999-09-04 Pavel Roskin * docs/menu.lst: More meaningful examples. Not using (0x80,0) diff --git a/NEWS b/NEWS index 324cdfd31..a790d8637 100644 --- a/NEWS +++ b/NEWS @@ -10,6 +10,9 @@ New in 0.5.93: * New commands "hide" and "unhide". * The character `=' after a command is not necessary any longer, but it is supported for backward compatibility. +* The command "help" displays helpful information about builtin + commands. +* The command "geometry" displays the information of a drive specified. New in 0.5.92 - 1999-07-26: * Bug fixes (i.e. Stage 1.5 can work fine again). diff --git a/stage1/stage1.S b/stage1/stage1.S index 0bb924b62..c0a23556b 100644 --- a/stage1/stage1.S +++ b/stage1/stage1.S @@ -398,7 +398,7 @@ lastlist: #else .long 1 /* this is the sector start parameter, in logical sectors from the start of the disk, sector 0 */ - .word 90 /* this is the number of sectors to read */ + .word 110 /* this is the number of sectors to read */ .word 0x0800 /* this is the segment of the starting address to load the data into */ #endif diff --git a/stage1/stage1_lba.S b/stage1/stage1_lba.S index 516c7349f..933c362f4 100644 --- a/stage1/stage1_lba.S +++ b/stage1/stage1_lba.S @@ -345,7 +345,7 @@ lastlist: #else .long 1 /* this is the sector start parameter, in logical sectors from the start of the disk, sector 0 */ - .word 90 /* this is the number of sectors to read */ + .word 110 /* this is the number of sectors to read */ .word 0x0800 /* this is the segment of the starting address to load the data into */ #endif diff --git a/stage2/Makefile.am b/stage2/Makefile.am index d2ed8456d..1cda8ccfc 100644 --- a/stage2/Makefile.am +++ b/stage2/Makefile.am @@ -13,9 +13,9 @@ INCLUDES = -I$(top_srcdir)/stage1 # The library for /sbin/grub. noinst_LIBRARIES = libgrub.a -libgrub_a_SOURCES = boot.c common.c char_io.c cmdline.c disk_io.c \ - gunzip.c fsys_ffs.c fsys_ext2fs.c fsys_fat.c fsys_minix.c \ - stage2.c +libgrub_a_SOURCES = boot.c builtins.c common.c char_io.c cmdline.c \ + disk_io.c gunzip.c fsys_ffs.c fsys_ext2fs.c fsys_fat.c \ + fsys_minix.c stage2.c libgrub_a_CFLAGS = $(GRUB_CFLAGS) -DGRUB_UTIL=1 -DFSYS_EXT2FS=1 \ -DFSYS_FAT=1 -DFSYS_FFS=1 -DFSYS_MINIX=1 -fwritable-strings @@ -37,9 +37,9 @@ STAGE1_5_COMPILE = $(STAGE2_COMPILE) -DNO_DECOMPRESSION=1 -DSTAGE1_5=1 \ # asm.S absolutely needs to come first! # For stage2 target. -stage2_exec_SOURCES = asm.S boot.c common.c char_io.c cmdline.c \ - disk_io.c gunzip.c stage2.c bios.c smp-imps.c fsys_ext2fs.c \ - fsys_fat.c fsys_ffs.c fsys_minix.c +stage2_exec_SOURCES = asm.S bios.c boot.c builtins.c common.c \ + char_io.c cmdline.c disk_io.c gunzip.c fsys_ext2fs.c \ + fsys_fat.c fsys_ffs.c fsys_minix.c smp-imps.c stage2.c stage2_exec_CFLAGS = $(STAGE2_COMPILE) $(FSYS_CFLAGS) stage2_exec_LDFLAGS = $(STAGE2_LINK) diff --git a/stage2/Makefile.in b/stage2/Makefile.in index 038bc3ea0..2ccaa2950 100644 --- a/stage2/Makefile.in +++ b/stage2/Makefile.in @@ -94,9 +94,9 @@ INCLUDES = -I$(top_srcdir)/stage1 # The library for /sbin/grub. noinst_LIBRARIES = libgrub.a -libgrub_a_SOURCES = boot.c common.c char_io.c cmdline.c disk_io.c \ - gunzip.c fsys_ffs.c fsys_ext2fs.c fsys_fat.c fsys_minix.c \ - stage2.c +libgrub_a_SOURCES = boot.c builtins.c common.c char_io.c cmdline.c \ + disk_io.c gunzip.c fsys_ffs.c fsys_ext2fs.c fsys_fat.c \ + fsys_minix.c stage2.c libgrub_a_CFLAGS = $(GRUB_CFLAGS) -DGRUB_UTIL=1 -DFSYS_EXT2FS=1 \ -DFSYS_FAT=1 -DFSYS_FFS=1 -DFSYS_MINIX=1 -fwritable-strings @@ -123,9 +123,9 @@ STAGE1_5_COMPILE = $(STAGE2_COMPILE) -DNO_DECOMPRESSION=1 -DSTAGE1_5=1 \ # asm.S absolutely needs to come first! # For stage2 target. -stage2_exec_SOURCES = asm.S boot.c common.c char_io.c cmdline.c \ - disk_io.c gunzip.c stage2.c bios.c smp-imps.c fsys_ext2fs.c \ - fsys_fat.c fsys_ffs.c fsys_minix.c +stage2_exec_SOURCES = asm.S bios.c boot.c builtins.c common.c \ + char_io.c cmdline.c disk_io.c gunzip.c fsys_ext2fs.c \ + fsys_fat.c fsys_ffs.c fsys_minix.c smp-imps.c stage2.c stage2_exec_CFLAGS = $(STAGE2_COMPILE) $(FSYS_CFLAGS) stage2_exec_LDFLAGS = $(STAGE2_LINK) @@ -176,10 +176,11 @@ LDFLAGS = @LDFLAGS@ LIBS = @LIBS@ libgrub_a_AR = $(AR) cru libgrub_a_LIBADD = -am_libgrub_a_OBJECTS = libgrub_a-boot.o libgrub_a-common.o \ -libgrub_a-char_io.o libgrub_a-cmdline.o libgrub_a-disk_io.o \ -libgrub_a-gunzip.o libgrub_a-fsys_ffs.o libgrub_a-fsys_ext2fs.o \ -libgrub_a-fsys_fat.o libgrub_a-fsys_minix.o libgrub_a-stage2.o +am_libgrub_a_OBJECTS = libgrub_a-boot.o libgrub_a-builtins.o \ +libgrub_a-common.o libgrub_a-char_io.o libgrub_a-cmdline.o \ +libgrub_a-disk_io.o libgrub_a-gunzip.o libgrub_a-fsys_ffs.o \ +libgrub_a-fsys_ext2fs.o libgrub_a-fsys_fat.o libgrub_a-fsys_minix.o \ +libgrub_a-stage2.o libgrub_a_OBJECTS = $(am_libgrub_a_OBJECTS) AR = ar PROGRAMS = $(noinst_PROGRAMS) @@ -212,11 +213,12 @@ minix_stage1_5_exec-fsys_minix.o minix_stage1_5_exec-bios.o minix_stage1_5_exec_OBJECTS = $(am_minix_stage1_5_exec_OBJECTS) minix_stage1_5_exec_LDADD = $(LDADD) minix_stage1_5_exec_DEPENDENCIES = -am_stage2_exec_OBJECTS = stage2_exec-asm.o stage2_exec-boot.o \ -stage2_exec-common.o stage2_exec-char_io.o stage2_exec-cmdline.o \ -stage2_exec-disk_io.o stage2_exec-gunzip.o stage2_exec-stage2.o \ -stage2_exec-bios.o stage2_exec-smp-imps.o stage2_exec-fsys_ext2fs.o \ -stage2_exec-fsys_fat.o stage2_exec-fsys_ffs.o stage2_exec-fsys_minix.o +am_stage2_exec_OBJECTS = stage2_exec-asm.o stage2_exec-bios.o \ +stage2_exec-boot.o stage2_exec-builtins.o stage2_exec-common.o \ +stage2_exec-char_io.o stage2_exec-cmdline.o stage2_exec-disk_io.o \ +stage2_exec-gunzip.o stage2_exec-fsys_ext2fs.o stage2_exec-fsys_fat.o \ +stage2_exec-fsys_ffs.o stage2_exec-fsys_minix.o stage2_exec-smp-imps.o \ +stage2_exec-stage2.o stage2_exec_OBJECTS = $(am_stage2_exec_OBJECTS) stage2_exec_LDADD = $(LDADD) stage2_exec_DEPENDENCIES = @@ -239,10 +241,11 @@ DIST_COMMON = $(noinst_HEADERS) Makefile.am Makefile.in compile DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) GZIP_ENV = --best -DEP_FILES = .deps/asm.P .deps/bios.P .deps/boot.P .deps/char_io.P \ -.deps/cmdline.P .deps/common.P .deps/disk_io.P .deps/fsys_ext2fs.P \ -.deps/fsys_fat.P .deps/fsys_ffs.P .deps/fsys_minix.P .deps/gunzip.P \ -.deps/smp-imps.P .deps/stage1_5.P .deps/stage2.P +DEP_FILES = .deps/asm.P .deps/bios.P .deps/boot.P .deps/builtins.P \ +.deps/char_io.P .deps/cmdline.P .deps/common.P .deps/disk_io.P \ +.deps/fsys_ext2fs.P .deps/fsys_fat.P .deps/fsys_ffs.P \ +.deps/fsys_minix.P .deps/gunzip.P .deps/smp-imps.P .deps/stage1_5.P \ +.deps/stage2.P SOURCES = $(libgrub_a_SOURCES) $(e2fs_stage1_5_exec_SOURCES) $(fat_stage1_5_exec_SOURCES) $(ffs_stage1_5_exec_SOURCES) $(minix_stage1_5_exec_SOURCES) $(stage2_exec_SOURCES) OBJECTS = $(am_libgrub_a_OBJECTS) $(am_e2fs_stage1_5_exec_OBJECTS) $(am_fat_stage1_5_exec_OBJECTS) $(am_ffs_stage1_5_exec_OBJECTS) $(am_minix_stage1_5_exec_OBJECTS) $(am_stage2_exec_OBJECTS) @@ -276,6 +279,7 @@ distclean-compile: maintainer-clean-compile: libgrub_a-boot.o: boot.c +libgrub_a-builtins.o: builtins.c libgrub_a-common.o: common.c libgrub_a-char_io.o: char_io.c libgrub_a-cmdline.o: cmdline.c @@ -350,19 +354,20 @@ minix_stage1_5.exec: $(minix_stage1_5_exec_OBJECTS) $(minix_stage1_5_exec_DEPEND $(LINK) $(minix_stage1_5_exec_LDFLAGS) $(minix_stage1_5_exec_OBJECTS) $(minix_stage1_5_exec_LDADD) $(LIBS) stage2_exec-asm.o: asm.S $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stage2_exec_CFLAGS) $(CFLAGS) -c -o stage2_exec-asm.o $< +stage2_exec-bios.o: bios.c stage2_exec-boot.o: boot.c +stage2_exec-builtins.o: builtins.c stage2_exec-common.o: common.c stage2_exec-char_io.o: char_io.c stage2_exec-cmdline.o: cmdline.c stage2_exec-disk_io.o: disk_io.c stage2_exec-gunzip.o: gunzip.c -stage2_exec-stage2.o: stage2.c -stage2_exec-bios.o: bios.c -stage2_exec-smp-imps.o: smp-imps.c stage2_exec-fsys_ext2fs.o: fsys_ext2fs.c stage2_exec-fsys_fat.o: fsys_fat.c stage2_exec-fsys_ffs.o: fsys_ffs.c stage2_exec-fsys_minix.o: fsys_minix.c +stage2_exec-smp-imps.o: smp-imps.c +stage2_exec-stage2.o: stage2.c stage2.exec: $(stage2_exec_OBJECTS) $(stage2_exec_DEPENDENCIES) @rm -f stage2.exec @@ -493,6 +498,25 @@ libgrub_a-boot.lo: boot.c >> .deps/$(*D)/$(*F).P; \ rm -f .deps/$(*D)/$(*F).pp +libgrub_a-builtins.o: builtins.c + @echo '$(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgrub_a_CFLAGS) $(CFLAGS) -c -o $@ $<'; \ + $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgrub_a_CFLAGS) $(CFLAGS) -Wp,-MD,.deps/$(*D)/$(*F).pp -c -o $@ $< + @-cp .deps/$(*D)/$(*F).pp .deps/$(*D)/$(*F).P; \ + tr ' ' '\012' < .deps/$(*D)/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*D)/$(*F).P; \ + rm .deps/$(*D)/$(*F).pp + +libgrub_a-builtins.lo: builtins.c + @echo '$(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgrub_a_CFLAGS) $(CFLAGS) -c -o $@ $<'; \ + $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgrub_a_CFLAGS) $(CFLAGS) -Wp,-MD,.deps/$(*D)/$(*F).pp -c -o $@ $< + @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \ + < .deps/$(*D)/$(*F).pp > .deps/$(*D)/$(*F).P; \ + tr ' ' '\012' < .deps/$(*D)/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*D)/$(*F).P; \ + rm -f .deps/$(*D)/$(*F).pp + libgrub_a-common.o: common.c @echo '$(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgrub_a_CFLAGS) $(CFLAGS) -c -o $@ $<'; \ $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgrub_a_CFLAGS) $(CFLAGS) -Wp,-MD,.deps/$(*D)/$(*F).pp -c -o $@ $< @@ -1139,6 +1163,25 @@ minix_stage1_5_exec-bios.lo: bios.c >> .deps/$(*D)/$(*F).P; \ rm -f .deps/$(*D)/$(*F).pp +stage2_exec-bios.o: bios.c + @echo '$(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stage2_exec_CFLAGS) $(CFLAGS) -c -o $@ $<'; \ + $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stage2_exec_CFLAGS) $(CFLAGS) -Wp,-MD,.deps/$(*D)/$(*F).pp -c -o $@ $< + @-cp .deps/$(*D)/$(*F).pp .deps/$(*D)/$(*F).P; \ + tr ' ' '\012' < .deps/$(*D)/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*D)/$(*F).P; \ + rm .deps/$(*D)/$(*F).pp + +stage2_exec-bios.lo: bios.c + @echo '$(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stage2_exec_CFLAGS) $(CFLAGS) -c -o $@ $<'; \ + $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stage2_exec_CFLAGS) $(CFLAGS) -Wp,-MD,.deps/$(*D)/$(*F).pp -c -o $@ $< + @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \ + < .deps/$(*D)/$(*F).pp > .deps/$(*D)/$(*F).P; \ + tr ' ' '\012' < .deps/$(*D)/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*D)/$(*F).P; \ + rm -f .deps/$(*D)/$(*F).pp + stage2_exec-boot.o: boot.c @echo '$(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stage2_exec_CFLAGS) $(CFLAGS) -c -o $@ $<'; \ $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stage2_exec_CFLAGS) $(CFLAGS) -Wp,-MD,.deps/$(*D)/$(*F).pp -c -o $@ $< @@ -1158,6 +1201,25 @@ stage2_exec-boot.lo: boot.c >> .deps/$(*D)/$(*F).P; \ rm -f .deps/$(*D)/$(*F).pp +stage2_exec-builtins.o: builtins.c + @echo '$(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stage2_exec_CFLAGS) $(CFLAGS) -c -o $@ $<'; \ + $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stage2_exec_CFLAGS) $(CFLAGS) -Wp,-MD,.deps/$(*D)/$(*F).pp -c -o $@ $< + @-cp .deps/$(*D)/$(*F).pp .deps/$(*D)/$(*F).P; \ + tr ' ' '\012' < .deps/$(*D)/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*D)/$(*F).P; \ + rm .deps/$(*D)/$(*F).pp + +stage2_exec-builtins.lo: builtins.c + @echo '$(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stage2_exec_CFLAGS) $(CFLAGS) -c -o $@ $<'; \ + $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stage2_exec_CFLAGS) $(CFLAGS) -Wp,-MD,.deps/$(*D)/$(*F).pp -c -o $@ $< + @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \ + < .deps/$(*D)/$(*F).pp > .deps/$(*D)/$(*F).P; \ + tr ' ' '\012' < .deps/$(*D)/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*D)/$(*F).P; \ + rm -f .deps/$(*D)/$(*F).pp + stage2_exec-common.o: common.c @echo '$(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stage2_exec_CFLAGS) $(CFLAGS) -c -o $@ $<'; \ $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stage2_exec_CFLAGS) $(CFLAGS) -Wp,-MD,.deps/$(*D)/$(*F).pp -c -o $@ $< @@ -1253,63 +1315,6 @@ stage2_exec-gunzip.lo: gunzip.c >> .deps/$(*D)/$(*F).P; \ rm -f .deps/$(*D)/$(*F).pp -stage2_exec-stage2.o: stage2.c - @echo '$(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stage2_exec_CFLAGS) $(CFLAGS) -c -o $@ $<'; \ - $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stage2_exec_CFLAGS) $(CFLAGS) -Wp,-MD,.deps/$(*D)/$(*F).pp -c -o $@ $< - @-cp .deps/$(*D)/$(*F).pp .deps/$(*D)/$(*F).P; \ - tr ' ' '\012' < .deps/$(*D)/$(*F).pp \ - | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ - >> .deps/$(*D)/$(*F).P; \ - rm .deps/$(*D)/$(*F).pp - -stage2_exec-stage2.lo: stage2.c - @echo '$(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stage2_exec_CFLAGS) $(CFLAGS) -c -o $@ $<'; \ - $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stage2_exec_CFLAGS) $(CFLAGS) -Wp,-MD,.deps/$(*D)/$(*F).pp -c -o $@ $< - @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \ - < .deps/$(*D)/$(*F).pp > .deps/$(*D)/$(*F).P; \ - tr ' ' '\012' < .deps/$(*D)/$(*F).pp \ - | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ - >> .deps/$(*D)/$(*F).P; \ - rm -f .deps/$(*D)/$(*F).pp - -stage2_exec-bios.o: bios.c - @echo '$(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stage2_exec_CFLAGS) $(CFLAGS) -c -o $@ $<'; \ - $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stage2_exec_CFLAGS) $(CFLAGS) -Wp,-MD,.deps/$(*D)/$(*F).pp -c -o $@ $< - @-cp .deps/$(*D)/$(*F).pp .deps/$(*D)/$(*F).P; \ - tr ' ' '\012' < .deps/$(*D)/$(*F).pp \ - | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ - >> .deps/$(*D)/$(*F).P; \ - rm .deps/$(*D)/$(*F).pp - -stage2_exec-bios.lo: bios.c - @echo '$(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stage2_exec_CFLAGS) $(CFLAGS) -c -o $@ $<'; \ - $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stage2_exec_CFLAGS) $(CFLAGS) -Wp,-MD,.deps/$(*D)/$(*F).pp -c -o $@ $< - @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \ - < .deps/$(*D)/$(*F).pp > .deps/$(*D)/$(*F).P; \ - tr ' ' '\012' < .deps/$(*D)/$(*F).pp \ - | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ - >> .deps/$(*D)/$(*F).P; \ - rm -f .deps/$(*D)/$(*F).pp - -stage2_exec-smp-imps.o: smp-imps.c - @echo '$(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stage2_exec_CFLAGS) $(CFLAGS) -c -o $@ $<'; \ - $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stage2_exec_CFLAGS) $(CFLAGS) -Wp,-MD,.deps/$(*D)/$(*F).pp -c -o $@ $< - @-cp .deps/$(*D)/$(*F).pp .deps/$(*D)/$(*F).P; \ - tr ' ' '\012' < .deps/$(*D)/$(*F).pp \ - | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ - >> .deps/$(*D)/$(*F).P; \ - rm .deps/$(*D)/$(*F).pp - -stage2_exec-smp-imps.lo: smp-imps.c - @echo '$(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stage2_exec_CFLAGS) $(CFLAGS) -c -o $@ $<'; \ - $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stage2_exec_CFLAGS) $(CFLAGS) -Wp,-MD,.deps/$(*D)/$(*F).pp -c -o $@ $< - @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \ - < .deps/$(*D)/$(*F).pp > .deps/$(*D)/$(*F).P; \ - tr ' ' '\012' < .deps/$(*D)/$(*F).pp \ - | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ - >> .deps/$(*D)/$(*F).P; \ - rm -f .deps/$(*D)/$(*F).pp - stage2_exec-fsys_ext2fs.o: fsys_ext2fs.c @echo '$(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stage2_exec_CFLAGS) $(CFLAGS) -c -o $@ $<'; \ $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stage2_exec_CFLAGS) $(CFLAGS) -Wp,-MD,.deps/$(*D)/$(*F).pp -c -o $@ $< @@ -1385,6 +1390,44 @@ stage2_exec-fsys_minix.lo: fsys_minix.c | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ >> .deps/$(*D)/$(*F).P; \ rm -f .deps/$(*D)/$(*F).pp + +stage2_exec-smp-imps.o: smp-imps.c + @echo '$(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stage2_exec_CFLAGS) $(CFLAGS) -c -o $@ $<'; \ + $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stage2_exec_CFLAGS) $(CFLAGS) -Wp,-MD,.deps/$(*D)/$(*F).pp -c -o $@ $< + @-cp .deps/$(*D)/$(*F).pp .deps/$(*D)/$(*F).P; \ + tr ' ' '\012' < .deps/$(*D)/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*D)/$(*F).P; \ + rm .deps/$(*D)/$(*F).pp + +stage2_exec-smp-imps.lo: smp-imps.c + @echo '$(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stage2_exec_CFLAGS) $(CFLAGS) -c -o $@ $<'; \ + $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stage2_exec_CFLAGS) $(CFLAGS) -Wp,-MD,.deps/$(*D)/$(*F).pp -c -o $@ $< + @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \ + < .deps/$(*D)/$(*F).pp > .deps/$(*D)/$(*F).P; \ + tr ' ' '\012' < .deps/$(*D)/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*D)/$(*F).P; \ + rm -f .deps/$(*D)/$(*F).pp + +stage2_exec-stage2.o: stage2.c + @echo '$(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stage2_exec_CFLAGS) $(CFLAGS) -c -o $@ $<'; \ + $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stage2_exec_CFLAGS) $(CFLAGS) -Wp,-MD,.deps/$(*D)/$(*F).pp -c -o $@ $< + @-cp .deps/$(*D)/$(*F).pp .deps/$(*D)/$(*F).P; \ + tr ' ' '\012' < .deps/$(*D)/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*D)/$(*F).P; \ + rm .deps/$(*D)/$(*F).pp + +stage2_exec-stage2.lo: stage2.c + @echo '$(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stage2_exec_CFLAGS) $(CFLAGS) -c -o $@ $<'; \ + $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(stage2_exec_CFLAGS) $(CFLAGS) -Wp,-MD,.deps/$(*D)/$(*F).pp -c -o $@ $< + @-sed -e 's/^\([^:]*\)\.o[ ]*:/\1.lo \1.o :/' \ + < .deps/$(*D)/$(*F).pp > .deps/$(*D)/$(*F).P; \ + tr ' ' '\012' < .deps/$(*D)/$(*F).pp \ + | sed -e 's/^\\$$//' -e '/^$$/ d' -e '/:$$/ d' -e 's/$$/ :/' \ + >> .deps/$(*D)/$(*F).P; \ + rm -f .deps/$(*D)/$(*F).pp check-TESTS: $(TESTS) @failed=0; all=0; xfail=0; xpass=0; \ srcdir=$(srcdir); export srcdir; \ diff --git a/stage2/boot.c b/stage2/boot.c index ce6b66bd9..f51966490 100644 --- a/stage2/boot.c +++ b/stage2/boot.c @@ -38,10 +38,11 @@ static struct mod_list mll[99]; * of the gory details of loading in a bootable image and the modules. */ -int +kernel_t load_image (char *kernel, char *arg) { - int len, i, exec_type = 0, align_4k = 1, type = 0; + int len, i, exec_type = 0, align_4k = 1; + kernel_t type = KERNEL_TYPE_NONE; unsigned long flags = 0, text_len = 0, data_len = 0, bss_len = 0; char *str = 0, *str2 = 0; union @@ -60,14 +61,14 @@ load_image (char *kernel, char *arg) pu.aout = (struct exec *) buffer; if (!grub_open (kernel)) - return 0; + return KERNEL_TYPE_NONE; if (!(len = grub_read (buffer, MULTIBOOT_SEARCH)) || len < 32) { if (!errnum) errnum = ERR_EXEC_FORMAT; - return 0; + return KERNEL_TYPE_NONE; } for (i = 0; i < len; i++) @@ -78,20 +79,21 @@ load_image (char *kernel, char *arg) if (flags & MULTIBOOT_UNSUPPORTED) { errnum = ERR_BOOT_FEATURES; - return 0; + return KERNEL_TYPE_NONE; } - type = 'm'; + type = KERNEL_TYPE_MULTIBOOT; str2 = "Multiboot"; break; } } /* ELF loading supported if multiboot and FreeBSD. */ - if ((type == 'm' || grub_strcmp (pu.elf->e_ident + EI_BRAND, "FreeBSD") == 0) + if ((type == KERNEL_TYPE_MULTIBOOT + || grub_strcmp (pu.elf->e_ident + EI_BRAND, "FreeBSD") == 0) && len > sizeof (Elf32_Ehdr) && BOOTABLE_I386_ELF ((*((Elf32_Ehdr *) buffer)))) { - if (type == 'm') + if (type == KERNEL_TYPE_MULTIBOOT) entry_addr = (entry_func) pu.elf->e_entry; else entry_addr = (entry_func) (pu.elf->e_entry & 0xFFFFFF); @@ -107,10 +109,10 @@ load_image (char *kernel, char *arg) errnum = ERR_EXEC_FORMAT; str = "elf"; - if (! type) + if (type == KERNEL_TYPE_NONE) { str2 = "FreeBSD"; - type = 'f'; + type = KERNEL_TYPE_FREEBSD; } } else if (flags & MULTIBOOT_AOUT_KLUDGE) @@ -141,7 +143,7 @@ load_image (char *kernel, char *arg) { entry_addr = (entry_func) pu.aout->a_entry; - if (!type) + if (type == KERNEL_TYPE_NONE) { /* * If it doesn't have a Multiboot header, then presume @@ -156,13 +158,13 @@ load_image (char *kernel, char *arg) */ if (buffer[0] == 0xb && buffer[1] == 1) { - type = 'f'; + type = KERNEL_TYPE_FREEBSD; entry_addr = (entry_func) (((int) entry_addr) & 0xFFFFFF); str2 = "FreeBSD"; } else { - type = 'n'; + type = KERNEL_TYPE_NETBSD; entry_addr = (entry_func) (((int) entry_addr) & 0xF00000); if (N_GETMAGIC ((*(pu.aout))) != NMAGIC) align_4k = 0; @@ -200,7 +202,7 @@ load_image (char *kernel, char *arg) { printf (" linux 'zImage' kernel too big, try 'make bzImage'\n"); errnum = ERR_WONT_FIT; - return 0; + return KERNEL_TYPE_NONE; } printf (" [Linux-%s, setup=0x%x, size=0x%x]\n", @@ -232,7 +234,7 @@ load_image (char *kernel, char *arg) else /* ERRNUM is already set inside the function safe_parse_maxint. */ - return 0; + return KERNEL_TYPE_NONE; /* Set the vid mode to VID_MODE. Note that this can work because i386 architecture is little-endian. */ @@ -275,7 +277,7 @@ load_image (char *kernel, char *arg) cur_addr = LINUX_STAGING_AREA + text_len; if (grub_read ((char *) LINUX_STAGING_AREA, text_len) >= (text_len - 16)) - return (big_linux ? 'L' : 'l'); + return (big_linux ? KERNEL_TYPE_BIG_LINUX : KERNEL_TYPE_LINUX); else if (!errnum) errnum = ERR_EXEC_FORMAT; } @@ -287,7 +289,7 @@ load_image (char *kernel, char *arg) /* return if error */ if (errnum) - return 0; + return KERNEL_TYPE_NONE; /* fill the multiboot info structure */ mbi.cmdline = (int) arg; @@ -419,7 +421,7 @@ load_image (char *kernel, char *arg) filepos = phdr->p_offset; filesiz = phdr->p_filesz; - if (type == 'f') + if (type == KERNEL_TYPE_FREEBSD) memaddr = RAW_ADDR (phdr->p_paddr & 0xFFFFFF); else memaddr = RAW_ADDR (phdr->p_paddr); @@ -466,7 +468,7 @@ load_image (char *kernel, char *arg) else { putchar ('\n'); - type = 0; + type = KERNEL_TYPE_NONE; } return type; @@ -543,7 +545,7 @@ bsd_boot_entry (int flags, int bootdev, int sym_start, int sym_end, void -bsd_boot (int type, int bootdev, char *arg) +bsd_boot (kernel_t type, int bootdev, char *arg) { char *str; int clval = 0, i; @@ -588,7 +590,7 @@ bsd_boot (int type, int bootdev, char *arg) str++; } - if (type == 'f') + if (type == KERNEL_TYPE_FREEBSD) { clval |= RB_BOOTINFO; diff --git a/stage2/builtins.c b/stage2/builtins.c new file mode 100644 index 000000000..19b7ab7ad --- /dev/null +++ b/stage2/builtins.c @@ -0,0 +1,1398 @@ +/* builtins.c - the GRUB builtin commands */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1996 Erich Boleyn + * Copyright (C) 1999 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include + +#ifndef GRUB_UTIL +# include "apic.h" +# include "smp-imps.h" +#endif + +/* The type of kernel loaded. */ +kernel_t kernel_type; +/* The boot device. */ +static int bootdev; +/* True when the debug mode is turned on, and false when it is turned off. */ +int debug = 0; +/* The default entry. */ +int default_entry = 0; +/* The fallback entry. */ +int fallback_entry = -1; +/* The address for Multiboot command-line buffer. */ +static char *mb_cmdline; +/* The password. */ +char *password; +/* Color settings. */ +int normal_color; +int highlight_color; +/* The timeout. */ +int grub_timeout = -1; + +/* Initialize the data for builtins. */ +void +init_builtins (void) +{ + kernel_type = KERNEL_TYPE_NONE; + /* BSD and chainloading evil hacks! */ + bootdev = set_bootdev (0); + mb_cmdline = (char *) MB_CMDLINE_BUF; +} + +/* Initialize the data for the configuration file. */ +void +init_config (void) +{ + default_entry = 0; + normal_color = A_NORMAL; + highlight_color = A_REVERSE; + password = 0; + fallback_entry = -1; + grub_timeout = -1; +} + +/* Print which sector is read when loading a file. */ +static void +debug_fs_print_func (int sector) +{ + grub_printf ("[%d]", sector); +} + + +/* boot */ +static int +boot_func (char *arg, int flags) +{ + switch (kernel_type) + { + case KERNEL_TYPE_FREEBSD: + case KERNEL_TYPE_NETBSD: + /* *BSD */ + bsd_boot (kernel_type, bootdev, arg); + break; + + case KERNEL_TYPE_LINUX: + /* Linux */ + linux_boot (); + break; + + case KERNEL_TYPE_BIG_LINUX: + /* Big Linux */ + big_linux_boot (); + break; + + case KERNEL_TYPE_CHAINLOADER: + /* Chainloader */ + gateA20 (0); + boot_drive = saved_drive; + chain_stage1 (0, BOOTSEC_LOCATION, BOOTSEC_LOCATION - 16); + break; + + case KERNEL_TYPE_MULTIBOOT: + /* Multiboot */ + multi_boot ((int) entry_addr, (int) &mbi); + break; + + default: + errnum = ERR_BOOT_COMMAND; + return 1; + } + + return 0; +} + +static struct builtin builtin_boot = +{ + "boot", + boot_func, + BUILTIN_CMDLINE, + "boot", + "Boot the OS/chain-loader which has been loaded." +}; + + +/* chainloader */ +static int +chainloader_func (char *arg, int flags) +{ + if (grub_open (arg) + && grub_read ((char *) BOOTSEC_LOCATION, SECTOR_SIZE) == SECTOR_SIZE + && (*((unsigned short *) (BOOTSEC_LOCATION + BOOTSEC_SIG_OFFSET)) + == BOOTSEC_SIGNATURE)) + kernel_type = KERNEL_TYPE_CHAINLOADER; + else if (! errnum) + { + errnum = ERR_EXEC_FORMAT; + kernel_type = KERNEL_TYPE_NONE; + return 1; + } + + return 0; +} + +static struct builtin builtin_chainloader = +{ + "chainloader", + chainloader_func, + BUILTIN_CMDLINE, + "chainloader file", + "Load FILE as a chain-loader." +}; + + +/* color */ +static int +color_func (char *arg, int flags) +{ + char *normal; + char *highlight; + + normal = arg; + highlight = skip_to (0, arg); + + if (safe_parse_maxint (&normal, &normal_color)) + { + /* The second argument is optional, so set highlight_color + to inverted NORMAL_COLOR. */ + if (*highlight == 0 + || ! safe_parse_maxint (&highlight, &highlight_color)) + highlight_color = ((normal_color >> 4) | ((normal_color & 0xf) << 4)); + } + else + return 1; + + return 0; +} + +static struct builtin builtin_color = +{ + "color", + color_func, + BUILTIN_CMDLINE | BUILTIN_MENU, + "color normal [highlight]", + "Change the menu colors. The color NORMAL is used for the normal" + " line in the menu, and the color HIGHLIGHT is used to highlight the" + " line where the cursor points to. If you omit HIGHLIGHT, then the" + " inverted color of NORMAL is used for the highlighted line. You" + " must specify an integer for a color value, and the 0-3 bits" + " represents the foreground color, the 4-6 bits represents the" + " background color, and the 7 bit represents that the foreground" + " blinks." +}; + + +/* debug */ +static int +debug_func (char *arg, int flags) +{ + if (debug) + { + debug = 0; + grub_printf (" Debug mode is turned off\n"); + } + else + { + debug = 1; + grub_printf (" Debug mode is turned on\n"); + } + + return 0; +} + +static struct builtin builtin_debug = +{ + "debug", + debug_func, + BUILTIN_CMDLINE, + "debug", + "Turn on/off the debug mode." +}; + + +/* default */ +static int +default_func (char *arg, int flags) +{ + if (! safe_parse_maxint (&arg, &default_entry)) + return 1; + + return 0; +} + +static struct builtin builtin_default = +{ + "default", + default_func, + BUILTIN_MENU, +#if 0 + "default num", + "Set the default entry to entry number NUM (if not specified, it is" + " 0, the first entry)." +#endif +}; + + +/* displaymem */ +static int +displaymem_func (char *arg, int flags) +{ + if (get_eisamemsize () != -1) + grub_printf (" EISA Memory BIOS Interface is present\n"); + if (get_mmap_entry ((void *) SCRATCHADDR, 0) != 0 + || *((int *) SCRATCHADDR) != 0) + grub_printf (" Address Map BIOS Interface is present\n"); + + grub_printf (" Lower memory: %uK, " + "Upper memory (to first chipset hole): %uK\n", + mbi.mem_lower, mbi.mem_upper); + + if (mbi.flags & MB_INFO_MEM_MAP) + { + struct AddrRangeDesc *map = (struct AddrRangeDesc *) mbi.mmap_addr; + int end_addr = mbi.mmap_addr + mbi.mmap_length; + + grub_printf (" [Address Range Descriptor entries " + "immediately follow (values are 64-bit)]\n"); + while (end_addr > (int) map) + { + char *str; + + if (map->Type == MB_ARD_MEMORY) + str = "Usable RAM"; + else + str = "Reserved"; + grub_printf (" %s: Base Address: 0x%x X 4GB + 0x%x,\n" + " Length: %u X 4GB + %u bytes\n", + str, map->BaseAddrHigh, map->BaseAddrLow, + map->LengthHigh, map->LengthLow); + + map = ((struct AddrRangeDesc *) (((int) map) + 4 + map->size)); + } + } + + return 0; +} + +static struct builtin builtin_displaymem = +{ + "displaymem", + displaymem_func, + BUILTIN_CMDLINE, + "displaymem", + "Display what GRUB thinks the system address space map of the" + " machine is, including all regions of physical RAM installed." +}; + + +/* fallback */ +static int +fallback_func (char *arg, int flags) +{ + if (! safe_parse_maxint (&arg, &fallback_entry)) + return 1; + + return 0; +} + +static struct builtin builtin_fallback = +{ + "fallback", + fallback_func, + BUILTIN_MENU, +#if 0 + "fallback num", + "Go into unattended boot mode: if the default boot entry has any" + " errors, instead of waiting for the user to do anything, it" + " immediately starts over using the NUM entry (same numbering as the" + " `default=' command). This obviously doesn't help if the machine" + " was in the middle of the boot process (after leaving GRUB's code)" + " and rebooted." +#endif +}; + + +/* fstest */ +static int +fstest_func (char *arg, int flags) +{ + if (debug_fs) + { + debug_fs = NULL; + printf (" Filesystem tracing is now off\n"); + } + else + { + debug_fs = debug_fs_print_func; + printf (" Filesystem tracing is now on\n"); + } + + return 0; +} + +static struct builtin builtin_fstest = +{ + "fstest", + fstest_func, + BUILTIN_CMDLINE, + "fstest", + "Toggle filesystem test mode." +}; + + +/* geometry */ +static int +geometry_func (char *arg, int flags) +{ + struct geometry geom; + + set_device (arg); + if (errnum) + return 1; + + if (get_diskinfo (current_drive, &geom)) + { + errnum = ERR_NO_DISK; + return 1; + } + else + { + char *msg; + +#ifdef GRUB_UTIL + msg = device_map[current_drive]; +#else + if (geom.flags & BIOSDISK_FLAG_LBA_EXTENSION) + msg = "LBA"; + else + msg = "CHS"; +#endif + + grub_printf ("drive 0x%x: C/H/S = %d/%d/%d, " + "The number of sectors = %d, %s\n", + current_drive, + geom.cylinders, geom.heads, geom.sectors, + geom.total_sectors, msg); + } + + return 0; +} + +static struct builtin builtin_geometry = +{ + "geometry", + geometry_func, + BUILTIN_CMDLINE, + "geometry drive", + "Print the information for the drive DRIVE." +}; + + +/* help */ +#define MAX_SHORT_DOC_LEN 39 +#define MAX_LONG_DOC_LEN 66 + +static int +help_func (char *arg, int flags) +{ + if (! *arg) + { + /* Invoked with no argument. Print the list of the short docs. */ + struct builtin **builtin; + int left = 1; + + for (builtin = builtin_table; *builtin != 0; builtin++) + { + int len; + int i; + + /* If this cannot be run in the command-line interface, + skip this. */ + if (! ((*builtin)->flags & BUILTIN_CMDLINE)) + continue; + + len = grub_strlen ((*builtin)->short_doc); + /* If the length of SHORT_DOC is too long, truncate it. */ + if (len > MAX_SHORT_DOC_LEN - 1) + len = MAX_SHORT_DOC_LEN - 1; + + for (i = 0; i < len; i++) + grub_putchar ((*builtin)->short_doc[i]); + + for (; i < MAX_SHORT_DOC_LEN; i++) + grub_putchar (' '); + + if (! left) + grub_putchar ('\n'); + + left = ! left; + } + } + else + { + /* Invoked with one or more patterns. */ + do + { + struct builtin **builtin; + char *ptr = arg; + char *next_arg; + + /* Get the next argument. */ + next_arg = skip_to (0, arg); + + /* Terminate ARG. */ + while (*ptr && *ptr != ' ') + ptr++; + *ptr = 0; + + for (builtin = builtin_table; *builtin; builtin++) + { + /* Skip this if this is only for the configuration file. */ + if (! ((*builtin)->flags & BUILTIN_CMDLINE)) + continue; + + if (substring (arg, (*builtin)->name) < 1) + { + char *doc = (*builtin)->long_doc; + + /* At first, print the name and the short doc. */ + grub_printf ("%s: %s\n", + (*builtin)->name, (*builtin)->short_doc); + + /* Print the long doc. */ + while (*doc) + { + int len = grub_strlen (doc); + int i; + + /* If LEN is too long, fold DOC. */ + if (len > MAX_LONG_DOC_LEN) + { + /* Fold this line at the position of a space. */ + for (len = MAX_LONG_DOC_LEN; len > 0; len--) + if (doc[len - 1] == ' ') + break; + } + + grub_printf (" "); + for (i = 0; i < len; i++) + grub_putchar (*doc++); + grub_putchar ('\n'); + } + } + } + + arg = next_arg; + } + while (*arg); + } + + return 0; +} + +static struct builtin builtin_help = +{ + "help", + help_func, + BUILTIN_CMDLINE, + "help [pattern ...]", + "Display helpful information about builtin commands." +}; + + +/* hide */ +static int +hide_func (char *arg, int flags) +{ + if (! set_device (arg)) + return 1; + + saved_partition = current_partition; + saved_drive = current_drive; + if (! hide_partition ()) + return 1; + + return 0; +} + +static struct builtin builtin_hide = +{ + "hide", + hide_func, + BUILTIN_CMDLINE | BUILTIN_MENU, + "hide drive", + "Hide the drive DRIVE by adding 0x10 into the partition type." +}; + + +/* impsprobe */ +static int +impsprobe_func (char *arg, int flags) +{ +#ifndef GRUB_UTIL + if (!imps_probe ()) +#endif + printf (" No MPS information found or probe failed\n"); + + return 0; +} + +static struct builtin builtin_impsprobe = +{ + "impsprobe", + impsprobe_func, + BUILTIN_CMDLINE, + "impsprobe", + "Probe the Intel Multiprocessor Specification 1.1 or 1.4" + " configuration table and boot the various CPUs which are found into" + " a tight loop." +}; + + +/* initrd */ +static int +initrd_func (char *arg, int flags) +{ + switch (kernel_type) + { + case KERNEL_TYPE_LINUX: + case KERNEL_TYPE_BIG_LINUX: + if (! load_initrd (arg)) + return 1; + break; + + default: + errnum = ERR_NEED_LX_KERNEL; + return 1; + } + + return 0; +} + +static struct builtin builtin_initrd = +{ + "initrd", + initrd_func, + BUILTIN_CMDLINE, + "initrd file [arg ...]", + "Load an initial ramdisk FILE for a Linux format boot image and set the" + " appropriate parameters in the Linux setup area in memory." +}; + + +/* install */ +static int +install_func (char *arg, int flags) +{ + char *stage1_file, *dest_dev, *file, *addr; + char buffer[SECTOR_SIZE], old_sect[SECTOR_SIZE]; + int new_drive = 0xFF; + int dest_drive, dest_sector; + int i; + struct geometry dest_geom; + int write_stage2_sect = 0; + int stage2_sect; + char *ptr; + int installaddr, installlist, installsect; + + /* Write SECTOR to INSTALLLIST, and update INSTALLADDR and + INSTALLSECT. */ + static void debug_fs_blocklist_func (int sector) + { + if (debug) + printf("[%d]", sector); + + if (*((unsigned long *) (installlist - 4)) + + *((unsigned short *) installlist) != sector + || installlist == BOOTSEC_LOCATION + STAGE1_FIRSTLIST + 4) + { + installlist -= 8; + + if (*((unsigned long *) (installlist - 8))) + errnum = ERR_WONT_FIT; + else + { + *((unsigned short *) (installlist + 2)) = (installaddr >> 4); + *((unsigned long *) (installlist - 4)) = sector; + } + } + + *((unsigned short *) installlist) += 1; + installsect = sector; + installaddr += 512; + } + + stage1_file = arg; + dest_dev = skip_to (0, stage1_file); + if (*dest_dev == 'd') + { + new_drive = 0; + dest_dev = skip_to (0, dest_dev); + } + file = skip_to (0, dest_dev); + addr = skip_to (0, file); + + /* Get the installation address. */ + if (! safe_parse_maxint (&addr, &installaddr)) + return 1; + + /* Read Stage 1. */ + if (! grub_open (stage1_file) + || ! grub_read (buffer, SECTOR_SIZE) == SECTOR_SIZE) + return 1; + + /* Read the old sector from DEST_DEV. */ + if (! set_device (dest_dev) + || ! open_partition () + || ! devread (0, 0, SECTOR_SIZE, old_sect)) + return 1; + + /* Store the information for the destination device. */ + dest_drive = current_drive; + dest_geom = buf_geom; + dest_sector = part_start; + +#ifndef NO_DECOMPRESSION + /* Do not decompress Stage 2. */ + no_decompression = 1; +#endif + + /* copy possible DOS BPB, 59 bytes at byte offset 3 */ + grub_memmove (buffer + BOOTSEC_BPB_OFFSET, + old_sect + BOOTSEC_BPB_OFFSET, + BOOTSEC_BPB_LENGTH); + + /* if for a hard disk, copy possible MBR/extended part table */ + if ((dest_drive & 0x80) && current_partition == 0xFFFFFF) + grub_memmove (buffer + BOOTSEC_PART_OFFSET, + old_sect + BOOTSEC_PART_OFFSET, + BOOTSEC_PART_LENGTH); + + /* Check for the version and the signature of Stage 1. */ + if (*((short *)(buffer + STAGE1_VER_MAJ_OFFS)) != COMPAT_VERSION + || (*((unsigned short *) (buffer + BOOTSEC_SIG_OFFSET)) + != BOOTSEC_SIGNATURE) + || (! (dest_drive & 0x80) + && (*((unsigned char *) (buffer + BOOTSEC_PART_OFFSET)) == 0x80 + || buffer[BOOTSEC_PART_OFFSET] == 0)) + || (buffer[STAGE1_ID_OFFSET] != STAGE1_ID_LBA + && buffer[STAGE1_ID_OFFSET] != STAGE1_ID_CHS)) + { + errnum = ERR_BAD_VERSION; + return 1; + } + + /* Open Stage 2. */ + if (! grub_open (file)) + return 1; + + /* If STAGE1_FILE is the LBA version, do a sanity check. */ + if (buffer[STAGE1_ID_OFFSET] == STAGE1_ID_LBA) + { + /* The geometry of the drive in which FILE is located. */ + struct geometry load_geom; + + /* Check if CURRENT_DRIVE is a floppy disk. */ + if (! (current_drive & 0x80)) + { + errnum = ERR_DEV_VALUES; + return 1; + } + + /* Get the geometry of CURRENT_DRIVE. */ + if (get_diskinfo (current_drive, &load_geom)) + { + errnum = ERR_NO_DISK; + return 1; + } + +#ifdef GRUB_UTIL + /* XXX Can we determine if LBA is supported in + the grub shell as well? */ + grub_printf ("Warning: make sure that the access mode for " + "(hd%d) is LBA.\n", + current_drive - 0x80); +#else + /* Check if LBA is supported. */ + if (! (load_geom.flags & BIOSDISK_FLAG_LBA_EXTENSION)) + { + errnum = ERR_DEV_VALUES; + return 1; + } +#endif + } + + if (! new_drive) + new_drive = current_drive; + else if (current_drive != dest_drive) + grub_printf ("Warning: the option `d' is not found, but Stage 2 will" + "be install into a\ndifferent drive from a drive into" + " which is installed Stage 1.\n"); + + memmove ((char*) BOOTSEC_LOCATION, buffer, SECTOR_SIZE); + + *((unsigned char *) (BOOTSEC_LOCATION + STAGE1_FIRSTLIST)) + = new_drive; + *((unsigned short *) (BOOTSEC_LOCATION + STAGE1_INSTALLADDR)) + = installaddr; + + i = BOOTSEC_LOCATION+STAGE1_FIRSTLIST - 4; + while (*((unsigned long *) i)) + { + if (i < BOOTSEC_LOCATION + STAGE1_FIRSTLIST - 256 + || (*((int *) (i - 4)) & 0x80000000) + || *((unsigned short *) i) >= 0xA00 + || *((short *) (i + 2)) == 0) + { + errnum = ERR_BAD_VERSION; + return 1; + } + + *((int *) i) = 0; + *((int *) (i - 4)) = 0; + i -= 8; + } + + installlist = BOOTSEC_LOCATION + STAGE1_FIRSTLIST + 4; + debug_fs = debug_fs_blocklist_func; + + /* Read the first sector of Stage 2. */ + if (! grub_read ((char *) SCRATCHADDR, SECTOR_SIZE) == SECTOR_SIZE) + { + debug_fs = 0; + return 1; + } + + /* Check for the version of Stage 2. */ + if (*((short *) (SCRATCHADDR + STAGE2_VER_MAJ_OFFS)) != COMPAT_VERSION) + { + errnum = ERR_BAD_VERSION; + debug_fs = 0; + return 1; + } + + stage2_sect = installsect; + ptr = skip_to (0, addr); + + if (*ptr == 'p') + { + write_stage2_sect = 1; + *((long *) (SCRATCHADDR + STAGE2_INSTALLPART)) = current_partition; + ptr = skip_to (0, ptr); + } + + if (*ptr) + { + char *str = ((char *) (SCRATCHADDR + STAGE2_VER_STR_OFFS)); + + write_stage2_sect = 1; + /* Find a string for the configuration filename. */ + while (*(str++)) + ; + /* Copy the filename to Stage 2. */ + while ((*(str++) = *(ptr++)) != 0) + ; + } + + /* Read the whole of Stage 2. */ + if (! grub_read ((char *) RAW_ADDR (0x100000), -1)) + { + debug_fs = 0; + return 1; + } + + /* Clear the cache. */ + buf_track = -1; + + if (biosdisk (BIOSDISK_WRITE, + dest_drive, &dest_geom, + dest_sector, 1, (BOOTSEC_LOCATION >> 4)) + || (write_stage2_sect + && biosdisk (BIOSDISK_WRITE, + current_drive, &buf_geom, + stage2_sect, 1, SCRATCHSEG))) + { + errnum = ERR_WRITE; + debug_fs = 0; + return 1; + } + + debug_fs = 0; + +#ifndef NO_DECOMPRESSION + no_decompression = 0; +#endif + + return 0; +} + +static struct builtin builtin_install = +{ + "install", + install_func, + BUILTIN_CMDLINE, + "install stage1 [d] device stage2 addr [p] [config_file]", + "Install STAGE1 into DEVICE, and install a blocklist for loading STAGE2" + " as a Stage 2. If the option `d' is present, the Stage 1 will always" + " look for the actual disk STAGE2 is installed on, rather than using" + " the booting drive. The Stage 2 will be loaded at address ADDR, which" + " must be 0x8000 for a true Stage 2, and 0x2000 for a Stage 1.5. If" + " the option `p' or CONFIG_FILE are present, then it reads the first" + " block of Stage 2, modifies it with the values of the partition STAGE2" + " was found on for `p' or places the string CONFIG_FILE into the area" + " telling the Stage 2 where to look for a configuration file at boot" + " time." +}; + + +/* kernel */ +static int +kernel_func (char *arg, int flags) +{ + int len = grub_strlen (arg); + + /* Reset MB_CMDLINE. */ + mb_cmdline = (char *) MB_CMDLINE_BUF; + if (len + 1 > MB_CMDLINE_BUFLEN) + { + errnum = ERR_WONT_FIT; + return 1; + } + + /* Copy the command-line to MB_CMDLINE. */ + grub_memmove (mb_cmdline, arg, len + 1); + kernel_type = load_image (arg, mb_cmdline); + if (kernel_type == KERNEL_TYPE_NONE) + return 1; + + mb_cmdline += len + 1; + return 0; +} + +static struct builtin builtin_kernel = +{ + "kernel", + kernel_func, + BUILTIN_CMDLINE, + "kernel file [arg ...]", + "Attempt to load the primary boot image (Multiboot a.out or ELF," + " Linux zImage or bzImage, FreeBSD a.out, or NetBSD a.out) from" + " FILE. This command ignores the rest of the contents of the line," + " except that the entire line starting with FILE is" + " passed verbatim as the \"kernel command line\". The module state is" + " reset, and so you must reload any modules." +}; + + +/* makeactive */ +static int +makeactive_func (char *arg, int flags) +{ + if (! make_saved_active ()) + return 1; + + return 0; +} + +static struct builtin builtin_makeactive = +{ + "makeactive", + makeactive_func, + BUILTIN_CMDLINE, + "makeactive", + "Set the active partition on the root disk to GRUB's root partition" + " (on a floppy this has no effect). This is limited to working with" + " _primary_ PC partitions." +}; + + +/* module */ +static int +module_func (char *arg, int flags) +{ + int len = grub_strlen (arg); + + switch (kernel_type) + { + case KERNEL_TYPE_MULTIBOOT: + if (mb_cmdline + len + 1 > (char *) MB_CMDLINE_BUF + MB_CMDLINE_BUFLEN) + { + errnum = ERR_WONT_FIT; + return 1; + } + grub_memmove (mb_cmdline, arg, len + 1); + if (! load_module (arg, mb_cmdline)) + return 1; + mb_cmdline += len + 1; + break; + + case KERNEL_TYPE_LINUX: + case KERNEL_TYPE_BIG_LINUX: + if (! load_initrd (arg)) + return 1; + break; + + default: + errnum = ERR_NEED_MB_KERNEL; + return 1; + } + + return 0; +} + +static struct builtin builtin_module = +{ + "module", + module_func, + BUILTIN_CMDLINE, + "module file [arg ...]", + "Load a boot module FILE for a Multiboot format boot image (no" + " interpretation of the file contents are made, so that user of this" + " command must know what the kernel in question works with). The" + " rest of the line is passed as the \"module command line\" much like" + " with the `kernel=' command." +}; + + +/* modulenounzip */ +static int +modulenounzip_func (char *arg, int flags) +{ + int ret; + +#ifndef NO_DECOMPRESSION + no_decompression = 1; +#endif + + ret = module_func (arg, flags); + +#ifndef NO_DECOMPRESSION + no_decompression = 0; +#endif + + return ret; +} + +static struct builtin builtin_modulenounzip = +{ + "modulenounzip", + modulenounzip_func, + BUILTIN_CMDLINE, + "modulenounzip file [arg ...]", + "Exactly like `module=', except that automatic decompression is" + " disabled." +}; + + +/* password */ +static int +password_func (char *arg, int flags) +{ + int len = grub_strlen (arg); + + if (len > PASSWORD_BUFLEN) + { + errnum = ERR_WONT_FIT; + return 1; + } + + password = (char *) PASSWORD_BUF; + grub_memmove (password, arg, len + 1); + return 0; +} + +static struct builtin builtin_password = +{ + "password", + password_func, + BUILTIN_MENU, +#if 0 + "password passwd file", + "Disable all interactive editing control (menu entry editor and" + " command line). If the password PASSWD is entered, it loads the" + " FILE as a new config file and restarts the GRUB Stage 2." +#endif +}; + + +/* pause */ +static int +pause_func (char *arg, int flags) +{ + /* If ESC is returned, then abort this entry. */ + if (ASCII_CHAR (getkey ()) == 27) + return 1; + + return 0; +} + +static struct builtin builtin_pause = +{ + "pause", + pause_func, + BUILTIN_CMDLINE, + "pause [message ...]", + "Print the MESSAGE, then wait until a key is pressed. Note that" + " placing <^G> (ASCII code 7) in the message will cause the speaker" + " to emit the standard beep sound, which is useful when prompting" + " the user to change floppies." +}; + + +/* quit */ +static int +quit_func (char *arg, int flags) +{ +#ifdef GRUB_UTIL + stop (); +#endif + + /* In Stage 2, just ignore this command. */ + return 0; +} + +static struct builtin builtin_quit = +{ + "quit", + quit_func, + BUILTIN_CMDLINE, + "quit", + "Exit from the grub shell." +}; + + +static int +read_func (char *arg, int flags) +{ + int addr; + + if (! safe_parse_maxint (&arg, &addr)) + return 1; + + grub_printf ("Address 0x%x: Value 0x%x\n", + addr, *((unsigned *) RAW_ADDR (addr))); + return 0; +} + +static struct builtin builtin_read = +{ + "read", + read_func, + BUILTIN_CMDLINE, + "read addr", + "Read a 32-bit unsigned value from memory at address ADDR and" + " displays it in hex format." +}; + + +static int +root_func (char *arg, int flags) +{ + int hdbias = 0; + char *biasptr; + char *next; + + /* Call set_device to get the drive and the partition in ARG. */ + next = set_device (arg); + if (! next) + return 1; + + /* Ignore ERR_FSYS_MOUNT. */ + if (! open_device () && errnum != ERR_FSYS_MOUNT) + return 1; + + /* Clear ERRNUM. */ + errnum = 0; + saved_partition = current_partition; + saved_drive = current_drive; + + /* BSD and chainloading evil hacks !! */ + biasptr = skip_to (0, next); + safe_parse_maxint (&biasptr, &hdbias); + errnum = 0; + bootdev = set_bootdev (hdbias); + + /* Print the type of the filesystem. */ + print_fsys_type (); + + return 0; +} + +static struct builtin builtin_root = +{ + "root", + root_func, + BUILTIN_CMDLINE, + "root device [hdbias]", + "Set the current \"root partition\" to the device DEVICE, then" + " attempt to mount it to get the partition size (for passing the" + " partition descriptor in `ES:ESI', used by some chain-loaded" + " bootloaders), the BSD drive-type (for booting BSD kernels using" + " their native boot format), and fix up automatic determination of" + " the PC partition where a BSD sub-partition is located. The" + " optional HDBIAS parameter is a number to tell a kernel which is" + " using one of the BSD boot methodologies how many BIOS drive" + " numbers are on controllers before the current one. An example is" + " if there is an IDE disk and a SCSI disk, then set the root" + " partition normally, except for a kernel using a BSD boot" + " methodology (FreeBSD or NetBSD), then use a `1' for HDBIAS." +}; + + +/* rootnoverify */ +static int +rootnoverify_func (char *arg, int flags) +{ + if (! set_device (arg)) + return 1; + + saved_partition = current_partition; + saved_drive = current_drive; + current_drive = -1; + return 0; +} + +static struct builtin builtin_rootnoverify = +{ + "rootnoverify", + rootnoverify_func, + BUILTIN_CMDLINE, + "rootnoverify device [hdbias]", + "Similar to `root=', but don't attempt to mount the partition. This" + " is useful for when an OS is outside of the area of the disk that" + " GRUB can read, but setting the correct root partition is still" + " desired. Note that the items mentioned in `root=' which" + " derived from attempting the mount will NOT work correctly." +}; + + +/* testload */ +static int +testload_func (char *arg, int flags) +{ + int i; + + kernel_type = KERNEL_TYPE_NONE; + + if (! grub_open (arg)) + return 1; + + debug_fs = debug_fs_print_func; + + /* Perform filesystem test on the specified file. */ + /* Read whole file first. */ + grub_printf ("Whole file: "); + + grub_read ((char *) RAW_ADDR (0x100000), -1); + + /* Now compare two sections of the file read differently. */ + + for (i = 0; i < 0x10ac0; i++) + { + *((unsigned char *) RAW_ADDR (0x200000 + i)) = 0; + *((unsigned char *) RAW_ADDR (0x300000 + i)) = 1; + } + + /* First partial read. */ + grub_printf ("\nPartial read 1: "); + + filepos = 0; + grub_read ((char *) RAW_ADDR (0x200000), 0x7); + grub_read ((char *) RAW_ADDR (0x200007), 0x100); + grub_read ((char *) RAW_ADDR (0x200107), 0x10); + grub_read ((char *) RAW_ADDR (0x200117), 0x999); + grub_read ((char *) RAW_ADDR (0x200ab0), 0x10); + grub_read ((char *) RAW_ADDR (0x200ac0), 0x10000); + + /* Second partial read. */ + grub_printf ("\nPartial read 2: "); + + filepos = 0; + grub_read ((char *) RAW_ADDR (0x300000), 0x10000); + grub_read ((char *) RAW_ADDR (0x310000), 0x10); + grub_read ((char *) RAW_ADDR (0x310010), 0x7); + grub_read ((char *) RAW_ADDR (0x310017), 0x10); + grub_read ((char *) RAW_ADDR (0x310027), 0x999); + grub_read ((char *) RAW_ADDR (0x3109c0), 0x100); + + grub_printf ("\nHeader1 = 0x%x, next = 0x%x, next = 0x%x, next = 0x%x\n", + *((int *) RAW_ADDR (0x200000)), + *((int *) RAW_ADDR (0x200004)), + *((int *) RAW_ADDR (0x200008)), + *((int *) RAW_ADDR (0x20000c))); + + grub_printf ("Header2 = 0x%x, next = 0x%x, next = 0x%x, next = 0x%x\n", + *((int *) RAW_ADDR (0x300000)), + *((int *) RAW_ADDR (0x300004)), + *((int *) RAW_ADDR (0x300008)), + *((int *) RAW_ADDR (0x30000c))); + + for (i = 0; i < 0x10ac0; i++) + if (*((unsigned char *) RAW_ADDR (0x2000000 + i)) + != *((unsigned char *) RAW_ADDR (0x3000000 + i))) + break; + + grub_printf ("Max is 0x10ac0: i=0x%x, filepos=0x%x\n", i, filepos); + debug_fs = 0; + return 0; +} + +static struct builtin builtin_testload = +{ + "testload", + testload_func, + BUILTIN_CMDLINE, + "testload file", + "Read the entire contents of FILE in several different ways and" + " compares them, to test the filesystem code. The output is somewhat" + " cryptic, but if no errors are reported and the final `i=X," + " filepos=Y' reading has X and Y equal, then it is definitely" + " consistent, and very likely works correctly subject to a" + " consistent offset error. If this test succeeds, then a good next" + " step is to try loading a kernel with your code." +}; + + +/* timeout */ +static int +timeout_func (char *arg, int flags) +{ + if (! safe_parse_maxint (&arg, &grub_timeout)) + return 1; + + return 0; +} + +static struct builtin builtin_timeout = +{ + "timeout", + timeout_func, + BUILTIN_MENU, +#if 0 + "timeout sec", + "Set a timeout, in SEC seconds, before automatically booting the" + " default entry (normally the first entry defined)." +#endif +}; + + +/* title */ +static int +title_func (char *arg, int flags) +{ + /* This function is not actually at least currently. */ + return 0; +} + +static struct builtin builtin_title = +{ + "title", + title_func, + BUILTIN_TITLE, +#if 0 + "title name [...]", + "Start a new boot entry, and set its name to the contents of the" + " rest of the line, starting with the first non-space character." +#endif +}; + + +/* unhide */ +static int +unhide_func (char *arg, int flags) +{ + if (! set_device (arg)) + return 1; + + saved_partition = current_partition; + saved_drive = current_drive; + if (! unhide_partition ()) + return 1; + + return 0; +} + +static struct builtin builtin_unhide = +{ + "unhide", + unhide_func, + BUILTIN_CMDLINE | BUILTIN_MENU, + "unhide drive", + "Unhide the drive DRIVE by subtracting 0x10 from the partition type." +}; + + +/* uppermem */ +static int +uppermem_func (char *arg, int flags) +{ + if (! safe_parse_maxint (&arg, (int *) &mbi.mem_upper)) + return 1; + + mbi.flags &= ~MB_INFO_MEM_MAP; + return 0; +} + +static struct builtin builtin_uppermem = +{ + "uppermem", + uppermem_func, + BUILTIN_CMDLINE, + "uppermem kbytes", + "Force GRUB to ignore what it found during the autoprobe of the" + " memory available to the system, and to use KBYTES as the number of" + " kilobytes of upper memory installed. Any address range maps of the" + " system are discarded." +}; + + +/* The table of builtin commands. Sorted in dictionary order. */ +struct builtin *builtin_table[] = +{ + &builtin_boot, + &builtin_chainloader, + &builtin_color, + &builtin_debug, + &builtin_default, + &builtin_displaymem, + &builtin_fallback, + &builtin_fstest, + &builtin_geometry, + &builtin_help, + &builtin_hide, + &builtin_impsprobe, + &builtin_initrd, + &builtin_install, + &builtin_kernel, + &builtin_makeactive, + &builtin_module, + &builtin_modulenounzip, + &builtin_password, + &builtin_pause, + &builtin_quit, + &builtin_read, + &builtin_root, + &builtin_rootnoverify, + &builtin_testload, + &builtin_timeout, + &builtin_title, + &builtin_unhide, + &builtin_uppermem, + 0 +}; diff --git a/stage2/char_io.c b/stage2/char_io.c index a949230fa..6cb75e9ae 100644 --- a/stage2/char_io.c +++ b/stage2/char_io.c @@ -147,8 +147,8 @@ init_page (void) If ECHO_CHAR is nonzero, echo it instead of the typed character. */ int -get_cmdline (char *prompt, char *commands, char *cmdline, int maxlen, - int echo_char) +get_cmdline (char *prompt, char *cmdline, int maxlen, + int echo_char, int completion) { int ystart, yend, xend, lpos, c; int plen = 0; @@ -160,7 +160,7 @@ get_cmdline (char *prompt, char *commands, char *cmdline, int maxlen, while (*str != 0) { putchar (echo_char ? echo_char : *str); - str ++; + str++; if (++xend > 78) { xend = 0; @@ -259,45 +259,61 @@ get_cmdline (char *prompt, char *commands, char *cmdline, int maxlen, case 27: /* ESC immediately return 1 */ return 1; case 9: /* TAB lists completions */ - { - int i, j = 0, llen_old = llen; + if (completion) + { + int i, j = 0, llen_old = llen; + + /* Find the first word. */ + while (cmdline[j] == ' ') + j++; + while (cmdline[j] && cmdline[j] != '=' && cmdline[j] != ' ') + j++; + + /* Since the command line cannot have a '\n', we're OK to + use C. */ + c = cmdline[lpos]; + + cl_kill_to_end (); + + /* goto part after line here */ + yend = ((llen + plen) / 79) + ystart; + putchar ('\n'); + gotoxy (0, getxy () & 0xff); + + + if (lpos > j) + { + for (i = lpos; i > 0 && cmdline[i - 1] != ' '; i--); + if (i <= j) + i = j + 1; + /* print possible completions */ + print_completions (cmdline + i); + /* if somebody in print_completions has added something, + account for that */ + while (cmdline[lpos]) + lpos++, llen_old++; + } + else + { + /* Print the command list. */ + struct builtin **builtin; - /* Find the first word. */ - while (cmdline[j] == ' ') - j++; - while (cmdline[j] && cmdline[j] != '=' && cmdline[j] != ' ') - j++; + for (builtin = builtin_table; *builtin != 0; builtin++) + { + /* Do not print the name if it cannot be run in + the command-line interface. */ + if (! ((*builtin)->flags & BUILTIN_CMDLINE)) + continue; - /* since the command line cannot have a '\n', we're OK to use c */ - c = cmdline[lpos]; - - cl_kill_to_end (); - - /* goto part after line here */ - yend = ((llen + plen) / 79) + ystart; - putchar ('\n'); - gotoxy (0, getxy () & 0xff); - - if (lpos > j) - { - for (i = lpos; i > 0 && cmdline[i - 1] != ' '; i--); - if (i <= j) - i = j + 1; - /* print possible completions */ - print_completions (cmdline + i); - /* if somebody in print_completions has added something, - account for that */ - while (cmdline[lpos]) - lpos++, llen_old++; - } - else if (commands) - printf (commands); - - /* restore command-line */ - cmdline[lpos] = c; - llen = llen_old; - cl_init (); - } + grub_printf ("%s ", (*builtin)->name); + } + } + + /* restore command-line */ + cmdline[lpos] = c; + llen = llen_old; + cl_init (); + } break; case 1: /* C-a go to beginning of line */ lpos = 0; diff --git a/stage2/cmdline.c b/stage2/cmdline.c index 60e7b87c2..0cf5f5a21 100644 --- a/stage2/cmdline.c +++ b/stage2/cmdline.c @@ -21,25 +21,6 @@ #include "shared.h" -#ifndef GRUB_UTIL -# include "apic.h" -# include "smp-imps.h" -#endif - -/* - * These are used for determining if the command-line should ask the user - * to correct errors during scripts. - */ -int fallback; -char *password; - -/* True when the debug mode is turned on, and false when it is turned off. */ -int debug = 0; - -/* Color settings */ -int normal_color; -int highlight_color; - /* Find the next word from CMDLINE and return the pointer. If AFTER_EQUAL is non-zero, assume that the character `=' is treated as a space. Caution: this assumption is for backward compatibility. */ @@ -66,679 +47,149 @@ skip_to (int after_equal, char *cmdline) void -init_cmdline (void) +print_cmdline_message (void) { printf (" [ Minimal BASH-like line editing is supported. For the first word, TAB lists possible command completions. Anywhere else TAB lists the possible completions of a device/filename. ESC at any time exits. ]\n"); } -char commands[] = -" Possible commands are: \"pause ...\", \"uppermem \", \"root \", - \"rootnoverify \", \"chainloader \", \"kernel ...\", - \"testload \", \"read \", \"displaymem\", \"impsprobe\", - \"geometry \", \"hide \", \"unhide \", - \"fstest\", \"debug\", \"module ...\", \"modulenounzip ...\", - \"color []\", \"makeactive\", \"boot\", \"quit\" and - \"install [d] [p] []\"\n"; - -static void -debug_fs_print_func (int sector) +/* Find the builtin whose command name is COMMAND and return the + pointer. If not found, return 0. */ +struct builtin * +find_command (char *command) { - printf ("[%d]", sector); -} + char *ptr; + char c; + struct builtin **builtin; + + /* Find the first space and terminate the command name. */ + ptr = command; + while (*ptr && *ptr != ' ' && *ptr != '=') + ptr++; + c = *ptr; + *ptr = 0; -static int installaddr, installlist, installsect; - -static void -debug_fs_blocklist_func (int sector) -{ - if (debug) - printf("[%d]", sector); - - if (*((unsigned long *)(installlist-4)) - + *((unsigned short *)installlist) != sector - || installlist == BOOTSEC_LOCATION+STAGE1_FIRSTLIST+4) + /* Seek out the builtin whose command name is COMMAND. */ + for (builtin = builtin_table; *builtin != 0; builtin++) { - installlist -= 8; - - if (*((unsigned long *)(installlist-8))) - errnum = ERR_WONT_FIT; - else + if (grub_strcmp (command, (*builtin)->name) == 0) { - *((unsigned short *)(installlist+2)) = (installaddr >> 4); - *((unsigned long *)(installlist-4)) = sector; + *ptr = c; + return *builtin; } } - - *((unsigned short *)installlist) += 1; - installsect = sector; - installaddr += 512; + + /* Cannot find COMMAND. */ + errnum = ERR_UNRECOGNIZED; + *ptr = c; + return 0; } - -/* Run the command-line interface or execute a command from SCRIPT if - SCRIPT is not NULL. Return CMDLINE_OK if successful, CMDLINE_ABORT - if ``quit'' command is executed, and CMDLINE_ERROR if an error - occures or ESC is pushed. */ -cmdline_t -enter_cmdline (char *script, char *heap) +static void +init_cmdline (void) { - int bootdev, cmd_len, type = 0, run_cmdline = 1, have_run_cmdline = 0; - char *cur_heap = heap, *cur_entry = script, *old_entry; - char *mb_cmdline = (char *) MB_CMDLINE_BUF; - - /* initialization */ + /* Initialization. */ saved_drive = boot_drive; saved_partition = install_partition; current_drive = 0xFF; errnum = 0; - - /* restore memory probe state */ + + /* Restore memory probe state. */ mbi.mem_upper = saved_mem_upper; if (mbi.mmap_length) mbi.flags |= MB_INFO_MEM_MAP; - /* BSD and chainloading evil hacks !! */ - bootdev = set_bootdev(0); + init_builtins (); +} - if (!script) +void +enter_cmdline (char *heap) +{ + /* Initialize the data and print a message. */ + init_cmdline (); + init_page (); + print_cmdline_message (); + + while (1) { - init_page(); - init_cmdline(); + struct builtin *builtin; + char *arg; + + *heap = 0; + print_error (); + + /* Get the command-line with the minimal BASH-like interface. */ + if (get_cmdline (PACKAGE "> ", heap, 2048, 0, 1)) + return; + + builtin = find_command (heap); + if (! builtin) + continue; + + if (! (builtin->flags & BUILTIN_CMDLINE)) + { + errnum = ERR_UNRECOGNIZED; + continue; + } + + arg = skip_to (1, heap); + (builtin->func) (arg, BUILTIN_CMDLINE); } +} -restart: - if (script) +int +run_script (char *script, char *heap) +{ + char *old_entry; + char *cur_entry = script; + + /* Initialize the data. */ + init_cmdline (); + + while (1) { + struct builtin *builtin; + char *arg; + + print_error (); + if (errnum) { - if (fallback < 0) - goto returnit; - print_error(); - if (password || errnum == ERR_BOOT_COMMAND) - { - printf("Press any key to continue..."); - (void) getkey (); -returnit: - return CMDLINE_OK; - } - - run_cmdline = 1; - if (!have_run_cmdline) - { - have_run_cmdline = 1; - putchar('\n'); - init_cmdline(); - } - } - else - { - run_cmdline = 0; - - /* update position in the boot script */ - old_entry = cur_entry; - while (*(cur_entry++)); - - /* copy to work area */ - memmove (cur_heap, old_entry, ((int)cur_entry) - ((int)old_entry)); - - printf("%s\n", old_entry); - } - } - else - { - cur_heap[0] = 0; - print_error(); - } - - if (run_cmdline && get_cmdline (PACKAGE "> ", commands, cur_heap, 2048, 0)) - return CMDLINE_ERROR; - - if (substring ("boot", cur_heap) == 0 || (script && !*cur_heap)) - { - if ((type == 'f') | (type == 'n')) - bsd_boot (type, bootdev, (char *) MB_CMDLINE_BUF); - if (type == 'l') - linux_boot (); - if (type == 'L') - big_linux_boot (); - - if (type == 'c') - { - gateA20 (0); - boot_drive = saved_drive; - chain_stage1 (0, BOOTSEC_LOCATION, BOOTSEC_LOCATION-16); - } - - if (!type) - { - errnum = ERR_BOOT_COMMAND; - goto restart; - } - - /* this is the final possibility */ - multi_boot((int)entry_addr, (int)(&mbi)); - } - - /* get clipped command-line */ - cur_cmdline = skip_to(1, cur_heap); - cmd_len = 0; - while (cur_cmdline[cmd_len++]); - - if (substring("chainloader", cur_heap) < 1) - { - if (grub_open (cur_cmdline) && - (grub_read ((char *) BOOTSEC_LOCATION, SECTOR_SIZE) == SECTOR_SIZE) && - (*((unsigned short *) (BOOTSEC_LOCATION+BOOTSEC_SIG_OFFSET)) - == BOOTSEC_SIGNATURE)) - type = 'c'; - else if (!errnum) - { - errnum = ERR_EXEC_FORMAT; - type = 0; - } - } - else if (substring("pause", cur_heap) < 1) - { - if (ASCII_CHAR (getkey ()) == 27) - return CMDLINE_ERROR; - } - else if (substring("uppermem", cur_heap) < 1) - { - if (safe_parse_maxint(&cur_cmdline, (int *)&(mbi.mem_upper))) - mbi.flags &= ~MB_INFO_MEM_MAP; - } - else if (substring("root", cur_heap) < 1) - { - int hdbias = 0; - char *next_cmd = set_device (cur_cmdline); - - if (next_cmd) - { - char *biasptr = skip_to (0, next_cmd); - - /* this will respond to any "rootn" command, - but that's OK */ - if (!errnum && (cur_heap[4] == 'n' || open_device() - || errnum == ERR_FSYS_MOUNT)) - { - errnum = 0; - saved_partition = current_partition; - saved_drive = current_drive; - - if (cur_heap[4] != 'n') - { - /* BSD and chainloading evil hacks !! */ - safe_parse_maxint(&biasptr, &hdbias); - errnum = 0; - bootdev = set_bootdev(hdbias); - - print_fsys_type(); - } - else - current_drive = -1; - } - } - } - else if (substring ("kernel", cur_heap) < 1) - { - /* Reset MB_CMDLINE. */ - mb_cmdline = (char *) MB_CMDLINE_BUF; - if (cmd_len + 1 > MB_CMDLINE_BUFLEN) - errnum = ERR_WONT_FIT; - else - { - /* Copy the command-line to MB_CMDLINE. */ - grub_memmove (mb_cmdline, cur_cmdline, cmd_len + 1); - if ((type = load_image (cur_cmdline, mb_cmdline)) != 0) - mb_cmdline += cmd_len + 1; - } - } - else if (substring ("module", cur_heap) < 1) - { - if (type == 'm') - { -#ifndef NO_DECOMPRESSION - /* this will respond to any "modulen" command, - but that's OK */ - if (cur_heap[6] == 'n') - no_decompression = 1; -#endif /* NO_DECOMPRESSION */ + if (fallback_entry < 0) + return 1; - if (mb_cmdline + cmd_len + 1 - > (char *) MB_CMDLINE_BUF + MB_CMDLINE_BUFLEN) - errnum = ERR_WONT_FIT; - else - { - /* Copy the command-line to MB_CMDLINE. */ - grub_memmove (mb_cmdline, cur_cmdline, cmd_len + 1); - if (load_module (cur_cmdline, mb_cmdline)) - mb_cmdline += cmd_len + 1; - } - -#ifndef NO_DECOMPRESSION - no_decompression = 0; -#endif /* NO_DECOMPRESSION */ + grub_printf ("Press any key to continue..."); + (void) getkey (); + return 1; } - else if (type == 'L' || type == 'l') + + old_entry = cur_entry; + while (*cur_entry++) + ; + + grub_memmove (heap, old_entry, (int) cur_entry - (int) old_entry); + grub_printf ("%s\n", old_entry); + + if (! *heap) { - load_initrd (cur_cmdline); + if (kernel_type == KERNEL_TYPE_NONE) + return 0; + + grub_memmove (heap, "boot", 5); } - else - errnum = ERR_NEED_MB_KERNEL; - } - else if (substring("initrd", cur_heap) < 1) - { - if (type == 'L' || type == 'l') - { - load_initrd (cur_cmdline); - } - else - errnum = ERR_NEED_LX_KERNEL; - } - else if (substring("install", cur_heap) < 1) - { - char *stage1_file = cur_cmdline, *dest_dev, *file, *addr; - char buffer[SECTOR_SIZE], old_sect[SECTOR_SIZE]; - int new_drive = 0xFF; - - dest_dev = skip_to(0, stage1_file); - if (*dest_dev == 'd') - { - new_drive = 0; - dest_dev = skip_to(0, dest_dev); - } - file = skip_to (0, dest_dev); - addr = skip_to (0, file); - - if (safe_parse_maxint (&addr, &installaddr) && - grub_open (stage1_file) && - grub_read (buffer, SECTOR_SIZE) == SECTOR_SIZE && - set_device (dest_dev) && open_partition () && - devread (0, 0, SECTOR_SIZE, old_sect)) - { - int dest_drive = current_drive; - struct geometry dest_geom = buf_geom; - int dest_sector = part_start, i; - -#ifndef NO_DECOMPRESSION - no_decompression = 1; -#endif - - /* copy possible DOS BPB, 59 bytes at byte offset 3 */ - memmove (buffer+BOOTSEC_BPB_OFFSET, old_sect+BOOTSEC_BPB_OFFSET, - BOOTSEC_BPB_LENGTH); - - /* if for a hard disk, copy possible MBR/extended part table */ - if ((dest_drive & 0x80) && current_partition == 0xFFFFFF) - memmove (buffer+BOOTSEC_PART_OFFSET, old_sect+BOOTSEC_PART_OFFSET, - BOOTSEC_PART_LENGTH); - - if (*((short *)(buffer+STAGE1_VER_MAJ_OFFS)) != COMPAT_VERSION - || (*((unsigned short *) (buffer+BOOTSEC_SIG_OFFSET)) - != BOOTSEC_SIGNATURE) - || (!(dest_drive & 0x80) - && (*((unsigned char *) (buffer+BOOTSEC_PART_OFFSET)) == 0x80 - || buffer[BOOTSEC_PART_OFFSET] == 0))) - { - errnum = ERR_BAD_VERSION; - } - else if (grub_open (file)) - { - /* If STAGE1_FILE is the LBA version, do a sanity check. */ - if (buffer[STAGE1_ID_OFFSET] == STAGE1_ID_LBA) - { - /* The geometry of the drive in which FILE is located. */ - struct geometry load_geom; - - /* Check if CURRENT_DRIVE is a floppy disk. */ - if (! (current_drive & 0x80)) - { - errnum = ERR_DEV_VALUES; - goto install_failure; - } - - /* Get the geometry of CURRENT_DRIVE. */ - if (get_diskinfo (current_drive, &load_geom)) - { - errnum = ERR_NO_DISK; - goto install_failure; - } - -#ifdef GRUB_UTIL - /* XXX Can we determine if LBA is supported in - /sbin/grub as well? */ - grub_printf ("Warning: make sure that the access mode for " - "(hd%d) is LBA.\n", current_drive - 0x80); -#else - /* Check if LBA is supported. */ - if (! (load_geom.flags & BIOSDISK_FLAG_LBA_EXTENSION)) - { - errnum = ERR_DEV_VALUES; - goto install_failure; - } -#endif - } - - if (!new_drive) - new_drive = current_drive; - - memmove ((char*)BOOTSEC_LOCATION, buffer, SECTOR_SIZE); - - *((unsigned char *)(BOOTSEC_LOCATION+STAGE1_FIRSTLIST)) - = new_drive; - *((unsigned short *)(BOOTSEC_LOCATION+STAGE1_INSTALLADDR)) - = installaddr; - - i = BOOTSEC_LOCATION+STAGE1_FIRSTLIST-4; - while (*((unsigned long *)i)) - { - if (i < BOOTSEC_LOCATION+STAGE1_FIRSTLIST-256 - || (*((int *)(i-4)) & 0x80000000) - || *((unsigned short *)i) >= 0xA00 - || *((short *) (i+2)) == 0) - { - errnum = ERR_BAD_VERSION; - break; - } - - *((int *)i) = 0; - *((int *)(i-4)) = 0; - i -= 8; - } - - installlist = BOOTSEC_LOCATION+STAGE1_FIRSTLIST+4; - debug_fs = debug_fs_blocklist_func; - - if (!errnum && - grub_read ((char *) SCRATCHADDR, SECTOR_SIZE) == SECTOR_SIZE) - { - if (*((short *)(SCRATCHADDR+STAGE2_VER_MAJ_OFFS)) - != COMPAT_VERSION) - errnum = ERR_BAD_VERSION; - else - { - int write_stage2_sect = 0, stage2_sect = installsect; - char *ptr; - - ptr = skip_to(0, addr); - - if (*ptr == 'p') - { - write_stage2_sect++; - *((long *)(SCRATCHADDR+STAGE2_INSTALLPART)) - = current_partition; - ptr = skip_to(0, ptr); - } - if (*ptr) - { - char *str - = ((char *) (SCRATCHADDR+STAGE2_VER_STR_OFFS)); - - write_stage2_sect++; - while (*(str++)); /* find string */ - while ((*(str++) = *(ptr++)) != 0); /* do copy */ - } - - grub_read ((char *) RAW_ADDR (0x100000), -1); - - buf_track = -1; - - if (!errnum - && (biosdisk(BIOSDISK_WRITE, - dest_drive, &dest_geom, - dest_sector, 1, (BOOTSEC_LOCATION>>4)) - || (write_stage2_sect - && biosdisk(BIOSDISK_WRITE, - current_drive, &buf_geom, - stage2_sect, 1, SCRATCHSEG)))) - errnum = ERR_WRITE; - } - } - - debug_fs = NULL; - } - -#ifndef NO_DECOMPRESSION - no_decompression = 0; -#endif - } - - install_failure: - /* Error running the install script, so drop to command line. */ - if (script) + builtin = find_command (heap); + if (! builtin) + continue; + + if (! (builtin->flags & BUILTIN_CMDLINE)) { - fallback = -1; - return CMDLINE_ERROR; + errnum = ERR_UNRECOGNIZED; + continue; } + + arg = skip_to (1, heap); + (builtin->func) (arg, BUILTIN_CMDLINE); } - else if (substring("testload", cur_heap) < 1) - { - type = 0; - if (grub_open (cur_cmdline)) - { - int i; - - debug_fs = debug_fs_print_func; - - /* - * Perform filesystem test on the specified file. - */ - - /* read whole file first */ - printf("Whole file: "); - - grub_read ((char *) RAW_ADDR (0x100000), -1); - - /* now compare two sections of the file read differently */ - - for (i = 0; i < 0x10ac0; i++) - { - *((unsigned char *) RAW_ADDR (0x200000+i)) = 0; - *((unsigned char *) RAW_ADDR (0x300000+i)) = 1; - } - - /* first partial read */ - printf("\nPartial read 1: "); - - filepos = 0; - grub_read ((char *) RAW_ADDR (0x200000), 0x7); - grub_read ((char *) RAW_ADDR (0x200007), 0x100); - grub_read ((char *) RAW_ADDR (0x200107), 0x10); - grub_read ((char *) RAW_ADDR (0x200117), 0x999); - grub_read ((char *) RAW_ADDR (0x200ab0), 0x10); - grub_read ((char *) RAW_ADDR (0x200ac0), 0x10000); - - /* second partial read */ - printf("\nPartial read 2: "); - - filepos = 0; - grub_read ((char *) RAW_ADDR (0x300000), 0x10000); - grub_read ((char *) RAW_ADDR (0x310000), 0x10); - grub_read ((char *) RAW_ADDR (0x310010), 0x7); - grub_read ((char *) RAW_ADDR (0x310017), 0x10); - grub_read ((char *) RAW_ADDR (0x310027), 0x999); - grub_read ((char *) RAW_ADDR (0x3109c0), 0x100); - - printf ("\nHeader1 = 0x%x, next = 0x%x, next = 0x%x, next = 0x%x\n", - *((int *) RAW_ADDR (0x200000)), - *((int *) RAW_ADDR (0x200004)), - *((int *) RAW_ADDR (0x200008)), - *((int *) RAW_ADDR (0x20000c))); - - printf ("Header2 = 0x%x, next = 0x%x, next = 0x%x, next = 0x%x\n", - *((int *) RAW_ADDR (0x300000)), - *((int *) RAW_ADDR (0x300004)), - *((int *) RAW_ADDR (0x300008)), - *((int *) RAW_ADDR (0x30000c))); - - for (i = 0; i < 0x10ac0 && *((unsigned char *) RAW_ADDR (0x200000+i)) - == *((unsigned char *) RAW_ADDR (0x300000+i)); i++); - - printf("Max is 0x10ac0: i=0x%x, filepos=0x%x\n", i, filepos); - - debug_fs = NULL; - } - } - else if (substring ("read", cur_heap) < 1) - { - int myaddr; - if (safe_parse_maxint (&cur_cmdline, &myaddr)) - printf ("Address 0x%x: Value 0x%x", - myaddr, *((unsigned *) RAW_ADDR (myaddr))); - } - else if (substring ("fstest", cur_heap) == 0) - { - if (debug_fs) - { - debug_fs = NULL; - printf (" Filesystem tracing is now off\n"); - } - else - { - debug_fs = debug_fs_print_func; - printf (" Filesystem tracing is now on\n"); - } - } - else if (substring ("impsprobe", cur_heap) == 0) - { -#ifndef GRUB_UTIL - if (!imps_probe ()) -#endif - printf (" No MPS information found or probe failed\n"); - } - else if (substring ("displaymem", cur_heap) == 0) - { - if (get_eisamemsize () != -1) - printf (" EISA Memory BIOS Interface is present\n"); - if (get_mmap_entry ((void *) SCRATCHADDR, 0) != 0 || - *((int *) SCRATCHADDR) != 0) - printf (" Address Map BIOS Interface is present\n"); - - printf (" Lower memory: %uK, Upper memory (to first chipset hole): %uK\n", - mbi.mem_lower, mbi.mem_upper); - - if (mbi.flags & MB_INFO_MEM_MAP) - { - struct AddrRangeDesc *map = (struct AddrRangeDesc *) mbi.mmap_addr; - int end_addr = mbi.mmap_addr + mbi.mmap_length; - - printf (" [Address Range Descriptor entries immediately follow (values are 64-bit)]\n"); - while (end_addr > (int) map) - { - char *str; - - if (map->Type == MB_ARD_MEMORY) - str = "Usable RAM"; - else - str = "Reserved"; - printf (" %s: Base Address: 0x%x X 4GB + 0x%x, - Length: %u X 4GB + %u bytes\n", - str, map->BaseAddrHigh, map->BaseAddrLow, - map->LengthHigh, map->LengthLow); - - map = ((struct AddrRangeDesc *) (((int) map) + 4 + map->size)); - } - } - } - else if (substring ("makeactive", cur_heap) == 0) - make_saved_active(); - else if (substring ("debug", cur_heap) == 0) - { - if (debug) - { - debug = 0; - grub_printf (" Debug mode is turned off\n"); - } - else - { - debug = 1; - grub_printf (" Debug mode is turned on\n"); - } - } - else if (substring ("color", cur_heap) < 1) - { - char *normal; - char *highlight; - - normal = cur_cmdline; - highlight = skip_to (0, normal); - - if (safe_parse_maxint (&normal, &normal_color)) - { - /* The second argument is optional, so set highlight_color - to inverted NORMAL_COLOR. */ - if (*highlight == 0 - || ! safe_parse_maxint (&highlight, &highlight_color)) - highlight_color = ((normal_color >> 4) - | ((normal_color & 0xf) << 4)); - } - } - else if (substring ("quit", cur_heap) < 1) - { -#ifdef GRUB_UTIL - return CMDLINE_ABORT; -#else - grub_printf (" The quit command is ignored in Stage2\n"); -#endif - } - else if (substring ("geometry", cur_heap) < 1) - { - set_device (cur_cmdline); - - if (! errnum) - { - struct geometry geom; - - if (get_diskinfo (current_drive, &geom)) - errnum = ERR_NO_DISK; - else - { - char *msg; - -#ifdef GRUB_UTIL - msg = device_map[current_drive]; -#else - if (geom.flags & BIOSDISK_FLAG_LBA_EXTENSION) - msg = "LBA"; - else - msg = "CHS"; -#endif - - grub_printf ("drive 0x%x: C/H/S = %d/%d/%d, " - "The number of sectors = %d, %s\n", - current_drive, - geom.cylinders, geom.heads, geom.sectors, - geom.total_sectors, msg); - } - } - } - else if (substring ("hide", cur_heap) < 1) - { - set_device (cur_cmdline); - - if (! errnum) - { - saved_partition = current_partition; - saved_drive = current_drive; - hide_partition (); - } - } - else if (substring ("unhide", cur_heap) < 1) - { - set_device (cur_cmdline); - - if (! errnum) - { - saved_partition = current_partition; - saved_drive = current_drive; - unhide_partition (); - } - } - else if (*cur_heap && *cur_heap != ' ') - errnum = ERR_UNRECOGNIZED; - - goto restart; } diff --git a/stage2/shared.h b/stage2/shared.h index 28fef24ce..ae8f494cd 100644 --- a/stage2/shared.h +++ b/stage2/shared.h @@ -74,6 +74,19 @@ extern char *grub_scratch_mem; #define MB_CMDLINE_BUF RAW_ADDR (0x2000) #define MB_CMDLINE_BUFLEN 0x6000 +/* The buffer for the password. */ +#define PASSWORD_BUF RAW_ADDR (0x78000) +#define PASSWORD_BUFLEN 0x200 + +/* The buffer for the command-line. */ +#define CMDLINE_BUF (PASSWORD_BUF + PASSWORD_BUFLEN) +/* Make sure that this is larger than NEW_HEAPSIZE defined below. */ +#define CMDLINE_BUFLEN 0x600 + +/* The buffer for the menu entries. */ +#define MENU_BUF (CMDLINE_BUF + CMDLINE_BUFLEN) +#define MENU_BUFLEN (0x8000 + PASSWORD_BUF - MENU_BUF) + /* * Linux setup parameters */ @@ -327,7 +340,8 @@ extern char **device_map; #ifndef STAGE1_5 /* GUI interface variables. */ -extern int fallback; +extern int fallback_entry; +extern int default_entry; extern char *password; extern char commands[]; #endif @@ -495,22 +509,43 @@ void stop_floppy (void); /* Command-line interface functions. */ #ifndef STAGE1_5 -char *skip_to (int after_equal, char *cmdline); -void init_cmdline (void); -/* The constants for the return value of enter_cmdline. */ +#define BUILTIN_CMDLINE 0x1 +#define BUILTIN_MENU 0x2 +#define BUILTIN_TITLE 0x4 + +struct builtin +{ + char *name; + int (*func) (char *, int); + int flags; + char *short_doc; + char *long_doc; +}; + +extern struct builtin *builtin_table[]; + typedef enum { - CMDLINE_OK = 0, - CMDLINE_ABORT, - CMDLINE_ERROR -} cmdline_t; + KERNEL_TYPE_NONE, + KERNEL_TYPE_MULTIBOOT, + KERNEL_TYPE_LINUX, + KERNEL_TYPE_BIG_LINUX, + KERNEL_TYPE_FREEBSD, + KERNEL_TYPE_NETBSD, + KERNEL_TYPE_CHAINLOADER +} kernel_t; -/* Run the command-line interface or execute a command from SCRIPT if - SCRIPT is not NULL. Return CMDLINE_OK if successful, CMDLINE_ABORT - if ``quit'' command is executed, and CMDLINE_ERROR if an error - occures or ESC is pushed. */ -cmdline_t enter_cmdline (char *script, char *heap); +extern kernel_t kernel_type; +extern int grub_timeout; + +void init_builtins (void); +void init_config (void); +char *skip_to (int after_equal, char *cmdline); +struct builtin *find_command (char *command); +void print_cmdline_message (void); +void enter_cmdline (char *heap); +int run_script (char *script, char *heap); #endif /* C library replacement functions with identical semantics. */ @@ -528,8 +563,8 @@ int grub_strlen (const char *str); void init_page (void); void print_error (void); char *convert_to_ascii (char *buf, int c,...); -int get_cmdline (char *prompt, char *commands, char *cmdline, - int maxlen, int echo_char); +int get_cmdline (char *prompt, char *cmdline, int maxlen, + int echo_char, int completion); int substring (char *s1, char *s2); int get_based_digit (int c, int base); int safe_parse_maxint (char **str_ptr, int *myint_ptr); @@ -582,10 +617,13 @@ void print_completions (char *filename); /* Copies the current partition data to the desired address. */ void copy_current_part_entry (char *buf); -void bsd_boot (int type, int bootdev, char *arg) __attribute__ ((noreturn)); -int load_image (char *kernel, char *arg); +#ifndef STAGE1_5 +void bsd_boot (kernel_t type, int bootdev, char *arg) + __attribute__ ((noreturn)); +kernel_t load_image (char *kernel, char *arg); int load_module (char *module, char *arg); int load_initrd (char *initrd); +#endif void init_bios_info (void); diff --git a/stage2/size_test b/stage2/size_test index 76c8b46b9..68710904f 100644 --- a/stage2/size_test +++ b/stage2/size_test @@ -52,7 +52,7 @@ check minix_stage1_5 31744 # This limitation is arbitrary; If you want to make this larger, just # modify Stage 1. -check stage2 46080 +check stage2 56320 # Success. exit 0 diff --git a/stage2/stage2.c b/stage2/stage2.c index 65b332189..a51c4d300 100644 --- a/stage2/stage2.c +++ b/stage2/stage2.c @@ -20,7 +20,7 @@ #include "shared.h" static char * -get_entry(char *list, int num, int nested) +get_entry (char *list, int num, int nested) { int i; @@ -38,16 +38,16 @@ get_entry(char *list, int num, int nested) static void -print_entries(int y, int size, int first, char *menu_entries) +print_entries (int y, int size, int first, char *menu_entries) { int i; - gotoxy(77, y+1); + gotoxy (77, y + 1); if (first) - putchar(DISP_UP); + putchar (DISP_UP); else - putchar(' '); + putchar (' '); menu_entries = get_entry (menu_entries, first, 0); @@ -55,37 +55,37 @@ print_entries(int y, int size, int first, char *menu_entries) { int j = 0; - gotoxy(3, y+i); + gotoxy (3, y + i); while (*menu_entries) { if (j < 71) { - putchar(*menu_entries); + putchar (*menu_entries); j++; } menu_entries++; } - if (*(menu_entries-1)) + if (*(menu_entries - 1)) menu_entries++; for (; j < 71; j++) - putchar(' '); + putchar (' '); } - gotoxy(77, y+size); + gotoxy (77, y + size); if (*menu_entries) - putchar(DISP_DOWN); + putchar (DISP_DOWN); else - putchar(' '); + putchar (' '); } static void -print_border(int y, int size) +print_border (int y, int size) { int i; @@ -102,37 +102,37 @@ print_border(int y, int size) } #endif - gotoxy(1, y); + gotoxy (1, y); - putchar(DISP_UL); + putchar (DISP_UL); for (i = 0; i < 73; i++) - putchar(DISP_HORIZ); - putchar(DISP_UR); + putchar (DISP_HORIZ); + putchar (DISP_UR); i = 1; while (1) { - gotoxy(1, y+i); + gotoxy (1, y + i); if (i > size) break; - putchar(DISP_VERT); - gotoxy(75, y+i); - putchar(DISP_VERT); + putchar (DISP_VERT); + gotoxy (75, y + i); + putchar (DISP_VERT); i++; } - putchar(DISP_LL); + putchar (DISP_LL); for (i = 0; i < 73; i++) - putchar(DISP_HORIZ); - putchar(DISP_LR); + putchar (DISP_HORIZ); + putchar (DISP_LR); } static void -set_line(int y, int attr) +set_line (int y, int attr) { int x; @@ -165,18 +165,9 @@ set_line_highlight (int y) #endif } -static int grub_timeout; - - -typedef enum -{ - MENU_OK = 0, - MENU_ABORT -} menu_t; - -static menu_t -run_menu(char *menu_entries, char *config_entries, int num_entries, - char *heap, int entryno) +static void +run_menu (char *menu_entries, char *config_entries, int num_entries, + char *heap, int entryno) { int c, time1, time2 = -1, first_entry = 0; char *cur_entry; @@ -188,38 +179,39 @@ run_menu(char *menu_entries, char *config_entries, int num_entries, restart: while (entryno > 11) { - first_entry++; entryno--; + first_entry++; + entryno--; } - init_page(); + init_page (); #ifndef GRUB_UTIL - nocursor(); + nocursor (); #endif - print_border(3, 12); + print_border (3, 12); - printf("\n + printf ("\n Use the \x18 and \x19 keys for selecting which entry is highlighted.\n"); if (password) { - printf(" Press enter to boot the selected OS or \'p\' to enter a + printf (" Press enter to boot the selected OS or \'p\' to enter a password to unlock the next set of features."); } else { if (config_entries) - printf(" Press enter to boot the selected OS, \'e\' to edit the + printf (" Press enter to boot the selected OS, \'e\' to edit the commands before booting, or \'c\' for a command-line."); else - printf( + printf ( " Press \'b\' to boot, \'e\' to edit the selected command in the boot sequence, \'c\' for a command-line, \'o\' to open a new line after (\'O\' for before) the selected line, \'d\' to remove the selected line, or escape to go back to the main menu."); } - print_entries(3, 12, first_entry, menu_entries); + print_entries (3, 12, first_entry, menu_entries); /* highlight initial line */ set_line_highlight (4 + entryno); @@ -242,58 +234,58 @@ restart: /* else not booting yet! */ time2 = time1; - gotoxy(3, 22); - printf("The highlighted entry will be booted automatically in %d seconds. ", grub_timeout); - gotoxy(74, 4+entryno); - grub_timeout --; + gotoxy (3, 22); + printf ("The highlighted entry will be booted automatically in %d seconds. ", grub_timeout); + gotoxy (74, 4 + entryno); + grub_timeout--; } - if (checkkey() != -1) + if (checkkey () != -1) { - c = getkey(); + c = getkey (); if (grub_timeout >= 0) { - gotoxy(3, 22); - printf(" "); + gotoxy (3, 22); + printf (" "); grub_timeout = -1; - fallback = -1; - gotoxy(74, 4+entryno); + fallback_entry = -1; + gotoxy (74, 4 + entryno); } - if ((c == KEY_UP) || (ASCII_CHAR(c) == 16)) + if ((c == KEY_UP) || (ASCII_CHAR (c) == 16)) { if (entryno > 0) { set_line_normal (4 + entryno); - entryno --; + entryno--; set_line_highlight (4 + entryno); } else if (first_entry > 0) { - first_entry --; - print_entries(3, 12, first_entry, menu_entries); + first_entry--; + print_entries (3, 12, first_entry, menu_entries); set_line_highlight (4); } } - if (((c == KEY_DOWN) || (ASCII_CHAR(c) == 14)) - && (first_entry+entryno+1) < num_entries) + if (((c == KEY_DOWN) || (ASCII_CHAR (c) == 14)) + && (first_entry + entryno + 1) < num_entries) { if (entryno < 11) { set_line_normal (4 + entryno); - entryno ++; + entryno++; set_line_highlight (4 + entryno); } - else if (num_entries > 12+first_entry) + else if (num_entries > 12 + first_entry) { - first_entry ++; + first_entry++; print_entries (3, 12, first_entry, menu_entries); set_line_highlight (15); } } - c = ASCII_CHAR(c); + c = ASCII_CHAR (c); if (config_entries) { @@ -313,12 +305,14 @@ restart: c = 'O'; } - cur_entry = get_entry(menu_entries, first_entry+entryno, 0); + cur_entry = get_entry (menu_entries, + first_entry + entryno, + 0); if (c == 'O') { memmove (cur_entry + 2, cur_entry, - ((int)heap) - ((int)cur_entry)); + ((int) heap) - ((int) cur_entry)); cur_entry[0] = ' '; cur_entry[1] = 0; @@ -330,25 +324,27 @@ restart: else if (num_entries > 0) { char *ptr = get_entry(menu_entries, - first_entry+entryno+1, 0); - memmove (cur_entry, ptr, ((int)heap) - ((int)ptr)); - heap -= (((int)ptr) - ((int)cur_entry)); + first_entry + entryno + 1, + 0); + + memmove (cur_entry, ptr, ((int) heap) - ((int) ptr)); + heap -= (((int) ptr) - ((int) cur_entry)); num_entries--; if (entryno >= num_entries) entryno--; - if (first_entry && num_entries < 12+first_entry) + if (first_entry && num_entries < 12 + first_entry) first_entry--; } - print_entries(3, 12, first_entry, menu_entries); + print_entries (3, 12, first_entry, menu_entries); set_line_highlight (4 + entryno); } cur_entry = menu_entries; if (c == 27) - return MENU_OK; + return; if (c == 'b') break; } @@ -361,14 +357,14 @@ restart: char entered[32]; char *pptr = password; - gotoxy(1, 21); + gotoxy (1, 21); /* Wipe out the previously entered password */ memset (entered, 0, sizeof (entered)); - get_cmdline (" Password: ", NULL, entered, 31, '*'); + get_cmdline (" Password: ", entered, 31, '*', 0); while (! isspace (*pptr) && *pptr) - pptr ++; + pptr++; /* Make sure that PASSWORD is NUL-terminated. */ *pptr++ = 0; @@ -377,13 +373,14 @@ restart: { char *new_file = config_file; while (isspace (*pptr)) - pptr ++; - while ((*(new_file ++) = *(pptr ++)) != 0); - return MENU_OK; + pptr++; + while ((*(new_file++) = *(pptr++)) != 0) + ; + return; } else { - printf("Failed!\n Press any key to continue..."); + printf ("Failed!\n Press any key to continue..."); getkey (); goto restart; } @@ -399,15 +396,17 @@ restart: if (config_entries) { new_heap = heap; - cur_entry = get_entry(config_entries, - first_entry+entryno, 1); + cur_entry = get_entry (config_entries, + first_entry + entryno, + 1); } else { /* safe area! */ new_heap = heap + NEW_HEAPSIZE + 1; - cur_entry = get_entry(menu_entries, - first_entry+entryno, 0); + cur_entry = get_entry (menu_entries, + first_entry + entryno, + 0); } do @@ -422,11 +421,11 @@ restart: *(new_heap++) = 0; if (config_entries) - run_menu(heap, NULL, num_entries, new_heap, 0); + run_menu (heap, NULL, num_entries, new_heap, 0); else { - cls(); - init_cmdline(); + cls (); + print_cmdline_message (); new_heap = heap + NEW_HEAPSIZE + 1; @@ -434,13 +433,14 @@ restart: saved_partition = install_partition; current_drive = 0xFF; - if (! get_cmdline(PACKAGE " edit> ", commands, new_heap, - NEW_HEAPSIZE + 1, 0)) + if (! get_cmdline (PACKAGE " edit> ", new_heap, + NEW_HEAPSIZE + 1, 0, 1)) { int j = 0; /* get length of new command */ - while (new_heap[j++]); + while (new_heap[j++]) + ; if (j < 2) { @@ -451,7 +451,7 @@ restart: /* align rest of commands properly */ memmove (cur_entry + j, cur_entry + i, - ((int)heap) - (((int)cur_entry) + i)); + ((int) heap) - (((int) cur_entry) + i)); /* copy command to correct area */ memmove (cur_entry, new_heap, j); @@ -464,18 +464,16 @@ restart: } if (c == 'c') { - /* Call the command-line interface, and if it aborts - (by ``quit'' command), then return. */ - if (enter_cmdline (NULL, heap) == CMDLINE_ABORT) - return MENU_ABORT; - + enter_cmdline (heap); goto restart; } #ifdef GRUB_UTIL if (c == 'q') { /* The same as ``quit''. */ - return MENU_ABORT; +#ifdef GRUB_UTIL + stop (); +#endif } #endif } @@ -486,47 +484,45 @@ restart: * Attempt to boot an entry. */ - do + while (1) { - cls(); + cls (); if (config_entries) - printf(" Booting \'%s\'\n\n", - get_entry(menu_entries, first_entry+entryno, 0)); + printf (" Booting \'%s\'\n\n", + get_entry (menu_entries, first_entry + entryno, 0)); else - printf(" Booting command-list\n\n"); + printf (" Booting command-list\n\n"); - if (!cur_entry) - cur_entry = get_entry(config_entries, first_entry+entryno, 1); + if (! cur_entry) + cur_entry = get_entry (config_entries, first_entry + entryno, 1); - if ((c = enter_cmdline (cur_entry, heap)) == CMDLINE_OK) + if (run_script (cur_entry, heap)) { - if (fallback < 0) - break; + if (fallback_entry < 0) + { + /* Both the entry and the fallback failed, so wait for + input. */ + grub_printf (" Press any key to continue..."); + (void) getkey (); + break; + } else { cur_entry = NULL; first_entry = 0; - entryno = fallback; - fallback = -1; + entryno = fallback_entry; + fallback_entry = -1; } } } - while (c == CMDLINE_OK); - - /* If aborted, then return. */ - if (c == CMDLINE_ABORT) - return MENU_ABORT; - /* Both the entry and the fallback failed, so wait for input. */ - printf (" Press any key to continue..."); - getkey (); goto restart; } static int -get_line_from_config(char *cmdline, int maxlen) +get_line_from_config (char *cmdline, int maxlen) { int pos = 0, literal = 0, comment = 0; char c; /* since we're loading it a byte at a time! */ @@ -551,7 +547,7 @@ get_line_from_config(char *cmdline, int maxlen) if (c == '\n') comment = 0; } - else if (!pos) + else if (! pos) { if (c == '#') comment = 1; @@ -574,27 +570,24 @@ get_line_from_config(char *cmdline, int maxlen) } +/* This is the starting function in C. */ void -cmain(void) +cmain (void) { - int config_len, menu_len, num_entries, default_entry; + int config_len, menu_len, num_entries; char *config_entries, *menu_entries; + /* Never return. */ for (;;) { config_len = 0; menu_len = 0; num_entries = 0; - default_entry = 0; - normal_color = A_NORMAL; - highlight_color = A_REVERSE; - config_entries = (char *)(mbi.mmap_addr + mbi.mmap_length); - menu_entries = (char *)(BUFFERADDR + (32 * 1024)); - password = NULL; fallback = -1; grub_timeout = -1; + config_entries = (char *) (mbi.mmap_addr + mbi.mmap_length); + menu_entries = (char *) MENU_BUF; + init_config (); - /* - * Here load the configuration file. - */ + /* Here load the configuration file. */ #ifdef GRUB_UTIL if (use_config_file && grub_open (config_file)) @@ -602,17 +595,31 @@ cmain(void) if (grub_open (config_file)) #endif { + /* STATE 0: Before any title command. + STATE 1: In a title command. + STATE >1: In a entry after a title command. */ int state = 0, prev_config_len = 0, prev_menu_len = 0; - char cmdline[1502], *ptr; + char *cmdline; + cmdline = (char *) CMDLINE_BUF; while (get_line_from_config (cmdline, NEW_HEAPSIZE)) { - ptr = skip_to(1, cmdline); + struct builtin *builtin; - if (substring("title", cmdline) < 1) + /* Get the pointer to the builtin structure. */ + builtin = find_command (cmdline); + if (! builtin) + /* Unknown command. Just skip now. */ + continue; + + if (builtin->flags & BUILTIN_TITLE) { + char *ptr; + + /* the command "title" is specially treated. */ if (state > 1) { + /* The next title is found. */ num_entries++; config_entries[config_len++] = 0; prev_menu_len = menu_len; @@ -620,61 +627,46 @@ cmain(void) } else { + /* The first title is found. */ menu_len = prev_menu_len; config_len = prev_config_len; } + /* Reset the state. */ state = 1; - - /* copy title into menu area */ - while ((menu_entries[menu_len++] = *(ptr++)) != 0); + + /* Copy title into menu area. */ + ptr = skip_to (1, cmdline); + while ((menu_entries[menu_len++] = *(ptr++)) != 0) + ; } - else if (!state) + else if (! state) { - if (substring ("timeout", cmdline) < 1) - safe_parse_maxint (&ptr, &grub_timeout); - else if (substring ("fallback", cmdline) < 1) - safe_parse_maxint (&ptr, &fallback); - else if (substring ("default", cmdline) < 1) - safe_parse_maxint (&ptr, &default_entry); - else if (substring ("color", cmdline) < 1) + /* Run a command found is possible. */ + if (builtin->flags & BUILTIN_MENU) { - char *normal; - char *highlight; - - normal = ptr; - highlight = skip_to (0, normal); - - if (safe_parse_maxint (&normal, &normal_color)) - { - if (*highlight == 0 - || ! safe_parse_maxint (&highlight, - &highlight_color)) - highlight_color = ((normal_color >> 4) - | ((normal_color & 0xf) << 4)); - } + char *arg = skip_to (1, cmdline); + (builtin->func) (arg, BUILTIN_MENU); + errnum = 0; } - else if (substring ("password", cmdline) < 1) - { - password = config_entries; - while ((*(config_entries++) = *(ptr++)) != 0); - } - - errnum = 0; + else + /* Ignored. */ + continue; } else { - int i = 0; - + char *ptr = cmdline; + state++; - - /* copy config file data to config area */ - while ((config_entries[config_len++] = cmdline[i++]) != 0); + /* Copy config file data to config area. */ + while ((config_entries[config_len++] = *ptr++) != 0) + ; } } - + if (state > 1) { + /* Finish the last entry. */ num_entries++; config_entries[config_len++] = 0; } @@ -683,29 +675,26 @@ cmain(void) menu_len = prev_menu_len; config_len = prev_config_len; } - + menu_entries[menu_len++] = 0; config_entries[config_len++] = 0; - memmove (config_entries + config_len, menu_entries, menu_len); + grub_memmove (config_entries + config_len, menu_entries, menu_len); menu_entries = config_entries + config_len; } - + if (! num_entries) { /* If no acceptable config file, goto command-line, starting heap from where the config entries would have been stored if there were any. */ - while (enter_cmdline (NULL, config_entries) != CMDLINE_ABORT) - ; - - return; + while (1) + enter_cmdline (config_entries); } else { /* Run menu interface. */ - if (run_menu(menu_entries, config_entries, num_entries, - menu_entries+menu_len, default_entry) == MENU_ABORT) - return; + run_menu (menu_entries, config_entries, num_entries, + menu_entries + menu_len, default_entry); } } }