diff --git a/experiments/alpine-standalone/.gitignore b/experiments/alpine-standalone/.gitignore new file mode 100644 index 0000000..075442d --- /dev/null +++ b/experiments/alpine-standalone/.gitignore @@ -0,0 +1,2 @@ +vmlinuz-virt +newroot/ diff --git a/experiments/alpine-standalone/Makefile b/experiments/alpine-standalone/Makefile new file mode 100644 index 0000000..2d85657 --- /dev/null +++ b/experiments/alpine-standalone/Makefile @@ -0,0 +1,29 @@ +all: run + +clean: + rm -f initramfs-syndicate-system + +veryclean: clean + rm -f disk.img + +ALPINE_VERSION=v3.14 + +# vmlinuz-lts: +# wget http://dl-cdn.alpinelinux.org/alpine/$(ALPINE_VERSION)/releases/aarch64/netboot/vmlinuz-lts +# initramfs-lts: +# wget http://dl-cdn.alpinelinux.org/alpine/$(ALPINE_VERSION)/releases/aarch64/netboot/initramfs-lts + +disk.img: + qemu-img create -f qcow2 $@ 8G + +initramfs-syndicate-system: pack-image.sh init.sh package-list + sudo PACKAGES="$$(cat package-list)" ./pack-image.sh + +# See https://superuser.com/questions/1397991/running-alpine-linux-on-qemu-arm-guests +run: initramfs-syndicate-system disk.img + qemu-system-aarch64 \ + -M virt -m 512M -cpu cortex-a57 \ + -kernel vmlinuz-virt -initrd initramfs-syndicate-system \ + -netdev user,id=unet,hostfwd=tcp::8022-:22 -device virtio-net-pci,netdev=unet \ + -hda disk.img \ + -nographic diff --git a/experiments/alpine-standalone/apks/.gitignore b/experiments/alpine-standalone/apks/.gitignore new file mode 100644 index 0000000..b1a258b --- /dev/null +++ b/experiments/alpine-standalone/apks/.gitignore @@ -0,0 +1,2 @@ +syndicate-system-apk-key.rsa +syndicate-system-apk-key.rsa.pub diff --git a/experiments/alpine-standalone/apks/Makefile b/experiments/alpine-standalone/apks/Makefile new file mode 100644 index 0000000..dd8edb7 --- /dev/null +++ b/experiments/alpine-standalone/apks/Makefile @@ -0,0 +1,106 @@ +# Originally based on a Makefile from the FRμIT project, +# https://fruit-testbed.org/, which is CC Attribution-ShareAlike 4.0 +# licensed. + +.PHONY: build sign clean + +TARGET = $(shell pwd)/target +KEYFILE ?= $(shell pwd)/syndicate-system-apk-key.rsa +USER = builder +ARCH ?= $(shell apk --print-arch) + +SU_CMD = su $(USER) +SU_CMD_PATH_OVERRIDE = PATH=/usr/sbin:/sbin:$$PATH + +PACKAGES = \ + +build: $(PACKAGES) sign + +# Packages added: +# - alpine-sdk for build support +# - shadow for `sg` +.prepare: + apk update && apk upgrade && apk add alpine-sdk shadow + [ -f /etc/apk/keys/$$(basename $(KEYFILE)).pub ] || cp $(KEYFILE).pub /etc/apk/keys/. + adduser -s /bin/sh -D $(USER) && \ + echo "$(USER) ALL=(ALL) ALL" >> /etc/sudoers && \ + addgroup $(USER) abuild && \ + chown $(USER):$(USER) . && \ + chown $(USER):$(USER) -R packages && \ + mkdir -p /home/$(USER)/.abuild/ && \ + cp -f $(KEYFILE) /home/$(USER)/.abuild/ && \ + chmod 0400 /home/$(USER)/.abuild/$$(basename $(KEYFILE)) && \ + chown $(USER):$(USER) /home/$(USER)/.abuild/$$(basename $(KEYFILE)) && \ + echo "PACKAGER_PRIVKEY=/home/syndicate-systemdev/.abuild/$$(basename $(KEYFILE))" > /home/$(USER)/.abuild/abuild.conf && \ + mkdir -p $(TARGET)/packages/$(ARCH) && \ + chown -R $(USER):$(USER) $(TARGET) + addgroup $(shell id -un) abuild + mkdir -p /var/cache/distfiles && chmod a+w /var/cache/distfiles + touch .prepare + +$(TARGET): .prepare $(PACKAGES) + +%.apk: .prepare + @if [ -e packages/$*/APKBUILD ]; then \ + echo "Building $*..."; \ + cd packages/$* && sg abuild "abuild -F -P $(TARGET) deps" && $(SU_CMD) -c "$(SU_CMD_PATH_OVERRIDE) abuild -P $(TARGET)"; \ + else \ + echo "Fetching $*..."; \ + apk fetch -o $(TARGET)/packages/$(ARCH) -R $*; \ + fi + +%.checksum: .prepare + cd packages/$* && $(SU_CMD) -c "$(SU_CMD_PATH_OVERRIDE) abuild checksum" + +sign: + rm -f $(TARGET)/packages/$(ARCH)/APKINDEX.tar.gz + cd $(TARGET)/packages/$(ARCH) && apk index -o APKINDEX.tar.gz --rewrite-arch $(ARCH) *.apk + sg abuild "abuild-sign -q -k $(KEYFILE) $(TARGET)/packages/$(ARCH)/APKINDEX.tar.gz" + +tgz: + cd $(TARGET)/ && tar cvzf syndicate-system-apks.tar.gz packages + + +clean.packages: + @if [ $$(grep $(USER) /etc/passwd | wc -l) -ne 0 ] && [ -e /usr/bin/abuild ]; then \ + for package in packages/*; do \ + if [ -e $$package/APKBUILD ]; then \ + echo "Cleaning $$package..."; \ + $(SU_CMD) -c "cd $$package && $(SU_CMD_PATH_OVERRIDE) abuild clean"; \ + fi; \ + done; \ + fi + +clean: clean.packages + @[ "$$(grep $(USER) /etc/passwd)" = "" ] || deluser $(USER) + @[ ! -e /etc/sudoers ] || sed -i 's/^$(USER).*$$//' /etc/sudoers + @[ "$$(mount | grep ' on /var/cache/distfiles ')" = "" ] || umount -f /var/cache/distfiles + @chown -R $$(id -u -n):$$(id -g -n) . + rm -f .prepare + +cleantarget: + rm -rf $(TARGET) + +cleancache: + @if [ -e /usr/bin/abuild ]; then \ + for package in packages/*; do \ + if [ -e $$package/APKBUILD ]; then \ + echo "Cleaning cache of $$package..."; \ + cd $$package && sg abuild "abuild -F cleancache"; \ + fi; \ + done; \ + fi + @rm -rf /var/cache/distfiles/* + +clean.%: + @if [ -e packages/$* ]; then \ + echo "Cleaning $*..."; \ + cd packages/$* && sg abuild "abuild -F clean" && sg abuild "abuild -F cleancache"; \ + else \ + echo "Package $* does not exist"; \ + fi + +cleanapks: + rm -f $(TARGET)/syndicate-system-apks.tar.gz + +cleanall: clean cleantarget cleancache cleanapks diff --git a/experiments/alpine-standalone/apks/build-via-docker.sh b/experiments/alpine-standalone/apks/build-via-docker.sh new file mode 100644 index 0000000..79fa2cb --- /dev/null +++ b/experiments/alpine-standalone/apks/build-via-docker.sh @@ -0,0 +1,39 @@ +#!/bin/sh +# +# Originally based on build-via-docker.sh from the FRμIT project, +# https://fruit-testbed.org/, which is CC Attribution-ShareAlike 4.0 +# licensed. + +ALPINE_VERSION=${ALPINE_VERSION:-v3.14} +DOCKER_ARCH=${DOCKER_ARCH:-aarch64} + +# If you run: +# docker run --rm --name squid adricu/alpine-squid +# and set DOCKER_SQUID_CONTAINER=squid +# then you can avoid repeated downloads of a lot of alpine packages. +# +DOCKER_SQUID_CONTAINER=${DOCKER_SQUID_CONTAINER:-""} +if [ "$DOCKER_SQUID_CONTAINER" = "" ]; then + docker_squid_opts="" +else + docker_squid_opts="--link ${DOCKER_SQUID_CONTAINER}:squid -e http_proxy=http://squid:3128/" +fi + +cd "$(dirname "$0")" + +tmpscript=$(mktemp tmpscript.XXXXXXXXXX) +trap "rm -f $tmpscript" 0 + +cat > $tmpscript < ${NEWROOT}$mp" + mount -o move $mp ${NEWROOT}$mp + done + + echo "Killing leftovers." + kill -15 -1 + sleep 0.2 + kill -9 -1 + + echo "Switching root." + exec switch_root -c ${CONSOLE} ${NEWROOT} /init +else + echo "Initializing with real rootfs." + + echo "Re-configuring network." + ifconfig lo 127.0.0.1 up + ifconfig eth0 up + udhcpc -i eth0 + + echo "Ensuring installation of /package-list." + apk add $(cat /package-list) +fi + +sync + +echo "Dropping to shell." + +# setsid creates a "session", which allows job control to work +exec setsid sh -c "exec sh -i <${CONSOLE} >${CONSOLE} 2>&1" diff --git a/experiments/alpine-standalone/pack-image.sh b/experiments/alpine-standalone/pack-image.sh new file mode 100755 index 0000000..c77f7bc --- /dev/null +++ b/experiments/alpine-standalone/pack-image.sh @@ -0,0 +1,111 @@ +#!/bin/sh +# +# Originally loosely based on pack-image.sh from the FRμIT project, +# https://fruit-testbed.org/, which is CC Attribution-ShareAlike 4.0 +# licensed. +# +# Run this script after the packages are available in +# apks/target/packages. + +set -xe + +INITRAMFS=${INITRAMFS:-initramfs-syndicate-system} +NATIVE_COMMANDS=${NATIVE_COMMANDS:-no} +DOCKER_ARCH=${DOCKER_ARCH:-aarch64} +ALPINE_VERSION=${ALPINE_VERSION:-v3.14} +VERSION=${VERSION:-0.1.0} +MOUNTPOINT=${MOUNTPOINT:-`pwd`/newroot} + +# docker run --rm --name squid adricu/alpine-squid +DOCKER_PROXY_ARGS=${DOCKER_PROXY_ARGS:- --link squid -e http_proxy=http://squid:3128/} + +PACKAGES=${PACKAGES:-} + +die () { + echo "$1" >&2 + exit 1 +} + +die_if_empty () { + [ ! -z "$2" ] || die "No $1 specified." +} + +die_if_empty PACKAGES "$PACKAGES" +die_if_empty VERSION "$VERSION" + +invoke_command () { + # Shell quoting is a nightmare. Beware spaces. + # + if [ "$NATIVE_COMMANDS" = "yes" ] + then + $@ + else + tmpscript=$(mktemp tmpscript.XXXXXXXXXX) + echo "$@" > $tmpscript + docker run -it --rm -v `pwd`:`pwd` \ + ${DOCKER_PROXY_ARGS} \ + multiarch/alpine:${DOCKER_ARCH}-${ALPINE_VERSION} \ + /bin/sh -c "cd `pwd`; sh $tmpscript" + rm -f $tmpscript + fi +} + +########################################################################### + +TMP_REPO_FILE=$(mktemp repositories.XXXXXXXXXX) + +cleanup () { + # rm -rf ${MOUNTPOINT} || true + rm -f ${TMP_REPO_FILE} || true +} + +trap cleanup 0 + +cat < /dev/null > ${TMP_REPO_FILE} +echo "`pwd`/apks/target/packages" >> ${TMP_REPO_FILE} +echo "https://dl-cdn.alpinelinux.org/alpine/${ALPINE_VERSION}/main" >> ${TMP_REPO_FILE} +echo "https://dl-cdn.alpinelinux.org/alpine/${ALPINE_VERSION}/community" >> ${TMP_REPO_FILE} + +# Create root file system. +# +echo "Repositories:" +cat ${TMP_REPO_FILE} +apkcmd="apk --repositories-file `pwd`/${TMP_REPO_FILE} -U --allow-untrusted" +invoke_command ${apkcmd} --root ${MOUNTPOINT} --initdb add ${PACKAGES} +# invoke_command ${apkcmd} --no-script --root ${MOUNTPOINT} add mkinitfs + +# Allow root logins on ttyS0 / ttyAMA0 +# +tmpsecuretty=$(mktemp tmpsecuretty.XXXXXXXXXX) +cat ${MOUNTPOINT}/etc/securetty | egrep -v '(ttyS0|ttyAMA0)' > $tmpsecuretty +echo ttyS0 >> $tmpsecuretty +echo ttyAMA0 >> $tmpsecuretty +cat $tmpsecuretty > ${MOUNTPOINT}/etc/securetty +rm -f $tmpsecuretty + +cat > ${MOUNTPOINT}/etc/os-release < ${MOUNTPOINT}/etc/apk/repositories < ${INITRAMFS} + +trap - 0 +cleanup diff --git a/experiments/alpine-standalone/package-list b/experiments/alpine-standalone/package-list new file mode 100644 index 0000000..8fa7903 --- /dev/null +++ b/experiments/alpine-standalone/package-list @@ -0,0 +1,6 @@ +alpine-baselayout +alpine-keys +btrfs-progs +linux-virt +parted +s6