]> git.saurik.com Git - apt.git/blobdiff - apt-pkg/deb/dpkgpm.cc
* apt-pkg/deb/dpkgpm.cc:
[apt.git] / apt-pkg / deb / dpkgpm.cc
index 5eb6406c6fbaf5e5ec3898262defd7160b17419d..4c473c1c2d93d282a25956d7a7eae560cbe9bfd3 100644 (file)
@@ -108,7 +108,7 @@ ionice(int PID)
 {
    if (!FileExists("/usr/bin/ionice"))
       return false;
-   pid_t Process = ExecFork();      
+   pid_t Process = ExecFork();
    if (Process == 0)
    {
       char buf[32];
@@ -123,6 +123,18 @@ ionice(int PID)
    return ExecWait(Process, "ionice");
 }
 
+// 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);
+}
+                                                                       /*}}}*/
+
 // DPkgPM::pkgDPkgPM - Constructor                                     /*{{{*/
 // ---------------------------------------------------------------------
 /* */
@@ -328,15 +340,7 @@ bool pkgDPkgPM::RunScriptsWithPkgs(const char *Cnf)
         SetCloseExec(STDIN_FILENO,false);      
         SetCloseExec(STDERR_FILENO,false);
 
-        if (_config->FindDir("DPkg::Chroot-Directory","/") != "/") 
-        {
-           std::cerr << "Chrooting into " 
-                     << _config->FindDir("DPkg::Chroot-Directory") 
-                     << std::endl;
-           if (chroot(_config->FindDir("DPkg::Chroot-Directory","/").c_str()) != 0)
-              _exit(100);
-        }
-
+        dpkgChrootDirectory();
         const char *Args[4];
         Args[0] = "/bin/sh";
         Args[1] = "-c";
@@ -829,6 +833,46 @@ static int racy_pselect(int nfds, fd_set *readfds, fd_set *writefds,
 */
 bool pkgDPkgPM::Go(int OutStatusFd)
 {
+   // Generate the base argument list for dpkg
+   std::vector<const char *> Args;
+   unsigned long StartSize = 0;
+   string const Tmp = _config->Find("Dir::Bin::dpkg","dpkg");
+   Args.push_back(Tmp.c_str());
+   StartSize += Tmp.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();
+      }
+   }
+
+   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);
+      execv(Args[0], (char**) &Args[0]);
+      _error->WarningE("dpkgGo", "Can't detect if dpkg supports multi-arch!");
+      _exit(2);
+   }
+
    fd_set rfds;
    struct timespec tv;
    sigset_t sigmask;
@@ -905,27 +949,20 @@ bool pkgDPkgPM::Go(int OutStatusFd)
    // create log
    OpenLog();
 
-   // Generate the base argument list for dpkg
-   std::vector<const char *> Args;
-   unsigned long StartSize = 0;
-   string const Tmp = _config->Find("Dir::Bin::dpkg","dpkg");
-   Args.push_back(Tmp.c_str());
-   StartSize += Tmp.length();
-
-   // Stick in any custom dpkg options
-   Configuration::Item const *Opts = _config->Tree("DPkg::Options");
-   if (Opts != 0)
+   bool dpkgMultiArch = false;
+   if (dpkgAssertMultiArch > 0)
    {
-      Opts = Opts->Child;
-      for (; Opts != 0; Opts = Opts->Next)
+      int Status = 0;
+      while (waitpid(dpkgAssertMultiArch, &Status, 0) != dpkgAssertMultiArch)
       {
-        if (Opts->Value.empty() == true)
+        if (errno == EINTR)
            continue;
-        Args.push_back(Opts->Value.c_str());
-        StartSize += Opts->Value.length();
+        _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;
    }
-   size_t const BaseArgs = Args.size();
 
    // this loop is runs once per operation
    for (vector<Item>::const_iterator I = List.begin(); I != List.end();)
@@ -965,14 +1002,17 @@ bool pkgDPkgPM::Go(int OutStatusFd)
       if (J - I > (signed)MaxArgs)
       {
         J = I + MaxArgs;
-        Args.reserve(MaxArgs + 10);
+        unsigned long const size = MaxArgs + 10;
+        Args.reserve(size);
+        Packages.reserve(size);
       }
       else
       {
-        Args.reserve((J - I) + 10);
+        unsigned long const size = (J - I) + 10;
+        Args.reserve(size);
+        Packages.reserve(size);
       }
 
-      
       int fd[2];
       pipe(fd);
 
@@ -983,7 +1023,6 @@ bool pkgDPkgPM::Go(int OutStatusFd)
       char status_fd_buf[20];
       snprintf(status_fd_buf,sizeof(status_fd_buf),"%i", fd[1]);
       ADDARG(status_fd_buf);
-
       unsigned long const Op = I->Op;
 
       switch (I->Op)
@@ -1048,14 +1087,22 @@ bool pkgDPkgPM::Go(int OutStatusFd)
               continue;
            if (I->Op == Item::Configure && disappearedPkgs.find(I->Pkg.Name()) != disappearedPkgs.end())
               continue;
-           if (I->Pkg.Arch() == nativeArch || !strcmp(I->Pkg.Arch(), "all"))
+           // We keep this here to allow "smooth" transitions from e.g. multiarch dpkg/ubuntu to dpkg/debian
+           if (dpkgMultiArch == false && (I->Pkg.Arch() == nativeArch || !strcmp(I->Pkg.Arch(), "all")))
            {
               char const * const name = I->Pkg.Name();
               ADDARG(name);
            }
            else
            {
-              char * const fullname = strdup(I->Pkg.FullName(false).c_str());
+              pkgCache::VerIterator PkgVer;
+              std::string name = I->Pkg.Name();
+              if (Op == Item::Remove || Op == Item::Purge)
+                 PkgVer = I->Pkg.CurrentVer();
+              else
+                 PkgVer = Cache[I->Pkg].InstVerIter(Cache);
+              name.append(":").append(PkgVer.Arch());
+              char * const fullname = strdup(name.c_str());
               Packages.push_back(fullname);
               ADDARG(fullname);
            }
@@ -1160,14 +1207,7 @@ bool pkgDPkgPM::Go(int OutStatusFd)
         }
         close(fd[0]); // close the read end of the pipe
 
-        if (_config->FindDir("DPkg::Chroot-Directory","/") != "/") 
-        {
-           std::cerr << "Chrooting into " 
-                     << _config->FindDir("DPkg::Chroot-Directory") 
-                     << std::endl;
-           if (chroot(_config->FindDir("DPkg::Chroot-Directory","/").c_str()) != 0)
-              _exit(100);
-        }
+        dpkgChrootDirectory();
 
         if (chdir(_config->FindDir("DPkg::Run-Directory","/").c_str()) != 0)
            _exit(100);