This patch implements UUID support in ext2, then in grub-probe and search
command, and finally in update-grub scripts.

The result is that when UUID can be used (i.e. our /boot is ext2), update-grub
puts the number in grub.cfg as a parameter to search command, and no longer
relies on hardcoded values for the `root' variable.

This is very helpful specially when device.map only maps to broken drive
names (which happens always on OFW and sometimes on BIOS).

-- 
Robert Millan

<GPLv2> I know my rights; I want my phone call!
<DRM> What good is a phone call… if you are unable to speak?
(as seen on /.)
diff -x configure -x config.h.in -x CVS -x '*~' -x '*.mk' -urp ../grub2/commands/search.c ./commands/search.c
--- ../grub2/commands/search.c	2007-07-22 01:32:19.000000000 +0200
+++ ./commands/search.c	2008-05-29 16:00:53.000000000 +0200
@@ -1,7 +1,7 @@
 /* search.c - search devices based on a file or a filesystem label */
 /*
  *  GRUB  --  GRand Unified Bootloader
- *  Copyright (C) 2005,2007  Free Software Foundation, Inc.
+ *  Copyright (C) 2005,2007,2008  Free Software Foundation, Inc.
  *
  *  GRUB is free software: you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -32,6 +32,7 @@ static const struct grub_arg_option opti
   {
     {"file", 'f', 0, "search devices by a file (default)", 0, 0},
     {"label", 'l', 0, "search devices by a filesystem label", 0, 0},
+    {"fs_uuid", 'u', 0, "search devices by a filesystem UUID", 0, 0},
     {"set", 's', GRUB_ARG_OPTION_OPTIONAL, "set a variable to the first device found", "VAR", ARG_TYPE_STRING},
     {0, 0, 0, 0, 0, 0}
   };
@@ -85,6 +86,54 @@ search_label (const char *key, const cha
 }
 
 static void
+search_fs_uuid (const char *key, const char *var)
+{
+  int count = 0;
+  auto int iterate_device (const char *name);
+
+  int iterate_device (const char *name)
+    {
+      grub_device_t dev;
+
+      dev = grub_device_open (name);
+      if (dev)
+	{
+	  grub_fs_t fs;
+	  
+	  fs = grub_fs_probe (dev);
+	  if (fs && fs->uuid)
+	    {
+	      char *uuid;
+	      
+	      (fs->uuid) (dev, &uuid);
+	      if (grub_errno == GRUB_ERR_NONE && uuid)
+		{
+		  if (grub_strcmp (uuid, key) == 0)
+		    {
+		      /* Found!  */
+		      grub_printf (" %s", name);
+		      if (count++ == 0 && var)
+			grub_env_set (var, name);
+		    }
+		  
+		  grub_free (uuid);
+		}
+	    }
+	  
+	  grub_device_close (dev);
+	}
+
+      grub_errno = GRUB_ERR_NONE;
+      return 0;
+    }
+  
+  grub_device_iterate (iterate_device);
+  
+  if (count == 0)
+    grub_error (GRUB_ERR_FILE_NOT_FOUND, "no such device: %s", key);
+}
+
+static void
 search_file (const char *key, const char *var)
 {
   int count = 0;
@@ -136,11 +185,13 @@ grub_cmd_search (struct grub_arg_list *s
   if (argc == 0)
     return grub_error (GRUB_ERR_INVALID_COMMAND, "no argument specified");
 
-  if (state[2].set)
-    var = state[2].arg ? : "root";
+  if (state[3].set)
+    var = state[3].arg ? state[3].arg : "root";
   
   if (state[1].set)
     search_label (args[0], var);
+  else if (state[2].set)
+    search_fs_uuid (args[0], var);
   else
     search_file (args[0], var);
 
@@ -151,8 +202,8 @@ GRUB_MOD_INIT(search)
 {
   (void) mod;			/* To stop warning. */
   grub_register_command ("search", grub_cmd_search, GRUB_COMMAND_FLAG_BOTH,
-			 "search [-f|-l|-s] NAME",
-			 "Search devices by a file or a filesystem label."
+			 "search [-f|-l|-u|-s] NAME",
+			 "Search devices by file, filesystem label or filesystem UUID."
 			 " If --set is specified, the first device found is"
 			 " set to a variable. If no variable name is"
 			 " specified, \"root\" is used.",
diff -x configure -x config.h.in -x CVS -x '*~' -x '*.mk' -urp ../grub2/fs/ext2.c ./fs/ext2.c
--- ../grub2/fs/ext2.c	2008-05-29 15:02:13.000000000 +0200
+++ ./fs/ext2.c	2008-05-29 15:39:27.000000000 +0200
@@ -120,7 +120,7 @@ struct grub_ext2_sblock
   grub_uint32_t feature_compatibility;
   grub_uint32_t feature_incompat;
   grub_uint32_t feature_ro_compat;
-  grub_uint32_t unique_id[4];
+  grub_uint16_t uuid[8];
   char volume_name[16];
   char last_mounted_on[64];
   grub_uint32_t compression_info;
@@ -861,7 +861,39 @@ grub_ext2_label (grub_device_t device, c
   if (data)
     *label = grub_strndup (data->sblock.volume_name, 14);
   else
-    *label = 0;
+    *label = NULL;
+
+#ifndef GRUB_UTIL
+  grub_dl_unref (my_mod);
+#endif
+
+  grub_free (data);
+
+  return grub_errno;
+}
+
+static grub_err_t
+grub_ext2_uuid (grub_device_t device, char **uuid)
+{
+  struct grub_ext2_data *data;
+  grub_disk_t disk = device->disk;
+
+#ifndef GRUB_UTIL
+  grub_dl_ref (my_mod);
+#endif
+
+  data = grub_ext2_mount (disk);
+  if (data)
+    {
+      *uuid = grub_malloc (40 + sizeof ('\0'));
+      grub_sprintf (*uuid, "%02x%02x-%02x-%02x-%02x-%02x%02x%02x",
+		    grub_be_to_cpu16 (data->sblock.uuid[0]), grub_be_to_cpu16 (data->sblock.uuid[1]),
+		    grub_be_to_cpu16 (data->sblock.uuid[2]), grub_be_to_cpu16 (data->sblock.uuid[3]),
+		    grub_be_to_cpu16 (data->sblock.uuid[4]), grub_be_to_cpu16 (data->sblock.uuid[5]),
+		    grub_be_to_cpu16 (data->sblock.uuid[6]), grub_be_to_cpu16 (data->sblock.uuid[7]));
+    }
+  else
+    *uuid = NULL;
 
 #ifndef GRUB_UTIL
   grub_dl_unref (my_mod);
@@ -881,6 +913,7 @@ static struct grub_fs grub_ext2_fs =
     .read = grub_ext2_read,
     .close = grub_ext2_close,
     .label = grub_ext2_label,
+    .uuid = grub_ext2_uuid,
     .next = 0
   };
 
diff -x configure -x config.h.in -x CVS -x '*~' -x '*.mk' -urp ../grub2/include/grub/fs.h ./include/grub/fs.h
--- ../grub2/include/grub/fs.h	2008-01-25 23:33:57.000000000 +0100
+++ ./include/grub/fs.h	2008-05-29 15:21:57.000000000 +0200
@@ -51,6 +51,11 @@ struct grub_fs
      caller.  */
   grub_err_t (*label) (grub_device_t device, char **label);
 
+  /* Return the uuid of the device DEVICE in UUID.  The uuid is
+     returned in a grub_malloc'ed buffer and should be freed by the
+     caller.  */
+  grub_err_t (*uuid) (grub_device_t device, char **uuid);
+
   /* The next filesystem.  */
   struct grub_fs *next;
 };
diff -x configure -x config.h.in -x CVS -x '*~' -x '*.mk' -urp ../grub2/util/grub.d/00_header.in ./util/grub.d/00_header.in
--- ../grub2/util/grub.d/00_header.in	2008-02-03 19:27:41.000000000 +0100
+++ ./util/grub.d/00_header.in	2008-05-29 17:04:42.000000000 +0200
@@ -38,8 +38,12 @@ set default=${GRUB_DEFAULT}
 set timeout=${GRUB_TIMEOUT}
 EOF
 
-if [ "x${GRUB_DRIVE}" = "x" ] ; then : ; else
-  echo "set root=${GRUB_DRIVE}"
+# If there's a filesystem UUID that GRUB is capable of identifiing, use it;
+# otherwise set root as per value in device.map.
+if [ "x${GRUB_DEVICE_BOOT_UUID}" = "x" ] ; then
+  echo "set root=`grub-probe --device ${GRUB_DEVICE_BOOT} --target=drive`"
+else
+  echo "search --fs_uuid ${GRUB_DEVICE_BOOT_UUID} --set"
 fi
 
 case ${platform}:${GRUB_TERMINAL} in
diff -x configure -x config.h.in -x CVS -x '*~' -x '*.mk' -urp ../grub2/util/grub.d/10_hurd.in ./util/grub.d/10_hurd.in
--- ../grub2/util/grub.d/10_hurd.in	2008-01-10 14:52:24.000000000 +0100
+++ ./util/grub.d/10_hurd.in	2008-05-29 16:19:11.000000000 +0200
@@ -31,9 +31,9 @@ for i in /boot/gnumach.gz /boot/gnumach 
   if test -e $i ; then
     basename=`basename $i`
     dirname=`dirname $i`
-    grub_dirname=`echo ${dirname} | sed -e "s%^/boot%${GRUB_DRIVE_BOOT}%g"`
+    rel_dirname=`make_system_path_relative_to_its_root $dirname`
     echo "Found GNU Mach: $i" >&2
-    kernel=${grub_dirname}/${basename}
+    kernel=${rel_dirname}/${basename}
     at_least_one=true
   fi
 done
diff -x configure -x config.h.in -x CVS -x '*~' -x '*.mk' -urp ../grub2/util/grub.d/10_linux.in ./util/grub.d/10_linux.in
--- ../grub2/util/grub.d/10_linux.in	2008-04-30 23:08:32.000000000 +0200
+++ ./util/grub.d/10_linux.in	2008-05-29 16:17:27.000000000 +0200
@@ -87,7 +87,7 @@ while [ "x$list" != "x" ] ; do
   echo "Found linux image: $linux" >&2
   basename=`basename $linux`
   dirname=`dirname $linux`
-  grub_dirname=`echo ${dirname} | sed -e "s%^/boot%${GRUB_DRIVE_BOOT}%g"`
+  rel_dirname=`make_system_path_relative_to_its_root $dirname`
   version=`echo $basename | sed -e "s,^[^0-9]*-,,g"`
   alt_version=`echo $version | sed -e "s,\.old$,,g"`
 
@@ -105,11 +105,11 @@ while [ "x$list" != "x" ] ; do
 
   cat << EOF
 menuentry "${OS}, linux ${version}" {
-	linux	${grub_dirname}/${basename} root=${GRUB_DEVICE} ro ${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}
+	linux	${rel_dirname}/${basename} root=${GRUB_DEVICE} ro ${GRUB_CMDLINE_LINUX} ${GRUB_CMDLINE_LINUX_DEFAULT}
 EOF
   if test -n "${initrd}" ; then
     cat << EOF
-	initrd	${grub_dirname}/${initrd}
+	initrd	${rel_dirname}/${initrd}
 EOF
   fi
   cat << EOF
@@ -118,11 +118,11 @@ EOF
 
   cat << EOF
 menuentry "${OS}, linux ${version} (single-user mode)" {
-	linux	${grub_dirname}/${basename} root=${GRUB_DEVICE} ro single ${GRUB_CMDLINE_LINUX}
+	linux	${rel_dirname}/${basename} root=${GRUB_DEVICE} ro single ${GRUB_CMDLINE_LINUX}
 EOF
   if test -n "${initrd}" ; then
     cat << EOF
-	initrd	${grub_dirname}/${initrd}
+	initrd	${rel_dirname}/${initrd}
 EOF
   fi
   cat << EOF
diff -x configure -x config.h.in -x CVS -x '*~' -x '*.mk' -urp ../grub2/util/grub-probe.c ./util/grub-probe.c
--- ../grub2/util/grub-probe.c	2008-05-06 15:34:28.000000000 +0200
+++ ./util/grub-probe.c	2008-05-29 15:38:29.000000000 +0200
@@ -44,6 +44,7 @@
 
 enum {
   PRINT_FS,
+  PRINT_FS_UUID,
   PRINT_DRIVE,
   PRINT_DEVICE,
   PRINT_PARTMAP,
@@ -110,6 +111,7 @@ probe (const char *path, char *device_na
   char *filebuf_via_grub = NULL, *filebuf_via_sys = NULL;
   int abstraction_type;
   grub_device_t dev = NULL;
+  grub_fs_t fs;
   
   if (path == NULL)
     {
@@ -185,10 +187,13 @@ probe (const char *path, char *device_na
       goto end;
     }
 
+  fs = grub_fs_probe (dev);
+  if (! fs)
+    grub_util_error ("%s", grub_errmsg);
+
   if (print == PRINT_FS)
     {
       struct stat st;
-      grub_fs_t fs;
 
       stat (path, &st);
 
@@ -210,19 +215,21 @@ probe (const char *path, char *device_na
 	  
 	  if (memcmp (filebuf_via_grub, filebuf_via_sys, file->size))
 	    grub_util_error ("files differ");
-
-	  fs = file->fs;
-	}
-      else
-	{
-	  fs = grub_fs_probe (dev);
-	  if (! fs)
-	    grub_util_error ("%s", grub_errmsg);
 	}
-
       printf ("%s\n", fs->name);
     }
 
+  if (print == PRINT_FS_UUID)
+    {
+      char *uuid;
+      if (! fs->uuid)
+	grub_util_error ("%s does not support UUIDs", fs->name);
+
+      fs->uuid (dev, &uuid);
+
+      printf ("%s\n", uuid);
+    }
+
  end:
   if (dev)
     grub_device_close (dev);
@@ -257,7 +264,7 @@ Probe device information for a given pat
 \n\
   -d, --device              given argument is a system device, not a path\n\
   -m, --device-map=FILE     use FILE as the device map [default=%s]\n\
-  -t, --target=(fs|drive|device|partmap|abstraction)\n\
+  -t, --target=(fs|fs_uuid|drive|device|partmap|abstraction)\n\
                             print filesystem module, GRUB drive, system device, partition map module or abstraction module [default=fs]\n\
   -h, --help                display this message and exit\n\
   -V, --version             print version information and exit\n\
@@ -302,6 +309,8 @@ main (int argc, char *argv[])
 	  case 't':
 	    if (!strcmp (optarg, "fs"))
 	      print = PRINT_FS;
+	    else if (!strcmp (optarg, "fs_uuid"))
+	      print = PRINT_FS_UUID;
 	    else if (!strcmp (optarg, "drive"))
 	      print = PRINT_DRIVE;
 	    else if (!strcmp (optarg, "device"))
diff -x configure -x config.h.in -x CVS -x '*~' -x '*.mk' -urp ../grub2/util/update-grub.in ./util/update-grub.in
--- ../grub2/util/update-grub.in	2008-05-28 21:56:26.000000000 +0200
+++ ./util/update-grub.in	2008-05-29 17:03:44.000000000 +0200
@@ -102,20 +102,16 @@ fi
 
 # Device containing our userland.  Typically used for root= parameter.
 GRUB_DEVICE="`grub-probe --target=device /`"
+GRUB_DEVICE_UUID="`grub-probe --device ${GRUB_DEVICE} --target=fs_uuid 2> /dev/null`"
+
+# Device containing our /boot partition.  Usually the same as GRUB_DEVICE.
+GRUB_DEVICE_BOOT="`grub-probe --target=device /boot`"
+GRUB_DEVICE_BOOT_UUID="`grub-probe --device ${GRUB_DEVICE_BOOT} --target=fs_uuid 2> /dev/null`"
 
 # Filesystem for the device containing our userland.  Used for stuff like
 # choosing Hurd filesystem module.
 GRUB_FS="`grub-probe --target=fs / 2> /dev/null || echo unknown`"
 
-# GRUB path to /.  Only used for "set root=".  Not critical.
-GRUB_DRIVE="`grub-probe --target=drive /`" || true
-
-# GRUB path to /boot
-GRUB_DRIVE_BOOT="`convert_system_path_to_grub_path /boot`"
-
-# GRUB path to /boot/grub
-GRUB_DRIVE_BOOT_GRUB="`convert_system_path_to_grub_path /boot/grub`"
-
 if test -f ${sysconfdir}/default/grub ; then
   . ${sysconfdir}/default/grub
 fi
@@ -155,7 +151,7 @@ esac
 
 # These are defined in this script, export them here so that user can
 # override them.
-export GRUB_DEVICE GRUB_FS GRUB_DRIVE GRUB_DRIVE_BOOT GRUB_DRIVE_BOOT_GRUB GRUB_FONT_PATH GRUB_PRELOAD_MODULES
+export GRUB_DEVICE GRUB_DEVICE_UUID GRUB_DEVICE_BOOT GRUB_DEVICE_BOOT_UUID GRUB_FS GRUB_FONT_PATH GRUB_PRELOAD_MODULES
 
 # These are optional, user-defined variables.
 export GRUB_DEFAULT GRUB_TIMEOUT GRUB_DISTRIBUTOR GRUB_CMDLINE_LINUX GRUB_CMDLINE_LINUX_DEFAULT GRUB_TERMINAL GRUB_SERIAL_COMMAND
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to