From 27996c53e756406da9bcf45c1ce7583c2412666c Mon Sep 17 00:00:00 2001 From: ms Date: Sat, 12 Aug 2006 15:16:04 +0000 Subject: [PATCH] =?utf8?q?Hinzugef=C3=BCgt:=20=20=20*=20GFXBoot=20-=20expe?= =?utf8?q?rimental?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit git-svn-id: http://svn.ipfire.org/svn/ipfire/trunk@244 ea5c0bd1-69bd-2848-81d8-4f18e57aeed8 --- config/aboot/scsiaboot.conf | 2 +- config/grub/grub.conf | 24 +- config/grub/message | Bin 0 -> 142848 bytes config/grub/scsigrub.conf | 24 +- doc/packages-list.txt | 1 + lfs/grub | 46 +- src/ROOTFILES.i386 | 1 + src/install+setup/install/grubbatch | 2 +- src/patches/grub-0.97/README | 30 + src/patches/grub-0.97/grub-0.96-PIC.patch | 71 + .../grub-0.97/grub-0.96-bounced-checks.patch | 19 + .../grub-0.97/grub-0.96-i2o-raid.patch | 61 + .../grub-0.97/grub-0.96-netboot-pic.patch | 15 + src/patches/grub-0.97/grub-0.96-nxstack.patch | 617 +++++++++ .../grub-0.97/grub-0.97-configfile.patch | 80 ++ src/patches/grub-0.97/grub-0.97-dirs.patch | 78 ++ src/patches/grub-0.97/grub-0.97-misc.patch | 94 ++ src/patches/grub-0.97/grub-0.97-splash.patch | 943 +++++++++++++ .../grub-0.97/grub-0.97-symlinkmenulst.patch | 14 + .../grub-0.97/grub-0.97-wildcards.patch | 1188 +++++++++++++++++ src/rc.d/rc.halt | 20 +- 21 files changed, 3285 insertions(+), 45 deletions(-) create mode 100644 config/grub/message create mode 100644 src/patches/grub-0.97/README create mode 100644 src/patches/grub-0.97/grub-0.96-PIC.patch create mode 100644 src/patches/grub-0.97/grub-0.96-bounced-checks.patch create mode 100644 src/patches/grub-0.97/grub-0.96-i2o-raid.patch create mode 100644 src/patches/grub-0.97/grub-0.96-netboot-pic.patch create mode 100644 src/patches/grub-0.97/grub-0.96-nxstack.patch create mode 100644 src/patches/grub-0.97/grub-0.97-configfile.patch create mode 100644 src/patches/grub-0.97/grub-0.97-dirs.patch create mode 100644 src/patches/grub-0.97/grub-0.97-misc.patch create mode 100644 src/patches/grub-0.97/grub-0.97-splash.patch create mode 100644 src/patches/grub-0.97/grub-0.97-symlinkmenulst.patch create mode 100644 src/patches/grub-0.97/grub-0.97-wildcards.patch diff --git a/config/aboot/scsiaboot.conf b/config/aboot/scsiaboot.conf index b3f0fb3cd3..4915e41d63 100644 --- a/config/aboot/scsiaboot.conf +++ b/config/aboot/scsiaboot.conf @@ -1 +1 @@ -0:1/vmlinuz root=ROOT panic=10 initrd=ipcoprd.img init=/linuxrc rw +0:1/vmlinuz root=ROOT panic=10 initrd=ipfirerd.img init=/linuxrc rw diff --git a/config/grub/grub.conf b/config/grub/grub.conf index ff9af0b3c6..543f976552 100644 --- a/config/grub/grub.conf +++ b/config/grub/grub.conf @@ -1,45 +1,47 @@ -timeout 5 -default saved +timeout 10 +#default saved foreground = 16064e background = ffffff -splashimage (hd0,0)/grub/ipfire.xpm.gz +gfxmenu /grub/message +#hiddenmenu +#splashimage (hd0,0)/grub/ipfire.xpm.gz title IPFire (1024x768) root (hd0,0) kernel /vmlinuz root=ROOT panic=10 acpi=off vga=791 splash=silent ro initrd /initrd.splash - savedefault + #savedefault title IPFire (640x480) root (hd0,0) kernel /vmlinuz root=ROOT panic=10 acpi=off vga=785 splash=silent ro initrd /initrd.splash - savedefault + #savedefault title IPFire SMP (1024x768) root (hd0,0) kernel /vmlinuz-smp root=ROOT panic=10 acpi=off vga=791 splash=silent ro initrd /initrd.splash - savedefault + #savedefault title IPFire SMP (640x480) root (hd0,0) kernel /vmlinuz-smp root=ROOT panic=10 acpi=off vga=785 splash=silent ro initrd /initrd.splash - savedefault + #savedefault title IPFire (ACPI enabled) (1024x768) root (hd0,0) kernel /vmlinuz root=ROOT panic=10 vga=791 splash=silent ro initrd /initrd.splash - savedefault + #savedefault title IPFire (ACPI enabled) (640x480) root (hd0,0) kernel /vmlinuz root=ROOT panic=10 vga=785 splash=silent ro initrd /initrd.splash - savedefault + #savedefault title IPFire SMP (ACPI HT enabled) (1024x768) root (hd0,0) kernel /vmlinuz-smp root=ROOT panic=10 acpi=ht vga=791 splash=silent ro initrd /initrd.splash - savedefault + #savedefault title IPFire SMP (ACPI HT enabled) (640x480) root (hd0,0) kernel /vmlinuz-smp root=ROOT panic=10 acpi=ht vga=785 splash=silent ro initrd /initrd.splash - savedefault + #savedefault diff --git a/config/grub/message b/config/grub/message new file mode 100644 index 0000000000000000000000000000000000000000..6825ac916bb684558fcb57eda41d7a27fe907f2b GIT binary patch literal 142848 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

`do~F&orCXeQ- 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%0D;C^?$T1jtY!61k}yBP1d>gFZ|Ue+Q;H^nv%s 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 literal 0 Hc-jL100001 diff --git a/config/grub/scsigrub.conf b/config/grub/scsigrub.conf index 13a850a183..9b20e03bd0 100644 --- a/config/grub/scsigrub.conf +++ b/config/grub/scsigrub.conf @@ -1,45 +1,47 @@ -timeout 5 -default saved +timeout 10 +#default saved foreground = 16064e background = ffffff -splashimage (hd0,0)/grub/ipfire.xpm.gz +gfxmenu /grub/message +#hiddenmenu +#splashimage (hd0,0)/grub/ipfire.xpm.gz title IPFire (1024x768) root (hd0,0) kernel /vmlinuz root=ROOT panic=10 init=/linuxrc acpi=off vga=791 splash=silent rw initrd /ipfirerd.img - savedefault + #savedefault title IPFire (640x480) root (hd0,0) kernel /vmlinuz root=ROOT panic=10 init=/linuxrc acpi=off vga=785 splash=silent rw initrd /ipfirerd.img - savedefault + #savedefault title IPFire SMP (1024x768) root (hd0,0) kernel /vmlinuz-smp root=ROOT panic=10 init=/linuxrc acpi=off vga=791 splash=silent rw initrd /ipfirerd-smp.img - savedefault + #savedefault title IPFire SMP (640x480) root (hd0,0) kernel /vmlinuz-smp root=ROOT panic=10 init=/linuxrc acpi=off vga=785 splash=silent rw initrd /ipfirerd-smp.img - savedefault + #savedefault title IPFire (ACPI enabled) (1024x768) root (hd0,0) kernel /vmlinuz root=ROOT panic=10 init=/linuxrc vga=791 splash=silent rw initrd /ipfirerd.img - savedefault + #savedefault title IPFire (ACPI enabled) (640x480) root (hd0,0) kernel /vmlinuz root=ROOT panic=10 init=/linuxrc vga=785 splash=silent rw initrd /ipfirerd.img - savedefault + #savedefault title IPFire SMP (ACPI HT enabled) (1024x768) root (hd0,0) kernel /vmlinuz-smp root=ROOT panic=10 init=/linuxrc acpi=ht vga=791 splash=silent rw initrd /ipfirerd-smp.img - savedefault + #savedefault title IPFire SMP (ACPI HT enabled) (640x480) root (hd0,0) kernel /vmlinuz-smp root=ROOT panic=10 init=/linuxrc acpi=ht vga=785 splash=silent rw initrd /ipfirerd-smp.img - savedefault + #savedefault diff --git a/doc/packages-list.txt b/doc/packages-list.txt index ab533270f8..caa14196b1 100644 --- a/doc/packages-list.txt +++ b/doc/packages-list.txt @@ -104,6 +104,7 @@ * grep-2.5.1 * groff-1.19 * grub-0.95 + * grub-0.97 * gzip-1.3.5 * hddtemp-0.3-beta14 * hdparm-6.3 diff --git a/lfs/grub b/lfs/grub index aa5dc69a00..d0800523e6 100644 --- a/lfs/grub +++ b/lfs/grub @@ -32,7 +32,7 @@ include Config -VER = 0.95 +VER = 0.97 THISAPP = grub-$(VER) DL_FILE = $(THISAPP).tar.gz @@ -50,7 +50,7 @@ objects = $(DL_FILE) $(DL_FILE) = $(DL_FROM)/$(DL_FILE) -$(DL_FILE)_MD5 = 4ca8e4363d5f1980f2c63b7f5cdbe0d1 +$(DL_FILE)_MD5 = cd3f3eb54446be6003156158d51f4884 install : $(TARGET) @@ -80,21 +80,45 @@ $(subst %,%_MD5,$(objects)) : $(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects)) @$(PREBUILD) @rm -rf $(DIR_APP) && cd $(DIR_SRC) && tar zxf $(DIR_DL)/$(DL_FILE) - cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/grub-0.93-configfile.patch - cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/grub-0.90-symlinkmenulst.patch - cd $(DIR_APP) && patch -Np0 < $(DIR_SRC)/src/patches/grub-0.93-endedit.patch - cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/grub-0.90-append.patch - cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/grub-0.91-bootonce.patch - cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/grub-0.93-graphics.patch - cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/grub-0.91-splashimagehelp.patch - cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/grub-0.93-graphics-bootterm.patch + +# cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/grub-0.93-configfile.patch +# cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/grub-0.90-symlinkmenulst.patch +# cd $(DIR_APP) && patch -Np0 < $(DIR_SRC)/src/patches/grub-0.93-endedit.patch +# cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/grub-0.90-append.patch +# cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/grub-0.91-bootonce.patch +# cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/grub-0.93-graphics.patch +# cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/grub-0.91-splashimagehelp.patch +# cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/grub-0.93-graphics-bootterm.patch +# cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/grub-0.93-special-device-names.patch +# cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/grub-0.94-i2o.patch +# cd $(DIR_APP)/netboot && patch -Np0 < $(DIR_SRC)/src/patches/grub-0.93-rtl8139.patch + + cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/grub-0.97/grub-0.97-configfile.patch + cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/grub-0.97/grub-0.97-symlinkmenulst.patch +# cd $(DIR_APP) && patch -Np0 < $(DIR_SRC)/src/patches/grub-0.93-endedit.patch +# cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/grub-0.90-append.patch +# cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/grub-0.91-bootonce.patch + cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/grub-0.97/grub-0.97-misc.patch + cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/grub-0.97/grub-0.97-dirs.patch + +# cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/grub-0.93-graphics.patch +# cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/grub-0.91-splashimagehelp.patch +# cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/grub-0.93-graphics-bootterm.patch + cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/grub-0.97/grub-0.97-splash.patch +# cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/grub-0.97/grub-0.97-wildcards.patch +# cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/grub-0.97/grub-0.96-PIC.patch +# cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/grub-0.97/grub-0.96-bounced-checks.patch cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/grub-0.93-special-device-names.patch +# cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/grub-0.97/grub-0.96-i2o-raid.patch cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/grub-0.94-i2o.patch +# cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/grub-0.97/grub-0.96-nxstack.patch +# cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/grub-0.97/grub-0.96-netboot-pic.patch cd $(DIR_APP)/netboot && patch -Np0 < $(DIR_SRC)/src/patches/grub-0.93-rtl8139.patch + cd $(DIR_APP) && autoreconf --install --force cd $(DIR_APP) && CFLAGS="-Os -fno-stack-protector" \ STAGE2_CFLAGS="-Os -fno-stack-protector" \ - ./configure --prefix=/usr \ + ./configure --prefix=/usr --datadir=/usr/share \ --enable-rtl8139 \ --enable-ne --enable-ne-scan=0x300 \ --disable-nls \ diff --git a/src/ROOTFILES.i386 b/src/ROOTFILES.i386 index 2ece52dec5..4eddbcdbd4 100644 --- a/src/ROOTFILES.i386 +++ b/src/ROOTFILES.i386 @@ -1267,6 +1267,7 @@ boot/grub/grub.conf boot/grub/grubbatch boot/grub/ipfire.xpm.gz boot/grub/scsigrub.conf +boot/grub/message #usr/bin/mbchk usr/sbin/grub usr/sbin/grub-install diff --git a/src/install+setup/install/grubbatch b/src/install+setup/install/grubbatch index 405baf2761..2893d63e46 100644 --- a/src/install+setup/install/grubbatch +++ b/src/install+setup/install/grubbatch @@ -1,6 +1,6 @@ #!/bin/sh /bin/cp -f /usr/share/grub/i386-pc/* /boot/grub -/usr/sbin/grub --no-floppy --batch < /dev/null 2> /dev/null +/usr/sbin/grub --no-floppy --batch < /dev/null 2> /dev/null device (hd0) DEVICE root (hd0,0) setup (hd0,0) diff --git a/src/patches/grub-0.97/README b/src/patches/grub-0.97/README new file mode 100644 index 0000000000..3fffda6c04 --- /dev/null +++ b/src/patches/grub-0.97/README @@ -0,0 +1,30 @@ +This file describes the patches in the patchsets: + +001_all_grub-0.97-misc.patch + Several simple fixes + +002_all_grub-0.97-splash.patch + Port of the SuSE's gfxboot patch + +003_all_grub-0.97-dirs.patch + FHS compilance + +004_all_grub-0.97-wildcards.patch + Port of the SuSE's wildcards patch with custom nice sorting addon + +005_all_grub-0.96-PIC.patch: + a patch to fix PIC issues by psm and Kevin F. Quinn in Gentoo bug #80693 + +010_all_grub-0.96-bounced-checks.patch: + Disables testing of FFS and UFS2 images (which always fail). See Gentoo bug + #71811 + +020_all_grub-0.96-i2o-raid.patch: + Support i2o RAID. See Gentoo bug #76143 + +040_all_grub-0.96-nxstack.patch: + Fix NX segfaulting on amd64 and x86_64. The patch is by Peter Jones. + See: http://lists.gnu.org/archive/html/bug-grub/2005-03/msg00011.html + +060_all_grub-0.96-netboot-pic.patch + Fix PIC issues in netboot code. See Gentoo bug #85566 diff --git a/src/patches/grub-0.97/grub-0.96-PIC.patch b/src/patches/grub-0.97/grub-0.96-PIC.patch new file mode 100644 index 0000000000..c69c0fa0e3 --- /dev/null +++ b/src/patches/grub-0.97/grub-0.96-PIC.patch @@ -0,0 +1,71 @@ +--- grub-0.96/stage2/char_io.c.orig 2005-02-18 09:12:39.163407496 +0100 ++++ grub-0.96/stage2/char_io.c 2005-02-18 09:13:11.431502000 +0100 +@@ -1202,37 +1202,62 @@ + } + #endif /* ! STAGE1_5 */ + ++#ifdef GRUB_UTIL ++# ifdef __PIC__ ++# if defined(HAVE_START_SYMBOL) && defined(HAVE_END_SYMBOL) ++ extern char start[]; ++ extern char end[]; ++# elif defined(HAVE_USCORE_START_SYMBOL) && defined (HAVE_USCORE_END_SYMBOL) ++ extern char _start[]; ++ extern char _end[]; ++# endif ++# endif ++#endif + int + memcheck (int addr, int len) + { + #ifdef GRUB_UTIL ++# ifdef __PIC__ ++# if defined(HAVE_START_SYMBOL) && defined(HAVE_END_SYMBOL) ++ if (start <= addr && end > addr + len) ++ return ! errnum; ++# elif defined(HAVE_USCORE_START_SYMBOL) && defined (HAVE_USCORE_END_SYMBOL) ++ if (_start <= addr && _end > addr + len) ++ return ! errnum; ++# endif ++# else /* __PIC__ */ + auto int start_addr (void); + auto int end_addr (void); + + auto int start_addr (void) + { + int ret; +-# if defined(HAVE_START_SYMBOL) ++# if defined(HAVE_START_SYMBOL) + asm volatile ("movl $start, %0" : "=a" (ret)); +-# elif defined(HAVE_USCORE_START_SYMBOL) ++# elif defined(HAVE_USCORE_START_SYMBOL) + asm volatile ("movl $_start, %0" : "=a" (ret)); +-# endif ++# else ++ erk! /* function would return undefined data in this case - barf */ ++# endif + return ret; + } + + auto int end_addr (void) + { + int ret; +-# if defined(HAVE_END_SYMBOL) ++# if defined(HAVE_END_SYMBOL) + asm volatile ("movl $end, %0" : "=a" (ret)); +-# elif defined(HAVE_USCORE_END_SYMBOL) ++# elif defined(HAVE_USCORE_END_SYMBOL) + asm volatile ("movl $_end, %0" : "=a" (ret)); +-# endif ++# else ++ erk! /* function would return undefined data in this case - barf */ ++# endif + return ret; + } + + if (start_addr () <= addr && end_addr () > addr + len) + return ! errnum; ++# endif /* __PIC__ */ + #endif /* GRUB_UTIL */ + + if ((addr < RAW_ADDR (0x1000)) diff --git a/src/patches/grub-0.97/grub-0.96-bounced-checks.patch b/src/patches/grub-0.97/grub-0.96-bounced-checks.patch new file mode 100644 index 0000000000..6ad2c82ee0 --- /dev/null +++ b/src/patches/grub-0.97/grub-0.96-bounced-checks.patch @@ -0,0 +1,19 @@ +Remove tests that the grub maintainers say can be ignored. + +http://lists.gnu.org/archive/html/bug-grub/2004-05/msg00076.html + +--- grub-0.96/stage2/size_test ++++ grub-0.96/stage2/size_test +@@ -36,9 +36,9 @@ + } + + # The bootloader area of a FFS partition is 14 sectors. +-check ffs_stage1_5 7168 +- +-check ufs2_stage1_5 7168 ++#check ffs_stage1_5 7168 ++# ++#check ufs2_stage1_5 7168 + + # Stage 1.5 can be installed in the sectors immediately after MBR in the + # first cylinder, so the size is (63 - 1) sectors. diff --git a/src/patches/grub-0.97/grub-0.96-i2o-raid.patch b/src/patches/grub-0.97/grub-0.96-i2o-raid.patch new file mode 100644 index 0000000000..5beec6f811 --- /dev/null +++ b/src/patches/grub-0.97/grub-0.96-i2o-raid.patch @@ -0,0 +1,61 @@ +diff -ru grub-0.96-orig/lib/device.c grub-0.96/lib/device.c +--- grub-0.96-orig/lib/device.c 2005-02-16 22:33:09.669384408 -0600 ++++ grub-0.96/lib/device.c 2005-02-17 00:47:05.127596672 -0600 +@@ -407,6 +407,12 @@ + { + 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, +@@ -798,6 +804,26 @@ + } + } + } ++ ++ /* 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__ */ + + /* OK, close the device map file if opened. */ +@@ -858,8 +884,15 @@ + if (strcmp (dev + strlen(dev) - 5, "/disc") == 0) + strcpy (dev + strlen(dev) - 5, "/part"); + } +- sprintf (dev + strlen(dev), "%d", ((partition >> 16) & 0xFF) + 1); +- ++ sprintf (dev + strlen(dev), "%s%d", ++ /* Compaq smart and others */ ++ (strncmp(dev, "/dev/ida/", 9) == 0 || ++ strncmp(dev, "/dev/ataraid/", 13) == 0 || ++ strncmp(dev, "/dev/cciss/", 11) == 0 || ++ strncmp(dev, "/dev/rd/", 8) == 0 || ++ strncmp(dev, "/dev/i2o/", 9) == 0) ? "p" : "", ++ ((partition >> 16) & 0xFF) + 1); ++ + /* Open the partition. */ + fd = open (dev, O_RDWR); + if (fd < 0) diff --git a/src/patches/grub-0.97/grub-0.96-netboot-pic.patch b/src/patches/grub-0.97/grub-0.96-netboot-pic.patch new file mode 100644 index 0000000000..5cac692bb2 --- /dev/null +++ b/src/patches/grub-0.97/grub-0.96-netboot-pic.patch @@ -0,0 +1,15 @@ +Patch by the PaX Team to fix PIC/PIE problems. + +http://bugs.gentoo.org/show_bug.cgi?id=85566 + +--- netboot/main.c ++++ netboot/main.c +@@ -701,7 +701,7 @@ + "adcw %%ax,%0\n\t" /* add carry of previous iteration */ + "loop 1b\n\t" + "adcw $0,%0" /* add carry of last iteration */ +- : "=b" (*sum), "=S"(start), "=c"(len) ++ : "=r" (*sum), "=S"(start), "=c"(len) + : "0"(*sum), "1"(start), "2"(len) + : "ax", "cc" + ); diff --git a/src/patches/grub-0.97/grub-0.96-nxstack.patch b/src/patches/grub-0.97/grub-0.96-nxstack.patch new file mode 100644 index 0000000000..ebfa82b808 --- /dev/null +++ b/src/patches/grub-0.97/grub-0.96-nxstack.patch @@ -0,0 +1,617 @@ +--- grub-0.97/grub/asmstub.c ++++ grub-0.97/grub/asmstub.c +@@ -42,6 +42,7 @@ + #include + #include + #include ++#include + + #ifdef __linux__ + # include /* ioctl */ +@@ -79,7 +80,7 @@ + struct apm_info apm_bios_info; + + /* Emulation requirements. */ +-char *grub_scratch_mem = 0; ++void *grub_scratch_mem = 0; + + struct geometry *disks = 0; + +@@ -103,14 +104,62 @@ + static unsigned int serial_speed; + #endif /* SIMULATE_SLOWNESS_OF_SERIAL */ + ++/* This allocates page-aligned storage of the specified size, which must be ++ * a multiple of the page size as determined by calling sysconf(_SC_PAGESIZE) ++ */ ++#ifdef __linux__ ++static void * ++grub_mmap_alloc(size_t len) ++{ ++ int mmap_flags = MAP_ANONYMOUS|MAP_PRIVATE|MAP_EXECUTABLE; ++ ++#ifdef MAP_32BIT ++ mmap_flags |= MAP_32BIT; ++#endif ++ /* Mark the simulated stack executable, as GCC uses stack trampolines ++ * to implement nested functions. */ ++ return mmap(NULL, len, PROT_READ|PROT_WRITE|PROT_EXEC, mmap_flags, -1, 0); ++} ++#else /* !defined(__linux__) */ ++static void * ++grub_mmap_alloc(size_t len) ++{ ++ int fd = 0, offset = 0, ret = 0; ++ void *pa = MAP_FAILED; ++ char template[] = "/tmp/grub_mmap_alloc_XXXXXX"; ++ errno_t e; ++ ++ fd = mkstemp(template); ++ if (fd < 0) ++ return pa; ++ ++ unlink(template); ++ ++ ret = ftruncate(fd, len); ++ if (ret < 0) ++ return pa; ++ ++ /* Mark the simulated stack executable, as GCC uses stack trampolines ++ * to implement nested functions. */ ++ pa = mmap(NULL, len, PROT_READ|PROT_WRITE|PROT_EXEC, ++ MAP_PRIVATE|MAP_EXECUTABLE, fd, offset); ++ ++ e = errno; ++ close(fd); ++ errno = e; ++ return pa; ++} ++#endif /* defined(__linux__) */ ++ + /* The main entry point into this mess. */ + int + grub_stage2 (void) + { + /* These need to be static, because they survive our stack transitions. */ + static int status = 0; +- static char *realstack; +- char *scratch, *simstack; ++ static void *realstack; ++ void *simstack_alloc_base, *simstack; ++ size_t simstack_size, page_size; + int i; + + /* We need a nested function so that we get a clean stack frame, +@@ -140,9 +189,35 @@ + } + + assert (grub_scratch_mem == 0); +- scratch = malloc (0x100000 + EXTENDED_MEMSIZE + 15); +- assert (scratch); +- grub_scratch_mem = (char *) ((((int) scratch) >> 4) << 4); ++ ++ /* Allocate enough pages for 0x100000 + EXTENDED_SIZE + 15, and ++ * make sure the memory is aligned to a multiple of the system's ++ * page size */ ++ page_size = sysconf (_SC_PAGESIZE); ++ simstack_size = ( 0x100000 + EXTENDED_MEMSIZE + 15); ++ if (simstack_size % page_size) ++ { ++ /* If we're not on a page_size boundary, round up to the next one */ ++ simstack_size &= ~(page_size-1); ++ simstack_size += page_size; ++ } ++ ++ /* Add one for a PROT_NONE boundary page at each end. */ ++ simstack_size += 2 * page_size; ++ ++ simstack_alloc_base = grub_mmap_alloc(simstack_size); ++ assert (simstack_alloc_base != MAP_FAILED); ++ ++ /* mark pages above and below our simstack area as innaccessable. ++ * If the implementation we're using doesn't support that, then the ++ * new protection modes are undefined. It's safe to just ignore ++ * them, though. It'd be nice if we knew that we'd get a SEGV for ++ * touching the area, but that's all. it'd be nice to have. */ ++ mprotect (simstack_alloc_base, page_size, PROT_NONE); ++ mprotect ((void *)((unsigned long)simstack_alloc_base + ++ simstack_size - page_size), page_size, PROT_NONE); ++ ++ grub_scratch_mem = (void *)((unsigned long)simstack_alloc_base + page_size); + + /* FIXME: simulate the memory holes using mprot, if available. */ + +@@ -215,7 +290,7 @@ + device_map = 0; + free (disks); + disks = 0; +- free (scratch); ++ munmap(simstack_alloc_base, simstack_size); + grub_scratch_mem = 0; + + if (serial_device) +--- grub-0.97/stage2/builtins.c ++++ grub-0.97/stage2/builtins.c +@@ -131,63 +131,98 @@ + } + + ++/* blocklist_read_helper nee disk_read_blocklist_func was a nested ++ * function, to which pointers were taken and exposed globally. Even ++ * in the GNU-C nested functions extension, they have local linkage, ++ * and aren't guaranteed to be accessable *at all* outside of their ++ * containing scope. ++ * ++ * Above and beyond all of that, the variables within blocklist_func_context ++ * are originally local variables, with local (not even static) linkage, ++ * from within blocklist_func. These were each referenced by ++ * disk_read_blocklist_func, which is only called from other functions ++ * through a globally scoped pointer. ++ * ++ * The documentation in GCC actually uses the words "all hell will break ++ * loose" to describe this scenario. ++ * ++ * Also, "start_sector" was also used uninitialized, but gcc doesn't warn ++ * about it (possibly because of the scoping madness?) ++ */ ++ ++static struct { ++ int start_sector; ++ int num_sectors; ++ int num_entries; ++ int last_length; ++} blocklist_func_context = { ++ .start_sector = 0, ++ .num_sectors = 0, ++ .num_entries = 0, ++ .last_length = 0 ++}; ++ ++/* Collect contiguous blocks into one entry as many as possible, ++ and print the blocklist notation on the screen. */ ++static void ++blocklist_read_helper (int sector, int offset, int length) ++{ ++ int *start_sector = &blocklist_func_context.start_sector; ++ int *num_sectors = &blocklist_func_context.num_sectors; ++ int *num_entries = &blocklist_func_context.num_entries; ++ int *last_length = &blocklist_func_context.last_length; ++ ++ if (*num_sectors > 0) ++ { ++ if (*start_sector + *num_sectors == sector ++ && offset == 0 && *last_length == SECTOR_SIZE) ++ { ++ *num_sectors++; ++ *last_length = length; ++ return; ++ } ++ else ++ { ++ if (*last_length == SECTOR_SIZE) ++ grub_printf ("%s%d+%d", *num_entries ? "," : "", ++ *start_sector - part_start, *num_sectors); ++ else if (*num_sectors > 1) ++ grub_printf ("%s%d+%d,%d[0-%d]", *num_entries ? "," : "", ++ *start_sector - part_start, *num_sectors-1, ++ *start_sector + *num_sectors-1 - part_start, ++ *last_length); ++ else ++ grub_printf ("%s%d[0-%d]", *num_entries ? "," : "", ++ *start_sector - part_start, *last_length); ++ *num_entries++; ++ *num_sectors = 0; ++ } ++ } ++ ++ if (offset > 0) ++ { ++ grub_printf("%s%d[%d-%d]", *num_entries ? "," : "", ++ sector-part_start, offset, offset+length); ++ *num_entries++; ++ } ++ else ++ { ++ *start_sector = sector; ++ *num_sectors = 1; ++ *last_length = length; ++ } ++} ++ + /* blocklist */ + static int + blocklist_func (char *arg, int flags) + { + char *dummy = (char *) RAW_ADDR (0x100000); +- int start_sector; +- int num_sectors = 0; +- int num_entries = 0; +- int last_length = 0; +- +- auto void disk_read_blocklist_func (int sector, int offset, int length); +- +- /* Collect contiguous blocks into one entry as many as possible, +- and print the blocklist notation on the screen. */ +- auto void disk_read_blocklist_func (int sector, int offset, int length) +- { +- if (num_sectors > 0) +- { +- if (start_sector + num_sectors == sector +- && offset == 0 && last_length == SECTOR_SIZE) +- { +- num_sectors++; +- last_length = length; +- return; +- } +- else +- { +- if (last_length == SECTOR_SIZE) +- grub_printf ("%s%d+%d", num_entries ? "," : "", +- start_sector - part_start, num_sectors); +- else if (num_sectors > 1) +- grub_printf ("%s%d+%d,%d[0-%d]", num_entries ? "," : "", +- start_sector - part_start, num_sectors-1, +- start_sector + num_sectors-1 - part_start, +- last_length); +- else +- grub_printf ("%s%d[0-%d]", num_entries ? "," : "", +- start_sector - part_start, last_length); +- num_entries++; +- num_sectors = 0; +- } +- } +- +- if (offset > 0) +- { +- grub_printf("%s%d[%d-%d]", num_entries ? "," : "", +- sector-part_start, offset, offset+length); +- num_entries++; +- } +- else +- { +- start_sector = sector; +- num_sectors = 1; +- last_length = length; +- } +- } + ++ int *start_sector = &blocklist_func_context.start_sector; ++ int *num_sectors = &blocklist_func_context.num_sectors; ++ int *num_entries = &blocklist_func_context.num_entries; ++ + /* Open the file. */ + if (! grub_open (arg)) + return 1; +@@ -204,15 +241,15 @@ + grub_printf (")"); + + /* Read in the whole file to DUMMY. */ +- disk_read_hook = disk_read_blocklist_func; ++ disk_read_hook = blocklist_read_helper; + if (! grub_read (dummy, -1)) + goto fail; + + /* The last entry may not be printed yet. Don't check if it is a + * full sector, since it doesn't matter if we read too much. */ +- if (num_sectors > 0) +- grub_printf ("%s%d+%d", num_entries ? "," : "", +- start_sector - part_start, num_sectors); ++ if (*num_sectors > 0) ++ grub_printf ("%s%d+%d", *num_entries ? "," : "", ++ *start_sector - part_start, *num_sectors); + + grub_printf ("\n"); + +@@ -1868,6 +1905,77 @@ + + + /* install */ ++static struct { ++ int saved_sector; ++ int installaddr; ++ int installlist; ++ char *stage2_first_buffer; ++} install_func_context = { ++ .saved_sector = 0, ++ .installaddr = 0, ++ .installlist = 0, ++ .stage2_first_buffer = NULL, ++}; ++ ++/* Save the first sector of Stage2 in STAGE2_SECT. */ ++/* Formerly disk_read_savesect_func with local scope inside install_func */ ++static void ++install_savesect_helper(int sector, int offset, int length) ++{ ++ if (debug) ++ printf ("[%d]", sector); ++ ++ /* ReiserFS has files which sometimes contain data not aligned ++ on sector boundaries. Returning an error is better than ++ silently failing. */ ++ if (offset != 0 || length != SECTOR_SIZE) ++ errnum = ERR_UNALIGNED; ++ ++ install_func_context.saved_sector = sector; ++} ++ ++/* Write SECTOR to INSTALLLIST, and update INSTALLADDR and INSTALLSECT. */ ++/* Formerly disk_read_blocklist_func with local scope inside install_func */ ++static void ++install_blocklist_helper (int sector, int offset, int length) ++{ ++ int *installaddr = &install_func_context.installaddr; ++ int *installlist = &install_func_context.installlist; ++ char **stage2_first_buffer = &install_func_context.stage2_first_buffer; ++ /* Was the last sector full? */ ++ static int last_length = SECTOR_SIZE; ++ ++ if (debug) ++ printf("[%d]", sector); ++ ++ if (offset != 0 || last_length != SECTOR_SIZE) ++ { ++ /* We found a non-sector-aligned data block. */ ++ errnum = ERR_UNALIGNED; ++ return; ++ } ++ ++ last_length = length; ++ ++ if (*((unsigned long *) (*installlist - 4)) ++ + *((unsigned short *) *installlist) != sector ++ || *installlist == (int) *stage2_first_buffer + SECTOR_SIZE + 4) ++ { ++ *installlist -= 8; ++ ++ if (*((unsigned long *) (*installlist - 8))) ++ errnum = ERR_WONT_FIT; ++ else ++ { ++ *((unsigned short *) (*installlist + 2)) = (*installaddr >> 4); ++ *((unsigned long *) (*installlist - 4)) = sector; ++ } ++ } ++ ++ *((unsigned short *) *installlist) += 1; ++ *installaddr += 512; ++} ++ + static int + install_func (char *arg, int flags) + { +@@ -1875,8 +1983,12 @@ + char *stage1_buffer = (char *) RAW_ADDR (0x100000); + char *stage2_buffer = stage1_buffer + SECTOR_SIZE; + char *old_sect = stage2_buffer + SECTOR_SIZE; +- char *stage2_first_buffer = old_sect + SECTOR_SIZE; +- char *stage2_second_buffer = stage2_first_buffer + SECTOR_SIZE; ++ /* stage2_first_buffer used to be defined as: ++ * char *stage2_first_buffer = old_sect + SECTOR_SIZE; */ ++ char **stage2_first_buffer = &install_func_context.stage2_first_buffer; ++ /* and stage2_second_buffer was: ++ * char *stage2_second_buffer = stage2_first_buffer + SECTOR_SIZE; */ ++ char *stage2_second_buffer = old_sect + SECTOR_SIZE + SECTOR_SIZE; + /* XXX: Probably SECTOR_SIZE is reasonable. */ + char *config_filename = stage2_second_buffer + SECTOR_SIZE; + char *dummy = config_filename + SECTOR_SIZE; +@@ -1885,10 +1997,11 @@ + int src_drive, src_partition, src_part_start; + int i; + struct geometry dest_geom, src_geom; +- int saved_sector; ++ int *saved_sector = &install_func_context.saved_sector; + int stage2_first_sector, stage2_second_sector; + char *ptr; +- int installaddr, installlist; ++ int *installaddr = &install_func_context.installaddr; ++ int *installlist = &install_func_context.installlist; + /* Point to the location of the name of a configuration file in Stage 2. */ + char *config_file_location; + /* If FILE is a Stage 1.5? */ +@@ -1897,67 +2010,13 @@ + int is_open = 0; + /* If LBA is forced? */ + int is_force_lba = 0; +- /* Was the last sector full? */ +- int last_length = SECTOR_SIZE; +- ++ ++ *stage2_first_buffer = old_sect + SECTOR_SIZE; + #ifdef GRUB_UTIL + /* If the Stage 2 is in a partition mounted by an OS, this will store + the filename under the OS. */ + char *stage2_os_file = 0; + #endif /* GRUB_UTIL */ +- +- auto void disk_read_savesect_func (int sector, int offset, int length); +- auto void disk_read_blocklist_func (int sector, int offset, int length); +- +- /* Save the first sector of Stage2 in STAGE2_SECT. */ +- auto void disk_read_savesect_func (int sector, int offset, int length) +- { +- if (debug) +- printf ("[%d]", sector); +- +- /* ReiserFS has files which sometimes contain data not aligned +- on sector boundaries. Returning an error is better than +- silently failing. */ +- if (offset != 0 || length != SECTOR_SIZE) +- errnum = ERR_UNALIGNED; +- +- saved_sector = sector; +- } +- +- /* Write SECTOR to INSTALLLIST, and update INSTALLADDR and +- INSTALLSECT. */ +- auto void disk_read_blocklist_func (int sector, int offset, int length) +- { +- if (debug) +- printf("[%d]", sector); +- +- if (offset != 0 || last_length != SECTOR_SIZE) +- { +- /* We found a non-sector-aligned data block. */ +- errnum = ERR_UNALIGNED; +- return; +- } +- +- last_length = length; +- +- if (*((unsigned long *) (installlist - 4)) +- + *((unsigned short *) installlist) != sector +- || installlist == (int) stage2_first_buffer + SECTOR_SIZE + 4) +- { +- installlist -= 8; +- +- if (*((unsigned long *) (installlist - 8))) +- errnum = ERR_WONT_FIT; +- else +- { +- *((unsigned short *) (installlist + 2)) = (installaddr >> 4); +- *((unsigned long *) (installlist - 4)) = sector; +- } +- } +- +- *((unsigned short *) installlist) += 1; +- installaddr += 512; +- } + + /* First, check the GNU-style long option. */ + while (1) +@@ -1987,10 +2049,10 @@ + addr = skip_to (0, file); + + /* Get the installation address. */ +- if (! safe_parse_maxint (&addr, &installaddr)) ++ if (! safe_parse_maxint (&addr, installaddr)) + { + /* ADDR is not specified. */ +- installaddr = 0; ++ *installaddr = 0; + ptr = addr; + errnum = 0; + } +@@ -2084,17 +2146,17 @@ + = (dest_drive & BIOS_FLAG_FIXED_DISK); + + /* Read the first sector of Stage 2. */ +- disk_read_hook = disk_read_savesect_func; +- if (grub_read (stage2_first_buffer, SECTOR_SIZE) != SECTOR_SIZE) ++ disk_read_hook = install_savesect_helper; ++ if (grub_read (*stage2_first_buffer, SECTOR_SIZE) != SECTOR_SIZE) + goto fail; + +- stage2_first_sector = saved_sector; ++ stage2_first_sector = *saved_sector; + + /* Read the second sector of Stage 2. */ + if (grub_read (stage2_second_buffer, SECTOR_SIZE) != SECTOR_SIZE) + goto fail; + +- stage2_second_sector = saved_sector; ++ stage2_second_sector = *saved_sector; + + /* Check for the version of Stage 2. */ + if (*((short *) (stage2_second_buffer + STAGE2_VER_MAJ_OFFS)) +@@ -2110,27 +2172,27 @@ + + /* If INSTALLADDR is not specified explicitly in the command-line, + determine it by the Stage 2 id. */ +- if (! installaddr) ++ if (! *installaddr) + { + if (! is_stage1_5) + /* Stage 2. */ +- installaddr = 0x8000; ++ *installaddr = 0x8000; + else + /* Stage 1.5. */ +- installaddr = 0x2000; ++ *installaddr = 0x2000; + } + + *((unsigned long *) (stage1_buffer + STAGE1_STAGE2_SECTOR)) + = stage2_first_sector; + *((unsigned short *) (stage1_buffer + STAGE1_STAGE2_ADDRESS)) +- = installaddr; ++ = *installaddr; + *((unsigned short *) (stage1_buffer + STAGE1_STAGE2_SEGMENT)) +- = installaddr >> 4; ++ = *installaddr >> 4; + +- i = (int) stage2_first_buffer + SECTOR_SIZE - 4; ++ i = (int) *stage2_first_buffer + SECTOR_SIZE - 4; + while (*((unsigned long *) i)) + { +- if (i < (int) stage2_first_buffer ++ if (i < (int) *stage2_first_buffer + || (*((int *) (i - 4)) & 0x80000000) + || *((unsigned short *) i) >= 0xA00 + || *((short *) (i + 2)) == 0) +@@ -2144,13 +2206,13 @@ + i -= 8; + } + +- installlist = (int) stage2_first_buffer + SECTOR_SIZE + 4; +- installaddr += SECTOR_SIZE; ++ *installlist = (int) *stage2_first_buffer + SECTOR_SIZE + 4; ++ *installaddr += SECTOR_SIZE; + + /* Read the whole of Stage2 except for the first sector. */ + grub_seek (SECTOR_SIZE); + +- disk_read_hook = disk_read_blocklist_func; ++ disk_read_hook = install_blocklist_helper; + if (! grub_read (dummy, -1)) + goto fail; + +@@ -2233,7 +2295,7 @@ + /* Skip the first sector. */ + grub_seek (SECTOR_SIZE); + +- disk_read_hook = disk_read_savesect_func; ++ disk_read_hook = install_savesect_helper; + if (grub_read (stage2_buffer, SECTOR_SIZE) != SECTOR_SIZE) + goto fail; + +@@ -2303,7 +2365,7 @@ + else + #endif /* GRUB_UTIL */ + { +- if (! devwrite (saved_sector - part_start, 1, stage2_buffer)) ++ if (! devwrite (*saved_sector - part_start, 1, stage2_buffer)) + goto fail; + } + } +@@ -2325,7 +2387,7 @@ + goto fail; + } + +- if (fwrite (stage2_first_buffer, 1, SECTOR_SIZE, fp) != SECTOR_SIZE) ++ if (fwrite (*stage2_first_buffer, 1, SECTOR_SIZE, fp) != SECTOR_SIZE) + { + fclose (fp); + errnum = ERR_WRITE; +@@ -2352,7 +2414,7 @@ + goto fail; + + if (! devwrite (stage2_first_sector - src_part_start, 1, +- stage2_first_buffer)) ++ *stage2_first_buffer)) + goto fail; + + if (! devwrite (stage2_second_sector - src_part_start, 1, +--- grub-0.97/stage2/shared.h ++++ grub-0.97/stage2/shared.h +@@ -36,8 +36,8 @@ + + /* Maybe redirect memory requests through grub_scratch_mem. */ + #ifdef GRUB_UTIL +-extern char *grub_scratch_mem; +-# define RAW_ADDR(x) ((x) + (int) grub_scratch_mem) ++extern void *grub_scratch_mem; ++# define RAW_ADDR(x) ((x) + (unsigned long) grub_scratch_mem) + # define RAW_SEG(x) (RAW_ADDR ((x) << 4) >> 4) + #else + # define RAW_ADDR(x) (x) diff --git a/src/patches/grub-0.97/grub-0.97-configfile.patch b/src/patches/grub-0.97/grub-0.97-configfile.patch new file mode 100644 index 0000000000..4a0c32e501 --- /dev/null +++ b/src/patches/grub-0.97/grub-0.97-configfile.patch @@ -0,0 +1,80 @@ +diff -ru grub-0.97-old/docs/grub.8 grub-0.97/docs/grub.8 +--- grub-0.97-old/docs/grub.8 2005-05-08 02:48:56.000000000 +0000 ++++ grub-0.97/docs/grub.8 2006-08-05 13:17:07.868362408 +0000 +@@ -15,7 +15,7 @@ + specify stage2 boot_drive [default=0x0] + .TP + \fB\-\-config\-file\fR=\fIFILE\fR +-specify stage2 config_file [default=/boot/grub/menu.lst] ++specify stage2 config_file [default=/boot/grub/grub.conf] + .TP + \fB\-\-device\-map\fR=\fIFILE\fR + use the device map file FILE +diff -ru grub-0.97-old/docs/grub.texi grub-0.97/docs/grub.texi +--- grub-0.97-old/docs/grub.texi 2005-05-08 02:59:59.000000000 +0000 ++++ grub-0.97/docs/grub.texi 2006-08-05 13:17:07.875361344 +0000 +@@ -1265,7 +1265,7 @@ + keys) that will do everything to boot an OS. + + To enable the menu, you need a configuration file, +-@file{menu.lst} under the boot directory. We'll analyze an example ++@file{grub.conf} under the boot directory. We'll analyze an example + file. + + The file first contains some general settings, the menu interface +@@ -1882,8 +1882,8 @@ + + An absolute file name resembles a Unix absolute file name, using + @samp{/} for the directory separator (not @samp{\} as in DOS). One +-example is @samp{(hd0,0)/boot/grub/menu.lst}. This means the file +-@file{/boot/grub/menu.lst} in the first partition of the first hard ++example is @samp{(hd0,0)/boot/grub/grub.conf}. This means the file ++@file{/boot/grub/grub.conf} in the first partition of the first hard + disk. If you omit the device name in an absolute file name, GRUB uses + GRUB's @dfn{root device} implicitly. So if you set the root device to, + say, @samp{(hd1,0)} by the command @command{root} (@pxref{root}), then +@@ -3542,7 +3542,7 @@ + + @item --config-file=@var{file} + Read the configuration file @var{file} instead of +-@file{/boot/grub/menu.lst}. The format is the same as the normal GRUB ++@file{/boot/grub/grub.conf}. The format is the same as the normal GRUB + syntax. See @ref{Filesystem}, for more information. + + @item --boot-drive=@var{drive} +diff -ru grub-0.97-old/grub/asmstub.c grub-0.97/grub/asmstub.c +--- grub-0.97-old/grub/asmstub.c 2005-02-16 20:45:14.000000000 +0000 ++++ grub-0.97/grub/asmstub.c 2006-08-05 13:17:07.866362712 +0000 +@@ -71,7 +71,7 @@ + unsigned long boot_drive = 0; + int saved_entryno = 0; + char version_string[] = VERSION; +-char config_file[128] = "/boot/grub/menu.lst"; /* FIXME: arbitrary */ ++char config_file[128] = "/boot/grub/grub.conf"; /* FIXME: arbitrary */ + unsigned long linux_text_len = 0; + char *linux_data_tmp_addr = 0; + char *linux_data_real_addr = 0; +diff -ru grub-0.97-old/stage2/asm.S grub-0.97/stage2/asm.S +--- grub-0.97-old/stage2/asm.S 2004-06-19 16:55:22.000000000 +0000 ++++ grub-0.97/stage2/asm.S 2006-08-05 13:17:07.859363776 +0000 +@@ -98,7 +98,7 @@ + .string VERSION + VARIABLE(config_file) + #ifndef STAGE1_5 +- .string "/boot/grub/menu.lst" ++ .string "/boot/grub/grub.conf" + #else /* STAGE1_5 */ + .long 0xffffffff + .string "/boot/grub/stage2" +diff -ru grub-0.97-old/stage2/builtins.c grub-0.97/stage2/builtins.c +--- grub-0.97-old/stage2/builtins.c 2005-02-15 21:58:23.000000000 +0000 ++++ grub-0.97/stage2/builtins.c 2006-08-05 13:17:07.864363016 +0000 +@@ -3973,7 +3973,7 @@ + + /* The prefix was determined. */ + grub_sprintf (stage2, "%s%s", prefix, "/stage2"); +- grub_sprintf (config_filename, "%s%s", prefix, "/menu.lst"); ++ grub_sprintf (config_filename, "%s%s", prefix, "/grub.conf"); + *real_config_filename = 0; + + /* Check if stage2 exists. */ diff --git a/src/patches/grub-0.97/grub-0.97-dirs.patch b/src/patches/grub-0.97/grub-0.97-dirs.patch new file mode 100644 index 0000000000..79b532e3ee --- /dev/null +++ b/src/patches/grub-0.97/grub-0.97-dirs.patch @@ -0,0 +1,78 @@ +diff -Nur grub-0.97-splash/docs/grub.texi grub-0.97-dirs/docs/grub.texi +--- grub-0.97-splash/docs/grub.texi 2005-08-21 20:29:22.000000000 +0300 ++++ grub-0.97-dirs/docs/grub.texi 2005-08-21 20:31:12.000000000 +0300 +@@ -479,13 +479,13 @@ + if, by any chance, your hard drive becomes unusable (unbootable). + + GRUB comes with boot images, which are normally put in the directory +-@file{/usr/lib/grub/i386-pc}. If you do not use grub-install, then ++@file{/usr/share/grub/i386-pc}. If you do not use grub-install, then + you need to copy the files @file{stage1}, @file{stage2}, and + @file{*stage1_5} to the directory @file{/boot/grub}, and run the + @command{grub-set-default} (@pxref{Invoking grub-set-default}) if you + intend to use @samp{default saved} (@pxref{default}) in your + configuration file. Hereafter, the directory where GRUB images are +-initially placed (normally @file{/usr/lib/grub/i386-pc}) will be ++initially placed (normally @file{/usr/share/grub/i386-pc}) will be + called the @dfn{image directory}, and the directory where the boot + loader needs to find them (usually @file{/boot/grub}) will be called + the @dfn{boot directory}. +@@ -513,7 +513,7 @@ + + @example + @group +-# @kbd{cd /usr/lib/grub/i386-pc} ++# @kbd{cd /usr/share/grub/i386-pc} + # @kbd{dd if=stage1 of=/dev/fd0 bs=512 count=1} + 1+0 records in + 1+0 records out +@@ -707,7 +707,7 @@ + Copy the file @file{stage2_eltorito}: + + @example +-$ @kbd{cp /usr/lib/grub/i386-pc/stage2_eltorito iso/boot/grub} ++$ @kbd{cp /usr/share/grub/i386-pc/stage2_eltorito iso/boot/grub} + @end example + + If desired, make the config file @file{menu.lst} under @file{iso/boot/grub} +diff -Nur grub-0.97-splash/Makefile.am grub-0.97-dirs/Makefile.am +--- grub-0.97-splash/Makefile.am 2005-08-21 20:29:14.000000000 +0300 ++++ grub-0.97-dirs/Makefile.am 2005-08-21 20:31:12.000000000 +0300 +@@ -2,3 +2,4 @@ + AUTOMAKE_OPTIONS = 1.7 gnu + SUBDIRS = netboot stage2 stage1 lib grub util docs + EXTRA_DIST = BUGS MAINTENANCE ++pkgdatadir=$(datadir) +diff -Nur grub-0.97-splash/stage1/Makefile.am grub-0.97-dirs/stage1/Makefile.am +--- grub-0.97-splash/stage1/Makefile.am 2005-08-21 20:29:14.000000000 +0300 ++++ grub-0.97-dirs/stage1/Makefile.am 2005-08-21 20:31:12.000000000 +0300 +@@ -1,4 +1,4 @@ +-pkglibdir = $(libdir)/$(PACKAGE)/$(host_cpu)-$(host_vendor) ++pkglibdir = /usr/share/grub/i386-pc + nodist_pkglib_DATA = stage1 + + CLEANFILES = $(nodist_pkglib_DATA) +diff -Nur grub-0.97-splash/stage2/Makefile.am grub-0.97-dirs/stage2/Makefile.am +--- grub-0.97-splash/stage2/Makefile.am 2005-08-21 20:29:14.000000000 +0300 ++++ grub-0.97-dirs/stage2/Makefile.am 2005-08-21 20:31:12.000000000 +0300 +@@ -27,7 +27,7 @@ + -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/share/grub/i386-pc + + EXTRA_PROGRAMS = nbloader.exec pxeloader.exec diskless.exec + +diff -Nur grub-0.97-splash/util/grub-install.in grub-0.97-dirs/util/grub-install.in +--- grub-0.97-splash/util/grub-install.in 2005-08-21 20:29:14.000000000 +0300 ++++ grub-0.97-dirs/util/grub-install.in 2005-08-21 20:31:12.000000000 +0300 +@@ -27,7 +27,7 @@ + host_cpu=@host_cpu@ + host_os=@host_os@ + host_vendor=@host_vendor@ +-pkglibdir=${libdir}/${PACKAGE}/${host_cpu}-${host_vendor} ++pkglibdir=/usr/share/grub/i386-pc + + grub_shell=${sbindir}/grub + grub_set_default=${sbindir}/grub-set-default diff --git a/src/patches/grub-0.97/grub-0.97-misc.patch b/src/patches/grub-0.97/grub-0.97-misc.patch new file mode 100644 index 0000000000..9fa07af3e7 --- /dev/null +++ b/src/patches/grub-0.97/grub-0.97-misc.patch @@ -0,0 +1,94 @@ +diff -Nur grub-0.97-ori/lib/device.c grub-0.97-misc/lib/device.c +--- grub-0.97-ori/lib/device.c 2005-03-28 02:14:25.000000000 +0300 ++++ grub-0.97-misc/lib/device.c 2005-08-21 20:22:30.000000000 +0300 +@@ -831,9 +831,11 @@ + 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); + } +diff -Nur grub-0.97-ori/stage2/boot.c grub-0.97-misc/stage2/boot.c +--- grub-0.97-ori/stage2/boot.c 2004-03-30 14:44:08.000000000 +0300 ++++ grub-0.97-misc/stage2/boot.c 2005-08-21 20:22:30.000000000 +0300 +@@ -824,8 +824,11 @@ + 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 -Nur grub-0.97-ori/stage2/builtins.c grub-0.97-misc/stage2/builtins.c +--- grub-0.97-ori/stage2/builtins.c 2005-02-15 23:58:23.000000000 +0200 ++++ grub-0.97-misc/stage2/builtins.c 2005-08-21 20:22:30.000000000 +0300 +@@ -1842,9 +1842,23 @@ + #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 +diff -Nur grub-0.97-ori/stage2/filesys.h grub-0.97-misc/stage2/filesys.h +--- grub-0.97-ori/stage2/filesys.h 2004-05-14 22:36:43.000000000 +0300 ++++ grub-0.97-misc/stage2/filesys.h 2005-08-21 20:22:30.000000000 +0300 +@@ -73,6 +73,16 @@ + int reiserfs_read (char *buf, int len); + int reiserfs_dir (char *dirname); + 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 +diff -Nur grub-0.97-ori/util/mbchk.c grub-0.97-misc/util/mbchk.c +--- grub-0.97-ori/util/mbchk.c 2003-10-19 18:36:45.000000000 +0300 ++++ grub-0.97-misc/util/mbchk.c 2005-08-21 20:22:30.000000000 +0300 +@@ -59,7 +59,9 @@ + int i; + char buf[8192]; + +- if (fread (buf, 1, 8192, fp) < 0) ++ fread (buf, 1, 8192, fp); ++ ++ if (ferror(fp)) + { + fprintf (stderr, "%s: Read error.\n", filename); + return 0; diff --git a/src/patches/grub-0.97/grub-0.97-splash.patch b/src/patches/grub-0.97/grub-0.97-splash.patch new file mode 100644 index 0000000000..e7066e097d --- /dev/null +++ b/src/patches/grub-0.97/grub-0.97-splash.patch @@ -0,0 +1,943 @@ +diff -Nur grub-0.97-misc/docs/grub.texi grub-0.97-splash/docs/grub.texi +--- grub-0.97-misc/docs/grub.texi 2005-08-21 20:22:18.000000000 +0300 ++++ grub-0.97-splash/docs/grub.texi 2005-08-21 20:29:22.000000000 +0300 +@@ -2118,6 +2118,7 @@ + * 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 + @end menu +@@ -2150,6 +2151,15 @@ + @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 + +diff -Nur grub-0.97-misc/grub/asmstub.c grub-0.97-splash/grub/asmstub.c +--- grub-0.97-misc/grub/asmstub.c 2005-08-21 20:22:18.000000000 +0300 ++++ grub-0.97-splash/grub/asmstub.c 2005-08-21 20:29:22.000000000 +0300 +@@ -480,6 +480,32 @@ + 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 -Nur grub-0.97-misc/stage2/asm.S grub-0.97-splash/stage2/asm.S +--- grub-0.97-misc/stage2/asm.S 2005-08-21 20:22:18.000000000 +0300 ++++ grub-0.97-splash/stage2/asm.S 2005-08-21 20:29:22.000000000 +0300 +@@ -1610,6 +1610,301 @@ + 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 ++ andl $0xf,%edi ++ shrl $4,%edx ++ ++ pushl %ebp ++ ++ call EXT_C(prot_to_real) ++ .code16 ++ ++ pushw %ds ++ ++ movw %dx,%ds ++ leal gfx_ofs_sys_cfg(%di),%esi ++ movl gfx_ofs_mem_file(%di),%eax ++ movl gfx_ofs_mem_cur(%di),%ebx ++ movl gfx_ofs_mem_max(%di),%ecx ++ movw %ds,%dx ++ ++ /* basically just a lcall, but we need %edi */ ++ pushw %cs ++ pushw $gfx_init_50 ++ pushl gfx_ofs_jmp_table + 4 * 0 (%di) ++ ++ movl gfx_ofs_mem_align(%di),%edi ++ ++ lret ++ ++gfx_init_50: ++ movl $0,%ebx ++ adcl $0,%ebx ++ ++ popw %ds ++ ++ DATA32 call EXT_C(real_to_prot) ++ .code32 ++ ++ popl %ebp ++ ++ movl %ebx,%eax ++ negl %ebx ++ incl %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 ++ andl $0xf,%ebx ++ shrl $4,%edx ++ ++ pushl %ebp ++ ++ call EXT_C(prot_to_real) ++ .code16 ++ ++ pushw %ds ++ ++ movw %dx,%ds ++ shll $4,%edx ++ movl gfx_ofs_cmdline(%bx),%edi ++ subl %edx,%edi ++ movw gfx_ofs_cmdline_len(%bx),%cx ++ movw gfx_ofs_timeout(%bx),%ax ++ imulw $18,%ax ++ ++ pushl %ebp ++ lcall *gfx_ofs_jmp_table + 4 * 2 (%bx) ++ popl %ebp ++ 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 %sp,%bp ++ ++ 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) ++ ++ movw %bp,%si ++ pushw %ss ++ popw %es ++ ++ 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) +diff -Nur grub-0.97-misc/stage2/builtins.c grub-0.97-splash/stage2/builtins.c +--- grub-0.97-misc/stage2/builtins.c 2005-08-21 20:22:30.000000000 +0300 ++++ grub-0.97-splash/stage2/builtins.c 2005-08-21 20:29:22.000000000 +0300 +@@ -63,6 +63,8 @@ + 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. */ +@@ -1331,6 +1333,26 @@ + }; + + ++/* 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) +@@ -4837,6 +4859,7 @@ + &builtin_find, + &builtin_fstest, + &builtin_geometry, ++ &builtin_gfxmenu, + &builtin_halt, + &builtin_help, + &builtin_hiddenmenu, +diff -Nur grub-0.97-misc/stage2/shared.h grub-0.97-splash/stage2/shared.h +--- grub-0.97-misc/stage2/shared.h 2005-08-21 20:22:18.000000000 +0300 ++++ grub-0.97-splash/stage2/shared.h 2005-08-21 20:29:22.000000000 +0300 +@@ -374,6 +374,27 @@ + #endif /* WITHOUT_LIBC_STUBS */ + + ++/* see typedef gfx_data_t below */ ++#define gfx_ofs_ok 0x00 ++#define gfx_ofs_mem_start 0x04 ++#define gfx_ofs_mem_cur 0x08 ++#define gfx_ofs_mem_max 0x0c ++#define gfx_ofs_code_seg 0x10 ++#define gfx_ofs_jmp_table 0x14 ++#define gfx_ofs_sys_cfg 0x44 ++#define gfx_ofs_cmdline 0x64 ++#define gfx_ofs_cmdline_len 0x68 ++#define gfx_ofs_menu_list 0x6c ++#define gfx_ofs_menu_default_entry 0x70 ++#define gfx_ofs_menu_entries 0x74 ++#define gfx_ofs_menu_entry_len 0x78 ++#define gfx_ofs_args_list 0x7c ++#define gfx_ofs_args_entry_len 0x80 ++#define gfx_ofs_timeout 0x84 ++#define gfx_ofs_mem_file 0x88 ++#define gfx_ofs_mem_align 0x8c ++ ++ + #ifndef ASM_FILE + /* + * Below this should be ONLY defines and other constructs for C code. +@@ -595,6 +616,41 @@ + 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 mem_start, mem_cur, mem_max; ++ unsigned code_seg; /* code segment of binary graphics code */ ++ unsigned jmp_table[12]; /* link to graphics functions */ ++ unsigned char sys_cfg[32]; /* 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) */ ++ unsigned mem_file; /* aligned gfx file start */ ++ unsigned mem_align; /* aligned cpio file start */ ++} __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 + { +diff -Nur grub-0.97-misc/stage2/stage2.c grub-0.97-splash/stage2/stage2.c +--- grub-0.97-misc/stage2/stage2.c 2005-08-21 20:22:18.000000000 +0300 ++++ grub-0.97-splash/stage2/stage2.c 2005-08-21 20:29:22.000000000 +0300 +@@ -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) +@@ -310,6 +312,12 @@ + + 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."); +@@ -753,6 +761,413 @@ + } + + ++ ++#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 ++ ++/* ++ * Go through config entry and find kernel args, if any. ++ */ ++static char *get_kernel_args(char *cfg) ++{ ++ int j; ++ char *s, *t = ""; ++ ++ for(j = 0; ; j++) { ++ s = get_entry(cfg, j, 0); ++ if(!*s) break; ++ if(!memcmp(s, "kernel", 6) && (s[6] == ' ' || s[6] == '\t')) { ++ t = skip_to(0, s); ++ if(*t) t = skip_to(0, t); ++ break; ++ } ++ } ++ ++ return t; ++} ++ ++ ++/* ++ * Check header and return code start offset. ++ */ ++static unsigned magic_ok(unsigned char *buf) ++{ ++ if( ++ *(unsigned *) buf == 0x0b2d97f00 && /* magic id */ ++ (buf[4] == 5 || buf[4] == 6) /* version 5 or 6 */ ++ ) { ++ 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 i, fname_len, flen, 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); ++ flen = *(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 += flen; ++ i = ((i + 1) & ~1); ++ } ++ else { ++ break; ++ } ++ } ++ ++ return code_start; ++} ++ ++ ++/* ++ * Leave that much space on the heap. Everything else goes to the graphics ++ * functions. ++ * ++ * 0x2000 is _not_ enough ++ */ ++#define MIN_HEAP_SIZE 0x4000 ++ ++/* gfx code needs at least this much free memory */ ++#define MIN_GFX_FREE 0xc000 ++ ++/* ++ * 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; ++ unsigned u, buf_size, code_start, file_start; ++ char *s, *t, *cfg, *new_config; ++ char *saved_heap; ++ int i, j, max_len; ++ int selected_entry; ++ gfx_data_t *gfx_data; ++ ++ /* ++ * 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(mem_start); ++ gfx_ofs_check(mem_cur); ++ gfx_ofs_check(mem_max); ++ 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); ++ gfx_ofs_check(mem_file); ++ gfx_ofs_check(mem_align); ++ #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[0] = 2; /* bootloader: grub */ ++ 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); ++ ++ ++ /* 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)); ++ 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))); ++ } ++ ++ ++ /* go back here when we no longer need the graphics data */ ++ saved_heap = heap; ++ ++ ++ /* get memory area to be used by graphics functions */ ++ ++ buf = (unsigned char *) (((unsigned) heap + 0xf) & ~0xf); ++ ++ buf_size = (unsigned char *) &buf - buf - MIN_HEAP_SIZE; ++ buf_size &= ~0xf; ++ ++ /* too small */ ++ if(buf_size < 0x10000) return; ++ ++ gfx_data->mem_start = (unsigned) buf; ++ gfx_data->mem_max = gfx_data->mem_start + buf_size; ++ ++#if 0 ++ printf("graphics menu\n"); ++ printf( ++ "heap = 0x%x, buf = 0x%x (0x%x bytes), graphics_file = %s\n", ++ heap, gfx_data->mem_start, buf_size, graphics_file ++ ); ++ getkey(); ++#endif ++ ++ heap += buf_size; ++ ++ ++ /* read the file */ ++ ++ if(!grub_open(graphics_file)) { ++ printf("graphics file \"%s\" missing, press a key to continue...\n", graphics_file); ++ getkey(); ++ return; ++ } ++ ++ i = grub_read(buf, buf_size); ++ ++ grub_close(); ++ ++ if(i <= 0) { ++ printf("error reading \"%s\", press a key to continue...\n", graphics_file); ++ getkey(); ++ return; ++ } ++ ++ /* besides the file, we need some working memory, too */ ++ if(i + MIN_GFX_FREE + 0x0f >= (int) buf_size) { ++ printf("file \"%s\" too large, press a key to continue...\n", graphics_file); ++ getkey(); ++ return; ++ } ++ ++ gfx_data->mem_cur = gfx_data->mem_start + ((i + 0x0f + 3) & ~3); /* align it */ ++ ++#if 0 ++ printf("image: %d bytes (%d bytes left)\n", i, gfx_data->mem_max - gfx_data->mem_cur); ++ getkey(); ++#endif ++ ++ ++ /* locate file inside cpio archive */ ++ if(!(code_start = find_file(buf, i, &file_start))) { ++ printf("\"%s\" has wrong format, press a key to continue...\n", graphics_file); ++ getkey(); ++ return; ++ } ++ ++ ++ /* align it */ ++ u = (-(code_start + gfx_data->mem_start + file_start)) & 0x0f; ++ gfx_data->mem_align = gfx_data->mem_start + u; ++ gfx_data->mem_file = gfx_data->mem_align + file_start; ++ if(u) { ++ memcpy((void *) gfx_data->mem_align, (void *) gfx_data->mem_start, i); ++ } ++ ++ /* init interface to graphics functions */ ++ ++ code_start += gfx_data->mem_file; ++ ++#if 0 ++ printf("code_start: 0x%x, file_start: 0x%x, mem_align = 0x%x, mem_file = 0x%x\n", ++ code_start, file_start, gfx_data->mem_align, gfx_data->mem_file ++ ); ++ getkey(); ++#endif ++ ++ gfx_data->code_seg = code_start >> 4; ++ ++#if 0 ++ printf("code start = 0x%x, code_seg = 0x%x\n", code_start, gfx_data->code_seg); ++#endif ++ ++ 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 *) code_start)[i]; ++ } ++ ++#if 0 ++ 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("def: >%s<\n", gfx_data->menu_default_entry); ++#endif ++ ++ ++ /* switch to graphics mode */ ++ ++ if(gfx_init(gfx_data)) { ++#if 0 ++ printf("gfx_init failed\n"); ++ getkey(); ++#endif ++ 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; ++ ++ 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; ++ ++ ++ /* create new config with modified kernel option */ ++ ++ cfg = get_entry(config_entries, selected_entry, 1); ++ ++ new_config = heap; ++ ++ for(i = 0; ; i++) { ++ s = get_entry(cfg, i, 0); ++ if(!*s) { ++ if(!i) *heap++ = 0; ++ *heap++ = 0; ++ break; ++ } ++ if(!memcmp(s, "kernel", 6) && (s[6] == ' ' || s[6] == '\t')) { ++ t = skip_to(0, s); ++ if(*t) t = skip_to(0, t); ++ memmove(heap, s, t - s); ++ heap += t - s; ++ *heap++ = ' '; ++ strcpy(heap, gfx_data->cmdline); ++ heap += strlen(gfx_data->cmdline) + 1; ++ } ++ 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) + { +@@ -1059,9 +1474,12 @@ + } + 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/src/patches/grub-0.97/grub-0.97-symlinkmenulst.patch b/src/patches/grub-0.97/grub-0.97-symlinkmenulst.patch new file mode 100644 index 0000000000..39b3f02b22 --- /dev/null +++ b/src/patches/grub-0.97/grub-0.97-symlinkmenulst.patch @@ -0,0 +1,14 @@ +diff -ur grub-0.97/util/grub-install.in grub-0.97-old/util/grub-install.in +--- grub-0.97/util/grub-install.in 2006-08-05 16:46:33.505226176 +0200 ++++ grub-0.97-old/util/grub-install.in 2004-07-24 20:57:31.000000000 +0200 +@@ -447,6 +447,10 @@ + rm -f $img_file + rm -f $log_file + ++if ! test -e ${grubdir}/grub.conf ; then ++ test -e ${grubdir}/menu.lst && ln -s ./menu.lst ${grubdir}/grub.conf ++fi ++ + # Create a safe temporary file. + test -n "$mklog" && log_file=`$mklog` + diff --git a/src/patches/grub-0.97/grub-0.97-wildcards.patch b/src/patches/grub-0.97/grub-0.97-wildcards.patch new file mode 100644 index 0000000000..a0789021aa --- /dev/null +++ b/src/patches/grub-0.97/grub-0.97-wildcards.patch @@ -0,0 +1,1188 @@ +diff -Nur grub-0.97-dirs/docs/grub.texi grub-0.97-wildcards/docs/grub.texi +--- grub-0.97-dirs/docs/grub.texi 2005-08-21 20:31:12.000000000 +0300 ++++ grub-0.97-wildcards/docs/grub.texi 2005-08-21 20:32:45.000000000 +0300 +@@ -2121,6 +2121,7 @@ + * gfxmenu:: Use graphical menu interface + * timeout:: Set the timeout + * title:: Start a menu entry ++* wildcard:: Define a wildcard boot entry + @end menu + + +@@ -2190,6 +2191,42 @@ + @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 + +diff -Nur grub-0.97-dirs/netboot/fsys_tftp.c grub-0.97-wildcards/netboot/fsys_tftp.c +--- grub-0.97-dirs/netboot/fsys_tftp.c 2005-08-21 20:31:02.000000000 +0300 ++++ grub-0.97-wildcards/netboot/fsys_tftp.c 2005-08-21 20:32:45.000000000 +0300 +@@ -409,7 +409,7 @@ + /* 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 @@ + #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 -Nur grub-0.97-dirs/stage2/builtins.c grub-0.97-wildcards/stage2/builtins.c +--- grub-0.97-dirs/stage2/builtins.c 2005-08-21 20:31:02.000000000 +0300 ++++ grub-0.97-wildcards/stage2/builtins.c 2005-08-21 20:32:45.000000000 +0300 +@@ -4828,6 +4828,49 @@ + }; + + ++/* 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[] = + { +@@ -4917,5 +4960,6 @@ + &builtin_unhide, + &builtin_uppermem, + &builtin_vbeprobe, ++ &builtin_wildcard, + 0 + }; +diff -Nur grub-0.97-dirs/stage2/disk_io.c grub-0.97-wildcards/stage2/disk_io.c +--- grub-0.97-dirs/stage2/disk_io.c 2005-08-21 20:31:02.000000000 +0300 ++++ grub-0.97-wildcards/stage2/disk_io.c 2005-08-21 20:32:45.000000000 +0300 +@@ -36,7 +36,6 @@ + void (*disk_read_func) (int, int, int) = NULL; + + #ifndef STAGE1_5 +-int print_possibilities; + + static int do_completion; + static int unique; +@@ -1479,7 +1478,7 @@ + if (! is_completion) + grub_printf (" Possible files are:"); + +- dir (buf); ++ dir (buf, print_a_completion); + + if (is_completion && *unique_string) + { +@@ -1498,7 +1497,7 @@ + *ptr = '/'; + *(ptr + 1) = 0; + +- dir (buf); ++ dir (buf, print_a_completion); + + /* Restore the original unique value. */ + unique = 1; +@@ -1626,12 +1625,7 @@ + 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 @@ + } + + int +-dir (char *dirname) ++dir (char *dirname, void (*handle)(char *)) + { + #ifndef NO_DECOMPRESSION + compressed_file = 0; +@@ -1761,19 +1755,18 @@ + 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 -Nur grub-0.97-dirs/stage2/filesys.h grub-0.97-wildcards/stage2/filesys.h +--- grub-0.97-dirs/stage2/filesys.h 2005-08-21 20:31:02.000000000 +0300 ++++ grub-0.97-wildcards/stage2/filesys.h 2005-08-21 20:32:45.000000000 +0300 +@@ -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 @@ + #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 @@ + #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 @@ + #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 @@ + #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,7 +71,7 @@ + #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 +@@ -91,7 +91,7 @@ + #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 +@@ -100,7 +100,7 @@ + #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 +@@ -110,7 +110,7 @@ + #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 +@@ -119,7 +119,7 @@ + #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 +@@ -129,7 +129,7 @@ + #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 +@@ -160,16 +160,10 @@ + 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 -Nur grub-0.97-dirs/stage2/fsys_ext2fs.c grub-0.97-wildcards/stage2/fsys_ext2fs.c +--- grub-0.97-dirs/stage2/fsys_ext2fs.c 2005-08-21 20:31:02.000000000 +0300 ++++ grub-0.97-wildcards/stage2/fsys_ext2fs.c 2005-08-21 20:32:45.000000000 +0300 +@@ -495,7 +495,7 @@ + * 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 +521,6 @@ + #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 +@@ -713,18 +712,9 @@ + 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 +755,15 @@ + 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 -Nur grub-0.97-dirs/stage2/fsys_fat.c grub-0.97-wildcards/stage2/fsys_fat.c +--- grub-0.97-dirs/stage2/fsys_fat.c 2005-08-21 20:31:02.000000000 +0300 ++++ grub-0.97-wildcards/stage2/fsys_fat.c 2005-08-21 20:32:45.000000000 +0300 +@@ -289,7 +289,7 @@ + } + + 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 @@ + *rest = 0; + + # ifndef STAGE1_5 +- if (print_possibilities && ch != '/') ++ if (handle && ch != '/') + do_possibilities = 1; + # endif + +@@ -356,16 +356,6 @@ + { + 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 @@ + { + 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 -Nur grub-0.97-dirs/stage2/fsys_ffs.c grub-0.97-wildcards/stage2/fsys_ffs.c +--- grub-0.97-dirs/stage2/fsys_ffs.c 2005-08-21 20:31:02.000000000 +0300 ++++ grub-0.97-wildcards/stage2/fsys_ffs.c 2005-08-21 20:32:45.000000000 +0300 +@@ -180,7 +180,7 @@ + + + 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 @@ + { + 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 @@ + 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 -Nur grub-0.97-dirs/stage2/fsys_iso9660.c grub-0.97-wildcards/stage2/fsys_iso9660.c +--- grub-0.97-dirs/stage2/fsys_iso9660.c 2005-08-21 20:31:02.000000000 +0300 ++++ grub-0.97-wildcards/stage2/fsys_iso9660.c 2005-08-21 20:32:45.000000000 +0300 +@@ -133,7 +133,7 @@ + } + + 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 @@ + 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 @@ + 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 @@ + size -= ISO_SECTOR_SIZE; + } /* size>0 */ + +- if (dirname[pathlen] == '/' || print_possibilities >= 0) ++ if (dirname[pathlen] == '/' || handle) + { + errnum = ERR_FILE_NOT_FOUND; + return 0; +diff -Nur grub-0.97-dirs/stage2/fsys_jfs.c grub-0.97-wildcards/stage2/fsys_jfs.c +--- grub-0.97-dirs/stage2/fsys_jfs.c 2005-08-21 20:31:02.000000000 +0300 ++++ grub-0.97-wildcards/stage2/fsys_jfs.c 2005-08-21 20:32:45.000000000 +0300 +@@ -270,7 +270,7 @@ + } + + int +-jfs_dir (char *dirname) ++jfs_dir (char *dirname, void (*handle)(char *)) + { + char *ptr, *rest, ch; + ldtentry_t *de; +@@ -357,12 +357,9 @@ + + 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 @@ + } + de = next_dentry (); + if (de == NULL) { +- if (print_possibilities < 0) +- return 1; +- + errnum = ERR_FILE_NOT_FOUND; + *rest = ch; + return 0; +diff -Nur grub-0.97-dirs/stage2/fsys_minix.c grub-0.97-wildcards/stage2/fsys_minix.c +--- grub-0.97-dirs/stage2/fsys_minix.c 2005-08-21 20:31:02.000000000 +0300 ++++ grub-0.97-wildcards/stage2/fsys_minix.c 2005-08-21 20:32:45.000000000 +0300 +@@ -294,7 +294,7 @@ + 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 @@ + 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 @@ + 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 -Nur grub-0.97-dirs/stage2/fsys_reiserfs.c grub-0.97-wildcards/stage2/fsys_reiserfs.c +--- grub-0.97-dirs/stage2/fsys_reiserfs.c 2005-08-21 20:31:02.000000000 +0300 ++++ grub-0.97-wildcards/stage2/fsys_reiserfs.c 2005-08-21 20:32:45.000000000 +0300 +@@ -991,7 +991,7 @@ + * 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 @@ + *rest = 0; + + # ifndef STAGE1_5 +- if (print_possibilities && ch != '/') ++ if (handle && ch != '/') + do_possibilities = 1; + # endif /* ! STAGE1_5 */ + +@@ -1170,10 +1170,8 @@ + { + 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 @@ + num_entries--; + } + } +- +-# ifndef STAGE1_5 +- if (print_possibilities < 0) +- return 1; +-# endif /* ! STAGE1_5 */ +- + errnum = ERR_FILE_NOT_FOUND; + *rest = ch; + return 0; +diff -Nur grub-0.97-dirs/stage2/fsys_ufs2.c grub-0.97-wildcards/stage2/fsys_ufs2.c +--- grub-0.97-dirs/stage2/fsys_ufs2.c 2005-08-21 20:31:02.000000000 +0300 ++++ grub-0.97-wildcards/stage2/fsys_ufs2.c 2005-08-21 20:32:45.000000000 +0300 +@@ -204,7 +204,7 @@ + } + + 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 @@ + { + 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 @@ + 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 -Nur grub-0.97-dirs/stage2/fsys_vstafs.c grub-0.97-wildcards/stage2/fsys_vstafs.c +--- grub-0.97-dirs/stage2/fsys_vstafs.c 2005-08-21 20:31:02.000000000 +0300 ++++ grub-0.97-wildcards/stage2/fsys_vstafs.c 2005-08-21 20:32:45.000000000 +0300 +@@ -115,7 +115,7 @@ + } + + int +-vstafs_dir (char *dirname) ++vstafs_dir (char *dirname, void (*handle)(char *)) + { + char *fn, ch; + struct dir_entry *d; +@@ -146,14 +146,9 @@ + 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 @@ + *(dirname = fn) = ch; + if (! d) + { +- if (print_possibilities < 0) +- { +- putchar ('\n'); +- return 1; +- } +- + errnum = ERR_FILE_NOT_FOUND; + return 0; + } +diff -Nur grub-0.97-dirs/stage2/fsys_xfs.c grub-0.97-wildcards/stage2/fsys_xfs.c +--- grub-0.97-dirs/stage2/fsys_xfs.c 2005-08-21 20:31:02.000000000 +0300 ++++ grub-0.97-wildcards/stage2/fsys_xfs.c 2005-08-21 20:32:45.000000000 +0300 +@@ -534,7 +534,7 @@ + } + + 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 @@ + 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 @@ + } + name = next_dentry (&new_ino); + if (name == NULL) { +- if (print_possibilities < 0) +- return 1; +- + errnum = ERR_FILE_NOT_FOUND; + *rest = ch; + return 0; +diff -Nur grub-0.97-dirs/stage2/shared.h grub-0.97-wildcards/stage2/shared.h +--- grub-0.97-dirs/stage2/shared.h 2005-08-21 20:31:02.000000000 +0300 ++++ grub-0.97-wildcards/stage2/shared.h 2005-08-21 20:32:45.000000000 +0300 +@@ -1012,9 +1012,11 @@ + /* 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 -Nur grub-0.97-dirs/stage2/stage2.c grub-0.97-wildcards/stage2/stage2.c +--- grub-0.97-dirs/stage2/stage2.c 2005-08-21 20:31:02.000000000 +0300 ++++ grub-0.97-wildcards/stage2/stage2.c 2005-08-21 20:33:24.000000000 +0300 +@@ -1243,6 +1243,230 @@ + } + + ++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; ++} ++ ++static int inplace_sort_nextint(char **p); ++ ++static int inplace_sort_nextint(char **p) ++{ ++ int i = 0; ++ ++ while (**p && **p < '0' && **p > '9') *p++; ++ if (!**p) return -1; ++ while (**p && **p >= '0' && **p <= '9') ++ { ++ i = i * 10 + **p - '0'; ++ *p++; ++ } ++ return i; ++} ++ ++static int inplace_sort_strcmp(char *l, char *r); ++ ++static int ++inplace_sort_strcmp(char *l, char *r) ++{ ++ char *lp = l; ++ char *rp = r; ++ int li, ri; ++ ++ do ++ { ++ li = inplace_sort_nextint(&lp); ++ ri = inplace_sort_nextint(&rp); ++ if (li > ri) return 1; ++ if (ri > li) return -1; ++ } ++ while (li != -1 || ri != -1); ++ return 0; ++} ++ ++#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 (inplace_sort_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 + cmain (void) +@@ -1262,6 +1486,97 @@ + menu_entries = (char *) MENU_BUF; + 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); +@@ -1414,8 +1729,16 @@ + 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; +@@ -1456,11 +1779,6 @@ + else + default_entry = 0; + } +- +- if (is_preset) +- close_preset_menu (); +- else +- grub_close (); + } + while (is_preset); + } diff --git a/src/rc.d/rc.halt b/src/rc.d/rc.halt index 5661959acb..5a05d7f522 100644 --- a/src/rc.d/rc.halt +++ b/src/rc.d/rc.halt @@ -15,48 +15,48 @@ progressbar() fi } # Set bootsplash -progressbar 9 +progressbar 0 if [ -e /proc/splash ]; then echo "silent" > /proc/splash fi echo "Stopping the RED interface..." -progressbar 8 +progressbar 1 /etc/rc.d/rc.red stop 2>/dev/null /etc/rc.d/rc.red clear 2>/dev/null echo "Shutting down..." -progressbar 7 +progressbar 2 sleep 3 echo "Saving the clock" -progressbar 6 +progressbar 3 /sbin/hwclock --systohc echo "Sending all processes the TERM signal..." -progressbar 5 +progressbar 4 /sbin/killall5 -15 sleep 3 echo "Sending all processes the KILL signal..." -progressbar 4 +progressbar 5 /sbin/killall5 -9 sleep 3 echo "Turning off swap" -progressbar 3 +progressbar 6 swapoff -a echo "Unmounting others" -progressbar 2 +progressbar 7 umount -n -a echo "Unmounting root" -progressbar 1 +progressbar 8 mount -n -o remount,ro / # Send nice shutdown beep now -progressbar 0 +progressbar 9 /usr/bin/beep -l 75 -f 3000 /usr/bin/beep -l 75 -f 2000 /usr/bin/beep -l 75 -f 1000 -- 2.39.2