diff options
author | Kirill Ponomarev <krion@FreeBSD.org> | 2004-02-10 22:00:02 +0000 |
---|---|---|
committer | Kirill Ponomarev <krion@FreeBSD.org> | 2004-02-10 22:00:02 +0000 |
commit | b74193bd53e81b231b9ba6095556d4d81d259240 (patch) | |
tree | b0abd5d0864a2eecce98229bab1247a508178477 /sysutils/grub | |
parent | 40b275372dbfc66a2e36008da98e7d17b20dabd4 (diff) | |
download | ports-b74193bd53e81b231b9ba6095556d4d81d259240.tar.gz ports-b74193bd53e81b231b9ba6095556d4d81d259240.zip |
Notes
Diffstat (limited to 'sysutils/grub')
-rw-r--r-- | sysutils/grub/Makefile | 34 | ||||
-rw-r--r-- | sysutils/grub/distinfo | 1 | ||||
-rw-r--r-- | sysutils/grub/files/patch-ufs2 | 9523 | ||||
-rw-r--r-- | sysutils/grub/pkg-message | 2 | ||||
-rw-r--r-- | sysutils/grub/pkg-plist | 17 |
5 files changed, 9541 insertions, 36 deletions
diff --git a/sysutils/grub/Makefile b/sysutils/grub/Makefile index b61bf4dec1a4..facc3cd1ec6e 100644 --- a/sysutils/grub/Makefile +++ b/sysutils/grub/Makefile @@ -7,35 +7,35 @@ PORTNAME= grub PORTVERSION= 0.94 -PORTREVISION= 2 +PORTREVISION= 3 CATEGORIES= sysutils MASTER_SITES= ftp://alpha.gnu.org/gnu/grub/ MAINTAINER= sem@ciam.ru COMMENT= GRand Unified Bootloader -GNU_CONFIGURE= yes -USE_GMAKE= yes +USE_AUTOMAKE_VER= 17 +AUTOMAKE_ENV= AUTOCONF=${AUTOCONF} +USE_AUTOCONF_VER= 257 +GNU_CONFIGURE= yes +USE_GMAKE= yes CONFIGURE_TARGET= --build=${MACHINE_ARCH}-freebsd-freebsd${OSREL} -ONLY_FOR_ARCHS= i386 +ONLY_FOR_ARCHS= i386 + +GRUB_DIR= ${DATADIR:C|^${PREFIX}/||}/i386-freebsd MAN1= mbchk.1 MAN8= grub.8 grub-install.8 grub-md5-crypt.8 grub-terminfo.8 INFO= grub multiboot +PLIST_DIRS= ${GRUB_DIR} ${DATADIR:C|^${PREFIX}/||} +PLIST_FILES= bin/mbchk sbin/grub sbin/grub-install sbin/grub-md5-crypt \ + sbin/grub-terminfo ${GRUB_DIR}/stage1 ${GRUB_DIR}/stage2 +.for f in e2fs fat ffs jfs minix reiserfs ufs2 vstafs xfs +PLIST_FILES+= ${GRUB_DIR}/${f}_stage1_5 +.endfor -#.if defined(WITH_SPLASHIMAGE) -#PATCH_SITES= http://people.redhat.com/~katzj/grub/patches/ -#PATCHFILES= ${DISTNAME}-vga16.patch ${DISTNAME}-splashimagehelp.patch -#PATCH_DIST_STRIP= -p1 -#USE_AUTOCONF= yes -#.else -#pre-fetch: -# @${ECHO_MSG} -# @${ECHO_MSG} "You may build grub with splash image support by" -# @${ECHO_MSG} "defining WITH_SPLASHIMAGE." -# @${ECHO_MSG} -# @sleep 2 -#.endif +pre-configure: + @cd ${WRKSRC}; ${ACLOCAL} post-install: @${CAT} ${PKGMESSAGE} diff --git a/sysutils/grub/distinfo b/sysutils/grub/distinfo index 446046f2ebac..1dbcdcb2acd9 100644 --- a/sysutils/grub/distinfo +++ b/sysutils/grub/distinfo @@ -1 +1,2 @@ MD5 (grub-0.94.tar.gz) = 299672a99cf59656e653d8ffd7851b56 +SIZE (grub-0.94.tar.gz) = 923518 diff --git a/sysutils/grub/files/patch-ufs2 b/sysutils/grub/files/patch-ufs2 new file mode 100644 index 000000000000..fcf637cabeef --- /dev/null +++ b/sysutils/grub/files/patch-ufs2 @@ -0,0 +1,9523 @@ +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 (§or, &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, ++ ¤t_partition, ¤t_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 *) ¤t_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 *) ¤t_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%' \ diff --git a/sysutils/grub/pkg-message b/sysutils/grub/pkg-message index 7821a1621f8f..65c7bd33bb12 100644 --- a/sysutils/grub/pkg-message +++ b/sysutils/grub/pkg-message @@ -4,6 +4,4 @@ of your hard drive. To do this, or to use it with a floppy disk, you will need to read the info page using 'info grub'. - -Warning! GRUB does not (yet) support UFS2. ########################################################### diff --git a/sysutils/grub/pkg-plist b/sysutils/grub/pkg-plist deleted file mode 100644 index 62fb4471fad0..000000000000 --- a/sysutils/grub/pkg-plist +++ /dev/null @@ -1,17 +0,0 @@ -bin/mbchk -sbin/grub -sbin/grub-install -sbin/grub-md5-crypt -sbin/grub-terminfo -share/grub/i386-freebsd/e2fs_stage1_5 -share/grub/i386-freebsd/fat_stage1_5 -share/grub/i386-freebsd/ffs_stage1_5 -share/grub/i386-freebsd/jfs_stage1_5 -share/grub/i386-freebsd/minix_stage1_5 -share/grub/i386-freebsd/reiserfs_stage1_5 -share/grub/i386-freebsd/stage1 -share/grub/i386-freebsd/stage2 -share/grub/i386-freebsd/vstafs_stage1_5 -share/grub/i386-freebsd/xfs_stage1_5 -@dirrm share/grub/i386-freebsd -@dirrm share/grub |