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