On Tue, Jun 29, 2004 at 12:44:00PM +0200, Yoshinori K. Okuji wrote: > On Monday 28 June 2004 16:02, Robert Millan wrote: > > Uhm. I think it's quite hard to support all possible variations of > > menu.lst in a script that sets the proper setdefault options, while > > ensuring there's no collateral effect. Do you have a particular > > scheme in mind for modifying it from the script? > > It's quite trivial for me. Here is an example to set up a menu.lst (not > complete or not tested):
Well, that would work. But still looks overkill, and having to remove the file through init.d is not very reliable. For example if you boot in single user it won't take effect. I think it should be grub itself who recovers to the normal estate after booting a new entry just once. I'm attaching a patch that does this in stage2. I think it's a cleaner solution. Please have a look and tell me what you think (Again, not tested or complete ;) -- Robert Millan "[..] but the delight and pride of Aule is in the deed of making, and in the thing made, and neither in possession nor in his own mastery; wherefore he gives and hoards not, and is free from care, passing ever on to some new work." -- J.R.R.T., Ainulindale (Silmarillion)
diff -Nur grub-0.95+cvs20040624.old/configure.ac grub-0.95+cvs20040624/configure.ac --- grub-0.95+cvs20040624.old/configure.ac 2004-06-20 15:48:46.000000000 +0200 +++ grub-0.95+cvs20040624/configure.ac 2004-06-29 19:38:41.000000000 +0200 @@ -666,5 +666,6 @@ docs/Makefile lib/Makefile util/Makefile \ grub/Makefile netboot/Makefile util/grub-image \ util/grub-install util/grub-md5-crypt \ - util/grub-terminfo util/grub-set-default]) + util/grub-terminfo util/grub-set-default \ + util/grub-set-override]) AC_OUTPUT diff -Nur grub-0.95+cvs20040624.old/stage2/shared.h grub-0.95+cvs20040624/stage2/shared.h --- grub-0.95+cvs20040624.old/stage2/shared.h 2004-06-20 15:48:47.000000000 +0200 +++ grub-0.95+cvs20040624/stage2/shared.h 2004-06-29 19:38:41.000000000 +0200 @@ -241,6 +241,10 @@ # endif #endif +#define STAGE2_SAVEDEFAULT_DUMMY -1 +#define STAGE2_SAVEDEFAULT_NOARGS -2 +#define STAGE2_SAVEDEFAULT_FALLBACK -3 + /* * defines for use when switching between real and protected mode */ @@ -692,6 +696,8 @@ extern entry_func entry_addr; +int savedefault_internal (char *, int); + /* Enter the stage1.5/stage2 C code after the stack is set up. */ void cmain (void); diff -Nur grub-0.95+cvs20040624.old/stage2/stage2.c grub-0.95+cvs20040624/stage2/stage2.c --- grub-0.95+cvs20040624.old/stage2/stage2.c 2004-06-20 15:48:47.000000000 +0200 +++ grub-0.95+cvs20040624/stage2/stage2.c 2004-06-29 19:38:41.000000000 +0200 @@ -827,6 +827,142 @@ return pos; } +/* savedefault_internal */ +static int +savedefault_internal (char *default_file, int arg) +{ +#if !defined(SUPPORT_DISKLESS) && !defined(GRUB_UTIL) + unsigned long tmp_drive = saved_drive; + unsigned long tmp_partition = saved_partition; + char buf[10]; + char sect[SECTOR_SIZE]; + int entryno; + int sector_count = 0; + int saved_sectors[2]; + int saved_offsets[2]; + int saved_lengths[2]; + + /* Save sector information about at most two sectors. */ + auto void disk_read_savesect_func (int sector, int offset, int length); + void disk_read_savesect_func (int sector, int offset, int length) + { + if (sector_count < 2) + { + saved_sectors[sector_count] = sector; + saved_offsets[sector_count] = offset; + saved_lengths[sector_count] = length; + } + sector_count++; + } + + /* Determine a saved entry number. */ + if (arg != STAGE2_SAVEDEFAULT_NOARGS) + { + if (arg == STAGE2_SAVEDEFAULT_FALLBACK) + { + int i; + int index = 0; + + for (i = 0; i < MAX_FALLBACK_ENTRIES; i++) + { + if (fallback_entries[i] < 0) + break; + if (fallback_entries[i] == current_entryno) + { + index = i + 1; + break; + } + } + + if (index >= MAX_FALLBACK_ENTRIES || fallback_entries[index] < 0) + { + /* This is the last. */ + errnum = ERR_BAD_ARGUMENT; + return 1; + } + + entryno = fallback_entries[index]; + } + else + entryno = arg; + } + else + entryno = current_entryno; + + /* Open the default file. */ + saved_drive = boot_drive; + saved_partition = install_partition; + if (grub_open (default_file)) + { + int len; + + disk_read_hook = disk_read_savesect_func; + len = grub_read (buf, sizeof (buf)); + disk_read_hook = 0; + grub_close (); + + if (len != sizeof (buf)) + { + /* This is too small. Do not modify the file manually, please! */ + errnum = ERR_READ; + goto fail; + } + + if (sector_count > 2) + { + /* Is this possible?! Too fragmented! */ + errnum = ERR_FSYS_CORRUPT; + goto fail; + } + + /* Set up a string to be written. */ + grub_memset (buf, '\n', sizeof (buf)); + grub_sprintf (buf, "%d", entryno); + + if (saved_lengths[0] < sizeof (buf)) + { + /* The file is anchored to another file and the first few bytes + are spanned in two sectors. Uggh... */ + if (! rawread (current_drive, saved_sectors[0], 0, SECTOR_SIZE, + sect)) + goto fail; + grub_memmove (sect + saved_offsets[0], buf, saved_lengths[0]); + if (! rawwrite (current_drive, saved_sectors[0], sect)) + goto fail; + + if (! rawread (current_drive, saved_sectors[1], 0, SECTOR_SIZE, + sect)) + goto fail; + grub_memmove (sect + saved_offsets[1], + buf + saved_lengths[0], + sizeof (buf) - saved_lengths[0]); + if (! rawwrite (current_drive, saved_sectors[1], sect)) + goto fail; + } + else + { + /* This is a simple case. It fits into a single sector. */ + if (! rawread (current_drive, saved_sectors[0], 0, SECTOR_SIZE, + sect)) + goto fail; + grub_memmove (sect + saved_offsets[0], buf, sizeof (buf)); + if (! rawwrite (current_drive, saved_sectors[0], sect)) + goto fail; + } + + /* Clear the cache. */ + buf_track = -1; + } + + fail: + saved_drive = tmp_drive; + saved_partition = tmp_partition; + return errnum; +#else /* ! SUPPORT_DISKLESS && ! GRUB_UTIL */ + errnum = ERR_UNRECOGNIZED; + return 1; +#endif /* ! SUPPORT_DISKLESS && ! GRUB_UTIL */ +} /* This is the starting function in C. */ void @@ -870,8 +1006,6 @@ char *default_file = (char *) DEFAULT_FILE_BUF; int i; - /* Get a saved default entry if possible. */ - saved_entryno = 0; grub_strncat (default_file, config_file, DEFAULT_FILE_BUFLEN); for (i = grub_strlen(default_file); i >= 0; i--) if (default_file[i] == '/') @@ -879,7 +1013,12 @@ i++; break; } - grub_strncat (default_file + i, "default", DEFAULT_FILE_BUFLEN - i); + + /* Uninitialised value */ + saved_entryno = STAGE2_SAVEDEFAULT_DUMMY; + + /* Try with "override" file */ + grub_strncat (default_file + i, "override", DEFAULT_FILE_BUFLEN - i); if (grub_open (default_file)) { char buf[10]; /* This is good enough. */ @@ -895,6 +1034,38 @@ grub_close (); } + + if (saved_entryno != STAGE2_SAVEDEFAULT_DUMMY) + { + /* "override" file had a valid value. Nuke it so it only works + once. */ + savedefault_internal (default_file, STAGE2_SAVEDEFAULT_DUMMY); + } + else + { + /* No override. Try with "default" file */ + grub_strncat (default_file + i, "default", DEFAULT_FILE_BUFLEN - i); + if (grub_open (default_file)) + { + char buf[10]; /* This is good enough. */ + char *p = buf; + int len; + + len = grub_read (buf, sizeof (buf)); + if (len > 0) + { + buf[sizeof (buf) - 1] = 0; + safe_parse_maxint (&p, &saved_entryno); + } + + grub_close (); + } + } + + /* None of them worked. Fallback to default. */ + if (saved_entryno == STAGE2_SAVEDEFAULT_DUMMY) + saved_entryno = 0; + errnum = ERR_NONE; do diff -Nur grub-0.95+cvs20040624.old/util/Makefile.am grub-0.95+cvs20040624/util/Makefile.am --- grub-0.95+cvs20040624.old/util/Makefile.am 2004-06-20 15:48:47.000000000 +0200 +++ grub-0.95+cvs20040624/util/Makefile.am 2004-06-29 18:40:14.000000000 +0200 @@ -1,6 +1,6 @@ bin_PROGRAMS = mbchk sbin_SCRIPTS = grub-install grub-md5-crypt grub-terminfo \ - grub-set-default + grub-set-default grub-set-override noinst_SCRIPTS = grub-image mkbimage EXTRA_DIST = mkbimage diff -Nur grub-0.95+cvs20040624.old/util/grub-set-override.in grub-0.95+cvs20040624/util/grub-set-override.in --- grub-0.95+cvs20040624.old/util/grub-set-override.in 1970-01-01 01:00:00.000000000 +0100 +++ grub-0.95+cvs20040624/util/grub-set-override.in 2004-06-29 19:18:42.000000000 +0200 @@ -0,0 +1,114 @@ +#! /bin/sh + +# Set a override boot entry for GRUB +# Copyright (C) 2004 Free Software Foundation, Inc. +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# Initialize some variables. [EMAIL PROTECTED]@ [EMAIL PROTECTED]@ + +rootdir= +entry= + +# Usage: usage +# Print the usage. +usage () { + cat <<EOF +Usage: grub-set-override [OPTION] entry +Set the override boot entry for GRUB. + + -h, --help print this message and exit + -v, --version print the version information and exit + --root-directory=DIR Use the directory DIR instead of the root directory + +ENTRY is a number or the special keyword \`override\'. + +Report bugs to <[EMAIL PROTECTED]>. +EOF +} + +# Check the arguments. +for option in "$@"; do + case "$option" in + -h | --help) + usage + exit 0 ;; + -v | --version) + echo "grub-set-override (GNU GRUB ${VERSION})" + exit 0 ;; + --root-directory=*) + rootdir=`echo "$option" | sed 's/--root-directory=//'` ;; + -*) + echo "Unrecognized option \`$option'" 1>&2 + usage + exit 1 + ;; + *) + if test "x$entry" != x; then + echo "More than one entries?" 1>&2 + usage + exit 1 + fi + # We don't care about what the user specified actually. + entry="${option}" ;; + esac +done + +if test "x$entry" = x; then + echo "entry not specified." 1>&2 + usage + exit 1 +fi + +# Determine the GRUB directory. This is different among OSes. +grubdir=${rootdir}/boot/grub +if test -d ${grubdir}; then + : +else + grubdir=${rootdir}/grub + if test -d ${grubdir}; then + : + else + echo "No GRUB directory found under ${rootdir}/" 1>&2 + exit 1 + fi +fi + +file=${grubdir}/override +if test -f ${file}; then + chmod 0600 ${file} + rm -f ${file} +fi +cat <<EOF > $file +$entry +# +# +# +# +# +# +# +# +# +# +# WARNING: If you want to edit this file directly, do not remove any line +# from this file, including this warning. Using \`grub-set-override\' is +# strongly recommended. +EOF + +# Bye. +exit 0
_______________________________________________ Bug-grub mailing list [EMAIL PROTECTED] http://lists.gnu.org/mailman/listinfo/bug-grub