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