From 833f5cffddd5d1d0acae38d25f55326f922b9a37 Mon Sep 17 00:00:00 2001
From: Sebastien Luttringer <sebastien.luttringer@smartjog.com>
Date: Fri, 21 Oct 2011 15:56:50 +0200
Subject: [PATCH] add chroot command

this command is and helper to chroot inside payload mounting /{proc,sys,dev,dev/pts} fs
inside the chroot and disable daemon restart
---
 bin/is                  | 15 ++++++++++++
 installsystems/tools.py | 54 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 69 insertions(+)

diff --git a/bin/is b/bin/is
index 3f08269..f84e399 100755
--- a/bin/is
+++ b/bin/is
@@ -117,6 +117,12 @@ def c_check(parser, args):
     for reponame in args.repository:
         repoman[reponame].check()
 
+def c_chroot(parser, args):
+    '''
+    Helper to go cleanly inside a chroot
+    '''
+    istools.chroot(args.path, shell=args.shell, mount=not args.no_mount)
+
 def c_clean(parser, args):
     '''
     Remove unreferenced files from repoistory
@@ -366,6 +372,15 @@ p_check = subparsers.add_parser("check", help=c_check.__doc__.lower())
 p_check.add_argument("repository", nargs="+", help="repositories to check")
 p_check.set_defaults(func=c_check)
 
+# chroot command parser
+p_chroot = subparsers.add_parser("chroot", help=c_chroot.__doc__.lower())
+p_chroot.add_argument("-m", "--no-mount", action="store_true", default=False,
+                      help="disable mouting of /{proc,dev,sys} inside chroot")
+p_chroot.add_argument("-s", "--shell", default="/bin/bash",
+                      help="shell to call inside chroot")
+p_chroot.add_argument("path")
+p_chroot.set_defaults(func=c_chroot)
+
 # clean command parser
 p_clean = subparsers.add_parser("clean", help=c_clean.__doc__.lower())
 p_clean.add_argument("repository", nargs="+", help="repositories to clean")
diff --git a/installsystems/tools.py b/installsystems/tools.py
index 6ccf791..826bae6 100644
--- a/installsystems/tools.py
+++ b/installsystems/tools.py
@@ -13,6 +13,8 @@ import shutil
 import urllib2
 import time
 
+from subprocess import call, check_call, CalledProcessError
+
 from installsystems.progressbar import ProgressBar, Percentage, FileTransferSpeed
 from installsystems.progressbar import Bar, BouncingBar, ETA, UnknownLength
 from installsystems.tarball import Tarball
@@ -327,3 +329,55 @@ def human_size(num):
             return "%3.1f%s" % (num, x)
         num /= 1024.0
     return "%3.1f%s" % (num, x)
+
+def chroot(path, shell="/bin/bash", mount=True):
+    '''
+    Chroot inside a directory and call shell
+    if mount is true, mount /{proc,dev,sys} inside the chroot
+    '''
+    # try to guest distro
+    if os.path.exists(os.path.join(path, "etc/debian_version")):
+        distro="debian"
+    elif os.path.exists(os.path.join(path, "etc/arch-release")):
+        distro="archlinux"
+    else:
+        distro=None
+    # try to mount /proc /sys /dev
+    if mount:
+        mps = ("proc", "sys", "dev", "dev/pts")
+        arrow("Mouting filesystems")
+        for mp in mps:
+            origin =  "/%s" % mp
+            target = os.path.join(path, mp)
+            if os.path.ismount(origin) and os.path.isdir(target):
+                arrow("%s -> %s" % (origin, target), 1)
+                try:
+                    check_call(["mount",  "--bind", origin, target], close_fds=True)
+                except CalledProcessError as e:
+                    warn("Mount failed: %s.\n" % e)
+    # in case of debian disable policy
+    if distro == "debian":
+        arrow("Creating debian chroot housekeepers")
+        # create a chroot header
+        try: open(os.path.join(path, "etc/debian_chroot"), "w").write("CHROOT")
+        except: pass
+        # fake policy-d
+        try: open(os.path.join(path, "usr/sbin/policy-rc.d"), "w").write("#!/bin/bash\nexit 42\n")
+        except: pass
+    # chrooting
+    arrow("Chrooting inside %s and running %s" % (path, shell))
+    call(["chroot", path, shell], close_fds=True)
+    # cleaning debian stuff
+    if distro == "debian":
+        arrow("Removing debian chroot housekeepers")
+        for f in ("etc/debian_chroot", "usr/sbin/policy-rc.d"):
+            try: os.unlink(os.path.join(path, f))
+            except: pass
+    # unmounting
+    if mount:
+        arrow("Unmouting filesystems")
+        for mp in reversed(mps):
+            target = os.path.join(path, mp)
+            if os.path.ismount(target):
+                arrow(target, 1)
+                call(["umount", target], close_fds=True)
-- 
GitLab