Compare commits

..

11 commits

Author SHA1 Message Date
8fe4fe3eda
hooks/busybox/extract00.sh: run busybox from an absolute path 2021-10-08 20:46:55 +02:00
7a062661e5
release 0.8.1 2021-10-07 13:35:39 +02:00
1d2a7ef71a
enforce dpkg >= 1.20.0 and remove dead code 2021-10-07 10:51:20 +02:00
4f278deadf
use rm and find instead of remove_tree()
* remove_tree() requires the CWD to be accessible or fails with
   cannot chdir to $CWD from $DIR_TO_DELETE: Permission denied, aborting.
 * CWD is not always accessible -- example: run mmdebstrap from a
   directory only accessible by the current user (like a tempdir) in
   unshare mode
 * find from findutils *also* requires CWD to be accessible but it's
   easier to temporarily change CWD in a subprocess because using
   there is no utility in perl core that changes CWD temporarily and
   cleans up after itself
 * we need to use find from findutils instead of rm in unshare mode
   because the root directory itself might not be removable by the
   unshared user so we only want to remove its subdirectories
2021-10-07 07:07:45 +02:00
c2d988b475
enforce apt >= 2.3.7 and remove dead code (closes: #14) 2021-10-06 23:30:09 +02:00
28cb757742
do not run xz and zstd with --threads=0
There are now systems with 160 cores (debci runs on two Ampere Altra
ARMv8 Neoverse-N1), which makes xz fail with: "xz: (stdin): Cannot
allocate memory"
2021-09-24 22:09:24 +02:00
932a3716bc
ldconfig.fakechroot: support DPKG_ROOT 2021-09-23 06:24:59 +02:00
12ec2c50aa
also create cmethopt and available in chrootless mode
- this allows bit-by-bit identical output of chrootless mode compared
   to other modes
2021-09-22 15:22:35 +02:00
03ebda088f
coverage.sh: use MMDEBSTRAP_APT_CONFIG to prevent apt options (like foreign archs) leaking into the apt calls 2021-09-22 09:04:27 +02:00
450881f4ce
coverage.sh: setup00-merged-usr.sh moved into a subdirectory 2021-09-21 23:01:58 +02:00
2bd6929fbc
make_mirror.sh: bullseye-updates doesn't ship Packages.gz anymore, so we use xz everywhere instead 2021-09-21 21:11:46 +02:00
6 changed files with 162 additions and 203 deletions

View file

@ -1,3 +1,12 @@
0.8.1 (2021-10-07)
------------------
- enforce dpkg >= 1.20.0 and apt >= 2.3.7
- allow working directory be not world readable
- do not run xz and zstd with --threads=0 since this is a bad default for
machines with more than 100 cores
- bit-by-bit identical chrootless mode
0.8.0 (2021-09-21)
------------------

View file

@ -103,12 +103,12 @@ if [ ! -e shared/ldconfig.fakechroot ] || [ ldconfig.fakechroot -nt shared/ldcon
cp -a /usr/libexec/mmdebstrap/ldconfig.fakechroot shared/ldconfig.fakechroot
fi
fi
mkdir -p shared/hooks
if [ ! -e shared/hooks/setup00-merged-usr.sh ] || [ hooks/setup00-merged-usr.sh -nt shared/hooks/setup00-merged-usr.sh ]; then
if [ -e hooks/setup00-merged-usr.sh ]; then
cp -a hooks/setup00-merged-usr.sh shared/hooks/
mkdir -p shared/hooks/merged-usr
if [ ! -e shared/hooks/merged-usr/setup00.sh ] || [ hooks/merged-usr/setup00.sh -nt shared/hooks/merged-usr/setup00.sh ]; then
if [ -e hooks/merged-usr/setup00.sh ]; then
cp -a hooks/merged-usr/setup00.sh shared/hooks/merged-usr/
else
cp -a /usr/share/mmdebstrap/hooks/setup00-merged-usr.sh shared/hooks/
cp -a /usr/share/mmdebstrap/hooks/merged-usr/setup00.sh shared/hooks/merged-usr/
fi
fi
mkdir -p shared/hooks/eatmydata
@ -127,7 +127,7 @@ if [ ! -e shared/hooks/eatmydata/customize.sh ] || [ hooks/eatmydata/customize.s
fi
fi
starttime=
total=212
total=213
skipped=0
runtests=0
i=1
@ -240,7 +240,7 @@ rm /tmp/debian-$dist-debootstrap/var/lib/dpkg/status-old \
/tmp/debian-$dist-mm/var/lib/dpkg/status-old
# remove dpkg files
rm /tmp/debian-$dist-debootstrap/var/lib/dpkg/available
touch /tmp/debian-$dist-debootstrap/var/lib/dpkg/available
rm /tmp/debian-$dist-debootstrap/var/lib/dpkg/cmethopt
# since we installed packages directly from the .deb files, Priorities differ
# thus we first check for equality and then remove the files
chroot /tmp/debian-$dist-debootstrap dpkg --list > dpkg1
@ -1055,6 +1055,39 @@ else
runtests=$((runtests+1))
fi
print_header "mode=unshare,variant=apt: CWD directory not accessible by unshared user"
cat << END > shared/test.sh
#!/bin/sh
set -eu
export LC_ALL=C.UTF-8
if [ ! -e /mmdebstrap-testenv ]; then
echo "this test modifies the system and should only be run inside a container" >&2
exit 1
fi
adduser --gecos user --disabled-password user
sysctl -w kernel.unprivileged_userns_clone=1
mkdir /tmp/debian-chroot
chmod 700 /tmp/debian-chroot
chown user:user /tmp/debian-chroot
if [ "$CMD" = "./mmdebstrap" ]; then
CMD=\$(realpath --canonicalize-existing ./mmdebstrap)
elif [ "$CMD" = "perl -MDevel::Cover=-silent,-nogcov ./mmdebstrap" ]; then
CMD="perl -MDevel::Cover=-silent,-nogcov \$(realpath --canonicalize-existing ./mmdebstrap)"
else
CMD="$CMD"
fi
env --chdir=/tmp/debian-chroot runuser -u user -- \$CMD --mode=unshare --variant=apt $DEFAULT_DIST /tmp/debian-chroot.tar $mirror
tar -tf /tmp/debian-chroot.tar | sort | diff -u tar1.txt -
rm /tmp/debian-chroot.tar
END
if [ "$HAVE_QEMU" = "yes" ]; then
./run_qemu.sh
runtests=$((runtests+1))
else
echo "HAVE_QEMU != yes -- Skipping test..." >&2
skipped=$((skipped+1))
fi
print_header "mode=unshare,variant=apt: create gzip compressed tarball"
cat << END > shared/test.sh
#!/bin/sh
@ -2076,7 +2109,7 @@ cat << END > shared/test.sh
set -eu
export LC_ALL=C.UTF-8
$CMD --mode=root --variant=apt \
--setup-hook=./hooks/setup00-merged-usr.sh \
--setup-hook=./hooks/merged-usr/setup00.sh \
--customize-hook='[ -L "\$1"/bin -a -L "\$1"/sbin -a -L "\$1"/lib ]' \
$DEFAULT_DIST /tmp/debian-chroot $mirror
tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort > tar2.txt
@ -2763,8 +2796,6 @@ rm /tmp/debian-chroot/etc/fstab
rm /tmp/debian-chroot/etc/hostname
rm /tmp/debian-chroot/etc/resolv.conf
rm /tmp/debian-chroot/var/lib/apt/lists/lock
rm /tmp/debian-chroot/var/lib/dpkg/available
rm /tmp/debian-chroot/var/lib/dpkg/cmethopt
rm /tmp/debian-chroot/var/lib/dpkg/status
# the rest should be empty directories that we can rmdir recursively
find /tmp/debian-chroot -depth -print0 | xargs -0 rmdir
@ -2793,8 +2824,6 @@ rm /tmp/debian-chroot/etc/fstab
rm /tmp/debian-chroot/etc/hostname
rm /tmp/debian-chroot/etc/resolv.conf
rm /tmp/debian-chroot/var/lib/apt/lists/lock
rm /tmp/debian-chroot/var/lib/dpkg/available
rm /tmp/debian-chroot/var/lib/dpkg/cmethopt
rm /tmp/debian-chroot/var/lib/dpkg/status
# the rest should be empty directories that we can rmdir recursively
find /tmp/debian-chroot -depth -print0 | xargs -0 rmdir
@ -2824,8 +2853,6 @@ rm /tmp/debian-chroot/etc/fstab
rm /tmp/debian-chroot/etc/hostname
rm /tmp/debian-chroot/etc/resolv.conf
rm /tmp/debian-chroot/var/lib/apt/lists/lock
rm /tmp/debian-chroot/var/lib/dpkg/available
rm /tmp/debian-chroot/var/lib/dpkg/cmethopt
rm /tmp/debian-chroot/var/lib/dpkg/status
# the rest should be empty directories that we can rmdir recursively
find /tmp/debian-chroot -depth -print0 | xargs -0 rmdir
@ -2844,8 +2871,8 @@ cat << END > shared/test.sh
set -eu
export LC_ALL=C.UTF-8
$CMD --mode=$defaultmode --variant=essential --include=apt \
--essential-hook='apt-get -o Dir="\$1" -oDir::Etc::TrustedParts=/etc/apt/trusted.gpg.d -oAcquire::Languages=none update' \
--essential-hook='apt-get --yes install --no-install-recommends -o Dir="\$1" -oDPkg::Chroot-Directory="\$1" apt' \
--essential-hook='APT_CONFIG=\$MMDEBSTRAP_APT_CONFIG apt-get update' \
--essential-hook='APT_CONFIG=\$MMDEBSTRAP_APT_CONFIG apt-get --yes install -oDPkg::Chroot-Directory="\$1" apt' \
$DEFAULT_DIST /tmp/debian-chroot.tar $mirror
tar -tf /tmp/debian-chroot.tar | sort | grep -v ./var/lib/apt/extended_states | diff -u tar1.txt -
rm /tmp/debian-chroot.tar
@ -2971,8 +2998,6 @@ rm /tmp/debian-chroot/etc/fstab
rm /tmp/debian-chroot/etc/hostname
rm /tmp/debian-chroot/etc/resolv.conf
rm /tmp/debian-chroot/var/lib/apt/lists/lock
rm /tmp/debian-chroot/var/lib/dpkg/available
rm /tmp/debian-chroot/var/lib/dpkg/cmethopt
rm /tmp/debian-chroot/var/lib/dpkg/status
# the rest should be empty directories that we can rmdir recursively
find /tmp/debian-chroot -depth -print0 | xargs -0 rmdir
@ -3216,10 +3241,6 @@ rm /tmp/debian-chroot/var/lib/dpkg/status
rm /tmp/debian-chroot/var/cache/apt/archives/lock
rm /tmp/debian-chroot/var/lib/dpkg/lock
rm /tmp/debian-chroot/var/lib/dpkg/lock-frontend
if [ "$mode" != "chrootless" ] || dpkg --compare-versions "\$(dpkg --robot --version)" lt 1.20.0; then
rm /tmp/debian-chroot/var/lib/dpkg/available
rm /tmp/debian-chroot/var/lib/dpkg/cmethopt
fi
rm /tmp/debian-chroot/var/lib/apt/lists/lock
## delete merged usr symlinks
#rm /tmp/debian-chroot/libx32
@ -3285,10 +3306,6 @@ rm /tmp/debian-chroot/var/cache/apt/archives/lock
rm /tmp/debian-chroot/var/lib/dpkg/lock
rm /tmp/debian-chroot/var/lib/dpkg/lock-frontend
rm /tmp/debian-chroot/var/lib/apt/lists/lock
if [ "$mode" != "chrootless" ] || dpkg --compare-versions "\$(dpkg --robot --version)" lt 1.20.0; then
rm /tmp/debian-chroot/var/lib/dpkg/available
rm /tmp/debian-chroot/var/lib/dpkg/cmethopt
fi
## delete merged usr symlinks
#rm /tmp/debian-chroot/libx32
#rm /tmp/debian-chroot/lib64
@ -3435,10 +3452,6 @@ rm /tmp/debian-chroot/var/cache/apt/archives/lock
rm /tmp/debian-chroot/var/lib/dpkg/lock
rm /tmp/debian-chroot/var/lib/dpkg/lock-frontend
rm /tmp/debian-chroot/var/lib/apt/lists/lock
if dpkg --compare-versions "\$(dpkg --robot --version)" lt 1.20.0; then
rm /tmp/debian-chroot/var/lib/dpkg/available
rm /tmp/debian-chroot/var/lib/dpkg/cmethopt
fi
## delete merged usr symlinks
#rm /tmp/debian-chroot/libx32
#rm /tmp/debian-chroot/lib64
@ -3497,10 +3510,6 @@ rm /tmp/debian-chroot/var/cache/apt/archives/lock
rm /tmp/debian-chroot/var/lib/dpkg/lock
rm /tmp/debian-chroot/var/lib/dpkg/lock-frontend
rm /tmp/debian-chroot/var/lib/apt/lists/lock
if dpkg --compare-versions "\$(dpkg --robot --version)" lt 1.20.0; then
rm /tmp/debian-chroot/var/lib/dpkg/available
rm /tmp/debian-chroot/var/lib/dpkg/cmethopt
fi
## delete merged usr symlinks
#rm /tmp/debian-chroot/libx32
#rm /tmp/debian-chroot/lib64

View file

@ -4,4 +4,7 @@ set -exu
rootdir="$1"
chroot "$rootdir" busybox --install -s
# Run busybox using an absolute path so that this script also works in case
# /proc is not mounted. Busybox uses /proc/self/exe to figure out the path
# to its executable.
chroot "$rootdir" /bin/busybox --install -s

View file

@ -90,6 +90,12 @@ def main():
chroot = Path(os.environ["FAKECHROOT_BASE_ORIG"])
# if chrootless mode is used from within a fakechroot chroot, then
# FAKECHROOT_BASE_ORIG will point at the outer chroot. We want to use
# the path from DPKG_ROOT inside of that instead
if os.environ.get("DPKG_ROOT", "") not in ["", "/"]:
chroot /= os.environ["DPKG_ROOT"].lstrip("/")
if not (chroot / "sbin" / "ldconfig").exists():
sys.exit(0)

View file

@ -97,7 +97,7 @@ get_oldaptnames() {
if [ ! -e "$1/$2" ]; then
return
fi
gzip -dc "$1/$2" \
xz -dc "$1/$2" \
| grep-dctrl --no-field-names --show-field=Package,Version,Architecture,Filename '' \
| paste -sd " \n" \
| while read name ver arch fname; do
@ -122,10 +122,10 @@ get_newaptnames() {
return
fi
# skip empty files by trying to uncompress the first byte of the payload
if [ "$(gzip -dc "$1/$2" | head -c1 | wc -c)" -eq 0 ]; then
if [ "$(xz -dc "$1/$2" | head -c1 | wc -c)" -eq 0 ]; then
return
fi
gzip -dc "$1/$2" \
xz -dc "$1/$2" \
| grep-dctrl --no-field-names --show-field=Package,Version,Architecture,Filename,SHA256 '' \
| paste -sd " \n" \
| while read name ver arch fname hash; do
@ -235,17 +235,17 @@ END
# /var/cache/apt/archives so that apt will not re-download *.deb
# packages that we already have
{
get_oldaptnames "$oldmirrordir" "dists/$dist/main/binary-$nativearch/Packages.gz"
get_oldaptnames "$oldmirrordir" "dists/$dist/main/binary-$nativearch/Packages.xz"
case "$dist" in oldstable|stable)
get_oldaptnames "$oldmirrordir" "dists/$dist-updates/main/binary-$nativearch/Packages.gz"
get_oldaptnames "$oldmirrordir" "dists/$dist-updates/main/binary-$nativearch/Packages.xz"
;;
esac
case "$dist" in
oldstable)
get_oldaptnames "$oldcachedir/debian-security" "dists/$dist/updates/main/binary-$nativearch/Packages.gz"
get_oldaptnames "$oldcachedir/debian-security" "dists/$dist/updates/main/binary-$nativearch/Packages.xz"
;;
stable)
get_oldaptnames "$oldcachedir/debian-security" "dists/$dist-security/main/binary-$nativearch/Packages.gz"
get_oldaptnames "$oldcachedir/debian-security" "dists/$dist-security/main/binary-$nativearch/Packages.xz"
;;
esac
} | sort -u > "$rootdir/oldaptnames"
@ -266,12 +266,12 @@ END
mkdir -p "$newmirrordir/dists/$dist/main/binary-$nativearch/"
curl --location "$mirror/dists/$dist/Release" > "$newmirrordir/dists/$dist/Release"
curl --location "$mirror/dists/$dist/Release.gpg" > "$newmirrordir/dists/$dist/Release.gpg"
curl --location "$mirror/dists/$dist/main/binary-$nativearch/Packages.gz" > "$newmirrordir/dists/$dist/main/binary-$nativearch/Packages.gz"
curl --location "$mirror/dists/$dist/main/binary-$nativearch/Packages.xz" > "$newmirrordir/dists/$dist/main/binary-$nativearch/Packages.xz"
case "$dist" in oldstable|stable)
mkdir -p "$newmirrordir/dists/$dist-updates/main/binary-$nativearch/"
curl --location "$mirror/dists/$dist-updates/Release" > "$newmirrordir/dists/$dist-updates/Release"
curl --location "$mirror/dists/$dist-updates/Release.gpg" > "$newmirrordir/dists/$dist-updates/Release.gpg"
curl --location "$mirror/dists/$dist-updates/main/binary-$nativearch/Packages.gz" > "$newmirrordir/dists/$dist-updates/main/binary-$nativearch/Packages.gz"
curl --location "$mirror/dists/$dist-updates/main/binary-$nativearch/Packages.xz" > "$newmirrordir/dists/$dist-updates/main/binary-$nativearch/Packages.xz"
;;
esac
case "$dist" in
@ -279,13 +279,13 @@ END
mkdir -p "$newcachedir/debian-security/dists/$dist/updates/main/binary-$nativearch/"
curl --location "$security_mirror/dists/$dist/updates/Release" > "$newcachedir/debian-security/dists/$dist/updates/Release"
curl --location "$security_mirror/dists/$dist/updates/Release.gpg" > "$newcachedir/debian-security/dists/$dist/updates/Release.gpg"
curl --location "$security_mirror/dists/$dist/updates/main/binary-$nativearch/Packages.gz" > "$newcachedir/debian-security/dists/$dist/updates/main/binary-$nativearch/Packages.gz"
curl --location "$security_mirror/dists/$dist/updates/main/binary-$nativearch/Packages.xz" > "$newcachedir/debian-security/dists/$dist/updates/main/binary-$nativearch/Packages.xz"
;;
stable)
mkdir -p "$newcachedir/debian-security/dists/$dist-security/main/binary-$nativearch/"
curl --location "$security_mirror/dists/$dist-security/Release" > "$newcachedir/debian-security/dists/$dist-security/Release"
curl --location "$security_mirror/dists/$dist-security/Release.gpg" > "$newcachedir/debian-security/dists/$dist-security/Release.gpg"
curl --location "$security_mirror/dists/$dist-security/main/binary-$nativearch/Packages.gz" > "$newcachedir/debian-security/dists/$dist-security/main/binary-$nativearch/Packages.gz"
curl --location "$security_mirror/dists/$dist-security/main/binary-$nativearch/Packages.xz" > "$newcachedir/debian-security/dists/$dist-security/main/binary-$nativearch/Packages.xz"
;;
esac
@ -298,17 +298,17 @@ END
# stripping the epoch from the filename and will break once mirrors change.
# This way, it doesn't matter where the mirror ends up storing the package.
{
get_newaptnames "$newmirrordir" "dists/$dist/main/binary-$nativearch/Packages.gz";
get_newaptnames "$newmirrordir" "dists/$dist/main/binary-$nativearch/Packages.xz";
case "$dist" in oldstable|stable)
get_newaptnames "$newmirrordir" "dists/$dist-updates/main/binary-$nativearch/Packages.gz"
get_newaptnames "$newmirrordir" "dists/$dist-updates/main/binary-$nativearch/Packages.xz"
;;
esac
case "$dist" in
oldstable)
get_newaptnames "$newcachedir/debian-security" "dists/$dist/updates/main/binary-$nativearch/Packages.gz"
get_newaptnames "$newcachedir/debian-security" "dists/$dist/updates/main/binary-$nativearch/Packages.xz"
;;
stable)
get_newaptnames "$newcachedir/debian-security" "dists/$dist-security/main/binary-$nativearch/Packages.gz"
get_newaptnames "$newcachedir/debian-security" "dists/$dist-security/main/binary-$nativearch/Packages.xz"
;;
esac
} | sort -u > "$rootdir/newaptnames"

View file

@ -23,13 +23,13 @@
use strict;
use warnings;
our $VERSION = '0.8.0';
our $VERSION = '0.8.1';
use English;
use Getopt::Long;
use Pod::Usage;
use File::Copy;
use File::Path qw(make_path remove_tree);
use File::Path qw(make_path);
use File::Temp qw(tempfile tempdir);
use File::Basename;
use File::Find;
@ -244,9 +244,9 @@ sub get_tar_compressor {
} elsif ($filename =~ /\.lz4$/) {
return ['lz4'];
} elsif ($filename =~ /\.(xz|txz)$/) {
return ['xz', '--threads=0'];
return ['xz'];
} elsif ($filename =~ /\.zst$/) {
return ['zstd', '--threads=0'];
return ['zstd'];
}
return;
}
@ -1550,41 +1550,6 @@ sub setup {
sub run_setup() {
my $options = shift;
my $dpkgversion = version->new(0);
{
my $pid = open my $fh, '-|' // error "failed to fork(): $!";
if ($pid == 0) {
# redirect stderr to /dev/null to hide error messages from dpkg
# versions before 1.20.0
open(STDERR, '>', '/dev/null')
or error "cannot open /dev/null for writing: $!";
exec 'dpkg', '--robot', '--version';
}
chomp(
my $content = do { local $/; <$fh> }
);
close $fh;
# the --robot option was introduced in 1.20.0 but until 1.20.2 the
# output contained a string after the version, separated by a
# whitespace -- since then, it's only the version
if ($? == 0 and $content =~ /^([0-9.]+)( .*)?$/) {
# dpkg is new enough for the --robot option
$dpkgversion = version->new($1);
}
}
my $aptversion = version->new(0);
{
my $pid = open my $fh, '-|', 'apt-get',
'--version' // error "failed to fork(): $!";
chomp(my $firstline = <$fh>);
close $fh;
if ( $? == 0
and $firstline =~ /^apt ([0-9]+\.[0-9]+\.[0-9]+) \([a-z0-9-]+\)$/)
{
$aptversion = version->new($1);
}
}
{
my @directories = (
'/etc/apt/apt.conf.d', '/etc/apt/sources.list.d',
@ -1595,8 +1560,7 @@ sub run_setup() {
push @directories, '/var/lib/dpkg';
# since we do not know the dpkg version inside the chroot at this
# point, we can only omit it in chrootless mode
if ( $options->{mode} ne 'chrootless'
or $dpkgversion < "1.20.0"
if ($options->{mode} ne 'chrootless'
or scalar @{ $options->{dpkgopts} } > 0) {
push @directories, '/etc/dpkg/dpkg.cfg.d/';
}
@ -1609,8 +1573,7 @@ sub run_setup() {
push @directories, '/var/log/apt';
# since we do not know the dpkg version inside the chroot at this
# point, we can only omit it in chrootless mode
if ( $options->{mode} ne 'chrootless'
or $dpkgversion < "1.20.0") {
if ($options->{mode} ne 'chrootless') {
push @directories, '/var/lib/dpkg/triggers',
'/var/lib/dpkg/info', '/var/lib/dpkg/alternatives',
'/var/lib/dpkg/updates';
@ -1688,24 +1651,6 @@ sub run_setup() {
# options.
print $conf "pkgCacheGen::ForceEssential \",\";\n";
}
if ($options->{dryrun}
and ($aptversion < "2.1.16")) {
# Without this option, apt will fail with:
# E: Could not configure 'libc6:amd64'.
# E: Could not perform immediate configuration on 'libgcc1:amd64'.
#
# See https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=953260
#
# For some while there were other immediate configuration problems
# which were fixed by changing the dependencies in src:glibc:
# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=972552
#
# Immediate configuration only was fixed in apt later which then also
# fixed these bugs:
# https://bugs.debian.org/973325
# https://bugs.debian.org/973305
print $conf "APT::Immediate-Configure false;\n";
}
close $conf;
# We put certain configuration items in their own configuration file
@ -1728,29 +1673,6 @@ sub run_setup() {
close $fh;
}
# /var/lib/dpkg/available is required to exist or otherwise package
# removals will fail
# since we do not know the dpkg version inside the chroot at this point, we
# can only omit it in chrootless mode
if ( $options->{mode} ne 'chrootless'
or $dpkgversion < "1.20.0") {
open my $fh, '>', "$options->{root}/var/lib/dpkg/available"
or error "failed to open(): $!";
close $fh;
}
# /var/lib/dpkg/cmethopt is used by dselect
# see #930788
# since we do not know the dpkg version inside the chroot at this point, we
# can only omit it in chrootless mode
if ( $options->{mode} ne 'chrootless'
or $dpkgversion < "1.20.0") {
open my $fh, '>', "$options->{root}/var/lib/dpkg/cmethopt"
or error "failed to open(): $!";
print $fh "apt apt\n";
close $fh;
}
# we create /var/lib/dpkg/arch inside the chroot either if there is more
# than the native architecture in the chroot or if chrootless mode is
# used to create a chroot of a different architecture than the native
@ -2039,27 +1961,10 @@ sub run_setup() {
sub run_update() {
my $options = shift;
my $aptversion = version->new(0);
{
my $pid = open my $fh, '-|', 'apt-get',
'--version' // error "failed to fork(): $!";
chomp(my $firstline = <$fh>);
close $fh;
if ( $? == 0
and $firstline =~ /^apt ([0-9]+\.[0-9]+\.[0-9]+) \([a-z0-9-]+\)$/)
{
$aptversion = version->new($1);
}
}
my $aptopts = {
ARGV => ['apt-get', 'update'],
ARGV => ['apt-get', 'update', '--error-on=any'],
CHDIR => $options->{root},
};
if ($aptversion < "2.1.16") {
$aptopts->{FIND_APT_WARNINGS} = 1;
} else {
push @{ $aptopts->{ARGV} }, '--error-on=any';
}
info "running apt-get update...";
run_apt_progress($aptopts);
@ -3102,15 +3007,14 @@ sub run_cleanup() {
# apt since 1.6 creates the auxfiles directory. If apt inside the
# chroot is older than that, then it will not know how to clean it.
if (-e "$options->{root}/var/lib/apt/lists/auxfiles") {
remove_tree("$options->{root}/var/lib/apt/lists/auxfiles",
{ error => \my $err });
if (@$err) {
for my $diag (@$err) {
my ($file, $message) = %$diag;
if ($file eq '') { warning "general error: $message"; }
else { warning "problem unlinking $file: $message"; }
}
}
0 == system(
'rm',
'--interactive=never',
'--recursive',
'--preserve-root',
'--one-file-system',
"$options->{root}/var/lib/apt/lists/auxfiles"
) or error "rm failed: $?";
}
}
@ -3180,15 +3084,11 @@ sub run_cleanup() {
next if $entry eq ".";
next if $entry eq "..";
warning "deleting files in /tmp: $entry";
remove_tree("$options->{root}/tmp/$entry",
{ error => \my $err });
if (@$err) {
for my $diag (@$err) {
my ($file, $message) = %$diag;
if ($file eq '') { warning "general error: $message"; }
else { warning "problem unlinking $file: $message"; }
}
}
0 == system(
'rm', '--interactive=never',
'--recursive', '--preserve-root',
'--one-file-system', "$options->{root}/tmp/$entry"
) or error "rm failed: $?";
}
closedir($dh);
}
@ -4564,8 +4464,11 @@ sub main() {
$ENV{PATH} = "/usr/sbin:/usr/bin:/sbin:/bin";
}
foreach my $tool ('dpkg', 'dpkg-deb', 'apt-get', 'apt-cache', 'apt-config',
'tar') {
foreach my $tool (
'dpkg', 'dpkg-deb', 'apt-get', 'apt-cache',
'apt-config', 'tar', 'rm', 'find',
'env'
) {
my $found = 0;
foreach my $path (split /:/, $ENV{PATH}) {
if (-f "$path/$tool" && -x _ ) {
@ -4578,6 +4481,49 @@ sub main() {
}
}
{
my $dpkgversion = version->new(0);
my $pid = open my $fh, '-|' // error "failed to fork(): $!";
if ($pid == 0) {
# redirect stderr to /dev/null to hide error messages from dpkg
# versions before 1.20.0
open(STDERR, '>', '/dev/null')
or error "cannot open /dev/null for writing: $!";
exec 'dpkg', '--robot', '--version';
}
chomp(
my $content = do { local $/; <$fh> }
);
close $fh;
# the --robot option was introduced in 1.20.0 but until 1.20.2 the
# output contained a string after the version, separated by a
# whitespace -- since then, it's only the version
if ($? == 0 and $content =~ /^([0-9.]+)( .*)?$/) {
# dpkg is new enough for the --robot option
$dpkgversion = version->new($1);
}
if ($dpkgversion < "1.20.0") {
error "need dpkg >= 1.20.0 but have $dpkgversion";
}
}
{
my $aptversion = version->new(0);
my $pid = open my $fh, '-|', 'apt-get',
'--version' // error "failed to fork(): $!";
chomp(
my $content = do { local $/; <$fh> }
);
close $fh;
if ( $? == 0
and $content =~ /^apt ([0-9]+\.[0-9]+\.[0-9]+) \([a-z0-9-]+\)$/m) {
$aptversion = version->new($1);
}
if ($aptversion < "2.3.7") {
error "need apt >= 2.3.7 but have $aptversion";
}
}
my $check_fakechroot_running = sub {
# test if we are inside fakechroot already
# We fork a child process because setting FAKECHROOT_DETECT seems to
@ -5950,31 +5896,18 @@ sub main() {
# no risk of removing anything important.
$pid = get_unshare_cmd(
sub {
# File::Path will produce the error "cannot stat initial
# working directory" if the working directory cannot be
# accessed by the unprivileged unshared user. Thus, we
# first navigate to the parent of the root directory.
chdir "$options->{root}/.."
or error "unable to chdir() to parent directory of"
. " $options->{root}: $!";
remove_tree($options->{root}, { error => \my $err });
if (@$err) {
for my $diag (@$err) {
my ($file, $message) = %$diag;
if ($file eq '') {
warning "general error: $message";
} else {
# the unshared process might not have
# sufficient permissions to remove the root
# directory. We attempt its removal later, so
# don't warn if its removal fails now.
if ($file ne $options->{root}) {
warning
"problem unlinking $file: $message";
}
}
}
}
# change CWD to chroot directory because find tries to
# chdir to the current directory which might not be
# accessible by the unshared user:
# find: Failed to restore initial working directory
0 == system('env', "--chdir=$options->{root}", 'find',
$options->{root}, '-mount',
'-mindepth', '1', '-delete')
or error "rm failed: $?";
# ignore failure in case the unshared user doesn't have the
# required permissions -- we attempt again later if
# necessary
rmdir "$options->{root}";
},
\@idmap
);
@ -5982,8 +5915,7 @@ sub main() {
$? == 0 or error "remove_tree failed";
# in unshare mode, the toplevel directory might've been created in
# a directory that the unshared user cannot change and thus cannot
# delete. If the root directory still exists after remove_tree
# above, we attempt its removal again outside as the normal user.
# delete. We attempt its removal again outside as the normal user.
if (-e $options->{root}) {
rmdir "$options->{root}"
or error "cannot rmdir $options->{root}: $!";
@ -6001,7 +5933,7 @@ sub main() {
# be removed.
0 == system('rm', '--interactive=never', '--recursive',
'--preserve-root', '--one-file-system', $options->{root})
or error "rm failed: $!";
or error "rm failed: $?";
} else {
error "unknown mode: $options->{mode}";
}
@ -7133,9 +7065,9 @@ extension to compressor applies:
.tlz lzma
.lzo lzop
.lz4 lz4
.xz xz --threads=0
.txz xz --threads=0
.zst zstd --threads=0
.xz xz
.txz xz
.zst zstd
To change compression specific options, either use the respecitve environment
variables like B<XZ_OPT> or send B<mmdebstrap> output to your compressor of