[PATCH 1/2] Create a DiskLabel format class for partition tables.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



---
 storage/errors.py            |    6 +
 storage/formats/disklabel.py |  261 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 267 insertions(+), 0 deletions(-)
 create mode 100644 storage/formats/disklabel.py

diff --git a/storage/errors.py b/storage/errors.py
index e0175fc..fbc2188 100644
--- a/storage/errors.py
+++ b/storage/errors.py
@@ -88,6 +88,12 @@ class PhysicalVolumeError(DeviceFormatError):
 class SwapSpaceError(DeviceFormatError):
     pass
 
+class DiskLabelError(DeviceFormatError):
+    pass
+
+class InvalidDiskLabelError(DiskLabelError):
+    pass
+
 # devicelibs
 class SwapError(StorageError):
     pass
diff --git a/storage/formats/disklabel.py b/storage/formats/disklabel.py
new file mode 100644
index 0000000..3f8b1e7
--- /dev/null
+++ b/storage/formats/disklabel.py
@@ -0,0 +1,261 @@
+# disklabel.py
+# Device format classes for anaconda's storage configuration module.
+#
+# Copyright (C) 2009  Red Hat, Inc.
+#
+# This copyrighted material is made available to anyone wishing to use,
+# modify, copy, or redistribute it subject to the terms and conditions of
+# the GNU General Public License v.2, or (at your option) any later version.
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY expressed or implied, including the implied warranties of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
+# Public License for more details.  You should have received a copy of the
+# GNU General Public License along with this program; if not, write to the
+# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.  Any Red Hat trademarks that are incorporated in the
+# source code or documentation are not subject to the GNU General Public
+# License and may only be used or replicated with the express permission of
+# Red Hat, Inc.
+#
+# Red Hat Author(s): Dave Lehman <dlehman@xxxxxxxxxx>
+#
+
+import os
+import copy
+
+from iutil import log_method_call
+import parted
+import platform
+from ..errors import *
+from . import DeviceFormat, register_device_format
+
+import gettext
+_ = lambda x: gettext.ldgettext("anaconda", x)
+
+import logging
+log = logging.getLogger("storage")
+
+
+class DiskLabel(DeviceFormat):
+    """ Disklabel """
+    _type = "disklabel"
+    _name = None
+    _formattable = True                # can be formatted
+    _supported = False                 # is supported
+
+    def __init__(self, *args, **kwargs):
+        """ Create a DiskLabel instance.
+
+            Keyword Arguments:
+
+                device -- path to the underlying device
+                exists -- indicates whether this is an existing format
+
+        """
+        log_method_call(self, *args, **kwargs)
+        DeviceFormat.__init__(self, *args, **kwargs)
+
+        self._size = None
+
+        self._partedDevice = None
+        self._partedDisk = None
+        self._origPartedDisk = None
+
+        if self.device:
+            # set up the parted objects and raise exception on failure
+            self._origPartedDisk = self.partedDisk.duplicate()
+
+    def __deepcopy__(self, memo):
+        """ Create a deep copy of a Disklabel 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 = ('_partedDevice', '_partedDisk', '_origPartedDisk')
+        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 resetPartedDisk(self):
+        """ Set this instance's partedDisk to reflect the disk's contents. """
+        log_method_call(self, device=self.device)
+        self._partedDisk = self._origPartedDisk
+
+    def freshPartedDisk(self):
+        """ Return a new, empty parted.Disk instance for this device. """
+        log_method_call(self, device=self.device)
+        labelType = platform.getPlatform(None).diskType
+        return parted.freshDisk(device=self.partedDevice, ty=labelType)
+
+    @property
+    def partedDisk(self):
+        if not self._partedDisk:
+            if self.exists:
+                try:
+                    self._partedDisk = parted.Disk(device=self.partedDevice)
+                except _ped.DiskLabelException as e:
+                    raise InvalidDiskLabelError()
+
+                if self._partedDisk.type == "loop":
+                    # When the device has no partition table but it has a FS,
+                    # it will be created with label type loop.  Treat the
+                    # same as if the device had no label (cause it really
+                    # doesn't).
+                    raise InvalidDiskLabelError()
+            else:
+                self._partedDisk = self.freshPartedDisk()
+
+        return self._partedDisk
+
+    @property
+    def partedDevice(self):
+        if not self._partedDevice and self.device and \
+           os.path.exists(self.device):
+            self._partedDevice = parted.Device(path=self.device)
+
+        return self._partedDevice
+
+    @property
+    def size(self):
+        size = self._size
+        if not size:
+            try:
+                size = self.partedDevice.getSize(unit="MB")
+            except Exception:
+                size = 0
+
+        return size
+
+    @property
+    def status(self):
+        """ Device status. """
+        return (self.exists and self.device and
+                os.path.exists(self.device) and
+                self.partedDevice and self.partedDisk)
+
+    def setup(self, *args, **kwargs):
+        """ Open, or set up, a device. """
+        log_method_call(self, device=self.device,
+                        type=self.type, status=self.status)
+        if not self.exists:
+            raise DeviceFormatError("format has not been created")
+
+        if self.status:
+            return
+
+        DeviceFormat.setup(self, *args, **kwargs)
+
+    def teardown(self, *args, **kwargs):
+        """ Close, or tear down, a device. """
+        log_method_call(self, device=self.device,
+                        type=self.type, status=self.status)
+        if not self.exists:
+            raise DeviceFormatError("format has not been created")
+
+    def create(self, *args, **kwargs):
+        """ Create the device. """
+        log_method_call(self, device=self.device,
+                        type=self.type, status=self.status)
+        if self.exists:
+            raise DeviceFormatError("format already exists")
+
+        if self.status:
+            raise DeviceFormatError("device exists and is active")
+
+        DeviceFormat.create(self, *args, **kwargs)
+        self.commit()
+        self.exists = True
+
+    def destroy(self, *args, **kwargs):
+        """ Wipe the disklabel from the device. """
+        log_method_call(self, device=self.device,
+                        type=self.type, status=self.status)
+        if not self.exists:
+            raise DeviceFormatError("format does not exist")
+
+        if not os.access(self.device, os.W_OK):
+            raise DeviceFormatError("device path does not exist")
+
+        self.partedDisk.clobber()
+        self.commit()
+        self.exists = False
+
+    def commit(self):
+        """ Commit the current partition table to disk and notify the OS. """
+        # give committing 5 tries, failing that, raise an exception
+        attempt = 1
+        maxTries = 5
+        keepTrying = True
+
+        while keepTrying and (attempt <= maxTries):
+            try:
+                self.partedDisk.commit()
+                keepTrying = False
+            except parted.DiskException as msg:
+                log.warning(msg)
+                attempt += 1
+
+        if keepTrying:
+            raise DeviceError("cannot commit to disk after %d attempts" % (maxTries,))
+
+    def addPartition(self, *args, **kwargs):
+        partition = kwargs.get("partition", None)
+        if not partition:
+            partition = args[0]
+        geometry = partition.geometry
+        constraint = kwargs.get("constraint", None)
+        if not constraint and len(args) > 1:
+            constraint = args[1]
+        elif not constraint:
+            constraint = parted.Constraint(exactGeom=geometry)
+
+        new_partition = parted.Partition(disk=self.partedDisk,
+                                         type=partition.type,
+                                         geometry=geometry)
+        self.partedDisk.addPartition(partition=new_partition,
+                                     constraint=constraint)
+
+    def removePartition(self, partition):
+        rempart = self.partedDisk.getPartitionByPath(partition.path)
+        self.partedDisk.removePartition(rempart)
+
+    @property
+    def extendedPartition(self):
+        try:
+            extended = self.partedDisk.getExtendedPartition()
+        except Exception:
+            extended = None
+        return extended
+
+    @property
+    def logicalPartitions(self):
+        try:
+            logicals = self.partedDisk.getLogicalPartitions()
+        except Exception:
+            logicals = []
+        return logicals
+
+    @property
+    def firstPartition(self):
+        try:
+            part = self.partedDisk.getFirstPartition()
+        except Exception:
+            part = None
+        return part
+
+    @property
+    def partitions(self):
+        try:
+            parts = self.partedDisk.partitions
+        except Exception:
+            parts = []
+        return parts
+
+register_device_format(DiskLabel)
+
-- 
1.6.0.6

_______________________________________________
Anaconda-devel-list mailing list
Anaconda-devel-list@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/anaconda-devel-list

[Index of Archives]     [Kickstart]     [Fedora Users]     [Fedora Legacy List]     [Fedora Maintainers]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [Yosemite Photos]     [KDE Users]     [Fedora Tools]
  Powered by Linux