fix mmdebstrap hanging if apt in download step failed (closes: #1017795)

This commit is contained in:
Johannes Schauer Marin Rodrigues 2022-08-30 21:55:57 +02:00
parent df2226fb25
commit 226f86fea9
Signed by untrusted user: josch
GPG key ID: F2CBA5C78FBD83E1
3 changed files with 60 additions and 34 deletions

View file

@ -323,3 +323,5 @@ Modes: root unshare
Needs-QEMU: true Needs-QEMU: true
Test: error-if-stdout-is-tty Test: error-if-stdout-is-tty
Test: variant-custom-timeout

View file

@ -979,46 +979,59 @@ sub run_apt_download_progress {
my $flags = fcntl($wfh, F_GETFD, 0) or error "fcntl F_GETFD: $!"; my $flags = fcntl($wfh, F_GETFD, 0) or error "fcntl F_GETFD: $!";
fcntl($wfh, F_SETFD, $flags & ~FD_CLOEXEC) or error "fcntl F_SETFD: $!"; fcntl($wfh, F_SETFD, $flags & ~FD_CLOEXEC) or error "fcntl F_SETFD: $!";
my $fd = fileno $wfh; my $fd = fileno $wfh;
# 2022-05-02, #debian-apt on OFTC, times in UTC+2 # run_apt_progress() can raise an exception which would leave this function
# 16:57 < josch> DonKult: how is -oDebug::pkgDpkgPm=1 -oDir::Log=/dev/null # without cleaning up the other thread we started, making mmdebstrap hang
# a "fancy no-op"? # in case run_apt_progress() fails -- so wrap this in eval() instead
# 11:52 < DonKult> josch: "fancy no-op" in sofar as it does nothing to the eval {
# system even through its not in a special mode ala # 2022-05-02, #debian-apt on OFTC, times in UTC+2
# simulation or download-only. It does all the things it # 16:57 < josch> DonKult: how is -oDebug::pkgDpkgPm=1
# normally does, except that it just prints the dpkg calls # -oDir::Log=/dev/null a "fancy no-op"?
# instead of execv() them which in practice amounts means # 11:52 < DonKult> josch: "fancy no-op" in sofar as it does nothing to
# it does nothing (the Dir::Log just prevents libapt from # the system even through its not in a special mode
# creating the /var/log/apt directories. As the code # ala simulation or download-only. It does all the
# creates them even if no logs will be placed there…). As # things it normally does, except that it just prints
# said, midterm an apt --print-install-packages or # the dpkg calls instead of execv() them which in
# something would be nice to avoid running everything. # practice amounts means it does nothing (the Dir::Log
run_apt_progress({ # just prevents libapt from creating the /var/log/apt
ARGV => [ # directories. As the code creates them even if no
'apt-get', # logs will be placed there…). As said, midterm an apt
'--yes', # --print-install-packages or something would be nice
'-oDebug::pkgDpkgPm=1', # to avoid running everything.
'-oDir::Log=/dev/null', run_apt_progress({
$options->{dryrun} ARGV => [
? '-oAPT::Get::Simulate=true' 'apt-get',
: ( '--yes',
"-oAPT::Keep-Fds::=$fd", '-oDebug::pkgDpkgPm=1',
"-oDPkg::Tools::options::'cat >&$fd'::InfoFD=$fd", '-oDir::Log=/dev/null',
"-oDpkg::Pre-Install-Pkgs::=cat >&$fd", $options->{dryrun}
# no need to lock the database if we are just downloading ? '-oAPT::Get::Simulate=true'
"-oDebug::NoLocking=1", : (
# no need for pty magic if we write no log "-oAPT::Keep-Fds::=$fd",
"-oDpkg::Use-Pty=0", "-oDPkg::Tools::options::'cat >&$fd'::InfoFD=$fd",
), "-oDpkg::Pre-Install-Pkgs::=cat >&$fd",
@{ $options->{APT_ARGV} }, # no need to lock the database if we are just downloading
], "-oDebug::NoLocking=1",
}); # no need for pty magic if we write no log
"-oDpkg::Use-Pty=0",
),
@{ $options->{APT_ARGV} },
],
});
};
my $err = '';
if ($@) {
$err = "apt download failed: $@";
}
# signal the child process that we are done # signal the child process that we are done
close $wfh; close $wfh;
# and then read from it what it got # and then read from it what it got
my @listofdebs = <$fh>; my @listofdebs = <$fh>;
close $fh; close $fh;
if ($? != 0) { if ($? != 0) {
error "status child failed"; $err = "status child failed";
}
if ($err) {
error $err;
} }
# remove trailing newlines # remove trailing newlines
chomp @listofdebs; chomp @listofdebs;

View file

@ -0,0 +1,11 @@
#!/bin/sh
set -eu
export LC_ALL=C.UTF-8
# mmdebstrap used to hang forever if apt in custom mode failed to resolve
# dependencies because a process died without cleaning up its children.
# https://bugs.debian.org/1017795
ret=0
{{ CMD }} --mode={{ MODE }} --variant=custom \
--include=this-package-does-not-exist {{ DIST }} /dev/null {{ MIRROR }} || ret=1
[ $ret -eq 1 ]