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