]> git.saurik.com Git - apt.git/blob - apt-private/private-cacheset.cc
fail instead of segfault on unreadable config files
[apt.git] / apt-private / private-cacheset.cc
1 #include <config.h>
2
3 #include <apt-pkg/cachefile.h>
4 #include <apt-pkg/pkgcache.h>
5 #include <apt-pkg/depcache.h>
6 #include <apt-pkg/cacheiterators.h>
7 #include <apt-pkg/cachefilter.h>
8 #include <apt-pkg/aptconfiguration.h>
9 #include <apt-pkg/configuration.h>
10 #include <apt-pkg/progress.h>
11 #include <apt-pkg/policy.h>
12 #include <apt-pkg/strutl.h>
13
14 #include <apt-private/private-cacheset.h>
15
16 #include <stddef.h>
17
18 #include <apti18n.h>
19
20 bool GetLocalitySortedVersionSet(pkgCacheFile &CacheFile, /*{{{*/
21 APT::VersionContainerInterface * const vci,
22 OpProgress * const progress)
23 {
24 Matcher null_matcher = Matcher();
25 return GetLocalitySortedVersionSet(CacheFile, vci,
26 null_matcher, progress);
27 }
28 bool GetLocalitySortedVersionSet(pkgCacheFile &CacheFile,
29 APT::VersionContainerInterface * const vci,
30 Matcher &matcher,
31 OpProgress * const progress)
32 {
33 pkgCache * const Cache = CacheFile.GetPkgCache();
34 if (unlikely(Cache == nullptr))
35 return false;
36 if (progress != nullptr)
37 progress->SubProgress(Cache->Head().PackageCount, _("Sorting"));
38
39 pkgDepCache * const DepCache = CacheFile.GetDepCache();
40 if (unlikely(DepCache == nullptr))
41 return false;
42 APT::CacheSetHelper helper(false);
43
44 int Done=0;
45
46 bool const insertCurrentVer = _config->FindB("APT::Cmd::Installed", false);
47 bool const insertUpgradable = _config->FindB("APT::Cmd::Upgradable", false);
48 bool const insertManualInstalled = _config->FindB("APT::Cmd::Manual-Installed", false);
49
50 for (pkgCache::PkgIterator P = Cache->PkgBegin(); P.end() == false; ++P)
51 {
52 if (progress != NULL)
53 {
54 if (Done % 500 == 0)
55 progress->Progress(Done);
56 ++Done;
57 }
58
59 // exclude virtual pkgs
60 if (P->VersionList == 0)
61 continue;
62
63 if ((matcher)(P) == false)
64 continue;
65
66 pkgDepCache::StateCache &state = (*DepCache)[P];
67 if (insertCurrentVer == true)
68 {
69 if (P->CurrentVer != 0)
70 vci->FromPackage(vci, CacheFile, P, APT::CacheSetHelper::INSTALLED, helper);
71 }
72 else if (insertUpgradable == true)
73 {
74 if(P.CurrentVer() && state.Upgradable())
75 vci->FromPackage(vci, CacheFile, P, APT::CacheSetHelper::CANDIDATE, helper);
76 }
77 else if (insertManualInstalled == true)
78 {
79 if (P.CurrentVer() &&
80 ((*DepCache)[P].Flags & pkgCache::Flag::Auto) == false)
81 vci->FromPackage(vci, CacheFile, P, APT::CacheSetHelper::CANDIDATE, helper);
82 }
83 else
84 {
85 if (vci->FromPackage(vci, CacheFile, P, APT::CacheSetHelper::CANDIDATE, helper) == false)
86 {
87 // no candidate, this may happen for packages in
88 // dpkg "deinstall ok config-file" state - we pick the first ver
89 // (which should be the only one)
90 vci->insert(P.VersionList());
91 }
92 }
93 }
94 if (progress != NULL)
95 progress->Done();
96 return true;
97 }
98 /*}}}*/
99
100 // CacheSetHelper saving virtual packages /*{{{*/
101 pkgCache::VerIterator CacheSetHelperVirtuals::canNotGetVersion(
102 enum CacheSetHelper::VerSelector const select,
103 pkgCacheFile &Cache,
104 pkgCache::PkgIterator const &Pkg)
105 {
106 if (select == NEWEST || select == CANDIDATE || select == ALL)
107 virtualPkgs.insert(Pkg);
108 return CacheSetHelper::canNotGetVersion(select, Cache, Pkg);
109 }
110 void CacheSetHelperVirtuals::canNotFindVersion(
111 enum CacheSetHelper::VerSelector const select,
112 APT::VersionContainerInterface * vci,
113 pkgCacheFile &Cache,
114 pkgCache::PkgIterator const &Pkg)
115 {
116 if (select == NEWEST || select == CANDIDATE || select == ALL)
117 virtualPkgs.insert(Pkg);
118 return CacheSetHelper::canNotFindVersion(select, vci, Cache, Pkg);
119 }
120 static pkgCache::PkgIterator canNotFindPkgName_impl(pkgCacheFile &Cache, std::string const &str)
121 {
122 std::string pkg = str;
123 size_t const archfound = pkg.find_last_of(':');
124 std::string arch;
125 if (archfound != std::string::npos) {
126 arch = pkg.substr(archfound+1);
127 pkg.erase(archfound);
128 if (arch == "all" || arch == "native")
129 arch = _config->Find("APT::Architecture");
130 }
131
132 // If we don't find 'foo:amd64' look for 'foo:amd64:any'.
133 // Note: we prepare for an error here as if foo:amd64 does not exist,
134 // but foo:amd64:any it means that this package is only referenced in a
135 // (architecture specific) dependency. We do not add to virtualPkgs directly
136 // as we can't decide from here which error message has to be printed.
137 // FIXME: This doesn't match 'barbarian' architectures
138 pkgCache::PkgIterator Pkg(Cache, 0);
139 std::vector<std::string> const archs = APT::Configuration::getArchitectures();
140 if (archfound == std::string::npos)
141 {
142 for (auto const &a : archs)
143 {
144 Pkg = Cache.GetPkgCache()->FindPkg(pkg + ':' + a, "any");
145 if (Pkg.end() == false && Pkg->ProvidesList != 0)
146 break;
147 }
148 if (Pkg.end() == true)
149 for (auto const &a : archs)
150 {
151 Pkg = Cache.GetPkgCache()->FindPkg(pkg + ':' + a, "any");
152 if (Pkg.end() == false)
153 break;
154 }
155 }
156 else
157 {
158 Pkg = Cache.GetPkgCache()->FindPkg(pkg + ':' + arch, "any");
159 if (Pkg.end() == true)
160 {
161 APT::CacheFilter::PackageArchitectureMatchesSpecification pams(arch);
162 for (auto const &a : archs)
163 {
164 if (pams(a.c_str()) == false)
165 continue;
166 Pkg = Cache.GetPkgCache()->FindPkg(pkg + ':' + a, "any");
167 if (Pkg.end() == false)
168 break;
169 }
170 }
171 }
172 return Pkg;
173 }
174 pkgCache::PkgIterator CacheSetHelperVirtuals::canNotFindPkgName(pkgCacheFile &Cache, std::string const &str)
175 {
176 pkgCache::PkgIterator const Pkg = canNotFindPkgName_impl(Cache, str);
177 if (Pkg.end())
178 return APT::CacheSetHelper::canNotFindPkgName(Cache, str);
179 return Pkg;
180 }
181 CacheSetHelperVirtuals::CacheSetHelperVirtuals(bool const ShowErrors, GlobalError::MsgType const &ErrorType) :
182 CacheSetHelper{ShowErrors, ErrorType}
183 {}
184 /*}}}*/
185
186 // CacheSetHelperAPTGet - responsible for message telling from the CacheSets/*{{{*/
187 CacheSetHelperAPTGet::CacheSetHelperAPTGet(std::ostream &pout) :
188 APT::CacheSetHelper{true}, out(pout)
189 {
190 explicitlyNamed = true;
191 }
192 void CacheSetHelperAPTGet::showTaskSelection(pkgCache::PkgIterator const &Pkg, std::string const &pattern)
193 {
194 ioprintf(out, _("Note, selecting '%s' for task '%s'\n"),
195 Pkg.FullName(true).c_str(), pattern.c_str());
196 explicitlyNamed = false;
197 }
198 void CacheSetHelperAPTGet::showFnmatchSelection(pkgCache::PkgIterator const &Pkg, std::string const &pattern)
199 {
200 ioprintf(out, _("Note, selecting '%s' for glob '%s'\n"),
201 Pkg.FullName(true).c_str(), pattern.c_str());
202 explicitlyNamed = false;
203 }
204 void CacheSetHelperAPTGet::showRegExSelection(pkgCache::PkgIterator const &Pkg, std::string const &pattern)
205 {
206 ioprintf(out, _("Note, selecting '%s' for regex '%s'\n"),
207 Pkg.FullName(true).c_str(), pattern.c_str());
208 explicitlyNamed = false;
209 }
210 void CacheSetHelperAPTGet::showSelectedVersion(pkgCache::PkgIterator const &/*Pkg*/, pkgCache::VerIterator const Ver,
211 std::string const &ver, bool const /*verIsRel*/)
212 {
213 if (ver == Ver.VerStr())
214 return;
215 selectedByRelease.push_back(make_pair(Ver, ver));
216 }
217 bool CacheSetHelperAPTGet::showVirtualPackageErrors(pkgCacheFile &Cache)
218 {
219 if (virtualPkgs.empty() == true)
220 return true;
221 for (APT::PackageSet::const_iterator Pkg = virtualPkgs.begin();
222 Pkg != virtualPkgs.end(); ++Pkg) {
223 if (Pkg->ProvidesList != 0) {
224 ioprintf(c1out,_("Package %s is a virtual package provided by:\n"),
225 Pkg.FullName(true).c_str());
226
227 pkgCache::PrvIterator I = Pkg.ProvidesList();
228 unsigned short provider = 0;
229 for (; I.end() == false; ++I) {
230 pkgCache::PkgIterator Pkg = I.OwnerPkg();
231
232 if (Cache[Pkg].CandidateVerIter(Cache) == I.OwnerVer()) {
233 c1out << " " << Pkg.FullName(true) << " " << I.OwnerVer().VerStr();
234 if (Cache[Pkg].Install() == true && Cache[Pkg].NewInstall() == false)
235 c1out << _(" [Installed]");
236 c1out << std::endl;
237 ++provider;
238 }
239 }
240 // if we found no candidate which provide this package, show non-candidates
241 if (provider == 0)
242 for (I = Pkg.ProvidesList(); I.end() == false; ++I)
243 c1out << " " << I.OwnerPkg().FullName(true) << " " << I.OwnerVer().VerStr()
244 << _(" [Not candidate version]") << std::endl;
245 else
246 out << _("You should explicitly select one to install.") << std::endl;
247 } else {
248 ioprintf(c1out,
249 _("Package %s is not available, but is referred to by another package.\n"
250 "This may mean that the package is missing, has been obsoleted, or\n"
251 "is only available from another source\n"),Pkg.FullName(true).c_str());
252
253 std::vector<bool> Seen(Cache.GetPkgCache()->Head().PackageCount, false);
254 APT::PackageList pkglist;
255 for (pkgCache::DepIterator Dep = Pkg.RevDependsList();
256 Dep.end() == false; ++Dep) {
257 if (Dep->Type != pkgCache::Dep::Replaces)
258 continue;
259 pkgCache::PkgIterator const DP = Dep.ParentPkg();
260 if (Seen[DP->ID] == true)
261 continue;
262 Seen[DP->ID] = true;
263 pkglist.insert(DP);
264 }
265 ShowList(c1out, _("However the following packages replace it:"), pkglist,
266 &AlwaysTrue, &PrettyFullName, &EmptyString);
267 }
268 c1out << std::endl;
269 }
270 return false;
271 }
272 pkgCache::VerIterator CacheSetHelperAPTGet::canNotFindCandidateVer(pkgCacheFile &Cache, pkgCache::PkgIterator const &Pkg)
273 {
274 APT::VersionSet const verset = tryVirtualPackage(Cache, Pkg, CacheSetHelper::CANDIDATE);
275 if (verset.empty() == false)
276 return *(verset.begin());
277 else if (ShowError == true) {
278 _error->Error(_("Package '%s' has no installation candidate"),Pkg.FullName(true).c_str());
279 virtualPkgs.insert(Pkg);
280 }
281 return pkgCache::VerIterator(Cache, 0);
282 }
283 pkgCache::VerIterator CacheSetHelperAPTGet::canNotFindNewestVer(pkgCacheFile &Cache, pkgCache::PkgIterator const &Pkg)
284 {
285 if (Pkg->ProvidesList != 0)
286 {
287 APT::VersionSet const verset = tryVirtualPackage(Cache, Pkg, CacheSetHelper::NEWEST);
288 if (verset.empty() == false)
289 return *(verset.begin());
290 if (ShowError == true)
291 ioprintf(out, _("Virtual packages like '%s' can't be removed\n"), Pkg.FullName(true).c_str());
292 }
293 else
294 {
295 pkgCache::GrpIterator Grp = Pkg.Group();
296 pkgCache::PkgIterator P = Grp.PackageList();
297 for (; P.end() != true; P = Grp.NextPkg(P))
298 {
299 if (P == Pkg)
300 continue;
301 if (P->CurrentVer != 0) {
302 // TRANSLATORS: Note, this is not an interactive question
303 ioprintf(c1out,_("Package '%s' is not installed, so not removed. Did you mean '%s'?\n"),
304 Pkg.FullName(true).c_str(), P.FullName(true).c_str());
305 break;
306 }
307 }
308 if (P.end() == true)
309 ioprintf(c1out,_("Package '%s' is not installed, so not removed\n"),Pkg.FullName(true).c_str());
310 }
311 return pkgCache::VerIterator(Cache, 0);
312 }
313 APT::VersionSet CacheSetHelperAPTGet::tryVirtualPackage(pkgCacheFile &Cache, pkgCache::PkgIterator const &Pkg,
314 CacheSetHelper::VerSelector const select)
315 {
316 /* This is a pure virtual package and there is a single available
317 candidate providing it. */
318 if (unlikely(Cache[Pkg].CandidateVer != 0) || Pkg->ProvidesList == 0)
319 return APT::VersionSet();
320
321 pkgCache::PkgIterator Prov;
322 bool found_one = false;
323 for (pkgCache::PrvIterator P = Pkg.ProvidesList(); P; ++P) {
324 pkgCache::VerIterator const PVer = P.OwnerVer();
325 pkgCache::PkgIterator const PPkg = PVer.ParentPkg();
326
327 /* Ignore versions that are not a candidate. */
328 if (Cache[PPkg].CandidateVer != PVer)
329 continue;
330
331 if (found_one == false) {
332 Prov = PPkg;
333 found_one = true;
334 } else if (PPkg != Prov) {
335 // same group, so it's a foreign package
336 if (PPkg->Group == Prov->Group) {
337 // do we already have the requested arch?
338 if (strcmp(Pkg.Arch(), Prov.Arch()) == 0 ||
339 strcmp(Prov.Arch(), "all") == 0 ||
340 unlikely(strcmp(PPkg.Arch(), Prov.Arch()) == 0)) // packages have only on candidate, but just to be sure
341 continue;
342 // see which architecture we prefer more and switch to it
343 std::vector<std::string> archs = APT::Configuration::getArchitectures();
344 if (std::find(archs.begin(), archs.end(), PPkg.Arch()) < std::find(archs.begin(), archs.end(), Prov.Arch()))
345 Prov = PPkg;
346 continue;
347 }
348 found_one = false; // we found at least two
349 break;
350 }
351 }
352
353 if (found_one == true) {
354 ioprintf(out, _("Note, selecting '%s' instead of '%s'\n"),
355 Prov.FullName(true).c_str(), Pkg.FullName(true).c_str());
356 return APT::VersionSet::FromPackage(Cache, Prov, select, *this);
357 }
358 return APT::VersionSet();
359 }
360 pkgCache::PkgIterator CacheSetHelperAPTGet::canNotFindPkgName(pkgCacheFile &Cache, std::string const &str)
361 {
362 pkgCache::PkgIterator const Pkg = canNotFindPkgName_impl(Cache, str);
363 if (Pkg.end())
364 return APT::CacheSetHelper::canNotFindPkgName(Cache, str);
365 return Pkg;
366 }
367 /*}}}*/