Join with aliencode
[ntk/apt.git] / cmdline / apt-cache.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 // $Id: apt-cache.cc,v 1.44 2001/02/20 07:03:17 jgg 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 <iostream.h>
35 #include <unistd.h>
36 #include <errno.h>
37 #include <regex.h>
38 #include <stdio.h>
39 /*}}}*/
40
41 pkgCache *GCache = 0;
42
43 // LocalitySort - Sort a version list by package file locality /*{{{*/
44 // ---------------------------------------------------------------------
45 /* */
46 int LocalityCompare(const void *a, const void *b)
47 {
48 pkgCache::VerFile *A = *(pkgCache::VerFile **)a;
49 pkgCache::VerFile *B = *(pkgCache::VerFile **)b;
50
51 if (A == 0 && B == 0)
52 return 0;
53 if (A == 0)
54 return 1;
55 if (B == 0)
56 return -1;
57
58 if (A->File == B->File)
59 return A->Offset - B->Offset;
60 return A->File - B->File;
61 }
62
63 void LocalitySort(pkgCache::VerFile **begin,
64 unsigned long Count,size_t Size)
65 {
66 qsort(begin,Count,Size,LocalityCompare);
67 }
68 /*}}}*/
69 // UnMet - Show unmet dependencies /*{{{*/
70 // ---------------------------------------------------------------------
71 /* */
72 bool UnMet(CommandLine &CmdL)
73 {
74 pkgCache &Cache = *GCache;
75 bool Important = _config->FindB("APT::Cache::Important",false);
76
77 for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; P++)
78 {
79 for (pkgCache::VerIterator V = P.VersionList(); V.end() == false; V++)
80 {
81 bool Header = false;
82 for (pkgCache::DepIterator D = V.DependsList(); D.end() == false;)
83 {
84 // Collect or groups
85 pkgCache::DepIterator Start;
86 pkgCache::DepIterator End;
87 D.GlobOr(Start,End);
88
89 // Skip conflicts and replaces
90 if (End->Type != pkgCache::Dep::PreDepends &&
91 End->Type != pkgCache::Dep::Depends &&
92 End->Type != pkgCache::Dep::Suggests &&
93 End->Type != pkgCache::Dep::Recommends)
94 continue;
95
96 // Important deps only
97 if (Important == true)
98 if (End->Type != pkgCache::Dep::PreDepends &&
99 End->Type != pkgCache::Dep::Depends)
100 continue;
101
102 // Verify the or group
103 bool OK = false;
104 pkgCache::DepIterator RealStart = Start;
105 do
106 {
107 // See if this dep is Ok
108 pkgCache::Version **VList = Start.AllTargets();
109 if (*VList != 0)
110 {
111 OK = true;
112 delete [] VList;
113 break;
114 }
115 delete [] VList;
116
117 if (Start == End)
118 break;
119 Start++;
120 }
121 while (1);
122
123 // The group is OK
124 if (OK == true)
125 continue;
126
127 // Oops, it failed..
128 if (Header == false)
129 ioprintf(cout,_("Package %s version %s has an unmet dep:\n"),
130 P.Name(),V.VerStr());
131 Header = true;
132
133 // Print out the dep type
134 cout << " " << End.DepType() << ": ";
135
136 // Show the group
137 Start = RealStart;
138 do
139 {
140 cout << Start.TargetPkg().Name();
141 if (Start.TargetVer() != 0)
142 cout << " (" << Start.CompType() << " " << Start.TargetVer() <<
143 ")";
144 if (Start == End)
145 break;
146 cout << " | ";
147 Start++;
148 }
149 while (1);
150
151 cout << endl;
152 }
153 }
154 }
155 return true;
156 }
157 /*}}}*/
158 // DumpPackage - Show a dump of a package record /*{{{*/
159 // ---------------------------------------------------------------------
160 /* */
161 bool DumpPackage(CommandLine &CmdL)
162 {
163 pkgCache &Cache = *GCache;
164 for (const char **I = CmdL.FileList + 1; *I != 0; I++)
165 {
166 pkgCache::PkgIterator Pkg = Cache.FindPkg(*I);
167 if (Pkg.end() == true)
168 {
169 _error->Warning(_("Unable to locate package %s"),*I);
170 continue;
171 }
172
173 cout << "Package: " << Pkg.Name() << endl;
174 cout << "Versions: " << endl;
175 for (pkgCache::VerIterator Cur = Pkg.VersionList(); Cur.end() != true; Cur++)
176 {
177 cout << Cur.VerStr();
178 for (pkgCache::VerFileIterator Vf = Cur.FileList(); Vf.end() == false; Vf++)
179 cout << "(" << Vf.File().FileName() << ")";
180 cout << endl;
181 }
182
183 cout << endl;
184
185 cout << "Reverse Depends: " << endl;
186 for (pkgCache::DepIterator D = Pkg.RevDependsList(); D.end() != true; D++)
187 {
188 cout << " " << D.ParentPkg().Name() << ',' << D.TargetPkg().Name();
189 if (D->Version != 0)
190 cout << ' ' << D.TargetVer() << endl;
191 else
192 cout << endl;
193 }
194
195 cout << "Dependencies: " << endl;
196 for (pkgCache::VerIterator Cur = Pkg.VersionList(); Cur.end() != true; Cur++)
197 {
198 cout << Cur.VerStr() << " - ";
199 for (pkgCache::DepIterator Dep = Cur.DependsList(); Dep.end() != true; Dep++)
200 cout << Dep.TargetPkg().Name() << " (" << (int)Dep->CompareOp << " " << Dep.TargetVer() << ") ";
201 cout << endl;
202 }
203
204 cout << "Provides: " << endl;
205 for (pkgCache::VerIterator Cur = Pkg.VersionList(); Cur.end() != true; Cur++)
206 {
207 cout << Cur.VerStr() << " - ";
208 for (pkgCache::PrvIterator Prv = Cur.ProvidesList(); Prv.end() != true; Prv++)
209 cout << Prv.ParentPkg().Name() << " ";
210 cout << endl;
211 }
212 cout << "Reverse Provides: " << endl;
213 for (pkgCache::PrvIterator Prv = Pkg.ProvidesList(); Prv.end() != true; Prv++)
214 cout << Prv.OwnerPkg().Name() << " " << Prv.OwnerVer().VerStr() << endl;
215 }
216
217 return true;
218 }
219 /*}}}*/
220 // Stats - Dump some nice statistics /*{{{*/
221 // ---------------------------------------------------------------------
222 /* */
223 bool Stats(CommandLine &Cmd)
224 {
225 pkgCache &Cache = *GCache;
226 cout << _("Total Package Names : ") << Cache.Head().PackageCount << " (" <<
227 SizeToStr(Cache.Head().PackageCount*Cache.Head().PackageSz) << ')' << endl;
228
229 int Normal = 0;
230 int Virtual = 0;
231 int NVirt = 0;
232 int DVirt = 0;
233 int Missing = 0;
234 pkgCache::PkgIterator I = Cache.PkgBegin();
235 for (;I.end() != true; I++)
236 {
237 if (I->VersionList != 0 && I->ProvidesList == 0)
238 {
239 Normal++;
240 continue;
241 }
242
243 if (I->VersionList != 0 && I->ProvidesList != 0)
244 {
245 NVirt++;
246 continue;
247 }
248
249 if (I->VersionList == 0 && I->ProvidesList != 0)
250 {
251 // Only 1 provides
252 if (I.ProvidesList()->NextProvides == 0)
253 {
254 DVirt++;
255 }
256 else
257 Virtual++;
258 continue;
259 }
260 if (I->VersionList == 0 && I->ProvidesList == 0)
261 {
262 Missing++;
263 continue;
264 }
265 }
266 cout << _(" Normal Packages: ") << Normal << endl;
267 cout << _(" Pure Virtual Packages: ") << Virtual << endl;
268 cout << _(" Single Virtual Packages: ") << DVirt << endl;
269 cout << _(" Mixed Virtual Packages: ") << NVirt << endl;
270 cout << _(" Missing: ") << Missing << endl;
271
272 cout << _("Total Distinct Versions: ") << Cache.Head().VersionCount << " (" <<
273 SizeToStr(Cache.Head().VersionCount*Cache.Head().VersionSz) << ')' << endl;
274 cout << _("Total Dependencies: ") << Cache.Head().DependsCount << " (" <<
275 SizeToStr(Cache.Head().DependsCount*Cache.Head().DependencySz) << ')' << endl;
276
277 cout << _("Total Ver/File relations: ") << Cache.Head().VerFileCount << " (" <<
278 SizeToStr(Cache.Head().VerFileCount*Cache.Head().VerFileSz) << ')' << endl;
279 cout << _("Total Provides Mappings: ") << Cache.Head().ProvidesCount << " (" <<
280 SizeToStr(Cache.Head().ProvidesCount*Cache.Head().ProvidesSz) << ')' << endl;
281
282 // String list stats
283 unsigned long Size = 0;
284 unsigned long Count = 0;
285 for (pkgCache::StringItem *I = Cache.StringItemP + Cache.Head().StringList;
286 I!= Cache.StringItemP; I = Cache.StringItemP + I->NextItem)
287 {
288 Count++;
289 Size += strlen(Cache.StrP + I->String) + 1;
290 }
291 cout << _("Total Globbed Strings: ") << Count << " (" << SizeToStr(Size) << ')' << endl;
292
293 unsigned long DepVerSize = 0;
294 for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; P++)
295 {
296 for (pkgCache::VerIterator V = P.VersionList(); V.end() == false; V++)
297 {
298 for (pkgCache::DepIterator D = V.DependsList(); D.end() == false; D++)
299 {
300 if (D->Version != 0)
301 DepVerSize += strlen(D.TargetVer()) + 1;
302 }
303 }
304 }
305 cout << _("Total Dependency Version space: ") << SizeToStr(DepVerSize) << endl;
306
307 unsigned long Slack = 0;
308 for (int I = 0; I != 7; I++)
309 Slack += Cache.Head().Pools[I].ItemSize*Cache.Head().Pools[I].Count;
310 cout << _("Total Slack space: ") << SizeToStr(Slack) << endl;
311
312 unsigned long Total = 0;
313 Total = Slack + Size + Cache.Head().DependsCount*Cache.Head().DependencySz +
314 Cache.Head().VersionCount*Cache.Head().VersionSz +
315 Cache.Head().PackageCount*Cache.Head().PackageSz +
316 Cache.Head().VerFileCount*Cache.Head().VerFileSz +
317 Cache.Head().ProvidesCount*Cache.Head().ProvidesSz;
318 cout << _("Total Space Accounted for: ") << SizeToStr(Total) << endl;
319
320 return true;
321 }
322 /*}}}*/
323 // Dump - show everything /*{{{*/
324 // ---------------------------------------------------------------------
325 /* This is worthless except fer debugging things */
326 bool Dump(CommandLine &Cmd)
327 {
328 pkgCache &Cache = *GCache;
329 cout << "Using Versioning System: " << Cache.VS->Label << endl;
330
331 for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; P++)
332 {
333 cout << "Package: " << P.Name() << endl;
334 for (pkgCache::VerIterator V = P.VersionList(); V.end() == false; V++)
335 {
336 cout << " Version: " << V.VerStr() << endl;
337 cout << " File: " << V.FileList().File().FileName() << endl;
338 for (pkgCache::DepIterator D = V.DependsList(); D.end() == false; D++)
339 cout << " Depends: " << D.TargetPkg().Name() << ' ' << D.TargetVer() << endl;
340 }
341 }
342
343 for (pkgCache::PkgFileIterator F = Cache.FileBegin(); F.end() == false; F++)
344 {
345 cout << "File: " << F.FileName() << endl;
346 cout << " Type: " << F.IndexType() << endl;
347 cout << " Size: " << F->Size << endl;
348 cout << " ID: " << F->ID << endl;
349 cout << " Flags: " << F->Flags << endl;
350 cout << " Time: " << TimeRFC1123(F->mtime) << endl;
351 cout << " Archive: " << F.Archive() << endl;
352 cout << " Component: " << F.Component() << endl;
353 cout << " Version: " << F.Version() << endl;
354 cout << " Origin: " << F.Origin() << endl;
355 cout << " Site: " << F.Site() << endl;
356 cout << " Label: " << F.Label() << endl;
357 cout << " Architecture: " << F.Architecture() << endl;
358 }
359
360 return true;
361 }
362 /*}}}*/
363 // DumpAvail - Print out the available list /*{{{*/
364 // ---------------------------------------------------------------------
365 /* This is needed to make dpkg --merge happy.. I spent a bit of time to
366 make this run really fast, perhaps I went a little overboard.. */
367 bool DumpAvail(CommandLine &Cmd)
368 {
369 pkgCache &Cache = *GCache;
370
371 pkgPolicy Plcy(&Cache);
372 if (ReadPinFile(Plcy) == false)
373 return false;
374
375 pkgCache::VerFile **VFList = new pkgCache::VerFile *[Cache.HeaderP->PackageCount];
376 memset(VFList,0,sizeof(*VFList)*Cache.HeaderP->PackageCount);
377
378 // Map versions that we want to write out onto the VerList array.
379 for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; P++)
380 {
381 if (P->VersionList == 0)
382 continue;
383
384 /* Find the proper version to use. If the policy says there are no
385 possible selections we return the installed version, if available..
386 This prevents dselect from making it obsolete. */
387 pkgCache::VerIterator V = Plcy.GetCandidateVer(P);
388 if (V.end() == true)
389 {
390 if (P->CurrentVer == 0)
391 continue;
392 V = P.CurrentVer();
393 }
394
395 pkgCache::VerFileIterator VF = V.FileList();
396 for (; VF.end() == false ; VF++)
397 if ((VF.File()->Flags & pkgCache::Flag::NotSource) == 0)
398 break;
399
400 /* Okay, here we have a bit of a problem.. The policy has selected the
401 currently installed package - however it only exists in the
402 status file.. We need to write out something or dselect will mark
403 the package as obsolete! Thus we emit the status file entry, but
404 below we remove the status line to make it valid for the
405 available file. However! We only do this if their do exist *any*
406 non-source versions of the package - that way the dselect obsolete
407 handling works OK. */
408 if (VF.end() == true)
409 {
410 for (pkgCache::VerIterator Cur = P.VersionList(); Cur.end() != true; Cur++)
411 {
412 for (VF = Cur.FileList(); VF.end() == false; VF++)
413 {
414 if ((VF.File()->Flags & pkgCache::Flag::NotSource) == 0)
415 {
416 VF = V.FileList();
417 break;
418 }
419 }
420
421 if (VF.end() == false)
422 break;
423 }
424 }
425
426 VFList[P->ID] = VF;
427 }
428
429 LocalitySort(VFList,Cache.HeaderP->PackageCount,sizeof(*VFList));
430
431 // Iterate over all the package files and write them out.
432 char *Buffer = new char[Cache.HeaderP->MaxVerFileSize+10];
433 for (pkgCache::VerFile **J = VFList; *J != 0;)
434 {
435 pkgCache::PkgFileIterator File(Cache,(*J)->File + Cache.PkgFileP);
436 if (File.IsOk() == false)
437 {
438 _error->Error(_("Package file %s is out of sync."),File.FileName());
439 break;
440 }
441
442 FileFd PkgF(File.FileName(),FileFd::ReadOnly);
443 if (_error->PendingError() == true)
444 break;
445
446 /* Write all of the records from this package file, since we
447 already did locality sorting we can now just seek through the
448 file in read order. We apply 1 more optimization here, since often
449 there will be < 1 byte gaps between records (for the \n) we read that
450 into the next buffer and offset a bit.. */
451 unsigned long Pos = 0;
452 for (; *J != 0; J++)
453 {
454 if ((*J)->File + Cache.PkgFileP != File)
455 break;
456
457 const pkgCache::VerFile &VF = **J;
458
459 // Read the record and then write it out again.
460 unsigned long Jitter = VF.Offset - Pos;
461 if (Jitter > 8)
462 {
463 if (PkgF.Seek(VF.Offset) == false)
464 break;
465 Jitter = 0;
466 }
467
468 if (PkgF.Read(Buffer,VF.Size + Jitter) == false)
469 break;
470 Buffer[VF.Size + Jitter] = '\n';
471
472 // See above..
473 if ((File->Flags & pkgCache::Flag::NotSource) == pkgCache::Flag::NotSource)
474 {
475 pkgTagSection Tags;
476 TFRewriteData RW[] = {{"Status",0},{}};
477 const char *Zero = 0;
478 if (Tags.Scan(Buffer+Jitter,VF.Size+1) == false ||
479 TFRewrite(stdout,Tags,&Zero,RW) == false)
480 {
481 _error->Error("Internal Error, Unable to parse a package record");
482 break;
483 }
484 fputc('\n',stdout);
485 }
486 else
487 {
488 if (fwrite(Buffer+Jitter,VF.Size+1,1,stdout) != 1)
489 break;
490 }
491
492 Pos = VF.Offset + VF.Size;
493 }
494
495 fflush(stdout);
496 if (_error->PendingError() == true)
497 break;
498 }
499
500 delete [] Buffer;
501 delete [] VFList;
502 return !_error->PendingError();
503 }
504 /*}}}*/
505 // Depends - Print out a dependency tree /*{{{*/
506 // ---------------------------------------------------------------------
507 /* */
508 bool Depends(CommandLine &CmdL)
509 {
510 pkgCache &Cache = *GCache;
511 SPtrArray<unsigned> Colours = new unsigned[Cache.Head().PackageCount];
512 memset(Colours,0,sizeof(*Colours)*Cache.Head().PackageCount);
513
514 for (const char **I = CmdL.FileList + 1; *I != 0; I++)
515 {
516 pkgCache::PkgIterator Pkg = Cache.FindPkg(*I);
517 if (Pkg.end() == true)
518 {
519 _error->Warning(_("Unable to locate package %s"),*I);
520 continue;
521 }
522 Colours[Pkg->ID] = 1;
523 }
524
525 bool Recurse = _config->FindB("APT::Cache::RecurseDepends",false);
526 bool DidSomething;
527 do
528 {
529 DidSomething = false;
530 for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; Pkg++)
531 {
532 if (Colours[Pkg->ID] != 1)
533 continue;
534 Colours[Pkg->ID] = 2;
535 DidSomething = true;
536
537 pkgCache::VerIterator Ver = Pkg.VersionList();
538 if (Ver.end() == true)
539 {
540 cout << '<' << Pkg.Name() << '>' << endl;
541 continue;
542 }
543
544 cout << Pkg.Name() << endl;
545
546 for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false; D++)
547 {
548 if ((D->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or)
549 cout << " |";
550 else
551 cout << " ";
552
553 // Show the package
554 pkgCache::PkgIterator Trg = D.TargetPkg();
555 if (Trg->VersionList == 0)
556 cout << D.DepType() << ": <" << Trg.Name() << ">" << endl;
557 else
558 cout << D.DepType() << ": " << Trg.Name() << endl;
559
560 if (Recurse == true)
561 Colours[D.TargetPkg()->ID]++;
562
563 // Display all solutions
564 SPtrArray<pkgCache::Version *> List = D.AllTargets();
565 pkgPrioSortList(Cache,List);
566 for (pkgCache::Version **I = List; *I != 0; I++)
567 {
568 pkgCache::VerIterator V(Cache,*I);
569 if (V != Cache.VerP + V.ParentPkg()->VersionList ||
570 V->ParentPkg == D->Package)
571 continue;
572 cout << " " << V.ParentPkg().Name() << endl;
573
574 if (Recurse == true)
575 Colours[D.ParentPkg()->ID]++;
576 }
577 }
578 }
579 }
580 while (DidSomething == true);
581
582 return true;
583 }
584 /*}}}*/
585 // Dotty - Generate a graph for Dotty /*{{{*/
586 // ---------------------------------------------------------------------
587 /* Dotty is the graphvis program for generating graphs. It is a fairly
588 simple queuing algorithm that just writes dependencies and nodes.
589 http://www.research.att.com/sw/tools/graphviz/ */
590 bool Dotty(CommandLine &CmdL)
591 {
592 pkgCache &Cache = *GCache;
593 bool GivenOnly = _config->FindB("APT::Cache::GivenOnly",false);
594
595 /* Normal packages are boxes
596 Pure Provides are triangles
597 Mixed are diamonds
598 Hexagons are missing packages*/
599 const char *Shapes[] = {"hexagon","triangle","box","diamond"};
600
601 /* Initialize the list of packages to show.
602 1 = To Show
603 2 = To Show no recurse
604 3 = Emitted no recurse
605 4 = Emitted
606 0 = None */
607 enum States {None=0, ToShow, ToShowNR, DoneNR, Done};
608 enum TheFlags {ForceNR=(1<<0)};
609 unsigned char *Show = new unsigned char[Cache.Head().PackageCount];
610 unsigned char *Flags = new unsigned char[Cache.Head().PackageCount];
611 unsigned char *ShapeMap = new unsigned char[Cache.Head().PackageCount];
612
613 // Show everything if no arguments given
614 if (CmdL.FileList[1] == 0)
615 for (unsigned long I = 0; I != Cache.Head().PackageCount; I++)
616 Show[I] = ToShow;
617 else
618 for (unsigned long I = 0; I != Cache.Head().PackageCount; I++)
619 Show[I] = None;
620 memset(Flags,0,sizeof(*Flags)*Cache.Head().PackageCount);
621
622 // Map the shapes
623 for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; Pkg++)
624 {
625 if (Pkg->VersionList == 0)
626 {
627 // Missing
628 if (Pkg->ProvidesList == 0)
629 ShapeMap[Pkg->ID] = 0;
630 else
631 ShapeMap[Pkg->ID] = 1;
632 }
633 else
634 {
635 // Normal
636 if (Pkg->ProvidesList == 0)
637 ShapeMap[Pkg->ID] = 2;
638 else
639 ShapeMap[Pkg->ID] = 3;
640 }
641 }
642
643 // Load the list of packages from the command line into the show list
644 for (const char **I = CmdL.FileList + 1; *I != 0; I++)
645 {
646 // Process per-package flags
647 string P = *I;
648 bool Force = false;
649 if (P.length() > 3)
650 {
651 if (P.end()[-1] == '^')
652 {
653 Force = true;
654 P.erase(P.end()-1);
655 }
656
657 if (P.end()[-1] == ',')
658 P.erase(P.end()-1);
659 }
660
661 // Locate the package
662 pkgCache::PkgIterator Pkg = Cache.FindPkg(P);
663 if (Pkg.end() == true)
664 {
665 _error->Warning(_("Unable to locate package %s"),*I);
666 continue;
667 }
668 Show[Pkg->ID] = ToShow;
669
670 if (Force == true)
671 Flags[Pkg->ID] |= ForceNR;
672 }
673
674 // Little header
675 printf("digraph packages {\n");
676 printf("concentrate=true;\n");
677 printf("size=\"30,40\";\n");
678
679 bool Act = true;
680 while (Act == true)
681 {
682 Act = false;
683 for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; Pkg++)
684 {
685 // See we need to show this package
686 if (Show[Pkg->ID] == None || Show[Pkg->ID] >= DoneNR)
687 continue;
688
689 // Colour as done
690 if (Show[Pkg->ID] == ToShowNR || (Flags[Pkg->ID] & ForceNR) == ForceNR)
691 {
692 // Pure Provides and missing packages have no deps!
693 if (ShapeMap[Pkg->ID] == 0 || ShapeMap[Pkg->ID] == 1)
694 Show[Pkg->ID] = Done;
695 else
696 Show[Pkg->ID] = DoneNR;
697 }
698 else
699 Show[Pkg->ID] = Done;
700 Act = true;
701
702 // No deps to map out
703 if (Pkg->VersionList == 0 || Show[Pkg->ID] == DoneNR)
704 continue;
705
706 pkgCache::VerIterator Ver = Pkg.VersionList();
707 for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false; D++)
708 {
709 // See if anything can meet this dep
710 // Walk along the actual package providing versions
711 bool Hit = false;
712 pkgCache::PkgIterator DPkg = D.TargetPkg();
713 for (pkgCache::VerIterator I = DPkg.VersionList();
714 I.end() == false && Hit == false; I++)
715 {
716 if (Cache.VS->CheckDep(I.VerStr(),D->CompareOp,D.TargetVer()) == true)
717 Hit = true;
718 }
719
720 // Follow all provides
721 for (pkgCache::PrvIterator I = DPkg.ProvidesList();
722 I.end() == false && Hit == false; I++)
723 {
724 if (Cache.VS->CheckDep(I.ProvideVersion(),D->CompareOp,D.TargetVer()) == false)
725 Hit = true;
726 }
727
728 // Only graph critical deps
729 if (D.IsCritical() == true)
730 {
731 printf("\"%s\" -> \"%s\"",Pkg.Name(),D.TargetPkg().Name());
732
733 // Colour the node for recursion
734 if (Show[D.TargetPkg()->ID] <= DoneNR)
735 {
736 /* If a conflicts does not meet anything in the database
737 then show the relation but do not recurse */
738 if (Hit == false &&
739 (D->Type == pkgCache::Dep::Conflicts ||
740 D->Type == pkgCache::Dep::Obsoletes))
741 {
742 if (Show[D.TargetPkg()->ID] == None &&
743 Show[D.TargetPkg()->ID] != ToShow)
744 Show[D.TargetPkg()->ID] = ToShowNR;
745 }
746 else
747 {
748 if (GivenOnly == true && Show[D.TargetPkg()->ID] != ToShow)
749 Show[D.TargetPkg()->ID] = ToShowNR;
750 else
751 Show[D.TargetPkg()->ID] = ToShow;
752 }
753 }
754
755 // Edge colour
756 switch(D->Type)
757 {
758 case pkgCache::Dep::Conflicts:
759 case pkgCache::Dep::Obsoletes:
760 printf("[color=springgreen];\n");
761 break;
762
763 case pkgCache::Dep::PreDepends:
764 printf("[color=blue];\n");
765 break;
766
767 default:
768 printf(";\n");
769 break;
770 }
771 }
772 }
773 }
774 }
775
776 /* Draw the box colours after the fact since we can not tell what colour
777 they should be until everything is finished drawing */
778 for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; Pkg++)
779 {
780 if (Show[Pkg->ID] < DoneNR)
781 continue;
782
783 // Orange box for early recursion stoppage
784 if (Show[Pkg->ID] == DoneNR)
785 printf("\"%s\" [color=orange,shape=%s];\n",Pkg.Name(),
786 Shapes[ShapeMap[Pkg->ID]]);
787 else
788 printf("\"%s\" [shape=%s];\n",Pkg.Name(),
789 Shapes[ShapeMap[Pkg->ID]]);
790 }
791
792 printf("}\n");
793 return true;
794 }
795 /*}}}*/
796 // DoAdd - Perform an adding operation /*{{{*/
797 // ---------------------------------------------------------------------
798 /* */
799 bool DoAdd(CommandLine &CmdL)
800 {
801 return _error->Error("Unimplemented");
802 #if 0
803 // Make sure there is at least one argument
804 if (CmdL.FileSize() <= 1)
805 return _error->Error("You must give at least one file name");
806
807 // Open the cache
808 FileFd CacheF(_config->FindFile("Dir::Cache::pkgcache"),FileFd::WriteAny);
809 if (_error->PendingError() == true)
810 return false;
811
812 DynamicMMap Map(CacheF,MMap::Public);
813 if (_error->PendingError() == true)
814 return false;
815
816 OpTextProgress Progress(*_config);
817 pkgCacheGenerator Gen(Map,Progress);
818 if (_error->PendingError() == true)
819 return false;
820
821 unsigned long Length = CmdL.FileSize() - 1;
822 for (const char **I = CmdL.FileList + 1; *I != 0; I++)
823 {
824 Progress.OverallProgress(I - CmdL.FileList,Length,1,"Generating cache");
825 Progress.SubProgress(Length);
826
827 // Do the merge
828 FileFd TagF(*I,FileFd::ReadOnly);
829 debListParser Parser(TagF);
830 if (_error->PendingError() == true)
831 return _error->Error("Problem opening %s",*I);
832
833 if (Gen.SelectFile(*I,"") == false)
834 return _error->Error("Problem with SelectFile");
835
836 if (Gen.MergeList(Parser) == false)
837 return _error->Error("Problem with MergeList");
838 }
839
840 Progress.Done();
841 GCache = &Gen.GetCache();
842 Stats(CmdL);
843
844 return true;
845 #endif
846 }
847 /*}}}*/
848 // DisplayRecord - Displays the complete record for the package /*{{{*/
849 // ---------------------------------------------------------------------
850 /* This displays the package record from the proper package index file.
851 It is not used by DumpAvail for performance reasons. */
852 bool DisplayRecord(pkgCache::VerIterator V)
853 {
854 // Find an appropriate file
855 pkgCache::VerFileIterator Vf = V.FileList();
856 for (; Vf.end() == false; Vf++)
857 if ((Vf.File()->Flags & pkgCache::Flag::NotSource) == 0)
858 break;
859 if (Vf.end() == true)
860 Vf = V.FileList();
861
862 // Check and load the package list file
863 pkgCache::PkgFileIterator I = Vf.File();
864 if (I.IsOk() == false)
865 return _error->Error(_("Package file %s is out of sync."),I.FileName());
866
867 FileFd PkgF(I.FileName(),FileFd::ReadOnly);
868 if (_error->PendingError() == true)
869 return false;
870
871 // Read the record and then write it out again.
872 unsigned char *Buffer = new unsigned char[GCache->HeaderP->MaxVerFileSize+1];
873 Buffer[V.FileList()->Size] = '\n';
874 if (PkgF.Seek(V.FileList()->Offset) == false ||
875 PkgF.Read(Buffer,V.FileList()->Size) == false ||
876 write(STDOUT_FILENO,Buffer,V.FileList()->Size+1) != V.FileList()->Size+1)
877 {
878 delete [] Buffer;
879 return false;
880 }
881
882 delete [] Buffer;
883
884 return true;
885 }
886 /*}}}*/
887 // Search - Perform a search /*{{{*/
888 // ---------------------------------------------------------------------
889 /* This searches the package names and pacakge descriptions for a pattern */
890 struct ExVerFile
891 {
892 pkgCache::VerFile *Vf;
893 bool NameMatch;
894 };
895
896 bool Search(CommandLine &CmdL)
897 {
898 pkgCache &Cache = *GCache;
899 bool ShowFull = _config->FindB("APT::Cache::ShowFull",false);
900 bool NamesOnly = _config->FindB("APT::Cache::NamesOnly",false);
901 unsigned NumPatterns = CmdL.FileSize() -1;
902
903 pkgDepCache::Policy Plcy;
904
905 // Make sure there is at least one argument
906 if (NumPatterns < 1)
907 return _error->Error(_("You must give exactly one pattern"));
908
909 // Compile the regex pattern
910 regex_t *Patterns = new regex_t[NumPatterns];
911 memset(Patterns,0,sizeof(*Patterns)*NumPatterns);
912 for (unsigned I = 0; I != NumPatterns; I++)
913 {
914 if (regcomp(&Patterns[I],CmdL.FileList[I+1],REG_EXTENDED | REG_ICASE |
915 REG_NOSUB) != 0)
916 {
917 for (; I != 0; I--)
918 regfree(&Patterns[I]);
919 return _error->Error("Regex compilation error");
920 }
921 }
922
923 // Create the text record parser
924 pkgRecords Recs(Cache);
925 if (_error->PendingError() == true)
926 {
927 for (unsigned I = 0; I != NumPatterns; I++)
928 regfree(&Patterns[I]);
929 return false;
930 }
931
932 ExVerFile *VFList = new ExVerFile[Cache.HeaderP->PackageCount+1];
933 memset(VFList,0,sizeof(*VFList)*Cache.HeaderP->PackageCount+1);
934
935 // Map versions that we want to write out onto the VerList array.
936 for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; P++)
937 {
938 for (unsigned I = 0; I != NumPatterns; I++)
939 {
940 if (regexec(&Patterns[I],P.Name(),0,0,0) == 0)
941 {
942 VFList[P->ID].NameMatch = true;
943 break;
944 }
945 }
946
947 // Doing names only, drop any that dont match..
948 if (NamesOnly == true && VFList[P->ID].NameMatch == false)
949 continue;
950
951 // Find the proper version to use.
952 pkgCache::VerIterator V = Plcy.GetCandidateVer(P);
953 if (V.end() == true)
954 continue;
955 VFList[P->ID].Vf = V.FileList();
956 }
957
958 LocalitySort(&VFList->Vf,Cache.HeaderP->PackageCount,sizeof(*VFList));
959
960 // Iterate over all the version records and check them
961 for (ExVerFile *J = VFList; J->Vf != 0; J++)
962 {
963 pkgRecords::Parser &P = Recs.Lookup(pkgCache::VerFileIterator(Cache,J->Vf));
964
965 bool Match = J->NameMatch;
966 string LongDesc = P.LongDesc();
967 for (unsigned I = 0; I != NumPatterns && Match == false; I++)
968 if (regexec(&Patterns[I],LongDesc.c_str(),0,0,0) == 0)
969 Match = true;
970
971 if (Match == true)
972 {
973 if (ShowFull == true)
974 {
975 const char *Start;
976 const char *End;
977 P.GetRec(Start,End);
978 fwrite(Start,End-Start,1,stdout);
979 putc('\n',stdout);
980 }
981 else
982 printf("%s - %s\n",P.Name().c_str(),P.ShortDesc().c_str());
983 }
984 }
985
986 delete [] VFList;
987 for (unsigned I = 0; I != NumPatterns; I++)
988 regfree(&Patterns[I]);
989 if (ferror(stdout))
990 return _error->Error("Write to stdout failed");
991 return true;
992 }
993 /*}}}*/
994 // ShowPackage - Dump the package record to the screen /*{{{*/
995 // ---------------------------------------------------------------------
996 /* */
997 bool ShowPackage(CommandLine &CmdL)
998 {
999 pkgCache &Cache = *GCache;
1000 pkgDepCache::Policy Plcy;
1001
1002 for (const char **I = CmdL.FileList + 1; *I != 0; I++)
1003 {
1004 pkgCache::PkgIterator Pkg = Cache.FindPkg(*I);
1005 if (Pkg.end() == true)
1006 {
1007 _error->Warning(_("Unable to locate package %s"),*I);
1008 continue;
1009 }
1010
1011 // Find the proper version to use.
1012 if (_config->FindB("APT::Cache::AllVersions","true") == true)
1013 {
1014 pkgCache::VerIterator V;
1015 for (V = Pkg.VersionList(); V.end() == false; V++)
1016 {
1017 if (DisplayRecord(V) == false)
1018 return false;
1019 }
1020 }
1021 else
1022 {
1023 pkgCache::VerIterator V = Plcy.GetCandidateVer(Pkg);
1024 if (V.end() == true || V.FileList().end() == true)
1025 continue;
1026 if (DisplayRecord(V) == false)
1027 return false;
1028 }
1029 }
1030 return true;
1031 }
1032 /*}}}*/
1033 // ShowPkgNames - Show package names /*{{{*/
1034 // ---------------------------------------------------------------------
1035 /* This does a prefix match on the first argument */
1036 bool ShowPkgNames(CommandLine &CmdL)
1037 {
1038 pkgCache &Cache = *GCache;
1039 pkgCache::PkgIterator I = Cache.PkgBegin();
1040 bool All = _config->FindB("APT::Cache::AllNames","false");
1041
1042 if (CmdL.FileList[1] != 0)
1043 {
1044 for (;I.end() != true; I++)
1045 {
1046 if (All == false && I->VersionList == 0)
1047 continue;
1048
1049 if (strncmp(I.Name(),CmdL.FileList[1],strlen(CmdL.FileList[1])) == 0)
1050 cout << I.Name() << endl;
1051 }
1052
1053 return true;
1054 }
1055
1056 // Show all pkgs
1057 for (;I.end() != true; I++)
1058 {
1059 if (All == false && I->VersionList == 0)
1060 continue;
1061 cout << I.Name() << endl;
1062 }
1063
1064 return true;
1065 }
1066 /*}}}*/
1067 // ShowSrcPackage - Show source package records /*{{{*/
1068 // ---------------------------------------------------------------------
1069 /* */
1070 bool ShowSrcPackage(CommandLine &CmdL)
1071 {
1072 pkgSourceList List;
1073 List.ReadMainList();
1074
1075 // Create the text record parsers
1076 pkgSrcRecords SrcRecs(List);
1077 if (_error->PendingError() == true)
1078 return false;
1079
1080 for (const char **I = CmdL.FileList + 1; *I != 0; I++)
1081 {
1082 SrcRecs.Restart();
1083
1084 pkgSrcRecords::Parser *Parse;
1085 while ((Parse = SrcRecs.Find(*I,false)) != 0)
1086 cout << Parse->AsStr() << endl;;
1087 }
1088 return true;
1089 }
1090 /*}}}*/
1091 // GenCaches - Call the main cache generator /*{{{*/
1092 // ---------------------------------------------------------------------
1093 /* */
1094 bool GenCaches(CommandLine &Cmd)
1095 {
1096 OpTextProgress Progress(*_config);
1097
1098 pkgSourceList List;
1099 if (List.ReadMainList() == false)
1100 return false;
1101 return pkgMakeStatusCache(List,Progress);
1102 }
1103 /*}}}*/
1104 // ShowHelp - Show a help screen /*{{{*/
1105 // ---------------------------------------------------------------------
1106 /* */
1107 bool ShowHelp(CommandLine &Cmd)
1108 {
1109 ioprintf(cout,_("%s %s for %s %s compiled on %s %s\n"),PACKAGE,VERSION,
1110 COMMON_OS,COMMON_CPU,__DATE__,__TIME__);
1111
1112 cout <<
1113 _("Usage: apt-cache [options] command\n"
1114 " apt-cache [options] add file1 [file1 ...]\n"
1115 " apt-cache [options] showpkg pkg1 [pkg2 ...]\n"
1116 "\n"
1117 "apt-cache is a low-level tool used to manipulate APT's binary\n"
1118 "cache files, and query information from them\n"
1119 "\n"
1120 "Commands:\n"
1121 " add - Add an package file to the source cache\n"
1122 " gencaches - Build both the package and source cache\n"
1123 " showpkg - Show some general information for a single package\n"
1124 " stats - Show some basic statistics\n"
1125 " dump - Show the entire file in a terse form\n"
1126 " dumpavail - Print an available file to stdout\n"
1127 " unmet - Show unmet dependencies\n"
1128 " check - Check the cache a bit\n"
1129 " search - Search the package list for a regex pattern\n"
1130 " show - Show a readable record for the package\n"
1131 " depends - Show raw dependency information for a package\n"
1132 " pkgnames - List the names of all packages\n"
1133 " dotty - Generate package graphs for GraphVis\n"
1134 "\n"
1135 "Options:\n"
1136 " -h This help text.\n"
1137 " -p=? The package cache.\n"
1138 " -s=? The source cache.\n"
1139 " -q Disable progress indicator.\n"
1140 " -i Show only important deps for the unmet command.\n"
1141 " -c=? Read this configuration file\n"
1142 " -o=? Set an arbitary configuration option, eg -o dir::cache=/tmp\n"
1143 "See the apt-cache(8) and apt.conf(5) manual pages for more information.\n");
1144 return true;
1145 }
1146 /*}}}*/
1147 // CacheInitialize - Initialize things for apt-cache /*{{{*/
1148 // ---------------------------------------------------------------------
1149 /* */
1150 void CacheInitialize()
1151 {
1152 _config->Set("quiet",0);
1153 _config->Set("help",false);
1154 }
1155 /*}}}*/
1156
1157 int main(int argc,const char *argv[])
1158 {
1159 CommandLine::Args Args[] = {
1160 {'h',"help","help",0},
1161 {'v',"version","version",0},
1162 {'p',"pkg-cache","Dir::Cache::pkgcache",CommandLine::HasArg},
1163 {'s',"src-cache","Dir::Cache::srcpkgcache",CommandLine::HasArg},
1164 {'q',"quiet","quiet",CommandLine::IntLevel},
1165 {'i',"important","APT::Cache::Important",0},
1166 {'f',"full","APT::Cache::ShowFull",0},
1167 {'g',"generate","APT::Cache::Generate",0},
1168 {'a',"all-versions","APT::Cache::AllVersions",0},
1169 {0,"names-only","APT::Cache::NamesOnly",0},
1170 {0,"all-names","APT::Cache::AllNames",0},
1171 {0,"recurse","APT::Cache::RecurseDepends",0},
1172 {'c',"config-file",0,CommandLine::ConfigFile},
1173 {'o',"option",0,CommandLine::ArbItem},
1174 {0,0,0,0}};
1175 CommandLine::Dispatch CmdsA[] = {{"help",&ShowHelp},
1176 {"add",&DoAdd},
1177 {"gencaches",&GenCaches},
1178 {"showsrc",&ShowSrcPackage},
1179 {0,0}};
1180 CommandLine::Dispatch CmdsB[] = {{"showpkg",&DumpPackage},
1181 {"stats",&Stats},
1182 {"dump",&Dump},
1183 {"dumpavail",&DumpAvail},
1184 {"unmet",&UnMet},
1185 {"search",&Search},
1186 {"depends",&Depends},
1187 {"dotty",&Dotty},
1188 {"show",&ShowPackage},
1189 {"pkgnames",&ShowPkgNames},
1190 {0,0}};
1191
1192 CacheInitialize();
1193
1194 // Parse the command line and initialize the package library
1195 CommandLine CmdL(Args,_config);
1196 if (pkgInitConfig(*_config) == false ||
1197 CmdL.Parse(argc,argv) == false ||
1198 pkgInitSystem(*_config,_system) == false)
1199 {
1200 _error->DumpErrors();
1201 return 100;
1202 }
1203
1204 // See if the help should be shown
1205 if (_config->FindB("help") == true ||
1206 CmdL.FileSize() == 0)
1207 {
1208 ShowHelp(CmdL);
1209 return 0;
1210 }
1211
1212 // Deal with stdout not being a tty
1213 if (ttyname(STDOUT_FILENO) == 0 && _config->FindI("quiet",0) < 1)
1214 _config->Set("quiet","1");
1215
1216 if (CmdL.DispatchArg(CmdsA,false) == false && _error->PendingError() == false)
1217 {
1218 MMap *Map;
1219 if (_config->FindB("APT::Cache::Generate",true) == false)
1220 {
1221 Map = new MMap(*new FileFd(_config->FindFile("Dir::Cache::pkgcache"),
1222 FileFd::ReadOnly),MMap::Public|MMap::ReadOnly);
1223 }
1224 else
1225 {
1226 // Open the cache file
1227 pkgSourceList List;
1228 List.ReadMainList();
1229
1230 // Generate it and map it
1231 OpProgress Prog;
1232 pkgMakeStatusCache(List,Prog,&Map,true);
1233 }
1234
1235 if (_error->PendingError() == false)
1236 {
1237 pkgCache Cache(Map);
1238 GCache = &Cache;
1239 if (_error->PendingError() == false)
1240 CmdL.DispatchArg(CmdsB);
1241 }
1242 delete Map;
1243 }
1244
1245 // Print any errors or warnings found during parsing
1246 if (_error->empty() == false)
1247 {
1248 bool Errors = _error->PendingError();
1249 _error->DumpErrors();
1250 return Errors == true?100:0;
1251 }
1252
1253 return 0;
1254 }