Fixed or handling bug
[ntk/apt.git] / cmdline / apt-cache.cc
CommitLineData
1164783d
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
3e94da1b 3// $Id: apt-cache.cc,v 1.43 2000/05/12 04:00:59 jgg Exp $
1164783d
AL
4/* ######################################################################
5
e1b74f61 6 apt-cache - Manages the cache files
1164783d 7
e1b74f61
AL
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
82297457 11 by the dselect method. Everything else is meant as a debug aide.
1164783d
AL
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>
8efa2a3b 21#include <apt-pkg/init.h>
404ec98e 22#include <apt-pkg/progress.h>
880e9be4 23#include <apt-pkg/sourcelist.h>
08e8f724 24#include <apt-pkg/cmndline.h>
cdcc6d34 25#include <apt-pkg/strutl.h>
9dbb421f 26#include <apt-pkg/pkgrecords.h>
f8f410f5 27#include <apt-pkg/srcrecords.h>
3e94da1b 28#include <apt-pkg/version.h>
43981212 29#include <config.h>
1164783d
AL
30
31#include <iostream.h>
cdb970c7 32#include <unistd.h>
43981212 33#include <errno.h>
9dbb421f 34#include <regex.h>
3e94da1b 35#include <stdio.h>
1164783d
AL
36 /*}}}*/
37
b0b4efb9
AL
38pkgCache *GCache = 0;
39
cc718e9a
AL
40// UnMet - Show unmet dependencies /*{{{*/
41// ---------------------------------------------------------------------
42/* */
b0b4efb9 43bool UnMet(CommandLine &CmdL)
cc718e9a 44{
b0b4efb9 45 pkgCache &Cache = *GCache;
76fbce56 46 bool Important = _config->FindB("APT::Cache::Important",false);
018f1533 47
cc718e9a
AL
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;
018f1533 53 for (pkgCache::DepIterator D = V.DependsList(); D.end() == false;)
cc718e9a
AL
54 {
55 // Collect or groups
56 pkgCache::DepIterator Start;
57 pkgCache::DepIterator End;
58 D.GlobOr(Start,End);
59
018f1533
AL
60/* cout << "s: Check " << Start.TargetPkg().Name() << ',' <<
61 End.TargetPkg().Name() << endl;*/
62
63 // Skip conflicts and replaces
cc718e9a
AL
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
018f1533
AL
70 // Important deps only
71 if (Important == true)
72 if (End->Type != pkgCache::Dep::PreDepends &&
73 End->Type != pkgCache::Dep::Depends)
74 continue;
75
cc718e9a
AL
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 /*}}}*/
1164783d
AL
132// DumpPackage - Show a dump of a package record /*{{{*/
133// ---------------------------------------------------------------------
134/* */
b0b4efb9 135bool DumpPackage(CommandLine &CmdL)
ad00ae81 136{
b0b4efb9 137 pkgCache &Cache = *GCache;
e1b74f61 138 for (const char **I = CmdL.FileList + 1; *I != 0; I++)
1164783d 139 {
e1b74f61 140 pkgCache::PkgIterator Pkg = Cache.FindPkg(*I);
1164783d
AL
141 if (Pkg.end() == true)
142 {
e1b74f61 143 _error->Warning("Unable to locate package %s",*I);
1164783d
AL
144 continue;
145 }
146
147 cout << "Package: " << Pkg.Name() << endl;
148 cout << "Versions: ";
149 for (pkgCache::VerIterator Cur = Pkg.VersionList(); Cur.end() != true; Cur++)
03e39e59
AL
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
1164783d
AL
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;
8efa2a3b
AL
179 }
180 cout << "Reverse Provides: " << endl;
181 for (pkgCache::PrvIterator Prv = Pkg.ProvidesList(); Prv.end() != true; Prv++)
2d6751b9 182 cout << Prv.OwnerPkg().Name() << " " << Prv.OwnerVer().VerStr() << endl;
1164783d
AL
183 }
184
185 return true;
186}
187 /*}}}*/
188// Stats - Dump some nice statistics /*{{{*/
189// ---------------------------------------------------------------------
190/* */
b0b4efb9 191bool Stats(CommandLine &Cmd)
1164783d 192{
b0b4efb9 193 pkgCache &Cache = *GCache;
f826cfaa
AL
194 cout << "Total Package Names : " << Cache.Head().PackageCount << " (" <<
195 SizeToStr(Cache.Head().PackageCount*Cache.Head().PackageSz) << ')' << endl;
1164783d
AL
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
f826cfaa
AL
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
a7e66b17
AL
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;
f826cfaa
AL
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 +
a7e66b17
AL
269 Cache.Head().PackageCount*Cache.Head().PackageSz +
270 Cache.Head().VerFileCount*Cache.Head().VerFileSz +
271 Cache.Head().ProvidesCount*Cache.Head().ProvidesSz;
f826cfaa
AL
272 cout << "Total Space Accounted for: " << SizeToStr(Total) << endl;
273
1164783d
AL
274 return true;
275}
276 /*}}}*/
83d89a9f
AL
277// Check - Check some things about the cache /*{{{*/
278// ---------------------------------------------------------------------
279/* Debug aide mostly */
b0b4efb9 280bool Check(CommandLine &Cmd)
83d89a9f 281{
b0b4efb9 282 pkgCache &Cache = *GCache;
83d89a9f
AL
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 /*}}}*/
1164783d
AL
299// Dump - show everything /*{{{*/
300// ---------------------------------------------------------------------
301/* */
b0b4efb9 302bool Dump(CommandLine &Cmd)
1164783d 303{
b0b4efb9 304 pkgCache &Cache = *GCache;
1164783d
AL
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;
b0b4efb9
AL
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;
1164783d
AL
330 }
331
332 return true;
333}
334 /*}}}*/
335// DumpAvail - Print out the available list /*{{{*/
336// ---------------------------------------------------------------------
337/* This is needed to make dpkg --merge happy */
b0b4efb9 338bool DumpAvail(CommandLine &Cmd)
1164783d 339{
b0b4efb9 340 pkgCache &Cache = *GCache;
ad00ae81 341 unsigned char *Buffer = new unsigned char[Cache.HeaderP->MaxVerFileSize];
1164783d 342
ad00ae81 343 for (pkgCache::PkgFileIterator I = Cache.FileBegin(); I.end() == false; I++)
1164783d 344 {
5b8c90bf
AL
345 if ((I->Flags & pkgCache::Flag::NotSource) != 0)
346 continue;
347
ad00ae81
AL
348 if (I.IsOk() == false)
349 {
350 delete [] Buffer;
351 return _error->Error("Package file %s is out of sync.",I.FileName());
352 }
1164783d 353
8e06abb2 354 FileFd PkgF(I.FileName(),FileFd::ReadOnly);
ad00ae81 355 if (_error->PendingError() == true)
1164783d 356 {
ad00ae81
AL
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 {
bd432be3 365 // Find the proper version to use. We should probably use the DepCache.
1fcbfcb8 366 pkgCache::VerIterator V = Cache.GetCandidateVer(P,false);
bd432be3
AL
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)
1164783d 375 {
bd432be3
AL
376 delete [] Buffer;
377 return false;
378 }
1164783d 379 }
ad00ae81
AL
380 }
381
349cd3b8
AL
382 return true;
383}
384 /*}}}*/
4b1b89c5 385// Depends - Print out a dependency tree /*{{{*/
349cd3b8
AL
386// ---------------------------------------------------------------------
387/* */
388bool 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
3e94da1b
AL
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/ */
446bool 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");
ad00ae81
AL
646 return true;
647}
648 /*}}}*/
649// DoAdd - Perform an adding operation /*{{{*/
650// ---------------------------------------------------------------------
651/* */
e1b74f61 652bool DoAdd(CommandLine &CmdL)
ad00ae81 653{
e1b74f61
AL
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");
ad00ae81
AL
657
658 // Open the cache
018f1533 659 FileFd CacheF(_config->FindFile("Dir::Cache::pkgcache"),FileFd::WriteAny);
ad00ae81
AL
660 if (_error->PendingError() == true)
661 return false;
662
663 DynamicMMap Map(CacheF,MMap::Public);
664 if (_error->PendingError() == true)
665 return false;
404ec98e 666
0a8e3465 667 OpTextProgress Progress(*_config);
404ec98e 668 pkgCacheGenerator Gen(Map,Progress);
ad00ae81
AL
669 if (_error->PendingError() == true)
670 return false;
671
e1b74f61
AL
672 unsigned long Length = CmdL.FileSize() - 1;
673 for (const char **I = CmdL.FileList + 1; *I != 0; I++)
ad00ae81 674 {
e1b74f61 675 Progress.OverallProgress(I - CmdL.FileList,Length,1,"Generating cache");
018f1533
AL
676 Progress.SubProgress(Length);
677
ad00ae81 678 // Do the merge
e1b74f61 679 FileFd TagF(*I,FileFd::ReadOnly);
ad00ae81
AL
680 debListParser Parser(TagF);
681 if (_error->PendingError() == true)
e1b74f61 682 return _error->Error("Problem opening %s",*I);
ad00ae81 683
e1b74f61 684 if (Gen.SelectFile(*I) == false)
ad00ae81
AL
685 return _error->Error("Problem with SelectFile");
686
687 if (Gen.MergeList(Parser) == false)
688 return _error->Error("Problem with MergeList");
1164783d 689 }
404ec98e
AL
690
691 Progress.Done();
b0b4efb9
AL
692 GCache = &Gen.GetCache();
693 Stats(CmdL);
ad00ae81 694
7e2e2d5d
AL
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. */
702bool 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
9dbb421f
AL
733 return true;
734}
735 /*}}}*/
736// Search - Perform a search /*{{{*/
737// ---------------------------------------------------------------------
738/* This searches the package names and pacakge descriptions for a pattern */
739bool Search(CommandLine &CmdL)
740{
741 pkgCache &Cache = *GCache;
7e2e2d5d
AL
742 bool ShowFull = _config->FindB("APT::Cache::ShowFull",false);
743 bool NamesOnly = _config->FindB("APT::Cache::NamesOnly",false);
9dbb421f
AL
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 {
7e2e2d5d 764 // We search against the install version as that makes the most sense..
1fcbfcb8 765 pkgCache::VerIterator V = Cache.GetCandidateVer(I);
7e2e2d5d
AL
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))
9dbb421f 774 {
7e2e2d5d
AL
775 if (ShowFull == true)
776 DisplayRecord(V);
777 else
778 cout << I.Name() << " - " << P.ShortDesc() << endl;
9dbb421f
AL
779 }
780 }
781
782 regfree(&Pattern);
1164783d
AL
783 return true;
784}
785 /*}}}*/
7e2e2d5d
AL
786// ShowPackage - Dump the package record to the screen /*{{{*/
787// ---------------------------------------------------------------------
788/* */
789bool 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.
648e3cb4
AL
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 }
7e2e2d5d 819 }
7c1133fe
AL
820 return true;
821}
822 /*}}}*/
823// ShowPkgNames - Show package names /*{{{*/
824// ---------------------------------------------------------------------
825/* This does a prefix match on the first argument */
826bool 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
7e2e2d5d
AL
854 return true;
855}
856 /*}}}*/
f8f410f5
AL
857// ShowSrcPackage - Show source package records /*{{{*/
858// ---------------------------------------------------------------------
859/* */
860bool 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 {
aaee8293
AL
872 SrcRecs.Restart();
873
f8f410f5
AL
874 pkgSrcRecords::Parser *Parse;
875 while ((Parse = SrcRecs.Find(*I,false)) != 0)
876 cout << Parse->AsStr();
877 }
878 return true;
879}
880 /*}}}*/
880e9be4
AL
881// GenCaches - Call the main cache generator /*{{{*/
882// ---------------------------------------------------------------------
883/* */
b0b4efb9 884bool GenCaches(CommandLine &Cmd)
880e9be4 885{
0a8e3465
AL
886 OpTextProgress Progress(*_config);
887
880e9be4
AL
888 pkgSourceList List;
889 List.ReadMainList();
0a8e3465 890 return pkgMakeStatusCache(List,Progress);
880e9be4
AL
891}
892 /*}}}*/
e1b74f61
AL
893// ShowHelp - Show a help screen /*{{{*/
894// ---------------------------------------------------------------------
895/* */
b0b4efb9 896bool ShowHelp(CommandLine &Cmd)
e1b74f61
AL
897{
898 cout << PACKAGE << ' ' << VERSION << " for " << ARCHITECTURE <<
899 " compiled on " << __DATE__ << " " << __TIME__ << endl;
04aa15a8
AL
900 if (_config->FindB("version") == true)
901 return 100;
e1b74f61
AL
902
903 cout << "Usage: apt-cache [options] command" << endl;
904 cout << " apt-cache [options] add file1 [file1 ...]" << endl;
0a8e3465 905 cout << " apt-cache [options] showpkg pkg1 [pkg2 ...]" << endl;
e1b74f61
AL
906 cout << endl;
907 cout << "apt-cache is a low-level tool used to manipulate APT's binary" << endl;
303a1703 908 cout << "cache files stored in " << _config->FindFile("Dir::Cache") << endl;
82297457 909 cout << "It is not meant for ordinary use only as a debug aide." << endl;
e1b74f61
AL
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;
cc718e9a 918 cout << " unmet - Show unmet dependencies" << endl;
83d89a9f 919 cout << " check - Check the cache a bit" << endl;
9dbb421f 920 cout << " search - Search the package list for a regex pattern" << endl;
7e2e2d5d 921 cout << " show - Show a readable record for the package" << endl;
349cd3b8 922 cout << " depends - Show raw dependency information for a package" << endl;
7c1133fe 923 cout << " pkgnames - List the names of all packages" << endl;
3e94da1b 924 cout << " dotty - Generate package graphs for GraphVis" << endl;
e1b74f61
AL
925 cout << endl;
926 cout << "Options:" << endl;
927 cout << " -h This help text." << endl;
303a1703
AL
928 cout << " -p=? The package cache. [" << _config->FindFile("Dir::Cache::pkgcache") << ']' << endl;
929 cout << " -s=? The source cache. [" << _config->FindFile("Dir::Cache::srcpkgcache") << ']' << endl;
85f72a56
AL
930 cout << " -q Disable progress indicator." << endl;
931 cout << " -i Show only important deps for the unmet command." << endl;
e1b74f61 932 cout << " -c=? Read this configuration file" << endl;
7974b907 933 cout << " -o=? Set an arbitary configuration option, eg -o dir::cache=/tmp" << endl;
21ae3cae 934 cout << "See the apt-cache(8) and apt.conf(5) manual pages for more information." << endl;
e1b74f61
AL
935 return 100;
936}
937 /*}}}*/
0a8e3465
AL
938// CacheInitialize - Initialize things for apt-cache /*{{{*/
939// ---------------------------------------------------------------------
940/* */
941void CacheInitialize()
942{
943 _config->Set("quiet",0);
944 _config->Set("help",false);
945}
946 /*}}}*/
1164783d 947
08e8f724 948int main(int argc,const char *argv[])
1164783d 949{
08e8f724
AL
950 CommandLine::Args Args[] = {
951 {'h',"help","help",0},
04aa15a8 952 {'v',"version","version",0},
e1b74f61
AL
953 {'p',"pkg-cache","Dir::Cache::pkgcache",CommandLine::HasArg},
954 {'s',"src-cache","Dir::Cache::srcpkgcache",CommandLine::HasArg},
955 {'q',"quiet","quiet",CommandLine::IntLevel},
76fbce56 956 {'i',"important","APT::Cache::Important",0},
7e2e2d5d 957 {'f',"full","APT::Cache::ShowFull",0},
4b1b89c5 958 {'g',"no-generate","APT::Cache::NoGenerate",0},
648e3cb4 959 {'a',"all-versions","APT::Cache::AllVersions",0},
7e2e2d5d 960 {0,"names-only","APT::Cache::NamesOnly",0},
7c1133fe 961 {0,"all-names","APT::Cache::AllNames",0},
e1b74f61
AL
962 {'c',"config-file",0,CommandLine::ConfigFile},
963 {'o',"option",0,CommandLine::ArbItem},
08e8f724 964 {0,0,0,0}};
b0b4efb9
AL
965 CommandLine::Dispatch CmdsA[] = {{"help",&ShowHelp},
966 {"add",&DoAdd},
967 {"gencaches",&GenCaches},
f8f410f5 968 {"showsrc",&ShowSrcPackage},
b0b4efb9
AL
969 {0,0}};
970 CommandLine::Dispatch CmdsB[] = {{"showpkg",&DumpPackage},
971 {"stats",&Stats},
972 {"dump",&Dump},
973 {"dumpavail",&DumpAvail},
974 {"unmet",&UnMet},
975 {"check",&Check},
9dbb421f 976 {"search",&Search},
349cd3b8 977 {"depends",&Depends},
3e94da1b 978 {"dotty",&Dotty},
7e2e2d5d 979 {"show",&ShowPackage},
7c1133fe 980 {"pkgnames",&ShowPkgNames},
b0b4efb9 981 {0,0}};
0a8e3465
AL
982
983 CacheInitialize();
e1b74f61
AL
984
985 // Parse the command line and initialize the package library
986 CommandLine CmdL(Args,_config);
08e8f724 987 if (pkgInitialize(*_config) == false ||
e1b74f61 988 CmdL.Parse(argc,argv) == false)
08e8f724
AL
989 {
990 _error->DumpErrors();
991 return 100;
1164783d 992 }
8efa2a3b 993
e1b74f61
AL
994 // See if the help should be shown
995 if (_config->FindB("help") == true ||
996 CmdL.FileSize() == 0)
b0b4efb9 997 return ShowHelp(CmdL);
880e9be4 998
a9a5908d
AL
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
b0b4efb9 1003 if (CmdL.DispatchArg(CmdsA,false) == false && _error->PendingError() == false)
4b1b89c5
AL
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();
f8f410f5 1016
4b1b89c5
AL
1017 // Generate it and map it
1018 OpProgress Prog;
1019 Map = pkgMakeStatusCacheMem(List,Prog);
1020 }
1021
b0b4efb9 1022 if (_error->PendingError() == false)
1164783d 1023 {
803fafcb 1024 pkgCache Cache(*Map);
b0b4efb9
AL
1025 GCache = &Cache;
1026 if (_error->PendingError() == false)
1027 CmdL.DispatchArg(CmdsB);
803fafcb
AL
1028 }
1029 delete Map;
1164783d
AL
1030 }
1031
1032 // Print any errors or warnings found during parsing
1033 if (_error->empty() == false)
1034 {
0a8e3465 1035 bool Errors = _error->PendingError();
1164783d 1036 _error->DumpErrors();
0a8e3465 1037 return Errors == true?100:0;
1164783d
AL
1038 }
1039
1040 return 0;
1041}