Quellcode durchsuchen

move pty magic into its own functions

Michael Vogt vor 12 Jahren
Ursprung
Commit
177296dffd
2 geänderte Dateien mit 97 neuen und 88 gelöschten Zeilen
  1. 95 88
      apt-pkg/deb/dpkgpm.cc
  2. 2 0
      apt-pkg/deb/dpkgpm.h

+ 95 - 88
apt-pkg/deb/dpkgpm.cc

@@ -55,7 +55,7 @@ class pkgDPkgPMPrivate
 public:
    pkgDPkgPMPrivate() : stdin_is_dev_null(false), dpkgbuf_pos(0),
 			term_out(NULL), history_out(NULL), 
-                        progress(NULL)
+                        progress(NULL), master(-1), slave(-1)
    {
       dpkgbuf[0] = '\0';
    }
@@ -70,6 +70,16 @@ public:
    FILE *history_out;
    string dpkg_error;
    APT::Progress::PackageManager *progress;
+
+   // pty stuff
+   struct	termios tt;
+   int master;
+   int slave;
+
+   // signals
+   sigset_t sigmask;
+   sigset_t original_sigmask;
+
 };
 
 namespace
@@ -1013,6 +1023,58 @@ bool pkgDPkgPM::Go(int StatusFd)
 }
 #endif
 
+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);
+       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 
@@ -1073,8 +1135,6 @@ bool pkgDPkgPM::GoNoABIBreak(APT::Progress::PackageManager *progress)
 
    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);
@@ -1116,7 +1176,13 @@ bool pkgDPkgPM::GoNoABIBreak(APT::Progress::PackageManager *progress)
 	 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())
    {
@@ -1309,67 +1375,20 @@ bool pkgDPkgPM::GoNoABIBreak(APT::Progress::PackageManager *progress)
       // 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
-      _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();
-
       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
 
@@ -1393,6 +1412,7 @@ bool pkgDPkgPM::GoNoABIBreak(APT::Progress::PackageManager *progress)
 	    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");
@@ -1415,12 +1435,9 @@ bool pkgDPkgPM::GoNoABIBreak(APT::Progress::PackageManager *progress)
       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();
@@ -1449,21 +1466,18 @@ bool pkgDPkgPM::GoNoABIBreak(APT::Progress::PackageManager *progress)
 
 	 // 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)
@@ -1474,10 +1488,10 @@ bool pkgDPkgPM::GoNoABIBreak(APT::Progress::PackageManager *progress)
   	    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);
       }
@@ -1488,13 +1502,6 @@ bool pkgDPkgPM::GoNoABIBreak(APT::Progress::PackageManager *progress)
       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)
       {
@@ -1524,10 +1531,10 @@ bool pkgDPkgPM::GoNoABIBreak(APT::Progress::PackageManager *progress)
 	 }
       }      
    }
-   CloseLog();
-
    // dpkg is done at this point
    d->progress->Stop();
+   StopPtyMagic();
+   CloseLog();
 
    if (pkgPackageManager::SigINTStop)
        _error->Warning(_("Operation was interrupted before it could finish"));

+ 2 - 0
apt-pkg/deb/dpkgpm.h

@@ -101,6 +101,8 @@ class pkgDPkgPM : public pkgPackageManager
 
    // helper
    void BuildPackagesProgressMap();
+   void StartPtyMagic();
+   void StopPtyMagic();
    
    // input processing
    void DoStdin(int master);