This code is ready for Rawhide testing and comment.
I've used it on Fedora 11 - 15.

commit b9cdca9fb0ab97239bc68d2184ce16818401a0e2
Author: Frederick Grose <fgrose@sugarlabs.org>
Date:   Sun Sep 18 20:49:01 2011 -0400

    Support liveimage mounting from within a booted LiveOS instance.
    
    Provide functions to add loop devices and remove them on exit, a
    LiveImageMountError(Exception) class for better error handling,
    random device-mapper node names, and the ability to liveimage-mount
    an image (in the LiveOS folder) saved in a plain directory.
    
    Provide a yum cache mount point option,
    bind mount /etc/resolv.conf to permit Internet updating,
    bind mount /dev/mapper to permit device checking,
    support dmsetup versions lacking --noudevrules & --noudevsync,
    miscellaneous code and whitespace optimizations.

diff --git a/tools/liveimage-mount b/tools/liveimage-mount
index 80d67d1..aed7606 100755
--- a/tools/liveimage-mount
+++ b/tools/liveimage-mount
@@ -1,9 +1,10 @@
 #!/usr/bin/python -tt
+# coding: latin-1
+# 2011-09-18 11:47:42 -0400
 #
-# liveimage-mount: Mount a LiveOS at the specified point, and log
-# into a shell.
+# liveimage-mount: Mount a LiveOS at the specified point, and log into a shell.
 #
-# Copyright 2011, Red Hat  Inc.
+# Copyright 2011, Red Hat  Inc., Sugar Labs®
 #   Code for Live mounting an attached LiveOS device added by Frederick Grose,
 #   <fgrose at sugarlabs.org>
 #
@@ -23,23 +24,39 @@
 import os
 import sys
 import stat
+import time
 import getopt
+import random
 import tempfile
 import subprocess
 
+extra_loops = []
 
 def usage(ecode):
     print """Usage:
-        liveimage-mount [opts] ISO.iso|LiveOSdevice MOUNTPOINT [COMMAND] [ARGS]
+       liveimage-mount [opts] ISO.iso|LiveOSdev|dir MOUNTPOINT [COMMAND] [ARGS]
 
                   where [opts] = [-h|--help
                                  [--chroot
                                  [--mount-hacks
-                                 [--persist]]]]]
+                                 [--persist
+                                 [-y|--yumcache=YUMCACHEPATH]]]]]
 
                     and [ARGS] = [arg1[ arg2[ ...]]]\n"""
     sys.exit(ecode)
 
+class LiveImageMountError(Exception):
+    """An exception base class for all liveimage-mount errors."""
+    def __init__(self, msg):
+        Exception.__init__(self, msg)
+    def __str__(self):
+        try:
+            return str(self.message)
+        except UnicodeEncodeError:
+            return repr(self.message)
+
+    def __unicode__(self):
+        return unicode(self.message)
 
 def call(*popenargs, **kwargs):
     '''
@@ -62,43 +79,81 @@ def call(*popenargs, **kwargs):
     return rc
 
 
-def rcall(args, env=None):
-    if env:
+def rcall(args, stdin=None, rpterr=True, env=None):
+    '''Return stdout, stderr, & returncode from a subprocess call.'''
+
+    out, err, p, environ = '', '', None, None
+    if env is not None:
         environ = os.environ.copy()
         environ.update(env)
-    else:
-        environ = None
     try:
-        p = subprocess.Popen(args, stdout=subprocess.PIPE,
-                             stderr=subprocess.PIPE, env=environ)
-        out, err = p.communicate()
+        p = subprocess.Popen(args, stdin=subprocess.PIPE, env=environ,
+                             stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+        out, err = p.communicate(stdin)
     except OSError, e:
-        raise CreatorError(u"Failed to execute:\n'%s'\n'%s'" % (args, e))
+        out, err = out, u'Failed executing:\n%s\nerror: %s' % (args, e)
+        if rpterr:
+            raise LiveImageMountError(u'Failed executing:\n%s\nerror: %s' %
+                                      (args, e))
     except:
-        raise CreatorError(u"""Failed to execute:\n'%s'
-            \renviron: '%s'\nstdout: '%s'\nstderr: '%s'\nreturncode: '%s'""" %
-            (args, environ, out, err, p.returncode))
+        out, err = (out, u'Failed to execute:\n%s\nenviron: %s' %
+                          (args, environ))
+        if rpterr:
+            raise LiveImageMountError(u'''Failed to execute:\n%s
+                               \renviron: %s\nstdout: %s\nstderr: %s''' %
+                               (args, environ, out, err))
     else:
-        if p.returncode != 0:
-            raise CreatorError(u"""Error in call:\n'%s'\nenviron: '%s'
-                \rstdout: '%s'\nstderr: '%s'\nreturncode: '%s'""" %
-                (args, environ, out, err, p.returncode))
-        return out
+        if p.returncode != 0 and rpterr:
+            raise LiveImageMountError(u'''Error in call:\n%s\nenviron: %s
+                               \rstdout: %s\nstderr: %s\nreturncode: %s''' %
+                               (args, environ, out, err, p.returncode))
+    finally:
+        return out, err
+
+
+def get_fsvalue(format=None, tag=None, token=None, filesystem=None):
+    """Return filesystem information based on a blkid tag, token, or device."""
+
+    dev_null = os.open('/dev/null', os.O_WRONLY)
+    args = ['/sbin/blkid', '-c', '/dev/null']
+    if format:
+        args.extend(['-o', format])
+    if tag:
+        args.extend(['-s', tag])
+    if token:
+        args.extend(['-l', '-t', token])
+    if filesystem:
+        args.extend([filesystem])
+    try:
+        fs_value = subprocess.Popen(args,
+                               stdout=subprocess.PIPE,
+                               stderr=dev_null).communicate()[0].rstrip()
+    except IOError, e:
+        raise LiveImageMountError("Failed to determine fs %s: %s" % value, e)
+    finally:
+        os.close(dev_null)
+    return fs_value
 
 
-def get_device_mountpoint(path):
-    """Return the device and mountpoint for a file or device path."""
+def add_loop(n=8):
+    """Add a loop device."""
 
-    info = list()
-    info[0:5] = [None] * 6
-    if os.path.exists(path):
-        st_mode = os.stat(path).st_mode
-        if stat.S_ISBLK(st_mode) or os.path.ismount(path):
-            devinfo = rcall(['/bin/df', path]).splitlines()
-            info = devinfo[1].split(None)
-            if len(info) == 1:
-                info.extend(devinfo[2].split(None))
-    return [info[0], info[5]]
+    while os.path.exists('/dev/loop%s' % n):
+        n += 1
+    os.mknod('/dev/loop%s' % n, 0660 | stat.S_IFBLK, os.makedev(7, n))
+    extra_loops.extend(['/dev/loop%s' % n])
+    return '/dev/loop%s' % n
+
+
+def loop_setup(path, ops=None):
+    """Make and associate a loop device with an image file or device."""
+
+    loop = add_loop()
+    args = ['/sbin/losetup', loop, path]
+    if ops is not None:
+        args += ops
+    call(args)
+    return loop
 
 
 def main():
@@ -108,9 +163,8 @@ def main():
         return 1
 
     try:
-        opts,args = getopt.getopt(sys.argv[1:], 'h', ['help',
-                                                       'chroot', 'persist',
-                                                       'mount-hacks'])
+        opts, args = getopt.getopt(sys.argv[1:], 'hy:', ['help', 'chroot',
+                                   'persist', 'mount-hacks', 'yumcache='])
     except getopt.GetoptError, e:
         usage(1)
 
@@ -118,7 +172,9 @@ def main():
     chroot = False
     persist = False
     mount_hacks = False
-    for o,a in opts:
+    yumcache = None
+    rm_dir = None
+    for o, a in opts:
         if o in ('-h', '--help'):
             usage(0)
         elif o in ('--chroot', ):
@@ -128,49 +184,64 @@ def main():
         elif o in ('--persist', ):
             """Option used to run a command in a spawned process."""
             persist = True
+        elif o in ('-y', '--yumcache'):
+            yumcache = a
 
     if len(args) < 2:
         usage(1)
 
     liveos = args[0]
     destmnt = args[1]
-
+    if not os.path.isdir(destmnt):
+        os.makedirs(destmnt)
+        rm_mnt = destmnt
+    if os.path.ismount(destmnt):
+        print """\n     Exiting...
+        %s is already in use as a mount point.\n""" % destmnt
+        ecode = 1
+        return
+        
     if not os.path.exists(liveos):
         print """\n     Exiting...
         %s is not a file, directory, or device.\n""" % liveos
         ecode = 1
         return
 
-    if stat.S_ISBLK(os.stat(liveos).st_mode):
+    liveos_stat = os.stat(liveos).st_mode
+    if stat.S_ISBLK(liveos_stat):
         img_type = 'blk'
-        imgloop = None
         overlayloop = None
+        liveosmnt = tempfile.mkdtemp(prefix='livemnt-device-')
+    elif stat.S_ISDIR(liveos_stat):
+        img_type = 'dir'
+        liveosmnt = liveos
     else:
         img_type = 'iso'
-
-    if img_type is 'blk':
-        liveosmnt = tempfile.mkdtemp(prefix='livemnt-device-')
-    if img_type is 'iso':
         liveosmnt = tempfile.mkdtemp(prefix='livemnt-iso-')
 
     liveosdir = os.path.join(liveosmnt, 'LiveOS')
     homemnt = None
     dm_cow = None
     mntlive = None
+    rmmntdir = None
+    rm_mnt = None
 
     command = args[2:]
     verbose = not command
 
+    dmsetup_cmd = ['/sbin/dmsetup']
+    if '--noudevsync' in rcall(['/sbin/dmsetup', '-h'])[1]:
+        dmsetup_cmd = ['/sbin/dmsetup', '--noudevrules', '--noudevsync']
+
     squashmnt = tempfile.mkdtemp(prefix='livemnt-squash-')
     squashloop = None
     imgloop = None
-    losetup_args = ['/sbin/losetup', '-f', '--show']
 
     try:
-        if img_type is 'blk':
+        if img_type == 'blk':
             call(['/bin/mount', liveos, liveosmnt])
-        elif img_type is 'iso':
-            liveosloop = rcall(losetup_args + [liveos]).rstrip()
+        elif img_type == 'iso':
+            liveosloop = loop_setup(liveos)
             call(['/bin/mount', '-o', 'ro', liveosloop, liveosmnt])
 
         squash_img = os.path.join(liveosdir, 'squashfs.img')
@@ -182,57 +253,89 @@ def main():
                 ecode = 1
                 return
         else:
-            squashloop = rcall(losetup_args + [squash_img]).rstrip()
+            squashloop = loop_setup(squash_img, ['-r'])
             call(['/bin/mount', '-o', 'ro', squashloop, squashmnt])
             ext3_img = os.path.join(squashmnt, 'LiveOS', 'ext3fs.img')
 
-        if img_type is 'blk':
-            imgloop = rcall(losetup_args + [ext3_img]).rstrip()
-            imgsize = rcall(['/sbin/blockdev', '--getsz', imgloop]).rstrip()
-            files = os.listdir(liveosdir)
-            overlay = None
-            for f in files:
-                if f.find('overlay-') == 0:
-                    overlay = f
-                    break
-            overlayloop = rcall(['/sbin/losetup', '-f']).rstrip()
-            if overlay:
-                call(['/sbin/losetup', overlayloop, os.path.join(liveosdir,
-                                                                 overlay)])
-                dm_cow = 'live-rw'
-            else:
-                overlay = tempfile.NamedTemporaryFile(dir='/dev/shm')
-                print "\npreparing temporary overlay..."
-                call(['/bin/dd', 'if=/dev/null', 'of=%s' % overlay.name,
-                      'bs=1024', 'count=1', 'seek=%s' % (512 * 1024)])
-                call(['/sbin/losetup', overlayloop, overlay.name])
-                dm_cow = 'live-ro'
-            call(['/sbin/dmsetup', '--noudevrules', '--noudevsync',
-                 'create', dm_cow, '--table=0 %s snapshot %s %s p 8' %
-                 (imgsize, imgloop, overlayloop)])
-            call(['/bin/mount', os.path.join('/dev/mapper', dm_cow), destmnt])
-            home_path = os.path.join(liveosdir, 'home.img')
-            if os.path.exists(home_path):
-                homemnt = os.path.join(destmnt, 'home')
-                homeloop = rcall(losetup_args + [home_path]).rstrip()
-                call(['/bin/mount', homeloop, homemnt])
-            mntlive = os.path.join(destmnt, 'mnt', 'live')
-            if not os.path.exists(mntlive):
-                os.makedirs(mntlive)
-            call(['/bin/mount', '--bind', liveosmnt, mntlive])
-        elif img_type is 'iso':
-            imgloop = rcall(losetup_args + [ext3_img]).rstrip()
-            call(['/bin/mount', '-o', 'ro', imgloop, destmnt])
+        if img_type in ('blk', 'dir'):
+            imgloop = loop_setup(ext3_img)
+        elif img_type == 'iso':
+            imgloop = loop_setup(ext3_img, ['-r'])
+        imgsize = rcall(['/sbin/blockdev', '--getsz', imgloop])[0].rstrip()
+        overlay = None
+        for f in os.listdir(liveosdir):
+            if f.find('overlay-') == 0:
+                overlay = f
+                break
+        fd, dm_cow = tempfile.mkstemp(prefix='dm-')
+        os.close(fd)
+        os.unlink(dm_cow)
+        dm_cow = os.path.basename(dm_cow)
+        if overlay:
+            overlayloop = loop_setup(os.path.join(liveosdir, overlay))
+        else:
+            overlay = tempfile.NamedTemporaryFile(dir='/dev/shm')
+            print "\npreparing temporary overlay..."
+            call(['/bin/dd', 'if=/dev/null', 'of=%s' % overlay.name,
+                  'bs=1024', 'count=1', 'seek=%s' % (512 * 1024)])
+            overlayloop = loop_setup(overlay.name)
+        call(dmsetup_cmd + ['create', dm_cow,
+                            '--table=0 %s snapshot %s %s p 8' %
+                            (imgsize, imgloop, overlayloop)])
+        call(['/bin/mount', os.path.join('/dev/mapper', dm_cow), destmnt])
+        home_path = os.path.join(liveosdir, 'home.img')
+        if os.path.exists(home_path):
+            homemnt = os.path.join(destmnt, 'home')
+            homedev = loop_setup(home_path)
+            if get_fsvalue('value', 'TYPE', None,
+                           homedev) == 'crypto_LUKS':
+                call(['/sbin/cryptsetup', 'luksOpen', homedev, 'EncHome'])
+                homedev = os.path.join('/dev', 'mapper', 'EncHome')
+            if img_type in ('blk', 'dir'):
+                call(['/bin/mount', homedev, homemnt])
+            elif img_type == 'iso':
+                call(['/bin/mount', '-o', 'ro', homedev, homemnt])
+        mntlive = os.path.join(destmnt, 'mnt', 'live')
+        if not os.path.isdir(mntlive):
+            os.makedirs(mntlive)
+            rmmntdir = True
+        call(['/bin/mount', '--bind', liveosmnt, mntlive])
 
         if mount_hacks:
-            subprocess.check_call(['mount', '-t', 'proc', 'proc', os.path.join(destmnt, 'proc')], stderr=sys.stderr)
-            subprocess.check_call(['mount', '-t', 'tmpfs', 'tmpfs', os.path.join(destmnt, 'var', 'run')], stderr=sys.stderr)
+            subprocess.check_call(['mount', '-t', 'proc', 'proc',
+                os.path.join(destmnt, 'proc')], stderr=sys.stderr)
+            subprocess.check_call(['mount', '-t', 'tmpfs', 'tmpfs',
+                os.path.join(destmnt, 'var', 'run')], stderr=sys.stderr)
+            subprocess.check_call(['mount', '-t', 'sysfs', 'sys',
+                os.path.join(destmnt, 'sys')], stderr=sys.stderr)
+            subprocess.check_call(['mount', '-t', 'devpts', 'devpts',
+                os.path.join(destmnt, 'dev', 'pts')], stderr=sys.stderr)
+            tmpfs = os.path.join(destmnt, 'dev', 'shm')
+            if not os.path.exists(tmpfs):
+                os.makedirs(tmpfs)
+            subprocess.check_call(['mount', '-t', 'tmpfs', 'tmpfs', tmpfs],
+                                  stderr=sys.stderr)
+            run_dir = os.path.join(destmnt, 'run')
+            if not os.path.exists(run_dir):
+                os.makedirs(run_dir)
+            call(['/bin/mount', '-t', 'tmpfs', 'run', run_dir])
+            if yumcache is not None:
+                call(['/bin/mount', '--bind', yumcache,
+                      os.path.join(destmnt, 'var', 'cache', 'yum')])
+            else:
+                subprocess.check_call(['mount', '-t', 'tmpfs', 'varcacheyum',
+                    os.path.join(destmnt, 'var', 'cache', 'yum')],
+                    stderr=sys.stderr)
+            call(['/bin/mount', '--bind', '/etc/resolv.conf',
+                  os.path.join(destmnt, 'etc', 'resolv.conf')])
+            call(['/bin/mount', '--bind', '/dev/mapper',
+                  os.path.join(destmnt, 'dev', 'mapper')])
 
         if len(command) > 0 and persist:
             args = []
             args.extend(command)
             live = ''
-            if img_type is 'blk':
+            if img_type in ('blk', 'dir'):
                 live = 'live-'
             print """Starting process with this command line:
             \r%s\n  %s is %smounted.""" % (' '.join(command), liveos, live)
@@ -244,50 +347,68 @@ def main():
             args.extend(command)
             ecode = subprocess.call(args, stdin=sys.stdin, stdout=sys.stdout, stderr=sys.stderr)
         elif chroot:
-            print "Starting subshell in chroot, press Ctrl-D to exit..."
+            print "Starting subshell in chroot, press Ctrl D to exit..."
             ecode = subprocess.call(['chroot', destmnt], stdin=sys.stdin, stdout=sys.stdout, stderr=sys.stderr)
         else:
-            if dm_cow == 'live-ro':
+            if img_type in ('blk', 'dir') and dm_cow[:7] == 'live-ro':
                 status = ' with NO LiveOS persistence,'
             else:
                 status = ''
-            print "Entering subshell,%s press Ctrl-D to exit..." % status
+            print "Entering subshell,%s press Ctrl D to exit..." % status
             ecode = subprocess.call([os.environ['SHELL']], cwd=destmnt, stdin=sys.stdin, stdout=sys.stdout, stderr=sys.stderr)
     finally:
+        if verbose:
+            print """Cleaning up...
+            Please wait if large files were written."""
         call(['/bin/sync'])
         if not persist:
-            if verbose:
-                print """Cleaning up...
-                Please wait if large files were written."""
             if mount_hacks:
-                subprocess.call(['umount', os.path.join(destmnt, 'var', 'run')])
-                subprocess.call(['umount', os.path.join(destmnt, 'proc')])
+                call(['umount', os.path.join(destmnt, 'var', 'run')])
+                call(['umount', os.path.join(destmnt, 'proc')])
+                call(['umount', os.path.join(destmnt, 'dev', 'pts')])
+                call(['umount', os.path.join(destmnt, 'sys')])
+                call(['umount', os.path.join(destmnt, 'dev', 'shm')])
+                call(['umount', os.path.join(destmnt, 'run')])
+                call(['umount', os.path.join(destmnt, 'var', 'cache', 'yum')])
+                call(['umount', os.path.join(destmnt, 'etc', 'resolv.conf')])
+                call(['umount', os.path.join(destmnt, 'dev', 'mapper')])
+
             if homemnt:
                 call(['/bin/umount', homemnt])
-                call(['/sbin/losetup', '-d', homeloop])
-            if img_type is 'blk':
-                if mntlive:
-                    call(['/bin/umount', mntlive])
-                    os.rmdir(mntlive)
+                if homedev == os.path.join('/dev', 'mapper', 'EncHome'):
+                    call(dmsetup_cmd + ['remove', 'EncHome'])
+                else:
+                    call(['/sbin/losetup', '-d', homedev])
+            if mntlive:
+                call(['/bin/umount', mntlive])
+                if rmmntdir:
+                    time.sleep(2)
+                    os.removedirs(mntlive)
             if os.path.ismount(destmnt):
+                os.chdir('..')
                 call(['/bin/umount', destmnt])
-            if img_type is 'blk':
-     m_cow:
-                    call(['/sbin/dmsetup', '--noudevrules', '--noudevsync',
-                          'remove', dm_cow])
-                if overlayloop:
-                    call(['/sbin/losetup', '-d', overlayloop])
+            if dm_cow:
+                #FIXME -f force option is sometimes needed when there are
+                # multiple invocations of liveimage-mount active.
+                call(dmsetup_cmd + ['remove', '-f', dm_cow])
+            if overlayloop:
+                call(['/sbin/losetup', '-d', overlayloop])
             if imgloop:
                 call(['/sbin/losetup', '-d', imgloop])
             if squashloop:
                 call(['/bin/umount', squashloop])
                 call(['/sbin/losetup', '-d', squashloop])
-            call(['/bin/umount', liveosmnt])
-            if not img_type is 'blk':
+            if os.path.ismount(liveosmnt):
+                call(['/bin/umount', liveosmnt])
+            if img_type is 'iso':
                 call(['/sbin/losetup', '-d', liveosloop])
             os.rmdir(squashmnt)
-            if not os.path.ismount(liveosmnt):
+            if not os.path.ismount(liveosmnt) and img_type != 'dir':
                 os.rmdir(liveosmnt)
+            time.sleep(2)
+            [call(['/bin/rm', '-f', loop]) for loop in extra_loops]
+            if rm_mnt is not None:
+                os.removedirs(rm_mnt)
             if verbose:
                 print "Cleanup complete"
 

On Thu, Apr 14, 2011 at 12:10 PM, Frederick Grose <fgrose@gmail.com> wrote:
[Patch 3/5]
Author: Frederick Grose <fgrose@sugarlabs.org>
Date:   Thu Apr 14 10:37:13 2011 -0400

    Support usage within a booted LiveOS instance.
   
    Provide functions to add loop devices and remove then on exit, a
    LiveImageMountError(Exception) class for better error handling, and
    random device mapper names.

diff --git a/tools/liveimage-mount b/tools/liveimage-mount
index 80d67d1..1ee5b16 100755
--- a/tools/liveimage-mount
+++ b/tools/liveimage-mount
@@ -23,10 +23,13 @@
 import os
 import sys
 import stat
+import time
 import getopt
+import random
 import tempfile
 import subprocess
 
+extra_loops = []
 
 def usage(ecode):
     print """Usage:
@@ -40,6 +43,18 @@ def usage(ecode):
                     and [ARGS] = [arg1[ arg2[ ...]]]\n"""
     sys.exit(ecode)
 
+class LiveImageMountError(Exception):
+    """An exception base class for all liveimage-mount errors."""
+    def __init__(self, msg):
+        Exception.__init__(self, msg)
+    def __str__(self):
+        try:
+            return str(self.message)
+        except UnicodeEncodeError:
+            return repr(self.message)
+
+    def __unicode__(self):
+        return unicode(self.message)
 
 def call(*popenargs, **kwargs):
     '''
@@ -62,43 +77,57 @@ def call(*popenargs, **kwargs):
     return rc
 
 
-def rcall(args, env=None):
+def rcall(args, stdin=None, stderr=True, env=None):
+    out, err, p, environ = None, None, None, None
     if env:
         environ = os.environ.copy()
         environ.update(env)
-    else:
-        environ = None
     try:
-        p = subprocess.Popen(args, stdout=subprocess.PIPE,
-                             stderr=subprocess.PIPE, env=environ)
-        out, err = p.communicate()
+        p = subprocess.Popen(args, stdin=subprocess.PIPE, env=environ,
+                             stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+        out, err = p.communicate(stdin)
     except OSError, e:
-        raise CreatorError(u"Failed to execute:\n'%s'\n'%s'" % (args, e))
+        raise LiveImageMountError(u"Failed executing:\n'%s'\n'%s'" % (args, e))
     except:
-        raise CreatorError(u"""Failed to execute:\n'%s'
-            \renviron: '%s'\nstdout: '%s'\nstderr: '%s'\nreturncode: '%s'""" %
-            (args, environ, out, err, p.returncode))
+        raise LiveImageMountError(u"""Failed to execute:\n'%s'
+                               \renviron: '%s'\nstdout: '%s'\nstderr: '%s'""" %
+                                  (args, environ, out, err))
     else:
-        if p.returncode != 0:
-            raise CreatorError(u"""Error in call:\n'%s'\nenviron: '%s'
-                \rstdout: '%s'\nstderr: '%s'\nreturncode: '%s'""" %
-                (args, environ, out, err, p.returncode))
+        if p.returncode != 0 and stderr:
+            raise LiveImageMountError(u'''Error in call:\n'%s'\nenviron: '%s'
+                            \rstdout: %s\nstderr: %sreturncode: %s''' %
+                               (args, environ, out, err, p.returncode))
         return out
 
 
-def get_device_mountpoint(path):
-    """Return the device and mountpoint for a file or device path."""
+def get_loop(path):
+    """Return the loop device for a given mount point path."""
+
+    loopdevice = None
+    for loop in rcall(['/sbin/losetup', '-a']).splitlines():
+        info = loop.split()
+        if path == info[2].strip('()'):
+            loopdevice = info[0].rstrip(':')
+            break
+    return loopdevice
+
+
+def add_loop(n=8):
+    """Add a loop device."""
+
+    while os.path.exists('/dev/loop%s' % n):
+        n += 1
+    os.mknod('/dev/loop%s' % n, 0660 | stat.S_IFBLK, os.makedev(7, n))
+    extra_loops.extend(['/dev/loop%s' % n])
+    return '/dev/loop%s' % n
 
-    info = list()
-    info[0:5] = [None] * 6
-    if os.path.exists(path):
-        st_mode = os.stat(path).st_mode
-        if stat.S_ISBLK(st_mode) or os.path.ismount(path):
-            devinfo = rcall(['/bin/df', path]).splitlines()
-            info = devinfo[1].split(None)
-            if len(info) == 1:
-                info.extend(devinfo[2].split(None))
-    return [info[0], info[5]]
+
+def loop_setup(path):
+    """Make and associate a loop device with an image file or device."""
+
+    loop = add_loop()
+    call(['/sbin/losetup', loop, path])
+    return loop
 
 
 def main():
@@ -145,18 +174,16 @@ def main():
         img_type = 'blk'
         imgloop = None
         overlayloop = None
+        liveosmnt = tempfile.mkdtemp(prefix='livemnt-device-')
     else:
         img_type = 'iso'
-
-    if img_type is 'blk':
-        liveosmnt = tempfile.mkdtemp(prefix='livemnt-device-')
-    if img_type is 'iso':
         liveosmnt = tempfile.mkdtemp(prefix='livemnt-iso-')
 
     liveosdir = os.path.join(liveosmnt, 'LiveOS')
     homemnt = None
     dm_cow = None
     mntlive = None
+    rmmntdir = None
 
     command = args[2:]
     verbose = not command
@@ -164,13 +191,12 @@ def main():
     squashmnt = tempfile.mkdtemp(prefix='livemnt-squash-')
     squashloop = None
     imgloop = None
-    losetup_args = ['/sbin/losetup', '-f', '--show']
 
     try:
-        if img_type is 'blk':
+        if img_type == 'blk':
             call(['/bin/mount', liveos, liveosmnt])
-        elif img_type is 'iso':
-            liveosloop = rcall(losetup_args + [liveos]).rstrip()
+        elif img_type == 'iso':
+            liveosloop = loop_setup(liveos)
             call(['/bin/mount', '-o', 'ro', liveosloop, liveosmnt])
 
         squash_img = os.path.join(liveosdir, 'squashfs.img')
@@ -182,12 +208,12 @@ def main():
                 ecode = 1
                 return
         else:
-            squashloop = rcall(losetup_args + [squash_img]).rstrip()
+            squashloop = loop_setup(squash_img)
             call(['/bin/mount', '-o', 'ro', squashloop, squashmnt])
             ext3_img = os.path.join(squashmnt, 'LiveOS', 'ext3fs.img')
 
-        if img_type is 'blk':
-            imgloop = rcall(losetup_args + [ext3_img]).rstrip()
+        if img_type == 'blk':
+            imgloop = loop_setup(ext3_img)
             imgsize = rcall(['/sbin/blockdev', '--getsz', imgloop]).rstrip()
             files = os.listdir(liveosdir)
             overlay = None
@@ -195,18 +221,19 @@ def main():
                 if f.find('overlay-') == 0:
                     overlay = f
                     break
-            overlayloop = rcall(['/sbin/losetup', '-f']).rstrip()
             if overlay:
-                call(['/sbin/losetup', overlayloop, os.path.join(liveosdir,
-                                                                 overlay)])
-                dm_cow = 'live-rw'
+                overlayloop = loop_setup(os.path.join(liveosdir, overlay))
+                dm_cow = "live-rw-%d-%d" % (os.getpid(),
+                                            random.randint(0, 2**16))
+
             else:
                 overlay = tempfile.NamedTemporaryFile(dir='/dev/shm')
                 print "\npreparing temporary overlay..."
                 call(['/bin/dd', 'if=/dev/null', 'of=%s' % overlay.name,
                       'bs=1024', 'count=1', 'seek=%s' % (512 * 1024)])
-                call(['/sbin/losetup', overlayloop, overlay.name])
-                dm_cow = 'live-ro'
+                overlayloop = loop_setup(overlay.name)
+                dm_cow = "live-ro-%d-%d" % (os.getpid(),
+                                            random.randint(0, 2**16))
             call(['/sbin/dmsetup', '--noudevrules', '--noudevsync',
                  'create', dm_cow, '--table=0 %s snapshot %s %s p 8' %
                  (imgsize, imgloop, overlayloop)])
@@ -214,14 +241,15 @@ def main():
             home_path = os.path.join(liveosdir, 'home.img')
             if os.path.exists(home_path):
                 homemnt = os.path.join(destmnt, 'home')
-                homeloop = rcall(losetup_args + [home_path]).rstrip()
+                homeloop = loop_setup(home_path)
                 call(['/bin/mount', homeloop, homemnt])
             mntlive = os.path.join(destmnt, 'mnt', 'live')
             if not os.path.exists(mntlive):
                 os.makedirs(mntlive)
+                rmmntdir = True
             call(['/bin/mount', '--bind', liveosmnt, mntlive])
-        elif img_type is 'iso':
-            imgloop = rcall(losetup_args + [ext3_img]).rstrip()
+        elif img_type == 'iso':
+            imgloop = loop_setup(ext3_img)
             call(['/bin/mount', '-o', 'ro', imgloop, destmnt])
 
         if mount_hacks:
@@ -232,7 +260,7 @@ def main():
             args = []
             args.extend(command)
             live = ''
-            if img_type is 'blk':
+            if img_type == 'blk':
                 live = 'live-'
             print """Starting process with this command line:
             \r%s\n  %s is %smounted.""" % (' '.join(command), liveos, live)
@@ -247,7 +275,7 @@ def main():
             print "Starting subshell in chroot, press Ctrl-D to exit..."
             ecode = subprocess.call(['chroot', destmnt], stdin=sys.stdin, stdout=sys.stdout, stderr=sys.stderr)
         else:
-            if dm_cow == 'live-ro':
+            if img_type == 'blk' and dm_cow[:7] == 'live-ro':
                 status = ' with NO LiveOS persistence,'
             else:
                 status = ''
@@ -268,11 +296,13 @@ def main():
             if img_type is 'blk':
                 if mntlive:
                     call(['/bin/umount', mntlive])
-                    os.rmdir(mntlive)
+                    if rmmntdir:
+                        time.sleep(2)
+                        os.rmdir(mntlive)
             if os.path.ismount(destmnt):
                 call(['/bin/umount', destmnt])
             if img_type is 'blk':
-     m_cow:
+                if dm_cow:
                     call(['/sbin/dmsetup', '--noudevrules', '--noudevsync',
                           'remove', dm_cow])
                 if overlayloop:
@@ -288,6 +318,10 @@ def main():
             os.rmdir(squashmnt)
             if not os.path.ismount(liveosmnt):
                 os.rmdir(liveosmnt)
+            time.sleep(2)
+            for loop in extra_loops:
+                if loop:
+                    call(['/bin/rm', '-f', loop])
             if verbose:
                 print "Cleanup complete"