More bugs fixes
[ntk/apt.git] / cmdline / apt-cache.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 // $Id: apt-cache.cc,v 1.17 1998/12/10 04:22:48 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 << " -c=? Read this configuration file" << endl;
456 cout << " -o=? Set an arbitary configuration option, ie -o dir::cache=/tmp" << endl;
457 cout << "See the apt-cache(8) and apt.conf(8) manual pages for more information." << endl;
458 return 100;
459 }
460 /*}}}*/
461 // CacheInitialize - Initialize things for apt-cache /*{{{*/
462 // ---------------------------------------------------------------------
463 /* */
464 void CacheInitialize()
465 {
466 _config->Set("quiet",0);
467 _config->Set("help",false);
468 }
469 /*}}}*/
470
471 int main(int argc,const char *argv[])
472 {
473 CommandLine::Args Args[] = {
474 {'h',"help","help",0},
475 {'p',"pkg-cache","Dir::Cache::pkgcache",CommandLine::HasArg},
476 {'s',"src-cache","Dir::Cache::srcpkgcache",CommandLine::HasArg},
477 {'q',"quiet","quiet",CommandLine::IntLevel},
478 {'i',"important","APT::Cache::Important",0},
479 {'c',"config-file",0,CommandLine::ConfigFile},
480 {'o',"option",0,CommandLine::ArbItem},
481 {0,0,0,0}};
482
483 CacheInitialize();
484
485 // Parse the command line and initialize the package library
486 CommandLine CmdL(Args,_config);
487 if (pkgInitialize(*_config) == false ||
488 CmdL.Parse(argc,argv) == false)
489 {
490 _error->DumpErrors();
491 return 100;
492 }
493
494 // See if the help should be shown
495 if (_config->FindB("help") == true ||
496 CmdL.FileSize() == 0)
497 return ShowHelp();
498
499 while (1)
500 {
501 if (strcmp(CmdL.FileList[0],"add") == 0)
502 {
503 ShowHelp();
504 break;
505 }
506
507 if (strcmp(CmdL.FileList[0],"add") == 0)
508 {
509 DoAdd(CmdL);
510 break;
511 }
512
513 if (strcmp(CmdL.FileList[0],"gencaches") == 0)
514 {
515 GenCaches();
516 break;
517 }
518
519 // Open the cache file
520 FileFd CacheF(_config->FindFile("Dir::Cache::pkgcache"),FileFd::ReadOnly);
521 if (_error->PendingError() == true)
522 break;
523
524 MMap Map(CacheF,MMap::Public | MMap::ReadOnly);
525 if (_error->PendingError() == true)
526 break;
527
528 pkgCache Cache(Map);
529 if (_error->PendingError() == true)
530 break;
531
532 if (strcmp(CmdL.FileList[0],"showpkg") == 0)
533 {
534 DumpPackage(Cache,CmdL);
535 break;
536 }
537
538 if (strcmp(CmdL.FileList[0],"stats") == 0)
539 {
540 Stats(Cache);
541 break;
542 }
543
544 if (strcmp(CmdL.FileList[0],"dump") == 0)
545 {
546 Dump(Cache);
547 break;
548 }
549
550 if (strcmp(CmdL.FileList[0],"dumpavail") == 0)
551 {
552 DumpAvail(Cache);
553 break;
554 }
555
556 if (strcmp(CmdL.FileList[0],"unmet") == 0)
557 {
558 UnMet(Cache);
559 break;
560 }
561
562 if (strcmp(CmdL.FileList[0],"check") == 0)
563 {
564 Check(Cache);
565 break;
566 }
567
568 _error->Error("Invalid operation %s", CmdL.FileList[0]);
569 break;
570 }
571
572 // Print any errors or warnings found during parsing
573 if (_error->empty() == false)
574 {
575 bool Errors = _error->PendingError();
576 _error->DumpErrors();
577 return Errors == true?100:0;
578 }
579
580 return 0;
581 }