]> git.saurik.com Git - apt.git/blobdiff - apt-pkg/deb/dpkgpm.cc
always run 'dpkg --configure -a' at the end of our dpkg callings
[apt.git] / apt-pkg / deb / dpkgpm.cc
index a5c05d5eadcb93f668d7a13513d027bf2a9bd67c..79120f6f58fbc5afaa2d43955220325107dfab69 100644 (file)
 
 using namespace std;
 
+APT_PURE static unsigned int
+EnvironmentSize()
+{
+  unsigned int size = 0;
+  char **envp = environ;
+
+  while (*envp != NULL)
+    size += strlen (*envp++) + 1;
+
+  return size;
+}
+
 class pkgDPkgPMPrivate 
 {
 public:
    pkgDPkgPMPrivate() : stdin_is_dev_null(false), dpkgbuf_pos(0),
                        term_out(NULL), history_out(NULL),
-                        progress(NULL), master(-1), slave(NULL)
+                       progress(NULL), tt_is_valid(false), master(-1),
+                       slave(NULL), protect_slave_from_dying(-1)
    {
       dpkgbuf[0] = '\0';
    }
@@ -78,8 +91,10 @@ public:
 
    // pty stuff
    struct termios tt;
+   bool tt_is_valid;
    int master;
    char * slave;
+   int protect_slave_from_dying;
 
    // signals
    sigset_t sigmask;
@@ -186,18 +201,10 @@ pkgCache::VerIterator FindNowVersion(const pkgCache::PkgIterator &Pkg)
 {
    pkgCache::VerIterator Ver;
    for (Ver = Pkg.VersionList(); Ver.end() == false; ++Ver)
-   {
-      pkgCache::VerFileIterator Vf = Ver.FileList();
-      pkgCache::PkgFileIterator F = Vf.File();
-      for (F = Vf.File(); F.end() == false; ++F)
-      {
-         if (F && F.Archive())
-         {
-            if (strcmp(F.Archive(), "now")) 
-               return Ver;
-         }
-      }
-   }
+      for (pkgCache::VerFileIterator Vf = Ver.FileList(); Vf.end() == false; ++Vf)
+        for (pkgCache::PkgFileIterator F = Vf.File(); F.end() == false; ++F)
+           if (F->Archive != 0 && strcmp(F.Archive(), "now") == 0)
+              return Ver;
    return Ver;
 }
                                                                        /*}}}*/
@@ -1032,6 +1039,12 @@ void pkgDPkgPM::BuildPackagesProgressMap()
         PackagesTotal++;
       }
    }
+   /* 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
+      while showing 100%. Also, spindown takes a while, so never reaching 100%
+      is way more correct than reaching 100% while still doing stuff even if
+      doing it this way is slightly bending the rules */
+   ++PackagesTotal;
 }
                                                                         /*}}}*/
 bool pkgDPkgPM::Go(int StatusFd)
@@ -1057,47 +1070,40 @@ void pkgDPkgPM::StartPtyMagic()
    }
 
    _error->PushToStack();
-   // if tcgetattr for both stdin/stdout returns 0 (no error)
-   // we do the pty magic
-   if (tcgetattr(STDOUT_FILENO, &d->tt) == 0 &&
-        tcgetattr(STDIN_FILENO, &d->tt) == 0)
+
+   d->master = posix_openpt(O_RDWR | O_NOCTTY);
+   if (d->master == -1)
+      _error->Errno("posix_openpt", _("Can not write log (%s)"), _("Is /dev/pts mounted?"));
+   else if (unlockpt(d->master) == -1)
+      _error->Errno("unlockpt", "Unlocking the slave of master fd %d failed!", d->master);
+   else
    {
-      d->master = posix_openpt(O_RDWR | O_NOCTTY);
-      if (d->master == -1)
-        _error->Errno("posix_openpt", _("Can not write log (%s)"), _("Is /dev/pts mounted?"));
-      else if (unlockpt(d->master) == -1)
-      {
-        _error->Errno("unlockpt", "Unlocking the slave of master fd %d failed!", d->master);
-        close(d->master);
-        d->master = -1;
-      }
+      char const * const slave_name = ptsname(d->master);
+      if (slave_name == NULL)
+        _error->Errno("ptsname", "Getting name for slave of master fd %d failed!", d->master);
       else
       {
-        char const * const slave_name = ptsname(d->master);
-        if (slave_name == NULL)
+        d->slave = strdup(slave_name);
+        if (d->slave == NULL)
+           _error->Errno("strdup", "Copying name %s for slave of master fd %d failed!", slave_name, d->master);
+        else if (grantpt(d->master) == -1)
+           _error->Errno("grantpt", "Granting access to slave %s based on master fd %d failed!", slave_name, d->master);
+        else if (tcgetattr(STDIN_FILENO, &d->tt) == 0)
         {
-           _error->Errno("unlockpt", "Getting name for slave of master fd %d failed!", d->master);
-           close(d->master);
-           d->master = -1;
-        }
-        else
-        {
-           d->slave = strdup(slave_name);
-           if (d->slave == NULL)
+           d->tt_is_valid = true;
+           struct termios raw_tt;
+           // copy window size of stdout if its a 'good' terminal
+           if (tcgetattr(STDOUT_FILENO, &raw_tt) == 0)
            {
-              _error->Errno("strdup", "Copying name %s for slave of master fd %d failed!", slave_name, d->master);
-              close(d->master);
-              d->master = -1;
+              struct winsize win;
+              if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) < 0)
+                 _error->Errno("ioctl", "Getting TIOCGWINSZ from stdout failed!");
+              if (ioctl(d->master, TIOCSWINSZ, &win) < 0)
+                 _error->Errno("ioctl", "Setting TIOCSWINSZ for master fd %d failed!", d->master);
            }
-           struct winsize win;
-           if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) < 0)
-              _error->Errno("ioctl", "Getting TIOCGWINSZ from stdout failed!");
-           if (ioctl(d->master, TIOCSWINSZ, &win) < 0)
-              _error->Errno("ioctl", "Setting TIOCSWINSZ for master fd %d failed!", d->master);
            if (tcsetattr(d->master, TCSANOW, &d->tt) == -1)
               _error->Errno("tcsetattr", "Setting in Start via TCSANOW for master fd %d failed!", d->master);
 
-           struct termios raw_tt;
            raw_tt = d->tt;
            cfmakeraw(&raw_tt);
            raw_tt.c_lflag &= ~ECHO;
@@ -1109,18 +1115,22 @@ void pkgDPkgPM::StartPtyMagic()
            sigaddset(&d->sigmask, SIGTTOU);
            sigprocmask(SIG_BLOCK,&d->sigmask, &d->original_sigmask);
            if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw_tt) == -1)
-              _error->Errno("tcsetattr", "Setting in Start via TCSAFLUSH for stdout failed!");
+              _error->Errno("tcsetattr", "Setting in Start via TCSAFLUSH for stdin failed!");
            sigprocmask(SIG_SETMASK, &d->original_sigmask, NULL);
+
+        }
+        if (d->slave != NULL)
+        {
+           /* on linux, closing (and later reopening) all references to the slave
+              makes the slave a death end, so we open it here to have one open all
+              the time. We could use this fd in SetupSlavePtyMagic() for linux, but
+              on kfreebsd we get an incorrect ("step like") output then while it has
+              no problem with closing all references… so to avoid platform specific
+              code here we combine both and be happy once more */
+           d->protect_slave_from_dying = open(d->slave, O_RDWR | O_CLOEXEC);
         }
       }
    }
-   else
-   {
-      // 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.
-      if (isatty(STDOUT_FILENO) == 1 || errno == EBADF)
-        _error->Errno("tcgetattr", _("Can not write log (%s)"), _("Is stdout a terminal?"));
-   }
 
    if (_error->PendingError() == true)
    {
@@ -1129,25 +1139,30 @@ void pkgDPkgPM::StartPtyMagic()
         close(d->master);
         d->master = -1;
       }
+      if (d->slave != NULL)
+      {
+        free(d->slave);
+        d->slave = NULL;
+      }
       _error->DumpErrors(std::cerr);
    }
    _error->RevertToStack();
 }
 void pkgDPkgPM::SetupSlavePtyMagic()
 {
-   if(d->master == -1)
+   if(d->master == -1 || d->slave == NULL)
       return;
 
    if (close(d->master) == -1)
       _error->FatalE("close", "Closing master %d in child failed!", d->master);
+   d->master = -1;
    if (setsid() == -1)
       _error->FatalE("setsid", "Starting a new session for child failed!");
 
    int const slaveFd = open(d->slave, O_RDWR);
    if (slaveFd == -1)
       _error->FatalE("open", _("Can not write log (%s)"), _("Is /dev/pts mounted?"));
-
-   if (ioctl(slaveFd, TIOCSCTTY, 0) < 0)
+   else if (ioctl(slaveFd, TIOCSCTTY, 0) < 0)
       _error->FatalE("ioctl", "Setting TIOCSCTTY for slave fd %d failed!", slaveFd);
    else
    {
@@ -1155,18 +1170,26 @@ void pkgDPkgPM::SetupSlavePtyMagic()
         if (dup2(slaveFd, i) == -1)
            _error->FatalE("dup2", "Dupping %d to %d in child failed!", slaveFd, i);
 
-      if (tcsetattr(0, TCSANOW, &d->tt) < 0)
+      if (d->tt_is_valid == true && tcsetattr(STDIN_FILENO, TCSANOW, &d->tt) < 0)
         _error->FatalE("tcsetattr", "Setting in Setup via TCSANOW for slave fd %d failed!", slaveFd);
    }
+
+   if (slaveFd != -1)
+      close(slaveFd);
 }
 void pkgDPkgPM::StopPtyMagic()
 {
    if (d->slave != NULL)
       free(d->slave);
    d->slave = NULL;
+   if (d->protect_slave_from_dying != -1)
+   {
+      close(d->protect_slave_from_dying);
+      d->protect_slave_from_dying = -1;
+   }
    if(d->master >= 0) 
    {
-      if (tcsetattr(0, TCSAFLUSH, &d->tt) == -1)
+      if (d->tt_is_valid == true && tcsetattr(STDIN_FILENO, TCSAFLUSH, &d->tt) == -1)
         _error->FatalE("tcsetattr", "Setting in Stop via TCSAFLUSH for stdin failed!");
       close(d->master);
       d->master = -1;
@@ -1230,8 +1253,15 @@ bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress)
    fd_set rfds;
    struct timespec tv;
 
-   unsigned int const MaxArgs = _config->FindI("Dpkg::MaxArgs",8*1024);
-   unsigned int const MaxArgBytes = _config->FindI("Dpkg::MaxArgBytes",32*1024);
+   // 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)
+      OSArgMax = 32*1024;
+   OSArgMax -= EnvironmentSize() - 2*1024;
+   unsigned int const MaxArgBytes = _config->FindI("Dpkg::MaxArgBytes", OSArgMax);
    bool const NoTriggers = _config->FindB("DPkg::NoTriggers", false);
 
    if (RunScripts("DPkg::Pre-Invoke") == false)
@@ -1242,9 +1272,8 @@ bool pkgDPkgPM::Go(APT::Progress::PackageManager *progress)
 
    // support subpressing of triggers processing for special
    // cases like d-i that runs the triggers handling manually
-   bool const SmartConf = (_config->Find("PackageManager::Configure", "all") != "all");
    bool const TriggersPending = _config->FindB("DPkg::TriggersPending", false);
-   if (_config->FindB("DPkg::ConfigurePending", SmartConf) == true)
+   if (_config->FindB("DPkg::ConfigurePending", true) == true)
       List.push_back(Item(Item::ConfigurePending, PkgIterator()));
 
    // for the progress
@@ -1665,7 +1694,7 @@ void pkgDPkgPM::WriteApportReport(const char *pkgpath, const char *errormsg)
    if (apportPkg.end() == true || apportPkg->CurrentVer == 0)
       return;
 
-   string pkgname, reportfile, srcpkgname, pkgver, arch;
+   string pkgname, reportfile, pkgver, arch;
    string::size_type pos;
    FILE *report;
 
@@ -1754,11 +1783,6 @@ void pkgDPkgPM::WriteApportReport(const char *pkgpath, const char *errormsg)
    if (Ver.end() == true)
       return;
    pkgver = Ver.VerStr() == NULL ? "unknown" : Ver.VerStr();
-   pkgRecords Recs(Cache);
-   pkgRecords::Parser &Parse = Recs.Lookup(Ver.FileList());
-   srcpkgname = Parse.SourcePkg();
-   if(srcpkgname.empty())
-      srcpkgname = pkgname;
 
    // if the file exists already, we check:
    // - if it was reported already (touched by apport). 
@@ -1809,7 +1833,16 @@ void pkgDPkgPM::WriteApportReport(const char *pkgpath, const char *errormsg)
    time_t now = time(NULL);
    fprintf(report, "Date: %s" , ctime(&now));
    fprintf(report, "Package: %s %s\n", pkgname.c_str(), pkgver.c_str());
+#if APT_PKG_ABI >= 413
+   fprintf(report, "SourcePackage: %s\n", Ver.SourcePkgName());
+#else
+   pkgRecords Recs(Cache);
+   pkgRecords::Parser &Parse = Recs.Lookup(Ver.FileList());
+   std::string srcpkgname = Parse.SourcePkg();
+   if(srcpkgname.empty())
+      srcpkgname = pkgname;
    fprintf(report, "SourcePackage: %s\n", srcpkgname.c_str());
+#endif
    fprintf(report, "ErrorMessage:\n %s\n", errormsg);
 
    // ensure that the log is flushed