diff options
Diffstat (limited to 'apt-pkg')
31 files changed, 536 insertions, 363 deletions
diff --git a/apt-pkg/acquire-item.cc b/apt-pkg/acquire-item.cc index 30743add..6cb9b012 100644 --- a/apt-pkg/acquire-item.cc +++ b/apt-pkg/acquire-item.cc @@ -356,7 +356,7 @@ pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire *Owner, Desc.URI = URI + ".diff/Index"; DestFile = _config->FindDir("Dir::State::lists") + "partial/"; - DestFile += URItoFileName(URI) + string(".DiffIndex"); + DestFile += URItoFileName(Desc.URI); if(Debug) std::clog << "pkgAcqDiffIndex: " << Desc.URI << std::endl; @@ -392,7 +392,7 @@ pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire *Owner, string pkgAcqDiffIndex::Custom600Headers() { string Final = _config->FindDir("Dir::State::lists"); - Final += URItoFileName(RealURI) + string(".IndexDiff"); + Final += URItoFileName(Desc.URI); if(Debug) std::clog << "Custom600Header-IMS: " << Final << std::endl; @@ -955,13 +955,6 @@ pkgAcqIndex::pkgAcqIndex(pkgAcquire *Owner, IndexTarget const *Target, if (CompressionExtension.empty() == false) CompressionExtension.erase(CompressionExtension.end()-1); - // only verify non-optional targets, see acquire-item.h for a FIXME - // to make this more flexible - if (Target->IsOptional()) - Verify = false; - else - Verify = true; - Init(Target->URI, Target->Description, Target->ShortDesc); } /*}}}*/ @@ -1054,23 +1047,24 @@ void pkgAcqIndex::Done(string Message,unsigned long long Size,string Hash, return; } - /* Verify the index file for correctness (all indexes must - * have a Package field) (LP: #346386) (Closes: #627642) */ - if (Verify == true) + // FIXME: this can go away once we only ever download stuff that + // has a valid hash and we never do GET based probing + // + /* Always verify the index file for correctness (all indexes must + * have a Package field) (LP: #346386) (Closes: #627642) + */ + FileFd fd(DestFile, FileFd::ReadOnly); + // Only test for correctness if the file is not empty (empty is ok) + if (fd.FileSize() > 0) { - FileFd fd(DestFile, FileFd::ReadOnly); - // Only test for correctness if the file is not empty (empty is ok) - if (fd.FileSize() > 0) - { - pkgTagSection sec; - pkgTagFile tag(&fd); - - // all our current indexes have a field 'Package' in each section - if (_error->PendingError() == true || tag.Step(sec) == false || sec.Exists("Package") == false) - { - RenameOnError(InvalidFormat); - return; - } + pkgTagSection sec; + pkgTagFile tag(&fd); + + // all our current indexes have a field 'Package' in each section + if (_error->PendingError() == true || tag.Step(sec) == false || sec.Exists("Package") == false) + { + RenameOnError(InvalidFormat); + return; } } diff --git a/apt-pkg/acquire-item.h b/apt-pkg/acquire-item.h index f48d2a0d..06537bf2 100644 --- a/apt-pkg/acquire-item.h +++ b/apt-pkg/acquire-item.h @@ -685,15 +685,8 @@ class pkgAcqIndex : public pkgAcquire::Item */ bool Erase; - /** \brief Verify for correctness by checking if a "Package" - * tag is found in the index. This can be set to - * false for optional index targets - * - */ - // FIXME: instead of a bool it should use a verify string that will - // then be used in the pkgAcqIndex::Done method to ensure that - // the downloaded file contains the expected tag - bool Verify; + // Unused, used to be used to verify that "Packages: " header was there + bool __DELME_ON_NEXT_ABI_BREAK_Verify; /** \brief The download request that is currently being * processed. diff --git a/apt-pkg/acquire.cc b/apt-pkg/acquire.cc index a187a00a..057bc24c 100644 --- a/apt-pkg/acquire.cc +++ b/apt-pkg/acquire.cc @@ -486,6 +486,9 @@ bool pkgAcquire::Clean(string Dir) if (DirectoryExists(Dir) == false) return true; + if(Dir == "/") + return _error->Error(_("Clean of %s is not supported"), Dir.c_str()); + DIR *D = opendir(Dir.c_str()); if (D == 0) return _error->Errno("opendir",_("Unable to read %s"),Dir.c_str()); diff --git a/apt-pkg/algorithms.cc b/apt-pkg/algorithms.cc index a7b67666..608ec7fc 100644 --- a/apt-pkg/algorithms.cc +++ b/apt-pkg/algorithms.cc @@ -445,19 +445,22 @@ void pkgProblemResolver::MakeScores() || (I->Flags & pkgCache::Flag::Important) == pkgCache::Flag::Important) Score += PrioEssentials; - // We transform the priority - if (Cache[I].InstVerIter(Cache)->Priority <= 5) - Score += PrioMap[Cache[I].InstVerIter(Cache)->Priority]; - + pkgCache::VerIterator const InstVer = Cache[I].InstVerIter(Cache); + // We apply priorities only to downloadable packages, all others are prio:extra + // as an obsolete prio:standard package can't be that standard anymore… + if (InstVer->Priority <= pkgCache::State::Extra && InstVer.Downloadable() == true) + Score += PrioMap[InstVer->Priority]; + else + Score += PrioMap[pkgCache::State::Extra]; + /* This helps to fix oddball problems with conflicting packages - on the same level. We enhance the score of installed packages - if those are not obsolete - */ + on the same level. We enhance the score of installed packages + if those are not obsolete */ if (I->CurrentVer != 0 && Cache[I].CandidateVer != 0 && Cache[I].CandidateVerIter(Cache).Downloadable()) Score += PrioInstalledAndNotObsolete; // propagate score points along dependencies - for (pkgCache::DepIterator D = Cache[I].InstVerIter(Cache).DependsList(); D.end() == false; ++D) + for (pkgCache::DepIterator D = InstVer.DependsList(); D.end() == false; ++D) { if (DepMap[D->Type] == 0) continue; diff --git a/apt-pkg/aptconfiguration.cc b/apt-pkg/aptconfiguration.cc index 6ba04756..9982759c 100644 --- a/apt-pkg/aptconfiguration.cc +++ b/apt-pkg/aptconfiguration.cc @@ -476,7 +476,7 @@ const Configuration::getCompressors(bool const Cached) { std::vector<std::string> const comp = _config->FindVector("APT::Compressor"); for (std::vector<std::string>::const_iterator c = comp.begin(); c != comp.end(); ++c) { - if (*c == "." || *c == "gzip" || *c == "bzip2" || *c == "lzma" || *c == "xz") + if (c->empty() || *c == "." || *c == "gzip" || *c == "bzip2" || *c == "lzma" || *c == "xz") continue; compressors.push_back(Compressor(c->c_str(), std::string(".").append(*c).c_str(), c->c_str(), "-9", "-d", 100)); } diff --git a/apt-pkg/cacheset.cc b/apt-pkg/cacheset.cc index d453a2bf..2ed6a96d 100644 --- a/apt-pkg/cacheset.cc +++ b/apt-pkg/cacheset.cc @@ -391,6 +391,8 @@ bool VersionContainerInterface::FromModifierCommandLine(unsigned short &modID, CacheSetHelper &helper) { Version select = NEWEST; std::string str = cmdline; + if (unlikely(str.empty() == true)) + return false; bool modifierPresent = false; unsigned short fallback = modID; for (std::list<Modifier>::const_iterator mod = mods.begin(); @@ -400,8 +402,8 @@ bool VersionContainerInterface::FromModifierCommandLine(unsigned short &modID, size_t const alength = strlen(mod->Alias); switch(mod->Pos) { case Modifier::POSTFIX: - if (str.compare(str.length() - alength, alength, - mod->Alias, 0, alength) != 0) + if (str.length() <= alength || + str.compare(str.length() - alength, alength, mod->Alias, 0, alength) != 0) continue; str.erase(str.length() - alength); modID = mod->ID; diff --git a/apt-pkg/cdrom.cc b/apt-pkg/cdrom.cc index 2635ede7..a5ad6a9f 100644 --- a/apt-pkg/cdrom.cc +++ b/apt-pkg/cdrom.cc @@ -563,6 +563,15 @@ bool pkgCdrom::WriteSourceList(string Name,vector<string> &List,bool Source) return true; } /*}}}*/ +bool pkgCdrom::UnmountCDROM(std::string const &CDROM, pkgCdromStatus * const log)/*{{{*/ +{ + if (_config->FindB("APT::CDROM::NoMount",false) == true) + return true; + if (log != NULL) + log->Update(_("Unmounting CD-ROM...\n"), STEP_LAST); + return UnmountCdrom(CDROM); +} + /*}}}*/ bool pkgCdrom::MountAndIdentCDROM(Configuration &Database, std::string &CDROM, std::string &ident, pkgCdromStatus * const log, bool const interactive)/*{{{*/ { // Startup @@ -583,9 +592,7 @@ bool pkgCdrom::MountAndIdentCDROM(Configuration &Database, std::string &CDROM, s { if (interactive == true) { - if(log != NULL) - log->Update(_("Unmounting CD-ROM...\n"), STEP_LAST); - UnmountCdrom(CDROM); + UnmountCDROM(CDROM, log); if(log != NULL) { @@ -605,6 +612,9 @@ bool pkgCdrom::MountAndIdentCDROM(Configuration &Database, std::string &CDROM, s return _error->Error("Failed to mount the cdrom."); } + if (IsMounted(CDROM) == false) + return _error->Error("Failed to mount the cdrom."); + // Hash the CD to get an ID if (log != NULL) log->Update(_("Identifying... "), STEP_IDENT); @@ -614,6 +624,7 @@ bool pkgCdrom::MountAndIdentCDROM(Configuration &Database, std::string &CDROM, s ident = ""; if (log != NULL) log->Update("\n"); + UnmountCDROM(CDROM, NULL); return false; } @@ -629,8 +640,11 @@ bool pkgCdrom::MountAndIdentCDROM(Configuration &Database, std::string &CDROM, s if (FileExists(DFile) == true) { if (ReadConfigFile(Database,DFile) == false) + { + UnmountCDROM(CDROM, NULL); return _error->Error("Unable to read the cdrom database %s", DFile.c_str()); + } } return true; } @@ -651,13 +665,7 @@ bool pkgCdrom::Ident(string &ident, pkgCdromStatus *log) /*{{{*/ } // Unmount and finish - if (_config->FindB("APT::CDROM::NoMount",false) == false) - { - if (log != NULL) - log->Update(_("Unmounting CD-ROM...\n"), STEP_LAST); - UnmountCdrom(CDROM); - } - + UnmountCDROM(CDROM, log); return true; } /*}}}*/ @@ -682,11 +690,15 @@ bool pkgCdrom::Add(pkgCdromStatus *log) /*{{{*/ { if (log != NULL) log->Update("\n"); + UnmountCDROM(CDROM, NULL); return false; } if (chdir(StartDir.c_str()) != 0) + { + UnmountCDROM(CDROM, NULL); return _error->Errno("chdir","Unable to change to %s", StartDir.c_str()); + } if (_config->FindB("Debug::aptcdrom",false) == true) { @@ -728,8 +740,7 @@ bool pkgCdrom::Add(pkgCdromStatus *log) /*{{{*/ if (List.empty() == true && SourceList.empty() == true) { - if (_config->FindB("APT::CDROM::NoMount",false) == false) - UnmountCdrom(CDROM); + UnmountCDROM(CDROM, NULL); return _error->Error(_("Unable to locate any package files, perhaps this is not a Debian Disc or the wrong architecture?")); } @@ -769,14 +780,14 @@ bool pkgCdrom::Add(pkgCdromStatus *log) /*{{{*/ { if(log == NULL) { - if (_config->FindB("APT::CDROM::NoMount",false) == false) - UnmountCdrom(CDROM); + UnmountCDROM(CDROM, NULL); return _error->Error("No disc name found and no way to ask for it"); } while(true) { if(!log->AskCdromName(Name)) { // user canceld + UnmountCDROM(CDROM, NULL); return false; } cout << "Name: '" << Name << "'" << endl; @@ -813,7 +824,10 @@ bool pkgCdrom::Add(pkgCdromStatus *log) /*{{{*/ string const partialListDir = listDir + "partial/"; if (CreateAPTDirectoryIfNeeded(_config->FindDir("Dir::State"), partialListDir) == false && CreateAPTDirectoryIfNeeded(listDir, partialListDir) == false) + { + UnmountCDROM(CDROM, NULL); return _error->Errno("cdrom", _("List directory %spartial is missing."), listDir.c_str()); + } // take care of the signatures and copy them if they are ok // (we do this before PackageCopy as it modifies "List" and "SourceList") @@ -827,7 +841,10 @@ bool pkgCdrom::Add(pkgCdromStatus *log) /*{{{*/ if (Copy.CopyPackages(CDROM,Name,List, log) == false || SrcCopy.CopyPackages(CDROM,Name,SourceList, log) == false || TransCopy.CopyTranslations(CDROM,Name,TransList, log) == false) + { + UnmountCDROM(CDROM, NULL); return false; + } // reduce the List so that it takes less space in sources.list ReduceSourcelist(CDROM,List); @@ -837,13 +854,19 @@ bool pkgCdrom::Add(pkgCdromStatus *log) /*{{{*/ if (_config->FindB("APT::cdrom::NoAct",false) == false) { if (WriteDatabase(Database) == false) + { + UnmountCDROM(CDROM, NULL); return false; - + } + if(log != NULL) log->Update(_("Writing new source list\n"), STEP_WRITE); if (WriteSourceList(Name,List,false) == false || WriteSourceList(Name,SourceList,true) == false) + { + UnmountCDROM(CDROM, NULL); return false; + } } // Print the sourcelist entries @@ -855,8 +878,7 @@ bool pkgCdrom::Add(pkgCdromStatus *log) /*{{{*/ string::size_type Space = (*I).find(' '); if (Space == string::npos) { - if (_config->FindB("APT::CDROM::NoMount",false) == false) - UnmountCdrom(CDROM); + UnmountCDROM(CDROM, NULL); return _error->Error("Internal error"); } @@ -874,8 +896,7 @@ bool pkgCdrom::Add(pkgCdromStatus *log) /*{{{*/ string::size_type Space = (*I).find(' '); if (Space == string::npos) { - if (_config->FindB("APT::CDROM::NoMount",false) == false) - UnmountCdrom(CDROM); + UnmountCDROM(CDROM, NULL); return _error->Error("Internal error"); } @@ -888,12 +909,7 @@ bool pkgCdrom::Add(pkgCdromStatus *log) /*{{{*/ } // Unmount and finish - if (_config->FindB("APT::CDROM::NoMount",false) == false) { - if (log != NULL) - log->Update(_("Unmounting CD-ROM...\n"), STEP_LAST); - UnmountCdrom(CDROM); - } - + UnmountCDROM(CDROM, log); return true; } /*}}}*/ diff --git a/apt-pkg/cdrom.h b/apt-pkg/cdrom.h index 0f2c2cd0..bd090217 100644 --- a/apt-pkg/cdrom.h +++ b/apt-pkg/cdrom.h @@ -77,6 +77,7 @@ class pkgCdrom /*{{{*/ private: APT_HIDDEN bool MountAndIdentCDROM(Configuration &Database, std::string &CDROM, std::string &ident, pkgCdromStatus * const log, bool const interactive); + APT_HIDDEN bool UnmountCDROM(std::string const &CDROM, pkgCdromStatus * const log); }; /*}}}*/ diff --git a/apt-pkg/clean.cc b/apt-pkg/clean.cc index 0ee3b765..37128e9a 100644 --- a/apt-pkg/clean.cc +++ b/apt-pkg/clean.cc @@ -34,7 +34,10 @@ bool pkgArchiveCleaner::Go(std::string Dir,pkgCache &Cache) { bool CleanInstalled = _config->FindB("APT::Clean-Installed",true); - + + if(Dir == "/") + return _error->Error(_("Clean of %s is not supported"), Dir.c_str()); + DIR *D = opendir(Dir.c_str()); if (D == 0) return _error->Errno("opendir",_("Unable to read %s"),Dir.c_str()); diff --git a/apt-pkg/contrib/fileutl.cc b/apt-pkg/contrib/fileutl.cc index 188bb87e..1ba4674e 100644 --- a/apt-pkg/contrib/fileutl.cc +++ b/apt-pkg/contrib/fileutl.cc @@ -58,13 +58,10 @@ #include <bzlib.h> #endif #ifdef HAVE_LZMA - #include <stdint.h> #include <lzma.h> #endif - -#ifdef WORDS_BIGENDIAN -#include <inttypes.h> -#endif +#include <endian.h> +#include <stdint.h> #include <apti18n.h> /*}}}*/ @@ -958,10 +955,10 @@ class FileFdPrivate { /*{{{*/ // FileFd::Open - Open a file /*{{{*/ // --------------------------------------------------------------------- /* The most commonly used open mode combinations are given with Mode */ -bool FileFd::Open(string FileName,unsigned int const Mode,CompressMode Compress, unsigned long const Perms) +bool FileFd::Open(string FileName,unsigned int const Mode,CompressMode Compress, unsigned long const AccessMode) { if (Mode == ReadOnlyGzip) - return Open(FileName, ReadOnly, Gzip, Perms); + return Open(FileName, ReadOnly, Gzip, AccessMode); if (Compress == Auto && (Mode & WriteOnly) == WriteOnly) return FileFdError("Autodetection on %s only works in ReadOnly openmode!", FileName.c_str()); @@ -1028,9 +1025,9 @@ bool FileFd::Open(string FileName,unsigned int const Mode,CompressMode Compress, if (compressor == compressors.end()) return FileFdError("Can't find a match for specified compressor mode for file %s", FileName.c_str()); - return Open(FileName, Mode, *compressor, Perms); + return Open(FileName, Mode, *compressor, AccessMode); } -bool FileFd::Open(string FileName,unsigned int const Mode,APT::Configuration::Compressor const &compressor, unsigned long const Perms) +bool FileFd::Open(string FileName,unsigned int const Mode,APT::Configuration::Compressor const &compressor, unsigned long const AccessMode) { Close(); Flags = AutoClose; @@ -1080,11 +1077,18 @@ bool FileFd::Open(string FileName,unsigned int const Mode,APT::Configuration::Co TemporaryFileName = string(name); free(name); - if(Perms != 600 && fchmod(iFd, Perms) == -1) + // umask() will always set the umask and return the previous value, so + // we first set the umask and then reset it to the old value + mode_t const CurrentUmask = umask(0); + umask(CurrentUmask); + // calculate the actual file permissions (just like open/creat) + mode_t const FilePermissions = (AccessMode & ~CurrentUmask); + + if(fchmod(iFd, FilePermissions) == -1) return FileFdErrno("fchmod", "Could not change permissions for temporary file %s", TemporaryFileName.c_str()); } else - iFd = open(FileName.c_str(), fileflags, Perms); + iFd = open(FileName.c_str(), fileflags, AccessMode); this->FileName = FileName; if (iFd == -1 || OpenInternDescriptor(Mode, compressor) == false) @@ -1237,7 +1241,8 @@ bool FileFd::OpenInternDescriptor(unsigned int const Mode, APT::Configuration::C if (d->lzma == NULL) d->lzma = new FileFdPrivate::LZMAFILE; d->lzma->file = (FILE*) compress_struct; - d->lzma->stream = LZMA_STREAM_INIT; + lzma_stream tmp_stream = LZMA_STREAM_INIT; + d->lzma->stream = tmp_stream; if ((Mode & ReadWrite) == ReadWrite) return FileFdError("ReadWrite mode is not supported for file %s", FileName.c_str()); @@ -1353,7 +1358,10 @@ bool FileFd::OpenInternDescriptor(unsigned int const Mode, APT::Configuration::C Args.push_back(a->c_str()); if (Comp == false && FileName.empty() == false) { - Args.push_back("--stdout"); + // commands not needing arguments, do not need to be told about using standard output + // in reality, only testcases with tools like cat, rev, rot13, … are able to trigger this + if (compressor.CompressArgs.empty() == false && compressor.UncompressArgs.empty() == false) + Args.push_back("--stdout"); if (TemporaryFileName.empty() == false) Args.push_back(TemporaryFileName.c_str()); else @@ -1646,6 +1654,8 @@ bool FileFd::Write(int Fd, const void *From, unsigned long long Size) /* */ bool FileFd::Seek(unsigned long long To) { + Flags &= ~HitEof; + if (d != NULL && (d->pipe == true || d->InternalStream() == true)) { // Our poor man seeking in pipes is costly, so try to avoid it @@ -1705,7 +1715,6 @@ bool FileFd::Skip(unsigned long long Over) { if (d != NULL && (d->pipe == true || d->InternalStream() == true)) { - d->seekpos += Over; char buffer[1024]; while (Over != 0) { @@ -1789,7 +1798,8 @@ static bool StatFileFd(char const * const msg, int const iFd, std::string const // higher-level code will generate more meaningful messages, // even translated this would be meaningless for users return _error->Errno("fstat", "Unable to determine %s for fd %i", msg, iFd); - ispipe = S_ISFIFO(Buf.st_mode); + if (FileName.empty() == false) + ispipe = S_ISFIFO(Buf.st_mode); } // for compressor pipes st_size is undefined and at 'best' zero @@ -1869,19 +1879,13 @@ unsigned long long FileFd::Size() FileFdErrno("lseek","Unable to seek to end of gzipped file"); return 0; } - size = 0; + uint32_t size = 0; if (read(iFd, &size, 4) != 4) { FileFdErrno("read","Unable to read original size of gzipped file"); return 0; } - -#ifdef WORDS_BIGENDIAN - uint32_t tmp_size = size; - uint8_t const * const p = (uint8_t const * const) &tmp_size; - tmp_size = (p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]; - size = tmp_size; -#endif + size = le32toh(size); if (lseek(iFd, oldPos, SEEK_SET) < 0) { diff --git a/apt-pkg/contrib/fileutl.h b/apt-pkg/contrib/fileutl.h index f25ed362..cc1a98ea 100644 --- a/apt-pkg/contrib/fileutl.h +++ b/apt-pkg/contrib/fileutl.h @@ -103,10 +103,10 @@ class FileFd return T; } - bool Open(std::string FileName,unsigned int const Mode,CompressMode Compress,unsigned long const Perms = 0666); - bool Open(std::string FileName,unsigned int const Mode,APT::Configuration::Compressor const &compressor,unsigned long const Perms = 0666); - inline bool Open(std::string const &FileName,unsigned int const Mode, unsigned long const Perms = 0666) { - return Open(FileName, Mode, None, Perms); + bool Open(std::string FileName,unsigned int const Mode,CompressMode Compress,unsigned long const AccessMode = 0666); + bool Open(std::string FileName,unsigned int const Mode,APT::Configuration::Compressor const &compressor,unsigned long const AccessMode = 0666); + inline bool Open(std::string const &FileName,unsigned int const Mode, unsigned long const AccessMode = 0666) { + return Open(FileName, Mode, None, AccessMode); }; bool OpenDescriptor(int Fd, unsigned int const Mode, CompressMode Compress, bool AutoClose=false); bool OpenDescriptor(int Fd, unsigned int const Mode, APT::Configuration::Compressor const &compressor, bool AutoClose=false); @@ -129,13 +129,13 @@ class FileFd inline bool IsCompressed() {return (Flags & Compressed) == Compressed;}; inline std::string &Name() {return FileName;}; - FileFd(std::string FileName,unsigned int const Mode,unsigned long Perms = 0666) : iFd(-1), Flags(0), d(NULL) + FileFd(std::string FileName,unsigned int const Mode,unsigned long AccessMode = 0666) : iFd(-1), Flags(0), d(NULL) { - Open(FileName,Mode, None, Perms); + Open(FileName,Mode, None, AccessMode); }; - FileFd(std::string FileName,unsigned int const Mode, CompressMode Compress, unsigned long Perms = 0666) : iFd(-1), Flags(0), d(NULL) + FileFd(std::string FileName,unsigned int const Mode, CompressMode Compress, unsigned long AccessMode = 0666) : iFd(-1), Flags(0), d(NULL) { - Open(FileName,Mode, Compress, Perms); + Open(FileName,Mode, Compress, AccessMode); }; FileFd() : iFd(-1), Flags(AutoClose), d(NULL) {}; FileFd(int const Fd, unsigned int const Mode = ReadWrite, CompressMode Compress = None) : iFd(-1), Flags(0), d(NULL) diff --git a/apt-pkg/contrib/hashes.cc b/apt-pkg/contrib/hashes.cc index 1fce0d75..15f83615 100644 --- a/apt-pkg/contrib/hashes.cc +++ b/apt-pkg/contrib/hashes.cc @@ -133,7 +133,7 @@ bool Hashes::AddFD(int const Fd,unsigned long long Size, bool const addMD5, bool const addSHA1, bool const addSHA256, bool const addSHA512) { unsigned char Buf[64*64]; - bool const ToEOF = (Size == 0); + bool const ToEOF = (Size == UntilEOF); while (Size != 0 || ToEOF) { unsigned long long n = sizeof(Buf); diff --git a/apt-pkg/contrib/hashes.h b/apt-pkg/contrib/hashes.h index 5cd1af03..7a62f8a8 100644 --- a/apt-pkg/contrib/hashes.h +++ b/apt-pkg/contrib/hashes.h @@ -78,6 +78,8 @@ class Hashes SHA256Summation SHA256; SHA512Summation SHA512; + static const int UntilEOF = 0; + inline bool Add(const unsigned char *Data,unsigned long long Size) { return MD5.Add(Data,Size) && SHA1.Add(Data,Size) && SHA256.Add(Data,Size) && SHA512.Add(Data,Size); diff --git a/apt-pkg/contrib/strutl.cc b/apt-pkg/contrib/strutl.cc index 4c26fe07..698397a0 100644 --- a/apt-pkg/contrib/strutl.cc +++ b/apt-pkg/contrib/strutl.cc @@ -435,23 +435,30 @@ string TimeToStr(unsigned long Sec) /* This replaces all occurrences of Subst with Contents in Str. */ string SubstVar(const string &Str,const string &Subst,const string &Contents) { + if (Subst.empty() == true) + return Str; + string::size_type Pos = 0; string::size_type OldPos = 0; string Temp; - - while (OldPos < Str.length() && + + while (OldPos < Str.length() && (Pos = Str.find(Subst,OldPos)) != string::npos) { - Temp += string(Str,OldPos,Pos) + Contents; - OldPos = Pos + Subst.length(); + if (OldPos != Pos) + Temp.append(Str, OldPos, Pos - OldPos); + if (Contents.empty() == false) + Temp.append(Contents); + OldPos = Pos + Subst.length(); } - + if (OldPos == 0) return Str; - + + if (OldPos >= Str.length()) + return Temp; return Temp + string(Str,OldPos); } - string SubstVar(string Str,const struct SubstVar *Vars) { for (; Vars->Subst != 0; Vars++) @@ -698,9 +705,12 @@ string LookupTag(const string &Message,const char *Tag,const char *Default) then returns the result. Several varients on true/false are checked. */ int StringToBool(const string &Text,int Default) { - char *End; - int Res = strtol(Text.c_str(),&End,0); - if (End != Text.c_str() && Res >= 0 && Res <= 1) + char *ParseEnd; + int Res = strtol(Text.c_str(),&ParseEnd,0); + // ensure that the entire string was converted by strtol to avoid + // failures on "apt-cache show -a 0ad" where the "0" is converted + const char *TextEnd = Text.c_str()+Text.size(); + if (ParseEnd == TextEnd && Res >= 0 && Res <= 1) return Res; // Check for positives diff --git a/apt-pkg/deb/debindexfile.cc b/apt-pkg/deb/debindexfile.cc index eee758b7..a0dd15cd 100644 --- a/apt-pkg/deb/debindexfile.cc +++ b/apt-pkg/deb/debindexfile.cc @@ -525,7 +525,7 @@ bool debTranslationsIndex::Merge(pkgCacheGenerator &Gen,OpProgress *Prog) const if (FileExists(TranslationFile)) { FileFd Trans(TranslationFile,FileFd::ReadOnly, FileFd::Extension); - debListParser TransParser(&Trans); + debTranslationsParser TransParser(&Trans); if (_error->PendingError() == true) return false; diff --git a/apt-pkg/deb/deblistparser.cc b/apt-pkg/deb/deblistparser.cc index a1bcfb71..02b9cb23 100644 --- a/apt-pkg/deb/deblistparser.cc +++ b/apt-pkg/deb/deblistparser.cc @@ -145,7 +145,8 @@ unsigned char debListParser::ParseMultiArch(bool const showErrors) /*{{{*/ bool debListParser::NewVersion(pkgCache::VerIterator &Ver) { // Parse the section - Ver->Section = UniqFindTagWrite("Section"); + unsigned long const idxSection = UniqFindTagWrite("Section"); + Ver->Section = idxSection; Ver->MultiArch = ParseMultiArch(true); // Archive Size Ver->Size = Section.FindULL("Size"); @@ -260,7 +261,10 @@ bool debListParser::UsePackage(pkgCache::PkgIterator &Pkg, pkgCache::VerIterator &Ver) { if (Pkg->Section == 0) - Pkg->Section = UniqFindTagWrite("Section"); + { + unsigned long const idxSection = UniqFindTagWrite("Section"); + Pkg->Section = idxSection; + } string const static myArch = _config->Find("APT::Architecture"); // Possible values are: "all", "native", "installed" and "none" diff --git a/apt-pkg/deb/deblistparser.h b/apt-pkg/deb/deblistparser.h index baace79f..3b696321 100644 --- a/apt-pkg/deb/deblistparser.h +++ b/apt-pkg/deb/deblistparser.h @@ -106,4 +106,15 @@ class debListParser : public pkgCacheGenerator::ListParser APT_HIDDEN unsigned char ParseMultiArch(bool const showErrors); }; +class debTranslationsParser : public debListParser +{ + public: + // a translation can never be a real package + virtual std::string Architecture() { return ""; } + virtual std::string Version() { return ""; } + + debTranslationsParser(FileFd *File, std::string const &Arch = "") + : debListParser(File, Arch) {}; +}; + #endif diff --git a/apt-pkg/deb/debsrcrecords.cc b/apt-pkg/deb/debsrcrecords.cc index b09588dd..a444cbe4 100644 --- a/apt-pkg/deb/debsrcrecords.cc +++ b/apt-pkg/deb/debsrcrecords.cc @@ -186,6 +186,7 @@ bool debSrcRecordParser::Files(std::vector<pkgSrcRecords::File> &List) /* */ debSrcRecordParser::~debSrcRecordParser() { - delete[] Buffer; + // was allocated via strndup() + free(Buffer); } /*}}}*/ diff --git a/apt-pkg/deb/dpkgpm.cc b/apt-pkg/deb/dpkgpm.cc index aa58071f..a7f93e49 100644 --- a/apt-pkg/deb/dpkgpm.cc +++ b/apt-pkg/deb/dpkgpm.cc @@ -1067,14 +1067,15 @@ void pkgDPkgPM::StartPtyMagic() } // setup the pty and stuff - struct winsize win; + struct winsize win; - // if tcgetattr does not return zero there was a error - // and we do not do any pty magic + // if tcgetattr for both stdin/stdout returns 0 (no error) + // we do the pty magic _error->PushToStack(); - if (tcgetattr(STDOUT_FILENO, &d->tt) == 0) + if (tcgetattr(STDIN_FILENO, &d->tt) == 0 && + tcgetattr(STDOUT_FILENO, &d->tt) == 0) { - if (ioctl(1, TIOCGWINSZ, (char *)&win) < 0) + if (ioctl(STDOUT_FILENO, TIOCGWINSZ, (char *)&win) < 0) { _error->Errno("ioctl", _("ioctl(TIOCGWINSZ) failed")); } else if (openpty(&d->master, &d->slave, NULL, &d->tt, &win) < 0) @@ -1451,7 +1452,8 @@ bool pkgDPkgPM::GoNoABIBreak(APT::Progress::PackageManager *progress) if (_config->FindB("DPkg::FlushSTDIN",true) == true && isatty(STDIN_FILENO)) { - int Flags,dummy; + int Flags; + int dummy = 0; if ((Flags = fcntl(STDIN_FILENO,F_GETFL,dummy)) < 0) _exit(100); @@ -1631,7 +1633,7 @@ void pkgDPkgPM::WriteApportReport(const char *pkgpath, const char *errormsg) string::size_type pos; FILE *report; - if (_config->FindB("Dpkg::ApportFailureReport", false) == false) + if (_config->FindB("Dpkg::ApportFailureReport", true) == false) { std::clog << "configured to not write apport reports" << std::endl; return; diff --git a/apt-pkg/depcache.cc b/apt-pkg/depcache.cc index 19a6e0d7..c25672d1 100644 --- a/apt-pkg/depcache.cc +++ b/apt-pkg/depcache.cc @@ -1374,7 +1374,7 @@ bool pkgDepCache::IsInstallOkDependenciesSatisfiableByCandidates(PkgIterator con // the dependency is critical, but can't be installed, so discard the candidate // as the problemresolver will trip over it otherwise trying to install it (#735967) - if (Pkg->CurrentVer != 0) + if (Pkg->CurrentVer != 0 && (PkgState[Pkg->ID].iFlags & Protected) != Protected) SetCandidateVersion(Pkg.CurrentVer()); return false; } @@ -1678,7 +1678,7 @@ pkgCache::VerIterator pkgDepCache::Policy::GetCandidateVer(PkgIterator const &Pk { /* Not source/not automatic versions cannot be a candidate version unless they are already installed */ - VerIterator Last(*(pkgCache *)this,0); + VerIterator Last; for (VerIterator I = Pkg.VersionList(); I.end() == false; ++I) { diff --git a/apt-pkg/edsp.cc b/apt-pkg/edsp.cc index ee42267b..0d0418e0 100644 --- a/apt-pkg/edsp.cc +++ b/apt-pkg/edsp.cc @@ -18,6 +18,7 @@ #include <apt-pkg/pkgcache.h> #include <apt-pkg/cacheiterators.h> #include <apt-pkg/strutl.h> +#include <apt-pkg/pkgrecords.h> #include <ctype.h> #include <stddef.h> @@ -25,6 +26,7 @@ #include <time.h> #include <unistd.h> #include <stdio.h> +#include <algorithm> #include <iostream> #include <vector> #include <limits> @@ -49,7 +51,12 @@ bool EDSP::WriteScenario(pkgDepCache &Cache, FILE* output, OpProgress *Progress) if (Progress != NULL) Progress->SubProgress(Cache.Head().VersionCount, _("Send scenario to solver")); unsigned long p = 0; + std::vector<std::string> archs = APT::Configuration::getArchitectures(); for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; ++Pkg) + { + std::string const arch = Pkg.Arch(); + if (std::find(archs.begin(), archs.end(), arch) == archs.end()) + continue; for (pkgCache::VerIterator Ver = Pkg.VersionList(); Ver.end() == false; ++Ver, ++p) { WriteScenarioVersion(Cache, output, Pkg, Ver); @@ -58,6 +65,7 @@ bool EDSP::WriteScenario(pkgDepCache &Cache, FILE* output, OpProgress *Progress) if (Progress != NULL && p % 100 == 0) Progress->Progress(p); } + } return true; } /*}}}*/ @@ -87,7 +95,12 @@ bool EDSP::WriteLimitedScenario(pkgDepCache &Cache, FILE* output, void EDSP::WriteScenarioVersion(pkgDepCache &Cache, FILE* output, pkgCache::PkgIterator const &Pkg, pkgCache::VerIterator const &Ver) { + pkgRecords Recs(Cache); + pkgRecords::Parser &rec = Recs.Lookup(Ver.FileList()); + string srcpkg = rec.SourcePkg().empty() ? Pkg.Name() : rec.SourcePkg(); + fprintf(output, "Package: %s\n", Pkg.Name()); + fprintf(output, "Source: %s\n", srcpkg.c_str()); fprintf(output, "Architecture: %s\n", Ver.Arch()); fprintf(output, "Version: %s\n", Ver.VerStr()); if (Pkg.CurrentVer() == Ver) @@ -107,10 +120,22 @@ void EDSP::WriteScenarioVersion(pkgDepCache &Cache, FILE* output, pkgCache::PkgI else if ((Ver->MultiArch & pkgCache::Version::Same) == 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()); + std::set<string> Releases; + for (pkgCache::VerFileIterator I = Ver.FileList(); I.end() == false; ++I) { + pkgCache::PkgFileIterator File = I.File(); + signed short const p = Cache.GetPolicy().GetPriority(File); if (Pin < p) Pin = p; + if ((File->Flags & pkgCache::Flag::NotSource) != pkgCache::Flag::NotSource) { + string Release = File.RelStr(); + if (!Release.empty()) + Releases.insert(Release); + } + } + if (!Releases.empty()) { + fprintf(output, "APT-Release:\n"); + for (std::set<string>::iterator R = Releases.begin(); R != Releases.end(); ++R) + fprintf(output, " %s\n", R->c_str()); } fprintf(output, "APT-Pin: %d\n", Pin); if (Cache.GetCandidateVer(Pkg) == Ver) @@ -231,7 +256,16 @@ bool EDSP::WriteRequest(pkgDepCache &Cache, FILE* output, bool const Upgrade, continue; req->append(" ").append(Pkg.FullName()); } - fprintf(output, "Request: EDSP 0.4\n"); + fprintf(output, "Request: EDSP 0.5\n"); + + const char *arch = _config->Find("APT::Architecture").c_str(); + std::vector<string> archs = APT::Configuration::getArchitectures(); + fprintf(output, "Architecture: %s\n", arch); + fprintf(output, "Architectures:"); + for (std::vector<string>::const_iterator a = archs.begin(); a != archs.end(); ++a) + fprintf(output, " %s", a->c_str()); + fprintf(output, "\n"); + if (del.empty() == false) fprintf(output, "Remove: %s\n", del.c_str()+1); if (inst.empty() == false) @@ -411,6 +445,13 @@ bool EDSP::ReadRequest(int const input, std::list<std::string> &install, distUpgrade = EDSP::StringToBool(line.c_str() + 14, false); else if (line.compare(0, 11, "Autoremove:") == 0) autoRemove = EDSP::StringToBool(line.c_str() + 12, false); + else if (line.compare(0, 13, "Architecture:") == 0) + _config->Set("APT::Architecture", line.c_str() + 14); + else if (line.compare(0, 14, "Architectures:") == 0) + { + std::string const archs = line.c_str() + 15; + _config->Set("APT::Architectures", SubstVar(archs, " ", ",")); + } else _error->Warning("Unknown line in EDSP Request stanza: %s", line.c_str()); @@ -508,7 +549,7 @@ bool EDSP::WriteError(char const * const uuid, std::string const &message, FILE* } /*}}}*/ // EDSP::ExecuteSolver - fork requested solver and setup ipc pipes {{{*/ -bool EDSP::ExecuteSolver(const char* const solver, int *solver_in, int *solver_out) { +pid_t EDSP::ExecuteSolver(const char* const solver, int * const solver_in, int * const solver_out, bool) { std::vector<std::string> const solverDirs = _config->FindVector("Dir::Bin::Solvers"); std::string file; for (std::vector<std::string>::const_iterator dir = solverDirs.begin(); @@ -520,10 +561,16 @@ bool EDSP::ExecuteSolver(const char* const solver, int *solver_in, int *solver_o } if (file.empty() == true) - return _error->Error("Can't call external solver '%s' as it is not in a configured directory!", solver); + { + _error->Error("Can't call external solver '%s' as it is not in a configured directory!", solver); + return 0; + } 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"); + { + _error->Errno("Resolve", "Can't create needed IPC pipes for EDSP"); + return 0; + } for (int i = 0; i < 4; ++i) SetCloseExec(external[i], true); @@ -540,11 +587,19 @@ bool EDSP::ExecuteSolver(const char* const solver, int *solver_in, int *solver_o close(external[3]); if (WaitFd(external[1], true, 5) == false) - return _error->Errno("Resolve", "Timed out while Waiting on availability of solver stdin"); + { + _error->Errno("Resolve", "Timed out while Waiting on availability of solver stdin"); + return 0; + } *solver_in = external[1]; *solver_out = external[2]; - return true; + return Solver; +} +bool EDSP::ExecuteSolver(const char* const solver, int *solver_in, int *solver_out) { + if (ExecuteSolver(solver, solver_in, solver_out, true) == 0) + return false; + return true; } /*}}}*/ // EDSP::ResolveExternal - resolve problems by asking external for help {{{*/ @@ -552,7 +607,8 @@ 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) + pid_t const solver_pid = EDSP::ExecuteSolver(solver, &solver_in, &solver_out, true); + if (solver_pid == 0) return false; FILE* output = fdopen(solver_in, "w"); @@ -572,6 +628,6 @@ bool EDSP::ResolveExternal(const char* const solver, pkgDepCache &Cache, if (EDSP::ReadResponse(solver_out, Cache, Progress) == false) return false; - return true; + return ExecWait(solver_pid, solver); } /*}}}*/ diff --git a/apt-pkg/edsp.h b/apt-pkg/edsp.h index f3092d3c..9e833556 100644 --- a/apt-pkg/edsp.h +++ b/apt-pkg/edsp.h @@ -205,10 +205,10 @@ public: * \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 + * \return PID of the started solver or 0 if failure occurred */ - bool static ExecuteSolver(const char* const solver, int *solver_in, int *solver_out); + pid_t static ExecuteSolver(const char* const solver, int * const solver_in, int * const solver_out, bool /*overload*/); + APT_DEPRECATED bool static ExecuteSolver(const char* const solver, int *solver_in, int *solver_out); /** \brief call an external resolver to handle the request * diff --git a/apt-pkg/init.cc b/apt-pkg/init.cc index 1966e192..a3f7d95e 100644 --- a/apt-pkg/init.cc +++ b/apt-pkg/init.cc @@ -86,6 +86,7 @@ bool pkgInitConfig(Configuration &Cnf) Cnf.Set("Dir::Ignore-Files-Silently::", "\\.dpkg-[a-z]+$"); Cnf.Set("Dir::Ignore-Files-Silently::", "\\.save$"); Cnf.Set("Dir::Ignore-Files-Silently::", "\\.orig$"); + Cnf.Set("Dir::Ignore-Files-Silently::", "\\.distUpgrade$"); // Default cdrom mount point Cnf.CndSet("Acquire::cdrom::mount", "/media/cdrom/"); diff --git a/apt-pkg/install-progress.cc b/apt-pkg/install-progress.cc index 299dffa3..d328c934 100644 --- a/apt-pkg/install-progress.cc +++ b/apt-pkg/install-progress.cc @@ -261,14 +261,14 @@ PackageManagerFancy::TermSize PackageManagerFancy::GetTerminalSize() { struct winsize win; - PackageManagerFancy::TermSize s; + PackageManagerFancy::TermSize s = { 0, 0 }; // FIXME: get from "child_pty" instead? if(ioctl(STDOUT_FILENO, TIOCGWINSZ, (char *)&win) != 0) return s; if(_config->FindB("Debug::InstallProgress::Fancy", false) == true) - std::cerr << "GetTerminalSize: " << win.ws_row << std::endl; + std::cerr << "GetTerminalSize: " << win.ws_row << " x " << win.ws_col << std::endl; s.rows = win.ws_row; s.columns = win.ws_col; @@ -280,6 +280,9 @@ void PackageManagerFancy::SetupTerminalScrollArea(int nr_rows) if(_config->FindB("Debug::InstallProgress::Fancy", false) == true) std::cerr << "SetupTerminalScrollArea: " << nr_rows << std::endl; + if (unlikely(nr_rows <= 1)) + return; + // scroll down a bit to avoid visual glitch when the screen // area shrinks by one row std::cout << "\n"; @@ -301,28 +304,30 @@ void PackageManagerFancy::SetupTerminalScrollArea(int nr_rows) // setup tty size to ensure xterm/linux console are working properly too // see bug #731738 struct winsize win; - ioctl(child_pty, TIOCGWINSZ, (char *)&win); - win.ws_row = nr_rows - 1; - ioctl(child_pty, TIOCSWINSZ, (char *)&win); + if (ioctl(child_pty, TIOCGWINSZ, (char *)&win) != -1) + { + win.ws_row = nr_rows - 1; + ioctl(child_pty, TIOCSWINSZ, (char *)&win); + } } void PackageManagerFancy::HandleSIGWINCH(int) { - int nr_terminal_rows = GetTerminalSize().rows; + int const nr_terminal_rows = GetTerminalSize().rows; SetupTerminalScrollArea(nr_terminal_rows); + DrawStatusLine(); } void PackageManagerFancy::Start(int a_child_pty) { child_pty = a_child_pty; - int nr_terminal_rows = GetTerminalSize().rows; - if (nr_terminal_rows > 0) - SetupTerminalScrollArea(nr_terminal_rows); + int const nr_terminal_rows = GetTerminalSize().rows; + SetupTerminalScrollArea(nr_terminal_rows); } void PackageManagerFancy::Stop() { - int nr_terminal_rows = GetTerminalSize().rows; + int const nr_terminal_rows = GetTerminalSize().rows; if (nr_terminal_rows > 0) { SetupTerminalScrollArea(nr_terminal_rows + 1); @@ -363,7 +368,13 @@ bool PackageManagerFancy::StatusChanged(std::string PackageName, HumanReadableAction)) return false; - PackageManagerFancy::TermSize size = GetTerminalSize(); + return DrawStatusLine(); +} +bool PackageManagerFancy::DrawStatusLine() +{ + PackageManagerFancy::TermSize const size = GetTerminalSize(); + if (unlikely(size.rows < 1 || size.columns < 1)) + return false; static std::string save_cursor = "\033[s"; static std::string restore_cursor = "\033[u"; @@ -393,7 +404,7 @@ bool PackageManagerFancy::StatusChanged(std::string PackageName, { int padding = 4; float progressbar_size = size.columns - padding - progress_str.size(); - float current_percent = (float)StepsDone/(float)TotalSteps; + float current_percent = percentage / 100.0; std::cout << " " << GetTextProgressStr(current_percent, progressbar_size) << " "; diff --git a/apt-pkg/install-progress.h b/apt-pkg/install-progress.h index a6c213ac..a787242a 100644 --- a/apt-pkg/install-progress.h +++ b/apt-pkg/install-progress.h @@ -4,6 +4,7 @@ #ifdef HAVE_CONFIG_H # include <config.h> #endif +#include <apt-pkg/macros.h> #include <string> #include <unistd.h> @@ -124,6 +125,7 @@ namespace Progress { private: static void staticSIGWINCH(int); static std::vector<PackageManagerFancy*> instances; + APT_HIDDEN bool DrawStatusLine(); protected: void SetupTerminalScrollArea(int nr_rows); diff --git a/apt-pkg/packagemanager.cc b/apt-pkg/packagemanager.cc index 5d6bc6bd..249542c6 100644 --- a/apt-pkg/packagemanager.cc +++ b/apt-pkg/packagemanager.cc @@ -261,7 +261,7 @@ bool pkgPackageManager::CheckRConflicts(PkgIterator Pkg,DepIterator D, if (Cache.VS().CheckDep(Ver,D->CompareOp,D.TargetVer()) == false) continue; - if (EarlyRemove(D.ParentPkg()) == false) + if (EarlyRemove(D.ParentPkg(), &D) == false) return _error->Error("Reverse conflicts early remove for package '%s' failed", Pkg.FullName().c_str()); } @@ -313,18 +313,41 @@ bool pkgPackageManager::ConfigureAll() return true; } /*}}}*/ +// PM::NonLoopingSmart - helper to avoid loops while calling Smart methods /*{{{*/ +// ----------------------------------------------------------------------- +/* ensures that a loop of the form A depends B, B depends A (and similar) + is not leading us down into infinite recursion segfault land */ +bool pkgPackageManager::NonLoopingSmart(SmartAction const action, pkgCache::PkgIterator &Pkg, + pkgCache::PkgIterator DepPkg, int const Depth, bool const PkgLoop, + bool * const Bad, bool * const Changed) +{ + if (PkgLoop == false) + List->Flag(Pkg,pkgOrderList::Loop); + bool success = false; + switch(action) + { + case UNPACK_IMMEDIATE: success = SmartUnPack(DepPkg, true, Depth + 1); break; + case UNPACK: success = SmartUnPack(DepPkg, false, Depth + 1); break; + case CONFIGURE: success = SmartConfigure(DepPkg, Depth + 1); break; + } + if (PkgLoop == false) + List->RmFlag(Pkg,pkgOrderList::Loop); + + if (success == false) + return false; + + if (Bad != NULL) + *Bad = false; + if (Changed != NULL && List->IsFlag(DepPkg,pkgOrderList::Loop) == false) + *Changed = true; + return true; +} + /*}}}*/ // PM::SmartConfigure - Perform immediate configuration of the pkg /*{{{*/ // --------------------------------------------------------------------- /* This function tries to put the system in a state where Pkg can be configured. - This involves checking each of Pkg's dependanies and unpacking and - configuring packages where needed. - - Note on failure: This method can fail, without causing any problems. - This can happen when using Immediate-Configure-All, SmartUnPack may call - SmartConfigure, it may fail because of a complex dependency situation, but - a error will only be reported if ConfigureAll fails. This is why some of the - messages this function reports on failure (return false;) as just warnings - only shown when debuging*/ + This involves checking each of Pkg's dependencies and unpacking and + configuring packages where needed. */ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg, int const Depth) { // If this is true, only check and correct and dependencies without the Loop flag @@ -339,9 +362,9 @@ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg, int const Depth) } VerIterator const instVer = Cache[Pkg].InstVerIter(Cache); - - /* Because of the ordered list, most dependencies should be unpacked, - however if there is a loop (A depends on B, B depends on A) this will not + + /* Because of the ordered list, most dependencies should be unpacked, + however if there is a loop (A depends on B, B depends on A) this will not be the case, so check for dependencies before configuring. */ bool Bad = false, Changed = false; const unsigned int max_loops = _config->FindI("APT::pkgPackageManager::MaxLoopCount", 5000); @@ -349,6 +372,8 @@ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg, int const Depth) std::list<DepIterator> needConfigure; do { + // Check each dependency and see if anything needs to be done + // so that it can be configured Changed = false; for (DepIterator D = instVer.DependsList(); D.end() == false; ) { @@ -360,7 +385,8 @@ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg, int const Depth) continue; Bad = true; - // Check for dependencies that have not been unpacked, probably due to loops. + // the first pass checks if we its all good, i.e. if we have + // to do anything at all for (DepIterator Cur = Start; true; ++Cur) { SPtrArray<Version *> VList = Cur.AllTargets(); @@ -388,25 +414,58 @@ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg, int const Depth) if (Debug) std::clog << OutputInDepth(Depth) << "Package " << Pkg << " loops in SmartConfigure" << std::endl; Bad = false; - break; + } + } + + if (Cur == End || Bad == false) + break; + } + + // this dependency is in a good state, so we can stop + if (Bad == false) + { + if (Debug) + std::clog << OutputInDepth(Depth) << "Found ok dep " << D.TargetPkg() << std::endl; + continue; + } + + // Check for dependencies that have not been unpacked, + // probably due to loops. + for (DepIterator Cur = Start; true; ++Cur) + { + SPtrArray<Version *> VList = Cur.AllTargets(); + + for (Version **I = VList; *I != 0; ++I) + { + VerIterator Ver(Cache,*I); + PkgIterator DepPkg = Ver.ParentPkg(); + + // Check if the current version of the package is available and will satisfy this dependency + if (DepPkg.CurrentVer() == Ver && List->IsNow(DepPkg) == true && + List->IsFlag(DepPkg,pkgOrderList::Removed) == false && + DepPkg.State() == PkgIterator::NeedsNothing) + continue; + + // Check if the version that is going to be installed will satisfy the dependency + if (Cache[DepPkg].InstallVer != *I || List->IsNow(DepPkg) == false) + continue; + + if (PkgLoop == true) + { + if (Debug) + std::clog << OutputInDepth(Depth) << "Package " << Pkg << " loops in SmartConfigure" << std::endl; + Bad = false; } else { if (Debug) clog << OutputInDepth(Depth) << "Unpacking " << DepPkg.FullName() << " to avoid loop " << Cur << endl; - if (PkgLoop == false) - List->Flag(Pkg,pkgOrderList::Loop); - if (SmartUnPack(DepPkg, true, Depth + 1) == true) - { - Bad = false; - if (List->IsFlag(DepPkg,pkgOrderList::Loop) == false) - Changed = true; - } - if (PkgLoop == false) - List->RmFlag(Pkg,pkgOrderList::Loop); - if (Bad == false) - break; + if (NonLoopingSmart(UNPACK_IMMEDIATE, Pkg, DepPkg, Depth, PkgLoop, &Bad, &Changed) == false) + return false; } + // at this point we either unpacked a Dep or we are in a loop, + // no need to unpack a second one + break; } if (Cur == End || Bad == false) @@ -422,6 +481,7 @@ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg, int const Depth) return _error->Error("Internal error: MaxLoopCount reached in SmartUnPack (1) for %s, aborting", Pkg.FullName().c_str()); } while (Changed == true); + // now go over anything that needs configuring Bad = false, Changed = false, i = 0; do { @@ -461,25 +521,12 @@ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg, int const Depth) Bad = false; break; } - /* Check for a loop to prevent one forming - If A depends on B and B depends on A, SmartConfigure will - just hop between them if this is not checked. Dont remove the - loop flag after finishing however as loop is already set. - This means that there is another SmartConfigure call for this - package and it will remove the loop flag */ - if (PkgLoop == false) - List->Flag(Pkg,pkgOrderList::Loop); - if (SmartConfigure(DepPkg, Depth + 1) == true) - { - Bad = false; - if (List->IsFlag(DepPkg,pkgOrderList::Loop) == false) - Changed = true; - } - if (PkgLoop == false) - List->RmFlag(Pkg,pkgOrderList::Loop); - // If SmartConfigure was succesfull, Bad is false, so break - if (Bad == false) - break; + if (Debug) + std::clog << OutputInDepth(Depth) << "Configure already unpacked " << DepPkg << std::endl; + if (NonLoopingSmart(CONFIGURE, Pkg, DepPkg, Depth, PkgLoop, &Bad, &Changed) == false) + return false; + break; + } else if (List->IsFlag(DepPkg,pkgOrderList::Configured)) { @@ -498,19 +545,16 @@ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg, int const Depth) if (i++ > max_loops) return _error->Error("Internal error: MaxLoopCount reached in SmartUnPack (2) for %s, aborting", Pkg.FullName().c_str()); } while (Changed == true); - - if (Bad) { - if (Debug) - _error->Warning(_("Could not configure '%s'. "),Pkg.FullName().c_str()); - return false; - } - + + if (Bad == true) + return _error->Error(_("Could not configure '%s'. "),Pkg.FullName().c_str()); + if (PkgLoop) return true; static std::string const conf = _config->Find("PackageManager::Configure","all"); static bool const ConfigurePkgs = (conf == "all" || conf == "smart"); - if (List->IsFlag(Pkg,pkgOrderList::Configured)) + if (List->IsFlag(Pkg,pkgOrderList::Configured)) return _error->Error("Internal configure error on '%s'.", Pkg.FullName().c_str()); if (ConfigurePkgs == true && Configure(Pkg) == false) @@ -527,7 +571,8 @@ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg, int const Depth) Cache[P].InstallVer == 0 || (P.CurrentVer() == Cache[P].InstallVer && (Cache[Pkg].iFlags & pkgDepCache::ReInstall) != pkgDepCache::ReInstall)) continue; - SmartConfigure(P, (Depth +1)); + if (SmartConfigure(P, (Depth +1)) == false) + return false; } // Sanity Check @@ -542,28 +587,36 @@ bool pkgPackageManager::SmartConfigure(PkgIterator Pkg, int const Depth) /* This is called to deal with conflicts arising from unpacking */ bool pkgPackageManager::EarlyRemove(PkgIterator Pkg) { + return EarlyRemove(Pkg, NULL); +} +bool pkgPackageManager::EarlyRemove(PkgIterator Pkg, DepIterator const * const Dep) +{ if (List->IsNow(Pkg) == false) return true; - + // Already removed it if (List->IsFlag(Pkg,pkgOrderList::Removed) == true) return true; - + // Woops, it will not be re-installed! if (List->IsFlag(Pkg,pkgOrderList::InList) == false) return false; + // these breaks on M-A:same packages can be dealt with. They 'loop' by design + if (Dep != NULL && (*Dep)->Type == pkgCache::Dep::DpkgBreaks && Dep->IsMultiArchImplicit() == true) + return true; + // Essential packages get special treatment bool IsEssential = false; if ((Pkg->Flags & pkgCache::Flag::Essential) != 0 || (Pkg->Flags & pkgCache::Flag::Important) != 0) IsEssential = true; - /* Check for packages that are the dependents of essential packages and + /* Check for packages that are the dependents of essential packages and promote them too */ if (Pkg->CurrentVer != 0) { - for (DepIterator D = Pkg.RevDependsList(); D.end() == false && + for (pkgCache::DepIterator D = Pkg.RevDependsList(); D.end() == false && IsEssential == false; ++D) if (D->Type == pkgCache::Dep::Depends || D->Type == pkgCache::Dep::PreDepends) if ((D.ParentPkg()->Flags & pkgCache::Flag::Essential) != 0 || @@ -580,11 +633,14 @@ bool pkgPackageManager::EarlyRemove(PkgIterator Pkg) "but if you really want to do it, activate the " "APT::Force-LoopBreak option."),Pkg.FullName().c_str()); } - + // dpkg will auto-deconfigure it, no need for the big remove hammer + else if (Dep != NULL && (*Dep)->Type == pkgCache::Dep::DpkgBreaks) + return true; + bool Res = SmartRemove(Pkg); if (Cache[Pkg].Delete() == false) List->Flag(Pkg,pkgOrderList::Removed,pkgOrderList::States); - + return Res; } /*}}}*/ @@ -629,13 +685,14 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg, bool const Immediate, int c VerIterator const instVer = Cache[Pkg].InstVerIter(Cache); - /* PreUnpack Checks: This loop checks and attempts to rectify and problems that would prevent the package being unpacked. + /* PreUnpack Checks: This loop checks and attempts to rectify any problems that would prevent the package being unpacked. It addresses: PreDepends, Conflicts, Obsoletes and Breaks (DpkgBreaks). Any resolutions that do not require it should avoid configuration (calling SmartUnpack with Immediate=true), this is because when unpacking some packages with - complex dependency structures, trying to configure some packages while breaking the loops can complicate things . + complex dependency structures, trying to configure some packages while breaking the loops can complicate things. This will be either dealt with if the package is configured as a dependency of Pkg (if and when Pkg is configured), or by the ConfigureAll call at the end of the for loop in OrderInstall. */ - bool Changed = false; + bool SomethingBad = false, Changed = false; + bool couldBeTemporaryRemoved = Depth != 0 && List->IsFlag(Pkg,pkgOrderList::Removed) == false; const unsigned int max_loops = _config->FindI("APT::pkgPackageManager::MaxLoopCount", 5000); unsigned int i = 0; do @@ -683,184 +740,142 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg, bool const Immediate, int c for (Version **I = VList; *I != 0; ++I) { VerIterator Ver(Cache,*I); - PkgIterator Pkg = Ver.ParentPkg(); + PkgIterator DepPkg = Ver.ParentPkg(); // Not the install version - if (Cache[Pkg].InstallVer != *I || - (Cache[Pkg].Keep() == true && Pkg.State() == PkgIterator::NeedsNothing)) + if (Cache[DepPkg].InstallVer != *I || + (Cache[DepPkg].Keep() == true && DepPkg.State() == PkgIterator::NeedsNothing)) continue; - if (List->IsFlag(Pkg,pkgOrderList::Configured)) + if (List->IsFlag(DepPkg,pkgOrderList::Configured)) { Bad = false; break; } // check if it needs unpack or if if configure is enough - if (List->IsFlag(Pkg,pkgOrderList::UnPacked) == false) + if (List->IsFlag(DepPkg,pkgOrderList::UnPacked) == false) { if (Debug) - clog << OutputInDepth(Depth) << "Trying to SmartUnpack " << Pkg.FullName() << endl; - // SmartUnpack with the ImmediateFlag to ensure its really ready - if (SmartUnPack(Pkg, true, Depth + 1) == true) - { - Bad = false; - if (List->IsFlag(Pkg,pkgOrderList::Loop) == false) - Changed = true; - break; - } + clog << OutputInDepth(Depth) << "Trying to SmartUnpack " << DepPkg.FullName() << endl; + if (NonLoopingSmart(UNPACK_IMMEDIATE, Pkg, DepPkg, Depth, PkgLoop, &Bad, &Changed) == false) + return false; } else { if (Debug) - clog << OutputInDepth(Depth) << "Trying to SmartConfigure " << Pkg.FullName() << endl; - if (SmartConfigure(Pkg, Depth + 1) == true) - { - Bad = false; - if (List->IsFlag(Pkg,pkgOrderList::Loop) == false) - Changed = true; - break; - } + clog << OutputInDepth(Depth) << "Trying to SmartConfigure " << DepPkg.FullName() << endl; + if (NonLoopingSmart(CONFIGURE, Pkg, DepPkg, Depth, PkgLoop, &Bad, &Changed) == false) + return false; } + break; } } if (Bad == true) - { - if (Start == End) - return _error->Error("Couldn't configure pre-depend %s for %s, " - "probably a dependency cycle.", - End.TargetPkg().FullName().c_str(),Pkg.FullName().c_str()); - } - else - continue; + SomethingBad = true; } else if (End->Type == pkgCache::Dep::Conflicts || - End->Type == pkgCache::Dep::Obsoletes) + End->Type == pkgCache::Dep::Obsoletes || + End->Type == pkgCache::Dep::DpkgBreaks) { - /* Look for conflicts. Two packages that are both in the install - state cannot conflict so we don't check.. */ SPtrArray<Version *> VList = End.AllTargets(); - for (Version **I = VList; *I != 0; I++) + for (Version **I = VList; *I != 0; ++I) { VerIterator Ver(Cache,*I); PkgIterator ConflictPkg = Ver.ParentPkg(); - VerIterator InstallVer(Cache,Cache[ConflictPkg].InstallVer); + if (ConflictPkg.CurrentVer() != Ver) + { + if (Debug) + std::clog << OutputInDepth(Depth) << "Ignore not-installed version " << Ver.VerStr() << " of " << ConflictPkg.FullName() << " for " << End << std::endl; + continue; + } - // See if the current version is conflicting - if (ConflictPkg.CurrentVer() == Ver && List->IsNow(ConflictPkg)) + if (List->IsNow(ConflictPkg) == false) { if (Debug) - clog << OutputInDepth(Depth) << Pkg.FullName() << " conflicts with " << ConflictPkg.FullName() << endl; - /* If a loop is not present or has not yet been detected, attempt to unpack packages - to resolve this conflict. If there is a loop present, remove packages to resolve this conflict */ - if (List->IsFlag(ConflictPkg,pkgOrderList::Loop) == false) - { - if (Cache[ConflictPkg].Keep() == 0 && Cache[ConflictPkg].InstallVer != 0) - { - if (Debug) - clog << OutputInDepth(Depth) << OutputInDepth(Depth) << "Unpacking " << ConflictPkg.FullName() << " to prevent conflict" << endl; - List->Flag(Pkg,pkgOrderList::Loop); - if (SmartUnPack(ConflictPkg,false, Depth + 1) == true) - if (List->IsFlag(ConflictPkg,pkgOrderList::Loop) == false) - Changed = true; - // Remove loop to allow it to be used later if needed - List->RmFlag(Pkg,pkgOrderList::Loop); - } - else if (EarlyRemove(ConflictPkg) == false) - return _error->Error("Internal Error, Could not early remove %s (1)",ConflictPkg.FullName().c_str()); - } - else if (List->IsFlag(ConflictPkg,pkgOrderList::Removed) == false) + std::clog << OutputInDepth(Depth) << "Ignore already dealt-with version " << Ver.VerStr() << " of " << ConflictPkg.FullName() << " for " << End << std::endl; + continue; + } + + if (List->IsFlag(ConflictPkg,pkgOrderList::Removed) == true) + { + if (Debug) + clog << OutputInDepth(Depth) << "Ignoring " << End << " as " << ConflictPkg.FullName() << "was temporarily removed" << endl; + continue; + } + + if (List->IsFlag(ConflictPkg,pkgOrderList::Loop) && PkgLoop) + { + if (End->Type == pkgCache::Dep::DpkgBreaks && End.IsMultiArchImplicit() == true) { if (Debug) - clog << OutputInDepth(Depth) << "Because of conficts knot, removing " << ConflictPkg.FullName() << " to conflict violation" << endl; - if (EarlyRemove(ConflictPkg) == false) - return _error->Error("Internal Error, Could not early remove %s (2)",ConflictPkg.FullName().c_str()); + clog << OutputInDepth(Depth) << "Because dependency is MultiArchImplicit we ignored looping on: " << ConflictPkg << endl; + continue; } - } - } - } - else if (End->Type == pkgCache::Dep::DpkgBreaks) - { - SPtrArray<Version *> VList = End.AllTargets(); - for (Version **I = VList; *I != 0; ++I) - { - VerIterator Ver(Cache,*I); - PkgIterator BrokenPkg = Ver.ParentPkg(); - if (BrokenPkg.CurrentVer() != Ver) - { if (Debug) - std::clog << OutputInDepth(Depth) << " Ignore not-installed version " << Ver.VerStr() << " of " << Pkg.FullName() << " for " << End << std::endl; + { + if (End->Type == pkgCache::Dep::DpkgBreaks) + clog << OutputInDepth(Depth) << "Because of breaks knot, deconfigure " << ConflictPkg.FullName() << " temporarily" << endl; + else + clog << OutputInDepth(Depth) << "Because of conflict knot, removing " << ConflictPkg.FullName() << " temporarily" << endl; + } + if (EarlyRemove(ConflictPkg, &End) == false) + return _error->Error("Internal Error, Could not early remove %s (2)",ConflictPkg.FullName().c_str()); + SomethingBad = true; continue; } - // Check if it needs to be unpacked - if (List->IsFlag(BrokenPkg,pkgOrderList::InList) && Cache[BrokenPkg].Delete() == false && - List->IsNow(BrokenPkg)) + if (Cache[ConflictPkg].Delete() == false) { - if (List->IsFlag(BrokenPkg,pkgOrderList::Loop) && PkgLoop) + if (Debug) { - // This dependency has already been dealt with by another SmartUnPack on Pkg - break; + clog << OutputInDepth(Depth) << "Unpacking " << ConflictPkg.FullName() << " to avoid " << End; + if (PkgLoop == true) + clog << " (Looping)"; + clog << std::endl; } - else + // we would like to avoid temporary removals and all that at best via a simple unpack + _error->PushToStack(); + if (NonLoopingSmart(UNPACK, Pkg, ConflictPkg, Depth, PkgLoop, NULL, &Changed) == false) { - // Found a break, so see if we can unpack the package to avoid it - // but do not set loop if another SmartUnPack already deals with it - // Also, avoid it if the package we would unpack pre-depends on this one - VerIterator InstallVer(Cache,Cache[BrokenPkg].InstallVer); - bool circle = false; - for (pkgCache::DepIterator D = InstallVer.DependsList(); D.end() == false; ++D) + // but if it fails ignore this failure and look for alternative ways of solving + if (Debug) { - if (D->Type != pkgCache::Dep::PreDepends) - continue; - SPtrArray<Version *> VL = D.AllTargets(); - for (Version **I = VL; *I != 0; ++I) - { - VerIterator V(Cache,*I); - PkgIterator P = V.ParentPkg(); - // we are checking for installation as an easy 'protection' against or-groups and (unchosen) providers - if (P != Pkg || (P.CurrentVer() != V && Cache[P].InstallVer != V)) - continue; - circle = true; - break; - } - if (circle == true) - break; + clog << OutputInDepth(Depth) << "Avoidance unpack of " << ConflictPkg.FullName() << " failed for " << End << std::endl; + _error->DumpErrors(std::clog); } - if (circle == true) + _error->RevertToStack(); + // ignorance can only happen if a) one of the offenders is already gone + if (List->IsFlag(ConflictPkg,pkgOrderList::Removed) == true) { if (Debug) - clog << OutputInDepth(Depth) << " Avoiding " << End << " avoided as " << BrokenPkg.FullName() << " has a pre-depends on " << Pkg.FullName() << std::endl; - continue; + clog << OutputInDepth(Depth) << "But " << ConflictPkg.FullName() << " was temporarily removed in the meantime to satisfy " << End << endl; } + else if (List->IsFlag(Pkg,pkgOrderList::Removed) == true) + { + if (Debug) + clog << OutputInDepth(Depth) << "But " << Pkg.FullName() << " was temporarily removed in the meantime to satisfy " << End << endl; + } + // or b) we can make one go (removal or dpkg auto-deconfigure) else { if (Debug) - { - clog << OutputInDepth(Depth) << " Unpacking " << BrokenPkg.FullName() << " to avoid " << End; - if (PkgLoop == true) - clog << " (Looping)"; - clog << std::endl; - } - if (PkgLoop == false) - List->Flag(Pkg,pkgOrderList::Loop); - if (SmartUnPack(BrokenPkg, false, Depth + 1) == true) - { - if (List->IsFlag(BrokenPkg,pkgOrderList::Loop) == false) - Changed = true; - } - if (PkgLoop == false) - List->RmFlag(Pkg,pkgOrderList::Loop); + clog << OutputInDepth(Depth) << "So temprorary remove/deconfigure " << ConflictPkg.FullName() << " to satisfy " << End << endl; + if (EarlyRemove(ConflictPkg, &End) == false) + return _error->Error("Internal Error, Could not early remove %s (2)",ConflictPkg.FullName().c_str()); } } + else + _error->MergeWithStack(); } - // Check if a package needs to be removed - else if (Cache[BrokenPkg].Delete() == true && List->IsFlag(BrokenPkg,pkgOrderList::Configured) == false) + else { if (Debug) - clog << OutputInDepth(Depth) << " Removing " << BrokenPkg.FullName() << " to avoid " << End << endl; - SmartRemove(BrokenPkg); + clog << OutputInDepth(Depth) << "Removing " << ConflictPkg.FullName() << " now to avoid " << End << endl; + // no earlyremove() here as user has already agreed to the permanent removal + if (SmartRemove(Pkg) == false) + return _error->Error("Internal Error, Could not early remove %s (1)",ConflictPkg.FullName().c_str()); } } } @@ -868,7 +883,17 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg, bool const Immediate, int c if (i++ > max_loops) return _error->Error("Internal error: APT::pkgPackageManager::MaxLoopCount reached in SmartConfigure for %s, aborting", Pkg.FullName().c_str()); } while (Changed == true); - + + if (SomethingBad == true) + return _error->Error("Couldn't configure %s, probably a dependency cycle.", Pkg.FullName().c_str()); + + if (couldBeTemporaryRemoved == true && List->IsFlag(Pkg,pkgOrderList::Removed) == true) + { + if (Debug) + std::clog << OutputInDepth(Depth) << "Prevent unpack as " << Pkg << " is currently temporarily removed" << std::endl; + return true; + } + // Check for reverse conflicts. if (CheckRConflicts(Pkg,Pkg.RevDependsList(), instVer.VerStr()) == false) @@ -929,7 +954,7 @@ bool pkgPackageManager::SmartUnPack(PkgIterator Pkg, bool const Immediate, int c if (Immediate == true) { // Perform immedate configuration of the package. if (SmartConfigure(Pkg, Depth + 1) == false) - _error->Warning(_("Could not perform immediate configuration on '%s'. " + _error->Error(_("Could not perform immediate configuration on '%s'. " "Please see man 5 apt.conf under APT::Immediate-Configure for details. (%d)"),Pkg.FullName().c_str(),2); } diff --git a/apt-pkg/packagemanager.h b/apt-pkg/packagemanager.h index 344ed919..d72790b6 100644 --- a/apt-pkg/packagemanager.h +++ b/apt-pkg/packagemanager.h @@ -79,13 +79,14 @@ class pkgPackageManager : protected pkgCache::Namespace // Install helpers bool ConfigureAll(); - bool SmartConfigure(PkgIterator Pkg, int const Depth); + bool SmartConfigure(PkgIterator Pkg, int const Depth) APT_MUSTCHECK; //FIXME: merge on abi break - bool SmartUnPack(PkgIterator Pkg); - bool SmartUnPack(PkgIterator Pkg, bool const Immediate, int const Depth); - bool SmartRemove(PkgIterator Pkg); - bool EarlyRemove(PkgIterator Pkg); - + bool SmartUnPack(PkgIterator Pkg) APT_MUSTCHECK; + bool SmartUnPack(PkgIterator Pkg, bool const Immediate, int const Depth) APT_MUSTCHECK; + bool SmartRemove(PkgIterator Pkg) APT_MUSTCHECK; + bool EarlyRemove(PkgIterator Pkg, DepIterator const * const Dep) APT_MUSTCHECK; + APT_DEPRECATED bool EarlyRemove(PkgIterator Pkg) APT_MUSTCHECK; + // The Actual installation implementation virtual bool Install(PkgIterator /*Pkg*/,std::string /*File*/) {return false;}; virtual bool Configure(PkgIterator /*Pkg*/) {return false;}; @@ -139,6 +140,12 @@ class pkgPackageManager : protected pkgCache::Namespace pkgPackageManager(pkgDepCache *Cache); virtual ~pkgPackageManager(); + + private: + enum APT_HIDDEN SmartAction { UNPACK_IMMEDIATE, UNPACK, CONFIGURE }; + APT_HIDDEN bool NonLoopingSmart(SmartAction const action, pkgCache::PkgIterator &Pkg, + pkgCache::PkgIterator DepPkg, int const Depth, bool const PkgLoop, + bool * const Bad, bool * const Changed) APT_MUSTCHECK; }; #endif diff --git a/apt-pkg/pkgcache.cc b/apt-pkg/pkgcache.cc index 91b75f52..58a63459 100644 --- a/apt-pkg/pkgcache.cc +++ b/apt-pkg/pkgcache.cc @@ -822,7 +822,7 @@ int pkgCache::VerIterator::CompareVer(const VerIterator &B) const // VerIterator::Downloadable - Checks if the version is downloadable /*{{{*/ // --------------------------------------------------------------------- /* */ -bool pkgCache::VerIterator::Downloadable() const +APT_PURE bool pkgCache::VerIterator::Downloadable() const { VerFileIterator Files = FileList(); for (; Files.end() == false; ++Files) @@ -835,7 +835,7 @@ bool pkgCache::VerIterator::Downloadable() const // --------------------------------------------------------------------- /* This checks to see if any of the versions files are not NotAutomatic. True if this version is selectable for automatic installation. */ -bool pkgCache::VerIterator::Automatic() const +APT_PURE bool pkgCache::VerIterator::Automatic() const { VerFileIterator Files = FileList(); for (; Files.end() == false; ++Files) diff --git a/apt-pkg/srcrecords.cc b/apt-pkg/srcrecords.cc index 775cf2e5..81b1c545 100644 --- a/apt-pkg/srcrecords.cc +++ b/apt-pkg/srcrecords.cc @@ -81,6 +81,27 @@ bool pkgSrcRecords::Restart() return true; } /*}}}*/ +// SrcRecords::Step - Step to the next Source Record /*{{{*/ +// --------------------------------------------------------------------- +/* Step to the next source package record */ +const pkgSrcRecords::Parser* pkgSrcRecords::Step() +{ + if (Current == Files.end()) + return 0; + + // Step to the next record, possibly switching files + while ((*Current)->Step() == false) + { + if (_error->PendingError() == true) + return 0; + ++Current; + if (Current == Files.end()) + return 0; + } + + return *Current; +} + /*}}}*/ // SrcRecords::Find - Find the first source package with the given name /*{{{*/ // --------------------------------------------------------------------- /* This searches on both source package names and output binary names and @@ -88,21 +109,11 @@ bool pkgSrcRecords::Restart() function to be called multiple times to get successive entries */ pkgSrcRecords::Parser *pkgSrcRecords::Find(const char *Package,bool const &SrcOnly) { - if (Current == Files.end()) - return 0; - while (true) { - // Step to the next record, possibly switching files - while ((*Current)->Step() == false) - { - if (_error->PendingError() == true) - return 0; - ++Current; - if (Current == Files.end()) - return 0; - } - + if(Step() == 0) + return 0; + // IO error somehow if (_error->PendingError() == true) return 0; diff --git a/apt-pkg/srcrecords.h b/apt-pkg/srcrecords.h index 9915debf..e000e176 100644 --- a/apt-pkg/srcrecords.h +++ b/apt-pkg/srcrecords.h @@ -95,8 +95,13 @@ class pkgSrcRecords // Reset the search bool Restart(); - // Locate a package by name - Parser *Find(const char *Package,bool const &SrcOnly = false); + // Step to the next SourcePackage and return pointer to the + // next SourceRecord. The pointer is owned by libapt. + const Parser* Step(); + + // Locate a package by name and return pointer to the Parser. + // The pointer is owned by libapt. + Parser* Find(const char *Package,bool const &SrcOnly = false); pkgSrcRecords(pkgSourceList &List); virtual ~pkgSrcRecords(); diff --git a/apt-pkg/upgrade.cc b/apt-pkg/upgrade.cc index 7926845c..29b11937 100644 --- a/apt-pkg/upgrade.cc +++ b/apt-pkg/upgrade.cc @@ -143,6 +143,12 @@ static bool pkgAllUpgradeNoNewPackages(pkgDepCache &Cache) */ static bool pkgAllUpgradeWithNewPackages(pkgDepCache &Cache) { + std::string const solver = _config->Find("APT::Solver", "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); |