diff options
Diffstat (limited to 'apt-pkg')
-rw-r--r-- | apt-pkg/acquire-item.cc | 138 | ||||
-rw-r--r-- | apt-pkg/acquire-item.h | 16 | ||||
-rw-r--r-- | apt-pkg/acquire-method.cc | 53 | ||||
-rw-r--r-- | apt-pkg/acquire-method.h | 17 | ||||
-rw-r--r-- | apt-pkg/acquire-worker.cc | 14 | ||||
-rw-r--r-- | apt-pkg/algorithms.cc | 3 | ||||
-rw-r--r-- | apt-pkg/contrib/strutl.cc | 29 | ||||
-rw-r--r-- | apt-pkg/contrib/strutl.h | 1 | ||||
-rw-r--r-- | apt-pkg/deb/debsystem.cc | 17 | ||||
-rw-r--r-- | apt-pkg/deb/dpkgpm.cc | 170 | ||||
-rw-r--r-- | apt-pkg/deb/dpkgpm.h | 10 | ||||
-rw-r--r-- | apt-pkg/depcache.cc | 1 | ||||
-rw-r--r-- | apt-pkg/indexcopy.cc | 9 | ||||
-rw-r--r-- | apt-pkg/indexrecords.cc | 6 | ||||
-rw-r--r-- | apt-pkg/init.cc | 3 | ||||
-rw-r--r-- | apt-pkg/makefile | 2 | ||||
-rw-r--r-- | apt-pkg/pkgcache.h | 8 | ||||
-rw-r--r-- | apt-pkg/pkgrecords.cc | 4 | ||||
-rw-r--r-- | apt-pkg/tagfile.cc | 2 |
19 files changed, 410 insertions, 93 deletions
diff --git a/apt-pkg/acquire-item.cc b/apt-pkg/acquire-item.cc index 09ea5da02..91f3d0605 100644 --- a/apt-pkg/acquire-item.cc +++ b/apt-pkg/acquire-item.cc @@ -63,6 +63,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 +76,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 +108,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 +117,6 @@ void pkgAcquire::Item::Done(string Message,unsigned long Size,string Hash, if (FileSize == 0) FileSize= Size; - Status = StatDone; ErrorText = string(); Owner->Dequeue(this); @@ -132,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 // --------------------------------------------------------------------- @@ -590,7 +640,6 @@ 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); } /*}}}*/ @@ -657,6 +706,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 @@ -849,8 +899,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); } /*}}}*/ @@ -863,7 +914,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 @@ -939,6 +990,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 { @@ -990,22 +1050,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) @@ -1035,7 +1088,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); @@ -1076,7 +1128,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 @@ -1180,30 +1232,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 a48f7f7e5..af0b2d888 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. * @@ -543,7 +555,8 @@ class pkgAcqIndex : public pkgAcquire::Item * (".bz2" is used if bzip2 is installed, ".gz" otherwise). */ 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 @@ -612,7 +625,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 bc29417f7..150fbb77b 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(); @@ -447,6 +452,38 @@ void pkgAcqMethod::Status(const char *Format,...) } /*}}}*/ +// AcqMethod::Redirect - Send a redirect message /*{{{*/ +// --------------------------------------------------------------------- +/* This method sends the redirect message and also manipulates the queue + to keep the pipeline synchronized. */ +void pkgAcqMethod::Redirect(const string &NewURI) +{ + string CurrentURI = "<UNKNOWN>"; + if (Queue != 0) + CurrentURI = Queue->Uri; + + char S[1024]; + snprintf(S, sizeof(S)-50, "103 Redirect\nURI: %s\nNew-URI: %s\n\n", + CurrentURI.c_str(), NewURI.c_str()); + + if (write(STDOUT_FILENO,S,strlen(S)) != (ssize_t)strlen(S)) + exit(100); + + // Change the URI for the request. + Queue->Uri = NewURI; + + /* To keep the pipeline synchronized, move the current request to + the end of the queue, past the end of the current pipeline. */ + FetchItem *I; + for (I = Queue; I->Next != 0; I = I->Next) ; + I->Next = Queue; + Queue = Queue->Next; + I->Next->Next = 0; + if (QueueBack == 0) + QueueBack = I->Next; +} + /*}}}*/ + // AcqMethod::FetchResult::FetchResult - Constructor /*{{{*/ // --------------------------------------------------------------------- /* */ diff --git a/apt-pkg/acquire-method.h b/apt-pkg/acquire-method.h index e02eab018..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), @@ -84,8 +86,11 @@ class pkgAcqMethod void Log(const char *Format,...); void Status(const char *Format,...); + 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/acquire-worker.cc b/apt-pkg/acquire-worker.cc index 1a754dae9..78c68737c 100644 --- a/apt-pkg/acquire-worker.cc +++ b/apt-pkg/acquire-worker.cc @@ -220,6 +220,20 @@ bool pkgAcquire::Worker::RunMessages() Status = LookupTag(Message,"Message"); break; + // 103 Redirect + case 103: + { + if (Itm == 0) + { + _error->Error("Method gave invalid 103 Redirect message"); + break; + } + + string NewURI = LookupTag(Message,"New-URI",URI.c_str()); + Itm->URI = NewURI; + break; + } + // 200 URI Start case 200: { diff --git a/apt-pkg/algorithms.cc b/apt-pkg/algorithms.cc index bd33d5ef1..8bd98a620 100644 --- a/apt-pkg/algorithms.cc +++ b/apt-pkg/algorithms.cc @@ -1109,8 +1109,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/contrib/strutl.cc b/apt-pkg/contrib/strutl.cc index bd374fd1e..fe9082f63 100644 --- a/apt-pkg/contrib/strutl.cc +++ b/apt-pkg/contrib/strutl.cc @@ -331,23 +331,27 @@ string TimeToStr(unsigned long Sec) { if (Sec > 60*60*24) { - sprintf(S,"%lid %lih%limin%lis",Sec/60/60/24,(Sec/60/60) % 24,(Sec/60) % 60,Sec % 60); + //d means days, h means hours, min means minutes, s means seconds + sprintf(S,_("%lid %lih %limin %lis"),Sec/60/60/24,(Sec/60/60) % 24,(Sec/60) % 60,Sec % 60); break; } if (Sec > 60*60) { - sprintf(S,"%lih%limin%lis",Sec/60/60,(Sec/60) % 60,Sec % 60); + //h means hours, min means minutes, s means seconds + sprintf(S,_("%lih %limin %lis"),Sec/60/60,(Sec/60) % 60,Sec % 60); break; } if (Sec > 60) { - sprintf(S,"%limin%lis",Sec/60,Sec % 60); + //min means minutes, s means seconds + sprintf(S,_("%limin %lis"),Sec/60,Sec % 60); break; } - - sprintf(S,"%lis",Sec); + + //s means seconds + sprintf(S,_("%lis"),Sec); break; } @@ -1032,6 +1036,21 @@ void ioprintf(ostream &out,const char *format,...) out << S; } /*}}}*/ +// strprintf - C format string outputter to C++ strings /*{{{*/ +// --------------------------------------------------------------------- +/* This is used to make the internationalization strings easier to translate + and to allow reordering of parameters */ +void strprintf(string &out,const char *format,...) +{ + va_list args; + va_start(args,format); + + // sprintf the description + char S[1024]; + vsnprintf(S,sizeof(S),format,args); + out = string(S); +} + /*}}}*/ // safe_snprintf - Safer snprintf /*{{{*/ // --------------------------------------------------------------------- /* This is a snprintf that will never (ever) go past 'End' and returns a diff --git a/apt-pkg/contrib/strutl.h b/apt-pkg/contrib/strutl.h index 53146ced7..d9972abf4 100644 --- a/apt-pkg/contrib/strutl.h +++ b/apt-pkg/contrib/strutl.h @@ -59,6 +59,7 @@ bool Hex2Num(const string &Str,unsigned char *Num,unsigned int Length); bool TokSplitString(char Tok,char *Input,char **List, unsigned long ListMax); void ioprintf(ostream &out,const char *format,...) APT_FORMAT2; +void strprintf(string &out,const char *format,...) APT_FORMAT2; char *safe_snprintf(char *Buffer,char *End,const char *Format,...) APT_FORMAT3; bool CheckDomainList(const string &Host, const string &List); diff --git a/apt-pkg/deb/debsystem.cc b/apt-pkg/deb/debsystem.cc index 11a84f1c6..186918d25 100644 --- a/apt-pkg/deb/debsystem.cc +++ b/apt-pkg/deb/debsystem.cc @@ -17,7 +17,8 @@ #include <apt-pkg/configuration.h> #include <apt-pkg/error.h> #include <apt-pkg/fileutl.h> - +#include <apti18n.h> + #include <sys/types.h> #include <unistd.h> #include <dirent.h> @@ -66,11 +67,11 @@ bool debSystem::Lock() if (LockFD == -1) { if (errno == EACCES || errno == EAGAIN) - return _error->Error("Unable to lock the administration directory (%s), " - "is another process using it?",AdminDir.c_str()); + return _error->Error(_("Unable to lock the administration directory (%s), " + "is another process using it?"),AdminDir.c_str()); else - return _error->Error("Unable to lock the administration directory (%s), " - "are you root?",AdminDir.c_str()); + return _error->Error(_("Unable to lock the administration directory (%s), " + "are you root?"),AdminDir.c_str()); } // See if we need to abort with a dirty journal @@ -78,8 +79,8 @@ bool debSystem::Lock() { close(LockFD); LockFD = -1; - return _error->Error("dpkg was interrupted, you must manually " - "run 'dpkg --configure -a' to correct the problem. "); + return _error->Error(_("dpkg was interrupted, you must manually " + "run 'sudo dpkg --configure -a' to correct the problem. ")); } LockCount++; @@ -96,7 +97,7 @@ bool debSystem::UnLock(bool NoErrors) return false; if (LockCount < 1) - return _error->Error("Not locked"); + return _error->Error(_("Not locked")); if (--LockCount == 0) { close(LockFD); diff --git a/apt-pkg/deb/dpkgpm.cc b/apt-pkg/deb/dpkgpm.cc index 40aafafa4..a54c20330 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> @@ -79,7 +81,7 @@ namespace /* */ 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) { } /*}}}*/ @@ -306,7 +308,6 @@ bool pkgDPkgPM::RunScriptsWithPkgs(const char *Cnf) return true; } - /*}}}*/ // DPkgPM::DoStdin - Read stdin and pass to slave pty /*{{{*/ // --------------------------------------------------------------------- @@ -374,7 +375,7 @@ void pkgDPkgPM::ProcessDpkgStatusLine(int OutStatusFd, char *line) '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 @@ -422,6 +423,14 @@ void pkgDPkgPM::ProcessDpkgStatusLine(int OutStatusFd, char *line) 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] @@ -430,6 +439,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) @@ -587,6 +598,11 @@ static int racy_pselect(int nfds, fd_set *readfds, fd_set *writefds, */ bool pkgDPkgPM::Go(int OutStatusFd) { + fd_set rfds; + struct timespec tv; + 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); @@ -798,7 +814,14 @@ bool pkgDPkgPM::Go(int OutStatusFd) rtt = tt; cfmakeraw(&rtt); rtt.c_lflag &= ~ECHO; + // 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); } // Fork dpkg @@ -865,10 +888,6 @@ bool pkgDPkgPM::Go(int OutStatusFd) close(slave); // setups fds - fd_set rfds; - struct timespec tv; - sigset_t sigmask; - sigset_t original_sigmask; sigemptyset(&sigmask); sigprocmask(SIG_BLOCK,&sigmask,&original_sigmask); @@ -887,7 +906,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) @@ -974,3 +992,139 @@ 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; + } + + // 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); + } + } + fclose(report); +} + /*}}}*/ diff --git a/apt-pkg/deb/dpkgpm.h b/apt-pkg/deb/dpkgpm.h index ebc7e32bf..62d3d893d 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,6 +48,12 @@ 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; + + +#if 1 // FIXME: BINARY COMPATIBILITY ONLY, remove on next ABI break + map<string,string> PackageProcessingOps; +#endif + // progress reporting unsigned int PackagesDone; unsigned int PackagesTotal; @@ -67,6 +74,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 2411bfe89..8584419e1 100644 --- a/apt-pkg/depcache.cc +++ b/apt-pkg/depcache.cc @@ -1461,3 +1461,4 @@ bool pkgDepCache::Sweep() return true; } + diff --git a/apt-pkg/indexcopy.cc b/apt-pkg/indexcopy.cc index 9e5c03e0b..b1e75e30f 100644 --- a/apt-pkg/indexcopy.cc +++ b/apt-pkg/indexcopy.cc @@ -522,6 +522,15 @@ bool SigVerify::Verify(string prefix, string file, indexRecords *MetaIndex) { const indexRecords::checkSum *Record = MetaIndex->Lookup(file); + // we skip non-existing files in the verifcation to support a cdrom + // with no Packages file (just a Package.gz), see LP: #255545 + // (non-existing files are not considered a error) + if(!FileExists(prefix+file)) + { + _error->Warning("Skipping non-exisiting file %s", string(prefix+file).c_str()); + return true; + } + if (!Record) { _error->Warning("Can't find authentication record for: %s",file.c_str()); diff --git a/apt-pkg/indexrecords.cc b/apt-pkg/indexrecords.cc index 502f454a8..ab208e246 100644 --- a/apt-pkg/indexrecords.cc +++ b/apt-pkg/indexrecords.cc @@ -37,14 +37,14 @@ bool indexRecords::Load(const string Filename) pkgTagFile TagFile(&Fd, Fd.Size() + 256); // XXX if (_error->PendingError() == true) { - ErrorText = _(("Unable to parse Release file " + Filename).c_str()); + strprintf(ErrorText, _("Unable to parse Release file %s"),Filename.c_str()); return false; } pkgTagSection Section; if (TagFile.Step(Section) == false) { - ErrorText = _(("No sections in Release file " + Filename).c_str()); + strprintf(ErrorText, _("No sections in Release file %s"), Filename.c_str()); return false; } @@ -78,7 +78,7 @@ bool indexRecords::Load(const string Filename) if(HashString::SupportedHashes()[i] == NULL) { - ErrorText = _(("No Hash entry in Release file " + Filename).c_str()); + strprintf(ErrorText, _("No Hash entry in Release file %s"), Filename.c_str()); return false; } diff --git a/apt-pkg/init.cc b/apt-pkg/init.cc index 338bef66c..c0384cd45 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/"); @@ -72,7 +73,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"); diff --git a/apt-pkg/makefile b/apt-pkg/makefile index 1b78c94f6..087f17740 100644 --- a/apt-pkg/makefile +++ b/apt-pkg/makefile @@ -13,7 +13,7 @@ include ../buildlib/defaults.mak # methods/makefile - FIXME LIBRARY=apt-pkg LIBEXT=$(GLIBC_VER)$(LIBSTDCPP_VER) -MAJOR=4.6 +MAJOR=4.7 MINOR=0 SLIBS=$(PTHREADLIB) $(INTLLIBS) -lutil APT_DOMAIN:=libapt-pkg$(MAJOR) diff --git a/apt-pkg/pkgcache.h b/apt-pkg/pkgcache.h index 59d5003bb..759e9a225 100644 --- a/apt-pkg/pkgcache.h +++ b/apt-pkg/pkgcache.h @@ -214,7 +214,7 @@ struct pkgCache::Package unsigned char InstState; // Flags unsigned char CurrentState; // State - unsigned short ID; + unsigned int ID; unsigned long Flags; }; @@ -235,7 +235,7 @@ struct pkgCache::PackageFile // Linked list map_ptrloc NextFile; // PackageFile - unsigned short ID; + unsigned int ID; time_t mtime; // Modification time for the file }; @@ -272,7 +272,7 @@ struct pkgCache::Version map_ptrloc Size; // These are the .deb size map_ptrloc InstalledSize; unsigned short Hash; - unsigned short ID; + unsigned int ID; unsigned char Priority; }; @@ -289,7 +289,7 @@ struct pkgCache::Description map_ptrloc NextDesc; // Description map_ptrloc ParentPkg; // Package - unsigned short ID; + unsigned int ID; }; struct pkgCache::Dependency 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 893cb8ee7..0ae6950f3 100644 --- a/apt-pkg/tagfile.cc +++ b/apt-pkg/tagfile.cc @@ -407,6 +407,7 @@ static const char *iTFRewritePackageOrder[] = { "Section", "Installed-Size", "Maintainer", + "Original-Maintainer", "Architecture", "Source", "Version", @@ -436,6 +437,7 @@ static const char *iTFRewriteSourceOrder[] = {"Package", "Priority", "Section", "Maintainer", + "Original-Maintainer", "Build-Depends", "Build-Depends-Indep", "Build-Conflicts", |