grub-devel.gnu.org archive mirror
 help / color / mirror / Atom feed
From: "Vladimir 'φ-coder/phcoder' Serbinenko" <phcoder@gmail.com>
To: The development of GNU GRUB <grub-devel@gnu.org>
Cc: Richard Laager <rlaager@wiktel.com>,
	Zachary Bedell <pendorbound@gmail.com>
Subject: Re: [Patch] Robustly search for ZFS labels & uberblocks
Date: Sat, 28 Jan 2012 13:51:08 +0100	[thread overview]
Message-ID: <4F23EF3C.9050407@gmail.com> (raw)
In-Reply-To: <1327719035.9477.68.camel@watermelon.coderich.net>

[-- Attachment #1: Type: text/plain, Size: 6412 bytes --]

On 28.01.2012 03:50, Richard Laager wrote:
> On Fri, 2012-01-27 at 14:04 -0500, Zachary Bedell wrote:
>> >  I've had to forward port the other changes necessary to support build on Linux.

I attach my zfs-related changed. I'll commit them before your patch and 
it already covers most of issues
> Attached is the work I've done on this front. This includes the "allow
> spaces in zpools" patch I previously submitted to grub-devel. And, the
> changes in 10_linux.in are from dajhorn's Ubuntu packages.
I already commented on 10_linux.in changes. They are pretty sloppy. 
(mostly is "it works for me and I don't care about other legitimate 
configs")
>
>
> zfs-on-linux.patch
>
>
> Index: grub/util/grub.d/10_linux.in
> ===================================================================
> --- grub.orig/util/grub.d/10_linux.in	2012-01-24 23:44:10.530591000 -0600
> +++ grub/util/grub.d/10_linux.in	2012-01-24 23:44:10.706928000 -0600
> @@ -56,8 +56,10 @@
>     LINUX_ROOT_DEVICE=UUID=${GRUB_DEVICE_UUID}
>   fi
>
> -if [ "x`${grub_probe} --device ${GRUB_DEVICE} --target=fs 2>/dev/null || true`" = xbtrfs ] \
> -    || [ "x`stat -f --printf=%T /`" = xbtrfs ]; then
> +LINUX_ROOT_FS=`${grub_probe} --device ${GRUB_DEVICE} --target=fs 2>/dev/null || true`
> +LINUX_ROOT_STAT=`stat -f --printf=%T / || true`
> +
> +if [ "x${LINUX_ROOT_FS}" = xbtrfs -o "x${LINUX_ROOT_STAT}" = xbtrfs ]; then
>     rootsubvol="`make_system_path_relative_to_its_root /`"
>     rootsubvol="${rootsubvol#/}"
>     if [ "x${rootsubvol}" != x ]; then
> @@ -76,6 +78,10 @@
>       GRUB_CMDLINE_EXTRA="$GRUB_CMDLINE_EXTRA crashkernel=384M-2G:64M,2G-:128M"
>   fi
>
> +if [ "x${LINUX_ROOT_FS}" = xzfs ]; then
> +  GRUB_CMDLINE_LINUX="boot=zfs \$bootfs ${GRUB_CMDLINE_LINUX}"
> +fi
> +
>   linux_entry ()
>   {
>     os="$1"
> @@ -114,6 +120,12 @@
>       fi
>       printf '%s\n' "${prepare_boot_cache}"
>     fi
> +  if [ "x${LINUX_ROOT_FS}" = xzfs ]; then
> +    cat<<  EOF
> +	insmod zfsinfo
> +	zfs-bootfs (\$root) bootfs
This makes 3 wrong assumptions in a row:
- / and /boot may be different.
- Linux may be in a non-root subvolume. Then the subvolid points to 
wrong one.
- / may be unaccessible to GRUB altogether.
In short: this command line part has to be generated on grub-mkconfig 
time and have a stable representation. I'd recommend UUID and subvolume 
name.
> +EOF
> +  fi
>     if [ "x$5" != "xquiet" ]; then
>       message="$(gettext_printf "Loading Linux %s ..." ${version})"
>       cat<<  EOF
> Index: grub/util/getroot.c
> ===================================================================
> --- grub.orig/util/getroot.c	2012-01-24 23:44:04.105772000 -0600
> +++ grub/util/getroot.c	2012-01-27 20:48:50.875006000 -0600
> @@ -52,6 +52,8 @@
>   #endif
>
>   #ifdef __linux__
> +# include<stdio.h>
> +# include<mntent.h>
>   # include<sys/types.h>
>   # include<sys/wait.h>
>   #endif
> @@ -115,6 +117,8 @@
>     return path;
>   }
>
> +static char *find_device_from_pool (const char *poolname);
> +
>   #ifdef __linux__
>
>   #define ESCAPED_PATH_MAX (4 * PATH_MAX)
> @@ -263,7 +267,32 @@
>         if (!*entries[i].device)
>   	continue;
>
> -      ret = strdup (entries[i].device);
> +      if (strcmp (entries[i].fstype, "zfs") == 0)
> +	{
> +	  char *poolname = entries[i].device;
> +	  char *poolname_i = poolname;
> +	  char *poolname_j = poolname;
> +	  /* Replace \040 with a space.  Cut at the first slash. */
> +	  while (*poolname_j)
> +	    {
> +	      if (*poolname_j == '/')
> +		break;
> +	      if (strncmp (poolname_j, "\\040", 4) == 0)
> +		{
> +		  *poolname_i = ' ';
> +		  poolname_i++;
> +		  poolname_j += 4;
> +		  continue;
> +		}
> +	      *poolname_i = *poolname_j;
> +	      poolname_i++;
> +	      poolname_j++;
> +	    }
> +	  *poolname_i = '\0';
> +	  ret = find_device_from_pool (poolname);
> +	}
> +      else
> +	ret = strdup (entries[i].device);
This is the same as what I've done for zfs-fuse except that:
- unescaping is done before here since already many revisions.
- It forgets subvolume handling.
>         if (relroot)
>   	*relroot = strdup (entries[i].enc_root);
>         break;
> @@ -280,13 +309,25 @@
>   static char *
>   find_root_device_from_libzfs (const char *dir)
>   {
> -  char *device = NULL;
> +  char *device;
>     char *poolname;
>     char *poolfs;
>
>     grub_find_zpool_from_dir (dir,&poolname,&poolfs);
>     if (! poolname)
>       return NULL;
> +  if (poolfs)
> +    free (poolfs);
> +
> +  device = find_device_from_pool(poolname);
> +  free(poolname);
> +  return device;
> +}
> +
> +static char *
> +find_device_from_pool (const char *poolname)
> +{
> +  char *device = NULL;
>   
Same as my fuse work.
>   #if defined(HAVE_LIBZFS)&&  defined(HAVE_LIBNVPAIR)
>     {
> @@ -357,7 +398,7 @@
>       char cksum[257], notes[257];
>       unsigned int dummy;
>
> -    cmd = xasprintf ("zpool status %s", poolname);
> +    cmd = xasprintf ("zpool status \"%s\"", poolname);
>       fp = popen (cmd, "r");
>       free (cmd);
>
> @@ -382,7 +423,10 @@
>   		st++;
>   	      break;
>   	    case 1:
> -	      if (!strcmp (name, poolname))
> +	      /* Use strncmp() because poolname can technically have trailing
> +	         spaces, which the sscanf() above will not catch.  Since we've
> +	         asked about this pool specifically, this should be safe. */
> +	      if (!strncmp (name, poolname, strlen(name)))
>   		st++;
>   	      break;
>   	    case 2:
> @@ -395,17 +439,71 @@
>   	
>   	free (line);
>         }
> +
> +#ifdef __linux__
> +    /* The name returned by zpool isn't necessarily directly under /dev. */
> +    {
> +      const char *disk_naming_schemes[] = {
> +	"/dev/disk/by-id/%s",
> +	"/dev/disk/by-path/%s",
> +	"/dev/disk/by-uuid/%s",
> +	"/dev/disk/by-partuuid/%s",
> +	"/dev/disk/by-label/%s",
> +	"/dev/disk/by-partlabel/%s",
> +	"/dev/%s",
Such a list is difficult to maintain. It's better to scan /dev/disk if 
/dev/<name> is unavailable.

+    mnttab = fopen ("/proc/mounts", "r");
+    if (! mnttab)
+      mnttab = fopen ("/etc/mtab", "r");
+    if (! mnttab)
+      return;
/etc/mtab is unreliable. As for /proc/mounts : is there a reason to suppose that /proc/mounts would work when /proc/self/mountinfo doesn't

>
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> https://lists.gnu.org/mailman/listinfo/grub-devel


-- 
Regards
Vladimir 'φ-coder/phcoder' Serbinenko


[-- Attachment #2: zfs.diff --]
[-- Type: text/x-diff, Size: 40652 bytes --]

=== modified file 'include/grub/emu/getroot.h'
--- include/grub/emu/getroot.h	2011-04-25 12:52:07 +0000
+++ include/grub/emu/getroot.h	2012-01-27 15:41:19 +0000
@@ -30,7 +30,7 @@
 };
 
 char *grub_find_device (const char *dir, dev_t dev);
-char *grub_guess_root_device (const char *dir);
+char **grub_guess_root_devices (const char *dir);
 int grub_util_get_dev_abstraction (const char *os_dev);
 char *grub_util_get_grub_dev (const char *os_dev);
 char *grub_make_system_path_relative_to_its_root (const char *path);

=== modified file 'include/grub/emu/misc.h'
--- include/grub/emu/misc.h	2011-12-13 13:51:41 +0000
+++ include/grub/emu/misc.h	2012-01-27 15:23:40 +0000
@@ -80,6 +80,4 @@
 int grub_device_mapper_supported (void);
 #endif
 
-char *grub_find_root_device_from_mountinfo (const char *dir, char **relroot);
-
 #endif /* GRUB_EMU_MISC_H */

=== modified file 'util/getroot.c'
--- util/getroot.c	2011-12-23 18:25:24 +0000
+++ util/getroot.c	2012-01-27 16:57:59 +0000
@@ -115,6 +115,149 @@
   return path;
 }
 
+static char **
+find_root_devices_from_poolname (char *poolname)
+{
+  char **devices = 0;
+  size_t ndevices = 0;
+  size_t devices_allocated = 0;
+
+#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR)
+  zpool_handle_t *zpool;
+  libzfs_handle_t *libzfs;
+  nvlist_t *config, *vdev_tree;
+  nvlist_t **children, **path;
+  unsigned int nvlist_count;
+  unsigned int i;
+  char *device = 0;
+
+  libzfs = grub_get_libzfs_handle ();
+  if (! libzfs)
+    return NULL;
+
+  zpool = zpool_open (libzfs, poolname);
+  config = zpool_get_config (zpool, NULL);
+
+  if (nvlist_lookup_nvlist (config, "vdev_tree", &vdev_tree) != 0)
+    error (1, errno, "nvlist_lookup_nvlist (\"vdev_tree\")");
+
+  if (nvlist_lookup_nvlist_array (vdev_tree, "children", &children, &nvlist_count) != 0)
+    error (1, errno, "nvlist_lookup_nvlist_array (\"children\")");
+  assert (nvlist_count > 0);
+
+  while (nvlist_lookup_nvlist_array (children[0], "children",
+				     &children, &nvlist_count) == 0)
+    assert (nvlist_count > 0);
+
+  for (i = 0; i < nvlist_count; i++)
+    {
+      if (nvlist_lookup_string (children[i], "path", &device) != 0)
+	error (1, errno, "nvlist_lookup_string (\"path\")");
+
+      struct stat st;
+      if (stat (device, &st) == 0)
+	{
+#ifdef __sun__
+	  if (grub_memcmp (device, "/dev/dsk/", sizeof ("/dev/dsk/") - 1)
+	      == 0)
+	    device = xasprintf ("/dev/rdsk/%s",
+				device + sizeof ("/dev/dsk/") - 1);
+	  else if (grub_memcmp (device, "/devices", sizeof ("/devices") - 1)
+		   == 0
+		   && grub_memcmp (device + strlen (device) - 4,
+				   ",raw", 4) != 0)
+	    device = xasprintf ("%s,raw", device);
+	  else
+#endif
+	    device = xstrdup (device);
+	  if (ndevices >= devices_allocated)
+	    {
+	      devices_allocated = 2 * (devices_allocated + 8);
+	      devices = xrealloc (devices, sizeof (devices[0])
+				  * devices_allocated);
+	    }
+	  devices[ndevices++] = device;
+	}
+
+      device = NULL;
+    }
+
+  zpool_close (zpool);
+#else
+  char *cmd;
+  FILE *fp;
+  int ret;
+  char *line;
+  size_t len;
+  int st;
+
+  char name[PATH_MAX + 1], state[257], readlen[257], writelen[257];
+  char cksum[257], notes[257];
+  unsigned int dummy;
+
+  cmd = xasprintf ("zpool status %s", poolname);
+  fp = popen (cmd, "r");
+  free (cmd);
+
+  st = 0;
+  while (1)
+    {
+      line = NULL;
+      ret = getline (&line, &len, fp);
+      if (ret == -1)
+	break;
+	
+      if (sscanf (line, " %s %256s %256s %256s %256s %256s",
+		  name, state, readlen, writelen, cksum, notes) >= 5)
+	switch (st)
+	  {
+	  case 0:
+	    if (!strcmp (name, "NAME")
+		&& !strcmp (state, "STATE")
+		&& !strcmp (readlen, "READ")
+		&& !strcmp (writelen, "WRITE")
+		&& !strcmp (cksum, "CKSUM"))
+	      st++;
+	    break;
+	  case 1:
+	    if (!strcmp (name, poolname))
+	      st++;
+	    break;
+	  case 2:
+	    if (strcmp (name, "mirror") && !sscanf (name, "mirror-%u", &dummy)
+		&& !sscanf (name, "raidz%u", &dummy)
+		&& !strcmp (state, "ONLINE"))
+	      {
+		char *tmp;
+		if (ndevices >= devices_allocated)
+		  {
+		    devices_allocated = 2 * (devices_allocated + 8);
+		    devices = xrealloc (devices, sizeof (devices[0])
+					* devices_allocated);
+		  }
+		devices[ndevices++] = xasprintf ("/dev/%s", name);
+	      }
+	    break;
+	  }
+	
+      free (line);
+    }
+
+  pclose (fp);
+#endif
+  if (devices)
+    {
+      if (ndevices >= devices_allocated)
+	{
+	  devices_allocated = 2 * (devices_allocated + 8);
+	  devices = xrealloc (devices, sizeof (devices[0])
+			      * devices_allocated);
+	}
+      devices[ndevices++] = 0;
+    }
+  return devices;
+}
+
 #ifdef __linux__
 
 #define ESCAPED_PATH_MAX (4 * PATH_MAX)
@@ -154,13 +297,13 @@
   *optr = 0;
 }
 
-char *
-grub_find_root_device_from_mountinfo (const char *dir, char **relroot)
+static char **
+grub_find_root_devices_from_mountinfo (const char *dir, char **relroot)
 {
   FILE *fp;
   char *buf = NULL;
   size_t len = 0;
-  char *ret = NULL;
+  char **ret = NULL;
   int entry_len = 0, entry_max = 4;
   struct mountinfo_entry *entries;
   struct mountinfo_entry parent_entry = { 0, 0, 0, "", "", "", "" };
@@ -263,9 +406,33 @@
       if (!*entries[i].device)
 	continue;
 
-      ret = strdup (entries[i].device);
-      if (relroot)
-	*relroot = strdup (entries[i].enc_root);
+      if (grub_strcmp (entries[i].fstype, "fuse.zfs") == 0)
+	{
+	  char *slash;
+	  slash = strchr (entries[i].device, '/');
+	  if (slash)
+	    *slash = 0;
+	  ret = find_root_devices_from_poolname (entries[i].device);
+	  if (slash)
+	    *slash = '/';
+	  if (relroot)
+	    {
+	      if (!slash)
+		*relroot = xasprintf ("/@%s", entries[i].enc_root);
+	      else if (strchr (slash + 1, '@'))
+		*relroot = xasprintf ("/%s%s", slash + 1, entries[i].enc_root);
+	      else
+		*relroot = xasprintf ("/%s@%s", slash + 1, entries[i].enc_root);
+	    }
+	}
+      else
+	{
+	  ret = xmalloc (2 * sizeof (ret[0]));
+	  ret[0] = strdup (entries[i].device);
+	  ret[1] = 0;
+	  if (relroot)
+	    *relroot = strdup (entries[i].enc_root);
+	}
       break;
     }
 
@@ -277,10 +444,10 @@
 
 #endif /* __linux__ */
 
-static char *
-find_root_device_from_libzfs (const char *dir)
+static char **
+find_root_devices_from_libzfs (const char *dir)
 {
-  char *device = NULL;
+  char **device = NULL;
   char *poolname;
   char *poolfs;
 
@@ -288,119 +455,7 @@
   if (! poolname)
     return NULL;
 
-#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR)
-  {
-    zpool_handle_t *zpool;
-    libzfs_handle_t *libzfs;
-    nvlist_t *config, *vdev_tree;
-    nvlist_t **children, **path;
-    unsigned int nvlist_count;
-    unsigned int i;
-
-    libzfs = grub_get_libzfs_handle ();
-    if (! libzfs)
-      return NULL;
-
-    zpool = zpool_open (libzfs, poolname);
-    config = zpool_get_config (zpool, NULL);
-
-    if (nvlist_lookup_nvlist (config, "vdev_tree", &vdev_tree) != 0)
-      error (1, errno, "nvlist_lookup_nvlist (\"vdev_tree\")");
-
-    if (nvlist_lookup_nvlist_array (vdev_tree, "children", &children, &nvlist_count) != 0)
-      error (1, errno, "nvlist_lookup_nvlist_array (\"children\")");
-    assert (nvlist_count > 0);
-
-    while (nvlist_lookup_nvlist_array (children[0], "children",
-				       &children, &nvlist_count) == 0)
-      assert (nvlist_count > 0);
-
-    for (i = 0; i < nvlist_count; i++)
-      {
-	if (nvlist_lookup_string (children[i], "path", &device) != 0)
-	  error (1, errno, "nvlist_lookup_string (\"path\")");
-
-	struct stat st;
-	if (stat (device, &st) == 0)
-	  {
-#ifdef __sun__
-	    if (grub_memcmp (device, "/dev/dsk/", sizeof ("/dev/dsk/") - 1)
-		== 0)
-	      device = xasprintf ("/dev/rdsk/%s",
-				  device + sizeof ("/dev/dsk/") - 1);
-	    else if (grub_memcmp (device, "/devices", sizeof ("/devices") - 1)
-		     == 0
-		     && grub_memcmp (device + strlen (device) - 4,
-				     ",raw", 4) != 0)
-	      device = xasprintf ("%s,raw", device);
-	    else
-#endif
-	      device = xstrdup (device);
-	    break;
-	  }
-
-	device = NULL;
-      }
-
-    zpool_close (zpool);
-  }
-#else
-  {
-    char *cmd;
-    FILE *fp;
-    int ret;
-    char *line;
-    size_t len;
-    int st;
-
-    char name[PATH_MAX + 1], state[257], readlen[257], writelen[257];
-    char cksum[257], notes[257];
-    unsigned int dummy;
-
-    cmd = xasprintf ("zpool status %s", poolname);
-    fp = popen (cmd, "r");
-    free (cmd);
-
-    st = 0;
-    while (st < 3)
-      {
-	line = NULL;
-	ret = getline (&line, &len, fp);
-	if (ret == -1)
-	  goto fail;
-	
-	if (sscanf (line, " %s %256s %256s %256s %256s %256s",
-		    name, state, readlen, writelen, cksum, notes) >= 5)
-	  switch (st)
-	    {
-	    case 0:
-	      if (!strcmp (name, "NAME")
-		  && !strcmp (state, "STATE")
-		  && !strcmp (readlen, "READ")
-		  && !strcmp (writelen, "WRITE")
-		  && !strcmp (cksum, "CKSUM"))
-		st++;
-	      break;
-	    case 1:
-	      if (!strcmp (name, poolname))
-		st++;
-	      break;
-	    case 2:
-	      if (strcmp (name, "mirror") && !sscanf (name, "mirror-%u", &dummy)
-		  && !sscanf (name, "raidz%u", &dummy)
-		  && !strcmp (state, "ONLINE"))
-		st++;
-	      break;
-	    }
-	
-	free (line);
-      }
-    device = xasprintf ("/dev/%s", name);
-
- fail:
-    pclose (fp);
-  }
-#endif
+  device = find_root_devices_from_poolname (poolname);
 
   free (poolname);
   if (poolfs)
@@ -641,10 +696,10 @@
 
 #endif /* __CYGWIN__ */
 
-char *
-grub_guess_root_device (const char *dir)
+char **
+grub_guess_root_devices (const char *dir)
 {
-  char *os_dev = NULL;
+  char **os_dev = NULL;
 #ifdef __GNU__
   file_t file;
   mach_port_t *ports;
@@ -678,9 +733,11 @@
   if (data[name_len - 1] != '\0')
     grub_util_error (_("Storage name for `%s' not NUL-terminated"), dir);
 
-  os_dev = xmalloc (strlen ("/dev/") + data_len);
-  memcpy (os_dev, "/dev/", strlen ("/dev/"));
-  memcpy (os_dev + strlen ("/dev/"), data, data_len);
+  os_dev = xmalloc (2 * sizeof (os_dev[0]));
+  os_dev[0] = xmalloc (strlen ("/dev/") + data_len);
+  memcpy (os_dev[0], "/dev/", strlen ("/dev/"));
+  memcpy (os_dev[0] + strlen ("/dev/"), data, data_len);
+  os_dev[1] = 0;
 
   if (ports && num_ports > 0)
     {
@@ -707,48 +764,56 @@
 
 #ifdef __linux__
   if (!os_dev)
-    os_dev = grub_find_root_device_from_mountinfo (dir, NULL);
+    os_dev = grub_find_root_devices_from_mountinfo (dir, NULL);
 #endif /* __linux__ */
 
   if (!os_dev)
-    os_dev = find_root_device_from_libzfs (dir);
-
-  if (os_dev)
-    {
-      char *tmp = os_dev;
-      os_dev = canonicalize_file_name (os_dev);
-      free (tmp);
-    }
-
-  if (os_dev)
-    {
-      int dm = (strncmp (os_dev, "/dev/dm-", sizeof ("/dev/dm-") - 1) == 0);
-      int root = (strcmp (os_dev, "/dev/root") == 0);
-      if (!dm && !root)
+    os_dev = find_root_devices_from_libzfs (dir);
+
+  if (os_dev)
+    {
+      char **cur;
+      for (cur = os_dev; *cur; cur++)
+	{
+	  char *tmp = *cur;
+	  int root, dm;
+	  *cur = canonicalize_file_name (*cur);
+	  free (tmp);
+	  root = (strcmp (*cur, "/dev/root") == 0);
+	  dm = (strncmp (*cur, "/dev/dm-", sizeof ("/dev/dm-") - 1) == 0);
+	  if (!dm && !root)
+	    continue;
+	  if (stat (*cur, &st) < 0)
+	    break;
+	  free (*cur);
+	  dev = st.st_rdev;
+	  *cur = grub_find_device (dm ? "/dev/mapper" : "/dev", dev);
+	}
+      if (!*cur)
 	return os_dev;
-      if (stat (os_dev, &st) >= 0)
-	{
-	  free (os_dev);
-	  dev = st.st_rdev;
-	  return grub_find_device (dm ? "/dev/mapper" : "/dev", dev);
-	}
+      for (cur = os_dev; *cur; cur++)
+	free (*cur);
       free (os_dev);
+      os_dev = 0;
     }
 
   if (stat (dir, &st) < 0)
     grub_util_error (_("cannot stat `%s'"), dir);
 
   dev = st.st_dev;
+
+  os_dev = xmalloc (2 * sizeof (os_dev[0]));
   
 #ifdef __CYGWIN__
   /* Cygwin specific function.  */
-  os_dev = grub_find_device (dir, dev);
+  os_dev[0] = grub_find_device (dir, dev);
 
 #else
 
   /* This might be truly slow, but is there any better way?  */
-  os_dev = grub_find_device ("/dev", dev);
+  os_dev[0] = grub_find_device ("/dev", dev);
 #endif
+  os_dev[1] = 0;
 #endif /* !__GNU__ */
 
   return os_dev;
@@ -1565,7 +1630,7 @@
 #ifdef __linux__
 	      {
 		char *bind;
-		grub_free (grub_find_root_device_from_mountinfo (buf2, &bind));
+		grub_free (grub_find_root_devices_from_mountinfo (buf2, &bind));
 		if (bind && bind[0] && bind[1])
 		  {
 		    buf3 = bind;
@@ -1598,7 +1663,7 @@
 #ifdef __linux__
   {
     char *bind;
-    grub_free (grub_find_root_device_from_mountinfo (buf2, &bind));
+    grub_free (grub_find_root_devices_from_mountinfo (buf2, &bind));
     if (bind && bind[0] && bind[1])
       {
 	char *temp = buf3;

=== modified file 'util/grub-install.in'
--- util/grub-install.in	2012-01-27 12:12:00 +0000
+++ util/grub-install.in	2012-01-27 18:29:29 +0000
@@ -473,7 +473,7 @@
 fi
 
 # Create the core image. First, auto-detect the filesystem module.
-fs_module="`"$grub_probe" --device-map="${device_map}" --target=fs --device "${grub_device}"`"
+fs_module="`echo "${grub_device}" | xargs "$grub_probe" --device-map="${device_map}" --target=fs --device `"
 if test "x$fs_module" = x ; then
     echo "Auto-detection of a filesystem of ${grub_device} failed." 1>&2
     echo "Try with --recheck." 1>&2
@@ -485,7 +485,7 @@
 # this command is allowed to fail (--target=fs already grants us that the
 # filesystem will be accessible).
 partmap_module=
-for x in `"$grub_probe" --device-map="${device_map}" --target=partmap --device "${grub_device}" 2> /dev/null`; do
+for x in `echo "${grub_device}" | xargs "$grub_probe" --device-map="${device_map}" --target=partmap --device 2> /dev/null`; do
    case "$x" in
        netbsd | openbsd) 
 	   partmap_module="$partmap_module part_bsd";;
@@ -496,7 +496,7 @@
 done
 
 # Device abstraction module, if any (lvm, raid).
-devabstraction_module="`"$grub_probe" --device-map="${device_map}" --target=abstraction --device "${grub_device}"`"
+devabstraction_module="`echo "${grub_device}" | xargs "$grub_probe" --device-map="${device_map}" --target=abstraction --device`"
 
 if [ "x$disk_module" = xata ]; then
     disk_module=pata
@@ -538,14 +538,14 @@
       fi
       install_drive="`echo "${install_drive}" | sed -e 's/^(\(\([^,\\\\]\|\\\\\\\\\|\\\\,\)*\)\(\(,[a-zA-Z0-9]*\)*\))$/\1/'`"
     fi
-    grub_drive="`"$grub_probe" --device-map="${device_map}" --target=drive --device "${grub_device}"`" || exit 1
+    grub_drive="`echo "${grub_device}" | xargs "$grub_probe" --device-map="${device_map}" --target=drive --device`" || exit 1
 
     # Strip partition number
     grub_partition="`echo "${grub_drive}" | sed -e 's/^(\(\([^,\\\\]\|\\\\\\\\\|\\\\,\)*\)\(\(,[a-zA-Z0-9]*\)*\))$/\3/'`"
     grub_drive="`echo "${grub_drive}" | sed -e 's/^(\(\([^,\\\\]\|\\\\\\\\\|\\\\,\)*\)\(\(,[a-zA-Z0-9]*\)*\))$/\1/'`"
     if ([ "x$disk_module" != x ] && [ "x$disk_module" != xbiosdisk ]) || [ "x${grub_drive}" != "x${install_drive}" ] || ([ "x$platform" != xefi ] && [ "x$platform" != xpc ] && [ x"${platform}" != x"ieee1275" ]); then
         # generic method (used on coreboot and ata mod)
-        uuid="`"$grub_probe" --device-map="${device_map}" --target=fs_uuid --device "${grub_device}"`"
+        uuid="`echo "${grub_device}" | xargs "$grub_probe" --device-map="${device_map}" --target=fs_uuid --device`"
         if [ "x${uuid}" = "x" ] ; then
           if [ "x$platform" != xefi ] && [ "x$platform" != xpc ] && [ x"${platform}" != x"ieee1275" ]; then
              echo "UUID needed with $platform, but the filesystem containing ${grubdir} does not support UUIDs." 1>&2
@@ -559,15 +559,15 @@
         fi
 
 	if [ x"$disk_module" != x ] && [ x"$disk_module" != xbiosdisk ]; then
-            hints="`"$grub_probe" --device-map="${device_map}" --target=baremetal_hints --device "${grub_device}"`"
+            hints="`echo "${grub_device}" | xargs "$grub_probe" --device-map="${device_map}" --target=baremetal_hints --device`"
 	elif [ x"$platform" = xpc ]; then
-            hints="`"$grub_probe" --device-map="${device_map}" --target=bios_hints --device "${grub_device}"`"
+            hints="`echo "${grub_device}" | xargs "$grub_probe" --device-map="${device_map}" --target=bios_hints --device`"
 	elif [ x"$platform" = xefi ]; then
-            hints="`"$grub_probe" --device-map="${device_map}" --target=efi_hints --device "${grub_device}"`"
+            hints="`echo "${grub_device}" | xargs "$grub_probe" --device-map="${device_map}" --target=efi_hints --device`"
 	elif [ x"$platform" = xieee1275 ]; then
-            hints="`"$grub_probe" --device-map="${device_map}" --target=ieee1275_hints --device "${grub_device}"`"
+            hints="`echo "${grub_device}" | xargs "$grub_probe" --device-map="${device_map}" --target=ieee1275_hints --device`"
 	elif [ x"$platform" = xloongson ] || [ x"$platform" = xqemu ] || [ x"$platform" = xcoreboot ] || [ x"$platform" = xmultiboot ] || [ x"$platform" = xqemu-mips ]; then
-            hints="`"$grub_probe" --device-map="${device_map}" --target=baremetal_hints --device "${grub_device}"`"
+            hints="`echo "${grub_device}" | xargs "$grub_probe" --device-map="${device_map}" --target=baremetal_hints --device`"
 	else
             echo "No hints available for your platform. Expect reduced performance"
 	    hints=
@@ -587,7 +587,7 @@
     fi
 else
     if [ x$GRUB_CRYPTODISK_ENABLE = xy ]; then
-	for uuid in "`"${grub_probe}" --device "${grub_device}" --target=cryptodisk_uuid`"; do
+	for uuid in "`echo "${grub_device}" | xargs "${grub_probe}"  --target=cryptodisk_uuid --device`"; do
 	    echo "cryptomount -u $uuid" >> "${grubdir}/load.cfg"
 	done
 	config_opt="-c ${grubdir}/load.cfg "

=== modified file 'util/grub-probe.c'
--- util/grub-probe.c	2012-01-23 18:33:40 +0000
+++ util/grub-probe.c	2012-01-27 18:16:06 +0000
@@ -300,299 +300,343 @@
     printf ("raid6rec ");
 }
 
+static inline void
+delim (int zdelim)
+{
+  if (zdelim)
+    putchar ('\0');
+  else
+    putchar ('\n');
+}
+
 static void
-probe (const char *path, char *device_name)
+probe (const char *path, char **device_names, int zdelim)
 {
-  char *drive_name = NULL;
+  char **drives_names = NULL;
+  char **curdev, **curdrive;
   char *grub_path = NULL;
-  char *filebuf_via_grub = NULL, *filebuf_via_sys = NULL;
-  grub_device_t dev = NULL;
-  grub_fs_t fs;
+  int ndev = 0;
 
-  if (path == NULL)
-    {
-#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__sun__)
-      if (! grub_util_check_char_device (device_name))
-        grub_util_error (_("%s is not a character device"), device_name);
-#else
-      if (! grub_util_check_block_device (device_name))
-        grub_util_error (_("%s is not a block device"), device_name);
-#endif
-    }
-  else
+  if (path != NULL)
     {
       grub_path = canonicalize_file_name (path);
-      device_name = grub_guess_root_device (grub_path);
+      device_names = grub_guess_root_devices (grub_path);
+      free (grub_path);
     }
 
-  if (! device_name)
+  if (! device_names)
     grub_util_error (_("cannot find a device for %s (is /dev mounted?)"), path);
 
   if (print == PRINT_DEVICE)
     {
-      printf ("%s\n", device_name);
-      goto end;
-    }
-
-  drive_name = grub_util_get_grub_dev (device_name);
-  if (! drive_name)
-    grub_util_error (_("cannot find a GRUB drive for %s.  Check your device.map"),
-		     device_name);
-
-  if (print == PRINT_DRIVE)
-    {
-      printf ("(%s)\n", drive_name);
-      goto end;
-    }
-
-  grub_util_info ("opening %s", drive_name);
-  dev = grub_device_open (drive_name);
-  if (! dev)
-    grub_util_error ("%s", _(grub_errmsg));
-
-  if (print == PRINT_HINT_STR)
-    {
-      const char *osdev = grub_util_biosdisk_get_osdev (dev->disk);
-      const char *orig_path = grub_util_devname_to_ofpath (osdev);
-      char *biosname, *bare, *efi;
-      const char *map;
-
-      if (orig_path)
-	{
+      for (curdev = device_names; *curdev; curdev++)
+	{
+	  printf ("%s", *curdev);
+	  delim (zdelim);
+	}
+      return;
+    }
+
+  for (curdev = device_names; *curdev; curdev++)
+    {
+      grub_util_pull_device (*curdev);
+      ndev++;
+    }
+  
+  drives_names = xmalloc (sizeof (drives_names[0]) * (ndev + 1)); 
+
+  for (curdev = device_names, curdrive = drives_names; *curdev; curdev++,
+       curdrive++)
+    {
+      *curdrive = grub_util_get_grub_dev (*curdev);
+      if (! *curdrive)
+	grub_util_error (_("cannot find a GRUB drive for %s.  Check your device.map"),
+			 *curdev);
+    }
+  *curdrive = 0;
+
+  if (print == PRINT_FS || print == PRINT_FS_UUID
+      || print == PRINT_FS_LABEL)
+    {
+      grub_device_t dev = NULL;
+      grub_fs_t fs;
+
+      grub_util_info ("opening %s", drives_names[0]);
+      dev = grub_device_open (drives_names[0]);
+      if (! dev)
+	grub_util_error ("%s", _(grub_errmsg));
+      
+      fs = grub_fs_probe (dev);
+      if (! fs)
+	grub_util_error ("%s", _(grub_errmsg));
+
+      if (print == PRINT_FS)
+	{
+	  printf ("%s", fs->name);
+	  delim (zdelim);
+	}
+      else if (print == PRINT_FS_UUID)
+	{
+	  char *uuid;
+	  if (! fs->uuid)
+	    grub_util_error (_("%s does not support UUIDs"), fs->name);
+
+	  if (fs->uuid (dev, &uuid) != GRUB_ERR_NONE)
+	    grub_util_error ("%s", grub_errmsg);
+
+	  printf ("%s", uuid);
+	  delim (zdelim);
+	}
+      else if (print == PRINT_FS_LABEL)
+	{
+	  char *label;
+	  if (! fs->label)
+	    grub_util_error (_("%s does not support labels"), fs->name);
+
+	  if (fs->label (dev, &label) != GRUB_ERR_NONE)
+	    grub_util_error ("%s", _(grub_errmsg));
+
+	  printf ("%s", label);
+	  delim (zdelim);
+	}
+      goto end;
+    }
+
+  for (curdrive = drives_names, curdev = device_names; *curdrive;
+       curdrive++, curdev++)
+    {
+      grub_device_t dev = NULL;
+
+      grub_util_info ("opening %s", *curdrive);
+      dev = grub_device_open (*curdrive);
+      if (! dev)
+	grub_util_error ("%s", _(grub_errmsg));
+
+      if (print == PRINT_HINT_STR)
+	{
+	  const char *osdev = grub_util_biosdisk_get_osdev (dev->disk);
+	  const char *orig_path = grub_util_devname_to_ofpath (osdev);
+	  char *biosname, *bare, *efi;
+	  const char *map;
+
+	  if (orig_path)
+	    {
+	      char *ofpath = escape_of_path (orig_path);
+	      printf ("--hint-ieee1275='");
+	      print_full_name (ofpath, dev);
+	      printf ("' ");
+	      free (ofpath);
+	    }
+
+	  biosname = guess_bios_drive (*curdev);
+	  if (biosname)
+	    {
+	      printf ("--hint-bios=");
+	      print_full_name (biosname, dev);
+	      printf (" ");
+	    }
+	  free (biosname);
+
+	  efi = guess_efi_drive (*curdev);
+	  if (efi)
+	    {
+	      printf ("--hint-efi=");
+	      print_full_name (efi, dev);
+	      printf (" ");
+	    }
+	  free (efi);
+
+	  bare = guess_baremetal_drive (*curdev);
+	  if (bare)
+	    {
+	      printf ("--hint-baremetal=");
+	      print_full_name (bare, dev);
+	      printf (" ");
+	    }
+	  free (bare);
+
+	  /* FIXME: Add ARC hint.  */
+
+	  map = grub_util_biosdisk_get_compatibility_hint (dev->disk);
+	  if (map)
+	    {
+	      printf ("--hint='");
+	      print_full_name (map, dev);
+	      printf ("' ");
+	    }
+	  printf ("\n");
+
+	  grub_device_close (dev);
+	  continue;
+	}
+
+      if (print == PRINT_COMPATIBILITY_HINT)
+	{
+	  const char *map;
+	  char *biosname;
+	  map = grub_util_biosdisk_get_compatibility_hint (dev->disk);
+	  if (map)
+	    {
+	      print_full_name (map, dev);
+	      delim (zdelim);
+	      grub_device_close (dev);
+	      /* Compatibility hint is one device only.  */
+	      break;
+	    }
+	  biosname = guess_bios_drive (*curdev);
+	  if (biosname)
+	    print_full_name (biosname, dev);
+	  delim (zdelim);
+	  free (biosname);
+	  grub_device_close (dev);
+	  /* Compatibility hint is one device only.  */
+	  if (biosname)
+	    break;
+	  continue;
+	}
+
+      if (print == PRINT_BIOS_HINT)
+	{
+	  char *biosname;
+	  biosname = guess_bios_drive (*curdev);
+	  if (biosname)
+	    print_full_name (biosname, dev);
+	  delim (zdelim);
+	  free (biosname);
+	  grub_device_close (dev);
+	  continue;
+	}
+      if (print == PRINT_IEEE1275_HINT)
+	{
+	  const char *osdev = grub_util_biosdisk_get_osdev (dev->disk);
+	  const char *orig_path = grub_util_devname_to_ofpath (osdev);
 	  char *ofpath = escape_of_path (orig_path);
-	  printf ("--hint-ieee1275='");
+	  const char *map;
+
+	  map = grub_util_biosdisk_get_compatibility_hint (dev->disk);
+	  if (map)
+	    {
+	      printf (" ");
+	      print_full_name (map, dev);
+	    }
+
+	  printf (" ");
 	  print_full_name (ofpath, dev);
-	  printf ("' ");
+
+	  delim (zdelim);
 	  free (ofpath);
-	}
-
-      biosname = guess_bios_drive (device_name);
-      if (biosname)
-	{
-	  printf ("--hint-bios=");
-	  print_full_name (biosname, dev);
-	  printf (" ");
-	}
-      free (biosname);
-
-      efi = guess_efi_drive (device_name);
-      if (efi)
-	{
-	  printf ("--hint-efi=");
-	  print_full_name (efi, dev);
-	  printf (" ");
-	}
-      free (efi);
-
-      bare = guess_baremetal_drive (device_name);
-      if (bare)
-	{
-	  printf ("--hint-baremetal=");
-	  print_full_name (bare, dev);
-	  printf (" ");
-	}
-      free (bare);
-
-      /* FIXME: Add ARC hint.  */
-
-      map = grub_util_biosdisk_get_compatibility_hint (dev->disk);
-      if (map)
-	{
-	  printf ("--hint='");
-	  print_full_name (map, dev);
-	  printf ("' ");
-	}
-      printf ("\n");
-
-      goto end;
-    }
-
-  if (print == PRINT_COMPATIBILITY_HINT)
-    {
-      const char *map;
-      char *biosname;
-      map = grub_util_biosdisk_get_compatibility_hint (dev->disk);
-      if (map)
-	{
-	  print_full_name (map, dev);
-	  printf ("\n");
-	  goto end;
-	}
-      biosname = guess_bios_drive (device_name);
-      if (biosname)
-	print_full_name (biosname, dev);
-      printf ("\n");
-      free (biosname);
-      goto end;
-    }
-
-  if (print == PRINT_BIOS_HINT)
-    {
-      char *biosname;
-      biosname = guess_bios_drive (device_name);
-      if (biosname)
-	print_full_name (biosname, dev);
-      printf ("\n");
-      free (biosname);
-      goto end;
-    }
-  if (print == PRINT_IEEE1275_HINT)
-    {
-      const char *osdev = grub_util_biosdisk_get_osdev (dev->disk);
-      const char *orig_path = grub_util_devname_to_ofpath (osdev);
-      char *ofpath = escape_of_path (orig_path);
-      const char *map;
-
-      map = grub_util_biosdisk_get_compatibility_hint (dev->disk);
-      if (map)
-	{
-	  printf (" ");
-	  print_full_name (map, dev);
-	}
-
-      printf (" ");
-      print_full_name (ofpath, dev);
-
-      printf ("\n");
-      free (ofpath);
-      goto end;
-    }
-  if (print == PRINT_EFI_HINT)
-    {
-      char *biosname;
-      char *name;
-      const char *map;
-      biosname = guess_efi_drive (device_name);
-
-      map = grub_util_biosdisk_get_compatibility_hint (dev->disk);
-      if (map)
-	{
-	  printf (" ");
-	  print_full_name (map, dev);
-	}
-      if (biosname)
-	{
-	  printf (" ");
-	  print_full_name (biosname, dev);
-	}
-
-      printf ("\n");
-      free (biosname);
-      goto end;
-    }
-
-  if (print == PRINT_BAREMETAL_HINT)
-    {
-      char *biosname;
-      char *name;
-      const char *map;
-
-      biosname = guess_baremetal_drive (device_name);
-
-      map = grub_util_biosdisk_get_compatibility_hint (dev->disk);
-      if (map)
-	{
-	  printf (" ");
-	  print_full_name (map, dev);
-	}
-      if (biosname)
-	{
-	  printf (" ");
-	  print_full_name (biosname, dev);
-	}
-
-      printf ("\n");
-      free (biosname);
-      goto end;
-    }
-
-  if (print == PRINT_ARC_HINT)
-    {
-      const char *map;
-
-      map = grub_util_biosdisk_get_compatibility_hint (dev->disk);
-      if (map)
-	{
-	  printf (" ");
-	  print_full_name (map, dev);
-	}
-      printf ("\n");
-
-      /* FIXME */
-
-      goto end;
-    }
-
-  if (print == PRINT_ABSTRACTION)
-    {
-      probe_abstraction (dev->disk);
-      printf ("\n");
-      goto end;
-    }
-
-  if (print == PRINT_CRYPTODISK_UUID)
-    {
-      probe_cryptodisk_uuid (dev->disk);
-      printf ("\n");
-      goto end;
-    }
-
-  if (print == PRINT_PARTMAP)
-    {
-      /* Check if dev->disk itself is contained in a partmap.  */
-      probe_partmap (dev->disk);
-      printf ("\n");
-      goto end;
-    }
-
-  if (print == PRINT_MSDOS_PARTTYPE)
-    {
-      if (dev->disk->partition
-	  && strcmp(dev->disk->partition->partmap->name, "msdos") == 0)
-        printf ("%02x", dev->disk->partition->msdostype);
-
-      printf ("\n");
-      goto end;
-    }
-
-  fs = grub_fs_probe (dev);
-  if (! fs)
-    grub_util_error ("%s", _(grub_errmsg));
-
-  if (print == PRINT_FS)
-    {
-      printf ("%s\n", fs->name);
-    }
-  else if (print == PRINT_FS_UUID)
-    {
-      char *uuid;
-      if (! fs->uuid)
-	grub_util_error (_("%s does not support UUIDs"), fs->name);
-
-      if (fs->uuid (dev, &uuid) != GRUB_ERR_NONE)
-	grub_util_error ("%s", grub_errmsg);
-
-      printf ("%s\n", uuid);
-    }
-  else if (print == PRINT_FS_LABEL)
-    {
-      char *label;
-      if (! fs->label)
-	grub_util_error (_("%s does not support labels"), fs->name);
-
-      if (fs->label (dev, &label) != GRUB_ERR_NONE)
-	grub_util_error ("%s", _(grub_errmsg));
-
-      printf ("%s\n", label);
+	  grub_device_close (dev);
+	  continue;
+	}
+      if (print == PRINT_EFI_HINT)
+	{
+	  char *biosname;
+	  char *name;
+	  const char *map;
+	  biosname = guess_efi_drive (*curdev);
+
+	  map = grub_util_biosdisk_get_compatibility_hint (dev->disk);
+	  if (map)
+	    {
+	      printf (" ");
+	      print_full_name (map, dev);
+	    }
+	  if (biosname)
+	    {
+	      printf (" ");
+	      print_full_name (biosname, dev);
+	    }
+
+	  delim (zdelim);
+	  free (biosname);
+	  grub_device_close (dev);
+	  continue;
+	}
+
+      if (print == PRINT_BAREMETAL_HINT)
+	{
+	  char *biosname;
+	  char *name;
+	  const char *map;
+
+	  biosname = guess_baremetal_drive (*curdev);
+
+	  map = grub_util_biosdisk_get_compatibility_hint (dev->disk);
+	  if (map)
+	    {
+	      printf (" ");
+	      print_full_name (map, dev);
+	    }
+	  if (biosname)
+	    {
+	      printf (" ");
+	      print_full_name (biosname, dev);
+	    }
+
+	  delim (zdelim);
+	  free (biosname);
+	  grub_device_close (dev);
+	  continue;
+	}
+
+      if (print == PRINT_ARC_HINT)
+	{
+	  const char *map;
+
+	  map = grub_util_biosdisk_get_compatibility_hint (dev->disk);
+	  if (map)
+	    {
+	      printf (" ");
+	      print_full_name (map, dev);
+	    }
+	  delim (zdelim);
+
+	  /* FIXME */
+	  grub_device_close (dev);
+	  continue;
+	}
+
+      if (print == PRINT_ABSTRACTION)
+	{
+	  probe_abstraction (dev->disk);
+	  delim (zdelim);
+	  grub_device_close (dev);
+	  continue;
+	}
+
+      if (print == PRINT_CRYPTODISK_UUID)
+	{
+	  probe_cryptodisk_uuid (dev->disk);
+	  delim (zdelim);
+	  grub_device_close (dev);
+	  continue;
+	}
+
+      if (print == PRINT_PARTMAP)
+	{
+	  /* Check if dev->disk itself is contained in a partmap.  */
+	  probe_partmap (dev->disk);
+	  delim (zdelim);
+	  grub_device_close (dev);
+	  continue;
+	}
+
+      if (print == PRINT_MSDOS_PARTTYPE)
+	{
+	  if (dev->disk->partition
+	      && strcmp(dev->disk->partition->partmap->name, "msdos") == 0)
+	    printf ("%02x", dev->disk->partition->msdostype);
+
+	  delim (zdelim);
+	  grub_device_close (dev);
+	  continue;
+	}
     }
 
  end:
-  if (dev)
-    grub_device_close (dev);
-  free (grub_path);
-  free (filebuf_via_grub);
-  free (filebuf_via_sys);
-  free (drive_name);
+  for (curdrive = drives_names; *curdrive; curdrive++)
+    free (*curdrive);
+  free (drives_names);
 }
 
 static struct option options[] =
@@ -637,7 +681,7 @@
 main (int argc, char *argv[])
 {
   char *dev_map = 0;
-  char *argument;
+  int zero_delim = 0;
 
   set_program_name (argv[0]);
 
@@ -646,7 +690,7 @@
   /* Check for options.  */
   while (1)
     {
-      int c = getopt_long (argc, argv, "dm:t:hVv", options, 0);
+      int c = getopt_long (argc, argv, "dm:t:hVv0", options, 0);
 
       if (c == -1)
 	break;
@@ -705,6 +749,10 @@
 	    usage (0);
 	    break;
 
+	  case '0':
+	    zero_delim = 1;
+	    break;
+
 	  case 'V':
 	    printf ("%s (%s) %s\n", program_name, PACKAGE_NAME, PACKAGE_VERSION);
 	    return 0;
@@ -729,14 +777,12 @@
       usage (1);
     }
 
-  if (optind + 1 != argc)
+  if (optind + 1 != argc && !argument_is_device)
     {
       fprintf (stderr, _("Unknown extra argument `%s'.\n"), argv[optind + 1]);
       usage (1);
     }
 
-  argument = argv[optind];
-
   /* Initialize the emulated biosdisk driver.  */
   grub_util_biosdisk_init (dev_map ? : DEFAULT_DEVICE_MAP);
 
@@ -755,9 +801,9 @@
 
   /* Do it.  */
   if (argument_is_device)
-    probe (NULL, argument);
+    probe (NULL, argv + optind, zero_delim);
   else
-    probe (argument, NULL);
+    probe (argv[optind], NULL, zero_delim);
 
   /* Free resources.  */
   grub_gcry_fini_all ();

=== modified file 'util/grub-setup.c'
--- util/grub-setup.c	2012-01-24 13:39:29 +0000
+++ util/grub-setup.c	2012-01-27 18:31:20 +0000
@@ -133,15 +139,16 @@
 static void
 setup (const char *dir,
        const char *boot_file, const char *core_file,
-       const char *root, const char *dest, int must_embed, int force,
+       const char *dest, int force,
        int fs_probe, int allow_floppy)
 {
   char *boot_path, *core_path, *core_path_dev, *core_path_dev_full;
   char *boot_img, *core_img;
+  char *root = 0;
   size_t boot_size, core_size;
   grub_uint16_t core_sectors;
-  grub_device_t root_dev, dest_dev;
-  struct grub_boot_blocklist *first_block, *block;
+  grub_device_t root_dev = 0, dest_dev;
+  struct grub_boot_blocklist *first_block, *block, *last_block;
   char *tmp_img;
   int i;
   grub_disk_addr_t first_sector;
@@ -235,17 +241,56 @@
 						- sizeof (*block));
   grub_util_info ("root is `%s', dest is `%s'", root, dest);
 
-  /* Open the root device and the destination device.  */
-  grub_util_info ("Opening root");
-  root_dev = grub_device_open (root);
-  if (! root_dev)
-    grub_util_error ("%s", _(grub_errmsg));
-
   grub_util_info ("Opening dest");
   dest_dev = grub_device_open (dest);
   if (! dest_dev)
     grub_util_error ("%s", _(grub_errmsg));
 
+  {
+    char **root_devices = grub_guess_root_devices (dir);
+    char **cur;
+    int found = 0;
+
+    for (cur = root_devices; *cur; cur++)
+      {
+	char *drive;
+	grub_device_t try_dev;
+
+	drive = grub_util_get_grub_dev (*cur);
+	if (!drive)
+	  continue;
+	try_dev = grub_device_open (drive);
+	if (! try_dev)
+	  continue;
+	if (!found && try_dev->disk->id == dest_dev->disk->id
+	    && try_dev->disk->dev->id == dest_dev->disk->dev->id)
+	  {
+	    if (root_dev)
+	      grub_device_close (root_dev);
+	    free (root);
+	    root_dev = try_dev;
+	    root = drive;
+	    found = 1;
+	    continue;
+	  }
+	if (!root_dev)
+	  {
+	    root_dev = try_dev;
+	    root = drive;
+	    continue;
+	  }
+	grub_device_close (try_dev);	
+	free (drive);
+      }
+    if (!root_dev)
+      {
+	grub_util_error ("guessing the root device failed, because of `%s'",
+			 grub_errmsg);
+      }
+    grub_util_info ("guessed root_dev `%s' from "
+		    "dir `%s'", root_dev->disk->name, dir);
+  }
+
   grub_util_info ("setting the root device to `%s'", root);
   if (grub_env_set ("root", root) != GRUB_ERR_NONE)
     grub_util_error ("%s", _(grub_errmsg));
@@ -485,16 +530,24 @@
 
 unable_to_embed:
 
-  if (must_embed)
-    grub_util_error (_("embedding is not possible, but this is required when "
-		       "the root device is on a RAID array or LVM volume"));
-
 #ifdef GRUB_MACHINE_PCBIOS
-  if (dest_dev->disk->id != root_dev->disk->id)
+  if (dest_dev->disk->id != root_dev->disk->id
+      || dest_dev->disk->dev->id != root_dev->disk->dev->id)
     grub_util_error (_("embedding is not possible, but this is required for "
 		       "cross-disk install"));
 #endif
 
+  {
+    grub_fs_t fs;
+    fs = grub_fs_probe (root_dev);
+    if (!fs)
+      grub_util_error (_("can't determine filesystem"));
+
+    if (!fs->blocklist_install)
+      grub_util_error (_("filesystem '%s' doesn't support blocklists"),
+		       fs->name);
+  }
+
   grub_util_warn (_("Embedding is not possible.  GRUB can only be installed in this "
 		    "setup by using blocklists.  However, blocklists are UNRELIABLE and "
 		    "their use is discouraged."));
@@ -617,11 +783,12 @@
     boot_devpath = (char *) (boot_img
 			     + GRUB_BOOT_AOUT_HEADER_SIZE
 			     + GRUB_BOOT_MACHINE_BOOT_DEVPATH);
-    if (file->device->disk->id != dest_dev->disk->id)
+    if (dest_dev->disk->id != root_dev->disk->id
+	|| dest_dev->disk->dev->id != root_dev->disk->dev->id)
       {
 	const char *dest_ofpath;
 	dest_ofpath
-	  = grub_util_devname_to_ofpath (grub_util_biosdisk_get_osdev (file->device->disk));
+	  = grub_util_devname_to_ofpath (grub_util_biosdisk_get_osdev (root_dev->disk));
 	grub_util_info ("dest_ofpath is `%s'", dest_ofpath);
 	strncpy (boot_devpath, dest_ofpath, GRUB_BOOT_MACHINE_BOOT_DEVPATH_END
 		 - GRUB_BOOT_MACHINE_BOOT_DEVPATH - 1);
@@ -722,7 +959,6 @@
   char *core_file;
   char *dir;
   char *dev_map;
-  char *root_dev;
   int  force;
   int  fs_probe;
   int allow_floppy;
@@ -783,13 +1019,6 @@
         arguments->dev_map = xstrdup (arg);
         break;
 
-      case 'r':
-        if (arguments->root_dev)
-          free (arguments->root_dev);
-
-        arguments->root_dev = xstrdup (arg);
-        break;
-
       case 'f':
         arguments->force = 1;
         break;
@@ -853,7 +1082,6 @@
 {
   char *root_dev = NULL;
   char *dest_dev = NULL;
-  int must_embed = 0;
   struct arguments arguments;
 
   set_program_name (argv[0]);
@@ -917,80 +1145,12 @@
       grub_util_info ("Using `%s' as GRUB device", dest_dev);
     }
 
-  if (arguments.root_dev)
-    {
-      root_dev = get_device_name (arguments.root_dev);
-
-      if (! root_dev)
-        grub_util_error (_("invalid root device `%s'"), arguments.root_dev);
-
-      root_dev = xstrdup (root_dev);
-    }
-  else
-    {
-      char *root_device =
-        grub_guess_root_device (arguments.dir ? : DEFAULT_DIRECTORY);
-
-      root_dev = grub_util_get_grub_dev (root_device);
-      if (! root_dev)
-	{
-	  grub_util_info ("guessing the root device failed, because of `%s'",
-			  grub_errmsg);
-          grub_util_error (_("cannot guess the root device. Specify the option "
-                             "`--root-device'"));
-	}
-      grub_util_info ("guessed root device `%s' and root_dev `%s' from "
-                      "dir `%s'", root_device, root_dev,
-                      arguments.dir ? : DEFAULT_DIRECTORY);
-    }
-
-#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
-  if (grub_util_lvm_isvolume (root_dev))
-    must_embed = 1;
-#endif
-
-#ifdef __linux__
-  if (root_dev[0] == 'm' && root_dev[1] == 'd'
-      && ((root_dev[2] >= '0' && root_dev[2] <= '9') || root_dev[2] == '/'))
-    {
-      /* FIXME: we can avoid this on RAID1.  */
-      must_embed = 1;
-    }
-
-  if (dest_dev[0] == 'm' && dest_dev[1] == 'd'
-      && ((dest_dev[2] >= '0' && dest_dev[2] <= '9') || dest_dev[2] == '/'))
-    {
-      char **devicelist;
-      int i;
-
-      if (arguments.device[0] == '/')
-	devicelist = grub_util_raid_getmembers (arguments.device, 1);
-      else
-	{
-	  char *devname;
-	  devname = xasprintf ("/dev/%s", dest_dev);
-	  devicelist = grub_util_raid_getmembers (dest_dev, 1);
-	  free (devname);
-	}
-
-      for (i = 0; devicelist[i]; i++)
-        {
-          setup (arguments.dir ? : DEFAULT_DIRECTORY,
-                 arguments.boot_file ? : DEFAULT_BOOT_FILE,
-                 arguments.core_file ? : DEFAULT_CORE_FILE,
-                 root_dev, grub_util_get_grub_dev (devicelist[i]), 1,
-                 arguments.force, arguments.fs_probe,
-		 arguments.allow_floppy);
-        }
-    }
-  else
-#endif
-    /* Do the real work.  */
-    setup (arguments.dir ? : DEFAULT_DIRECTORY,
-           arguments.boot_file ? : DEFAULT_BOOT_FILE,
-           arguments.core_file ? : DEFAULT_CORE_FILE,
-           root_dev, dest_dev, must_embed, arguments.force,
-	   arguments.fs_probe, arguments.allow_floppy);
+  /* Do the real work.  */
+  setup (arguments.dir ? : DEFAULT_DIRECTORY,
+	 arguments.boot_file ? : DEFAULT_BOOT_FILE,
+	 arguments.core_file ? : DEFAULT_CORE_FILE,
+	 dest_dev, arguments.force,
+	 arguments.fs_probe, arguments.allow_floppy);
 
   /* Free resources.  */
   grub_fini_all ();
@@ -999,7 +1159,6 @@
   free (arguments.boot_file);
   free (arguments.core_file);
   free (arguments.dir);
-  free (arguments.root_dev);
   free (arguments.dev_map);
   free (arguments.device);
   free (root_dev);


  reply	other threads:[~2012-01-28 12:51 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-09-19 18:45 [Patch] Robustly search for ZFS labels & uberblocks Zachary Bedell
2011-09-28 21:20 ` Vladimir 'φ-coder/phcoder' Serbinenko
2012-01-19 11:36   ` Richard Laager
2012-01-22 14:18     ` Vladimir 'φ-coder/phcoder' Serbinenko
2012-01-22 20:31       ` Richard Laager
2012-01-24  7:12       ` Richard Laager
2012-01-27 19:04       ` Zachary Bedell
2012-01-27 22:22         ` Vladimir 'φ-coder/phcoder' Serbinenko
2012-01-28  2:50         ` Richard Laager
2012-01-28 12:51           ` Vladimir 'φ-coder/phcoder' Serbinenko [this message]
2012-01-28 16:50             ` Richard Laager
2012-01-28 17:06               ` Darik Horn
2012-01-28 17:39                 ` Vladimir 'φ-coder/phcoder' Serbinenko
2012-01-28 18:33             ` Richard Laager
2012-01-28 19:21               ` Vladimir 'φ-coder/phcoder' Serbinenko
2012-01-29 22:42               ` Vladimir 'φ-coder/phcoder' Serbinenko
2012-01-31  8:45                 ` Richard Laager
2012-02-02 11:13                   ` Richard Laager
2012-02-03 10:02                     ` Vladimir 'φ-coder/phcoder' Serbinenko
2012-02-03  9:52                   ` Vladimir 'φ-coder/phcoder' Serbinenko
2012-02-03 11:20                     ` Richard Laager
2012-01-28 18:40             ` Darik Horn
2012-01-28 19:27               ` Vladimir 'φ-coder/phcoder' Serbinenko
2012-01-30  1:22             ` Richard Laager
2012-01-30  1:43               ` Vladimir 'φ-coder/phcoder' Serbinenko
2011-11-03 14:45 ` Vladimir 'φ-coder/phcoder' Serbinenko

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4F23EF3C.9050407@gmail.com \
    --to=phcoder@gmail.com \
    --cc=grub-devel@gnu.org \
    --cc=pendorbound@gmail.com \
    --cc=rlaager@wiktel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).