From c919ad6e4d0de48acb60f2a1371ade9bfb0451f8 Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Sun, 9 Sep 2012 16:03:52 +0200 Subject: =?UTF-8?q?handle=20packages=20without=20a=20mandatory=20architect?= =?UTF-8?q?ure=20(debian-policy=20=C2=A75.3)=20by=20introducing=20a=20pseu?= =?UTF-8?q?do-architecture=20'none'=20so=20that=20the=20small=20group=20of?= =?UTF-8?q?=20users=20with=20these=20packages=20can=20get=20right=20of=20t?= =?UTF-8?q?hem=20without=20introducing=20too=20much=20hassle=20for=20other?= =?UTF-8?q?=20users=20(Closes:=20#686346)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apt-pkg/algorithms.cc | 5 +++++ apt-pkg/deb/deblistparser.cc | 22 ++++++++++++++---- apt-pkg/deb/dpkgpm.cc | 8 +++++-- apt-pkg/pkgcache.cc | 6 ++++- apt-pkg/pkgcachegen.cc | 53 +++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 86 insertions(+), 8 deletions(-) (limited to 'apt-pkg') diff --git a/apt-pkg/algorithms.cc b/apt-pkg/algorithms.cc index 2f5fcc7ab..1b0161ffd 100644 --- a/apt-pkg/algorithms.cc +++ b/apt-pkg/algorithms.cc @@ -194,6 +194,11 @@ bool pkgSimulate::Remove(PkgIterator iPkg,bool Purge) { // Adapt the iterator PkgIterator Pkg = Sim.FindPkg(iPkg.Name(), iPkg.Arch()); + if (Pkg.end() == true) + { + std::cerr << (Purge ? "Purg" : "Remv") << " invalid package " << iPkg.FullName() << std::endl; + return false; + } Flags[Pkg->ID] = 3; Sim.MarkDelete(Pkg); diff --git a/apt-pkg/deb/deblistparser.cc b/apt-pkg/deb/deblistparser.cc index 12c6ab4c9..b84bd6fdd 100644 --- a/apt-pkg/deb/deblistparser.cc +++ b/apt-pkg/deb/deblistparser.cc @@ -645,6 +645,8 @@ bool debListParser::ParseDepends(pkgCache::VerIterator &Ver, a != Architectures.end(); ++a) if (NewDepends(Ver,Package,*a,Version,Op,Type) == false) return false; + if (NewDepends(Ver,Package,"none",Version,Op,Type) == false) + return false; } else if (MultiArchEnabled == true && found != string::npos && strcmp(Package.c_str() + found, ":any") != 0) @@ -658,8 +660,18 @@ bool debListParser::ParseDepends(pkgCache::VerIterator &Ver, if (NewDepends(Ver,Package,Arch,Version,Op,Type) == false) return false; } - else if (NewDepends(Ver,Package,pkgArch,Version,Op,Type) == false) - return false; + else + { + if (NewDepends(Ver,Package,pkgArch,Version,Op,Type) == false) + return false; + if ((Type == pkgCache::Dep::Conflicts || + Type == pkgCache::Dep::DpkgBreaks || + Type == pkgCache::Dep::Replaces) && + NewDepends(Ver, Package, + (pkgArch != "none") ? "none" : _config->Find("APT::Architecture"), + Version,Op,Type) == false) + return false; + } if (Start == Stop) break; } @@ -753,13 +765,15 @@ bool debListParser::Step() drop the whole section. A missing arch tag only happens (in theory) inside the Status file, so that is a positive return */ string const Architecture = Section.FindS("Architecture"); - if (Architecture.empty() == true) - return true; if (Arch.empty() == true || Arch == "any" || MultiArchEnabled == false) { if (APT::Configuration::checkArchitecture(Architecture) == true) return true; + /* parse version stanzas without an architecture only in the status file + (and as misfortune bycatch flat-archives) */ + if ((Arch.empty() == true || Arch == "any") && Architecture.empty() == true) + return true; } else { diff --git a/apt-pkg/deb/dpkgpm.cc b/apt-pkg/deb/dpkgpm.cc index ae9143e0d..c9df41d3a 100644 --- a/apt-pkg/deb/dpkgpm.cc +++ b/apt-pkg/deb/dpkgpm.cc @@ -1131,7 +1131,9 @@ bool pkgDPkgPM::Go(int OutStatusFd) if (I->Op == Item::Configure && disappearedPkgs.find(I->Pkg.Name()) != disappearedPkgs.end()) continue; // We keep this here to allow "smooth" transitions from e.g. multiarch dpkg/ubuntu to dpkg/debian - if (dpkgMultiArch == false && (I->Pkg.Arch() == nativeArch || !strcmp(I->Pkg.Arch(), "all"))) + if (dpkgMultiArch == false && (I->Pkg.Arch() == nativeArch || + strcmp(I->Pkg.Arch(), "all") == 0 || + strcmp(I->Pkg.Arch(), "none") == 0)) { char const * const name = I->Pkg.Name(); ADDARG(name); @@ -1148,7 +1150,9 @@ bool pkgDPkgPM::Go(int OutStatusFd) } else PkgVer = Cache[I->Pkg].InstVerIter(Cache); - if (PkgVer.end() == false) + if (strcmp(I->Pkg.Arch(), "none") == 0) + ; // never arch-qualify a package without an arch + else if (PkgVer.end() == false) name.append(":").append(PkgVer.Arch()); else _error->Warning("Can not find PkgVer for '%s'", name.c_str()); diff --git a/apt-pkg/pkgcache.cc b/apt-pkg/pkgcache.cc index 9acb7da72..353172d8a 100644 --- a/apt-pkg/pkgcache.cc +++ b/apt-pkg/pkgcache.cc @@ -238,7 +238,7 @@ pkgCache::PkgIterator pkgCache::FindPkg(const string &Name) { // --------------------------------------------------------------------- /* Returns 0 on error, pointer to the package otherwise */ pkgCache::PkgIterator pkgCache::FindPkg(const string &Name, string const &Arch) { - if (MultiArchCache() == false) { + if (MultiArchCache() == false && Arch != "none") { if (Arch == "native" || Arch == "all" || Arch == "any" || Arch == NativeArch()) return SingleArchFindPkg(Name); @@ -376,6 +376,10 @@ pkgCache::PkgIterator pkgCache::GrpIterator::FindPreferredPkg(bool const &Prefer if (Pkg.end() == false && (PreferNonVirtual == false || Pkg->VersionList != 0)) return Pkg; } + // packages without an architecture + Pkg = FindPkg("none"); + if (Pkg.end() == false && (PreferNonVirtual == false || Pkg->VersionList != 0)) + return Pkg; if (PreferNonVirtual == true) return FindPreferredPkg(false); diff --git a/apt-pkg/pkgcachegen.cc b/apt-pkg/pkgcachegen.cc index f70cbd02a..490c2ecbb 100644 --- a/apt-pkg/pkgcachegen.cc +++ b/apt-pkg/pkgcachegen.cc @@ -200,7 +200,19 @@ bool pkgCacheGenerator::MergeList(ListParser &List, } if (Arch.empty() == true) - Arch = _config->Find("APT::Architecture"); + { + // use the pseudo arch 'none' for arch-less packages + Arch = "none"; + /* We might built a SingleArchCache here, which we don't want to blow up + just for these :none packages to a proper MultiArchCache, so just ensure + that we have always a native package structure first for SingleArch */ + pkgCache::PkgIterator NP; + if (NewPackage(NP, PackageName, _config->Find("APT::Architecture")) == false) + // TRANSLATOR: The first placeholder is a package name, + // the other two should be copied verbatim as they include debug info + return _error->Error(_("Error occurred while processing %s (%s%d)"), + PackageName.c_str(), "NewPackage", 0); + } // Get a pointer to the package structure pkgCache::PkgIterator Pkg; @@ -418,6 +430,42 @@ bool pkgCacheGenerator::MergeListVersion(ListParser &List, pkgCache::PkgIterator return _error->Error(_("Error occurred while processing %s (%s%d)"), Pkg.Name(), "AddImplicitDepends", 1); } + /* :none packages are packages without an architecture. They are forbidden by + debian-policy, so usually they will only be in (old) dpkg status files - + and dpkg will complain about them - and are pretty rare. We therefore do + usually not create conflicts while the parent is created, but only if a :none + package (= the target) appears. This creates incorrect dependencies on :none + for architecture-specific dependencies on the package we copy from, but we + will ignore this bug as architecture-specific dependencies are only allowed + in jessie and until then the :none packages should be extinct (hopefully). + In other words: This should work long enough to allow graceful removal of + these packages, it is not supposed to allow users to keep using them … */ + if (strcmp(Pkg.Arch(), "none") == 0) + { + pkgCache::PkgIterator M = Grp.FindPreferredPkg(); + if (M.end() == false && Pkg != M) + { + pkgCache::DepIterator D = M.RevDependsList(); + Dynamic DynD(D); + for (; D.end() == false; ++D) + { + if ((D->Type != pkgCache::Dep::Conflicts && + D->Type != pkgCache::Dep::DpkgBreaks && + D->Type != pkgCache::Dep::Replaces) || + D.ParentPkg().Group() == Grp) + continue; + + map_ptrloc *OldDepLast = NULL; + pkgCache::VerIterator ConVersion = D.ParentVer(); + // duplicate the Conflicts/Breaks/Replaces for :none arch + if (D->Version == 0) + NewDepends(Pkg, ConVersion, "", 0, D->Type, OldDepLast); + else + NewDepends(Pkg, ConVersion, D.TargetVer(), + D->CompareOp, D->Type, OldDepLast); + } + } + } } if (unlikely(AddImplicitDepends(Grp, Pkg, Ver) == false)) return _error->Error(_("Error occurred while processing %s (%s%d)"), @@ -871,6 +919,9 @@ bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator &Ver, // Locate the target package pkgCache::PkgIterator Pkg = Grp.FindPkg(Arch); + // we don't create 'none' packages and their dependencies if we can avoid it … + if (Pkg.end() == true && Arch == "none") + return true; Dynamic DynPkg(Pkg); if (Pkg.end() == true) { if (unlikely(Owner->NewPackage(Pkg, PackageName, Arch) == false)) -- cgit v1.2.3 From 8ec008808cd6083a633685a732dfe9b8a58a89da Mon Sep 17 00:00:00 2001 From: David Kalnischkies Date: Sun, 9 Sep 2012 21:22:54 +0200 Subject: * apt-pkg/pkgcachegen.cc: - do not create 'native' (or now 'none') package structures as a side effect of description translation parsing as it pollutes the cache --- apt-pkg/pkgcachegen.cc | 2 ++ 1 file changed, 2 insertions(+) (limited to 'apt-pkg') diff --git a/apt-pkg/pkgcachegen.cc b/apt-pkg/pkgcachegen.cc index 490c2ecbb..54b07c465 100644 --- a/apt-pkg/pkgcachegen.cc +++ b/apt-pkg/pkgcachegen.cc @@ -195,8 +195,10 @@ bool pkgCacheGenerator::MergeList(ListParser &List, string const Version = List.Version(); if (Version.empty() == true && Arch.empty() == true) { + // package descriptions if (MergeListGroup(List, PackageName) == false) return false; + continue; } if (Arch.empty() == true) -- cgit v1.2.3