# this owns partitioning, fstab generation, disk scanning, raid, etc # # a fstab is returned as a list of: # ( mntpoint, device, fsystem, doFormat, size, (file) ) # tuples, sorted by mntpoint; note that device may be a raid device; the file # value is optional, and if it exists it names a file which will be created # on the (already existant!) device and loopback mounted # # the swap information is stored as ( device, format ) tuples # # raid lists are stored as ( mntpoint, raiddevice, fssystem, doFormat, # raidlevel, [ device list ] ) # # we always store as much of the fstab within the disk druid structure # as we can -- Don't Duplicate Data. import isys import iutil import os import string import raid import struct from translate import _ def isValidExt2(device): file = '/tmp/' + device isys.makeDevInode(device, file) try: fd = os.open(file, os.O_RDONLY) except: return 0 buf = os.read(fd, 2048) os.close(fd) if len(buf) != 2048: return 0 if struct.unpack("H", buf[1080:1082]) == (0xef53,): return 1 return 0 class Fstab: def attemptPartitioning(self, partitions, clearParts): attempt = [] swapCount = 0 fstab = [] for (mntpoint, dev, fstype, reformat, size) in self.extraFilesystems: fstab.append ((dev, mntpoint)) ddruid = self.createDruid(fstab = fstab, ignoreBadDrives = 1) for (mntpoint, size, maxsize, grow, device) in partitions: type = 0x83 if (mntpoint == "swap"): mntpoint = "Swap%04d-auto" % swapCount swapCount = swapCount + 1 type = 0x82 elif (mntpoint[0:5] == "raid."): type = 0xfd attempt.append((mntpoint, size, maxsize, type, grow, -1, device)) try: ddruid.attempt (attempt, "Junk Argument", clearParts) return ddruid except: pass return None def getMbrDevice(self): return self.driveList()[0] def getBootDevice(self): bootDevice = None rootDevice = None for (mntpoint, partition, fsystem, doFormat, size) in self.mountList(): if mntpoint == '/': rootDevice = partition elif mntpoint == '/boot': bootDevice = partition if not bootDevice: bootDevice = rootDevice return bootDevice def getRootDevice(self): for (mntpoint, partition, fsystem, doFormat, size) in self.mountList(): if mntpoint == '/': return (partition, fsystem) def rootOnLoop(self): if not self.setupFilesystems: return 0 for (mntpoint, partition, fsystem, doFormat, size) in self.mountList(): if mntpoint == '/': if fsystem == "vfat": return 1 else: return 0 raise ValueError, "no root device has been set" def getLoopbackSize(self): return (self.loopbackSize, self.loopbackSwapSize) def setLoopbackSize(self, size, swapSize): self.loopbackSize = size self.loopbackSwapSize = swapSize def setDruid(self, druid, raid): self.ddruid = druid self.fsCache = {} for (mntPoint, raidDev, level, devices) in raid: if mntPoint == "swap": fsystem = "swap" else: fsystem = "ext2" self.addNewRaidDevice(mntPoint, raidDev, fsystem, level, devices) def rescanPartitions(self, clearFstabCache = 0): if self.ddruid: self.closeDrives(clearFstabCache) fstab = [] for (mntpoint, dev, fstype, reformat, size) in self.cachedFstab: fstab.append ((dev, mntpoint)) self.ddruid = self.fsedit(0, self.driveList(), fstab, self.zeroMbr, self.readOnly) del self.cachedFstab def closeDrives(self, clearFstabCache = 0): # we expect a rescanPartitions() after this!!! if clearFstabCache: self.cachedFstab = [] else: self.cachedFstab = self.mountList(skipExtra = 1) self.ddruid = None def setReadonly(self, readOnly): self.readOnly = readOnly self.ddruid.setReadOnly(readOnly) def savePartitions(self): self.ddruid.save() def runDruid(self): rc = self.ddruid.edit() # yikes! this needs to be smarter self.beenSaved = 0 return rc def updateFsCache(self): realFs = {} for (partition, mount, fsystem, size) in self.ddruid.getFstab(): realFs[(partition, mount)] = 1 for ((partition, mount)) in self.fsCache.keys(): if not realFs.has_key((partition, mount)): del self.fsCache[(partition, mount)] def setFormatFilesystem(self, device, format): for (mntpoint, partition, fsystem, doFormat, size) in self.mountList(): if partition == device: self.fsCache[(partition, mntpoint)] = (format,) return raise TypeError, "unknown partition to format %s" % (device,) def formatAllFilesystems(self): for (partition, mount, fsystem, size) in self.ddruid.getFstab(): if mount[0] == '/': self.fsCache[(partition, mount)] = (1,) (devices, raid) = self.ddruid.partitionList() for (mount, partition, fsystem, level, i, j, deviceList) in \ self.raidList()[1]: if mount[0] == '/': self.fsCache[(partition, mount)] = (1,) def partitionList(self): return self.ddruid.partitionList() def driveList(self): drives = isys.hardDriveDict().keys() drives.sort (isys.compareDrives) return drives def drivesByName(self): return isys.hardDriveDict() def swapList(self): fstab = [] for (partition, mount, fsystem, size) in self.ddruid.getFstab(): if fsystem != "swap": continue fstab.append((partition, 1)) # Add raid mounts to mount list (devices, raid) = self.raidList() for (mntpoint, device, fsType, raidType, start, size, makeup) in raid: if fsType != "swap": continue fstab.append((device, 1)) for n in self.extraFilesystems: (mntpoint, device, fsType, doFormat, size) = n if fsType != "swap": continue fstab.append((device, 1)) return fstab def turnOffSwap(self): if not self.swapOn: return self.swapOn = 0 for (device, doFormat) in self.swapList(): file = '/tmp/swap/' + device isys.swapoff(file) def turnOnSwap(self, formatSwap = 1): # we could be smarter about this if self.swapOn or self.rootOnLoop(): return self.swapOn = 1 iutil.mkdirChain('/tmp/swap') for (device, doFormat) in self.swapList(): file = '/tmp/swap/' + device isys.makeDevInode(device, file) if formatSwap: w = self.waitWindow(_("Formatting"), _("Formatting swap space on /dev/%s...") % (device,)) rc = iutil.execWithRedirect ("/usr/sbin/mkswap", [ "mkswap", '-v1', file ], stdout = None, stderr = None, searchPath = 1) w.pop() if rc: self.messageWindow(_("Error"), _("Error creating swap on device ") + device) else: isys.swapon (file) else: try: isys.swapon (file) except: # XXX should we complain? pass def addNewRaidDevice(self, mountPoint, raidDevice, fileSystem, raidLevel, deviceList): self.supplementalRaid.append((mountPoint, raidDevice, fileSystem, raidLevel, deviceList)) def clearExistingRaid(self): self.existingRaid = [] def addExistingRaidDevice(self, raidDevice, mntPoint, fsystem, deviceList): self.existingRaid.append(raidDevice, mntPoint, fsystem, deviceList) def existingRaidList(self): return self.existingRaid def raidList(self): (devices, raid) = self.ddruid.partitionList() if raid == None: raid = [] for (mountPoint, raidDevice, fileSystem, raidLevel, deviceList) in \ self.supplementalRaid: raid.append(mountPoint, raidDevice, fileSystem, raidLevel, 0, 0, deviceList) return (devices, raid) def createRaidTab(self, file, devPrefix, createDevices = 0): (devices, raid) = self.raidList() if not raid: return deviceDict = {} for (device, name, type, start, size) in devices: deviceDict[name] = device rt = open(file, "w") for (mntpoint, device, fstype, raidType, start, size, makeup) in raid: if createDevices: isys.makeDevInode(device, devPrefix + '/' + device) rt.write("raiddev %s/%s\n" % (devPrefix, device,)) rt.write("raid-level %d\n" % (raidType,)) rt.write("nr-raid-disks %d\n" % (len(makeup),)) rt.write("chunk-size 64k\n") rt.write("persistent-superblock 1\n"); rt.write("#nr-spare-disks 0\n") i = 0 for subDevName in makeup: isys.makeDevInode(deviceDict[subDevName], '%s/%s' % (devPrefix, deviceDict[subDevName])) rt.write(" device %s/%s\n" % (devPrefix, deviceDict[subDevName],)) rt.write(" raid-disk %d\n" % (i,)) i = i + 1 rt.write("\n") rt.close() def umountFilesystems(self, instPath, ignoreErrors = 0): if (not self.setupFilesystems): return isys.umount(instPath + '/proc') mounts = self.mountList() mounts.reverse() for (n, device, fsystem, doFormat, size) in mounts: if fsystem != "swap": try: mntPoint = instPath + n isys.umount(mntPoint) except SystemError, (errno, msg): if not ignoreErrors: self.messageWindow(_("Error"), _("Error unmounting %s: %s") % (device, msg)) if self.rootOnLoop(): isys.makeDevInode("loop0", '/tmp/' + "loop0") isys.unlosetup("/tmp/loop0") for (raidDevice, mntPoint, fileSystem, deviceList) in self.existingRaid: isys.raidstop(raidDevice) def makeFilesystems(self): # let's make the RAID devices first -- the fstab will then proceed # naturally (devices, raid) = self.raidList() if self.serial: messageFile = "/tmp/mke2fs.log" else: messageFile = "/dev/tty5" if raid: self.createRaidTab("/tmp/raidtab", "/tmp", createDevices = 1) w = self.waitWindow(_("Creating"), _("Creating RAID devices...")) for (mntpoint, device, fsType, raidType, start, size, makeup) in raid: iutil.execWithRedirect ("/usr/sbin/mkraid", [ 'mkraid', '--really-force', '--configfile', '/tmp/raidtab', '/tmp/' + device ], stderr = messageFile, stdout = messageFile) w.pop() # XXX remove extraneous inodes here # print "created raid" if not self.setupFilesystems: return arch = iutil.getArch () if arch == "alpha": bootPart = self.getBootDevice() for (mntpoint, device, fsystem, doFormat, size) in self.mountList(): if not doFormat: continue isys.makeDevInode(device, '/tmp/' + device) if fsystem == "ext2": args = [ "mke2fs", '/tmp/' + device ] # FORCE the partition that MILO has to read # to have 1024 block size. It's the only # thing that our milo seems to read. if arch == "alpha" and device == bootPart: args = args + ["-b", "1024", '-r', '0', '-O', 'none'] # set up raid options for md devices. if device[:2] == 'md': for (rmnt, rdevice, fsType, raidType, start, size, makeup) in raid: if rdevice == device: rtype = raidType rdisks = len (makeup) if rtype == 5: rdisks = rdisks - 1 args = args + [ '-R', 'stride=%d' % (rdisks * 16) ] elif rtype == 0: args = args + [ '-R', 'stride=%d' % (rdisks * 16) ] if self.badBlockCheck: args.append ("-c") w = self.waitWindow(_("Formatting"), _("Formatting %s filesystem...") % (mntpoint,)) iutil.execWithRedirect ("/usr/sbin/mke2fs", args, stdout = messageFile, stderr = messageFile, searchPath = 1) w.pop() else: pass os.remove('/tmp/' + device) def mountFilesystems(self, instPath): if (not self.setupFilesystems): return for (raidDevice, mntPoint, fileSystem, deviceList) in self.existingRaid: isys.raidstart(raidDevice, deviceList[0]) for (mntpoint, device, fsystem, doFormat, size) in self.mountList(): if fsystem == "swap": continue elif fsystem == "vfat" and mntpoint == "/": # do a magical loopback mount -- whee! w = self.waitWindow(_("Loopback"), _("Creating loopback filesystem on device /dev/%s...") % (device,)) iutil.mkdirChain("/mnt/loophost") isys.makeDevInode(device, '/tmp/' + device) isys.mount('/tmp/' + device, "/mnt/loophost", fstype = "vfat") os.remove( '/tmp/' + device); isys.makeDevInode("loop0", '/tmp/' + "loop0") isys.ddfile("/mnt/loophost/redhat.img", self.loopbackSize) isys.losetup("/tmp/loop0", "/mnt/loophost/redhat.img") if self.serial: messageFile = "/tmp/mke2fs.log" else: messageFile = "/dev/tty5" iutil.execWithRedirect ("/usr/sbin/mke2fs", [ "mke2fs", "/tmp/loop0" ], stdout = messageFile, stderr = messageFile, searchPath = 1) isys.mount('/tmp/loop0', instPath) os.remove('/tmp/loop0') if self.loopbackSwapSize: isys.ddfile("/mnt/loophost/rh-swap.img", self.loopbackSwapSize) iutil.execWithRedirect ("/usr/sbin/mkswap", [ "mkswap", '-v1', '/mnt/loophost/rh-swap.img' ], stdout = None, stderr = None) isys.swapon("/mnt/loophost/rh-swap.img") w.pop() elif fsystem == "ext2": try: iutil.mkdirChain(instPath + mntpoint) isys.makeDevInode(device, '/tmp/' + device) isys.mount('/tmp/' + device, instPath + mntpoint) os.remove( '/tmp/' + device); except SystemError, (errno, msg): self.messageWindow(_("Error"), _("Error mounting %s: %s") % (device, msg)) raise SystemError, (errno, msg) try: os.mkdir (instPath + '/proc') except: pass isys.mount('/proc', instPath + '/proc', 'proc') def write(self, prefix, fdDevice = "/dev/fd0"): format = "%-23s %-23s %-7s %-15s %d %d\n"; f = open (prefix + "/etc/fstab", "w") for (mntpoint, dev, fs, reformat, size) in self.mountList(): if fs == "vfat" and mntpoint == "/": f.write("# LOOP0: /dev/%s %s /redhat.img\n" % (dev, fs)) dev = "loop0" fs = "ext2" iutil.mkdirChain(prefix + mntpoint) if mntpoint == '/': f.write (format % ( '/dev/' + dev, mntpoint, fs, 'defaults', 1, 1)) else: if fs == "ext2": f.write (format % ( '/dev/' + dev, mntpoint, fs, 'defaults', 1, 2)) elif fs == "iso9660": f.write (format % ( '/dev/' + dev, mntpoint, fs, 'noauto,owner,ro', 0, 0)) elif fs == "auto" and (dev == "zip" or dev == "jaz"): f.write (format % ( '/dev/' + dev, mntpoint, fs, 'noauto,owner', 0, 0)) else: f.write (format % ( '/dev/' + dev, mntpoint, fs, 'defaults', 0, 0)) f.write (format % (fdDevice, "/mnt/floppy", 'auto', 'noauto,owner', 0, 0)) f.write (format % ("none", "/proc", 'proc', 'defaults', 0, 0)) f.write (format % ("none", "/dev/pts", 'devpts', 'gid=5,mode=620', 0, 0)) if self.loopbackSwapSize: f.write(format % ("/initrd/loopfs/rh-swap.img", 'swap', 'swap', 'defaults', 0, 0)) for (partition, doFormat) in self.swapList(): f.write (format % ("/dev/" + partition, 'swap', 'swap', 'defaults', 0, 0)) f.close () # touch mtab open (prefix + "/etc/mtab", "w+") f.close () self.createRaidTab(prefix + "/etc/raidtab", "/dev") def clearMounts(self): self.extraFilesystems = [] def addMount(self, partition, mount, fsystem, doFormat = 0, size = 0): self.extraFilesystems.append(mount, partition, fsystem, doFormat, size) # XXX code from sparc merge # if fsystem == "swap": # ufs = 0 # try: # isys.makeDevInode(device, '/tmp/' + device) # except: # pass # try: # ufs = isys.checkUFS ('/tmp/' + device) # except: # pass # if not ufs: # location = "swap" # reformat = 1 # self.mounts[location] = (device, fsystem, reformat) def mountList(self, skipExtra = 0): def sortMounts(one, two): mountOne = one[0] mountTwo = two[0] if (mountOne < mountTwo): return -1 elif (mountOne == mountTwo): return 0 return 1 fstab = [] for (partition, mount, fsystem, size) in self.ddruid.getFstab(): if fsystem == "swap": continue if not self.fsCache.has_key((partition, mount)): if mount == '/home' and isValidExt2(partition): self.fsCache[(partition, mount)] = (0, ) else: self.fsCache[(partition, mount)] = (1, ) (doFormat,) = self.fsCache[(partition, mount)] fstab.append((mount, partition, fsystem, doFormat, size )) for (raidDevice, mntPoint, fsType, deviceList) in self.existingRaid: if fsType == "swap": continue fstab.append((mntPoint, raidDevice, fsType, 0, 0 )) # Add raid mounts to mount list (devices, raid) = self.raidList() for (mntpoint, device, fsType, raidType, start, size, makeup) in raid: if fsType == "swap": continue if not self.fsCache.has_key((device, mntpoint)): self.fsCache[(device, mntpoint)] = (1, ) (doFormat,) = self.fsCache[(device, mntpoint)] fstab.append((mntpoint, device, fsType, doFormat, size )) if not skipExtra: for n in self.extraFilesystems: (mntpoint, sevice, fsType, doFormat, size) = n if fsType == "swap": continue fstab.append(n) fstab.sort(sortMounts) return fstab def saveDruidPartitions(self): if self.beenSaved: return self.ddruid.save() self.beenSaved = 1 def setBadBlockCheck(self, state): self.badBlockCheck = state def getBadBlockCheck(self): return self.badBlockCheck def createDruid(self, fstab = [], ignoreBadDrives = 0): return self.fsedit(0, self.driveList(), fstab, self.zeroMbr, self.readOnly, ignoreBadDrives) def getRunDruid(self): return self.shouldRunDruid def setRunDruid(self, state): self.shouldRunDruid = state def __init__(self, fsedit, setupFilesystems, serial, zeroMbr, readOnly, waitWindow, messageWindow): self.fsedit = fsedit self.fsCache = {} self.swapOn = 0 self.supplementalRaid = [] self.beenSaved = 1 self.setupFilesystems = setupFilesystems self.serial = serial self.zeroMbr = zeroMbr self.readOnly = readOnly self.waitWindow = waitWindow self.messageWindow = messageWindow self.badBlockCheck = 0 self.extraFilesystems = [] self.existingRaid = [] self.ddruid = self.createDruid() self.loopbackSize = 0 self.loopbackSwapSize = 0 # I intentionally don't initialize this, as all install paths should # initialize this automatically #self.shouldRunDruid = 0 class GuiFstab(Fstab): def accel (self, widget, area): self.accelgroup = self.GtkAccelGroup (_obj = widget.get_data ("accelgroup")) self.toplevel = widget.get_toplevel() self.toplevel.add_accel_group (self.accelgroup) def runDruid(self, callback): self.ddruid.setCallback (callback) bin = self.GtkFrame (None, _obj = self.ddruid.getWindow ()) bin.connect ("draw", self.accel) bin.set_shadow_type (self.SHADOW_NONE) self.ddruid.edit () return bin def runDruidFinished(self): if self.accelgroup: self.toplevel.remove_accel_group (self.accelgroup) self.ddruid.next () self.updateFsCache() # yikes! this needs to be smarter self.beenSaved = 0 def __init__(self, setupFilesystems, serial, zeroMbr, readOnly, waitWindow, messageWindow): from gnomepyfsedit import fsedit from gtk import * Fstab.__init__(self, fsedit, setupFilesystems, serial, zeroMbr, readOnly, waitWindow, messageWindow) self.GtkFrame = GtkFrame self.GtkAccelGroup = GtkAccelGroup self.SHADOW_NONE = SHADOW_NONE self.accelgroup = None class NewtFstab(Fstab): def __init__(self, setupFilesystems, serial, zeroMbr, readOnly, waitWindow, messageWindow): from newtpyfsedit import fsedit Fstab.__init__(self, fsedit, setupFilesystems, serial, zeroMbr, readOnly, waitWindow, messageWindow) def readFstab (path, fstab): f = open (path, "r") lines = f.readlines () f.close fstab.clearExistingRaid() fstab.clearMounts() drives = fstab.driveList() raidList = raid.scanForRaid(drives) raidByDev = {} for (mdDev, devList) in raidList: raidByDev[mdDev] = devList for line in lines: fields = string.split (line) # skip comments if fields and fields[0][0] == '#': continue if not fields: continue # all valid fstab entries have 6 fields if len (fields) < 4 or len (fields) > 6: continue if fields[2] != "ext2" and fields[2] != "swap": continue if string.find(fields[3], "noauto") != -1: continue if (fields[0][0:7] != "/dev/hd" and fields[0][0:7] != "/dev/sd" and fields[0][0:7] != "/dev/md" and fields[0][0:8] != "/dev/rd/" and fields[0][0:9] != "/dev/ida/"): continue if fields[0][0:7] == "/dev/md": fstab.addExistingRaidDevice(fields[0][5:], fields[1], fields[2], raidByDev[int(fields[0][7:])]) else: fstab.addMount(fields[0][5:], fields[1], fields[2])