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