From 8020f444cf7bbc936be9e45670401e641e297d36 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Mon, 17 Oct 2011 09:40:12 -0400 Subject: [PATCH] Add documentation for parallel-debian --- README-testing-multiroot.md | 38 ----- .../0001-Add-support-for-subroot-option.patch | 148 ++++++++++++++++++ .../0001-switch_root-Add-subroot-option.patch | 102 ++++++++++++ parallel-debian/README-testing-multiroot.md | 80 ++++++++++ parallel-debian/create-wheezy-image.sh | 16 ++ parallel-debian/make-image-parallel.sh | 20 +++ 6 files changed, 366 insertions(+), 38 deletions(-) delete mode 100644 README-testing-multiroot.md create mode 100644 parallel-debian/0001-Add-support-for-subroot-option.patch create mode 100644 parallel-debian/0001-switch_root-Add-subroot-option.patch create mode 100644 parallel-debian/README-testing-multiroot.md create mode 100755 parallel-debian/create-wheezy-image.sh create mode 100755 parallel-debian/make-image-parallel.sh diff --git a/README-testing-multiroot.md b/README-testing-multiroot.md deleted file mode 100644 index 209aaaed..00000000 --- a/README-testing-multiroot.md +++ /dev/null @@ -1,38 +0,0 @@ -Experimenting with multiple roots ---------------------------------- - -$ qemu-img create debian.img 600M -$ mkfs.ext2 debian.img -$ mkdir debian-mnt -$ mount -o loop debian.img debian-mnt -$ debootstrap wheezy debian-mnt -$ chroot debian-mnt -$ apt-get install linux-image-3.0.0 -Control-d -$ cp debian-mnt/boot/vmlinuz* . -$ cp debian-mnt/boot/initrd* . -$ umount debian-mnt - -You now have a Debian disk image in debian.img and a kernel+initrd that are bootable with qemu. - -Modifying the image -------------------- - -The first thing I did was re-mount the image, and move almost everythig -(/boot, /var, /etc), except lost+found to a new directory "r0". - -Then I started hacking on the initrd, making understand how to chroot -to "r0". - -This means that after booting, every process would be in /r0 - -including any hacktree process. Assuming objects live in say -/objects, we need some way for hacktree to switch things. I think -just chroot breakout would work. This has the advantage the daemon -can continue to use libraries from the active host. - -Note there is a self-reference here (as is present in Debian/Fedora -etc.) - the update system would at present be shipped with the system -itself. Should they be independent? That has advantages and -disadvantages. I think we should just try really really hard to avoid -breaking hacktree in updates. - diff --git a/parallel-debian/0001-Add-support-for-subroot-option.patch b/parallel-debian/0001-Add-support-for-subroot-option.patch new file mode 100644 index 00000000..5abf7c79 --- /dev/null +++ b/parallel-debian/0001-Add-support-for-subroot-option.patch @@ -0,0 +1,148 @@ +From 0e22e86348bb356e69ed28a58e959b7fab7c43cc Mon Sep 17 00:00:00 2001 +From: Colin Walters +Date: Sun, 16 Oct 2011 14:26:40 -0400 +Subject: [PATCH] Add support for subroot= option + +Passing this option causes the initrd to chroot() into a subdirectory of /. +This is useful for parallel installing multiple systems in one filesystem. + +This relies on a patched switch_root from util-linux. +--- + init | 32 +++++++++++++++++++++----------- + scripts/init-bottom/udev | 5 ++--- + scripts/local | 6 ++++-- + 3 files changed, 27 insertions(+), 16 deletions(-) + +diff --git a/init b/init +index 445c354..3ff2750 100755 +--- a/init ++++ b/init +@@ -49,6 +49,8 @@ export init=/sbin/init + export quiet=n + export readonly=y + export rootmnt=/root ++export subroot= ++export rootsubmnt= + export debug= + export panic= + export blacklist= +@@ -68,6 +70,10 @@ for x in $(cat /proc/cmdline); do + init=*) + init=${x#init=} + ;; ++ subroot=*) ++ subroot=${x#subroot=} ++ rootsubmnt=${x#subroot=} ++ ;; + root=*) + ROOT=${x#root=} + case $ROOT in +@@ -218,14 +224,18 @@ maybe_break mountroot + mountroot + log_end_msg + ++if test -n "${rootsubmnt}"; then ++ rootsubmnt=${rootmnt}/${rootsubmnt} ++fi ++ + maybe_break bottom + [ "$quiet" != "y" ] && log_begin_msg "Running /scripts/init-bottom" + run_scripts /scripts/init-bottom + [ "$quiet" != "y" ] && log_end_msg + + # Preserve information on old systems without /run on the rootfs +-if [ -d ${rootmnt}/run ]; then +- mount -n -o move /run ${rootmnt}/run ++if [ -d ${rootsubmnt}/run ]; then ++ mount -n -o move /run ${rootsubmnt}/run + else + # The initramfs udev database must be migrated: + if [ -d /run/udev ] && [ ! -d /dev/.udev ]; then +@@ -239,27 +249,27 @@ else + fi + + # Move virtual filesystems over to the real filesystem +-mount -n -o move /sys ${rootmnt}/sys +-mount -n -o move /proc ${rootmnt}/proc ++mount -n -o move /sys ${rootsubmnt}/sys ++mount -n -o move /proc ${rootsubmnt}/proc + + validate_init() { + checktarget="${1}" + + # Work around absolute symlinks +- if [ -d "${rootmnt}" ] && [ -h "${rootmnt}${checktarget}" ]; then +- case $(readlink "${rootmnt}${checktarget}") in /*) +- checktarget="$(chroot ${rootmnt} readlink ${checktarget})" ++ if [ -d "${rootsubmnt}" ] && [ -h "${rootsubmnt}${checktarget}" ]; then ++ case $(readlink "${rootsubmnt}${checktarget}") in /*) ++ checktarget="$(chroot ${rootsubmnt} readlink ${checktarget})" + ;; + esac + fi + + # Make sure the specified init can be executed +- if [ ! -x "${rootmnt}${checktarget}" ]; then ++ if [ ! -x "${rootsubmnt}${checktarget}" ]; then + return 1 + fi + + # Upstart uses /etc/init as configuration directory :-/ +- if [ -d "${rootmnt}${checktarget}" ]; then ++ if [ -d "${rootsubmnt}${checktarget}" ]; then + return 1 + fi + } +@@ -273,7 +283,7 @@ if [ -n "${init}" ]; then + fi + + # Common case: /sbin/init is present +-if [ ! -x "${rootmnt}/sbin/init" ]; then ++if [ ! -x "${rootsubmnt}/sbin/init" ]; then + # ... if it's not available search for valid init + if [ -z "${init}" ] ; then + for inittest in /sbin/init /etc/init /bin/init /bin/sh; do +@@ -315,5 +325,5 @@ unset resume + unset resume_offset + + # Chain to real filesystem +-exec run-init ${rootmnt} ${init} "$@" <${rootmnt}/dev/console >${rootmnt}/dev/console ++exec switch_root --subroot ${subroot} ${rootmnt} ${init} "$@" <${rootsubmnt}/dev/console >${rootsubmnt}/dev/console + panic "Could not execute run-init." +diff --git a/scripts/init-bottom/udev b/scripts/init-bottom/udev +index 375dfab..7922d0f 100755 +--- a/scripts/init-bottom/udev ++++ b/scripts/init-bottom/udev +@@ -20,9 +20,8 @@ if [ -e /etc/udev/udev.conf ]; then + fi + + # move the /dev tmpfs to the rootfs +-mount -n -o move /dev ${rootmnt}${udev_root} ++mount -n -o move /dev ${rootsubmnt}${udev_root} + + # create a temporary symlink to the final /dev for other initramfs scripts + nuke /dev +-ln -s ${rootmnt}${udev_root} /dev +- ++ln -s ${rootsubmnt}${udev_root} /dev +diff --git a/scripts/local b/scripts/local +index 521e69a..25b518f 100644 +--- a/scripts/local ++++ b/scripts/local +@@ -101,9 +101,11 @@ mountroot() + # FIXME This has no error checking + # Mount root + if [ "${FSTYPE}" != "unknown" ]; then +- mount ${roflag} -t ${FSTYPE} ${ROOTFLAGS} ${ROOT} ${rootmnt} ++ echo mount ${roflag} -t ${FSTYPE} ${ROOTFLAGS} ${ROOT} ${rootmnt} ++ mount ${roflag} -t ${FSTYPE} ${ROOTFLAGS} ${ROOT} ${rootmnt} || echo "FAILED TO MOUNT ROOT" + else +- mount ${roflag} ${ROOTFLAGS} ${ROOT} ${rootmnt} ++ echo mount ${roflag} ${ROOTFLAGS} ${ROOT} ${rootmnt} ++ mount ${roflag} ${ROOTFLAGS} ${ROOT} ${rootmnt} || echo "FAILED TO MOUNT ROOT" + fi + + [ "$quiet" != "y" ] && log_begin_msg "Running /scripts/local-bottom" +-- +1.7.6.4 + diff --git a/parallel-debian/0001-switch_root-Add-subroot-option.patch b/parallel-debian/0001-switch_root-Add-subroot-option.patch new file mode 100644 index 00000000..145ee70b --- /dev/null +++ b/parallel-debian/0001-switch_root-Add-subroot-option.patch @@ -0,0 +1,102 @@ +From fa0e7df4e3d6550f0391bb3b81b2b6ac5165439d Mon Sep 17 00:00:00 2001 +From: Colin Walters +Date: Sun, 16 Oct 2011 21:01:46 -0400 +Subject: [PATCH] switch_root: Add --subroot option + +This is useful for parallel installing multiple operating system +roots. See: http://git.gnome.org/browse/hacktree +--- + sys-utils/switch_root.8 | 4 ++++ + sys-utils/switch_root.c | 31 +++++++++++++++++++++---------- + 2 files changed, 25 insertions(+), 10 deletions(-) + +diff --git a/sys-utils/switch_root.8 b/sys-utils/switch_root.8 +index 34ab0d0..6981852 100644 +--- a/sys-utils/switch_root.8 ++++ b/sys-utils/switch_root.8 +@@ -27,6 +27,10 @@ process. + show help and exit + .IP "\fB\-V, \-\-version\fP" + show version number and exit ++.IP "\-\-subroot\fP" ++Instead of calling chroot into the / of the new root, instead use the ++given argument. This helps parallel install multiple operating systems in one ++root filesystem. + + .SH RETURN VALUE + .B switch_root +diff --git a/sys-utils/switch_root.c b/sys-utils/switch_root.c +index 2dfed71..20ae5d6 100644 +--- a/sys-utils/switch_root.c ++++ b/sys-utils/switch_root.c +@@ -108,7 +108,7 @@ done: + return rc; + } + +-static int switchroot(const char *newroot) ++static int switchroot(const char *newroot, const char *subroot) + { + /* Don't try to unmount the old "/", there's no way to do it. */ + const char *umounts[] = { "/dev", "/proc", "/sys", NULL }; +@@ -141,7 +141,7 @@ static int switchroot(const char *newroot) + return -1; + } + +- if (chroot(".")) { ++ if (chroot(subroot ? subroot : ".")) { + warn("failed to change root"); + return -1; + } +@@ -160,7 +160,7 @@ static int switchroot(const char *newroot) + + static void usage(FILE *output) + { +- fprintf(output, "usage: %s \n", ++ fprintf(output, "usage: %s [--subroot DIR] \n", + program_invocation_short_name); + exit(output == stderr ? EXIT_FAILURE : EXIT_SUCCESS); + } +@@ -175,22 +175,33 @@ static void version(void) + int main(int argc, char *argv[]) + { + char *newroot, *init, **initargs; ++ char *subroot = NULL; ++ int argi; + +- if (argv[1] && (!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h"))) ++ if (argc < 2) ++ usage(stderr); ++ ++ argi = 1; ++ if ((!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h"))) + usage(stdout); +- if (argv[1] && (!strcmp(argv[1], "--version") || !strcmp(argv[1], "-V"))) ++ if ((!strcmp(argv[1], "--version") || !strcmp(argv[1], "-V"))) + version(); +- if (argc < 3) ++ if (argc > 3 && argv[1] && (!strcmp(argv[1], "--subroot"))) { ++ subroot = argv[2]; ++ argi = 3; ++ } ++ if (argc <= argi+1) { + usage(stderr); ++ } + +- newroot = argv[1]; +- init = argv[2]; +- initargs = &argv[2]; ++ newroot = argv[argi]; ++ init = argv[argi+1]; ++ initargs = &argv[argi+1]; + + if (!*newroot || !*init) + usage(stderr); + +- if (switchroot(newroot)) ++ if (switchroot(newroot, subroot)) + errx(EXIT_FAILURE, "failed. Sorry."); + + if (access(init, X_OK)) +-- +1.7.6.4 + diff --git a/parallel-debian/README-testing-multiroot.md b/parallel-debian/README-testing-multiroot.md new file mode 100644 index 00000000..8c0a1343 --- /dev/null +++ b/parallel-debian/README-testing-multiroot.md @@ -0,0 +1,80 @@ + +Experimenting with multiple roots +--------------------------------- + + + +Follow the steps for making a disk image, downloading the business +card CD, booting it in QEMU and running through the installer. + +Test that the image works after installation too, before you start +modifying things below! Remember to remove the -cdrom and -boot +options from the installation QEMU command. + +Modifying the image +------------------- + +You now have a disk image in debian.img, and the first partition +should be ext4. + +The first thing I did was mount the image, and move almost everythig +(/boot, /var, /etc), except lost+found to a new directory "r0". + + $ mkdir /mnt/debian + $ modprobe nbd max_part=8 + $ qemu-nbd --connect=/dev/nbd0 debian.qcow + $ mount /dev/nbd0p1 /mnt/debian/ + $ cd /mnt/debian + $ mkdir r0 + $ DIRS="bin boot dev etc lib lib64 media mnt opt proc root run sbin selinux srv sys tmp usr var" + $ mv $DIRS r0 + +Now with it still mounted, we need to move on to the next part - +modifying the initrd. + +Then I started hacking on the initrd, making understand how to chroot +to "r0". I ended up with two patches - one to util-linux, and one to +the "init" script in Debian's initrd. + +See: + 0001-switch_root-Add-subroot-option.patch + 0001-Add-support-for-subroot-option.patch + +$ git clone --depth=1 git://github.com/karelzak/util-linux.git +$ cd util-linux +$ patch -p1 -i ../0001-switch_root-Add-subroot-option.patch +$ ./autogen.sh; ./configure ; make + +Now you have a modified "sys-utils/switch_root" binary. Let's next +patch the initrd and rebuild it: + +Make a backup: + + $ mkdir initrd + $ cp /mnt/debian/boot/initrd.img-3.0.0-1-amd64{,.orig} + +Unpack, and patch: + + $ zcat /mnt/debian/boot/initrd.img-3.0.0-1-amd64 | (cd initrd; cpio -d -i -v) + $ (cd initrd && patch -p1 -i ../0001-Add-support-for-subroot-option.patch) + +Repack: + + $ (cd initrd; find | cpio -o -H newc) | gzip > /mnt/debian/boot/initrd.img-3.0.0-1-amd64.new + $ mv /mnt/debian/boot/initrd.img-3.0.0-1-amd64{.new,} + +Running hacktree inside the system +---------------------------------- + +This means that after booting, every process would be in /r0 - +including any hacktree process. Assuming objects live in say +/objects, we need some way for hacktree to switch things. I think +just chroot breakout would work. This has the advantage the daemon +can continue to use libraries from the active host. + +Note there is a self-reference here (as is present in Debian/Fedora +etc.) - the update system would at present be shipped with the system +itself. Should they be independent? That has advantages and +disadvantages. I think we should just try really really hard to avoid +breaking hacktree in updates. + diff --git a/parallel-debian/create-wheezy-image.sh b/parallel-debian/create-wheezy-image.sh new file mode 100755 index 00000000..6f8263ab --- /dev/null +++ b/parallel-debian/create-wheezy-image.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +set -e +set -x + +if test -f debian.img; then + echo debian.img already exists + exit 1 +fi + +qemu-img create debian.img 600M +mkfs.ext2 -q -F debian.img +mkdir -p debian-mnt +mount -o loop debian.img debian-mnt +debootstrap --arch amd64 wheezy debian-mnt +umount debian-mnt diff --git a/parallel-debian/make-image-parallel.sh b/parallel-debian/make-image-parallel.sh new file mode 100755 index 00000000..b6aaa9e7 --- /dev/null +++ b/parallel-debian/make-image-parallel.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +set -e +set -x + +DIRS="bin boot dev etc lib lib64 media mnt opt proc root run sbin selinux srv sys tmp usr var" + +if ! test -f debian.img; then + echo need debian.img + exit 1 +fi + +mount -o loop debian.img debian-mnt +cd debian-mnt +if ! test -d r0; then + mkdir r0 + mv $DIRS r0 +fi +cd .. +umount debian-mnt