This patch adds a new command to grub - setdefault.
Its a close derivative of savedefault, the only difference is that it expects a
numeric argument, where original uses an implicit argument.
Its purpose is to support multi-kernel testing; a grub.conf can specify a sequence
of different kernels to run, which *presumably* would execute some substantial
set of tests, then reboot to the next kernel, which would repeat until the last
setdefault (ie: 0 in example below) returned the box to normal operation.
Heres a sequence of 4 kernels on my machine:
# Here are the sequential boot tests
title Test RH 7.2 (2.4.20-20.7) setdefault 5 root (hd0,1) kernel /vmlinuz-2.4.20-20.7 ro root=LABEL=/ initrd /initrd-2.4.20-20.7.img
title Test RH 7.2 (2.4.20-18.7) setdefault 6 root (hd0,1) kernel /vmlinuz-2.4.20-18.7 ro root=LABEL=/ initrd /initrd-2.4.20-18.7.img
title Test RedHat 9 (2.4.20-20.9) setdefault 7 root (hd0,0) kernel /boot/vmlinuz-2.4.20-20.9 ro root=LABEL=/1 initrd /boot/initrd-2.4.20-20.9.img
title Test RedHat 9 (2.4.20-8) setdefault 0 root (hd0,0) kernel /boot/vmlinuz-2.4.20-8 ro root=LABEL=/1 initrd /boot/initrd-2.4.20-8.img
I expect to combine this with a runlevel=4 or similar to make it easy to trigger
the *smoke-test* and reboot from rc.local.
The patch is against RH grub-0.93-7 srpm, which has 18 patches for 0.90-0.93
Its also somewhat unfinished;
1. I copy-pasted verbatim from savedefault_helper to setdefault_helper
The 'right' thing to do would be to rename savedefault_helper as setdefault_helper,
and modify savedefault to call it. IOW, savedefault is higher-level than setdefault,
and should be implemented on top. Doing this however felt a bit too brazen.
2. No (proper patch to the source of ) docs.
I couldnt quite make out from docs/Makefile.am which texi/info/etc file to edit into.
I added stuff into grub.texi.config.new, with hope that it could be easily cut-pasted
into wherever it belongs.
I also left some of the help-text in static struct builtin builtin_setdefault:
I am unsure whether any of the options should be allowed; I think --once would not make
any sense though. I did not strip the code for those options, so I thought it best to leave
an inappropriate marker.
Lastly - I found the FAQ and info on installation somewhat confusing -
Specifically, putting an ext2 on a floppy is apparently mutually exclusive with writing stage1, stage2
via dd. I'll try to explain better in a separate (appropriately titled) msg.
--- grub.texi.config.old Tue Nov 4 09:15:22 2003 +++ grub.texi.config.new Tue Nov 4 09:39:10 2003 @@ -1845,8 +1845,9 @@ used. You can specify @samp{saved} instead of a number. In this case, the -default entry is the entry saved with the command [EMAIL PROTECTED] @xref{savedefault}, for more information. +default entry is the entry saved with the commands [EMAIL PROTECTED] or @command{setdefault}. [EMAIL PROTECTED], @xref{setdefault}, for more information. @end deffn @@ -2404,6 +2405,7 @@ * root:: Set GRUB's root device * rootnoverify:: Set GRUB's root device without mounting * savedefault:: Save current entry as the default entry +* setdefault:: Save given value as the default entry * setup:: Set up GRUB's installation automatically * testload:: Load a file for testing a filesystem * testvbe:: Test VESA BIOS EXTENSION @@ -2890,6 +2892,46 @@ @end deffn [EMAIL PROTECTED] setdefault [EMAIL PROTECTED] setdefault + [EMAIL PROTECTED] Command setdefault +Set the given menu entry as a default entry. This command allows you +to set up a sequence of configurations which will boot different +kernels in sequence. This is intended to support unattended testing +of kernels, or of applications that should be portable across different +kernels. Here is an example: + [EMAIL PROTECTED] [EMAIL PROTECTED] +default saved +timeout 10 +# Assume 0..2 are normal boots. +# test boot sequence 3,4 + +# assume this is +title GNU/Linux TEST +root (hd0,0) +kernel /boot/vmlinuz root=/dev/sda1 vga=ext +initrd /boot/initrd +savedefault 4 + +title FreeBSD TEST +root (hd0,a) +kernel /boot/loader +setdefault 0 [EMAIL PROTECTED] group [EMAIL PROTECTED] example + +With this configuration, once you (the user) select the 4th entry, +GRUB will set the default to the 5th entry, then boot the 4th. When +the tests (which you configure separately) within the 4th entry +complete and reboot, the 5th entry is then booted; it too runs tests +and reboots, but before it does, it sets the default back to 0, +resuming normal operations. +See also @ref{default}. @end deffn + + @node setup @subsection setup
--- builtins.old.c Fri Oct 31 08:14:40 2003 +++ builtins.c Tue Nov 4 09:54:21 2003 @@ -3515,6 +3515,189 @@ }; + +#if !defined(SUPPORT_DISKLESS) && !defined(GRUB_UTIL) +/* Write specified default entry number into stage2 file. */ +static int +setdefault_helper(int new_default) +{ + char buffer[512]; + int *entryno_ptr; + + /* Get the geometry of the boot drive (i.e. the disk which contains + this stage2). */ + if (get_diskinfo (boot_drive, &buf_geom)) + { + errnum = ERR_NO_DISK; + return 1; + } + + /* Load the second sector of this stage2. */ + if (! rawread (boot_drive, install_second_sector, 0, SECTOR_SIZE, buffer)) + { + return 1; + } + + /* Sanity check. */ + if (buffer[STAGE2_STAGE2_ID] != STAGE2_ID_STAGE2 + || *((short *) (buffer + STAGE2_VER_MAJ_OFFS)) != COMPAT_VERSION) + { + errnum = ERR_BAD_VERSION; + return 1; + } + + entryno_ptr = (int *) (buffer + STAGE2_SAVED_ENTRYNO); + + /* Check if the saved entry number differs from current entry number. */ + if (*entryno_ptr != new_default) + { + /* Overwrite the saved entry number. */ + *entryno_ptr = new_default; + + /* Save the image in the disk. */ + if (! rawwrite (boot_drive, install_second_sector, buffer)) + return 1; + + /* Clear the cache. */ + buf_track = -1; + } + + return 0; +} +#endif + +#if !defined(SUPPORT_DISKLESS) && defined(GRUB_UTIL) +/* + * Full implementation of new `setdefault' for GRUB shell. + * XXX This needs fixing for stage2 files which aren't accessible + * through a mounted filesystem. + */ +static int +setdefault_shell(char *arg, int flags) +{ + char *stage2_os_file = "/boot/grub/stage2"; /* Default filename */ + FILE *fp; + char buffer[512]; + int *entryno_ptr; + int new_default = 0; + + while (1) + { + if (grub_memcmp ("--stage2=", arg, sizeof ("--stage2=") - 1) == 0) + { + stage2_os_file = arg + sizeof ("--stage2=") - 1; + arg = skip_to (0, arg); + nul_terminate (stage2_os_file); + } + else if (grub_memcmp ("--default=", arg, sizeof ("--default=") - 1) == 0) + { + char *p = arg + sizeof ("--default=") - 1; + if (! safe_parse_maxint (&p, &new_default)) + return 1; + arg = skip_to (0, arg); + } + else if (grub_memcmp ("--once", arg, sizeof ("--once") - 1) == 0) + { + new_default |= STAGE2_ONCEONLY_ENTRY; + arg = skip_to (0, arg); + } + else + break; + } + + if (! (fp = fopen(stage2_os_file, "r+"))) + { + errnum = ERR_FILE_NOT_FOUND; + return 1; + } + + if (fseek (fp, SECTOR_SIZE, SEEK_SET) != 0) + { + fclose (fp); + errnum = ERR_BAD_VERSION; + return 1; + } + + if (fread (buffer, 1, SECTOR_SIZE, fp) != SECTOR_SIZE) + { + fclose (fp); + errnum = ERR_READ; + return 1; + } + + /* Sanity check. */ + if (buffer[STAGE2_STAGE2_ID] != STAGE2_ID_STAGE2 + || *((short *) (buffer + STAGE2_VER_MAJ_OFFS)) != COMPAT_VERSION) + { + errnum = ERR_BAD_VERSION; + return 1; + } + + entryno_ptr = (int *) (buffer + STAGE2_SAVED_ENTRYNO); + *entryno_ptr = new_default; + + if (fseek (fp, SECTOR_SIZE, SEEK_SET) != 0) + { + fclose (fp); + errnum = ERR_BAD_VERSION; + return 1; + } + + if (fwrite (buffer, 1, SECTOR_SIZE, fp) != SECTOR_SIZE) + { + fclose (fp); + errnum = ERR_WRITE; + return 1; + } + + (void)fflush (fp); + fclose (fp); + return 0; +} +#endif + +/* setdefault */ +static int +setdefault_func (char *arg, int flags) +{ +#if !defined(SUPPORT_DISKLESS) +#if !defined(GRUB_UTIL) + int new_default; + /* This command is only useful when you boot an entry from the menu + interface. */ + if (! (flags & BUILTIN_SCRIPT)) + { + errnum = ERR_UNRECOGNIZED; + return 1; + } + /* convert new-default arg (a string) into an int */ + if (!safe_parse_maxint(&arg, &new_default)) return 1; + return setdefault_helper(new_default); +#else /* defined(GRUB_UTIL) */ + return setdefault_shell(arg, flags); +#endif +#else /* ! SUPPORT_DISKLESS && ! GRUB_UTIL */ + errnum = ERR_UNRECOGNIZED; + return 1; +#endif /* ! SUPPORT_DISKLESS && ! GRUB_UTIL */ +} + +static struct builtin builtin_setdefault = +{ + "setdefault", + setdefault_func, + BUILTIN_CMDLINE, +#ifdef GRUB_UTIL + "setdefault [--stage2=STAGE2_FILE] [--default=DEFAULT] [--once] Entry-Number", + "Save DEFAULT as the default boot entry in STAGE2_FILE. If '--once'" + " is specified, the default is reset after the next reboot." +#else + "setdefault", + "Set the given entry as the default boot entry." +#endif +}; + + #ifdef SUPPORT_SERIAL /* serial */ static int @@ -5009,6 +5192,7 @@ &builtin_root, &builtin_rootnoverify, &builtin_savedefault, + &builtin_setdefault, #ifdef SUPPORT_SERIAL &builtin_serial, #endif /* SUPPORT_SERIAL */
_______________________________________________ Bug-grub mailing list [EMAIL PROTECTED] http://mail.gnu.org/mailman/listinfo/bug-grub