]> git.saurik.com Git - apt.git/blob - cmdline/apt-cache.cc
Made autoclean respect 'q' settings. Closes: #63023
[apt.git] / cmdline / apt-cache.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 // $Id: apt-cache.cc,v 1.43 2000/05/12 04:00:59 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. The
10 only really usefull function right now is dumpavail which is used
11 by the dselect method. Everything else is meant as a debug aide.
12
13 Returns 100 on failure, 0 on success.
14
15 ##################################################################### */
16 /*}}}*/
17 // Include Files /*{{{*/
18 #include <apt-pkg/error.h>
19 #include <apt-pkg/pkgcachegen.h>
20 #include <apt-pkg/deblistparser.h>
21 #include <apt-pkg/init.h>
22 #include <apt-pkg/progress.h>
23 #include <apt-pkg/sourcelist.h>
24 #include <apt-pkg/cmndline.h>
25 #include <apt-pkg/strutl.h>
26 #include <apt-pkg/pkgrecords.h>
27 #include <apt-pkg/srcrecords.h>
28 #include <apt-pkg/version.h>
29 #include <config.h>
30
31 #include <iostream.h>
32 #include <unistd.h>
33 #include <errno.h>
34 #include <regex.h>
35 #include <stdio.h>
36 /*}}}*/
37
38 pkgCache *GCache = 0;
39
40 // UnMet - Show unmet dependencies /*{{{*/
41 // ---------------------------------------------------------------------
42 /* */
43 bool UnMet(CommandLine &CmdL)
44 {
45 pkgCache &Cache = *GCache;
46 bool Important = _config->FindB("APT::Cache::Important",false);
47
48 for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; P++)
49 {
50 for (pkgCache::VerIterator V = P.VersionList(); V.end() == false; V++)
51 {
52 bool Header = false;
53 for (pkgCache::DepIterator D = V.DependsList(); D.end() == false;)
54 {
55 // Collect or groups
56 pkgCache::DepIterator Start;
57 pkgCache::DepIterator End;
58 D.GlobOr(Start,End);
59
60 /* cout << "s: Check " << Start.TargetPkg().Name() << ',' <<
61 End.TargetPkg().Name() << endl;*/
62
63 // Skip conflicts and replaces
64 if (End->Type != pkgCache::Dep::PreDepends &&
65 End->Type != pkgCache::Dep::Depends &&
66 End->Type != pkgCache::Dep::Suggests &&
67 End->Type != pkgCache::Dep::Recommends)
68 continue;
69
70 // Important deps only
71 if (Important == true)
72 if (End->Type != pkgCache::Dep::PreDepends &&
73 End->Type != pkgCache::Dep::Depends)
74 continue;
75
76 // Verify the or group
77 bool OK = false;
78 pkgCache::DepIterator RealStart = Start;
79 do
80 {
81 // See if this dep is Ok
82 pkgCache::Version **VList = Start.AllTargets();
83 if (*VList != 0)
84 {
85 OK = true;
86 delete [] VList;
87 break;
88 }
89 delete [] VList;
90
91 if (Start == End)
92 break;
93 Start++;
94 }
95 while (1);
96
97 // The group is OK
98 if (OK == true)
99 continue;
100
101 // Oops, it failed..
102 if (Header == false)
103 cout << "Package " << P.Name() << " version " <<
104 V.VerStr() << " has an unmet dep:" << endl;
105 Header = true;
106
107 // Print out the dep type
108 cout << " " << End.DepType() << ": ";
109
110 // Show the group
111 Start = RealStart;
112 do
113 {
114 cout << Start.TargetPkg().Name();
115 if (Start.TargetVer() != 0)
116 cout << " (" << Start.CompType() << " " << Start.TargetVer() <<
117 ")";
118 if (Start == End)
119 break;
120 cout << " | ";
121 Start++;
122 }
123 while (1);
124
125 cout << endl;
126 }
127 }
128 }
129 return true;
130 }
131 /*}}}*/
132 // DumpPackage - Show a dump of a package record /*{{{*/
133 // ---------------------------------------------------------------------
134 /* */
135 bool DumpPackage(CommandLine &CmdL)
136 {
137 pkgCache &Cache = *GCache;
138 for (const char **I = CmdL.FileList + 1; *I != 0; I++)
139 {
140 pkgCache::PkgIterator Pkg = Cache.FindPkg(*I);
141 if (Pkg.end() == true)
142 {
143 _error->Warning("Unable to locate package %s",*I);
144 continue;
145 }
146
147 cout << "Package: " << Pkg.Name() << endl;
148 cout << "Versions: ";
149 for (pkgCache::VerIterator Cur = Pkg.VersionList(); Cur.end() != true; Cur++)
150 {
151 cout << Cur.VerStr();
152 for (pkgCache::VerFileIterator Vf = Cur.FileList(); Vf.end() == false; Vf++)
153 cout << "(" << Vf.File().FileName() << ")";
154 cout << ',';
155 }
156
157 cout << endl;
158
159 cout << "Reverse Depends: " << endl;
160 for (pkgCache::DepIterator D = Pkg.RevDependsList(); D.end() != true; D++)
161 cout << " " << D.ParentPkg().Name() << ',' << D.TargetPkg().Name() << endl;
162
163 cout << "Dependencies: " << endl;
164 for (pkgCache::VerIterator Cur = Pkg.VersionList(); Cur.end() != true; Cur++)
165 {
166 cout << Cur.VerStr() << " - ";
167 for (pkgCache::DepIterator Dep = Cur.DependsList(); Dep.end() != true; Dep++)
168 cout << Dep.TargetPkg().Name() << " (" << (int)Dep->CompareOp << " " << Dep.TargetVer() << ") ";
169 cout << endl;
170 }
171
172 cout << "Provides: " << endl;
173 for (pkgCache::VerIterator Cur = Pkg.VersionList(); Cur.end() != true; Cur++)
174 {
175 cout << Cur.VerStr() << " - ";
176 for (pkgCache::PrvIterator Prv = Cur.ProvidesList(); Prv.end() != true; Prv++)
177 cout << Prv.ParentPkg().Name() << " ";
178 cout << endl;
179 }
180 cout << "Reverse Provides: " << endl;
181 for (pkgCache::PrvIterator Prv = Pkg.ProvidesList(); Prv.end() != true; Prv++)
182 cout << Prv.OwnerPkg().Name() << " " << Prv.OwnerVer().VerStr() << endl;
183 }
184
185 return true;
186 }
187 /*}}}*/
188 // Stats - Dump some nice statistics /*{{{*/
189 // ---------------------------------------------------------------------
190 /* */
191 bool Stats(CommandLine &Cmd)
192 {
193 pkgCache &Cache = *GCache;
194 cout << "Total Package Names : " << Cache.Head().PackageCount << " (" <<
195 SizeToStr(Cache.Head().PackageCount*Cache.Head().PackageSz) << ')' << endl;
196 pkgCache::PkgIterator I = Cache.PkgBegin();
197
198 int Normal = 0;
199 int Virtual = 0;
200 int NVirt = 0;
201 int DVirt = 0;
202 int Missing = 0;
203 for (;I.end() != true; I++)
204 {
205 if (I->VersionList != 0 && I->ProvidesList == 0)
206 {
207 Normal++;
208 continue;
209 }
210
211 if (I->VersionList != 0 && I->ProvidesList != 0)
212 {
213 NVirt++;
214 continue;
215 }
216
217 if (I->VersionList == 0 && I->ProvidesList != 0)
218 {
219 // Only 1 provides
220 if (I.ProvidesList()->NextProvides == 0)
221 {
222 DVirt++;
223 }
224 else
225 Virtual++;
226 continue;
227 }
228 if (I->VersionList == 0 && I->ProvidesList == 0)
229 {
230 Missing++;
231 continue;
232 }
233 }
234 cout << " Normal Packages: " << Normal << endl;
235 cout << " Pure Virtual Packages: " << Virtual << endl;
236 cout << " Single Virtual Packages: " << DVirt << endl;
237 cout << " Mixed Virtual Packages: " << NVirt << endl;
238 cout << " Missing: " << Missing << endl;
239
240 cout << "Total Distinct Versions: " << Cache.Head().VersionCount << " (" <<
241 SizeToStr(Cache.Head().VersionCount*Cache.Head().VersionSz) << ')' << endl;
242 cout << "Total Dependencies: " << Cache.Head().DependsCount << " (" <<
243 SizeToStr(Cache.Head().DependsCount*Cache.Head().DependencySz) << ')' << endl;
244
245 cout << "Total Ver/File relations: " << Cache.Head().VerFileCount << " (" <<
246 SizeToStr(Cache.Head().VerFileCount*Cache.Head().VerFileSz) << ')' << endl;
247 cout << "Total Provides Mappings: " << Cache.Head().ProvidesCount << " (" <<
248 SizeToStr(Cache.Head().ProvidesCount*Cache.Head().ProvidesSz) << ')' << endl;
249
250 // String list stats
251 unsigned long Size = 0;
252 unsigned long Count = 0;
253 for (pkgCache::StringItem *I = Cache.StringItemP + Cache.Head().StringList;
254 I!= Cache.StringItemP; I = Cache.StringItemP + I->NextItem)
255 {
256 Count++;
257 Size += strlen(Cache.StrP + I->String);
258 }
259 cout << "Total Globbed Strings: " << Count << " (" << SizeToStr(Size) << ')' << endl;
260
261 unsigned long Slack = 0;
262 for (int I = 0; I != 7; I++)
263 Slack += Cache.Head().Pools[I].ItemSize*Cache.Head().Pools[I].Count;
264 cout << "Total Slack space: " << SizeToStr(Slack) << endl;
265
266 unsigned long Total = 0;
267 Total = Slack + Size + Cache.Head().DependsCount*Cache.Head().DependencySz +
268 Cache.Head().VersionCount*Cache.Head().VersionSz +
269 Cache.Head().PackageCount*Cache.Head().PackageSz +
270 Cache.Head().VerFileCount*Cache.Head().VerFileSz +
271 Cache.Head().ProvidesCount*Cache.Head().ProvidesSz;
272 cout << "Total Space Accounted for: " << SizeToStr(Total) << endl;
273
274 return true;
275 }
276 /*}}}*/
277 // Check - Check some things about the cache /*{{{*/
278 // ---------------------------------------------------------------------
279 /* Debug aide mostly */
280 bool Check(CommandLine &Cmd)
281 {
282 pkgCache &Cache = *GCache;
283 pkgCache::PkgIterator Pkg = Cache.PkgBegin();
284 for (;Pkg.end() != true; Pkg++)
285 {
286 if (Pkg.Section() == 0 && Pkg->VersionList != 0)
287 cout << "Bad section " << Pkg.Name() << endl;
288
289 for (pkgCache::VerIterator Cur = Pkg.VersionList();
290 Cur.end() != true; Cur++)
291 {
292 if (Cur->Priority < 1 || Cur->Priority > 5)
293 cout << "Bad prio " << Pkg.Name() << ',' << Cur.VerStr() << " == " << (int)Cur->Priority << endl;
294 }
295 }
296 return true;
297 }
298 /*}}}*/
299 // Dump - show everything /*{{{*/
300 // ---------------------------------------------------------------------
301 /* */
302 bool Dump(CommandLine &Cmd)
303 {
304 pkgCache &Cache = *GCache;
305 for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; P++)
306 {
307 cout << "Package: " << P.Name() << endl;
308 for (pkgCache::VerIterator V = P.VersionList(); V.end() == false; V++)
309 {
310 cout << " Version: " << V.VerStr() << endl;
311 cout << " File: " << V.FileList().File().FileName() << endl;
312 for (pkgCache::DepIterator D = V.DependsList(); D.end() == false; D++)
313 cout << " Depends: " << D.TargetPkg().Name() << ' ' << D.TargetVer() << endl;
314 }
315 }
316
317 for (pkgCache::PkgFileIterator F(Cache); F.end() == false; F++)
318 {
319 cout << "File: " << F.FileName() << endl;
320 cout << " Size: " << F->Size << endl;
321 cout << " ID: " << F->ID << endl;
322 cout << " Flags: " << F->Flags << endl;
323 cout << " Time: " << TimeRFC1123(F->mtime) << endl;
324 cout << " Archive: " << F.Archive() << endl;
325 cout << " Component: " << F.Component() << endl;
326 cout << " Version: " << F.Version() << endl;
327 cout << " Origin: " << F.Origin() << endl;
328 cout << " Label: " << F.Label() << endl;
329 cout << " Architecture: " << F.Architecture() << endl;
330 }
331
332 return true;
333 }
334 /*}}}*/
335 // DumpAvail - Print out the available list /*{{{*/
336 // ---------------------------------------------------------------------
337 /* This is needed to make dpkg --merge happy */
338 bool DumpAvail(CommandLine &Cmd)
339 {
340 pkgCache &Cache = *GCache;
341 unsigned char *Buffer = new unsigned char[Cache.HeaderP->MaxVerFileSize];
342
343 for (pkgCache::PkgFileIterator I = Cache.FileBegin(); I.end() == false; I++)
344 {
345 if ((I->Flags & pkgCache::Flag::NotSource) != 0)
346 continue;
347
348 if (I.IsOk() == false)
349 {
350 delete [] Buffer;
351 return _error->Error("Package file %s is out of sync.",I.FileName());
352 }
353
354 FileFd PkgF(I.FileName(),FileFd::ReadOnly);
355 if (_error->PendingError() == true)
356 {
357 delete [] Buffer;
358 return false;
359 }
360
361 /* Write all of the records from this package file, we search the entire
362 structure to find them */
363 for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; P++)
364 {
365 // Find the proper version to use. We should probably use the DepCache.
366 pkgCache::VerIterator V = Cache.GetCandidateVer(P,false);
367
368 if (V.end() == true || V.FileList().File() != I)
369 continue;
370
371 // Read the record and then write it out again.
372 if (PkgF.Seek(V.FileList()->Offset) == false ||
373 PkgF.Read(Buffer,V.FileList()->Size) == false ||
374 write(STDOUT_FILENO,Buffer,V.FileList()->Size) != V.FileList()->Size)
375 {
376 delete [] Buffer;
377 return false;
378 }
379 }
380 }
381
382 return true;
383 }
384 /*}}}*/
385 // Depends - Print out a dependency tree /*{{{*/
386 // ---------------------------------------------------------------------
387 /* */
388 bool Depends(CommandLine &CmdL)
389 {
390 pkgCache &Cache = *GCache;
391
392 for (const char **I = CmdL.FileList + 1; *I != 0; I++)
393 {
394 pkgCache::PkgIterator Pkg = Cache.FindPkg(*I);
395 if (Pkg.end() == true)
396 {
397 _error->Warning("Unable to locate package %s",*I);
398 continue;
399 }
400
401 pkgCache::VerIterator Ver = Pkg.VersionList();
402 if (Ver.end() == true)
403 {
404 cout << '<' << Pkg.Name() << '>' << endl;
405 continue;
406 }
407
408 cout << Pkg.Name() << endl;
409
410 for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false; D++)
411 {
412 if ((D->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or)
413 cout << " |";
414 else
415 cout << " ";
416
417 // Show the package
418 pkgCache::PkgIterator Trg = D.TargetPkg();
419 if (Trg->VersionList == 0)
420 cout << D.DepType() << ": <" << Trg.Name() << ">" << endl;
421 else
422 cout << D.DepType() << ": " << Trg.Name() << endl;
423
424 // Display all solutions
425 pkgCache::Version **List = D.AllTargets();
426 for (pkgCache::Version **I = List; *I != 0; I++)
427 {
428 pkgCache::VerIterator V(Cache,*I);
429 if (V != Cache.VerP + V.ParentPkg()->VersionList ||
430 V->ParentPkg == D->Package)
431 continue;
432 cout << " " << V.ParentPkg().Name() << endl;
433 }
434 delete [] List;
435 }
436 }
437
438 return true;
439 }
440 /*}}}*/
441 // Dotty - Generate a graph for Dotty /*{{{*/
442 // ---------------------------------------------------------------------
443 /* Dotty is the graphvis program for generating graphs. It is a fairly
444 simple queuing algorithm that just writes dependencies and nodes.
445 http://www.research.att.com/sw/tools/graphviz/ */
446 bool Dotty(CommandLine &CmdL)
447 {
448 pkgCache &Cache = *GCache;
449 bool GivenOnly = _config->FindB("APT::Cache::GivenOnly",false);
450
451 /* Normal packages are boxes
452 Pure Provides are triangles
453 Mixed are diamonds
454 Hexagons are missing packages*/
455 const char *Shapes[] = {"hexagon","triangle","box","diamond"};
456
457 /* Initialize the list of packages to show.
458 1 = To Show
459 2 = To Show no recurse
460 3 = Emitted no recurse
461 4 = Emitted
462 0 = None */
463 enum States {None=0, ToShow, ToShowNR, DoneNR, Done};
464 enum TheFlags {ForceNR=(1<<0)};
465 unsigned char *Show = new unsigned char[Cache.Head().PackageCount];
466 unsigned char *Flags = new unsigned char[Cache.Head().PackageCount];
467 unsigned char *ShapeMap = new unsigned char[Cache.Head().PackageCount];
468
469 // Show everything if no arguments given
470 if (CmdL.FileList[1] == 0)
471 for (unsigned long I = 0; I != Cache.Head().PackageCount; I++)
472 Show[I] = ToShow;
473 else
474 for (unsigned long I = 0; I != Cache.Head().PackageCount; I++)
475 Show[I] = None;
476 memset(Flags,0,sizeof(*Flags)*Cache.Head().PackageCount);
477
478 // Map the shapes
479 for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; Pkg++)
480 {
481 if (Pkg->VersionList == 0)
482 {
483 // Missing
484 if (Pkg->ProvidesList == 0)
485 ShapeMap[Pkg->ID] = 0;
486 else
487 ShapeMap[Pkg->ID] = 1;
488 }
489 else
490 {
491 // Normal
492 if (Pkg->ProvidesList == 0)
493 ShapeMap[Pkg->ID] = 2;
494 else
495 ShapeMap[Pkg->ID] = 3;
496 }
497 }
498
499 // Load the list of packages from the command line into the show list
500 for (const char **I = CmdL.FileList + 1; *I != 0; I++)
501 {
502 // Process per-package flags
503 string P = *I;
504 bool Force = false;
505 if (P.length() > 3)
506 {
507 if (P.end()[-1] == '^')
508 {
509 Force = true;
510 P.erase(P.end()-1);
511 }
512
513 if (P.end()[-1] == ',')
514 P.erase(P.end()-1);
515 }
516
517 // Locate the package
518 pkgCache::PkgIterator Pkg = Cache.FindPkg(P);
519 if (Pkg.end() == true)
520 {
521 _error->Warning("Unable to locate package %s",*I);
522 continue;
523 }
524 Show[Pkg->ID] = ToShow;
525
526 if (Force == true)
527 Flags[Pkg->ID] |= ForceNR;
528 }
529
530 // Little header
531 printf("digraph packages {\n");
532 printf("concentrate=true;\n");
533 printf("size=\"30,40\";\n");
534
535 bool Act = true;
536 while (Act == true)
537 {
538 Act = false;
539 for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; Pkg++)
540 {
541 // See we need to show this package
542 if (Show[Pkg->ID] == None || Show[Pkg->ID] >= DoneNR)
543 continue;
544
545 // Colour as done
546 if (Show[Pkg->ID] == ToShowNR || (Flags[Pkg->ID] & ForceNR) == ForceNR)
547 {
548 // Pure Provides and missing packages have no deps!
549 if (ShapeMap[Pkg->ID] == 0 || ShapeMap[Pkg->ID] == 1)
550 Show[Pkg->ID] = Done;
551 else
552 Show[Pkg->ID] = DoneNR;
553 }
554 else
555 Show[Pkg->ID] = Done;
556 Act = true;
557
558 // No deps to map out
559 if (Pkg->VersionList == 0 || Show[Pkg->ID] == DoneNR)
560 continue;
561
562 pkgCache::VerIterator Ver = Pkg.VersionList();
563 for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false; D++)
564 {
565 // See if anything can meet this dep
566 // Walk along the actual package providing versions
567 bool Hit = false;
568 pkgCache::PkgIterator DPkg = D.TargetPkg();
569 for (pkgCache::VerIterator I = DPkg.VersionList();
570 I.end() == false && Hit == false; I++)
571 {
572 if (pkgCheckDep(D.TargetVer(),I.VerStr(),D->CompareOp) == true)
573 Hit = true;
574 }
575
576 // Follow all provides
577 for (pkgCache::PrvIterator I = DPkg.ProvidesList();
578 I.end() == false && Hit == false; I++)
579 {
580 if (pkgCheckDep(D.TargetVer(),I.ProvideVersion(),D->CompareOp) == false)
581 Hit = true;
582 }
583
584 // Only graph critical deps
585 if (D.IsCritical() == true)
586 {
587 printf("\"%s\" -> \"%s\"",Pkg.Name(),D.TargetPkg().Name());
588
589 // Colour the node for recursion
590 if (Show[D.TargetPkg()->ID] <= DoneNR)
591 {
592 /* If a conflicts does not meet anything in the database
593 then show the relation but do not recurse */
594 if (Hit == false && D->Type == pkgCache::Dep::Conflicts)
595 {
596 if (Show[D.TargetPkg()->ID] == None &&
597 Show[D.TargetPkg()->ID] != ToShow)
598 Show[D.TargetPkg()->ID] = ToShowNR;
599 }
600 else
601 {
602 if (GivenOnly == true && Show[D.TargetPkg()->ID] != ToShow)
603 Show[D.TargetPkg()->ID] = ToShowNR;
604 else
605 Show[D.TargetPkg()->ID] = ToShow;
606 }
607 }
608
609 // Edge colour
610 switch(D->Type)
611 {
612 case pkgCache::Dep::Conflicts:
613 printf("[color=springgreen];\n");
614 break;
615
616 case pkgCache::Dep::PreDepends:
617 printf("[color=blue];\n");
618 break;
619
620 default:
621 printf(";\n");
622 break;
623 }
624 }
625 }
626 }
627 }
628
629 /* Draw the box colours after the fact since we can not tell what colour
630 they should be until everything is finished drawing */
631 for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; Pkg++)
632 {
633 if (Show[Pkg->ID] < DoneNR)
634 continue;
635
636 // Orange box for early recursion stoppage
637 if (Show[Pkg->ID] == DoneNR)
638 printf("\"%s\" [color=orange,shape=%s];\n",Pkg.Name(),
639 Shapes[ShapeMap[Pkg->ID]]);
640 else
641 printf("\"%s\" [shape=%s];\n",Pkg.Name(),
642 Shapes[ShapeMap[Pkg->ID]]);
643 }
644
645 printf("}\n");
646 return true;
647 }
648 /*}}}*/
649 // DoAdd - Perform an adding operation /*{{{*/
650 // ---------------------------------------------------------------------
651 /* */
652 bool DoAdd(CommandLine &CmdL)
653 {
654 // Make sure there is at least one argument
655 if (CmdL.FileSize() <= 1)
656 return _error->Error("You must give at least one file name");
657
658 // Open the cache
659 FileFd CacheF(_config->FindFile("Dir::Cache::pkgcache"),FileFd::WriteAny);
660 if (_error->PendingError() == true)
661 return false;
662
663 DynamicMMap Map(CacheF,MMap::Public);
664 if (_error->PendingError() == true)
665 return false;
666
667 OpTextProgress Progress(*_config);
668 pkgCacheGenerator Gen(Map,Progress);
669 if (_error->PendingError() == true)
670 return false;
671
672 unsigned long Length = CmdL.FileSize() - 1;
673 for (const char **I = CmdL.FileList + 1; *I != 0; I++)
674 {
675 Progress.OverallProgress(I - CmdL.FileList,Length,1,"Generating cache");
676 Progress.SubProgress(Length);
677
678 // Do the merge
679 FileFd TagF(*I,FileFd::ReadOnly);
680 debListParser Parser(TagF);
681 if (_error->PendingError() == true)
682 return _error->Error("Problem opening %s",*I);
683
684 if (Gen.SelectFile(*I) == false)
685 return _error->Error("Problem with SelectFile");
686
687 if (Gen.MergeList(Parser) == false)
688 return _error->Error("Problem with MergeList");
689 }
690
691 Progress.Done();
692 GCache = &Gen.GetCache();
693 Stats(CmdL);
694
695 return true;
696 }
697 /*}}}*/
698 // DisplayRecord - Displays the complete record for the package /*{{{*/
699 // ---------------------------------------------------------------------
700 /* This displays the package record from the proper package index file.
701 It is not used by DumpAvail for performance reasons. */
702 bool DisplayRecord(pkgCache::VerIterator V)
703 {
704 // Find an appropriate file
705 pkgCache::VerFileIterator Vf = V.FileList();
706 for (; Vf.end() == false; Vf++)
707 if ((Vf.File()->Flags & pkgCache::Flag::NotSource) == 0)
708 break;
709 if (Vf.end() == true)
710 Vf = V.FileList();
711
712 // Check and load the package list file
713 pkgCache::PkgFileIterator I = Vf.File();
714 if (I.IsOk() == false)
715 return _error->Error("Package file %s is out of sync.",I.FileName());
716
717 FileFd PkgF(I.FileName(),FileFd::ReadOnly);
718 if (_error->PendingError() == true)
719 return false;
720
721 // Read the record and then write it out again.
722 unsigned char *Buffer = new unsigned char[GCache->HeaderP->MaxVerFileSize];
723 if (PkgF.Seek(V.FileList()->Offset) == false ||
724 PkgF.Read(Buffer,V.FileList()->Size) == false ||
725 write(STDOUT_FILENO,Buffer,V.FileList()->Size) != V.FileList()->Size)
726 {
727 delete [] Buffer;
728 return false;
729 }
730
731 delete [] Buffer;
732
733 return true;
734 }
735 /*}}}*/
736 // Search - Perform a search /*{{{*/
737 // ---------------------------------------------------------------------
738 /* This searches the package names and pacakge descriptions for a pattern */
739 bool Search(CommandLine &CmdL)
740 {
741 pkgCache &Cache = *GCache;
742 bool ShowFull = _config->FindB("APT::Cache::ShowFull",false);
743 bool NamesOnly = _config->FindB("APT::Cache::NamesOnly",false);
744
745 // Make sure there is at least one argument
746 if (CmdL.FileSize() != 2)
747 return _error->Error("You must give exactly one pattern");
748
749 // Compile the regex pattern
750 regex_t Pattern;
751 if (regcomp(&Pattern,CmdL.FileList[1],REG_EXTENDED | REG_ICASE |
752 REG_NOSUB) != 0)
753 return _error->Error("Regex compilation error");
754
755 // Create the text record parser
756 pkgRecords Recs(Cache);
757 if (_error->PendingError() == true)
758 return false;
759
760 // Search package names
761 pkgCache::PkgIterator I = Cache.PkgBegin();
762 for (;I.end() != true; I++)
763 {
764 // We search against the install version as that makes the most sense..
765 pkgCache::VerIterator V = Cache.GetCandidateVer(I);
766 if (V.end() == true)
767 continue;
768
769 pkgRecords::Parser &P = Recs.Lookup(V.FileList());
770
771 if (regexec(&Pattern,I.Name(),0,0,0) == 0 ||
772 (NamesOnly == false &&
773 regexec(&Pattern,P.LongDesc().c_str(),0,0,0) == 0))
774 {
775 if (ShowFull == true)
776 DisplayRecord(V);
777 else
778 cout << I.Name() << " - " << P.ShortDesc() << endl;
779 }
780 }
781
782 regfree(&Pattern);
783 return true;
784 }
785 /*}}}*/
786 // ShowPackage - Dump the package record to the screen /*{{{*/
787 // ---------------------------------------------------------------------
788 /* */
789 bool ShowPackage(CommandLine &CmdL)
790 {
791 pkgCache &Cache = *GCache;
792 for (const char **I = CmdL.FileList + 1; *I != 0; I++)
793 {
794 pkgCache::PkgIterator Pkg = Cache.FindPkg(*I);
795 if (Pkg.end() == true)
796 {
797 _error->Warning("Unable to locate package %s",*I);
798 continue;
799 }
800
801 // Find the proper version to use. We should probably use the DepCache.
802 if (_config->FindB("APT::Cache::AllVersions","true") == true)
803 {
804 pkgCache::VerIterator V;
805 for (V = Pkg.VersionList(); V.end() == false; V++)
806 {
807 if (DisplayRecord(V) == false)
808 return false;
809 }
810 }
811 else
812 {
813 pkgCache::VerIterator V = Cache.GetCandidateVer(Pkg);
814 if (V.end() == true || V.FileList().end() == true)
815 continue;
816 if (DisplayRecord(V) == false)
817 return false;
818 }
819 }
820 return true;
821 }
822 /*}}}*/
823 // ShowPkgNames - Show package names /*{{{*/
824 // ---------------------------------------------------------------------
825 /* This does a prefix match on the first argument */
826 bool ShowPkgNames(CommandLine &CmdL)
827 {
828 pkgCache &Cache = *GCache;
829 pkgCache::PkgIterator I = Cache.PkgBegin();
830 bool All = _config->FindB("APT::Cache::AllNames","false");
831
832 if (CmdL.FileList[1] != 0)
833 {
834 for (;I.end() != true; I++)
835 {
836 if (All == false && I->VersionList == 0)
837 continue;
838
839 if (strncmp(I.Name(),CmdL.FileList[1],strlen(CmdL.FileList[1])) == 0)
840 cout << I.Name() << endl;
841 }
842
843 return true;
844 }
845
846 // Show all pkgs
847 for (;I.end() != true; I++)
848 {
849 if (All == false && I->VersionList == 0)
850 continue;
851 cout << I.Name() << endl;
852 }
853
854 return true;
855 }
856 /*}}}*/
857 // ShowSrcPackage - Show source package records /*{{{*/
858 // ---------------------------------------------------------------------
859 /* */
860 bool ShowSrcPackage(CommandLine &CmdL)
861 {
862 pkgSourceList List;
863 List.ReadMainList();
864
865 // Create the text record parsers
866 pkgSrcRecords SrcRecs(List);
867 if (_error->PendingError() == true)
868 return false;
869
870 for (const char **I = CmdL.FileList + 1; *I != 0; I++)
871 {
872 SrcRecs.Restart();
873
874 pkgSrcRecords::Parser *Parse;
875 while ((Parse = SrcRecs.Find(*I,false)) != 0)
876 cout << Parse->AsStr();
877 }
878 return true;
879 }
880 /*}}}*/
881 // GenCaches - Call the main cache generator /*{{{*/
882 // ---------------------------------------------------------------------
883 /* */
884 bool GenCaches(CommandLine &Cmd)
885 {
886 OpTextProgress Progress(*_config);
887
888 pkgSourceList List;
889 List.ReadMainList();
890 return pkgMakeStatusCache(List,Progress);
891 }
892 /*}}}*/
893 // ShowHelp - Show a help screen /*{{{*/
894 // ---------------------------------------------------------------------
895 /* */
896 bool ShowHelp(CommandLine &Cmd)
897 {
898 cout << PACKAGE << ' ' << VERSION << " for " << ARCHITECTURE <<
899 " compiled on " << __DATE__ << " " << __TIME__ << endl;
900 if (_config->FindB("version") == true)
901 return 100;
902
903 cout << "Usage: apt-cache [options] command" << endl;
904 cout << " apt-cache [options] add file1 [file1 ...]" << endl;
905 cout << " apt-cache [options] showpkg pkg1 [pkg2 ...]" << endl;
906 cout << endl;
907 cout << "apt-cache is a low-level tool used to manipulate APT's binary" << endl;
908 cout << "cache files stored in " << _config->FindFile("Dir::Cache") << endl;
909 cout << "It is not meant for ordinary use only as a debug aide." << endl;
910 cout << endl;
911 cout << "Commands:" << endl;
912 cout << " add - Add an package file to the source cache" << endl;
913 cout << " gencaches - Build both the package and source cache" << endl;
914 cout << " showpkg - Show some general information for a single package" << endl;
915 cout << " stats - Show some basic statistics" << endl;
916 cout << " dump - Show the entire file in a terse form" << endl;
917 cout << " dumpavail - Print an available file to stdout" << endl;
918 cout << " unmet - Show unmet dependencies" << endl;
919 cout << " check - Check the cache a bit" << endl;
920 cout << " search - Search the package list for a regex pattern" << endl;
921 cout << " show - Show a readable record for the package" << endl;
922 cout << " depends - Show raw dependency information for a package" << endl;
923 cout << " pkgnames - List the names of all packages" << endl;
924 cout << " dotty - Generate package graphs for GraphVis" << endl;
925 cout << endl;
926 cout << "Options:" << endl;
927 cout << " -h This help text." << endl;
928 cout << " -p=? The package cache. [" << _config->FindFile("Dir::Cache::pkgcache") << ']' << endl;
929 cout << " -s=? The source cache. [" << _config->FindFile("Dir::Cache::srcpkgcache") << ']' << endl;
930 cout << " -q Disable progress indicator." << endl;
931 cout << " -i Show only important deps for the unmet command." << endl;
932 cout << " -c=? Read this configuration file" << endl;
933 cout << " -o=? Set an arbitary configuration option, eg -o dir::cache=/tmp" << endl;
934 cout << "See the apt-cache(8) and apt.conf(5) manual pages for more information." << endl;
935 return 100;
936 }
937 /*}}}*/
938 // CacheInitialize - Initialize things for apt-cache /*{{{*/
939 // ---------------------------------------------------------------------
940 /* */
941 void CacheInitialize()
942 {
943 _config->Set("quiet",0);
944 _config->Set("help",false);
945 }
946 /*}}}*/
947
948 int main(int argc,const char *argv[])
949 {
950 CommandLine::Args Args[] = {
951 {'h',"help","help",0},
952 {'v',"version","version",0},
953 {'p',"pkg-cache","Dir::Cache::pkgcache",CommandLine::HasArg},
954 {'s',"src-cache","Dir::Cache::srcpkgcache",CommandLine::HasArg},
955 {'q',"quiet","quiet",CommandLine::IntLevel},
956 {'i',"important","APT::Cache::Important",0},
957 {'f',"full","APT::Cache::ShowFull",0},
958 {'g',"no-generate","APT::Cache::NoGenerate",0},
959 {'a',"all-versions","APT::Cache::AllVersions",0},
960 {0,"names-only","APT::Cache::NamesOnly",0},
961 {0,"all-names","APT::Cache::AllNames",0},
962 {'c',"config-file",0,CommandLine::ConfigFile},
963 {'o',"option",0,CommandLine::ArbItem},
964 {0,0,0,0}};
965 CommandLine::Dispatch CmdsA[] = {{"help",&ShowHelp},
966 {"add",&DoAdd},
967 {"gencaches",&GenCaches},
968 {"showsrc",&ShowSrcPackage},
969 {0,0}};
970 CommandLine::Dispatch CmdsB[] = {{"showpkg",&DumpPackage},
971 {"stats",&Stats},
972 {"dump",&Dump},
973 {"dumpavail",&DumpAvail},
974 {"unmet",&UnMet},
975 {"check",&Check},
976 {"search",&Search},
977 {"depends",&Depends},
978 {"dotty",&Dotty},
979 {"show",&ShowPackage},
980 {"pkgnames",&ShowPkgNames},
981 {0,0}};
982
983 CacheInitialize();
984
985 // Parse the command line and initialize the package library
986 CommandLine CmdL(Args,_config);
987 if (pkgInitialize(*_config) == false ||
988 CmdL.Parse(argc,argv) == false)
989 {
990 _error->DumpErrors();
991 return 100;
992 }
993
994 // See if the help should be shown
995 if (_config->FindB("help") == true ||
996 CmdL.FileSize() == 0)
997 return ShowHelp(CmdL);
998
999 // Deal with stdout not being a tty
1000 if (ttyname(STDOUT_FILENO) == 0 && _config->FindI("quiet",0) < 1)
1001 _config->Set("quiet","1");
1002
1003 if (CmdL.DispatchArg(CmdsA,false) == false && _error->PendingError() == false)
1004 {
1005 MMap *Map;
1006 if (_config->FindB("APT::Cache::NoGenerate",false) == true)
1007 {
1008 Map = new MMap(*new FileFd(_config->FindFile("Dir::Cache::pkgcache"),
1009 FileFd::ReadOnly),MMap::Public|MMap::ReadOnly);
1010 }
1011 else
1012 {
1013 // Open the cache file
1014 pkgSourceList List;
1015 List.ReadMainList();
1016
1017 // Generate it and map it
1018 OpProgress Prog;
1019 Map = pkgMakeStatusCacheMem(List,Prog);
1020 }
1021
1022 if (_error->PendingError() == false)
1023 {
1024 pkgCache Cache(*Map);
1025 GCache = &Cache;
1026 if (_error->PendingError() == false)
1027 CmdL.DispatchArg(CmdsB);
1028 }
1029 delete Map;
1030 }
1031
1032 // Print any errors or warnings found during parsing
1033 if (_error->empty() == false)
1034 {
1035 bool Errors = _error->PendingError();
1036 _error->DumpErrors();
1037 return Errors == true?100:0;
1038 }
1039
1040 return 0;
1041 }