Rework interfaces and move some common functions to misc.py
authorZhou Shuangquan <shuangquan.zhou@intel.com>
Thu, 28 Jul 2011 06:10:46 +0000 (14:10 +0800)
committerZhou Shuangquan <shuangquan.zhou@intel.com>
Thu, 28 Jul 2011 06:14:23 +0000 (14:14 +0800)
Note: remove "pack/unpack"
      add "_mount_srcimg/_umount_srcimg" for supporting chroot
      add "_base_on" for supporting convertor

Signed-off-by: Zhou Shuangquan <shuangquan.zhou@intel.com>
micng/pluginbase/imager_plugin.py
micng/utils/misc.py [changed mode: 0644->0755]

index fb5aacc..15014d0 100755 (executable)
@@ -787,24 +787,28 @@ class ImagerPlugin(PluginBase):
         self.do_umount()
         self.do_package()
 
+    def _base_on(self, base_on):
+        """Support Image Convertor, unpack the source image for building the instroot directory.
+        
+            Subclass need a actual implementation.
+        """
+        shutil.copyfile(base_on, self._image)
+
     def _mount_srcimg(self, srcimg):
         """Mount source image.
     
-           This method may be used by subclasses to mount source image for convertor/chroot,
-           e.g. mount a raw image. There is no default implementation.
+           This method may be used by subclasses to mount source image for Chroot,
+           There is no default implementation. 
+           e.g.
+           "livecd":
+               imgcreate.DiskMount(imgcreate.LoopbackDisk(self.img, 0), self.imgmnt)
         """
         pass
 
     def _umount_srcimg(self, srcimg):
         """Umount source image.
     
-           This method may be used by subclasses to umount source image for convertor/chroot,
+           This method may be used by subclasses to umount source image for Chroot,
            e.g. umount a raw image. There is no default implementation.
         """
         pass
-    
-    def pack(self):
-        self.do_package()
-        
-    def unpack(self, srcimg):
-        self._mount_srcimg(srcimg)
old mode 100644 (file)
new mode 100755 (executable)
index d36e5e6..b60590e
@@ -43,9 +43,11 @@ except ImportError:
     import cElementTree
 xmlparse = cElementTree.parse
 
-from errors import *
-from fs_related import *
+import errors as errors
+import fs_related as fs_related
 
+chroot_lockfd = -1
+chroot_lock = ""
 
 def setlocale():
     try:
@@ -1144,3 +1146,176 @@ def add_optparser(arg):
             f.optparser = arg
         return f
     return decorate
+
+def setup_chrootenv(chrootdir, bindmounts = None):##move to mic/utils/misc
+    global chroot_lockfd, chroot_lock
+    def get_bind_mounts(chrootdir, bindmounts):
+        chrootmounts = []
+        if bindmounts in ("", None):
+            bindmounts = ""
+        mounts = bindmounts.split(";")
+        for mount in mounts:
+            if mount == "":
+                continue
+            srcdst = mount.split(":")
+            srcdst[0] = os.path.abspath(os.path.expanduser(srcdst[0]))
+            if len(srcdst) == 1:
+               srcdst.append("none")
+            if not os.path.isdir(srcdst[0]):
+                continue
+            if srcdst[0] in ("/proc", "/proc/sys/fs/binfmt_misc", "/", "/sys", "/dev", "/dev/pts", "/dev/shm", "/var/lib/dbus", "/var/run/dbus", "/var/lock"):
+                pwarning("%s will be mounted by default." % srcdst[0])
+                continue
+            if srcdst[1] == "" or srcdst[1] == "none":
+                srcdst[1] = None
+            else:
+                srcdst[1] = os.path.abspath(os.path.expanduser(srcdst[1]))
+                if os.path.isdir(chrootdir + "/" + srcdst[1]):
+                    pwarning("%s has existed in %s , skip it." % (srcdst[1], chrootdir))
+                    continue
+            chrootmounts.append(fs_related.BindChrootMount(srcdst[0], chrootdir, srcdst[1]))
+    
+        """Default bind mounts"""
+        chrootmounts.append(fs_related.BindChrootMount("/proc", chrootdir, None))
+        chrootmounts.append(fs_related.BindChrootMount("/proc/sys/fs/binfmt_misc", chrootdir, None))
+        chrootmounts.append(fs_related.BindChrootMount("/sys", chrootdir, None))
+        chrootmounts.append(fs_related.BindChrootMount("/dev", chrootdir, None))
+        chrootmounts.append(fs_related.BindChrootMount("/dev/pts", chrootdir, None))
+        chrootmounts.append(fs_related.BindChrootMount("/dev/shm", chrootdir, None))
+        chrootmounts.append(fs_related.BindChrootMount("/var/lib/dbus", chrootdir, None))
+        chrootmounts.append(fs_related.BindChrootMount("/var/run/dbus", chrootdir, None))
+        chrootmounts.append(fs_related.BindChrootMount("/var/lock", chrootdir, None))
+        chrootmounts.append(fs_related.BindChrootMount("/", chrootdir, "/parentroot", "ro"))
+        for kernel in os.listdir("/lib/modules"):
+            chrootmounts.append(fs_related.BindChrootMount("/lib/modules/" + kernel, chrootdir, None, "ro"))
+    
+        return chrootmounts
+
+    def bind_mount(chrootmounts):
+        for b in chrootmounts:
+            print "bind_mount: %s -> %s" % (b.src, b.dest)
+            b.mount()
+
+    def setup_resolv(chrootdir):
+        shutil.copyfile("/etc/resolv.conf", chrootdir + "/etc/resolv.conf")
+
+    globalmounts = get_bind_mounts(chrootdir, bindmounts)
+    bind_mount(globalmounts)
+    setup_resolv(chrootdir)
+    mtab = "/etc/mtab"
+    dstmtab = chrootdir + mtab
+    if not os.path.islink(dstmtab):
+        shutil.copyfile(mtab, dstmtab)
+    chroot_lock = os.path.join(chrootdir, ".chroot.lock")
+    chroot_lockfd = open(chroot_lock, "w")
+    return globalmounts    
+
+def cleanup_chrootenv(chrootdir, bindmounts = None, globalmounts = []):
+    global chroot_lockfd, chroot_lock
+    def bind_unmount(chrootmounts):
+        chrootmounts.reverse()
+        for b in chrootmounts:
+            print "bind_unmount: %s -> %s" % (b.src, b.dest)
+            b.unmount()
+
+    def cleanup_resolv(chrootdir):
+        fd = open(chrootdir + "/etc/resolv.conf", "w")
+        fd.truncate(0)
+        fd.close()
+
+    def kill_processes(chrootdir):
+        for file in glob.glob("/proc/*/root"):
+            try:
+                if os.readlink(file) == chrootdir:
+                    pid = int(file.split("/")[2])
+                    os.kill(pid, 9)
+            except:
+                pass
+
+    def cleanup_mountdir(chrootdir, bindmounts):
+        if bindmounts == "" or bindmounts == None:
+            return
+        chrootmounts = []
+        mounts = bindmounts.split(";")
+        for mount in mounts:
+            if mount == "":
+                continue
+            srcdst = mount.split(":")
+            if len(srcdst) == 1:
+               srcdst.append("none")
+            if srcdst[1] == "" or srcdst[1] == "none":
+                srcdst[1] = srcdst[0]
+            srcdst[1] = os.path.abspath(os.path.expanduser(srcdst[1]))
+            tmpdir = chrootdir + "/" + srcdst[1]
+            if os.path.isdir(tmpdir):
+                if len(os.listdir(tmpdir)) == 0:
+                    shutil.rmtree(tmpdir, ignore_errors = True)
+                else:
+                    print "Warning: dir %s isn't empty." % tmpdir
+    
+    chroot_lockfd.close()
+    bind_unmount(globalmounts)
+    if not fs_releate.my_fuser(chroot_lock):
+        tmpdir = chrootdir + "/parentroot"
+        if len(os.listdir(tmpdir)) == 0:
+            shutil.rmtree(tmpdir, ignore_errors = True)
+        cleanup_resolv(chrootdir)
+        if os.path.exists(chrootdir + "/etc/mtab"):
+            os.unlink(chrootdir + "/etc/mtab")
+        kill_processes(chrootdir)
+    cleanup_mountdir(chrootdir, bindmounts)
+
+def chroot(chrootdir, bindmounts = None, execute = "/bin/bash"):
+    def mychroot():
+        os.chroot(chrootdir)
+        os.chdir("/")
+
+    dev_null = os.open("/dev/null", os.O_WRONLY)
+    files_to_check = ["/bin/bash", "/sbin/init"]
+    
+    architecture_found = False
+
+    """ Register statically-linked qemu-arm if it is an ARM fs """
+    qemu_emulator = None
+
+    for ftc in files_to_check:
+        ftc = "%s/%s" % (chrootdir,ftc)
+        
+        # Return code of 'file' is "almost always" 0 based on some man pages
+        # so we need to check the file existance first.
+        if not os.path.exists(ftc):
+            continue
+
+        filecmd = find_binary_path("file")
+        initp1 = subprocess.Popen([filecmd, ftc], stdout=subprocess.PIPE, stderr=dev_null)
+        fileOutput = initp1.communicate()[0].strip().split("\n")
+        
+        for i in range(len(fileOutput)):
+            if fileOutput[i].find("ARM") > 0:
+                qemu_emulator = setup_qemu_emulator.(chrootdir, "arm")
+                architecture_found = True
+                break
+            if fileOutput[i].find("Intel") > 0:
+                architecture_found = True
+                break
+                
+        if architecture_found:
+            break
+                
+    os.close(dev_null)
+    if not architecture_found:
+        raise errors.CreatorError("Failed to get architecture from any of the following files %s from chroot." % files_to_check)
+
+    try:
+        print "Launching shell. Exit to continue."
+        print "----------------------------------"
+        globalmounts = setup_chrootenv(chrootdir, bindmounts)
+        args = shlex.split(execute)
+        subprocess.call(args, preexec_fn = mychroot)
+    except OSError, (err, msg):
+        raise errors.CreatorError("Failed to chroot: %s" % msg)
+    finally:
+        cleanup_chrootenv(chrootdir, bindmounts, globalmounts)
+        if qemu_emulator:
+            os.unlink(chrootdir + qemu_emulator)        
+