From 273559fae459326ff6fccfe5cc026020daf151f6 Mon Sep 17 00:00:00 2001 From: Colin Walters <walters@verbum.org> Date: Fri, 17 Oct 2014 00:01:25 -0400 Subject: [PATCH 2/5] rpmostreepayload: Copy all subdirectories of /usr/lib/ostree-boot Previously we were special casing extlinux/ and grub2/, but this misses out on efi/. To support rpmostreepayload + GRUB2 + EFI, we need special handling here. Any bootloaders installing files in /boot instead of a subdirectory will then need to be special cased (or "fixed"). Now in a perfect world, I'd have a time machine and we could go back and have every bootloader install in a subdirectory /boot/data or something. But we basically can't change existing systems, which kind of traps us into the current RPM-level layout forever, with rpm-ostree postprocessing it. (One could argue it's rpm-ostree's job to postprocess this so Anaconda wouldn't have to care. Open to that.) --- pyanaconda/packaging/rpmostreepayload.py | 60 +++++++++++++++++++++++--------- 1 file changed, 44 insertions(+), 16 deletions(-) diff --git a/pyanaconda/packaging/rpmostreepayload.py b/pyanaconda/packaging/rpmostreepayload.py index dfb0466..bf8d7e1 100644 --- a/pyanaconda/packaging/rpmostreepayload.py +++ b/pyanaconda/packaging/rpmostreepayload.py @@ -89,6 +89,41 @@ class RPMOSTreePayload(ArchivePayload): else: progressQ.send_message("Writing objects") + def _copyBootloaderData(self): + # Copy bootloader data files from the deployment + # checkout to the target root. See + # https://bugzilla.gnome.org/show_bug.cgi?id=726757 This + # happens once, at installation time. + # extlinux ships its modules directly in the RPM in /boot. + # For GRUB2, Anaconda installs device.map there. We may need + # to add other bootloaders here though (if they can't easily + # be fixed to *copy* data into /boot at install time, instead + # of shipping it in the RPM). + physboot = iutil.getTargetPhysicalRoot() + '/boot' + ostree_boot_source = iutil.getSysroot() + '/usr/lib/ostree-boot' + if not os.path.isdir(ostree_boot_source): + ostree_boot_source = iutil.getSysroot() + '/boot' + for fname in os.listdir(ostree_boot_source): + srcpath = os.path.join(ostree_boot_source, fname) + destpath = os.path.join(physboot, fname) + + # We're only copying directories + if not os.path.isdir(srcpath): + continue + + # Special handling for EFI, as it's a mount point that's + # expected to already exist (so if we used copytree, we'd + # traceback). If it doesn't, we're not on a UEFI system, + # so we don't want to copy the data. + if fname == 'efi' and os.path.isdir(destpath): + for subname in os.listdir(srcpath): + sub_srcpath = os.path.join(srcpath, subname) + sub_destpath = os.path.join(destpath, subname) + self._safeExecWithRedirect('cp', ['-r', '-p', sub_srcpath, sub_destpath]) + else: + log.info("Copying bootloader data: " + fname) + shutil.copytree(srcpath, destpath) + def install(self): mainctx = GLib.MainContext.new() mainctx.push_thread_default() @@ -161,22 +196,15 @@ class RPMOSTreePayload(ArchivePayload): deployment_path = sysroot.get_deployment_directory(deployment) iutil.setSysroot(deployment_path.get_path()) - # Copy specific bootloader data files from the deployment - # checkout to the target root. See - # https://bugzilla.gnome.org/show_bug.cgi?id=726757 This - # happens once, at installation time. - # extlinux ships its modules directly in the RPM in /boot. - # For GRUB2, Anaconda installs device.map there. We may need - # to add other bootloaders here though (if they can't easily - # be fixed to *copy* data into /boot at install time, instead - # of shipping it in the RPM). - physboot = iutil.getTargetPhysicalRoot() + '/boot' - sysboot = iutil.getSysroot() + '/boot' - for fname in ['extlinux', 'grub2']: - srcpath = os.path.join(sysboot, fname) - if os.path.isdir(srcpath): - log.info("Copying bootloader data: " + fname) - shutil.copytree(srcpath, os.path.join(physboot, fname)) + try: + self._copyBootloaderData() + except (OSError, RuntimeError) as e: + exn = PayloadInstallError("Failed to copy bootloader data: %s" % e) + log.error(str(exn)) + if errors.errorHandler.cb(exn) == errors.ERROR_RAISE: + progressQ.send_quit(1) + iutil.ipmi_report(constants.IPMI_ABORTED) + sys.exit(1) mainctx.pop_thread_default() -- 1.8.3.1