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