]> git.saurik.com Git - apt.git/blobdiff - apt-pkg/deb/dpkgpm.cc
doc: Fix fuzzy string regression
[apt.git] / apt-pkg / deb / dpkgpm.cc
index 7355af9d507246205f202ff65bc3195b860ee1b0..c1b9a28f4ad1ecd3f363e313c94408db8d871a4a 100644 (file)
@@ -1,10 +1,9 @@
 // -*- mode: cpp; mode: fold -*-
 // Description                                                         /*{{{*/
 // -*- mode: cpp; mode: fold -*-
 // Description                                                         /*{{{*/
-// $Id: dpkgpm.cc,v 1.28 2004/01/27 02:25:01 mdz Exp $
 /* ######################################################################
 
    DPKG Package Manager - Provide an interface to dpkg
 /* ######################################################################
 
    DPKG Package Manager - Provide an interface to dpkg
-   
+
    ##################################################################### */
                                                                        /*}}}*/
 // Includes                                                            /*{{{*/
    ##################################################################### */
                                                                        /*}}}*/
 // Includes                                                            /*{{{*/
@@ -40,7 +39,9 @@
 #include <termios.h>
 #include <time.h>
 #include <unistd.h>
 #include <termios.h>
 #include <time.h>
 #include <unistd.h>
+
 #include <algorithm>
 #include <algorithm>
+#include <array>
 #include <cstring>
 #include <iostream>
 #include <map>
 #include <cstring>
 #include <iostream>
 #include <map>
 #include <string>
 #include <utility>
 #include <vector>
 #include <string>
 #include <utility>
 #include <vector>
+#include <sstream>
+#include <numeric>
 
 #include <apti18n.h>
                                                                        /*}}}*/
 
 using namespace std;
 
 
 #include <apti18n.h>
                                                                        /*}}}*/
 
 using namespace std;
 
-APT_PURE static unsigned int
-EnvironmentSize()
+APT_PURE static string AptHistoryRequestingUser()                      /*{{{*/
+{
+   const char* EnvKeys[]{"SUDO_UID", "PKEXEC_UID", "PACKAGEKIT_CALLER_UID"};
+
+   for (const auto &Key: EnvKeys)
+   {
+      if (getenv(Key) != nullptr)
+      {
+         int uid = atoi(getenv(Key));
+         if (uid > 0) {
+            struct passwd pwd;
+            struct passwd *result;
+            char buf[255];
+            if (getpwuid_r(uid, &pwd, buf, sizeof(buf), &result) == 0 && result != NULL) {
+               std::string res;
+               strprintf(res, "%s (%d)", pwd.pw_name, uid);
+               return res;
+            }
+         }
+      }
+   }
+   return "";
+}
+                                                                       /*}}}*/
+APT_PURE static unsigned int EnvironmentSize()                         /*{{{*/
 {
   unsigned int size = 0;
   char **envp = environ;
 {
   unsigned int size = 0;
   char **envp = environ;
@@ -65,8 +91,8 @@ EnvironmentSize()
 
   return size;
 }
 
   return size;
 }
-
-class pkgDPkgPMPrivate 
+                                                                       /*}}}*/
+class pkgDPkgPMPrivate                                                 /*{{{*/
 {
 public:
    pkgDPkgPMPrivate() : stdin_is_dev_null(false), dpkgbuf_pos(0),
 {
 public:
    pkgDPkgPMPrivate() : stdin_is_dev_null(false), dpkgbuf_pos(0),
@@ -102,7 +128,7 @@ public:
 
    bool direct_stdin;
 };
 
    bool direct_stdin;
 };
-
+                                                                       /*}}}*/
 namespace
 {
   // Maps the dpkg "processing" info to human readable names.  Entry 0
 namespace
 {
   // Maps the dpkg "processing" info to human readable names.  Entry 0
@@ -138,13 +164,10 @@ namespace
   };
 }
 
   };
 }
 
-/* helper function to ionice the given PID 
-
- there is no C header for ionice yet - just the syscall interface
- so we use the binary from util-linux
-*/
-static bool
-ionice(int PID)
+// ionice - helper function to ionice the given PID                    /*{{{*/
+/* there is no C header for ionice yet - just the syscall interface
+   so we use the binary from util-linux */
+static bool ionice(int PID)
 {
    if (!FileExists("/usr/bin/ionice"))
       return false;
 {
    if (!FileExists("/usr/bin/ionice"))
       return false;
@@ -162,13 +185,13 @@ ionice(int PID)
    }
    return ExecWait(Process, "ionice");
 }
    }
    return ExecWait(Process, "ionice");
 }
-
+                                                                       /*}}}*/
 // FindNowVersion - Helper to find a Version in "now" state    /*{{{*/
 // ---------------------------------------------------------------------
 // FindNowVersion - Helper to find a Version in "now" state    /*{{{*/
 // ---------------------------------------------------------------------
-/* This is helpful when a package is no longer installed but has residual 
+/* This is helpful when a package is no longer installed but has residual
  * config files
  */
  * config files
  */
-static 
+static
 pkgCache::VerIterator FindNowVersion(const pkgCache::PkgIterator &Pkg)
 {
    pkgCache::VerIterator Ver;
 pkgCache::VerIterator FindNowVersion(const pkgCache::PkgIterator &Pkg)
 {
    pkgCache::VerIterator Ver;
@@ -248,7 +271,7 @@ bool pkgDPkgPM::Remove(PkgIterator Pkg,bool Purge)
 {
    if (Pkg.end() == true)
       return false;
 {
    if (Pkg.end() == true)
       return false;
-   
+
    if (Purge == true)
       List.push_back(Item(Item::Purge,Pkg));
    else
    if (Purge == true)
       List.push_back(Item(Item::Purge,Pkg));
    else
@@ -289,14 +312,14 @@ bool pkgDPkgPM::SendPkgsInfo(FILE * const F, unsigned int const &Version)
         Top = Top->Child;
         continue;
       }
         Top = Top->Child;
         continue;
       }
-      
+
       while (Top != 0 && Top->Next == 0)
         Top = Top->Parent;
       if (Top != 0)
         Top = Top->Next;
       while (Top != 0 && Top->Next == 0)
         Top = Top->Parent;
       if (Top != 0)
         Top = Top->Next;
-   }   
+   }
    fprintf(F,"\n");
    fprintf(F,"\n");
+
    // Write out the package actions in order.
    for (vector<Item>::iterator I = List.begin(); I != List.end(); ++I)
    {
    // Write out the package actions in order.
    for (vector<Item>::iterator I = List.begin(); I != List.end(); ++I)
    {
@@ -304,7 +327,7 @@ bool pkgDPkgPM::SendPkgsInfo(FILE * const F, unsigned int const &Version)
         continue;
 
       pkgDepCache::StateCache &S = Cache[I->Pkg];
         continue;
 
       pkgDepCache::StateCache &S = Cache[I->Pkg];
-      
+
       fprintf(F,"%s ",I->Pkg.Name());
 
       // Current version which we are going to replace
       fprintf(F,"%s ",I->Pkg.Name());
 
       // Current version which we are going to replace
@@ -359,13 +382,13 @@ bool pkgDPkgPM::SendPkgsInfo(FILE * const F, unsigned int const &Version)
            fprintf(F,"**ERROR**\n");
         else
            fprintf(F,"%s\n",I->File.c_str());
            fprintf(F,"**ERROR**\n");
         else
            fprintf(F,"%s\n",I->File.c_str());
-      }      
+      }
       else if (I->Op == Item::Configure)
         fprintf(F,"**CONFIGURE**\n");
       else if (I->Op == Item::Remove ||
          I->Op == Item::Purge)
         fprintf(F,"**REMOVE**\n");
       else if (I->Op == Item::Configure)
         fprintf(F,"**CONFIGURE**\n");
       else if (I->Op == Item::Remove ||
          I->Op == Item::Purge)
         fprintf(F,"**REMOVE**\n");
-      
+
       if (ferror(F) != 0)
         return false;
    }
       if (ferror(F) != 0)
         return false;
    }
@@ -387,7 +410,7 @@ bool pkgDPkgPM::RunScriptsWithPkgs(const char *Cnf)
    Opts = Opts->Child;
 
    sighandler_t old_sigpipe = signal(SIGPIPE, SIG_IGN);
    Opts = Opts->Child;
 
    sighandler_t old_sigpipe = signal(SIGPIPE, SIG_IGN);
-   
+
    unsigned int Count = 1;
    for (; Opts != 0; Opts = Opts->Next, Count++)
    {
    unsigned int Count = 1;
    for (; Opts != 0; Opts = Opts->Next, Count++)
    {
@@ -404,10 +427,10 @@ bool pkgDPkgPM::RunScriptsWithPkgs(const char *Cnf)
       if ((Pos = OptSec.find(' ')) == string::npos || Pos == 0)
         Pos = OptSec.length();
       OptSec = "DPkg::Tools::Options::" + string(Opts->Value.c_str(),Pos);
       if ((Pos = OptSec.find(' ')) == string::npos || Pos == 0)
         Pos = OptSec.length();
       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);
       unsigned int Version = _config->FindI(OptSec+"::Version",1);
       unsigned int InfoFD = _config->FindI(OptSec + "::InfoFD", STDIN_FILENO);
-      
+
       // Create the pipes
       std::set<int> KeepFDs;
       MergeKeepFdsFromConfiguration(KeepFDs);
       // Create the pipes
       std::set<int> KeepFDs;
       MergeKeepFdsFromConfiguration(KeepFDs);
@@ -450,10 +473,10 @@ bool pkgDPkgPM::RunScriptsWithPkgs(const char *Cnf)
       close(Pipes[0]);
       FILE *F = fdopen(Pipes[1],"w");
       if (F == 0) {
       close(Pipes[0]);
       FILE *F = fdopen(Pipes[1],"w");
       if (F == 0) {
-         result = _error->Errno("fdopen","Faild to open new FD");
+         result = _error->Errno("fdopen","Failed to open new FD");
          break;
       }
          break;
       }
-      
+
       // Feed it the filenames.
       if (Version <= 1)
       {
       // Feed it the filenames.
       if (Version <= 1)
       {
@@ -466,7 +489,7 @@ bool pkgDPkgPM::RunScriptsWithPkgs(const char *Cnf)
            // No errors here..
            if (I->File[0] != '/')
               continue;
            // No errors here..
            if (I->File[0] != '/')
               continue;
-           
+
            /* Feed the filename of each package that is pending install
               into the pipe. */
            fprintf(F,"%s\n",I->File.c_str());
            /* Feed the filename of each package that is pending install
               into the pipe. */
            fprintf(F,"%s\n",I->File.c_str());
@@ -478,7 +501,7 @@ bool pkgDPkgPM::RunScriptsWithPkgs(const char *Cnf)
         SendPkgsInfo(F, Version);
 
       fclose(F);
         SendPkgsInfo(F, Version);
 
       fclose(F);
-      
+
       // Clean up the sub process
       if (ExecWait(Process,Opts->Value.c_str()) == false) {
         result = _error->Error("Failure running script %s",Opts->Value.c_str());
       // Clean up the sub process
       if (ExecWait(Process,Opts->Value.c_str()) == false) {
         result = _error->Error("Failure running script %s",Opts->Value.c_str());
@@ -522,18 +545,15 @@ void pkgDPkgPM::DoTerminalPty(int master)
       struct timespec sleepfor = { 0, 500000000 };
       nanosleep(&sleepfor, NULL);
       return;
       struct timespec sleepfor = { 0, 500000000 };
       nanosleep(&sleepfor, NULL);
       return;
-   }  
-   if(len <= 0) 
+   }
+   if(len <= 0)
       return;
    FileFd::Write(1, term_buf, len);
    if(d->term_out)
       fwrite(term_buf, len, sizeof(char), d->term_out);
 }
                                                                        /*}}}*/
       return;
    FileFd::Write(1, term_buf, len);
    if(d->term_out)
       fwrite(term_buf, len, sizeof(char), d->term_out);
 }
                                                                        /*}}}*/
-// DPkgPM::ProcessDpkgStatusBuf                                                /*{{{*/
-// ---------------------------------------------------------------------
-/*
- */
+// DPkgPM::ProcessDpkgStatusBuf                                                /*{{{*/
 void pkgDPkgPM::ProcessDpkgStatusLine(char *line)
 {
    bool const Debug = _config->FindB("Debug::pkgDPkgProgressReporting",false);
 void pkgDPkgPM::ProcessDpkgStatusLine(char *line)
 {
    bool const Debug = _config->FindB("Debug::pkgDPkgProgressReporting",false);
@@ -543,14 +563,14 @@ void pkgDPkgPM::ProcessDpkgStatusLine(char *line)
    /* dpkg sends strings like this:
       'status:   <pkg>: <pkg  qstate>'
       'status:   <pkg>:<arch>: <pkg  qstate>'
    /* dpkg sends strings like this:
       'status:   <pkg>: <pkg  qstate>'
       'status:   <pkg>:<arch>: <pkg  qstate>'
-      
+
       'processing: {install,upgrade,configure,remove,purge,disappear,trigproc}: pkg'
       'processing: {install,upgrade,configure,remove,purge,disappear,trigproc}: trigger'
    */
 
    // we need to split on ": " (note the appended space) as the ':' is
    // part of the pkgname:arch information that dpkg sends
       'processing: {install,upgrade,configure,remove,purge,disappear,trigproc}: pkg'
       'processing: {install,upgrade,configure,remove,purge,disappear,trigproc}: trigger'
    */
 
    // we need to split on ": " (note the appended space) as the ':' is
    // part of the pkgname:arch information that dpkg sends
-   // 
+   //
    // A dpkg error message may contain additional ":" (like
    //  "failed in buffer_write(fd) (10, ret=-1): backend dpkg-deb ..."
    // so we need to ensure to not split too much
    // A dpkg error message may contain additional ":" (like
    //  "failed in buffer_write(fd) (10, ret=-1): backend dpkg-deb ..."
    // so we need to ensure to not split too much
@@ -669,37 +689,64 @@ void pkgDPkgPM::ProcessDpkgStatusLine(char *line)
       d->progress->StatusChanged(pkgname, PackagesDone, PackagesTotal, msg);
 
       // FIXME: this needs a muliarch testcase
       d->progress->StatusChanged(pkgname, PackagesDone, PackagesTotal, msg);
 
       // FIXME: this needs a muliarch testcase
-      // FIXME2: is "pkgname" here reliable with dpkg only sending us 
+      // FIXME2: is "pkgname" here reliable with dpkg only sending us
       //         short pkgnames?
       if (action == "disappear")
         handleDisappearAction(pkgname);
       return;
       //         short pkgnames?
       if (action == "disappear")
         handleDisappearAction(pkgname);
       return;
-   } 
+   }
 
    if (prefix == "status")
    {
 
    if (prefix == "status")
    {
-      vector<struct DpkgState> const &states = PackageOps[pkg];
-      if(PackageOpsDone[pkg] < states.size())
+      std::vector<struct DpkgState> &states = PackageOps[pkg];
+      if (action == "triggers-pending")
       {
       {
-         char const * const next_action = states[PackageOpsDone[pkg]].state;
-        if (next_action && Debug == true)
+        if (Debug == true)
            std::clog << "(parsed from dpkg) pkg: " << short_pkgname
            std::clog << "(parsed from dpkg) pkg: " << short_pkgname
-              << " action: " << action << " (expected: '" << next_action << "' "
+              << " action: " << action << " (prefix 2 to "
               << PackageOpsDone[pkg] << " of " << states.size() << ")" << endl;
 
               << PackageOpsDone[pkg] << " of " << states.size() << ")" << endl;
 
-        // check if the package moved to the next dpkg state
-        if(next_action && (action == next_action))
+        states.insert(states.begin(), {"installed", N_("Installed %s")});
+        states.insert(states.begin(), {"half-configured", N_("Configuring %s")});
+        PackagesTotal += 2;
+      }
+      else if(PackageOpsDone[pkg] < states.size())
+      {
+        char const * next_action = states[PackageOpsDone[pkg]].state;
+        if (next_action)
         {
         {
-           // only read the translation if there is actually a next action
-           char const * const translation = _(states[PackageOpsDone[pkg]].str);
+           /*
+           if (action == "half-installed" && strcmp("half-configured", next_action) == 0 &&
+                 PackageOpsDone[pkg] + 2 < states.size() && action == states[PackageOpsDone[pkg] + 2].state)
+           {
+              if (Debug == true)
+                 std::clog << "(parsed from dpkg) pkg: " << short_pkgname << " action: " << action
+                    << " pending trigger defused by unpack" << std::endl;
+              // unpacking a package defuses the pending trigger
+              PackageOpsDone[pkg] += 2;
+              PackagesDone += 2;
+              next_action = states[PackageOpsDone[pkg]].state;
+           }
+           */
+           if (Debug == true)
+              std::clog << "(parsed from dpkg) pkg: " << short_pkgname
+                 << " action: " << action << " (expected: '" << next_action << "' "
+                 << PackageOpsDone[pkg] << " of " << states.size() << ")" << endl;
+
+           // check if the package moved to the next dpkg state
+           if(action == next_action)
+           {
+              // only read the translation if there is actually a next action
+              char const * const translation = _(states[PackageOpsDone[pkg]].str);
 
 
-           // we moved from one dpkg state to a new one, report that
-           ++PackageOpsDone[pkg];
-           ++PackagesDone;
+              // we moved from one dpkg state to a new one, report that
+              ++PackageOpsDone[pkg];
+              ++PackagesDone;
 
 
-           std::string msg;
-           strprintf(msg, translation, i18n_pkgname.c_str());
-           d->progress->StatusChanged(pkgname, PackagesDone, PackagesTotal, msg);
+              std::string msg;
+              strprintf(msg, translation, i18n_pkgname.c_str());
+              d->progress->StatusChanged(pkgname, PackagesDone, PackagesTotal, msg);
+           }
         }
       }
    }
         }
       }
    }
@@ -876,6 +923,9 @@ bool pkgDPkgPM::OpenLog()
       }
       if (_config->Exists("Commandline::AsString") == true)
         WriteHistoryTag("Commandline", _config->Find("Commandline::AsString"));
       }
       if (_config->Exists("Commandline::AsString") == true)
         WriteHistoryTag("Commandline", _config->Find("Commandline::AsString"));
+      std::string RequestingUser = AptHistoryRequestingUser();
+      if (RequestingUser != "")
+         WriteHistoryTag("Requested-By", RequestingUser);
       WriteHistoryTag("Install", install);
       WriteHistoryTag("Reinstall", reinstall);
       WriteHistoryTag("Upgrade", upgrade);
       WriteHistoryTag("Install", install);
       WriteHistoryTag("Reinstall", reinstall);
       WriteHistoryTag("Upgrade", upgrade);
@@ -884,7 +934,7 @@ bool pkgDPkgPM::OpenLog()
       WriteHistoryTag("Purge",purge);
       fflush(d->history_out);
    }
       WriteHistoryTag("Purge",purge);
       fflush(d->history_out);
    }
-   
+
    return true;
 }
                                                                        /*}}}*/
    return true;
 }
                                                                        /*}}}*/
@@ -933,79 +983,66 @@ bool pkgDPkgPM::CloseLog()
    return true;
 }
                                                                        /*}}}*/
    return true;
 }
                                                                        /*}}}*/
-                                                                       /*}}}*/
-/*{{{*/
-// This implements a racy version of pselect for those architectures
-// that don't have a working implementation.
-// FIXME: Probably can be removed on Lenny+1
-static int racy_pselect(int nfds, fd_set *readfds, fd_set *writefds,
-   fd_set *exceptfds, const struct timespec *timeout,
-   const sigset_t *sigmask)
-{
-   sigset_t origmask;
-   struct timeval tv;
-   int retval;
-
-   tv.tv_sec = timeout->tv_sec;
-   tv.tv_usec = timeout->tv_nsec/1000;
-
-   sigprocmask(SIG_SETMASK, sigmask, &origmask);
-   retval = select(nfds, readfds, writefds, exceptfds, &tv);
-   sigprocmask(SIG_SETMASK, &origmask, 0);
-   return retval;
-}
-                                                                        /*}}}*/
 
 // DPkgPM::BuildPackagesProgressMap                                    /*{{{*/
 void pkgDPkgPM::BuildPackagesProgressMap()
 {
    // map the dpkg states to the operations that are performed
    // (this is sorted in the same way as Item::Ops)
 
 // DPkgPM::BuildPackagesProgressMap                                    /*{{{*/
 void pkgDPkgPM::BuildPackagesProgressMap()
 {
    // map the dpkg states to the operations that are performed
    // (this is sorted in the same way as Item::Ops)
-   static const struct DpkgState DpkgStatesOpMap[][7] = {
+   static const std::array<std::array<DpkgState, 3>, 4> DpkgStatesOpMap = {{
       // Install operation
       // Install operation
-      { 
-        {"half-installed", N_("Preparing %s")}, 
-        {"unpacked", N_("Unpacking %s") }, 
-        {NULL, NULL}
-      },
+      {{
+        {"half-installed", N_("Preparing %s")},
+        {"unpacked", N_("Unpacking %s") },
+        {nullptr, nullptr}
+      }},
       // Configure operation
       // Configure operation
-      { 
+      {{
         {"unpacked",N_("Preparing to configure %s") },
         {"half-configured", N_("Configuring %s") },
         { "installed", N_("Installed %s")},
         {"unpacked",N_("Preparing to configure %s") },
         {"half-configured", N_("Configuring %s") },
         { "installed", N_("Installed %s")},
-        {NULL, NULL}
-      },
+      }},
       // Remove operation
       // Remove operation
-      { 
+      {{
         {"half-configured", N_("Preparing for removal of %s")},
         {"half-installed", N_("Removing %s")},
         {"config-files",  N_("Removed %s")},
         {"half-configured", N_("Preparing for removal of %s")},
         {"half-installed", N_("Removing %s")},
         {"config-files",  N_("Removed %s")},
-        {NULL, NULL}
-      },
+      }},
       // Purge operation
       // Purge operation
-      { 
+      {{
         {"config-files", N_("Preparing to completely remove %s")},
         {"not-installed", N_("Completely removed %s")},
         {"config-files", N_("Preparing to completely remove %s")},
         {"not-installed", N_("Completely removed %s")},
-        {NULL, NULL}
-      },
-   };
+        {nullptr, nullptr}
+      }},
+   }};
+   static_assert(Item::Purge == 3, "Enum item has unexpected index for mapping array");
 
    // init the PackageOps map, go over the list of packages that
    // that will be [installed|configured|removed|purged] and add
    // them to the PackageOps map (the dpkg states it goes through)
    // and the PackageOpsTranslations (human readable strings)
 
    // init the PackageOps map, go over the list of packages that
    // that will be [installed|configured|removed|purged] and add
    // them to the PackageOps map (the dpkg states it goes through)
    // and the PackageOpsTranslations (human readable strings)
-   for (vector<Item>::const_iterator I = List.begin(); I != List.end(); ++I)
+   for (auto &&I : List)
    {
    {
-      if((*I).Pkg.end() == true)
+      if(I.Pkg.end() == true)
         continue;
 
         continue;
 
-      string const name = (*I).Pkg.FullName();
+      string const name = I.Pkg.FullName();
       PackageOpsDone[name] = 0;
       PackageOpsDone[name] = 0;
-      for(int i=0; (DpkgStatesOpMap[(*I).Op][i]).state != NULL; ++i)
+      auto AddToPackageOps = std::back_inserter(PackageOps[name]);
+      if (I.Op == Item::Purge && I.Pkg->CurrentVer != 0)
       {
       {
-        PackageOps[name].push_back(DpkgStatesOpMap[(*I).Op][i]);
-        PackagesTotal++;
+        // purging a package which is installed first passes through remove states
+        auto const DpkgOps = DpkgStatesOpMap[Item::Remove];
+        std::copy(DpkgOps.begin(), DpkgOps.end(), AddToPackageOps);
+        PackagesTotal += DpkgOps.size();
       }
       }
+      auto const DpkgOps = DpkgStatesOpMap[I.Op];
+      std::copy_if(DpkgOps.begin(), DpkgOps.end(), AddToPackageOps, [&](DpkgState const &state) {
+        if (state.state == nullptr)
+           return false;
+        ++PackagesTotal;
+        return true;
+      });
    }
    /* one extra: We don't want the progress bar to reach 100%, especially not
       if we call dpkg --configure --pending and process a bunch of triggers
    }
    /* one extra: We don't want the progress bar to reach 100%, especially not
       if we call dpkg --configure --pending and process a bunch of triggers
@@ -1015,18 +1052,18 @@ void pkgDPkgPM::BuildPackagesProgressMap()
    ++PackagesTotal;
 }
                                                                         /*}}}*/
    ++PackagesTotal;
 }
                                                                         /*}}}*/
-bool pkgDPkgPM::Go(int StatusFd)
+bool pkgDPkgPM::Go(int StatusFd)                                       /*{{{*/
 {
    APT::Progress::PackageManager *progress = NULL;
    if (StatusFd == -1)
       progress = APT::Progress::PackageManagerProgressFactory();
    else
       progress = new APT::Progress::PackageManagerProgressFd(StatusFd);
 {
    APT::Progress::PackageManager *progress = NULL;
    if (StatusFd == -1)
       progress = APT::Progress::PackageManagerProgressFactory();
    else
       progress = new APT::Progress::PackageManagerProgressFd(StatusFd);
-   
+
    return Go(progress);
 }
    return Go(progress);
 }
-
-void pkgDPkgPM::StartPtyMagic()
+                                                                       /*}}}*/
+void pkgDPkgPM::StartPtyMagic()                                                /*{{{*/
 {
    if (_config->FindB("Dpkg::Use-Pty", true) == false)
    {
 {
    if (_config->FindB("Dpkg::Use-Pty", true) == false)
    {
@@ -1124,7 +1161,8 @@ void pkgDPkgPM::StartPtyMagic()
    }
    _error->RevertToStack();
 }
    }
    _error->RevertToStack();
 }
-void pkgDPkgPM::SetupSlavePtyMagic()
+                                                                       /*}}}*/
+void pkgDPkgPM::SetupSlavePtyMagic()                                   /*{{{*/
 {
    if(d->master == -1 || d->slave == NULL)
       return;
 {
    if(d->master == -1 || d->slave == NULL)
       return;
@@ -1156,7 +1194,8 @@ void pkgDPkgPM::SetupSlavePtyMagic()
    if (slaveFd != -1)
       close(slaveFd);
 }
    if (slaveFd != -1)
       close(slaveFd);
 }
-void pkgDPkgPM::StopPtyMagic()
+                                                                       /*}}}*/
+void pkgDPkgPM::StopPtyMagic()                                         /*{{{*/
 {
    if (d->slave != NULL)
       free(d->slave);
 {
    if (d->slave != NULL)
       free(d->slave);
@@ -1166,7 +1205,7 @@ void pkgDPkgPM::StopPtyMagic()
       close(d->protect_slave_from_dying);
       d->protect_slave_from_dying = -1;
    }
       close(d->protect_slave_from_dying);
       d->protect_slave_from_dying = -1;
    }
-   if(d->master >= 0) 
+   if(d->master >= 0)
    {
       if (d->tt_is_valid == true && tcsetattr(STDIN_FILENO, TCSAFLUSH, &d->tt) == -1)
         _error->FatalE("tcsetattr", "Setting in Stop via TCSAFLUSH for stdin failed!");
    {
       if (d->tt_is_valid == true && tcsetattr(STDIN_FILENO, TCSAFLUSH, &d->tt) == -1)
         _error->FatalE("tcsetattr", "Setting in Stop via TCSAFLUSH for stdin failed!");
@@ -1177,7 +1216,7 @@ void pkgDPkgPM::StopPtyMagic()
 
 // DPkgPM::Go - Run the sequence                                       /*{{{*/
 // ---------------------------------------------------------------------
 
 // DPkgPM::Go - Run the sequence                                       /*{{{*/
 // ---------------------------------------------------------------------
-/* This globs the operations and calls dpkg 
+/* This globs the operations and calls dpkg
  *
  * If it is called with a progress object apt will report the install
  * progress to this object. It maps the dpkg states a package goes
  *
  * If it is called with a progress object apt will report the install
  * progress to this object. It maps the dpkg states a package goes
@@ -1194,16 +1233,13 @@ bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress)
    std::vector<const char *> Args(sArgs.size(), NULL);
    std::transform(sArgs.begin(), sArgs.end(), Args.begin(),
         [](std::string const &s) { return s.c_str(); });
    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 StartSize = std::accumulate(sArgs.begin(), sArgs.end(), 0llu,
         [](unsigned long long const i, std::string const &s) { return i + s.length(); });
    size_t const BaseArgs = Args.size();
 
    fd_set rfds;
    struct timespec tv;
 
         [](unsigned long long const i, std::string const &s) { return i + s.length(); });
    size_t const BaseArgs = Args.size();
 
    fd_set rfds;
    struct timespec tv;
 
-   // FIXME: do we really need this limit when we have MaxArgBytes?
-   unsigned int const MaxArgs = _config->FindI("Dpkg::MaxArgs",32*1024);
-
    // try to figure out the max environment size
    int OSArgMax = sysconf(_SC_ARG_MAX);
    if(OSArgMax < 0)
    // try to figure out the max environment size
    int OSArgMax = sysconf(_SC_ARG_MAX);
    if(OSArgMax < 0)
@@ -1218,15 +1254,33 @@ bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress)
    if (RunScriptsWithPkgs("DPkg::Pre-Install-Pkgs") == false)
       return false;
 
    if (RunScriptsWithPkgs("DPkg::Pre-Install-Pkgs") == false)
       return false;
 
+   auto const noopDPkgInvocation = _config->FindB("Debug::pkgDPkgPM",false);
+   // store auto-bits as they are supposed to be after dpkg is run
+   if (noopDPkgInvocation == false)
+      Cache.writeStateFile(NULL);
+
+   decltype(List)::const_iterator::difference_type const notconfidx =
+      _config->FindB("Dpkg::ExplicitLastConfigure", false) ? std::numeric_limits<decltype(notconfidx)>::max() :
+      std::distance(List.cbegin(), std::find_if_not(List.crbegin(), List.crend(), [](Item const &i) { return i.Op == Item::Configure; }).base());
+
    // support subpressing of triggers processing for special
    // cases like d-i that runs the triggers handling manually
    bool const TriggersPending = _config->FindB("DPkg::TriggersPending", false);
    // support subpressing of triggers processing for special
    // cases like d-i that runs the triggers handling manually
    bool const TriggersPending = _config->FindB("DPkg::TriggersPending", false);
-   if (_config->FindB("DPkg::ConfigurePending", true) == true)
+   bool const ConfigurePending = _config->FindB("DPkg::ConfigurePending", true);
+   if (ConfigurePending)
       List.push_back(Item(Item::ConfigurePending, PkgIterator()));
 
    // for the progress
    BuildPackagesProgressMap();
 
       List.push_back(Item(Item::ConfigurePending, PkgIterator()));
 
    // for the progress
    BuildPackagesProgressMap();
 
+   if (notconfidx != std::numeric_limits<decltype(notconfidx)>::max())
+   {
+      if (ConfigurePending)
+        List.erase(std::next(List.begin(), notconfidx), std::prev(List.end()));
+      else
+        List.erase(std::next(List.begin(), notconfidx), List.end());
+   }
+
    d->stdin_is_dev_null = false;
 
    // create log
    d->stdin_is_dev_null = false;
 
    // create log
@@ -1237,7 +1291,7 @@ bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress)
    // start pty magic before the loop
    StartPtyMagic();
 
    // start pty magic before the loop
    StartPtyMagic();
 
-   // Tell the progress that its starting and fork dpkg 
+   // Tell the progress that its starting and fork dpkg
    d->progress->Start(d->master);
 
    // this loop is runs once per dpkg operation
    d->progress->Start(d->master);
 
    // this loop is runs once per dpkg operation
@@ -1262,33 +1316,14 @@ bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress)
         for (; J != List.end() && J->Op == I->Op; ++J)
            /* nothing */;
 
         for (; J != List.end() && J->Op == I->Op; ++J)
            /* nothing */;
 
-      // keep track of allocated strings for multiarch package names
-      std::vector<char *> Packages;
+      auto const size = (J - I) + 10;
 
       // start with the baseset of arguments
 
       // start with the baseset of arguments
-      unsigned long Size = StartSize;
+      auto Size = StartSize;
       Args.erase(Args.begin() + BaseArgs, Args.end());
       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
-      // the argument list is split in a way that A depends on B
-      // and they are in the same "--configure A B" run
-      // - with the split they may now be configured in different
-      //   runs, using Immediate-Configure-All can help prevent this.
-      if (J - I > (signed)MaxArgs)
-      {
-        J = I + MaxArgs;
-        unsigned long const size = MaxArgs + 10;
-        Args.reserve(size);
-        Packages.reserve(size);
-      }
-      else
-      {
-        unsigned long const size = (J - I) + 10;
-        Args.reserve(size);
-        Packages.reserve(size);
-      }
+      Args.reserve(size);
+      // keep track of allocated strings for multiarch package names
+      std::vector<char *> Packages(size, nullptr);
 
       int fd[2];
       if (pipe(fd) != 0)
 
       int fd[2];
       if (pipe(fd) != 0)
@@ -1310,13 +1345,13 @@ bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress)
         ADDARGC("--force-remove-essential");
         ADDARGC("--remove");
         break;
         ADDARGC("--force-remove-essential");
         ADDARGC("--remove");
         break;
-        
+
         case Item::Purge:
         ADDARGC("--force-depends");
         ADDARGC("--force-remove-essential");
         ADDARGC("--purge");
         break;
         case Item::Purge:
         ADDARGC("--force-depends");
         ADDARGC("--force-remove-essential");
         ADDARGC("--purge");
         break;
-        
+
         case Item::Configure:
         ADDARGC("--configure");
         break;
         case Item::Configure:
         ADDARGC("--configure");
         break;
@@ -1403,8 +1438,8 @@ bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress)
 #undef ADDARG
 
       J = I;
 #undef ADDARG
 
       J = I;
-      
-      if (_config->FindB("Debug::pkgDPkgPM",false) == true)
+
+      if (noopDPkgInvocation == true)
       {
         for (std::vector<const char *>::const_iterator a = Args.begin();
              a != Args.end(); ++a)
       {
         for (std::vector<const char *>::const_iterator a = Args.begin();
              a != Args.end(); ++a)
@@ -1414,6 +1449,8 @@ bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress)
               p != Packages.end(); ++p)
            free(*p);
         Packages.clear();
               p != Packages.end(); ++p)
            free(*p);
         Packages.clear();
+        close(fd[0]);
+        close(fd[1]);
         continue;
       }
       Args.push_back(NULL);
         continue;
       }
       Args.push_back(NULL);
@@ -1422,18 +1459,17 @@ bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress)
       clog << flush;
       cerr << flush;
 
       clog << flush;
       cerr << flush;
 
-      /* Mask off sig int/quit. We do this because dpkg also does when 
+      /* Mask off sig int/quit. We do this because dpkg also does when
          it forks scripts. What happens is that when you hit ctrl-c it sends
          it forks scripts. What happens is that when you hit ctrl-c it sends
-        it to all processes in the group. Since dpkg ignores the signal 
+        it to all processes in the group. Since dpkg ignores the signal
         it doesn't die but we do! So we must also ignore it */
       sighandler_t old_SIGQUIT = signal(SIGQUIT,SIG_IGN);
       sighandler_t old_SIGINT = signal(SIGINT,SigINT);
         it doesn't die but we do! So we must also ignore it */
       sighandler_t old_SIGQUIT = signal(SIGQUIT,SIG_IGN);
       sighandler_t old_SIGINT = signal(SIGINT,SigINT);
-      
+
       // Check here for any SIGINT
       // Check here for any SIGINT
-      if (pkgPackageManager::SigINTStop && (Op == Item::Remove || Op == Item::Purge || Op == Item::Install)) 
+      if (pkgPackageManager::SigINTStop && (Op == Item::Remove || Op == Item::Purge || Op == Item::Install))
          break;
          break;
-      
-      
+
       // ignore SIGHUP as well (debian #463030)
       sighandler_t old_SIGHUP = signal(SIGHUP,SIG_IGN);
 
       // ignore SIGHUP as well (debian #463030)
       sighandler_t old_SIGHUP = signal(SIGHUP,SIG_IGN);
 
@@ -1460,33 +1496,37 @@ bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress)
             int dummy = 0;
            if ((Flags = fcntl(STDIN_FILENO,F_GETFL,dummy)) < 0)
               _exit(100);
             int dummy = 0;
            if ((Flags = fcntl(STDIN_FILENO,F_GETFL,dummy)) < 0)
               _exit(100);
-           
+
            // Discard everything in stdin before forking dpkg
            if (fcntl(STDIN_FILENO,F_SETFL,Flags | O_NONBLOCK) < 0)
               _exit(100);
            // Discard everything in stdin before forking dpkg
            if (fcntl(STDIN_FILENO,F_SETFL,Flags | O_NONBLOCK) < 0)
               _exit(100);
-           
+
            while (read(STDIN_FILENO,&dummy,1) == 1);
            while (read(STDIN_FILENO,&dummy,1) == 1);
-           
+
            if (fcntl(STDIN_FILENO,F_SETFL,Flags & (~(long)O_NONBLOCK)) < 0)
               _exit(100);
         }
 
            if (fcntl(STDIN_FILENO,F_SETFL,Flags & (~(long)O_NONBLOCK)) < 0)
               _exit(100);
         }
 
+        // if color support isn't enabled/disabled explicitly tell
+        // dpkg to use the same state apt is using for its color support
+        if (_config->FindB("APT::Color", false) == true)
+           setenv("DPKG_COLORS", "always", 0);
+        else
+           setenv("DPKG_COLORS", "never", 0);
+
         execvp(Args[0], (char**) &Args[0]);
         cerr << "Could not exec dpkg!" << endl;
         _exit(100);
         execvp(Args[0], (char**) &Args[0]);
         cerr << "Could not exec dpkg!" << endl;
         _exit(100);
-      }      
-
-      // apply ionice
-      if (_config->FindB("DPkg::UseIoNice", false) == true)
-        ionice(Child);
-
-      // Wait for dpkg
-      int Status = 0;
+      }
 
       // we read from dpkg here
       int const _dpkgin = fd[0];
       close(fd[1]);                        // close the write end of the pipe
 
 
       // we read from dpkg here
       int const _dpkgin = fd[0];
       close(fd[1]);                        // close the write end of the pipe
 
+      // apply ionice
+      if (_config->FindB("DPkg::UseIoNice", false) == true)
+        ionice(Child);
+
       // setups fds
       sigemptyset(&d->sigmask);
       sigprocmask(SIG_BLOCK,&d->sigmask,&d->original_sigmask);
       // setups fds
       sigemptyset(&d->sigmask);
       sigprocmask(SIG_BLOCK,&d->sigmask,&d->original_sigmask);
@@ -1498,22 +1538,16 @@ bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress)
       Packages.clear();
 
       // the result of the waitpid call
       Packages.clear();
 
       // the result of the waitpid call
+      int Status = 0;
       int res;
       int res;
-      int select_ret;
+      bool waitpid_failure = false;
       while ((res=waitpid(Child,&Status, WNOHANG)) != Child) {
         if(res < 0) {
       while ((res=waitpid(Child,&Status, WNOHANG)) != Child) {
         if(res < 0) {
-           // FIXME: move this to a function or something, looks ugly here
            // error handling, waitpid returned -1
            if (errno == EINTR)
               continue;
            // error handling, waitpid returned -1
            if (errno == EINTR)
               continue;
-           RunScripts("DPkg::Post-Invoke");
-
-           // Restore sig int/quit
-           signal(SIGQUIT,old_SIGQUIT);
-           signal(SIGINT,old_SIGINT);
-
-           signal(SIGHUP,old_SIGHUP);
-           return _error->Errno("waitpid","Couldn't wait for subprocess");
+           waitpid_failure = true;
+           break;
         }
 
         // wait for input or output here
         }
 
         // wait for input or output here
@@ -1525,22 +1559,19 @@ bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress)
            FD_SET(d->master, &rfds);
          tv.tv_sec = 0;
          tv.tv_nsec = d->progress->GetPulseInterval();
            FD_SET(d->master, &rfds);
          tv.tv_sec = 0;
          tv.tv_nsec = d->progress->GetPulseInterval();
-        select_ret = pselect(max(d->master, _dpkgin)+1, &rfds, NULL, NULL, 
+        auto const select_ret = pselect(max(d->master, _dpkgin)+1, &rfds, NULL, NULL,
                              &tv, &d->original_sigmask);
                              &tv, &d->original_sigmask);
-        if (select_ret < 0 && (errno == EINVAL || errno == ENOSYS))
-           select_ret = racy_pselect(max(d->master, _dpkgin)+1, &rfds, NULL,
-                                     NULL, &tv, &d->original_sigmask);
          d->progress->Pulse();
          d->progress->Pulse();
-        if (select_ret == 0) 
-           continue;
-        else if (select_ret < 0 && errno == EINTR)
-           continue;
-        else if (select_ret < 0) 
-        {
-           perror("select() returned error");
-           continue;
-        } 
-        
+        if (select_ret == 0)
+           continue;
+        else if (select_ret < 0 && errno == EINTR)
+           continue;
+        else if (select_ret < 0)
+        {
+           perror("select() returned error");
+           continue;
+        }
+
         if(d->master >= 0 && FD_ISSET(d->master, &rfds))
            DoTerminalPty(d->master);
         if(d->master >= 0 && FD_ISSET(0, &rfds))
         if(d->master >= 0 && FD_ISSET(d->master, &rfds))
            DoTerminalPty(d->master);
         if(d->master >= 0 && FD_ISSET(0, &rfds))
@@ -1553,12 +1584,19 @@ bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress)
       // Restore sig int/quit
       signal(SIGQUIT,old_SIGQUIT);
       signal(SIGINT,old_SIGINT);
       // Restore sig int/quit
       signal(SIGQUIT,old_SIGQUIT);
       signal(SIGINT,old_SIGINT);
-      
       signal(SIGHUP,old_SIGHUP);
       signal(SIGHUP,old_SIGHUP);
+
+      if (waitpid_failure == true)
+      {
+        strprintf(d->dpkg_error, "Sub-process %s couldn't be waited for.",Args[0]);
+        _error->Error("%s", d->dpkg_error.c_str());
+        break;
+      }
+
       // Check for an error code.
       if (WIFEXITED(Status) == 0 || WEXITSTATUS(Status) != 0)
       {
       // Check for an error code.
       if (WIFEXITED(Status) == 0 || WEXITSTATUS(Status) != 0)
       {
-        // if it was set to "keep-dpkg-runing" then we won't return
+        // if it was set to "keep-dpkg-running" then we won't return
         // here but keep the loop going and just report it as a error
         // for later
         bool const stopOnError = _config->FindB("Dpkg::StopOnError",true);
         // here but keep the loop going and just report it as a error
         // for later
         bool const stopOnError = _config->FindB("Dpkg::StopOnError",true);
@@ -1576,17 +1614,13 @@ bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress)
       }
    }
    // dpkg is done at this point
       }
    }
    // dpkg is done at this point
-   d->progress->Stop();
    StopPtyMagic();
    CloseLog();
 
    if (pkgPackageManager::SigINTStop)
        _error->Warning(_("Operation was interrupted before it could finish"));
 
    StopPtyMagic();
    CloseLog();
 
    if (pkgPackageManager::SigINTStop)
        _error->Warning(_("Operation was interrupted before it could finish"));
 
-   if (RunScripts("DPkg::Post-Invoke") == false)
-      return false;
-
-   if (_config->FindB("Debug::pkgDPkgPM",false) == false)
+   if (noopDPkgInvocation == false)
    {
       std::string const oldpkgcache = _config->FindFile("Dir::cache::pkgcache");
       if (oldpkgcache.empty() == false && RealFileExists(oldpkgcache) == true &&
    {
       std::string const oldpkgcache = _config->FindFile("Dir::cache::pkgcache");
       if (oldpkgcache.empty() == false && RealFileExists(oldpkgcache) == true &&
@@ -1603,7 +1637,15 @@ bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress)
       }
    }
 
       }
    }
 
-   Cache.writeStateFile(NULL);
+   // disappearing packages can forward their auto-bit
+   if (disappearedPkgs.empty() == false)
+      Cache.writeStateFile(NULL);
+
+   d->progress->Stop();
+
+   if (RunScripts("DPkg::Post-Invoke") == false)
+      return false;
+
    return d->dpkg_error.empty();
 }
 
    return d->dpkg_error.empty();
 }
 
@@ -1614,7 +1656,7 @@ void SigINT(int /*sig*/) {
 // pkgDpkgPM::Reset - Dump the contents of the command list            /*{{{*/
 // ---------------------------------------------------------------------
 /* */
 // pkgDpkgPM::Reset - Dump the contents of the command list            /*{{{*/
 // ---------------------------------------------------------------------
 /* */
-void pkgDPkgPM::Reset() 
+void pkgDPkgPM::Reset()
 {
    List.erase(List.begin(),List.end());
 }
 {
    List.erase(List.begin(),List.end());
 }
@@ -1622,7 +1664,7 @@ void pkgDPkgPM::Reset()
 // pkgDpkgPM::WriteApportReport - write out error report pkg failure   /*{{{*/
 // ---------------------------------------------------------------------
 /* */
 // pkgDpkgPM::WriteApportReport - write out error report pkg failure   /*{{{*/
 // ---------------------------------------------------------------------
 /* */
-void pkgDPkgPM::WriteApportReport(const char *pkgpath, const char *errormsg) 
+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
 {
    // If apport doesn't exist or isn't installed do nothing
    // This e.g. prevents messages in 'universes' without apport
@@ -1647,20 +1689,20 @@ void pkgDPkgPM::WriteApportReport(const char *pkgpath, const char *errormsg)
       return;
    }
 
       return;
    }
 
-   // check if its not a follow up error 
+   // check if its not a follow up error
    const char *needle = dgettext("dpkg", "dependency problems - leaving unconfigured");
    if(strstr(errormsg, needle) != NULL) {
       std::clog << _("No apport report written because the error message indicates its a followup error from a previous failure.") << std::endl;
       return;
    }
 
    const char *needle = dgettext("dpkg", "dependency problems - leaving unconfigured");
    if(strstr(errormsg, needle) != NULL) {
       std::clog << _("No apport report written because the error message indicates its a followup error from a previous failure.") << std::endl;
       return;
    }
 
-   // do not report disk-full failures 
+   // do not report disk-full failures
    if(strstr(errormsg, strerror(ENOSPC)) != NULL) {
       std::clog << _("No apport report written because the error message indicates a disk full error") << std::endl;
       return;
    }
 
    if(strstr(errormsg, strerror(ENOSPC)) != NULL) {
       std::clog << _("No apport report written because the error message indicates a disk full error") << std::endl;
       return;
    }
 
-   // do not report out-of-memory failures 
+   // do not report out-of-memory failures
    if(strstr(errormsg, strerror(ENOMEM)) != NULL ||
       strstr(errormsg, "failed to allocate memory") != NULL) {
       std::clog << _("No apport report written because the error message indicates a out of memory error") << std::endl;
    if(strstr(errormsg, strerror(ENOMEM)) != NULL ||
       strstr(errormsg, "failed to allocate memory") != NULL) {
       std::clog << _("No apport report written because the error message indicates a out of memory error") << std::endl;
@@ -1696,7 +1738,7 @@ void pkgDPkgPM::WriteApportReport(const char *pkgpath, const char *errormsg)
          // to kill the "s" manually
          if (list[1].size() > 1) {
             list[1].erase(0, 1);
          // to kill the "s" manually
          if (list[1].size() > 1) {
             list[1].erase(0, 1);
-            if(strstr(errormsg, list[0].c_str()) && 
+            if(strstr(errormsg, list[0].c_str()) &&
                strstr(errormsg, list[1].c_str())) {
                std::clog << _("No apport report written because the error message indicates a dpkg I/O error") << std::endl;
                return;
                strstr(errormsg, list[1].c_str())) {
                std::clog << _("No apport report written because the error message indicates a dpkg I/O error") << std::endl;
                return;
@@ -1726,7 +1768,8 @@ void pkgDPkgPM::WriteApportReport(const char *pkgpath, const char *errormsg)
    //    we overwrite it. This is the same behaviour as apport
    // - if we have a report with the same pkgversion already
    //   then we skip it
    //    we overwrite it. This is the same behaviour as apport
    // - if we have a report with the same pkgversion already
    //   then we skip it
-   reportfile = flCombine("/var/crash",pkgname+".0.crash");
+   _config->CndSet("Dir::Apport", "var/crash");
+   reportfile = flCombine(_config->FindDir("Dir::Apport", "var/crash"), pkgname+".0.crash");
    if(FileExists(reportfile))
    {
       struct stat buf;
    if(FileExists(reportfile))
    {
       struct stat buf;