Compare commits

..

No commits in common. "c4a43ea0f9ce18c18216d51df3076e21716219a4" and "c61e81a2445a263ab14bc1865679e177784c297a" have entirely different histories.

3 changed files with 365 additions and 148 deletions

View file

@ -127,7 +127,7 @@ if [ ! -e shared/hooks/eatmydata/customize.sh ] || [ hooks/eatmydata/customize.s
fi
fi
starttime=
total=177
total=213
skipped=0
runtests=0
i=1
@ -2141,10 +2141,6 @@ tar -C /tmp/debian-chroot --one-file-system -c . | tar -t | sort > tar2.txt
ppc64el)
echo ./lib64;
;;
s390x)
echo ./lib32;
echo ./usr/lib32/;
;;
esac
} | sort -u | diff -u - tar2.txt
rm -r /tmp/debian-chroot
@ -3080,6 +3076,123 @@ END
done
done
# test all variants
for variant in essential apt required minbase buildd important debootstrap - standard; do
print_header "mode=root,variant=$variant: create tarball"
cat << END > shared/test.sh
#!/bin/sh
set -eu
export LC_ALL=C.UTF-8
$CMD --mode=root --variant=$variant $DEFAULT_DIST /tmp/debian-chroot.tar $mirror
tar -tf /tmp/debian-chroot.tar | sort > "$variant.txt"
rm /tmp/debian-chroot.tar
END
if [ "$HAVE_QEMU" = "yes" ]; then
./run_qemu.sh
runtests=$((runtests+1))
else
./run_null.sh SUDO
runtests=$((runtests+1))
fi
# check if the other modes produce the same result in each variant
for mode in unshare fakechroot proot; do
print_header "mode=$mode,variant=$variant: create tarball"
# fontconfig doesn't install reproducibly because differences
# in /var/cache/fontconfig/. See
# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=864082
if [ "$variant" = standard ]; then
echo "skipping test because of #864082" >&2
skipped=$((skipped+1))
continue
fi
if [ "$mode" = "unshare" ] && [ "$HAVE_UNSHARE" != "yes" ]; then
echo "HAVE_UNSHARE != yes -- Skipping test..." >&2
skipped=$((skipped+1))
continue
fi
if [ "$mode" = "proot" ] && [ "$HAVE_PROOT" != "yes" ]; then
echo "HAVE_PROOT != yes -- Skipping test..." >&2
skipped=$((skipped+1))
continue
fi
cat << END > shared/test.sh
#!/bin/sh
set -eu
export LC_ALL=C.UTF-8
if [ "\$(id -u)" -eq 0 ] && ! id -u user > /dev/null 2>&1; then
if [ ! -e /mmdebstrap-testenv ]; then
echo "this test modifies the system and should only be run inside a container" >&2
exit 1
fi
adduser --gecos user --disabled-password user
fi
if [ "$mode" = unshare ]; then
if [ ! -e /mmdebstrap-testenv ]; then
echo "this test modifies the system and should only be run inside a container" >&2
exit 1
fi
sysctl -w kernel.unprivileged_userns_clone=1
fi
prefix=
[ "\$(id -u)" -eq 0 ] && prefix="runuser -u user --"
\$prefix $CMD --mode=$mode --variant=$variant $DEFAULT_DIST /tmp/debian-chroot.tar $mirror
tar -tf /tmp/debian-chroot.tar | sort | diff -u "./$variant.txt" -
rm /tmp/debian-chroot.tar
END
if [ "$HAVE_QEMU" = "yes" ]; then
./run_qemu.sh
runtests=$((runtests+1))
else
./run_null.sh
runtests=$((runtests+1))
fi
done
# some variants are equal and some are strict superset of the last
# special case of the buildd variant: nothing is a superset of it
case "$variant" in
essential) ;; # nothing to compare it to
apt)
[ $(comm -23 shared/essential.txt shared/apt.txt | wc -l) -eq 0 ]
[ $(comm -13 shared/essential.txt shared/apt.txt | wc -l) -gt 0 ]
rm shared/essential.txt
;;
required)
[ $(comm -23 shared/apt.txt shared/required.txt | wc -l) -eq 0 ]
[ $(comm -13 shared/apt.txt shared/required.txt | wc -l) -gt 0 ]
rm shared/apt.txt
;;
minbase) # equal to required
cmp shared/required.txt shared/minbase.txt
rm shared/required.txt
;;
buildd)
[ $(comm -23 shared/minbase.txt shared/buildd.txt | wc -l) -eq 0 ]
[ $(comm -13 shared/minbase.txt shared/buildd.txt | wc -l) -gt 0 ]
rm shared/buildd.txt # we need minbase.txt but not buildd.txt
;;
important)
[ $(comm -23 shared/minbase.txt shared/important.txt | wc -l) -eq 0 ]
[ $(comm -13 shared/minbase.txt shared/important.txt | wc -l) -gt 0 ]
rm shared/minbase.txt
;;
debootstrap) # equal to important
cmp shared/important.txt shared/debootstrap.txt
rm shared/important.txt
;;
-) # equal to debootstrap
cmp shared/debootstrap.txt shared/-.txt
rm shared/debootstrap.txt
;;
standard)
[ $(comm -23 shared/-.txt shared/standard.txt | wc -l) -eq 0 ]
[ $(comm -13 shared/-.txt shared/standard.txt | wc -l) -gt 0 ]
rm shared/-.txt shared/standard.txt
;;
*) exit 1;;
esac
done
# test extract variant also with chrootless mode
for mode in root unshare fakechroot proot chrootless; do
print_header "mode=$mode,variant=extract: unpack doc-debian"

View file

@ -224,9 +224,6 @@ Apt::Get::Download-Only true;
Acquire::Languages "none";
Dir::Etc::Trusted "/etc/apt/trusted.gpg";
Dir::Etc::TrustedParts "/etc/apt/trusted.gpg.d";
Acquire::http::Dl-Limit "1000";
Acquire::https::Dl-Limit "1000";
Acquire::Retries "5";
END
> "$rootdir/var/lib/dpkg/status"
@ -469,17 +466,6 @@ cleanuptmpdir() {
export SOURCE_DATE_EPOCH=$(date --date="$(grep-dctrl -s Date -n '' "$newmirrordir/dists/$DEFAULT_DIST/Release")" +%s)
if [ "$HAVE_QEMU" = "yes" ]; then
case "$HOSTARCH" in
amd64|i386)
# okay
;;
*)
echo "qemu support is only available on amd64 and i386" >&2
echo "because syslinux is only available on those arches" >&2
exit 1
;;
esac
# We must not use any --dpkgopt here because any dpkg options still
# leak into the chroot with chrootless mode.
# We do not use our own package cache here because
@ -521,9 +507,6 @@ if [ "$HAVE_QEMU" = "yes" ]; then
arches=$HOSTARCH
fi
$CMD --variant=apt --architectures=$arches --include="$pkgs" \
--aptopt='Acquire::http::Dl-Limit "1000"' \
--aptopt='Acquire::https::Dl-Limit "1000"' \
--aptopt='Acquire::Retries "5"' \
$DEFAULT_DIST - "$mirror" > "$tmpdir/debian-chroot.tar"
cat << END > "$tmpdir/extlinux.conf"
@ -557,7 +540,7 @@ END
cat << 'END' > "$tmpdir/worker.sh"
#!/bin/sh
echo 'root:root' | chpasswd
mount -t 9p -o trans=virtio,access=any,msize=128k mmdebstrap /mnt
mount -t 9p -o trans=virtio,access=any mmdebstrap /mnt
# need to restart mini-httpd because we mounted different content into www-root
systemctl restart mini-httpd

View file

@ -1510,7 +1510,8 @@ sub setup {
run_update($options);
}
(my $essential_pkgs, my $cached_debs) = run_download($options);
(my $pkgs_to_install, my $essential_pkgs, my $cached_debs)
= run_download($options);
# in theory, we don't have to extract the packages in chrootless mode
# but we do it anyways because otherwise directory creation timestamps
@ -1532,7 +1533,7 @@ sub setup {
run_hooks('essential', $options);
run_install($options, $chrootcmd);
run_install($options, $pkgs_to_install, $chrootcmd);
run_hooks('customize', $options);
}
@ -1991,6 +1992,22 @@ sub run_update() {
sub run_download() {
my $options = shift;
my %pkgs_to_install;
for my $incl (@{ $options->{include} }) {
for my $pkg (split /[,\s]+/, $incl) {
# strip leading and trailing whitespace
$pkg =~ s/^\s+|\s+$//g;
# skip if the remainder is an empty string
if ($pkg eq '') {
next;
}
$pkgs_to_install{$pkg} = ();
}
}
if ($options->{variant} eq 'buildd') {
$pkgs_to_install{'build-essential'} = ();
}
# We use /var/cache/apt/archives/ to figure out which packages apt chooses
# to install. That's why the directory must be empty if:
# - /var/cache/apt/archives exists, and
@ -2014,7 +2031,7 @@ sub run_download() {
if (
!$options->{dryrun}
&& ((none { $_ eq $options->{variant} } ('extract', 'custom'))
|| scalar @{ $options->{include} } != 0)
|| scalar keys %pkgs_to_install != 0)
&& -d "$options->{root}/var/cache/apt/archives/"
) {
my $apt_archives = "/var/cache/apt/archives/";
@ -2047,22 +2064,10 @@ sub run_download() {
# (essential variant) then we have to compute the package set ourselves.
# Same if we want to install priority based variants.
if (any { $_ eq $options->{variant} } ('extract', 'custom')) {
if (scalar @{ $options->{include} } == 0) {
if (scalar keys %pkgs_to_install == 0) {
info "nothing to download -- skipping...";
return ([], []);
}
my %pkgs_to_install;
for my $incl (@{ $options->{include} }) {
for my $pkg (split /[,\s]+/, $incl) {
# strip leading and trailing whitespace
$pkg =~ s/^\s+|\s+$//g;
# skip if the remainder is an empty string
if ($pkg eq '') {
next;
}
$pkgs_to_install{$pkg} = ();
}
}
my %result = ();
if ($options->{dryrun}) {
@ -2121,10 +2126,7 @@ sub run_download() {
],
%result
});
} elsif (
any { $_ eq $options->{variant} }
('essential', 'standard', 'important', 'required', 'buildd')
) {
} elsif ($options->{variant} eq 'essential') {
# 2021-06-07, #debian-apt on OFTC, times in UTC+2
# 17:27 < DonKult> (?essential includes 'apt' through)
# 17:30 < josch> DonKult: no, because pkgCacheGen::ForceEssential ",";
@ -2149,7 +2151,7 @@ sub run_download() {
'install',
'?narrow('
. (
length($options->{suite})
defined($options->{suite})
? '?archive(' . $options->{suite} . '),'
: ''
)
@ -2159,6 +2161,209 @@ sub run_download() {
],
%result
});
} elsif (
any { $_ eq $options->{variant} }
('standard', 'important', 'required', 'minbase', 'buildd')
) {
# In the future, after bug https://bugs.debian.org/989558 is fixed, we
# want to use apt patterns to select the packages to install:
#
# ?narrow(?archive(unstable),?architecture(amd64),?priority(important))
#
# Once this is possible, we can append above statement to the apt-get
# install call in run_download() instead of assembling the package list
# here and passing it through all the way. Then this function only
# takes care of retrieving the essential packages.
#
# https://salsa.debian.org/apt-team/apt/-/merge_requests/185
my %ess_pkgs;
my %ess_pkgs_target;
my %pkgs_to_install_target = %pkgs_to_install;
my $num_suite_matches = 0;
my $num_suite_mismatch = 0;
open(
my $pipe_apt,
'-|',
'apt-get',
'indextargets',
'--format',
('$(CODENAME)' . "\t" . '$(SUITE)' . "\t" . '$(FILENAME)'),
'Created-By: Packages'
) or error "cannot start apt-get indextargets: $!";
while (my $line = <$pipe_apt>) {
chomp $line;
my ($codename, $suite, $fname) = split /\t/, $line, 3;
debug "processing indextarget output for $codename $suite $fname";
my $suite_matches = 0;
if (
defined $options->{suite}
and
($options->{suite} eq $codename or $options->{suite} eq $suite)
) {
$suite_matches = 1;
$num_suite_matches++;
} else {
$num_suite_mismatch++;
}
open(my $pipe_cat, '-|', '/usr/lib/apt/apt-helper', 'cat-file',
$fname)
or error "cannot start apt-helper cat-file: $!";
my $pkgname;
my $ess = '';
my $prio = 'optional';
my $arch = '';
while (my $line = <$pipe_cat>) {
chomp $line;
# Dpkg::Index takes 10 seconds to parse a typical Packages
# file. Thus we instead use a simple parser that just retrieve
# the information we need.
if ($line ne "") {
if ($line =~ /^Package: (.*)/) {
$pkgname = $1;
} elsif ($line =~ /^Essential: yes$/) {
$ess = 'yes';
} elsif ($line =~ /^Priority: (.*)/) {
$prio = $1;
} elsif ($line =~ /^Architecture: (.*)/) {
$arch = $1;
}
next;
}
# we are only interested of packages of native architecture or
# Architecture:all
if ($arch eq $options->{nativearch} or $arch eq 'all') {
# the line is empty, thus a package stanza just finished
# processing and we can handle it now
if ($ess eq 'yes') {
$ess_pkgs{$pkgname} = ();
if ($suite_matches) {
$ess_pkgs_target{$pkgname} = ();
}
} elsif ($options->{variant} eq 'essential') {
# for this variant we are only interested in the
# essential packages
} elsif (
any { $_ eq $options->{variant} } (
'standard', 'important', 'required', 'buildd',
'minbase'
)
) {
if ($prio eq 'optional' or $prio eq 'extra') {
# always ignore packages of priority optional and
# extra
} elsif ($prio eq 'standard') {
if (
none { $_ eq $options->{variant} }
('important', 'required', 'buildd', 'minbase')
) {
$pkgs_to_install{$pkgname} = ();
if ($suite_matches) {
$pkgs_to_install_target{$pkgname} = ();
}
}
} elsif ($prio eq 'important') {
if (
none { $_ eq $options->{variant} }
('required', 'buildd', 'minbase')
) {
$pkgs_to_install{$pkgname} = ();
if ($suite_matches) {
$pkgs_to_install_target{$pkgname} = ();
}
}
} elsif ($prio eq 'required') {
# required packages are part of all sets except
# essential and apt
$pkgs_to_install{$pkgname} = ();
if ($suite_matches) {
$pkgs_to_install_target{$pkgname} = ();
}
} else {
error "unknown priority: $prio";
}
} else {
error "unknown variant: $options->{variant}";
}
}
# reset values
undef $pkgname;
$ess = '';
$prio = 'optional';
$arch = '';
}
close $pipe_cat;
$? == 0 or error "apt-helper cat-file failed: $?";
}
close $pipe_apt;
$? == 0 or error "apt-get indextargets failed: $?";
# We now have two package sets, %pkgs_to_install and
# %pkgs_to_install_target, where the latter was only filled if the
# suite matched the codename or the suite name of one of the given
# apt indices.
# We only need to bother with this distinction if one or more of the
# indices matched and one or more of the indices mismatched. If either
# nothing matched or all matched, then we can just use %pkgs_to_install
if ( defined $options->{suite}
and $num_suite_matches > 0
and $num_suite_mismatch > 0) {
# Now we know that some matched and some didn't. But we only
# replace the results from all indices with the results from those
# indices that matched if the results are actually different and
# if there is more than zero packages from the indices that matched
if (scalar keys %ess_pkgs_target > 0
and keys %ess_pkgs != %ess_pkgs_target) {
info( "multiple sources defined, using those matching "
. "'$options->{suite}' to find essential packages");
%ess_pkgs = %ess_pkgs_target;
}
if (scalar keys %pkgs_to_install_target > 0
and keys %pkgs_to_install != keys %pkgs_to_install_target) {
if ($options->{variant} eq 'essential') {
error "logic error";
} elsif (
any { $_ eq $options->{variant} }
('standard', 'important', 'required', 'buildd', 'minbase')
) {
info( "multiple sources defined -- using those matching "
. "'$options->{suite}' to find packages for variant "
. "'$options->{variant}'");
%pkgs_to_install = %pkgs_to_install_target;
} else {
error "unknown variant: $options->{variant}";
}
}
}
debug "Identified the following Essential:yes packages:";
foreach my $pkg (sort keys %ess_pkgs) {
debug " $pkg";
}
my %result = ();
if ($options->{dryrun}) {
info "simulate downloading packages with apt...";
} else {
# if there are already packages in /var/cache/apt/archives/, we
# need to use our proxysolver to obtain the solution chosen by apt
if (scalar @cached_debs > 0) {
$result{EDSP_RES} = \@dl_debs;
}
info "downloading packages with apt...";
}
run_apt_progress({
ARGV => [
'apt-get',
'--yes',
'-oApt::Get::Download-Only=true',
$options->{dryrun} ? '-oAPT::Get::Simulate=true' : (),
'install'
],
PKGS => [keys %ess_pkgs],
%result
});
} else {
error "unknown variant: $options->{variant}";
}
@ -2228,7 +2433,7 @@ sub run_download() {
# list before returning it.
@essential_pkgs = sort @essential_pkgs;
return (\@essential_pkgs, \@cached_debs);
return ([keys %pkgs_to_install], \@essential_pkgs, \@cached_debs);
}
sub run_extract() {
@ -2670,51 +2875,12 @@ sub run_essential() {
}
sub run_install() {
my $options = shift;
my $chrootcmd = shift;
my %pkgs_to_install;
for my $incl (@{ $options->{include} }) {
for my $pkg (split /[,\s]+/, $incl) {
# strip leading and trailing whitespace
$pkg =~ s/^\s+|\s+$//g;
# skip if the remainder is an empty string
if ($pkg eq '') {
next;
}
$pkgs_to_install{$pkg} = ();
}
}
if ($options->{variant} eq 'buildd') {
$pkgs_to_install{'build-essential'} = ();
}
if (
any { $_ eq $options->{variant} }
('required', 'important', 'standard', 'buildd')
) {
my $priority;
if (any { $_ eq $options->{variant} } ('required', 'buildd')) {
$priority = '?priority(required)';
} elsif ($options->{variant} eq 'important') {
$priority = '?or(?priority(required),?priority(important))';
} elsif ($options->{variant} eq 'standard') {
$priority = '?or(~prequired,~pimportant,~pstandard)';
}
$pkgs_to_install{
"?narrow("
. (
length($options->{suite})
? '?archive(' . $options->{suite} . '),'
: ''
)
. "?architecture($options->{nativearch}),"
. "$priority)"
} = ();
}
my @pkgs_to_install = keys %pkgs_to_install;
my $options = shift;
my $pkgs_to_install = shift;
my $chrootcmd = shift;
if ($options->{mode} eq 'chrootless') {
if (scalar @pkgs_to_install > 0) {
if (scalar @{$pkgs_to_install} > 0) {
my @chrootless_opts = (
'-oDPkg::Options::=--force-not-root',
'-oDPkg::Options::=--force-script-chrootless',
@ -2725,7 +2891,7 @@ sub run_install() {
);
run_apt_progress({
ARGV => ['apt-get', '--yes', @chrootless_opts, 'install'],
PKGS => [@pkgs_to_install],
PKGS => $pkgs_to_install,
});
}
} elsif (
@ -2733,7 +2899,7 @@ sub run_install() {
('root', 'unshare', 'fakechroot', 'proot')
) {
if ($options->{variant} ne 'custom'
and scalar @pkgs_to_install > 0) {
and scalar @{$pkgs_to_install} > 0) {
# Advantage of running apt on the outside instead of inside the
# chroot:
#
@ -2779,7 +2945,7 @@ sub run_install() {
'--yes',
'install'
],
PKGS => [@pkgs_to_install],
PKGS => $pkgs_to_install,
});
},
$options
@ -2792,7 +2958,7 @@ sub run_install() {
'apt-get', '--yes',
'-oAPT::Get::Simulate=true', 'install'
],
PKGS => [@pkgs_to_install],
PKGS => $pkgs_to_install,
});
}
}
@ -3794,9 +3960,6 @@ sub get_keyring_by_suite {
my $debianvendor;
my $ubuntuvendor;
# make $@ local, so we don't print "Can't locate Dpkg/Vendor/Debian.pm"
# in other parts where we evaluate $@
local $@ = '';
eval {
require Dpkg::Vendor::Debian;
require Dpkg::Vendor::Ubuntu;
@ -3916,9 +4079,6 @@ sub get_sourceslist_by_suite {
# https://lists.debian.org/87r26wqr2a.fsf@43-1.org
my $bullseye_or_later = 0;
my $distro_info = '/usr/share/distro-info/debian.csv';
# make $@ local, so we don't print "Can't locate Debian/DistroInfo.pm"
# in other parts where we evaluate $@
local $@ = '';
eval { require Debian::DistroInfo; };
if (!$@) {
# libdistro-info-perl is installed
@ -4145,20 +4305,9 @@ sub main() {
'h|help' => sub { pod2usage(-exitval => 0, -verbose => 1) },
'man' => sub { pod2usage(-exitval => 0, -verbose => 2) },
'version' => sub { print STDOUT "mmdebstrap $VERSION\n"; exit 0; },
'components=s@' => \$options->{components},
'variant=s' => \$options->{variant},
'include=s' => sub {
my ($opt_name, $opt_value) = @_;
for my $pkg (split /[,\s]+/, $opt_value) {
# strip leading and trailing whitespace
$pkg =~ s/^\s+|\s+$//g;
# skip if the remainder is an empty string
if ($pkg eq '') {
next;
}
push @{ $options->{include} }, $pkg;
}
},
'components=s@' => \$options->{components},
'variant=s' => \$options->{variant},
'include=s@' => \$options->{include},
'architectures=s@' => \$options->{architectures},
'mode=s' => \$options->{mode},
'dpkgopt=s@' => \$options->{dpkgopts},
@ -4281,10 +4430,6 @@ sub main() {
if (any { $_ eq $options->{variant} } ('-', 'debootstrap')) {
$options->{variant} = 'important';
}
# minbase is an alias for required
if ($options->{variant} eq 'minbase') {
$options->{variant} = 'required';
}
# fakeroot is an alias for fakechroot
if ($options->{mode} eq 'fakeroot') {
@ -4374,8 +4519,8 @@ sub main() {
and $content =~ /^apt ([0-9]+\.[0-9]+\.[0-9]+) \([a-z0-9-]+\)$/m) {
$aptversion = version->new($1);
}
if ($aptversion < "2.3.10") {
error "need apt >= 2.3.10 but have $aptversion";
if ($aptversion < "2.3.7") {
error "need apt >= 2.3.7 but have $aptversion";
}
}
@ -6007,9 +6152,9 @@ option depends on the selected variant. The B<extract> and B<custom> variants
install no packages by default, so for these variants, the packages specified
by this option will be the only ones that get either extracted or installed by
dpkg, respectively. For all other variants, apt is used to install the
additional packages. Package names are directly passed to apt and thus, you
can use apt features like C<pkg/suite>, C<pkg=version>, C<pkg->, use a glob or
regex for C<pkg> or use apt patterns. See apt(8) for the supported
additional packages. Package names are directly passed to
apt and thus, you can use apt features like C<pkg/suite>, C<pkg=version>,
C<pkg-> or use a glob or regex for C<pkg>. See apt(8) for the supported
syntax. The option can be specified multiple times and the packages are
concatenated in the order in which they are given on the command line. If
later list items are repeated, then they get dropped so that the resulting
@ -6316,10 +6461,8 @@ All package sets also include the direct and indirect hard dependencies (but
not recommends) of the selected package sets. The variants B<minbase>,
B<buildd> and B<->, resemble the package sets that debootstrap would install
with the same I<--variant> argument. The release with a name matching the
I<SUITE> argument as well as the native architecture will be used to determine
the C<Essential:yes> and priority values. To select packages with matching
priority from any suite, specify the empty string for I<SUITE>. The default
variant is B<debootstrap>.
I<SUITE> argument will be used to determine the C<Essential:yes> and priority
values.
=over 8
@ -6346,30 +6489,19 @@ The B<essential> set plus apt.
=item B<required>, B<minbase>
The B<essential> set plus all packages with Priority:required and apt.
It is roughly equivalent to running mmdebstrap with
--variant=essential --include="?priority(required)"
=item B<buildd>
The B<minbase> set plus build-essential.
It is roughly equivalent to running mmdebstrap with
--variant=essential --include="?priority(required),build-essential"
=item B<important>, B<debootstrap>, B<->
The B<required> set plus all packages with Priority:important. This is the
default of debootstrap. It is roughly equivalent to running mmdebstrap with
--variant=essential --include="~prequired|~pimportant"
default of debootstrap.
=item B<standard>
The B<important> set plus all packages with Priority:standard.
It is roughly equivalent to running mmdebstrap with
--variant=essential --include="~prequired|~pimportant|~pstandard"
=back
@ -6847,17 +6979,6 @@ Create a system that can be used with podman:
root
$ podman rmi debian
As a docker/podman replacement:
$ mmdebstrap unstable | mmtarfilter --path-exclude='/dev/*' > chroot.tar
[...]
$ mmdebstrap --variant=custom --skip=update \
--setup-hook='tar-in chroot.tar /' \
--customize-hook='chroot "$1" whoami' unstable /dev/null
[...]
root
$ rm chroot.tar
=head1 ENVIRONMENT VARIABLES
=over 8