From 2a019b5fee65a738bdd38717b0b84eea638a776d Mon Sep 17 00:00:00 2001 From: Richard Maw Date: Tue, 11 Nov 2014 17:28:13 +0000 Subject: Revert "Make system-integration commands use containerised_cmdline" This reverts commit 203f34b2b19b1d3dc51a956ae9329d064ea294dd. The path inversion logic is still buggy for the case of wanting to keep the top-level directory writable. This escaped detection in the test suite because it resulted in directories two levels down being made read-only, and I was only testing one level down. --- morphlib/builder2.py | 60 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 55 insertions(+), 5 deletions(-) diff --git a/morphlib/builder2.py b/morphlib/builder2.py index f71f21db..8615ed59 100644 --- a/morphlib/builder2.py +++ b/morphlib/builder2.py @@ -28,6 +28,7 @@ import time import traceback import subprocess import tempfile +import textwrap import gzip import cliapp @@ -646,6 +647,53 @@ class SystemBuilder(BuilderBase): # pragma: no cover os.chmod(os_release_file, 0644) + def _chroot_runcmd(self, rootdir, to_mount, env, *args): + # We need to do mounts in a different namespace. Unfortunately + # this means we have to in-line the mount commands in the + # command-line. + command = textwrap.dedent(r''' + mount --make-rprivate / + rootdir="$1" + shift + ''') + cmdargs = [rootdir] + + # We need to mount all the specified mounts in the namespace, + # we don't need to unmount them before exiting, as they'll be + # unmounted when the namespace is no longer used. + command += textwrap.dedent(r''' + while true; do + case "$1" in + --) + shift + break + ;; + *) + mount_point="$1" + mount_type="$2" + mount_source="$3" + shift 3 + path="$rootdir/$mount_point" + mount -t "$mount_type" "$mount_source" "$path" + ;; + esac + done + ''') + for mount_opts in to_mount: + cmdargs.extend(mount_opts) + cmdargs.append('--') + + command += textwrap.dedent(r''' + exec chroot "$rootdir" "$@" + ''') + cmdargs.extend(args) + + # The single - is just a shell convention to fill $0 when using -c, + # since ordinarily $0 contains the program name. + cmdline = ['unshare', '--mount', '--', 'sh', '-ec', command, '-'] + cmdline.extend(cmdargs) + self.app.runcmd(cmdline, env=env) + def run_system_integration_commands(self, rootdir): # pragma: no cover ''' Run the system integration commands ''' @@ -660,16 +708,18 @@ class SystemBuilder(BuilderBase): # pragma: no cover self.app.status(msg='Running the system integration commands') to_mount = ( + ('proc', 'proc', 'none'), ('dev/shm', 'tmpfs', 'none'), ('tmp', 'tmpfs', 'none'), ) try: + for mount_point, mount_type, source in to_mount: + path = os.path.join(rootdir, mount_point) + if not os.path.exists(path): + os.makedirs(path) for bin in sorted(os.listdir(sys_integration_dir)): - self.app.runcmd( - morphlib.util.containerised_cmdline( - [os.path.join(SYSTEM_INTEGRATION_PATH, bin)], - root=rootdir, mounts=to_mount, mount_proc=True), - env=env) + self._chroot_runcmd(rootdir, to_mount, env, + os.path.join(SYSTEM_INTEGRATION_PATH, bin)) except BaseException, e: self.app.status( msg='Error while running system integration commands', -- cgit v1.2.1