forked from Lainports/freebsd-ports
9523 lines
251 KiB
Text
9523 lines
251 KiB
Text
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%' \
|