From 48498443e74b2a7e089709b954c50b7df374684b Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Tue, 13 Aug 2013 18:18:15 +0200 Subject: allow Pre-Install-Pkgs hooks to get info over an FD != stdin This adds ::InfoFD option alongside the ::Version one to request sending the information to the specified FD, by default it is STDIN as it was the case before. The environment variable APT_HOOK_INFO_FD contains the FD the data is on as a confirmation that the APT version used understood the request. Allowing the hook to choose the FD is needed/helpful e.g. for shellscripts which have a hard time accessing FDs above 9 (as >= 10 are usually used internally by them) Closes: #671728 --- apt-pkg/deb/dpkgpm.cc | 20 +++-- doc/apt.conf.5.xml | 13 ++- ...bug-712116-dpkg-pre-install-pkgs-hook-multiarch | 94 +++++++++++++--------- 3 files changed, 81 insertions(+), 46 deletions(-) diff --git a/apt-pkg/deb/dpkgpm.cc b/apt-pkg/deb/dpkgpm.cc index 959d06455..4b5467eff 100644 --- a/apt-pkg/deb/dpkgpm.cc +++ b/apt-pkg/deb/dpkgpm.cc @@ -382,24 +382,32 @@ bool pkgDPkgPM::RunScriptsWithPkgs(const char *Cnf) OptSec = "DPkg::Tools::Options::" + string(Opts->Value.c_str(),Pos); unsigned int Version = _config->FindI(OptSec+"::Version",1); + unsigned int InfoFD = _config->FindI(OptSec + "::InfoFD", STDIN_FILENO); // Create the pipes int Pipes[2]; if (pipe(Pipes) != 0) return _error->Errno("pipe","Failed to create IPC pipe to subprocess"); - SetCloseExec(Pipes[0],true); + if (InfoFD != (unsigned)Pipes[0]) + SetCloseExec(Pipes[0],true); + else + _config->Set("APT::Keep-Fds::", Pipes[0]); SetCloseExec(Pipes[1],true); - + // Purified Fork for running the script - pid_t Process = ExecFork(); + pid_t Process = ExecFork(); if (Process == 0) { // Setup the FDs - dup2(Pipes[0],STDIN_FILENO); + dup2(Pipes[0], InfoFD); SetCloseExec(STDOUT_FILENO,false); - SetCloseExec(STDIN_FILENO,false); + SetCloseExec(STDIN_FILENO,false); SetCloseExec(STDERR_FILENO,false); + string hookfd; + strprintf(hookfd, "%d", InfoFD); + setenv("APT_HOOK_INFO_FD", hookfd.c_str(), 1); + dpkgChrootDirectory(); const char *Args[4]; Args[0] = "/bin/sh"; @@ -409,6 +417,8 @@ bool pkgDPkgPM::RunScriptsWithPkgs(const char *Cnf) execv(Args[0],(char **)Args); _exit(100); } + if (InfoFD == (unsigned)Pipes[0]) + _config->Clear("APT::Keep-Fds", Pipes[0]); close(Pipes[0]); FILE *F = fdopen(Pipes[1],"w"); if (F == 0) diff --git a/doc/apt.conf.5.xml b/doc/apt.conf.5.xml index f5e1f966d..42119baa5 100644 --- a/doc/apt.conf.5.xml +++ b/doc/apt.conf.5.xml @@ -688,7 +688,8 @@ DPkg::Pre-Install-Pkgs {"/usr/sbin/dpkg-preconfigure --apt";}; options this must be specified in list notation. The commands are invoked in order using /bin/sh; should any fail APT will abort. APT will pass the filenames of all .deb files it is going to - install to the commands, one per line on standard input. + install to the commands, one per line on the requested file descriptor, defaulting + to standard input. Version 2 of this protocol dumps more information, including the protocol version, the APT configuration space and the packages, files @@ -700,7 +701,15 @@ DPkg::Pre-Install-Pkgs {"/usr/sbin/dpkg-preconfigure --apt";}; DPkg::Tools::options::cmd::Version accordingly, the default being version 1. If APT isn't supporting the requested version it will send the information in the highest version it has support for instead. - + + + The file descriptor to be used to send the information can be requested with + DPkg::Tools::options::cmd::InfoFD + which defaults to 0 for standard input and is available since + version 0.9.11. Support for the option can be detected by looking for the environment + variable APT_HOOK_INFO_FD which contains the number of the used + file descriptor as a confirmation. + diff --git a/test/integration/test-bug-712116-dpkg-pre-install-pkgs-hook-multiarch b/test/integration/test-bug-712116-dpkg-pre-install-pkgs-hook-multiarch index af65397ea..62355a6b5 100755 --- a/test/integration/test-bug-712116-dpkg-pre-install-pkgs-hook-multiarch +++ b/test/integration/test-bug-712116-dpkg-pre-install-pkgs-hook-multiarch @@ -26,95 +26,111 @@ hook='pre-install-pkgs' enablehookversion() { echo "#!/bin/sh -while read line; do +FD=0 +echo -n > ${hook}-v${1}.list +if [ -n \"${2}\" ]; then + FD=\$APT_HOOK_INFO_FD + if [ "\$FD" != \"${2}\" ]; then echo \"ERROR: Information is not on requested FD: \$FD != ${2}\" >> ${hook}-v${1}.list; fi +fi +while read ${hook}-v${1}.list" > ${hook}-v${1}.sh +done >> ${hook}-v${1}.list" > ${hook}-v${1}.sh chmod +x ${hook}-v${1}.sh echo "dpkg::${hook}:: \"./${hook}-v${1}.sh --foo -bar\"; DPkg::Tools::options::\"./${hook}-v${1}.sh\"::Version \"$1\";" > rootdir/etc/apt/apt.conf.d/hook-v$1 + if [ -n "$2" ]; then + echo "DPkg::Tools::options::\"./${hook}-v${1}.sh\"::InfoFD \"${2}\";" >> rootdir/etc/apt/apt.conf.d/hook-v$1 + fi } -enablehookversion 2 -enablehookversion 3 - observehook() { rm -f ${hook}-v2.list ${hook}-v3.list msgtest 'Observe hooks while' "$*" testsuccess --nomsg aptget "$@" -y --force-yes } -observehook install stuff -t stable -testfileequal "${hook}-v2.list" 'libsame - < 1 **CONFIGURE** +testrun() { + observehook install stuff -t stable + testfileequal "${hook}-v2.list" 'libsame - < 1 **CONFIGURE** toolkit - < 1 **CONFIGURE** stuff - < 1 **CONFIGURE**' -testfileequal "${hook}-v3.list" 'libsame - - none < 1 amd64 same **CONFIGURE** + testfileequal "${hook}-v3.list" 'libsame - - none < 1 amd64 same **CONFIGURE** toolkit - - none < 1 all foreign **CONFIGURE** stuff - - none < 1 amd64 none **CONFIGURE**' -observehook install stuff -t unstable -testfileequal "${hook}-v2.list" 'libsame 1 < 2 **CONFIGURE** + observehook install stuff -t unstable + testfileequal "${hook}-v2.list" 'libsame 1 < 2 **CONFIGURE** toolkit 1 < 2 **CONFIGURE** stuff 1 < 2 **CONFIGURE**' -testfileequal "${hook}-v3.list" 'libsame 1 amd64 same < 2 amd64 same **CONFIGURE** + testfileequal "${hook}-v3.list" 'libsame 1 amd64 same < 2 amd64 same **CONFIGURE** toolkit 1 all foreign < 2 amd64 foreign **CONFIGURE** stuff 1 amd64 none < 2 amd64 none **CONFIGURE**' -observehook install stuff:i386 -t unstable -testfileequal "${hook}-v2.list" 'stuff 2 > - **REMOVE** + observehook install stuff:i386 -t unstable + testfileequal "${hook}-v2.list" 'stuff 2 > - **REMOVE** libsame - < 2 **CONFIGURE** stuff - < 2 **CONFIGURE**' -testfileequal "${hook}-v3.list" 'stuff 2 amd64 none > - - none **REMOVE** + testfileequal "${hook}-v3.list" 'stuff 2 amd64 none > - - none **REMOVE** libsame - - none < 2 i386 same **CONFIGURE** stuff - - none < 2 i386 none **CONFIGURE**' -observehook remove libsame -testfileequal "${hook}-v2.list" 'libsame 2 > - **REMOVE**' -testfileequal "${hook}-v3.list" 'libsame 2 amd64 same > - - none **REMOVE**' + observehook remove libsame + testfileequal "${hook}-v2.list" 'libsame 2 > - **REMOVE**' + testfileequal "${hook}-v3.list" 'libsame 2 amd64 same > - - none **REMOVE**' -observehook install stuff:i386/stable libsame:i386/stable toolkit/stable -testfileequal "${hook}-v2.list" 'libsame 2 > 1 **CONFIGURE** + observehook install stuff:i386/stable libsame:i386/stable toolkit/stable + testfileequal "${hook}-v2.list" 'libsame 2 > 1 **CONFIGURE** toolkit 2 > 1 **CONFIGURE** stuff 2 > 1 **CONFIGURE**' -testfileequal "${hook}-v3.list" 'libsame 2 i386 same > 1 i386 same **CONFIGURE** + testfileequal "${hook}-v3.list" 'libsame 2 i386 same > 1 i386 same **CONFIGURE** toolkit 2 amd64 foreign > 1 all foreign **CONFIGURE** stuff 2 i386 none > 1 i386 none **CONFIGURE**' -observehook install 'libsame:*' -testfileequal "${hook}-v2.list" 'libsame 1 < 2 **CONFIGURE** + observehook install 'libsame:*' + testfileequal "${hook}-v2.list" 'libsame 1 < 2 **CONFIGURE** libsame - < 2 **CONFIGURE** toolkit 1 < 2 **CONFIGURE** stuff 1 < 2 **CONFIGURE**' -testfileequal "${hook}-v3.list" 'libsame 1 i386 same < 2 i386 same **CONFIGURE** + testfileequal "${hook}-v3.list" 'libsame 1 i386 same < 2 i386 same **CONFIGURE** libsame - - none < 2 amd64 same **CONFIGURE** toolkit 1 all foreign < 2 amd64 foreign **CONFIGURE** stuff 1 i386 none < 2 i386 none **CONFIGURE**' -observehook purge stuff:i386 'libsame:*' toolkit -testfileequal "${hook}-v2.list" 'libsame 2 > - **REMOVE** + observehook purge stuff:i386 'libsame:*' toolkit + testfileequal "${hook}-v2.list" 'libsame 2 > - **REMOVE** stuff 2 > - **REMOVE** libsame 2 > - **REMOVE** toolkit 2 > - **REMOVE**' -testfileequal "${hook}-v3.list" 'libsame 2 amd64 same > - - none **REMOVE** + testfileequal "${hook}-v3.list" 'libsame 2 amd64 same > - - none **REMOVE** stuff 2 i386 none > - - none **REMOVE** libsame 2 i386 same > - - none **REMOVE** toolkit 2 amd64 foreign > - - none **REMOVE**' -observehook install confpkg -testfileequal "${hook}-v2.list" 'confpkg - < 1 **CONFIGURE**' -testfileequal "${hook}-v3.list" 'confpkg - - none < 1 amd64 none **CONFIGURE**' + observehook install confpkg + testfileequal "${hook}-v2.list" 'confpkg - < 1 **CONFIGURE**' + testfileequal "${hook}-v3.list" 'confpkg - - none < 1 amd64 none **CONFIGURE**' + + observehook remove confpkg + testfileequal "${hook}-v2.list" 'confpkg 1 > - **REMOVE**' + testfileequal "${hook}-v3.list" 'confpkg 1 amd64 none > - - none **REMOVE**' -observehook remove confpkg -testfileequal "${hook}-v2.list" 'confpkg 1 > - **REMOVE**' -testfileequal "${hook}-v3.list" 'confpkg 1 amd64 none > - - none **REMOVE**' + msgtest 'Conffiles of package remained after remove' 'confpkg' + dpkg -l confpkg | grep -q '^rc' && msgpass || msgfail -msgtest 'Conffiles of package remained after remove' 'confpkg' -dpkg -l confpkg | grep -q '^rc' && msgpass || msgfail + observehook purge confpkg + testfileequal "${hook}-v2.list" 'confpkg 1 > - **REMOVE**' + testfileequal "${hook}-v3.list" 'confpkg 1 amd64 none > - - none **REMOVE**' -observehook purge confpkg -testfileequal "${hook}-v2.list" 'confpkg 1 > - **REMOVE**' -testfileequal "${hook}-v3.list" 'confpkg 1 amd64 none > - - none **REMOVE**' + msgtest 'Conffiles are gone after purge' 'confpkg' + dpkg -l confpkg 2>/dev/null | grep -q '^rc' && msgfail || msgpass +} + +enablehookversion 2 +enablehookversion 3 +testrun -msgtest 'Conffiles are gone after purge' 'confpkg' -dpkg -l confpkg 2>/dev/null | grep -q '^rc' && msgfail || msgpass +enablehookversion 2 13 +enablehookversion 3 13 +testrun -- cgit v1.2.3