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