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
|
KB Sriram added a better detection of FAT filesystem and fixed a
|
||||||
network device completion.
|
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>
|
2003-12-30 Yoshinori K. Okuji <okuji@enbug.org>
|
||||||
|
|
||||||
* stage2/fsys_ext2fs.c (ext2_is_fast_symlink): New function.
|
* 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
|
NEWS - list of user-visible changes between releases of GRUB
|
||||||
|
|
||||||
New:
|
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.
|
* Support building on x86-64 with gcc -m32.
|
||||||
* Use a BIOS call to turn on/off Gate A20. This should solve various
|
* Use a BIOS call to turn on/off Gate A20. This should solve various
|
||||||
problems related to Gate A20 in modern BIOSes.
|
problems related to Gate A20 in modern BIOSes.
|
||||||
|
|
|
@ -1829,7 +1829,6 @@ These commands can only be used in the menu:
|
||||||
|
|
||||||
@menu
|
@menu
|
||||||
* default:: Set the default entry
|
* default:: Set the default entry
|
||||||
* fallback:: Set the fallback entry
|
|
||||||
* hiddenmenu:: Hide the menu interface
|
* hiddenmenu:: Hide the menu interface
|
||||||
* timeout:: Set the timeout
|
* timeout:: Set the timeout
|
||||||
* title:: Start a menu entry
|
* title:: Start a menu entry
|
||||||
|
@ -1850,18 +1849,6 @@ default entry is the entry saved with the command
|
||||||
@end deffn
|
@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
|
@node hiddenmenu
|
||||||
@subsection hiddenmenu
|
@subsection hiddenmenu
|
||||||
|
|
||||||
|
@ -1902,6 +1889,8 @@ Commands usable both in the menu and in the command-line.
|
||||||
* color:: Color the menu interface
|
* color:: Color the menu interface
|
||||||
* device:: Specify a file as a drive
|
* device:: Specify a file as a drive
|
||||||
* dhcp:: Initialize a network device via DHCP
|
* dhcp:: Initialize a network device via DHCP
|
||||||
|
* expires:: Invalidate a menu entry after some time
|
||||||
|
* fallback:: Set the fallback entry
|
||||||
* hide:: Hide a partition
|
* hide:: Hide a partition
|
||||||
* ifconfig:: Configure a network device manually
|
* ifconfig:: Configure a network device manually
|
||||||
* pager:: Change the state of the internal pager
|
* pager:: Change the state of the internal pager
|
||||||
|
@ -2053,6 +2042,66 @@ with the vendor tag @samp{150}.
|
||||||
@end deffn
|
@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
|
@node hide
|
||||||
@subsection 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
|
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
|
the MBR, but the first partition starts right after the MBR or they are
|
||||||
used by EZ-BIOS.
|
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
|
@end table
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -486,6 +486,30 @@ getrtsecs (void)
|
||||||
return time (0);
|
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
|
int
|
||||||
currticks (void)
|
currticks (void)
|
||||||
{
|
{
|
||||||
|
|
83
stage2/asm.S
83
stage2/asm.S
|
@ -2259,7 +2259,7 @@ ENTRY(console_setcursor)
|
||||||
* getrtsecs()
|
* getrtsecs()
|
||||||
* if a seconds value can be read, read it and return it (BCD),
|
* if a seconds value can be read, read it and return it (BCD),
|
||||||
* otherwise return 0xFF
|
* 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
|
* Call with %ah = 0x2
|
||||||
* Return:
|
* Return:
|
||||||
* If RT Clock can give correct values
|
* If RT Clock can give correct values
|
||||||
|
@ -2294,7 +2294,86 @@ gottime:
|
||||||
pop %ebp
|
pop %ebp
|
||||||
ret
|
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()
|
* currticks()
|
||||||
* return the real time in ticks, of which there are about
|
* 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."
|
" 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 */
|
/* fallback */
|
||||||
static int
|
static int
|
||||||
|
@ -1153,15 +1211,13 @@ static struct builtin builtin_fallback =
|
||||||
{
|
{
|
||||||
"fallback",
|
"fallback",
|
||||||
fallback_func,
|
fallback_func,
|
||||||
BUILTIN_MENU,
|
BUILTIN_MENU | BUILTIN_CMDLINE | BUILTIN_HELP_LIST,
|
||||||
#if 0
|
|
||||||
"fallback NUM",
|
"fallback NUM",
|
||||||
"Go into unattended boot mode: if the default boot entry has any"
|
"Go into unattended boot mode: if the default boot entry has any"
|
||||||
" errors, instead of waiting for the user to do anything, it"
|
" errors, instead of waiting for the user to do anything, it"
|
||||||
" immediately starts over using the NUM entry (same numbering as the"
|
" immediately starts over using the NUM entry (same numbering as the"
|
||||||
" `default' command). This obviously won't help if the machine"
|
" `default' command). This obviously won't help if the machine"
|
||||||
" was rebooted by a kernel that GRUB loaded."
|
" was rebooted by a kernel that GRUB loaded, unless combined with expires."
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -4690,6 +4746,7 @@ struct builtin *builtin_table[] =
|
||||||
&builtin_dump,
|
&builtin_dump,
|
||||||
#endif /* GRUB_UTIL */
|
#endif /* GRUB_UTIL */
|
||||||
&builtin_embed,
|
&builtin_embed,
|
||||||
|
&builtin_expires,
|
||||||
&builtin_fallback,
|
&builtin_fallback,
|
||||||
&builtin_find,
|
&builtin_find,
|
||||||
&builtin_fstest,
|
&builtin_fstest,
|
||||||
|
|
|
@ -62,10 +62,12 @@ char *err_list[] =
|
||||||
[ERR_BOOT_COMMAND] = "Kernel must be loaded before booting",
|
[ERR_BOOT_COMMAND] = "Kernel must be loaded before booting",
|
||||||
[ERR_BOOT_FAILURE] = "Unknown boot failure",
|
[ERR_BOOT_FAILURE] = "Unknown boot failure",
|
||||||
[ERR_BOOT_FEATURES] = "Unsupported Multiboot features requested",
|
[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_FORMAT] = "Unrecognized device string",
|
||||||
[ERR_DEV_NEED_INIT] = "Device not initialized yet",
|
[ERR_DEV_NEED_INIT] = "Device not initialized yet",
|
||||||
[ERR_DEV_VALUES] = "Invalid device requested",
|
[ERR_DEV_VALUES] = "Invalid device requested",
|
||||||
[ERR_EXEC_FORMAT] = "Invalid or unsupported executable format",
|
[ERR_EXEC_FORMAT] = "Invalid or unsupported executable format",
|
||||||
|
[ERR_EXPIRED] = "This boot option has expired",
|
||||||
[ERR_FILELENGTH] =
|
[ERR_FILELENGTH] =
|
||||||
"Filesystem compatibility error, cannot read whole file",
|
"Filesystem compatibility error, cannot read whole file",
|
||||||
[ERR_FILE_NOT_FOUND] = "File not found",
|
[ERR_FILE_NOT_FOUND] = "File not found",
|
||||||
|
|
|
@ -533,6 +533,8 @@ typedef enum
|
||||||
ERR_DEV_NEED_INIT,
|
ERR_DEV_NEED_INIT,
|
||||||
ERR_NO_DISK_SPACE,
|
ERR_NO_DISK_SPACE,
|
||||||
ERR_NUMBER_OVERFLOW,
|
ERR_NUMBER_OVERFLOW,
|
||||||
|
ERR_EXPIRED,
|
||||||
|
ERR_DATESTAMP,
|
||||||
|
|
||||||
MAX_ERR_NUM
|
MAX_ERR_NUM
|
||||||
} grub_error_t;
|
} grub_error_t;
|
||||||
|
@ -760,6 +762,7 @@ int get_code_end (void);
|
||||||
/* low-level timing info */
|
/* low-level timing info */
|
||||||
int getrtsecs (void);
|
int getrtsecs (void);
|
||||||
int currticks (void);
|
int currticks (void);
|
||||||
|
void get_rtc_now (void);
|
||||||
|
|
||||||
/* Clear the screen. */
|
/* Clear the screen. */
|
||||||
void cls (void);
|
void cls (void);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue