Added support for remote booting: commands "expires" and "fallback"
This commit is contained in:
parent
d1d9022b1f
commit
6e7a81f3aa
9 changed files with 261 additions and 19 deletions
3
AUTHORS
3
AUTHORS
|
@ -48,3 +48,6 @@ Tilmann Bubeck added support for vt100-incompatible terminals.
|
|||
|
||||
KB Sriram added a better detection of FAT filesystem and fixed a
|
||||
network device completion.
|
||||
|
||||
Rick van Rein added the expires command to smoothen remote kernel upgrades.
|
||||
|
||||
|
|
10
ChangeLog
10
ChangeLog
|
@ -1,3 +1,13 @@
|
|||
2004-01-05 Rick van Rein <rick@vanrein.org>
|
||||
|
||||
* stage2/builtins.c: New menu command "expires". The change also
|
||||
influences the files stage2/shared.h, stage2/common.c, stage2/asm.S,
|
||||
grub/asmstub.c and docs/grub.texi. The "fallback" command is now a
|
||||
general command, in support of chained fallbacks.
|
||||
|
||||
* docs/grub.texi: Added missing documentation for ERR_NUMBER_OVERFLOW.
|
||||
|
||||
|
||||
2003-12-30 Yoshinori K. Okuji <okuji@enbug.org>
|
||||
|
||||
* stage2/fsys_ext2fs.c (ext2_is_fast_symlink): New function.
|
||||
|
|
2
NEWS
2
NEWS
|
@ -1,6 +1,8 @@
|
|||
NEWS - list of user-visible changes between releases of GRUB
|
||||
|
||||
New:
|
||||
* Add an expires command for temporary testing of boot entries, to solve
|
||||
problems with remotely maintained systems that need a kernel changeover.
|
||||
* Support building on x86-64 with gcc -m32.
|
||||
* Use a BIOS call to turn on/off Gate A20. This should solve various
|
||||
problems related to Gate A20 in modern BIOSes.
|
||||
|
|
|
@ -1829,7 +1829,6 @@ These commands can only be used in the menu:
|
|||
|
||||
@menu
|
||||
* default:: Set the default entry
|
||||
* fallback:: Set the fallback entry
|
||||
* hiddenmenu:: Hide the menu interface
|
||||
* timeout:: Set the timeout
|
||||
* title:: Start a menu entry
|
||||
|
@ -1850,18 +1849,6 @@ default entry is the entry saved with the command
|
|||
@end deffn
|
||||
|
||||
|
||||
@node fallback
|
||||
@subsection fallback
|
||||
|
||||
@deffn Command fallback num
|
||||
Go into unattended boot mode: if the default boot entry has any errors,
|
||||
instead of waiting for the user to do anything, immediately start
|
||||
over using the @var{num} entry (same numbering as the @code{default}
|
||||
command (@pxref{default})). This obviously won't help if the machine was
|
||||
rebooted by a kernel that GRUB loaded.
|
||||
@end deffn
|
||||
|
||||
|
||||
@node hiddenmenu
|
||||
@subsection hiddenmenu
|
||||
|
||||
|
@ -1902,6 +1889,8 @@ Commands usable both in the menu and in the command-line.
|
|||
* color:: Color the menu interface
|
||||
* device:: Specify a file as a drive
|
||||
* dhcp:: Initialize a network device via DHCP
|
||||
* expires:: Invalidate a menu entry after some time
|
||||
* fallback:: Set the fallback entry
|
||||
* hide:: Hide a partition
|
||||
* ifconfig:: Configure a network device manually
|
||||
* pager:: Change the state of the internal pager
|
||||
|
@ -2053,6 +2042,66 @@ with the vendor tag @samp{150}.
|
|||
@end deffn
|
||||
|
||||
|
||||
@node expires
|
||||
@subsection expires
|
||||
|
||||
@deffn Command expires YYYY-MM-DD HH:MM
|
||||
Make the current boot entry, as introduced by @command{title} (@pxref{title})
|
||||
expire after the given date and time. This is usually combined with
|
||||
the @command{fallback} command (@pxref{fallback}),
|
||||
which introduces the boot entry to be used after expiry.
|
||||
|
||||
When adminstering systems remotely, it is troublesome and dangerous
|
||||
to switch to new kernel versions. This option enables a GRUB setup
|
||||
to test new kernels, with a fallback to the old kernel after some
|
||||
time. All that is needed to fall back is a reset after the expiration,
|
||||
either manually imposed by a local operator or initiated by the loaded
|
||||
operating system.
|
||||
|
||||
The date is written in numbers, with the year in four digits. The time
|
||||
is written in 24-hour format, and reflects the time of the realtime clock.
|
||||
If the realtime clock holds the GMT time and the computer operates in
|
||||
another zone, then the argument to @command{expires} should still be
|
||||
GMT-time, because GRUB accesses the realtime clock.
|
||||
|
||||
@example
|
||||
@group
|
||||
default 0
|
||||
|
||||
title Test kernel with IPsec in place
|
||||
fallback 1
|
||||
expires 2004-01-04 18:15
|
||||
root (hd0,0)
|
||||
kernel /boot/vmlinuz-ipsec root=/dev/hda1
|
||||
initrd /boot/initrd.img
|
||||
boot
|
||||
|
||||
title Known-to-work kernel without IPsec
|
||||
root (hd0,0)
|
||||
kernel /boot/vmlinuz root=/dev/hda1
|
||||
initrd /boot/initrd.img
|
||||
boot
|
||||
@end group
|
||||
@end example
|
||||
@end deffn
|
||||
|
||||
@node fallback
|
||||
@subsection fallback
|
||||
|
||||
@deffn Command fallback num
|
||||
Go into unattended boot mode: if the default boot entry has any errors,
|
||||
instead of waiting for the user to do anything, immediately start
|
||||
over using the @var{num} entry (same numbering as the @code{default}
|
||||
command (@pxref{default})). This obviously won't help if the machine was
|
||||
rebooted by a kernel that GRUB loaded, unless combined with @command{expires}
|
||||
(@pxref{expires}).
|
||||
|
||||
The fallback command can be chained by specifying it in a boot entry
|
||||
which serves as a fallback option. The only point of caution is that
|
||||
it must be executed before the error triggering it occurs.
|
||||
@end deffn
|
||||
|
||||
|
||||
@node hide
|
||||
@subsection hide
|
||||
|
||||
|
@ -3190,6 +3239,19 @@ This error is returned if a disk doesn't have enough spare space. This
|
|||
happens when you try to embed Stage 1.5 into the unused sectors after
|
||||
the MBR, but the first partition starts right after the MBR or they are
|
||||
used by EZ-BIOS.
|
||||
|
||||
@item 35 : Overflow while parsing number
|
||||
Overflow while parsing number.
|
||||
|
||||
@item 36 : This boot option has expired
|
||||
This error is returned if an expiration date/time setup for this boot
|
||||
option falls before the date/time currently in the realtime clock.
|
||||
|
||||
@item 37 : Datestamp not formatted as YYYY-MM-DD HH:MM
|
||||
The expires command requires strict adherence to the given argument
|
||||
format. This failure is the safe one, as it avoids that a badly
|
||||
interpreted argument leads to never-expiring boot options.
|
||||
|
||||
@end table
|
||||
|
||||
|
||||
|
|
|
@ -486,6 +486,30 @@ getrtsecs (void)
|
|||
return time (0);
|
||||
}
|
||||
|
||||
unsigned char makebcd (int plainval)
|
||||
{
|
||||
return ((plainval / 10) << 4) + (plainval % 10);
|
||||
}
|
||||
|
||||
/* obtain current timestamp and store it in bytes rtc_now [6] */
|
||||
void
|
||||
get_rtc_now ()
|
||||
{
|
||||
extern unsigned char rtc_now [6];
|
||||
time_t ticks;
|
||||
struct tm *now;
|
||||
|
||||
time (&ticks);
|
||||
now = localtime (&ticks);
|
||||
|
||||
rtc_now [0] = makebcd ( ( now->tm_year + 1900 ) / 100 );
|
||||
rtc_now [1] = makebcd ( now->tm_year % 100 );
|
||||
rtc_now [2] = makebcd ( now->tm_mon + 1 );
|
||||
rtc_now [3] = makebcd ( now->tm_mday );
|
||||
rtc_now [4] = makebcd ( now->tm_hour );
|
||||
rtc_now [5] = makebcd ( now->tm_min );
|
||||
}
|
||||
|
||||
int
|
||||
currticks (void)
|
||||
{
|
||||
|
|
83
stage2/asm.S
83
stage2/asm.S
|
@ -2259,7 +2259,7 @@ ENTRY(console_setcursor)
|
|||
* getrtsecs()
|
||||
* if a seconds value can be read, read it and return it (BCD),
|
||||
* otherwise return 0xFF
|
||||
* BIOS call "INT 1AH Function 02H" to check whether a character is pending
|
||||
* BIOS call "INT 1AH Function 02H" to obtain the current time from the RTC
|
||||
* Call with %ah = 0x2
|
||||
* Return:
|
||||
* If RT Clock can give correct values
|
||||
|
@ -2294,7 +2294,86 @@ gottime:
|
|||
pop %ebp
|
||||
ret
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* get_rtc_now()
|
||||
* obtain bytes rtc_now[6] holding YYYYMMDDHHMM from the realtime clock under the BIOS
|
||||
* be sure to correct for any glitches
|
||||
* BIOS call "INT 1AH Function 02H" to obtain the current time from the RTC
|
||||
* Call with %ah = 0x2
|
||||
* Return:
|
||||
* If RT Clock can give correct values
|
||||
* %ch = hour (BCD)
|
||||
* %cl = minutes (BCD)
|
||||
* %dh = seconds (BCD)
|
||||
* %dl = daylight savings time (00h std, 01h daylight)
|
||||
* Carry flag = clear
|
||||
* else
|
||||
* Carry flag = set
|
||||
* (this indicates that the clock is updating, or
|
||||
* BIOS call "INT 1AH Function 04H" to obtain the current date from the RTC
|
||||
* Call with %ah = 0x4
|
||||
* Return:
|
||||
* If RT Clock can give correct values
|
||||
* %ch = century (BCD)
|
||||
* %cl = year (BCD)
|
||||
* %dh = month (BCD)
|
||||
* %dl = day of month (BCD)
|
||||
* Carry flag = clear
|
||||
* else
|
||||
* Carry flag = set
|
||||
* (this indicates that the clock is updating, or
|
||||
* that it isn't running)
|
||||
*/
|
||||
ENTRY(get_rtc_now)
|
||||
pushl %ebp
|
||||
|
||||
call EXT_C(prot_to_real) /* enter real mode */
|
||||
.code16
|
||||
|
||||
rtcredo:
|
||||
movb $0x4, %ah
|
||||
int $0x1a
|
||||
DATA32 jc rtcredo
|
||||
|
||||
pushw %dx
|
||||
pushw %cx
|
||||
|
||||
rtcretry:
|
||||
movb $0x2, %ah
|
||||
int $0x1a
|
||||
DATA32 jc rtcretry
|
||||
|
||||
pushw %cx
|
||||
|
||||
/* Now ensure that the date hasn't advanced in the meantime */
|
||||
movb $0x4, %ah
|
||||
int $0x1a
|
||||
movb %dl, %al
|
||||
|
||||
popw %bx
|
||||
popw %cx
|
||||
popw %dx
|
||||
|
||||
DATA32 jc rtcdone
|
||||
|
||||
cmpb %al, %dl
|
||||
DATA32 jne rtcredo
|
||||
|
||||
rtcdone:
|
||||
DATA32 call EXT_C(real_to_prot)
|
||||
.code32
|
||||
|
||||
movb %ch, EXT_C(rtc_now+0)
|
||||
movb %cl, EXT_C(rtc_now+1)
|
||||
movb %dh, EXT_C(rtc_now+2)
|
||||
movb %dl, EXT_C(rtc_now+3)
|
||||
movb %bh, EXT_C(rtc_now+4)
|
||||
movb %bl, EXT_C(rtc_now+5)
|
||||
|
||||
popl %ebp
|
||||
ret
|
||||
|
||||
/*
|
||||
* currticks()
|
||||
* return the real time in ticks, of which there are about
|
||||
|
|
|
@ -1138,6 +1138,64 @@ static struct builtin builtin_embed =
|
|||
" Print the number of sectors which STAGE1_5 occupies if successful."
|
||||
};
|
||||
|
||||
|
||||
/* expires */
|
||||
|
||||
static unsigned char parsebcdbyte (char *str)
|
||||
{
|
||||
if ((str [0] >= '0') && (str [0] <= '9') && (str [1] >= '0') && (str [1] <= '9'))
|
||||
{
|
||||
return ( str [0] << 4 ) + str [1] - ( 17 * '0' );
|
||||
}
|
||||
return 0xff;
|
||||
};
|
||||
|
||||
unsigned char rtc_now [6];
|
||||
unsigned char expires [6];
|
||||
|
||||
static int
|
||||
expires_func (char *arg, int flags)
|
||||
{
|
||||
/* Store YYYYMMDDHHMM in expires[] */
|
||||
if ( ((expires [0] = parsebcdbyte (arg+ 0)) == 0xff) ||
|
||||
((expires [1] = parsebcdbyte (arg+ 2)) == 0xff) ||
|
||||
(arg [ 4] != '-') ||
|
||||
((expires [2] = parsebcdbyte (arg+ 5)) == 0xff) ||
|
||||
(arg [ 7] != '-') ||
|
||||
((expires [3] = parsebcdbyte (arg+ 8)) == 0xff) ||
|
||||
(arg [10] != ' ') ||
|
||||
((expires [4] = parsebcdbyte (arg+11)) == 0xff) ||
|
||||
(arg [13] != ':') ||
|
||||
((expires [5] = parsebcdbyte (arg+14)) == 0xff) ||
|
||||
(arg [16] != 0) )
|
||||
{
|
||||
errnum = ERR_DATESTAMP;
|
||||
return 1;
|
||||
}
|
||||
|
||||
get_rtc_now (); /* Call BIOS to fill rtc_now[6] with YYYYMMDDHHMM */
|
||||
|
||||
if (grub_memcmp (rtc_now, expires, 6) >= 0)
|
||||
{
|
||||
errnum = ERR_EXPIRED;
|
||||
return 1; /* Failure: this boot entry has expired, try fallback */
|
||||
}
|
||||
|
||||
return 0; /* Success: this boot entry has not expired yet */
|
||||
};
|
||||
|
||||
static struct builtin builtin_expires =
|
||||
{
|
||||
"expires",
|
||||
expires_func,
|
||||
BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
|
||||
"expires YYYY-MM-DD HH:MM",
|
||||
"The current boot entry fails after the realtime clock reaches"
|
||||
" the date and time provided. This may be useful to test new kernels"
|
||||
" on distant systems -- rebooting those after a testing period can"
|
||||
" fallback to the old kernel when the boot entry under test expires."
|
||||
};
|
||||
|
||||
|
||||
/* fallback */
|
||||
static int
|
||||
|
@ -1153,15 +1211,13 @@ static struct builtin builtin_fallback =
|
|||
{
|
||||
"fallback",
|
||||
fallback_func,
|
||||
BUILTIN_MENU,
|
||||
#if 0
|
||||
BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
|
||||
"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"
|
||||
" `default' command). This obviously won't help if the machine"
|
||||
" was rebooted by a kernel that GRUB loaded."
|
||||
#endif
|
||||
" was rebooted by a kernel that GRUB loaded, unless combined with expires."
|
||||
};
|
||||
|
||||
|
||||
|
@ -4690,6 +4746,7 @@ struct builtin *builtin_table[] =
|
|||
&builtin_dump,
|
||||
#endif /* GRUB_UTIL */
|
||||
&builtin_embed,
|
||||
&builtin_expires,
|
||||
&builtin_fallback,
|
||||
&builtin_find,
|
||||
&builtin_fstest,
|
||||
|
|
|
@ -62,10 +62,12 @@ char *err_list[] =
|
|||
[ERR_BOOT_COMMAND] = "Kernel must be loaded before booting",
|
||||
[ERR_BOOT_FAILURE] = "Unknown boot failure",
|
||||
[ERR_BOOT_FEATURES] = "Unsupported Multiboot features requested",
|
||||
[ERR_DATESTAMP] = "Datestamp not formatted as YYYY-MM-DD HH:MM",
|
||||
[ERR_DEV_FORMAT] = "Unrecognized device string",
|
||||
[ERR_DEV_NEED_INIT] = "Device not initialized yet",
|
||||
[ERR_DEV_VALUES] = "Invalid device requested",
|
||||
[ERR_EXEC_FORMAT] = "Invalid or unsupported executable format",
|
||||
[ERR_EXPIRED] = "This boot option has expired",
|
||||
[ERR_FILELENGTH] =
|
||||
"Filesystem compatibility error, cannot read whole file",
|
||||
[ERR_FILE_NOT_FOUND] = "File not found",
|
||||
|
|
|
@ -533,6 +533,8 @@ typedef enum
|
|||
ERR_DEV_NEED_INIT,
|
||||
ERR_NO_DISK_SPACE,
|
||||
ERR_NUMBER_OVERFLOW,
|
||||
ERR_EXPIRED,
|
||||
ERR_DATESTAMP,
|
||||
|
||||
MAX_ERR_NUM
|
||||
} grub_error_t;
|
||||
|
@ -760,6 +762,7 @@ int get_code_end (void);
|
|||
/* low-level timing info */
|
||||
int getrtsecs (void);
|
||||
int currticks (void);
|
||||
void get_rtc_now (void);
|
||||
|
||||
/* Clear the screen. */
|
||||
void cls (void);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue