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