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