[PATCH 2/7] Replace booty with a new bootloader module.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Moves requirements for and detection of bootloader stage1/stage2
target devices into the bootloader classes themselves.

Separates the concepts of bios drive ordering and boot drive selection.

Removes support for LILO and ABOOT.

Removes chandev code from ZIPL.

Moves target/stage1 device type descriptions into BootLoader classes.

Adds prevention of duplicate labels on upgrades.
---
 configure.ac                        |    1 -
 pyanaconda/Makefile.am              |    2 +-
 pyanaconda/bootloader.py            | 1823 +++++++++++++++++++++++++++++++----
 pyanaconda/booty/Makefile.am        |   24 -
 pyanaconda/booty/__init__.py        |   52 -
 pyanaconda/booty/alpha.py           |  140 ---
 pyanaconda/booty/bootloaderInfo.py  |  714 --------------
 pyanaconda/booty/checkbootloader.py |  176 ----
 pyanaconda/booty/ia64.py            |   38 -
 pyanaconda/booty/lilo.py            |  308 ------
 pyanaconda/booty/ppc.py             |  184 ----
 pyanaconda/booty/s390.py            |  186 ----
 pyanaconda/booty/sparc.py           |  128 ---
 pyanaconda/booty/util.py            |    9 -
 pyanaconda/booty/x86.py             |  562 -----------
 15 files changed, 1630 insertions(+), 2717 deletions(-)
 delete mode 100644 pyanaconda/booty/Makefile.am
 delete mode 100644 pyanaconda/booty/__init__.py
 delete mode 100644 pyanaconda/booty/alpha.py
 delete mode 100644 pyanaconda/booty/bootloaderInfo.py
 delete mode 100644 pyanaconda/booty/checkbootloader.py
 delete mode 100644 pyanaconda/booty/ia64.py
 delete mode 100644 pyanaconda/booty/lilo.py
 delete mode 100644 pyanaconda/booty/ppc.py
 delete mode 100644 pyanaconda/booty/s390.py
 delete mode 100644 pyanaconda/booty/sparc.py
 delete mode 100644 pyanaconda/booty/util.py
 delete mode 100644 pyanaconda/booty/x86.py

diff --git a/configure.ac b/configure.ac
index ed7350e..e466d52 100644
--- a/configure.ac
+++ b/configure.ac
@@ -286,7 +286,6 @@ AC_CONFIG_FILES([Makefile
                  po/Makefile.in
                  scripts/Makefile
                  pyanaconda/Makefile
-                 pyanaconda/booty/Makefile
                  pyanaconda/isys/Makefile
                  pyanaconda/storage/Makefile
                  pyanaconda/storage/devicelibs/Makefile
diff --git a/pyanaconda/Makefile.am b/pyanaconda/Makefile.am
index dda42d0..1269502 100644
--- a/pyanaconda/Makefile.am
+++ b/pyanaconda/Makefile.am
@@ -17,7 +17,7 @@
 #
 # Author: Martin Sivak <msivak@xxxxxxxxxx>
 
-SUBDIRS = booty installclasses isys iw textw storage 
+SUBDIRS = installclasses isys iw textw storage
 
 MAINTAINERCLEANFILES = Makefile.in
 
diff --git a/pyanaconda/bootloader.py b/pyanaconda/bootloader.py
index ce27f69..c99620a 100644
--- a/pyanaconda/bootloader.py
+++ b/pyanaconda/bootloader.py
@@ -1,242 +1,1677 @@
+# bootloader.py
+# Anaconda's bootloader configuration module.
 #
-# bootloader.py: anaconda bootloader shims
+# Copyright (C) 2011 Red Hat, Inc.
 #
-# Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006  Red Hat, Inc.
-# All rights reserved.
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions of
+# the GNU General Public License v.2, or (at your option) any later version.
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY expressed or implied, including the implied warranties of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+# Public License for more details.  You should have received a copy of the
+# GNU General Public License along with this program; if not, write to the
+# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.  Any Red Hat trademarks that are incorporated in the
+# source code or documentation are not subject to the GNU General Public
+# License and may only be used or replicated with the express permission of
+# Red Hat, Inc.
 #
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-#
-# Author(s): Erik Troan <ewt@xxxxxxxxxx>
-#            Jeremy Katz <katzj@xxxxxxxxxx>
+# Red Hat Author(s): David Lehman <dlehman@xxxxxxxxxx>
 #
 
-import isys
-import parted
-import os, sys
-import iutil
-import string
-from flags import flags
-from constants import *
-from storage.devices import devicePathToName
-from storage import getReleaseString
-from booty.util import getDiskPart
+import sys
+import os
+import re
+import struct
+
+from pyanaconda import iutil
+from pyanaconda.storage.devicelibs import mdraid
+from pyanaconda.isys import sync
+from pyanaconda.product import productName
+from pyanaconda.flags import flags
+from pyanaconda.constants import *
+from pyanaconda.storage.errors import StorageError
 
 import gettext
 _ = lambda x: gettext.ldgettext("anaconda", x)
+N_ = lambda x: x
 
 import logging
 log = logging.getLogger("anaconda")
 
-import booty
-from booty import bootloaderInfo, checkbootloader
 
-def isEfiSystemPartition(part):
-    if not part.active:
+def get_boot_block(device, seek_blocks=0):
+    block = " " * 512
+    status = device.status
+    if not status:
+        try:
+            device.setup()
+        except StorageError:
+            return block
+    fd = os.open(device.path, os.O_RDONLY)
+    if seek_blocks:
+        os.lseek(fd, seek_blocks * 512, 0)
+    block = os.read(fd, 512)
+    os.close(fd)
+    if not status:
+        try:
+            device.teardown(recursive=True)
+        except StorageError:
+            pass
+
+    return block
+
+def is_windows_boot_block(block):
+    try:
+        windows = (len(block) >= 512 and
+                   struct.unpack("H", block[0x1fe: 0x200]) == (0xaa55,))
+    except struct.error:
+        windows = False
+    return windows
+
+def has_windows_boot_block(device):
+    return is_windows_boot_block(get_boot_block(device))
+
+
+class BootLoaderError(Exception):
+    pass
+
+
+class ArgumentList(list):
+    def _is_match(self, item, value):
+        try:
+            _item = item.split("=")[0]
+        except (ValueError, AttributeError):
+            _item = item
+
+        try:
+            _value = value.split("=")[0]
+        except (ValueError, AttributeError):
+            _value = value
+
+        return _item == _value
+
+    def __contains__(self, value):
+        for arg in self:
+            if self._is_match(arg, value):
+                return True
+
         return False
-    return (part.disk.type == "gpt" and
-            part.name == "EFI System Partition" and
-            part.getFlag(parted.PARTITION_BOOT) and
-            part.fileSystem.type in ("fat16", "fat32") and
-            isys.readFSLabel(part.getDeviceNodeName()) != "ANACONDA")
 
-def bootloaderSetupChoices(anaconda):
-    if anaconda.dir == DISPATCH_BACK:
-        rc = anaconda.intf.messageWindow(_("Warning"),
-                _("Filesystems have already been activated.  You "
-                  "cannot go back past this point.\n\nWould you like to "
-                  "continue with the installation?"),
-                type="custom", custom_icon=["error","error"],
-                custom_buttons=[_("_Exit installer"), _("_Continue")])
+    def count(self, value):
+        return len([x for x in self if self._is_match(x, value)])
 
-        if rc == 0:
-            sys.exit(0)
-        return DISPATCH_FORWARD
+    def index(self, value):
+        for i in range(len(self)):
+            if self._is_match(self[i], value):
+                return i
 
-    if anaconda.ksdata and anaconda.ksdata.bootloader.driveorder:
-        anaconda.bootloader.updateDriveList(anaconda.ksdata.bootloader.driveorder)
-    else:
-        #We want the selected bootloader drive to be preferred
-        pref = anaconda.bootloader.drivelist[:1]
-        anaconda.bootloader.updateDriveList(pref)
-
-    if iutil.isEfi() and not anaconda.bootloader.device:
-        bootPart = None
-        partitions = anaconda.storage.partitions
-        for part in partitions:
-            if part.partedPartition.active and isEfiSystemPartition(part.partedPartition):
-                bootPart = part.name
-                break
-        if bootPart:
-            anaconda.bootloader.setDevice(bootPart)
-
-# iSeries bootloader on upgrades
-    if iutil.getPPCMachine() == "iSeries" and not anaconda.bootloader.device:
-        bootPart = None
-        partitions = anaconda.storage.partitions
-        for part in partitions:
-            if part.partedPartition.active and \
-               part.partedPartition.getFlag(parted.PARTITION_PREP):
-                bootPart = part.name
-                break
-        if bootPart:
-            anaconda.bootloader.setDevice(bootPart)
-
-    choices = anaconda.platform.bootloaderChoices(anaconda.bootloader)
-    if not choices and iutil.getPPCMachine() != "iSeries":
-	anaconda.dispatch.skipStep("instbootloader")
-    else:
-	anaconda.dispatch.skipStep("instbootloader", skip = 0)
-
-    # FIXME: ...
-    anaconda.bootloader.images.setup(anaconda.storage)
-
-    if anaconda.bootloader.defaultDevice != None and choices:
-        keys = choices.keys()
-        # there are only two possible things that can be in the keys
-        # mbr and boot.  boot is ALWAYS present.  so if the dev isn't
-        # listed, it was mbr and we should nicely fall back to boot
-        if anaconda.bootloader.defaultDevice not in keys:
-            log.warning("MBR not suitable as boot device; installing to partition")
-            anaconda.bootloader.defaultDevice = "boot"
-        anaconda.bootloader.setDevice(choices[anaconda.bootloader.defaultDevice][0])
-    elif choices and iutil.isMactel() and choices.has_key("boot"): # haccckkkk
-        anaconda.bootloader.setDevice(choices["boot"][0])        
-    elif choices and choices.has_key("mbr"):
-        anaconda.bootloader.setDevice(choices["mbr"][0])
-    elif choices and choices.has_key("boot"):
-        anaconda.bootloader.setDevice(choices["boot"][0])
-
-def fixedMdraidGrubTarget(anaconda, grubTarget):
-    # handle change made in F12 - before F12 mdX used to mean installation
-    # into mbrs of mdX members' disks
-    fixedGrubTarget = grubTarget
-    (product, version) = getReleaseString(anaconda.rootPath)
-    try:
-        if float(version) < 12:
-            stage1Devs = anaconda.bootloader.getPhysicalDevices(grubTarget)
-            fixedGrubTarget = getDiskPart(stage1Devs[0])[0]
-            log.info("Mdraid grub upgrade: %s -> %s" % (grubTarget.name,
-                                                        fixedGrubTarget.name))
-    except ValueError:
-        log.warning("Can't decide mdraid grub upgrade fix, product: %s, version: %s" % (product, version))
+        raise ValueError("'%s' is not in list" % value)
 
-    return fixedGrubTarget
+    def rindex(self, value):
+        for i in reversed(range(len(self))):
+            if self._is_match(self[i], value):
+                return i
 
-def writeBootloader(anaconda):
-    def dosync():
-        isys.sync()
-        isys.sync()
-        isys.sync()
+        raise ValueError("'%s' is not in list" % value)
 
-    if anaconda.bootloader.defaultDevice == -1:
-        return
+    def append(self, value):
+        """ Append a new argument to the list.
+
+            If the value is an exact match to an existing argument it will
+            not be added again. Also, empty strings will not be added.
+        """
+        if value == "":
+            return
 
-    if anaconda.bootloader.doUpgradeOnly:
-        (bootType, theDev) = checkbootloader.getBootloaderTypeAndBoot(anaconda.rootPath, storage=anaconda.storage)
-        
-        anaconda.bootloader.doUpgradeonly = 1
-        if bootType == "GRUB":
-            grubTarget = anaconda.storage.devicetree.getDeviceByPath(theDev)
-            if grubTarget.type == "mdarray":
-                grubTarget = fixedMdraidGrubTarget(anaconda, grubTarget)
-            anaconda.bootloader.useGrubVal = 1
-            anaconda.bootloader.setDevice(grubTarget.name)
+        try:
+            idx = self.index(value)
+        except ValueError:
+            pass
         else:
-            anaconda.bootloader.doUpgradeOnly = 0
+            if self[idx] == value:
+                return
 
-    w = anaconda.intf.waitWindow(_("Bootloader"), _("Installing bootloader."))
+        super(ArgumentList, self).append(value)
 
-    kernelList = []
-    otherList = []
-    # getDefault needs to return a device, but that's too invasive for now.
-    rootDev = anaconda.storage.rootDevice
+    def extend(self, values):
+        map(self.append, values)
 
-    if not anaconda.bootloader.images.getDefault():
-        defaultDev = None
-    else:
-        defaultDev = anaconda.storage.devicetree.getDeviceByName(anaconda.bootloader.images.getDefault())
+    def __str__(self):
+        return " ".join(map(str, self))
 
-    kernelLabel = None
-    kernelLongLabel = None
 
-    for (dev, (label, longlabel, type)) in anaconda.bootloader.images.getImages().items():
-        if (rootDev is None and kernelLabel is None) or (dev == rootDev.name):
-	    kernelLabel = label
-            kernelLongLabel = longlabel
-	elif (not defaultDev and not dev) or (defaultDev and dev == defaultDev.name):
-	    otherList = [(label, longlabel, dev)] + otherList
-	else:
-	    otherList.append((label, longlabel, dev))
+class BootLoaderImage(object):
+    """ Base class for bootloader images. Suitable for non-linux OS images. """
+    def __init__(self, device=None, label=None):
+        self.label = label
+        self.device = device
 
-    if kernelLabel is None:
-        log.error("unable to find default image, bailing")
-        w.pop()
-        return
 
-    defkern = "kernel"
-    for (version, arch, nick) in \
-            anaconda.backend.kernelVersionList(anaconda.rootPath):
-        if nick != 'base':
-            defkern = "kernel-%s" %(nick,)
-            kernelList.append(("%s-%s" %(kernelLabel, nick),
-                               "%s-%s" %(kernelLongLabel, nick),
-                               version))
+class LinuxBootLoaderImage(BootLoaderImage):
+    def __init__(self, device=None, label=None, short=None, version=None):
+        super(LinuxBootLoaderImage, self).__init__(device=device, label=label)
+        self.label = label              # label string
+        self.short_label = short        # shorter label string
+        self.device = device            # StorageDevice instance
+        self.version = version          # kernel version string
+        self._kernel = None             # filename string
+        self._initrd = None             # filename string
+
+    @property
+    def kernel(self):
+        filename = self._kernel
+        if self.version and not filename:
+            filename = "vmlinuz-%s" % self.version
+        return filename
+
+    @property
+    def initrd(self):
+        filename = self._initrd
+        if self.version and not filename:
+            filename = "initramfs-%s.img" % self.version
+        return filename
+
+
+class BootLoader(object):
+    """TODO:
+            - iSeries bootloader?
+                - same as pSeries, except optional, I think
+            - upgrade of non-grub bootloaders
+            - detection of existing bootloaders
+            - resolve overlap between Platform checkFoo methods and
+              _is_valid_target_device and _is_valid_boot_device
+            - split certain parts of _is_valid_target_device and
+              _is_valid_boot_device into specific bootloader classes
+    """
+    name = "Generic Bootloader"
+    packages = []
+    config_file = None
+    config_file_mode = 0600
+    can_dual_boot = False
+    can_update = False
+    image_label_attr = "label"
+
+    # requirements for bootloader target devices
+    target_device_types = ["partition"]
+    target_device_raid_levels = []
+    target_device_format_types = []
+    target_device_disklabel_types = ["msdos"]
+    target_device_mountpoints = []
+    target_device_min_size = None
+    target_device_max_size = None
+
+    target_descriptions = {"disk": N_("Master Boot Record"),
+                           "partition": N_("First sector of boot partition"),
+                           "mdarray": N_("RAID Device")}
+
+    # requirements for boot devices
+    boot_device_types = ["partition"]
+    boot_device_raid_levels = []
+    boot_device_format_types = []
+
+    # linux-specific requirements for boot devices
+    linux_boot_device_format_types = ["ext4", "ext3", "ext2"]
+    linux_boot_device_mountpoints = ["/boot", "/"]
+    linux_boot_device_min_size = 50
+    linux_boot_device_max_size = None
+
+    # this is so stupid...
+    global_preserve_args = ["speakup_synth", "apic", "noapic", "apm", "ide",
+                            "noht", "acpi", "video", "pci", "nodmraid",
+                            "nompath", "nomodeset", "noiswmd", "fips"]
+    preserve_args = []
+
+    def __init__(self, storage=None):
+        # pyanaconda.storage.Storage instance
+        self.storage = storage
+
+        self.boot_args = ArgumentList()
+        self.dracut_args = []
+
+        self._drives = []
+        self._drive_order = []
+
+        # timeout in seconds
+        self._timeout = None
+        self.password = None
+
+        # console/serial stuff
+        self.console = ""
+        self.console_options = ""
+        self._set_console()
+
+        # list of BootLoaderImage instances representing bootable OSs
+        self.linux_images = []
+        self.chain_images = []
+
+        # default image
+        self._default_image = None
+
+        # the device the bootloader will be installed on
+        self._target_device = None
+
+        self._update_only = False
+
+    #
+    # target device access
+    #
+    @property
+    def stage1_device(self):
+        """ Stage1 target device. """
+        if not self._target_device:
+            self.stage1_device = self.target_devices[0]
+
+        return self._target_device
+
+    @stage1_device.setter
+    def stage1_device(self, device):
+        if not self._is_valid_target_device(device):
+            raise ValueError("%s is not a valid target device" % device.name)
+
+        log.debug("new bootloader stage1 device: %s" % device.name)
+        self._target_device = device
+
+    @property
+    def stage2_device(self):
+        """ Stage2 target device. """
+        return self.storage.mountpoints.get("/boot", self.storage.rootDevice)
+
+    #
+    # drive list access
+    #
+    @property
+    def drive_order(self):
+        """Potentially partial order for drives."""
+        return self._drive_order
+
+    @drive_order.setter
+    def drive_order(self, order):
+        log.debug("new drive order: %s" % order)
+        self._drive_order = order
+        self.clear_drive_list() # this will get regenerated on next access
+
+    def _sort_drives(self, drives):
+        """Sort drives based on the drive order."""
+        _drives = drives[:]
+        for name in reversed(self._drive_order):
+            try:
+                idx = [d.name for d in _drives].index(name)
+            except ValueError:
+                log.error("bios order specified unknown drive %s" % name)
+                continue
+
+            first = _drives.pop(idx)
+            _drives.insert(0, first)
+
+        return _drives
+
+    def clear_drive_list(self):
+        """ Clear the drive list to force re-populate on next access. """
+        self._drives = []
+
+    @property
+    def drives(self):
+        """Sorted list of available drives."""
+        if self._drives:
+            # only generate the list if it is empty
+            return self._drives
+
+        # XXX requiring partitioned may break clearpart
+        drives = [d for d in self.storage.disks if d.partitioned]
+        self._drives = self._sort_drives(drives)
+        return self._drives
+
+    #
+    # image list access
+    #
+    @property
+    def default(self):
+        """The default image."""
+        if not self._default_image:
+            if self.linux_images:
+                _default = self.linux_images[0]
+            else:
+                _default = LinuxBootLoaderImage(device=self.storage.rootDevice,
+                                                label=productName,
+                                                short="linux")
+
+            self._default_image = _default
+
+        return self._default_image
+
+    @default.setter
+    def default(self, image):
+        if image not in self.images:
+            raise ValueError("new default image not in image list")
+
+        log.debug("new default image: %s" % image)
+        self._default_image = image
+
+    @property
+    def images(self):
+        """ List of OS images that will be included in the configuration. """
+        if not self.linux_images:
+            self.linux_images.append(self.default)
+
+        all_images = self.linux_images
+        all_images.extend([i for i in self.chain_images if i.label])
+        return all_images
+
+    def clear_images(self):
+        """Empty out the image list."""
+        self.linux_images = []
+        self.chain_images = []
+
+    def add_image(self, image):
+        """Add a BootLoaderImage instance to the image list."""
+        if isinstance(image, LinuxBootLoaderImage):
+            self.linux_images.append(image)
+        else:
+            self.chain_images.append(image)
+
+    def image_label(self, image):
+        """Return the appropriate image label for this bootloader."""
+        return getattr(image, self.image_label_attr)
+
+    def _find_chain_images(self):
+        """ Collect a list of potential non-linux OS installations. """
+        # XXX not used -- do we want to pre-populate the image list for the ui?
+        self.chain_images = []
+        if not self.can_dual_boot:
+            return
+
+        for device in [d for d in self.bootable_chain_devices if d.exists]:
+            self.chain_images.append(BootLoaderImage(device=device))
+
+    #
+    # target/stage1 device access
+    #
+    def _device_type_index(self, device, types):
+        """ Return the index of the matching type in types to device's type.
+
+            Return None if no match is found. """
+        index = None
+        try:
+            index = types.index(device.type)
+        except ValueError:
+            if "disk" in types and device.isDisk:
+                index = types.index("disk")
+
+        return index
+
+    def _device_type_match(self, device, types):
+        """ Return True if device is of one of the types in the list types. """
+        return self._device_type_index(device, types) is not None
+
+    def device_description(self, device):
+        idx = self._device_type_index(device, self.target_device_types)
+        if idx is None:
+            raise ValueError("'%s' not a valid stage1 type" % device.type)
+
+        return self.target_descriptions[self.target_device_types[idx]]
+
+    def set_preferred_stage2_type(self, preferred):
+        """ Set a preferred type of stage1 device.
+
+            XXX should this reorder the list or remove everything else? """
+        if preferred == "mbr":
+            preferred = "disk"
+
+        try:
+            index = self.target_device_types.index(preferred)
+        except ValueError:
+            raise ValueError("'%s' not a valid stage1 device type" % preferred)
+
+        self.target_device_types.insert(0, self.target_device_types.pop(index))
+
+    def _is_valid_target_device(self, device):
+        """ Return True if the device is a valid stage1 target device.
+
+            The criteria for being a valid stage1 target device vary from
+            platform to platform. On some platforms a disk with an msdos
+            disklabel is a valid stage1 target, while some platforms require
+            a special device. Some examples of these special devices are EFI
+            system partitions on EFI machines, PReP boot partitions on
+            iSeries, and Apple bootstrap partitions on Mac. """
+        if not self._device_type_match(device, self.target_device_types):
+            return False
+
+        if (self.target_device_min_size is not None and
+            device.size < self.target_device_min_size):
+            return False
+
+        if (self.target_device_max_size is not None and
+            device.size > self.target_device_max_size):
+            return False
+
+        if not getattr(device, "bootable", True) or \
+           (hasattr(device, "partedPartition") and
+            not device.partedPartition.active):
+            return False
+
+        if getattr(device.format, "label", None) == "ANACONDA":
+            return False
+
+        if self.target_device_format_types and \
+           device.format.type not in self.target_device_format_types:
+            return False
+
+        if self.target_device_disklabel_types:
+            for disk in device.disks:
+                label_type = disk.format.labelType
+                if label_type not in self.target_device_disklabel_types:
+                    return False
+
+        if self.target_device_mountpoints and \
+           hasattr(device.format, "mountpoint") and \
+           device.format.mountpoint not in self.target_device_mountpoints:
+            return False
+
+        return True
+
+    @property
+    def target_devices(self):
+        """ A list of valid stage1 target devices.
+
+            The list self.target_device_types is ordered, so we return a list
+            of all valid target devices, sorted by device type, then sorted
+            according to our drive ordering.
+        """
+        slots = [[] for t in self.target_device_types]
+        for device in self.storage.devices:
+            idx = self._device_type_index(device, self.target_device_types)
+            if idx is None:
+                continue
+
+            if self._is_valid_target_device(device):
+                slots[idx].append(device)
+
+        devices = []
+        for slot in slots:
+            devices.extend(slot)
+
+        return self._sort_drives(devices)
+
+    #
+    # boot/stage2 device access
+    #
+
+    def _is_valid_boot_device(self, device, linux=False):
+        """ Return True if the specified device might contain an OS image. """
+        if not self._device_type_match(device, self.boot_device_types):
+            return False
+
+        if device.type == "mdarray" and \
+           device.level not in self.boot_device_raid_levels:
+            # TODO: also check metadata version, as ridiculous as that is
+            return False
+
+        if not self.target_devices:
+            # XXX is this really a dealbreaker?
+            return False
+
+        # FIXME: the windows boot block part belongs in GRUB
+        if hasattr(device, "partedPartition") and \
+           (not device.bootable or not device.partedPartition.active) and \
+           not has_windows_boot_block(device):
+            return False
+
+        if linux:
+            format_types = self.linux_boot_device_format_types
+            mountpoint = getattr(device.format, "mountpoint", None)
+            if mountpoint not in self.linux_boot_device_mountpoints:
+                return False
         else:
-            kernelList.append((kernelLabel, kernelLongLabel, version))
+            format_types = self.boot_device_format_types
+
+        return device.format.type in format_types
+
+    @property
+    def bootable_chain_devices(self):
+        """ Potential boot devices containing non-linux operating systems. """
+        return [d for d in self.storage.devices if self._is_valid_boot_device(d)]
+
+    @property
+    def bootable_linux_devices(self):
+        """ Potential boot devices containing linux operating systems. """
+        return [d for d in self.storage.devices
+                    if self._is_valid_boot_device(d, linux=True)]
+
+    #
+    # miscellaneous
+    #
+
+    @property
+    def has_windows(self):
+        return False
+
+    @property
+    def timeout(self):
+        """Bootloader timeout in seconds."""
+        if self._timeout is not None:
+            t = self._timeout
+        elif self.console and self.console.startswith("ttyS"):
+            t = 5
+        else:
+            t = 20
+
+        return t
+
+    @timeout.setter
+    def timeout(self, seconds):
+        self._timeout = seconds
+
+    @property
+    def update_only(self):
+        return self._update_only
+
+    @update_only.setter
+    def update_only(self, value):
+        if value and not self.can_update:
+            raise ValueError("this bootloader does not support updates")
+        elif self.can_update:
+            self._update_only = value
+
+    def set_boot_args(self, *args, **kwargs):
+        """ Set up the boot command line.
+
+            Keyword Arguments:
+
+                network - a pyanaconda.network.Network instance (for network
+                          storage devices' boot arguments)
+
+            All other arguments are expected to have a dracutSetupString()
+            method.
+        """
+        network = kwargs.pop("network", None)
+
+        #
+        # FIPS
+        #
+        if flags.cmdline.get("fips") == "1":
+            self.boot_args.append("boot=%s" % self.stage2_device.fstabSpec)
+
+        #
+        # dracut
+        #
+
+        # storage
+        from pyanaconda.storage.devices import NetworkStorageDevice
+        dracut_devices = [self.storage.rootDevice]
+        if self.stage2_device != self.storage.rootDevice:
+            dracut_devices.append(self.stage2_device)
+
+        dracut_devices.extend(self.storage.fsset.swapDevices)
+
+        done = []
+        # When we see a device whose setup string starts with a key in this
+        # dict we pop that pair from the dict. When we're done looking at
+        # devices we are left with the values that belong in the boot args.
+        dracut_storage = {"rd_LUKS_UUID": "rd_NO_LUKS",
+                          "rd_LVM_LV": "rd_NO_LVM",
+                          "rd_MD_UUID": "rd_NO_MD",
+                          "rd_DM_UUID": "rd_NO_DM"}
+        for device in dracut_devices:
+            for dep in self.storage.devices:
+                if device in done:
+                    continue
+
+                if device != dep and not device.dependsOn(dep):
+                    continue
+
+                setup_string = dep.dracutSetupString().strip()
+                if not setup_string:
+                    continue
+
+                self.boot_args.append(setup_string)
+                self.dracut_args.append(setup_string)
+                done.append(dep)
+                dracut_storage.pop(setup_string.split("=")[0], None)
+
+                # network storage
+                # XXX this is nothing to be proud of
+                if isinstance(dep, NetworkStorageDevice):
+                    if network is None:
+                        log.error("missing network instance for setup of boot "
+                                  "command line for network storage device %s"
+                                  % dep.name)
+                        raise BootLoaderError("missing network instance when "
+                                              "setting boot args for network "
+                                              "storage device")
+
+                    setup_string = network.dracutSetupString(dep).strip()
+                    self.boot_args.append(setup_string)
+                    self.dracut_args.append(setup_string)
+
+        self.boot_args.extend(dracut_storage.values())
+        self.dracut_args.extend(dracut_storage.values())
+
+        # passed-in objects
+        for cfg_obj in list(args) + kwargs.values():
+            setup_string = cfg_obj.dracutSetupString().strip()
+            self.boot_args.append(setup_string)
+            self.dracut_args.append(setup_string)
+
+        #
+        # preservation of some of our boot args
+        # FIXME: this is stupid.
+        #
+        for opt in self.global_preserve_args + self.preserve_args:
+            if opt not in flags.cmdline:
+                continue
+
+            arg = flags.cmdline.get(opt)
+            new_arg = opt
+            if arg:
+                new_arg += "=%s" % arg
+
+            self.boot_args.append(new_arg)
+
+    #
+    # configuration
+    #
+
+    @property
+    def boot_prefix(self):
+        """ Prefix, if any, to paths in /boot. """
+        if self.stage2_device == self.storage.rootDevice:
+            prefix = "/boot"
+        else:
+            prefix = ""
+
+        return prefix
+
+    def _set_console(self):
+        """ Set console options based on boot arguments. """
+        if flags.serial:
+            console = flags.cmdline.get("console", "ttyS0").split(",", 1)
+            self.console = console[0]
+            if len(console) > 1:
+                self.console_options = console[1]
+        elif flags.virtpconsole:
+            self.console = re.sub("^/dev/", "", flags.virtpconsole)
+
+    def write_config_console(self, config):
+        """Write console-related configuration lines."""
+        pass
+
+    def write_config_password(self, config):
+        """Write password-related configuration lines."""
+        pass
+
+    def write_config_header(self, config):
+        """Write global configuration lines."""
+        self.write_config_console(config)
+        self.write_config_password(config)
+
+    def write_config_images(self, config):
+        """Write image configuration entries."""
+        # XXX might this be identical for yaboot and silo?
+        raise NotImplementedError()
+
+    def write_config_post(self, install_root=""):
+        try:
+            os.chmod(install_root + self.config_file, self.config_file_mode)
+        except OSError as e:
+            log.error("failed to set config file permissions: %s" % e)
+
+    def write_config(self, install_root=""):
+        """ Write the bootloader configuration. """
+        if not self.config_file:
+            raise BootLoaderError("no config file defined for this bootloader")
+
+        config_path = os.path.normpath(install_root + self.config_file)
+        if os.access(config_path, os.R_OK):
+            os.rename(config_path, config_path + ".rpmsave")
+
+        config = open(config_path, "w")
+        self.write_config_header(config, install_root=install_root)
+        self.write_config_images(config)
+        config.close()
+        self.write_config_post(install_root=install_root)
+
+    def writeKS(self, f):
+        """ Write bootloader section of kickstart configuration. """
+        if self.stage1_device.isDisk:
+            location = "mbr"
+        elif self.stage1_device:
+            location = "partition"
+        else:
+            location = "none\n"
+
+        f.write("bootloader --location=%s" % location)
+
+        if not self.stage1_device:
+            return
+
+        if self.drive_order:
+            f.write(" --driveorder=%s" % ",".join(self.drive_order))
+
+        append = [a for a in self.boot_args if a not in self.dracut_args]
+        if append:
+            f.write(" --append=\"%s\"" % " ".join(append))
+
+        f.write("\n")
+
+    def read(self):
+        """ Read an existing bootloader configuration. """
+        raise NotImplementedError()
+
+    #
+    # installation
+    #
+    def write(self, install_root=""):
+        """ Write the bootloader configuration and install the bootloader. """
+        if self.update_only:
+            self.update(install_root=install_root)
+            return
+
+        self.write_config(install_root=install_root)
+        sync()
+        sync()
+        sync()
+        sync()
+        self.install(install_root=install_root)
+
+    def update(self, install_root=""):
+        """ Update an existing bootloader configuration. """
+        pass
+
+
+class GRUB(BootLoader):
+    name = "GRUB"
+    _config_dir = "grub"
+    _config_file = "grub.conf"
+    _device_map_file = "device.map"
+    can_dual_boot = True
+    can_update = True
+
+    # list of strings representing options for bootloader target device types
+    target_device_types = ["disk", "partition", "mdarray"]
+    target_device_raid_levels = [mdraid.RAID1]
+    target_device_format_types = []
+    target_device_format_mountpoints = ["/boot", "/"]
+    target_device_disklabel_types = ["msdos", "gpt"]    # gpt?
+
+    # list of strings representing options for boot device types
+    boot_device_types = ["partition", "mdarray"]
+    boot_device_raid_levels = [mdraid.RAID1]
+    # XXX hpfs, if reported by blkid/udev, will end up with a type of None
+    boot_device_format_types = ["vfat", "ntfs", "hpfs"]
+
+    packages = ["grub"]
+
+    def __init__(self, storage):
+        super(GRUB, self).__init__(storage)
+        self.encrypt_password = False
+
+    #
+    # grub-related conveniences
+    #
+
+    def grub_device_name(self, device):
+        """ Return a grub-friendly representation of device. """
+        drive = getattr(device, "disk", device)
+        name = "(hd%d" % self.drives.index(drive)
+        if hasattr(device, "disk"):
+            name += ",%d" % (device.partedPartition.number - 1,)
+        name += ")"
+        return name
 
+    @property
+    def grub_config_dir(self):
+        """ Config dir, adjusted for grub's view of the world. """
+        return self.boot_prefix + self._config_dir
+
+    #
+    # configuration
+    #
+
+    @property
+    def config_dir(self):
+        """ Full path to configuration directory. """
+        return "/boot/" + self._config_dir
+
+    @property
+    def config_file(self):
+        """ Full path to configuration file. """
+        return "%s/%s" % (self.config_dir, self._config_file)
+
+    @property
+    def device_map_file(self):
+        """ Full path to device.map file. """
+        return "%s/%s" % (self.config_dir, self._device_map_file)
+
+    @property
+    def grub_conf_device_line(self):
+        return ""
+
+    def write_config_console(self, config):
+        """ Write console-related configuration. """
+        if not self.console:
+            return
+
+        if self.console.startswith("ttyS"):
+            unit = self.console[-1]
+            speed = "9600"
+            for opt in self.console_options.split(","):
+                if opt.isdigit:
+                    speed = opt
+                    break
+
+            config.write("serial --unit=%s --speed=%s\n" % (unit, speed))
+            config.write("terminal --timeout=%s serial console\n"
+                         % self.timeout)
+
+        console_arg = "console=%s" % self.console
+        if self.console_options:
+            console_arg += ",%s" % self.console_options
+        self.boot_args.append(console_arg)
+
+    @property
+    def encrypted_password(self):
+        import string
+        import crypt
+        import random
+        salt = "$6$"
+        salt_len = 16
+        salt_chars = string.letters + string.digits + './'
+
+        rand_gen = random.SystemRandom()
+        salt += "".join([rand_gen.choice(salt_chars) for i in range(salt_len)])
+        password = crypt.crypt(self.password, salt)
+        return password
+
+    def write_config_password(self, config):
+        """ Write password-related configuration. """
+        if self.password:
+            if self.encrypt_password:
+                password = "--encrypted " + self.encrypted_password
+            else:
+                password = self.password
+
+            config.write("password %s\n" % password)
+
+    def write_config_header(self, config, install_root=""):
+        """Write global configuration information. """
+        if self.boot_prefix:
+            have_boot = "do not "
+        else:
+            have_boot = ""
+
+        s = """# grub.conf generated by anaconda\n"
+# Note that you do not have to rerun grub after making changes to this file.
+# NOTICE:  You %(do)shave a /boot partition. This means that all kernel and
+#          initrd paths are relative to %(boot)s, eg.
+#          root %(grub_target)s
+#          kernel %(prefix)s/vmlinuz-version ro root=%(root_device)s
+#          initrd %(prefix)s/initrd-[generic-]version.img
+""" % {"do": have_boot, "boot": self.stage2_device.format.mountpoint,
+       "root_device": self.stage2_device.path,
+       "grub_target": self.grub_device_name(self.stage1_device),
+       "prefix": self.boot_prefix}
+
+        config.write(s)
+        config.write("boot=%s\n" % self.stage1_device.path)
+        config.write(self.grub_conf_device_line)
+
+        # find the index of the default image
+        try:
+            default_index = self.images.index(self.default)
+        except ValueError:
+            e = "Failed to find default image (%s)" % self.default.label
+            raise BootLoaderError(e)
+
+        config.write("default=%d\n" % default_index)
+        config.write("timeout=%d\n" % self.timeout)
+
+        self.write_config_console(config)
+
+        if not flags.serial:
+            splash = "splash.xpm.gz"
+            splash_path = os.path.normpath("%s%s/%s" % (install_root,
+                                                        self.config_dir,
+                                                        splash))
+            if os.access(splash_path, os.R_OK):
+                grub_root_grub_name = self.grub_device_name(self.stage2_device)
+                config.write("splashimage=%s/%s/%s\n" % (grub_root_grub_name,
+                                                         self.grub_config_dir,
+                                                         splash))
+                config.write("hiddenmenu\n")
+
+        self.write_config_password(config)
+
+    def write_config_images(self, config):
+        """ Write image entries into configuration file. """
+        for image in self.images:
+            if isinstance(image, LinuxBootLoaderImage):
+                args = ArgumentList()
+                grub_root = self.grub_device_name(self.stage2_device)
+                args.extend(["ro", "root=%s" % image.device.fstabSpec])
+                args.extend(self.boot_args)
+                stanza = ("title %(label)s (%(version)s)\n"
+                          "\troot %(grub_root)s\n"
+                          "\tkernel %(prefix)s/%(kernel)s %(args)s\n"
+                          "\tinitrd %(prefix)s/%(initrd)s\n"
+                          % {"label": image.label, "version": image.version,
+                             "grub_root": grub_root,
+                             "kernel": image.kernel, "initrd": image.initrd,
+                             "args": args,
+                             "prefix": self.boot_prefix})
+            else:
+                stanza = ("title %(label)s\n"
+                          "\trootnoverify %(grub_root)s\n"
+                          "\tchainloader +1\n"
+                          % {"label": image.label,
+                             "grub_root": self.grub_device_name(image.device)})
+
+            config.write(stanza)
+
+    def write_device_map(self, install_root=""):
+        """ Write out a device map containing all supported devices. """
+        map_path = os.path.normpath(install_root + self.device_map_file)
+        if os.access(map_path, os.R_OK):
+            os.rename(map_path, map_path + ".rpmsave")
+
+        dev_map = open(map_path, "w")
+        dev_map.write("# this device map was generated by anaconda\n")
+        for drive in self.drives:
+            dev_map.write("%s      %s\n" % (self.grub_device_name(drive),
+                                            drive.path))
+        dev_map.close()
+
+    def write_config_post(self, install_root=""):
+        """ Perform additional configuration after writing config file(s). """
+        super(GRUB, self).write_config_post(install_root=install_root)
+
+        # make symlink for menu.lst (grub's default config file name)
+        menu_lst = "%s%s/menu.lst" % (install_root, self.config_dir)
+        if os.access(menu_lst, os.R_OK):
+            try:
+                os.rename(menu_lst, menu_lst + '.rpmsave')
+            except OSError as e:
+                log.error("failed to back up %s: %s" % (menu_lst, e))
+
+        try:
+            os.symlink(self._config_file, menu_lst)
+        except OSError as e:
+            log.error("failed to create grub menu.lst symlink: %s" % e)
+
+        # make symlink to grub.conf in /etc since that's where configs belong
+        etc_grub = "%s/etc/%s" % (install_root, self._config_file)
+        if os.access(etc_grub, os.R_OK):
+            try:
+                os.rename(etc_grub, etc_grub + '.rpmsave')
+            except OSError as e:
+                log.error("failed to back up %s: %s" % (etc_grub, e))
+
+        try:
+            os.symlink("..%s" % self.config_file, etc_grub)
+        except OSError as e:
+            log.error("failed to create /etc/grub.conf symlink: %s" % e)
+
+    def write_config(self, install_root=""):
+        """ Write bootloader configuration to disk. """
+        # write device.map
+        self.write_device_map(install_root=install_root)
+
+        # this writes the actual configuration file
+        super(GRUB, self).write_config(install_root=install_root)
+
+    #
+    # installation
+    #
+
+    def install(self, install_root=""):
+        rc = iutil.execWithRedirect("grub-install", ["--just-copy"],
+                                    stdout="/dev/tty5", stderr="/dev/tty5",
+                                    root=install_root)
+        if rc:
+            raise BootLoaderError("bootloader install failed")
+
+        boot = self.stage2_device
+        targets = []
+        if boot.type != "mdarray":
+            targets.append((self.stage1_device, self.stage2_device))
+        else:
+            if [d for d in self.stage2_device.parents if d.type != "partition"]:
+                raise BootLoaderError("boot array member devices must be "
+                                      "partitions")
+
+            # make sure we have stage1 and stage2 installed with redundancy
+            # so that boot can succeed even in the event of failure or removal
+            # of some of the disks containing the member partitions of the
+            # /boot array
+            for stage2dev in self.stage2_device.parents:
+                if self.stage1_device.isDisk:
+                    # install to mbr
+                    if self.stage2_device.dependsOn(self.stage1_device):
+                        # if target disk contains any of /boot array's member
+                        # partitions, set up stage1 on each member's disk
+                        # and stage2 on each member partition
+                        stage1dev = stage2dev.disk
+                    else:
+                        # if target disk does not contain any of /boot array's
+                        # member partitions, install stage1 to the target disk
+                        # and stage2 to each of the member partitions
+                        stage1dev = self.stage1_device
+                else:
+                    # target is /boot device and /boot is raid, so install
+                    # grub to each of /boot member partitions
+                    stage1dev = stage2dev
+
+                targets.append((stage1dev, stage2dev))
+
+        for (stage1dev, stage2dev) in targets:
+            cmd = ("root %(stage2dev)s\n"
+                   "install --stage2=%(config_dir)s/stage2"
+                   " /%(grub_config_dir)s/stage1 d %(stage1dev)s"
+                   " /%(grub_config_dir)s/stage2 p"
+                   " %(stage2dev)s/%(grub_config_dir)s/%(config_basename)s\n"
+                   % {"grub_config_dir": self.grub_config_dir,
+                      "config_dir": self.config_dir,
+                      "config_basename": self._config_file,
+                      "stage1dev": self.grub_device_name(self.stage1_device),
+                      "stage2dev": self.grub_device_name(self.stage2_device)})
+            (pread, pwrite) = os.pipe()
+            os.write(pwrite, cmd)
+            os.close(pwrite)
+            args = ["--batch", "--no-floppy",
+                    "--device-map=%s" % self.device_map_file]
+            rc = iutil.execWithRedirect("grub", args,
+                                        stdout="/dev/tty5", stderr="/dev/tty5",
+                                        stdin=pread, root=install_root)
+            os.close(pread)
+            if rc:
+                raise BootLoaderError("bootloader install failed")
+
+    def update(self, install_root=""):
+        self.install(install_root=install_root)
+
+    #
+    # miscellaneous
+    #
+
+    @property
+    def has_windows(self):
+        return len(self.bootable_chain_devices) != 0
+
+
+class EFIGRUB(GRUB):
+    name = "GRUB (EFI)"
+    can_dual_boot = False
+    _config_dir = "efi/EFI/redhat"
+
+    # bootloader target device types
+    target_device_types = ["partition", "mdarray"]
+    target_device_raid_levels = [mdraid.RAID1]
+    target_device_format_types = ["efi"]
+    target_device_mountpoints = ["/boot/efi"]
+    target_device_disklabel_types = ["gpt"]
+    target_device_min_size = 50
+    target_device_max_size = 256
+
+    target_descriptions = {"partition": N_("EFI System Partition"),
+                           "mdarray": N_("RAID Device")}
+
+    # boot device types
+    boot_device_format_types = []
+
+    def efibootmgr(self, *args, **kwargs):
+        if kwargs.pop("capture", False):
+            exec_func = iutil.execWithCapture
+        else:
+            exec_func = iutil.execWithRedirect
+
+        return exec_func("efibootmgr", list(args), **kwargs)
+
+    #
+    # configuration
+    #
+
+    @property
+    def efi_product_path(self):
+        """ The EFI product path.
+
+            eg: HD(1,800,64000,faacb4ef-e361-455e-bd97-ca33632550c3)
+        """
+        path = ""
+        buf = self.efibootmgr("-v", stderr="/dev/tty5", capture=True)
+        matches = re.search(productName + r'\s+HD\(.+?\)', buf)
+        if matches:
+            path = re.sub(productName + r'\s+',
+                          '',
+                          buf[matches[0].start():matches[0].end()])
+
+        return path
+
+    @property
+    def grub_conf_device_line(self):
+        return "device %s %s\n" % (self.grub_device_name(self.stage2_device),
+                                   self.efi_product_path)
+
+    #
+    # installation
+    #
+
+    def remove_efi_boot_target(self, install_root=""):
+        buf = self.efibootmgr(capture=True)
+        for line in buf.splitlines():
+            try:
+                (slot, _product) = line.split(None, 1)
+            except ValueError:
+                continue
+
+            if _product == productName:
+                slot_id = slot[4:8]
+                if not slot_id.isdigit():
+                    log.warning("failed to parse efi boot slot (%s)" % slot)
+                    continue
+
+                rc = self.efibootmgr("-b", slot_id, "-B",
+                                     root=install_root,
+                                     stdout="/dev/tty5", stderr="/dev/tty5")
+                if rc:
+                    raise BootLoaderError("failed to remove old efi boot entry")
+
+    def add_efi_boot_target(self, install_root=""):
+        boot_efi = self.storage.mountpoints["/boot/efi"]
+        if boot_efi.type == "partition":
+            boot_disk = boot_efi.disk
+            boot_part_num = boot_efi.partedPartition.number
+        elif boot_efi.type == "mdarray":
+            # FIXME: I'm just guessing here. This probably needs the full
+            #        treatment, ie: multiple targets for each member.
+            boot_disk = boot_efi.parents[0].disk
+            boot_part_num = boot_efi.parents[0].partedPartition.number
+
+        rc = self.efibootmgr("-c", "-w", "-L", productName,
+                             "-d", boot_disk.path, "-p", boot_part_num,
+                             "-l", "\\EFI\\redhat\\grub.efi",
+                             root=install_root,
+                             stdout="/dev/tty5", stderr="/dev/tty5")
+        if rc:
+            raise BootLoaderError("failed to set new efi boot target")
+
+    def install(self, install_root=""):
+        self.remove_efi_boot_target(install_root=install_root)
+        self.add_efi_boot_target(install_root=install_root)
+
+    def update(self, install_root=""):
+        self.write(install_root=install_root)
+
+
+class YabootSILOBase(BootLoader):
+    def write_config_password(self, config):
+        if self.password:
+            config.write("password=%s\n" % self.password)
+            config.write("restricted\n")
+
+    def write_config_images(self, config):
+        for image in self.images:
+            if not isinstance(image, LinuxBootLoaderImage):
+                # mac os images are handled specially in the header on mac
+                continue
+
+            args = ArgumentList()
+            if image.initrd:
+                initrd_line = "\tinitrd=%s/%s\n" % (self.boot_prefix,
+                                                    image.initrd)
+            else:
+                initrd_line = ""
+
+            root_device_spec = self.storage.rootDevice.fstabSpec
+            if root_device_spec.startswith("/"):
+                root_line = "\troot=%s\n" % root_device_spec
+            else:
+                args.append("root=%s" % root_device_spec)
+                root_line = ""
+
+            args.extend(self.boot_args)
+
+            stanza = ("image=%(boot_prefix)s%(kernel)s\n"
+                      "\tlabel=%(label)s\n"
+                      "\tread-only\n"
+                      "%(initrd_line)s"
+                      "%(root_line)s"
+                      "\tappend=\"%(args)s\"\n\n"
+                      % {"kernel": image.kernel,  "initrd_line": initrd_line,
+                         "label": self.image_label(image),
+                         "root_line": root_line, "args": args,
+                         "boot_prefix": self.boot_prefix})
+            config.write(stanza)
+
+
+class Yaboot(YabootSILOBase):
+    name = "Yaboot"
+    _config_file = "yaboot.conf"
+    prog = "ybin"
+
+    # list of strings representing options for bootloader target device types
+    target_device_types = ["partition", "mdarray"]
+    target_device_raid_levels = [mdraid.RAID1]
+    target_device_format_types = ["appleboot", "prepboot"]
+
+    # list of strings representing options for boot device types
+    boot_device_types = ["partition", "mdarray"]
+    boot_device_raid_levels = [mdraid.RAID1]
+    boot_device_format_types = ["hfs", "hfs+"]
+
+    packages = ["yaboot"]
+
+    image_label_attr = "short_label"
+
+    def __init__(self, storage):
+        BootLoader.__init__(self, storage)
+
+    #
+    # configuration
+    #
+
+    @property
+    def config_dir(self):
+        conf_dir = "/etc"
+        if self.stage2_device.format.mountpoint == "/boot":
+            conf_dir = "/boot/etc"
+        return conf_dir
+
+    @property
+    def config_file(self):
+        return "%s/%s" % (self.config_dir, self._config_file)
+
+    def write_config_header(self, config):
+        if self.stage2_device.type == "mdarray":
+            boot_part_num = self.stage2_device.parents[0].partedPartition.number
+        else:
+            boot_part_num = self.stage2_device.partedPartition.number
+
+        # yaboot.conf timeout is in tenths of a second. Brilliant.
+        header = ("# yaboot.conf generated by anaconda\n\n"
+                  "boot=%(stage1dev)s\n"
+                  "init-message=\"Welcome to %(product)s!\\nHit <TAB> for "
+                  "boot options\"\n\n"
+                  "partition=%(part_num)d\n"
+                  "timeout=%(timeout)d\n"
+                  "install=/usr/lib/yaboot/yaboot\n"
+                  "delay=5\n"
+                  "enablecdboot\n"
+                  "enableofboot\n"
+                  "enablenetboot\n"
+                  % {"stage1dev": self.stage1_device.path,
+                     "product": productName, "part_num": boot_part_num,
+                     "timeout": self.timeout * 10})
+        config.write(header)
+        self.write_config_variant_header(config)
+        self.write_config_password(config)
+        config.write("\n")
+
+    def write_config_variant_header(self, config):
+        config.write("nonvram\n")
+        config.write("mntpoint=/boot/yaboot\n")
+        config.write("usemount\n")
+
+    def write_config_post(self, install_root=""):
+        super(Yaboot, self).write_config_post(install_root=install_root)
+
+        # make symlink in /etc to yaboot.conf if config is in /boot/etc
+        etc_yaboot_conf = install_root + "/etc/yaboot.conf"
+        if not os.access(etc_yaboot_conf, os.R_OK):
+            try:
+                os.symlink("../boot/etc/yaboot.conf", etc_yaboot_conf)
+            except OSError as e:
+                log.error("failed to create /etc/yaboot.conf symlink: %s" % e)
+
+    def write_config(self, install_root=""):
+        if not os.path.isdir(install_root + self.config_dir):
+            os.mkdir(install_root + self.config_dir)
+
+        # this writes the config
+        super(Yaboot, self).write_config(install_root=install_root)
+
+    #
+    # installation
+    #
+
+    def install(self, install_root=""):
+        args = ["-f", "-C", self.config_file]
+        rc = iutil.execWithRedirect(self.prog, args,
+                                    stdout="/dev/tty5", stderr="/dev/tty5",
+                                    root=install_root)
+        if rc:
+            raise BootLoaderError("bootloader installation failed")
+
+
+class IPSeriesYaboot(Yaboot):
+    # XXX is this just for pSeries?
+    name = "Yaboot (IPSeries)"
+    prog = "mkofboot"
+
+    target_device_format_types = ["prepboot"]
+    target_device_min_size = 4
+    target_device_max_size = 10
+
+    target_descriptions = {"partition": N_("PReP Boot Partition"),
+                           "mdarray": N_("RAID Device")}
+
+    #
+    # configuration
+    #
+
+    def write_config_variant_header(self, config):
+        config.write("nonvram\n")   # only on pSeries?
+        config.write("fstype=raw\n")
+
+
+class MacYaboot(Yaboot):
+    name = "Yaboot (Mac)"
+    prog = "mkofboot"
+
+    can_dual_boot = True
+    target_device_format_types = ["appleboot"]
+    target_device_disklabel_types = ["mac"]
+    target_device_min_size = 800.00 / 1024.00
+    target_device_max_size = 1
+
+    target_descriptions = {"partition": N_("Apple Bootstrap Partition"),
+                           "mdarray": N_("RAID Device")}
+
+    #
+    # configuration
+    #
+
+    def write_config_variant_header(self, config):
+        try:
+            mac_os = [i for i in self.chain_images if i.label][0]
+        except IndexError:
+            pass
+        else:
+            config.write("macosx=%s\n" % mac_os.device.path)
+
+        config.write("magicboot=/usr/lib/yaboot/ofboot\n")
+
+
+class ZIPL(BootLoader):
+    name = "ZIPL"
+    config_file = "/etc/zipl.conf"
+
+    # list of strings representing options for bootloader target device types
+    target_device_types = ["disk", "partition"]
+    target_device_disklabel_types = ["msdos", "dasd"]
+
+    # list of strings representing options for boot device types
+    boot_device_types = ["partition", "mdarray", "lvmlv"]
+    boot_device_raid_levels = [mdraid.RAID1]
+
+    packages = ["s390utils"]    # is this bootloader or platform?
+    image_label_attr = "short_label"
+    preserve_args = ["cio_ignore"]
+
+    #
+    # configuration
+    #
+
+    @property
+    def boot_dir(self):
+        return "/boot"
+
+    def write_config_images(self, config):
+        for image in self.images:
+            args = ArgumentList()
+            if image.initrd:
+                initrd_line = "\tramdisk=%s/%s\n" % (self.boot_dir,
+                                                     image.initrd)
+            else:
+                initrd_line = ""
+            args.append("root=%s/%s" % (self.boot_dir, image.kernel))
+            args.extend(self.boot_args)
+            stanza = ("[%(label)s]\n"
+                      "\timage=%(boot_dir)s/%(kernel)s\n"
+                      "%(initrd_line)s"
+                      "\tparameters=\"%(args)s\"\n"
+                      % {"label": self.image_label(image),
+                         "kernel": image.kernel, "initrd_line": initrd_line,
+                         "args": args,
+                         "boot_dir": self.boot_dir})
+            config.write(stanza)
+
+    def write_config_header(self, config):
+        header = ("[defaultboot]\n"
+                  "timeout=%{timeout}d\n"
+                  "default=%{default}\n"
+                  "target=/boot\n"
+                  % {"timeout": self.timeout,
+                     "default": self.image_label(self.default)})
+        config.write(header)
+
+    #
+    # installation
+    #
+
+    def install(self, install_root=""):
+        buf = iutil.execWithCapture("zipl", [],
+                                    stderr="/dev/tty5",
+                                    root=install_root)
+        for line in buf.splitlines():
+            if line.startswith("Preparing boot device: "):
+                # Output here may look like:
+                #     Preparing boot device: dasdb (0200).
+                #     Preparing boot device: dasdl.
+                # We want to extract the device name and pass that.
+                name = re.sub(".+?: ", "", line)
+                name = re.sub("(\s\(.+\))?\.$", "", name)
+                device = self.storage.devicetree.getDeviceByName(name)
+                if not device:
+                    raise BootLoaderError("could not find IPL device")
+
+                self.stage1_device = device
+
+
+class SILO(YabootSILOBase):
+    name = "SILO"
+    _config_file = "silo.conf"
+    message_file = "/etc/silo.message"
+
+    # list of strings representing options for bootloader target device types
+    target_device_types = ["partition"]
+    target_device_disklabel_types = ["sun"]
+
+    # list of strings representing options for boot device types
+    boot_device_types = ["partition"]
+
+    packages = ["silo"]
+
+    image_label_attr = "short_label"
+
+    #
+    # configuration
+    #
+
+    @property
+    def config_dir(self):
+        if self.stage2_device.format.mountpoint == "/boot":
+            return "/boot"
+        else:
+            return "/etc"
+
+    @property
+    def config_file(self):
+        return "%s/%s" % (self.config_dir, self._config_file)
+
+    def write_message_file(self, install_root=""):
+        message_file = os.path.normpath(install_root + self.message_file)
+        f = open(message_file, "w")
+        f.write("Welcome to %s!\nHit <TAB> for boot options\n\n" % productName)
+        f.close()
+        os.chmod(message_file, 0600)
+
+    def write_config_header(self, config):
+        header = ("# silo.conf generated by anaconda\n\n"
+                  "#boot=%(stage1dev)s\n"
+                  "message=%(message)s\n"
+                  "timeout=%(timeout)d\n"
+                  "partition=%(boot_part_num)d\n"
+                  "default=%(default)s\n"
+                  % {"stage1dev": self.stage1_device.path,
+                     "message": self.message_file, "timeout": self.timeout,
+                     "boot_part_num": self.stage1_device.partedPartition.number,
+                     "default": self.image_label(self.default)})
+        config.write(header)
+        self.write_config_password(config)
+
+    def write_config_post(self, install_root=""):
+        etc_silo = os.path.normpath(install_root + "/etc/" + self._config_file)
+        if not os.access(etc_silo, os.R_OK):
+            try:
+                os.symlink("../boot/%s" % self._config_file, etc_silo)
+            except OSError as e:
+                log.warning("failed to create /etc/silo.conf symlink: %s" % e)
+
+    def write_config(self, install_root=""):
+        self.write_message_file(install_root=install_root)
+        super(SILO, self).write_config(install_root=install_root)
+
+    #
+    # installation
+    #
+
+    def install(self, install_root=""):
+        backup = "%s/backup.b" % self.config_dir
+        args = ["-f", "-C", self.config_file, "-S", backup]
+        variant = iutil.getSparcMachine()
+        if variant in ("sun4u", "sun4v"):
+            args.append("-u")
+        else:
+            args.append("-U")
+
+        rc = iutil.execWithRedirect("silo", args,
+                                    stdout="/dev/tty5", stderr="/dev/tty5",
+                                    root=install_root)
+
+        if rc:
+            raise BootLoaderError("bootloader install failed")
+
+
+""" anaconda-specific functions """
+
+# this doesn't need to exist anymore, but the messageWindow probably needs to
+# go somewhere
+def bootloaderSetupChoices(anaconda):
+    if anaconda.dir == DISPATCH_BACK:
+        rc = anaconda.intf.messageWindow(_("Warning"),
+                _("Filesystems have already been activated.  You "
+                  "cannot go back past this point.\n\nWould you like to "
+                  "continue with the installation?"),
+                type="custom", custom_icon=["error","error"],
+                custom_buttons=[_("_Exit installer"), _("_Continue")])
+
+        if rc == 0:
+            sys.exit(0)
+        return DISPATCH_FORWARD
+
+
+def writeSysconfigKernel(anaconda, default_kernel):
     f = open(anaconda.rootPath + "/etc/sysconfig/kernel", "w+")
     f.write("# UPDATEDEFAULT specifies if new-kernel-pkg should make\n"
             "# new kernels the default\n")
     # only update the default if we're setting the default to linux (#156678)
-    if (not defaultDev and not rootDev) or (defaultDev and rootDev.name == defaultDev.name):
+    if anaconda.bootloader.default.device == anaconda.storage.rootDevice:
         f.write("UPDATEDEFAULT=yes\n")
     else:
-        f.write("UPDATEDEFAULT=no\n")        
+        f.write("UPDATEDEFAULT=no\n")
     f.write("\n")
     f.write("# DEFAULTKERNEL specifies the default kernel package type\n")
-    f.write("DEFAULTKERNEL=%s\n" %(defkern,))
+    f.write("DEFAULTKERNEL=%s\n" % default_kernel)
     f.close()
 
-    dosync()
-    try:
-        rc = anaconda.bootloader.write(anaconda.rootPath, anaconda.bootloader,
-                                       kernelList, otherList, defaultDev)
-        w.pop()
 
-        if rc and anaconda.intf:
-            anaconda.intf.messageWindow(_("Warning"),
-                               _("There was an error installing the bootloader.  "
-                                 "The system may not be bootable."))
-    except booty.BootyNoKernelWarning:
-        w.pop()
+def writeBootloader(anaconda):
+    """ Write bootloader configuration to disk.
+
+        When we get here, the bootloader will already have a default linux
+        image. We only have to add images for the non-default kernels and
+        adjust the default to reflect whatever the default variant is.
+    """
+
+    # TODO: Verify the bootloader configuration has all it needs.
+    #
+    #       - zipl doesn't need to have a stage1 device set.
+    #       - Isn't it possible for stage1 to be unset on iSeries if not using
+    #         yaboot? If so, presumably they told us not to install any
+    #         bootloader.
+    stage1_device = anaconda.bootloader.stage1_device
+    log.info("bootloader stage1 target device is %s" % stage1_device.name)
+    stage2_device = anaconda.bootloader.stage2_device
+    log.info("bootloader stage2 target device is %s" % stage2_device.name)
+
+    w = None
+    if anaconda.intf:
+        w = anaconda.intf.waitWindow(_("Bootloader"),
+                                     _("Installing bootloader."))
+
+    # get a list of installed kernel packages
+    kernel_versions = anaconda.backend.kernelVersionList(anaconda.rootPath)
+    if not kernel_versions:
+        log.warning("no kernel was installed -- bootloader config unchanged")
         if anaconda.intf:
             anaconda.intf.messageWindow(_("Warning"),
-                               _("No kernel packages were installed on the "
-                                 "system.  Bootloader configuration "
-                                 "will not be changed."))
+                        _("No kernel packages were installed on the system "
+                          "Bootloader configuration will not be changed."))
+        return
 
-    dosync()
+    # The first one is the default kernel. Update the bootloader's default
+    # entry to reflect the details of the default kernel.
+    (version, arch, nick) = kernel_versions.pop(0)
+    default_image = anaconda.bootloader.default
+    if not default_image:
+        log.error("unable to find default image, bailing")
+        if w:
+            w.pop()
+        return
 
-def hasWindows(bl):
-    if not booty.doesDualBoot():
-        return False
+    default_image.version = version
+
+    # all the linux images' labels are based on the default image's
+    base_label = default_image.label
+    base_short = default_image.short_label
+
+    # get the name of the default kernel package for use in
+    # /etc/sysconfig/kernel
+    default_kernel = "kernel"
+    if nick != "base":
+        default_kernel += "-%s" % nick
+
+    # now add an image for each of the other kernels
+    used = ["base"]
+    for (version, arch, nick) in kernel_versions:
+        if nick in used:
+            nick += "-%s" % version
+
+        used.append(nick)
+        label = "%s-%s" % (base_label, nick)
+        short = "%s-%s" % (base_short, nick)
+        image = LinuxBootLoaderImage(device=anaconda.storage.rootDevice,
+                                     version=version,
+                                     label=label, short=short)
+        anaconda.bootloader.add_image(image)
 
-    foundWindows = False
-    # no point looking at the root device which won't be a dos type anyway
-    for (dev, type) in bl.images.availableBootDevices(bl.storage, addRoot=False):
-        if type in booty.dosFilesystems:
-            foundWindows = True
-            break
+    # write out /etc/sysconfig/kernel
+    writeSysconfigKernel(anaconda, default_kernel)
+
+    # set up dracut/fips boot args
+    anaconda.bootloader.set_boot_args(keyboard=anaconda.keyboard,
+                                      language=anaconda.instLanguage,
+                                      network=anaconda.network)
+
+    try:
+        anaconda.bootloader.write(install_root=anaconda.rootPath)
+    except BootLoaderError as e:
+        if anaconda.intf:
+            anaconda.intf.messageWindow(_("Warning"),
+                            _("There was an error installing the bootloader.  "
+                              "The system may not be bootable."))
+    finally:
+        if w:
+            w.pop()
 
-    return foundWindows
diff --git a/pyanaconda/booty/Makefile.am b/pyanaconda/booty/Makefile.am
deleted file mode 100644
index 8d03ee0..0000000
--- a/pyanaconda/booty/Makefile.am
+++ /dev/null
@@ -1,24 +0,0 @@
-# booty/Makefile.am for anaconda
-#
-# Copyright (C) 2009  Red Hat, Inc.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License as published
-# by the Free Software Foundation; either version 2.1 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-#
-# Author: David Cantrell <dcantrell@xxxxxxxxxx>
-
-pkgpyexecdir = $(pyexecdir)/py$(PACKAGE_NAME)
-bootydir = $(pkgpyexecdir)/booty
-booty_PYTHON = *.py
-
-MAINTAINERCLEANFILES = Makefile.in
diff --git a/pyanaconda/booty/__init__.py b/pyanaconda/booty/__init__.py
deleted file mode 100644
index defff9a..0000000
--- a/pyanaconda/booty/__init__.py
+++ /dev/null
@@ -1,52 +0,0 @@
-#
-# bootloader.py - generic boot loader handling backend for up2date and anaconda
-#
-# Jeremy Katz <katzj@xxxxxxxxxx>
-# Adrian Likins <alikins@xxxxxxxxxx>
-# Peter Jones <pjones@xxxxxxxxxx>
-#
-# Copyright 2001-2005 Red Hat, Inc.
-#
-# This software may be freely redistributed under the terms of the GNU
-# library public license.
-#
-# You should have received a copy of the GNU Library Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-#
-"""Module for manipulation and creation of boot loader configurations"""
-
-from pyanaconda import iutil
-from bootloaderInfo import *
-from pyanaconda.bootloader import *
-
-class BootyNoKernelWarning(Exception):
-    def __init__ (self, value=""):
-        self.value = value
-
-    def __str__ (self):
-        return self.value
-
-# return instance of the appropriate bootloader for our arch
-def getBootloader(anaconda):
-    """Get the bootloader info object for your architecture"""
-    if iutil.isX86():
-        import x86
-        return x86.x86BootloaderInfo(anaconda)
-    elif iutil.isIA64():
-        import ia64
-        return ia64.ia64BootloaderInfo(anaconda)
-    elif iutil.isS390():
-        import s390
-        return s390.s390BootloaderInfo(anaconda)
-    elif iutil.isAlpha():
-        import alpha
-        return alpha.alphaBootloaderInfo(anaconda)
-    elif iutil.isPPC():
-        import ppc
-        return ppc.ppcBootloaderInfo(anaconda)
-    elif iutil.isSparc():
-        import sparc
-        return sparc.sparcBootloaderInfo(anaconda)
-    else:
-        return bootloaderInfo(anaconda)
diff --git a/pyanaconda/booty/alpha.py b/pyanaconda/booty/alpha.py
deleted file mode 100644
index c7bd6e9..0000000
--- a/pyanaconda/booty/alpha.py
+++ /dev/null
@@ -1,140 +0,0 @@
-import os
-from pyanaconda import iutil
-
-from pyanaconda.booty import BootyNoKernelWarning
-from bootloaderInfo import *
-from util import getDiskPart
-
-class alphaBootloaderInfo(bootloaderInfo):
-    def writeAboot(self, instRoot, bl, kernelList,
-                   chainList, defaultDev):
-        rootDevice = self.storage.rootDevice
-        try:
-            bootDevice = self.storage.mountpoints["/boot"]
-        except KeyError:
-            bootDevice = rootDevice
-
-        bootnotroot = bootDevice != rootDevice
-
-        confFile = instRoot + self.configfile
-
-        # If /etc/aboot.conf already exists we rename it
-        # /etc/aboot.conf.rpmsave.
-        if os.path.isfile(confFile):
-            os.rename (confFile, confFile + ".rpmsave")
-
-        # Then we create the necessary files. If the root device isn't
-        # the boot device, we create /boot/etc/ where the aboot.conf
-        # will live, and we create /etc/aboot.conf as a symlink to it.
-        if bootnotroot:
-            # Do we have /boot/etc ? If not, create one
-            if not os.path.isdir (instRoot + '/boot/etc'):
-                os.mkdir(instRoot + '/boot/etc', 0755)
-
-            # We install the symlink (/etc/aboot.conf has already been
-            # renamed in necessary.)
-            os.symlink("../boot" + self.configfile, confFile)
-
-            cfPath = instRoot + "/boot" + self.configfile
-            # Kernel path is set to / because a boot partition will
-            # be a root on its own.
-            kernelPath = '/'
-        # Otherwise, we just need to create /etc/aboot.conf.
-        else:
-            cfPath = confFile
-            kernelPath = self.kernelLocation
-
-        # If we already have an aboot.conf, rename it
-        if os.access (cfPath, os.R_OK):
-            self.perms = os.stat(cfPath)[0] & 0777
-            os.rename(cfPath, cfPath + '.rpmsave')
-                
-        # Now we're going to create and populate cfPath.
-        f = open (cfPath, 'w+')
-        f.write ("# aboot default configurations\n")
-
-        if bootnotroot:
-            f.write ("# NOTICE: You have a /boot partition. This means that\n")
-            f.write ("#         all kernel paths are relative to /boot/\n")
-
-        # bpn is the boot partition number.
-        bpn = getDiskPart(bootDevice)
-        lines = 0
-
-        # We write entries line using the following format:
-        # <line><bpn><kernel-name> root=<rootdev> [options]
-        # We get all the kernels we need to know about in kernelList.
-
-        for (kernel, tag, version) in kernelList:
-            kernelTag = "-" + version
-            kernelFile = "%svmlinuz%s" %(kernelPath, kernelTag)
-
-            f.write("%d:%d%s" %(lines, bpn, kernelFile))
-
-            # See if we can come up with an initrd argument that exists
-            initrd = self.makeInitrd(kernelTag, instRoot)
-            if initrd:
-                f.write(" initrd=%s%s" %(kernelPath, initrd))
-
-            realroot = rootDevice.fstabSpec
-            f.write(" root=%s" %(realroot,))
-
-            args = self.args.get()
-            if args:
-                f.write(" %s" %(args,))
-
-            f.write("\n")
-            lines = lines + 1
-
-        # We're done writing the file
-        f.close ()
-        del f
-
-        # Now we're ready to write the relevant boot information. wbd
-        # is the whole boot device, bdpn is the boot device partition
-        # number.
-        wbd = getDiskPart(bootDevice)[0]
-        bdpn = getDiskPart(bootDevice)[1]
-
-        # Calling swriteboot. The first argument is the disk to write
-        # to and the second argument is a path to the bootstrap loader
-        # file.
-        args = [("/dev/%s" % wbd), "/boot/bootlx"]
-        rc = iutil.execWithRedirect ('/sbin/swriteboot', args,
-                                     root = instRoot,
-                                     stdout = "/dev/tty5",
-                                     stderr = "/dev/tty5")
-        if rc:
-            return rc
-
-        # Calling abootconf to configure the installed aboot. The
-        # first argument is the disk to use, the second argument is
-        # the number of the partition on which aboot.conf resides.
-        # It's always the boot partition whether it's / or /boot (with
-        # the mount point being omitted.)
-        args = [("/dev/%s" % wbd), str (bdpn)]
-        rc = iutil.execWithRedirect ('/sbin/abootconf', args,
-                                     root = instRoot,
-                                     stdout = "/dev/tty5",
-                                     stderr = "/dev/tty5")
-        if rc:
-            return rc
-
-        return 0
-
-
-    def write(self, instRoot, bl, kernelList, chainList, defaultDev):
-        if len(kernelList) < 1:
-            raise BootyNoKernelWarning
-
-        return self.writeAboot(instRoot, bl, kernelList,
-                               chainList, defaultDev)
-
-    def __init__(self, anaconda):
-        bootloaderInfo.__init__(self, anaconda)
-        self.useGrubVal = 0
-        self._configdir = "/etc"
-        self._configname = "aboot.conf"
-        # self.kernelLocation is already set to what we need.
-        self.password = None
-        self.pure = None
diff --git a/pyanaconda/booty/bootloaderInfo.py b/pyanaconda/booty/bootloaderInfo.py
deleted file mode 100644
index c297557..0000000
--- a/pyanaconda/booty/bootloaderInfo.py
+++ /dev/null
@@ -1,714 +0,0 @@
-#
-# bootloaderInfo.py - bootloader config object used in creation of new
-#                     bootloader configs.  Originally from anaconda
-#
-# Jeremy Katz <katzj@xxxxxxxxxx>
-# Erik Troan <ewt@xxxxxxxxxx>
-# Peter Jones <pjones@xxxxxxxxxx>
-#
-# Copyright 2005-2008 Red Hat, Inc.
-#
-# This software may be freely redistributed under the terms of the GNU
-# library public license.
-#
-# You should have received a copy of the GNU Library Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-#
-
-import os, sys
-import crypt
-import random
-import shutil
-import string
-import struct
-from copy import copy
-
-import gettext
-_ = lambda x: gettext.ldgettext("anaconda", x)
-N_ = lambda x: x
-
-from lilo import LiloConfigFile
-
-from pyanaconda.flags import flags
-from pyanaconda import iutil
-from pyanaconda import isys
-from pyanaconda.product import *
-
-import pyanaconda.booty
-import checkbootloader
-from util import getDiskPart
-
-if not iutil.isS390():
-    import block
-
-dosFilesystems = ('FAT', 'fat16', 'fat32', 'ntfs', 'hpfs')
-
-def doesDualBoot():
-    if iutil.isX86():
-        return 1
-    return 0
-
-def checkForBootBlock(device):
-    fd = os.open(device, os.O_RDONLY)
-    buf = os.read(fd, 512)
-    os.close(fd)
-    if len(buf) >= 512 and \
-           struct.unpack("H", buf[0x1fe: 0x200]) == (0xaa55,):
-        return True
-    return False
-
-# hack and a half
-# there's no guarantee that data is written to the disk and grub
-# reads both the filesystem and the disk.  suck.
-def syncDataToDisk(dev, mntpt, instRoot = "/"):
-    isys.sync()
-    isys.sync()
-    isys.sync()
-
-    # and xfs is even more "special" (#117968)
-    if isys.readFSType(dev) == "xfs":
-        iutil.execWithRedirect("/usr/sbin/xfs_freeze",
-                               ["-f", mntpt],
-                               stdout = "/dev/tty5",
-                               stderr = "/dev/tty5",
-                               root = instRoot)
-        iutil.execWithRedirect("/usr/sbin/xfs_freeze",
-                               ["-u", mntpt],
-                               stdout = "/dev/tty5",
-                               stderr = "/dev/tty5",
-                               root = instRoot)    
-
-def rootIsDevice(dev):
-    if dev.startswith("LABEL=") or dev.startswith("UUID="):
-        return False
-    return True
-
-class KernelArguments:
-
-    def getDracutStorageArgs(self, devices):
-        args = []
-        types = {}
-        for device in devices:
-            for d in self.anaconda.storage.devices:
-                if d is not device and not device.dependsOn(d):
-                    continue
-
-                s = d.dracutSetupString()
-                types[s.split("=")[0]] = True
-                if s not in args:
-                    args.append(s)
-
-                from pyanaconda import storage
-                if isinstance(d, storage.devices.NetworkStorageDevice):
-                    s = self.anaconda.network.dracutSetupString(d)
-                    if s not in args:
-                        args.append(s)
-
-        for i in [ [ "rd_LUKS_UUID", "rd_NO_LUKS" ],
-                   [ "rd_LVM_LV", "rd_NO_LVM" ],
-                   [ "rd_MD_UUID", "rd_NO_MD" ],
-                   [ "rd_DM_UUID", "rd_NO_DM" ] ]:
-            if not types.has_key(i[0]):
-                args.append(i[1])
-
-        return args
-
-    def get(self):
-        args = ""
-        bootArgs = []
-        rootDev = self.anaconda.storage.rootDevice
-        neededDevs = [ rootDev ] + self.anaconda.storage.swaps
-
-        if flags.cmdline.get("fips") == "1":
-            bootDev = self.anaconda.storage.mountpoints.get("/boot", rootDev)
-            bootArgs = [ "boot=%s" % bootDev.fstabSpec ]
-            if bootDev is not rootDev:
-                neededDevs = [ rootDev, bootDev ]
-
-        if self.anaconda.storage.fsset.swapDevices:
-            neededDevs.append(self.anaconda.storage.fsset.swapDevices[0])
-
-        for s in bootArgs + \
-                 self.getDracutStorageArgs(neededDevs) + [
-                 self.anaconda.instLanguage.dracutSetupString(),
-                 self.anaconda.keyboard.dracutSetupString(),
-                 self.args,
-                 self.appendArgs ]:
-            s = s.strip()
-            if not s:
-                continue
-            if args:
-                args += " "
-            args += s
-
-        return args
-
-    def set(self, args):
-        self.args = args
-        self.appendArgs = ""
-
-    def getNoDracut(self):
-        args = self.args.strip() + " " + self.appendArgs.strip()
-        return args.strip()
-
-    def chandevget(self):
-        return self.cargs
-
-    def chandevset(self, args):
-        self.cargs = args
-
-    def append(self, args):
-        # don't duplicate the addition of an argument (#128492)
-        if self.args.find(args) != -1:
-            return
-        if self.appendArgs.find(args) != -1:
-            return
-
-        if self.appendArgs:
-            self.appendArgs += " "
-
-        self.appendArgs += args
-
-    def __init__(self, anaconda):
-        newArgs = []
-
-        self.anaconda = anaconda
-
-        if iutil.isS390():
-            self.cargs = []
-
-        # look for kernel arguments we know should be preserved and add them
-        ourargs = ["speakup_synth", "apic", "noapic", "apm", "ide", "noht",
-                   "acpi", "video", "pci", "nodmraid", "nompath", "nomodeset",
-                   "noiswmd", "fips"]
-
-        if iutil.isS390():
-            ourargs.append("cio_ignore")
-
-        for arg in ourargs:
-            if not flags.cmdline.has_key(arg):
-                continue
-
-            val = flags.cmdline.get(arg, "")
-            if val:
-                newArgs.append("%s=%s" % (arg, val))
-            else:
-                newArgs.append(arg)
-
-        self.args = " ".join(newArgs)
-        self.appendArgs = ""
-
-
-class BootImages:
-    """A collection to keep track of boot images available on the system.
-    Examples would be:
-    ('linux', 'Red Hat Linux', 'ext2'),
-    ('Other', 'Other', 'fat32'), ...
-    """
-    def __init__(self):
-        self.default = None
-        self.images = {}
-
-    def getImages(self):
-        """returns dictionary of (label, longlabel, devtype) pairs 
-        indexed by device"""
-        # return a copy so users can modify it w/o affecting us
-        return copy(self.images)
-
-    def setDefault(self, default):
-        # default is a device
-        self.default = default
-
-    def getDefault(self):
-        return self.default
-
-    # Construct a dictionary mapping device names to (OS, product, type)
-    # tuples.
-    def setup(self, storage):
-        devices = {}
-        bootDevs = self.availableBootDevices(storage)
-
-        for (dev, type) in bootDevs:
-            devices[dev.name] = 1
-
-        # These partitions have disappeared
-        for dev in self.images.keys():
-            if not devices.has_key(dev):
-                del self.images[dev]
-
-        # These have appeared
-        for (dev, type) in bootDevs:
-            if not self.images.has_key(dev.name):
-                if type in dosFilesystems and doesDualBoot():
-                    self.images[dev.name] = ("Other", "Other", type)
-                elif type in ("hfs", "hfs+") and iutil.getPPCMachine() == "PMac":
-                    self.images[dev.name] = ("Other", "Other", type)
-                else:
-                    self.images[dev.name] = (None, None, type)
-
-        if not self.images.has_key(self.default):
-            self.default = storage.rootDevice.name
-            (label, longlabel, type) = self.images[self.default]
-            if not label:
-                self.images[self.default] = ("linux", productName, type)
-
-    # Return a list of (storage.Device, string) tuples that are bootable
-    # devices.  The string is the type of the device, which is just a string
-    # like "vfat" or "swap" or "lvm".
-    # Appends information about the root device when addRoot is true.
-    def availableBootDevices(self, storage, addRoot=True):
-        import parted
-        retval = []
-        foundDos = False
-        foundAppleBootstrap = False
-
-        for part in [p for p in storage.partitions if p.exists]:
-            # Skip extended, metadata, freespace, etc.
-            if part.partType not in (parted.PARTITION_NORMAL, parted.PARTITION_LOGICAL) or not part.format:
-                continue
-
-            if part.format.type in dosFilesystems and \
-               not foundDos and doesDualBoot() and \
-               not part.getFlag(parted.PARTITION_DIAG):
-                try:
-                    bootable = checkForBootBlock(part.path)
-                except (OSError, struct.error):
-                    pass
-                else:
-                    retval.append((part, part.format.type))
-                    foundDos = True
-            elif part.format.type == "appleboot" and \
-                 iutil.getPPCMachine() == "PMac" and part.bootable:
-                foundAppleBootstrap = True
-            elif part.format.type in ["hfs", "hfs+"] and foundAppleBootstrap:
-                # questionable for same reason as above, but on mac this time
-                retval.append((part, part.format.type))
-
-        if addRoot:
-            rootDevice = storage.rootDevice
-            if not rootDevice or not rootDevice.format:
-                raise ValueError, ("Trying to pick boot devices but do not have a "
-                                   "sane root partition.  Aborting install.")
-            retval.append((rootDevice, rootDevice.format.type))
-
-        retval.sort()
-        return retval
-
-class bootloaderInfo(object):
-    def getConfigFileName(self):
-        if not self._configname:
-            raise NotImplementedError
-        return self._configname
-    configname = property(getConfigFileName, None, None, \
-                          "bootloader config file name")
-
-    def getConfigFileDir(self):
-        if not self._configdir:
-            raise NotImplementedError
-        return self._configdir
-    configdir = property(getConfigFileDir, None, None, \
-                         "bootloader config file directory")
-
-    def getConfigFilePath(self):
-        return "%s/%s" % (self.configdir, self.configname)
-    configfile = property(getConfigFilePath, None, None, \
-                          "full path and name of the real config file")
-
-    def setUseGrub(self, val):
-        pass
-
-    def useGrub(self):
-        return self.useGrubVal
-
-    def setPassword(self, val, isCrypted = 1):
-        pass
-
-    def getPassword(self):
-        pass
-
-    def getDevice(self):
-        return self.device
-
-    def setDevice(self, device):
-        self.device = device
-
-        (dev, part) = getDiskPart(
-                             self.storage.devicetree.getDeviceByName(device))
-        if part is None:
-            self.defaultDevice = "mbr"
-        else:
-            self.defaultDevice = "partition"
-
-    def makeInitrd(self, kernelTag, instRoot):
-        initrd = "initrd%s.img" % kernelTag
-        if os.access(instRoot + "/boot/" + initrd, os.R_OK):
-            return initrd
-
-        initrd = "initramfs%s.img" % kernelTag
-        if os.access(instRoot + "/boot/" + initrd, os.R_OK):
-            return initrd
-
-        return None
-
-    def getBootloaderConfig(self, instRoot, bl, kernelList,
-                            chainList, defaultDev):
-        images = bl.images.getImages()
-
-        confFile = instRoot + self.configfile
-
-        # on upgrade read in the lilo config file
-        lilo = LiloConfigFile ()
-        self.perms = 0600
-        if os.access (confFile, os.R_OK):
-            self.perms = os.stat(confFile)[0] & 0777
-            lilo.read(confFile)
-            os.rename(confFile, confFile + ".rpmsave")
-        # if it's an absolute symlink, just get it out of our way
-        elif (os.path.islink(confFile) and os.readlink(confFile)[0] == '/'):
-            os.rename(confFile, confFile + ".rpmsave")
-
-        # Remove any invalid entries that are in the file; we probably
-        # just removed those kernels. 
-        for label in lilo.listImages():
-            (fsType, sl, path, other) = lilo.getImage(label)
-            if fsType == "other": continue
-
-            if not os.access(instRoot + sl.getPath(), os.R_OK):
-                lilo.delImage(label)
-
-        lilo.addEntry("prompt", replace = 0)
-        lilo.addEntry("timeout", self.timeout or "20", replace = 0)
-
-        rootDev = self.storage.rootDevice
-
-        if rootDev.name == defaultDev.name:
-            lilo.addEntry("default", kernelList[0][0])
-        else:
-            lilo.addEntry("default", chainList[0][0])
-
-        for (label, longlabel, version) in kernelList:
-            kernelTag = "-" + version
-            kernelFile = self.kernelLocation + "vmlinuz" + kernelTag
-
-            try:
-                lilo.delImage(label)
-            except IndexError as msg:
-                pass
-
-            sl = LiloConfigFile(imageType = "image", path = kernelFile)
-
-            initrd = self.makeInitrd(kernelTag, instRoot)
-
-            sl.addEntry("label", label)
-            if initrd:
-                sl.addEntry("initrd", "%s%s" %(self.kernelLocation, initrd))
-
-            sl.addEntry("read-only")
-
-            append = "%s" %(self.args.get(),)
-            realroot = rootDev.fstabSpec
-            if rootIsDevice(realroot):
-                sl.addEntry("root", rootDev.path)
-            else:
-                if len(append) > 0:
-                    append = "%s root=%s" %(append,realroot)
-                else:
-                    append = "root=%s" %(realroot,)
-            
-            if len(append) > 0:
-                sl.addEntry('append', '"%s"' % (append,))
-                
-            lilo.addImage (sl)
-
-        for (label, longlabel, device) in chainList:
-            if ((not label) or (label == "")):
-                continue
-            try:
-                (fsType, sl, path, other) = lilo.getImage(label)
-                lilo.delImage(label)
-            except IndexError:
-                sl = LiloConfigFile(imageType = "other",
-                                    path = "/dev/%s" %(device))
-                sl.addEntry("optional")
-
-            sl.addEntry("label", label)
-            lilo.addImage (sl)
-
-        # Sanity check #1. There could be aliases in sections which conflict
-        # with the new images we just created. If so, erase those aliases
-        imageNames = {}
-        for label in lilo.listImages():
-            imageNames[label] = 1
-
-        for label in lilo.listImages():
-            (fsType, sl, path, other) = lilo.getImage(label)
-            if sl.testEntry('alias'):
-                alias = sl.getEntry('alias')
-                if imageNames.has_key(alias):
-                    sl.delEntry('alias')
-                imageNames[alias] = 1
-
-        # Sanity check #2. If single-key is turned on, go through all of
-        # the image names (including aliases) (we just built the list) and
-        # see if single-key will still work.
-        if lilo.testEntry('single-key'):
-            singleKeys = {}
-            turnOff = 0
-            for label in imageNames.keys():
-                l = label[0]
-                if singleKeys.has_key(l):
-                    turnOff = 1
-                singleKeys[l] = 1
-            if turnOff:
-                lilo.delEntry('single-key')
-
-        return lilo
-
-    def write(self, instRoot, bl, kernelList, chainList, defaultDev):
-        rc = 0
-
-        if len(kernelList) >= 1:
-            config = self.getBootloaderConfig(instRoot, bl,
-                                              kernelList, chainList,
-                                              defaultDev)
-            rc = config.write(instRoot + self.configfile, perms = self.perms)
-        else:
-            raise pyanaconda.booty.BootyNoKernelWarning
-
-        return rc
-
-    def getArgList(self):
-        args = []
-
-        if self.defaultDevice is None:
-            args.append("--location=none")
-            return args
-
-        args.append("--location=%s" % (self.defaultDevice,))
-        args.append("--driveorder=%s" % (",".join(self.drivelist)))
-
-        if self.args.getNoDracut():
-            args.append("--append=\"%s\"" %(self.args.getNoDracut()))
-
-        return args
-
-    def writeKS(self, f):
-        f.write("bootloader")
-        for arg in self.getArgList():
-            f.write(" " + arg)
-        f.write("\n")
-
-    def updateDriveList(self, sortedList=[]):
-        # bootloader is unusual in that we only want to look at disks that
-        # have disklabels -- no partitioned md or unpartitioned disks
-        disks = self.storage.disks
-        partitioned = self.storage.partitioned
-        self._drivelist = [d.name for d in disks if d in partitioned]
-        self._drivelist.sort(self.storage.compareDisks)
-
-        # If we're given a sort order, make sure the drives listed in it
-        # are put at the head of the drivelist in that order.  All other
-        # drives follow behind in whatever order they're found.
-        if sortedList != []:
-            revSortedList = sortedList
-            revSortedList.reverse()
-
-            for i in revSortedList:
-                try:
-                    ele = self._drivelist.pop(self._drivelist.index(i))
-                    self._drivelist.insert(0, ele)
-                except LookupError:
-                    pass
-
-    def _getDriveList(self):
-        if self._drivelist is not None:
-            return self._drivelist
-        self.updateDriveList()
-        return self._drivelist
-    def _setDriveList(self, val):
-        self._drivelist = val
-    drivelist = property(_getDriveList, _setDriveList)
-
-    def __init__(self, anaconda):
-        self.args = KernelArguments(anaconda)
-        self.images = BootImages()
-        self.device = None
-        self.defaultDevice = None  # XXX hack, used by kickstart
-        self.useGrubVal = 0      # only used on x86
-        self._configdir = None
-        self._configname = None
-        self.kernelLocation = "/boot/"
-        self.password = None
-        self.pure = None
-        self.above1024 = 0
-        self.timeout = None
-        self.storage = anaconda.storage
-        self.serial = 0
-        self.serialDevice = None
-        self.serialOptions = None
-
-        # this has somewhat strange semantics.  if 0, act like a normal
-        # "install" case.  if 1, update lilo.conf (since grubby won't do that)
-        # and then run lilo or grub only.
-        # XXX THIS IS A HACK.  implementation details are only there for x86
-        self.doUpgradeOnly = 0
-        self.kickstart = 0
-
-        self._drivelist = None
-
-        if flags.serial != 0:
-            self.serial = 1
-            self.timeout = 5
-
-            console = flags.cmdline.get("console", "")
-            if console:
-                # the options are everything after the comma
-                comma = console.find(",")
-                if comma != -1:
-                    self.serialDevice = console[:comma]
-                    self.serialOptions = console[comma + 1:]
-                else:
-                    self.serialDevice = console
-                    self.serialOptions = ""
-            else:
-                self.serialDevice = "ttyS0"
-                self.serialOptions = ""
-
-            if self.serialOptions:
-                self.args.append("console=%s,%s" %(self.serialDevice,
-                                                   self.serialOptions))
-            else:
-                self.args.append("console=%s" % self.serialDevice)
-
-        if flags.virtpconsole is not None:
-            if flags.virtpconsole.startswith("/dev/"):
-                con = flags.virtpconsole[5:]
-            else:
-                con = flags.virtpconsole
-            self.args.append("console=%s" %(con,))
-
-class efiBootloaderInfo(bootloaderInfo):
-    def getBootloaderName(self):
-        return self._bootloader
-    bootloader = property(getBootloaderName, None, None, \
-                          "name of the bootloader to install")
-
-    # XXX wouldn't it be nice to have a real interface to use efibootmgr from?
-    def removeOldEfiEntries(self, instRoot):
-        p = os.pipe()
-        rc = iutil.execWithRedirect('efibootmgr', [],
-                                    root = instRoot, stdout = p[1])
-        os.close(p[1])
-        if rc:
-            return rc
-
-        c = os.read(p[0], 1)
-        buf = c
-        while (c):
-            c = os.read(p[0], 1)
-            buf = buf + c
-        os.close(p[0])
-        lines = string.split(buf, '\n')
-        for line in lines:
-            fields = string.split(line)
-            if len(fields) < 2:
-                continue
-            if string.join(fields[1:], " ") == productName:
-                entry = fields[0][4:8]
-                rc = iutil.execWithRedirect('efibootmgr',
-                                            ["-b", entry, "-B"],
-                                            root = instRoot,
-                                            stdout="/dev/tty5", stderr="/dev/tty5")
-                if rc:
-                    return rc
-
-        return 0
-
-    def addNewEfiEntry(self, instRoot):
-        try:
-            bootdev = self.storage.mountpoints["/boot/efi"].name
-        except (KeyError, AttributeError):
-            bootdev = "sda1"
-
-        link = "%s%s/%s" % (instRoot, "/etc/", self.configname)
-        if not os.access(link, os.R_OK):
-            os.symlink("../%s" % (self.configfile), link)
-
-        ind = len(bootdev)
-        try:
-            while (bootdev[ind-1] in string.digits):
-                ind = ind - 1
-        except IndexError:
-            ind = len(bootdev) - 1
-
-        bootdisk = bootdev[:ind]
-        bootpart = bootdev[ind:]
-        if (bootdisk.startswith('ida/') or bootdisk.startswith('cciss/') or
-            bootdisk.startswith('rd/') or bootdisk.startswith('sx8/')):
-            bootdisk = bootdisk[:-1]
-
-        argv = [ "efibootmgr", "-c" , "-w", "-L",
-                 productName, "-d", "/dev/%s" % bootdisk,
-                 "-p", bootpart, "-l", "\\EFI\\redhat\\" + self.bootloader ]
-        rc = iutil.execWithRedirect(argv[0], argv[1:], root = instRoot,
-                                    stdout = "/dev/tty5",
-                                    stderr = "/dev/tty5")
-        return rc
-
-    def getEfiProductPath(self, productName, force=False):
-        """ Return the full EFI path of the installed product.
-            eg. HD(4,2c8800,64000,902c1655-2677-4455-b2a5-29d0ce835610)
-
-            pass force=True to skip the cache and rerun efibootmgr
-        """
-        if not force and self._efiProductPath:
-            return self._efiProductPath
-
-        argv = [ "efibootmgr", "-v" ]
-        buf = iutil.execWithCapture(argv[0], argv[1:],
-                                    stderr="/dev/tty5")
-
-        efiProductPath = None
-        for line in buf.splitlines():
-            line = line.strip()
-            if not line:
-                continue
-            if productName in line:
-                efiProductPath = line[line.rfind(productName)+len(productName):].strip()
-                break
-
-        if efiProductPath:
-            # Grab just the drive path
-            import re
-            m = re.match("(.*?\(.*?\)).*", efiProductPath)
-            if m:
-                efiProductPath = m.group(1)
-            else:
-                efiProductPath = None
-
-        self._efiProductPath = efiProductPath
-        return self._efiProductPath
-
-    def installGrub(self, instRoot, bootDev, grubTarget, grubPath, cfPath):
-        if not iutil.isEfi():
-            raise EnvironmentError
-        rc = self.removeOldEfiEntries(instRoot)
-        if rc:
-            return rc
-        return self.addNewEfiEntry(instRoot)
-
-    def __init__(self, anaconda, initialize = True):
-        if initialize:
-            bootloaderInfo.__init__(self, anaconda)
-        else:
-            self.storage = anaconda.storage
-
-        self._efiProductPath = None
-
-        if iutil.isEfi():
-            self._configdir = "/boot/efi/EFI/redhat"
-            self._configname = "grub.conf"
-            self._bootloader = "grub.efi"
-            self.useGrubVal = 1
-            self.kernelLocation = ""
diff --git a/pyanaconda/booty/checkbootloader.py b/pyanaconda/booty/checkbootloader.py
deleted file mode 100644
index 3cf8dc3..0000000
--- a/pyanaconda/booty/checkbootloader.py
+++ /dev/null
@@ -1,176 +0,0 @@
-#!/usr/bin/python
-#
-# Check to see whether it looks like GRUB or LILO is the boot loader
-# being used on the system.
-#
-# Jeremy Katz <katzj@xxxxxxxxxx>
-# Peter Jones <pjones@xxxxxxxxxx>
-#
-# Copyright 2001,2005 Red Hat, Inc.
-#
-# This software may be freely redistributed under the terms of the GNU
-# library public license.
-#
-# You should have received a copy of the GNU Library Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-import os
-import string
-
-from util import getDiskPart
-from pyanaconda import iutil
-
-grubConfigFile = "/etc/grub.conf"
-liloConfigFile = "/etc/lilo.conf"
-yabootConfigFile = "/etc/yaboot.conf"
-siloConfigFile = "/etc/silo.conf"
-ziplConfigFile = "/etc/zipl.conf"
-
-def getBootBlock(bootDev, instRoot, seekBlocks=0):
-    """Get the boot block from bootDev.  Return a 512 byte string."""
-    block = " " * 512
-    if bootDev is None:
-        return block
-
-    try:
-        fd = os.open("%s%s" % (instRoot, bootDev), os.O_RDONLY)
-        if seekBlocks > 0:
-            os.lseek(fd, seekBlocks * 512, 0)
-        block = os.read(fd, 512)
-        os.close(fd)
-    except:
-        pass
-
-    return block
-
-# takes a line like #boot=/dev/hda and returns /dev/hda
-# also handles cases like quoted versions and other nonsense
-def getBootDevString(line):
-    dev = string.split(line, '=')[1]
-    dev = string.strip(dev)
-    dev = string.replace(dev, '"', '')
-    dev = string.replace(dev, "'", "")
-    return dev
-
-def getBootDevList(line):
-    devs = string.split(line, '=')[1]
-    rets = []
-    for dev in devs:
-        dev = getBootDevString("=%s" % (dev,))
-        rets.append(dev)
-    return string.join(rets)
-
-def getBootloaderTypeAndBoot(instRoot, storage):
-    haveGrubConf = 1
-    haveLiloConf = 1
-    haveYabootConf = 1
-    haveSiloConf = 1
-    haveZiplConf = 1
-    
-    bootDev = None
-    
-    # make sure they have the config file, otherwise we definitely can't
-    # use that bootloader
-    if not os.access(instRoot + grubConfigFile, os.R_OK):
-        haveGrubConf = 0
-    if not os.access(instRoot + liloConfigFile, os.R_OK):
-        haveLiloConf = 0
-    if not os.access(instRoot + yabootConfigFile, os.R_OK):
-        haveYabootConf = 0
-    if not os.access(instRoot + siloConfigFile, os.R_OK):
-        haveSiloConf = 0
-    if not os.access(instRoot + ziplConfigFile, os.R_OK):
-        haveZiplConf = 0
-
-    if haveGrubConf:
-        bootDev = None
-        for (fn, stanza) in [ ("/etc/sysconfig/grub", "boot="),
-                              (grubConfigFile, "#boot=") ]:
-            try:
-                f = open(instRoot + fn, "r")
-            except:
-                continue
-        
-            # the following bits of code are straight from checkbootloader.py
-            lines = f.readlines()
-            f.close()
-            for line in lines:
-                if line.startswith(stanza):
-                    bootDev = getBootDevString(line)
-                    break
-            if bootDev is not None:
-                break
-
-        if iutil.isEfi():
-            return ("GRUB", bootDev)
-
-        if bootDev is not None:
-            block = getBootBlock(bootDev, instRoot)
-            # XXX I don't like this, but it's what the maintainer suggested :(
-            if string.find(block, "GRUB") >= 0:
-                return ("GRUB", bootDev)
-
-    if haveLiloConf:
-        f = open(instRoot + liloConfigFile, "r")
-        lines = f.readlines()
-        for line in lines:
-            if line[0:5] == "boot=":
-                bootDev = getBootDevString(line)
-                break
-
-        block = getBootBlock(bootDev, instRoot)
-        # this at least is well-defined
-        if block[6:10] == "LILO":
-            return ("LILO", bootDev)
-
-    if haveYabootConf:
-        f = open(instRoot + yabootConfigFile, "r")
-        lines = f.readlines()
-        for line in lines:
-            if line[0:5] == "boot=":
-                bootDev = getBootDevList(line)
-
-        if bootDev:
-                return ("YABOOT", bootDev)
-
-    if haveSiloConf:
-        bootDev = None
-        # We've never done the /etc/sysconfig/silo thing, but maybe 
-        # we should start...
-        for (fn, stanza) in [ ("/etc/sysconfig/silo", "boot="),
-                              (grubConfigFile, "#boot=") ]:
-            try:
-                f = open(instRoot + fn, "r")
-            except:
-                continue
-
-            lines = f.readlines()
-            f.close()
-            for line in lines:
-                if line.startswith(stanza):
-                    bootDev = getBootDevString(line)
-                    break
-            if bootDev is not None:
-                break
-
-        if bootDev is not None:
-            # XXX SILO sucks just like grub.
-            dev = storage.devicetree.getDeviceByName(bootDev)
-            if getDiskPart(dev)[1] != 4:
-                block = getBootBlock(bootDev, instRoot, 1)
-                if block[24:28] == "SILO":
-                    return ("SILO", bootDev)
-
-    if haveZiplConf:
-        bootDev = None
-        f = open(instRoot + ziplConfigFile, "r")
-        lines = f.readlines()
-        for line in lines:
-            if line[0:7] == "target=":
-                bootDev = getBootDevList(line)
-
-        if bootDev:
-            return ("ZIPL", bootDev)
-
-    return (None, None)
diff --git a/pyanaconda/booty/ia64.py b/pyanaconda/booty/ia64.py
deleted file mode 100644
index 796ed5c..0000000
--- a/pyanaconda/booty/ia64.py
+++ /dev/null
@@ -1,38 +0,0 @@
-from pyanaconda.booty import BootyNoKernelWarning
-from bootloaderInfo import *
-
-class ia64BootloaderInfo(efiBootloaderInfo):
-    def getBootloaderConfig(self, instRoot, bl, kernelList,
-                            chainList, defaultDev):
-        config = bootloaderInfo.getBootloaderConfig(self, instRoot,
-                                                    bl, kernelList, chainList,
-                                                    defaultDev)
-        # altix boxes need relocatable (#120851)
-        config.addEntry("relocatable")
-
-        return config
-
-    def writeLilo(self, instRoot, bl, kernelList, 
-                  chainList, defaultDev):
-        config = self.getBootloaderConfig(instRoot, bl,
-                                          kernelList, chainList, defaultDev)
-        return config.write(instRoot + self.configfile, perms = 0755)
-
-    def write(self, instRoot, bl, kernelList, chainList, defaultDev):
-        if len(kernelList) >= 1:
-            rc = self.writeLilo(instRoot, bl, kernelList,
-                                chainList, defaultDev)
-            if rc:
-                return rc
-        else:
-            raise BootyNoKernelWarning
-
-        rc = self.removeOldEfiEntries(instRoot)
-        if rc:
-            return rc
-        return self.addNewEfiEntry(instRoot)
-
-    def __init__(self, anaconda):
-        efiBootloaderInfo.__init__(self, anaconda)
-        self._configname = "elilo.conf"
-        self._bootloader = "elilo.efi"
diff --git a/pyanaconda/booty/lilo.py b/pyanaconda/booty/lilo.py
deleted file mode 100644
index dc2328e..0000000
--- a/pyanaconda/booty/lilo.py
+++ /dev/null
@@ -1,308 +0,0 @@
-#!/usr/bin/python
-#
-# Module for manipulation of lilo.conf files. Original found
-#    in the anaconda installer
-# Copyright (c) 1999-2001 Red Hat, Inc.  Distributed under GPL.
-#
-# Author: Matt Wilson <msw@xxxxxxxxxx>
-#         Eric Troan <ewt@xxxxxxxxxx>
-#         Adrian Likins <alikins@xxxxxxxxxx>
-"""Module for manipulation of lilo.conf files."""
-import string
-import os
-
-from UserDict import UserDict
-
-
-class UserDictCase(UserDict):
-    """A dictionary with case insensitive keys"""
-    def __init__(self, data = {}):
-        UserDict.__init__(self)
-        # if we are passed a dictionary transfer it over...
-        for k in data.keys():
-            kl = string.lower(k)
-            self.data[kl] = data[k]
-    # some methods used to make the class work as a dictionary
-    def __setitem__(self, key, value):
-        key = string.lower(key)
-        self.data[key] = value
-    def __getitem__(self, key):
-        key = string.lower(key)
-        if not self.data.has_key(key):
-            return None
-        return self.data[key]
-    get = __getitem__
-    def __delitem__(self, key):
-        key = string.lower(key)
-        del self.data[key]
-    def has_key(self, key):
-        key = string.lower(key)
-        return self.data.has_key(key)
-    # return this data as a real hash
-    def get_hash(self):
-        return self.data
-    # return the data for marshalling
-    def __getstate__(self):
-        return self.data
-    # we need a setstate because of the __getstate__ presence screws up deepcopy
-    def __setstate__(self, state):
-        self.__init__(state)
-    # get a dictionary out of this instance ({}.update doesn't get instances)
-    def dict(self):
-        return self.data
-
-class LiloConfigFile:
-    """class representing a lilo.conf lilo configuration file. Used to
-    manipulate the file directly"""
-    
-    def __repr__ (self, tab = 0):
-        s = ""
-        for n in self.order:
-            if (tab):
-                s = s + '\t'
-            if n[0] == '#':
-                s = s + n[1:]
-            else:
-                s = s + n
-                if self.items[n]:
-                    s = s + "=" + self.items[n]
-            s = s + '\n'
-        for count in range(len(self.diskRemaps)):
-            s = s + "disk = %s\n" % self.diskRemaps[count][1]
-            s = s + "\tbios = %s\n" % self.biosRemaps[count][1] 
-        for cl in self.images:
-            s = s + "\n%s=%s\n" % (cl.imageType, cl.path)
-            s = s + cl.__repr__(1)
-        return s
-
-    def addEntry(self, item, val = None, replace = 1):
-        if not self.items.has_key(item):
-            self.order.append(item)
-        elif not replace:
-            return
-
-        if (val):
-            self.items[item] = str(val)
-        else:
-            self.items[item] = None
-
-    def getEntry(self, item):
-        if self.items.has_key(item):
-            return self.items[item]
-        else:
-            return None
-
-    def delEntry(self, item):
-        newOrder = []
-        for i in self.order:
-            if item != i: newOrder.append(i)
-        self.order = newOrder
-
-        del self.items[item]
-
-    def listEntries(self):
-        foo = self.items
-        return foo
-
-    def testEntry(self, item):
-        if self.items.has_key(item):
-            return 1
-        else:
-            return 0
-
-    def getImage(self, label):
-        for config in self.images:
-            # sanity check
-            if label is None:
-                break
-            if config.getEntry('label'):
-                if string.lower(config.getEntry('label')) == string.lower(label):
-                    return (config.imageType, config, config.path, config.other)
-            if config.getEntry('alias'):
-                if string.lower(config.getEntry('alias')) == string.lower(label):
-                    return (config.imageType, config, config.path, config.other)
-    
-        
-        raise IndexError, "unknown image %s" % (label)
-
-    def addImage (self, config,first=None):
-        # make sure the config has a valid label
-        config.getEntry('label')
-        if not config.path or not config.imageType:
-            raise ValueError, "subconfig missing path or image type"
-
-        if first:
-            self.images = [config] + self.images
-        else:
-            self.images.append(config)
-
-    def delImage (self, label):
-        for config in self.images:
-            # sanity check
-            if label is None:
-                break
-            if config.getEntry('label'):
-                if string.lower(config.getEntry('label')) == string.lower(label):
-                    self.images.remove (config)
-                    return
-
-        raise IndexError, "unknown image %s" % (label,)
-
-    def getDefault (self):
-        default = None
-        try:
-            default = self.getEntry("default")
-        except:
-            pass
-
-        if not default:
-            default = self.listImages()[0]
-
-        theDefault = self.getImage(default)
-
-        return theDefault[1]
-
-    def getDefaultLinux (self):
-        defaultIsOther = None
-
-        # XXX ick... this code badly needs work =\
-        theDefault = self.getDefault()
-
-        if theDefault.other:
-            defaultIsOther = 1
-
-        # if the default is other, look for the first linux image
-        if theDefault.other:
-            for image_label in self.listImages():
-                image = self.getImage(image_label)[1]
-                if not image.other:
-                    theDefault = image
-                    break
-
-        # if we get here and are *still* an other, then we have no linux
-        # images.  ick
-        if theDefault.other:
-            return None
-        else:
-            return theDefault
-
-    def listImages (self):
-        l = []
-        for config in self.images:
-            l.append(config.getEntry('label'))
-        return l
-
-    def listAliases (self):
-        l = []
-        for config in self.images:
-            if config.getEntry('alias'):
-                l.append(config.getEntry('alias'))
-        return l
-
-    def getPath (self):
-        return self.path
-
-    def write(self, file, perms = 0644):
-        f = open(file, "w")
-        f.write(self.__repr__())
-        f.close()
-        os.chmod(file, perms)
-
-    def read (self, file):
-        f = open(file, "r")
-        image = None
-        for l in f.readlines():
-            l = l[:-1]
-            orig = l
-            while (l and (l[0] == ' ' or l[0] == '\t')):
-                l = l[1:]
-            if not l:
-                continue
-            if l[0] == '#' and not image:
-                self.order.append('#' + orig)
-                continue
-            fields = string.split(l, '=', 1)
-            if l[0] == '#' and image:
-                args = ('#' + l,)
-            elif (len(fields) == 2):
-                f0 = string.strip (fields [0])
-                f1 = string.strip (fields [1])
-                if (f0 != "append"):
-                    # people are silly and put quotes brokenly in their
-                    # lilo.conf but you have to use them for append.  ARGH!
-                    f1 = string.replace(f1, '"', '')
-                    f1 = string.replace(f1, "'", "")
-                if (f0 == "image" or f0 == "other"):
-                    if image: self.addImage(image)
-                    image = LiloConfigFile(imageType = f0, 
-                                           path = f1)
-                    if (f0 == "other"):
-                        image.other = 1
-                    args = None
-                else:
-                    args = (f0, f1)
-                if (f0 == "disk"):
-                    self.diskRemaps.append((f0,f1))
-                    args = None
-                if (f0 == "bios"):
-                    self.biosRemaps.append((f0,f1))
-                    args = None
-
-            else:
-                args = (string.strip (l),)
-
-            if (args and image):
-                apply(image.addEntry, args)
-            elif args:
-                apply(self.addEntry, args)
-
-        if image: self.addImage(image)
-            
-        f.close()
-
-    def __init__(self, imageType = None, path = None):
-        self.imageType = imageType
-        self.path = path
-        self.order = []
-        self.images = []
-        self.other = None
-        self.items = UserDictCase()
-        self.biosRemaps = []
-        self.diskRemaps = []
-        self.unsupported = []
-
-
-if __name__ == "__main__":
-    import sys
-    #sys.path.append("")
-    config = LiloConfigFile ()
-    config.read ('/etc/lilo.conf')
-    print config
-    print "image list", config.listImages()
-    config.delImage ('linux')
-    print '----------------------------------'
-    config = LiloConfigFile ()
-    config.read ('/etc/lilo.conf')
-    print config
-    print '----------------------------------'
-    print '----------------------------------'
-    print "list images"
-    print config.listImages()
-    print config.getImage('linux')
-    print "----------------------------------"
-    print "addimage (testlinux)"
-    blip = """
-read-only
-blippy-blob=sdfsdf
-append=\"sdfasdfasdf\"
-root=/dev/hda6
-"""
-    sl = LiloConfigFile(imageType = "image", path="/boot/somevmlinuz-2.4.0")
-    sl.addEntry("label", "newkernel")
-    sl.addEntry("initrd", "blipppy")
-    config.addImage(sl)
-
-    print '-------------------------------------'
-    print "writing out /tmp/lilo.conf"
-    print config.write("/tmp/lilo.conf")
-    print config
diff --git a/pyanaconda/booty/ppc.py b/pyanaconda/booty/ppc.py
deleted file mode 100644
index c473156..0000000
--- a/pyanaconda/booty/ppc.py
+++ /dev/null
@@ -1,184 +0,0 @@
-import string
-import os
-
-from pyanaconda.booty import BootyNoKernelWarning
-from bootloaderInfo import *
-from pyanaconda import iutil
-
-class ppcBootloaderInfo(bootloaderInfo):
-    def getBootDevs(self, bl):
-        import parted
-
-        retval = []
-        machine = iutil.getPPCMachine()
-
-        if machine == 'pSeries':
-            for dev in self.storage.fsset.devices:
-                if dev.format.type == "prepboot":
-                    retval.append(dev.path)
-        elif machine == 'PMac':
-            for dev in self.storage.fsset.devices:
-                if dev.format.type == "hfs" and dev.format.bootable:
-                    retval.append(dev.path)
-
-        if len(retval) == 0:
-            # Try to get a boot device; bplan OF understands ext3
-            if machine == 'Pegasos' or machine == 'Efika':
-                try:
-                    device = self.storage.mountpoints["/boot"]
-                except KeyError:
-                    # Try / if we don't have this we're not going to work
-                    device = self.storage.rootDevice
-
-                retval.append(device.path)
-            else:
-                if bl.getDevice():
-                    d = bl.getDevice()
-                    retval.append(self.storage.devicetree.getDeviceByName(d).path)
-
-        return retval
-
-    def writeYaboot(self, instRoot, bl, kernelList, 
-                    chainList, defaultDev):
-
-        yabootTarget = string.join(self.getBootDevs(bl))
-
-        try:
-            bootDev = self.storage.mountpoints["/boot"]
-
-            cf = "/boot/etc/yaboot.conf"
-            cfPath = ""
-            if not os.path.isdir(instRoot + "/boot/etc"):
-                os.mkdir(instRoot + "/boot/etc")
-        except KeyError:
-            bootDev = self.storage.rootDevice
-
-            cfPath = "/boot"
-            cf = "/etc/yaboot.conf"
-
-        if bootDev.type == "mdarray":
-            partNumber = bootDev.parents[0].partedPartition.number
-        else:
-            partNumber = bootDev.partedPartition.number
-
-        f = open(instRoot + cf, "w+")
-
-        f.write("# yaboot.conf generated by anaconda\n\n")
-        f.write("boot=%s\n" %(yabootTarget,))
-        f.write("init-message=\"Welcome to %s!\\nHit <TAB> for boot options\"\n\n"
-                % productName)
-
-        f.write("partition=%s\n" % partNumber)
-        f.write("timeout=%s\n" % (self.timeout or 80))
-        f.write("install=/usr/lib/yaboot/yaboot\n")
-        f.write("delay=5\n")
-        f.write("enablecdboot\n")
-        f.write("enableofboot\n")
-        f.write("enablenetboot\n")        
-
-        yabootProg = "/sbin/mkofboot"
-        if iutil.getPPCMachine() == "PMac":
-            # write out the first hfs/hfs+ partition as being macosx
-            for (label, longlabel, device) in chainList:
-                if ((not label) or (label == "")):
-                    continue
-                f.write("macosx=/dev/%s\n" %(device,))
-                break
-            
-            f.write("magicboot=/usr/lib/yaboot/ofboot\n")
-
-        elif iutil.getPPCMachine() == "pSeries":
-            f.write("nonvram\n")
-            f.write("fstype=raw\n")
-
-        else: #  Default non-destructive case for anything else.
-            f.write("nonvram\n")
-            f.write("mntpoint=/boot/yaboot\n")
-            f.write("usemount\n")
-            if not os.access(instRoot + "/boot/yaboot", os.R_OK):
-                os.mkdir(instRoot + "/boot/yaboot")
-            yabootProg = "/sbin/ybin"
-
-        if self.password:
-            f.write("password=%s\n" %(self.password,))
-            f.write("restricted\n")
-
-        f.write("\n")
-
-        rootDev = self.storage.rootDevice
-
-        for (label, longlabel, version) in kernelList:
-            kernelTag = "-" + version
-            kernelFile = "%s/vmlinuz%s" %(cfPath, kernelTag)
-
-            f.write("image=%s\n" %(kernelFile,))
-            f.write("\tlabel=%s\n" %(label,))
-            f.write("\tread-only\n")
-
-            initrd = self.makeInitrd(kernelTag, instRoot)
-            if initrd:
-                f.write("\tinitrd=%s/%s\n" %(cfPath, initrd))
-
-            append = "%s" %(self.args.get(),)
-
-            realroot = rootDev.fstabSpec
-            if rootIsDevice(realroot):
-                f.write("\troot=%s\n" %(realroot,))
-            else:
-                if len(append) > 0:
-                    append = "%s root=%s" %(append,realroot)
-                else:
-                    append = "root=%s" %(realroot,)
-
-            if len(append) > 0:
-                f.write("\tappend=\"%s\"\n" %(append,))
-            f.write("\n")
-
-        f.close()
-        os.chmod(instRoot + cf, 0600)
-
-        # FIXME: hack to make sure things are written to disk
-        from pyanaconda import isys
-        isys.sync()
-        isys.sync()
-        isys.sync()
-
-        ybinargs = [ yabootProg, "-f", "-C", cf ]
-
-        rc = iutil.execWithRedirect(ybinargs[0],
-                                    ybinargs[1:],
-                                    stdout = "/dev/tty5",
-                                    stderr = "/dev/tty5",
-                                    root = instRoot)
-        if rc:
-            return rc
-
-        if (not os.access(instRoot + "/etc/yaboot.conf", os.R_OK) and
-            os.access(instRoot + "/boot/etc/yaboot.conf", os.R_OK)):
-            os.symlink("../boot/etc/yaboot.conf",
-                       instRoot + "/etc/yaboot.conf")
-
-        return 0
-
-    def setPassword(self, val, isCrypted = 1):
-        # yaboot just handles the password and doesn't care if its crypted
-        # or not
-        self.password = val
-
-    def write(self, instRoot, bl, kernelList, chainList, defaultDev):
-        if len(kernelList) >= 1:
-            rc = self.writeYaboot(instRoot, bl, kernelList, 
-                                  chainList, defaultDev)
-            if rc:
-                return rc
-        else:
-            raise BootyNoKernelWarning
-
-        return 0
-
-    def __init__(self, anaconda):
-        bootloaderInfo.__init__(self, anaconda)
-        self.useYabootVal = 1
-        self.kernelLocation = "/boot"
-        self._configdir = "/etc"
-        self._configname = "yaboot.conf"
diff --git a/pyanaconda/booty/s390.py b/pyanaconda/booty/s390.py
deleted file mode 100644
index 8cee296..0000000
--- a/pyanaconda/booty/s390.py
+++ /dev/null
@@ -1,186 +0,0 @@
-import os
-
-from bootloaderInfo import *
-from pyanaconda import iutil
-
-class s390BootloaderInfo(bootloaderInfo):
-    def getBootloaderConfig(self, instRoot, bl, kernelList,
-                            chainList, defaultDev):
-        # on upgrade read in the lilo config file
-        lilo = LiloConfigFile ()
-        self.perms = 0600
-        confFile = instRoot + self.configfile
-
-        if os.access (confFile, os.R_OK):
-            self.perms = os.stat(confFile)[0] & 0777
-            lilo.read(confFile)
-            os.rename(confFile, confFile + ".rpmsave")
-
-        # Remove any invalid entries that are in the file; we probably
-        # just removed those kernels. 
-        for label in lilo.listImages():
-            (fsType, sl, path, other) = lilo.getImage(label)
-            if fsType == "other": continue
-
-            if not os.access(instRoot + sl.getPath(), os.R_OK):
-                lilo.delImage(label)
-
-        rootDev = self.storage.rootDevice
-
-        if rootDev.name == defaultDev.name:
-            lilo.addEntry("default", kernelList[0][0])
-        else:
-            lilo.addEntry("default", chainList[0][0])
-
-        for (label, longlabel, version) in kernelList:
-            kernelTag = "-" + version
-            kernelFile = self.kernelLocation + "vmlinuz" + kernelTag
-
-            try:
-                lilo.delImage(label)
-            except IndexError as msg:
-                pass
-
-            sl = LiloConfigFile(imageType = "image", path = kernelFile)
-
-            initrd = self.makeInitrd(kernelTag, instRoot)
-
-            sl.addEntry("label", label)
-            if initrd:
-                sl.addEntry("initrd", "%s%s" %(self.kernelLocation, initrd))
-
-            sl.addEntry("read-only")
-            sl.addEntry("root", rootDev.path)
-            sl.addEntry("ipldevice", rootDev.path[:-1])
-
-            if self.args.get():
-                sl.addEntry('append', '"%s"' % self.args.get())
-                
-            lilo.addImage (sl)
-
-        for (label, longlabel, device) in chainList:
-            if ((not label) or (label == "")):
-                continue
-            try:
-                (fsType, sl, path, other) = lilo.getImage(label)
-                lilo.delImage(label)
-            except IndexError:
-                sl = LiloConfigFile(imageType = "other",
-                                    path = "/dev/%s" %(device))
-                sl.addEntry("optional")
-
-            sl.addEntry("label", label)
-            lilo.addImage (sl)
-
-        # Sanity check #1. There could be aliases in sections which conflict
-        # with the new images we just created. If so, erase those aliases
-        imageNames = {}
-        for label in lilo.listImages():
-            imageNames[label] = 1
-
-        for label in lilo.listImages():
-            (fsType, sl, path, other) = lilo.getImage(label)
-            if sl.testEntry('alias'):
-                alias = sl.getEntry('alias')
-                if imageNames.has_key(alias):
-                    sl.delEntry('alias')
-                imageNames[alias] = 1
-
-        # Sanity check #2. If single-key is turned on, go through all of
-        # the image names (including aliases) (we just built the list) and
-        # see if single-key will still work.
-        if lilo.testEntry('single-key'):
-            singleKeys = {}
-            turnOff = 0
-            for label in imageNames.keys():
-                l = label[0]
-                if singleKeys.has_key(l):
-                    turnOff = 1
-                singleKeys[l] = 1
-            if turnOff:
-                lilo.delEntry('single-key')
-
-        return lilo
-
-    def writeChandevConf(self, bl, instroot):   # S/390 only 
-        cf = "/etc/chandev.conf"
-        self.perms = 0644
-        if bl.args.chandevget():
-            fd = os.open(instroot + "/etc/chandev.conf",
-                         os.O_WRONLY | os.O_CREAT)
-            os.write(fd, "noauto\n")
-            for cdev in bl.args.chandevget():
-                os.write(fd,'%s\n' % cdev)
-            os.close(fd)
-        return ""
-        
-    
-    def writeZipl(self, instRoot, bl, kernelList, chainList,
-                  defaultDev, justConfigFile):
-        rootDev = self.storage.rootDevice
-        
-        cf = '/etc/zipl.conf'
-        self.perms = 0600
-        if os.access (instRoot + cf, os.R_OK):
-            self.perms = os.stat(instRoot + cf)[0] & 0777
-            os.rename(instRoot + cf,
-                      instRoot + cf + '.rpmsave')
-
-        f = open(instRoot + cf, "w+")        
-
-        f.write('[defaultboot]\n')
-        if self.timeout:
-            f.write('timeout=%d\n' % self.timeout)
-        f.write('default=' + kernelList[-1][0] + '-' + kernelList[-1][2] + '\n')
-        f.write('target=%s\n' % (self.kernelLocation))
-
-        cfPath = "/boot/"
-        for (label, longlabel, version) in kernelList:
-            kernelTag = "-" + version
-            kernelFile = "%svmlinuz%s" % (cfPath, kernelTag)
-
-            initrd = self.makeInitrd(kernelTag, instRoot)
-            f.write('[%s-%s]\n' % (label, version))
-            f.write('\timage=%s\n' % (kernelFile))
-            if initrd:
-                f.write('\tramdisk=%s%s\n' %(self.kernelLocation, initrd))
-
-            realroot = rootDev.fstabSpec
-            f.write('\tparameters="root=%s' %(realroot,))
-            if bl.args.get():
-                f.write(' %s' % (bl.args.get()))
-            f.write('"\n')
-
-        f.close()
-
-        if not justConfigFile:
-            rc = iutil.execWithCapture("zipl", [], root = instRoot,
-                                       stderr = "/dev/stderr")
-            for line in rc.splitlines():
-                if line.startswith("Preparing boot device: "):
-                    # Output here may look like:
-                    #     Preparing boot device: dasdb (0200).
-                    #     Preparing boot device: dasdl.
-                    # We want to extract the device name and pass that.
-
-                    fields = line[23:].split()
-                    self.setDevice(fields[0].replace('.', ''))
-
-        return 0
-
-    def write(self, instRoot, bl, kernelList, chainList,
-            defaultDev):
-        rc = self.writeZipl(instRoot, bl, kernelList, 
-                            chainList, defaultDev,
-                            not self.useZiplVal)
-        if rc:
-            return rc
-
-        return self.writeChandevConf(bl, instRoot)
-
-    def __init__(self, anaconda):
-        bootloaderInfo.__init__(self, anaconda)
-        self.useZiplVal = 1      # only used on s390
-        self.kernelLocation = "/boot/"
-        self._configdir = "/etc"
-        self._configname = "zipl.conf"
diff --git a/pyanaconda/booty/sparc.py b/pyanaconda/booty/sparc.py
deleted file mode 100644
index aad3b00..0000000
--- a/pyanaconda/booty/sparc.py
+++ /dev/null
@@ -1,128 +0,0 @@
-import string
-import os
-
-from pyanaconda.booty import BootyNoKernelWarning
-from util import getDiskPart
-from bootloaderInfo import *
-from pyanaconda import iutil
-
-class sparcBootloaderInfo(bootloaderInfo):
-    def writeSilo(self, instRoot, bl, kernelList,
-                  chainList, defaultDev):
-
-        try:
-            bootDev = self.storage.mountpoints["/boot"]
-
-            mf = '/silo.message'
-            cf = "/boot/silo.conf"
-            mfdir = '/boot'
-            cfPath = ""
-            if not os.path.isdir(instRoot + "/boot"):
-                os.mkdir(instRoot + "/boot")
-        except KeyError:
-            bootDev = self.storage.rootDevice
-
-            cf = "/etc/silo.conf"
-            mfdir = '/etc'
-            cfPath = "/boot"
-
-        f = open(instRoot + mfdir + mf, "w+")
-        f.write("Welcome to %s!\nHit <TAB> for boot options\n\n" % productName)
-        f.close()
-        os.chmod(instRoot + mfdir + mf, 0600)
-
-        f = open(instRoot + cf, "w+")
-        f.write("# silo.conf generated by anaconda\n\n")
-
-        f.write("#boot=%s\n" % (bootDev.path,))
-        f.write("message=%s\n" % (mf,))
-        f.write("timeout=%s\n" % (self.timeout or 50))
-
-        (disk, partNum) = getDiskPart(bootDev)
-        f.write("partition=%s\n" % (partNum,))
-
-        if self.password:
-            f.write("password=%s\n" % (self.password,))
-            f.write("restricted\n")
-
-        f.write("default=%s\n" % (kernelList[0][0],))
-        f.write("\n")
-
-        rootDev = self.storage.rootDevice
-
-        for (label, longlabel, version) in kernelList:
-            kernelTag = "-" + version
-            kernelFile = "%s/vmlinuz%s" % (cfPath, kernelTag)
-
-            f.write("image=%s\n" % (kernelFile,))
-            f.write("\tlabel=%s\n" % (label,))
-            f.write("\tread-only\n")
-
-            initrd = self.makeInitrd(kernelTag, instRoot)
-            if initrd:
-                f.write("\tinitrd=%s/%s\n" % (cfPath, initrd))
-
-            append = "%s" % (self.args.get(),)
-
-            realroot = rootDev.fstabSpec
-            if rootIsDevice(realroot):
-                f.write("\troot=%s\n" % (realroot,))
-            else:
-                if len(append) > 0:
-                    append = "%s root=%s" % (append, realroot)
-                else:
-                    append = "root=%s" % (realroot,)
-
-            if len(append) > 0:
-                f.write("\tappend=\"%s\"\n" % (append,))
-            f.write("\n")
-
-        f.close()
-        os.chmod(instRoot + cf, 0600)
-
-        # FIXME: hack to make sure things are written to disk
-        from pyanaconda import isys
-        isys.sync()
-        isys.sync()
-        isys.sync()
-
-        backup = "%s/backup.b" % (cfPath,)
-        sbinargs = ["/sbin/silo", "-f", "-C", cf, "-S", backup]
-        if (iutil.getSparcMachine() == "sun4u" or iutil.getSparcMachine() == "sun4v"):
-            sbinargs += ["-u"]
-        else:
-            sbinargs += ["-U"]
-
-        rc = iutil.execWithRedirect(sbinargs[0],
-                                    sbinargs[1:],
-                                    stdout = "/dev/tty5",
-                                    stderr = "/dev/tty5",
-                                    root = instRoot)
-        if rc:
-            return rc
-
-        if (not os.access(instRoot + "/etc/silo.conf", os.R_OK) and
-            os.access(instRoot + "/boot/silo.conf", os.R_OK)):
-            os.symlink("../boot/silo.conf",
-                       instRoot + "/etc/silo.conf")
-
-        return 0
-
-    def setPassword(self, val, isCrypted = 1):
-        # silo just handles the password unencrypted
-        self.password = val
-
-    def write(self, instRoot, bl, kernelList, chainList,
-              defaultDev):
-        if len(kernelList) >= 1:
-            return self.writeSilo(instRoot, bl, kernelList, chainList,
-                                  defaultDev)
-        else:
-            raise BootyNoKernelWarning
-
-    def __init__(self, anaconda):
-        bootloaderInfo.__init__(self, anaconda)
-        self.useSiloVal = 1
-        self.kernelLocation = "/boot"
-        self._configdir = "/etc"
-        self._configname = "silo.conf"
diff --git a/pyanaconda/booty/util.py b/pyanaconda/booty/util.py
deleted file mode 100644
index ab33ae1..0000000
--- a/pyanaconda/booty/util.py
+++ /dev/null
@@ -1,9 +0,0 @@
-def getDiskPart(dev):
-    if dev.type == "partition":
-        partNum = dev.partedPartition.number
-        disk = dev.disk
-    else:
-        partNum = None
-        disk = dev
-
-    return (disk, partNum)
diff --git a/pyanaconda/booty/x86.py b/pyanaconda/booty/x86.py
deleted file mode 100644
index 003901a..0000000
--- a/pyanaconda/booty/x86.py
+++ /dev/null
@@ -1,562 +0,0 @@
-import os
-import string
-
-from pyanaconda.booty import BootyNoKernelWarning
-from util import getDiskPart
-from bootloaderInfo import *
-from pyanaconda.flags import flags
-import checkbootloader
-from pyanaconda import iutil
-
-import logging
-log = logging.getLogger("anaconda")
-
-class x86BootloaderInfo(efiBootloaderInfo):
-    def setPassword(self, val, isCrypted = 1):
-        if not val:
-            self.password = val
-            self.pure = val
-            return
-        
-        if isCrypted and self.useGrubVal == 0:
-            self.pure = None
-            return
-        elif isCrypted:
-            self.password = val
-            self.pure = None
-        else:
-            salt = "$6$"
-            saltLen = 16
-
-            saltchars = string.letters + string.digits + './'
-            rnd = random.SystemRandom()
-            for i in range(saltLen):
-                salt += rnd.choice(saltchars)
-
-            self.password = crypt.crypt(val, salt)
-            self.pure = val
-        
-    def getPassword (self):
-        return self.pure
-
-    def setUseGrub(self, val):
-        self.useGrubVal = val
-
-    def getPhysicalDevices(self, dev):
-        # This finds a list of devices on which the given device name resides.
-        # Accepted values for "device" are raid1 md devices (i.e. "md0"),
-        # physical disks ("hda"), and real partitions on physical disks
-        # ("hda1"). Anything else gets ignored.
-        if dev.type == "mdarray":
-            if dev.level != 1:
-                log.error("x86BootloaderInfo.getPhysicalDevices ignoring non "
-                          "level 1 raid array %s" % dev.name)
-                return []
-            devs = dev.parents
-        else:
-            devs = [ dev ]
-
-        physicalDevices = []
-        for dev in devs:
-            if dev in self.storage.disks or dev.type == "partition":
-                physicalDevices.append(dev)
-            else:
-                log.error("x86BootloaderInfo.getPhysicalDevices ignoring %s" %
-                          dev.name)
-
-        return physicalDevices
-
-    def runGrubInstall(self, instRoot, bootDev, cmds, cfPath):
-        if cfPath == "/":
-            syncDataToDisk(bootDev, "/boot", instRoot)
-        else:
-            syncDataToDisk(bootDev, "/", instRoot)
-
-        # copy the stage files over into /boot
-        rc = iutil.execWithRedirect("/sbin/grub-install",
-                                    ["--just-copy"],
-                                    stdout = "/dev/tty5", stderr = "/dev/tty5",
-                                    root = instRoot)
-        if rc:
-            return rc
-
-        # really install the bootloader
-        for cmd in cmds:
-            p = os.pipe()
-            os.write(p[1], cmd + '\n')
-            os.close(p[1])
-
-            # FIXME: hack to try to make sure everything is written
-            #        to the disk
-            if cfPath == "/":
-                syncDataToDisk(bootDev, "/boot", instRoot)
-            else:
-                syncDataToDisk(bootDev, "/", instRoot)
-
-            rc = iutil.execWithRedirect('/sbin/grub' ,
-                                        [ "--batch", "--no-floppy",
-                                          "--device-map=/boot/grub/device.map" ],
-                                        stdin = p[0],
-                                        stdout = "/dev/tty5", stderr = "/dev/tty5",
-                                        root = instRoot)
-            os.close(p[0])
-
-            if rc:
-                return rc
-
-    def matchingBootTargets(self, stage1Devs, bootDevs):
-        matches = []
-        for stage1Dev in stage1Devs:
-            for mdBootPart in bootDevs:
-                if getDiskPart(stage1Dev)[0] == getDiskPart(mdBootPart)[0]:
-                    matches.append((stage1Dev, mdBootPart))
-        return matches
-
-    def addMemberMbrs(self, matches, bootDevs):
-        updatedMatches = list(matches)
-        bootDevsHavingStage1Dev = [match[1] for match in matches]
-        for mdBootPart in bootDevs:
-            if mdBootPart not in bootDevsHavingStage1Dev:
-               updatedMatches.append((getDiskPart(mdBootPart)[0], mdBootPart))
-        return updatedMatches
-
-    def installGrub(self, instRoot, bootDev, grubTarget, grubPath, cfPath):
-        if iutil.isEfi():
-            return efiBootloaderInfo.installGrub(self, instRoot, bootDev, grubTarget,
-                                                 grubPath, cfPath)
-
-        args = "--stage2=/boot/grub/stage2 "
-
-        stage1Devs = self.getPhysicalDevices(
-                          self.storage.devicetree.getDeviceByName(grubTarget))
-        bootDevs = self.getPhysicalDevices(bootDev)
-
-        installs = [(None,
-                     self.grubbyPartitionName(stage1Devs[0]),
-                     self.grubbyPartitionName(bootDevs[0]))]
-
-        if bootDev.type == "mdarray":
-
-            matches = self.matchingBootTargets(stage1Devs, bootDevs)
-
-            # If the stage1 target disk contains member of boot raid array (mbr
-            # case) or stage1 target partition is member of boot raid array
-            # (partition case)
-            if matches:
-                # 1) install stage1 on target disk/partiton
-                stage1Dev, mdMemberBootPart = matches[0]
-                installs = [(None,
-                             self.grubbyPartitionName(stage1Dev),
-                             self.grubbyPartitionName(mdMemberBootPart))]
-                firstMdMemberDiskGrubbyName = self.grubbyDiskName(
-                                        getDiskPart(mdMemberBootPart)[0])
-
-                # 2) and install stage1 on other members' disks/partitions too
-                # NOTES:
-                # - the goal is to be able to boot after a members' disk removal
-                # - so we have to use grub device names as if after removal
-                #   (i.e. the same disk name (e.g. (hd0)) for both member disks)
-                # - if member partitions have different numbers only removal of
-                #   specific one of members will work because stage2 containing
-                #   reference to config file is shared and therefore can contain
-                #   only one value
-
-                # if target is mbr, we want to install also to mbr of other
-                # members, so extend the matching list
-                matches = self.addMemberMbrs(matches, bootDevs)
-                for stage1Target, mdMemberBootPart in matches[1:]:
-                    # prepare special device mapping corresponding to member removal
-                    mdMemberBootDisk = getDiskPart(mdMemberBootPart)[0]
-                    # It can happen due to ks --driveorder option, but is it ok?
-                    if not mdMemberBootDisk.name in self.drivelist:
-                        continue
-                    mdRaidDeviceRemap = (firstMdMemberDiskGrubbyName,
-                                         mdMemberBootDisk.name)
-
-                    stage1TargetGrubbyName = self.grubbyPartitionName(stage1Target)
-                    rootPartGrubbyName = self.grubbyPartitionName(mdMemberBootPart)
-
-                    # now replace grub disk name part according to special device
-                    # mapping
-                    old = self.grubbyDiskName(mdMemberBootDisk).strip('() ')
-                    new = firstMdMemberDiskGrubbyName.strip('() ')
-                    rootPartGrubbyName = rootPartGrubbyName.replace(old, new)
-                    stage1TargetGrubbyName = stage1TargetGrubbyName.replace(old, new)
-
-                    installs.append((mdRaidDeviceRemap,
-                                     stage1TargetGrubbyName,
-                                     rootPartGrubbyName))
-
-                # This is needed for case when /boot member partitions have
-                # different numbers. Shared stage2 can contain only one reference
-                # to grub.conf file, so let's ensure that it is reference to partition
-                # on disk which we will boot from - that is, install grub to
-                # this disk as last so that its reference is not overwritten.
-                installs.reverse()
-
-        cmds = []
-        for mdRaidDeviceRemap, stage1Target, rootPart in installs:
-            if mdRaidDeviceRemap:
-                cmd = "device (%s) /dev/%s\n" % tuple(mdRaidDeviceRemap)
-            else:
-                cmd = ''
-            cmd += "root %s\n" % (rootPart,)
-            cmd += "install %s%s/stage1 d %s %s/stage2 p %s%s/grub.conf" % \
-                (args, grubPath, stage1Target, grubPath, rootPart, grubPath)
-            cmds.append(cmd)
-        return self.runGrubInstall(instRoot, bootDev.name, cmds, cfPath)
-
-    def writeGrub(self, instRoot, bl, kernelList, chainList,
-            defaultDev, upgrade=False):
-
-        rootDev = self.storage.rootDevice
-        grubTarget = bl.getDevice()
-
-        try:
-            bootDev = self.storage.mountpoints["/boot"]
-            grubPath = "/grub"
-            cfPath = "/"
-        except KeyError:
-            bootDev = rootDev
-            grubPath = "/boot/grub"
-            cfPath = "/boot/"
-
-        if not upgrade and not iutil.isEfi():
-            self.writeGrubConf(instRoot, bootDev, rootDev, defaultDev,
-                               kernelList, chainList, grubTarget, grubPath,
-                               cfPath)
-
-        # keep track of which devices are used for the device.map
-        usedDevs = set()
-        usedDevs.update(self.getPhysicalDevices(
-                          self.storage.devicetree.getDeviceByName(grubTarget)))
-        usedDevs.update(self.getPhysicalDevices(bootDev))
-        usedDevs.update([self.storage.devicetree.getDeviceByName(dev) for
-                            (label, longlabel, dev) in chainList if longlabel])
-
-        if not upgrade:
-            self.writeDeviceMap(instRoot, usedDevs, upgrade)
-            self.writeSysconfig(instRoot, grubTarget, upgrade)
-
-        ret = self.installGrub(instRoot, bootDev, grubTarget, grubPath, cfPath)
-        if iutil.isEfi():
-            self.writeGrubConf(instRoot, bootDev, rootDev, defaultDev,
-                               kernelList, chainList, grubTarget, grubPath,
-                               cfPath)
-        return ret
-
-    def writeGrubConf(self, instRoot, bootDev, rootDev, defaultDev, kernelList,
-                      chainList, grubTarget, grubPath, cfPath):
-
-        bootDevs = self.getPhysicalDevices(bootDev)
-
-        # XXX old config file should be read here for upgrade
-
-        cf = "%s%s" % (instRoot, self.configfile)
-        self.perms = 0600
-        if os.access (cf, os.R_OK):
-            self.perms = os.stat(cf)[0] & 0777
-            os.rename(cf, cf + '.rpmsave')
-
-        f = open(cf, "w+")
-
-        f.write("# grub.conf generated by anaconda\n")
-        f.write("#\n")
-        f.write("# Note that you do not have to rerun grub "
-                "after making changes to this file\n")
-
-        if grubPath == "/grub":
-            f.write("# NOTICE:  You have a /boot partition.  This means "
-                    "that\n")
-            f.write("#          all kernel and initrd paths are relative "
-                    "to /boot/, eg.\n")
-        else:
-            f.write("# NOTICE:  You do not have a /boot partition.  "
-                    "This means that\n")
-            f.write("#          all kernel and initrd paths are relative "
-                    "to /, eg.\n")
-
-        f.write('#          root %s\n' % self.grubbyPartitionName(bootDevs[0]))
-        f.write("#          kernel %svmlinuz-version ro root=%s\n" % (cfPath, rootDev.path))
-        f.write("#          initrd %sinitrd-[generic-]version.img\n" % (cfPath))
-        f.write("#boot=/dev/%s\n" % (grubTarget))
-
-        if iutil.isEfi():
-            from pyanaconda.product import productName
-            # Map the target device to the full EFI path
-            if self.getEfiProductPath(productName):
-                (n, pn) = getDiskPart(bootDevs[0])
-                f.write("device (%s) %s\n" % (self.grubbyDiskName(n), self.getEfiProductPath(productName)))
-
-        # get the default image to boot... we have to walk and find it
-        # since grub indexes by where it is in the config file
-        if defaultDev.name == rootDev.name:
-            default = 0
-        else:
-            # if the default isn't linux, it's the first thing in the
-            # chain list
-            default = len(kernelList)
-
-
-        f.write('default=%s\n' % (default))
-
-        if self.serial == 1:
-            # Set the global timeout in serial case
-            f.write('timeout=%d\n' % (self.timeout or 5))
-            # grub the 0-based number of the serial console device
-            unit = self.serialDevice[-1]
-            
-            # and we want to set the speed too
-            speedend = 0
-            for char in self.serialOptions:
-                if char not in string.digits:
-                    break
-                speedend = speedend + 1
-            if speedend != 0:
-                speed = self.serialOptions[:speedend]
-            else:
-                # reasonable default
-                speed = "9600"
-                
-            f.write("serial --unit=%s --speed=%s\n" %(unit, speed))
-            f.write("terminal --timeout=%s serial console\n" % (self.timeout or 5))
-        else:
-            # Default to 0 timeout in the non-serial case
-            f.write('timeout=%d\n' % (self.timeout or 0))
-            # we only want splashimage if they're not using a serial console
-            if os.access("%s/boot/grub/splash.xpm.gz" %(instRoot,), os.R_OK):
-                f.write('splashimage=%s%sgrub/splash.xpm.gz\n'
-                        % (self.grubbyPartitionName(bootDevs[0]), cfPath))
-                f.write("hiddenmenu\n")
-
-            
-        if self.password:
-            f.write('password --encrypted %s\n' %(self.password))
-        
-        for (label, longlabel, version) in kernelList:
-            kernelTag = "-" + version
-            kernelFile = "%svmlinuz%s" % (cfPath, kernelTag)
-
-            initrd = self.makeInitrd(kernelTag, instRoot)
-
-            f.write('title %s (%s)\n' % (longlabel, version))
-            f.write('\troot %s\n' % self.grubbyPartitionName(bootDevs[0]))
-
-            realroot = " root=%s" % rootDev.fstabSpec
-
-            if version.endswith("xen0") or (version.endswith("xen") and not os.path.exists("/proc/xen")):
-                # hypervisor case
-                sermap = { "ttyS0": "com1", "ttyS1": "com2",
-                           "ttyS2": "com3", "ttyS3": "com4" }
-                if self.serial and sermap.has_key(self.serialDevice) and \
-                       self.serialOptions:
-                    hvs = "%s=%s" %(sermap[self.serialDevice],
-                                    self.serialOptions)
-                else:
-                    hvs = ""
-                if version.endswith("xen0"):
-                    hvFile = "%sxen.gz-%s %s" %(cfPath,
-                                                version.replace("xen0", ""),
-                                                hvs)
-                else:
-                    hvFile = "%sxen.gz-%s %s" %(cfPath,
-                                                version.replace("xen", ""),
-                                                hvs)
-                f.write('\tkernel %s\n' %(hvFile,))
-                f.write('\tmodule %s ro%s' %(kernelFile, realroot))
-                if self.args.get():
-                    f.write(' %s' % self.args.get())
-                f.write('\n')
-
-                if initrd:
-                    f.write('\tmodule %s%s\n' % (cfPath, initrd))
-            else: # normal kernel
-                f.write('\tkernel %s ro%s' % (kernelFile, realroot))
-                if self.args.get():
-                    f.write(' %s' % self.args.get())
-                f.write('\n')
-
-                if initrd:
-                    f.write('\tinitrd %s%s\n' % (cfPath, initrd))
-
-        for (label, longlabel, device) in chainList:
-            if ((not longlabel) or (longlabel == "")):
-                continue
-            f.write('title %s\n' % (longlabel))
-            f.write('\trootnoverify %s\n' % self.grubbyPartitionName(
-                             self.storage.devicetree.getDeviceByName(device)))
-#            f.write('\tmakeactive\n')
-            f.write('\tchainloader +1')
-            f.write('\n')
-
-        f.close()
-
-        if not "/efi/" in cf:
-            os.chmod(cf, self.perms)
-
-        try:
-            # make symlink for menu.lst (default config file name)
-            menulst = "%s%s/menu.lst" % (instRoot, self.configdir)
-            if os.access (menulst, os.R_OK):
-                os.rename(menulst, menulst + ".rpmsave")
-            os.symlink("./grub.conf", menulst)
-        except:
-            pass
-
-        try:
-            # make symlink for /etc/grub.conf (config files belong in /etc)
-            etcgrub = "%s%s" % (instRoot, "/etc/grub.conf")
-            if os.access (etcgrub, os.R_OK):
-                os.rename(etcgrub, etcgrub + ".rpmsave")
-            os.symlink(".." + self.configfile, etcgrub)
-        except:
-            pass
-
-    def writeDeviceMap(self, instRoot, usedDevs, upgrade=False):
-
-        if os.access(instRoot + "/boot/grub/device.map", os.R_OK):
-            # For upgrade, we want also e.g. devs that has been added
-            # to file during install for chainloading.
-            if upgrade:
-                f = open(instRoot + "/boot/grub/device.map", "r")
-                for line in f:
-                    if line.startswith('(hd'):
-                        (grubdisk, dev) = line.split()[:2]
-                        dev = dev[5:]
-                        if dev in self.drivelist:
-                            usedDevs.add(
-                                self.storage.devicetree.getDeviceByName(dev))
-                f.close()
-            os.rename(instRoot + "/boot/grub/device.map",
-                      instRoot + "/boot/grub/device.map.rpmsave")
-
-        f = open(instRoot + "/boot/grub/device.map", "w+")
-        f.write("# this device map was generated by anaconda\n")
-        usedDiskDevs = set()
-        for dev in usedDevs:
-            drive = getDiskPart(dev)[0]
-            usedDiskDevs.add(drive)
-        devs = list(usedDiskDevs)
-        devs.sort(key=lambda d: d.name)
-        for dev in devs:
-            f.write("(%s)     %s\n" % (self.grubbyDiskName(dev), dev.path))
-        f.close()
-
-    def writeSysconfig(self, instRoot, grubTarget, upgrade):
-        sysconf = '/etc/sysconfig/grub'
-        if os.access (instRoot + sysconf, os.R_OK):
-            if upgrade:
-                return
-            self.perms = os.stat(instRoot + sysconf)[0] & 0777
-            os.rename(instRoot + sysconf,
-                      instRoot + sysconf + '.rpmsave')
-        # if it's an absolute symlink, just get it out of our way
-        elif (os.path.islink(instRoot + sysconf) and
-              os.readlink(instRoot + sysconf)[0] == '/'):
-            if upgrade:
-                return
-            os.rename(instRoot + sysconf,
-                      instRoot + sysconf + '.rpmsave')
-        f = open(instRoot + sysconf, 'w+')
-        f.write("boot=/dev/%s\n" %(grubTarget,))
-        f.write("forcelba=0\n")
-        f.close()
-
-    def grubbyDiskName(self, dev):
-        return "hd%d" % self.drivelist.index(dev.name)
-
-    def grubbyPartitionName(self, dev):
-        (disk, partNum) = getDiskPart(dev)
-        if partNum != None:
-            return "(%s,%d)" % (self.grubbyDiskName(disk), partNum - 1)
-        else:
-            return "(%s)" %(self.grubbyDiskName(disk))
-
-    def getBootloaderConfig(self, instRoot, bl, kernelList,
-                            chainList, defaultDev):
-        config = bootloaderInfo.getBootloaderConfig(self, instRoot,
-                                                    bl, kernelList, chainList,
-                                                    defaultDev)
-
-        liloTarget = bl.getDevice()
-
-        config.addEntry("boot", '/dev/' + liloTarget, replace = 0)
-        config.addEntry("map", "/boot/map", replace = 0)
-        config.addEntry("install", "/boot/boot.b", replace = 0)
-        message = "/boot/message"
-
-        if self.pure is not None and not self.useGrubVal:
-            config.addEntry("restricted", replace = 0)
-            config.addEntry("password", self.pure, replace = 0)
-
-        if self.serial == 1:
-           # grab the 0-based number of the serial console device
-            unit = self.serialDevice[-1]
-            # FIXME: we should probably put some options, but lilo
-            # only supports up to 9600 baud so just use the defaults
-            # it's better than nothing :(
-            config.addEntry("serial=%s" %(unit,))
-        else:
-            # message screws up serial console
-            if os.access(instRoot + message, os.R_OK):
-                config.addEntry("message", message, replace = 0)
-
-        if not config.testEntry('lba32'):
-            if bl.above1024 and not iutil.isX86(bits=32):
-                config.addEntry("lba32", replace = 0)
-
-        return config
-
-    def write(self, instRoot, bl, kernelList, chainList,
-              defaultDev):
-        if self.timeout is None and chainList:
-            self.timeout = 5
-
-        # XXX HACK ALERT - see declaration above
-        if self.doUpgradeOnly:
-            if self.useGrubVal:
-                return self.writeGrub(instRoot, bl, kernelList,
-                                      chainList, defaultDev,
-                                      upgrade = True)
-            return 0
-
-        if len(kernelList) < 1:
-            raise BootyNoKernelWarning
-
-        rc = self.writeGrub(instRoot, bl, kernelList, 
-                            chainList, defaultDev,
-                            not self.useGrubVal)
-        if rc:
-            return rc
-
-        # XXX move the lilo.conf out of the way if they're using GRUB
-        # so that /sbin/installkernel does a more correct thing
-        if self.useGrubVal and os.access(instRoot + '/etc/lilo.conf', os.R_OK):
-            os.rename(instRoot + "/etc/lilo.conf",
-                      instRoot + "/etc/lilo.conf.anaconda")
-
-        return 0
-
-    def getArgList(self):
-        args = bootloaderInfo.getArgList(self)
-
-        if self.password:
-            args.append("--password=%s" %(self.password))
-
-        return args
-
-    def __init__(self, anaconda):
-        bootloaderInfo.__init__(self, anaconda)
-
-        # these have to be set /before/ efiBootloaderInfo.__init__(), or
-        # they'll be overwritten.
-        self._configdir = "/boot/grub"
-        self._configname = "grub.conf"
-
-        efiBootloaderInfo.__init__(self, anaconda, initialize=False)
-
-        # XXX use checkbootloader to determine what to default to
-        self.useGrubVal = 1
-        self.kernelLocation = "/boot/"
-        self.password = None
-        self.pure = None
-- 
1.7.3.4

_______________________________________________
Anaconda-devel-list mailing list
Anaconda-devel-list@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/anaconda-devel-list


[Index of Archives]     [Kickstart]     [Fedora Users]     [Fedora Legacy List]     [Fedora Maintainers]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [Yosemite Photos]     [KDE Users]     [Fedora Tools]
  Powered by Linux