]> git.saurik.com Git - apt.git/commitdiff
implement a public pkgSystem::MultiArchSupported
authorDavid Kalnischkies <david@kalnischkies.de>
Tue, 15 Sep 2015 10:44:53 +0000 (12:44 +0200)
committerDavid Kalnischkies <david@kalnischkies.de>
Wed, 4 Nov 2015 14:02:36 +0000 (15:02 +0100)
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
apt-pkg/deb/debsystem.h
apt-pkg/deb/dpkgpm.cc
apt-pkg/pkgsystem.cc
apt-pkg/pkgsystem.h
cmdline/apt-mark.cc

index 465e13b9eb2f3db700736c785ef7fa40b73eb64c..5353761fcbf92421d82c80900182201e4d4deb67 100644 (file)
@@ -22,6 +22,8 @@
 #include <apt-pkg/pkgcache.h>
 #include <apt-pkg/cacheiterators.h>
 
+#include <algorithm>
+
 #include <ctype.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 #include <dirent.h>
 #include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <fcntl.h>
 
 #include <apti18n.h>
                                                                        /*}}}*/
@@ -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<std::string> debSystem::GetDpkgBaseCommand()               /*{{{*/
+{
+   // Generate the base argument list for dpkg
+   std::vector<std::string> 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<std::string> const Args = GetDpkgBaseCommand();
+   std::vector<const char *> 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;
+}
+                                                                       /*}}}*/
index aed77520e1c19133e0572ddb8a69cccb6514d3a2..521552ef481555befcb7127ad7ca2e9e07a65b7a 100644 (file)
@@ -45,6 +45,11 @@ class debSystem : public pkgSystem
 
    debSystem();
    virtual ~debSystem();
+
+   APT_HIDDEN static std::string GetDpkgExecutable();
+   APT_HIDDEN static std::vector<std::string> GetDpkgBaseCommand();
+   APT_HIDDEN static void DpkgChrootDirectory();
+   APT_HIDDEN static bool SupportsMultiArch();
 };
 
 extern debSystem debSys;
index 7a02533838fa0fb3bb82ecf56fc50b1e77d4bfcd..3ec8b2d60e3fc66c32821b2eb7a323b91ab6d73f 100644 (file)
@@ -14,6 +14,7 @@
 #include <apt-pkg/configuration.h>
 #include <apt-pkg/depcache.h>
 #include <apt-pkg/dpkgpm.h>
+#include <apt-pkg/debsystem.h>
 #include <apt-pkg/error.h>
 #include <apt-pkg/fileutl.h>
 #include <apt-pkg/install-progress.h>
@@ -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<const char *> 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<std::string> const sArgs = debSystem::GetDpkgBaseCommand();
+   std::vector<const char *> 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);
index a6b61e65563fabf174f4316fe902c94814f28e1b..2a0fc9d3b78ce842f913ca561e01576f3fa0f1bb 100644 (file)
@@ -12,6 +12,7 @@
 // Include Files                                                       /*{{{*/
 #include<config.h>
 
+#include <apt-pkg/debsystem.h>
 #include <apt-pkg/pkgsystem.h>
 #include <apt-pkg/macros.h>
 
@@ -46,5 +47,13 @@ APT_PURE pkgSystem *pkgSystem::GetSystem(const char *Label)
    return 0;   
 }
                                                                        /*}}}*/
+bool pkgSystem::MultiArchSupported() const                             /*{{{*/
+{
+   debSystem const * const deb = dynamic_cast<debSystem const *>(this);
+   if (deb != NULL)
+      return deb->SupportsMultiArch();
+   return true;
+}
+                                                                       /*}}}*/
 
 pkgSystem::~pkgSystem() {}
index 5b31457e0bf8c71303b9b996d2a816c662eee3ef..c7de63c8739ea93c84dd773f67545cc83aac0099 100644 (file)
@@ -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:
index 02c73fc2e4a04a73245ea8db6cf2997bde664f8a..20166b3121508b14d53a82e798576a7ebb6df6a6 100644 (file)
@@ -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)
    {