freebsd-ports/sysutils/grub/files/patch-ufs2
Kirill Ponomarev b74193bd53 - a patch for UFS2 support (contributed by Valery Hromov)
- get rid of pkg-plist
- cleanup old code

PR:		ports/62299
Submitted by:	maintainer
2004-02-10 22:00:02 +00:00

9523 lines
251 KiB
Text
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

diff -ruN grub-0.94.orig/configure.ac configure.ac
--- grub-0.94.orig/configure.ac Wed Feb 11 00:22:12 2004
+++ configure.ac Wed Feb 11 00:22:29 2004
@@ -227,6 +227,13 @@
FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_FFS=1"
fi
+AC_ARG_ENABLE(ufs2,
+ [ --disable-ufs2 disable UFS2 support in Stage 2])
+
+if test x"$enable_ufs2" != xno; then
+ FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_UFS2=1"
+fi
+
AC_ARG_ENABLE(minix,
[ --disable-minix disable Minix fs support in Stage 2])
diff -ruN grub-0.94.orig/configure.ac.orig configure.ac.orig
--- grub-0.94.orig/configure.ac.orig Thu Jan 1 03:00:00 1970
+++ configure.ac.orig Sun Oct 19 21:25:30 2003
@@ -0,0 +1,640 @@
+dnl Configure script for GRUB.
+dnl Copyright 1999,2000,2001,2002,2003 Free Software Foundation, Inc.
+
+dnl Permission to use, copy, modify and distribute this software and its
+dnl documentation is hereby granted, provided that both the copyright
+dnl notice and this permission notice appear in all copies of the
+dnl software, derivative works or modified versions, and any portions
+dnl thereof, and that both notices appear in supporting documentation.
+dnl
+dnl THE FREE SOFTWARE FOUNDATION ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+dnl "AS IS" CONDITION. THE FREE SOFTWARE FOUNDATION DISCLAIMS ANY
+dnl LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE
+dnl USE OF THIS SOFTWARE.
+
+AC_PREREQ(2.57)
+AC_INIT([GRUB], [0.94], [bug-grub@gnu.org])
+AC_CONFIG_SRCDIR([stage2/stage2.c])
+AC_CONFIG_HEADER([config.h])
+AM_INIT_AUTOMAKE
+
+AC_CANONICAL_HOST
+
+case "$host_cpu" in
+i[[3456]]86) host_cpu=i386 ;;
+x86_64) host_cpu=x86_64 ;;
+*) AC_MSG_ERROR([unsupported CPU type]) ;;
+esac
+
+AC_SUBST(host_cpu)
+AC_SUBST(host_vendor)
+
+#
+# Options
+#
+
+AM_MAINTAINER_MODE
+if test "x$enable_maintainer_mode" = xyes; then
+ AC_PATH_PROG(PERL,perl)
+ if test -z "$PERL"; then
+ AC_MSG_ERROR([perl not found])
+ fi
+fi
+
+# This should be checked before AC_PROG_CC
+if test "x$CFLAGS" = x; then
+ default_CFLAGS=yes
+fi
+
+if test "x$host_cpu" = xx86_64; then
+ CFLAGS="-m32 $CFLAGS"
+fi
+
+#
+# Programs
+#
+
+AC_CHECK_TOOL(CC, gcc)
+AC_PROG_CC
+# We need this for older versions of Autoconf.
+_AM_DEPENDENCIES(CC)
+
+dnl Because recent automake complains about AS, set it here.
+CCAS="$CC"
+AC_SUBST(CCAS)
+
+AC_ARG_WITH(binutils,
+ [ --with-binutils=DIR search the directory DIR to find binutils])
+
+if test "x$with_binutils" != x; then
+dnl AC_PATH_TOOL is not seen in autoconf 2.13, so use AC_PATH_PROG
+dnl instead for now. It is preferable when you cross-compile GRUB.
+dnl AC_PATH_TOOL(RANLIB, ranlib, :, "$with_binutils:$PATH")
+ AC_PATH_PROG(RANLIB, ranlib, :, "$with_binutils:$PATH")
+else
+ AC_PROG_RANLIB
+fi
+
+# optimization flags
+if test "x$ac_cv_prog_gcc" = xyes; then
+ if test "x$default_CFLAGS" = xyes; then
+ # Autoconf may set CFLAGS to -O2 and/or -g. So eliminate them.
+ CFLAGS="`echo $CFLAGS | sed -e 's/-g//g' -e 's/-O[[0-9]]//g'` -g"
+ # If the user specify the directory for binutils, add the option `-B'.
+ if test "x$with_binutils" != x; then
+ CFLAGS="-B$with_binutils/ $CFLAGS"
+ fi
+ STAGE1_CFLAGS="-O2"
+ GRUB_CFLAGS="-O2"
+ AC_CACHE_CHECK([whether optimization for size works], size_flag, [
+ saved_CFLAGS=$CFLAGS
+ CFLAGS="-Os -g"
+ AC_TRY_COMPILE(, , size_flag=yes, size_flag=no)
+ CFLAGS=$saved_CFLAGS
+ ])
+ if test "x$size_flag" = xyes; then
+ STAGE2_CFLAGS="-Os"
+ else
+ STAGE2_CFLAGS="-O2 -fno-strength-reduce -fno-unroll-loops"
+ fi
+ fi
+fi
+
+AC_SUBST(STAGE1_CFLAGS)
+AC_SUBST(STAGE2_CFLAGS)
+AC_SUBST(GRUB_CFLAGS)
+
+# Enforce coding standards.
+CPPFLAGS="$CPPFLAGS -Wall -Wmissing-prototypes -Wunused -Wshadow"
+CPPFLAGS="$CPPFLAGS -Wpointer-arith"
+
+AC_CACHE_CHECK([whether -Wundef works], undef_flag, [
+ saved_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="-Wundef"
+ AC_TRY_COMPILE(, , undef_flag=yes, undef_flag=no)
+ CPPFLAGS="$saved_CPPFLAGS"
+])
+
+# The options `-falign-*' are supported by gcc 3.0 or later.
+# Probably it is sufficient to only check for -falign-loops.
+AC_CACHE_CHECK([whether -falign-loops works], [falign_loop_flag], [
+ saved_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="-falign-loops=1"
+ AC_TRY_COMPILE(, , [falign_loop_flag=yes], [falign_loop_flag=no])
+ CPPFLAGS="$saved_CPPFLAGS"
+])
+
+# Force no alignment to save space.
+if test "x$falign_loop_flag" = xyes; then
+ CPPFLAGS="$CPPFLAGS -falign-jumps=1 -falign-loops=1 -falign-functions=1"
+else
+ CPPFLAGS="$CPPFLAGS -malign-jumps=1 -malign-loops=1 -malign-functions=1"
+fi
+
+if test "x$undef_flag" = xyes; then
+ CPPFLAGS="$CPPFLAGS -Wundef"
+fi
+
+if test "x$with_binutils" != x; then
+dnl AC_PATH_TOOL(OBJCOPY, objcopy, , "$with_binutils:$PATH")
+ AC_PATH_PROG(OBJCOPY, objcopy, , "$with_binutils:$PATH")
+else
+ AC_CHECK_TOOL(OBJCOPY, objcopy)
+fi
+
+# Defined in acinclude.m4.
+grub_ASM_USCORE
+grub_PROG_OBJCOPY_ABSOLUTE
+if test "x$grub_cv_prog_objcopy_absolute" != xyes; then
+ AC_MSG_ERROR([GRUB requires a working absolute objcopy; upgrade your binutils])
+fi
+
+grub_ASM_PREFIX_REQUIREMENT
+
+grub_ASM_ADDR32
+if test "x$grub_cv_asm_addr32" != xyes; then
+ AC_MSG_ERROR([GRUB requires GAS .code16 addr32 support; upgrade your binutils])
+fi
+
+grub_ASM_ABSOLUTE_WITHOUT_ASTERISK
+
+grub_CHECK_START_SYMBOL
+grub_CHECK_USCORE_START_SYMBOL
+if test "x$grub_cv_check_start_symbol" != "xyes" \
+ -a "x$grub_cv_check_uscore_start_symbol" != "xyes"; then
+ AC_MSG_ERROR([Neither start nor _start is defined])
+fi
+
+grub_CHECK_USCORE_USCORE_BSS_START_SYMBOL
+grub_CHECK_USCORE_EDATA_SYMBOL
+grub_CHECK_EDATA_SYMBOL
+if test "x$grub_cv_check_uscore_uscore_bss_start_symbol" != "xyes" \
+ -a "x$grub_cv_check_uscore_edata_symbol" != "xyes" \
+ -a "x$grub_cv_check_edata_symbol" != "xyes"; then
+ AC_MSG_ERROR([None of __bss_start, _edata, edata defined])
+fi
+
+grub_CHECK_END_SYMBOL
+grub_CHECK_USCORE_END_SYMBOL
+if test "x$grub_cv_check_end_symbol" != "xyes" \
+ -a "x$grub_cv_check_uscore_end_symbol" != "xyes"; then
+ AC_MSG_ERROR([Neither end nor _end is defined])
+fi
+
+# Check for curses libraries.
+AC_ARG_WITH(curses,
+ [ --without-curses do not use curses])
+
+# Get the filename or the whole disk and open it.
+# Known to work on NetBSD.
+AC_CHECK_LIB(util, opendisk, [GRUB_LIBS="$GRUB_LIBS -lutil"
+ AC_DEFINE(HAVE_OPENDISK, 1, [Define if opendisk() in -lutil can be used])])
+
+# Unless the user specify --without-curses, check for curses.
+if test "x$with_curses" != "xno"; then
+ AC_CHECK_LIB(ncurses, wgetch, [GRUB_LIBS="$GRUB_LIBS -lncurses"
+ AC_DEFINE(HAVE_LIBCURSES)],
+ [AC_CHECK_LIB(curses, wgetch, [GRUB_LIBS="$GRUB_LIBS -lcurses"
+ AC_DEFINE(HAVE_LIBCURSES)])])
+fi
+
+AC_SUBST(GRUB_LIBS)
+
+# Check for headers.
+AC_CHECK_HEADERS(string.h strings.h ncurses/curses.h ncurses.h curses.h)
+
+# Check for user options.
+
+# filesystems support.
+AC_ARG_ENABLE(ext2fs,
+ [ --disable-ext2fs disable ext2fs support in Stage 2])
+
+if test x"$enable_ext2fs" != xno; then
+ FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_EXT2FS=1"
+fi
+
+AC_ARG_ENABLE(fat,
+ [ --disable-fat disable FAT support in Stage 2])
+
+if test x"$enable_fat" != xno; then
+ FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_FAT=1"
+fi
+
+AC_ARG_ENABLE(ffs,
+ [ --disable-ffs disable FFS support in Stage 2])
+
+if test x"$enable_ffs" != xno; then
+ FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_FFS=1"
+fi
+
+AC_ARG_ENABLE(minix,
+ [ --disable-minix disable Minix fs support in Stage 2])
+
+if test x"$enable_minix" != xno; then
+ FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_MINIX=1"
+fi
+
+AC_ARG_ENABLE(reiserfs,
+ [ --disable-reiserfs disable ReiserFS support in Stage 2])
+
+if test x"$enable_reiserfs" != xno; then
+ FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_REISERFS=1"
+fi
+
+AC_ARG_ENABLE(vstafs,
+ [ --disable-vstafs disable VSTa FS support in Stage 2])
+
+if test x"$enable_vstafs" != xno; then
+ FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_VSTAFS=1"
+fi
+
+AC_ARG_ENABLE(jfs,
+ [ --disable-jfs disable IBM JFS support in Stage 2])
+
+if test x"$enable_jfs" != xno; then
+ FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_JFS=1"
+fi
+
+AC_ARG_ENABLE(xfs,
+ [ --disable-xfs disable SGI XFS support in Stage 2])
+
+if test x"$enable_xfs" != xno; then
+ FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_XFS=1"
+fi
+
+dnl AC_ARG_ENABLE(tftp,
+dnl [ --enable-tftp enable TFTP support in Stage 2])
+dnl
+dnl #if test x"$enable_tftp" = xyes; then
+dnl FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_TFTP=1"
+dnl fi
+
+AC_ARG_ENABLE(gunzip,
+ [ --disable-gunzip disable decompression in Stage 2])
+
+if test x"$enable_gunzip" = xno; then
+ FSYS_CFLAGS="$FSYS_CFLAGS -DNO_DECOMPRESSION=1"
+fi
+
+AC_ARG_ENABLE(md5-password,
+ [ --disable-md5-password disable MD5 password support in Stage 2])
+if test "x$enable_md5_password" != xno; then
+ FSYS_CFLAGS="$FSYS_CFLAGS -DUSE_MD5_PASSWORDS=1"
+fi
+
+dnl The netboot support.
+dnl General options.
+AC_ARG_ENABLE(packet-retransmission,
+ [ --disable-packet-retransmission
+ turn off packet retransmission])
+if test "x$enable_packet_retransmission" != xno; then
+ NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DCONGESTED=1"
+fi
+
+AC_ARG_ENABLE(pci-direct,
+ [ --enable-pci-direct access PCI directly instead of using BIOS])
+if test "x$enable_pci_direct" = xyes; then
+ NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DCONFIG_PCI_DIRECT=1"
+fi
+
+dnl Device drivers.
+AC_ARG_ENABLE(3c509,
+ [ --enable-3c509 enable 3Com509 driver])
+if test "x$enable_3c509" = xyes; then
+ NET_CFLAGS="$NET_CFLAGS -DINCLUDE_3C509"
+ NETBOOT_DRIVERS="$NETBOOT_DRIVERS 3c509.o"
+fi
+
+AC_ARG_ENABLE(3c529,
+ [ --enable-3c529 enable 3Com529 driver])
+if test "x$enable_3c529" = xyes; then
+ NET_CFLAGS="$NET_CFLAGS -DINCLUDE_3C529=1"
+ NETBOOT_DRIVERS="$NETBOOT_DRIVERS 3c529.o"
+fi
+
+AC_ARG_ENABLE(3c595,
+ [ --enable-3c595 enable 3Com595 driver])
+if test "x$enable_3c595" = xyes; then
+ NET_CFLAGS="$NET_CFLAGS -DINCLUDE_3C595=1"
+ NETBOOT_DRIVERS="$NETBOOT_DRIVERS 3c595.o"
+fi
+
+AC_ARG_ENABLE(3c90x,
+ [ --enable-3c90x enable 3Com90x driver])
+if test "x$enable_3c90x" = xyes; then
+ NET_CFLAGS="$NET_CFLAGS -DINCLUDE_3C90X=1"
+ NETBOOT_DRIVERS="$NETBOOT_DRIVERS 3c90x.o"
+fi
+
+AC_ARG_ENABLE(cs89x0,
+ [ --enable-cs89x0 enable CS89x0 driver])
+if test "x$enable_cs89x0" = xyes; then
+ NET_CFLAGS="$NET_CFLAGS -DINCLUDE_CS89X0=1"
+ NETBOOT_DRIVERS="$NETBOOT_DRIVERS cs89x0.o"
+fi
+
+AC_ARG_ENABLE(davicom,
+ [ --enable-davicom enable Davicom driver])
+if test "x$enable_davicom" = xyes; then
+ NET_CFLAGS="$NET_CFLAGS -DINCLUDE_DAVICOM=1"
+ NETBOOT_DRIVERS="$NETBOOT_DRIVERS davicom.o"
+fi
+
+AC_ARG_ENABLE(depca,
+ [ --enable-depca enable DEPCA and EtherWORKS driver])
+if test "x$enable_depca" = xyes; then
+ NET_CFLAGS="$NET_CFLAGS -DINCLUDE_DEPCA=1"
+ NETBOOT_DRIVERS="$NETBOOT_DRIVERS depca.o"
+fi
+
+AC_ARG_ENABLE(eepro,
+ [ --enable-eepro enable Etherexpress Pro/10 driver])
+if test "x$enable_eepro" = xyes; then
+ NET_CFLAGS="$NET_CFLAGS -DINCLUDE_EEPRO=1"
+ NETBOOT_DRIVERS="$NETBOOT_DRIVERS eepro.o"
+fi
+
+AC_ARG_ENABLE(eepro100,
+ [ --enable-eepro100 enable Etherexpress Pro/100 driver])
+if test "x$enable_eepro100" = xyes; then
+ NET_CFLAGS="$NET_CFLAGS -DINCLUDE_EEPRO100=1"
+ NETBOOT_DRIVERS="$NETBOOT_DRIVERS eepro100.o"
+fi
+
+AC_ARG_ENABLE(epic100,
+ [ --enable-epic100 enable SMC 83c170 EPIC/100 driver])
+if test "x$enable_epic100" = xyes; then
+ NET_CFLAGS="$NET_CFLAGS -DINCLUDE_EPIC100=1"
+ NETBOOT_DRIVERS="$NETBOOT_DRIVERS epic100.o"
+fi
+
+AC_ARG_ENABLE(3c507,
+ [ --enable-3c507 enable 3Com507 driver])
+if test "x$enable_3c507" = xyes; then
+ NET_CFLAGS="$NET_CFLAGS -DINCLUDE_3C507=1"
+ NETBOOT_DRIVERS="$NETBOOT_DRIVERS 3c507.o"
+fi
+
+AC_ARG_ENABLE(exos205,
+ [ --enable-exos205 enable EXOS205 driver])
+if test "x$enable_exos205" = xyes; then
+ NET_CFLAGS="$NET_CFLAGS -DINCLUDE_EXOS205=1"
+ NETBOOT_DRIVERS="$NETBOOT_DRIVERS exos205.o"
+fi
+
+AC_ARG_ENABLE(ni5210,
+ [ --enable-ni5210 enable Racal-Interlan NI5210 driver])
+if test "x$enable_ni5210" = xyes; then
+ NET_CFLAGS="$NET_CFLAGS -DINCLUDE_NI5210=1"
+ NETBOOT_DRIVERS="$NETBOOT_DRIVERS ni5210.o"
+fi
+
+AC_ARG_ENABLE(lance,
+ [ --enable-lance enable Lance PCI PCNet/32 driver])
+if test "x$enable_lance" = xyes; then
+ NET_CFLAGS="$NET_CFLAGS -DINCLUDE_LANCE=1"
+ NETBOOT_DRIVERS="$NETBOOT_DRIVERS lance.o"
+fi
+
+AC_ARG_ENABLE(ne2100,
+ [ --enable-ne2100 enable Novell NE2100 driver])
+if test "x$enable_ne2100" = xyes; then
+ NET_CFLAGS="$NET_CFLAGS -DINCLUDE_NE2100=1"
+ NETBOOT_DRIVERS="$NETBOOT_DRIVERS ne2100.o"
+fi
+
+AC_ARG_ENABLE(ni6510,
+ [ --enable-ni6510 enable Racal-Interlan NI6510 driver])
+if test "x$enable_ni6510" = xyes; then
+ NET_CFLAGS="$NET_CFLAGS -DINCLUDE_NI6510=1"
+ NETBOOT_DRIVERS="$NETBOOT_DRIVERS ni6510.o"
+fi
+
+AC_ARG_ENABLE(natsemi,
+ [ --enable-natsemi enable NatSemi DP8381x driver])
+if test "x$enable_natsemi" = xyes; then
+ NET_CFLAGS="$NET_CFLAGS -DINCLUDE_NATSEMI=1"
+ NETBOOT_DRIVERS="$NETBOOT_DRIVERS natsemi.o"
+fi
+
+AC_ARG_ENABLE(ni5010,
+ [ --enable-ni5010 enable Racal-Interlan NI5010 driver])
+if test "x$enable_ni5010" = xyes; then
+ NET_CFLAGS="$NET_CFLAGS -DINCLUDE_NI5010=1"
+ NETBOOT_DRIVERS="$NETBOOT_DRIVERS ni5010.o"
+fi
+
+AC_ARG_ENABLE(3c503,
+ [ --enable-3c503 enable 3Com503 driver])
+if test "x$enable_3c503" = xyes; then
+ NET_CFLAGS="$NET_CFLAGS -DINCLUDE_3C503=1"
+ NETBOOT_DRIVERS="$NETBOOT_DRIVERS 3c503.o"
+fi
+
+AC_ARG_ENABLE(ne,
+ [ --enable-ne enable NE1000/2000 ISA driver])
+if test "x$enable_ne" = xyes; then
+ NET_CFLAGS="$NET_CFLAGS -DINCLUDE_NE=1"
+ NETBOOT_DRIVERS="$NETBOOT_DRIVERS ne.o"
+fi
+
+AC_ARG_ENABLE(ns8390,
+ [ --enable-ns8390 enable NE2000 PCI driver])
+if test "x$enable_ns8390" = xyes; then
+ NET_CFLAGS="$NET_CFLAGS -DINCLUDE_NS8390=1"
+ NETBOOT_DRIVERS="$NETBOOT_DRIVERS ns8390.o"
+fi
+
+AC_ARG_ENABLE(wd,
+ [ --enable-wd enable WD8003/8013, SMC8216/8416 driver])
+if test "x$enable_wd" = xyes; then
+ NET_CFLAGS="$NET_CFLAGS -DINCLUDE_WD=1"
+ NETBOOT_DRIVERS="$NETBOOT_DRIVERS wd.o"
+fi
+
+AC_ARG_ENABLE(otulip,
+ [ --enable-otulip enable old Tulip driver])
+if test "x$enable_otulip" = xyes; then
+ NET_CFLAGS="$NET_CFLAGS -DINCLUDE_OTULIP=1"
+ NETBOOT_DRIVERS="$NETBOOT_DRIVERS otulip.o"
+fi
+
+AC_ARG_ENABLE(rtl8139,
+ [ --enable-rtl8139 enable Realtek 8139 driver])
+if test "x$enable_rtl8139" = xyes; then
+ NET_CFLAGS="$NET_CFLAGS -DINCLUDE_RTL8139=1"
+ NETBOOT_DRIVERS="$NETBOOT_DRIVERS rtl8139.o"
+fi
+
+AC_ARG_ENABLE(sis900,
+ [ --enable-sis900 enable SIS 900 and SIS 7016 driver])
+if test "x$enable_sis900" = xyes; then
+ NET_CFLAGS="$NET_CFLAGS -DINCLUDE_SIS900=1"
+ NETBOOT_DRIVERS="$NETBOOT_DRIVERS sis900.o"
+fi
+
+AC_ARG_ENABLE(sk-g16,
+ [ --enable-sk-g16 enable Schneider and Koch G16 driver])
+if test "x$enable_sk_g16" = xyes; then
+ NET_CFLAGS="$NET_CFLAGS -DINCLUDE_SK_G16=1"
+ NETBOOT_DRIVERS="$NETBOOT_DRIVERS sk_g16.o"
+fi
+
+AC_ARG_ENABLE(smc9000,
+ [ --enable-smc9000 enable SMC9000 driver])
+if test "x$enable_smc9000" = xyes; then
+ NET_CFLAGS="$NET_CFLAGS -DINCLUDE_SMC9000=1"
+ NETBOOT_DRIVERS="$NETBOOT_DRIVERS smc9000.o"
+fi
+
+AC_ARG_ENABLE(tiara,
+ [ --enable-tiara enable Tiara driver])
+if test "x$enable_tiara" = xyes; then
+ NET_CFLAGS="$NET_CFLAGS -DINCLUDE_TIARA=1"
+ NETBOOT_DRIVERS="$NETBOOT_DRIVERS tiara.o"
+fi
+
+AC_ARG_ENABLE(tulip,
+ [ --enable-tulip enable Tulip driver])
+if test "x$enable_tulip" = xyes; then
+ NET_CFLAGS="$NET_CFLAGS -DINCLUDE_TULIP=1"
+ NETBOOT_DRIVERS="$NETBOOT_DRIVERS tulip.o"
+fi
+
+AC_ARG_ENABLE(via-rhine,
+ [ --enable-via-rhine enable Rhine-I/II driver])
+if test "x$enable_via_rhine" = xyes; then
+ NET_CFLAGS="$NET_CFLAGS -DINCLUDE_VIA_RHINE=1"
+ NETBOOT_DRIVERS="$NETBOOT_DRIVERS via_rhine.o"
+fi
+
+AC_ARG_ENABLE(w89c840,
+ [ --enable-w89c840 enable Winbond W89c840, Compex RL100-ATX driver])
+if test "x$enable_w89c840" = xyes; then
+ NET_CFLAGS="$NET_CFLAGS -DINCLUDE_W89C840=1"
+ NETBOOT_DRIVERS="$NETBOOT_DRIVERS w89c840.o"
+fi
+
+dnl Check if the netboot support is turned on.
+AM_CONDITIONAL(NETBOOT_SUPPORT, test "x$NET_CFLAGS" != x)
+if test "x$NET_CFLAGS" != x; then
+ FSYS_CFLAGS="$FSYS_CFLAGS -DFSYS_TFTP=1"
+fi
+
+dnl Extra options.
+AC_ARG_ENABLE(3c503-shmem,
+ [ --enable-3c503-shmem use 3c503 shared memory mode])
+if test "x$enable_3c503_shmem" = xyes; then
+ NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DT503_SHMEM=1"
+fi
+
+AC_ARG_ENABLE(3c503-aui,
+ [ --enable-3c503-aui use AUI by default on 3c503 cards])
+if test "x$enable_3c503_aui" = xyes; then
+ NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DT503_AUI=1"
+fi
+
+AC_ARG_ENABLE(compex-rl2000-fix,
+ [ --enable-compex-rl2000-fix
+ specify this if you have a Compex RL2000 PCI])
+if test "x$enable_compex_rl2000_fix" = xyes; then
+ NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DCOMPEX_RL2000_FIX=1"
+fi
+
+AC_ARG_ENABLE(smc9000-scan,
+ [ --enable-smc9000-scan=LIST
+ probe for SMC9000 I/O addresses using LIST],
+ [NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DSMC9000_SCAN=$enable_smc9000_scan"])
+
+AC_ARG_ENABLE(ne-scan,
+ [ --enable-ne-scan=LIST probe for NE base address using LIST],
+ [NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DNE_SCAN=$enable_ne_scan"],
+ [NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DNE_SCAN=0x280,0x300,0x320,0x340"])
+
+AC_ARG_ENABLE(wd-default-mem,
+ [ --enable-wd-default-mem=MEM
+ set the default memory location for WD/SMC],
+ [NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DWD_DEFAULT_MEM=$enable_wd_default_mem"],
+ [NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DWD_DEFAULT_MEM=0xCC000"])
+
+AC_ARG_ENABLE(cs-scan,
+ [ --enable-cs-scan=LIST probe for CS89x0 base address using LIST],
+ [NET_EXTRAFLAGS="$NET_EXTRAFLAGS -DCS_SCAN=$enable_cs_scan"])
+
+dnl Diskless
+AC_ARG_ENABLE(diskless,
+ [ --enable-diskless enable diskless support])
+AM_CONDITIONAL(DISKLESS_SUPPORT, test "x$enable_diskless" = xyes)
+
+dnl Hercules terminal
+AC_ARG_ENABLE(hercules,
+ [ --disable-hercules disable hercules terminal support])
+AM_CONDITIONAL(HERCULES_SUPPORT, test "x$enable_hercules" != xno)
+
+dnl Serial terminal
+AC_ARG_ENABLE(serial,
+ [ --disable-serial disable serial terminal support])
+AM_CONDITIONAL(SERIAL_SUPPORT, test "x$enable_serial" != xno)
+
+dnl Simulation of the slowness of a serial device.
+AC_ARG_ENABLE(serial-speed-simulation,
+ [ --enable-serial-speed-simulation
+ simulate the slowness of a serial device])
+AM_CONDITIONAL(SERIAL_SPEED_SIMULATION,
+ test "x$enable_serial_speed_simulation" = xyes)
+
+# Sanity check.
+if test "x$enable_diskless" = xyes; then
+ if test "x$NET_CFLAGS" = x; then
+ AC_MSG_ERROR([You must enable at least one network driver])
+ fi
+fi
+
+dnl Embed a menu string in GRUB itself.
+AC_ARG_ENABLE(preset-menu,
+ [ --enable-preset-menu=FILE
+ preset a menu file FILE in Stage 2])
+if test "x$enable_preset_menu" = x; then
+ :
+else
+ if test -r $enable_preset_menu; then
+ grub_DEFINE_FILE(PRESET_MENU_STRING, [$enable_preset_menu])
+ else
+ AC_MSG_ERROR([Cannot read the preset menu file $enable_preset_menu])
+ fi
+fi
+
+dnl Build the example Multiboot kernel.
+AC_ARG_ENABLE(example-kernel,
+ [ --enable-example-kernel
+ build the example Multiboot kernel])
+AM_CONDITIONAL(BUILD_EXAMPLE_KERNEL, test "x$enable_example_kernel" = xyes)
+
+dnl Automatic Linux mem= option.
+AC_ARG_ENABLE(auto-linux-mem-opt,
+ [ --disable-auto-linux-mem-opt
+ don't pass Linux mem= option automatically])
+if test "x$enable_auto_linux_mem_opt" = xno; then
+ :
+else
+ AC_DEFINE(AUTO_LINUX_MEM_OPT)
+fi
+
+dnl Now substitute the variables.
+AC_SUBST(FSYS_CFLAGS)
+AC_SUBST(NET_CFLAGS)
+AC_SUBST(NET_EXTRAFLAGS)
+AC_SUBST(NETBOOT_DRIVERS)
+
+dnl Because recent automake complains about CCASFLAGS, set it here.
+CCASFLAGS='$(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)'
+AC_SUBST(CCASFLAGS)
+
+
+dnl Output.
+AC_CONFIG_FILES([Makefile stage1/Makefile stage2/Makefile \
+ docs/Makefile lib/Makefile util/Makefile \
+ grub/Makefile netboot/Makefile util/grub-image \
+ util/grub-install util/grub-md5-crypt \
+ util/grub-terminfo])
+AC_OUTPUT
diff -ruN grub-0.94.orig/grub/Makefile.am grub/Makefile.am
--- grub-0.94.orig/grub/Makefile.am Wed Feb 11 00:22:12 2004
+++ grub/Makefile.am Wed Feb 11 00:22:29 2004
@@ -7,6 +7,7 @@
endif
AM_CPPFLAGS = -DGRUB_UTIL=1 -DFSYS_EXT2FS=1 -DFSYS_FAT=1 \
+ -DFSYS_UFS2=1 \
-DFSYS_FFS=1 -DFSYS_MINIX=1 -DSUPPORT_HERCULES=1 \
$(SERIAL_FLAGS) -I$(top_srcdir)/stage2 \
-I$(top_srcdir)/stage1 -I$(top_srcdir)/lib
diff -ruN grub-0.94.orig/grub/Makefile.am.orig grub/Makefile.am.orig
--- grub-0.94.orig/grub/Makefile.am.orig Thu Jan 1 03:00:00 1970
+++ grub/Makefile.am.orig Sun Jan 18 22:34:24 2004
@@ -0,0 +1,17 @@
+sbin_PROGRAMS = grub
+
+if SERIAL_SPEED_SIMULATION
+SERIAL_FLAGS = -DSUPPORT_SERIAL=1 -DSIMULATE_SLOWNESS_OF_SERIAL=1
+else
+SERIAL_FLAGS = -DSUPPORT_SERIAL=1
+endif
+
+AM_CPPFLAGS = -DGRUB_UTIL=1 -DFSYS_EXT2FS=1 -DFSYS_FAT=1 \
+ -DFSYS_FFS=1 -DFSYS_MINIX=1 -DSUPPORT_HERCULES=1 \
+ $(SERIAL_FLAGS) -I$(top_srcdir)/stage2 \
+ -I$(top_srcdir)/stage1 -I$(top_srcdir)/lib
+
+AM_CFLAGS = $(GRUB_CFLAGS) -fwritable-strings
+
+grub_SOURCES = main.c asmstub.c
+grub_LDADD = ../stage2/libgrub.a ../lib/libcommon.a $(GRUB_LIBS)
diff -ruN grub-0.94.orig/stage2/Makefile.am stage2/Makefile.am
--- grub-0.94.orig/stage2/Makefile.am Wed Feb 11 00:22:12 2004
+++ stage2/Makefile.am Wed Feb 11 00:22:29 2004
@@ -17,10 +17,12 @@
noinst_LIBRARIES = libgrub.a
libgrub_a_SOURCES = boot.c builtins.c char_io.c cmdline.c common.c \
disk_io.c fsys_ext2fs.c fsys_fat.c fsys_ffs.c fsys_jfs.c \
+ fsys_ufs2.c \
fsys_minix.c fsys_reiserfs.c fsys_vstafs.c fsys_xfs.c gunzip.c \
md5.c serial.c stage2.c terminfo.c tparm.c
libgrub_a_CFLAGS = $(GRUB_CFLAGS) -I$(top_srcdir)/lib \
-DGRUB_UTIL=1 -DFSYS_EXT2FS=1 -DFSYS_FAT=1 -DFSYS_FFS=1 \
+ -DFSYS_UFS2=1 \
-DFSYS_JFS=1 -DFSYS_MINIX=1 -DFSYS_REISERFS=1 -DFSYS_VSTAFS=1 \
-DFSYS_XFS=1 -DUSE_MD5_PASSWORDS=1 \
-DSUPPORT_SERIAL=1 -DSUPPORT_HERCULES=1 -fwritable-strings
@@ -33,21 +35,25 @@
if DISKLESS_SUPPORT
pkgdata_DATA = stage2 e2fs_stage1_5 fat_stage1_5 ffs_stage1_5 \
jfs_stage1_5 minix_stage1_5 reiserfs_stage1_5 vstafs_stage1_5 \
+ ufs2_stage1_5 \
xfs_stage1_5 nbgrub pxegrub
noinst_DATA = pre_stage2 start nbloader pxeloader diskless
noinst_PROGRAMS = pre_stage2.exec start.exec e2fs_stage1_5.exec \
fat_stage1_5.exec ffs_stage1_5.exec jfs_stage1_5.exec \
minix_stage1_5.exec reiserfs_stage1_5.exec \
+ ufs2_stage1_5.exec \
vstafs_stage1_5.exec xfs_stage1_5.exec nbloader.exec \
pxeloader.exec diskless.exec
else
pkgdata_DATA = stage2 e2fs_stage1_5 fat_stage1_5 ffs_stage1_5 \
jfs_stage1_5 minix_stage1_5 reiserfs_stage1_5 vstafs_stage1_5 \
+ ufs2_stage1_5 \
xfs_stage1_5
noinst_DATA = pre_stage2 start
noinst_PROGRAMS = pre_stage2.exec start.exec e2fs_stage1_5.exec \
fat_stage1_5.exec ffs_stage1_5.exec jfs_stage1_5.exec \
minix_stage1_5.exec reiserfs_stage1_5.exec \
+ ufs2_stage1_5.exec \
vstafs_stage1_5.exec xfs_stage1_5.exec
endif
MOSTLYCLEANFILES = $(noinst_PROGRAMS)
@@ -84,6 +90,7 @@
# For stage2 target.
pre_stage2_exec_SOURCES = asm.S bios.c boot.c builtins.c char_io.c \
cmdline.c common.c console.c disk_io.c fsys_ext2fs.c \
+ fsys_ufs2.c \
fsys_fat.c fsys_ffs.c fsys_jfs.c fsys_minix.c fsys_reiserfs.c \
fsys_vstafs.c fsys_xfs.c gunzip.c hercules.c md5.c serial.c \
smp-imps.c stage2.c terminfo.c tparm.c
@@ -148,6 +155,15 @@
ffs_stage1_5_exec_CCASFLAGS = $(STAGE1_5_COMPILE) -DFSYS_FFS=1 \
-DNO_BLOCK_FILES=1
ffs_stage1_5_exec_LDFLAGS = $(STAGE1_5_LINK)
+
+# For ufs2_stage1_5 target.
+ufs2_stage1_5_exec_SOURCES = start.S asm.S common.c char_io.c disk_io.c \
+ stage1_5.c fsys_ufs2.c bios.c
+ufs2_stage1_5_exec_CFLAGS = $(STAGE1_5_COMPILE) -DFSYS_UFS2=1 \
+ -DNO_BLOCK_FILES=1
+ufs2_stage1_5_exec_CCASFLAGS = $(STAGE1_5_COMPILE) -DFSYS_UFS2=1 \
+ -DNO_BLOCK_FILES=1
+ufs2_stage1_5_exec_LDFLAGS = $(STAGE1_5_LINK)
# For minix_stage1_5 target.
minix_stage1_5_exec_SOURCES = start.S asm.S common.c char_io.c disk_io.c \
diff -ruN grub-0.94.orig/stage2/Makefile.am.orig stage2/Makefile.am.orig
--- grub-0.94.orig/stage2/Makefile.am.orig Thu Jan 1 03:00:00 1970
+++ stage2/Makefile.am.orig Sun Oct 19 20:45:18 2003
@@ -0,0 +1,239 @@
+# For test target.
+TESTS = size_test
+noinst_SCRIPTS = $(TESTS)
+
+# For dist target.
+noinst_HEADERS = apic.h defs.h dir.h disk_inode.h disk_inode_ffs.h \
+ fat.h filesys.h freebsd.h fs.h hercules.h i386-elf.h \
+ imgact_aout.h jfs.h mb_header.h mb_info.h md5.h nbi.h \
+ pc_slice.h serial.h shared.h smp-imps.h term.h terminfo.h \
+ tparm.h nbi.h vstafs.h xfs.h
+EXTRA_DIST = setjmp.S apm.S $(noinst_SCRIPTS)
+
+# For <stage1.h>.
+INCLUDES = -I$(top_srcdir)/stage1
+
+# The library for /sbin/grub.
+noinst_LIBRARIES = libgrub.a
+libgrub_a_SOURCES = boot.c builtins.c char_io.c cmdline.c common.c \
+ disk_io.c fsys_ext2fs.c fsys_fat.c fsys_ffs.c fsys_jfs.c \
+ fsys_minix.c fsys_reiserfs.c fsys_vstafs.c fsys_xfs.c gunzip.c \
+ md5.c serial.c stage2.c terminfo.c tparm.c
+libgrub_a_CFLAGS = $(GRUB_CFLAGS) -I$(top_srcdir)/lib \
+ -DGRUB_UTIL=1 -DFSYS_EXT2FS=1 -DFSYS_FAT=1 -DFSYS_FFS=1 \
+ -DFSYS_JFS=1 -DFSYS_MINIX=1 -DFSYS_REISERFS=1 -DFSYS_VSTAFS=1 \
+ -DFSYS_XFS=1 -DUSE_MD5_PASSWORDS=1 \
+ -DSUPPORT_SERIAL=1 -DSUPPORT_HERCULES=1 -fwritable-strings
+
+# Stage 2 and Stage 1.5's.
+pkgdatadir = $(datadir)/$(PACKAGE)/$(host_cpu)-$(host_vendor)
+
+EXTRA_PROGRAMS = nbloader.exec pxeloader.exec diskless.exec
+
+if DISKLESS_SUPPORT
+pkgdata_DATA = stage2 e2fs_stage1_5 fat_stage1_5 ffs_stage1_5 \
+ jfs_stage1_5 minix_stage1_5 reiserfs_stage1_5 vstafs_stage1_5 \
+ xfs_stage1_5 nbgrub pxegrub
+noinst_DATA = pre_stage2 start nbloader pxeloader diskless
+noinst_PROGRAMS = pre_stage2.exec start.exec e2fs_stage1_5.exec \
+ fat_stage1_5.exec ffs_stage1_5.exec jfs_stage1_5.exec \
+ minix_stage1_5.exec reiserfs_stage1_5.exec \
+ vstafs_stage1_5.exec xfs_stage1_5.exec nbloader.exec \
+ pxeloader.exec diskless.exec
+else
+pkgdata_DATA = stage2 e2fs_stage1_5 fat_stage1_5 ffs_stage1_5 \
+ jfs_stage1_5 minix_stage1_5 reiserfs_stage1_5 vstafs_stage1_5 \
+ xfs_stage1_5
+noinst_DATA = pre_stage2 start
+noinst_PROGRAMS = pre_stage2.exec start.exec e2fs_stage1_5.exec \
+ fat_stage1_5.exec ffs_stage1_5.exec jfs_stage1_5.exec \
+ minix_stage1_5.exec reiserfs_stage1_5.exec \
+ vstafs_stage1_5.exec xfs_stage1_5.exec
+endif
+MOSTLYCLEANFILES = $(noinst_PROGRAMS)
+
+PRE_STAGE2_LINK = -nostdlib -Wl,-N -Wl,-Ttext -Wl,8200
+START_LINK = -nostdlib -Wl,-N -Wl,-Ttext -Wl,8000
+NBLOADER_LINK = -nostdlib -Wl,-N -Wl,-Ttext -Wl,0
+PXELOADER_LINK = -nostdlib -Wl,-N -Wl,-Ttext -Wl,7C00
+
+if NETBOOT_SUPPORT
+NETBOOT_FLAGS = -I$(top_srcdir)/netboot -DSUPPORT_NETBOOT=1
+else
+NETBOOT_FLAGS =
+endif
+
+if SERIAL_SUPPORT
+SERIAL_FLAGS = -DSUPPORT_SERIAL=1
+else
+SERIAL_FLAGS =
+endif
+
+if HERCULES_SUPPORT
+HERCULES_FLAGS = -DSUPPORT_HERCULES=1
+else
+HERCULES_FLAGS =
+endif
+
+STAGE2_COMPILE = $(STAGE2_CFLAGS) -fno-builtin -nostdinc \
+ $(NETBOOT_FLAGS) $(SERIAL_FLAGS) $(HERCULES_FLAGS)
+
+STAGE1_5_LINK = -nostdlib -Wl,-N -Wl,-Ttext -Wl,2000
+STAGE1_5_COMPILE = $(STAGE2_COMPILE) -DNO_DECOMPRESSION=1 -DSTAGE1_5=1
+
+# For stage2 target.
+pre_stage2_exec_SOURCES = asm.S bios.c boot.c builtins.c char_io.c \
+ cmdline.c common.c console.c disk_io.c fsys_ext2fs.c \
+ fsys_fat.c fsys_ffs.c fsys_jfs.c fsys_minix.c fsys_reiserfs.c \
+ fsys_vstafs.c fsys_xfs.c gunzip.c hercules.c md5.c serial.c \
+ smp-imps.c stage2.c terminfo.c tparm.c
+pre_stage2_exec_CFLAGS = $(STAGE2_COMPILE) $(FSYS_CFLAGS)
+pre_stage2_exec_CCASFLAGS = $(STAGE2_COMPILE) $(FSYS_CFLAGS)
+pre_stage2_exec_LDFLAGS = $(PRE_STAGE2_LINK)
+
+if NETBOOT_SUPPORT
+pre_stage2_exec_LDADD = ../netboot/libdrivers.a
+endif
+
+if DISKLESS_SUPPORT
+BUILT_SOURCES = stage2_size.h diskless_size.h
+else
+BUILT_SOURCES = stage2_size.h
+endif
+
+CLEANFILES = $(pkgdata_DATA) $(noinst_DATA) $(BUILT_SOURCES)
+
+stage2_size.h: pre_stage2
+ -rm -f stage2_size.h
+ set dummy `ls -l pre_stage2`; \
+ echo "#define STAGE2_SIZE $$6" > stage2_size.h
+
+start_exec_SOURCES = start.S
+start_exec_CCASFLAGS = $(STAGE2_COMPILE)
+start_exec_LDFLAGS = $(START_LINK)
+
+# XXX: automake doesn't provide a way to specify dependencies for object
+# files explicitly, so we must write this by a general Makefile scheme.
+# If automake change the naming scheme for per-executable objects, this
+# will be broken.
+start_exec-start.$(OBJEXT): stage2_size.h
+
+stage2: pre_stage2 start
+ -rm -f stage2
+ cat start pre_stage2 > stage2
+
+# For e2fs_stage1_5 target.
+e2fs_stage1_5_exec_SOURCES = start.S asm.S common.c char_io.c disk_io.c \
+ stage1_5.c fsys_ext2fs.c bios.c
+e2fs_stage1_5_exec_CFLAGS = $(STAGE1_5_COMPILE) -DFSYS_EXT2FS=1 \
+ -DNO_BLOCK_FILES=1
+e2fs_stage1_5_exec_CCASFLAGS = $(STAGE1_5_COMPILE) -DFSYS_EXT2FS=1 \
+ -DNO_BLOCK_FILES=1
+e2fs_stage1_5_exec_LDFLAGS = $(STAGE1_5_LINK)
+
+# For fat_stage1_5 target.
+fat_stage1_5_exec_SOURCES = start.S asm.S common.c char_io.c disk_io.c \
+ stage1_5.c fsys_fat.c bios.c
+fat_stage1_5_exec_CFLAGS = $(STAGE1_5_COMPILE) -DFSYS_FAT=1 \
+ -DNO_BLOCK_FILES=1
+fat_stage1_5_exec_CCASFLAGS = $(STAGE1_5_COMPILE) -DFSYS_FAT=1 \
+ -DNO_BLOCK_FILES=1
+fat_stage1_5_exec_LDFLAGS = $(STAGE1_5_LINK)
+
+# For ffs_stage1_5 target.
+ffs_stage1_5_exec_SOURCES = start.S asm.S common.c char_io.c disk_io.c \
+ stage1_5.c fsys_ffs.c bios.c
+ffs_stage1_5_exec_CFLAGS = $(STAGE1_5_COMPILE) -DFSYS_FFS=1 \
+ -DNO_BLOCK_FILES=1
+ffs_stage1_5_exec_CCASFLAGS = $(STAGE1_5_COMPILE) -DFSYS_FFS=1 \
+ -DNO_BLOCK_FILES=1
+ffs_stage1_5_exec_LDFLAGS = $(STAGE1_5_LINK)
+
+# For minix_stage1_5 target.
+minix_stage1_5_exec_SOURCES = start.S asm.S common.c char_io.c disk_io.c \
+ stage1_5.c fsys_minix.c bios.c
+minix_stage1_5_exec_CFLAGS = $(STAGE1_5_COMPILE) -DFSYS_MINIX=1 \
+ -DNO_BLOCK_FILES=1
+minix_stage1_5_exec_CCASFLAGS = $(STAGE1_5_COMPILE) -DFSYS_MINIX=1 \
+ -DNO_BLOCK_FILES=1
+minix_stage1_5_exec_LDFLAGS = $(STAGE1_5_LINK)
+
+# For reiserfs_stage1_5 target.
+reiserfs_stage1_5_exec_SOURCES = start.S asm.S common.c char_io.c \
+ disk_io.c stage1_5.c fsys_reiserfs.c bios.c
+reiserfs_stage1_5_exec_CFLAGS = $(STAGE1_5_COMPILE) -DFSYS_REISERFS=1 \
+ -DNO_BLOCK_FILES=1
+reiserfs_stage1_5_exec_CCASFLAGS = $(STAGE1_5_COMPILE) -DFSYS_REISERFS=1 \
+ -DNO_BLOCK_FILES=1
+reiserfs_stage1_5_exec_LDFLAGS = $(STAGE1_5_LINK)
+
+# For vstafs_stage1_5 target.
+vstafs_stage1_5_exec_SOURCES = start.S asm.S common.c char_io.c \
+ disk_io.c stage1_5.c fsys_vstafs.c bios.c
+vstafs_stage1_5_exec_CFLAGS = $(STAGE1_5_COMPILE) -DFSYS_VSTAFS=1 \
+ -DNO_BLOCK_FILES=1
+vstafs_stage1_5_exec_CCASFLAGS = $(STAGE1_5_COMPILE) -DFSYS_VSTAFS=1 \
+ -DNO_BLOCK_FILES=1
+vstafs_stage1_5_exec_LDFLAGS = $(STAGE1_5_LINK)
+
+# For jfs_stage1_5 target.
+jfs_stage1_5_exec_SOURCES = start.S asm.S common.c char_io.c \
+ disk_io.c stage1_5.c fsys_jfs.c bios.c
+jfs_stage1_5_exec_CFLAGS = $(STAGE1_5_COMPILE) -DFSYS_JFS=1 \
+ -DNO_BLOCK_FILES=1
+jfs_stage1_5_exec_CCASFLAGS = $(STAGE1_5_COMPILE) -DFSYS_JFS=1 \
+ -DNO_BLOCK_FILES=1
+jfs_stage1_5_exec_LDFLAGS = $(STAGE1_5_LINK)
+
+# For xfs_stage1_5 target.
+xfs_stage1_5_exec_SOURCES = start.S asm.S common.c char_io.c \
+ disk_io.c stage1_5.c fsys_xfs.c bios.c
+xfs_stage1_5_exec_CFLAGS = $(STAGE1_5_COMPILE) -DFSYS_XFS=1 \
+ -DNO_BLOCK_FILES=1
+xfs_stage1_5_exec_CCASFLAGS = $(STAGE1_5_COMPILE) -DFSYS_XFS=1 \
+ -DNO_BLOCK_FILES=1
+xfs_stage1_5_exec_LDFLAGS = $(STAGE1_5_LINK)
+
+# For diskless target.
+diskless_exec_SOURCES = $(pre_stage2_exec_SOURCES)
+diskless_exec_CFLAGS = $(STAGE2_COMPILE) $(FSYS_CFLAGS) \
+ -DSUPPORT_DISKLESS=1
+diskless_exec_CCASFLAGS = $(STAGE2_COMPILE) $(FSYS_CFLAGS) \
+ -DSUPPORT_DISKLESS=1
+diskless_exec_LDFLAGS = $(PRE_STAGE2_LINK)
+diskless_exec_LDADD = ../netboot/libdrivers.a
+
+diskless_size.h: diskless
+ -rm -f $@
+ set dummy `ls -l $^`; \
+ echo "#define DISKLESS_SIZE $$6" > $@
+
+# For nbloader target.
+nbloader_exec_SOURCES = nbloader.S
+nbloader_exec_CCASFLAGS = $(STAGE2_COMPILE)
+nbloader_exec_LDFLAGS = $(NBLOADER_LINK)
+
+# XXX: See the comment for start_exec-start.o.
+nbloader_exec-nbloader.$(OBJEXT): diskless_size.h
+
+# For nbgrub target.
+nbgrub: nbloader diskless
+ -rm -f $@
+ cat $^ > $@
+
+# For pxeloader target.
+pxeloader_exec_SOURCES = pxeloader.S
+pxeloader_exec_CCASFLAGS = $(STAGE2_COMPILE)
+pxeloader_exec_LDFLAGS = $(PXELOADER_LINK)
+
+# XXX: See the comment for start_exec-start.o.
+pxeloader_exec-pxeloader.$(OBJEXT): diskless_size.h
+
+# For pxegrub target.
+pxegrub: pxeloader diskless
+ -rm -f $@
+ cat $^ > $@
+
+# General rule for making a raw binary.
+%: %.exec
+ $(OBJCOPY) -O binary $< $@
diff -ruN grub-0.94.orig/stage2/builtins.c stage2/builtins.c
--- grub-0.94.orig/stage2/builtins.c Wed Feb 11 00:22:12 2004
+++ stage2/builtins.c Wed Feb 11 00:22:29 2004
@@ -3747,6 +3747,7 @@
{
{"ext2fs", "/e2fs_stage1_5"},
{"fat", "/fat_stage1_5"},
+ {"ufs2", "/ufs2_stage1_5"},
{"ffs", "/ffs_stage1_5"},
{"jfs", "/jfs_stage1_5"},
{"minix", "/minix_stage1_5"},
diff -ruN grub-0.94.orig/stage2/builtins.c.orig stage2/builtins.c.orig
--- grub-0.94.orig/stage2/builtins.c.orig Thu Jan 1 03:00:00 1970
+++ stage2/builtins.c.orig Sun Jan 11 12:39:22 2004
@@ -0,0 +1,4755 @@
+/* builtins.c - the GRUB builtin commands */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1999,2000,2001,2002,2003,2004 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 stdio.h before shared.h, because we can't define
+ WITHOUT_LIBC_STUBS here. */
+#ifdef GRUB_UTIL
+# include <stdio.h>
+#endif
+
+#include <shared.h>
+#include <filesys.h>
+#include <term.h>
+
+#ifdef SUPPORT_NETBOOT
+# define GRUB 1
+# include <etherboot.h>
+#endif
+
+#ifdef SUPPORT_SERIAL
+# include <serial.h>
+# include <terminfo.h>
+#endif
+
+#ifdef GRUB_UTIL
+# include <device.h>
+#else /* ! GRUB_UTIL */
+# include <apic.h>
+# include <smp-imps.h>
+#endif /* ! GRUB_UTIL */
+
+#ifdef USE_MD5_PASSWORDS
+# include <md5.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 number of current entry. */
+int current_entryno;
+/* The address for Multiboot command-line buffer. */
+static char *mb_cmdline;
+/* The password. */
+char *password;
+/* The password type. */
+password_t password_type;
+/* The flag for indicating that the user is authoritative. */
+int auth = 0;
+/* The timeout. */
+int grub_timeout = -1;
+/* Whether to show the menu or not. */
+int show_menu = 1;
+/* The BIOS drive map. */
+static unsigned short bios_drive_map[DRIVE_MAP_SIZE + 1];
+
+/* Prototypes for allowing straightfoward calling of builtins functions
+ inside other functions. */
+static int configfile_func (char *arg, int flags);
+
+/* 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;
+ password = 0;
+ fallback_entry = -1;
+ grub_timeout = -1;
+}
+
+/* Check a password for correctness. Returns 0 if password was
+ correct, and a value != 0 for error, similarly to strcmp. */
+int
+check_password (char *entered, char* expected, password_t type)
+{
+ switch (type)
+ {
+ case PASSWORD_PLAIN:
+ return strcmp (entered, expected);
+
+#ifdef USE_MD5_PASSWORDS
+ case PASSWORD_MD5:
+ return check_md5_password (entered, expected);
+#endif
+ default:
+ /* unsupported password type: be secure */
+ return 1;
+ }
+}
+
+/* Print which sector is read when loading a file. */
+static void
+disk_read_print_func (int sector, int offset, int length)
+{
+ grub_printf ("[%d,%d,%d]", sector, offset, length);
+}
+
+
+/* blocklist */
+static int
+blocklist_func (char *arg, int flags)
+{
+ char *dummy = (char *) RAW_ADDR (0x100000);
+ int start_sector;
+ int num_sectors = 0;
+ int num_entries = 0;
+ int last_length = 0;
+
+ /* Collect contiguous blocks into one entry as many as possible,
+ and print the blocklist notation on the screen. */
+ static void disk_read_blocklist_func (int sector, int offset, int length)
+ {
+ if (num_sectors > 0)
+ {
+ if (start_sector + num_sectors == sector
+ && offset == 0 && last_length == SECTOR_SIZE)
+ {
+ num_sectors++;
+ last_length = length;
+ return;
+ }
+ else
+ {
+ if (last_length == SECTOR_SIZE)
+ grub_printf ("%s%d+%d", num_entries ? "," : "",
+ start_sector - part_start, num_sectors);
+ else if (num_sectors > 1)
+ grub_printf ("%s%d+%d,%d[0-%d]", num_entries ? "," : "",
+ start_sector - part_start, num_sectors-1,
+ start_sector + num_sectors-1 - part_start,
+ last_length);
+ else
+ grub_printf ("%s%d[0-%d]", num_entries ? "," : "",
+ start_sector - part_start, last_length);
+ num_entries++;
+ num_sectors = 0;
+ }
+ }
+
+ if (offset > 0)
+ {
+ grub_printf("%s%d[%d-%d]", num_entries ? "," : "",
+ sector-part_start, offset, offset+length);
+ num_entries++;
+ }
+ else
+ {
+ start_sector = sector;
+ num_sectors = 1;
+ last_length = length;
+ }
+ }
+
+ /* Open the file. */
+ if (! grub_open (arg))
+ return 1;
+
+ /* Print the device name. */
+ grub_printf ("(%cd%d",
+ (current_drive & 0x80) ? 'h' : 'f',
+ current_drive & ~0x80);
+
+ if ((current_partition & 0xFF0000) != 0xFF0000)
+ grub_printf (",%d", (current_partition >> 16) & 0xFF);
+
+ if ((current_partition & 0x00FF00) != 0x00FF00)
+ grub_printf (",%c", 'a' + ((current_partition >> 8) & 0xFF));
+
+ grub_printf (")");
+
+ /* Read in the whole file to DUMMY. */
+ disk_read_hook = disk_read_blocklist_func;
+ if (! grub_read (dummy, -1))
+ goto fail;
+
+ /* The last entry may not be printed yet. Don't check if it is a
+ * full sector, since it doesn't matter if we read too much. */
+ if (num_sectors > 0)
+ grub_printf ("%s%d+%d", num_entries ? "," : "",
+ start_sector - part_start, num_sectors);
+
+ grub_printf ("\n");
+
+ fail:
+ disk_read_hook = 0;
+ grub_close ();
+ return errnum;
+}
+
+static struct builtin builtin_blocklist =
+{
+ "blocklist",
+ blocklist_func,
+ BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
+ "blocklist FILE",
+ "Print the blocklist notation of the file FILE."
+};
+
+/* boot */
+static int
+boot_func (char *arg, int flags)
+{
+ /* Clear the int15 handler if we can boot the kernel successfully.
+ This assumes that the boot code never fails only if KERNEL_TYPE is
+ not KERNEL_TYPE_NONE. Is this assumption is bad? */
+ if (kernel_type != KERNEL_TYPE_NONE)
+ unset_int15_handler ();
+
+#ifdef SUPPORT_NETBOOT
+ /* Shut down the networking. */
+ cleanup_net ();
+#endif
+
+ switch (kernel_type)
+ {
+ case KERNEL_TYPE_FREEBSD:
+ case KERNEL_TYPE_NETBSD:
+ /* *BSD */
+ bsd_boot (kernel_type, bootdev, (char *) mbi.cmdline);
+ 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 */
+
+ /* Check if we should set the int13 handler. */
+ if (bios_drive_map[0] != 0)
+ {
+ int i;
+
+ /* Search for SAVED_DRIVE. */
+ for (i = 0; i < DRIVE_MAP_SIZE; i++)
+ {
+ if (! bios_drive_map[i])
+ break;
+ else if ((bios_drive_map[i] & 0xFF) == saved_drive)
+ {
+ /* Exchage SAVED_DRIVE with the mapped drive. */
+ saved_drive = (bios_drive_map[i] >> 8) & 0xFF;
+ break;
+ }
+ }
+
+ /* Set the handler. This is somewhat dangerous. */
+ set_int13_handler (bios_drive_map);
+ }
+
+ gateA20 (0);
+ boot_drive = saved_drive;
+ chain_stage1 (0, BOOTSEC_LOCATION, boot_part_addr);
+ 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 | BUILTIN_HELP_LIST,
+ "boot",
+ "Boot the OS/chain-loader which has been loaded."
+};
+
+
+#ifdef SUPPORT_NETBOOT
+/* bootp */
+static int
+bootp_func (char *arg, int flags)
+{
+ int with_configfile = 0;
+
+ if (grub_memcmp (arg, "--with-configfile", sizeof ("--with-configfile") - 1)
+ == 0)
+ {
+ with_configfile = 1;
+ arg = skip_to (0, arg);
+ }
+
+ if (! bootp ())
+ {
+ if (errnum == ERR_NONE)
+ errnum = ERR_DEV_VALUES;
+
+ return 1;
+ }
+
+ /* Notify the configuration. */
+ print_network_configuration ();
+
+ /* XXX: this can cause an endless loop, but there is no easy way to
+ detect such a loop unfortunately. */
+ if (with_configfile)
+ configfile_func (config_file, flags);
+
+ return 0;
+}
+
+static struct builtin builtin_bootp =
+{
+ "bootp",
+ bootp_func,
+ BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
+ "bootp [--with-configfile]",
+ "Initialize a network device via BOOTP. If the option `--with-configfile'"
+ " is given, try to load a configuration file specified by the 150 vendor"
+ " tag."
+};
+#endif /* SUPPORT_NETBOOT */
+
+
+/* cat */
+static int
+cat_func (char *arg, int flags)
+{
+ char c;
+
+ if (! grub_open (arg))
+ return 1;
+
+ while (grub_read (&c, 1))
+ {
+ /* Because running "cat" with a binary file can confuse the terminal,
+ print only some characters as they are. */
+ if (grub_isspace (c) || (c >= ' ' && c <= '~'))
+ grub_putchar (c);
+ else
+ grub_putchar ('?');
+ }
+
+ grub_close ();
+ return 0;
+}
+
+static struct builtin builtin_cat =
+{
+ "cat",
+ cat_func,
+ BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
+ "cat FILE",
+ "Print the contents of the file FILE."
+};
+
+
+/* chainloader */
+static int
+chainloader_func (char *arg, int flags)
+{
+ int force = 0;
+ char *file = arg;
+
+ /* If the option `--force' is specified? */
+ if (substring ("--force", arg) <= 0)
+ {
+ force = 1;
+ file = skip_to (0, arg);
+ }
+
+ /* Open the file. */
+ if (! grub_open (file))
+ {
+ kernel_type = KERNEL_TYPE_NONE;
+ return 1;
+ }
+
+ /* Read the first block. */
+ if (grub_read ((char *) BOOTSEC_LOCATION, SECTOR_SIZE) != SECTOR_SIZE)
+ {
+ grub_close ();
+ kernel_type = KERNEL_TYPE_NONE;
+
+ /* This below happens, if a file whose size is less than 512 bytes
+ is loaded. */
+ if (errnum == ERR_NONE)
+ errnum = ERR_EXEC_FORMAT;
+
+ return 1;
+ }
+
+ /* If not loading it forcibly, check for the signature. */
+ if (! force
+ && (*((unsigned short *) (BOOTSEC_LOCATION + BOOTSEC_SIG_OFFSET))
+ != BOOTSEC_SIGNATURE))
+ {
+ grub_close ();
+ errnum = ERR_EXEC_FORMAT;
+ kernel_type = KERNEL_TYPE_NONE;
+ return 1;
+ }
+
+ grub_close ();
+ kernel_type = KERNEL_TYPE_CHAINLOADER;
+
+ /* XXX: Windows evil hack. For now, only the first five letters are
+ checked. */
+ if (IS_PC_SLICE_TYPE_FAT (current_slice)
+ && ! grub_memcmp ((char *) BOOTSEC_LOCATION + BOOTSEC_BPB_SYSTEM_ID,
+ "MSWIN", 5))
+ *((unsigned long *) (BOOTSEC_LOCATION + BOOTSEC_BPB_HIDDEN_SECTORS))
+ = part_start;
+
+ errnum = ERR_NONE;
+
+ return 0;
+}
+
+static struct builtin builtin_chainloader =
+{
+ "chainloader",
+ chainloader_func,
+ BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
+ "chainloader [--force] FILE",
+ "Load the chain-loader FILE. If --force is specified, then load it"
+ " forcibly, whether the boot loader signature is present or not."
+};
+
+
+/* This function could be used to debug new filesystem code. Put a file
+ in the new filesystem and the same file in a well-tested filesystem.
+ Then, run "cmp" with the files. If no output is obtained, probably
+ the code is good, otherwise investigate what's wrong... */
+/* cmp FILE1 FILE2 */
+static int
+cmp_func (char *arg, int flags)
+{
+ /* The filenames. */
+ char *file1, *file2;
+ /* The addresses. */
+ char *addr1, *addr2;
+ int i;
+ /* The size of the file. */
+ int size;
+
+ /* Get the filenames from ARG. */
+ file1 = arg;
+ file2 = skip_to (0, arg);
+ if (! *file1 || ! *file2)
+ {
+ errnum = ERR_BAD_ARGUMENT;
+ return 1;
+ }
+
+ /* Terminate the filenames for convenience. */
+ nul_terminate (file1);
+ nul_terminate (file2);
+
+ /* Read the whole data from FILE1. */
+ addr1 = (char *) RAW_ADDR (0x100000);
+ if (! grub_open (file1))
+ return 1;
+
+ /* Get the size. */
+ size = filemax;
+ if (grub_read (addr1, -1) != size)
+ {
+ grub_close ();
+ return 1;
+ }
+
+ grub_close ();
+
+ /* Read the whole data from FILE2. */
+ addr2 = addr1 + size;
+ if (! grub_open (file2))
+ return 1;
+
+ /* Check if the size of FILE2 is equal to the one of FILE2. */
+ if (size != filemax)
+ {
+ grub_printf ("Differ in size: 0x%x [%s], 0x%x [%s]\n",
+ size, file1, filemax, file2);
+ grub_close ();
+ return 0;
+ }
+
+ if (! grub_read (addr2, -1))
+ {
+ grub_close ();
+ return 1;
+ }
+
+ grub_close ();
+
+ /* Now compare ADDR1 with ADDR2. */
+ for (i = 0; i < size; i++)
+ {
+ if (addr1[i] != addr2[i])
+ grub_printf ("Differ at the offset %d: 0x%x [%s], 0x%x [%s]\n",
+ i, (unsigned) addr1[i], file1,
+ (unsigned) addr2[i], file2);
+ }
+
+ return 0;
+}
+
+static struct builtin builtin_cmp =
+{
+ "cmp",
+ cmp_func,
+ BUILTIN_CMDLINE,
+ "cmp FILE1 FILE2",
+ "Compare the file FILE1 with the FILE2 and inform the different values"
+ " if any."
+};
+
+
+/* color */
+/* Set new colors used for the menu interface. Support two methods to
+ specify a color name: a direct integer representation and a symbolic
+ color name. An example of the latter is "blink-light-gray/blue". */
+static int
+color_func (char *arg, int flags)
+{
+ char *normal;
+ char *highlight;
+ int new_normal_color;
+ int new_highlight_color;
+ static char *color_list[16] =
+ {
+ "black",
+ "blue",
+ "green",
+ "cyan",
+ "red",
+ "magenta",
+ "brown",
+ "light-gray",
+ "dark-gray",
+ "light-blue",
+ "light-green",
+ "light-cyan",
+ "light-red",
+ "light-magenta",
+ "yellow",
+ "white"
+ };
+
+ /* Convert the color name STR into the magical number. */
+ static int color_number (char *str)
+ {
+ char *ptr;
+ int i;
+ int color = 0;
+
+ /* Find the separator. */
+ for (ptr = str; *ptr && *ptr != '/'; ptr++)
+ ;
+
+ /* If not found, return -1. */
+ if (! *ptr)
+ return -1;
+
+ /* Terminate the string STR. */
+ *ptr++ = 0;
+
+ /* If STR contains the prefix "blink-", then set the `blink' bit
+ in COLOR. */
+ if (substring ("blink-", str) <= 0)
+ {
+ color = 0x80;
+ str += 6;
+ }
+
+ /* Search for the color name. */
+ for (i = 0; i < 16; i++)
+ if (grub_strcmp (color_list[i], str) == 0)
+ {
+ color |= i;
+ break;
+ }
+
+ if (i == 16)
+ return -1;
+
+ str = ptr;
+ nul_terminate (str);
+
+ /* Search for the color name. */
+ for (i = 0; i < 8; i++)
+ if (grub_strcmp (color_list[i], str) == 0)
+ {
+ color |= i << 4;
+ break;
+ }
+
+ if (i == 8)
+ return -1;
+
+ return color;
+ }
+
+ normal = arg;
+ highlight = skip_to (0, arg);
+
+ new_normal_color = color_number (normal);
+ if (new_normal_color < 0 && ! safe_parse_maxint (&normal, &new_normal_color))
+ return 1;
+
+ /* The second argument is optional, so set highlight_color
+ to inverted NORMAL_COLOR. */
+ if (! *highlight)
+ new_highlight_color = ((new_normal_color >> 4)
+ | ((new_normal_color & 0xf) << 4));
+ else
+ {
+ new_highlight_color = color_number (highlight);
+ if (new_highlight_color < 0
+ && ! safe_parse_maxint (&highlight, &new_highlight_color))
+ return 1;
+ }
+
+ if (current_term->setcolor)
+ current_term->setcolor (new_normal_color, new_highlight_color);
+
+ return 0;
+}
+
+static struct builtin builtin_color =
+{
+ "color",
+ color_func,
+ BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
+ "color NORMAL [HIGHLIGHT]",
+ "Change the menu colors. The color NORMAL is used for most"
+ " lines in the menu, and the color HIGHLIGHT is used to highlight the"
+ " line where the cursor points. If you omit HIGHLIGHT, then the"
+ " inverted color of NORMAL is used for the highlighted line."
+ " The format of a color is \"FG/BG\". FG and BG are symbolic color names."
+ " A symbolic color name must be one of these: black, blue, green,"
+ " cyan, red, magenta, brown, light-gray, dark-gray, light-blue,"
+ " light-green, light-cyan, light-red, light-magenta, yellow and white."
+ " But only the first eight names can be used for BG. You can prefix"
+ " \"blink-\" to FG if you want a blinking foreground color."
+};
+
+
+/* configfile */
+static int
+configfile_func (char *arg, int flags)
+{
+ char *new_config = config_file;
+
+ /* Check if the file ARG is present. */
+ if (! grub_open (arg))
+ return 1;
+
+ grub_close ();
+
+ /* Copy ARG to CONFIG_FILE. */
+ while ((*new_config++ = *arg++) != 0)
+ ;
+
+#ifdef GRUB_UTIL
+ /* Force to load the configuration file. */
+ use_config_file = 1;
+#endif
+
+ /* Make sure that the user will not be authoritative. */
+ auth = 0;
+
+ /* Restart cmain. */
+ grub_longjmp (restart_env, 0);
+
+ /* Never reach here. */
+ return 0;
+}
+
+static struct builtin builtin_configfile =
+{
+ "configfile",
+ configfile_func,
+ BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
+ "configfile FILE",
+ "Load FILE as the configuration file."
+};
+
+
+/* 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)
+{
+#ifndef SUPPORT_DISKLESS
+ if (grub_strcmp (arg, "saved") == 0)
+ {
+ default_entry = saved_entryno;
+ return 0;
+ }
+#endif /* SUPPORT_DISKLESS */
+
+ 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 | `saved']",
+ "Set the default entry to entry number NUM (if not specified, it is"
+ " 0, the first entry) or the entry number saved by savedefault."
+#endif
+};
+
+
+#ifdef GRUB_UTIL
+/* device */
+static int
+device_func (char *arg, int flags)
+{
+ char *drive = arg;
+ char *device;
+
+ /* Get the drive number from DRIVE. */
+ if (! set_device (drive))
+ return 1;
+
+ /* Get the device argument. */
+ device = skip_to (0, drive);
+
+ /* Terminate DEVICE. */
+ nul_terminate (device);
+
+ if (! *device || ! check_device (device))
+ {
+ errnum = ERR_FILE_NOT_FOUND;
+ return 1;
+ }
+
+ assign_device_name (current_drive, device);
+
+ return 0;
+}
+
+static struct builtin builtin_device =
+{
+ "device",
+ device_func,
+ BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
+ "device DRIVE DEVICE",
+ "Specify DEVICE as the actual drive for a BIOS drive DRIVE. This command"
+ " can be used only in the grub shell."
+};
+#endif /* GRUB_UTIL */
+
+
+#ifdef SUPPORT_NETBOOT
+/* dhcp */
+static int
+dhcp_func (char *arg, int flags)
+{
+ /* For now, this is an alias for bootp. */
+ return bootp_func (arg, flags);
+}
+
+static struct builtin builtin_dhcp =
+{
+ "dhcp",
+ dhcp_func,
+ BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
+ "dhcp",
+ "Initialize a network device via DHCP."
+};
+#endif /* SUPPORT_NETBOOT */
+
+
+/* displayapm */
+static int
+displayapm_func (char *arg, int flags)
+{
+ if (mbi.flags & MB_INFO_APM_TABLE)
+ {
+ grub_printf ("APM BIOS information:\n"
+ " Version: 0x%x\n"
+ " 32-bit CS: 0x%x\n"
+ " Offset: 0x%x\n"
+ " 16-bit CS: 0x%x\n"
+ " 16-bit DS: 0x%x\n"
+ " 32-bit CS length: 0x%x\n"
+ " 16-bit CS length: 0x%x\n"
+ " 16-bit DS length: 0x%x\n",
+ (unsigned) apm_bios_info.version,
+ (unsigned) apm_bios_info.cseg,
+ apm_bios_info.offset,
+ (unsigned) apm_bios_info.cseg_16,
+ (unsigned) apm_bios_info.dseg_16,
+ (unsigned) apm_bios_info.cseg_len,
+ (unsigned) apm_bios_info.cseg_16_len,
+ (unsigned) apm_bios_info.dseg_16_len);
+ }
+ else
+ {
+ grub_printf ("No APM BIOS found or probe failed\n");
+ }
+
+ return 0;
+}
+
+static struct builtin builtin_displayapm =
+{
+ "displayapm",
+ displayapm_func,
+ BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
+ "displayapm",
+ "Display APM BIOS information."
+};
+
+
+/* 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: 0x%x X 4GB + 0x%x bytes\n",
+ str,
+ (unsigned long) (map->BaseAddr >> 32),
+ (unsigned long) (map->BaseAddr & 0xFFFFFFFF),
+ (unsigned long) (map->Length >> 32),
+ (unsigned long) (map->Length & 0xFFFFFFFF));
+
+ map = ((struct AddrRangeDesc *) (((int) map) + 4 + map->size));
+ }
+ }
+
+ return 0;
+}
+
+static struct builtin builtin_displaymem =
+{
+ "displaymem",
+ displaymem_func,
+ BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
+ "displaymem",
+ "Display what GRUB thinks the system address space map of the"
+ " machine is, including all regions of physical RAM installed."
+};
+
+
+/* dump FROM TO */
+#ifdef GRUB_UTIL
+static int
+dump_func (char *arg, int flags)
+{
+ char *from, *to;
+ FILE *fp;
+ char c;
+
+ from = arg;
+ to = skip_to (0, arg);
+ if (! *from || ! *to)
+ {
+ errnum = ERR_BAD_ARGUMENT;
+ return 1;
+ }
+
+ nul_terminate (from);
+ nul_terminate (to);
+
+ if (! grub_open (from))
+ return 1;
+
+ fp = fopen (to, "w");
+ if (! fp)
+ {
+ errnum = ERR_WRITE;
+ return 1;
+ }
+
+ while (grub_read (&c, 1))
+ if (fputc (c, fp) == EOF)
+ {
+ errnum = ERR_WRITE;
+ fclose (fp);
+ return 1;
+ }
+
+ if (fclose (fp) == EOF)
+ {
+ errnum = ERR_WRITE;
+ return 1;
+ }
+
+ grub_close ();
+ return 0;
+}
+
+static struct builtin builtin_dump =
+ {
+ "dump",
+ dump_func,
+ BUILTIN_CMDLINE,
+ "dump FROM TO",
+ "Dump the contents of the file FROM to the file TO. FROM must be"
+ " a GRUB file and TO must be an OS file."
+ };
+#endif /* GRUB_UTIL */
+
+
+static char embed_info[32];
+/* embed */
+/* Embed a Stage 1.5 in the first cylinder after MBR or in the
+ bootloader block in a FFS. */
+static int
+embed_func (char *arg, int flags)
+{
+ char *stage1_5;
+ char *device;
+ char *stage1_5_buffer = (char *) RAW_ADDR (0x100000);
+ int len, size;
+ int sector;
+
+ stage1_5 = arg;
+ device = skip_to (0, stage1_5);
+
+ /* Open a Stage 1.5. */
+ if (! grub_open (stage1_5))
+ return 1;
+
+ /* Read the whole of the Stage 1.5. */
+ len = grub_read (stage1_5_buffer, -1);
+ grub_close ();
+
+ if (errnum)
+ return 1;
+
+ size = (len + SECTOR_SIZE - 1) / SECTOR_SIZE;
+
+ /* Get the device where the Stage 1.5 will be embedded. */
+ set_device (device);
+ if (errnum)
+ return 1;
+
+ if (current_partition == 0xFFFFFF)
+ {
+ /* Embed it after the MBR. */
+
+ char mbr[SECTOR_SIZE];
+ char ezbios_check[2*SECTOR_SIZE];
+ int i;
+
+ /* Open the partition. */
+ if (! open_partition ())
+ return 1;
+
+ /* No floppy has MBR. */
+ if (! (current_drive & 0x80))
+ {
+ errnum = ERR_DEV_VALUES;
+ return 1;
+ }
+
+ /* Read the MBR of CURRENT_DRIVE. */
+ if (! rawread (current_drive, PC_MBR_SECTOR, 0, SECTOR_SIZE, mbr))
+ return 1;
+
+ /* Sanity check. */
+ if (! PC_MBR_CHECK_SIG (mbr))
+ {
+ errnum = ERR_BAD_PART_TABLE;
+ return 1;
+ }
+
+ /* Check if the disk can store the Stage 1.5. */
+ for (i = 0; i < 4; i++)
+ if (PC_SLICE_TYPE (mbr, i) && PC_SLICE_START (mbr, i) - 1 < size)
+ {
+ errnum = ERR_NO_DISK_SPACE;
+ return 1;
+ }
+
+ /* Check for EZ-BIOS signature. It should be in the third
+ * sector, but due to remapping it can appear in the second, so
+ * load and check both.
+ */
+ if (! rawread (current_drive, 1, 0, 2 * SECTOR_SIZE, ezbios_check))
+ return 1;
+
+ if (! memcmp (ezbios_check + 3, "AERMH", 5)
+ || ! memcmp (ezbios_check + 512 + 3, "AERMH", 5))
+ {
+ /* The space after the MBR is used by EZ-BIOS which we must
+ * not overwrite.
+ */
+ errnum = ERR_NO_DISK_SPACE;
+ return 1;
+ }
+
+ sector = 1;
+ }
+ else
+ {
+ /* Embed it in the bootloader block in the filesystem. */
+ int start_sector;
+
+ /* Open the partition. */
+ if (! open_device ())
+ return 1;
+
+ /* Check if the current slice supports embedding. */
+ if (fsys_table[fsys_type].embed_func == 0
+ || ! fsys_table[fsys_type].embed_func (&start_sector, size))
+ {
+ errnum = ERR_DEV_VALUES;
+ return 1;
+ }
+
+ sector = part_start + start_sector;
+ }
+
+ /* Clear the cache. */
+ buf_track = -1;
+
+ /* Now perform the embedding. */
+ if (! devwrite (sector - part_start, size, stage1_5_buffer))
+ return 1;
+
+ grub_printf (" %d sectors are embedded.\n", size);
+ grub_sprintf (embed_info, "%d+%d", sector - part_start, size);
+ return 0;
+}
+
+static struct builtin builtin_embed =
+{
+ "embed",
+ embed_func,
+ BUILTIN_CMDLINE,
+ "embed STAGE1_5 DEVICE",
+ "Embed the Stage 1.5 STAGE1_5 in the sectors after MBR if DEVICE"
+ " is a drive, or in the \"bootloader\" area if DEVICE is a FFS partition."
+ " Print the number of sectors which STAGE1_5 occupies if successful."
+};
+
+
+/* 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 won't help if the machine"
+ " was rebooted by a kernel that GRUB loaded."
+#endif
+};
+
+
+/* find */
+/* Search for the filename ARG in all of partitions. */
+static int
+find_func (char *arg, int flags)
+{
+ char *filename = arg;
+ unsigned long drive;
+ unsigned long tmp_drive = saved_drive;
+ unsigned long tmp_partition = saved_partition;
+ int got_file = 0;
+
+ /* Floppies. */
+ for (drive = 0; drive < 8; drive++)
+ {
+ current_drive = drive;
+ current_partition = 0xFFFFFF;
+
+ if (open_device ())
+ {
+ saved_drive = current_drive;
+ saved_partition = current_partition;
+ if (grub_open (filename))
+ {
+ grub_close ();
+ grub_printf (" (fd%d)\n", drive);
+ got_file = 1;
+ }
+ }
+
+ errnum = ERR_NONE;
+ }
+
+ /* Hard disks. */
+ for (drive = 0x80; drive < 0x88; drive++)
+ {
+ unsigned long part = 0xFFFFFF;
+ unsigned long start, len, offset, ext_offset;
+ int type, entry;
+ char buf[SECTOR_SIZE];
+
+ current_drive = drive;
+ while (next_partition (drive, 0xFFFFFF, &part, &type,
+ &start, &len, &offset, &entry,
+ &ext_offset, buf))
+ {
+ if (type != PC_SLICE_TYPE_NONE
+ && ! IS_PC_SLICE_TYPE_BSD (type)
+ && ! IS_PC_SLICE_TYPE_EXTENDED (type))
+ {
+ current_partition = part;
+ if (open_device ())
+ {
+ saved_drive = current_drive;
+ saved_partition = current_partition;
+ if (grub_open (filename))
+ {
+ int bsd_part = (part >> 8) & 0xFF;
+ int pc_slice = part >> 16;
+
+ grub_close ();
+
+ if (bsd_part == 0xFF)
+ grub_printf (" (hd%d,%d)\n",
+ drive - 0x80, pc_slice);
+ else
+ grub_printf (" (hd%d,%d,%c)\n",
+ drive - 0x80, pc_slice, bsd_part + 'a');
+
+ got_file = 1;
+ }
+ }
+ }
+
+ /* We want to ignore any error here. */
+ errnum = ERR_NONE;
+ }
+
+ /* next_partition always sets ERRNUM in the last call, so clear
+ it. */
+ errnum = ERR_NONE;
+ }
+
+ saved_drive = tmp_drive;
+ saved_partition = tmp_partition;
+
+ if (got_file)
+ {
+ errnum = ERR_NONE;
+ return 0;
+ }
+
+ errnum = ERR_FILE_NOT_FOUND;
+ return 1;
+}
+
+static struct builtin builtin_find =
+{
+ "find",
+ find_func,
+ BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
+ "find FILENAME",
+ "Search for the filename FILENAME in all of partitions and print the list of"
+ " the devices which contain the file."
+};
+
+
+/* fstest */
+static int
+fstest_func (char *arg, int flags)
+{
+ if (disk_read_hook)
+ {
+ disk_read_hook = NULL;
+ printf (" Filesystem tracing is now off\n");
+ }
+ else
+ {
+ disk_read_hook = disk_read_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;
+ char *msg;
+ char *device = arg;
+#ifdef GRUB_UTIL
+ char *ptr;
+#endif
+
+ /* Get the device number. */
+ set_device (device);
+ if (errnum)
+ return 1;
+
+ /* Check for the geometry. */
+ if (get_diskinfo (current_drive, &geom))
+ {
+ errnum = ERR_NO_DISK;
+ return 1;
+ }
+
+ /* Attempt to read the first sector, because some BIOSes turns out not
+ to support LBA even though they set the bit 0 in the support
+ bitmap, only after reading something actually. */
+ if (biosdisk (BIOSDISK_READ, current_drive, &geom, 0, 1, SCRATCHSEG))
+ {
+ errnum = ERR_READ;
+ return 1;
+ }
+
+#ifdef GRUB_UTIL
+ ptr = skip_to (0, device);
+ if (*ptr)
+ {
+ char *cylinder, *head, *sector, *total_sector;
+ int num_cylinder, num_head, num_sector, num_total_sector;
+
+ cylinder = ptr;
+ head = skip_to (0, cylinder);
+ sector = skip_to (0, head);
+ total_sector = skip_to (0, sector);
+ if (! safe_parse_maxint (&cylinder, &num_cylinder)
+ || ! safe_parse_maxint (&head, &num_head)
+ || ! safe_parse_maxint (&sector, &num_sector))
+ return 1;
+
+ disks[current_drive].cylinders = num_cylinder;
+ disks[current_drive].heads = num_head;
+ disks[current_drive].sectors = num_sector;
+
+ if (safe_parse_maxint (&total_sector, &num_total_sector))
+ disks[current_drive].total_sectors = num_total_sector;
+ else
+ disks[current_drive].total_sectors
+ = num_cylinder * num_head * num_sector;
+ errnum = 0;
+
+ geom = disks[current_drive];
+ buf_drive = -1;
+ }
+#endif /* GRUB_UTIL */
+
+#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);
+ real_open_partition (1);
+
+ return 0;
+}
+
+static struct builtin builtin_geometry =
+{
+ "geometry",
+ geometry_func,
+ BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
+ "geometry DRIVE [CYLINDER HEAD SECTOR [TOTAL_SECTOR]]",
+ "Print the information for a drive DRIVE. In the grub shell, you can"
+ " set the geometry of the drive arbitrarily. The number of the cylinders,"
+ " the one of the heads, the one of the sectors and the one of the total"
+ " sectors are set to CYLINDER, HEAD, SECTOR and TOTAL_SECTOR,"
+ " respectively. If you omit TOTAL_SECTOR, then it will be calculated based"
+ " on the C/H/S values automatically."
+};
+
+
+/* halt */
+static int
+halt_func (char *arg, int flags)
+{
+ int no_apm;
+
+ no_apm = (grub_memcmp (arg, "--no-apm", 8) == 0);
+ grub_halt (no_apm);
+
+ /* Never reach here. */
+ return 1;
+}
+
+static struct builtin builtin_halt =
+{
+ "halt",
+ halt_func,
+ BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
+ "halt [--no-apm]",
+ "Halt your system. If APM is avaiable on it, turn off the power using"
+ " the APM BIOS, unless you specify the option `--no-apm'."
+};
+
+
+/* help */
+#define MAX_SHORT_DOC_LEN 39
+#define MAX_LONG_DOC_LEN 66
+
+static int
+help_func (char *arg, int flags)
+{
+ int all = 0;
+
+ if (grub_memcmp (arg, "--all", sizeof ("--all") - 1) == 0)
+ {
+ all = 1;
+ arg = skip_to (0, arg);
+ }
+
+ 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 used in the command-line interface,
+ skip this. */
+ if (! ((*builtin)->flags & BUILTIN_CMDLINE))
+ continue;
+
+ /* If this doesn't need to be listed automatically and "--all"
+ is not specified, skip this. */
+ if (! all && ! ((*builtin)->flags & BUILTIN_HELP_LIST))
+ 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;
+ }
+
+ /* If the last entry was at the left column, no newline was printed
+ at the end. */
+ if (! left)
+ grub_putchar ('\n');
+ }
+ else
+ {
+ /* Invoked with one or more patterns. */
+ do
+ {
+ struct builtin **builtin;
+ char *next_arg;
+
+ /* Get the next argument. */
+ next_arg = skip_to (0, arg);
+
+ /* Terminate ARG. */
+ nul_terminate (arg);
+
+ 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 | BUILTIN_HELP_LIST,
+ "help [--all] [PATTERN ...]",
+ "Display helpful information about builtin commands. Not all commands"
+ " aren't shown without the option `--all'."
+};
+
+
+/* hiddenmenu */
+static int
+hiddenmenu_func (char *arg, int flags)
+{
+ show_menu = 0;
+ return 0;
+}
+
+static struct builtin builtin_hiddenmenu =
+{
+ "hiddenmenu",
+ hiddenmenu_func,
+ BUILTIN_MENU,
+#if 0
+ "hiddenmenu",
+ "Hide the menu."
+#endif
+};
+
+
+/* hide */
+static int
+hide_func (char *arg, int flags)
+{
+ if (! set_device (arg))
+ return 1;
+
+ if (! set_partition_hidden_flag (1))
+ return 1;
+
+ return 0;
+}
+
+static struct builtin builtin_hide =
+{
+ "hide",
+ hide_func,
+ BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
+ "hide PARTITION",
+ "Hide PARTITION by setting the \"hidden\" bit in"
+ " its partition type code."
+};
+
+
+#ifdef SUPPORT_NETBOOT
+/* ifconfig */
+static int
+ifconfig_func (char *arg, int flags)
+{
+ char *svr = 0, *ip = 0, *gw = 0, *sm = 0;
+
+ if (! eth_probe ())
+ {
+ grub_printf ("No ethernet card found.\n");
+ errnum = ERR_DEV_VALUES;
+ return 1;
+ }
+
+ while (*arg)
+ {
+ if (! grub_memcmp ("--server=", arg, sizeof ("--server=") - 1))
+ svr = arg + sizeof("--server=") - 1;
+ else if (! grub_memcmp ("--address=", arg, sizeof ("--address=") - 1))
+ ip = arg + sizeof ("--address=") - 1;
+ else if (! grub_memcmp ("--gateway=", arg, sizeof ("--gateway=") - 1))
+ gw = arg + sizeof ("--gateway=") - 1;
+ else if (! grub_memcmp ("--mask=", arg, sizeof("--mask=") - 1))
+ sm = arg + sizeof ("--mask=") - 1;
+ else
+ {
+ errnum = ERR_BAD_ARGUMENT;
+ return 1;
+ }
+
+ arg = skip_to (0, arg);
+ }
+
+ if (! ifconfig (ip, sm, gw, svr))
+ {
+ errnum = ERR_BAD_ARGUMENT;
+ return 1;
+ }
+
+ print_network_configuration ();
+ return 0;
+}
+
+static struct builtin builtin_ifconfig =
+{
+ "ifconfig",
+ ifconfig_func,
+ BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
+ "ifconfig [--address=IP] [--gateway=IP] [--mask=MASK] [--server=IP]",
+ "Configure the IP address, the netmask, the gateway and the server"
+ " address or print current network configuration."
+};
+#endif /* SUPPORT_NETBOOT */
+
+
+/* impsprobe */
+static int
+impsprobe_func (char *arg, int flags)
+{
+#ifdef GRUB_UTIL
+ /* In the grub shell, we cannot probe IMPS. */
+ errnum = ERR_UNRECOGNIZED;
+ return 1;
+#else /* ! GRUB_UTIL */
+ if (!imps_probe ())
+ printf (" No MPS information found or probe failed\n");
+
+ return 0;
+#endif /* ! GRUB_UTIL */
+}
+
+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 | BUILTIN_HELP_LIST,
+ "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 *stage1_buffer = (char *) RAW_ADDR (0x100000);
+ char *stage2_buffer = stage1_buffer + SECTOR_SIZE;
+ char *old_sect = stage2_buffer + SECTOR_SIZE;
+ char *stage2_first_buffer = old_sect + SECTOR_SIZE;
+ char *stage2_second_buffer = stage2_first_buffer + SECTOR_SIZE;
+ /* XXX: Probably SECTOR_SIZE is reasonable. */
+ char *config_filename = stage2_second_buffer + SECTOR_SIZE;
+ char *dummy = config_filename + SECTOR_SIZE;
+ int new_drive = 0xFF;
+ int dest_drive, dest_partition, dest_sector;
+ int src_drive, src_partition, src_part_start;
+ int i;
+ struct geometry dest_geom, src_geom;
+ int saved_sector;
+ int stage2_first_sector, stage2_second_sector;
+ char *ptr;
+ int installaddr, installlist;
+ /* Point to the location of the name of a configuration file in Stage 2. */
+ char *config_file_location;
+ /* If FILE is a Stage 1.5? */
+ int is_stage1_5 = 0;
+ /* Must call grub_close? */
+ int is_open = 0;
+ /* If LBA is forced? */
+ int is_force_lba = 0;
+ /* Was the last sector full? */
+ int last_length = SECTOR_SIZE;
+
+#ifdef GRUB_UTIL
+ /* If the Stage 2 is in a partition mounted by an OS, this will store
+ the filename under the OS. */
+ char *stage2_os_file = 0;
+#endif /* GRUB_UTIL */
+
+ /* Save the first sector of Stage2 in STAGE2_SECT. */
+ static void disk_read_savesect_func (int sector, int offset, int length)
+ {
+ if (debug)
+ printf ("[%d]", sector);
+
+ /* ReiserFS has files which sometimes contain data not aligned
+ on sector boundaries. Returning an error is better than
+ silently failing. */
+ if (offset != 0 || length != SECTOR_SIZE)
+ errnum = ERR_UNALIGNED;
+
+ saved_sector = sector;
+ }
+
+ /* Write SECTOR to INSTALLLIST, and update INSTALLADDR and
+ INSTALLSECT. */
+ static void disk_read_blocklist_func (int sector, int offset, int length)
+ {
+ if (debug)
+ printf("[%d]", sector);
+
+ if (offset != 0 || last_length != SECTOR_SIZE)
+ {
+ /* We found a non-sector-aligned data block. */
+ errnum = ERR_UNALIGNED;
+ return;
+ }
+
+ last_length = length;
+
+ if (*((unsigned long *) (installlist - 4))
+ + *((unsigned short *) installlist) != sector
+ || installlist == (int) stage2_first_buffer + SECTOR_SIZE + 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;
+ installaddr += 512;
+ }
+
+ /* First, check the GNU-style long option. */
+ while (1)
+ {
+ if (grub_memcmp ("--force-lba", arg, sizeof ("--force-lba") - 1) == 0)
+ {
+ is_force_lba = 1;
+ arg = skip_to (0, arg);
+ }
+#ifdef GRUB_UTIL
+ else if (grub_memcmp ("--stage2=", arg, sizeof ("--stage2=") - 1) == 0)
+ {
+ stage2_os_file = arg + sizeof ("--stage2=") - 1;
+ arg = skip_to (0, arg);
+ nul_terminate (stage2_os_file);
+ }
+#endif /* GRUB_UTIL */
+ else
+ break;
+ }
+
+ 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))
+ {
+ /* ADDR is not specified. */
+ installaddr = 0;
+ ptr = addr;
+ errnum = 0;
+ }
+ else
+ ptr = skip_to (0, addr);
+
+#ifndef NO_DECOMPRESSION
+ /* Do not decompress Stage 1 or Stage 2. */
+ no_decompression = 1;
+#endif
+
+ /* Read Stage 1. */
+ is_open = grub_open (stage1_file);
+ if (! is_open
+ || ! grub_read (stage1_buffer, SECTOR_SIZE) == SECTOR_SIZE)
+ goto fail;
+
+ /* Read the old sector from DEST_DEV. */
+ if (! set_device (dest_dev)
+ || ! open_partition ()
+ || ! devread (0, 0, SECTOR_SIZE, old_sect))
+ goto fail;
+
+ /* Store the information for the destination device. */
+ dest_drive = current_drive;
+ dest_partition = current_partition;
+ dest_geom = buf_geom;
+ dest_sector = part_start;
+
+ /* Copy the possible DOS BPB, 59 bytes at byte offset 3. */
+ grub_memmove (stage1_buffer + BOOTSEC_BPB_OFFSET,
+ old_sect + BOOTSEC_BPB_OFFSET,
+ BOOTSEC_BPB_LENGTH);
+
+ /* If for a hard disk, copy the possible MBR/extended part table. */
+ if (dest_drive & 0x80)
+ grub_memmove (stage1_buffer + STAGE1_WINDOWS_NT_MAGIC,
+ old_sect + STAGE1_WINDOWS_NT_MAGIC,
+ STAGE1_PARTEND - STAGE1_WINDOWS_NT_MAGIC);
+
+ /* Check for the version and the signature of Stage 1. */
+ if (*((short *)(stage1_buffer + STAGE1_VER_MAJ_OFFS)) != COMPAT_VERSION
+ || (*((unsigned short *) (stage1_buffer + BOOTSEC_SIG_OFFSET))
+ != BOOTSEC_SIGNATURE))
+ {
+ errnum = ERR_BAD_VERSION;
+ goto fail;
+ }
+
+ /* This below is not true any longer. But should we leave this alone? */
+
+ /* If DEST_DRIVE is a floppy, Stage 2 must have the iteration probe
+ routine. */
+ if (! (dest_drive & 0x80)
+ && (*((unsigned char *) (stage1_buffer + BOOTSEC_PART_OFFSET)) == 0x80
+ || stage1_buffer[BOOTSEC_PART_OFFSET] == 0))
+ {
+ errnum = ERR_BAD_VERSION;
+ goto fail;
+ }
+
+ grub_close ();
+
+ /* Open Stage 2. */
+ is_open = grub_open (file);
+ if (! is_open)
+ goto fail;
+
+ src_drive = current_drive;
+ src_partition = current_partition;
+ src_part_start = part_start;
+ src_geom = buf_geom;
+
+ if (! new_drive)
+ new_drive = src_drive;
+ else if (src_drive != dest_drive)
+ grub_printf ("Warning: the option `d' was not used, but the Stage 1 will"
+ " be installed on a\ndifferent drive than the drive where"
+ " the Stage 2 resides.\n");
+
+ /* Set the boot drive. */
+ *((unsigned char *) (stage1_buffer + STAGE1_BOOT_DRIVE)) = new_drive;
+
+ /* Set the "force LBA" flag. */
+ *((unsigned char *) (stage1_buffer + STAGE1_FORCE_LBA)) = is_force_lba;
+
+ /* Set the boot drive mask. This is a workaround for buggy BIOSes which
+ don't pass boot drive correctly. Instead, they pass 0x00 even when
+ booted from 0x80. */
+ *((unsigned char *) (stage1_buffer + STAGE1_BOOT_DRIVE_MASK))
+ = (dest_drive & BIOS_FLAG_FIXED_DISK);
+
+ /* Read the first sector of Stage 2. */
+ disk_read_hook = disk_read_savesect_func;
+ if (grub_read (stage2_first_buffer, SECTOR_SIZE) != SECTOR_SIZE)
+ goto fail;
+
+ stage2_first_sector = saved_sector;
+
+ /* Read the second sector of Stage 2. */
+ if (grub_read (stage2_second_buffer, SECTOR_SIZE) != SECTOR_SIZE)
+ goto fail;
+
+ stage2_second_sector = saved_sector;
+
+ /* Check for the version of Stage 2. */
+ if (*((short *) (stage2_second_buffer + STAGE2_VER_MAJ_OFFS))
+ != COMPAT_VERSION)
+ {
+ errnum = ERR_BAD_VERSION;
+ goto fail;
+ }
+
+ /* Check for the Stage 2 id. */
+ if (stage2_second_buffer[STAGE2_STAGE2_ID] != STAGE2_ID_STAGE2)
+ is_stage1_5 = 1;
+
+ /* If INSTALLADDR is not specified explicitly in the command-line,
+ determine it by the Stage 2 id. */
+ if (! installaddr)
+ {
+ if (! is_stage1_5)
+ /* Stage 2. */
+ installaddr = 0x8000;
+ else
+ /* Stage 1.5. */
+ installaddr = 0x2000;
+ }
+
+ *((unsigned long *) (stage1_buffer + STAGE1_STAGE2_SECTOR))
+ = stage2_first_sector;
+ *((unsigned short *) (stage1_buffer + STAGE1_STAGE2_ADDRESS))
+ = installaddr;
+ *((unsigned short *) (stage1_buffer + STAGE1_STAGE2_SEGMENT))
+ = installaddr >> 4;
+
+ i = (int) stage2_first_buffer + SECTOR_SIZE - 4;
+ while (*((unsigned long *) i))
+ {
+ if (i < (int) stage2_first_buffer
+ || (*((int *) (i - 4)) & 0x80000000)
+ || *((unsigned short *) i) >= 0xA00
+ || *((short *) (i + 2)) == 0)
+ {
+ errnum = ERR_BAD_VERSION;
+ goto fail;
+ }
+
+ *((int *) i) = 0;
+ *((int *) (i - 4)) = 0;
+ i -= 8;
+ }
+
+ installlist = (int) stage2_first_buffer + SECTOR_SIZE + 4;
+ installaddr += SECTOR_SIZE;
+
+ /* Read the whole of Stage2 except for the first sector. */
+ grub_seek (SECTOR_SIZE);
+
+ disk_read_hook = disk_read_blocklist_func;
+ if (! grub_read (dummy, -1))
+ goto fail;
+
+ disk_read_hook = 0;
+
+ /* Find a string for the configuration filename. */
+ config_file_location = stage2_second_buffer + STAGE2_VER_STR_OFFS;
+ while (*(config_file_location++))
+ ;
+
+ /* Set the "force LBA" flag for Stage2. */
+ *((unsigned char *) (stage2_second_buffer + STAGE2_FORCE_LBA))
+ = is_force_lba;
+
+ if (*ptr == 'p')
+ {
+ *((long *) (stage2_second_buffer + STAGE2_INSTALLPART))
+ = src_partition;
+ if (is_stage1_5)
+ {
+ /* Reset the device information in FILE if it is a Stage 1.5. */
+ unsigned long device = 0xFFFFFFFF;
+
+ grub_memmove (config_file_location, (char *) &device,
+ sizeof (device));
+ }
+
+ ptr = skip_to (0, ptr);
+ }
+
+ if (*ptr)
+ {
+ grub_strcpy (config_filename, ptr);
+ nul_terminate (config_filename);
+
+ if (! is_stage1_5)
+ /* If it is a Stage 2, just copy PTR to CONFIG_FILE_LOCATION. */
+ grub_strcpy (config_file_location, ptr);
+ else
+ {
+ char *real_config;
+ unsigned long device;
+
+ /* Translate the external device syntax to the internal device
+ syntax. */
+ if (! (real_config = set_device (ptr)))
+ {
+ /* The Stage 2 PTR does not contain the device name, so
+ use the root device instead. */
+ errnum = ERR_NONE;
+ current_drive = saved_drive;
+ current_partition = saved_partition;
+ real_config = ptr;
+ }
+
+ if (current_drive == src_drive)
+ {
+ /* If the drive where the Stage 2 resides is the same as
+ the one where the Stage 1.5 resides, do not embed the
+ drive number. */
+ current_drive = 0xFF;
+ }
+
+ device = (current_drive << 24) | current_partition;
+ grub_memmove (config_file_location, (char *) &device,
+ sizeof (device));
+ grub_strcpy (config_file_location + sizeof (device),
+ real_config);
+ }
+
+ /* If a Stage 1.5 is used, then we need to modify the Stage2. */
+ if (is_stage1_5)
+ {
+ char *real_config_filename = skip_to (0, ptr);
+
+ is_open = grub_open (config_filename);
+ if (! is_open)
+ goto fail;
+
+ /* Skip the first sector. */
+ grub_seek (SECTOR_SIZE);
+
+ disk_read_hook = disk_read_savesect_func;
+ if (grub_read (stage2_buffer, SECTOR_SIZE) != SECTOR_SIZE)
+ goto fail;
+
+ disk_read_hook = 0;
+ grub_close ();
+ is_open = 0;
+
+ /* Sanity check. */
+ if (*(stage2_buffer + STAGE2_STAGE2_ID) != STAGE2_ID_STAGE2)
+ {
+ errnum = ERR_BAD_VERSION;
+ goto fail;
+ }
+
+ /* Set the "force LBA" flag for Stage2. */
+ *(stage2_buffer + STAGE2_FORCE_LBA) = is_force_lba;
+
+ /* If REAL_CONFIG_FILENAME is specified, copy it to the Stage2. */
+ if (*real_config_filename)
+ {
+ /* Specified */
+ char *location;
+
+ /* Find a string for the configuration filename. */
+ location = stage2_buffer + STAGE2_VER_STR_OFFS;
+ while (*(location++))
+ ;
+
+ /* Copy the name. */
+ grub_strcpy (location, real_config_filename);
+ }
+
+ /* Write it to the disk. */
+ buf_track = -1;
+
+#ifdef GRUB_UTIL
+ /* In the grub shell, access the Stage 2 via the OS filesystem
+ service, if possible. */
+ if (stage2_os_file)
+ {
+ FILE *fp;
+
+ fp = fopen (stage2_os_file, "r+");
+ if (! fp)
+ {
+ errnum = ERR_FILE_NOT_FOUND;
+ goto fail;
+ }
+
+ if (fseek (fp, SECTOR_SIZE, SEEK_SET) != 0)
+ {
+ fclose (fp);
+ errnum = ERR_BAD_VERSION;
+ goto fail;
+ }
+
+ if (fwrite (stage2_buffer, 1, SECTOR_SIZE, fp)
+ != SECTOR_SIZE)
+ {
+ fclose (fp);
+ errnum = ERR_WRITE;
+ goto fail;
+ }
+
+ fclose (fp);
+ }
+ else
+#endif /* GRUB_UTIL */
+ {
+ if (! devwrite (saved_sector - part_start, 1, stage2_buffer))
+ goto fail;
+ }
+ }
+ }
+
+ /* Clear the cache. */
+ buf_track = -1;
+
+ /* Write the modified sectors of Stage2 to the disk. */
+#ifdef GRUB_UTIL
+ if (! is_stage1_5 && stage2_os_file)
+ {
+ FILE *fp;
+
+ fp = fopen (stage2_os_file, "r+");
+ if (! fp)
+ {
+ errnum = ERR_FILE_NOT_FOUND;
+ goto fail;
+ }
+
+ if (fwrite (stage2_first_buffer, 1, SECTOR_SIZE, fp) != SECTOR_SIZE)
+ {
+ fclose (fp);
+ errnum = ERR_WRITE;
+ goto fail;
+ }
+
+ if (fwrite (stage2_second_buffer, 1, SECTOR_SIZE, fp) != SECTOR_SIZE)
+ {
+ fclose (fp);
+ errnum = ERR_WRITE;
+ goto fail;
+ }
+
+ fclose (fp);
+ }
+ else
+#endif /* GRUB_UTIL */
+ {
+ /* The first. */
+ current_drive = src_drive;
+ current_partition = src_partition;
+
+ if (! open_partition ())
+ goto fail;
+
+ if (! devwrite (stage2_first_sector - src_part_start, 1,
+ stage2_first_buffer))
+ goto fail;
+
+ if (! devwrite (stage2_second_sector - src_part_start, 1,
+ stage2_second_buffer))
+ goto fail;
+ }
+
+ /* Write the modified sector of Stage 1 to the disk. */
+ current_drive = dest_drive;
+ current_partition = dest_partition;
+ if (! open_partition ())
+ goto fail;
+
+ devwrite (0, 1, stage1_buffer);
+
+ fail:
+ if (is_open)
+ grub_close ();
+
+ disk_read_hook = 0;
+
+#ifndef NO_DECOMPRESSION
+ no_decompression = 0;
+#endif
+
+ return errnum;
+}
+
+static struct builtin builtin_install =
+{
+ "install",
+ install_func,
+ BUILTIN_CMDLINE,
+ "install [--stage2=STAGE2_FILE] [--force-lba] STAGE1 [d] DEVICE STAGE2 [ADDR] [p] [CONFIG_FILE] [REAL_CONFIG_FILE]",
+ "Install STAGE1 on 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 disk where STAGE2 was installed, rather than using"
+ " the booting drive. The Stage 2 will be loaded at address ADDR, which"
+ " will be determined automatically if you don't specify it. If"
+ " the option `p' or CONFIG_FILE is present, then the first block"
+ " of Stage 2 is patched with new values of the partition and name"
+ " of the configuration file used by the true Stage 2 (for a Stage 1.5,"
+ " this is the name of the true Stage 2) at boot time. If STAGE2 is a Stage"
+ " 1.5 and REAL_CONFIG_FILE is present, then the Stage 2 CONFIG_FILE is"
+ " patched with the configuration filename REAL_CONFIG_FILE."
+ " If the option `--force-lba' is specified, disable some sanity checks"
+ " for LBA mode. If the option `--stage2' is specified, rewrite the Stage"
+ " 2 via your OS's filesystem instead of the raw device."
+};
+
+
+/* ioprobe */
+static int
+ioprobe_func (char *arg, int flags)
+{
+#ifdef GRUB_UTIL
+
+ errnum = ERR_UNRECOGNIZED;
+ return 1;
+
+#else /* ! GRUB_UTIL */
+
+ unsigned short *port;
+
+ /* Get the drive number. */
+ set_device (arg);
+ if (errnum)
+ return 1;
+
+ /* Clean out IO_MAP. */
+ grub_memset ((char *) io_map, 0, IO_MAP_SIZE * sizeof (unsigned short));
+
+ /* Track the int13 handler. */
+ track_int13 (current_drive);
+
+ /* Print out the result. */
+ for (port = io_map; *port != 0; port++)
+ grub_printf (" 0x%x", (unsigned int) *port);
+
+ return 0;
+
+#endif /* ! GRUB_UTIL */
+}
+
+static struct builtin builtin_ioprobe =
+{
+ "ioprobe",
+ ioprobe_func,
+ BUILTIN_CMDLINE,
+ "ioprobe DRIVE",
+ "Probe I/O ports used for the drive DRIVE."
+};
+
+
+/* kernel */
+static int
+kernel_func (char *arg, int flags)
+{
+ int len;
+ kernel_t suggested_type = KERNEL_TYPE_NONE;
+ unsigned long load_flags = 0;
+
+#ifndef AUTO_LINUX_MEM_OPT
+ load_flags |= KERNEL_LOAD_NO_MEM_OPTION;
+#endif
+
+ /* Deal with GNU-style long options. */
+ while (1)
+ {
+ /* If the option `--type=TYPE' is specified, convert the string to
+ a kernel type. */
+ if (grub_memcmp (arg, "--type=", 7) == 0)
+ {
+ arg += 7;
+
+ if (grub_memcmp (arg, "netbsd", 6) == 0)
+ suggested_type = KERNEL_TYPE_NETBSD;
+ else if (grub_memcmp (arg, "freebsd", 7) == 0)
+ suggested_type = KERNEL_TYPE_FREEBSD;
+ else if (grub_memcmp (arg, "openbsd", 7) == 0)
+ /* XXX: For now, OpenBSD is identical to NetBSD, from GRUB's
+ point of view. */
+ suggested_type = KERNEL_TYPE_NETBSD;
+ else if (grub_memcmp (arg, "linux", 5) == 0)
+ suggested_type = KERNEL_TYPE_LINUX;
+ else if (grub_memcmp (arg, "biglinux", 8) == 0)
+ suggested_type = KERNEL_TYPE_BIG_LINUX;
+ else if (grub_memcmp (arg, "multiboot", 9) == 0)
+ suggested_type = KERNEL_TYPE_MULTIBOOT;
+ else
+ {
+ errnum = ERR_BAD_ARGUMENT;
+ return 1;
+ }
+ }
+ /* If the `--no-mem-option' is specified, don't pass a Linux's mem
+ option automatically. If the kernel is another type, this flag
+ has no effect. */
+ else if (grub_memcmp (arg, "--no-mem-option", 15) == 0)
+ load_flags |= KERNEL_LOAD_NO_MEM_OPTION;
+ else
+ break;
+
+ /* Try the next. */
+ arg = skip_to (0, arg);
+ }
+
+ 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, suggested_type, load_flags);
+ if (kernel_type == KERNEL_TYPE_NONE)
+ return 1;
+
+ mb_cmdline += len + 1;
+ return 0;
+}
+
+static struct builtin builtin_kernel =
+{
+ "kernel",
+ kernel_func,
+ BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
+ "kernel [--no-mem-option] [--type=TYPE] FILE [ARG ...]",
+ "Attempt to load the primary boot image from FILE. The rest of the"
+ " line is passed verbatim as the \"kernel command line\". Any modules"
+ " must be reloaded after using this command. The option --type is used"
+ " to suggest what type of kernel to be loaded. TYPE must be either of"
+ " \"netbsd\", \"freebsd\", \"openbsd\", \"linux\", \"biglinux\" and"
+ " \"multiboot\". The option --no-mem-option tells GRUB not to pass a"
+ " Linux's mem option automatically."
+};
+
+
+/* lock */
+static int
+lock_func (char *arg, int flags)
+{
+ if (! auth && password)
+ {
+ errnum = ERR_PRIVILEGED;
+ return 1;
+ }
+
+ return 0;
+}
+
+static struct builtin builtin_lock =
+{
+ "lock",
+ lock_func,
+ BUILTIN_CMDLINE,
+ "lock",
+ "Break a command execution unless the user is authenticated."
+};
+
+
+/* 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 | BUILTIN_HELP_LIST,
+ "makeactive",
+ "Set the active partition on the root disk to GRUB's root device."
+ " This command is limited to _primary_ PC partitions on a hard disk."
+};
+
+
+/* map */
+/* Map FROM_DRIVE to TO_DRIVE. */
+static int
+map_func (char *arg, int flags)
+{
+ char *to_drive;
+ char *from_drive;
+ unsigned long to, from;
+ int i;
+
+ to_drive = arg;
+ from_drive = skip_to (0, arg);
+
+ /* Get the drive number for TO_DRIVE. */
+ set_device (to_drive);
+ if (errnum)
+ return 1;
+ to = current_drive;
+
+ /* Get the drive number for FROM_DRIVE. */
+ set_device (from_drive);
+ if (errnum)
+ return 1;
+ from = current_drive;
+
+ /* Search for an empty slot in BIOS_DRIVE_MAP. */
+ for (i = 0; i < DRIVE_MAP_SIZE; i++)
+ {
+ /* Perhaps the user wants to override the map. */
+ if ((bios_drive_map[i] & 0xff) == from)
+ break;
+
+ if (! bios_drive_map[i])
+ break;
+ }
+
+ if (i == DRIVE_MAP_SIZE)
+ {
+ errnum = ERR_WONT_FIT;
+ return 1;
+ }
+
+ if (to == from)
+ /* If TO is equal to FROM, delete the entry. */
+ grub_memmove ((char *) &bios_drive_map[i], (char *) &bios_drive_map[i + 1],
+ sizeof (unsigned short) * (DRIVE_MAP_SIZE - i));
+ else
+ bios_drive_map[i] = from | (to << 8);
+
+ return 0;
+}
+
+static struct builtin builtin_map =
+{
+ "map",
+ map_func,
+ BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
+ "map TO_DRIVE FROM_DRIVE",
+ "Map the drive FROM_DRIVE to the drive TO_DRIVE. This is necessary"
+ " when you chain-load some operating systems, such as DOS, if such an"
+ " OS resides at a non-first drive."
+};
+
+
+#ifdef USE_MD5_PASSWORDS
+/* md5crypt */
+static int
+md5crypt_func (char *arg, int flags)
+{
+ char crypted[36];
+ char key[32];
+ unsigned int seed;
+ int i;
+ const char *const seedchars =
+ "./0123456789ABCDEFGHIJKLMNOPQRST"
+ "UVWXYZabcdefghijklmnopqrstuvwxyz";
+
+ /* First create a salt. */
+
+ /* The magical prefix. */
+ grub_memset (crypted, 0, sizeof (crypted));
+ grub_memmove (crypted, "$1$", 3);
+
+ /* Create the length of a salt. */
+ seed = currticks ();
+
+ /* Generate a salt. */
+ for (i = 0; i < 8 && seed; i++)
+ {
+ /* FIXME: This should be more random. */
+ crypted[3 + i] = seedchars[seed & 0x3f];
+ seed >>= 6;
+ }
+
+ /* A salt must be terminated with `$', if it is less than 8 chars. */
+ crypted[3 + i] = '$';
+
+#ifdef DEBUG_MD5CRYPT
+ grub_printf ("salt = %s\n", crypted);
+#endif
+
+ /* Get a password. */
+ grub_memset (key, 0, sizeof (key));
+ get_cmdline ("Password: ", key, sizeof (key) - 1, '*', 0);
+
+ /* Crypt the key. */
+ make_md5_password (key, crypted);
+
+ grub_printf ("Encrypted: %s\n", crypted);
+ return 0;
+}
+
+static struct builtin builtin_md5crypt =
+{
+ "md5crypt",
+ md5crypt_func,
+ BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
+ "md5crypt",
+ "Generate a password in MD5 format."
+};
+#endif /* USE_MD5_PASSWORDS */
+
+
+/* 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 | BUILTIN_HELP_LIST,
+ "module FILE [ARG ...]",
+ "Load a boot module FILE for a Multiboot format boot image (no"
+ " interpretation of the file contents is made, so users of this"
+ " command must know what the kernel in question expects). The"
+ " rest of the line is passed as the \"module command line\", like"
+ " 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 | BUILTIN_HELP_LIST,
+ "modulenounzip FILE [ARG ...]",
+ "The same as `module', except that automatic decompression is"
+ " disabled."
+};
+
+
+/* pager [on|off] */
+static int
+pager_func (char *arg, int flags)
+{
+ /* If ARG is empty, toggle the flag. */
+ if (! *arg)
+ use_pager = ! use_pager;
+ else if (grub_memcmp (arg, "on", 2) == 0)
+ use_pager = 1;
+ else if (grub_memcmp (arg, "off", 3) == 0)
+ use_pager = 0;
+ else
+ {
+ errnum = ERR_BAD_ARGUMENT;
+ return 1;
+ }
+
+ grub_printf (" Internal pager is now %s\n", use_pager ? "on" : "off");
+ return 0;
+}
+
+static struct builtin builtin_pager =
+{
+ "pager",
+ pager_func,
+ BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
+ "pager [FLAG]",
+ "Toggle pager mode with no argument. If FLAG is given and its value"
+ " is `on', turn on the mode. If FLAG is `off', turn off the mode."
+};
+
+
+/* partnew PART TYPE START LEN */
+static int
+partnew_func (char *arg, int flags)
+{
+ int new_type, new_start, new_len;
+ int start_cl, start_ch, start_dh;
+ int end_cl, end_ch, end_dh;
+ int entry;
+ char mbr[512];
+
+ /* Convert a LBA address to a CHS address in the INT 13 format. */
+ auto void lba_to_chs (int lba, int *cl, int *ch, int *dh);
+ void lba_to_chs (int lba, int *cl, int *ch, int *dh)
+ {
+ int cylinder, head, sector;
+
+ sector = lba % buf_geom.sectors + 1;
+ head = (lba / buf_geom.sectors) % buf_geom.heads;
+ cylinder = lba / (buf_geom.sectors * buf_geom.heads);
+
+ if (cylinder >= buf_geom.cylinders)
+ cylinder = buf_geom.cylinders - 1;
+
+ *cl = sector | ((cylinder & 0x300) >> 2);
+ *ch = cylinder & 0xFF;
+ *dh = head;
+ }
+
+ /* Get the drive and the partition. */
+ if (! set_device (arg))
+ return 1;
+
+ /* The drive must be a hard disk. */
+ if (! (current_drive & 0x80))
+ {
+ errnum = ERR_BAD_ARGUMENT;
+ return 1;
+ }
+
+ /* The partition must a primary partition. */
+ if ((current_partition >> 16) > 3
+ || (current_partition & 0xFFFF) != 0xFFFF)
+ {
+ errnum = ERR_BAD_ARGUMENT;
+ return 1;
+ }
+
+ entry = current_partition >> 16;
+
+ /* Get the new partition type. */
+ arg = skip_to (0, arg);
+ if (! safe_parse_maxint (&arg, &new_type))
+ return 1;
+
+ /* The partition type is unsigned char. */
+ if (new_type > 0xFF)
+ {
+ errnum = ERR_BAD_ARGUMENT;
+ return 1;
+ }
+
+ /* Get the new partition start. */
+ arg = skip_to (0, arg);
+ if (! safe_parse_maxint (&arg, &new_start))
+ return 1;
+
+ /* Get the new partition length. */
+ arg = skip_to (0, arg);
+ if (! safe_parse_maxint (&arg, &new_len))
+ return 1;
+
+ /* Read the MBR. */
+ if (! rawread (current_drive, 0, 0, SECTOR_SIZE, mbr))
+ return 1;
+
+ /* Check if the new partition will fit in the disk. */
+ if (new_start + new_len > buf_geom.total_sectors)
+ {
+ errnum = ERR_GEOM;
+ return 1;
+ }
+
+ /* Store the partition information in the MBR. */
+ lba_to_chs (new_start, &start_cl, &start_ch, &start_dh);
+ lba_to_chs (new_start + new_len - 1, &end_cl, &end_ch, &end_dh);
+
+ PC_SLICE_FLAG (mbr, entry) = 0;
+ PC_SLICE_HEAD (mbr, entry) = start_dh;
+ PC_SLICE_SEC (mbr, entry) = start_cl;
+ PC_SLICE_CYL (mbr, entry) = start_ch;
+ PC_SLICE_TYPE (mbr, entry) = new_type;
+ PC_SLICE_EHEAD (mbr, entry) = end_dh;
+ PC_SLICE_ESEC (mbr, entry) = end_cl;
+ PC_SLICE_ECYL (mbr, entry) = end_ch;
+ PC_SLICE_START (mbr, entry) = new_start;
+ PC_SLICE_LENGTH (mbr, entry) = new_len;
+
+ /* Make sure that the MBR has a valid signature. */
+ PC_MBR_SIG (mbr) = PC_MBR_SIGNATURE;
+
+ /* Write back the MBR to the disk. */
+ buf_track = -1;
+ if (! rawwrite (current_drive, 0, mbr))
+ return 1;
+
+ return 0;
+}
+
+static struct builtin builtin_partnew =
+{
+ "partnew",
+ partnew_func,
+ BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
+ "partnew PART TYPE START LEN",
+ "Create a primary partition at the starting address START with the"
+ " length LEN, with the type TYPE. START and LEN are in sector units."
+};
+
+
+/* parttype PART TYPE */
+static int
+parttype_func (char *arg, int flags)
+{
+ int new_type;
+ unsigned long part = 0xFFFFFF;
+ unsigned long start, len, offset, ext_offset;
+ int entry, type;
+ char mbr[512];
+
+ /* Get the drive and the partition. */
+ if (! set_device (arg))
+ return 1;
+
+ /* The drive must be a hard disk. */
+ if (! (current_drive & 0x80))
+ {
+ errnum = ERR_BAD_ARGUMENT;
+ return 1;
+ }
+
+ /* The partition must be a PC slice. */
+ if ((current_partition >> 16) == 0xFF
+ || (current_partition & 0xFFFF) != 0xFFFF)
+ {
+ errnum = ERR_BAD_ARGUMENT;
+ return 1;
+ }
+
+ /* Get the new partition type. */
+ arg = skip_to (0, arg);
+ if (! safe_parse_maxint (&arg, &new_type))
+ return 1;
+
+ /* The partition type is unsigned char. */
+ if (new_type > 0xFF)
+ {
+ errnum = ERR_BAD_ARGUMENT;
+ return 1;
+ }
+
+ /* Look for the partition. */
+ while (next_partition (current_drive, 0xFFFFFF, &part, &type,
+ &start, &len, &offset, &entry,
+ &ext_offset, mbr))
+ {
+ if (part == current_partition)
+ {
+ /* Found. */
+
+ /* Set the type to NEW_TYPE. */
+ PC_SLICE_TYPE (mbr, entry) = new_type;
+
+ /* Write back the MBR to the disk. */
+ buf_track = -1;
+ if (! rawwrite (current_drive, offset, mbr))
+ return 1;
+
+ /* Succeed. */
+ return 0;
+ }
+ }
+
+ /* The partition was not found. ERRNUM was set by next_partition. */
+ return 1;
+}
+
+static struct builtin builtin_parttype =
+{
+ "parttype",
+ parttype_func,
+ BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
+ "parttype PART TYPE",
+ "Change the type of the partition PART to TYPE."
+};
+
+
+/* password */
+static int
+password_func (char *arg, int flags)
+{
+ int len;
+ password_t type = PASSWORD_PLAIN;
+
+#ifdef USE_MD5_PASSWORDS
+ if (grub_memcmp (arg, "--md5", 5) == 0)
+ {
+ type = PASSWORD_MD5;
+ arg = skip_to (0, arg);
+ }
+#endif
+ if (grub_memcmp (arg, "--", 2) == 0)
+ {
+ type = PASSWORD_UNSUPPORTED;
+ arg = skip_to (0, arg);
+ }
+
+ if ((flags & (BUILTIN_CMDLINE | BUILTIN_SCRIPT)) != 0)
+ {
+ /* Do password check! */
+ char entered[32];
+
+ /* Wipe out any previously entered password */
+ entered[0] = 0;
+ get_cmdline ("Password: ", entered, 31, '*', 0);
+
+ nul_terminate (arg);
+ if (check_password (entered, arg, type) != 0)
+ {
+ errnum = ERR_PRIVILEGED;
+ return 1;
+ }
+ }
+ else
+ {
+ len = grub_strlen (arg);
+
+ /* PASSWORD NUL NUL ... */
+ if (len + 2 > PASSWORD_BUFLEN)
+ {
+ errnum = ERR_WONT_FIT;
+ return 1;
+ }
+
+ /* Copy the password and clear the rest of the buffer. */
+ password = (char *) PASSWORD_BUF;
+ grub_memmove (password, arg, len);
+ grub_memset (password + len, 0, PASSWORD_BUFLEN - len);
+ password_type = type;
+ }
+ return 0;
+}
+
+static struct builtin builtin_password =
+{
+ "password",
+ password_func,
+ BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_NO_ECHO,
+ "password [--md5] PASSWD [FILE]",
+ "If used in the first section of a menu 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. If you"
+ " omit the argument FILE, then GRUB just unlocks privileged"
+ " instructions. You can also use it in the script section, in"
+ " which case it will ask for the password, before continueing."
+ " The option --md5 tells GRUB that PASSWD is encrypted with"
+ " md5crypt."
+};
+
+
+/* pause */
+static int
+pause_func (char *arg, int flags)
+{
+ printf("%s\n", arg);
+
+ /* 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 | BUILTIN_NO_ECHO,
+ "pause [MESSAGE ...]",
+ "Print MESSAGE, then wait until a key is pressed."
+};
+
+
+#ifdef GRUB_UTIL
+/* quit */
+static int
+quit_func (char *arg, int flags)
+{
+ stop ();
+
+ /* Never reach here. */
+ return 0;
+}
+
+static struct builtin builtin_quit =
+{
+ "quit",
+ quit_func,
+ BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
+ "quit",
+ "Exit from the GRUB shell."
+};
+#endif /* GRUB_UTIL */
+
+
+#ifdef SUPPORT_NETBOOT
+/* rarp */
+static int
+rarp_func (char *arg, int flags)
+{
+ if (! rarp ())
+ {
+ if (errnum == ERR_NONE)
+ errnum = ERR_DEV_VALUES;
+
+ return 1;
+ }
+
+ /* Notify the configuration. */
+ print_network_configuration ();
+ return 0;
+}
+
+static struct builtin builtin_rarp =
+{
+ "rarp",
+ rarp_func,
+ BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
+ "rarp",
+ "Initialize a network device via RARP."
+};
+#endif /* SUPPORT_NETBOOT */
+
+
+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 value from memory at address ADDR and"
+ " display it in hex format."
+};
+
+
+/* reboot */
+static int
+reboot_func (char *arg, int flags)
+{
+ grub_reboot ();
+
+ /* Never reach here. */
+ return 1;
+}
+
+static struct builtin builtin_reboot =
+{
+ "reboot",
+ reboot_func,
+ BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
+ "reboot",
+ "Reboot your system."
+};
+
+
+/* Print the root device information. */
+static void
+print_root_device (void)
+{
+ if (saved_drive == NETWORK_DRIVE)
+ {
+ /* Network drive. */
+ grub_printf (" (nd):");
+ }
+ else if (saved_drive & 0x80)
+ {
+ /* Hard disk drive. */
+ grub_printf (" (hd%d", saved_drive - 0x80);
+
+ if ((saved_partition & 0xFF0000) != 0xFF0000)
+ grub_printf (",%d", saved_partition >> 16);
+
+ if ((saved_partition & 0x00FF00) != 0x00FF00)
+ grub_printf (",%c", ((saved_partition >> 8) & 0xFF) + 'a');
+
+ grub_printf ("):");
+ }
+ else
+ {
+ /* Floppy disk drive. */
+ grub_printf (" (fd%d):", saved_drive);
+ }
+
+ /* Print the filesystem information. */
+ current_partition = saved_partition;
+ current_drive = saved_drive;
+ print_fsys_type ();
+}
+
+static int
+real_root_func (char *arg, int attempt_mount)
+{
+ int hdbias = 0;
+ char *biasptr;
+ char *next;
+
+ /* If ARG is empty, just print the current root device. */
+ if (! *arg)
+ {
+ print_root_device ();
+ return 0;
+ }
+
+ /* 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 (attempt_mount)
+ {
+ if (! open_device () && errnum != ERR_FSYS_MOUNT)
+ return 1;
+ }
+ else
+ {
+ /* This is necessary, because the location of a partition table
+ must be set appropriately. */
+ if (open_partition ())
+ {
+ set_bootdev (0);
+ if (errnum)
+ return 1;
+ }
+ }
+
+ /* Clear ERRNUM. */
+ errnum = 0;
+ saved_partition = current_partition;
+ saved_drive = current_drive;
+
+ if (attempt_mount)
+ {
+ /* BSD and chainloading evil hacks !! */
+ biasptr = skip_to (0, next);
+ safe_parse_maxint (&biasptr, &hdbias);
+ errnum = 0;
+ bootdev = set_bootdev (hdbias);
+ if (errnum)
+ return 1;
+
+ /* Print the type of the filesystem. */
+ print_fsys_type ();
+ }
+
+ return 0;
+}
+
+static int
+root_func (char *arg, int flags)
+{
+ return real_root_func (arg, 1);
+}
+
+static struct builtin builtin_root =
+{
+ "root",
+ root_func,
+ BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
+ "root [DEVICE [HDBIAS]]",
+ "Set the current \"root device\" 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 correctly determine "
+ " the PC partition where a BSD sub-partition is located. The"
+ " optional HDBIAS parameter is a number to tell a BSD kernel"
+ " how many BIOS drive numbers are on controllers before the current"
+ " one. For example, if there is an IDE disk and a SCSI disk, and your"
+ " FreeBSD root partition is on the SCSI disk, then use a `1' for HDBIAS."
+};
+
+
+/* rootnoverify */
+static int
+rootnoverify_func (char *arg, int flags)
+{
+ return real_root_func (arg, 0);
+}
+
+static struct builtin builtin_rootnoverify =
+{
+ "rootnoverify",
+ rootnoverify_func,
+ BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
+ "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 device is still"
+ " desired. Note that the items mentioned in `root' which"
+ " derived from attempting the mount will NOT work correctly."
+};
+
+
+/* savedefault */
+static int
+savedefault_func (char *arg, int flags)
+{
+#if !defined(SUPPORT_DISKLESS) && !defined(GRUB_UTIL)
+ char buffer[512];
+ int *entryno_ptr;
+
+ /* This command is only useful when you boot an entry from the menu
+ interface. */
+ if (! (flags & BUILTIN_SCRIPT))
+ {
+ errnum = ERR_UNRECOGNIZED;
+ return 1;
+ }
+
+ /* Get the geometry of the boot drive (i.e. the disk which contains
+ this stage2). */
+ if (get_diskinfo (boot_drive, &buf_geom))
+ {
+ errnum = ERR_NO_DISK;
+ return 1;
+ }
+
+ /* Load the second sector of this stage2. */
+ if (! rawread (boot_drive, install_second_sector, 0, SECTOR_SIZE, buffer))
+ {
+ return 1;
+ }
+
+ /* Sanity check. */
+ if (buffer[STAGE2_STAGE2_ID] != STAGE2_ID_STAGE2
+ || *((short *) (buffer + STAGE2_VER_MAJ_OFFS)) != COMPAT_VERSION)
+ {
+ errnum = ERR_BAD_VERSION;
+ return 1;
+ }
+
+ entryno_ptr = (int *) (buffer + STAGE2_SAVED_ENTRYNO);
+
+ /* Check if the saved entry number differs from current entry number. */
+ if (*entryno_ptr != current_entryno)
+ {
+ /* Overwrite the saved entry number. */
+ *entryno_ptr = current_entryno;
+
+ /* Save the image in the disk. */
+ if (! rawwrite (boot_drive, install_second_sector, buffer))
+ return 1;
+
+ /* Clear the cache. */
+ buf_track = -1;
+ }
+
+ return 0;
+#else /* ! SUPPORT_DISKLESS && ! GRUB_UTIL */
+ errnum = ERR_UNRECOGNIZED;
+ return 1;
+#endif /* ! SUPPORT_DISKLESS && ! GRUB_UTIL */
+}
+
+static struct builtin builtin_savedefault =
+{
+ "savedefault",
+ savedefault_func,
+ BUILTIN_CMDLINE,
+ "savedefault",
+ "Save the current entry as the default boot entry."
+};
+
+
+#ifdef SUPPORT_SERIAL
+/* serial */
+static int
+serial_func (char *arg, int flags)
+{
+ unsigned short port = serial_hw_get_port (0);
+ unsigned int speed = 9600;
+ int word_len = UART_8BITS_WORD;
+ int parity = UART_NO_PARITY;
+ int stop_bit_len = UART_1_STOP_BIT;
+
+ /* Process GNU-style long options.
+ FIXME: We should implement a getopt-like function, to avoid
+ duplications. */
+ while (1)
+ {
+ if (grub_memcmp (arg, "--unit=", sizeof ("--unit=") - 1) == 0)
+ {
+ char *p = arg + sizeof ("--unit=") - 1;
+ int unit;
+
+ if (! safe_parse_maxint (&p, &unit))
+ return 1;
+
+ if (unit < 0 || unit > 3)
+ {
+ errnum = ERR_DEV_VALUES;
+ return 1;
+ }
+
+ port = serial_hw_get_port (unit);
+ }
+ else if (grub_memcmp (arg, "--speed=", sizeof ("--speed=") - 1) == 0)
+ {
+ char *p = arg + sizeof ("--speed=") - 1;
+ int num;
+
+ if (! safe_parse_maxint (&p, &num))
+ return 1;
+
+ speed = (unsigned int) num;
+ }
+ else if (grub_memcmp (arg, "--port=", sizeof ("--port=") - 1) == 0)
+ {
+ char *p = arg + sizeof ("--port=") - 1;
+ int num;
+
+ if (! safe_parse_maxint (&p, &num))
+ return 1;
+
+ port = (unsigned short) num;
+ }
+ else if (grub_memcmp (arg, "--word=", sizeof ("--word=") - 1) == 0)
+ {
+ char *p = arg + sizeof ("--word=") - 1;
+ int len;
+
+ if (! safe_parse_maxint (&p, &len))
+ return 1;
+
+ switch (len)
+ {
+ case 5: word_len = UART_5BITS_WORD; break;
+ case 6: word_len = UART_6BITS_WORD; break;
+ case 7: word_len = UART_7BITS_WORD; break;
+ case 8: word_len = UART_8BITS_WORD; break;
+ default:
+ errnum = ERR_BAD_ARGUMENT;
+ return 1;
+ }
+ }
+ else if (grub_memcmp (arg, "--stop=", sizeof ("--stop=") - 1) == 0)
+ {
+ char *p = arg + sizeof ("--stop=") - 1;
+ int len;
+
+ if (! safe_parse_maxint (&p, &len))
+ return 1;
+
+ switch (len)
+ {
+ case 1: stop_bit_len = UART_1_STOP_BIT; break;
+ case 2: stop_bit_len = UART_2_STOP_BITS; break;
+ default:
+ errnum = ERR_BAD_ARGUMENT;
+ return 1;
+ }
+ }
+ else if (grub_memcmp (arg, "--parity=", sizeof ("--parity=") - 1) == 0)
+ {
+ char *p = arg + sizeof ("--parity=") - 1;
+
+ if (grub_memcmp (p, "no", sizeof ("no") - 1) == 0)
+ parity = UART_NO_PARITY;
+ else if (grub_memcmp (p, "odd", sizeof ("odd") - 1) == 0)
+ parity = UART_ODD_PARITY;
+ else if (grub_memcmp (p, "even", sizeof ("even") - 1) == 0)
+ parity = UART_EVEN_PARITY;
+ else
+ {
+ errnum = ERR_BAD_ARGUMENT;
+ return 1;
+ }
+ }
+# ifdef GRUB_UTIL
+ /* In the grub shell, don't use any port number but open a tty
+ device instead. */
+ else if (grub_memcmp (arg, "--device=", sizeof ("--device=") - 1) == 0)
+ {
+ char *p = arg + sizeof ("--device=") - 1;
+ char dev[256]; /* XXX */
+ char *q = dev;
+
+ while (*p && ! grub_isspace (*p))
+ *q++ = *p++;
+
+ *q = 0;
+ serial_set_device (dev);
+ }
+# endif /* GRUB_UTIL */
+ else
+ break;
+
+ arg = skip_to (0, arg);
+ }
+
+ /* Initialize the serial unit. */
+ if (! serial_hw_init (port, speed, word_len, parity, stop_bit_len))
+ {
+ errnum = ERR_BAD_ARGUMENT;
+ return 1;
+ }
+
+ return 0;
+}
+
+static struct builtin builtin_serial =
+{
+ "serial",
+ serial_func,
+ BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
+ "serial [--unit=UNIT] [--port=PORT] [--speed=SPEED] [--word=WORD] [--parity=PARITY] [--stop=STOP] [--device=DEV]",
+ "Initialize a serial device. UNIT is a digit that specifies which serial"
+ " device is used (e.g. 0 == COM1). If you need to specify the port number,"
+ " set it by --port. SPEED is the DTE-DTE speed. WORD is the word length,"
+ " PARITY is the type of parity, which is one of `no', `odd' and `even'."
+ " STOP is the length of stop bit(s). The option --device can be used only"
+ " in the grub shell, which specifies the file name of a tty device. The"
+ " default values are COM1, 9600, 8N1."
+};
+#endif /* SUPPORT_SERIAL */
+
+
+/* setkey */
+struct keysym
+{
+ char *unshifted_name; /* the name in unshifted state */
+ char *shifted_name; /* the name in shifted state */
+ unsigned char unshifted_ascii; /* the ascii code in unshifted state */
+ unsigned char shifted_ascii; /* the ascii code in shifted state */
+ unsigned char keycode; /* keyboard scancode */
+};
+
+/* The table for key symbols. If the "shifted" member of an entry is
+ NULL, the entry does not have shifted state. */
+static struct keysym keysym_table[] =
+{
+ {"escape", 0, 0x1b, 0, 0x01},
+ {"1", "exclam", '1', '!', 0x02},
+ {"2", "at", '2', '@', 0x03},
+ {"3", "numbersign", '3', '#', 0x04},
+ {"4", "dollar", '4', '$', 0x05},
+ {"5", "percent", '5', '%', 0x06},
+ {"6", "caret", '6', '^', 0x07},
+ {"7", "ampersand", '7', '&', 0x08},
+ {"8", "asterisk", '8', '*', 0x09},
+ {"9", "parenleft", '9', '(', 0x0a},
+ {"0", "parenright", '0', ')', 0x0b},
+ {"minus", "underscore", '-', '_', 0x0c},
+ {"equal", "plus", '=', '+', 0x0d},
+ {"backspace", 0, '\b', 0, 0x0e},
+ {"tab", 0, '\t', 0, 0x0f},
+ {"q", "Q", 'q', 'Q', 0x10},
+ {"w", "W", 'w', 'W', 0x11},
+ {"e", "E", 'e', 'E', 0x12},
+ {"r", "R", 'r', 'R', 0x13},
+ {"t", "T", 't', 'T', 0x14},
+ {"y", "Y", 'y', 'Y', 0x15},
+ {"u", "U", 'u', 'U', 0x16},
+ {"i", "I", 'i', 'I', 0x17},
+ {"o", "O", 'o', 'O', 0x18},
+ {"p", "P", 'p', 'P', 0x19},
+ {"bracketleft", "braceleft", '[', '{', 0x1a},
+ {"bracketright", "braceright", ']', '}', 0x1b},
+ {"enter", 0, '\n', 0, 0x1c},
+ {"control", 0, 0, 0, 0x1d},
+ {"a", "A", 'a', 'A', 0x1e},
+ {"s", "S", 's', 'S', 0x1f},
+ {"d", "D", 'd', 'D', 0x20},
+ {"f", "F", 'f', 'F', 0x21},
+ {"g", "G", 'g', 'G', 0x22},
+ {"h", "H", 'h', 'H', 0x23},
+ {"j", "J", 'j', 'J', 0x24},
+ {"k", "K", 'k', 'K', 0x25},
+ {"l", "L", 'l', 'L', 0x26},
+ {"semicolon", "colon", ';', ':', 0x27},
+ {"quote", "doublequote", '\'', '"', 0x28},
+ {"backquote", "tilde", '`', '~', 0x29},
+ {"shift", 0, 0, 0, 0x2a},
+ {"backslash", "bar", '\\', '|', 0x2b},
+ {"z", "Z", 'z', 'Z', 0x2c},
+ {"x", "X", 'x', 'X', 0x2d},
+ {"c", "C", 'c', 'C', 0x2e},
+ {"v", "V", 'v', 'V', 0x2f},
+ {"b", "B", 'b', 'B', 0x30},
+ {"n", "N", 'n', 'N', 0x31},
+ {"m", "M", 'm', 'M', 0x32},
+ {"comma", "less", ',', '<', 0x33},
+ {"period", "greater", '.', '>', 0x34},
+ {"slash", "question", '/', '?', 0x35},
+ {"alt", 0, 0, 0, 0x38},
+ {"space", 0, ' ', 0, 0x39},
+ {"capslock", 0, 0, 0, 0x3a},
+ {"F1", 0, 0, 0, 0x3b},
+ {"F2", 0, 0, 0, 0x3c},
+ {"F3", 0, 0, 0, 0x3d},
+ {"F4", 0, 0, 0, 0x3e},
+ {"F5", 0, 0, 0, 0x3f},
+ {"F6", 0, 0, 0, 0x40},
+ {"F7", 0, 0, 0, 0x41},
+ {"F8", 0, 0, 0, 0x42},
+ {"F9", 0, 0, 0, 0x43},
+ {"F10", 0, 0, 0, 0x44},
+ /* Caution: do not add NumLock here! we cannot deal with it properly. */
+ {"delete", 0, 0x7f, 0, 0x53}
+};
+
+static int
+setkey_func (char *arg, int flags)
+{
+ char *to_key, *from_key;
+ int to_code, from_code;
+ int map_in_interrupt = 0;
+
+ static int find_key_code (char *key)
+ {
+ int i;
+
+ for (i = 0; i < sizeof (keysym_table) / sizeof (keysym_table[0]); i++)
+ {
+ if (keysym_table[i].unshifted_name &&
+ grub_strcmp (key, keysym_table[i].unshifted_name) == 0)
+ return keysym_table[i].keycode;
+ else if (keysym_table[i].shifted_name &&
+ grub_strcmp (key, keysym_table[i].shifted_name) == 0)
+ return keysym_table[i].keycode;
+ }
+
+ return 0;
+ }
+
+ static int find_ascii_code (char *key)
+ {
+ int i;
+
+ for (i = 0; i < sizeof (keysym_table) / sizeof (keysym_table[0]); i++)
+ {
+ if (keysym_table[i].unshifted_name &&
+ grub_strcmp (key, keysym_table[i].unshifted_name) == 0)
+ return keysym_table[i].unshifted_ascii;
+ else if (keysym_table[i].shifted_name &&
+ grub_strcmp (key, keysym_table[i].shifted_name) == 0)
+ return keysym_table[i].shifted_ascii;
+ }
+
+ return 0;
+ }
+
+ to_key = arg;
+ from_key = skip_to (0, to_key);
+
+ if (! *to_key)
+ {
+ /* If the user specifies no argument, reset the key mappings. */
+ grub_memset (bios_key_map, 0, KEY_MAP_SIZE * sizeof (unsigned short));
+ grub_memset (ascii_key_map, 0, KEY_MAP_SIZE * sizeof (unsigned short));
+
+ return 0;
+ }
+ else if (! *from_key)
+ {
+ /* The user must specify two arguments or zero argument. */
+ errnum = ERR_BAD_ARGUMENT;
+ return 1;
+ }
+
+ nul_terminate (to_key);
+ nul_terminate (from_key);
+
+ to_code = find_ascii_code (to_key);
+ from_code = find_ascii_code (from_key);
+ if (! to_code || ! from_code)
+ {
+ map_in_interrupt = 1;
+ to_code = find_key_code (to_key);
+ from_code = find_key_code (from_key);
+ if (! to_code || ! from_code)
+ {
+ errnum = ERR_BAD_ARGUMENT;
+ return 1;
+ }
+ }
+
+ if (map_in_interrupt)
+ {
+ int i;
+
+ /* Find an empty slot. */
+ for (i = 0; i < KEY_MAP_SIZE; i++)
+ {
+ if ((bios_key_map[i] & 0xff) == from_code)
+ /* Perhaps the user wants to overwrite the map. */
+ break;
+
+ if (! bios_key_map[i])
+ break;
+ }
+
+ if (i == KEY_MAP_SIZE)
+ {
+ errnum = ERR_WONT_FIT;
+ return 1;
+ }
+
+ if (to_code == from_code)
+ /* If TO is equal to FROM, delete the entry. */
+ grub_memmove ((char *) &bios_key_map[i],
+ (char *) &bios_key_map[i + 1],
+ sizeof (unsigned short) * (KEY_MAP_SIZE - i));
+ else
+ bios_key_map[i] = (to_code << 8) | from_code;
+
+ /* Ugly but should work. */
+ unset_int15_handler ();
+ set_int15_handler ();
+ }
+ else
+ {
+ int i;
+
+ /* Find an empty slot. */
+ for (i = 0; i < KEY_MAP_SIZE; i++)
+ {
+ if ((ascii_key_map[i] & 0xff) == from_code)
+ /* Perhaps the user wants to overwrite the map. */
+ break;
+
+ if (! ascii_key_map[i])
+ break;
+ }
+
+ if (i == KEY_MAP_SIZE)
+ {
+ errnum = ERR_WONT_FIT;
+ return 1;
+ }
+
+ if (to_code == from_code)
+ /* If TO is equal to FROM, delete the entry. */
+ grub_memmove ((char *) &ascii_key_map[i],
+ (char *) &ascii_key_map[i + 1],
+ sizeof (unsigned short) * (KEY_MAP_SIZE - i));
+ else
+ ascii_key_map[i] = (to_code << 8) | from_code;
+ }
+
+ return 0;
+}
+
+static struct builtin builtin_setkey =
+{
+ "setkey",
+ setkey_func,
+ BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
+ "setkey [TO_KEY FROM_KEY]",
+ "Change the keyboard map. The key FROM_KEY is mapped to the key TO_KEY."
+ " A key must be an alphabet, a digit, or one of these: escape, exclam,"
+ " at, numbersign, dollar, percent, caret, ampersand, asterisk, parenleft,"
+ " parenright, minus, underscore, equal, plus, backspace, tab, bracketleft,"
+ " braceleft, bracketright, braceright, enter, control, semicolon, colon,"
+ " quote, doublequote, backquote, tilde, shift, backslash, bar, comma,"
+ " less, period, greater, slash, question, alt, space, capslock, FX (X"
+ " is a digit), and delete. If no argument is specified, reset key"
+ " mappings."
+};
+
+
+/* setup */
+static int
+setup_func (char *arg, int flags)
+{
+ /* Point to the string of the installed drive/partition. */
+ char *install_ptr;
+ /* Point to the string of the drive/parition where the GRUB images
+ reside. */
+ char *image_ptr;
+ unsigned long installed_drive, installed_partition;
+ unsigned long image_drive, image_partition;
+ unsigned long tmp_drive, tmp_partition;
+ char stage1[64];
+ char stage2[64];
+ char config_filename[64];
+ char real_config_filename[64];
+ char cmd_arg[256];
+ char device[16];
+ char *buffer = (char *) RAW_ADDR (0x100000);
+ int is_force_lba = 0;
+ char *stage2_arg = 0;
+ char *prefix = 0;
+
+ auto int check_file (char *file);
+ auto void sprint_device (int drive, int partition);
+ auto int embed_stage1_5 (char * stage1_5, int drive, int partition);
+
+ /* Check if the file FILE exists like Autoconf. */
+ int check_file (char *file)
+ {
+ int ret;
+
+ grub_printf (" Checking if \"%s\" exists... ", file);
+ ret = grub_open (file);
+ if (ret)
+ {
+ grub_close ();
+ grub_printf ("yes\n");
+ }
+ else
+ grub_printf ("no\n");
+
+ return ret;
+ }
+
+ /* Construct a device name in DEVICE. */
+ void sprint_device (int drive, int partition)
+ {
+ grub_sprintf (device, "(%cd%d",
+ (drive & 0x80) ? 'h' : 'f',
+ drive & ~0x80);
+ if ((partition & 0xFF0000) != 0xFF0000)
+ {
+ char tmp[16];
+ grub_sprintf (tmp, ",%d", (partition >> 16) & 0xFF);
+ grub_strncat (device, tmp, 256);
+ }
+ if ((partition & 0x00FF00) != 0x00FF00)
+ {
+ char tmp[16];
+ grub_sprintf (tmp, ",%c", 'a' + ((partition >> 8) & 0xFF));
+ grub_strncat (device, tmp, 256);
+ }
+ grub_strncat (device, ")", 256);
+ }
+
+ int embed_stage1_5 (char *stage1_5, int drive, int partition)
+ {
+ /* We install GRUB into the MBR, so try to embed the
+ Stage 1.5 in the sectors right after the MBR. */
+ sprint_device (drive, partition);
+ grub_sprintf (cmd_arg, "%s %s", stage1_5, device);
+
+ /* Notify what will be run. */
+ grub_printf (" Running \"embed %s\"... ", cmd_arg);
+
+ embed_func (cmd_arg, flags);
+ if (! errnum)
+ {
+ /* Construct the blocklist representation. */
+ grub_sprintf (buffer, "%s%s", device, embed_info);
+ grub_printf ("succeeded\n");
+ return 1;
+ }
+ else
+ {
+ grub_printf ("failed (this is not fatal)\n");
+ return 0;
+ }
+ }
+
+ struct stage1_5_map {
+ char *fsys;
+ char *name;
+ };
+ struct stage1_5_map stage1_5_map[] =
+ {
+ {"ext2fs", "/e2fs_stage1_5"},
+ {"fat", "/fat_stage1_5"},
+ {"ffs", "/ffs_stage1_5"},
+ {"jfs", "/jfs_stage1_5"},
+ {"minix", "/minix_stage1_5"},
+ {"reiserfs", "/reiserfs_stage1_5"},
+ {"vstafs", "/vstafs_stage1_5"},
+ {"xfs", "/xfs_stage1_5"}
+ };
+
+ tmp_drive = saved_drive;
+ tmp_partition = saved_partition;
+
+ /* Check if the user specifies --force-lba. */
+ while (1)
+ {
+ if (grub_memcmp ("--force-lba", arg, sizeof ("--force-lba") - 1) == 0)
+ {
+ is_force_lba = 1;
+ arg = skip_to (0, arg);
+ }
+ else if (grub_memcmp ("--prefix=", arg, sizeof ("--prefix=") - 1) == 0)
+ {
+ prefix = arg + sizeof ("--prefix=") - 1;
+ arg = skip_to (0, arg);
+ nul_terminate (prefix);
+ }
+#ifdef GRUB_UTIL
+ else if (grub_memcmp ("--stage2=", arg, sizeof ("--stage2=") - 1) == 0)
+ {
+ stage2_arg = arg;
+ arg = skip_to (0, arg);
+ nul_terminate (stage2_arg);
+ }
+#endif /* GRUB_UTIL */
+ else
+ break;
+ }
+
+ install_ptr = arg;
+ image_ptr = skip_to (0, install_ptr);
+
+ /* Make sure that INSTALL_PTR is valid. */
+ set_device (install_ptr);
+ if (errnum)
+ return 1;
+
+ installed_drive = current_drive;
+ installed_partition = current_partition;
+
+ /* Mount the drive pointed by IMAGE_PTR. */
+ if (*image_ptr)
+ {
+ /* If the drive/partition where the images reside is specified,
+ get the drive and the partition. */
+ set_device (image_ptr);
+ if (errnum)
+ return 1;
+ }
+ else
+ {
+ /* If omitted, use SAVED_PARTITION and SAVED_DRIVE. */
+ current_drive = saved_drive;
+ current_partition = saved_partition;
+ }
+
+ image_drive = saved_drive = current_drive;
+ image_partition = saved_partition = current_partition;
+
+ /* Open it. */
+ if (! open_device ())
+ goto fail;
+
+ /* Check if stage1 exists. If the user doesn't specify the option
+ `--prefix', attempt /boot/grub and /grub. */
+ /* NOTE: It is dangerous to run this command without `--prefix' in the
+ grub shell, since that affects `--stage2'. */
+ if (! prefix)
+ {
+ prefix = "/boot/grub";
+ grub_sprintf (stage1, "%s%s", prefix, "/stage1");
+ if (! check_file (stage1))
+ {
+ errnum = ERR_NONE;
+ prefix = "/grub";
+ grub_sprintf (stage1, "%s%s", prefix, "/stage1");
+ if (! check_file (stage1))
+ goto fail;
+ }
+ }
+ else
+ {
+ grub_sprintf (stage1, "%s%s", prefix, "/stage1");
+ if (! check_file (stage1))
+ goto fail;
+ }
+
+ /* The prefix was determined. */
+ grub_sprintf (stage2, "%s%s", prefix, "/stage2");
+ grub_sprintf (config_filename, "%s%s", prefix, "/menu.lst");
+ *real_config_filename = 0;
+
+ /* Check if stage2 exists. */
+ if (! check_file (stage2))
+ goto fail;
+
+ {
+ char *fsys = fsys_table[fsys_type].name;
+ int i;
+ int size = sizeof (stage1_5_map) / sizeof (stage1_5_map[0]);
+
+ /* Iterate finding the same filesystem name as FSYS. */
+ for (i = 0; i < size; i++)
+ if (grub_strcmp (fsys, stage1_5_map[i].fsys) == 0)
+ {
+ /* OK, check if the Stage 1.5 exists. */
+ char stage1_5[64];
+
+ grub_sprintf (stage1_5, "%s%s", prefix, stage1_5_map[i].name);
+ if (check_file (stage1_5))
+ {
+ if (embed_stage1_5 (stage1_5,
+ installed_drive, installed_partition)
+ || embed_stage1_5 (stage1_5,
+ image_drive, image_partition))
+ {
+ grub_strcpy (real_config_filename, config_filename);
+ sprint_device (image_drive, image_partition);
+ grub_sprintf (config_filename, "%s%s", device, stage2);
+ grub_strcpy (stage2, buffer);
+ }
+ }
+ errnum = 0;
+ break;
+ }
+ }
+
+ /* Construct a string that is used by the command "install" as its
+ arguments. */
+ sprint_device (installed_drive, installed_partition);
+
+#if 1
+ /* Don't embed a drive number unnecessarily. */
+ grub_sprintf (cmd_arg, "%s%s%s%s %s%s %s p %s %s",
+ is_force_lba? "--force-lba " : "",
+ stage2_arg? stage2_arg : "",
+ stage2_arg? " " : "",
+ stage1,
+ (installed_drive != image_drive) ? "d " : "",
+ device,
+ stage2,
+ config_filename,
+ real_config_filename);
+#else /* NOT USED */
+ /* This code was used, because we belived some BIOSes had a problem
+ that they didn't pass a booting drive correctly. It turned out,
+ however, stage1 could trash a booting drive when checking LBA support,
+ because some BIOSes modified the register %dx in INT 13H, AH=48H.
+ So it becamed unclear whether GRUB should use a pre-defined booting
+ drive or not. If the problem still exists, it would be necessary to
+ switch back to this code. */
+ grub_sprintf (cmd_arg, "%s%s%s%s d %s %s p %s %s",
+ is_force_lba? "--force-lba " : "",
+ stage2_arg? stage2_arg : "",
+ stage2_arg? " " : "",
+ stage1,
+ device,
+ stage2,
+ config_filename,
+ real_config_filename);
+#endif /* NOT USED */
+
+ /* Notify what will be run. */
+ grub_printf (" Running \"install %s\"... ", cmd_arg);
+
+ /* Make sure that SAVED_DRIVE and SAVED_PARTITION are identical
+ with IMAGE_DRIVE and IMAGE_PARTITION, respectively. */
+ saved_drive = image_drive;
+ saved_partition = image_partition;
+
+ /* Run the command. */
+ if (! install_func (cmd_arg, flags))
+ grub_printf ("succeeded\nDone.\n");
+ else
+ grub_printf ("failed\n");
+
+ fail:
+ saved_drive = tmp_drive;
+ saved_partition = tmp_partition;
+ return errnum;
+}
+
+static struct builtin builtin_setup =
+{
+ "setup",
+ setup_func,
+ BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
+ "setup [--prefix=DIR] [--stage2=STAGE2_FILE] [--force-lba] INSTALL_DEVICE [IMAGE_DEVICE]",
+ "Set up the installation of GRUB automatically. This command uses"
+ " the more flexible command \"install\" in the backend and installs"
+ " GRUB into the device INSTALL_DEVICE. If IMAGE_DEVICE is specified,"
+ " then find the GRUB images in the device IMAGE_DEVICE, otherwise"
+ " use the current \"root device\", which can be set by the command"
+ " \"root\". If you know that your BIOS should support LBA but GRUB"
+ " doesn't work in LBA mode, specify the option `--force-lba'."
+ " If you install GRUB under the grub shell and you cannot unmount the"
+ " partition where GRUB images reside, specify the option `--stage2'"
+ " to tell GRUB the file name under your OS."
+};
+
+
+#if defined(SUPPORT_SERIAL) || defined(SUPPORT_HERCULES)
+/* terminal */
+static int
+terminal_func (char *arg, int flags)
+{
+ /* The index of the default terminal in TERM_TABLE. */
+ int default_term = -1;
+ struct term_entry *prev_term = current_term;
+ int to = -1;
+ int lines = 0;
+ int no_message = 0;
+ unsigned long term_flags = 0;
+ /* XXX: Assume less than 32 terminals. */
+ unsigned long term_bitmap = 0;
+
+ /* Get GNU-style long options. */
+ while (1)
+ {
+ if (grub_memcmp (arg, "--dumb", sizeof ("--dumb") - 1) == 0)
+ term_flags |= TERM_DUMB;
+ else if (grub_memcmp (arg, "--no-echo", sizeof ("--no-echo") - 1) == 0)
+ /* ``--no-echo'' implies ``--no-edit''. */
+ term_flags |= (TERM_NO_ECHO | TERM_NO_EDIT);
+ else if (grub_memcmp (arg, "--no-edit", sizeof ("--no-edit") - 1) == 0)
+ term_flags |= TERM_NO_EDIT;
+ else if (grub_memcmp (arg, "--timeout=", sizeof ("--timeout=") - 1) == 0)
+ {
+ char *val = arg + sizeof ("--timeout=") - 1;
+
+ if (! safe_parse_maxint (&val, &to))
+ return 1;
+ }
+ else if (grub_memcmp (arg, "--lines=", sizeof ("--lines=") - 1) == 0)
+ {
+ char *val = arg + sizeof ("--lines=") - 1;
+
+ if (! safe_parse_maxint (&val, &lines))
+ return 1;
+
+ /* Probably less than four is meaningless.... */
+ if (lines < 4)
+ {
+ errnum = ERR_BAD_ARGUMENT;
+ return 1;
+ }
+ }
+ else if (grub_memcmp (arg, "--silent", sizeof ("--silent") - 1) == 0)
+ no_message = 1;
+ else
+ break;
+
+ arg = skip_to (0, arg);
+ }
+
+ /* If no argument is specified, show current setting. */
+ if (! *arg)
+ {
+ grub_printf ("%s%s%s%s\n",
+ current_term->name,
+ current_term->flags & TERM_DUMB ? " (dumb)" : "",
+ current_term->flags & TERM_NO_EDIT ? " (no edit)" : "",
+ current_term->flags & TERM_NO_ECHO ? " (no echo)" : "");
+ return 0;
+ }
+
+ while (*arg)
+ {
+ int i;
+ char *next = skip_to (0, arg);
+
+ nul_terminate (arg);
+
+ for (i = 0; term_table[i].name; i++)
+ {
+ if (grub_strcmp (arg, term_table[i].name) == 0)
+ {
+ if (term_table[i].flags & TERM_NEED_INIT)
+ {
+ errnum = ERR_DEV_NEED_INIT;
+ return 1;
+ }
+
+ if (default_term < 0)
+ default_term = i;
+
+ term_bitmap |= (1 << i);
+ break;
+ }
+ }
+
+ if (! term_table[i].name)
+ {
+ errnum = ERR_BAD_ARGUMENT;
+ return 1;
+ }
+
+ arg = next;
+ }
+
+ /* If multiple terminals are specified, wait until the user pushes any
+ key on one of the terminals. */
+ if (term_bitmap & ~(1 << default_term))
+ {
+ int time1, time2 = -1;
+
+ /* XXX: Disable the pager. */
+ count_lines = -1;
+
+ /* Get current time. */
+ while ((time1 = getrtsecs ()) == 0xFF)
+ ;
+
+ /* Wait for a key input. */
+ while (to)
+ {
+ int i;
+
+ for (i = 0; term_table[i].name; i++)
+ {
+ if (term_bitmap & (1 << i))
+ {
+ if (term_table[i].checkkey () >= 0)
+ {
+ (void) term_table[i].getkey ();
+ default_term = i;
+
+ goto end;
+ }
+ }
+ }
+
+ /* Prompt the user, once per sec. */
+ if ((time1 = getrtsecs ()) != time2 && time1 != 0xFF)
+ {
+ if (! no_message)
+ {
+ /* Need to set CURRENT_TERM to each of selected
+ terminals. */
+ for (i = 0; term_table[i].name; i++)
+ if (term_bitmap & (1 << i))
+ {
+ current_term = term_table + i;
+ grub_printf ("\rPress any key to continue.\n");
+ }
+
+ /* Restore CURRENT_TERM. */
+ current_term = prev_term;
+ }
+
+ time2 = time1;
+ if (to > 0)
+ to--;
+ }
+ }
+ }
+
+ end:
+ current_term = term_table + default_term;
+ current_term->flags = term_flags;
+
+ if (lines)
+ max_lines = lines;
+ else
+ /* 24 would be a good default value. */
+ max_lines = 24;
+
+ /* If the interface is currently the command-line,
+ restart it to repaint the screen. */
+ if (current_term != prev_term && (flags & BUILTIN_CMDLINE))
+ grub_longjmp (restart_cmdline_env, 0);
+
+ return 0;
+}
+
+static struct builtin builtin_terminal =
+{
+ "terminal",
+ terminal_func,
+ BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
+ "terminal [--dumb] [--no-echo] [--no-edit] [--timeout=SECS] [--lines=LINES] [--silent] [console] [serial] [hercules]",
+ "Select a terminal. When multiple terminals are specified, wait until"
+ " you push any key to continue. If both console and serial are specified,"
+ " the terminal to which you input a key first will be selected. If no"
+ " argument is specified, print current setting. The option --dumb"
+ " specifies that your terminal is dumb, otherwise, vt100-compatibility"
+ " is assumed. If you specify --no-echo, input characters won't be echoed."
+ " If you specify --no-edit, the BASH-like editing feature will be disabled."
+ " If --timeout is present, this command will wait at most for SECS"
+ " seconds. The option --lines specifies the maximum number of lines."
+ " The option --silent is used to suppress messages."
+};
+#endif /* SUPPORT_SERIAL || SUPPORT_HERCULES */
+
+
+#ifdef SUPPORT_SERIAL
+static int
+terminfo_func (char *arg, int flags)
+{
+ struct terminfo term;
+
+ if (*arg)
+ {
+ struct
+ {
+ const char *name;
+ char *var;
+ }
+ options[] =
+ {
+ {"--name=", term.name},
+ {"--cursor-address=", term.cursor_address},
+ {"--clear-screen=", term.clear_screen},
+ {"--enter-standout-mode=", term.enter_standout_mode},
+ {"--exit-standout-mode=", term.exit_standout_mode}
+ };
+
+ grub_memset (&term, 0, sizeof (term));
+
+ while (*arg)
+ {
+ int i;
+ char *next = skip_to (0, arg);
+
+ nul_terminate (arg);
+
+ for (i = 0; i < sizeof (options) / sizeof (options[0]); i++)
+ {
+ const char *name = options[i].name;
+ int len = grub_strlen (name);
+
+ if (! grub_memcmp (arg, name, len))
+ {
+ grub_strcpy (options[i].var, ti_unescape_string (arg + len));
+ break;
+ }
+ }
+
+ if (i == sizeof (options) / sizeof (options[0]))
+ {
+ errnum = ERR_BAD_ARGUMENT;
+ return errnum;
+ }
+
+ arg = next;
+ }
+
+ if (term.name[0] == 0 || term.cursor_address[0] == 0)
+ {
+ errnum = ERR_BAD_ARGUMENT;
+ return errnum;
+ }
+
+ ti_set_term (&term);
+ }
+ else
+ {
+ /* No option specifies printing out current settings. */
+ ti_get_term (&term);
+
+ grub_printf ("name=%s\n",
+ ti_escape_string (term.name));
+ grub_printf ("cursor_address=%s\n",
+ ti_escape_string (term.cursor_address));
+ grub_printf ("clear_screen=%s\n",
+ ti_escape_string (term.clear_screen));
+ grub_printf ("enter_standout_mode=%s\n",
+ ti_escape_string (term.enter_standout_mode));
+ grub_printf ("exit_standout_mode=%s\n",
+ ti_escape_string (term.exit_standout_mode));
+ }
+
+ return 0;
+}
+
+static struct builtin builtin_terminfo =
+{
+ "terminfo",
+ terminfo_func,
+ BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
+ "terminfo [--name=NAME --cursor-address=SEQ [--clear-screen=SEQ]"
+ " [--enter-standout-mode=SEQ] [--exit-standout-mode=SEQ]]",
+
+ "Define the capabilities of your terminal. Use this command to"
+ " define escape sequences, if it is not vt100-compatible."
+ " You may use \\e for ESC and ^X for a control character."
+ " If no option is specified, the current settings are printed."
+};
+#endif /* SUPPORT_SERIAL */
+
+
+/* testload */
+static int
+testload_func (char *arg, int flags)
+{
+ int i;
+
+ kernel_type = KERNEL_TYPE_NONE;
+
+ if (! grub_open (arg))
+ return 1;
+
+ disk_read_hook = disk_read_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: ");
+
+ grub_seek (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: ");
+
+ grub_seek (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 (0x200000 + i))
+ != *((unsigned char *) RAW_ADDR (0x300000 + i)))
+ break;
+
+ grub_printf ("Max is 0x10ac0: i=0x%x, filepos=0x%x\n", i, filepos);
+ disk_read_hook = 0;
+ grub_close ();
+ 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."
+};
+
+
+/* testvbe MODE */
+static int
+testvbe_func (char *arg, int flags)
+{
+ int mode_number;
+ struct vbe_controller controller;
+ struct vbe_mode mode;
+
+ if (! *arg)
+ {
+ errnum = ERR_BAD_ARGUMENT;
+ return 1;
+ }
+
+ if (! safe_parse_maxint (&arg, &mode_number))
+ return 1;
+
+ /* Preset `VBE2'. */
+ grub_memmove (controller.signature, "VBE2", 4);
+
+ /* Detect VBE BIOS. */
+ if (get_vbe_controller_info (&controller) != 0x004F)
+ {
+ grub_printf (" VBE BIOS is not present.\n");
+ return 0;
+ }
+
+ if (controller.version < 0x0200)
+ {
+ grub_printf (" VBE version %d.%d is not supported.\n",
+ (int) (controller.version >> 8),
+ (int) (controller.version & 0xFF));
+ return 0;
+ }
+
+ if (get_vbe_mode_info (mode_number, &mode) != 0x004F
+ || (mode.mode_attributes & 0x0091) != 0x0091)
+ {
+ grub_printf (" Mode 0x%x is not supported.\n", mode_number);
+ return 0;
+ }
+
+ /* Now trip to the graphics mode. */
+ if (set_vbe_mode (mode_number | (1 << 14)) != 0x004F)
+ {
+ grub_printf (" Switching to Mode 0x%x failed.\n", mode_number);
+ return 0;
+ }
+
+ /* Draw something on the screen... */
+ {
+ unsigned char *base_buf = (unsigned char *) mode.phys_base;
+ int scanline = controller.version >= 0x0300
+ ? mode.linear_bytes_per_scanline : mode.bytes_per_scanline;
+ /* FIXME: this assumes that any depth is a modulo of 8. */
+ int bpp = mode.bits_per_pixel / 8;
+ int width = mode.x_resolution;
+ int height = mode.y_resolution;
+ int x, y;
+ unsigned color = 0;
+
+ /* Iterate drawing on the screen, until the user hits any key. */
+ while (checkkey () == -1)
+ {
+ for (y = 0; y < height; y++)
+ {
+ unsigned char *line_buf = base_buf + scanline * y;
+
+ for (x = 0; x < width; x++)
+ {
+ unsigned char *buf = line_buf + bpp * x;
+ int i;
+
+ for (i = 0; i < bpp; i++, buf++)
+ *buf = (color >> (i * 8)) & 0xff;
+ }
+
+ color++;
+ }
+ }
+
+ /* Discard the input. */
+ getkey ();
+ }
+
+ /* Back to the default text mode. */
+ if (set_vbe_mode (0x03) != 0x004F)
+ {
+ /* Why?! */
+ grub_reboot ();
+ }
+
+ return 0;
+}
+
+static struct builtin builtin_testvbe =
+{
+ "testvbe",
+ testvbe_func,
+ BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
+ "testvbe MODE",
+ "Test the VBE mode MODE. Hit any key to return."
+};
+
+
+#ifdef SUPPORT_NETBOOT
+/* tftpserver */
+static int
+tftpserver_func (char *arg, int flags)
+{
+ if (! *arg || ! ifconfig (0, 0, 0, arg))
+ {
+ errnum = ERR_BAD_ARGUMENT;
+ return 1;
+ }
+
+ print_network_configuration ();
+ return 0;
+}
+
+static struct builtin builtin_tftpserver =
+{
+ "tftpserver",
+ tftpserver_func,
+ BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
+ "tftpserver IPADDR",
+ "Override the TFTP server address."
+};
+#endif /* SUPPORT_NETBOOT */
+
+
+/* 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 used 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;
+
+ if (! set_partition_hidden_flag (0))
+ return 1;
+
+ return 0;
+}
+
+static struct builtin builtin_unhide =
+{
+ "unhide",
+ unhide_func,
+ BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
+ "unhide PARTITION",
+ "Unhide PARTITION by clearing the \"hidden\" bit in its"
+ " partition type code."
+};
+
+
+/* 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 | BUILTIN_HELP_LIST,
+ "uppermem KBYTES",
+ "Force GRUB to assume that only KBYTES kilobytes of upper memory are"
+ " installed. Any system address range maps are discarded."
+};
+
+
+/* vbeprobe */
+static int
+vbeprobe_func (char *arg, int flags)
+{
+ struct vbe_controller controller;
+ unsigned short *mode_list;
+ int mode_number = -1;
+
+ auto unsigned long vbe_far_ptr_to_linear (unsigned long);
+
+ unsigned long vbe_far_ptr_to_linear (unsigned long ptr)
+ {
+ unsigned short seg = (ptr >> 16);
+ unsigned short off = (ptr & 0xFFFF);
+
+ return (seg << 4) + off;
+ }
+
+ if (*arg)
+ {
+ if (! safe_parse_maxint (&arg, &mode_number))
+ return 1;
+ }
+
+ /* Set the signature to `VBE2', to obtain VBE 3.0 information. */
+ grub_memmove (controller.signature, "VBE2", 4);
+
+ if (get_vbe_controller_info (&controller) != 0x004F)
+ {
+ grub_printf (" VBE BIOS is not present.\n");
+ return 0;
+ }
+
+ /* Check the version. */
+ if (controller.version < 0x0200)
+ {
+ grub_printf (" VBE version %d.%d is not supported.\n",
+ (int) (controller.version >> 8),
+ (int) (controller.version & 0xFF));
+ return 0;
+ }
+
+ /* Print some information. */
+ grub_printf (" VBE version %d.%d\n",
+ (int) (controller.version >> 8),
+ (int) (controller.version & 0xFF));
+
+ /* Iterate probing modes. */
+ for (mode_list
+ = (unsigned short *) vbe_far_ptr_to_linear (controller.video_mode);
+ *mode_list != 0xFFFF;
+ mode_list++)
+ {
+ struct vbe_mode mode;
+
+ if (get_vbe_mode_info (*mode_list, &mode) != 0x004F)
+ continue;
+
+ /* Skip this, if this is not supported or linear frame buffer
+ mode is not support. */
+ if ((mode.mode_attributes & 0x0081) != 0x0081)
+ continue;
+
+ if (mode_number == -1 || mode_number == *mode_list)
+ {
+ char *model;
+ switch (mode.memory_model)
+ {
+ case 0x00: model = "Text"; break;
+ case 0x01: model = "CGA graphics"; break;
+ case 0x02: model = "Hercules graphics"; break;
+ case 0x03: model = "Planar"; break;
+ case 0x04: model = "Packed pixel"; break;
+ case 0x05: model = "Non-chain 4, 256 color"; break;
+ case 0x06: model = "Direct Color"; break;
+ case 0x07: model = "YUV"; break;
+ default: model = "Unknown"; break;
+ }
+
+ grub_printf (" 0x%x: %s, %ux%ux%u\n",
+ (unsigned) *mode_list,
+ model,
+ (unsigned) mode.x_resolution,
+ (unsigned) mode.y_resolution,
+ (unsigned) mode.bits_per_pixel);
+
+ if (mode_number != -1)
+ break;
+ }
+ }
+
+ if (mode_number != -1 && mode_number != *mode_list)
+ grub_printf (" Mode 0x%x is not found or supported.\n", mode_number);
+
+ return 0;
+}
+
+static struct builtin builtin_vbeprobe =
+{
+ "vbeprobe",
+ vbeprobe_func,
+ BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
+ "vbeprobe [MODE]",
+ "Probe VBE information. If the mode number MODE is specified, show only"
+ " the information about only the mode."
+};
+
+
+/* The table of builtin commands. Sorted in dictionary order. */
+struct builtin *builtin_table[] =
+{
+ &builtin_blocklist,
+ &builtin_boot,
+#ifdef SUPPORT_NETBOOT
+ &builtin_bootp,
+#endif /* SUPPORT_NETBOOT */
+ &builtin_cat,
+ &builtin_chainloader,
+ &builtin_cmp,
+ &builtin_color,
+ &builtin_configfile,
+ &builtin_debug,
+ &builtin_default,
+#ifdef GRUB_UTIL
+ &builtin_device,
+#endif /* GRUB_UTIL */
+#ifdef SUPPORT_NETBOOT
+ &builtin_dhcp,
+#endif /* SUPPORT_NETBOOT */
+ &builtin_displayapm,
+ &builtin_displaymem,
+#ifdef GRUB_UTIL
+ &builtin_dump,
+#endif /* GRUB_UTIL */
+ &builtin_embed,
+ &builtin_fallback,
+ &builtin_find,
+ &builtin_fstest,
+ &builtin_geometry,
+ &builtin_halt,
+ &builtin_help,
+ &builtin_hiddenmenu,
+ &builtin_hide,
+#ifdef SUPPORT_NETBOOT
+ &builtin_ifconfig,
+#endif /* SUPPORT_NETBOOT */
+ &builtin_impsprobe,
+ &builtin_initrd,
+ &builtin_install,
+ &builtin_ioprobe,
+ &builtin_kernel,
+ &builtin_lock,
+ &builtin_makeactive,
+ &builtin_map,
+#ifdef USE_MD5_PASSWORDS
+ &builtin_md5crypt,
+#endif /* USE_MD5_PASSWORDS */
+ &builtin_module,
+ &builtin_modulenounzip,
+ &builtin_pager,
+ &builtin_partnew,
+ &builtin_parttype,
+ &builtin_password,
+ &builtin_pause,
+#ifdef GRUB_UTIL
+ &builtin_quit,
+#endif /* GRUB_UTIL */
+#ifdef SUPPORT_NETBOOT
+ &builtin_rarp,
+#endif /* SUPPORT_NETBOOT */
+ &builtin_read,
+ &builtin_reboot,
+ &builtin_root,
+ &builtin_rootnoverify,
+ &builtin_savedefault,
+#ifdef SUPPORT_SERIAL
+ &builtin_serial,
+#endif /* SUPPORT_SERIAL */
+ &builtin_setkey,
+ &builtin_setup,
+#if defined(SUPPORT_SERIAL) || defined(SUPPORT_HERCULES)
+ &builtin_terminal,
+#endif /* SUPPORT_SERIAL || SUPPORT_HERCULES */
+#ifdef SUPPORT_SERIAL
+ &builtin_terminfo,
+#endif /* SUPPORT_SERIAL */
+ &builtin_testload,
+ &builtin_testvbe,
+#ifdef SUPPORT_NETBOOT
+ &builtin_tftpserver,
+#endif /* SUPPORT_NETBOOT */
+ &builtin_timeout,
+ &builtin_title,
+ &builtin_unhide,
+ &builtin_uppermem,
+ &builtin_vbeprobe,
+ 0
+};
diff -ruN grub-0.94.orig/stage2/disk_io.c stage2/disk_io.c
--- grub-0.94.orig/stage2/disk_io.c Wed Feb 11 00:22:12 2004
+++ stage2/disk_io.c Wed Feb 11 00:22:29 2004
@@ -72,6 +72,9 @@
# ifdef FSYS_XFS
{"xfs", xfs_mount, xfs_read, xfs_dir, 0, 0},
# endif
+# ifdef FSYS_UFS2
+ {"ufs2", ufs2_mount, ufs2_read, ufs2_dir, 0, ufs2_embed},
+# endif
/* XX FFS should come last as it's superblock is commonly crossing tracks
on floppies from track 1 to 2, while others only use 1. */
# ifdef FSYS_FFS
diff -ruN grub-0.94.orig/stage2/disk_io.c.orig stage2/disk_io.c.orig
--- grub-0.94.orig/stage2/disk_io.c.orig Thu Jan 1 03:00:00 1970
+++ stage2/disk_io.c.orig Sun Oct 19 19:58:03 2003
@@ -0,0 +1,1741 @@
+/* disk_io.c - implement abstract BIOS disk input and output */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1999,2000,2001,2002,2003 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 <shared.h>
+#include <filesys.h>
+
+#ifdef SUPPORT_NETBOOT
+# define GRUB 1
+# include <etherboot.h>
+#endif
+
+#ifdef GRUB_UTIL
+# include <device.h>
+#endif
+
+/* instrumentation variables */
+void (*disk_read_hook) (int, int, int) = NULL;
+void (*disk_read_func) (int, int, int) = NULL;
+
+#ifndef STAGE1_5
+int print_possibilities;
+
+static int do_completion;
+static int unique;
+static char *unique_string;
+
+#endif
+
+int fsmax;
+struct fsys_entry fsys_table[NUM_FSYS + 1] =
+{
+ /* TFTP should come first because others don't handle net device. */
+# ifdef FSYS_TFTP
+ {"tftp", tftp_mount, tftp_read, tftp_dir, tftp_close, 0},
+# endif
+# ifdef FSYS_FAT
+ {"fat", fat_mount, fat_read, fat_dir, 0, 0},
+# endif
+# ifdef FSYS_EXT2FS
+ {"ext2fs", ext2fs_mount, ext2fs_read, ext2fs_dir, 0, 0},
+# endif
+# ifdef FSYS_MINIX
+ {"minix", minix_mount, minix_read, minix_dir, 0, 0},
+# endif
+# ifdef FSYS_REISERFS
+ {"reiserfs", reiserfs_mount, reiserfs_read, reiserfs_dir, 0, reiserfs_embed},
+# endif
+# ifdef FSYS_VSTAFS
+ {"vstafs", vstafs_mount, vstafs_read, vstafs_dir, 0, 0},
+# endif
+# ifdef FSYS_JFS
+ {"jfs", jfs_mount, jfs_read, jfs_dir, 0, jfs_embed},
+# endif
+# ifdef FSYS_XFS
+ {"xfs", xfs_mount, xfs_read, xfs_dir, 0, 0},
+# endif
+ /* XX FFS should come last as it's superblock is commonly crossing tracks
+ on floppies from track 1 to 2, while others only use 1. */
+# ifdef FSYS_FFS
+ {"ffs", ffs_mount, ffs_read, ffs_dir, 0, ffs_embed},
+# endif
+ {0, 0, 0, 0, 0, 0}
+};
+
+
+/* These have the same format as "boot_drive" and "install_partition", but
+ are meant to be working values. */
+unsigned long current_drive = 0xFF;
+unsigned long current_partition;
+
+#ifndef STAGE1_5
+/* The register ESI should contain the address of the partition to be
+ used for loading a chain-loader when chain-loading the loader. */
+unsigned long boot_part_addr = 0;
+#endif
+
+/*
+ * Global variables describing details of the filesystem
+ */
+
+/* FIXME: BSD evil hack */
+#include "freebsd.h"
+int bsd_evil_hack;
+
+/* filesystem type */
+int fsys_type = NUM_FSYS;
+#ifndef NO_BLOCK_FILES
+static int block_file = 0;
+#endif /* NO_BLOCK_FILES */
+
+/* these are the translated numbers for the open partition */
+unsigned long part_start;
+unsigned long part_length;
+
+int current_slice;
+
+/* disk buffer parameters */
+int buf_drive = -1;
+int buf_track;
+struct geometry buf_geom;
+
+/* filesystem common variables */
+int filepos;
+int filemax;
+
+int
+rawread (int drive, int sector, int byte_offset, int byte_len, char *buf)
+{
+ int slen = (byte_offset + byte_len + SECTOR_SIZE - 1) >> SECTOR_BITS;
+
+ if (byte_len <= 0)
+ return 1;
+
+ while (byte_len > 0 && !errnum)
+ {
+ int soff, num_sect, bufaddr, track, size = byte_len;
+
+ /*
+ * Check track buffer. If it isn't valid or it is from the
+ * wrong disk, then reset the disk geometry.
+ */
+ if (buf_drive != drive)
+ {
+ if (get_diskinfo (drive, &buf_geom))
+ {
+ errnum = ERR_NO_DISK;
+ return 0;
+ }
+ buf_drive = drive;
+ buf_track = -1;
+ }
+
+ /* Make sure that SECTOR is valid. */
+ if (sector < 0 || sector >= buf_geom.total_sectors)
+ {
+ errnum = ERR_GEOM;
+ return 0;
+ }
+
+ /* Get first sector of track */
+ soff = sector % buf_geom.sectors;
+ track = sector - soff;
+ num_sect = buf_geom.sectors - soff;
+ bufaddr = BUFFERADDR + (soff * SECTOR_SIZE) + byte_offset;
+
+ if (track != buf_track)
+ {
+ int bios_err, read_start = track, read_len = buf_geom.sectors;
+
+ /*
+ * If there's more than one read in this entire loop, then
+ * only make the earlier reads for the portion needed. This
+ * saves filling the buffer with data that won't be used!
+ */
+ if (slen > num_sect)
+ {
+ read_start = sector;
+ read_len = num_sect;
+ bufaddr = BUFFERADDR + byte_offset;
+ }
+
+ bios_err = biosdisk (BIOSDISK_READ, drive, &buf_geom,
+ read_start, read_len, BUFFERSEG);
+ if (bios_err)
+ {
+ buf_track = -1;
+
+ if (bios_err == BIOSDISK_ERROR_GEOMETRY)
+ errnum = ERR_GEOM;
+ else
+ {
+ /*
+ * If there was an error, try to load only the
+ * required sector(s) rather than failing completely.
+ */
+ if (slen > num_sect
+ || biosdisk (BIOSDISK_READ, drive, &buf_geom,
+ sector, slen, BUFFERSEG))
+ errnum = ERR_READ;
+
+ bufaddr = BUFFERADDR + byte_offset;
+ }
+ }
+ else
+ buf_track = track;
+
+ if ((buf_track == 0 || sector == 0)
+ && (PC_SLICE_TYPE (BUFFERADDR, 0) == PC_SLICE_TYPE_EZD
+ || PC_SLICE_TYPE (BUFFERADDR, 1) == PC_SLICE_TYPE_EZD
+ || PC_SLICE_TYPE (BUFFERADDR, 2) == PC_SLICE_TYPE_EZD
+ || PC_SLICE_TYPE (BUFFERADDR, 3) == PC_SLICE_TYPE_EZD))
+ {
+ /* This is a EZD disk map sector 0 to sector 1 */
+ if (buf_track == 0 || slen >= 2)
+ {
+ /* We already read the sector 1, copy it to sector 0 */
+ memmove ((char *) BUFFERADDR,
+ (char *) BUFFERADDR + SECTOR_SIZE, SECTOR_SIZE);
+ }
+ else
+ {
+ if (biosdisk (BIOSDISK_READ, drive, &buf_geom,
+ 1, 1, BUFFERSEG))
+ errnum = ERR_READ;
+ }
+ }
+ }
+
+ if (size > ((num_sect * SECTOR_SIZE) - byte_offset))
+ size = (num_sect * SECTOR_SIZE) - byte_offset;
+
+ /*
+ * Instrumentation to tell which sectors were read and used.
+ */
+ if (disk_read_func)
+ {
+ int sector_num = sector;
+ int length = SECTOR_SIZE - byte_offset;
+ if (length > size)
+ length = size;
+ (*disk_read_func) (sector_num++, byte_offset, length);
+ length = size - length;
+ if (length > 0)
+ {
+ while (length > SECTOR_SIZE)
+ {
+ (*disk_read_func) (sector_num++, 0, SECTOR_SIZE);
+ length -= SECTOR_SIZE;
+ }
+ (*disk_read_func) (sector_num, 0, length);
+ }
+ }
+
+ memmove (buf, (char *) bufaddr, size);
+
+ buf += size;
+ byte_len -= size;
+ sector += num_sect;
+ slen -= num_sect;
+ byte_offset = 0;
+ }
+
+ return (!errnum);
+}
+
+
+int
+devread (int sector, int byte_offset, int byte_len, char *buf)
+{
+ /*
+ * Check partition boundaries
+ */
+ if (sector < 0
+ || ((sector + ((byte_offset + byte_len - 1) >> SECTOR_BITS))
+ >= part_length))
+ {
+ errnum = ERR_OUTSIDE_PART;
+ return 0;
+ }
+
+ /*
+ * Get the read to the beginning of a partition.
+ */
+ sector += byte_offset >> SECTOR_BITS;
+ byte_offset &= SECTOR_SIZE - 1;
+
+#if !defined(STAGE1_5)
+ if (disk_read_hook && debug)
+ printf ("<%d, %d, %d>", sector, byte_offset, byte_len);
+#endif /* !STAGE1_5 */
+
+ /*
+ * Call RAWREAD, which is very similar, but:
+ *
+ * -- It takes an extra parameter, the drive number.
+ * -- It requires that "sector" is relative to the beginning
+ * of the disk.
+ * -- It doesn't handle offsets of more than 511 bytes into the
+ * sector.
+ */
+ return rawread (current_drive, part_start + sector, byte_offset,
+ byte_len, buf);
+}
+
+#ifndef STAGE1_5
+int
+rawwrite (int drive, int sector, char *buf)
+{
+ if (sector == 0)
+ {
+ if (biosdisk (BIOSDISK_READ, drive, &buf_geom, 0, 1, SCRATCHSEG))
+ {
+ errnum = ERR_WRITE;
+ return 0;
+ }
+
+ if (PC_SLICE_TYPE (SCRATCHADDR, 0) == PC_SLICE_TYPE_EZD
+ || PC_SLICE_TYPE (SCRATCHADDR, 1) == PC_SLICE_TYPE_EZD
+ || PC_SLICE_TYPE (SCRATCHADDR, 2) == PC_SLICE_TYPE_EZD
+ || PC_SLICE_TYPE (SCRATCHADDR, 3) == PC_SLICE_TYPE_EZD)
+ sector = 1;
+ }
+
+ memmove ((char *) SCRATCHADDR, buf, SECTOR_SIZE);
+ if (biosdisk (BIOSDISK_WRITE, drive, &buf_geom,
+ sector, 1, SCRATCHSEG))
+ {
+ errnum = ERR_WRITE;
+ return 0;
+ }
+
+ if (sector - sector % buf_geom.sectors == buf_track)
+ /* Clear the cache. */
+ buf_track = -1;
+
+ return 1;
+}
+
+int
+devwrite (int sector, int sector_count, char *buf)
+{
+#if defined(GRUB_UTIL) && defined(__linux__)
+ if (current_partition != 0xFFFFFF)
+ {
+ /* If the grub shell is running under Linux and the user wants to
+ embed a Stage 1.5 into a partition instead of a MBR, use system
+ calls directly instead of biosdisk, because of the bug in
+ Linux. *sigh* */
+ return write_to_partition (device_map, current_drive, current_partition,
+ sector, sector_count, buf);
+ }
+ else
+#endif /* GRUB_UTIL && __linux__ */
+ {
+ int i;
+
+ for (i = 0; i < sector_count; i++)
+ {
+ if (! rawwrite (current_drive, part_start + sector + i,
+ buf + (i << SECTOR_BITS)))
+ return 0;
+
+ }
+ return 1;
+ }
+}
+
+static int
+sane_partition (void)
+{
+ /* network drive */
+ if (current_drive == NETWORK_DRIVE)
+ return 1;
+
+ if (!(current_partition & 0xFF000000uL)
+ && (current_drive & 0xFFFFFF7F) < 8
+ && (current_partition & 0xFF) == 0xFF
+ && ((current_partition & 0xFF00) == 0xFF00
+ || (current_partition & 0xFF00) < 0x800)
+ && ((current_partition >> 16) == 0xFF
+ || (current_drive & 0x80)))
+ return 1;
+
+ errnum = ERR_DEV_VALUES;
+ return 0;
+}
+#endif /* ! STAGE1_5 */
+
+static void
+attempt_mount (void)
+{
+#ifndef STAGE1_5
+ for (fsys_type = 0; fsys_type < NUM_FSYS; fsys_type++)
+ if ((fsys_table[fsys_type].mount_func) ())
+ break;
+
+ if (fsys_type == NUM_FSYS && errnum == ERR_NONE)
+ errnum = ERR_FSYS_MOUNT;
+#else
+ fsys_type = 0;
+ if ((*(fsys_table[fsys_type].mount_func)) () != 1)
+ {
+ fsys_type = NUM_FSYS;
+ errnum = ERR_FSYS_MOUNT;
+ }
+#endif
+}
+
+
+#ifndef STAGE1_5
+/* Turn on the active flag for the partition SAVED_PARTITION in the
+ drive SAVED_DRIVE. If an error occurs, return zero, otherwise return
+ non-zero. */
+int
+make_saved_active (void)
+{
+ char mbr[512];
+
+ if (saved_drive & 0x80)
+ {
+ /* Hard disk */
+ int part = saved_partition >> 16;
+
+ /* If the partition is not a primary partition, the active flag is
+ meaningless. (XXX: Really?) */
+ if (part > 3)
+ {
+ errnum = ERR_DEV_VALUES;
+ return 0;
+ }
+
+ /* Read the MBR in the scratch space. */
+ if (! rawread (saved_drive, 0, 0, SECTOR_SIZE, mbr))
+ return 0;
+
+ /* If the partition is an extended partition, setting the active
+ flag violates the specification by IBM. */
+ if (IS_PC_SLICE_TYPE_EXTENDED (PC_SLICE_TYPE (mbr, part)))
+ {
+ errnum = ERR_DEV_VALUES;
+ return 0;
+ }
+
+ /* Check if the active flag is disabled. */
+ if (PC_SLICE_FLAG (mbr, part) != PC_SLICE_FLAG_BOOTABLE)
+ {
+ int i;
+
+ /* Clear all the active flags in this table. */
+ for (i = 0; i < 4; i++)
+ PC_SLICE_FLAG (mbr, i) = 0;
+
+ /* Set the flag. */
+ PC_SLICE_FLAG (mbr, part) = PC_SLICE_FLAG_BOOTABLE;
+
+ /* Write back the MBR. */
+ if (! rawwrite (saved_drive, 0, mbr))
+ return 0;
+ }
+ }
+ else
+ {
+ /* If the drive is not a hard disk drive, you shouldn't call this
+ function. (XXX: Should I just ignore this error?) */
+ errnum = ERR_DEV_VALUES;
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Hide/Unhide CURRENT_PARTITION. */
+int
+set_partition_hidden_flag (int hidden)
+{
+ unsigned long part = 0xFFFFFF;
+ unsigned long start, len, offset, ext_offset;
+ int entry, type;
+ char mbr[512];
+
+ /* The drive must be a hard disk. */
+ if (! (current_drive & 0x80))
+ {
+ errnum = ERR_BAD_ARGUMENT;
+ return 1;
+ }
+
+ /* The partition must be a PC slice. */
+ if ((current_partition >> 16) == 0xFF
+ || (current_partition & 0xFFFF) != 0xFFFF)
+ {
+ errnum = ERR_BAD_ARGUMENT;
+ return 1;
+ }
+
+ /* Look for the partition. */
+ while (next_partition (current_drive, 0xFFFFFF, &part, &type,
+ &start, &len, &offset, &entry,
+ &ext_offset, mbr))
+ {
+ if (part == current_partition)
+ {
+ /* Found. */
+ if (hidden)
+ PC_SLICE_TYPE (mbr, entry) |= PC_SLICE_TYPE_HIDDEN_FLAG;
+ else
+ PC_SLICE_TYPE (mbr, entry) &= ~PC_SLICE_TYPE_HIDDEN_FLAG;
+
+ /* Write back the MBR to the disk. */
+ buf_track = -1;
+ if (! rawwrite (current_drive, offset, mbr))
+ return 1;
+
+ /* Succeed. */
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+
+static void
+check_and_print_mount (void)
+{
+ attempt_mount ();
+ if (errnum == ERR_FSYS_MOUNT)
+ errnum = ERR_NONE;
+ if (!errnum)
+ print_fsys_type ();
+ print_error ();
+}
+#endif /* STAGE1_5 */
+
+
+/* Get the information on next partition on the drive DRIVE.
+ The caller must not modify the contents of the arguments when
+ iterating this function. The partition representation in GRUB will
+ be stored in *PARTITION. Likewise, the partition type in *TYPE, the
+ start sector in *START, the length in *LEN, the offset of the
+ partition table in *OFFSET, the entry number in the table in *ENTRY,
+ the offset of the extended partition in *EXT_OFFSET.
+ BUF is used to store a MBR, the boot sector of a partition, or
+ a BSD label sector, and it must be at least 512 bytes length.
+ When calling this function first, *PARTITION must be initialized to
+ 0xFFFFFF. The return value is zero if fails, otherwise non-zero. */
+int
+next_partition (unsigned long drive, unsigned long dest,
+ unsigned long *partition, int *type,
+ unsigned long *start, unsigned long *len,
+ unsigned long *offset, int *entry,
+ unsigned long *ext_offset, char *buf)
+{
+ /* Forward declarations. */
+ auto int next_bsd_partition (void);
+ auto int next_pc_slice (void);
+
+ /* Get next BSD partition in current PC slice. */
+ int next_bsd_partition (void)
+ {
+ int i;
+ int bsd_part_no = (*partition & 0xFF00) >> 8;
+
+ /* If this is the first time... */
+ if (bsd_part_no == 0xFF)
+ {
+ /* Check if the BSD label is within current PC slice. */
+ if (*len < BSD_LABEL_SECTOR + 1)
+ {
+ errnum = ERR_BAD_PART_TABLE;
+ return 0;
+ }
+
+ /* Read the BSD label. */
+ if (! rawread (drive, *start + BSD_LABEL_SECTOR,
+ 0, SECTOR_SIZE, buf))
+ return 0;
+
+ /* Check if it is valid. */
+ if (! BSD_LABEL_CHECK_MAG (buf))
+ {
+ errnum = ERR_BAD_PART_TABLE;
+ return 0;
+ }
+
+ bsd_part_no = -1;
+ }
+
+ /* Search next valid BSD partition. */
+ for (i = bsd_part_no + 1; i < BSD_LABEL_NPARTS (buf); i++)
+ {
+ if (BSD_PART_TYPE (buf, i))
+ {
+ /* Note that *TYPE and *PARTITION were set
+ for current PC slice. */
+ *type = (BSD_PART_TYPE (buf, i) << 8) | (*type & 0xFF);
+ *start = BSD_PART_START (buf, i);
+ *len = BSD_PART_LENGTH (buf, i);
+ *partition = (*partition & 0xFF00FF) | (i << 8);
+
+#ifndef STAGE1_5
+ /* XXX */
+ if ((drive & 0x80) && BSD_LABEL_DTYPE (buf) == DTYPE_SCSI)
+ bsd_evil_hack = 4;
+#endif /* ! STAGE1_5 */
+
+ return 1;
+ }
+ }
+
+ errnum = ERR_NO_PART;
+ return 0;
+ }
+
+ /* Get next PC slice. Be careful of that this function may return
+ an empty PC slice (i.e. a partition whose type is zero) as well. */
+ int next_pc_slice (void)
+ {
+ int pc_slice_no = (*partition & 0xFF0000) >> 16;
+
+ /* If this is the first time... */
+ if (pc_slice_no == 0xFF)
+ {
+ *offset = 0;
+ *ext_offset = 0;
+ *entry = -1;
+ pc_slice_no = -1;
+ }
+
+ /* Read the MBR or the boot sector of the extended partition. */
+ if (! rawread (drive, *offset, 0, SECTOR_SIZE, buf))
+ return 0;
+
+ /* Check if it is valid. */
+ if (! PC_MBR_CHECK_SIG (buf))
+ {
+ errnum = ERR_BAD_PART_TABLE;
+ return 0;
+ }
+
+ /* Increase the entry number. */
+ (*entry)++;
+
+ /* If this is out of current partition table... */
+ if (*entry == PC_SLICE_MAX)
+ {
+ int i;
+
+ /* Search the first extended partition in current table. */
+ for (i = 0; i < PC_SLICE_MAX; i++)
+ {
+ if (IS_PC_SLICE_TYPE_EXTENDED (PC_SLICE_TYPE (buf, i)))
+ {
+ /* Found. Set the new offset and the entry number,
+ and restart this function. */
+ *offset = *ext_offset + PC_SLICE_START (buf, i);
+ if (! *ext_offset)
+ *ext_offset = *offset;
+ *entry = -1;
+ return next_pc_slice ();
+ }
+ }
+
+ errnum = ERR_NO_PART;
+ return 0;
+ }
+
+ *type = PC_SLICE_TYPE (buf, *entry);
+ *start = *offset + PC_SLICE_START (buf, *entry);
+ *len = PC_SLICE_LENGTH (buf, *entry);
+
+ /* The calculation of a PC slice number is complicated, because of
+ the rather odd definition of extended partitions. Even worse,
+ there is no guarantee that this is consistent with every
+ operating systems. Uggh. */
+ if (pc_slice_no < PC_SLICE_MAX
+ || (! IS_PC_SLICE_TYPE_EXTENDED (*type)
+ && *type != PC_SLICE_TYPE_NONE))
+ pc_slice_no++;
+
+ *partition = (pc_slice_no << 16) | 0xFFFF;
+ return 1;
+ }
+
+ /* Start the body of this function. */
+
+#ifndef STAGE1_5
+ if (current_drive == NETWORK_DRIVE)
+ return 0;
+#endif
+
+ /* If previous partition is a BSD partition or a PC slice which
+ contains BSD partitions... */
+ if ((*partition != 0xFFFFFF && IS_PC_SLICE_TYPE_BSD (*type & 0xff))
+ || ! (drive & 0x80))
+ {
+ if (*type == PC_SLICE_TYPE_NONE)
+ *type = PC_SLICE_TYPE_FREEBSD;
+
+ /* Get next BSD partition, if any. */
+ if (next_bsd_partition ())
+ return 1;
+
+ /* If the destination partition is a BSD partition and current
+ BSD partition has any error, abort the operation. */
+ if ((dest & 0xFF00) != 0xFF00
+ && ((dest & 0xFF0000) == 0xFF0000
+ || (dest & 0xFF0000) == (*partition & 0xFF0000)))
+ return 0;
+
+ /* Ignore the error. */
+ errnum = ERR_NONE;
+ }
+
+ return next_pc_slice ();
+}
+
+#ifndef STAGE1_5
+static unsigned long cur_part_offset;
+static unsigned long cur_part_addr;
+#endif
+
+/* Open a partition. */
+int
+real_open_partition (int flags)
+{
+ unsigned long dest_partition = current_partition;
+ unsigned long part_offset;
+ unsigned long ext_offset;
+ int entry;
+ char buf[SECTOR_SIZE];
+ int bsd_part, pc_slice;
+
+ /* For simplicity. */
+ auto int next (void);
+ int next (void)
+ {
+ int ret = next_partition (current_drive, dest_partition,
+ &current_partition, &current_slice,
+ &part_start, &part_length,
+ &part_offset, &entry, &ext_offset, buf);
+ bsd_part = (current_partition >> 8) & 0xFF;
+ pc_slice = current_partition >> 16;
+ return ret;
+ }
+
+#ifndef STAGE1_5
+ /* network drive */
+ if (current_drive == NETWORK_DRIVE)
+ return 1;
+
+ if (! sane_partition ())
+ return 0;
+#endif
+
+ bsd_evil_hack = 0;
+ current_slice = 0;
+ part_start = 0;
+
+ /* Make sure that buf_geom is valid. */
+ if (buf_drive != current_drive)
+ {
+ if (get_diskinfo (current_drive, &buf_geom))
+ {
+ errnum = ERR_NO_DISK;
+ return 0;
+ }
+ buf_drive = current_drive;
+ buf_track = -1;
+ }
+ part_length = buf_geom.total_sectors;
+
+ /* If this is the whole disk, return here. */
+ if (! flags && current_partition == 0xFFFFFF)
+ return 1;
+
+ if (flags)
+ dest_partition = 0xFFFFFF;
+
+ /* Initialize CURRENT_PARTITION for next_partition. */
+ current_partition = 0xFFFFFF;
+
+ while (next ())
+ {
+#ifndef STAGE1_5
+ loop_start:
+
+ cur_part_offset = part_offset;
+ cur_part_addr = BOOT_PART_TABLE + (entry << 4);
+#endif /* ! STAGE1_5 */
+
+ /* If this is a valid partition... */
+ if (current_slice)
+ {
+#ifndef STAGE1_5
+ /* Display partition information. */
+ if (flags && ! IS_PC_SLICE_TYPE_EXTENDED (current_slice))
+ {
+ if (! do_completion)
+ {
+ if (current_drive & 0x80)
+ grub_printf (" Partition num: %d, ",
+ current_partition >> 16);
+
+ if (! IS_PC_SLICE_TYPE_BSD (current_slice))
+ check_and_print_mount ();
+ else
+ {
+ int got_part = 0;
+ int saved_slice = current_slice;
+
+ while (next ())
+ {
+ if (bsd_part == 0xFF)
+ break;
+
+ if (! got_part)
+ {
+ grub_printf ("[BSD sub-partitions immediately follow]\n");
+ got_part = 1;
+ }
+
+ grub_printf (" BSD Partition num: \'%c\', ",
+ bsd_part + 'a');
+ check_and_print_mount ();
+ }
+
+ if (! got_part)
+ grub_printf (" No BSD sub-partition found, partition type 0x%x\n",
+ saved_slice);
+
+ if (errnum)
+ {
+ errnum = ERR_NONE;
+ break;
+ }
+
+ goto loop_start;
+ }
+ }
+ else
+ {
+ if (bsd_part != 0xFF)
+ {
+ char str[16];
+
+ if (! (current_drive & 0x80)
+ || (dest_partition >> 16) == pc_slice)
+ grub_sprintf (str, "%c)", bsd_part + 'a');
+ else
+ grub_sprintf (str, "%d,%c)",
+ pc_slice, bsd_part + 'a');
+ print_a_completion (str);
+ }
+ else if (! IS_PC_SLICE_TYPE_BSD (current_slice))
+ {
+ char str[8];
+
+ grub_sprintf (str, "%d)", pc_slice);
+ print_a_completion (str);
+ }
+ }
+ }
+
+ errnum = ERR_NONE;
+#endif /* ! STAGE1_5 */
+
+ /* Check if this is the destination partition. */
+ if (! flags
+ && (dest_partition == current_partition
+ || ((dest_partition >> 16) == 0xFF
+ && ((dest_partition >> 8) & 0xFF) == bsd_part)))
+ return 1;
+ }
+ }
+
+#ifndef STAGE1_5
+ if (flags)
+ {
+ if (! (current_drive & 0x80))
+ {
+ current_partition = 0xFFFFFF;
+ check_and_print_mount ();
+ }
+
+ errnum = ERR_NONE;
+ return 1;
+ }
+#endif /* ! STAGE1_5 */
+
+ return 0;
+}
+
+
+int
+open_partition (void)
+{
+ return real_open_partition (0);
+}
+
+
+#ifndef STAGE1_5
+/* XX used for device completion in 'set_device' and 'print_completions' */
+static int incomplete, disk_choice;
+static enum
+{
+ PART_UNSPECIFIED = 0,
+ PART_DISK,
+ PART_CHOSEN,
+}
+part_choice;
+#endif /* ! STAGE1_5 */
+
+char *
+set_device (char *device)
+{
+#ifdef STAGE1_5
+ /* In Stage 1.5, the first 4 bytes of FILENAME has a device number. */
+ unsigned long dev = *((unsigned long *) device);
+ int drive = (dev >> 24) & 0xFF;
+ int partition = dev & 0xFFFFFF;
+
+ /* If DRIVE is disabled (0xFF), use SAVED_DRIVE instead. */
+ if (drive == 0xFF)
+ current_drive = saved_drive;
+ else
+ current_drive = drive;
+
+ /* The `partition' part must always have a valid number. */
+ current_partition = partition;
+
+ return device + sizeof (unsigned long);
+
+#else /* ! STAGE1_5 */
+
+ int result = 0;
+
+ incomplete = 0;
+ disk_choice = 1;
+ part_choice = PART_UNSPECIFIED;
+ current_drive = saved_drive;
+ current_partition = 0xFFFFFF;
+
+ if (*device == '(' && !*(device + 1))
+ /* user has given '(' only, let disk_choice handle what disks we have */
+ return device + 1;
+
+ if (*device == '(' && *(++device))
+ {
+ if (*device != ',' && *device != ')')
+ {
+ char ch = *device;
+#ifdef SUPPORT_NETBOOT
+ if (*device == 'f' || *device == 'h' ||
+ (*device == 'n' && network_ready))
+#else
+ if (*device == 'f' || *device == 'h')
+#endif /* SUPPORT_NETBOOT */
+ {
+ /* user has given '([fhn]', check for resp. add 'd' and
+ let disk_choice handle what disks we have */
+ if (!*(device + 1))
+ {
+ device++;
+ *device++ = 'd';
+ *device = '\0';
+ return device;
+ }
+ else if (*(device + 1) == 'd' && !*(device + 2))
+ return device + 2;
+ }
+
+#ifdef SUPPORT_NETBOOT
+ if ((*device == 'f' || *device == 'h' ||
+ (*device == 'n' && network_ready))
+#else
+ if ((*device == 'f' || *device == 'h')
+#endif /* SUPPORT_NETBOOT */
+ && (device += 2, (*(device - 1) != 'd')))
+ errnum = ERR_NUMBER_PARSING;
+
+#ifdef SUPPORT_NETBOOT
+ if (ch == 'n' && network_ready)
+ current_drive = NETWORK_DRIVE;
+ else
+#endif /* SUPPORT_NETBOOT */
+ {
+ safe_parse_maxint (&device, (int *) &current_drive);
+
+ disk_choice = 0;
+ if (ch == 'h')
+ current_drive += 0x80;
+ }
+ }
+
+ if (errnum)
+ return 0;
+
+ if (*device == ')')
+ {
+ part_choice = PART_CHOSEN;
+ result = 1;
+ }
+ else if (*device == ',')
+ {
+ /* Either an absolute PC or BSD partition. */
+ disk_choice = 0;
+ part_choice ++;
+ device++;
+
+ if (*device >= '0' && *device <= '9')
+ {
+ part_choice ++;
+ current_partition = 0;
+
+ if (!(current_drive & 0x80)
+ || !safe_parse_maxint (&device, (int *) &current_partition)
+ || current_partition > 254)
+ {
+ errnum = ERR_DEV_FORMAT;
+ return 0;
+ }
+
+ current_partition = (current_partition << 16) + 0xFFFF;
+
+ if (*device == ',')
+ device++;
+
+ if (*device >= 'a' && *device <= 'h')
+ {
+ current_partition = (((*(device++) - 'a') << 8)
+ | (current_partition & 0xFF00FF));
+ }
+ }
+ else if (*device >= 'a' && *device <= 'h')
+ {
+ part_choice ++;
+ current_partition = ((*(device++) - 'a') << 8) | 0xFF00FF;
+ }
+
+ if (*device == ')')
+ {
+ if (part_choice == PART_DISK)
+ {
+ current_partition = saved_partition;
+ part_choice ++;
+ }
+
+ result = 1;
+ }
+ }
+ }
+
+ if (! sane_partition ())
+ return 0;
+
+ if (result)
+ return device + 1;
+ else
+ {
+ if (!*device)
+ incomplete = 1;
+ errnum = ERR_DEV_FORMAT;
+ }
+
+ return 0;
+
+#endif /* ! STAGE1_5 */
+}
+
+/*
+ * This performs a "mount" on the current device, both drive and partition
+ * number.
+ */
+
+int
+open_device (void)
+{
+ if (open_partition ())
+ attempt_mount ();
+
+ if (errnum != ERR_NONE)
+ return 0;
+
+ return 1;
+}
+
+
+#ifndef STAGE1_5
+int
+set_bootdev (int hdbias)
+{
+ int i, j;
+
+ /* Copy the boot partition information to 0x7be-0x7fd for chain-loading. */
+ if ((saved_drive & 0x80) && cur_part_addr)
+ {
+ if (rawread (saved_drive, cur_part_offset,
+ 0, SECTOR_SIZE, (char *) SCRATCHADDR))
+ {
+ char *dst, *src;
+
+ /* Need only the partition table.
+ XXX: We cannot use grub_memmove because BOOT_PART_TABLE
+ (0x07be) is less than 0x1000. */
+ dst = (char *) BOOT_PART_TABLE;
+ src = (char *) SCRATCHADDR + BOOTSEC_PART_OFFSET;
+ while (dst < (char *) BOOT_PART_TABLE + BOOTSEC_PART_LENGTH)
+ *dst++ = *src++;
+
+ /* Set the active flag of the booted partition. */
+ for (i = 0; i < 4; i++)
+ PC_SLICE_FLAG (BOOT_PART_TABLE, i) = 0;
+
+ *((unsigned char *) cur_part_addr) = PC_SLICE_FLAG_BOOTABLE;
+ boot_part_addr = cur_part_addr;
+ }
+ else
+ return 0;
+ }
+
+ /*
+ * Set BSD boot device.
+ */
+ i = (saved_partition >> 16) + 2;
+ if (saved_partition == 0xFFFFFF)
+ i = 1;
+ else if ((saved_partition >> 16) == 0xFF)
+ i = 0;
+
+ /* FIXME: extremely evil hack!!! */
+ j = 2;
+ if (saved_drive & 0x80)
+ j = bsd_evil_hack;
+
+ return MAKEBOOTDEV (j, (i >> 4), (i & 0xF),
+ ((saved_drive - hdbias) & 0x7F),
+ ((saved_partition >> 8) & 0xFF));
+}
+#endif /* STAGE1_5 */
+
+
+static char *
+setup_part (char *filename)
+{
+#ifdef STAGE1_5
+
+ if (! (filename = set_device (filename)))
+ {
+ current_drive = 0xFF;
+ return 0;
+ }
+
+# ifndef NO_BLOCK_FILES
+ if (*filename != '/')
+ open_partition ();
+ else
+# endif /* ! NO_BLOCK_FILES */
+ open_device ();
+
+#else /* ! STAGE1_5 */
+
+ if (*filename == '(')
+ {
+ if ((filename = set_device (filename)) == 0)
+ {
+ current_drive = 0xFF;
+ return 0;
+ }
+# ifndef NO_BLOCK_FILES
+ if (*filename != '/')
+ open_partition ();
+ else
+# endif /* ! NO_BLOCK_FILES */
+ open_device ();
+ }
+ else if (saved_drive != current_drive
+ || saved_partition != current_partition
+ || (*filename == '/' && fsys_type == NUM_FSYS)
+ || buf_drive == -1)
+ {
+ current_drive = saved_drive;
+ current_partition = saved_partition;
+ /* allow for the error case of "no filesystem" after the partition
+ is found. This makes block files work fine on no filesystem */
+# ifndef NO_BLOCK_FILES
+ if (*filename != '/')
+ open_partition ();
+ else
+# endif /* ! NO_BLOCK_FILES */
+ open_device ();
+ }
+
+#endif /* ! STAGE1_5 */
+
+ if (errnum && (*filename == '/' || errnum != ERR_FSYS_MOUNT))
+ return 0;
+ else
+ errnum = 0;
+
+#ifndef STAGE1_5
+ if (!sane_partition ())
+ return 0;
+#endif
+
+ return filename;
+}
+
+
+#ifndef STAGE1_5
+/*
+ * This prints the filesystem type or gives relevant information.
+ */
+
+void
+print_fsys_type (void)
+{
+ if (! do_completion)
+ {
+ printf (" Filesystem type ");
+
+ if (fsys_type != NUM_FSYS)
+ printf ("is %s, ", fsys_table[fsys_type].name);
+ else
+ printf ("unknown, ");
+
+ if (current_partition == 0xFFFFFF)
+ printf ("using whole disk\n");
+ else
+ printf ("partition type 0x%x\n", current_slice & 0xFF);
+ }
+}
+#endif /* STAGE1_5 */
+
+#ifndef STAGE1_5
+/* If DO_COMPLETION is true, just print NAME. Otherwise save the unique
+ part into UNIQUE_STRING. */
+void
+print_a_completion (char *name)
+{
+ /* If NAME is "." or "..", do not count it. */
+ if (grub_strcmp (name, ".") == 0 || grub_strcmp (name, "..") == 0)
+ return;
+
+ if (do_completion)
+ {
+ char *buf = unique_string;
+
+ if (! unique)
+ while ((*buf++ = *name++))
+ ;
+ else
+ {
+ while (*buf && (*buf == *name))
+ {
+ buf++;
+ name++;
+ }
+ /* mismatch, strip it. */
+ *buf = '\0';
+ }
+ }
+ else
+ grub_printf (" %s", name);
+
+ unique++;
+}
+
+/*
+ * This lists the possible completions of a device string, filename, or
+ * any sane combination of the two.
+ */
+
+int
+print_completions (int is_filename, int is_completion)
+{
+ char *buf = (char *) COMPLETION_BUF;
+ char *ptr = buf;
+
+ unique_string = (char *) UNIQUE_BUF;
+ *unique_string = 0;
+ unique = 0;
+ do_completion = is_completion;
+
+ if (! is_filename)
+ {
+ /* Print the completions of builtin commands. */
+ struct builtin **builtin;
+
+ if (! is_completion)
+ grub_printf (" Possible commands are:");
+
+ for (builtin = builtin_table; (*builtin); builtin++)
+ {
+ /* If *BUILTIN cannot be run in the command-line, skip it. */
+ if (! ((*builtin)->flags & BUILTIN_CMDLINE))
+ continue;
+
+ if (substring (buf, (*builtin)->name) <= 0)
+ print_a_completion ((*builtin)->name);
+ }
+
+ if (is_completion && *unique_string)
+ {
+ if (unique == 1)
+ {
+ char *u = unique_string + grub_strlen (unique_string);
+
+ *u++ = ' ';
+ *u = 0;
+ }
+
+ grub_strcpy (buf, unique_string);
+ }
+
+ if (! is_completion)
+ grub_putchar ('\n');
+
+ print_error ();
+ do_completion = 0;
+ if (errnum)
+ return -1;
+ else
+ return unique - 1;
+ }
+
+ if (*buf == '/' || (ptr = set_device (buf)) || incomplete)
+ {
+ errnum = 0;
+
+ if (*buf == '(' && (incomplete || ! *ptr))
+ {
+ if (! part_choice)
+ {
+ /* disk completions */
+ int disk_no, i, j;
+ struct geometry geom;
+
+ if (! is_completion)
+ grub_printf (" Possible disks are: ");
+
+#ifdef SUPPORT_NETBOOT
+ if (!ptr || *(ptr-1) != 'd' || *(ptr-2) != 'n')
+#endif /* SUPPORT_NETBOOT */
+ {
+ for (i = (ptr && (*(ptr-1) == 'd' && *(ptr-2) == 'h') ? 1:0);
+ i < (ptr && (*(ptr-1) == 'd' && *(ptr-2) == 'f') ? 1:2);
+ i++)
+ {
+ for (j = 0; j < 8; j++)
+ {
+ disk_no = (i * 0x80) + j;
+ if ((disk_choice || disk_no == current_drive)
+ && ! get_diskinfo (disk_no, &geom))
+ {
+ char dev_name[8];
+
+ grub_sprintf (dev_name, "%cd%d", i ? 'h':'f', j);
+ print_a_completion (dev_name);
+ }
+ }
+ }
+ }
+# ifdef SUPPORT_NETBOOT
+ if (network_ready &&
+ (disk_choice || NETWORK_DRIVE == current_drive) &&
+ (!ptr || *(ptr-1) == '(' ||
+ (*(ptr-1) == 'd' && *(ptr-2) == 'n')))
+ print_a_completion ("nd");
+# endif /* SUPPORT_NETBOOT */
+
+ if (is_completion && *unique_string)
+ {
+ ptr = buf;
+ while (*ptr != '(')
+ ptr--;
+ ptr++;
+ grub_strcpy (ptr, unique_string);
+ if (unique == 1)
+ {
+ ptr += grub_strlen (ptr);
+ if (*unique_string == 'h')
+ {
+ *ptr++ = ',';
+ *ptr = 0;
+ }
+ else
+ {
+ *ptr++ = ')';
+ *ptr = 0;
+ }
+ }
+ }
+
+ if (! is_completion)
+ grub_putchar ('\n');
+ }
+ else
+ {
+ /* partition completions */
+ if (part_choice == PART_CHOSEN
+ && open_partition ()
+ && ! IS_PC_SLICE_TYPE_BSD (current_slice))
+ {
+ unique = 1;
+ ptr = buf + grub_strlen (buf);
+ if (*(ptr - 1) != ')')
+ {
+ *ptr++ = ')';
+ *ptr = 0;
+ }
+ }
+ else
+ {
+ if (! is_completion)
+ grub_printf (" Possible partitions are:\n");
+ real_open_partition (1);
+
+ if (is_completion && *unique_string)
+ {
+ ptr = buf;
+ while (*ptr++ != ',')
+ ;
+ grub_strcpy (ptr, unique_string);
+ }
+ }
+ }
+ }
+ else if (ptr && *ptr == '/')
+ {
+ /* filename completions */
+ if (! is_completion)
+ grub_printf (" Possible files are:");
+
+ dir (buf);
+
+ if (is_completion && *unique_string)
+ {
+ ptr += grub_strlen (ptr);
+ while (*ptr != '/')
+ ptr--;
+ ptr++;
+
+ grub_strcpy (ptr, unique_string);
+
+ if (unique == 1)
+ {
+ ptr += grub_strlen (unique_string);
+
+ /* Check if the file UNIQUE_STRING is a directory. */
+ *ptr = '/';
+ *(ptr + 1) = 0;
+
+ dir (buf);
+
+ /* Restore the original unique value. */
+ unique = 1;
+
+ if (errnum)
+ {
+ /* Regular file */
+ errnum = 0;
+ *ptr = ' ';
+ *(ptr + 1) = 0;
+ }
+ }
+ }
+
+ if (! is_completion)
+ grub_putchar ('\n');
+ }
+ else
+ errnum = ERR_BAD_FILENAME;
+ }
+
+ print_error ();
+ do_completion = 0;
+ if (errnum)
+ return -1;
+ else
+ return unique - 1;
+}
+#endif /* STAGE1_5 */
+
+
+/*
+ * This is the generic file open function.
+ */
+
+int
+grub_open (char *filename)
+{
+#ifndef NO_DECOMPRESSION
+ compressed_file = 0;
+#endif /* NO_DECOMPRESSION */
+
+ /* if any "dir" function uses/sets filepos, it must
+ set it to zero before returning if opening a file! */
+ filepos = 0;
+
+ if (!(filename = setup_part (filename)))
+ return 0;
+
+#ifndef NO_BLOCK_FILES
+ block_file = 0;
+#endif /* NO_BLOCK_FILES */
+
+ /* This accounts for partial filesystem implementations. */
+ fsmax = MAXINT;
+
+ if (*filename != '/')
+ {
+#ifndef NO_BLOCK_FILES
+ char *ptr = filename;
+ int tmp, list_addr = BLK_BLKLIST_START;
+ filemax = 0;
+
+ while (list_addr < BLK_MAX_ADDR)
+ {
+ tmp = 0;
+ safe_parse_maxint (&ptr, &tmp);
+ errnum = 0;
+
+ if (*ptr != '+')
+ {
+ if ((*ptr && *ptr != '/' && !isspace (*ptr))
+ || tmp == 0 || tmp > filemax)
+ errnum = ERR_BAD_FILENAME;
+ else
+ filemax = tmp;
+
+ break;
+ }
+
+ /* since we use the same filesystem buffer, mark it to
+ be remounted */
+ fsys_type = NUM_FSYS;
+
+ BLK_BLKSTART (list_addr) = tmp;
+ ptr++;
+
+ if (!safe_parse_maxint (&ptr, &tmp)
+ || tmp == 0
+ || (*ptr && *ptr != ',' && *ptr != '/' && !isspace (*ptr)))
+ {
+ errnum = ERR_BAD_FILENAME;
+ break;
+ }
+
+ BLK_BLKLENGTH (list_addr) = tmp;
+
+ filemax += (tmp * SECTOR_SIZE);
+ list_addr += BLK_BLKLIST_INC_VAL;
+
+ if (*ptr != ',')
+ break;
+
+ ptr++;
+ }
+
+ if (list_addr < BLK_MAX_ADDR && ptr != filename && !errnum)
+ {
+ block_file = 1;
+ BLK_CUR_FILEPOS = 0;
+ BLK_CUR_BLKLIST = BLK_BLKLIST_START;
+ BLK_CUR_BLKNUM = 0;
+
+#ifndef NO_DECOMPRESSION
+ return gunzip_test_header ();
+#else /* NO_DECOMPRESSION */
+ return 1;
+#endif /* NO_DECOMPRESSION */
+ }
+#else /* NO_BLOCK_FILES */
+ errnum = ERR_BAD_FILENAME;
+#endif /* NO_BLOCK_FILES */
+ }
+
+ if (!errnum && fsys_type == NUM_FSYS)
+ errnum = ERR_FSYS_MOUNT;
+
+# ifndef STAGE1_5
+ /* set "dir" function to open a file */
+ print_possibilities = 0;
+# endif
+
+ if (!errnum && (*(fsys_table[fsys_type].dir_func)) (filename))
+ {
+#ifndef NO_DECOMPRESSION
+ return gunzip_test_header ();
+#else /* NO_DECOMPRESSION */
+ return 1;
+#endif /* NO_DECOMPRESSION */
+ }
+
+ return 0;
+}
+
+
+int
+grub_read (char *buf, int len)
+{
+ /* Make sure "filepos" is a sane value */
+ if ((filepos < 0) || (filepos > filemax))
+ filepos = filemax;
+
+ /* Make sure "len" is a sane value */
+ if ((len < 0) || (len > (filemax - filepos)))
+ len = filemax - filepos;
+
+ /* if target file position is past the end of
+ the supported/configured filesize, then
+ there is an error */
+ if (filepos + len > fsmax)
+ {
+ errnum = ERR_FILELENGTH;
+ return 0;
+ }
+
+#ifndef NO_DECOMPRESSION
+ if (compressed_file)
+ return gunzip_read (buf, len);
+#endif /* NO_DECOMPRESSION */
+
+#ifndef NO_BLOCK_FILES
+ if (block_file)
+ {
+ int size, off, ret = 0;
+
+ while (len && !errnum)
+ {
+ /* we may need to look for the right block in the list(s) */
+ if (filepos < BLK_CUR_FILEPOS)
+ {
+ BLK_CUR_FILEPOS = 0;
+ BLK_CUR_BLKLIST = BLK_BLKLIST_START;
+ BLK_CUR_BLKNUM = 0;
+ }
+
+ /* run BLK_CUR_FILEPOS up to filepos */
+ while (filepos > BLK_CUR_FILEPOS)
+ {
+ if ((filepos - (BLK_CUR_FILEPOS & ~(SECTOR_SIZE - 1)))
+ >= SECTOR_SIZE)
+ {
+ BLK_CUR_FILEPOS += SECTOR_SIZE;
+ BLK_CUR_BLKNUM++;
+
+ if (BLK_CUR_BLKNUM >= BLK_BLKLENGTH (BLK_CUR_BLKLIST))
+ {
+ BLK_CUR_BLKLIST += BLK_BLKLIST_INC_VAL;
+ BLK_CUR_BLKNUM = 0;
+ }
+ }
+ else
+ BLK_CUR_FILEPOS = filepos;
+ }
+
+ off = filepos & (SECTOR_SIZE - 1);
+ size = ((BLK_BLKLENGTH (BLK_CUR_BLKLIST) - BLK_CUR_BLKNUM)
+ * SECTOR_SIZE) - off;
+ if (size > len)
+ size = len;
+
+ disk_read_func = disk_read_hook;
+
+ /* read current block and put it in the right place in memory */
+ devread (BLK_BLKSTART (BLK_CUR_BLKLIST) + BLK_CUR_BLKNUM,
+ off, size, buf);
+
+ disk_read_func = NULL;
+
+ len -= size;
+ filepos += size;
+ ret += size;
+ buf += size;
+ }
+
+ if (errnum)
+ ret = 0;
+
+ return ret;
+ }
+#endif /* NO_BLOCK_FILES */
+
+ if (fsys_type == NUM_FSYS)
+ {
+ errnum = ERR_FSYS_MOUNT;
+ return 0;
+ }
+
+ return (*(fsys_table[fsys_type].read_func)) (buf, len);
+}
+
+#ifndef STAGE1_5
+/* Reposition a file offset. */
+int
+grub_seek (int offset)
+{
+ if (offset > filemax || offset < 0)
+ return -1;
+
+ filepos = offset;
+ return offset;
+}
+
+int
+dir (char *dirname)
+{
+#ifndef NO_DECOMPRESSION
+ compressed_file = 0;
+#endif /* NO_DECOMPRESSION */
+
+ if (!(dirname = setup_part (dirname)))
+ return 0;
+
+ if (*dirname != '/')
+ errnum = ERR_BAD_FILENAME;
+
+ if (fsys_type == NUM_FSYS)
+ errnum = ERR_FSYS_MOUNT;
+
+ if (errnum)
+ return 0;
+
+ /* set "dir" function to list completions */
+ print_possibilities = 1;
+
+ return (*(fsys_table[fsys_type].dir_func)) (dirname);
+}
+#endif /* STAGE1_5 */
+
+void
+grub_close (void)
+{
+#ifndef NO_BLOCK_FILES
+ if (block_file)
+ return;
+#endif /* NO_BLOCK_FILES */
+
+ if (fsys_table[fsys_type].close_func != 0)
+ (*(fsys_table[fsys_type].close_func)) ();
+}
diff -ruN grub-0.94.orig/stage2/filesys.h stage2/filesys.h
--- grub-0.94.orig/stage2/filesys.h Wed Feb 11 00:22:12 2004
+++ stage2/filesys.h Wed Feb 11 00:22:29 2004
@@ -30,6 +30,16 @@
#define FSYS_FFS_NUM 0
#endif
+#ifdef FSYS_UFS2
+#define FSYS_UFS2_NUM 1
+int ufs2_mount (void);
+int ufs2_read (char *buf, int len);
+int ufs2_dir (char *dirname);
+int ufs2_embed (int *start_sector, int needed_sectors);
+#else
+#define FSYS_UFS2_NUM 0
+#endif
+
#ifdef FSYS_FAT
#define FSYS_FAT_NUM 1
int fat_mount (void);
@@ -109,6 +119,7 @@
#define NUM_FSYS \
(FSYS_FFS_NUM + FSYS_FAT_NUM + FSYS_EXT2FS_NUM + FSYS_MINIX_NUM \
+ FSYS_REISERFS_NUM + FSYS_VSTAFS_NUM + FSYS_JFS_NUM + FSYS_XFS_NUM \
+ + FSYS_UFS2_NUM \
+ FSYS_TFTP_NUM)
#endif
diff -ruN grub-0.94.orig/stage2/filesys.h.orig stage2/filesys.h.orig
--- grub-0.94.orig/stage2/filesys.h.orig Thu Jan 1 03:00:00 1970
+++ stage2/filesys.h.orig Wed Jul 9 15:45:52 2003
@@ -0,0 +1,146 @@
+/* filesys.h - abstract filesystem interface */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1999, 2000, 2001 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 "pc_slice.h"
+
+#ifdef FSYS_FFS
+#define FSYS_FFS_NUM 1
+int ffs_mount (void);
+int ffs_read (char *buf, int len);
+int ffs_dir (char *dirname);
+int ffs_embed (int *start_sector, int needed_sectors);
+#else
+#define FSYS_FFS_NUM 0
+#endif
+
+#ifdef FSYS_FAT
+#define FSYS_FAT_NUM 1
+int fat_mount (void);
+int fat_read (char *buf, int len);
+int fat_dir (char *dirname);
+#else
+#define FSYS_FAT_NUM 0
+#endif
+
+#ifdef FSYS_EXT2FS
+#define FSYS_EXT2FS_NUM 1
+int ext2fs_mount (void);
+int ext2fs_read (char *buf, int len);
+int ext2fs_dir (char *dirname);
+#else
+#define FSYS_EXT2FS_NUM 0
+#endif
+
+#ifdef FSYS_MINIX
+#define FSYS_MINIX_NUM 1
+int minix_mount (void);
+int minix_read (char *buf, int len);
+int minix_dir (char *dirname);
+#else
+#define FSYS_MINIX_NUM 0
+#endif
+
+#ifdef FSYS_REISERFS
+#define FSYS_REISERFS_NUM 1
+int reiserfs_mount (void);
+int reiserfs_read (char *buf, int len);
+int reiserfs_dir (char *dirname);
+int reiserfs_embed (int *start_sector, int needed_sectors);
+#else
+#define FSYS_REISERFS_NUM 0
+#endif
+
+#ifdef FSYS_VSTAFS
+#define FSYS_VSTAFS_NUM 1
+int vstafs_mount (void);
+int vstafs_read (char *buf, int len);
+int vstafs_dir (char *dirname);
+#else
+#define FSYS_VSTAFS_NUM 0
+#endif
+
+#ifdef FSYS_JFS
+#define FSYS_JFS_NUM 1
+int jfs_mount (void);
+int jfs_read (char *buf, int len);
+int jfs_dir (char *dirname);
+int jfs_embed (int *start_sector, int needed_sectors);
+#else
+#define FSYS_JFS_NUM 0
+#endif
+
+#ifdef FSYS_XFS
+#define FSYS_XFS_NUM 1
+int xfs_mount (void);
+int xfs_read (char *buf, int len);
+int xfs_dir (char *dirname);
+#else
+#define FSYS_XFS_NUM 0
+#endif
+
+#ifdef FSYS_TFTP
+#define FSYS_TFTP_NUM 1
+int tftp_mount (void);
+int tftp_read (char *buf, int len);
+int tftp_dir (char *dirname);
+void tftp_close (void);
+#else
+#define FSYS_TFTP_NUM 0
+#endif
+
+#ifndef NUM_FSYS
+#define NUM_FSYS \
+ (FSYS_FFS_NUM + FSYS_FAT_NUM + FSYS_EXT2FS_NUM + FSYS_MINIX_NUM \
+ + FSYS_REISERFS_NUM + FSYS_VSTAFS_NUM + FSYS_JFS_NUM + FSYS_XFS_NUM \
+ + FSYS_TFTP_NUM)
+#endif
+
+/* defines for the block filesystem info area */
+#ifndef NO_BLOCK_FILES
+#define BLK_CUR_FILEPOS (*((int*)FSYS_BUF))
+#define BLK_CUR_BLKLIST (*((int*)(FSYS_BUF+4)))
+#define BLK_CUR_BLKNUM (*((int*)(FSYS_BUF+8)))
+#define BLK_MAX_ADDR (FSYS_BUF+0x7FF9)
+#define BLK_BLKSTART(l) (*((int*)l))
+#define BLK_BLKLENGTH(l) (*((int*)(l+4)))
+#define BLK_BLKLIST_START (FSYS_BUF+12)
+#define BLK_BLKLIST_INC_VAL 8
+#endif /* NO_BLOCK_FILES */
+
+/* this next part is pretty ugly, but it keeps it in one place! */
+
+struct fsys_entry
+{
+ char *name;
+ int (*mount_func) (void);
+ int (*read_func) (char *buf, int len);
+ int (*dir_func) (char *dirname);
+ void (*close_func) (void);
+ int (*embed_func) (int *start_sector, int needed_sectors);
+};
+
+#ifdef STAGE1_5
+# define print_possibilities 0
+#else
+extern int print_possibilities;
+#endif
+
+extern int fsmax;
+extern struct fsys_entry fsys_table[NUM_FSYS + 1];
diff -ruN grub-0.94.orig/stage2/fsys_ufs2.c stage2/fsys_ufs2.c
--- grub-0.94.orig/stage2/fsys_ufs2.c Thu Jan 1 03:00:00 1970
+++ stage2/fsys_ufs2.c Wed Feb 11 00:22:29 2004
@@ -0,0 +1,305 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2000, 2001 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.
+ */
+
+/*
+ * Elements of this file were originally from the FreeBSD "biosboot"
+ * bootloader file "disk.c" dated 4/12/95.
+ *
+ * The license and header comments from that file are included here.
+ */
+
+/*
+ * Mach Operating System
+ * Copyright (c) 1992, 1991 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ *
+ * from: Mach, Revision 2.2 92/04/04 11:35:49 rpd
+ *
+ */
+
+#ifdef FSYS_UFS2
+
+#include "shared.h"
+#include "filesys.h"
+
+#include "ufs2.h"
+
+/* used for filesystem map blocks */
+static int mapblock;
+static int mapblock_offset;
+static int mapblock_bsize;
+
+/* pointer to superblock */
+#define SUPERBLOCK ((struct fs *) ( FSYS_BUF + 8192 ))
+#define INODE ((struct ufs2_dinode *) ( FSYS_BUF + 16384 ))
+#define MAPBUF ( FSYS_BUF + 24576 )
+#define MAPBUF_LEN 8192
+
+
+int
+ufs2_mount (void)
+{
+ int retval = 1;
+
+ if ((((current_drive & 0x80) || (current_slice != 0))
+ && ! IS_PC_SLICE_TYPE_BSD_WITH_FS (current_slice, FS_BSDFFS))
+ || part_length < (SBLOCK_UFS2 + (SBLOCKSIZE / DEV_BSIZE))
+ || !devread (0, SBLOCK_UFS2, SBLOCKSIZE, (char *) SUPERBLOCK)
+ || SUPERBLOCK->fs_magic != FS_UFS2_MAGIC)
+ retval = 0;
+
+ mapblock = -1;
+ mapblock_offset = -1;
+
+ return retval;
+}
+
+static int64_t
+block_map (int file_block)
+{
+ int bnum, offset, bsize;
+
+ if (file_block < NDADDR)
+ return (INODE->di_db[file_block]);
+
+ /* If the blockmap loaded does not include FILE_BLOCK,
+ load a new blockmap. */
+ if ((bnum = fsbtodb (SUPERBLOCK, INODE->di_ib[0])) != mapblock
+ || (mapblock_offset <= bnum && bnum <= mapblock_offset + mapblock_bsize))
+ {
+ if (MAPBUF_LEN < SUPERBLOCK->fs_bsize)
+ {
+ offset = ((file_block - NDADDR) % NINDIR (SUPERBLOCK));
+ bsize = MAPBUF_LEN;
+
+ if (offset + MAPBUF_LEN > SUPERBLOCK->fs_bsize)
+ offset = (SUPERBLOCK->fs_bsize - MAPBUF_LEN) / sizeof (int);
+ }
+ else
+ {
+ bsize = SUPERBLOCK->fs_bsize;
+ offset = 0;
+ }
+
+ if (! devread (bnum, offset * sizeof (int), bsize, (char *) MAPBUF))
+ {
+ mapblock = -1;
+ mapblock_bsize = -1;
+ mapblock_offset = -1;
+ errnum = ERR_FSYS_CORRUPT;
+ return -1;
+ }
+
+ mapblock = bnum;
+ mapblock_bsize = bsize;
+ mapblock_offset = offset;
+ }
+
+ return (((int64_t *) MAPBUF)[((file_block - NDADDR) % NINDIR (SUPERBLOCK))
+ - mapblock_offset]);
+}
+
+int
+ufs2_read (char *buf, int len)
+{
+ int logno, off, size, ret = 0;
+ int64_t map;
+
+ while (len && !errnum)
+ {
+ off = blkoff (SUPERBLOCK, filepos);
+ logno = lblkno (SUPERBLOCK, filepos);
+ size = blksize (SUPERBLOCK, INODE, logno);
+
+ if ((map = block_map (logno)) < 0)
+ break;
+
+ size -= off;
+
+ if (size > len)
+ size = len;
+
+ disk_read_func = disk_read_hook;
+
+ devread (fsbtodb (SUPERBLOCK, map), off, size, buf);
+
+ disk_read_func = NULL;
+
+ buf += size;
+ len -= size;
+ filepos += size;
+ ret += size;
+ }
+
+ if (errnum)
+ ret = 0;
+
+ return ret;
+}
+
+int
+ufs2_dir (char *dirname)
+{
+ char *rest, ch;
+ int block, off, loc, ino = ROOTINO;
+ int64_t map;
+ struct direct *dp;
+
+/* main loop to find destination inode */
+loop:
+
+ /* load current inode (defaults to the root inode) */
+
+ if (!devread (fsbtodb (SUPERBLOCK, ino_to_fsba (SUPERBLOCK, ino)),
+ ino % (SUPERBLOCK->fs_inopb) * sizeof (struct ufs2_dinode),
+ sizeof (struct ufs2_dinode), (char *) INODE))
+ return 0; /* XXX what return value? */
+
+ /* if we have a real file (and we're not just printing possibilities),
+ then this is where we want to exit */
+
+ if (!*dirname || isspace (*dirname))
+ {
+ if ((INODE->di_mode & IFMT) != IFREG)
+ {
+ errnum = ERR_BAD_FILETYPE;
+ return 0;
+ }
+
+ filemax = INODE->di_size;
+
+ /* incomplete implementation requires this! */
+ fsmax = (NDADDR + NINDIR (SUPERBLOCK)) * SUPERBLOCK->fs_bsize;
+ return 1;
+ }
+
+ /* continue with file/directory name interpretation */
+
+ while (*dirname == '/')
+ dirname++;
+
+ if (!(INODE->di_size) || ((INODE->di_mode & IFMT) != IFDIR))
+ {
+ errnum = ERR_BAD_FILETYPE;
+ return 0;
+ }
+
+ for (rest = dirname; (ch = *rest) && !isspace (ch) && ch != '/'; rest++);
+
+ *rest = 0;
+ loc = 0;
+
+ /* loop for reading a the entries in a directory */
+
+ do
+ {
+ if (loc >= INODE->di_size)
+ {
+#if 0
+ putchar ('\n');
+#endif
+
+ if (print_possibilities < 0)
+ return 1;
+
+ errnum = ERR_FILE_NOT_FOUND;
+ *rest = ch;
+ return 0;
+ }
+
+ if (!(off = blkoff (SUPERBLOCK, loc)))
+ {
+ block = lblkno (SUPERBLOCK, loc);
+
+ if ((map = block_map (block)) < 0
+ || !devread (fsbtodb (SUPERBLOCK, map), 0,
+ blksize (SUPERBLOCK, INODE, block),
+ (char *) FSYS_BUF))
+ {
+ errnum = ERR_FSYS_CORRUPT;
+ *rest = ch;
+ return 0;
+ }
+ }
+
+ dp = (struct direct *) (FSYS_BUF + off);
+ loc += dp->d_reclen;
+
+#ifndef STAGE1_5
+ if (dp->d_ino && print_possibilities && ch != '/'
+ && (!*dirname || substring (dirname, dp->d_name) <= 0))
+ {
+ if (print_possibilities > 0)
+ print_possibilities = -print_possibilities;
+
+ print_a_completion (dp->d_name);
+ }
+#endif /* STAGE1_5 */
+ }
+ while (!dp->d_ino || (substring (dirname, dp->d_name) != 0
+ || (print_possibilities && ch != '/')));
+
+ /* only get here if we have a matching directory entry */
+
+ ino = dp->d_ino;
+ *(dirname = rest) = ch;
+
+ /* go back to main loop at top of function */
+ goto loop;
+}
+
+int
+ufs2_embed (int *start_sector, int needed_sectors)
+{
+ /* XXX: I don't know if this is really correct. Someone who is
+ familiar with BSD should check for this. */
+ if (needed_sectors > 14)
+ return 0;
+
+ *start_sector = 1;
+#if 1
+ /* FIXME: Disable the embedding in FFS until someone checks if
+ the code above is correct. */
+ return 0;
+#else
+ return 1;
+#endif
+}
+
+#endif /* FSYS_UFS2 */
diff -ruN grub-0.94.orig/stage2/shared.h stage2/shared.h
--- grub-0.94.orig/stage2/shared.h Wed Feb 11 00:22:12 2004
+++ stage2/shared.h Wed Feb 11 00:22:29 2004
@@ -205,6 +205,7 @@
#define STAGE2_ID_VSTAFS_STAGE1_5 6
#define STAGE2_ID_JFS_STAGE1_5 7
#define STAGE2_ID_XFS_STAGE1_5 8
+#define STAGE2_ID_UFS2_STAGE1_5 9
#ifndef STAGE1_5
# define STAGE2_ID STAGE2_ID_STAGE2
@@ -225,6 +226,8 @@
# define STAGE2_ID STAGE2_ID_JFS_STAGE1_5
# elif defined(FSYS_XFS)
# define STAGE2_ID STAGE2_ID_XFS_STAGE1_5
+# elif defined(FSYS_UFS2)
+# define STAGE2_ID STAGE2_ID_UFS2_STAGE1_5
# else
# error "unknown Stage 2"
# endif
diff -ruN grub-0.94.orig/stage2/shared.h.orig stage2/shared.h.orig
--- grub-0.94.orig/stage2/shared.h.orig Thu Jan 1 03:00:00 1970
+++ stage2/shared.h.orig Sun Jan 11 12:39:22 2004
@@ -0,0 +1,980 @@
+/* shared.h - definitions used in all GRUB-specific code */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1999,2000,2001,2002,2003,2004 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.
+ */
+
+/*
+ * Generic defines to use anywhere
+ */
+
+#ifndef GRUB_SHARED_HEADER
+#define GRUB_SHARED_HEADER 1
+
+#include <config.h>
+
+/* Add an underscore to a C symbol in assembler code if needed. */
+#ifdef HAVE_ASM_USCORE
+# define EXT_C(sym) _ ## sym
+#else
+# define EXT_C(sym) sym
+#endif
+
+/* Maybe redirect memory requests through grub_scratch_mem. */
+#ifdef GRUB_UTIL
+extern char *grub_scratch_mem;
+# define RAW_ADDR(x) ((x) + (int) grub_scratch_mem)
+# define RAW_SEG(x) (RAW_ADDR ((x) << 4) >> 4)
+#else
+# define RAW_ADDR(x) (x)
+# define RAW_SEG(x) (x)
+#endif
+
+/*
+ * Integer sizes
+ */
+
+#define MAXINT 0x7FFFFFFF
+
+/* Maximum command line size. Before you blindly increase this value,
+ see the comment in char_io.c (get_cmdline). */
+#define MAX_CMDLINE 1600
+#define NEW_HEAPSIZE 1500
+
+/* 512-byte scratch area */
+#define SCRATCHADDR RAW_ADDR (0x77e00)
+#define SCRATCHSEG RAW_SEG (0x77e0)
+
+/*
+ * This is the location of the raw device buffer. It is 31.5K
+ * in size.
+ */
+
+#define BUFFERLEN 0x7e00
+#define BUFFERADDR RAW_ADDR (0x70000)
+#define BUFFERSEG RAW_SEG (0x7000)
+
+#define BOOT_PART_TABLE RAW_ADDR (0x07be)
+
+/*
+ * BIOS disk defines
+ */
+#define BIOSDISK_READ 0x0
+#define BIOSDISK_WRITE 0x1
+#define BIOSDISK_ERROR_GEOMETRY 0x100
+#define BIOSDISK_FLAG_LBA_EXTENSION 0x1
+
+/*
+ * This is the filesystem (not raw device) buffer.
+ * It is 32K in size, do not overrun!
+ */
+
+#define FSYS_BUFLEN 0x8000
+#define FSYS_BUF RAW_ADDR (0x68000)
+
+/* Command-line buffer for Multiboot kernels and modules. This area
+ includes the area into which Stage 1.5 and Stage 1 are loaded, but
+ that's no problem. */
+#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)
+#define CMDLINE_BUFLEN MAX_CMDLINE
+
+/* The kill buffer for the command-line. */
+#define KILL_BUF (CMDLINE_BUF + CMDLINE_BUFLEN)
+#define KILL_BUFLEN MAX_CMDLINE
+
+/* The history buffer for the command-line. */
+#define HISTORY_BUF (KILL_BUF + KILL_BUFLEN)
+#define HISTORY_SIZE 5
+#define HISTORY_BUFLEN (MAX_CMDLINE * HISTORY_SIZE)
+
+/* The buffer for the completion. */
+#define COMPLETION_BUF (HISTORY_BUF + HISTORY_BUFLEN)
+#define COMPLETION_BUFLEN MAX_CMDLINE
+
+/* The buffer for the unique string. */
+#define UNIQUE_BUF (COMPLETION_BUF + COMPLETION_BUFLEN)
+#define UNIQUE_BUFLEN MAX_CMDLINE
+
+/* The buffer for the menu entries. */
+#define MENU_BUF (UNIQUE_BUF + UNIQUE_BUFLEN)
+#define MENU_BUFLEN (0x8000 + PASSWORD_BUF - UNIQUE_BUF)
+
+/* The size of the drive map. */
+#define DRIVE_MAP_SIZE 8
+
+/* The size of the key map. */
+#define KEY_MAP_SIZE 128
+
+/* The size of the io map. */
+#define IO_MAP_SIZE 128
+
+/*
+ * Linux setup parameters
+ */
+
+#define LINUX_MAGIC_SIGNATURE 0x53726448 /* "HdrS" */
+#define LINUX_DEFAULT_SETUP_SECTS 4
+#define LINUX_FLAG_CAN_USE_HEAP 0x80
+#define LINUX_INITRD_MAX_ADDRESS 0x38000000
+#define LINUX_MAX_SETUP_SECTS 64
+#define LINUX_BOOT_LOADER_TYPE 0x71
+#define LINUX_HEAP_END_OFFSET (0x9000 - 0x200)
+
+#define LINUX_BZIMAGE_ADDR RAW_ADDR (0x100000)
+#define LINUX_ZIMAGE_ADDR RAW_ADDR (0x10000)
+#define LINUX_OLD_REAL_MODE_ADDR RAW_ADDR (0x90000)
+#define LINUX_SETUP_STACK 0x9000
+
+#define LINUX_FLAG_BIG_KERNEL 0x1
+
+/* Linux's video mode selection support. Actually I hate it! */
+#define LINUX_VID_MODE_NORMAL 0xFFFF
+#define LINUX_VID_MODE_EXTENDED 0xFFFE
+#define LINUX_VID_MODE_ASK 0xFFFD
+
+#define LINUX_CL_OFFSET 0x9000
+#define LINUX_CL_END_OFFSET 0x90FF
+#define LINUX_SETUP_MOVE_SIZE 0x9100
+#define LINUX_CL_MAGIC 0xA33F
+
+/*
+ * General disk stuff
+ */
+
+#define SECTOR_SIZE 0x200
+#define SECTOR_BITS 9
+#define BIOS_FLAG_FIXED_DISK 0x80
+
+#define BOOTSEC_LOCATION RAW_ADDR (0x7C00)
+#define BOOTSEC_SIGNATURE 0xAA55
+#define BOOTSEC_BPB_OFFSET 0x3
+#define BOOTSEC_BPB_LENGTH 0x3B
+#define BOOTSEC_BPB_SYSTEM_ID 0x3
+#define BOOTSEC_BPB_HIDDEN_SECTORS 0x1C
+#define BOOTSEC_PART_OFFSET 0x1BE
+#define BOOTSEC_PART_LENGTH 0x40
+#define BOOTSEC_SIG_OFFSET 0x1FE
+#define BOOTSEC_LISTSIZE 8
+
+/* Not bad, perhaps. */
+#define NETWORK_DRIVE 0x20
+
+/*
+ * GRUB specific information
+ * (in LSB order)
+ */
+
+#include <stage1.h>
+
+#define STAGE2_VER_MAJ_OFFS 0x6
+#define STAGE2_INSTALLPART 0x8
+#define STAGE2_SAVED_ENTRYNO 0xc
+#define STAGE2_STAGE2_ID 0x10
+#define STAGE2_FORCE_LBA 0x11
+#define STAGE2_VER_STR_OFFS 0x12
+
+/* Stage 2 identifiers */
+#define STAGE2_ID_STAGE2 0
+#define STAGE2_ID_FFS_STAGE1_5 1
+#define STAGE2_ID_E2FS_STAGE1_5 2
+#define STAGE2_ID_FAT_STAGE1_5 3
+#define STAGE2_ID_MINIX_STAGE1_5 4
+#define STAGE2_ID_REISERFS_STAGE1_5 5
+#define STAGE2_ID_VSTAFS_STAGE1_5 6
+#define STAGE2_ID_JFS_STAGE1_5 7
+#define STAGE2_ID_XFS_STAGE1_5 8
+
+#ifndef STAGE1_5
+# define STAGE2_ID STAGE2_ID_STAGE2
+#else
+# if defined(FSYS_FFS)
+# define STAGE2_ID STAGE2_ID_FFS_STAGE1_5
+# elif defined(FSYS_EXT2FS)
+# define STAGE2_ID STAGE2_ID_E2FS_STAGE1_5
+# elif defined(FSYS_FAT)
+# define STAGE2_ID STAGE2_ID_FAT_STAGE1_5
+# elif defined(FSYS_MINIX)
+# define STAGE2_ID STAGE2_ID_MINIX_STAGE1_5
+# elif defined(FSYS_REISERFS)
+# define STAGE2_ID STAGE2_ID_REISERFS_STAGE1_5
+# elif defined(FSYS_VSTAFS)
+# define STAGE2_ID STAGE2_ID_VSTAFS_STAGE1_5
+# elif defined(FSYS_JFS)
+# define STAGE2_ID STAGE2_ID_JFS_STAGE1_5
+# elif defined(FSYS_XFS)
+# define STAGE2_ID STAGE2_ID_XFS_STAGE1_5
+# else
+# error "unknown Stage 2"
+# endif
+#endif
+
+/*
+ * defines for use when switching between real and protected mode
+ */
+
+#define CR0_PE_ON 0x1
+#define CR0_PE_OFF 0xfffffffe
+#define PROT_MODE_CSEG 0x8
+#define PROT_MODE_DSEG 0x10
+#define PSEUDO_RM_CSEG 0x18
+#define PSEUDO_RM_DSEG 0x20
+#define STACKOFF (0x2000 - 0x10)
+#define PROTSTACKINIT (FSYS_BUF - 0x10)
+
+
+/*
+ * Assembly code defines
+ *
+ * "EXT_C" is assumed to be defined in the Makefile by the configure
+ * command.
+ */
+
+#define ENTRY(x) .globl EXT_C(x) ; EXT_C(x):
+#define VARIABLE(x) ENTRY(x)
+
+
+#define K_RDWR 0x60 /* keyboard data & cmds (read/write) */
+#define K_STATUS 0x64 /* keyboard status */
+#define K_CMD 0x64 /* keybd ctlr command (write-only) */
+
+#define K_OBUF_FUL 0x01 /* output buffer full */
+#define K_IBUF_FUL 0x02 /* input buffer full */
+
+#define KC_CMD_WIN 0xd0 /* read output port */
+#define KC_CMD_WOUT 0xd1 /* write output port */
+#define KB_OUTPUT_MASK 0xdd /* enable output buffer full interrupt
+ enable data line
+ enable clock line */
+#define KB_A20_ENABLE 0x02
+
+/* Codes for getchar. */
+#define ASCII_CHAR(x) ((x) & 0xFF)
+#if !defined(GRUB_UTIL) || !defined(HAVE_LIBCURSES)
+# define KEY_LEFT 0x4B00
+# define KEY_RIGHT 0x4D00
+# define KEY_UP 0x4800
+# define KEY_DOWN 0x5000
+# define KEY_IC 0x5200 /* insert char */
+# define KEY_DC 0x5300 /* delete char */
+# define KEY_BACKSPACE 0x0008
+# define KEY_HOME 0x4700
+# define KEY_END 0x4F00
+# define KEY_NPAGE 0x5100
+# define KEY_PPAGE 0x4900
+# define A_NORMAL 0x7
+# define A_REVERSE 0x70
+#elif defined(HAVE_NCURSES_CURSES_H)
+# include <ncurses/curses.h>
+#elif defined(HAVE_NCURSES_H)
+# include <ncurses.h>
+#elif defined(HAVE_CURSES_H)
+# include <curses.h>
+#endif
+
+/* In old BSD curses, A_NORMAL and A_REVERSE are not defined, so we
+ define them here if they are undefined. */
+#ifndef A_NORMAL
+# define A_NORMAL 0
+#endif /* ! A_NORMAL */
+#ifndef A_REVERSE
+# ifdef A_STANDOUT
+# define A_REVERSE A_STANDOUT
+# else /* ! A_STANDOUT */
+# define A_REVERSE 0
+# endif /* ! A_STANDOUT */
+#endif /* ! A_REVERSE */
+
+/* Define ACS_* ourselves, since the definitions are not consistent among
+ various curses implementations. */
+#undef ACS_ULCORNER
+#undef ACS_URCORNER
+#undef ACS_LLCORNER
+#undef ACS_LRCORNER
+#undef ACS_HLINE
+#undef ACS_VLINE
+#undef ACS_LARROW
+#undef ACS_RARROW
+#undef ACS_UARROW
+#undef ACS_DARROW
+
+#define ACS_ULCORNER '+'
+#define ACS_URCORNER '+'
+#define ACS_LLCORNER '+'
+#define ACS_LRCORNER '+'
+#define ACS_HLINE '-'
+#define ACS_VLINE '|'
+#define ACS_LARROW '<'
+#define ACS_RARROW '>'
+#define ACS_UARROW '^'
+#define ACS_DARROW 'v'
+
+/* Special graphics characters for IBM displays. */
+#define DISP_UL 218
+#define DISP_UR 191
+#define DISP_LL 192
+#define DISP_LR 217
+#define DISP_HORIZ 196
+#define DISP_VERT 179
+#define DISP_LEFT 0x1b
+#define DISP_RIGHT 0x1a
+#define DISP_UP 0x18
+#define DISP_DOWN 0x19
+
+/* Remap some libc-API-compatible function names so that we prevent
+ circularararity. */
+#ifndef WITHOUT_LIBC_STUBS
+#define memmove grub_memmove
+#define memcpy grub_memmove /* we don't need a separate memcpy */
+#define memset grub_memset
+#define isspace grub_isspace
+#define printf grub_printf
+#define sprintf grub_sprintf
+#undef putchar
+#define putchar grub_putchar
+#define strncat grub_strncat
+#define strstr grub_strstr
+#define memcmp grub_memcmp
+#define strcmp grub_strcmp
+#define tolower grub_tolower
+#define strlen grub_strlen
+#define strcpy grub_strcpy
+#endif /* WITHOUT_LIBC_STUBS */
+
+
+#ifndef ASM_FILE
+/*
+ * Below this should be ONLY defines and other constructs for C code.
+ */
+
+/* multiboot stuff */
+
+#include "mb_header.h"
+#include "mb_info.h"
+
+/* For the Linux/i386 boot protocol version 2.03. */
+struct linux_kernel_header
+{
+ char code1[0x0020];
+ unsigned short cl_magic; /* Magic number 0xA33F */
+ unsigned short cl_offset; /* The offset of command line */
+ char code2[0x01F1 - 0x0020 - 2 - 2];
+ unsigned char setup_sects; /* The size of the setup in sectors */
+ unsigned short root_flags; /* If the root is mounted readonly */
+ unsigned short syssize; /* obsolete */
+ unsigned short swap_dev; /* obsolete */
+ unsigned short ram_size; /* obsolete */
+ unsigned short vid_mode; /* Video mode control */
+ unsigned short root_dev; /* Default root device number */
+ unsigned short boot_flag; /* 0xAA55 magic number */
+ unsigned short jump; /* Jump instruction */
+ unsigned long header; /* Magic signature "HdrS" */
+ unsigned short version; /* Boot protocol version supported */
+ unsigned long realmode_swtch; /* Boot loader hook */
+ unsigned long start_sys; /* Points to kernel version string */
+ unsigned char type_of_loader; /* Boot loader identifier */
+ unsigned char loadflags; /* Boot protocol option flags */
+ unsigned short setup_move_size; /* Move to high memory size */
+ unsigned long code32_start; /* Boot loader hook */
+ unsigned long ramdisk_image; /* initrd load address */
+ unsigned long ramdisk_size; /* initrd size */
+ unsigned long bootsect_kludge; /* obsolete */
+ unsigned short heap_end_ptr; /* Free memory after setup end */
+ unsigned short pad1; /* Unused */
+ char *cmd_line_ptr; /* Points to the kernel command line */
+ unsigned long initrd_addr_max; /* The highest address of initrd */
+} __attribute__ ((packed));
+
+/* Memory map address range descriptor used by GET_MMAP_ENTRY. */
+struct mmar_desc
+{
+ unsigned long desc_len; /* Size of this descriptor. */
+ unsigned long long addr; /* Base address. */
+ unsigned long long length; /* Length in bytes. */
+ unsigned long type; /* Type of address range. */
+} __attribute__ ((packed));
+
+/* VBE controller information. */
+struct vbe_controller
+{
+ unsigned char signature[4];
+ unsigned short version;
+ unsigned long oem_string;
+ unsigned long capabilities;
+ unsigned long video_mode;
+ unsigned short total_memory;
+ unsigned short oem_software_rev;
+ unsigned long oem_vendor_name;
+ unsigned long oem_product_name;
+ unsigned long oem_product_rev;
+ unsigned char reserved[222];
+ unsigned char oem_data[256];
+} __attribute__ ((packed));
+
+/* VBE mode information. */
+struct vbe_mode
+{
+ unsigned short mode_attributes;
+ unsigned char win_a_attributes;
+ unsigned char win_b_attributes;
+ unsigned short win_granularity;
+ unsigned short win_size;
+ unsigned short win_a_segment;
+ unsigned short win_b_segment;
+ unsigned long win_func;
+ unsigned short bytes_per_scanline;
+
+ /* >=1.2 */
+ unsigned short x_resolution;
+ unsigned short y_resolution;
+ unsigned char x_char_size;
+ unsigned char y_char_size;
+ unsigned char number_of_planes;
+ unsigned char bits_per_pixel;
+ unsigned char number_of_banks;
+ unsigned char memory_model;
+ unsigned char bank_size;
+ unsigned char number_of_image_pages;
+ unsigned char reserved0;
+
+ /* direct color */
+ unsigned char red_mask_size;
+ unsigned char red_field_position;
+ unsigned char green_mask_size;
+ unsigned char green_field_position;
+ unsigned char blue_mask_size;
+ unsigned char blue_field_position;
+ unsigned char reserved_mask_size;
+ unsigned char reserved_field_position;
+ unsigned char direct_color_mode_info;
+
+ /* >=2.0 */
+ unsigned long phys_base;
+ unsigned long reserved1;
+ unsigned short reversed2;
+
+ /* >=3.0 */
+ unsigned short linear_bytes_per_scanline;
+ unsigned char banked_number_of_image_pages;
+ unsigned char linear_number_of_image_pages;
+ unsigned char linear_red_mask_size;
+ unsigned char linear_red_field_position;
+ unsigned char linear_green_mask_size;
+ unsigned char linear_green_field_position;
+ unsigned char linear_blue_mask_size;
+ unsigned char linear_blue_field_position;
+ unsigned char linear_reserved_mask_size;
+ unsigned char linear_reserved_field_position;
+ unsigned long max_pixel_clock;
+
+ unsigned char reserved3[189];
+} __attribute__ ((packed));
+
+
+#undef NULL
+#define NULL ((void *) 0)
+
+/* Error codes (descriptions are in common.c) */
+typedef enum
+{
+ ERR_NONE = 0,
+ ERR_BAD_FILENAME,
+ ERR_BAD_FILETYPE,
+ ERR_BAD_GZIP_DATA,
+ ERR_BAD_GZIP_HEADER,
+ ERR_BAD_PART_TABLE,
+ ERR_BAD_VERSION,
+ ERR_BELOW_1MB,
+ ERR_BOOT_COMMAND,
+ ERR_BOOT_FAILURE,
+ ERR_BOOT_FEATURES,
+ ERR_DEV_FORMAT,
+ ERR_DEV_VALUES,
+ ERR_EXEC_FORMAT,
+ ERR_FILELENGTH,
+ ERR_FILE_NOT_FOUND,
+ ERR_FSYS_CORRUPT,
+ ERR_FSYS_MOUNT,
+ ERR_GEOM,
+ ERR_NEED_LX_KERNEL,
+ ERR_NEED_MB_KERNEL,
+ ERR_NO_DISK,
+ ERR_NO_PART,
+ ERR_NUMBER_PARSING,
+ ERR_OUTSIDE_PART,
+ ERR_READ,
+ ERR_SYMLINK_LOOP,
+ ERR_UNRECOGNIZED,
+ ERR_WONT_FIT,
+ ERR_WRITE,
+ ERR_BAD_ARGUMENT,
+ ERR_UNALIGNED,
+ ERR_PRIVILEGED,
+ ERR_DEV_NEED_INIT,
+ ERR_NO_DISK_SPACE,
+ ERR_NUMBER_OVERFLOW,
+
+ MAX_ERR_NUM
+} grub_error_t;
+
+extern unsigned long install_partition;
+extern unsigned long boot_drive;
+extern unsigned long install_second_sector;
+extern struct apm_info apm_bios_info;
+extern unsigned long boot_part_addr;
+extern int saved_entryno;
+extern unsigned char force_lba;
+extern char version_string[];
+extern char config_file[];
+extern unsigned long linux_text_len;
+extern char *linux_data_tmp_addr;
+extern char *linux_data_real_addr;
+
+#ifdef GRUB_UTIL
+/* If not using config file, this variable is set to zero,
+ otherwise non-zero. */
+extern int use_config_file;
+/* If using the preset menu, this variable is set to non-zero,
+ otherwise zero. */
+extern int use_preset_menu;
+/* If not using curses, this variable is set to zero, otherwise non-zero. */
+extern int use_curses;
+/* The flag for verbose messages. */
+extern int verbose;
+/* The flag for read-only. */
+extern int read_only;
+/* The number of floppies to be probed. */
+extern int floppy_disks;
+/* The map between BIOS drives and UNIX device file names. */
+extern char **device_map;
+/* The filename which stores the information about a device map. */
+extern char *device_map_file;
+/* The array of geometries. */
+extern struct geometry *disks;
+/* Assign DRIVE to a device name DEVICE. */
+extern void assign_device_name (int drive, const char *device);
+#endif
+
+#ifndef STAGE1_5
+/* GUI interface variables. */
+extern int fallback_entry;
+extern int default_entry;
+extern int current_entryno;
+
+/* The constants for password types. */
+typedef enum
+{
+ PASSWORD_PLAIN,
+ PASSWORD_MD5,
+ PASSWORD_UNSUPPORTED
+}
+password_t;
+
+extern char *password;
+extern password_t password_type;
+extern int auth;
+extern char commands[];
+
+/* For `more'-like feature. */
+extern int max_lines;
+extern int count_lines;
+extern int use_pager;
+#endif
+
+#ifndef NO_DECOMPRESSION
+extern int no_decompression;
+extern int compressed_file;
+#endif
+
+/* instrumentation variables */
+extern void (*disk_read_hook) (int, int, int);
+extern void (*disk_read_func) (int, int, int);
+
+#ifndef STAGE1_5
+/* The flag for debug mode. */
+extern int debug;
+#endif /* STAGE1_5 */
+
+extern unsigned long current_drive;
+extern unsigned long current_partition;
+
+extern int fsys_type;
+
+/* The information for a disk geometry. The CHS information is only for
+ DOS/Partition table compatibility, and the real number of sectors is
+ stored in TOTAL_SECTORS. */
+struct geometry
+{
+ /* The number of cylinders */
+ unsigned long cylinders;
+ /* The number of heads */
+ unsigned long heads;
+ /* The number of sectors */
+ unsigned long sectors;
+ /* The total number of sectors */
+ unsigned long total_sectors;
+ /* Flags */
+ unsigned long flags;
+};
+
+extern unsigned long part_start;
+extern unsigned long part_length;
+
+extern int current_slice;
+
+extern int buf_drive;
+extern int buf_track;
+extern struct geometry buf_geom;
+
+/* these are the current file position and maximum file position */
+extern int filepos;
+extern int filemax;
+
+/*
+ * Common BIOS/boot data.
+ */
+
+extern struct multiboot_info mbi;
+extern unsigned long saved_drive;
+extern unsigned long saved_partition;
+#ifndef STAGE1_5
+extern unsigned long saved_mem_upper;
+extern unsigned long extended_memory;
+#endif
+
+/*
+ * Error variables.
+ */
+
+extern grub_error_t errnum;
+extern char *err_list[];
+
+/* Simplify declaration of entry_addr. */
+typedef void (*entry_func) (int, int, int, int, int, int)
+ __attribute__ ((noreturn));
+
+extern entry_func entry_addr;
+
+/* Enter the stage1.5/stage2 C code after the stack is set up. */
+void cmain (void);
+
+/* Halt the processor (called after an unrecoverable error). */
+void stop (void) __attribute__ ((noreturn));
+
+/* Reboot the system. */
+void grub_reboot (void) __attribute__ ((noreturn));
+
+/* Halt the system, using APM if possible. If NO_APM is true, don't use
+ APM even if it is available. */
+void grub_halt (int no_apm) __attribute__ ((noreturn));
+
+/* Copy MAP to the drive map and set up int13_handler. */
+void set_int13_handler (unsigned short *map);
+
+/* Set up int15_handler. */
+void set_int15_handler (void);
+
+/* Restore the original int15 handler. */
+void unset_int15_handler (void);
+
+/* Track the int13 handler to probe I/O address space. */
+void track_int13 (int drive);
+
+/* The key map. */
+extern unsigned short bios_key_map[];
+extern unsigned short ascii_key_map[];
+extern unsigned short io_map[];
+
+/* calls for direct boot-loader chaining */
+void chain_stage1 (unsigned long segment, unsigned long offset,
+ unsigned long part_table_addr)
+ __attribute__ ((noreturn));
+void chain_stage2 (unsigned long segment, unsigned long offset,
+ int second_sector)
+ __attribute__ ((noreturn));
+
+/* do some funky stuff, then boot linux */
+void linux_boot (void) __attribute__ ((noreturn));
+
+/* do some funky stuff, then boot bzImage linux */
+void big_linux_boot (void) __attribute__ ((noreturn));
+
+/* booting a multiboot executable */
+void multi_boot (int start, int mb_info) __attribute__ ((noreturn));
+
+/* If LINEAR is nonzero, then set the Intel processor to linear mode.
+ Otherwise, bit 20 of all memory accesses is always forced to zero,
+ causing a wraparound effect for bugwards compatibility with the
+ 8086 CPU. */
+void gateA20 (int linear);
+
+/* memory probe routines */
+int get_memsize (int type);
+int get_eisamemsize (void);
+
+/* Fetch the next entry in the memory map and return the continuation
+ value. DESC is a pointer to the descriptor buffer, and CONT is the
+ previous continuation value (0 to get the first entry in the
+ map). */
+int get_mmap_entry (struct mmar_desc *desc, int cont);
+
+/* Get the linear address of a ROM configuration table. Return zero,
+ if fails. */
+unsigned long get_rom_config_table (void);
+
+/* Get APM BIOS information. */
+void get_apm_info (void);
+
+/* Get VBE controller information. */
+int get_vbe_controller_info (struct vbe_controller *controller);
+
+/* Get VBE mode information. */
+int get_vbe_mode_info (int mode_number, struct vbe_mode *mode);
+
+/* Set VBE mode. */
+int set_vbe_mode (int mode_number);
+
+/* Return the data area immediately following our code. */
+int get_code_end (void);
+
+/* low-level timing info */
+int getrtsecs (void);
+int currticks (void);
+
+/* Clear the screen. */
+void cls (void);
+
+/* Turn on/off cursor. */
+int setcursor (int on);
+
+/* Get the current cursor position (where 0,0 is the top left hand
+ corner of the screen). Returns packed values, (RET >> 8) is x,
+ (RET & 0xff) is y. */
+int getxy (void);
+
+/* Set the cursor position. */
+void gotoxy (int x, int y);
+
+/* Displays an ASCII character. IBM displays will translate some
+ characters to special graphical ones (see the DISP_* constants). */
+void grub_putchar (int c);
+
+/* Wait for a keypress, and return its packed BIOS/ASCII key code.
+ Use ASCII_CHAR(ret) to extract the ASCII code. */
+int getkey (void);
+
+/* Like GETKEY, but doesn't block, and returns -1 if no keystroke is
+ available. */
+int checkkey (void);
+
+/* Low-level disk I/O */
+int get_diskinfo (int drive, struct geometry *geometry);
+int biosdisk (int subfunc, int drive, struct geometry *geometry,
+ int sector, int nsec, int segment);
+void stop_floppy (void);
+
+/* Command-line interface functions. */
+#ifndef STAGE1_5
+
+/* The flags for the builtins. */
+#define BUILTIN_CMDLINE 0x1 /* Run in the command-line. */
+#define BUILTIN_MENU 0x2 /* Run in the menu. */
+#define BUILTIN_TITLE 0x4 /* Only for the command title. */
+#define BUILTIN_SCRIPT 0x8 /* Run in the script. */
+#define BUILTIN_NO_ECHO 0x10 /* Don't print command on booting. */
+#define BUILTIN_HELP_LIST 0x20 /* Show help in listing. */
+
+/* The table for a builtin. */
+struct builtin
+{
+ /* The command name. */
+ char *name;
+ /* The callback function. */
+ int (*func) (char *, int);
+ /* The combination of the flags defined above. */
+ int flags;
+ /* The short version of the documentation. */
+ char *short_doc;
+ /* The long version of the documentation. */
+ char *long_doc;
+};
+
+/* All the builtins are registered in this. */
+extern struct builtin *builtin_table[];
+
+/* The constants for kernel types. */
+typedef enum
+{
+ KERNEL_TYPE_NONE, /* None is loaded. */
+ KERNEL_TYPE_MULTIBOOT, /* Multiboot. */
+ KERNEL_TYPE_LINUX, /* Linux. */
+ KERNEL_TYPE_BIG_LINUX, /* Big Linux. */
+ KERNEL_TYPE_FREEBSD, /* FreeBSD. */
+ KERNEL_TYPE_NETBSD, /* NetBSD. */
+ KERNEL_TYPE_CHAINLOADER /* Chainloader. */
+}
+kernel_t;
+
+extern kernel_t kernel_type;
+extern int show_menu;
+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 (int forever);
+void enter_cmdline (char *heap, int forever);
+int run_script (char *script, char *heap);
+#endif
+
+/* C library replacement functions with identical semantics. */
+void grub_printf (const char *format,...);
+int grub_sprintf (char *buffer, const char *format, ...);
+int grub_tolower (int c);
+int grub_isspace (int c);
+int grub_strncat (char *s1, const char *s2, int n);
+void *grub_memmove (void *to, const void *from, int len);
+void *grub_memset (void *start, int c, int len);
+int grub_strncat (char *s1, const char *s2, int n);
+char *grub_strstr (const char *s1, const char *s2);
+int grub_memcmp (const char *s1, const char *s2, int n);
+int grub_strcmp (const char *s1, const char *s2);
+int grub_strlen (const char *str);
+char *grub_strcpy (char *dest, const char *src);
+
+#ifndef GRUB_UTIL
+typedef unsigned long grub_jmp_buf[6];
+#else
+/* In the grub shell, use the libc jmp_buf instead. */
+# include <setjmp.h>
+# define grub_jmp_buf jmp_buf
+#endif
+
+#ifdef GRUB_UTIL
+# define grub_setjmp setjmp
+# define grub_longjmp longjmp
+#else /* ! GRUB_UTIL */
+int grub_setjmp (grub_jmp_buf env);
+void grub_longjmp (grub_jmp_buf env, int val);
+#endif /* ! GRUB_UTIL */
+
+/* The environment for restarting Stage 2. */
+extern grub_jmp_buf restart_env;
+/* The environment for restarting the command-line interface. */
+extern grub_jmp_buf restart_cmdline_env;
+
+/* misc */
+void init_page (void);
+void print_error (void);
+char *convert_to_ascii (char *buf, int c, ...);
+int get_cmdline (char *prompt, char *cmdline, int maxlen,
+ int echo_char, int history);
+int substring (const char *s1, const char *s2);
+int nul_terminate (char *str);
+int get_based_digit (int c, int base);
+int safe_parse_maxint (char **str_ptr, int *myint_ptr);
+int memcheck (int start, int len);
+void grub_putstr (const char *str);
+
+#ifndef NO_DECOMPRESSION
+/* Compression support. */
+int gunzip_test_header (void);
+int gunzip_read (char *buf, int len);
+#endif /* NO_DECOMPRESSION */
+
+int rawread (int drive, int sector, int byte_offset, int byte_len, char *buf);
+int devread (int sector, int byte_offset, int byte_len, char *buf);
+int rawwrite (int drive, int sector, char *buf);
+int devwrite (int sector, int sector_len, char *buf);
+
+/* Parse a device string and initialize the global parameters. */
+char *set_device (char *device);
+int open_device (void);
+int real_open_partition (int flags);
+int open_partition (void);
+int next_partition (unsigned long drive, unsigned long dest,
+ unsigned long *partition, int *type,
+ unsigned long *start, unsigned long *len,
+ unsigned long *offset, int *entry,
+ unsigned long *ext_offset, char *buf);
+
+/* Sets device to the one represented by the SAVED_* parameters. */
+int make_saved_active (void);
+
+/* Set or clear the current root partition's hidden flag. */
+int set_partition_hidden_flag (int hidden);
+
+/* Open a file or directory on the active device, using GRUB's
+ internal filesystem support. */
+int grub_open (char *filename);
+
+/* Read LEN bytes into BUF from the file that was opened with
+ GRUB_OPEN. If LEN is -1, read all the remaining data in the file. */
+int grub_read (char *buf, int len);
+
+/* Reposition a file offset. */
+int grub_seek (int offset);
+
+/* Close a file. */
+void grub_close (void);
+
+/* List the contents of the directory that was opened with GRUB_OPEN,
+ printing all completions. */
+int dir (char *dirname);
+
+int set_bootdev (int hdbias);
+
+/* Display statistics on the current active device. */
+void print_fsys_type (void);
+
+/* Display device and filename completions. */
+void print_a_completion (char *filename);
+int print_completions (int is_filename, int is_completion);
+
+/* Copies the current partition data to the desired address. */
+void copy_current_part_entry (char *buf);
+
+#ifndef STAGE1_5
+void bsd_boot (kernel_t type, int bootdev, char *arg)
+ __attribute__ ((noreturn));
+
+/* Define flags for load_image here. */
+/* Don't pass a Linux's mem option automatically. */
+#define KERNEL_LOAD_NO_MEM_OPTION (1 << 0)
+
+kernel_t load_image (char *kernel, char *arg, kernel_t suggested_type,
+ unsigned long load_flags);
+
+int load_module (char *module, char *arg);
+int load_initrd (char *initrd);
+
+int check_password(char *entered, char* expected, password_t type);
+#endif
+
+void init_bios_info (void);
+
+#endif /* ASM_FILE */
+
+#endif /* ! GRUB_SHARED_HEADER */
diff -ruN grub-0.94.orig/stage2/size_test stage2/size_test
--- grub-0.94.orig/stage2/size_test Wed Feb 11 00:22:12 2004
+++ stage2/size_test Wed Feb 11 00:22:29 2004
@@ -40,6 +40,8 @@
# The bootloader area of a FFS partition is 14 sectors.
check ffs_stage1_5 7168
+check ufs2_stage1_5 7168
+
# Stage 1.5 can be installed in the sectors immediately after MBR in the
# first cylinder, so the size is (63 - 1) sectors.
check fat_stage1_5 31744
diff -ruN grub-0.94.orig/stage2/size_test.orig stage2/size_test.orig
--- grub-0.94.orig/stage2/size_test.orig Thu Jan 1 03:00:00 1970
+++ stage2/size_test.orig Wed Jul 9 15:45:53 2003
@@ -0,0 +1,54 @@
+#!/bin/sh
+
+# Check the sizes of Stage 2 and Stage 1.5's.
+# 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, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+# Written by OKUJI Yoshinori <okuji@kuicr.kyoto-u.ac.jp>
+
+
+# This function checks if the size of the first argument (filename) is
+# greater than the second argument (limit). If so, then exit with the
+# status 1, otherwise do nothing.
+check ()
+{
+ local file size limit
+
+ file=$1
+ limit=$2
+ set dummy `ls -l $file`
+ size=$6
+ if test $size -gt $limit; then
+ echo "$file is too big ($size > $limit)."
+ exit 1
+ fi
+}
+
+# The bootloader area of a FFS partition is 14 sectors.
+check ffs_stage1_5 7168
+
+# Stage 1.5 can be installed in the sectors immediately after MBR in the
+# first cylinder, so the size is (63 - 1) sectors.
+check fat_stage1_5 31744
+
+# Likewise.
+check e2fs_stage1_5 31744
+
+# Likewise.
+check minix_stage1_5 31744
+
+# Success.
+exit 0
diff -ruN grub-0.94.orig/stage2/ufs2.h stage2/ufs2.h
--- grub-0.94.orig/stage2/ufs2.h Thu Jan 1 03:00:00 1970
+++ stage2/ufs2.h Wed Feb 11 00:23:16 2004
@@ -0,0 +1,410 @@
+/*
+ * Copyright (c) 2002 Networks Associates Technology, Inc.
+ * All rights reserved.
+ *
+ * This software was developed for the FreeBSD Project by Marshall
+ * Kirk McKusick and Network Associates Laboratories, the Security
+ * Research Division of Network Associates, Inc. under DARPA/SPAWAR
+ * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS
+ * research program
+ *
+ * Copyright (c) 1982, 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The names of the authors may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)dinode.h 8.3 (Berkeley) 1/21/94
+ * $FreeBSD: /tmp/pcvs/ports/sysutils/grub/files/Attic/patch-ufs2,v 1.1 2004-02-10 22:00:02 krion Exp $
+ */
+
+#ifndef _GRUB_UFS2_H_
+#define _GRUB_UFS2_H_
+
+typedef signed char int8_t;
+typedef signed short int16_t;
+typedef signed int int32_t;
+typedef signed long long int int64_t;
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned int uint32_t;
+typedef unsigned long long int uint64_t;
+
+typedef uint8_t u_char;
+typedef uint32_t u_int;
+
+typedef uint8_t u_int8_t;
+typedef uint16_t u_int16_t;
+typedef uint32_t u_int32_t;
+typedef uint64_t u_int64_t;
+
+/*
+ * __uint* constants already defined in
+ * FreeBSD 5.x /usr/include/machine/_types.h
+ * or
+ * FreeBSD 4.x /usr/include/machine/ansi.h
+ */
+#if !defined(_MACHINE__TYPES_H_) && !defined(_MACHINE_ANSI_H_)
+typedef uint8_t __uint8_t;
+typedef uint16_t __uint16_t;
+typedef uint32_t __uint32_t;
+typedef uint64_t __uint64_t;
+#endif /* _MACHINE__TYPES_H_ */
+
+#define i_size di_size
+
+
+#define DEV_BSIZE 512
+
+/*
+ * The root inode is the root of the filesystem. Inode 0 can't be used for
+ * normal purposes and historically bad blocks were linked to inode 1, thus
+ * the root inode is 2. (Inode 1 is no longer used for this purpose, however
+ * numerous dump tapes make this assumption, so we are stuck with it).
+ */
+#define ROOTINO ((ino_t)2)
+
+/*
+ * The size of physical and logical block numbers and time fields in UFS.
+ */
+typedef int64_t ufs2_daddr_t;
+typedef int64_t ufs_lbn_t;
+typedef int64_t ufs_time_t;
+
+/* inode number */
+typedef __uint32_t ino_t;
+
+/* File permissions. */
+#define IEXEC 0000100 /* Executable. */
+#define IWRITE 0000200 /* Writeable. */
+#define IREAD 0000400 /* Readable. */
+#define ISVTX 0001000 /* Sticky bit. */
+#define ISGID 0002000 /* Set-gid. */
+#define ISUID 0004000 /* Set-uid. */
+
+/* File types. */
+#define IFMT 0170000 /* Mask of file type. */
+#define IFIFO 0010000 /* Named pipe (fifo). */
+#define IFCHR 0020000 /* Character device. */
+#define IFDIR 0040000 /* Directory file. */
+#define IFBLK 0060000 /* Block device. */
+#define IFREG 0100000 /* Regular file. */
+#define IFLNK 0120000 /* Symbolic link. */
+#define IFSOCK 0140000 /* UNIX domain socket. */
+#define IFWHT 0160000 /* Whiteout. */
+
+/*
+ * A dinode contains all the meta-data associated with a UFS2 file.
+ * This structure defines the on-disk format of a dinode. Since
+ * this structure describes an on-disk structure, all its fields
+ * are defined by types with precise widths.
+ */
+
+#define NXADDR 2 /* External addresses in inode. */
+#define NDADDR 12 /* Direct addresses in inode. */
+#define NIADDR 3 /* Indirect addresses in inode. */
+
+struct ufs2_dinode {
+ u_int16_t di_mode; /* 0: IFMT, permissions; see below. */
+ int16_t di_nlink; /* 2: File link count. */
+ u_int32_t di_uid; /* 4: File owner. */
+ u_int32_t di_gid; /* 8: File group. */
+ u_int32_t di_blksize; /* 12: Inode blocksize. */
+ u_int64_t di_size; /* 16: File byte count. */
+ u_int64_t di_blocks; /* 24: Bytes actually held. */
+ ufs_time_t di_atime; /* 32: Last access time. */
+ ufs_time_t di_mtime; /* 40: Last modified time. */
+ ufs_time_t di_ctime; /* 48: Last inode change time. */
+ ufs_time_t di_birthtime; /* 56: Inode creation time. */
+ int32_t di_mtimensec; /* 64: Last modified time. */
+ int32_t di_atimensec; /* 68: Last access time. */
+ int32_t di_ctimensec; /* 72: Last inode change time. */
+ int32_t di_birthnsec; /* 76: Inode creation time. */
+ int32_t di_gen; /* 80: Generation number. */
+ u_int32_t di_kernflags; /* 84: Kernel flags. */
+ u_int32_t di_flags; /* 88: Status flags (chflags). */
+ int32_t di_extsize; /* 92: External attributes block. */
+ ufs2_daddr_t di_extb[NXADDR];/* 96: External attributes block. */
+ ufs2_daddr_t di_db[NDADDR]; /* 112: Direct disk blocks. */
+ ufs2_daddr_t di_ib[NIADDR]; /* 208: Indirect disk blocks. */
+ int64_t di_spare[3]; /* 232: Reserved; currently unused */
+};
+
+#define MAXNAMLEN 255
+
+struct direct {
+ u_int32_t d_ino; /* inode number of entry */
+ u_int16_t d_reclen; /* length of this record */
+ u_int8_t d_type; /* file type, see below */
+ u_int8_t d_namlen; /* length of string in d_name */
+ char d_name[MAXNAMLEN + 1];/* name with length <= MAXNAMLEN */
+};
+
+/*
+ * File types
+ */
+#define DT_UNKNOWN 0
+#define DT_FIFO 1
+#define DT_CHR 2
+#define DT_DIR 4
+#define DT_BLK 6
+#define DT_REG 8
+#define DT_LNK 10
+#define DT_SOCK 12
+#define DT_WHT 14
+
+#define SBLOCK_UFS2 65536
+#define SBLOCKSIZE 8192
+
+#define MAXMNTLEN 512
+
+#define NOCSPTRS ((128 / sizeof(void *)) - 4)
+
+/*
+ * The maximum number of snapshot nodes that can be associated
+ * with each filesystem. This limit affects only the number of
+ * snapshot files that can be recorded within the superblock so
+ * that they can be found when the filesystem is mounted. However,
+ * maintaining too many will slow the filesystem performance, so
+ * having this limit is a good idea.
+ */
+#define FSMAXSNAP 20
+
+/*
+ * Per cylinder group information; summarized in blocks allocated
+ * from first cylinder group data blocks. These blocks have to be
+ * read in from fs_csaddr (size fs_cssize) in addition to the
+ * super block.
+ */
+struct csum {
+ int32_t cs_ndir; /* number of directories */
+ int32_t cs_nbfree; /* number of free blocks */
+ int32_t cs_nifree; /* number of free inodes */
+ int32_t cs_nffree; /* number of free frags */
+};
+
+struct csum_total {
+ int64_t cs_ndir; /* number of directories */
+ int64_t cs_nbfree; /* number of free blocks */
+ int64_t cs_nifree; /* number of free inodes */
+ int64_t cs_nffree; /* number of free frags */
+ int64_t cs_numclusters; /* number of free clusters */
+ int64_t cs_spare[3]; /* future expansion */
+};
+
+/*
+ * Super block for an FFS filesystem.
+ */
+struct fs {
+ int32_t fs_firstfield; /* historic filesystem linked list, */
+ int32_t fs_unused_1; /* used for incore super blocks */
+ int32_t fs_sblkno; /* offset of super-block in filesys */
+ int32_t fs_cblkno; /* offset of cyl-block in filesys */
+ int32_t fs_iblkno; /* offset of inode-blocks in filesys */
+ int32_t fs_dblkno; /* offset of first data after cg */
+ int32_t fs_old_cgoffset; /* cylinder group offset in cylinder */
+ int32_t fs_old_cgmask; /* used to calc mod fs_ntrak */
+ int32_t fs_old_time; /* last time written */
+ int32_t fs_old_size; /* number of blocks in fs */
+ int32_t fs_old_dsize; /* number of data blocks in fs */
+ int32_t fs_ncg; /* number of cylinder groups */
+ int32_t fs_bsize; /* size of basic blocks in fs */
+ int32_t fs_fsize; /* size of frag blocks in fs */
+ int32_t fs_frag; /* number of frags in a block in fs */
+/* these are configuration parameters */
+ int32_t fs_minfree; /* minimum percentage of free blocks */
+ int32_t fs_old_rotdelay; /* num of ms for optimal next block */
+ int32_t fs_old_rps; /* disk revolutions per second */
+/* these fields can be computed from the others */
+ int32_t fs_bmask; /* ``blkoff'' calc of blk offsets */
+ int32_t fs_fmask; /* ``fragoff'' calc of frag offsets */
+ int32_t fs_bshift; /* ``lblkno'' calc of logical blkno */
+ int32_t fs_fshift; /* ``numfrags'' calc number of frags */
+/* these are configuration parameters */
+ int32_t fs_maxcontig; /* max number of contiguous blks */
+ int32_t fs_maxbpg; /* max number of blks per cyl group */
+/* these fields can be computed from the others */
+ int32_t fs_fragshift; /* block to frag shift */
+ int32_t fs_fsbtodb; /* fsbtodb and dbtofsb shift constant */
+ int32_t fs_sbsize; /* actual size of super block */
+ int32_t fs_spare1[2]; /* old fs_csmask */
+ /* old fs_csshift */
+ int32_t fs_nindir; /* value of NINDIR */
+ int32_t fs_inopb; /* value of INOPB */
+ int32_t fs_old_nspf; /* value of NSPF */
+/* yet another configuration parameter */
+ int32_t fs_optim; /* optimization preference, see below */
+ int32_t fs_old_npsect; /* # sectors/track including spares */
+ int32_t fs_old_interleave; /* hardware sector interleave */
+ int32_t fs_old_trackskew; /* sector 0 skew, per track */
+ int32_t fs_id[2]; /* unique filesystem id */
+/* sizes determined by number of cylinder groups and their sizes */
+ int32_t fs_old_csaddr; /* blk addr of cyl grp summary area */
+ int32_t fs_cssize; /* size of cyl grp summary area */
+ int32_t fs_cgsize; /* cylinder group size */
+ int32_t fs_spare2; /* old fs_ntrak */
+ int32_t fs_old_nsect; /* sectors per track */
+ int32_t fs_old_spc; /* sectors per cylinder */
+ int32_t fs_old_ncyl; /* cylinders in filesystem */
+ int32_t fs_old_cpg; /* cylinders per group */
+ int32_t fs_ipg; /* inodes per group */
+ int32_t fs_fpg; /* blocks per group * fs_frag */
+/* this data must be re-computed after crashes */
+ struct csum fs_old_cstotal; /* cylinder summary information */
+/* these fields are cleared at mount time */
+ int8_t fs_fmod; /* super block modified flag */
+ int8_t fs_clean; /* filesystem is clean flag */
+ int8_t fs_ronly; /* mounted read-only flag */
+ int8_t fs_old_flags; /* old FS_ flags */
+ u_char fs_fsmnt[MAXMNTLEN]; /* name mounted on */
+/* these fields retain the current block allocation info */
+ int32_t fs_cgrotor; /* last cg searched */
+ void *fs_ocsp[NOCSPTRS]; /* padding; was list of fs_cs buffers */
+ u_int8_t *fs_contigdirs; /* # of contiguously allocated dirs */
+ struct csum *fs_csp; /* cg summary info buffer for fs_cs */
+ int32_t *fs_maxcluster; /* max cluster in each cyl group */
+ u_int *fs_active; /* used by snapshots to track fs */
+ int32_t fs_old_cpc; /* cyl per cycle in postbl */
+ int32_t fs_maxbsize; /* maximum blocking factor permitted */
+ int64_t fs_sparecon64[17]; /* old rotation block list head */
+ int64_t fs_sblockloc; /* byte offset of standard superblock */
+ struct csum_total fs_cstotal; /* cylinder summary information */
+ ufs_time_t fs_time; /* last time written */
+ int64_t fs_size; /* number of blocks in fs */
+ int64_t fs_dsize; /* number of data blocks in fs */
+ ufs2_daddr_t fs_csaddr; /* blk addr of cyl grp summary area */
+ int64_t fs_pendingblocks; /* blocks in process of being freed */
+ int32_t fs_pendinginodes; /* inodes in process of being freed */
+ int32_t fs_snapinum[FSMAXSNAP];/* list of snapshot inode numbers */
+ int32_t fs_avgfilesize; /* expected average file size */
+ int32_t fs_avgfpdir; /* expected # of files per directory */
+ int32_t fs_save_cgsize; /* save real cg size to use fs_bsize */
+ int32_t fs_sparecon32[26]; /* reserved for future constants */
+ int32_t fs_flags; /* see FS_ flags below */
+ int32_t fs_contigsumsize; /* size of cluster summary array */
+ int32_t fs_maxsymlinklen; /* max length of an internal symlink */
+ int32_t fs_old_inodefmt; /* format of on-disk inodes */
+ u_int64_t fs_maxfilesize; /* maximum representable file size */
+ int64_t fs_qbmask; /* ~fs_bmask for use with 64-bit size */
+ int64_t fs_qfmask; /* ~fs_fmask for use with 64-bit size */
+ int32_t fs_state; /* validate fs_clean field */
+ int32_t fs_old_postblformat; /* format of positional layout tables */
+ int32_t fs_old_nrpos; /* number of rotational positions */
+ int32_t fs_spare5[2]; /* old fs_postbloff */
+ /* old fs_rotbloff */
+ int32_t fs_magic; /* magic number */
+};
+
+/*
+ * Filesystem identification
+ */
+#define FS_UFS2_MAGIC 0x19540119 /* UFS2 fast filesystem magic number */
+
+/*
+ * Turn filesystem block numbers into disk block addresses.
+ * This maps filesystem blocks to device size blocks.
+ */
+#define fsbtodb(fs, b) ((b) << (fs)->fs_fsbtodb)
+#define dbtofsb(fs, b) ((b) >> (fs)->fs_fsbtodb)
+
+/*
+ * Cylinder group macros to locate things in cylinder groups.
+ * They calc filesystem addresses of cylinder group data structures.
+ */
+#define cgbase(fs, c) ((ufs2_daddr_t)((fs)->fs_fpg * (c)))
+#define cgimin(fs, c) (cgstart(fs, c) + (fs)->fs_iblkno) /* inode blk */
+#define cgstart(fs, c) \
+ ((fs)->fs_magic == FS_UFS2_MAGIC ? cgbase(fs, c) : \
+ (cgbase(fs, c) + (fs)->fs_old_cgoffset * ((c) & ~((fs)->fs_old_cgmask))))
+
+/*
+ * Macros for handling inode numbers:
+ * inode number to filesystem block offset.
+ * inode number to cylinder group number.
+ * inode number to filesystem block address.
+ */
+#define ino_to_cg(fs, x) ((x) / (fs)->fs_ipg)
+#define ino_to_fsba(fs, x) \
+ ((ufs2_daddr_t)(cgimin(fs, ino_to_cg(fs, x)) + \
+ (blkstofrags((fs), (((x) % (fs)->fs_ipg) / INOPB(fs))))))
+#define ino_to_fsbo(fs, x) ((x) % INOPB(fs))
+
+/*
+ * The following macros optimize certain frequently calculated
+ * quantities by using shifts and masks in place of divisions
+ * modulos and multiplications.
+ */
+#define blkoff(fs, loc) /* calculates (loc % fs->fs_bsize) */ \
+ ((loc) & (fs)->fs_qbmask)
+
+/* Use this only when `blk' is known to be small, e.g., < NDADDR. */
+#define smalllblktosize(fs, blk) /* calculates (blk * fs->fs_bsize) */ \
+ ((blk) << (fs)->fs_bshift)
+
+
+#define lblkno(fs, loc) /* calculates (loc / fs->fs_bsize) */ \
+ ((loc) >> (fs)->fs_bshift)
+
+#define fragroundup(fs, size) /* calculates roundup(size, fs->fs_fsize) */ \
+ (((size) + (fs)->fs_qfmask) & (fs)->fs_fmask)
+
+#define fragstoblks(fs, frags) /* calculates (frags / fs->fs_frag) */ \
+ ((frags) >> (fs)->fs_fragshift)
+#define blkstofrags(fs, blks) /* calculates (blks * fs->fs_frag) */ \
+ ((blks) << (fs)->fs_fragshift)
+#define fragnum(fs, fsb) /* calculates (fsb % fs->fs_frag) */ \
+ ((fsb) & ((fs)->fs_frag - 1))
+#define blknum(fs, fsb) /* calculates rounddown(fsb, fs->fs_frag) */ \
+ ((fsb) &~ ((fs)->fs_frag - 1))
+
+/*
+ * Determining the size of a file block in the filesystem.
+ */
+#define blksize(fs, ip, lbn) \
+ (((lbn) >= NDADDR || (ip)->i_size >= smalllblktosize(fs, (lbn) + 1)) \
+ ? (fs)->fs_bsize \
+ : (fragroundup(fs, blkoff(fs, (ip)->i_size))))
+#define sblksize(fs, size, lbn) \
+ (((lbn) >= NDADDR || (size) >= ((lbn) + 1) << (fs)->fs_bshift) \
+ ? (fs)->fs_bsize \
+ : (fragroundup(fs, blkoff(fs, (size)))))
+
+
+/*
+ * Number of inodes in a secondary storage block/fragment.
+ */
+#define INOPB(fs) ((fs)->fs_inopb)
+#define INOPF(fs) ((fs)->fs_inopb >> (fs)->fs_fragshift)
+
+/*
+ * Number of indirects in a filesystem block.
+ */
+#define NINDIR(fs) ((fs)->fs_nindir)
+
+#endif /* _GRUB_UFS2_H_ */
--- util/grub-install.in.orig Wed Feb 11 00:31:26 2004
+++ util/grub-install.in Wed Feb 11 00:31:58 2004
@@ -105,11 +105,11 @@
tmp_disk=`echo "$1" | sed 's%\([sh]d[0-9]*\).*%\1%'`
tmp_part=`echo "$1" | sed "s%$tmp_disk%%"` ;;
freebsd*)
- tmp_disk=`echo "$1" | sed 's%r\{0,1\}\([saw]d[0-9]*\).*$%r\1%' \
- | sed 's%r\{0,1\}\(da[0-9]*\).*$%r\1%'`
+ tmp_disk=`echo "$1" | sed 's%\([saw]d[0-9]*\).*$%\1%' \
+ | sed 's%\(da[0-9]*\).*$%\1%'`
tmp_part=`echo "$1" \
- | sed "s%.*/r\{0,1\}[saw]d[0-9]\(s[0-9]*[a-h]\)%\1%" \
- | sed "s%.*/r\{0,1\}da[0-9]\(s[0-9]*[a-h]\)%\1%"`
+ | sed "s%.*/[saw]d[0-9]\(s[0-9]*[a-h]\)%\1%" \
+ | sed "s%.*/da[0-9]\(s[0-9]*[a-h]\)%\1%"`
;;
netbsd*)
tmp_disk=`echo "$1" | sed 's%r\{0,1\}\([sw]d[0-9]*\).*$%r\1d%' \