]>
git.saurik.com Git - apt.git/blob - cmdline/apt-cache.cc
1 // -*- mode: cpp; mode: fold -*-
3 // $Id: apt-cache.cc,v 1.72 2004/04/30 04:34:03 mdz Exp $
4 /* ######################################################################
6 apt-cache - Manages the cache files
8 apt-cache provides some functions fo manipulating the cache files.
9 It uses the command line interface common to all the APT tools.
11 Returns 100 on failure, 0 on success.
13 ##################################################################### */
15 // Include Files /*{{{*/
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>
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-main.h>
71 // UnMet - Show unmet dependencies /*{{{*/
72 // ---------------------------------------------------------------------
74 static bool ShowUnMet(pkgCache::VerIterator
const &V
, bool const Important
)
77 for (pkgCache::DepIterator D
= V
.DependsList(); D
.end() == false;)
80 pkgCache::DepIterator Start
;
81 pkgCache::DepIterator End
;
84 // Important deps only
85 if (Important
== true)
86 if (End
->Type
!= pkgCache::Dep::PreDepends
&&
87 End
->Type
!= pkgCache::Dep::Depends
)
90 // Skip conflicts and replaces
91 if (End
.IsNegative() == true || End
->Type
== pkgCache::Dep::Replaces
)
94 // Verify the or group
96 pkgCache::DepIterator RealStart
= Start
;
99 // See if this dep is Ok
100 pkgCache::Version
**VList
= Start
.AllTargets();
121 ioprintf(cout
,_("Package %s version %s has an unmet dep:\n"),
122 V
.ParentPkg().FullName(true).c_str(),V
.VerStr());
125 // Print out the dep type
126 cout
<< " " << End
.DepType() << ": ";
132 cout
<< Start
.TargetPkg().FullName(true);
133 if (Start
.TargetVer() != 0)
134 cout
<< " (" << Start
.CompType() << " " << Start
.TargetVer() <<
147 static bool UnMet(CommandLine
&CmdL
)
149 bool const Important
= _config
->FindB("APT::Cache::Important",false);
151 pkgCacheFile CacheFile
;
152 if (unlikely(CacheFile
.GetPkgCache() == NULL
))
155 if (CmdL
.FileSize() <= 1)
157 for (pkgCache::PkgIterator P
= CacheFile
.GetPkgCache()->PkgBegin(); P
.end() == false; ++P
)
158 for (pkgCache::VerIterator V
= P
.VersionList(); V
.end() == false; ++V
)
159 if (ShowUnMet(V
, Important
) == false)
164 CacheSetHelperVirtuals
helper(true, GlobalError::NOTICE
);
165 APT::VersionList verset
= APT::VersionList::FromCommandLine(CacheFile
, CmdL
.FileList
+ 1,
166 APT::CacheSetHelper::CANDIDATE
, helper
);
167 for (APT::VersionList::iterator V
= verset
.begin(); V
!= verset
.end(); ++V
)
168 if (ShowUnMet(V
, Important
) == false)
174 // DumpPackage - Show a dump of a package record /*{{{*/
175 // ---------------------------------------------------------------------
177 static bool DumpPackage(CommandLine
&CmdL
)
179 pkgCacheFile CacheFile
;
180 APT::CacheSetHelper
helper(true, GlobalError::NOTICE
);
181 APT::PackageList pkgset
= APT::PackageList::FromCommandLine(CacheFile
, CmdL
.FileList
+ 1, helper
);
183 for (APT::PackageList::const_iterator Pkg
= pkgset
.begin(); Pkg
!= pkgset
.end(); ++Pkg
)
185 cout
<< "Package: " << Pkg
.FullName(true) << endl
;
186 cout
<< "Versions: " << endl
;
187 for (pkgCache::VerIterator Cur
= Pkg
.VersionList(); Cur
.end() != true; ++Cur
)
189 cout
<< Cur
.VerStr();
190 for (pkgCache::VerFileIterator Vf
= Cur
.FileList(); Vf
.end() == false; ++Vf
)
191 cout
<< " (" << Vf
.File().FileName() << ")";
193 for (pkgCache::DescIterator D
= Cur
.DescriptionList(); D
.end() == false; ++D
)
195 cout
<< " Description Language: " << D
.LanguageCode() << endl
196 << " File: " << D
.FileList().File().FileName() << endl
197 << " MD5: " << D
.md5() << endl
;
204 cout
<< "Reverse Depends: " << endl
;
205 for (pkgCache::DepIterator D
= Pkg
.RevDependsList(); D
.end() != true; ++D
)
207 cout
<< " " << D
.ParentPkg().FullName(true) << ',' << D
.TargetPkg().FullName(true);
209 cout
<< ' ' << DeNull(D
.TargetVer()) << endl
;
214 cout
<< "Dependencies: " << endl
;
215 for (pkgCache::VerIterator Cur
= Pkg
.VersionList(); Cur
.end() != true; ++Cur
)
217 cout
<< Cur
.VerStr() << " - ";
218 for (pkgCache::DepIterator Dep
= Cur
.DependsList(); Dep
.end() != true; ++Dep
)
219 cout
<< Dep
.TargetPkg().FullName(true) << " (" << (int)Dep
->CompareOp
<< " " << DeNull(Dep
.TargetVer()) << ") ";
223 cout
<< "Provides: " << endl
;
224 for (pkgCache::VerIterator Cur
= Pkg
.VersionList(); Cur
.end() != true; ++Cur
)
226 cout
<< Cur
.VerStr() << " - ";
227 for (pkgCache::PrvIterator Prv
= Cur
.ProvidesList(); Prv
.end() != true; ++Prv
)
228 cout
<< Prv
.ParentPkg().FullName(true) << " (= " << (Prv
->ProvideVersion
== 0 ? "" : Prv
.ProvideVersion()) << ") ";
231 cout
<< "Reverse Provides: " << endl
;
232 for (pkgCache::PrvIterator Prv
= Pkg
.ProvidesList(); Prv
.end() != true; ++Prv
)
233 cout
<< Prv
.OwnerPkg().FullName(true) << " " << Prv
.OwnerVer().VerStr() << " (= " << (Prv
->ProvideVersion
== 0 ? "" : Prv
.ProvideVersion()) << ")"<< endl
;
239 // ShowHashTableStats - Show stats about a hashtable /*{{{*/
240 // ---------------------------------------------------------------------
242 static map_pointer_t
PackageNext(pkgCache::Package
const * const P
) { return P
->NextPackage
; }
243 static map_pointer_t
GroupNext(pkgCache::Group
const * const G
) { return G
->Next
; }
245 static void ShowHashTableStats(std::string Type
,
247 map_pointer_t
*Hashtable
,
249 map_pointer_t(*Next
)(T
const * const))
251 // hashtable stats for the HashTable
252 unsigned long NumBuckets
= Size
;
253 unsigned long UsedBuckets
= 0;
254 unsigned long UnusedBuckets
= 0;
255 unsigned long LongestBucket
= 0;
256 unsigned long ShortestBucket
= NumBuckets
;
257 unsigned long Entries
= 0;
258 for (unsigned int i
=0; i
< NumBuckets
; ++i
)
260 T
*P
= StartP
+ Hashtable
[i
];
261 if(P
== 0 || P
== StartP
)
267 unsigned long ThisBucketSize
= 0;
268 for (; P
!= StartP
; P
= StartP
+ Next(P
))
270 Entries
+= ThisBucketSize
;
271 LongestBucket
= std::max(ThisBucketSize
, LongestBucket
);
272 ShortestBucket
= std::min(ThisBucketSize
, ShortestBucket
);
274 cout
<< "Total buckets in " << Type
<< ": " << NumBuckets
<< std::endl
;
275 cout
<< " Unused: " << UnusedBuckets
<< std::endl
;
276 cout
<< " Used: " << UsedBuckets
<< std::endl
;
277 cout
<< " Average entries: " << Entries
/(double)NumBuckets
<< std::endl
;
278 cout
<< " Longest: " << LongestBucket
<< std::endl
;
279 cout
<< " Shortest: " << ShortestBucket
<< std::endl
;
282 // Stats - Dump some nice statistics /*{{{*/
283 // ---------------------------------------------------------------------
285 static bool Stats(CommandLine
&CmdL
)
287 if (CmdL
.FileSize() > 1) {
288 _error
->Error(_("apt-cache stats does not take any arguments"));
292 pkgCacheFile CacheFile
;
293 pkgCache
*Cache
= CacheFile
.GetPkgCache();
295 if (unlikely(Cache
== NULL
))
298 cout
<< _("Total package names: ") << Cache
->Head().GroupCount
<< " (" <<
299 SizeToStr(Cache
->Head().GroupCount
*Cache
->Head().GroupSz
) << ')' << endl
300 << _("Total package structures: ") << Cache
->Head().PackageCount
<< " (" <<
301 SizeToStr(Cache
->Head().PackageCount
*Cache
->Head().PackageSz
) << ')' << endl
;
308 pkgCache::PkgIterator I
= Cache
->PkgBegin();
309 for (;I
.end() != true; ++I
)
311 if (I
->VersionList
!= 0 && I
->ProvidesList
== 0)
317 if (I
->VersionList
!= 0 && I
->ProvidesList
!= 0)
323 if (I
->VersionList
== 0 && I
->ProvidesList
!= 0)
326 if (I
.ProvidesList()->NextProvides
== 0)
334 if (I
->VersionList
== 0 && I
->ProvidesList
== 0)
340 cout
<< _(" Normal packages: ") << Normal
<< endl
;
341 cout
<< _(" Pure virtual packages: ") << Virtual
<< endl
;
342 cout
<< _(" Single virtual packages: ") << DVirt
<< endl
;
343 cout
<< _(" Mixed virtual packages: ") << NVirt
<< endl
;
344 cout
<< _(" Missing: ") << Missing
<< endl
;
346 cout
<< _("Total distinct versions: ") << Cache
->Head().VersionCount
<< " (" <<
347 SizeToStr(Cache
->Head().VersionCount
*Cache
->Head().VersionSz
) << ')' << endl
;
348 cout
<< _("Total distinct descriptions: ") << Cache
->Head().DescriptionCount
<< " (" <<
349 SizeToStr(Cache
->Head().DescriptionCount
*Cache
->Head().DescriptionSz
) << ')' << endl
;
350 cout
<< _("Total dependencies: ") << Cache
->Head().DependsCount
<< "/" << Cache
->Head().DependsDataCount
<< " (" <<
351 SizeToStr((Cache
->Head().DependsCount
*Cache
->Head().DependencySz
) +
352 (Cache
->Head().DependsDataCount
*Cache
->Head().DependencyDataSz
)) << ')' << endl
;
353 cout
<< _("Total ver/file relations: ") << Cache
->Head().VerFileCount
<< " (" <<
354 SizeToStr(Cache
->Head().VerFileCount
*Cache
->Head().VerFileSz
) << ')' << endl
;
355 cout
<< _("Total Desc/File relations: ") << Cache
->Head().DescFileCount
<< " (" <<
356 SizeToStr(Cache
->Head().DescFileCount
*Cache
->Head().DescFileSz
) << ')' << endl
;
357 cout
<< _("Total Provides mappings: ") << Cache
->Head().ProvidesCount
<< " (" <<
358 SizeToStr(Cache
->Head().ProvidesCount
*Cache
->Head().ProvidesSz
) << ')' << endl
;
361 std::set
<map_stringitem_t
> stritems
;
362 for (pkgCache::GrpIterator G
= Cache
->GrpBegin(); G
.end() == false; ++G
)
363 stritems
.insert(G
->Name
);
364 for (pkgCache::PkgIterator P
= Cache
->PkgBegin(); P
.end() == false; ++P
)
366 stritems
.insert(P
->Arch
);
367 for (pkgCache::VerIterator V
= P
.VersionList(); V
.end() == false; ++V
)
370 stritems
.insert(V
->VerStr
);
372 stritems
.insert(V
->Section
);
373 stritems
.insert(V
->SourcePkgName
);
374 stritems
.insert(V
->SourceVerStr
);
375 for (pkgCache::DepIterator D
= V
.DependsList(); D
.end() == false; ++D
)
378 stritems
.insert(D
->Version
);
380 for (pkgCache::DescIterator D
= V
.DescriptionList(); D
.end() == false; ++D
)
382 stritems
.insert(D
->md5sum
);
383 stritems
.insert(D
->language_code
);
386 for (pkgCache::PrvIterator Prv
= P
.ProvidesList(); Prv
.end() == false; ++Prv
)
388 if (Prv
->ProvideVersion
!= 0)
389 stritems
.insert(Prv
->ProvideVersion
);
392 for (pkgCache::RlsFileIterator F
= Cache
->RlsFileBegin(); F
!= Cache
->RlsFileEnd(); ++F
)
394 stritems
.insert(F
->FileName
);
395 stritems
.insert(F
->Archive
);
396 stritems
.insert(F
->Codename
);
397 stritems
.insert(F
->Version
);
398 stritems
.insert(F
->Origin
);
399 stritems
.insert(F
->Label
);
400 stritems
.insert(F
->Site
);
402 for (pkgCache::PkgFileIterator F
= Cache
->FileBegin(); F
!= Cache
->FileEnd(); ++F
)
404 stritems
.insert(F
->FileName
);
405 stritems
.insert(F
->Architecture
);
406 stritems
.insert(F
->Component
);
407 stritems
.insert(F
->IndexType
);
410 unsigned long Size
= 0;
411 for (std::set
<map_stringitem_t
>::const_iterator i
= stritems
.begin(); i
!= stritems
.end(); ++i
)
412 Size
+= strlen(Cache
->StrP
+ *i
) + 1;
413 cout
<< _("Total globbed strings: ") << stritems
.size() << " (" << SizeToStr(Size
) << ')' << endl
;
416 unsigned long Slack
= 0;
417 for (int I
= 0; I
!= 7; I
++)
418 Slack
+= Cache
->Head().Pools
[I
].ItemSize
*Cache
->Head().Pools
[I
].Count
;
419 cout
<< _("Total slack space: ") << SizeToStr(Slack
) << endl
;
421 unsigned long Total
= 0;
422 #define APT_CACHESIZE(X,Y) (Cache->Head().X * Cache->Head().Y)
423 Total
= Slack
+ Size
+
424 APT_CACHESIZE(GroupCount
, GroupSz
) +
425 APT_CACHESIZE(PackageCount
, PackageSz
) +
426 APT_CACHESIZE(VersionCount
, VersionSz
) +
427 APT_CACHESIZE(DescriptionCount
, DescriptionSz
) +
428 APT_CACHESIZE(DependsCount
, DependencySz
) +
429 APT_CACHESIZE(DependsDataCount
, DependencyDataSz
) +
430 APT_CACHESIZE(ReleaseFileCount
, ReleaseFileSz
) +
431 APT_CACHESIZE(PackageFileCount
, PackageFileSz
) +
432 APT_CACHESIZE(VerFileCount
, VerFileSz
) +
433 APT_CACHESIZE(DescFileCount
, DescFileSz
) +
434 APT_CACHESIZE(ProvidesCount
, ProvidesSz
) +
435 (2 * Cache
->Head().GetHashTableSize() * sizeof(map_id_t
));
436 cout
<< _("Total space accounted for: ") << SizeToStr(Total
) << endl
;
440 ShowHashTableStats
<pkgCache::Package
>("PkgHashTable", Cache
->PkgP
, Cache
->Head().PkgHashTableP(), Cache
->Head().GetHashTableSize(), PackageNext
);
441 ShowHashTableStats
<pkgCache::Group
>("GrpHashTable", Cache
->GrpP
, Cache
->Head().GrpHashTableP(), Cache
->Head().GetHashTableSize(), GroupNext
);
446 // Dump - show everything /*{{{*/
447 // ---------------------------------------------------------------------
448 /* This is worthless except fer debugging things */
449 static bool Dump(CommandLine
&)
451 pkgCacheFile CacheFile
;
452 pkgCache
*Cache
= CacheFile
.GetPkgCache();
453 if (unlikely(Cache
== NULL
))
456 std::cout
<< "Using Versioning System: " << Cache
->VS
->Label
<< std::endl
;
458 for (pkgCache::PkgIterator P
= Cache
->PkgBegin(); P
.end() == false; ++P
)
460 std::cout
<< "Package: " << P
.FullName(true) << std::endl
;
461 for (pkgCache::VerIterator V
= P
.VersionList(); V
.end() == false; ++V
)
463 std::cout
<< " Version: " << V
.VerStr() << std::endl
;
464 std::cout
<< " File: " << V
.FileList().File().FileName() << std::endl
;
465 for (pkgCache::DepIterator D
= V
.DependsList(); D
.end() == false; ++D
)
466 std::cout
<< " Depends: " << D
.TargetPkg().FullName(true) << ' ' <<
467 DeNull(D
.TargetVer()) << std::endl
;
468 for (pkgCache::DescIterator D
= V
.DescriptionList(); D
.end() == false; ++D
)
470 std::cout
<< " Description Language: " << D
.LanguageCode() << std::endl
471 << " File: " << D
.FileList().File().FileName() << std::endl
472 << " MD5: " << D
.md5() << std::endl
;
477 for (pkgCache::PkgFileIterator F
= Cache
->FileBegin(); F
.end() == false; ++F
)
479 std::cout
<< "File: " << F
.FileName() << std::endl
;
480 std::cout
<< " Type: " << F
.IndexType() << std::endl
;
481 std::cout
<< " Size: " << F
->Size
<< std::endl
;
482 std::cout
<< " ID: " << F
->ID
<< std::endl
;
483 std::cout
<< " Flags: " << F
->Flags
<< std::endl
;
484 std::cout
<< " Time: " << TimeRFC1123(F
->mtime
) << std::endl
;
485 std::cout
<< " Archive: " << DeNull(F
.Archive()) << std::endl
;
486 std::cout
<< " Component: " << DeNull(F
.Component()) << std::endl
;
487 std::cout
<< " Version: " << DeNull(F
.Version()) << std::endl
;
488 std::cout
<< " Origin: " << DeNull(F
.Origin()) << std::endl
;
489 std::cout
<< " Site: " << DeNull(F
.Site()) << std::endl
;
490 std::cout
<< " Label: " << DeNull(F
.Label()) << std::endl
;
491 std::cout
<< " Architecture: " << DeNull(F
.Architecture()) << std::endl
;
497 // DumpAvail - Print out the available list /*{{{*/
498 // ---------------------------------------------------------------------
499 /* This is needed to make dpkg --merge happy.. I spent a bit of time to
500 make this run really fast, perhaps I went a little overboard.. */
501 static bool DumpAvail(CommandLine
&)
503 pkgCacheFile CacheFile
;
504 pkgCache
*Cache
= CacheFile
.GetPkgCache();
505 if (unlikely(Cache
== NULL
|| CacheFile
.BuildPolicy() == false))
508 unsigned long Count
= Cache
->HeaderP
->PackageCount
+1;
509 pkgCache::VerFile
**VFList
= new pkgCache::VerFile
*[Count
];
510 memset(VFList
,0,sizeof(*VFList
)*Count
);
512 // Map versions that we want to write out onto the VerList array.
513 for (pkgCache::PkgIterator P
= Cache
->PkgBegin(); P
.end() == false; ++P
)
515 if (P
->VersionList
== 0)
518 /* Find the proper version to use. If the policy says there are no
519 possible selections we return the installed version, if available..
520 This prevents dselect from making it obsolete. */
521 pkgCache::VerIterator V
= CacheFile
.GetPolicy()->GetCandidateVer(P
);
524 if (P
->CurrentVer
== 0)
529 pkgCache::VerFileIterator VF
= V
.FileList();
530 for (; VF
.end() == false ; ++VF
)
531 if ((VF
.File()->Flags
& pkgCache::Flag::NotSource
) == 0)
534 /* Okay, here we have a bit of a problem.. The policy has selected the
535 currently installed package - however it only exists in the
536 status file.. We need to write out something or dselect will mark
537 the package as obsolete! Thus we emit the status file entry, but
538 below we remove the status line to make it valid for the
539 available file. However! We only do this if their do exist *any*
540 non-source versions of the package - that way the dselect obsolete
541 handling works OK. */
542 if (VF
.end() == true)
544 for (pkgCache::VerIterator Cur
= P
.VersionList(); Cur
.end() != true; ++Cur
)
546 for (VF
= Cur
.FileList(); VF
.end() == false; ++VF
)
548 if ((VF
.File()->Flags
& pkgCache::Flag::NotSource
) == 0)
555 if (VF
.end() == false)
563 LocalitySort(VFList
,Count
,sizeof(*VFList
));
565 std::vector
<pkgTagSection::Tag
> RW
;
566 RW
.push_back(pkgTagSection::Tag::Remove("Status"));
567 RW
.push_back(pkgTagSection::Tag::Remove("Config-Version"));
569 stdoutfd
.OpenDescriptor(STDOUT_FILENO
, FileFd::WriteOnly
, false);
571 // Iterate over all the package files and write them out.
572 char *Buffer
= new char[Cache
->HeaderP
->MaxVerFileSize
+10];
573 for (pkgCache::VerFile
**J
= VFList
; *J
!= 0;)
575 pkgCache::PkgFileIterator
File(*Cache
,(*J
)->File
+ Cache
->PkgFileP
);
576 if (File
.IsOk() == false)
578 _error
->Error(_("Package file %s is out of sync."),File
.FileName());
582 FileFd
PkgF(File
.FileName(),FileFd::ReadOnly
, FileFd::Extension
);
583 if (_error
->PendingError() == true)
586 /* Write all of the records from this package file, since we
587 already did locality sorting we can now just seek through the
588 file in read order. We apply 1 more optimization here, since often
589 there will be < 1 byte gaps between records (for the \n) we read that
590 into the next buffer and offset a bit.. */
591 unsigned long Pos
= 0;
594 if ((*J
)->File
+ Cache
->PkgFileP
!= File
)
597 const pkgCache::VerFile
&VF
= **J
;
599 // Read the record and then write it out again.
600 unsigned long Jitter
= VF
.Offset
- Pos
;
603 if (PkgF
.Seek(VF
.Offset
) == false)
608 if (PkgF
.Read(Buffer
,VF
.Size
+ Jitter
) == false)
610 Buffer
[VF
.Size
+ Jitter
] = '\n';
613 if ((File
->Flags
& pkgCache::Flag::NotSource
) == pkgCache::Flag::NotSource
)
616 if (Tags
.Scan(Buffer
+Jitter
,VF
.Size
+1) == false ||
617 Tags
.Write(stdoutfd
, NULL
, RW
) == false ||
618 stdoutfd
.Write("\n", 1) == false)
620 _error
->Error("Internal Error, Unable to parse a package record");
626 if (stdoutfd
.Write(Buffer
+ Jitter
, VF
.Size
+ 1) == false)
630 Pos
= VF
.Offset
+ VF
.Size
;
633 if (_error
->PendingError() == true)
639 return !_error
->PendingError();
642 // xvcg - Generate a graph for xvcg /*{{{*/
643 // ---------------------------------------------------------------------
644 // Code contributed from Junichi Uekawa <dancer@debian.org> on 20 June 2002.
646 static bool XVcg(CommandLine
&CmdL
)
648 pkgCacheFile CacheFile
;
649 pkgCache
*Cache
= CacheFile
.GetPkgCache();
650 if (unlikely(Cache
== NULL
))
653 bool GivenOnly
= _config
->FindB("APT::Cache::GivenOnly",false);
655 /* Normal packages are boxes
656 Pure Provides are triangles
658 rhomb are missing packages*/
659 const char *Shapes
[] = {"ellipse","triangle","box","rhomb"};
661 /* Initialize the list of packages to show.
663 2 = To Show no recurse
664 3 = Emitted no recurse
667 enum States
{None
=0, ToShow
, ToShowNR
, DoneNR
, Done
};
668 enum TheFlags
{ForceNR
=(1<<0)};
669 unsigned char *Show
= new unsigned char[Cache
->Head().PackageCount
];
670 unsigned char *Flags
= new unsigned char[Cache
->Head().PackageCount
];
671 unsigned char *ShapeMap
= new unsigned char[Cache
->Head().PackageCount
];
673 // Show everything if no arguments given
674 if (CmdL
.FileList
[1] == 0)
675 for (unsigned long I
= 0; I
!= Cache
->Head().PackageCount
; I
++)
678 for (unsigned long I
= 0; I
!= Cache
->Head().PackageCount
; I
++)
680 memset(Flags
,0,sizeof(*Flags
)*Cache
->Head().PackageCount
);
683 for (pkgCache::PkgIterator Pkg
= Cache
->PkgBegin(); Pkg
.end() == false; ++Pkg
)
685 if (Pkg
->VersionList
== 0)
688 if (Pkg
->ProvidesList
== 0)
689 ShapeMap
[Pkg
->ID
] = 0;
691 ShapeMap
[Pkg
->ID
] = 1;
696 if (Pkg
->ProvidesList
== 0)
697 ShapeMap
[Pkg
->ID
] = 2;
699 ShapeMap
[Pkg
->ID
] = 3;
703 // Load the list of packages from the command line into the show list
704 APT::CacheSetHelper
helper(true, GlobalError::NOTICE
);
705 std::list
<APT::CacheSetHelper::PkgModifier
> mods
;
706 mods
.push_back(APT::CacheSetHelper::PkgModifier(0, ",", APT::PackageSet::Modifier::POSTFIX
));
707 mods
.push_back(APT::CacheSetHelper::PkgModifier(1, "^", APT::PackageSet::Modifier::POSTFIX
));
708 std::map
<unsigned short, APT::PackageSet
> pkgsets
=
709 APT::PackageSet::GroupedFromCommandLine(CacheFile
, CmdL
.FileList
+ 1, mods
, 0, helper
);
711 for (APT::PackageSet::const_iterator Pkg
= pkgsets
[0].begin();
712 Pkg
!= pkgsets
[0].end(); ++Pkg
)
713 Show
[Pkg
->ID
] = ToShow
;
714 for (APT::PackageSet::const_iterator Pkg
= pkgsets
[1].begin();
715 Pkg
!= pkgsets
[1].end(); ++Pkg
)
717 Show
[Pkg
->ID
] = ToShow
;
718 Flags
[Pkg
->ID
] |= ForceNR
;
722 cout
<< "graph: { title: \"packages\"" << endl
<<
723 "xmax: 700 ymax: 700 x: 30 y: 30" << endl
<<
724 "layout_downfactor: 8" << endl
;
730 for (pkgCache::PkgIterator Pkg
= Cache
->PkgBegin(); Pkg
.end() == false; ++Pkg
)
732 // See we need to show this package
733 if (Show
[Pkg
->ID
] == None
|| Show
[Pkg
->ID
] >= DoneNR
)
736 //printf ("node: { title: \"%s\" label: \"%s\" }\n", Pkg.Name(), Pkg.Name());
739 if (Show
[Pkg
->ID
] == ToShowNR
|| (Flags
[Pkg
->ID
] & ForceNR
) == ForceNR
)
741 // Pure Provides and missing packages have no deps!
742 if (ShapeMap
[Pkg
->ID
] == 0 || ShapeMap
[Pkg
->ID
] == 1)
743 Show
[Pkg
->ID
] = Done
;
745 Show
[Pkg
->ID
] = DoneNR
;
748 Show
[Pkg
->ID
] = Done
;
751 // No deps to map out
752 if (Pkg
->VersionList
== 0 || Show
[Pkg
->ID
] == DoneNR
)
755 pkgCache::VerIterator Ver
= Pkg
.VersionList();
756 for (pkgCache::DepIterator D
= Ver
.DependsList(); D
.end() == false; ++D
)
758 // See if anything can meet this dep
759 // Walk along the actual package providing versions
761 pkgCache::PkgIterator DPkg
= D
.TargetPkg();
762 for (pkgCache::VerIterator I
= DPkg
.VersionList();
763 I
.end() == false && Hit
== false; ++I
)
765 if (Cache
->VS
->CheckDep(I
.VerStr(),D
->CompareOp
,D
.TargetVer()) == true)
769 // Follow all provides
770 for (pkgCache::PrvIterator I
= DPkg
.ProvidesList();
771 I
.end() == false && Hit
== false; ++I
)
773 if (Cache
->VS
->CheckDep(I
.ProvideVersion(),D
->CompareOp
,D
.TargetVer()) == false)
778 // Only graph critical deps
779 if (D
.IsCritical() == true)
781 printf ("edge: { sourcename: \"%s\" targetname: \"%s\" class: 2 ",Pkg
.FullName(true).c_str(), D
.TargetPkg().FullName(true).c_str() );
783 // Colour the node for recursion
784 if (Show
[D
.TargetPkg()->ID
] <= DoneNR
)
786 /* If a conflicts does not meet anything in the database
787 then show the relation but do not recurse */
788 if (Hit
== false && D
.IsNegative() == true)
790 if (Show
[D
.TargetPkg()->ID
] == None
&&
791 Show
[D
.TargetPkg()->ID
] != ToShow
)
792 Show
[D
.TargetPkg()->ID
] = ToShowNR
;
796 if (GivenOnly
== true && Show
[D
.TargetPkg()->ID
] != ToShow
)
797 Show
[D
.TargetPkg()->ID
] = ToShowNR
;
799 Show
[D
.TargetPkg()->ID
] = ToShow
;
806 case pkgCache::Dep::Conflicts
:
807 printf("label: \"conflicts\" color: lightgreen }\n");
809 case pkgCache::Dep::DpkgBreaks
:
810 printf("label: \"breaks\" color: lightgreen }\n");
812 case pkgCache::Dep::Obsoletes
:
813 printf("label: \"obsoletes\" color: lightgreen }\n");
816 case pkgCache::Dep::PreDepends
:
817 printf("label: \"predepends\" color: blue }\n");
829 /* Draw the box colours after the fact since we can not tell what colour
830 they should be until everything is finished drawing */
831 for (pkgCache::PkgIterator Pkg
= Cache
->PkgBegin(); Pkg
.end() == false; ++Pkg
)
833 if (Show
[Pkg
->ID
] < DoneNR
)
836 if (Show
[Pkg
->ID
] == DoneNR
)
837 printf("node: { title: \"%s\" label: \"%s\" color: orange shape: %s }\n", Pkg
.FullName(true).c_str(), Pkg
.FullName(true).c_str(),
838 Shapes
[ShapeMap
[Pkg
->ID
]]);
840 printf("node: { title: \"%s\" label: \"%s\" shape: %s }\n", Pkg
.FullName(true).c_str(), Pkg
.FullName(true).c_str(),
841 Shapes
[ShapeMap
[Pkg
->ID
]]);
853 // Dotty - Generate a graph for Dotty /*{{{*/
854 // ---------------------------------------------------------------------
855 /* Dotty is the graphvis program for generating graphs. It is a fairly
856 simple queuing algorithm that just writes dependencies and nodes.
857 http://www.research.att.com/sw/tools/graphviz/ */
858 static bool Dotty(CommandLine
&CmdL
)
860 pkgCacheFile CacheFile
;
861 pkgCache
*Cache
= CacheFile
.GetPkgCache();
862 if (unlikely(Cache
== NULL
))
865 bool GivenOnly
= _config
->FindB("APT::Cache::GivenOnly",false);
867 /* Normal packages are boxes
868 Pure Provides are triangles
870 Hexagons are missing packages*/
871 const char *Shapes
[] = {"hexagon","triangle","box","diamond"};
873 /* Initialize the list of packages to show.
875 2 = To Show no recurse
876 3 = Emitted no recurse
879 enum States
{None
=0, ToShow
, ToShowNR
, DoneNR
, Done
};
880 enum TheFlags
{ForceNR
=(1<<0)};
881 unsigned char *Show
= new unsigned char[Cache
->Head().PackageCount
];
882 unsigned char *Flags
= new unsigned char[Cache
->Head().PackageCount
];
883 unsigned char *ShapeMap
= new unsigned char[Cache
->Head().PackageCount
];
885 // Show everything if no arguments given
886 if (CmdL
.FileList
[1] == 0)
887 for (unsigned long I
= 0; I
!= Cache
->Head().PackageCount
; I
++)
890 for (unsigned long I
= 0; I
!= Cache
->Head().PackageCount
; I
++)
892 memset(Flags
,0,sizeof(*Flags
)*Cache
->Head().PackageCount
);
895 for (pkgCache::PkgIterator Pkg
= Cache
->PkgBegin(); Pkg
.end() == false; ++Pkg
)
897 if (Pkg
->VersionList
== 0)
900 if (Pkg
->ProvidesList
== 0)
901 ShapeMap
[Pkg
->ID
] = 0;
903 ShapeMap
[Pkg
->ID
] = 1;
908 if (Pkg
->ProvidesList
== 0)
909 ShapeMap
[Pkg
->ID
] = 2;
911 ShapeMap
[Pkg
->ID
] = 3;
915 // Load the list of packages from the command line into the show list
916 APT::CacheSetHelper
helper(true, GlobalError::NOTICE
);
917 std::list
<APT::CacheSetHelper::PkgModifier
> mods
;
918 mods
.push_back(APT::CacheSetHelper::PkgModifier(0, ",", APT::PackageSet::Modifier::POSTFIX
));
919 mods
.push_back(APT::CacheSetHelper::PkgModifier(1, "^", APT::PackageSet::Modifier::POSTFIX
));
920 std::map
<unsigned short, APT::PackageSet
> pkgsets
=
921 APT::PackageSet::GroupedFromCommandLine(CacheFile
, CmdL
.FileList
+ 1, mods
, 0, helper
);
923 for (APT::PackageSet::const_iterator Pkg
= pkgsets
[0].begin();
924 Pkg
!= pkgsets
[0].end(); ++Pkg
)
925 Show
[Pkg
->ID
] = ToShow
;
926 for (APT::PackageSet::const_iterator Pkg
= pkgsets
[1].begin();
927 Pkg
!= pkgsets
[1].end(); ++Pkg
)
929 Show
[Pkg
->ID
] = ToShow
;
930 Flags
[Pkg
->ID
] |= ForceNR
;
934 printf("digraph packages {\n");
935 printf("concentrate=true;\n");
936 printf("size=\"30,40\";\n");
942 for (pkgCache::PkgIterator Pkg
= Cache
->PkgBegin(); Pkg
.end() == false; ++Pkg
)
944 // See we need to show this package
945 if (Show
[Pkg
->ID
] == None
|| Show
[Pkg
->ID
] >= DoneNR
)
949 if (Show
[Pkg
->ID
] == ToShowNR
|| (Flags
[Pkg
->ID
] & ForceNR
) == ForceNR
)
951 // Pure Provides and missing packages have no deps!
952 if (ShapeMap
[Pkg
->ID
] == 0 || ShapeMap
[Pkg
->ID
] == 1)
953 Show
[Pkg
->ID
] = Done
;
955 Show
[Pkg
->ID
] = DoneNR
;
958 Show
[Pkg
->ID
] = Done
;
961 // No deps to map out
962 if (Pkg
->VersionList
== 0 || Show
[Pkg
->ID
] == DoneNR
)
965 pkgCache::VerIterator Ver
= Pkg
.VersionList();
966 for (pkgCache::DepIterator D
= Ver
.DependsList(); D
.end() == false; ++D
)
968 // See if anything can meet this dep
969 // Walk along the actual package providing versions
971 pkgCache::PkgIterator DPkg
= D
.TargetPkg();
972 for (pkgCache::VerIterator I
= DPkg
.VersionList();
973 I
.end() == false && Hit
== false; ++I
)
975 if (Cache
->VS
->CheckDep(I
.VerStr(),D
->CompareOp
,D
.TargetVer()) == true)
979 // Follow all provides
980 for (pkgCache::PrvIterator I
= DPkg
.ProvidesList();
981 I
.end() == false && Hit
== false; ++I
)
983 if (Cache
->VS
->CheckDep(I
.ProvideVersion(),D
->CompareOp
,D
.TargetVer()) == false)
987 // Only graph critical deps
988 if (D
.IsCritical() == true)
990 printf("\"%s\" -> \"%s\"",Pkg
.FullName(true).c_str(),D
.TargetPkg().FullName(true).c_str());
992 // Colour the node for recursion
993 if (Show
[D
.TargetPkg()->ID
] <= DoneNR
)
995 /* If a conflicts does not meet anything in the database
996 then show the relation but do not recurse */
997 if (Hit
== false && D
.IsNegative() == true)
999 if (Show
[D
.TargetPkg()->ID
] == None
&&
1000 Show
[D
.TargetPkg()->ID
] != ToShow
)
1001 Show
[D
.TargetPkg()->ID
] = ToShowNR
;
1005 if (GivenOnly
== true && Show
[D
.TargetPkg()->ID
] != ToShow
)
1006 Show
[D
.TargetPkg()->ID
] = ToShowNR
;
1008 Show
[D
.TargetPkg()->ID
] = ToShow
;
1015 case pkgCache::Dep::Conflicts
:
1016 case pkgCache::Dep::Obsoletes
:
1017 case pkgCache::Dep::DpkgBreaks
:
1018 printf("[color=springgreen];\n");
1021 case pkgCache::Dep::PreDepends
:
1022 printf("[color=blue];\n");
1034 /* Draw the box colours after the fact since we can not tell what colour
1035 they should be until everything is finished drawing */
1036 for (pkgCache::PkgIterator Pkg
= Cache
->PkgBegin(); Pkg
.end() == false; ++Pkg
)
1038 if (Show
[Pkg
->ID
] < DoneNR
)
1041 // Orange box for early recursion stoppage
1042 if (Show
[Pkg
->ID
] == DoneNR
)
1043 printf("\"%s\" [color=orange,shape=%s];\n",Pkg
.FullName(true).c_str(),
1044 Shapes
[ShapeMap
[Pkg
->ID
]]);
1046 printf("\"%s\" [shape=%s];\n",Pkg
.FullName(true).c_str(),
1047 Shapes
[ShapeMap
[Pkg
->ID
]]);
1057 /* ShowAuto - show automatically installed packages (sorted) {{{*/
1058 static bool ShowAuto(CommandLine
&)
1060 pkgCacheFile CacheFile
;
1061 pkgCache
*Cache
= CacheFile
.GetPkgCache();
1062 pkgDepCache
*DepCache
= CacheFile
.GetDepCache();
1063 if (unlikely(Cache
== NULL
|| DepCache
== NULL
))
1066 std::vector
<string
> packages
;
1067 packages
.reserve(Cache
->HeaderP
->PackageCount
/ 3);
1069 for (pkgCache::PkgIterator P
= Cache
->PkgBegin(); P
.end() == false; ++P
)
1070 if ((*DepCache
)[P
].Flags
& pkgCache::Flag::Auto
)
1071 packages
.push_back(P
.Name());
1073 std::sort(packages
.begin(), packages
.end());
1075 for (vector
<string
>::iterator I
= packages
.begin(); I
!= packages
.end(); ++I
)
1078 _error
->Notice(_("This command is deprecated. Please use 'apt-mark showauto' instead."));
1082 // ShowPkgNames - Show package names /*{{{*/
1083 // ---------------------------------------------------------------------
1084 /* This does a prefix match on the first argument */
1085 static bool ShowPkgNames(CommandLine
&CmdL
)
1087 pkgCacheFile CacheFile
;
1088 if (unlikely(CacheFile
.BuildCaches(NULL
, false) == false))
1090 pkgCache::GrpIterator I
= CacheFile
.GetPkgCache()->GrpBegin();
1091 bool const All
= _config
->FindB("APT::Cache::AllNames","false");
1093 if (CmdL
.FileList
[1] != 0)
1095 for (;I
.end() != true; ++I
)
1097 if (All
== false && I
->FirstPackage
== 0)
1099 if (I
.FindPkg("any")->VersionList
== 0)
1101 if (strncmp(I
.Name(),CmdL
.FileList
[1],strlen(CmdL
.FileList
[1])) == 0)
1102 cout
<< I
.Name() << endl
;
1109 for (;I
.end() != true; ++I
)
1111 if (All
== false && I
->FirstPackage
== 0)
1113 if (I
.FindPkg("any")->VersionList
== 0)
1115 cout
<< I
.Name() << endl
;
1121 // Madison - Look a bit like katie's madison /*{{{*/
1122 // ---------------------------------------------------------------------
1124 static bool Madison(CommandLine
&CmdL
)
1126 pkgCacheFile CacheFile
;
1127 pkgSourceList
*SrcList
= CacheFile
.GetSourceList();
1132 // Create the src text record parsers and ignore errors about missing
1133 // deb-src lines that are generated from pkgSrcRecords::pkgSrcRecords
1134 pkgSrcRecords
SrcRecs(*SrcList
);
1135 if (_error
->PendingError() == true)
1138 APT::CacheSetHelper
helper(true, GlobalError::NOTICE
);
1139 for (const char **I
= CmdL
.FileList
+ 1; *I
!= 0; I
++)
1141 _error
->PushToStack();
1142 APT::PackageList pkgset
= APT::PackageList::FromString(CacheFile
, *I
, helper
);
1143 for (APT::PackageList::const_iterator Pkg
= pkgset
.begin(); Pkg
!= pkgset
.end(); ++Pkg
)
1145 for (pkgCache::VerIterator V
= Pkg
.VersionList(); V
.end() == false; ++V
)
1147 for (pkgCache::VerFileIterator VF
= V
.FileList(); VF
.end() == false; ++VF
)
1149 // This might be nice, but wouldn't uniquely identify the source -mdz
1150 // if (VF.File().Archive() != 0)
1152 // cout << setw(10) << Pkg.Name() << " | " << setw(10) << V.VerStr() << " | "
1153 // << VF.File().Archive() << endl;
1156 // Locate the associated index files so we can derive a description
1157 for (pkgSourceList::const_iterator S
= SrcList
->begin(); S
!= SrcList
->end(); ++S
)
1159 vector
<pkgIndexFile
*> *Indexes
= (*S
)->GetIndexFiles();
1160 for (vector
<pkgIndexFile
*>::const_iterator IF
= Indexes
->begin();
1161 IF
!= Indexes
->end(); ++IF
)
1163 if ((*IF
)->FindInCache(*(VF
.File().Cache())) == VF
.File())
1165 cout
<< setw(10) << Pkg
.FullName(true) << " | " << setw(10) << V
.VerStr() << " | "
1166 << (*IF
)->Describe(true) << endl
;
1175 pkgSrcRecords::Parser
*SrcParser
;
1176 bool foundSomething
= false;
1177 while ((SrcParser
= SrcRecs
.Find(*I
, false)) != 0)
1179 foundSomething
= true;
1180 // Maybe support Release info here too eventually
1181 cout
<< setw(10) << SrcParser
->Package() << " | "
1182 << setw(10) << SrcParser
->Version() << " | "
1183 << SrcParser
->Index().Describe(true) << endl
;
1185 if (foundSomething
== true)
1186 _error
->RevertToStack();
1188 _error
->MergeWithStack();
1194 // GenCaches - Call the main cache generator /*{{{*/
1195 // ---------------------------------------------------------------------
1197 static bool GenCaches(CommandLine
&)
1199 OpTextProgress
Progress(*_config
);
1201 pkgCacheFile CacheFile
;
1202 return CacheFile
.BuildCaches(&Progress
, true);
1205 bool ShowHelp(CommandLine
&) /*{{{*/
1208 _("Usage: apt-cache [options] command\n"
1209 " apt-cache [options] show pkg1 [pkg2 ...]\n"
1211 "apt-cache queries and displays available information about installed\n"
1212 "as well as installable packages. It works exclusively on the data\n"
1213 "acquired via the 'update' command of e.g. apt-get to the local cache.\n"
1214 "The displayed information can therefore be outdated if the last update\n"
1215 "is too long ago, but in exchange apt-cache works independently of the\n"
1216 "availability of the configured sources (e.g. offline).\n");
1220 std::vector
<aptDispatchWithHelp
> GetCommands() /*{{{*/
1223 {"gencaches",&GenCaches
, nullptr},
1224 {"showsrc",&ShowSrcPackage
, _("Show source records")},
1225 {"showpkg",&DumpPackage
, nullptr},
1226 {"stats",&Stats
, nullptr},
1227 {"dump",&Dump
, nullptr},
1228 {"dumpavail",&DumpAvail
, nullptr},
1229 {"unmet",&UnMet
, nullptr},
1230 {"search",&DoSearch
, _("Search the package list for a regex pattern")},
1231 {"depends",&Depends
, _("Show raw dependency information for a package")},
1232 {"rdepends",&RDepends
, _("Show reverse dependency information for a package")},
1233 {"dotty",&Dotty
, nullptr},
1234 {"xvcg",&XVcg
, nullptr},
1235 {"show",&ShowPackage
, _("Show a readable record for the package")},
1236 {"pkgnames",&ShowPkgNames
, _("List the names of all packages in the system")},
1237 {"showauto",&ShowAuto
, nullptr},
1238 {"policy",&Policy
, _("Show policy settings")},
1239 {"madison",&Madison
, nullptr},
1240 {nullptr, nullptr, nullptr}
1244 int main(int argc
,const char *argv
[]) /*{{{*/
1248 // Parse the command line and initialize the package library
1250 auto const Cmds
= ParseCommandLine(CmdL
, APT_CMD::APT_CACHE
, &_config
, &_system
, argc
, argv
);
1254 if (_config
->Exists("APT::Cache::Generate") == true)
1255 _config
->Set("pkgCacheFile::Generate", _config
->FindB("APT::Cache::Generate", true));
1257 return DispatchCommandLine(CmdL
, Cmds
);