# # bootloaderInfo.py - bootloader config object used in creation of new # bootloader configs. Originally from anaconda # # Jeremy Katz # Erik Troan # # Copyright 2002 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 whrandom import butil import string from lilo import LiloConfigFile from rhpl.log import log from rhpl.translate import _, N_ import rhpl.executil import booty import checkbootloader dosFilesystems = ('FAT', 'fat16', 'fat32', 'ntfs', 'hpfs') if os.path.exists('edd'): sys.path.append('edd/') else: sys.path.append('/usr/lib/bootloader') if butil.getArch() == "i386": import edd def doesDualBoot(): if butil.getArch() == "i386" or butil.getArch() == "x86_64": return 1 return 0 # 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 = "/"): import isys, fsset isys.sync() isys.sync() isys.sync() # and xfs is even more "special" (#117968) if fsset.isValidXFS(dev): rhpl.executil.execWithRedirect( "/usr/sbin/xfs_freeze", ["/usr/sbin/xfs_freeze", "-f", mntpt], stdout = "/dev/tty5", stderr = "/dev/tty5", root = instRoot) rhpl.executil.execWithRedirect( "/usr/sbin/xfs_freeze", ["/usr/sbin/xfs_freeze", "-u", mntpt], stdout = "/dev/tty5", stderr = "/dev/tty5", root = instRoot) class BootyNoKernelWarning: def __init__ (self, value=""): self.value = value def __str__ (self): return self.value class KernelArguments: def get(self): return self.args def set(self, args): self.args = args def chandevget(self): return self.cargs def chandevset(self, args): self.cargs = args def append(self, args): if self.args: # don't duplicate the addition of an argument (#128492) if self.args.find(args) != -1: return self.args = self.args + " " self.args = self.args + "%s" % (args,) def __init__(self): str = "" if butil.getArch() == "s390": self.cargs = [] f = open("/tmp/install.cfg") lines = f.readlines() for line in lines: try: (vname,vparm) = line.split('=', 1) vname = vname.strip() vparm = vparm.replace('"','') vparm = vparm.strip() if vname == "DASD": str = str + "dasd=" + vparm if vname == "CHANDEV": self.cargs.append(vparm) if vname == "QETHPARM": self.cargs.append(vparm) except Exception, e: pass # look for kernel arguments we know should be preserved and add them ourargs = ["speakup_synth=", "apic", "noapic", "apm=", "ide=nodma", "noht", "acpi=", "video="] f = open("/proc/cmdline") cmdline = f.read()[:-1] f.close() cmdlineargs = cmdline.split(" ") for arg in cmdlineargs: for check in ourargs: if arg.startswith(check): if str: str = str + " " str = str + arg self.args = str class BootImages: # returns dictionary of (label, longlabel, devtype) pairs indexed by device def getImages(self): # return a copy so users can modify it w/o affecting us dict = {} for key in self.images.keys(): dict[key] = self.images[key] return dict def setImageLabel(self, dev, label, setLong = 0): if setLong: self.images[dev] = (self.images[dev][0], label, self.images[dev][2]) else: self.images[dev] = (label, self.images[dev][1], self.images[dev][2]) # default is a device def setDefault(self, default): self.default = default def getDefault(self): return self.default # XXX this has internal anaconda-ish knowledge. ick def setup(self, diskSet, fsset): devices = {} devs = self.availableBootDevices(diskSet, fsset) for (dev, type) in devs: devices[dev] = 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 devs: if not self.images.has_key(dev): if type in dosFilesystems: self.images[dev] = ("Other", "Other", type) else: self.images[dev] = (None, None, type) if not self.images.has_key(self.default): entry = fsset.getEntryByMountPoint('/') self.default = entry.device.getDevice() (label, longlabel, type) = self.images[self.default] if not label: self.images[self.default] = ("linux", butil.getProductName(), type) # XXX more internal anaconda knowledge def availableBootDevices(self, diskSet, fsset): devs = [] foundDos = 0 for (dev, type) in diskSet.partitionTypes(): if type in dosFilesystems and not foundDos and doesDualBoot(): import isys import partedUtils isys.makeDevInode(dev, '/tmp/' + dev) part = partedUtils.get_partition_by_name(diskSet.disks, dev) if part.native_type not in partedUtils.dosPartitionTypes: continue try: bootable = isys.checkBoot('/tmp/' + dev) devs.append((dev, type)) foundDos = 1 except Exception, e: log("exception checking %s: %s" %(dev, e)) pass elif ((type == 'ntfs' or type =='hpfs') and not foundDos and doesDualBoot()): devs.append((dev, type)) # maybe questionable, but the first ntfs or fat is likely to # be the correct one to boot with XP using ntfs foundDos = 1 elif (type == 'hfs') and butil.getPPCMachine() == "PMac": import isys import partedUtils isys.makeDevInode(dev, '/tmp/' + dev) part = partedUtils.get_partition_by_name(diskSet.disks, dev) if partedUtils.get_flags(part) != "boot": devs.append((dev, type)) slash = fsset.getEntryByMountPoint('/') if not slash or not slash.device or not slash.fsystem: raise ValueError, ("Trying to pick boot devices but do not have a " "sane root partition. Aborting install.") devs.append((slash.device.getDevice(), slash.fsystem.getName())) devs.sort() return devs def __init__(self): self.default = None self.images = {} class bootloaderInfo: def setUseGrub(self, val): pass def useGrub(self): return self.useGrubVal def setForceLBA(self, val): pass 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) if part is None: self.defaultDevice = "mbr" else: self.defaultDevice = "partition" # XXX need to abstract out the requirement for a fsset to be able # to get it "on the fly" on a running system as well as being able # to get it how we do now from anaconda. probably by having the # first thing in the chain create a "fsset" object that has the # dictionary of mounted filesystems since that's what we care about def getBootloaderConfig(self, instRoot, fsset, bl, langs, kernelList, chainList, defaultDev): images = bl.images.getImages() # on upgrade read in the lilo config file lilo = LiloConfigFile () self.perms = 0600 if os.access (instRoot + self.configfile, os.R_OK): self.perms = os.stat(instRoot + self.configfile)[0] & 0777 lilo.read (instRoot + self.configfile) os.rename(instRoot + self.configfile, instRoot + self.configfile + '.rpmsave') # if it's an absolute symlink, just get it out of our way elif (os.path.islink(instRoot + self.configfile) and os.readlink(instRoot + self.configfile)[0] == '/'): os.rename(instRoot + self.configfile, instRoot + self.configfile + '.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", "20", replace = 0) rootDev = fsset.getEntryByMountPoint("/").device.getDevice() if not rootDev: raise RuntimeError, "Installing lilo, but there is no root device" if rootDev == defaultDev: 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 = booty.makeInitrd (kernelTag, instRoot) sl.addEntry("label", label) if os.access (instRoot + initrd, os.R_OK): sl.addEntry("initrd", "%sinitrd%s.img" %(self.kernelLocation, kernelTag)) sl.addEntry("read-only") append = "%s" %(self.args.get(),) realroot = getRootDevName(initrd, fsset, rootDev, instRoot) if not realroot.startswith("LABEL="): sl.addEntry("root", '/dev/' + rootDev) 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, fsset, bl, langs, kernelList, chainList, defaultDev, justConfig, intf = None): if len(kernelList) >= 1: config = self.getBootloaderConfig(instRoot, fsset, bl, langs, kernelList, chainList, defaultDev) config.write(instRoot + self.configfile, perms = self.perms) else: self.noKernelsWarn(intf) return "" # XXX in the future we also should do some validation on the config # file that's already there # XXX concept of the intf isn't very well defined outside of anaconda... # probably should just pass back up an error def noKernelsWarn(self, intf): raise BootyNoKernelWarning def getArgList(self): args = [] if self.defaultDevice is None: args.append("--location=none") return args args.append("--location=%s" % (self.defaultDevice,)) if self.args.get(): args.append("--append=\"%s\"" %(self.args.get())) return args def writeKS(self, f): f.write("bootloader") for arg in self.getArgList(): f.write(" " + arg) f.write("\n") def createDriveList(self): # create a drive list that we can use for drive mappings # XXX has anaconda internals knowledge import isys import flags drives = isys.hardDriveDict().keys() drives.sort (isys.compareDrives) # now filter out all of the removable media unless expert mode rc = [] for drive in drives: if not isys.driveIsRemovable(drive) or flags.flags.expert: rc.append(drive) return rc def __init__(self): self.args = KernelArguments() self.images = BootImages() self.device = None self.useLinear = 1 # only used for kickstart compatibility self.defaultDevice = None # XXX hack, used by kickstart self.useGrubVal = 0 # only used on x86 self.configfile = None self.kernelLocation = "/boot/" self.forceLBA32 = 0 self.password = None self.pure = None self.above1024 = 0 # 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 = self.createDriveList() from flags import flags if flags.serial != 0: # now look at /proc/cmdline to pull any serial console # args f = open("/proc/cmdline", "r") cmdline = f.read()[:-1] f.close() options = "" device = None cmdlineargs = cmdline.split(" ") for arg in cmdlineargs: # found a console argument if arg.startswith("console="): (foo, console) = arg.split("=") # the options are everything after the comma comma = console.find(",") if comma != -1: options = console[comma:] device = console[:comma] else: options = "" device = console if device is None: self.serialDevice = "ttyS0" self.serialOptions = "" else: self.serialDevice = device # don't keep the comma in the options self.serialOptions = options[1:] self.args.append("console=%s%s" %(self.serialDevice, options)) self.serial = 1 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 ia64BootloaderInfo(bootloaderInfo): # XXX wouldn't it be nice to have a real interface to use efibootmgr from? def removeOldEfiEntries(self, instRoot): p = os.pipe() rhpl.executil.execWithRedirect('/usr/sbin/efibootmgr', ["efibootmgr"], root = instRoot, stdout = p[1]) os.close(p[1]) 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:], " ") == butil.getProductName(): entry = fields[0][4:8] rhpl.executil.execWithRedirect('/usr/sbin/efibootmgr', ["efibootmgr", "-b", entry, "-B"], root = instRoot, stdout="/dev/tty5", stderr="/dev/tty5") def getBootloaderConfig(self, instRoot, fsset, bl, langs, kernelList, chainList, defaultDev): config = bootloaderInfo.getBootloaderConfig(self, instRoot, fsset, bl, langs, kernelList, chainList, defaultDev) # altix boxes need relocatable (#120851) config.addEntry("relocatable") return config def writeLilo(self, instRoot, fsset, bl, langs, kernelList, chainList, defaultDev, justConfig): config = self.getBootloaderConfig(instRoot, fsset, bl, langs, kernelList, chainList, defaultDev) config.write(instRoot + self.configfile, perms = self.perms) return "" def write(self, instRoot, fsset, bl, langs, kernelList, chainList, defaultDev, justConfig, intf): if len(kernelList) >= 1: str = self.writeLilo(instRoot, fsset, bl, langs, kernelList, chainList, defaultDev, justConfig) else: self.noKernelsWarn(intf) bootdev = fsset.getEntryByMountPoint("/boot/efi").device.getDevice() if not bootdev: bootdev = fsset.getEntryByDeviceName("sda1").device.getDevice() if not os.access(instRoot + "/etc/elilo.conf", os.R_OK): os.symlink("../" + self.configfile, instRoot + "/etc/elilo.conf") 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/')): bootdisk = bootdisk[:-1] self.removeOldEfiEntries(instRoot) argv = [ "/usr/sbin/efibootmgr", "-c" , "-w", "-L", butil.getProductName(), "-d", "/dev/%s" % bootdisk, "-p", bootpart, "-l", "EFI\\redhat\\elilo.efi" ] rhpl.executil.execWithRedirect(argv[0], argv, root = instRoot, stdout = "/dev/tty5", stderr = "/dev/tty5") def __init__(self): bootloaderInfo.__init__(self) self.useGrubVal = 1 self.kernelLocation = "" self.configfile = "/boot/efi/EFI/redhat/elilo.conf" class x86BootloaderInfo(bootloaderInfo): def setPassword(self, val, isCrypted = 1): if not val: self.password = val self.pure = val return if isCrypted and self.useGrubVal == 0: log("requested crypted password with lilo; ignoring") self.pure = None return elif isCrypted: self.password = val self.pure = None else: salt = "$1$" saltLen = 8 for i in range(saltLen): salt = salt + whrandom.choice (string.letters + string.digits + './') self.password = crypt.crypt (val, salt) self.pure = val def getPassword (self): return self.pure def setForceLBA(self, val): self.forceLBA32 = val 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. # # XXX this has internal anaconda-ish knowledge. ick. import isys import lvm if string.split(device, '/', 1)[0] in map (lambda vg: vg[0], lvm.vglist()): return [] if device.startswith('md'): bootable = 0 parts = checkbootloader.getRaidDisks(device, 1, stripPart=0) parts.sort() return parts return [device] def writeGrub(self, instRoot, fsset, bl, langs, kernelList, chainList, defaultDev, justConfigFile): if len(kernelList) < 1: return "" images = bl.images.getImages() rootDev = fsset.getEntryByMountPoint("/").device.getDevice() if not os.path.isdir(instRoot + '/boot/grub/'): os.mkdir(instRoot + '/boot/grub', 0755) # XXX old config file should be read here for upgrade cf = '/boot/grub/grub.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') grubTarget = bl.getDevice() target = "mbr" if grubTarget[-1].isdigit() and not grubTarget.startswith('md'): target = "partition" f = open(instRoot + 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") bootDev = fsset.getEntryByMountPoint("/boot") grubPath = "/grub" cfPath = "/" if not bootDev: bootDev = fsset.getEntryByMountPoint("/") grubPath = "/boot/grub" cfPath = "/boot/" 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") else: 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") bootDevs = self.getPhysicalDevices(bootDev.device.getDevice()) bootDev = bootDev.device.getDevice() f.write('# root %s\n' % self.grubbyPartitionName(bootDevs[0])) f.write("# kernel %svmlinuz-version ro " "root=/dev/%s\n" % (cfPath, rootDev)) f.write("# initrd %sinitrd-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 == rootDev: default = 0 else: # if the default isn't linux, it's the first thing in the # chain list default = len(kernelList) # keep track of which devices are used for the device.map usedDevs = {} f.write('default=%s\n' % (default)) if len(chainList) > 0: timeout = 5 else: timeout = 5 f.write('timeout=%d\n' %(timeout,)) 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=5 serial console\n") 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") for dev in self.getPhysicalDevices(grubTarget): usedDevs[dev] = 1 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 = booty.makeInitrd (kernelTag, instRoot) f.write('title %s (%s)\n' % (longlabel, version)) f.write('\troot %s\n' % self.grubbyPartitionName(bootDevs[0])) realroot = getRootDevName(initrd, fsset, rootDev, instRoot) realroot = " root=%s" %(realroot,) f.write('\tkernel %s ro%s' % (kernelFile, realroot)) if self.args.get(): f.write(' %s' % self.args.get()) f.write('\n') if os.access (instRoot + initrd, os.R_OK): f.write('\tinitrd %sinitrd%s.img\n' % (cfPath, kernelTag)) 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') usedDevs[device] = 1 f.close() os.chmod(instRoot + "/boot/grub/grub.conf", self.perms) try: # make symlink for menu.lst (default config file name) if os.access (instRoot + "/boot/grub/menu.lst", os.R_OK): os.rename(instRoot + "/boot/grub/menu.lst", instRoot + "/boot/grub/menu.lst.rpmsave") os.symlink("./grub.conf", instRoot + "/boot/grub/menu.lst") except: pass try: # make symlink for /etc/grub.conf (config files belong in /etc) if os.access (instRoot + "/etc/grub.conf", os.R_OK): os.rename(instRoot + "/etc/grub.conf", instRoot + "/etc/grub.conf.rpmsave") os.symlink("../boot/grub/grub.conf", instRoot + "/etc/grub.conf") except: pass for dev in self.getPhysicalDevices(rootDev): usedDevs[dev] = 1 if not os.access(instRoot + "/boot/grub/device.map", os.R_OK): f = open(instRoot + "/boot/grub/device.map", "w+") f.write("# this device map was generated by anaconda\n") f.write("(fd0) /dev/fd0\n") devs = usedDevs.keys() usedDevs = {} for dev in devs: drive = getDiskPart(dev)[0] if usedDevs.has_key(drive): continue usedDevs[drive] = 1 devs = usedDevs.keys() 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. if not drive.startswith('md'): f.write("(%s) /dev/%s\n" % (self.grubbyDiskName(drive), drive)) f.close() if self.forceLBA32: forcelba = "--force-lba " else: forcelba = "" sysconf = '/etc/sysconfig/grub' if os.access (instRoot + sysconf, os.R_OK): 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] == '/'): os.rename(instRoot + sysconf, instRoot + sysconf + '.rpmsave') f = open(instRoot + sysconf, 'w+') f.write("boot=/dev/%s\n" %(grubTarget,)) if self.forceLBA32: f.write("forcelba=1\n") else: f.write("forcelba=0\n") f.close() cmds = [] for bootDev in bootDevs: gtPart = self.getMatchingPart(bootDev, grubTarget) gtDisk = self.grubbyPartitionName(getDiskPart(gtPart)[0]) bPart = self.grubbyPartitionName(bootDev) cmd = "root %s" % (bPart,) cmds.append(cmd) stage1Target = gtDisk if target == "partition": stage1Target = self.grubbyPartitionName(gtPart) cmd = "install %s%s/stage1 d %s %s/stage2 p %s%s/grub.conf" % \ (forcelba, grubPath, stage1Target, grubPath, bPart, grubPath) cmds.append(cmd) if not justConfigFile: log("GRUB commands:") for cmd in cmds: log("\t%s\n", cmd) # copy the stage files over into /boot rhpl.executil.execWithRedirect( "/sbin/grub-install", ["/sbin/grub-install", "--just-copy"], stdout = "/dev/tty5", stderr = "/dev/tty5", root = instRoot) # FIXME: hack to try to make sure everything is written to the disk if cfPath == "/": syncDataToDisk(bootDev, "/boot", instRoot) else: syncDataToDisk(bootDev, "/", instRoot) # really install the bootloader p = os.pipe() for cmd in cmds: os.write(p[1], cmd + '\n') os.close(p[1]) rhpl.executil.execWithRedirect('/sbin/grub' , [ "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]) return "" def getMatchingPart(self, bootDev, target): bootName, bootPartNum = getDiskPart(bootDev) devices = self.getPhysicalDevices(target) for device in devices: name, partNum = getDiskPart(device) if name == bootName: return device return devices[0] def grubbyDiskName(self, name): return "hd%d" % self.drivelist.index(name) def grubbyPartitionName(self, dev): (name, partNum) = getDiskPart(dev) if partNum != None: return "(%s,%d)" % (self.grubbyDiskName(name), partNum) else: return "(%s)" %(self.grubbyDiskName(name)) def getBootloaderConfig(self, instRoot, fsset, bl, langs, kernelList, chainList, defaultDev): config = bootloaderInfo.getBootloaderConfig(self, instRoot, fsset, bl, langs, 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) import language for lang in language.expandLangs(langs.getDefault()): fn = "/boot/message." + lang if os.access(instRoot + fn, os.R_OK): message = fn break 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') and not config.testEntry('linear'): if self.forceLBA32 or (bl.above1024 and butil.getArch() != "x86_64" and edd.detect()): config.addEntry("lba32", replace = 0) elif self.useLinear: config.addEntry("linear", replace = 0) else: config.addEntry("nolinear", replace = 0) return config def writeLilo(self, instRoot, fsset, bl, langs, kernelList, chainList, defaultDev, justConfig): if not self.doUpgradeOnly and len(kernelList) >= 1: config = self.getBootloaderConfig(instRoot, fsset, bl, langs, kernelList, chainList, defaultDev) config.write(instRoot + self.configfile, perms = self.perms) elif self.doUpgradeOnly: # this is to work around the fact that older kernels don't # remove themselves from lilo.conf on upgrade # it's a really bad hack, probably also needs to happen on # other arches once they support upgradeonly config = LiloConfigFile () if os.access (instRoot + self.configfile, os.R_OK): self.perms = os.stat(instRoot + self.configfile)[0] & 0777 config.read (instRoot + self.configfile) # Remove any invalid entries that are in the file; we probably # just removed those kernels. for label in config.listImages(): (fsType, sl, path, other) = config.getImage(label) if fsType == "other": continue if not os.access(instRoot + sl.getPath(), os.R_OK): config.delImage(label) # make sure that the default entry really exists. since # getDefault actually gets the entry for us, we'll get an # exception if it doesn't really exist. try: default = config.getDefault() except: try: config.delEntry("default") except: pass config.write(instRoot + self.configfile, perms = self.perms) # FIXME: do some syncs, just to make sure the config is written out import isys isys.sync() isys.sync() isys.sync() if not justConfig: str = rhpl.executil.execWithRedirect('/sbin/lilo' , ["/sbin/lilo", "-v"], stdout = "/dev/tty5", stderr = "/dev/tty5", root = instRoot) else: str = "" return str # 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, fsset, bl, langs, kernelList, chainList, defaultDev, justConfigFile): if justConfigFile: return "" theDev = None for (fn, stanza) in [ ("/etc/sysconfig/grub", "boot="), ("/boot/grub/grub.conf", "#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): import checkbootloader theDev = checkbootloader.getBootDevString(line) break if theDev is not None: break if theDev is None: # we could find the dev before, but can't now... cry about it return "" # migrate info to /etc/sysconfig/grub sysconf = '/etc/sysconfig/grub' if not os.access(instRoot + sysconf, os.R_OK): f = open(instRoot + sysconf, "w+") f.write("boot=%s\n" %(theDev,)) if self.forceLBA32: f.write("forcelba=1\n") else: f.write("forcelba=0\n") f.close() # 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 bootDev = fsset.getEntryByMountPoint("/boot") grubPath = "/grub" cfPath = "/" if not bootDev: bootDev = fsset.getEntryByMountPoint("/") grubPath = "/boot/grub" cfPath = "/boot/" masterBootDev = bootDev.device.getDevice(asBoot = 0) if masterBootDev[0:2] == 'md': rootDevs = checkbootloader.getRaidDisks(masterBootDev, raidLevel=1, stripPart = 0) else: rootDevs = [masterBootDev] if theDev[5:7] == 'md': stage1Devs = checkbootloader.getRaidDisks(theDev[5:], raidLevel=1) else: stage1Devs = [theDev[5:]] for stage1Dev in stage1Devs: # cross fingers; if we can't find a root device on the same # hardware as this boot device, we just blindly hope the first # thing in the list works. grubbyStage1Dev = self.grubbyPartitionName(stage1Dev) grubbyRootPart = self.grubbyPartitionName(rootDevs[0]) for rootDev in rootDevs: testGrubbyRootDev = getDiskPart(rootDev)[0] testGrubbyRootDev = self.grubbyPartitionName(testGrubbyRootDev) if grubbyStage1Dev == testGrubbyRootDev: grubbyRootPart = self.grubbyPartitionName(rootDev) break cmd = "root %s\ninstall %s/stage1 d %s %s/stage2 p %s%s/grub.conf" \ % (grubbyRootPart, grubPath, grubbyStage1Dev, grubPath, grubbyRootPart, grubPath) if not justConfigFile: log("GRUB command %s", cmd) # copy the stage files over into /boot rhpl.executil.execWithRedirect( "/sbin/grub-install", ["/sbin/grub-install", "--just-copy"], stdout = "/dev/tty5", stderr = "/dev/tty5", root = instRoot) # get the stage files synced to disk import isys isys.sync() isys.sync() isys.sync() # really install the bootloader p = os.pipe() os.write(p[1], cmd + '\n') os.close(p[1]) rhpl.executil.execWithRedirect('/sbin/grub' , [ "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]) return "" def write(self, instRoot, fsset, bl, langs, kernelList, chainList, defaultDev, justConfig, intf): # XXX HACK ALERT - see declaration above if self.doUpgradeOnly: if not self.useGrubVal: # we do upgrades sort of right for lilo... str = self.writeLilo(instRoot, fsset, bl, langs, kernelList, chainList, defaultDev, justConfig | (self.useGrubVal)) else: self.upgradeGrub(instRoot, fsset, bl, langs, kernelList, chainList, defaultDev, justConfig) # and the hacks continue. with 2.6, ide-scsi isn't used # anymore (#116622) import isys cdrw = isys.ideCdRwList() torem = [] for device in cdrw: torem.append("%s=ide-scsi" %(device,)) for fn in ("/etc/lilo.conf", "/boot/grub/grub.conf", "/etc/lilo.conf.anaconda"): if not os.path.exists(instRoot + fn): continue f = open(instRoot + fn, "r") buf = f.read() f.close() for dev in torem: buf = buf.replace(dev, "") f = open(instRoot + fn, "w") f.write(buf) f.close() return if len(kernelList) < 1: self.noKernelsWarn(intf) str = self.writeLilo(instRoot, fsset, bl, langs, kernelList, chainList, defaultDev, justConfig | (self.useGrubVal)) str = self.writeGrub(instRoot, fsset, bl, langs, kernelList, chainList, defaultDev, justConfig | (not self.useGrubVal)) # 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") def getArgList(self): args = bootloaderInfo.getArgList(self) if not self.useGrubVal: args.append("--useLilo") if self.forceLBA32: args.append("--lba32") if not self.useLinear: args.append("--nolinear") if self.password: args.append("--md5pass=%s" %(self.password)) # XXX add location of bootloader here too return args def __init__(self): bootloaderInfo.__init__(self) # XXX use checkbootloader to determine what to default to self.useGrubVal = 1 self.kernelLocation = "/boot/" self.configfile = "/etc/lilo.conf" self.password = None self.pure = None class s390BootloaderInfo(bootloaderInfo): def getBootloaderConfig(self, instRoot, fsset, bl, langs, kernelList, chainList, defaultDev): images = bl.images.getImages() # on upgrade read in the lilo config file lilo = LiloConfigFile () self.perms = 0600 if os.access (instRoot + self.configfile, os.R_OK): self.perms = os.stat(instRoot + self.configfile)[0] & 0777 lilo.read (instRoot + self.configfile) os.rename(instRoot + self.configfile, instRoot + self.configfile + '.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 = fsset.getEntryByMountPoint("/").device.getDevice() if not rootDev: raise RuntimeError, "Installing zipl, but there is no root device" if rootDev == defaultDev: 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 = booty.makeInitrd (kernelTag, instRoot) sl.addEntry("label", label) if os.access (instRoot + initrd, os.R_OK): sl.addEntry("initrd", "%sinitrd%s.img" %(self.kernelLocation, kernelTag)) sl.addEntry("read-only") sl.addEntry("root", '/dev/' + rootDev) sl.addEntry("ipldevice", '/dev/' + rootDev[:-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, fsset, bl, langs, kernelList, chainList, defaultDev, justConfigFile): images = bl.images.getImages() rootDev = fsset.getEntryByMountPoint("/").device.getDevice() 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 = booty.makeInitrd (kernelTag, instRoot) f.write('[%s]\n' % (label)) f.write('\timage=%s\n' % (kernelFile)) if os.access (instRoot + initrd, os.R_OK): f.write('\tramdisk=%sinitrd%s.img\n' %(self.kernelLocation, kernelTag)) realroot = getRootDevName(initrd, fsset, rootDev, instRoot) f.write('\tparameters="root=%s' %(realroot,)) if bl.args.get(): f.write(' %s' % (bl.args.get())) f.write('"\n') f.close() if not justConfigFile: argv = [ "/sbin/zipl" ] rhpl.executil.execWithRedirect(argv[0], argv, root = instRoot, stdout = "/dev/stdout", stderr = "/dev/stderr") return "" def write(self, instRoot, fsset, bl, langs, kernelList, chainList, defaultDev, justConfig, intf): str = self.writeZipl(instRoot, fsset, bl, langs, kernelList, chainList, defaultDev, justConfig | (not self.useZiplVal)) str = self.writeChandevConf(bl, instRoot) def __init__(self): bootloaderInfo.__init__(self) self.useZiplVal = 1 # only used on s390 self.kernelLocation = "/boot/" self.configfile = "/etc/zipl.conf" class alphaBootloaderInfo(bootloaderInfo): def wholeDevice (self, path): (device, foo) = getDiskPart(path) return device def partitionNum (self, path): # getDiskPart returns part numbers 0-based; we need it one based # *sigh* (foo, partitionNumber) = getDiskPart(path) return partitionNumber + 1 # See if we would have to use MILO. MILO isn't supported by Red Hat. def useMilo (self): try: f = open ('/proc/cpuinfo', 'ro') except: return lines = f.readlines () f.close() serial = "" for line in lines: if line.find("system serial number") != -1: serial = string.strip (string.split (line, ':')[1]) break if serial and len (serial) >= 4 and serial.startswith("MILO"): return 1 else: return 0 def writeAboot(self, instRoot, fsset, bl, langs, kernelList, chainList, defaultDev, justConfig): # Get bootDevice and rootDevice rootDevice = fsset.getEntryByMountPoint("/").device.getDevice() if fsset.getEntryByMountPoint("/boot"): bootDevice = fsset.getEntryByMountPoint("/boot").device.getDevice() else: bootDevice = rootDevice bootnotroot = bootDevice != rootDevice # If /etc/aboot.conf already exists we rename it # /etc/aboot.conf.rpmsave. if os.path.isfile(instRoot + self.configfile): os.rename (instRoot + self.configfile, instRoot + self.configfile + ".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, instRoot + self.configfile) 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 = instRoot + self.configfile 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) lines = 0 # We write entries line using the following format: # root= [options] # We get all the kernels we need to know about in kernelList. for (kernel, tag, kernelTag) in kernelList: 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 = booty.makeInitrd (kernelTag, instRoot) if os.access(instRoot + initrd, os.R_OK): f.write(" initrd=%sinitrd-%s.img" %(kernelPath, kernelTag)) realroot = getRootDevName(initrd, fsset, rootDevice, instRoot) 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 if not justConfig: # 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) bdpn = self.partitionNum (bootDevice) # Calling swriteboot. The first argument is the disk to write # to and the second argument is a path to the bootstrap loader # file. args = ("swriteboot", ("/dev/%s" % wbd), "/boot/bootlx") log("swriteboot command: %s" %(args,)) rhpl.executil.execWithRedirect ('/sbin/swriteboot', args, root = instRoot, stdout = "/dev/tty5", stderr = "/dev/tty5") # 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 = ("abootconf", ("/dev/%s" % wbd), str (bdpn)) log("abootconf command: %s" %(args,)) rhpl.executil.execWithRedirect ('/sbin/abootconf', args, root = instRoot, stdout = "/dev/tty5", stderr = "/dev/tty5") def write(self, instRoot, fsset, bl, langs, kernelList, chainList, defaultDev, justConfig, intf): if len(kernelList) < 1: self.noKernelsWarn(intf) if self.useMilo(): intf.messageWindow(_("MILO Not Supported"), "This system requires the support of MILO to " + "boot linux (MILO is not included in this " + "distribution.) The installation of the " + "bootloader can't be completed on this system.") # elif not justConfig FIXME. else: self.writeAboot(instRoot, fsset, bl, langs, kernelList, chainList, defaultDev, justConfig) def __init__(self): bootloaderInfo.__init__(self) self.useGrubVal = 0 self.configfile = "/etc/aboot.conf" # self.kernelLocation is already set to what we need. self.password = None self.pure = None class ppcBootloaderInfo(bootloaderInfo): def writeYaboot(self, instRoot, fsset, bl, langs, kernelList, chainList, defaultDev, justConfigFile): from flags import flags yabootTarget = '/dev/%s' %(bl.getDevice()) bootDev = fsset.getEntryByMountPoint("/boot") if bootDev: cf = "/boot/etc/yaboot.conf" cfPath = "" if not os.path.isdir(instRoot + "/boot/etc"): os.mkdir(instRoot + "/boot/etc") else: bootDev = fsset.getEntryByMountPoint("/") cfPath = "/boot" cf = "/etc/yaboot.conf" bootDev = bootDev.device.getDevice(asBoot = 1) f = open(instRoot + cf, "w+") f.write("# yaboot.conf generated by anaconda\n\n") f.write("boot=%s\n" %(yabootTarget,)) f.write("init-message=Welcome to %s\\!\nHit for boot options\n\n" %(butil.getProductName(),)) (name, partNum) = getDiskPart(bootDev) partno = partNum + 1 # 1 based f.write("partition=%s\n" %(partno,)) f.write("timeout=20\n") f.write("install=/usr/lib/yaboot/yaboot\n") f.write("delay=5\n") if butil.getPPCMachine() == "PMac": f.write("magicboot=/usr/lib/yaboot/ofboot\n") if butil.getPPCMachine() == "pSeries": f.write("nonvram\n") if self.password: f.write("password=%s\n" %(self.password,)) f.write("restricted\n") f.write("\n") rootDev = fsset.getEntryByMountPoint("/").device.getDevice() 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 = booty.makeInitrd(kernelTag, instRoot) if os.access(instRoot + initrd, os.R_OK): f.write("\tinitrd=%s/initrd%s.img\n" %(cfPath,kernelTag)) append = "%s" %(self.args.get(),) realroot = getRootDevName(initrd, fsset, rootDev, instRoot) if not realroot.startswith("LABEL="): 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 = [ "/sbin/mkofboot", "-f", "-C", cf ] if butil.getPPCMachine() == "pSeries": ybinargs.extend(["--filesystem", "raw"]) log("running: %s" %(ybinargs,)) if not flags.test: rhpl.executil.execWithRedirect(ybinargs[0], ybinargs, stdout = "/dev/tty5", stderr = "/dev/tty5", root = instRoot) 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 "" 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, fsset, bl, langs, kernelList, chainList, defaultDev, justConfig, intf): if len(kernelList) >= 1: str = self.writeYaboot(instRoot, fsset, bl, langs, kernelList, chainList, defaultDev, justConfig) else: self.noKernelsWarn(intf) def __init__(self): bootloaderInfo.__init__(self) self.useYabootVal = 1 self.kernelLocation = "/boot" self.configfile = "/etc/yaboot.conf" class iseriesBootloaderInfo(bootloaderInfo): def ddFile(self, inf, of, bs = 4096): src = os.open(inf, os.O_RDONLY) dest = os.open(of, os.O_WRONLY | os.O_CREAT) size = 0 buf = os.read(src, bs) while len(buf) > 0: size = size + len(buf) os.write(dest, buf) buf = os.read(src, bs) os.close(src) os.close(dest) return size def write(self, instRoot, fsset, bl, langs, kernelList, chainList, defaultDev, justConfig, intf): if len(kernelList) < 1: self.noKernelsWarn(intf) return if len(kernelList) > 1: # FIXME: how can this happen? log("more than one kernel on iSeries. bailing and just using " "the first") # iseries is Weird (tm) -- here's the basic theory # a) have /boot/vmlinitrd-$(version) # b) copy default kernel to PReP partition # c) dd default kernel to /proc/iSeries/mf/C/vmlinux # d) set cmdline in /boot/cmdline-$(version) # e) copy cmdline to /proc/iSeries/mf/C/cmdline # f) set default side to 'C' i /proc/iSeries/mf/side # g) put default kernel and cmdline on side B too (#91038) rootDevice = fsset.getEntryByMountPoint("/").device.getDevice() # write our command line files for (kernel, tag, kernelTag) in kernelList: cmdFile = "%scmdline-%s" %(self.kernelLocation, kernelTag) initrd = "%sinitrd-%s.img" %(self.kernelLocation, kernelTag) realroot = getRootDevName(initrd, fsset, rootDevice, instRoot) f = open(instRoot + cmdFile, "w") f.write("ro root=%s" %(realroot,)) if bl.args.get(): f.write(" %s" %(bl.args.get(),)) f.write("\n") f.close() os.chmod(instRoot + cmdFile, 0644) kernel, tag, kernelTag = kernelList[0] kernelFile = "%svmlinitrd-%s" %(self.kernelLocation, kernelTag) # write the kernel to the PReP partition since that's what # OS/400 will load as NWSSTG bootDev = bl.getDevice() if bootDev: log("Writing kernel %s to PReP partition %s" %(kernelFile, bootDev)) try: self.ddFile(instRoot + kernelFile, "%s/dev/%s" %(instRoot, bootDev)) except Exception, e: # FIXME: should this be more fatal log("Failed to write kernel: %s" %(e,)) else: log("No PReP boot partition, not writing kernel for NWSSTG") # now, it's a lot faster to boot if we don't make people go back # into OS/400, so set up side C (used by default for NWSSTG) with # our current bits for side in ("C", "B"): log("Writing kernel and cmdline to side %s" %(side,)) wrotekernel = 0 try: self.ddFile(instRoot + kernelFile, "%s/proc/iSeries/mf/%s/vmlinux" %(instRoot, side)) wrotekernel = 1 except Exception, e: # FIXME: should this be more fatal? log("Failed to write kernel to side %s: %s" %(side, e)) if wrotekernel == 1: try: # blank it. ugh. f = open("%s/proc/iSeries/mf/%s/cmdline" %(instRoot, side), "w+") f.write(" " * 255) f.close() self.ddFile("%s/%scmdline-%s" %(instRoot, self.kernelLocation, kernelTag), "%s/proc/iSeries/mf/%s/cmdline" %(instRoot, side)) except Exception, e: log("Failed to write kernel command line to side %s: %s" %(side, e)) log("Setting default side to C") f = open(instRoot + "/proc/iSeries/mf/side", "w") f.write("C") f.close() def __init__(self): bootloaderInfo.__init__(self) self.kernelLocation = "/boot/" ############### # end of boot loader objects... these are just some utility functions used # return (disk, partition number) eg ('hda', 1) def getDiskPart(dev): cut = len(dev) if (dev.startswith('rd/') or dev.startswith('ida/') or dev.startswith('cciss/')): if dev[-2] == 'p': cut = -1 elif dev[-3] == 'p': cut = -2 else: if dev[-2] in string.digits: cut = -2 elif dev[-1] in string.digits: cut = -1 name = dev[:cut] # hack off the trailing 'p' from /dev/cciss/*, for example if name[-1] == 'p': for letter in name: if letter not in string.letters and letter != "/": name = name[:-1] break if cut < 0: partNum = int(dev[cut:]) - 1 else: partNum = None return (name, partNum) # hackery to determine if we should do root=LABEL=/ or whatnot # as usual, knows too much about anaconda def getRootDevName(initrd, fsset, rootDev, instRoot): if not os.access(instRoot + initrd, os.R_OK): return "/dev/%s" % (rootDev,) try: rootEntry = fsset.getEntryByMountPoint("/") if rootEntry.getLabel() is not None: return "LABEL=%s" %(rootEntry.getLabel(),) return "/dev/%s" %(rootDev,) except: return "/dev/%s" %(rootDev,)