.gear/rules | 2 + .../tags/607d849b5fb32b41822516380089de50078ed12b | 6 + .gear/tags/list | 1 + Makefile.am | 1 + configure.ac | 3 +- docs/grub-install.8 | 2 + docs/grub.texi | 61 ++- grub.spec | 323 +++++++ grub/asmstub.c | 52 +- grub/main.c | 2 +- grubonce | 57 ++ lib/device.c | 269 ++++++- netboot/config.c | 12 + netboot/fsys_tftp.c | 4 +- netboot/i82586.c | 2 +- netboot/main.c | 4 +- netboot/pci.h | 4 + stage1/Makefile.am | 2 +- stage1/stage1.S | 11 +- stage2/Makefile.am | 2 +- stage2/asm.S | 371 ++++++++- stage2/boot.c | 7 +- stage2/builtins.c | 148 +++- stage2/disk_io.c | 39 +- stage2/filesys.h | 40 +- stage2/fsys_ext2fs.c | 39 +- stage2/fsys_fat.c | 26 +- stage2/fsys_ffs.c | 20 +- stage2/fsys_iso9660.c | 14 +- stage2/fsys_jfs.c | 14 +- stage2/fsys_minix.c | 28 +- stage2/fsys_reiserfs.c | 18 +- stage2/fsys_ufs2.c | 16 +- stage2/fsys_vstafs.c | 17 +- stage2/fsys_xfs.c | 13 +- stage2/iso9660.h | 4 +- stage2/pc_slice.h | 2 + stage2/shared.h | 60 ++- stage2/stage2.c | 896 +++++++++++++++++++- util/grub-install.in | 278 +++++-- util/grub-md5-crypt.in | 2 +- util/mbchk.c | 4 +- 42 files changed, 2534 insertions(+), 342 deletions(-) diff --git a/.gear/rules b/.gear/rules new file mode 100644 index 0000000..f78a96e --- /dev/null +++ b/.gear/rules @@ -0,0 +1,2 @@ +tar: @name@-@version@:. +diff: @name@-@version@:. . diff --git a/.gear/tags/607d849b5fb32b41822516380089de50078ed12b b/.gear/tags/607d849b5fb32b41822516380089de50078ed12b new file mode 100644 index 0000000..c6739e7 --- /dev/null +++ b/.gear/tags/607d849b5fb32b41822516380089de50078ed12b @@ -0,0 +1,6 @@ +object bc19bc026c057091d3ff25c0312afd200a153ef8 +type commit +tag grub-0.97 +tagger Alexey I. Froloff 1202825111 +0300 + +grub 0.97 diff --git a/.gear/tags/list b/.gear/tags/list new file mode 100644 index 0000000..b403ab4 --- /dev/null +++ b/.gear/tags/list @@ -0,0 +1 @@ +607d849b5fb32b41822516380089de50078ed12b grub-0.97 diff --git a/Makefile.am b/Makefile.am index 63a9a4f..202a9d1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2,3 +2,4 @@ AUTOMAKE_OPTIONS = 1.7 gnu SUBDIRS = netboot stage2 stage1 lib grub util docs EXTRA_DIST = BUGS MAINTENANCE +pkgdatadir=$(datadir) diff --git a/configure.ac b/configure.ac index bb9e1d9..dfd5cc6 100644 --- a/configure.ac +++ b/configure.ac @@ -60,8 +60,7 @@ AC_PROG_CC _AM_DEPENDENCIES(CC) dnl Because recent automake complains about AS, set it here. -CCAS="$CC" -AC_SUBST(CCAS) +AM_PROG_AS AC_ARG_WITH(binutils, [ --with-binutils=DIR search the directory DIR to find binutils]) diff --git a/docs/grub-install.8 b/docs/grub-install.8 index ac588a3..accff22 100644 --- a/docs/grub-install.8 +++ b/docs/grub-install.8 @@ -30,6 +30,8 @@ BIOS .TP \fB\-\-recheck\fR probe a device map even if it already exists + +This option is unreliable and its use is strongly discouraged. .PP INSTALL_DEVICE can be a GRUB device name or a system device filename. .PP diff --git a/docs/grub.texi b/docs/grub.texi index 51d330a..18e3736 100644 --- a/docs/grub.texi +++ b/docs/grub.texi @@ -2118,8 +2118,10 @@ These commands can only be used in the menu: * default:: Set the default entry * fallback:: Set the fallback entry * hiddenmenu:: Hide the menu interface +* gfxmenu:: Use graphical menu interface * timeout:: Set the timeout * title:: Start a menu entry +* wildcard:: Define a wildcard boot entry @end menu @@ -2150,6 +2152,15 @@ fallback entry numbers. @end deffn +@node gfxmenu +@subsection gfxmenu + +@deffn Command gfxmenu file +Use the graphical menu interface. The graphics data are taken from +@var{file} and must be created using 'mkbootmsg' from the gfxboot package. +@end deffn + + @node hiddenmenu @subsection hiddenmenu @@ -2180,6 +2191,42 @@ the line, starting with the first non-space character. @end deffn +@node wildcard +@subsection wildcard + +@deffn Command wildcard pathname +Treat this boot entry as a wildcard entry: The +wildcard, title, kernel, and initrd commands (see @ref{Menu-specific +commands} and @ref{Command-line and menu entry commands}) each have an +asterisk (*) in their value. A filename match is performed on the +@var{pathname} of the wildcard command. For each match, the entire boot +entry is duplicated. The part of the filename whcih matches the asterisk +in the wildcard command replaces the asterisks in the title, kernel, and +initrd commands. For example, with the files vmlinuz-2.6.5-1 and +vmlinuz-2.6.8-8 below (hd0,7)/boot, the following entry in the stage 2 +configuration file: + +@example +title Linux-* + wildcard (hd0,7)/boot/vmlinuz-* + kernel (hd0,7)/boot/vmlinuz-* root=/dev/hda8 + initrd (hd0,7)/boot/initrd-* +@end example + +would expand as follows: + +@example +title Linux-2.6.5-1 + wildcard (hd0,7)/boot/vmlinuz-2.6.5-1 + kernel (hd0,7)/boot/vmlinuz-2.6.5-1 root=/dev/hda8 + initrd (hd0,7)/boot/initrd-2.6.5-1 +title Linux-2.6.8-8 + wildcard (hd0,7)/boot/vmlinuz-2.6.8-8 + kernel (hd0,7)/boot/vmlinuz-2.6.8-8 root=/dev/hda8 + initrd (hd0,7)/boot/initrd-2.6.8-8 +@end example +@end deffn + @node General commands @section The list of general commands @@ -2909,7 +2956,7 @@ appropriate parameters in the Linux setup area in memory. See also @node install @subsection install -@deffn Command install [@option{--force-lba}] [@option{--stage2=os_stage2_file}] stage1_file [@option{d}] dest_dev stage2_file [addr] [@option{p}] [config_file] [real_config_file] +@deffn Command install [@option{--force-lba[=off]}] [@option{--stage2=os_stage2_file}] stage1_file [@option{d}] dest_dev stage2_file [addr] [@option{p}] [config_file] [real_config_file] This command is fairly complex, and you should not use this command unless you are familiar with GRUB. Use @command{setup} (@pxref{setup}) instead. @@ -2956,6 +3003,13 @@ HP Vectra XU 6/200 BIOS version GG.06.11 bitmap even if they do have the support. So GRUB provides a solution to ignore the wrong bitmap, that is, the option @option{--force-lba}. Don't use this option if you know that your BIOS doesn't have LBA support. +On the other hand there is at least one known BIOS that does the opposite, +it claims to support LBA and then fails to provide it. Iff you have an +Adaptec 2940 with BIOS revision 1.21 ( newer ones just work and older ones +don't make the false claim ), or otherwise experience grub hanging +after stage1, you can try to use the option @option{--force-lba=off}, +as long as all disk blocks involved in booting reside +within the first 1024 cylinders. @strong{Caution3:} You must specify the option @option{--stage2} in the grub shell, if you cannot unmount the filesystem where your stage2 file @@ -3702,8 +3756,9 @@ Use @var{file} as the grub shell. You can append arbitrary options to @item --recheck Recheck the device map, even if @file{/boot/grub/device.map} already -exists. You should use this option whenever you add/remove a disk -into/from your computer. +exists. + +This option is unreliable and its use is strongly discouraged. @end table diff --git a/grub.spec b/grub.spec new file mode 100644 index 0000000..5b6b68a --- /dev/null +++ b/grub.spec @@ -0,0 +1,323 @@ +Name: grub +Version: 0.97 +Release: alt3 + +Summary: GRand Unified Bootloader +Group: System/Kernel and hardware +License: GPL +URL: http://www.gnu.org/software/grub/grub.en.html + +ExclusiveArch: %ix86 + +Packager: Sir Raorn + +Source: ftp://alpha.gnu.org/gnu/grub/%name-%version.tar +Patch: %name-%version-%release.patch + +Provides: %name-doc = %version, %name-graph = %version +Obsoletes: %name-doc, %name-graph + +# Automatically added by buildreq on Mon Feb 25 2008 +BuildRequires: libncurses-devel tetex-latex + +##BuildRequires: libncurses-devel reiser4progs-minimal-devel tetex-latex + +%package utils +Group: System/Kernel and hardware +Summary: Additional utilites for %name + +%description +GNU GRUB is a multiboot boot loader. It was derived from GRUB. It is an +attempt to produce a boot loader for IBM PC-compatible machines that +has both the ability to be friendly to beginning or otherwise +nontechnically interested users and the flexibility to help experts in +diverse environments. It is compatible with Free/Net/OpenBSD and Linux. +It supports Win 9x/NT and OS/2 via chainloaders. It has a menu +interface and a command line interface. +It implements the Multiboot standard, which allows for flexible loading +of multiple boot images (needed for modular kernels such as the GNU +Hurd). + +%description utils +Additional utilites for %name + +%prep +%setup +%patch -p1 + +%build +%autoreconf + +%define _optlevel s +%add_optflags -DNDEBUG -W -Wall -Wpointer-arith +%add_optflags -fno-stack-protector -fno-strict-aliasing -minline-all-stringops +%ifarch x86_64 + %add_optflags -m32 -fno-asynchronous-unwind-tables +%endif +%configure \ + --bindir=/bin --sbindir=/sbin \ + --disable-auto-linux-mem-opt --enable-diskless \ + --enable-{3c50{3,7},3c5{0,2}9,3c595,3c90x,cs89x0,davicom,depca,eepro{,100},epic100} \ + --enable-{exos205,lance,ne,ne2100,ni{50,52,65}00,ns8390} \ + --enable-{rtl8139,sk-g16,smc9000,tiara,tulip,via-rhine,w89c840,wd} +%make_build +(cd stage2; mv nbgrub pxegrub ..) +mv stage2/stage2{,.netboot} +%make_build clean +%configure \ + --bindir=/bin --sbindir=/sbin \ + --prefix=/usr --infodir=%{_infodir} --mandir=%{_mandir} --datadir=%{_datadir} \ + --libexecdir=%{_libexecdir} \ + --disable-auto-linux-mem-opt +%make_build +%make_build -C docs dvi + +%install +%make_install DESTDIR=%buildroot install +mkdir -p %buildroot/boot/grub/pictures +ln -sfn . %buildroot/boot/boot +install -p {nb,pxe}grub stage2/stage2{,.netboot} %buildroot/boot/grub +install -m755 -p grubonce %buildroot/sbin +mv %buildroot%_libexecdir/grub/* %buildroot/boot/grub +rm -rf %buildroot%_libexecdir/grub +ln -sfn ../../boot/grub %buildroot%_libexecdir + +%post +if [ -x /usr/sbin/detectloader -a -f /proc/partitions ]; then + LOADER=$(/usr/sbin/detectloader) + if [ "$LOADER" = "GRUB" ]; then + if [ -f /boot/grub/install.sh ]; then + # Old grub installation + sh /boot/grub/install.sh > /dev/null + elif [ -s /etc/sysconfig/grub -a grep -q quit /etc/sysconfig/grub 1>/dev/null 2>/dev/null ]; then + # This file should be created by (future) alterator-grub + /sbin/grub --batch < /etc/sysconfig/grub > /dev/null + else + cat <&2 +Please install GRUB manually. +EOF + fi + fi +fi + +%install_info %name.info +%install_info multiboot.info + +%preun +%uninstall_info %name.info +%uninstall_info multiboot.info + + +%files +%doc BUGS NEWS TODO README THANKS AUTHORS INSTALL ChangeLog COPYING docs/menu.lst +%dir /boot/grub +%dir /boot/boot +/boot/grub/*stage* +/boot/grub/nbgrub +/boot/grub/pxegrub +%_infodir/* +%_mandir/*/* +/sbin/* +/bin/* +%exclude /sbin/grub-terminfo +%dir %_libexecdir/grub + +%files utils +/sbin/grub-terminfo + +%changelog +* Thu Feb 28 2008 Sir Raorn 0.97-alt3 +- Resurrected from orphaned +- Removed ReiserFS4 support +- Updated gfxboot support from SuSE +- mdraid/dmraid support in grub-install(8) from Fedora +- All binaries moved to /bin and /sbin +- Wildcard menu.lst entries support from SuSE + +* Tue May 30 2006 Andriy Stepanov 0.97-alt2 +- Add support for reiser4 FS + +* Wed May 24 2006 Andriy Stepanov 0.97-alt1 +- Switch to new version. Dual plain grub and with PXE support. + +* Wed Oct 20 2004 Stanislav Ievlev 0.95-alt1 +- 0.95 + +* Tue Mar 09 2004 Stanislav Ievlev 0.94-alt1 +- 0.94 + +* Wed Jan 14 2004 Stanislav Ievlev 0.93-alt2 +- fix building with gcc3.3 + +* Tue Apr 08 2003 Stanislav Ievlev 0.93-alt1 +- removed patches for old graphics support +- removed grub-splashes too +- patch (nodeprecatedflags) removed +- dump patch turned off +- new grub-terminfo utility placed into grub-utils subpackage (to avoid deps on termutils-devel) + +* Fri Feb 07 2003 Stanislav Ievlev 0.92-alt3.1 +- removed old graphics support +- removed grub-graph package (now obsolete) + +* Mon Feb 03 2003 Rider 0.92-alt3 +- GFX menu support from SuSE + +* Sun Oct 6 2002 Ivan Zakharyaschev 0.92-alt2 +- try to fix graph menu cursor clearing passed items: keypressclear patch + modified -- now it refreshes the screen multiple times + (not only the first time) + +* Mon Apr 01 2002 Stanislav Ievlev 0.91-alt5 +- Added patch to fix meminfo displaying + +* Fri Feb 15 2002 Stanislav Ievlev 0.91-alt4 +- fixed grub-install + +* Mon Feb 04 2002 Stanislav Ievlev 0.91-alt3 +- real dump terminal fix and some other patches from grub-bug mailing list + + +* Wed Jan 30 2002 Stanislav Ievlev 0.91-alt2 +- added temporary hack for the DUMB_TERMINAL mode + +* Tue Jan 29 2002 Stanislav Ievlev 0.91-alt1 +- 0.91 +- all mandrake patches removed + +* Fri Nov 16 2001 Stanislav Ievlev 0.90-alt8 +- Added latest XFS+JFS patches +- Added some RH patches + +* Wed Nov 14 2001 Dmitry V. Levin 0.90-alt7 +- Moved rebootin utility to bootloader-utils package. + +* Wed Aug 22 2001 Stanislav Ievlev 0.90-alt6 +- New image and new package (graph). + +* Wed Aug 15 2001 Stanislav Ievlev 0.90-alt5 +- Added first picture ( Junior ;) ). + +* Mon Aug 13 2001 Stanislav Ievlev 0.90-alt4 +- Added patch for JFS support + +* Wed Aug 08 2001 Stanislav Ievlev 0.90-alt3 +- Removed Mandrake's builtins. We don't need it +- Added vga16 support. +- We don't need previous hack now. All works. + Problem was: some bad function set errnum nonzero. + +* Thu Aug 02 2001 Stanislav Ievlev 0.90-alt2 +- Temporary hack: memcheck() function doesn't work. + +* Thu Jul 26 2001 Stanislav Ievlev 0.90-alt1 +- 0.90. Little changes from previous snapshot + +* Thu Jun 28 2001 Stanislav Ievlev 0.5.96.1-ipl5mdk +- Update to CVS at 20010530 + +* Mon May 28 2001 Stanislav Ievlev 0.5.96.1-ipl4mdk +- New patches from Mandrake + +* Mon Dec 18 2000 AEN +- adopted for RE + +* Mon Dec 11 2000 Pixel 0.5.96.1-2mdk +- add a call to /boot/grub/install.sh if needed + +* Sat Dec 9 2000 Pixel 0.5.96.1-1mdk +- new version + * patch fixbiosbug-nbsectors no more needed (unless you define NO_BUGGY_BIOS_IN_THE_WORLD) + +* Thu Aug 24 2000 Pixel 0.5.95-7mdk +- %%uninstall_info is fixed, yeepee :) + +* Tue Aug 22 2000 Pixel 0.5.95-6mdk +- fixbiosbug-nbsectors for some Geom Errors (warly's case) + +* Wed Aug 16 2000 Pixel 0.5.95-5mdk +- fix erroneous remove_info macro (sillyme) + +* Mon Aug 07 2000 Frederic Lepied 0.5.95-4mdk +- automatically added BuildRequires + +* Fri Jul 21 2000 Pixel 0.5.95-3mdk +- macroization, BM + +* Wed Jul 12 2000 Pixel 0.5.95-2mdk +- add a patch for ezbios nonsense + +* Mon Jul 3 2000 Pixel 0.5.95-1mdk +- new version + +* Sat May 20 2000 Pixel 0.5.94-14mdk +- add rebootin command (use altconfigfile cmd in menu.lst) +- add altconfigfile (read once) + +* Mon May 8 2000 Pixel 0.5.94-12mdk +- add reiserfs handling (missing symlink handling though) + +* Wed May 3 2000 Pixel 0.5.94-11mdk +- fix for linux-extended extended partition + +* Tue May 2 2000 Pixel 0.5.94-10mdk +- fix case of not found keytable + +* Tue Apr 18 2000 Pixel 0.5.94-9mdk +- remove a patch from caldera + +* Sun Apr 16 2000 Pixel 0.5.94-8mdk +- nicer menu +- don't add automatic mem= if one is given + +* Tue Apr 4 2000 Pixel 0.5.94-7mdk +- fix install path + +* Mon Apr 3 2000 Pixel 0.5.94-6mdk +- integrate patches from caldera + +* Fri Mar 31 2000 Pixel 0.5.94-5mdk +- re-rebuild + +* Wed Mar 29 2000 Pixel 0.5.94-4mdk +- big patch (i18n & look) + +* Sat Mar 25 2000 Pixel 0.5.94-3mdk +- split printable doc and some more to have smaller package (keep mainly info in +main package, very good one) +- cleanup install-info in %% post scripts + +* Fri Mar 24 2000 Pixel 0.5.94-2mdk +- remove unneeded patch +- use of %% { ix86 } + +* Wed Mar 22 2000 Pixel 0.5.94-1mdk +- remove now unneeded --disable-gunzip +- added option --disable-lba-support-bitmap-check +- patch for *very* buggy bioses (tells grub every hd is gigantic) +- new version + +* Mon Mar 13 2000 Pixel 0.5.93.1-7mdk +- configure with --disable-gunzip +(so that initrd is not gunzip'ed and fits in memory, that's the kernel's job anyway) + +* Wed Mar 1 2000 Pixel 0.5.93.1-6mdk +- remove no-device-check (was stupid) +- replace by something better (option --devices) + +* Tue Feb 29 2000 Pixel 0.5.93.1-5mdk +- add option no-device-check for grub binary (mainly for non-interactive use) + +* Sun Jan 16 2000 Chmouel Boudjnah 0.5.93.1-4mdk +- Add Exclusivearch. + +* Tue Jan 4 2000 Chmouel Boudjnah 0.5.93.1-3mdk +- Add install_grub_on_floppy script (thnks b.bodin). +- Add dvi docs (tknks b.bodin). + +* Mon Jan 3 2000 Chmouel Boudjnah 0.5.93.1-2mdk +- Add %%packager (thnks rpmlint). +- Remove CFLAGS. + +* Mon Jan 3 2000 Chmouel Boudjnah +- First spec file for Mandrake distribution based on debian version. diff --git a/grub/asmstub.c b/grub/asmstub.c index ab95b4b..56280b9 100644 --- a/grub/asmstub.c +++ b/grub/asmstub.c @@ -43,6 +43,8 @@ int grub_stage2 (void); #include #include +#include + #ifdef __linux__ # include /* ioctl */ # if !defined(__GLIBC__) || \ @@ -142,14 +144,30 @@ grub_stage2 (void) } assert (grub_scratch_mem == 0); - scratch = malloc (0x100000 + EXTENDED_MEMSIZE + 15); +#ifdef MAP_32BIT +#define MY_MAP_SET MAP_PRIVATE | MAP_GROWSDOWN | MAP_ANONYMOUS | MAP_32BIT +#else +#define MY_MAP_SET MAP_PRIVATE | MAP_GROWSDOWN | MAP_ANONYMOUS +#endif + scratch = mmap(NULL, + 0x100000 + EXTENDED_MEMSIZE + 15, + PROT_EXEC | PROT_READ | PROT_WRITE, + MY_MAP_SET, + -1, + 0); + assert (scratch); grub_scratch_mem = (char *) ((((int) scratch) >> 4) << 4); /* FIXME: simulate the memory holes using mprot, if available. */ assert (disks == 0); - disks = malloc (NUM_DISKS * sizeof (*disks)); + disks = mmap(NULL, + NUM_DISKS * sizeof (*disks), + PROT_EXEC | PROT_READ | PROT_WRITE, + MY_MAP_SET, + -1, + 0); assert (disks); /* Initialize DISKS. */ for (i = 0; i < NUM_DISKS; i++) @@ -215,9 +233,9 @@ grub_stage2 (void) /* Release memory. */ restore_device_map (device_map); device_map = 0; - free (disks); + munmap(disks, NUM_DISKS * sizeof (*disks)); disks = 0; - free (scratch); + munmap(scratch, 0x100000 + EXTENDED_MEMSIZE + 15); grub_scratch_mem = 0; if (serial_device) @@ -480,6 +498,32 @@ set_vbe_mode (int mode_number) return 0; } +/* graphical menu functions . */ +int +gfx_init (gfx_data_t *gfx_data) +{ + return 0; +} + +int +gfx_done (gfx_data_t *gfx_data) +{ + return 0; +} + +int +gfx_input (gfx_data_t *gfx_data, int *menu_entry) +{ + return 0; +} + +int +gfx_setup_menu (gfx_data_t *gfx_data) +{ + return 0; +} + + /* low-level timing info */ int getrtsecs (void) diff --git a/grub/main.c b/grub/main.c index dfe847e..c9476fd 100644 --- a/grub/main.c +++ b/grub/main.c @@ -44,7 +44,7 @@ int use_curses = 0; int verbose = 0; int read_only = 0; int floppy_disks = 1; -char *device_map_file = 0; +char *device_map_file = "/boot/grub/device.map"; static int default_boot_drive; static int default_install_partition; static char *default_config_file; diff --git a/grubonce b/grubonce new file mode 100755 index 0000000..84df31d --- /dev/null +++ b/grubonce @@ -0,0 +1,57 @@ +#!/usr/bin/perl + +# Keep this sort of configurable for the future. +$GRUBDIR="/boot/grub"; + +# Parse the menu file, and see if we can get a match for a maybe given arg. +open(MENU, "<$GRUBDIR/menu.lst") || die "no menu.lst in $GRUBDIR"; +$gotit = 0; +$titleno = -1; +$global_default = undef; +while() { + m,\s*default\s+(.+), && $titleno == -1 && ($global_default = $1); + next unless m,\s*title\s+(.*),i; + $title_name = $1; + $titleno++; + + if (@ARGV > 0) { + # Argument may be entirely numerical, in which case it is an index, + # or a perl RE that leads to the first title matching. + if (( $ARGV[0] =~ m,^[0-9]+$, && $titleno eq $ARGV[0] ) || + ( $ARGV[0] !~ m,^[0-9]+$, && $title_name =~ m,$ARGV[0],i) ) { + $gotit = 1; + last; + } + } else { + print "$titleno: $title_name\n"; + } +} +close(MENU); + +print "Warning: you haven't set a global default!\n" if !defined($global_default); + +# Without a command line argument, we have now listet the titles and are done. +exit 0 if @ARGV < 1; + +# Else the user wants to write the default file. We have better found a match! +if ($gotit > 0) { + print "Warning: your global default is 'saved'; changing default permanently!" + if $global_default eq "saved"; + + print "Using entry #$titleno: $title_name\n"; + + # set the magic one-time flag + $titleno |= 0x4000; + + open(DEFFILE, ">$GRUBDIR/default") || + die "Cannot open default file for writing"; + $buf = $titleno . "\0" . "\n" x 9; + syswrite(DEFFILE, $buf, 10); + close(DEFFILE); + + exit 0; +} else { + print $ARGV[0] . " not found in $GRUBDIR/menu.lst\n"; + exit 1; +} + diff --git a/lib/device.c b/lib/device.c index d0663b3..ddd4687 100644 --- a/lib/device.c +++ b/lib/device.c @@ -131,6 +131,122 @@ get_kfreebsd_version () #include #include +#if defined(__linux__) +/* The 2.6 kernel has removed all of the geometry handling for IDE drives + * that did fixups for LBA, etc. This means that the geometry we get + * with the ioctl has a good chance of being wrong. So, we get to + * also know about partition tables and try to read what the geometry + * is there. *grumble* Very closely based on code from cfdisk + */ +static void get_kernel_geometry(int fd, int *cyl, int *heads, int *sectors) { + struct hd_geometry hdg; + + if (ioctl (fd, HDIO_GETGEO, &hdg)) + return; + + *cyl = hdg.cylinders; + *heads = hdg.heads; + *sectors = hdg.sectors; +} + +struct partition { + unsigned char boot_ind; /* 0x80 - active */ + unsigned char head; /* starting head */ + unsigned char sector; /* starting sector */ + unsigned char cyl; /* starting cylinder */ + unsigned char sys_ind; /* What partition type */ + unsigned char end_head; /* end head */ + unsigned char end_sector; /* end sector */ + unsigned char end_cyl; /* end cylinder */ + unsigned char start4[4]; /* starting sector counting from 0 */ + unsigned char size4[4]; /* nr of sectors in partition */ +}; + +#define ALIGNMENT 2 +typedef union { + struct { + unsigned char align[ALIGNMENT]; + unsigned char b[SECTOR_SIZE]; + } c; + struct { + unsigned char align[ALIGNMENT]; + unsigned char buffer[0x1BE]; + struct partition part[4]; + unsigned char magicflag[2]; + } p; +} partition_table; + +#define PART_TABLE_FLAG0 0x55 +#define PART_TABLE_FLAG1 0xAA + +static void +get_partition_table_geometry(partition_table *bufp, int *cyl, int *heads, + int *sectors) { + struct partition *p; + int i,h,s,hh,ss; + int first = 1; + int bad = 0; + + if (bufp->p.magicflag[0] != PART_TABLE_FLAG0 || + bufp->p.magicflag[1] != PART_TABLE_FLAG1) { + /* Matthew Wilcox: slightly friendlier version of + fatal(_("Bad signature on partition table"), 3); + */ + fprintf(stderr, "Unknown partition table signature\n"); + return; + } + + hh = ss = 0; + for (i=0; i<4; i++) { + p = &(bufp->p.part[i]); + if (p->sys_ind != 0) { + h = p->end_head + 1; + s = (p->end_sector & 077); + if (first) { + hh = h; + ss = s; + first = 0; + } else if (hh != h || ss != s) + bad = 1; + } + } + + if (!first && !bad) { + *heads = hh; + *sectors = ss; + } +} + +static void get_linux_geometry (int fd, struct geometry *geom) { + int kern_cyl = 0, kern_head = 0, kern_sectors = 0; + int pt_cyl = 0, pt_head = 0, pt_sectors = 0; + partition_table bufp; + + get_kernel_geometry(fd, &kern_cyl, &kern_head, &kern_sectors); + + if (read(fd, bufp.c.b, SECTOR_SIZE) == SECTOR_SIZE) { + get_partition_table_geometry(&bufp, &pt_cyl, &pt_head, &pt_sectors); + } else { + fprintf(stderr, "Unable to read partition table: %s\n", strerror(errno)); + } + + if (pt_head && pt_sectors) { + int cyl_size; + + geom->heads = pt_head; + geom->sectors = pt_sectors; + cyl_size = pt_head * pt_sectors; + geom->cylinders = geom->total_sectors/cyl_size; + } else { + geom->heads = kern_head; + geom->sectors = kern_sectors; + geom->cylinders = kern_cyl; + } + + return; +} +#endif + /* Get the geometry of a drive DRIVE. */ void get_drive_geometry (struct geometry *geom, char **map, int drive) @@ -151,20 +267,16 @@ get_drive_geometry (struct geometry *geom, char **map, int drive) #if defined(__linux__) /* Linux */ { - struct hd_geometry hdg; unsigned long nr; - if (ioctl (fd, HDIO_GETGEO, &hdg)) - goto fail; - if (ioctl (fd, BLKGETSIZE, &nr)) goto fail; - - /* Got the geometry, so save it. */ - geom->cylinders = hdg.cylinders; - geom->heads = hdg.heads; - geom->sectors = hdg.sectors; + geom->total_sectors = nr; + get_linux_geometry(fd, geom); + + if (!geom->heads && !geom->cylinders && !geom->sectors) + goto fail; goto success; } @@ -403,10 +515,27 @@ get_dac960_disk_name (char *name, int controller, int drive) } static void +get_cciss_disk_name (char * name, int controller, int drive) +{ + sprintf (name, "/dev/cciss/c%dd%d", controller, drive); +} + +static void +get_cpqarray_disk_name (char * name, int controller, int drive) +{ + sprintf (name, "/dev/ida/c%dd%d", controller, drive); +} +static void get_ataraid_disk_name (char *name, int unit) { sprintf (name, "/dev/ataraid/d%c", unit + '0'); } + +static void +get_i2o_disk_name (char *name, int unit) +{ + sprintf (name, "/dev/i2o/hd%c", unit + 'a'); +} #endif /* Check if DEVICE can be read. If an error occurs, return zero, @@ -515,6 +644,7 @@ read_device_map (FILE *fp, char **map, const char *map_file) probing devices. */ char buf[1024]; /* XXX */ int line_number = 0; + int retval = 0; /* default to failure */ while (fgets (buf, sizeof (buf), fp)) { @@ -541,14 +671,14 @@ read_device_map (FILE *fp, char **map, const char *map_file) if (*ptr != '(') { show_error (line_number, "No open parenthesis found"); - return 0; + continue; } ptr++; if ((*ptr != 'f' && *ptr != 'h') || *(ptr + 1) != 'd') { show_error (line_number, "Bad drive name"); - return 0; + continue; } if (*ptr == 'f') @@ -559,7 +689,7 @@ read_device_map (FILE *fp, char **map, const char *map_file) if (drive < 0) { show_error (line_number, "Bad device number"); - return 0; + continue; } else if (drive > 127) { @@ -575,7 +705,7 @@ read_device_map (FILE *fp, char **map, const char *map_file) if (*ptr != ')') { show_error (line_number, "No close parenthesis found"); - return 0; + continue; } ptr++; @@ -586,7 +716,7 @@ read_device_map (FILE *fp, char **map, const char *map_file) if (! *ptr) { show_error (line_number, "No filename found"); - return 0; + continue; } /* Terminate the filename. */ @@ -604,9 +734,11 @@ read_device_map (FILE *fp, char **map, const char *map_file) map[drive] = strdup (ptr); assert (map[drive]); + + retval = 1; /* at least 1 drive configured successfully */ } - return 1; + return retval; } /* Initialize the device map MAP. *MAP will be allocated from the heap @@ -782,7 +914,7 @@ init_device_map (char ***map, const char *map_file, int floppy_disks) for (controller = 0; controller < 8; controller++) { - for (drive = 0; drive < 15; drive++) + for (drive = 0; drive < 32; drive++) { char name[24]; @@ -801,6 +933,90 @@ init_device_map (char ***map, const char *map_file, int floppy_disks) } } } + + /* I2O disks. */ + for (i = 0; i < 8; i++) + { + char name[16]; + + get_i2o_disk_name (name, i); + if (check_device (name)) + { + (*map)[num_hd + 0x80] = strdup (name); + assert ((*map)[num_hd + 0x80]); + + /* If the device map file is opened, write the map. */ + if (fp) + fprintf (fp, "(hd%d)\t%s\n", num_hd, name); + + num_hd++; + } + } + +#endif /* __linux__ */ + +#ifdef __linux__ + /* This is for cciss - we have + /dev/cciss/cdp. + + cciss driver currently supports up to 8 controllers, 16 logical + drives, and 7 partitions. */ + { + int controller, drive; + + for (controller = 0; controller < 8; controller++) + { + for (drive = 0; drive < 16; drive++) + { + char name[24]; + + get_cciss_disk_name (name, controller, drive); + if (check_device (name)) + { + (*map)[num_hd + 0x80] = strdup (name); + assert ((*map)[num_hd + 0x80]); + + /* If the device map file is opened, write the map. */ + if (fp) + fprintf (fp, "(hd%d)\t%s\n", num_hd, name); + + num_hd++; + } + } + } + } +#endif /* __linux__ */ + +#ifdef __linux__ + /* This is for cpqarray - we have + /dev/ida/cdp. + + cpqarray driver currently supports up to 8 controllers, 16 logical + drives, and 15 partitions. */ + { + int controller, drive; + + for (controller = 0; controller < 8; controller++) + { + for (drive = 0; drive < 15; drive++) + { + char name[24]; + + get_cpqarray_disk_name (name, controller, drive); + if (check_device (name)) + { + (*map)[num_hd + 0x80] = strdup (name); + assert ((*map)[num_hd + 0x80]); + + /* If the device map file is opened, write the map. */ + if (fp) + fprintf (fp, "(hd%d)\t%s\n", num_hd, name); + + num_hd++; + } + } + } + } #endif /* __linux__ */ /* OK, close the device map file if opened. */ @@ -831,9 +1047,11 @@ int is_disk_device (char **map, int drive) { struct stat st; + int retval; assert (map[drive] != 0); - assert (stat (map[drive], &st) == 0); + retval = stat (map[drive], &st); + assert (retval == 0); /* For now, disk devices under Linux are all block devices. */ return S_ISBLK (st.st_mode); } @@ -843,7 +1061,7 @@ write_to_partition (char **map, int drive, int partition, int sector, int size, const char *buf) { char dev[PATH_MAX]; /* XXX */ - int fd; + int fd, len, pnum; if ((partition & 0x00FF00) != 0x00FF00) { @@ -861,7 +1079,20 @@ write_to_partition (char **map, int drive, int partition, if (strcmp (dev + strlen(dev) - 5, "/disc") == 0) strcpy (dev + strlen(dev) - 5, "/part"); } - sprintf (dev + strlen(dev), "%d", ((partition >> 16) & 0xFF) + 1); + + len = strlen(dev); + pnum = ((partition >> 16) & 0xFF); + if (strncmp (dev, "/dev/disk/by-id/", 16) == 0) + { + sprintf (dev + len, "-part%d", pnum + 1); + } + else if (isdigit(dev[len-1])) + { + /* It is obviously some RAID disk: "/dev//c0d0" . "p1" */ + sprintf (dev + len, "p%d", pnum + 1); + } + else + sprintf (dev + len, "%d", pnum + 1); /* Open the partition. */ fd = open (dev, O_RDWR); diff --git a/netboot/config.c b/netboot/config.c index 3949a67..009e6cd 100644 --- a/netboot/config.c +++ b/netboot/config.c @@ -122,6 +122,14 @@ static struct pci_device pci_nic_list[] = "Intel EtherExpressPro100 ID1029", 0, 0, 0, 0}, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ID1030, "Intel Corporation 82559 InBusiness 10/100", 0, 0, 0, 0}, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ID1031, + "Intel EtherExpressPro100 ID1031", 0, 0, 0, 0}, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ID1039, + "Intel EtherExpressPro100 ID1039", 0, 0, 0, 0}, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ID103B, + "Intel 82801BD PRO/100 VM", 0, 0, 0, 0}, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ID1050, + "Intel EtherExpressPro100 82555 10/100", 0, 0, 0, 0}, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82562, "Intel EtherExpressPro100 82562EM", 0, 0, 0, 0}, #endif @@ -281,6 +289,10 @@ static struct pci_dispatch_table PCI_NIC[] = { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82559ER, eepro100_probe }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ID1029, eepro100_probe }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ID1030, eepro100_probe }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ID1031, eepro100_probe }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ID1039, eepro100_probe }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ID103B, eepro100_probe }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ID1050, eepro100_probe }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82562, eepro100_probe }, # endif /* INCLUDE_EEPRO100 */ # ifdef INCLUDE_EPIC100 diff --git a/netboot/fsys_tftp.c b/netboot/fsys_tftp.c index b0233e8..c2140a4 100644 --- a/netboot/fsys_tftp.c +++ b/netboot/fsys_tftp.c @@ -409,7 +409,7 @@ tftp_read (char *addr, int size) /* Check if the file DIRNAME really exists. Get the size and save it in FILEMAX. */ int -tftp_dir (char *dirname) +tftp_dir (char *dirname, void (*handle)(char *)) { int ch; @@ -418,7 +418,7 @@ tftp_dir (char *dirname) #endif /* In TFTP, there is no way to know what files exist. */ - if (print_possibilities) + if (handle) return 1; /* Don't know the size yet. */ diff --git a/netboot/i82586.c b/netboot/i82586.c index 15540c2..f8ec3fa 100644 --- a/netboot/i82586.c +++ b/netboot/i82586.c @@ -735,7 +735,7 @@ static unsigned char exos_i186_init[] = static int exos205_probe2(void) { unsigned short i; - unsigned short shmem[10]; + unsigned short shmem[10] = { 0,0,0,0,0,0,0,0,0,0 }; /* Fix the ISCP address and base. */ init_words[3] = scb_base; diff --git a/netboot/main.c b/netboot/main.c index 82759b6..abd9212 100644 --- a/netboot/main.c +++ b/netboot/main.c @@ -54,9 +54,9 @@ struct rom_info rom; static int vendorext_isvalid; static unsigned long netmask; -static struct bootpd_t bootp_data; +struct bootpd_t bootp_data; static unsigned long xid; -static unsigned char *end_of_rfc1533 = NULL; +unsigned char *end_of_rfc1533 = NULL; #ifndef NO_DHCP_SUPPORT #endif /* NO_DHCP_SUPPORT */ diff --git a/netboot/pci.h b/netboot/pci.h index a99dc14..cacd8de 100644 --- a/netboot/pci.h +++ b/netboot/pci.h @@ -129,6 +129,10 @@ __asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory") #define PCI_DEVICE_ID_INTEL_82559ER 0x1209 #define PCI_DEVICE_ID_INTEL_ID1029 0x1029 #define PCI_DEVICE_ID_INTEL_ID1030 0x1030 +#define PCI_DEVICE_ID_INTEL_ID1031 0x1031 +#define PCI_DEVICE_ID_INTEL_ID1039 0x1039 +#define PCI_DEVICE_ID_INTEL_ID103B 0x103B +#define PCI_DEVICE_ID_INTEL_ID1050 0x1050 #define PCI_DEVICE_ID_INTEL_82562 0x2449 #define PCI_VENDOR_ID_AMD 0x1022 #define PCI_DEVICE_ID_AMD_LANCE 0x2000 diff --git a/stage1/Makefile.am b/stage1/Makefile.am index 0afc285..16e076a 100644 --- a/stage1/Makefile.am +++ b/stage1/Makefile.am @@ -1,4 +1,4 @@ -pkglibdir = $(libdir)/$(PACKAGE)/$(host_cpu)-$(host_vendor) +pkglibdir = /usr/lib/grub nodist_pkglib_DATA = stage1 CLEANFILES = $(nodist_pkglib_DATA) diff --git a/stage1/stage1.S b/stage1/stage1.S index 985963d..886633f 100644 --- a/stage1/stage1.S +++ b/stage1/stage1.S @@ -69,9 +69,12 @@ mode: .byte 0 disk_address_packet: sectors: - .long 0 + .byte 0 + .ascii "GRU" heads: - .long 0 + .ascii "B" + .byte 0 + .word 0 cylinders: .word 0 sector_start: @@ -177,7 +180,11 @@ real_start: /* check if AH=0x42 is supported if FORCE_LBA is zero */ MOV_MEM_TO_AL(ABS(force_lba)) /* movb ABS(force_lba), %al */ testb %al, %al + /* check if LBA is forced OFF 0x80 <= %al <= 0xff */ + js chs_mode + /* or forced ON 0x01 <= %al <= 0x7f */ jnz lba_mode + /* otherwise trust BIOS int's result */ andw $1, %cx jz chs_mode diff --git a/stage2/Makefile.am b/stage2/Makefile.am index f8e6d42..33e1231 100644 --- a/stage2/Makefile.am +++ b/stage2/Makefile.am @@ -27,7 +27,7 @@ libgrub_a_CFLAGS = $(GRUB_CFLAGS) -I$(top_srcdir)/lib \ -DUSE_MD5_PASSWORDS=1 -DSUPPORT_SERIAL=1 -DSUPPORT_HERCULES=1 # Stage 2 and Stage 1.5's. -pkglibdir = $(libdir)/$(PACKAGE)/$(host_cpu)-$(host_vendor) +pkglibdir = /usr/lib/grub EXTRA_PROGRAMS = nbloader.exec pxeloader.exec diskless.exec diff --git a/stage2/asm.S b/stage2/asm.S index 34b6e7d..e2b07c0 100644 --- a/stage2/asm.S +++ b/stage2/asm.S @@ -1091,7 +1091,11 @@ ENTRY(check_int13_extensions) /* check if AH=0x42 is supported if FORCE_LBA is zero */ movb EXT_C(force_lba), %al testb %al, %al + /* check if LBA is forced OFF 0x80 <= %al <= 0xff */ + js 1f + /* or forced ON 0x01 <= %al <= 0x7f */ jnz 2f + /* otherwise trust BIOS int's result */ andw $1, %cx jnz 2f @@ -1610,48 +1614,369 @@ ENTRY(set_vbe_mode) popl %ebp ret + +/* + * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + * + * graphical menu functions + * + */ + +/* + * int gfx_init (gfx_data_t *gfx_data) + * + * init gfx things + * + * return vales: + * 0: ok + * 1: failed + * sets gfx_data->ok + */ + +ENTRY(gfx_init) + pushl %ebp + movl %esp, %ebp + + pushl %edi + pushl %esi + pushl %ebx + + movl 8(%ebp),%edx + movl %edx,%edi + leal gfx_ofs_sys_cfg(%edx),%esi + andl $0xf,%edi + shrl $4,%edx + + pushl %ebp + + call EXT_C(prot_to_real) + .code16 + + pushw %ds + movw %dx,%ds + + lcall *gfx_ofs_jmp_table + 4 * 0 (%di) + + sbbl %ebx,%ebx + negl %ebx + + popw %ds + + DATA32 call EXT_C(real_to_prot) + .code32 + + popl %ebp + + movl %ebx,%eax + xorl $1,%ebx + movl 8(%ebp),%edx + movl %ebx,gfx_ofs_ok(%edx) + + popl %ebx + popl %esi + popl %edi + + popl %ebp + ret + + +/* + * int gfx_done (gfx_data_t *gfx_data) + * + * shut down gfx things + * + * return vales: + * always 0 + * sets gfx_data->ok + */ + +ENTRY(gfx_done) + pushl %ebp + movl %esp, %ebp + + pushl %edi + pushl %esi + pushl %ebx + + movl 8(%ebp),%edx + movl %edx,%ebx + andl $0xf,%ebx + shrl $4,%edx + + pushl %ebp + + call EXT_C(prot_to_real) + .code16 + + pushw %ds + + movw %dx,%ds + + lcall *gfx_ofs_jmp_table + 4 * 1 (%bx) + + popw %ds + + DATA32 call EXT_C(real_to_prot) + .code32 + + popl %ebp + + xorl %eax,%eax + movl 8(%ebp),%edx + movl %eax,gfx_ofs_ok(%edx) + + popl %ebx + popl %esi + popl %edi + + popl %ebp + ret + + +/* + * int gfx_input (gfx_data_t *gfx_data, int *menu_entry) + * + * let user enter a command line + * + * uses gfx_data->cmdline as buffer + * + * return values: + * 1: abort + * 2: boot + * menu_entry: selected entry + */ + +ENTRY(gfx_input) + pushl %ebp + movl %esp, %ebp + + pushl %edi + pushl %esi + pushl %ebx + + movl 8(%ebp),%edx + movl %edx,%ebx + leal gfx_ofs_sys_cfg(%edx),%esi + andl $0xf,%ebx + shrl $4,%edx + + pushl %ebp + + call EXT_C(prot_to_real) + .code16 + + pushw %ds + + movw %dx,%ds + + movl gfx_ofs_cmdline(%bx),%edi + movl gfx_ofs_cmdline_len(%bx),%ecx + movl gfx_ofs_timeout(%bx),%eax + imull $18,%eax + + lcall *gfx_ofs_jmp_table + 4 * 2 (%bx) + + movl %eax,%ecx + + popw %ds + + DATA32 call EXT_C(real_to_prot) + .code32 + + popl %ebp + + movl 12(%ebp),%edx + movl %ebx,(%edx) + + movl %ecx,%eax + + popl %ebx + popl %esi + popl %edi + + popl %ebp + ret + + +/* + * int gfx_setup_menu (gfx_data_t *gfx_data) + * + * draw boot menu + * + * return values: + * always 0 + */ + +/* menu entry descriptor */ +#define menu_entries 0 +#define menu_default 2 /* seg:ofs */ +#define menu_ent_list 6 /* seg:ofs */ +#define menu_ent_size 10 +#define menu_arg_list 12 /* seg:ofs */ +#define menu_arg_size 16 +#define sizeof_menu_desc 18 + +ENTRY(gfx_setup_menu) + pushl %ebp + movl %esp, %ebp + + pushl %edi + pushl %esi + pushl %ebx + + movl 8(%ebp),%edx + movl %edx,%ebx + andl $0xf,%ebx + shrl $4,%edx + + call EXT_C(prot_to_real) + .code16 + + pushw %ds + + movw %dx,%ds + shll $4,%edx + + subw $sizeof_menu_desc,%sp + movw %esp,%ebp + + movl gfx_ofs_menu_entries(%bx),%eax + movw %ax,menu_entries(%bp) + + movl gfx_ofs_menu_default_entry(%bx),%eax + subl %edx,%eax + movw %ax,menu_default(%bp) + movw %ds,menu_default+2(%bp) + + movl gfx_ofs_menu_list(%bx),%eax + subl %edx,%eax + movw %ax,menu_ent_list(%bp) + movw %ds,menu_ent_list+2(%bp) + + movl gfx_ofs_menu_entry_len(%bx),%eax + movw %ax,menu_ent_size(%bp) + + movl gfx_ofs_args_list(%bx),%eax + subl %edx,%eax + movw %ax,menu_arg_list(%bp) + movw %ds,menu_arg_list+2(%bp) + + movl gfx_ofs_args_entry_len(%bx),%eax + movw %ax,menu_arg_size(%bp) + + movl %ss,%esi + shll $4,%esi + addl %ebp,%esi + + lcall %ds: *gfx_ofs_jmp_table + 4 * 3 (%bx) + + addw $sizeof_menu_desc,%sp + + popw %ds + + DATA32 call EXT_C(real_to_prot) + .code32 + + xorl %eax,%eax + + popl %ebx + popl %esi + popl %edi + + popl %ebp + ret + + +/* + * + * end graphics stuff + * + * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + */ + /* * gateA20(int linear) * * Gate address-line 20 for high memory. * - * This routine is probably overconservative in what it does, but so what? - * - * It also eats any keystrokes in the keyboard buffer. :-( + * Try to disable the A20 gate by all means. (The argument is ignored) + * On success (the memory world is free), a -1 is returned, 0 on failure. + * It may also eat any keystrokes in the keyboard buffer. :-( */ ENTRY(gateA20) + pushl %ebx + pushl %edx + call testA20 + jnz 1f + call A20_BIOS + call testA20 + jnz 1f + call A20_PORT92 + call testA20 + jnz 1f + call A20_KBDCTL + call testA20 + jnz 1f + movl $0,%eax + jmp 2f +1: movl $-1,%eax +2: popl %edx + popl %ebx + ret + +testA20: + movl 0x500,%eax + movl 0x100500,%ebx + notl %eax + movl %eax,0x100500 + cmpl %eax,0x500 + pushfl + movl %ebx,0x100500 + notl %eax + movl %eax,0x500 + popfl + ret + +A20_BIOS: /* first, try a BIOS call */ - pushl %ebp - movl 8(%esp), %edx call EXT_C(prot_to_real) .code16 - movw $0x2400, %ax - testw %dx, %dx - jz 1f - incw %ax + movw $0x2401, %ax 1: stc int $0x15 - jnc 2f - - /* set non-zero if failed */ - movb $1, %ah - - /* save the status */ -2: movb %ah, %dl DATA32 call EXT_C(real_to_prot) .code32 - - popl %ebp - testb %dl, %dl - jnz 3f ret -3: /* use keyboard controller */ + +A20_PORT92: + /* + * try to switch gateA20 using PORT92, the "Fast A20 and Init" + * register + */ + mov $0x92, %dx + inb %dx, %al + /* skip the port92 code if it's unimplemented (read returns 0xff) */ + cmpb $0xff, %al + jz 6f + + /* set bit1, the ALT_A20_GATE bit */ + orb $2, %al +/* and $0xfd, %al */ + + /* clear the INIT_NOW bit; don't accidently reset the machine */ + and $0xfe, %al + outb %al, %dx +6: ret + + +A20_KBDCTL: + /* use keyboard controller */ pushl %eax call gloop1 @@ -1665,11 +1990,7 @@ gloopint1: jnz gloopint1 movb $KB_OUTPUT_MASK, %al - cmpb $0, 0x8(%esp) - jz gdoit - orb $KB_A20_ENABLE, %al -gdoit: outb $K_RDWR call gloop1 diff --git a/stage2/boot.c b/stage2/boot.c index 4185d23..4616572 100644 --- a/stage2/boot.c +++ b/stage2/boot.c @@ -824,8 +824,11 @@ load_initrd (char *initrd) moveto = (mbi.mem_upper + 0x400) << 10; moveto = (moveto - len) & 0xfffff000; - max_addr = (lh->header == LINUX_MAGIC_SIGNATURE && lh->version >= 0x0203 - ? lh->initrd_addr_max : LINUX_INITRD_MAX_ADDRESS); + max_addr = LINUX_INITRD_MAX_ADDRESS; + if (lh->header == LINUX_MAGIC_SIGNATURE && + lh->version >= 0x0203 && + lh->initrd_addr_max < max_addr) + max_addr = lh->initrd_addr_max; if (moveto + len >= max_addr) moveto = (max_addr - len) & 0xfffff000; diff --git a/stage2/builtins.c b/stage2/builtins.c index 3e08a86..4761af4 100644 --- a/stage2/builtins.c +++ b/stage2/builtins.c @@ -63,6 +63,8 @@ int fallback_entryno; int fallback_entries[MAX_FALLBACK_ENTRIES]; /* The number of current entry. */ int current_entryno; +/* graphics file */ +char graphics_file[64]; /* The address for Multiboot command-line buffer. */ static char *mb_cmdline; /* The password. */ @@ -455,6 +457,10 @@ chainloader_func (char *arg, int flags) *((unsigned long *) (BOOTSEC_LOCATION + BOOTSEC_BPB_HIDDEN_SECTORS)) = part_start; + /* if a new device was specified, make sure DX is passed correctly */ + if ('(' == *file) + set_device(file); + errnum = ERR_NONE; return 0; @@ -766,11 +772,11 @@ static int default_func (char *arg, int flags) { #ifndef SUPPORT_DISKLESS - if (grub_strcmp (arg, "saved") == 0) + if (grub_strcmp (arg, "saved") == 0 || (saved_entryno & 0x4000)) { - default_entry = saved_entryno; - return 0; + default_entry = saved_entryno & 0x3fff; } + else #endif /* SUPPORT_DISKLESS */ if (! safe_parse_maxint (&arg, &default_entry)) @@ -791,6 +797,22 @@ static struct builtin builtin_default = #endif }; +#ifndef SUPPORT_DISKLESS +static int savedefault_func (char *arg, int flags); +void __savedefault_once_reset() +{ + if (saved_entryno & 0x4000) + { + int saved_current_entryno = current_entryno; + grub_timeout = 0; + current_entryno = default_entry; + savedefault_func("\0", BUILTIN_SCRIPT); + current_entryno = saved_current_entryno; + saved_entryno &= 0x3fff; + } +} +#endif /* SUPPORT_DISKLESS */ + #ifdef GRUB_UTIL /* device */ @@ -1331,6 +1353,26 @@ static struct builtin builtin_fstest = }; +/* graphics */ +static int +gfxmenu_func (char *arg, int flags) +{ + memmove(graphics_file, arg, sizeof graphics_file - 1); + graphics_file[sizeof graphics_file - 1] = 0; + + return 0; +} + +static struct builtin builtin_gfxmenu = +{ + "gfxmenu", + gfxmenu_func, + BUILTIN_MENU | BUILTIN_HELP_LIST, + "gfxmenu FILE", + "Use the graphical menu from FILE." +}; + + /* geometry */ static int geometry_func (char *arg, int flags) @@ -1834,7 +1876,12 @@ install_func (char *arg, int flags) /* First, check the GNU-style long option. */ while (1) { - if (grub_memcmp ("--force-lba", arg, sizeof ("--force-lba") - 1) == 0) + if (grub_memcmp ("--force-lba=off", arg, sizeof ("--force-lba=off") - 1) == 0) + { + is_force_lba = 0xff; + arg = skip_to (0, arg); + } + else if (grub_memcmp ("--force-lba", arg, sizeof ("--force-lba") - 1) == 0) { is_force_lba = 1; arg = skip_to (0, arg); @@ -1842,9 +1889,23 @@ install_func (char *arg, int flags) #ifdef GRUB_UTIL else if (grub_memcmp ("--stage2=", arg, sizeof ("--stage2=") - 1) == 0) { + int fd; stage2_os_file = arg + sizeof ("--stage2=") - 1; arg = skip_to (0, arg); nul_terminate (stage2_os_file); + +#if defined(__linux__) && defined (FSYS_REISERFS) + if ((fd=open(stage2_os_file, O_RDONLY)) >= 0) + { + struct statfs buf; + /* see if the file sits on a reiserfs, + and try do defragment it if so. */ + fstatfs(fd, &buf); + if (buf.f_type == REISERFS_SUPER_MAGIC) + ioctl (fd, REISERFS_IOC_UNPACK, 1); + } +#endif /* __linux__ && FSYS_REISERFS */ + } #endif /* GRUB_UTIL */ else @@ -2263,7 +2324,7 @@ 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 [--stage2=STAGE2_FILE] [--force-lba[=off]] 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" @@ -2276,8 +2337,9 @@ static struct builtin builtin_install = " 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." + " for LBA mode, `--force-lba=off' will disable it completely. If the" + " option `--stage2' is specified, rewrite the Stage 2 via your OS's" + " filesystem instead of the raw device." }; @@ -3890,7 +3952,12 @@ setup_func (char *arg, int flags) /* Check if the user specifies --force-lba. */ while (1) { - if (grub_memcmp ("--force-lba", arg, sizeof ("--force-lba") - 1) == 0) + if (grub_memcmp ("--force-lba=off", arg, sizeof ("--force-lba=off") - 1) == 0) + { + is_force_lba = 0xff; + arg = skip_to (0, arg); + } + else if (grub_memcmp ("--force-lba", arg, sizeof ("--force-lba") - 1) == 0) { is_force_lba = 1; arg = skip_to (0, arg); @@ -4011,6 +4078,9 @@ setup_func (char *arg, int flags) } } + /* force buffer cache invalidation after embedding */ + buf_drive = -1; + /* Construct a string that is used by the command "install" as its arguments. */ sprint_device (installed_drive, installed_partition); @@ -4018,7 +4088,9 @@ setup_func (char *arg, int flags) #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 " : "", + is_force_lba ? + (is_force_lba == 0xff ? "--force-lba=off " : "--force-lba ") + : "", stage2_arg? stage2_arg : "", stage2_arg? " " : "", stage1, @@ -4071,17 +4143,18 @@ 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]", + "setup [--prefix=DIR] [--stage2=STAGE2_FILE] [--force-lba[=off]] 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." + " doesn't work in LBA mode, specify the option `--force-lba'. If the" + " BIOS claims to support LBA mode but really doesn't, use" + " `--force-lba=off'. 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." }; @@ -4186,7 +4259,7 @@ terminal_func (char *arg, int flags) /* If multiple terminals are specified, wait until the user pushes any key on one of the terminals. */ - if (term_bitmap & ~(1 << default_term)) + if ((term_bitmap & ~(1 << default_term)) && !(saved_entryno & 0x4000)) { int time1, time2 = -1; @@ -4792,6 +4865,49 @@ static struct builtin builtin_vbeprobe = }; +/* wildcard */ + static int +wildcard_func (char *arg, int flags) +{ +#ifdef DEBUG_WILDCARD + char *w = wildcard (arg); + + if (w) + { + while (*w) + { + grub_printf("%s ", w); + w += strlen (w) + 1; + } + grub_printf("\n"); + return 1; + } + else + print_error(); +#endif + + /* This special command is interpreted in the config file parser. */ + return 0; +} + +static struct builtin builtin_wildcard = + { + "wildcard", + wildcard_func, +#ifndef DEBUG_WILDCARD + BUILTIN_MENU, +#else + BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST, + "wildcard GLOB", + "Declare this menu entry as a wildcard entry. GLOB is a path containing" + " one asterisk. All files matching this expression are looked up; the" + " menu entry is duplicated for each match with asterisks in other" + " commands replaced by the string matching the asterisk in the wildcard" + " command." +#endif +}; + + /* The table of builtin commands. Sorted in dictionary order. */ struct builtin *builtin_table[] = { @@ -4823,6 +4939,7 @@ struct builtin *builtin_table[] = &builtin_find, &builtin_fstest, &builtin_geometry, + &builtin_gfxmenu, &builtin_halt, &builtin_help, &builtin_hiddenmenu, @@ -4880,5 +4997,6 @@ struct builtin *builtin_table[] = &builtin_unhide, &builtin_uppermem, &builtin_vbeprobe, + &builtin_wildcard, 0 }; diff --git a/stage2/disk_io.c b/stage2/disk_io.c index b9bc526..605c213 100644 --- a/stage2/disk_io.c +++ b/stage2/disk_io.c @@ -36,7 +36,6 @@ 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; @@ -128,7 +127,7 @@ int filepos; int filemax; static inline unsigned long -log2 (unsigned long word) +grub_log2 (unsigned long word) { asm volatile ("bsfl %1,%0" : "=r" (word) @@ -140,7 +139,7 @@ int rawread (int drive, int sector, int byte_offset, int byte_len, char *buf) { int slen, sectors_per_vtrack; - int sector_size_bits = log2 (buf_geom.sector_size); + int sector_size_bits = grub_log2 (buf_geom.sector_size); if (byte_len <= 0) return 1; @@ -163,7 +162,7 @@ rawread (int drive, int sector, int byte_offset, int byte_len, char *buf) } buf_drive = drive; buf_track = -1; - sector_size_bits = log2 (buf_geom.sector_size); + sector_size_bits = grub_log2 (buf_geom.sector_size); } /* Make sure that SECTOR is valid. */ @@ -1479,7 +1478,7 @@ print_completions (int is_filename, int is_completion) if (! is_completion) grub_printf (" Possible files are:"); - dir (buf); + dir (buf, print_a_completion); if (is_completion && *unique_string) { @@ -1498,7 +1497,7 @@ print_completions (int is_filename, int is_completion) *ptr = '/'; *(ptr + 1) = 0; - dir (buf); + dir (buf, print_a_completion); /* Restore the original unique value. */ unique = 1; @@ -1626,12 +1625,7 @@ grub_open (char *filename) 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)) + if (!errnum && (*(fsys_table[fsys_type].dir_func)) (filename, NULL)) { #ifndef NO_DECOMPRESSION return gunzip_test_header (); @@ -1752,7 +1746,7 @@ grub_seek (int offset) } int -dir (char *dirname) +dir (char *dirname, void (*handle)(char *)) { #ifndef NO_DECOMPRESSION compressed_file = 0; @@ -1761,19 +1755,18 @@ dir (char *dirname) if (!(dirname = setup_part (dirname))) return 0; + errnum = 0; if (*dirname != '/') errnum = ERR_BAD_FILENAME; - - if (fsys_type == NUM_FSYS) + else 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); + else + { + fsys_table[fsys_type].dir_func (dirname, handle); + if (errnum == ERR_FILE_NOT_FOUND) + errnum = 0; + } + return errnum == 0; } #endif /* STAGE1_5 */ diff --git a/stage2/filesys.h b/stage2/filesys.h index bbad8b9..9241103 100644 --- a/stage2/filesys.h +++ b/stage2/filesys.h @@ -24,7 +24,7 @@ #define FSYS_FFS_NUM 1 int ffs_mount (void); int ffs_read (char *buf, int len); -int ffs_dir (char *dirname); +int ffs_dir (char *dirname, void (*handle)(char *)); int ffs_embed (int *start_sector, int needed_sectors); #else #define FSYS_FFS_NUM 0 @@ -34,7 +34,7 @@ int ffs_embed (int *start_sector, int needed_sectors); #define FSYS_UFS2_NUM 1 int ufs2_mount (void); int ufs2_read (char *buf, int len); -int ufs2_dir (char *dirname); +int ufs2_dir (char *dirname, void (*handle)(char *)); int ufs2_embed (int *start_sector, int needed_sectors); #else #define FSYS_UFS2_NUM 0 @@ -44,7 +44,7 @@ int ufs2_embed (int *start_sector, int needed_sectors); #define FSYS_FAT_NUM 1 int fat_mount (void); int fat_read (char *buf, int len); -int fat_dir (char *dirname); +int fat_dir (char *dirname, void (*handle)(char *)); #else #define FSYS_FAT_NUM 0 #endif @@ -53,7 +53,7 @@ int fat_dir (char *dirname); #define FSYS_EXT2FS_NUM 1 int ext2fs_mount (void); int ext2fs_read (char *buf, int len); -int ext2fs_dir (char *dirname); +int ext2fs_dir (char *dirname, void (*handle)(char *)); #else #define FSYS_EXT2FS_NUM 0 #endif @@ -62,7 +62,7 @@ int ext2fs_dir (char *dirname); #define FSYS_MINIX_NUM 1 int minix_mount (void); int minix_read (char *buf, int len); -int minix_dir (char *dirname); +int minix_dir (char *dirname, void (*handle)(char *)); #else #define FSYS_MINIX_NUM 0 #endif @@ -71,8 +71,18 @@ int minix_dir (char *dirname); #define FSYS_REISERFS_NUM 1 int reiserfs_mount (void); int reiserfs_read (char *buf, int len); -int reiserfs_dir (char *dirname); +int reiserfs_dir (char *dirname, void (*handle)(char *)); int reiserfs_embed (int *start_sector, int needed_sectors); +#if defined(__linux__) && defined (GRUB_UTIL) +#include +#include +#include +#include +#include +/* from */ +#define REISERFS_SUPER_MAGIC 0x52654973 +#define REISERFS_IOC_UNPACK _IOW(0xCD,1,long) +#endif #else #define FSYS_REISERFS_NUM 0 #endif @@ -81,7 +91,7 @@ int reiserfs_embed (int *start_sector, int needed_sectors); #define FSYS_VSTAFS_NUM 1 int vstafs_mount (void); int vstafs_read (char *buf, int len); -int vstafs_dir (char *dirname); +int vstafs_dir (char *dirname, void (*handle)(char *)); #else #define FSYS_VSTAFS_NUM 0 #endif @@ -90,7 +100,7 @@ int vstafs_dir (char *dirname); #define FSYS_JFS_NUM 1 int jfs_mount (void); int jfs_read (char *buf, int len); -int jfs_dir (char *dirname); +int jfs_dir (char *dirname, void (*handle)(char *)); int jfs_embed (int *start_sector, int needed_sectors); #else #define FSYS_JFS_NUM 0 @@ -100,7 +110,7 @@ int jfs_embed (int *start_sector, int needed_sectors); #define FSYS_XFS_NUM 1 int xfs_mount (void); int xfs_read (char *buf, int len); -int xfs_dir (char *dirname); +int xfs_dir (char *dirname, void (*handle)(char *)); #else #define FSYS_XFS_NUM 0 #endif @@ -109,7 +119,7 @@ int xfs_dir (char *dirname); #define FSYS_TFTP_NUM 1 int tftp_mount (void); int tftp_read (char *buf, int len); -int tftp_dir (char *dirname); +int tftp_dir (char *dirname, void (*handle)(char *)); void tftp_close (void); #else #define FSYS_TFTP_NUM 0 @@ -119,7 +129,7 @@ void tftp_close (void); #define FSYS_ISO9660_NUM 1 int iso9660_mount (void); int iso9660_read (char *buf, int len); -int iso9660_dir (char *dirname); +int iso9660_dir (char *dirname, void (*handle)(char *)); #else #define FSYS_ISO9660_NUM 0 #endif @@ -150,16 +160,10 @@ struct fsys_entry char *name; int (*mount_func) (void); int (*read_func) (char *buf, int len); - int (*dir_func) (char *dirname); + int (*dir_func) (char *dirname, void (*print_one)(char *)); 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 --git a/stage2/fsys_ext2fs.c b/stage2/fsys_ext2fs.c index 560048f..6d46f8f 100644 --- a/stage2/fsys_ext2fs.c +++ b/stage2/fsys_ext2fs.c @@ -193,7 +193,7 @@ struct ext2_dir_entry /* ext2/super.c */ -#define log2(n) ffz(~(n)) +#define grub_log2(n) ffz(~(n)) #define EXT2_SUPER_MAGIC 0xEF53 /* include/linux/ext2_fs.h */ #define EXT2_ROOT_INO 2 /* include/linux/ext2_fs.h */ @@ -216,7 +216,7 @@ struct ext2_dir_entry /* linux/ext2_fs.h */ #define EXT2_ADDR_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (__u32)) -#define EXT2_ADDR_PER_BLOCK_BITS(s) (log2(EXT2_ADDR_PER_BLOCK(s))) +#define EXT2_ADDR_PER_BLOCK_BITS(s) (grub_log2(EXT2_ADDR_PER_BLOCK(s))) /* linux/ext2_fs.h */ #define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_log_block_size + 10) @@ -257,6 +257,8 @@ ext2fs_mount (void) if ((((current_drive & 0x80) || (current_slice != 0)) && (current_slice != PC_SLICE_TYPE_EXT2FS) && (current_slice != PC_SLICE_TYPE_LINUX_RAID) + && (current_slice != PC_SLICE_TYPE_ZEN) + && (current_slice != PC_SLICE_TYPE_ZEN_DISABLED) && (! IS_PC_SLICE_TYPE_BSD_WITH_FS (current_slice, FS_EXT2FS)) && (! IS_PC_SLICE_TYPE_BSD_WITH_FS (current_slice, FS_OTHER))) || part_length < (SBLOCK + (sizeof (struct ext2_super_block) / DEV_BSIZE)) @@ -495,7 +497,7 @@ int ext2_is_fast_symlink (void) * side effects: messes up GROUP_DESC buffer area */ int -ext2fs_dir (char *dirname) +ext2fs_dir (char *dirname, void (*handle)(char *)) { int current_ino = EXT2_ROOT_INO; /* start at the root */ int updir_ino = current_ino; /* the parent of the current directory */ @@ -521,7 +523,6 @@ ext2fs_dir (char *dirname) #ifdef E2DEBUG unsigned char *i; #endif /* E2DEBUG */ - /* loop invariants: current_ino = inode to lookup dirname = pointer to filename component we are cur looking up within @@ -537,7 +538,7 @@ ext2fs_dir (char *dirname) /* look up an inode */ group_id = (current_ino - 1) / (SUPERBLOCK->s_inodes_per_group); - group_desc = group_id >> log2 (EXT2_DESC_PER_BLOCK (SUPERBLOCK)); + group_desc = group_id >> grub_log2 (EXT2_DESC_PER_BLOCK (SUPERBLOCK)); desc = group_id & (EXT2_DESC_PER_BLOCK (SUPERBLOCK) - 1); #ifdef E2DEBUG printf ("ipg=%d, dpb=%d\n", SUPERBLOCK->s_inodes_per_group, @@ -553,7 +554,7 @@ ext2fs_dir (char *dirname) gdp = GROUP_DESC; ino_blk = gdp[desc].bg_inode_table + (((current_ino - 1) % (SUPERBLOCK->s_inodes_per_group)) - >> log2 (EXT2_BLOCK_SIZE (SUPERBLOCK) / sizeof (struct ext2_inode))); + >> grub_log2 (EXT2_BLOCK_SIZE (SUPERBLOCK) / sizeof (struct ext2_inode))); #ifdef E2DEBUG printf ("inode table fsblock=%d\n", ino_blk); #endif /* E2DEBUG */ @@ -713,18 +714,9 @@ ext2fs_dir (char *dirname) give up */ if (loc >= INODE->i_size) { - if (print_possibilities < 0) - { -# if 0 - putchar ('\n'); -# endif - } - else - { - errnum = ERR_FILE_NOT_FOUND; - *rest = ch; - } - return (print_possibilities < 0); + errnum = ERR_FILE_NOT_FOUND; + *rest = ch; + return 0; } /* else, find the (logical) block component of our location */ @@ -765,20 +757,15 @@ ext2fs_dir (char *dirname) str_chk = substring (dirname, dp->name); # ifndef STAGE1_5 - if (print_possibilities && ch != '/' - && (!*dirname || str_chk <= 0)) - { - if (print_possibilities > 0) - print_possibilities = -print_possibilities; - print_a_completion (dp->name); - } + if (handle && ch != '/' && (!*dirname || str_chk <= 0)) + handle (dp->name); # endif dp->name[dp->name_len] = saved_c; } } - while (!dp->inode || (str_chk || (print_possibilities && ch != '/'))); + while (!dp->inode || (str_chk || (handle && ch != '/'))); current_ino = dp->inode; *(dirname = rest) = ch; diff --git a/stage2/fsys_fat.c b/stage2/fsys_fat.c index f40e658..1a62fcf 100644 --- a/stage2/fsys_fat.c +++ b/stage2/fsys_fat.c @@ -55,7 +55,7 @@ struct fat_superblock #define FAT_CACHE_SIZE 2048 static __inline__ unsigned long -log2 (unsigned long word) +grub_log2 (unsigned long word) { __asm__ ("bsfl %1,%0" : "=r" (word) @@ -84,9 +84,9 @@ fat_mount (void) if (bpb.sects_per_clust == 0) return 0; - FAT_SUPER->sectsize_bits = log2 (FAT_CVT_U16 (bpb.bytes_per_sect)); + FAT_SUPER->sectsize_bits = grub_log2 (FAT_CVT_U16 (bpb.bytes_per_sect)); FAT_SUPER->clustsize_bits - = FAT_SUPER->sectsize_bits + log2 (bpb.sects_per_clust); + = FAT_SUPER->sectsize_bits + grub_log2 (bpb.sects_per_clust); /* Fill in info about super block */ FAT_SUPER->num_sectors = FAT_CVT_U16 (bpb.short_sectors) @@ -289,7 +289,7 @@ fat_read (char *buf, int len) } int -fat_dir (char *dirname) +fat_dir (char *dirname, void (*handle)(char *)) { char *rest, ch, dir_buf[FAT_DIRENTRY_LENGTH]; char *filename = (char *) NAME_BUF; @@ -345,7 +345,7 @@ fat_dir (char *dirname) *rest = 0; # ifndef STAGE1_5 - if (print_possibilities && ch != '/') + if (handle && ch != '/') do_possibilities = 1; # endif @@ -356,16 +356,6 @@ fat_dir (char *dirname) { if (!errnum) { -# ifndef STAGE1_5 - if (print_possibilities < 0) - { -#if 0 - putchar ('\n'); -#endif - return 1; - } -# endif /* STAGE1_5 */ - errnum = ERR_FILE_NOT_FOUND; *rest = ch; } @@ -460,11 +450,7 @@ fat_dir (char *dirname) { print_filename: if (substring (dirname, filename) <= 0) - { - if (print_possibilities > 0) - print_possibilities = -print_possibilities; - print_a_completion (filename); - } + handle (filename); continue; } # endif /* STAGE1_5 */ diff --git a/stage2/fsys_ffs.c b/stage2/fsys_ffs.c index 6e2300f..c0d0fa6 100644 --- a/stage2/fsys_ffs.c +++ b/stage2/fsys_ffs.c @@ -180,7 +180,7 @@ ffs_read (char *buf, int len) int -ffs_dir (char *dirname) +ffs_dir (char *dirname, void (*handle)(char *)) { char *rest, ch; int block, off, loc, map, ino = ROOTINO; @@ -236,13 +236,6 @@ loop: { if (loc >= INODE->i_size) { -#if 0 - putchar ('\n'); -#endif - - if (print_possibilities < 0) - return 1; - errnum = ERR_FILE_NOT_FOUND; *rest = ch; return 0; @@ -267,18 +260,13 @@ loop: loc += dp->d_reclen; #ifndef STAGE1_5 - if (dp->d_ino && print_possibilities && ch != '/' + if (dp->d_ino && handle && ch != '/' && (!*dirname || substring (dirname, dp->d_name) <= 0)) - { - if (print_possibilities > 0) - print_possibilities = -print_possibilities; - - print_a_completion (dp->d_name); - } + handle (dp->d_name); #endif /* STAGE1_5 */ } while (!dp->d_ino || (substring (dirname, dp->d_name) != 0 - || (print_possibilities && ch != '/'))); + || (handle && ch != '/'))); /* only get here if we have a matching directory entry */ diff --git a/stage2/fsys_iso9660.c b/stage2/fsys_iso9660.c index 90e4aa8..e314f28 100644 --- a/stage2/fsys_iso9660.c +++ b/stage2/fsys_iso9660.c @@ -57,7 +57,7 @@ struct iso_inode_info { static inline unsigned long -log2 (unsigned long word) +grub_log2 (unsigned long word) { asm volatile ("bsfl %1,%0" : "=r" (word) @@ -68,7 +68,7 @@ log2 (unsigned long word) static int iso9660_devread (int sector, int byte_offset, int byte_len, char *buf) { - unsigned short sector_size_lg2 = log2(buf_geom.sector_size); + unsigned short sector_size_lg2 = grub_log2(buf_geom.sector_size); /* * We have to use own devread() function since BIOS return wrong geometry @@ -133,7 +133,7 @@ iso9660_mount (void) } int -iso9660_dir (char *dirname) +iso9660_dir (char *dirname, void (*handle)(char *)) { struct iso_directory_record *idr; RR_ptr_t rr_ptr; @@ -346,7 +346,7 @@ iso9660_dir (char *dirname) if (name_len >= pathlen && !memcmp(name, dirname, pathlen)) { - if (dirname[pathlen] == '/' || !print_possibilities) + if (dirname[pathlen] == '/' || !handle) { /* * DIRNAME is directory component of pathname, @@ -377,11 +377,9 @@ iso9660_dir (char *dirname) else /* Completion */ { #ifndef STAGE1_5 - if (print_possibilities > 0) - print_possibilities = -print_possibilities; memcpy(NAME_BUF, name, name_len); NAME_BUF[name_len] = '\0'; - print_a_completion (NAME_BUF); + handle (NAME_BUF); #endif } } @@ -390,7 +388,7 @@ iso9660_dir (char *dirname) size -= ISO_SECTOR_SIZE; } /* size>0 */ - if (dirname[pathlen] == '/' || print_possibilities >= 0) + if (dirname[pathlen] == '/' || handle) { errnum = ERR_FILE_NOT_FOUND; return 0; diff --git a/stage2/fsys_jfs.c b/stage2/fsys_jfs.c index 307f836..1619d29 100644 --- a/stage2/fsys_jfs.c +++ b/stage2/fsys_jfs.c @@ -270,7 +270,7 @@ jfs_read (char *buf, int len) } int -jfs_dir (char *dirname) +jfs_dir (char *dirname, void (*handle)(char *)) { char *ptr, *rest, ch; ldtentry_t *de; @@ -357,12 +357,9 @@ jfs_dir (char *dirname) cmp = (!*dirname) ? -1 : substring (dirname, namebuf); #ifndef STAGE1_5 - if (print_possibilities && ch != '/' - && cmp <= 0) { - if (print_possibilities > 0) - print_possibilities = -print_possibilities; - print_a_completion (namebuf); - } else + if (handle && ch != '/' && cmp <= 0) + handle (namebuf); + else #endif if (cmp == 0) { parent_inum = inum; @@ -372,9 +369,6 @@ jfs_dir (char *dirname) } de = next_dentry (); if (de == NULL) { - if (print_possibilities < 0) - return 1; - errnum = ERR_FILE_NOT_FOUND; *rest = ch; return 0; diff --git a/stage2/fsys_minix.c b/stage2/fsys_minix.c index 5c76796..b86b2b4 100644 --- a/stage2/fsys_minix.c +++ b/stage2/fsys_minix.c @@ -294,7 +294,7 @@ minix_read (char *buf, int len) inode of the file we were trying to look up side effects: none yet */ int -minix_dir (char *dirname) +minix_dir (char *dirname, void (*handle)(char *)) { int current_ino = MINIX_ROOT_INO; /* start at the root */ int updir_ino = current_ino; /* the parent of the current directory */ @@ -457,18 +457,9 @@ minix_dir (char *dirname) give up */ if (loc >= INODE->i_size) { - if (print_possibilities < 0) - { -#if 0 - putchar ('\n'); -#endif - } - else - { - errnum = ERR_FILE_NOT_FOUND; - *rest = ch; - } - return (print_possibilities < 0); + errnum = ERR_FILE_NOT_FOUND; + *rest = ch; + return 0; } /* else, find the (logical) block component of our location */ @@ -510,20 +501,15 @@ minix_dir (char *dirname) str_chk = substring (dirname, dp->name); # ifndef STAGE1_5 - if (print_possibilities && ch != '/' - && (!*dirname || str_chk <= 0)) - { - if (print_possibilities > 0) - print_possibilities = -print_possibilities; - print_a_completion (dp->name); - } + if (handle && ch != '/' && (!*dirname || str_chk <= 0)) + handle (dp->name); # endif dp->name[namelen] = saved_c; } } - while (!dp->inode || (str_chk || (print_possibilities && ch != '/'))); + while (!dp->inode || (str_chk || (handle && ch != '/'))); current_ino = dp->inode; *(dirname = rest) = ch; diff --git a/stage2/fsys_reiserfs.c b/stage2/fsys_reiserfs.c index 93ec5f8..7a6f8fc 100644 --- a/stage2/fsys_reiserfs.c +++ b/stage2/fsys_reiserfs.c @@ -367,7 +367,7 @@ struct fsys_reiser_info static __inline__ unsigned long -log2 (unsigned long word) +grub_log2 (unsigned long word) { __asm__ ("bsfl %1,%0" : "=r" (word) @@ -609,7 +609,7 @@ reiserfs_mount (void) INFO->version = super.s_version; INFO->blocksize = super.s_blocksize; - INFO->fullblocksize_shift = log2 (super.s_blocksize); + INFO->fullblocksize_shift = grub_log2 (super.s_blocksize); INFO->blocksize_shift = INFO->fullblocksize_shift - SECTOR_BITS; INFO->cached_slots = (FSYSREISER_CACHE_SIZE >> INFO->fullblocksize_shift) - 1; @@ -991,7 +991,7 @@ reiserfs_read (char *buf, int len) * the size of the file. */ int -reiserfs_dir (char *dirname) +reiserfs_dir (char *dirname, void (*handle)(char *)) { struct reiserfs_de_head *de_head; char *rest, ch; @@ -1123,7 +1123,7 @@ reiserfs_dir (char *dirname) *rest = 0; # ifndef STAGE1_5 - if (print_possibilities && ch != '/') + if (handle && ch != '/') do_possibilities = 1; # endif /* ! STAGE1_5 */ @@ -1170,10 +1170,8 @@ reiserfs_dir (char *dirname) { if (cmp <= 0) { - if (print_possibilities > 0) - print_possibilities = -print_possibilities; *name_end = 0; - print_a_completion (filename); + handle (filename); *name_end = tmp; } } @@ -1189,12 +1187,6 @@ reiserfs_dir (char *dirname) num_entries--; } } - -# ifndef STAGE1_5 - if (print_possibilities < 0) - return 1; -# endif /* ! STAGE1_5 */ - errnum = ERR_FILE_NOT_FOUND; *rest = ch; return 0; diff --git a/stage2/fsys_ufs2.c b/stage2/fsys_ufs2.c index 3b64313..ffb8a79 100644 --- a/stage2/fsys_ufs2.c +++ b/stage2/fsys_ufs2.c @@ -204,7 +204,7 @@ ufs2_read (char *buf, int len) } int -ufs2_dir (char *dirname) +ufs2_dir (char *dirname, void (*handle)(char *)) { char *rest, ch; int block, off, loc, ino = ROOTINO; @@ -261,9 +261,6 @@ loop: { if (loc >= INODE_UFS2->di_size) { - if (print_possibilities < 0) - return 1; - errnum = ERR_FILE_NOT_FOUND; *rest = ch; return 0; @@ -288,18 +285,13 @@ loop: loc += dp->d_reclen; #ifndef STAGE1_5 - if (dp->d_ino && print_possibilities && ch != '/' + if (dp->d_ino && handle && ch != '/' && (!*dirname || substring (dirname, dp->d_name) <= 0)) - { - if (print_possibilities > 0) - print_possibilities = -print_possibilities; - - print_a_completion (dp->d_name); - } + handle (dp->d_name); #endif /* STAGE1_5 */ } while (!dp->d_ino || (substring (dirname, dp->d_name) != 0 - || (print_possibilities && ch != '/'))); + || (handle && ch != '/'))); /* only get here if we have a matching directory entry */ diff --git a/stage2/fsys_vstafs.c b/stage2/fsys_vstafs.c index a116717..834849b 100644 --- a/stage2/fsys_vstafs.c +++ b/stage2/fsys_vstafs.c @@ -115,7 +115,7 @@ vstafs_nextdir (void) } int -vstafs_dir (char *dirname) +vstafs_dir (char *dirname, void (*handle)(char *)) { char *fn, ch; struct dir_entry *d; @@ -146,14 +146,9 @@ vstafs_dir (char *dirname) continue; #ifndef STAGE1_5 - if (print_possibilities && ch != '/' + if (handle && ch != '/' && (! *dirname || strcmp (dirname, d->name) <= 0)) - { - if (print_possibilities > 0) - print_possibilities = -print_possibilities; - - printf (" %s", d->name); - } + handle(d->name); #endif if (! grub_strcmp (dirname, d->name)) { @@ -168,12 +163,6 @@ vstafs_dir (char *dirname) *(dirname = fn) = ch; if (! d) { - if (print_possibilities < 0) - { - putchar ('\n'); - return 1; - } - errnum = ERR_FILE_NOT_FOUND; return 0; } diff --git a/stage2/fsys_xfs.c b/stage2/fsys_xfs.c index 76c4c13..266fcaa 100644 --- a/stage2/fsys_xfs.c +++ b/stage2/fsys_xfs.c @@ -534,7 +534,7 @@ xfs_read (char *buf, int len) } int -xfs_dir (char *dirname) +xfs_dir (char *dirname, void (*handle)(char *)) { xfs_ino_t ino, parent_ino, new_ino; xfs_fsize_t di_size; @@ -595,11 +595,9 @@ xfs_dir (char *dirname) for (;;) { cmp = (!*dirname) ? -1 : substring (dirname, name); #ifndef STAGE1_5 - if (print_possibilities && ch != '/' && cmp <= 0) { - if (print_possibilities > 0) - print_possibilities = -print_possibilities; - print_a_completion (name); - } else + if (handle && ch != '/' && cmp <= 0) + handle (name); + else #endif if (cmp == 0) { parent_ino = ino; @@ -610,9 +608,6 @@ xfs_dir (char *dirname) } name = next_dentry (&new_ino); if (name == NULL) { - if (print_possibilities < 0) - return 1; - errnum = ERR_FILE_NOT_FOUND; *rest = ch; return 0; diff --git a/stage2/iso9660.h b/stage2/iso9660.h index 4a6a8cc..c311ecf 100644 --- a/stage2/iso9660.h +++ b/stage2/iso9660.h @@ -73,11 +73,11 @@ typedef union { typedef struct __iso_16bit { u_int16_t l, b; -} iso_16bit_t __attribute__ ((packed)); +} iso_16bit_t; typedef struct __iso_32bit { u_int32_t l, b; -} iso_32bit_t __attribute__ ((packed)); +} iso_32bit_t; typedef u_int8_t iso_date_t[7]; diff --git a/stage2/pc_slice.h b/stage2/pc_slice.h index a38d97f..9fb0df8 100644 --- a/stage2/pc_slice.h +++ b/stage2/pc_slice.h @@ -114,6 +114,8 @@ #define PC_SLICE_TYPE_EXT2FS 0x83 #define PC_SLICE_TYPE_LINUX_EXTENDED 0x85 #define PC_SLICE_TYPE_VSTAFS 0x9e +#define PC_SLICE_TYPE_ZEN 0xbc +#define PC_SLICE_TYPE_ZEN_DISABLED 0xbd #define PC_SLICE_TYPE_DELL_UTIL 0xde #define PC_SLICE_TYPE_LINUX_RAID 0xfd diff --git a/stage2/shared.h b/stage2/shared.h index 77eef11..4dea4b7 100644 --- a/stage2/shared.h +++ b/stage2/shared.h @@ -174,8 +174,8 @@ extern char *grub_scratch_mem; #define BOOTSEC_LOCATION RAW_ADDR (0x7C00) #define BOOTSEC_SIGNATURE 0xAA55 -#define BOOTSEC_BPB_OFFSET 0x3 -#define BOOTSEC_BPB_LENGTH 0x3B +#define BOOTSEC_BPB_OFFSET 0xA +#define BOOTSEC_BPB_LENGTH 0x34 #define BOOTSEC_BPB_SYSTEM_ID 0x3 #define BOOTSEC_BPB_HIDDEN_SECTORS 0x1C #define BOOTSEC_PART_OFFSET 0x1BE @@ -374,6 +374,22 @@ extern char *grub_scratch_mem; #endif /* WITHOUT_LIBC_STUBS */ +/* see typedef gfx_data_t below */ +#define gfx_ofs_ok 0x00 +#define gfx_ofs_code_seg 0x04 +#define gfx_ofs_jmp_table 0x08 +#define gfx_ofs_sys_cfg 0x38 +#define gfx_ofs_cmdline 0x6c +#define gfx_ofs_cmdline_len 0x70 +#define gfx_ofs_menu_list 0x74 +#define gfx_ofs_menu_default_entry 0x78 +#define gfx_ofs_menu_entries 0x7c +#define gfx_ofs_menu_entry_len 0x80 +#define gfx_ofs_args_list 0x84 +#define gfx_ofs_args_entry_len 0x88 +#define gfx_ofs_timeout 0x8c + + #ifndef ASM_FILE /* * Below this should be ONLY defines and other constructs for C code. @@ -595,6 +611,38 @@ extern int fallback_entryno; extern int default_entry; extern int current_entryno; + +/* + * graphics menu stuff + * + * Note: gfx_data and all data referred to in it must lie within a 64k area. + */ +typedef struct { + unsigned ok; /* set while we're in graphics mode */ + unsigned code_seg; /* code segment of binary graphics code */ + unsigned jmp_table[12]; /* link to graphics functions */ + unsigned char sys_cfg[52]; /* sys_cfg[0]: identifies boot loader (grub == 2) */ + char *cmdline; /* command line returned by gfx_input() */ + unsigned cmdline_len; /* length of the above */ + char *menu_list; /* list of menu entries, each of fixed length (menu_entry_len) */ + char *menu_default_entry; /* the default entry */ + unsigned menu_entries; /* number of entries in menu_list */ + unsigned menu_entry_len; /* one entry */ + char *args_list; /* same structure as menu_list, menu_entries entries */ + unsigned args_entry_len; /* one entry */ + unsigned timeout; /* in seconds (0: no timeout) */ +} __attribute__ ((packed)) gfx_data_t; + +extern gfx_data_t *graphics_data; + +/* pointer to graphics image data */ +extern char graphics_file[64]; + +int gfx_init(gfx_data_t *gfx_data); +int gfx_done(gfx_data_t *gfx_data); +int gfx_input(gfx_data_t *gfx_data, int *menu_entry); +int gfx_setup_menu(gfx_data_t *gfx_data); + /* The constants for password types. */ typedef enum { @@ -956,9 +1004,11 @@ 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); +/* List the contents of DIRECTORY. */ +int dir (char *dirname, void (*handle)(char *)); + +/* Wildcard expand the last pathname component of GLOB. */ +char *wildcard (char *glob, int *len); int set_bootdev (int hdbias); diff --git a/stage2/stage2.c b/stage2/stage2.c index 4dbf6f5..128c044 100644 --- a/stage2/stage2.c +++ b/stage2/stage2.c @@ -22,6 +22,8 @@ grub_jmp_buf restart_env; +gfx_data_t *graphics_data; + #if defined(PRESET_MENU_STRING) || defined(SUPPORT_DISKLESS) # if defined(PRESET_MENU_STRING) @@ -234,6 +236,8 @@ run_menu (char *menu_entries, char *config_entries, int num_entries, int c, time1, time2 = -1, first_entry = 0; char *cur_entry = 0; + cls(); + /* * Main loop for menu UI. */ @@ -261,14 +265,16 @@ restart: /* Get current time. */ while ((time1 = getrtsecs ()) == 0xFF) ; + grub_printf("\rPress any key to enter the menu\n\n\n"); while (1) { /* Check if ESC is pressed. */ - if (checkkey () != -1 && ASCII_CHAR (getkey ()) == '\e') + if (checkkey () != -1) { grub_timeout = -1; show_menu = 1; + getkey (); break; } @@ -287,7 +293,8 @@ restart: grub_timeout--; /* Print a message. */ - grub_printf ("\rPress `ESC' to enter the menu... %d ", + grub_printf ("\rBooting %s in %d seconds...", + get_entry(menu_entries, first_entry + entryno, 0), grub_timeout); } } @@ -310,6 +317,12 @@ restart: if (! auth && password) { + if (*graphics_file) + { + printf ("\ + WARNING: graphical menu doesn\'t work\ + in conjunction with the password feature\n" ); + } printf ("\ Press enter to boot the selected OS or \'p\' to enter a\n\ password to unlock the next set of features."); @@ -319,7 +332,8 @@ restart: if (config_entries) printf ("\ Press enter to boot the selected OS, \'e\' to edit the\n\ - commands before booting, or \'c\' for a command-line."); + commands before booting, \'a\' to modify the kernel arguments\n\ + before booting, or \'c\' for a command-line."); else printf ("\ Press \'b\' to boot, \'e\' to edit the selected command in the\n\ @@ -697,6 +711,87 @@ restart: enter_cmdline (heap, 0); goto restart; } + if (config_entries && c == 'a') + { + int new_num_entries = 0, i = 0, j; + char *new_heap; + char * entries; + char * entry_copy; + char * append_line; + char * start; + + entry_copy = new_heap = heap; + cur_entry = get_entry (config_entries, first_entry + entryno, + 1); + + do + { + while ((*(new_heap++) = cur_entry[i++]) != 0); + new_num_entries++; + } + while (config_entries && cur_entry[i]); + + /* this only needs to be done if config_entries is non-NULL, + but it doesn't hurt to do it always */ + *(new_heap++) = 0; + + new_heap = heap + NEW_HEAPSIZE + 1; + + entries = entry_copy; + while (*entries) + { + if ((strstr(entries, "kernel") == entries) && + isspace(entries[6])) + break; + + while (*entries) entries++; + entries++; + } + + if (!*entries) + goto restart; + + start = entries + 6; + + /* skip the white space */ + while (*start && isspace(*start)) start++; + /* skip the kernel name */ + while (*start && !isspace(*start)) start++; + /* skip the white space */ + while (*start && isspace(*start)) start++; + + append_line = new_heap; + grub_strcpy(append_line, start); + + cls(); + print_cmdline_message (0); + + if (get_cmdline(PACKAGE " append> ", + append_line, NEW_HEAPSIZE + 1, + 0, 1)) + goto restart; + + /* have new args; append_line points to the + new args and start points to the old + args */ + + i = grub_strlen(start); + j = grub_strlen(append_line); + + /* align rest of commands properly */ + memmove (start + j, start + i, + ((int) append_line) - ((int) start) - (i > j ? i : j)); + + /* copy command to correct area */ + memmove (start, append_line, j); + + /* set up this entry to boot */ + config_entries = NULL; + cur_entry = entry_copy; + heap = new_heap; + + break; + } #ifdef GRUB_UTIL if (c == 'q') { @@ -753,6 +848,496 @@ restart: } + +#if 0 +/* for debugging */ +static void hexdump(unsigned char *buf, unsigned len) +{ + int i, j = 0; + char s[17]; + unsigned addr = (unsigned) buf; + + s[16] = 0; + while(len--) { + i = buf[j]; + i = i & 0xff; + s[j & 15] = (i >= 0x20 && i <= 0x7e) ? i : '.'; + if(!(j & 15)) { + printf("%x ", j + addr); + } + if(!(j & 7) && (j & 15)) printf(" "); + /* stupid grub_printf */ + printf("%x", (i >> 4) & 0x0f); + printf("%x ", i & 0x0f); + if(!(++j & 15)) { + printf(" %s\n", s); + } + } + + if(j & 15) { + s[j & 15] = 0; + if(!(j & 8)) printf(" "); + i = 1 + 3 * (16 - (j & 15)); + while(i--) printf(" "); + printf("%s\n", s); + } +} +#endif + + +/* kernel + (grub-)module options */ +#define GFX_CMD_BUF_SIZE 512 + +/* command line separator char */ +#define GFX_CMD_SEP 1 + +/* + * Go through config entry and find kernel args, if any. + * Put things into buf and return it. + */ +static char *get_kernel_args(char *cfg, char *buf) +{ + int i, j; + char *s, *t = "", *p, *t2; + + *(p = buf) = 0; + + for(j = 0; ; j++) { + s = get_entry(cfg, j, 0); + if(!*s) break; + if( + (!memcmp(s, "kernel", 6) || !memcmp(s, "module", 6)) && + (s[6] == ' ' || s[6] == '\t') + ) { + t = skip_to(0, s); + t2 = s[0] == 'm' ? strstr(t, "initrd") : NULL; + if(*t) t = skip_to(0, t); + if(t2 && t2 < t) break; /* module is likely a normal initrd -> skip */ + i = strlen(t); + if(p - buf + i > GFX_CMD_BUF_SIZE - 2) break; + *p++ = GFX_CMD_SEP; + strcpy(p, t); + p += i; + + continue; + } + } + + if(*buf) buf++; /* skip initial separator char */ + + return buf; +} + + +/* + * Check header and return code start offset. + */ +static unsigned magic_ok(unsigned char *buf) +{ + if( + *(unsigned *) buf == 0x0b2d97f00 && /* magic id */ + (buf[4] == 8) /* version 8 */ + ) { + return *(unsigned *) (buf + 8); + } + + return 0; +} + + +/* + * Search cpio archive for gfx file. + */ +static unsigned find_file(unsigned char *buf, unsigned len, unsigned *gfx_file_start, unsigned *file_len) +{ + unsigned i, fname_len, code_start = 0; + + *gfx_file_start = 0; + + for(i = 0; i < len;) { + if((len - i) >= 0x1a && (buf[i] + (buf[i + 1] << 8)) == 0x71c7) { + fname_len = *(unsigned short *) (buf + i + 20); + *file_len = *(unsigned short *) (buf + i + 24) + (*(unsigned short *) (buf + i + 22) << 16); + i += 26 + fname_len; + i = ((i + 1) & ~1); + if((code_start = magic_ok(buf + i))) { + *gfx_file_start = i; + return code_start; + } + i += *file_len; + i = ((i + 1) & ~1); + } + else { + break; + } + } + + return code_start; +} + +static inline unsigned char * stack_ptr(void) +{ + unsigned char * u; + + asm("movl %%esp, %0" : "=r" (u)); + + return u; +} + +static void sleep(int delay) +{ + int tick, last_tick = currticks(); + + delay *= 18; + + while(delay--) { + while((tick = currticks()) == last_tick) { } + last_tick = tick; + } +} + +static void wait_for_key() +{ + printf("Press a key to continue..."); + getkey(); + printf("\r \r"); +} + + +/* + * Leave that much space on the heap. Everything else goes to the graphics + * functions. + * + * 0x2000 is _not_ enough + */ +#define MIN_HEAP_SIZE 0x4000 +#define MIN_GFX_FREE 0x1000 + +#define SC_BOOTLOADER 0 +#define SC_FAILSAFE 3 +#define SC_SYSCONFIG_SIZE 4 +#define SC_BOOTLOADER_SEG 8 +#define SC_XMEM_0 24 +#define SC_XMEM_1 26 +#define SC_XMEM_2 28 +#define SC_XMEM_3 30 +#define SC_FILE 32 +#define SC_ARCHIVE_START 36 +#define SC_ARCHIVE_END 40 +#define SC_MEM0_START 44 +#define SC_MEM0_END 48 + +/* + * Does normally not return. + */ +static void +run_graphics_menu (char *menu_entries, char *config_entries, int num_entries, + char *heap, int entryno) +{ + unsigned char *buf, *buf_ext; + unsigned buf_size, buf_ext_size, code_start, file_start; + char *s, *t, *t2, *cfg, *new_config, *p; + char *saved_heap; + int i, j, max_len, gfx_file_size, verbose; + int selected_entry; + gfx_data_t *gfx_data; + char *cmd_buf; + unsigned mem0_start, mem0_end, file_len; + + /* + * check gfx_data_t struct offsets for consistency; gcc will optimize away + * the whole block + */ + + /* dummy function to make ld fail */ + { + extern void wrong_struct_size(void); + #define gfx_ofs_check(a) if(gfx_ofs_##a != (char *) &gfx_data->a - (char *) gfx_data) wrong_struct_size(); + gfx_ofs_check(ok); + gfx_ofs_check(code_seg); + gfx_ofs_check(jmp_table); + gfx_ofs_check(sys_cfg); + gfx_ofs_check(cmdline); + gfx_ofs_check(cmdline_len); + gfx_ofs_check(menu_list); + gfx_ofs_check(menu_default_entry); + gfx_ofs_check(menu_entries); + gfx_ofs_check(menu_entry_len); + gfx_ofs_check(args_list); + gfx_ofs_check(args_entry_len); + gfx_ofs_check(timeout); + #undef gfx_ofs_check + } + + if(!num_entries) return; + + graphics_data = gfx_data = (gfx_data_t *) heap; + heap += sizeof *gfx_data; + memset(gfx_data, 0, sizeof *gfx_data); + + gfx_data->sys_cfg[SC_BOOTLOADER] = 2; /* bootloader: grub */ + gfx_data->sys_cfg[SC_SYSCONFIG_SIZE] = 52; /* config data size */ + *(unsigned short *) (gfx_data->sys_cfg + SC_BOOTLOADER_SEG) = (unsigned) gfx_data >> 4; /* segment */ + gfx_data->sys_cfg[SC_XMEM_0] = 0x21; /* 1MB @ 2MB */ + gfx_data->sys_cfg[SC_XMEM_1] = 0x41; /* 1MB @ 4MB */ + verbose = (*(unsigned char *) 0x417) & 3 ? 1 : 0; /* SHIFT pressed */ + gfx_data->sys_cfg[SC_FAILSAFE] = verbose; + + gfx_data->timeout = grub_timeout >= 0 ? grub_timeout : 0; + + + /* setup command line edit buffer */ + + gfx_data->cmdline_len = 256; + + gfx_data->cmdline = heap; + heap += gfx_data->cmdline_len; + memset(gfx_data->cmdline, 0, gfx_data->cmdline_len); + + cmd_buf = heap; + heap += GFX_CMD_BUF_SIZE; + + /* setup menu entries */ + + for(i = max_len = 0; i < num_entries; i++) { + j = strlen(get_entry(menu_entries, i, 0)); + if(j > max_len) max_len = j; + } + + if(!max_len) return; + + gfx_data->menu_entry_len = max_len + 1; + gfx_data->menu_entries = num_entries; + + gfx_data->menu_list = heap; + heap += gfx_data->menu_entry_len * gfx_data->menu_entries; + + memset(gfx_data->menu_list, 0, gfx_data->menu_entry_len * gfx_data->menu_entries); + + for(i = 0; i < (int) gfx_data->menu_entries; i++) { + strcpy(gfx_data->menu_list + i * gfx_data->menu_entry_len, get_entry(menu_entries, i, 0)); + } + + gfx_data->menu_default_entry = gfx_data->menu_list + entryno * gfx_data->menu_entry_len; + + + /* setup list of kernel args */ + + for(i = max_len = 0; i < num_entries; i++) { + s = get_kernel_args(get_entry(config_entries, i, 1), cmd_buf); + j = strlen(s); + if(j > max_len) max_len = j; + } + + gfx_data->args_entry_len = max_len + 1; + + gfx_data->args_list = heap; + heap += gfx_data->args_entry_len * gfx_data->menu_entries; + + memset(gfx_data->args_list, 0, gfx_data->args_entry_len * gfx_data->menu_entries); + + for(i = 0; i < (int) gfx_data->menu_entries; i++) { + strcpy(gfx_data->args_list + i* gfx_data->args_entry_len, get_kernel_args(get_entry(config_entries, i, 1), cmd_buf)); + } + + + /* go back here when we no longer need the graphics data */ + saved_heap = heap; + + + /* get memory area to be used by graphics functions */ + + /* use 1MB starting at 2MB as file buffer */ + buf_ext = (unsigned char *) (2 << 20); + buf_ext_size = 1 << 20; + + /* must be 16-byte aligned */ + buf = (unsigned char *) (((unsigned) heap + 0xf) & ~0xf); + + buf_size = stack_ptr() - buf - MIN_HEAP_SIZE; + buf_size &= ~0xf; + + mem0_start = (unsigned) buf; + mem0_end = mem0_start + buf_size; + + if(verbose) { + printf("low memory 0x%x - 0x%x (%d bytes)\n", mem0_start, mem0_end, buf_size); + wait_for_key(); + } + + heap += buf_size; + + /* read the file */ + + if(!grub_open(graphics_file)) { + printf("%s: file not found\n", graphics_file); + sleep(5); + heap = saved_heap; + return; + } + + gfx_file_size = grub_read(buf_ext, buf_ext_size); + + grub_close(); + + if(gfx_file_size <= 0) { + printf("%s: read error\n", graphics_file); + sleep(5); + heap = saved_heap; + return; + } + + if(verbose) { + printf("%s: %d bytes (%d bytes left)\n", graphics_file, gfx_file_size, buf_ext_size - gfx_file_size); + wait_for_key(); + } + + /* locate file inside cpio archive */ + if(!(code_start = find_file(buf_ext, gfx_file_size, &file_start, &file_len))) { + printf("%s: invalid file format\n", graphics_file); + sleep(5); + heap = saved_heap; + return; + } + + if(verbose) { + printf("init: start 0x%x, len %d; code offset 0x%x\n", file_start, file_len, code_start); + wait_for_key(); + } + + if(file_len - code_start + MIN_GFX_FREE > buf_size) { + printf("not enough free memory: %d extra bytes need\n", file_len - code_start + MIN_GFX_FREE - buf_size); + sleep(5); + heap = saved_heap; + return; + } + + memcpy((void *) buf, (void *) (buf_ext + file_start + code_start), file_len - code_start); + + mem0_start += file_len - code_start; + mem0_start = (mem0_start + 3) & ~3; /* align */ + + /* init interface to graphics functions */ + + *(unsigned *) (gfx_data->sys_cfg + SC_FILE) = (unsigned) buf_ext + file_start; + *(unsigned *) (gfx_data->sys_cfg + SC_ARCHIVE_START) = (unsigned) buf_ext; + *(unsigned *) (gfx_data->sys_cfg + SC_ARCHIVE_END) = (unsigned) buf_ext + gfx_file_size; + *(unsigned *) (gfx_data->sys_cfg + SC_MEM0_START) = mem0_start; + *(unsigned *) (gfx_data->sys_cfg + SC_MEM0_END) = mem0_end; + + gfx_data->code_seg = (unsigned) buf >> 4; + + if(verbose) { + printf("init 0x%x, archive 0x%x - 0x%x, low mem 0x%x - 0x%x\ncode seg 0x%x\n", + (unsigned) buf_ext + file_start, + (unsigned) buf_ext, (unsigned) buf_ext + gfx_file_size, + mem0_start, mem0_end, gfx_data->code_seg + ); + wait_for_key(); + } + + for(i = 0; (unsigned) i < sizeof gfx_data->jmp_table / sizeof *gfx_data->jmp_table; i++) { + gfx_data->jmp_table[i] = (gfx_data->code_seg << 16) + ((unsigned short *) buf)[i]; + } + + if(verbose) { + for(i = 0; i < 12; i++) { + printf("%d: 0x%x\n", i, gfx_data->jmp_table[i]); + } + + for(i = 0; i < gfx_data->menu_entries; i++) { + printf("\"%s\" -- \"%s\"\n", + gfx_data->menu_list + i * gfx_data->menu_entry_len, + gfx_data->args_list + i * gfx_data->args_entry_len + ); + } + + printf("default: \"%s\"\n", gfx_data->menu_default_entry); + wait_for_key(); + } + + /* switch to graphics mode */ + + if(gfx_init(gfx_data)) { + printf("graphics initialization failed\n"); + sleep(5); + heap = saved_heap; + return; + } + + gfx_setup_menu(gfx_data); + + i = gfx_input(gfx_data, &selected_entry); + + /* ESC -> show text menu */ + if(i == 1) { + gfx_done(gfx_data); + grub_timeout = -1; + + heap = saved_heap; + return; + } + + gfx_done(gfx_data); + + heap = saved_heap; /* free most of the graphics data */ + + // printf("cmdline: >%s<, entry = %d\n", gfx_data->cmdline, selected_entry); + + if(selected_entry < 0 || selected_entry > num_entries) return; + + /* for 'savedefault' */ + current_entryno = selected_entry; + + + /* create new config with modified kernel option */ + + cfg = get_entry(config_entries, selected_entry, 1); + + new_config = heap; + + for(p = gfx_data->cmdline, i = 0; ; i++) { + s = get_entry(cfg, i, 0); + if(!*s) { + if(!i) *heap++ = 0; + *heap++ = 0; + break; + } + /* note: must match get_kernel_args() */ + if( + (!memcmp(s, "kernel", 6) || !memcmp(s, "module", 6)) && + (s[6] == ' ' || s[6] == '\t') + ) { + t = skip_to(0, s); + t2 = s[0] == 'm' ? strstr(t, "initrd") : NULL; + if(*t) t = skip_to(0, t); + if(t2 && t2 < t) { /* module is likely a normal initrd -> skip */ + strcpy(heap, s); + heap += strlen(s) + 1; + continue; + } + memmove(heap, s, t - s); + heap += t - s; + *heap++ = ' '; + while(*p && *p != GFX_CMD_SEP) *heap++ = *p++; + *heap++ = 0; + if(*p == GFX_CMD_SEP) p++; + } + else { + strcpy(heap, s); + heap += strlen(s) + 1; + } + } + + *heap++ = 0; + + // hexdump(new_config, heap - new_config); + // getkey(); + + run_script(new_config, heap); +} + + static int get_line_from_config (char *cmdline, int maxlen, int read_from_file) { @@ -827,6 +1412,195 @@ get_line_from_config (char *cmdline, int maxlen, int read_from_file) return pos; } +extern void __savedefault_once_reset(); + +char *wildcard_prefix, *wildcard_suffix; +char wildcard_matches[1024], *end_wildcard_matches; + +static void wildcard_handler(char *name); + +/* Match one directory entry against the current wildcard. If the entry + matches, store it in WILDCARD_MATCHES. Silently ignore entries that + don't fit into WILDCARD_MATCHES anymore. */ +static void +wildcard_handler(char *name) +{ + char *n = name, *p = wildcard_prefix; + + while (*p && *p == *n) + { + p++; + n++; + } + if (*p) + return; /* prefix mismatch */ + + p = name + grub_strlen (name) - grub_strlen (wildcard_suffix); + /* [n .. p) is the part matching the asterisk */ + + if (p < n || grub_strcmp (p, wildcard_suffix) != 0) + return; /* suffix mismatch */ + + /* store this match */ + if (p - n + 1 > sizeof (wildcard_matches) - + (end_wildcard_matches - wildcard_matches)) + return; /* out of space */ + while (n < p) + *end_wildcard_matches++ = *n++; + *end_wildcard_matches++ = 0; +} + +/* Wildcard expand the GLOB argument. Return NULL upon failure, or + a list of 0-terminated expansions, terminated by a zero-length string. */ +char * +wildcard (char *glob, int *len) +{ + char path[128], *p; + int ret; + + end_wildcard_matches = wildcard_matches; + if (grub_strlen (glob) + 1 > sizeof (path)) { + errnum = ERR_FILELENGTH; + return NULL; /* cannot handle pathnames this long */ + } + grub_strcpy (path, glob); + p = path; + while (*p) + p++; + wildcard_suffix = p; + while (p > path && *p != '/') + p--; + if (*p != '/') + { + errnum = ERR_BAD_FILETYPE; + return NULL; /* Cannot wildcard device names */ + } + *(++p) = 0; + wildcard_prefix = glob + (p - path); + for (p = wildcard_prefix;; p++) + { + if (*p == 0) + { + /* We cannot do exact matches: this cannot be represented in the + result list. */ + return NULL; + } + else if (*p == '*') + { + *p++ = 0; + wildcard_suffix = p; + break; + } + } + + ret = dir (path, wildcard_handler); + /* restore original argument */ + wildcard_prefix[grub_strlen (wildcard_prefix)] = '*'; + if (!ret) + return NULL; + *len = end_wildcard_matches - wildcard_matches; + return wildcard_matches; +} + +#define skip(str) ((str) + grub_strlen (str) + 1) + +static void inplace_sort (char *str, int len); + +static void +inplace_sort (char *str, int len) +{ + int m, n = 0; + char *s, *t; + + /* we use x as temporary storage */ + char *x = str + len; + + for (s = str; s < x; s = skip (s)) + n++; + + for (; n >= 2; n--) + { + s = str; + t = skip (s); + + for (m = n; m >= 2; m--) + { + if (grub_strcmp (s, t) > 0) + { + int ls = skip (s) - s; + int lt = skip (t) - t; + + memcpy (x, s, ls); + grub_memmove (s + ls, s + lt, t - (s + ls)); + memcpy (s, t, lt); + t = t + lt - ls; + memcpy (t, x, ls); + } + s = t; + t = skip (t); + } + } +} + +#undef skip + +static int this_config_len (const char *config); +static int +this_config_len (const char *config) +{ + const char *c = config; + while (*c) + { + while (*c) + c++; + c++; + } + c++; + return c - config; +} + +static const char * expand_asterisks (const char *str, int *len, + const char *subst); + +/* Expand all asterisks (*) in a menu entry or commands section with its + substitution. Use a backslash as escape character. */ +static const char * +expand_asterisks (const char *str, int *len, const char *subst) +{ + static char buffer[1024]; + char *b = buffer, escaped = 0; + const char *end = str + *len; + + while (str < end) + { + if (*str == '*' && !escaped) + { + if (b - buffer + grub_strlen (subst) > sizeof (buffer)) + { + errnum = ERR_FILELENGTH; + return NULL; + } + grub_strcpy (b, subst); + b += grub_strlen (subst); + } + else if (*str == '\\' && !escaped) + escaped = 1; + else + { + escaped = 0; + if (b - buffer + 1 > sizeof (buffer)) + { + errnum = ERR_FILELENGTH; + return NULL; + } + *b++ = *str; + } + str++; + } + *len = b - buffer; + + return buffer; +} /* This is the starting function in C. */ void @@ -848,6 +1622,97 @@ cmain (void) init_config (); } + auto void expand_wildcard_entries (void); + void expand_wildcard_entries (void) + { + char *config_entry = config_entries; + char *menu_entry = menu_entries; + + while (*menu_entry) + { + char *command = config_entry; + + do + { + char *c = command; + const char *w = "wildcard"; + + while (*w && *c == *w) + { + c++; + w++; + } + if (*w == 0 && (*c == ' ' || *c == '\t' || *c == '=')) + { + int len, wlen; + + /* This is a wildcard command. Advance to the argument. */ + while (*c == ' ' || *c == '\t' || *c == '=') + c++; + + /* Expand wildcard entry. */ + w = wildcard (c, &wlen); + if (w) + inplace_sort (w, wlen); + + /* Remove the wildcard command from the command section; + it has no meaning beyond the wildcard expansion just + performed. */ + len = grub_strlen (command) + 1; + grub_memmove (command, command + len, + config_len - (command - config_entries)); + config_len -= len; + + while (w && wlen) + { + /* Insert expansion before the wildcard entry in the + list of entry names. */ + len = grub_strlen (menu_entry) + 1; + const char *x = expand_asterisks (menu_entry, &len, w); + grub_memmove (menu_entry + len, menu_entry, + menu_len - (menu_entry - menu_entries)); + memcpy (menu_entry, x, len); + menu_entry += len; + menu_len += len; + + /* Insert expansion before the wildcard command section + in the list of command sections. */ + len = this_config_len (config_entry); + x = expand_asterisks (config_entry, &len, w); + grub_memmove (config_entry + len, config_entry, + config_len - (config_entry - + config_entries)); + memcpy (config_entry, x, len); + config_entry += len; + config_len += len; + + num_entries++; + wlen -= grub_strlen (w) + 1; + w += grub_strlen (w) + 1; + } + + /* Remove the wildcard command section; it has just + been expanded. */ + len = grub_strlen (menu_entry) + 1; + grub_memmove (menu_entry, menu_entry + len, + menu_len - (menu_entry - menu_entries)); + menu_len -= len; + + len = this_config_len(config_entry); + grub_memmove (config_entry, config_entry + len, + config_len - (config_entry - config_entries)); + config_len -= len; + + num_entries--; + } + command += grub_strlen (command) + 1; + } + while (*command); + menu_entry += grub_strlen (menu_entry) + 1; + config_entry += this_config_len(config_entry); + } + } + /* Initialize the environment for restarting Stage 2. */ grub_setjmp (restart_env); @@ -999,8 +1864,16 @@ cmain (void) config_len = prev_config_len; } + if (is_preset) + close_preset_menu (); + else + grub_close (); + menu_entries[menu_len++] = 0; config_entries[config_len++] = 0; + + expand_wildcard_entries(); + grub_memmove (config_entries + config_len, menu_entries, menu_len); menu_entries = config_entries + config_len; @@ -1042,14 +1915,12 @@ cmain (void) default_entry = 0; } - if (is_preset) - close_preset_menu (); - else - grub_close (); } while (is_preset); } - +#ifndef SUPPORT_DISKLESS + __savedefault_once_reset(); +#endif if (! num_entries) { /* If no acceptable config file, goto command-line, starting @@ -1059,9 +1930,12 @@ cmain (void) } else { - /* Run menu interface. */ - run_menu (menu_entries, config_entries, num_entries, - menu_entries + menu_len, default_entry); + if (*graphics_file && !password && show_menu && grub_timeout) + { + run_graphics_menu(menu_entries, config_entries, num_entries,menu_entries + menu_len, default_entry); + } + /* Run menu interface. */ + run_menu (menu_entries, config_entries, num_entries, menu_entries + menu_len, default_entry); } } } diff --git a/util/grub-install.in b/util/grub-install.in index 2e598b0..ffa9f90 100644 --- a/util/grub-install.in +++ b/util/grub-install.in @@ -27,15 +27,17 @@ VERSION=@VERSION@ host_cpu=@host_cpu@ host_os=@host_os@ host_vendor=@host_vendor@ -pkglibdir=${libdir}/${PACKAGE}/${host_cpu}-${host_vendor} +pkglibdir=${libdir}/${PACKAGE}/ grub_shell=${sbindir}/grub +mdadm=${sbindir}/mdadm grub_set_default=${sbindir}/grub-set-default log_file=/tmp/grub-install.log.$$ img_file=/tmp/grub-install.img.$$ rootdir= grub_prefix=/boot/grub +install_drives= install_device= no_floppy= force_lba= @@ -70,6 +72,8 @@ Install GRUB on your drive. --force-lba force GRUB to use LBA mode even for a buggy BIOS --recheck probe a device map even if it already exists + This flag is unreliable and its use is + strongly discouraged. INSTALL_DEVICE can be a GRUB device name or a system device filename. @@ -96,17 +100,26 @@ convert () { # Break the device name into the disk part and the partition part. case "$host_os" in linux*) - tmp_disk=`echo "$1" | sed -e 's%\([sh]d[a-z]\)[0-9]*$%\1%' \ + tmp_disk=`echo "$1" | grep -v '/mapper/control$' | + grep -v '/mapper/[[:alnum:]]\+-[[:alnum:]]\+$' | uniq | + sed -e 's%\([sh]d[a-z]\)[0-9]*$%\1%' \ -e 's%\(d[0-9]*\)p[0-9]*$%\1%' \ -e 's%\(fd[0-9]*\)$%\1%' \ -e 's%/part[0-9]*$%/disc%' \ - -e 's%\(c[0-7]d[0-9]*\).*$%\1%'` - tmp_part=`echo "$1" | sed -e 's%.*/[sh]d[a-z]\([0-9]*\)$%\1%' \ + -e 's%\(c[0-7]d[0-9]*\).*$%\1%' \ + -e 's%\(/mapper/[[:alpha:]]\+[[:digit:]]\+\)p[[:digit:]]\+$%\1%' \ + -e 's%\(/mapper/[[:alpha:]]\+_[[:alpha:]]\+\)[[:digit:]]\+$%\1%'` + tmp_part=`echo "$1" | grep -v '/mapper/control$' | + grep -v '/mapper/[[:alnum:]]\+-[[:alnum:]]\+$' | uniq | + sed -e 's%.*/[sh]d[a-z]\([0-9]*\)$%\1%' \ -e 's%.*d[0-9]*p%%' \ -e 's%.*/fd[0-9]*$%%' \ -e 's%.*/floppy/[0-9]*$%%' \ -e 's%.*/\(disc\|part\([0-9]*\)\)$%\2%' \ - -e 's%.*c[0-7]d[0-9]*p%%'` + -e 's%.*c[0-7]d[0-9]*p%%' \ + -e 's%.*/mapper/[[:alpha:]]\+[[:digit:]]\+p\([[:digit:]]\+\)$%\1%' \ + -e 's%.*/mapper/[[:alpha:]]\+_[[:alpha:]]\+\([[:digit:]]\+\)$%\1%' | + grep -v '.*/mapper/.*'` ;; gnu*) tmp_disk=`echo "$1" | sed 's%\([sh]d[0-9]*\).*%\1%'` @@ -211,23 +224,135 @@ resolve_symlink () { echo "$tmp_fname" } +# Usage: is_raid1_device devicename +# Returns 0 if devicename is a raid1 md device, 1 if it is not. +is_raid1_device () { + case "$host_os" in + linux*) + level=`$mdadm --query --detail $1 2>/dev/null | \ + awk '/Raid Level :/ {print $4}'` + if [ "$level" = "raid1" ]; then + return 0 + fi + ;; + esac + return 1 +} + +# Usage: find_real_devs device +# Returns space separated list of devices for linux if device is +# a raid1 device. In all other cases, the provided value is returned. +find_real_devs () { + source_device=$1 + case "$host_os" in + linux*) + if is_raid1_device $source_device ; then + list="" + for device in `$mdadm --query --detail "${source_device}" | \ + awk '/\/dev\/[^(md)]/ {print $7}'` ; do + list="$list $device" + done + echo $list + return 0 + fi + ;; + esac + echo $source_device + return 0 +} + +# Usage: stat_device file +# Find major:minor of a device node. +stat_device() { + majmin=`stat -c "%t:%T" "$1" 2>/dev/null` + if test -z "$majmin"; then + echo "Could not find device for $1" 2>&1 + exit 1 + fi + + echo "$majmin" +} + +# Usage: find_mapper_device file +# Find a file in /dev/mapper with the same major:minor as the specified node. +find_mapper_device() { + if [ -b "$1" ]; then + dev="$1" + else + mntpnt=`echo "$1" | sed 's,/,\\\\/,g'` + dev=`awk '($2 ~ /'$mntpnt'/) { print $1 }' /etc/mtab` + fi + if test -z "$dev"; then + echo "Could not find device for $1" 2>&1 + exit 1 + fi + + majmin=`stat_device $dev` + for x in /dev/mapper/* ; do + devmajmin=`stat_device "$x"` + if [ "$majmin" == "$devmajmin" ]; then + echo "$x" + return 0 + fi + done + return 1 +} + # Usage: find_device file # Find block device on which the file resides. find_device () { # For now, this uses the program `df' to get the device name, but is # this really portable? - tmp_fname=`df $1/ | sed -n 's%.*\(/dev/[^ ]*\).*%\1%p'` + tmp_fname=`df $1/ | awk '/\/dev\/|LABEL=|UUID=/{ print $1 }'` + + if echo "$tmp_fname" | grep -q LABEL= ; then + label=`echo "$tmp_fname" | sed -e s/.*=//` + tmp_fname=`readlink -f /dev/disk/by-label/$label` + fi + if echo "$tmp_fname" | grep -q UUID= ; then + uuid=`echo "$tmp_fname" | sed -e s/.*=//` + tmp_fname=`readlink -f /dev/disk/by-uuid/$uuid` + fi if test -z "$tmp_fname"; then echo "Could not find device for $1" 2>&1 exit 1 fi - tmp_fname=`resolve_symlink $tmp_fname` + ret_fname=`resolve_symlink $tmp_fname` + tmp_fname=`find_mapper_device $ret_fname` + if test -n "$tmp_fname"; then + ret_fname="$tmp_fname" + fi - echo "$tmp_fname" + echo "$ret_fname" + return 0 } + +dump_boot_block () { + sync + $grub_shell --batch $no_floppy --device-map=$device_map <$log_file +dump ${root_drive}${tmp} ${img_file} +quit +EOF +} + + +install_boot_block () { + # Before all invocations of the grub shell, call sync to make sure + # the raw device is in sync with any bufferring in filesystems. + sync + + # Now perform the installation. + $grub_shell --batch $no_floppy --device-map=$device_map <>$log_file +root $1 +setup $force_lba --stage2=$grubdir/stage2 --prefix=$grub_prefix $2 +quit +EOF +} + + # Check the arguments. for option in "$@"; do case "$option" in @@ -293,6 +418,14 @@ esac grubdir=${bootdir}/grub device_map=${grubdir}/device.map +if [ "$recheck" == "yes" ]; then + if grep 'mapper' ${device_map} >/dev/null; then + echo 'grub-install does not support reprobing of device.map when' 1>&2 + echo 'using a device-mapper based boot device.' 1>&2 + exit 1 + fi +fi + # Check if GRUB is installed. # This is necessary, because the user can specify "grub --read-only". set $grub_shell dummy @@ -326,7 +459,7 @@ test -d "$grubdir" || mkdir "$grubdir" || exit 1 # If --recheck is specified, remove the device map, if present. if test $recheck = yes; then - rm -f $device_map + mv $device_map ${device_map}.backup fi # Create the device map file if it is not present. @@ -336,6 +469,10 @@ else # Create a safe temporary file. test -n "$mklog" && log_file=`$mklog` + # Before all invocations of the grub shell, call sync to make sure + # the raw device is in sync with any bufferring in filesystems. + sync + $grub_shell --batch $no_floppy --device-map=$device_map <$log_file quit EOF @@ -351,7 +488,22 @@ fi tmp=`sed -n '/^([fh]d[0-9]*)/s/\(^(.*)\).*/\1/p' $device_map \ | sort | uniq -d | sed -n 1p` if test -n "$tmp"; then - echo "The drive $tmp is defined multiple times in the device map $device_map" 1>&2 + echo "The drive $tmp is defined multiple times in the new device map." 1>&2 + if test $recheck = yes; then + echo "Reverting to backed up copy." 1>&2 + mv ${device_map}.backup $device_map + fi + exit 1 +fi + +# Make sure device.map has at least one hd device +grep -q "^(hd[0-9]\+)" $device_map +if [ "x$?" != "x0" ]; then + echo "No suitable drive was found in the generated device map." 1>&2 + if test $recheck = yes; then + echo "Reverting to backed up copy." 1>&2 + mv ${device_map}.backup $device_map + fi exit 1 fi @@ -359,23 +511,34 @@ fi case "$install_device" in /dev/*) install_device=`resolve_symlink "$install_device"` - install_drive=`convert "$install_device"` - # I don't know why, but some shells wouldn't die if exit is - # called in a function. - if test "x$install_drive" = x; then + for install_drive in `find_real_devs $install_device` ; do + install_drive=`convert $install_drive` + if is_raid1_device $install_device; then + install_drive=`echo $install_drive | sed 's/,[0-9]*)/)/'` + fi + if [ "x$install_drive" = "x" ]; then + exit 1 + fi + install_drives="${install_drives} ${install_drive}" + done + unset install_drive + + if test "x$install_drives" = x ; then exit 1 fi ;; \([hf]d[0-9]*\)) - install_drive="$install_device" ;; + install_drives="$install_device" ;; [hf]d[0-9]*) # The GRUB format with no parenthesis. - install_drive="($install_device)" ;; + install_drives="($install_device)" ;; *) echo "Format of install_device not recognized." 1>&2 usage exit 1 ;; esac +unset install_device + # Get the root drive. root_device=`find_device ${rootdir}` bootdir_device=`find_device ${bootdir}` @@ -387,14 +550,7 @@ if test "x$root_device" != "x$bootdir_device"; then grub_prefix="/grub" fi -# Convert the root device to a GRUB drive. -root_drive=`convert "$root_device"` -if test "x$root_drive" = x; then - exit 1 -fi - -# Check if the root directory exists in the same device as the grub -# directory. +# Check if the root directory exists in the same device as the grub directory. grubdir_device=`find_device ${grubdir}` if test "x$grubdir_device" != "x$root_device"; then @@ -406,14 +562,19 @@ EOF exit 1 fi -# Copy the GRUB images to the GRUB directory. -for file in ${grubdir}/stage1 ${grubdir}/stage2 ${grubdir}/*stage1_5; do - rm -f $file || exit 1 -done -for file in \ - ${pkglibdir}/stage1 ${pkglibdir}/stage2 ${pkglibdir}/*stage1_5; do - cp -f $file ${grubdir} || exit 1 -done +# FHS says that /usr/share is used for architecture independent data, +# so all stage-files are directly installed to /usr/lib/grub. +# Therefor this part is no longer needed. +# <--cut_here--> +## Copy the GRUB images to the GRUB directory. +#for file in ${grubdir}/stage1 ${grubdir}/stage2 ${grubdir}/*stage1_5; do +# rm -f $file || exit 1 +#done +#for file in \ +# ${pkglibdir}/stage1 ${pkglibdir}/stage2 ${pkglibdir}/*stage1_5; do +# cp -f $file ${grubdir} || exit 1 +#done +# <--uncut--> # Make a default file. ${grub_set_default} --root-directory=${rootdir} default @@ -422,25 +583,33 @@ ${grub_set_default} --root-directory=${rootdir} default test -n "$mkimg" && img_file=`$mkimg` test -n "$mklog" && log_file=`$mklog` +# There's not a real root device, so just pick the first +if is_raid1_device $root_device ; then + root_device=`find_real_devs $root_device | awk '{print $1}'` +fi + +# Convert the root deviceto a GRUB drive. +root_drive=`convert "$root_device"` +if [ "x$root_drive" = x ]; then + exit 1 +fi + for file in ${grubdir}/stage1 ${grubdir}/stage2 ${grubdir}/*stage1_5; do count=5 tmp=`echo $file | sed "s|^${grubdir}|${grub_prefix}|"` while test $count -gt 0; do - $grub_shell --batch $no_floppy --device-map=$device_map <$log_file -dump ${root_drive}${tmp} ${img_file} -quit -EOF - if grep "Error [0-9]*: " $log_file >/dev/null; then - : - elif cmp $file $img_file >/dev/null; then - break - fi - sleep 1 - count=`expr $count - 1` + dump_boot_block $root_drive $img_file + if grep "Error [0-9]*: " $log_file >/dev/null; then + : + elif cmp $file $img_file >/dev/null; then + break + fi + sleep 1 + count=`expr $count - 1` done if test $count -eq 0; then - echo "The file $file not read correctly." 1>&2 - exit 1 + echo "The file $file not read correctly." 1>&2 + exit 1 fi done @@ -450,17 +619,22 @@ rm -f $log_file # Create a safe temporary file. test -n "$mklog" && log_file=`$mklog` -# Now perform the installation. -$grub_shell --batch $no_floppy --device-map=$device_map <$log_file -root $root_drive -setup $force_lba --stage2=$grubdir/stage2 --prefix=$grub_prefix $install_drive -quit -EOF +for install_drive in $install_drives; do + # Convert the root deviceto a GRUB drive. + root_drive=`convert "$root_device"` + if [ "x$root_drive" = x ]; then + exit 1 + fi + install_boot_block $root_drive $install_drive +done -if grep "Error [0-9]*: " $log_file >/dev/null || test $debug = yes; then +if grep "Error [0-9]*: " $log_file >/dev/null ; then cat $log_file 1>&2 exit 1 fi +if test $debug = yes; then + cat $log_file 1>&2 +fi rm -f $log_file diff --git a/util/grub-md5-crypt.in b/util/grub-md5-crypt.in index c030c87..e327676 100644 --- a/util/grub-md5-crypt.in +++ b/util/grub-md5-crypt.in @@ -88,7 +88,7 @@ if test "x$password" != "x$password2"; then fi # Run the grub shell. -$grub_shell --batch --device-map=/dev/null <