Instead of re-execing mmdebstrap under /bin/sh, use Text::ParseWords::shellwords

- saves a few PIDs
 - saves a bit of time because useless exec and fork is avoided
 - allows to run in pivoted chroots without mmdebstrap
This commit is contained in:
Johannes Schauer Marin Rodrigues 2022-11-08 13:02:47 +01:00
parent d2238c891b
commit eb54f6a23a
Signed by untrusted user: josch
GPG key ID: F2CBA5C78FBD83E1

View file

@ -45,6 +45,7 @@ use Term::ANSIColor;
use Socket; use Socket;
use Time::HiRes; use Time::HiRes;
use Math::BigInt; use Math::BigInt;
use Text::ParseWords;
use version; use version;
## no critic (InputOutput::RequireBriefOpen) ## no critic (InputOutput::RequireBriefOpen)
@ -1659,24 +1660,12 @@ sub run_hooks {
open(STDIN, '<&', $options->{hooksock}) open(STDIN, '<&', $options->{hooksock})
or error "cannot open STDIN: $!"; or error "cannot open STDIN: $!";
# we execute ourselves under sh to avoid having to # Text::ParseWords::shellwords does for perl what shlex
# implement a clever parser of the quoting used in $script # does for python
# for the filenames my @args = shellwords $script;
my $prefix = ""; hookhelper($options->{root}, $options->{mode}, $name,
if ($is_covering) { $options->{qemu}, $verbosity_level, @args);
$prefix exit 0;
= "$EXECUTABLE_NAME -MDevel::Cover=-silent,-nogcov ";
}
exec 'sh', '-c',
"$prefix$PROGRAM_NAME --hook-helper"
. " \"\$1\" \"\$2\" \"\$3\" \"\$4\" \"\$5\" $script",
'exec', $options->{root}, $options->{mode}, $name,
(
defined $options->{qemu}
? "qemu-$options->{qemu}"
: 'env',
$verbosity_level
);
} }
waitpid($pid, 0); waitpid($pid, 0);
$? == 0 or error "special hook failed with exit code $?"; $? == 0 or error "special hook failed with exit code $?";
@ -3176,16 +3165,12 @@ sub chrooted_realpath {
} }
sub hookhelper { sub hookhelper {
my ($root, $mode, $hook, $qemu, $verbosity, $command, @args) = @_;
$verbosity_level = $verbosity;
# 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
eval { eval {
my $root = $ARGV[1];
my $mode = $ARGV[2];
my $hook = $ARGV[3];
my $qemu = $ARGV[4];
$verbosity_level = $ARGV[5];
my $command = $ARGV[6];
my @cmdprefix = (); my @cmdprefix = ();
my @tarcmd = ( my @tarcmd = (
@ -3213,12 +3198,12 @@ sub hookhelper {
any { $_ eq $command } any { $_ eq $command }
('copy-in', 'tar-in', 'upload', 'sync-in') ('copy-in', 'tar-in', 'upload', 'sync-in')
) { ) {
if (scalar @ARGV < 9) { if (scalar @args < 2) {
error "$command needs at least one path on the" error "$command needs at least one path on the"
. " outside and the output path inside the chroot"; . " outside and the output path inside the chroot";
} }
my $outpath = $ARGV[-1]; my $outpath = pop @args;
for (my $i = 7 ; $i < $#ARGV ; $i++) { foreach my $file (@args) {
# the right argument for tar's --directory argument depends on # the right argument for tar's --directory argument depends on
# whether tar is called from inside the chroot or from the # whether tar is called from inside the chroot or from the
# outside # outside
@ -3288,20 +3273,17 @@ sub hookhelper {
# instruct the parent process to create a tarball of the # instruct the parent process to create a tarball of the
# requested path outside the chroot # requested path outside the chroot
debug "helper: sending mktar"; debug "helper: sending mktar";
print STDOUT ( print STDOUT (pack("n", length $file) . "mktar" . $file);
pack("n", length $ARGV[$i]) . "mktar" . $ARGV[$i]);
} elsif ($command eq 'sync-in') { } elsif ($command eq 'sync-in') {
# instruct the parent process to create a tarball of the # instruct the parent process to create a tarball of the
# content of the requested path outside the chroot # content of the requested path outside the chroot
debug "helper: sending mktac"; debug "helper: sending mktac";
print STDOUT ( print STDOUT (pack("n", length $file) . "mktac" . $file);
pack("n", length $ARGV[$i]) . "mktac" . $ARGV[$i]);
} elsif (any { $_ eq $command } ('upload', 'tar-in')) { } elsif (any { $_ eq $command } ('upload', 'tar-in')) {
# instruct parent process to open a tarball of the # instruct parent process to open a tarball of the
# requested path outside the chroot for reading # requested path outside the chroot for reading
debug "helper: sending openr"; debug "helper: sending openr";
print STDOUT ( print STDOUT (pack("n", length $file) . "openr" . $file);
pack("n", length $ARGV[$i]) . "openr" . $ARGV[$i]);
} else { } else {
error "unknown command: $command"; error "unknown command: $command";
} }
@ -3360,31 +3342,31 @@ sub hookhelper {
any { $_ eq $command } any { $_ eq $command }
('copy-out', 'tar-out', 'download', 'sync-out') ('copy-out', 'tar-out', 'download', 'sync-out')
) { ) {
if (scalar @ARGV < 9) { if (scalar @args < 2) {
error "$command needs at least one path inside the chroot and" error "$command needs at least one path inside the chroot and"
. " the output path on the outside"; . " the output path on the outside";
} }
my $outpath = $ARGV[-1]; my $outpath = pop @args;
for (my $i = 7 ; $i < $#ARGV ; $i++) { foreach my $file (@args) {
# the right argument for tar's --directory argument depends on # the right argument for tar's --directory argument depends on
# whether tar is called from inside the chroot or from the # whether tar is called from inside the chroot or from the
# outside # outside
my $directory; my $directory;
if ($hook eq 'setup') { if ($hook eq 'setup') {
# tar runs outside, so acquire the correct path # tar runs outside, so acquire the correct path
$directory = chrooted_realpath $root, $ARGV[$i]; $directory = chrooted_realpath $root, $file;
} elsif ( } elsif (
any { $_ eq $hook } any { $_ eq $hook }
('extract', 'essential', 'customize') ('extract', 'essential', 'customize')
) { ) {
if ($mode eq 'fakechroot') { if ($mode eq 'fakechroot') {
# tar will run inside the chroot # tar will run inside the chroot
$directory = $ARGV[$i]; $directory = $file;
} elsif ( } elsif (
any { $_ eq $mode } any { $_ eq $mode }
('root', 'chrootless', 'unshare') ('root', 'chrootless', 'unshare')
) { ) {
$directory = chrooted_realpath $root, $ARGV[$i]; $directory = chrooted_realpath $root, $file;
} else { } else {
error "unknown mode: $mode"; error "unknown mode: $mode";
} }
@ -3497,11 +3479,11 @@ sub hookhelper {
} }
sub hooklistener { sub hooklistener {
$verbosity_level = shift;
# 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
eval { eval {
$verbosity_level = $ARGV[1];
while (1) { while (1) {
# get the next message # get the next message
my $msg = "error"; my $msg = "error";
@ -4235,14 +4217,15 @@ sub main() {
umask 022; umask 022;
if (scalar @ARGV >= 7 && $ARGV[0] eq "--hook-helper") { if (scalar @ARGV >= 7 && $ARGV[0] eq "--hook-helper") {
hookhelper(); shift @ARGV; # shift off "--hook-helper"
hookhelper(@ARGV);
exit 0; exit 0;
} }
# this is the counterpart to --hook-helper and will receive and carry # this is the counterpart to --hook-helper and will receive and carry
# out its instructions # out its instructions
if (scalar @ARGV == 2 && $ARGV[0] eq "--hook-listener") { if (scalar @ARGV == 2 && $ARGV[0] eq "--hook-listener") {
hooklistener(); hooklistener($ARGV[1]);
exit 0; exit 0;
} }
@ -5812,11 +5795,8 @@ sub main() {
open(STDIN, '<&', $parentsock) open(STDIN, '<&', $parentsock)
or error "cannot open STDIN: $!"; or error "cannot open STDIN: $!";
my @prefix = (); hooklistener($verbosity_level);
if ($is_covering) { exit 0;
@prefix = ($EXECUTABLE_NAME, "-MDevel::Cover=-silent,-nogcov");
}
exec @prefix, $PROGRAM_NAME, "--hook-listener", $verbosity_level;
} }
waitpid($lpid, 0); waitpid($lpid, 0);
if ($? != 0) { if ($? != 0) {