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