[SoaS] [PATCH 3a/6] substitute was: [PATCH 3/5] Liveimage-mount within running LiveOS instance

Frederick Grose fgrose at sugarlabs.org
Sun Sep 18 21:28:48 EDT 2011


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

commit b9cdca9fb0ab97239bc68d2184ce16818401a0e2
Author: Frederick Grose <fgrose at 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 at gmail.com> wrote:

> [Patch 3/5]
> Author: Frederick Grose <fgrose at 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"
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.sugarlabs.org/archive/soas/attachments/20110918/40dccc9d/attachment-0001.html>


More information about the SoaS mailing list