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

[PATCH 05/16] Add support for loop devices.



---
 pyanaconda/storage/devicelibs/loop.py |   99 +++++++++++++++++++++++++++++++
 pyanaconda/storage/devices.py         |  103 +++++++++++++++++++++++++++++++++
 pyanaconda/storage/errors.py          |    3 +
 3 files changed, 205 insertions(+), 0 deletions(-)
 create mode 100644 pyanaconda/storage/devicelibs/loop.py

diff --git a/pyanaconda/storage/devicelibs/loop.py b/pyanaconda/storage/devicelibs/loop.py
new file mode 100644
index 0000000..298e613
--- /dev/null
+++ b/pyanaconda/storage/devicelibs/loop.py
@@ -0,0 +1,99 @@
+#
+# loop.py
+# loop device functions
+#
+# Copyright (C) 2010  Red Hat, Inc.  All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty 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, see <http://www.gnu.org/licenses/>.
+#
+# Author(s): David Lehman <dlehman redhat com>
+#
+
+import os
+
+from pyanaconda import iutil
+from ..errors import *
+
+import gettext
+_ = lambda x: gettext.ldgettext("anaconda", x)
+
+import logging
+log = logging.getLogger("storage")
+
+
+def losetup(args, capture=False):
+    if capture:
+        exec_func = iutil.execWithCapture
+        exec_kwargs = {}
+    else:
+        exec_func = iutil.execWithRedirect
+        exec_kwargs = {"stdout": "/dev/tty5"}
+
+    try:
+        # ask losetup what this loop device's backing device is
+        ret = exec_func("losetup", args,
+                        stderr="/dev/tty5",
+                        **exec_kwargs)
+    except RuntimeError as e:
+        raise LoopError(e.message)
+
+    return ret
+
+def get_device_path(name):
+    args = ["/dev/" + name]
+    buf = losetup(args, capture=True)
+    try:
+        start = buf.index("(") + 1
+        end = buf.rindex(")")
+        path = buf[start:end]
+    except IndexError:
+        path = ""
+
+    log.debug("get_device_path(%s) got '%s'" % (name, path))
+    return path
+
+def get_loop_name(path):
+    args = ["-j", path]
+    buf = losetup(args, capture=True)
+    if len(buf.splitlines()) > 1:
+        # there should never be more than one loop device listed
+        raise LoopError("multiple loops associated with %s" % path)
+
+    name = os.path.basename(buf.split(":")[0])
+    log.debug("get_loop_name(%s) got '%s'" % (path, name))
+    return name
+
+def loop_setup(path):
+    args = ["-f", path]
+    msg = None
+    try:
+        msg = losetup(args)
+    except LoopError as e:
+        msg = e.message
+
+    if msg:
+        raise LoopError("failed to set up loop for %s: %s" % (path, msg))
+
+def loop_teardown(path):
+    args = ["-d", path]
+    msg = None
+    try:
+        msg = losetup(args)
+    except LoopError as e:
+        msg = e.message
+
+    if msg:
+        raise DeviceError("failed to tear down loop %s: %s" % (path, msg))
+
+
diff --git a/pyanaconda/storage/devices.py b/pyanaconda/storage/devices.py
index 026d337..dc4d930 100644
--- a/pyanaconda/storage/devices.py
+++ b/pyanaconda/storage/devices.py
@@ -102,6 +102,7 @@ import time
 from devicelibs import mdraid
 from devicelibs import lvm
 from devicelibs import dm
+from devicelibs import loop
 import parted
 import _ped
 import block
@@ -3570,6 +3571,108 @@ class DirectoryDevice(FileDevice):
         self.exists = False
 
 
+class LoopDevice(StorageDevice):
+    """ A loop device. """
+    _type = "loop"
+
+    def __init__(self, name=None, format=None, size=None, sysfsPath=None,
+                 exists=None, parents=None):
+        """ Create a LoopDevice instance.
+
+            Arguments:
+
+                name -- the device's name
+
+            Keyword Arguments:
+
+                format -- a DeviceFormat instance
+                size -- the device's size in MB
+                parents -- a list of required devices (Device instances)
+                exists -- indicates whether this is an existing device
+
+
+            Loop devices always exist.
+        """
+        if not parents:
+            raise ValueError("LoopDevice requires a backing device")
+
+        if not name:
+            # set up a temporary name until we've activated the loop device
+            name = "tmploop%d" % Device._id
+
+        StorageDevice.__init__(self, name, format=format, size=size,
+                               exists=True, parents=parents)
+
+    def updateName(self):
+        """ Update this device's name. """
+        if not self.slave.status:
+            # if the backing device is inactive, so are we
+            return self.name
+
+        if self.name.startswith("loop"):
+            # if our name is loopN we must already be active
+            return self.name
+
+        name = loop.get_loop_name(self.slave.path)
+        if name.startswith("loop"):
+            self._name = name
+
+        return self.name
+
+    @property
+    def status(self):
+        #return (self.sysfsPath and
+        #        os.path.isdir("/sys" + self.sysfsPath) and
+        #        len(os.listdir("/sys" + self.sysfsPath + '/holders')) > 0)
+        return (self.slave.status and
+                self.name.startswith("loop") and
+                loop.get_loop_name(self.slave.path) == self.name)
+
+    @property
+    def size(self):
+        return self.slave.size
+
+    def setup(self, intf=None, orig=False):
+        """ Open, or set up, a device. """
+        log_method_call(self, self.name, orig=orig, status=self.status)
+        if not self.exists:
+            raise DeviceError("device has not been created", self.name)
+
+        if self.status:
+            return
+
+        loop.loop_setup(self.slave.path)
+        udev_settle()
+        self.updateName()
+        self.updateSysfsPath()
+        self._size = self.currentSize
+
+    def teardown(self, recursive=False):
+        """ Close, or tear down, a device. """
+        log_method_call(self, self.name, status=self.status)
+        if not self.exists and not recursive:
+            raise DeviceError("device has not been created", self.name)
+
+        if self.status:
+            if self.originalFormat.exists:
+                self.originalFormat.teardown()
+            if self.format.exists:
+                self.format.teardown()
+            udev_settle()
+
+        loop.loop_teardown(self.path)
+        udev_settle()
+        self.updateSysfsPath()
+        self._name = "tmploop%d" % self.id
+
+        if recursive:
+            self.teardownParents(recursive=recursive)
+
+    @property
+    def slave(self):
+        return self.parents[0]
+
+
 class iScsiDiskDevice(DiskDevice, NetworkStorageDevice):
     """ An iSCSI disk. """
     _type = "iscsi"
diff --git a/pyanaconda/storage/errors.py b/pyanaconda/storage/errors.py
index e53bb23..39f75c0 100644
--- a/pyanaconda/storage/errors.py
+++ b/pyanaconda/storage/errors.py
@@ -125,6 +125,9 @@ class CryptoError(StorageError):
 class MPathError(StorageError):
     pass
 
+class LoopError(StorageError):
+    pass
+
 # DeviceTree
 class DeviceTreeError(StorageError):
     pass
-- 
1.7.3.2


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