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