Compare commits
33 commits
1f606f913d
...
abcfda0442
Author | SHA1 | Date | |
---|---|---|---|
abcfda0442 | |||
63d5ffb2a6 | |||
a1e5043676 | |||
ecc167e87e | |||
2d758ba576 | |||
16c7276921 | |||
1a62ccec46 | |||
d02ea1c7f1 | |||
ce12fbdd41 | |||
aef8fcfb75 | |||
cb500ef6ba | |||
c33f719278 | |||
84c53fc120 | |||
27d1bad2a5 | |||
261cfda58f | |||
629187cd68 | |||
e77e194ebd | |||
bc7ce4affc | |||
199e577757 | |||
21366f76b7 | |||
bf41b91e6f | |||
cee8b67045 | |||
669c404938 | |||
767fa11571 | |||
c23727e136 | |||
eaa67aea9c | |||
6068e7d22e | |||
8339721fca | |||
e5bcc1827e | |||
806ea4b35d | |||
8bf8da5e8e | |||
2c5e6db317 | |||
c741711938 |
13 changed files with 656 additions and 230 deletions
|
@ -446,6 +446,10 @@ def main():
|
||||||
print("failed %d:" % len(failed), file=sys.stderr)
|
print("failed %d:" % len(failed), file=sys.stderr)
|
||||||
for f in failed:
|
for f in failed:
|
||||||
print(f, file=sys.stderr)
|
print(f, file=sys.stderr)
|
||||||
|
currenttime = time.time()
|
||||||
|
walltime = timedelta(seconds=int(currenttime - starttime))
|
||||||
|
print(f"total runtime: {walltime}", file=sys.stderr)
|
||||||
|
if failed:
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
|
11
coverage.txt
11
coverage.txt
|
@ -277,12 +277,14 @@ Variants: - standard
|
||||||
Skip-If:
|
Skip-If:
|
||||||
variant == "-" and hostarch not in ["armel", "armhf", "mipsel"] # #1031276
|
variant == "-" and hostarch not in ["armel", "armhf", "mipsel"] # #1031276
|
||||||
variant == "standard" and hostarch in ["armel", "armhf", "mipsel"] # #1031276
|
variant == "standard" and hostarch in ["armel", "armhf", "mipsel"] # #1031276
|
||||||
|
variant == "standard" and dist == "oldstable" # #864082, #1004557, #1004558
|
||||||
|
|
||||||
Test: debug
|
Test: debug
|
||||||
Variants: - standard
|
Variants: - standard
|
||||||
Skip-If:
|
Skip-If:
|
||||||
variant == "-" and hostarch not in ["armel", "armhf", "mipsel"] # #1031276
|
variant == "-" and hostarch not in ["armel", "armhf", "mipsel"] # #1031276
|
||||||
variant == "standard" and hostarch in ["armel", "armhf", "mipsel"] # #1031276
|
variant == "standard" and hostarch in ["armel", "armhf", "mipsel"] # #1031276
|
||||||
|
variant == "standard" and dist == "oldstable" # #864082, #1004557, #1004558
|
||||||
|
|
||||||
Test: quiet
|
Test: quiet
|
||||||
Needs-Root: true
|
Needs-Root: true
|
||||||
|
@ -420,3 +422,12 @@ Skip-If: hostarch in ["i386", "armel", "armhf", "mipsel"] # #1023286
|
||||||
|
|
||||||
Test: auto-mode-as-normal-user
|
Test: auto-mode-as-normal-user
|
||||||
Modes: auto
|
Modes: auto
|
||||||
|
|
||||||
|
Test: skip-output-dev
|
||||||
|
Modes: root unshare
|
||||||
|
|
||||||
|
Test: skip-output-mknod
|
||||||
|
Modes: root unshare
|
||||||
|
|
||||||
|
Test: skip-tar-in-mknod
|
||||||
|
Modes: unshare
|
||||||
|
|
|
@ -250,6 +250,17 @@ END
|
||||||
trap "-" EXIT INT TERM
|
trap "-" EXIT INT TERM
|
||||||
)
|
)
|
||||||
|
|
||||||
|
check_proxy_running() {
|
||||||
|
if timeout 1 bash -c 'exec 3<>/dev/tcp/127.0.0.1/8080 && printf "GET http://deb.debian.org/debian/dists/'"$DEFAULT_DIST"'/InRelease HTTP/1.1\nHost: deb.debian.org\n\n" >&3 && grep "Suite: '"$DEFAULT_DIST"'" <&3 >/dev/null' 2>/dev/null; then
|
||||||
|
return 0
|
||||||
|
elif timeout 1 env http_proxy="http://127.0.0.1:8080/" wget --quiet -O - "http://deb.debian.org/debian/dists/$DEFAULT_DIST/InRelease" | grep "Suite: $DEFAULT_DIST" >/dev/null; then
|
||||||
|
return 0
|
||||||
|
elif timeout 1 curl --proxy "http://127.0.0.1:8080/" --silent "http://deb.debian.org/debian/dists/$DEFAULT_DIST/InRelease" | grep "Suite: $DEFAULT_DIST" >/dev/null; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
if [ -e "./shared/cache.A" ] && [ -e "./shared/cache.B" ]; then
|
if [ -e "./shared/cache.A" ] && [ -e "./shared/cache.B" ]; then
|
||||||
echo "both ./shared/cache.A and ./shared/cache.B exist" >&2
|
echo "both ./shared/cache.A and ./shared/cache.B exist" >&2
|
||||||
echo "was a former run of the script aborted?" >&2
|
echo "was a former run of the script aborted?" >&2
|
||||||
|
@ -301,8 +312,9 @@ components=main
|
||||||
# by default, use the mmdebstrap executable in the current directory
|
# by default, use the mmdebstrap executable in the current directory
|
||||||
: "${CMD:=./mmdebstrap}"
|
: "${CMD:=./mmdebstrap}"
|
||||||
: "${USE_HOST_APT_CONFIG:=no}"
|
: "${USE_HOST_APT_CONFIG:=no}"
|
||||||
|
: "${FORCE_UPDATE:=no}"
|
||||||
|
|
||||||
if [ -e "$oldmirrordir/dists/$DEFAULT_DIST/InRelease" ]; then
|
if [ "$FORCE_UPDATE" != "yes" ] && [ -e "$oldmirrordir/dists/$DEFAULT_DIST/InRelease" ]; then
|
||||||
http_code=$(curl --output /dev/null --silent --location --head --time-cond "$oldmirrordir/dists/$DEFAULT_DIST/InRelease" --write-out '%{http_code}' "$mirror/dists/$DEFAULT_DIST/InRelease")
|
http_code=$(curl --output /dev/null --silent --location --head --time-cond "$oldmirrordir/dists/$DEFAULT_DIST/InRelease" --write-out '%{http_code}' "$mirror/dists/$DEFAULT_DIST/InRelease")
|
||||||
case "$http_code" in
|
case "$http_code" in
|
||||||
200) ;; # need update
|
200) ;; # need update
|
||||||
|
@ -316,7 +328,7 @@ PROXYPID=$!
|
||||||
trap 'kill "$PROXYPID" || :' EXIT INT TERM
|
trap 'kill "$PROXYPID" || :' EXIT INT TERM
|
||||||
|
|
||||||
for i in $(seq 10); do
|
for i in $(seq 10); do
|
||||||
curl --proxy "http://127.0.0.1:8080/" --silent -o /dev/null "http://deb.debian.org/debian/dists/$DEFAULT_DIST/InRelease" && break
|
check_proxy_running && break
|
||||||
sleep 1
|
sleep 1
|
||||||
done
|
done
|
||||||
if [ ! -s "$newmirrordir/dists/$DEFAULT_DIST/InRelease" ]; then
|
if [ ! -s "$newmirrordir/dists/$DEFAULT_DIST/InRelease" ]; then
|
||||||
|
@ -425,7 +437,7 @@ if [ "$HAVE_QEMU" = "yes" ]; then
|
||||||
PROXYPID=$!
|
PROXYPID=$!
|
||||||
|
|
||||||
for i in $(seq 10); do
|
for i in $(seq 10); do
|
||||||
curl --proxy "http://127.0.0.1:8080/" --silent -o /dev/null "http://deb.debian.org/debian/dists/$DEFAULT_DIST/InRelease" && break
|
check_proxy_running && break
|
||||||
sleep 1
|
sleep 1
|
||||||
done
|
done
|
||||||
if [ ! -s "$newmirrordir/dists/$DEFAULT_DIST/InRelease" ]; then
|
if [ ! -s "$newmirrordir/dists/$DEFAULT_DIST/InRelease" ]; then
|
||||||
|
@ -437,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,disorderfs,squashfs-tools-ng,genext2fs,linux-image-generic
|
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
|
||||||
|
@ -549,3 +561,5 @@ mv --no-target-directory ./shared/cache.tmp ./shared/cache
|
||||||
deletecache "$oldcachedir"
|
deletecache "$oldcachedir"
|
||||||
|
|
||||||
trap - EXIT INT TERM
|
trap - EXIT INT TERM
|
||||||
|
|
||||||
|
echo "$0 finished successfully" >&2
|
||||||
|
|
559
mmdebstrap
559
mmdebstrap
|
@ -1170,12 +1170,18 @@ sub setup_mounts {
|
||||||
);
|
);
|
||||||
next;
|
next;
|
||||||
}
|
}
|
||||||
|
if (-e "$options->{root}/dev/$fname") {
|
||||||
|
warning(
|
||||||
|
"skipping creation of ./dev/$fname because it"
|
||||||
|
. " already exists in the target");
|
||||||
|
next;
|
||||||
|
}
|
||||||
push @cleanup_tasks, sub {
|
push @cleanup_tasks, sub {
|
||||||
unlink "$options->{root}/dev/$fname"
|
unlink "$options->{root}/dev/$fname"
|
||||||
or warning("cannot unlink ./dev/$fname: $!");
|
or warning("cannot unlink ./dev/$fname: $!");
|
||||||
};
|
};
|
||||||
symlink $linkname, "$options->{root}/dev/$fname"
|
symlink $linkname, "$options->{root}/dev/$fname"
|
||||||
or error
|
or warning
|
||||||
"cannot create symlink ./dev/$fname -> $linkname";
|
"cannot create symlink ./dev/$fname -> $linkname";
|
||||||
}
|
}
|
||||||
} elsif ($type == 3 or $type == 4) {
|
} elsif ($type == 3 or $type == 4) {
|
||||||
|
@ -1266,8 +1272,9 @@ sub setup_mounts {
|
||||||
next;
|
next;
|
||||||
}
|
}
|
||||||
if (!$options->{havemknod}) {
|
if (!$options->{havemknod}) {
|
||||||
# If had mknod, then the directory to bind-mount into
|
# If had mknod, then the directory to bind-mount
|
||||||
# was already created in the run_setup function.
|
# into was already created in the run_setup
|
||||||
|
# function.
|
||||||
push @cleanup_tasks, sub {
|
push @cleanup_tasks, sub {
|
||||||
rmdir "$options->{root}/dev/$fname"
|
rmdir "$options->{root}/dev/$fname"
|
||||||
or warning("cannot rmdir ./dev/$fname: $!");
|
or warning("cannot rmdir ./dev/$fname: $!");
|
||||||
|
@ -1309,17 +1316,17 @@ sub setup_mounts {
|
||||||
or warning("umount ./dev/$fname failed: $?");
|
or warning("umount ./dev/$fname failed: $?");
|
||||||
};
|
};
|
||||||
if ($fname eq "pts/") {
|
if ($fname eq "pts/") {
|
||||||
# We cannot just bind-mount /dev/pts from the host as
|
# We cannot just bind-mount /dev/pts from the host
|
||||||
# doing so will make posix_openpt() fail. Instead, we
|
# as doing so will make posix_openpt() fail.
|
||||||
# need to mount a new devpts.
|
# Instead, we need to mount a new devpts.
|
||||||
# We need ptmxmode=666 because /dev/ptmx is a symlink
|
# We need ptmxmode=666 because /dev/ptmx is a
|
||||||
# to /dev/pts/ptmx and without it posix_openpt() will
|
# symlink to /dev/pts/ptmx and without it
|
||||||
# fail if we are not the root user.
|
# posix_openpt() will fail if we are not the root
|
||||||
# See also:
|
# user. See also:
|
||||||
# kernel.org/doc/Documentation/filesystems/devpts.txt
|
# kernel.o/doc/Documentation/filesystems/devpts.txt
|
||||||
# salsa.debian.org/debian/schroot/-/merge_requests/2
|
# salsa.d.o/debian/schroot/-/merge_requests/2
|
||||||
# https://bugs.debian.org/856877
|
# https://bugs.debian.org/856877
|
||||||
# https://bugs.debian.org/817236
|
# https://bugs.debian.org/817236
|
||||||
0 == system(
|
0 == system(
|
||||||
'mount',
|
'mount',
|
||||||
'-t',
|
'-t',
|
||||||
|
@ -1623,6 +1630,7 @@ sub run_hooks {
|
||||||
if (defined $options->{suite}) {
|
if (defined $options->{suite}) {
|
||||||
push @env_opts, "MMDEBSTRAP_SUITE=$options->{suite}";
|
push @env_opts, "MMDEBSTRAP_SUITE=$options->{suite}";
|
||||||
}
|
}
|
||||||
|
push @env_opts, "MMDEBSTRAP_FORMAT=$options->{format}";
|
||||||
# Storing the hook name is important for hook scripts to potentially change
|
# Storing the hook name is important for hook scripts to potentially change
|
||||||
# their behavior depending on the hook. It's also important for when the
|
# their behavior depending on the hook. It's also important for when the
|
||||||
# hook wants to use the mmdebstrap --hook-helper.
|
# hook wants to use the mmdebstrap --hook-helper.
|
||||||
|
@ -1653,6 +1661,9 @@ sub run_hooks {
|
||||||
push @env_opts,
|
push @env_opts,
|
||||||
("MMDEBSTRAP_ESSENTIAL=" . (join " ", @{$essential_pkgs}));
|
("MMDEBSTRAP_ESSENTIAL=" . (join " ", @{$essential_pkgs}));
|
||||||
}
|
}
|
||||||
|
if ($options->{mode} eq 'unshare') {
|
||||||
|
push @env_opts, "container=mmdebstrap-unshare";
|
||||||
|
}
|
||||||
|
|
||||||
# Unset the close-on-exec flag, so that the file descriptor does not
|
# Unset the close-on-exec flag, so that the file descriptor does not
|
||||||
# get closed when we exec
|
# get closed when we exec
|
||||||
|
@ -1744,7 +1755,8 @@ sub run_hooks {
|
||||||
# does for python
|
# does for python
|
||||||
my @args = shellwords $script;
|
my @args = shellwords $script;
|
||||||
hookhelper($options->{root}, $options->{mode}, $name,
|
hookhelper($options->{root}, $options->{mode}, $name,
|
||||||
$options->{qemu}, $verbosity_level, @args);
|
(join ',', @{ $options->{skip} }),
|
||||||
|
$verbosity_level, @args);
|
||||||
exit 0;
|
exit 0;
|
||||||
}
|
}
|
||||||
waitpid($pid, 0);
|
waitpid($pid, 0);
|
||||||
|
@ -2589,6 +2601,8 @@ sub run_extract() {
|
||||||
}
|
}
|
||||||
# not using dpkg-deb --extract as that would replace the
|
# not using dpkg-deb --extract as that would replace the
|
||||||
# merged-usr symlinks with plain directories
|
# merged-usr symlinks with plain directories
|
||||||
|
# even after switching from pre-merging to post-merging, dpkg-deb
|
||||||
|
# will ignore filter rules from dpkg.cfg.d
|
||||||
# https://bugs.debian.org/989602
|
# https://bugs.debian.org/989602
|
||||||
# not using dpkg --unpack because that would try running preinst
|
# not using dpkg --unpack because that would try running preinst
|
||||||
# maintainer scripts
|
# maintainer scripts
|
||||||
|
@ -2768,90 +2782,49 @@ sub run_prepare {
|
||||||
error "unknown mode: $options->{mode}";
|
error "unknown mode: $options->{mode}";
|
||||||
}
|
}
|
||||||
|
|
||||||
# copy qemu-user-static binary into chroot
|
# foreign architecture setup for fakechroot mode
|
||||||
if (defined $options->{qemu}) {
|
if (defined $options->{qemu} && $options->{mode} eq 'fakechroot') {
|
||||||
if ($options->{mode} eq 'fakechroot') {
|
# Make sure that the fakeroot and fakechroot shared libraries exist for
|
||||||
# Make sure that the fakeroot and fakechroot shared
|
# the right architecture
|
||||||
# libraries exist for the right architecture
|
open my $fh, '-|', 'dpkg-architecture', '-a',
|
||||||
open my $fh, '-|', 'dpkg-architecture', '-a',
|
$options->{nativearch},
|
||||||
$options->{nativearch},
|
'-qDEB_HOST_MULTIARCH' // error "failed to fork(): $!";
|
||||||
'-qDEB_HOST_MULTIARCH' // error "failed to fork(): $!";
|
chomp(
|
||||||
chomp(
|
my $deb_host_multiarch = do { local $/; <$fh> }
|
||||||
my $deb_host_multiarch = do { local $/; <$fh> }
|
);
|
||||||
);
|
close $fh;
|
||||||
close $fh;
|
if (($? != 0) or (!$deb_host_multiarch)) {
|
||||||
if (($? != 0) or (!$deb_host_multiarch)) {
|
error "dpkg-architecture failed: $?";
|
||||||
error "dpkg-architecture failed: $?";
|
}
|
||||||
}
|
my $fakechrootdir = "/usr/lib/$deb_host_multiarch/fakechroot";
|
||||||
my $fakechrootdir = "/usr/lib/$deb_host_multiarch/fakechroot";
|
if (!-e "$fakechrootdir/libfakechroot.so") {
|
||||||
if (!-e "$fakechrootdir/libfakechroot.so") {
|
error "$fakechrootdir/libfakechroot.so doesn't exist."
|
||||||
error "$fakechrootdir/libfakechroot.so doesn't exist."
|
. " Install libfakechroot:$options->{nativearch}"
|
||||||
. " Install libfakechroot:$options->{nativearch}"
|
. " outside the chroot";
|
||||||
. " outside the chroot";
|
}
|
||||||
}
|
my $fakerootdir = "/usr/lib/$deb_host_multiarch/libfakeroot";
|
||||||
my $fakerootdir = "/usr/lib/$deb_host_multiarch/libfakeroot";
|
if (!-e "$fakerootdir/libfakeroot-sysv.so") {
|
||||||
if (!-e "$fakerootdir/libfakeroot-sysv.so") {
|
error "$fakerootdir/libfakeroot-sysv.so doesn't exist."
|
||||||
error "$fakerootdir/libfakeroot-sysv.so doesn't exist."
|
. " Install libfakeroot:$options->{nativearch}"
|
||||||
. " Install libfakeroot:$options->{nativearch}"
|
. " outside the chroot";
|
||||||
. " outside the chroot";
|
}
|
||||||
}
|
|
||||||
# The rest of this block sets environment variables, so we
|
# The rest of this block sets environment variables, so we have to add
|
||||||
# have to add the "no critic" statement to stop perlcritic
|
# the "no critic" statement to stop perlcritic from complaining about
|
||||||
# from complaining about setting global variables
|
# setting global variables
|
||||||
## no critic (Variables::RequireLocalizedPunctuationVars)
|
## no critic (Variables::RequireLocalizedPunctuationVars)
|
||||||
# fakechroot only fills LD_LIBRARY_PATH with the
|
# fakechroot only fills LD_LIBRARY_PATH with the directories of the
|
||||||
# directories of the host's architecture. We append the
|
# host's architecture. We append the directories of the chroot
|
||||||
# directories of the chroot architecture.
|
# architecture.
|
||||||
$ENV{LD_LIBRARY_PATH}
|
$ENV{LD_LIBRARY_PATH}
|
||||||
= "$ENV{LD_LIBRARY_PATH}:$fakechrootdir:$fakerootdir";
|
= "$ENV{LD_LIBRARY_PATH}:$fakechrootdir:$fakerootdir";
|
||||||
# The binfmt support on the outside is used, so qemu needs
|
# The binfmt support on the outside is used, so qemu needs to know
|
||||||
# to know where it has to look for shared libraries
|
# where it has to look for shared libraries
|
||||||
if (defined $ENV{QEMU_LD_PREFIX}
|
if (defined $ENV{QEMU_LD_PREFIX}
|
||||||
&& $ENV{QEMU_LD_PREFIX} ne "") {
|
&& $ENV{QEMU_LD_PREFIX} ne "") {
|
||||||
$ENV{QEMU_LD_PREFIX} = "$ENV{QEMU_LD_PREFIX}:$options->{root}";
|
$ENV{QEMU_LD_PREFIX} = "$ENV{QEMU_LD_PREFIX}:$options->{root}";
|
||||||
} else {
|
|
||||||
$ENV{QEMU_LD_PREFIX} = $options->{root};
|
|
||||||
}
|
|
||||||
} elsif (any { $_ eq $options->{mode} } ('root', 'unshare')) {
|
|
||||||
my $require_qemu_static = 1;
|
|
||||||
# make $@ local, so we don't print an eventual error
|
|
||||||
# in other parts where we evaluate $@
|
|
||||||
local $@ = '';
|
|
||||||
eval {
|
|
||||||
# Check for the F flag which makes the kernel open the binfmt
|
|
||||||
# binary at configuration time instead of lazily at startup
|
|
||||||
# time. If the flag is set, then the qemu-static binary is not
|
|
||||||
# required inside the chroot.
|
|
||||||
if (-e "/proc/sys/fs/binfmt_misc/qemu-$options->{qemu}") {
|
|
||||||
open my $fh, '<',
|
|
||||||
"/proc/sys/fs/binfmt_misc/qemu-$options->{qemu}";
|
|
||||||
while (my $line = <$fh>) {
|
|
||||||
chomp($line);
|
|
||||||
if ($line =~ /^flags: [A-Z]*F[A-Z]*$/) {
|
|
||||||
$require_qemu_static = 0;
|
|
||||||
last;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close $fh;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if ($require_qemu_static) {
|
|
||||||
# other modes require a static qemu-user binary
|
|
||||||
my $qemubin = "/usr/bin/qemu-$options->{qemu}-static";
|
|
||||||
if (!-e $qemubin) {
|
|
||||||
error "cannot find $qemubin";
|
|
||||||
}
|
|
||||||
copy $qemubin, "$options->{root}/$qemubin"
|
|
||||||
or error "cannot copy $qemubin: $!";
|
|
||||||
# File::Copy does not retain permissions but on some
|
|
||||||
# platforms (like Travis CI) the binfmt interpreter must
|
|
||||||
# have the executable bit set or otherwise execve will
|
|
||||||
# fail with EACCES
|
|
||||||
chmod 0755, "$options->{root}/$qemubin"
|
|
||||||
or error "cannot chmod $qemubin: $!";
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
error "unknown mode: $options->{mode}";
|
$ENV{QEMU_LD_PREFIX} = $options->{root};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2992,15 +2965,15 @@ sub run_install() {
|
||||||
|
|
||||||
my @pkgs_to_install = (@{ $options->{include} });
|
my @pkgs_to_install = (@{ $options->{include} });
|
||||||
if ($options->{variant} eq 'buildd') {
|
if ($options->{variant} eq 'buildd') {
|
||||||
push @pkgs_to_install, 'build-essential';
|
push @pkgs_to_install, 'build-essential', 'apt';
|
||||||
}
|
}
|
||||||
if (any { $_ eq $options->{variant} }
|
if (any { $_ eq $options->{variant} }
|
||||||
('required', 'important', 'standard', 'buildd')) {
|
('required', 'important', 'standard')) {
|
||||||
# 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.
|
||||||
my $priority;
|
my $priority;
|
||||||
if (any { $_ eq $options->{variant} } ('required', 'buildd')) {
|
if (any { $_ eq $options->{variant} } ('required')) {
|
||||||
$priority = '?and(?priority(required),?not(?essential))';
|
$priority = '?and(?priority(required),?not(?essential))';
|
||||||
} elsif ($options->{variant} eq 'important') {
|
} elsif ($options->{variant} eq 'important') {
|
||||||
$priority = '?and(?or(?priority(required),?priority(important)),'
|
$priority = '?and(?or(?priority(required),?priority(important)),'
|
||||||
|
@ -3169,7 +3142,7 @@ sub run_cleanup() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (any { $_ eq 'cleanup/mmdebstrap/qemu' } @{ $options->{skip} }) {
|
if (any { $_ eq 'cleanup/mmdebstrap/qemu' } @{ $options->{skip} }) {
|
||||||
info "skipping cleanup/mmdebstrap/qume as requested";
|
info "skipping cleanup/mmdebstrap/qemu as requested";
|
||||||
} elsif (defined $options->{qemu}
|
} elsif (defined $options->{qemu}
|
||||||
and any { $_ eq $options->{mode} } ('root', 'unshare')
|
and any { $_ eq $options->{mode} } ('root', 'unshare')
|
||||||
and -e "$options->{root}/usr/bin/qemu-$options->{qemu}-static") {
|
and -e "$options->{root}/usr/bin/qemu-$options->{qemu}-static") {
|
||||||
|
@ -3258,6 +3231,52 @@ sub run_cleanup() {
|
||||||
closedir($dh);
|
closedir($dh);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (any { $_ eq 'cleanup/dev' } @{ $options->{skip} }) {
|
||||||
|
info "skipping cleanup/dev as requested";
|
||||||
|
} else {
|
||||||
|
|
||||||
|
# By default, tar is run with --exclude=./dev because we create the
|
||||||
|
# ./dev entries ourselves using @devfiles. But if --skip=output/dev is
|
||||||
|
# used, --exclude=./dev is not passed so that the chroot includes ./dev
|
||||||
|
# as created by base-files. But if mknod was available (for example
|
||||||
|
# when running as root) then ./dev will also include the @devfiles
|
||||||
|
# entries created by run_setup() and thus the resulting tarball will
|
||||||
|
# include things inside ./dev despite the user having supplied
|
||||||
|
# --skip=output/dev. So if --skip=output/dev was passed and if a
|
||||||
|
# tarball is to be created, we need to make sure to clean up the
|
||||||
|
# ./dev entries that were created in run_setup(). This is not done
|
||||||
|
# when creating a directory because in that case we want to do the
|
||||||
|
# same as debootstrap and create a directory including device nodes.
|
||||||
|
if ($options->{format} ne 'directory' && any { $_ eq 'output/dev' }
|
||||||
|
@{ $options->{skip} }) {
|
||||||
|
foreach my $file (@devfiles) {
|
||||||
|
my ($fname, $mode, $type, $linkname, $devmajor, $devminor)
|
||||||
|
= @{$file};
|
||||||
|
if (!-e "$options->{root}/dev/$fname") {
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
# do not remove ./dev itself
|
||||||
|
if ($fname eq "") {
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
if ($type == 0) { # normal file
|
||||||
|
error "type 0 not implemented";
|
||||||
|
} elsif ($type == 1) { # hardlink
|
||||||
|
error "type 1 not implemented";
|
||||||
|
} elsif (any { $_ eq $type } (2, 3, 4))
|
||||||
|
{ # symlink, char, block
|
||||||
|
unlink "$options->{root}/dev/$fname"
|
||||||
|
or error "failed to unlink ./dev/$fname: $!";
|
||||||
|
} elsif ($type == 5) { # directory
|
||||||
|
rmdir "$options->{root}/dev/$fname"
|
||||||
|
or error "failed to unlink ./dev/$fname: $!";
|
||||||
|
} else {
|
||||||
|
error "unsupported type: $type";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3340,8 +3359,20 @@ sub pivot_root {
|
||||||
}
|
}
|
||||||
|
|
||||||
sub hookhelper {
|
sub hookhelper {
|
||||||
my ($root, $mode, $hook, $qemu, $verbosity, $command, @args) = @_;
|
my ($root, $mode, $hook, $skipopt, $verbosity, $command, @args) = @_;
|
||||||
$verbosity_level = $verbosity;
|
$verbosity_level = $verbosity;
|
||||||
|
my @skipopts = ();
|
||||||
|
if (length $skipopt) {
|
||||||
|
for my $skip (split /[,\s]+/, $skipopt) {
|
||||||
|
# strip leading and trailing whitespace
|
||||||
|
$skip =~ s/^\s+|\s+$//g;
|
||||||
|
# skip if the remainder is an empty string
|
||||||
|
if ($skip eq '') {
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
push @skipopts, $skip;
|
||||||
|
}
|
||||||
|
}
|
||||||
# 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
|
||||||
|
@ -3430,8 +3461,48 @@ sub hookhelper {
|
||||||
@cmdprefix, @tarcmd, '--xattrs-include=*',
|
@cmdprefix, @tarcmd, '--xattrs-include=*',
|
||||||
'--directory', $directory, '--extract', '--file', '-'
|
'--directory', $directory, '--extract', '--file', '-'
|
||||||
);
|
);
|
||||||
debug("helper: running " . (join " ", @cmd));
|
# go via mmtarfilter if copy-in/mknod, tar-in/mknod or
|
||||||
open($fh, '|-', @cmd) // error "failed to fork(): $!";
|
# sync-in/mknod were part of the skip options
|
||||||
|
if (any { $_ eq "$command/mknod" } @skipopts) {
|
||||||
|
info "skipping $command/mknod as requested";
|
||||||
|
my $tarfilter = "mmtarfilter";
|
||||||
|
if (-x "./tarfilter") {
|
||||||
|
$tarfilter = "./tarfilter";
|
||||||
|
}
|
||||||
|
pipe my $filter_reader, $fh or error "pipe failed: $!";
|
||||||
|
pipe my $tar_reader, my $filter_writer
|
||||||
|
or error "pipe failed: $!";
|
||||||
|
my $pid1 = fork() // error "fork() failed: $!";
|
||||||
|
if ($pid1 == 0) {
|
||||||
|
open(STDIN, '<&', $filter_reader)
|
||||||
|
or error "cannot open STDIN: $!";
|
||||||
|
open(STDOUT, '>&', $filter_writer)
|
||||||
|
or error "cannot open STDOUT: $!";
|
||||||
|
close($tar_reader)
|
||||||
|
or error "cannot close tar_reader: $!";
|
||||||
|
debug(
|
||||||
|
"helper: running $tarfilter --type-exclude=3 "
|
||||||
|
. "--type-exclude=4");
|
||||||
|
eval { Devel::Cover::set_coverage("none") }
|
||||||
|
if $is_covering;
|
||||||
|
exec $tarfilter, '--type-exclude=3',
|
||||||
|
'--type-exclude=4';
|
||||||
|
}
|
||||||
|
my $pid2 = fork() // error "fork() failed: $!";
|
||||||
|
if ($pid2 == 0) {
|
||||||
|
open(STDIN, '<&', $tar_reader)
|
||||||
|
or error "cannot open STDIN: $!";
|
||||||
|
close($filter_writer)
|
||||||
|
or error "cannot close filter_writer: $!";
|
||||||
|
debug("helper: running " . (join " ", @cmd));
|
||||||
|
eval { Devel::Cover::set_coverage("none") }
|
||||||
|
if $is_covering;
|
||||||
|
exec { $cmd[0] } @cmd;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
debug("helper: running " . (join " ", @cmd));
|
||||||
|
open($fh, '|-', @cmd) // error "failed to fork(): $!";
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
error "unknown command: $command";
|
error "unknown command: $command";
|
||||||
}
|
}
|
||||||
|
@ -3951,13 +4022,15 @@ sub hooklistener {
|
||||||
if ($? != 0) {
|
if ($? != 0) {
|
||||||
error "tar failed";
|
error "tar failed";
|
||||||
}
|
}
|
||||||
|
} elsif ($msg eq "error") {
|
||||||
|
error "received error on socket";
|
||||||
} else {
|
} else {
|
||||||
error "unknown message: $msg";
|
error "unknown message: $msg";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if ($@) {
|
if ($@) {
|
||||||
debug("hooklistener errored out: $@");
|
warning("hooklistener errored out: $@");
|
||||||
# inform the other side that something went wrong
|
# inform the other side that something went wrong
|
||||||
print STDOUT (pack("n", 0) . "error")
|
print STDOUT (pack("n", 0) . "error")
|
||||||
or error "cannot write to socket: $!";
|
or error "cannot write to socket: $!";
|
||||||
|
@ -4441,6 +4514,7 @@ sub main() {
|
||||||
include => [],
|
include => [],
|
||||||
architectures => [$hostarch],
|
architectures => [$hostarch],
|
||||||
mode => 'auto',
|
mode => 'auto',
|
||||||
|
format => 'auto',
|
||||||
dpkgopts => [],
|
dpkgopts => [],
|
||||||
aptopts => [],
|
aptopts => [],
|
||||||
apttrusted => $apttrusted,
|
apttrusted => $apttrusted,
|
||||||
|
@ -4454,7 +4528,6 @@ sub main() {
|
||||||
skip => [],
|
skip => [],
|
||||||
};
|
};
|
||||||
my $logfile = undef;
|
my $logfile = undef;
|
||||||
my $format = 'auto';
|
|
||||||
Getopt::Long::Configure('default', 'bundling', 'auto_abbrev',
|
Getopt::Long::Configure('default', 'bundling', 'auto_abbrev',
|
||||||
'ignore_case_always');
|
'ignore_case_always');
|
||||||
GetOptions(
|
GetOptions(
|
||||||
|
@ -4537,7 +4610,7 @@ sub main() {
|
||||||
'q|quiet' => sub { $verbosity_level = 0; },
|
'q|quiet' => sub { $verbosity_level = 0; },
|
||||||
'v|verbose' => sub { $verbosity_level = 2; },
|
'v|verbose' => sub { $verbosity_level = 2; },
|
||||||
'd|debug' => sub { $verbosity_level = 3; },
|
'd|debug' => sub { $verbosity_level = 3; },
|
||||||
'format=s' => \$format,
|
'format=s' => \$options->{format},
|
||||||
'logfile=s' => \$logfile,
|
'logfile=s' => \$logfile,
|
||||||
# no-op options so that mmdebstrap can be used with
|
# no-op options so that mmdebstrap can be used with
|
||||||
# sbuild-createchroot --debootstrap=mmdebstrap
|
# sbuild-createchroot --debootstrap=mmdebstrap
|
||||||
|
@ -4704,16 +4777,16 @@ sub main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
# sqfs is an alias for squashfs
|
# sqfs is an alias for squashfs
|
||||||
if ($format eq 'sqfs') {
|
if ($options->{format} eq 'sqfs') {
|
||||||
$format = 'squashfs';
|
$options->{format} = 'squashfs';
|
||||||
}
|
}
|
||||||
# dir is an alias for directory
|
# dir is an alias for directory
|
||||||
if ($format eq 'dir') {
|
if ($options->{format} eq 'dir') {
|
||||||
$format = 'directory';
|
$options->{format} = 'directory';
|
||||||
}
|
}
|
||||||
my @valid_formats
|
my @valid_formats
|
||||||
= ('auto', 'directory', 'tar', 'squashfs', 'ext2', 'null');
|
= ('auto', 'directory', 'tar', 'squashfs', 'ext2', 'null');
|
||||||
if (none { $_ eq $format } @valid_formats) {
|
if (none { $_ eq $options->{format} } @valid_formats) {
|
||||||
error "invalid format. Choose from " . (join ', ', @valid_formats);
|
error "invalid format. Choose from " . (join ', ', @valid_formats);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5480,7 +5553,7 @@ sub main() {
|
||||||
my $tar_compressor = get_tar_compressor($options->{target});
|
my $tar_compressor = get_tar_compressor($options->{target});
|
||||||
|
|
||||||
# figure out the right format
|
# figure out the right format
|
||||||
if ($format eq 'auto') {
|
if ($options->{format} eq 'auto') {
|
||||||
# (stat(...))[6] is the device identifier which contains the major and
|
# (stat(...))[6] is the device identifier which contains the major and
|
||||||
# minor numbers for character special files
|
# minor numbers for character special files
|
||||||
# major 1 and minor 3 is /dev/null on Linux
|
# major 1 and minor 3 is /dev/null on Linux
|
||||||
|
@ -5489,7 +5562,7 @@ sub main() {
|
||||||
and -c '/dev/null'
|
and -c '/dev/null'
|
||||||
and major((stat("/dev/null"))[6]) == 1
|
and major((stat("/dev/null"))[6]) == 1
|
||||||
and minor((stat("/dev/null"))[6]) == 3) {
|
and minor((stat("/dev/null"))[6]) == 3) {
|
||||||
$format = 'null';
|
$options->{format} = 'null';
|
||||||
} elsif ($options->{target} eq '-'
|
} elsif ($options->{target} eq '-'
|
||||||
and $OSNAME eq 'linux'
|
and $OSNAME eq 'linux'
|
||||||
and major((stat(STDOUT))[6]) == 1
|
and major((stat(STDOUT))[6]) == 1
|
||||||
|
@ -5497,9 +5570,9 @@ sub main() {
|
||||||
# by checking the major and minor number of the STDOUT fd we also
|
# by checking the major and minor number of the STDOUT fd we also
|
||||||
# can detect redirections to /dev/null and choose the null format
|
# can detect redirections to /dev/null and choose the null format
|
||||||
# accordingly
|
# accordingly
|
||||||
$format = 'null';
|
$options->{format} = 'null';
|
||||||
} elsif ($options->{target} ne '-' and -d $options->{target}) {
|
} elsif ($options->{target} ne '-' and -d $options->{target}) {
|
||||||
$format = 'directory';
|
$options->{format} = 'directory';
|
||||||
} elsif (
|
} elsif (
|
||||||
defined $tar_compressor
|
defined $tar_compressor
|
||||||
or $options->{target} =~ /\.tar$/
|
or $options->{target} =~ /\.tar$/
|
||||||
|
@ -5507,7 +5580,7 @@ sub main() {
|
||||||
or -p $options->{target} # named pipe (fifo)
|
or -p $options->{target} # named pipe (fifo)
|
||||||
or -c $options->{target} # character special like /dev/null
|
or -c $options->{target} # character special like /dev/null
|
||||||
) {
|
) {
|
||||||
$format = 'tar';
|
$options->{format} = 'tar';
|
||||||
# check if the compressor is installed
|
# check if the compressor is installed
|
||||||
if (defined $tar_compressor) {
|
if (defined $tar_compressor) {
|
||||||
my $pid = fork() // error "fork() failed: $!";
|
my $pid = fork() // error "fork() failed: $!";
|
||||||
|
@ -5527,7 +5600,7 @@ sub main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} elsif ($options->{target} =~ /\.(squashfs|sqfs)$/) {
|
} elsif ($options->{target} =~ /\.(squashfs|sqfs)$/) {
|
||||||
$format = 'squashfs';
|
$options->{format} = 'squashfs';
|
||||||
# check if tar2sqfs is installed
|
# check if tar2sqfs is installed
|
||||||
my $pid = fork() // error "fork() failed: $!";
|
my $pid = fork() // error "fork() failed: $!";
|
||||||
if ($pid == 0) {
|
if ($pid == 0) {
|
||||||
|
@ -5543,7 +5616,7 @@ sub main() {
|
||||||
error("failed to start tar2sqfs --version");
|
error("failed to start tar2sqfs --version");
|
||||||
}
|
}
|
||||||
} elsif ($options->{target} =~ /\.ext2$/) {
|
} elsif ($options->{target} =~ /\.ext2$/) {
|
||||||
$format = 'ext2';
|
$options->{format} = 'ext2';
|
||||||
# check if the installed version of genext2fs supports tarballs on
|
# check if the installed version of genext2fs supports tarballs on
|
||||||
# stdin
|
# stdin
|
||||||
(undef, my $filename) = tempfile(
|
(undef, my $filename) = tempfile(
|
||||||
|
@ -5564,32 +5637,34 @@ sub main() {
|
||||||
error "genext2fs failed with exit status: $exitstatus";
|
error "genext2fs failed with exit status: $exitstatus";
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$format = 'directory';
|
$options->{format} = 'directory';
|
||||||
}
|
}
|
||||||
info "automatically chosen format: $format";
|
info "automatically chosen format: $options->{format}";
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($options->{target} eq '-' and $format ne 'tar' and $format ne 'null') {
|
if ( $options->{target} eq '-'
|
||||||
error "the $format format is unable to write to standard output";
|
and $options->{format} ne 'tar'
|
||||||
|
and $options->{format} ne 'null') {
|
||||||
|
error "the $options->{format} format is unable to write to stdout";
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($format eq 'null'
|
if ($options->{format} eq 'null'
|
||||||
and none { $_ eq $options->{target} } ('-', '/dev/null')) {
|
and none { $_ eq $options->{target} } ('-', '/dev/null')) {
|
||||||
info "ignoring target $options->{target} with null format";
|
info "ignoring target $options->{target} with null format";
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($format eq 'ext2') {
|
if ($options->{format} eq 'ext2') {
|
||||||
if (!can_execute 'genext2fs') {
|
if (!can_execute 'genext2fs') {
|
||||||
error "need genext2fs for ext2 format";
|
error "need genext2fs for ext2 format";
|
||||||
}
|
}
|
||||||
} elsif ($format eq 'squashfs') {
|
} elsif ($options->{format} eq 'squashfs') {
|
||||||
if (!can_execute 'tar2sqfs') {
|
if (!can_execute 'tar2sqfs') {
|
||||||
error "need tar2sqfs binary from the squashfs-tools-ng package";
|
error "need tar2sqfs binary from the squashfs-tools-ng package";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (any { $_ eq $format } ('tar', 'squashfs', 'ext2', 'null')) {
|
if (any { $_ eq $options->{format} } ('tar', 'squashfs', 'ext2', 'null')) {
|
||||||
if ($format ne 'null') {
|
if ($options->{format} ne 'null') {
|
||||||
if (any { $_ eq $options->{variant} } ('extract', 'custom')
|
if (any { $_ eq $options->{variant} } ('extract', 'custom')
|
||||||
and $options->{mode} eq 'fakechroot') {
|
and $options->{mode} eq 'fakechroot') {
|
||||||
info "creating a tarball or squashfs image or ext2 image in"
|
info "creating a tarball or squashfs image or ext2 image in"
|
||||||
|
@ -5626,7 +5701,7 @@ sub main() {
|
||||||
) {
|
) {
|
||||||
chmod 0755, $options->{root} or error "cannot chmod root: $!";
|
chmod 0755, $options->{root} or error "cannot chmod root: $!";
|
||||||
}
|
}
|
||||||
} elsif ($format eq 'directory') {
|
} elsif ($options->{format} eq 'directory') {
|
||||||
# user does not seem to have specified a tarball as output, thus work
|
# user does not seem to have specified a tarball as output, thus work
|
||||||
# directly in the supplied directory
|
# directly in the supplied directory
|
||||||
$options->{root} = $options->{target};
|
$options->{root} = $options->{target};
|
||||||
|
@ -5682,7 +5757,7 @@ sub main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
error "unknown format: $format";
|
error "unknown format: $options->{format}";
|
||||||
}
|
}
|
||||||
|
|
||||||
# check for double quotes because apt doesn't allow to escape them and
|
# check for double quotes because apt doesn't allow to escape them and
|
||||||
|
@ -5766,15 +5841,28 @@ sub main() {
|
||||||
error "unknown mode: $options->{mode}";
|
error "unknown mode: $options->{mode}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# If a tarball is to be created, we always (except if --skip=output/dev is
|
||||||
|
# passed) craft the /dev entries ourselves.
|
||||||
|
# Why do we put /dev entries in the final tarball?
|
||||||
|
# - because debootstrap does it
|
||||||
|
# - because schroot (#856877) and pbuilder rely on it and we care about
|
||||||
|
# Debian buildds (using schroot) and reproducible builds infra (using
|
||||||
|
# pbuilder)
|
||||||
|
# If both the above assertion change, we can stop creating /dev entries as
|
||||||
|
# well.
|
||||||
my $devtar = '';
|
my $devtar = '';
|
||||||
# We always craft the /dev entries ourselves if a tarball is to be created
|
if (any { $_ eq $options->{format} } ('tar', 'squashfs', 'ext2')) {
|
||||||
if (any { $_ eq $format } ('tar', 'squashfs', 'ext2')) {
|
|
||||||
foreach my $file (@devfiles) {
|
foreach my $file (@devfiles) {
|
||||||
my ($fname, $mode, $type, $linkname, $devmajor, $devminor)
|
my ($fname, $mode, $type, $linkname, $devmajor, $devminor)
|
||||||
= @{$file};
|
= @{$file};
|
||||||
if (length "./dev/$fname" > 100) {
|
if (length "./dev/$fname" > 100) {
|
||||||
error "tar entry cannot exceed 100 characters";
|
error "tar entry cannot exceed 100 characters";
|
||||||
}
|
}
|
||||||
|
if ($type == 3
|
||||||
|
and any { $_ eq 'output/mknod' } @{ $options->{skip} }) {
|
||||||
|
info "skipping output/mknod as requested for ./dev/$fname";
|
||||||
|
next;
|
||||||
|
}
|
||||||
my $entry = pack(
|
my $entry = pack(
|
||||||
'a100 a8 a8 a8 a12 a12 A8 a1 a100 a8 a32 a32 a8 a8 a155 x12',
|
'a100 a8 a8 a8 a12 a12 A8 a1 a100 a8 a32 a32 a8 a8 a155 x12',
|
||||||
"./dev/$fname",
|
"./dev/$fname",
|
||||||
|
@ -5798,10 +5886,10 @@ sub main() {
|
||||||
= sprintf("%06o\0", unpack("%16C*", $entry));
|
= sprintf("%06o\0", unpack("%16C*", $entry));
|
||||||
$devtar .= $entry;
|
$devtar .= $entry;
|
||||||
}
|
}
|
||||||
} elsif (any { $_ eq $format } ('directory', 'null')) {
|
} elsif (any { $_ eq $options->{format} } ('directory', 'null')) {
|
||||||
# nothing to do
|
# nothing to do
|
||||||
} else {
|
} else {
|
||||||
error "unknown format: $format";
|
error "unknown format: $options->{format}";
|
||||||
}
|
}
|
||||||
|
|
||||||
my $exitstatus = 0;
|
my $exitstatus = 0;
|
||||||
|
@ -5814,11 +5902,14 @@ sub main() {
|
||||||
'--format=pax',
|
'--format=pax',
|
||||||
'--pax-option=exthdr.name=%d/PaxHeaders/%f,delete=atime,delete=ctime',
|
'--pax-option=exthdr.name=%d/PaxHeaders/%f,delete=atime,delete=ctime',
|
||||||
'-c',
|
'-c',
|
||||||
'--exclude=./dev',
|
|
||||||
'--exclude=./lost+found'
|
'--exclude=./lost+found'
|
||||||
);
|
);
|
||||||
|
# only exclude ./dev if device nodes are written out (the default)
|
||||||
|
if (none { $_ eq 'output/dev' } @{ $options->{skip} }) {
|
||||||
|
push @taropts, '--exclude=./dev';
|
||||||
|
}
|
||||||
# tar2sqfs and genext2fs do not support extended attributes
|
# tar2sqfs and genext2fs do not support extended attributes
|
||||||
if ($format eq "squashfs") {
|
if ($options->{format} eq "squashfs") {
|
||||||
# tar2sqfs supports user.*, trusted.* and security.* but not system.*
|
# tar2sqfs supports user.*, trusted.* and security.* but not system.*
|
||||||
# https://bugs.debian.org/988100
|
# https://bugs.debian.org/988100
|
||||||
# lib/sqfs/xattr/xattr.c of https://github.com/AgentD/squashfs-tools-ng
|
# lib/sqfs/xattr/xattr.c of https://github.com/AgentD/squashfs-tools-ng
|
||||||
|
@ -5827,7 +5918,7 @@ sub main() {
|
||||||
warning("tar2sqfs does not support extended attributes"
|
warning("tar2sqfs does not support extended attributes"
|
||||||
. " from the 'system' namespace");
|
. " from the 'system' namespace");
|
||||||
push @taropts, '--xattrs', '--xattrs-exclude=system.*';
|
push @taropts, '--xattrs', '--xattrs-exclude=system.*';
|
||||||
} elsif ($format eq "ext2") {
|
} elsif ($options->{format} eq "ext2") {
|
||||||
warning "genext2fs does not support extended attributes";
|
warning "genext2fs does not support extended attributes";
|
||||||
} else {
|
} else {
|
||||||
push @taropts, '--xattrs';
|
push @taropts, '--xattrs';
|
||||||
|
@ -5879,7 +5970,7 @@ sub main() {
|
||||||
close $childsock;
|
close $childsock;
|
||||||
|
|
||||||
close $nblkreader;
|
close $nblkreader;
|
||||||
if (!$options->{dryrun} && $format eq 'ext2') {
|
if (!$options->{dryrun} && $options->{format} eq 'ext2') {
|
||||||
my $numblocks = approx_disk_usage($options->{root});
|
my $numblocks = approx_disk_usage($options->{root});
|
||||||
print $nblkwriter "$numblocks\n";
|
print $nblkwriter "$numblocks\n";
|
||||||
$nblkwriter->flush();
|
$nblkwriter->flush();
|
||||||
|
@ -5888,7 +5979,8 @@ sub main() {
|
||||||
|
|
||||||
if ($options->{dryrun}) {
|
if ($options->{dryrun}) {
|
||||||
info "simulate creating tarball...";
|
info "simulate creating tarball...";
|
||||||
} elsif (any { $_ eq $format } ('tar', 'squashfs', 'ext2')) {
|
} elsif (any { $_ eq $options->{format} }
|
||||||
|
('tar', 'squashfs', 'ext2')) {
|
||||||
info "creating tarball...";
|
info "creating tarball...";
|
||||||
|
|
||||||
# redirect tar output to the writing end of the pipe so
|
# redirect tar output to the writing end of the pipe so
|
||||||
|
@ -5909,10 +6001,11 @@ sub main() {
|
||||||
or error "tar failed: $?";
|
or error "tar failed: $?";
|
||||||
|
|
||||||
info "done";
|
info "done";
|
||||||
} elsif (any { $_ eq $format } ('directory', 'null')) {
|
} elsif (any { $_ eq $options->{format} }
|
||||||
|
('directory', 'null')) {
|
||||||
# nothing to do
|
# nothing to do
|
||||||
} else {
|
} else {
|
||||||
error "unknown format: $format";
|
error "unknown format: $options->{format}";
|
||||||
}
|
}
|
||||||
|
|
||||||
exit 0;
|
exit 0;
|
||||||
|
@ -5944,7 +6037,7 @@ sub main() {
|
||||||
close $childsock;
|
close $childsock;
|
||||||
|
|
||||||
close $nblkreader;
|
close $nblkreader;
|
||||||
if (!$options->{dryrun} && $format eq 'ext2') {
|
if (!$options->{dryrun} && $options->{format} eq 'ext2') {
|
||||||
my $numblocks = approx_disk_usage($options->{root});
|
my $numblocks = approx_disk_usage($options->{root});
|
||||||
print $nblkwriter $numblocks;
|
print $nblkwriter $numblocks;
|
||||||
$nblkwriter->flush();
|
$nblkwriter->flush();
|
||||||
|
@ -5953,7 +6046,8 @@ sub main() {
|
||||||
|
|
||||||
if ($options->{dryrun}) {
|
if ($options->{dryrun}) {
|
||||||
info "simulate creating tarball...";
|
info "simulate creating tarball...";
|
||||||
} elsif (any { $_ eq $format } ('tar', 'squashfs', 'ext2')) {
|
} elsif (any { $_ eq $options->{format} }
|
||||||
|
('tar', 'squashfs', 'ext2')) {
|
||||||
info "creating tarball...";
|
info "creating tarball...";
|
||||||
|
|
||||||
# redirect tar output to the writing end of the pipe so that
|
# redirect tar output to the writing end of the pipe so that
|
||||||
|
@ -6001,10 +6095,10 @@ sub main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
info "done";
|
info "done";
|
||||||
} elsif (any { $_ eq $format } ('directory', 'null')) {
|
} elsif (any { $_ eq $options->{format} } ('directory', 'null')) {
|
||||||
# nothing to do
|
# nothing to do
|
||||||
} else {
|
} else {
|
||||||
error "unknown format: $format";
|
error "unknown format: $options->{format}";
|
||||||
}
|
}
|
||||||
|
|
||||||
exit 0;
|
exit 0;
|
||||||
|
@ -6062,7 +6156,7 @@ sub main() {
|
||||||
|
|
||||||
my $numblocks = 0;
|
my $numblocks = 0;
|
||||||
close $nblkwriter;
|
close $nblkwriter;
|
||||||
if (!$options->{dryrun} && $format eq 'ext2') {
|
if (!$options->{dryrun} && $options->{format} eq 'ext2') {
|
||||||
$numblocks = <$nblkreader>;
|
$numblocks = <$nblkreader>;
|
||||||
if (defined $numblocks) {
|
if (defined $numblocks) {
|
||||||
chomp $numblocks;
|
chomp $numblocks;
|
||||||
|
@ -6079,9 +6173,11 @@ sub main() {
|
||||||
|
|
||||||
if ($options->{dryrun}) {
|
if ($options->{dryrun}) {
|
||||||
# nothing to do
|
# nothing to do
|
||||||
} elsif (any { $_ eq $format } ('directory', 'null')) {
|
} elsif (any { $_ eq $options->{format} } ('directory', 'null')) {
|
||||||
# nothing to do
|
# nothing to do
|
||||||
} elsif (any { $_ eq $format } ('tar', 'squashfs', 'ext2')) {
|
} elsif ($options->{format} eq 'ext2' && $numblocks <= 0) {
|
||||||
|
# nothing to do because of invalid $numblocks
|
||||||
|
} elsif (any { $_ eq $options->{format} } ('tar', 'squashfs', 'ext2')) {
|
||||||
# we use eval() so that error() doesn't take this process down and
|
# we use eval() so that error() doesn't take this process down and
|
||||||
# thus leaves the setup() process without a parent
|
# thus leaves the setup() process without a parent
|
||||||
eval {
|
eval {
|
||||||
|
@ -6090,27 +6186,27 @@ sub main() {
|
||||||
error "cannot copy to standard output: $!";
|
error "cannot copy to standard output: $!";
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if ( $format eq 'squashfs'
|
if ( $options->{format} eq 'squashfs'
|
||||||
or $format eq 'ext2'
|
or $options->{format} eq 'ext2'
|
||||||
or defined $tar_compressor) {
|
or defined $tar_compressor) {
|
||||||
my @argv = ();
|
my @argv = ();
|
||||||
if ($format eq 'squashfs') {
|
if ($options->{format} eq 'squashfs') {
|
||||||
push @argv, 'tar2sqfs',
|
push @argv, 'tar2sqfs',
|
||||||
'--quiet', '--no-skip', '--force',
|
'--quiet', '--no-skip', '--force',
|
||||||
'--exportable',
|
'--exportable',
|
||||||
'--compressor', 'xz',
|
'--compressor', 'xz',
|
||||||
'--block-size', '1048576',
|
'--block-size', '1048576',
|
||||||
$options->{target};
|
$options->{target};
|
||||||
} elsif ($format eq 'ext2') {
|
} elsif ($options->{format} eq 'ext2') {
|
||||||
if ($numblocks <= 0) {
|
if ($numblocks <= 0) {
|
||||||
error "invalid number of blocks: $numblocks";
|
error "invalid number of blocks: $numblocks";
|
||||||
}
|
}
|
||||||
push @argv, 'genext2fs', '-B', 1024, '-b', $numblocks,
|
push @argv, 'genext2fs', '-B', 1024, '-b', $numblocks,
|
||||||
'-i', '16384', '-a', '-', $options->{target};
|
'-i', '16384', '-a', '-', $options->{target};
|
||||||
} elsif ($format eq 'tar') {
|
} elsif ($options->{format} eq 'tar') {
|
||||||
push @argv, @{$tar_compressor};
|
push @argv, @{$tar_compressor};
|
||||||
} else {
|
} else {
|
||||||
error "unknown format: $format";
|
error "unknown format: $options->{format}";
|
||||||
}
|
}
|
||||||
POSIX::sigprocmask(SIG_BLOCK, $sigset)
|
POSIX::sigprocmask(SIG_BLOCK, $sigset)
|
||||||
or error "Can't block signals: $!";
|
or error "Can't block signals: $!";
|
||||||
|
@ -6128,15 +6224,16 @@ sub main() {
|
||||||
or error "Can't unblock signals: $!";
|
or error "Can't unblock signals: $!";
|
||||||
|
|
||||||
# redirect stdout to file or /dev/null
|
# redirect stdout to file or /dev/null
|
||||||
if ($format eq 'squashfs' or $format eq 'ext2') {
|
if ( $options->{format} eq 'squashfs'
|
||||||
|
or $options->{format} eq 'ext2') {
|
||||||
open(STDOUT, '>', '/dev/null')
|
open(STDOUT, '>', '/dev/null')
|
||||||
or error "cannot open /dev/null for writing: $!";
|
or error "cannot open /dev/null for writing: $!";
|
||||||
} elsif ($format eq 'tar') {
|
} elsif ($options->{format} eq 'tar') {
|
||||||
open(STDOUT, '>', $options->{target})
|
open(STDOUT, '>', $options->{target})
|
||||||
or error
|
or error
|
||||||
"cannot open $options->{target} for writing: $!";
|
"cannot open $options->{target} for writing: $!";
|
||||||
} else {
|
} else {
|
||||||
error "unknown format: $format";
|
error "unknown format: $options->{format}";
|
||||||
}
|
}
|
||||||
open(STDIN, '<&', $rfh)
|
open(STDIN, '<&', $rfh)
|
||||||
or error "cannot open file handle for reading: $!";
|
or error "cannot open file handle for reading: $!";
|
||||||
|
@ -6168,12 +6265,34 @@ sub main() {
|
||||||
# running tar and this process itself) to reliably tear down
|
# running tar and this process itself) to reliably tear down
|
||||||
# all running child processes. The main process is not affected
|
# all running child processes. The main process is not affected
|
||||||
# because we are ignoring SIGHUP.
|
# because we are ignoring SIGHUP.
|
||||||
|
#
|
||||||
|
# FIXME: this codepath becomes dangerous in case mmdebstrap is not
|
||||||
|
# run in its own process group. When run from the terminal, the
|
||||||
|
# shell creates a new process group as part of its job control, so
|
||||||
|
# sending SIGHUP to all processes in our own process group should
|
||||||
|
# not be dangerous. But for example, on debci, lxc will run in the
|
||||||
|
# same process group as mmdebstrap and sending SIGHUP to the whole
|
||||||
|
# process group will also kill lxc. Creating a new process group
|
||||||
|
# for $pid will break things because only the foreground job is
|
||||||
|
# allowed to read from the terminal. If a background job does it,
|
||||||
|
# i will be suspended with SIGTTIN. Even though apt could be told
|
||||||
|
# to not read from the terminal by opening STDIN from /dev/null,
|
||||||
|
# this would make --chrooted-customize-hook=bash impossible.
|
||||||
|
# Making the $pid process group the foreground job will destroy all
|
||||||
|
# the signal handling we have set up for when the user presses
|
||||||
|
# ctrl+c in a terminal. Even if we fix the signal handling we now
|
||||||
|
# find ourselves in the opposite situation: the $pid process must
|
||||||
|
# now clean up the former main process tree reliably. And we cannot
|
||||||
|
# create a new process group for everything all-in-one because that
|
||||||
|
# would also destroy CTRL+C handling from the terminal.
|
||||||
warning "creating tarball failed: $@";
|
warning "creating tarball failed: $@";
|
||||||
kill HUP => -getpgrp();
|
my $pgroup = getpgrp();
|
||||||
|
warning "sending SIGHUP to all processes in process group $pgroup";
|
||||||
|
kill HUP => -$pgroup;
|
||||||
$exitstatus = 1;
|
$exitstatus = 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
error "unknown format: $format";
|
error "unknown format: $options->{format}";
|
||||||
}
|
}
|
||||||
close($rfh);
|
close($rfh);
|
||||||
waitpid $pid, 0;
|
waitpid $pid, 0;
|
||||||
|
@ -6184,9 +6303,10 @@ sub main() {
|
||||||
# change signal handler message
|
# change signal handler message
|
||||||
$waiting_for = "cleanup";
|
$waiting_for = "cleanup";
|
||||||
|
|
||||||
if (any { $_ eq $format } ('directory')) {
|
if (any { $_ eq $options->{format} } ('directory')) {
|
||||||
# nothing to do
|
# nothing to do
|
||||||
} elsif (any { $_ eq $format } ('tar', 'squashfs', 'ext2', 'null')) {
|
} elsif (any { $_ eq $options->{format} }
|
||||||
|
('tar', 'squashfs', 'ext2', 'null')) {
|
||||||
if (!-e $options->{root}) {
|
if (!-e $options->{root}) {
|
||||||
error "$options->{root} does not exist";
|
error "$options->{root} does not exist";
|
||||||
}
|
}
|
||||||
|
@ -6234,7 +6354,7 @@ sub main() {
|
||||||
error "unknown mode: $options->{mode}";
|
error "unknown mode: $options->{mode}";
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
error "unknown format: $format";
|
error "unknown format: $options->{format}";
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($got_signal) {
|
if ($got_signal) {
|
||||||
|
@ -6272,24 +6392,24 @@ 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. See section B<OPERATION> for an overview of how
|
||||||
B<mmdebstrap> works internally.
|
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 and I<SUITE> is not a stable release name,
|
||||||
If I<SUITE> is a stable release name and no I<MIRROR> is specified, then
|
L<http://deb.debian.org/debian> is used. If I<SUITE> is a stable release name
|
||||||
mirrors for updates and security are automatically added. If a I<MIRROR>
|
and no I<MIRROR> is specified, then mirrors for updates and security are
|
||||||
option starts with "deb " or "deb-src " then it is used as a one-line-style
|
automatically added. If a I<MIRROR> option starts with "deb " or "deb-src "
|
||||||
format entry for apt's sources.list inside the chroot. If a I<MIRROR> option
|
then it is used as a one-line-style format entry for apt's sources.list inside
|
||||||
contains a "://" then it is interpreted as a mirror URI and the apt line
|
the chroot. If a I<MIRROR> option contains a "://" then it is interpreted as a
|
||||||
inside the chroot is assembled as "deb [arch=A] B C D" where A is the host's
|
mirror URI and the apt line inside the chroot is assembled as "deb [arch=A] B C
|
||||||
native architecture, B is the I<MIRROR>, C is the given I<SUITE> and D is the
|
D" where A is the host's native architecture, B is the I<MIRROR>, C is the
|
||||||
components given via B<--components> (defaults to "main"). If a I<MIRROR>
|
given I<SUITE> and D is the components given via B<--components> (defaults to
|
||||||
option happens to be an existing file, then its contents are pasted into the
|
"main"). If a I<MIRROR> option happens to be an existing file, then its
|
||||||
chroot's sources.list. This can be used to supply a deb822 style
|
contents are pasted into the chroot's sources.list. This can be used to supply
|
||||||
sources.list. If I<MIRROR> is C<-> then standard input is pasted into the
|
a deb822 style sources.list. If I<MIRROR> is C<-> then standard input is pasted
|
||||||
chroot's sources.list. More than one mirror can be specified and are appended
|
into the chroot's sources.list. More than one mirror can be specified and are
|
||||||
to the chroot's sources.list in the given order. If you specify a https or tor
|
appended to the chroot's sources.list in the given order. If you specify a
|
||||||
I<MIRROR> and you want the chroot to be able to update itself, don't forget to
|
https or tor I<MIRROR> and you want the chroot to be able to update itself,
|
||||||
also install the ca-certificates package, the apt-transport-https package for
|
don't forget to also install the ca-certificates package, the
|
||||||
apt versions less than 1.5 and/or the apt-transport-tor package using the
|
apt-transport-https package for apt versions less than 1.5 and/or the
|
||||||
B<--include> option, as necessary.
|
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
|
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,
|
to a tarball filename, the path to a squashfs image, the path to an ext2 image,
|
||||||
|
@ -6573,6 +6693,10 @@ installed. At that point, the chroot directory does not contain any
|
||||||
executables and thus cannot be chroot-ed into. See section B<HOOKS> for more
|
executables and thus cannot be chroot-ed into. See section B<HOOKS> for more
|
||||||
information.
|
information.
|
||||||
|
|
||||||
|
Example: add additional apt sources entries on top of the default ones:
|
||||||
|
|
||||||
|
--setup-hook='echo "deb http..." > "$1"/etc/apt/sources.list.d/custom.list'
|
||||||
|
|
||||||
Example: Setup chroot for installing a sub-essential busybox-based chroot
|
Example: Setup chroot for installing a sub-essential busybox-based chroot
|
||||||
with --variant=custom
|
with --variant=custom
|
||||||
--include=dpkg,busybox,libc-bin,base-files,base-passwd,debianutils
|
--include=dpkg,busybox,libc-bin,base-files,base-passwd,debianutils
|
||||||
|
@ -6623,15 +6747,23 @@ Execute arbitrary I<command>s after the chroot is set up and all packages got
|
||||||
installed but before final cleanup actions are carried out. See section
|
installed but before final cleanup actions are carried out. See section
|
||||||
B<HOOKS> for more information.
|
B<HOOKS> for more information.
|
||||||
|
|
||||||
Example: Preparing a chroot for use with autopkgtest
|
Example: Add a user without a password
|
||||||
|
|
||||||
--customize-hook='chroot "$1" passwd --delete root'
|
|
||||||
--customize-hook='chroot "$1" useradd --home-dir /home/user
|
--customize-hook='chroot "$1" useradd --home-dir /home/user
|
||||||
--create-home user'
|
--create-home user'
|
||||||
--customize-hook='chroot "$1" passwd --delete user'
|
--customize-hook='chroot "$1" passwd --delete user'
|
||||||
|
|
||||||
|
Example: set up F</etc/hostname> and F</etc/hosts>
|
||||||
|
|
||||||
--customize-hook='echo host > "$1/etc/hostname"'
|
--customize-hook='echo host > "$1/etc/hostname"'
|
||||||
--customize-hook='echo "127.0.0.1 localhost host" > "$1/etc/hosts"'
|
--customize-hook='echo "127.0.0.1 localhost host" > "$1/etc/hosts"'
|
||||||
--customize-hook=/usr/share/autopkgtest/setup-commands/setup-testbed
|
|
||||||
|
Example: to mimic B<debootstrap> behaviour, B<mmdebstrap> copies from the host.
|
||||||
|
Remove them in a B<--customize-hook> to make the chroot reproducible across
|
||||||
|
multiple hosts:
|
||||||
|
|
||||||
|
--customize-hook='rm "$1"/etc/resolv.conf'
|
||||||
|
--customize-hook='rm "$1"/etc/hostname'
|
||||||
|
|
||||||
=item B<--hook-directory>=I<directory>
|
=item B<--hook-directory>=I<directory>
|
||||||
|
|
||||||
|
@ -6726,7 +6858,7 @@ This mode directly executes chroot and is the same mode of operation as is
|
||||||
used by debootstrap. It is the only mode that can directly create a directory
|
used by debootstrap. It is the only mode that can directly create a directory
|
||||||
chroot with the right permissions. If the chroot directory is not accessible
|
chroot with the right permissions. If the chroot directory is not accessible
|
||||||
by the _apt user, then apt sandboxing will be automatically disabled. This mode
|
by the _apt user, then apt sandboxing will be automatically disabled. This mode
|
||||||
needs to be able to mount and thus requires C<SYS_CAP_ADMIN>.
|
needs to be able to mount and thus requires C<CAP_SYS_ADMIN>.
|
||||||
|
|
||||||
=item B<unshare>
|
=item B<unshare>
|
||||||
|
|
||||||
|
@ -6967,9 +7099,9 @@ to all four of them. Any information specific to each hook is documented under
|
||||||
the specific hook options in the section B<OPTIONS>.
|
the specific hook options in the section B<OPTIONS>.
|
||||||
|
|
||||||
The options can be specified multiple times and the commands are executed in
|
The options can be specified multiple times and the commands are executed in
|
||||||
the order in which they are given on the command line. There are four
|
the order in which they are given on the command line. There are four different
|
||||||
different types of hook option arguments. If the argument passed to the hook
|
types of hook option arguments. If the argument passed to the hook option
|
||||||
option starts with C<copy-in>, C<copy-out>, C<tar-in>, C<tar-out>, C<upload> or
|
starts with C<copy-in>, C<copy-out>, C<tar-in>, C<tar-out>, C<upload> or
|
||||||
C<download> followed by a space, then the hook is interpreted as a special
|
C<download> followed by a space, then the hook is interpreted as a special
|
||||||
hook. Otherwise, if I<command> is an existing executable file from C<$PATH> or
|
hook. Otherwise, if I<command> is an existing executable file from C<$PATH> or
|
||||||
if I<command> does not contain any shell metacharacters, then I<command> is
|
if I<command> does not contain any shell metacharacters, then I<command> is
|
||||||
|
@ -6982,11 +7114,12 @@ C<APT_CONFIG> as written by mmdebstrap it can be found in the
|
||||||
C<MMDEBSTRAP_APT_CONFIG> environment variable. All environment variables set by
|
C<MMDEBSTRAP_APT_CONFIG> environment variable. All environment variables set by
|
||||||
the user are preserved, except for C<TMPDIR> which is cleared. See section
|
the user are preserved, except for C<TMPDIR> which is cleared. See section
|
||||||
B<TMPDIR>. Furthermore, C<MMDEBSTRAP_MODE> will store the mode set by
|
B<TMPDIR>. Furthermore, C<MMDEBSTRAP_MODE> will store the mode set by
|
||||||
B<--mode>, C<MMDEBSTRAP_HOOK> stores which hook is currently run (setup,
|
B<--mode>, C<MMDEBSTRAP_FORMAT> stores the format chosen by B<--format>,
|
||||||
extract, essential, customize), C<MMDEBSTRAP_ARGV0> stores the name of the
|
C<MMDEBSTRAP_HOOK> stores which hook is currently run (setup, extract,
|
||||||
binary with which B<mmdebstrap> was executed and C<MMDEBSTRAP_VERBOSITY> stores
|
essential, customize), C<MMDEBSTRAP_ARGV0> stores the name of the binary with
|
||||||
the numerical verbosity level (0 for no output, 1 for normal, 2 for verbose and
|
which B<mmdebstrap> was executed and C<MMDEBSTRAP_VERBOSITY> stores the
|
||||||
3 for debug output). The C<MMDEBSTRAP_INCLUDE> variable stores the list of
|
numerical verbosity level (0 for no output, 1 for normal, 2 for verbose and 3
|
||||||
|
for debug output). The C<MMDEBSTRAP_INCLUDE> variable stores the list of
|
||||||
packages, apt patterns or file paths given by the B<--include> option,
|
packages, apt patterns or file paths given by the B<--include> option,
|
||||||
separated by a comma and with commas and percent signs in the option values
|
separated by a comma and with commas and percent signs in the option values
|
||||||
urlencoded. If I<SUITE> name was supplied, it's stored in C<MMDEBSTRAP_SUITE>.
|
urlencoded. If I<SUITE> name was supplied, it's stored in C<MMDEBSTRAP_SUITE>.
|
||||||
|
@ -7035,7 +7168,9 @@ only update the content of an existing directory.
|
||||||
=item B<tar-in> I<outside.tar> I<pathinside>
|
=item B<tar-in> I<outside.tar> I<pathinside>
|
||||||
|
|
||||||
Unpacks a tarball I<outside.tar> from outside the chroot into a certain
|
Unpacks a tarball I<outside.tar> from outside the chroot into a certain
|
||||||
location I<pathinside> inside the chroot.
|
location I<pathinside> inside the chroot. In B<unshare> mode, device nodes
|
||||||
|
cannot be created. To ignore device nodes in tarballs, use
|
||||||
|
B<--skip=tar-in/mknod>.
|
||||||
|
|
||||||
=item B<tar-out> I<pathinside> I<outside.tar>
|
=item B<tar-out> I<pathinside> I<outside.tar>
|
||||||
|
|
||||||
|
@ -7248,10 +7383,21 @@ Performs cleanup tasks, unless B<--skip=cleanup> is used:
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
|
=item B<output>
|
||||||
|
|
||||||
For formats other than B<directory>, pack up the temporary chroot directory
|
For formats other than B<directory>, pack up the temporary chroot directory
|
||||||
into a tarball, ext2 image or squashfs image and delete the temporary chroot
|
into a tarball, ext2 image or squashfs image and delete the temporary chroot
|
||||||
directory.
|
directory.
|
||||||
|
|
||||||
|
If B<--skip=output/dev> is added, the resulting chroot will not contain the
|
||||||
|
device nodes, directories and symlinks that B<debootstrap> creates but just
|
||||||
|
an empty /dev as created by B<base-files>.
|
||||||
|
|
||||||
|
If B<--skip=output/mknod> is added, the resulting chroot will not contain
|
||||||
|
device nodes (neither block nor character special devices). This is useful
|
||||||
|
if the chroot tarball is to be exatracted in environments where mknod does
|
||||||
|
not function like in unshared user namespaces.
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
=head1 EXAMPLES
|
=head1 EXAMPLES
|
||||||
|
@ -7379,7 +7525,14 @@ sources on the current system:
|
||||||
--wildcards './usr/src/libdvd-pkg/libdvdcss2_*_*.deb'
|
--wildcards './usr/src/libdvd-pkg/libdvdcss2_*_*.deb'
|
||||||
$ ls libdvdcss2_*_*.deb
|
$ ls libdvdcss2_*_*.deb
|
||||||
|
|
||||||
Use as replacement for autopkgtest-build-qemu and vmdb2:
|
Use as replacement for autopkgtest-build-qemu and vmdb2 for all architectures
|
||||||
|
supporting EFI booting (amd64, arm64, armhf, i386, riscv64), use a convenience
|
||||||
|
wrapper around B<mmdebstrap>:
|
||||||
|
|
||||||
|
$ mmdebstrap-autopkgtest-build-qemu unstable ./autopkgtest.img
|
||||||
|
|
||||||
|
Use as replacement for autopkgtest-build-qemu and vmdb2 on architectures
|
||||||
|
supporting extlinux (amd64 and i386):
|
||||||
|
|
||||||
$ mmdebstrap --variant=important --include=linux-image-amd64 \
|
$ mmdebstrap --variant=important --include=linux-image-amd64 \
|
||||||
--customize-hook='chroot "$1" passwd --delete root' \
|
--customize-hook='chroot "$1" passwd --delete root' \
|
||||||
|
@ -7411,7 +7564,7 @@ As a debootstrap wrapper to run it without superuser privileges but using Linux
|
||||||
user namespaces instead. This fixes Debian bug #829134.
|
user namespaces instead. This fixes Debian bug #829134.
|
||||||
|
|
||||||
$ mmdebstrap --variant=custom --mode=unshare \
|
$ mmdebstrap --variant=custom --mode=unshare \
|
||||||
--setup-hook='env container=lxc debootstrap unstable "$1"' \
|
--setup-hook='debootstrap unstable "$1"' \
|
||||||
- debian-debootstrap.tar
|
- debian-debootstrap.tar
|
||||||
|
|
||||||
Build a non-Debian chroot like Ubuntu bionic:
|
Build a non-Debian chroot like Ubuntu bionic:
|
||||||
|
@ -7456,6 +7609,12 @@ Create a system that can be used with docker:
|
||||||
root
|
root
|
||||||
$ sudo docker rmi debian
|
$ sudo docker rmi debian
|
||||||
|
|
||||||
|
Create and boot a qemu virtual machine for an arbitrary architecture using
|
||||||
|
the B<debvm-create> wrapper script around B<mmdebstrap>:
|
||||||
|
|
||||||
|
$ debvm-create -r stable -- --architecture=riscv64
|
||||||
|
$ debvm-run
|
||||||
|
|
||||||
Create a system that can be used with podman:
|
Create a system that can be used with podman:
|
||||||
|
|
||||||
$ mmdebstrap unstable | podman import - debian
|
$ mmdebstrap unstable | podman import - debian
|
||||||
|
@ -7466,9 +7625,9 @@ Create a system that can be used with podman:
|
||||||
|
|
||||||
As a docker/podman replacement:
|
As a docker/podman replacement:
|
||||||
|
|
||||||
$ mmdebstrap unstable | mmtarfilter --path-exclude='/dev/*' > chroot.tar
|
$ mmdebstrap unstable chroot.tar
|
||||||
[...]
|
[...]
|
||||||
$ mmdebstrap --variant=custom --skip=update \
|
$ mmdebstrap --variant=custom --skip=update,tar-in/mknod \
|
||||||
--setup-hook='tar-in chroot.tar /' \
|
--setup-hook='tar-in chroot.tar /' \
|
||||||
--customize-hook='chroot "$1" whoami' unstable /dev/null
|
--customize-hook='chroot "$1" whoami' unstable /dev/null
|
||||||
[...]
|
[...]
|
||||||
|
@ -7481,8 +7640,8 @@ installed, then instead of downloading and installing the essential packages
|
||||||
twice you can instead build on top of the already present minimal chroot:
|
twice you can instead build on top of the already present minimal chroot:
|
||||||
|
|
||||||
$ mmdebstrap --variant=apt unstable chroot.tar
|
$ mmdebstrap --variant=apt unstable chroot.tar
|
||||||
$ mmdebstrap --variant=custom --setup-hook \
|
$ mmdebstrap --variant=custom --skip=update,setup,cleanup,tar-in/mknod \
|
||||||
'mmtarfilter "--path-exclude=/dev/*" < chroot.tar | tar -C "$1" -x' \
|
--setup-hook='tar-in chroot.tar /' \
|
||||||
--customize-hook='chroot "$1" apt-get install --yes pkg1 pkg2' \
|
--customize-hook='chroot "$1" apt-get install --yes pkg1 pkg2' \
|
||||||
'' chroot-full.tar
|
'' chroot-full.tar
|
||||||
|
|
||||||
|
|
109
mmdebstrap-autopkgtest-build-qemu
Normal file → Executable file
109
mmdebstrap-autopkgtest-build-qemu
Normal file → Executable file
|
@ -2,16 +2,111 @@
|
||||||
# Copyright 2023 Johannes Schauer Marin Rodrigues <josch@debian.org>
|
# Copyright 2023 Johannes Schauer Marin Rodrigues <josch@debian.org>
|
||||||
# Copyright 2023 Helmut Grohne <helmut@subdivi.de>
|
# Copyright 2023 Helmut Grohne <helmut@subdivi.de>
|
||||||
# SPDX-License-Identifier: MIT
|
# SPDX-License-Identifier: MIT
|
||||||
#
|
|
||||||
# This script is mostly compatible with autopkgtest-build-qemu as shipped in
|
|
||||||
# autopkgtest. Main differences:
|
|
||||||
# * It does not support any value for --boot but efi.
|
|
||||||
# * It uses different tools, most importantly swaps out vmdb2.
|
|
||||||
# * It can be run as non-root via user namespaces.
|
|
||||||
|
|
||||||
# We generally use single quotes to avoid variable expansion:
|
# We generally use single quotes to avoid variable expansion:
|
||||||
# shellcheck disable=SC2016
|
# shellcheck disable=SC2016
|
||||||
|
|
||||||
|
# Replacement for autopkgtest-build-qemu and vmdb2 for all architectures
|
||||||
|
# supporting EFI booting (amd64, arm64, armhf, i386, riscv64).
|
||||||
|
# For use as replacement for autopkgtest-build-qemu and vmdb2 on ppc64el which
|
||||||
|
# neither supports extlinux nor efi booting there is an unmaintained script
|
||||||
|
# which uses grub instead to boot:
|
||||||
|
#
|
||||||
|
# https://gitlab.mister-muffin.de/josch/mmdebstrap/src/commit/
|
||||||
|
# e523741610a4ed8579642bfc755956f64c847ef3/mmdebstrap-autopkgtest-build-qemu
|
||||||
|
|
||||||
|
: <<'POD2MAN'
|
||||||
|
=head1 NAME
|
||||||
|
|
||||||
|
mmdebstrap-autopkgtest-build-qemu - autopkgtest-build-qemu without vmdb2 but mmdebstrap and EFI boot
|
||||||
|
|
||||||
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
|
B<mmdebstrap-autopkgtest-build-qemu> [I<OPTIONS>] B<--boot>=B<efi> I<RELEASE> I<IMAGE>
|
||||||
|
|
||||||
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
|
B<mmdebstrap-autopkgtest-build-qemu> is a mostly compatible drop-in replacement
|
||||||
|
for B<autopkgtest-build-qemu>(1) with two main differences: Firstly, it uses
|
||||||
|
B<mmdebstrap>(1) instead of B<vmdb2>(1) and thus is able to create QEMU disk
|
||||||
|
images without requiring superuser privileges. Secondly, it uses
|
||||||
|
B<systemd-boot>(7) and thus only supports booting via EFI.
|
||||||
|
|
||||||
|
=head1 POSITIONAL PARAMETERS
|
||||||
|
|
||||||
|
=over 8
|
||||||
|
|
||||||
|
=item I<RELEASE>
|
||||||
|
|
||||||
|
The release to download from the I<MIRROR>. This parameter is required.
|
||||||
|
|
||||||
|
=item I<IMAGE>
|
||||||
|
|
||||||
|
The file to write, in raw format. This parameter is required.
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
=head1 OPTIONS
|
||||||
|
|
||||||
|
=over 8
|
||||||
|
|
||||||
|
=item B<--mirror>=I<MIRROR>
|
||||||
|
|
||||||
|
Specify which distribution to install. It defaults to
|
||||||
|
http://deb.debian.org/debian (i.e. Debian), but you can pass a mirror of any
|
||||||
|
Debian derivative.
|
||||||
|
|
||||||
|
=item B<--architecture>=I<ARCHITECTURE>
|
||||||
|
|
||||||
|
Set the architecture for the virtual machine image, specified as a B<dpkg>(1)
|
||||||
|
architecture. If omitted, the host architecture is assumed.
|
||||||
|
|
||||||
|
B<--arch>=I<ARCH> is an alias for this option.
|
||||||
|
|
||||||
|
=item B<--script>=I<SCRIPT>
|
||||||
|
|
||||||
|
Specifies a user script that will be called with the root filesystem of the
|
||||||
|
image as its first parameter. This script can them make any necesssary
|
||||||
|
modifications to the root filesystem.
|
||||||
|
|
||||||
|
The script must be a POSIX shell script, and should not depend on bash-specific
|
||||||
|
features. This script will be executed inside a B<chroot>(1) call in the
|
||||||
|
virtual machine root filesystem.
|
||||||
|
|
||||||
|
=item B<--size>=I<SIZE>
|
||||||
|
|
||||||
|
Specifies the image size for the virtual machine, defaulting to 25G.
|
||||||
|
|
||||||
|
=item B<--apt-proxy>=I<PROXY>
|
||||||
|
|
||||||
|
Specify an apt proxy to use in the virtual machine. By default, if you have
|
||||||
|
an apt proxy configured on the host, the virtual machine will automatically use
|
||||||
|
this, otherwise there is no default.
|
||||||
|
|
||||||
|
=item B<--boot>=B<efi>, B<--efi>
|
||||||
|
|
||||||
|
Select the way the generated image will expect to be booted. Unless you
|
||||||
|
explicitly select --boot=efi, operation will fail.
|
||||||
|
|
||||||
|
=item B<--keyring>=I<KEYRING>
|
||||||
|
|
||||||
|
Passes an additional B<--keyring> parameter to B<mmdebstrap>.
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
=head1 EXAMPLES
|
||||||
|
|
||||||
|
$ mmdebstrap-autopkgtest-build-qemu --boot=efi stable /path/to/debian-stable-i386.img i386
|
||||||
|
|
||||||
|
$ mmdebstrap-autopkgtest-build-qemu --boot=efi unstable /path/to/debian-unstable.img
|
||||||
|
|
||||||
|
=head1 SEE ALSO
|
||||||
|
|
||||||
|
B<autopkgtest-build-qemu>(1), B<autopkgtest-virt-qemu>(1), B<mmdebstrap>(1), B<autopkgtest>(1)
|
||||||
|
|
||||||
|
=cut
|
||||||
|
POD2MAN
|
||||||
|
|
||||||
set -eu
|
set -eu
|
||||||
|
|
||||||
die() {
|
die() {
|
||||||
|
@ -19,7 +114,7 @@ die() {
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
usage() {
|
usage() {
|
||||||
die "usage: $0 [--boot=|--architecture=|--apt-proxy=|--keyring=|--mirror=|--script=|--size=] <RELEASE> <IMAGE> [MIRROR] [ARCHITECTURE] [SCRIPT] [SIZE]"
|
die "usage: $0 [--architecture=|--apt-proxy=|--keyring=|--mirror=|--script=|--size=] --boot=efi <RELEASE> <IMAGE>"
|
||||||
}
|
}
|
||||||
usage_error() {
|
usage_error() {
|
||||||
echo "error: $*" 1>&2
|
echo "error: $*" 1>&2
|
||||||
|
|
66
tarfilter
66
tarfilter
|
@ -43,6 +43,29 @@ class PaxFilterAction(argparse.Action):
|
||||||
setattr(namespace, "paxfilter", items)
|
setattr(namespace, "paxfilter", items)
|
||||||
|
|
||||||
|
|
||||||
|
class TypeFilterAction(argparse.Action):
|
||||||
|
def __call__(self, parser, namespace, values, option_string=None):
|
||||||
|
items = getattr(namespace, "typefilter", [])
|
||||||
|
match values:
|
||||||
|
case "REGTYPE" | "0":
|
||||||
|
items.append(tarfile.REGTYPE)
|
||||||
|
case "LNKTYPE" | "1":
|
||||||
|
items.append(tarfile.LNKTYPE)
|
||||||
|
case "SYMTYPE" | "2":
|
||||||
|
items.append(tarfile.SYMTYPE)
|
||||||
|
case "CHRTYPE" | "3":
|
||||||
|
items.append(tarfile.CHRTYPE)
|
||||||
|
case "BLKTYPE" | "4":
|
||||||
|
items.append(tarfile.BLKTYPE)
|
||||||
|
case "DIRTYPE" | "5":
|
||||||
|
items.append(tarfile.DIRTYPE)
|
||||||
|
case "FIFOTYPE" | "6":
|
||||||
|
items.append(tarfile.FIFOTYPE)
|
||||||
|
case _:
|
||||||
|
raise ValueError("invalid type: %s" % values)
|
||||||
|
setattr(namespace, "typefilter", items)
|
||||||
|
|
||||||
|
|
||||||
class TransformAction(argparse.Action):
|
class TransformAction(argparse.Action):
|
||||||
def __call__(self, parser, namespace, values, option_string=None):
|
def __call__(self, parser, namespace, values, option_string=None):
|
||||||
items = getattr(namespace, "trans", [])
|
items = getattr(namespace, "trans", [])
|
||||||
|
@ -89,10 +112,11 @@ dpkg(1) for information on how these two options work in detail. To reuse the
|
||||||
exact same semantics as used by dpkg, paths must be given as /path and not as
|
exact same semantics as used by dpkg, paths must be given as /path and not as
|
||||||
./path even though they might be stored as such in the tarball.
|
./path even though they might be stored as such in the tarball.
|
||||||
|
|
||||||
Secondly, filter out unwanted pax extended headers. This is useful in cases
|
Secondly, filter out unwanted pax extended headers using --pax-exclude and
|
||||||
where a tool only accepts certain xattr prefixes. For example tar2sqfs only
|
--pax-include. This is useful in cases where a tool only accepts certain xattr
|
||||||
supports SCHILY.xattr.user.*, SCHILY.xattr.trusted.* and
|
prefixes. For example tar2sqfs only supports SCHILY.xattr.user.*,
|
||||||
SCHILY.xattr.security.* but not SCHILY.xattr.system.posix_acl_default.*.
|
SCHILY.xattr.trusted.* and SCHILY.xattr.security.* but not
|
||||||
|
SCHILY.xattr.system.posix_acl_default.*.
|
||||||
|
|
||||||
Both types of options use Unix shell-style wildcards:
|
Both types of options use Unix shell-style wildcards:
|
||||||
|
|
||||||
|
@ -101,10 +125,16 @@ Both types of options use Unix shell-style wildcards:
|
||||||
[seq] matches any character in seq
|
[seq] matches any character in seq
|
||||||
[!seq] matches any character not in seq
|
[!seq] matches any character not in seq
|
||||||
|
|
||||||
Thirdly, transform the path of tar members using a sed expression just as with
|
Thirdly, filter out files matching a specific tar archive member type using
|
||||||
|
--type-exclude. Valid type names are REGTYPE (regular file), LNKTYPE
|
||||||
|
(hardlink), SYMTYPE (symlink), CHRTYPE (character special), BLKTYPE (block
|
||||||
|
special), DIRTYPE (directory), FIFOTYPE (fifo) or their tar format flag value
|
||||||
|
(0-6, respectively).
|
||||||
|
|
||||||
|
Fourthly, transform the path of tar members using a sed expression just as with
|
||||||
GNU tar --transform.
|
GNU tar --transform.
|
||||||
|
|
||||||
Fourthly, strip leading directory components off of tar members. Just as with
|
Fifthly, strip leading directory components off of tar members. Just as with
|
||||||
GNU tar --strip-components, tar members that have less or equal components in
|
GNU tar --strip-components, tar members that have less or equal components in
|
||||||
their path are not passed through.
|
their path are not passed through.
|
||||||
|
|
||||||
|
@ -140,6 +170,15 @@ Lastly, shift user id and group id of each entry by the value given by the
|
||||||
help="Re-include a pax header after a previous exclusion. "
|
help="Re-include a pax header after a previous exclusion. "
|
||||||
"This option can be specified multiple times.",
|
"This option can be specified multiple times.",
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--type-exclude",
|
||||||
|
metavar="type",
|
||||||
|
action=TypeFilterAction,
|
||||||
|
help="Exclude certain member types by their type. Choose types either "
|
||||||
|
"by their name (REGTYPE, LNKTYPE, SYMTYPE, CHRTYPE, BLKTYPE, DIRTYPE, "
|
||||||
|
"FIFOTYPE) or by their tar format flag values (0-6, respectively). "
|
||||||
|
"This option can be specified multiple times.",
|
||||||
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--transform",
|
"--transform",
|
||||||
"--xform",
|
"--xform",
|
||||||
|
@ -164,6 +203,7 @@ Lastly, shift user id and group id of each entry by the value given by the
|
||||||
if (
|
if (
|
||||||
not hasattr(args, "pathfilter")
|
not hasattr(args, "pathfilter")
|
||||||
and not hasattr(args, "paxfilter")
|
and not hasattr(args, "paxfilter")
|
||||||
|
and not hasattr(args, "typefilter")
|
||||||
and not hasattr(args, "strip_components")
|
and not hasattr(args, "strip_components")
|
||||||
):
|
):
|
||||||
from shutil import copyfileobj
|
from shutil import copyfileobj
|
||||||
|
@ -207,14 +247,24 @@ Lastly, shift user id and group id of each entry by the value given by the
|
||||||
skip = True
|
skip = True
|
||||||
return skip
|
return skip
|
||||||
|
|
||||||
# starting with Python 3.8, the default format became PAX_FORMAT, so this
|
def type_filter_should_skip(member):
|
||||||
# is only for compatibility with older versions of Python 3
|
if not hasattr(args, "typefilter"):
|
||||||
|
return False
|
||||||
|
for t in args.typefilter:
|
||||||
|
if member.type == t:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
# starting with Python 3.8, the default format became PAX_FORMAT but we
|
||||||
|
# are still explicit here in case of future changes.
|
||||||
with tarfile.open(fileobj=sys.stdin.buffer, mode="r|*") as in_tar, tarfile.open(
|
with tarfile.open(fileobj=sys.stdin.buffer, mode="r|*") as in_tar, tarfile.open(
|
||||||
fileobj=sys.stdout.buffer, mode="w|", format=tarfile.PAX_FORMAT
|
fileobj=sys.stdout.buffer, mode="w|", format=tarfile.PAX_FORMAT
|
||||||
) as out_tar:
|
) as out_tar:
|
||||||
for member in in_tar:
|
for member in in_tar:
|
||||||
if path_filter_should_skip(member):
|
if path_filter_should_skip(member):
|
||||||
continue
|
continue
|
||||||
|
if type_filter_should_skip(member):
|
||||||
|
continue
|
||||||
if args.strip_components:
|
if args.strip_components:
|
||||||
comps = member.name.split("/")
|
comps = member.name.split("/")
|
||||||
# just as with GNU tar, archive members with less or equal
|
# just as with GNU tar, archive members with less or equal
|
||||||
|
|
|
@ -35,15 +35,8 @@ if [ -n "$AUTOPROXY" ] && [ -x "$AUTOPROXY" ] && [ -e /tmp/.auto-apt-proxy-0 ];
|
||||||
chmod 644 "$TMP_APT_CONFIG"
|
chmod 644 "$TMP_APT_CONFIG"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# debootstrap runs mount -t proc proc /proc which doesn't work in an unshared
|
|
||||||
# namespace on privileged docker (like salsaci), so mount /proc manually
|
|
||||||
# https://bugs.debian.org/1031222
|
|
||||||
# https://salsa.debian.org/installer-team/debootstrap/-/merge_requests/91
|
|
||||||
$prefix {{ CMD }} --variant=custom --mode={{ MODE }} \
|
$prefix {{ CMD }} --variant=custom --mode={{ MODE }} \
|
||||||
--setup-hook='env '"${AUTOPROXY:+APT_CONFIG='$TMP_APT_CONFIG'}"' container=lxc debootstrap --variant={{ VARIANT }} unstable "$1" {{ MIRROR }}' \
|
--setup-hook='env '"${AUTOPROXY:+APT_CONFIG='$TMP_APT_CONFIG'}"' debootstrap --variant={{ VARIANT }} unstable "$1" {{ MIRROR }}' \
|
||||||
--setup-hook='mount -o rbind /proc "$1/proc"' \
|
|
||||||
--setup-hook='chroot "$1" dpkg-reconfigure systemd || true' \
|
|
||||||
--setup-hook='umount --lazy "$1/proc"' \
|
|
||||||
- /tmp/debian-mm.tar {{ MIRROR }}
|
- /tmp/debian-mm.tar {{ MIRROR }}
|
||||||
if [ -n "$AUTOPROXY" ] && [ -x "$AUTOPROXY" ] && [ -e /tmp/.auto-apt-proxy-0 ]; then
|
if [ -n "$AUTOPROXY" ] && [ -x "$AUTOPROXY" ] && [ -e /tmp/.auto-apt-proxy-0 ]; then
|
||||||
rm "$TMP_APT_CONFIG"
|
rm "$TMP_APT_CONFIG"
|
||||||
|
|
|
@ -174,6 +174,13 @@ if [ "{{ VARIANT }}" = "-" ]; then
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# since debootstrap 1.0.133 there is no tzdata in the buildd variant and thus
|
||||||
|
# debootstrap creates its own /etc/localtime
|
||||||
|
if [ "{{ VARIANT }}" = "buildd" ]; then
|
||||||
|
[ "$(readlink /tmp/debian-{{ DIST }}-debootstrap/etc/localtime)" = /usr/share/zoneinfo/UTC ]
|
||||||
|
rm /tmp/debian-{{ DIST }}-debootstrap/etc/localtime
|
||||||
|
fi
|
||||||
|
|
||||||
# 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
|
||||||
|
|
||||||
|
|
35
tests/skip-output-dev
Normal file
35
tests/skip-output-dev
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
#!/bin/sh
|
||||||
|
set -eu
|
||||||
|
export LC_ALL=C.UTF-8
|
||||||
|
|
||||||
|
prefix=
|
||||||
|
if [ "$(id -u)" -eq 0 ] && [ "{{ MODE }}" != "root" ] && [ "{{ MODE }}" != "auto" ]; then
|
||||||
|
if ! id "${SUDO_USER:-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
|
||||||
|
useradd --home-dir "/home/${SUDO_USER:-user}" --create-home "${SUDO_USER:-user}"
|
||||||
|
fi
|
||||||
|
prefix="runuser -u ${SUDO_USER:-user} --"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# test this for both unshare and root mode because the code paths creating
|
||||||
|
# entries in /dev are different depending on whether mknod is available or not
|
||||||
|
$prefix {{ CMD }} --mode={{ MODE }} --variant=apt --skip=output/dev {{ DIST }} - {{ MIRROR }} | {
|
||||||
|
tar -t;
|
||||||
|
echo ./dev/console;
|
||||||
|
echo ./dev/fd;
|
||||||
|
echo ./dev/full;
|
||||||
|
echo ./dev/null;
|
||||||
|
echo ./dev/ptmx;
|
||||||
|
echo ./dev/pts/;
|
||||||
|
echo ./dev/random;
|
||||||
|
echo ./dev/shm/;
|
||||||
|
echo ./dev/stderr;
|
||||||
|
echo ./dev/stdin;
|
||||||
|
echo ./dev/stdout;
|
||||||
|
echo ./dev/tty;
|
||||||
|
echo ./dev/urandom;
|
||||||
|
echo ./dev/zero;
|
||||||
|
} | sort | diff -u tar1.txt -
|
30
tests/skip-output-mknod
Normal file
30
tests/skip-output-mknod
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
#!/bin/sh
|
||||||
|
set -eu
|
||||||
|
export LC_ALL=C.UTF-8
|
||||||
|
|
||||||
|
prefix=
|
||||||
|
if [ "$(id -u)" -eq 0 ] && [ "{{ MODE }}" != "root" ] && [ "{{ MODE }}" != "auto" ]; then
|
||||||
|
if ! id "${SUDO_USER:-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
|
||||||
|
useradd --home-dir "/home/${SUDO_USER:-user}" --create-home "${SUDO_USER:-user}"
|
||||||
|
fi
|
||||||
|
prefix="runuser -u ${SUDO_USER:-user} --"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# test this for both unshare and root mode because the code paths creating
|
||||||
|
# entries in /dev are different depending on whether mknod is available or not
|
||||||
|
$prefix {{ CMD }} --mode={{ MODE }} --variant=apt --skip=output/mknod \
|
||||||
|
{{ DIST }} - {{ MIRROR }} | {
|
||||||
|
tar -t;
|
||||||
|
echo ./dev/console;
|
||||||
|
echo ./dev/full;
|
||||||
|
echo ./dev/null;
|
||||||
|
echo ./dev/ptmx;
|
||||||
|
echo ./dev/random;
|
||||||
|
echo ./dev/tty;
|
||||||
|
echo ./dev/urandom;
|
||||||
|
echo ./dev/zero;
|
||||||
|
} | sort | diff -u tar1.txt -
|
28
tests/skip-tar-in-mknod
Normal file
28
tests/skip-tar-in-mknod
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
#!/bin/sh
|
||||||
|
set -eu
|
||||||
|
export LC_ALL=C.UTF-8
|
||||||
|
export SOURCE_DATE_EPOCH={{ SOURCE_DATE_EPOCH }}
|
||||||
|
|
||||||
|
[ {{ MODE }} = "unshare" ]
|
||||||
|
|
||||||
|
trap "rm -f /tmp/debian-chroot.tar" EXIT INT TERM
|
||||||
|
|
||||||
|
prefix=
|
||||||
|
if [ "$(id -u)" -eq 0 ] && [ "{{ MODE }}" != "root" ] && [ "{{ MODE }}" != "auto" ]; then
|
||||||
|
if ! id "${SUDO_USER:-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
|
||||||
|
useradd --home-dir "/home/${SUDO_USER:-user}" --create-home "${SUDO_USER:-user}"
|
||||||
|
fi
|
||||||
|
prefix="runuser -u ${SUDO_USER:-user} --"
|
||||||
|
fi
|
||||||
|
|
||||||
|
$prefix {{ CMD }} --mode={{ MODE }} --variant=custom \
|
||||||
|
--skip=update,setup,cleanup,tar-in/mknod \
|
||||||
|
--setup-hook='tar-in ./cache/mmdebstrap-{{ DIST }}-apt.tar /' \
|
||||||
|
'' /tmp/debian-chroot.tar
|
||||||
|
|
||||||
|
cmp ./cache/mmdebstrap-{{ DIST }}-apt.tar /tmp/debian-chroot.tar \
|
||||||
|
|| diffoscope ./cache/mmdebstrap-{{ DIST }}-apt.tar /tmp/debian-chroot.tar
|
|
@ -8,7 +8,7 @@ mkdir /tmp/root/real
|
||||||
run_testA() {
|
run_testA() {
|
||||||
echo content > /tmp/foo
|
echo content > /tmp/foo
|
||||||
# shellcheck disable=SC2094
|
# 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 '' 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 -r xs1; [ "$xs1" -eq 0 ]; read -r xs2; [ "$xs2" -eq 0 ]; }
|
||||||
echo content | diff -u - /tmp/root/real/foo
|
echo content | diff -u - /tmp/root/real/foo
|
||||||
|
|
|
@ -8,12 +8,12 @@ echo "MMDEBSTRAP_APT_CONFIG $MMDEBSTRAP_APT_CONFIG"
|
||||||
echo "$MMDEBSTRAP_HOOK" >> /tmp/hooks
|
echo "$MMDEBSTRAP_HOOK" >> /tmp/hooks
|
||||||
[ "$MMDEBSTRAP_MODE" = "root" ]
|
[ "$MMDEBSTRAP_MODE" = "root" ]
|
||||||
echo test-content $MMDEBSTRAP_HOOK > test
|
echo test-content $MMDEBSTRAP_HOOK > test
|
||||||
{{ CMD }} --hook-helper "$1" "$MMDEBSTRAP_MODE" "$MMDEBSTRAP_HOOK" env 1 upload test /test <&$MMDEBSTRAP_HOOKSOCK >&$MMDEBSTRAP_HOOKSOCK
|
{{ CMD }} --hook-helper "$1" "$MMDEBSTRAP_MODE" "$MMDEBSTRAP_HOOK" '' 1 upload test /test <&$MMDEBSTRAP_HOOKSOCK >&$MMDEBSTRAP_HOOKSOCK
|
||||||
rm test
|
rm test
|
||||||
echo "content inside chroot:"
|
echo "content inside chroot:"
|
||||||
cat "$1/test"
|
cat "$1/test"
|
||||||
[ "test-content $MMDEBSTRAP_HOOK" = "$(cat "$1/test")" ]
|
[ "test-content $MMDEBSTRAP_HOOK" = "$(cat "$1/test")" ]
|
||||||
{{ CMD }} --hook-helper "$1" "$MMDEBSTRAP_MODE" "$MMDEBSTRAP_HOOK" env 1 download /test test <&$MMDEBSTRAP_HOOKSOCK >&$MMDEBSTRAP_HOOKSOCK
|
{{ CMD }} --hook-helper "$1" "$MMDEBSTRAP_MODE" "$MMDEBSTRAP_HOOK" '' 1 download /test test <&$MMDEBSTRAP_HOOKSOCK >&$MMDEBSTRAP_HOOKSOCK
|
||||||
echo "content outside chroot:"
|
echo "content outside chroot:"
|
||||||
cat test
|
cat test
|
||||||
[ "test-content $MMDEBSTRAP_HOOK" = "$(cat test)" ]
|
[ "test-content $MMDEBSTRAP_HOOK" = "$(cat test)" ]
|
||||||
|
|
Loading…
Reference in a new issue