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