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