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
[email protected]
https://lists.gnu.org/mailman/listinfo/grub-devel


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

=== 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);

_______________________________________________
Grub-devel mailing list
[email protected]
https://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to