[Fedora-livecd-list] [PATCH] -Refactor-disk-mount-classes-to-allow-multi-partitions

huff dhuff at redhat.com
Wed May 21 14:40:47 UTC 2008


---
 imgcreate/creator.py |   17 ++--
 imgcreate/fs.py      |  250 ++++++++++++++++++++++++++++++++------------------
 imgcreate/live.py    |    6 +-
 3 files changed, 175 insertions(+), 98 deletions(-)

diff --git a/imgcreate/creator.py b/imgcreate/creator.py
index febb847..7ccbef9 100644
--- a/imgcreate/creator.py
+++ b/imgcreate/creator.py
@@ -208,7 +208,11 @@ class ImageCreator(object):
 
         """
         s =  "/dev/root  /         %s    defaults,noatime 0 0\n" %(self._fstype)
-        s += "devpts     /dev/pts  devpts  gid=5,mode=620   0 0\n"
+        s += self._get_fstab_special()
+        return s
+
+    def _get_fstab_special(self):
+        s = "devpts     /dev/pts  devpts  gid=5,mode=620   0 0\n"
         s += "tmpfs      /dev/shm  tmpfs   defaults         0 0\n"
         s += "proc       /proc     proc    defaults         0 0\n"
         s += "sysfs      /sys      sysfs   defaults         0 0\n"
@@ -840,12 +844,11 @@ class LoopImageCreator(ImageCreator):
         if not base_on is None:
             shutil.copyfile(base_on, self._image)
 
-        self.__instloop = SparseExtLoopbackMount(self._image,
-                                                 self._instroot,
-                                                 self.__image_size,
-                                                 self.__fstype,
-                                                 self.__blocksize,
-                                                 self.fslabel)
+        self.__instloop = ExtDiskMount(SparseLoopbackDisk(self._image, self.__image_size),
+                                       self._instroot,
+                                       self.__fstype,
+                                       self.__blocksize,
+                                       self.fslabel)
 
         try:
             self.__instloop.mount()
diff --git a/imgcreate/fs.py b/imgcreate/fs.py
index 98c0db4..314a776 100644
--- a/imgcreate/fs.py
+++ b/imgcreate/fs.py
@@ -24,6 +24,7 @@ import stat
 import subprocess
 import random
 import string
+import logging
 
 from imgcreate.errors import *
 
@@ -86,42 +87,51 @@ class BindChrootMount:
         subprocess.call(["/bin/umount", self.dest])
         self.mounted = False
 
-class LoopbackMount:
-    def __init__(self, lofile, mountdir, fstype = None):
-        self.lofile = lofile
-        self.mountdir = mountdir
-        self.fstype = fstype
+class Disk:
+    def __init__(self, size, device = None):
+        self._device = device
+        self._size = size
 
-        self.mounted = False
-        self.losetup = False
-        self.rmdir   = False
-        self.loopdev = None
+    def create(self):
+        pass
 
     def cleanup(self):
-        self.unmount()
-        self.lounsetup()
+        pass
 
-    def unmount(self):
-        if self.mounted:
-            rc = subprocess.call(["/bin/umount", self.mountdir])
-            if rc == 0:
-                self.mounted = False
+    def get_device(self):
+        return self._device
+    def set_device(self, path):
+        self._device = path
+    device = property(get_device, set_device)
 
-        if self.rmdir and not self.mounted:
-            try:
-                os.rmdir(self.mountdir)
-            except OSError, e:
-                pass
-            self.rmdir = False
+    def get_size(self):
+        return self._size
+    size = property(get_size)
+
+
+class RawDisk(Disk):
+    def __init__(self, size, device):
+        Disk.__init__(self, size, device)
+
+    def fixed(self):
+        return True
+
+    def exists(self):
+        return True
+
+class LoopbackDisk(Disk):
+    def __init__(self, lofile, size):
+        Disk.__init__(self, size)
+        self.lofile = lofile
+
+    def fixed(self):
+        return False
 
-    def lounsetup(self):
-        if self.losetup:
-            rc = subprocess.call(["/sbin/losetup", "-d", self.loopdev])
-            self.losetup = False
-            self.loopdev = None
+    def exists(self):
+        return os.path.exists(self.lofile)
 
-    def loopsetup(self):
-        if self.losetup:
+    def create(self):
+        if self.device is not None:
             return
 
         losetupProc = subprocess.Popen(["/sbin/losetup", "-f"],
@@ -132,40 +142,27 @@ class LoopbackMount:
             raise MountError("Failed to allocate loop device for '%s'" %
                              self.lofile)
 
-        self.loopdev = losetupOutput.split()[0]
+        device = losetupOutput.split()[0]
 
-        rc = subprocess.call(["/sbin/losetup", self.loopdev, self.lofile])
+        logging.debug("Losetup add %s mapping to %s"  % (device, self.lofile))
+        rc = subprocess.call(["/sbin/losetup", device, self.lofile])
         if rc != 0:
             raise MountError("Failed to allocate loop device for '%s'" %
                              self.lofile)
+        self.device = device
 
-        self.losetup = True
-
-    def mount(self):
-        if self.mounted:
+    def cleanup(self):
+        if self.device is None:
             return
+        logging.debug("Losetup remove %s" % self.device)
+        rc = subprocess.call(["/sbin/losetup", "-d", self.device])
+        self.device = None
 
-        self.loopsetup()
 
-        if not os.path.isdir(self.mountdir):
-            os.makedirs(self.mountdir)
-            self.rmdir = True
 
-        args = [ "/bin/mount", self.loopdev, self.mountdir ]
-        if self.fstype:
-            args.extend(["-t", self.fstype])
-
-        rc = subprocess.call(args)
-        if rc != 0:
-            raise MountError("Failed to mount '%s' to '%s'" %
-                             (self.loopdev, self.mountdir))
-
-        self.mounted = True
-
-class SparseLoopbackMount(LoopbackMount):
-    def __init__(self, lofile, mountdir, size, fstype = None):
-        LoopbackMount.__init__(self, lofile, mountdir, fstype)
-        self.size = size
+class SparseLoopbackDisk(LoopbackDisk):
+    def __init__(self, lofile, size):
+        LoopbackDisk.__init__(self, lofile, size)
 
     def expand(self, create = False, size = None):
         flags = os.O_WRONLY
@@ -176,6 +173,7 @@ class SparseLoopbackMount(LoopbackMount):
         if size is None:
             size = self.size
 
+        logging.debug("Extending sparse file %s to %d" % (self.lofile, size))
         fd = os.open(self.lofile, flags)
 
         os.lseek(fd, size, 0)
@@ -185,36 +183,107 @@ class SparseLoopbackMount(LoopbackMount):
     def truncate(self, size = None):
         if size is None:
             size = self.size
+
+        logging.debug("Truncating sparse file %s to %d" % (self.lofile, size))
         fd = os.open(self.lofile, os.O_WRONLY)
         os.ftruncate(fd, size)
         os.close(fd)
 
     def create(self):
         self.expand(create = True)
+        LoopbackDisk.create(self)
+
+class Mount:
+    def __init__(self, mountdir):
+        self.mountdir = mountdir
+
+    def cleanup(self):
+        self.unmount()
+
+    def mount(self):
+        pass
+
+    def unmount(self):
+        pass
+
+class DiskMount(Mount):
+    def __init__(self, disk, mountdir, fstype = None, rmmountdir = True):
+        Mount.__init__(self, mountdir)
+
+        self.disk = disk
+        self.fstype = fstype
+        self.rmmountdir = rmmountdir
+
+        self.mounted = False
+        self.rmdir   = False
+
+    def cleanup(self):
+        Mount.cleanup(self)
+        self.disk.cleanup()
+
+    def unmount(self):
+        if self.mounted:
+            logging.debug("Unmounting directory %s" % self.mountdir)
+            rc = subprocess.call(["/bin/umount", self.mountdir])
+            if rc == 0:
+                self.mounted = False
+
+        if self.rmdir and not self.mounted:
+            try:
+                os.rmdir(self.mountdir)
+            except OSError, e:
+                pass
+            self.rmdir = False
+
+
+    def __create(self):
+        self.disk.create()
+
 
-class SparseExtLoopbackMount(SparseLoopbackMount):
-    def __init__(self, lofile, mountdir, size, fstype, blocksize, fslabel):
-        SparseLoopbackMount.__init__(self, lofile, mountdir, size, fstype)
+    def mount(self):
+        if self.mounted:
+            return
+
+        if not os.path.isdir(self.mountdir):
+            logging.debug("Creating mount point %s" % self.mountdir)
+            os.makedirs(self.mountdir)
+            self.rmdir = self.rmmountdir
+
+        self.__create()
+
+        logging.debug("Mounting %s at %s" % (self.disk.device, self.mountdir))
+        args = [ "/bin/mount", self.disk.device, self.mountdir ]
+        if self.fstype:
+            args.extend(["-t", self.fstype])
+
+        rc = subprocess.call(args)
+        if rc != 0:
+            raise MountError("Failed to mount '%s' to '%s'" %
+                             (self.disk.device, self.mountdir))
+
+        self.mounted = True
+
+class ExtDiskMount(DiskMount):
+    def __init__(self, disk, mountdir, fstype, blocksize, fslabel, rmmountdir=True):
+        DiskMount.__init__(self, disk, mountdir, fstype, rmmountdir)
         self.blocksize = blocksize
         self.fslabel = fslabel
 
     def __format_filesystem(self):
+        logging.debug("Formating %s filesystem on %s" % (self.fstype, self.disk.device))
         rc = subprocess.call(["/sbin/mkfs." + self.fstype,
                               "-F", "-L", self.fslabel,
                               "-m", "1", "-b", str(self.blocksize),
-                              self.lofile,
-                              str(self.size / self.blocksize)])
+                              self.disk.device])
+        #                      str(self.disk.size / self.blocksize)])
         if rc != 0:
             raise MountError("Error creating %s filesystem" % (self.fstype,))
+        logging.debug("Tuning filesystem on %s" % self.disk.device)
         subprocess.call(["/sbin/tune2fs", "-c0", "-i0", "-Odir_index",
-                         "-ouser_xattr,acl", self.lofile])
-
-    def create(self):
-        SparseLoopbackMount.create(self)
-        self.__format_filesystem()
+                         "-ouser_xattr,acl", self.disk.device])
 
-    def resize(self, size = None):
-        current_size = os.stat(self.lofile)[stat.ST_SIZE]
+    def __resize_filesystem(self, size = None):
+        current_size = os.stat(self.disk.lofile)[stat.ST_SIZE]
 
         if size is None:
             size = self.size
@@ -227,21 +296,28 @@ class SparseExtLoopbackMount(SparseLoopbackMount):
 
         self.__fsck()
 
-        resize2fs(self.lofile, size)
-
-        if size < current_size:
-            self.truncate(size)
+        resize2fs(self.disk.lofile, size)
         return size
 
-    def mount(self):
-        if not os.path.isfile(self.lofile):
-            self.create()
+    def __create(self):
+        resize = False
+        if not self.disk.fixed() and self.disk.exists():
+            resize = True
+
+        self.disk.create()
+
+        if resize:
+            self.__resize_filesystem()
         else:
-            self.resize()
-        return SparseLoopbackMount.mount(self)
+            self.__format_filesystem()
+
+    def mount(self):
+        self.__create()
+        DiskMount.mount(self)
 
     def __fsck(self):
-        subprocess.call(["/sbin/e2fsck", "-f", "-y", self.lofile])
+        logging.debug("Checking filesystem %s" % self.disk.lofile)
+        subprocess.call(["/sbin/e2fsck", "-f", "-y", self.disk.lofile])
 
     def __get_size_from_filesystem(self):
         def parse_field(output, field):
@@ -253,7 +329,7 @@ class SparseExtLoopbackMount(SparseLoopbackMount):
 
         dev_null = os.open("/dev/null", os.O_WRONLY)
         try:
-            out = subprocess.Popen(['/sbin/dumpe2fs', '-h', self.lofile],
+            out = subprocess.Popen(['/sbin/dumpe2fs', '-h', self.disk.lofile],
                                    stdout = subprocess.PIPE,
                                    stderr = dev_null).communicate()[0]
         finally:
@@ -273,7 +349,7 @@ class SparseExtLoopbackMount(SparseLoopbackMount):
         while top != (bot + 1):
             t = bot + ((top - bot) / 2)
 
-            if not resize2fs(self.lofile, t):
+            if not resize2fs(self.disk.lofile, t):
                 top = t
             else:
                 bot = t
@@ -284,8 +360,7 @@ class SparseExtLoopbackMount(SparseLoopbackMount):
         
         minsize = self.__resize_to_minimal()
 
-        self.truncate(minsize)
-        self.resize(size)
+        self.disk.truncate(minsize)
         return minsize
 
 class DeviceMapperSnapshot(object):
@@ -306,8 +381,8 @@ class DeviceMapperSnapshot(object):
         if self.__created:
             return
 
-        self.imgloop.loopsetup()
-        self.cowloop.loopsetup()
+        self.imgloop.create()
+        self.cowloop.create()
 
         self.__name = "imgcreate-%d-%d" % (os.getpid(),
                                            random.randint(0, 2**16))
@@ -315,8 +390,8 @@ class DeviceMapperSnapshot(object):
         size = os.stat(self.imgloop.lofile)[stat.ST_SIZE]
 
         table = "0 %d snapshot %s %s p 8" % (size / 512,
-                                             self.imgloop.loopdev,
-                                             self.cowloop.loopdev)
+                                             self.imgloop.device,
+                                             self.cowloop.device)
 
         args = ["/sbin/dmsetup", "create", self.__name, "--table", table]
         if subprocess.call(args) != 0:
@@ -382,15 +457,14 @@ class DeviceMapperSnapshot(object):
 #   8) Create a squashfs of the COW
 #
 def create_image_minimizer(path, image, minimal_size):
-    imgloop = LoopbackMount(image, "None")
+    imgloop = LoopbackDisk(image, None) # Passing bogus size - doesn't matter
 
-    cowloop = SparseLoopbackMount(os.path.join(os.path.dirname(path), "osmin"),
-                                  None, 64L * 1024L * 1024L)
+    cowloop = SparseLoopbackDisk(os.path.join(os.path.dirname(path), "osmin"),
+                                 64L * 1024L * 1024L)
 
     snapshot = DeviceMapperSnapshot(imgloop, cowloop)
 
     try:
-        cowloop.create()
         snapshot.create()
 
         resize2fs(snapshot.path, minimal_size)
diff --git a/imgcreate/live.py b/imgcreate/live.py
index 130f7fa..9ecd3cf 100644
--- a/imgcreate/live.py
+++ b/imgcreate/live.py
@@ -129,7 +129,7 @@ class LiveImageCreatorBase(LoopImageCreator):
     #
     def __base_on_iso(self, base_on):
         """helper function to extract ext3 file system from a live CD ISO"""
-        isoloop = LoopbackMount(base_on, self._mkdtemp())
+        isoloop = Mount(LoopbackDisk(base_on), self._mkdtemp())
 
         try:
             isoloop.mount()
@@ -143,10 +143,10 @@ class LiveImageCreatorBase(LoopImageCreator):
         else:
             squashimg = isoloop.mountdir + "/LiveOS/squashfs.img"
             
-        squashloop = LoopbackMount(squashimg, self._mkdtemp(), "squashfs")
+        squashloop = Mount(LoopbackDisk(squashimg), self._mkdtemp(), "squashfs")
 
         try:
-            if not os.path.exists(squashloop.lofile):
+            if not squashloop.disk.exists():
                 raise CreatorError("'%s' is not a valid live CD ISO : "
                                    "squashfs.img doesn't exist" % base_on)
 
-- 
1.5.4.1




More information about the Fedora-livecd-list mailing list