]>
Commit | Line | Data |
---|---|---|
1164783d AL |
1 | // -*- mode: cpp; mode: fold -*- |
2 | // Description /*{{{*/ | |
880e9be4 | 3 | // $Id: apt-cache.cc,v 1.6 1998/07/26 23:11:56 jgg Exp $ |
1164783d AL |
4 | /* ###################################################################### |
5 | ||
6 | apt-cache - Manages the cache file. | |
7 | ||
8 | This program should eventually handle both low and high level | |
9 | manipulation of the cache file. Depending how far things go it | |
10 | might get quite a sophisticated UI. | |
11 | ||
12 | Currently the command line is as follows: | |
13 | apt-cache add cache file1:dist:ver file2:dist:ver ... | |
14 | ie: | |
15 | apt-cache add ./cache Pacakges:hamm:1.0 | |
16 | ||
17 | A usefull feature is 'upgradable' ie | |
18 | apt-cache upgradable ./cache | |
19 | will list .debs that should be installed to make all packages the latest | |
20 | version. | |
21 | ||
22 | Returns 100 on failure, 0 on success. | |
23 | ||
24 | ##################################################################### */ | |
25 | /*}}}*/ | |
26 | // Include Files /*{{{*/ | |
27 | #include <apt-pkg/error.h> | |
28 | #include <apt-pkg/pkgcachegen.h> | |
29 | #include <apt-pkg/deblistparser.h> | |
8efa2a3b | 30 | #include <apt-pkg/init.h> |
404ec98e | 31 | #include <apt-pkg/progress.h> |
880e9be4 | 32 | #include <apt-pkg/sourcelist.h> |
1164783d AL |
33 | |
34 | #include <iostream.h> | |
35 | #include <fstream.h> | |
36 | ||
37 | /*}}}*/ | |
38 | ||
39 | string CacheFile; | |
40 | ||
41 | // SplitArg - Split the triple /*{{{*/ | |
42 | // --------------------------------------------------------------------- | |
43 | /* */ | |
44 | bool SplitArg(const char *Arg,string &File,string &Dist,string Ver) | |
45 | { | |
46 | const char *Start = Arg; | |
47 | const char *I = Arg; | |
48 | for (;*I != 0 && *I != ':'; I++); | |
49 | if (*I != ':') | |
50 | return _error->Error("Malformed argument %s, must be in file:dist:rev form",Arg); | |
51 | File = string(Start,I - Start); | |
52 | ||
53 | I++; | |
54 | Start = I; | |
55 | for (;*I != 0 && *I != ':'; I++); | |
56 | if (*I != ':') | |
57 | return _error->Error("Malformed argument %s, must be in file:dist:rev form",Arg); | |
58 | Dist = string(Start,I - Start); | |
59 | ||
60 | I++; | |
61 | Start = I; | |
62 | for (;*I != 0 && *I != ':'; I++); | |
63 | if (I == Start) | |
64 | return _error->Error("Malformed argument %s, must be in file:dist:rev form",Arg); | |
65 | Ver = string(Start,I - Start); | |
66 | ||
1164783d AL |
67 | return true; |
68 | } | |
69 | /*}}}*/ | |
70 | // DumpPackage - Show a dump of a package record /*{{{*/ | |
71 | // --------------------------------------------------------------------- | |
72 | /* */ | |
ad00ae81 AL |
73 | bool DumpPackage(pkgCache &Cache,int argc,char *argv[]) |
74 | { | |
1164783d AL |
75 | for (int I = 0; I != argc; I++) |
76 | { | |
77 | pkgCache::PkgIterator Pkg = Cache.FindPkg(argv[I]); | |
78 | if (Pkg.end() == true) | |
79 | { | |
80 | _error->Warning("Unable to locate package %s",argv[0]); | |
81 | continue; | |
82 | } | |
83 | ||
84 | cout << "Package: " << Pkg.Name() << endl; | |
85 | cout << "Versions: "; | |
86 | for (pkgCache::VerIterator Cur = Pkg.VersionList(); Cur.end() != true; Cur++) | |
87 | cout << Cur.VerStr() << ','; | |
88 | cout << endl; | |
89 | ||
90 | cout << "Reverse Depends: " << endl; | |
91 | for (pkgCache::DepIterator D = Pkg.RevDependsList(); D.end() != true; D++) | |
92 | cout << " " << D.ParentPkg().Name() << ',' << D.TargetPkg().Name() << endl; | |
93 | ||
94 | cout << "Dependencies: " << endl; | |
95 | for (pkgCache::VerIterator Cur = Pkg.VersionList(); Cur.end() != true; Cur++) | |
96 | { | |
97 | cout << Cur.VerStr() << " - "; | |
98 | for (pkgCache::DepIterator Dep = Cur.DependsList(); Dep.end() != true; Dep++) | |
99 | cout << Dep.TargetPkg().Name() << " (" << (int)Dep->CompareOp << " " << Dep.TargetVer() << ") "; | |
100 | cout << endl; | |
101 | } | |
102 | ||
103 | cout << "Provides: " << endl; | |
104 | for (pkgCache::VerIterator Cur = Pkg.VersionList(); Cur.end() != true; Cur++) | |
105 | { | |
106 | cout << Cur.VerStr() << " - "; | |
107 | for (pkgCache::PrvIterator Prv = Cur.ProvidesList(); Prv.end() != true; Prv++) | |
108 | cout << Prv.ParentPkg().Name() << " "; | |
109 | cout << endl; | |
8efa2a3b AL |
110 | } |
111 | cout << "Reverse Provides: " << endl; | |
112 | for (pkgCache::PrvIterator Prv = Pkg.ProvidesList(); Prv.end() != true; Prv++) | |
113 | cout << Prv.OwnerPkg().Name() << " " << Prv.OwnerVer().VerStr(); | |
114 | cout << endl; | |
1164783d AL |
115 | } |
116 | ||
117 | return true; | |
118 | } | |
119 | /*}}}*/ | |
120 | // Stats - Dump some nice statistics /*{{{*/ | |
121 | // --------------------------------------------------------------------- | |
122 | /* */ | |
ad00ae81 | 123 | bool Stats(pkgCache &Cache) |
1164783d | 124 | { |
1164783d AL |
125 | cout << "Total Package Names : " << Cache.Head().PackageCount << endl; |
126 | pkgCache::PkgIterator I = Cache.PkgBegin(); | |
127 | ||
128 | int Normal = 0; | |
129 | int Virtual = 0; | |
130 | int NVirt = 0; | |
131 | int DVirt = 0; | |
132 | int Missing = 0; | |
133 | for (;I.end() != true; I++) | |
134 | { | |
135 | if (I->VersionList != 0 && I->ProvidesList == 0) | |
136 | { | |
137 | Normal++; | |
138 | continue; | |
139 | } | |
140 | ||
141 | if (I->VersionList != 0 && I->ProvidesList != 0) | |
142 | { | |
143 | NVirt++; | |
144 | continue; | |
145 | } | |
146 | ||
147 | if (I->VersionList == 0 && I->ProvidesList != 0) | |
148 | { | |
149 | // Only 1 provides | |
150 | if (I.ProvidesList()->NextProvides == 0) | |
151 | { | |
152 | DVirt++; | |
153 | } | |
154 | else | |
155 | Virtual++; | |
156 | continue; | |
157 | } | |
158 | if (I->VersionList == 0 && I->ProvidesList == 0) | |
159 | { | |
160 | Missing++; | |
161 | continue; | |
162 | } | |
163 | } | |
164 | cout << " Normal Packages: " << Normal << endl; | |
165 | cout << " Pure Virtual Packages: " << Virtual << endl; | |
166 | cout << " Single Virtual Packages: " << DVirt << endl; | |
167 | cout << " Mixed Virtual Packages: " << NVirt << endl; | |
168 | cout << " Missing: " << Missing << endl; | |
169 | ||
170 | cout << "Total Distinct Versions: " << Cache.Head().VersionCount << endl; | |
171 | cout << "Total Dependencies: " << Cache.Head().DependsCount << endl; | |
172 | return true; | |
173 | } | |
174 | /*}}}*/ | |
175 | // Dump - show everything /*{{{*/ | |
176 | // --------------------------------------------------------------------- | |
177 | /* */ | |
ad00ae81 | 178 | bool Dump(pkgCache &Cache) |
1164783d | 179 | { |
1164783d AL |
180 | for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; P++) |
181 | { | |
182 | cout << "Package: " << P.Name() << endl; | |
183 | for (pkgCache::VerIterator V = P.VersionList(); V.end() == false; V++) | |
184 | { | |
185 | cout << " Version: " << V.VerStr() << endl; | |
186 | cout << " File: " << V.FileList().File().FileName() << endl; | |
187 | for (pkgCache::DepIterator D = V.DependsList(); D.end() == false; D++) | |
188 | cout << " Depends: " << D.TargetPkg().Name() << ' ' << D.TargetVer() << endl; | |
189 | } | |
190 | } | |
191 | ||
192 | for (pkgCache::PkgFileIterator F(Cache); F.end() == false; F++) | |
193 | { | |
194 | cout << "File: " << F.FileName() << endl; | |
195 | cout << " Size: " << F->Size << endl; | |
196 | cout << " ID: " << F->ID << endl; | |
197 | cout << " Flags: " << F->Flags << endl; | |
198 | cout << " Time: " << ctime(&F->mtime) << endl; | |
199 | } | |
200 | ||
201 | return true; | |
202 | } | |
203 | /*}}}*/ | |
204 | // DumpAvail - Print out the available list /*{{{*/ | |
205 | // --------------------------------------------------------------------- | |
206 | /* This is needed to make dpkg --merge happy */ | |
ad00ae81 | 207 | bool DumpAvail(pkgCache &Cache) |
1164783d | 208 | { |
ad00ae81 | 209 | unsigned char *Buffer = new unsigned char[Cache.HeaderP->MaxVerFileSize]; |
1164783d | 210 | |
ad00ae81 | 211 | for (pkgCache::PkgFileIterator I = Cache.FileBegin(); I.end() == false; I++) |
1164783d | 212 | { |
ad00ae81 | 213 | if ((I->Flags & pkgCache::Flag::NotSource) != 0) |
1164783d AL |
214 | continue; |
215 | ||
ad00ae81 AL |
216 | if (I.IsOk() == false) |
217 | { | |
218 | delete [] Buffer; | |
219 | return _error->Error("Package file %s is out of sync.",I.FileName()); | |
220 | } | |
1164783d | 221 | |
8e06abb2 | 222 | FileFd PkgF(I.FileName(),FileFd::ReadOnly); |
ad00ae81 | 223 | if (_error->PendingError() == true) |
1164783d | 224 | { |
ad00ae81 AL |
225 | delete [] Buffer; |
226 | return false; | |
227 | } | |
228 | ||
229 | /* Write all of the records from this package file, we search the entire | |
230 | structure to find them */ | |
231 | for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; P++) | |
232 | { | |
233 | for (pkgCache::VerIterator V = P.VersionList(); V.end() == false; V++) | |
1164783d | 234 | { |
ad00ae81 AL |
235 | if (V->FileList == 0) |
236 | continue; | |
237 | if (V.FileList().File() != I) | |
238 | continue; | |
239 | ||
240 | // Read the record and then write it out again. | |
241 | if (PkgF.Seek(V.FileList()->Offset) == false || | |
242 | PkgF.Read(Buffer,V.FileList()->Size) == false || | |
243 | write(STDOUT_FILENO,Buffer,V.FileList()->Size) != V.FileList()->Size) | |
244 | { | |
245 | delete [] Buffer; | |
246 | return false; | |
247 | } | |
1164783d | 248 | } |
1164783d | 249 | } |
ad00ae81 AL |
250 | } |
251 | ||
252 | return true; | |
253 | } | |
254 | /*}}}*/ | |
255 | // DoAdd - Perform an adding operation /*{{{*/ | |
256 | // --------------------------------------------------------------------- | |
257 | /* */ | |
258 | bool DoAdd(int argc,char *argv[]) | |
259 | { | |
260 | string FileName; | |
261 | string Dist; | |
262 | string Ver; | |
263 | ||
264 | // Open the cache | |
8e06abb2 | 265 | FileFd CacheF(CacheFile,FileFd::WriteEmpty); |
ad00ae81 AL |
266 | if (_error->PendingError() == true) |
267 | return false; | |
268 | ||
269 | DynamicMMap Map(CacheF,MMap::Public); | |
270 | if (_error->PendingError() == true) | |
271 | return false; | |
404ec98e AL |
272 | |
273 | OpTextProgress Progress; | |
274 | pkgCacheGenerator Gen(Map,Progress); | |
ad00ae81 AL |
275 | if (_error->PendingError() == true) |
276 | return false; | |
277 | ||
278 | for (int I = 0; I != argc; I++) | |
279 | { | |
404ec98e | 280 | Progress.OverallProgress(I,argc,1,"Generating cache"); |
ad00ae81 AL |
281 | if (SplitArg(argv[I],FileName,Dist,Ver) == false) |
282 | return false; | |
1164783d | 283 | |
ad00ae81 | 284 | // Do the merge |
8e06abb2 | 285 | FileFd TagF(FileName.c_str(),FileFd::ReadOnly); |
ad00ae81 AL |
286 | debListParser Parser(TagF); |
287 | if (_error->PendingError() == true) | |
288 | return _error->Error("Problem opening %s",FileName.c_str()); | |
289 | ||
290 | if (Gen.SelectFile(FileName) == false) | |
291 | return _error->Error("Problem with SelectFile"); | |
292 | ||
293 | if (Gen.MergeList(Parser) == false) | |
294 | return _error->Error("Problem with MergeList"); | |
1164783d | 295 | } |
404ec98e AL |
296 | |
297 | Progress.Done(); | |
ad00ae81 AL |
298 | Stats(Gen.GetCache()); |
299 | ||
1164783d AL |
300 | return true; |
301 | } | |
302 | /*}}}*/ | |
880e9be4 AL |
303 | // GenCaches - Call the main cache generator /*{{{*/ |
304 | // --------------------------------------------------------------------- | |
305 | /* */ | |
306 | bool GenCaches() | |
307 | { | |
308 | OpTextProgress Progress; | |
309 | pkgSourceList List; | |
310 | List.ReadMainList(); | |
311 | return pkgMakeStatusCache(List,Progress); | |
312 | } | |
313 | /*}}}*/ | |
1164783d AL |
314 | |
315 | int main(int argc, char *argv[]) | |
316 | { | |
317 | // Check arguments. | |
318 | if (argc < 3) | |
319 | { | |
320 | cerr << "Usage is apt-cache add cache file1:dist:ver file2:dist:ver ..." << endl; | |
321 | return 100; | |
322 | } | |
8efa2a3b AL |
323 | |
324 | pkgInitialize(*_config); | |
1164783d AL |
325 | while (1) |
326 | { | |
ad00ae81 | 327 | CacheFile = argv[2]; |
1164783d AL |
328 | if (strcmp(argv[1],"add") == 0) |
329 | { | |
ad00ae81 | 330 | DoAdd(argc - 3,argv + 3); |
1164783d AL |
331 | break; |
332 | } | |
ad00ae81 | 333 | |
880e9be4 AL |
334 | if (strcmp(argv[1],"gencaches") == 0) |
335 | { | |
336 | GenCaches(); | |
337 | break; | |
338 | } | |
339 | ||
ad00ae81 | 340 | // Open the cache file |
8e06abb2 | 341 | FileFd CacheF(CacheFile,FileFd::ReadOnly); |
ad00ae81 AL |
342 | if (_error->PendingError() == true) |
343 | break; | |
344 | ||
345 | MMap Map(CacheF,MMap::Public | MMap::ReadOnly); | |
346 | if (_error->PendingError() == true) | |
347 | break; | |
348 | ||
349 | pkgCache Cache(Map); | |
350 | if (_error->PendingError() == true) | |
351 | break; | |
1164783d AL |
352 | |
353 | if (strcmp(argv[1],"showpkg") == 0) | |
354 | { | |
355 | CacheFile = argv[2]; | |
ad00ae81 | 356 | DumpPackage(Cache,argc - 3,argv + 3); |
1164783d AL |
357 | break; |
358 | } | |
359 | ||
360 | if (strcmp(argv[1],"stats") == 0) | |
361 | { | |
ad00ae81 | 362 | Stats(Cache); |
1164783d AL |
363 | break; |
364 | } | |
365 | ||
366 | if (strcmp(argv[1],"dump") == 0) | |
367 | { | |
ad00ae81 | 368 | Dump(Cache); |
1164783d AL |
369 | break; |
370 | } | |
371 | ||
372 | if (strcmp(argv[1],"dumpavail") == 0) | |
373 | { | |
ad00ae81 | 374 | DumpAvail(Cache); |
1164783d AL |
375 | break; |
376 | } | |
880e9be4 | 377 | |
1164783d AL |
378 | _error->Error("Invalid operation %s", argv[1]); |
379 | break; | |
380 | } | |
381 | ||
382 | // Print any errors or warnings found during parsing | |
383 | if (_error->empty() == false) | |
384 | { | |
385 | _error->DumpErrors(); | |
386 | return 100; | |
387 | } | |
388 | ||
389 | return 0; | |
390 | } |