Compare commits

..

No commits in common. "2f768b07dc93103ed70c49ee653641164621e2df" and "f2020cf3ed5a9c634fd75a2b29407c21cd022558" have entirely different histories.

10 changed files with 105 additions and 220 deletions

View file

@ -20,8 +20,6 @@ if [ -e ./mmdebstrap ]; then
fi fi
perlcritic --severity 4 --verbose 8 ./mmdebstrap perlcritic --severity 4 --verbose 8 ./mmdebstrap
pod2man ./mmdebstrap >/dev/null
fi fi
for f in tarfilter coverage.py caching_proxy.py; do for f in tarfilter coverage.py caching_proxy.py; do
@ -29,7 +27,7 @@ for f in tarfilter coverage.py caching_proxy.py; do
black --check "./$f" black --check "./$f"
done done
shellcheck --exclude=SC2016 coverage.sh make_mirror.sh run_null.sh run_qemu.sh gpgvnoexpkeysig mmdebstrap-autopkgtest-build-qemu hooks/*/*.sh 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"

View file

@ -449,7 +449,7 @@ if [ "$HAVE_QEMU" = "yes" ]; then
tmpdir="$(mktemp -d)" tmpdir="$(mktemp -d)"
trap 'kill "$PROXYPID" || :;cleanuptmpdir; cleanup_newcachedir' EXIT INT TERM trap 'kill "$PROXYPID" || :;cleanuptmpdir; cleanup_newcachedir' EXIT INT TERM
pkgs=perl-doc,systemd-sysv,perl,arch-test,fakechroot,fakeroot,mount,uidmap,qemu-user-static,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,squashfs-tools-ng,genext2fs,linux-image-generic,passwd pkgs=perl-doc,systemd-sysv,perl,arch-test,fakechroot,fakeroot,mount,uidmap,qemu-user-static,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,squashfs-tools-ng,genext2fs,linux-image-generic
if [ ! -e ./mmdebstrap ]; then if [ ! -e ./mmdebstrap ]; then
pkgs="$pkgs,mmdebstrap" pkgs="$pkgs,mmdebstrap"
fi fi
@ -493,8 +493,6 @@ mount -t 9p -o trans=virtio,access=any,msize=128k mmdebstrap /mnt
# need to restart mini-httpd because we mounted different content into www-root # need to restart mini-httpd because we mounted different content into www-root
systemctl restart mini-httpd systemctl restart mini-httpd
ip link set enp0s1 down || :
handler () { handler () {
while IFS= read -r line || [ -n "$line" ]; do while IFS= read -r line || [ -n "$line" ]; do
printf "%s %s: %s\n" "$(date -u -d "0 $(date +%s.%3N) seconds - $2 seconds" +"%T.%3N")" "$1" "$line" printf "%s %s: %s\n" "$(date -u -d "0 $(date +%s.%3N) seconds - $2 seconds" +"%T.%3N")" "$1" "$line"
@ -532,8 +530,7 @@ END
fi fi
# set PATH to pick up the correct mmdebstrap variant # set PATH to pick up the correct mmdebstrap variant
env PATH="$(dirname "$(realpath --canonicalize-existing "$CMD")"):$PATH" \ env PATH="$(dirname "$(realpath --canonicalize-existing "$CMD")"):$PATH" \
debvm-create --skip=usrmerge,systemdnetwork \ debvm-create --skip=usrmerge --size="$DISK_SIZE" --release="$DEFAULT_DIST" \
--size="$DISK_SIZE" --release="$DEFAULT_DIST" \
--output="$newcachedir/debian-$DEFAULT_DIST.ext4" -- \ --output="$newcachedir/debian-$DEFAULT_DIST.ext4" -- \
--architectures="$arches" --include="$pkgs" \ --architectures="$arches" --include="$pkgs" \
--setup-hook='echo "Acquire::http::Proxy \"http://127.0.0.1:8080/\";" > "$1/etc/apt/apt.conf.d/00proxy"' \ --setup-hook='echo "Acquire::http::Proxy \"http://127.0.0.1:8080/\";" > "$1/etc/apt/apt.conf.d/00proxy"' \
@ -544,7 +541,7 @@ END
--customize-hook='touch "$1/mmdebstrap-testenv"' \ --customize-hook='touch "$1/mmdebstrap-testenv"' \
--customize-hook='copy-in "'"$tmpdir"'/mmdebstrap.service" /etc/systemd/system/' \ --customize-hook='copy-in "'"$tmpdir"'/mmdebstrap.service" /etc/systemd/system/' \
--customize-hook='copy-in "'"$tmpdir"'/worker.sh" /' \ --customize-hook='copy-in "'"$tmpdir"'/worker.sh" /' \
--customize-hook='echo 127.0.0.1 localhost > "$1/etc/hosts"' \ --customize-hook='printf 127.0.0.1 localhost > "$1/etc/hosts"' \
--customize-hook='printf "START=1\nDAEMON_OPTS=\"-h 127.0.0.1 -p 80 -u nobody -dd /mnt/cache -i /var/run/mini-httpd.pid -T UTF-8\"\n" > "$1/etc/default/mini-httpd"' \ --customize-hook='printf "START=1\nDAEMON_OPTS=\"-h 127.0.0.1 -p 80 -u nobody -dd /mnt/cache -i /var/run/mini-httpd.pid -T UTF-8\"\n" > "$1/etc/default/mini-httpd"' \
"$mirror" "$mirror"

View file

@ -1953,7 +1953,7 @@ sub run_setup() {
# since we do not know the dpkg version inside the chroot at this # since we do not know the dpkg version inside the chroot at this
# point, we can only omit it in chrootless mode # point, we can only omit it in chrootless mode
if ($options->{mode} ne 'chrootless' if ($options->{mode} ne 'chrootless'
or length $options->{dpkgopts} > 0) { or scalar @{ $options->{dpkgopts} } > 0) {
push @directories, '/etc/dpkg/dpkg.cfg.d/'; push @directories, '/etc/dpkg/dpkg.cfg.d/';
} }
# if dpkg and apt operate from the outside we need some more # if dpkg and apt operate from the outside we need some more
@ -2083,11 +2083,26 @@ sub run_setup() {
close $fh; close $fh;
} }
if (length $options->{aptopts} > 0 if (scalar @{ $options->{aptopts} } > 0
and (!-e "$options->{root}/etc/apt/apt.conf.d/99mmdebstrap")) { and (!-e "$options->{root}/etc/apt/apt.conf.d/99mmdebstrap")) {
open my $fh, '>', "$options->{root}/etc/apt/apt.conf.d/99mmdebstrap" open my $fh, '>', "$options->{root}/etc/apt/apt.conf.d/99mmdebstrap"
or error "cannot open /etc/apt/apt.conf.d/99mmdebstrap: $!"; or error "cannot open /etc/apt/apt.conf.d/99mmdebstrap: $!";
print $fh $options->{aptopts}; foreach my $opt (@{ $options->{aptopts} }) {
if (-r $opt) {
# flush handle because copy() uses syswrite() which bypasses
# buffered IO
$fh->flush();
copy $opt, $fh or error "cannot copy $opt: $!";
} else {
print $fh $opt;
if ($opt !~ /;$/) {
print $fh ';';
}
if ($opt !~ /\n$/) {
print $fh "\n";
}
}
}
close $fh; close $fh;
if ($verbosity_level >= 3) { if ($verbosity_level >= 3) {
debug "content of /etc/apt/apt.conf.d/99mmdebstrap:"; debug "content of /etc/apt/apt.conf.d/99mmdebstrap:";
@ -2095,7 +2110,7 @@ sub run_setup() {
} }
} }
if (length $options->{dpkgopts} > 0 if (scalar @{ $options->{dpkgopts} } > 0
and (!-e "$options->{root}/etc/dpkg/dpkg.cfg.d/99mmdebstrap")) { and (!-e "$options->{root}/etc/dpkg/dpkg.cfg.d/99mmdebstrap")) {
# FIXME: in chrootless mode, dpkg will only read the configuration # FIXME: in chrootless mode, dpkg will only read the configuration
# from the host -- see #808203 # from the host -- see #808203
@ -2105,7 +2120,19 @@ sub run_setup() {
} }
open my $fh, '>', "$options->{root}/etc/dpkg/dpkg.cfg.d/99mmdebstrap" open my $fh, '>', "$options->{root}/etc/dpkg/dpkg.cfg.d/99mmdebstrap"
or error "cannot open /etc/dpkg/dpkg.cfg.d/99mmdebstrap: $!"; or error "cannot open /etc/dpkg/dpkg.cfg.d/99mmdebstrap: $!";
print $fh $options->{dpkgopts}; foreach my $opt (@{ $options->{dpkgopts} }) {
if (-r $opt) {
# flush handle because copy() uses syswrite() which bypasses
# buffered IO
$fh->flush();
copy $opt, $fh or error "cannot copy $opt: $!";
} else {
print $fh $opt;
if ($opt !~ /\n$/) {
print $fh "\n";
}
}
}
close $fh; close $fh;
if ($verbosity_level >= 3) { if ($verbosity_level >= 3) {
debug "content of /etc/dpkg/dpkg.cfg.d/99mmdebstrap:"; debug "content of /etc/dpkg/dpkg.cfg.d/99mmdebstrap:";
@ -2207,8 +2234,6 @@ sub run_setup() {
chmod $mode, "$options->{root}/$file" chmod $mode, "$options->{root}/$file"
or error "cannot chmod $file: $!"; or error "cannot chmod $file: $!";
} }
} elsif (-e $file && -e "$options->{root}/$file") {
info "rootfs alreday contains $file";
} else { } else {
warning("Host system does not have a $file to copy into the" warning("Host system does not have a $file to copy into the"
. " rootfs."); . " rootfs.");
@ -3112,7 +3137,7 @@ sub run_cleanup() {
} else { } else {
# clean up temporary configuration file # clean up temporary configuration file
unlink "$options->{root}/etc/apt/apt.conf.d/00mmdebstrap" unlink "$options->{root}/etc/apt/apt.conf.d/00mmdebstrap"
or warning "failed to unlink /etc/apt/apt.conf.d/00mmdebstrap: $!"; or error "failed to unlink /etc/apt/apt.conf.d/00mmdebstrap: $!";
if (defined $ENV{APT_CONFIG} && -e $ENV{APT_CONFIG}) { if (defined $ENV{APT_CONFIG} && -e $ENV{APT_CONFIG}) {
unlink $ENV{APT_CONFIG} unlink $ENV{APT_CONFIG}
@ -4493,8 +4518,8 @@ sub main() {
architectures => [$hostarch], architectures => [$hostarch],
mode => 'auto', mode => 'auto',
format => 'auto', format => 'auto',
dpkgopts => '', dpkgopts => [],
aptopts => '', aptopts => [],
apttrusted => $apttrusted, apttrusted => $apttrusted,
apttrustedparts => $apttrustedparts, apttrustedparts => $apttrustedparts,
noop => [], noop => [],
@ -4561,44 +4586,9 @@ sub main() {
}, },
'architectures=s@' => \$options->{architectures}, 'architectures=s@' => \$options->{architectures},
'mode=s' => \$options->{mode}, 'mode=s' => \$options->{mode},
'dpkgopt=s' => sub { 'dpkgopt=s@' => \$options->{dpkgopts},
my ($opt_name, $opt_value) = @_; 'aptopt=s@' => \$options->{aptopts},
if (-r $opt_value) { 'keyring=s' => sub {
open my $fh, '<', $opt_value
or error "failed to open $opt_value: $!";
$options->{dpkgopts} .= do { local $/; <$fh> };
if ($options->{dpkgopts} !~ /\n$/) {
print $fh "\n";
}
close $fh;
} else {
$options->{dpkgopts} .= $opt_value;
if ($opt_value !~ /\n$/) {
$options->{dpkgopts} .= "\n";
}
}
},
'aptopt=s' => sub {
my ($opt_name, $opt_value) = @_;
if (-r $opt_value) {
open my $fh, '<', $opt_value
or error "failed to open $opt_value: $!";
$options->{aptopts} .= do { local $/; <$fh> };
if ($options->{aptopts} !~ /\n$/) {
print $fh "\n";
}
close $fh;
} else {
$options->{aptopts} .= $opt_value;
if ($opt_value !~ /;$/) {
$options->{aptopts} .= ';';
}
if ($opt_value !~ /\n$/) {
$options->{aptopts} .= "\n";
}
}
},
'keyring=s' => sub {
my ($opt_name, $opt_value) = @_; my ($opt_name, $opt_value) = @_;
if ($opt_value =~ /"/) { if ($opt_value =~ /"/) {
error "--keyring: apt cannot handle paths with double quotes:" error "--keyring: apt cannot handle paths with double quotes:"
@ -4732,7 +4722,7 @@ sub main() {
} }
push @{ $options->{skip} }, $skip; push @{ $options->{skip} }, $skip;
} }
}) or pod2usage(-exitval => 2, -verbose => 0); }) or pod2usage(-exitval => 2, -verbose => 1);
if (defined($logfile)) { if (defined($logfile)) {
open(STDERR, '>', $logfile) or error "cannot open $logfile: $!"; open(STDERR, '>', $logfile) or error "cannot open $logfile: $!";
@ -4949,17 +4939,9 @@ sub main() {
test_unshare_userns(1); test_unshare_userns(1);
} }
} elsif ($options->{mode} eq 'chrootless') { } elsif ($options->{mode} eq 'chrootless') {
if (any { $_ eq 'check/chrootless' } @{ $options->{skip} }) { if ($EFFECTIVE_USER_ID == 0) {
info "skipping check/chrootless as requested"; warning "running chrootless mode as root might damage the host "
} else { . "system";
my $ischroot = 0 == system 'ischroot';
if ( $EFFECTIVE_USER_ID == 0
&& !exists $ENV{FAKEROOTKEY}
&& !$ischroot) {
error
"running chrootless mode as root without fakeroot might "
. "damage the host system if not run inside a chroot";
}
} }
} else { } else {
error "unknown mode: $options->{mode}"; error "unknown mode: $options->{mode}";
@ -6410,52 +6392,45 @@ 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 dependency relationships. See section B<OPERATION> for an overview of complex dependencies. See section B<OPERATION> for an overview of how
how B<mmdebstrap> works internally. B<mmdebstrap> works internally.
The I<SUITE> option may either be a valid release code name (eg, sid, bookworm, If no I<MIRROR> option is provided and I<SUITE> is not a stable release name,
trixie) or a symbolic name (eg, unstable, testing, stable, oldstable). Any L<http://deb.debian.org/debian> is used. If I<SUITE> is a stable release name
suite name that works with apt on the given mirror will work. The I<SUITE> and no I<MIRROR> is specified, then mirrors for updates and security are
option is optional if no I<TARGET> and no I<MIRROR> option is provided. If automatically added. If a I<MIRROR> option starts with "deb " or "deb-src "
I<SUITE> is missing, then the information of the desired suite has to come from then it is used as a one-line-style format entry for apt's sources.list inside
standard input as part of a valid apt sources.list file or be set up via hooks. the chroot. If a I<MIRROR> option contains a "://" then it is interpreted as a
mirror URI and the apt line inside the chroot is assembled as "deb [arch=A] B C
D" where A is the host's native architecture, B is the I<MIRROR>, C is the
given I<SUITE> and D is the components given via B<--components> (defaults to
"main"). If a I<MIRROR> option happens to be an existing file, then its
contents are pasted into the chroot's sources.list. This can be used to supply
a deb822 style sources.list. If I<MIRROR> is C<-> then standard input is pasted
into the chroot's sources.list. More than one mirror can be specified and are
appended to the chroot's sources.list in the given order. If you specify a
https or tor I<MIRROR> and you want the chroot to be able to update itself,
don't forget to also install the ca-certificates package, the
apt-transport-https package for apt versions less than 1.5 and/or the
apt-transport-tor package using the B<--include> option, as necessary.
The optional I<TARGET> argument can either be the path to a directory, the path
to a tarball filename, the path to a squashfs image, the path to an ext2 image,
a FIFO, a character special device, or C<->. Without the B<--format> option,
I<TARGET> will be used to choose the format. See the section B<FORMATS> for
more information. If no I<TARGET> was specified or if I<TARGET> is C<->, an
uncompressed tarball will be sent to standard output.
The I<SUITE> may be a valid release code name (eg, sid, stretch, jessie) or a
symbolic name (eg, unstable, testing, stable, oldstable). Any suite name that
works with apt on the given mirror will work. If no I<SUITE> was specified,
then a single I<MIRROR> C<-> is added and thus the information of the desired
suite has to come from standard input as part of a valid apt sources.list file.
The value of the I<SUITE> argument will be used to determine which apt index to The value of the I<SUITE> argument will be used to determine which apt index to
use for finding out the set of C<Essential:yes> packages and/or the set of use for finding out the set of C<Essential:yes> packages and/or the set of
packages with the right priority for the selected variant. This functionality packages with the right priority for the selected variant. See the section
can be disabled by choosing the empty string for I<SUITE>. See the section
B<VARIANTS> for more information. B<VARIANTS> for more information.
The I<TARGET> option may either be the path to a directory, the path to a
tarball filename, the path to a squashfs image, the path to an ext2 image, a
FIFO, a character special device, or C<->. The I<TARGET> option is optional if
no I<MIRROR> option is provided. If I<TARGET> is missing or if I<TARGET> is
C<->, an uncompressed tarball will be sent to standard output. Without the
B<--format> option, I<TARGET> will be used to choose the format. See the
section B<FORMATS> for more information.
The I<MIRROR> option may either be provided as a URI, in apt one-line format,
as a path to a file in apt's one-line or deb822-format, or C<->. If no
I<MIRROR> option is provided, then L<http://deb.debian.org/debian> is used as
the default. If I<SUITE> does not refer to "unstable" or "testing", then
I<SUITE>-updates and I<SUITE>-security mirrors are automatically added. If a
I<MIRROR> option starts with "deb " or "deb-src " then it is used as a one-line
format entry for apt's sources.list inside the chroot. If a I<MIRROR> option
contains a "://" then it is interpreted as a mirror URI and the apt line inside
the chroot is assembled as "deb [arch=A] B C D" where A is the host's native
architecture, B is the I<MIRROR>, C is the given I<SUITE> and D is the
components given via B<--components> (defaults to "main"). If a I<MIRROR>
option happens to be an existing file, then its contents are written into the
chroot's sources.list (if the first I<MIRROR> is a file in one-line format) or
into the chroot's sources.list.d directory, named with the extension .list or
.sources, depending on whether the file is in one-line or deb822 format,
respectively. If I<MIRROR> is C<-> then standard input is pasted into the
chroot's sources.list. More than one mirror can be specified and are appended
to the chroot's sources.list in the given order. If you specify a https or tor
I<MIRROR> and you want the chroot to be able to update itself, don't forget to
also install the ca-certificates package, the apt-transport-https package for
apt versions less than 1.5 and/or the apt-transport-tor package using the
B<--include> option, as necessary.
All status output is printed to standard error unless B<--logfile> is used to All status output is printed to standard error unless B<--logfile> is used to
redirect it to a file or B<--quiet> or B<--silent> is used to suppress any redirect it to a file or B<--quiet> or B<--silent> is used to suppress any
output on standard error. Help and version information will be printed to output on standard error. Help and version information will be printed to
@ -6928,11 +6903,6 @@ available and you know your subuid/subgid offset (100000 in this example):
$ sudo systemd-nspawn --private-users=100000 \ $ sudo systemd-nspawn --private-users=100000 \
> --directory=./debian-rootfs /bin/bash > --directory=./debian-rootfs /bin/bash
A directory created in B<unshare> mode cannot be removed the normal way.
Instead, use something like this:
$ unshare --map-root-user --map-auto rm -rf ./debian-rootfs
If this mode is used as the root user, the user namespace is not unshared (but If this mode is used as the root user, the user namespace is not unshared (but
the mount namespace and other still are) and created directories will have the mount namespace and other still are) and created directories will have
correct ownership information. This is also useful in cases where the root user correct ownership information. This is also useful in cases where the root user
@ -6964,13 +6934,10 @@ dpkg-root-support usertag of debian-dpkg@lists.debian.org in the Debian bug
tracking system. B<WARNING>: if this option is used carelessly with packages tracking system. B<WARNING>: if this option is used carelessly with packages
that do not support C<DPKG_ROOT>, this mode can result in undesired changes to that do not support C<DPKG_ROOT>, this mode can result in undesired changes to
the system running B<mmdebstrap> because maintainer-scripts will be run without the system running B<mmdebstrap> because maintainer-scripts will be run without
L<chroot(1)>. Make sure to run this mode without superuser privileges and/or L<chroot(1)>.
inside a throw-away chroot enviroment like so:
mmdebstrap --variant=apt --include=mmdebstrap \ =for TODO
--customize-hook='chroot "$1" mmdebstrap --mode=chrootless =item B<qemu>
--variant=apt unstable chrootless.tar' \
--customize-hook='copy-out chrootless.tar .' unstable /dev/null
=back =back
@ -7001,9 +6968,7 @@ then this variant will fail because it cannot configure the packages.
=item B<essential> =item B<essential>
C<Essential:yes> packages. If I<SUITE> is a non-empty string, then only C<Essential:yes> packages.
packages from the archive with suite or codename matching I<SUITE> will be
considered for selection of C<Essential:yes> packages.
=item B<apt> =item B<apt>
@ -7018,7 +6983,7 @@ ignored without throwing an error.
=item B<required>, B<minbase> =item B<required>, B<minbase>
The B<essential> set plus all packages with Priority:required. The B<essential> set plus all packages with Priority:required and apt.
It is roughly equivalent to running mmdebstrap with It is roughly equivalent to running mmdebstrap with
--variant=essential --include="?priority(required)" --variant=essential --include="?priority(required)"
@ -7275,8 +7240,6 @@ Upon startup, several checks are carried out, like:
=item * which mode to use and whether prerequisites are met =item * which mode to use and whether prerequisites are met
=item * do not allow chrootless mode as root (without fakeroot) unless inside a chroot. This check can be disabled using B<--skip=check/chrootless>
=item * whether the requested architecture can be executed (requires arch-test) using qemu binfmt_misc support. This requires arch-test and can be disabled using B<--skip=check/qemu> =item * whether the requested architecture can be executed (requires arch-test) using qemu binfmt_misc support. This requires arch-test and can be disabled using B<--skip=check/qemu>
=item * how the apt sources can be assembled from I<SUITE>, I<MIRROR> and B<--components> and/or from standard input as deb822 or one-line format and whether the required GPG keys exist. =item * how the apt sources can be assembled from I<SUITE>, I<MIRROR> and B<--components> and/or from standard input as deb822 or one-line format and whether the required GPG keys exist.

View file

@ -30,9 +30,7 @@ B<mmdebstrap-autopkgtest-build-qemu> is a mostly compatible drop-in replacement
for L<autopkgtest-build-qemu(1)> with two main differences: Firstly, it uses for L<autopkgtest-build-qemu(1)> with two main differences: Firstly, it uses
L<mmdebstrap(1)> instead of L<vmdb2(1)> and thus is able to create QEMU disk L<mmdebstrap(1)> instead of L<vmdb2(1)> and thus is able to create QEMU disk
images without requiring superuser privileges. Secondly, it uses images without requiring superuser privileges. Secondly, it uses
L<systemd-boot(7)> and thus only supports booting via EFI. For architectures L<systemd-boot(7)> and thus only supports booting via EFI.
for which L<autopkgtest-virt-qemu(1)> does not default to EFI booting you must
pass B<--boot=efi> when invoking the autopkgtest virt backend.
=head1 POSITIONAL PARAMETERS =head1 POSITIONAL PARAMETERS
@ -98,17 +96,9 @@ Passes an additional B<--keyring> parameter to B<mmdebstrap>.
=head1 EXAMPLES =head1 EXAMPLES
Make sure, that F</path/to/debian-unstable.img> is a path that the unshared $ mmdebstrap-autopkgtest-build-qemu --boot=efi stable /path/to/debian-stable-i386.img i386
user has access to. This can be done by ensuring world-execute permissions on
all path components or by creating the image in a world-readable directory like
/tmp before copying it into its final location.
$ mmdebstrap-autopkgtest-build-qemu --boot=efi --arch=amd64 unstable /path/to/debian-unstable.img $ mmdebstrap-autopkgtest-build-qemu --boot=efi unstable /path/to/debian-unstable.img
[...]
$ autopkgtest mypackage -- qemu --boot=efi --dpkg-architecture=amd64 /path/to/debian-unstable.img
Make sure to add B<--boot=efi> to both the B<mmdebstrap-autopkgtest-build-qemu>
as well as the B<autopkgtest-virt-qemu> invocation.
=head1 SEE ALSO =head1 SEE ALSO
@ -233,31 +223,21 @@ test "$BOOT" = efi ||
case "$ARCHITECTURE" in case "$ARCHITECTURE" in
amd64) amd64)
EFIIMG=bootx64.efi EFIIMG=bootx64.efi
QEMUARCH=x86_64
VMFPKG=ovmf
;; ;;
arm64) arm64)
EFIIMG=bootaa64.efi EFIIMG=bootaa64.efi
QEMUARCH=aarch64
VMFPKG=qemu-efi-aarch64
;; ;;
armhf) armhf)
EFIIMG=bootarm.efi EFIIMG=bootarm.efi
QEMUARCH=arm
VMFPKG=qemu-efi-arm
;; ;;
i386) i386)
EFIIMG=bootia32.efi EFIIMG=bootia32.efi
QEMUARCH=i386
VMFPKG=ovmf-ia32
;; ;;
riscv64) riscv64)
EFIIMG=bootriscv64.efi EFIIMG=bootriscv64.efi
QEMUARCH=riscv64
VMFPKG=
;; ;;
*) *)
die "unsupported architecture: $ARCHITECTURE" die "unsupported architecture"
;; ;;
esac esac
@ -270,17 +250,9 @@ else
test "$(dpkg-query -f '${db:Status-Status}' -W "binutils$GNU_SUFFIX")" = installed || test "$(dpkg-query -f '${db:Status-Status}' -W "binutils$GNU_SUFFIX")" = installed ||
die "please install binutils$GNU_SUFFIX or binutils-multiarch" die "please install binutils$GNU_SUFFIX or binutils-multiarch"
fi fi
arches=" $(dpkg --print-architecture) $(dpkg --print-foreign-architectures | tr '\n' ' ') "
case $arches in
*" $ARCHITECTURE "*) : ;; # nothing to do
*) die "enable $ARCHITECTURE by running: sudo dpkg --add-architecture $ARCHITECTURE && sudo apt update" ;;
esac
for pkg in autopkgtest dosfstools e2fsprogs fdisk mount mtools passwd "systemd-boot-efi:$ARCHITECTURE" uidmap; do for pkg in autopkgtest dosfstools e2fsprogs fdisk mount mtools passwd "systemd-boot-efi:$ARCHITECTURE" uidmap; do
if [ "$(dpkg-query -f '${db:Status-Status}' -W "$pkg")" != installed ]; then test "$(dpkg-query -f '${db:Status-Status}' -W "$pkg")" = installed ||
die "please install $pkg" die "please install $pkg"
fi
done done
BOOTSTUB="/usr/lib/systemd/boot/efi/linux${EFIIMG#boot}.stub" BOOTSTUB="/usr/lib/systemd/boot/efi/linux${EFIIMG#boot}.stub"
@ -306,14 +278,6 @@ rm -f "$IMAGE"
unshare -U -r --map-groups=auto chown 0:1 "$IMAGE" unshare -U -r --map-groups=auto chown 0:1 "$IMAGE"
chmod 0660 "$IMAGE" chmod 0660 "$IMAGE"
# Make sure that the unshared user is able to access the file.
# Alternatively to using /sbin/mkfs.ext4 could use --format=ext2 which would
# add an extra copy operation and come with the limitations of ext2.
# Another solution: https://github.com/tytso/e2fsprogs/pull/118
if ! mmdebstrap --unshare-helper touch "$IMAGE"; then
die "$IMAGE cannot be accessed by the unshared user -- either make all path components up to the image itself world-executable or place the image into a world-readable path like /tmp"
fi
set -- \ set -- \
--mode=unshare \ --mode=unshare \
--variant=important \ --variant=important \
@ -423,12 +387,3 @@ start=$((FAT_OFFSET_SECTORS + FAT_SIZE_SECTORS)), type=0FC63DAF-8483-4772-8E79-3
EOF EOF
dd if="$WORKDIR/fat" of="$IMAGE" conv=notrunc,sparse bs=512 "seek=$FAT_OFFSET_SECTORS" status=none dd if="$WORKDIR/fat" of="$IMAGE" conv=notrunc,sparse bs=512 "seek=$FAT_OFFSET_SECTORS" status=none
if test "$(dpkg --print-architecture)" != "$ARCHITECTURE" && test "$(dpkg-query -f '${db:Status-Status}' -W "qemu-system-$QEMUARCH")" != installed; then
echo "I: you might need to install a package providing qemu-system-$QEMUARCH to use this image with autopkgtest-virt-qemu" >&2
fi
if test -n "$VMFPKG" && test "$(dpkg-query -f '${db:Status-Status}' -W "$VMFPKG")" != installed; then
echo "I: you might need to install $VMFPKG to use this image with autopkgtest-virt-qemu" >&2
fi
echo "I: don't forget to pass --boot=efi when running autopkgtest-virt-qemu with this image" >&2

View file

@ -10,6 +10,9 @@ cleanup() {
rv=$? rv=$?
rm -f "$tmpdir/log" rm -f "$tmpdir/log"
[ -e "$tmpdir" ] && rmdir "$tmpdir" [ -e "$tmpdir" ] && rmdir "$tmpdir"
if [ -n "${TAIL_PID:-}" ]; then
kill "$TAIL_PID"
fi
if [ -e shared/output.txt ]; then if [ -e shared/output.txt ]; then
res="$(cat shared/exitstatus.txt)" res="$(cat shared/exitstatus.txt)"
if [ "$res" != "0" ]; then if [ "$res" != "0" ]; then
@ -27,7 +30,8 @@ if [ -e shared/output.txt ]; then
rm shared/output.txt rm shared/output.txt
fi fi
touch shared/output.txt touch shared/output.txt
setpriv --pdeathsig TERM tail -f shared/output.txt & tail -f shared/output.txt &
TAIL_PID=$!
# to connect to serial use: # to connect to serial use:
# minicom -D 'unix#/tmp/ttyS0' # minicom -D 'unix#/tmp/ttyS0'
@ -36,7 +40,6 @@ setpriv --pdeathsig TERM tail -f shared/output.txt &
# 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 debvm-run --image="$(realpath "$cachedir")/debian-$DEFAULT_DIST.ext4" -- \ timeout --foreground 40m debvm-run --image="$(realpath "$cachedir")/debian-$DEFAULT_DIST.ext4" -- \
-nic none \
-m 4G -snapshot \ -m 4G -snapshot \
-monitor unix:/tmp/monitor,server,nowait \ -monitor unix:/tmp/monitor,server,nowait \
-serial unix:/tmp/ttyS0,server,nowait \ -serial unix:/tmp/ttyS0,server,nowait \

View file

@ -13,7 +13,6 @@ echo "SOURCE_DATE_EPOCH=$SOURCE_DATE_EPOCH"
{{ CMD }} --variant={{ VARIANT }} --mode={{ MODE }} \ {{ CMD }} --variant={{ VARIANT }} --mode={{ MODE }} \
--essential-hook='[ {{ DIST }} = oldstable ] && [ {{ VARIANT }} = - ] && echo _apt:*:100:65534::/nonexistent:/usr/sbin/nologin >> "$1"/etc/passwd || :' \ --essential-hook='[ {{ DIST }} = oldstable ] && [ {{ VARIANT }} = - ] && echo _apt:*:100:65534::/nonexistent:/usr/sbin/nologin >> "$1"/etc/passwd || :' \
"$(if [ {{ DIST }} = oldstable ]; then echo --merged-usr; else echo --hook-dir=./hooks/merged-usr; fi)" \ "$(if [ {{ DIST }} = oldstable ]; then echo --merged-usr; else echo --hook-dir=./hooks/merged-usr; fi)" \
"$(case {{ DIST }} in oldstable) echo --include=e2fsprogs,mount,tzdata,gcc-9-base;; stable) echo --include=e2fsprogs,mount,tzdata;; *) echo --include=base-files ;; 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
@ -177,30 +176,11 @@ fi
# since debootstrap 1.0.133 there is no tzdata in the buildd variant and thus # since debootstrap 1.0.133 there is no tzdata in the buildd variant and thus
# debootstrap creates its own /etc/localtime # debootstrap creates its own /etc/localtime
if [ "{{ VARIANT }}" = "buildd" ] && [ "{{ DIST }}" != "stable" ] && [ "{{ DIST }}" != "oldstable" ]; then if [ "{{ VARIANT }}" = "buildd" ]; then
[ "$(readlink /tmp/debian-{{ DIST }}-debootstrap/etc/localtime)" = /usr/share/zoneinfo/UTC ] [ "$(readlink /tmp/debian-{{ DIST }}-debootstrap/etc/localtime)" = /usr/share/zoneinfo/UTC ]
rm /tmp/debian-{{ DIST }}-debootstrap/etc/localtime rm /tmp/debian-{{ DIST }}-debootstrap/etc/localtime
fi fi
# starting with systemd 255 upstream dropped splitusr support and depending on
# the installation order, symlink targets are prefixed with /usr or not
# See #1060000 and #1054137
case {{ DIST }} in testing|unstable)
for f in multi-user.target.wants/e2scrub_reap.service timers.target.wants/apt-daily-upgrade.timer timers.target.wants/apt-daily.timer timers.target.wants/e2scrub_all.timer; do
for d in mm debootstrap; do
[ -L "/tmp/debian-{{ DIST }}-$d/etc/systemd/system/$f" ] || continue
oldlink="$(readlink "/tmp/debian-{{ DIST }}-$d/etc/systemd/system/$f")"
case $oldlink in
/usr/*) : ;;
/*) oldlink="/usr$oldlink" ;;
*) echo unexpected >&2; exit 1 ;;
esac
ln -sf "$oldlink" "/tmp/debian-{{ DIST }}-$d/etc/systemd/system/$f"
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
@ -209,9 +189,8 @@ diff --unified --no-dereference --recursive /tmp/debian-{{ DIST }}-debootstrap /
find /tmp/debian-{{ DIST }}-debootstrap /tmp/debian-{{ DIST }}-mm -type d -print0 | xargs -0 touch --date="@{{ SOURCE_DATE_EPOCH }}" find /tmp/debian-{{ DIST }}-debootstrap /tmp/debian-{{ DIST }}-mm -type d -print0 | xargs -0 touch --date="@{{ SOURCE_DATE_EPOCH }}"
# debootstrap never ran apt -- fixing permissions # 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
unmergedPATH="$PATH$(if [ "{{ DIST }}" = oldstable ]; then echo :/bin:/sbin; fi)" chroot /tmp/debian-{{ DIST }}-debootstrap chmod 0700 $d
PATH="$unmergedPATH" chroot /tmp/debian-{{ DIST }}-debootstrap chmod 0700 $d chroot /tmp/debian-{{ DIST }}-debootstrap chown "$(id -u _apt):root" $d
PATH="$unmergedPATH" 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 .

View file

@ -8,7 +8,7 @@ trap "rm -f /tmp/chrootless.tar /tmp/root.tar" EXIT INT TERM
for INCLUDE in '' 'apt' 'apt,build-essential' 'systemd-sysv'; do for INCLUDE in '' 'apt' 'apt,build-essential' 'systemd-sysv'; do
for MODE in root chrootless; do for MODE in root chrootless; do
{{ CMD }} --mode=$MODE --variant={{ VARIANT }} --hook-dir=./hooks/merged-usr \ {{ CMD }} --mode=$MODE --variant={{ VARIANT }} --hook-dir=./hooks/merged-usr \
${INCLUDE:+--include="$INCLUDE"} --skip=check/chrootless \ ${INCLUDE:+--include="$INCLUDE"} \
{{ DIST }} "/tmp/$MODE.tar" {{ MIRROR }} {{ DIST }} "/tmp/$MODE.tar" {{ MIRROR }}
done done
cmp /tmp/root.tar /tmp/chrootless.tar || diffoscope /tmp/root.tar /tmp/chrootless.tar cmp /tmp/root.tar /tmp/chrootless.tar || diffoscope /tmp/root.tar /tmp/chrootless.tar

View file

@ -18,23 +18,18 @@ if [ "$(id -u)" -eq 0 ] && [ "{{ MODE }}" != "root" ] && [ "{{ MODE }}" != "auto
prefix="runuser -u ${SUDO_USER:-user} --" prefix="runuser -u ${SUDO_USER:-user} --"
fi fi
MMTARFILTER=
[ -x /usr/bin/mmtarfilter ] && MMTARFILTER=/usr/bin/mmtarfilter
[ -x ./tarfilter ] && MMTARFILTER=./tarfilter
# 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
# permissions drwxr-sr-x and extended attributes of ./var/log/journal/ cannot # permissions drwxr-sr-x and extended attributes of ./var/log/journal/ cannot
# be preserved under fakeroot # be preserved under fakeroot
# this applies to 'z' lines in files in /usr/lib/tmpfiles.d/
for INCLUDE in '' 'apt' 'apt,build-essential' 'systemd-sysv'; do for INCLUDE in '' 'apt' 'apt,build-essential' 'systemd-sysv'; do
{{ CMD }} --variant={{ VARIANT }} --hook-dir=./hooks/merged-usr \ {{ CMD }} --variant={{ VARIANT }} --hook-dir=./hooks/merged-usr \
--customize-hook="if [ \"$INCLUDE\" = systemd-sysv ]; then for f in var/log/journal etc/credstore etc/credstore.encrypted; do chmod 00755 \"\$1/\$f\"; done; fi" \ --customize-hook='if [ -d "$1"/var/log/journal ]; then rmdir "$1"/var/log/journal; mkdir --mode=2755 "$1"/var/log/journal; chroot "$1" chown root:systemd-journal /var/log/journal; fi' \
${INCLUDE:+--include="$INCLUDE"} \ ${INCLUDE:+--include="$INCLUDE"} \
{{ DIST }} - {{ MIRROR }} | "$MMTARFILTER" --pax-exclude='*' >/tmp/root.tar {{ DIST }} /tmp/root.tar {{ MIRROR }}
$prefix fakeroot {{ CMD }} --mode={{ MODE }} --variant={{ VARIANT }} --hook-dir=./hooks/merged-usr \ $prefix fakeroot {{ CMD }} --mode={{ MODE }} --variant={{ VARIANT }} --hook-dir=./hooks/merged-usr \
${INCLUDE:+--include="$INCLUDE"} \ ${INCLUDE:+--include="$INCLUDE"} \
{{ DIST }} - {{ MIRROR }} | "$MMTARFILTER" > /tmp/chrootless.tar {{ DIST }} /tmp/chrootless.tar {{ MIRROR }}
cmp /tmp/root.tar /tmp/chrootless.tar || diffoscope /tmp/root.tar /tmp/chrootless.tar cmp /tmp/root.tar /tmp/chrootless.tar || diffoscope /tmp/root.tar /tmp/chrootless.tar
rm /tmp/chrootless.tar /tmp/root.tar rm /tmp/chrootless.tar /tmp/root.tar
done done

View file

@ -45,7 +45,7 @@ for INCLUDE in '' 'apt' 'systemd-sysv'; do
arch-test "$arch" && exit 1 arch-test "$arch" && exit 1
{{ CMD }} --mode=chrootless --architecture="$arch" --variant={{ VARIANT }} \ {{ CMD }} --mode=chrootless --architecture="$arch" --variant={{ VARIANT }} \
--hook-dir=./hooks/merged-usr ${INCLUDE:+--include="$INCLUDE"} \ --hook-dir=./hooks/merged-usr ${INCLUDE:+--include="$INCLUDE"} \
--skip=check/chrootless {{ DIST }} "/tmp/chrootless.tar" {{ MIRROR }} {{ DIST }} "/tmp/chrootless.tar" {{ MIRROR }}
# when creating a foreign architecture chroot, the tarballs are not # when creating a foreign architecture chroot, the tarballs are not
# bit-by-bit identical but contain a few remaining differences: # bit-by-bit identical but contain a few remaining differences:
# #

View file

@ -22,17 +22,12 @@ chroot /tmp/debian-chroot dpkg-query -f '${binary:Package}\n' -W \
rm /tmp/expected rm /tmp/expected
for cmd in echo cat sed grep; do 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)" = "/usr/bin/busybox" test "$(readlink /tmp/debian-chroot/bin/$cmd)" = "/bin/busybox"
done done
for cmd in sort tee; do for cmd in sort tee; 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)" = "/usr/bin/busybox" test "$(readlink /tmp/debian-chroot/usr/bin/$cmd)" = "/bin/busybox"
done done
# if /bin or /sbin are not symlinks, add /bin and /sbin to PATH
if [ ! -L /tmp/debian-chroot/bin ] || [ ! -L /tmp/debian-chroot/sbin ]; then
export PATH="$PATH:/sbin:/bin"
fi
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 \