]> git.saurik.com Git - apt.git/blob - cmdline/apt-cache.cc
Release support
[apt.git] / cmdline / apt-cache.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 // $Id: apt-cache.cc,v 1.19 1998/12/14 02:23:47 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().PackageCount << " (" <<
241 SizeToStr(Cache.Head().PackageCount*Cache.Head().PackageSz) << ')' << endl;
242
243 // String list stats
244 unsigned long Size = 0;
245 unsigned long Count = 0;
246 for (pkgCache::StringItem *I = Cache.StringItemP + Cache.Head().StringList;
247 I!= Cache.StringItemP; I = Cache.StringItemP + I->NextItem)
248 {
249 Count++;
250 Size += strlen(Cache.StrP + I->String);
251 }
252 cout << "Total Globbed Strings: " << Count << " (" << SizeToStr(Size) << ')' << endl;
253
254 unsigned long Slack = 0;
255 for (int I = 0; I != 7; I++)
256 Slack += Cache.Head().Pools[I].ItemSize*Cache.Head().Pools[I].Count;
257 cout << "Total Slack space: " << SizeToStr(Slack) << endl;
258
259 unsigned long Total = 0;
260 Total = Slack + Size + Cache.Head().DependsCount*Cache.Head().DependencySz +
261 Cache.Head().VersionCount*Cache.Head().VersionSz +
262 Cache.Head().PackageCount*Cache.Head().PackageSz;
263 cout << "Total Space Accounted for: " << SizeToStr(Total) << endl;
264
265 return true;
266 }
267 /*}}}*/
268 // Check - Check some things about the cache /*{{{*/
269 // ---------------------------------------------------------------------
270 /* Debug aide mostly */
271 bool Check(CommandLine &Cmd)
272 {
273 pkgCache &Cache = *GCache;
274 pkgCache::PkgIterator Pkg = Cache.PkgBegin();
275 for (;Pkg.end() != true; Pkg++)
276 {
277 if (Pkg.Section() == 0 && Pkg->VersionList != 0)
278 cout << "Bad section " << Pkg.Name() << endl;
279
280 for (pkgCache::VerIterator Cur = Pkg.VersionList();
281 Cur.end() != true; Cur++)
282 {
283 if (Cur->Priority < 1 || Cur->Priority > 5)
284 cout << "Bad prio " << Pkg.Name() << ',' << Cur.VerStr() << " == " << (int)Cur->Priority << endl;
285 }
286 }
287 return true;
288 }
289 /*}}}*/
290 // Dump - show everything /*{{{*/
291 // ---------------------------------------------------------------------
292 /* */
293 bool Dump(CommandLine &Cmd)
294 {
295 pkgCache &Cache = *GCache;
296 for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; P++)
297 {
298 cout << "Package: " << P.Name() << endl;
299 for (pkgCache::VerIterator V = P.VersionList(); V.end() == false; V++)
300 {
301 cout << " Version: " << V.VerStr() << endl;
302 cout << " File: " << V.FileList().File().FileName() << endl;
303 for (pkgCache::DepIterator D = V.DependsList(); D.end() == false; D++)
304 cout << " Depends: " << D.TargetPkg().Name() << ' ' << D.TargetVer() << endl;
305 }
306 }
307
308 for (pkgCache::PkgFileIterator F(Cache); F.end() == false; F++)
309 {
310 cout << "File: " << F.FileName() << endl;
311 cout << " Size: " << F->Size << endl;
312 cout << " ID: " << F->ID << endl;
313 cout << " Flags: " << F->Flags << endl;
314 cout << " Time: " << TimeRFC1123(F->mtime) << endl;
315 cout << " Archive: " << F.Archive() << endl;
316 cout << " Component: " << F.Component() << endl;
317 cout << " Version: " << F.Version() << endl;
318 cout << " Origin: " << F.Origin() << endl;
319 cout << " Label: " << F.Label() << endl;
320 cout << " Architecture: " << F.Architecture() << endl;
321 }
322
323 return true;
324 }
325 /*}}}*/
326 // DumpAvail - Print out the available list /*{{{*/
327 // ---------------------------------------------------------------------
328 /* This is needed to make dpkg --merge happy */
329 bool DumpAvail(CommandLine &Cmd)
330 {
331 pkgCache &Cache = *GCache;
332 unsigned char *Buffer = new unsigned char[Cache.HeaderP->MaxVerFileSize];
333
334 for (pkgCache::PkgFileIterator I = Cache.FileBegin(); I.end() == false; I++)
335 {
336 if ((I->Flags & pkgCache::Flag::NotSource) != 0)
337 continue;
338
339 if (I.IsOk() == false)
340 {
341 delete [] Buffer;
342 return _error->Error("Package file %s is out of sync.",I.FileName());
343 }
344
345 FileFd PkgF(I.FileName(),FileFd::ReadOnly);
346 if (_error->PendingError() == true)
347 {
348 delete [] Buffer;
349 return false;
350 }
351
352 /* Write all of the records from this package file, we search the entire
353 structure to find them */
354 for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; P++)
355 {
356 for (pkgCache::VerIterator V = P.VersionList(); V.end() == false; V++)
357 {
358 if (V->FileList == 0)
359 continue;
360 if (V.FileList().File() != I)
361 continue;
362
363 // Read the record and then write it out again.
364 if (PkgF.Seek(V.FileList()->Offset) == false ||
365 PkgF.Read(Buffer,V.FileList()->Size) == false ||
366 write(STDOUT_FILENO,Buffer,V.FileList()->Size) != V.FileList()->Size)
367 {
368 delete [] Buffer;
369 return false;
370 }
371 }
372 }
373 }
374
375 return true;
376 }
377 /*}}}*/
378 // DoAdd - Perform an adding operation /*{{{*/
379 // ---------------------------------------------------------------------
380 /* */
381 bool DoAdd(CommandLine &CmdL)
382 {
383 // Make sure there is at least one argument
384 if (CmdL.FileSize() <= 1)
385 return _error->Error("You must give at least one file name");
386
387 // Open the cache
388 FileFd CacheF(_config->FindFile("Dir::Cache::pkgcache"),FileFd::WriteAny);
389 if (_error->PendingError() == true)
390 return false;
391
392 DynamicMMap Map(CacheF,MMap::Public);
393 if (_error->PendingError() == true)
394 return false;
395
396 OpTextProgress Progress(*_config);
397 pkgCacheGenerator Gen(Map,Progress);
398 if (_error->PendingError() == true)
399 return false;
400
401 unsigned long Length = CmdL.FileSize() - 1;
402 for (const char **I = CmdL.FileList + 1; *I != 0; I++)
403 {
404 Progress.OverallProgress(I - CmdL.FileList,Length,1,"Generating cache");
405 Progress.SubProgress(Length);
406
407 // Do the merge
408 FileFd TagF(*I,FileFd::ReadOnly);
409 debListParser Parser(TagF);
410 if (_error->PendingError() == true)
411 return _error->Error("Problem opening %s",*I);
412
413 if (Gen.SelectFile(*I) == false)
414 return _error->Error("Problem with SelectFile");
415
416 if (Gen.MergeList(Parser) == false)
417 return _error->Error("Problem with MergeList");
418 }
419
420 Progress.Done();
421 GCache = &Gen.GetCache();
422 Stats(CmdL);
423
424 return true;
425 }
426 /*}}}*/
427 // GenCaches - Call the main cache generator /*{{{*/
428 // ---------------------------------------------------------------------
429 /* */
430 bool GenCaches(CommandLine &Cmd)
431 {
432 OpTextProgress Progress(*_config);
433
434 pkgSourceList List;
435 List.ReadMainList();
436 return pkgMakeStatusCache(List,Progress);
437 }
438 /*}}}*/
439 // ShowHelp - Show a help screen /*{{{*/
440 // ---------------------------------------------------------------------
441 /* */
442 bool ShowHelp(CommandLine &Cmd)
443 {
444 cout << PACKAGE << ' ' << VERSION << " for " << ARCHITECTURE <<
445 " compiled on " << __DATE__ << " " << __TIME__ << endl;
446
447 cout << "Usage: apt-cache [options] command" << endl;
448 cout << " apt-cache [options] add file1 [file1 ...]" << endl;
449 cout << " apt-cache [options] showpkg pkg1 [pkg2 ...]" << endl;
450 cout << endl;
451 cout << "apt-cache is a low-level tool used to manipulate APT's binary" << endl;
452 cout << "cache files stored in " << _config->FindFile("Dir::Cache") << endl;
453 cout << "It is not ment for ordinary use only as a debug aide." << endl;
454 cout << endl;
455 cout << "Commands:" << endl;
456 cout << " add - Add an package file to the source cache" << endl;
457 cout << " gencaches - Build both the package and source cache" << endl;
458 cout << " showpkg - Show some general information for a single package" << endl;
459 cout << " stats - Show some basic statistics" << endl;
460 cout << " dump - Show the entire file in a terse form" << endl;
461 cout << " dumpavail - Print an available file to stdout" << endl;
462 cout << " unmet - Show unmet dependencies" << endl;
463 cout << " check - Check the cache a bit" << endl;
464 cout << endl;
465 cout << "Options:" << endl;
466 cout << " -h This help text." << endl;
467 cout << " -p=? The package cache. [" << _config->FindFile("Dir::Cache::pkgcache") << ']' << endl;
468 cout << " -s=? The source cache. [" << _config->FindFile("Dir::Cache::srcpkgcache") << ']' << endl;
469 cout << " -q Disable progress indicator." << endl;
470 cout << " -i Show only important deps for the unmet command." << endl;
471 cout << " -c=? Read this configuration file" << endl;
472 cout << " -o=? Set an arbitary configuration option, ie -o dir::cache=/tmp" << endl;
473 cout << "See the apt-cache(8) and apt.conf(8) manual pages for more information." << endl;
474 return 100;
475 }
476 /*}}}*/
477 // CacheInitialize - Initialize things for apt-cache /*{{{*/
478 // ---------------------------------------------------------------------
479 /* */
480 void CacheInitialize()
481 {
482 _config->Set("quiet",0);
483 _config->Set("help",false);
484 }
485 /*}}}*/
486
487 int main(int argc,const char *argv[])
488 {
489 CommandLine::Args Args[] = {
490 {'h',"help","help",0},
491 {'p',"pkg-cache","Dir::Cache::pkgcache",CommandLine::HasArg},
492 {'s',"src-cache","Dir::Cache::srcpkgcache",CommandLine::HasArg},
493 {'q',"quiet","quiet",CommandLine::IntLevel},
494 {'i',"important","APT::Cache::Important",0},
495 {'c',"config-file",0,CommandLine::ConfigFile},
496 {'o',"option",0,CommandLine::ArbItem},
497 {0,0,0,0}};
498 CommandLine::Dispatch CmdsA[] = {{"help",&ShowHelp},
499 {"add",&DoAdd},
500 {"gencaches",&GenCaches},
501 {0,0}};
502 CommandLine::Dispatch CmdsB[] = {{"showpkg",&DumpPackage},
503 {"stats",&Stats},
504 {"dump",&Dump},
505 {"dumpavail",&DumpAvail},
506 {"unmet",&UnMet},
507 {"check",&Check},
508 {0,0}};
509
510 CacheInitialize();
511
512 // Parse the command line and initialize the package library
513 CommandLine CmdL(Args,_config);
514 if (pkgInitialize(*_config) == false ||
515 CmdL.Parse(argc,argv) == false)
516 {
517 _error->DumpErrors();
518 return 100;
519 }
520
521 // See if the help should be shown
522 if (_config->FindB("help") == true ||
523 CmdL.FileSize() == 0)
524 return ShowHelp(CmdL);
525
526 if (CmdL.DispatchArg(CmdsA,false) == false && _error->PendingError() == false)
527 {
528 // Open the cache file
529 FileFd CacheF(_config->FindFile("Dir::Cache::pkgcache"),FileFd::ReadOnly);
530 MMap Map(CacheF,MMap::Public | MMap::ReadOnly);
531 if (_error->PendingError() == false)
532 {
533 pkgCache Cache(Map);
534 GCache = &Cache;
535 if (_error->PendingError() == false)
536 CmdL.DispatchArg(CmdsB);
537 }
538 }
539
540 // Print any errors or warnings found during parsing
541 if (_error->empty() == false)
542 {
543 bool Errors = _error->PendingError();
544 _error->DumpErrors();
545 return Errors == true?100:0;
546 }
547
548 return 0;
549 }