From 27996c53e756406da9bcf45c1ce7583c2412666c Mon Sep 17 00:00:00 2001 From: ms Date: Sat, 12 Aug 2006 15:16:04 +0000 Subject: [PATCH] =?UTF-8?q?Hinzugef=C3=BCgt:=20=20=20*=20GFXBoot=20-=20exp?= =?UTF-8?q?erimental?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 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 b3f0fb3cd..4915e41d6 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 ff9af0b3c..543f97655 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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 z 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 /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 000000000..3fffda6c0 --- /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 000000000..c69c0fa0e --- /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 000000000..6ad2c82ee --- /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 000000000..5beec6f81 --- /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 000000000..5cac692bb --- /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 000000000..ebfa82b80 --- /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 000000000..4a0c32e50 --- /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 000000000..79b532e3e --- /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 000000000..9fa07af3e --- /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 000000000..e7066e097 --- /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 000000000..39b3f02b2 --- /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 000000000..a0789021a --- /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 5661959ac..5a05d7f52 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