]> git.saurik.com Git - apt.git/commitdiff
move pty magic into its own functions
authorMichael Vogt <mvo@debian.org>
Thu, 31 Oct 2013 20:03:33 +0000 (21:03 +0100)
committerMichael Vogt <mvo@debian.org>
Thu, 31 Oct 2013 20:03:33 +0000 (21:03 +0100)
1  2 
apt-pkg/deb/dpkgpm.cc
apt-pkg/deb/dpkgpm.h

diff --combined apt-pkg/deb/dpkgpm.cc
index b252c02ebef52824ab81ab901705130e84185ec5,ddfc7c04e34f6e024e2c0e3da2c37c23bd763033..d1b11098c5304f5a8316ff478c8a3226cbb4fa8d
@@@ -19,7 -19,6 +19,7 @@@
  #include <apt-pkg/fileutl.h>
  #include <apt-pkg/cachefile.h>
  #include <apt-pkg/packagemanager.h>
 +#include <apt-pkg/install-progress.h>
  
  #include <unistd.h>
  #include <stdlib.h>
@@@ -55,12 -54,16 +55,12 @@@ class pkgDPkgPMPrivat
  public:
     pkgDPkgPMPrivate() : stdin_is_dev_null(false), dpkgbuf_pos(0),
                        term_out(NULL), history_out(NULL), 
-                         progress(NULL)
 -                        last_reported_progress(0.0), nr_terminal_rows(0),
 -                        fancy_progress_output(false), master(-1), slave(-1)
++                        progress(NULL), master(-1), slave(-1)
     {
        dpkgbuf[0] = '\0';
 -      if(_config->FindB("Dpkg::Progress-Fancy", false) == true)
 -      {
 -         fancy_progress_output = true;
 -         _config->Set("DpkgPM::Progress", true);
 -      }
 -
 +   }
 +   ~pkgDPkgPMPrivate()
 +   {
     }
     bool stdin_is_dev_null;
     // the buffer we use for the dpkg status-fd reading
     FILE *term_out;
     FILE *history_out;
     string dpkg_error;
 -
 -   float last_reported_progress;
 -   int nr_terminal_rows;
 -   bool fancy_progress_output;
 +   APT::Progress::PackageManager *progress;
+    // pty stuff
+    struct     termios tt;
+    int master;
+    int slave;
+    // signals
+    sigset_t sigmask;
+    sigset_t original_sigmask;
  };
  
  namespace
@@@ -132,20 -148,6 +142,20 @@@ 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()
  {
@@@ -522,7 -524,7 +532,7 @@@ void pkgDPkgPM::DoTerminalPty(int maste
  // ---------------------------------------------------------------------
  /*
   */
 -void pkgDPkgPM::ProcessDpkgStatusLine(int OutStatusFd, char *line)
 +void pkgDPkgPM::ProcessDpkgStatusLine(char *line)
  {
     bool const Debug = _config->FindB("Debug::pkgDPkgProgressReporting",false);
     if (Debug == true)
     {
        pkgname = APT::String::Strip(list[2]);
        action = APT::String::Strip(list[1]);
 -
 -      // this is what we support in the processing stage
 -      if(action != "install" && action != "configure" &&
 -         action != "remove" && action != "purge" && action != "purge")
 -      {
 -         if (Debug == true)
 -            std::clog << "ignoring processing action: '" << action
 -                      << "'" << std::endl;
 -         return;
 -      }
     }
     // "status" has the form: "status: pkg: state"
     // with state in ["half-installed", "unpacked", "half-configured", 
     {
        if(action == "error")
        {
 -         status << "pmerror:" << list[1]
 -                << ":"  << (PackagesDone/float(PackagesTotal)*100.0) 
 -                << ":" << list[3]
 -                << endl;
 -         if(OutStatusFd > 0)
 -            FileFd::Write(OutStatusFd, status.str().c_str(), status.str().size());
 -         if (Debug == true)
 -            std::clog << "send: '" << status.str() << "'" << endl;
 +         d->progress->Error(list[1], PackagesDone, PackagesTotal,
 +                            list[3]);
           pkgFailures++;
           WriteApportReport(list[1].c_str(), list[3].c_str());
           return;
        }
        else if(action == "conffile")
        {
 -         status << "pmconffile:" << list[1]
 -                << ":"  << (PackagesDone/float(PackagesTotal)*100.0) 
 -                << ":" << list[3]
 -                << endl;
 -         if(OutStatusFd > 0)
 -            FileFd::Write(OutStatusFd, status.str().c_str(), status.str().size());
 -         if (Debug == true)
 -            std::clog << "send: '" << status.str() << "'" << endl;
 +         d->progress->ConffilePrompt(list[1], PackagesDone, PackagesTotal,
 +                                     list[3]);
           return;
        }
     }
         return;
        }
        std::string msg;
 -      strprintf(msg, _(iter->second), short_pkgname.c_str());
 -
 -      status << "pmstatus:" << short_pkgname
 -           << ":"  << (PackagesDone/float(PackagesTotal)*100.0) 
 -           << ":" << msg
 -           << endl;
 -      if(OutStatusFd > 0)
 -       FileFd::Write(OutStatusFd, status.str().c_str(), status.str().size());
 -      if (Debug == true)
 -       std::clog << "send: '" << status.str() << "'" << endl;
 +      strprintf(msg, _(iter->second), i18n_pkgname.c_str());
 +      d->progress->StatusChanged(pkgname, PackagesDone, PackagesTotal, msg);
  
        // FIXME: this needs a muliarch testcase
        // FIXME2: is "pkgname" here reliable with dpkg only sending us 
           // action
           const char *translation = _(states[PackageOpsDone[pkg]].str);
           std::string msg;
 -         strprintf(msg, translation, short_pkgname.c_str());
 -         
 +
           // we moved from one dpkg state to a new one, report that
           PackageOpsDone[pkg]++;
           PackagesDone++;
 -         // build the status str
 -         status << "pmstatus:" << short_pkgname
 -                << ":"  << (PackagesDone/float(PackagesTotal)*100.0) 
 -                << ":" << msg
 -                << endl;
 -         if(_config->FindB("DPkgPM::Progress", false) == true)
 -            SendTerminalProgress(PackagesDone/float(PackagesTotal)*100.0);
 +
 +         strprintf(msg, translation, i18n_pkgname.c_str());
 +         d->progress->StatusChanged(pkgname, PackagesDone, PackagesTotal, msg);
           
 -         if(OutStatusFd > 0)
 -            FileFd::Write(OutStatusFd, status.str().c_str(), status.str().size());
 -         if (Debug == true)
 -            std::clog << "send: '" << status.str() << "'" << endl;
        }
        if (Debug == true) 
           std::clog << "(parsed from dpkg) pkg: " << short_pkgname
  // DPkgPM::handleDisappearAction                                      /*{{{*/
  void pkgDPkgPM::handleDisappearAction(string const &pkgname)
  {
 -   // record the package name for display and stuff later
 -   disappearedPkgs.insert(pkgname);
 -
     pkgCache::PkgIterator Pkg = Cache.FindPkg(pkgname);
     if (unlikely(Pkg.end() == true))
        return;
 +
 +   // record the package name for display and stuff later
 +   disappearedPkgs.insert(Pkg.FullName(true));
 +
     // the disappeared package was auto-installed - nothing to do
     if ((Cache[Pkg].Flags & pkgCache::Flag::Auto) == pkgCache::Flag::Auto)
        return;
  // ---------------------------------------------------------------------
  /*
   */
 -void pkgDPkgPM::DoDpkgStatusFd(int statusfd, int OutStatusFd)
 +void pkgDPkgPM::DoDpkgStatusFd(int statusfd)
  {
     char *p, *q;
     int len;
     while((q=(char*)memchr(p, '\n', d->dpkgbuf+d->dpkgbuf_pos-p)) != NULL)
     {
        *q = 0;
 -      ProcessDpkgStatusLine(OutStatusFd, p);
 +      ProcessDpkgStatusLine(p);
        p=q+1; // continue with next line
     }
  
@@@ -924,6 -964,50 +934,6 @@@ bool pkgDPkgPM::CloseLog(
     return true;
  }
                                                                        /*}}}*/
 -// DPkgPM::SendTerminalProgress                                       /*{{{*/
 -// ---------------------------------------------------------------------
 -/* Send progress info to the terminal
 - */
 -void pkgDPkgPM::SendTerminalProgress(float percentage)
 -{
 -   int reporting_steps = _config->FindI("DpkgPM::Reporting-Steps", 1);
 -
 -   if(percentage < (d->last_reported_progress + reporting_steps))
 -      return;
 -
 -   std::string progress_str;
 -   strprintf(progress_str, _("Progress: [%3i%%]"), (int)percentage);
 -   if (d->fancy_progress_output)
 -   {
 -         int row = d->nr_terminal_rows;
 -
 -         static string save_cursor = "\033[s";
 -         static string restore_cursor = "\033[u";
 -
 -         static string set_bg_color = "\033[42m"; // green
 -         static string set_fg_color = "\033[30m"; // black
 -
 -         static string restore_bg =  "\033[49m";
 -         static string restore_fg = "\033[39m";
 -
 -         std::cout << save_cursor
 -            // move cursor position to last row
 -                   << "\033[" << row << ";0f" 
 -                   << set_bg_color
 -                   << set_fg_color
 -                   << progress_str
 -                   << restore_cursor
 -                   << restore_bg
 -                   << restore_fg;
 -   }
 -   else
 -   {
 -         std::cout << progress_str << "\r\n";
 -   }
 -   std::flush(std::cout);
 -                   
 -   d->last_reported_progress = percentage;
 -}
                                                                        /*}}}*/
  /*{{{*/
  // This implements a racy version of pselect for those architectures
@@@ -945,98 -1029,128 +955,150 @@@ static int racy_pselect(int nfds, fd_se
     sigprocmask(SIG_SETMASK, &origmask, 0);
     return retval;
  }
 -/*}}}*/
 +                                                                        /*}}}*/
  
 -void pkgDPkgPM::SetupTerminalScrollArea(int nr_rows)
 +// DPkgPM::BuildPackagesProgressMap                                   /*{{{*/
 +void pkgDPkgPM::BuildPackagesProgressMap()
  {
 -     if(!d->fancy_progress_output)
 -        return;
 -
 -     // scroll down a bit to avoid visual glitch when the screen
 -     // area shrinks by one row
 -     std::cout << "\n";
 -         
 -     // save cursor
 -     std::cout << "\033[s";
 -         
 -     // set scroll region (this will place the cursor in the top left)
 -     std::cout << "\033[1;" << nr_rows - 1 << "r";
 -            
 -     // restore cursor but ensure its inside the scrolling area
 -     std::cout << "\033[u";
 -     static const char *move_cursor_up = "\033[1A";
 -     std::cout << move_cursor_up;
 -     std::flush(std::cout);
 -}
 +   // 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] = {
 +      // Install operation
 +      { 
 +       {"half-installed", N_("Preparing %s")}, 
 +       {"unpacked", N_("Unpacking %s") }, 
 +       {NULL, NULL}
 +      },
 +      // Configure operation
 +      { 
 +       {"unpacked",N_("Preparing to configure %s") },
 +       {"half-configured", N_("Configuring %s") },
 +       { "installed", N_("Installed %s")},
 +       {NULL, NULL}
 +      },
 +      // Remove operation
 +      { 
 +       {"half-configured", N_("Preparing for removal of %s")},
 +       {"half-installed", N_("Removing %s")},
 +       {"config-files",  N_("Removed %s")},
 +       {NULL, NULL}
 +      },
 +      // Purge operation
 +      { 
 +       {"config-files", N_("Preparing to completely remove %s")},
 +       {"not-installed", N_("Completely removed %s")},
 +       {NULL, NULL}
 +      },
 +   };
  
 -void pkgDPkgPM::CleanupTerminal()
 -{
 -   // reset scroll area
 -   SetupTerminalScrollArea(d->nr_terminal_rows + 1);
 -   if(d->fancy_progress_output)
 +   // 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)
     {
 -      // override the progress line (sledgehammer)
 -      static const char* clear_screen_below_cursor = "\033[J";
 -      std::cout << clear_screen_below_cursor;
 -      std::flush(std::cout);
 +      if((*I).Pkg.end() == true)
 +       continue;
 +
 +      string const name = (*I).Pkg.FullName();
 +      PackageOpsDone[name] = 0;
 +      for(int i=0; (DpkgStatesOpMap[(*I).Op][i]).state != NULL; ++i)
 +      {
 +       PackageOps[name].push_back(DpkgStatesOpMap[(*I).Op][i]);
 +       PackagesTotal++;
 +      }
     }
  }
 +                                                                        /*}}}*/
 +#if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR < 13)
 +bool pkgDPkgPM::Go(int StatusFd)
 +{
 +   APT::Progress::PackageManager *progress = NULL;
 +   if (StatusFd == -1)
 +      progress = APT::Progress::PackageManagerProgressFactory();
 +   else
 +      progress = new APT::Progress::PackageManagerProgressFd(StatusFd);
 +   
 +   return GoNoABIBreak(progress);
 +}
 +#endif
  
 -       d->nr_terminal_rows = win.ws_row;
+ void pkgDPkgPM::StartPtyMagic()
+ {
+    // setup the pty and stuff
+    struct     winsize win;
+    // if tcgetattr does not return zero there was a error
+    // and we do not do any pty magic
+    _error->PushToStack();
+    if (tcgetattr(STDOUT_FILENO, &d->tt) == 0)
+    {
+        ioctl(1, TIOCGWINSZ, (char *)&win);
 -
 -      // setup terminal
 -      SetupTerminalScrollArea(d->nr_terminal_rows);
+        if (openpty(&d->master, &d->slave, NULL, &d->tt, &win) < 0)
+        {
+            _error->Errno("openpty", _("Can not write log (%s)"), _("Is /dev/pts mounted?"));
+            d->master = d->slave = -1;
+         } else {
+           struct termios rtt;
+           rtt = d->tt;
+           cfmakeraw(&rtt);
+           rtt.c_lflag &= ~ECHO;
+           rtt.c_lflag |= ISIG;
+           // block SIGTTOU during tcsetattr to prevent a hang if
+           // the process is a member of the background process group
+           // http://www.opengroup.org/onlinepubs/000095399/functions/tcsetattr.html
+           sigemptyset(&d->sigmask);
+           sigaddset(&d->sigmask, SIGTTOU);
+           sigprocmask(SIG_BLOCK,&d->sigmask, &d->original_sigmask);
+           tcsetattr(0, TCSAFLUSH, &rtt);
+           sigprocmask(SIG_SETMASK, &d->original_sigmask, 0);
+         }
+       }
+    // complain only if stdout is either a terminal (but still failed) or is an invalid
+       // descriptor otherwise we would complain about redirection to e.g. /dev/null as well.
+       else if (isatty(STDOUT_FILENO) == 1 || errno == EBADF)
+          _error->Errno("tcgetattr", _("Can not write log (%s)"), _("Is stdout a terminal?"));
+       if (_error->PendingError() == true)
+        _error->DumpErrors(std::cerr);
+       _error->RevertToStack();
+ }
+ void pkgDPkgPM::StopPtyMagic()
+ {
+    if(d->slave > 0)
+       close(d->slave);
+    if(d->master >= 0) 
+    {
+       tcsetattr(0, TCSAFLUSH, &d->tt);
+       close(d->master);
+    }
+ }
  // DPkgPM::Go - Run the sequence                                      /*{{{*/
  // ---------------------------------------------------------------------
  /* This globs the operations and calls dpkg 
 - *   
 - * If it is called with "OutStatusFd" set to a valid file descriptor
 - * apt will report the install progress over this fd. It maps the
 - * dpkg states a package goes through to human readable (and i10n-able)
 + *
 + * 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
 + * through to human readable (and i10n-able)
   * names and calculates a percentage for each step.
 -*/
 -bool pkgDPkgPM::Go(int OutStatusFd)
 + */
 +#if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR >= 13)
 +bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress)
 +#else
 +bool pkgDPkgPM::GoNoABIBreak(APT::Progress::PackageManager *progress)
 +#endif
  {
     pkgPackageManager::SigINTStop = false;
 +   d->progress = progress;
  
     // 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();
 +   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");
  
     fd_set rfds;
     struct timespec tv;
-    sigset_t sigmask;
-    sigset_t original_sigmask;
  
     unsigned int const MaxArgs = _config->FindI("Dpkg::MaxArgs",8*1024);
     unsigned int const MaxArgBytes = _config->FindI("Dpkg::MaxArgBytes",32*1024);
     if (_config->FindB("DPkg::ConfigurePending", SmartConf) == true)
        List.push_back(Item(Item::ConfigurePending, PkgIterator()));
  
 -   // 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] = {
 -      // Install operation
 -      { 
 -       {"half-installed", N_("Preparing %s")}, 
 -       {"unpacked", N_("Unpacking %s") }, 
 -       {NULL, NULL}
 -      },
 -      // Configure operation
 -      { 
 -       {"unpacked",N_("Preparing to configure %s") },
 -       {"half-configured", N_("Configuring %s") },
 -       { "installed", N_("Installed %s")},
 -       {NULL, NULL}
 -      },
 -      // Remove operation
 -      { 
 -       {"half-configured", N_("Preparing for removal of %s")},
 -       {"half-installed", N_("Removing %s")},
 -       {"config-files",  N_("Removed %s")},
 -       {NULL, NULL}
 -      },
 -      // Purge operation
 -      { 
 -       {"config-files", N_("Preparing to completely remove %s")},
 -       {"not-installed", N_("Completely removed %s")},
 -       {NULL, NULL}
 -      },
 -   };
 -
 -   // 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)
 -   {
 -      if((*I).Pkg.end() == true)
 -       continue;
 -
 -      string const name = (*I).Pkg.FullName();
 -      PackageOpsDone[name] = 0;
 -      for(int i=0; (DpkgStatesOpMap[(*I).Op][i]).state != NULL; ++i)
 -      {
 -       PackageOps[name].push_back(DpkgStatesOpMap[(*I).Op][i]);
 -       PackagesTotal++;
 -      }
 -   }
 +   // for the progress
 +   BuildPackagesProgressMap();
  
     d->stdin_is_dev_null = false;
  
         dpkgMultiArch = true;
     }
  
-    // go over each item
+    // start pty magic before the loop
+    StartPtyMagic();
++   // Tell the progress that its starting and fork dpkg 
++   d->progress->Start();
++
+    // this loop is runs once per dpkg operation
     vector<Item>::const_iterator I = List.begin();
     while (I != List.end())
     {
         {
            if((*I).Pkg.end() == true)
               continue;
 -          if (I->Op == Item::Configure && disappearedPkgs.find(I->Pkg.Name()) != disappearedPkgs.end())
 +          if (I->Op == Item::Configure && disappearedPkgs.find(I->Pkg.FullName(true)) != disappearedPkgs.end())
               continue;
            // We keep this here to allow "smooth" transitions from e.g. multiarch dpkg/ubuntu to dpkg/debian
            if (dpkgMultiArch == false && (I->Pkg.Arch() == nativeArch ||
        // ignore SIGHUP as well (debian #463030)
        sighandler_t old_SIGHUP = signal(SIGHUP,SIG_IGN);
  
-       struct  termios tt;
-       struct  winsize win;
-       int     master = -1;
-       int     slave = -1;
-       // if tcgetattr does not return zero there was a error
-       // and we do not do any pty magic
-       _error->PushToStack();
-       if (tcgetattr(STDOUT_FILENO, &tt) == 0)
-       {
-        ioctl(STDOUT_FILENO, TIOCGWINSZ, (char *)&win);
-        if (openpty(&master, &slave, NULL, &tt, &win) < 0)
-        {
-           _error->Errno("openpty", _("Can not write log (%s)"), _("Is /dev/pts mounted?"));
-           master = slave = -1;
-        }  else {
-           struct termios rtt;
-           rtt = tt;
-           cfmakeraw(&rtt);
-           rtt.c_lflag &= ~ECHO;
-           rtt.c_lflag |= ISIG;
-           // block SIGTTOU during tcsetattr to prevent a hang if
-           // the process is a member of the background process group
-           // http://www.opengroup.org/onlinepubs/000095399/functions/tcsetattr.html
-           sigemptyset(&sigmask);
-           sigaddset(&sigmask, SIGTTOU);
-           sigprocmask(SIG_BLOCK,&sigmask, &original_sigmask);
-           tcsetattr(0, TCSAFLUSH, &rtt);
-           sigprocmask(SIG_SETMASK, &original_sigmask, 0);
-        }
-       }
-       // complain only if stdout is either a terminal (but still failed) or is an invalid
-       // descriptor otherwise we would complain about redirection to e.g. /dev/null as well.
-       else if (isatty(STDOUT_FILENO) == 1 || errno == EBADF)
-          _error->Errno("tcgetattr", _("Can not write log (%s)"), _("Is stdout a terminal?"));
-       if (_error->PendingError() == true)
-        _error->DumpErrors(std::cerr);
-       _error->RevertToStack();
-       // this is the dpkg status-fd, we need to keep it
 -       // Fork dpkg
 -      pid_t Child;
--      _config->Set("APT::Keep-Fds::",fd[1]);
-       // Tell the progress that its starting and fork dpkg 
-       // FIXME: this is called once per dpkg run which is *too often*
-       d->progress->Start();
 -      // send status information that we are about to fork dpkg
 -      if(OutStatusFd > 0) {
 -       ostringstream status;
 -       status << "pmstatus:dpkg-exec:" 
 -              << (PackagesDone/float(PackagesTotal)*100.0) 
 -              << ":" << _("Running dpkg")
 -              << endl;
 -       FileFd::Write(OutStatusFd, status.str().c_str(), status.str().size());
 -      }
--
 -      Child = ExecFork();
 +      pid_t Child = ExecFork();
        // This is the child
        if (Child == 0)
        {
  
-        if(slave >= 0 && master >= 0) 
+        if(d->slave >= 0 && d->master >= 0) 
         {
            setsid();
-           ioctl(slave, TIOCSCTTY, 0);
-           close(master);
-           dup2(slave, 0);
-           dup2(slave, 1);
-           dup2(slave, 2);
-           close(slave);
+           ioctl(d->slave, TIOCSCTTY, 0);
+           close(d->master);
+           dup2(d->slave, 0);
+           dup2(d->slave, 1);
+           dup2(d->slave, 2);
+           close(d->slave);
         }
         close(fd[0]); // close the read end of the pipe
  
            if (fcntl(STDIN_FILENO,F_SETFL,Flags & (~(long)O_NONBLOCK)) < 0)
               _exit(100);
         }
         /* No Job Control Stop Env is a magic dpkg var that prevents it
            from using sigstop */
         putenv((char *)"DPKG_NO_TSTP=yes");
        int const _dpkgin = fd[0];
        close(fd[1]);                        // close the write end of the pipe
  
-       if(slave > 0)
-        close(slave);
        // setups fds
-       sigemptyset(&sigmask);
-       sigprocmask(SIG_BLOCK,&sigmask,&original_sigmask);
+       sigemptyset(&d->sigmask);
+       sigprocmask(SIG_BLOCK,&d->sigmask,&d->original_sigmask);
  
        /* free vectors (and therefore memory) as we don't need the included data anymore */
        for (std::vector<char *>::const_iterator p = Packages.begin();
  
         // wait for input or output here
         FD_ZERO(&rfds);
-        if (master >= 0 && !d->stdin_is_dev_null)
+        if (d->master >= 0 && !d->stdin_is_dev_null)
            FD_SET(0, &rfds); 
         FD_SET(_dpkgin, &rfds);
-        if(master >= 0)
-           FD_SET(master, &rfds);
-        tv.tv_sec = 0;
-        tv.tv_nsec = d->progress->GetPulseInterval();
-        select_ret = pselect(max(master, _dpkgin)+1, &rfds, NULL, NULL, 
-                             &tv, &original_sigmask);
+        if(d->master >= 0)
+           FD_SET(d->master, &rfds);
+        tv.tv_sec = 1;
+        tv.tv_nsec = 0;
+        select_ret = pselect(max(d->master, _dpkgin)+1, &rfds, NULL, NULL, 
+                             &tv, &d->original_sigmask);
         if (select_ret < 0 && (errno == EINVAL || errno == ENOSYS))
-           select_ret = racy_pselect(max(master, _dpkgin)+1, &rfds, NULL,
-                                     NULL, &tv, &original_sigmask);
-          d->progress->Pulse();
+           select_ret = racy_pselect(max(d->master, _dpkgin)+1, &rfds, NULL,
+                                     NULL, &tv, &d->original_sigmask);
         if (select_ret == 0) 
            continue;
         else if (select_ret < 0 && errno == EINTR)
            continue;
         } 
         
-        if(master >= 0 && FD_ISSET(master, &rfds))
-           DoTerminalPty(master);
-        if(master >= 0 && FD_ISSET(0, &rfds))
-           DoStdin(master);
+        if(d->master >= 0 && FD_ISSET(d->master, &rfds))
+           DoTerminalPty(d->master);
+        if(d->master >= 0 && FD_ISSET(0, &rfds))
+           DoStdin(d->master);
         if(FD_ISSET(_dpkgin, &rfds))
 -          DoDpkgStatusFd(_dpkgin, OutStatusFd);
 +          DoDpkgStatusFd(_dpkgin);
        }
        close(_dpkgin);
  
        signal(SIGINT,old_SIGINT);
        
        signal(SIGHUP,old_SIGHUP);
-       if(master >= 0) 
-       {
-        tcsetattr(0, TCSAFLUSH, &tt);
-        close(master);
-       }
        // Check for an error code.
        if (WIFEXITED(Status) == 0 || WEXITSTATUS(Status) != 0)
        {
         if(stopOnError) 
         {
            CloseLog();
 -            CleanupTerminal();
 +            d->progress->Stop();
            return false;
         }
        }      
     }
--   CloseLog();
--
     // dpkg is done at this point
 -   if(_config->FindB("DPkgPM::Progress", false) == true)
 -      SendTerminalProgress(100);
 -
 -   CleanupTerminal();
 +   d->progress->Stop();
+    StopPtyMagic();
++   CloseLog();
  
     if (pkgPackageManager::SigINTStop)
         _error->Warning(_("Operation was interrupted before it could finish"));
diff --combined apt-pkg/deb/dpkgpm.h
index 50b5d609b36124eb5b7ac38d52c37d0ae9000aac,5551b43832ec6933aa708af970087b72be63d9e0..06318d94f79693261f90c46c1368189afe78e28e
@@@ -15,7 -15,6 +15,7 @@@
  #include <map>
  #include <stdio.h>
  #include <apt-pkg/macros.h>
 +#include <apt-pkg/init.h>
  
  #ifndef APT_8_CLEANER_HEADERS
  using std::vector;
@@@ -24,7 -23,6 +24,7 @@@ using std::map
  
  class pkgDPkgPMPrivate;
  
 +
  class pkgDPkgPM : public pkgPackageManager
  {
     private:
     __deprecated bool SendV2Pkgs(FILE *F);
     bool SendPkgsInfo(FILE * const F, unsigned int const &Version);
     void WriteHistoryTag(std::string const &tag, std::string value);
 +   std::string ExpandShortPackageName(pkgDepCache &Cache,
 +                                      const std::string &short_pkgname);
  
     // Terminal progress 
     void SetupTerminalScrollArea(int nr_scrolled_rows);
     void SendTerminalProgress(float percentage);
 -   void CleanupTerminal();
  
     // apport integration
     void WriteApportReport(const char *pkgpath, const char *errormsg);
     bool OpenLog();
     bool CloseLog();
  
 +   // helper
 +   void BuildPackagesProgressMap();
+    void StartPtyMagic();
+    void StopPtyMagic();
     
     // input processing
     void DoStdin(int master);
     void DoTerminalPty(int master);
 -   void DoDpkgStatusFd(int statusfd, int OutStatusFd);
 -   void ProcessDpkgStatusLine(int OutStatusFd, char *line);
 +   void DoDpkgStatusFd(int statusfd);
 +   void ProcessDpkgStatusLine(char *line);
 +#if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR < 13)
 +   void DoDpkgStatusFd(int statusfd, int unused) {
 +      DoDpkgStatusFd(statusfd);
 +   }
 +   void ProcessDpkgStatusLine(int unused, char *line) {
 +      ProcessDpkgStatusLine(line);
 +   }
 +#endif
 +
  
     // The Actuall installation implementation
     virtual bool Install(PkgIterator Pkg,std::string File);
     virtual bool Configure(PkgIterator Pkg);
     virtual bool Remove(PkgIterator Pkg,bool Purge = false);
 +
 +#if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR >= 13)
 +   virtual bool Go(APT::Progress::PackageManager *progress);
 +#else
     virtual bool Go(int StatusFd=-1);
 +   bool GoNoABIBreak(APT::Progress::PackageManager *progress);
 +#endif
 +
     virtual void Reset();
     
     public: