#!/bin/sh
# Copyright 2022 Helmut Grohne <helmut@subdivi.de>
# SPDX-License-Identifier: MIT

# shellcheck disable=SC2016 # Intentional quoting technique

set -u

ARCHITECTURE=$(dpkg --print-architecture)
IMAGE=rootfs.ext2
INCLUDE_PACKAGES=init
MIRROR="http://deb.debian.org/debian"
SIZE=$((1024*1024*1024))
SSHKEY=
SUITE=unstable
VMNAME=testvm

die() {
	echo "$*" 1>&2
	exit 1
}

usage() {
	die "usage: $0 [-a architecture] [-h hostname] [-k sshkey] [-m mirror] [-o output] [-p packages] [-r release] [-s size_in_GB] [-- mmdebstrap options]"
}


while test "$#" -gt 0; do
	case "$1" in
		-a)
			test "$#" -eq 1 && usage
			ARCHITECTURE=$2
			shift 2
		;;
		-h)
			test "$#" -eq 1 && usage
			VMNAME=$2
			shift 2
		;;
		-k)
			test "$#" -eq 1 && usage
			SSHKEY=$2
			shift 2
		;;
		-m)
			test "$#" -eq 1 && usage
			MIRROR=$2
			shift 2
		;;
		-o)
			test "$#" -eq 1 && usage
			IMAGE=$2
			shift 2
		;;
		-p)
			test "$#" -eq 1 && usage
			INCLUDE_PACKAGES="$INCLUDE_PACKAGES,$2"
			shift 2
		;;
		-r)
			test "$#" -eq 1 && usage
			SUITE=$2
			shift 2
		;;
		-s)
			test "$#" -eq 1 && usage
			SIZE=$(($2*1024*1024*1024))
			shift 2
		;;
		--)
			shift
			break
		;;
		*)
			usage
		;;
	esac
done

if test -n "$SSHKEY" && ! test -f "$SSHKEY"; then
	die "error: ssh keyfile '$SSHKEY' not found"
fi

KERNEL_SUFFIX=-$ARCHITECTURE
case "$ARCHITECTURE" in
	amd64|arm64)
		KERNEL_SUFFIX="-cloud-$ARCHITECTURE"
		if test "$SUITE" = jessie || test "$SUITE" = stretch; then
			KERNEL_SUFFIX="-$ARCHITECTURE"
		fi
	;;
	armhf)
		KERNEL_SUFFIX=-armmp
	;;
	i386)
		KERNEL_SUFFIX=-686-pae
	;;
	mips64el)
		KERNEL_SUFFIX=-mips64r2el
	;;
	mipsel)
		KERNEL_SUFFIX=-mips32r2el
	;;
	ppc64el)
		KERNEL_SUFFIX=-powerpc64le
	;;
esac

INCLUDE_PACKAGES="$INCLUDE_PACKAGES,linux-image$KERNEL_SUFFIX"

if test -n "$SSHKEY"; then
	INCLUDE_PACKAGES="$INCLUDE_PACKAGES,openssh-server"
fi

# add a DNS resolver
case "$SUITE" in
	jessie)
		set -- '--customize-hook=chroot "$1" systemctl enable systemd-resolved.service' "$@"
		set -- '--customize-hook=ln -fs ../run/systemd/resolve/resolv.conf "$1/etc/resolv.conf"' "$@"
	;;
	stretch)
		set -- '--customize-hook=chroot "$1" systemctl enable systemd-resolved.service' "$@"
		set -- '--customize-hook=ln -fs ../run/systemd/resolve/resolv.conf "$1/etc/resolv.conf"' "$@"
		INCLUDE_PACKAGES="$INCLUDE_PACKAGES,libnss-resolve"
	;;
	buster|bullseye|stable)
		set -- '--customize-hook=chroot "$1" systemctl enable systemd-resolved.service' "$@"
		set -- '--customize-hook=ln -fs ../run/systemd/resolve/stub-resolv.conf "$1/etc/resolv.conf"' "$@"
		INCLUDE_PACKAGES="$INCLUDE_PACKAGES,libnss-resolve"
	;;
	*)
		INCLUDE_PACKAGES="$INCLUDE_PACKAGES,libnss-resolve"
	;;
esac

# construct mmdebstrap options as $@:
set -- \
	--verbose \
	--variant=apt \
	--format=ext2 \
	"--architecture=$ARCHITECTURE" \
	"--include=$INCLUDE_PACKAGES" \
	"$@"

# unless we set up a fstab, / will be read-only
set -- "--customize-hook=echo 'LABEL=debvm / ext4 defaults 0 1' >"'"$1/etc/fstab"' "$@"

# set up a hostname
set -- \
	"--customize-hook=echo $VMNAME >"'"$1/etc/hostname"' \
	"--customize-hook=echo 127.0.0.1 localhost $VMNAME >"'"$1/etc/hosts"' \
	"$@"

# allow password-less root login
set -- '--customize-hook=chroot "$1" passwd --delete root' "$@"

# dhcp on all network interfaces
set -- \
	'--customize-hook=chroot "$1" systemctl enable systemd-networkd.service' \
	"--customize-hook=printf '"'[Match]\nName=en*\nName=eth*\n[Network]\nDHCP=yes\n[DHCP]\nUseDomains=yes\n'"'"' > "$1/etc/systemd/network/20-wired.network"' \
	"$@"

# add ssh key for root
if test -n "$SSHKEY"; then
	set -- \
		'--customize-hook=mkdir -p "$1/root/.ssh"' \
		"--customize-hook=upload $SSHKEY /root/.ssh/authorized_keys" \
		"$@"
fi

set -- --skip=cleanup/apt "$@"

case "$SUITE" in
	jessie)
		# Use obsolete and expired keys.
		set -- '--keyring=/usr/share/keyrings/debian-archive-removed-keys.gpg' "$@"
		set -- --aptopt='Apt::Key::gpgvcommand "/usr/libexec/mmdebstrap/gpgvnoexpkeysig"' "$@"
		# chfn does not work, because libpam-runtime.postinst is late setting up /etc/pam.d/common-auth et al, see #1026765
		set -- --extract-hook='chroot "$1" pam-auth-update --package --force' "$@"
	;;
	buster)
		# We need /var/lib/dpkg/available for dpkg --set-selections to work.
		set -- '--customize-hook=cat "$1"/var/lib/apt/lists/*_Packages | chroot "$1" dpkg --update-avail' "$@"
	;;
	bookworm|testing|sid|unstable)
		# Avoid the usrmerge package
		set -- --hook-dir=/usr/share/mmdebstrap/hooks/merged-usr "$@"
	;;
esac

# suite target mirror
set -- "$@" "$SUITE" "$IMAGE" "deb $MIRROR $SUITE main"

set -ex

mmdebstrap "$@"

truncate -s "$SIZE" "$IMAGE"
/sbin/resize2fs "$IMAGE"
/sbin/tune2fs -L debvm -i 0 -O extents,uninit_bg,dir_index,has_journal "$IMAGE"