From 8d6d3f00b14217e69ecabd68379b1e29bf4a3ccd Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Tue, 15 Sep 2015 12:44:53 +0200 Subject: [PATCH] implement a public pkgSystem::MultiArchSupported Some codepaths need to check if the system (in our case usually dpkg) supports MultiArch or not. We had copy-pasted the check so far into these paths, but having it as a system check is better for reusability. --- apt-pkg/deb/debsystem.cc | 93 ++++++++++++++++++++++++++++++++++++++++ apt-pkg/deb/debsystem.h | 5 +++ apt-pkg/deb/dpkgpm.cc | 92 +++++---------------------------------- apt-pkg/pkgsystem.cc | 9 ++++ apt-pkg/pkgsystem.h | 13 ++++++ cmdline/apt-mark.cc | 37 +--------------- 6 files changed, 131 insertions(+), 118 deletions(-) diff --git a/apt-pkg/deb/debsystem.cc b/apt-pkg/deb/debsystem.cc index 465e13b9e..5353761fc 100644 --- a/apt-pkg/deb/debsystem.cc +++ b/apt-pkg/deb/debsystem.cc @@ -22,6 +22,8 @@ #include #include +#include + #include #include #include @@ -30,6 +32,10 @@ #include #include #include +#include +#include +#include +#include #include /*}}}*/ @@ -250,3 +256,90 @@ bool debSystem::FindIndex(pkgCache::PkgFileIterator File, return false; } /*}}}*/ + +std::string debSystem::GetDpkgExecutable() /*{{{*/ +{ + string Tmp = _config->Find("Dir::Bin::dpkg","dpkg"); + string const dpkgChrootDir = _config->FindDir("DPkg::Chroot-Directory", "/"); + size_t dpkgChrootLen = dpkgChrootDir.length(); + if (dpkgChrootDir != "/" && Tmp.find(dpkgChrootDir) == 0) + { + if (dpkgChrootDir[dpkgChrootLen - 1] == '/') + --dpkgChrootLen; + Tmp = Tmp.substr(dpkgChrootLen); + } + return Tmp; +} + /*}}}*/ +std::vector debSystem::GetDpkgBaseCommand() /*{{{*/ +{ + // Generate the base argument list for dpkg + std::vector Args = { GetDpkgExecutable() }; + // Stick in any custom dpkg options + Configuration::Item const *Opts = _config->Tree("DPkg::Options"); + if (Opts != 0) + { + Opts = Opts->Child; + for (; Opts != 0; Opts = Opts->Next) + { + if (Opts->Value.empty() == true) + continue; + Args.push_back(Opts->Value); + } + } + return Args; +} + /*}}}*/ +void debSystem::DpkgChrootDirectory() /*{{{*/ +{ + std::string const chrootDir = _config->FindDir("DPkg::Chroot-Directory"); + if (chrootDir == "/") + return; + std::cerr << "Chrooting into " << chrootDir << std::endl; + if (chroot(chrootDir.c_str()) != 0) + _exit(100); + if (chdir("/") != 0) + _exit(100); +} + /*}}}*/ +bool debSystem::SupportsMultiArch() /*{{{*/ +{ + // Generate the base argument list for dpkg + std::vector const Args = GetDpkgBaseCommand(); + std::vector cArgs(Args.size(), NULL); + std::transform(Args.begin(), Args.end(), cArgs.begin(), [](std::string const &s) { return s.c_str(); }); + + // we need to detect if we can qualify packages with the architecture or not + cArgs.push_back("--assert-multi-arch"); + cArgs.push_back(NULL); + + pid_t dpkgAssertMultiArch = ExecFork(); + if (dpkgAssertMultiArch == 0) + { + DpkgChrootDirectory(); + // redirect everything to the ultimate sink as we only need the exit-status + int const nullfd = open("/dev/null", O_RDONLY); + dup2(nullfd, STDIN_FILENO); + dup2(nullfd, STDOUT_FILENO); + dup2(nullfd, STDERR_FILENO); + execvp(cArgs[0], (char**) &cArgs[0]); + _error->WarningE("dpkgGo", "Can't detect if dpkg supports multi-arch!"); + _exit(2); + } + + if (dpkgAssertMultiArch > 0) + { + int Status = 0; + while (waitpid(dpkgAssertMultiArch, &Status, 0) != dpkgAssertMultiArch) + { + if (errno == EINTR) + continue; + _error->WarningE("dpkgGo", _("Waited for %s but it wasn't there"), "dpkg --assert-multi-arch"); + break; + } + if (WIFEXITED(Status) == true && WEXITSTATUS(Status) == 0) + return true; + } + return false; +} + /*}}}*/ diff --git a/apt-pkg/deb/debsystem.h b/apt-pkg/deb/debsystem.h index aed77520e..521552ef4 100644 --- a/apt-pkg/deb/debsystem.h +++ b/apt-pkg/deb/debsystem.h @@ -45,6 +45,11 @@ class debSystem : public pkgSystem debSystem(); virtual ~debSystem(); + + APT_HIDDEN static std::string GetDpkgExecutable(); + APT_HIDDEN static std::vector GetDpkgBaseCommand(); + APT_HIDDEN static void DpkgChrootDirectory(); + APT_HIDDEN static bool SupportsMultiArch(); }; extern debSystem debSys; diff --git a/apt-pkg/deb/dpkgpm.cc b/apt-pkg/deb/dpkgpm.cc index 7a0253383..3ec8b2d60 100644 --- a/apt-pkg/deb/dpkgpm.cc +++ b/apt-pkg/deb/dpkgpm.cc @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -162,35 +163,6 @@ ionice(int PID) return ExecWait(Process, "ionice"); } -static std::string getDpkgExecutable() -{ - string Tmp = _config->Find("Dir::Bin::dpkg","dpkg"); - string const dpkgChrootDir = _config->FindDir("DPkg::Chroot-Directory", "/"); - size_t dpkgChrootLen = dpkgChrootDir.length(); - if (dpkgChrootDir != "/" && Tmp.find(dpkgChrootDir) == 0) - { - if (dpkgChrootDir[dpkgChrootLen - 1] == '/') - --dpkgChrootLen; - Tmp = Tmp.substr(dpkgChrootLen); - } - return Tmp; -} - -// dpkgChrootDirectory - chrooting for dpkg if needed /*{{{*/ -static void dpkgChrootDirectory() -{ - std::string const chrootDir = _config->FindDir("DPkg::Chroot-Directory"); - if (chrootDir == "/") - return; - std::cerr << "Chrooting into " << chrootDir << std::endl; - if (chroot(chrootDir.c_str()) != 0) - _exit(100); - if (chdir("/") != 0) - _exit(100); -} - /*}}}*/ - - // FindNowVersion - Helper to find a Version in "now" state /*{{{*/ // --------------------------------------------------------------------- /* This is helpful when a package is no longer installed but has residual @@ -466,7 +438,7 @@ bool pkgDPkgPM::RunScriptsWithPkgs(const char *Cnf) strprintf(hookfd, "%d", InfoFD); setenv("APT_HOOK_INFO_FD", hookfd.c_str(), 1); - dpkgChrootDirectory(); + debSystem::DpkgChrootDirectory(); const char *Args[4]; Args[0] = "/bin/sh"; Args[1] = "-c"; @@ -1225,44 +1197,13 @@ bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress) d->progress = progress; // Generate the base argument list for dpkg - unsigned long StartSize = 0; - std::vector Args; - std::string DpkgExecutable = getDpkgExecutable(); - Args.push_back(DpkgExecutable.c_str()); - StartSize += DpkgExecutable.length(); - - // Stick in any custom dpkg options - Configuration::Item const *Opts = _config->Tree("DPkg::Options"); - if (Opts != 0) - { - Opts = Opts->Child; - for (; Opts != 0; Opts = Opts->Next) - { - if (Opts->Value.empty() == true) - continue; - Args.push_back(Opts->Value.c_str()); - StartSize += Opts->Value.length(); - } - } - + std::vector const sArgs = debSystem::GetDpkgBaseCommand(); + std::vector Args(sArgs.size(), NULL); + std::transform(sArgs.begin(), sArgs.end(), Args.begin(), + [](std::string const &s) { return s.c_str(); }); + unsigned long long const StartSize = std::accumulate(sArgs.begin(), sArgs.end(), 0, + [](unsigned long long const i, std::string const &s) { return i + s.length(); }); size_t const BaseArgs = Args.size(); - // we need to detect if we can qualify packages with the architecture or not - Args.push_back("--assert-multi-arch"); - Args.push_back(NULL); - - pid_t dpkgAssertMultiArch = ExecFork(); - if (dpkgAssertMultiArch == 0) - { - dpkgChrootDirectory(); - // redirect everything to the ultimate sink as we only need the exit-status - int const nullfd = open("/dev/null", O_RDONLY); - dup2(nullfd, STDIN_FILENO); - dup2(nullfd, STDOUT_FILENO); - dup2(nullfd, STDERR_FILENO); - execvp(Args[0], (char**) &Args[0]); - _error->WarningE("dpkgGo", "Can't detect if dpkg supports multi-arch!"); - _exit(2); - } fd_set rfds; struct timespec tv; @@ -1298,20 +1239,7 @@ bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress) // create log OpenLog(); - bool dpkgMultiArch = false; - if (dpkgAssertMultiArch > 0) - { - int Status = 0; - while (waitpid(dpkgAssertMultiArch, &Status, 0) != dpkgAssertMultiArch) - { - if (errno == EINTR) - continue; - _error->WarningE("dpkgGo", _("Waited for %s but it wasn't there"), "dpkg --assert-multi-arch"); - break; - } - if (WIFEXITED(Status) == true && WEXITSTATUS(Status) == 0) - dpkgMultiArch = true; - } + bool dpkgMultiArch = debSystem::SupportsMultiArch(); // start pty magic before the loop StartPtyMagic(); @@ -1528,7 +1456,7 @@ bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress) SetupSlavePtyMagic(); close(fd[0]); // close the read end of the pipe - dpkgChrootDirectory(); + debSystem::DpkgChrootDirectory(); if (chdir(_config->FindDir("DPkg::Run-Directory","/").c_str()) != 0) _exit(100); diff --git a/apt-pkg/pkgsystem.cc b/apt-pkg/pkgsystem.cc index a6b61e655..2a0fc9d3b 100644 --- a/apt-pkg/pkgsystem.cc +++ b/apt-pkg/pkgsystem.cc @@ -12,6 +12,7 @@ // Include Files /*{{{*/ #include +#include #include #include @@ -46,5 +47,13 @@ APT_PURE pkgSystem *pkgSystem::GetSystem(const char *Label) return 0; } /*}}}*/ +bool pkgSystem::MultiArchSupported() const /*{{{*/ +{ + debSystem const * const deb = dynamic_cast(this); + if (deb != NULL) + return deb->SupportsMultiArch(); + return true; +} + /*}}}*/ pkgSystem::~pkgSystem() {} diff --git a/apt-pkg/pkgsystem.h b/apt-pkg/pkgsystem.h index 5b31457e0..c7de63c87 100644 --- a/apt-pkg/pkgsystem.h +++ b/apt-pkg/pkgsystem.h @@ -92,6 +92,19 @@ class pkgSystem return 0; }; + //FIXME: these methods should be virtual + /** does this system has support for MultiArch? + * + * Systems supporting only single arch (not systems which are single arch) + * are considered legacy systems and support for it will likely degrade over + * time. + * + * The default implementation returns always \b true. + * + * @return \b true if the system supports MultiArch, \b false if not. + */ + bool MultiArchSupported() const; + pkgSystem(char const * const Label, pkgVersioningSystem * const VS); virtual ~pkgSystem(); private: diff --git a/cmdline/apt-mark.cc b/cmdline/apt-mark.cc index 02c73fc2e..20166b312 100644 --- a/cmdline/apt-mark.cc +++ b/cmdline/apt-mark.cc @@ -201,28 +201,7 @@ static bool DoHold(CommandLine &CmdL) Args.push_back(Opts->Value.c_str()); } } - size_t const BaseArgs = Args.size(); - // we need to detect if we can qualify packages with the architecture or not - Args.push_back("--assert-multi-arch"); - Args.push_back(NULL); - - - pid_t dpkgAssertMultiArch = ExecFork(); - if (dpkgAssertMultiArch == 0) - { - std::string const chrootDir = _config->FindDir("DPkg::Chroot-Directory"); - // redirect everything to the ultimate sink as we only need the exit-status - int const nullfd = open("/dev/null", O_RDONLY); - dup2(nullfd, STDIN_FILENO); - dup2(nullfd, STDOUT_FILENO); - dup2(nullfd, STDERR_FILENO); - if (chrootDir != "/" && chroot(chrootDir.c_str()) != 0 && chdir("/") != 0) - _error->WarningE("getArchitecture", "Couldn't chroot into %s for dpkg --assert-multi-arch", chrootDir.c_str()); - execvp(Args[0], (char**) &Args[0]); - _error->WarningE("dpkgGo", "Can't detect if dpkg supports multi-arch!"); - _exit(2); - } APT::PackageList pkgset = APT::PackageList::FromCommandLine(CacheFile, CmdL.FileList + 1); if (pkgset.empty() == true) @@ -244,21 +223,6 @@ static bool DoHold(CommandLine &CmdL) ++Pkg; } - bool dpkgMultiArch = false; - if (dpkgAssertMultiArch > 0) - { - int Status = 0; - while (waitpid(dpkgAssertMultiArch, &Status, 0) != dpkgAssertMultiArch) - { - if (errno == EINTR) - continue; - _error->WarningE("dpkgGo", _("Waited for %s but it wasn't there"), "dpkg --assert-multi-arch"); - break; - } - if (WIFEXITED(Status) == true && WEXITSTATUS(Status) == 0) - dpkgMultiArch = true; - } - if (pkgset.empty() == true) return true; @@ -359,6 +323,7 @@ static bool DoHold(CommandLine &CmdL) _exit(2); } + bool const dpkgMultiArch = _system->MultiArchSupported(); FILE* dpkg = fdopen(external[1], "w"); for (APT::PackageList::iterator Pkg = pkgset.begin(); Pkg != pkgset.end(); ++Pkg) { -- 2.45.2