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