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