diff --git a/scripts/classic b/scripts/classic new file mode 100755 index 0000000..ab5ca89 --- /dev/null +++ b/scripts/classic @@ -0,0 +1,63 @@ +#!/bin/sh + +set -e + +ROOT=$SNAP_COMMON/classic + +# $1: source +# $2: target +# $3: if not empty, bind mount will be read-only +# note that we do NOT clean these up at the end, as the user might start many +# classic shells in parallel; we could start all of them in their own mount +# namespace, but that would make the classic shell less useful for +# developing/debugging the snappy host +do_bindmount() { + if ! mountpoint -q "$ROOT/$2"; then + if [ -d "$1" -a ! -L "$1" ]; then + mkdir -p "$ROOT/$2" + fi + mount --make-rprivate --rbind -o rbind "$1" "$ROOT/$2" + if [ -n "${3:-}" ]; then + mount --rbind -o remount,ro "$1" "$ROOT/$2" + fi + fi +} + +if [ "$(id -u)" != "0" ]; then + echo "needs to run as root" + exit 1 +fi + +if [ ! -d $ROOT ]; then + # IMPORTANT: do not run the classic.create as this will run it with + # snap-confine again and this will cause havoc with current + # snap-confine + $SNAP/bin/create +fi + +# FIXME: confinement will prevent this +do_bindmount /home /home +do_bindmount /run /run +do_bindmount /proc /proc +do_bindmount /sys /sys +do_bindmount /dev /dev +do_bindmount / /snappy + +SUDO_USER=root + +# fix LP: #1619455 +cp -a /var/lib/extrausers/* $ROOT/var/lib/extrausers/ +cp -a /etc/sudoers.d/* $ROOT/etc/sudoers.d/ + +# assemble command line +DEVPTS="mount -o mode=666,ptmxmode=666 -t devpts devpts /dev/pts" +SUDOCMD="sudo debian_chroot=classic -u ${SUDO_USER} -i $@" +# FIXME: workaround for https://bugs.launchpad.net/snappy/+bug/1611493 +SCRIPT="script --quiet --return --command \"$SUDOCMD\" /dev/null" + +CMD="$DEVPTS; $SCRIPT" + +systemd-run --quiet --scope --unit=classic-$$.scope --description="Classic shell" chroot "$ROOT" sh -c "$CMD" + +# kill leftover processes after exiting, if it's still around +systemctl stop classic-$$.scope 2>/dev/null || true diff --git a/scripts/classic-create b/scripts/classic-create new file mode 100755 index 0000000..10b8efa --- /dev/null +++ b/scripts/classic-create @@ -0,0 +1,61 @@ +#!/bin/sh + +set -eu + +ROOT=$SNAP_COMMON/classic + +if [ -d $ROOT ]; then + echo "classic already enabled" + exit 1 +fi + +if [ $(id -u) -ne 0 ]; then + echo "This script needs to be called as root" >&2 + exit 1 +fi + +CORE="" +if [ -e /snap/core/current ]; then + CORE="core" +elif [ -e /snap/ubuntu-core/current ]; then + CORE="ubuntu-core" +else + echo "Cannot find core snap" + exit 1 +fi + +# FIXME: confinement will prevent this +echo "Creating classic environment" +VERSION="$(/bin/readlink /snap/${CORE}/current)" +SNAPROOT="/var/lib/snapd/snaps/${CORE}_${VERSION}.snap" +/usr/bin/unsquashfs -d $ROOT $SNAPROOT +mkdir $ROOT/snappy + +# enable +sudo chroot $ROOT /var/lib/classic/enable.sh + +# copy important config +for f in hostname timezone localtime; do + cp -a /etc/writable/$f $ROOT/etc/writable +done +for f in hosts; do + cp -a /etc/$f $ROOT/etc/ +done + + +# don't start services in the chroot on apt-get install +cat < "$ROOT/usr/sbin/policy-rc.d" +#!/bin/sh +while true; do + case "\$1" in + -*) shift ;; + makedev) exit 0;; + x11-common) exit 0;; + *) exit 101;; + esac +done +EOF +chmod 755 "$ROOT/usr/sbin/policy-rc.d" + +# workaround bug in livecd-rootfs +chmod 1777 "$ROOT/tmp" diff --git a/scripts/classic-reset b/scripts/classic-reset new file mode 100755 index 0000000..62c4329 --- /dev/null +++ b/scripts/classic-reset @@ -0,0 +1,19 @@ +#!/bin/sh + +set -eu + +ROOT=$SNAP_COMMON/classic + +if [ "$(id -u)" != "0" ]; then + echo "needs to run as root" + exit 1 +fi + +for d in /home /run /proc /sys /dev /var/lib/extrausers /etc/sudoers /etc/sudoers.d /snappy; do + if mountpoint -q "$ROOT/$d"; then + umount "$ROOT/$d" + fi +done + +# cleanup +rm -rf $ROOT diff --git a/scripts/container-manager.sh b/scripts/container-manager.sh index 8dd9fe8..90f867d 100755 --- a/scripts/container-manager.sh +++ b/scripts/container-manager.sh @@ -1,4 +1,5 @@ #!/bin/sh +set -x # We need to put the rootfs somewhere where we can modify some # parts of the content on first boot (namely file permissions). @@ -21,6 +22,50 @@ if [ ! -e $SYSTEM_IMG ]; then exit 1 fi +build_kernel_modules() { + kversion=$1 + + rm -rf $SNAP_COMMON/kernel-* + + $SNAP/bin/classic-create || true + + rm -rf $SNAP_COMMON/classic/build + mkdir -p $SNAP_COMMON/classic/build + cp -rav $SNAP/ashmem $SNAP_COMMON/classic/build/ + cp -rav $SNAP/binder $SNAP_COMMON/classic/build/ + + cat< $SNAP_COMMON/classic/build/run.sh +#!/bin/sh +set -ex +apt update +apt install -y --force-yes linux-headers-$kversion build-essential +cd /build/ashmem +make +cd /build/binder +make +EOF + + chmod +x $SNAP_COMMON/classic/build/run.sh + $SNAP/bin/classic /build/run.sh + + mkdir -p $SNAP_COMMON/kernel-$kversion + cp $SNAP_COMMON/classic/build/ashmem/ashmem_linux.ko \ + $SNAP_COMMON/kernel-$kversion/ + cp $SNAP_COMMON/classic/build/binder/binder_linux.ko \ + $SNAP_COMMON/kernel-$kversion/ +} + +load_kernel_modules() { + kversion=`uname -r` + rmmod ashmem_linux binder_linux || true + echo "Loading kernel modules for version $kversion.." + insmod $SNAP_COMMON/kernel-$kversion/binder_linux.ko + insmod $SNAP_COMMON/kernel-$kversion/ashmem_linux.ko + sleep 0.5 + chmod 666 /dev/binder + chmod 666 /dev/ashmem +} + start() { # Extract ramdisk content instead of trying to bind mount the # cpio image file to allow modifications. @@ -52,6 +97,13 @@ start() { # possible. See snapcraft.yaml for further details. $SNAP/bin/anbox-bridge.sh start + kversion=`uname -r` + if [ ! -e $SNAP_COMMON/kernel-$kversion ]; then + build_kernel_modules $kversion + fi + + load_kernel_modules + exec $SNAP/usr/sbin/aa-exec -p unconfined -- $SNAP/bin/anbox-wrapper.sh container-manager } @@ -63,6 +115,8 @@ stop() { umount $ROOTFS_PATH $SNAP/bin/anbox-bridge.sh stop + + rmmod ashmem_linux binder_linux || true } case "$1" in diff --git a/snapcraft.yaml b/snapcraft.yaml index 376defc..972822a 100644 --- a/snapcraft.yaml +++ b/snapcraft.yaml @@ -29,6 +29,9 @@ parts: files: system.img: system.img ramdisk.img: ramdisk.img + kernel-modules: + plugin: dump + source: kernel anbox-common: plugin: copy source: . @@ -36,10 +39,16 @@ parts: scripts/snap-wrapper.sh: bin/anbox-wrapper.sh scripts/container-manager.sh: bin/container-manager.sh scripts/anbox-bridge.sh: bin/anbox-bridge.sh + scripts/classic: bin/classic + scripts/classic-create: bin/classic-create + scripts/classic-reset: bin/classic-reset snap: - bin/anbox-bridge.sh - bin/anbox-wrapper.sh - bin/container-manager.sh + - bin/classic + - bin/classic-create + - bin/classic-reset apparmor: plugin: nil stage-packages: