X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/a4cf3665915b79ef6dcafd9d1e12b722e0ee5342..e43312cf4e19bd3eab15a4f43a586e2ab28c9763:/apt-pkg/deb/dpkgpm.cc diff --git a/apt-pkg/deb/dpkgpm.cc b/apt-pkg/deb/dpkgpm.cc index 68f0a339f..7e1933f06 100644 --- a/apt-pkg/deb/dpkgpm.cc +++ b/apt-pkg/deb/dpkgpm.cc @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -44,7 +45,8 @@ using namespace std; // --------------------------------------------------------------------- /* */ pkgDPkgPM::pkgDPkgPM(pkgDepCache *Cache) - : pkgPackageManager(Cache), dpkgbuf_pos(0), PackagesTotal(0), PackagesDone(0) + : pkgPackageManager(Cache), dpkgbuf_pos(0), PackagesDone(0), + PackagesTotal(0), term_out(NULL) { } /*}}}*/ @@ -351,7 +353,7 @@ void pkgDPkgPM::DoStdin(int master) /* * read the terminal pty and write log */ -void pkgDPkgPM::DoTerminalPty(int master, FILE *term_out) +void pkgDPkgPM::DoTerminalPty(int master) { char term_buf[1024] = {0,}; @@ -410,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) @@ -494,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 /*{{{*/ // --------------------------------------------------------------------- @@ -517,7 +561,7 @@ bool pkgDPkgPM::Go(int OutStatusFd) // 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[][5] = { + static const struct DpkgState DpkgStatesOpMap[][7] = { // Install operation { {"half-installed", N_("Preparing %s")}, @@ -528,12 +572,20 @@ bool pkgDPkgPM::Go(int OutStatusFd) { {"unpacked",N_("Preparing to configure %s") }, {"half-configured", N_("Configuring %s") }, +#if 0 + {"triggers-awaited", N_("Processing triggers for %s") }, + {"triggers-pending", N_("Processing triggers for %s") }, +#endif { "installed", N_("Installed %s")}, {NULL, NULL} }, // Remove operation { {"half-configured", N_("Preparing for removal of %s")}, +#if 0 + {"triggers-awaited", N_("Preparing for removal of %s")}, + {"triggers-pending", N_("Preparing for removal of %s")}, +#endif {"half-installed", N_("Removing %s")}, {"config-files", N_("Removed %s")}, {NULL, NULL} @@ -562,25 +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")); - FILE *term_out = NULL; - 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::iterator I = List.begin(); I != List.end();) @@ -778,9 +812,6 @@ bool pkgDPkgPM::Go(int OutStatusFd) int _dpkgin = fd[0]; close(fd[1]); // close the write end of the pipe - // the read buffers for the communication with dpkg - char buf[2] = {0,0}; - // the result of the waitpid call int res; if(slave > 0) @@ -813,13 +844,18 @@ bool pkgDPkgPM::Go(int OutStatusFd) tv.tv_sec = 1; tv.tv_usec = 0; select_ret = select(max(master, _dpkgin)+1, &rfds, NULL, NULL, &tv); - if (select_ret < 0) - std::cerr << "Error in select()" << std::endl; - else if (select_ret == 0) - continue; - + if (select_ret == 0) + continue; + else if (select_ret < 0 && errno == EINTR) + continue; + else if (select_ret < 0) + { + perror("select() returned error"); + continue; + } + if(master >= 0 && FD_ISSET(master, &rfds)) - DoTerminalPty(master, term_out); + DoTerminalPty(master); if(master >= 0 && FD_ISSET(0, &rfds)) DoStdin(master); if(FD_ISSET(_dpkgin, &rfds)) @@ -854,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; @@ -876,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); +} + /*}}}*/