Added the remove command
[ntk/apt.git] / cmdline / apt-cache.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 // $Id: apt-cache.cc,v 1.10 1998/10/19 23:45:35 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 // DumpPackage - Show a dump of a package record /*{{{*/
31 // ---------------------------------------------------------------------
32 /* */
33 bool DumpPackage(pkgCache &Cache,CommandLine &CmdL)
34 {
35 for (const char **I = CmdL.FileList + 1; *I != 0; I++)
36 {
37 pkgCache::PkgIterator Pkg = Cache.FindPkg(*I);
38 if (Pkg.end() == true)
39 {
40 _error->Warning("Unable to locate package %s",*I);
41 continue;
42 }
43
44 cout << "Package: " << Pkg.Name() << endl;
45 cout << "Versions: ";
46 for (pkgCache::VerIterator Cur = Pkg.VersionList(); Cur.end() != true; Cur++)
47 cout << Cur.VerStr() << ',';
48 cout << endl;
49
50 cout << "Reverse Depends: " << endl;
51 for (pkgCache::DepIterator D = Pkg.RevDependsList(); D.end() != true; D++)
52 cout << " " << D.ParentPkg().Name() << ',' << D.TargetPkg().Name() << endl;
53
54 cout << "Dependencies: " << endl;
55 for (pkgCache::VerIterator Cur = Pkg.VersionList(); Cur.end() != true; Cur++)
56 {
57 cout << Cur.VerStr() << " - ";
58 for (pkgCache::DepIterator Dep = Cur.DependsList(); Dep.end() != true; Dep++)
59 cout << Dep.TargetPkg().Name() << " (" << (int)Dep->CompareOp << " " << Dep.TargetVer() << ") ";
60 cout << endl;
61 }
62
63 cout << "Provides: " << endl;
64 for (pkgCache::VerIterator Cur = Pkg.VersionList(); Cur.end() != true; Cur++)
65 {
66 cout << Cur.VerStr() << " - ";
67 for (pkgCache::PrvIterator Prv = Cur.ProvidesList(); Prv.end() != true; Prv++)
68 cout << Prv.ParentPkg().Name() << " ";
69 cout << endl;
70 }
71 cout << "Reverse Provides: " << endl;
72 for (pkgCache::PrvIterator Prv = Pkg.ProvidesList(); Prv.end() != true; Prv++)
73 cout << Prv.OwnerPkg().Name() << " " << Prv.OwnerVer().VerStr();
74 cout << endl;
75 }
76
77 return true;
78 }
79 /*}}}*/
80 // Stats - Dump some nice statistics /*{{{*/
81 // ---------------------------------------------------------------------
82 /* */
83 bool Stats(pkgCache &Cache)
84 {
85 cout << "Total Package Names : " << Cache.Head().PackageCount << endl;
86 pkgCache::PkgIterator I = Cache.PkgBegin();
87
88 int Normal = 0;
89 int Virtual = 0;
90 int NVirt = 0;
91 int DVirt = 0;
92 int Missing = 0;
93 for (;I.end() != true; I++)
94 {
95 if (I->VersionList != 0 && I->ProvidesList == 0)
96 {
97 Normal++;
98 continue;
99 }
100
101 if (I->VersionList != 0 && I->ProvidesList != 0)
102 {
103 NVirt++;
104 continue;
105 }
106
107 if (I->VersionList == 0 && I->ProvidesList != 0)
108 {
109 // Only 1 provides
110 if (I.ProvidesList()->NextProvides == 0)
111 {
112 DVirt++;
113 }
114 else
115 Virtual++;
116 continue;
117 }
118 if (I->VersionList == 0 && I->ProvidesList == 0)
119 {
120 Missing++;
121 continue;
122 }
123 }
124 cout << " Normal Packages: " << Normal << endl;
125 cout << " Pure Virtual Packages: " << Virtual << endl;
126 cout << " Single Virtual Packages: " << DVirt << endl;
127 cout << " Mixed Virtual Packages: " << NVirt << endl;
128 cout << " Missing: " << Missing << endl;
129
130 cout << "Total Distinct Versions: " << Cache.Head().VersionCount << endl;
131 cout << "Total Dependencies: " << Cache.Head().DependsCount << endl;
132 return true;
133 }
134 /*}}}*/
135 // Dump - show everything /*{{{*/
136 // ---------------------------------------------------------------------
137 /* */
138 bool Dump(pkgCache &Cache)
139 {
140 for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; P++)
141 {
142 cout << "Package: " << P.Name() << endl;
143 for (pkgCache::VerIterator V = P.VersionList(); V.end() == false; V++)
144 {
145 cout << " Version: " << V.VerStr() << endl;
146 cout << " File: " << V.FileList().File().FileName() << endl;
147 for (pkgCache::DepIterator D = V.DependsList(); D.end() == false; D++)
148 cout << " Depends: " << D.TargetPkg().Name() << ' ' << D.TargetVer() << endl;
149 }
150 }
151
152 for (pkgCache::PkgFileIterator F(Cache); F.end() == false; F++)
153 {
154 cout << "File: " << F.FileName() << endl;
155 cout << " Size: " << F->Size << endl;
156 cout << " ID: " << F->ID << endl;
157 cout << " Flags: " << F->Flags << endl;
158 cout << " Time: " << ctime(&F->mtime) << endl;
159 }
160
161 return true;
162 }
163 /*}}}*/
164 // DumpAvail - Print out the available list /*{{{*/
165 // ---------------------------------------------------------------------
166 /* This is needed to make dpkg --merge happy */
167 bool DumpAvail(pkgCache &Cache)
168 {
169 unsigned char *Buffer = new unsigned char[Cache.HeaderP->MaxVerFileSize];
170
171 for (pkgCache::PkgFileIterator I = Cache.FileBegin(); I.end() == false; I++)
172 {
173 if ((I->Flags & pkgCache::Flag::NotSource) != 0)
174 continue;
175
176 if (I.IsOk() == false)
177 {
178 delete [] Buffer;
179 return _error->Error("Package file %s is out of sync.",I.FileName());
180 }
181
182 FileFd PkgF(I.FileName(),FileFd::ReadOnly);
183 if (_error->PendingError() == true)
184 {
185 delete [] Buffer;
186 return false;
187 }
188
189 /* Write all of the records from this package file, we search the entire
190 structure to find them */
191 for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; P++)
192 {
193 for (pkgCache::VerIterator V = P.VersionList(); V.end() == false; V++)
194 {
195 if (V->FileList == 0)
196 continue;
197 if (V.FileList().File() != I)
198 continue;
199
200 // Read the record and then write it out again.
201 if (PkgF.Seek(V.FileList()->Offset) == false ||
202 PkgF.Read(Buffer,V.FileList()->Size) == false ||
203 write(STDOUT_FILENO,Buffer,V.FileList()->Size) != V.FileList()->Size)
204 {
205 delete [] Buffer;
206 return false;
207 }
208 }
209 }
210 }
211
212 return true;
213 }
214 /*}}}*/
215 // DoAdd - Perform an adding operation /*{{{*/
216 // ---------------------------------------------------------------------
217 /* */
218 bool DoAdd(CommandLine &CmdL)
219 {
220 // Make sure there is at least one argument
221 if (CmdL.FileSize() <= 1)
222 return _error->Error("You must give at least one file name");
223
224 // Open the cache
225 FileFd CacheF(_config->FindFile("Dir::Cache::srcpkgcache"),FileFd::WriteAny);
226 if (_error->PendingError() == true)
227 return false;
228
229 DynamicMMap Map(CacheF,MMap::Public);
230 if (_error->PendingError() == true)
231 return false;
232
233 OpTextProgress Progress(*_config);
234 pkgCacheGenerator Gen(Map,Progress);
235 if (_error->PendingError() == true)
236 return false;
237
238 unsigned long Length = CmdL.FileSize() - 1;
239 for (const char **I = CmdL.FileList + 1; *I != 0; I++)
240 {
241 Progress.OverallProgress(I - CmdL.FileList,Length,1,"Generating cache");
242
243 // Do the merge
244 FileFd TagF(*I,FileFd::ReadOnly);
245 debListParser Parser(TagF);
246 if (_error->PendingError() == true)
247 return _error->Error("Problem opening %s",*I);
248
249 if (Gen.SelectFile(*I) == false)
250 return _error->Error("Problem with SelectFile");
251
252 if (Gen.MergeList(Parser) == false)
253 return _error->Error("Problem with MergeList");
254 }
255
256 Progress.Done();
257 Stats(Gen.GetCache());
258
259 return true;
260 }
261 /*}}}*/
262 // GenCaches - Call the main cache generator /*{{{*/
263 // ---------------------------------------------------------------------
264 /* */
265 bool GenCaches()
266 {
267 OpTextProgress Progress(*_config);
268
269 pkgSourceList List;
270 List.ReadMainList();
271 return pkgMakeStatusCache(List,Progress);
272 }
273 /*}}}*/
274 // ShowHelp - Show a help screen /*{{{*/
275 // ---------------------------------------------------------------------
276 /* */
277 int ShowHelp()
278 {
279 cout << PACKAGE << ' ' << VERSION << " for " << ARCHITECTURE <<
280 " compiled on " << __DATE__ << " " << __TIME__ << endl;
281
282 cout << "Usage: apt-cache [options] command" << endl;
283 cout << " apt-cache [options] add file1 [file1 ...]" << endl;
284 cout << " apt-cache [options] showpkg pkg1 [pkg2 ...]" << endl;
285 cout << endl;
286 cout << "apt-cache is a low-level tool used to manipulate APT's binary" << endl;
287 cout << "cache files stored in " << _config->FindFile("Dir::Cache") << endl;
288 cout << "It is not ment for ordinary use only as a debug aide." << endl;
289 cout << endl;
290 cout << "Commands:" << endl;
291 cout << " add - Add an package file to the source cache" << endl;
292 cout << " gencaches - Build both the package and source cache" << endl;
293 cout << " showpkg - Show some general information for a single package" << endl;
294 cout << " stats - Show some basic statistics" << endl;
295 cout << " dump - Show the entire file in a terse form" << endl;
296 cout << " dumpavail - Print an available file to stdout" << endl;
297 cout << endl;
298 cout << "Options:" << endl;
299 cout << " -h This help text." << endl;
300 cout << " -p=? The package cache. [" << _config->FindFile("Dir::Cache::pkgcache") << ']' << endl;
301 cout << " -s=? The source cache. [" << _config->FindFile("Dir::Cache::srcpkgcache") << ']' << endl;
302 cout << " -q Disable progress indicator. " << endl;
303 cout << " -c=? Read this configuration file" << endl;
304 cout << " -o=? Set an arbitary configuration option, ie -o dir::cache=/tmp" << endl;
305 cout << "See the apt-cache(8) and apt.conf(8) manual pages for more information." << endl;
306 return 100;
307 }
308 /*}}}*/
309 // CacheInitialize - Initialize things for apt-cache /*{{{*/
310 // ---------------------------------------------------------------------
311 /* */
312 void CacheInitialize()
313 {
314 _config->Set("quiet",0);
315 _config->Set("help",false);
316 }
317 /*}}}*/
318
319 int main(int argc,const char *argv[])
320 {
321 CommandLine::Args Args[] = {
322 {'h',"help","help",0},
323 {'p',"pkg-cache","Dir::Cache::pkgcache",CommandLine::HasArg},
324 {'s',"src-cache","Dir::Cache::srcpkgcache",CommandLine::HasArg},
325 {'q',"quiet","quiet",CommandLine::IntLevel},
326 {'c',"config-file",0,CommandLine::ConfigFile},
327 {'o',"option",0,CommandLine::ArbItem},
328 {0,0,0,0}};
329
330 CacheInitialize();
331
332 // Parse the command line and initialize the package library
333 CommandLine CmdL(Args,_config);
334 if (pkgInitialize(*_config) == false ||
335 CmdL.Parse(argc,argv) == false)
336 {
337 _error->DumpErrors();
338 return 100;
339 }
340
341 // See if the help should be shown
342 if (_config->FindB("help") == true ||
343 CmdL.FileSize() == 0)
344 return ShowHelp();
345
346 while (1)
347 {
348 if (strcmp(CmdL.FileList[0],"add") == 0)
349 {
350 DoAdd(CmdL);
351 break;
352 }
353
354 if (strcmp(CmdL.FileList[0],"gencaches") == 0)
355 {
356 GenCaches();
357 break;
358 }
359
360 // Open the cache file
361 FileFd CacheF(_config->FindFile("Dir::Cache::pkgcache"),FileFd::ReadOnly);
362 if (_error->PendingError() == true)
363 break;
364
365 MMap Map(CacheF,MMap::Public | MMap::ReadOnly);
366 if (_error->PendingError() == true)
367 break;
368
369 pkgCache Cache(Map);
370 if (_error->PendingError() == true)
371 break;
372
373 if (strcmp(CmdL.FileList[0],"showpkg") == 0)
374 {
375 DumpPackage(Cache,CmdL);
376 break;
377 }
378
379 if (strcmp(CmdL.FileList[0],"stats") == 0)
380 {
381 Stats(Cache);
382 break;
383 }
384
385 if (strcmp(CmdL.FileList[0],"dump") == 0)
386 {
387 Dump(Cache);
388 break;
389 }
390
391 if (strcmp(CmdL.FileList[0],"dumpavail") == 0)
392 {
393 DumpAvail(Cache);
394 break;
395 }
396
397 _error->Error("Invalid operation %s", CmdL.FileList[0]);
398 break;
399 }
400
401 // Print any errors or warnings found during parsing
402 if (_error->empty() == false)
403 {
404 bool Errors = _error->PendingError();
405 _error->DumpErrors();
406 return Errors == true?100:0;
407 }
408
409 return 0;
410 }