]> git.saurik.com Git - apt.git/blobdiff - apt-pkg/deb/dpkgpm.cc
* apt-pkg/acquire-item.cc:
[apt.git] / apt-pkg / deb / dpkgpm.cc
index c1741981999a2f7c7717b2e922c49782676cc892..499c3db8a5b0c2f35900f8e59cd5191d51838f7f 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,45 @@ 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);
+}
+                                                                       /*}}}*/
+
+
+// FindNowVersion - Helper to find a Version in "now" state    /*{{{*/
+// ---------------------------------------------------------------------
+/* This is helpful when a package is no longer installed but has residual 
+ * config files
+ */
+static 
+pkgCache::VerIterator FindNowVersion(const pkgCache::PkgIterator &Pkg)
+{
+   pkgCache::VerIterator Ver;
+   for (Ver = Pkg.VersionList(); Ver.end() == false; Ver++)
+   {
+      pkgCache::VerFileIterator Vf = Ver.FileList();
+      pkgCache::PkgFileIterator F = Vf.File();
+      for (F = Vf.File(); F.end() == false; F++)
+      {
+         if (F && F.Archive())
+         {
+            if (strcmp(F.Archive(), "now")) 
+               return Ver;
+         }
+      }
+   }
+   return Ver;
+}
+                                                                       /*}}}*/
+
 // DPkgPM::pkgDPkgPM - Constructor                                     /*{{{*/
 // ---------------------------------------------------------------------
 /* */
@@ -328,15 +367,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 +860,56 @@ 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 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);
+      }
+   }
+   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);
+      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;
    sigset_t sigmask;
@@ -905,6 +986,21 @@ bool pkgDPkgPM::Go(int OutStatusFd)
    // 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;
+   }
+
    // this loop is runs once per operation
    for (vector<Item>::const_iterator I = List.begin(); I != List.end();)
    {
@@ -926,11 +1022,13 @@ bool pkgDPkgPM::Go(int OutStatusFd)
         for (; J != List.end() && J->Op == I->Op; ++J)
            /* nothing */;
 
-      // Generate the argument list
-      std::vector<const char *> Args;
       // keep track of allocated strings for multiarch package names
       std::vector<char *> Packages;
 
+      // start with the baseset of arguments
+      unsigned long Size = StartSize;
+      Args.erase(Args.begin() + BaseArgs, Args.end());
+
       // Now check if we are within the MaxArgs limit
       //
       // this code below is problematic, because it may happen that
@@ -941,32 +1039,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);
       }
 
-      unsigned long Size = 0;
-      string const Tmp = _config->Find("Dir::Bin::dpkg","dpkg");
-      Args.push_back(Tmp.c_str());
-      Size += 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());
-           Size += Opts->Value.length();
-        }       
-      }
-      
       int fd[2];
       pipe(fd);
 
@@ -977,7 +1060,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)
@@ -1042,14 +1124,29 @@ bool pkgDPkgPM::Go(int OutStatusFd)
               continue;
            if (I->Op == Item::Configure && disappearedPkgs.find(I->Pkg.Name()) != disappearedPkgs.end())
               continue;
-           if (false && (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();
+                  if(PkgVer.end() == true)
+                     PkgVer = FindNowVersion(I->Pkg);
+               }
+              else
+                 PkgVer = Cache[I->Pkg].InstVerIter(Cache);
+               if (PkgVer.end() == false)
+                  name.append(":").append(PkgVer.Arch());
+               else
+                  _error->Warning("Can not find PkgVer for '%s'", name.c_str());
+              char * const fullname = strdup(name.c_str());
               Packages.push_back(fullname);
               ADDARG(fullname);
            }
@@ -1067,7 +1164,7 @@ bool pkgDPkgPM::Go(int OutStatusFd)
         for (std::vector<const char *>::const_iterator a = Args.begin();
              a != Args.end(); ++a)
            clog << *a << ' ';
-        clog << "size=" << Size << endl;
+        clog << endl;
         continue;
       }
       Args.push_back(NULL);
@@ -1154,14 +1251,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);
@@ -1356,6 +1446,12 @@ void pkgDPkgPM::Reset()
 /* */
 void pkgDPkgPM::WriteApportReport(const char *pkgpath, const char *errormsg) 
 {
+   // If apport doesn't exist or isn't installed do nothing
+   // This e.g. prevents messages in 'universes' without apport
+   pkgCache::PkgIterator apportPkg = Cache.FindPkg("apport");
+   if (apportPkg.end() == true || apportPkg->CurrentVer == 0)
+      return;
+
    string pkgname, reportfile, srcpkgname, pkgver, arch;
    string::size_type pos;
    FILE *report;