aboutsummaryrefslogtreecommitdiff
path: root/booty
diff options
context:
space:
mode:
authorwiktor w brodlo <wiktor@brodlo.net>2011-06-15 16:59:54 +0000
committerwiktor w brodlo <wiktor@brodlo.net>2011-06-15 16:59:54 +0000
commit2590d96369d0217e31dc2812690dde61dac417b5 (patch)
tree82276f787b08a28548e342c7921486f1acefab9f /booty
parentfirst commit (diff)
downloadanaconda-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.am24
-rw-r--r--booty/__init__.py52
-rw-r--r--booty/alpha.py150
-rw-r--r--booty/bootloaderInfo.py694
-rw-r--r--booty/checkbootloader.py207
-rw-r--r--booty/ia64.py38
-rw-r--r--booty/lilo.py308
-rw-r--r--booty/ppc.py180
-rw-r--r--booty/s390.py178
-rw-r--r--booty/sparc.py129
-rw-r--r--booty/util.py33
-rw-r--r--booty/x86.py541
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