When using the entire disk, whole-disk formats are replaced with a new disklabel. When replacing existing linux installations, linux- native whole-disk formats are replaced with a new disklabel. Disks containing whole-disk formatting are not offered as bootloader installation targets. --- iw/autopart_type.py | 85 ++++++++++++++++++++++++++++++++++------ iw/partition_ui_helpers_gui.py | 9 ++-- storage/partitioning.py | 80 ++++++++++++++++++++++++-------------- 3 files changed, 129 insertions(+), 45 deletions(-) diff --git a/iw/autopart_type.py b/iw/autopart_type.py index fc0e4be..c0dfcd8 100644 --- a/iw/autopart_type.py +++ b/iw/autopart_type.py @@ -34,6 +34,8 @@ import network from storage import iscsi from storage import fcoe from storage.deviceaction import * +from storage.partitioning import shouldClear +import isys import gettext _ = lambda x: gettext.ldgettext("anaconda", x) @@ -211,6 +213,16 @@ class PartitionTypeWindow(InstallWindow): if not rc: raise gui.StayOnScreen + # our list of bootloader drives may contain some drives not in + # the bootloader's list because of unpartitioned drives that + # were selected for clearing and will therefore be partitioned + # by the time we install the bootloader + for drive in self.bl_drivelist: + if drive.name not in self.anaconda.id.bootloader.drivelist: + self.anaconda.id.bootloader.drivelist.append(drive.name) + self.anaconda.id.bootloader.drivelist.sort(isys.compareDrives) + + # put the chosen boot device at the front of the list self.anaconda.id.bootloader.drivelist.remove(defboot) self.anaconda.id.bootloader.drivelist.insert(0, defboot) @@ -251,6 +263,58 @@ class PartitionTypeWindow(InstallWindow): self.xml.get_widget("bootDriveCombo").set_sensitive(True) self.xml.get_widget("encryptButton").set_sensitive(True) + self.updateDriveLists() + + def updateDriveLists(self): + active = self.combo.get_active_iter() + clearpart = self.combo.get_model().get_value(active, 1) + + # modify self.bootcombo and self.drivelist to reflect the current + # projected set of partitioned disks + disallowed = [self.anaconda.updateSrc] + disks = self.storage.disks + partitioned = self.storage.partitioned + if clearpart not in [CLEARPART_TYPE_ALL, -1]: + # only disks that are already partitioned or whose whole-disk + # formatting is "linux native" should be allowed + for disk in disks: + if disk not in partitioned and not shouldClear(disk, clearpart): + disallowed.append(disk.name) + else: + # for CLEARPART_TYPE_ALL and custom layouts all disks should be + # allowed since we'll put a disklabel on any unlabeled disks we + # clear + disks = self.storage.disks + + createAllowedDrivesStore(self.storage.disks, + self.storage.clearPartDisks, + self.drivelist, + disallowDrives=disallowed) + + # Figure out which disks are selected for populating the bootloader + # combo. Also deselect unsuitable disks and ensure they cannot be + # selected. + selections = {} + row_iter = iter(self.drivelist.get_model()) + for row in row_iter: + (selected, drive, size, desc, sensitive) = tuple(row) + selections[drive] = selected + + if self.drivelist.sensitivity_col is not None: + row[self.drivelist.sensitivity_col] = drive not in disallowed + + if drive in disallowed: + row[0] = False + + # bootloader is unusual in that we only want to look at disks that + # have disklabels -- no partitioned md or unpartitioned disks + self.bl_drivelist = [] + for disk in self.storage.disks: + if selections[disk.name] and disk.name not in disallowed: + self.bl_drivelist.append(disk) + self.bl_drivelist.sort(cmp=isys.compareDrives, key=lambda d: d.name) + self._fillBootStore() + def addIscsiDrive(self): if not network.hasActiveNetDev(): net = NetworkConfigurator(self.anaconda.id.network) @@ -487,24 +551,22 @@ class PartitionTypeWindow(InstallWindow): w = self.intf.waitWindow(_("Rescanning disks"), _("Rescanning disks")) self.storage.reset() - createAllowedDrivesStore(self.storage.disks, - self.storage.clearPartDisks, - self.drivelist, - disallowDrives=[self.anaconda.updateSrc]) - self._fillBootStore() + self.updateDriveLists() w.pop() def _fillBootStore(self): + # this isn't strictly necessary, but it can't hurt -- especially if + # the user has added drives via iscsi or fcoe or similar self.anaconda.id.bootloader.updateDriveList() + bootstore = self.bootcombo.get_model() bootstore.clear() - if len(self.anaconda.id.bootloader.drivelist) > 0: - defaultBoot = self.anaconda.id.bootloader.drivelist[0] + if len(self.bl_drivelist) > 0: + defaultBoot = self.bl_drivelist[0].name else: defaultBoot = None - for disk in self.storage.disks: - if disk.name not in self.anaconda.id.bootloader.drivelist: - continue + + for disk in self.bl_drivelist: dispstr = "%s %8.0f MB %s" %(disk.name, disk.size, disk.description) i = bootstore.append(None) bootstore[i] = (dispstr, disk.name) @@ -574,7 +636,7 @@ class PartitionTypeWindow(InstallWindow): bootstore = gtk.TreeStore(gobject.TYPE_STRING, gobject.TYPE_STRING) self.bootcombo.set_model(bootstore) - self._fillBootStore() + self.updateDriveLists() self.prevrev = None self.review = not self.dispatch.stepInSkipList("partition") @@ -604,5 +666,4 @@ class PartitionTypeWindow(InstallWindow): sigs = { "on_partitionTypeCombo_changed": self.comboChanged, "on_addButton_clicked": self.addDrive } self.xml.signal_autoconnect(sigs) - return vbox diff --git a/iw/partition_ui_helpers_gui.py b/iw/partition_ui_helpers_gui.py index ee6d0ac..2f05a6e 100644 --- a/iw/partition_ui_helpers_gui.py +++ b/iw/partition_ui_helpers_gui.py @@ -166,10 +166,11 @@ def createAllowedDrivesStore(disks, reqdrives, drivelist, selectDrives=True, def createAllowedDrivesList(disks, reqdrives, selectDrives=True, disallowDrives=[]): store = gtk.TreeStore(gobject.TYPE_BOOLEAN, - gobject.TYPE_STRING, - gobject.TYPE_STRING, - gobject.TYPE_STRING) - drivelist = WideCheckList(3, store) + gobject.TYPE_STRING, + gobject.TYPE_STRING, + gobject.TYPE_STRING, + gobject.TYPE_BOOLEAN) + drivelist = WideCheckList(3, store, sensitivity=True) createAllowedDrivesStore(disks, reqdrives, drivelist, selectDrives=selectDrives, disallowDrives=disallowDrives) diff --git a/storage/partitioning.py b/storage/partitioning.py index 1bb1567..101f6d4 100644 --- a/storage/partitioning.py +++ b/storage/partitioning.py @@ -32,6 +32,7 @@ from constants import * from errors import * from deviceaction import * from devices import PartitionDevice, LUKSDevice, devicePathToName +from formats import getFormat import gettext _ = lambda x: gettext.ldgettext("anaconda", x) @@ -276,37 +277,40 @@ def doAutoPartition(anaconda): anaconda.id.storage.reset() return DISPATCH_BACK -def shouldClear(part, clearPartType, clearPartDisks=None): - if not isinstance(part, PartitionDevice): +def shouldClear(device, clearPartType, clearPartDisks=None): + if clearPartType not in [CLEARPART_TYPE_LINUX, CLEARPART_TYPE_ALL]: return False - if not clearPartType in [CLEARPART_TYPE_LINUX, CLEARPART_TYPE_ALL]: - return False - - # Never clear the special first partition on a Mac disk label, as that - # holds the partition table itself. - if part.disk.format.partedDisk.type == "mac" and \ - part.partedPartition.number == 1 and \ - part.partedPartition.name == "Apple": - return False - - # If we got a list of disks to clear, make sure this one's on it - if clearPartDisks and part.disk.name not in clearPartDisks: - return False - - # Don't clear partitions holding install media. - if part.protected: - return False - - # We don't want to fool with extended partitions, freespace, &c - if part.partType not in [parted.PARTITION_NORMAL, parted.PARTITION_LOGICAL]: - return False - - if clearPartType == CLEARPART_TYPE_LINUX and \ - not part.format.linuxNative and \ - not part.getFlag(parted.PARTITION_LVM) and \ - not part.getFlag(parted.PARTITION_RAID) and \ - not part.getFlag(parted.PARTITION_SWAP): + if isinstance(device, PartitionDevice): + # Never clear the special first partition on a Mac disk label, as that + # holds the partition table itself. + if device.disk.format.partedDisk.type == "mac" and \ + device.partedPartition.number == 1 and \ + device.partedPartition.name == "Apple": + return False + + # If we got a list of disks to clear, make sure this one's on it + if clearPartDisks and device.disk.name not in clearPartDisks: + return False + + # We don't want to fool with extended partitions, freespace, &c + if device.partType not in [parted.PARTITION_NORMAL, + parted.PARTITION_LOGICAL]: + return False + + if clearPartType == CLEARPART_TYPE_LINUX and \ + not device.format.linuxNative and \ + not device.getFlag(parted.PARTITION_LVM) and \ + not device.getFlag(parted.PARTITION_RAID) and \ + not device.getFlag(parted.PARTITION_SWAP): + return False + elif device.isDisk and not device.partitioned: + if clearPartType == CLEARPART_TYPE_LINUX and \ + not device.format.linuxNative: + return False + + # Don't clear devices holding install media. + if device.protected: return False # TODO: do platform-specific checks on ia64, pSeries, iSeries, mac @@ -377,6 +381,24 @@ def removeEmptyExtendedPartitions(storage): storage.destroyDevice(extended) #disk.partedDisk.removePartition(extended.partedPartition) + for disk in [d for d in storage.disks if d not in storage.partitioned]: + # clear any whole-disk formats that need clearing + if shouldClear(disk, storage.clearPartType, storage.clearPartDisks): + log.debug("clearing %s" % disk.name) + devices = storage.deviceDeps(disk) + while devices: + log.debug("devices to remove: %s" % ([d.name for d in devices],)) + leaves = [d for d in devices if d.isleaf] + log.debug("leaves to remove: %s" % ([d.name for d in leaves],)) + for leaf in leaves: + storage.destroyDevice(leaf) + devices.remove(leaf) + + destroy_action = ActionDestroyFormat(disk) + newLabel = getFormat("disklabel", device=disk.path) + create_action = ActionCreateFormat(disk, format=newLabel) + storage.devicetree.registerAction(destroy_action) + storage.devicetree.registerAction(create_action) def partitionCompare(part1, part2): """ More specifically defined partitions come first. -- 1.6.5.2 _______________________________________________ Anaconda-devel-list mailing list Anaconda-devel-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/anaconda-devel-list