700 lines
23 KiB
Python
700 lines
23 KiB
Python
|
#
|
||
|
# 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 ]
|
||
|
|
||
|
if self.anaconda.storage.fsset.swapDevices:
|
||
|
neededDevs.append(self.anaconda.storage.fsset.swapDevices[0])
|
||
|
|
||
|
for s in bootArgs + \
|
||
|
self.getDracutStorageArgs(neededDevs) + [
|
||
|
self.anaconda.instLanguage.dracutSetupString(),
|
||
|
self.anaconda.keyboard.dracutSetupString(),
|
||
|
self.args,
|
||
|
self.appendArgs ]:
|
||
|
s = s.strip()
|
||
|
if not s:
|
||
|
continue
|
||
|
if args:
|
||
|
args += " "
|
||
|
args += s
|
||
|
|
||
|
return args
|
||
|
|
||
|
def set(self, args):
|
||
|
self.args = args
|
||
|
self.appendArgs = ""
|
||
|
|
||
|
def getNoDracut(self):
|
||
|
args = self.args.strip() + " " + self.appendArgs.strip()
|
||
|
return args.strip()
|
||
|
|
||
|
def chandevget(self):
|
||
|
return self.cargs
|
||
|
|
||
|
def chandevset(self, args):
|
||
|
self.cargs = args
|
||
|
|
||
|
def append(self, args):
|
||
|
# don't duplicate the addition of an argument (#128492)
|
||
|
if self.args.find(args) != -1:
|
||
|
return
|
||
|
if self.appendArgs.find(args) != -1:
|
||
|
return
|
||
|
|
||
|
if self.appendArgs:
|
||
|
self.appendArgs += " "
|
||
|
|
||
|
self.appendArgs += args
|
||
|
|
||
|
def __init__(self, anaconda):
|
||
|
newArgs = []
|
||
|
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() and \
|
||
|
not part.getFlag(parted.PARTITION_DIAG):
|
||
|
try:
|
||
|
bootable = checkForBootBlock(part.path)
|
||
|
retval.append((part, type))
|
||
|
foundDos = True
|
||
|
except:
|
||
|
pass
|
||
|
elif type in ["ntfs", "hpfs"] and not foundDos and \
|
||
|
doesDualBoot() and not part.getFlag(parted.PARTITION_DIAG):
|
||
|
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 = ""
|