Compare commits
No commits in common. "7a057e37dd53c46e46e9d9fb1c25347aa77a7a46" and "b454892ddda5e1a62162dd3401f8cbad0732c4e6" have entirely different histories.
7a057e37dd
...
b454892ddd
33 changed files with 373 additions and 571 deletions
|
@ -1,9 +1,3 @@
|
||||||
1.2.3 (2022-11-16)
|
|
||||||
------------------
|
|
||||||
|
|
||||||
- use Text::ParseWords::shellwords instead of spawning a new shell
|
|
||||||
- mount and unmount once, instead for each run_chroot() call
|
|
||||||
|
|
||||||
1.2.2 (2022-10-27)
|
1.2.2 (2022-10-27)
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
|
25
coverage.py
25
coverage.py
|
@ -172,9 +172,6 @@ def main():
|
||||||
metavar="format",
|
metavar="format",
|
||||||
help=f"only run tests with this format (Default = {default_format})",
|
help=f"only run tests with this format (Default = {default_format})",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
|
||||||
"--skip", metavar="test", action="append", help="skip this test"
|
|
||||||
)
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
# copy over files from git or as distributed
|
# copy over files from git or as distributed
|
||||||
|
@ -298,21 +295,6 @@ def main():
|
||||||
line = line.replace("{{ FORMAT }}", fmt)
|
line = line.replace("{{ FORMAT }}", fmt)
|
||||||
line = line.replace("{{ HOSTARCH }}", hostarch)
|
line = line.replace("{{ HOSTARCH }}", hostarch)
|
||||||
fout.write(line)
|
fout.write(line)
|
||||||
# ignore:
|
|
||||||
# SC2016 Expressions don't expand in single quotes, use double quotes for that.
|
|
||||||
# SC2050 This expression is constant. Did you forget the $ on a variable?
|
|
||||||
# SC2194 This word is constant. Did you forget the $ on a variable?
|
|
||||||
shellcheck = subprocess.run(
|
|
||||||
[
|
|
||||||
"shellcheck",
|
|
||||||
"--exclude=SC2050,SC2194,SC2016",
|
|
||||||
"-f",
|
|
||||||
"gcc",
|
|
||||||
"shared/test.sh",
|
|
||||||
],
|
|
||||||
check=False,
|
|
||||||
stdout=subprocess.PIPE,
|
|
||||||
).stdout.decode()
|
|
||||||
argv = None
|
argv = None
|
||||||
match test:
|
match test:
|
||||||
case "qemu":
|
case "qemu":
|
||||||
|
@ -328,9 +310,6 @@ def main():
|
||||||
print(f"skipped because of {reason}", file=sys.stderr)
|
print(f"skipped because of {reason}", file=sys.stderr)
|
||||||
continue
|
continue
|
||||||
print(separator, file=sys.stderr)
|
print(separator, file=sys.stderr)
|
||||||
if args.skip and name in args.skip:
|
|
||||||
print(f"skipping because of --skip={name}", file=sys.stderr)
|
|
||||||
continue
|
|
||||||
if args.dist and args.dist != dist:
|
if args.dist and args.dist != dist:
|
||||||
print(f"skipping because of --dist={args.dist}", file=sys.stderr)
|
print(f"skipping because of --dist={args.dist}", file=sys.stderr)
|
||||||
continue
|
continue
|
||||||
|
@ -351,9 +330,7 @@ def main():
|
||||||
proc.wait()
|
proc.wait()
|
||||||
break
|
break
|
||||||
print(separator, file=sys.stderr)
|
print(separator, file=sys.stderr)
|
||||||
if proc.returncode != 0 or shellcheck != "":
|
if proc.returncode != 0:
|
||||||
if shellcheck != "":
|
|
||||||
print(shellcheck)
|
|
||||||
failed.append(
|
failed.append(
|
||||||
format_failed(
|
format_failed(
|
||||||
i + 1, len(tests), name, dist, mode, variant, fmt, config_dict
|
i + 1, len(tests), name, dist, mode, variant, fmt, config_dict
|
||||||
|
|
13
coverage.sh
13
coverage.sh
|
@ -14,7 +14,7 @@ if [ -e ./mmdebstrap ]; then
|
||||||
fi
|
fi
|
||||||
rm "$TMPFILE"
|
rm "$TMPFILE"
|
||||||
|
|
||||||
if [ "$(sed -e '/^__END__$/,$d' ./mmdebstrap | wc --max-line-length)" -gt 79 ]; then
|
if [ $(sed -e '/^__END__$/,$d' ./mmdebstrap | wc --max-line-length) -gt 79 ]; then
|
||||||
echo "exceeded maximum line length of 79 characters" >&2
|
echo "exceeded maximum line length of 79 characters" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
@ -25,8 +25,6 @@ fi
|
||||||
[ -e ./tarfilter ] && black --check ./tarfilter
|
[ -e ./tarfilter ] && black --check ./tarfilter
|
||||||
[ -e ./coverage.py ] && black --check ./coverage.py
|
[ -e ./coverage.py ] && black --check ./coverage.py
|
||||||
|
|
||||||
shellcheck --exclude=SC2016 coverage.sh make_mirror.sh run_null.sh run_qemu.sh gpgvnoexpkeysig hooks/*/*.sh
|
|
||||||
|
|
||||||
mirrordir="./shared/cache/debian"
|
mirrordir="./shared/cache/debian"
|
||||||
|
|
||||||
if [ ! -e "$mirrordir" ]; then
|
if [ ! -e "$mirrordir" ]; then
|
||||||
|
@ -77,6 +75,11 @@ export LC_ALL=C.UTF-8
|
||||||
: "${HAVE_PROOT:=yes}"
|
: "${HAVE_PROOT:=yes}"
|
||||||
: "${HAVE_BINFMT:=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
|
# by default, use the mmdebstrap executable in the current directory together
|
||||||
# with perl Devel::Cover but allow to overwrite this
|
# with perl Devel::Cover but allow to overwrite this
|
||||||
: "${CMD:=perl -MDevel::Cover=-silent,-nogcov ./mmdebstrap}"
|
: "${CMD:=perl -MDevel::Cover=-silent,-nogcov ./mmdebstrap}"
|
||||||
|
@ -100,14 +103,14 @@ cover -delete cover_db >&2
|
||||||
END
|
END
|
||||||
if [ "$HAVE_QEMU" = "yes" ]; then
|
if [ "$HAVE_QEMU" = "yes" ]; then
|
||||||
./run_qemu.sh
|
./run_qemu.sh
|
||||||
elif [ "$HAVE_UNSHARE" != "yes" ]; then
|
elif [ "$mode" = "root" ]; then
|
||||||
./run_null.sh SUDO
|
./run_null.sh SUDO
|
||||||
else
|
else
|
||||||
./run_null.sh
|
./run_null.sh
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo
|
echo
|
||||||
echo "open file://$(pwd)/shared/report/coverage.html in a browser"
|
echo open file://$(pwd)/shared/report/coverage.html in a browser
|
||||||
echo
|
echo
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
|
@ -291,14 +291,12 @@ Variants: custom
|
||||||
Test: chrootless
|
Test: chrootless
|
||||||
Variants: essential
|
Variants: essential
|
||||||
Modes: chrootless
|
Modes: chrootless
|
||||||
Needs-Root: true
|
|
||||||
Skip-If:
|
Skip-If:
|
||||||
dist in ["oldstable", "stable"]
|
dist in ["oldstable", "stable"]
|
||||||
|
|
||||||
Test: chrootless-fakeroot
|
Test: chrootless-fakeroot
|
||||||
Variants: essential
|
Variants: essential
|
||||||
Modes: chrootless
|
Modes: chrootless
|
||||||
Needs-QEMU: true
|
|
||||||
Skip-If:
|
Skip-If:
|
||||||
dist in ["oldstable", "stable"]
|
dist in ["oldstable", "stable"]
|
||||||
|
|
||||||
|
@ -346,7 +344,3 @@ Test: error-if-stdout-is-tty
|
||||||
Test: variant-custom-timeout
|
Test: variant-custom-timeout
|
||||||
|
|
||||||
Test: include-deb-file
|
Test: include-deb-file
|
||||||
|
|
||||||
Test: pivot_root
|
|
||||||
Modes: root unshare
|
|
||||||
Needs-QEMU: true
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ if [ -e "$rootdir/var/lib/dpkg/arch" ]; then
|
||||||
else
|
else
|
||||||
chrootarch=$(dpkg --print-architecture)
|
chrootarch=$(dpkg --print-architecture)
|
||||||
fi
|
fi
|
||||||
libdir="/usr/lib/$(dpkg-architecture -a "$chrootarch" -q DEB_HOST_MULTIARCH)"
|
libdir="/usr/lib/$(dpkg-architecture -a $chrootarch -q DEB_HOST_MULTIARCH)"
|
||||||
|
|
||||||
# if eatmydata was actually installed properly, then we are not removing
|
# if eatmydata was actually installed properly, then we are not removing
|
||||||
# anything here
|
# anything here
|
||||||
|
|
|
@ -14,10 +14,8 @@ else
|
||||||
chrootarch=$(dpkg --print-architecture)
|
chrootarch=$(dpkg --print-architecture)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
trusted=
|
eval $(apt-config shell trusted Dir::Etc::trusted/f)
|
||||||
eval "$(apt-config shell trusted Dir::Etc::trusted/f)"
|
eval $(apt-config shell trustedparts Dir::Etc::trustedparts/d)
|
||||||
trustedparts=
|
|
||||||
eval "$(apt-config shell trustedparts Dir::Etc::trustedparts/d)"
|
|
||||||
tmpfile=$(mktemp --tmpdir="$rootdir/tmp")
|
tmpfile=$(mktemp --tmpdir="$rootdir/tmp")
|
||||||
cat << END > "$tmpfile"
|
cat << END > "$tmpfile"
|
||||||
Apt::Architecture "$chrootarch";
|
Apt::Architecture "$chrootarch";
|
||||||
|
@ -32,7 +30,7 @@ END
|
||||||
tmpdir=$(mktemp --directory --tmpdir="$rootdir/tmp")
|
tmpdir=$(mktemp --directory --tmpdir="$rootdir/tmp")
|
||||||
env --chdir="$tmpdir" APT_CONFIG="$tmpfile" apt-get download --print-uris eatmydata libeatmydata1 \
|
env --chdir="$tmpdir" APT_CONFIG="$tmpfile" apt-get download --print-uris eatmydata libeatmydata1 \
|
||||||
| sed -ne "s/^'\([^']\+\)'\s\+\(\S\+\)\s\+\([0-9]\+\)\s\+\(SHA256:[a-f0-9]\+\)$/\1 \2 \3 \4/p" \
|
| sed -ne "s/^'\([^']\+\)'\s\+\(\S\+\)\s\+\([0-9]\+\)\s\+\(SHA256:[a-f0-9]\+\)$/\1 \2 \3 \4/p" \
|
||||||
| while read -r uri fname size hash; do
|
| while read uri fname size hash; do
|
||||||
echo "processing $fname" >&2
|
echo "processing $fname" >&2
|
||||||
if [ -e "$tmpdir/$fname" ]; then
|
if [ -e "$tmpdir/$fname" ]; then
|
||||||
echo "$tmpdir/$fname already exists" >&2
|
echo "$tmpdir/$fname already exists" >&2
|
||||||
|
@ -47,7 +45,7 @@ env --chdir="$tmpdir" APT_CONFIG="$tmpfile" apt-get download --print-uris eatmyd
|
||||||
| tar --directory="$rootdir/usr/bin" --strip-components=3 --extract --verbose ./usr/bin/eatmydata
|
| tar --directory="$rootdir/usr/bin" --strip-components=3 --extract --verbose ./usr/bin/eatmydata
|
||||||
;;
|
;;
|
||||||
libeatmydata1_*_$chrootarch.deb)
|
libeatmydata1_*_$chrootarch.deb)
|
||||||
libdir="/usr/lib/$(dpkg-architecture -a "$chrootarch" -q DEB_HOST_MULTIARCH)"
|
libdir="/usr/lib/$(dpkg-architecture -a $chrootarch -q DEB_HOST_MULTIARCH)"
|
||||||
mkdir -p "$rootdir$libdir"
|
mkdir -p "$rootdir$libdir"
|
||||||
dpkg-deb --fsys-tarfile "$tmpdir/$fname" \
|
dpkg-deb --fsys-tarfile "$tmpdir/$fname" \
|
||||||
| tar --directory="$rootdir$libdir" --strip-components=4 --extract --verbose --wildcards ".$libdir/libeatmydata.so*"
|
| tar --directory="$rootdir$libdir" --strip-components=4 --extract --verbose --wildcards ".$libdir/libeatmydata.so*"
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
#
|
|
||||||
# shellcheck disable=SC2086
|
|
||||||
|
|
||||||
set -eu
|
set -eu
|
||||||
|
|
||||||
|
@ -23,17 +21,17 @@ case $MMDEBSTRAP_MODE in
|
||||||
echo "removing the following directories:" >&2 ;;
|
echo "removing the following directories:" >&2 ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
< "$rootdir/run/mmdebstrap/file-mirror-automount" \
|
cat "$rootdir/run/mmdebstrap/file-mirror-automount" \
|
||||||
xargs $xargsopts echo " $rootdir/{}"
|
| xargs $xargsopts echo " $rootdir/{}"
|
||||||
|
|
||||||
case $MMDEBSTRAP_MODE in
|
case $MMDEBSTRAP_MODE in
|
||||||
root|unshare)
|
root|unshare)
|
||||||
< "$rootdir/run/mmdebstrap/file-mirror-automount" \
|
cat "$rootdir/run/mmdebstrap/file-mirror-automount" \
|
||||||
xargs $xargsopts umount "$rootdir/{}"
|
| xargs $xargsopts umount "$rootdir/{}"
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
< "$rootdir/run/mmdebstrap/file-mirror-automount" \
|
cat "$rootdir/run/mmdebstrap/file-mirror-automount" \
|
||||||
xargs $xargsopts rm -r "$rootdir/{}"
|
| xargs $xargsopts rm -r "$rootdir/{}"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
|
|
@ -9,10 +9,10 @@ fi
|
||||||
rootdir="$1"
|
rootdir="$1"
|
||||||
|
|
||||||
# process all configured apt repositories
|
# process all configured apt repositories
|
||||||
env APT_CONFIG="$MMDEBSTRAP_APT_CONFIG" apt-get indextargets --no-release-info --format '$(REPO_URI)' \
|
env APT_CONFIG=$MMDEBSTRAP_APT_CONFIG apt-get indextargets --no-release-info --format '$(REPO_URI)' \
|
||||||
| sed -ne 's/^file:\/\+//p' \
|
| sed -ne 's/^file:\/\+//p' \
|
||||||
| sort -u \
|
| sort -u \
|
||||||
| while read -r path; do
|
| while read path; do
|
||||||
mkdir -p "$rootdir/run/mmdebstrap"
|
mkdir -p "$rootdir/run/mmdebstrap"
|
||||||
case $MMDEBSTRAP_MODE in
|
case $MMDEBSTRAP_MODE in
|
||||||
root|unshare)
|
root|unshare)
|
||||||
|
@ -22,8 +22,8 @@ env APT_CONFIG="$MMDEBSTRAP_APT_CONFIG" apt-get indextargets --no-release-info -
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo "copying /$path into the chroot" >&2
|
echo "copying /$path into the chroot" >&2
|
||||||
mkdir -p "$rootdir/$(dirname "$path")"
|
mkdir -p "$rootdir/$(dirname $path)"
|
||||||
cp -av "/$path" "$rootdir/$(dirname "$path")"
|
cp -av "/$path" "$rootdir/$(dirname $path)"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
printf '/%s\0' "$path" >> "$rootdir/run/mmdebstrap/file-mirror-automount"
|
printf '/%s\0' "$path" >> "$rootdir/run/mmdebstrap/file-mirror-automount"
|
||||||
|
|
|
@ -51,10 +51,8 @@ ARCH=$(dpkg --print-architecture)
|
||||||
eval "$(APT_CONFIG="$MMDEBSTRAP_APT_CONFIG" apt-config shell ARCH Apt::Architecture)"
|
eval "$(APT_CONFIG="$MMDEBSTRAP_APT_CONFIG" apt-config shell ARCH Apt::Architecture)"
|
||||||
|
|
||||||
if [ -e /usr/share/debootstrap/functions ]; then
|
if [ -e /usr/share/debootstrap/functions ]; then
|
||||||
# shellcheck disable=SC1091
|
|
||||||
. /usr/share/debootstrap/functions
|
. /usr/share/debootstrap/functions
|
||||||
doing_variant () { [ "$1" != "buildd" ]; }
|
doing_variant () { [ $1 != "buildd" ]; }
|
||||||
# shellcheck disable=SC2034
|
|
||||||
MERGED_USR="yes"
|
MERGED_USR="yes"
|
||||||
setup_merged_usr
|
setup_merged_usr
|
||||||
else
|
else
|
||||||
|
|
|
@ -58,9 +58,11 @@ deletecache() {
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
for f in "$dir/debian-"*.qcow; do
|
if [ -e $dir/debian-*.qcow ]; then
|
||||||
rm --one-file-system "$f"
|
rm --one-file-system "$dir"/debian-*.qcow
|
||||||
done
|
else
|
||||||
|
echo "does not exist: $dir/debian-*.qcow" >&2
|
||||||
|
fi
|
||||||
if [ -e "$dir/debian/pool/main" ]; then
|
if [ -e "$dir/debian/pool/main" ]; then
|
||||||
rm --one-file-system --recursive "$dir/debian/pool/main"
|
rm --one-file-system --recursive "$dir/debian/pool/main"
|
||||||
else
|
else
|
||||||
|
@ -101,7 +103,7 @@ get_oldaptnames() {
|
||||||
xz -dc "$1/$2" \
|
xz -dc "$1/$2" \
|
||||||
| grep-dctrl --no-field-names --show-field=Package,Version,Architecture,Filename '' \
|
| grep-dctrl --no-field-names --show-field=Package,Version,Architecture,Filename '' \
|
||||||
| paste -sd " \n" \
|
| paste -sd " \n" \
|
||||||
| while read -r name ver arch fname; do
|
| while read name ver arch fname; do
|
||||||
if [ ! -e "$1/$fname" ]; then
|
if [ ! -e "$1/$fname" ]; then
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
|
@ -129,7 +131,7 @@ get_newaptnames() {
|
||||||
xz -dc "$1/$2" \
|
xz -dc "$1/$2" \
|
||||||
| grep-dctrl --no-field-names --show-field=Package,Version,Architecture,Filename,SHA256 '' \
|
| grep-dctrl --no-field-names --show-field=Package,Version,Architecture,Filename,SHA256 '' \
|
||||||
| paste -sd " \n" \
|
| paste -sd " \n" \
|
||||||
| while read -r name ver arch fname hash; do
|
| while read name ver arch fname hash; do
|
||||||
# sanity check for the hash because sometimes the
|
# sanity check for the hash because sometimes the
|
||||||
# archive switches the hash algorithm
|
# archive switches the hash algorithm
|
||||||
if [ "${#hash}" -ne 64 ]; then
|
if [ "${#hash}" -ne 64 ]; then
|
||||||
|
@ -148,7 +150,7 @@ get_newaptnames() {
|
||||||
# since we move hardlinks around, the same hardlink might've been
|
# since we move hardlinks around, the same hardlink might've been
|
||||||
# moved already into the same place by another distribution.
|
# moved already into the same place by another distribution.
|
||||||
# mv(1) refuses to copy A to B if both are hardlinks of each other.
|
# mv(1) refuses to copy A to B if both are hardlinks of each other.
|
||||||
if [ -e "$aptname" ] && [ -e "$1/$fname" ] && [ "$(stat -c "%d %i" "$aptname")" = "$(stat -c "%d %i" "$1/$fname")" ]; then
|
if [ "$aptname" -ef "$1/$fname" ]; then
|
||||||
# both files are already the same so we just need to
|
# both files are already the same so we just need to
|
||||||
# delete the source
|
# delete the source
|
||||||
rm "$aptname"
|
rm "$aptname"
|
||||||
|
@ -230,7 +232,7 @@ Acquire::https::Dl-Limit "1000";
|
||||||
Acquire::Retries "5";
|
Acquire::Retries "5";
|
||||||
END
|
END
|
||||||
|
|
||||||
: > "$rootdir/var/lib/dpkg/status"
|
> "$rootdir/var/lib/dpkg/status"
|
||||||
|
|
||||||
APT_CONFIG="$rootdir/etc/apt/apt.conf" apt-get update
|
APT_CONFIG="$rootdir/etc/apt/apt.conf" apt-get update
|
||||||
|
|
||||||
|
@ -262,7 +264,7 @@ END
|
||||||
--or --field=Priority important --or --field=Priority standard \
|
--or --field=Priority important --or --field=Priority standard \
|
||||||
\))
|
\))
|
||||||
|
|
||||||
pkgs="$pkgs build-essential busybox gpg eatmydata"
|
pkgs="$(echo $pkgs) build-essential busybox gpg eatmydata"
|
||||||
|
|
||||||
# we need usr-is-merged to simulate debootstrap behaviour for all dists
|
# we need usr-is-merged to simulate debootstrap behaviour for all dists
|
||||||
# starting from Debian 12 (Bullseye)
|
# starting from Debian 12 (Bullseye)
|
||||||
|
@ -271,7 +273,6 @@ END
|
||||||
*) pkgs="$pkgs usr-is-merged usrmerge" ;;
|
*) pkgs="$pkgs usr-is-merged usrmerge" ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
# shellcheck disable=SC2086
|
|
||||||
APT_CONFIG="$rootdir/etc/apt/apt.conf" apt-get --yes install $pkgs
|
APT_CONFIG="$rootdir/etc/apt/apt.conf" apt-get --yes install $pkgs
|
||||||
|
|
||||||
# to be able to also test gpg verification, we need to create a mirror
|
# to be able to also test gpg verification, we need to create a mirror
|
||||||
|
@ -335,7 +336,7 @@ END
|
||||||
# new one anymore
|
# new one anymore
|
||||||
comm -23 "$rootdir/oldaptnames" "$rootdir/newaptnames" | xargs --delimiter="\n" --no-run-if-empty rm
|
comm -23 "$rootdir/oldaptnames" "$rootdir/newaptnames" | xargs --delimiter="\n" --no-run-if-empty rm
|
||||||
# now the apt cache should be empty
|
# now the apt cache should be empty
|
||||||
if [ -n "$(ls -1qA "$rootdir/var/cache/apt/archives/")" ]; then
|
if [ ! -z "$(ls -1qA "$rootdir/var/cache/apt/archives/")" ]; then
|
||||||
echo "$rootdir/var/cache/apt/archives not empty:"
|
echo "$rootdir/var/cache/apt/archives not empty:"
|
||||||
ls -la "$rootdir/var/cache/apt/archives/"
|
ls -la "$rootdir/var/cache/apt/archives/"
|
||||||
exit 1
|
exit 1
|
||||||
|
@ -419,7 +420,7 @@ fi
|
||||||
for nativearch in $arches; do
|
for nativearch in $arches; do
|
||||||
for dist in oldstable stable testing unstable; do
|
for dist in oldstable stable testing unstable; do
|
||||||
# non-host architectures are only downloaded for $DEFAULT_DIST
|
# non-host architectures are only downloaded for $DEFAULT_DIST
|
||||||
if [ "$nativearch" != "$HOSTARCH" ] && [ "$DEFAULT_DIST" != "$dist" ]; then
|
if [ $nativearch != $HOSTARCH ] && [ $DEFAULT_DIST != $dist ]; then
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
# we need a first pass without updates and security patches
|
# we need a first pass without updates and security patches
|
||||||
|
@ -464,10 +465,12 @@ cleanuptmpdir() {
|
||||||
if [ ! -e "$tmpdir" ]; then
|
if [ ! -e "$tmpdir" ]; then
|
||||||
return
|
return
|
||||||
fi
|
fi
|
||||||
for f in "$tmpdir/worker.sh" \
|
for f in "$tmpdir/extlinux.conf" \
|
||||||
|
"$tmpdir/worker.sh" \
|
||||||
"$tmpdir/mini-httpd" "$tmpdir/hosts" \
|
"$tmpdir/mini-httpd" "$tmpdir/hosts" \
|
||||||
"$tmpdir/debian-chroot.tar" \
|
"$tmpdir/debian-chroot.tar" \
|
||||||
"$tmpdir/mmdebstrap.service"; do
|
"$tmpdir/mmdebstrap.service" \
|
||||||
|
"$tmpdir/debian-$DEFAULT_DIST.img"; do
|
||||||
if [ ! -e "$f" ]; then
|
if [ ! -e "$f" ]; then
|
||||||
echo "does not exist: $f" >&2
|
echo "does not exist: $f" >&2
|
||||||
continue
|
continue
|
||||||
|
@ -477,17 +480,16 @@ cleanuptmpdir() {
|
||||||
rmdir "$tmpdir"
|
rmdir "$tmpdir"
|
||||||
}
|
}
|
||||||
|
|
||||||
SOURCE_DATE_EPOCH="$(date --date="$(grep-dctrl -s Date -n '' "$newmirrordir/dists/$DEFAULT_DIST/Release")" +%s)"
|
export SOURCE_DATE_EPOCH=$(date --date="$(grep-dctrl -s Date -n '' "$newmirrordir/dists/$DEFAULT_DIST/Release")" +%s)
|
||||||
export SOURCE_DATE_EPOCH
|
|
||||||
|
|
||||||
if [ "$HAVE_QEMU" = "yes" ]; then
|
if [ "$HAVE_QEMU" = "yes" ]; then
|
||||||
case "$HOSTARCH" in
|
case "$HOSTARCH" in
|
||||||
amd64|i386|arm64)
|
amd64|i386)
|
||||||
# okay
|
# okay
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo "qemu support is only available on amd64, i386 and arm64" >&2
|
echo "qemu support is only available on amd64 and i386" >&2
|
||||||
echo "because grub is only available on those arches" >&2
|
echo "because syslinux is only available on those arches" >&2
|
||||||
exit 1
|
exit 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
@ -501,7 +503,7 @@ if [ "$HAVE_QEMU" = "yes" ]; then
|
||||||
tmpdir="$(mktemp -d)"
|
tmpdir="$(mktemp -d)"
|
||||||
trap "cleanuptmpdir; cleanup_newcachedir" EXIT INT TERM
|
trap "cleanuptmpdir; cleanup_newcachedir" EXIT INT TERM
|
||||||
|
|
||||||
pkgs=perl-doc,systemd-sysv,perl,arch-test,fakechroot,fakeroot,mount,uidmap,qemu-user-static,binfmt-support,qemu-user,dpkg-dev,mini-httpd,libdevel-cover-perl,libtemplate-perl,debootstrap,procps,apt-cudf,aspcud,python3,libcap2-bin,gpg,debootstrap,distro-info-data,iproute2,ubuntu-keyring,apt-utils,grub-efi
|
pkgs=perl-doc,systemd-sysv,perl,arch-test,fakechroot,fakeroot,mount,uidmap,qemu-user-static,binfmt-support,qemu-user,dpkg-dev,mini-httpd,libdevel-cover-perl,libtemplate-perl,debootstrap,procps,apt-cudf,aspcud,python3,libcap2-bin,gpg,debootstrap,distro-info-data,iproute2,ubuntu-keyring,apt-utils
|
||||||
if [ "$DEFAULT_DIST" != "oldstable" ]; then
|
if [ "$DEFAULT_DIST" != "oldstable" ]; then
|
||||||
pkgs="$pkgs,squashfs-tools-ng,genext2fs"
|
pkgs="$pkgs,squashfs-tools-ng,genext2fs"
|
||||||
fi
|
fi
|
||||||
|
@ -532,12 +534,21 @@ if [ "$HAVE_QEMU" = "yes" ]; then
|
||||||
else
|
else
|
||||||
arches=$HOSTARCH
|
arches=$HOSTARCH
|
||||||
fi
|
fi
|
||||||
$CMD --variant=apt --architectures="$arches" --include="$pkgs" \
|
$CMD --variant=apt --architectures=$arches --include="$pkgs" \
|
||||||
--aptopt='Acquire::http::Dl-Limit "1000"' \
|
--aptopt='Acquire::http::Dl-Limit "1000"' \
|
||||||
--aptopt='Acquire::https::Dl-Limit "1000"' \
|
--aptopt='Acquire::https::Dl-Limit "1000"' \
|
||||||
--aptopt='Acquire::Retries "5"' \
|
--aptopt='Acquire::Retries "5"' \
|
||||||
$DEFAULT_DIST - "$mirror" > "$tmpdir/debian-chroot.tar"
|
$DEFAULT_DIST - "$mirror" > "$tmpdir/debian-chroot.tar"
|
||||||
|
|
||||||
|
cat << END > "$tmpdir/extlinux.conf"
|
||||||
|
default linux
|
||||||
|
timeout 0
|
||||||
|
|
||||||
|
label linux
|
||||||
|
kernel /vmlinuz
|
||||||
|
append initrd=/initrd.img root=/dev/vda1 rw console=tty0 console=ttyS0,115200n8
|
||||||
|
serial 0 115200
|
||||||
|
END
|
||||||
cat << END > "$tmpdir/mmdebstrap.service"
|
cat << END > "$tmpdir/mmdebstrap.service"
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=mmdebstrap worker script
|
Description=mmdebstrap worker script
|
||||||
|
@ -620,30 +631,13 @@ END
|
||||||
if [ -z ${DISK_SIZE+x} ]; then
|
if [ -z ${DISK_SIZE+x} ]; then
|
||||||
DISK_SIZE=10G
|
DISK_SIZE=10G
|
||||||
fi
|
fi
|
||||||
case "$HOSTARCH" in
|
guestfish -N "$tmpdir/debian-$DEFAULT_DIST.img"=disk:$DISK_SIZE -- \
|
||||||
amd64) GRUB_TARGET=x86_64-efi;;
|
part-disk /dev/sda mbr : \
|
||||||
i386) GRUB_TARGET=i386-efi;;
|
mkfs ext2 /dev/sda1 : \
|
||||||
arm64) GRUB_TARGET=arm64-efi;;
|
mount /dev/sda1 / : \
|
||||||
esac
|
tar-in "$tmpdir/debian-chroot.tar" / : \
|
||||||
case "$HOSTARCH" in
|
|
||||||
arm64) SERIAL="loglevel=3 console=tty0 console=ttyAMA0,115200n8" ;;
|
|
||||||
*) SERIAL="loglevel=3 console=tty0 console=ttyS0,115200n8" ;;
|
|
||||||
esac
|
|
||||||
guestfish -- \
|
|
||||||
disk-create "$newcachedir/debian-$DEFAULT_DIST.qcow" qcow2 "$DISK_SIZE" : \
|
|
||||||
add-drive "$newcachedir/debian-$DEFAULT_DIST.qcow" format:qcow2 : \
|
|
||||||
launch : \
|
|
||||||
part-init /dev/sda gpt : \
|
|
||||||
part-add /dev/sda primary 8192 262144 : \
|
|
||||||
part-add /dev/sda primary 262145 -34 : \
|
|
||||||
part-set-gpt-type /dev/sda 1 C12A7328-F81F-11D2-BA4B-00A0C93EC93B : \
|
|
||||||
mkfs ext2 /dev/sda2 : \
|
|
||||||
mount /dev/sda2 / : \
|
|
||||||
tar-in "$tmpdir/debian-chroot.tar" / xattrs:true : \
|
|
||||||
mkdir-p /boot/efi : \
|
|
||||||
mkfs vfat /dev/sda1 : \
|
|
||||||
mount /dev/sda1 /boot/efi : \
|
|
||||||
command /sbin/ldconfig : \
|
command /sbin/ldconfig : \
|
||||||
|
copy-in "$tmpdir/extlinux.conf" / : \
|
||||||
mkdir-p /etc/systemd/system/multi-user.target.wants : \
|
mkdir-p /etc/systemd/system/multi-user.target.wants : \
|
||||||
ln-s ../mmdebstrap.service /etc/systemd/system/multi-user.target.wants/mmdebstrap.service : \
|
ln-s ../mmdebstrap.service /etc/systemd/system/multi-user.target.wants/mmdebstrap.service : \
|
||||||
copy-in "$tmpdir/mmdebstrap.service" /etc/systemd/system/ : \
|
copy-in "$tmpdir/mmdebstrap.service" /etc/systemd/system/ : \
|
||||||
|
@ -651,16 +645,15 @@ END
|
||||||
copy-in "$tmpdir/mini-httpd" /etc/default : \
|
copy-in "$tmpdir/mini-httpd" /etc/default : \
|
||||||
copy-in "$tmpdir/hosts" /etc/ : \
|
copy-in "$tmpdir/hosts" /etc/ : \
|
||||||
touch /mmdebstrap-testenv : \
|
touch /mmdebstrap-testenv : \
|
||||||
command "sh -c 'echo UUID=\$(blkid -c /dev/null -o value -s UUID /dev/sda2) / ext4 errors=remount-ro 0 1 > /etc/fstab'" : \
|
upload /usr/lib/EXTLINUX/mbr.bin /mbr.bin : \
|
||||||
command "sh -c 'echo UUID=\$(blkid -c /dev/null -o value -s UUID /dev/sda1) /boot/efi vfat errors=remount-ro 0 2 >> /etc/fstab'" : \
|
copy-file-to-device /mbr.bin /dev/sda size:440 : \
|
||||||
command "sed -i 's/^GRUB_CMDLINE_LINUX_DEFAULT=/GRUB_CMDLINE_LINUX_DEFAULT=\"biosdevname=0 net.ifnames=0 consoleblank=0 rw $SERIAL\"/' /etc/default/grub" : \
|
rm /mbr.bin : \
|
||||||
command "update-initramfs -u" : \
|
extlinux / : \
|
||||||
command "grub-mkconfig -o /boot/grub/grub.cfg" : \
|
|
||||||
command "grub-install /dev/sda --target=$GRUB_TARGET --no-nvram --force-extra-removable --no-floppy --modules=part_gpt --grub-mkdevicemap=/boot/grub/device.map" : \
|
|
||||||
sync : \
|
sync : \
|
||||||
umount /boot/efi : \
|
|
||||||
umount / : \
|
umount / : \
|
||||||
|
part-set-bootable /dev/sda 1 true : \
|
||||||
shutdown
|
shutdown
|
||||||
|
qemu-img convert -O qcow2 "$tmpdir/debian-$DEFAULT_DIST.img" "$newcachedir/debian-$DEFAULT_DIST.qcow"
|
||||||
cleanuptmpdir
|
cleanuptmpdir
|
||||||
trap "cleanup_newcachedir" EXIT INT TERM
|
trap "cleanup_newcachedir" EXIT INT TERM
|
||||||
fi
|
fi
|
||||||
|
|
561
mmdebstrap
561
mmdebstrap
|
@ -23,7 +23,7 @@
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
our $VERSION = '1.2.3';
|
our $VERSION = '1.2.2';
|
||||||
|
|
||||||
use English;
|
use English;
|
||||||
use Getopt::Long;
|
use Getopt::Long;
|
||||||
|
@ -36,7 +36,7 @@ use File::Find;
|
||||||
use Cwd qw(abs_path getcwd);
|
use Cwd qw(abs_path getcwd);
|
||||||
require "syscall.ph"; ## no critic (Modules::RequireBarewordIncludes)
|
require "syscall.ph"; ## no critic (Modules::RequireBarewordIncludes)
|
||||||
require "sys/ioctl.ph"; ## no critic (Modules::RequireBarewordIncludes)
|
require "sys/ioctl.ph"; ## no critic (Modules::RequireBarewordIncludes)
|
||||||
use Fcntl qw(S_IFCHR S_IFBLK FD_CLOEXEC F_GETFD F_SETFD);
|
use Fcntl qw(S_IFCHR S_IFBLK FD_CLOEXEC F_GETFD F_SETFD);
|
||||||
use List::Util qw(any none);
|
use List::Util qw(any none);
|
||||||
use POSIX
|
use POSIX
|
||||||
qw(SIGINT SIGHUP SIGPIPE SIGTERM SIG_BLOCK SIG_UNBLOCK strftime isatty);
|
qw(SIGINT SIGHUP SIGPIPE SIGTERM SIG_BLOCK SIG_UNBLOCK strftime isatty);
|
||||||
|
@ -45,7 +45,6 @@ use Term::ANSIColor;
|
||||||
use Socket;
|
use Socket;
|
||||||
use Time::HiRes;
|
use Time::HiRes;
|
||||||
use Math::BigInt;
|
use Math::BigInt;
|
||||||
use Text::ParseWords;
|
|
||||||
use version;
|
use version;
|
||||||
|
|
||||||
## no critic (InputOutput::RequireBriefOpen)
|
## no critic (InputOutput::RequireBriefOpen)
|
||||||
|
@ -62,17 +61,12 @@ use version;
|
||||||
*_LINUX_CAPABILITY_VERSION_3 = \0x20080522;
|
*_LINUX_CAPABILITY_VERSION_3 = \0x20080522;
|
||||||
*CAP_SYS_ADMIN = \21;
|
*CAP_SYS_ADMIN = \21;
|
||||||
*PR_CAPBSET_READ = \23;
|
*PR_CAPBSET_READ = \23;
|
||||||
# from sys/mount.h
|
|
||||||
*MS_BIND = \0x1000;
|
|
||||||
*MS_REC = \0x4000;
|
|
||||||
*MNT_DETACH = \2;
|
|
||||||
our (
|
our (
|
||||||
$CLONE_NEWNS, $CLONE_NEWUTS,
|
$CLONE_NEWNS, $CLONE_NEWUTS,
|
||||||
$CLONE_NEWIPC, $CLONE_NEWUSER,
|
$CLONE_NEWIPC, $CLONE_NEWUSER,
|
||||||
$CLONE_NEWPID, $CLONE_NEWNET,
|
$CLONE_NEWPID, $CLONE_NEWNET,
|
||||||
$_LINUX_CAPABILITY_VERSION_3, $CAP_SYS_ADMIN,
|
$_LINUX_CAPABILITY_VERSION_3, $CAP_SYS_ADMIN,
|
||||||
$PR_CAPBSET_READ, $MS_BIND,
|
$PR_CAPBSET_READ
|
||||||
$MS_REC, $MNT_DETACH
|
|
||||||
);
|
);
|
||||||
|
|
||||||
#<<<
|
#<<<
|
||||||
|
@ -1114,11 +1108,28 @@ sub run_apt_download_progress {
|
||||||
return @listofdebs;
|
return @listofdebs;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub setup_mounts {
|
sub run_chroot {
|
||||||
|
my $cmd = shift;
|
||||||
my $options = shift;
|
my $options = shift;
|
||||||
|
|
||||||
my @cleanup_tasks = ();
|
my @cleanup_tasks = ();
|
||||||
|
|
||||||
|
my $cleanup = sub {
|
||||||
|
my $signal = $_[0];
|
||||||
|
while (my $task = pop @cleanup_tasks) {
|
||||||
|
$task->();
|
||||||
|
}
|
||||||
|
if ($signal) {
|
||||||
|
warning "pid $PID cought signal: $signal";
|
||||||
|
exit 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
local $SIG{INT} = $cleanup;
|
||||||
|
local $SIG{HUP} = $cleanup;
|
||||||
|
local $SIG{PIPE} = $cleanup;
|
||||||
|
local $SIG{TERM} = $cleanup;
|
||||||
|
|
||||||
eval {
|
eval {
|
||||||
if (any { $_ eq $options->{mode} } ('root', 'unshare')) {
|
if (any { $_ eq $options->{mode} } ('root', 'unshare')) {
|
||||||
# if more than essential should be installed, make the system look
|
# if more than essential should be installed, make the system look
|
||||||
|
@ -1153,8 +1164,10 @@ sub setup_mounts {
|
||||||
}
|
}
|
||||||
} elsif ($type == 3 or $type == 4) {
|
} elsif ($type == 3 or $type == 4) {
|
||||||
# character/block special
|
# character/block special
|
||||||
if (any { $_ =~ '^chroot/mount(?:/dev)?$' }
|
if (
|
||||||
@{ $options->{skip} }) {
|
any { $_ =~ '^chroot/mount(?:/dev)?$' }
|
||||||
|
@{ $options->{skip} }
|
||||||
|
) {
|
||||||
info "skipping chroot/mount/dev as requested";
|
info "skipping chroot/mount/dev as requested";
|
||||||
} elsif (!$options->{canmount}) {
|
} elsif (!$options->{canmount}) {
|
||||||
warning "skipping bind-mounting ./dev/$fname";
|
warning "skipping bind-mounting ./dev/$fname";
|
||||||
|
@ -1176,7 +1189,7 @@ sub setup_mounts {
|
||||||
or error "cannot create /dev/pts/ptmx symlink";
|
or error "cannot create /dev/pts/ptmx symlink";
|
||||||
push @cleanup_tasks, sub {
|
push @cleanup_tasks, sub {
|
||||||
unlink "$options->{root}/dev/ptmx"
|
unlink "$options->{root}/dev/ptmx"
|
||||||
or warning "unlink /dev/ptmx";
|
or error "unlink /dev/ptmx";
|
||||||
};
|
};
|
||||||
next;
|
next;
|
||||||
}
|
}
|
||||||
|
@ -1213,8 +1226,10 @@ sub setup_mounts {
|
||||||
}
|
}
|
||||||
} elsif ($type == 5) {
|
} elsif ($type == 5) {
|
||||||
# directory
|
# directory
|
||||||
if (any { $_ =~ '^chroot/mount(?:/dev)?$' }
|
if (
|
||||||
@{ $options->{skip} }) {
|
any { $_ =~ '^chroot/mount(?:/dev)?$' }
|
||||||
|
@{ $options->{skip} }
|
||||||
|
) {
|
||||||
info "skipping chroot/mount/dev as requested";
|
info "skipping chroot/mount/dev as requested";
|
||||||
} elsif (!$options->{canmount}) {
|
} elsif (!$options->{canmount}) {
|
||||||
warning "skipping bind-mounting ./dev/$fname";
|
warning "skipping bind-mounting ./dev/$fname";
|
||||||
|
@ -1480,12 +1495,6 @@ sub setup_mounts {
|
||||||
if (any { $_ eq 'chroot/policy-rc.d' } @{ $options->{skip} }) {
|
if (any { $_ eq 'chroot/policy-rc.d' } @{ $options->{skip} }) {
|
||||||
info "skipping chroot/policy-rc.d as requested";
|
info "skipping chroot/policy-rc.d as requested";
|
||||||
} else {
|
} else {
|
||||||
push @cleanup_tasks, sub {
|
|
||||||
if (-f "$options->{root}/usr/sbin/policy-rc.d") {
|
|
||||||
unlink "$options->{root}/usr/sbin/policy-rc.d"
|
|
||||||
or error "cannot unlink policy-rc.d: $!";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if (-d "$options->{root}/usr/sbin/") {
|
if (-d "$options->{root}/usr/sbin/") {
|
||||||
open my $fh, '>', "$options->{root}/usr/sbin/policy-rc.d"
|
open my $fh, '>', "$options->{root}/usr/sbin/policy-rc.d"
|
||||||
or error "cannot open policy-rc.d: $!";
|
or error "cannot open policy-rc.d: $!";
|
||||||
|
@ -1501,14 +1510,6 @@ sub setup_mounts {
|
||||||
if (any { $_ eq 'chroot/start-stop-daemon' } @{ $options->{skip} }) {
|
if (any { $_ eq 'chroot/start-stop-daemon' } @{ $options->{skip} }) {
|
||||||
info "skipping chroot/start-stop-daemon as requested";
|
info "skipping chroot/start-stop-daemon as requested";
|
||||||
} else {
|
} else {
|
||||||
push @cleanup_tasks, sub {
|
|
||||||
if (-e "$options->{root}/sbin/start-stop-daemon.REAL") {
|
|
||||||
move(
|
|
||||||
"$options->{root}/sbin/start-stop-daemon.REAL",
|
|
||||||
"$options->{root}/sbin/start-stop-daemon"
|
|
||||||
) or error "cannot move start-stop-daemon: $!";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if (-f "$options->{root}/sbin/start-stop-daemon") {
|
if (-f "$options->{root}/sbin/start-stop-daemon") {
|
||||||
if (-e "$options->{root}/sbin/start-stop-daemon.REAL") {
|
if (-e "$options->{root}/sbin/start-stop-daemon.REAL") {
|
||||||
error
|
error
|
||||||
|
@ -1530,12 +1531,40 @@ sub setup_mounts {
|
||||||
or error "cannot chmod start-stop-daemon: $!";
|
or error "cannot chmod start-stop-daemon: $!";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&{$cmd}();
|
||||||
|
|
||||||
|
# cleanup
|
||||||
|
if (any { $_ eq 'chroot/start-stop-daemon' } @{ $options->{skip} }) {
|
||||||
|
info "skipping chroot/start-stop-daemon as requested";
|
||||||
|
} else {
|
||||||
|
if (-e "$options->{root}/sbin/start-stop-daemon.REAL") {
|
||||||
|
move(
|
||||||
|
"$options->{root}/sbin/start-stop-daemon.REAL",
|
||||||
|
"$options->{root}/sbin/start-stop-daemon"
|
||||||
|
) or error "cannot move start-stop-daemon: $!";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (any { $_ eq 'chroot/policy-rc.d' } @{ $options->{skip} }) {
|
||||||
|
info "skipping chroot/policy-rc.d as requested";
|
||||||
|
} else {
|
||||||
|
if (-f "$options->{root}/usr/sbin/policy-rc.d") {
|
||||||
|
unlink "$options->{root}/usr/sbin/policy-rc.d"
|
||||||
|
or error "cannot unlink policy-rc.d: $!";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if ($@) {
|
my $error = $@;
|
||||||
error "setup_mounts failed: $@";
|
|
||||||
|
# we use the cleanup function to do the unmounting
|
||||||
|
$cleanup->(0);
|
||||||
|
|
||||||
|
if ($error) {
|
||||||
|
error "run_chroot failed: $error";
|
||||||
}
|
}
|
||||||
return @cleanup_tasks;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub run_hooks {
|
sub run_hooks {
|
||||||
|
@ -1600,64 +1629,8 @@ sub run_hooks {
|
||||||
("MMDEBSTRAP_INCLUDE=" . (join ",", @escaped_includes));
|
("MMDEBSTRAP_INCLUDE=" . (join ",", @escaped_includes));
|
||||||
}
|
}
|
||||||
|
|
||||||
# Unset the close-on-exec flag, so that the file descriptor does not
|
my $runner = sub {
|
||||||
# get closed when we exec
|
|
||||||
my $flags = fcntl($options->{hooksock}, F_GETFD, 0)
|
|
||||||
or error "fcntl F_GETFD: $!";
|
|
||||||
fcntl($options->{hooksock}, F_SETFD, $flags & ~FD_CLOEXEC)
|
|
||||||
or error "fcntl F_SETFD: $!";
|
|
||||||
|
|
||||||
{
|
|
||||||
foreach my $script (@{ $options->{"${name}_hook"} }) {
|
foreach my $script (@{ $options->{"${name}_hook"} }) {
|
||||||
my $type = $script->[0];
|
|
||||||
$script = $script->[1];
|
|
||||||
|
|
||||||
if ($type eq "pivoted") {
|
|
||||||
info "running --chrooted-$name-hook in shell: sh -c "
|
|
||||||
. "'$script'";
|
|
||||||
my $pid = fork() // error "fork() failed: $!";
|
|
||||||
if ($pid == 0) {
|
|
||||||
# child
|
|
||||||
my @cmdprefix = ();
|
|
||||||
if ($options->{mode} eq 'fakechroot') {
|
|
||||||
# we are calling the chroot executable instead of
|
|
||||||
# chrooting the process so that fakechroot can handle
|
|
||||||
# it
|
|
||||||
@cmdprefix = ('chroot', $options->{root});
|
|
||||||
} elsif ($options->{mode} eq 'root') {
|
|
||||||
# unsharing the mount namespace is not enough for
|
|
||||||
# pivot_root to work as root (why?) unsharing the user
|
|
||||||
# namespace as well (but without remapping) makes
|
|
||||||
# pivot_root work (why??) but still makes later lazy
|
|
||||||
# umounts fail (why???). Since pivot_root is mainly
|
|
||||||
# useful for being able to run unshare mode inside
|
|
||||||
# unshare mode, we fall back to just calling chroot()
|
|
||||||
# until somebody has motivation and time to figure out
|
|
||||||
# what is going on.
|
|
||||||
chroot $options->{root}
|
|
||||||
or error "failed to chroot(): $!";
|
|
||||||
$options->{root} = "/";
|
|
||||||
chdir "/" or error "failed chdir() to /: $!";
|
|
||||||
} elsif ($options->{mode} eq 'unshare') {
|
|
||||||
0 == syscall &SYS_unshare, $CLONE_NEWNS
|
|
||||||
or error "unshare() failed: $!";
|
|
||||||
pivot_root($options->{root});
|
|
||||||
} else {
|
|
||||||
error "unknown mode: $options->{mode}";
|
|
||||||
}
|
|
||||||
0 == system(@cmdprefix, 'env', @env_opts, 'sh', '-c',
|
|
||||||
$script)
|
|
||||||
or error "command failed: $script";
|
|
||||||
exit 0;
|
|
||||||
}
|
|
||||||
waitpid($pid, 0);
|
|
||||||
$? == 0 or error "chrooted hook failed with exit code $?";
|
|
||||||
next;
|
|
||||||
}
|
|
||||||
|
|
||||||
# inode and device number of chroot before
|
|
||||||
my ($dev_before, $ino_before, undef) = stat($options->{root});
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
$script =~ /^(
|
$script =~ /^(
|
||||||
copy-in|copy-out
|
copy-in|copy-out
|
||||||
|
@ -1686,12 +1659,24 @@ sub run_hooks {
|
||||||
open(STDIN, '<&', $options->{hooksock})
|
open(STDIN, '<&', $options->{hooksock})
|
||||||
or error "cannot open STDIN: $!";
|
or error "cannot open STDIN: $!";
|
||||||
|
|
||||||
# Text::ParseWords::shellwords does for perl what shlex
|
# we execute ourselves under sh to avoid having to
|
||||||
# does for python
|
# implement a clever parser of the quoting used in $script
|
||||||
my @args = shellwords $script;
|
# for the filenames
|
||||||
hookhelper($options->{root}, $options->{mode}, $name,
|
my $prefix = "";
|
||||||
$options->{qemu}, $verbosity_level, @args);
|
if ($is_covering) {
|
||||||
exit 0;
|
$prefix
|
||||||
|
= "$EXECUTABLE_NAME -MDevel::Cover=-silent,-nogcov ";
|
||||||
|
}
|
||||||
|
exec 'sh', '-c',
|
||||||
|
"$prefix$PROGRAM_NAME --hook-helper"
|
||||||
|
. " \"\$1\" \"\$2\" \"\$3\" \"\$4\" \"\$5\" $script",
|
||||||
|
'exec', $options->{root}, $options->{mode}, $name,
|
||||||
|
(
|
||||||
|
defined $options->{qemu}
|
||||||
|
? "qemu-$options->{qemu}"
|
||||||
|
: 'env',
|
||||||
|
$verbosity_level
|
||||||
|
);
|
||||||
}
|
}
|
||||||
waitpid($pid, 0);
|
waitpid($pid, 0);
|
||||||
$? == 0 or error "special hook failed with exit code $?";
|
$? == 0 or error "special hook failed with exit code $?";
|
||||||
|
@ -1710,29 +1695,22 @@ sub run_hooks {
|
||||||
'sh', '-c', $script, 'exec', $options->{root})
|
'sh', '-c', $script, 'exec', $options->{root})
|
||||||
or error "command failed: $script";
|
or error "command failed: $script";
|
||||||
}
|
}
|
||||||
|
|
||||||
# If the chroot directory vanished, check if pivot_root was
|
|
||||||
# performed.
|
|
||||||
#
|
|
||||||
# Running pivot_root is only really useful in the customize-hooks
|
|
||||||
# because mmdebstrap uses apt from the outside to install packages
|
|
||||||
# and that will fail after pivot_root because the process doesn't
|
|
||||||
# have access to the system on the outside anymore.
|
|
||||||
if (!-e $options->{root}) {
|
|
||||||
my ($dev_root, $ino_root, undef) = stat("/");
|
|
||||||
if ($dev_before == $dev_root and $ino_before == $ino_root) {
|
|
||||||
info "detected pivot_root, changing chroot directory to /";
|
|
||||||
# the old chroot directory is now /
|
|
||||||
# the hook probably executed pivot_root
|
|
||||||
$options->{root} = "/";
|
|
||||||
chdir "/" or error "failed chdir() to /: $!";
|
|
||||||
} else {
|
|
||||||
error "chroot directory $options->{root} vanished";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# Unset the close-on-exec flag, so that the file descriptor does not
|
||||||
|
# get closed when we exec
|
||||||
|
my $flags = fcntl($options->{hooksock}, F_GETFD, 0)
|
||||||
|
or error "fcntl F_GETFD: $!";
|
||||||
|
fcntl($options->{hooksock}, F_SETFD, $flags & ~FD_CLOEXEC)
|
||||||
|
or error "fcntl F_SETFD: $!";
|
||||||
|
if ($name eq 'setup') {
|
||||||
|
# execute directly without mounting anything (the mount points do not
|
||||||
|
# exist yet)
|
||||||
|
&{$runner}();
|
||||||
|
} else {
|
||||||
|
run_chroot(\&$runner, $options);
|
||||||
|
}
|
||||||
# Restore flags
|
# Restore flags
|
||||||
fcntl($options->{hooksock}, F_SETFD, $flags) or error "fcntl F_SETFD: $!";
|
fcntl($options->{hooksock}, F_SETFD, $flags) or error "fcntl F_SETFD: $!";
|
||||||
return;
|
return;
|
||||||
|
@ -1788,57 +1766,21 @@ sub setup {
|
||||||
# FIXME: dpkg could be changed to produce the same results
|
# FIXME: dpkg could be changed to produce the same results
|
||||||
run_extract($options, $essential_pkgs);
|
run_extract($options, $essential_pkgs);
|
||||||
|
|
||||||
# setup mounts
|
run_hooks('extract', $options);
|
||||||
my @cleanup_tasks = ();
|
|
||||||
my $cleanup = sub {
|
if ($options->{variant} ne 'extract') {
|
||||||
my $signal = $_[0];
|
my $chrootcmd = [];
|
||||||
while (my $task = pop @cleanup_tasks) {
|
if ($options->{mode} ne 'chrootless') {
|
||||||
$task->();
|
$chrootcmd = run_prepare($options);
|
||||||
}
|
}
|
||||||
if ($signal) {
|
|
||||||
warning "pid $PID cought signal: $signal";
|
|
||||||
exit 1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
# we only need to setup the mounts if there is anything to do
|
run_essential($options, $essential_pkgs, $chrootcmd, $cached_debs);
|
||||||
if ( $options->{variant} ne 'custom'
|
|
||||||
or scalar @{ $options->{include} } > 0
|
|
||||||
or scalar @{ $options->{"extract_hook"} } > 0
|
|
||||||
or scalar @{ $options->{"essential_hook"} } > 0
|
|
||||||
or scalar @{ $options->{"customize_hook"} } > 0) {
|
|
||||||
local $SIG{INT} = $cleanup;
|
|
||||||
local $SIG{HUP} = $cleanup;
|
|
||||||
local $SIG{PIPE} = $cleanup;
|
|
||||||
local $SIG{TERM} = $cleanup;
|
|
||||||
|
|
||||||
@cleanup_tasks = setup_mounts($options);
|
run_hooks('essential', $options);
|
||||||
}
|
|
||||||
|
|
||||||
eval {
|
run_install($options, $chrootcmd);
|
||||||
run_hooks('extract', $options);
|
|
||||||
|
|
||||||
if ($options->{variant} ne 'extract') {
|
run_hooks('customize', $options);
|
||||||
my $chrootcmd = [];
|
|
||||||
if ($options->{mode} ne 'chrootless') {
|
|
||||||
$chrootcmd = run_prepare($options);
|
|
||||||
}
|
|
||||||
|
|
||||||
run_essential($options, $essential_pkgs, $chrootcmd, $cached_debs);
|
|
||||||
|
|
||||||
run_hooks('essential', $options);
|
|
||||||
|
|
||||||
run_install($options);
|
|
||||||
|
|
||||||
run_hooks('customize', $options);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
my $msg = $@;
|
|
||||||
|
|
||||||
$cleanup->(0);
|
|
||||||
if ($msg) {
|
|
||||||
error "setup failed: $msg";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (any { $_ eq 'cleanup' } @{ $options->{skip} }) {
|
if (any { $_ eq 'cleanup' } @{ $options->{skip} }) {
|
||||||
|
@ -2367,8 +2309,10 @@ sub run_download() {
|
||||||
dryrun => $options->{dryrun},
|
dryrun => $options->{dryrun},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
} elsif (any { $_ eq $options->{variant} }
|
} elsif (
|
||||||
('essential', 'standard', 'important', 'required', 'buildd')) {
|
any { $_ eq $options->{variant} }
|
||||||
|
('essential', 'standard', 'important', 'required', 'buildd')
|
||||||
|
) {
|
||||||
# 2021-06-07, #debian-apt on OFTC, times in UTC+2
|
# 2021-06-07, #debian-apt on OFTC, times in UTC+2
|
||||||
# 17:27 < DonKult> (?essential includes 'apt' through)
|
# 17:27 < DonKult> (?essential includes 'apt' through)
|
||||||
# 17:30 < josch> DonKult: no, because pkgCacheGen::ForceEssential ",";
|
# 17:30 < josch> DonKult: no, because pkgCacheGen::ForceEssential ",";
|
||||||
|
@ -2836,11 +2780,18 @@ sub run_essential() {
|
||||||
info "simulate installing essential packages...";
|
info "simulate installing essential packages...";
|
||||||
} else {
|
} else {
|
||||||
info "installing essential packages...";
|
info "installing essential packages...";
|
||||||
run_dpkg_progress({
|
run_chroot(
|
||||||
ARGV =>
|
sub {
|
||||||
[@{$chrootcmd}, 'dpkg', '--install', '--force-depends'],
|
run_dpkg_progress({
|
||||||
PKGS => $essential_pkgs,
|
ARGV => [
|
||||||
});
|
@{$chrootcmd}, 'dpkg',
|
||||||
|
'--install', '--force-depends'
|
||||||
|
],
|
||||||
|
PKGS => $essential_pkgs,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
$options
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
error "unknown mode: $options->{mode}";
|
error "unknown mode: $options->{mode}";
|
||||||
|
@ -2867,7 +2818,8 @@ sub run_essential() {
|
||||||
}
|
}
|
||||||
|
|
||||||
sub run_install() {
|
sub run_install() {
|
||||||
my $options = shift;
|
my $options = shift;
|
||||||
|
my $chrootcmd = shift;
|
||||||
|
|
||||||
my %pkgs_to_install;
|
my %pkgs_to_install;
|
||||||
for my $incl (@{ $options->{include} }) {
|
for my $incl (@{ $options->{include} }) {
|
||||||
|
@ -2884,8 +2836,10 @@ sub run_install() {
|
||||||
if ($options->{variant} eq 'buildd') {
|
if ($options->{variant} eq 'buildd') {
|
||||||
$pkgs_to_install{'build-essential'} = ();
|
$pkgs_to_install{'build-essential'} = ();
|
||||||
}
|
}
|
||||||
if (any { $_ eq $options->{variant} }
|
if (
|
||||||
('required', 'important', 'standard', 'buildd')) {
|
any { $_ eq $options->{variant} }
|
||||||
|
('required', 'important', 'standard', 'buildd')
|
||||||
|
) {
|
||||||
# Many of the priority:required packages are also essential:yes. We
|
# Many of the priority:required packages are also essential:yes. We
|
||||||
# make sure not to select those here to avoid useless "xxx is already
|
# make sure not to select those here to avoid useless "xxx is already
|
||||||
# the newest version" messages.
|
# the newest version" messages.
|
||||||
|
@ -2958,26 +2912,35 @@ sub run_install() {
|
||||||
# --root but this would only make sense in situations where there
|
# --root but this would only make sense in situations where there
|
||||||
# is no dpkg inside the chroot.
|
# is no dpkg inside the chroot.
|
||||||
if (!$options->{dryrun}) {
|
if (!$options->{dryrun}) {
|
||||||
info "installing remaining packages inside the chroot...";
|
run_chroot(
|
||||||
run_apt_progress({
|
sub {
|
||||||
ARGV => [
|
info "installing remaining packages inside the"
|
||||||
'apt-get',
|
. " chroot...";
|
||||||
'-o',
|
run_apt_progress({
|
||||||
'Dir::Bin::dpkg=env',
|
ARGV => [
|
||||||
'-o',
|
'apt-get',
|
||||||
'DPkg::Options::=--unset=TMPDIR',
|
'-o',
|
||||||
'-o',
|
'Dir::Bin::dpkg=env',
|
||||||
'DPkg::Options::=dpkg',
|
'-o',
|
||||||
$options->{mode} eq 'fakechroot'
|
'DPkg::Options::=--unset=TMPDIR',
|
||||||
? ('-o', 'DPkg::Install::Recursive::force=true')
|
'-o',
|
||||||
: (),
|
'DPkg::Options::=dpkg',
|
||||||
'-o',
|
$options->{mode} eq 'fakechroot'
|
||||||
"DPkg::Chroot-Directory=$options->{root}",
|
? (
|
||||||
'--yes',
|
'-o',
|
||||||
'install'
|
'DPkg::Install::Recursive::force=true'
|
||||||
],
|
)
|
||||||
PKGS => [@pkgs_to_install],
|
: (),
|
||||||
});
|
'-o',
|
||||||
|
"DPkg::Chroot-Directory=$options->{root}",
|
||||||
|
'--yes',
|
||||||
|
'install'
|
||||||
|
],
|
||||||
|
PKGS => [@pkgs_to_install],
|
||||||
|
});
|
||||||
|
},
|
||||||
|
$options
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
info "simulate installing remaining packages inside the"
|
info "simulate installing remaining packages inside the"
|
||||||
. " chroot...";
|
. " chroot...";
|
||||||
|
@ -3212,30 +3175,17 @@ sub chrooted_realpath {
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub pivot_root {
|
|
||||||
my $root = shift;
|
|
||||||
my $target = "/mnt";
|
|
||||||
my $put_old = "tmp";
|
|
||||||
0 == syscall &SYS_mount, $root, $target, 0, $MS_REC | $MS_BIND, 0
|
|
||||||
or error "mount failed: $!";
|
|
||||||
chdir "/mnt" or error "failed chdir() to /mnt: $!";
|
|
||||||
0 == syscall &SYS_pivot_root, my $new_root = ".", $put_old
|
|
||||||
or error "pivot_root failed: $!";
|
|
||||||
chroot "." or error "failed to chroot() to .: $!";
|
|
||||||
0 == syscall &SYS_umount2, $put_old, $MNT_DETACH
|
|
||||||
or error "umount2 failed: $!";
|
|
||||||
0 == syscall &SYS_umount2, my $sys = "sys", $MNT_DETACH
|
|
||||||
or error "umount2 failed: $!";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub hookhelper {
|
sub hookhelper {
|
||||||
my ($root, $mode, $hook, $qemu, $verbosity, $command, @args) = @_;
|
|
||||||
$verbosity_level = $verbosity;
|
|
||||||
# we put everything in an eval block because that way we can easily handle
|
# we put everything in an eval block because that way we can easily handle
|
||||||
# errors without goto labels or much code duplication: the error handler
|
# errors without goto labels or much code duplication: the error handler
|
||||||
# has to send an "error" message to the other side
|
# has to send an "error" message to the other side
|
||||||
eval {
|
eval {
|
||||||
|
my $root = $ARGV[1];
|
||||||
|
my $mode = $ARGV[2];
|
||||||
|
my $hook = $ARGV[3];
|
||||||
|
my $qemu = $ARGV[4];
|
||||||
|
$verbosity_level = $ARGV[5];
|
||||||
|
my $command = $ARGV[6];
|
||||||
|
|
||||||
my @cmdprefix = ();
|
my @cmdprefix = ();
|
||||||
my @tarcmd = (
|
my @tarcmd = (
|
||||||
|
@ -3259,14 +3209,16 @@ sub hookhelper {
|
||||||
error "unknown hook: $hook";
|
error "unknown hook: $hook";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (any { $_ eq $command } ('copy-in', 'tar-in', 'upload', 'sync-in'))
|
if (
|
||||||
{
|
any { $_ eq $command }
|
||||||
if (scalar @args < 2) {
|
('copy-in', 'tar-in', 'upload', 'sync-in')
|
||||||
|
) {
|
||||||
|
if (scalar @ARGV < 9) {
|
||||||
error "$command needs at least one path on the"
|
error "$command needs at least one path on the"
|
||||||
. " outside and the output path inside the chroot";
|
. " outside and the output path inside the chroot";
|
||||||
}
|
}
|
||||||
my $outpath = pop @args;
|
my $outpath = $ARGV[-1];
|
||||||
foreach my $file (@args) {
|
for (my $i = 7 ; $i < $#ARGV ; $i++) {
|
||||||
# the right argument for tar's --directory argument depends on
|
# the right argument for tar's --directory argument depends on
|
||||||
# whether tar is called from inside the chroot or from the
|
# whether tar is called from inside the chroot or from the
|
||||||
# outside
|
# outside
|
||||||
|
@ -3274,13 +3226,17 @@ sub hookhelper {
|
||||||
if ($hook eq 'setup') {
|
if ($hook eq 'setup') {
|
||||||
# tar runs outside, so acquire the correct path
|
# tar runs outside, so acquire the correct path
|
||||||
$directory = chrooted_realpath $root, $outpath;
|
$directory = chrooted_realpath $root, $outpath;
|
||||||
} elsif (any { $_ eq $hook }
|
} elsif (
|
||||||
('extract', 'essential', 'customize')) {
|
any { $_ eq $hook }
|
||||||
|
('extract', 'essential', 'customize')
|
||||||
|
) {
|
||||||
if ($mode eq 'fakechroot') {
|
if ($mode eq 'fakechroot') {
|
||||||
# tar will run inside the chroot
|
# tar will run inside the chroot
|
||||||
$directory = $outpath;
|
$directory = $outpath;
|
||||||
} elsif (any { $_ eq $mode }
|
} elsif (
|
||||||
('root', 'chrootless', 'unshare')) {
|
any { $_ eq $mode }
|
||||||
|
('root', 'chrootless', 'unshare')
|
||||||
|
) {
|
||||||
$directory = chrooted_realpath $root, $outpath;
|
$directory = chrooted_realpath $root, $outpath;
|
||||||
} else {
|
} else {
|
||||||
error "unknown mode: $mode";
|
error "unknown mode: $mode";
|
||||||
|
@ -3311,8 +3267,10 @@ sub hookhelper {
|
||||||
# open the requested file for writing
|
# open the requested file for writing
|
||||||
open $fh, '|-', @cmdprefix, 'sh', '-c', 'cat > "$1"',
|
open $fh, '|-', @cmdprefix, 'sh', '-c', 'cat > "$1"',
|
||||||
'exec', $directory // error "failed to fork(): $!";
|
'exec', $directory // error "failed to fork(): $!";
|
||||||
} elsif (any { $_ eq $command }
|
} elsif (
|
||||||
('copy-in', 'tar-in', 'sync-in')) {
|
any { $_ eq $command }
|
||||||
|
('copy-in', 'tar-in', 'sync-in')
|
||||||
|
) {
|
||||||
# open a tar process that extracts the tarfile that we
|
# open a tar process that extracts the tarfile that we
|
||||||
# supply it with on stdin to the output directory inside
|
# supply it with on stdin to the output directory inside
|
||||||
# the chroot
|
# the chroot
|
||||||
|
@ -3330,17 +3288,20 @@ sub hookhelper {
|
||||||
# instruct the parent process to create a tarball of the
|
# instruct the parent process to create a tarball of the
|
||||||
# requested path outside the chroot
|
# requested path outside the chroot
|
||||||
debug "helper: sending mktar";
|
debug "helper: sending mktar";
|
||||||
print STDOUT (pack("n", length $file) . "mktar" . $file);
|
print STDOUT (
|
||||||
|
pack("n", length $ARGV[$i]) . "mktar" . $ARGV[$i]);
|
||||||
} elsif ($command eq 'sync-in') {
|
} elsif ($command eq 'sync-in') {
|
||||||
# instruct the parent process to create a tarball of the
|
# instruct the parent process to create a tarball of the
|
||||||
# content of the requested path outside the chroot
|
# content of the requested path outside the chroot
|
||||||
debug "helper: sending mktac";
|
debug "helper: sending mktac";
|
||||||
print STDOUT (pack("n", length $file) . "mktac" . $file);
|
print STDOUT (
|
||||||
|
pack("n", length $ARGV[$i]) . "mktac" . $ARGV[$i]);
|
||||||
} elsif (any { $_ eq $command } ('upload', 'tar-in')) {
|
} elsif (any { $_ eq $command } ('upload', 'tar-in')) {
|
||||||
# instruct parent process to open a tarball of the
|
# instruct parent process to open a tarball of the
|
||||||
# requested path outside the chroot for reading
|
# requested path outside the chroot for reading
|
||||||
debug "helper: sending openr";
|
debug "helper: sending openr";
|
||||||
print STDOUT (pack("n", length $file) . "openr" . $file);
|
print STDOUT (
|
||||||
|
pack("n", length $ARGV[$i]) . "openr" . $ARGV[$i]);
|
||||||
} else {
|
} else {
|
||||||
error "unknown command: $command";
|
error "unknown command: $command";
|
||||||
}
|
}
|
||||||
|
@ -3395,29 +3356,35 @@ sub hookhelper {
|
||||||
error "tar failed";
|
error "tar failed";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} elsif (any { $_ eq $command }
|
} elsif (
|
||||||
('copy-out', 'tar-out', 'download', 'sync-out')) {
|
any { $_ eq $command }
|
||||||
if (scalar @args < 2) {
|
('copy-out', 'tar-out', 'download', 'sync-out')
|
||||||
|
) {
|
||||||
|
if (scalar @ARGV < 9) {
|
||||||
error "$command needs at least one path inside the chroot and"
|
error "$command needs at least one path inside the chroot and"
|
||||||
. " the output path on the outside";
|
. " the output path on the outside";
|
||||||
}
|
}
|
||||||
my $outpath = pop @args;
|
my $outpath = $ARGV[-1];
|
||||||
foreach my $file (@args) {
|
for (my $i = 7 ; $i < $#ARGV ; $i++) {
|
||||||
# the right argument for tar's --directory argument depends on
|
# the right argument for tar's --directory argument depends on
|
||||||
# whether tar is called from inside the chroot or from the
|
# whether tar is called from inside the chroot or from the
|
||||||
# outside
|
# outside
|
||||||
my $directory;
|
my $directory;
|
||||||
if ($hook eq 'setup') {
|
if ($hook eq 'setup') {
|
||||||
# tar runs outside, so acquire the correct path
|
# tar runs outside, so acquire the correct path
|
||||||
$directory = chrooted_realpath $root, $file;
|
$directory = chrooted_realpath $root, $ARGV[$i];
|
||||||
} elsif (any { $_ eq $hook }
|
} elsif (
|
||||||
('extract', 'essential', 'customize')) {
|
any { $_ eq $hook }
|
||||||
|
('extract', 'essential', 'customize')
|
||||||
|
) {
|
||||||
if ($mode eq 'fakechroot') {
|
if ($mode eq 'fakechroot') {
|
||||||
# tar will run inside the chroot
|
# tar will run inside the chroot
|
||||||
$directory = $file;
|
$directory = $ARGV[$i];
|
||||||
} elsif (any { $_ eq $mode }
|
} elsif (
|
||||||
('root', 'chrootless', 'unshare')) {
|
any { $_ eq $mode }
|
||||||
$directory = chrooted_realpath $root, $file;
|
('root', 'chrootless', 'unshare')
|
||||||
|
) {
|
||||||
|
$directory = chrooted_realpath $root, $ARGV[$i];
|
||||||
} else {
|
} else {
|
||||||
error "unknown mode: $mode";
|
error "unknown mode: $mode";
|
||||||
}
|
}
|
||||||
|
@ -3530,11 +3497,11 @@ sub hookhelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
sub hooklistener {
|
sub hooklistener {
|
||||||
$verbosity_level = shift;
|
|
||||||
# we put everything in an eval block because that way we can easily handle
|
# we put everything in an eval block because that way we can easily handle
|
||||||
# errors without goto labels or much code duplication: the error handler
|
# errors without goto labels or much code duplication: the error handler
|
||||||
# has to send an "error" message to the other side
|
# has to send an "error" message to the other side
|
||||||
eval {
|
eval {
|
||||||
|
$verbosity_level = $ARGV[1];
|
||||||
while (1) {
|
while (1) {
|
||||||
# get the next message
|
# get the next message
|
||||||
my $msg = "error";
|
my $msg = "error";
|
||||||
|
@ -4119,8 +4086,10 @@ sub get_sourceslist_by_suite {
|
||||||
# the security mirror changes, starting with bullseye
|
# the security mirror changes, starting with bullseye
|
||||||
# https://lists.debian.org/87r26wqr2a.fsf@43-1.org
|
# https://lists.debian.org/87r26wqr2a.fsf@43-1.org
|
||||||
my $bullseye_or_later = 0;
|
my $bullseye_or_later = 0;
|
||||||
if (any { $_ eq $suite } ('stable', 'bullseye', 'bookworm', 'trixie'))
|
if (
|
||||||
{
|
any { $_ eq $suite }
|
||||||
|
('stable', 'bullseye', 'bookworm', 'trixie')
|
||||||
|
) {
|
||||||
$bullseye_or_later = 1;
|
$bullseye_or_later = 1;
|
||||||
}
|
}
|
||||||
my $distro_info = '/usr/share/distro-info/debian.csv';
|
my $distro_info = '/usr/share/distro-info/debian.csv';
|
||||||
|
@ -4266,15 +4235,14 @@ sub main() {
|
||||||
umask 022;
|
umask 022;
|
||||||
|
|
||||||
if (scalar @ARGV >= 7 && $ARGV[0] eq "--hook-helper") {
|
if (scalar @ARGV >= 7 && $ARGV[0] eq "--hook-helper") {
|
||||||
shift @ARGV; # shift off "--hook-helper"
|
hookhelper();
|
||||||
hookhelper(@ARGV);
|
|
||||||
exit 0;
|
exit 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
# this is the counterpart to --hook-helper and will receive and carry
|
# this is the counterpart to --hook-helper and will receive and carry
|
||||||
# out its instructions
|
# out its instructions
|
||||||
if (scalar @ARGV == 2 && $ARGV[0] eq "--hook-listener") {
|
if (scalar @ARGV == 2 && $ARGV[0] eq "--hook-listener") {
|
||||||
hooklistener($ARGV[1]);
|
hooklistener();
|
||||||
exit 0;
|
exit 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4434,25 +4402,16 @@ sub main() {
|
||||||
'force-check-gpg' =>
|
'force-check-gpg' =>
|
||||||
sub { push @{ $options->{noop} }, 'force-check-gpg'; },
|
sub { push @{ $options->{noop} }, 'force-check-gpg'; },
|
||||||
'setup-hook=s' => sub {
|
'setup-hook=s' => sub {
|
||||||
push @{ $options->{setup_hook} }, ["normal", $_[1]];
|
push @{ $options->{setup_hook} }, $_[1];
|
||||||
},
|
},
|
||||||
'extract-hook=s' => sub {
|
'extract-hook=s' => sub {
|
||||||
push @{ $options->{extract_hook} }, ["normal", $_[1]];
|
push @{ $options->{extract_hook} }, $_[1];
|
||||||
},
|
|
||||||
'chrooted-extract-hook=s' => sub {
|
|
||||||
push @{ $options->{extract_hook} }, ["pivoted", $_[1]];
|
|
||||||
},
|
},
|
||||||
'essential-hook=s' => sub {
|
'essential-hook=s' => sub {
|
||||||
push @{ $options->{essential_hook} }, ["normal", $_[1]];
|
push @{ $options->{essential_hook} }, $_[1];
|
||||||
},
|
|
||||||
'chrooted-essential-hook=s' => sub {
|
|
||||||
push @{ $options->{essential_hook} }, ["pivoted", $_[1]];
|
|
||||||
},
|
},
|
||||||
'customize-hook=s' => sub {
|
'customize-hook=s' => sub {
|
||||||
push @{ $options->{customize_hook} }, ["normal", $_[1]];
|
push @{ $options->{customize_hook} }, $_[1];
|
||||||
},
|
|
||||||
'chrooted-customize-hook=s' => sub {
|
|
||||||
push @{ $options->{customize_hook} }, ["pivoted", $_[1]];
|
|
||||||
},
|
},
|
||||||
'hook-directory=s' => sub {
|
'hook-directory=s' => sub {
|
||||||
my ($opt_name, $opt_value) = @_;
|
my ($opt_name, $opt_value) = @_;
|
||||||
|
@ -4487,7 +4446,7 @@ sub main() {
|
||||||
# list of hooks
|
# list of hooks
|
||||||
foreach my $hook (keys %scripts) {
|
foreach my $hook (keys %scripts) {
|
||||||
push @{ $options->{"${hook}_hook"} },
|
push @{ $options->{"${hook}_hook"} },
|
||||||
(map { ["normal", $_] } (sort @{ $scripts{$hook} }));
|
(sort @{ $scripts{$hook} });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
# Sometimes --simulate fails even though non-simulate succeeds because
|
# Sometimes --simulate fails even though non-simulate succeeds because
|
||||||
|
@ -4528,14 +4487,6 @@ sub main() {
|
||||||
if (scalar @{ $options->{"${hook}_hook"} } > 0) {
|
if (scalar @{ $options->{"${hook}_hook"} } > 0) {
|
||||||
warning "In dry-run mode, --$hook-hook options have no effect";
|
warning "In dry-run mode, --$hook-hook options have no effect";
|
||||||
}
|
}
|
||||||
if ($options->{mode} eq 'chrootless') {
|
|
||||||
foreach my $script (@{ $options->{"${hook}_hook"} }) {
|
|
||||||
if ($script->[0] eq "pivoted") {
|
|
||||||
error "--chrooted-$hook-hook are illegal in "
|
|
||||||
. "chrootless mode";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5569,8 +5520,10 @@ sub main() {
|
||||||
);
|
);
|
||||||
waitpid $pid, 0;
|
waitpid $pid, 0;
|
||||||
$? == 0 or error "havemknod failed";
|
$? == 0 or error "havemknod failed";
|
||||||
} elsif (any { $_ eq $options->{mode} }
|
} elsif (
|
||||||
('root', 'fakechroot', 'chrootless')) {
|
any { $_ eq $options->{mode} }
|
||||||
|
('root', 'fakechroot', 'chrootless')
|
||||||
|
) {
|
||||||
$options->{havemknod} = havemknod($options->{root});
|
$options->{havemknod} = havemknod($options->{root});
|
||||||
} else {
|
} else {
|
||||||
error "unknown mode: $options->{mode}";
|
error "unknown mode: $options->{mode}";
|
||||||
|
@ -5728,8 +5681,10 @@ sub main() {
|
||||||
},
|
},
|
||||||
\@idmap
|
\@idmap
|
||||||
);
|
);
|
||||||
} elsif (any { $_ eq $options->{mode} }
|
} elsif (
|
||||||
('root', 'fakechroot', 'chrootless')) {
|
any { $_ eq $options->{mode} }
|
||||||
|
('root', 'fakechroot', 'chrootless')
|
||||||
|
) {
|
||||||
$pid = fork() // error "fork() failed: $!";
|
$pid = fork() // error "fork() failed: $!";
|
||||||
if ($pid == 0) {
|
if ($pid == 0) {
|
||||||
local $SIG{'INT'} = 'DEFAULT';
|
local $SIG{'INT'} = 'DEFAULT';
|
||||||
|
@ -5791,8 +5746,10 @@ sub main() {
|
||||||
0 == system('chroot', $options->{root}, 'tar',
|
0 == system('chroot', $options->{root}, 'tar',
|
||||||
@taropts, '-C', '/', '.')
|
@taropts, '-C', '/', '.')
|
||||||
or error "tar failed: $?";
|
or error "tar failed: $?";
|
||||||
} elsif (any { $_ eq $options->{mode} } ('root', 'chrootless'))
|
} elsif (
|
||||||
{
|
any { $_ eq $options->{mode} }
|
||||||
|
('root', 'chrootless')
|
||||||
|
) {
|
||||||
# If the chroot directory is not owned by the root user,
|
# If the chroot directory is not owned by the root user,
|
||||||
# then we assume that no measure was taken to fake root
|
# then we assume that no measure was taken to fake root
|
||||||
# permissions. Since the final tarball should contain
|
# permissions. Since the final tarball should contain
|
||||||
|
@ -5855,8 +5812,11 @@ sub main() {
|
||||||
open(STDIN, '<&', $parentsock)
|
open(STDIN, '<&', $parentsock)
|
||||||
or error "cannot open STDIN: $!";
|
or error "cannot open STDIN: $!";
|
||||||
|
|
||||||
hooklistener($verbosity_level);
|
my @prefix = ();
|
||||||
exit 0;
|
if ($is_covering) {
|
||||||
|
@prefix = ($EXECUTABLE_NAME, "-MDevel::Cover=-silent,-nogcov");
|
||||||
|
}
|
||||||
|
exec @prefix, $PROGRAM_NAME, "--hook-listener", $verbosity_level;
|
||||||
}
|
}
|
||||||
waitpid($lpid, 0);
|
waitpid($lpid, 0);
|
||||||
if ($? != 0) {
|
if ($? != 0) {
|
||||||
|
@ -6021,8 +5981,10 @@ sub main() {
|
||||||
rmdir "$options->{root}"
|
rmdir "$options->{root}"
|
||||||
or error "cannot rmdir $options->{root}: $!";
|
or error "cannot rmdir $options->{root}: $!";
|
||||||
}
|
}
|
||||||
} elsif (any { $_ eq $options->{mode} }
|
} elsif (
|
||||||
('root', 'fakechroot', 'chrootless')) {
|
any { $_ eq $options->{mode} }
|
||||||
|
('root', 'fakechroot', 'chrootless')
|
||||||
|
) {
|
||||||
# without unshare, we use the system's rm to recursively remove the
|
# without unshare, we use the system's rm to recursively remove the
|
||||||
# temporary directory just to make sure that we do not accidentally
|
# temporary directory just to make sure that we do not accidentally
|
||||||
# remove more than we should by using --one-file-system.
|
# remove more than we should by using --one-file-system.
|
||||||
|
@ -6068,8 +6030,7 @@ B<mmdebstrap> creates a Debian chroot of I<SUITE> into I<TARGET> from one or
|
||||||
more I<MIRROR>s. It is meant as an alternative to the debootstrap tool (see
|
more I<MIRROR>s. It is meant as an alternative to the debootstrap tool (see
|
||||||
section B<DEBOOTSTRAP>). In contrast to debootstrap it uses apt to resolve
|
section B<DEBOOTSTRAP>). In contrast to debootstrap it uses apt to resolve
|
||||||
dependencies and is thus able to use more than one mirror and resolve more
|
dependencies and is thus able to use more than one mirror and resolve more
|
||||||
complex dependencies. See section B<OPERATION> for an overview of how
|
complex dependencies.
|
||||||
B<mmdebstrap> works internally.
|
|
||||||
|
|
||||||
If no I<MIRROR> option is provided, L<http://deb.debian.org/debian> is used.
|
If no I<MIRROR> option is provided, L<http://deb.debian.org/debian> is used.
|
||||||
If I<SUITE> is a stable release name and no I<MIRROR> is specified, then
|
If I<SUITE> is a stable release name and no I<MIRROR> is specified, then
|
||||||
|
@ -6239,6 +6200,7 @@ Example: Exclude paths to reduce chroot size
|
||||||
--dpkgopt='path-exclude=/usr/share/doc/*'
|
--dpkgopt='path-exclude=/usr/share/doc/*'
|
||||||
--dpkgopt='path-include=/usr/share/doc/*/copyright'
|
--dpkgopt='path-include=/usr/share/doc/*/copyright'
|
||||||
--dpkgopt='path-include=/usr/share/doc/*/changelog.Debian.*'
|
--dpkgopt='path-include=/usr/share/doc/*/changelog.Debian.*'
|
||||||
|
--dpkgopt='path-exclude=/usr/share/{doc,info,man,omf,help,gnome/help}/*'
|
||||||
|
|
||||||
=item B<--include>=I<pkg1>[,I<pkg2>,...]
|
=item B<--include>=I<pkg1>[,I<pkg2>,...]
|
||||||
|
|
||||||
|
@ -6795,28 +6757,7 @@ retained.
|
||||||
|
|
||||||
=head1 OPERATION
|
=head1 OPERATION
|
||||||
|
|
||||||
This section gives an overview of the different steps to create a chroot. At
|
This section gives an overview of the different steps to create a chroot.
|
||||||
its core, what B<mmdebstrap> does can be put into a 14 line shell script:
|
|
||||||
|
|
||||||
mkdir -p "$2/etc/apt" "$2/var/cache"
|
|
||||||
cat << END > "$2/apt.conf"
|
|
||||||
Apt::Architecture "$(dpkg --print-architecture)";
|
|
||||||
Apt::Architectures "$(dpkg --print-architecture)";
|
|
||||||
Dir "$(cd "$2" && pwd)";
|
|
||||||
Dir::Etc::Trusted "$(eval "$(apt-config shell v Dir::Etc::Trusted/f)"; printf "$v")";
|
|
||||||
Dir::Etc::TrustedParts "$(eval "$(apt-config shell v Dir::Etc::TrustedParts/d)"; printf "$v")";
|
|
||||||
END
|
|
||||||
echo "deb http://deb.debian.org/debian/ $1 main" > "$2/etc/apt/sources.list"
|
|
||||||
APT_CONFIG="$2/apt.conf" apt-get update
|
|
||||||
APT_CONFIG="$2/apt.conf" apt-get --yes --download-only install '?essential'
|
|
||||||
for f in "$2"/var/cache/apt/archives/*.deb; do dpkg-deb --extract "$f" "$2"; done
|
|
||||||
chroot "$2" sh -c "dpkg --install --force-depends /var/cache/apt/archives/*.deb"
|
|
||||||
|
|
||||||
The additional complexity of B<mmdebstrap> is to support operation without
|
|
||||||
superuser privileges, bit-by-bit reproducible output, hooks and foreign
|
|
||||||
architecture support.
|
|
||||||
|
|
||||||
The remainder of this section explains what B<mmdebstrap> does step-by-step.
|
|
||||||
|
|
||||||
=over 8
|
=over 8
|
||||||
|
|
||||||
|
@ -6879,17 +6820,6 @@ C<apt-get dist-upgrade>. In the remaining variants, all Packages files
|
||||||
downloaded by the B<update> step are inspected to find the C<Essential:yes>
|
downloaded by the B<update> step are inspected to find the C<Essential:yes>
|
||||||
package set as well as all packages of the required priority.
|
package set as well as all packages of the required priority.
|
||||||
|
|
||||||
=item B<mount>
|
|
||||||
|
|
||||||
Mount relevant device nodes, F</proc> and F</sys> into the chroot and unmount
|
|
||||||
them afterwards. This can be disabled using B<--skip=chroot/mount> or
|
|
||||||
specifically by B<--skip=chroot/mount/dev>, B<--skip=chroot/mount/proc> and
|
|
||||||
B<--skip=chroot/mount/sys>, respectively. B<mmdebstrap> will disable running
|
|
||||||
services by temporarily moving F</usr/sbin/policy-rc.d> and
|
|
||||||
F</sbin/start-stop-daemon> if they exist. This can be disabled with
|
|
||||||
B<--skip=chroot/policy-rc.d> and B<--skip=chroot/start-stop-daemon>,
|
|
||||||
respectively.
|
|
||||||
|
|
||||||
=item B<extract>
|
=item B<extract>
|
||||||
|
|
||||||
Extract the downloaded packages into the rootfs.
|
Extract the downloaded packages into the rootfs.
|
||||||
|
@ -6930,10 +6860,17 @@ out in B<extract> mode.
|
||||||
Run B<--customize-hook> options and all F<customize*> scripts in B<--hook-dir>.
|
Run B<--customize-hook> options and all F<customize*> scripts in B<--hook-dir>.
|
||||||
This step is not carried out in B<extract> mode.
|
This step is not carried out in B<extract> mode.
|
||||||
|
|
||||||
=item B<unmount>
|
Whenever B<mmdebstrap> does a chroot call in B<root> or B<unshare> modes, it
|
||||||
|
will mount relevant device nodes, F</proc> and F</sys> into the chroot and
|
||||||
|
unmount them afterwards. This can be disabled using B<--skip=chroot/mount> or
|
||||||
|
specifically by B<--skip=chroot/mount/dev>, B<--skip=chroot/mount/proc> and
|
||||||
|
B<--skip=chroot/mount/sys>, respectively.
|
||||||
|
|
||||||
Unmount everything that was mounted during the B<mount> stage and restores
|
For each command that is run inside the chroot, B<mmdebstrap> will disable
|
||||||
F</usr/sbin/policy-rc.d> and F</sbin/start-stop-daemon> if necessary.
|
running services by temporarily moving F</usr/sbin/policy-rc.d> and
|
||||||
|
F</sbin/start-stop-daemon> if they exist. This can be disabled with
|
||||||
|
B<--skip=chroot/policy-rc.d> and B<--skip=chroot/start-stop-daemon>,
|
||||||
|
respectively.
|
||||||
|
|
||||||
=item B<cleanup>
|
=item B<cleanup>
|
||||||
|
|
||||||
|
|
|
@ -145,7 +145,7 @@ case "$nativearch" in
|
||||||
[ $BOOT = bios ] || [ $BOOT = efi ]
|
[ $BOOT = bios ] || [ $BOOT = efi ]
|
||||||
if [ $BOOT = bios ]; then
|
if [ $BOOT = bios ]; then
|
||||||
include="linux-image-686-pae grub-pc"
|
include="linux-image-686-pae grub-pc"
|
||||||
grub_target="i386-pc"
|
grub_target="i386-efi"
|
||||||
elif [ $BOOT = efi ]; then
|
elif [ $BOOT = efi ]; then
|
||||||
include="linux-image-686-pae grub-efi"
|
include="linux-image-686-pae grub-efi"
|
||||||
grub_target="i386-efi"
|
grub_target="i386-efi"
|
||||||
|
|
25
run_qemu.sh
25
run_qemu.sh
|
@ -25,26 +25,6 @@ cleanup() {
|
||||||
|
|
||||||
trap cleanup INT TERM EXIT
|
trap cleanup INT TERM EXIT
|
||||||
|
|
||||||
ARCH=$(dpkg --print-architecture)
|
|
||||||
case $ARCH in
|
|
||||||
i386)
|
|
||||||
MACHINE="accel=kvm:tcg"
|
|
||||||
CODE="/usr/share/OVMF/OVMF32_CODE_4M.secboot.fd"
|
|
||||||
QEMUARCH="i386"
|
|
||||||
;;
|
|
||||||
amd64)
|
|
||||||
MACHINE="accel=kvm:tcg"
|
|
||||||
CODE="/usr/share/OVMF/OVMF_CODE.fd"
|
|
||||||
QEMUARCH="x86_64"
|
|
||||||
;;
|
|
||||||
arm64)
|
|
||||||
MACHINE="type=virt,gic-version=host,accel=kvm"
|
|
||||||
CODE="/usr/share/AAVMF/AAVMF_CODE.fd,readonly"
|
|
||||||
QEMUARCH="aarch64"
|
|
||||||
;;
|
|
||||||
*) echo "qemu kvm not supported on $ARCH" >&2;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# the path to debian-$DEFAULT_DIST.qcow must be absolute or otherwise qemu will
|
# the path to debian-$DEFAULT_DIST.qcow must be absolute or otherwise qemu will
|
||||||
# look for the path relative to debian-$DEFAULT_DIST-overlay.qcow
|
# look for the path relative to debian-$DEFAULT_DIST-overlay.qcow
|
||||||
qemu-img create -f qcow2 -b "$(realpath $cachedir)/debian-$DEFAULT_DIST.qcow" -F qcow2 "$tmpdir/debian-$DEFAULT_DIST-overlay.qcow"
|
qemu-img create -f qcow2 -b "$(realpath $cachedir)/debian-$DEFAULT_DIST.qcow" -F qcow2 "$tmpdir/debian-$DEFAULT_DIST-overlay.qcow"
|
||||||
|
@ -54,16 +34,15 @@ qemu-img create -f qcow2 -b "$(realpath $cachedir)/debian-$DEFAULT_DIST.qcow" -F
|
||||||
# or this (quit with ctrl+q):
|
# or this (quit with ctrl+q):
|
||||||
# socat stdin,raw,echo=0,escape=0x11 unix-connect:/tmp/ttyS0
|
# socat stdin,raw,echo=0,escape=0x11 unix-connect:/tmp/ttyS0
|
||||||
ret=0
|
ret=0
|
||||||
timeout --foreground 40m qemu-system-"$QEMUARCH" \
|
timeout --foreground 20m qemu-system-x86_64 \
|
||||||
-cpu host \
|
-cpu host \
|
||||||
-no-user-config \
|
-no-user-config \
|
||||||
-M "$MACHINE" -m 4G -nographic \
|
-M accel=kvm:tcg -m 4G -nographic \
|
||||||
-object rng-random,filename=/dev/urandom,id=rng0 -device virtio-rng-pci,rng=rng0 \
|
-object rng-random,filename=/dev/urandom,id=rng0 -device virtio-rng-pci,rng=rng0 \
|
||||||
-monitor unix:/tmp/monitor,server,nowait \
|
-monitor unix:/tmp/monitor,server,nowait \
|
||||||
-serial unix:/tmp/ttyS0,server,nowait \
|
-serial unix:/tmp/ttyS0,server,nowait \
|
||||||
-serial unix:/tmp/ttyS1,server,nowait \
|
-serial unix:/tmp/ttyS1,server,nowait \
|
||||||
-net nic,model=virtio -net user \
|
-net nic,model=virtio -net user \
|
||||||
-drive if=pflash,format=raw,unit=0,read-only,file="$CODE" \
|
|
||||||
-virtfs local,id=mmdebstrap,path="$(pwd)/shared",security_model=none,mount_tag=mmdebstrap \
|
-virtfs local,id=mmdebstrap,path="$(pwd)/shared",security_model=none,mount_tag=mmdebstrap \
|
||||||
-drive file="$tmpdir/debian-$DEFAULT_DIST-overlay.qcow",cache=unsafe,index=0,if=virtio \
|
-drive file="$tmpdir/debian-$DEFAULT_DIST-overlay.qcow",cache=unsafe,index=0,if=virtio \
|
||||||
>"$tmpdir/log" 2>&1 || ret=$?
|
>"$tmpdir/log" 2>&1 || ret=$?
|
||||||
|
|
|
@ -74,8 +74,8 @@ 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 chmod 0700 $d
|
||||||
chroot /tmp/debian-debootstrap chown _apt:root $d
|
chroot /tmp/debian-debootstrap chown _apt:root $d
|
||||||
done
|
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-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 -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/root1.tar > /tmp/root1.tar.list
|
||||||
tar --full-time --verbose -tf /tmp/root2.tar > /tmp/root2.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
|
# despite SOURCE_DATE_EPOCH and --clamp-mtime, the timestamps in the tarball
|
||||||
|
|
|
@ -7,9 +7,9 @@ if [ ! -e /mmdebstrap-testenv ]; then
|
||||||
fi
|
fi
|
||||||
for f in /usr/share/keyrings/*.gpg; do
|
for f in /usr/share/keyrings/*.gpg; do
|
||||||
name=$(basename "$f" .gpg)
|
name=$(basename "$f" .gpg)
|
||||||
gpg --enarmor < "/usr/share/keyrings/$name.gpg" \
|
gpg --enarmor < /usr/share/keyrings/$name.gpg \
|
||||||
| sed 's/ PGP ARMORED FILE/ PGP PUBLIC KEY BLOCK/;/^Comment: /d' \
|
| sed 's/ PGP ARMORED FILE/ PGP PUBLIC KEY BLOCK/;/^Comment: /d' \
|
||||||
> "/etc/apt/trusted.gpg.d/$name.asc"
|
> /etc/apt/trusted.gpg.d/$name.asc
|
||||||
done
|
done
|
||||||
rm /etc/apt/trusted.gpg.d/*.gpg
|
rm /etc/apt/trusted.gpg.d/*.gpg
|
||||||
rm /usr/share/keyrings/*.gpg
|
rm /usr/share/keyrings/*.gpg
|
||||||
|
|
|
@ -3,7 +3,7 @@ set -eu
|
||||||
export LC_ALL=C.UTF-8
|
export LC_ALL=C.UTF-8
|
||||||
trap "rm -f /tmp/debian-chroot.tar" EXIT INT TERM
|
trap "rm -f /tmp/debian-chroot.tar" EXIT INT TERM
|
||||||
{{ CMD }} --mode={{ MODE }} --variant=custom \
|
{{ CMD }} --mode={{ MODE }} --variant=custom \
|
||||||
--include "$(tr '\n' ',' < pkglist.txt)" \
|
--include $(cat pkglist.txt | tr '\n' ',') \
|
||||||
--aptopt='APT::Solver "aspcud"' \
|
--aptopt='APT::Solver "aspcud"' \
|
||||||
{{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }}
|
{{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }}
|
||||||
tar -tf /tmp/debian-chroot.tar | sort \
|
tar -tf /tmp/debian-chroot.tar | sort \
|
||||||
|
|
|
@ -12,7 +12,7 @@ echo "SOURCE_DATE_EPOCH=$SOURCE_DATE_EPOCH"
|
||||||
# we cannot use useradd because passwd is not Essential:yes
|
# we cannot use useradd because passwd is not Essential:yes
|
||||||
{{ CMD }} --variant={{ VARIANT }} --mode={{ MODE }} \
|
{{ CMD }} --variant={{ VARIANT }} --mode={{ MODE }} \
|
||||||
--essential-hook='case {{ DIST }} in oldstable|stable) if [ {{ VARIANT }} = - ]; then echo _apt:*:100:65534::/nonexistent:/usr/sbin/nologin >> "$1"/etc/passwd; fi;; esac' \
|
--essential-hook='case {{ DIST }} in oldstable|stable) if [ {{ VARIANT }} = - ]; then echo _apt:*:100:65534::/nonexistent:/usr/sbin/nologin >> "$1"/etc/passwd; fi;; esac' \
|
||||||
"$(case {{ DIST }} in oldstable|stable) echo --merged-usr ;; *) echo --hook-dir=./hooks/merged-usr ;; esac)" \
|
$(case {{ DIST }} in oldstable|stable) : ;; *) echo --hook-dir=./hooks/merged-usr ;; esac) \
|
||||||
{{ DIST }} /tmp/debian-{{ DIST }}-mm.tar {{ MIRROR }}
|
{{ DIST }} /tmp/debian-{{ DIST }}-mm.tar {{ MIRROR }}
|
||||||
|
|
||||||
mkdir /tmp/debian-{{ DIST }}-mm
|
mkdir /tmp/debian-{{ DIST }}-mm
|
||||||
|
@ -147,7 +147,6 @@ done
|
||||||
# Because of unreproducible uids (#969631) we created the _apt user ourselves
|
# 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
|
# 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
|
# versions of adduser and shadow will create a different /etc/shadow
|
||||||
if [ "{{ VARIANT }}" = "-" ]; then
|
|
||||||
case {{ DIST }} in oldstable|stable)
|
case {{ DIST }} in oldstable|stable)
|
||||||
for f in shadow shadow-; do
|
for f in shadow shadow-; do
|
||||||
if grep -q '^_apt:!:' /tmp/debian-{{ DIST }}-debootstrap/etc/$f; then
|
if grep -q '^_apt:!:' /tmp/debian-{{ DIST }}-debootstrap/etc/$f; then
|
||||||
|
@ -155,13 +154,12 @@ for f in shadow shadow-; do
|
||||||
fi
|
fi
|
||||||
done;;
|
done;;
|
||||||
esac
|
esac
|
||||||
fi
|
|
||||||
|
|
||||||
for log in faillog lastlog; do
|
for log in faillog lastlog; do
|
||||||
if ! cmp /tmp/debian-{{ DIST }}-debootstrap/var/log/$log /tmp/debian-{{ DIST }}-mm/var/log/$log >&2;then
|
if ! cmp /tmp/debian-{{ DIST }}-debootstrap/var/log/$log /tmp/debian-{{ DIST }}-mm/var/log/$log >&2;then
|
||||||
# if the files differ, make sure they are all zeroes
|
# if the files differ, make sure they are all zeroes
|
||||||
cmp -n "$(stat -c %s "/tmp/debian-{{ DIST }}-debootstrap/var/log/$log")" "/tmp/debian-{{ DIST }}-debootstrap/var/log/$log" /dev/zero >&2
|
cmp -n $(stat -c %s /tmp/debian-{{ DIST }}-debootstrap/var/log/$log) /tmp/debian-{{ DIST }}-debootstrap/var/log/$log /dev/zero >&2
|
||||||
cmp -n "$(stat -c %s "/tmp/debian-{{ DIST }}-mm/var/log/$log")" "/tmp/debian-{{ DIST }}-mm/var/log/$log" /dev/zero >&2
|
cmp -n $(stat -c %s /tmp/debian-{{ DIST }}-mm/var/log/$log) /tmp/debian-{{ DIST }}-mm/var/log/$log /dev/zero >&2
|
||||||
# then delete them
|
# then delete them
|
||||||
rm /tmp/debian-{{ DIST }}-debootstrap/var/log/$log /tmp/debian-{{ DIST }}-mm/var/log/$log
|
rm /tmp/debian-{{ DIST }}-debootstrap/var/log/$log /tmp/debian-{{ DIST }}-mm/var/log/$log
|
||||||
fi
|
fi
|
||||||
|
@ -172,7 +170,7 @@ done
|
||||||
if [ "{{ VARIANT }}" = "-" ]; then
|
if [ "{{ VARIANT }}" = "-" ]; then
|
||||||
case {{ DIST }} in testing|unstable)
|
case {{ DIST }} in testing|unstable)
|
||||||
for f in group group- gshadow gshadow-; do
|
for f in group group- gshadow gshadow-; do
|
||||||
cmp /tmp/debian-{{ DIST }}-mm/etc/$f /tmp/debian-{{ DIST }}-debootstrap/etc/$f 2>/dev/null && exit 1
|
! cmp /tmp/debian-{{ DIST }}-mm/etc/$f /tmp/debian-{{ DIST }}-debootstrap/etc/$f 2>/dev/null
|
||||||
for d in mm debootstrap; do
|
for d in mm debootstrap; do
|
||||||
sort /tmp/debian-{{ DIST }}-$d/etc/$f > /tmp/debian-{{ DIST }}-$d/etc/$f.bak
|
sort /tmp/debian-{{ DIST }}-$d/etc/$f > /tmp/debian-{{ DIST }}-$d/etc/$f.bak
|
||||||
mv /tmp/debian-{{ DIST }}-$d/etc/$f.bak /tmp/debian-{{ DIST }}-$d/etc/$f
|
mv /tmp/debian-{{ DIST }}-$d/etc/$f.bak /tmp/debian-{{ DIST }}-$d/etc/$f
|
||||||
|
@ -183,7 +181,8 @@ if [ "{{ VARIANT }}" = "-" ]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# workaround for https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=917773
|
# workaround for https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=917773
|
||||||
case {{ DIST }} in oldstable|stable)
|
# also needed for users that are created by systemd-sysusers before systemd 252
|
||||||
|
# https://github.com/systemd/systemd/pull/24534
|
||||||
for f in shadow shadow-; do
|
for f in shadow shadow-; do
|
||||||
if [ ! -e /tmp/debian-{{ DIST }}-mm/etc/$f ]; then
|
if [ ! -e /tmp/debian-{{ DIST }}-mm/etc/$f ]; then
|
||||||
continue
|
continue
|
||||||
|
@ -196,8 +195,7 @@ for f in shadow shadow-; do
|
||||||
else
|
else
|
||||||
echo no difference for /etc/$f on {{ DIST }} {{ VARIANT }} >&2
|
echo no difference for /etc/$f on {{ DIST }} {{ VARIANT }} >&2
|
||||||
fi
|
fi
|
||||||
done;;
|
done
|
||||||
esac
|
|
||||||
|
|
||||||
# check if the file content differs
|
# check if the file content differs
|
||||||
diff --unified --no-dereference --recursive /tmp/debian-{{ DIST }}-debootstrap /tmp/debian-{{ DIST }}-mm >&2
|
diff --unified --no-dereference --recursive /tmp/debian-{{ DIST }}-debootstrap /tmp/debian-{{ DIST }}-mm >&2
|
||||||
|
@ -208,10 +206,10 @@ find /tmp/debian-{{ DIST }}-debootstrap /tmp/debian-{{ DIST }}-mm -type d -print
|
||||||
# debootstrap never ran apt -- fixing permissions
|
# debootstrap never ran apt -- fixing permissions
|
||||||
for d in ./var/lib/apt/lists/partial ./var/cache/apt/archives/partial; do
|
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 chmod 0700 $d
|
||||||
chroot /tmp/debian-{{ DIST }}-debootstrap chown "$(id -u _apt):root" $d
|
chroot /tmp/debian-{{ DIST }}-debootstrap chown $(id -u _apt):root $d
|
||||||
done
|
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 }}-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 -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/root1.tar > /tmp/root1.tar.list
|
||||||
tar --full-time --verbose -tf /tmp/root2.tar > /tmp/root2.tar.list
|
tar --full-time --verbose -tf /tmp/root2.tar > /tmp/root2.tar.list
|
||||||
diff -u /tmp/root1.tar.list /tmp/root2.tar.list >&2
|
diff -u /tmp/root1.tar.list /tmp/root2.tar.list >&2
|
||||||
|
|
|
@ -2,10 +2,6 @@
|
||||||
set -eu
|
set -eu
|
||||||
export LC_ALL=C.UTF-8
|
export LC_ALL=C.UTF-8
|
||||||
export SOURCE_DATE_EPOCH={{ SOURCE_DATE_EPOCH }}
|
export SOURCE_DATE_EPOCH={{ SOURCE_DATE_EPOCH }}
|
||||||
if dpkg --compare-versions "$(dpkg-query -W -f='${Version}' libpam-runtime)" le 1.5.2-5; then
|
|
||||||
# https://bugs.debian.org/1022952
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
trap "rm -f /tmp/chrootless.tar /tmp/root.tar" EXIT INT TERM
|
trap "rm -f /tmp/chrootless.tar /tmp/root.tar" EXIT INT TERM
|
||||||
# we need --hook-dir=./hooks/merged-usr because usrmerge does not understand
|
# we need --hook-dir=./hooks/merged-usr because usrmerge does not understand
|
||||||
# DPKG_ROOT
|
# DPKG_ROOT
|
||||||
|
|
|
@ -20,7 +20,7 @@ for INCLUDE in '' 'systemd-sysv'; do
|
||||||
--hook-dir=./hooks/merged-usr ${INCLUDE:+--include="$INCLUDE"} \
|
--hook-dir=./hooks/merged-usr ${INCLUDE:+--include="$INCLUDE"} \
|
||||||
{{ DIST }} "/tmp/root.tar" {{ MIRROR }}
|
{{ DIST }} "/tmp/root.tar" {{ MIRROR }}
|
||||||
echo 0 > /proc/sys/fs/binfmt_misc/qemu-aarch64
|
echo 0 > /proc/sys/fs/binfmt_misc/qemu-aarch64
|
||||||
arch-test arm64 && exit 1
|
! arch-test arm64
|
||||||
{{ CMD }} --mode=chrootless --architecture=arm64 --variant={{ VARIANT }} \
|
{{ CMD }} --mode=chrootless --architecture=arm64 --variant={{ VARIANT }} \
|
||||||
--hook-dir=./hooks/merged-usr ${INCLUDE:+--include="$INCLUDE"} \
|
--hook-dir=./hooks/merged-usr ${INCLUDE:+--include="$INCLUDE"} \
|
||||||
{{ DIST }} "/tmp/chrootless.tar" {{ MIRROR }}
|
{{ DIST }} "/tmp/chrootless.tar" {{ MIRROR }}
|
||||||
|
|
|
@ -11,7 +11,7 @@ if [ ! -e /mmdebstrap-testenv ]; then
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
tmpdir=$(mktemp -d)
|
tmpdir=$(mktemp -d)
|
||||||
trap 'rm -f "$tmpdir"/*.deb /tmp/orig.tar /tmp/test1.tar /tmp/test2.tar; rmdir "$tmpdir"' EXIT INT TERM
|
trap "rm -f \"$tmpdir\"/*.deb /tmp/orig.tar /tmp/test1.tar /tmp/test2.tar; rmdir \"$tmpdir\"" EXIT INT TERM
|
||||||
|
|
||||||
include="--include=doc-debian"
|
include="--include=doc-debian"
|
||||||
if [ "{{ VARIANT }}" = "custom" ]; then
|
if [ "{{ VARIANT }}" = "custom" ]; then
|
||||||
|
|
|
@ -42,8 +42,8 @@ $prefix {{ CMD }} --mode={{ MODE }} --variant=apt --architectures=arm64 {{ DIST
|
||||||
| sed 's/aarch64-linux-gnu/x86_64-linux-gnu/' \
|
| sed 's/aarch64-linux-gnu/x86_64-linux-gnu/' \
|
||||||
| sed 's/arm64/amd64/';
|
| sed 's/arm64/amd64/';
|
||||||
} | sort > tar2.txt
|
} | sort > tar2.txt
|
||||||
{ < tar1.txt \
|
{ cat tar1.txt \
|
||||||
grep -v '^\./usr/bin/i386$' \
|
| grep -v '^\./usr/bin/i386$' \
|
||||||
| grep -v '^\./usr/bin/x86_64$' \
|
| grep -v '^\./usr/bin/x86_64$' \
|
||||||
| grep -v '^\./lib32$' \
|
| grep -v '^\./lib32$' \
|
||||||
| grep -v '^\./lib64$' \
|
| grep -v '^\./lib64$' \
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
set -eu
|
set -eu
|
||||||
export LC_ALL=C.UTF-8
|
export LC_ALL=C.UTF-8
|
||||||
prefix=
|
prefix=
|
||||||
include=,
|
include=
|
||||||
if [ "$(id -u)" -eq 0 ] && [ "{{ MODE }}" != root ] && [ "{{ MODE }}" != auto ]; then
|
if [ "$(id -u)" -eq 0 ] && [ "{{ MODE }}" != root ] && [ "{{ MODE }}" != auto ]; then
|
||||||
# this must be qemu
|
# this must be qemu
|
||||||
if ! id -u user >/dev/null 2>&1; then
|
if ! id -u user >/dev/null 2>&1; then
|
||||||
|
@ -24,11 +24,11 @@ if [ "$(id -u)" -eq 0 ] && [ "{{ MODE }}" != root ] && [ "{{ MODE }}" != auto ];
|
||||||
sysctl -w kernel.unprivileged_userns_clone=1
|
sysctl -w kernel.unprivileged_userns_clone=1
|
||||||
fi
|
fi
|
||||||
prefix="runuser -u user --"
|
prefix="runuser -u user --"
|
||||||
if [ "{{ VARIANT }}" = extract ] || [ "{{ VARIANT }}" = custom ]; then
|
if [ "{{ MODE }}" = extract ] || [ "{{ MODE }}" = custom ]; then
|
||||||
include="$(tr '\n' ',' < pkglist.txt)"
|
include="--include=$(cat pkglist.txt | tr '\n' ',')"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
$prefix {{ CMD }} --mode={{ MODE }} --include="$include" --dry-run --variant={{ VARIANT }} {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }}
|
$prefix {{ CMD }} --mode={{ MODE }} $include --dry-run --variant={{ VARIANT }} {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }}
|
||||||
if [ -e /tmp/debian-chroot.tar ]; then
|
if [ -e /tmp/debian-chroot.tar ]; then
|
||||||
echo "/tmp/debian-chroot.tar must not be created with --dry-run" >&2
|
echo "/tmp/debian-chroot.tar must not be created with --dry-run" >&2
|
||||||
exit 1
|
exit 1
|
||||||
|
|
|
@ -117,7 +117,7 @@ END
|
||||||
# use script to create a fake tty
|
# use script to create a fake tty
|
||||||
# run all tests as root and as a normal user (the latter requires ptmxmode=666)
|
# run all tests as root and as a normal user (the latter requires ptmxmode=666)
|
||||||
script -qfc "$prefix {{ CMD }} --mode={{ MODE }} --variant=apt \
|
script -qfc "$prefix {{ CMD }} --mode={{ MODE }} --variant=apt \
|
||||||
--include=gcc,libc6-dev,python3,adduser \
|
--include=gcc,libc6-dev,python3 \
|
||||||
--customize-hook='chroot \"\$1\" adduser --gecos user --disabled-password user' \
|
--customize-hook='chroot \"\$1\" adduser --gecos user --disabled-password user' \
|
||||||
--customize-hook='chroot \"\$1\" python3 -c \"import pty; print(pty.openpty())\"' \
|
--customize-hook='chroot \"\$1\" python3 -c \"import pty; print(pty.openpty())\"' \
|
||||||
--customize-hook='chroot \"\$1\" runuser -u user -- python3 -c \"import pty; print(pty.openpty())\"' \
|
--customize-hook='chroot \"\$1\" runuser -u user -- python3 -c \"import pty; print(pty.openpty())\"' \
|
||||||
|
|
|
@ -7,5 +7,5 @@ export LC_ALL=C.UTF-8
|
||||||
trap "rm -f Release; rm -rf /tmp/debian-chroot" EXIT INT TERM
|
trap "rm -f Release; rm -rf /tmp/debian-chroot" EXIT INT TERM
|
||||||
/usr/lib/apt/apt-helper download-file "{{ MIRROR }}/dists/{{ DIST }}/Release" Release
|
/usr/lib/apt/apt-helper download-file "{{ MIRROR }}/dists/{{ DIST }}/Release" Release
|
||||||
codename=$(awk '/^Codename: / { print $2; }' Release)
|
codename=$(awk '/^Codename: / { print $2; }' Release)
|
||||||
{{ CMD }} --mode={{ MODE }} --variant=apt "$codename" /tmp/debian-chroot {{ MIRROR }}
|
{{ CMD }} --mode={{ MODE }} --variant=apt $codename /tmp/debian-chroot {{ MIRROR }}
|
||||||
echo "deb {{ MIRROR }} $codename main" | diff -u - /tmp/debian-chroot/etc/apt/sources.list
|
echo "deb {{ MIRROR }} $codename main" | diff -u - /tmp/debian-chroot/etc/apt/sources.list
|
||||||
|
|
|
@ -22,8 +22,8 @@ apt-get remove --yes qemu-user-static binfmt-support qemu-user
|
||||||
| sed 's/i386/amd64/' \
|
| sed 's/i386/amd64/' \
|
||||||
| sed 's/\/stubs-32.ph$/\/stubs-64.ph/';
|
| sed 's/\/stubs-32.ph$/\/stubs-64.ph/';
|
||||||
} | sort > tar2.txt
|
} | sort > tar2.txt
|
||||||
{ < tar1.txt \
|
{ cat tar1.txt \
|
||||||
grep -v '^\./usr/bin/i386$' \
|
| grep -v '^\./usr/bin/i386$' \
|
||||||
| grep -v '^\./usr/bin/x86_64$' \
|
| grep -v '^\./usr/bin/x86_64$' \
|
||||||
| grep -v '^\./usr/lib32/$' \
|
| grep -v '^\./usr/lib32/$' \
|
||||||
| grep -v '^\./lib32$' \
|
| grep -v '^\./lib32$' \
|
||||||
|
|
|
@ -3,24 +3,19 @@
|
||||||
set -eu
|
set -eu
|
||||||
export LC_ALL=C.UTF-8
|
export LC_ALL=C.UTF-8
|
||||||
|
|
||||||
# instead of obtaining a .deb from our cache, we create a new package because
|
{{ CMD }} --variant=apt \
|
||||||
# otherwise apt might decide to download the package with the same name and
|
--customize-hook='mkdir "$1"/tmp/apt' \
|
||||||
# version from the cache instead of using the local .deb
|
--customize-hook='chroot "$1" env --chdir=/tmp/apt apt-get download busybox' \
|
||||||
mkdir -p /tmp/dummypkg/DEBIAN
|
--customize-hook='copy-out /tmp/apt /tmp' \
|
||||||
cat << END > "/tmp/dummypkg/DEBIAN/control"
|
{{ DIST }} /dev/null {{ MIRROR }}
|
||||||
Package: dummypkg
|
pkg="$(find /tmp/apt -type f)"
|
||||||
Priority: optional
|
# some sanity checks
|
||||||
Section: oldlibs
|
[ -f "$pkg" ]
|
||||||
Maintainer: Johannes Schauer Marin Rodrigues <josch@debian.org>
|
case $pkg in
|
||||||
Architecture: all
|
/tmp/apt/busybox*_{{ HOSTARCH }}.deb) : ;;
|
||||||
Multi-Arch: foreign
|
*) exit 1;;
|
||||||
Source: dummypkg
|
esac
|
||||||
Version: 1
|
# now try to install that package
|
||||||
Description: dummypkg
|
{{ CMD }} --variant=apt --include="$pkg" \
|
||||||
END
|
--customize-hook='chroot "$1" dpkg-query -W -f="\${Status}\n" busybox | grep "^install ok installed$"' \
|
||||||
dpkg-deb --build "/tmp/dummypkg" "/tmp/dummypkg.deb"
|
|
||||||
|
|
||||||
{{ CMD }} --variant=apt --include="/tmp/dummypkg.deb" \
|
|
||||||
--hook-dir=./hooks/file-mirror-automount \
|
|
||||||
--customize-hook='chroot "$1" dpkg-query -W -f="\${Status}\n" dummypkg | grep "^install ok installed$"' \
|
|
||||||
{{ DIST }} /dev/null {{ MIRROR }}
|
{{ DIST }} /dev/null {{ MIRROR }}
|
||||||
|
|
|
@ -21,14 +21,13 @@ for cmd in echo cat sed grep; do
|
||||||
test -L /tmp/debian-chroot/bin/$cmd
|
test -L /tmp/debian-chroot/bin/$cmd
|
||||||
test "$(readlink /tmp/debian-chroot/bin/$cmd)" = "/bin/busybox"
|
test "$(readlink /tmp/debian-chroot/bin/$cmd)" = "/bin/busybox"
|
||||||
done
|
done
|
||||||
for cmd in sort tee; do
|
for cmd in sort; do
|
||||||
test -L /tmp/debian-chroot/usr/bin/$cmd
|
test -L /tmp/debian-chroot/usr/bin/$cmd
|
||||||
test "$(readlink /tmp/debian-chroot/usr/bin/$cmd)" = "/bin/busybox"
|
test "$(readlink /tmp/debian-chroot/usr/bin/$cmd)" = "/bin/busybox"
|
||||||
done
|
done
|
||||||
chroot /tmp/debian-chroot echo foobar \
|
chroot /tmp/debian-chroot echo foobar \
|
||||||
| chroot /tmp/debian-chroot cat \
|
| chroot /tmp/debian-chroot cat \
|
||||||
| chroot /tmp/debian-chroot sort \
|
| chroot /tmp/debian-chroot sort \
|
||||||
| chroot /tmp/debian-chroot tee /dev/null \
|
|
||||||
| chroot /tmp/debian-chroot sed 's/foobar/blubber/' \
|
| chroot /tmp/debian-chroot sed 's/foobar/blubber/' \
|
||||||
| chroot /tmp/debian-chroot grep blubber >/dev/null
|
| chroot /tmp/debian-chroot grep blubber >/dev/null
|
||||||
rm -r /tmp/debian-chroot
|
rm -r /tmp/debian-chroot
|
||||||
|
|
|
@ -11,7 +11,7 @@ fi
|
||||||
prefix=
|
prefix=
|
||||||
[ "$(id -u)" -eq 0 ] && prefix="runuser -u user --"
|
[ "$(id -u)" -eq 0 ] && prefix="runuser -u user --"
|
||||||
$prefix {{ CMD }} --mode=chrootless --variant=custom --include=doc-debian {{ DIST }} /tmp/debian-chroot {{ MIRROR }}
|
$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 -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
|
tar tvf /tmp/debian-chroot.tar > doc-debian.tar.list
|
||||||
rm /tmp/debian-chroot.tar
|
rm /tmp/debian-chroot.tar
|
||||||
# delete contents of doc-debian
|
# delete contents of doc-debian
|
||||||
|
|
|
@ -14,7 +14,7 @@ prefix=
|
||||||
$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 }}
|
$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/setup
|
||||||
rm /tmp/debian-chroot/tmp/customize
|
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 -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 -
|
tar tvf /tmp/debian-chroot.tar | grep -v ' ./dev' | diff -u doc-debian.tar.list -
|
||||||
rm /tmp/debian-chroot.tar
|
rm /tmp/debian-chroot.tar
|
||||||
# delete contents of doc-debian
|
# delete contents of doc-debian
|
||||||
|
|
|
@ -1,55 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
set -eu
|
|
||||||
export LC_ALL=C.UTF-8
|
|
||||||
export SOURCE_DATE_EPOCH={{ SOURCE_DATE_EPOCH }}
|
|
||||||
trap "rm -f /tmp/chroot1.tar /tmp/chroot2.tar /tmp/chroot3.tar /tmp/mmdebstrap" EXIT INT TERM
|
|
||||||
|
|
||||||
if [ ! -e /mmdebstrap-testenv ]; then
|
|
||||||
echo "this test modifies the system and should only be run inside a container" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$(id -u)" -eq 0 ] && ! id -u user > /dev/null 2>&1; then
|
|
||||||
adduser --gecos user --disabled-password user
|
|
||||||
fi
|
|
||||||
|
|
||||||
prefix=
|
|
||||||
[ "$(id -u)" -eq 0 ] && [ "{{ MODE }}" != "root" ] && prefix="runuser -u user --"
|
|
||||||
|
|
||||||
MMDEBSTRAP=
|
|
||||||
[ -e /usr/bin/mmdebstrap ] && MMDEBSTRAP=/usr/bin/mmdebstrap
|
|
||||||
[ -e ./mmdebstrap ] && MMDEBSTRAP=./mmdebstrap
|
|
||||||
|
|
||||||
$prefix {{ CMD }} --mode={{ MODE }} --variant=apt \
|
|
||||||
--include=mount \
|
|
||||||
{{ DIST }} /tmp/chroot1.tar {{ MIRROR }}
|
|
||||||
|
|
||||||
if [ {{ MODE }} = "unshare" ]; then
|
|
||||||
# calling pivot_root in root mode does not work for mysterious reasons:
|
|
||||||
# pivot_root: failed to change root from `.' to `mnt': Invalid argument
|
|
||||||
$prefix {{ CMD }} --mode={{ MODE }} --variant=apt --include=mount \
|
|
||||||
--customize-hook="upload $MMDEBSTRAP /$MMDEBSTRAP" \
|
|
||||||
--customize-hook='chmod +x "$1"/'"$MMDEBSTRAP" \
|
|
||||||
--customize-hook='mount -o rbind "$1" /mnt && cd /mnt && /sbin/pivot_root . mnt' \
|
|
||||||
--customize-hook='unshare -U echo nested unprivileged unshare' \
|
|
||||||
--customize-hook='{{ CMD }} --mode=unshare --variant=apt --include=mount {{ DIST }} /tmp/chroot3.tar {{ MIRROR }}' \
|
|
||||||
--customize-hook='copy-out /tmp/chroot3.tar /tmp' \
|
|
||||||
--customize-hook='rm "$1/'"$MMDEBSTRAP"'"' \
|
|
||||||
--customize-hook='umount -l mnt sys' \
|
|
||||||
{{ DIST }} /tmp/chroot2.tar {{ MIRROR }}
|
|
||||||
|
|
||||||
cmp /tmp/chroot1.tar /tmp/chroot2.tar
|
|
||||||
cmp /tmp/chroot1.tar /tmp/chroot3.tar
|
|
||||||
rm /tmp/chroot2.tar /tmp/chroot3.tar
|
|
||||||
fi
|
|
||||||
|
|
||||||
$prefix {{ CMD }} --mode={{ MODE }} --variant=apt --include=mount \
|
|
||||||
--customize-hook="upload $MMDEBSTRAP /$MMDEBSTRAP" \
|
|
||||||
--customize-hook='chmod +x "$1"/'"$MMDEBSTRAP" \
|
|
||||||
--chrooted-customize-hook='{{ CMD }} --mode=unshare --variant=apt --include=mount {{ DIST }} /tmp/chroot3.tar {{ MIRROR }}' \
|
|
||||||
--customize-hook='copy-out /tmp/chroot3.tar /tmp' \
|
|
||||||
--customize-hook='rm "$1/'"$MMDEBSTRAP"'"' \
|
|
||||||
{{ DIST }} /tmp/chroot2.tar {{ MIRROR }}
|
|
||||||
|
|
||||||
cmp /tmp/chroot1.tar /tmp/chroot2.tar
|
|
||||||
cmp /tmp/chroot1.tar /tmp/chroot3.tar
|
|
|
@ -1,13 +1,12 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
set -eu
|
set -eu
|
||||||
export LC_ALL=C.UTF-8
|
export LC_ALL=C.UTF-8
|
||||||
setsid --wait {{ CMD }} --mode=root --variant=apt --customize-hook='touch hookstarted && sleep 10 && touch fail' {{ DIST }} /tmp/debian-chroot {{ MIRROR }} &
|
setsid --wait {{ CMD }} --mode=root --variant=apt --customize-hook='touch done && sleep 10 && touch fail' {{ DIST }} /tmp/debian-chroot {{ MIRROR }} &
|
||||||
pid=$!
|
pid=$!
|
||||||
while sleep 1; do [ -e hookstarted ] && break; done
|
while sleep 1; do [ -e done ] && break; done
|
||||||
rm hookstarted
|
rm done
|
||||||
# negative PID values choose the whole process group
|
pgid=$(echo $(ps -p $pid -o pgid=))
|
||||||
pgid=$((-1*$(ps -p "$pid" -o pgid=)))
|
/bin/kill --signal INT -- -$pgid
|
||||||
/bin/kill --signal INT -- "$pgid"
|
|
||||||
ret=0
|
ret=0
|
||||||
wait $pid || ret=$?
|
wait $pid || ret=$?
|
||||||
rm -r /tmp/debian-chroot
|
rm -r /tmp/debian-chroot
|
||||||
|
|
|
@ -7,10 +7,9 @@ ln -s /real /tmp/root/link
|
||||||
mkdir /tmp/root/real
|
mkdir /tmp/root/real
|
||||||
run_testA() {
|
run_testA() {
|
||||||
echo content > /tmp/foo
|
echo content > /tmp/foo
|
||||||
# shellcheck disable=SC2094
|
{ { { {{ CMD }} --hook-helper /tmp/root root setup env 1 upload /tmp/foo $1 < /tmp/myfifo 3>&-; echo $? >&3; printf "\\000\\000adios";
|
||||||
{ { { {{ 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;
|
} | {{ CMD }} --hook-listener 1 3>&- >/tmp/myfifo; echo $?; } 3>&1;
|
||||||
} | { read -r xs1; [ "$xs1" -eq 0 ]; read -r xs2; [ "$xs2" -eq 0 ]; }
|
} | { read xs1; [ "$xs1" -eq 0 ]; read xs2; [ "$xs2" -eq 0 ]; }
|
||||||
echo content | diff -u - /tmp/root/real/foo
|
echo content | diff -u - /tmp/root/real/foo
|
||||||
rm /tmp/foo
|
rm /tmp/foo
|
||||||
rm /tmp/root/real/foo
|
rm /tmp/root/real/foo
|
||||||
|
|
|
@ -3,4 +3,4 @@ set -eu
|
||||||
export LC_ALL=C.UTF-8
|
export LC_ALL=C.UTF-8
|
||||||
# we redirect to /dev/null instead of using --quiet to not cause a broken pipe
|
# 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
|
# when grep exits before mmdebstrap was able to write all its output
|
||||||
{{ CMD }} --version | grep -E '^mmdebstrap [0-9](\.[0-9])+$' >/dev/null
|
{{ CMD }} --version | egrep '^mmdebstrap [0-9](\.[0-9])+$' >/dev/null
|
||||||
|
|
Loading…
Reference in a new issue