From 4b368aab8717ee55f1c1d6b9d52406b882da924b Mon Sep 17 00:00:00 2001 From: "Brian C. Lane" Date: Fri, 11 May 2012 17:35:16 -0700 Subject: [PATCH] livemedia-creator: cleanup after a crash Make sure we don't leave any device-mapper or loop devices laying around after a crash. --- src/pylorax/imgutils.py | 10 ++++++++++ src/sbin/livemedia-creator | 22 +++++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/pylorax/imgutils.py b/src/pylorax/imgutils.py index 2b760d31..c78d179d 100644 --- a/src/pylorax/imgutils.py +++ b/src/pylorax/imgutils.py @@ -72,6 +72,16 @@ def loop_detach(loopdev): '''Detach the given loop device. Return False on failure.''' return (call(["losetup", "--detach", loopdev]) == 0) +def get_loop_name(path): + '''Return the loop device associated with the path. + Raises RuntimeError if more than one loop is associated''' + buf = check_output(["losetup", "-j", path], stderr=PIPE) + if len(buf.splitlines()) > 1: + # there should never be more than one loop device listed + raise RuntimeError("multiple loops associated with %s" % path) + name = os.path.basename(buf.split(":")[0]) + return name + def dm_attach(dev, size, name=None): '''Attach a devicemapper device to the given device, with the given size. If name is None, a random name will be chosen. Returns the device name. diff --git a/src/sbin/livemedia-creator b/src/sbin/livemedia-creator index 1c1a5ec5..ef4b670e 100755 --- a/src/sbin/livemedia-creator +++ b/src/sbin/livemedia-creator @@ -45,7 +45,8 @@ from pykickstart.version import makeVersion from pylorax.base import DataHolder from pylorax.treebuilder import TreeBuilder, RuntimeBuilder, udev_escape from pylorax.sysutils import joinpaths, remove, linktree -from pylorax.imgutils import PartitionMount, mksparse, mkext4img +from pylorax.imgutils import PartitionMount, mksparse, mkext4img, loop_detach +from pylorax.imgutils import get_loop_name, dm_detach from pylorax.executils import execWithRedirect, execWithCapture # no-virt mode doesn't need libvirt, so make it optional @@ -385,6 +386,17 @@ class VirtualInstall( object ): subprocess.call(["virsh","destroy",self.virt_name]) subprocess.call(["virsh","undefine",self.virt_name]) +def is_image_mounted(disk_img): + """ + Return True if the disk_img is mounted + """ + with open("/proc/mounts") as mounts: + for mount in mounts: + fields = mount.split() + if len(fields) > 2 and fields[1] == disk_img: + return True + return False + def anaconda_install( disk_img, disk_size, kickstart, repo, args ): """ @@ -704,6 +716,14 @@ if __name__ == '__main__': if os.path.exists( "/tmp/"+l ): shutil.copy2( "/tmp/"+l, log_anaconda ) os.unlink( "/tmp/"+l ) + + # If anaconda failed the disk image may still be in use by dm + dm_name = os.path.splitext(os.path.basename(disk_img))[0] + dm_path = "/dev/mapper/"+dm_name + if os.path.exists(dm_path): + dm_detach(dm_path) + loop_detach(get_loop_name(disk_img)) + else: iso_mount = IsoMountpoint( opts.iso ) log_monitor = LogMonitor( install_log )