From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from list by lists.gnu.org with archive (Exim 4.71) id 1aUUcH-00077P-0G for mharc-grub-devel@gnu.org; Sat, 13 Feb 2016 02:27:41 -0500 Received: from eggs.gnu.org ([2001:4830:134:3::10]:46267) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aUUcD-00077C-Ht for grub-devel@gnu.org; Sat, 13 Feb 2016 02:27:39 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1aUUcA-0004JO-8R for grub-devel@gnu.org; Sat, 13 Feb 2016 02:27:37 -0500 Received: from mail-lb0-x232.google.com ([2a00:1450:4010:c04::232]:33844) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1aUUc9-0004JH-QE for grub-devel@gnu.org; Sat, 13 Feb 2016 02:27:34 -0500 Received: by mail-lb0-x232.google.com with SMTP id aj3so8772368lbd.1 for ; Fri, 12 Feb 2016 23:27:33 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=subject:to:references:from:message-id:date:user-agent:mime-version :in-reply-to:content-type; bh=kFpx6dBqZ4C476nZb+FA5AgeDr2DXv8DaSQTMG4MuSs=; b=SD6NqjFIIsrH3+c55oLOPMjolwjTNYmI/9sVM9fdTjks74Fd3C7eZ7E6W7tY4S9p/A 1I0Z6bOBCMs5du+EDxbwCJH/fKhNpjprsedg2wvue/WcBThMuCBFntDIJvb8uAv9inMR CC+YTYqKuJr9QQBS0U9d/X0cMxBHA9ZGWfY7vVpzheCXjrQNc1A/yTxtcn0A1dcPqWlj wENVw5WMeMxn0kfdvDVdIMQ2tXsg8HilTMSp7hkAs2ZxnYj0yxfuRLzzQY5/7jEev0sC AsVJlHJWl91Uxv4MxuopTfD07ofuuEmW4OJP6Wzswa3ZTd+9s19rFMFx4NsBhRaeURjp BRBw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:subject:to:references:from:message-id:date :user-agent:mime-version:in-reply-to:content-type; bh=kFpx6dBqZ4C476nZb+FA5AgeDr2DXv8DaSQTMG4MuSs=; b=keuenUDT6PMZTwkZ6WV0zn1iUFhZ10bzx2V3nMZO3gMgicUZG++R6NpUUCodvWE87g qKWkqFnPagvi0M3l0bglSl/cXQ8PVSa1JGRTlsVCRle9UTrPjLSPCwhPnqh/KKbA1T/n sQMsL5ao9hkQBrYFJRfJlYRG2gCDggAQwx9K0F2iS2s2hZPfuN7S2Qfm1GYapfQVhTb6 whLhkYSKQXImh6eRgO6koCccamIZwCsrEWySb94+TMU+FaM0z/a453kcTPX5QSKUAjLv 4niwDyx/4B5PNS1g2z+LkwNekARIZUm+U7kb3KWcmbYpGujRa0CdDMyF2Qshdi1Dt1oV Mymg== X-Gm-Message-State: AG10YOSLxgQ/rjyL3PzJGbEVXkvAJDVUiCRuDxUuPKMbkFjRq0sEXtQJaAe13V6BQ2ks6w== X-Received: by 10.112.164.97 with SMTP id yp1mr2440865lbb.30.1455348453045; Fri, 12 Feb 2016 23:27:33 -0800 (PST) Received: from [192.168.1.41] (ppp109-252-76-159.pppoe.spdop.ru. [109.252.76.159]) by smtp.gmail.com with ESMTPSA id i127sm2336248lfd.3.2016.02.12.23.27.31 for (version=TLSv1/SSLv3 cipher=OTHER); Fri, 12 Feb 2016 23:27:32 -0800 (PST) Subject: Re: [RFC] grub-install: allow none or multiple install devices on PC BIOS To: grub-devel@gnu.org References: <1431111221-32399-1-git-send-email-arvidjaar@gmail.com> <56BE2774.60806@gmail.com> From: Andrei Borzenkov X-Enigmail-Draft-Status: N1110 Message-ID: <56BEDAE2.9080402@gmail.com> Date: Sat, 13 Feb 2016 10:27:30 +0300 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:38.0) Gecko/20100101 Thunderbird/38.5.1 MIME-Version: 1.0 In-Reply-To: <56BE2774.60806@gmail.com> Content-Type: multipart/signed; micalg=pgp-sha1; protocol="application/pgp-signature"; boundary="SAmCbQp2SJqXgG9BxAOaVpo377BiiDVGP" X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 2a00:1450:4010:c04::232 X-BeenThere: grub-devel@gnu.org X-Mailman-Version: 2.1.14 Precedence: list Reply-To: The development of GNU GRUB List-Id: The development of GNU GRUB List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 13 Feb 2016 07:27:39 -0000 This is an OpenPGP/MIME signed message (RFC 4880 and 3156) --SAmCbQp2SJqXgG9BxAOaVpo377BiiDVGP Content-Type: multipart/mixed; boundary="------------060006020707050308040809" This is a multi-part message in MIME format. --------------060006020707050308040809 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable 12.02.2016 21:41, Vladimir '=CF=86-coder/phcoder' Serbinenko =D0=BF=D0=B8= =D1=88=D0=B5=D1=82: > On 08.05.2015 20:53, Andrei Borzenkov wrote: >> There are two main applications. >> >> 1. Omit install device to create generic image intended for chainloadi= ng >> 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 i= f >> possible. >> >> 2. Redundant installation on multi-device filesystem, RAID or similar.= >> This allows both optimizing image w.r.t. to using --prefix vs. load.cf= g >> as well as creating image just once. >> >> Patch allows transparently use none or multiple installation devices, >> similar to >> >> grub_devices=3D"/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 jus= t >> 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. --------------060006020707050308040809 Content-Type: text/x-patch; name="optional-install-device.patch" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="optional-install-device.patch" From: Andrei Borzenkov 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=3D"/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) =20 /* 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 =3D name; char c; @@ -203,7 +206,7 @@ grub_disk_open (const char *name) disk->max_agglomerate =3D 1048576 >> (GRUB_DISK_SECTOR_BITS + GRUB_DISK_CACHE_BITS); =20 - p =3D find_part_sep (name); + p =3D grub_find_part_sep (name); if (p) { grub_size_t len =3D 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 =20 #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 =3D 0; static int recheck =3D 0; static int update_nvram =3D 1; -static char *install_device =3D NULL; +static char **install_devices =3D NULL; +static char **install_drives =3D NULL; +static int n_install_devices; +static int n_allocated_devices; static char *debug_image =3D NULL; static char *rootdir =3D NULL; static char *bootdir =3D NULL; @@ -234,9 +237,12 @@ argp_parser (int key, char *arg, struct argp_state *= state) return 0; =20 case ARGP_KEY_ARG: - if (install_device) - grub_util_error ("%s", _("More than one install device?")); - install_device =3D xstrdup (arg); + if (n_install_devices >=3D n_allocated_devices) + { + n_allocated_devices +=3D 16; + install_devices =3D xrealloc (install_devices, n_allocated_devices); + } + install_devices[n_install_devices++] =3D xstrdup (arg); return 0; =20 default: @@ -534,25 +540,22 @@ probe_cryptodisk_uuid (grub_disk_t disk) } =20 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 =3D grub_find_part_sep (root); + size_t root_len =3D root_part ? root_part - root : strlen (root); + + for (d =3D install_devs; *d; d++) { - if ((*a =3D=3D ',' || *a =3D=3D '\0') && (*b =3D=3D ',' || *b =3D=3D= '\0')) - return 1; - if (*a !=3D *b) + const char *p =3D grub_find_part_sep (*d); + size_t len =3D p ? p - *d : strlen (*d); + + if (len !=3D root_len || (len && strncmp (root, *d, len))) return 0; - if (*a =3D=3D '\\') - { - if (a[1] !=3D b[1]) - return 0; - a +=3D 2; - b +=3D 2; - continue; - } - a++; - b++; } + + return 1; } =20 static char * @@ -815,6 +818,21 @@ fill_core_services (const char *core_services) free (sysv_plist); } =20 +static void +free_install_devices (void) +{ + size_t i; + + if (!install_devices) + return; + + for (i =3D 0; i < n_install_devices; i++) + free (install_devices[i]); + free (install_devices); + install_devices =3D NULL; + n_install_devices =3D n_allocated_devices =3D 0; +} + int main (int argc, char *argv[]) { @@ -835,6 +853,8 @@ main (int argc, char *argv[]) int efidir_is_mac =3D 0; int is_prep =3D 0; const char *pkgdatadir; + size_t i; + =20 grub_util_host_init (&argc, &argv); product_version =3D 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 =3D 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 =3D NULL; + free_install_devices (); break; =20 /* pacify warning. */ @@ -1009,8 +1039,6 @@ main (int argc, char *argv[]) if (is_efi) { grub_fs_t fs; - free (install_device); - install_device =3D NULL; if (!efidir) { char *d =3D 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 =3D efidir_device_names[0]; + /* We will use just the first device */ + install_devices =3D efidir_device_names; =20 for (curdev =3D 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") =3D=3D 0 || grub_strcmp (fs->name, "hfsplus") =3D=3D 0) { - install_device =3D macppcdir_device_names[0]; + /* We just use the first one */ + free_install_devices (); + install_devices =3D macppcdir_device_names; is_prep =3D 0; } } @@ -1319,35 +1350,38 @@ main (int argc, char *argv[]) debug_image); } char *prefix_drive =3D NULL; - char *install_drive =3D NULL; =20 - if (install_device) + if (install_devices) { - if (install_device[0] =3D=3D '(' - && install_device[grub_strlen (install_device) - 1] =3D=3D ')') - { - size_t len =3D grub_strlen (install_device) - 2; - install_drive =3D xmalloc (len + 1); - memcpy (install_drive, install_device + 1, len); - install_drive[len] =3D '\0'; - } - else - { - grub_util_pull_device (install_device); - install_drive =3D grub_util_get_grub_dev (install_device); - if (!install_drive) - grub_util_error (_("cannot find a GRUB drive for %s. Check your de= vice.map"), - install_device); - } + install_drives =3D xmalloc ((n_install_devices + 1) * sizeof (*ins= tall_drives)); + + for (i =3D 0; i < n_install_devices; i++) + if (install_devices[i][0] =3D=3D '(' + && install_devices[i][grub_strlen (install_devices[i]) - 1] =3D=3D = ')') + { + size_t len =3D grub_strlen (install_devices[i]) - 2; + install_drives[i] =3D xmalloc (len + 1); + memcpy (install_drives[i], install_devices[i] + 1, len); + install_drives[i][len] =3D '\0'; + } + else + { + grub_util_pull_device (install_devices[i]); + install_drives[i] =3D 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] =3D NULL; } =20 if (!have_abstractions) { if ((disk_module && grub_strcmp (disk_module, "biosdisk") !=3D 0) || grub_drives[1] - || (!install_drive + || (!install_drives && platform !=3D 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 =3D NULL; @@ -1480,19 +1514,8 @@ main (int argc, char *argv[]) else { /* We need to hardcode the partition number in the core image's prefi= x. */ - char *p; - for (p =3D grub_drives[0]; *p; ) - { - if (*p =3D=3D '\\' && p[1]) - { - p +=3D 2; - continue; - } - if (*p =3D=3D ',' || *p =3D=3D '\0') - break; - p++; - } - prefix_drive =3D xasprintf ("(%s)", p); + const char *p =3D grub_find_part_sep (grub_drives[0]); + prefix_drive =3D 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); =20 - grub_util_info ("%sgrub-bios-setup %s %s %s %s %s --directory=3D'%s' --= device-map=3D'%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); - =09 - /* 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 =3D 0; i < n_install_devices; i++) + { + grub_util_info ("%sgrub-bios-setup %s %s %s %s %s --directory=3D'%s= ' --device-map=3D'%s' '%s'", + /* TRANSLATORS: This is a prefix in the log to indicate that usua= lly + 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]); =09 /* 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[]) =20 fill_core_services (core_services); =20 - ins_dev =3D grub_device_open (install_drive); + ins_dev =3D grub_device_open (install_drives[0]); =20 bless (ins_dev, core_services, 0); =20 @@ -1746,7 +1772,7 @@ main (int argc, char *argv[]) =20 partno =3D ins_dev->disk->partition ? ins_dev->disk->partition->number + 1 : 0; - dev =3D grub_util_get_os_disk (install_device); + dev =3D 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 parti= tion. */ - if (is_prep && install_device && install_device[0]) + if (is_prep) { grub_device_t ins_dev; - ins_dev =3D grub_device_open (install_drive); + ins_dev =3D 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 part= ition")); @@ -1773,13 +1799,13 @@ main (int argc, char *argv[]) } else { - char *s =3D xasprintf ("dd if=3D/dev/zero of=3D%s", install_devic= e); + char *s =3D xasprintf ("dd if=3D/dev/zero of=3D%s", install_devic= es[0]); grub_util_error (_("the PReP partition is not empty. If you are s= ure 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_d= evice), + grub_install_register_ieee1275 (1, grub_util_get_os_disk (install_d= evices[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; =20 case GRUB_INSTALL_PLATFORM_I386_EFI: @@ -1835,7 +1861,7 @@ main (int argc, char *argv[]) =20 fill_core_services(core_services); =20 - ins_dev =3D grub_device_open (install_drive); + ins_dev =3D grub_device_open (install_drives[0]); =20 bless (ins_dev, boot_efi, 1); if (!removable && update_nvram) --=20 tg: (080a208..) u/optional-install-device (depends on: master) --------------060006020707050308040809-- --SAmCbQp2SJqXgG9BxAOaVpo377BiiDVGP Content-Type: application/pgp-signature; name="signature.asc" Content-Description: OpenPGP digital signature Content-Disposition: attachment; filename="signature.asc" -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iEYEARECAAYFAla+2uMACgkQR6LMutpd94x0pgCgo6wx4GkvjZf0/7ej0XimcFGe 4ogAoLXAwdJ1GAoK2VBN2H6gFGbbE/r0 =Muf3 -----END PGP SIGNATURE----- --SAmCbQp2SJqXgG9BxAOaVpo377BiiDVGP--