diff --git a/coverage.py b/coverage.py new file mode 100755 index 0000000..fbdb772 --- /dev/null +++ b/coverage.py @@ -0,0 +1,220 @@ +#!/usr/bin/env python3 + +from debian.deb822 import Deb822 +import os +import sys +import shutil +import subprocess +import argparse +import time +from datetime import timedelta +from collections import defaultdict + +have_qemu = os.getenv("HAVE_QEMU", "yes") == "yes" +have_unshare = os.getenv("HAVE_UNSHARE", "yes") == "yes" +have_binfmt = os.getenv("HAVE_BINFMT", "yes") == "yes" +run_ma_same_tests = os.getenv("RUN_MA_SAME_TESTS", "yes") == "yes" + +default_dist = os.getenv("DEFAULT_DIST", "unstable") +all_dists = ["oldstable", "stable", "testing", "unstable"] +default_mode = "auto" if have_unshare else "root" +all_modes = ["auto", "root", "unshare", "fakechroot", "chrootless"] +default_variant = "apt" +all_variants = [ + "extract", + "custom", + "essential", + "apt", + "minbase", + "buildd", + "-", + "standard", +] +default_format = "auto" +all_formats = ["auto", "directory", "tar", "squashfs", "ext2", "null"] + +only_dists = [] + +mirror = os.getenv("mirror", "http://127.0.0.1/debian") +hostarch = subprocess.check_output(["dpkg", "--print-architecture"]).decode().strip() + +separator = ( + "------------------------------------------------------------------------------" +) + + +def skip(condition, dist, mode, variant, fmt): + if not condition: + return "" + for line in condition.splitlines(): + if not line: + continue + if eval(line): + return line.strip() + return "" + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("test", nargs="*", help="only run these tests") + parser.add_argument( + "-x", + "--exitfirst", + action="store_const", + dest="maxfail", + const=1, + help="exit instantly on first error or failed test.", + ) + parser.add_argument( + "--maxfail", + metavar="num", + action="store", + type=int, + dest="maxfail", + default=0, + help="exit after first num failures or errors.", + ) + args = parser.parse_args() + + onlyrun = None + if len(sys.argv) > 1: + onlyrun = sys.argv[1] + + tests = [] + with open("coverage.txt") as f: + for test in Deb822.iter_paragraphs(f): + name = test["Test"] + if args.test and name not in args.test: + continue + dists = test.get("Dists", default_dist) + if dists == "any": + dists = all_dists + elif dists == "default": + dists = [default_dist] + else: + dists = dists.split() + modes = test.get("Modes", default_mode) + if modes == "any": + modes = all_modes + elif modes == "default": + modes = [default_mode] + else: + modes = modes.split() + variants = test.get("Variants", default_variant) + if variants == "any": + variants = all_variants + elif variants == "default": + variants = [default_variant] + else: + variants = variants.split() + formats = test.get("Formats", default_format) + if formats == "any": + formats = all_formats + elif formats == "default": + formats = [default_format] + else: + formats = formats.split() + for dist in dists: + if only_dists and dist not in only_dists: + continue + for mode in modes: + for variant in variants: + for fmt in formats: + skipreason = skip( + test.get("Skip-If"), dist, mode, variant, fmt + ) + if skipreason: + tt = ("skip", skipreason) + elif have_qemu: + tt = "qemu" + elif test.get("Needs-QEMU", "false") == "true": + tt = ("skip", "test needs QEMU") + elif test.get("Needs-Root", "false") == "true": + tt = "sudo" + elif mode == "auto" and not have_unshare: + tt = "sudo" + elif mode == "root": + tt = "sudo" + elif mode == "unshare" and not have_unshare: + tt = ("skip", "test needs unshare") + else: + tt = "null" + tests.append((tt, name, dist, mode, variant, fmt)) + + starttime = time.time() + skipped = defaultdict(list) + failed = [] + for i, (test, name, dist, mode, variant, fmt) in enumerate(tests): + print(separator, file=sys.stderr) + print("(%d/%d) %s" % (i + 1, len(tests), name), file=sys.stderr) + print("dist: %s" % dist, file=sys.stderr) + print("mode: %s" % mode, file=sys.stderr) + print("variant: %s" % variant, file=sys.stderr) + print("format: %s" % fmt, file=sys.stderr) + if i > 0: + currenttime = time.time() + timeleft = timedelta( + seconds=(len(tests) - i) * (currenttime - starttime) / i + ) + print("time left: %s" % timeleft, file=sys.stderr) + with open("tests/" + name) as fin, open("shared/test.sh", "w") as fout: + for line in fin: + for e in ["CMD", "SOURCE_DATE_EPOCH"]: + line = line.replace("{{ " + e + " }}", os.getenv(e)) + line = line.replace("{{ DIST }}", dist) + line = line.replace("{{ MIRROR }}", mirror) + line = line.replace("{{ MODE }}", mode) + line = line.replace("{{ VARIANT }}", variant) + line = line.replace("{{ FORMAT }}", fmt) + line = line.replace("{{ HOSTARCH }}", hostarch) + fout.write(line) + argv = None + match test: + case "qemu": + argv = ["./run_qemu.sh"] + case "sudo": + argv = ["./run_null.sh", "SUDO"] + case "null": + argv = ["./run_null.sh"] + case ("skip", reason): + skipped[reason].append( + ("(%d/%d) %s" % (i + 1, len(tests), name), dist, mode, variant, fmt) + ) + print(f"skipped because of {reason}", file=sys.stderr) + continue + print(separator, file=sys.stderr) + proc = subprocess.Popen(argv) + try: + proc.wait() + except KeyboardInterrupt: + proc.kill() + break + print(separator, file=sys.stderr) + if proc.returncode != 0: + failed.append( + ("(%d/%d) %s" % (i + 1, len(tests), name), dist, mode, variant, fmt) + ) + print("result: FAILURE", file=sys.stderr) + else: + print("result: SUCCESS", file=sys.stderr) + if args.maxfail and len(failed) >= args.maxfail: + break + print( + "successully ran %d tests" % (len(tests) - len(skipped) - len(failed)), + file=sys.stderr, + ) + if skipped: + print("skipped %d:" % len(skipped), file=sys.stderr) + for reason, l in skipped.items(): + print(f"skipped because of {reason}:", file=sys.stderr) + for t in l: + print(f" {t}", file=sys.stderr) + if failed: + print("failed %d:" % len(failed), file=sys.stderr) + for t in failed: + print(f" {t}", file=sys.stderr) + exit(1) + + +if __name__ == "__main__": + main() diff --git a/coverage.sh b/coverage.sh index c4765b6..9fe5d6d 100755 --- a/coverage.sh +++ b/coverage.sh @@ -2,7 +2,7 @@ set -eu -if [ -e ./mmdebstrap -a -e ./taridshift -a -e ./tarfilter ]; then +if [ -e ./mmdebstrap -a -e ./taridshift -a -e ./tarfilter -a -e ./coverage.py ]; then TMPFILE=$(mktemp) perltidy < ./mmdebstrap > "$TMPFILE" ret=0 @@ -21,7 +21,7 @@ if [ -e ./mmdebstrap -a -e ./taridshift -a -e ./tarfilter ]; then perlcritic --severity 4 --verbose 8 ./mmdebstrap - black --check ./taridshift ./tarfilter + black --check ./taridshift ./tarfilter ./coverage.py fi mirrordir="./shared/cache/debian" @@ -37,10 +37,6 @@ rm -f shared/cover_db.img : "${DEFAULT_DIST:=unstable}" : "${HAVE_QEMU:=yes}" : "${RUN_MA_SAME_TESTS:=yes}" -: "${ONLINE:=no}" -: "${CONTAINER:=no}" - -HOSTARCH=$(dpkg --print-architecture) if [ "$HAVE_QEMU" = "yes" ]; then # prepare image for cover_db @@ -141,25 +137,6 @@ if [ ! -e shared/hooks/file-mirror-automount/customize00.sh ] || [ hooks/file-mi cp -a /usr/share/mmdebstrap/hooks/file-mirror-automount/customize00.sh shared/hooks/file-mirror-automount/ fi fi -starttime= -total=184 -skipped=0 -runtests=0 -i=1 - -print_header() { - echo ------------------------------------------------------------------------------ >&2 - echo "($i/$total) $1" >&2 - if [ -z "$starttime" ]; then - starttime=$(date +%s) - else - currenttime=$(date +%s) - timeleft=$(((total-i+1)*(currenttime-starttime)/(i-1))) - printf "time left: %02d:%02d:%02d\n" $((timeleft/3600)) $(((timeleft%3600)/60)) $((timeleft%60)) - fi - echo ------------------------------------------------------------------------------ >&2 - i=$((i+1)) -} # choose the timestamp of the unstable Release file, so that we get # reproducible results for the same mirror timestamp @@ -182,3591 +159,25 @@ fi : "${CMD:=perl -MDevel::Cover=-silent,-nogcov ./mmdebstrap}" mirror="http://127.0.0.1/debian" -for dist in oldstable stable testing unstable; do - for variant in minbase buildd -; do - print_header "mode=$defaultmode,variant=$variant: check against debootstrap $dist" - cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -export SOURCE_DATE_EPOCH=$SOURCE_DATE_EPOCH - -# we create the apt user ourselves or otherwise its uid/gid will differ -# compared to the one chosen in debootstrap because of different installation -# order in comparison to the systemd users -# https://bugs.debian.org/969631 -# we cannot use useradd because passwd is not Essential:yes -$CMD --variant=$variant --mode=$defaultmode \ - --essential-hook='if [ $variant = - ]; then echo _apt:*:100:65534::/nonexistent:/usr/sbin/nologin >> "\$1"/etc/passwd; fi' \ - $dist /tmp/debian-$dist-mm.tar $mirror - -mkdir /tmp/debian-$dist-mm -tar --xattrs --xattrs-include='*' -C /tmp/debian-$dist-mm -xf /tmp/debian-$dist-mm.tar -rm /tmp/debian-$dist-mm.tar - -mkdir /tmp/debian-$dist-debootstrap -tar --xattrs --xattrs-include='*' -C /tmp/debian-$dist-debootstrap -xf "cache/debian-$dist-$variant.tar" - -# diff cannot compare device nodes, so we use tar to do that for us and then -# delete the directory -tar -C /tmp/debian-$dist-debootstrap -cf dev1.tar ./dev -tar -C /tmp/debian-$dist-mm -cf dev2.tar ./dev -ret=0 -cmp dev1.tar dev2.tar || ret=\$? -if [ "\$ret" -ne 0 ]; then - if type diffoscope >/dev/null; then - diffoscope dev1.tar dev2.tar - exit 1 - else - echo "no diffoscope installed" >&2 - fi - if type base64 >/dev/null; then - base64 dev1.tar - base64 dev2.tar - exit 1 - else - echo "no base64 installed" >&2 - fi - if type xxd >/dev/null; then - xxd dev1.tar - xxd dev2.tar - exit 1 - else - echo "no xxd installed" >&2 - fi - exit 1 -fi -rm dev1.tar dev2.tar -rm -r /tmp/debian-$dist-debootstrap/dev /tmp/debian-$dist-mm/dev - -# remove downloaded deb packages -rm /tmp/debian-$dist-debootstrap/var/cache/apt/archives/*.deb -# remove aux-cache -rm /tmp/debian-$dist-debootstrap/var/cache/ldconfig/aux-cache -# remove logs -rm /tmp/debian-$dist-debootstrap/var/log/dpkg.log \ - /tmp/debian-$dist-debootstrap/var/log/bootstrap.log \ - /tmp/debian-$dist-debootstrap/var/log/alternatives.log -# remove *-old files -rm /tmp/debian-$dist-debootstrap/var/cache/debconf/config.dat-old \ - /tmp/debian-$dist-mm/var/cache/debconf/config.dat-old -rm /tmp/debian-$dist-debootstrap/var/cache/debconf/templates.dat-old \ - /tmp/debian-$dist-mm/var/cache/debconf/templates.dat-old -rm /tmp/debian-$dist-debootstrap/var/lib/dpkg/status-old \ - /tmp/debian-$dist-mm/var/lib/dpkg/status-old -# remove dpkg files -rm /tmp/debian-$dist-debootstrap/var/lib/dpkg/available -rm /tmp/debian-$dist-debootstrap/var/lib/dpkg/cmethopt -# since we installed packages directly from the .deb files, Priorities differ -# thus we first check for equality and then remove the files -chroot /tmp/debian-$dist-debootstrap dpkg --list > dpkg1 -chroot /tmp/debian-$dist-mm dpkg --list > dpkg2 -diff -u dpkg1 dpkg2 -rm dpkg1 dpkg2 -grep -v '^Priority: ' /tmp/debian-$dist-debootstrap/var/lib/dpkg/status > status1 -grep -v '^Priority: ' /tmp/debian-$dist-mm/var/lib/dpkg/status > status2 -diff -u status1 status2 -rm status1 status2 -rm /tmp/debian-$dist-debootstrap/var/lib/dpkg/status /tmp/debian-$dist-mm/var/lib/dpkg/status -# debootstrap exposes the hosts's kernel version -if [ -e /tmp/debian-$dist-debootstrap/etc/apt/apt.conf.d/01autoremove-kernels ]; then - rm /tmp/debian-$dist-debootstrap/etc/apt/apt.conf.d/01autoremove-kernels -fi -if [ -e /tmp/debian-$dist-mm/etc/apt/apt.conf.d/01autoremove-kernels ]; then - rm /tmp/debian-$dist-mm/etc/apt/apt.conf.d/01autoremove-kernels -fi -# who creates /run/mount? -if [ -e "/tmp/debian-$dist-debootstrap/run/mount/utab" ]; then - rm "/tmp/debian-$dist-debootstrap/run/mount/utab" -fi -if [ -e "/tmp/debian-$dist-debootstrap/run/mount" ]; then - rmdir "/tmp/debian-$dist-debootstrap/run/mount" -fi -# debootstrap doesn't clean apt -rm /tmp/debian-$dist-debootstrap/var/lib/apt/lists/127.0.0.1_debian_dists_${dist}_main_binary-${HOSTARCH}_Packages \ - /tmp/debian-$dist-debootstrap/var/lib/apt/lists/127.0.0.1_debian_dists_${dist}_Release \ - /tmp/debian-$dist-debootstrap/var/lib/apt/lists/127.0.0.1_debian_dists_${dist}_Release.gpg - -if [ "$variant" = "-" ]; then - rm /tmp/debian-$dist-debootstrap/etc/machine-id - rm /tmp/debian-$dist-mm/etc/machine-id - rm /tmp/debian-$dist-debootstrap/var/lib/systemd/catalog/database - rm /tmp/debian-$dist-mm/var/lib/systemd/catalog/database - - cap=\$(chroot /tmp/debian-$dist-debootstrap /sbin/getcap /bin/ping) - expected="/bin/ping cap_net_raw=ep" - if [ "$dist" = oldstable ]; then - expected="/bin/ping = cap_net_raw+ep" - fi - if [ "\$cap" != "\$expected" ]; then - echo "expected bin/ping to have capabilities \$expected" >&2 - echo "but debootstrap produced: \$cap" >&2 - exit 1 - fi - cap=\$(chroot /tmp/debian-$dist-mm /sbin/getcap /bin/ping) - if [ "\$cap" != "\$expected" ]; then - echo "expected bin/ping to have capabilities \$expected" >&2 - echo "but mmdebstrap produced: \$cap" >&2 - exit 1 - fi -fi -rm /tmp/debian-$dist-mm/var/cache/apt/archives/lock -rm /tmp/debian-$dist-mm/var/lib/apt/extended_states -rm /tmp/debian-$dist-mm/var/lib/apt/lists/lock - -# the list of shells might be sorted wrongly -for f in "/tmp/debian-$dist-debootstrap/etc/shells" "/tmp/debian-$dist-mm/etc/shells"; do - sort -o "\$f" "\$f" -done - -# Because of unreproducible uids (#969631) we created the _apt user ourselves -# and because passwd is not Essential:yes we didn't use useradd. But newer -# versions of adduser and shadow will create a different /etc/shadow -for f in shadow shadow-; do - if grep -q '^_apt:!:' /tmp/debian-$dist-debootstrap/etc/\$f; then - sed -i 's/^_apt:\*:\([^:]\+\):0:99999:7:::$/_apt:!:\1::::::/' /tmp/debian-$dist-mm/etc/\$f - fi -done - -# workaround for https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=917773 -if ! cmp /tmp/debian-$dist-debootstrap/etc/shadow /tmp/debian-$dist-mm/etc/shadow; then - echo patching /etc/shadow on $dist $variant >&2 - awk -v FS=: -v OFS=: -v SDE=\$SOURCE_DATE_EPOCH '{ print \$1,\$2,int(SDE/60/60/24),\$4,\$5,\$6,\$7,\$8,\$9 }' < /tmp/debian-$dist-mm/etc/shadow > /tmp/debian-$dist-mm/etc/shadow.bak - cat /tmp/debian-$dist-mm/etc/shadow.bak > /tmp/debian-$dist-mm/etc/shadow - rm /tmp/debian-$dist-mm/etc/shadow.bak -else - echo no difference for /etc/shadow on $dist $variant >&2 -fi -if ! cmp /tmp/debian-$dist-debootstrap/etc/shadow- /tmp/debian-$dist-mm/etc/shadow-; then - echo patching /etc/shadow- on $dist $variant >&2 - awk -v FS=: -v OFS=: -v SDE=\$SOURCE_DATE_EPOCH '{ print \$1,\$2,int(SDE/60/60/24),\$4,\$5,\$6,\$7,\$8,\$9 }' < /tmp/debian-$dist-mm/etc/shadow- > /tmp/debian-$dist-mm/etc/shadow-.bak - cat /tmp/debian-$dist-mm/etc/shadow-.bak > /tmp/debian-$dist-mm/etc/shadow- - rm /tmp/debian-$dist-mm/etc/shadow-.bak -else - echo no difference for /etc/shadow- on $dist $variant >&2 -fi - -# Because of unreproducible uids (#969631) we created the _apt user ourselves -# and because passwd is not Essential:yes we didn't use useradd. But passwd -# since 1:4.11.1+dfsg1-1 will create empty mail files, so we create it too. -# https://bugs.debian.org/1004710 -if [ $variant = - ]; then - if [ -e /tmp/debian-$dist-debootstrap/var/mail/_apt ]; then - touch /tmp/debian-$dist-mm/var/mail/_apt - chmod 660 /tmp/debian-$dist-mm/var/mail/_apt - chown 100:8 /tmp/debian-$dist-mm/var/mail/_apt - fi -fi - -# check if the file content differs -diff --unified --no-dereference --recursive /tmp/debian-$dist-debootstrap /tmp/debian-$dist-mm >&2 - -# check permissions, ownership, symlink targets, modification times using tar -# directory mtimes will differ, thus we equalize them first -find /tmp/debian-$dist-debootstrap /tmp/debian-$dist-mm -type d -print0 | xargs -0 touch --date="@$SOURCE_DATE_EPOCH" -# debootstrap never ran apt -- fixing permissions -for d in ./var/lib/apt/lists/partial ./var/cache/apt/archives/partial; do - chroot /tmp/debian-$dist-debootstrap chmod 0700 \$d - chroot /tmp/debian-$dist-debootstrap chown _apt:root \$d -done -tar -C /tmp/debian-$dist-debootstrap --numeric-owner --sort=name --clamp-mtime --mtime=$(date --utc --date=@$SOURCE_DATE_EPOCH --iso-8601=seconds) -cf /tmp/root1.tar . -tar -C /tmp/debian-$dist-mm --numeric-owner --sort=name --clamp-mtime --mtime=$(date --utc --date=@$SOURCE_DATE_EPOCH --iso-8601=seconds) -cf /tmp/root2.tar . -tar --full-time --verbose -tf /tmp/root1.tar > /tmp/root1.tar.list -tar --full-time --verbose -tf /tmp/root2.tar > /tmp/root2.tar.list -diff -u /tmp/root1.tar.list /tmp/root2.tar.list -rm /tmp/root1.tar /tmp/root2.tar /tmp/root1.tar.list /tmp/root2.tar.list - -# check if file properties (permissions, ownership, symlink names, modification time) differ -# -# we cannot use this (yet) because it cannot cope with paths that have [ or @ in them -#fmtree -c -p /tmp/debian-$dist-debootstrap -k flags,gid,link,mode,size,time,uid | sudo fmtree -p /tmp/debian-$dist-mm - -rm -r /tmp/debian-$dist-debootstrap /tmp/debian-$dist-mm -END - if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) - elif [ "$defaultmode" = "root" ]; then - ./run_null.sh SUDO - runtests=$((runtests+1)) - else - ./run_null.sh - runtests=$((runtests+1)) - fi - done -done - -# this is a solution for https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=829134 -print_header "mode=unshare,variant=custom: as debootstrap unshare wrapper" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -export SOURCE_DATE_EPOCH=$SOURCE_DATE_EPOCH -if [ ! -e /mmdebstrap-testenv ]; then - echo "this test modifies the system and should only be run inside a container" >&2 - exit 1 -fi -sysctl -w kernel.unprivileged_userns_clone=1 -adduser --gecos user --disabled-password user -runuser -u user -- $CMD --variant=custom --mode=unshare --setup-hook='env container=lxc debootstrap --no-merged-usr unstable "\$1" $mirror' - /tmp/debian-mm.tar $mirror - -mkdir /tmp/debian-mm -tar --xattrs --xattrs-include='*' -C /tmp/debian-mm -xf /tmp/debian-mm.tar +export HAVE_QEMU HAVE_UNSHARE HAVE_BINFMT RUN_MA_SAME_TESTS DEFAULT_DIST SOURCE_DATE_EPOCH CMD mirror -mkdir /tmp/debian-debootstrap -tar --xattrs --xattrs-include='*' -C /tmp/debian-debootstrap -xf "cache/debian-unstable--.tar" +./coverage.py -# diff cannot compare device nodes, so we use tar to do that for us and then -# delete the directory -tar -C /tmp/debian-debootstrap -cf dev1.tar ./dev -tar -C /tmp/debian-mm -cf dev2.tar ./dev -cmp dev1.tar dev2.tar -rm dev1.tar dev2.tar -rm -r /tmp/debian-debootstrap/dev /tmp/debian-mm/dev - -# remove downloaded deb packages -rm /tmp/debian-debootstrap/var/cache/apt/archives/*.deb -# remove aux-cache -rm /tmp/debian-debootstrap/var/cache/ldconfig/aux-cache -# remove logs -rm /tmp/debian-debootstrap/var/log/dpkg.log \ - /tmp/debian-debootstrap/var/log/bootstrap.log \ - /tmp/debian-debootstrap/var/log/alternatives.log \ - /tmp/debian-mm/var/log/bootstrap.log - -# debootstrap doesn't clean apt -rm /tmp/debian-debootstrap/var/lib/apt/lists/127.0.0.1_debian_dists_unstable_main_binary-${HOSTARCH}_Packages \ - /tmp/debian-debootstrap/var/lib/apt/lists/127.0.0.1_debian_dists_unstable_Release \ - /tmp/debian-debootstrap/var/lib/apt/lists/127.0.0.1_debian_dists_unstable_Release.gpg - -rm /tmp/debian-debootstrap/etc/machine-id /tmp/debian-mm/etc/machine-id -rm /tmp/debian-mm/var/cache/apt/archives/lock -rm /tmp/debian-mm/var/lib/apt/lists/lock - -# check if the file content differs -diff --no-dereference --recursive /tmp/debian-debootstrap /tmp/debian-mm - -# check permissions, ownership, symlink targets, modification times using tar -# mtimes of directories created by mmdebstrap will differ, thus we equalize them first -for d in etc/apt/preferences.d/ etc/apt/sources.list.d/ etc/dpkg/dpkg.cfg.d/ var/log/apt/; do - touch --date="@$SOURCE_DATE_EPOCH" /tmp/debian-debootstrap/\$d /tmp/debian-mm/\$d -done -# debootstrap never ran apt -- fixing permissions -for d in ./var/lib/apt/lists/partial ./var/cache/apt/archives/partial; do - chroot /tmp/debian-debootstrap chmod 0700 \$d - chroot /tmp/debian-debootstrap chown _apt:root \$d +if [ -e shared/cover_db.img ]; then + # produce report inside the VM to make sure that the versions match or + # otherwise we might get: + # Can't read shared/cover_db/runs/1598213854.252.64287/cover.14 with Sereal: Sereal: Error: Bad Sereal header: Not a valid Sereal document. at offset 1 of input at srl_decoder.c line 600 at /usr/lib/x86_64-linux-gnu/perl5/5.30/Devel/Cover/DB/IO/Sereal.pm line 34, <$fh> chunk 1. + cat << END > shared/test.sh +cover -nogcov -report html_basic cover_db >&2 +mkdir -p report +for f in common.js coverage.html cover.css css.js mmdebstrap--branch.html mmdebstrap--condition.html mmdebstrap.html mmdebstrap--subroutine.html standardista-table-sorting.js; do + cp -a cover_db/\$f report done -tar -C /tmp/debian-debootstrap --numeric-owner --xattrs --xattrs-include='*' --sort=name --clamp-mtime --mtime=$(date --utc --date=@$SOURCE_DATE_EPOCH --iso-8601=seconds) -cf /tmp/root1.tar . -tar -C /tmp/debian-mm --numeric-owner --xattrs --xattrs-include='*' --sort=name --clamp-mtime --mtime=$(date --utc --date=@$SOURCE_DATE_EPOCH --iso-8601=seconds) -cf /tmp/root2.tar . -tar --full-time --verbose -tf /tmp/root1.tar > /tmp/root1.tar.list -tar --full-time --verbose -tf /tmp/root2.tar > /tmp/root2.tar.list -# despite SOURCE_DATE_EPOCH and --clamp-mtime, the timestamps in the tarball -# will slightly differ from each other in the sub-second precision (last -# decimals) so the tarballs will not be identical, so we use diff to compare -# content and tar to compare attributes -diff -u /tmp/root1.tar.list /tmp/root2.tar.list -rm /tmp/root1.tar /tmp/root2.tar /tmp/root1.tar.list /tmp/root2.tar.list - -rm /tmp/debian-mm.tar -rm -r /tmp/debian-debootstrap /tmp/debian-mm -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - echo "HAVE_QEMU != yes -- Skipping test..." >&2 - skipped=$((skipped+1)) -fi - - -print_header "test --help" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -# we redirect to /dev/null instead of using --quiet to not cause a broken pipe -# when grep exits before mmdebstrap was able to write all its output -$CMD --help | grep --fixed-strings 'mmdebstrap [OPTION...] [SUITE [TARGET [MIRROR...]]]' >/dev/null -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - ./run_null.sh SUDO - runtests=$((runtests+1)) -fi - -print_header "test --man" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 - -# we redirect to /dev/null instead of using --quiet to not cause a broken pipe -# when grep exits before mmdebstrap was able to write all its output -$CMD --man | grep --fixed-strings 'mmdebstrap [OPTION...] [*SUITE* [*TARGET* [*MIRROR*...]]]' >/dev/null -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - ./run_null.sh SUDO - runtests=$((runtests+1)) -fi - -print_header "test --version" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -# we redirect to /dev/null instead of using --quiet to not cause a broken pipe -# when grep exits before mmdebstrap was able to write all its output -$CMD --version | egrep '^mmdebstrap [0-9](\.[0-9])+$' >/dev/null -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - ./run_null.sh SUDO - runtests=$((runtests+1)) -fi - -print_header "mode=root,variant=apt: create directory" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -$CMD --mode=root --variant=apt $DEFAULT_DIST /tmp/debian-chroot $mirror -chroot /tmp/debian-chroot dpkg-query --showformat '\${binary:Package}\n' --show > pkglist.txt -tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort > tar1.txt -rm -r /tmp/debian-chroot -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - ./run_null.sh SUDO - runtests=$((runtests+1)) -fi - -print_header "mode=unshare,variant=apt: unshare as root user" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -[ "\$(whoami)" = "root" ] -$CMD --mode=unshare --variant=apt \ - --customize-hook='chroot "\$1" sh -c "test -e /proc/self/fd"' \ - $DEFAULT_DIST /tmp/debian-chroot.tar $mirror -tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - -rm /tmp/debian-chroot.tar -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - ./run_null.sh SUDO - runtests=$((runtests+1)) -fi - -# make sure that using codenames works https://bugs.debian.org/cgi-bin/1003191 -for dist in oldstable stable testing unstable; do - print_header "mode=$defaultmode,variant=apt: test $dist using codename" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -/usr/lib/apt/apt-helper download-file "$mirror/dists/$dist/Release" Release -codename=\$(awk '/^Codename: / { print \$2; }' Release) -rm Release -$CMD --mode=$defaultmode --variant=apt \$codename /tmp/debian-chroot.tar $mirror -if [ "$dist" = "$DEFAULT_DIST" ]; then - tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - -fi -rm /tmp/debian-chroot.tar +cover -delete cover_db >&2 END if [ "$HAVE_QEMU" = "yes" ]; then ./run_qemu.sh - runtests=$((runtests+1)) - elif [ "$defaultmode" = "root" ]; then - ./run_null.sh SUDO - runtests=$((runtests+1)) - else - ./run_null.sh - runtests=$((runtests+1)) - fi -done - -print_header "mode=unshare,variant=apt: fail without /etc/subuid" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -if [ ! -e /mmdebstrap-testenv ]; then - echo "this test modifies the system and should only be run inside a container" >&2 - exit 1 -fi -adduser --gecos user --disabled-password user -sysctl -w kernel.unprivileged_userns_clone=1 -rm /etc/subuid -ret=0 -runuser -u user -- $CMD --mode=unshare --variant=apt $DEFAULT_DIST /tmp/debian-chroot $mirror || ret=\$? -if [ "\$ret" = 0 ]; then - echo expected failure but got exit \$ret >&2 - exit 1 -fi -rm -r /tmp/debian-chroot -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - echo "HAVE_QEMU != yes -- Skipping test..." >&2 - skipped=$((skipped+1)) -fi - -print_header "mode=unshare,variant=apt: fail without username in /etc/subuid" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -if [ ! -e /mmdebstrap-testenv ]; then - echo "this test modifies the system and should only be run inside a container" >&2 - exit 1 -fi -adduser --gecos user --disabled-password user -sysctl -w kernel.unprivileged_userns_clone=1 -awk -F: '\$1!="user"' /etc/subuid > /etc/subuid.tmp -mv /etc/subuid.tmp /etc/subuid -ret=0 -runuser -u user -- $CMD --mode=unshare --variant=apt $DEFAULT_DIST /tmp/debian-chroot $mirror || ret=\$? -if [ "\$ret" = 0 ]; then - echo expected failure but got exit \$ret >&2 - exit 1 -fi -rm -r /tmp/debian-chroot -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - echo "HAVE_QEMU != yes -- Skipping test..." >&2 - skipped=$((skipped+1)) -fi - -# Before running unshare mode as root, we run "unshare --mount" but that fails -# if mmdebstrap itself is executed from within a chroot: -# unshare: cannot change root filesystem propagation: Invalid argument -# This test tests the workaround in mmdebstrap using --propagation unchanged -print_header "mode=root,variant=apt: unshare as root user inside chroot" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -[ "\$(whoami)" = "root" ] -cat << 'SCRIPT' > script.sh -#!/bin/sh -set -eu -rootfs="\$1" -mkdir -p "\$rootfs/mnt" -[ -e /usr/bin/mmdebstrap ] && cp -aT /usr/bin/mmdebstrap "\$rootfs/usr/bin/mmdebstrap" -[ -e ./mmdebstrap ] && cp -aT ./mmdebstrap "\$rootfs/mnt/mmdebstrap" -chroot "\$rootfs" env --chdir=/mnt \ - $CMD --mode=unshare --variant=apt \ - $DEFAULT_DIST /tmp/debian-chroot.tar $mirror -SCRIPT -chmod +x script.sh -$CMD --mode=root --variant=apt --include=perl,mount \ - --customize-hook=./script.sh \ - --customize-hook="download /tmp/debian-chroot.tar /tmp/debian-chroot.tar" \ - $DEFAULT_DIST /dev/null $mirror -tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - -rm /tmp/debian-chroot.tar script.sh -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - ./run_null.sh SUDO - runtests=$((runtests+1)) -fi - -# Same as above but this time we run mmdebstrap in root mode from inside a -# chroot. -print_header "mode=root,variant=apt: root mode inside chroot" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -[ "\$(whoami)" = "root" ] -cat << 'SCRIPT' > script.sh -#!/bin/sh -set -eu -rootfs="\$1" -mkdir -p "\$rootfs/mnt" -[ -e /usr/bin/mmdebstrap ] && cp -aT /usr/bin/mmdebstrap "\$rootfs/usr/bin/mmdebstrap" -[ -e ./mmdebstrap ] && cp -aT ./mmdebstrap "\$rootfs/mnt/mmdebstrap" -chroot "\$rootfs" env --chdir=/mnt \ - $CMD --mode=root --variant=apt \ - $DEFAULT_DIST /tmp/debian-chroot.tar $mirror -SCRIPT -chmod +x script.sh -$CMD --mode=root --variant=apt --include=perl,mount \ - --customize-hook=./script.sh \ - --customize-hook="download /tmp/debian-chroot.tar /tmp/debian-chroot.tar" \ - $DEFAULT_DIST /dev/null $mirror -tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - -rm /tmp/debian-chroot.tar script.sh -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - ./run_null.sh SUDO - runtests=$((runtests+1)) -fi - -# Same as above but this time we run mmdebstrap in root mode from inside -# an unshare chroot. -print_header "mode=root,variant=apt: root mode inside unshare chroot" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -if [ ! -e /mmdebstrap-testenv ]; then - echo "this test modifies the system and should only be run inside a container" >&2 - exit 1 -fi -[ "\$(whoami)" = "root" ] -adduser --gecos user --disabled-password user -sysctl -w kernel.unprivileged_userns_clone=1 -cat << 'SCRIPT' > script.sh -#!/bin/sh -set -eu -rootfs="\$1" -mkdir -p "\$rootfs/mnt" -[ -e /usr/bin/mmdebstrap ] && cp -aT /usr/bin/mmdebstrap "\$rootfs/usr/bin/mmdebstrap" -[ -e ./mmdebstrap ] && cp -aT ./mmdebstrap "\$rootfs/mnt/mmdebstrap" -chroot "\$rootfs" env --chdir=/mnt \ - $CMD --mode=root --variant=apt \ - $DEFAULT_DIST /tmp/debian-chroot.tar $mirror -SCRIPT -chmod +x script.sh -runuser -u user -- $CMD --mode=unshare --variant=apt --include=perl,mount \ - --customize-hook=./script.sh \ - --customize-hook="download /tmp/debian-chroot.tar /tmp/debian-chroot.tar" \ - $DEFAULT_DIST /dev/null $mirror -tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - -rm /tmp/debian-chroot.tar script.sh -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - echo "HAVE_QEMU != yes -- Skipping test..." >&2 - skipped=$((skipped+1)) -fi - -print_header "mode=root,variant=apt: root without cap_sys_admin" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -[ "\$(whoami)" = "root" ] -capsh --drop=cap_sys_admin -- -c 'exec "\$@"' exec \ - $CMD --mode=root --variant=apt \ - --customize-hook='chroot "\$1" sh -c "test ! -e /proc/self/fd"' \ - $DEFAULT_DIST /tmp/debian-chroot.tar $mirror -tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - -rm /tmp/debian-chroot.tar -END -if [ "$CONTAINER" = "lxc" ]; then - # see https://stackoverflow.com/questions/65748254/ - echo "cannot run under lxc -- Skipping test..." >&2 - skipped=$((skipped+1)) -elif [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - ./run_null.sh SUDO - runtests=$((runtests+1)) -fi - -print_header "mode=root,variant=apt: mount is missing" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -if [ ! -e /mmdebstrap-testenv ]; then - echo "this test modifies the system and should only be run inside a container" >&2 - exit 1 -fi -for p in /bin /usr/bin /sbin /usr/sbin; do - rm -f "\$p/mount" -done -$CMD --mode=root --variant=apt $DEFAULT_DIST /tmp/debian-chroot.tar $mirror -tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - -rm /tmp/debian-chroot.tar -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - echo "HAVE_QEMU != yes -- Skipping test..." >&2 - skipped=$((skipped+1)) -fi - -for variant in essential apt minbase buildd important standard; do - for format in tar squashfs ext2; do - print_header "mode=root/unshare/fakechroot,variant=$variant: check for bit-by-bit identical $format output" - if [ "$variant" = "standard" ]; then - case "$DEFAULT_DIST" in oldstable|stable) - echo "skipping test because of #864082, #1004557 and #1004558" >&2 - skipped=$((skipped+1)) - continue - ;; - esac - fi - if [ "$variant" = "important" ] && [ "$DEFAULT_DIST" = "oldstable" ]; then - echo "skipping test on oldstable because /var/lib/systemd/catalog/database differs" >&2 - skipped=$((skipped+1)) - continue - fi - if [ "$format" = "squashfs" ] && [ "$DEFAULT_DIST" = "oldstable" ]; then - echo "skipping test on oldstable because squashfs-tools-ng is not available" >&2 - skipped=$((skipped+1)) - continue - fi - if [ "$format" = "ext2" ] && [ "$DEFAULT_DIST" = "oldstable" ]; then - echo "skipping test on oldstable because genext2fs does not support SOURCE_DATE_EPOCH" >&2 - skipped=$((skipped+1)) - continue - fi - cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -if [ ! -e /mmdebstrap-testenv ]; then - echo "this test modifies the system and should only be run inside a container" >&2 - exit 1 -fi -adduser --gecos user --disabled-password user -sysctl -w kernel.unprivileged_userns_clone=1 -export SOURCE_DATE_EPOCH=$SOURCE_DATE_EPOCH -mount -o size=4G -t tmpfs tmpfs /tmp # workaround for #1010957 -$CMD --mode=root --variant=$variant $DEFAULT_DIST /tmp/debian-chroot-root.$format $mirror -if [ "$format" = tar ]; then - printf 'ustar ' | cmp --bytes=6 --ignore-initial=257:0 /tmp/debian-chroot-root.tar - -elif [ "$format" = squashfs ]; then - printf 'hsqs' | cmp --bytes=4 /tmp/debian-chroot-root.squashfs - -elif [ "$format" = ext2 ]; then - printf '\123\357' | cmp --bytes=2 --ignore-initial=1080:0 /tmp/debian-chroot-root.ext2 - -else - echo "unknown format: $format" >&2 -fi -runuser -u user -- $CMD --mode=unshare --variant=$variant $DEFAULT_DIST /tmp/debian-chroot-unshare.$format $mirror -cmp /tmp/debian-chroot-root.$format /tmp/debian-chroot-unshare.$format -rm /tmp/debian-chroot-unshare.$format -case $variant in essential|apt|minbase|buildd) - # variants important and standard differ because permissions drwxr-sr-x - # and extended attributes of ./var/log/journal/ cannot be preserved - # in fakechroot mode - runuser -u user -- $CMD --mode=fakechroot --variant=$variant $DEFAULT_DIST /tmp/debian-chroot-fakechroot.$format $mirror - cmp /tmp/debian-chroot-root.$format /tmp/debian-chroot-fakechroot.$format - rm /tmp/debian-chroot-fakechroot.$format - ;; -esac -rm /tmp/debian-chroot-root.$format -END - if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) - else - echo "HAVE_QEMU != yes -- Skipping test..." >&2 - skipped=$((skipped+1)) - fi - done -done - -print_header "mode=unshare,variant=apt: test taridshift utility" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -if [ ! -e /mmdebstrap-testenv ]; then - echo "this test modifies the system and should only be run inside a container" >&2 - exit 1 -fi -adduser --gecos user --disabled-password user -echo user:100000:65536 | cmp /etc/subuid - -echo user:100000:65536 | cmp /etc/subgid - -sysctl -w kernel.unprivileged_userns_clone=1 -# include iputils-ping so that we can verify that taridshift does not remove -# extended attributes -# run through tarshift no-op to create a tarball that should be bit-by-bit -# identical to a round trip through "taridshift X" and "taridshift -X" -runuser -u user -- $CMD --mode=unshare --variant=apt --include=iputils-ping $DEFAULT_DIST - $mirror \ - | ./taridshift 0 > /tmp/debian-chroot.tar -# make sure that xattrs are set in the original tarball -mkdir /tmp/debian-chroot -tar --xattrs --xattrs-include='*' --directory /tmp/debian-chroot -xf /tmp/debian-chroot.tar ./bin/ping -echo "/tmp/debian-chroot/bin/ping cap_net_raw=ep" > /tmp/expected -getcap /tmp/debian-chroot/bin/ping | diff -u /tmp/expected - -rm /tmp/debian-chroot/bin/ping -rmdir /tmp/debian-chroot/bin -rmdir /tmp/debian-chroot -# shift the uid/gid forward by 100000 and backward by 100000 -./taridshift 100000 < /tmp/debian-chroot.tar > /tmp/debian-chroot-shifted.tar -./taridshift -100000 < /tmp/debian-chroot-shifted.tar > /tmp/debian-chroot-shiftedback.tar -# the tarball before and after the roundtrip through taridshift should be bit -# by bit identical -cmp /tmp/debian-chroot.tar /tmp/debian-chroot-shiftedback.tar -# manually adjust uid/gid and compare "tar -t" output -tar --numeric-owner -tvf /tmp/debian-chroot.tar \ - | sed 's# 100/0 # 100100/100000 #' \ - | sed 's# 100/8 # 100100/100008 #' \ - | sed 's# 0/0 # 100000/100000 #' \ - | sed 's# 0/5 # 100000/100005 #' \ - | sed 's# 0/8 # 100000/100008 #' \ - | sed 's# 0/42 # 100000/100042 #' \ - | sed 's# 0/43 # 100000/100043 #' \ - | sed 's# 0/50 # 100000/100050 #' \ - | sed 's/ \\+/ /g' \ - > /tmp/debian-chroot.txt -tar --numeric-owner -tvf /tmp/debian-chroot-shifted.tar \ - | sed 's/ \\+/ /g' \ - | diff -u /tmp/debian-chroot.txt - -mkdir /tmp/debian-chroot -tar --xattrs --xattrs-include='*' --directory /tmp/debian-chroot -xf /tmp/debian-chroot-shifted.tar -echo "100000 100000" > /tmp/expected -stat --format="%u %g" /tmp/debian-chroot/bin/ping | diff -u /tmp/expected - -echo "/tmp/debian-chroot/bin/ping cap_net_raw=ep" > /tmp/expected -getcap /tmp/debian-chroot/bin/ping | diff -u /tmp/expected - -echo "0 0" > /tmp/expected -runuser -u user -- $CMD --unshare-helper /usr/sbin/chroot /tmp/debian-chroot stat --format="%u %g" /bin/ping \ - | diff -u /tmp/expected - -echo "/bin/ping cap_net_raw=ep" > /tmp/expected -runuser -u user -- $CMD --unshare-helper /usr/sbin/chroot /tmp/debian-chroot getcap /bin/ping \ - | diff -u /tmp/expected - -rm /tmp/debian-chroot.tar /tmp/debian-chroot-shifted.tar /tmp/debian-chroot.txt /tmp/debian-chroot-shiftedback.tar /tmp/expected -rm -r /tmp/debian-chroot -END -if [ "$DEFAULT_DIST" = "oldstable" ]; then - echo "the python3 tarfile module in oldstable does not preserve xattrs -- Skipping test..." >&2 - skipped=$((skipped+1)) -elif [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - echo "HAVE_QEMU != yes -- Skipping test..." >&2 - skipped=$((skipped+1)) -fi - -print_header "mode=$defaultmode,variant=apt: test progress bars on fake tty" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -script -qfc "$CMD --mode=$defaultmode --variant=apt $DEFAULT_DIST /tmp/debian-chroot.tar $mirror" /dev/null -tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - -rm /tmp/debian-chroot.tar -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -elif [ "$defaultmode" = "root" ]; then - ./run_null.sh SUDO - runtests=$((runtests+1)) -else - ./run_null.sh - runtests=$((runtests+1)) -fi - -print_header "mode=$defaultmode,variant=apt: test --debug output on fake tty" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -script -qfc "$CMD --mode=$defaultmode --debug --variant=apt $DEFAULT_DIST /tmp/debian-chroot.tar $mirror" /dev/null -tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - -rm /tmp/debian-chroot.tar -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -elif [ "$defaultmode" = "root" ]; then - ./run_null.sh SUDO - runtests=$((runtests+1)) -else - ./run_null.sh - runtests=$((runtests+1)) -fi - -print_header "mode=root,variant=apt: existing empty directory" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -mkdir /tmp/debian-chroot -$CMD --mode=root --variant=apt $DEFAULT_DIST /tmp/debian-chroot $mirror -tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - -rm -r /tmp/debian-chroot -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - ./run_null.sh SUDO - runtests=$((runtests+1)) -fi - -print_header "mode=root,variant=apt: existing directory with lost+found" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -mkdir /tmp/debian-chroot -mkdir /tmp/debian-chroot/lost+found -$CMD --mode=root --variant=apt $DEFAULT_DIST /tmp/debian-chroot $mirror -rmdir /tmp/debian-chroot/lost+found -tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - -rm -r /tmp/debian-chroot -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - ./run_null.sh SUDO - runtests=$((runtests+1)) -fi - -print_header "mode=$defaultmode,variant=apt: fail installing to non-empty lost+found" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -mkdir /tmp/debian-chroot -mkdir /tmp/debian-chroot/lost+found -touch /tmp/debian-chroot/lost+found/exists -ret=0 -$CMD --mode=$defaultmode --variant=apt $DEFAULT_DIST /tmp/debian-chroot $mirror || ret=\$? -rm /tmp/debian-chroot/lost+found/exists -rmdir /tmp/debian-chroot/lost+found -rmdir /tmp/debian-chroot -if [ "\$ret" = 0 ]; then - echo expected failure but got exit \$ret >&2 - exit 1 -fi -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -elif [ "$defaultmode" = "root" ]; then - ./run_null.sh SUDO - runtests=$((runtests+1)) -else - ./run_null.sh - runtests=$((runtests+1)) -fi - -print_header "mode=$defaultmode,variant=apt: fail installing to non-empty target directory" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -mkdir /tmp/debian-chroot -mkdir /tmp/debian-chroot/lost+found -touch /tmp/debian-chroot/exists -ret=0 -$CMD --mode=$defaultmode --variant=apt $DEFAULT_DIST /tmp/debian-chroot $mirror || ret=\$? -rmdir /tmp/debian-chroot/lost+found -rm /tmp/debian-chroot/exists -rmdir /tmp/debian-chroot -if [ "\$ret" = 0 ]; then - echo expected failure but got exit \$ret >&2 - exit 1 -fi -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -elif [ "$defaultmode" = "root" ]; then - ./run_null.sh SUDO - runtests=$((runtests+1)) -else - ./run_null.sh - runtests=$((runtests+1)) -fi - -print_header "mode=unshare,variant=apt: missing device nodes outside the chroot" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -if [ ! -e /mmdebstrap-testenv ]; then - echo "this test modifies the system and should only be run inside a container" >&2 - exit 1 -fi -rm /dev/console -adduser --gecos user --disabled-password user -sysctl -w kernel.unprivileged_userns_clone=1 -runuser -u user -- $CMD --mode=unshare --variant=apt $DEFAULT_DIST /tmp/debian-chroot.tar $mirror -tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - -rm /tmp/debian-chroot.tar -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - echo "HAVE_QEMU != yes -- Skipping test..." >&2 - skipped=$((skipped+1)) -fi - -print_header "mode=unshare,variant=custom: missing /dev, /sys, /proc inside the chroot" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -if [ ! -e /mmdebstrap-testenv ]; then - echo "this test modifies the system and should only be run inside a container" >&2 - exit 1 -fi -adduser --gecos user --disabled-password user -sysctl -w kernel.unprivileged_userns_clone=1 -runuser -u user -- $CMD --mode=unshare --variant=custom --include=dpkg,dash,diffutils,coreutils,libc-bin,sed $DEFAULT_DIST /dev/null $mirror -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - echo "HAVE_QEMU != yes -- Skipping test..." >&2 - skipped=$((skipped+1)) -fi - -print_header "mode=root,variant=apt: chroot directory not accessible by _apt user" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -mkdir /tmp/debian-chroot -chmod 700 /tmp/debian-chroot -$CMD --mode=root --variant=apt $DEFAULT_DIST /tmp/debian-chroot $mirror -tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - -rm -r /tmp/debian-chroot -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - ./run_null.sh SUDO - runtests=$((runtests+1)) -fi - -print_header "mode=unshare,variant=apt: CWD directory not accessible by unshared user" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -if [ ! -e /mmdebstrap-testenv ]; then - echo "this test modifies the system and should only be run inside a container" >&2 - exit 1 -fi -adduser --gecos user --disabled-password user -sysctl -w kernel.unprivileged_userns_clone=1 -mkdir /tmp/debian-chroot -chmod 700 /tmp/debian-chroot -chown user:user /tmp/debian-chroot -if [ "$CMD" = "./mmdebstrap" ]; then - CMD=\$(realpath --canonicalize-existing ./mmdebstrap) -elif [ "$CMD" = "perl -MDevel::Cover=-silent,-nogcov ./mmdebstrap" ]; then - CMD="perl -MDevel::Cover=-silent,-nogcov \$(realpath --canonicalize-existing ./mmdebstrap)" -else - CMD="$CMD" -fi -env --chdir=/tmp/debian-chroot runuser -u user -- \$CMD --mode=unshare --variant=apt $DEFAULT_DIST /tmp/debian-chroot.tar $mirror -tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - -rm /tmp/debian-chroot.tar -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - echo "HAVE_QEMU != yes -- Skipping test..." >&2 - skipped=$((skipped+1)) -fi - -print_header "mode=unshare,variant=apt: create gzip compressed tarball" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -if [ ! -e /mmdebstrap-testenv ]; then - echo "this test modifies the system and should only be run inside a container" >&2 - exit 1 -fi -adduser --gecos user --disabled-password user -sysctl -w kernel.unprivileged_userns_clone=1 -runuser -u user -- $CMD --mode=unshare --variant=apt $DEFAULT_DIST /tmp/debian-chroot.tar.gz $mirror -printf '\037\213\010' | cmp --bytes=3 /tmp/debian-chroot.tar.gz - -tar -tf /tmp/debian-chroot.tar.gz | sort | diff -u tar1.txt - -rm /tmp/debian-chroot.tar.gz -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - echo "HAVE_QEMU != yes -- Skipping test..." >&2 - skipped=$((skipped+1)) -fi - -print_header "mode=unshare,variant=apt: custom TMPDIR" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -if [ ! -e /mmdebstrap-testenv ]; then - echo "this test modifies the system and should only be run inside a container" >&2 - exit 1 -fi -adduser --gecos user --disabled-password user -sysctl -w kernel.unprivileged_userns_clone=1 -homedir=\$(runuser -u user -- sh -c 'cd && pwd') -runuser -u user -- mkdir "\$homedir/tmp" -runuser -u user -- env TMPDIR="\$homedir/tmp" $CMD --mode=unshare --variant=apt \ - --setup-hook='case "\$1" in "'"\$homedir/tmp/mmdebstrap."'"??????????) exit 0;; *) exit 1;; esac' \ - $DEFAULT_DIST /tmp/debian-chroot.tar $mirror -tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - -# use rmdir as a quick check that nothing is remaining in TMPDIR -runuser -u user -- rmdir "\$homedir/tmp" -rm /tmp/debian-chroot.tar -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - echo "HAVE_QEMU != yes -- Skipping test..." >&2 - skipped=$((skipped+1)) -fi - -print_header "mode=$defaultmode,variant=apt: test xz compressed tarball" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -$CMD --mode=$defaultmode --variant=apt $DEFAULT_DIST /tmp/debian-chroot.tar.xz $mirror -printf '\3757zXZ\0' | cmp --bytes=6 /tmp/debian-chroot.tar.xz - -tar -tf /tmp/debian-chroot.tar.xz | sort | diff -u tar1.txt - -rm /tmp/debian-chroot.tar.xz -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -elif [ "$defaultmode" = "root" ]; then - ./run_null.sh SUDO - runtests=$((runtests+1)) -else - ./run_null.sh - runtests=$((runtests+1)) -fi - -print_header "mode=$defaultmode,variant=apt: directory ending in .tar" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -$CMD --mode=$defaultmode --variant=apt --format=directory $DEFAULT_DIST /tmp/debian-chroot.tar $mirror -ftype=\$(stat -c %F /tmp/debian-chroot.tar) -if [ "\$ftype" != directory ]; then - echo "expected directory but got: \$ftype" >&2 - exit 1 -fi -tar -C /tmp/debian-chroot.tar --one-file-system -c . | tar -t | sort | diff -u tar1.txt - -rm -r /tmp/debian-chroot.tar -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -elif [ "$defaultmode" = "root" ]; then - ./run_null.sh SUDO - runtests=$((runtests+1)) -else - ./run_null.sh - runtests=$((runtests+1)) -fi - -print_header "mode=auto,variant=apt: test auto-mode without unshare capabilities" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -if [ ! -e /mmdebstrap-testenv ]; then - echo "this test modifies the system and should only be run inside a container" >&2 - exit 1 -fi -adduser --gecos user --disabled-password user -sysctl -w kernel.unprivileged_userns_clone=0 -runuser -u user -- $CMD --mode=auto --variant=apt $DEFAULT_DIST /tmp/debian-chroot.tar.gz $mirror -tar -tf /tmp/debian-chroot.tar.gz | sort | diff -u tar1.txt - -rm /tmp/debian-chroot.tar.gz -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - echo "HAVE_QEMU != yes -- Skipping test..." >&2 - skipped=$((skipped+1)) -fi - -print_header "mode=$defaultmode,variant=apt: fail with missing lz4" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -ret=0 -$CMD --mode=$defaultmode --variant=apt $DEFAULT_DIST /tmp/debian-chroot.tar.lz4 $mirror || ret=\$? -if [ "\$ret" = 0 ]; then - echo expected failure but got exit \$ret >&2 - exit 1 -fi -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -elif [ "$defaultmode" = "root" ]; then - ./run_null.sh SUDO - runtests=$((runtests+1)) -else - ./run_null.sh - runtests=$((runtests+1)) -fi - -print_header "mode=$defaultmode,variant=apt: fail with path with quotes" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -ret=0 -$CMD --mode=$defaultmode --variant=apt $DEFAULT_DIST /tmp/quoted\"path $mirror || ret=\$? -if [ "\$ret" = 0 ]; then - echo expected failure but got exit \$ret >&2 - exit 1 -fi -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -elif [ "$defaultmode" = "root" ]; then - ./run_null.sh SUDO - runtests=$((runtests+1)) -else - ./run_null.sh - runtests=$((runtests+1)) -fi - -print_header "mode=root,variant=apt: create tarball with /tmp mounted nodev" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -if [ ! -e /mmdebstrap-testenv ]; then - echo "this test modifies the system and should only be run inside a container" >&2 - exit 1 -fi -mount -t tmpfs -o nodev,nosuid,size=300M tmpfs /tmp -# use --customize-hook to exercise the mounting/unmounting code of block devices in root mode -$CMD --mode=root --variant=apt --customize-hook='mount | grep /dev/full' --customize-hook='test "\$(echo foo | tee /dev/full 2>&1 1>/dev/null)" = "tee: /dev/full: No space left on device"' $DEFAULT_DIST /tmp/debian-chroot.tar $mirror -tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - -rm /tmp/debian-chroot.tar -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - echo "HAVE_QEMU != yes -- Skipping test..." >&2 - skipped=$((skipped+1)) -fi - -print_header "mode=$defaultmode,variant=apt: read from stdin, write to stdout" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -echo "deb $mirror $DEFAULT_DIST main" | $CMD --mode=$defaultmode --variant=apt > /tmp/debian-chroot.tar -tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - -rm /tmp/debian-chroot.tar -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -elif [ "$defaultmode" = "root" ]; then - ./run_null.sh SUDO - runtests=$((runtests+1)) -else - ./run_null.sh - runtests=$((runtests+1)) -fi - -print_header "mode=$defaultmode,variant=apt: supply components manually" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -$CMD --mode=$defaultmode --variant=apt --components="main main" --comp="main,main" $DEFAULT_DIST /tmp/debian-chroot $mirror -echo "deb $mirror $DEFAULT_DIST main" | cmp /tmp/debian-chroot/etc/apt/sources.list -tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - -rm -r /tmp/debian-chroot -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -elif [ "$defaultmode" = "root" ]; then - ./run_null.sh SUDO - runtests=$((runtests+1)) -else - ./run_null.sh - runtests=$((runtests+1)) -fi - -print_header "mode=root,variant=apt: stable default mirror" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -if [ ! -e /mmdebstrap-testenv ]; then - echo "this test modifies the system and should only be run inside a container" >&2 - exit 1 -fi -cat << HOSTS >> /etc/hosts -127.0.0.1 deb.debian.org -127.0.0.1 security.debian.org -HOSTS -apt-cache policy -cat /etc/apt/sources.list -$CMD --mode=root --variant=apt stable /tmp/debian-chroot -cat << SOURCES | cmp /tmp/debian-chroot/etc/apt/sources.list -deb http://deb.debian.org/debian stable main -deb http://deb.debian.org/debian stable-updates main -deb http://security.debian.org/debian-security stable-security main -SOURCES -rm -r /tmp/debian-chroot -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - echo "HAVE_QEMU != yes -- Skipping test..." >&2 - skipped=$((skipped+1)) -fi - -print_header "mode=$defaultmode,variant=apt: pass distribution but implicitly write to stdout" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -if [ ! -e /mmdebstrap-testenv ]; then - echo "this test modifies the system and should only be run inside a container" >&2 - exit 1 -fi -cat << HOSTS >> /etc/hosts -127.0.0.1 deb.debian.org -127.0.0.1 security.debian.org -HOSTS -$CMD --mode=$defaultmode --variant=apt $DEFAULT_DIST > /tmp/debian-chroot.tar -tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - -rm /tmp/debian-chroot.tar -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - echo "HAVE_QEMU != yes -- Skipping test..." >&2 - skipped=$((skipped+1)) -fi - -print_header "mode=$defaultmode,variant=apt: test aspcud apt solver" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -$CMD --mode=$defaultmode --variant=custom \ - --include \$(cat pkglist.txt | tr '\n' ',') \ - --aptopt='APT::Solver "aspcud"' \ - $DEFAULT_DIST /tmp/debian-chroot.tar $mirror -tar -tf /tmp/debian-chroot.tar | sort \ - | grep -v '^./etc/apt/apt.conf.d/99mmdebstrap$' \ - | diff -u tar1.txt - -rm /tmp/debian-chroot.tar -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -elif [ "$defaultmode" = "root" ]; then - ./run_null.sh SUDO - runtests=$((runtests+1)) -else - ./run_null.sh - runtests=$((runtests+1)) -fi - -print_header "mode=$defaultmode,variant=apt: mirror is -" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -echo "deb $mirror $DEFAULT_DIST main" | $CMD --mode=$defaultmode --variant=apt $DEFAULT_DIST /tmp/debian-chroot.tar - -tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - -rm /tmp/debian-chroot.tar -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -elif [ "$defaultmode" = "root" ]; then - ./run_null.sh SUDO - runtests=$((runtests+1)) -else - ./run_null.sh - runtests=$((runtests+1)) -fi - -print_header "mode=$defaultmode,variant=apt: copy:// mirror" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -if [ ! -e /mmdebstrap-testenv ]; then - echo "this test requires the cache directory to be mounted on /mnt and should only be run inside a container" >&2 - exit 1 -fi -$CMD --mode=$defaultmode --variant=apt $DEFAULT_DIST /tmp/debian-chroot.tar "deb copy:///mnt/cache/debian $DEFAULT_DIST main" -tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - -rm /tmp/debian-chroot.tar -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - echo "HAVE_QEMU != yes -- Skipping test..." >&2 - skipped=$((skipped+1)) -fi - -print_header "mode=$defaultmode,variant=apt: file:// mirror" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -if [ ! -e /mmdebstrap-testenv ]; then - echo "this test requires the cache directory to be mounted on /mnt and should only be run inside a container" >&2 - exit 1 -fi -$CMD --mode=$defaultmode --variant=apt --setup-hook='mkdir -p "\$1"/mnt/cache/debian; mount -o ro,bind /mnt/cache/debian "\$1"/mnt/cache/debian' --customize-hook='umount "\$1"/mnt/cache/debian; rmdir "\$1"/mnt/cache/debian "\$1"/mnt/cache' $DEFAULT_DIST /tmp/debian-chroot.tar "deb file:///mnt/cache/debian $DEFAULT_DIST main" -tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - -rm /tmp/debian-chroot.tar -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - echo "HAVE_QEMU != yes -- Skipping test..." >&2 - skipped=$((skipped+1)) -fi - -print_header "mode=$defaultmode,variant=apt: test file-mirror-automount hook" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -if [ ! -e /mmdebstrap-testenv ]; then - echo "this test requires the cache directory to be mounted on /mnt and should only be run inside a container" >&2 - exit 1 -fi -$CMD --mode=$defaultmode --variant=apt --hook-dir=./hooks/file-mirror-automount --customize-hook='rmdir "\$1"/mnt/cache/debian/ "\$1"/mnt/cache' $DEFAULT_DIST /tmp/debian-chroot.tar "deb file:///mnt/cache/debian $DEFAULT_DIST main" -tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - -rm /tmp/debian-chroot.tar -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - echo "HAVE_QEMU != yes -- Skipping test..." >&2 - skipped=$((skipped+1)) -fi - -print_header "mode=$defaultmode,variant=apt: mirror is deb..." -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -$CMD --mode=$defaultmode --variant=apt $DEFAULT_DIST /tmp/debian-chroot.tar "deb $mirror $DEFAULT_DIST main" -tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - -rm /tmp/debian-chroot.tar -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -elif [ "$defaultmode" = "root" ]; then - ./run_null.sh SUDO - runtests=$((runtests+1)) -else - ./run_null.sh - runtests=$((runtests+1)) -fi - -print_header "mode=$defaultmode,variant=apt: mirror is real file" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -echo "deb $mirror $DEFAULT_DIST main" > /tmp/sources.list -$CMD --mode=$defaultmode --variant=apt $DEFAULT_DIST /tmp/debian-chroot.tar /tmp/sources.list -tar -tf /tmp/debian-chroot.tar \ - | sed 's#^./etc/apt/sources.list.d/0000sources.list\$#./etc/apt/sources.list#' \ - | sort | diff -u tar1.txt - -rm /tmp/debian-chroot.tar /tmp/sources.list -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -elif [ "$defaultmode" = "root" ]; then - ./run_null.sh SUDO - runtests=$((runtests+1)) -else - ./run_null.sh - runtests=$((runtests+1)) -fi - -print_header "mode=$defaultmode,variant=apt: test deb822 (1/2)" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -cat << SOURCES > /tmp/deb822.sources -Types: deb -URIs: ${mirror}1 -Suites: $DEFAULT_DIST -Components: main -SOURCES -echo "deb ${mirror}2 $DEFAULT_DIST main" > /tmp/sources.list -echo "deb ${mirror}3 $DEFAULT_DIST main" \ - | $CMD --mode=$defaultmode --variant=apt $DEFAULT_DIST \ - /tmp/debian-chroot \ - /tmp/deb822.sources \ - ${mirror}4 \ - - \ - "deb ${mirror}5 $DEFAULT_DIST main" \ - ${mirror}6 \ - /tmp/sources.list -test ! -e /tmp/debian-chroot/etc/apt/sources.list -cat << SOURCES | cmp /tmp/debian-chroot/etc/apt/sources.list.d/0000deb822.sources - -Types: deb -URIs: ${mirror}1 -Suites: $DEFAULT_DIST -Components: main -SOURCES -cat << SOURCES | cmp /tmp/debian-chroot/etc/apt/sources.list.d/0001main.list - -deb ${mirror}4 $DEFAULT_DIST main - -deb ${mirror}3 $DEFAULT_DIST main - -deb ${mirror}5 $DEFAULT_DIST main - -deb ${mirror}6 $DEFAULT_DIST main -SOURCES -echo "deb ${mirror}2 $DEFAULT_DIST main" | cmp /tmp/debian-chroot/etc/apt/sources.list.d/0002sources.list - -tar -C /tmp/debian-chroot --one-file-system -c . \ - | { - tar -t \ - | grep -v "^./etc/apt/sources.list.d/0000deb822.sources$" \ - | grep -v "^./etc/apt/sources.list.d/0001main.list$" \ - | grep -v "^./etc/apt/sources.list.d/0002sources.list"; - printf "./etc/apt/sources.list\n"; - } | sort | diff -u tar1.txt - -rm -r /tmp/debian-chroot -rm /tmp/sources.list /tmp/deb822.sources -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -elif [ "$defaultmode" = "root" ]; then - ./run_null.sh SUDO - runtests=$((runtests+1)) -else - ./run_null.sh - runtests=$((runtests+1)) -fi - -print_header "mode=$defaultmode,variant=apt: test deb822 (2/2)" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -cat << SOURCES > /tmp/deb822 -Types: deb -URIs: ${mirror}1 -Suites: $DEFAULT_DIST -Components: main -SOURCES -echo "deb ${mirror}2 $DEFAULT_DIST main" > /tmp/sources -cat << SOURCES | $CMD --mode=$defaultmode --variant=apt $DEFAULT_DIST \ - /tmp/debian-chroot \ - /tmp/deb822 \ - - \ - /tmp/sources -Types: deb -URIs: ${mirror}3 -Suites: $DEFAULT_DIST -Components: main -SOURCES -test ! -e /tmp/debian-chroot/etc/apt/sources.list -ls -lha /tmp/debian-chroot/etc/apt/sources.list.d/ -cat << SOURCES | cmp /tmp/debian-chroot/etc/apt/sources.list.d/0000deb822.sources - -Types: deb -URIs: ${mirror}1 -Suites: $DEFAULT_DIST -Components: main -SOURCES -cat << SOURCES | cmp /tmp/debian-chroot/etc/apt/sources.list.d/0001main.sources - -Types: deb -URIs: ${mirror}3 -Suites: $DEFAULT_DIST -Components: main -SOURCES -echo "deb ${mirror}2 $DEFAULT_DIST main" | cmp /tmp/debian-chroot/etc/apt/sources.list.d/0002sources.list - -tar -C /tmp/debian-chroot --one-file-system -c . \ - | { - tar -t \ - | grep -v "^./etc/apt/sources.list.d/0000deb822.sources$" \ - | grep -v "^./etc/apt/sources.list.d/0001main.sources$" \ - | grep -v "^./etc/apt/sources.list.d/0002sources.list$"; - printf "./etc/apt/sources.list\n"; - } | sort | diff -u tar1.txt - -rm -r /tmp/debian-chroot -rm /tmp/sources /tmp/deb822 -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -elif [ "$defaultmode" = "root" ]; then - ./run_null.sh SUDO - runtests=$((runtests+1)) -else - ./run_null.sh - runtests=$((runtests+1)) -fi - -print_header "mode=$defaultmode,variant=apt: automatic mirror from suite" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -if [ ! -e /mmdebstrap-testenv ]; then - echo "this test modifies the system and should only be run inside a container" >&2 - exit 1 -fi -cat << HOSTS >> /etc/hosts -127.0.0.1 deb.debian.org -127.0.0.1 security.debian.org -HOSTS -$CMD --mode=$defaultmode --variant=apt $DEFAULT_DIST /tmp/debian-chroot.tar -tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - -rm /tmp/debian-chroot.tar -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - echo "HAVE_QEMU != yes -- Skipping test..." >&2 - skipped=$((skipped+1)) -fi - -print_header "mode=$defaultmode,variant=apt: invalid mirror" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -ret=0 -$CMD --mode=$defaultmode --variant=apt $DEFAULT_DIST /tmp/debian-chroot.tar $mirror/invalid || ret=\$? -rm /tmp/debian-chroot.tar -if [ "\$ret" = 0 ]; then - echo expected failure but got exit \$ret >&2 - exit 1 -fi -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -elif [ "$defaultmode" = "root" ]; then - ./run_null.sh SUDO - runtests=$((runtests+1)) -else - ./run_null.sh - runtests=$((runtests+1)) -fi - -print_header "mode=root,variant=apt: fail installing to /" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -ret=0 -$CMD --mode=root --variant=apt $DEFAULT_DIST / $mirror || ret=\$? -if [ "\$ret" = 0 ]; then - echo expected failure but got exit \$ret >&2 - exit 1 -fi -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - ./run_null.sh SUDO - runtests=$((runtests+1)) -fi - -print_header "mode=root,variant=apt: fail installing to existing file" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -touch /tmp/exists -ret=0 -$CMD --mode=root --variant=apt $DEFAULT_DIST /tmp/exists $mirror || ret=\$? -if [ "\$ret" = 0 ]; then - echo expected failure but got exit \$ret >&2 - exit 1 -fi -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - ./run_null.sh SUDO - runtests=$((runtests+1)) -fi - -print_header "mode=$defaultmode,variant=apt: test arm64 without qemu support" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -if [ ! -e /mmdebstrap-testenv ]; then - echo "this test modifies the system and should only be run inside a container" >&2 - exit 1 -fi -apt-get remove --yes qemu-user-static binfmt-support qemu-user -ret=0 -$CMD --mode=$defaultmode --variant=apt --architectures=arm64 $DEFAULT_DIST /tmp/debian-chroot.tar $mirror || ret=\$? -if [ "\$ret" = 0 ]; then - echo expected failure but got exit \$ret >&2 - exit 1 -fi -END -if [ "$HOSTARCH" != amd64 ]; then - echo "HOSTARCH != amd64 -- Skipping test..." >&2 - skipped=$((skipped+1)) -elif [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - echo "HAVE_QEMU != yes -- Skipping test..." >&2 - skipped=$((skipped+1)) -fi - -print_header "mode=$defaultmode,variant=apt: test i386 (which can be executed without qemu)" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -if [ ! -e /mmdebstrap-testenv ]; then - echo "this test modifies the system and should only be run inside a container" >&2 - exit 1 -fi -# remove qemu just to be sure -apt-get remove --yes qemu-user-static binfmt-support qemu-user -$CMD --mode=$defaultmode --variant=apt --architectures=i386 $DEFAULT_DIST /tmp/debian-chroot.tar $mirror -# we ignore differences between architectures by ignoring some files -# and renaming others -{ tar -tf /tmp/debian-chroot.tar \ - | grep -v '^\./usr/bin/i386$' \ - | grep -v '^\./lib/ld-linux\.so\.2$' \ - | grep -v '^\./lib/i386-linux-gnu/ld-linux\.so\.2$' \ - | grep -v '^\./usr/lib/gcc/i686-linux-gnu/$' \ - | grep -v '^\./usr/lib/gcc/i686-linux-gnu/[0-9]\+/$' \ - | grep -v '^\./usr/share/man/man8/i386\.8\.gz$' \ - | grep -v '^\./usr/share/doc/[^/]\+/changelog\(\.Debian\)\?\.i386\.gz$' \ - | sed 's/i386-linux-gnu/x86_64-linux-gnu/' \ - | sed 's/i386/amd64/'; -} | sort > tar2.txt -{ cat tar1.txt \ - | grep -v '^\./usr/bin/i386$' \ - | grep -v '^\./usr/bin/x86_64$' \ - | grep -v '^\./lib64/$' \ - | grep -v '^\./lib64/ld-linux-x86-64\.so\.2$' \ - | grep -v '^\./usr/lib/gcc/x86_64-linux-gnu/$' \ - | grep -v '^\./usr/lib/gcc/x86_64-linux-gnu/[0-9]\+/$' \ - | grep -v '^\./lib/x86_64-linux-gnu/ld-linux-x86-64\.so\.2$' \ - | grep -v '^\./lib/x86_64-linux-gnu/libmvec-2\.[0-9]\+\.so$' \ - | grep -v '^\./lib/x86_64-linux-gnu/libmvec\.so\.1$' \ - | grep -v '^\./usr/share/doc/[^/]\+/changelog\(\.Debian\)\?\.amd64\.gz$' \ - | grep -v '^\./usr/share/man/man8/i386\.8\.gz$' \ - | grep -v '^\./usr/share/man/man8/x86_64\.8\.gz$'; -} | sort | diff -u - tar2.txt -rm /tmp/debian-chroot.tar -END -# this test compares the contents of different architectures, so this might -# fail if the versions do not match -if [ "$RUN_MA_SAME_TESTS" = "yes" ]; then - if [ "$HOSTARCH" != amd64 ]; then - echo "HOSTARCH != amd64 -- Skipping test..." >&2 - skipped=$((skipped+1)) - elif [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) - else - echo "HAVE_QEMU != yes -- Skipping test..." >&2 - skipped=$((skipped+1)) - fi -else - echo "RUN_MA_SAME_TESTS != yes -- Skipping test..." >&2 - skipped=$((skipped+1)) -fi - -# to test foreign architecture package installation we choose a package which -# - is not part of the native installation set -# - does not have any dependencies -# - installs only few files -# - doesn't change its name regularly (like gcc-*-base) -print_header "mode=root,variant=apt: test --include=libmagic-mgc:arm64" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -$CMD --mode=root --variant=apt --architectures=amd64,arm64 --include=libmagic-mgc:arm64 $DEFAULT_DIST /tmp/debian-chroot $mirror -{ echo "amd64"; echo "arm64"; } | cmp /tmp/debian-chroot/var/lib/dpkg/arch - -rm /tmp/debian-chroot/var/lib/dpkg/arch -rm /tmp/debian-chroot/var/lib/apt/extended_states -rm /tmp/debian-chroot/var/lib/dpkg/info/libmagic-mgc.list -rm /tmp/debian-chroot/var/lib/dpkg/info/libmagic-mgc.md5sums -rm /tmp/debian-chroot/usr/lib/file/magic.mgc -rm /tmp/debian-chroot/usr/share/doc/libmagic-mgc/README.Debian -rm /tmp/debian-chroot/usr/share/doc/libmagic-mgc/changelog.Debian.gz -rm /tmp/debian-chroot/usr/share/doc/libmagic-mgc/changelog.gz -rm /tmp/debian-chroot/usr/share/doc/libmagic-mgc/copyright -rm /tmp/debian-chroot/usr/share/file/magic.mgc -rm /tmp/debian-chroot/usr/share/misc/magic.mgc -rmdir /tmp/debian-chroot/usr/share/doc/libmagic-mgc/ -rmdir /tmp/debian-chroot/usr/share/file/magic/ -rmdir /tmp/debian-chroot/usr/share/file/ -rmdir /tmp/debian-chroot/usr/lib/file/ -tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - -rm -r /tmp/debian-chroot -END -if [ "$RUN_MA_SAME_TESTS" = "yes" ]; then - if [ "$HOSTARCH" != amd64 ]; then - echo "HOSTARCH != amd64 -- Skipping test..." >&2 - skipped=$((skipped+1)) - elif [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) - else - ./run_null.sh SUDO - runtests=$((runtests+1)) - fi -else - echo "RUN_MA_SAME_TESTS != yes -- Skipping test..." >&2 - skipped=$((skipped+1)) -fi - -print_header "mode=root,variant=apt: test --include=libmagic-mgc:arm64 with multiple --arch options" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -$CMD --mode=root --variant=apt --architectures=amd64 --architectures=arm64 --include=libmagic-mgc:arm64 $DEFAULT_DIST /tmp/debian-chroot $mirror -{ echo "amd64"; echo "arm64"; } | cmp /tmp/debian-chroot/var/lib/dpkg/arch - -rm /tmp/debian-chroot/var/lib/dpkg/arch -rm /tmp/debian-chroot/var/lib/apt/extended_states -rm /tmp/debian-chroot/var/lib/dpkg/info/libmagic-mgc.list -rm /tmp/debian-chroot/var/lib/dpkg/info/libmagic-mgc.md5sums -rm /tmp/debian-chroot/usr/lib/file/magic.mgc -rm /tmp/debian-chroot/usr/share/doc/libmagic-mgc/README.Debian -rm /tmp/debian-chroot/usr/share/doc/libmagic-mgc/changelog.Debian.gz -rm /tmp/debian-chroot/usr/share/doc/libmagic-mgc/changelog.gz -rm /tmp/debian-chroot/usr/share/doc/libmagic-mgc/copyright -rm /tmp/debian-chroot/usr/share/file/magic.mgc -rm /tmp/debian-chroot/usr/share/misc/magic.mgc -rmdir /tmp/debian-chroot/usr/share/doc/libmagic-mgc/ -rmdir /tmp/debian-chroot/usr/share/file/magic/ -rmdir /tmp/debian-chroot/usr/share/file/ -rmdir /tmp/debian-chroot/usr/lib/file/ -tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - -rm -r /tmp/debian-chroot -END -if [ "$RUN_MA_SAME_TESTS" = "yes" ]; then - if [ "$HOSTARCH" != amd64 ]; then - echo "HOSTARCH != amd64 -- Skipping test..." >&2 - skipped=$((skipped+1)) - elif [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) - else - ./run_null.sh SUDO - runtests=$((runtests+1)) - fi -else - echo "RUN_MA_SAME_TESTS != yes -- Skipping test..." >&2 - skipped=$((skipped+1)) -fi - -print_header "mode=root,variant=apt: test --aptopt" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -echo 'Acquire::Languages "none";' > /tmp/config -$CMD --mode=root --variant=apt --aptopt='Acquire::Check-Valid-Until "false"' --aptopt=/tmp/config $DEFAULT_DIST /tmp/debian-chroot $mirror -printf 'Acquire::Check-Valid-Until "false";\nAcquire::Languages "none";\n' | cmp /tmp/debian-chroot/etc/apt/apt.conf.d/99mmdebstrap - -rm /tmp/debian-chroot/etc/apt/apt.conf.d/99mmdebstrap -tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - -rm -r /tmp/debian-chroot /tmp/config -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - ./run_null.sh SUDO - runtests=$((runtests+1)) -fi - -print_header "mode=root,variant=apt: test --keyring" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -if [ ! -e /mmdebstrap-testenv ]; then - echo "this test modifies the system and should only be run inside a container" >&2 - exit 1 -fi -rm /etc/apt/trusted.gpg.d/*.gpg -$CMD --mode=root --variant=apt --keyring=/usr/share/keyrings/debian-archive-keyring.gpg --keyring=/usr/share/keyrings/ $DEFAULT_DIST /tmp/debian-chroot "deb $mirror $DEFAULT_DIST main" -# make sure that no [signedby=...] managed to make it into the sources.list -echo "deb $mirror $DEFAULT_DIST main" | cmp /tmp/debian-chroot/etc/apt/sources.list - -tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - -rm -r /tmp/debian-chroot -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - echo "HAVE_QEMU != yes -- Skipping test..." >&2 - skipped=$((skipped+1)) -fi - -print_header "mode=root,variant=apt: test --keyring overwrites" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -mkdir -p /tmp/emptydir -touch /tmp/emptyfile -# this overwrites the apt keyring options and should fail -ret=0 -$CMD --mode=root --variant=apt --keyring=/tmp/emptydir --keyring=/tmp/emptyfile $DEFAULT_DIST /tmp/debian-chroot "deb $mirror $DEFAULT_DIST main" || ret=\$? -# make sure that no [signedby=...] managed to make it into the sources.list -echo "deb $mirror $DEFAULT_DIST main" | cmp /tmp/debian-chroot/etc/apt/sources.list - -rm -r /tmp/debian-chroot -rmdir /tmp/emptydir -rm /tmp/emptyfile -if [ "\$ret" = 0 ]; then - echo expected failure but got exit \$ret >&2 - exit 1 -fi -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - ./run_null.sh SUDO - runtests=$((runtests+1)) -fi - -print_header "mode=root,variant=apt: test signed-by without host keys" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -if [ ! -e /mmdebstrap-testenv ]; then - echo "this test modifies the system and should only be run inside a container" >&2 - exit 1 -fi -rm /etc/apt/trusted.gpg.d/*.gpg -$CMD --mode=root --variant=apt $DEFAULT_DIST /tmp/debian-chroot $mirror -printf 'deb [signed-by="/usr/share/keyrings/debian-archive-keyring.gpg"] $mirror $DEFAULT_DIST main\n' | cmp /tmp/debian-chroot/etc/apt/sources.list - -tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - -rm -r /tmp/debian-chroot -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - echo "HAVE_QEMU != yes -- Skipping test..." >&2 - skipped=$((skipped+1)) -fi - -print_header "mode=root,variant=apt: test ascii armored keys" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -if [ ! -e /mmdebstrap-testenv ]; then - echo "this test modifies the system and should only be run inside a container" >&2 - exit 1 -fi -for f in /usr/share/keyrings/*.gpg; do - name=\$(basename "\$f" .gpg) - gpg --enarmor < /usr/share/keyrings/\$name.gpg \ - | sed 's/ PGP ARMORED FILE/ PGP PUBLIC KEY BLOCK/;/^Comment: /d' \ - > /etc/apt/trusted.gpg.d/\$name.asc -done -rm /etc/apt/trusted.gpg.d/*.gpg -rm /usr/share/keyrings/*.gpg -$CMD --mode=root --variant=apt $DEFAULT_DIST /tmp/debian-chroot.tar $mirror -tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - -rm -r /tmp/debian-chroot.tar -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - echo "HAVE_QEMU != yes -- Skipping test..." >&2 - skipped=$((skipped+1)) -fi - -print_header "mode=root,variant=apt: test signed-by with host keys" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -$CMD --mode=root --variant=apt $DEFAULT_DIST /tmp/debian-chroot $mirror -printf 'deb $mirror $DEFAULT_DIST main\n' | cmp /tmp/debian-chroot/etc/apt/sources.list - -tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - -rm -r /tmp/debian-chroot -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - ./run_null.sh SUDO - runtests=$((runtests+1)) -fi - -print_header "mode=root,variant=apt: test --dpkgopt" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -echo no-pager > /tmp/config -$CMD --mode=root --variant=apt --dpkgopt="path-exclude=/usr/share/doc/*" --dpkgopt=/tmp/config --dpkgopt="path-include=/usr/share/doc/dpkg/copyright" $DEFAULT_DIST /tmp/debian-chroot $mirror -printf 'path-exclude=/usr/share/doc/*\nno-pager\npath-include=/usr/share/doc/dpkg/copyright\n' | cmp /tmp/debian-chroot/etc/dpkg/dpkg.cfg.d/99mmdebstrap - -rm /tmp/debian-chroot/etc/dpkg/dpkg.cfg.d/99mmdebstrap -tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort > tar2.txt -{ grep -v '^./usr/share/doc/.' tar1.txt; echo ./usr/share/doc/dpkg/; echo ./usr/share/doc/dpkg/copyright; } | sort | diff -u - tar2.txt -rm -r /tmp/debian-chroot /tmp/config -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - ./run_null.sh SUDO - runtests=$((runtests+1)) -fi - -print_header "mode=root,variant=apt: test --include" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -$CMD --mode=root --variant=apt --include=doc-debian $DEFAULT_DIST /tmp/debian-chroot $mirror -rm /tmp/debian-chroot/usr/share/doc-base/debian-* -rm -r /tmp/debian-chroot/usr/share/doc/debian -rm -r /tmp/debian-chroot/usr/share/doc/doc-debian -rm /tmp/debian-chroot/var/lib/apt/extended_states -rm /tmp/debian-chroot/var/lib/dpkg/info/doc-debian.list -rm /tmp/debian-chroot/var/lib/dpkg/info/doc-debian.md5sums -tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - -rm -r /tmp/debian-chroot -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - ./run_null.sh SUDO - runtests=$((runtests+1)) -fi - -print_header "mode=root,variant=apt: test multiple --include" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -$CMD --mode=root --variant=apt --include=doc-debian --include=tzdata $DEFAULT_DIST /tmp/debian-chroot $mirror -rm /tmp/debian-chroot/usr/share/doc-base/debian-* -rm -r /tmp/debian-chroot/usr/share/doc/debian -rm -r /tmp/debian-chroot/usr/share/doc/doc-debian -rm /tmp/debian-chroot/etc/localtime -rm /tmp/debian-chroot/etc/timezone -rm /tmp/debian-chroot/usr/sbin/tzconfig -rm -r /tmp/debian-chroot/usr/share/doc/tzdata -rm -r /tmp/debian-chroot/usr/share/zoneinfo -rm /tmp/debian-chroot/var/lib/apt/extended_states -rm /tmp/debian-chroot/var/lib/dpkg/info/doc-debian.list -rm /tmp/debian-chroot/var/lib/dpkg/info/doc-debian.md5sums -rm /tmp/debian-chroot/var/lib/dpkg/info/tzdata.list -rm /tmp/debian-chroot/var/lib/dpkg/info/tzdata.md5sums -rm /tmp/debian-chroot/var/lib/dpkg/info/tzdata.config -rm /tmp/debian-chroot/var/lib/dpkg/info/tzdata.postinst -rm /tmp/debian-chroot/var/lib/dpkg/info/tzdata.postrm -rm /tmp/debian-chroot/var/lib/dpkg/info/tzdata.templates -tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - -rm -r /tmp/debian-chroot -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - ./run_null.sh SUDO - runtests=$((runtests+1)) -fi - -# This checks for https://bugs.debian.org/976166 -# Since $DEFAULT_DIST varies, we hardcode stable and unstable. -print_header "mode=root,variant=apt: test --include with multiple apt sources" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -$CMD --mode=root --variant=minbase --include=doc-debian unstable /tmp/debian-chroot "deb $mirror unstable main" "deb $mirror stable main" -chroot /tmp/debian-chroot dpkg-query --show doc-debian -rm -r /tmp/debian-chroot -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - ./run_null.sh SUDO - runtests=$((runtests+1)) -fi - -print_header "mode=root,variant=apt: test merged-usr via --setup-hook" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -$CMD --mode=root --variant=apt \ - --setup-hook=./hooks/merged-usr/setup00.sh \ - --customize-hook='[ -L "\$1"/bin -a -L "\$1"/sbin -a -L "\$1"/lib ]' \ - $DEFAULT_DIST /tmp/debian-chroot $mirror -tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort > tar2.txt -{ - sed -e 's/^\.\/bin\//.\/usr\/bin\//;s/^\.\/lib\//.\/usr\/lib\//;s/^\.\/sbin\//.\/usr\/sbin\//;' tar1.txt | { - case $HOSTARCH in - amd64) sed -e 's/^\.\/lib32\//.\/usr\/lib32\//;s/^\.\/lib64\//.\/usr\/lib64\//;s/^\.\/libx32\//.\/usr\/libx32\//;';; - ppc64el) sed -e 's/^\.\/lib64\//.\/usr\/lib64\//;';; - *) cat;; - esac - }; - echo ./bin; - echo ./lib; - echo ./sbin; - case $HOSTARCH in - amd64) - echo ./lib32; - echo ./lib64; - echo ./libx32; - echo ./usr/lib32/; - echo ./usr/libx32/; - ;; - i386) - echo ./lib64; - echo ./libx32; - echo ./usr/lib64/; - echo ./usr/libx32/; - ;; - ppc64el) - echo ./lib64; - ;; - s390x) - echo ./lib32; - echo ./usr/lib32/; - ;; - esac -} | sort -u | diff -u - tar2.txt -rm -r /tmp/debian-chroot -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - ./run_null.sh SUDO - runtests=$((runtests+1)) -fi - -print_header "mode=root,variant=apt: test --essential-hook" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -cat << 'SCRIPT' > /tmp/essential.sh -#!/bin/sh -echo tzdata tzdata/Zones/Europe select Berlin | chroot "\$1" debconf-set-selections -SCRIPT -chmod +x /tmp/essential.sh -$CMD --mode=root --variant=apt --include=tzdata --essential-hook='echo tzdata tzdata/Areas select Europe | chroot "\$1" debconf-set-selections' --essential-hook=/tmp/essential.sh $DEFAULT_DIST /tmp/debian-chroot $mirror -echo Europe/Berlin | cmp /tmp/debian-chroot/etc/timezone -tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort \ - | grep -v '^./etc/localtime' \ - | grep -v '^./etc/timezone' \ - | grep -v '^./usr/sbin/tzconfig' \ - | grep -v '^./usr/share/doc/tzdata' \ - | grep -v '^./usr/share/zoneinfo' \ - | grep -v '^./var/lib/dpkg/info/tzdata.' \ - | grep -v '^./var/lib/apt/extended_states$' \ - | diff -u tar1.txt - -rm /tmp/essential.sh -rm -r /tmp/debian-chroot -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - ./run_null.sh SUDO - runtests=$((runtests+1)) -fi - -print_header "mode=root,variant=apt: test --customize-hook" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -cat << 'SCRIPT' > /tmp/customize.sh -#!/bin/sh -chroot "\$1" whoami > "\$1/output2" -chroot "\$1" pwd >> "\$1/output2" -SCRIPT -chmod +x /tmp/customize.sh -$CMD --mode=root --variant=apt --customize-hook='chroot "\$1" sh -c "whoami; pwd" > "\$1/output1"' --customize-hook=/tmp/customize.sh $DEFAULT_DIST /tmp/debian-chroot $mirror -printf "root\n/\n" | cmp /tmp/debian-chroot/output1 -printf "root\n/\n" | cmp /tmp/debian-chroot/output2 -rm /tmp/debian-chroot/output1 -rm /tmp/debian-chroot/output2 -tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - -rm /tmp/customize.sh -rm -r /tmp/debian-chroot -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - ./run_null.sh SUDO - runtests=$((runtests+1)) -fi - -print_header "mode=root,variant=apt: test failing --customize-hook" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -ret=0 -$CMD --mode=root --variant=apt --customize-hook='chroot "\$1" sh -c "exit 1"' $DEFAULT_DIST /tmp/debian-chroot $mirror || ret=\$? -rm -r /tmp/debian-chroot -if [ "\$ret" = 0 ]; then - echo expected failure but got exit \$ret >&2 - exit 1 -fi -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - ./run_null.sh SUDO - runtests=$((runtests+1)) -fi - -print_header "mode=root,variant=apt: test sigint during --customize-hook" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -setsid --wait $CMD --mode=root --variant=apt --customize-hook='touch done && sleep 10 && touch fail' $DEFAULT_DIST /tmp/debian-chroot $mirror & -pid=\$! -while sleep 1; do [ -e done ] && break; done -rm done -pgid=\$(echo \$(ps -p \$pid -o pgid=)) -/bin/kill --signal INT -- -\$pgid -ret=0 -wait \$pid || ret=\$? -rm -r /tmp/debian-chroot -if [ -e fail ]; then - echo customize hook was not interrupted >&2 - rm fail - exit 1 -fi -if [ "\$ret" = 0 ]; then - echo expected failure but got exit \$ret >&2 - exit 1 -fi -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - ./run_null.sh SUDO - runtests=$((runtests+1)) -fi - -print_header "mode=root,variant=apt: test --hook-directory" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -for h in hookA hookB; do - mkdir /tmp/\$h - for s in setup extract essential customize; do - cat << SCRIPT > /tmp/\$h/\${s}00.sh -#!/bin/sh -echo \$h/\${s}00 >> "\\\$1/\$s" -SCRIPT - chmod +x /tmp/\$h/\${s}00.sh - cat << SCRIPT > /tmp/\$h/\${s}01.sh -echo \$h/\${s}01 >> "\\\$1/\$s" -SCRIPT - chmod +x /tmp/\$h/\${s}01.sh - done -done -$CMD --mode=root --variant=apt \ - --setup-hook='echo cliA/setup >> "\$1"/setup' \ - --extract-hook='echo cliA/extract >> "\$1"/extract' \ - --essential-hook='echo cliA/essential >> "\$1"/essential' \ - --customize-hook='echo cliA/customize >> "\$1"/customize' \ - --hook-dir=/tmp/hookA \ - --setup-hook='echo cliB/setup >> "\$1"/setup' \ - --extract-hook='echo cliB/extract >> "\$1"/extract' \ - --essential-hook='echo cliB/essential >> "\$1"/essential' \ - --customize-hook='echo cliB/customize >> "\$1"/customize' \ - --hook-dir=/tmp/hookB \ - --setup-hook='echo cliC/setup >> "\$1"/setup' \ - --extract-hook='echo cliC/extract >> "\$1"/extract' \ - --essential-hook='echo cliC/essential >> "\$1"/essential' \ - --customize-hook='echo cliC/customize >> "\$1"/customize' \ - $DEFAULT_DIST /tmp/debian-chroot $mirror -printf "cliA/setup\nhookA/setup00\nhookA/setup01\ncliB/setup\nhookB/setup00\nhookB/setup01\ncliC/setup\n" | diff -u - /tmp/debian-chroot/setup -printf "cliA/extract\nhookA/extract00\nhookA/extract01\ncliB/extract\nhookB/extract00\nhookB/extract01\ncliC/extract\n" | diff -u - /tmp/debian-chroot/extract -printf "cliA/essential\nhookA/essential00\nhookA/essential01\ncliB/essential\nhookB/essential00\nhookB/essential01\ncliC/essential\n" | diff -u - /tmp/debian-chroot/essential -printf "cliA/customize\nhookA/customize00\nhookA/customize01\ncliB/customize\nhookB/customize00\nhookB/customize01\ncliC/customize\n" | diff -u - /tmp/debian-chroot/customize -for s in setup extract essential customize; do - rm /tmp/debian-chroot/\$s -done -tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - -for h in hookA hookB; do - for s in setup extract essential customize; do - rm /tmp/\$h/\${s}00.sh - rm /tmp/\$h/\${s}01.sh - done - rmdir /tmp/\$h -done -rm -r /tmp/debian-chroot -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - ./run_null.sh SUDO - runtests=$((runtests+1)) -fi - -print_header "mode=root,variant=apt: test eatmydata via --hook-dir" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -cat << SCRIPT > /tmp/checkeatmydata.sh -#!/bin/sh -set -exu -cat << EOF | diff - "\\\$1"/usr/bin/dpkg -#!/bin/sh -exec /usr/bin/eatmydata /usr/bin/dpkg.distrib "\\\\\\\$@" -EOF -[ -e "\\\$1"/usr/bin/eatmydata ] -SCRIPT -chmod +x /tmp/checkeatmydata.sh -# first four bytes: magic -elfheader="\\177ELF" -# fifth byte: bits -case "\$(dpkg-architecture -qDEB_HOST_ARCH_BITS)" in - 32) elfheader="\$elfheader\\001";; - 64) elfheader="\$elfheader\\002";; - *) echo "bits not supported"; exit 1;; -esac -# sixth byte: endian -case "\$(dpkg-architecture -qDEB_HOST_ARCH_ENDIAN)" in - little) elfheader="\$elfheader\\001";; - big) elfheader="\$elfheader\\002";; - *) echo "endian not supported"; exit 1;; -esac -# seventh and eigth byte: elf version (1) and abi (unset) -elfheader="\$elfheader\\001\\000" -$CMD --mode=root --variant=apt \ - --customize-hook=/tmp/checkeatmydata.sh \ - --essential-hook=/tmp/checkeatmydata.sh \ - --extract-hook='printf "'"\$elfheader"'" | cmp --bytes=8 - "\$1"/usr/bin/dpkg' \ - --hook-dir=./hooks/eatmydata \ - --customize-hook='printf "'"\$elfheader"'" | cmp --bytes=8 - "\$1"/usr/bin/dpkg' \ - $DEFAULT_DIST /tmp/debian-chroot $mirror -tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - -rm /tmp/checkeatmydata.sh -rm -r /tmp/debian-chroot -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - ./run_null.sh SUDO - runtests=$((runtests+1)) -fi - -print_header "mode=root,variant=apt: test special hooks using helpers" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -mkfifo /tmp/myfifo -mkdir /tmp/root -ln -s /real /tmp/root/link -mkdir /tmp/root/real -run_testA() { - echo content > /tmp/foo - { { { $CMD --hook-helper /tmp/root root setup env 1 upload /tmp/foo \$1 < /tmp/myfifo 3>&-; echo \$? >&3; printf "\\000\\000adios"; - } | $CMD --hook-listener 1 3>&- >/tmp/myfifo; echo \$?; } 3>&1; - } | { read xs1; [ "\$xs1" -eq 0 ]; read xs2; [ "\$xs2" -eq 0 ]; } - echo content | diff -u - /tmp/root/real/foo - rm /tmp/foo - rm /tmp/root/real/foo -} -run_testA link/foo -run_testA /link/foo -run_testA ///link///foo/// -run_testA /././link/././foo/././ -run_testA /link/../link/foo -run_testA /link/../../link/foo -run_testA /../../link/foo -rmdir /tmp/root/real -rm /tmp/root/link -rmdir /tmp/root -rm /tmp/myfifo -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - ./run_null.sh SUDO - runtests=$((runtests+1)) -fi - -print_header "mode=root,variant=apt: test special hooks using helpers and env vars" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -cat << 'SCRIPT' > /tmp/script.sh -#!/bin/sh -set -eu -echo "MMDEBSTRAP_APT_CONFIG \$MMDEBSTRAP_APT_CONFIG" -echo "\$MMDEBSTRAP_HOOK" >> /tmp/hooks -[ "\$MMDEBSTRAP_MODE" = "root" ] -echo test-content \$MMDEBSTRAP_HOOK > test -$CMD --hook-helper "\$1" "\$MMDEBSTRAP_MODE" "\$MMDEBSTRAP_HOOK" env 1 upload test /test <&\$MMDEBSTRAP_HOOKSOCK >&\$MMDEBSTRAP_HOOKSOCK -rm test -echo "content inside chroot:" -cat "\$1/test" -[ "test-content \$MMDEBSTRAP_HOOK" = "\$(cat "\$1/test")" ] -$CMD --hook-helper "\$1" "\$MMDEBSTRAP_MODE" "\$MMDEBSTRAP_HOOK" env 1 download /test test <&\$MMDEBSTRAP_HOOKSOCK >&\$MMDEBSTRAP_HOOKSOCK -echo "content outside chroot:" -cat test -[ "test-content \$MMDEBSTRAP_HOOK" = "\$(cat test)" ] -rm test -SCRIPT -chmod +x /tmp/script.sh -$CMD --mode=root --variant=apt \ - --setup-hook=/tmp/script.sh \ - --extract-hook=/tmp/script.sh \ - --essential-hook=/tmp/script.sh \ - --customize-hook=/tmp/script.sh \ - $DEFAULT_DIST /tmp/debian-chroot $mirror -printf "setup\nextract\nessential\ncustomize\n" | diff -u - /tmp/hooks -rm /tmp/script.sh /tmp/hooks -rm -r /tmp/debian-chroot -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - ./run_null.sh SUDO - runtests=$((runtests+1)) -fi - -# test special hooks -for mode in root unshare fakechroot proot; do - print_header "mode=$mode,variant=apt: test special hooks with $mode mode" - if [ "$mode" = "unshare" ] && [ "$HAVE_UNSHARE" != "yes" ]; then - echo "HAVE_UNSHARE != yes -- Skipping test..." >&2 - skipped=$((skipped+1)) - continue - fi - if [ "$mode" = "proot" ] && [ "$HAVE_PROOT" != "yes" ]; then - echo "HAVE_PROOT != yes -- Skipping test..." >&2 - skipped=$((skipped+1)) - continue - fi - cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -if [ "\$(id -u)" -eq 0 ] && ! id -u user > /dev/null 2>&1; then - if [ ! -e /mmdebstrap-testenv ]; then - echo "this test modifies the system and should only be run inside a container" >&2 - exit 1 - fi - adduser --gecos user --disabled-password user -fi -if [ "$mode" = unshare ]; then - if [ ! -e /mmdebstrap-testenv ]; then - echo "this test modifies the system and should only be run inside a container" >&2 - exit 1 - fi - sysctl -w kernel.unprivileged_userns_clone=1 -fi -prefix= -[ "\$(id -u)" -eq 0 ] && [ "$mode" != "root" ] && prefix="runuser -u user --" -[ "$mode" = "fakechroot" ] && prefix="\$prefix fakechroot fakeroot" -symlinktarget=/real -case $mode in fakechroot|proot) symlinktarget='\$1/real';; esac -echo copy-in-setup > /tmp/copy-in-setup -echo copy-in-essential > /tmp/copy-in-essential -echo copy-in-customize > /tmp/copy-in-customize -echo tar-in-setup > /tmp/tar-in-setup -echo tar-in-essential > /tmp/tar-in-essential -echo tar-in-customize > /tmp/tar-in-customize -tar --numeric-owner --format=pax --pax-option=exthdr.name=%d/PaxHeaders/%f,delete=atime,delete=ctime -C /tmp -cf /tmp/tar-in-setup.tar tar-in-setup -tar --numeric-owner --format=pax --pax-option=exthdr.name=%d/PaxHeaders/%f,delete=atime,delete=ctime -C /tmp -cf /tmp/tar-in-essential.tar tar-in-essential -tar --numeric-owner --format=pax --pax-option=exthdr.name=%d/PaxHeaders/%f,delete=atime,delete=ctime -C /tmp -cf /tmp/tar-in-customize.tar tar-in-customize -rm /tmp/tar-in-setup -rm /tmp/tar-in-essential -rm /tmp/tar-in-customize -echo upload-setup > /tmp/upload-setup -echo upload-essential > /tmp/upload-essential -echo upload-customize > /tmp/upload-customize -mkdir /tmp/sync-in-setup -mkdir /tmp/sync-in-essential -mkdir /tmp/sync-in-customize -echo sync-in-setup > /tmp/sync-in-setup/file -echo sync-in-essential > /tmp/sync-in-essential/file -echo sync-in-customize > /tmp/sync-in-customize/file -\$prefix $CMD --mode=$mode --variant=apt \ - --setup-hook='mkdir "\$1/real"' \ - --setup-hook='copy-in /tmp/copy-in-setup /real' \ - --setup-hook='echo copy-in-setup | cmp "\$1/real/copy-in-setup" -' \ - --setup-hook='rm "\$1/real/copy-in-setup"' \ - --setup-hook='echo copy-out-setup > "\$1/real/copy-out-setup"' \ - --setup-hook='copy-out /real/copy-out-setup /tmp' \ - --setup-hook='rm "\$1/real/copy-out-setup"' \ - --setup-hook='tar-in /tmp/tar-in-setup.tar /real' \ - --setup-hook='echo tar-in-setup | cmp "\$1/real/tar-in-setup" -' \ - --setup-hook='tar-out /real/tar-in-setup /tmp/tar-out-setup.tar' \ - --setup-hook='rm "\$1"/real/tar-in-setup' \ - --setup-hook='upload /tmp/upload-setup /real/upload' \ - --setup-hook='echo upload-setup | cmp "\$1/real/upload" -' \ - --setup-hook='download /real/upload /tmp/download-setup' \ - --setup-hook='rm "\$1/real/upload"' \ - --setup-hook='sync-in /tmp/sync-in-setup /real' \ - --setup-hook='echo sync-in-setup | cmp "\$1/real/file" -' \ - --setup-hook='sync-out /real /tmp/sync-out-setup' \ - --setup-hook='rm "\$1/real/file"' \ - --essential-hook='ln -s "'"\$symlinktarget"'" "\$1/symlink"' \ - --essential-hook='copy-in /tmp/copy-in-essential /symlink' \ - --essential-hook='echo copy-in-essential | cmp "\$1/real/copy-in-essential" -' \ - --essential-hook='rm "\$1/real/copy-in-essential"' \ - --essential-hook='echo copy-out-essential > "\$1/real/copy-out-essential"' \ - --essential-hook='copy-out /symlink/copy-out-essential /tmp' \ - --essential-hook='rm "\$1/real/copy-out-essential"' \ - --essential-hook='tar-in /tmp/tar-in-essential.tar /symlink' \ - --essential-hook='echo tar-in-essential | cmp "\$1/real/tar-in-essential" -' \ - --essential-hook='tar-out /symlink/tar-in-essential /tmp/tar-out-essential.tar' \ - --essential-hook='rm "\$1"/real/tar-in-essential' \ - --essential-hook='upload /tmp/upload-essential /symlink/upload' \ - --essential-hook='echo upload-essential | cmp "\$1/real/upload" -' \ - --essential-hook='download /symlink/upload /tmp/download-essential' \ - --essential-hook='rm "\$1/real/upload"' \ - --essential-hook='sync-in /tmp/sync-in-essential /symlink' \ - --essential-hook='echo sync-in-essential | cmp "\$1/real/file" -' \ - --essential-hook='sync-out /real /tmp/sync-out-essential' \ - --essential-hook='rm "\$1/real/file"' \ - --customize-hook='copy-in /tmp/copy-in-customize /symlink' \ - --customize-hook='echo copy-in-customize | cmp "\$1/real/copy-in-customize" -' \ - --customize-hook='rm "\$1/real/copy-in-customize"' \ - --customize-hook='echo copy-out-customize > "\$1/real/copy-out-customize"' \ - --customize-hook='copy-out /symlink/copy-out-customize /tmp' \ - --customize-hook='rm "\$1/real/copy-out-customize"' \ - --customize-hook='tar-in /tmp/tar-in-customize.tar /symlink' \ - --customize-hook='echo tar-in-customize | cmp "\$1/real/tar-in-customize" -' \ - --customize-hook='tar-out /symlink/tar-in-customize /tmp/tar-out-customize.tar' \ - --customize-hook='rm "\$1"/real/tar-in-customize' \ - --customize-hook='upload /tmp/upload-customize /symlink/upload' \ - --customize-hook='echo upload-customize | cmp "\$1/real/upload" -' \ - --customize-hook='download /symlink/upload /tmp/download-customize' \ - --customize-hook='rm "\$1/real/upload"' \ - --customize-hook='sync-in /tmp/sync-in-customize /symlink' \ - --customize-hook='echo sync-in-customize | cmp "\$1/real/file" -' \ - --customize-hook='sync-out /real /tmp/sync-out-customize' \ - --customize-hook='rm "\$1/real/file"' \ - --customize-hook='rmdir "\$1/real"' \ - --customize-hook='rm "\$1/symlink"' \ - $DEFAULT_DIST /tmp/debian-chroot.tar $mirror -for n in setup essential customize; do - ret=0 - cmp /tmp/tar-in-\$n.tar /tmp/tar-out-\$n.tar || ret=\$? - if [ "\$ret" -ne 0 ]; then - if type diffoscope >/dev/null; then - diffoscope /tmp/tar-in-\$n.tar /tmp/tar-out-\$n.tar - exit 1 - else - echo "no diffoscope installed" >&2 - fi - if type base64 >/dev/null; then - base64 /tmp/tar-in-\$n.tar - base64 /tmp/tar-out-\$n.tar - exit 1 - else - echo "no base64 installed" >&2 - fi - if type xxd >/dev/null; then - xxd /tmp/tar-in-\$n.tar - xxd /tmp/tar-out-\$n.tar - exit 1 - else - echo "no xxd installed" >&2 - fi - exit 1 - fi -done -echo copy-out-setup | cmp /tmp/copy-out-setup - -echo copy-out-essential | cmp /tmp/copy-out-essential - -echo copy-out-customize | cmp /tmp/copy-out-customize - -echo upload-setup | cmp /tmp/download-setup - -echo upload-essential | cmp /tmp/download-essential - -echo upload-customize | cmp /tmp/download-customize - -echo sync-in-setup | cmp /tmp/sync-out-setup/file - -echo sync-in-essential | cmp /tmp/sync-out-essential/file - -echo sync-in-customize | cmp /tmp/sync-out-customize/file - -tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - -rm /tmp/debian-chroot.tar \ - /tmp/copy-in-setup /tmp/copy-in-essential /tmp/copy-in-customize \ - /tmp/copy-out-setup /tmp/copy-out-essential /tmp/copy-out-customize \ - /tmp/tar-in-setup.tar /tmp/tar-in-essential.tar /tmp/tar-in-customize.tar \ - /tmp/tar-out-setup.tar /tmp/tar-out-essential.tar /tmp/tar-out-customize.tar \ - /tmp/upload-setup /tmp/upload-essential /tmp/upload-customize \ - /tmp/download-setup /tmp/download-essential /tmp/download-customize \ - /tmp/sync-in-setup/file /tmp/sync-in-essential/file /tmp/sync-in-customize/file \ - /tmp/sync-out-setup/file /tmp/sync-out-essential/file /tmp/sync-out-customize/file -rmdir /tmp/sync-in-setup /tmp/sync-in-essential /tmp/sync-in-customize \ - /tmp/sync-out-setup /tmp/sync-out-essential /tmp/sync-out-customize -END - if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) - else - echo "HAVE_QEMU != yes -- Skipping test..." >&2 - skipped=$((skipped+1)) - fi -done - -print_header "mode=root,variant=apt: debootstrap no-op options" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -$CMD --mode=root --variant=apt --resolve-deps --merged-usr --no-merged-usr --force-check-gpg $DEFAULT_DIST /tmp/debian-chroot $mirror -tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - -rm -r /tmp/debian-chroot -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - ./run_null.sh SUDO - runtests=$((runtests+1)) -fi - -print_header "mode=root,variant=apt: --verbose" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -$CMD --mode=root --variant=apt --verbose $DEFAULT_DIST /tmp/debian-chroot $mirror -tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - -rm -r /tmp/debian-chroot -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - ./run_null.sh SUDO - runtests=$((runtests+1)) -fi - -print_header "mode=root,variant=apt: --debug" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -$CMD --mode=root --variant=apt --debug $DEFAULT_DIST /tmp/debian-chroot $mirror -tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - -rm -r /tmp/debian-chroot -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - ./run_null.sh SUDO - runtests=$((runtests+1)) -fi - -print_header "mode=root,variant=apt: --quiet" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -$CMD --mode=root --variant=apt --quiet $DEFAULT_DIST /tmp/debian-chroot $mirror -tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - -rm -r /tmp/debian-chroot -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - ./run_null.sh SUDO - runtests=$((runtests+1)) -fi - -print_header "mode=root,variant=apt: --logfile" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -# we check the full log to also prevent debug printfs to accidentally make it into a commit -$CMD --mode=root --variant=apt --logfile=/tmp/log $DEFAULT_DIST /tmp/debian-chroot $mirror -# omit the last line which should contain the runtime -head --lines=-1 /tmp/log > /tmp/trimmed -cat << LOG | diff -u - /tmp/trimmed -I: chroot architecture $HOSTARCH is equal to the host's architecture -I: automatically chosen format: directory -I: running apt-get update... -I: downloading packages with apt... -I: extracting archives... -I: installing essential packages... -I: cleaning package lists and apt cache... -LOG -tail --lines=1 /tmp/log | grep '^I: success in .* seconds$' -tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - -rm -r /tmp/debian-chroot -rm /tmp/log /tmp/trimmed -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - ./run_null.sh SUDO - runtests=$((runtests+1)) -fi - -print_header "mode=$defaultmode,variant=apt: without /etc/resolv.conf and /etc/hostname" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -if [ ! -e /mmdebstrap-testenv ]; then - echo "this test modifies the system and should only be run inside a container" >&2 - exit 1 -fi -rm /etc/resolv.conf /etc/hostname -$CMD --mode=$defaultmode --variant=apt $DEFAULT_DIST /tmp/debian-chroot.tar $mirror -{ tar -tf /tmp/debian-chroot.tar; - printf "./etc/hostname\n"; - printf "./etc/resolv.conf\n"; -} | sort | diff -u tar1.txt - -rm /tmp/debian-chroot.tar -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - echo "HAVE_QEMU != yes -- Skipping test..." >&2 - skipped=$((skipped+1)) -fi - -print_header "mode=$defaultmode,variant=custom: preserve mode of /etc/resolv.conf and /etc/hostname" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -if [ ! -e /mmdebstrap-testenv ]; then - echo "this test modifies the system and should only be run inside a container" >&2 - exit 1 -fi -for f in /etc/resolv.conf /etc/hostname; do - # preserve original content - cat "\$f" > "\$f.bak" - # in case \$f is a symlink, we replace it by a real file - if [ -L "\$f" ]; then - rm "\$f" - cp "\$f.bak" "\$f" - fi - chmod 644 "\$f" - [ "\$(stat --format=%A "\$f")" = "-rw-r--r--" ] -done -$CMD --variant=custom --mode=$defaultmode $DEFAULT_DIST /tmp/debian-chroot $mirror -for f in /etc/resolv.conf /etc/hostname; do - [ "\$(stat --format=%A "/tmp/debian-chroot/\$f")" = "-rw-r--r--" ] -done -rm /tmp/debian-chroot/dev/console -rm /tmp/debian-chroot/dev/fd -rm /tmp/debian-chroot/dev/full -rm /tmp/debian-chroot/dev/null -rm /tmp/debian-chroot/dev/ptmx -rm /tmp/debian-chroot/dev/random -rm /tmp/debian-chroot/dev/stderr -rm /tmp/debian-chroot/dev/stdin -rm /tmp/debian-chroot/dev/stdout -rm /tmp/debian-chroot/dev/tty -rm /tmp/debian-chroot/dev/urandom -rm /tmp/debian-chroot/dev/zero -rm /tmp/debian-chroot/etc/apt/sources.list -rm /tmp/debian-chroot/etc/fstab -rm /tmp/debian-chroot/etc/hostname -rm /tmp/debian-chroot/etc/resolv.conf -rm /tmp/debian-chroot/var/lib/apt/lists/lock -rm /tmp/debian-chroot/var/lib/dpkg/status -# the rest should be empty directories that we can rmdir recursively -find /tmp/debian-chroot -depth -print0 | xargs -0 rmdir -for f in /etc/resolv.conf /etc/hostname; do - chmod 755 "\$f" - [ "\$(stat --format=%A "\$f")" = "-rwxr-xr-x" ] -done -$CMD --variant=custom --mode=$defaultmode $DEFAULT_DIST /tmp/debian-chroot $mirror -for f in /etc/resolv.conf /etc/hostname; do - [ "\$(stat --format=%A "/tmp/debian-chroot/\$f")" = "-rwxr-xr-x" ] -done -rm /tmp/debian-chroot/dev/console -rm /tmp/debian-chroot/dev/fd -rm /tmp/debian-chroot/dev/full -rm /tmp/debian-chroot/dev/null -rm /tmp/debian-chroot/dev/ptmx -rm /tmp/debian-chroot/dev/random -rm /tmp/debian-chroot/dev/stderr -rm /tmp/debian-chroot/dev/stdin -rm /tmp/debian-chroot/dev/stdout -rm /tmp/debian-chroot/dev/tty -rm /tmp/debian-chroot/dev/urandom -rm /tmp/debian-chroot/dev/zero -rm /tmp/debian-chroot/etc/apt/sources.list -rm /tmp/debian-chroot/etc/fstab -rm /tmp/debian-chroot/etc/hostname -rm /tmp/debian-chroot/etc/resolv.conf -rm /tmp/debian-chroot/var/lib/apt/lists/lock -rm /tmp/debian-chroot/var/lib/dpkg/status -# the rest should be empty directories that we can rmdir recursively -find /tmp/debian-chroot -depth -print0 | xargs -0 rmdir -for f in /etc/resolv.conf /etc/hostname; do - rm "\$f" - ln -s "\$f.bak" "\$f" - [ "\$(stat --format=%A "\$f")" = "lrwxrwxrwx" ] -done -$CMD --variant=custom --mode=$defaultmode $DEFAULT_DIST /tmp/debian-chroot $mirror -for f in /etc/resolv.conf /etc/hostname; do - [ "\$(stat --format=%A "/tmp/debian-chroot/\$f")" = "-rw-r--r--" ] -done -rm /tmp/debian-chroot/dev/console -rm /tmp/debian-chroot/dev/fd -rm /tmp/debian-chroot/dev/full -rm /tmp/debian-chroot/dev/null -rm /tmp/debian-chroot/dev/ptmx -rm /tmp/debian-chroot/dev/random -rm /tmp/debian-chroot/dev/stderr -rm /tmp/debian-chroot/dev/stdin -rm /tmp/debian-chroot/dev/stdout -rm /tmp/debian-chroot/dev/tty -rm /tmp/debian-chroot/dev/urandom -rm /tmp/debian-chroot/dev/zero -rm /tmp/debian-chroot/etc/apt/sources.list -rm /tmp/debian-chroot/etc/fstab -rm /tmp/debian-chroot/etc/hostname -rm /tmp/debian-chroot/etc/resolv.conf -rm /tmp/debian-chroot/var/lib/apt/lists/lock -rm /tmp/debian-chroot/var/lib/dpkg/status -# the rest should be empty directories that we can rmdir recursively -find /tmp/debian-chroot -depth -print0 | xargs -0 rmdir -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - echo "HAVE_QEMU != yes -- Skipping test..." >&2 - skipped=$((skipped+1)) -fi - -print_header "mode=$defaultmode,variant=essential: test not having to install apt in --include because a hook did it before" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -$CMD --mode=$defaultmode --variant=essential --include=apt \ - --essential-hook='APT_CONFIG=\$MMDEBSTRAP_APT_CONFIG apt-get update' \ - --essential-hook='APT_CONFIG=\$MMDEBSTRAP_APT_CONFIG apt-get --yes install -oDPkg::Chroot-Directory="\$1" apt' \ - $DEFAULT_DIST /tmp/debian-chroot.tar $mirror -tar -tf /tmp/debian-chroot.tar | sort | grep -v ./var/lib/apt/extended_states | diff -u tar1.txt - -rm /tmp/debian-chroot.tar -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -elif [ "$defaultmode" = "root" ]; then - ./run_null.sh SUDO - runtests=$((runtests+1)) -else - ./run_null.sh - runtests=$((runtests+1)) -fi - -print_header "mode=$defaultmode,variant=apt: remove start-stop-daemon and policy-rc.d in hook" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -$CMD --mode=$defaultmode --variant=apt --customize-hook='rm "\$1/usr/sbin/policy-rc.d"; rm "\$1/sbin/start-stop-daemon"' $DEFAULT_DIST /tmp/debian-chroot.tar $mirror -tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - -rm /tmp/debian-chroot.tar -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -elif [ "$defaultmode" = "root" ]; then - ./run_null.sh SUDO - runtests=$((runtests+1)) -else - ./run_null.sh - runtests=$((runtests+1)) -fi - -# test that the user can drop archives into /var/cache/apt/archives as well as -# into /var/cache/apt/archives/partial -for variant in extract custom essential apt minbase buildd important standard; do - print_header "mode=$defaultmode,variant=$variant: compare output with pre-seeded /var/cache/apt/archives" - if [ "$variant" = "standard" ]; then - case "$DEFAULT_DIST" in oldstable|stable) - echo "skipping test because of #864082, #1004557 and #1004558" >&2 - skipped=$((skipped+1)) - continue - ;; - esac - fi - if [ "$variant" = "important" ] && [ "$DEFAULT_DIST" = "oldstable" ]; then - echo "skipping test on oldstable because /var/lib/systemd/catalog/database differs" >&2 - skipped=$((skipped+1)) - continue - fi -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -export SOURCE_DATE_EPOCH=$SOURCE_DATE_EPOCH -if [ ! -e /mmdebstrap-testenv ]; then - echo "this test requires the cache directory to be mounted on /mnt and should only be run inside a container" >&2 - exit 1 -fi -include="--include=doc-debian" -if [ "$variant" = "custom" ]; then - include="\$include,base-files,base-passwd,coreutils,dash,diffutils,dpkg,libc-bin,sed" -fi -mount -o size=4G -t tmpfs tmpfs /tmp # workaround for #1010957 -$CMD \$include --mode=$defaultmode --variant=$variant \ - --setup-hook='mkdir -p "\$1"/var/cache/apt/archives/partial' \ - --setup-hook='touch "\$1"/var/cache/apt/archives/lock' \ - --setup-hook='chmod 0640 "\$1"/var/cache/apt/archives/lock' \ - $DEFAULT_DIST - $mirror > orig.tar -# somehow, when trying to create a tarball from the 9p mount, tar throws the -# following error: tar: ./doc-debian_6.4_all.deb: File shrank by 132942 bytes; padding with zeros -# to reproduce, try: tar --directory /mnt/cache/debian/pool/main/d/doc-debian/ --create --file - . | tar --directory /tmp/ --extract --file - -# this will be different: -# md5sum /mnt/cache/debian/pool/main/d/doc-debian/*.deb /tmp/*.deb -# another reason to copy the files into a new directory is, that we can use shell globs -tmpdir=\$(mktemp -d) -cp /mnt/cache/debian/pool/main/b/busybox/busybox_*"_$HOSTARCH.deb" /mnt/cache/debian/pool/main/a/apt/apt_*"_$HOSTARCH.deb" "\$tmpdir" -$CMD \$include --mode=$defaultmode --variant=$variant \ - --setup-hook='mkdir -p "\$1"/var/cache/apt/archives/partial' \ - --setup-hook='sync-in "'"\$tmpdir"'" /var/cache/apt/archives/partial' \ - $DEFAULT_DIST - $mirror > test1.tar -cmp orig.tar test1.tar -$CMD \$include --mode=$defaultmode --variant=$variant \ - --customize-hook='touch "\$1"/var/cache/apt/archives/partial' \ - --setup-hook='mkdir -p "\$1"/var/cache/apt/archives/' \ - --setup-hook='sync-in "'"\$tmpdir"'" /var/cache/apt/archives/' \ - --setup-hook='chmod 0755 "\$1"/var/cache/apt/archives/' \ - --customize-hook='find "'"\$tmpdir"'" -type f -exec md5sum "{}" \; | sed "s|"'"\$tmpdir"'"|\$1/var/cache/apt/archives|" | md5sum --check' \ - $DEFAULT_DIST - $mirror > test2.tar -cmp orig.tar test2.tar -rm "\$tmpdir"/*.deb orig.tar test1.tar test2.tar -rmdir "\$tmpdir" -END - if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) - else - echo "HAVE_QEMU != yes -- Skipping test..." >&2 - skipped=$((skipped+1)) - fi -done - -print_header "mode=$defaultmode,variant=apt: create directory --dry-run" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -$CMD --mode=$defaultmode --dry-run --variant=apt --setup-hook="exit 1" --essential-hook="exit 1" --customize-hook="exit 1" $DEFAULT_DIST /tmp/debian-chroot $mirror -rm /tmp/debian-chroot/dev/console -rm /tmp/debian-chroot/dev/fd -rm /tmp/debian-chroot/dev/full -rm /tmp/debian-chroot/dev/null -rm /tmp/debian-chroot/dev/ptmx -rm /tmp/debian-chroot/dev/random -rm /tmp/debian-chroot/dev/stderr -rm /tmp/debian-chroot/dev/stdin -rm /tmp/debian-chroot/dev/stdout -rm /tmp/debian-chroot/dev/tty -rm /tmp/debian-chroot/dev/urandom -rm /tmp/debian-chroot/dev/zero -rm /tmp/debian-chroot/etc/apt/sources.list -rm /tmp/debian-chroot/etc/fstab -rm /tmp/debian-chroot/etc/hostname -rm /tmp/debian-chroot/etc/resolv.conf -rm /tmp/debian-chroot/var/lib/apt/lists/lock -rm /tmp/debian-chroot/var/lib/dpkg/status -# the rest should be empty directories that we can rmdir recursively -find /tmp/debian-chroot -depth -print0 | xargs -0 rmdir -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -elif [ "$defaultmode" = "root" ]; then - ./run_null.sh SUDO - runtests=$((runtests+1)) -else - ./run_null.sh - runtests=$((runtests+1)) -fi - -# test all --dry-run variants - -# we are testing all variants here because with 0.7.5 we had a bug: -# mmdebstrap sid /dev/null --simulate ==> E: cannot read /var/cache/apt/archives/ -for variant in extract custom essential apt minbase buildd important standard; do - for mode in root unshare fakechroot proot chrootless; do - print_header "mode=$mode,variant=$variant: create tarball --dry-run" - if [ "$mode" = "unshare" ] && [ "$HAVE_UNSHARE" != "yes" ]; then - echo "HAVE_UNSHARE != yes -- Skipping test..." >&2 - skipped=$((skipped+1)) - continue - fi - if [ "$mode" = "proot" ] && [ "$HAVE_PROOT" != "yes" ]; then - echo "HAVE_PROOT != yes -- Skipping test..." >&2 - skipped=$((skipped+1)) - continue - fi - cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -prefix= -include= -if [ "\$(id -u)" -eq 0 ] && [ "$mode" != root ]; then - # this must be qemu - if ! id -u user >/dev/null 2>&1; then - if [ ! -e /mmdebstrap-testenv ]; then - echo "this test modifies the system and should only be run inside a container" >&2 - exit 1 - fi - adduser --gecos user --disabled-password user - fi - if [ "$mode" = unshare ]; then - if [ ! -e /mmdebstrap-testenv ]; then - echo "this test modifies the system and should only be run inside a container" >&2 - exit 1 - fi - sysctl -w kernel.unprivileged_userns_clone=1 - fi - prefix="runuser -u user --" - if [ "$mode" = extract ] || [ "$mode" = custom ]; then - include="--include=\$(cat pkglist.txt | tr '\n' ',')" - fi -fi -\$prefix $CMD --mode=$mode \$include --dry-run --variant=$variant $DEFAULT_DIST /tmp/debian-chroot.tar $mirror -if [ -e /tmp/debian-chroot.tar ]; then - echo "/tmp/debian-chroot.tar must not be created with --dry-run" >&2 - exit 1 -fi -END - if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) - elif [ "$mode" = "root" ]; then - ./run_null.sh SUDO - runtests=$((runtests+1)) - else - ./run_null.sh - runtests=$((runtests+1)) - fi - done -done - -# test extract variant also with chrootless mode -for mode in root unshare fakechroot proot chrootless; do - print_header "mode=$mode,variant=extract: unpack doc-debian" - if [ "$mode" = "unshare" ] && [ "$HAVE_UNSHARE" != "yes" ]; then - echo "HAVE_UNSHARE != yes -- Skipping test..." >&2 - skipped=$((skipped+1)) - continue - fi - if [ "$mode" = "proot" ] && [ "$HAVE_PROOT" != "yes" ]; then - echo "HAVE_PROOT != yes -- Skipping test..." >&2 - skipped=$((skipped+1)) - continue - fi - cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -if [ "\$(id -u)" -eq 0 ] && ! id -u user > /dev/null 2>&1; then - if [ ! -e /mmdebstrap-testenv ]; then - echo "this test modifies the system and should only be run inside a container" >&2 - exit 1 - fi - adduser --gecos user --disabled-password user -fi -if [ "$mode" = unshare ]; then - if [ ! -e /mmdebstrap-testenv ]; then - echo "this test modifies the system and should only be run inside a container" >&2 - exit 1 - fi - sysctl -w kernel.unprivileged_userns_clone=1 -fi -prefix= -[ "\$(id -u)" -eq 0 ] && [ "$mode" != "root" ] && prefix="runuser -u user --" -[ "$mode" = "fakechroot" ] && prefix="\$prefix fakechroot fakeroot" -\$prefix $CMD --mode=$mode --variant=extract --include=doc-debian $DEFAULT_DIST /tmp/debian-chroot $mirror -# delete contents of doc-debian -rm /tmp/debian-chroot/usr/share/doc-base/debian-* -rm -r /tmp/debian-chroot/usr/share/doc/debian -rm -r /tmp/debian-chroot/usr/share/doc/doc-debian -# delete real files -rm /tmp/debian-chroot/etc/apt/sources.list -rm /tmp/debian-chroot/etc/fstab -rm /tmp/debian-chroot/etc/hostname -rm /tmp/debian-chroot/etc/resolv.conf -rm /tmp/debian-chroot/var/lib/dpkg/status -rm /tmp/debian-chroot/var/cache/apt/archives/lock -rm /tmp/debian-chroot/var/lib/apt/lists/lock -## delete merged usr symlinks -#rm /tmp/debian-chroot/libx32 -#rm /tmp/debian-chroot/lib64 -#rm /tmp/debian-chroot/lib32 -#rm /tmp/debian-chroot/sbin -#rm /tmp/debian-chroot/bin -#rm /tmp/debian-chroot/lib -# delete ./dev (files might exist or not depending on the mode) -rm -f /tmp/debian-chroot/dev/console -rm -f /tmp/debian-chroot/dev/fd -rm -f /tmp/debian-chroot/dev/full -rm -f /tmp/debian-chroot/dev/null -rm -f /tmp/debian-chroot/dev/ptmx -rm -f /tmp/debian-chroot/dev/random -rm -f /tmp/debian-chroot/dev/stderr -rm -f /tmp/debian-chroot/dev/stdin -rm -f /tmp/debian-chroot/dev/stdout -rm -f /tmp/debian-chroot/dev/tty -rm -f /tmp/debian-chroot/dev/urandom -rm -f /tmp/debian-chroot/dev/zero -# the rest should be empty directories that we can rmdir recursively -find /tmp/debian-chroot -depth -print0 | xargs -0 rmdir -END - if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) - else - echo "HAVE_QEMU != yes -- Skipping test..." >&2 - skipped=$((skipped+1)) - fi -done - -print_header "mode=chrootless,variant=custom: install doc-debian" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -if [ "\$(id -u)" -eq 0 ] && ! id -u user > /dev/null 2>&1; then - if [ ! -e /mmdebstrap-testenv ]; then - echo "this test modifies the system and should only be run inside a container" >&2 - exit 1 - fi - adduser --gecos user --disabled-password user -fi -prefix= -[ "\$(id -u)" -eq 0 ] && prefix="runuser -u user --" -\$prefix $CMD --mode=chrootless --variant=custom --include=doc-debian $DEFAULT_DIST /tmp/debian-chroot $mirror -tar -C /tmp/debian-chroot --owner=0 --group=0 --numeric-owner --sort=name --clamp-mtime --mtime=$(date --utc --date=@$SOURCE_DATE_EPOCH --iso-8601=seconds) -cf /tmp/debian-chroot.tar . -tar tvf /tmp/debian-chroot.tar > doc-debian.tar.list -rm /tmp/debian-chroot.tar -# delete contents of doc-debian -rm /tmp/debian-chroot/usr/share/doc-base/debian-* -rm -r /tmp/debian-chroot/usr/share/doc/debian -rm -r /tmp/debian-chroot/usr/share/doc/doc-debian -# delete real files -rm /tmp/debian-chroot/etc/apt/sources.list -rm /tmp/debian-chroot/etc/fstab -rm /tmp/debian-chroot/etc/hostname -rm /tmp/debian-chroot/etc/resolv.conf -rm /tmp/debian-chroot/var/lib/dpkg/status -rm /tmp/debian-chroot/var/cache/apt/archives/lock -rm /tmp/debian-chroot/var/lib/dpkg/lock -rm /tmp/debian-chroot/var/lib/dpkg/lock-frontend -rm /tmp/debian-chroot/var/lib/apt/lists/lock -## delete merged usr symlinks -#rm /tmp/debian-chroot/libx32 -#rm /tmp/debian-chroot/lib64 -#rm /tmp/debian-chroot/lib32 -#rm /tmp/debian-chroot/sbin -#rm /tmp/debian-chroot/bin -#rm /tmp/debian-chroot/lib -# in chrootless mode, there is more to remove -rm /tmp/debian-chroot/var/lib/dpkg/triggers/Lock -rm /tmp/debian-chroot/var/lib/dpkg/triggers/Unincorp -rm /tmp/debian-chroot/var/lib/dpkg/status-old -rm /tmp/debian-chroot/var/lib/dpkg/info/format -rm /tmp/debian-chroot/var/lib/dpkg/info/doc-debian.md5sums -rm /tmp/debian-chroot/var/lib/dpkg/info/doc-debian.list -# the rest should be empty directories that we can rmdir recursively -find /tmp/debian-chroot -depth -print0 | xargs -0 rmdir -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - ./run_null.sh - runtests=$((runtests+1)) -fi - -# regularly check whether more packages work with chrootless: -# for p in $(grep-aptavail -F Essential yes -s Package -n | sort -u); do ./mmdebstrap --mode=chrootless --variant=custom --include=bsdutils,coreutils,debianutils,diffutils,dpkg,findutils,grep,gzip,hostname,init-system-helpers,ncurses-base,ncurses-bin,perl-base,sed,sysvinit-utils,tar,$p unstable /dev/null; done -# -# see https://bugs.debian.org/cgi-bin/pkgreport.cgi?users=debian-dpkg@lists.debian.org;tag=dpkg-root-support -# -# base-files: #824594 -# base-passwd: debconf -# bash: depends base-files -# bsdutils: ok -# coreutils: ok -# dash: debconf -# debianutils: ok -# diffutils: ok -# dpkg: ok -# findutils: ok -# grep: ok -# gzip: ok -# hostname: ok -# init-system-helpers: ok -# libc-bin: #983412 -# login: debconf -# ncurses-base: ok -# ncurses-bin: ok -# perl-base: ok -# sed: ok -# sysvinit-utils: ok -# tar: ok -# util-linux: debconf -print_header "mode=chrootless,variant=custom: install known-good from essential:yes" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -if [ "\$(id -u)" -eq 0 ] && ! id -u user > /dev/null 2>&1; then - if [ ! -e /mmdebstrap-testenv ]; then - echo "this test modifies the system and should only be run inside a container" >&2 - exit 1 - fi - adduser --gecos user --disabled-password user -fi -prefix= -[ "\$(id -u)" -eq 0 ] && prefix="runuser -u user --" -\$prefix $CMD --mode=chrootless --variant=custom --include=bsdutils,coreutils,debianutils,diffutils,dpkg,findutils,grep,gzip,hostname,init-system-helpers,ncurses-base,ncurses-bin,perl-base,sed,sysvinit-utils,tar $DEFAULT_DIST /dev/null $mirror -END -if [ "$DEFAULT_DIST" = "oldstable" ]; then - echo "chrootless doesn't work in oldstable -- Skipping test..." >&2 - skipped=$((skipped+1)) -elif true; then - # https://salsa.debian.org/pkg-debconf/debconf/-/merge_requests/8 - echo "blocked by #983425 -- Skipping test..." >&2 - skipped=$((skipped+1)) -elif [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - ./run_null.sh - runtests=$((runtests+1)) -fi - -print_header "mode=chrootless,variant=custom: install doc-debian and output tarball" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -export SOURCE_DATE_EPOCH=$SOURCE_DATE_EPOCH -if [ "\$(id -u)" -eq 0 ] && ! id -u user > /dev/null 2>&1; then - if [ ! -e /mmdebstrap-testenv ]; then - echo "this test modifies the system and should only be run inside a container" >&2 - exit 1 - fi - adduser --gecos user --disabled-password user -fi -prefix= -[ "\$(id -u)" -eq 0 ] && prefix="runuser -u user --" -\$prefix $CMD --mode=chrootless --variant=custom --include=doc-debian $DEFAULT_DIST /tmp/debian-chroot.tar $mirror -tar tvf /tmp/debian-chroot.tar | grep -v ' ./dev' | diff -u doc-debian.tar.list - -rm /tmp/debian-chroot.tar -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - ./run_null.sh - runtests=$((runtests+1)) -fi - -print_header "mode=chrootless,variant=custom: install doc-debian and test hooks" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -export SOURCE_DATE_EPOCH=$SOURCE_DATE_EPOCH -if [ "\$(id -u)" -eq 0 ] && ! id -u user > /dev/null 2>&1; then - if [ ! -e /mmdebstrap-testenv ]; then - echo "this test modifies the system and should only be run inside a container" >&2 - exit 1 - fi - adduser --gecos user --disabled-password user -fi -prefix= -[ "\$(id -u)" -eq 0 ] && prefix="runuser -u user --" -\$prefix $CMD --mode=chrootless --skip=cleanup/tmp --variant=custom --include=doc-debian --setup-hook='touch "\$1/tmp/setup"' --customize-hook='touch "\$1/tmp/customize"' $DEFAULT_DIST /tmp/debian-chroot $mirror -rm /tmp/debian-chroot/tmp/setup -rm /tmp/debian-chroot/tmp/customize -tar -C /tmp/debian-chroot --owner=0 --group=0 --numeric-owner --sort=name --clamp-mtime --mtime=$(date --utc --date=@$SOURCE_DATE_EPOCH --iso-8601=seconds) -cf /tmp/debian-chroot.tar . -tar tvf /tmp/debian-chroot.tar | grep -v ' ./dev' | diff -u doc-debian.tar.list - -rm /tmp/debian-chroot.tar -# delete contents of doc-debian -rm /tmp/debian-chroot/usr/share/doc-base/debian-* -rm -r /tmp/debian-chroot/usr/share/doc/debian -rm -r /tmp/debian-chroot/usr/share/doc/doc-debian -# delete real files -rm /tmp/debian-chroot/etc/apt/sources.list -rm /tmp/debian-chroot/etc/fstab -rm /tmp/debian-chroot/etc/hostname -rm /tmp/debian-chroot/etc/resolv.conf -rm /tmp/debian-chroot/var/lib/dpkg/status -rm /tmp/debian-chroot/var/cache/apt/archives/lock -rm /tmp/debian-chroot/var/lib/dpkg/lock -rm /tmp/debian-chroot/var/lib/dpkg/lock-frontend -rm /tmp/debian-chroot/var/lib/apt/lists/lock -## delete merged usr symlinks -#rm /tmp/debian-chroot/libx32 -#rm /tmp/debian-chroot/lib64 -#rm /tmp/debian-chroot/lib32 -#rm /tmp/debian-chroot/sbin -#rm /tmp/debian-chroot/bin -#rm /tmp/debian-chroot/lib -# in chrootless mode, there is more to remove -rm /tmp/debian-chroot/var/lib/dpkg/triggers/Lock -rm /tmp/debian-chroot/var/lib/dpkg/triggers/Unincorp -rm /tmp/debian-chroot/var/lib/dpkg/status-old -rm /tmp/debian-chroot/var/lib/dpkg/info/format -rm /tmp/debian-chroot/var/lib/dpkg/info/doc-debian.md5sums -rm /tmp/debian-chroot/var/lib/dpkg/info/doc-debian.list -# the rest should be empty directories that we can rmdir recursively -find /tmp/debian-chroot -depth -print0 | xargs -0 rmdir -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - ./run_null.sh - runtests=$((runtests+1)) -fi - -print_header "mode=chrootless,variant=custom: install libmagic-mgc on arm64" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -if [ "\$(id -u)" -eq 0 ] && ! id -u user > /dev/null 2>&1; then - if [ ! -e /mmdebstrap-testenv ]; then - echo "this test modifies the system and should only be run inside a container" >&2 - exit 1 - fi - adduser --gecos user --disabled-password user -fi -prefix= -[ "\$(id -u)" -eq 0 ] && prefix="runuser -u user --" -\$prefix $CMD --mode=chrootless --variant=custom --architectures=arm64 --include=libmagic-mgc $DEFAULT_DIST /tmp/debian-chroot $mirror -# delete contents of libmagic-mgc -rm /tmp/debian-chroot/usr/lib/file/magic.mgc -rm /tmp/debian-chroot/usr/share/doc/libmagic-mgc/README.Debian -rm /tmp/debian-chroot/usr/share/doc/libmagic-mgc/changelog.Debian.gz -rm /tmp/debian-chroot/usr/share/doc/libmagic-mgc/changelog.gz -rm /tmp/debian-chroot/usr/share/doc/libmagic-mgc/copyright -rm /tmp/debian-chroot/usr/share/file/magic.mgc -rm /tmp/debian-chroot/usr/share/misc/magic.mgc -# delete real files -rm /tmp/debian-chroot/etc/apt/sources.list -rm /tmp/debian-chroot/etc/fstab -rm /tmp/debian-chroot/etc/hostname -rm /tmp/debian-chroot/etc/resolv.conf -rm /tmp/debian-chroot/var/lib/dpkg/status -rm /tmp/debian-chroot/var/cache/apt/archives/lock -rm /tmp/debian-chroot/var/lib/dpkg/lock -rm /tmp/debian-chroot/var/lib/dpkg/lock-frontend -rm /tmp/debian-chroot/var/lib/apt/lists/lock -## delete merged usr symlinks -#rm /tmp/debian-chroot/libx32 -#rm /tmp/debian-chroot/lib64 -#rm /tmp/debian-chroot/lib32 -#rm /tmp/debian-chroot/sbin -#rm /tmp/debian-chroot/bin -#rm /tmp/debian-chroot/lib -# in chrootless mode, there is more to remove -rm /tmp/debian-chroot/var/lib/dpkg/arch -rm /tmp/debian-chroot/var/lib/dpkg/triggers/Lock -rm /tmp/debian-chroot/var/lib/dpkg/triggers/Unincorp -rm /tmp/debian-chroot/var/lib/dpkg/status-old -rm /tmp/debian-chroot/var/lib/dpkg/info/format -rm /tmp/debian-chroot/var/lib/dpkg/info/libmagic-mgc.md5sums -rm /tmp/debian-chroot/var/lib/dpkg/info/libmagic-mgc.list -# the rest should be empty directories that we can rmdir recursively -find /tmp/debian-chroot -depth -print0 | xargs -0 rmdir -END -if [ "$HOSTARCH" != amd64 ]; then - echo "HOSTARCH != amd64 -- Skipping test..." >&2 - skipped=$((skipped+1)) -elif [ "$HAVE_BINFMT" = "yes" ]; then - if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) - else - ./run_null.sh - runtests=$((runtests+1)) - fi -else - echo "HAVE_BINFMT != yes -- Skipping test..." >&2 - skipped=$((skipped+1)) -fi - -print_header "mode=root,variant=custom: install busybox-based sub-essential system" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -pkgs=base-files,base-passwd,busybox,debianutils,dpkg,libc-bin,mawk,tar -# busybox --install -s will install symbolic links into the rootfs, leaving -# existing files untouched. It has to run after extraction (otherwise there is -# no busybox binary) and before first configuration -$CMD --mode=root --variant=custom \ - --include=\$pkgs \ - --setup-hook='mkdir -p "\$1/bin"' \ - --setup-hook='echo root:x:0:0:root:/root:/bin/sh > "\$1/etc/passwd"' \ - --setup-hook='printf "root:x:0:\nmail:x:8:\nutmp:x:43:\n" > "\$1/etc/group"' \ - --extract-hook='chroot "\$1" busybox --install -s' \ - $DEFAULT_DIST /tmp/debian-chroot $mirror -echo "\$pkgs" | tr ',' '\n' > /tmp/expected -chroot /tmp/debian-chroot dpkg-query -f '\${binary:Package}\n' -W \ - | comm -12 - /tmp/expected \ - | diff -u - /tmp/expected -rm /tmp/expected -for cmd in echo cat sed grep; do - test -L /tmp/debian-chroot/bin/\$cmd - test "\$(readlink /tmp/debian-chroot/bin/\$cmd)" = "/bin/busybox" -done -for cmd in sort; do - test -L /tmp/debian-chroot/usr/bin/\$cmd - test "\$(readlink /tmp/debian-chroot/usr/bin/\$cmd)" = "/bin/busybox" -done -chroot /tmp/debian-chroot echo foobar \ - | chroot /tmp/debian-chroot cat \ - | chroot /tmp/debian-chroot sort \ - | chroot /tmp/debian-chroot sed 's/foobar/blubber/' \ - | chroot /tmp/debian-chroot grep blubber >/dev/null -rm -r /tmp/debian-chroot -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) -else - ./run_null.sh SUDO - runtests=$((runtests+1)) -fi - -# test foreign architecture with all modes -# create directory in sudo mode - -for mode in root unshare fakechroot proot; do - print_header "mode=$mode,variant=apt: create arm64 tarball" - if [ "$HOSTARCH" != amd64 ]; then - echo "HOSTARCH != amd64 -- Skipping test..." >&2 - skipped=$((skipped+1)) - continue - fi - if [ "$mode" = "fakechroot" ] && [ "$RUN_MA_SAME_TESTS" != yes ]; then - echo "RUN_MA_SAME_TESTS != yes -- Skipping test..." >&2 - skipped=$((skipped+1)) - continue - fi - if [ "$HAVE_BINFMT" != "yes" ]; then - echo "HAVE_BINFMT != yes -- Skipping test..." >&2 - skipped=$((skipped+1)) - continue - fi - if [ "$mode" = "unshare" ] && [ "$HAVE_UNSHARE" != "yes" ]; then - echo "HAVE_UNSHARE != yes -- Skipping test..." >&2 - skipped=$((skipped+1)) - continue - fi - if [ "$mode" = "proot" ] && [ "$HAVE_PROOT" != "yes" ]; then - echo "HAVE_PROOT != yes -- Skipping test..." >&2 - skipped=$((skipped+1)) - continue - fi - cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -if [ "\$(id -u)" -eq 0 ] && ! id -u user > /dev/null 2>&1; then - if [ ! -e /mmdebstrap-testenv ]; then - echo "this test modifies the system and should only be run inside a container" >&2 - exit 1 - fi - adduser --gecos user --disabled-password user -fi -if [ "$mode" = unshare ]; then - if [ ! -e /mmdebstrap-testenv ]; then - echo "this test modifies the system and should only be run inside a container" >&2 - exit 1 - fi - sysctl -w kernel.unprivileged_userns_clone=1 -fi -prefix= -[ "\$(id -u)" -eq 0 ] && [ "$mode" != "root" ] && prefix="runuser -u user --" -[ "$mode" = "fakechroot" ] && prefix="\$prefix fakechroot fakeroot" -\$prefix $CMD --mode=$mode --variant=apt --architectures=arm64 $DEFAULT_DIST /tmp/debian-chroot.tar $mirror -# we ignore differences between architectures by ignoring some files -# and renaming others -# in proot mode, some extra files are put there by proot -{ tar -tf /tmp/debian-chroot.tar \ - | grep -v '^\./lib/ld-linux-aarch64\.so\.1$' \ - | grep -v '^\./lib/aarch64-linux-gnu/ld-linux-aarch64\.so\.1$' \ - | grep -v '^\./usr/share/doc/[^/]\+/changelog\(\.Debian\)\?\.arm64\.gz$' \ - | sed 's/aarch64-linux-gnu/x86_64-linux-gnu/' \ - | sed 's/arm64/amd64/'; -} | sort > tar2.txt -{ cat tar1.txt \ - | grep -v '^\./usr/bin/i386$' \ - | grep -v '^\./usr/bin/x86_64$' \ - | grep -v '^\./lib64/$' \ - | grep -v '^\./lib64/ld-linux-x86-64\.so\.2$' \ - | grep -v '^\./lib/x86_64-linux-gnu/ld-linux-x86-64\.so\.2$' \ - | grep -v '^\./lib/x86_64-linux-gnu/libmvec-2\.[0-9]\+\.so$' \ - | grep -v '^\./lib/x86_64-linux-gnu/libmvec\.so\.1$' \ - | grep -v '^\./usr/share/doc/[^/]\+/changelog\(\.Debian\)\?\.amd64\.gz$' \ - | grep -v '^\./usr/share/man/man8/i386\.8\.gz$' \ - | grep -v '^\./usr/share/man/man8/x86_64\.8\.gz$'; - [ "$mode" = "proot" ] && printf "./etc/ld.so.preload\n"; -} | sort | diff -u - tar2.txt -rm /tmp/debian-chroot.tar -END - if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) - elif [ "$mode" = "root" ]; then - ./run_null.sh SUDO - runtests=$((runtests+1)) - else - ./run_null.sh - runtests=$((runtests+1)) - fi -done - -print_header "mode=$defaultmode,variant=apt: test ubuntu focal" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -if ! /usr/lib/apt/apt-helper download-file http://archive.ubuntu.com/ubuntu/dists/focal/Release /dev/null && grep "QEMU Virtual CPU" /proc/cpuinfo; then - if [ ! -e /mmdebstrap-testenv ]; then - echo "this test modifies the system and should only be run inside a container" >&2 - exit 1 - fi - ip link set dev ens3 up - ip addr add 10.0.2.15/24 dev ens3 - ip route add default via 10.0.2.2 dev ens3 - echo "nameserver 10.0.2.3" > /etc/resolv.conf -fi -$CMD --mode=$defaultmode --variant=apt --customize-hook='grep UBUNTU_CODENAME=focal "\$1/etc/os-release"' focal /dev/null -END -if [ "$ONLINE" = "yes" ]; then - if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - runtests=$((runtests+1)) - elif [ "$defaultmode" = "root" ]; then - ./run_null.sh SUDO - runtests=$((runtests+1)) - else - ./run_null.sh - runtests=$((runtests+1)) - fi -else - echo "ONLINE != yes -- Skipping test..." >&2 - skipped=$((skipped+1)) -fi - - -if [ -e shared/cover_db.img ]; then - # produce report inside the VM to make sure that the versions match or - # otherwise we might get: - # Can't read shared/cover_db/runs/1598213854.252.64287/cover.14 with Sereal: Sereal: Error: Bad Sereal header: Not a valid Sereal document. at offset 1 of input at srl_decoder.c line 600 at /usr/lib/x86_64-linux-gnu/perl5/5.30/Devel/Cover/DB/IO/Sereal.pm line 34, <$fh> chunk 1. - cat << END > shared/test.sh -cover -nogcov -report html_basic cover_db >&2 -mkdir -p report -for f in common.js coverage.html cover.css css.js mmdebstrap--branch.html mmdebstrap--condition.html mmdebstrap.html mmdebstrap--subroutine.html standardista-table-sorting.js; do - cp -a cover_db/\$f report -done -cover -delete cover_db >&2 -END - if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh - elif [ "$mode" = "root" ]; then + elif [ "$mode" = "root" ]; then ./run_null.sh SUDO else ./run_null.sh @@ -3777,22 +188,4 @@ END echo fi -if [ "$((i-1))" -ne "$total" ]; then - echo "unexpected number of tests: got $((i-1)) but expected $total" >&2 - exit 1 -fi - -if [ "$skipped" -gt 0 ]; then - echo "number of skipped tests: $skipped" >&2 -fi - -if [ "$runtests" -gt 0 ]; then - echo "number of executed tests: $runtests" >&2 -fi - -if [ "$((skipped+runtests))" -ne "$total" ]; then - echo "sum of skipped and executed tests is not equal to $total" >&2 - exit 1 -fi - rm shared/test.sh shared/tar1.txt shared/tar2.txt shared/pkglist.txt shared/doc-debian.tar.list shared/mmdebstrap shared/taridshift shared/tarfilter shared/proxysolver diff --git a/coverage.txt b/coverage.txt new file mode 100644 index 0000000..dfc7a87 --- /dev/null +++ b/coverage.txt @@ -0,0 +1,314 @@ +Test: check-against-debootstrap-dist +Dists: any +Variants: minbase buildd - +Needs-Root: true + +Test: as-debootstrap-unshare-wrapper +Needs-QEMU: true + +Test: help + +Test: man + +Test: version + +Test: create-directory +Needs-Root: true + +Test: unshare-as-root-user +Needs-Root: true + +Test: dist-using-codename +Dists: any + +Test: fail-without-etc-subuid +Needs-QEMU: true + +Test: fail-without-username-in-etc-subuid +Needs-QEMU: true + +Test: unshare-as-root-user-inside-chroot +Needs-Root: true + +Test: root-mode-inside-chroot +Needs-Root: true + +Test: root-mode-inside-unshare-chroot +Needs-QEMU: true + +Test: root-without-cap-sys-admin +Needs-Root: true + +Test: mount-is-missing +Needs-QEMU: true + +Test: check-for-bit-by-bit-identical-format-output +Needs-QEMU: true +Formats: tar squashfs ext2 +Variants: essential apt minbase buildd important standard +Skip-If: + variant == "standard" and dist in ["oldstable", "stable"] # #864082, #1004557, #1004558 + variant == "important" and dist == "oldstable" # /var/lib/systemd/catalog/database differs + fmt == "squashfs" and dist == "oldstable" # squashfs-tools-ng is not available + fmt == "ext2" and dist == "oldstable" # genext2fs does not support SOURCE_DATE_EPOCH + +Test: taridshift-utility +Needs-QEMU: true +Skip-If: dist == "oldstable" # python3 tarfile module does not preserve xattrs + +Test: progress-bars-on-fake-tty + +Test: debug-output-on-fake-tty + +Test: existing-empty-directory +Needs-Root: true + +Test: existing-directory-with-lost-found +Needs-Root: true + +Test: fail-installing-to-non-empty-lost-found + +Test: fail-installing-to-non-empty-target-directory + +Test: missing-device-nodes-outside-the-chroot +Needs-QEMU: true + +Test: missing-dev-sys-proc-inside-the-chroot +Needs-QEMU: true + +Test: chroot-directory-not-accessible-by-apt-user +Needs-Root: true + +Test: cwd-directory-not-accessible-by-unshared-user +Needs-QEMU: true + +Test: create-gzip-compressed-tarball +Needs-QEMU: true + +Test: custom-tmpdir +Needs-QEMU: true + +Test: xz-compressed-tarball + +Test: directory-ending-in-tar +Modes: root +Needs-Root: true + +Test: auto-mode-without-unshare-capabilities +Needs-QEMU: true + +Test: fail-with-missing-lz4 + +Test: fail-with-path-with-quotes + +Test: create-tarball-with-tmp-mounted-nodev +Needs-QEMU: true + +Test: read-from-stdin-write-to-stdout + +Test: supply-components-manually +Modes: root +Needs-Root: true + +Test: stable-default-mirror +Needs-QEMU: true + +Test: pass-distribution-but-implicitly-write-to-stdout +Needs-QEMU: true + +Test: aspcud-apt-solver + +Test: mirror-is-stdin + +Test: copy-mirror +Needs-QEMU: true + +Test: file-mirror +Needs-QEMU: true + +Test: file-mirror-automount-hook +Needs-QEMU: true + +Test: mirror-is-deb + +Test: mirror-is-real-file + +Test: deb822-1-2 +Modes: root +Needs-Root: true + +Test: deb822-2-2 +Modes: root +Needs-Root: true + +Test: automatic-mirror-from-suite +Needs-QEMU: true + +Test: invalid-mirror + +Test: fail-installing-to-root +Modes: root +Needs-Root: true + +Test: fail-installing-to-existing-file +Modes: root +Needs-Root: true + +Test: arm64-without-qemu-support +Needs-QEMU: true +Skip-If: hostarch != "amd64" + +Test: i386-which-can-be-executed-without-qemu +Needs-QEMU: true +Skip-If: + hostarch != "amd64" + not run_ma_same_tests + +Test: include-libmagic-mgc-arm64 +Needs-Root: true +Skip-If: + hostarch != "amd64" + not run_ma_same_tests + +Test: include-libmagic-mgc-arm64-with-multiple-arch-options +Needs-Root: true +Skip-If: + hostarch != "amd64" + not run_ma_same_tests + +Test: aptopt +Needs-Root: true + +Test: keyring +Needs-QEMU: true + +Test: keyring-overwrites +Needs-Root: true + +Test: signed-by-without-host-keys +Needs-QEMU: true + +Test: ascii-armored-keys +Needs-QEMU: true + +Test: signed-by-with-host-keys +Needs-Root: true + +Test: dpkgopt +Needs-Root: true + +Test: include +Needs-Root: true + +Test: multiple-include +Needs-Root: true + +Test: include-with-multiple-apt-sources +Needs-Root: true + +Test: merged-usr-via-setup-hook +Needs-Root: true + +Test: essential-hook +Needs-Root: true + +Test: customize-hook +Needs-Root: true + +Test: failing-customize-hook +Needs-Root: true + +Test: sigint-during-customize-hook +Needs-Root: true + +Test: hook-directory +Needs-Root: true + +Test: eatmydata-via-hook-dir +Needs-Root: true + +Test: special-hooks-using-helpers +Needs-Root: true + +Test: special-hooks-using-helpers-and-env-vars +Needs-Root: true + +Test: special-hooks-with-mode-mode +Modes: root unshare fakechroot +Needs-QEMU: true + +Test: debootstrap-no-op-options +Needs-Root: true + +Test: verbose +Needs-Root: true + +Test: debug +Needs-Root: true + +Test: quiet +Needs-Root: true + +Test: logfile +Needs-Root: true + +Test: without-etc-resolv-conf-and-etc-hostname +Needs-QEMU: true + +Test: preserve-mode-of-etc-resolv-conf-and-etc-hostname +Modes: root +Needs-QEMU: true + +Test: not-having-to-install-apt-in-include-because-a-hook-did-it-before + +Test: remove-start-stop-daemon-and-policy-rc-d-in-hook + +Test: compare-output-with-pre-seeded-var-cache-apt-archives +Needs-QEMU: true +Variants: any +Skip-If: + variant == "standard" and dist in ["oldstable", "stable"] # #864082, #1004557, #1004558 + variant == "important" and dist == "oldstable" # /var/lib/systemd/catalog/database differs + +Test: create-tarball-dry-run +Variants: any +Modes: any + +Test: unpack-doc-debian +Needs-QEMU: true +Modes: any +Variants: extract + +Test: install-doc-debian +Modes: chrootless +Variants: custom + +Test: install-known-good-from-essential-yes +Variants: custom +Modes: chrootless +Skip-If: + True # #1006692 + dist in ["oldstable", "stable"] + +Test: install-doc-debian-and-output-tarball +Variants: custom +Modes: chrootless + +Test: install-doc-debian-and-test-hooks +Variants: custom +Modes: chrootless + +Test: install-libmagic-mgc-on-arm64 +Skip-If: + hostarch != "amd64" + not have_binfmt + +Test: install-busybox-based-sub-essential-system +Needs-Root: true + +Test: create-arm64-tarball +Modes: root unshare fakechroot +Skip-If: + hostarch != "amd64" + mode == "fakechroot" and not run_ma_same_tests + not have_binfmt diff --git a/tests/aptopt b/tests/aptopt new file mode 100644 index 0000000..c757c30 --- /dev/null +++ b/tests/aptopt @@ -0,0 +1,9 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rm -rf /tmp/debian-chroot; rm -f /tmp/config" EXIT INT TERM +echo 'Acquire::Languages "none";' > /tmp/config +{{ CMD }} --mode=root --variant=apt --aptopt='Acquire::Check-Valid-Until "false"' --aptopt=/tmp/config {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +printf 'Acquire::Check-Valid-Until "false";\nAcquire::Languages "none";\n' | cmp /tmp/debian-chroot/etc/apt/apt.conf.d/99mmdebstrap - +rm /tmp/debian-chroot/etc/apt/apt.conf.d/99mmdebstrap +tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - diff --git a/tests/arm64-without-qemu-support b/tests/arm64-without-qemu-support new file mode 100644 index 0000000..2024a43 --- /dev/null +++ b/tests/arm64-without-qemu-support @@ -0,0 +1,14 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 +fi +apt-get remove --yes qemu-user-static binfmt-support qemu-user +ret=0 +{{ CMD }} --mode={{ MODE }} --variant=apt --architectures=arm64 {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }} || ret=$? +if [ "$ret" = 0 ]; then + echo expected failure but got exit $ret >&2 + exit 1 +fi diff --git a/tests/as-debootstrap-unshare-wrapper b/tests/as-debootstrap-unshare-wrapper new file mode 100644 index 0000000..8f61171 --- /dev/null +++ b/tests/as-debootstrap-unshare-wrapper @@ -0,0 +1,71 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +export SOURCE_DATE_EPOCH={{ SOURCE_DATE_EPOCH }} +if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 +fi +sysctl -w kernel.unprivileged_userns_clone=1 +adduser --gecos user --disabled-password user +runuser -u user -- {{ CMD }} --variant=custom --mode=unshare --setup-hook='env container=lxc debootstrap --no-merged-usr unstable "$1" {{ MIRROR }}' - /tmp/debian-mm.tar {{ MIRROR }} + +mkdir /tmp/debian-mm +tar --xattrs --xattrs-include='*' -C /tmp/debian-mm -xf /tmp/debian-mm.tar + +mkdir /tmp/debian-debootstrap +tar --xattrs --xattrs-include='*' -C /tmp/debian-debootstrap -xf "cache/debian-unstable--.tar" + +# diff cannot compare device nodes, so we use tar to do that for us and then +# delete the directory +tar -C /tmp/debian-debootstrap -cf dev1.tar ./dev +tar -C /tmp/debian-mm -cf dev2.tar ./dev +cmp dev1.tar dev2.tar +rm dev1.tar dev2.tar +rm -r /tmp/debian-debootstrap/dev /tmp/debian-mm/dev + +# remove downloaded deb packages +rm /tmp/debian-debootstrap/var/cache/apt/archives/*.deb +# remove aux-cache +rm /tmp/debian-debootstrap/var/cache/ldconfig/aux-cache +# remove logs +rm /tmp/debian-debootstrap/var/log/dpkg.log \ + /tmp/debian-debootstrap/var/log/bootstrap.log \ + /tmp/debian-debootstrap/var/log/alternatives.log \ + /tmp/debian-mm/var/log/bootstrap.log + +# debootstrap doesn't clean apt +rm /tmp/debian-debootstrap/var/lib/apt/lists/127.0.0.1_debian_dists_unstable_main_binary-{{ HOSTARCH }}_Packages \ + /tmp/debian-debootstrap/var/lib/apt/lists/127.0.0.1_debian_dists_unstable_Release \ + /tmp/debian-debootstrap/var/lib/apt/lists/127.0.0.1_debian_dists_unstable_Release.gpg + +rm /tmp/debian-debootstrap/etc/machine-id /tmp/debian-mm/etc/machine-id +rm /tmp/debian-mm/var/cache/apt/archives/lock +rm /tmp/debian-mm/var/lib/apt/lists/lock + +# check if the file content differs +diff --no-dereference --recursive /tmp/debian-debootstrap /tmp/debian-mm + +# check permissions, ownership, symlink targets, modification times using tar +# mtimes of directories created by mmdebstrap will differ, thus we equalize them first +for d in etc/apt/preferences.d/ etc/apt/sources.list.d/ etc/dpkg/dpkg.cfg.d/ var/log/apt/; do + touch --date="@{{ SOURCE_DATE_EPOCH }}" /tmp/debian-debootstrap/$d /tmp/debian-mm/$d +done +# debootstrap never ran apt -- fixing permissions +for d in ./var/lib/apt/lists/partial ./var/cache/apt/archives/partial; do + chroot /tmp/debian-debootstrap chmod 0700 $d + chroot /tmp/debian-debootstrap chown _apt:root $d +done +tar -C /tmp/debian-debootstrap --numeric-owner --xattrs --xattrs-include='*' --sort=name --clamp-mtime --mtime=$(date --utc --date=@{{ SOURCE_DATE_EPOCH }} --iso-8601=seconds) -cf /tmp/root1.tar . +tar -C /tmp/debian-mm --numeric-owner --xattrs --xattrs-include='*' --sort=name --clamp-mtime --mtime=$(date --utc --date=@{{ SOURCE_DATE_EPOCH }} --iso-8601=seconds) -cf /tmp/root2.tar . +tar --full-time --verbose -tf /tmp/root1.tar > /tmp/root1.tar.list +tar --full-time --verbose -tf /tmp/root2.tar > /tmp/root2.tar.list +# despite SOURCE_DATE_EPOCH and --clamp-mtime, the timestamps in the tarball +# will slightly differ from each other in the sub-second precision (last +# decimals) so the tarballs will not be identical, so we use diff to compare +# content and tar to compare attributes +diff -u /tmp/root1.tar.list /tmp/root2.tar.list +rm /tmp/root1.tar /tmp/root2.tar /tmp/root1.tar.list /tmp/root2.tar.list + +rm /tmp/debian-mm.tar +rm -r /tmp/debian-debootstrap /tmp/debian-mm diff --git a/tests/ascii-armored-keys b/tests/ascii-armored-keys new file mode 100644 index 0000000..70a45cc --- /dev/null +++ b/tests/ascii-armored-keys @@ -0,0 +1,18 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 +fi +for f in /usr/share/keyrings/*.gpg; do + name=$(basename "$f" .gpg) + gpg --enarmor < /usr/share/keyrings/$name.gpg \ + | sed 's/ PGP ARMORED FILE/ PGP PUBLIC KEY BLOCK/;/^Comment: /d' \ + > /etc/apt/trusted.gpg.d/$name.asc +done +rm /etc/apt/trusted.gpg.d/*.gpg +rm /usr/share/keyrings/*.gpg +{{ CMD }} --mode=root --variant=apt {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }} +tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - +rm -r /tmp/debian-chroot.tar diff --git a/tests/aspcud-apt-solver b/tests/aspcud-apt-solver new file mode 100644 index 0000000..ec5689c --- /dev/null +++ b/tests/aspcud-apt-solver @@ -0,0 +1,11 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rm -f /tmp/debian-chroot.tar" EXIT INT TERM +{{ CMD }} --mode={{ MODE }} --variant=custom \ + --include $(cat pkglist.txt | tr '\n' ',') \ + --aptopt='APT::Solver "aspcud"' \ + {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }} +tar -tf /tmp/debian-chroot.tar | sort \ + | grep -v '^./etc/apt/apt.conf.d/99mmdebstrap$' \ + | diff -u tar1.txt - diff --git a/tests/auto-mode-without-unshare-capabilities b/tests/auto-mode-without-unshare-capabilities new file mode 100644 index 0000000..eb4cf76 --- /dev/null +++ b/tests/auto-mode-without-unshare-capabilities @@ -0,0 +1,12 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 +fi +adduser --gecos user --disabled-password user +sysctl -w kernel.unprivileged_userns_clone=0 +runuser -u user -- {{ CMD }} --mode=auto --variant=apt {{ DIST }} /tmp/debian-chroot.tar.gz {{ MIRROR }} +tar -tf /tmp/debian-chroot.tar.gz | sort | diff -u tar1.txt - +rm /tmp/debian-chroot.tar.gz diff --git a/tests/automatic-mirror-from-suite b/tests/automatic-mirror-from-suite new file mode 100644 index 0000000..7cff5a6 --- /dev/null +++ b/tests/automatic-mirror-from-suite @@ -0,0 +1,14 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 +fi +cat << HOSTS >> /etc/hosts +127.0.0.1 deb.debian.org +127.0.0.1 security.debian.org +HOSTS +{{ CMD }} --mode={{ MODE }} --variant=apt {{ DIST }} /tmp/debian-chroot.tar +tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - +rm /tmp/debian-chroot.tar diff --git a/tests/check-against-debootstrap-dist b/tests/check-against-debootstrap-dist new file mode 100644 index 0000000..2bdaa30 --- /dev/null +++ b/tests/check-against-debootstrap-dist @@ -0,0 +1,196 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +export SOURCE_DATE_EPOCH={{ SOURCE_DATE_EPOCH }} + +# we create the apt user ourselves or otherwise its uid/gid will differ +# compared to the one chosen in debootstrap because of different installation +# order in comparison to the systemd users +# https://bugs.debian.org/969631 +# we cannot use useradd because passwd is not Essential:yes +{{ CMD }} --variant={{ VARIANT }} --mode={{ MODE }} \ + --essential-hook='if [ {{ VARIANT }} = - ]; then echo _apt:*:100:65534::/nonexistent:/usr/sbin/nologin >> "$1"/etc/passwd; fi' \ + {{ DIST }} /tmp/debian-{{ DIST }}-mm.tar {{ MIRROR }} + +mkdir /tmp/debian-{{ DIST }}-mm +tar --xattrs --xattrs-include='*' -C /tmp/debian-{{ DIST }}-mm -xf /tmp/debian-{{ DIST }}-mm.tar +rm /tmp/debian-{{ DIST }}-mm.tar + +mkdir /tmp/debian-{{ DIST }}-debootstrap +tar --xattrs --xattrs-include='*' -C /tmp/debian-{{ DIST }}-debootstrap -xf "cache/debian-{{ DIST }}-{{ VARIANT }}.tar" + +# diff cannot compare device nodes, so we use tar to do that for us and then +# delete the directory +tar -C /tmp/debian-{{ DIST }}-debootstrap -cf dev1.tar ./dev +tar -C /tmp/debian-{{ DIST }}-mm -cf dev2.tar ./dev +ret=0 +cmp dev1.tar dev2.tar || ret=$? +if [ "$ret" -ne 0 ]; then + if type diffoscope >/dev/null; then + diffoscope dev1.tar dev2.tar + exit 1 + else + echo "no diffoscope installed" >&2 + fi + if type base64 >/dev/null; then + base64 dev1.tar + base64 dev2.tar + exit 1 + else + echo "no base64 installed" >&2 + fi + if type xxd >/dev/null; then + xxd dev1.tar + xxd dev2.tar + exit 1 + else + echo "no xxd installed" >&2 + fi + exit 1 +fi +rm dev1.tar dev2.tar +rm -r /tmp/debian-{{ DIST }}-debootstrap/dev /tmp/debian-{{ DIST }}-mm/dev + +# remove downloaded deb packages +rm /tmp/debian-{{ DIST }}-debootstrap/var/cache/apt/archives/*.deb +# remove aux-cache +rm /tmp/debian-{{ DIST }}-debootstrap/var/cache/ldconfig/aux-cache +# remove logs +rm /tmp/debian-{{ DIST }}-debootstrap/var/log/dpkg.log \ + /tmp/debian-{{ DIST }}-debootstrap/var/log/bootstrap.log \ + /tmp/debian-{{ DIST }}-debootstrap/var/log/alternatives.log +# remove *-old files +rm /tmp/debian-{{ DIST }}-debootstrap/var/cache/debconf/config.dat-old \ + /tmp/debian-{{ DIST }}-mm/var/cache/debconf/config.dat-old +rm /tmp/debian-{{ DIST }}-debootstrap/var/cache/debconf/templates.dat-old \ + /tmp/debian-{{ DIST }}-mm/var/cache/debconf/templates.dat-old +rm /tmp/debian-{{ DIST }}-debootstrap/var/lib/dpkg/status-old \ + /tmp/debian-{{ DIST }}-mm/var/lib/dpkg/status-old +# remove dpkg files +rm /tmp/debian-{{ DIST }}-debootstrap/var/lib/dpkg/available +rm /tmp/debian-{{ DIST }}-debootstrap/var/lib/dpkg/cmethopt +# since we installed packages directly from the .deb files, Priorities differ +# thus we first check for equality and then remove the files +chroot /tmp/debian-{{ DIST }}-debootstrap dpkg --list > dpkg1 +chroot /tmp/debian-{{ DIST }}-mm dpkg --list > dpkg2 +diff -u dpkg1 dpkg2 +rm dpkg1 dpkg2 +grep -v '^Priority: ' /tmp/debian-{{ DIST }}-debootstrap/var/lib/dpkg/status > status1 +grep -v '^Priority: ' /tmp/debian-{{ DIST }}-mm/var/lib/dpkg/status > status2 +diff -u status1 status2 +rm status1 status2 +rm /tmp/debian-{{ DIST }}-debootstrap/var/lib/dpkg/status /tmp/debian-{{ DIST }}-mm/var/lib/dpkg/status +# debootstrap exposes the hosts's kernel version +if [ -e /tmp/debian-{{ DIST }}-debootstrap/etc/apt/apt.conf.d/01autoremove-kernels ]; then + rm /tmp/debian-{{ DIST }}-debootstrap/etc/apt/apt.conf.d/01autoremove-kernels +fi +if [ -e /tmp/debian-{{ DIST }}-mm/etc/apt/apt.conf.d/01autoremove-kernels ]; then + rm /tmp/debian-{{ DIST }}-mm/etc/apt/apt.conf.d/01autoremove-kernels +fi +# who creates /run/mount? +if [ -e "/tmp/debian-{{ DIST }}-debootstrap/run/mount/utab" ]; then + rm "/tmp/debian-{{ DIST }}-debootstrap/run/mount/utab" +fi +if [ -e "/tmp/debian-{{ DIST }}-debootstrap/run/mount" ]; then + rmdir "/tmp/debian-{{ DIST }}-debootstrap/run/mount" +fi +# debootstrap doesn't clean apt +rm /tmp/debian-{{ DIST }}-debootstrap/var/lib/apt/lists/127.0.0.1_debian_dists_{{ DIST }}_main_binary-{{ HOSTARCH }}_Packages \ + /tmp/debian-{{ DIST }}-debootstrap/var/lib/apt/lists/127.0.0.1_debian_dists_{{ DIST }}_Release \ + /tmp/debian-{{ DIST }}-debootstrap/var/lib/apt/lists/127.0.0.1_debian_dists_{{ DIST }}_Release.gpg + +if [ "{{ VARIANT }}" = "-" ]; then + rm /tmp/debian-{{ DIST }}-debootstrap/etc/machine-id + rm /tmp/debian-{{ DIST }}-mm/etc/machine-id + rm /tmp/debian-{{ DIST }}-debootstrap/var/lib/systemd/catalog/database + rm /tmp/debian-{{ DIST }}-mm/var/lib/systemd/catalog/database + + cap=$(chroot /tmp/debian-{{ DIST }}-debootstrap /sbin/getcap /bin/ping) + expected="/bin/ping cap_net_raw=ep" + if [ "{{ DIST }}" = oldstable ]; then + expected="/bin/ping = cap_net_raw+ep" + fi + if [ "$cap" != "$expected" ]; then + echo "expected bin/ping to have capabilities $expected" >&2 + echo "but debootstrap produced: $cap" >&2 + exit 1 + fi + cap=$(chroot /tmp/debian-{{ DIST }}-mm /sbin/getcap /bin/ping) + if [ "$cap" != "$expected" ]; then + echo "expected bin/ping to have capabilities $expected" >&2 + echo "but mmdebstrap produced: $cap" >&2 + exit 1 + fi +fi +rm /tmp/debian-{{ DIST }}-mm/var/cache/apt/archives/lock +rm /tmp/debian-{{ DIST }}-mm/var/lib/apt/extended_states +rm /tmp/debian-{{ DIST }}-mm/var/lib/apt/lists/lock + +# the list of shells might be sorted wrongly +for f in "/tmp/debian-{{ DIST }}-debootstrap/etc/shells" "/tmp/debian-{{ DIST }}-mm/etc/shells"; do + sort -o "$f" "$f" +done + +# Because of unreproducible uids (#969631) we created the _apt user ourselves +# and because passwd is not Essential:yes we didn't use useradd. But newer +# versions of adduser and shadow will create a different /etc/shadow +for f in shadow shadow-; do + if grep -q '^_apt:!:' /tmp/debian-{{ DIST }}-debootstrap/etc/$f; then + sed -i 's/^_apt:\*:\([^:]\+\):0:99999:7:::$/_apt:!:\1::::::/' /tmp/debian-{{ DIST }}-mm/etc/$f + fi +done + +# workaround for https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=917773 +if ! cmp /tmp/debian-{{ DIST }}-debootstrap/etc/shadow /tmp/debian-{{ DIST }}-mm/etc/shadow; then + echo patching /etc/shadow on {{ DIST }} {{ VARIANT }} >&2 + awk -v FS=: -v OFS=: -v SDE={{ SOURCE_DATE_EPOCH }} '{ print $1,$2,int(SDE/60/60/24),$4,$5,$6,$7,$8,$9 }' < /tmp/debian-{{ DIST }}-mm/etc/shadow > /tmp/debian-{{ DIST }}-mm/etc/shadow.bak + cat /tmp/debian-{{ DIST }}-mm/etc/shadow.bak > /tmp/debian-{{ DIST }}-mm/etc/shadow + rm /tmp/debian-{{ DIST }}-mm/etc/shadow.bak +else + echo no difference for /etc/shadow on {{ DIST }} {{ VARIANT }} >&2 +fi +if ! cmp /tmp/debian-{{ DIST }}-debootstrap/etc/shadow- /tmp/debian-{{ DIST }}-mm/etc/shadow-; then + echo patching /etc/shadow- on {{ DIST }} {{ VARIANT }} >&2 + awk -v FS=: -v OFS=: -v SDE={{ SOURCE_DATE_EPOCH }} '{ print $1,$2,int(SDE/60/60/24),$4,$5,$6,$7,$8,$9 }' < /tmp/debian-{{ DIST }}-mm/etc/shadow- > /tmp/debian-{{ DIST }}-mm/etc/shadow-.bak + cat /tmp/debian-{{ DIST }}-mm/etc/shadow-.bak > /tmp/debian-{{ DIST }}-mm/etc/shadow- + rm /tmp/debian-{{ DIST }}-mm/etc/shadow-.bak +else + echo no difference for /etc/shadow- on {{ DIST }} {{ VARIANT }} >&2 +fi + +# Because of unreproducible uids (#969631) we created the _apt user ourselves +# and because passwd is not Essential:yes we didn't use useradd. But passwd +# since 1:4.11.1+dfsg1-1 will create empty mail files, so we create it too. +# https://bugs.debian.org/1004710 +if [ {{ VARIANT }} = - ]; then + if [ -e /tmp/debian-{{ DIST }}-debootstrap/var/mail/_apt ]; then + touch /tmp/debian-{{ DIST }}-mm/var/mail/_apt + chmod 660 /tmp/debian-{{ DIST }}-mm/var/mail/_apt + chown 100:8 /tmp/debian-{{ DIST }}-mm/var/mail/_apt + fi +fi + +# check if the file content differs +diff --unified --no-dereference --recursive /tmp/debian-{{ DIST }}-debootstrap /tmp/debian-{{ DIST }}-mm >&2 + +# check permissions, ownership, symlink targets, modification times using tar +# directory mtimes will differ, thus we equalize them first +find /tmp/debian-{{ DIST }}-debootstrap /tmp/debian-{{ DIST }}-mm -type d -print0 | xargs -0 touch --date="@{{ SOURCE_DATE_EPOCH }}" +# debootstrap never ran apt -- fixing permissions +for d in ./var/lib/apt/lists/partial ./var/cache/apt/archives/partial; do + chroot /tmp/debian-{{ DIST }}-debootstrap chmod 0700 $d + chroot /tmp/debian-{{ DIST }}-debootstrap chown _apt:root $d +done +tar -C /tmp/debian-{{ DIST }}-debootstrap --numeric-owner --sort=name --clamp-mtime --mtime=$(date --utc --date=@{{ SOURCE_DATE_EPOCH }} --iso-8601=seconds) -cf /tmp/root1.tar . +tar -C /tmp/debian-{{ DIST }}-mm --numeric-owner --sort=name --clamp-mtime --mtime=$(date --utc --date=@{{ SOURCE_DATE_EPOCH }} --iso-8601=seconds) -cf /tmp/root2.tar . +tar --full-time --verbose -tf /tmp/root1.tar > /tmp/root1.tar.list +tar --full-time --verbose -tf /tmp/root2.tar > /tmp/root2.tar.list +diff -u /tmp/root1.tar.list /tmp/root2.tar.list +rm /tmp/root1.tar /tmp/root2.tar /tmp/root1.tar.list /tmp/root2.tar.list + +# check if file properties (permissions, ownership, symlink names, modification time) differ +# +# we cannot use this (yet) because it cannot cope with paths that have [ or @ in them +#fmtree -c -p /tmp/debian-{{ DIST }}-debootstrap -k flags,gid,link,mode,size,time,uid | sudo fmtree -p /tmp/debian-{{ DIST }}-mm + +rm -r /tmp/debian-{{ DIST }}-debootstrap /tmp/debian-{{ DIST }}-mm diff --git a/tests/check-for-bit-by-bit-identical-format-output b/tests/check-for-bit-by-bit-identical-format-output new file mode 100644 index 0000000..2eff00c --- /dev/null +++ b/tests/check-for-bit-by-bit-identical-format-output @@ -0,0 +1,35 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 +fi +adduser --gecos user --disabled-password user +sysctl -w kernel.unprivileged_userns_clone=1 +export SOURCE_DATE_EPOCH={{ SOURCE_DATE_EPOCH }} +mount -o size=4G -t tmpfs tmpfs /tmp # workaround for #1010957 +{{ CMD }} --mode=root --variant={{ VARIANT }} {{ DIST }} /tmp/debian-chroot-root.{{ FORMAT }} {{ MIRROR }} +if [ "{{ FORMAT }}" = tar ]; then + printf 'ustar ' | cmp --bytes=6 --ignore-initial=257:0 /tmp/debian-chroot-root.tar - +elif [ "{{ FORMAT }}" = squashfs ]; then + printf 'hsqs' | cmp --bytes=4 /tmp/debian-chroot-root.squashfs - +elif [ "{{ FORMAT }}" = ext2 ]; then + printf '\123\357' | cmp --bytes=2 --ignore-initial=1080:0 /tmp/debian-chroot-root.ext2 - +else + echo "unknown format: {{ FORMAT }}" >&2 + exit 1 +fi +runuser -u user -- {{ CMD }} --mode=unshare --variant={{ VARIANT }} {{ DIST }} /tmp/debian-chroot-unshare.{{ FORMAT }} {{ MIRROR }} +cmp /tmp/debian-chroot-root.{{ FORMAT }} /tmp/debian-chroot-unshare.{{ FORMAT }} +rm /tmp/debian-chroot-unshare.{{ FORMAT }} +case {{ VARIANT }} in essential|apt|minbase|buildd) + # variants important and standard differ because permissions drwxr-sr-x + # and extended attributes of ./var/log/journal/ cannot be preserved + # in fakechroot mode + runuser -u user -- {{ CMD }} --mode=fakechroot --variant={{ VARIANT }} {{ DIST }} /tmp/debian-chroot-fakechroot.{{ FORMAT }} {{ MIRROR }} + cmp /tmp/debian-chroot-root.{{ FORMAT }} /tmp/debian-chroot-fakechroot.{{ FORMAT }} + rm /tmp/debian-chroot-fakechroot.{{ FORMAT }} + ;; +esac +rm /tmp/debian-chroot-root.{{ FORMAT }} diff --git a/tests/chroot-directory-not-accessible-by-apt-user b/tests/chroot-directory-not-accessible-by-apt-user new file mode 100644 index 0000000..eb2d343 --- /dev/null +++ b/tests/chroot-directory-not-accessible-by-apt-user @@ -0,0 +1,8 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rm -rf /tmp/debian-chroot" EXIT INT TERM +mkdir /tmp/debian-chroot +chmod 700 /tmp/debian-chroot +{{ CMD }} --mode=root --variant=apt {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - diff --git a/tests/compare-output-with-pre-seeded-var-cache-apt-archives b/tests/compare-output-with-pre-seeded-var-cache-apt-archives new file mode 100644 index 0000000..ccf5fa8 --- /dev/null +++ b/tests/compare-output-with-pre-seeded-var-cache-apt-archives @@ -0,0 +1,45 @@ +#!/bin/sh +# +# test that the user can drop archives into /var/cache/apt/archives as well as +# into /var/cache/apt/archives/partial + +set -eu +export LC_ALL=C.UTF-8 +export SOURCE_DATE_EPOCH={{ SOURCE_DATE_EPOCH }} +if [ ! -e /mmdebstrap-testenv ]; then + echo "this test requires the cache directory to be mounted on /mnt and should only be run inside a container" >&2 + exit 1 +fi +include="--include=doc-debian" +if [ "{{ VARIANT }}" = "custom" ]; then + include="$include,base-files,base-passwd,coreutils,dash,diffutils,dpkg,libc-bin,sed" +fi +mount -o size=4G -t tmpfs tmpfs /tmp # workaround for #1010957 +{{ CMD }} $include --mode={{ MODE }} --variant={{ VARIANT }} \ + --setup-hook='mkdir -p "$1"/var/cache/apt/archives/partial' \ + --setup-hook='touch "$1"/var/cache/apt/archives/lock' \ + --setup-hook='chmod 0640 "$1"/var/cache/apt/archives/lock' \ + {{ DIST }} - {{ MIRROR }} > orig.tar +# somehow, when trying to create a tarball from the 9p mount, tar throws the +# following error: tar: ./doc-debian_6.4_all.deb: File shrank by 132942 bytes; padding with zeros +# to reproduce, try: tar --directory /mnt/cache/debian/pool/main/d/doc-debian/ --create --file - . | tar --directory /tmp/ --extract --file - +# this will be different: +# md5sum /mnt/cache/debian/pool/main/d/doc-debian/*.deb /tmp/*.deb +# another reason to copy the files into a new directory is, that we can use shell globs +tmpdir=$(mktemp -d) +cp /mnt/cache/debian/pool/main/b/busybox/busybox_*"_{{ HOSTARCH }}.deb" /mnt/cache/debian/pool/main/a/apt/apt_*"_{{ HOSTARCH }}.deb" "$tmpdir" +{{ CMD }} $include --mode={{ MODE }} --variant={{ VARIANT }} \ + --setup-hook='mkdir -p "$1"/var/cache/apt/archives/partial' \ + --setup-hook='sync-in "'"$tmpdir"'" /var/cache/apt/archives/partial' \ + {{ DIST }} - {{ MIRROR }} > test1.tar +cmp orig.tar test1.tar +{{ CMD }} $include --mode={{ MODE }} --variant={{ VARIANT }} \ + --customize-hook='touch "$1"/var/cache/apt/archives/partial' \ + --setup-hook='mkdir -p "$1"/var/cache/apt/archives/' \ + --setup-hook='sync-in "'"$tmpdir"'" /var/cache/apt/archives/' \ + --setup-hook='chmod 0755 "$1"/var/cache/apt/archives/' \ + --customize-hook='find "'"$tmpdir"'" -type f -exec md5sum "{}" \; | sed "s|"'"$tmpdir"'"|$1/var/cache/apt/archives|" | md5sum --check' \ + {{ DIST }} - {{ MIRROR }} > test2.tar +cmp orig.tar test2.tar +rm "$tmpdir"/*.deb orig.tar test1.tar test2.tar +rmdir "$tmpdir" diff --git a/tests/copy-mirror b/tests/copy-mirror new file mode 100644 index 0000000..1903925 --- /dev/null +++ b/tests/copy-mirror @@ -0,0 +1,10 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +if [ ! -e /mmdebstrap-testenv ]; then + echo "this test requires the cache directory to be mounted on /mnt and should only be run inside a container" >&2 + exit 1 +fi +{{ CMD }} --mode={{ MODE }} --variant=apt {{ DIST }} /tmp/debian-chroot.tar "deb copy:///mnt/cache/debian {{ DIST }} main" +tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - +rm /tmp/debian-chroot.tar diff --git a/tests/create-arm64-tarball b/tests/create-arm64-tarball new file mode 100644 index 0000000..f115206 --- /dev/null +++ b/tests/create-arm64-tarball @@ -0,0 +1,45 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +if [ "$(id -u)" -eq 0 ] && ! id -u user > /dev/null 2>&1; then + if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 + fi + adduser --gecos user --disabled-password user +fi +if [ "{{ MODE }}" = unshare ]; then + if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 + fi + sysctl -w kernel.unprivileged_userns_clone=1 +fi +prefix= +[ "$(id -u)" -eq 0 ] && [ "{{ MODE }}" != "root" ] && prefix="runuser -u user --" +[ "{{ MODE }}" = "fakechroot" ] && prefix="$prefix fakechroot fakeroot" +$prefix {{ CMD }} --mode={{ MODE }} --variant=apt --architectures=arm64 {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }} +# we ignore differences between architectures by ignoring some files +# and renaming others +# in proot mode, some extra files are put there by proot +{ tar -tf /tmp/debian-chroot.tar \ + | grep -v '^\./lib/ld-linux-aarch64\.so\.1$' \ + | grep -v '^\./lib/aarch64-linux-gnu/ld-linux-aarch64\.so\.1$' \ + | grep -v '^\./usr/share/doc/[^/]\+/changelog\(\.Debian\)\?\.arm64\.gz$' \ + | sed 's/aarch64-linux-gnu/x86_64-linux-gnu/' \ + | sed 's/arm64/amd64/'; +} | sort > tar2.txt +{ cat tar1.txt \ + | grep -v '^\./usr/bin/i386$' \ + | grep -v '^\./usr/bin/x86_64$' \ + | grep -v '^\./lib64/$' \ + | grep -v '^\./lib64/ld-linux-x86-64\.so\.2$' \ + | grep -v '^\./lib/x86_64-linux-gnu/ld-linux-x86-64\.so\.2$' \ + | grep -v '^\./lib/x86_64-linux-gnu/libmvec-2\.[0-9]\+\.so$' \ + | grep -v '^\./lib/x86_64-linux-gnu/libmvec\.so\.1$' \ + | grep -v '^\./usr/share/doc/[^/]\+/changelog\(\.Debian\)\?\.amd64\.gz$' \ + | grep -v '^\./usr/share/man/man8/i386\.8\.gz$' \ + | grep -v '^\./usr/share/man/man8/x86_64\.8\.gz$'; + [ "{{ MODE }}" = "proot" ] && printf "./etc/ld.so.preload\n"; +} | sort | diff -u - tar2.txt +rm /tmp/debian-chroot.tar diff --git a/tests/create-directory b/tests/create-directory new file mode 100644 index 0000000..2e60248 --- /dev/null +++ b/tests/create-directory @@ -0,0 +1,7 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +{{ CMD }} --mode=root --variant=apt {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +chroot /tmp/debian-chroot dpkg-query --showformat '${binary:Package}\n' --show > pkglist.txt +tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort > tar1.txt +rm -r /tmp/debian-chroot diff --git a/tests/create-directory-dry-run b/tests/create-directory-dry-run new file mode 100644 index 0000000..56565bd --- /dev/null +++ b/tests/create-directory-dry-run @@ -0,0 +1,43 @@ +cat << END > shared/test.sh +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +{{ CMD }} --mode={{ MODE }} --dry-run --variant=apt --setup-hook="exit 1" --essential-hook="exit 1" --customize-hook="exit 1" {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +rm /tmp/debian-chroot/dev/console +rm /tmp/debian-chroot/dev/fd +rm /tmp/debian-chroot/dev/full +rm /tmp/debian-chroot/dev/null +rm /tmp/debian-chroot/dev/ptmx +rm /tmp/debian-chroot/dev/random +rm /tmp/debian-chroot/dev/stderr +rm /tmp/debian-chroot/dev/stdin +rm /tmp/debian-chroot/dev/stdout +rm /tmp/debian-chroot/dev/tty +rm /tmp/debian-chroot/dev/urandom +rm /tmp/debian-chroot/dev/zero +rm /tmp/debian-chroot/etc/apt/sources.list +rm /tmp/debian-chroot/etc/fstab +rm /tmp/debian-chroot/etc/hostname +rm /tmp/debian-chroot/etc/resolv.conf +rm /tmp/debian-chroot/var/lib/apt/lists/lock +rm /tmp/debian-chroot/var/lib/dpkg/status +# the rest should be empty directories that we can rmdir recursively +find /tmp/debian-chroot -depth -print0 | xargs -0 rmdir +END +if [ "$HAVE_QEMU" = "yes" ]; then + ./run_qemu.sh + runtests=$((runtests+1)) +elif [ "{{ MODE }}" = "root" ]; then + ./run_null.sh SUDO + runtests=$((runtests+1)) +else + ./run_null.sh + runtests=$((runtests+1)) +fi + +# test all --dry-run variants + +# we are testing all variants here because with 0.7.5 we had a bug: +# mmdebstrap sid /dev/null --simulate ==> E: cannot read /var/cache/apt/archives/ +for variant in extract custom essential apt minbase buildd important standard; do + for mode in root unshare fakechroot proot chrootless; do diff --git a/tests/create-gzip-compressed-tarball b/tests/create-gzip-compressed-tarball new file mode 100644 index 0000000..4cb4a7b --- /dev/null +++ b/tests/create-gzip-compressed-tarball @@ -0,0 +1,13 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 +fi +adduser --gecos user --disabled-password user +sysctl -w kernel.unprivileged_userns_clone=1 +runuser -u user -- {{ CMD }} --mode=unshare --variant=apt {{ DIST }} /tmp/debian-chroot.tar.gz {{ MIRROR }} +printf '\037\213\010' | cmp --bytes=3 /tmp/debian-chroot.tar.gz - +tar -tf /tmp/debian-chroot.tar.gz | sort | diff -u tar1.txt - +rm /tmp/debian-chroot.tar.gz diff --git a/tests/create-tarball-dry-run b/tests/create-tarball-dry-run new file mode 100644 index 0000000..783ff47 --- /dev/null +++ b/tests/create-tarball-dry-run @@ -0,0 +1,35 @@ +#!/bin/sh +# +# we are testing all variants here because with 0.7.5 we had a bug: +# mmdebstrap sid /dev/null --simulate ==> E: cannot read /var/cache/apt/archives/ + +set -eu +export LC_ALL=C.UTF-8 +prefix= +include= +if [ "$(id -u)" -eq 0 ] && [ "{{ MODE }}" != root ] && [ "{{ MODE }}" != auto ]; then + # this must be qemu + if ! id -u user >/dev/null 2>&1; then + if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 + fi + adduser --gecos user --disabled-password user + fi + if [ "{{ MODE }}" = unshare ]; then + if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 + fi + sysctl -w kernel.unprivileged_userns_clone=1 + fi + prefix="runuser -u user --" + if [ "{{ MODE }}" = extract ] || [ "{{ MODE }}" = custom ]; then + include="--include=$(cat pkglist.txt | tr '\n' ',')" + fi +fi +$prefix {{ CMD }} --mode={{ MODE }} $include --dry-run --variant={{ VARIANT }} {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }} +if [ -e /tmp/debian-chroot.tar ]; then + echo "/tmp/debian-chroot.tar must not be created with --dry-run" >&2 + exit 1 +fi diff --git a/tests/create-tarball-with-tmp-mounted-nodev b/tests/create-tarball-with-tmp-mounted-nodev new file mode 100644 index 0000000..67bae32 --- /dev/null +++ b/tests/create-tarball-with-tmp-mounted-nodev @@ -0,0 +1,12 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 +fi +mount -t tmpfs -o nodev,nosuid,size=300M tmpfs /tmp +# use --customize-hook to exercise the mounting/unmounting code of block devices in root mode +{{ CMD }} --mode=root --variant=apt --customize-hook='mount | grep /dev/full' --customize-hook='test "$(echo foo | tee /dev/full 2>&1 1>/dev/null)" = "tee: /dev/full: No space left on device"' {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }} +tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - +rm /tmp/debian-chroot.tar diff --git a/tests/custom-tmpdir b/tests/custom-tmpdir new file mode 100644 index 0000000..cf9fe5c --- /dev/null +++ b/tests/custom-tmpdir @@ -0,0 +1,18 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 +fi +adduser --gecos user --disabled-password user +sysctl -w kernel.unprivileged_userns_clone=1 +homedir=$(runuser -u user -- sh -c 'cd && pwd') +runuser -u user -- mkdir "$homedir/tmp" +runuser -u user -- env TMPDIR="$homedir/tmp" {{ CMD }} --mode=unshare --variant=apt \ + --setup-hook='case "$1" in "'"$homedir/tmp/mmdebstrap."'"??????????) exit 0;; *) exit 1;; esac' \ + {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }} +tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - +# use rmdir as a quick check that nothing is remaining in TMPDIR +runuser -u user -- rmdir "$homedir/tmp" +rm /tmp/debian-chroot.tar diff --git a/tests/customize-hook b/tests/customize-hook new file mode 100644 index 0000000..6437eac --- /dev/null +++ b/tests/customize-hook @@ -0,0 +1,16 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rm -rf /tmp/debian-chroot; rm -f /tmp/customize.sh" EXIT INT TERM +cat << 'SCRIPT' > /tmp/customize.sh +#!/bin/sh +chroot "$1" whoami > "$1/output2" +chroot "$1" pwd >> "$1/output2" +SCRIPT +chmod +x /tmp/customize.sh +{{ CMD }} --mode=root --variant=apt --customize-hook='chroot "$1" sh -c "whoami; pwd" > "$1/output1"' --customize-hook=/tmp/customize.sh {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +printf "root\n/\n" | cmp /tmp/debian-chroot/output1 +printf "root\n/\n" | cmp /tmp/debian-chroot/output2 +rm /tmp/debian-chroot/output1 +rm /tmp/debian-chroot/output2 +tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - diff --git a/tests/cwd-directory-not-accessible-by-unshared-user b/tests/cwd-directory-not-accessible-by-unshared-user new file mode 100644 index 0000000..ed0834d --- /dev/null +++ b/tests/cwd-directory-not-accessible-by-unshared-user @@ -0,0 +1,22 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 +fi +adduser --gecos user --disabled-password user +sysctl -w kernel.unprivileged_userns_clone=1 +mkdir /tmp/debian-chroot +chmod 700 /tmp/debian-chroot +chown user:user /tmp/debian-chroot +if [ "{{ CMD }}" = "./mmdebstrap" ]; then + CMD=$(realpath --canonicalize-existing ./mmdebstrap) +elif [ "{{ CMD }}" = "perl -MDevel::Cover=-silent,-nogcov ./mmdebstrap" ]; then + CMD="perl -MDevel::Cover=-silent,-nogcov $(realpath --canonicalize-existing ./mmdebstrap)" +else + CMD="{{ CMD }}" +fi +env --chdir=/tmp/debian-chroot runuser -u user -- $CMD --mode=unshare --variant=apt {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }} +tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - +rm /tmp/debian-chroot.tar diff --git a/tests/deb822-1-2 b/tests/deb822-1-2 new file mode 100644 index 0000000..1459117 --- /dev/null +++ b/tests/deb822-1-2 @@ -0,0 +1,45 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rm -rf /tmp/debian-chroot; rm -f /tmp/sources.list /tmp/deb822.sources" EXIT INT TERM +cat << SOURCES > /tmp/deb822.sources +Types: deb +URIs: {{ MIRROR }}1 +Suites: {{ DIST }} +Components: main +SOURCES +echo "deb {{ MIRROR }}2 {{ DIST }} main" > /tmp/sources.list +echo "deb {{ MIRROR }}3 {{ DIST }} main" \ + | {{ CMD }} --mode={{ MODE }} --variant=apt {{ DIST }} \ + /tmp/debian-chroot \ + /tmp/deb822.sources \ + {{ MIRROR }}4 \ + - \ + "deb {{ MIRROR }}5 {{ DIST }} main" \ + {{ MIRROR }}6 \ + /tmp/sources.list +test ! -e /tmp/debian-chroot/etc/apt/sources.list +cat << SOURCES | cmp /tmp/debian-chroot/etc/apt/sources.list.d/0000deb822.sources - +Types: deb +URIs: {{ MIRROR }}1 +Suites: {{ DIST }} +Components: main +SOURCES +cat << SOURCES | cmp /tmp/debian-chroot/etc/apt/sources.list.d/0001main.list - +deb {{ MIRROR }}4 {{ DIST }} main + +deb {{ MIRROR }}3 {{ DIST }} main + +deb {{ MIRROR }}5 {{ DIST }} main + +deb {{ MIRROR }}6 {{ DIST }} main +SOURCES +echo "deb {{ MIRROR }}2 {{ DIST }} main" | cmp /tmp/debian-chroot/etc/apt/sources.list.d/0002sources.list - +tar -C /tmp/debian-chroot --one-file-system -c . \ + | { + tar -t \ + | grep -v "^./etc/apt/sources.list.d/0000deb822.sources$" \ + | grep -v "^./etc/apt/sources.list.d/0001main.list$" \ + | grep -v "^./etc/apt/sources.list.d/0002sources.list"; + printf "./etc/apt/sources.list\n"; + } | sort | diff -u tar1.txt - diff --git a/tests/deb822-2-2 b/tests/deb822-2-2 new file mode 100644 index 0000000..c533264 --- /dev/null +++ b/tests/deb822-2-2 @@ -0,0 +1,44 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rm -rf /tmp/debian-chroot; rm -f /tmp/sources /tmp/deb822" EXIT INT TERM +cat << SOURCES > /tmp/deb822 +Types: deb +URIs: {{ MIRROR }}1 +Suites: {{ DIST }} +Components: main +SOURCES +echo "deb {{ MIRROR }}2 {{ DIST }} main" > /tmp/sources +cat << SOURCES | {{ CMD }} --mode={{ MODE }} --variant=apt {{ DIST }} \ + /tmp/debian-chroot \ + /tmp/deb822 \ + - \ + /tmp/sources +Types: deb +URIs: {{ MIRROR }}3 +Suites: {{ DIST }} +Components: main +SOURCES +test ! -e /tmp/debian-chroot/etc/apt/sources.list +ls -lha /tmp/debian-chroot/etc/apt/sources.list.d/ +cat << SOURCES | cmp /tmp/debian-chroot/etc/apt/sources.list.d/0000deb822.sources - +Types: deb +URIs: {{ MIRROR }}1 +Suites: {{ DIST }} +Components: main +SOURCES +cat << SOURCES | cmp /tmp/debian-chroot/etc/apt/sources.list.d/0001main.sources - +Types: deb +URIs: {{ MIRROR }}3 +Suites: {{ DIST }} +Components: main +SOURCES +echo "deb {{ MIRROR }}2 {{ DIST }} main" | cmp /tmp/debian-chroot/etc/apt/sources.list.d/0002sources.list - +tar -C /tmp/debian-chroot --one-file-system -c . \ + | { + tar -t \ + | grep -v "^./etc/apt/sources.list.d/0000deb822.sources$" \ + | grep -v "^./etc/apt/sources.list.d/0001main.sources$" \ + | grep -v "^./etc/apt/sources.list.d/0002sources.list$"; + printf "./etc/apt/sources.list\n"; + } | sort | diff -u tar1.txt - diff --git a/tests/debootstrap-no-op-options b/tests/debootstrap-no-op-options new file mode 100644 index 0000000..cd41681 --- /dev/null +++ b/tests/debootstrap-no-op-options @@ -0,0 +1,6 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +{{ CMD }} --mode=root --variant=apt --resolve-deps --merged-usr --no-merged-usr --force-check-gpg {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - +rm -r /tmp/debian-chroot diff --git a/tests/debug b/tests/debug new file mode 100644 index 0000000..c81ba21 --- /dev/null +++ b/tests/debug @@ -0,0 +1,6 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +{{ CMD }} --mode=root --variant=apt --debug {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - +rm -r /tmp/debian-chroot diff --git a/tests/debug-output-on-fake-tty b/tests/debug-output-on-fake-tty new file mode 100644 index 0000000..c8c8a87 --- /dev/null +++ b/tests/debug-output-on-fake-tty @@ -0,0 +1,6 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rm -f /tmp/debian-chroot.tar" EXIT INT TERM +script -qfc "{{ CMD }} --mode={{ MODE }} --debug --variant=apt {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }}" /dev/null +tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - diff --git a/tests/directory-ending-in-tar b/tests/directory-ending-in-tar new file mode 100644 index 0000000..b44e35a --- /dev/null +++ b/tests/directory-ending-in-tar @@ -0,0 +1,12 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +[ "$(whoami)" = "root" ] +trap "rm -rf /tmp/debian-chroot.tar" EXIT INT TERM +{{ CMD }} --mode={{ MODE }} --variant=apt --format=directory {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }} +ftype=$(stat -c %F /tmp/debian-chroot.tar) +if [ "$ftype" != directory ]; then + echo "expected directory but got: $ftype" >&2 + exit 1 +fi +tar -C /tmp/debian-chroot.tar --one-file-system -c . | tar -t | sort | diff -u tar1.txt - diff --git a/tests/dist-using-codename b/tests/dist-using-codename new file mode 100644 index 0000000..29ab48c --- /dev/null +++ b/tests/dist-using-codename @@ -0,0 +1,11 @@ +#!/bin/sh +# +# make sure that using codenames works https://bugs.debian.org/1003191 + +set -eu +export LC_ALL=C.UTF-8 +trap "rm -f Release; rm -rf /tmp/debian-chroot" EXIT INT TERM +/usr/lib/apt/apt-helper download-file "{{ MIRROR }}/dists/{{ DIST }}/Release" Release +codename=$(awk '/^Codename: / { print $2; }' Release) +{{ CMD }} --mode={{ MODE }} --variant=apt $codename /tmp/debian-chroot {{ MIRROR }} +echo "deb {{ MIRROR }} $codename main" | diff -u - /tmp/debian-chroot/etc/apt/sources.list diff --git a/tests/dpkgopt b/tests/dpkgopt new file mode 100644 index 0000000..1a41da4 --- /dev/null +++ b/tests/dpkgopt @@ -0,0 +1,10 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rm -rf /tmp/debian-chroot; rm -f /tmp/config" EXIT INT TERM +echo no-pager > /tmp/config +{{ CMD }} --mode=root --variant=apt --dpkgopt="path-exclude=/usr/share/doc/*" --dpkgopt=/tmp/config --dpkgopt="path-include=/usr/share/doc/dpkg/copyright" {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +printf 'path-exclude=/usr/share/doc/*\nno-pager\npath-include=/usr/share/doc/dpkg/copyright\n' | cmp /tmp/debian-chroot/etc/dpkg/dpkg.cfg.d/99mmdebstrap - +rm /tmp/debian-chroot/etc/dpkg/dpkg.cfg.d/99mmdebstrap +tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort > tar2.txt +{ grep -v '^./usr/share/doc/.' tar1.txt; echo ./usr/share/doc/dpkg/; echo ./usr/share/doc/dpkg/copyright; } | sort | diff -u - tar2.txt diff --git a/tests/eatmydata-via-hook-dir b/tests/eatmydata-via-hook-dir new file mode 100644 index 0000000..4ffec71 --- /dev/null +++ b/tests/eatmydata-via-hook-dir @@ -0,0 +1,39 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +cat << SCRIPT > /tmp/checkeatmydata.sh +#!/bin/sh +set -exu +cat << EOF | diff - "\$1"/usr/bin/dpkg +#!/bin/sh +exec /usr/bin/eatmydata /usr/bin/dpkg.distrib "\\\$@" +EOF +[ -e "\$1"/usr/bin/eatmydata ] +SCRIPT +chmod +x /tmp/checkeatmydata.sh +# first four bytes: magic +elfheader="\\177ELF" +# fifth byte: bits +case "$(dpkg-architecture -qDEB_HOST_ARCH_BITS)" in + 32) elfheader="$elfheader\\001";; + 64) elfheader="$elfheader\\002";; + *) echo "bits not supported"; exit 1;; +esac +# sixth byte: endian +case "$(dpkg-architecture -qDEB_HOST_ARCH_ENDIAN)" in + little) elfheader="$elfheader\\001";; + big) elfheader="$elfheader\\002";; + *) echo "endian not supported"; exit 1;; +esac +# seventh and eigth byte: elf version (1) and abi (unset) +elfheader="$elfheader\\001\\000" +{{ CMD }} --mode=root --variant=apt \ + --customize-hook=/tmp/checkeatmydata.sh \ + --essential-hook=/tmp/checkeatmydata.sh \ + --extract-hook='printf "'"$elfheader"'" | cmp --bytes=8 - "$1"/usr/bin/dpkg' \ + --hook-dir=./hooks/eatmydata \ + --customize-hook='printf "'"$elfheader"'" | cmp --bytes=8 - "$1"/usr/bin/dpkg' \ + {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - +rm /tmp/checkeatmydata.sh +rm -r /tmp/debian-chroot diff --git a/tests/essential-hook b/tests/essential-hook new file mode 100644 index 0000000..0f55100 --- /dev/null +++ b/tests/essential-hook @@ -0,0 +1,20 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rm -rf /tmp/debian-chroot; rm -f /tmp/essential.sh" EXIT INT TERM +cat << 'SCRIPT' > /tmp/essential.sh +#!/bin/sh +echo tzdata tzdata/Zones/Europe select Berlin | chroot "$1" debconf-set-selections +SCRIPT +chmod +x /tmp/essential.sh +{{ CMD }} --mode=root --variant=apt --include=tzdata --essential-hook='echo tzdata tzdata/Areas select Europe | chroot "$1" debconf-set-selections' --essential-hook=/tmp/essential.sh {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +echo Europe/Berlin | cmp /tmp/debian-chroot/etc/timezone +tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort \ + | grep -v '^./etc/localtime' \ + | grep -v '^./etc/timezone' \ + | grep -v '^./usr/sbin/tzconfig' \ + | grep -v '^./usr/share/doc/tzdata' \ + | grep -v '^./usr/share/zoneinfo' \ + | grep -v '^./var/lib/dpkg/info/tzdata.' \ + | grep -v '^./var/lib/apt/extended_states$' \ + | diff -u tar1.txt - diff --git a/tests/existing-directory-with-lost-found b/tests/existing-directory-with-lost-found new file mode 100644 index 0000000..9757d06 --- /dev/null +++ b/tests/existing-directory-with-lost-found @@ -0,0 +1,9 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rm -rf /tmp/debian-chroot" EXIT INT TERM +mkdir /tmp/debian-chroot +mkdir /tmp/debian-chroot/lost+found +{{ CMD }} --mode=root --variant=apt {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +rmdir /tmp/debian-chroot/lost+found +tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - diff --git a/tests/existing-empty-directory b/tests/existing-empty-directory new file mode 100644 index 0000000..23efeea --- /dev/null +++ b/tests/existing-empty-directory @@ -0,0 +1,7 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rm -rf /tmp/debian-chroot" EXIT INT TERM +mkdir /tmp/debian-chroot +{{ CMD }} --mode=root --variant=apt {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - diff --git a/tests/fail-installing-to-existing-file b/tests/fail-installing-to-existing-file new file mode 100644 index 0000000..5a633fc --- /dev/null +++ b/tests/fail-installing-to-existing-file @@ -0,0 +1,10 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +touch /tmp/exists +ret=0 +{{ CMD }} --mode={{ MODE }} --variant=apt {{ DIST }} /tmp/exists {{ MIRROR }} || ret=$? +if [ "$ret" = 0 ]; then + echo expected failure but got exit $ret >&2 + exit 1 +fi diff --git a/tests/fail-installing-to-non-empty-lost-found b/tests/fail-installing-to-non-empty-lost-found new file mode 100644 index 0000000..4130bf5 --- /dev/null +++ b/tests/fail-installing-to-non-empty-lost-found @@ -0,0 +1,13 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rm /tmp/debian-chroot/lost+found/exists; rmdir /tmp/debian-chroot/lost+found /tmp/debian-chroot" EXIT INT TERM +mkdir /tmp/debian-chroot +mkdir /tmp/debian-chroot/lost+found +touch /tmp/debian-chroot/lost+found/exists +ret=0 +{{ CMD }} --mode={{ MODE }} --variant=apt {{ DIST }} /tmp/debian-chroot {{ MIRROR }} || ret=$? +if [ "$ret" = 0 ]; then + echo expected failure but got exit $ret >&2 + exit 1 +fi diff --git a/tests/fail-installing-to-non-empty-target-directory b/tests/fail-installing-to-non-empty-target-directory new file mode 100644 index 0000000..2606b7f --- /dev/null +++ b/tests/fail-installing-to-non-empty-target-directory @@ -0,0 +1,13 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rmdir /tmp/debian-chroot/lost+found; rm /tmp/debian-chroot/exists; rmdir /tmp/debian-chroot" EXIT INT TERM +mkdir /tmp/debian-chroot +mkdir /tmp/debian-chroot/lost+found +touch /tmp/debian-chroot/exists +ret=0 +{{ CMD }} --mode={{ MODE }} --variant=apt {{ DIST }} /tmp/debian-chroot {{ MIRROR }} || ret=$? +if [ "$ret" = 0 ]; then + echo expected failure but got exit $ret >&2 + exit 1 +fi diff --git a/tests/fail-installing-to-root b/tests/fail-installing-to-root new file mode 100644 index 0000000..ded6b5d --- /dev/null +++ b/tests/fail-installing-to-root @@ -0,0 +1,9 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +ret=0 +{{ CMD }} --mode={{ MODE }} --variant=apt {{ DIST }} / {{ MIRROR }} || ret=$? +if [ "$ret" = 0 ]; then + echo expected failure but got exit $ret >&2 + exit 1 +fi diff --git a/tests/fail-with-missing-lz4 b/tests/fail-with-missing-lz4 new file mode 100644 index 0000000..71c6d60 --- /dev/null +++ b/tests/fail-with-missing-lz4 @@ -0,0 +1,9 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +ret=0 +{{ CMD }} --mode={{ MODE }} --variant=apt {{ DIST }} /tmp/debian-chroot.tar.lz4 {{ MIRROR }} || ret=$? +if [ "$ret" = 0 ]; then + echo expected failure but got exit $ret >&2 + exit 1 +fi diff --git a/tests/fail-with-path-with-quotes b/tests/fail-with-path-with-quotes new file mode 100644 index 0000000..0cb2631 --- /dev/null +++ b/tests/fail-with-path-with-quotes @@ -0,0 +1,9 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +ret=0 +{{ CMD }} --mode={{ MODE }} --variant=apt {{ DIST }} /tmp/quoted\"path {{ MIRROR }} || ret=$? +if [ "$ret" = 0 ]; then + echo expected failure but got exit $ret >&2 + exit 1 +fi diff --git a/tests/fail-without-etc-subuid b/tests/fail-without-etc-subuid new file mode 100644 index 0000000..3f15a9e --- /dev/null +++ b/tests/fail-without-etc-subuid @@ -0,0 +1,17 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 +fi +adduser --gecos user --disabled-password user +sysctl -w kernel.unprivileged_userns_clone=1 +rm /etc/subuid +ret=0 +runuser -u user -- {{ CMD }} --mode=unshare --variant=apt {{ DIST }} /tmp/debian-chroot {{ MIRROR }} || ret=$? +if [ "$ret" = 0 ]; then + echo expected failure but got exit $ret >&2 + exit 1 +fi +rm -r /tmp/debian-chroot diff --git a/tests/fail-without-username-in-etc-subuid b/tests/fail-without-username-in-etc-subuid new file mode 100644 index 0000000..e1479ee --- /dev/null +++ b/tests/fail-without-username-in-etc-subuid @@ -0,0 +1,18 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 +fi +adduser --gecos user --disabled-password user +sysctl -w kernel.unprivileged_userns_clone=1 +awk -F: '$1!="user"' /etc/subuid > /etc/subuid.tmp +mv /etc/subuid.tmp /etc/subuid +ret=0 +runuser -u user -- {{ CMD }} --mode=unshare --variant=apt {{ DIST }} /tmp/debian-chroot {{ MIRROR }} || ret=$? +if [ "$ret" = 0 ]; then + echo expected failure but got exit $ret >&2 + exit 1 +fi +rm -r /tmp/debian-chroot diff --git a/tests/failing-customize-hook b/tests/failing-customize-hook new file mode 100644 index 0000000..8ecc065 --- /dev/null +++ b/tests/failing-customize-hook @@ -0,0 +1,10 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +ret=0 +{{ CMD }} --mode=root --variant=apt --customize-hook='chroot "$1" sh -c "exit 1"' {{ DIST }} /tmp/debian-chroot {{ MIRROR }} || ret=$? +rm -r /tmp/debian-chroot +if [ "$ret" = 0 ]; then + echo expected failure but got exit $ret >&2 + exit 1 +fi diff --git a/tests/file-mirror b/tests/file-mirror new file mode 100644 index 0000000..d24092d --- /dev/null +++ b/tests/file-mirror @@ -0,0 +1,10 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +if [ ! -e /mmdebstrap-testenv ]; then + echo "this test requires the cache directory to be mounted on /mnt and should only be run inside a container" >&2 + exit 1 +fi +{{ CMD }} --mode={{ MODE }} --variant=apt --setup-hook='mkdir -p "$1"/mnt/cache/debian; mount -o ro,bind /mnt/cache/debian "$1"/mnt/cache/debian' --customize-hook='umount "$1"/mnt/cache/debian; rmdir "$1"/mnt/cache/debian "$1"/mnt/cache' {{ DIST }} /tmp/debian-chroot.tar "deb file:///mnt/cache/debian {{ DIST }} main" +tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - +rm /tmp/debian-chroot.tar diff --git a/tests/file-mirror-automount-hook b/tests/file-mirror-automount-hook new file mode 100644 index 0000000..24e3caa --- /dev/null +++ b/tests/file-mirror-automount-hook @@ -0,0 +1,10 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +if [ ! -e /mmdebstrap-testenv ]; then + echo "this test requires the cache directory to be mounted on /mnt and should only be run inside a container" >&2 + exit 1 +fi +{{ CMD }} --mode={{ MODE }} --variant=apt --hook-dir=./hooks/file-mirror-automount --customize-hook='rmdir "$1"/mnt/cache/debian/ "$1"/mnt/cache' {{ DIST }} /tmp/debian-chroot.tar "deb file:///mnt/cache/debian {{ DIST }} main" +tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - +rm /tmp/debian-chroot.tar diff --git a/tests/help b/tests/help new file mode 100644 index 0000000..535eeba --- /dev/null +++ b/tests/help @@ -0,0 +1,6 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +# we redirect to /dev/null instead of using --quiet to not cause a broken pipe +# when grep exits before mmdebstrap was able to write all its output +{{ CMD }} --help | grep --fixed-strings 'mmdebstrap [OPTION...] [SUITE [TARGET [MIRROR...]]]' >/dev/null diff --git a/tests/hook-directory b/tests/hook-directory new file mode 100644 index 0000000..c9b22f9 --- /dev/null +++ b/tests/hook-directory @@ -0,0 +1,49 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +for h in hookA hookB; do + mkdir /tmp/$h + for s in setup extract essential customize; do + cat << SCRIPT > /tmp/$h/${s}00.sh +#!/bin/sh +echo $h/${s}00 >> "\$1/$s" +SCRIPT + chmod +x /tmp/$h/${s}00.sh + cat << SCRIPT > /tmp/$h/${s}01.sh +echo $h/${s}01 >> "\$1/$s" +SCRIPT + chmod +x /tmp/$h/${s}01.sh + done +done +{{ CMD }} --mode=root --variant=apt \ + --setup-hook='echo cliA/setup >> "$1"/setup' \ + --extract-hook='echo cliA/extract >> "$1"/extract' \ + --essential-hook='echo cliA/essential >> "$1"/essential' \ + --customize-hook='echo cliA/customize >> "$1"/customize' \ + --hook-dir=/tmp/hookA \ + --setup-hook='echo cliB/setup >> "$1"/setup' \ + --extract-hook='echo cliB/extract >> "$1"/extract' \ + --essential-hook='echo cliB/essential >> "$1"/essential' \ + --customize-hook='echo cliB/customize >> "$1"/customize' \ + --hook-dir=/tmp/hookB \ + --setup-hook='echo cliC/setup >> "$1"/setup' \ + --extract-hook='echo cliC/extract >> "$1"/extract' \ + --essential-hook='echo cliC/essential >> "$1"/essential' \ + --customize-hook='echo cliC/customize >> "$1"/customize' \ + {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +printf "cliA/setup\nhookA/setup00\nhookA/setup01\ncliB/setup\nhookB/setup00\nhookB/setup01\ncliC/setup\n" | diff -u - /tmp/debian-chroot/setup +printf "cliA/extract\nhookA/extract00\nhookA/extract01\ncliB/extract\nhookB/extract00\nhookB/extract01\ncliC/extract\n" | diff -u - /tmp/debian-chroot/extract +printf "cliA/essential\nhookA/essential00\nhookA/essential01\ncliB/essential\nhookB/essential00\nhookB/essential01\ncliC/essential\n" | diff -u - /tmp/debian-chroot/essential +printf "cliA/customize\nhookA/customize00\nhookA/customize01\ncliB/customize\nhookB/customize00\nhookB/customize01\ncliC/customize\n" | diff -u - /tmp/debian-chroot/customize +for s in setup extract essential customize; do + rm /tmp/debian-chroot/$s +done +tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - +for h in hookA hookB; do + for s in setup extract essential customize; do + rm /tmp/$h/${s}00.sh + rm /tmp/$h/${s}01.sh + done + rmdir /tmp/$h +done +rm -r /tmp/debian-chroot diff --git a/tests/i386-which-can-be-executed-without-qemu b/tests/i386-which-can-be-executed-without-qemu new file mode 100644 index 0000000..5e964a6 --- /dev/null +++ b/tests/i386-which-can-be-executed-without-qemu @@ -0,0 +1,38 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 +fi +# remove qemu just to be sure +apt-get remove --yes qemu-user-static binfmt-support qemu-user +{{ CMD }} --mode={{ MODE }} --variant=apt --architectures=i386 {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }} +# we ignore differences between architectures by ignoring some files +# and renaming others +{ tar -tf /tmp/debian-chroot.tar \ + | grep -v '^\./usr/bin/i386$' \ + | grep -v '^\./lib/ld-linux\.so\.2$' \ + | grep -v '^\./lib/i386-linux-gnu/ld-linux\.so\.2$' \ + | grep -v '^\./usr/lib/gcc/i686-linux-gnu/$' \ + | grep -v '^\./usr/lib/gcc/i686-linux-gnu/[0-9]\+/$' \ + | grep -v '^\./usr/share/man/man8/i386\.8\.gz$' \ + | grep -v '^\./usr/share/doc/[^/]\+/changelog\(\.Debian\)\?\.i386\.gz$' \ + | sed 's/i386-linux-gnu/x86_64-linux-gnu/' \ + | sed 's/i386/amd64/'; +} | sort > tar2.txt +{ cat tar1.txt \ + | grep -v '^\./usr/bin/i386$' \ + | grep -v '^\./usr/bin/x86_64$' \ + | grep -v '^\./lib64/$' \ + | grep -v '^\./lib64/ld-linux-x86-64\.so\.2$' \ + | grep -v '^\./usr/lib/gcc/x86_64-linux-gnu/$' \ + | grep -v '^\./usr/lib/gcc/x86_64-linux-gnu/[0-9]\+/$' \ + | grep -v '^\./lib/x86_64-linux-gnu/ld-linux-x86-64\.so\.2$' \ + | grep -v '^\./lib/x86_64-linux-gnu/libmvec-2\.[0-9]\+\.so$' \ + | grep -v '^\./lib/x86_64-linux-gnu/libmvec\.so\.1$' \ + | grep -v '^\./usr/share/doc/[^/]\+/changelog\(\.Debian\)\?\.amd64\.gz$' \ + | grep -v '^\./usr/share/man/man8/i386\.8\.gz$' \ + | grep -v '^\./usr/share/man/man8/x86_64\.8\.gz$'; +} | sort | diff -u - tar2.txt +rm /tmp/debian-chroot.tar diff --git a/tests/include b/tests/include new file mode 100644 index 0000000..95c9c69 --- /dev/null +++ b/tests/include @@ -0,0 +1,12 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rm -rf /tmp/debian-chroot" EXIT INT TERM +{{ CMD }} --mode=root --variant=apt --include=doc-debian {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +rm /tmp/debian-chroot/usr/share/doc-base/debian-* +rm -r /tmp/debian-chroot/usr/share/doc/debian +rm -r /tmp/debian-chroot/usr/share/doc/doc-debian +rm /tmp/debian-chroot/var/lib/apt/extended_states +rm /tmp/debian-chroot/var/lib/dpkg/info/doc-debian.list +rm /tmp/debian-chroot/var/lib/dpkg/info/doc-debian.md5sums +tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - diff --git a/tests/include-libmagic-mgc-arm64 b/tests/include-libmagic-mgc-arm64 new file mode 100644 index 0000000..3c7947a --- /dev/null +++ b/tests/include-libmagic-mgc-arm64 @@ -0,0 +1,29 @@ +#!/bin/sh +# +# to test foreign architecture package installation we choose a package which +# - is not part of the native installation set +# - does not have any dependencies +# - installs only few files +# - doesn't change its name regularly (like gcc-*-base) + +set -eu +export LC_ALL=C.UTF-8 +{{ CMD }} --mode=root --variant=apt --architectures=amd64,arm64 --include=libmagic-mgc:arm64 {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +{ echo "amd64"; echo "arm64"; } | cmp /tmp/debian-chroot/var/lib/dpkg/arch - +rm /tmp/debian-chroot/var/lib/dpkg/arch +rm /tmp/debian-chroot/var/lib/apt/extended_states +rm /tmp/debian-chroot/var/lib/dpkg/info/libmagic-mgc.list +rm /tmp/debian-chroot/var/lib/dpkg/info/libmagic-mgc.md5sums +rm /tmp/debian-chroot/usr/lib/file/magic.mgc +rm /tmp/debian-chroot/usr/share/doc/libmagic-mgc/README.Debian +rm /tmp/debian-chroot/usr/share/doc/libmagic-mgc/changelog.Debian.gz +rm /tmp/debian-chroot/usr/share/doc/libmagic-mgc/changelog.gz +rm /tmp/debian-chroot/usr/share/doc/libmagic-mgc/copyright +rm /tmp/debian-chroot/usr/share/file/magic.mgc +rm /tmp/debian-chroot/usr/share/misc/magic.mgc +rmdir /tmp/debian-chroot/usr/share/doc/libmagic-mgc/ +rmdir /tmp/debian-chroot/usr/share/file/magic/ +rmdir /tmp/debian-chroot/usr/share/file/ +rmdir /tmp/debian-chroot/usr/lib/file/ +tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - +rm -r /tmp/debian-chroot diff --git a/tests/include-libmagic-mgc-arm64-with-multiple-arch-options b/tests/include-libmagic-mgc-arm64-with-multiple-arch-options new file mode 100644 index 0000000..9a4a308 --- /dev/null +++ b/tests/include-libmagic-mgc-arm64-with-multiple-arch-options @@ -0,0 +1,22 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +{{ CMD }} --mode=root --variant=apt --architectures=amd64 --architectures=arm64 --include=libmagic-mgc:arm64 {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +{ echo "amd64"; echo "arm64"; } | cmp /tmp/debian-chroot/var/lib/dpkg/arch - +rm /tmp/debian-chroot/var/lib/dpkg/arch +rm /tmp/debian-chroot/var/lib/apt/extended_states +rm /tmp/debian-chroot/var/lib/dpkg/info/libmagic-mgc.list +rm /tmp/debian-chroot/var/lib/dpkg/info/libmagic-mgc.md5sums +rm /tmp/debian-chroot/usr/lib/file/magic.mgc +rm /tmp/debian-chroot/usr/share/doc/libmagic-mgc/README.Debian +rm /tmp/debian-chroot/usr/share/doc/libmagic-mgc/changelog.Debian.gz +rm /tmp/debian-chroot/usr/share/doc/libmagic-mgc/changelog.gz +rm /tmp/debian-chroot/usr/share/doc/libmagic-mgc/copyright +rm /tmp/debian-chroot/usr/share/file/magic.mgc +rm /tmp/debian-chroot/usr/share/misc/magic.mgc +rmdir /tmp/debian-chroot/usr/share/doc/libmagic-mgc/ +rmdir /tmp/debian-chroot/usr/share/file/magic/ +rmdir /tmp/debian-chroot/usr/share/file/ +rmdir /tmp/debian-chroot/usr/lib/file/ +tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - +rm -r /tmp/debian-chroot diff --git a/tests/include-with-multiple-apt-sources b/tests/include-with-multiple-apt-sources new file mode 100644 index 0000000..1d335d4 --- /dev/null +++ b/tests/include-with-multiple-apt-sources @@ -0,0 +1,10 @@ +#!/bin/sh +# +# This checks for https://bugs.debian.org/976166 +# Since $DEFAULT_DIST varies, we hardcode stable and unstable. + +set -eu +export LC_ALL=C.UTF-8 +trap "rm -rf /tmp/debian-chroot" EXIT INT TERM +{{ CMD }} --mode=root --variant=minbase --include=doc-debian unstable /tmp/debian-chroot "deb {{ MIRROR }} unstable main" "deb {{ MIRROR }} stable main" +chroot /tmp/debian-chroot dpkg-query --show doc-debian diff --git a/tests/install-busybox-based-sub-essential-system b/tests/install-busybox-based-sub-essential-system new file mode 100644 index 0000000..8c64f70 --- /dev/null +++ b/tests/install-busybox-based-sub-essential-system @@ -0,0 +1,33 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +pkgs=base-files,base-passwd,busybox,debianutils,dpkg,libc-bin,mawk,tar +# busybox --install -s will install symbolic links into the rootfs, leaving +# existing files untouched. It has to run after extraction (otherwise there is +# no busybox binary) and before first configuration +{{ CMD }} --mode=root --variant=custom \ + --include=$pkgs \ + --setup-hook='mkdir -p "$1/bin"' \ + --setup-hook='echo root:x:0:0:root:/root:/bin/sh > "$1/etc/passwd"' \ + --setup-hook='printf "root:x:0:\nmail:x:8:\nutmp:x:43:\n" > "$1/etc/group"' \ + --extract-hook='chroot "$1" busybox --install -s' \ + {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +echo "$pkgs" | tr ',' '\n' > /tmp/expected +chroot /tmp/debian-chroot dpkg-query -f '${binary:Package}\n' -W \ + | comm -12 - /tmp/expected \ + | diff -u - /tmp/expected +rm /tmp/expected +for cmd in echo cat sed grep; do + test -L /tmp/debian-chroot/bin/$cmd + test "$(readlink /tmp/debian-chroot/bin/$cmd)" = "/bin/busybox" +done +for cmd in sort; do + test -L /tmp/debian-chroot/usr/bin/$cmd + test "$(readlink /tmp/debian-chroot/usr/bin/$cmd)" = "/bin/busybox" +done +chroot /tmp/debian-chroot echo foobar \ + | chroot /tmp/debian-chroot cat \ + | chroot /tmp/debian-chroot sort \ + | chroot /tmp/debian-chroot sed 's/foobar/blubber/' \ + | chroot /tmp/debian-chroot grep blubber >/dev/null +rm -r /tmp/debian-chroot diff --git a/tests/install-doc-debian b/tests/install-doc-debian new file mode 100644 index 0000000..29f1245 --- /dev/null +++ b/tests/install-doc-debian @@ -0,0 +1,46 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +if [ "$(id -u)" -eq 0 ] && ! id -u user > /dev/null 2>&1; then + if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 + fi + adduser --gecos user --disabled-password user +fi +prefix= +[ "$(id -u)" -eq 0 ] && prefix="runuser -u user --" +$prefix {{ CMD }} --mode=chrootless --variant=custom --include=doc-debian {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +tar -C /tmp/debian-chroot --owner=0 --group=0 --numeric-owner --sort=name --clamp-mtime --mtime=$(date --utc --date=@{{ SOURCE_DATE_EPOCH }} --iso-8601=seconds) -cf /tmp/debian-chroot.tar . +tar tvf /tmp/debian-chroot.tar > doc-debian.tar.list +rm /tmp/debian-chroot.tar +# delete contents of doc-debian +rm /tmp/debian-chroot/usr/share/doc-base/debian-* +rm -r /tmp/debian-chroot/usr/share/doc/debian +rm -r /tmp/debian-chroot/usr/share/doc/doc-debian +# delete real files +rm /tmp/debian-chroot/etc/apt/sources.list +rm /tmp/debian-chroot/etc/fstab +rm /tmp/debian-chroot/etc/hostname +rm /tmp/debian-chroot/etc/resolv.conf +rm /tmp/debian-chroot/var/lib/dpkg/status +rm /tmp/debian-chroot/var/cache/apt/archives/lock +rm /tmp/debian-chroot/var/lib/dpkg/lock +rm /tmp/debian-chroot/var/lib/dpkg/lock-frontend +rm /tmp/debian-chroot/var/lib/apt/lists/lock +## delete merged usr symlinks +#rm /tmp/debian-chroot/libx32 +#rm /tmp/debian-chroot/lib64 +#rm /tmp/debian-chroot/lib32 +#rm /tmp/debian-chroot/sbin +#rm /tmp/debian-chroot/bin +#rm /tmp/debian-chroot/lib +# in chrootless mode, there is more to remove +rm /tmp/debian-chroot/var/lib/dpkg/triggers/Lock +rm /tmp/debian-chroot/var/lib/dpkg/triggers/Unincorp +rm /tmp/debian-chroot/var/lib/dpkg/status-old +rm /tmp/debian-chroot/var/lib/dpkg/info/format +rm /tmp/debian-chroot/var/lib/dpkg/info/doc-debian.md5sums +rm /tmp/debian-chroot/var/lib/dpkg/info/doc-debian.list +# the rest should be empty directories that we can rmdir recursively +find /tmp/debian-chroot -depth -print0 | xargs -0 rmdir diff --git a/tests/install-doc-debian-and-output-tarball b/tests/install-doc-debian-and-output-tarball new file mode 100644 index 0000000..cdfb636 --- /dev/null +++ b/tests/install-doc-debian-and-output-tarball @@ -0,0 +1,16 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +export SOURCE_DATE_EPOCH={{ SOURCE_DATE_EPOCH }} +if [ "$(id -u)" -eq 0 ] && ! id -u user > /dev/null 2>&1; then + if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 + fi + adduser --gecos user --disabled-password user +fi +prefix= +[ "$(id -u)" -eq 0 ] && prefix="runuser -u user --" +$prefix {{ CMD }} --mode=chrootless --variant=custom --include=doc-debian {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }} +tar tvf /tmp/debian-chroot.tar | grep -v ' ./dev' | diff -u doc-debian.tar.list - +rm /tmp/debian-chroot.tar diff --git a/tests/install-doc-debian-and-test-hooks b/tests/install-doc-debian-and-test-hooks new file mode 100644 index 0000000..05eb4a3 --- /dev/null +++ b/tests/install-doc-debian-and-test-hooks @@ -0,0 +1,49 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +export SOURCE_DATE_EPOCH={{ SOURCE_DATE_EPOCH }} +if [ "$(id -u)" -eq 0 ] && ! id -u user > /dev/null 2>&1; then + if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 + fi + adduser --gecos user --disabled-password user +fi +prefix= +[ "$(id -u)" -eq 0 ] && prefix="runuser -u user --" +$prefix {{ CMD }} --mode=chrootless --skip=cleanup/tmp --variant=custom --include=doc-debian --setup-hook='touch "$1/tmp/setup"' --customize-hook='touch "$1/tmp/customize"' {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +rm /tmp/debian-chroot/tmp/setup +rm /tmp/debian-chroot/tmp/customize +tar -C /tmp/debian-chroot --owner=0 --group=0 --numeric-owner --sort=name --clamp-mtime --mtime=$(date --utc --date=@{{ SOURCE_DATE_EPOCH }} --iso-8601=seconds) -cf /tmp/debian-chroot.tar . +tar tvf /tmp/debian-chroot.tar | grep -v ' ./dev' | diff -u doc-debian.tar.list - +rm /tmp/debian-chroot.tar +# delete contents of doc-debian +rm /tmp/debian-chroot/usr/share/doc-base/debian-* +rm -r /tmp/debian-chroot/usr/share/doc/debian +rm -r /tmp/debian-chroot/usr/share/doc/doc-debian +# delete real files +rm /tmp/debian-chroot/etc/apt/sources.list +rm /tmp/debian-chroot/etc/fstab +rm /tmp/debian-chroot/etc/hostname +rm /tmp/debian-chroot/etc/resolv.conf +rm /tmp/debian-chroot/var/lib/dpkg/status +rm /tmp/debian-chroot/var/cache/apt/archives/lock +rm /tmp/debian-chroot/var/lib/dpkg/lock +rm /tmp/debian-chroot/var/lib/dpkg/lock-frontend +rm /tmp/debian-chroot/var/lib/apt/lists/lock +## delete merged usr symlinks +#rm /tmp/debian-chroot/libx32 +#rm /tmp/debian-chroot/lib64 +#rm /tmp/debian-chroot/lib32 +#rm /tmp/debian-chroot/sbin +#rm /tmp/debian-chroot/bin +#rm /tmp/debian-chroot/lib +# in chrootless mode, there is more to remove +rm /tmp/debian-chroot/var/lib/dpkg/triggers/Lock +rm /tmp/debian-chroot/var/lib/dpkg/triggers/Unincorp +rm /tmp/debian-chroot/var/lib/dpkg/status-old +rm /tmp/debian-chroot/var/lib/dpkg/info/format +rm /tmp/debian-chroot/var/lib/dpkg/info/doc-debian.md5sums +rm /tmp/debian-chroot/var/lib/dpkg/info/doc-debian.list +# the rest should be empty directories that we can rmdir recursively +find /tmp/debian-chroot -depth -print0 | xargs -0 rmdir diff --git a/tests/install-known-good-from-essential-yes b/tests/install-known-good-from-essential-yes new file mode 100644 index 0000000..dd18ece --- /dev/null +++ b/tests/install-known-good-from-essential-yes @@ -0,0 +1,43 @@ +#!/bin/sh +# +# regularly check whether more packages work with chrootless: +# for p in $(grep-aptavail -F Essential yes -s Package -n | sort -u); do ./mmdebstrap -- mode=chrootless --variant=custom --include=bsdutils,coreutils,debianutils,diffutils,dpkg, findutils,grep,gzip,hostname,init-system-helpers,ncurses-base,ncurses-bin,perl-base,sed, sysvinit-utils,tar,$p unstable /dev/null; done +# +# see https://bugs.debian.org/cgi-bin/pkgreport.cgi?users=debian-dpkg@lists.debian.org;tag=dpkg- root-support +# +# base-files: #824594 +# base-passwd: debconf +# bash: depends base-files +# bsdutils: ok +# coreutils: ok +# dash: debconf +# debianutils: ok +# diffutils: ok +# dpkg: ok +# findutils: ok +# grep: ok +# gzip: ok +# hostname: ok +# init-system-helpers: ok +# libc-bin: #983412 +# login: debconf +# ncurses-base: ok +# ncurses-bin: ok +# perl-base: ok +# sed: ok +# sysvinit-utils: ok +# tar: ok +# util-linux: debconf + +set -eu +export LC_ALL=C.UTF-8 +if [ "$(id -u)" -eq 0 ] && ! id -u user > /dev/null 2>&1; then + if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 + fi + adduser --gecos user --disabled-password user +fi +prefix= +[ "$(id -u)" -eq 0 ] && prefix="runuser -u user --" +$prefix {{ CMD }} --mode=chrootless --variant=custom --include=bsdutils,coreutils,debianutils,diffutils,dpkg,findutils,grep,gzip,hostname,init-system-helpers,ncurses-base,ncurses-bin,perl-base,sed,sysvinit-utils,tar {{ DIST }} /dev/null {{ MIRROR }} diff --git a/tests/install-libmagic-mgc-on-arm64 b/tests/install-libmagic-mgc-on-arm64 new file mode 100644 index 0000000..c26e043 --- /dev/null +++ b/tests/install-libmagic-mgc-on-arm64 @@ -0,0 +1,48 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +if [ "$(id -u)" -eq 0 ] && ! id -u user > /dev/null 2>&1; then + if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 + fi + adduser --gecos user --disabled-password user +fi +prefix= +[ "$(id -u)" -eq 0 ] && prefix="runuser -u user --" +$prefix {{ CMD }} --mode=chrootless --variant=custom --architectures=arm64 --include=libmagic-mgc {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +# delete contents of libmagic-mgc +rm /tmp/debian-chroot/usr/lib/file/magic.mgc +rm /tmp/debian-chroot/usr/share/doc/libmagic-mgc/README.Debian +rm /tmp/debian-chroot/usr/share/doc/libmagic-mgc/changelog.Debian.gz +rm /tmp/debian-chroot/usr/share/doc/libmagic-mgc/changelog.gz +rm /tmp/debian-chroot/usr/share/doc/libmagic-mgc/copyright +rm /tmp/debian-chroot/usr/share/file/magic.mgc +rm /tmp/debian-chroot/usr/share/misc/magic.mgc +# delete real files +rm /tmp/debian-chroot/etc/apt/sources.list +rm /tmp/debian-chroot/etc/fstab +rm /tmp/debian-chroot/etc/hostname +rm /tmp/debian-chroot/etc/resolv.conf +rm /tmp/debian-chroot/var/lib/dpkg/status +rm /tmp/debian-chroot/var/cache/apt/archives/lock +rm /tmp/debian-chroot/var/lib/dpkg/lock +rm /tmp/debian-chroot/var/lib/dpkg/lock-frontend +rm /tmp/debian-chroot/var/lib/apt/lists/lock +## delete merged usr symlinks +#rm /tmp/debian-chroot/libx32 +#rm /tmp/debian-chroot/lib64 +#rm /tmp/debian-chroot/lib32 +#rm /tmp/debian-chroot/sbin +#rm /tmp/debian-chroot/bin +#rm /tmp/debian-chroot/lib +# in chrootless mode, there is more to remove +rm /tmp/debian-chroot/var/lib/dpkg/arch +rm /tmp/debian-chroot/var/lib/dpkg/triggers/Lock +rm /tmp/debian-chroot/var/lib/dpkg/triggers/Unincorp +rm /tmp/debian-chroot/var/lib/dpkg/status-old +rm /tmp/debian-chroot/var/lib/dpkg/info/format +rm /tmp/debian-chroot/var/lib/dpkg/info/libmagic-mgc.md5sums +rm /tmp/debian-chroot/var/lib/dpkg/info/libmagic-mgc.list +# the rest should be empty directories that we can rmdir recursively +find /tmp/debian-chroot -depth -print0 | xargs -0 rmdir diff --git a/tests/invalid-mirror b/tests/invalid-mirror new file mode 100644 index 0000000..97cde05 --- /dev/null +++ b/tests/invalid-mirror @@ -0,0 +1,10 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +ret=0 +{{ CMD }} --mode={{ MODE }} --variant=apt {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }}/invalid || ret=$? +rm /tmp/debian-chroot.tar +if [ "$ret" = 0 ]; then + echo expected failure but got exit $ret >&2 + exit 1 +fi diff --git a/tests/keyring b/tests/keyring new file mode 100644 index 0000000..a48f864 --- /dev/null +++ b/tests/keyring @@ -0,0 +1,13 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 +fi +rm /etc/apt/trusted.gpg.d/*.gpg +{{ CMD }} --mode=root --variant=apt --keyring=/usr/share/keyrings/debian-archive-keyring.gpg --keyring=/usr/share/keyrings/ {{ DIST }} /tmp/debian-chroot "deb {{ MIRROR }} {{ DIST }} main" +# make sure that no [signedby=...] managed to make it into the sources.list +echo "deb {{ MIRROR }} {{ DIST }} main" | cmp /tmp/debian-chroot/etc/apt/sources.list - +tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - +rm -r /tmp/debian-chroot diff --git a/tests/keyring-overwrites b/tests/keyring-overwrites new file mode 100644 index 0000000..f070654 --- /dev/null +++ b/tests/keyring-overwrites @@ -0,0 +1,15 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rm -rf /tmp/debian-chroot; rmdir /tmp/emptydir; rm -f /tmp/emptyfile" EXIT INT TERM +mkdir -p /tmp/emptydir +touch /tmp/emptyfile +# this overwrites the apt keyring options and should fail +ret=0 +{{ CMD }} --mode=root --variant=apt --keyring=/tmp/emptydir --keyring=/tmp/emptyfile {{ DIST }} /tmp/debian-chroot "deb {{ MIRROR }} {{ DIST }} main" || ret=$? +# make sure that no [signedby=...] managed to make it into the sources.list +echo "deb {{ MIRROR }} {{ DIST }} main" | cmp /tmp/debian-chroot/etc/apt/sources.list - +if [ "$ret" = 0 ]; then + echo expected failure but got exit $ret >&2 + exit 1 +fi diff --git a/tests/logfile b/tests/logfile new file mode 100644 index 0000000..57e0776 --- /dev/null +++ b/tests/logfile @@ -0,0 +1,20 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +# we check the full log to also prevent debug printfs to accidentally make it into a commit +{{ CMD }} --mode=root --variant=apt --logfile=/tmp/log {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +# omit the last line which should contain the runtime +head --lines=-1 /tmp/log > /tmp/trimmed +cat << LOG | diff -u - /tmp/trimmed +I: chroot architecture {{ HOSTARCH }} is equal to the host's architecture +I: automatically chosen format: directory +I: running apt-get update... +I: downloading packages with apt... +I: extracting archives... +I: installing essential packages... +I: cleaning package lists and apt cache... +LOG +tail --lines=1 /tmp/log | grep '^I: success in .* seconds$' +tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - +rm -r /tmp/debian-chroot +rm /tmp/log /tmp/trimmed diff --git a/tests/man b/tests/man new file mode 100644 index 0000000..b5c38b9 --- /dev/null +++ b/tests/man @@ -0,0 +1,7 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 + +# we redirect to /dev/null instead of using --quiet to not cause a broken pipe +# when grep exits before mmdebstrap was able to write all its output +{{ CMD }} --man | grep --fixed-strings 'mmdebstrap [OPTION...] [*SUITE* [*TARGET* [*MIRROR*...]]]' >/dev/null diff --git a/tests/merged-usr-via-setup-hook b/tests/merged-usr-via-setup-hook new file mode 100644 index 0000000..79f7c92 --- /dev/null +++ b/tests/merged-usr-via-setup-hook @@ -0,0 +1,43 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rm -rf /tmp/debian-chroot" EXIT INT TERM +{{ CMD }} --mode=root --variant=apt \ + --setup-hook=./hooks/merged-usr/setup00.sh \ + --customize-hook='[ -L "$1"/bin -a -L "$1"/sbin -a -L "$1"/lib ]' \ + {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort > tar2.txt +{ + sed -e 's/^\.\/bin\//.\/usr\/bin\//;s/^\.\/lib\//.\/usr\/lib\//;s/^\.\/sbin\//.\/usr\/sbin\//;' tar1.txt | { + case {{ HOSTARCH }} in + amd64) sed -e 's/^\.\/lib32\//.\/usr\/lib32\//;s/^\.\/lib64\//.\/usr\/lib64\//;s/^\.\/libx32\//.\/usr\/libx32\//;';; + ppc64el) sed -e 's/^\.\/lib64\//.\/usr\/lib64\//;';; + *) cat;; + esac + }; + echo ./bin; + echo ./lib; + echo ./sbin; + case {{ HOSTARCH }} in + amd64) + echo ./lib32; + echo ./lib64; + echo ./libx32; + echo ./usr/lib32/; + echo ./usr/libx32/; + ;; + i386) + echo ./lib64; + echo ./libx32; + echo ./usr/lib64/; + echo ./usr/libx32/; + ;; + ppc64el) + echo ./lib64; + ;; + s390x) + echo ./lib32; + echo ./usr/lib32/; + ;; + esac +} | sort -u | diff -u - tar2.txt diff --git a/tests/mirror-is-deb b/tests/mirror-is-deb new file mode 100644 index 0000000..c751aad --- /dev/null +++ b/tests/mirror-is-deb @@ -0,0 +1,6 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rm -f /tmp/debian-chroot.tar" EXIT INT TERM +{{ CMD }} --mode={{ MODE }} --variant=apt {{ DIST }} /tmp/debian-chroot.tar "deb {{ MIRROR }} {{ DIST }} main" +tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - diff --git a/tests/mirror-is-real-file b/tests/mirror-is-real-file new file mode 100644 index 0000000..76f9efc --- /dev/null +++ b/tests/mirror-is-real-file @@ -0,0 +1,9 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rm -f /tmp/debian-chroot.tar /tmp/sources.list" EXIT INT TERM +echo "deb {{ MIRROR }} {{ DIST }} main" > /tmp/sources.list +{{ CMD }} --mode={{ MODE }} --variant=apt {{ DIST }} /tmp/debian-chroot.tar /tmp/sources.list +tar -tf /tmp/debian-chroot.tar \ + | sed 's#^./etc/apt/sources.list.d/0000sources.list$#./etc/apt/sources.list#' \ + | sort | diff -u tar1.txt - diff --git a/tests/mirror-is-stdin b/tests/mirror-is-stdin new file mode 100644 index 0000000..ba0e376 --- /dev/null +++ b/tests/mirror-is-stdin @@ -0,0 +1,6 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rm -f /tmp/debian-chroot.tar" EXIT INT TERM +echo "deb {{ MIRROR }} {{ DIST }} main" | {{ CMD }} --mode={{ MODE }} --variant=apt {{ DIST }} /tmp/debian-chroot.tar - +tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - diff --git a/tests/missing-dev-sys-proc-inside-the-chroot b/tests/missing-dev-sys-proc-inside-the-chroot new file mode 100644 index 0000000..f2370f9 --- /dev/null +++ b/tests/missing-dev-sys-proc-inside-the-chroot @@ -0,0 +1,10 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 +fi +adduser --gecos user --disabled-password user +sysctl -w kernel.unprivileged_userns_clone=1 +runuser -u user -- {{ CMD }} --mode=unshare --variant=custom --include=dpkg,dash,diffutils,coreutils,libc-bin,sed {{ DIST }} /dev/null {{ MIRROR }} diff --git a/tests/missing-device-nodes-outside-the-chroot b/tests/missing-device-nodes-outside-the-chroot new file mode 100644 index 0000000..73a4902 --- /dev/null +++ b/tests/missing-device-nodes-outside-the-chroot @@ -0,0 +1,13 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 +fi +rm /dev/console +adduser --gecos user --disabled-password user +sysctl -w kernel.unprivileged_userns_clone=1 +runuser -u user -- {{ CMD }} --mode=unshare --variant=apt {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }} +tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - +rm /tmp/debian-chroot.tar diff --git a/tests/mount-is-missing b/tests/mount-is-missing new file mode 100644 index 0000000..2e0c4b0 --- /dev/null +++ b/tests/mount-is-missing @@ -0,0 +1,13 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 +fi +for p in /bin /usr/bin /sbin /usr/sbin; do + rm -f "$p/mount" +done +{{ CMD }} --mode=root --variant=apt {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }} +tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - +rm /tmp/debian-chroot.tar diff --git a/tests/multiple-include b/tests/multiple-include new file mode 100644 index 0000000..6af8c3f --- /dev/null +++ b/tests/multiple-include @@ -0,0 +1,23 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rm -rf /tmp/debian-chroot" EXIT INT TERM +{{ CMD }} --mode=root --variant=apt --include=doc-debian --include=tzdata {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +rm /tmp/debian-chroot/usr/share/doc-base/debian-* +rm -r /tmp/debian-chroot/usr/share/doc/debian +rm -r /tmp/debian-chroot/usr/share/doc/doc-debian +rm /tmp/debian-chroot/etc/localtime +rm /tmp/debian-chroot/etc/timezone +rm /tmp/debian-chroot/usr/sbin/tzconfig +rm -r /tmp/debian-chroot/usr/share/doc/tzdata +rm -r /tmp/debian-chroot/usr/share/zoneinfo +rm /tmp/debian-chroot/var/lib/apt/extended_states +rm /tmp/debian-chroot/var/lib/dpkg/info/doc-debian.list +rm /tmp/debian-chroot/var/lib/dpkg/info/doc-debian.md5sums +rm /tmp/debian-chroot/var/lib/dpkg/info/tzdata.list +rm /tmp/debian-chroot/var/lib/dpkg/info/tzdata.md5sums +rm /tmp/debian-chroot/var/lib/dpkg/info/tzdata.config +rm /tmp/debian-chroot/var/lib/dpkg/info/tzdata.postinst +rm /tmp/debian-chroot/var/lib/dpkg/info/tzdata.postrm +rm /tmp/debian-chroot/var/lib/dpkg/info/tzdata.templates +tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - diff --git a/tests/not-having-to-install-apt-in-include-because-a-hook-did-it-before b/tests/not-having-to-install-apt-in-include-because-a-hook-did-it-before new file mode 100644 index 0000000..196fa2f --- /dev/null +++ b/tests/not-having-to-install-apt-in-include-because-a-hook-did-it-before @@ -0,0 +1,9 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rm -f /tmp/debian-chroot.tar" EXIT INT TERM +{{ CMD }} --mode={{ MODE }} --variant=essential --include=apt \ + --essential-hook='APT_CONFIG=$MMDEBSTRAP_APT_CONFIG apt-get update' \ + --essential-hook='APT_CONFIG=$MMDEBSTRAP_APT_CONFIG apt-get --yes install -oDPkg::Chroot-Directory="$1" apt' \ + {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }} +tar -tf /tmp/debian-chroot.tar | sort | grep -v ./var/lib/apt/extended_states | diff -u tar1.txt - diff --git a/tests/pass-distribution-but-implicitly-write-to-stdout b/tests/pass-distribution-but-implicitly-write-to-stdout new file mode 100644 index 0000000..16d2243 --- /dev/null +++ b/tests/pass-distribution-but-implicitly-write-to-stdout @@ -0,0 +1,14 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 +fi +cat << HOSTS >> /etc/hosts +127.0.0.1 deb.debian.org +127.0.0.1 security.debian.org +HOSTS +{{ CMD }} --mode={{ MODE }} --variant=apt {{ DIST }} > /tmp/debian-chroot.tar +tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - +rm /tmp/debian-chroot.tar diff --git a/tests/preserve-mode-of-etc-resolv-conf-and-etc-hostname b/tests/preserve-mode-of-etc-resolv-conf-and-etc-hostname new file mode 100644 index 0000000..1922e7d --- /dev/null +++ b/tests/preserve-mode-of-etc-resolv-conf-and-etc-hostname @@ -0,0 +1,99 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 +fi +for f in /etc/resolv.conf /etc/hostname; do + # preserve original content + cat "$f" > "$f.bak" + # in case $f is a symlink, we replace it by a real file + if [ -L "$f" ]; then + rm "$f" + cp "$f.bak" "$f" + fi + chmod 644 "$f" + [ "$(stat --format=%A "$f")" = "-rw-r--r--" ] +done +{{ CMD }} --variant=custom --mode={{ MODE }} {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +for f in /etc/resolv.conf /etc/hostname; do + [ "$(stat --format=%A "/tmp/debian-chroot/$f")" = "-rw-r--r--" ] +done +rm /tmp/debian-chroot/dev/console +rm /tmp/debian-chroot/dev/fd +rm /tmp/debian-chroot/dev/full +rm /tmp/debian-chroot/dev/null +rm /tmp/debian-chroot/dev/ptmx +rm /tmp/debian-chroot/dev/random +rm /tmp/debian-chroot/dev/stderr +rm /tmp/debian-chroot/dev/stdin +rm /tmp/debian-chroot/dev/stdout +rm /tmp/debian-chroot/dev/tty +rm /tmp/debian-chroot/dev/urandom +rm /tmp/debian-chroot/dev/zero +rm /tmp/debian-chroot/etc/apt/sources.list +rm /tmp/debian-chroot/etc/fstab +rm /tmp/debian-chroot/etc/hostname +rm /tmp/debian-chroot/etc/resolv.conf +rm /tmp/debian-chroot/var/lib/apt/lists/lock +rm /tmp/debian-chroot/var/lib/dpkg/status +# the rest should be empty directories that we can rmdir recursively +find /tmp/debian-chroot -depth -print0 | xargs -0 rmdir +for f in /etc/resolv.conf /etc/hostname; do + chmod 755 "$f" + [ "$(stat --format=%A "$f")" = "-rwxr-xr-x" ] +done +{{ CMD }} --variant=custom --mode={{ MODE }} {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +for f in /etc/resolv.conf /etc/hostname; do + [ "$(stat --format=%A "/tmp/debian-chroot/$f")" = "-rwxr-xr-x" ] +done +rm /tmp/debian-chroot/dev/console +rm /tmp/debian-chroot/dev/fd +rm /tmp/debian-chroot/dev/full +rm /tmp/debian-chroot/dev/null +rm /tmp/debian-chroot/dev/ptmx +rm /tmp/debian-chroot/dev/random +rm /tmp/debian-chroot/dev/stderr +rm /tmp/debian-chroot/dev/stdin +rm /tmp/debian-chroot/dev/stdout +rm /tmp/debian-chroot/dev/tty +rm /tmp/debian-chroot/dev/urandom +rm /tmp/debian-chroot/dev/zero +rm /tmp/debian-chroot/etc/apt/sources.list +rm /tmp/debian-chroot/etc/fstab +rm /tmp/debian-chroot/etc/hostname +rm /tmp/debian-chroot/etc/resolv.conf +rm /tmp/debian-chroot/var/lib/apt/lists/lock +rm /tmp/debian-chroot/var/lib/dpkg/status +# the rest should be empty directories that we can rmdir recursively +find /tmp/debian-chroot -depth -print0 | xargs -0 rmdir +for f in /etc/resolv.conf /etc/hostname; do + rm "$f" + ln -s "$f.bak" "$f" + [ "$(stat --format=%A "$f")" = "lrwxrwxrwx" ] +done +{{ CMD }} --variant=custom --mode={{ MODE }} {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +for f in /etc/resolv.conf /etc/hostname; do + [ "$(stat --format=%A "/tmp/debian-chroot/$f")" = "-rw-r--r--" ] +done +rm /tmp/debian-chroot/dev/console +rm /tmp/debian-chroot/dev/fd +rm /tmp/debian-chroot/dev/full +rm /tmp/debian-chroot/dev/null +rm /tmp/debian-chroot/dev/ptmx +rm /tmp/debian-chroot/dev/random +rm /tmp/debian-chroot/dev/stderr +rm /tmp/debian-chroot/dev/stdin +rm /tmp/debian-chroot/dev/stdout +rm /tmp/debian-chroot/dev/tty +rm /tmp/debian-chroot/dev/urandom +rm /tmp/debian-chroot/dev/zero +rm /tmp/debian-chroot/etc/apt/sources.list +rm /tmp/debian-chroot/etc/fstab +rm /tmp/debian-chroot/etc/hostname +rm /tmp/debian-chroot/etc/resolv.conf +rm /tmp/debian-chroot/var/lib/apt/lists/lock +rm /tmp/debian-chroot/var/lib/dpkg/status +# the rest should be empty directories that we can rmdir recursively +find /tmp/debian-chroot -depth -print0 | xargs -0 rmdir diff --git a/tests/progress-bars-on-fake-tty b/tests/progress-bars-on-fake-tty new file mode 100644 index 0000000..05c2e7a --- /dev/null +++ b/tests/progress-bars-on-fake-tty @@ -0,0 +1,6 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rm -f /tmp/debian-chroot.tar" EXIT INT TERM +script -qfc "{{ CMD }} --mode={{ MODE }} --variant=apt {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }}" /dev/null +tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - diff --git a/tests/quiet b/tests/quiet new file mode 100644 index 0000000..d1cbb22 --- /dev/null +++ b/tests/quiet @@ -0,0 +1,6 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +{{ CMD }} --mode=root --variant=apt --quiet {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - +rm -r /tmp/debian-chroot diff --git a/tests/read-from-stdin-write-to-stdout b/tests/read-from-stdin-write-to-stdout new file mode 100644 index 0000000..960cd3a --- /dev/null +++ b/tests/read-from-stdin-write-to-stdout @@ -0,0 +1,6 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rm /tmp/debian-chroot.tar" EXIT INT TERM +echo "deb {{ MIRROR }} {{ DIST }} main" | {{ CMD }} --mode={{ MODE }} --variant=apt > /tmp/debian-chroot.tar +tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - diff --git a/tests/remove-start-stop-daemon-and-policy-rc-d-in-hook b/tests/remove-start-stop-daemon-and-policy-rc-d-in-hook new file mode 100644 index 0000000..74648da --- /dev/null +++ b/tests/remove-start-stop-daemon-and-policy-rc-d-in-hook @@ -0,0 +1,6 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rm -f /tmp/debian-chroot.tar" EXIT INT TERM +{{ CMD }} --mode={{ MODE }} --variant=apt --customize-hook='rm "$1/usr/sbin/policy-rc.d"; rm "$1/sbin/start-stop-daemon"' {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }} +tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - diff --git a/tests/root-mode-inside-chroot b/tests/root-mode-inside-chroot new file mode 100644 index 0000000..d145773 --- /dev/null +++ b/tests/root-mode-inside-chroot @@ -0,0 +1,26 @@ +#!/bin/sh +# +# Same as unshare-as-root-user-inside-chroot but this time we run mmdebstrap in +# root mode from inside a chroot + +set -eu +export LC_ALL=C.UTF-8 +[ "$(whoami)" = "root" ] +cat << 'SCRIPT' > script.sh +#!/bin/sh +set -eu +rootfs="$1" +mkdir -p "$rootfs/mnt" +[ -e /usr/bin/mmdebstrap ] && cp -aT /usr/bin/mmdebstrap "$rootfs/usr/bin/mmdebstrap" +[ -e ./mmdebstrap ] && cp -aT ./mmdebstrap "$rootfs/mnt/mmdebstrap" +chroot "$rootfs" env --chdir=/mnt \ + {{ CMD }} --mode=root --variant=apt \ + {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }} +SCRIPT +chmod +x script.sh +{{ CMD }} --mode=root --variant=apt --include=perl,mount \ + --customize-hook=./script.sh \ + --customize-hook="download /tmp/debian-chroot.tar /tmp/debian-chroot.tar" \ + {{ DIST }} /dev/null {{ MIRROR }} +tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - +rm /tmp/debian-chroot.tar script.sh diff --git a/tests/root-mode-inside-unshare-chroot b/tests/root-mode-inside-unshare-chroot new file mode 100644 index 0000000..e552346 --- /dev/null +++ b/tests/root-mode-inside-unshare-chroot @@ -0,0 +1,32 @@ +#!/bin/sh +# +# Same as root-mode-inside-chroot but this time we run mmdebstrap in root mode +# from inside an unshare chroot. + +set -eu +export LC_ALL=C.UTF-8 +if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 +fi +[ "$(whoami)" = "root" ] +adduser --gecos user --disabled-password user +sysctl -w kernel.unprivileged_userns_clone=1 +cat << 'SCRIPT' > script.sh +#!/bin/sh +set -eu +rootfs="$1" +mkdir -p "$rootfs/mnt" +[ -e /usr/bin/mmdebstrap ] && cp -aT /usr/bin/mmdebstrap "$rootfs/usr/bin/mmdebstrap" +[ -e ./mmdebstrap ] && cp -aT ./mmdebstrap "$rootfs/mnt/mmdebstrap" +chroot "$rootfs" env --chdir=/mnt \ + {{ CMD }} --mode=root --variant=apt \ + {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }} +SCRIPT +chmod +x script.sh +runuser -u user -- {{ CMD }} --mode=unshare --variant=apt --include=perl,mount \ + --customize-hook=./script.sh \ + --customize-hook="download /tmp/debian-chroot.tar /tmp/debian-chroot.tar" \ + {{ DIST }} /dev/null {{ MIRROR }} +tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - +rm /tmp/debian-chroot.tar script.sh diff --git a/tests/root-without-cap-sys-admin b/tests/root-without-cap-sys-admin new file mode 100644 index 0000000..419f7b3 --- /dev/null +++ b/tests/root-without-cap-sys-admin @@ -0,0 +1,17 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +[ "$(whoami)" = "root" ] + +if grep --null-data --quiet --no-messages '^container=lxc$' /proc/1/environ; then + # see https://stackoverflow.com/questions/65748254/ + echo "cannot run under lxc -- Skipping test..." >&2 + exit 0 +fi + +capsh --drop=cap_sys_admin -- -c 'exec "$@"' exec \ + {{ CMD }} --mode=root --variant=apt \ + --customize-hook='chroot "$1" sh -c "test ! -e /proc/self/fd"' \ + {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }} +tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - +rm /tmp/debian-chroot.tar diff --git a/tests/sigint-during-customize-hook b/tests/sigint-during-customize-hook new file mode 100644 index 0000000..6eba0de --- /dev/null +++ b/tests/sigint-during-customize-hook @@ -0,0 +1,21 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +setsid --wait {{ CMD }} --mode=root --variant=apt --customize-hook='touch done && sleep 10 && touch fail' {{ DIST }} /tmp/debian-chroot {{ MIRROR }} & +pid=$! +while sleep 1; do [ -e done ] && break; done +rm done +pgid=$(echo $(ps -p $pid -o pgid=)) +/bin/kill --signal INT -- -$pgid +ret=0 +wait $pid || ret=$? +rm -r /tmp/debian-chroot +if [ -e fail ]; then + echo customize hook was not interrupted >&2 + rm fail + exit 1 +fi +if [ "$ret" = 0 ]; then + echo expected failure but got exit $ret >&2 + exit 1 +fi diff --git a/tests/signed-by-with-host-keys b/tests/signed-by-with-host-keys new file mode 100644 index 0000000..ef0d8c7 --- /dev/null +++ b/tests/signed-by-with-host-keys @@ -0,0 +1,7 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rm -rf /tmp/debian-chroot" EXIT INT TERM +{{ CMD }} --mode=root --variant=apt {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +printf 'deb {{ MIRROR }} {{ DIST }} main\n' | cmp /tmp/debian-chroot/etc/apt/sources.list - +tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - diff --git a/tests/signed-by-without-host-keys b/tests/signed-by-without-host-keys new file mode 100644 index 0000000..ec630de --- /dev/null +++ b/tests/signed-by-without-host-keys @@ -0,0 +1,12 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 +fi +rm /etc/apt/trusted.gpg.d/*.gpg +{{ CMD }} --mode=root --variant=apt {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +printf 'deb [signed-by="/usr/share/keyrings/debian-archive-keyring.gpg"] {{ MIRROR }} {{ DIST }} main\n' | cmp /tmp/debian-chroot/etc/apt/sources.list - +tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - +rm -r /tmp/debian-chroot diff --git a/tests/special-hooks-using-helpers b/tests/special-hooks-using-helpers new file mode 100644 index 0000000..c0180ad --- /dev/null +++ b/tests/special-hooks-using-helpers @@ -0,0 +1,27 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +mkfifo /tmp/myfifo +mkdir /tmp/root +ln -s /real /tmp/root/link +mkdir /tmp/root/real +run_testA() { + echo content > /tmp/foo + { { { {{ CMD }} --hook-helper /tmp/root root setup env 1 upload /tmp/foo $1 < /tmp/myfifo 3>&-; echo $? >&3; printf "\\000\\000adios"; + } | {{ CMD }} --hook-listener 1 3>&- >/tmp/myfifo; echo $?; } 3>&1; + } | { read xs1; [ "$xs1" -eq 0 ]; read xs2; [ "$xs2" -eq 0 ]; } + echo content | diff -u - /tmp/root/real/foo + rm /tmp/foo + rm /tmp/root/real/foo +} +run_testA link/foo +run_testA /link/foo +run_testA ///link///foo/// +run_testA /././link/././foo/././ +run_testA /link/../link/foo +run_testA /link/../../link/foo +run_testA /../../link/foo +rmdir /tmp/root/real +rm /tmp/root/link +rmdir /tmp/root +rm /tmp/myfifo diff --git a/tests/special-hooks-using-helpers-and-env-vars b/tests/special-hooks-using-helpers-and-env-vars new file mode 100644 index 0000000..a3ba90e --- /dev/null +++ b/tests/special-hooks-using-helpers-and-env-vars @@ -0,0 +1,31 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +cat << 'SCRIPT' > /tmp/script.sh +#!/bin/sh +set -eu +echo "MMDEBSTRAP_APT_CONFIG $MMDEBSTRAP_APT_CONFIG" +echo "$MMDEBSTRAP_HOOK" >> /tmp/hooks +[ "$MMDEBSTRAP_MODE" = "root" ] +echo test-content $MMDEBSTRAP_HOOK > test +{{ CMD }} --hook-helper "$1" "$MMDEBSTRAP_MODE" "$MMDEBSTRAP_HOOK" env 1 upload test /test <&$MMDEBSTRAP_HOOKSOCK >&$MMDEBSTRAP_HOOKSOCK +rm test +echo "content inside chroot:" +cat "$1/test" +[ "test-content $MMDEBSTRAP_HOOK" = "$(cat "$1/test")" ] +{{ CMD }} --hook-helper "$1" "$MMDEBSTRAP_MODE" "$MMDEBSTRAP_HOOK" env 1 download /test test <&$MMDEBSTRAP_HOOKSOCK >&$MMDEBSTRAP_HOOKSOCK +echo "content outside chroot:" +cat test +[ "test-content $MMDEBSTRAP_HOOK" = "$(cat test)" ] +rm test +SCRIPT +chmod +x /tmp/script.sh +{{ CMD }} --mode=root --variant=apt \ + --setup-hook=/tmp/script.sh \ + --extract-hook=/tmp/script.sh \ + --essential-hook=/tmp/script.sh \ + --customize-hook=/tmp/script.sh \ + {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +printf "setup\nextract\nessential\ncustomize\n" | diff -u - /tmp/hooks +rm /tmp/script.sh /tmp/hooks +rm -r /tmp/debian-chroot diff --git a/tests/special-hooks-with-mode-mode b/tests/special-hooks-with-mode-mode new file mode 100644 index 0000000..eda67bf --- /dev/null +++ b/tests/special-hooks-with-mode-mode @@ -0,0 +1,151 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +if [ "$(id -u)" -eq 0 ] && ! id -u user > /dev/null 2>&1; then + if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 + fi + adduser --gecos user --disabled-password user +fi +if [ "{{ MODE }}" = unshare ]; then + if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 + fi + sysctl -w kernel.unprivileged_userns_clone=1 +fi +prefix= +[ "$(id -u)" -eq 0 ] && [ "{{ MODE }}" != "root" ] && prefix="runuser -u user --" +[ "{{ MODE }}" = "fakechroot" ] && prefix="$prefix fakechroot fakeroot" +symlinktarget=/real +case {{ MODE }} in fakechroot|proot) symlinktarget='$1/real';; esac +echo copy-in-setup > /tmp/copy-in-setup +echo copy-in-essential > /tmp/copy-in-essential +echo copy-in-customize > /tmp/copy-in-customize +echo tar-in-setup > /tmp/tar-in-setup +echo tar-in-essential > /tmp/tar-in-essential +echo tar-in-customize > /tmp/tar-in-customize +tar --numeric-owner --format=pax --pax-option=exthdr.name=%d/PaxHeaders/%f,delete=atime,delete=ctime -C /tmp -cf /tmp/tar-in-setup.tar tar-in-setup +tar --numeric-owner --format=pax --pax-option=exthdr.name=%d/PaxHeaders/%f,delete=atime,delete=ctime -C /tmp -cf /tmp/tar-in-essential.tar tar-in-essential +tar --numeric-owner --format=pax --pax-option=exthdr.name=%d/PaxHeaders/%f,delete=atime,delete=ctime -C /tmp -cf /tmp/tar-in-customize.tar tar-in-customize +rm /tmp/tar-in-setup +rm /tmp/tar-in-essential +rm /tmp/tar-in-customize +echo upload-setup > /tmp/upload-setup +echo upload-essential > /tmp/upload-essential +echo upload-customize > /tmp/upload-customize +mkdir /tmp/sync-in-setup +mkdir /tmp/sync-in-essential +mkdir /tmp/sync-in-customize +echo sync-in-setup > /tmp/sync-in-setup/file +echo sync-in-essential > /tmp/sync-in-essential/file +echo sync-in-customize > /tmp/sync-in-customize/file +$prefix {{ CMD }} --mode={{ MODE }} --variant=apt \ + --setup-hook='mkdir "$1/real"' \ + --setup-hook='copy-in /tmp/copy-in-setup /real' \ + --setup-hook='echo copy-in-setup | cmp "$1/real/copy-in-setup" -' \ + --setup-hook='rm "$1/real/copy-in-setup"' \ + --setup-hook='echo copy-out-setup > "$1/real/copy-out-setup"' \ + --setup-hook='copy-out /real/copy-out-setup /tmp' \ + --setup-hook='rm "$1/real/copy-out-setup"' \ + --setup-hook='tar-in /tmp/tar-in-setup.tar /real' \ + --setup-hook='echo tar-in-setup | cmp "$1/real/tar-in-setup" -' \ + --setup-hook='tar-out /real/tar-in-setup /tmp/tar-out-setup.tar' \ + --setup-hook='rm "$1"/real/tar-in-setup' \ + --setup-hook='upload /tmp/upload-setup /real/upload' \ + --setup-hook='echo upload-setup | cmp "$1/real/upload" -' \ + --setup-hook='download /real/upload /tmp/download-setup' \ + --setup-hook='rm "$1/real/upload"' \ + --setup-hook='sync-in /tmp/sync-in-setup /real' \ + --setup-hook='echo sync-in-setup | cmp "$1/real/file" -' \ + --setup-hook='sync-out /real /tmp/sync-out-setup' \ + --setup-hook='rm "$1/real/file"' \ + --essential-hook='ln -s "'"$symlinktarget"'" "$1/symlink"' \ + --essential-hook='copy-in /tmp/copy-in-essential /symlink' \ + --essential-hook='echo copy-in-essential | cmp "$1/real/copy-in-essential" -' \ + --essential-hook='rm "$1/real/copy-in-essential"' \ + --essential-hook='echo copy-out-essential > "$1/real/copy-out-essential"' \ + --essential-hook='copy-out /symlink/copy-out-essential /tmp' \ + --essential-hook='rm "$1/real/copy-out-essential"' \ + --essential-hook='tar-in /tmp/tar-in-essential.tar /symlink' \ + --essential-hook='echo tar-in-essential | cmp "$1/real/tar-in-essential" -' \ + --essential-hook='tar-out /symlink/tar-in-essential /tmp/tar-out-essential.tar' \ + --essential-hook='rm "$1"/real/tar-in-essential' \ + --essential-hook='upload /tmp/upload-essential /symlink/upload' \ + --essential-hook='echo upload-essential | cmp "$1/real/upload" -' \ + --essential-hook='download /symlink/upload /tmp/download-essential' \ + --essential-hook='rm "$1/real/upload"' \ + --essential-hook='sync-in /tmp/sync-in-essential /symlink' \ + --essential-hook='echo sync-in-essential | cmp "$1/real/file" -' \ + --essential-hook='sync-out /real /tmp/sync-out-essential' \ + --essential-hook='rm "$1/real/file"' \ + --customize-hook='copy-in /tmp/copy-in-customize /symlink' \ + --customize-hook='echo copy-in-customize | cmp "$1/real/copy-in-customize" -' \ + --customize-hook='rm "$1/real/copy-in-customize"' \ + --customize-hook='echo copy-out-customize > "$1/real/copy-out-customize"' \ + --customize-hook='copy-out /symlink/copy-out-customize /tmp' \ + --customize-hook='rm "$1/real/copy-out-customize"' \ + --customize-hook='tar-in /tmp/tar-in-customize.tar /symlink' \ + --customize-hook='echo tar-in-customize | cmp "$1/real/tar-in-customize" -' \ + --customize-hook='tar-out /symlink/tar-in-customize /tmp/tar-out-customize.tar' \ + --customize-hook='rm "$1"/real/tar-in-customize' \ + --customize-hook='upload /tmp/upload-customize /symlink/upload' \ + --customize-hook='echo upload-customize | cmp "$1/real/upload" -' \ + --customize-hook='download /symlink/upload /tmp/download-customize' \ + --customize-hook='rm "$1/real/upload"' \ + --customize-hook='sync-in /tmp/sync-in-customize /symlink' \ + --customize-hook='echo sync-in-customize | cmp "$1/real/file" -' \ + --customize-hook='sync-out /real /tmp/sync-out-customize' \ + --customize-hook='rm "$1/real/file"' \ + --customize-hook='rmdir "$1/real"' \ + --customize-hook='rm "$1/symlink"' \ + {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }} +for n in setup essential customize; do + ret=0 + cmp /tmp/tar-in-$n.tar /tmp/tar-out-$n.tar || ret=$? + if [ "$ret" -ne 0 ]; then + if type diffoscope >/dev/null; then + diffoscope /tmp/tar-in-$n.tar /tmp/tar-out-$n.tar + exit 1 + else + echo "no diffoscope installed" >&2 + fi + if type base64 >/dev/null; then + base64 /tmp/tar-in-$n.tar + base64 /tmp/tar-out-$n.tar + exit 1 + else + echo "no base64 installed" >&2 + fi + if type xxd >/dev/null; then + xxd /tmp/tar-in-$n.tar + xxd /tmp/tar-out-$n.tar + exit 1 + else + echo "no xxd installed" >&2 + fi + exit 1 + fi +done +echo copy-out-setup | cmp /tmp/copy-out-setup - +echo copy-out-essential | cmp /tmp/copy-out-essential - +echo copy-out-customize | cmp /tmp/copy-out-customize - +echo upload-setup | cmp /tmp/download-setup - +echo upload-essential | cmp /tmp/download-essential - +echo upload-customize | cmp /tmp/download-customize - +echo sync-in-setup | cmp /tmp/sync-out-setup/file - +echo sync-in-essential | cmp /tmp/sync-out-essential/file - +echo sync-in-customize | cmp /tmp/sync-out-customize/file - +tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - +rm /tmp/debian-chroot.tar \ + /tmp/copy-in-setup /tmp/copy-in-essential /tmp/copy-in-customize \ + /tmp/copy-out-setup /tmp/copy-out-essential /tmp/copy-out-customize \ + /tmp/tar-in-setup.tar /tmp/tar-in-essential.tar /tmp/tar-in-customize.tar \ + /tmp/tar-out-setup.tar /tmp/tar-out-essential.tar /tmp/tar-out-customize.tar \ + /tmp/upload-setup /tmp/upload-essential /tmp/upload-customize \ + /tmp/download-setup /tmp/download-essential /tmp/download-customize \ + /tmp/sync-in-setup/file /tmp/sync-in-essential/file /tmp/sync-in-customize/file \ + /tmp/sync-out-setup/file /tmp/sync-out-essential/file /tmp/sync-out-customize/file +rmdir /tmp/sync-in-setup /tmp/sync-in-essential /tmp/sync-in-customize \ + /tmp/sync-out-setup /tmp/sync-out-essential /tmp/sync-out-customize diff --git a/tests/stable-default-mirror b/tests/stable-default-mirror new file mode 100644 index 0000000..c79f9d6 --- /dev/null +++ b/tests/stable-default-mirror @@ -0,0 +1,20 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 +fi +cat << HOSTS >> /etc/hosts +127.0.0.1 deb.debian.org +127.0.0.1 security.debian.org +HOSTS +apt-cache policy +cat /etc/apt/sources.list +{{ CMD }} --mode=root --variant=apt stable /tmp/debian-chroot +cat << SOURCES | cmp /tmp/debian-chroot/etc/apt/sources.list +deb http://deb.debian.org/debian stable main +deb http://deb.debian.org/debian stable-updates main +deb http://security.debian.org/debian-security stable-security main +SOURCES +rm -r /tmp/debian-chroot diff --git a/tests/supply-components-manually b/tests/supply-components-manually new file mode 100644 index 0000000..038b5dc --- /dev/null +++ b/tests/supply-components-manually @@ -0,0 +1,7 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rm -rf /tmp/debian-chroot" EXIT INT TERM +{{ CMD }} --mode={{ MODE }} --variant=apt --components="main main" --comp="main,main" {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +echo "deb {{ MIRROR }} {{ DIST }} main" | cmp /tmp/debian-chroot/etc/apt/sources.list +tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - diff --git a/tests/taridshift-utility b/tests/taridshift-utility new file mode 100644 index 0000000..a945d6a --- /dev/null +++ b/tests/taridshift-utility @@ -0,0 +1,59 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 +fi +trap "rm -f /tmp/debian-chroot.tar /tmp/debian-chroot-shifted.tar /tmp/debian-chroot.txt /tmp/debian-chroot-shiftedback.tar /tmp/expected; rm -rf /tmp/debian-chroot" EXIT INT TERM +adduser --gecos user --disabled-password user +echo user:100000:65536 | cmp /etc/subuid - +echo user:100000:65536 | cmp /etc/subgid - +sysctl -w kernel.unprivileged_userns_clone=1 +# include iputils-ping so that we can verify that taridshift does not remove +# extended attributes +# run through tarshift no-op to create a tarball that should be bit-by-bit +# identical to a round trip through "taridshift X" and "taridshift -X" +runuser -u user -- {{ CMD }} --mode=unshare --variant=apt --include=iputils-ping {{ DIST }} - {{ MIRROR }} \ + | ./taridshift 0 > /tmp/debian-chroot.tar +# make sure that xattrs are set in the original tarball +mkdir /tmp/debian-chroot +tar --xattrs --xattrs-include='*' --directory /tmp/debian-chroot -xf /tmp/debian-chroot.tar ./bin/ping +echo "/tmp/debian-chroot/bin/ping cap_net_raw=ep" > /tmp/expected +getcap /tmp/debian-chroot/bin/ping | diff -u /tmp/expected - +rm /tmp/debian-chroot/bin/ping +rmdir /tmp/debian-chroot/bin +rmdir /tmp/debian-chroot +# shift the uid/gid forward by 100000 and backward by 100000 +./taridshift 100000 < /tmp/debian-chroot.tar > /tmp/debian-chroot-shifted.tar +./taridshift -100000 < /tmp/debian-chroot-shifted.tar > /tmp/debian-chroot-shiftedback.tar +# the tarball before and after the roundtrip through taridshift should be bit +# by bit identical +cmp /tmp/debian-chroot.tar /tmp/debian-chroot-shiftedback.tar +# manually adjust uid/gid and compare "tar -t" output +tar --numeric-owner -tvf /tmp/debian-chroot.tar \ + | sed 's# 100/0 # 100100/100000 #' \ + | sed 's# 100/8 # 100100/100008 #' \ + | sed 's# 0/0 # 100000/100000 #' \ + | sed 's# 0/5 # 100000/100005 #' \ + | sed 's# 0/8 # 100000/100008 #' \ + | sed 's# 0/42 # 100000/100042 #' \ + | sed 's# 0/43 # 100000/100043 #' \ + | sed 's# 0/50 # 100000/100050 #' \ + | sed 's/ \+/ /g' \ + > /tmp/debian-chroot.txt +tar --numeric-owner -tvf /tmp/debian-chroot-shifted.tar \ + | sed 's/ \+/ /g' \ + | diff -u /tmp/debian-chroot.txt - +mkdir /tmp/debian-chroot +tar --xattrs --xattrs-include='*' --directory /tmp/debian-chroot -xf /tmp/debian-chroot-shifted.tar +echo "100000 100000" > /tmp/expected +stat --format="%u %g" /tmp/debian-chroot/bin/ping | diff -u /tmp/expected - +echo "/tmp/debian-chroot/bin/ping cap_net_raw=ep" > /tmp/expected +getcap /tmp/debian-chroot/bin/ping | diff -u /tmp/expected - +echo "0 0" > /tmp/expected +runuser -u user -- {{ CMD }} --unshare-helper /usr/sbin/chroot /tmp/debian-chroot stat --format="%u %g" /bin/ping \ + | diff -u /tmp/expected - +echo "/bin/ping cap_net_raw=ep" > /tmp/expected +runuser -u user -- {{ CMD }} --unshare-helper /usr/sbin/chroot /tmp/debian-chroot getcap /bin/ping \ + | diff -u /tmp/expected - diff --git a/tests/unpack-doc-debian b/tests/unpack-doc-debian new file mode 100644 index 0000000..246f608 --- /dev/null +++ b/tests/unpack-doc-debian @@ -0,0 +1,55 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +if [ "$(id -u)" -eq 0 ] && ! id -u user > /dev/null 2>&1; then + if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 + fi + adduser --gecos user --disabled-password user +fi +if [ "{{ MODE }}" = unshare ]; then + if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 + fi + sysctl -w kernel.unprivileged_userns_clone=1 +fi +prefix= +[ "$(id -u)" -eq 0 ] && [ "{{ MODE }}" != "root" ] && prefix="runuser -u user --" +[ "{{ MODE }}" = "fakechroot" ] && prefix="$prefix fakechroot fakeroot" +$prefix {{ CMD }} --mode={{ MODE }} --variant=extract --include=doc-debian {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +# delete contents of doc-debian +rm /tmp/debian-chroot/usr/share/doc-base/debian-* +rm -r /tmp/debian-chroot/usr/share/doc/debian +rm -r /tmp/debian-chroot/usr/share/doc/doc-debian +# delete real files +rm /tmp/debian-chroot/etc/apt/sources.list +rm /tmp/debian-chroot/etc/fstab +rm /tmp/debian-chroot/etc/hostname +rm /tmp/debian-chroot/etc/resolv.conf +rm /tmp/debian-chroot/var/lib/dpkg/status +rm /tmp/debian-chroot/var/cache/apt/archives/lock +rm /tmp/debian-chroot/var/lib/apt/lists/lock +## delete merged usr symlinks +#rm /tmp/debian-chroot/libx32 +#rm /tmp/debian-chroot/lib64 +#rm /tmp/debian-chroot/lib32 +#rm /tmp/debian-chroot/sbin +#rm /tmp/debian-chroot/bin +#rm /tmp/debian-chroot/lib +# delete ./dev (files might exist or not depending on the mode) +rm -f /tmp/debian-chroot/dev/console +rm -f /tmp/debian-chroot/dev/fd +rm -f /tmp/debian-chroot/dev/full +rm -f /tmp/debian-chroot/dev/null +rm -f /tmp/debian-chroot/dev/ptmx +rm -f /tmp/debian-chroot/dev/random +rm -f /tmp/debian-chroot/dev/stderr +rm -f /tmp/debian-chroot/dev/stdin +rm -f /tmp/debian-chroot/dev/stdout +rm -f /tmp/debian-chroot/dev/tty +rm -f /tmp/debian-chroot/dev/urandom +rm -f /tmp/debian-chroot/dev/zero +# the rest should be empty directories that we can rmdir recursively +find /tmp/debian-chroot -depth -print0 | xargs -0 rmdir diff --git a/tests/unshare-as-root-user b/tests/unshare-as-root-user new file mode 100644 index 0000000..e1ba4d6 --- /dev/null +++ b/tests/unshare-as-root-user @@ -0,0 +1,9 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +[ "$(whoami)" = "root" ] +trap "rm -f /tmp/debian-chroot.tar" EXIT INT TERM +{{ CMD }} --mode=unshare --variant=apt \ + --customize-hook='chroot "$1" sh -c "test -e /proc/self/fd"' \ + {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }} +tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - diff --git a/tests/unshare-as-root-user-inside-chroot b/tests/unshare-as-root-user-inside-chroot new file mode 100644 index 0000000..9c0eb0d --- /dev/null +++ b/tests/unshare-as-root-user-inside-chroot @@ -0,0 +1,28 @@ +#!/bin/sh +# +# Before running unshare mode as root, we run "unshare --mount" but that fails +# if mmdebstrap itself is executed from within a chroot: +# unshare: cannot change root filesystem propagation: Invalid argument +# This test tests the workaround in mmdebstrap using --propagation unchanged + +set -eu +export LC_ALL=C.UTF-8 +[ "$(whoami)" = "root" ] +trap "rm -f /tmp/debian-chroot.tar script.sh" EXIT INT TERM +cat << 'SCRIPT' > script.sh +#!/bin/sh +set -eu +rootfs="$1" +mkdir -p "$rootfs/mnt" +[ -e /usr/bin/mmdebstrap ] && cp -aT /usr/bin/mmdebstrap "$rootfs/usr/bin/mmdebstrap" +[ -e ./mmdebstrap ] && cp -aT ./mmdebstrap "$rootfs/mnt/mmdebstrap" +chroot "$rootfs" env --chdir=/mnt \ + {{ CMD }} --mode=unshare --variant=apt \ + {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }} +SCRIPT +chmod +x script.sh +{{ CMD }} --mode=root --variant=apt --include=perl,mount \ + --customize-hook=./script.sh \ + --customize-hook="download /tmp/debian-chroot.tar /tmp/debian-chroot.tar" \ + {{ DIST }} /dev/null {{ MIRROR }} +tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt - diff --git a/tests/verbose b/tests/verbose new file mode 100644 index 0000000..1388e19 --- /dev/null +++ b/tests/verbose @@ -0,0 +1,6 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +{{ CMD }} --mode=root --variant=apt --verbose {{ DIST }} /tmp/debian-chroot {{ MIRROR }} +tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort | diff -u tar1.txt - +rm -r /tmp/debian-chroot diff --git a/tests/version b/tests/version new file mode 100644 index 0000000..a8c3e45 --- /dev/null +++ b/tests/version @@ -0,0 +1,6 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +# we redirect to /dev/null instead of using --quiet to not cause a broken pipe +# when grep exits before mmdebstrap was able to write all its output +{{ CMD }} --version | egrep '^mmdebstrap [0-9](\.[0-9])+$' >/dev/null diff --git a/tests/without-etc-resolv-conf-and-etc-hostname b/tests/without-etc-resolv-conf-and-etc-hostname new file mode 100644 index 0000000..1d3dfef --- /dev/null +++ b/tests/without-etc-resolv-conf-and-etc-hostname @@ -0,0 +1,14 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +if [ ! -e /mmdebstrap-testenv ]; then + echo "this test modifies the system and should only be run inside a container" >&2 + exit 1 +fi +trap "rm -f /tmp/debian-chroot.tar" EXIT INT TERM +rm /etc/resolv.conf /etc/hostname +{{ CMD }} --mode={{ MODE }} --variant=apt {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }} +{ tar -tf /tmp/debian-chroot.tar; + printf "./etc/hostname\n"; + printf "./etc/resolv.conf\n"; +} | sort | diff -u tar1.txt - diff --git a/tests/xz-compressed-tarball b/tests/xz-compressed-tarball new file mode 100644 index 0000000..6dc6a37 --- /dev/null +++ b/tests/xz-compressed-tarball @@ -0,0 +1,7 @@ +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +trap "rm -f /tmp/debian-chroot.tar.xz" EXIT INT TERM +{{ CMD }} --mode={{ MODE }} --variant=apt {{ DIST }} /tmp/debian-chroot.tar.xz {{ MIRROR }} +printf '\3757zXZ\0' | cmp --bytes=6 /tmp/debian-chroot.tar.xz - +tar -tf /tmp/debian-chroot.tar.xz | sort | diff -u tar1.txt -