From: Michael Tremer Date: Sun, 10 May 2009 20:35:46 +0000 (+0200) Subject: Daily checkin. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=099849d41a65a69fdfc0cabd0a3210738d9da96f;p=ipfire-3.x.git Daily checkin. --- diff --git a/.gitignore b/.gitignore index 18cdbb70e..690c03f99 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ /*.iso /*.tar.gz *~ +*.py[co] diff --git a/lfs/python-parted b/lfs/python-parted index a66991cbe..557387ff4 100644 --- a/lfs/python-parted +++ b/lfs/python-parted @@ -25,7 +25,7 @@ include Config PKG_NAME = pyparted -PKG_VER = 2.0.10 +PKG_VER = 2.0.12 THISAPP = $(PKG_NAME)-$(PKG_VER) DL_FILE = $(THISAPP).tar.gz diff --git a/src/pomona/exception.py b/src/pomona/exception.py index 52ad9bf79..36fd2b004 100644 --- a/src/pomona/exception.py +++ b/src/pomona/exception.py @@ -127,6 +127,8 @@ def handleException(installer, (type, value, tb)): # restore original exception handler sys.excepthook = sys.__excepthook__ + installer.log.error("Exception occured. Read more in /tmp/instdump.txt.") + # get traceback information list = formatException(type, value, tb) text = string.joinfields(list, "") diff --git a/src/pomona/log.py b/src/pomona/log.py index 84608939a..aee3e5d5f 100644 --- a/src/pomona/log.py +++ b/src/pomona/log.py @@ -12,21 +12,27 @@ class Logger: def critical(self, msg): self.logfile.write(self.logline % (self.time(), "CRITICAL", msg,)) + self.flush() def info(self, msg): self.logfile.write(self.logline % (self.time(), "INFO", msg,)) + self.flush() def debug(self, msg): self.logfile.write(self.logline % (self.time(), "DEBUG", msg,)) + self.flush() def error(self, msg): self.logfile.write(self.logline % (self.time(), "ERROR", msg,)) + self.flush() def warning(self, msg): self.logfile.write(self.logline % (self.time(), "WARNING", msg,)) + self.flush() def stdout(self, msg): self.logfile.write(self.logline % (self.time(), "STDOUT", msg,)) + self.flush() print msg def time(self): @@ -34,3 +40,6 @@ class Logger: def __del__(self): self.logfile.close() + + def flush(self): + self.logfile.flush() diff --git a/src/pomona/partition.py b/src/pomona/partition.py index 8695263cc..843dba894 100644 --- a/src/pomona/partition.py +++ b/src/pomona/partition.py @@ -2,6 +2,8 @@ from snack import * +from storage.deviceaction import * +import storage import storage.formats as formats from storage.devicelibs.lvm import safeLvmName @@ -161,6 +163,7 @@ class PartitionWindow(object): return row = 0 + actions = [] if not device.exists: tstr = _("Add Partition") @@ -168,6 +171,12 @@ class PartitionWindow(object): tstr = _("Edit Partition") grid = GridForm(self.screen, tstr, 1, 6) + if device.exists: + if device.format.exists and getattr(device.format, "label", None): + lbl = Label("%s %s" % (_("Original File System Label:"), device.format.label)) + grid.add(lbl, 0, row) + row += 1 + (mountgrid, mountpoint) = self.makeMountPoint(device) grid.add(mountgrid, 0, row) row += 1 @@ -176,13 +185,15 @@ class PartitionWindow(object): subgrid1 = Grid(2, 1) (devgrid, drivelist) = self.makeDriveList(device) - subgrid1.setField(devgrid, 0, 0, (0,1,0,0), growx=1) + subgrid1.setField(devgrid, 0, 0) (fsgrid, fstype) = self.makeFileSystemList(device) - subgrid1.setField(fsgrid, 1, 0) + subgrid1.setField(fsgrid, 1, 0, (1,0,0,0), growx=1) grid.add(subgrid1, 0, row, (0,1,0,0), growx=1) row += 1 + else: + pass bb = ButtonBar(self.screen, (TEXT_OK_BUTTON, TEXT_CANCEL_BUTTON)) grid.add(bb, 0, row, (0,1,0,0), growx = 1) @@ -202,10 +213,14 @@ class PartitionWindow(object): if device.format: device.format.mountpoint = mountpoint.value() + + if not device.exists: + actions.append(ActionCreateDevice(self.installer, device)) break self.screen.popWindow() + return actions def editVG(self, device): if not device.exists: @@ -251,14 +266,30 @@ class PartitionWindow(object): self.installer.intf.messageWindow(_("Unable To Edit"), _("You must first select a partition to edit.")) return + + reason = self.storage.deviceImmutable(device) + if reason: + self.installer.intf.messageWindow(_("Unable To Edit"), + _("You cannot edit this device:\n\n%s") + % reason,) + return - self.editPart(device) + actions = None + if device.type == "mdarray": + pass #self.editRaidArray(device) + elif device.type == "lvmvg": + actions = self.editVG(device) + elif device.type == "lvmlv": + actions = self.editLV(device) + elif isinstance(device, storage.devices.PartitionDevice): + actions = self.editPart(device) + + for action in actions: + self.storage.devicetree.registerAction(action) def deleteCb(self): device = self.lb.current() - - self.installer.log.debug("%s" % device.type) - + if not device: self.installer.intf.messageWindow(_("Unable To Delete"), _("You must first select a partition to delete.")) @@ -280,7 +311,7 @@ class PartitionWindow(object): self.screen = self.installer.intf.screen self.storage = self.installer.ds.storage - self.installer.intf.setHelpline(_("F1-Help F2-New F3-Edit F4-Delete F5-Reset F12-OK")) + self.installer.intf.setHelpline(_("F2-New F3-Edit F4-Delete F5-Reset F12-OK")) self.g = GridForm(self.screen, _("Partitioning"), 1, 5) self.lb = CListbox(height=10, cols=4, diff --git a/src/pomona/storage/__init__.py b/src/pomona/storage/__init__.py index 9b3022335..2a0da0b8d 100644 --- a/src/pomona/storage/__init__.py +++ b/src/pomona/storage/__init__.py @@ -415,6 +415,70 @@ class Storage(object): return lvtemplate + def deviceImmutable(self, device): + """ Return any reason the device cannot be modified/removed. + + Return False if the device can be removed. + + Devices that cannot be removed include: + + - protected partitions + - devices that are part of an md array or lvm vg + - extended partition containing logical partitions that + meet any of the above criteria + + """ + if not isinstance(device, Device): + raise ValueError("arg1 (%s) must be a Device instance" % device) + + if device.name in self.protectedDisks: + return _("This partition is holding the data for the hard " + "drive install.") + elif device.format.type == "mdmember": + for array in self.mdarrays: + if array.dependsOn(device): + if array.minor is not None: + return _("This device is part of the RAID " + "device %s.") % (array.path,) + else: + return _("This device is part of a RAID device.") + elif device.format.type == "lvmpv": + for vg in self.vgs: + if vg.dependsOn(device): + if vg.name is not None: + return _("This device is part of the LVM " + "volume group '%s'.") % (vg.name,) + else: + return _("This device is part of a LVM volume " + "group.") + elif device.format.type == "luks": + try: + luksdev = self.devicetree.getChildren(device)[0] + except IndexError: + pass + else: + return self.deviceImmutable(luksdev) + elif isinstance(device, PartitionDevice) and device.isExtended: + reasons = {} + for dep in self.deviceDeps(device): + reason = self.deviceImmutable(dep) + if reason: + reasons[dep.path] = reason + if reasons: + msg = _("This device is an extended partition which " + "contains logical partitions that cannot be " + "deleted:\n\n") + for dev in reasons: + msg += "%s: %s" % (dev, reasons[dev]) + return msg + + for i in self.devicetree.immutableDevices: + if i[0] == device.name: + return i[1] + + return False + + class FSSet(object): """ A class to represent a set of filesystems. """ def __init__(self, installer): diff --git a/src/pomona/storage/devices.py b/src/pomona/storage/devices.py index 0d952a7f0..362805481 100644 --- a/src/pomona/storage/devices.py +++ b/src/pomona/storage/devices.py @@ -1,8 +1,11 @@ #/usr/bin/python +import copy import math import parted +import _ped +from errors import * from formats import get_device_format_class, getFormat from udev import * from util import notify_kernel, numeric_type @@ -80,6 +83,25 @@ class Device(object): for parent in self.parents: parent.addChild() + def __deepcopy__(self, memo): + """ Create a deep copy of a Device instance. + + We can't do copy.deepcopy on parted objects, which is okay. + For these parted objects, we just do a shallow copy. + """ + new = self.__class__.__new__(self.__class__) + memo[id(self)] = new + shallow_copy_attrs = ('partedDisk', '_partedDevice', + '_partedPartition', '_origPartedDisk', + '_raidSet', 'installer', 'screen') + for (attr, value) in self.__dict__.items(): + if attr in shallow_copy_attrs: + setattr(new, attr, copy.copy(value)) + else: + setattr(new, attr, copy.deepcopy(value, memo)) + + return new + def removeChild(self): self.kids -= 1 @@ -1009,6 +1031,57 @@ class PartitionDevice(StorageDevice): else: return self.format.maxSize +class OpticalDevice(StorageDevice): + """ An optical drive, eg: cdrom, dvd+r, &c. + + XXX Is this useful? + """ + _type = "cdrom" + + def __init__(self, installer, name, major=None, minor=None, exists=None, + format=None, parents=None, sysfsPath=''): + StorageDevice.__init__(self, installer, name, format=format, + major=major, minor=minor, exists=True, + parents=parents, sysfsPath=sysfsPath) + + @property + def mediaPresent(self): + """ Return a boolean indicating whether or not the device contains + media. + """ + if not self.exists: + raise DeviceError("device has not been created", self.path) + + try: + fd = os.open(self.path, os.O_RDONLY) + except OSError as e: + # errno 123 = No medium found + if e.errno == 123: + return False + else: + return True + else: + os.close(fd) + return True + + def eject(self): + """ Eject the drawer. """ + #import _isys + + if not self.exists: + raise DeviceError("device has not been created", self.path) + + # Make a best effort attempt to do the eject. If it fails, it's not + # critical. + fd = os.open(self.path, os.O_RDONLY | os.O_NONBLOCK) + + #try: + # _isys.ejectcdrom(fd) + #except SystemError as e: + # log.warning("error ejecting cdrom %s: %s" % (self.name, e)) + + os.close(fd) + class DMDevice(StorageDevice): """ A device-mapper device """ _type = "dm" diff --git a/src/pomona/storage/devicetree.py b/src/pomona/storage/devicetree.py index ff7501415..8d3a1e17e 100644 --- a/src/pomona/storage/devicetree.py +++ b/src/pomona/storage/devicetree.py @@ -1,6 +1,7 @@ #!/usr/bin/python import os +import block import formats @@ -18,6 +19,7 @@ class DeviceTree: self._actions = [] self._ignoredDisks = [] + self.immutableDevices = [] for disk in self.storage.ignoredDisks: self.addIgnoredDisk(disk) @@ -251,46 +253,45 @@ class DeviceTree: sysfs_path = udev_device_get_sysfs_path(info) if self.isIgnored(info): - #self.installer.log.debug("Ignoring %s (%s)" % (name, sysfs_path)) + self.installer.log.debug("Ignoring %s (%s)" % (name, sysfs_path)) return - #self.installer.log.debug("Scanning %s (%s)..." % (name, sysfs_path)) + self.installer.log.debug("Scanning %s (%s)..." % (name, sysfs_path)) device = self.getDeviceByName(name) # # The first step is to either look up or create the device # if udev_device_is_dm(info): - pass - # # try to look up the device - # if device is None and uuid: - # # try to find the device by uuid - # device = self.getDeviceByUuid(uuid) - # - # if device is None: - # device = self.addUdevDMDevice(info) - #elif udev_device_is_md(info): - # if device is None and uuid: - # # try to find the device by uuid - # device = self.getDeviceByUuid(uuid) - # - # if device is None: - # device = self.addUdevMDDevice(info) - #elif udev_device_is_cdrom(info): - # if device is None: - # device = self.addUdevOpticalDevice(info) - #elif udev_device_is_dmraid(info): + # try to look up the device + if device is None and uuid: + # try to find the device by uuid + device = self.getDeviceByUuid(uuid) + + if device is None: + device = self.addUdevDMDevice(info) + elif udev_device_is_md(info): + if device is None and uuid: + # try to find the device by uuid + device = self.getDeviceByUuid(uuid) + + if device is None: + device = self.addUdevMDDevice(info) + elif udev_device_is_cdrom(info): + if device is None: + device = self.addUdevOpticalDevice(info) + elif udev_device_is_dmraid(info): # This is special handling to avoid the "unrecognized disklabel" # code since dmraid member disks won't have a disklabel. We # use a StorageDevice because DiskDevices need disklabels. # Quite lame, but it doesn't matter much since we won't use # the StorageDevice instances for anything. - # if device is None: - # device = StorageDevice(name, - # major=udev_device_get_major(info), - # minor=udev_device_get_minor(info), - # sysfsPath=sysfs_path, exists=True) - # self._addDevice(device) + if device is None: + device = StorageDevice(name, + major=udev_device_get_major(info), + minor=udev_device_get_minor(info), + sysfsPath=sysfs_path, exists=True) + self._addDevice(device) elif udev_device_is_disk(info): if device is None: device = self.addUdevDiskDevice(info) @@ -299,7 +300,7 @@ class DeviceTree: device = self.addUdevPartitionDevice(info) # now handle the device's formatting - #self.handleUdevDeviceFormat(info, device) + self.handleUdevDeviceFormat(info, device) def addUdevDiskDevice(self, info): name = udev_device_get_name(info) @@ -358,6 +359,165 @@ class DeviceTree: self._addDevice(device) return device + def addUdevOpticalDevice(self, info): + # Looks like if it has ID_INSTANCE=0:1 we can ignore it. + device = OpticalDevice(self.installer, udev_device_get_name(info), + major=udev_device_get_major(info), + minor=udev_device_get_minor(info), + sysfsPath=udev_device_get_sysfs_path(info)) + self._addDevice(device) + return device + + def handleUdevDeviceFormat(self, info, device): + #log.debug("%s" % info) + name = udev_device_get_name(info) + sysfs_path = udev_device_get_sysfs_path(info) + uuid = udev_device_get_uuid(info) + label = udev_device_get_label(info) + format_type = udev_device_get_format(info) + + format = None + if (not device) or (not format_type) or device.format.type: + # this device has no formatting or it has already been set up + # FIXME: this probably needs something special for disklabels + self.installer.log.debug("no type or existing type for %s, bailing" % (name,)) + return + + # set up the common arguments for the format constructor + args = [format_type] + kwargs = {"uuid": uuid, + "label": label, + "device": device.path, + "exists": True} + + # set up type-specific arguments for the format constructor + if format_type == "crypto_LUKS": + # luks/dmcrypt + kwargs["name"] = "luks-%s" % uuid + elif format_type == "linux_raid_member": + # mdraid + try: + kwargs["mdUuid"] = udev_device_get_md_uuid(info) + except KeyError: + self.installer.log.debug("mdraid member %s has no md uuid" % name) + elif format_type == "LVM2_member": + # lvm + try: + kwargs["vgName"] = udev_device_get_vg_name(info) + except KeyError as e: + self.installer.log.debug("PV %s has no vg_name" % name) + try: + kwargs["vgUuid"] = udev_device_get_vg_uuid(info) + except KeyError: + self.installer.log.debug("PV %s has no vg_uuid" % name) + try: + kwargs["peStart"] = udev_device_get_pv_pe_start(info) + except KeyError: + self.installer.log.debug("PV %s has no pe_start" % name) + + try: + self.installer.log.debug("type detected on '%s' is '%s'" % (name, format_type,)) + device.format = formats.getFormat(format_type, *args, **kwargs) + except FSError, e: + self.installer.log.debug("type '%s' on '%s' invalid, assuming no format - %s" % + (format_type, name, e,)) + device.format = formats.DeviceFormat(self.installer) + return + + # + # now do any special handling required for the device's format + # + #if device.format.type == "luks": + # self.handleUdevLUKSFormat(info, device) + #elif device.format.type == "mdmember": + # self.handleUdevMDMemberFormat(info, device) + #elif device.format.type == "dmraidmember": + # self.handleUdevDMRaidMemberFormat(info, device) + #elif device.format.type == "lvmpv": + # self.handleUdevLVMPVFormat(info, device) + + def handleUdevDMRaidMemberFormat(self, info, device): + name = udev_device_get_name(info) + sysfs_path = udev_device_get_sysfs_path(info) + uuid = udev_device_get_uuid(info) + major = udev_device_get_major(info) + minor = udev_device_get_minor(info) + + def _all_ignored(rss): + retval = True + for rs in rss: + if rs.name not in self._ignoredDisks: + retval = False + break + return retval + + # Have we already created the DMRaidArrayDevice? + rss = block.getRaidSetFromRelatedMem(uuid=uuid, name=name, + major=major, minor=minor) + if len(rss) == 0: + # we ignore the device in the hope that all the devices + # from this set will be ignored. + # FIXME: Can we reformat a raid device? + self.addIgnoredDisk(device.name) + return + + # We ignore the device if all the rss are in self._ignoredDisks + if _all_ignored(rss): + self.addIgnoredDisk(device.name) + return + + for rs in rss: + dm_array = self.getDeviceByName(rs.name) + if dm_array is not None: + # We add the new device. + dm_array._addDevice(device) + else: + # Activate the Raid set. + rs.activate(mknod=True) + + # Create the DMRaidArray + if self.zeroMbr: + cb = lambda: True + else: + cb = lambda: questionInitializeDisk(self.intf, + rs.name) + + # Create the DMRaidArray + if not self.clearPartDisks or \ + rs.name in self.clearPartDisks: + # if the disk contains protected partitions + # we will not wipe the disklabel even if + # clearpart --initlabel was specified + initlabel = self.reinitializeDisks + for protected in self.protectedPartitions: + disk_name = re.sub(r'p\d+$', '', protected) + if disk_name != protected and \ + disk_name == rs.name: + initlabel = False + break + + try: + dm_array = DMRaidArrayDevice(rs.name, + raidSet=rs, + parents=[device], + initcb=cb, + initlabel=initlabel) + + self._addDevice(dm_array) + # Use the rs's object on the device. + # pyblock can return the memebers of a set and the + # device has the attribute to hold it. But ATM we + # are not really using it. Commenting this out until + # we really need it. + #device.format.raidmem = block.getMemFromRaidSet(dm_array, + # major=major, minor=minor, uuid=uuid, name=name) + except DeviceUserDeniedFormatError: + # We should ignore the dmraid and its components + self.addIgnoredDisk(rs.name) + if _all_ignored(rss): + self.addIgnoredDisk(device.name) + rs.deactivate() + def getDependentDevices(self, dep): """ Return a list of devices that depend on dep. diff --git a/src/pomona/storage/formats/__init__.py b/src/pomona/storage/formats/__init__.py index b5d6f7746..b8fd9bc43 100644 --- a/src/pomona/storage/formats/__init__.py +++ b/src/pomona/storage/formats/__init__.py @@ -1,6 +1,7 @@ #!/usr/bin/python import os +import copy device_formats = {} def register_device_format(fmt_class): @@ -99,7 +100,7 @@ def get_default_filesystem_type(boot=None): raise DeviceFormatError("None of %s is supported by your kernel" % ",".join(fstypes)) -class DeviceFormat: +class DeviceFormat(object): """ Generic device format. """ _type = None _name = "Unknown" @@ -133,6 +134,18 @@ class DeviceFormat: self.options = kwargs.get("options") self._migrate = False + def __deepcopy__(self, memo): + new = self.__class__.__new__(self.__class__) + memo[id(self)] = new + shallow_copy_attrs = ('installer', 'screen') + for (attr, value) in self.__dict__.items(): + if attr in shallow_copy_attrs: + setattr(new, attr, copy.copy(value)) + else: + setattr(new, attr, copy.deepcopy(value, memo)) + + return new + def _setOptions(self, options): self._options = options diff --git a/src/pomona/storage/formats/swap.py b/src/pomona/storage/formats/swap.py index 289f98555..487d3656b 100644 --- a/src/pomona/storage/formats/swap.py +++ b/src/pomona/storage/formats/swap.py @@ -3,6 +3,7 @@ from parted import PARTITION_SWAP from . import DeviceFormat, register_device_format +from ..devicelibs import swap class SwapSpace(DeviceFormat): """ Swap space """ diff --git a/src/pomona/text.py b/src/pomona/text.py index a648b78f8..271931116 100644 --- a/src/pomona/text.py +++ b/src/pomona/text.py @@ -62,7 +62,7 @@ class ExceptionWindow(TextWindow): def run(self): self.rc = ButtonChoiceWindow(self.screen, _("Exception Occurred"), - self.text, self.buttons) + self.text, self.buttons, width=60) def getrc(self): return 0