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