summaryrefslogtreecommitdiff
path: root/apt-pkg
diff options
context:
space:
mode:
Diffstat (limited to 'apt-pkg')
-rw-r--r--apt-pkg/acquire-item.cc24
-rw-r--r--apt-pkg/acquire-method.cc247
-rw-r--r--apt-pkg/acquire-method.h3
-rw-r--r--apt-pkg/acquire-worker.cc11
-rw-r--r--apt-pkg/algorithms.cc105
-rw-r--r--apt-pkg/algorithms.h1
-rw-r--r--apt-pkg/aptconfiguration.cc2
-rw-r--r--apt-pkg/cacheiterators.h1
-rw-r--r--apt-pkg/cacheset.h26
-rw-r--r--apt-pkg/cdrom.cc88
-rw-r--r--apt-pkg/contrib/cdromutl.cc16
-rw-r--r--apt-pkg/contrib/error.cc2
-rw-r--r--apt-pkg/contrib/mmap.cc8
-rw-r--r--apt-pkg/contrib/netrc.cc12
-rw-r--r--apt-pkg/contrib/progress.cc27
-rw-r--r--apt-pkg/contrib/progress.h3
-rw-r--r--apt-pkg/contrib/strutl.cc8
-rw-r--r--apt-pkg/deb/deblistparser.cc12
-rw-r--r--apt-pkg/deb/debmetaindex.cc5
-rw-r--r--apt-pkg/deb/dpkgpm.cc5
-rw-r--r--apt-pkg/depcache.cc137
-rw-r--r--apt-pkg/depcache.h1
-rw-r--r--apt-pkg/edsp.cc439
-rw-r--r--apt-pkg/edsp.h197
-rw-r--r--apt-pkg/edsp/edsplistparser.cc7
-rw-r--r--apt-pkg/indexcopy.cc10
-rw-r--r--apt-pkg/init.cc2
-rw-r--r--apt-pkg/orderlist.cc18
-rw-r--r--apt-pkg/packagemanager.cc44
-rw-r--r--apt-pkg/packagemanager.h2
-rw-r--r--apt-pkg/pkgcache.cc46
-rw-r--r--apt-pkg/pkgcache.h6
-rw-r--r--apt-pkg/pkgcachegen.cc5
-rw-r--r--apt-pkg/policy.cc14
34 files changed, 1008 insertions, 526 deletions
diff --git a/apt-pkg/acquire-item.cc b/apt-pkg/acquire-item.cc
index cf88ded7b..6785b4e1b 100644
--- a/apt-pkg/acquire-item.cc
+++ b/apt-pkg/acquire-item.cc
@@ -840,7 +840,7 @@ string pkgAcqIndex::Custom600Headers()
if (ShortDesc().find("Translation") != 0)
msg += "\nFail-Ignore: true";
struct stat Buf;
- if (stat(Final.c_str(),&Buf) != 0)
+ if (stat(Final.c_str(),&Buf) == 0)
msg += "\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
return msg;
@@ -1502,6 +1502,26 @@ void pkgAcqMetaIndex::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
ReportMirrorFailure("GPGFailure");
}
+ /* Always move the meta index, even if gpgv failed. This ensures
+ * that PackageFile objects are correctly filled in */
+ if (FileExists(DestFile)) {
+ string FinalFile = _config->FindDir("Dir::State::lists");
+ FinalFile += URItoFileName(RealURI);
+ /* InRelease files become Release files, otherwise
+ * they would be considered as trusted later on */
+ if (SigFile == DestFile) {
+ RealURI = RealURI.replace(RealURI.rfind("InRelease"), 9,
+ "Release");
+ FinalFile = FinalFile.replace(FinalFile.rfind("InRelease"), 9,
+ "Release");
+ SigFile = FinalFile;
+ }
+ Rename(DestFile,FinalFile);
+ chmod(FinalFile.c_str(),0644);
+
+ DestFile = FinalFile;
+ }
+
// No Release file was present, or verification failed, so fall
// back to queueing Packages files without verification
QueueIndexes(false);
@@ -1625,7 +1645,7 @@ pkgAcqArchive::pkgAcqArchive(pkgAcquire *Owner,pkgSourceList *Sources,
// Select a source
if (QueueNext() == false && _error->PendingError() == false)
- _error->Error(_("I wasn't able to locate file for the %s package. "
+ _error->Error(_("I wasn't able to locate a file for the %s package. "
"This might mean you need to manually fix this package."),
Version.ParentPkg().Name());
}
diff --git a/apt-pkg/acquire-method.cc b/apt-pkg/acquire-method.cc
index fb45d9ee7..e9e102488 100644
--- a/apt-pkg/acquire-method.cc
+++ b/apt-pkg/acquire-method.cc
@@ -23,9 +23,7 @@
#include <apt-pkg/hashes.h>
#include <iostream>
-#include <stdarg.h>
#include <stdio.h>
-#include <unistd.h>
#include <sys/signal.h>
/*}}}*/
@@ -36,32 +34,28 @@ using namespace std;
/* This constructs the initialization text */
pkgAcqMethod::pkgAcqMethod(const char *Ver,unsigned long Flags)
{
- char S[300] = "";
- char *End = S;
- strcat(End,"100 Capabilities\n");
- sprintf(End+strlen(End),"Version: %s\n",Ver);
+ std::cout << "100 Capabilities\n"
+ << "Version: " << Ver << "\n";
if ((Flags & SingleInstance) == SingleInstance)
- strcat(End,"Single-Instance: true\n");
-
+ std::cout << "Single-Instance: true\n";
+
if ((Flags & Pipeline) == Pipeline)
- strcat(End,"Pipeline: true\n");
-
+ std::cout << "Pipeline: true\n";
+
if ((Flags & SendConfig) == SendConfig)
- strcat(End,"Send-Config: true\n");
+ std::cout << "Send-Config: true\n";
if ((Flags & LocalOnly) == LocalOnly)
- strcat(End,"Local-Only: true\n");
+ std::cout <<"Local-Only: true\n";
if ((Flags & NeedsCleanup) == NeedsCleanup)
- strcat(End,"Needs-Cleanup: true\n");
+ std::cout << "Needs-Cleanup: true\n";
if ((Flags & Removable) == Removable)
- strcat(End,"Removable: true\n");
- strcat(End,"\n");
+ std::cout << "Removable: true\n";
- if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
- exit(100);
+ std::cout << "\n" << std::flush;
SetNonBlock(STDIN_FILENO,true);
@@ -94,13 +88,11 @@ void pkgAcqMethod::Fail(string Err,bool Transient)
if (*I == '\n')
*I = ' ';
}
-
- char S[1024];
- char *End = S;
+
if (Queue != 0)
{
- 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());
+ std::cout << "400 URI Failure\nURI: " << Queue->Uri << "\n"
+ << "Message: " << Err << " " << IP << "\n";
// Dequeue
FetchItem *Tmp = Queue;
Queue = Queue->Next;
@@ -109,22 +101,17 @@ void pkgAcqMethod::Fail(string Err,bool Transient)
QueueBack = Queue;
}
else
- {
- End += snprintf(S,sizeof(S)-50,"400 URI Failure\nURI: <UNKNOWN>\n"
- "Message: %s\n",Err.c_str());
- }
+ std::cout << "400 URI Failure\nURI: <UNKNOWN>\nMessage: " << Err << "\n";
+
if(FailReason.empty() == false)
- End += snprintf(End,sizeof(S)-50 - (End - S),"FailReason: %s\n",FailReason.c_str());
+ std::cout << "FailReason: " << FailReason << "\n";
if (UsedMirror.empty() == false)
- End += snprintf(End,sizeof(S)-50 - (End - S),"UsedMirror: %s\n",UsedMirror.c_str());
- // Set the transient flag
+ std::cout << "UsedMirror: " << UsedMirror << "\n";
+ // Set the transient flag
if (Transient == true)
- strcat(S,"Transient-Failure: true\n\n");
- else
- strcat(S,"\n");
-
- if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
- exit(100);
+ std::cout << "Transient-Failure: true\n";
+
+ std::cout << "\n" << std::flush;
}
/*}}}*/
// AcqMethod::URIStart - Indicate a download is starting /*{{{*/
@@ -134,27 +121,22 @@ void pkgAcqMethod::URIStart(FetchResult &Res)
{
if (Queue == 0)
abort();
-
- char S[1024] = "";
- char *End = S;
-
- End += snprintf(S,sizeof(S),"200 URI Start\nURI: %s\n",Queue->Uri.c_str());
+
+ std::cout << "200 URI Start\n"
+ << "URI: " << Queue->Uri << "\n";
if (Res.Size != 0)
- End += snprintf(End,sizeof(S)-4 - (End - S),"Size: %lu\n",Res.Size);
-
+ std::cout << "Size: " << Res.Size << "\n";
+
if (Res.LastModified != 0)
- End += snprintf(End,sizeof(S)-4 - (End - S),"Last-Modified: %s\n",
- TimeRFC1123(Res.LastModified).c_str());
-
+ std::cout << "Last-Modified: " << TimeRFC1123(Res.LastModified) << "\n";
+
if (Res.ResumePoint != 0)
- End += snprintf(End,sizeof(S)-4 - (End - S),"Resume-Point: %lu\n",
- Res.ResumePoint);
+ std::cout << "Resume-Point: " << Res.ResumePoint << "\n";
+
if (UsedMirror.empty() == false)
- End += snprintf(End,sizeof(S)-4 - (End - S),"UsedMirror: %s\n",UsedMirror.c_str());
-
- strcat(End,"\n");
- if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
- exit(100);
+ std::cout << "UsedMirror: " << UsedMirror << "\n";
+
+ std::cout << "\n" << std::flush;
}
/*}}}*/
// AcqMethod::URIDone - A URI is finished /*{{{*/
@@ -164,76 +146,65 @@ void pkgAcqMethod::URIDone(FetchResult &Res, FetchResult *Alt)
{
if (Queue == 0)
abort();
-
- char S[1024] = "";
- char *End = S;
-
- End += snprintf(S,sizeof(S),"201 URI Done\nURI: %s\n",Queue->Uri.c_str());
+
+ std::cout << "201 URI Done\n"
+ << "URI: " << Queue->Uri << "\n";
if (Res.Filename.empty() == false)
- End += snprintf(End,sizeof(S)-50 - (End - S),"Filename: %s\n",Res.Filename.c_str());
-
+ std::cout << "Filename: " << Res.Filename << "\n";
+
if (Res.Size != 0)
- End += snprintf(End,sizeof(S)-50 - (End - S),"Size: %lu\n",Res.Size);
-
+ std::cout << "Size: " << Res.Size << "\n";
+
if (Res.LastModified != 0)
- End += snprintf(End,sizeof(S)-50 - (End - S),"Last-Modified: %s\n",
- TimeRFC1123(Res.LastModified).c_str());
+ std::cout << "Last-Modified: " << TimeRFC1123(Res.LastModified) << "\n";
if (Res.MD5Sum.empty() == false)
- {
- End += snprintf(End,sizeof(S)-50 - (End - S),"MD5-Hash: %s\n",Res.MD5Sum.c_str());
- End += snprintf(End,sizeof(S)-50 - (End - S),"MD5Sum-Hash: %s\n",Res.MD5Sum.c_str());
- }
+ std::cout << "MD5-Hash: " << Res.MD5Sum << "\n"
+ << "MD5Sum-Hash: " << Res.MD5Sum << "\n";
if (Res.SHA1Sum.empty() == false)
- End += snprintf(End,sizeof(S)-50 - (End - S),"SHA1-Hash: %s\n",Res.SHA1Sum.c_str());
+ std::cout << "SHA1-Hash: " << Res.SHA1Sum << "\n";
if (Res.SHA256Sum.empty() == false)
- End += snprintf(End,sizeof(S)-50 - (End - S),"SHA256-Hash: %s\n",Res.SHA256Sum.c_str());
+ std::cout << "SHA256-Hash: " << Res.SHA256Sum << "\n";
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();
- I != Res.GPGVOutput.end(); I++)
- End += snprintf(End,sizeof(S)-50 - (End - S), " %s\n", (*I).c_str());
+ std::cout << "UsedMirror: " << UsedMirror << "\n";
+ if (Res.GPGVOutput.empty() == false)
+ {
+ std::cout << "GPGVOutput:\n";
+ for (vector<string>::const_iterator I = Res.GPGVOutput.begin();
+ I != Res.GPGVOutput.end(); ++I)
+ std::cout << " " << *I << "\n";
+ }
if (Res.ResumePoint != 0)
- End += snprintf(End,sizeof(S)-50 - (End - S),"Resume-Point: %lu\n",
- Res.ResumePoint);
+ std::cout << "Resume-Point: " << Res.ResumePoint << "\n";
if (Res.IMSHit == true)
- strcat(End,"IMS-Hit: true\n");
- End = S + strlen(S);
-
+ std::cout << "IMS-Hit: true\n";
+
if (Alt != 0)
{
if (Alt->Filename.empty() == false)
- End += snprintf(End,sizeof(S)-50 - (End - S),"Alt-Filename: %s\n",Alt->Filename.c_str());
-
+ std::cout << "Alt-Filename: " << Alt->Filename << "\n";
+
if (Alt->Size != 0)
- End += snprintf(End,sizeof(S)-50 - (End - S),"Alt-Size: %lu\n",Alt->Size);
-
+ std::cout << "Alt-Size: " << Alt->Size << "\n";
+
if (Alt->LastModified != 0)
- End += snprintf(End,sizeof(S)-50 - (End - S),"Alt-Last-Modified: %s\n",
- TimeRFC1123(Alt->LastModified).c_str());
-
+ std::cout << "Alt-Last-Modified: " << TimeRFC1123(Alt->LastModified) << "\n";
+
if (Alt->MD5Sum.empty() == false)
- End += snprintf(End,sizeof(S)-50 - (End - S),"Alt-MD5-Hash: %s\n",
- Alt->MD5Sum.c_str());
+ std::cout << "Alt-MD5-Hash: " << Alt->MD5Sum << "\n";
if (Alt->SHA1Sum.empty() == false)
- End += snprintf(End,sizeof(S)-50 - (End - S),"Alt-SHA1-Hash: %s\n",
- Alt->SHA1Sum.c_str());
+ std::cout << "Alt-SHA1-Hash: " << Alt->SHA1Sum << "\n";
if (Alt->SHA256Sum.empty() == false)
- End += snprintf(End,sizeof(S)-50 - (End - S),"Alt-SHA256-Hash: %s\n",
- Alt->SHA256Sum.c_str());
-
+ std::cout << "Alt-SHA256-Hash: " << Alt->SHA256Sum << "\n";
+
if (Alt->IMSHit == true)
- strcat(End,"Alt-IMS-Hit: true\n");
+ std::cout << "Alt-IMS-Hit: true\n";
}
-
- strcat(End,"\n");
- if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
- exit(100);
+
+ std::cout << "\n" << std::flush;
// Dequeue
FetchItem *Tmp = Queue;
@@ -249,13 +220,10 @@ void pkgAcqMethod::URIDone(FetchResult &Res, FetchResult *Alt)
to be ackd */
bool pkgAcqMethod::MediaFail(string Required,string Drive)
{
- char S[1024];
- snprintf(S,sizeof(S),"403 Media Failure\nMedia: %s\nDrive: %s\n\n",
+ fprintf(stdout, "403 Media Failure\nMedia: %s\nDrive: %s\n",
Required.c_str(),Drive.c_str());
+ std::cout << "\n" << std::flush;
- if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
- exit(100);
-
vector<string> MyMessages;
/* Here we read messages until we find a 603, each non 603 message is
@@ -406,30 +374,34 @@ int pkgAcqMethod::Run(bool Single)
return 0;
}
/*}}}*/
-// AcqMethod::Log - Send a log message /*{{{*/
+// AcqMethod::PrintStatus - privately really send a log/status message /*{{{*/
// ---------------------------------------------------------------------
/* */
-void pkgAcqMethod::Log(const char *Format,...)
+void pkgAcqMethod::PrintStatus(char const * const header, const char* Format,
+ va_list &args) const
{
string CurrentURI = "<UNKNOWN>";
if (Queue != 0)
CurrentURI = Queue->Uri;
-
+ if (UsedMirror.empty() == true)
+ fprintf(stdout, "%s\nURI: %s\nMessage: ",
+ header, CurrentURI.c_str());
+ else
+ fprintf(stdout, "%s\nURI: %s\nUsedMirror: %s\nMessage: ",
+ header, CurrentURI.c_str(), UsedMirror.c_str());
+ vfprintf(stdout,Format,args);
+ std::cout << "\n\n" << std::flush;
+}
+ /*}}}*/
+// AcqMethod::Log - Send a log message /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+void pkgAcqMethod::Log(const char *Format,...)
+{
va_list args;
va_start(args,Format);
-
- // sprintf the description
- char S[1024];
- unsigned int Len = snprintf(S,sizeof(S)-4,"101 Log\n"
- "URI: %s\n"
- "UsedMirror: %s\n"
- "Message: ", UsedMirror.c_str(),
- CurrentURI.c_str());
- vsnprintf(S+Len,sizeof(S)-4-Len,Format,args);
- strcat(S,"\n\n");
-
- if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
- exit(100);
+ PrintStatus("101 Log", Format, args);
+ va_end(args);
}
/*}}}*/
// AcqMethod::Status - Send a status message /*{{{*/
@@ -437,26 +409,10 @@ void pkgAcqMethod::Log(const char *Format,...)
/* */
void pkgAcqMethod::Status(const char *Format,...)
{
- string CurrentURI = "<UNKNOWN>";
- if (Queue != 0)
- CurrentURI = Queue->Uri;
-
va_list args;
va_start(args,Format);
-
- // sprintf the description
- char S[1024];
- unsigned int Len = snprintf(S,sizeof(S)-4,"102 Status\n"
- "URI: %s\n"
- "UsedMirror: %s\n"
- "Message: ",UsedMirror.c_str(),
- CurrentURI.c_str());
-
- vsnprintf(S+Len,sizeof(S)-4-Len,Format,args);
- strcat(S,"\n\n");
-
- if (write(STDOUT_FILENO,S,strlen(S)) != (signed)strlen(S))
- exit(100);
+ PrintStatus("102 Status", Format, args);
+ va_end(args);
}
/*}}}*/
// AcqMethod::Redirect - Send a redirect message /*{{{*/
@@ -465,16 +421,13 @@ void pkgAcqMethod::Status(const char *Format,...)
to keep the pipeline synchronized. */
void pkgAcqMethod::Redirect(const string &NewURI)
{
- string CurrentURI = "<UNKNOWN>";
+ std::cout << "103 Redirect\nURI: ";
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);
+ std::cout << Queue->Uri << "\n";
+ else
+ std::cout << "<UNKNOWN>\n";
+ std::cout << "New-URI: " << NewURI << "\n"
+ << "\n" << std::flush;
// Change the URI for the request.
Queue->Uri = NewURI;
diff --git a/apt-pkg/acquire-method.h b/apt-pkg/acquire-method.h
index 03851e823..72efa8065 100644
--- a/apt-pkg/acquire-method.h
+++ b/apt-pkg/acquire-method.h
@@ -23,6 +23,7 @@
#include <apt-pkg/configuration.h>
#include <apt-pkg/strutl.h>
+#include <stdarg.h>
class Hashes;
class pkgAcqMethod
@@ -78,6 +79,8 @@ class pkgAcqMethod
bool MediaFail(string Required,string Drive);
virtual void Exit() {};
+ void PrintStatus(char const * const header, const char* Format, va_list &args) const;
+
public:
enum CnfFlags {SingleInstance = (1<<0),
Pipeline = (1<<1), SendConfig = (1<<2),
diff --git a/apt-pkg/acquire-worker.cc b/apt-pkg/acquire-worker.cc
index ddd8e3101..75e03232a 100644
--- a/apt-pkg/acquire-worker.cc
+++ b/apt-pkg/acquire-worker.cc
@@ -287,10 +287,10 @@ bool pkgAcquire::Worker::RunMessages()
Log->Pulse(Owner->GetOwner());
OwnerQ->ItemDone(Itm);
- if (TotalSize != 0 &&
- (unsigned)atoi(LookupTag(Message,"Size","0").c_str()) != TotalSize)
- _error->Warning("Bizarre Error - File size is not what the server reported %s %lu",
- LookupTag(Message,"Size","0").c_str(),TotalSize);
+ unsigned long const ServerSize = atol(LookupTag(Message,"Size","0").c_str());
+ if (TotalSize != 0 && ServerSize != TotalSize)
+ _error->Warning("Size of file %s is not what the server reported %s %lu",
+ Owner->DestFile.c_str(), LookupTag(Message,"Size","0").c_str(),TotalSize);
// see if there is a hash to verify
string RecivedHash;
@@ -309,8 +309,7 @@ bool pkgAcquire::Worker::RunMessages()
<< endl << endl;
}
}
- Owner->Done(Message,atoi(LookupTag(Message,"Size","0").c_str()),
- RecivedHash.c_str(), Config);
+ Owner->Done(Message, ServerSize, RecivedHash.c_str(), Config);
ItemDone();
// Log that we are done
diff --git a/apt-pkg/algorithms.cc b/apt-pkg/algorithms.cc
index bbe315ef7..6f1f82d50 100644
--- a/apt-pkg/algorithms.cc
+++ b/apt-pkg/algorithms.cc
@@ -104,9 +104,7 @@ bool pkgSimulate::Install(PkgIterator iPkg,string /*File*/)
DepIterator Start;
DepIterator End;
D.GlobOr(Start,End);
- if (Start->Type == pkgCache::Dep::Conflicts ||
- Start->Type == pkgCache::Dep::DpkgBreaks ||
- Start->Type == pkgCache::Dep::Obsoletes ||
+ if (Start.IsNegative() == true ||
End->Type == pkgCache::Dep::PreDepends)
{
if ((Sim[End] & pkgDepCache::DepGInstall) == 0)
@@ -332,6 +330,12 @@ bool pkgFixBroken(pkgDepCache &Cache)
*/
bool pkgDistUpgrade(pkgDepCache &Cache)
{
+ std::string const solver = _config->Find("APT::Solver::Name", "internal");
+ if (solver != "internal") {
+ OpTextProgress Prog(*_config);
+ return EDSP::ResolveExternal(solver.c_str(), Cache, false, true, false, &Prog);
+ }
+
pkgDepCache::ActionGroup group(Cache);
/* Upgrade all installed packages first without autoinst to help the resolver
@@ -384,6 +388,12 @@ bool pkgDistUpgrade(pkgDepCache &Cache)
to install packages not marked for install */
bool pkgAllUpgrade(pkgDepCache &Cache)
{
+ std::string const solver = _config->Find("APT::Solver::Name", "internal");
+ if (solver != "internal") {
+ OpTextProgress Prog(*_config);
+ return EDSP::ResolveExternal(solver.c_str(), Cache, true, false, false, &Prog);
+ }
+
pkgDepCache::ActionGroup group(Cache);
pkgProblemResolver Fix(&Cache);
@@ -650,12 +660,10 @@ bool pkgProblemResolver::DoUpgrade(pkgCache::PkgIterator Pkg)
// Compute a single dependency element (glob or)
pkgCache::DepIterator Start = D;
pkgCache::DepIterator End = D;
- unsigned char State = 0;
for (bool LastOR = true; D.end() == false && LastOR == true;)
{
- State |= Cache[D];
LastOR = (D->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or;
- D++;
+ ++D;
if (LastOR == true)
End = D;
}
@@ -700,9 +708,7 @@ bool pkgProblemResolver::DoUpgrade(pkgCache::PkgIterator Pkg)
{
/* We let the algorithm deal with conflicts on its next iteration,
it is much smarter than us */
- if (Start->Type == pkgCache::Dep::Conflicts ||
- Start->Type == pkgCache::Dep::DpkgBreaks ||
- Start->Type == pkgCache::Dep::Obsoletes)
+ if (Start.IsNegative() == true)
break;
if (Debug == true)
@@ -740,46 +746,9 @@ bool pkgProblemResolver::DoUpgrade(pkgCache::PkgIterator Pkg)
bool pkgProblemResolver::Resolve(bool BrokenFix)
{
std::string const solver = _config->Find("APT::Solver::Name", "internal");
-
- if (solver != "internal")
- {
-// std::string const file = _config->FindDir("Dir::Bin::Solvers") + solver;
- std::string const file = solver;
- if (RealFileExists(file.c_str()) == false)
- return _error->Error("Can't call external solver '%s' as it is not available: %s", solver.c_str(), file.c_str());
- int external[4] = {-1, -1, -1, -1};
- if (pipe(external) != 0 || pipe(external + 2) != 0)
- return _error->Errno("Resolve", "Can't create needed IPC pipes for EDSP");
- for (int i = 0; i < 4; ++i)
- SetCloseExec(external[i], true);
-
- pid_t Solver = ExecFork();
- if (Solver == 0)
- {
- dup2(external[0], STDIN_FILENO);
- dup2(external[3], STDOUT_FILENO);
- const char* calling[2] = { file.c_str(), 0 };
- execv(calling[0], (char**) calling);
- std::cerr << "Failed to execute solver '" << solver << "'!" << std::endl;
- _exit(100);
- }
- close(external[0]);
- close(external[3]);
-
- if (WaitFd(external[1], true, 5) == false)
- return _error->Errno("Resolve", "Waiting on availability of solver stdin timed out");
-
- FILE* output = fdopen(external[1], "w");
- if (output == NULL)
- return _error->Errno("Resolve", "fdopen on solver stdin failed");
- EDSP::WriteRequest(Cache, output);
- EDSP::WriteScenario(Cache, output);
- fclose(output);
-
- if (EDSP::ReadResponse(external[2], Cache) == false)
- return _error->Error("Reading solver response failed");
-
- return ExecWait(Solver, solver.c_str(), false);
+ if (solver != "internal") {
+ OpTextProgress Prog(*_config);
+ return EDSP::ResolveExternal(solver.c_str(), Cache, false, false, false, &Prog);
}
return ResolveInternal(BrokenFix);
}
@@ -981,9 +950,7 @@ bool pkgProblemResolver::ResolveInternal(bool const BrokenFix)
if a package has a dep on another package that cant be found */
SPtrArray<pkgCache::Version *> VList = Start.AllTargets();
if (*VList == 0 && (Flags[I->ID] & Protected) != Protected &&
- Start->Type != pkgCache::Dep::Conflicts &&
- Start->Type != pkgCache::Dep::DpkgBreaks &&
- Start->Type != pkgCache::Dep::Obsoletes &&
+ Start.IsNegative() == false &&
Cache[I].NowBroken() == false)
{
if (InOr == true)
@@ -1008,10 +975,7 @@ bool pkgProblemResolver::ResolveInternal(bool const BrokenFix)
at is not the currently selected version of the
package, which means it is not necessary to
remove/keep */
- if (Cache[Pkg].InstallVer != Ver &&
- (Start->Type == pkgCache::Dep::Conflicts ||
- Start->Type == pkgCache::Dep::DpkgBreaks ||
- Start->Type == pkgCache::Dep::Obsoletes))
+ if (Cache[Pkg].InstallVer != Ver && Start.IsNegative() == true)
{
if (Debug)
clog << " Conflicts//Breaks against version "
@@ -1029,9 +993,7 @@ bool pkgProblemResolver::ResolveInternal(bool const BrokenFix)
fiddle with the VList package */
if (Scores[I->ID] <= Scores[Pkg->ID] ||
((Cache[Start] & pkgDepCache::DepNow) == 0 &&
- End->Type != pkgCache::Dep::Conflicts &&
- End->Type != pkgCache::Dep::DpkgBreaks &&
- End->Type != pkgCache::Dep::Obsoletes))
+ End.IsNegative() == false))
{
// Try a little harder to fix protected packages..
if ((Flags[I->ID] & Protected) == Protected)
@@ -1138,10 +1100,8 @@ bool pkgProblemResolver::ResolveInternal(bool const BrokenFix)
}
// Hm, nothing can possibly satisify this dep. Nuke it.
- if (VList[0] == 0 &&
- Start->Type != pkgCache::Dep::Conflicts &&
- Start->Type != pkgCache::Dep::DpkgBreaks &&
- Start->Type != pkgCache::Dep::Obsoletes &&
+ if (VList[0] == 0 &&
+ Start.IsNegative() == false &&
(Flags[I->ID] & Protected) != Protected)
{
bool Installed = Cache[I].Install();
@@ -1187,9 +1147,7 @@ bool pkgProblemResolver::ResolveInternal(bool const BrokenFix)
Change = true;
if ((Cache[J->Dep] & pkgDepCache::DepGNow) == 0)
{
- if (J->Dep->Type == pkgCache::Dep::Conflicts ||
- J->Dep->Type == pkgCache::Dep::DpkgBreaks ||
- J->Dep->Type == pkgCache::Dep::Obsoletes)
+ if (J->Dep.IsNegative() == true)
{
if (Debug == true)
clog << " Fixing " << I.FullName(false) << " via remove of " << J->Pkg.FullName(false) << endl;
@@ -1253,6 +1211,21 @@ bool pkgProblemResolver::ResolveInternal(bool const BrokenFix)
system was non-broken previously. */
bool pkgProblemResolver::ResolveByKeep()
{
+ std::string const solver = _config->Find("APT::Solver::Name", "internal");
+ if (solver != "internal") {
+ OpTextProgress Prog(*_config);
+ return EDSP::ResolveExternal(solver.c_str(), Cache, true, false, false, &Prog);
+ }
+ return ResolveByKeepInternal();
+}
+ /*}}}*/
+// ProblemResolver::ResolveByKeepInternal - Resolve problems using keep /*{{{*/
+// ---------------------------------------------------------------------
+/* This is the work horse of the soft upgrade routine. It is very gental
+ in that it does not install or remove any packages. It is assumed that the
+ system was non-broken previously. */
+bool pkgProblemResolver::ResolveByKeepInternal()
+{
pkgDepCache::ActionGroup group(Cache);
unsigned long Size = Cache.Head().PackageCount;
diff --git a/apt-pkg/algorithms.h b/apt-pkg/algorithms.h
index 0778ec722..582cbc527 100644
--- a/apt-pkg/algorithms.h
+++ b/apt-pkg/algorithms.h
@@ -107,6 +107,7 @@ class pkgProblemResolver /*{{{*/
bool DoUpgrade(pkgCache::PkgIterator Pkg);
bool ResolveInternal(bool const BrokenFix = false);
+ bool ResolveByKeepInternal();
public:
diff --git a/apt-pkg/aptconfiguration.cc b/apt-pkg/aptconfiguration.cc
index 14ee09e0d..ca602d4bf 100644
--- a/apt-pkg/aptconfiguration.cc
+++ b/apt-pkg/aptconfiguration.cc
@@ -337,7 +337,7 @@ std::vector<std::string> const Configuration::getArchitectures(bool const &Cache
char* arch = strtok(buf, " ");
while (arch != NULL) {
for (; isspace(*arch) != 0; ++arch);
- if (arch != '\0') {
+ if (arch[0] != '\0') {
char const* archend = arch;
for (; isspace(*archend) == 0 && *archend != '\0'; ++archend);
archs.push_back(string(arch, (archend - arch)));
diff --git a/apt-pkg/cacheiterators.h b/apt-pkg/cacheiterators.h
index 8f9f811da..0c9813c6d 100644
--- a/apt-pkg/cacheiterators.h
+++ b/apt-pkg/cacheiterators.h
@@ -287,6 +287,7 @@ class pkgCache::DepIterator : public Iterator<Dependency, DepIterator> {
inline PkgIterator ParentPkg() const {return PkgIterator(*Owner,Owner->PkgP + Owner->VerP[S->ParentVer].ParentPkg);};
inline bool Reverse() const {return Type == DepRev;};
bool IsCritical() const;
+ bool IsNegative() const;
void GlobOr(DepIterator &Start,DepIterator &End);
Version **AllTargets() const;
bool SmartTargetPkg(PkgIterator &Result) const;
diff --git a/apt-pkg/cacheset.h b/apt-pkg/cacheset.h
index e690d660c..eb4f04d72 100644
--- a/apt-pkg/cacheset.h
+++ b/apt-pkg/cacheset.h
@@ -135,7 +135,7 @@ public: /*{{{*/
static APT::PackageSet FromTask(pkgCacheFile &Cache, std::string pattern, CacheSetHelper &helper);
static APT::PackageSet FromTask(pkgCacheFile &Cache, std::string const &pattern) {
CacheSetHelper helper;
- return APT::PackageSet::FromTask(Cache, pattern, helper);
+ return FromTask(Cache, pattern, helper);
}
/** \brief returns all packages in the cache whose name matchs a given pattern
@@ -149,7 +149,7 @@ public: /*{{{*/
static APT::PackageSet FromRegEx(pkgCacheFile &Cache, std::string pattern, CacheSetHelper &helper);
static APT::PackageSet FromRegEx(pkgCacheFile &Cache, std::string const &pattern) {
CacheSetHelper helper;
- return APT::PackageSet::FromRegEx(Cache, pattern, helper);
+ return FromRegEx(Cache, pattern, helper);
}
/** \brief returns all packages specified by a string
@@ -160,7 +160,7 @@ public: /*{{{*/
static APT::PackageSet FromString(pkgCacheFile &Cache, std::string const &string, CacheSetHelper &helper);
static APT::PackageSet FromString(pkgCacheFile &Cache, std::string const &string) {
CacheSetHelper helper;
- return APT::PackageSet::FromString(Cache, string, helper);
+ return FromString(Cache, string, helper);
}
/** \brief returns a package specified by a string
@@ -171,7 +171,7 @@ public: /*{{{*/
static pkgCache::PkgIterator FromName(pkgCacheFile &Cache, std::string const &string, CacheSetHelper &helper);
static pkgCache::PkgIterator FromName(pkgCacheFile &Cache, std::string const &string) {
CacheSetHelper helper;
- return APT::PackageSet::FromName(Cache, string, helper);
+ return FromName(Cache, string, helper);
}
/** \brief returns all packages specified on the commandline
@@ -184,7 +184,7 @@ public: /*{{{*/
static APT::PackageSet FromCommandLine(pkgCacheFile &Cache, const char **cmdline, CacheSetHelper &helper);
static APT::PackageSet FromCommandLine(pkgCacheFile &Cache, const char **cmdline) {
CacheSetHelper helper;
- return APT::PackageSet::FromCommandLine(Cache, cmdline, helper);
+ return FromCommandLine(Cache, cmdline, helper);
}
struct Modifier {
@@ -215,7 +215,7 @@ public: /*{{{*/
std::list<PackageSet::Modifier> const &mods,
unsigned short const &fallback) {
CacheSetHelper helper;
- return APT::PackageSet::GroupedFromCommandLine(Cache, cmdline,
+ return GroupedFromCommandLine(Cache, cmdline,
mods, fallback, helper);
}
@@ -309,10 +309,10 @@ public: /*{{{*/
static APT::VersionSet FromCommandLine(pkgCacheFile &Cache, const char **cmdline,
APT::VersionSet::Version const &fallback) {
CacheSetHelper helper;
- return APT::VersionSet::FromCommandLine(Cache, cmdline, fallback, helper);
+ return FromCommandLine(Cache, cmdline, fallback, helper);
}
static APT::VersionSet FromCommandLine(pkgCacheFile &Cache, const char **cmdline) {
- return APT::VersionSet::FromCommandLine(Cache, cmdline, CANDINST);
+ return FromCommandLine(Cache, cmdline, CANDINST);
}
static APT::VersionSet FromString(pkgCacheFile &Cache, std::string pkg,
@@ -321,10 +321,10 @@ public: /*{{{*/
static APT::VersionSet FromString(pkgCacheFile &Cache, std::string pkg,
APT::VersionSet::Version const &fallback) {
CacheSetHelper helper;
- return APT::VersionSet::FromString(Cache, pkg, fallback, helper);
+ return FromString(Cache, pkg, fallback, helper);
}
static APT::VersionSet FromString(pkgCacheFile &Cache, std::string pkg) {
- return APT::VersionSet::FromString(Cache, pkg, CANDINST);
+ return FromString(Cache, pkg, CANDINST);
}
/** \brief returns all versions specified for the package
@@ -338,10 +338,10 @@ public: /*{{{*/
static APT::VersionSet FromPackage(pkgCacheFile &Cache, pkgCache::PkgIterator const &P,
APT::VersionSet::Version const &fallback) {
CacheSetHelper helper;
- return APT::VersionSet::FromPackage(Cache, P, fallback, helper);
+ return FromPackage(Cache, P, fallback, helper);
}
static APT::VersionSet FromPackage(pkgCacheFile &Cache, pkgCache::PkgIterator const &P) {
- return APT::VersionSet::FromPackage(Cache, P, CANDINST);
+ return FromPackage(Cache, P, CANDINST);
}
struct Modifier {
@@ -364,7 +364,7 @@ public: /*{{{*/
std::list<VersionSet::Modifier> const &mods,
unsigned short const &fallback) {
CacheSetHelper helper;
- return APT::VersionSet::GroupedFromCommandLine(Cache, cmdline,
+ return GroupedFromCommandLine(Cache, cmdline,
mods, fallback, helper);
}
/*}}}*/
diff --git a/apt-pkg/cdrom.cc b/apt-pkg/cdrom.cc
index 36a1d7f12..2a914c665 100644
--- a/apt-pkg/cdrom.cc
+++ b/apt-pkg/cdrom.cc
@@ -155,7 +155,11 @@ bool pkgCdrom::FindPackages(string CD,
break;
if (chdir(CD.c_str()) != 0)
- return _error->Errno("chdir","Unable to change to %s",CD.c_str());
+ {
+ _error->Errno("chdir","Unable to change to %s", CD.c_str());
+ closedir(D);
+ return false;
+ }
};
closedir(D);
@@ -257,8 +261,10 @@ bool pkgCdrom::DropRepeats(vector<string> &List,const char *Name)
Inodes[I] = Buf.st_ino;
}
- if (_error->PendingError() == true)
+ if (_error->PendingError() == true) {
+ delete[] Inodes;
return false;
+ }
// Look for dups
for (unsigned int I = 0; I != List.size(); I++)
@@ -513,7 +519,8 @@ bool pkgCdrom::Ident(string &ident, pkgCdromStatus *log) /*{{{*/
if (CDROM[0] == '.')
CDROM= SafeGetCWD() + '/' + CDROM;
- if(log) {
+ if (log != NULL)
+ {
msg.str("");
ioprintf(msg, _("Using CD-ROM mount point %s\nMounting CD-ROM\n"),
CDROM.c_str());
@@ -523,7 +530,7 @@ bool pkgCdrom::Ident(string &ident, pkgCdromStatus *log) /*{{{*/
return _error->Error("Failed to mount the cdrom.");
// Hash the CD to get an ID
- if(log)
+ if (log != NULL)
log->Update(_("Identifying.. "));
@@ -533,10 +540,12 @@ bool pkgCdrom::Ident(string &ident, pkgCdromStatus *log) /*{{{*/
return false;
}
- msg.str("");
- ioprintf(msg, "[%s]\n",ident.c_str());
- log->Update(msg.str());
-
+ if (log != NULL)
+ {
+ msg.str("");
+ ioprintf(msg, "[%s]\n",ident.c_str());
+ log->Update(msg.str());
+ }
// Read the database
Configuration Database;
@@ -547,7 +556,8 @@ bool pkgCdrom::Ident(string &ident, pkgCdromStatus *log) /*{{{*/
return _error->Error("Unable to read the cdrom database %s",
DFile.c_str());
}
- if(log) {
+ if (log != NULL)
+ {
msg.str("");
ioprintf(msg, _("Stored label: %s\n"),
Database.Find("CD::"+ident).c_str());
@@ -555,8 +565,10 @@ bool pkgCdrom::Ident(string &ident, pkgCdromStatus *log) /*{{{*/
}
// Unmount and finish
- if (_config->FindB("APT::CDROM::NoMount",false) == false) {
- log->Update(_("Unmounting CD-ROM...\n"), STEP_LAST);
+ if (_config->FindB("APT::CDROM::NoMount",false) == false)
+ {
+ if (log != NULL)
+ log->Update(_("Unmounting CD-ROM...\n"), STEP_LAST);
UnmountCdrom(CDROM);
}
@@ -572,7 +584,8 @@ bool pkgCdrom::Add(pkgCdromStatus *log) /*{{{*/
if (CDROM[0] == '.')
CDROM= SafeGetCWD() + '/' + CDROM;
- if(log) {
+ if(log != NULL)
+ {
log->SetTotal(STEP_LAST);
msg.str("");
ioprintf(msg, _("Using CD-ROM mount point %s\n"), CDROM.c_str());
@@ -592,11 +605,12 @@ bool pkgCdrom::Add(pkgCdromStatus *log) /*{{{*/
// Unmount the CD and get the user to put in the one they want
if (_config->FindB("APT::CDROM::NoMount",false) == false)
{
- if(log)
+ if(log != NULL)
log->Update(_("Unmounting CD-ROM\n"), STEP_UNMOUNT);
UnmountCdrom(CDROM);
- if(log) {
+ if(log != NULL)
+ {
log->Update(_("Waiting for disc...\n"), STEP_WAIT);
if(!log->ChangeCdrom()) {
// user aborted
@@ -605,26 +619,29 @@ bool pkgCdrom::Add(pkgCdromStatus *log) /*{{{*/
}
// Mount the new CDROM
- log->Update(_("Mounting CD-ROM...\n"), STEP_MOUNT);
+ if(log != NULL)
+ log->Update(_("Mounting CD-ROM...\n"), STEP_MOUNT);
+
if (MountCdrom(CDROM) == false)
return _error->Error("Failed to mount the cdrom.");
}
// Hash the CD to get an ID
- if(log)
+ if(log != NULL)
log->Update(_("Identifying.. "), STEP_IDENT);
string ID;
if (IdentCdrom(CDROM,ID) == false)
{
- log->Update("\n");
+ if (log != NULL)
+ log->Update("\n");
return false;
}
- if(log)
+ if(log != NULL)
+ {
log->Update("["+ID+"]\n");
-
- if(log)
log->Update(_("Scanning disc for index files..\n"),STEP_SCAN);
-
+ }
+
// Get the CD structure
vector<string> List;
vector<string> SourceList;
@@ -634,7 +651,8 @@ bool pkgCdrom::Add(pkgCdromStatus *log) /*{{{*/
string InfoDir;
if (FindPackages(CDROM,List,SourceList, SigList,TransList,InfoDir,log) == false)
{
- log->Update("\n");
+ if (log != NULL)
+ log->Update("\n");
return false;
}
@@ -661,7 +679,7 @@ bool pkgCdrom::Add(pkgCdromStatus *log) /*{{{*/
DropRepeats(SourceList,"Sources");
DropRepeats(SigList,"Release.gpg");
DropRepeats(TransList,"");
- if(log) {
+ if(log != NULL) {
msg.str("");
ioprintf(msg, _("Found %zu package indexes, %zu source indexes, "
"%zu translation indexes and %zu signatures\n"),
@@ -698,7 +716,8 @@ bool pkgCdrom::Add(pkgCdromStatus *log) /*{{{*/
if (*J == '"' || *J == ']' || *J == '[')
*J = '_';
- if(log) {
+ if(log != NULL)
+ {
msg.str("");
ioprintf(msg, _("Found label '%s'\n"), Name.c_str());
log->Update(msg.str());
@@ -710,7 +729,7 @@ bool pkgCdrom::Add(pkgCdromStatus *log) /*{{{*/
if (_config->FindB("APT::CDROM::Rename",false) == true ||
Name.empty() == true)
{
- if(!log)
+ if(log == NULL)
{
if (_config->FindB("APT::CDROM::NoMount",false) == false)
UnmountCdrom(CDROM);
@@ -743,13 +762,13 @@ bool pkgCdrom::Add(pkgCdromStatus *log) /*{{{*/
*J = '_';
Database.Set("CD::" + ID,Name);
- if(log) {
+ if(log != NULL)
+ {
msg.str("");
ioprintf(msg, _("This disc is called: \n'%s'\n"), Name.c_str());
log->Update(msg.str());
+ log->Update(_("Copying package lists..."), STEP_COPY);
}
-
- log->Update(_("Copying package lists..."), STEP_COPY);
// take care of the signatures and copy them if they are ok
// (we do this before PackageCopy as it modifies "List" and "SourceList")
SigVerify SignVerify;
@@ -774,16 +793,15 @@ bool pkgCdrom::Add(pkgCdromStatus *log) /*{{{*/
if (WriteDatabase(Database) == false)
return false;
- if(log) {
+ if(log != NULL)
log->Update(_("Writing new source list\n"), STEP_WRITE);
- }
if (WriteSourceList(Name,List,false) == false ||
WriteSourceList(Name,SourceList,true) == false)
return false;
}
// Print the sourcelist entries
- if(log)
+ if(log != NULL)
log->Update(_("Source list entries for this disc are:\n"));
for (vector<string>::iterator I = List.begin(); I != List.end(); I++)
@@ -796,7 +814,8 @@ bool pkgCdrom::Add(pkgCdromStatus *log) /*{{{*/
return _error->Error("Internal error");
}
- if(log) {
+ if(log != NULL)
+ {
msg.str("");
msg << "deb cdrom:[" << Name << "]/" << string(*I,0,Space) <<
" " << string(*I,Space+1) << endl;
@@ -814,7 +833,7 @@ bool pkgCdrom::Add(pkgCdromStatus *log) /*{{{*/
return _error->Error("Internal error");
}
- if(log) {
+ if(log != NULL) {
msg.str("");
msg << "deb-src cdrom:[" << Name << "]/" << string(*I,0,Space) <<
" " << string(*I,Space+1) << endl;
@@ -824,7 +843,8 @@ bool pkgCdrom::Add(pkgCdromStatus *log) /*{{{*/
// Unmount and finish
if (_config->FindB("APT::CDROM::NoMount",false) == false) {
- log->Update(_("Unmounting CD-ROM...\n"), STEP_LAST);
+ if (log != NULL)
+ log->Update(_("Unmounting CD-ROM...\n"), STEP_LAST);
UnmountCdrom(CDROM);
}
diff --git a/apt-pkg/contrib/cdromutl.cc b/apt-pkg/contrib/cdromutl.cc
index 83c324f54..821e6d688 100644
--- a/apt-pkg/contrib/cdromutl.cc
+++ b/apt-pkg/contrib/cdromutl.cc
@@ -20,7 +20,6 @@
#include <apti18n.h>
#include <sys/wait.h>
-#include <sys/errno.h>
#include <sys/statvfs.h>
#include <dirent.h>
#include <fcntl.h>
@@ -206,8 +205,11 @@ bool IdentCdrom(string CD,string &Res,unsigned int Version)
Hash.Add(Dir->d_name);
};
- if (chdir(StartDir.c_str()) != 0)
- return _error->Errno("chdir",_("Unable to change to %s"),StartDir.c_str());
+ if (chdir(StartDir.c_str()) != 0) {
+ _error->Errno("chdir",_("Unable to change to %s"),StartDir.c_str());
+ closedir(D);
+ return false;
+ }
closedir(D);
// Some stats from the fsys
@@ -236,7 +238,7 @@ bool IdentCdrom(string CD,string &Res,unsigned int Version)
}
/*}}}*/
-// FindMountPointForDevice - Find mountpoint for the given device /*{{{*/
+// FindMountPointForDevice - Find mountpoint for the given device /*{{{*/
string FindMountPointForDevice(const char *devnode)
{
char buf[255];
@@ -254,7 +256,10 @@ string FindMountPointForDevice(const char *devnode)
while ( fgets(buf, sizeof(buf), f) != NULL) {
if (strncmp(buf, devnode, strlen(devnode)) == 0) {
if(TokSplitString(' ', buf, out, 10))
+ {
+ fclose(f);
return string(out[1]);
+ }
}
}
fclose(f);
@@ -263,5 +268,4 @@ string FindMountPointForDevice(const char *devnode)
return string();
}
-
-
+ /*}}}*/
diff --git a/apt-pkg/contrib/error.cc b/apt-pkg/contrib/error.cc
index fe50e606b..18810d2a4 100644
--- a/apt-pkg/contrib/error.cc
+++ b/apt-pkg/contrib/error.cc
@@ -107,6 +107,7 @@ bool GlobalError::InsertErrno(MsgType type, const char* Function,
msgSize = n + 1;
else
msgSize *= 2;
+ free(S);
return true;
}
@@ -160,6 +161,7 @@ bool GlobalError::Insert(MsgType type, const char* Description,
msgSize = n + 1;
else
msgSize *= 2;
+ free(S);
return true;
}
diff --git a/apt-pkg/contrib/mmap.cc b/apt-pkg/contrib/mmap.cc
index 9945b1606..19381ae47 100644
--- a/apt-pkg/contrib/mmap.cc
+++ b/apt-pkg/contrib/mmap.cc
@@ -237,11 +237,19 @@ DynamicMMap::DynamicMMap(unsigned long Flags,unsigned long const &WorkSpace,
if ((this->Flags & Fallback) != Fallback) {
// Set the permissions.
int Prot = PROT_READ;
+#ifdef MAP_ANONYMOUS
int Map = MAP_PRIVATE | MAP_ANONYMOUS;
+#else
+ int Map = MAP_PRIVATE | MAP_ANON;
+#endif
if ((this->Flags & ReadOnly) != ReadOnly)
Prot |= PROT_WRITE;
if ((this->Flags & Public) == Public)
+#ifdef MAP_ANONYMOUS
Map = MAP_SHARED | MAP_ANONYMOUS;
+#else
+ Map = MAP_SHARED | MAP_ANON;
+#endif
// use anonymous mmap() to get the memory
Base = (unsigned char*) mmap(0, WorkSpace, Prot, Map, -1, 0);
diff --git a/apt-pkg/contrib/netrc.cc b/apt-pkg/contrib/netrc.cc
index d8027fc24..34f472ee1 100644
--- a/apt-pkg/contrib/netrc.cc
+++ b/apt-pkg/contrib/netrc.cc
@@ -160,10 +160,10 @@ void maybe_add_auth (URI &Uri, string NetRCFile)
{
char login[64] = "";
char password[64] = "";
- char *netrcfile = strdupa (NetRCFile.c_str ());
+ char *netrcfile = strdup(NetRCFile.c_str());
// first check for a generic host based netrc entry
- char *host = strdupa (Uri.Host.c_str ());
+ char *host = strdup(Uri.Host.c_str());
if (host && parsenetrc (host, login, password, netrcfile) == 0)
{
if (_config->FindB("Debug::Acquire::netrc", false) == true)
@@ -173,13 +173,16 @@ void maybe_add_auth (URI &Uri, string NetRCFile)
<< std::endl;
Uri.User = string (login);
Uri.Password = string (password);
+ free(netrcfile);
+ free(host);
return;
}
+ free(host);
// if host did not work, try Host+Path next, this will trigger
// a lookup uri.startswith(host) in the netrc file parser (because
// of the "/"
- char *hostpath = strdupa (string(Uri.Host+Uri.Path).c_str ());
+ char *hostpath = strdup(string(Uri.Host+Uri.Path).c_str());
if (hostpath && parsenetrc (hostpath, login, password, netrcfile) == 0)
{
if (_config->FindB("Debug::Acquire::netrc", false) == true)
@@ -189,8 +192,9 @@ void maybe_add_auth (URI &Uri, string NetRCFile)
<< std::endl;
Uri.User = string (login);
Uri.Password = string (password);
- return;
}
+ free(netrcfile);
+ free(hostpath);
}
}
}
diff --git a/apt-pkg/contrib/progress.cc b/apt-pkg/contrib/progress.cc
index 45e81edcb..84ee4c124 100644
--- a/apt-pkg/contrib/progress.cc
+++ b/apt-pkg/contrib/progress.cc
@@ -65,27 +65,18 @@ void OpProgress::OverallProgress(unsigned long Current, unsigned long Total,
// OpProgress::SubProgress - Set the sub progress state /*{{{*/
// ---------------------------------------------------------------------
/* */
-void OpProgress::SubProgress(unsigned long SubTotal,const string &Op)
+void OpProgress::SubProgress(unsigned long SubTotal,const string &Op,
+ float const Percent)
{
this->SubTotal = SubTotal;
- SubOp = Op;
- if (Total == 0)
- Percent = 0;
+ if (Op.empty() == false)
+ SubOp = Op;
+ if (Total == 0 || Percent == 0)
+ this->Percent = 0;
+ else if (Percent != -1)
+ this->Percent = this->Current += (Size*Percent)/SubTotal;
else
- Percent = Current*100.0/Total;
- Update();
-}
- /*}}}*/
-// OpProgress::SubProgress - Set the sub progress state /*{{{*/
-// ---------------------------------------------------------------------
-/* */
-void OpProgress::SubProgress(unsigned long SubTotal)
-{
- this->SubTotal = SubTotal;
- if (Total == 0)
- Percent = 0;
- else
- Percent = Current*100.0/Total;
+ this->Percent = Current*100.0/Total;
Update();
}
/*}}}*/
diff --git a/apt-pkg/contrib/progress.h b/apt-pkg/contrib/progress.h
index 7dd004f7e..3a914d17f 100644
--- a/apt-pkg/contrib/progress.h
+++ b/apt-pkg/contrib/progress.h
@@ -55,8 +55,7 @@ class OpProgress
public:
void Progress(unsigned long Current);
- void SubProgress(unsigned long SubTotal);
- void SubProgress(unsigned long SubTotal,const string &Op);
+ void SubProgress(unsigned long SubTotal, const string &Op = "", float const Percent = -1);
void OverallProgress(unsigned long Current,unsigned long Total,
unsigned long Size,const string &Op);
virtual void Done() {};
diff --git a/apt-pkg/contrib/strutl.cc b/apt-pkg/contrib/strutl.cc
index 2e2bb5ebc..072dda3ac 100644
--- a/apt-pkg/contrib/strutl.cc
+++ b/apt-pkg/contrib/strutl.cc
@@ -692,14 +692,16 @@ int StringToBool(const string &Text,int Default)
year 2000 complient and timezone neutral */
string TimeRFC1123(time_t Date)
{
- struct tm Conv = *gmtime(&Date);
- char Buf[300];
+ struct tm Conv;
+ if (gmtime_r(&Date, &Conv) == NULL)
+ return "";
+ char Buf[300];
const char *Day[] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
const char *Month[] = {"Jan","Feb","Mar","Apr","May","Jun","Jul",
"Aug","Sep","Oct","Nov","Dec"};
- sprintf(Buf,"%s, %02i %s %i %02i:%02i:%02i GMT",Day[Conv.tm_wday],
+ snprintf(Buf, sizeof(Buf), "%s, %02i %s %i %02i:%02i:%02i GMT",Day[Conv.tm_wday],
Conv.tm_mday,Month[Conv.tm_mon],Conv.tm_year+1900,Conv.tm_hour,
Conv.tm_min,Conv.tm_sec);
return Buf;
diff --git a/apt-pkg/deb/deblistparser.cc b/apt-pkg/deb/deblistparser.cc
index 4be626741..4a9e94c85 100644
--- a/apt-pkg/deb/deblistparser.cc
+++ b/apt-pkg/deb/deblistparser.cc
@@ -284,18 +284,18 @@ unsigned short debListParser::VersionHash()
/* Strip out any spaces from the text, this undoes dpkgs reformatting
of certain fields. dpkg also has the rather interesting notion of
reformatting depends operators < -> <= */
- char *I = S;
+ char *J = S;
for (; Start != End; Start++)
{
if (isspace(*Start) == 0)
- *I++ = tolower_ascii(*Start);
+ *J++ = tolower_ascii(*Start);
if (*Start == '<' && Start[1] != '<' && Start[1] != '=')
- *I++ = '=';
+ *J++ = '=';
if (*Start == '>' && Start[1] != '>' && Start[1] != '=')
- *I++ = '=';
+ *J++ = '=';
}
- Result = AddCRC16(Result,S,I - S);
+ Result = AddCRC16(Result,S,J - S);
}
return Result;
@@ -487,7 +487,7 @@ const char *debListParser::ParseDepends(const char *Start,const char *Stop,
// Parse off the package name
const char *I = Start;
for (;I != Stop && isspace(*I) == 0 && *I != '(' && *I != ')' &&
- *I != ',' && *I != '|'; I++);
+ *I != ',' && *I != '|' && *I != '[' && *I != ']'; I++);
// Malformed, no '('
if (I != Stop && *I == ')')
diff --git a/apt-pkg/deb/debmetaindex.cc b/apt-pkg/deb/debmetaindex.cc
index a6edab6b9..a91cc34e9 100644
--- a/apt-pkg/deb/debmetaindex.cc
+++ b/apt-pkg/deb/debmetaindex.cc
@@ -195,11 +195,14 @@ vector <struct IndexTarget *>* debReleaseIndex::ComputeIndexTargets() const {
}
}
+ std::vector<std::string> const lang = APT::Configuration::getLanguages(true);
+ if (lang.empty() == true)
+ return IndexTargets;
+
// get the Translations:
// - if its a dists-style repository get the i18n/Index first
// - if its flat try to acquire files by guessing
if (Dist[Dist.size() - 1] == '/') {
- std::vector<std::string> const lang = APT::Configuration::getLanguages(true);
for (std::set<std::string>::const_iterator s = sections.begin();
s != sections.end(); ++s) {
for (std::vector<std::string>::const_iterator l = lang.begin();
diff --git a/apt-pkg/deb/dpkgpm.cc b/apt-pkg/deb/dpkgpm.cc
index 01808be24..b37980b7e 100644
--- a/apt-pkg/deb/dpkgpm.cc
+++ b/apt-pkg/deb/dpkgpm.cc
@@ -391,8 +391,9 @@ void pkgDPkgPM::DoTerminalPty(int master)
{
// this happens when the child is about to exit, we
// give it time to actually exit, otherwise we run
- // into a race
- usleep(500000);
+ // into a race so we sleep for half a second.
+ struct timespec sleepfor = { 0, 500000000 };
+ nanosleep(&sleepfor, NULL);
return;
}
if(len <= 0)
diff --git a/apt-pkg/depcache.cc b/apt-pkg/depcache.cc
index ed9e2084c..5cb68804d 100644
--- a/apt-pkg/depcache.cc
+++ b/apt-pkg/depcache.cc
@@ -70,7 +70,7 @@ void pkgDepCache::ActionGroup::release()
cache.MarkAndSweep();
}
- released = false;
+ released = true;
}
}
@@ -339,8 +339,7 @@ bool pkgDepCache::CheckDep(DepIterator Dep,int Type,PkgIterator &Res)
/* Check simple depends. A depends -should- never self match but
we allow it anyhow because dpkg does. Technically it is a packaging
bug. Conflicts may never self match */
- if (Dep.TargetPkg() != Dep.ParentPkg() ||
- (Dep->Type != Dep::Conflicts && Dep->Type != Dep::DpkgBreaks && Dep->Type != Dep::Obsoletes))
+ if (Dep.TargetPkg() != Dep.ParentPkg() || Dep.IsNegative() == false)
{
PkgIterator Pkg = Dep.TargetPkg();
// Check the base package
@@ -370,8 +369,7 @@ bool pkgDepCache::CheckDep(DepIterator Dep,int Type,PkgIterator &Res)
{
/* Provides may never be applied against the same package (or group)
if it is a conflicts. See the comment above. */
- if (P.OwnerPkg()->Group == Pkg->Group &&
- (Dep->Type == Dep::Conflicts || Dep->Type == Dep::DpkgBreaks))
+ if (P.OwnerPkg()->Group == Pkg->Group && Dep.IsNegative() == true)
continue;
// Check if the provides is a hit
@@ -549,8 +547,8 @@ void pkgDepCache::AddStates(const PkgIterator &Pkg,int Add)
// Not installed
if (Pkg->CurrentVer == 0)
{
- if (State.Mode == ModeDelete &&
- (State.iFlags | Purge) == Purge && Pkg.Purge() == false)
+ if (State.Mode == ModeDelete &&
+ (State.iFlags & Purge) == Purge && Pkg.Purge() == false)
iDelCount += Add;
if (State.Mode == ModeInstall)
@@ -594,9 +592,7 @@ void pkgDepCache::BuildGroupOrs(VerIterator const &V)
/* Invert for Conflicts. We have to do this twice to get the
right sense for a conflicts group */
- if (D->Type == Dep::Conflicts ||
- D->Type == Dep::DpkgBreaks ||
- D->Type == Dep::Obsoletes)
+ if (D.IsNegative() == true)
State = ~State;
// Add to the group if we are within an or..
@@ -607,9 +603,7 @@ void pkgDepCache::BuildGroupOrs(VerIterator const &V)
Group = 0;
// Invert for Conflicts
- if (D->Type == Dep::Conflicts ||
- D->Type == Dep::DpkgBreaks ||
- D->Type == Dep::Obsoletes)
+ if (D.IsNegative() == true)
State = ~State;
}
}
@@ -742,9 +736,7 @@ void pkgDepCache::Update(OpProgress *Prog)
Group = 0;
// Invert for Conflicts
- if (D->Type == Dep::Conflicts ||
- D->Type == Dep::DpkgBreaks ||
- D->Type == Dep::Obsoletes)
+ if (D.IsNegative() == true)
State = ~State;
}
}
@@ -774,9 +766,7 @@ void pkgDepCache::Update(DepIterator D)
State = DependencyState(D);
// Invert for Conflicts
- if (D->Type == Dep::Conflicts ||
- D->Type == Dep::DpkgBreaks ||
- D->Type == Dep::Obsoletes)
+ if (D.IsNegative() == true)
State = ~State;
RemoveStates(D.ParentPkg());
@@ -1088,7 +1078,22 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst,
*/
if (IsImportantDep(Start) == false)
continue;
-
+
+ /* If we are in an or group locate the first or that can
+ succeed. We have already cached this.. */
+ for (; Ors > 1 && (DepState[Start->ID] & DepCVer) != DepCVer; --Ors)
+ ++Start;
+ if (Ors == 1 && (DepState[Start->ID] &DepCVer) != DepCVer && Start.IsNegative() == false)
+ {
+ if(DebugAutoInstall == true)
+ std::clog << OutputInDepth(Depth) << Start << " can't be satisfied!" << std::endl;
+ if (Start.IsCritical() == false)
+ continue;
+ // if the dependency was critical, we can't install it, so remove it again
+ MarkDelete(Pkg,false,Depth + 1, false);
+ return;
+ }
+
/* Check if any ImportantDep() (but not Critical) were added
* since we installed the package. Also check for deps that
* were satisfied in the past: for instance, if a version
@@ -1096,57 +1101,49 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst,
* package should follow that Recommends rather than causing the
* dependency to be removed. (bug #470115)
*/
- bool isNewImportantDep = false;
- bool isPreviouslySatisfiedImportantDep = false;
- if(!ForceImportantDeps && !Start.IsCritical())
+ if (Pkg->CurrentVer != 0 && ForceImportantDeps == false && Start.IsCritical() == false)
{
- bool found=false;
- VerIterator instVer = Pkg.CurrentVer();
- if(!instVer.end())
+ bool isNewImportantDep = true;
+ bool isPreviouslySatisfiedImportantDep = false;
+ for (DepIterator D = Pkg.CurrentVer().DependsList(); D.end() != true; ++D)
+ {
+ //FIXME: Should we handle or-group better here?
+ // We do not check if the package we look for is part of the same or-group
+ // we might find while searching, but could that really be a problem?
+ if (D.IsCritical() == true || IsImportantDep(D) == false ||
+ Start.TargetPkg() != D.TargetPkg())
+ continue;
+
+ isNewImportantDep = false;
+
+ while ((D->CompareOp & Dep::Or) != 0)
+ ++D;
+
+ isPreviouslySatisfiedImportantDep = (((*this)[D] & DepGNow) != 0);
+ if (isPreviouslySatisfiedImportantDep == true)
+ break;
+ }
+
+ if(isNewImportantDep == true)
+ {
+ if (DebugAutoInstall == true)
+ std::clog << OutputInDepth(Depth) << "new important dependency: "
+ << Start.TargetPkg().FullName() << std::endl;
+ }
+ else if(isPreviouslySatisfiedImportantDep == true)
{
- for (DepIterator D = instVer.DependsList(); D.end() != true; D++)
- {
- //FIXME: deal better with or-groups(?)
- if(IsImportantDep(D) && !D.IsCritical() &&
- Start.TargetPkg() == D.TargetPkg())
- {
- if(!isPreviouslySatisfiedImportantDep)
- {
- DepIterator D2 = D;
- while((D2->CompareOp & Dep::Or) != 0)
- ++D2;
-
- isPreviouslySatisfiedImportantDep =
- (((*this)[D2] & DepGNow) != 0);
- }
-
- found=true;
- }
- }
- // this is a new dep if it was not found to be already
- // a important dep of the installed pacakge
- isNewImportantDep = !found;
+ if (DebugAutoInstall == true)
+ std::clog << OutputInDepth(Depth) << "previously satisfied important dependency on "
+ << Start.TargetPkg().FullName() << std::endl;
+ }
+ else
+ {
+ if (DebugAutoInstall == true)
+ std::clog << OutputInDepth(Depth) << "ignore old unsatisfied important dependency on "
+ << Start.TargetPkg().FullName() << std::endl;
+ continue;
}
}
- if(isNewImportantDep)
- if(DebugAutoInstall == true)
- std::clog << OutputInDepth(Depth) << "new important dependency: "
- << Start.TargetPkg().Name() << std::endl;
- if(isPreviouslySatisfiedImportantDep)
- if(DebugAutoInstall == true)
- std::clog << OutputInDepth(Depth) << "previously satisfied important dependency on "
- << Start.TargetPkg().Name() << std::endl;
-
- // skip important deps if the package is already installed
- if (Pkg->CurrentVer != 0 && Start.IsCritical() == false
- && !isNewImportantDep && !isPreviouslySatisfiedImportantDep
- && !ForceImportantDeps)
- continue;
-
- /* If we are in an or group locate the first or that can
- succeed. We have already cached this.. */
- for (; Ors > 1 && (DepState[Start->ID] & DepCVer) != DepCVer; Ors--)
- Start++;
/* This bit is for processing the possibilty of an install/upgrade
fixing the problem */
@@ -1212,8 +1209,7 @@ void pkgDepCache::MarkInstall(PkgIterator const &Pkg,bool AutoInst,
/* For conflicts we just de-install the package and mark as auto,
Conflicts may not have or groups. For dpkg's Breaks we try to
upgrade the package. */
- if (Start->Type == Dep::Conflicts || Start->Type == Dep::Obsoletes ||
- Start->Type == Dep::DpkgBreaks)
+ if (Start.IsNegative() == true)
{
for (Version **I = List; *I != 0; I++)
{
@@ -1609,6 +1605,9 @@ bool pkgDepCache::MarkFollowsSuggests()
// pkgDepCache::MarkRequired - the main mark algorithm /*{{{*/
bool pkgDepCache::MarkRequired(InRootSetFunc &userFunc)
{
+ if (_config->Find("APT::Solver::Name", "internal") != "internal")
+ return true;
+
bool follow_recommends;
bool follow_suggests;
bool debug_autoremove = _config->FindB("Debug::pkgAutoRemove",false);
diff --git a/apt-pkg/depcache.h b/apt-pkg/depcache.h
index b15cd527d..f95ad9a14 100644
--- a/apt-pkg/depcache.h
+++ b/apt-pkg/depcache.h
@@ -232,6 +232,7 @@ class pkgDepCache : protected pkgCache::Namespace
inline bool NewInstall() const {return Status == 2 && Mode == ModeInstall;};
inline bool Delete() const {return Mode == ModeDelete;};
inline bool Keep() const {return Mode == ModeKeep;};
+ inline bool Protect() const {return (iFlags & Protected) == Protected;};
inline bool Upgrade() const {return Status > 0 && Mode == ModeInstall;};
inline bool Upgradable() const {return Status >= 1;};
inline bool Downgrade() const {return Status < 0 && Mode == ModeInstall;};
diff --git a/apt-pkg/edsp.cc b/apt-pkg/edsp.cc
index e6dc16536..218ce9f24 100644
--- a/apt-pkg/edsp.cc
+++ b/apt-pkg/edsp.cc
@@ -18,97 +18,196 @@
#include <stdio.h>
/*}}}*/
+// we could use pkgCache::DepType and ::Priority, but these would be localized strings…
+const char * const EDSP::PrioMap[] = {0, "important", "required", "standard",
+ "optional", "extra"};
+const char * const EDSP::DepMap[] = {"", "Depends", "Pre-Depends", "Suggests",
+ "Recommends" , "Conflicts", "Replaces",
+ "Obsoletes", "Breaks", "Enhances"};
+
// EDSP::WriteScenario - to the given file descriptor /*{{{*/
-bool EDSP::WriteScenario(pkgDepCache &Cache, FILE* output)
+bool EDSP::WriteScenario(pkgDepCache &Cache, FILE* output, OpProgress *Progress)
{
- // we could use pkgCache::DepType and ::Priority, but these would be lokalized strings…
- const char * const PrioMap[] = {0, "important", "required", "standard",
- "optional", "extra"};
- const char * const DepMap[] = {"", "Depends", "PreDepends", "Suggests",
- "Recommends" , "Conflicts", "Replaces",
- "Obsoletes", "Breaks", "Enhances"};
-
+ if (Progress != NULL)
+ Progress->SubProgress(Cache.Head().VersionCount, _("Send scenario to solver"));
+ unsigned long p = 0;
for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; ++Pkg)
- {
+ for (pkgCache::VerIterator Ver = Pkg.VersionList(); Ver.end() == false; ++Ver, ++p)
+ {
+ WriteScenarioVersion(Cache, output, Pkg, Ver);
+ WriteScenarioDependency(Cache, output, Pkg, Ver);
+ fprintf(output, "\n");
+ if (Progress != NULL && p % 100 == 0)
+ Progress->Progress(p);
+ }
+ return true;
+}
+ /*}}}*/
+// EDSP::WriteLimitedScenario - to the given file descriptor /*{{{*/
+bool EDSP::WriteLimitedScenario(pkgDepCache &Cache, FILE* output,
+ APT::PackageSet const &pkgset,
+ OpProgress *Progress)
+{
+ if (Progress != NULL)
+ Progress->SubProgress(Cache.Head().VersionCount, _("Send scenario to solver"));
+ unsigned long p = 0;
+ for (APT::PackageSet::const_iterator Pkg = pkgset.begin(); Pkg != pkgset.end(); ++Pkg, ++p)
for (pkgCache::VerIterator Ver = Pkg.VersionList(); Ver.end() == false; ++Ver)
{
- fprintf(output, "Package: %s\n", Pkg.Name());
- fprintf(output, "Architecture: %s\n", Ver.Arch());
- fprintf(output, "Version: %s\n", Ver.VerStr());
- if (Pkg.CurrentVer() == Ver)
- fprintf(output, "Installed: yes\n");
- if (Pkg->SelectedState == pkgCache::State::Hold)
- fprintf(output, "Hold: yes\n");
- fprintf(output, "APT-ID: %u\n", Ver->ID);
- fprintf(output, "Priority: %s\n", PrioMap[Ver->Priority]);
- if ((Pkg->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential)
- fprintf(output, "Essential: yes\n");
- fprintf(output, "Section: %s\n", Ver.Section());
- if (Ver->MultiArch == pkgCache::Version::Allowed || Ver->MultiArch == pkgCache::Version::AllAllowed)
- fprintf(output, "Multi-Arch: allowed\n");
- else if (Ver->MultiArch == pkgCache::Version::Foreign || Ver->MultiArch == pkgCache::Version::AllForeign)
- fprintf(output, "Multi-Arch: foreign\n");
- else if (Ver->MultiArch == pkgCache::Version::Same)
- fprintf(output, "Multi-Arch: same\n");
- signed short Pin = std::numeric_limits<signed short>::min();
- for (pkgCache::VerFileIterator File = Ver.FileList(); File.end() == false; ++File) {
- signed short const p = Cache.GetPolicy().GetPriority(File.File());
- if (Pin < p)
- Pin = p;
- }
- fprintf(output, "APT-Pin: %d\n", Pin);
- if (Cache.GetCandidateVer(Pkg) == Ver)
- fprintf(output, "APT-Candidate: yes\n");
- if ((Cache[Pkg].Flags & pkgCache::Flag::Auto) == pkgCache::Flag::Auto)
- fprintf(output, "APT-Automatic: yes\n");
- std::string dependencies[pkgCache::Dep::Enhances + 1];
- bool orGroup = false;
- for (pkgCache::DepIterator Dep = Ver.DependsList(); Dep.end() == false; ++Dep)
- {
- // Ignore implicit dependencies for multiarch here
- if (strcmp(Pkg.Arch(), Dep.TargetPkg().Arch()) != 0)
- continue;
- if (orGroup == false)
- dependencies[Dep->Type].append(", ");
- dependencies[Dep->Type].append(Dep.TargetPkg().Name());
- if (Dep->Version != 0)
- dependencies[Dep->Type].append(" (").append(pkgCache::CompTypeDeb(Dep->CompareOp)).append(" ").append(Dep.TargetVer()).append(")");
- if ((Dep->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or)
- {
- dependencies[Dep->Type].append(" | ");
- orGroup = true;
- }
- else
- orGroup = false;
- }
- for (int i = 1; i < pkgCache::Dep::Enhances + 1; ++i)
- if (dependencies[i].empty() == false)
- fprintf(output, "%s: %s\n", DepMap[i], dependencies[i].c_str()+2);
- string provides;
- for (pkgCache::PrvIterator Prv = Ver.ProvidesList(); Prv.end() == false; ++Prv)
- {
- // Ignore implicit provides for multiarch here
- if (strcmp(Pkg.Arch(), Prv.ParentPkg().Arch()) != 0 || strcmp(Pkg.Name(),Prv.Name()) == 0)
- continue;
- provides.append(", ").append(Prv.Name());
- }
- if (provides.empty() == false)
- fprintf(output, "Provides: %s\n", provides.c_str()+2);
-
-
+ WriteScenarioVersion(Cache, output, Pkg, Ver);
+ WriteScenarioLimitedDependency(Cache, output, Pkg, Ver, pkgset);
fprintf(output, "\n");
+ if (Progress != NULL && p % 100 == 0)
+ Progress->Progress(p);
}
- }
+ if (Progress != NULL)
+ Progress->Done();
return true;
}
/*}}}*/
+// EDSP::WriteScenarioVersion /*{{{*/
+void EDSP::WriteScenarioVersion(pkgDepCache &Cache, FILE* output, pkgCache::PkgIterator const &Pkg,
+ pkgCache::VerIterator const &Ver)
+{
+ fprintf(output, "Package: %s\n", Pkg.Name());
+ fprintf(output, "Architecture: %s\n", Ver.Arch());
+ fprintf(output, "Version: %s\n", Ver.VerStr());
+ if (Pkg.CurrentVer() == Ver)
+ fprintf(output, "Installed: yes\n");
+ if (Pkg->SelectedState == pkgCache::State::Hold ||
+ (Cache[Pkg].Keep() == true && Cache[Pkg].Protect() == true))
+ fprintf(output, "Hold: yes\n");
+ fprintf(output, "APT-ID: %d\n", Ver->ID);
+ fprintf(output, "Priority: %s\n", PrioMap[Ver->Priority]);
+ if ((Pkg->Flags & pkgCache::Flag::Essential) == pkgCache::Flag::Essential)
+ fprintf(output, "Essential: yes\n");
+ fprintf(output, "Section: %s\n", Ver.Section());
+ if (Ver->MultiArch == pkgCache::Version::Allowed || Ver->MultiArch == pkgCache::Version::AllAllowed)
+ fprintf(output, "Multi-Arch: allowed\n");
+ else if (Ver->MultiArch == pkgCache::Version::Foreign || Ver->MultiArch == pkgCache::Version::AllForeign)
+ fprintf(output, "Multi-Arch: foreign\n");
+ else if (Ver->MultiArch == pkgCache::Version::Same)
+ fprintf(output, "Multi-Arch: same\n");
+ signed short Pin = std::numeric_limits<signed short>::min();
+ for (pkgCache::VerFileIterator File = Ver.FileList(); File.end() == false; ++File) {
+ signed short const p = Cache.GetPolicy().GetPriority(File.File());
+ if (Pin < p)
+ Pin = p;
+ }
+ fprintf(output, "APT-Pin: %d\n", Pin);
+ if (Cache.GetCandidateVer(Pkg) == Ver)
+ fprintf(output, "APT-Candidate: yes\n");
+ if ((Cache[Pkg].Flags & pkgCache::Flag::Auto) == pkgCache::Flag::Auto)
+ fprintf(output, "APT-Automatic: yes\n");
+}
+ /*}}}*/
+// EDSP::WriteScenarioDependency /*{{{*/
+void EDSP::WriteScenarioDependency(pkgDepCache &Cache, FILE* output, pkgCache::PkgIterator const &Pkg,
+ pkgCache::VerIterator const &Ver)
+{
+ std::string dependencies[pkgCache::Dep::Enhances + 1];
+ bool orGroup = false;
+ for (pkgCache::DepIterator Dep = Ver.DependsList(); Dep.end() == false; ++Dep)
+ {
+ // Ignore implicit dependencies for multiarch here
+ if (strcmp(Pkg.Arch(), Dep.TargetPkg().Arch()) != 0)
+ continue;
+ if (orGroup == false)
+ dependencies[Dep->Type].append(", ");
+ dependencies[Dep->Type].append(Dep.TargetPkg().Name());
+ if (Dep->Version != 0)
+ dependencies[Dep->Type].append(" (").append(pkgCache::CompTypeDeb(Dep->CompareOp)).append(" ").append(Dep.TargetVer()).append(")");
+ if ((Dep->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or)
+ {
+ dependencies[Dep->Type].append(" | ");
+ orGroup = true;
+ }
+ else
+ orGroup = false;
+ }
+ for (int i = 1; i < pkgCache::Dep::Enhances + 1; ++i)
+ if (dependencies[i].empty() == false)
+ fprintf(output, "%s: %s\n", DepMap[i], dependencies[i].c_str()+2);
+ string provides;
+ for (pkgCache::PrvIterator Prv = Ver.ProvidesList(); Prv.end() == false; ++Prv)
+ {
+ // Ignore implicit provides for multiarch here
+ if (strcmp(Pkg.Arch(), Prv.ParentPkg().Arch()) != 0 || strcmp(Pkg.Name(),Prv.Name()) == 0)
+ continue;
+ provides.append(", ").append(Prv.Name());
+ }
+ if (provides.empty() == false)
+ fprintf(output, "Provides: %s\n", provides.c_str()+2);
+}
+ /*}}}*/
+// EDSP::WriteScenarioLimitedDependency /*{{{*/
+void EDSP::WriteScenarioLimitedDependency(pkgDepCache &Cache, FILE* output,
+ pkgCache::PkgIterator const &Pkg,
+ pkgCache::VerIterator const &Ver,
+ APT::PackageSet const &pkgset)
+{
+ std::string dependencies[pkgCache::Dep::Enhances + 1];
+ bool orGroup = false;
+ for (pkgCache::DepIterator Dep = Ver.DependsList(); Dep.end() == false; ++Dep)
+ {
+ // Ignore implicit dependencies for multiarch here
+ if (strcmp(Pkg.Arch(), Dep.TargetPkg().Arch()) != 0)
+ continue;
+ if (orGroup == false)
+ {
+ if (pkgset.find(Dep.TargetPkg()) == pkgset.end())
+ continue;
+ dependencies[Dep->Type].append(", ");
+ }
+ else if (pkgset.find(Dep.TargetPkg()) == pkgset.end())
+ {
+ if ((Dep->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or)
+ continue;
+ dependencies[Dep->Type].erase(dependencies[Dep->Type].end()-3, dependencies[Dep->Type].end());
+ orGroup = false;
+ continue;
+ }
+ dependencies[Dep->Type].append(Dep.TargetPkg().Name());
+ if (Dep->Version != 0)
+ dependencies[Dep->Type].append(" (").append(pkgCache::CompTypeDeb(Dep->CompareOp)).append(" ").append(Dep.TargetVer()).append(")");
+ if ((Dep->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or)
+ {
+ dependencies[Dep->Type].append(" | ");
+ orGroup = true;
+ }
+ else
+ orGroup = false;
+ }
+ for (int i = 1; i < pkgCache::Dep::Enhances + 1; ++i)
+ if (dependencies[i].empty() == false)
+ fprintf(output, "%s: %s\n", DepMap[i], dependencies[i].c_str()+2);
+ string provides;
+ for (pkgCache::PrvIterator Prv = Ver.ProvidesList(); Prv.end() == false; ++Prv)
+ {
+ // Ignore implicit provides for multiarch here
+ if (strcmp(Pkg.Arch(), Prv.ParentPkg().Arch()) != 0 || strcmp(Pkg.Name(),Prv.Name()) == 0)
+ continue;
+ if (pkgset.find(Prv.ParentPkg()) == pkgset.end())
+ continue;
+ provides.append(", ").append(Prv.Name());
+ }
+ if (provides.empty() == false)
+ fprintf(output, "Provides: %s\n", provides.c_str()+2);
+}
+ /*}}}*/
// EDSP::WriteRequest - to the given file descriptor /*{{{*/
bool EDSP::WriteRequest(pkgDepCache &Cache, FILE* output, bool const Upgrade,
- bool const DistUpgrade, bool const AutoRemove)
+ bool const DistUpgrade, bool const AutoRemove,
+ OpProgress *Progress)
{
+ if (Progress != NULL)
+ Progress->SubProgress(Cache.Head().PackageCount, _("Send request to solver"));
+ unsigned long p = 0;
string del, inst;
- for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; ++Pkg)
+ for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; ++Pkg, ++p)
{
+ if (Progress != NULL && p % 100 == 0)
+ Progress->Progress(p);
string* req;
if (Cache[Pkg].Delete() == true)
req = &del;
@@ -118,7 +217,7 @@ bool EDSP::WriteRequest(pkgDepCache &Cache, FILE* output, bool const Upgrade,
continue;
req->append(" ").append(Pkg.FullName());
}
- fprintf(output, "Request: EDSP 0.2\n");
+ fprintf(output, "Request: EDSP 0.4\n");
if (del.empty() == false)
fprintf(output, "Remove: %s\n", del.c_str()+1);
if (inst.empty() == false)
@@ -141,26 +240,76 @@ bool EDSP::WriteRequest(pkgDepCache &Cache, FILE* output, bool const Upgrade,
}
/*}}}*/
// EDSP::ReadResponse - from the given file descriptor /*{{{*/
-bool EDSP::ReadResponse(int const input, pkgDepCache &Cache) {
+bool EDSP::ReadResponse(int const input, pkgDepCache &Cache, OpProgress *Progress) {
+ /* We build an map id to mmap offset here
+ In theory we could use the offset as ID, but then VersionCount
+ couldn't be used to create other versionmappings anymore and it
+ would be too easy for a (buggy) solver to segfault APT… */
+ unsigned long long const VersionCount = Cache.Head().VersionCount;
+ unsigned long VerIdx[VersionCount];
+ for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; ++P) {
+ for (pkgCache::VerIterator V = P.VersionList(); V.end() == false; ++V)
+ VerIdx[V->ID] = V.Index();
+ Cache[P].Marked = true;
+ Cache[P].Garbage = false;
+ }
+
FileFd in;
in.OpenDescriptor(input, FileFd::ReadOnly);
- pkgTagFile response(&in);
+ pkgTagFile response(&in, 100);
pkgTagSection section;
+
while (response.Step(section) == true) {
std::string type;
if (section.Exists("Install") == true)
type = "Install";
else if (section.Exists("Remove") == true)
type = "Remove";
- //FIXME: handle progress
+ else if (section.Exists("Progress") == true) {
+ if (Progress != NULL) {
+ string msg = section.FindS("Message");
+ if (msg.empty() == true)
+ msg = _("Prepare for receiving solution");
+ Progress->SubProgress(100, msg, section.FindI("Percentage", 0));
+ }
+ continue;
+ } else if (section.Exists("Error") == true) {
+ std::string msg = SubstVar(SubstVar(section.FindS("Message"), "\n .\n", "\n\n"), "\n ", "\n");
+ if (msg.empty() == true) {
+ msg = _("External solver failed without a proper error message");
+ _error->Error(msg.c_str());
+ } else
+ _error->Error("External solver failed with: %s", msg.substr(0,msg.find('\n')).c_str());
+ if (Progress != NULL)
+ Progress->Done();
+ std::cerr << "The solver encountered an error of type: " << section.FindS("Error") << std::endl;
+ std::cerr << "The following information might help you to understand what is wrong:" << std::endl;
+ std::cerr << msg << std::endl << std::endl;
+ return false;
+ } else if (section.Exists("Autoremove") == true)
+ type = "Autoremove";
else
continue;
- int const id = section.FindI(type.c_str(), -1);
- if (id == -1)
- return _error->Error("Unable to parse %s request!", type.c_str());
+ size_t const id = section.FindULL(type.c_str(), VersionCount);
+ if (id == VersionCount) {
+ _error->Warning("Unable to parse %s request with id value '%s'!", type.c_str(), section.FindS(type.c_str()).c_str());
+ continue;
+ } else if (id > Cache.Head().VersionCount) {
+ _error->Warning("ID value '%s' in %s request stanza is to high to refer to a known version!", section.FindS(type.c_str()).c_str(), type.c_str());
+ continue;
+ }
- //FIXME: find version by id and mark it correctly
+ pkgCache::VerIterator Ver(Cache.GetCache(), Cache.GetCache().VerP + VerIdx[id]);
+ Cache.SetCandidateVersion(Ver);
+ if (type == "Install")
+ Cache.MarkInstall(Ver.ParentPkg(), false, 0, false);
+ else if (type == "Remove")
+ Cache.MarkDelete(Ver.ParentPkg(), false);
+ else if (type == "Autoremove") {
+ Cache[Ver.ParentPkg()].Marked = false;
+ Cache[Ver.ParentPkg()].Garbage = true;
+ }
}
return true;
}
@@ -277,12 +426,22 @@ bool EDSP::ApplyRequest(std::list<std::string> const &install,
pkgDepCache &Cache)
{
for (std::list<std::string>::const_iterator i = install.begin();
- i != install.end(); ++i)
- Cache.MarkInstall(Cache.FindPkg(*i), false);
+ i != install.end(); ++i) {
+ pkgCache::PkgIterator P = Cache.FindPkg(*i);
+ if (P.end() == true)
+ _error->Warning("Package %s is not known, so can't be installed", i->c_str());
+ else
+ Cache.MarkInstall(P, false);
+ }
for (std::list<std::string>::const_iterator i = remove.begin();
- i != remove.end(); ++i)
- Cache.MarkDelete(Cache.FindPkg(*i));
+ i != remove.end(); ++i) {
+ pkgCache::PkgIterator P = Cache.FindPkg(*i);
+ if (P.end() == true)
+ _error->Warning("Package %s is not known, so can't be installed", i->c_str());
+ else
+ Cache.MarkDelete(P);
+ }
return true;
}
/*}}}*/
@@ -293,17 +452,113 @@ bool EDSP::WriteSolution(pkgDepCache &Cache, FILE* output)
for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; ++Pkg)
{
if (Cache[Pkg].Delete() == true)
- fprintf(output, "Remove: %d\n", Cache.GetCandidateVer(Pkg)->ID);
+ {
+ fprintf(output, "Remove: %d\n", Pkg.CurrentVer()->ID);
+ if (Debug == true)
+ fprintf(output, "Package: %s\nVersion: %s\n", Pkg.FullName().c_str(), Pkg.CurrentVer().VerStr());
+ }
else if (Cache[Pkg].NewInstall() == true || Cache[Pkg].Upgrade() == true)
+ {
fprintf(output, "Install: %d\n", Cache.GetCandidateVer(Pkg)->ID);
+ if (Debug == true)
+ fprintf(output, "Package: %s\nVersion: %s\n", Pkg.FullName().c_str(), Cache.GetCandidateVer(Pkg).VerStr());
+ }
+ else if (Cache[Pkg].Garbage == true)
+ {
+ fprintf(output, "Autoremove: %d\n", Pkg.CurrentVer()->ID);
+ if (Debug == true)
+ fprintf(output, "Package: %s\nVersion: %s\n", Pkg.FullName().c_str(), Pkg.CurrentVer().VerStr());
+ fprintf(stderr, "Autoremove: %s\nVersion: %s\n", Pkg.FullName().c_str(), Pkg.CurrentVer().VerStr());
+ }
else
continue;
- if (Debug == true)
- fprintf(output, "Package: %s\nVersion: %s\n", Pkg.FullName().c_str(), Cache.GetCandidateVer(Pkg).VerStr());
fprintf(output, "\n");
}
return true;
}
/*}}}*/
-bool EDSP::WriteError(std::string const &message, FILE* output) { return false; }
+// EDSP::WriteProgess - pulse to the given file descriptor /*{{{*/
+bool EDSP::WriteProgress(unsigned short const percent, const char* const message, FILE* output) {
+ fprintf(output, "Progress: %s\n", TimeRFC1123(time(NULL)).c_str());
+ fprintf(output, "Percentage: %d\n", percent);
+ fprintf(output, "Message: %s\n\n", message);
+ fflush(output);
+ return true;
+}
+ /*}}}*/
+// EDSP::WriteError - format an error message to be send to file descriptor /*{{{*/
+bool EDSP::WriteError(char const * const uuid, std::string const &message, FILE* output) {
+ fprintf(output, "Error: %s\n", uuid);
+ fprintf(output, "Message: %s\n\n", SubstVar(SubstVar(message, "\n\n", "\n.\n"), "\n", "\n ").c_str());
+ return true;
+}
+ /*}}}*/
+// EDSP::ExecuteSolver - fork requested solver and setup ipc pipes {{{*/
+bool EDSP::ExecuteSolver(const char* const solver, int *solver_in, int *solver_out) {
+ std::vector<std::string> const solverDirs = _config->FindVector("Dir::Bin::Solvers");
+ std::string file;
+ for (std::vector<std::string>::const_iterator dir = solverDirs.begin();
+ dir != solverDirs.end(); ++dir) {
+ file = flCombine(*dir, solver);
+ if (RealFileExists(file.c_str()) == true)
+ break;
+ file.clear();
+ }
+
+ if (file.empty() == true)
+ return _error->Error("Can't call external solver '%s' as it is not in a configured directory!", solver);
+ int external[4] = {-1, -1, -1, -1};
+ if (pipe(external) != 0 || pipe(external + 2) != 0)
+ return _error->Errno("Resolve", "Can't create needed IPC pipes for EDSP");
+ for (int i = 0; i < 4; ++i)
+ SetCloseExec(external[i], true);
+
+ pid_t Solver = ExecFork();
+ if (Solver == 0) {
+ dup2(external[0], STDIN_FILENO);
+ dup2(external[3], STDOUT_FILENO);
+ const char* calling[2] = { file.c_str(), 0 };
+ execv(calling[0], (char**) calling);
+ std::cerr << "Failed to execute solver '" << solver << "'!" << std::endl;
+ _exit(100);
+ }
+ close(external[0]);
+ close(external[3]);
+
+ if (WaitFd(external[1], true, 5) == false)
+ return _error->Errno("Resolve", "Timed out while Waiting on availability of solver stdin");
+
+ *solver_in = external[1];
+ *solver_out = external[2];
+ return true;
+}
+ /*}}}*/
+// EDSP::ResolveExternal - resolve problems by asking external for help {{{*/
+bool EDSP::ResolveExternal(const char* const solver, pkgDepCache &Cache,
+ bool const upgrade, bool const distUpgrade,
+ bool const autoRemove, OpProgress *Progress) {
+ int solver_in, solver_out;
+ if (EDSP::ExecuteSolver(solver, &solver_in, &solver_out) == false)
+ return false;
+
+ FILE* output = fdopen(solver_in, "w");
+ if (output == NULL)
+ return _error->Errno("Resolve", "fdopen on solver stdin failed");
+
+ if (Progress != NULL)
+ Progress->OverallProgress(0, 100, 5, _("Execute external solver"));
+ EDSP::WriteRequest(Cache, output, upgrade, distUpgrade, autoRemove, Progress);
+ if (Progress != NULL)
+ Progress->OverallProgress(5, 100, 20, _("Execute external solver"));
+ EDSP::WriteScenario(Cache, output, Progress);
+ fclose(output);
+
+ if (Progress != NULL)
+ Progress->OverallProgress(25, 100, 75, _("Execute external solver"));
+ if (EDSP::ReadResponse(solver_out, Cache, Progress) == false)
+ return false;
+
+ return true;
+}
+ /*}}}*/
diff --git a/apt-pkg/edsp.h b/apt-pkg/edsp.h
index 31f8891f3..743c3f5d1 100644
--- a/apt-pkg/edsp.h
+++ b/apt-pkg/edsp.h
@@ -1,39 +1,222 @@
// -*- mode: cpp; mode: fold -*-
-// Description /*{{{*/
-/* ######################################################################
+/** Description \file edsp.h {{{
+ ######################################################################
Set of methods to help writing and reading everything needed for EDSP
+ with the noteable exception of reading a scenario for conversion into
+ a Cache as this is handled by edsp interface for listparser and friends
##################################################################### */
/*}}}*/
#ifndef PKGLIB_EDSP_H
#define PKGLIB_EDSP_H
#include <apt-pkg/depcache.h>
+#include <apt-pkg/cacheset.h>
+#include <apt-pkg/progress.h>
#include <string>
class EDSP /*{{{*/
{
+ // we could use pkgCache::DepType and ::Priority, but these would be localized strings…
+ static const char * const PrioMap[];
+ static const char * const DepMap[];
+
bool static ReadLine(int const input, std::string &line);
bool static StringToBool(char const *answer, bool const defValue);
+ void static WriteScenarioVersion(pkgDepCache &Cache, FILE* output,
+ pkgCache::PkgIterator const &Pkg,
+ pkgCache::VerIterator const &Ver);
+ void static WriteScenarioDependency(pkgDepCache &Cache, FILE* output,
+ pkgCache::PkgIterator const &Pkg,
+ pkgCache::VerIterator const &Ver);
+ void static WriteScenarioLimitedDependency(pkgDepCache &Cache, FILE* output,
+ pkgCache::PkgIterator const &Pkg,
+ pkgCache::VerIterator const &Ver,
+ APT::PackageSet const &pkgset);
public:
+ /** \brief creates the EDSP request stanza
+ *
+ * In the EDSP protocol the first thing send to the resolver is a stanza
+ * encoding the request. This method will write this stanza by looking at
+ * the given Cache and requests the installation of all packages which were
+ * marked for installation in it (equally for remove).
+ *
+ * \param Cache in which the request is encoded
+ * \param output is written to this "file"
+ * \param upgrade is true if it is an request like apt-get upgrade
+ * \param distUpgrade is true if it is a request like apt-get dist-upgrade
+ * \param autoRemove is true if removal of unneeded packages should be performed
+ * \param Progress is an instance to report progress to
+ *
+ * \return true if request was composed successfully, otherwise false
+ */
bool static WriteRequest(pkgDepCache &Cache, FILE* output,
bool const upgrade = false,
bool const distUpgrade = false,
- bool const autoRemove = false);
- bool static WriteScenario(pkgDepCache &Cache, FILE* output);
- bool static ReadResponse(int const input, pkgDepCache &Cache);
+ bool const autoRemove = false,
+ OpProgress *Progress = NULL);
+
+ /** \brief creates the scenario representing the package universe
+ *
+ * After the request all known information about a package are send
+ * to the solver. The output looks similar to a Packages or status file
+ *
+ * All packages and version included in this Cache are send, even if
+ * it doesn't make sense from an APT resolver point of view like versions
+ * with a negative pin to enable the solver to propose even that as a
+ * solution or at least to be able to give a hint what can be done to
+ * statisfy a request.
+ *
+ * \param Cache is the known package universe
+ * \param output is written to this "file"
+ * \param Progress is an instance to report progress to
+ *
+ * \return true if universe was composed successfully, otherwise false
+ */
+ bool static WriteScenario(pkgDepCache &Cache, FILE* output, OpProgress *Progress = NULL);
+
+ /** \brief creates a limited scenario representing the package universe
+ *
+ * This method works similar to #WriteScenario as it works in the same
+ * way but doesn't send the complete universe to the solver but only
+ * packages included in the pkgset which will have only dependencies
+ * on packages which are in the given set. All other dependencies will
+ * be removed, so that this method can be used to create testcases
+ *
+ * \param Cache is the known package universe
+ * \param output is written to this "file"
+ * \param pkgset is a set of packages the universe should be limited to
+ * \param Progress is an instance to report progress to
+ *
+ * \return true if universe was composed successfully, otherwise false
+ */
+ bool static WriteLimitedScenario(pkgDepCache &Cache, FILE* output,
+ APT::PackageSet const &pkgset,
+ OpProgress *Progress = NULL);
- // ReadScenario is provided by the listparser infrastructure
+ /** \brief waits and acts on the information returned from the solver
+ *
+ * This method takes care of interpreting whatever the solver sends
+ * through the standard output like a solution, progress or an error.
+ * The main thread should handle his control over to this method to
+ * wait for the solver to finish the given task
+ *
+ * \param input file descriptor with the response from the solver
+ * \param Cache the solution should be applied on if any
+ * \param Progress is an instance to report progress to
+ *
+ * \return true if a solution is found and applied correctly, otherwise false
+ */
+ bool static ReadResponse(int const input, pkgDepCache &Cache, OpProgress *Progress = NULL);
+
+ /** \brief search and read the request stanza for action later
+ *
+ * This method while ignore the input up to the point it finds the
+ * Request: line as an indicator for the Request stanza.
+ * The request is stored in the parameters install and remove then,
+ * as the cache isn't build yet as the scenario follows the request.
+ *
+ * \param input file descriptor with the edsp input for the solver
+ * \param[out] install is a list which gets populated with requested installs
+ * \param[out] remove is a list which gets populated with requested removals
+ * \param[out] upgrade is true if it is a request like apt-get upgrade
+ * \param[out] distUpgrade is true if it is a request like apt-get dist-upgrade
+ * \param[out] autoRemove is true if removal of uneeded packages should be performed
+ *
+ * \return true if the request could be found and worked on, otherwise false
+ */
bool static ReadRequest(int const input, std::list<std::string> &install,
std::list<std::string> &remove, bool &upgrade,
bool &distUpgrade, bool &autoRemove);
+
+ /** \brief takes the request lists and applies it on the cache
+ *
+ * The lists as created by #ReadRequest will be used to find the
+ * packages in question and mark them for install/remove.
+ * No solving is done and no auto-install/-remove.
+ *
+ * \param install is a list of packages to mark for installation
+ * \param remove is a list of packages to mark for removal
+ * \param Cache is there the markers should be set
+ *
+ * \return false if the request couldn't be applied, true otherwise
+ */
bool static ApplyRequest(std::list<std::string> const &install,
std::list<std::string> const &remove,
pkgDepCache &Cache);
+
+ /** \brief encodes the changes in the Cache as a EDSP solution
+ *
+ * The markers in the Cache are observed and send to given
+ * file. The solution isn't checked for consistency or alike,
+ * so even broken solutions can be written successfully,
+ * but the front-end revicing it will properly fail then.
+ *
+ * \param Cache which represents the solution
+ * \param output to write the stanzas forming the solution to
+ *
+ * \return true if solution could be written, otherwise false
+ */
bool static WriteSolution(pkgDepCache &Cache, FILE* output);
- bool static WriteError(std::string const &message, FILE* output);
+ /** \brief sends a progress report
+ *
+ * \param percent of the solving completed
+ * \param message the solver wants the user to see
+ * \param output the front-end listens for progress report
+ */
+ bool static WriteProgress(unsigned short const percent, const char* const message, FILE* output);
+
+ /** \brief sends an error report
+ *
+ * Solvers are expected to execute successfully even if
+ * they were unable to calculate a solution for a given task.
+ * Obviously they can't send a solution through, so this
+ * methods deals with formatting an error message correctly
+ * so that the front-ends can recieve and display it.
+ *
+ * The first line of the message should be a short description
+ * of the error so it can be used for dialog titles or alike
+ *
+ * \param uuid of this error message
+ * \param message is free form text to discribe the error
+ * \param output the front-end listens for error messages
+ */
+ bool static WriteError(char const * const uuid, std::string const &message, FILE* output);
+
+
+ /** \brief executes the given solver and returns the pipe ends
+ *
+ * The given solver is executed if it can be found in one of the
+ * configured directories and setup for it is performed.
+ *
+ * \param solver to execute
+ * \param[out] solver_in will be the stdin of the solver
+ * \param[out] solver_out will be the stdout of the solver
+ *
+ * \return true if the solver could be started and the pipes
+ * are set up correctly, otherwise false and the pipes are invalid
+ */
+ bool static ExecuteSolver(const char* const solver, int *solver_in, int *solver_out);
+
+ /** \brief call an external resolver to handle the request
+ *
+ * This method wraps all the methods above to call an external solver
+ *
+ * \param solver to execute
+ * \param Cache with the problem and as universe to work in
+ * \param upgrade is true if it is a request like apt-get upgrade
+ * \param distUpgrade is true if it is a request like apt-get dist-upgrade
+ * \param autoRemove is true if unneeded packages should be removed
+ * \param Progress is an instance to report progress to
+ *
+ * \return true if the solver has successfully solved the problem,
+ * otherwise false
+ */
+ bool static ResolveExternal(const char* const solver, pkgDepCache &Cache,
+ bool const upgrade, bool const distUpgrade,
+ bool const autoRemove, OpProgress *Progress = NULL);
};
/*}}}*/
#endif
diff --git a/apt-pkg/edsp/edsplistparser.cc b/apt-pkg/edsp/edsplistparser.cc
index 913455efa..3349e8cce 100644
--- a/apt-pkg/edsp/edsplistparser.cc
+++ b/apt-pkg/edsp/edsplistparser.cc
@@ -63,10 +63,13 @@ unsigned short edspListParser::VersionHash()
bool edspListParser::ParseStatus(pkgCache::PkgIterator &Pkg,
pkgCache::VerIterator &Ver)
{
- if (Section.FindFlag("Hold",Pkg->Flags,pkgCache::State::Installed) == false)
+ unsigned long state = 0;
+ if (Section.FindFlag("Hold",state,pkgCache::State::Hold) == false)
return false;
+ if (state != 0)
+ Pkg->SelectedState = pkgCache::State::Hold;
- unsigned long state = 0;
+ state = 0;
if (Section.FindFlag("Installed",state,pkgCache::State::Installed) == false)
return false;
if (state != 0)
diff --git a/apt-pkg/indexcopy.cc b/apt-pkg/indexcopy.cc
index c2ee1c347..064fb007c 100644
--- a/apt-pkg/indexcopy.cc
+++ b/apt-pkg/indexcopy.cc
@@ -75,7 +75,7 @@ bool IndexCopy::CopyPackages(string CDROM,string Name,vector<string> &List,
// Open the package file
FileFd Pkg;
- if (FileExists(*I + GetFileName()) == true)
+ if (RealFileExists(*I + GetFileName()) == true)
{
Pkg.Open(*I + GetFileName(),FileFd::ReadOnly);
FileSize = Pkg.Size();
@@ -532,7 +532,7 @@ bool SigVerify::Verify(string prefix, string file, indexRecords *MetaIndex)
// 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))
+ if(!RealFileExists(prefix+file))
{
_error->Warning(_("Skipping nonexistent file %s"), string(prefix+file).c_str());
return true;
@@ -601,7 +601,7 @@ bool SigVerify::CopyAndVerify(string CDROM,string Name,vector<string> &SigList,
string const release = *I+"Release";
// a Release.gpg without a Release should never happen
- if(FileExists(release) == false)
+ if(RealFileExists(release) == false)
{
delete MetaIndex;
continue;
@@ -681,7 +681,7 @@ bool SigVerify::RunGPGV(std::string const &File, std::string const &FileGPG,
std::vector<string> keyrings;
if (DirectoryExists(trustedPath))
keyrings = GetListOfFilesInDir(trustedPath, "gpg", false, true);
- if (FileExists(trustedFile) == true)
+ if (RealFileExists(trustedFile) == true)
keyrings.push_back(trustedFile);
std::vector<const char *> Args;
@@ -788,7 +788,7 @@ bool TranslationsCopy::CopyTranslations(string CDROM,string Name, /*{{{*/
// Open the package file
FileFd Pkg;
- if (FileExists(*I) == true)
+ if (RealFileExists(*I) == true)
{
Pkg.Open(*I,FileFd::ReadOnly);
FileSize = Pkg.Size();
diff --git a/apt-pkg/init.cc b/apt-pkg/init.cc
index a30f27844..aff585e3b 100644
--- a/apt-pkg/init.cc
+++ b/apt-pkg/init.cc
@@ -72,7 +72,9 @@ bool pkgInitConfig(Configuration &Cnf)
Cnf.Set("Dir::Etc::preferencesparts","preferences.d");
Cnf.Set("Dir::Etc::trusted", "trusted.gpg");
Cnf.Set("Dir::Etc::trustedparts","trusted.gpg.d");
+
Cnf.Set("Dir::Bin::methods","/usr/lib/apt/methods");
+ Cnf.Set("Dir::Bin::solvers::","/usr/lib/apt/solvers");
Cnf.Set("Dir::Media::MountPath","/media/apt");
// State
diff --git a/apt-pkg/orderlist.cc b/apt-pkg/orderlist.cc
index d5bd19581..ba43bc757 100644
--- a/apt-pkg/orderlist.cc
+++ b/apt-pkg/orderlist.cc
@@ -490,7 +490,7 @@ bool pkgOrderList::VisitRProvides(DepFunc F,VerIterator Ver)
bool Res = true;
for (PrvIterator P = Ver.ProvidesList(); P.end() == false; P++)
Res &= (this->*F)(P.ParentPkg().RevDependsList());
- return true;
+ return Res;
}
/*}}}*/
// OrderList::VisitProvides - Visit all of the providing packages /*{{{*/
@@ -507,15 +507,11 @@ bool pkgOrderList::VisitProvides(DepIterator D,bool Critical)
if (Cache[Pkg].Keep() == true && Pkg.State() == PkgIterator::NeedsNothing)
continue;
- if (D->Type != pkgCache::Dep::Conflicts &&
- D->Type != pkgCache::Dep::DpkgBreaks &&
- D->Type != pkgCache::Dep::Obsoletes &&
+ if (D.IsNegative() == false &&
Cache[Pkg].InstallVer != *I)
continue;
- if ((D->Type == pkgCache::Dep::Conflicts ||
- D->Type == pkgCache::Dep::DpkgBreaks ||
- D->Type == pkgCache::Dep::Obsoletes) &&
+ if (D.IsNegative() == true &&
(Version *)Pkg.CurrentVer() != *I)
continue;
@@ -647,9 +643,7 @@ bool pkgOrderList::DepUnPackCrit(DepIterator D)
{
/* Forward critical dependencies MUST be correct before the
package can be unpacked. */
- if (D->Type != pkgCache::Dep::Conflicts &&
- D->Type != pkgCache::Dep::DpkgBreaks &&
- D->Type != pkgCache::Dep::Obsoletes &&
+ if (D.IsNegative() == false &&
D->Type != pkgCache::Dep::PreDepends)
continue;
@@ -1077,9 +1071,7 @@ bool pkgOrderList::CheckDep(DepIterator D)
/* Conflicts requires that all versions are not present, depends
just needs one */
- if (D->Type != pkgCache::Dep::Conflicts &&
- D->Type != pkgCache::Dep::DpkgBreaks &&
- D->Type != pkgCache::Dep::Obsoletes)
+ if (D.IsNegative() == false)
{
/* Try to find something that does not have the after flag set
if at all possible */
diff --git a/apt-pkg/packagemanager.cc b/apt-pkg/packagemanager.cc
index 4c655cb7b..fe9f6eb68 100644
--- a/apt-pkg/packagemanager.cc
+++ b/apt-pkg/packagemanager.cc
@@ -319,6 +319,17 @@ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg)
List->Flag(Pkg,pkgOrderList::Configured,pkgOrderList::States);
}
+ if (Cache[Pkg].InstVerIter(Cache)->MultiArch == pkgCache::Version::Same)
+ for (PkgIterator P = Pkg.Group().PackageList();
+ P.end() == false; P = Pkg.Group().NextPkg(P))
+ {
+ if (Pkg == P || List->IsFlag(P,pkgOrderList::Configured) == true ||
+ Cache[P].InstallVer == 0 || (P.CurrentVer() == Cache[P].InstallVer &&
+ (Cache[Pkg].iFlags & pkgDepCache::ReInstall) != pkgDepCache::ReInstall))
+ continue;
+ SmartConfigure(P);
+ }
+
// Sanity Check
if (List->IsFlag(Pkg,pkgOrderList::Configured) == false)
return _error->Error(_("Could not perform immediate configuration on '%s'. "
@@ -475,21 +486,28 @@ bool pkgPackageManager::SmartRemove(PkgIterator Pkg)
/* This performs the task of handling pre-depends. */
bool pkgPackageManager::SmartUnPack(PkgIterator Pkg)
{
+ return SmartUnPack(Pkg, true);
+}
+bool pkgPackageManager::SmartUnPack(PkgIterator Pkg, bool const Immediate)
+{
// Check if it is already unpacked
if (Pkg.State() == pkgCache::PkgIterator::NeedsConfigure &&
Cache[Pkg].Keep() == true)
{
List->Flag(Pkg,pkgOrderList::UnPacked,pkgOrderList::States);
- if (List->IsFlag(Pkg,pkgOrderList::Immediate) == true)
+ if (Immediate == true &&
+ List->IsFlag(Pkg,pkgOrderList::Immediate) == true)
if (SmartConfigure(Pkg) == false)
return _error->Error(_("Could not perform immediate configuration on already unpacked '%s'. "
"Please see man 5 apt.conf under APT::Immediate-Configure for details."),Pkg.Name());
return true;
}
+ VerIterator const instVer = Cache[Pkg].InstVerIter(Cache);
+
/* See if this packages install version has any predependencies
that are not met by 'now' packages. */
- for (DepIterator D = Cache[Pkg].InstVerIter(Cache).DependsList();
+ for (DepIterator D = instVer.DependsList();
D.end() == false; )
{
// Compute a single dependency element (glob or)
@@ -575,20 +593,32 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg)
// Check for reverse conflicts.
if (CheckRConflicts(Pkg,Pkg.RevDependsList(),
- Cache[Pkg].InstVerIter(Cache).VerStr()) == false)
+ instVer.VerStr()) == false)
return false;
- for (PrvIterator P = Cache[Pkg].InstVerIter(Cache).ProvidesList();
+ for (PrvIterator P = instVer.ProvidesList();
P.end() == false; P++)
CheckRConflicts(Pkg,P.ParentPkg().RevDependsList(),P.ProvideVersion());
+ List->Flag(Pkg,pkgOrderList::UnPacked,pkgOrderList::States);
+
+ if (instVer->MultiArch == pkgCache::Version::Same)
+ for (PkgIterator P = Pkg.Group().PackageList();
+ P.end() == false; P = Pkg.Group().NextPkg(P))
+ {
+ if (Pkg == P || List->IsFlag(P,pkgOrderList::UnPacked) == true ||
+ Cache[P].InstallVer == 0 || (P.CurrentVer() == Cache[P].InstallVer &&
+ (Cache[Pkg].iFlags & pkgDepCache::ReInstall) != pkgDepCache::ReInstall))
+ continue;
+ SmartUnPack(P, false);
+ }
+
if(Install(Pkg,FileNames[Pkg->ID]) == false)
return false;
- List->Flag(Pkg,pkgOrderList::UnPacked,pkgOrderList::States);
-
// Perform immedate configuration of the package.
- if (List->IsFlag(Pkg,pkgOrderList::Immediate) == true)
+ if (Immediate == true &&
+ List->IsFlag(Pkg,pkgOrderList::Immediate) == true)
if (SmartConfigure(Pkg) == false)
return _error->Error(_("Could not perform immediate configuration on '%s'. "
"Please see man 5 apt.conf under APT::Immediate-Configure for details. (%d)"),Pkg.Name(),2);
diff --git a/apt-pkg/packagemanager.h b/apt-pkg/packagemanager.h
index efd2cfac6..053b4dc13 100644
--- a/apt-pkg/packagemanager.h
+++ b/apt-pkg/packagemanager.h
@@ -69,7 +69,9 @@ class pkgPackageManager : protected pkgCache::Namespace
// Install helpers
bool ConfigureAll();
bool SmartConfigure(PkgIterator Pkg);
+ //FIXME: merge on abi break
bool SmartUnPack(PkgIterator Pkg);
+ bool SmartUnPack(PkgIterator Pkg, bool const Immediate);
bool SmartRemove(PkgIterator Pkg);
bool EarlyRemove(PkgIterator Pkg);
diff --git a/apt-pkg/pkgcache.cc b/apt-pkg/pkgcache.cc
index c6326abf1..38e4e904e 100644
--- a/apt-pkg/pkgcache.cc
+++ b/apt-pkg/pkgcache.cc
@@ -211,12 +211,18 @@ pkgCache::PkgIterator pkgCache::SingleArchFindPkg(const string &Name)
// ---------------------------------------------------------------------
/* Returns 0 on error, pointer to the package otherwise */
pkgCache::PkgIterator pkgCache::FindPkg(const string &Name) {
- if (MultiArchCache() == false)
- return SingleArchFindPkg(Name);
size_t const found = Name.find(':');
if (found == string::npos)
- return FindPkg(Name, "native");
+ {
+ if (MultiArchCache() == false)
+ return SingleArchFindPkg(Name);
+ else
+ return FindPkg(Name, "native");
+ }
string const Arch = Name.substr(found+1);
+ /* Beware: This is specialcased to handle pkg:any in dependencies as
+ these are linked to virtual pkg:any named packages with all archs.
+ If you want any arch from a given pkg, use FindPkg(pkg,arch) */
if (Arch == "any")
return FindPkg(Name, "any");
return FindPkg(Name.substr(0, found), Arch);
@@ -228,7 +234,7 @@ pkgCache::PkgIterator pkgCache::FindPkg(const string &Name) {
pkgCache::PkgIterator pkgCache::FindPkg(const string &Name, string const &Arch) {
if (MultiArchCache() == false) {
if (Arch == "native" || Arch == "all" || Arch == "any" ||
- Arch == _config->Find("APT::Architecture"))
+ Arch == NativeArch())
return SingleArchFindPkg(Name);
else
return PkgIterator(*this,0);
@@ -322,15 +328,15 @@ pkgCache::PkgIterator pkgCache::GrpIterator::FindPkg(string Arch) const {
if (Arch == "any")
return PkgIterator(*Owner, Owner->PkgP + S->FirstPackage);
- static string const myArch = _config->Find("APT::Architecture");
+ char const* const myArch = Owner->NativeArch();
/* Most of the time the package for our native architecture is
the one we add at first to the cache, but this would be the
last one we check, so we do it now. */
if (Arch == "native" || Arch == myArch || Arch == "all") {
- Arch = myArch;
pkgCache::Package *Pkg = Owner->PkgP + S->LastPackage;
- if (stringcasecmp(Arch, Owner->StrP + Pkg->Arch) == 0)
+ if (strcasecmp(myArch, Owner->StrP + Pkg->Arch) == 0)
return PkgIterator(*Owner, Pkg);
+ Arch = myArch;
}
/* Iterate over the list to find the matching arch
@@ -503,7 +509,8 @@ std::string pkgCache::PkgIterator::FullName(bool const &Pretty) const
{
string fullname = Name();
if (Pretty == false ||
- (strcmp(Arch(), "all") != 0 && _config->Find("APT::Architecture") != Arch()))
+ (strcmp(Arch(), "all") != 0 &&
+ strcmp(Owner->NativeArch(), Arch()) != 0))
return fullname.append(":").append(Arch());
return fullname;
}
@@ -514,15 +521,24 @@ std::string pkgCache::PkgIterator::FullName(bool const &Pretty) const
conflicts (including dpkg's Breaks fields). */
bool pkgCache::DepIterator::IsCritical() const
{
- if (S->Type == pkgCache::Dep::Conflicts ||
- S->Type == pkgCache::Dep::DpkgBreaks ||
- S->Type == pkgCache::Dep::Obsoletes ||
+ if (IsNegative() == true ||
S->Type == pkgCache::Dep::Depends ||
S->Type == pkgCache::Dep::PreDepends)
return true;
return false;
}
/*}}}*/
+// DepIterator::IsNegative - Returns true if the dep is a negative one /*{{{*/
+// ---------------------------------------------------------------------
+/* Some dependencies are positive like Depends and Recommends, others
+ are negative like Conflicts which can and should be handled differently */
+bool pkgCache::DepIterator::IsNegative() const
+{
+ return S->Type == Dep::DpkgBreaks ||
+ S->Type == Dep::Conflicts ||
+ S->Type == Dep::Obsoletes;
+}
+ /*}}}*/
// DepIterator::SmartTargetPkg - Resolve dep target pointers w/provides /*{{{*/
// ---------------------------------------------------------------------
/* This intellegently looks at dep target packages and tries to figure
@@ -600,9 +616,7 @@ pkgCache::Version **pkgCache::DepIterator::AllTargets() const
if (Owner->VS->CheckDep(I.VerStr(),S->CompareOp,TargetVer()) == false)
continue;
- if ((S->Type == pkgCache::Dep::Conflicts ||
- S->Type == pkgCache::Dep::DpkgBreaks ||
- S->Type == pkgCache::Dep::Obsoletes) &&
+ if (IsNegative() == true &&
ParentPkg() == I.ParentPkg())
continue;
@@ -617,9 +631,7 @@ pkgCache::Version **pkgCache::DepIterator::AllTargets() const
if (Owner->VS->CheckDep(I.ProvideVersion(),S->CompareOp,TargetVer()) == false)
continue;
- if ((S->Type == pkgCache::Dep::Conflicts ||
- S->Type == pkgCache::Dep::DpkgBreaks ||
- S->Type == pkgCache::Dep::Obsoletes) &&
+ if (IsNegative() == true &&
ParentPkg() == I.OwnerPkg())
continue;
diff --git a/apt-pkg/pkgcache.h b/apt-pkg/pkgcache.h
index d654a2976..1b1743724 100644
--- a/apt-pkg/pkgcache.h
+++ b/apt-pkg/pkgcache.h
@@ -215,6 +215,7 @@ class pkgCache /*{{{*/
private:
bool MultiArchEnabled;
PkgIterator SingleArchFindPkg(const string &Name);
+ inline char const * const NativeArch() const;
};
/*}}}*/
// Header structure /*{{{*/
@@ -649,6 +650,11 @@ struct pkgCache::StringItem
map_ptrloc NextItem; // StringItem
};
/*}}}*/
+
+
+inline char const * const pkgCache::NativeArch() const
+ { return StrP + HeaderP->Architecture; };
+
#include <apt-pkg/cacheiterators.h>
inline pkgCache::GrpIterator pkgCache::GrpBegin()
diff --git a/apt-pkg/pkgcachegen.cc b/apt-pkg/pkgcachegen.cc
index 46dd22007..8e088ba68 100644
--- a/apt-pkg/pkgcachegen.cc
+++ b/apt-pkg/pkgcachegen.cc
@@ -479,7 +479,8 @@ bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator &Pkg,const string &Name
// Set the name, arch and the ID
Pkg->Name = Grp->Name;
Pkg->Group = Grp.Index();
- map_ptrloc const idxArch = WriteUniqString((Arch == "all") ? _config->Find("APT::Architecture") : Arch.c_str());
+ // all is mapped to the native architecture
+ map_ptrloc const idxArch = (Arch == "all") ? Cache.HeaderP->Architecture : WriteUniqString(Arch.c_str());
if (unlikely(idxArch == 0))
return false;
Pkg->Arch = idxArch;
@@ -783,7 +784,7 @@ bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator &Ver,
// We do not add self referencing provides
if (Ver.ParentPkg().Name() == PkgName && (PkgArch == Ver.ParentPkg().Arch() ||
- (PkgArch == "all" && _config->Find("APT::Architecture") == Ver.ParentPkg().Arch())))
+ (PkgArch == "all" && strcmp((Cache.StrP + Cache.HeaderP->Architecture), Ver.ParentPkg().Arch()) == 0)))
return true;
// Get a structure
diff --git a/apt-pkg/policy.cc b/apt-pkg/policy.cc
index 4e4077feb..4fc272a74 100644
--- a/apt-pkg/policy.cc
+++ b/apt-pkg/policy.cc
@@ -216,10 +216,22 @@ void pkgPolicy::CreatePin(pkgVersionMatch::MatchType Type,string Name,
P->Data = Data;
return;
}
+
+ // Allow pinning by wildcards
+ // TODO: Maybe we should always prefer specific pins over non-
+ // specific ones.
+ if (Name[0] == '/' || Name.find_first_of("*[?") != string::npos)
+ {
+ pkgVersionMatch match(Data, Type);
+ for (pkgCache::GrpIterator G = Cache->GrpBegin(); G.end() != true; ++G)
+ if (match.ExpressionMatches(Name, G.Name()))
+ CreatePin(Type, G.Name(), Data, Priority);
+ return;
+ }
// Get a spot to put the pin
pkgCache::GrpIterator Grp = Cache->FindGrp(Name);
- for (pkgCache::PkgIterator Pkg = Grp.FindPkg("any");
+ for (pkgCache::PkgIterator Pkg = Grp.PackageList();
Pkg.end() != true; Pkg = Grp.NextPkg(Pkg))
{
Pin *P = 0;