You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
mmdebstrap/coverage.sh

3758 lines
124 KiB
Bash

6 years ago
#!/bin/sh
set -eu
if [ -e ./mmdebstrap -a -e ./taridshift -a -e ./tarfilter ]; then
TMPFILE=$(mktemp)
perltidy < ./mmdebstrap > "$TMPFILE"
ret=0
diff -u ./mmdebstrap "$TMPFILE" || ret=$?
if [ "$ret" -ne 0 ]; then
echo "perltidy failed" >&2
rm "$TMPFILE"
exit 1
fi
rm "$TMPFILE"
if [ $(sed -e '/^__END__$/,$d' ./mmdebstrap | wc --max-line-length) -gt 79 ]; then
echo "exceeded maximum line length of 79 characters" >&2
exit 1
fi
perlcritic --severity 4 --verbose 8 ./mmdebstrap
black --check ./taridshift ./tarfilter
fi
mirrordir="./shared/cache/debian"
if [ ! -e "$mirrordir" ]; then
echo "run ./make_mirror.sh before running $0" >&2
exit 1
fi
# we use -f because the file might not exist
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
guestfish -N shared/cover_db.img=disk:64M -- mkfs vfat /dev/sda
if [ ! -e "./shared/cache/debian-$DEFAULT_DIST.qcow" ]; then
echo "./shared/cache/debian-$DEFAULT_DIST.qcow does not exist" >&2
exit 1
fi
fi
# check if all required debootstrap tarballs exist
notfound=0
for dist in oldstable stable testing unstable; do
for variant in minbase buildd -; do
if [ ! -e "shared/cache/debian-$dist-$variant.tar" ]; then
echo "shared/cache/debian-$dist-$variant.tar does not exist" >&2
notfound=1
fi
done
done
if [ "$notfound" -ne 0 ]; then
echo "not all required debootstrap tarballs are present" >&2
exit 1
fi
# only copy if necessary
if [ ! -e shared/mmdebstrap ] || [ mmdebstrap -nt shared/mmdebstrap ]; then
if [ -e ./mmdebstrap ]; then
cp -a mmdebstrap shared
else
cp -a /usr/bin/mmdebstrap shared
fi
fi
if [ ! -e shared/taridshift ] || [ taridshift -nt shared/taridshift ]; then
if [ -e ./taridshift ]; then
cp -a ./taridshift shared
else
cp -a /usr/bin/mmtaridshift shared/taridshift
fi
fi
if [ ! -e shared/tarfilter ] || [ tarfilter -nt shared/tarfilter ]; then
if [ -e ./tarfilter ]; then
cp -a tarfilter shared
else
cp -a /usr/bin/mmtarfilter shared/tarfilter
fi
fi
if [ ! -e shared/proxysolver ] || [ proxysolver -nt shared/proxysolver ]; then
if [ -e ./proxysolver ]; then
cp -a proxysolver shared
else
cp -a /usr/lib/apt/solvers/mmdebstrap-dump-solution shared/proxysolver
fi
fi
if [ ! -e shared/ldconfig.fakechroot ] || [ ldconfig.fakechroot -nt shared/ldconfig.fakechroot ]; then
if [ -e ./ldconfig.fakechroot ]; then
cp -a ldconfig.fakechroot shared
else
cp -a /usr/libexec/mmdebstrap/ldconfig.fakechroot shared/ldconfig.fakechroot
fi
fi
mkdir -p shared/hooks/merged-usr
if [ ! -e shared/hooks/merged-usr/setup00.sh ] || [ hooks/merged-usr/setup00.sh -nt shared/hooks/merged-usr/setup00.sh ]; then
if [ -e hooks/merged-usr/setup00.sh ]; then
cp -a hooks/merged-usr/setup00.sh shared/hooks/merged-usr/
else
cp -a /usr/share/mmdebstrap/hooks/merged-usr/setup00.sh shared/hooks/merged-usr/
fi
fi
mkdir -p shared/hooks/eatmydata
if [ ! -e shared/hooks/eatmydata/extract.sh ] || [ hooks/eatmydata/extract.sh -nt shared/hooks/eatmydata/extract.sh ]; then
if [ -e hooks/eatmydata/extract.sh ]; then
cp -a hooks/eatmydata/extract.sh shared/hooks/eatmydata/
else
cp -a /usr/share/mmdebstrap/hooks/eatmydata/extract.sh shared/hooks/eatmydata/
fi
fi
if [ ! -e shared/hooks/eatmydata/customize.sh ] || [ hooks/eatmydata/customize.sh -nt shared/hooks/eatmydata/customize.sh ]; then
if [ -e hooks/eatmydata/customize.sh ]; then
cp -a hooks/eatmydata/customize.sh shared/hooks/eatmydata/
else
cp -a /usr/share/mmdebstrap/hooks/eatmydata/customize.sh shared/hooks/eatmydata/
fi
fi
starttime=
total=213
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
SOURCE_DATE_EPOCH=$(date --date="$(grep-dctrl -s Date -n '' "$mirrordir/dists/$DEFAULT_DIST/Release")" +%s)
6 years ago
# for traditional sort order that uses native byte values
export LC_ALL=C.UTF-8
6 years ago
: "${HAVE_UNSHARE:=yes}"
: "${HAVE_PROOT:=yes}"
: "${HAVE_BINFMT:=yes}"
defaultmode="auto"
if [ "$HAVE_UNSHARE" != "yes" ]; then
defaultmode="root"
fi
# by default, use the mmdebstrap executable in the current directory together
# with perl Devel::Cover but allow to overwrite this
: "${CMD:=perl -MDevel::Cover=-silent,-nogcov ./mmdebstrap}"
mirror="http://127.0.0.1/debian"
6 years ago
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
$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
6 years ago
# 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
# 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
# check if the file content differs
diff --unified --no-dereference --recursive /tmp/debian-$dist-debootstrap /tmp/debian-$dist-mm
# 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
6 years ago
# 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
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
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
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
print_header "mode=unshare,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"
# fontconfig doesn't install reproducibly because differences
# in /var/cache/fontconfig/. See
# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=864082
if [ "$variant" = "standard" ]; then
echo "skipping test because of #864082" >&2
skipped=$((skipped+1))
continue
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
$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# 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