From ac210742432c271f1e3616cde6a05a57abc468f5 Mon Sep 17 00:00:00 2001 From: Johannes 'josch' Schauer Date: Sat, 9 Jan 2021 19:41:59 +0100 Subject: [PATCH] set MMDEBSTRAP_APT_CONFIG, MMDEBSTRAP_MODE and MMDEBSTRAP_HOOKSOCK for hook scripts --- coverage.sh | 46 +++++++++++++++++++++++++++++++++++++++++++++- mmdebstrap | 35 ++++++++++++++++++++++++++++++++--- 2 files changed, 77 insertions(+), 4 deletions(-) diff --git a/coverage.sh b/coverage.sh index d86c84e..66bae72 100755 --- a/coverage.sh +++ b/coverage.sh @@ -119,7 +119,7 @@ if [ ! -e shared/hooks/eatmydata/customize.sh ] || [ hooks/eatmydata/customize.s fi fi starttime= -total=170 +total=171 skipped=0 runtests=0 i=1 @@ -2188,6 +2188,50 @@ else runtests=$((runtests+1)) fi +print_header "mode=root,variant=apt: test special hooks using helpers" +cat << END > shared/test.sh +#!/bin/sh +set -eu +export LC_ALL=C.UTF-8 +cat << 'SCRIPT' > /tmp/script.sh +#!/bin/sh +set -eu +echo "MMDEBSTRAP_APT_CONFIG \$MMDEBSTRAP_APT_CONFIG" +[ "\$MMDEBSTRAP_MODE" = "root" ] +echo test-content \$2 > test +$CMD --hook-helper "\$1" "\$MMDEBSTRAP_MODE" "\$2" env 1 upload test /test <&\$MMDEBSTRAP_HOOKSOCK >&\$MMDEBSTRAP_HOOKSOCK +rm test +echo "content inside chroot:" +cat "\$1/test" +[ "test-content \$2" = "\$(cat "\$1/test")" ] +$CMD --hook-helper "\$1" "\$MMDEBSTRAP_MODE" "\$2" env 1 download /test test <&\$MMDEBSTRAP_HOOKSOCK >&\$MMDEBSTRAP_HOOKSOCK +echo "content outside chroot:" +cat test +[ "test-content \$2" = "\$(cat test)" ] +rm test +SCRIPT +chmod +x /tmp/script.sh +for h in setup extract essential customize; do + printf '#!/bin/sh\nset -eu\nexec /tmp/script.sh "\$1" "'"\$h"'"' > "/tmp/\$h.sh" + chmod +x "/tmp/\$h.sh" +done +$CMD --mode=root --variant=apt \ + --setup-hook=/tmp/setup.sh \ + --extract-hook=/tmp/extract.sh \ + --essential-hook=/tmp/essential.sh \ + --customize-hook=/tmp/customize.sh \ + $DEFAULT_DIST /tmp/debian-chroot $mirror +rm /tmp/script.sh /tmp/setup.sh /tmp/extract.sh /tmp/essential.sh /tmp/customize.sh +rm -r /tmp/debian-chroot +END +if [ "$HAVE_QEMU" = "yes" ]; then + ./run_qemu.sh + runtests=$((runtests+1)) +else + ./run_null.sh SUDO + runtests=$((runtests+1)) +fi + # test special hooks for mode in root unshare fakechroot proot; do print_header "mode=$mode,variant=apt: test special hooks with $mode mode" diff --git a/mmdebstrap b/mmdebstrap index a657bc4..b4a67fa 100755 --- a/mmdebstrap +++ b/mmdebstrap @@ -1188,6 +1188,28 @@ sub run_hooks { return; } + my @env_opts = (); + # There is no need to unset TMPDIR because we already have set it ourselves + # to "$options->{root}/tmp" in run_setup(). This is to have a writable + # TMPDIR even in unshare mode. + # + # The APT_CONFIG variable, if set, will confuse any manual calls to + # apt-get. If you want to use the same config used by mmdebstrap, the + # original value is stored in MMDEBSTRAP_APT_CONFIG. + if (defined $ENV{APT_CONFIG} && $ENV{APT_CONFIG} ne "") { + push @env_opts, '--unset=APT_CONFIG'; + } + if (defined $ENV{APT_CONFIG} && $ENV{APT_CONFIG} ne "") { + push @env_opts, "MMDEBSTRAP_APT_CONFIG=$ENV{APT_CONFIG}"; + } + # Storing the mode is important for hook scripts to potentially change + # their behavior depending on the mode. It's also important for when the + # hook wants to use the mmdebstrap --hook-helper. + push @env_opts, "MMDEBSTRAP_MODE=$options->{mode}"; + # This is the file descriptor of the socket that the mmdebstrap + # --hook-helper can write to and read from to communicate with the outside. + push @env_opts, ("MMDEBSTRAP_HOOKSOCK=" . fileno($options->{hooksock})); + my $runner = sub { foreach my $script (@{ $options->{"${name}_hook"} }) { if ( @@ -1246,20 +1268,25 @@ sub run_hooks { # execute it directly if it's an executable file # or if it there are no shell metacharacters # (the /a regex modifier makes \w match only ASCII) - 0 == system('env', '--unset=TMPDIR', '--unset=APT_CONFIG', - $script, $options->{root}) + 0 == system('env', @env_opts, $script, $options->{root}) or error "command failed: $script"; } else { info "running --$name-hook in shell: sh -c '$script' exec" . " $options->{root}"; # otherwise, wrap everything in sh -c - 0 == system('env', '--unset=TMPDIR', '--unset=APT_CONFIG', + 0 == system('env', @env_opts, 'sh', '-c', $script, 'exec', $options->{root}) or error "command failed: $script"; } } }; + # Unset the close-on-exec flag, so that the file descriptor does not + # get closed when we exec + my $flags = fcntl($options->{hooksock}, F_GETFD, 0) + or error "fcntl F_GETFD: $!"; + fcntl($options->{hooksock}, F_SETFD, $flags & ~FD_CLOEXEC) + or error "fcntl F_SETFD: $!"; if ($name eq 'setup') { # execute directly without mounting anything (the mount points do not # exist yet) @@ -1267,6 +1294,8 @@ sub run_hooks { } else { run_chroot(\&$runner, $options); } + # Restore flags + fcntl($options->{hooksock}, F_SETFD, $flags) or error "fcntl F_SETFD: $!"; return; }