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.
+
+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.
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.
@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
@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
* 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
@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
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
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)
{
* 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
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
" Print the number of sectors which STAGE1_5 occupies if successful."
};
+\f
+/* 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."
+};
+
\f
/* fallback */
static int
{
"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."
};
\f
&builtin_dump,
#endif /* GRUB_UTIL */
&builtin_embed,
+ &builtin_expires,
&builtin_fallback,
&builtin_find,
&builtin_fstest,
[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",
ERR_DEV_NEED_INIT,
ERR_NO_DISK_SPACE,
ERR_NUMBER_OVERFLOW,
+ ERR_EXPIRED,
+ ERR_DATESTAMP,
MAX_ERR_NUM
} grub_error_t;
/* low-level timing info */
int getrtsecs (void);
int currticks (void);
+void get_rtc_now (void);
/* Clear the screen. */
void cls (void);