grub-devel.gnu.org archive mirror
 help / color / mirror / Atom feed
* [RFC] grub-install: allow none or multiple install devices on PC BIOS
@ 2015-05-08 18:53 Andrei Borzenkov
  2015-05-12 10:52 ` Michael Chang
  2016-02-12 18:41 ` Vladimir 'φ-coder/phcoder' Serbinenko
  0 siblings, 2 replies; 10+ messages in thread
From: Andrei Borzenkov @ 2015-05-08 18:53 UTC (permalink / raw)
  To: grub-devel

There are two main applications.

1. Omit install device to create generic image intended for chainloading
from other master loader. Such image can be put on any device (or file
system) and will still be able to find its $root. Currently even with
--no-bootsector grub-install optimizes image by skipping UUID search if
possible.

2. Redundant installation on multi-device filesystem, RAID or similar.
This allows both optimizing image w.r.t. to using --prefix vs. load.cfg
as well as creating image just once.

Patch allows transparently use none or multiple installation devices,
similar to

grub_devices="/dev/sda /dev/sda1 /dev/sdb"
grub-install $grub_devices

where grub_devices can be empty and still do the right thing.

This is work in progress, although it is functionally complete and just
needs some cleanups.

Comments?

---
 grub-core/kern/disk.c |   5 +-
 include/grub/disk.h   |   2 +
 util/grub-install.c   | 217 +++++++++++++++++++++++++++++++-------------------
 3 files changed, 143 insertions(+), 81 deletions(-)

diff --git a/grub-core/kern/disk.c b/grub-core/kern/disk.c
index 789f8c0..56f16b4 100644
--- a/grub-core/kern/disk.c
+++ b/grub-core/kern/disk.c
@@ -168,7 +168,10 @@ grub_disk_dev_unregister (grub_disk_dev_t dev)
 
 /* Return the location of the first ',', if any, which is not
    escaped by a '\'.  */
-static const char *
+#if !defined (GRUB_UTIL)
+static
+#endif
+const char *
 find_part_sep (const char *name)
 {
   const char *p = name;
diff --git a/include/grub/disk.h b/include/grub/disk.h
index b385af8..b2081eb 100644
--- a/include/grub/disk.h
+++ b/include/grub/disk.h
@@ -256,6 +256,8 @@ void grub_ldm_fini (void);
 void grub_mdraid09_fini (void);
 void grub_mdraid1x_fini (void);
 void grub_diskfilter_fini (void);
+extern const char *find_part_sep (const char *);
+
 #endif
 
 #endif /* ! GRUB_DISK_HEADER */
diff --git a/util/grub-install.c b/util/grub-install.c
index 7b394c9..bb6532c 100644
--- a/util/grub-install.c
+++ b/util/grub-install.c
@@ -57,7 +57,10 @@ static char *target;
 static int removable = 0;
 static int recheck = 0;
 static int update_nvram = 1;
-static char *install_device = NULL;
+static char **install_devices = NULL;
+static char **install_drives = NULL;
+static int n_install_devices;
+static int n_allocated_devices;
 static char *debug_image = NULL;
 static char *rootdir = NULL;
 static char *bootdir = NULL;
@@ -234,9 +237,12 @@ argp_parser (int key, char *arg, struct argp_state *state)
       return 0;
 
     case ARGP_KEY_ARG:
-      if (install_device)
-	grub_util_error ("%s", _("More than one install device?"));
-      install_device = xstrdup (arg);
+      if (n_install_devices >= n_allocated_devices)
+	{
+	  n_allocated_devices += 16;
+	  install_devices = xrealloc (install_devices, n_allocated_devices);
+	}
+      install_devices[n_install_devices++] = xstrdup (arg);
       return 0;
 
     default:
@@ -534,25 +540,55 @@ probe_cryptodisk_uuid (grub_disk_t disk)
 }
 
 static int
-is_same_disk (const char *a, const char *b)
+same_disks (char **root_devs)
 {
-  while (1)
+  int i;
+
+  for (i = 0; i < n_install_devices; i++)
     {
-      if ((*a == ',' || *a == '\0') && (*b == ',' || *b == '\0'))
-	return 1;
-      if (*a != *b)
-	return 0;
-      if (*a == '\\')
+      char **d;
+      const char *p1 = find_part_sep (install_drives[i]);
+      size_t len1 = p1 ? p1 - install_drives[i] : strlen (install_drives[i]);
+
+      for (d = root_devs; *d; d++)
 	{
-	  if (a[1] != b[1])
-	    return 0;
-	  a += 2;
-	  b += 2;
-	  continue;
+	  const char *p2 = find_part_sep (*d);
+	  size_t len2 = p2 ? p2 - *d : strlen (*d);
+
+	  if (len1 == len2 &&
+	      strncmp (install_drives[i], *d, len1) == 0)
+	    break;
 	}
-      a++;
-      b++;
+      if (!*d)
+	return 0;
+    }
+
+  return 1;
+}
+
+static int
+same_partitions (char **root_devs)
+{
+  const char *first_part;
+  char **p;
+
+  if (!root_devs[1])
+    return 1;
+
+  first_part = find_part_sep (root_devs[0]);
+  for (p = root_devs + 1; *p; p++)
+    {
+      const char *part = find_part_sep (*p);
+
+      if ((first_part == NULL) ^ (part == NULL))
+	return 0;
+      if (!first_part && !part)
+	continue;
+      if (strcmp (first_part, part))
+	return 0;
     }
+
+  return 1;
 }
 
 static char *
@@ -835,6 +871,8 @@ main (int argc, char *argv[])
   int efidir_is_mac = 0;
   int is_prep = 0;
   const char *pkgdatadir;
+  size_t i;
+
 
   grub_util_host_init (&argc, &argv);
   product_version = xstrdup (PACKAGE_VERSION);
@@ -926,12 +964,26 @@ main (int argc, char *argv[])
   switch (platform)
     {
     case GRUB_INSTALL_PLATFORM_I386_PC:
+      break;
+
+    default:
+      if (n_install_devices > 1)
+	grub_util_error ("%s", _("More than one install device?"));
+      break;
+    }
+
+  switch (platform)
+    {
+    case GRUB_INSTALL_PLATFORM_I386_PC:
+      if (!install_devices)
+	install_bootsector = 0;
+      break;
     case GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275:
-      if (!install_device)
+      if (!install_devices)
 	grub_util_error ("%s", _("install device isn't specified"));
       break;
     case GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275:
-      if (install_device)
+      if (install_devices)
 	is_prep = 1;
       break;
     case GRUB_INSTALL_PLATFORM_MIPS_ARC:
@@ -952,8 +1004,11 @@ main (int argc, char *argv[])
     case GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS:
     case GRUB_INSTALL_PLATFORM_I386_XEN:
     case GRUB_INSTALL_PLATFORM_X86_64_XEN:
-      free (install_device);
-      install_device = NULL;
+      for (i = 0; i < n_install_devices; i++)
+	free (install_devices[i]);
+      free (install_devices);
+      install_devices = NULL;
+      n_install_devices = n_allocated_devices = 0;
       break;
 
       /* pacify warning.  */
@@ -996,11 +1051,6 @@ main (int argc, char *argv[])
       is_efi = 1;
       break;
     default:
-      is_efi = 0;
-      break;
-
-      /* pacify warning.  */
-    case GRUB_INSTALL_PLATFORM_MAX:
       break;
     }
 
@@ -1009,8 +1059,6 @@ main (int argc, char *argv[])
   if (is_efi)
     {
       grub_fs_t fs;
-      free (install_device);
-      install_device = NULL;
       if (!efidir)
 	{
 	  char *d = grub_util_path_concat (2, bootdir, "efi");
@@ -1045,7 +1093,9 @@ main (int argc, char *argv[])
       if (!efidir_device_names || !efidir_device_names[0])
 	grub_util_error (_("cannot find a device for %s (is /dev mounted?)"),
 			     efidir);
-      install_device = efidir_device_names[0];
+      /* FIXME free install_devices */
+      /* We will use just the first device */
+      install_devices = efidir_device_names;
 
       for (curdev = efidir_device_names; *curdev; curdev++)
 	  grub_util_pull_device (*curdev);
@@ -1207,7 +1257,9 @@ main (int argc, char *argv[])
 	  if (grub_strcmp (fs->name, "hfs") == 0
 	      || grub_strcmp (fs->name, "hfsplus") == 0)
 	    {
-	      install_device = macppcdir_device_names[0];
+	      /* FIXME free install_devices */
+	      /* We just use the first one */
+	      install_devices = macppcdir_device_names;
 	      is_prep = 0;
 	    }
 	}
@@ -1318,35 +1370,37 @@ main (int argc, char *argv[])
 	      debug_image);
     }
   char *prefix_drive = NULL;
-  char *install_drive = NULL;
 
-  if (install_device)
+  if (install_devices)
     {
-      if (install_device[0] == '('
-	  && install_device[grub_strlen (install_device) - 1] == ')')
-        {
-	  size_t len = grub_strlen (install_device) - 2;
-	  install_drive = xmalloc (len + 1);
-	  memcpy (install_drive, install_device + 1, len);
-	  install_drive[len] = '\0';
-        }
-      else
-	{
-	  grub_util_pull_device (install_device);
-	  install_drive = grub_util_get_grub_dev (install_device);
-	  if (!install_drive)
-	    grub_util_error (_("cannot find a GRUB drive for %s.  Check your device.map"),
-			     install_device);
-	}
+      install_drives = xmalloc (n_install_devices * sizeof (*install_drives));
+
+      for (i = 0; i < n_install_devices; i++)
+	if (install_devices[i][0] == '('
+	    && install_devices[i][grub_strlen (install_devices[i]) - 1] == ')')
+	  {
+	    size_t len = grub_strlen (install_devices[i]) - 2;
+	    install_drives[i] = xmalloc (len + 1);
+	    memcpy (install_drives[i], install_devices[i] + 1, len);
+	    install_drives[i][len] = '\0';
+	  }
+	else
+	  {
+	    grub_util_pull_device (install_devices[i]);
+	    install_drives[i] = grub_util_get_grub_dev (install_devices[i]);
+	    if (!install_drives[i])
+	      grub_util_error (_("cannot find a GRUB drive for %s.  Check your device.map"),
+			       install_devices[i]);
+	  }
     }
 
   if (!have_abstractions)
     {
       if ((disk_module && grub_strcmp (disk_module, "biosdisk") != 0)
-	  || grub_drives[1]
-	  || (!install_drive
+	  || (grub_drives[1] && !same_partitions (grub_drives))
+	  || (!install_drives
 	      && platform != GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275)
-	  || (install_drive && !is_same_disk (grub_drives[0], install_drive))
+	  || (install_drives && !same_disks (grub_drives))
 	  || !have_bootdev (platform))
 	{
 	  char *uuid = NULL;
@@ -1656,24 +1710,27 @@ main (int argc, char *argv[])
 					      "boot.img");
 	grub_install_copy_file (boot_img_src, boot_img, 1);
 
-	grub_util_info ("%sgrub-bios-setup %s %s %s %s %s --directory='%s' --device-map='%s' '%s'",
-			/* TRANSLATORS: This is a prefix in the log to indicate that usually
-			   a command would be executed but due to an option was skipped.  */
-			install_bootsector ? "" : _("NOT RUNNING: "),
-			allow_floppy ? "--allow-floppy " : "",
-			verbosity ? "--verbose " : "",
-			force ? "--force " : "",
-			!fs_probe ? "--skip-fs-probe" : "",
-			!add_rs_codes ? "--no-rs-codes" : "",
-			platdir,
-			device_map,
-			install_device);
-			
-	/*  Now perform the installation.  */
-	if (install_bootsector)
-	  grub_util_bios_setup (platdir, "boot.img", "core.img",
-				install_drive, force,
-				fs_probe, allow_floppy, add_rs_codes);
+	for (i = 0; i < n_install_devices; i++)
+	  {
+	    grub_util_info ("%sgrub-bios-setup %s %s %s %s %s --directory='%s' --device-map='%s' '%s'",
+			    /* TRANSLATORS: This is a prefix in the log to indicate that usually
+			       a command would be executed but due to an option was skipped.  */
+			    install_bootsector ? "" : _("NOT RUNNING: "),
+			    allow_floppy ? "--allow-floppy " : "",
+			    verbosity ? "--verbose " : "",
+			    force ? "--force " : "",
+			    !fs_probe ? "--skip-fs-probe" : "",
+			    !add_rs_codes ? "--no-rs-codes" : "",
+			    platdir,
+			    device_map,
+			    install_devices[i]);
+
+	    /*  Now perform the installation.  */
+	    if (install_bootsector)
+	      grub_util_bios_setup (platdir, "boot.img", "core.img",
+				    install_drives[i], force,
+				    fs_probe, allow_floppy, add_rs_codes);
+	  }
 	break;
       }
     case GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275:
@@ -1693,12 +1750,12 @@ main (int argc, char *argv[])
 			!fs_probe ? "--skip-fs-probe" : "",
 			platdir,
 			device_map,
-			install_drive);
+			install_drives[0]);
 			
 	/*  Now perform the installation.  */
 	if (install_bootsector)
 	  grub_util_sparc_setup (platdir, "boot.img", "core.img",
-				 install_device, force,
+				 install_devices[0], force,
 				 fs_probe, allow_floppy,
 				 0 /* unused */ );
 	break;
@@ -1734,7 +1791,7 @@ main (int argc, char *argv[])
 
 	  fill_core_services (core_services);
 
-	  ins_dev = grub_device_open (install_drive);
+	  ins_dev = grub_device_open (install_drives[0]);
 
 	  bless (ins_dev, core_services, 0);
 
@@ -1745,7 +1802,7 @@ main (int argc, char *argv[])
 
 	      partno = ins_dev->disk->partition
 		? ins_dev->disk->partition->number + 1 : 0;
-	      dev = grub_util_get_os_disk (install_device);
+	      dev = grub_util_get_os_disk (install_devices[0]);
 	      grub_install_register_ieee1275 (0, dev, partno,
 					      "\\\\BootX");
 	    }
@@ -1757,10 +1814,10 @@ main (int argc, char *argv[])
 	  break;
 	}
       /* If a install device is defined, copy the core.elf to PReP partition.  */
-      if (is_prep && install_device && install_device[0])
+      if (is_prep)
 	{
 	  grub_device_t ins_dev;
-	  ins_dev = grub_device_open (install_drive);
+	  ins_dev = grub_device_open (install_drives[0]);
 	  if (!ins_dev || !is_prep_partition (ins_dev))
 	    {
 	      grub_util_error ("%s", _("the chosen partition is not a PReP partition"));
@@ -1772,13 +1829,13 @@ main (int argc, char *argv[])
 	    }
 	  else
 	    {
-	      char *s = xasprintf ("dd if=/dev/zero of=%s", install_device);
+	      char *s = xasprintf ("dd if=/dev/zero of=%s", install_devices[0]);
 	      grub_util_error (_("the PReP partition is not empty. If you are sure you want to use it, run dd to clear it: `%s'"),
 			       s);
 	    }
 	  grub_device_close (ins_dev);
 	  if (update_nvram)
-	    grub_install_register_ieee1275 (1, grub_util_get_os_disk (install_device),
+	    grub_install_register_ieee1275 (1, grub_util_get_os_disk (install_devices[0]),
 					    0, NULL);
 	  break;
       }
@@ -1798,7 +1855,7 @@ main (int argc, char *argv[])
 	}
       break;
     case GRUB_INSTALL_PLATFORM_MIPS_ARC:
-      grub_install_sgi_setup (install_device, imgfile, "grub");
+      grub_install_sgi_setup (install_devices[0], imgfile, "grub");
       break;
 
     case GRUB_INSTALL_PLATFORM_I386_EFI:
@@ -1834,7 +1891,7 @@ main (int argc, char *argv[])
 
 	  fill_core_services(core_services);
 
-	  ins_dev = grub_device_open (install_drive);
+	  ins_dev = grub_device_open (install_drives[0]);
 
 	  bless (ins_dev, boot_efi, 1);
 	  if (!removable && update_nvram)
-- 
tg: (0725881..) e/optional-install-device (depends on: master)


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [RFC] grub-install: allow none or multiple install devices on PC BIOS
  2015-05-08 18:53 [RFC] grub-install: allow none or multiple install devices on PC BIOS Andrei Borzenkov
@ 2015-05-12 10:52 ` Michael Chang
  2015-05-12 11:57   ` Andrei Borzenkov
  2016-02-12 18:41 ` Vladimir 'φ-coder/phcoder' Serbinenko
  1 sibling, 1 reply; 10+ messages in thread
From: Michael Chang @ 2015-05-12 10:52 UTC (permalink / raw)
  To: The development of GNU GRUB

On Fri, May 08, 2015 at 09:53:41PM +0300, Andrei Borzenkov wrote:
> There are two main applications.
> 
> 1. Omit install device to create generic image intended for chainloading
> from other master loader. Such image can be put on any device (or file
> system) and will still be able to find its $root. Currently even with
> --no-bootsector grub-install optimizes image by skipping UUID search if
> possible.
> 
> 2. Redundant installation on multi-device filesystem, RAID or similar.
> This allows both optimizing image w.r.t. to using --prefix vs. load.cfg
> as well as creating image just once.

I can only tell it to solve the problem of time wasting in copying
modules and images creation due to multiple invocation of grub-install
for doing redundency install. Beside that, do you foresee any other
improvement it can provide?

> 
> Patch allows transparently use none or multiple installation devices,
> similar to
> 
> grub_devices="/dev/sda /dev/sda1 /dev/sdb"

It also looks to me that this patch can solve the problem of multiple
device install with blocklists. Think about the user installs to mbr
(sda) and partition (sda1) because he someshow wants the paritition to
be chainload-able for resuce or for any of his own interests. 

If the user occasionally do.

grub-install /dev/sda1 grub-install /dev/sda

The chainload will fail for sda1 since later install to mbr replaces the
core.img.

You patch can avoid such pit-fall by doing it once.

> grub-install $grub_devices

What if one of the device failed, should it continue installing the rest
or abort immediately ?

Thanks,
Michael


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC] grub-install: allow none or multiple install devices on PC BIOS
  2015-05-12 10:52 ` Michael Chang
@ 2015-05-12 11:57   ` Andrei Borzenkov
  2015-05-12 14:57     ` Michael Chang
  2015-05-12 15:22     ` Michael Chang
  0 siblings, 2 replies; 10+ messages in thread
From: Andrei Borzenkov @ 2015-05-12 11:57 UTC (permalink / raw)
  To: Michael Chang; +Cc: The development of GNU GRUB

В Tue, 12 May 2015 18:52:22 +0800
Michael Chang <mchang@suse.com> пишет:

> On Fri, May 08, 2015 at 09:53:41PM +0300, Andrei Borzenkov wrote:
> > There are two main applications.
> > 
> > 1. Omit install device to create generic image intended for chainloading
> > from other master loader. Such image can be put on any device (or file
> > system) and will still be able to find its $root. Currently even with
> > --no-bootsector grub-install optimizes image by skipping UUID search if
> > possible.
> > 

Actually I think it is useful for all platforms.

> > 2. Redundant installation on multi-device filesystem, RAID or similar.
> > This allows both optimizing image w.r.t. to using --prefix vs. load.cfg
> > as well as creating image just once.
> 
> I can only tell it to solve the problem of time wasting in copying
> modules and images creation due to multiple invocation of grub-install
> for doing redundency install. Beside that, do you foresee any other
> improvement it can provide?
> 

You answered it yourself below. That is why I think it is useful mostly
for PC BIOS that is unique with embedding problem.

> > 
> > Patch allows transparently use none or multiple installation devices,
> > similar to
> > 
> > grub_devices="/dev/sda /dev/sda1 /dev/sdb"
> 
> It also looks to me that this patch can solve the problem of multiple
> device install with blocklists. Think about the user installs to mbr
> (sda) and partition (sda1) because he someshow wants the paritition to
> be chainload-able for resuce or for any of his own interests. 
> 
> If the user occasionally do.
> 
> grub-install /dev/sda1 grub-install /dev/sda
> 
> The chainload will fail for sda1 since later install to mbr replaces the
> core.img.
> 

Exactly. This was common problem for openSUSE users as at least in
earlier versions installer defaulted to multiple bootloader locations
and only some of them allowed embedding.

> You patch can avoid such pit-fall by doing it once.
> 
> > grub-install $grub_devices
> 
> What if one of the device failed, should it continue installing the rest
> or abort immediately ?
> 

It will abort, unfortunately. Changing it is really intrusive as it
may happen deep in call chain which simply does grub_util_error(). It
is something that may be considered for the future. BTW as far as I can
tell pbl aborts installation if any of grub-install invocation failed.


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC] grub-install: allow none or multiple install devices on PC BIOS
  2015-05-12 11:57   ` Andrei Borzenkov
@ 2015-05-12 14:57     ` Michael Chang
  2015-05-12 15:22     ` Michael Chang
  1 sibling, 0 replies; 10+ messages in thread
From: Michael Chang @ 2015-05-12 14:57 UTC (permalink / raw)
  To: The development of GNU GRUB

On Tue, May 12, 2015 at 02:57:00PM +0300, Andrei Borzenkov wrote:
> В Tue, 12 May 2015 18:52:22 +0800
> Michael Chang <mchang@suse.com> пишет:
> 
> > On Fri, May 08, 2015 at 09:53:41PM +0300, Andrei Borzenkov wrote:
> > > There are two main applications.
> > > 
> 
> It will abort, unfortunately. Changing it is really intrusive as it
> may happen deep in call chain which simply does grub_util_error(). It
> is something that may be considered for the future. BTW as far as I can
> tell pbl aborts installation if any of grub-install invocation failed.
> 

Yes. That's why I would like to confirm the default behavior. It may
be able to proceed regardless of error, but aborting looks better
decision to me.

Thanks,
Michael


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC] grub-install: allow none or multiple install devices on PC BIOS
  2015-05-12 11:57   ` Andrei Borzenkov
  2015-05-12 14:57     ` Michael Chang
@ 2015-05-12 15:22     ` Michael Chang
  2016-02-13  7:29       ` Andrei Borzenkov
  1 sibling, 1 reply; 10+ messages in thread
From: Michael Chang @ 2015-05-12 15:22 UTC (permalink / raw)
  To: The development of GNU GRUB

On Tue, May 12, 2015 at 02:57:00PM +0300, Andrei Borzenkov wrote:
> В Tue, 12 May 2015 18:52:22 +0800
> Michael Chang <mchang@suse.com> пишет:
> 
> > On Fri, May 08, 2015 at 09:53:41PM +0300, Andrei Borzenkov wrote:
> > > There are two main applications.
> > > 
> > > 1. Omit install device to create generic image intended for chainloading
> > > from other master loader. Such image can be put on any device (or file
> > > system) and will still be able to find its $root. Currently even with
> > > --no-bootsector grub-install optimizes image by skipping UUID search if
> > > possible.
> > > 
> 
> Actually I think it is useful for all platforms.

As it works across all platform, os-prober should consider chanloading
core images if possible rather than digging into grub configs. Is there
any plan for that ?

Thanks,
Michael


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC] grub-install: allow none or multiple install devices on PC BIOS
  2015-05-08 18:53 [RFC] grub-install: allow none or multiple install devices on PC BIOS Andrei Borzenkov
  2015-05-12 10:52 ` Michael Chang
@ 2016-02-12 18:41 ` Vladimir 'φ-coder/phcoder' Serbinenko
  2016-02-13  7:27   ` Andrei Borzenkov
  1 sibling, 1 reply; 10+ messages in thread
From: Vladimir 'φ-coder/phcoder' Serbinenko @ 2016-02-12 18:41 UTC (permalink / raw)
  To: The development of GNU GRUB

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

On 08.05.2015 20:53, Andrei Borzenkov wrote:
> There are two main applications.
> 
> 1. Omit install device to create generic image intended for chainloading
> from other master loader. Such image can be put on any device (or file
> system) and will still be able to find its $root. Currently even with
> --no-bootsector grub-install optimizes image by skipping UUID search if
> possible.
> 
> 2. Redundant installation on multi-device filesystem, RAID or similar.
> This allows both optimizing image w.r.t. to using --prefix vs. load.cfg
> as well as creating image just once.
> 
> Patch allows transparently use none or multiple installation devices,
> similar to
> 
> grub_devices="/dev/sda /dev/sda1 /dev/sdb"
> grub-install $grub_devices
> 
> where grub_devices can be empty and still do the right thing.
> 
> This is work in progress, although it is functionally complete and just
> needs some cleanups.
> 
> Comments?
I like the idea and it was on my "nice to have" list for some time. Do
you want to clean it up first or should I review this version?
> 
> ---
>  grub-core/kern/disk.c |   5 +-
>  include/grub/disk.h   |   2 +
>  util/grub-install.c   | 217 +++++++++++++++++++++++++++++++-------------------
>  3 files changed, 143 insertions(+), 81 deletions(-)
> 
> diff --git a/grub-core/kern/disk.c b/grub-core/kern/disk.c
> index 789f8c0..56f16b4 100644
> --- a/grub-core/kern/disk.c
> +++ b/grub-core/kern/disk.c
> @@ -168,7 +168,10 @@ grub_disk_dev_unregister (grub_disk_dev_t dev)
>  
>  /* Return the location of the first ',', if any, which is not
>     escaped by a '\'.  */
> -static const char *
> +#if !defined (GRUB_UTIL)
> +static
> +#endif
> +const char *
>  find_part_sep (const char *name)
>  {
>    const char *p = name;
> diff --git a/include/grub/disk.h b/include/grub/disk.h
> index b385af8..b2081eb 100644
> --- a/include/grub/disk.h
> +++ b/include/grub/disk.h
> @@ -256,6 +256,8 @@ void grub_ldm_fini (void);
>  void grub_mdraid09_fini (void);
>  void grub_mdraid1x_fini (void);
>  void grub_diskfilter_fini (void);
> +extern const char *find_part_sep (const char *);
> +
>  #endif
>  
>  #endif /* ! GRUB_DISK_HEADER */
> diff --git a/util/grub-install.c b/util/grub-install.c
> index 7b394c9..bb6532c 100644
> --- a/util/grub-install.c
> +++ b/util/grub-install.c
> @@ -57,7 +57,10 @@ static char *target;
>  static int removable = 0;
>  static int recheck = 0;
>  static int update_nvram = 1;
> -static char *install_device = NULL;
> +static char **install_devices = NULL;
> +static char **install_drives = NULL;
> +static int n_install_devices;
> +static int n_allocated_devices;
>  static char *debug_image = NULL;
>  static char *rootdir = NULL;
>  static char *bootdir = NULL;
> @@ -234,9 +237,12 @@ argp_parser (int key, char *arg, struct argp_state *state)
>        return 0;
>  
>      case ARGP_KEY_ARG:
> -      if (install_device)
> -	grub_util_error ("%s", _("More than one install device?"));
> -      install_device = xstrdup (arg);
> +      if (n_install_devices >= n_allocated_devices)
> +	{
> +	  n_allocated_devices += 16;
> +	  install_devices = xrealloc (install_devices, n_allocated_devices);
> +	}
> +      install_devices[n_install_devices++] = xstrdup (arg);
>        return 0;
>  
>      default:
> @@ -534,25 +540,55 @@ probe_cryptodisk_uuid (grub_disk_t disk)
>  }
>  
>  static int
> -is_same_disk (const char *a, const char *b)
> +same_disks (char **root_devs)
>  {
> -  while (1)
> +  int i;
> +
> +  for (i = 0; i < n_install_devices; i++)
>      {
> -      if ((*a == ',' || *a == '\0') && (*b == ',' || *b == '\0'))
> -	return 1;
> -      if (*a != *b)
> -	return 0;
> -      if (*a == '\\')
> +      char **d;
> +      const char *p1 = find_part_sep (install_drives[i]);
> +      size_t len1 = p1 ? p1 - install_drives[i] : strlen (install_drives[i]);
> +
> +      for (d = root_devs; *d; d++)
>  	{
> -	  if (a[1] != b[1])
> -	    return 0;
> -	  a += 2;
> -	  b += 2;
> -	  continue;
> +	  const char *p2 = find_part_sep (*d);
> +	  size_t len2 = p2 ? p2 - *d : strlen (*d);
> +
> +	  if (len1 == len2 &&
> +	      strncmp (install_drives[i], *d, len1) == 0)
> +	    break;
>  	}
> -      a++;
> -      b++;
> +      if (!*d)
> +	return 0;
> +    }
> +
> +  return 1;
> +}
> +
> +static int
> +same_partitions (char **root_devs)
> +{
> +  const char *first_part;
> +  char **p;
> +
> +  if (!root_devs[1])
> +    return 1;
> +
> +  first_part = find_part_sep (root_devs[0]);
> +  for (p = root_devs + 1; *p; p++)
> +    {
> +      const char *part = find_part_sep (*p);
> +
> +      if ((first_part == NULL) ^ (part == NULL))
> +	return 0;
> +      if (!first_part && !part)
> +	continue;
> +      if (strcmp (first_part, part))
> +	return 0;
>      }
> +
> +  return 1;
>  }
>  
>  static char *
> @@ -835,6 +871,8 @@ main (int argc, char *argv[])
>    int efidir_is_mac = 0;
>    int is_prep = 0;
>    const char *pkgdatadir;
> +  size_t i;
> +
>  
>    grub_util_host_init (&argc, &argv);
>    product_version = xstrdup (PACKAGE_VERSION);
> @@ -926,12 +964,26 @@ main (int argc, char *argv[])
>    switch (platform)
>      {
>      case GRUB_INSTALL_PLATFORM_I386_PC:
> +      break;
> +
> +    default:
> +      if (n_install_devices > 1)
> +	grub_util_error ("%s", _("More than one install device?"));
> +      break;
> +    }
> +
> +  switch (platform)
> +    {
> +    case GRUB_INSTALL_PLATFORM_I386_PC:
> +      if (!install_devices)
> +	install_bootsector = 0;
> +      break;
>      case GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275:
> -      if (!install_device)
> +      if (!install_devices)
>  	grub_util_error ("%s", _("install device isn't specified"));
>        break;
>      case GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275:
> -      if (install_device)
> +      if (install_devices)
>  	is_prep = 1;
>        break;
>      case GRUB_INSTALL_PLATFORM_MIPS_ARC:
> @@ -952,8 +1004,11 @@ main (int argc, char *argv[])
>      case GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS:
>      case GRUB_INSTALL_PLATFORM_I386_XEN:
>      case GRUB_INSTALL_PLATFORM_X86_64_XEN:
> -      free (install_device);
> -      install_device = NULL;
> +      for (i = 0; i < n_install_devices; i++)
> +	free (install_devices[i]);
> +      free (install_devices);
> +      install_devices = NULL;
> +      n_install_devices = n_allocated_devices = 0;
>        break;
>  
>        /* pacify warning.  */
> @@ -996,11 +1051,6 @@ main (int argc, char *argv[])
>        is_efi = 1;
>        break;
>      default:
> -      is_efi = 0;
> -      break;
> -
> -      /* pacify warning.  */
> -    case GRUB_INSTALL_PLATFORM_MAX:
>        break;
>      }
>  
> @@ -1009,8 +1059,6 @@ main (int argc, char *argv[])
>    if (is_efi)
>      {
>        grub_fs_t fs;
> -      free (install_device);
> -      install_device = NULL;
>        if (!efidir)
>  	{
>  	  char *d = grub_util_path_concat (2, bootdir, "efi");
> @@ -1045,7 +1093,9 @@ main (int argc, char *argv[])
>        if (!efidir_device_names || !efidir_device_names[0])
>  	grub_util_error (_("cannot find a device for %s (is /dev mounted?)"),
>  			     efidir);
> -      install_device = efidir_device_names[0];
> +      /* FIXME free install_devices */
> +      /* We will use just the first device */
> +      install_devices = efidir_device_names;
>  
>        for (curdev = efidir_device_names; *curdev; curdev++)
>  	  grub_util_pull_device (*curdev);
> @@ -1207,7 +1257,9 @@ main (int argc, char *argv[])
>  	  if (grub_strcmp (fs->name, "hfs") == 0
>  	      || grub_strcmp (fs->name, "hfsplus") == 0)
>  	    {
> -	      install_device = macppcdir_device_names[0];
> +	      /* FIXME free install_devices */
> +	      /* We just use the first one */
> +	      install_devices = macppcdir_device_names;
>  	      is_prep = 0;
>  	    }
>  	}
> @@ -1318,35 +1370,37 @@ main (int argc, char *argv[])
>  	      debug_image);
>      }
>    char *prefix_drive = NULL;
> -  char *install_drive = NULL;
>  
> -  if (install_device)
> +  if (install_devices)
>      {
> -      if (install_device[0] == '('
> -	  && install_device[grub_strlen (install_device) - 1] == ')')
> -        {
> -	  size_t len = grub_strlen (install_device) - 2;
> -	  install_drive = xmalloc (len + 1);
> -	  memcpy (install_drive, install_device + 1, len);
> -	  install_drive[len] = '\0';
> -        }
> -      else
> -	{
> -	  grub_util_pull_device (install_device);
> -	  install_drive = grub_util_get_grub_dev (install_device);
> -	  if (!install_drive)
> -	    grub_util_error (_("cannot find a GRUB drive for %s.  Check your device.map"),
> -			     install_device);
> -	}
> +      install_drives = xmalloc (n_install_devices * sizeof (*install_drives));
> +
> +      for (i = 0; i < n_install_devices; i++)
> +	if (install_devices[i][0] == '('
> +	    && install_devices[i][grub_strlen (install_devices[i]) - 1] == ')')
> +	  {
> +	    size_t len = grub_strlen (install_devices[i]) - 2;
> +	    install_drives[i] = xmalloc (len + 1);
> +	    memcpy (install_drives[i], install_devices[i] + 1, len);
> +	    install_drives[i][len] = '\0';
> +	  }
> +	else
> +	  {
> +	    grub_util_pull_device (install_devices[i]);
> +	    install_drives[i] = grub_util_get_grub_dev (install_devices[i]);
> +	    if (!install_drives[i])
> +	      grub_util_error (_("cannot find a GRUB drive for %s.  Check your device.map"),
> +			       install_devices[i]);
> +	  }
>      }
>  
>    if (!have_abstractions)
>      {
>        if ((disk_module && grub_strcmp (disk_module, "biosdisk") != 0)
> -	  || grub_drives[1]
> -	  || (!install_drive
> +	  || (grub_drives[1] && !same_partitions (grub_drives))
> +	  || (!install_drives
>  	      && platform != GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275)
> -	  || (install_drive && !is_same_disk (grub_drives[0], install_drive))
> +	  || (install_drives && !same_disks (grub_drives))
>  	  || !have_bootdev (platform))
>  	{
>  	  char *uuid = NULL;
> @@ -1656,24 +1710,27 @@ main (int argc, char *argv[])
>  					      "boot.img");
>  	grub_install_copy_file (boot_img_src, boot_img, 1);
>  
> -	grub_util_info ("%sgrub-bios-setup %s %s %s %s %s --directory='%s' --device-map='%s' '%s'",
> -			/* TRANSLATORS: This is a prefix in the log to indicate that usually
> -			   a command would be executed but due to an option was skipped.  */
> -			install_bootsector ? "" : _("NOT RUNNING: "),
> -			allow_floppy ? "--allow-floppy " : "",
> -			verbosity ? "--verbose " : "",
> -			force ? "--force " : "",
> -			!fs_probe ? "--skip-fs-probe" : "",
> -			!add_rs_codes ? "--no-rs-codes" : "",
> -			platdir,
> -			device_map,
> -			install_device);
> -			
> -	/*  Now perform the installation.  */
> -	if (install_bootsector)
> -	  grub_util_bios_setup (platdir, "boot.img", "core.img",
> -				install_drive, force,
> -				fs_probe, allow_floppy, add_rs_codes);
> +	for (i = 0; i < n_install_devices; i++)
> +	  {
> +	    grub_util_info ("%sgrub-bios-setup %s %s %s %s %s --directory='%s' --device-map='%s' '%s'",
> +			    /* TRANSLATORS: This is a prefix in the log to indicate that usually
> +			       a command would be executed but due to an option was skipped.  */
> +			    install_bootsector ? "" : _("NOT RUNNING: "),
> +			    allow_floppy ? "--allow-floppy " : "",
> +			    verbosity ? "--verbose " : "",
> +			    force ? "--force " : "",
> +			    !fs_probe ? "--skip-fs-probe" : "",
> +			    !add_rs_codes ? "--no-rs-codes" : "",
> +			    platdir,
> +			    device_map,
> +			    install_devices[i]);
> +
> +	    /*  Now perform the installation.  */
> +	    if (install_bootsector)
> +	      grub_util_bios_setup (platdir, "boot.img", "core.img",
> +				    install_drives[i], force,
> +				    fs_probe, allow_floppy, add_rs_codes);
> +	  }
>  	break;
>        }
>      case GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275:
> @@ -1693,12 +1750,12 @@ main (int argc, char *argv[])
>  			!fs_probe ? "--skip-fs-probe" : "",
>  			platdir,
>  			device_map,
> -			install_drive);
> +			install_drives[0]);
>  			
>  	/*  Now perform the installation.  */
>  	if (install_bootsector)
>  	  grub_util_sparc_setup (platdir, "boot.img", "core.img",
> -				 install_device, force,
> +				 install_devices[0], force,
>  				 fs_probe, allow_floppy,
>  				 0 /* unused */ );
>  	break;
> @@ -1734,7 +1791,7 @@ main (int argc, char *argv[])
>  
>  	  fill_core_services (core_services);
>  
> -	  ins_dev = grub_device_open (install_drive);
> +	  ins_dev = grub_device_open (install_drives[0]);
>  
>  	  bless (ins_dev, core_services, 0);
>  
> @@ -1745,7 +1802,7 @@ main (int argc, char *argv[])
>  
>  	      partno = ins_dev->disk->partition
>  		? ins_dev->disk->partition->number + 1 : 0;
> -	      dev = grub_util_get_os_disk (install_device);
> +	      dev = grub_util_get_os_disk (install_devices[0]);
>  	      grub_install_register_ieee1275 (0, dev, partno,
>  					      "\\\\BootX");
>  	    }
> @@ -1757,10 +1814,10 @@ main (int argc, char *argv[])
>  	  break;
>  	}
>        /* If a install device is defined, copy the core.elf to PReP partition.  */
> -      if (is_prep && install_device && install_device[0])
> +      if (is_prep)
>  	{
>  	  grub_device_t ins_dev;
> -	  ins_dev = grub_device_open (install_drive);
> +	  ins_dev = grub_device_open (install_drives[0]);
>  	  if (!ins_dev || !is_prep_partition (ins_dev))
>  	    {
>  	      grub_util_error ("%s", _("the chosen partition is not a PReP partition"));
> @@ -1772,13 +1829,13 @@ main (int argc, char *argv[])
>  	    }
>  	  else
>  	    {
> -	      char *s = xasprintf ("dd if=/dev/zero of=%s", install_device);
> +	      char *s = xasprintf ("dd if=/dev/zero of=%s", install_devices[0]);
>  	      grub_util_error (_("the PReP partition is not empty. If you are sure you want to use it, run dd to clear it: `%s'"),
>  			       s);
>  	    }
>  	  grub_device_close (ins_dev);
>  	  if (update_nvram)
> -	    grub_install_register_ieee1275 (1, grub_util_get_os_disk (install_device),
> +	    grub_install_register_ieee1275 (1, grub_util_get_os_disk (install_devices[0]),
>  					    0, NULL);
>  	  break;
>        }
> @@ -1798,7 +1855,7 @@ main (int argc, char *argv[])
>  	}
>        break;
>      case GRUB_INSTALL_PLATFORM_MIPS_ARC:
> -      grub_install_sgi_setup (install_device, imgfile, "grub");
> +      grub_install_sgi_setup (install_devices[0], imgfile, "grub");
>        break;
>  
>      case GRUB_INSTALL_PLATFORM_I386_EFI:
> @@ -1834,7 +1891,7 @@ main (int argc, char *argv[])
>  
>  	  fill_core_services(core_services);
>  
> -	  ins_dev = grub_device_open (install_drive);
> +	  ins_dev = grub_device_open (install_drives[0]);
>  
>  	  bless (ins_dev, boot_efi, 1);
>  	  if (!removable && update_nvram)
> 



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 213 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC] grub-install: allow none or multiple install devices on PC BIOS
  2016-02-12 18:41 ` Vladimir 'φ-coder/phcoder' Serbinenko
@ 2016-02-13  7:27   ` Andrei Borzenkov
  0 siblings, 0 replies; 10+ messages in thread
From: Andrei Borzenkov @ 2016-02-13  7:27 UTC (permalink / raw)
  To: grub-devel


[-- Attachment #1.1: Type: text/plain, Size: 2355 bytes --]

12.02.2016 21:41, Vladimir 'φ-coder/phcoder' Serbinenko пишет:
> On 08.05.2015 20:53, Andrei Borzenkov wrote:
>> There are two main applications.
>>
>> 1. Omit install device to create generic image intended for chainloading
>> from other master loader. Such image can be put on any device (or file
>> system) and will still be able to find its $root. Currently even with
>> --no-bootsector grub-install optimizes image by skipping UUID search if
>> possible.
>>
>> 2. Redundant installation on multi-device filesystem, RAID or similar.
>> This allows both optimizing image w.r.t. to using --prefix vs. load.cfg
>> as well as creating image just once.
>>
>> Patch allows transparently use none or multiple installation devices,
>> similar to
>>
>> grub_devices="/dev/sda /dev/sda1 /dev/sdb"
>> grub-install $grub_devices
>>
>> where grub_devices can be empty and still do the right thing.
>>
>> This is work in progress, although it is functionally complete and just
>> needs some cleanups.
>>
>> Comments?
> I like the idea and it was on my "nice to have" list for some time. Do
> you want to clean it up first or should I review this version?


I updated it to the current master with small cleanup. See attached.
Open questions

- we probably should not allow empty install list by default. This is
too error prone to have grub-install silently succeed leaving unbootable
system. Should we add special argument or --force will do?

- it still may be useful to be able to force UUID search instead of
encoding partition number irrespectively of install device locations.
But that is separate topic.

- messages from grub-setup need now qualification with device. It is
otherwise confusing when you have several devices and do not know which
one it refers to.

- for completeness this should really be pushed into grub-bios-setup as
well. But this is a lot of work for rather small gain (only when
installing on multiple partitions on the same disk). Most common
applications I had in mind are zero install devices or different disks
in RAID.

- this makes grub-install even less atomic than it is now. It would be
really useful to have framework for alternative /boot/grub locations so
that boot sector always refers to valid boot location. Or notion of
"undo" where we could revert changes.

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.2: optional-install-device.patch --]
[-- Type: text/x-patch; name="optional-install-device.patch", Size: 14346 bytes --]

From: Andrei Borzenkov <arvidjaar@gmail.com>
Subject: [PATCH] grub-install: allow none or multiple install devices on PC BIOS

There are two main applications.

1. Omit install device to create generic image intended for chainloading
from other master loader. Such image can be put on any device (or file
system) and will still be able to find its $root. Currently even with
--no-bootsector grub-install optimizes image by skipping UUID search if
possible.

2. Redundant installation on multi-device filesystem, RAID or similar.
This allows both optimizing image w.r.t. to using --prefix vs. load.cfg
as well as creating image just once.

Patch allows transparently use none or multiple installation devices,
similar to

grub_devices="/dev/sda /dev/sda1 /dev/sdb"
grub-install $grub_devices

where grub_devices can be empty and still do the right thing.

---
 grub-core/kern/disk.c |   9 ++-
 include/grub/disk.h   |   2 +
 util/grub-install.c   | 202 ++++++++++++++++++++++++++++----------------------
 3 files changed, 122 insertions(+), 91 deletions(-)

diff --git a/grub-core/kern/disk.c b/grub-core/kern/disk.c
index 789f8c0..29e39a5 100644
--- a/grub-core/kern/disk.c
+++ b/grub-core/kern/disk.c
@@ -168,8 +168,11 @@ grub_disk_dev_unregister (grub_disk_dev_t dev)
 
 /* Return the location of the first ',', if any, which is not
    escaped by a '\'.  */
-static const char *
-find_part_sep (const char *name)
+#if !defined (GRUB_UTIL)
+static
+#endif
+const char *
+grub_find_part_sep (const char *name)
 {
   const char *p = name;
   char c;
@@ -203,7 +206,7 @@ grub_disk_open (const char *name)
   disk->max_agglomerate = 1048576 >> (GRUB_DISK_SECTOR_BITS
 				      + GRUB_DISK_CACHE_BITS);
 
-  p = find_part_sep (name);
+  p = grub_find_part_sep (name);
   if (p)
     {
       grub_size_t len = p - name;
diff --git a/include/grub/disk.h b/include/grub/disk.h
index b385af8..254c920 100644
--- a/include/grub/disk.h
+++ b/include/grub/disk.h
@@ -256,6 +256,8 @@ void grub_ldm_fini (void);
 void grub_mdraid09_fini (void);
 void grub_mdraid1x_fini (void);
 void grub_diskfilter_fini (void);
+const char *grub_find_part_sep (const char *);
+
 #endif
 
 #endif /* ! GRUB_DISK_HEADER */
diff --git a/util/grub-install.c b/util/grub-install.c
index 6c89c2b..9a0919c 100644
--- a/util/grub-install.c
+++ b/util/grub-install.c
@@ -57,7 +57,10 @@ static char *target;
 static int removable = 0;
 static int recheck = 0;
 static int update_nvram = 1;
-static char *install_device = NULL;
+static char **install_devices = NULL;
+static char **install_drives = NULL;
+static int n_install_devices;
+static int n_allocated_devices;
 static char *debug_image = NULL;
 static char *rootdir = NULL;
 static char *bootdir = NULL;
@@ -234,9 +237,12 @@ argp_parser (int key, char *arg, struct argp_state *state)
       return 0;
 
     case ARGP_KEY_ARG:
-      if (install_device)
-	grub_util_error ("%s", _("More than one install device?"));
-      install_device = xstrdup (arg);
+      if (n_install_devices >= n_allocated_devices)
+	{
+	  n_allocated_devices += 16;
+	  install_devices = xrealloc (install_devices, n_allocated_devices);
+	}
+      install_devices[n_install_devices++] = xstrdup (arg);
       return 0;
 
     default:
@@ -534,25 +540,22 @@ probe_cryptodisk_uuid (grub_disk_t disk)
 }
 
 static int
-is_same_disk (const char *a, const char *b)
+is_same_disk (const char *root, char **install_devs)
 {
-  while (1)
+  char **d;
+  const char *root_part = grub_find_part_sep (root);
+  size_t root_len = root_part ? root_part - root : strlen (root);
+
+  for (d = install_devs; *d; d++)
     {
-      if ((*a == ',' || *a == '\0') && (*b == ',' || *b == '\0'))
-	return 1;
-      if (*a != *b)
+      const char *p = grub_find_part_sep (*d);
+      size_t len = p ? p - *d : strlen (*d);
+
+      if (len != root_len || (len && strncmp (root, *d, len)))
 	return 0;
-      if (*a == '\\')
-	{
-	  if (a[1] != b[1])
-	    return 0;
-	  a += 2;
-	  b += 2;
-	  continue;
-	}
-      a++;
-      b++;
     }
+
+  return 1;
 }
 
 static char *
@@ -815,6 +818,21 @@ fill_core_services (const char *core_services)
   free (sysv_plist);
 }
 
+static void
+free_install_devices (void)
+{
+  size_t i;
+
+  if (!install_devices)
+    return;
+
+  for (i = 0; i < n_install_devices; i++)
+    free (install_devices[i]);
+  free (install_devices);
+  install_devices = NULL;
+  n_install_devices = n_allocated_devices = 0;
+}
+
 int
 main (int argc, char *argv[])
 {
@@ -835,6 +853,8 @@ main (int argc, char *argv[])
   int efidir_is_mac = 0;
   int is_prep = 0;
   const char *pkgdatadir;
+  size_t i;
+
 
   grub_util_host_init (&argc, &argv);
   product_version = xstrdup (PACKAGE_VERSION);
@@ -926,14 +946,25 @@ main (int argc, char *argv[])
   switch (platform)
     {
     case GRUB_INSTALL_PLATFORM_I386_PC:
+      break;
+
+    default:
+      if (n_install_devices > 1)
+	grub_util_error ("%s", _("More than one install device?"));
+      break;
+    }
+
+  switch (platform)
+    {
     case GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275:
-      if (!install_device)
+      if (!install_devices)
 	grub_util_error ("%s", _("install device isn't specified"));
       break;
     case GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275:
-      if (install_device)
+      if (install_devices)
 	is_prep = 1;
       break;
+    case GRUB_INSTALL_PLATFORM_I386_PC:
     case GRUB_INSTALL_PLATFORM_MIPS_ARC:
     case GRUB_INSTALL_PLATFORM_MIPSEL_ARC:
       break;
@@ -952,8 +983,7 @@ main (int argc, char *argv[])
     case GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS:
     case GRUB_INSTALL_PLATFORM_I386_XEN:
     case GRUB_INSTALL_PLATFORM_X86_64_XEN:
-      free (install_device);
-      install_device = NULL;
+      free_install_devices ();
       break;
 
       /* pacify warning.  */
@@ -1009,8 +1039,6 @@ main (int argc, char *argv[])
   if (is_efi)
     {
       grub_fs_t fs;
-      free (install_device);
-      install_device = NULL;
       if (!efidir)
 	{
 	  char *d = grub_util_path_concat (2, bootdir, "efi");
@@ -1045,7 +1073,8 @@ main (int argc, char *argv[])
       if (!efidir_device_names || !efidir_device_names[0])
 	grub_util_error (_("cannot find a device for %s (is /dev mounted?)"),
 			     efidir);
-      install_device = efidir_device_names[0];
+      /* We will use just the first device */
+      install_devices = efidir_device_names;
 
       for (curdev = efidir_device_names; *curdev; curdev++)
 	  grub_util_pull_device (*curdev);
@@ -1207,7 +1236,9 @@ main (int argc, char *argv[])
 	  if (grub_strcmp (fs->name, "hfs") == 0
 	      || grub_strcmp (fs->name, "hfsplus") == 0)
 	    {
-	      install_device = macppcdir_device_names[0];
+	      /* We just use the first one */
+	      free_install_devices ();
+	      install_devices = macppcdir_device_names;
 	      is_prep = 0;
 	    }
 	}
@@ -1319,35 +1350,38 @@ main (int argc, char *argv[])
 	      debug_image);
     }
   char *prefix_drive = NULL;
-  char *install_drive = NULL;
 
-  if (install_device)
+  if (install_devices)
     {
-      if (install_device[0] == '('
-	  && install_device[grub_strlen (install_device) - 1] == ')')
-        {
-	  size_t len = grub_strlen (install_device) - 2;
-	  install_drive = xmalloc (len + 1);
-	  memcpy (install_drive, install_device + 1, len);
-	  install_drive[len] = '\0';
-        }
-      else
-	{
-	  grub_util_pull_device (install_device);
-	  install_drive = grub_util_get_grub_dev (install_device);
-	  if (!install_drive)
-	    grub_util_error (_("cannot find a GRUB drive for %s.  Check your device.map"),
-			     install_device);
-	}
+      install_drives = xmalloc ((n_install_devices + 1) * sizeof (*install_drives));
+
+      for (i = 0; i < n_install_devices; i++)
+	if (install_devices[i][0] == '('
+	    && install_devices[i][grub_strlen (install_devices[i]) - 1] == ')')
+	  {
+	    size_t len = grub_strlen (install_devices[i]) - 2;
+	    install_drives[i] = xmalloc (len + 1);
+	    memcpy (install_drives[i], install_devices[i] + 1, len);
+	    install_drives[i][len] = '\0';
+	  }
+	else
+	  {
+	    grub_util_pull_device (install_devices[i]);
+	    install_drives[i] = grub_util_get_grub_dev (install_devices[i]);
+	    if (!install_drives[i])
+	      grub_util_error (_("cannot find a GRUB drive for %s.  Check your device.map"),
+			       install_devices[i]);
+	  }
+      install_drives[n_install_devices] = NULL;
     }
 
   if (!have_abstractions)
     {
       if ((disk_module && grub_strcmp (disk_module, "biosdisk") != 0)
 	  || grub_drives[1]
-	  || (!install_drive
+	  || (!install_drives
 	      && platform != GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275)
-	  || (install_drive && !is_same_disk (grub_drives[0], install_drive))
+	  || (install_drives && !is_same_disk (grub_drives[0], install_drives))
 	  || !have_bootdev (platform))
 	{
 	  char *uuid = NULL;
@@ -1480,19 +1514,8 @@ main (int argc, char *argv[])
       else
 	{
 	  /* We need to hardcode the partition number in the core image's prefix.  */
-	  char *p;
-	  for (p = grub_drives[0]; *p; )
-	    {
-	      if (*p == '\\' && p[1])
-		{
-		  p += 2;
-		  continue;
-		}
-	      if (*p == ',' || *p == '\0')
-		break;
-	      p++;
-	    }
-	  prefix_drive = xasprintf ("(%s)", p);
+	  const char *p = grub_find_part_sep (grub_drives[0]);
+	  prefix_drive = xasprintf ("(%s)", p ?: "");
 	}
     }
   else
@@ -1657,24 +1680,27 @@ main (int argc, char *argv[])
 					      "boot.img");
 	grub_install_copy_file (boot_img_src, boot_img, 1);
 
-	grub_util_info ("%sgrub-bios-setup %s %s %s %s %s --directory='%s' --device-map='%s' '%s'",
-			/* TRANSLATORS: This is a prefix in the log to indicate that usually
-			   a command would be executed but due to an option was skipped.  */
-			install_bootsector ? "" : _("NOT RUNNING: "),
-			allow_floppy ? "--allow-floppy " : "",
-			verbosity ? "--verbose " : "",
-			force ? "--force " : "",
-			!fs_probe ? "--skip-fs-probe" : "",
-			!add_rs_codes ? "--no-rs-codes" : "",
-			platdir,
-			device_map,
-			install_device);
-			
-	/*  Now perform the installation.  */
-	if (install_bootsector)
-	  grub_util_bios_setup (platdir, "boot.img", "core.img",
-				install_drive, force,
-				fs_probe, allow_floppy, add_rs_codes);
+	for (i = 0; i < n_install_devices; i++)
+	  {
+	    grub_util_info ("%sgrub-bios-setup %s %s %s %s %s --directory='%s' --device-map='%s' '%s'",
+			    /* TRANSLATORS: This is a prefix in the log to indicate that usually
+			       a command would be executed but due to an option was skipped.  */
+			    install_bootsector ? "" : _("NOT RUNNING: "),
+			    allow_floppy ? "--allow-floppy " : "",
+			    verbosity ? "--verbose " : "",
+			    force ? "--force " : "",
+			    !fs_probe ? "--skip-fs-probe" : "",
+			    !add_rs_codes ? "--no-rs-codes" : "",
+			    platdir,
+			    device_map,
+			    install_devices[i]);
+
+	    /*  Now perform the installation.  */
+	    if (install_bootsector)
+	      grub_util_bios_setup (platdir, "boot.img", "core.img",
+				    install_drives[i], force,
+				    fs_probe, allow_floppy, add_rs_codes);
+	  }
 	break;
       }
     case GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275:
@@ -1694,12 +1720,12 @@ main (int argc, char *argv[])
 			!fs_probe ? "--skip-fs-probe" : "",
 			platdir,
 			device_map,
-			install_drive);
+			install_drives[0]);
 			
 	/*  Now perform the installation.  */
 	if (install_bootsector)
 	  grub_util_sparc_setup (platdir, "boot.img", "core.img",
-				 install_drive, force,
+				 install_drives[0], force,
 				 fs_probe, allow_floppy,
 				 0 /* unused */ );
 	break;
@@ -1735,7 +1761,7 @@ main (int argc, char *argv[])
 
 	  fill_core_services (core_services);
 
-	  ins_dev = grub_device_open (install_drive);
+	  ins_dev = grub_device_open (install_drives[0]);
 
 	  bless (ins_dev, core_services, 0);
 
@@ -1746,7 +1772,7 @@ main (int argc, char *argv[])
 
 	      partno = ins_dev->disk->partition
 		? ins_dev->disk->partition->number + 1 : 0;
-	      dev = grub_util_get_os_disk (install_device);
+	      dev = grub_util_get_os_disk (install_devices[0]);
 	      grub_install_register_ieee1275 (0, dev, partno,
 					      "\\\\BootX");
 	    }
@@ -1758,10 +1784,10 @@ main (int argc, char *argv[])
 	  break;
 	}
       /* If a install device is defined, copy the core.elf to PReP partition.  */
-      if (is_prep && install_device && install_device[0])
+      if (is_prep)
 	{
 	  grub_device_t ins_dev;
-	  ins_dev = grub_device_open (install_drive);
+	  ins_dev = grub_device_open (install_drives[0]);
 	  if (!ins_dev || !is_prep_partition (ins_dev))
 	    {
 	      grub_util_error ("%s", _("the chosen partition is not a PReP partition"));
@@ -1773,13 +1799,13 @@ main (int argc, char *argv[])
 	    }
 	  else
 	    {
-	      char *s = xasprintf ("dd if=/dev/zero of=%s", install_device);
+	      char *s = xasprintf ("dd if=/dev/zero of=%s", install_devices[0]);
 	      grub_util_error (_("the PReP partition is not empty. If you are sure you want to use it, run dd to clear it: `%s'"),
 			       s);
 	    }
 	  grub_device_close (ins_dev);
 	  if (update_nvram)
-	    grub_install_register_ieee1275 (1, grub_util_get_os_disk (install_device),
+	    grub_install_register_ieee1275 (1, grub_util_get_os_disk (install_devices[0]),
 					    0, NULL);
 	  break;
       }
@@ -1799,7 +1825,7 @@ main (int argc, char *argv[])
 	}
       break;
     case GRUB_INSTALL_PLATFORM_MIPS_ARC:
-      grub_install_sgi_setup (install_device, imgfile, "grub");
+      grub_install_sgi_setup (install_devices[0], imgfile, "grub");
       break;
 
     case GRUB_INSTALL_PLATFORM_I386_EFI:
@@ -1835,7 +1861,7 @@ main (int argc, char *argv[])
 
 	  fill_core_services(core_services);
 
-	  ins_dev = grub_device_open (install_drive);
+	  ins_dev = grub_device_open (install_drives[0]);
 
 	  bless (ins_dev, boot_efi, 1);
 	  if (!removable && update_nvram)
-- 
tg: (080a208..) u/optional-install-device (depends on: master)

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [RFC] grub-install: allow none or multiple install devices on PC BIOS
  2015-05-12 15:22     ` Michael Chang
@ 2016-02-13  7:29       ` Andrei Borzenkov
  2016-02-16  4:11         ` Michael Chang
  0 siblings, 1 reply; 10+ messages in thread
From: Andrei Borzenkov @ 2016-02-13  7:29 UTC (permalink / raw)
  To: grub-devel

12.05.2015 18:22, Michael Chang пишет:
> On Tue, May 12, 2015 at 02:57:00PM +0300, Andrei Borzenkov wrote:
>> В Tue, 12 May 2015 18:52:22 +0800
>> Michael Chang <mchang@suse.com> пишет:
>>
>>> On Fri, May 08, 2015 at 09:53:41PM +0300, Andrei Borzenkov wrote:
>>>> There are two main applications.
>>>>
>>>> 1. Omit install device to create generic image intended for chainloading
>>>> from other master loader. Such image can be put on any device (or file
>>>> system) and will still be able to find its $root. Currently even with
>>>> --no-bootsector grub-install optimizes image by skipping UUID search if
>>>> possible.
>>>>
>>
>> Actually I think it is useful for all platforms.
> 
> As it works across all platform, os-prober should consider chanloading
> core images if possible rather than digging into grub configs. Is there
> any plan for that ?
> 

At least on EFI it is not possible to chainload GRUB from /boot until it
supports multiboot; and even then it will be multiboot2, so it means
separate commands. We have enough issues with efi-specific linux loaders :(



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC] grub-install: allow none or multiple install devices on PC BIOS
  2016-02-13  7:29       ` Andrei Borzenkov
@ 2016-02-16  4:11         ` Michael Chang
  2016-02-16 18:11           ` Andrei Borzenkov
  0 siblings, 1 reply; 10+ messages in thread
From: Michael Chang @ 2016-02-16  4:11 UTC (permalink / raw)
  To: The development of GNU GRUB

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

On Sat, Feb 13, 2016 at 10:29:58AM +0300, Andrei Borzenkov wrote:
> 12.05.2015 18:22, Michael Chang пишет:
> > On Tue, May 12, 2015 at 02:57:00PM +0300, Andrei Borzenkov wrote:
> >> В Tue, 12 May 2015 18:52:22 +0800
> >> Michael Chang <mchang@suse.com> пишет:
> >>
> >>> On Fri, May 08, 2015 at 09:53:41PM +0300, Andrei Borzenkov wrote:
> >>>> There are two main applications.
> >>>>
> >>>> 1. Omit install device to create generic image intended for chainloading
> >>>> from other master loader. Such image can be put on any device (or file
> >>>> system) and will still be able to find its $root. Currently even with
> >>>> --no-bootsector grub-install optimizes image by skipping UUID search if
> >>>> possible.
> >>>>
> >>
> >> Actually I think it is useful for all platforms.
> > 
> > As it works across all platform, os-prober should consider chanloading
> > core images if possible rather than digging into grub configs. Is there
> > any plan for that ?
> > 
> 
> At least on EFI it is not possible to chainload GRUB from /boot until it

I'm skeptical to this. From what I know it's possible because grub's efi
chainloader reads efi image via it's own filesystem support, so that it
did not limited by what firmware could offer. And LoadImage can accept
SourceBuffer as an option to pass the pointer of loaded image buffer
directly.

Honestly I didn't really test it, but glancing at the source code it
sounds promoising to work to me.

Thanks,
Michael

> supports multiboot; and even then it will be multiboot2, so it means
> separate commands. We have enough issues with efi-specific linux loaders :(
> 
> 
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> https://lists.gnu.org/mailman/listinfo/grub-devel

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [RFC] grub-install: allow none or multiple install devices on PC BIOS
  2016-02-16  4:11         ` Michael Chang
@ 2016-02-16 18:11           ` Andrei Borzenkov
  0 siblings, 0 replies; 10+ messages in thread
From: Andrei Borzenkov @ 2016-02-16 18:11 UTC (permalink / raw)
  To: grub-devel

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

16.02.2016 07:11, Michael Chang пишет:
> On Sat, Feb 13, 2016 at 10:29:58AM +0300, Andrei Borzenkov wrote:
>> 12.05.2015 18:22, Michael Chang пишет:
>>> On Tue, May 12, 2015 at 02:57:00PM +0300, Andrei Borzenkov wrote:
>>>> В Tue, 12 May 2015 18:52:22 +0800
>>>> Michael Chang <mchang@suse.com> пишет:
>>>>
>>>>> On Fri, May 08, 2015 at 09:53:41PM +0300, Andrei Borzenkov wrote:
>>>>>> There are two main applications.
>>>>>>
>>>>>> 1. Omit install device to create generic image intended for chainloading
>>>>>> from other master loader. Such image can be put on any device (or file
>>>>>> system) and will still be able to find its $root. Currently even with
>>>>>> --no-bootsector grub-install optimizes image by skipping UUID search if
>>>>>> possible.
>>>>>>
>>>>
>>>> Actually I think it is useful for all platforms.
>>>
>>> As it works across all platform, os-prober should consider chanloading
>>> core images if possible rather than digging into grub configs. Is there
>>> any plan for that ?
>>>
>>
>> At least on EFI it is not possible to chainload GRUB from /boot until it
> 
> I'm skeptical to this. From what I know it's possible because grub's efi
> chainloader reads efi image via it's own filesystem support, so that it
> did not limited by what firmware could offer. And LoadImage can accept
> SourceBuffer as an option to pass the pointer of loaded image buffer
> directly.
> 
> Honestly I didn't really test it, but glancing at the source code it
> sounds promoising to work to me.
> 

Yes, indeed. I'm not sure what went wrong last time I tried it; I had
problem with device path.

Still, this is core.img vs. core.elf, which means it is platform dependent.


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2016-02-16 18:11 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-05-08 18:53 [RFC] grub-install: allow none or multiple install devices on PC BIOS Andrei Borzenkov
2015-05-12 10:52 ` Michael Chang
2015-05-12 11:57   ` Andrei Borzenkov
2015-05-12 14:57     ` Michael Chang
2015-05-12 15:22     ` Michael Chang
2016-02-13  7:29       ` Andrei Borzenkov
2016-02-16  4:11         ` Michael Chang
2016-02-16 18:11           ` Andrei Borzenkov
2016-02-12 18:41 ` Vladimir 'φ-coder/phcoder' Serbinenko
2016-02-13  7:27   ` Andrei Borzenkov

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).