diff options
Diffstat (limited to 'apt-pkg')
-rw-r--r-- | apt-pkg/acquire-item.cc | 203 | ||||
-rw-r--r-- | apt-pkg/acquire-item.h | 26 | ||||
-rw-r--r-- | apt-pkg/acquire-method.cc | 21 | ||||
-rw-r--r-- | apt-pkg/acquire-method.h | 15 | ||||
-rw-r--r-- | apt-pkg/algorithms.cc | 3 | ||||
-rw-r--r-- | apt-pkg/aptconfiguration.cc | 90 | ||||
-rw-r--r-- | apt-pkg/aptconfiguration.h | 46 | ||||
-rw-r--r-- | apt-pkg/contrib/configuration.cc | 27 | ||||
-rw-r--r-- | apt-pkg/contrib/configuration.h | 3 | ||||
-rw-r--r-- | apt-pkg/contrib/fileutl.cc | 2 | ||||
-rw-r--r-- | apt-pkg/contrib/strutl.cc | 19 | ||||
-rw-r--r-- | apt-pkg/deb/debsystem.cc | 3 | ||||
-rw-r--r-- | apt-pkg/deb/dpkgpm.cc | 341 | ||||
-rw-r--r-- | apt-pkg/deb/dpkgpm.h | 7 | ||||
-rw-r--r-- | apt-pkg/depcache.cc | 4 | ||||
-rw-r--r-- | apt-pkg/indexcopy.cc | 3 | ||||
-rw-r--r-- | apt-pkg/init.cc | 5 | ||||
-rw-r--r-- | apt-pkg/init.h | 2 | ||||
-rw-r--r-- | apt-pkg/makefile | 7 | ||||
-rw-r--r-- | apt-pkg/orderlist.cc | 63 | ||||
-rw-r--r-- | apt-pkg/packagemanager.cc | 40 | ||||
-rw-r--r-- | apt-pkg/pkgrecords.cc | 4 | ||||
-rw-r--r-- | apt-pkg/tagfile.cc | 2 |
23 files changed, 736 insertions, 200 deletions
diff --git a/apt-pkg/acquire-item.cc b/apt-pkg/acquire-item.cc index 39ae327cb..171dafa24 100644 --- a/apt-pkg/acquire-item.cc +++ b/apt-pkg/acquire-item.cc @@ -15,6 +15,7 @@ // Include Files /*{{{*/ #include <apt-pkg/acquire-item.h> #include <apt-pkg/configuration.h> +#include <apt-pkg/aptconfiguration.h> #include <apt-pkg/sourcelist.h> #include <apt-pkg/vendorlist.h> #include <apt-pkg/error.h> @@ -63,6 +64,7 @@ void pkgAcquire::Item::Failed(string Message,pkgAcquire::MethodConfig *Cnf) { Status = StatIdle; ErrorText = LookupTag(Message,"Message"); + UsedMirror = LookupTag(Message,"UsedMirror"); if (QueueCounter <= 1) { /* This indicates that the file is not available right now but might @@ -75,10 +77,17 @@ void pkgAcquire::Item::Failed(string Message,pkgAcquire::MethodConfig *Cnf) Dequeue(); return; } - + Status = StatError; Dequeue(); } + + // report mirror failure back to LP if we actually use a mirror + string FailReason = LookupTag(Message, "FailReason"); + if(FailReason.size() != 0) + ReportMirrorFailure(FailReason); + else + ReportMirrorFailure(ErrorText); } /*}}}*/ // Acquire::Item::Start - Item has begun to download /*{{{*/ @@ -100,7 +109,7 @@ void pkgAcquire::Item::Done(string Message,unsigned long Size,string Hash, { // We just downloaded something.. string FileName = LookupTag(Message,"Filename"); - // we only inform the Log class if it was actually not a local thing + UsedMirror = LookupTag(Message,"UsedMirror"); if (Complete == false && !Local && FileName == DestFile) { if (Owner->Log != 0) @@ -109,7 +118,6 @@ void pkgAcquire::Item::Done(string Message,unsigned long Size,string Hash, if (FileSize == 0) FileSize= Size; - Status = StatDone; ErrorText = string(); Owner->Dequeue(this); @@ -131,6 +139,49 @@ void pkgAcquire::Item::Rename(string From,string To) } } /*}}}*/ + +void pkgAcquire::Item::ReportMirrorFailure(string FailCode) +{ + // we only act if a mirror was used at all + if(UsedMirror.empty()) + return; +#if 0 + std::cerr << "\nReportMirrorFailure: " + << UsedMirror + << " Uri: " << DescURI() + << " FailCode: " + << FailCode << std::endl; +#endif + const char *Args[40]; + unsigned int i = 0; + string report = _config->Find("Methods::Mirror::ProblemReporting", + "/usr/lib/apt/apt-report-mirror-failure"); + if(!FileExists(report)) + return; + Args[i++] = report.c_str(); + Args[i++] = UsedMirror.c_str(); + Args[i++] = DescURI().c_str(); + Args[i++] = FailCode.c_str(); + Args[i++] = NULL; + pid_t pid = ExecFork(); + if(pid < 0) + { + _error->Error("ReportMirrorFailure Fork failed"); + return; + } + else if(pid == 0) + { + execvp(Args[0], (char**)Args); + std::cerr << "Could not exec " << Args[0] << std::endl; + _exit(100); + } + if(!ExecWait(pid, "report-mirror-failure")) + { + _error->Warning("Couldn't report problem to '%s'", + _config->Find("Methods::Mirror::ProblemReporting").c_str()); + } +} + // AcqDiffIndex::AcqDiffIndex - Constructor /*{{{*/ // --------------------------------------------------------------------- /* Get the DiffIndex file first and see if there are patches availabe @@ -551,13 +602,14 @@ pkgAcqIndex::pkgAcqIndex(pkgAcquire *Owner, if(comprExt.empty()) { // autoselect the compression method - if(FileExists("/bin/bzip2")) - CompressionExtension = ".bz2"; - else - CompressionExtension = ".gz"; - } else { - CompressionExtension = (comprExt == "plain" ? "" : comprExt); + std::vector<std::string> types = APT::Configuration::getCompressionTypes(); + if (types.empty() == true) + comprExt = "plain"; + else + comprExt = "." + types[0]; } + CompressionExtension = ((comprExt == "plain" || comprExt == ".") ? "" : comprExt); + Desc.URI = URI + CompressionExtension; Desc.Description = URIDesc; @@ -578,30 +630,32 @@ string pkgAcqIndex::Custom600Headers() struct stat Buf; if (stat(Final.c_str(),&Buf) != 0) return "\nIndex-File: true"; - return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf.st_mtime); } /*}}}*/ void pkgAcqIndex::Failed(string Message,pkgAcquire::MethodConfig *Cnf) /*{{{*/ { - bool descChanged = false; - // no .bz2 found, retry with .gz - if(Desc.URI.substr(Desc.URI.size()-3) == "bz2") { - Desc.URI = Desc.URI.substr(0,Desc.URI.size()-3) + "gz"; - - new pkgAcqIndex(Owner, RealURI, Desc.Description,Desc.ShortDesc, - ExpectedHash, string(".gz")); - descChanged = true; - } - // no .gz found, retry with uncompressed - else if(Desc.URI.substr(Desc.URI.size()-2) == "gz") { - Desc.URI = Desc.URI.substr(0,Desc.URI.size()-2); + std::vector<std::string> types = APT::Configuration::getCompressionTypes(); - new pkgAcqIndex(Owner, RealURI, Desc.Description,Desc.ShortDesc, - ExpectedHash, string("plain")); - descChanged = true; - } - if (descChanged) { + for (std::vector<std::string>::const_iterator t = types.begin(); + t != types.end(); t++) + { + // jump over all already tried compression types + const unsigned int nameLen = Desc.URI.size() - (*t).size(); + if(Desc.URI.substr(nameLen) != *t) + continue; + + // we want to try it with the next extension (and make sure to + // not skip over the end) + t++; + if (t == types.end()) + break; + + // queue new download + Desc.URI = Desc.URI.substr(0, nameLen) + *t; + new pkgAcqIndex(Owner, RealURI, Desc.Description, Desc.ShortDesc, + ExpectedHash, string(".").append(*t)); + Status = StatDone; Complete = false; Dequeue(); @@ -643,6 +697,7 @@ void pkgAcqIndex::Done(string Message,unsigned long Size,string Hash, Status = StatAuthError; ErrorText = _("Hash Sum mismatch"); Rename(DestFile,DestFile + ".FAILED"); + ReportMirrorFailure("HashChecksumFailure"); return; } // Done, move it into position @@ -698,11 +753,11 @@ void pkgAcqIndex::Done(string Message,unsigned long Size,string Hash, Local = true; string compExt = flExtension(flNotDir(URI(Desc.URI).Path)); - const char *decompProg; - if(compExt == "bz2") - decompProg = "bzip2"; - else if(compExt == "gz") - decompProg = "gzip"; + string decompProg; + + // get the binary name for your used compression type + decompProg = _config->Find(string("Acquire::CompressionTypes::").append(compExt),""); + if(decompProg.empty() == false); // flExtensions returns the full name if no extension is found // this is why we have this complicated compare operation here // FIMXE: add a new flJustExtension() that return "" if no @@ -717,9 +772,9 @@ void pkgAcqIndex::Done(string Message,unsigned long Size,string Hash, Decompression = true; DestFile += ".decomp"; - Desc.URI = string(decompProg) + ":" + FileName; + Desc.URI = decompProg + ":" + FileName; QueueURI(Desc); - Mode = decompProg; + Mode = decompProg.c_str(); } /*}}}*/ // AcqIndexTrans::pkgAcqIndexTrans - Constructor /*{{{*/ @@ -833,8 +888,9 @@ void pkgAcqMetaSig::Done(string Message,unsigned long Size,string MD5, Rename(LastGoodSig, DestFile); // queue a pkgAcqMetaIndex to be verified against the sig we just retrieved - new pkgAcqMetaIndex(Owner, MetaIndexURI, MetaIndexURIDesc, MetaIndexShortDesc, - DestFile, IndexTargets, MetaIndexParser); + new pkgAcqMetaIndex(Owner, MetaIndexURI, MetaIndexURIDesc, + MetaIndexShortDesc, DestFile, IndexTargets, + MetaIndexParser); } /*}}}*/ @@ -847,7 +903,7 @@ void pkgAcqMetaSig::Failed(string Message,pkgAcquire::MethodConfig *Cnf)/*{{{*/ { Item::Failed(Message,Cnf); // move the sigfile back on transient network failures - if(FileExists(DestFile)) + if(FileExists(LastGoodSig)) Rename(LastGoodSig,Final); // set the status back to , Item::Failed likes to reset it @@ -922,6 +978,15 @@ void pkgAcqMetaIndex::Done(string Message,unsigned long Size,string Hash, /*{{{* if (AuthPass == true) { AuthDone(Message); + + // all cool, move Release file into place + Complete = true; + + string FinalFile = _config->FindDir("Dir::State::lists"); + FinalFile += URItoFileName(RealURI); + Rename(DestFile,FinalFile); + chmod(FinalFile.c_str(),0644); + DestFile = FinalFile; } else { @@ -973,22 +1038,15 @@ void pkgAcqMetaIndex::RetrievalDone(string Message) /*{{{*/ return; } - // see if the download was a IMSHit + // make sure to verify against the right file on I-M-S hit IMSHit = StringToBool(LookupTag(Message,"IMS-Hit"),false); + if(IMSHit) + { + string FinalFile = _config->FindDir("Dir::State::lists"); + FinalFile += URItoFileName(RealURI); + DestFile = FinalFile; + } Complete = true; - - string FinalFile = _config->FindDir("Dir::State::lists"); - FinalFile += URItoFileName(RealURI); - - // If we get a IMS hit we can remove the empty file in partial - // othersie we move the file in place - if (IMSHit) - unlink(DestFile.c_str()); - else - Rename(DestFile,FinalFile); - - chmod(FinalFile.c_str(),0644); - DestFile = FinalFile; } /*}}}*/ void pkgAcqMetaIndex::AuthDone(string Message) /*{{{*/ @@ -1018,7 +1076,6 @@ void pkgAcqMetaIndex::AuthDone(string Message) /*{{{*/ QueueIndexes(true); // Done, move signature file into position - string VerifiedSigFile = _config->FindDir("Dir::State::lists") + URItoFileName(RealURI) + ".gpg"; Rename(SigFile,VerifiedSigFile); @@ -1059,7 +1116,7 @@ void pkgAcqMetaIndex::QueueIndexes(bool verify) /*{{{*/ // Queue Packages file (either diff or full packages files, depending // on the users option) - if(_config->FindB("Acquire::PDiffs",true) == true) + if(_config->FindB("Acquire::PDiffs",false) == true) new pkgAcqDiffIndex(Owner, (*Target)->URI, (*Target)->Description, (*Target)->ShortDesc, ExpectedIndexHash); else @@ -1162,30 +1219,30 @@ void pkgAcqMetaIndex::Failed(string Message,pkgAcquire::MethodConfig *Cnf) { if (AuthPass == true) { - // if we fail the authentication but got the file via a IMS-Hit - // this means that the file wasn't downloaded and that it might be - // just stale (server problem, proxy etc). we delete what we have - // queue it again without i-m-s - // alternatively we could just unlink the file and let the user try again - if (IMSHit) + // gpgv method failed, if we have a good signature + string LastGoodSigFile = _config->FindDir("Dir::State::lists") + + "partial/" + URItoFileName(RealURI) + ".gpg.reverify"; + if(FileExists(LastGoodSigFile)) { - Complete = false; - Local = false; - AuthPass = false; - unlink(DestFile.c_str()); - - DestFile = _config->FindDir("Dir::State::lists") + "partial/"; - DestFile += URItoFileName(RealURI); - Desc.URI = RealURI; - QueueURI(Desc); + string VerifiedSigFile = _config->FindDir("Dir::State::lists") + + URItoFileName(RealURI) + ".gpg"; + Rename(LastGoodSigFile,VerifiedSigFile); + Status = StatTransientNetworkError; + _error->Warning(_("A error occurred during the signature " + "verification. The repository is not updated " + "and the previous index files will be used." + "GPG error: %s: %s\n"), + Desc.Description.c_str(), + LookupTag(Message,"Message").c_str()); + RunScripts("APT::Update::Auth-Failure"); return; + } else { + _error->Warning(_("GPG error: %s: %s"), + Desc.Description.c_str(), + LookupTag(Message,"Message").c_str()); } - // gpgv method failed - _error->Warning("GPG error: %s: %s", - Desc.Description.c_str(), - LookupTag(Message,"Message").c_str()); - + ReportMirrorFailure("GPGFailure"); } // No Release file was present, or verification failed, so fall diff --git a/apt-pkg/acquire-item.h b/apt-pkg/acquire-item.h index 36a926a0f..06fcffc73 100644 --- a/apt-pkg/acquire-item.h +++ b/apt-pkg/acquire-item.h @@ -142,6 +142,7 @@ class pkgAcquire::Item * download progress indicator's overall statistics. */ bool Local; + string UsedMirror; /** \brief The number of fetch queues into which this item has been * inserted. @@ -242,6 +243,17 @@ class pkgAcquire::Item /** \return \b true if this object is being fetched from a trusted source. */ virtual bool IsTrusted() {return false;}; + + // report mirror problems + /** \brief Report mirror problem + * + * This allows reporting mirror failures back to a centralized + * server. The apt-report-mirror-failure script is called for this + * + * \param FailCode A short failure string that is send + */ + void ReportMirrorFailure(string FailCode); + /** \brief Initialize an item. * @@ -540,10 +552,13 @@ class pkgAcqIndex : public pkgAcquire::Item * * \param compressExt The compression-related extension with which * this index file should be downloaded, or "" to autodetect - * (".bz2" is used if bzip2 is installed, ".gz" otherwise). + * Compression types can be set with config Acquire::CompressionTypes, + * default is ".lzma" or ".bz2" (if the needed binaries are present) + * fallback is ".gz" or none. */ pkgAcqIndex(pkgAcquire *Owner,string URI,string URIDesc, - string ShortDesc, HashString ExpectedHash, string compressExt=""); + string ShortDesc, HashString ExpectedHash, + string compressExt=""); }; /*}}}*/ /** \brief An acquire item that is responsible for fetching a {{{ @@ -569,12 +584,6 @@ class pkgAcqIndexTrans : public pkgAcqIndex * \param URIDesc A "URI-style" description of this index file. * * \param ShortDesc A brief description of this index file. - * - * \param ExpectedHash The expected hashsum of this index file. - * - * \param compressExt The compression-related extension with which - * this index file should be downloaded, or "" to autodetect - * (".bz2" is used if bzip2 is installed, ".gz" otherwise). */ pkgAcqIndexTrans(pkgAcquire *Owner,string URI,string URIDesc, string ShortDesc); @@ -612,7 +621,6 @@ class pkgAcqMetaSig : public pkgAcquire::Item /** \brief The last good signature file */ string LastGoodSig; - /** \brief The fetch request that is currently being processed. */ pkgAcquire::ItemDesc Desc; diff --git a/apt-pkg/acquire-method.cc b/apt-pkg/acquire-method.cc index fe066741c..3008c8d1a 100644 --- a/apt-pkg/acquire-method.cc +++ b/apt-pkg/acquire-method.cc @@ -96,12 +96,11 @@ void pkgAcqMethod::Fail(string Err,bool Transient) } char S[1024]; + char *End = S; if (Queue != 0) { - snprintf(S,sizeof(S)-50,"400 URI Failure\nURI: %s\n" - "Message: %s %s\n",Queue->Uri.c_str(),Err.c_str(), - FailExtra.c_str()); - + End += snprintf(S,sizeof(S)-50,"400 URI Failure\nURI: %s\n" + "Message: %s %s\n",Queue->Uri.c_str(), Err.c_str(), IP.c_str()); // Dequeue FetchItem *Tmp = Queue; Queue = Queue->Next; @@ -110,10 +109,14 @@ void pkgAcqMethod::Fail(string Err,bool Transient) QueueBack = Queue; } else - snprintf(S,sizeof(S)-50,"400 URI Failure\nURI: <UNKNOWN>\n" - "Message: %s %s\n",Err.c_str(), - FailExtra.c_str()); - + { + End += snprintf(S,sizeof(S)-50,"400 URI Failure\nURI: <UNKNOWN>\n" + "Message: %s\n",Err.c_str()); + } + if(FailReason.empty() == false) + End += snprintf(End,sizeof(S)-50 - (End - S),"FailReason: %s\n",FailReason.c_str()); + if (UsedMirror.empty() == false) + End += snprintf(End,sizeof(S)-50 - (End - S),"UsedMirror: %s\n",UsedMirror.c_str()); // Set the transient flag if (Transient == true) strcat(S,"Transient-Failure: true\n\n"); @@ -184,6 +187,8 @@ void pkgAcqMethod::URIDone(FetchResult &Res, FetchResult *Alt) End += snprintf(End,sizeof(S)-50 - (End - S),"SHA1-Hash: %s\n",Res.SHA1Sum.c_str()); if (Res.SHA256Sum.empty() == false) End += snprintf(End,sizeof(S)-50 - (End - S),"SHA256-Hash: %s\n",Res.SHA256Sum.c_str()); + if (UsedMirror.empty() == false) + End += snprintf(End,sizeof(S)-50 - (End - S),"UsedMirror: %s\n",UsedMirror.c_str()); if (Res.GPGVOutput.size() > 0) End += snprintf(End,sizeof(S)-50 - (End - S),"GPGVOutput:\n"); for (vector<string>::iterator I = Res.GPGVOutput.begin(); diff --git a/apt-pkg/acquire-method.h b/apt-pkg/acquire-method.h index fab77e664..99a4605b1 100644 --- a/apt-pkg/acquire-method.h +++ b/apt-pkg/acquire-method.h @@ -59,7 +59,9 @@ class pkgAcqMethod vector<string> Messages; FetchItem *Queue; FetchItem *QueueBack; - string FailExtra; + string FailReason; + string UsedMirror; + string IP; // Handlers for messages virtual bool Configuration(string Message); @@ -68,14 +70,14 @@ class pkgAcqMethod // Outgoing messages void Fail(bool Transient = false); inline void Fail(const char *Why, bool Transient = false) {Fail(string(Why),Transient);}; - void Fail(string Why, bool Transient = false); - void URIStart(FetchResult &Res); - void URIDone(FetchResult &Res,FetchResult *Alt = 0); + virtual void Fail(string Why, bool Transient = false); + virtual void URIStart(FetchResult &Res); + virtual void URIDone(FetchResult &Res,FetchResult *Alt = 0); + bool MediaFail(string Required,string Drive); virtual void Exit() {}; public: - enum CnfFlags {SingleInstance = (1<<0), Pipeline = (1<<1), SendConfig = (1<<2), LocalOnly = (1<<3), NeedsCleanup = (1<<4), @@ -87,7 +89,8 @@ class pkgAcqMethod void Redirect(const string &NewURI); int Run(bool Single = false); - inline void SetFailExtraMsg(string Msg) {FailExtra = Msg;}; + inline void SetFailReason(string Msg) {FailReason = Msg;}; + inline void SetIP(string aIP) {IP = aIP;}; pkgAcqMethod(const char *Ver,unsigned long Flags = 0); virtual ~pkgAcqMethod() {}; diff --git a/apt-pkg/algorithms.cc b/apt-pkg/algorithms.cc index 34da745de..a3963d546 100644 --- a/apt-pkg/algorithms.cc +++ b/apt-pkg/algorithms.cc @@ -1140,8 +1140,7 @@ bool pkgProblemResolver::Resolve(bool BrokenFix) return _error->Error(_("Unable to correct problems, you have held broken packages.")); } - // set the auto-flags (mvo: I'm not sure if we _really_ need this, but - // I didn't managed + // set the auto-flags (mvo: I'm not sure if we _really_ need this) pkgCache::PkgIterator I = Cache.PkgBegin(); for (;I.end() != true; I++) { if (Cache[I].NewInstall() && !(Flags[I->ID] & PreInstalled)) { diff --git a/apt-pkg/aptconfiguration.cc b/apt-pkg/aptconfiguration.cc new file mode 100644 index 000000000..45ae9bed5 --- /dev/null +++ b/apt-pkg/aptconfiguration.cc @@ -0,0 +1,90 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +/* ###################################################################### + + Provide access methods to various configuration settings, + setup defaults and returns validate settings. + + ##################################################################### */ + /*}}}*/ +// Include Files /*{{{*/ +#include <apt-pkg/fileutl.h> +#include <apt-pkg/aptconfiguration.h> +#include <apt-pkg/configuration.h> + +#include <vector> +#include <string> +#include <algorithm> + /*}}}*/ +namespace APT { +// getCompressionTypes - Return Vector of usbale compressiontypes /*{{{*/ +// --------------------------------------------------------------------- +/* return a vector of compression types in the prefered order. */ +std::vector<std::string> +const Configuration::getCompressionTypes(bool const &Cached) { + static std::vector<std::string> types; + if (types.empty() == false) { + if (Cached == true) + return types; + else + types.clear(); + } + + // setup the defaults for the compressiontypes => method mapping + _config->CndSet("Acquire::CompressionTypes::bz2","bzip2"); + _config->CndSet("Acquire::CompressionTypes::lzma","lzma"); + _config->CndSet("Acquire::CompressionTypes::gz","gzip"); + + // Set default application paths to check for optional compression types + _config->CndSet("Dir::Bin::lzma", "/usr/bin/lzma"); + _config->CndSet("Dir::Bin::bzip2", "/bin/bzip2"); + + // accept non-list order as override setting for config settings on commandline + std::string const overrideOrder = _config->Find("Acquire::CompressionTypes::Order",""); + if (overrideOrder.empty() == false) + types.push_back(overrideOrder); + + // load the order setting into our vector + std::vector<std::string> const order = _config->FindVector("Acquire::CompressionTypes::Order"); + for (std::vector<std::string>::const_iterator o = order.begin(); + o != order.end(); o++) { + if ((*o).empty() == true) + continue; + // ignore types we have no method ready to use + if (_config->Exists(string("Acquire::CompressionTypes::").append(*o)) == false) + continue; + // ignore types we have no app ready to use + string const appsetting = string("Dir::Bin::").append(*o); + if (_config->Exists(appsetting) == true) { + std::string const app = _config->FindFile(appsetting.c_str(), ""); + if (app.empty() == false && FileExists(app) == false) + continue; + } + types.push_back(*o); + } + + // move again over the option tree to add all missing compression types + ::Configuration::Item const *Types = _config->Tree("Acquire::CompressionTypes"); + if (Types != 0) + Types = Types->Child; + + for (; Types != 0; Types = Types->Next) { + if (Types->Tag == "Order" || Types->Tag.empty() == true) + continue; + // ignore types we already have in the vector + if (std::find(types.begin(),types.end(),Types->Tag) != types.end()) + continue; + // ignore types we have no app ready to use + string const appsetting = string("Dir::Bin::").append(Types->Value); + if (appsetting.empty() == false && _config->Exists(appsetting) == true) { + std::string const app = _config->FindFile(appsetting.c_str(), ""); + if (app.empty() == false && FileExists(app) == false) + continue; + } + types.push_back(Types->Tag); + } + + return types; +} + /*}}}*/ +} diff --git a/apt-pkg/aptconfiguration.h b/apt-pkg/aptconfiguration.h new file mode 100644 index 000000000..6a123adce --- /dev/null +++ b/apt-pkg/aptconfiguration.h @@ -0,0 +1,46 @@ +// -*- mode: cpp; mode: fold -*- +// Description /*{{{*/ +/** \class APT::Configuration + * \brief Provide access methods to various configuration settings + * + * This class and their methods providing a layer around the usual access + * methods with _config to ensure that settings are correct and to be able + * to set defaults without the need to recheck it in every method again. + */ + /*}}}*/ +#ifndef APT_CONFIGURATION_H +#define APT_CONFIGURATION_H +// Include Files /*{{{*/ +#include <string> +#include <vector> + /*}}}*/ +namespace APT { +class Configuration { /*{{{*/ +public: /*{{{*/ + /** \brief Returns a vector of usable Compression Types + * + * Files can be compressed in various ways to decrease the size of the + * download. Therefore the Acquiremethods support a few compression types + * and some archives provide also a few different types. This option + * group exists to give the user the choice to prefer one type over the + * other (some compression types are very resource intensive - great if you + * have a limited download, bad if you have a really lowpowered hardware.) + * + * This method ensures that the defaults are set and checks at runtime + * if the type can be used. E.g. the current default is to prefer bzip2 + * over lzma and gz - if the bzip2 binary is not available it has not much + * sense in downloading the bz2 file, therefore we will not return bz2 as + * a usable compression type. The availability is checked with the settings + * in the Dir::Bin group. + * + * \param Cached saves the result so we need to calculated it only once + * this parameter should ony be used for testing purposes. + * + * \return a vector of (all) Language Codes in the prefered usage order + */ + std::vector<std::string> static const getCompressionTypes(bool const &Cached = true); + /*}}}*/ +}; + /*}}}*/ +} +#endif diff --git a/apt-pkg/contrib/configuration.cc b/apt-pkg/contrib/configuration.cc index 48a5f0bff..4e8586e83 100644 --- a/apt-pkg/contrib/configuration.cc +++ b/apt-pkg/contrib/configuration.cc @@ -223,6 +223,25 @@ string Configuration::FindDir(const char *Name,const char *Default) const return Res; } /*}}}*/ +// Configuration::FindVector - Find a vector of values /*{{{*/ +// --------------------------------------------------------------------- +/* Returns a vector of config values under the given item */ +vector<string> Configuration::FindVector(const char *Name) const +{ + vector<string> Vec; + const Item *Top = Lookup(Name); + if (Top == NULL) + return Vec; + + Item *I = Top->Child; + while(I != NULL) + { + Vec.push_back(I->Value); + I = I->Next; + } + return Vec; +} + /*}}}*/ // Configuration::FindI - Find an integer value /*{{{*/ // --------------------------------------------------------------------- /* */ @@ -582,9 +601,11 @@ bool ReadConfigFile(Configuration &Conf,const string &FName,bool AsSectional, InQuote = !InQuote; if (InQuote == true) continue; - - if ((*I == '/' && I + 1 != End && I[1] == '/') || *I == '#') - { + + if ((*I == '/' && I + 1 != End && I[1] == '/') || + (*I == '#' && strcmp(string(I,I+6).c_str(),"#clear") != 0 && + strcmp(string(I,I+8).c_str(),"#include") != 0)) + { End = I; break; } diff --git a/apt-pkg/contrib/configuration.h b/apt-pkg/contrib/configuration.h index 2534692a3..e2da83f5b 100644 --- a/apt-pkg/contrib/configuration.h +++ b/apt-pkg/contrib/configuration.h @@ -31,6 +31,7 @@ #include <string> +#include <vector> #include <iostream> using std::string; @@ -70,6 +71,8 @@ class Configuration string Find(const string Name,const char *Default = 0) const {return Find(Name.c_str(),Default);}; string FindFile(const char *Name,const char *Default = 0) const; string FindDir(const char *Name,const char *Default = 0) const; + std::vector<string> FindVector(const string &Name) const; + std::vector<string> FindVector(const char *Name) const; int FindI(const char *Name,int Default = 0) const; int FindI(const string Name,int Default = 0) const {return FindI(Name.c_str(),Default);}; bool FindB(const char *Name,bool Default = false) const; diff --git a/apt-pkg/contrib/fileutl.cc b/apt-pkg/contrib/fileutl.cc index a7de09c44..4240d9f49 100644 --- a/apt-pkg/contrib/fileutl.cc +++ b/apt-pkg/contrib/fileutl.cc @@ -451,10 +451,12 @@ bool ExecWait(pid_t Pid,const char *Name,bool Reap) if (Reap == true) return false; if (WIFSIGNALED(Status) != 0) + { if( WTERMSIG(Status) == SIGSEGV) return _error->Error(_("Sub-process %s received a segmentation fault."),Name); else return _error->Error(_("Sub-process %s received signal %u."),Name, WTERMSIG(Status)); + } if (WIFEXITED(Status) != 0) return _error->Error(_("Sub-process %s returned an error code (%u)"),Name,WEXITSTATUS(Status)); diff --git a/apt-pkg/contrib/strutl.cc b/apt-pkg/contrib/strutl.cc index a991b8988..4c05f2df8 100644 --- a/apt-pkg/contrib/strutl.cc +++ b/apt-pkg/contrib/strutl.cc @@ -67,9 +67,20 @@ bool UTF8ToCodeset(const char *codeset, const string &orig, string *dest) outbuf = new char[insize+1]; outptr = outbuf; - iconv(cd, &inptr, &insize, &outptr, &outsize); - *outptr = '\0'; + while (insize != 0) + { + size_t const err = iconv(cd, &inptr, &insize, &outptr, &outsize); + if (err == (size_t)(-1)) + { + insize--; + outsize++; + inptr++; + *outptr = '?'; + outptr++; + } + } + *outptr = '\0'; *dest = outbuf; delete[] outbuf; @@ -304,13 +315,13 @@ string SizeToStr(double Size) { if (ASize < 100 && I != 0) { - sprintf(S,"%.1f%c",ASize,Ext[I]); + sprintf(S,"%'.1f%c",ASize,Ext[I]); break; } if (ASize < 10000) { - sprintf(S,"%.0f%c",ASize,Ext[I]); + sprintf(S,"%'.0f%c",ASize,Ext[I]); break; } ASize /= 1000.0; diff --git a/apt-pkg/deb/debsystem.cc b/apt-pkg/deb/debsystem.cc index 59f826d96..089a465c1 100644 --- a/apt-pkg/deb/debsystem.cc +++ b/apt-pkg/deb/debsystem.cc @@ -18,7 +18,6 @@ #include <apt-pkg/error.h> #include <apt-pkg/fileutl.h> #include <apti18n.h> - #include <sys/types.h> #include <unistd.h> #include <dirent.h> @@ -80,7 +79,7 @@ bool debSystem::Lock() close(LockFD); LockFD = -1; return _error->Error(_("dpkg was interrupted, you must manually " - "run 'dpkg --configure -a' to correct the problem. ")); + "run 'sudo dpkg --configure -a' to correct the problem. ")); } LockCount++; diff --git a/apt-pkg/deb/dpkgpm.cc b/apt-pkg/deb/dpkgpm.cc index ab71d4e96..332b3cf0b 100644 --- a/apt-pkg/deb/dpkgpm.cc +++ b/apt-pkg/deb/dpkgpm.cc @@ -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> #include <apt-pkg/fileutl.h> @@ -24,6 +25,7 @@ #include <sys/wait.h> #include <signal.h> #include <errno.h> +#include <string.h> #include <stdio.h> #include <string.h> #include <algorithm> @@ -104,7 +106,7 @@ ionice(int PID) /* */ pkgDPkgPM::pkgDPkgPM(pkgDepCache *Cache) : pkgPackageManager(Cache), dpkgbuf_pos(0), - term_out(NULL), PackagesDone(0), PackagesTotal(0) + term_out(NULL), PackagesDone(0), PackagesTotal(0), pkgFailures(0) { } /*}}}*/ @@ -134,8 +136,14 @@ bool pkgDPkgPM::Configure(PkgIterator Pkg) { if (Pkg.end() == true) return false; - - List.push_back(Item(Item::Configure,Pkg)); + + List.push_back(Item(Item::Configure, Pkg)); + + // Use triggers for config calls if we configure "smart" + // as otherwise Pre-Depends will not be satisfied, see #526774 + if (_config->FindB("DPkg::TriggersPending", false) == true) + List.push_back(Item(Item::TriggersPending, PkgIterator())); + return true; } /*}}}*/ @@ -190,6 +198,9 @@ bool pkgDPkgPM::SendV2Pkgs(FILE *F) // Write out the package actions in order. for (vector<Item>::iterator I = List.begin(); I != List.end(); I++) { + if(I->Pkg.end() == true) + continue; + pkgDepCache::StateCache &S = Cache[I->Pkg]; fprintf(F,"%s ",I->Pkg.Name()); @@ -331,7 +342,6 @@ bool pkgDPkgPM::RunScriptsWithPkgs(const char *Cnf) return true; } - /*}}}*/ // DPkgPM::DoStdin - Read stdin and pass to slave pty /*{{{*/ // --------------------------------------------------------------------- @@ -378,10 +388,11 @@ void pkgDPkgPM::DoTerminalPty(int master) */ void pkgDPkgPM::ProcessDpkgStatusLine(int OutStatusFd, char *line) { + bool const Debug = _config->FindB("Debug::pkgDPkgProgressReporting",false); // the status we output ostringstream status; - if (_config->FindB("Debug::pkgDPkgProgressReporting",false) == true) + if (Debug == true) std::clog << "got from dpkg '" << line << "'" << std::endl; @@ -396,10 +407,11 @@ void pkgDPkgPM::ProcessDpkgStatusLine(int OutStatusFd, char *line) 'processing: install: pkg' 'processing: configure: pkg' 'processing: remove: pkg' + 'processing: purge: pkg' - but for apt is it a ignored "unknown" action 'processing: trigproc: trigger' */ - char* list[5]; + char* list[6]; // dpkg sends multiline error messages sometimes (see // #374195 for a example. we should support this by // either patching dpkg to not send multiline over the @@ -408,28 +420,28 @@ void pkgDPkgPM::ProcessDpkgStatusLine(int OutStatusFd, char *line) TokSplitString(':', line, list, sizeof(list)/sizeof(list[0])); if( list[0] == NULL || list[1] == NULL || list[2] == NULL) { - if (_config->FindB("Debug::pkgDPkgProgressReporting",false) == true) + if (Debug == true) std::clog << "ignoring line: not enough ':'" << std::endl; return; } - char *pkg = list[1]; - char *action = _strstrip(list[2]); + const char* const pkg = list[1]; + const char* action = _strstrip(list[2]); // 'processing' from dpkg looks like // 'processing: action: pkg' if(strncmp(list[0], "processing", strlen("processing")) == 0) { char s[200]; - char *pkg_or_trigger = _strstrip(list[2]); - action =_strstrip( list[1]); + const char* const pkg_or_trigger = _strstrip(list[2]); + action = _strstrip( list[1]); const std::pair<const char *, const char *> * const iter = std::find_if(PackageProcessingOpsBegin, PackageProcessingOpsEnd, MatchProcessingOp(action)); if(iter == PackageProcessingOpsEnd) { - if (_config->FindB("Debug::pkgDPkgProgressReporting",false) == true) - std::clog << "ignoring unknwon action: " << action << std::endl; + if (Debug == true) + std::clog << "ignoring unknown action: " << action << std::endl; return; } snprintf(s, sizeof(s), _(iter->second), pkg_or_trigger); @@ -440,24 +452,34 @@ void pkgDPkgPM::ProcessDpkgStatusLine(int OutStatusFd, char *line) << endl; if(OutStatusFd > 0) write(OutStatusFd, status.str().c_str(), status.str().size()); - if (_config->FindB("Debug::pkgDPkgProgressReporting",false) == true) + if (Debug == true) std::clog << "send: '" << status.str() << "'" << endl; return; } if(strncmp(action,"error",strlen("error")) == 0) { + // urgs, sometime has ":" in its error string so that we + // end up with the error message split between list[3] + // and list[4], e.g. the message: + // "failed in buffer_write(fd) (10, ret=-1): backend dpkg-deb ..." + // concat them again + if( list[4] != NULL ) + list[3][strlen(list[3])] = ':'; + status << "pmerror:" << list[1] << ":" << (PackagesDone/float(PackagesTotal)*100.0) << ":" << list[3] << endl; if(OutStatusFd > 0) write(OutStatusFd, status.str().c_str(), status.str().size()); - if (_config->FindB("Debug::pkgDPkgProgressReporting",false) == true) + if (Debug == true) std::clog << "send: '" << status.str() << "'" << endl; + pkgFailures++; + WriteApportReport(list[1], list[3]); return; } - if(strncmp(action,"conffile",strlen("conffile")) == 0) + else if(strncmp(action,"conffile",strlen("conffile")) == 0) { status << "pmconffile:" << list[1] << ":" << (PackagesDone/float(PackagesTotal)*100.0) @@ -465,12 +487,12 @@ void pkgDPkgPM::ProcessDpkgStatusLine(int OutStatusFd, char *line) << endl; if(OutStatusFd > 0) write(OutStatusFd, status.str().c_str(), status.str().size()); - if (_config->FindB("Debug::pkgDPkgProgressReporting",false) == true) + if (Debug == true) std::clog << "send: '" << status.str() << "'" << endl; return; } - vector<struct DpkgState> &states = PackageOps[pkg]; + vector<struct DpkgState> const &states = PackageOps[pkg]; const char *next_action = NULL; if(PackageOpsDone[pkg] < states.size()) next_action = states[PackageOpsDone[pkg]].state; @@ -493,15 +515,15 @@ void pkgDPkgPM::ProcessDpkgStatusLine(int OutStatusFd, char *line) << endl; if(OutStatusFd > 0) write(OutStatusFd, status.str().c_str(), status.str().size()); - if (_config->FindB("Debug::pkgDPkgProgressReporting",false) == true) + if (Debug == true) std::clog << "send: '" << status.str() << "'" << endl; } - if (_config->FindB("Debug::pkgDPkgProgressReporting",false) == true) + if (Debug == true) std::clog << "(parsed from dpkg) pkg: " << pkg << " action: " << action << endl; } - -// DPkgPM::DoDpkgStatusFd /*{{{*/ + /*}}}*/ +// DPkgPM::DoDpkgStatusFd /*{{{*/ // --------------------------------------------------------------------- /* */ @@ -538,7 +560,7 @@ void pkgDPkgPM::DoDpkgStatusFd(int statusfd, int OutStatusFd) dpkgbuf_pos = dpkgbuf+dpkgbuf_pos-p; } /*}}}*/ - +// DPkgPM::OpenLog /*{{{*/ bool pkgDPkgPM::OpenLog() { string logdir = _config->FindDir("Dir::Log"); @@ -561,7 +583,8 @@ bool pkgDPkgPM::OpenLog() } return true; } - + /*}}}*/ +// DPkg::CloseLog /*{{{*/ bool pkgDPkgPM::CloseLog() { if(term_out) @@ -578,7 +601,7 @@ bool pkgDPkgPM::CloseLog() term_out = NULL; return true; } - + /*}}}*/ /*{{{*/ // This implements a racy version of pselect for those architectures // that don't have a working implementation. @@ -600,7 +623,6 @@ static int racy_pselect(int nfds, fd_set *readfds, fd_set *writefds, return retval; } /*}}}*/ - // DPkgPM::Go - Run the sequence /*{{{*/ // --------------------------------------------------------------------- /* This globs the operations and calls dpkg @@ -617,9 +639,9 @@ bool pkgDPkgPM::Go(int OutStatusFd) sigset_t sigmask; sigset_t original_sigmask; - unsigned int MaxArgs = _config->FindI("Dpkg::MaxArgs",8*1024); - unsigned int MaxArgBytes = _config->FindI("Dpkg::MaxArgBytes",32*1024); - bool NoTriggers = _config->FindB("DPkg::NoTriggers",false); + unsigned int const MaxArgs = _config->FindI("Dpkg::MaxArgs",8*1024); + unsigned int const MaxArgBytes = _config->FindI("Dpkg::MaxArgBytes",32*1024); + bool const NoTriggers = _config->FindB("DPkg::NoTriggers", false); if (RunScripts("DPkg::Pre-Invoke") == false) return false; @@ -627,6 +649,13 @@ bool pkgDPkgPM::Go(int OutStatusFd) if (RunScriptsWithPkgs("DPkg::Pre-Install-Pkgs") == false) return false; + // 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) + List.push_back(Item(Item::ConfigurePending, PkgIterator())); + // 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] = { @@ -662,16 +691,19 @@ bool pkgDPkgPM::Go(int OutStatusFd) // 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>::iterator I = List.begin(); I != List.end();I++) + for (vector<Item>::const_iterator I = List.begin(); I != List.end();I++) { - string name = (*I).Pkg.Name(); + if((*I).Pkg.end() == true) + continue; + + string const name = (*I).Pkg.Name(); PackageOpsDone[name] = 0; for(int i=0; (DpkgStatesOpMap[(*I).Op][i]).state != NULL; i++) { PackageOps[name].push_back(DpkgStatesOpMap[(*I).Op][i]); PackagesTotal++; } - } + } stdin_is_dev_null = false; @@ -679,11 +711,25 @@ bool pkgDPkgPM::Go(int OutStatusFd) OpenLog(); // this loop is runs once per operation - for (vector<Item>::iterator I = List.begin(); I != List.end();) + for (vector<Item>::const_iterator I = List.begin(); I != List.end();) { - vector<Item>::iterator J = I; - for (; J != List.end() && J->Op == I->Op; J++) - /* nothing */; + // Do all actions with the same Op in one run + vector<Item>::const_iterator J = I; + if (TriggersPending == true) + for (; J != List.end(); J++) + { + if (J->Op == I->Op) + continue; + if (J->Op != Item::TriggersPending) + break; + vector<Item>::const_iterator T = J + 1; + if (T != List.end() && T->Op == I->Op) + continue; + break; + } + else + for (; J != List.end() && J->Op == I->Op; J++) + /* nothing */; // Generate the argument list const char *Args[MaxArgs + 50]; @@ -700,7 +746,7 @@ bool pkgDPkgPM::Go(int OutStatusFd) unsigned int n = 0; unsigned long Size = 0; - string Tmp = _config->Find("Dir::Bin::dpkg","dpkg"); + string const Tmp = _config->Find("Dir::Bin::dpkg","dpkg"); Args[n++] = Tmp.c_str(); Size += strlen(Args[n-1]); @@ -750,11 +796,23 @@ bool pkgDPkgPM::Go(int OutStatusFd) case Item::Configure: Args[n++] = "--configure"; - if (NoTriggers) - Args[n++] = "--no-triggers"; Size += strlen(Args[n-1]); break; - + + case Item::ConfigurePending: + Args[n++] = "--configure"; + Size += strlen(Args[n-1]); + Args[n++] = "--pending"; + Size += strlen(Args[n-1]); + break; + + case Item::TriggersPending: + Args[n++] = "--triggers-only"; + Size += strlen(Args[n-1]); + Args[n++] = "--pending"; + Size += strlen(Args[n-1]); + break; + case Item::Install: Args[n++] = "--unpack"; Size += strlen(Args[n-1]); @@ -762,7 +820,14 @@ bool pkgDPkgPM::Go(int OutStatusFd) Size += strlen(Args[n-1]); break; } - + + if (NoTriggers == true && I->Op != Item::TriggersPending && + I->Op != Item::ConfigurePending) + { + Args[n++] = "--no-triggers"; + Size += strlen(Args[n-1]); + } + // Write in the file or package names if (I->Op == Item::Install) { @@ -778,6 +843,8 @@ bool pkgDPkgPM::Go(int OutStatusFd) { for (;I != J && Size < MaxArgBytes; I++) { + if((*I).Pkg.end() == true) + continue; Args[n++] = I->Pkg.Name(); Size += strlen(Args[n-1]); } @@ -916,11 +983,9 @@ bool pkgDPkgPM::Go(int OutStatusFd) int Status = 0; // we read from dpkg here - int _dpkgin = fd[0]; + int const _dpkgin = fd[0]; close(fd[1]); // close the write end of the pipe - // the result of the waitpid call - int res; if(slave > 0) close(slave); @@ -928,6 +993,8 @@ bool pkgDPkgPM::Go(int OutStatusFd) sigemptyset(&sigmask); sigprocmask(SIG_BLOCK,&sigmask,&original_sigmask); + // the result of the waitpid call + int res; int select_ret; while ((res=waitpid(Child,&Status, WNOHANG)) != Child) { if(res < 0) { @@ -943,7 +1010,6 @@ bool pkgDPkgPM::Go(int OutStatusFd) signal(SIGHUP,old_SIGHUP); return _error->Errno("waitpid","Couldn't wait for subprocess"); } - // wait for input or output here FD_ZERO(&rfds); if (!stdin_is_dev_null) @@ -994,7 +1060,7 @@ bool pkgDPkgPM::Go(int OutStatusFd) // if it was set to "keep-dpkg-runing" then we won't return // here but keep the loop going and just report it as a error // for later - bool stopOnError = _config->FindB("Dpkg::StopOnError",true); + bool const stopOnError = _config->FindB("Dpkg::StopOnError",true); if(stopOnError) RunScripts("DPkg::Post-Invoke"); @@ -1030,3 +1096,186 @@ 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) + { + std::clog << "configured to not write apport reports" << std::endl; + return; + } + + // only report the first errors + if(pkgFailures > _config->FindI("APT::Apport::MaxReports", 3)) + { + std::clog << _("No apport report written because MaxReports is reached already") << std::endl; + return; + } + + // check if its not a follow up error + const char *needle = dgettext("dpkg", "dependency problems - leaving unconfigured"); + if(strstr(errormsg, needle) != NULL) { + std::clog << _("No apport report written because the error message indicates its a followup error from a previous failure.") << std::endl; + return; + } + + // do not report disk-full failures + if(strstr(errormsg, strerror(ENOSPC)) != NULL) { + std::clog << _("No apport report written because the error message indicates a disk full error") << std::endl; + return; + } + + // do not report out-of-memory failures + if(strstr(errormsg, strerror(ENOMEM)) != NULL) { + std::clog << _("No apport report written because the error message indicates a out of memory error") << std::endl; + return; + } + + // do not report dpkg I/O errors + // XXX - this message is localized, but this only matches the English version. This is better than nothing. + if(strstr(errormsg, "short read in buffer_copy (")) { + std::clog << _("No apport report written because the error message indicates a dpkg I/O error") << std::endl; + 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); + 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). + // 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); + } + } + + // log the ordering + const char *ops_str[] = {"Install", "Configure","Remove","Purge"}; + fprintf(report, "AptOrdering:\n"); + for (vector<Item>::iterator I = List.begin(); I != List.end(); I++) + fprintf(report, " %s: %s\n", (*I).Pkg.Name(), ops_str[(*I).Op]); + + // attach dmesg log (to learn about segfaults) + if (FileExists("/bin/dmesg")) + { + FILE *log = NULL; + char buf[1024]; + + fprintf(report, "Dmesg:\n"); + log = popen("/bin/dmesg","r"); + if(log != NULL) + { + while( fgets(buf, sizeof(buf), log) != NULL) + fprintf(report, " %s", buf); + fclose(log); + } + } + + // attach df -l log (to learn about filesystem status) + if (FileExists("/bin/df")) + { + FILE *log = NULL; + char buf[1024]; + + fprintf(report, "Df:\n"); + log = popen("/bin/df -l","r"); + if(log != NULL) + { + while( fgets(buf, sizeof(buf), log) != NULL) + fprintf(report, " %s", buf); + fclose(log); + } + } + + fclose(report); + +} + /*}}}*/ diff --git a/apt-pkg/deb/dpkgpm.h b/apt-pkg/deb/dpkgpm.h index ebc7e32bf..90e5b95e6 100644 --- a/apt-pkg/deb/dpkgpm.h +++ b/apt-pkg/deb/dpkgpm.h @@ -31,6 +31,7 @@ class pkgDPkgPM : public pkgPackageManager FILE *term_out; protected: + int pkgFailures; // progress reporting struct DpkgState @@ -47,13 +48,14 @@ class pkgDPkgPM : public pkgPackageManager // the int is the state that is already done (e.g. a package that is // going to be install is already in state "half-installed") map<string,unsigned int> PackageOpsDone; + // progress reporting unsigned int PackagesDone; unsigned int PackagesTotal; struct Item { - enum Ops {Install, Configure, Remove, Purge} Op; + enum Ops {Install, Configure, Remove, Purge, ConfigurePending, TriggersPending} Op; string File; PkgIterator Pkg; Item(Ops Op,PkgIterator Pkg,string File = "") : Op(Op), @@ -67,6 +69,9 @@ class pkgDPkgPM : public pkgPackageManager bool RunScriptsWithPkgs(const char *Cnf); bool SendV2Pkgs(FILE *F); + // apport integration + void WriteApportReport(const char *pkgpath, const char *errormsg); + // dpkg log bool OpenLog(); bool CloseLog(); diff --git a/apt-pkg/depcache.cc b/apt-pkg/depcache.cc index 45e427d81..ec7a5de64 100644 --- a/apt-pkg/depcache.cc +++ b/apt-pkg/depcache.cc @@ -823,7 +823,7 @@ void pkgDepCache::MarkDelete(PkgIterator const &Pkg, bool rPurge, bool pkgDepCache::IsDeleteOk(PkgIterator const &Pkg,bool rPurge, unsigned long Depth, bool FromUser) { - if (FromUser == false && Pkg->SelectedState == pkgCache::State::Hold) + if (FromUser == false && Pkg->SelectedState == pkgCache::State::Hold && _config->FindB("APT::Ignore-Hold",false) == false) { if (DebugMarker == true) std::clog << OutputInDepth(Depth) << "Hold prevents MarkDelete of " << Pkg << " FU=" << FromUser << std::endl; @@ -1085,7 +1085,7 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst, bool pkgDepCache::IsInstallOk(PkgIterator const &Pkg,bool AutoInst, unsigned long Depth, bool FromUser) { - if (FromUser == false && Pkg->SelectedState == pkgCache::State::Hold) + if (FromUser == false && Pkg->SelectedState == pkgCache::State::Hold && _config->FindB("APT::Ignore-Hold",false) == false) { if (DebugMarker == true) std::clog << OutputInDepth(Depth) << "Hold prevents MarkInstall of " << Pkg << " FU=" << FromUser << std::endl; diff --git a/apt-pkg/indexcopy.cc b/apt-pkg/indexcopy.cc index e7bf046a4..57c9f95ca 100644 --- a/apt-pkg/indexcopy.cc +++ b/apt-pkg/indexcopy.cc @@ -592,7 +592,10 @@ bool SigVerify::CopyAndVerify(string CDROM,string Name,vector<string> &SigList, // a Release.gpg without a Release should never happen if(!FileExists(*I+"Release")) + { + delete MetaIndex; continue; + } // verify the gpg signature of "Release" diff --git a/apt-pkg/init.cc b/apt-pkg/init.cc index 2a3dfae74..6f02203cd 100644 --- a/apt-pkg/init.cc +++ b/apt-pkg/init.cc @@ -51,6 +51,7 @@ bool pkgInitConfig(Configuration &Cnf) Cnf.Set("Dir::State::lists","lists/"); Cnf.Set("Dir::State::cdroms","cdroms.list"); + Cnf.Set("Dir::State::mirrors","mirrors/"); // Cache Cnf.Set("Dir::Cache","var/cache/apt/"); @@ -74,7 +75,7 @@ bool pkgInitConfig(Configuration &Cnf) // State Cnf.Set("Dir::Log","var/log/apt"); Cnf.Set("Dir::Log::Terminal","term.log"); - + // Translation Cnf.Set("APT::Acquire::Translation", "environment"); @@ -104,7 +105,7 @@ bool pkgInitConfig(Configuration &Cnf) if (Res == false) return false; - + if (Cnf.FindB("Debug::pkgInitConfig",false) == true) Cnf.Dump(); diff --git a/apt-pkg/init.h b/apt-pkg/init.h index 165299253..44d1d107c 100644 --- a/apt-pkg/init.h +++ b/apt-pkg/init.h @@ -19,7 +19,7 @@ // See the makefile #define APT_PKG_MAJOR 4 #define APT_PKG_MINOR 8 -#define APT_PKG_RELEASE 0 +#define APT_PKG_RELEASE 1 extern const char *pkgVersion; extern const char *pkgLibVersion; diff --git a/apt-pkg/makefile b/apt-pkg/makefile index 26fc9fac5..f2a8460a9 100644 --- a/apt-pkg/makefile +++ b/apt-pkg/makefile @@ -14,7 +14,7 @@ include ../buildlib/defaults.mak LIBRARY=apt-pkg LIBEXT=$(GLIBC_VER)$(LIBSTDCPP_VER) MAJOR=4.8 -MINOR=0 +MINOR=1 SLIBS=$(PTHREADLIB) $(INTLLIBS) -lutil -ldl APT_DOMAIN:=libapt-pkg$(MAJOR) @@ -34,14 +34,15 @@ SOURCE+= pkgcache.cc version.cc depcache.cc \ acquire-worker.cc acquire-method.cc init.cc clean.cc \ srcrecords.cc cachefile.cc versionmatch.cc policy.cc \ pkgsystem.cc indexfile.cc pkgcachegen.cc acquire-item.cc \ - indexrecords.cc vendor.cc vendorlist.cc cdrom.cc indexcopy.cc + indexrecords.cc vendor.cc vendorlist.cc cdrom.cc indexcopy.cc \ + aptconfiguration.cc HEADERS+= algorithms.h depcache.h pkgcachegen.h cacheiterators.h \ orderlist.h sourcelist.h packagemanager.h tagfile.h \ init.h pkgcache.h version.h progress.h pkgrecords.h \ acquire.h acquire-worker.h acquire-item.h acquire-method.h \ clean.h srcrecords.h cachefile.h versionmatch.h policy.h \ pkgsystem.h indexfile.h metaindex.h indexrecords.h vendor.h \ - vendorlist.h cdrom.h indexcopy.h + vendorlist.h cdrom.h indexcopy.h aptconfiguration.h # Source code for the debian specific components # In theory the deb headers do not need to be exported.. diff --git a/apt-pkg/orderlist.cc b/apt-pkg/orderlist.cc index 01b150722..0ee2e2bc8 100644 --- a/apt-pkg/orderlist.cc +++ b/apt-pkg/orderlist.cc @@ -174,22 +174,35 @@ bool pkgOrderList::DoRun() bool pkgOrderList::OrderCritical() { FileList = 0; - - Primary = &pkgOrderList::DepUnPackPre; + + Primary = &pkgOrderList::DepUnPackPreD; Secondary = 0; RevDepends = 0; Remove = 0; LoopCount = 0; - + // Sort Me = this; - qsort(List,End - List,sizeof(*List),&OrderCompareB); - + qsort(List,End - List,sizeof(*List),&OrderCompareB); + if (DoRun() == false) return false; - + if (LoopCount != 0) return _error->Error("Fatal, predepends looping detected"); + + if (Debug == true) + { + clog << "** Critical Unpack ordering done" << endl; + + for (iterator I = List; I != End; I++) + { + PkgIterator P(Cache,*I); + if (IsNow(P) == true) + clog << " " << P.Name() << ' ' << IsMissing(P) << ',' << IsFlag(P,After) << endl; + } + } + return true; } /*}}}*/ @@ -205,7 +218,7 @@ bool pkgOrderList::OrderUnpack(string *FileList) if (FileList != 0) { WipeFlags(After); - + // Set the inlist flag for (iterator I = List; I != End; I++) { @@ -214,7 +227,7 @@ bool pkgOrderList::OrderUnpack(string *FileList) Flag(*I,After); } } - + Primary = &pkgOrderList::DepUnPackCrit; Secondary = &pkgOrderList::DepConfigure; RevDepends = &pkgOrderList::DepUnPackDep; @@ -229,7 +242,7 @@ bool pkgOrderList::OrderUnpack(string *FileList) clog << "** Pass A" << endl; if (DoRun() == false) return false; - + if (Debug == true) clog << "** Pass B" << endl; Secondary = 0; @@ -243,7 +256,7 @@ bool pkgOrderList::OrderUnpack(string *FileList) Remove = 0; // Otherwise the libreadline remove problem occures if (DoRun() == false) return false; - + if (Debug == true) clog << "** Pass D" << endl; LoopCount = 0; @@ -259,9 +272,9 @@ bool pkgOrderList::OrderUnpack(string *FileList) { PkgIterator P(Cache,*I); if (IsNow(P) == true) - clog << P.Name() << ' ' << IsMissing(P) << ',' << IsFlag(P,After) << endl; + clog << " " << P.Name() << ' ' << IsMissing(P) << ',' << IsFlag(P,After) << endl; } - } + } return true; } @@ -286,29 +299,35 @@ bool pkgOrderList::OrderConfigure() /* Higher scores order earlier */ int pkgOrderList::Score(PkgIterator Pkg) { + static int const ScoreDelete = _config->FindI("OrderList::Score::Delete", 500); + // Removal is always done first if (Cache[Pkg].Delete() == true) - return 200; - + return ScoreDelete; + // This should never happen.. if (Cache[Pkg].InstVerIter(Cache).end() == true) return -1; - + + static int const ScoreEssential = _config->FindI("OrderList::Score::Essential", 200); + static int const ScoreImmediate = _config->FindI("OrderList::Score::Immediate", 10); + static int const ScorePreDepends = _config->FindI("OrderList::Score::PreDepends", 50); + int Score = 0; if ((Pkg->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential) - Score += 100; + Score += ScoreEssential; if (IsFlag(Pkg,Immediate) == true) - Score += 10; - - for (DepIterator D = Cache[Pkg].InstVerIter(Cache).DependsList(); + Score += ScoreImmediate; + + for (DepIterator D = Cache[Pkg].InstVerIter(Cache).DependsList(); D.end() == false; D++) if (D->Type == pkgCache::Dep::PreDepends) { - Score += 50; + Score += ScorePreDepends; break; } - + // Important Required Standard Optional Extra signed short PrioMap[] = {0,5,4,3,1,0}; if (Cache[Pkg].InstVerIter(Cache)->Priority <= 5) @@ -386,6 +405,7 @@ int pkgOrderList::OrderCompareA(const void *a, const void *b) int ScoreA = Me->Score(A); int ScoreB = Me->Score(B); + if (ScoreA > ScoreB) return -1; @@ -422,6 +442,7 @@ int pkgOrderList::OrderCompareB(const void *a, const void *b) int ScoreA = Me->Score(A); int ScoreB = Me->Score(B); + if (ScoreA > ScoreB) return -1; diff --git a/apt-pkg/packagemanager.cc b/apt-pkg/packagemanager.cc index 019a1db1f..c6812ed11 100644 --- a/apt-pkg/packagemanager.cc +++ b/apt-pkg/packagemanager.cc @@ -57,7 +57,10 @@ bool pkgPackageManager::GetArchives(pkgAcquire *Owner,pkgSourceList *Sources, if (CreateOrderList() == false) return false; - if (List->OrderUnpack() == false) + bool const ordering = + _config->FindB("PackageManager::UnpackAll",true) ? + List->OrderUnpack() : List->OrderCritical(); + if (ordering == false) return _error->Error("Internal ordering error"); for (pkgOrderList::iterator I = List->begin(); I != List->end(); I++) @@ -163,7 +166,7 @@ bool pkgPackageManager::CreateOrderList() delete List; List = new pkgOrderList(&Cache); - bool NoImmConfigure = !_config->FindB("APT::Immediate-Configure",true); + static bool const NoImmConfigure = !_config->FindB("APT::Immediate-Configure",true); // Generate the list of affected packages and sort it for (PkgIterator I = Cache.PkgBegin(); I.end() == false; I++) @@ -266,13 +269,16 @@ bool pkgPackageManager::ConfigureAll() if (OList.OrderConfigure() == false) return false; - + + std::string const conf = _config->Find("PackageManager::Configure","all"); + bool const ConfigurePkgs = (conf == "all"); + // Perform the configuring for (pkgOrderList::iterator I = OList.begin(); I != OList.end(); I++) { PkgIterator Pkg(Cache,*I); - if (Configure(Pkg) == false) + if (ConfigurePkgs == true && Configure(Pkg) == false) return false; List->Flag(Pkg,pkgOrderList::Configured,pkgOrderList::States); @@ -294,19 +300,20 @@ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg) if (DepAdd(OList,Pkg) == false) return false; - - if (OList.OrderConfigure() == false) - return false; - + + static std::string const conf = _config->Find("PackageManager::Configure","all"); + static bool const ConfigurePkgs = (conf == "all" || conf == "smart"); + + if (ConfigurePkgs == true) + if (OList.OrderConfigure() == false) + return false; + // Perform the configuring for (pkgOrderList::iterator I = OList.begin(); I != OList.end(); I++) { PkgIterator Pkg(Cache,*I); - if (Debug == true) - clog << " SmartConfigure on" << Pkg.Name() << endl; - - if (Configure(Pkg) == false) + if (ConfigurePkgs == true && Configure(Pkg) == false) return false; List->Flag(Pkg,pkgOrderList::Configured,pkgOrderList::States); @@ -590,9 +597,12 @@ pkgPackageManager::OrderResult pkgPackageManager::OrderInstall() Reset(); if (Debug == true) - clog << "Begining to order" << endl; + clog << "Beginning to order" << endl; - if (List->OrderUnpack(FileNames) == false) + bool const ordering = + _config->FindB("PackageManager::UnpackAll",true) ? + List->OrderUnpack(FileNames) : List->OrderCritical(); + if (ordering == false) { _error->Error("Internal ordering error"); return Failed; @@ -645,7 +655,7 @@ pkgPackageManager::OrderResult pkgPackageManager::OrderInstall() return Failed; DoneSomething = true; } - + // Final run through the configure phase if (ConfigureAll() == false) return Failed; diff --git a/apt-pkg/pkgrecords.cc b/apt-pkg/pkgrecords.cc index e506de73a..a5dab22ff 100644 --- a/apt-pkg/pkgrecords.cc +++ b/apt-pkg/pkgrecords.cc @@ -23,8 +23,8 @@ pkgRecords::pkgRecords(pkgCache &Cache) : Cache(Cache), Files(Cache.HeaderP->PackageFileCount) { - for (pkgCache::PkgFileIterator I = Cache.FileBegin(); - I.end() == false; I++) + for (pkgCache::PkgFileIterator I = Cache.FileBegin(); + I.end() == false; I++) { const pkgIndexFile::Type *Type = pkgIndexFile::Type::GetType(I.IndexType()); if (Type == 0) diff --git a/apt-pkg/tagfile.cc b/apt-pkg/tagfile.cc index 7c5d15a58..1c41f1265 100644 --- a/apt-pkg/tagfile.cc +++ b/apt-pkg/tagfile.cc @@ -418,6 +418,7 @@ static const char *iTFRewritePackageOrder[] = { "Section", "Installed-Size", "Maintainer", + "Original-Maintainer", "Architecture", "Source", "Version", @@ -447,6 +448,7 @@ static const char *iTFRewriteSourceOrder[] = {"Package", "Priority", "Section", "Maintainer", + "Original-Maintainer", "Build-Depends", "Build-Depends-Indep", "Build-Conflicts", |