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