]> git.saurik.com Git - apt.git/blobdiff - apt-pkg/deb/dpkgpm.cc
* cmdline/apt-mark:
[apt.git] / apt-pkg / deb / dpkgpm.cc
index b92d0118c3df8de271791da743507c76e5a51246..e1e26e903c1da4200b6d34312082007db46beb55 100644 (file)
@@ -12,6 +12,7 @@
 #include <apt-pkg/error.h>
 #include <apt-pkg/configuration.h>
 #include <apt-pkg/depcache.h>
+#include <apt-pkg/pkgrecords.h>
 #include <apt-pkg/strutl.h>
 #include <apti18n.h>
 
@@ -411,6 +412,8 @@ void pkgDPkgPM::ProcessDpkgStatusLine(int OutStatusFd, char *line)
         write(OutStatusFd, status.str().c_str(), status.str().size());
       if (_config->FindB("Debug::pkgDPkgProgressReporting",false) == true)
         std::clog << "send: '" << status.str() << "'" << endl;
+      pkgFailures++;
+      WriteApportReport(list[1], list[3]);
       return;
    }
    if(strncmp(action,"conffile",strlen("conffile")) == 0)
@@ -495,6 +498,46 @@ void pkgDPkgPM::DoDpkgStatusFd(int statusfd, int OutStatusFd)
 }
                                                                        /*}}}*/
 
+bool pkgDPkgPM::OpenLog()
+{
+   string logdir = _config->FindDir("Dir::Log");
+   if(not FileExists(logdir))
+      return _error->Error(_("Directory '%s' missing"), logdir.c_str());
+   string logfile_name = flCombine(logdir,
+                                  _config->Find("Dir::Log::Terminal"));
+   if (!logfile_name.empty())
+   {
+      term_out = fopen(logfile_name.c_str(),"a");
+      chmod(logfile_name.c_str(), 0600);
+      // output current time
+      char outstr[200];
+      time_t t = time(NULL);
+      struct tm *tmp = localtime(&t);
+      strftime(outstr, sizeof(outstr), "%F  %T", tmp);
+      fprintf(term_out, "\nLog started: ");
+      fprintf(term_out, outstr);
+      fprintf(term_out, "\n");
+   }
+   return true;
+}
+
+bool pkgDPkgPM::CloseLog()
+{
+   if(term_out)
+   {
+      char outstr[200];
+      time_t t = time(NULL);
+      struct tm *tmp = localtime(&t);
+      strftime(outstr, sizeof(outstr), "%F  %T", tmp);
+      fprintf(term_out, "Log ended: ");
+      fprintf(term_out, outstr);
+      fprintf(term_out, "\n");
+      fclose(term_out);
+   }
+   term_out = NULL;
+   return true;
+}
+
 
 // DPkgPM::Go - Run the sequence                                       /*{{{*/
 // ---------------------------------------------------------------------
@@ -571,24 +614,7 @@ bool pkgDPkgPM::Go(int OutStatusFd)
    }   
 
    // create log
-   string logdir = _config->FindDir("Dir::Log");
-   if(not FileExists(logdir))
-      return _error->Error(_("Directory '%s' missing"), logdir.c_str());
-   string logfile_name = flCombine(logdir,
-                                  _config->Find("Dir::Log::Terminal"));
-   if (!logfile_name.empty())
-   {
-      term_out = fopen(logfile_name.c_str(),"a");
-      chmod(logfile_name.c_str(), 0600);
-      // output current time
-      char outstr[200];
-      time_t t = time(NULL);
-      struct tm *tmp = localtime(&t);
-      strftime(outstr, sizeof(outstr), "%F  %T", tmp);
-      fprintf(term_out, "\nLog started: ");
-      fprintf(term_out, outstr);
-      fprintf(term_out, "\n");
-   }
+   OpenLog();
 
    // this loop is runs once per operation
    for (vector<Item>::iterator I = List.begin(); I != List.end();)
@@ -864,14 +890,12 @@ bool pkgDPkgPM::Go(int OutStatusFd)
 
         if(stopOnError) 
         {
-           if(term_out)
-              fclose(term_out);
+           CloseLog();
            return false;
         }
       }      
    }
-   if(term_out)
-      fclose(term_out);
+   CloseLog();
 
    if (RunScripts("DPkg::Post-Invoke") == false)
       return false;
@@ -886,3 +910,115 @@ void pkgDPkgPM::Reset()
    List.erase(List.begin(),List.end());
 }
                                                                        /*}}}*/
+// pkgDpkgPM::WriteApportReport - write out error report pkg failure   /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+void pkgDPkgPM::WriteApportReport(const char *pkgpath, const char *errormsg) 
+{
+   string pkgname, reportfile, srcpkgname, pkgver, arch;
+   string::size_type pos;
+   FILE *report;
+
+   if (_config->FindB("Dpkg::ApportFailureReport",true) == false)
+      return;
+
+   // only report the first error if we are in StopOnError=false mode
+   // to prevent bogus reports
+   if((_config->FindB("Dpkg::StopOnError",true) == false) && pkgFailures > 1)
+      return;
+
+   // get the pkgname and reportfile
+   pkgname = flNotDir(pkgpath);
+   pos = pkgname.find('_');
+   if(pos != string::npos)
+      pkgname = pkgname.substr(0, pos);
+
+   // find the package versin and source package name
+   pkgCache::PkgIterator Pkg = Cache.FindPkg(pkgname);
+   if (Pkg.end() == true)
+      return;
+   pkgCache::VerIterator Ver = Cache.GetCandidateVer(Pkg);
+   pkgver = Ver.VerStr();
+   if (Ver.end() == true)
+      return;
+   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). 
+   //   If not, we do nothing, otherwise
+   //    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");
+   if(FileExists(reportfile))
+   {
+      struct stat buf;
+      char strbuf[255];
+
+      // check atime/mtime
+      stat(reportfile.c_str(), &buf);
+      if(buf.st_mtime > buf.st_atime)
+        return;
+
+      // check if the existing report is the same version
+      report = fopen(reportfile.c_str(),"r");
+      while(fgets(strbuf, sizeof(strbuf), report) != NULL)
+      {
+        if(strstr(strbuf,"Package:") == strbuf)
+        {
+           char pkgname[255], version[255];
+           if(sscanf(strbuf, "Package: %s %s", pkgname, version) == 2)
+              if(strcmp(pkgver.c_str(), version) == 0)
+              {
+                 fclose(report);
+                 return;
+              }
+        }
+      }
+      fclose(report);
+   }
+
+   // now write the report
+   arch = _config->Find("APT::Architecture");
+   report = fopen(reportfile.c_str(),"w");
+   if(report == NULL)
+      return;
+   if(_config->FindB("DPkgPM::InitialReportOnly",false) == true)
+      chmod(reportfile.c_str(), 0);
+   else
+      chmod(reportfile.c_str(), 0600);
+   fprintf(report, "ProblemType: Package\n");
+   fprintf(report, "Architecture: %s\n", arch.c_str());
+   time_t now = time(NULL);
+   fprintf(report, "Date: %s" , ctime(&now));
+   fprintf(report, "Package: %s %s\n", pkgname.c_str(), pkgver.c_str());
+   fprintf(report, "SourcePackage: %s\n", srcpkgname.c_str());
+   fprintf(report, "ErrorMessage:\n %s\n", errormsg);
+
+   // ensure that the log is flushed
+   if(term_out)
+      fflush(term_out);
+
+   // attach terminal log it if we have it
+   string logfile_name = _config->FindFile("Dir::Log::Terminal");
+   if (!logfile_name.empty())
+   {
+      FILE *log = NULL;
+      char buf[1024];
+
+      fprintf(report, "DpkgTerminalLog:\n");
+      log = fopen(logfile_name.c_str(),"r");
+      if(log != NULL)
+      {
+        while( fgets(buf, sizeof(buf), log) != NULL)
+           fprintf(report, " %s", buf);
+        fclose(log);
+      }
+   }
+   fclose(report);
+}
+                                                                       /*}}}*/