]> git.saurik.com Git - apt.git/blame - cmdline/apt-cache.cc
Fixed another oops
[apt.git] / cmdline / apt-cache.cc
CommitLineData
1164783d
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
04aa15a8 3// $Id: apt-cache.cc,v 1.23 1999/01/30 02:12:53 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
11 by the dselect method. Everything else is ment 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>
1164783d
AL
26
27#include <iostream.h>
e1b74f61 28#include <config.h>
1164783d
AL
29 /*}}}*/
30
b0b4efb9
AL
31pkgCache *GCache = 0;
32
cc718e9a
AL
33// UnMet - Show unmet dependencies /*{{{*/
34// ---------------------------------------------------------------------
35/* */
b0b4efb9 36bool UnMet(CommandLine &CmdL)
cc718e9a 37{
b0b4efb9 38 pkgCache &Cache = *GCache;
76fbce56 39 bool Important = _config->FindB("APT::Cache::Important",false);
018f1533 40
cc718e9a
AL
41 for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; P++)
42 {
43 for (pkgCache::VerIterator V = P.VersionList(); V.end() == false; V++)
44 {
45 bool Header = false;
018f1533 46 for (pkgCache::DepIterator D = V.DependsList(); D.end() == false;)
cc718e9a
AL
47 {
48 // Collect or groups
49 pkgCache::DepIterator Start;
50 pkgCache::DepIterator End;
51 D.GlobOr(Start,End);
52
018f1533
AL
53/* cout << "s: Check " << Start.TargetPkg().Name() << ',' <<
54 End.TargetPkg().Name() << endl;*/
55
56 // Skip conflicts and replaces
cc718e9a
AL
57 if (End->Type != pkgCache::Dep::PreDepends &&
58 End->Type != pkgCache::Dep::Depends &&
59 End->Type != pkgCache::Dep::Suggests &&
60 End->Type != pkgCache::Dep::Recommends)
61 continue;
62
018f1533
AL
63 // Important deps only
64 if (Important == true)
65 if (End->Type != pkgCache::Dep::PreDepends &&
66 End->Type != pkgCache::Dep::Depends)
67 continue;
68
cc718e9a
AL
69 // Verify the or group
70 bool OK = false;
71 pkgCache::DepIterator RealStart = Start;
72 do
73 {
74 // See if this dep is Ok
75 pkgCache::Version **VList = Start.AllTargets();
76 if (*VList != 0)
77 {
78 OK = true;
79 delete [] VList;
80 break;
81 }
82 delete [] VList;
83
84 if (Start == End)
85 break;
86 Start++;
87 }
88 while (1);
89
90 // The group is OK
91 if (OK == true)
92 continue;
93
94 // Oops, it failed..
95 if (Header == false)
96 cout << "Package " << P.Name() << " version " <<
97 V.VerStr() << " has an unmet dep:" << endl;
98 Header = true;
99
100 // Print out the dep type
101 cout << " " << End.DepType() << ": ";
102
103 // Show the group
104 Start = RealStart;
105 do
106 {
107 cout << Start.TargetPkg().Name();
108 if (Start.TargetVer() != 0)
109 cout << " (" << Start.CompType() << " " << Start.TargetVer() <<
110 ")";
111 if (Start == End)
112 break;
113 cout << " | ";
114 Start++;
115 }
116 while (1);
117
118 cout << endl;
119 }
120 }
121 }
122 return true;
123}
124 /*}}}*/
1164783d
AL
125// DumpPackage - Show a dump of a package record /*{{{*/
126// ---------------------------------------------------------------------
127/* */
b0b4efb9 128bool DumpPackage(CommandLine &CmdL)
ad00ae81 129{
b0b4efb9 130 pkgCache &Cache = *GCache;
e1b74f61 131 for (const char **I = CmdL.FileList + 1; *I != 0; I++)
1164783d 132 {
e1b74f61 133 pkgCache::PkgIterator Pkg = Cache.FindPkg(*I);
1164783d
AL
134 if (Pkg.end() == true)
135 {
e1b74f61 136 _error->Warning("Unable to locate package %s",*I);
1164783d
AL
137 continue;
138 }
139
140 cout << "Package: " << Pkg.Name() << endl;
141 cout << "Versions: ";
142 for (pkgCache::VerIterator Cur = Pkg.VersionList(); Cur.end() != true; Cur++)
03e39e59
AL
143 {
144 cout << Cur.VerStr();
145 for (pkgCache::VerFileIterator Vf = Cur.FileList(); Vf.end() == false; Vf++)
146 cout << "(" << Vf.File().FileName() << ")";
147 cout << ',';
148 }
149
1164783d
AL
150 cout << endl;
151
152 cout << "Reverse Depends: " << endl;
153 for (pkgCache::DepIterator D = Pkg.RevDependsList(); D.end() != true; D++)
154 cout << " " << D.ParentPkg().Name() << ',' << D.TargetPkg().Name() << endl;
155
156 cout << "Dependencies: " << endl;
157 for (pkgCache::VerIterator Cur = Pkg.VersionList(); Cur.end() != true; Cur++)
158 {
159 cout << Cur.VerStr() << " - ";
160 for (pkgCache::DepIterator Dep = Cur.DependsList(); Dep.end() != true; Dep++)
161 cout << Dep.TargetPkg().Name() << " (" << (int)Dep->CompareOp << " " << Dep.TargetVer() << ") ";
162 cout << endl;
163 }
164
165 cout << "Provides: " << endl;
166 for (pkgCache::VerIterator Cur = Pkg.VersionList(); Cur.end() != true; Cur++)
167 {
168 cout << Cur.VerStr() << " - ";
169 for (pkgCache::PrvIterator Prv = Cur.ProvidesList(); Prv.end() != true; Prv++)
170 cout << Prv.ParentPkg().Name() << " ";
171 cout << endl;
8efa2a3b
AL
172 }
173 cout << "Reverse Provides: " << endl;
174 for (pkgCache::PrvIterator Prv = Pkg.ProvidesList(); Prv.end() != true; Prv++)
175 cout << Prv.OwnerPkg().Name() << " " << Prv.OwnerVer().VerStr();
176 cout << endl;
03e39e59 177
1164783d
AL
178 }
179
180 return true;
181}
182 /*}}}*/
183// Stats - Dump some nice statistics /*{{{*/
184// ---------------------------------------------------------------------
185/* */
b0b4efb9 186bool Stats(CommandLine &Cmd)
1164783d 187{
b0b4efb9 188 pkgCache &Cache = *GCache;
f826cfaa
AL
189 cout << "Total Package Names : " << Cache.Head().PackageCount << " (" <<
190 SizeToStr(Cache.Head().PackageCount*Cache.Head().PackageSz) << ')' << endl;
1164783d
AL
191 pkgCache::PkgIterator I = Cache.PkgBegin();
192
193 int Normal = 0;
194 int Virtual = 0;
195 int NVirt = 0;
196 int DVirt = 0;
197 int Missing = 0;
198 for (;I.end() != true; I++)
199 {
200 if (I->VersionList != 0 && I->ProvidesList == 0)
201 {
202 Normal++;
203 continue;
204 }
205
206 if (I->VersionList != 0 && I->ProvidesList != 0)
207 {
208 NVirt++;
209 continue;
210 }
211
212 if (I->VersionList == 0 && I->ProvidesList != 0)
213 {
214 // Only 1 provides
215 if (I.ProvidesList()->NextProvides == 0)
216 {
217 DVirt++;
218 }
219 else
220 Virtual++;
221 continue;
222 }
223 if (I->VersionList == 0 && I->ProvidesList == 0)
224 {
225 Missing++;
226 continue;
227 }
228 }
229 cout << " Normal Packages: " << Normal << endl;
230 cout << " Pure Virtual Packages: " << Virtual << endl;
231 cout << " Single Virtual Packages: " << DVirt << endl;
232 cout << " Mixed Virtual Packages: " << NVirt << endl;
233 cout << " Missing: " << Missing << endl;
234
f826cfaa
AL
235 cout << "Total Distinct Versions: " << Cache.Head().VersionCount << " (" <<
236 SizeToStr(Cache.Head().VersionCount*Cache.Head().VersionSz) << ')' << endl;
237 cout << "Total Dependencies: " << Cache.Head().DependsCount << " (" <<
238 SizeToStr(Cache.Head().DependsCount*Cache.Head().DependencySz) << ')' << endl;
239
a7e66b17
AL
240 cout << "Total Ver/File relations: " << Cache.Head().VerFileCount << " (" <<
241 SizeToStr(Cache.Head().VerFileCount*Cache.Head().VerFileSz) << ')' << endl;
242 cout << "Total Provides Mappings: " << Cache.Head().ProvidesCount << " (" <<
243 SizeToStr(Cache.Head().ProvidesCount*Cache.Head().ProvidesSz) << ')' << endl;
f826cfaa
AL
244
245 // String list stats
246 unsigned long Size = 0;
247 unsigned long Count = 0;
248 for (pkgCache::StringItem *I = Cache.StringItemP + Cache.Head().StringList;
249 I!= Cache.StringItemP; I = Cache.StringItemP + I->NextItem)
250 {
251 Count++;
252 Size += strlen(Cache.StrP + I->String);
253 }
254 cout << "Total Globbed Strings: " << Count << " (" << SizeToStr(Size) << ')' << endl;
255
256 unsigned long Slack = 0;
257 for (int I = 0; I != 7; I++)
258 Slack += Cache.Head().Pools[I].ItemSize*Cache.Head().Pools[I].Count;
259 cout << "Total Slack space: " << SizeToStr(Slack) << endl;
260
261 unsigned long Total = 0;
262 Total = Slack + Size + Cache.Head().DependsCount*Cache.Head().DependencySz +
263 Cache.Head().VersionCount*Cache.Head().VersionSz +
a7e66b17
AL
264 Cache.Head().PackageCount*Cache.Head().PackageSz +
265 Cache.Head().VerFileCount*Cache.Head().VerFileSz +
266 Cache.Head().ProvidesCount*Cache.Head().ProvidesSz;
f826cfaa
AL
267 cout << "Total Space Accounted for: " << SizeToStr(Total) << endl;
268
1164783d
AL
269 return true;
270}
271 /*}}}*/
83d89a9f
AL
272// Check - Check some things about the cache /*{{{*/
273// ---------------------------------------------------------------------
274/* Debug aide mostly */
b0b4efb9 275bool Check(CommandLine &Cmd)
83d89a9f 276{
b0b4efb9 277 pkgCache &Cache = *GCache;
83d89a9f
AL
278 pkgCache::PkgIterator Pkg = Cache.PkgBegin();
279 for (;Pkg.end() != true; Pkg++)
280 {
281 if (Pkg.Section() == 0 && Pkg->VersionList != 0)
282 cout << "Bad section " << Pkg.Name() << endl;
283
284 for (pkgCache::VerIterator Cur = Pkg.VersionList();
285 Cur.end() != true; Cur++)
286 {
287 if (Cur->Priority < 1 || Cur->Priority > 5)
288 cout << "Bad prio " << Pkg.Name() << ',' << Cur.VerStr() << " == " << (int)Cur->Priority << endl;
289 }
290 }
291 return true;
292}
293 /*}}}*/
1164783d
AL
294// Dump - show everything /*{{{*/
295// ---------------------------------------------------------------------
296/* */
b0b4efb9 297bool Dump(CommandLine &Cmd)
1164783d 298{
b0b4efb9 299 pkgCache &Cache = *GCache;
1164783d
AL
300 for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; P++)
301 {
302 cout << "Package: " << P.Name() << endl;
303 for (pkgCache::VerIterator V = P.VersionList(); V.end() == false; V++)
304 {
305 cout << " Version: " << V.VerStr() << endl;
306 cout << " File: " << V.FileList().File().FileName() << endl;
307 for (pkgCache::DepIterator D = V.DependsList(); D.end() == false; D++)
308 cout << " Depends: " << D.TargetPkg().Name() << ' ' << D.TargetVer() << endl;
309 }
310 }
311
312 for (pkgCache::PkgFileIterator F(Cache); F.end() == false; F++)
313 {
314 cout << "File: " << F.FileName() << endl;
315 cout << " Size: " << F->Size << endl;
316 cout << " ID: " << F->ID << endl;
317 cout << " Flags: " << F->Flags << endl;
b0b4efb9
AL
318 cout << " Time: " << TimeRFC1123(F->mtime) << endl;
319 cout << " Archive: " << F.Archive() << endl;
320 cout << " Component: " << F.Component() << endl;
321 cout << " Version: " << F.Version() << endl;
322 cout << " Origin: " << F.Origin() << endl;
323 cout << " Label: " << F.Label() << endl;
324 cout << " Architecture: " << F.Architecture() << endl;
1164783d
AL
325 }
326
327 return true;
328}
329 /*}}}*/
330// DumpAvail - Print out the available list /*{{{*/
331// ---------------------------------------------------------------------
332/* This is needed to make dpkg --merge happy */
b0b4efb9 333bool DumpAvail(CommandLine &Cmd)
1164783d 334{
b0b4efb9 335 pkgCache &Cache = *GCache;
ad00ae81 336 unsigned char *Buffer = new unsigned char[Cache.HeaderP->MaxVerFileSize];
1164783d 337
ad00ae81 338 for (pkgCache::PkgFileIterator I = Cache.FileBegin(); I.end() == false; I++)
1164783d 339 {
ad00ae81 340 if ((I->Flags & pkgCache::Flag::NotSource) != 0)
1164783d
AL
341 continue;
342
ad00ae81
AL
343 if (I.IsOk() == false)
344 {
345 delete [] Buffer;
346 return _error->Error("Package file %s is out of sync.",I.FileName());
347 }
1164783d 348
8e06abb2 349 FileFd PkgF(I.FileName(),FileFd::ReadOnly);
ad00ae81 350 if (_error->PendingError() == true)
1164783d 351 {
ad00ae81
AL
352 delete [] Buffer;
353 return false;
354 }
355
356 /* Write all of the records from this package file, we search the entire
357 structure to find them */
358 for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; P++)
359 {
360 for (pkgCache::VerIterator V = P.VersionList(); V.end() == false; V++)
1164783d 361 {
ad00ae81
AL
362 if (V->FileList == 0)
363 continue;
364 if (V.FileList().File() != I)
365 continue;
366
367 // Read the record and then write it out again.
368 if (PkgF.Seek(V.FileList()->Offset) == false ||
369 PkgF.Read(Buffer,V.FileList()->Size) == false ||
370 write(STDOUT_FILENO,Buffer,V.FileList()->Size) != V.FileList()->Size)
371 {
372 delete [] Buffer;
373 return false;
374 }
1164783d 375 }
1164783d 376 }
ad00ae81
AL
377 }
378
379 return true;
380}
381 /*}}}*/
382// DoAdd - Perform an adding operation /*{{{*/
383// ---------------------------------------------------------------------
384/* */
e1b74f61 385bool DoAdd(CommandLine &CmdL)
ad00ae81 386{
e1b74f61
AL
387 // Make sure there is at least one argument
388 if (CmdL.FileSize() <= 1)
389 return _error->Error("You must give at least one file name");
ad00ae81
AL
390
391 // Open the cache
018f1533 392 FileFd CacheF(_config->FindFile("Dir::Cache::pkgcache"),FileFd::WriteAny);
ad00ae81
AL
393 if (_error->PendingError() == true)
394 return false;
395
396 DynamicMMap Map(CacheF,MMap::Public);
397 if (_error->PendingError() == true)
398 return false;
404ec98e 399
0a8e3465 400 OpTextProgress Progress(*_config);
404ec98e 401 pkgCacheGenerator Gen(Map,Progress);
ad00ae81
AL
402 if (_error->PendingError() == true)
403 return false;
404
e1b74f61
AL
405 unsigned long Length = CmdL.FileSize() - 1;
406 for (const char **I = CmdL.FileList + 1; *I != 0; I++)
ad00ae81 407 {
e1b74f61 408 Progress.OverallProgress(I - CmdL.FileList,Length,1,"Generating cache");
018f1533
AL
409 Progress.SubProgress(Length);
410
ad00ae81 411 // Do the merge
e1b74f61 412 FileFd TagF(*I,FileFd::ReadOnly);
ad00ae81
AL
413 debListParser Parser(TagF);
414 if (_error->PendingError() == true)
e1b74f61 415 return _error->Error("Problem opening %s",*I);
ad00ae81 416
e1b74f61 417 if (Gen.SelectFile(*I) == false)
ad00ae81
AL
418 return _error->Error("Problem with SelectFile");
419
420 if (Gen.MergeList(Parser) == false)
421 return _error->Error("Problem with MergeList");
1164783d 422 }
404ec98e
AL
423
424 Progress.Done();
b0b4efb9
AL
425 GCache = &Gen.GetCache();
426 Stats(CmdL);
ad00ae81 427
1164783d
AL
428 return true;
429}
430 /*}}}*/
880e9be4
AL
431// GenCaches - Call the main cache generator /*{{{*/
432// ---------------------------------------------------------------------
433/* */
b0b4efb9 434bool GenCaches(CommandLine &Cmd)
880e9be4 435{
0a8e3465
AL
436 OpTextProgress Progress(*_config);
437
880e9be4
AL
438 pkgSourceList List;
439 List.ReadMainList();
0a8e3465 440 return pkgMakeStatusCache(List,Progress);
880e9be4
AL
441}
442 /*}}}*/
e1b74f61
AL
443// ShowHelp - Show a help screen /*{{{*/
444// ---------------------------------------------------------------------
445/* */
b0b4efb9 446bool ShowHelp(CommandLine &Cmd)
e1b74f61
AL
447{
448 cout << PACKAGE << ' ' << VERSION << " for " << ARCHITECTURE <<
449 " compiled on " << __DATE__ << " " << __TIME__ << endl;
04aa15a8
AL
450 if (_config->FindB("version") == true)
451 return 100;
e1b74f61
AL
452
453 cout << "Usage: apt-cache [options] command" << endl;
454 cout << " apt-cache [options] add file1 [file1 ...]" << endl;
0a8e3465 455 cout << " apt-cache [options] showpkg pkg1 [pkg2 ...]" << endl;
e1b74f61
AL
456 cout << endl;
457 cout << "apt-cache is a low-level tool used to manipulate APT's binary" << endl;
303a1703 458 cout << "cache files stored in " << _config->FindFile("Dir::Cache") << endl;
e1b74f61
AL
459 cout << "It is not ment for ordinary use only as a debug aide." << endl;
460 cout << endl;
461 cout << "Commands:" << endl;
462 cout << " add - Add an package file to the source cache" << endl;
463 cout << " gencaches - Build both the package and source cache" << endl;
464 cout << " showpkg - Show some general information for a single package" << endl;
465 cout << " stats - Show some basic statistics" << endl;
466 cout << " dump - Show the entire file in a terse form" << endl;
467 cout << " dumpavail - Print an available file to stdout" << endl;
cc718e9a 468 cout << " unmet - Show unmet dependencies" << endl;
83d89a9f 469 cout << " check - Check the cache a bit" << endl;
e1b74f61
AL
470 cout << endl;
471 cout << "Options:" << endl;
472 cout << " -h This help text." << endl;
303a1703
AL
473 cout << " -p=? The package cache. [" << _config->FindFile("Dir::Cache::pkgcache") << ']' << endl;
474 cout << " -s=? The source cache. [" << _config->FindFile("Dir::Cache::srcpkgcache") << ']' << endl;
85f72a56
AL
475 cout << " -q Disable progress indicator." << endl;
476 cout << " -i Show only important deps for the unmet command." << endl;
e1b74f61
AL
477 cout << " -c=? Read this configuration file" << endl;
478 cout << " -o=? Set an arbitary configuration option, ie -o dir::cache=/tmp" << endl;
21ae3cae 479 cout << "See the apt-cache(8) and apt.conf(5) manual pages for more information." << endl;
e1b74f61
AL
480 return 100;
481}
482 /*}}}*/
0a8e3465
AL
483// CacheInitialize - Initialize things for apt-cache /*{{{*/
484// ---------------------------------------------------------------------
485/* */
486void CacheInitialize()
487{
488 _config->Set("quiet",0);
489 _config->Set("help",false);
490}
491 /*}}}*/
1164783d 492
08e8f724 493int main(int argc,const char *argv[])
1164783d 494{
08e8f724
AL
495 CommandLine::Args Args[] = {
496 {'h',"help","help",0},
04aa15a8 497 {'v',"version","version",0},
e1b74f61
AL
498 {'p',"pkg-cache","Dir::Cache::pkgcache",CommandLine::HasArg},
499 {'s',"src-cache","Dir::Cache::srcpkgcache",CommandLine::HasArg},
500 {'q',"quiet","quiet",CommandLine::IntLevel},
76fbce56 501 {'i',"important","APT::Cache::Important",0},
e1b74f61
AL
502 {'c',"config-file",0,CommandLine::ConfigFile},
503 {'o',"option",0,CommandLine::ArbItem},
08e8f724 504 {0,0,0,0}};
b0b4efb9
AL
505 CommandLine::Dispatch CmdsA[] = {{"help",&ShowHelp},
506 {"add",&DoAdd},
507 {"gencaches",&GenCaches},
508 {0,0}};
509 CommandLine::Dispatch CmdsB[] = {{"showpkg",&DumpPackage},
510 {"stats",&Stats},
511 {"dump",&Dump},
512 {"dumpavail",&DumpAvail},
513 {"unmet",&UnMet},
514 {"check",&Check},
515 {0,0}};
0a8e3465
AL
516
517 CacheInitialize();
e1b74f61
AL
518
519 // Parse the command line and initialize the package library
520 CommandLine CmdL(Args,_config);
08e8f724 521 if (pkgInitialize(*_config) == false ||
e1b74f61 522 CmdL.Parse(argc,argv) == false)
08e8f724
AL
523 {
524 _error->DumpErrors();
525 return 100;
1164783d 526 }
8efa2a3b 527
e1b74f61
AL
528 // See if the help should be shown
529 if (_config->FindB("help") == true ||
530 CmdL.FileSize() == 0)
b0b4efb9 531 return ShowHelp(CmdL);
880e9be4 532
b0b4efb9
AL
533 if (CmdL.DispatchArg(CmdsA,false) == false && _error->PendingError() == false)
534 {
ad00ae81 535 // Open the cache file
303a1703 536 FileFd CacheF(_config->FindFile("Dir::Cache::pkgcache"),FileFd::ReadOnly);
ad00ae81 537 MMap Map(CacheF,MMap::Public | MMap::ReadOnly);
b0b4efb9 538 if (_error->PendingError() == false)
1164783d 539 {
b0b4efb9
AL
540 pkgCache Cache(Map);
541 GCache = &Cache;
542 if (_error->PendingError() == false)
543 CmdL.DispatchArg(CmdsB);
544 }
1164783d
AL
545 }
546
547 // Print any errors or warnings found during parsing
548 if (_error->empty() == false)
549 {
0a8e3465 550 bool Errors = _error->PendingError();
1164783d 551 _error->DumpErrors();
0a8e3465 552 return Errors == true?100:0;
1164783d
AL
553 }
554
555 return 0;
556}