#!/bin/sh

set -exu

# the archive with the highest priority where the base-files package comes from
# determines whether we are on stable, testing or unstable
DEFAULT_DIST=$(cat << END | python3 -
import apt_pkg, sys
apt_pkg.init()
c = apt_pkg.Cache(None)
d = apt_pkg.DepCache(c)
s = apt_pkg.SourceList()
s.read_main_list()

highest_prio = -1
highest_archive = None
for pkgfile, _ in d.get_candidate_ver(c["base-files"]).file_list:
	print("processing: %s"%pkgfile, file=sys.stderr)
	index = s.find_index(pkgfile)
	if index is None:
		print("index is none -- skipping", file=sys.stderr)
		continue
	if not index.is_trusted:
		print("index is not trusted -- skipping", file=sys.stderr)
		continue
	archive = pkgfile.archive
	if archive not in ["stable", "testing", "unstable"]:
		print("index archive %s is %s -- skipping"%(index, archive), file=sys.stderr)
		continue
	prio = d.policy.get_priority(pkgfile)
	if prio > highest_prio:
		highest_prio = prio
		highest_archive = archive
if highest_archive is None:
	print("highest priority apt archive is neither stable, testing or unstable", file=sys.stderr)
	for f in c.file_list:
		print('========================', file=sys.stderr)
		for a in ['architecture', 'archive', 'codename', 'component', 'filename', 'id', 'index_type', 'label', 'not_automatic', 'not_source', 'origin', 'site', 'size', 'version']:
			print("%s: %s"%(a, getattr(f, a, None)), file=sys.stderr)
		print("priority: ", d.policy.get_priority(f), file=sys.stderr)
	exit(1)
print("highest archive priority: %s"%highest_archive, file=sys.stderr)
print(highest_archive)
END
)

# On stable and testing we can run tests that require m-a:same packages to
# exist in the same version across multiple architectures. Only on unstable we
# disable this because packages in unstable are often out-of-sync.
RUN_MA_SAME_TESTS=yes
case $DEFAULT_DIST in
	unstable)
		RUN_MA_SAME_TESTS=no
		;;
	stable|testing)
		# nothing to do
		;;
	*)
		echo "unknown distribution $DEFAULT_DIST, must be one of stable, testing or unstable" >&2
		;;
esac

SRC="$(pwd)"

# change to temporary directory to not interfere with the source
cd "$AUTOPKGTEST_TMP"

# coverage.sh expects the scripts to be in the current directory
# we copy make_mirror.sh instead of symlinking it because we are going to patch
# it
cp -a "$SRC/make_mirror.sh" make_mirror.sh
ln -s "$SRC/run_qemu.sh" run_qemu.sh
ln -s "$SRC/run_null.sh" run_null.sh

## All of this is a temporary workaround until #909637 is fixed and we can use
## fakechroot instead
#
## make_mirror.sh runs ./mmdebstrap with --mode=unshare. Since we don't want to
## require machine isolation, we create a small wrapper script which is suid
## root and calls the *installed* mmdebstrap with --mode=root
## We need to make use of the suid bit because we run coverage.sh as a normal
## user but need to run mmdebstrap as root.
## Shell scripts cannot have the suid bit, so we need to compile a small C
## program.
#
#cat << 'END' > ./suidexec.c
##include <stdlib.h>
##include <sys/types.h>
##include <unistd.h>
#int main(int argc, char* argv[]) {
#	char **args = (char **)malloc(sizeof(char*)*argc+2);
#	args[0] = "mmdebstrap";
#	for (int i = 1; i < argc; ++i) {
#		args[i] = argv[i];
#	}
#	args[argc] = "--mode=root";
#	args[argc+1] = (char *)NULL;
#	setuid(0);
#	execv("/usr/bin/mmdebstrap", args);
#}
#END
#gcc ./suidexec.c -o ./mmdebstrap
#
#chmod u+s,a+x ./mmdebstrap

# on Debian Salsa CI, $AUTOPKGTEST_NORMAL_USER is empty
if [ -z "$AUTOPKGTEST_NORMAL_USER" ]; then
	AUTOPKGTEST_NORMAL_USER=debci
	useradd --create-home --groups sudo "$AUTOPKGTEST_NORMAL_USER"
#	useradd --create-home --groups kvm "$AUTOPKGTEST_NORMAL_USER"
#	ls -lha /dev/kvm || true
#	lsmod | grep kvm || true
else
	adduser "$AUTOPKGTEST_NORMAL_USER" sudo
#	adduser "$AUTOPKGTEST_NORMAL_USER" kvm
fi

mkdir ./shared
chown "$AUTOPKGTEST_NORMAL_USER" ./shared

echo "$AUTOPKGTEST_NORMAL_USER ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers

# add symlink from cache to cache.A so that debootstrap finds all the packages
# which are put into cache.A even before make_mirror.sh creates the symlink
# itself
ln -s cache.A "$AUTOPKGTEST_TMP/shared/cache"
# we cannot use mini_httpd (or most other http servers) because they perform a
# chdir() into the directory that is to be served on startup. But later on we
# completely remove and replace that directory when creating the Debian mirror.
# Thus we need a really stupid server which is able to cope with having its
# www-root being replaced under its feet.
#mini_httpd -D -h 127.0.0.1 -p 80 -u "$AUTOPKGTEST_NORMAL_USER" -T UTF-8 -dd "$AUTOPKGTEST_TMP/shared/cache" &
python3 -m http.server --directory="$AUTOPKGTEST_TMP/shared/cache" --bind 127.0.0.1 80 2>/dev/null &
HTTPD_PID=$!
trap "kill $HTTPD_PID" INT QUIT TERM EXIT

# create a fake mmdebstrap file in the current directory that coverage.sh can
# copy
cat << END > ./mmdebstrap
#!/usr/bin/perl
use strict;
use warnings;
exit(1)
END

cat << END > ./taridshift
#!/usr/bin/env python3
exit(1)
END

# add entries to /etc/subuid and /etc/subgid if they don't exist yet
if [ ! -e /etc/subuid ] || ! grep "$AUTOPKGTEST_NORMAL_USER" /etc/subuid; then
	echo "$AUTOPKGTEST_NORMAL_USER:100000:65536" >> /etc/subuid
fi
if [ ! -e /etc/subgid ] || ! grep "$AUTOPKGTEST_NORMAL_USER" /etc/subgid; then
	echo "$AUTOPKGTEST_NORMAL_USER:100000:65536" >> /etc/subgid
fi

# we cannot add foreign architecture dependencies to debian/tests/control
# See https://bugs.debian.org/913082
if [ "$RUN_MA_SAME_TESTS" = "yes" ]; then
	dpkg --add-architecture armhf
	apt-get update
	apt-get install --yes libfakechroot:armhf libfakeroot:armhf
fi

## wrap umount because /proc refuses to cleanly unmount under lxc if the
## packages binfmt-support and qemu-user-static are installed in debootstrap
## variant
#mkdir ./bin
#cat << 'END' > ./bin/umount
##!/bin/sh
#exec /bin/umount --lazy "$@"
#END
#chmod +x ./bin/umount
#
## place the installed mmdebstrap into the current directory so that coverage.sh
## can copy it into the shared directory
#cp /usr/bin/mmdebstrap ./shared
#
## runuser will not touch XDG_RUNTIME_DIR but guestfish needs it
## The usual directory /run/user/$(id -u $AUTOPKGTEST_NORMAL_USER) doesn't seem
## to exist, $AUTOPKGTEST_NORMAL_USER has no write access to $AUTOPKGTEST_TMP
#mkdir "/home/$AUTOPKGTEST_NORMAL_USER/run"
#chmod 0700 "/home/$AUTOPKGTEST_NORMAL_USER/run"
#chown "$AUTOPKGTEST_NORMAL_USER" "/home/$AUTOPKGTEST_NORMAL_USER/run"
#export XDG_RUNTIME_DIR="/home/$AUTOPKGTEST_NORMAL_USER/run"

echo "running on:"
cat /etc/debian_version
echo "environment:"
env

i=0
while true; do
	rm -rf ./shared
	mkdir ./shared
	chown "$AUTOPKGTEST_NORMAL_USER" ./shared
	ln -s cache.A "$AUTOPKGTEST_TMP/shared/cache"
	ret=0
	timeout 20m runuser -u "$AUTOPKGTEST_NORMAL_USER" -- env CMD=mmdebstrap DEFAULT_DIST=$DEFAULT_DIST RUN_MA_SAME_TESTS=$RUN_MA_SAME_TESTS HAVE_UNSHARE=no HAVE_QEMU=no HAVE_PROOT=no HAVE_BINFMT=no "$SRC/make_mirror.sh" || ret=$?
	# success -- break the loop
	if [ "$ret" -eq 0 ]; then
		break
	fi
	i=$((i+1))

	# too many failures -- exit
	if [ "$i" -ge 3 ]; then
		echo "too many failures, giving up"
		exit 77
	fi

	# trying again...
	echo "make_mirror.sh failed, trying again..."
	sleep 5m
done

# now run the script
# we set PATH so that the umount wrapper is used
# we set CMD so that Devel::Cover is not used
#runuser -u "$AUTOPKGTEST_NORMAL_USER" -- env CMD=./mmdebstrap PATH="$AUTOPKGTEST_TMP/bin:/bin:/usr/bin" "$SRC/coverage.sh"
# HAVE_PROOT=no or otherwise:
#    proot error: can't retrieve loader path (/proc/self/fd/)
#    proot error: execve("/usr/bin/mv"): No such file or directory
#    proot info: possible causes:
#      * the program is a script but its interpreter (eg. /bin/sh) was not found;
#      * the program is an ELF but its interpreter (eg. ld-linux.so) was not found;
#      * the program is a foreign binary but qemu was not specified;
#      * qemu does not work correctly (if specified);
#      * the loader was not found or doesn't work.
#    fatal error: see `proot --help`.
# HAVE_UNSHARE=no or otherwise:
#    newuidmap: Could not open proc directory for target 23920
#    newuidmap 23920  0 1000 1 1 100000 1 failed:  at /usr/bin/mmdebstrap line 319.
#    child had a non-zero exit status: 1 at /usr/bin/mmdebstrap line 341.
#    chown failed at /usr/bin/mmdebstrap line 1698.
# HAVE_QEMU=no because there is no kvm kernel module
# HAVE_BINFMT=no because there is no binfmt_misc kernel module
runuser -u "$AUTOPKGTEST_NORMAL_USER" -- env CMD=mmdebstrap DEFAULT_DIST=$DEFAULT_DIST RUN_MA_SAME_TESTS=$RUN_MA_SAME_TESTS HAVE_UNSHARE=no HAVE_QEMU=no HAVE_PROOT=no HAVE_BINFMT=no "$SRC/coverage.sh"
