summaryrefslogtreecommitdiff
path: root/apt-pkg
diff options
context:
space:
mode:
authorDavid Kalnischkies <kalnischkies@gmail.com>2012-09-09 16:03:52 +0200
committerDavid Kalnischkies <kalnischkies@gmail.com>2012-09-09 16:03:52 +0200
commitc919ad6e4d0de48acb60f2a1371ade9bfb0451f8 (patch)
treef814cdfc029498db53928c06e619c91683b3f115 /apt-pkg
parent601c2c8ec3d33a1e787af75f20b51d1131cb6d74 (diff)
handle packages without a mandatory architecture (debian-policy §5.3)
by introducing a pseudo-architecture 'none' so that the small group of users with these packages can get right of them without introducing too much hassle for other users (Closes: #686346)
Diffstat (limited to 'apt-pkg')
-rw-r--r--apt-pkg/algorithms.cc5
-rw-r--r--apt-pkg/deb/deblistparser.cc22
-rw-r--r--apt-pkg/deb/dpkgpm.cc8
-rw-r--r--apt-pkg/pkgcache.cc6
-rw-r--r--apt-pkg/pkgcachegen.cc53
5 files changed, 86 insertions, 8 deletions
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<pkgCache::DepIterator> 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<pkgCache::PkgIterator> DynPkg(Pkg);
if (Pkg.end() == true) {
if (unlikely(Owner->NewPackage(Pkg, PackageName, Arch) == false))