bug-grub
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[patch] add setdefault X


From: Jim Cromie
Subject: [patch] add setdefault X
Date: Tue, 04 Nov 2003 10:07:28 -0700
User-agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.4) Gecko/20030624

hi folks,

This patch adds a new command to grub - setdefault.

Its a close derivative of savedefault, the only difference is that it expects a
numeric argument, where original uses an implicit argument.

Its purpose is to support multi-kernel testing; a grub.conf can specify a sequence of different kernels to run, which *presumably* would execute some substantial set of tests, then reboot to the next kernel, which would repeat until the last
setdefault (ie: 0 in example below) returned the box to normal operation.

Heres a sequence of 4 kernels on my machine:


# Here are the sequential boot tests

title Test RH 7.2 (2.4.20-20.7)
   setdefault 5
   root (hd0,1)
   kernel /vmlinuz-2.4.20-20.7 ro root=LABEL=/
   initrd /initrd-2.4.20-20.7.img

title Test RH 7.2 (2.4.20-18.7)
   setdefault 6
   root (hd0,1)
   kernel /vmlinuz-2.4.20-18.7 ro root=LABEL=/
   initrd /initrd-2.4.20-18.7.img

title Test RedHat 9 (2.4.20-20.9)
   setdefault 7
   root (hd0,0)
   kernel /boot/vmlinuz-2.4.20-20.9 ro root=LABEL=/1
   initrd /boot/initrd-2.4.20-20.9.img

title Test RedHat 9 (2.4.20-8)
   setdefault 0
   root (hd0,0)
   kernel /boot/vmlinuz-2.4.20-8 ro root=LABEL=/1
   initrd /boot/initrd-2.4.20-8.img


I expect to combine this with a runlevel=4 or similar to make it easy to trigger
the *smoke-test* and reboot from rc.local.



The patch is against RH grub-0.93-7 srpm, which has 18 patches for 0.90-0.93

Its also somewhat unfinished;

1.  I copy-pasted verbatim from savedefault_helper to setdefault_helper

The 'right' thing to do would be to rename savedefault_helper as setdefault_helper, and modify savedefault to call it. IOW, savedefault is higher-level than setdefault, and should be implemented on top. Doing this however felt a bit too brazen.

2.   No (proper patch to the source of ) docs.

I couldnt quite make out from docs/Makefile.am which texi/info/etc file to edit into. I added stuff into grub.texi.config.new, with hope that it could be easily cut-pasted
   into wherever it belongs.

I also left some of the help-text in static struct builtin builtin_setdefault:

I am unsure whether any of the options should be allowed; I think --once would not make any sense though. I did not strip the code for those options, so I thought it best to leave
   an inappropriate marker.


Lastly - I found the FAQ and info on installation somewhat confusing -
Specifically, putting an ext2 on a floppy is apparently mutually exclusive with writing stage1, stage2 via dd. I'll try to explain better in a separate (appropriately titled) msg.
--- grub.texi.config.old        Tue Nov  4 09:15:22 2003
+++ grub.texi.config.new        Tue Nov  4 09:39:10 2003
@@ -1845,8 +1845,9 @@
 used.
 
 You can specify @samp{saved} instead of a number. In this case, the
-default entry is the entry saved with the command
address@hidden @xref{savedefault}, for more information.
+default entry is the entry saved with the commands
address@hidden or @command{setdefault}. 
address@hidden, @xref{setdefault}, for more information.
 @end deffn
 
 
@@ -2404,6 +2405,7 @@
 * root::                        Set GRUB's root device
 * rootnoverify::                Set GRUB's root device without mounting
 * savedefault::                 Save current entry as the default entry
+* setdefault::                  Save given value as the default entry
 * setup::                       Set up GRUB's installation automatically
 * testload::                    Load a file for testing a filesystem
 * testvbe::                     Test VESA BIOS EXTENSION
@@ -2890,6 +2892,46 @@
 @end deffn
 
 
address@hidden setdefault
address@hidden setdefault
+
address@hidden Command setdefault
+Set the given menu entry as a default entry.  This command allows you
+to set up a sequence of configurations which will boot different
+kernels in sequence.  This is intended to support unattended testing
+of kernels, or of applications that should be portable across different
+kernels. Here is an example:
+
address@hidden
address@hidden
+default saved
+timeout 10
+# Assume 0..2 are normal boots.  
+# test boot sequence 3,4
+
+# assume this is
+title GNU/Linux TEST
+root (hd0,0)
+kernel /boot/vmlinuz root=/dev/sda1 vga=ext
+initrd /boot/initrd
+savedefault 4
+
+title FreeBSD TEST
+root (hd0,a)
+kernel /boot/loader
+setdefault 0
address@hidden group
address@hidden example
+
+With this configuration, once you (the user) select the 4th entry,
+GRUB will set the default to the 5th entry, then boot the 4th.  When
+the tests (which you configure separately) within the 4th entry
+complete and reboot, the 5th entry is then booted; it too runs tests
+and reboots, but before it does, it sets the default back to 0,
+resuming normal operations.
+See also @ref{default}.  @end deffn
+
+
 @node setup
 @subsection setup
 
--- builtins.old.c      Fri Oct 31 08:14:40 2003
+++ builtins.c  Tue Nov  4 09:54:21 2003
@@ -3515,6 +3515,189 @@
 };
 
 
+
+#if !defined(SUPPORT_DISKLESS) && !defined(GRUB_UTIL)
+/* Write specified default entry number into stage2 file. */
+static int
+setdefault_helper(int new_default)
+{
+  char buffer[512];
+  int *entryno_ptr;
+
+  /* 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))
+    {
+      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 != new_default)
+    {
+      /* Overwrite the saved entry number.  */
+      *entryno_ptr = new_default;
+      
+      /* Save the image in the disk.  */
+      if (! rawwrite (boot_drive, install_second_sector, buffer))
+       return 1;
+      
+      /* Clear the cache.  */
+      buf_track = -1;
+    }
+
+  return 0;
+}
+#endif
+
+#if !defined(SUPPORT_DISKLESS) && defined(GRUB_UTIL)
+/*
+ * Full implementation of new `setdefault' for GRUB shell.
+ * XXX This needs fixing for stage2 files which aren't accessible
+ *     through a mounted filesystem.
+ */
+static int
+setdefault_shell(char *arg, int flags)
+{
+  char *stage2_os_file = "/boot/grub/stage2"; /* Default filename */
+  FILE *fp;
+  char buffer[512];
+  int *entryno_ptr;
+  int new_default = 0;
+
+  while (1)
+    {
+      if (grub_memcmp ("--stage2=", arg, sizeof ("--stage2=") - 1) == 0)
+        {
+          stage2_os_file = arg + sizeof ("--stage2=") - 1;
+          arg = skip_to (0, arg);
+          nul_terminate (stage2_os_file);
+        }
+      else if (grub_memcmp ("--default=", arg, sizeof ("--default=") - 1) == 0)
+        {
+          char *p = arg + sizeof ("--default=") - 1;
+          if (! safe_parse_maxint (&p, &new_default))
+            return 1;
+          arg = skip_to (0, arg);
+        }
+      else if (grub_memcmp ("--once", arg, sizeof ("--once") - 1) == 0)
+        {
+          new_default |= STAGE2_ONCEONLY_ENTRY;
+          arg = skip_to (0, arg);
+        }
+      else
+        break;
+    }
+
+  if (! (fp = fopen(stage2_os_file, "r+")))
+    {
+      errnum = ERR_FILE_NOT_FOUND;
+      return 1;
+    }
+  
+  if (fseek (fp, SECTOR_SIZE, SEEK_SET) != 0)
+    {
+      fclose (fp);
+      errnum = ERR_BAD_VERSION;
+      return 1;
+    }
+  
+  if (fread (buffer, 1, SECTOR_SIZE, fp) != SECTOR_SIZE)
+    {
+      fclose (fp);
+      errnum = ERR_READ;
+      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);
+  *entryno_ptr = new_default;
+
+  if (fseek (fp, SECTOR_SIZE, SEEK_SET) != 0)
+    {
+      fclose (fp);
+      errnum = ERR_BAD_VERSION;
+      return 1;
+    }
+  
+  if (fwrite (buffer, 1, SECTOR_SIZE, fp) != SECTOR_SIZE)
+    {
+      fclose (fp);
+      errnum = ERR_WRITE;
+      return 1;
+    }
+  
+  (void)fflush (fp);
+  fclose (fp);
+  return 0;
+}
+#endif
+
+/* setdefault */
+static int
+setdefault_func (char *arg, int flags)
+{
+#if !defined(SUPPORT_DISKLESS)
+#if !defined(GRUB_UTIL)
+  int new_default;
+  /* This command is only useful when you boot an entry from the menu
+     interface.  */
+  if (! (flags & BUILTIN_SCRIPT))
+    {
+      errnum = ERR_UNRECOGNIZED;
+      return 1;
+    }
+  /* convert new-default arg (a string) into an int */
+  if (!safe_parse_maxint(&arg, &new_default)) return 1;
+  return setdefault_helper(new_default);
+#else /* defined(GRUB_UTIL) */
+  return setdefault_shell(arg, flags);
+#endif
+#else /* ! SUPPORT_DISKLESS && ! GRUB_UTIL */
+  errnum = ERR_UNRECOGNIZED;
+  return 1;
+#endif /* ! SUPPORT_DISKLESS && ! GRUB_UTIL */
+}
+
+static struct builtin builtin_setdefault =
+{
+  "setdefault",
+  setdefault_func,
+  BUILTIN_CMDLINE,
+#ifdef GRUB_UTIL
+  "setdefault [--stage2=STAGE2_FILE] [--default=DEFAULT] [--once] 
Entry-Number",
+  "Save DEFAULT as the default boot entry in STAGE2_FILE. If '--once'"
+  " is specified, the default is reset after the next reboot."
+#else
+  "setdefault",
+  "Set the given entry as the default boot entry."
+#endif
+};
+
+
 #ifdef SUPPORT_SERIAL
 /* serial */
 static int
@@ -5009,6 +5192,7 @@
   &builtin_root,
   &builtin_rootnoverify,
   &builtin_savedefault,
+  &builtin_setdefault,
 #ifdef SUPPORT_SERIAL
   &builtin_serial,
 #endif /* SUPPORT_SERIAL */

reply via email to

[Prev in Thread] Current Thread [Next in Thread]