mirror of
https://git.savannah.gnu.org/git/grub.git
synced 2026-10-27 17:49:23 +00:00
2004-06-20 Yoshinori K. Okuji <okuji@enbug.org>
This is a big change on saving a default entry. This change makes it possible to set up a quite robust system using GRUB. Now we do not use the second sector of Stage 2 to store an entry number but use the file /boot/grub/default. This file must be generated by grub-set-default, although this file is plain-text. * util/grub-set-default.in: New file. * util/grub-install.in (grub_set_default): New variable. Use /grub instead of /boot/grub on OpenBSD as well as NetBSD. Run grub-set-default to make a default file. * util/Makefile.am (sbin_SCRIPTS): Added grub-set-default. * stage2/stage2.c (run_menu): Change the fallback handling to support multiple fallback entries. (cmain): Likewise. Also, get a saved entry from a default file if possible, before reading a config file. * stage2/shared.h (DEFAULT_FILE_BUF): New macro. (DEFAULT_FILE_BUFLEN): Likewise. (CMDLINE_BUF): Set to DEFAULT_FILE_BUF + DEFAULT_FILE_BUFLEN. (MENU_BUFLEN): Set to 0x8000 + PASSWORD_BUF - MENU_BUF. (fallback_entry): Removed. (fallback_entries): Declared. (fallback_entryno): Likewise. (MAX_FALLBACK_ENTRIES): New macro. * stage2/cmdline.c (run_script): Use FALLBACK_ENTRYNO instead of FALLBACK_ENTRY. * stage2/builtins.c (fallback_entry): Removed. (fallback_entryno): New variable. (fallback_entries): Likewise. (init_config): Initialize FALLBACK_ENTRYNO and FALLBACK_ENTRIES. (fallback_func): Rewritten completely. (savedefault_func): Likewise. * docs/grub.texi (grub-set-default): New direntry. (Installation): Describe grub-set-default for manual installations. (Making your system robust): New section. (Booting once-only): New subsection. (Booting fallback systems): Likewise. (fallback): Describe multiple fallback entries. (savedefault): Describe an optional argument. (Invoking grub-set-default): New chapter. (Future): Replaced with a description about GRUB 2. * configure.ac (AC_CONFIG_FILES): Added util/grub-set-default.
This commit is contained in:
1 parent
e15e075464
commit
5b5f6dc772
16 files changed
+705
-98
No files matched your search
+155
-40
@@ -59,7 +59,8 @@ int debug = 0;
|
||||
/* The default entry. */
|
||||
int default_entry = 0;
|
||||
/* The fallback entry. */
|
||||
int fallback_entry = -1;
|
||||
int fallback_entryno;
|
||||
int fallback_entries[MAX_FALLBACK_ENTRIES];
|
||||
/* The number of current entry. */
|
||||
int current_entryno;
|
||||
/* The address for Multiboot command-line buffer. */
|
||||
@@ -97,7 +98,8 @@ init_config (void)
|
||||
{
|
||||
default_entry = 0;
|
||||
password = 0;
|
||||
fallback_entry = -1;
|
||||
fallback_entryno = -1;
|
||||
fallback_entries[0] = -1;
|
||||
grub_timeout = -1;
|
||||
}
|
||||
|
||||
@@ -1143,9 +1145,35 @@ static struct builtin builtin_embed =
|
||||
static int
|
||||
fallback_func (char *arg, int flags)
|
||||
{
|
||||
if (! safe_parse_maxint (&arg, &fallback_entry))
|
||||
return 1;
|
||||
int i = 0;
|
||||
|
||||
while (*arg)
|
||||
{
|
||||
int entry;
|
||||
int j;
|
||||
|
||||
if (! safe_parse_maxint (&arg, &entry))
|
||||
return 1;
|
||||
|
||||
/* Remove duplications to prevent infinite looping. */
|
||||
for (j = 0; j < i; j++)
|
||||
if (entry == fallback_entries[j])
|
||||
break;
|
||||
if (j != i)
|
||||
continue;
|
||||
|
||||
fallback_entries[i++] = entry;
|
||||
if (i == MAX_FALLBACK_ENTRIES)
|
||||
break;
|
||||
|
||||
arg = skip_to (0, arg);
|
||||
}
|
||||
|
||||
if (i < MAX_FALLBACK_ENTRIES)
|
||||
fallback_entries[i] = -1;
|
||||
|
||||
fallback_entryno = (i == 0) ? -1 : 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1155,7 +1183,7 @@ static struct builtin builtin_fallback =
|
||||
fallback_func,
|
||||
BUILTIN_MENU,
|
||||
#if 0
|
||||
"fallback NUM",
|
||||
"fallback NUM...",
|
||||
"Go into unattended boot mode: if the default boot entry has any"
|
||||
" errors, instead of waiting for the user to do anything, it"
|
||||
" immediately starts over using the NUM entry (same numbering as the"
|
||||
@@ -3185,8 +3213,29 @@ static int
|
||||
savedefault_func (char *arg, int flags)
|
||||
{
|
||||
#if !defined(SUPPORT_DISKLESS) && !defined(GRUB_UTIL)
|
||||
char buffer[512];
|
||||
int *entryno_ptr;
|
||||
unsigned long tmp_drive = saved_drive;
|
||||
unsigned long tmp_partition = saved_partition;
|
||||
char *default_file = (char *) DEFAULT_FILE_BUF;
|
||||
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++;
|
||||
}
|
||||
|
||||
/* This command is only useful when you boot an entry from the menu
|
||||
interface. */
|
||||
@@ -3195,46 +3244,110 @@ savedefault_func (char *arg, int flags)
|
||||
errnum = ERR_UNRECOGNIZED;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* 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))
|
||||
/* Determine a saved entry number. */
|
||||
if (*arg)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
if (grub_memcmp (arg, "fallback", sizeof ("fallback") - 1) == 0)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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 != current_entryno)
|
||||
{
|
||||
/* Overwrite the saved entry number. */
|
||||
*entryno_ptr = current_entryno;
|
||||
|
||||
/* Save the image in the disk. */
|
||||
if (! rawwrite (boot_drive, install_second_sector, buffer))
|
||||
entryno = fallback_entries[index];
|
||||
}
|
||||
else if (! safe_parse_maxint (&arg, &entryno))
|
||||
return 1;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
saved_drive = tmp_drive;
|
||||
saved_partition = tmp_partition;
|
||||
return errnum;
|
||||
#else /* ! SUPPORT_DISKLESS && ! GRUB_UTIL */
|
||||
errnum = ERR_UNRECOGNIZED;
|
||||
return 1;
|
||||
@@ -3246,8 +3359,10 @@ static struct builtin builtin_savedefault =
|
||||
"savedefault",
|
||||
savedefault_func,
|
||||
BUILTIN_CMDLINE,
|
||||
"savedefault",
|
||||
"Save the current entry as the default boot entry."
|
||||
"savedefault [NUM | `fallback']",
|
||||
"Save the current entry as the default boot entry if no argument is"
|
||||
" specified. If a number is specified, this number is saved. If"
|
||||
" `fallback' is used, next fallback entry is saved."
|
||||
};
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user