#!/bin/sh
# Copyright 2022 Jochen Sprickerhof
# Copyright 2022 Simon McVittie
# SPDX-License-Identifier: GPL-2.0-or-later

set -eu

cache_script="$(dirname "$(readlink -f "$0")")/cache-test-packages"

if [ -z "${vendor:-}" ]; then
    if dpkg-vendor --is ubuntu; then
        vendor=ubuntu
    else
        vendor=debian
    fi
fi

if [ "$vendor" = ubuntu ]; then
    mirror="http://archive.ubuntu.com/ubuntu"
    suite=${suite:-$(ubuntu-distro-info --latest)}
    components="main universe"
elif [ "$vendor" = debian ]; then
    mirror="http://deb.debian.org/debian"
    suite=${suite:-testing}
    components="main"
else
    echo "Unsupported vendor: $vendor" >&2
    exit 1
fi

scratch="$(mktemp -d)"

# Skip test if util-linux is too old. This can happen when backporting
# to older releases. This check can be dropped once all the plausible
# backport target releases will ship util-linux (>= 2.38).
if dpkg --compare-versions "$(dpkg-query -W -f '${Version}' util-linux)" lt 2.38; then
    echo "SKIP: util-linux is too old using the unshare virt server."
    exit 77
fi

# Skip the test if unprivileged namespaces are restricted, see:
# https://gitlab.com/apparmor/apparmor/-/wikis/unprivileged_userns_restriction.
# This is the default in (some?) Ubuntu systems.
if [ "$(/usr/sbin/sysctl -ne kernel.apparmor_restrict_unprivileged_userns)" = 1 ]; then
    echo "SKIP: unprivileged namespaces are restricted (kernel.apparmor_restrict_unprivileged_userns=1)"
    exit 77
fi

# --skip=cleanup/apt/lists: expected by tests, alternatively autopkgtest -U
# shellcheck disable=SC2016
set -- --include=eatmydata,dpkg-dev \
    --mode=unshare \
    --skip=cleanup/apt/lists,cleanup/apt/cache \
    --variant=apt \
    --customize-hook='chroot "$1" apt-mark auto dpkg-dev'
if [ "$vendor" = ubuntu ]; then
    set -- "$@" --include=ubuntu-keyring
    if [ "$suite" != xenial ]; then
        set -- "$@" --keyring=/usr/share/keyrings/ubuntu-archive-keyring.gpg
    fi
fi
source_options=
if [ "$vendor" = ubuntu ] && [ "$suite" = xenial ]; then
    # Skip archive authentication: modern policy rejects Xenial's signing keys.
    source_options='[trusted=yes]'
    # Xenial's systemd postinst calls chfn, whose PAM stack fails during
    # bootstrap. Temporarily divert chfn during bootstrap; restore it before
    # the rootfs tarball is used as an autopkgtest testbed.
    # shellcheck disable=SC2016
    set -- "$@" \
        --extract-hook='dpkg-divert --root="$1" --add --rename --local --divert /usr/bin/chfn.distrib /usr/bin/chfn && printf "#!/bin/sh\nexit 0\n" > "$1/usr/bin/chfn" && chmod 755 "$1/usr/bin/chfn"' \
        --customize-hook='rm -f "$1/usr/bin/chfn" && dpkg-divert --root="$1" --remove --rename --local --divert /usr/bin/chfn.distrib /usr/bin/chfn'
fi

# Let the hook's mapped user traverse scratch to read the copied script.
cp "$cache_script" "$scratch/cache-test-packages"
chmod 711 "$scratch"
set -- "$@" \
    "--customize-hook=chroot \"\$1\" sh < \"$scratch/cache-test-packages\""

source_options=${source_options:+$source_options }
set -- "$@" \
    "$suite" \
    "$scratch/rootfs.tar" \
    "deb ${source_options}$mirror $suite $components" \
    "deb-src ${source_options}$mirror $suite $components"
if [ "$vendor" = ubuntu ]; then
    set -- "$@" \
        "deb ${source_options}$mirror $suite-updates $components" \
        "deb ${source_options}$mirror $suite-security $components" \
        "deb-src ${source_options}$mirror $suite-updates $components" \
        "deb-src ${source_options}$mirror $suite-security $components"
fi

if ! mmdebstrap "$@"; then
    echo "SKIP: Unable to create rootfs tarball"
    rm -fr "$scratch"
    exit 77
fi

export AUTOPKGTEST_TEST_UNSHARE="$scratch/rootfs.tar"

if [ -z "${AUTOPKGTEST_TEST_UNINSTALLED-}" ]; then
    export AUTOPKGTEST_TEST_INSTALLED=yes
fi

# Wrapping the test in annotate-output helps to distinguish the output of
# the autopkgtest that is running these tests from the output of the
# autopkgtest that is under test, which would otherwise be really confusing.
e=0
annotate-output ./tests/autopkgtest UnshareRunner || e=1
rm -fr "$scratch"
exit "$e"
