Separate desktop and development environment is a good practice to maintain availability. Since we need most update to date packages (or the same version with different configuration), if we install these packages in desktop environment, that breaks a lot of things.

Although, a VM can provides the same separation, what if we need to build a lot of package from source? The performance which virtual machine provides won't fulfil our needs.

chroot command (switch into another root file system you prepared), however, if we can acquire root permission, can reach both separation and high performance goals.

Where can I get a root file system? Canonical provides . Gentoo Linux has , you name it. After downloaded, you extract files as root with -p argument to keep permissions. eg.
$ sudo tar -jcvpf

Another issue arise: how can my desktop environment and chrooted environemnt exchange data? Following command can help us
$ sudo mount --bind A B

After "mount --bind", Linux kernel treats B almost exactly the same as A (except recursive mount points in A).

Wait, if I "mount --bind" multiple times, do I need to "umount" these mount points manually? The answer is YES. Further, if you run "mount", it will dump a lot of annoying mount points made by "mount --bind".

unshare command can provides namespace separation. With "unshare --mount CMD", the mount points that CMD create are invisible from the outside of the CMD process. And, since these mount points are private (no way to umount from outside of CMD process), kernel will unmount it automatically after CMD process terminated.

What if we want to recursively mount all mount points from A to B? Do we need to mount it one by one? "mount -R" (or mount --rbind) can do it for you. For example, there are a lot of mount points in /sys, with "mount -R", you recursively mount it to another mount point with only one command
$ sudo mount /sys /new-rootfs/sys

OK, now we know some commands. But what directories do we need inside chrooted environment? Many, for different purposes.

Basic ones are

  • mount -R /proc /new-root/proc
  • mount -R /dev /new-root/dev
  • mount -R /sys /new-root/sys

Many commands need to talk to kernel via these spacial file systems. Since X client need to talk to X server via unix socket, this one is also need

  • mount -R /tmp /new-root/tmp

Modern Linux desktop environment depends on dbus heavily, so machine-id (/etc/dbus-1/machine-id) and its socket file (/run/dbus/system_bus_socket) are also important

  • mount -R /etc/dbus-1 /new-root/etc/dbus-1
  • mount -R /run /new-root/run

Since older packages find these files from old places (/var/lib/dbus, /var/run/dbus), we must also mount it to maintain compatibility

  • mount -R /etc/dbus-1 /new-root/var/lib/dbus
  • mount -R /run /new-root/var/run

Mount reads /etc/mtab to provide mount point information. If it's a regular file, after some chroot & mount, we will find that mount information in chrooted environment is out of sync. The solution is simple

  • ln -sfn /proc/self/mounts /new-root/etc/mtab

This way, what mount command reads are directly from kernel.

Finally, we need to sync name server configuration with outside of chrooted environment to make network work. Here "mount --bind" comes again, but the source and target are both file, not directory

  • mount --bind /etc/resolv.conf /new-root/etc/resolv.conf

Concepts are complex, but script are straightforward

!/bin/bash

if [[ 0 != $UID ]]; then

echo Super user previlige is required >&2

exit 1
fi

if [[ -z $UNSHARE ]]; then

UNSHARE=1 exec unshare --mount -- $0 "[email protected]"
fi

root="$(dirname $(readlink -f $0))/root"
if [[ ! -d "$root" ]]; then

echo Root directory not found: "$root" >&2

exit 1
fi

mount -R /proc "$root"/proc
mount -R /dev "$root"/dev
mount -R /sys "$root"/sys
mount -R /tmp "$root"/tmp
mount -R /run "$root"/run
mount -R /run "$root"/var/run
mount --bind /etc/dbus-1 "$root"/etc/dbus-1
mount --bind /etc/dbus-1 "$root"/var/lib/dbus
mount --bind /etc/resolv.conf "$root"/etc/resolv.conf
ln -sfn /proc/self/mounts "$root"/etc/mtab

exec chroot "$root"

Save this script in any directory you want. Make it executable. Download rootfs tarball, for example Ubuntu Core
$ wget http://cdimage.ubuntu.com/ubuntu-core/releases/12.04/release/ubuntu-core-12.04.2-core-i386.tar.gz
$ mkdir root
$ sudo tar -zxvpf core-12.04.2-core-i386.tar.gz -C root

stage3-i686-20130416.tar.bz2