--- 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@xxxxxxxxxx> +# + +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 _______________________________________________ Anaconda-devel-list mailing list Anaconda-devel-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/anaconda-devel-list