diff options
author | 2011-06-15 16:59:54 +0000 | |
---|---|---|
committer | 2011-06-15 16:59:54 +0000 | |
commit | 2590d96369d0217e31dc2812690dde61dac417b5 (patch) | |
tree | 82276f787b08a28548e342c7921486f1acefab9f /booty | |
parent | first commit (diff) | |
download | anaconda-2590d96369d0217e31dc2812690dde61dac417b5.tar.gz anaconda-2590d96369d0217e31dc2812690dde61dac417b5.tar.bz2 anaconda-2590d96369d0217e31dc2812690dde61dac417b5.zip |
Initial import from Sabayon (ver 0.9.9.56)
Diffstat (limited to 'booty')
-rw-r--r-- | booty/Makefile.am | 24 | ||||
-rw-r--r-- | booty/__init__.py | 52 | ||||
-rw-r--r-- | booty/alpha.py | 150 | ||||
-rw-r--r-- | booty/bootloaderInfo.py | 694 | ||||
-rw-r--r-- | booty/checkbootloader.py | 207 | ||||
-rw-r--r-- | booty/ia64.py | 38 | ||||
-rw-r--r-- | booty/lilo.py | 308 | ||||
-rw-r--r-- | booty/ppc.py | 180 | ||||
-rw-r--r-- | booty/s390.py | 178 | ||||
-rw-r--r-- | booty/sparc.py | 129 | ||||
-rw-r--r-- | booty/util.py | 33 | ||||
-rw-r--r-- | booty/x86.py | 541 |
12 files changed, 2534 insertions, 0 deletions
diff --git a/booty/Makefile.am b/booty/Makefile.am new file mode 100644 index 0000000..8d03ee0 --- /dev/null +++ b/booty/Makefile.am @@ -0,0 +1,24 @@ +# booty/Makefile.am for anaconda +# +# Copyright (C) 2009 Red Hat, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +# Author: David Cantrell <dcantrell@redhat.com> + +pkgpyexecdir = $(pyexecdir)/py$(PACKAGE_NAME) +bootydir = $(pkgpyexecdir)/booty +booty_PYTHON = *.py + +MAINTAINERCLEANFILES = Makefile.in diff --git a/booty/__init__.py b/booty/__init__.py new file mode 100644 index 0000000..b54e194 --- /dev/null +++ b/booty/__init__.py @@ -0,0 +1,52 @@ +# +# bootloader.py - generic boot loader handling backend for up2date and anaconda +# +# Jeremy Katz <katzj@redhat.com> +# Adrian Likins <alikins@redhat.com> +# Peter Jones <pjones@redhat.com> +# +# 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""" + +import iutil +from bootloaderInfo import * +from 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/booty/alpha.py b/booty/alpha.py new file mode 100644 index 0000000..0ed0b8a --- /dev/null +++ b/booty/alpha.py @@ -0,0 +1,150 @@ +import os +import iutil + +from booty import BootyNoKernelWarning +from bootloaderInfo import * +from util import getDiskPart + +class alphaBootloaderInfo(bootloaderInfo): + def wholeDevice (self, path): + (device, foo) = getDiskPart(path, self.storage) + return device + + def partitionNum (self, path): + # getDiskPart returns part numbers 0-based; we need it one based + # *sigh* + (foo, partitionNumber) = getDiskPart(path, self.storage) + return partitionNumber + 1 + + 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 = self.partitionNum(bootDevice.path) + lines = 0 + + # We write entries line using the following format: + # <line><bpn><kernel-name> root=<rootdev> [options] + # We get all the kernels we need to know about in kernelList. + + for (kernel, tag, version) in kernelList: + kernelTag = "-" + version + kernelFile = "%svmlinuz%s" %(kernelPath, kernelTag) + + f.write("%d:%d%s" %(lines, bpn, kernelFile)) + + # See if we can come up with an initrd argument that exists + initrd = self.makeInitrd(kernelTag, instRoot) + if initrd: + f.write(" initrd=%s%s" %(kernelPath, initrd)) + + realroot = rootDevice.fstabSpec + f.write(" root=%s" %(realroot,)) + + args = self.args.get() + if args: + f.write(" %s" %(args,)) + + f.write("\n") + lines = lines + 1 + + # We're done writing the file + f.close () + del f + + # Now we're ready to write the relevant boot information. wbd + # is the whole boot device, bdpn is the boot device partition + # number. + wbd = self.wholeDevice (bootDevice.path) + bdpn = self.partitionNum (bootDevice.path) + + # 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/booty/bootloaderInfo.py b/booty/bootloaderInfo.py new file mode 100644 index 0000000..610195f --- /dev/null +++ b/booty/bootloaderInfo.py @@ -0,0 +1,694 @@ +# +# bootloaderInfo.py - bootloader config object used in creation of new +# bootloader configs. Originally from anaconda +# +# Jeremy Katz <katzj@redhat.com> +# Erik Troan <ewt@redhat.com> +# Peter Jones <pjones@redhat.com> +# +# 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 flags import flags +import iutil +import isys +from product import * + +import 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) + + 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 ] + + 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 ] + + 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 = [] + cfgFilename = "/tmp/install.cfg" + + self.anaconda = anaconda + + if iutil.isS390(): + self.cargs = [] + f = open(cfgFilename) + for line in f: + try: + (vname,vparm) = line.split('=', 1) + vname = vname.strip() + vparm = vparm.replace('"','') + vparm = vparm.strip() + if vname == "CHANDEV": + self.cargs.append(vparm) + if vname == "QETHPARM": + self.cargs.append(vparm) + except Exception, e: + pass + f.close() + + # 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"] + + 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". + def availableBootDevices(self, storage): + 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 + + type = part.format.type + + if type in dosFilesystems and not foundDos and doesDualBoot(): + try: + bootable = checkForBootBlock(part.path) + retval.append((part, type)) + foundDos = True + except: + pass + elif type in ["ntfs", "hpfs"] and not foundDos and doesDualBoot(): + retval.append((part, type)) + # maybe questionable, but the first ntfs or fat is likely to + # be the correct one to boot with XP using ntfs + foundDos = True + elif type == "appleboot" and iutil.getPPCMachine() == "PMac" and part.bootable: + foundAppleBootstrap = True + elif type in ["hfs", "hfs+"] and foundAppleBootstrap: + # questionable for same reason as above, but on mac this time + retval.append((part, type)) + + 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(device, self.storage) + 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, 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 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: + 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 + + # 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: + options = "" + device = "" + console = flags.cmdline.get("console", "") + + # the options are everything after the comma + comma = console.find(",") + if comma != -1: + options = console[comma:] + device = console[:comma] + else: + device = console + + if not device and iutil.isIA64(): + self.serialDevice = "ttyS0" + self.serialOptions = "" + else: + self.serialDevice = device + # don't keep the comma in the options + self.serialOptions = options[1:] + + if self.serialDevice: + self.args.append("console=%s%s" %(self.serialDevice, options)) + self.serial = 1 + self.timeout = 5 + else: + self.serial = 0 + self.serialDevice = None + self.serialOptions = None + + 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('/usr/sbin/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('/usr/sbin/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: + 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 = [ "/usr/sbin/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 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 + + 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/booty/checkbootloader.py b/booty/checkbootloader.py new file mode 100644 index 0000000..1b1ca1d --- /dev/null +++ b/booty/checkbootloader.py @@ -0,0 +1,207 @@ +#!/usr/bin/python +# +# Check to see whether it looks like GRUB or LILO is the boot loader +# being used on the system. +# +# Jeremy Katz <katzj@redhat.com> +# Peter Jones <pjones@redhat.com> +# +# 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 +import iutil + +grubConfigFile = "/etc/grub.conf" +liloConfigFile = "/etc/lilo.conf" +yabootConfigFile = "/etc/yaboot.conf" +siloConfigFile = "/etc/silo.conf" + +def getRaidDisks(raidDevice, storage, raidLevel=None, stripPart=1): + rc = [] + if raidLevel is not None: + try: + raidLevel = "raid%d" % (int(raidLevel),) + except ValueError: + pass + + try: + f = open("/proc/mdstat", "r") + lines = f.readlines() + f.close() + except: + return rc + + for line in lines: + fields = string.split(line, ' ') + if fields[0] == raidDevice: + if raidLevel is not None and fields[3] != raidLevel: + continue + for field in fields[4:]: + if string.find(field, "[") == -1: + continue + dev = string.split(field, '[')[0] + if len(dev) == 0: + continue + if stripPart: + disk = getDiskPart(dev, storage)[0] + rc.append(disk) + else: + rc.append(dev) + + return rc + + +def getBootBlock(bootDev, instRoot, storage, seekBlocks=0): + """Get the boot block from bootDev. Return a 512 byte string.""" + block = " " * 512 + if bootDev is None: + return block + + # get the devices in the raid device + if bootDev[5:7] == "md": + bootDevs = getRaidDisks(bootDev[5:], storage) + bootDevs.sort() + else: + bootDevs = [ bootDev[5:] ] + + # FIXME: this is kind of a hack + # look at all of the devs in the raid device until we can read the + # boot block for one of them. should do this better at some point + # by looking at all of the drives properly + for dev in bootDevs: + try: + fd = os.open("%s/dev/%s" % (instRoot, dev), os.O_RDONLY) + if seekBlocks > 0: + os.lseek(fd, seekBlocks * 512, 0) + block = os.read(fd, 512) + os.close(fd) + return block + 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 + + 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 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, storage) + # 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, storage) + # 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. + if getDiskPart(bootDev, storage)[1] != 3: + block = getBootBlock(bootDev, instRoot, storage, 1) + if block[24:28] == "SILO": + return ("SILO", bootDev) + + return (None, None) diff --git a/booty/ia64.py b/booty/ia64.py new file mode 100644 index 0000000..f0f0146 --- /dev/null +++ b/booty/ia64.py @@ -0,0 +1,38 @@ +from 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/booty/lilo.py b/booty/lilo.py new file mode 100644 index 0000000..dc2328e --- /dev/null +++ b/booty/lilo.py @@ -0,0 +1,308 @@ +#!/usr/bin/python +# +# Module for manipulation of lilo.conf files. Original found +# in the anaconda installer +# Copyright (c) 1999-2001 Red Hat, Inc. Distributed under GPL. +# +# Author: Matt Wilson <msw@redhat.com> +# Eric Troan <ewt@redhat.com> +# Adrian Likins <alikins@redhat.com> +"""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/booty/ppc.py b/booty/ppc.py new file mode 100644 index 0000000..a640344 --- /dev/null +++ b/booty/ppc.py @@ -0,0 +1,180 @@ +import string +import os + +from booty import BootyNoKernelWarning +from util import getDiskPart +from bootloaderInfo import * +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" + + f = open(instRoot + cf, "w+") + + f.write("# yaboot.conf generated by anaconda\n\n") + f.write("boot=%s\n" %(yabootTarget,)) + f.write("init-message=\"Welcome to %s!\\nHit <TAB> for boot options\"\n\n" + % productName) + + f.write("partition=%s\n" % bootDev.partedPartition.number) + 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 + 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/booty/s390.py b/booty/s390.py new file mode 100644 index 0000000..1a4c9f3 --- /dev/null +++ b/booty/s390.py @@ -0,0 +1,178 @@ +import os + +from bootloaderInfo import * +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, 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') + 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.execWithRedirect("/sbin/zipl", [], root = instRoot, + stdout = "/dev/stdout", + stderr = "/dev/stderr") + if rc: + return rc + + 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/booty/sparc.py b/booty/sparc.py new file mode 100644 index 0000000..1cb790d --- /dev/null +++ b/booty/sparc.py @@ -0,0 +1,129 @@ +import string +import os + +from booty import BootyNoKernelWarning +from util import getDiskPart +from bootloaderInfo import * +import iutil + +class sparcBootloaderInfo(bootloaderInfo): + def writeSilo(self, instRoot, bl, kernelList, + chainList, defaultDev): + + try: + bootDev = self.storage.mountpoints["/boot"] + + mf = '/silo.message' + cf = "/boot/silo.conf" + mfdir = '/boot' + cfPath = "" + if not os.path.isdir(instRoot + "/boot"): + os.mkdir(instRoot + "/boot") + except KeyError: + bootDev = self.storage.rootDevice + + cf = "/etc/silo.conf" + mfdir = '/etc' + cfPath = "/boot" + + f = open(instRoot + mfdir + mf, "w+") + f.write("Welcome to %s!\nHit <TAB> for boot options\n\n" % productName) + f.close() + os.chmod(instRoot + mfdir + mf, 0600) + + f = open(instRoot + cf, "w+") + f.write("# silo.conf generated by anaconda\n\n") + + f.write("#boot=%s\n" % (bootDev.path,)) + f.write("message=%s\n" % (mf,)) + f.write("timeout=%s\n" % (self.timeout or 50)) + + (name, partNum) = getDiskPart(bootDev.name, self.storage) + partno = partNum + 1 + f.write("partition=%s\n" % (partno,)) + + 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 + 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/booty/util.py b/booty/util.py new file mode 100644 index 0000000..48c3194 --- /dev/null +++ b/booty/util.py @@ -0,0 +1,33 @@ +import string +from flags import flags + +def getDiskPart(dev, storage): + path = storage.devicetree.getDeviceByName(dev).path[5:] + cut = len(dev) + if dev[-1] in string.digits: + if (path.startswith('rd/') or path.startswith('ida/') or + path.startswith('cciss/') or path.startswith('sx8/') or + path.startswith('mapper/') or path.startswith('mmcblk') or + path.startswith('md')): + if dev[-2] == 'p': + cut = -2 + elif dev[-3] == 'p' and dev[-2] in string.digits: + cut = -3 + else: + if dev[-2] in string.digits: + cut = -2 + else: + cut = -1 + + name = dev[:cut] + + if cut < 0: + part = dev[cut:] + if part[0] == 'p': + part = part[1:] + partNum = int(part) - 1 + else: + partNum = None + + return (name, partNum) + diff --git a/booty/x86.py b/booty/x86.py new file mode 100644 index 0000000..14bd641 --- /dev/null +++ b/booty/x86.py @@ -0,0 +1,541 @@ +import os +import string + +from booty import BootyNoKernelWarning +from util import getDiskPart +from bootloaderInfo import * +from flags import flags +import checkbootloader +import iutil + +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 = "$1$" + saltLen = 8 + + saltchars = string.letters + string.digits + './' + for i in range(saltLen): + salt += random.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, device): + # 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"). Volume groups/logical volumes are not accepted. + dev = self.storage.devicetree.getDeviceByName(device) + path = dev.path[5:] + + if device in map (lambda x: x.name, self.storage.lvs + self.storage.vgs): + return [] + + if path.startswith("mapper/luks-"): + return [] + + if dev.type == "mdarray": + bootable = 0 + parts = checkbootloader.getRaidDisks(device, self.storage, + raidLevel=1, stripPart=0) + parts.sort() + return parts + + return [device] + + 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, self.storage)[0] == getDiskPart(mdBootPart, self.storage)[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, self.storage)[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(grubTarget) + bootDevs = self.getPhysicalDevices(bootDev.name) + + 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, self.storage)[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, self.storage)[0] + # It can happen due to ks --driveorder option, but is it ok? + if not mdMemberBootDisk in self.drivelist: + continue + mdRaidDeviceRemap = (firstMdMemberDiskGrubbyName, + mdMemberBootDisk) + + 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: + 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(grubTarget)) + usedDevs.update(self.getPhysicalDevices(rootDev.name)) + usedDevs.update(self.getPhysicalDevices(bootDev.name)) + usedDevs.update([dev for (label, longlabel, dev) in chainList if longlabel]) + + if not upgrade: + self.writeDeviceMap(instRoot, usedDevs, upgrade) + self.writeSysconfig(instRoot, grubTarget, upgrade) + + return self.installGrub(instRoot, bootDev, grubTarget, grubPath, cfPath) + + def writeGrubConf(self, instRoot, bootDev, rootDev, defaultDev, kernelList, + chainList, grubTarget, grubPath, cfPath): + + bootDevs = self.getPhysicalDevices(bootDev.name) + + # 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)) + + # 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)) + f.write('timeout=%d\n' % (self.timeout or 0)) + + if self.serial == 1: + # 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: + # 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 --md5 %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(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(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, self.storage)[0] + usedDiskDevs.add(drive) + devs = list(usedDiskDevs) + devs.sort() + for drive in devs: + # XXX hack city. If they're not the sort of thing that'll + # be in the device map, they shouldn't still be in the list. + dev = self.storage.devicetree.getDeviceByName(drive) + if not dev.type == "mdarray": + f.write("(%s) %s\n" % (self.grubbyDiskName(drive), 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, name): + return "hd%d" % self.drivelist.index(name) + + def grubbyPartitionName(self, dev): + (name, partNum) = getDiskPart(dev, self.storage) + if partNum != None: + return "(%s,%d)" % (self.grubbyDiskName(name), partNum) + else: + return "(%s)" %(self.grubbyDiskName(name)) + + + 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("--md5pass=%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 |