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.
From: Andrei Borzenkov <arvidj...@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: signature.asc
Description: OpenPGP digital signature

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

Reply via email to