]> git.saurik.com Git - apt.git/blob - cmdline/apt-cache.cc
26d96c86011340381f85c6afe888e83c33d44a77
[apt.git] / cmdline / apt-cache.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 // $Id: apt-cache.cc,v 1.24 1999/02/08 07:54:58 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 ment 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 <config.h>
27
28 #include <iostream.h>
29 #include <errno.h>
30 /*}}}*/
31
32 pkgCache *GCache = 0;
33
34 // UnMet - Show unmet dependencies /*{{{*/
35 // ---------------------------------------------------------------------
36 /* */
37 bool UnMet(CommandLine &CmdL)
38 {
39 pkgCache &Cache = *GCache;
40 bool Important = _config->FindB("APT::Cache::Important",false);
41
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;
47 for (pkgCache::DepIterator D = V.DependsList(); D.end() == false;)
48 {
49 // Collect or groups
50 pkgCache::DepIterator Start;
51 pkgCache::DepIterator End;
52 D.GlobOr(Start,End);
53
54 /* cout << "s: Check " << Start.TargetPkg().Name() << ',' <<
55 End.TargetPkg().Name() << endl;*/
56
57 // Skip conflicts and replaces
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
64 // Important deps only
65 if (Important == true)
66 if (End->Type != pkgCache::Dep::PreDepends &&
67 End->Type != pkgCache::Dep::Depends)
68 continue;
69
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 /*}}}*/
126 // DumpPackage - Show a dump of a package record /*{{{*/
127 // ---------------------------------------------------------------------
128 /* */
129 bool DumpPackage(CommandLine &CmdL)
130 {
131 pkgCache &Cache = *GCache;
132 for (const char **I = CmdL.FileList + 1; *I != 0; I++)
133 {
134 pkgCache::PkgIterator Pkg = Cache.FindPkg(*I);
135 if (Pkg.end() == true)
136 {
137 _error->Warning("Unable to locate package %s",*I);
138 continue;
139 }
140
141 cout << "Package: " << Pkg.Name() << endl;
142 cout << "Versions: ";
143 for (pkgCache::VerIterator Cur = Pkg.VersionList(); Cur.end() != true; Cur++)
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
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;
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;
178
179 }
180
181 return true;
182 }
183 /*}}}*/
184 // Stats - Dump some nice statistics /*{{{*/
185 // ---------------------------------------------------------------------
186 /* */
187 bool Stats(CommandLine &Cmd)
188 {
189 pkgCache &Cache = *GCache;
190 cout << "Total Package Names : " << Cache.Head().PackageCount << " (" <<
191 SizeToStr(Cache.Head().PackageCount*Cache.Head().PackageSz) << ')' << endl;
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
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
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;
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 +
265 Cache.Head().PackageCount*Cache.Head().PackageSz +
266 Cache.Head().VerFileCount*Cache.Head().VerFileSz +
267 Cache.Head().ProvidesCount*Cache.Head().ProvidesSz;
268 cout << "Total Space Accounted for: " << SizeToStr(Total) << endl;
269
270 return true;
271 }
272 /*}}}*/
273 // Check - Check some things about the cache /*{{{*/
274 // ---------------------------------------------------------------------
275 /* Debug aide mostly */
276 bool Check(CommandLine &Cmd)
277 {
278 pkgCache &Cache = *GCache;
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 /*}}}*/
295 // Dump - show everything /*{{{*/
296 // ---------------------------------------------------------------------
297 /* */
298 bool Dump(CommandLine &Cmd)
299 {
300 pkgCache &Cache = *GCache;
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;
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;
326 }
327
328 return true;
329 }
330 /*}}}*/
331 // DumpAvail - Print out the available list /*{{{*/
332 // ---------------------------------------------------------------------
333 /* This is needed to make dpkg --merge happy */
334 bool DumpAvail(CommandLine &Cmd)
335 {
336 pkgCache &Cache = *GCache;
337 unsigned char *Buffer = new unsigned char[Cache.HeaderP->MaxVerFileSize];
338
339 for (pkgCache::PkgFileIterator I = Cache.FileBegin(); I.end() == false; I++)
340 {
341 if ((I->Flags & pkgCache::Flag::NotSource) != 0)
342 continue;
343
344 if (I.IsOk() == false)
345 {
346 delete [] Buffer;
347 return _error->Error("Package file %s is out of sync.",I.FileName());
348 }
349
350 FileFd PkgF(I.FileName(),FileFd::ReadOnly);
351 if (_error->PendingError() == true)
352 {
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++)
362 {
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 }
376 }
377 }
378 }
379
380 return true;
381 }
382 /*}}}*/
383 // DoAdd - Perform an adding operation /*{{{*/
384 // ---------------------------------------------------------------------
385 /* */
386 bool DoAdd(CommandLine &CmdL)
387 {
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");
391
392 // Open the cache
393 FileFd CacheF(_config->FindFile("Dir::Cache::pkgcache"),FileFd::WriteAny);
394 if (_error->PendingError() == true)
395 return false;
396
397 DynamicMMap Map(CacheF,MMap::Public);
398 if (_error->PendingError() == true)
399 return false;
400
401 OpTextProgress Progress(*_config);
402 pkgCacheGenerator Gen(Map,Progress);
403 if (_error->PendingError() == true)
404 return false;
405
406 unsigned long Length = CmdL.FileSize() - 1;
407 for (const char **I = CmdL.FileList + 1; *I != 0; I++)
408 {
409 Progress.OverallProgress(I - CmdL.FileList,Length,1,"Generating cache");
410 Progress.SubProgress(Length);
411
412 // Do the merge
413 FileFd TagF(*I,FileFd::ReadOnly);
414 debListParser Parser(TagF);
415 if (_error->PendingError() == true)
416 return _error->Error("Problem opening %s",*I);
417
418 if (Gen.SelectFile(*I) == false)
419 return _error->Error("Problem with SelectFile");
420
421 if (Gen.MergeList(Parser) == false)
422 return _error->Error("Problem with MergeList");
423 }
424
425 Progress.Done();
426 GCache = &Gen.GetCache();
427 Stats(CmdL);
428
429 return true;
430 }
431 /*}}}*/
432 // GenCaches - Call the main cache generator /*{{{*/
433 // ---------------------------------------------------------------------
434 /* */
435 bool GenCaches(CommandLine &Cmd)
436 {
437 OpTextProgress Progress(*_config);
438
439 pkgSourceList List;
440 List.ReadMainList();
441 return pkgMakeStatusCache(List,Progress);
442 }
443 /*}}}*/
444 // ShowHelp - Show a help screen /*{{{*/
445 // ---------------------------------------------------------------------
446 /* */
447 bool ShowHelp(CommandLine &Cmd)
448 {
449 cout << PACKAGE << ' ' << VERSION << " for " << ARCHITECTURE <<
450 " compiled on " << __DATE__ << " " << __TIME__ << endl;
451 if (_config->FindB("version") == true)
452 return 100;
453
454 cout << "Usage: apt-cache [options] command" << endl;
455 cout << " apt-cache [options] add file1 [file1 ...]" << endl;
456 cout << " apt-cache [options] showpkg pkg1 [pkg2 ...]" << endl;
457 cout << endl;
458 cout << "apt-cache is a low-level tool used to manipulate APT's binary" << endl;
459 cout << "cache files stored in " << _config->FindFile("Dir::Cache") << endl;
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;
469 cout << " unmet - Show unmet dependencies" << endl;
470 cout << " check - Check the cache a bit" << endl;
471 cout << endl;
472 cout << "Options:" << endl;
473 cout << " -h This help text." << endl;
474 cout << " -p=? The package cache. [" << _config->FindFile("Dir::Cache::pkgcache") << ']' << endl;
475 cout << " -s=? The source cache. [" << _config->FindFile("Dir::Cache::srcpkgcache") << ']' << endl;
476 cout << " -q Disable progress indicator." << endl;
477 cout << " -i Show only important deps for the unmet command." << endl;
478 cout << " -c=? Read this configuration file" << endl;
479 cout << " -o=? Set an arbitary configuration option, ie -o dir::cache=/tmp" << endl;
480 cout << "See the apt-cache(8) and apt.conf(5) manual pages for more information." << endl;
481 return 100;
482 }
483 /*}}}*/
484 // CacheInitialize - Initialize things for apt-cache /*{{{*/
485 // ---------------------------------------------------------------------
486 /* */
487 void CacheInitialize()
488 {
489 _config->Set("quiet",0);
490 _config->Set("help",false);
491 }
492 /*}}}*/
493
494 int main(int argc,const char *argv[])
495 {
496 CommandLine::Args Args[] = {
497 {'h',"help","help",0},
498 {'v',"version","version",0},
499 {'p',"pkg-cache","Dir::Cache::pkgcache",CommandLine::HasArg},
500 {'s',"src-cache","Dir::Cache::srcpkgcache",CommandLine::HasArg},
501 {'q',"quiet","quiet",CommandLine::IntLevel},
502 {'i',"important","APT::Cache::Important",0},
503 {'c',"config-file",0,CommandLine::ConfigFile},
504 {'o',"option",0,CommandLine::ArbItem},
505 {0,0,0,0}};
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}};
517
518 CacheInitialize();
519
520 // Parse the command line and initialize the package library
521 CommandLine CmdL(Args,_config);
522 if (pkgInitialize(*_config) == false ||
523 CmdL.Parse(argc,argv) == false)
524 {
525 _error->DumpErrors();
526 return 100;
527 }
528
529 // See if the help should be shown
530 if (_config->FindB("help") == true ||
531 CmdL.FileSize() == 0)
532 return ShowHelp(CmdL);
533
534 if (CmdL.DispatchArg(CmdsA,false) == false && _error->PendingError() == false)
535 {
536 // Open the cache file
537 FileFd CacheF(_config->FindFile("Dir::Cache::pkgcache"),FileFd::ReadOnly);
538 MMap Map(CacheF,MMap::Public | MMap::ReadOnly);
539 if (_error->PendingError() == false)
540 {
541 pkgCache Cache(Map);
542 GCache = &Cache;
543 if (_error->PendingError() == false)
544 CmdL.DispatchArg(CmdsB);
545 }
546 }
547
548 // Print any errors or warnings found during parsing
549 if (_error->empty() == false)
550 {
551 bool Errors = _error->PendingError();
552 _error->DumpErrors();
553 return Errors == true?100:0;
554 }
555
556 return 0;
557 }