diff --git a/pyanaconda/bootloader.py b/pyanaconda/bootloader.py
index 3748d7f..3b5c21d 100644
--- a/pyanaconda/bootloader.py
+++ b/pyanaconda/bootloader.py
@@ -1,36 +1,37 @@
+# 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 .
-#
-# Author(s): Erik Troan
-# Jeremy Katz
+# Red Hat Author(s): David Lehman
#
-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 os
+import re
+import struct
+
+from pyanaconda import platform
+from pyanaconda import iutil
+
+from pyanaconda.product import productName
+from pyanaconda.flags import flags
+from pyanaconda.storage.devicelibs import mdraid
+import pyanaconda.storage.errors
+from pyanaconda.isys import sync
import gettext
_ = lambda x: gettext.ldgettext("anaconda", x)
@@ -38,208 +39,1473 @@ _ = lambda x: gettext.ldgettext("anaconda", 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 pyanaconda.storage.errors.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 pyanaconda.storage.errors.StorageError:
+ pass
+
+ return block
+
+def is_windows_boot_block(block):
+ return (len(block) >= 512 and
+ struct.unpack("H", buf[0x1fe: 0x200]) == (0xaa55,))
+
+
+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):
+ return self.count(value) != 0
+
+ def count(self, value):
+ c = 0
+ for arg in self:
+ if self._is_match(arg, value):
+ c += 1
+
+ return c
+
+ def index(self, value):
+ for i in range(len(self)):
+ if self._is_match(self[i], value):
+ return i
+
+ raise ValueError("'%s' is not in list" % value)
+
+
+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
+
+
+class LinuxBootLoaderImage(BootLoaderImage):
+ def __init__(self, device=None, label=None, short=None, version=None,
+ kernel=None, initrd=None, args=None):
+ 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 = kernel # filename string
+ self.initrd = initrd # filename string
+
+ if isinstance(args, list):
+ self.boot_args = ArgumentList(args)
+ elif isinstance(args, str):
+ self.boot_args = ArgumentList(args.split())
+
+ @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
+
+
+# This is for bootloader detection loops to look for config files or perhaps
+# some kind of bootloader factory. Currently it isn't used.
+bootloader_classes = {}
+
+class BootLoader(object):
+ """TODO:
+ - make a base class for Yaboot and SILO to inherit from
+ - iSeries bootloader?
+ - writeKS
+ - resolve overlap between Platform checkFoo methods and
+ _is_valid_target_device and _device_is_bootable
+ """
+ name = "Generic Bootloader"
+ arches = []
+ packages = []
+ config_file = None
+ config_file_mode = 0600
+ can_dual_boot = 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
+
+ # 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
+
+ def __init__(self, storage=storage):
+ if storage.platform.bootloader != self.name:
+ raise ValueError("wrong bootloader for this platform")
+
+ # pyanaconda.storage.Storage instance
+ self.storage = storage
+
+ self._drives = []
+ self._drive_order = []
+
+ # timeout in seconds
+ self._timeout = None
+
+ # XXX abstract crypto?
+ 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.kernel_args = []
+
+ #
+ # target device access
+ #
+ @property
+ def stage1_device(self):
+ """ Stage1 target device. """
+ if not self._target_device:
+ self._target_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)
+
+ 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):
+ self._drive_order = order
+ self._drives = [] # 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
+
+ if idx == 0:
+ # if this one's already at the front there's nothing to do
+ continue
+
+ new_drives = [_drives.pop(idx)]
+ new_drives.extend(_drives)
+ _drives = new_drives
+
+ return _drives
+
+ @property
+ def drives(self):
+ """Sorted list of available drives."""
+ if self._drives:
+ # only generate the list if it is empty
+ return self._drives
+
+ drives = [d for d in 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 and self.linux_images:
+ self._default_image = self.linux_images[0]
+
+ 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")
+
+ self._default_image = image
+
+ @property
+ def images(self):
+ """ List of OS images that will be included in the configuration. """
+ if not self.linux_images:
+ default = LinuxBootLoaderImage(device=self.storage.rootDevice,
+ label=productName,
+ short="linux")
+ self.linux_images.append(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. """
+ images = []
+
+ if not self.can_dual_boot:
+ return
+
+ for partition in self.storage.partitions:
+ if not partition.exists:
+ continue
+
+ if self._device_is_bootable(partition):
+ image = BootLoaderImage(device=partition)
+ self.chain_images.append(image)
+
+ #
+ # target/stage1 device access
+ #
+ 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 device.type not in 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 device.exists:
+ 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 device.format.type not self.target_device_format_types:
+ return False
+
+ if device.format.type == "disklabel" or device.type == "partition":
+ if device.format.type == "disklabel":
+ label_type = device.format.labelType
+ else:
+ label_type = device.disk.format.labelType
+
+ if label_type not in self.target_device_disklabel_types:
+ return False
+
+ if 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:
+ try:
+ idx = self.target_device_types.index(device.type)
+ except ValueError:
+ 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 _device_is_bootable(self, device, linux=False):
+ """ Return True if the specified device might contain an OS image. """
+ if device.type not in 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._bootloader_device_present():
+ # XXX is this really a dealbreaker?
+ return False
+
+ if hasattr(device, "partedPartition") and \
+ (not device.bootable or not device.partedPartition.active) and \
+ not check_for_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:
+ 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._device_is_bootable(d)]
+
+ @property
+ def bootable_linux_devices(self):
+ """ Potential boot devices containing linux operating systems. """
+ return [d for d in self.storage.devices
+ if self._device_is_bootable(d, linux=True)]
+
+ #
+ # miscellaneous
+ #
+
+ @property
+ def has_windows(self):
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")])
+ @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
- if rc == 0:
- sys.exit(0)
- return DISPATCH_FORWARD
+ return t
- 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))
+ @timeout.setter
+ def timeout(self, seconds):
+ self._timeout = seconds
- return fixedGrubTarget
+ #
+ # configuration
+ #
-def writeBootloader(anaconda):
- def dosync():
- isys.sync()
- isys.sync()
- isys.sync()
+ 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)
- if anaconda.bootloader.defaultDevice == -1:
- return
+ def write_config_console(self, config):
+ """Write console-related configuration lines."""
+ pass
+
+ def write_config_password(self, config):
+ """Write password-related configuration lines."""
+ if self.password:
+ config.write("password=%s\n" % self.password)
+
+ def write_config_header(self, config):
+ """Write global configuration lines."""
+ self.write_config_console()
+ self.write_config_password()
+
+ 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")
- 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)
+ 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. """
+ raise NotImplementedError()
+
+ def read(self):
+ """ Read an existing bootloader configuration. """
+ raise NotImplementedError()
+
+ #
+ # installation
+ #
+ def write(self, install_root=""):
+ """ Write the bootloader configuration and install the bootloader. """
+ 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
+
+
+bootloader_classes[BootLoader.name] = BootLoader
+
+
+class GRUB(BootLoader):
+ name = "GRUB"
+ arches = ["i[3456]86", "x86_64"]
+ _config_dir = "grub"
+ _config_file = "grub.conf"
+ _device_map_file = "device.map"
+ can_dual_boot = True
+
+ # list of strings representing options for bootloader target device types
+ target_device_types = ["disk", "partition"]
+ target_device_raid_levels = []
+ target_device_format_types = []
+ 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)
+
+ #
+ # grub-related conveniences
+ #
+
+ def grub_device_name(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_prefix(self):
+ """ Prefix, if any, to paths in /boot. """
+ stage2dev = self.stage2_device
+ if stage2dev == self.storage.rootDevice:
+ prefix = "/boot"
else:
- anaconda.bootloader.doUpgradeOnly = 0
+ prefix = ""
- w = anaconda.intf.waitWindow(_("Bootloader"), _("Installing bootloader."))
+ return prefix
- kernelList = []
- otherList = []
- # getDefault needs to return a device, but that's too invasive for now.
- rootDev = anaconda.storage.rootDevice
+ @property
+ def grub_config_dir(self):
+ """ Config dir, adjusted for grub's view of the world. """
+ return self.grub_prefix + self._config_dir
- if not anaconda.bootloader.images.getDefault():
- defaultDev = None
- else:
- defaultDev = anaconda.storage.devicetree.getDeviceByName(anaconda.bootloader.images.getDefault())
+ #
+ # configuration
+ #
- kernelLabel = None
- kernelLongLabel = None
+ @property
+ def config_dir(self):
+ """ Full path to configuration directory. """
+ return "/boot" + self._config_dir
- 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))
+ @property
+ def config_file(self):
+ """ Full path to configuration file. """
+ return "%s/%s" % (self.config_dir, self._config_file)
- if kernelLabel is None:
- log.error("unable to find default image, bailing")
- w.pop()
- return
+ @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.kernel_args.append(console_arg)
+
+ def write_config_password(self, config):
+ """ Write password-related configuration. """
+ if self.password:
+ # FIXME: implement encryption
+ config.write("password --encrypted %s\n" % self.password)
+
+ def write_config_header(self, config, install_root=""):
+ """Write global configuration information. """
+ if self.grub_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.grub_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)
+ f.write("splashimage=%s%s/%s\n" % (grub_root_grub_name,
+ self.grub_config_dir,
+ splash))
+ f.write("hiddenmenu\n")
+
+ self.write_config_password()
+
+ def write_config_images(self, config):
+ """ Write image entries into configuration file. """
+ for image in self.images:
+ if isinstance(image, LinuxBootLoaderImage):
+ kernel_args = ["ro", "root=%s" % image.device.fstabSpec]
+ kernel_args.extend(self.kernel_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": self.grub_device_name(image.device),
+ "kernel": image.kernel,
+ "args": " ".join(kernel_args),
+ "prefix": self.grub_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("(hd%d) %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)
- plainLabelUsed = 0
- defkern = "kernel"
- for (version, arch, nick) in \
- anaconda.backend.kernelVersionList(anaconda.rootPath):
- if plainLabelUsed:
- kernelList.append(("%s-%s" %(kernelLabel, nick),
- "%s-%s" %(kernelLongLabel, nick),
- version))
- else:
- kernelList.append((kernelLabel, kernelLongLabel, version))
- if nick != "base":
- defkern = "kernel-%s" %(nick,)
- plainLabelUsed = 1
+ # 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)"
+ " %(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(self.stage1_device),
+ "stage2dev": self.grub_device(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):
+ self.install(install_root=install_root)
+
+ #
+ # miscellaneous
+ #
+
+ @property
+ def has_windows(self):
+ return len(self.bootable_chain_devices) != 0
+
+bootloader_classes[GRUB.name] = GRUB
+
+
+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
+
+ # 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.install(install_root=install_root)
+
+bootloader_classes[EFIGRUB.name] = EFIGRUB
+
+
+class Yaboot(BootLoader):
+ name = "Yaboot"
+ arches = ["ppc*"]
+ _config_file = "yaboot.conf"
+ prog = "ybin"
+
+ # list of strings representing options for bootloader target device types
+ target_device_types = ["mbr", "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)
+
+ @property
+ def boot_prefix(self):
+ if self.stage2_device.format.mountpoint == "/boot":
+ return ""
+ else:
+ return "/boot"
+
+ def write_config_password(self, config):
+ if self.password:
+ config.write("password=%s\n" % self.password)
+ config.write("restricted\n")
+
+ 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
+
+ header = ("# yaboot.conf generated by anaconda\n\n"
+ "boot=%(stage1dev)s\n"
+ "init-message=\"Welcome to %(product)s!\\nHit 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})
+ config.write(header)
+ self.write_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_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 = self.kernel_args[:]
+ 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 = ""
+
+ 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": " ".join(args),
+ "boot_prefix": self.boot_prefix})
+ config.write(stanza)
+
+ 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")
+
+
+bootloader_classes[Yaboot.name] = Yaboot
+
+
+class IPSeriesYaboot(Yaboot):
+ # FIXME: 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
+
+ #
+ # configuration
+ #
+
+ def write_config_variant_header(self, config):
+ config.write("nonvram\n") # only on pSeries?
+ config.write("fstype=raw\n")
+
+bootloader_classes[IPSeriesYaboot.name] = IPSeriesYaboot
+
+
+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
+
+ #
+ # 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")
+
+
+bootloader_classes[MacYaboot.name] = MacYaboot
+
+
+class ZIPL(BootLoader):
+ name = "ZIPL"
+ arches = ["s390*"]
+ config_file = "/etc/zipl.conf"
+ chandev_config_file = "/etc/chandev.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", "lvm"]
+ boot_device_raid_levels = [mdraid.RAID1]
+
+ packages = ["s390utils"] # is this bootloader or platform?
+
+ image_label_attr = "short_label"
+
+ def __init__(self, storage, chandevs=None):
+ super(ZIPL, self).__init__(storage)
+ self.chandevs = chandevs
+
+ #
+ # configuration
+ #
+
+ @property
+ def boot_dir(self):
+ return "/boot"
+
+ def write_config_images(self, config):
+ for image in self.images:
+ args = self.kernel_args[:]
+ args.insert(0, "root=%s/%s" % (self.boot_dir, image.kernel))
+ stanza = ("[%(label)s]\n"
+ "\timage=%(boot_dir)/%(kernel)s\n"
+ "%(initrd_line)s"
+ "\tparameters=\"%(args)s\"\n"
+ % {"label": self.image_label(image),
+ "kernel": image.kernel, "initrd_line": initrd_line,
+ "args": " ".join(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)
+
+ def write_chandev_config(self, install_root=""):
+ if self.chandevs:
+ chandev_path = install_root + self.chandev_config_file
+ if os.access(chandev_path, os.R_OK):
+ try:
+ os.rename(chandev_path, chandev_path + ".rpmsave")
+ except OSError as e:
+ log.warning("failed to back up /etc/chandev.conf: %s" % e)
+
+ f = open(chandev_path, "w")
+ f.write("noauto\n")
+ for chandev in self.chandevs:
+ f.write("%s\n" % chandev)
+ f.close()
+
+ try:
+ os.chmod(chandev_path, 0644)
+ except OSError as e:
+ log.error("failed to set mode of /etc/chandev.conf: %s" % e)
+
+ def write_config(self, install_root=""):
+ self.write_chandev_config(install_root=install_root)
+ super(ZIPL, self).write_config(install_root=install_root)
+
+ #
+ # 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.
+ device = re.sub(".+?: ", "", line)
+ device = re.sub("(\s\(.+\))?\.$", "", device)
+ # XXX FIXME: why do we do this? booty called self.setDevice
+ # with the above device. for ks.cfg? is our
+ # already-set device wrong?
+
+
+bootloader_classes[ZIPL.name] = ZIPL
+
+
+class SILO(BootLoader):
+ name = "SILO"
+ arches = ["sparc*"]
+ 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 boot_prefix(self):
+ # FIXME: same as Yaboot
+ if self.stage2_device.format.mountpoint == "/boot":
+ return ""
+ else:
+ return "/boot"
+
+ @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 for boot options\n\n" % productName)
+ f.close()
+ os.chmod(message_file, 0600)
+
+ def write_config_images(self, config):
+ # FIXME: same as Yaboot minus the macos bit
+ for image in self.images:
+ args = self.kernel_args[:]
+ 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 = ""
+
+ 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": " ".join(args),
+ "boot_prefix": self.boot_prefix})
+ config.write(stanza)
+
+ def write_config_password(self, config):
+ # FIXME: same as Yaboot
+ if self.password:
+ config.write("password=%s\n" % self.password)
+ config.write("restricted\n")
+
+ 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")
+
+bootloader_classes[SILO.name] = SILO
+
+""" 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):
+ # FIXME: verify both stage1 and stage2 devices are set
+ stage1_device = anaconda.bootloader.stage1_device
+ stage2_device = anaconda.bootloader.stage2_device
+
+ w = None
+ if anaconda.intf:
+ w = anaconda.intf.waitWindow(_("Bootloader"),
+ _("Installing bootloader."))
+
+ """ Current behavior is to use the first kernel as the default.
+
+ 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. """
+
+ # 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[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
+
+ # get the name of the default kernel package for use in
+ # /etc/sysconfig/kernel
+ default_kernel = "kernel"
+ if nick != "base":
+ default_kernel += "-%s" % nick
+
+ # all the linux images' labels are based on the default image's
+ base_label = default_image.label
+ base_short = default_image.short_label
+ kernel_versions.pop(0)
+
+ # now add images for each of the other kernels
+ for (version, arch, nick) in kernel_versions:
+ 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)
+
+ 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 .
-#
-# Author: David Cantrell
-
-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
-# Adrian Likins
-# Peter Jones
-#
-# 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:
- # root= [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
-# Erik Troan
-# Peter Jones
-#
-# 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
-# Peter Jones
-#
-# 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
-# Eric Troan
-# Adrian Likins
-"""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 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 38f6a9e..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[0][0] + '\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]\n' % (label))
- 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 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
diff --git a/pyanaconda/dispatch.py b/pyanaconda/dispatch.py
index f111f84..c67e96a 100644
--- a/pyanaconda/dispatch.py
+++ b/pyanaconda/dispatch.py
@@ -92,7 +92,6 @@ installSteps = [
("storagedone", storageComplete, ),
("enablefilesystems", turnOnFilesystems, ),
("upgbootloader", ),
- ("bootloadersetup", bootloaderSetupChoices, ),
("bootloader", ),
("reposetup", doBackendSetup, ),
("tasksel", ),
diff --git a/pyanaconda/iw/blpasswidget.py b/pyanaconda/iw/blpasswidget.py
index 4b377b5..6655be3 100644
--- a/pyanaconda/iw/blpasswidget.py
+++ b/pyanaconda/iw/blpasswidget.py
@@ -31,12 +31,9 @@ class BootloaderPasswordWidget:
self.parent = parent
self.intf = anaconda.intf
- if anaconda.bootloader.getPassword():
- usePass = 1
- self.password = anaconda.bootloader.getPassword()
- else:
- usePass = 0
- self.password = None
+ self.password = anaconda.platform.bootloader.password
+ if self.password:
+ usePass = True
vbox = gtk.VBox(False, 6)
@@ -44,12 +41,8 @@ class BootloaderPasswordWidget:
self.usePassCb = gtk.CheckButton(_("_Use a boot loader password"))
self.usePassCb.set_tooltip_text(_("A boot loader password prevents users from changing kernel options, increasing security."))
self.passButton = gtk.Button("No password")
- if usePass:
- self.usePassCb.set_active(True)
- self.passButton.set_sensitive(True)
- else:
- self.usePassCb.set_active(False)
- self.passButton.set_sensitive(False)
+ self.usePassCb.set_active(usePass)
+ self.passButton.set_sensitive(usePass)
self.usePassCb.connect("toggled", self.passCallback)
self.passButton.connect("clicked", self.passButtonCallback)
self.setPassLabel()
@@ -130,7 +123,7 @@ class BootloaderPasswordWidget:
dialog.show_all()
- while 1:
+ while True:
rc = dialog.run()
if rc in [gtk.RESPONSE_CANCEL, gtk.RESPONSE_DELETE_EVENT]:
rc = False
diff --git a/pyanaconda/iw/bootloader_main_gui.py b/pyanaconda/iw/bootloader_main_gui.py
index 3512026..738e24f 100644
--- a/pyanaconda/iw/bootloader_main_gui.py
+++ b/pyanaconda/iw/bootloader_main_gui.py
@@ -47,24 +47,19 @@ class MainBootloaderWindow(InstallWindow):
def getNext(self):
# go ahead and set the device even if we already knew it
# since that won't change anything
- self.bl.setDevice(self.bldev)
-
- self.bl.drivelist = self.driveorder
+ self.bl._target_device = self.bldev
+ self.bl.drive_order = self.driveorder
if not self.grubCB.get_active():
# if we're not installing a boot loader, don't show the second
# screen and don't worry about other options
self.dispatch.skipStep("instbootloader", skip = 1)
-
- # kind of a hack...
- self.bl.defaultDevice = None
return
else:
self.dispatch.skipStep("instbootloader", skip = 0)
- self.bl.setUseGrub(1)
# set the password
- self.bl.setPassword(self.blpass.getPassword(), isCrypted = 0)
+ self.bl.password = self.blpass.getPassword()
# set the bootloader images based on what's in our list
self.oslist.setBootloaderImages()
@@ -88,7 +83,7 @@ class MainBootloaderWindow(InstallWindow):
first = combo.get_model()[iter][1]
desc = choices["mbr"][1]
- dxml.get_widget("mbrRadio").set_label("%s - /dev/%s" %(_(desc), first))
+ dxml.get_widget("mbrRadio").set_label("%s - %s" %(_(desc), first.path))
dxml.get_widget("mbrRadio").set_data("bootDevice", first)
def __genStore(combo, disks, active):
@@ -114,13 +109,13 @@ class MainBootloaderWindow(InstallWindow):
dialog.set_transient_for(self.parent)
dialog.show()
- choices = anaconda.platform.bootloaderChoices(self.bl)
+ choices = anaconda.platform.bootloaderChoices
for t in ("mbr", "boot"):
if not choices.has_key(t):
continue
(device, desc) = choices[t]
w = dxml.get_widget("%sRadio" %(t,))
- w.set_label("%s - /dev/%s" %(_(desc), device))
+ w.set_label("%s - %s" %(_(desc), device.path))
w.show()
if self.bldev == device:
w.set_active(True)
@@ -128,6 +123,7 @@ class MainBootloaderWindow(InstallWindow):
w.set_active(False)
w.set_data("bootDevice", device)
+ bl_disks = anaconda.platform.bootloader.drives
for i in range(1, 5):
if len(self.driveorder) < i:
break
@@ -135,15 +131,12 @@ class MainBootloaderWindow(InstallWindow):
lbl = dxml.get_widget("bd%dLabel" %(i,))
combo.show()
lbl.show()
- partitioned = anaconda.storage.partitioned
- disks = anaconda.storage.disks
- bl_disks = [d for d in disks if d in partitioned]
m = __genStore(combo, bl_disks, self.driveorder[i - 1])
dxml.get_widget("bd1Combo").connect("changed", __driveChange, dxml, choices)
__driveChange(dxml.get_widget("bd1Combo"), dxml, choices)
- while 1:
+ while True:
rc = dialog.run()
if rc in [gtk.RESPONSE_CANCEL, gtk.RESPONSE_DELETE_EVENT]:
break
@@ -174,55 +167,28 @@ class MainBootloaderWindow(InstallWindow):
if d not in neworder:
neworder.append(d)
self.driveorder = neworder
-
break
dialog.destroy()
- self.grubCB.set_label(_("_Install boot loader on /dev/%s.") %
- (self.bldev,))
+ self.grubCB.set_label(_("_Install boot loader on %s.") %
+ (self.bldev.path,))
return rc
- def _setBLCBText(self):
- self.grubCB.set_label(_("_Install boot loader on /dev/%s.") %
- (self.bldev,))
-
-
def getScreen(self, anaconda):
self.dispatch = anaconda.dispatch
self.bl = anaconda.bootloader
self.intf = anaconda.intf
-
- self.driveorder = self.bl.drivelist
- if len(self.driveorder) == 0:
- partitioned = anaconda.storage.partitioned
- disks = anaconda.storage.disks
- self.driveorder = [d.name for d in disks if d in partitioned]
-
- if self.bl.getPassword():
- self.usePass = 1
- self.password = self.bl.getPassword()
- else:
- self.usePass = 0
- self.password = None
+ self.driveorder = [d.name for d in self.bl.drives]
thebox = gtk.VBox (False, 12)
thebox.set_border_width(18)
# make sure we get a valid device to say we're installing to
- if self.bl.getDevice() is not None:
- self.bldev = self.bl.getDevice()
- else:
- # we don't know what it is yet... if mbr is possible, we want
- # it, else we want the boot dev
- choices = anaconda.platform.bootloaderChoices(self.bl)
- if choices.has_key('mbr'):
- self.bldev = choices['mbr'][0]
- else:
- self.bldev = choices['boot'][0]
+ self.bldev = self.bl.stage1_device
hb = gtk.HBox(False, 12)
- self.grubCB = gtk.CheckButton(_("_Install boot loader on /dev/%s.") %
- (self.bldev,))
+ self.grubCB = gtk.CheckButton(_("_Install boot loader on %s.") %
+ (self.bldev.path,))
self.grubCB.set_active(not self.dispatch.stepInSkipList("instbootloader"))
self.grubCB.connect("toggled", self.bootloaderChanged)
hb.pack_start(self.grubCB, False)
diff --git a/pyanaconda/iw/osbootwidget.py b/pyanaconda/iw/osbootwidget.py
index 9fc3dbd..4cca438 100644
--- a/pyanaconda/iw/osbootwidget.py
+++ b/pyanaconda/iw/osbootwidget.py
@@ -27,6 +27,7 @@ from pyanaconda import gui
import datacombo
from pyanaconda.constants import *
from pyanaconda.storage.devices import devicePathToName
+import copy
import gettext
_ = lambda x: gettext.ldgettext("anaconda", x)
@@ -34,15 +35,12 @@ _ = lambda x: gettext.ldgettext("anaconda", x)
class OSBootWidget:
"""Widget to display OSes to boot and allow adding new ones."""
- def __init__(self, anaconda, parent, blname = None):
- self.bl = anaconda.bootloader
+ def __init__(self, anaconda, parent):
+ self.bl = anaconda.platform.bootloader
self.storage = anaconda.storage
self.parent = parent
self.intf = anaconda.intf
- if blname is not None:
- self.blname = blname
- else:
- self.blname = "GRUB"
+ self.blname = self.bl.name
self.setIllegalChars()
@@ -59,9 +57,8 @@ class OSBootWidget:
sw.set_size_request(300, 100)
box.pack_start(sw, True)
-
self.osStore = gtk.ListStore(gobject.TYPE_BOOLEAN, gobject.TYPE_STRING,
- gobject.TYPE_STRING, gobject.TYPE_BOOLEAN)
+ gobject.TYPE_STRING, gobject.TYPE_PYOBJECT)
self.osTreeView = gtk.TreeView(self.osStore)
theColumns = [ _("Default"), _("Label"), _("Device") ]
@@ -86,8 +83,11 @@ class OSBootWidget:
sw.add(self.osTreeView)
self.osTreeView.connect('row-activated', self.osTreeActivateCb)
- self.imagelist = self.bl.images.getImages()
- self.defaultDev = self.bl.images.getDefault()
+ self.images = {}
+ for image in self.bl.images:
+ self.images[image.device.name] = copy.copy(image)
+
+ self.defaultDev = self.bl.default.device
self.fillOSList()
buttonbar = gtk.VButtonBox()
@@ -126,7 +126,7 @@ class OSBootWidget:
self.fillOSList()
# adds/edits a new "other" os to the boot loader config
- def editOther(self, oldDevice, oldLabel, isDefault, isRoot = 0):
+ def editOther(self, image):
dialog = gtk.Dialog(_("Image"), self.parent)
dialog.add_button('gtk-cancel', gtk.RESPONSE_CANCEL)
dialog.add_button('gtk-ok', 1)
@@ -152,7 +152,7 @@ class OSBootWidget:
label = gui.MnemonicLabel(_("_Device"))
table.attach(label, 0, 1, 2, 3, gtk.FILL, 0, 10)
- if not isRoot:
+ if not image.device == self.storage.rootDevice:
parts = []
for part in self.storage.partitions:
@@ -167,8 +167,8 @@ class OSBootWidget:
defindex = 0
i = 0
for part in parts:
- deviceCombo.append(part.path, part.name)
- if oldDevice and oldDevice == part.name:
+ deviceCombo.append(part.path, part)
+ if image.device and image.device == part:
defindex = i
i = i + 1
@@ -178,22 +178,17 @@ class OSBootWidget:
table.attach(deviceCombo, 1, 2, 2, 3, gtk.FILL, 0, 10)
label.set_mnemonic_widget(deviceCombo)
else:
- table.attach(gtk.Label(oldDevice), 1, 2, 2, 3, gtk.FILL, 0, 10)
+ table.attach(gtk.Label(image.device.name), 1, 2, 2, 3, gtk.FILL, 0, 10)
default = gtk.CheckButton(_("Default Boot _Target"))
table.attach(default, 0, 2, 3, 4, gtk.FILL, 0, 10)
- if isDefault != 0:
- default.set_active(True)
-
- if self.numentries == 1 and oldDevice != None:
+ default.set_active(image.device == self.defaultDev)
+ if len(self.images.keys()) == 1 and image.device:
default.set_sensitive(False)
- else:
- default.set_sensitive(True)
-
dialog.vbox.pack_start(table)
dialog.show_all()
- while 1:
+ while True:
rc = dialog.run()
# cancel
@@ -202,10 +197,10 @@ class OSBootWidget:
label = labelEntry.get_text()
- if not isRoot:
+ if not image.device == self.storage.rootDevice:
dev = deviceCombo.get_active_value()
else:
- dev = oldDevice
+ dev = image.device
if not dev:
self.intf.messageWindow(_("Error"),
@@ -234,17 +229,15 @@ class OSBootWidget:
# verify that the label hasn't been used
foundBad = 0
- for key in self.imagelist.keys():
- if dev == key:
+ for key in self.images.keys():
+ if dev.name == key:
continue
- if self.blname == "GRUB":
- thisLabel = self.imagelist[key][1]
- else:
- thisLabel = self.imagelist[key][0]
+
+ thisLabel = self.bl.image_label(self.images[key])
# if the label is the same as it used to be, they must
# have changed the device which is fine
- if thisLabel == oldLabel:
+ if thisLabel == image.label:
continue
if thisLabel == label:
@@ -258,32 +251,23 @@ class OSBootWidget:
continue
# they could be duplicating a device, which we don't handle
- if dev in self.imagelist.keys() and (not oldDevice or
- dev != oldDevice):
+ if dev.name in self.images.keys() and (not image.device or
+ dev != image.device):
self.intf.messageWindow(_("Duplicate Device"),
_("This device is already being "
"used for another boot entry."),
type="warning")
continue
- # if we're editing a previous, get what the old info was for
- # labels. otherwise, make it something safe for grub and the
- # device name for lilo for lack of any better ideas
- if oldDevice:
- (oldshort, oldlong, oldisroot) = self.imagelist[oldDevice]
- else:
- (oldshort, oldlong, oldisroot) = (dev, label, None)
-
# if we're editing and the device has changed, delete the old
- if oldDevice and dev != oldDevice:
- del self.imagelist[oldDevice]
+ if image.device and dev != image.device:
+ del self.images[image.device.name]
+ image.device = dev
+
+ image.label = label
# go ahead and add it
- if self.blname == "GRUB":
- self.imagelist[dev] = (oldshort, label, isRoot)
- else:
- self.imagelist[dev] = (label, oldlong, isRoot)
-
+ self.images[dev.name] = image
if default.get_active():
self.defaultDev = dev
@@ -299,27 +283,22 @@ class OSBootWidget:
if not iter:
return None
- dev = devicePathToName(model.get_value(iter, 2))
- label = model.get_value(iter, 1)
- isRoot = model.get_value(iter, 3)
- isDefault = model.get_value(iter, 0)
- return (dev, label, isDefault, isRoot)
-
+ return model.get_value(iter, 3)
def addEntry(self, widget, *args):
- self.editOther(None, None, 0)
+ image = bootloader.BootLoaderImage(device=None, label=None)
+ self.editOther(image)
def deleteEntry(self, widget, *args):
rc = self.getSelected()
if not rc:
return
- (dev, label, isDefault, isRoot) = rc
- if not isRoot:
- del self.imagelist[dev]
- if isDefault:
- keys = self.imagelist.keys()
- keys.sort()
- self.defaultDev = keys[0]
+ if image.device != self.storage.rootDevice:
+ del self.images[image.device.name]
+ if image.device == self.defaultDev:
+ devs = [i.device for i in self.images]
+ devs.sort(key=lambda d: d.name)
+ self.defaultDev = devs[0]
self.fillOSList()
else:
@@ -334,68 +313,45 @@ class OSBootWidget:
rc = self.getSelected()
if not rc:
return
- (dev, label, isDefault, isRoot) = rc
- self.editOther(dev, label, isDefault, isRoot)
+ self.editOther(rc)
# the default os was changed in the treeview
def toggledDefault(self, data, row):
iter = self.osStore.get_iter((int(row),))
- dev = self.osStore.get_value(iter, 2)
- self.defaultDev = devicePathToName(dev)
+ self.defaultDev = self.osStore.get_value(iter, 3)
self.fillOSList()
# fill in the os list tree view
def fillOSList(self):
self.osStore.clear()
- keys = self.imagelist.keys()
- keys.sort()
-
- for dev in keys:
- (label, longlabel, fstype) = self.imagelist[dev]
- device = self.storage.devicetree.getDeviceByName(dev)
- if self.blname == "GRUB":
- theLabel = longlabel
- else:
- theLabel = label
+ devs = sorted(self.images.keys())
+ for dev in devs:
+ image = self.images[dev]
# if the label is empty, remove from the image list and don't
# worry about it
- if not theLabel:
- del self.imagelist[dev]
+ if not image.label:
+ del self.images[dev]
continue
- isRoot = 0
- rootDev = self.storage.rootDevice
- if rootDev and rootDev.name == dev:
- isRoot = 1
-
- devPath = getattr(device, "path", "/dev/%s" % dev)
iter = self.osStore.append()
- self.osStore.set_value(iter, 1, theLabel)
- self.osStore.set_value(iter, 2, devPath)
- self.osStore.set_value(iter, 3, isRoot)
- if self.defaultDev == dev:
- self.osStore.set_value(iter, 0, True)
- else:
- self.osStore.set_value(iter, 0, False)
-
- self.numentries = len(keys)
+ self.osStore.set_value(iter, 0, self.defaultDev == image.device)
+ self.osStore.set_value(iter, 1, self.bl.image_label(image))
+ self.osStore.set_value(iter, 2, dev)
+ self.osStore.set_value(iter, 3, image)
def osTreeActivateCb(self, view, path, col):
self.editEntry(view)
-
-
+
def getWidget(self):
return self.widget
- # FIXME: I really shouldn't have such intimate knowledge of
- # the bootloader object
def setBootloaderImages(self):
- "Apply the changes from our list into the self.bl object"
- # make a copy of our image list to shove into the bl struct
- self.bl.images.images = {}
- for key in self.imagelist.keys():
- self.bl.images.images[key] = self.imagelist[key]
- self.bl.images.setDefault(self.defaultDev)
+ """Apply the changes from our list into the self.bl object."""
+ self.bl.clear_images()
+ for image in self.images.values():
+ self.bl.add_image(image)
+ if image.device == self.defaultDev:
+ self.bl.default = image
diff --git a/pyanaconda/iw/upgrade_bootloader_gui.py b/pyanaconda/iw/upgrade_bootloader_gui.py
index afbe62b..60ecad2 100644
--- a/pyanaconda/iw/upgrade_bootloader_gui.py
+++ b/pyanaconda/iw/upgrade_bootloader_gui.py
@@ -23,7 +23,6 @@
from iw_gui import *
import gtk
-from pyanaconda.booty import checkbootloader
from pyanaconda.storage.devices import devicePathToName
from pyanaconda.constants import *
@@ -41,96 +40,37 @@ class UpgradeBootloaderWindow (InstallWindow):
def getNext(self):
if self.nobl_radio.get_active():
- self.dispatch.skipStep("bootloadersetup", skip = 1)
self.dispatch.skipStep("bootloader", skip = 1)
self.dispatch.skipStep("instbootloader", skip = 1)
elif self.newbl_radio.get_active():
- self.dispatch.skipStep("bootloadersetup", skip = 0)
self.dispatch.skipStep("bootloader", skip = 0)
self.dispatch.skipStep("instbootloader", skip = 0)
self.bl.doUpgradeOnly = 0
else:
- self.dispatch.skipStep("bootloadersetup", skip = 0)
self.dispatch.skipStep("bootloader", skip = 1)
self.dispatch.skipStep("instbootloader", skip = 0)
self.bl.doUpgradeOnly = 1
- if self.type == "GRUB":
- self.bl.useGrubVal = 1
- else:
- self.bl.useGrubVal = 0
- self.bl.setDevice(devicePathToName(self.bootDev))
-
- def _newToLibata(self, rootPath):
- # NOTE: any changes here need to be done in upgrade_bootloader_text too
- try:
- f = open("/proc/modules", "r")
- buf = f.read()
- if buf.find("libata") == -1:
- return False
- except:
- log.debug("error reading /proc/modules")
- pass
-
- try:
- f = open(rootPath + "/etc/modprobe.conf")
- except:
- log.debug("error reading /etc/modprobe.conf")
- return False
-
- modlines = f.readlines()
- f.close()
-
- try:
- f = open("/tmp/scsidisks")
- except:
- log.debug("error reading /tmp/scsidisks")
- return False
- mods = []
- for l in f.readlines():
- (disk, mod) = l.split()
- if mod.strip() not in mods:
- mods.append(mod.strip())
- f.close()
-
- for l in modlines:
- stripped = l.strip()
-
- if stripped == "" or stripped[0] == "#":
- continue
-
- if stripped.find("scsi_hostadapter") != -1:
- mod = stripped.split()[-1]
- if mod in mods:
- mods.remove(mod)
-
- if len(mods) > 0:
- return True
- return False
+ self.bl.stage1_device = self.bootDev
def getScreen(self, anaconda):
self.dispatch = anaconda.dispatch
- self.bl = anaconda.bootloader
+ self.bl = anaconda.platform.bootloader
- newToLibata = self._newToLibata(anaconda.rootPath)
-
- (self.type, self.bootDev) = \
- checkbootloader.getBootloaderTypeAndBoot(anaconda.rootPath, storage=anaconda.storage)
+ # TODO: implement bootloader detection
+ self.type = None
+ self.bootDev = None
self.update_radio = gtk.RadioButton(None, _("_Update boot loader configuration"))
updatestr = _("This will update your current boot loader.")
- if newToLibata or (self.type is None or self.bootDev is None):
- if newToLibata:
- current = _("Due to system changes, your boot loader "
- "configuration can not be automatically updated.")
- else:
- current = _("The installer is unable to detect the boot loader "
- "currently in use on your system.")
+ if self.type is None or self.bootDev is None:
+ current = _("The installer is unable to detect the boot loader "
+ "currently in use on your system.")
self.update_label = gtk.Label("%s" % (updatestr,))
self.update_radio.set_sensitive(False)
self.update_label.set_sensitive(False)
- update = 0
+ update = False
else:
current = _("The installer has detected the %(type)s boot loader "
"currently installed on %(bootDev)s.") \
@@ -138,7 +78,7 @@ class UpgradeBootloaderWindow (InstallWindow):
self.update_label = gtk.Label("%s %s" % (updatestr,
_("This is the recommended option.")))
self.update_radio.set_active(False)
- update = 1
+ update = True
self.newbl_radio = gtk.RadioButton(self.update_radio,
_("_Create new boot loader "
@@ -165,10 +105,8 @@ class UpgradeBootloaderWindow (InstallWindow):
str = _("What would you like to do?")
# if they have one, the default is to update, otherwise the
# default is to not touch anything
- if update == 1:
+ if update:
default = self.update_radio
- elif newToLibata:
- default = self.newbl_radio
else:
default = self.nobl_radio
diff --git a/pyanaconda/kickstart.py b/pyanaconda/kickstart.py
index 636d0fe..87f20fe 100644
--- a/pyanaconda/kickstart.py
+++ b/pyanaconda/kickstart.py
@@ -246,8 +246,8 @@ class Bootloader(commands.bootloader.F15_Bootloader):
raise KickstartValueError, formatErrorMsg(self.lineno, msg="Selected upgrade mode for bootloader but not doing an upgrade")
if self.upgrade:
- self.anaconda.bootloader.kickstart = 1
- self.anaconda.bootloader.doUpgradeOnly = 1
+ # TODO: new dispatcher step or flag in BootLoader?
+ raise NotImplementedError("bootloader update not implemented yet")
if location is None:
self.anaconda.ksdata.permanentSkipSteps.extend(["bootloadersetup", "instbootloader"])
@@ -255,45 +255,29 @@ class Bootloader(commands.bootloader.F15_Bootloader):
self.anaconda.ksdata.showSteps.append("bootloader")
if self.appendLine:
- self.anaconda.bootloader.args.append(self.appendLine)
+ self.anaconda.bootloader.kernel_args.append(self.appendLine)
if self.password:
- self.anaconda.bootloader.setPassword(self.password, isCrypted = self.isCrypted)
+ # TODO: implement password encryption
+ self.anaconda.bootloader.password = self.password
if location != None:
- self.anaconda.bootloader.defaultDevice = location
- else:
- self.anaconda.bootloader.defaultDevice = -1
+ self.anaconda.bootloader.default = location
if self.timeout:
self.anaconda.bootloader.timeout = self.timeout
- # add unpartitioned devices that will get partitioned into
- # bootloader.drivelist
- disks = self.anaconda.storage.disks
- partitioned = self.anaconda.storage.partitioned
- for disk in [d for d in disks if not d.partitioned]:
- if shouldClear(disk, self.anaconda.storage.config.clearPartType,
- self.anaconda.storage.config.clearPartDisks):
- # add newly partitioned disks to the drivelist
- self.anaconda.bootloader.drivelist.append(disk.name)
- elif disk.name in self.anaconda.bootloader.drivelist:
- # remove unpartitioned disks from the drivelist
- self.anaconda.bootloader.drivelist.remove(disk.name)
- self.anaconda.bootloader.drivelist.sort(
- cmp=self.anaconda.storage.compareDisks)
+ # TODO: add sanity checking for things like choosing unpartitioned disks as
+ # bootloader target devices
# Throw out drives specified that don't exist.
- if self.driveorder and len(self.driveorder) > 0:
- new = []
- for drive in self.driveorder:
- if drive in self.anaconda.bootloader.drivelist:
- new.append(drive)
- else:
- log.warning("requested drive %s in boot drive order "
- "doesn't exist" %(drive,))
+ disk_names = [d.name for d in self.anaconda.storage.disks]
+ for drive in self.driveorder[:]:
+ if drive not in disk_names:
+ log.warning("requested drive %s in boot drive order doesn't exist" % drive)
+ self.driveorder.remove(drive)
- self.anaconda.bootloader.updateDriveList(new)
+ self.anaconda.bootloader.drive_order = self.driveorder
self.anaconda.ksdata.permanentSkipSteps.extend(["upgbootloader", "bootloader"])
diff --git a/pyanaconda/platform.py b/pyanaconda/platform.py
index 3942887..4d6a85e 100644
--- a/pyanaconda/platform.py
+++ b/pyanaconda/platform.py
@@ -34,15 +34,9 @@ class Platform(object):
during installation. The intent is to eventually encapsulate all the
architecture quirks in one place to avoid lots of platform checks
throughout anaconda."""
- _bootFSTypes = ["ext3"]
- _diskLabelType = "msdos"
- _isEfi = iutil.isEfi()
_minimumSector = 0
_packages = []
- _supportsLvmBoot = False
- _supportsMdRaidBoot = False
- _minBootPartSize = 50
- _maxBootPartSize = 0
+ _bootloaderClass = BootLoader
def __init__(self, anaconda):
"""Creates a new Platform object. This is basically an abstract class.
@@ -50,34 +44,40 @@ class Platform(object):
returned by getPlatform below. Not all subclasses need to provide
all the methods in this class."""
self.anaconda = anaconda
+ self.bootloader = self._bootloaderClass(storage=anaconda.storage)
- def _mntDict(self):
- """Return a dictionary mapping mount points to devices."""
- ret = {}
- for device in [d for d in self.anaconda.storage.devices if d.format.mountable]:
- ret[device.format.mountpoint] = device
-
- return ret
-
+ @property
def bootDevice(self):
- """Return the device where /boot is mounted."""
- if self.__class__ is Platform:
- raise NotImplementedError("bootDevice not implemented for this platform")
+ """The device that includes the /boot filesystem."""
+ return self.bootloader.stage2_device
- mntDict = self._mntDict()
- return mntDict.get("/boot", mntDict.get("/"))
+ @property
+ def bootloaderDevice(self):
+ """The device the bootloader will be installed into."""
+ return self.bootloader.stage1_device
+
+ @property
+ def bootFSTypes(self):
+ """A list of all valid filesystem types for the boot partition."""
+ return self.bootloader.linux_boot_device_format_types
@property
def defaultBootFSType(self):
- """Return the default filesystem type for the boot partition."""
- return self._bootFSTypes[0]
+ """The default filesystem type for the boot partition."""
+ return self.bootFSTypes[0]
@property
- def bootFSTypes(self):
- """Return a list of all valid filesystem types for the boot partition."""
- return self._bootFSTypes
+ def diskLabelTypes(self):
+ """A list of valid disklabel types for this architecture."""
+ return self.bootloader.target_device_disklabel_types
- def bootloaderChoices(self, bl):
+ @property
+ def defaultDiskLabelType(self):
+ """The default disklabel type for this architecture."""
+ return self.diskLabelTypes[0]
+
+ @property
+ def bootloaderChoices(self):
"""Return the default list of places to install the bootloader.
This is returned as a dictionary of locations to (device, identifier)
tuples. If there is no boot device, an empty dictionary is
@@ -85,21 +85,41 @@ class Platform(object):
if self.__class__ is Platform:
raise NotImplementedError("bootloaderChoices not implemented for this platform")
- bootDev = self.bootDevice()
+ bootDev = self.bootDevice
ret = {}
if not bootDev:
return ret
+ # XXX reconsider how/if this is used
if bootDev.type == "mdarray":
ret["boot"] = (bootDev.name, N_("RAID Device"))
- ret["mbr"] = (bl.drivelist[0], N_("Master Boot Record (MBR)"))
+ ret["mbr"] = (self.bootloader.drives[0].name,
+ N_("Master Boot Record (MBR)"))
else:
ret["boot"] = (bootDev.name, N_("First sector of boot partition"))
- ret["mbr"] = (bl.drivelist[0], N_("Master Boot Record (MBR)"))
+ ret["mbr"] = (self.bootloaderDevice.name,
+ N_("Master Boot Record (MBR)"))
return ret
+ def checkDiskLabel(self, req):
+ """Check the disk containing req for the correct disklabel type.
+
+ Return a list of error strings if incorrect disklabels are found."""
+ errors = []
+ for partition in self.storage.partitions:
+ if req != partition and not req.dependsOn(partition):
+ continue
+
+ labelType = partition.disk.format.labelType
+ labelTypes = self.bootloader.target_device_diskabel_types
+ if labelType not in labelTypes:
+ errors.append(_("%s must have a %s disk label.")
+ % (partition.disk.name,
+ " or ".join([t.upper for t in labelTypes])))
+ return errors
+
def checkBootRequest(self, req):
"""Perform an architecture-specific check on the boot device. Not all
platforms may need to do any checks. Returns a list of errors if
@@ -109,47 +129,52 @@ class Platform(object):
if not req:
return [_("You have not created a bootable partition.")]
- # most arches can't have boot on RAID
- if req.type == "mdarray":
- if not self.supportsMdRaidBoot:
- errors.append(_("Bootable partitions cannot be on a RAID device."))
- elif req.type == "mdarray" and req.level != 1:
- errors.append(_("Bootable partitions can only be on RAID1 devices."))
- else:
- for p in req.parents:
- if p.type != "partition":
- errors.append(_("Bootable RAID1 set members must be partitions."))
- break
-
- # most arches can't have boot on a logical volume
- if req.type == "lvmlv" and not self.supportsLvmBoot:
- errors.append(_("Bootable partitions cannot be on a logical volume."))
+ # TODO: reimplement BootLoader._device_is_bootable(req, linux=True)
+ # such that it returns a list of error strings instead of
+ # True/False
+
+ if req.type not in self.bootloader.boot_device_types:
+ errors.append(_("The /boot filesystem cannot be on devices of "
+ "type %s") % req.type)
+ elif req.type == "mdarray":
+ raid_levels = self.bootloader.boot_device_raid_levels
+ if req.level not in raid_levels:
+ levels = ",".join(["RAID%d" % l for l in raid_levels])
+ errors.append(_("RAID sets containing the /boot filesystem "
+ "must have one of the following raid levels: "
+ "%s.") % levels)
+
+ for p in req.parents:
+ if p.type != "partition":
+ errors.append(_("RAID sets containing the /boot "
+ "filesystem may only have partitions "
+ "as member devices."))
+ break
# Make sure /boot is on a supported FS type. This prevents crazy
# things like boot on vfat.
if not req.format.bootable or \
- (getattr(req.format, "mountpoint", None) == "/boot" and
- req.format.type not in self.bootFSTypes):
- errors.append(_("Bootable partitions cannot be on an %s filesystem.") % req.format.type)
+ req.format.type not in self.bootFSTypes:
+ errors.append(_("The /boot filesystem cannot be of type %s.") % req.format.type)
if req.type == "luks/dm-crypt":
# Handle encrypted boot on a partition.
- errors.append(_("Bootable partitions cannot be on an encrypted block device"))
+ errors.append(_("The /boot filesystem cannot be on an encrypted block device"))
else:
# Handle encrypted boot on more complicated devices.
for dev in filter(lambda d: d.type == "luks/dm-crypt", self.anaconda.storage.devices):
if req in self.anaconda.storage.deviceDeps(dev):
- errors.append(_("Bootable partitions cannot be on an encrypted block device"))
+ errors.append(_("The /boot filesystem cannot be on an encrypted block device"))
+ errors.extend(self.checkDiskLabel(req)
return errors
- def diskLabelType(self, deviceType):
- """Return the disk label type as a string."""
- return self._diskLabelType
+ def checkBootLoaderRequest(self, req):
+ """ Perform architecture-specific checks on the bootloader device.
- @property
- def isEfi(self):
- return self._isEfi
+ Returns a list of error strings.
+ """
+ return self.checkDiskLabel(req)
@property
def minimumSector(self, disk):
@@ -158,7 +183,7 @@ class Platform(object):
@property
def packages (self):
- return self._packages
+ return self._packages + self.bootloader.packages
def setDefaultPartitioning(self):
"""Return the default platform-specific partitioning information."""
@@ -166,59 +191,36 @@ class Platform(object):
return [PartSpec(mountpoint="/boot", fstype=self.defaultBootFSType, size=500,
weight=self.weight(mountpoint="/boot"))]
- @property
- def supportsLvmBoot(self):
- """Does the platform support /boot on LVM logical volume?"""
- return self._supportsLvmBoot
-
- @property
- def supportsMdRaidBoot(self):
- """Does the platform support /boot on MD RAID?"""
- return self._supportsMdRaidBoot
-
- @property
- def minBootPartSize(self):
- return self._minBootPartSize
-
- @property
- def maxBootPartSize(self):
- return self._maxBootPartSize
-
- def validBootPartSize(self, size):
- """ Is the given size (in MB) acceptable for a boot device? """
+ def validBootLoaderPartSize(self, size):
+ """ Is the given size (in MB) acceptable for a bootloader device? """
if not isinstance(size, int) and not isinstance(size, float):
return False
- return ((not self.minBootPartSize or size >= self.minBootPartSize)
+ return ((self.bootloader.target_device_min_size is None or
+ size >= self.bootloader.target_device_min_size)
and
- (not self.maxBootPartSize or size <= self.maxBootPartSize))
+ (self.bootloader.target_device_max_size is None or
+ size <= self.bootloader.target_device_max_size))
def weight(self, fstype=None, mountpoint=None):
""" Given an fstype (as a string) or a mountpoint, return an integer
for the base sorting weight. This is used to modify the sort
algorithm for partition requests, mainly to make sure bootable
partitions and /boot are placed where they need to be."""
- return 0
-
-class EFI(Platform):
- _bootFSTypes = ["ext4", "ext3", "ext2"]
- _diskLabelType = "gpt"
- _minBootPartSize = 50
- _maxBootPartSize = 256
-
- def bootDevice(self):
- bootDev = None
+ if fstype in self.bootFSTypes and mountpoint == "/boot":
+ return 2000
+ else:
+ return 0
- for part in self.anaconda.storage.partitions:
- if part.format.type == "efi" and self.validBootPartSize(part.size):
- bootDev = part
- # if we're only picking one, it might as well be the first
- break
+class X86(Platform):
+ _bootloaderClass = GRUB
- return bootDev
+class EFI(Platform):
+ _bootloaderClass = EFIGRUB
- def bootloaderChoices(self, bl):
- bootDev = self.bootDevice()
+ @property
+ def bootloaderChoices(self):
+ bootDev = self.bootloaderDevice
ret = {}
if not bootDev:
@@ -227,40 +229,20 @@ class EFI(Platform):
ret["boot"] = (bootDev.name, N_("EFI System Partition"))
return ret
- def checkBootRequest(self, req):
- """ Perform architecture-specific checks on the boot device.
+ def checkBootLoaderRequest(self, req):
+ """ Perform architecture-specific checks on the bootloader device.
Returns a list of error strings.
-
- NOTE: X86 does not have a separate checkBootRequest method,
- so this one must work for x86 as well as EFI.
"""
if not req:
return [_("You have not created a /boot/efi partition.")]
- errors = Platform.checkBootRequest(self, req)
-
- if req.format.mountpoint == "/boot/efi":
- if req.format.type != "efi":
- errors.append(_("/boot/efi is not EFI."))
+ errors = []
- # Don't try to check the disklabel on lv's etc, using lv for /boot
- # is already checked in the generic Platform.checkBootRequest()
- partitions = []
- if req.type == "partition":
- partitions = [ req ]
- elif req.type == "mdarray":
- partitions = filter(lambda d: d.type == "partition", req.parents)
-
- # Check that we've got a correct disk label.
- for p in partitions:
- partedDisk = p.disk.format.partedDisk
- labelType = self.diskLabelType(partedDisk.device.type)
- # Allow using gpt with x86, but not msdos with EFI
- if partedDisk.type != labelType and partedDisk.type != "gpt":
- errors.append(_("%s must have a %s disk label.")
- % (p.disk.name, labelType.upper()))
+ if req.format.type != "efi":
+ errors.append(_("/boot/efi is not EFI."))
+ errors.extend(Platform.checkBootLoaderRequest(self))
return errors
def setDefaultPartitioning(self):
@@ -271,31 +253,26 @@ class EFI(Platform):
return ret
def weight(self, fstype=None, mountpoint=None):
- if fstype and fstype == "efi" or mountpoint and mountpoint == "/boot/efi":
+ score = Platform.weight(self, fstype=fstype, mountpoint=mountpoint)
+ if score:
+ return score
+ elif fstype and fstype == "efi" or mountpoint and mountpoint == "/boot/efi":
return 5000
- elif mountpoint and mountpoint == "/boot":
- return 2000
else:
return 0
class Alpha(Platform):
- _diskLabelType = "bsd"
+ _bootloaderClass = "aboot"
- def checkBootRequest(self, req):
- errors = Platform.checkBootRequest(self, req)
+ def checkBootLoaderRequest(self, req):
+ errors = Platform.checkBootLoaderRequest(self, req)
if not req or req.type != "partition" or not req.disk:
return errors
- disk = req.disk.format.partedDisk
-
- # Check that we're a BSD disk label
- if not disk.type == self._diskLabelType:
- errors.append(_("%s must have a bsd disk label.") % req.disk.name)
-
# The first free space should start at the beginning of the drive and
# span for a megabyte or more.
- free = disk.getFirstPartition()
+ free = disk.format.firstPartition
while free:
if free.type & parted.PARTITION_FREESPACE:
break
@@ -307,74 +284,46 @@ class Alpha(Platform):
return errors
-class IA64(EFI):
- _packages = ["elilo"]
-
- def __init__(self, anaconda):
- EFI.__init__(self, anaconda)
-
class PPC(Platform):
- _bootFSTypes = ["ext4", "ext3", "ext2"]
- _packages = ["yaboot"]
+ _bootloaderClass = Yaboot
+ _packages = []
_ppcMachine = iutil.getPPCMachine()
- _supportsMdRaidBoot = True
@property
def ppcMachine(self):
return self._ppcMachine
class IPSeriesPPC(PPC):
- _minBootPartSize = 4
- _maxBootPartSize = 10
-
- def bootDevice(self):
- bootDev = None
-
- # We want the first PReP partition.
- for device in self.anaconda.storage.partitions:
- if device.format.type == "prepboot":
- bootDev = device
- break
-
- return bootDev
+ _bootloaderClass = IPSeriesYaboot
- def bootloaderChoices(self, bl):
+ @property
+ def bootloaderChoices(self):
ret = {}
- bootDev = self.bootDevice()
+ bootDev = self.bootDevice
if not bootDev:
return ret
if bootDev.type == "mdarray":
ret["boot"] = (bootDev.name, N_("RAID Device"))
- ret["mbr"] = (bl.drivelist[0], N_("Master Boot Record (MBR)"))
+ ret["mbr"] = (self.bootloader.drives[0].name,
+ N_("Master Boot Record (MBR)"))
else:
- ret["boot"] = (bootDev.name, N_("PPC PReP Boot"))
+ ret["boot"] = (self.bootloaderDevice.name, N_("PPC PReP Boot"))
return ret
- def checkBootRequest(self, req):
- errors = PPC.checkBootRequest(self, req)
+ def checkBootLoaderRequest(self, req):
+ errors = PPC.checkBootLoaderRequest(self, req)
bootPart = getattr(req, "partedPartition", None)
if not bootPart:
return errors
- # All of the above just checks the PPC PReP boot partitions. We still
- # need to make sure that whatever /boot is on also meets these criteria.
- if req == self.bootDevice():
- # However, this check only applies to prepboot.
- if bootPart.geometry.end * bootPart.geometry.device.sectorSize / (1024.0 * 1024) > 4096:
- errors.append(_("The boot partition must be within the first 4MB of the disk."))
+ if bootPart.geometry.end * bootPart.geometry.device.sectorSize / (1024.0 * 1024) > 10:
+ errors.append(_("The boot partition must be within the first 10MB of the disk."))
- try:
- req = self.anaconda.storage.mountpoints["/boot"]
- except KeyError:
- req = self.anaconda.storage.rootDevice
-
- return errors + self.checkBootRequest(req)
- else:
- return errors
+ return errors
def setDefaultPartitioning(self):
from storage.partspec import PartSpec
@@ -384,70 +333,44 @@ class IPSeriesPPC(PPC):
return ret
def weight(self, fstype=None, mountpoint=None):
- if fstype and fstype == "prepboot":
+ score = Platform.weight(self, fstype=fstype, mountpoint=mountpoint)
+ if score:
+ return score
+ elif fstype and fstype == "prepboot":
return 5000
- elif mountpoint and mountpoint == "/boot":
- return 2000
else:
return 0
class NewWorldPPC(PPC):
- _diskLabelType = "mac"
- _minBootPartSize = (800.00 / 1024.00)
- _maxBootPartSize = 1
-
- def bootDevice(self):
- bootDev = None
+ _bootloaderClass = MacYaboot
- for part in self.anaconda.storage.partitions:
- if part.format.type == "appleboot" and self.validBootPartSize(part.size):
- bootDev = part
- # if we're only picking one, it might as well be the first
- break
-
- return bootDev
-
- def bootloaderChoices(self, bl):
+ @property
+ def bootloaderChoices(self):
ret = {}
- bootDev = self.bootDevice()
+ bootDev = self.bootDevice
if not bootDev:
return ret
if bootDev.type == "mdarray":
ret["boot"] = (bootDev.name, N_("RAID Device"))
- ret["mbr"] = (bl.drivelist[0], N_("Master Boot Record (MBR)"))
+ ret["mbr"] = (self.bootloader.drives[0].name,
+ N_("Master Boot Record (MBR)"))
else:
- ret["boot"] = (bootDev.name, N_("Apple Bootstrap"))
- for (n, device) in enumerate(self.anaconda.storage.partitions):
- if device.format.type == "appleboot" and device.path != bootDev.path:
- ret["boot%d" % n] = (device.path, N_("Apple Bootstrap"))
+ ret["boot"] = (self.bootloaderDevice.name, N_("Apple Bootstrap"))
+ for (n, device) in enumerate(self.bootloader.target_devices):
+ if device != self.bootloaderDevice:
+ ret["boot%d" % n] = (device.name, N_("Apple Bootstrap"))
return ret
- def checkBootRequest(self, req):
- errors = PPC.checkBootRequest(self, req)
+ def checkBootLoaderRequest(self, req):
+ errors = PPC.checkBootLoaderRequest(self, req)
if not req or req.type != "partition" or not req.disk:
return errors
- disk = req.disk.format.partedDisk
-
- # Check that we're a Mac disk label
- if not disk.type == self._diskLabelType:
- errors.append(_("%s must have a mac disk label.") % req.disk.name)
-
- # All of the above just checks the appleboot partitions. We still
- # need to make sure that whatever /boot is on also meets these criteria.
- if req == self.bootDevice():
- try:
- req = self.anaconda.storage.mountpoints["/boot"]
- except KeyError:
- req = self.anaconda.storage.rootDevice
-
- return errors + self.checkBootRequest(req)
- else:
- return errors
+ return errors
def setDefaultPartitioning(self):
from storage.partspec import PartSpec
@@ -457,34 +380,25 @@ class NewWorldPPC(PPC):
return ret
def weight(self, fstype=None, mountpoint=None):
- if fstype and fstype == "appleboot":
+ score = Platform.weight(self, fstype=fstype, mountpoint=mountpoint)
+ if score:
+ return score
+ elif fstype and fstype == "appleboot":
return 5000
- elif mountpoint and mountpoint == "/boot":
- return 2000
else:
return 0
class PS3(PPC):
- _diskLabelType = "msdos"
-
def __init__(self, anaconda):
PPC.__init__(self, anaconda)
class S390(Platform):
- _bootFSTypes = ["ext4", "ext3", "ext2"]
+ _bootloaderClass = ZIPL
_packages = ["s390utils"]
- _supportsLvmBoot = True
def __init__(self, anaconda):
Platform.__init__(self, anaconda)
- def diskLabelType(self, deviceType):
- """Return the disk label type as a string."""
- if deviceType == parted.DEVICE_DASD:
- return "dasd"
- else:
- return Platform.diskLabelType(self, deviceType)
-
def setDefaultPartitioning(self):
"""Return the default platform-specific partitioning information."""
from storage.partspec import PartSpec
@@ -492,15 +406,8 @@ class S390(Platform):
weight=self.weight(mountpoint="/boot"), asVol=True,
singlePV=True)]
- def weight(self, fstype=None, mountpoint=None):
- if mountpoint and mountpoint == "/boot":
- return 5000
- else:
- return 0
-
class Sparc(Platform):
- _diskLabelType = "sun"
- _packages = ["silo"]
+ _bootloaderClass = SILO
@property
def minimumSector(self, disk):
@@ -509,72 +416,12 @@ class Sparc(Platform):
start /= long(1024 / disk.device.sectorSize)
return start+1
-class X86(EFI):
- _bootFSTypes = ["ext4", "ext3", "ext2"]
- _packages = ["grub"]
- _supportsMdRaidBoot = True
-
- def __init__(self, anaconda):
- EFI.__init__(self, anaconda)
-
- if self.isEfi:
- self._diskLabelType = "gpt"
- else:
- self._diskLabelType = "msdos"
-
- def bootDevice(self):
- if self.isEfi:
- return EFI.bootDevice(self)
- else:
- return Platform.bootDevice(self)
-
- def bootloaderChoices(self, bl):
- if self.isEfi:
- return EFI.bootloaderChoices(self, bl)
-
- bootDev = self.bootDevice()
- ret = {}
-
- if not bootDev:
- return {}
-
- if bootDev.type == "mdarray":
- ret["boot"] = (bootDev.name, N_("RAID Device"))
- ret["mbr"] = (bl.drivelist[0], N_("Master Boot Record (MBR)"))
- else:
- ret["boot"] = (bootDev.name, N_("First sector of boot partition"))
- ret["mbr"] = (bl.drivelist[0], N_("Master Boot Record (MBR)"))
-
- return ret
-
- @property
- def maxBootPartSize(self):
- if self.isEfi:
- return EFI._maxBootPartSize
- else:
- return Platform._maxBootPartSize
-
- @property
- def minBootPartSize(self):
- if self.isEfi:
- return EFI._minBootPartSize
- else:
- return Platform._minBootPartSize
-
- def setDefaultPartitioning(self):
- if self.isEfi:
- return EFI.setDefaultPartitioning(self)
- else:
- return Platform.setDefaultPartitioning(self)
-
def getPlatform(anaconda):
"""Check the architecture of the system and return an instance of a
Platform subclass to match. If the architecture could not be determined,
raise an exception."""
if iutil.isAlpha():
return Alpha(anaconda)
- elif iutil.isIA64():
- return IA64(anaconda)
elif iutil.isPPC():
ppcMachine = iutil.getPPCMachine()
@@ -590,6 +437,8 @@ def getPlatform(anaconda):
return S390(anaconda)
elif iutil.isSparc():
return Sparc(anaconda)
+ elif iutil.isEfi():
+ return EFI(anaconda)
elif iutil.isX86():
return X86(anaconda)
else:
diff --git a/pyanaconda/storage/__init__.py b/pyanaconda/storage/__init__.py
index a0cbdfa..f063c0f 100644
--- a/pyanaconda/storage/__init__.py
+++ b/pyanaconda/storage/__init__.py
@@ -375,7 +375,7 @@ class Storage(object):
# now set the boot partition's flag
try:
- boot = self.platform.bootDevice()
+ boot = self.platform.bootDevice
if boot.type == "mdarray":
bootDevs = boot.parents
else:
@@ -1055,7 +1055,7 @@ class Storage(object):
root = self.fsset.rootDevice
swaps = self.fsset.swapDevices
try:
- boot = self.platform.bootDevice()
+ boot = self.platform.bootDevice
except (DeviceError, AttributeError):
# AttributeError means we have no anaconda or platform. it's ok.
boot = None
diff --git a/pyanaconda/storage/partitioning.py b/pyanaconda/storage/partitioning.py
index e8f3921..d09cfb6 100644
--- a/pyanaconda/storage/partitioning.py
+++ b/pyanaconda/storage/partitioning.py
@@ -849,13 +849,11 @@ def doPartitioning(storage, bootloader=None):
# start over with flexible-size requests
part.req_size = part.req_base_size
- # FIXME: isn't there a better place for this to happen?
try:
- bootDev = storage.platform.bootDevice()
+ bootDev = storage.platform.bootDevice
except DeviceError:
- bootDev = None
-
- if bootDev:
+ pass
+ else:
bootDev.req_bootable = True
removeNewPartitions(disks, partitions)