]> git.saurik.com Git - apt.git/blob - cmdline/apt-cache.cc
Set STRIP_FROM_PATH for doxygen
[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
47 #include <regex.h>
48 #include <stddef.h>
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <unistd.h>
52 #include <algorithm>
53 #include <cstring>
54 #include <iomanip>
55 #include <iostream>
56 #include <list>
57 #include <map>
58 #include <set>
59 #include <string>
60 #include <vector>
61
62 #include <apti18n.h>
63 /*}}}*/
64
65 using namespace std;
66
67 // LocalitySort - Sort a version list by package file locality /*{{{*/
68 // ---------------------------------------------------------------------
69 /* */
70 static int LocalityCompare(const void *a, const void *b)
71 {
72 pkgCache::VerFile *A = *(pkgCache::VerFile **)a;
73 pkgCache::VerFile *B = *(pkgCache::VerFile **)b;
74
75 if (A == 0 && B == 0)
76 return 0;
77 if (A == 0)
78 return 1;
79 if (B == 0)
80 return -1;
81
82 if (A->File == B->File)
83 return A->Offset - B->Offset;
84 return A->File - B->File;
85 }
86
87 static void LocalitySort(pkgCache::VerFile **begin,
88 unsigned long Count,size_t Size)
89 {
90 qsort(begin,Count,Size,LocalityCompare);
91 }
92
93 static void LocalitySort(pkgCache::DescFile **begin,
94 unsigned long Count,size_t Size)
95 {
96 qsort(begin,Count,Size,LocalityCompare);
97 }
98 /*}}}*/
99 // UnMet - Show unmet dependencies /*{{{*/
100 // ---------------------------------------------------------------------
101 /* */
102 static bool ShowUnMet(pkgCache::VerIterator const &V, bool const Important)
103 {
104 bool Header = false;
105 for (pkgCache::DepIterator D = V.DependsList(); D.end() == false;)
106 {
107 // Collect or groups
108 pkgCache::DepIterator Start;
109 pkgCache::DepIterator End;
110 D.GlobOr(Start,End);
111
112 // Important deps only
113 if (Important == true)
114 if (End->Type != pkgCache::Dep::PreDepends &&
115 End->Type != pkgCache::Dep::Depends)
116 continue;
117
118 // Skip conflicts and replaces
119 if (End.IsNegative() == true)
120 continue;
121
122 // Verify the or group
123 bool OK = false;
124 pkgCache::DepIterator RealStart = Start;
125 do
126 {
127 // See if this dep is Ok
128 pkgCache::Version **VList = Start.AllTargets();
129 if (*VList != 0)
130 {
131 OK = true;
132 delete [] VList;
133 break;
134 }
135 delete [] VList;
136
137 if (Start == End)
138 break;
139 ++Start;
140 }
141 while (1);
142
143 // The group is OK
144 if (OK == true)
145 continue;
146
147 // Oops, it failed..
148 if (Header == false)
149 ioprintf(cout,_("Package %s version %s has an unmet dep:\n"),
150 V.ParentPkg().FullName(true).c_str(),V.VerStr());
151 Header = true;
152
153 // Print out the dep type
154 cout << " " << End.DepType() << ": ";
155
156 // Show the group
157 Start = RealStart;
158 do
159 {
160 cout << Start.TargetPkg().FullName(true);
161 if (Start.TargetVer() != 0)
162 cout << " (" << Start.CompType() << " " << Start.TargetVer() <<
163 ")";
164 if (Start == End)
165 break;
166 cout << " | ";
167 ++Start;
168 }
169 while (1);
170
171 cout << endl;
172 }
173 return true;
174 }
175 static bool UnMet(CommandLine &CmdL)
176 {
177 bool const Important = _config->FindB("APT::Cache::Important",false);
178
179 pkgCacheFile CacheFile;
180 if (unlikely(CacheFile.GetPkgCache() == NULL))
181 return false;
182
183 if (CmdL.FileSize() <= 1)
184 {
185 for (pkgCache::PkgIterator P = CacheFile.GetPkgCache()->PkgBegin(); P.end() == false; ++P)
186 for (pkgCache::VerIterator V = P.VersionList(); V.end() == false; ++V)
187 if (ShowUnMet(V, Important) == false)
188 return false;
189 }
190 else
191 {
192 CacheSetHelperVirtuals helper(true, GlobalError::NOTICE);
193 APT::VersionList verset = APT::VersionList::FromCommandLine(CacheFile, CmdL.FileList + 1,
194 APT::VersionList::CANDIDATE, helper);
195 for (APT::VersionList::iterator V = verset.begin(); V != verset.end(); ++V)
196 if (ShowUnMet(V, Important) == false)
197 return false;
198 }
199 return true;
200 }
201 /*}}}*/
202 // DumpPackage - Show a dump of a package record /*{{{*/
203 // ---------------------------------------------------------------------
204 /* */
205 static bool DumpPackage(CommandLine &CmdL)
206 {
207 pkgCacheFile CacheFile;
208 APT::CacheSetHelper helper(true, GlobalError::NOTICE);
209 APT::PackageList pkgset = APT::PackageList::FromCommandLine(CacheFile, CmdL.FileList + 1, helper);
210
211 for (APT::PackageList::const_iterator Pkg = pkgset.begin(); Pkg != pkgset.end(); ++Pkg)
212 {
213 cout << "Package: " << Pkg.FullName(true) << endl;
214 cout << "Versions: " << endl;
215 for (pkgCache::VerIterator Cur = Pkg.VersionList(); Cur.end() != true; ++Cur)
216 {
217 cout << Cur.VerStr();
218 for (pkgCache::VerFileIterator Vf = Cur.FileList(); Vf.end() == false; ++Vf)
219 cout << " (" << Vf.File().FileName() << ")";
220 cout << endl;
221 for (pkgCache::DescIterator D = Cur.DescriptionList(); D.end() == false; ++D)
222 {
223 cout << " Description Language: " << D.LanguageCode() << endl
224 << " File: " << D.FileList().File().FileName() << endl
225 << " MD5: " << D.md5() << endl;
226 }
227 cout << endl;
228 }
229
230 cout << endl;
231
232 cout << "Reverse Depends: " << endl;
233 for (pkgCache::DepIterator D = Pkg.RevDependsList(); D.end() != true; ++D)
234 {
235 cout << " " << D.ParentPkg().FullName(true) << ',' << D.TargetPkg().FullName(true);
236 if (D->Version != 0)
237 cout << ' ' << DeNull(D.TargetVer()) << endl;
238 else
239 cout << endl;
240 }
241
242 cout << "Dependencies: " << endl;
243 for (pkgCache::VerIterator Cur = Pkg.VersionList(); Cur.end() != true; ++Cur)
244 {
245 cout << Cur.VerStr() << " - ";
246 for (pkgCache::DepIterator Dep = Cur.DependsList(); Dep.end() != true; ++Dep)
247 cout << Dep.TargetPkg().FullName(true) << " (" << (int)Dep->CompareOp << " " << DeNull(Dep.TargetVer()) << ") ";
248 cout << endl;
249 }
250
251 cout << "Provides: " << endl;
252 for (pkgCache::VerIterator Cur = Pkg.VersionList(); Cur.end() != true; ++Cur)
253 {
254 cout << Cur.VerStr() << " - ";
255 for (pkgCache::PrvIterator Prv = Cur.ProvidesList(); Prv.end() != true; ++Prv)
256 cout << Prv.ParentPkg().FullName(true) << " ";
257 cout << endl;
258 }
259 cout << "Reverse Provides: " << endl;
260 for (pkgCache::PrvIterator Prv = Pkg.ProvidesList(); Prv.end() != true; ++Prv)
261 cout << Prv.OwnerPkg().FullName(true) << " " << Prv.OwnerVer().VerStr() << endl;
262 }
263
264 return true;
265 }
266 /*}}}*/
267 // Stats - Dump some nice statistics /*{{{*/
268 // ---------------------------------------------------------------------
269 /* */
270 static bool Stats(CommandLine &)
271 {
272 pkgCacheFile CacheFile;
273 pkgCache *Cache = CacheFile.GetPkgCache();
274 if (unlikely(Cache == NULL))
275 return false;
276
277 cout << _("Total package names: ") << Cache->Head().GroupCount << " (" <<
278 SizeToStr(Cache->Head().GroupCount*Cache->Head().GroupSz) << ')' << endl
279 << _("Total package structures: ") << Cache->Head().PackageCount << " (" <<
280 SizeToStr(Cache->Head().PackageCount*Cache->Head().PackageSz) << ')' << endl;
281
282 int Normal = 0;
283 int Virtual = 0;
284 int NVirt = 0;
285 int DVirt = 0;
286 int Missing = 0;
287 pkgCache::PkgIterator I = Cache->PkgBegin();
288 for (;I.end() != true; ++I)
289 {
290 if (I->VersionList != 0 && I->ProvidesList == 0)
291 {
292 Normal++;
293 continue;
294 }
295
296 if (I->VersionList != 0 && I->ProvidesList != 0)
297 {
298 NVirt++;
299 continue;
300 }
301
302 if (I->VersionList == 0 && I->ProvidesList != 0)
303 {
304 // Only 1 provides
305 if (I.ProvidesList()->NextProvides == 0)
306 {
307 DVirt++;
308 }
309 else
310 Virtual++;
311 continue;
312 }
313 if (I->VersionList == 0 && I->ProvidesList == 0)
314 {
315 Missing++;
316 continue;
317 }
318 }
319 cout << _(" Normal packages: ") << Normal << endl;
320 cout << _(" Pure virtual packages: ") << Virtual << endl;
321 cout << _(" Single virtual packages: ") << DVirt << endl;
322 cout << _(" Mixed virtual packages: ") << NVirt << endl;
323 cout << _(" Missing: ") << Missing << endl;
324
325 cout << _("Total distinct versions: ") << Cache->Head().VersionCount << " (" <<
326 SizeToStr(Cache->Head().VersionCount*Cache->Head().VersionSz) << ')' << endl;
327 cout << _("Total distinct descriptions: ") << Cache->Head().DescriptionCount << " (" <<
328 SizeToStr(Cache->Head().DescriptionCount*Cache->Head().DescriptionSz) << ')' << endl;
329 cout << _("Total dependencies: ") << Cache->Head().DependsCount << " (" <<
330 SizeToStr(Cache->Head().DependsCount*Cache->Head().DependencySz) << ')' << endl;
331
332 cout << _("Total ver/file relations: ") << Cache->Head().VerFileCount << " (" <<
333 SizeToStr(Cache->Head().VerFileCount*Cache->Head().VerFileSz) << ')' << endl;
334 cout << _("Total Desc/File relations: ") << Cache->Head().DescFileCount << " (" <<
335 SizeToStr(Cache->Head().DescFileCount*Cache->Head().DescFileSz) << ')' << endl;
336 cout << _("Total Provides mappings: ") << Cache->Head().ProvidesCount << " (" <<
337 SizeToStr(Cache->Head().ProvidesCount*Cache->Head().ProvidesSz) << ')' << endl;
338
339 // String list stats
340 unsigned long Size = 0;
341 unsigned long Count = 0;
342 for (pkgCache::StringItem *I = Cache->StringItemP + Cache->Head().StringList;
343 I!= Cache->StringItemP; I = Cache->StringItemP + I->NextItem)
344 {
345 Count++;
346 Size += strlen(Cache->StrP + I->String) + 1;
347 }
348 cout << _("Total globbed strings: ") << Count << " (" << SizeToStr(Size) << ')' << endl;
349
350 unsigned long DepVerSize = 0;
351 for (pkgCache::PkgIterator P = Cache->PkgBegin(); P.end() == false; ++P)
352 {
353 for (pkgCache::VerIterator V = P.VersionList(); V.end() == false; ++V)
354 {
355 for (pkgCache::DepIterator D = V.DependsList(); D.end() == false; ++D)
356 {
357 if (D->Version != 0)
358 DepVerSize += strlen(D.TargetVer()) + 1;
359 }
360 }
361 }
362 cout << _("Total dependency version space: ") << SizeToStr(DepVerSize) << endl;
363
364 unsigned long Slack = 0;
365 for (int I = 0; I != 7; I++)
366 Slack += Cache->Head().Pools[I].ItemSize*Cache->Head().Pools[I].Count;
367 cout << _("Total slack space: ") << SizeToStr(Slack) << endl;
368
369 unsigned long Total = 0;
370 Total = Slack + Size + Cache->Head().DependsCount*Cache->Head().DependencySz +
371 Cache->Head().VersionCount*Cache->Head().VersionSz +
372 Cache->Head().PackageCount*Cache->Head().PackageSz +
373 Cache->Head().VerFileCount*Cache->Head().VerFileSz +
374 Cache->Head().ProvidesCount*Cache->Head().ProvidesSz;
375 cout << _("Total space accounted for: ") << SizeToStr(Total) << endl;
376
377 return true;
378 }
379 /*}}}*/
380 // Dump - show everything /*{{{*/
381 // ---------------------------------------------------------------------
382 /* This is worthless except fer debugging things */
383 static bool Dump(CommandLine &)
384 {
385 pkgCacheFile CacheFile;
386 pkgCache *Cache = CacheFile.GetPkgCache();
387 if (unlikely(Cache == NULL))
388 return false;
389
390 std::cout << "Using Versioning System: " << Cache->VS->Label << std::endl;
391
392 for (pkgCache::PkgIterator P = Cache->PkgBegin(); P.end() == false; ++P)
393 {
394 std::cout << "Package: " << P.FullName(true) << std::endl;
395 for (pkgCache::VerIterator V = P.VersionList(); V.end() == false; ++V)
396 {
397 std::cout << " Version: " << V.VerStr() << std::endl;
398 std::cout << " File: " << V.FileList().File().FileName() << std::endl;
399 for (pkgCache::DepIterator D = V.DependsList(); D.end() == false; ++D)
400 std::cout << " Depends: " << D.TargetPkg().FullName(true) << ' ' <<
401 DeNull(D.TargetVer()) << std::endl;
402 for (pkgCache::DescIterator D = V.DescriptionList(); D.end() == false; ++D)
403 {
404 std::cout << " Description Language: " << D.LanguageCode() << std::endl
405 << " File: " << D.FileList().File().FileName() << std::endl
406 << " MD5: " << D.md5() << std::endl;
407 }
408 }
409 }
410
411 for (pkgCache::PkgFileIterator F = Cache->FileBegin(); F.end() == false; ++F)
412 {
413 std::cout << "File: " << F.FileName() << std::endl;
414 std::cout << " Type: " << F.IndexType() << std::endl;
415 std::cout << " Size: " << F->Size << std::endl;
416 std::cout << " ID: " << F->ID << std::endl;
417 std::cout << " Flags: " << F->Flags << std::endl;
418 std::cout << " Time: " << TimeRFC1123(F->mtime) << std::endl;
419 std::cout << " Archive: " << DeNull(F.Archive()) << std::endl;
420 std::cout << " Component: " << DeNull(F.Component()) << std::endl;
421 std::cout << " Version: " << DeNull(F.Version()) << std::endl;
422 std::cout << " Origin: " << DeNull(F.Origin()) << std::endl;
423 std::cout << " Site: " << DeNull(F.Site()) << std::endl;
424 std::cout << " Label: " << DeNull(F.Label()) << std::endl;
425 std::cout << " Architecture: " << DeNull(F.Architecture()) << std::endl;
426 }
427
428 return true;
429 }
430 /*}}}*/
431 // DumpAvail - Print out the available list /*{{{*/
432 // ---------------------------------------------------------------------
433 /* This is needed to make dpkg --merge happy.. I spent a bit of time to
434 make this run really fast, perhaps I went a little overboard.. */
435 static bool DumpAvail(CommandLine &)
436 {
437 pkgCacheFile CacheFile;
438 pkgCache *Cache = CacheFile.GetPkgCache();
439 if (unlikely(Cache == NULL || CacheFile.BuildPolicy() == false))
440 return false;
441
442 unsigned long Count = Cache->HeaderP->PackageCount+1;
443 pkgCache::VerFile **VFList = new pkgCache::VerFile *[Count];
444 memset(VFList,0,sizeof(*VFList)*Count);
445
446 // Map versions that we want to write out onto the VerList array.
447 for (pkgCache::PkgIterator P = Cache->PkgBegin(); P.end() == false; ++P)
448 {
449 if (P->VersionList == 0)
450 continue;
451
452 /* Find the proper version to use. If the policy says there are no
453 possible selections we return the installed version, if available..
454 This prevents dselect from making it obsolete. */
455 pkgCache::VerIterator V = CacheFile.GetPolicy()->GetCandidateVer(P);
456 if (V.end() == true)
457 {
458 if (P->CurrentVer == 0)
459 continue;
460 V = P.CurrentVer();
461 }
462
463 pkgCache::VerFileIterator VF = V.FileList();
464 for (; VF.end() == false ; ++VF)
465 if ((VF.File()->Flags & pkgCache::Flag::NotSource) == 0)
466 break;
467
468 /* Okay, here we have a bit of a problem.. The policy has selected the
469 currently installed package - however it only exists in the
470 status file.. We need to write out something or dselect will mark
471 the package as obsolete! Thus we emit the status file entry, but
472 below we remove the status line to make it valid for the
473 available file. However! We only do this if their do exist *any*
474 non-source versions of the package - that way the dselect obsolete
475 handling works OK. */
476 if (VF.end() == true)
477 {
478 for (pkgCache::VerIterator Cur = P.VersionList(); Cur.end() != true; ++Cur)
479 {
480 for (VF = Cur.FileList(); VF.end() == false; ++VF)
481 {
482 if ((VF.File()->Flags & pkgCache::Flag::NotSource) == 0)
483 {
484 VF = V.FileList();
485 break;
486 }
487 }
488
489 if (VF.end() == false)
490 break;
491 }
492 }
493
494 VFList[P->ID] = VF;
495 }
496
497 LocalitySort(VFList,Count,sizeof(*VFList));
498
499 // Iterate over all the package files and write them out.
500 char *Buffer = new char[Cache->HeaderP->MaxVerFileSize+10];
501 for (pkgCache::VerFile **J = VFList; *J != 0;)
502 {
503 pkgCache::PkgFileIterator File(*Cache,(*J)->File + Cache->PkgFileP);
504 if (File.IsOk() == false)
505 {
506 _error->Error(_("Package file %s is out of sync."),File.FileName());
507 break;
508 }
509
510 FileFd PkgF(File.FileName(),FileFd::ReadOnly, FileFd::Extension);
511 if (_error->PendingError() == true)
512 break;
513
514 /* Write all of the records from this package file, since we
515 already did locality sorting we can now just seek through the
516 file in read order. We apply 1 more optimization here, since often
517 there will be < 1 byte gaps between records (for the \n) we read that
518 into the next buffer and offset a bit.. */
519 unsigned long Pos = 0;
520 for (; *J != 0; J++)
521 {
522 if ((*J)->File + Cache->PkgFileP != File)
523 break;
524
525 const pkgCache::VerFile &VF = **J;
526
527 // Read the record and then write it out again.
528 unsigned long Jitter = VF.Offset - Pos;
529 if (Jitter > 8)
530 {
531 if (PkgF.Seek(VF.Offset) == false)
532 break;
533 Jitter = 0;
534 }
535
536 if (PkgF.Read(Buffer,VF.Size + Jitter) == false)
537 break;
538 Buffer[VF.Size + Jitter] = '\n';
539
540 // See above..
541 if ((File->Flags & pkgCache::Flag::NotSource) == pkgCache::Flag::NotSource)
542 {
543 pkgTagSection Tags;
544 TFRewriteData RW[] = {{"Status", NULL, NULL},{"Config-Version", NULL, NULL},{NULL, NULL, NULL}};
545 const char *Zero = 0;
546 if (Tags.Scan(Buffer+Jitter,VF.Size+1) == false ||
547 TFRewrite(stdout,Tags,&Zero,RW) == false)
548 {
549 _error->Error("Internal Error, Unable to parse a package record");
550 break;
551 }
552 fputc('\n',stdout);
553 }
554 else
555 {
556 if (fwrite(Buffer+Jitter,VF.Size+1,1,stdout) != 1)
557 break;
558 }
559
560 Pos = VF.Offset + VF.Size;
561 }
562
563 fflush(stdout);
564 if (_error->PendingError() == true)
565 break;
566 }
567
568 delete [] Buffer;
569 delete [] VFList;
570 return !_error->PendingError();
571 }
572 /*}}}*/
573 // ShowDepends - Helper for printing out a dependency tree /*{{{*/
574 static bool ShowDepends(CommandLine &CmdL, bool const RevDepends)
575 {
576 pkgCacheFile CacheFile;
577 pkgCache *Cache = CacheFile.GetPkgCache();
578 if (unlikely(Cache == NULL))
579 return false;
580
581 CacheSetHelperVirtuals helper(false);
582 APT::VersionList verset = APT::VersionList::FromCommandLine(CacheFile, CmdL.FileList + 1, APT::VersionList::CANDIDATE, helper);
583 if (verset.empty() == true && helper.virtualPkgs.empty() == true)
584 return _error->Error(_("No packages found"));
585 std::vector<bool> Shown(Cache->Head().PackageCount);
586
587 bool const Recurse = _config->FindB("APT::Cache::RecurseDepends", false);
588 bool const Installed = _config->FindB("APT::Cache::Installed", false);
589 bool const Important = _config->FindB("APT::Cache::Important", false);
590 bool const ShowDepType = _config->FindB("APT::Cache::ShowDependencyType", RevDepends == false);
591 bool const ShowVersion = _config->FindB("APT::Cache::ShowVersion", false);
592 bool const ShowPreDepends = _config->FindB("APT::Cache::ShowPre-Depends", true);
593 bool const ShowDepends = _config->FindB("APT::Cache::ShowDepends", true);
594 bool const ShowRecommends = _config->FindB("APT::Cache::ShowRecommends", Important == false);
595 bool const ShowSuggests = _config->FindB("APT::Cache::ShowSuggests", Important == false);
596 bool const ShowReplaces = _config->FindB("APT::Cache::ShowReplaces", Important == false);
597 bool const ShowConflicts = _config->FindB("APT::Cache::ShowConflicts", Important == false);
598 bool const ShowBreaks = _config->FindB("APT::Cache::ShowBreaks", Important == false);
599 bool const ShowEnhances = _config->FindB("APT::Cache::ShowEnhances", Important == false);
600 bool const ShowOnlyFirstOr = _config->FindB("APT::Cache::ShowOnlyFirstOr", false);
601
602 while (verset.empty() != true)
603 {
604 pkgCache::VerIterator Ver = *verset.begin();
605 verset.erase(verset.begin());
606 pkgCache::PkgIterator Pkg = Ver.ParentPkg();
607 Shown[Pkg->ID] = true;
608
609 cout << Pkg.FullName(true) << endl;
610
611 if (RevDepends == true)
612 cout << "Reverse Depends:" << endl;
613 for (pkgCache::DepIterator D = RevDepends ? Pkg.RevDependsList() : Ver.DependsList();
614 D.end() == false; ++D)
615 {
616 switch (D->Type) {
617 case pkgCache::Dep::PreDepends: if (!ShowPreDepends) continue; break;
618 case pkgCache::Dep::Depends: if (!ShowDepends) continue; break;
619 case pkgCache::Dep::Recommends: if (!ShowRecommends) continue; break;
620 case pkgCache::Dep::Suggests: if (!ShowSuggests) continue; break;
621 case pkgCache::Dep::Replaces: if (!ShowReplaces) continue; break; case pkgCache::Dep::Conflicts: if (!ShowConflicts) continue; break;
622 case pkgCache::Dep::DpkgBreaks: if (!ShowBreaks) continue; break;
623 case pkgCache::Dep::Enhances: if (!ShowEnhances) continue; break;
624 }
625
626 pkgCache::PkgIterator Trg = RevDepends ? D.ParentPkg() : D.TargetPkg();
627
628 if((Installed && Trg->CurrentVer != 0) || !Installed)
629 {
630
631 if ((D->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or && ShowOnlyFirstOr == false)
632 cout << " |";
633 else
634 cout << " ";
635
636 // Show the package
637 if (ShowDepType == true)
638 cout << D.DepType() << ": ";
639 if (Trg->VersionList == 0)
640 cout << "<" << Trg.FullName(true) << ">";
641 else
642 cout << Trg.FullName(true);
643 if (ShowVersion == true && D->Version != 0)
644 cout << " (" << pkgCache::CompTypeDeb(D->CompareOp) << ' ' << D.TargetVer() << ')';
645 cout << std::endl;
646
647 if (Recurse == true && Shown[Trg->ID] == false)
648 {
649 Shown[Trg->ID] = true;
650 verset.insert(APT::VersionSet::FromPackage(CacheFile, Trg, APT::VersionSet::CANDIDATE, helper));
651 }
652
653 }
654
655 // Display all solutions
656 SPtrArray<pkgCache::Version *> List = D.AllTargets();
657 pkgPrioSortList(*Cache,List);
658 for (pkgCache::Version **I = List; *I != 0; I++)
659 {
660 pkgCache::VerIterator V(*Cache,*I);
661 if (V != Cache->VerP + V.ParentPkg()->VersionList ||
662 V->ParentPkg == D->Package)
663 continue;
664 cout << " " << V.ParentPkg().FullName(true) << endl;
665
666 if (Recurse == true && Shown[V.ParentPkg()->ID] == false)
667 {
668 Shown[V.ParentPkg()->ID] = true;
669 verset.insert(APT::VersionSet::FromPackage(CacheFile, V.ParentPkg(), APT::VersionSet::CANDIDATE, helper));
670 }
671 }
672
673 if (ShowOnlyFirstOr == true)
674 while ((D->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or) ++D;
675 }
676 }
677
678 for (APT::PackageSet::const_iterator Pkg = helper.virtualPkgs.begin();
679 Pkg != helper.virtualPkgs.end(); ++Pkg)
680 cout << '<' << Pkg.FullName(true) << '>' << endl;
681
682 return true;
683 }
684 /*}}}*/
685 // Depends - Print out a dependency tree /*{{{*/
686 // ---------------------------------------------------------------------
687 /* */
688 static bool Depends(CommandLine &CmdL)
689 {
690 return ShowDepends(CmdL, false);
691 }
692 /*}}}*/
693 // RDepends - Print out a reverse dependency tree /*{{{*/
694 // ---------------------------------------------------------------------
695 /* */
696 static bool RDepends(CommandLine &CmdL)
697 {
698 return ShowDepends(CmdL, true);
699 }
700 /*}}}*/
701 // xvcg - Generate a graph for xvcg /*{{{*/
702 // ---------------------------------------------------------------------
703 // Code contributed from Junichi Uekawa <dancer@debian.org> on 20 June 2002.
704
705 static bool XVcg(CommandLine &CmdL)
706 {
707 pkgCacheFile CacheFile;
708 pkgCache *Cache = CacheFile.GetPkgCache();
709 if (unlikely(Cache == NULL))
710 return false;
711
712 bool GivenOnly = _config->FindB("APT::Cache::GivenOnly",false);
713
714 /* Normal packages are boxes
715 Pure Provides are triangles
716 Mixed are diamonds
717 rhomb are missing packages*/
718 const char *Shapes[] = {"ellipse","triangle","box","rhomb"};
719
720 /* Initialize the list of packages to show.
721 1 = To Show
722 2 = To Show no recurse
723 3 = Emitted no recurse
724 4 = Emitted
725 0 = None */
726 enum States {None=0, ToShow, ToShowNR, DoneNR, Done};
727 enum TheFlags {ForceNR=(1<<0)};
728 unsigned char *Show = new unsigned char[Cache->Head().PackageCount];
729 unsigned char *Flags = new unsigned char[Cache->Head().PackageCount];
730 unsigned char *ShapeMap = new unsigned char[Cache->Head().PackageCount];
731
732 // Show everything if no arguments given
733 if (CmdL.FileList[1] == 0)
734 for (unsigned long I = 0; I != Cache->Head().PackageCount; I++)
735 Show[I] = ToShow;
736 else
737 for (unsigned long I = 0; I != Cache->Head().PackageCount; I++)
738 Show[I] = None;
739 memset(Flags,0,sizeof(*Flags)*Cache->Head().PackageCount);
740
741 // Map the shapes
742 for (pkgCache::PkgIterator Pkg = Cache->PkgBegin(); Pkg.end() == false; ++Pkg)
743 {
744 if (Pkg->VersionList == 0)
745 {
746 // Missing
747 if (Pkg->ProvidesList == 0)
748 ShapeMap[Pkg->ID] = 0;
749 else
750 ShapeMap[Pkg->ID] = 1;
751 }
752 else
753 {
754 // Normal
755 if (Pkg->ProvidesList == 0)
756 ShapeMap[Pkg->ID] = 2;
757 else
758 ShapeMap[Pkg->ID] = 3;
759 }
760 }
761
762 // Load the list of packages from the command line into the show list
763 APT::CacheSetHelper helper(true, GlobalError::NOTICE);
764 std::list<APT::PackageSet::Modifier> mods;
765 mods.push_back(APT::PackageSet::Modifier(0, ",", APT::PackageSet::Modifier::POSTFIX));
766 mods.push_back(APT::PackageSet::Modifier(1, "^", APT::PackageSet::Modifier::POSTFIX));
767 std::map<unsigned short, APT::PackageSet> pkgsets =
768 APT::PackageSet::GroupedFromCommandLine(CacheFile, CmdL.FileList + 1, mods, 0, helper);
769
770 for (APT::PackageSet::const_iterator Pkg = pkgsets[0].begin();
771 Pkg != pkgsets[0].end(); ++Pkg)
772 Show[Pkg->ID] = ToShow;
773 for (APT::PackageSet::const_iterator Pkg = pkgsets[1].begin();
774 Pkg != pkgsets[1].end(); ++Pkg)
775 {
776 Show[Pkg->ID] = ToShow;
777 Flags[Pkg->ID] |= ForceNR;
778 }
779
780 // Little header
781 cout << "graph: { title: \"packages\"" << endl <<
782 "xmax: 700 ymax: 700 x: 30 y: 30" << endl <<
783 "layout_downfactor: 8" << endl;
784
785 bool Act = true;
786 while (Act == true)
787 {
788 Act = false;
789 for (pkgCache::PkgIterator Pkg = Cache->PkgBegin(); Pkg.end() == false; ++Pkg)
790 {
791 // See we need to show this package
792 if (Show[Pkg->ID] == None || Show[Pkg->ID] >= DoneNR)
793 continue;
794
795 //printf ("node: { title: \"%s\" label: \"%s\" }\n", Pkg.Name(), Pkg.Name());
796
797 // Colour as done
798 if (Show[Pkg->ID] == ToShowNR || (Flags[Pkg->ID] & ForceNR) == ForceNR)
799 {
800 // Pure Provides and missing packages have no deps!
801 if (ShapeMap[Pkg->ID] == 0 || ShapeMap[Pkg->ID] == 1)
802 Show[Pkg->ID] = Done;
803 else
804 Show[Pkg->ID] = DoneNR;
805 }
806 else
807 Show[Pkg->ID] = Done;
808 Act = true;
809
810 // No deps to map out
811 if (Pkg->VersionList == 0 || Show[Pkg->ID] == DoneNR)
812 continue;
813
814 pkgCache::VerIterator Ver = Pkg.VersionList();
815 for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false; ++D)
816 {
817 // See if anything can meet this dep
818 // Walk along the actual package providing versions
819 bool Hit = false;
820 pkgCache::PkgIterator DPkg = D.TargetPkg();
821 for (pkgCache::VerIterator I = DPkg.VersionList();
822 I.end() == false && Hit == false; ++I)
823 {
824 if (Cache->VS->CheckDep(I.VerStr(),D->CompareOp,D.TargetVer()) == true)
825 Hit = true;
826 }
827
828 // Follow all provides
829 for (pkgCache::PrvIterator I = DPkg.ProvidesList();
830 I.end() == false && Hit == false; ++I)
831 {
832 if (Cache->VS->CheckDep(I.ProvideVersion(),D->CompareOp,D.TargetVer()) == false)
833 Hit = true;
834 }
835
836
837 // Only graph critical deps
838 if (D.IsCritical() == true)
839 {
840 printf ("edge: { sourcename: \"%s\" targetname: \"%s\" class: 2 ",Pkg.FullName(true).c_str(), D.TargetPkg().FullName(true).c_str() );
841
842 // Colour the node for recursion
843 if (Show[D.TargetPkg()->ID] <= DoneNR)
844 {
845 /* If a conflicts does not meet anything in the database
846 then show the relation but do not recurse */
847 if (Hit == false && D.IsNegative() == true)
848 {
849 if (Show[D.TargetPkg()->ID] == None &&
850 Show[D.TargetPkg()->ID] != ToShow)
851 Show[D.TargetPkg()->ID] = ToShowNR;
852 }
853 else
854 {
855 if (GivenOnly == true && Show[D.TargetPkg()->ID] != ToShow)
856 Show[D.TargetPkg()->ID] = ToShowNR;
857 else
858 Show[D.TargetPkg()->ID] = ToShow;
859 }
860 }
861
862 // Edge colour
863 switch(D->Type)
864 {
865 case pkgCache::Dep::Conflicts:
866 printf("label: \"conflicts\" color: lightgreen }\n");
867 break;
868 case pkgCache::Dep::DpkgBreaks:
869 printf("label: \"breaks\" color: lightgreen }\n");
870 break;
871 case pkgCache::Dep::Obsoletes:
872 printf("label: \"obsoletes\" color: lightgreen }\n");
873 break;
874
875 case pkgCache::Dep::PreDepends:
876 printf("label: \"predepends\" color: blue }\n");
877 break;
878
879 default:
880 printf("}\n");
881 break;
882 }
883 }
884 }
885 }
886 }
887
888 /* Draw the box colours after the fact since we can not tell what colour
889 they should be until everything is finished drawing */
890 for (pkgCache::PkgIterator Pkg = Cache->PkgBegin(); Pkg.end() == false; ++Pkg)
891 {
892 if (Show[Pkg->ID] < DoneNR)
893 continue;
894
895 if (Show[Pkg->ID] == DoneNR)
896 printf("node: { title: \"%s\" label: \"%s\" color: orange shape: %s }\n", Pkg.FullName(true).c_str(), Pkg.FullName(true).c_str(),
897 Shapes[ShapeMap[Pkg->ID]]);
898 else
899 printf("node: { title: \"%s\" label: \"%s\" shape: %s }\n", Pkg.FullName(true).c_str(), Pkg.FullName(true).c_str(),
900 Shapes[ShapeMap[Pkg->ID]]);
901
902 }
903
904 delete[] Show;
905 delete[] Flags;
906 delete[] ShapeMap;
907
908 printf("}\n");
909 return true;
910 }
911 /*}}}*/
912 // Dotty - Generate a graph for Dotty /*{{{*/
913 // ---------------------------------------------------------------------
914 /* Dotty is the graphvis program for generating graphs. It is a fairly
915 simple queuing algorithm that just writes dependencies and nodes.
916 http://www.research.att.com/sw/tools/graphviz/ */
917 static bool Dotty(CommandLine &CmdL)
918 {
919 pkgCacheFile CacheFile;
920 pkgCache *Cache = CacheFile.GetPkgCache();
921 if (unlikely(Cache == NULL))
922 return false;
923
924 bool GivenOnly = _config->FindB("APT::Cache::GivenOnly",false);
925
926 /* Normal packages are boxes
927 Pure Provides are triangles
928 Mixed are diamonds
929 Hexagons are missing packages*/
930 const char *Shapes[] = {"hexagon","triangle","box","diamond"};
931
932 /* Initialize the list of packages to show.
933 1 = To Show
934 2 = To Show no recurse
935 3 = Emitted no recurse
936 4 = Emitted
937 0 = None */
938 enum States {None=0, ToShow, ToShowNR, DoneNR, Done};
939 enum TheFlags {ForceNR=(1<<0)};
940 unsigned char *Show = new unsigned char[Cache->Head().PackageCount];
941 unsigned char *Flags = new unsigned char[Cache->Head().PackageCount];
942 unsigned char *ShapeMap = new unsigned char[Cache->Head().PackageCount];
943
944 // Show everything if no arguments given
945 if (CmdL.FileList[1] == 0)
946 for (unsigned long I = 0; I != Cache->Head().PackageCount; I++)
947 Show[I] = ToShow;
948 else
949 for (unsigned long I = 0; I != Cache->Head().PackageCount; I++)
950 Show[I] = None;
951 memset(Flags,0,sizeof(*Flags)*Cache->Head().PackageCount);
952
953 // Map the shapes
954 for (pkgCache::PkgIterator Pkg = Cache->PkgBegin(); Pkg.end() == false; ++Pkg)
955 {
956 if (Pkg->VersionList == 0)
957 {
958 // Missing
959 if (Pkg->ProvidesList == 0)
960 ShapeMap[Pkg->ID] = 0;
961 else
962 ShapeMap[Pkg->ID] = 1;
963 }
964 else
965 {
966 // Normal
967 if (Pkg->ProvidesList == 0)
968 ShapeMap[Pkg->ID] = 2;
969 else
970 ShapeMap[Pkg->ID] = 3;
971 }
972 }
973
974 // Load the list of packages from the command line into the show list
975 APT::CacheSetHelper helper(true, GlobalError::NOTICE);
976 std::list<APT::PackageSet::Modifier> mods;
977 mods.push_back(APT::PackageSet::Modifier(0, ",", APT::PackageSet::Modifier::POSTFIX));
978 mods.push_back(APT::PackageSet::Modifier(1, "^", APT::PackageSet::Modifier::POSTFIX));
979 std::map<unsigned short, APT::PackageSet> pkgsets =
980 APT::PackageSet::GroupedFromCommandLine(CacheFile, CmdL.FileList + 1, mods, 0, helper);
981
982 for (APT::PackageSet::const_iterator Pkg = pkgsets[0].begin();
983 Pkg != pkgsets[0].end(); ++Pkg)
984 Show[Pkg->ID] = ToShow;
985 for (APT::PackageSet::const_iterator Pkg = pkgsets[1].begin();
986 Pkg != pkgsets[1].end(); ++Pkg)
987 {
988 Show[Pkg->ID] = ToShow;
989 Flags[Pkg->ID] |= ForceNR;
990 }
991
992 // Little header
993 printf("digraph packages {\n");
994 printf("concentrate=true;\n");
995 printf("size=\"30,40\";\n");
996
997 bool Act = true;
998 while (Act == true)
999 {
1000 Act = false;
1001 for (pkgCache::PkgIterator Pkg = Cache->PkgBegin(); Pkg.end() == false; ++Pkg)
1002 {
1003 // See we need to show this package
1004 if (Show[Pkg->ID] == None || Show[Pkg->ID] >= DoneNR)
1005 continue;
1006
1007 // Colour as done
1008 if (Show[Pkg->ID] == ToShowNR || (Flags[Pkg->ID] & ForceNR) == ForceNR)
1009 {
1010 // Pure Provides and missing packages have no deps!
1011 if (ShapeMap[Pkg->ID] == 0 || ShapeMap[Pkg->ID] == 1)
1012 Show[Pkg->ID] = Done;
1013 else
1014 Show[Pkg->ID] = DoneNR;
1015 }
1016 else
1017 Show[Pkg->ID] = Done;
1018 Act = true;
1019
1020 // No deps to map out
1021 if (Pkg->VersionList == 0 || Show[Pkg->ID] == DoneNR)
1022 continue;
1023
1024 pkgCache::VerIterator Ver = Pkg.VersionList();
1025 for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false; ++D)
1026 {
1027 // See if anything can meet this dep
1028 // Walk along the actual package providing versions
1029 bool Hit = false;
1030 pkgCache::PkgIterator DPkg = D.TargetPkg();
1031 for (pkgCache::VerIterator I = DPkg.VersionList();
1032 I.end() == false && Hit == false; ++I)
1033 {
1034 if (Cache->VS->CheckDep(I.VerStr(),D->CompareOp,D.TargetVer()) == true)
1035 Hit = true;
1036 }
1037
1038 // Follow all provides
1039 for (pkgCache::PrvIterator I = DPkg.ProvidesList();
1040 I.end() == false && Hit == false; ++I)
1041 {
1042 if (Cache->VS->CheckDep(I.ProvideVersion(),D->CompareOp,D.TargetVer()) == false)
1043 Hit = true;
1044 }
1045
1046 // Only graph critical deps
1047 if (D.IsCritical() == true)
1048 {
1049 printf("\"%s\" -> \"%s\"",Pkg.FullName(true).c_str(),D.TargetPkg().FullName(true).c_str());
1050
1051 // Colour the node for recursion
1052 if (Show[D.TargetPkg()->ID] <= DoneNR)
1053 {
1054 /* If a conflicts does not meet anything in the database
1055 then show the relation but do not recurse */
1056 if (Hit == false && D.IsNegative() == true)
1057 {
1058 if (Show[D.TargetPkg()->ID] == None &&
1059 Show[D.TargetPkg()->ID] != ToShow)
1060 Show[D.TargetPkg()->ID] = ToShowNR;
1061 }
1062 else
1063 {
1064 if (GivenOnly == true && Show[D.TargetPkg()->ID] != ToShow)
1065 Show[D.TargetPkg()->ID] = ToShowNR;
1066 else
1067 Show[D.TargetPkg()->ID] = ToShow;
1068 }
1069 }
1070
1071 // Edge colour
1072 switch(D->Type)
1073 {
1074 case pkgCache::Dep::Conflicts:
1075 case pkgCache::Dep::Obsoletes:
1076 case pkgCache::Dep::DpkgBreaks:
1077 printf("[color=springgreen];\n");
1078 break;
1079
1080 case pkgCache::Dep::PreDepends:
1081 printf("[color=blue];\n");
1082 break;
1083
1084 default:
1085 printf(";\n");
1086 break;
1087 }
1088 }
1089 }
1090 }
1091 }
1092
1093 /* Draw the box colours after the fact since we can not tell what colour
1094 they should be until everything is finished drawing */
1095 for (pkgCache::PkgIterator Pkg = Cache->PkgBegin(); Pkg.end() == false; ++Pkg)
1096 {
1097 if (Show[Pkg->ID] < DoneNR)
1098 continue;
1099
1100 // Orange box for early recursion stoppage
1101 if (Show[Pkg->ID] == DoneNR)
1102 printf("\"%s\" [color=orange,shape=%s];\n",Pkg.FullName(true).c_str(),
1103 Shapes[ShapeMap[Pkg->ID]]);
1104 else
1105 printf("\"%s\" [shape=%s];\n",Pkg.FullName(true).c_str(),
1106 Shapes[ShapeMap[Pkg->ID]]);
1107 }
1108
1109 printf("}\n");
1110 delete[] Show;
1111 delete[] Flags;
1112 delete[] ShapeMap;
1113 return true;
1114 }
1115 /*}}}*/
1116 // DisplayRecord - Displays the complete record for the package /*{{{*/
1117 // ---------------------------------------------------------------------
1118 /* This displays the package record from the proper package index file.
1119 It is not used by DumpAvail for performance reasons. */
1120
1121 static APT_PURE unsigned char const* skipDescriptionFields(unsigned char const * DescP)
1122 {
1123 char const * const TagName = "\nDescription";
1124 size_t const TagLen = strlen(TagName);
1125 while ((DescP = (unsigned char*)strchr((char*)DescP, '\n')) != NULL)
1126 {
1127 if (DescP[1] == ' ')
1128 DescP += 2;
1129 else if (strncmp((char*)DescP, TagName, TagLen) == 0)
1130 DescP += TagLen;
1131 else
1132 break;
1133 }
1134 if (DescP != NULL)
1135 ++DescP;
1136 return DescP;
1137 }
1138 static bool DisplayRecord(pkgCacheFile &CacheFile, pkgCache::VerIterator V)
1139 {
1140 pkgCache *Cache = CacheFile.GetPkgCache();
1141 if (unlikely(Cache == NULL))
1142 return false;
1143
1144 // Find an appropriate file
1145 pkgCache::VerFileIterator Vf = V.FileList();
1146 for (; Vf.end() == false; ++Vf)
1147 if ((Vf.File()->Flags & pkgCache::Flag::NotSource) == 0)
1148 break;
1149 if (Vf.end() == true)
1150 Vf = V.FileList();
1151
1152 // Check and load the package list file
1153 pkgCache::PkgFileIterator I = Vf.File();
1154 if (I.IsOk() == false)
1155 return _error->Error(_("Package file %s is out of sync."),I.FileName());
1156
1157 FileFd PkgF;
1158 if (PkgF.Open(I.FileName(), FileFd::ReadOnly, FileFd::Extension) == false)
1159 return false;
1160
1161 // Read the record (and ensure that it ends with a newline and NUL)
1162 unsigned char *Buffer = new unsigned char[Cache->HeaderP->MaxVerFileSize+2];
1163 Buffer[Vf->Size] = '\n';
1164 Buffer[Vf->Size+1] = '\0';
1165 if (PkgF.Seek(Vf->Offset) == false ||
1166 PkgF.Read(Buffer,Vf->Size) == false)
1167 {
1168 delete [] Buffer;
1169 return false;
1170 }
1171
1172 // Get a pointer to start of Description field
1173 const unsigned char *DescP = (unsigned char*)strstr((char*)Buffer, "\nDescription");
1174 if (DescP != NULL)
1175 ++DescP;
1176 else
1177 DescP = Buffer + Vf->Size;
1178
1179 // Write all but Description
1180 size_t const length = DescP - Buffer;
1181 if (length != 0 && FileFd::Write(STDOUT_FILENO, Buffer, length) == false)
1182 {
1183 delete [] Buffer;
1184 return false;
1185 }
1186
1187 // Show the right description
1188 pkgRecords Recs(*Cache);
1189 pkgCache::DescIterator Desc = V.TranslatedDescription();
1190 if (Desc.end() == false)
1191 {
1192 pkgRecords::Parser &P = Recs.Lookup(Desc.FileList());
1193 cout << "Description" << ( (strcmp(Desc.LanguageCode(),"") != 0) ? "-" : "" ) << Desc.LanguageCode() << ": " << P.LongDesc();
1194 cout << std::endl << "Description-md5: " << Desc.md5() << std::endl;
1195
1196 // Find the first field after the description (if there is any)
1197 DescP = skipDescriptionFields(DescP);
1198 }
1199 // else we have no translation, so we found a lonely Description-md5 -> don't skip it
1200
1201 // write the rest of the buffer, but skip mixed in Descriptions* fields
1202 while (DescP != NULL)
1203 {
1204 const unsigned char * const Start = DescP;
1205 const unsigned char *End = (unsigned char*)strstr((char*)DescP, "\nDescription");
1206 if (End == NULL)
1207 {
1208 End = &Buffer[Vf->Size];
1209 DescP = NULL;
1210 }
1211 else
1212 {
1213 ++End; // get the newline into the output
1214 DescP = skipDescriptionFields(End + strlen("Description"));
1215 }
1216 size_t const length = End - Start;
1217 if (length != 0 && FileFd::Write(STDOUT_FILENO, Start, length) == false)
1218 {
1219 delete [] Buffer;
1220 return false;
1221 }
1222 }
1223
1224 // write a final newline after the last field
1225 cout<<endl;
1226
1227 delete [] Buffer;
1228 return true;
1229 }
1230 /*}}}*/
1231 struct ExDescFile
1232 {
1233 pkgCache::DescFile *Df;
1234 map_ptrloc ID;
1235 };
1236
1237 // Search - Perform a search /*{{{*/
1238 // ---------------------------------------------------------------------
1239 /* This searches the package names and package descriptions for a pattern */
1240 static bool Search(CommandLine &CmdL)
1241 {
1242 bool const ShowFull = _config->FindB("APT::Cache::ShowFull",false);
1243 bool const NamesOnly = _config->FindB("APT::Cache::NamesOnly",false);
1244 unsigned int const NumPatterns = CmdL.FileSize() -1;
1245
1246 pkgCacheFile CacheFile;
1247 pkgCache *Cache = CacheFile.GetPkgCache();
1248 pkgDepCache::Policy *Plcy = CacheFile.GetPolicy();
1249 if (unlikely(Cache == NULL || Plcy == NULL))
1250 return false;
1251
1252 // Make sure there is at least one argument
1253 if (NumPatterns < 1)
1254 return _error->Error(_("You must give at least one search pattern"));
1255
1256 // Compile the regex pattern
1257 regex_t *Patterns = new regex_t[NumPatterns];
1258 memset(Patterns,0,sizeof(*Patterns)*NumPatterns);
1259 for (unsigned I = 0; I != NumPatterns; I++)
1260 {
1261 if (regcomp(&Patterns[I],CmdL.FileList[I+1],REG_EXTENDED | REG_ICASE |
1262 REG_NOSUB) != 0)
1263 {
1264 for (; I != 0; I--)
1265 regfree(&Patterns[I]);
1266 return _error->Error("Regex compilation error");
1267 }
1268 }
1269
1270 if (_error->PendingError() == true)
1271 {
1272 for (unsigned I = 0; I != NumPatterns; I++)
1273 regfree(&Patterns[I]);
1274 return false;
1275 }
1276
1277 size_t const descCount = Cache->HeaderP->GroupCount + 1;
1278 ExDescFile *DFList = new ExDescFile[descCount];
1279 memset(DFList,0,sizeof(*DFList) * descCount);
1280
1281 bool *PatternMatch = new bool[descCount * NumPatterns];
1282 memset(PatternMatch,false,sizeof(*PatternMatch) * descCount * NumPatterns);
1283
1284 // Map versions that we want to write out onto the VerList array.
1285 for (pkgCache::GrpIterator G = Cache->GrpBegin(); G.end() == false; ++G)
1286 {
1287 size_t const PatternOffset = G->ID * NumPatterns;
1288 size_t unmatched = 0, matched = 0;
1289 for (unsigned I = 0; I < NumPatterns; ++I)
1290 {
1291 if (PatternMatch[PatternOffset + I] == true)
1292 ++matched;
1293 else if (regexec(&Patterns[I],G.Name(),0,0,0) == 0)
1294 PatternMatch[PatternOffset + I] = true;
1295 else
1296 ++unmatched;
1297 }
1298
1299 // already dealt with this package?
1300 if (matched == NumPatterns)
1301 continue;
1302
1303 // Doing names only, drop any that don't match..
1304 if (NamesOnly == true && unmatched == NumPatterns)
1305 continue;
1306
1307 // Find the proper version to use
1308 pkgCache::PkgIterator P = G.FindPreferredPkg();
1309 if (P.end() == true)
1310 continue;
1311 pkgCache::VerIterator V = Plcy->GetCandidateVer(P);
1312 if (V.end() == false)
1313 {
1314 pkgCache::DescIterator const D = V.TranslatedDescription();
1315 //FIXME: packages without a description can't be found
1316 if (D.end() == true)
1317 continue;
1318 DFList[G->ID].Df = D.FileList();
1319 DFList[G->ID].ID = G->ID;
1320 }
1321
1322 if (unmatched == NumPatterns)
1323 continue;
1324
1325 // Include all the packages that provide matching names too
1326 for (pkgCache::PrvIterator Prv = P.ProvidesList() ; Prv.end() == false; ++Prv)
1327 {
1328 pkgCache::VerIterator V = Plcy->GetCandidateVer(Prv.OwnerPkg());
1329 if (V.end() == true)
1330 continue;
1331
1332 unsigned long id = Prv.OwnerPkg().Group()->ID;
1333 pkgCache::DescIterator const D = V.TranslatedDescription();
1334 //FIXME: packages without a description can't be found
1335 if (D.end() == true)
1336 continue;
1337 DFList[id].Df = D.FileList();
1338 DFList[id].ID = id;
1339
1340 size_t const PrvPatternOffset = id * NumPatterns;
1341 for (unsigned I = 0; I < NumPatterns; ++I)
1342 PatternMatch[PrvPatternOffset + I] = PatternMatch[PatternOffset + I];
1343 }
1344 }
1345
1346 LocalitySort(&DFList->Df,Cache->HeaderP->GroupCount,sizeof(*DFList));
1347
1348 // Create the text record parser
1349 pkgRecords Recs(*Cache);
1350 // Iterate over all the version records and check them
1351 for (ExDescFile *J = DFList; J->Df != 0; ++J)
1352 {
1353 pkgRecords::Parser &P = Recs.Lookup(pkgCache::DescFileIterator(*Cache,J->Df));
1354 size_t const PatternOffset = J->ID * NumPatterns;
1355
1356 if (NamesOnly == false)
1357 {
1358 string const LongDesc = P.LongDesc();
1359 for (unsigned I = 0; I < NumPatterns; ++I)
1360 {
1361 if (PatternMatch[PatternOffset + I] == true)
1362 continue;
1363 else if (regexec(&Patterns[I],LongDesc.c_str(),0,0,0) == 0)
1364 PatternMatch[PatternOffset + I] = true;
1365 }
1366 }
1367
1368 bool matchedAll = true;
1369 for (unsigned I = 0; I < NumPatterns; ++I)
1370 if (PatternMatch[PatternOffset + I] == false)
1371 {
1372 matchedAll = false;
1373 break;
1374 }
1375
1376 if (matchedAll == true)
1377 {
1378 if (ShowFull == true)
1379 {
1380 const char *Start;
1381 const char *End;
1382 P.GetRec(Start,End);
1383 fwrite(Start,End-Start,1,stdout);
1384 putc('\n',stdout);
1385 }
1386 else
1387 printf("%s - %s\n",P.Name().c_str(),P.ShortDesc().c_str());
1388 }
1389 }
1390
1391 delete [] DFList;
1392 delete [] PatternMatch;
1393 for (unsigned I = 0; I != NumPatterns; I++)
1394 regfree(&Patterns[I]);
1395 if (ferror(stdout))
1396 return _error->Error("Write to stdout failed");
1397 return true;
1398 }
1399 /*}}}*/
1400 /* ShowAuto - show automatically installed packages (sorted) {{{*/
1401 static bool ShowAuto(CommandLine &)
1402 {
1403 pkgCacheFile CacheFile;
1404 pkgCache *Cache = CacheFile.GetPkgCache();
1405 pkgDepCache *DepCache = CacheFile.GetDepCache();
1406 if (unlikely(Cache == NULL || DepCache == NULL))
1407 return false;
1408
1409 std::vector<string> packages;
1410 packages.reserve(Cache->HeaderP->PackageCount / 3);
1411
1412 for (pkgCache::PkgIterator P = Cache->PkgBegin(); P.end() == false; ++P)
1413 if ((*DepCache)[P].Flags & pkgCache::Flag::Auto)
1414 packages.push_back(P.Name());
1415
1416 std::sort(packages.begin(), packages.end());
1417
1418 for (vector<string>::iterator I = packages.begin(); I != packages.end(); ++I)
1419 cout << *I << "\n";
1420
1421 _error->Notice(_("This command is deprecated. Please use 'apt-mark showauto' instead."));
1422 return true;
1423 }
1424 /*}}}*/
1425 // ShowPackage - Dump the package record to the screen /*{{{*/
1426 // ---------------------------------------------------------------------
1427 /* */
1428 static bool ShowPackage(CommandLine &CmdL)
1429 {
1430 pkgCacheFile CacheFile;
1431 CacheSetHelperVirtuals helper(true, GlobalError::NOTICE);
1432 APT::VersionList::Version const select = _config->FindB("APT::Cache::AllVersions", true) ?
1433 APT::VersionList::ALL : APT::VersionList::CANDIDATE;
1434 APT::VersionList const verset = APT::VersionList::FromCommandLine(CacheFile, CmdL.FileList + 1, select, helper);
1435 for (APT::VersionList::const_iterator Ver = verset.begin(); Ver != verset.end(); ++Ver)
1436 if (DisplayRecord(CacheFile, Ver) == false)
1437 return false;
1438
1439 if (verset.empty() == true)
1440 {
1441 if (helper.virtualPkgs.empty() == true)
1442 return _error->Error(_("No packages found"));
1443 else
1444 _error->Notice(_("No packages found"));
1445 }
1446 return true;
1447 }
1448 /*}}}*/
1449 // ShowPkgNames - Show package names /*{{{*/
1450 // ---------------------------------------------------------------------
1451 /* This does a prefix match on the first argument */
1452 static bool ShowPkgNames(CommandLine &CmdL)
1453 {
1454 pkgCacheFile CacheFile;
1455 if (unlikely(CacheFile.BuildCaches(NULL, false) == false))
1456 return false;
1457 pkgCache::GrpIterator I = CacheFile.GetPkgCache()->GrpBegin();
1458 bool const All = _config->FindB("APT::Cache::AllNames","false");
1459
1460 if (CmdL.FileList[1] != 0)
1461 {
1462 for (;I.end() != true; ++I)
1463 {
1464 if (All == false && I->FirstPackage == 0)
1465 continue;
1466 if (I.FindPkg("any")->VersionList == 0)
1467 continue;
1468 if (strncmp(I.Name(),CmdL.FileList[1],strlen(CmdL.FileList[1])) == 0)
1469 cout << I.Name() << endl;
1470 }
1471
1472 return true;
1473 }
1474
1475 // Show all pkgs
1476 for (;I.end() != true; ++I)
1477 {
1478 if (All == false && I->FirstPackage == 0)
1479 continue;
1480 if (I.FindPkg("any")->VersionList == 0)
1481 continue;
1482 cout << I.Name() << endl;
1483 }
1484
1485 return true;
1486 }
1487 /*}}}*/
1488 // ShowSrcPackage - Show source package records /*{{{*/
1489 // ---------------------------------------------------------------------
1490 /* */
1491 static bool ShowSrcPackage(CommandLine &CmdL)
1492 {
1493 pkgCacheFile CacheFile;
1494 pkgSourceList *List = CacheFile.GetSourceList();
1495 if (unlikely(List == NULL))
1496 return false;
1497
1498 // Create the text record parsers
1499 pkgSrcRecords SrcRecs(*List);
1500 if (_error->PendingError() == true)
1501 return false;
1502
1503 unsigned found = 0;
1504 for (const char **I = CmdL.FileList + 1; *I != 0; I++)
1505 {
1506 SrcRecs.Restart();
1507
1508 pkgSrcRecords::Parser *Parse;
1509 unsigned found_this = 0;
1510 while ((Parse = SrcRecs.Find(*I,false)) != 0) {
1511 cout << Parse->AsStr() << endl;;
1512 found++;
1513 found_this++;
1514 }
1515 if (found_this == 0) {
1516 _error->Warning(_("Unable to locate package %s"),*I);
1517 continue;
1518 }
1519 }
1520 if (found == 0)
1521 _error->Notice(_("No packages found"));
1522 return true;
1523 }
1524 /*}}}*/
1525 // Policy - Show the results of the preferences file /*{{{*/
1526 // ---------------------------------------------------------------------
1527 /* */
1528 static bool Policy(CommandLine &CmdL)
1529 {
1530 pkgCacheFile CacheFile;
1531 pkgCache *Cache = CacheFile.GetPkgCache();
1532 pkgPolicy *Plcy = CacheFile.GetPolicy();
1533 pkgSourceList *SrcList = CacheFile.GetSourceList();
1534 if (unlikely(Cache == NULL || Plcy == NULL || SrcList == NULL))
1535 return false;
1536
1537 /* Should the MultiArchKiller be run to see which pseudo packages for an
1538 arch all package are currently installed? Activating it gives a speed
1539 penality for no real gain beside enhanced debugging, so in general no. */
1540 if (_config->FindB("APT::Cache::Policy::DepCache", false) == true)
1541 CacheFile.GetDepCache();
1542
1543 // Print out all of the package files
1544 if (CmdL.FileList[1] == 0)
1545 {
1546 cout << _("Package files:") << endl;
1547 for (pkgCache::PkgFileIterator F = Cache->FileBegin(); F.end() == false; ++F)
1548 {
1549 // Locate the associated index files so we can derive a description
1550 pkgIndexFile *Indx;
1551 if (SrcList->FindIndex(F,Indx) == false &&
1552 _system->FindIndex(F,Indx) == false)
1553 return _error->Error(_("Cache is out of sync, can't x-ref a package file"));
1554
1555 printf("%4i %s\n",
1556 Plcy->GetPriority(F),Indx->Describe(true).c_str());
1557
1558 // Print the reference information for the package
1559 string Str = F.RelStr();
1560 if (Str.empty() == false)
1561 printf(" release %s\n",F.RelStr().c_str());
1562 if (F.Site() != 0 && F.Site()[0] != 0)
1563 printf(" origin %s\n",F.Site());
1564 }
1565
1566 // Show any packages have explicit pins
1567 cout << _("Pinned packages:") << endl;
1568 pkgCache::PkgIterator I = Cache->PkgBegin();
1569 for (;I.end() != true; ++I)
1570 {
1571 if (Plcy->GetPriority(I) == 0)
1572 continue;
1573
1574 // Print the package name and the version we are forcing to
1575 cout << " " << I.FullName(true) << " -> ";
1576
1577 pkgCache::VerIterator V = Plcy->GetMatch(I);
1578 if (V.end() == true)
1579 cout << _("(not found)") << endl;
1580 else
1581 cout << V.VerStr() << endl;
1582 }
1583
1584 return true;
1585 }
1586
1587 char const * const msgInstalled = _(" Installed: ");
1588 char const * const msgCandidate = _(" Candidate: ");
1589 short const InstalledLessCandidate =
1590 mbstowcs(NULL, msgInstalled, 0) - mbstowcs(NULL, msgCandidate, 0);
1591 short const deepInstalled =
1592 (InstalledLessCandidate < 0 ? (InstalledLessCandidate*-1) : 0) - 1;
1593 short const deepCandidate =
1594 (InstalledLessCandidate > 0 ? (InstalledLessCandidate) : 0) - 1;
1595
1596 // Print out detailed information for each package
1597 APT::CacheSetHelper helper(true, GlobalError::NOTICE);
1598 APT::PackageList pkgset = APT::PackageList::FromCommandLine(CacheFile, CmdL.FileList + 1, helper);
1599 for (APT::PackageList::const_iterator Pkg = pkgset.begin(); Pkg != pkgset.end(); ++Pkg)
1600 {
1601 cout << Pkg.FullName(true) << ":" << endl;
1602
1603 // Installed version
1604 cout << msgInstalled << OutputInDepth(deepInstalled, " ");
1605 if (Pkg->CurrentVer == 0)
1606 cout << _("(none)") << endl;
1607 else
1608 cout << Pkg.CurrentVer().VerStr() << endl;
1609
1610 // Candidate Version
1611 cout << msgCandidate << OutputInDepth(deepCandidate, " ");
1612 pkgCache::VerIterator V = Plcy->GetCandidateVer(Pkg);
1613 if (V.end() == true)
1614 cout << _("(none)") << endl;
1615 else
1616 cout << V.VerStr() << endl;
1617
1618 // Pinned version
1619 if (Plcy->GetPriority(Pkg) != 0)
1620 {
1621 cout << _(" Package pin: ");
1622 V = Plcy->GetMatch(Pkg);
1623 if (V.end() == true)
1624 cout << _("(not found)") << endl;
1625 else
1626 cout << V.VerStr() << endl;
1627 }
1628
1629 // Show the priority tables
1630 cout << _(" Version table:") << endl;
1631 for (V = Pkg.VersionList(); V.end() == false; ++V)
1632 {
1633 if (Pkg.CurrentVer() == V)
1634 cout << " *** " << V.VerStr();
1635 else
1636 cout << " " << V.VerStr();
1637 cout << " " << Plcy->GetPriority(Pkg) << endl;
1638 for (pkgCache::VerFileIterator VF = V.FileList(); VF.end() == false; ++VF)
1639 {
1640 // Locate the associated index files so we can derive a description
1641 pkgIndexFile *Indx;
1642 if (SrcList->FindIndex(VF.File(),Indx) == false &&
1643 _system->FindIndex(VF.File(),Indx) == false)
1644 return _error->Error(_("Cache is out of sync, can't x-ref a package file"));
1645 printf(" %4i %s\n",Plcy->GetPriority(VF.File()),
1646 Indx->Describe(true).c_str());
1647 }
1648 }
1649 }
1650
1651 return true;
1652 }
1653 /*}}}*/
1654 // Madison - Look a bit like katie's madison /*{{{*/
1655 // ---------------------------------------------------------------------
1656 /* */
1657 static bool Madison(CommandLine &CmdL)
1658 {
1659 pkgCacheFile CacheFile;
1660 pkgSourceList *SrcList = CacheFile.GetSourceList();
1661
1662 if (SrcList == 0)
1663 return false;
1664
1665 // Create the src text record parsers and ignore errors about missing
1666 // deb-src lines that are generated from pkgSrcRecords::pkgSrcRecords
1667 pkgSrcRecords SrcRecs(*SrcList);
1668 if (_error->PendingError() == true)
1669 _error->Discard();
1670
1671 APT::CacheSetHelper helper(true, GlobalError::NOTICE);
1672 for (const char **I = CmdL.FileList + 1; *I != 0; I++)
1673 {
1674 _error->PushToStack();
1675 APT::PackageList pkgset = APT::PackageList::FromString(CacheFile, *I, helper);
1676 for (APT::PackageList::const_iterator Pkg = pkgset.begin(); Pkg != pkgset.end(); ++Pkg)
1677 {
1678 for (pkgCache::VerIterator V = Pkg.VersionList(); V.end() == false; ++V)
1679 {
1680 for (pkgCache::VerFileIterator VF = V.FileList(); VF.end() == false; ++VF)
1681 {
1682 // This might be nice, but wouldn't uniquely identify the source -mdz
1683 // if (VF.File().Archive() != 0)
1684 // {
1685 // cout << setw(10) << Pkg.Name() << " | " << setw(10) << V.VerStr() << " | "
1686 // << VF.File().Archive() << endl;
1687 // }
1688
1689 // Locate the associated index files so we can derive a description
1690 for (pkgSourceList::const_iterator S = SrcList->begin(); S != SrcList->end(); ++S)
1691 {
1692 vector<pkgIndexFile *> *Indexes = (*S)->GetIndexFiles();
1693 for (vector<pkgIndexFile *>::const_iterator IF = Indexes->begin();
1694 IF != Indexes->end(); ++IF)
1695 {
1696 if ((*IF)->FindInCache(*(VF.File().Cache())) == VF.File())
1697 {
1698 cout << setw(10) << Pkg.FullName(true) << " | " << setw(10) << V.VerStr() << " | "
1699 << (*IF)->Describe(true) << endl;
1700 }
1701 }
1702 }
1703 }
1704 }
1705 }
1706
1707 SrcRecs.Restart();
1708 pkgSrcRecords::Parser *SrcParser;
1709 bool foundSomething = false;
1710 while ((SrcParser = SrcRecs.Find(*I, false)) != 0)
1711 {
1712 foundSomething = true;
1713 // Maybe support Release info here too eventually
1714 cout << setw(10) << SrcParser->Package() << " | "
1715 << setw(10) << SrcParser->Version() << " | "
1716 << SrcParser->Index().Describe(true) << endl;
1717 }
1718 if (foundSomething == true)
1719 _error->RevertToStack();
1720 else
1721 _error->MergeWithStack();
1722 }
1723
1724 return true;
1725 }
1726 /*}}}*/
1727 // GenCaches - Call the main cache generator /*{{{*/
1728 // ---------------------------------------------------------------------
1729 /* */
1730 static bool GenCaches(CommandLine &)
1731 {
1732 OpTextProgress Progress(*_config);
1733
1734 pkgCacheFile CacheFile;
1735 return CacheFile.BuildCaches(&Progress, true);
1736 }
1737 /*}}}*/
1738 // ShowHelp - Show a help screen /*{{{*/
1739 // ---------------------------------------------------------------------
1740 /* */
1741 static bool ShowHelp(CommandLine &)
1742 {
1743 ioprintf(cout,_("%s %s for %s compiled on %s %s\n"),PACKAGE,PACKAGE_VERSION,
1744 COMMON_ARCH,__DATE__,__TIME__);
1745
1746 if (_config->FindB("version") == true)
1747 return true;
1748
1749 cout <<
1750 _("Usage: apt-cache [options] command\n"
1751 " apt-cache [options] showpkg pkg1 [pkg2 ...]\n"
1752 " apt-cache [options] showsrc pkg1 [pkg2 ...]\n"
1753 "\n"
1754 "apt-cache is a low-level tool used to query information\n"
1755 "from APT's binary cache files\n"
1756 "\n"
1757 "Commands:\n"
1758 " gencaches - Build both the package and source cache\n"
1759 " showpkg - Show some general information for a single package\n"
1760 " showsrc - Show source records\n"
1761 " stats - Show some basic statistics\n"
1762 " dump - Show the entire file in a terse form\n"
1763 " dumpavail - Print an available file to stdout\n"
1764 " unmet - Show unmet dependencies\n"
1765 " search - Search the package list for a regex pattern\n"
1766 " show - Show a readable record for the package\n"
1767 " depends - Show raw dependency information for a package\n"
1768 " rdepends - Show reverse dependency information for a package\n"
1769 " pkgnames - List the names of all packages in the system\n"
1770 " dotty - Generate package graphs for GraphViz\n"
1771 " xvcg - Generate package graphs for xvcg\n"
1772 " policy - Show policy settings\n"
1773 "\n"
1774 "Options:\n"
1775 " -h This help text.\n"
1776 " -p=? The package cache.\n"
1777 " -s=? The source cache.\n"
1778 " -q Disable progress indicator.\n"
1779 " -i Show only important deps for the unmet command.\n"
1780 " -c=? Read this configuration file\n"
1781 " -o=? Set an arbitrary configuration option, eg -o dir::cache=/tmp\n"
1782 "See the apt-cache(8) and apt.conf(5) manual pages for more information.\n");
1783 return true;
1784 }
1785 /*}}}*/
1786 int main(int argc,const char *argv[]) /*{{{*/
1787 {
1788 CommandLine::Dispatch Cmds[] = {{"help",&ShowHelp},
1789 {"gencaches",&GenCaches},
1790 {"showsrc",&ShowSrcPackage},
1791 {"showpkg",&DumpPackage},
1792 {"stats",&Stats},
1793 {"dump",&Dump},
1794 {"dumpavail",&DumpAvail},
1795 {"unmet",&UnMet},
1796 {"search",&Search},
1797 {"depends",&Depends},
1798 {"rdepends",&RDepends},
1799 {"dotty",&Dotty},
1800 {"xvcg",&XVcg},
1801 {"show",&ShowPackage},
1802 {"pkgnames",&ShowPkgNames},
1803 {"showauto",&ShowAuto},
1804 {"policy",&Policy},
1805 {"madison",&Madison},
1806 {0,0}};
1807
1808 std::vector<CommandLine::Args> Args = getCommandArgs("apt-cache", CommandLine::GetCommand(Cmds, argc, argv));
1809
1810 // Set up gettext support
1811 setlocale(LC_ALL,"");
1812 textdomain(PACKAGE);
1813
1814 // Parse the command line and initialize the package library
1815 CommandLine CmdL(Args.data(),_config);
1816 if (pkgInitConfig(*_config) == false ||
1817 CmdL.Parse(argc,argv) == false ||
1818 pkgInitSystem(*_config,_system) == false)
1819 {
1820 _error->DumpErrors();
1821 return 100;
1822 }
1823
1824 // See if the help should be shown
1825 if (_config->FindB("help") == true ||
1826 CmdL.FileSize() == 0)
1827 {
1828 ShowHelp(CmdL);
1829 return 0;
1830 }
1831
1832 // Deal with stdout not being a tty
1833 if (!isatty(STDOUT_FILENO) && _config->FindI("quiet", -1) == -1)
1834 _config->Set("quiet","1");
1835
1836 if (_config->Exists("APT::Cache::Generate") == true)
1837 _config->Set("pkgCacheFile::Generate", _config->FindB("APT::Cache::Generate", true));
1838
1839 // Match the operation
1840 CmdL.DispatchArg(Cmds);
1841
1842 // Print any errors or warnings found during parsing
1843 bool const Errors = _error->PendingError();
1844 if (_config->FindI("quiet",0) > 0)
1845 _error->DumpErrors();
1846 else
1847 _error->DumpErrors(GlobalError::DEBUG);
1848 return Errors == true ? 100 : 0;
1849 }
1850 /*}}}*/