When updating device.map during upgrade of grub, I missed case when driveorder
changes between install and upgrade (e.g. when driveorder different from that
detected during upgrade had been specified when isntalling) in my previous
patch. To fix it, I generate device.map in similar way as when installing (only
updating it with some devices that we can know about only from updated
device.map - e.g. chainloaded devices). This brought me to another
consolidation of the code (started in previous grub installation patches):
* remove updateGrub, use writeGrub with upgrade flag instead
* move code from writeGrub into separate methods
writeGrubConf (called only for grub (re)install)
writeSysconfig (called both for grub (re)install and upgrade)
writeDeviceMap (called both for grub (re)install and upgrade)
* remove old writeSysconfig and updateDeviceMap that were called
only from upgradeGrub, use new writeSysconfig and writeDeviceMap
with upgrade flag instead.
---
booty/x86.py | 164 ++++++++++++++++++++++-----------------------------------
1 files changed, 63 insertions(+), 101 deletions(-)
diff --git a/booty/x86.py b/booty/x86.py
index 9106bb0..40ec7f2 100644
--- a/booty/x86.py
+++ b/booty/x86.py
@@ -200,9 +200,44 @@ class x86BootloaderInfo(efiBootloaderInfo):
return self.runGrubInstall(instRoot, bootDev.name, cmds, cfPath)
def writeGrub(self, instRoot, bl, kernelList, chainList,
- defaultDev, justConfigFile):
+ defaultDev, justConfigFile, 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 justConfigFile or not upgrade:
+ self.writeDeviceMap(instRoot, usedDevs, upgrade)
+ self.writeSysconfig(instRoot, grubTarget, upgrade)
+
+ if not justConfigFile:
+ return self.installGrub(instRoot, bootDev, grubTarget, grubPath, cfPath)
+
+ return 0
+
+ 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
@@ -212,8 +247,6 @@ class x86BootloaderInfo(efiBootloaderInfo):
self.perms = os.stat(cf)[0]& 0777
os.rename(cf, cf + '.rpmsave')
- grubTarget = bl.getDevice()
-
f = open(cf, "w+")
f.write("# grub.conf generated by anaconda\n")
@@ -221,24 +254,16 @@ class x86BootloaderInfo(efiBootloaderInfo):
f.write("# Note that you do not have to rerun grub "
"after making changes to this file\n")
- try:
- bootDev = self.storage.mountpoints["/boot"]
- grubPath = "/grub"
- cfPath = "/"
+ 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")
- except KeyError:
- bootDev = rootDev
- grubPath = "/boot/grub"
- cfPath = "/boot/"
+ 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")
-
- bootDevs = self.getPhysicalDevices(bootDev.name)
f.write('# root %s\n' % self.grubbyPartitionName(bootDevs[0]))
f.write("# kernel %svmlinuz-version ro root=%s\n" % (cfPath, rootDev.path))
@@ -254,8 +279,6 @@ class x86BootloaderInfo(efiBootloaderInfo):
# chain list
default = len(kernelList)
- # keep track of which devices are used for the device.map
- usedDevs = {}
f.write('default=%s\n' % (default))
f.write('timeout=%d\n' % (self.timeout or 0))
@@ -285,8 +308,6 @@ class x86BootloaderInfo(efiBootloaderInfo):
% (self.grubbyPartitionName(bootDevs[0]), cfPath))
f.write("hiddenmenu\n")
- for dev in self.getPhysicalDevices(grubTarget):
- usedDevs[dev] = 1
if self.password:
f.write('password --md5 %s\n' %(self.password))
@@ -345,7 +366,6 @@ class x86BootloaderInfo(efiBootloaderInfo):
# f.write('\tmakeactive\n')
f.write('\tchainloader +1')
f.write('\n')
- usedDevs[device] = 1
f.close()
@@ -369,24 +389,31 @@ class x86BootloaderInfo(efiBootloaderInfo):
os.symlink(".." + self.configfile, etcgrub)
except:
pass
-
- for dev in self.getPhysicalDevices(rootDev.name) + bootDevs:
- usedDevs[dev] = 1
+
+ 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")
- devs = usedDevs.keys()
- usedDevs = {}
- for dev in devs:
+ usedDiskDevs = set()
+ for dev in usedDevs:
drive = getDiskPart(dev, self.storage)[0]
- if usedDevs.has_key(drive):
- continue
- usedDevs[drive] = 1
- devs = usedDevs.keys()
+ 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
@@ -396,25 +423,25 @@ class x86BootloaderInfo(efiBootloaderInfo):
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()
-
- if not justConfigFile:
- return self.installGrub(instRoot, bootDev, grubTarget, grubPath, cfPath)
-
- return 0
def grubbyDiskName(self, name):
return "hd%d" % self.drivelist.index(name)
@@ -462,72 +489,6 @@ class x86BootloaderInfo(efiBootloaderInfo):
return config
- def updateDeviceMap(self, instRoot):
- if os.access(instRoot + "/boot/grub/device.map", os.R_OK):
- f = open(instRoot + "/boot/grub/device.map", "r")
- updatedlines = []
- update = False
- for line in f:
- line = line.strip()
- if line.startswith('(hd'):
- (grubdisk, path) = line.split()[:2]
- i = int(grubdisk.lstrip('(hd ').rstrip(') '))
- actual_path = self.storage.devicetree.getDeviceByName(self.drivelist[i]).path
- if path != actual_path:
- line = "%s %s" % (grubdisk, actual_path)
- update = True
- updatedlines.append(line)
- f.close()
-
- if update:
- os.rename(instRoot + "/boot/grub/device.map",
- instRoot + "/boot/grub/device.map.rpmsave")
- f = open(instRoot + "/boot/grub/device.map", "w+")
- upd_comment = "# file updated by anaconda\n"
- f.write(upd_comment + '\n'.join(updatedlines) + '\n')
- f.close()
-
- # this is a hackish function that depends on the way anaconda writes
- # out the grub.conf with a #boot= comment
- # XXX this falls into the category of self.doUpgradeOnly
- def upgradeGrub(self, instRoot, bl, kernelList, chainList,
- defaultDev, justConfigFile):
- if justConfigFile:
- return ""
-
- grubTarget = bl.getDevice()
-
- if grubTarget is None:
- return ""
-
- # migrate info to /etc/sysconfig/grub
- self.writeSysconfig(instRoot, grubTarget)
-
- # update device.map
- self.updateDeviceMap(instRoot)
-
- # more suckage. grub-install can't work without a valid /etc/mtab
- # so we have to do shenanigans to get updated grub installed...
- # steal some more code above
- try:
- bootDev = self.storage.mountpoints["/boot"]
- grubPath = "/grub"
- cfPath = "/"
- except KeyError:
- bootDev = self.storage.rootDevice
- grubPath = "/boot/grub"
- cfPath = "/boot/"
-
- return self.installGrub(instRoot, bootDev, grubTarget, grubPath, cfPath)
-
- def writeSysconfig(self, instRoot, installDev):
- sysconf = '/etc/sysconfig/grub'
- if not os.access(instRoot + sysconf, os.R_OK):
- f = open(instRoot + sysconf, "w+")
- f.write("boot=%s\n" %(installDev,))
- f.write("forcelba=0\n")
- f.close()
-
def write(self, instRoot, bl, kernelList, chainList,
defaultDev, justConfig):
if self.timeout is None and chainList:
@@ -536,8 +497,9 @@ class x86BootloaderInfo(efiBootloaderInfo):
# XXX HACK ALERT - see declaration above
if self.doUpgradeOnly:
if self.useGrubVal:
- return self.upgradeGrub(instRoot, bl, kernelList,
- chainList, defaultDev, justConfig)
+ return self.writeGrub(instRoot, bl, kernelList,
+ chainList, defaultDev, justConfig,
+ upgrade = True)
return 0
if len(kernelList)< 1: