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