]> git.saurik.com Git - apt.git/blob - cmdline/apt-cache.cc
apt-cache: stats: Average is over used, not all, buckets
[apt.git] / cmdline / apt-cache.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 // $Id: apt-cache.cc,v 1.72 2004/04/30 04:34:03 mdz Exp $
4 /* ######################################################################
5
6 apt-cache - Manages the cache files
7
8 apt-cache provides some functions fo manipulating the cache files.
9 It uses the command line interface common to all the APT tools.
10
11 Returns 100 on failure, 0 on success.
12
13 ##################################################################### */
14 /*}}}*/
15 // Include Files /*{{{*/
16 #include<config.h>
17
18 #include <apt-pkg/algorithms.h>
19 #include <apt-pkg/cachefile.h>
20 #include <apt-pkg/cacheset.h>
21 #include <apt-pkg/cmndline.h>
22 #include <apt-pkg/error.h>
23 #include <apt-pkg/fileutl.h>
24 #include <apt-pkg/indexfile.h>
25 #include <apt-pkg/init.h>
26 #include <apt-pkg/metaindex.h>
27 #include <apt-pkg/pkgrecords.h>
28 #include <apt-pkg/pkgsystem.h>
29 #include <apt-pkg/policy.h>
30 #include <apt-pkg/progress.h>
31 #include <apt-pkg/sourcelist.h>
32 #include <apt-pkg/sptr.h>
33 #include <apt-pkg/srcrecords.h>
34 #include <apt-pkg/strutl.h>
35 #include <apt-pkg/tagfile.h>
36 #include <apt-pkg/version.h>
37 #include <apt-pkg/cacheiterators.h>
38 #include <apt-pkg/configuration.h>
39 #include <apt-pkg/depcache.h>
40 #include <apt-pkg/macros.h>
41 #include <apt-pkg/mmap.h>
42 #include <apt-pkg/pkgcache.h>
43
44 #include <apt-private/private-cacheset.h>
45 #include <apt-private/private-cmndline.h>
46 #include <apt-private/private-depends.h>
47 #include <apt-private/private-show.h>
48 #include <apt-private/private-search.h>
49 #include <apt-private/private-unmet.h>
50 #include <apt-private/private-main.h>
51
52 #include <regex.h>
53 #include <stddef.h>
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <unistd.h>
57 #include <algorithm>
58 #include <cstring>
59 #include <iomanip>
60 #include <iostream>
61 #include <list>
62 #include <map>
63 #include <set>
64 #include <string>
65 #include <vector>
66
67 #include <apti18n.h>
68 /*}}}*/
69
70 using namespace std;
71
72 // DumpPackage - Show a dump of a package record /*{{{*/
73 // ---------------------------------------------------------------------
74 /* */
75 static bool DumpPackage(CommandLine &CmdL)
76 {
77 pkgCacheFile CacheFile;
78 APT::CacheSetHelper helper(true, GlobalError::NOTICE);
79 APT::PackageList pkgset = APT::PackageList::FromCommandLine(CacheFile, CmdL.FileList + 1, helper);
80
81 for (APT::PackageList::const_iterator Pkg = pkgset.begin(); Pkg != pkgset.end(); ++Pkg)
82 {
83 cout << "Package: " << Pkg.FullName(true) << endl;
84 cout << "Versions: " << endl;
85 for (pkgCache::VerIterator Cur = Pkg.VersionList(); Cur.end() != true; ++Cur)
86 {
87 cout << Cur.VerStr();
88 for (pkgCache::VerFileIterator Vf = Cur.FileList(); Vf.end() == false; ++Vf)
89 cout << " (" << Vf.File().FileName() << ")";
90 cout << endl;
91 for (pkgCache::DescIterator D = Cur.DescriptionList(); D.end() == false; ++D)
92 {
93 cout << " Description Language: " << D.LanguageCode() << endl
94 << " File: " << D.FileList().File().FileName() << endl
95 << " MD5: " << D.md5() << endl;
96 }
97 cout << endl;
98 }
99
100 cout << endl;
101
102 cout << "Reverse Depends: " << endl;
103 for (pkgCache::DepIterator D = Pkg.RevDependsList(); D.end() != true; ++D)
104 {
105 cout << " " << D.ParentPkg().FullName(true) << ',' << D.TargetPkg().FullName(true);
106 if (D->Version != 0)
107 cout << ' ' << DeNull(D.TargetVer()) << endl;
108 else
109 cout << endl;
110 }
111
112 cout << "Dependencies: " << endl;
113 for (pkgCache::VerIterator Cur = Pkg.VersionList(); Cur.end() != true; ++Cur)
114 {
115 cout << Cur.VerStr() << " - ";
116 for (pkgCache::DepIterator Dep = Cur.DependsList(); Dep.end() != true; ++Dep)
117 cout << Dep.TargetPkg().FullName(true) << " (" << (int)Dep->CompareOp << " " << DeNull(Dep.TargetVer()) << ") ";
118 cout << endl;
119 }
120
121 cout << "Provides: " << endl;
122 for (pkgCache::VerIterator Cur = Pkg.VersionList(); Cur.end() != true; ++Cur)
123 {
124 cout << Cur.VerStr() << " - ";
125 for (pkgCache::PrvIterator Prv = Cur.ProvidesList(); Prv.end() != true; ++Prv)
126 cout << Prv.ParentPkg().FullName(true) << " (= " << (Prv->ProvideVersion == 0 ? "" : Prv.ProvideVersion()) << ") ";
127 cout << endl;
128 }
129 cout << "Reverse Provides: " << endl;
130 for (pkgCache::PrvIterator Prv = Pkg.ProvidesList(); Prv.end() != true; ++Prv)
131 cout << Prv.OwnerPkg().FullName(true) << " " << Prv.OwnerVer().VerStr() << " (= " << (Prv->ProvideVersion == 0 ? "" : Prv.ProvideVersion()) << ")"<< endl;
132 }
133
134 return true;
135 }
136 /*}}}*/
137 // ShowHashTableStats - Show stats about a hashtable /*{{{*/
138 // ---------------------------------------------------------------------
139 /* */
140 static map_pointer_t PackageNext(pkgCache::Package const * const P) { return P->NextPackage; }
141 static map_pointer_t GroupNext(pkgCache::Group const * const G) { return G->Next; }
142 template<class T>
143 static void ShowHashTableStats(std::string Type,
144 T *StartP,
145 map_pointer_t *Hashtable,
146 unsigned long Size,
147 map_pointer_t(*Next)(T const * const))
148 {
149 // hashtable stats for the HashTable
150 unsigned long NumBuckets = Size;
151 unsigned long UsedBuckets = 0;
152 unsigned long UnusedBuckets = 0;
153 unsigned long LongestBucket = 0;
154 unsigned long ShortestBucket = NumBuckets;
155 unsigned long Entries = 0;
156 for (unsigned int i=0; i < NumBuckets; ++i)
157 {
158 T *P = StartP + Hashtable[i];
159 if(P == 0 || P == StartP)
160 {
161 ++UnusedBuckets;
162 continue;
163 }
164 ++UsedBuckets;
165 unsigned long ThisBucketSize = 0;
166 for (; P != StartP; P = StartP + Next(P))
167 ++ThisBucketSize;
168 Entries += ThisBucketSize;
169 LongestBucket = std::max(ThisBucketSize, LongestBucket);
170 ShortestBucket = std::min(ThisBucketSize, ShortestBucket);
171 }
172 cout << "Total buckets in " << Type << ": " << NumBuckets << std::endl;
173 cout << " Unused: " << UnusedBuckets << std::endl;
174 cout << " Used: " << UsedBuckets << std::endl;
175 cout << " Average entries: " << Entries/(double)UsedBuckets << std::endl;
176 cout << " Longest: " << LongestBucket << std::endl;
177 cout << " Shortest: " << ShortestBucket << std::endl;
178 }
179 /*}}}*/
180 // Stats - Dump some nice statistics /*{{{*/
181 // ---------------------------------------------------------------------
182 /* */
183 static bool Stats(CommandLine &CmdL)
184 {
185 if (CmdL.FileSize() > 1) {
186 _error->Error(_("apt-cache stats does not take any arguments"));
187 return false;
188 }
189
190 pkgCacheFile CacheFile;
191 pkgCache *Cache = CacheFile.GetPkgCache();
192
193 if (unlikely(Cache == NULL))
194 return false;
195
196 cout << _("Total package names: ") << Cache->Head().GroupCount << " (" <<
197 SizeToStr(Cache->Head().GroupCount*Cache->Head().GroupSz) << ')' << endl
198 << _("Total package structures: ") << Cache->Head().PackageCount << " (" <<
199 SizeToStr(Cache->Head().PackageCount*Cache->Head().PackageSz) << ')' << endl;
200
201 int Normal = 0;
202 int Virtual = 0;
203 int NVirt = 0;
204 int DVirt = 0;
205 int Missing = 0;
206 pkgCache::PkgIterator I = Cache->PkgBegin();
207 for (;I.end() != true; ++I)
208 {
209 if (I->VersionList != 0 && I->ProvidesList == 0)
210 {
211 Normal++;
212 continue;
213 }
214
215 if (I->VersionList != 0 && I->ProvidesList != 0)
216 {
217 NVirt++;
218 continue;
219 }
220
221 if (I->VersionList == 0 && I->ProvidesList != 0)
222 {
223 // Only 1 provides
224 if (I.ProvidesList()->NextProvides == 0)
225 {
226 DVirt++;
227 }
228 else
229 Virtual++;
230 continue;
231 }
232 if (I->VersionList == 0 && I->ProvidesList == 0)
233 {
234 Missing++;
235 continue;
236 }
237 }
238 cout << _(" Normal packages: ") << Normal << endl;
239 cout << _(" Pure virtual packages: ") << Virtual << endl;
240 cout << _(" Single virtual packages: ") << DVirt << endl;
241 cout << _(" Mixed virtual packages: ") << NVirt << endl;
242 cout << _(" Missing: ") << Missing << endl;
243
244 cout << _("Total distinct versions: ") << Cache->Head().VersionCount << " (" <<
245 SizeToStr(Cache->Head().VersionCount*Cache->Head().VersionSz) << ')' << endl;
246 cout << _("Total distinct descriptions: ") << Cache->Head().DescriptionCount << " (" <<
247 SizeToStr(Cache->Head().DescriptionCount*Cache->Head().DescriptionSz) << ')' << endl;
248 cout << _("Total dependencies: ") << Cache->Head().DependsCount << "/" << Cache->Head().DependsDataCount << " (" <<
249 SizeToStr((Cache->Head().DependsCount*Cache->Head().DependencySz) +
250 (Cache->Head().DependsDataCount*Cache->Head().DependencyDataSz)) << ')' << endl;
251 cout << _("Total ver/file relations: ") << Cache->Head().VerFileCount << " (" <<
252 SizeToStr(Cache->Head().VerFileCount*Cache->Head().VerFileSz) << ')' << endl;
253 cout << _("Total Desc/File relations: ") << Cache->Head().DescFileCount << " (" <<
254 SizeToStr(Cache->Head().DescFileCount*Cache->Head().DescFileSz) << ')' << endl;
255 cout << _("Total Provides mappings: ") << Cache->Head().ProvidesCount << " (" <<
256 SizeToStr(Cache->Head().ProvidesCount*Cache->Head().ProvidesSz) << ')' << endl;
257
258 // String list stats
259 std::set<map_stringitem_t> stritems;
260 for (pkgCache::GrpIterator G = Cache->GrpBegin(); G.end() == false; ++G)
261 stritems.insert(G->Name);
262 for (pkgCache::PkgIterator P = Cache->PkgBegin(); P.end() == false; ++P)
263 {
264 stritems.insert(P->Arch);
265 for (pkgCache::VerIterator V = P.VersionList(); V.end() == false; ++V)
266 {
267 if (V->VerStr != 0)
268 stritems.insert(V->VerStr);
269 if (V->Section != 0)
270 stritems.insert(V->Section);
271 stritems.insert(V->SourcePkgName);
272 stritems.insert(V->SourceVerStr);
273 for (pkgCache::DepIterator D = V.DependsList(); D.end() == false; ++D)
274 {
275 if (D->Version != 0)
276 stritems.insert(D->Version);
277 }
278 for (pkgCache::DescIterator D = V.DescriptionList(); D.end() == false; ++D)
279 {
280 stritems.insert(D->md5sum);
281 stritems.insert(D->language_code);
282 }
283 }
284 for (pkgCache::PrvIterator Prv = P.ProvidesList(); Prv.end() == false; ++Prv)
285 {
286 if (Prv->ProvideVersion != 0)
287 stritems.insert(Prv->ProvideVersion);
288 }
289 }
290 for (pkgCache::RlsFileIterator F = Cache->RlsFileBegin(); F != Cache->RlsFileEnd(); ++F)
291 {
292 stritems.insert(F->FileName);
293 stritems.insert(F->Archive);
294 stritems.insert(F->Codename);
295 stritems.insert(F->Version);
296 stritems.insert(F->Origin);
297 stritems.insert(F->Label);
298 stritems.insert(F->Site);
299 }
300 for (pkgCache::PkgFileIterator F = Cache->FileBegin(); F != Cache->FileEnd(); ++F)
301 {
302 stritems.insert(F->FileName);
303 stritems.insert(F->Architecture);
304 stritems.insert(F->Component);
305 stritems.insert(F->IndexType);
306 }
307
308 unsigned long Size = 0;
309 for (std::set<map_stringitem_t>::const_iterator i = stritems.begin(); i != stritems.end(); ++i)
310 Size += strlen(Cache->StrP + *i) + 1;
311 cout << _("Total globbed strings: ") << stritems.size() << " (" << SizeToStr(Size) << ')' << endl;
312 stritems.clear();
313
314 unsigned long Slack = 0;
315 for (int I = 0; I != 7; I++)
316 Slack += Cache->Head().Pools[I].ItemSize*Cache->Head().Pools[I].Count;
317 cout << _("Total slack space: ") << SizeToStr(Slack) << endl;
318
319 unsigned long Total = 0;
320 #define APT_CACHESIZE(X,Y) (Cache->Head().X * Cache->Head().Y)
321 Total = Slack + Size +
322 APT_CACHESIZE(GroupCount, GroupSz) +
323 APT_CACHESIZE(PackageCount, PackageSz) +
324 APT_CACHESIZE(VersionCount, VersionSz) +
325 APT_CACHESIZE(DescriptionCount, DescriptionSz) +
326 APT_CACHESIZE(DependsCount, DependencySz) +
327 APT_CACHESIZE(DependsDataCount, DependencyDataSz) +
328 APT_CACHESIZE(ReleaseFileCount, ReleaseFileSz) +
329 APT_CACHESIZE(PackageFileCount, PackageFileSz) +
330 APT_CACHESIZE(VerFileCount, VerFileSz) +
331 APT_CACHESIZE(DescFileCount, DescFileSz) +
332 APT_CACHESIZE(ProvidesCount, ProvidesSz) +
333 (2 * Cache->Head().GetHashTableSize() * sizeof(map_id_t));
334 cout << _("Total space accounted for: ") << SizeToStr(Total) << endl;
335 #undef APT_CACHESIZE
336
337 // hashtable stats
338 ShowHashTableStats<pkgCache::Package>("PkgHashTable", Cache->PkgP, Cache->Head().PkgHashTableP(), Cache->Head().GetHashTableSize(), PackageNext);
339 ShowHashTableStats<pkgCache::Group>("GrpHashTable", Cache->GrpP, Cache->Head().GrpHashTableP(), Cache->Head().GetHashTableSize(), GroupNext);
340
341 return true;
342 }
343 /*}}}*/
344 // Dump - show everything /*{{{*/
345 // ---------------------------------------------------------------------
346 /* This is worthless except fer debugging things */
347 static bool Dump(CommandLine &)
348 {
349 pkgCacheFile CacheFile;
350 pkgCache *Cache = CacheFile.GetPkgCache();
351 if (unlikely(Cache == NULL))
352 return false;
353
354 std::cout << "Using Versioning System: " << Cache->VS->Label << std::endl;
355
356 for (pkgCache::PkgIterator P = Cache->PkgBegin(); P.end() == false; ++P)
357 {
358 std::cout << "Package: " << P.FullName(true) << std::endl;
359 for (pkgCache::VerIterator V = P.VersionList(); V.end() == false; ++V)
360 {
361 std::cout << " Version: " << V.VerStr() << std::endl;
362 std::cout << " File: " << V.FileList().File().FileName() << std::endl;
363 for (pkgCache::DepIterator D = V.DependsList(); D.end() == false; ++D)
364 std::cout << " Depends: " << D.TargetPkg().FullName(true) << ' ' <<
365 DeNull(D.TargetVer()) << std::endl;
366 for (pkgCache::DescIterator D = V.DescriptionList(); D.end() == false; ++D)
367 {
368 std::cout << " Description Language: " << D.LanguageCode() << std::endl
369 << " File: " << D.FileList().File().FileName() << std::endl
370 << " MD5: " << D.md5() << std::endl;
371 }
372 }
373 }
374
375 for (pkgCache::PkgFileIterator F = Cache->FileBegin(); F.end() == false; ++F)
376 {
377 std::cout << "File: " << F.FileName() << std::endl;
378 std::cout << " Type: " << F.IndexType() << std::endl;
379 std::cout << " Size: " << F->Size << std::endl;
380 std::cout << " ID: " << F->ID << std::endl;
381 std::cout << " Flags: " << F->Flags << std::endl;
382 std::cout << " Time: " << TimeRFC1123(F->mtime) << std::endl;
383 std::cout << " Archive: " << DeNull(F.Archive()) << std::endl;
384 std::cout << " Component: " << DeNull(F.Component()) << std::endl;
385 std::cout << " Version: " << DeNull(F.Version()) << std::endl;
386 std::cout << " Origin: " << DeNull(F.Origin()) << std::endl;
387 std::cout << " Site: " << DeNull(F.Site()) << std::endl;
388 std::cout << " Label: " << DeNull(F.Label()) << std::endl;
389 std::cout << " Architecture: " << DeNull(F.Architecture()) << std::endl;
390 }
391
392 return true;
393 }
394 /*}}}*/
395 // DumpAvail - Print out the available list /*{{{*/
396 // ---------------------------------------------------------------------
397 /* This is needed to make dpkg --merge happy.. I spent a bit of time to
398 make this run really fast, perhaps I went a little overboard.. */
399 static bool DumpAvail(CommandLine &)
400 {
401 pkgCacheFile CacheFile;
402 pkgCache *Cache = CacheFile.GetPkgCache();
403 if (unlikely(Cache == NULL || CacheFile.BuildPolicy() == false))
404 return false;
405
406 unsigned long Count = Cache->HeaderP->PackageCount+1;
407 pkgCache::VerFile **VFList = new pkgCache::VerFile *[Count];
408 memset(VFList,0,sizeof(*VFList)*Count);
409
410 // Map versions that we want to write out onto the VerList array.
411 for (pkgCache::PkgIterator P = Cache->PkgBegin(); P.end() == false; ++P)
412 {
413 if (P->VersionList == 0)
414 continue;
415
416 /* Find the proper version to use. If the policy says there are no
417 possible selections we return the installed version, if available..
418 This prevents dselect from making it obsolete. */
419 pkgCache::VerIterator V = CacheFile.GetPolicy()->GetCandidateVer(P);
420 if (V.end() == true)
421 {
422 if (P->CurrentVer == 0)
423 continue;
424 V = P.CurrentVer();
425 }
426
427 pkgCache::VerFileIterator VF = V.FileList();
428 for (; VF.end() == false ; ++VF)
429 if ((VF.File()->Flags & pkgCache::Flag::NotSource) == 0)
430 break;
431
432 /* Okay, here we have a bit of a problem.. The policy has selected the
433 currently installed package - however it only exists in the
434 status file.. We need to write out something or dselect will mark
435 the package as obsolete! Thus we emit the status file entry, but
436 below we remove the status line to make it valid for the
437 available file. However! We only do this if their do exist *any*
438 non-source versions of the package - that way the dselect obsolete
439 handling works OK. */
440 if (VF.end() == true)
441 {
442 for (pkgCache::VerIterator Cur = P.VersionList(); Cur.end() != true; ++Cur)
443 {
444 for (VF = Cur.FileList(); VF.end() == false; ++VF)
445 {
446 if ((VF.File()->Flags & pkgCache::Flag::NotSource) == 0)
447 {
448 VF = V.FileList();
449 break;
450 }
451 }
452
453 if (VF.end() == false)
454 break;
455 }
456 }
457
458 VFList[P->ID] = VF;
459 }
460
461 LocalitySort(VFList,Count,sizeof(*VFList));
462
463 std::vector<pkgTagSection::Tag> RW;
464 RW.push_back(pkgTagSection::Tag::Remove("Status"));
465 RW.push_back(pkgTagSection::Tag::Remove("Config-Version"));
466 FileFd stdoutfd;
467 stdoutfd.OpenDescriptor(STDOUT_FILENO, FileFd::WriteOnly, false);
468
469 // Iterate over all the package files and write them out.
470 char *Buffer = new char[Cache->HeaderP->MaxVerFileSize+10];
471 for (pkgCache::VerFile **J = VFList; *J != 0;)
472 {
473 pkgCache::PkgFileIterator File(*Cache,(*J)->File + Cache->PkgFileP);
474 if (File.IsOk() == false)
475 {
476 _error->Error(_("Package file %s is out of sync."),File.FileName());
477 break;
478 }
479
480 FileFd PkgF(File.FileName(),FileFd::ReadOnly, FileFd::Extension);
481 if (_error->PendingError() == true)
482 break;
483
484 /* Write all of the records from this package file, since we
485 already did locality sorting we can now just seek through the
486 file in read order. We apply 1 more optimization here, since often
487 there will be < 1 byte gaps between records (for the \n) we read that
488 into the next buffer and offset a bit.. */
489 unsigned long Pos = 0;
490 for (; *J != 0; J++)
491 {
492 if ((*J)->File + Cache->PkgFileP != File)
493 break;
494
495 const pkgCache::VerFile &VF = **J;
496
497 // Read the record and then write it out again.
498 unsigned long Jitter = VF.Offset - Pos;
499 if (Jitter > 8)
500 {
501 if (PkgF.Seek(VF.Offset) == false)
502 break;
503 Jitter = 0;
504 }
505
506 if (PkgF.Read(Buffer,VF.Size + Jitter) == false)
507 break;
508 Buffer[VF.Size + Jitter] = '\n';
509
510 // See above..
511 if ((File->Flags & pkgCache::Flag::NotSource) == pkgCache::Flag::NotSource)
512 {
513 pkgTagSection Tags;
514 if (Tags.Scan(Buffer+Jitter,VF.Size+1) == false ||
515 Tags.Write(stdoutfd, NULL, RW) == false ||
516 stdoutfd.Write("\n", 1) == false)
517 {
518 _error->Error("Internal Error, Unable to parse a package record");
519 break;
520 }
521 }
522 else
523 {
524 if (stdoutfd.Write(Buffer + Jitter, VF.Size + 1) == false)
525 break;
526 }
527
528 Pos = VF.Offset + VF.Size;
529 }
530
531 if (_error->PendingError() == true)
532 break;
533 }
534
535 delete [] Buffer;
536 delete [] VFList;
537 return !_error->PendingError();
538 }
539 /*}}}*/
540 // xvcg - Generate a graph for xvcg /*{{{*/
541 // ---------------------------------------------------------------------
542 // Code contributed from Junichi Uekawa <dancer@debian.org> on 20 June 2002.
543
544 static bool XVcg(CommandLine &CmdL)
545 {
546 pkgCacheFile CacheFile;
547 pkgCache *Cache = CacheFile.GetPkgCache();
548 if (unlikely(Cache == NULL))
549 return false;
550
551 bool GivenOnly = _config->FindB("APT::Cache::GivenOnly",false);
552
553 /* Normal packages are boxes
554 Pure Provides are triangles
555 Mixed are diamonds
556 rhomb are missing packages*/
557 const char *Shapes[] = {"ellipse","triangle","box","rhomb"};
558
559 /* Initialize the list of packages to show.
560 1 = To Show
561 2 = To Show no recurse
562 3 = Emitted no recurse
563 4 = Emitted
564 0 = None */
565 enum States {None=0, ToShow, ToShowNR, DoneNR, Done};
566 enum TheFlags {ForceNR=(1<<0)};
567 unsigned char *Show = new unsigned char[Cache->Head().PackageCount];
568 unsigned char *Flags = new unsigned char[Cache->Head().PackageCount];
569 unsigned char *ShapeMap = new unsigned char[Cache->Head().PackageCount];
570
571 // Show everything if no arguments given
572 if (CmdL.FileList[1] == 0)
573 for (unsigned long I = 0; I != Cache->Head().PackageCount; I++)
574 Show[I] = ToShow;
575 else
576 for (unsigned long I = 0; I != Cache->Head().PackageCount; I++)
577 Show[I] = None;
578 memset(Flags,0,sizeof(*Flags)*Cache->Head().PackageCount);
579
580 // Map the shapes
581 for (pkgCache::PkgIterator Pkg = Cache->PkgBegin(); Pkg.end() == false; ++Pkg)
582 {
583 if (Pkg->VersionList == 0)
584 {
585 // Missing
586 if (Pkg->ProvidesList == 0)
587 ShapeMap[Pkg->ID] = 0;
588 else
589 ShapeMap[Pkg->ID] = 1;
590 }
591 else
592 {
593 // Normal
594 if (Pkg->ProvidesList == 0)
595 ShapeMap[Pkg->ID] = 2;
596 else
597 ShapeMap[Pkg->ID] = 3;
598 }
599 }
600
601 // Load the list of packages from the command line into the show list
602 APT::CacheSetHelper helper(true, GlobalError::NOTICE);
603 std::list<APT::CacheSetHelper::PkgModifier> mods;
604 mods.push_back(APT::CacheSetHelper::PkgModifier(0, ",", APT::PackageSet::Modifier::POSTFIX));
605 mods.push_back(APT::CacheSetHelper::PkgModifier(1, "^", APT::PackageSet::Modifier::POSTFIX));
606 std::map<unsigned short, APT::PackageSet> pkgsets =
607 APT::PackageSet::GroupedFromCommandLine(CacheFile, CmdL.FileList + 1, mods, 0, helper);
608
609 for (APT::PackageSet::const_iterator Pkg = pkgsets[0].begin();
610 Pkg != pkgsets[0].end(); ++Pkg)
611 Show[Pkg->ID] = ToShow;
612 for (APT::PackageSet::const_iterator Pkg = pkgsets[1].begin();
613 Pkg != pkgsets[1].end(); ++Pkg)
614 {
615 Show[Pkg->ID] = ToShow;
616 Flags[Pkg->ID] |= ForceNR;
617 }
618
619 // Little header
620 cout << "graph: { title: \"packages\"" << endl <<
621 "xmax: 700 ymax: 700 x: 30 y: 30" << endl <<
622 "layout_downfactor: 8" << endl;
623
624 bool Act = true;
625 while (Act == true)
626 {
627 Act = false;
628 for (pkgCache::PkgIterator Pkg = Cache->PkgBegin(); Pkg.end() == false; ++Pkg)
629 {
630 // See we need to show this package
631 if (Show[Pkg->ID] == None || Show[Pkg->ID] >= DoneNR)
632 continue;
633
634 //printf ("node: { title: \"%s\" label: \"%s\" }\n", Pkg.Name(), Pkg.Name());
635
636 // Colour as done
637 if (Show[Pkg->ID] == ToShowNR || (Flags[Pkg->ID] & ForceNR) == ForceNR)
638 {
639 // Pure Provides and missing packages have no deps!
640 if (ShapeMap[Pkg->ID] == 0 || ShapeMap[Pkg->ID] == 1)
641 Show[Pkg->ID] = Done;
642 else
643 Show[Pkg->ID] = DoneNR;
644 }
645 else
646 Show[Pkg->ID] = Done;
647 Act = true;
648
649 // No deps to map out
650 if (Pkg->VersionList == 0 || Show[Pkg->ID] == DoneNR)
651 continue;
652
653 pkgCache::VerIterator Ver = Pkg.VersionList();
654 for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false; ++D)
655 {
656 // See if anything can meet this dep
657 // Walk along the actual package providing versions
658 bool Hit = false;
659 pkgCache::PkgIterator DPkg = D.TargetPkg();
660 for (pkgCache::VerIterator I = DPkg.VersionList();
661 I.end() == false && Hit == false; ++I)
662 {
663 if (Cache->VS->CheckDep(I.VerStr(),D->CompareOp,D.TargetVer()) == true)
664 Hit = true;
665 }
666
667 // Follow all provides
668 for (pkgCache::PrvIterator I = DPkg.ProvidesList();
669 I.end() == false && Hit == false; ++I)
670 {
671 if (Cache->VS->CheckDep(I.ProvideVersion(),D->CompareOp,D.TargetVer()) == false)
672 Hit = true;
673 }
674
675
676 // Only graph critical deps
677 if (D.IsCritical() == true)
678 {
679 printf ("edge: { sourcename: \"%s\" targetname: \"%s\" class: 2 ",Pkg.FullName(true).c_str(), D.TargetPkg().FullName(true).c_str() );
680
681 // Colour the node for recursion
682 if (Show[D.TargetPkg()->ID] <= DoneNR)
683 {
684 /* If a conflicts does not meet anything in the database
685 then show the relation but do not recurse */
686 if (Hit == false && D.IsNegative() == true)
687 {
688 if (Show[D.TargetPkg()->ID] == None &&
689 Show[D.TargetPkg()->ID] != ToShow)
690 Show[D.TargetPkg()->ID] = ToShowNR;
691 }
692 else
693 {
694 if (GivenOnly == true && Show[D.TargetPkg()->ID] != ToShow)
695 Show[D.TargetPkg()->ID] = ToShowNR;
696 else
697 Show[D.TargetPkg()->ID] = ToShow;
698 }
699 }
700
701 // Edge colour
702 switch(D->Type)
703 {
704 case pkgCache::Dep::Conflicts:
705 printf("label: \"conflicts\" color: lightgreen }\n");
706 break;
707 case pkgCache::Dep::DpkgBreaks:
708 printf("label: \"breaks\" color: lightgreen }\n");
709 break;
710 case pkgCache::Dep::Obsoletes:
711 printf("label: \"obsoletes\" color: lightgreen }\n");
712 break;
713
714 case pkgCache::Dep::PreDepends:
715 printf("label: \"predepends\" color: blue }\n");
716 break;
717
718 default:
719 printf("}\n");
720 break;
721 }
722 }
723 }
724 }
725 }
726
727 /* Draw the box colours after the fact since we can not tell what colour
728 they should be until everything is finished drawing */
729 for (pkgCache::PkgIterator Pkg = Cache->PkgBegin(); Pkg.end() == false; ++Pkg)
730 {
731 if (Show[Pkg->ID] < DoneNR)
732 continue;
733
734 if (Show[Pkg->ID] == DoneNR)
735 printf("node: { title: \"%s\" label: \"%s\" color: orange shape: %s }\n", Pkg.FullName(true).c_str(), Pkg.FullName(true).c_str(),
736 Shapes[ShapeMap[Pkg->ID]]);
737 else
738 printf("node: { title: \"%s\" label: \"%s\" shape: %s }\n", Pkg.FullName(true).c_str(), Pkg.FullName(true).c_str(),
739 Shapes[ShapeMap[Pkg->ID]]);
740
741 }
742
743 delete[] Show;
744 delete[] Flags;
745 delete[] ShapeMap;
746
747 printf("}\n");
748 return true;
749 }
750 /*}}}*/
751 // Dotty - Generate a graph for Dotty /*{{{*/
752 // ---------------------------------------------------------------------
753 /* Dotty is the graphvis program for generating graphs. It is a fairly
754 simple queuing algorithm that just writes dependencies and nodes.
755 http://www.research.att.com/sw/tools/graphviz/ */
756 static bool Dotty(CommandLine &CmdL)
757 {
758 pkgCacheFile CacheFile;
759 pkgCache *Cache = CacheFile.GetPkgCache();
760 if (unlikely(Cache == NULL))
761 return false;
762
763 bool GivenOnly = _config->FindB("APT::Cache::GivenOnly",false);
764
765 /* Normal packages are boxes
766 Pure Provides are triangles
767 Mixed are diamonds
768 Hexagons are missing packages*/
769 const char *Shapes[] = {"hexagon","triangle","box","diamond"};
770
771 /* Initialize the list of packages to show.
772 1 = To Show
773 2 = To Show no recurse
774 3 = Emitted no recurse
775 4 = Emitted
776 0 = None */
777 enum States {None=0, ToShow, ToShowNR, DoneNR, Done};
778 enum TheFlags {ForceNR=(1<<0)};
779 unsigned char *Show = new unsigned char[Cache->Head().PackageCount];
780 unsigned char *Flags = new unsigned char[Cache->Head().PackageCount];
781 unsigned char *ShapeMap = new unsigned char[Cache->Head().PackageCount];
782
783 // Show everything if no arguments given
784 if (CmdL.FileList[1] == 0)
785 for (unsigned long I = 0; I != Cache->Head().PackageCount; I++)
786 Show[I] = ToShow;
787 else
788 for (unsigned long I = 0; I != Cache->Head().PackageCount; I++)
789 Show[I] = None;
790 memset(Flags,0,sizeof(*Flags)*Cache->Head().PackageCount);
791
792 // Map the shapes
793 for (pkgCache::PkgIterator Pkg = Cache->PkgBegin(); Pkg.end() == false; ++Pkg)
794 {
795 if (Pkg->VersionList == 0)
796 {
797 // Missing
798 if (Pkg->ProvidesList == 0)
799 ShapeMap[Pkg->ID] = 0;
800 else
801 ShapeMap[Pkg->ID] = 1;
802 }
803 else
804 {
805 // Normal
806 if (Pkg->ProvidesList == 0)
807 ShapeMap[Pkg->ID] = 2;
808 else
809 ShapeMap[Pkg->ID] = 3;
810 }
811 }
812
813 // Load the list of packages from the command line into the show list
814 APT::CacheSetHelper helper(true, GlobalError::NOTICE);
815 std::list<APT::CacheSetHelper::PkgModifier> mods;
816 mods.push_back(APT::CacheSetHelper::PkgModifier(0, ",", APT::PackageSet::Modifier::POSTFIX));
817 mods.push_back(APT::CacheSetHelper::PkgModifier(1, "^", APT::PackageSet::Modifier::POSTFIX));
818 std::map<unsigned short, APT::PackageSet> pkgsets =
819 APT::PackageSet::GroupedFromCommandLine(CacheFile, CmdL.FileList + 1, mods, 0, helper);
820
821 for (APT::PackageSet::const_iterator Pkg = pkgsets[0].begin();
822 Pkg != pkgsets[0].end(); ++Pkg)
823 Show[Pkg->ID] = ToShow;
824 for (APT::PackageSet::const_iterator Pkg = pkgsets[1].begin();
825 Pkg != pkgsets[1].end(); ++Pkg)
826 {
827 Show[Pkg->ID] = ToShow;
828 Flags[Pkg->ID] |= ForceNR;
829 }
830
831 // Little header
832 printf("digraph packages {\n");
833 printf("concentrate=true;\n");
834 printf("size=\"30,40\";\n");
835
836 bool Act = true;
837 while (Act == true)
838 {
839 Act = false;
840 for (pkgCache::PkgIterator Pkg = Cache->PkgBegin(); Pkg.end() == false; ++Pkg)
841 {
842 // See we need to show this package
843 if (Show[Pkg->ID] == None || Show[Pkg->ID] >= DoneNR)
844 continue;
845
846 // Colour as done
847 if (Show[Pkg->ID] == ToShowNR || (Flags[Pkg->ID] & ForceNR) == ForceNR)
848 {
849 // Pure Provides and missing packages have no deps!
850 if (ShapeMap[Pkg->ID] == 0 || ShapeMap[Pkg->ID] == 1)
851 Show[Pkg->ID] = Done;
852 else
853 Show[Pkg->ID] = DoneNR;
854 }
855 else
856 Show[Pkg->ID] = Done;
857 Act = true;
858
859 // No deps to map out
860 if (Pkg->VersionList == 0 || Show[Pkg->ID] == DoneNR)
861 continue;
862
863 pkgCache::VerIterator Ver = Pkg.VersionList();
864 for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false; ++D)
865 {
866 // See if anything can meet this dep
867 // Walk along the actual package providing versions
868 bool Hit = false;
869 pkgCache::PkgIterator DPkg = D.TargetPkg();
870 for (pkgCache::VerIterator I = DPkg.VersionList();
871 I.end() == false && Hit == false; ++I)
872 {
873 if (Cache->VS->CheckDep(I.VerStr(),D->CompareOp,D.TargetVer()) == true)
874 Hit = true;
875 }
876
877 // Follow all provides
878 for (pkgCache::PrvIterator I = DPkg.ProvidesList();
879 I.end() == false && Hit == false; ++I)
880 {
881 if (Cache->VS->CheckDep(I.ProvideVersion(),D->CompareOp,D.TargetVer()) == false)
882 Hit = true;
883 }
884
885 // Only graph critical deps
886 if (D.IsCritical() == true)
887 {
888 printf("\"%s\" -> \"%s\"",Pkg.FullName(true).c_str(),D.TargetPkg().FullName(true).c_str());
889
890 // Colour the node for recursion
891 if (Show[D.TargetPkg()->ID] <= DoneNR)
892 {
893 /* If a conflicts does not meet anything in the database
894 then show the relation but do not recurse */
895 if (Hit == false && D.IsNegative() == true)
896 {
897 if (Show[D.TargetPkg()->ID] == None &&
898 Show[D.TargetPkg()->ID] != ToShow)
899 Show[D.TargetPkg()->ID] = ToShowNR;
900 }
901 else
902 {
903 if (GivenOnly == true && Show[D.TargetPkg()->ID] != ToShow)
904 Show[D.TargetPkg()->ID] = ToShowNR;
905 else
906 Show[D.TargetPkg()->ID] = ToShow;
907 }
908 }
909
910 // Edge colour
911 switch(D->Type)
912 {
913 case pkgCache::Dep::Conflicts:
914 case pkgCache::Dep::Obsoletes:
915 case pkgCache::Dep::DpkgBreaks:
916 printf("[color=springgreen];\n");
917 break;
918
919 case pkgCache::Dep::PreDepends:
920 printf("[color=blue];\n");
921 break;
922
923 default:
924 printf(";\n");
925 break;
926 }
927 }
928 }
929 }
930 }
931
932 /* Draw the box colours after the fact since we can not tell what colour
933 they should be until everything is finished drawing */
934 for (pkgCache::PkgIterator Pkg = Cache->PkgBegin(); Pkg.end() == false; ++Pkg)
935 {
936 if (Show[Pkg->ID] < DoneNR)
937 continue;
938
939 // Orange box for early recursion stoppage
940 if (Show[Pkg->ID] == DoneNR)
941 printf("\"%s\" [color=orange,shape=%s];\n",Pkg.FullName(true).c_str(),
942 Shapes[ShapeMap[Pkg->ID]]);
943 else
944 printf("\"%s\" [shape=%s];\n",Pkg.FullName(true).c_str(),
945 Shapes[ShapeMap[Pkg->ID]]);
946 }
947
948 printf("}\n");
949 delete[] Show;
950 delete[] Flags;
951 delete[] ShapeMap;
952 return true;
953 }
954 /*}}}*/
955 /* ShowAuto - show automatically installed packages (sorted) {{{*/
956 static bool ShowAuto(CommandLine &)
957 {
958 pkgCacheFile CacheFile;
959 pkgCache *Cache = CacheFile.GetPkgCache();
960 pkgDepCache *DepCache = CacheFile.GetDepCache();
961 if (unlikely(Cache == NULL || DepCache == NULL))
962 return false;
963
964 std::vector<string> packages;
965 packages.reserve(Cache->HeaderP->PackageCount / 3);
966
967 for (pkgCache::PkgIterator P = Cache->PkgBegin(); P.end() == false; ++P)
968 if ((*DepCache)[P].Flags & pkgCache::Flag::Auto)
969 packages.push_back(P.Name());
970
971 std::sort(packages.begin(), packages.end());
972
973 for (vector<string>::iterator I = packages.begin(); I != packages.end(); ++I)
974 cout << *I << "\n";
975
976 _error->Notice(_("This command is deprecated. Please use 'apt-mark showauto' instead."));
977 return true;
978 }
979 /*}}}*/
980 // ShowPkgNames - Show package names /*{{{*/
981 // ---------------------------------------------------------------------
982 /* This does a prefix match on the first argument */
983 static bool ShowPkgNames(CommandLine &CmdL)
984 {
985 pkgCacheFile CacheFile;
986 if (unlikely(CacheFile.BuildCaches(NULL, false) == false))
987 return false;
988 pkgCache::GrpIterator I = CacheFile.GetPkgCache()->GrpBegin();
989 bool const All = _config->FindB("APT::Cache::AllNames","false");
990
991 if (CmdL.FileList[1] != 0)
992 {
993 for (;I.end() != true; ++I)
994 {
995 if (All == false && I->FirstPackage == 0)
996 continue;
997 if (I.FindPkg("any")->VersionList == 0)
998 continue;
999 if (strncmp(I.Name(),CmdL.FileList[1],strlen(CmdL.FileList[1])) == 0)
1000 cout << I.Name() << endl;
1001 }
1002
1003 return true;
1004 }
1005
1006 // Show all pkgs
1007 for (;I.end() != true; ++I)
1008 {
1009 if (All == false && I->FirstPackage == 0)
1010 continue;
1011 if (I.FindPkg("any")->VersionList == 0)
1012 continue;
1013 cout << I.Name() << endl;
1014 }
1015
1016 return true;
1017 }
1018 /*}}}*/
1019 // Madison - Look a bit like katie's madison /*{{{*/
1020 // ---------------------------------------------------------------------
1021 /* */
1022 static bool Madison(CommandLine &CmdL)
1023 {
1024 pkgCacheFile CacheFile;
1025 pkgSourceList *SrcList = CacheFile.GetSourceList();
1026
1027 if (SrcList == 0)
1028 return false;
1029
1030 // Create the src text record parsers and ignore errors about missing
1031 // deb-src lines that are generated from pkgSrcRecords::pkgSrcRecords
1032 pkgSrcRecords SrcRecs(*SrcList);
1033 if (_error->PendingError() == true)
1034 _error->Discard();
1035
1036 APT::CacheSetHelper helper(true, GlobalError::NOTICE);
1037 for (const char **I = CmdL.FileList + 1; *I != 0; I++)
1038 {
1039 _error->PushToStack();
1040 APT::PackageList pkgset = APT::PackageList::FromString(CacheFile, *I, helper);
1041 for (APT::PackageList::const_iterator Pkg = pkgset.begin(); Pkg != pkgset.end(); ++Pkg)
1042 {
1043 for (pkgCache::VerIterator V = Pkg.VersionList(); V.end() == false; ++V)
1044 {
1045 for (pkgCache::VerFileIterator VF = V.FileList(); VF.end() == false; ++VF)
1046 {
1047 // This might be nice, but wouldn't uniquely identify the source -mdz
1048 // if (VF.File().Archive() != 0)
1049 // {
1050 // cout << setw(10) << Pkg.Name() << " | " << setw(10) << V.VerStr() << " | "
1051 // << VF.File().Archive() << endl;
1052 // }
1053
1054 // Locate the associated index files so we can derive a description
1055 for (pkgSourceList::const_iterator S = SrcList->begin(); S != SrcList->end(); ++S)
1056 {
1057 vector<pkgIndexFile *> *Indexes = (*S)->GetIndexFiles();
1058 for (vector<pkgIndexFile *>::const_iterator IF = Indexes->begin();
1059 IF != Indexes->end(); ++IF)
1060 {
1061 if ((*IF)->FindInCache(*(VF.File().Cache())) == VF.File())
1062 {
1063 cout << setw(10) << Pkg.FullName(true) << " | " << setw(10) << V.VerStr() << " | "
1064 << (*IF)->Describe(true) << endl;
1065 }
1066 }
1067 }
1068 }
1069 }
1070 }
1071
1072 SrcRecs.Restart();
1073 pkgSrcRecords::Parser *SrcParser;
1074 bool foundSomething = false;
1075 while ((SrcParser = SrcRecs.Find(*I, false)) != 0)
1076 {
1077 foundSomething = true;
1078 // Maybe support Release info here too eventually
1079 cout << setw(10) << SrcParser->Package() << " | "
1080 << setw(10) << SrcParser->Version() << " | "
1081 << SrcParser->Index().Describe(true) << endl;
1082 }
1083 if (foundSomething == true)
1084 _error->RevertToStack();
1085 else
1086 _error->MergeWithStack();
1087 }
1088
1089 return true;
1090 }
1091 /*}}}*/
1092 // GenCaches - Call the main cache generator /*{{{*/
1093 // ---------------------------------------------------------------------
1094 /* */
1095 static bool GenCaches(CommandLine &)
1096 {
1097 OpTextProgress Progress(*_config);
1098
1099 pkgCacheFile CacheFile;
1100 return CacheFile.BuildCaches(&Progress, true);
1101 }
1102 /*}}}*/
1103 static bool ShowHelp(CommandLine &) /*{{{*/
1104 {
1105 std::cout <<
1106 _("Usage: apt-cache [options] command\n"
1107 " apt-cache [options] show pkg1 [pkg2 ...]\n"
1108 "\n"
1109 "apt-cache queries and displays available information about installed\n"
1110 "and installable packages. It works exclusively on the data acquired\n"
1111 "into the local cache via the 'update' command of e.g. apt-get. The\n"
1112 "displayed information may therefore be outdated if the last update was\n"
1113 "too long ago, but in exchange apt-cache works independently of the\n"
1114 "availability of the configured sources (e.g. offline).\n");
1115 return true;
1116 }
1117 /*}}}*/
1118 static std::vector<aptDispatchWithHelp> GetCommands() /*{{{*/
1119 {
1120 return {
1121 {"gencaches",&GenCaches, nullptr},
1122 {"showsrc",&ShowSrcPackage, _("Show source records")},
1123 {"showpkg",&DumpPackage, nullptr},
1124 {"stats",&Stats, nullptr},
1125 {"dump",&Dump, nullptr},
1126 {"dumpavail",&DumpAvail, nullptr},
1127 {"unmet",&UnMet, nullptr},
1128 {"search",&DoSearch, _("Search the package list for a regex pattern")},
1129 {"depends",&Depends, _("Show raw dependency information for a package")},
1130 {"rdepends",&RDepends, _("Show reverse dependency information for a package")},
1131 {"dotty",&Dotty, nullptr},
1132 {"xvcg",&XVcg, nullptr},
1133 {"show",&ShowPackage, _("Show a readable record for the package")},
1134 {"pkgnames",&ShowPkgNames, _("List the names of all packages in the system")},
1135 {"showauto",&ShowAuto, nullptr},
1136 {"policy",&Policy, _("Show policy settings")},
1137 {"madison",&Madison, nullptr},
1138 {nullptr, nullptr, nullptr}
1139 };
1140 }
1141 /*}}}*/
1142 int main(int argc,const char *argv[]) /*{{{*/
1143 {
1144 InitLocale();
1145
1146 // Parse the command line and initialize the package library
1147 CommandLine CmdL;
1148 auto const Cmds = ParseCommandLine(CmdL, APT_CMD::APT_CACHE, &_config, &_system, argc, argv, &ShowHelp, &GetCommands);
1149
1150 InitOutput();
1151
1152 if (_config->Exists("APT::Cache::Generate") == true)
1153 _config->Set("pkgCacheFile::Generate", _config->FindB("APT::Cache::Generate", true));
1154
1155 return DispatchCommandLine(CmdL, Cmds);
1156 }
1157 /*}}}*/