]> 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

index b252c02ebef52824ab81ab901705130e84185ec5,ddfc7c04e34f6e024e2c0e3da2c37c23bd763033..d1b11098c5304f5a8316ff478c8a3226cbb4fa8d
@@@ -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
@@@ -945,74 -1029,99 +955,126 @@@ 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 
@@@ -1116,7 -1274,10 +1176,13 @@@ bool pkgDPkgPM::GoNoABIBreak(APT::Progr
         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())
     {
        // 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)
        {
            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);
  
         }
        }      
     }
--   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"));
index 50b5d609b36124eb5b7ac38d52c37d0ae9000aac,5551b43832ec6933aa708af970087b72be63d9e0..06318d94f79693261f90c46c1368189afe78e28e
@@@ -99,8 -96,8 +99,10 @@@ class pkgDPkgPM : public pkgPackageMana
     bool OpenLog();
     bool CloseLog();
  
 +   // helper
 +   void BuildPackagesProgressMap();
+    void StartPtyMagic();
+    void StopPtyMagic();
     
     // input processing
     void DoStdin(int master);