]> git.saurik.com Git - apt.git/blob - cmdline/apt-cache.cc
95f185b4fb825f971bbea1810a42c0fe3aa17e49
[apt.git] / cmdline / apt-cache.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 // $Id: apt-cache.cc,v 1.72 2004/04/30 04:34:03 mdz 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.
10
11 Returns 100 on failure, 0 on success.
12
13 ##################################################################### */
14 /*}}}*/
15 // Include Files /*{{{*/
16 #include <apt-pkg/error.h>
17 #include <cassert>
18 #include <apt-pkg/pkgcachegen.h>
19 #include <apt-pkg/cachefile.h>
20 #include <apt-pkg/init.h>
21 #include <apt-pkg/progress.h>
22 #include <apt-pkg/sourcelist.h>
23 #include <apt-pkg/cmndline.h>
24 #include <apt-pkg/strutl.h>
25 #include <apt-pkg/pkgrecords.h>
26 #include <apt-pkg/srcrecords.h>
27 #include <apt-pkg/version.h>
28 #include <apt-pkg/policy.h>
29 #include <apt-pkg/tagfile.h>
30 #include <apt-pkg/algorithms.h>
31 #include <apt-pkg/sptr.h>
32 #include <apt-pkg/packageset.h>
33
34 #include <config.h>
35 #include <apti18n.h>
36
37 #include <locale.h>
38 #include <iostream>
39 #include <unistd.h>
40 #include <errno.h>
41 #include <regex.h>
42 #include <stdio.h>
43
44 #include <iomanip>
45 /*}}}*/
46
47 using namespace std;
48
49 pkgCache *GCache = 0;
50 pkgSourceList *SrcList = 0;
51
52 // LocalitySort - Sort a version list by package file locality /*{{{*/
53 // ---------------------------------------------------------------------
54 /* */
55 int LocalityCompare(const void *a, const void *b)
56 {
57 pkgCache::VerFile *A = *(pkgCache::VerFile **)a;
58 pkgCache::VerFile *B = *(pkgCache::VerFile **)b;
59
60 if (A == 0 && B == 0)
61 return 0;
62 if (A == 0)
63 return 1;
64 if (B == 0)
65 return -1;
66
67 if (A->File == B->File)
68 return A->Offset - B->Offset;
69 return A->File - B->File;
70 }
71
72 void LocalitySort(pkgCache::VerFile **begin,
73 unsigned long Count,size_t Size)
74 {
75 qsort(begin,Count,Size,LocalityCompare);
76 }
77
78 void LocalitySort(pkgCache::DescFile **begin,
79 unsigned long Count,size_t Size)
80 {
81 qsort(begin,Count,Size,LocalityCompare);
82 }
83 /*}}}*/
84 // UnMet - Show unmet dependencies /*{{{*/
85 // ---------------------------------------------------------------------
86 /* */
87 bool UnMet(CommandLine &CmdL)
88 {
89 pkgCache &Cache = *GCache;
90 bool Important = _config->FindB("APT::Cache::Important",false);
91
92 for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; P++)
93 {
94 for (pkgCache::VerIterator V = P.VersionList(); V.end() == false; V++)
95 {
96 bool Header = false;
97 for (pkgCache::DepIterator D = V.DependsList(); D.end() == false;)
98 {
99 // Collect or groups
100 pkgCache::DepIterator Start;
101 pkgCache::DepIterator End;
102 D.GlobOr(Start,End);
103
104 // Skip conflicts and replaces
105 if (End->Type != pkgCache::Dep::PreDepends &&
106 End->Type != pkgCache::Dep::Depends &&
107 End->Type != pkgCache::Dep::Suggests &&
108 End->Type != pkgCache::Dep::Recommends)
109 continue;
110
111 // Important deps only
112 if (Important == true)
113 if (End->Type != pkgCache::Dep::PreDepends &&
114 End->Type != pkgCache::Dep::Depends)
115 continue;
116
117 // Verify the or group
118 bool OK = false;
119 pkgCache::DepIterator RealStart = Start;
120 do
121 {
122 // See if this dep is Ok
123 pkgCache::Version **VList = Start.AllTargets();
124 if (*VList != 0)
125 {
126 OK = true;
127 delete [] VList;
128 break;
129 }
130 delete [] VList;
131
132 if (Start == End)
133 break;
134 Start++;
135 }
136 while (1);
137
138 // The group is OK
139 if (OK == true)
140 continue;
141
142 // Oops, it failed..
143 if (Header == false)
144 ioprintf(cout,_("Package %s version %s has an unmet dep:\n"),
145 P.FullName(true).c_str(),V.VerStr());
146 Header = true;
147
148 // Print out the dep type
149 cout << " " << End.DepType() << ": ";
150
151 // Show the group
152 Start = RealStart;
153 do
154 {
155 cout << Start.TargetPkg().FullName(true);
156 if (Start.TargetVer() != 0)
157 cout << " (" << Start.CompType() << " " << Start.TargetVer() <<
158 ")";
159 if (Start == End)
160 break;
161 cout << " | ";
162 Start++;
163 }
164 while (1);
165
166 cout << endl;
167 }
168 }
169 }
170 return true;
171 }
172 /*}}}*/
173 // DumpPackage - Show a dump of a package record /*{{{*/
174 // ---------------------------------------------------------------------
175 /* */
176 bool DumpPackage(CommandLine &CmdL)
177 {
178 pkgCache &Cache = *GCache;
179 APT::PackageSet pkgset = APT::PackageSet::FromCommandLine(Cache, CmdL.FileList);
180
181 for (APT::PackageSet::const_iterator Pkg = pkgset.begin(); Pkg != pkgset.end(); ++Pkg)
182 {
183 cout << "Package: " << Pkg.FullName(true) << endl;
184 cout << "Versions: " << endl;
185 for (pkgCache::VerIterator Cur = Pkg.VersionList(); Cur.end() != true; Cur++)
186 {
187 cout << Cur.VerStr();
188 for (pkgCache::VerFileIterator Vf = Cur.FileList(); Vf.end() == false; Vf++)
189 cout << " (" << Vf.File().FileName() << ")";
190 cout << endl;
191 for (pkgCache::DescIterator D = Cur.DescriptionList(); D.end() == false; D++)
192 {
193 cout << " Description Language: " << D.LanguageCode() << endl
194 << " File: " << D.FileList().File().FileName() << endl
195 << " MD5: " << D.md5() << endl;
196 }
197 cout << endl;
198 }
199
200 cout << endl;
201
202 cout << "Reverse Depends: " << endl;
203 for (pkgCache::DepIterator D = Pkg.RevDependsList(); D.end() != true; D++)
204 {
205 cout << " " << D.ParentPkg().FullName(true) << ',' << D.TargetPkg().FullName(true);
206 if (D->Version != 0)
207 cout << ' ' << DeNull(D.TargetVer()) << endl;
208 else
209 cout << endl;
210 }
211
212 cout << "Dependencies: " << endl;
213 for (pkgCache::VerIterator Cur = Pkg.VersionList(); Cur.end() != true; Cur++)
214 {
215 cout << Cur.VerStr() << " - ";
216 for (pkgCache::DepIterator Dep = Cur.DependsList(); Dep.end() != true; Dep++)
217 cout << Dep.TargetPkg().FullName(true) << " (" << (int)Dep->CompareOp << " " << DeNull(Dep.TargetVer()) << ") ";
218 cout << endl;
219 }
220
221 cout << "Provides: " << endl;
222 for (pkgCache::VerIterator Cur = Pkg.VersionList(); Cur.end() != true; Cur++)
223 {
224 cout << Cur.VerStr() << " - ";
225 for (pkgCache::PrvIterator Prv = Cur.ProvidesList(); Prv.end() != true; Prv++)
226 cout << Prv.ParentPkg().FullName(true) << " ";
227 cout << endl;
228 }
229 cout << "Reverse Provides: " << endl;
230 for (pkgCache::PrvIterator Prv = Pkg.ProvidesList(); Prv.end() != true; Prv++)
231 cout << Prv.OwnerPkg().FullName(true) << " " << Prv.OwnerVer().VerStr() << endl;
232 }
233
234 return true;
235 }
236 /*}}}*/
237 // Stats - Dump some nice statistics /*{{{*/
238 // ---------------------------------------------------------------------
239 /* */
240 bool Stats(CommandLine &Cmd)
241 {
242 pkgCache &Cache = *GCache;
243 cout << _("Total package names: ") << Cache.Head().GroupCount << " (" <<
244 SizeToStr(Cache.Head().GroupCount*Cache.Head().GroupSz) << ')' << endl
245 << _("Total package structures: ") << Cache.Head().PackageCount << " (" <<
246 SizeToStr(Cache.Head().PackageCount*Cache.Head().PackageSz) << ')' << endl;
247
248 int Normal = 0;
249 int Virtual = 0;
250 int NVirt = 0;
251 int DVirt = 0;
252 int Missing = 0;
253 pkgCache::PkgIterator I = Cache.PkgBegin();
254 for (;I.end() != true; I++)
255 {
256 if (I->VersionList != 0 && I->ProvidesList == 0)
257 {
258 Normal++;
259 continue;
260 }
261
262 if (I->VersionList != 0 && I->ProvidesList != 0)
263 {
264 NVirt++;
265 continue;
266 }
267
268 if (I->VersionList == 0 && I->ProvidesList != 0)
269 {
270 // Only 1 provides
271 if (I.ProvidesList()->NextProvides == 0)
272 {
273 DVirt++;
274 }
275 else
276 Virtual++;
277 continue;
278 }
279 if (I->VersionList == 0 && I->ProvidesList == 0)
280 {
281 Missing++;
282 continue;
283 }
284 }
285 cout << _(" Normal packages: ") << Normal << endl;
286 cout << _(" Pure virtual packages: ") << Virtual << endl;
287 cout << _(" Single virtual packages: ") << DVirt << endl;
288 cout << _(" Mixed virtual packages: ") << NVirt << endl;
289 cout << _(" Missing: ") << Missing << endl;
290
291 cout << _("Total distinct versions: ") << Cache.Head().VersionCount << " (" <<
292 SizeToStr(Cache.Head().VersionCount*Cache.Head().VersionSz) << ')' << endl;
293 cout << _("Total distinct descriptions: ") << Cache.Head().DescriptionCount << " (" <<
294 SizeToStr(Cache.Head().DescriptionCount*Cache.Head().DescriptionSz) << ')' << endl;
295 cout << _("Total dependencies: ") << Cache.Head().DependsCount << " (" <<
296 SizeToStr(Cache.Head().DependsCount*Cache.Head().DependencySz) << ')' << endl;
297
298 cout << _("Total ver/file relations: ") << Cache.Head().VerFileCount << " (" <<
299 SizeToStr(Cache.Head().VerFileCount*Cache.Head().VerFileSz) << ')' << endl;
300 cout << _("Total Desc/File relations: ") << Cache.Head().DescFileCount << " (" <<
301 SizeToStr(Cache.Head().DescFileCount*Cache.Head().DescFileSz) << ')' << endl;
302 cout << _("Total Provides mappings: ") << Cache.Head().ProvidesCount << " (" <<
303 SizeToStr(Cache.Head().ProvidesCount*Cache.Head().ProvidesSz) << ')' << endl;
304
305 // String list stats
306 unsigned long Size = 0;
307 unsigned long Count = 0;
308 for (pkgCache::StringItem *I = Cache.StringItemP + Cache.Head().StringList;
309 I!= Cache.StringItemP; I = Cache.StringItemP + I->NextItem)
310 {
311 Count++;
312 Size += strlen(Cache.StrP + I->String) + 1;
313 }
314 cout << _("Total globbed strings: ") << Count << " (" << SizeToStr(Size) << ')' << endl;
315
316 unsigned long DepVerSize = 0;
317 for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; P++)
318 {
319 for (pkgCache::VerIterator V = P.VersionList(); V.end() == false; V++)
320 {
321 for (pkgCache::DepIterator D = V.DependsList(); D.end() == false; D++)
322 {
323 if (D->Version != 0)
324 DepVerSize += strlen(D.TargetVer()) + 1;
325 }
326 }
327 }
328 cout << _("Total dependency version space: ") << SizeToStr(DepVerSize) << endl;
329
330 unsigned long Slack = 0;
331 for (int I = 0; I != 7; I++)
332 Slack += Cache.Head().Pools[I].ItemSize*Cache.Head().Pools[I].Count;
333 cout << _("Total slack space: ") << SizeToStr(Slack) << endl;
334
335 unsigned long Total = 0;
336 Total = Slack + Size + Cache.Head().DependsCount*Cache.Head().DependencySz +
337 Cache.Head().VersionCount*Cache.Head().VersionSz +
338 Cache.Head().PackageCount*Cache.Head().PackageSz +
339 Cache.Head().VerFileCount*Cache.Head().VerFileSz +
340 Cache.Head().ProvidesCount*Cache.Head().ProvidesSz;
341 cout << _("Total space accounted for: ") << SizeToStr(Total) << endl;
342
343 return true;
344 }
345 /*}}}*/
346 // Dump - show everything /*{{{*/
347 // ---------------------------------------------------------------------
348 /* This is worthless except fer debugging things */
349 bool Dump(CommandLine &Cmd)
350 {
351 pkgCache &Cache = *GCache;
352 cout << "Using Versioning System: " << Cache.VS->Label << endl;
353
354 for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; P++)
355 {
356 cout << "Package: " << P.FullName(true) << endl;
357 for (pkgCache::VerIterator V = P.VersionList(); V.end() == false; V++)
358 {
359 cout << " Version: " << V.VerStr() << endl;
360 cout << " File: " << V.FileList().File().FileName() << endl;
361 for (pkgCache::DepIterator D = V.DependsList(); D.end() == false; D++)
362 cout << " Depends: " << D.TargetPkg().FullName(true) << ' ' <<
363 DeNull(D.TargetVer()) << endl;
364 for (pkgCache::DescIterator D = V.DescriptionList(); D.end() == false; D++)
365 {
366 cout << " Description Language: " << D.LanguageCode() << endl
367 << " File: " << D.FileList().File().FileName() << endl
368 << " MD5: " << D.md5() << endl;
369 }
370 }
371 }
372
373 for (pkgCache::PkgFileIterator F = Cache.FileBegin(); F.end() == false; F++)
374 {
375 cout << "File: " << F.FileName() << endl;
376 cout << " Type: " << F.IndexType() << endl;
377 cout << " Size: " << F->Size << endl;
378 cout << " ID: " << F->ID << endl;
379 cout << " Flags: " << F->Flags << endl;
380 cout << " Time: " << TimeRFC1123(F->mtime) << endl;
381 cout << " Archive: " << DeNull(F.Archive()) << endl;
382 cout << " Component: " << DeNull(F.Component()) << endl;
383 cout << " Version: " << DeNull(F.Version()) << endl;
384 cout << " Origin: " << DeNull(F.Origin()) << endl;
385 cout << " Site: " << DeNull(F.Site()) << endl;
386 cout << " Label: " << DeNull(F.Label()) << endl;
387 cout << " Architecture: " << DeNull(F.Architecture()) << endl;
388 }
389
390 return true;
391 }
392 /*}}}*/
393 // DumpAvail - Print out the available list /*{{{*/
394 // ---------------------------------------------------------------------
395 /* This is needed to make dpkg --merge happy.. I spent a bit of time to
396 make this run really fast, perhaps I went a little overboard.. */
397 bool DumpAvail(CommandLine &Cmd)
398 {
399 pkgCache &Cache = *GCache;
400
401 pkgPolicy Plcy(&Cache);
402 if (ReadPinFile(Plcy) == false || ReadPinDir(Plcy) == false)
403 return false;
404
405 unsigned long Count = Cache.HeaderP->PackageCount+1;
406 pkgCache::VerFile **VFList = new pkgCache::VerFile *[Count];
407 memset(VFList,0,sizeof(*VFList)*Count);
408
409 // Map versions that we want to write out onto the VerList array.
410 for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; P++)
411 {
412 if (P->VersionList == 0)
413 continue;
414
415 /* Find the proper version to use. If the policy says there are no
416 possible selections we return the installed version, if available..
417 This prevents dselect from making it obsolete. */
418 pkgCache::VerIterator V = Plcy.GetCandidateVer(P);
419 if (V.end() == true)
420 {
421 if (P->CurrentVer == 0)
422 continue;
423 V = P.CurrentVer();
424 }
425
426 pkgCache::VerFileIterator VF = V.FileList();
427 for (; VF.end() == false ; VF++)
428 if ((VF.File()->Flags & pkgCache::Flag::NotSource) == 0)
429 break;
430
431 /* Okay, here we have a bit of a problem.. The policy has selected the
432 currently installed package - however it only exists in the
433 status file.. We need to write out something or dselect will mark
434 the package as obsolete! Thus we emit the status file entry, but
435 below we remove the status line to make it valid for the
436 available file. However! We only do this if their do exist *any*
437 non-source versions of the package - that way the dselect obsolete
438 handling works OK. */
439 if (VF.end() == true)
440 {
441 for (pkgCache::VerIterator Cur = P.VersionList(); Cur.end() != true; Cur++)
442 {
443 for (VF = Cur.FileList(); VF.end() == false; VF++)
444 {
445 if ((VF.File()->Flags & pkgCache::Flag::NotSource) == 0)
446 {
447 VF = V.FileList();
448 break;
449 }
450 }
451
452 if (VF.end() == false)
453 break;
454 }
455 }
456
457 VFList[P->ID] = VF;
458 }
459
460 LocalitySort(VFList,Count,sizeof(*VFList));
461
462 // Iterate over all the package files and write them out.
463 char *Buffer = new char[Cache.HeaderP->MaxVerFileSize+10];
464 for (pkgCache::VerFile **J = VFList; *J != 0;)
465 {
466 pkgCache::PkgFileIterator File(Cache,(*J)->File + Cache.PkgFileP);
467 if (File.IsOk() == false)
468 {
469 _error->Error(_("Package file %s is out of sync."),File.FileName());
470 break;
471 }
472
473 FileFd PkgF(File.FileName(),FileFd::ReadOnly);
474 if (_error->PendingError() == true)
475 break;
476
477 /* Write all of the records from this package file, since we
478 already did locality sorting we can now just seek through the
479 file in read order. We apply 1 more optimization here, since often
480 there will be < 1 byte gaps between records (for the \n) we read that
481 into the next buffer and offset a bit.. */
482 unsigned long Pos = 0;
483 for (; *J != 0; J++)
484 {
485 if ((*J)->File + Cache.PkgFileP != File)
486 break;
487
488 const pkgCache::VerFile &VF = **J;
489
490 // Read the record and then write it out again.
491 unsigned long Jitter = VF.Offset - Pos;
492 if (Jitter > 8)
493 {
494 if (PkgF.Seek(VF.Offset) == false)
495 break;
496 Jitter = 0;
497 }
498
499 if (PkgF.Read(Buffer,VF.Size + Jitter) == false)
500 break;
501 Buffer[VF.Size + Jitter] = '\n';
502
503 // See above..
504 if ((File->Flags & pkgCache::Flag::NotSource) == pkgCache::Flag::NotSource)
505 {
506 pkgTagSection Tags;
507 TFRewriteData RW[] = {{"Status",0},{"Config-Version",0},{}};
508 const char *Zero = 0;
509 if (Tags.Scan(Buffer+Jitter,VF.Size+1) == false ||
510 TFRewrite(stdout,Tags,&Zero,RW) == false)
511 {
512 _error->Error("Internal Error, Unable to parse a package record");
513 break;
514 }
515 fputc('\n',stdout);
516 }
517 else
518 {
519 if (fwrite(Buffer+Jitter,VF.Size+1,1,stdout) != 1)
520 break;
521 }
522
523 Pos = VF.Offset + VF.Size;
524 }
525
526 fflush(stdout);
527 if (_error->PendingError() == true)
528 break;
529 }
530
531 delete [] Buffer;
532 delete [] VFList;
533 return !_error->PendingError();
534 }
535 /*}}}*/
536 // Depends - Print out a dependency tree /*{{{*/
537 // ---------------------------------------------------------------------
538 /* */
539 bool Depends(CommandLine &CmdL)
540 {
541 pkgCache &Cache = *GCache;
542 SPtrArray<unsigned> Colours = new unsigned[Cache.Head().PackageCount];
543 memset(Colours,0,sizeof(*Colours)*Cache.Head().PackageCount);
544
545 APT::PackageSet pkgset = APT::PackageSet::FromCommandLine(Cache, CmdL.FileList);
546 for (APT::PackageSet::const_iterator Pkg = pkgset.begin(); Pkg != pkgset.end(); ++Pkg)
547 Colours[Pkg->ID] = 1;
548
549 bool Recurse = _config->FindB("APT::Cache::RecurseDepends",false);
550 bool Installed = _config->FindB("APT::Cache::Installed",false);
551 bool Important = _config->FindB("APT::Cache::Important",false);
552 bool DidSomething;
553 do
554 {
555 DidSomething = false;
556 for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; Pkg++)
557 {
558 if (Colours[Pkg->ID] != 1)
559 continue;
560 Colours[Pkg->ID] = 2;
561 DidSomething = true;
562
563 pkgCache::VerIterator Ver = Pkg.VersionList();
564 if (Ver.end() == true)
565 {
566 cout << '<' << Pkg.FullName(true) << '>' << endl;
567 continue;
568 }
569
570 cout << Pkg.FullName(true) << endl;
571
572 for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false; D++)
573 {
574 // Important deps only
575 if (Important == true)
576 if (D->Type != pkgCache::Dep::PreDepends &&
577 D->Type != pkgCache::Dep::Depends)
578 continue;
579
580 pkgCache::PkgIterator Trg = D.TargetPkg();
581
582 if((Installed && Trg->CurrentVer != 0) || !Installed)
583 {
584
585 if ((D->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or)
586 cout << " |";
587 else
588 cout << " ";
589
590 // Show the package
591 if (Trg->VersionList == 0)
592 cout << D.DepType() << ": <" << Trg.FullName(true) << ">" << endl;
593 else
594 cout << D.DepType() << ": " << Trg.FullName(true) << endl;
595
596 if (Recurse == true)
597 Colours[D.TargetPkg()->ID]++;
598
599 }
600
601 // Display all solutions
602 SPtrArray<pkgCache::Version *> List = D.AllTargets();
603 pkgPrioSortList(Cache,List);
604 for (pkgCache::Version **I = List; *I != 0; I++)
605 {
606 pkgCache::VerIterator V(Cache,*I);
607 if (V != Cache.VerP + V.ParentPkg()->VersionList ||
608 V->ParentPkg == D->Package)
609 continue;
610 cout << " " << V.ParentPkg().FullName(true) << endl;
611
612 if (Recurse == true)
613 Colours[D.ParentPkg()->ID]++;
614 }
615 }
616 }
617 }
618 while (DidSomething == true);
619
620 return true;
621 }
622 /*}}}*/
623 // RDepends - Print out a reverse dependency tree - mbc /*{{{*/
624 // ---------------------------------------------------------------------
625 /* */
626 bool RDepends(CommandLine &CmdL)
627 {
628 pkgCache &Cache = *GCache;
629 SPtrArray<unsigned> Colours = new unsigned[Cache.Head().PackageCount];
630 memset(Colours,0,sizeof(*Colours)*Cache.Head().PackageCount);
631
632 APT::PackageSet pkgset = APT::PackageSet::FromCommandLine(Cache, CmdL.FileList);
633 for (APT::PackageSet::const_iterator Pkg = pkgset.begin(); Pkg != pkgset.end(); ++Pkg)
634 Colours[Pkg->ID] = 1;
635
636 bool Recurse = _config->FindB("APT::Cache::RecurseDepends",false);
637 bool Installed = _config->FindB("APT::Cache::Installed",false);
638 bool DidSomething;
639 do
640 {
641 DidSomething = false;
642 for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; Pkg++)
643 {
644 if (Colours[Pkg->ID] != 1)
645 continue;
646 Colours[Pkg->ID] = 2;
647 DidSomething = true;
648
649 pkgCache::VerIterator Ver = Pkg.VersionList();
650 if (Ver.end() == true)
651 {
652 cout << '<' << Pkg.FullName(true) << '>' << endl;
653 continue;
654 }
655
656 cout << Pkg.FullName(true) << endl;
657
658 cout << "Reverse Depends:" << endl;
659 for (pkgCache::DepIterator D = Pkg.RevDependsList(); D.end() == false; D++)
660 {
661 // Show the package
662 pkgCache::PkgIterator Trg = D.ParentPkg();
663
664 if((Installed && Trg->CurrentVer != 0) || !Installed)
665 {
666
667 if ((D->CompareOp & pkgCache::Dep::Or) == pkgCache::Dep::Or)
668 cout << " |";
669 else
670 cout << " ";
671
672 if (Trg->VersionList == 0)
673 cout << D.DepType() << ": <" << Trg.FullName(true) << ">" << endl;
674 else
675 cout << Trg.FullName(true) << endl;
676
677 if (Recurse == true)
678 Colours[D.ParentPkg()->ID]++;
679
680 }
681
682 // Display all solutions
683 SPtrArray<pkgCache::Version *> List = D.AllTargets();
684 pkgPrioSortList(Cache,List);
685 for (pkgCache::Version **I = List; *I != 0; I++)
686 {
687 pkgCache::VerIterator V(Cache,*I);
688 if (V != Cache.VerP + V.ParentPkg()->VersionList ||
689 V->ParentPkg == D->Package)
690 continue;
691 cout << " " << V.ParentPkg().FullName(true) << endl;
692
693 if (Recurse == true)
694 Colours[D.ParentPkg()->ID]++;
695 }
696 }
697 }
698 }
699 while (DidSomething == true);
700
701 return true;
702 }
703 /*}}}*/
704 // xvcg - Generate a graph for xvcg /*{{{*/
705 // ---------------------------------------------------------------------
706 // Code contributed from Junichi Uekawa <dancer@debian.org> on 20 June 2002.
707
708 bool XVcg(CommandLine &CmdL)
709 {
710 pkgCache &Cache = *GCache;
711 bool GivenOnly = _config->FindB("APT::Cache::GivenOnly",false);
712
713 /* Normal packages are boxes
714 Pure Provides are triangles
715 Mixed are diamonds
716 rhomb are missing packages*/
717 const char *Shapes[] = {"ellipse","triangle","box","rhomb"};
718
719 /* Initialize the list of packages to show.
720 1 = To Show
721 2 = To Show no recurse
722 3 = Emitted no recurse
723 4 = Emitted
724 0 = None */
725 enum States {None=0, ToShow, ToShowNR, DoneNR, Done};
726 enum TheFlags {ForceNR=(1<<0)};
727 unsigned char *Show = new unsigned char[Cache.Head().PackageCount];
728 unsigned char *Flags = new unsigned char[Cache.Head().PackageCount];
729 unsigned char *ShapeMap = new unsigned char[Cache.Head().PackageCount];
730
731 // Show everything if no arguments given
732 if (CmdL.FileList[1] == 0)
733 for (unsigned long I = 0; I != Cache.Head().PackageCount; I++)
734 Show[I] = ToShow;
735 else
736 for (unsigned long I = 0; I != Cache.Head().PackageCount; I++)
737 Show[I] = None;
738 memset(Flags,0,sizeof(*Flags)*Cache.Head().PackageCount);
739
740 // Map the shapes
741 for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; Pkg++)
742 {
743 if (Pkg->VersionList == 0)
744 {
745 // Missing
746 if (Pkg->ProvidesList == 0)
747 ShapeMap[Pkg->ID] = 0;
748 else
749 ShapeMap[Pkg->ID] = 1;
750 }
751 else
752 {
753 // Normal
754 if (Pkg->ProvidesList == 0)
755 ShapeMap[Pkg->ID] = 2;
756 else
757 ShapeMap[Pkg->ID] = 3;
758 }
759 }
760
761 // Load the list of packages from the command line into the show list
762 for (const char **I = CmdL.FileList + 1; *I != 0; I++)
763 {
764 // Process per-package flags
765 string P = *I;
766 bool Force = false;
767 if (P.length() > 3)
768 {
769 if (P.end()[-1] == '^')
770 {
771 Force = true;
772 P.erase(P.end()-1);
773 }
774
775 if (P.end()[-1] == ',')
776 P.erase(P.end()-1);
777 }
778
779 // Locate the package
780 pkgCache::PkgIterator Pkg = Cache.FindPkg(P);
781 if (Pkg.end() == true)
782 {
783 _error->Warning(_("Unable to locate package %s"),*I);
784 continue;
785 }
786 Show[Pkg->ID] = ToShow;
787
788 if (Force == true)
789 Flags[Pkg->ID] |= ForceNR;
790 }
791
792 // Little header
793 cout << "graph: { title: \"packages\"" << endl <<
794 "xmax: 700 ymax: 700 x: 30 y: 30" << endl <<
795 "layout_downfactor: 8" << endl;
796
797 bool Act = true;
798 while (Act == true)
799 {
800 Act = false;
801 for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; Pkg++)
802 {
803 // See we need to show this package
804 if (Show[Pkg->ID] == None || Show[Pkg->ID] >= DoneNR)
805 continue;
806
807 //printf ("node: { title: \"%s\" label: \"%s\" }\n", Pkg.Name(), Pkg.Name());
808
809 // Colour as done
810 if (Show[Pkg->ID] == ToShowNR || (Flags[Pkg->ID] & ForceNR) == ForceNR)
811 {
812 // Pure Provides and missing packages have no deps!
813 if (ShapeMap[Pkg->ID] == 0 || ShapeMap[Pkg->ID] == 1)
814 Show[Pkg->ID] = Done;
815 else
816 Show[Pkg->ID] = DoneNR;
817 }
818 else
819 Show[Pkg->ID] = Done;
820 Act = true;
821
822 // No deps to map out
823 if (Pkg->VersionList == 0 || Show[Pkg->ID] == DoneNR)
824 continue;
825
826 pkgCache::VerIterator Ver = Pkg.VersionList();
827 for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false; D++)
828 {
829 // See if anything can meet this dep
830 // Walk along the actual package providing versions
831 bool Hit = false;
832 pkgCache::PkgIterator DPkg = D.TargetPkg();
833 for (pkgCache::VerIterator I = DPkg.VersionList();
834 I.end() == false && Hit == false; I++)
835 {
836 if (Cache.VS->CheckDep(I.VerStr(),D->CompareOp,D.TargetVer()) == true)
837 Hit = true;
838 }
839
840 // Follow all provides
841 for (pkgCache::PrvIterator I = DPkg.ProvidesList();
842 I.end() == false && Hit == false; I++)
843 {
844 if (Cache.VS->CheckDep(I.ProvideVersion(),D->CompareOp,D.TargetVer()) == false)
845 Hit = true;
846 }
847
848
849 // Only graph critical deps
850 if (D.IsCritical() == true)
851 {
852 printf ("edge: { sourcename: \"%s\" targetname: \"%s\" class: 2 ",Pkg.FullName(true).c_str(), D.TargetPkg().FullName(true).c_str() );
853
854 // Colour the node for recursion
855 if (Show[D.TargetPkg()->ID] <= DoneNR)
856 {
857 /* If a conflicts does not meet anything in the database
858 then show the relation but do not recurse */
859 if (Hit == false &&
860 (D->Type == pkgCache::Dep::Conflicts ||
861 D->Type == pkgCache::Dep::DpkgBreaks ||
862 D->Type == pkgCache::Dep::Obsoletes))
863 {
864 if (Show[D.TargetPkg()->ID] == None &&
865 Show[D.TargetPkg()->ID] != ToShow)
866 Show[D.TargetPkg()->ID] = ToShowNR;
867 }
868 else
869 {
870 if (GivenOnly == true && Show[D.TargetPkg()->ID] != ToShow)
871 Show[D.TargetPkg()->ID] = ToShowNR;
872 else
873 Show[D.TargetPkg()->ID] = ToShow;
874 }
875 }
876
877 // Edge colour
878 switch(D->Type)
879 {
880 case pkgCache::Dep::Conflicts:
881 printf("label: \"conflicts\" color: lightgreen }\n");
882 break;
883 case pkgCache::Dep::DpkgBreaks:
884 printf("label: \"breaks\" color: lightgreen }\n");
885 break;
886 case pkgCache::Dep::Obsoletes:
887 printf("label: \"obsoletes\" color: lightgreen }\n");
888 break;
889
890 case pkgCache::Dep::PreDepends:
891 printf("label: \"predepends\" color: blue }\n");
892 break;
893
894 default:
895 printf("}\n");
896 break;
897 }
898 }
899 }
900 }
901 }
902
903 /* Draw the box colours after the fact since we can not tell what colour
904 they should be until everything is finished drawing */
905 for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; Pkg++)
906 {
907 if (Show[Pkg->ID] < DoneNR)
908 continue;
909
910 if (Show[Pkg->ID] == DoneNR)
911 printf("node: { title: \"%s\" label: \"%s\" color: orange shape: %s }\n", Pkg.FullName(true).c_str(), Pkg.FullName(true).c_str(),
912 Shapes[ShapeMap[Pkg->ID]]);
913 else
914 printf("node: { title: \"%s\" label: \"%s\" shape: %s }\n", Pkg.FullName(true).c_str(), Pkg.FullName(true).c_str(),
915 Shapes[ShapeMap[Pkg->ID]]);
916
917 }
918
919 delete[] Show;
920 delete[] Flags;
921 delete[] ShapeMap;
922
923 printf("}\n");
924 return true;
925 }
926 /*}}}*/
927 // Dotty - Generate a graph for Dotty /*{{{*/
928 // ---------------------------------------------------------------------
929 /* Dotty is the graphvis program for generating graphs. It is a fairly
930 simple queuing algorithm that just writes dependencies and nodes.
931 http://www.research.att.com/sw/tools/graphviz/ */
932 bool Dotty(CommandLine &CmdL)
933 {
934 pkgCache &Cache = *GCache;
935 bool GivenOnly = _config->FindB("APT::Cache::GivenOnly",false);
936
937 /* Normal packages are boxes
938 Pure Provides are triangles
939 Mixed are diamonds
940 Hexagons are missing packages*/
941 const char *Shapes[] = {"hexagon","triangle","box","diamond"};
942
943 /* Initialize the list of packages to show.
944 1 = To Show
945 2 = To Show no recurse
946 3 = Emitted no recurse
947 4 = Emitted
948 0 = None */
949 enum States {None=0, ToShow, ToShowNR, DoneNR, Done};
950 enum TheFlags {ForceNR=(1<<0)};
951 unsigned char *Show = new unsigned char[Cache.Head().PackageCount];
952 unsigned char *Flags = new unsigned char[Cache.Head().PackageCount];
953 unsigned char *ShapeMap = new unsigned char[Cache.Head().PackageCount];
954
955 // Show everything if no arguments given
956 if (CmdL.FileList[1] == 0)
957 for (unsigned long I = 0; I != Cache.Head().PackageCount; I++)
958 Show[I] = ToShow;
959 else
960 for (unsigned long I = 0; I != Cache.Head().PackageCount; I++)
961 Show[I] = None;
962 memset(Flags,0,sizeof(*Flags)*Cache.Head().PackageCount);
963
964 // Map the shapes
965 for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; Pkg++)
966 {
967 if (Pkg->VersionList == 0)
968 {
969 // Missing
970 if (Pkg->ProvidesList == 0)
971 ShapeMap[Pkg->ID] = 0;
972 else
973 ShapeMap[Pkg->ID] = 1;
974 }
975 else
976 {
977 // Normal
978 if (Pkg->ProvidesList == 0)
979 ShapeMap[Pkg->ID] = 2;
980 else
981 ShapeMap[Pkg->ID] = 3;
982 }
983 }
984
985 // Load the list of packages from the command line into the show list
986 for (const char **I = CmdL.FileList + 1; *I != 0; I++)
987 {
988 // Process per-package flags
989 string P = *I;
990 bool Force = false;
991 if (P.length() > 3)
992 {
993 if (P.end()[-1] == '^')
994 {
995 Force = true;
996 P.erase(P.end()-1);
997 }
998
999 if (P.end()[-1] == ',')
1000 P.erase(P.end()-1);
1001 }
1002
1003 // Locate the package
1004 pkgCache::PkgIterator Pkg = Cache.FindPkg(P);
1005 if (Pkg.end() == true)
1006 {
1007 _error->Warning(_("Unable to locate package %s"),*I);
1008 continue;
1009 }
1010 Show[Pkg->ID] = ToShow;
1011
1012 if (Force == true)
1013 Flags[Pkg->ID] |= ForceNR;
1014 }
1015
1016 // Little header
1017 printf("digraph packages {\n");
1018 printf("concentrate=true;\n");
1019 printf("size=\"30,40\";\n");
1020
1021 bool Act = true;
1022 while (Act == true)
1023 {
1024 Act = false;
1025 for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; Pkg++)
1026 {
1027 // See we need to show this package
1028 if (Show[Pkg->ID] == None || Show[Pkg->ID] >= DoneNR)
1029 continue;
1030
1031 // Colour as done
1032 if (Show[Pkg->ID] == ToShowNR || (Flags[Pkg->ID] & ForceNR) == ForceNR)
1033 {
1034 // Pure Provides and missing packages have no deps!
1035 if (ShapeMap[Pkg->ID] == 0 || ShapeMap[Pkg->ID] == 1)
1036 Show[Pkg->ID] = Done;
1037 else
1038 Show[Pkg->ID] = DoneNR;
1039 }
1040 else
1041 Show[Pkg->ID] = Done;
1042 Act = true;
1043
1044 // No deps to map out
1045 if (Pkg->VersionList == 0 || Show[Pkg->ID] == DoneNR)
1046 continue;
1047
1048 pkgCache::VerIterator Ver = Pkg.VersionList();
1049 for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false; D++)
1050 {
1051 // See if anything can meet this dep
1052 // Walk along the actual package providing versions
1053 bool Hit = false;
1054 pkgCache::PkgIterator DPkg = D.TargetPkg();
1055 for (pkgCache::VerIterator I = DPkg.VersionList();
1056 I.end() == false && Hit == false; I++)
1057 {
1058 if (Cache.VS->CheckDep(I.VerStr(),D->CompareOp,D.TargetVer()) == true)
1059 Hit = true;
1060 }
1061
1062 // Follow all provides
1063 for (pkgCache::PrvIterator I = DPkg.ProvidesList();
1064 I.end() == false && Hit == false; I++)
1065 {
1066 if (Cache.VS->CheckDep(I.ProvideVersion(),D->CompareOp,D.TargetVer()) == false)
1067 Hit = true;
1068 }
1069
1070 // Only graph critical deps
1071 if (D.IsCritical() == true)
1072 {
1073 printf("\"%s\" -> \"%s\"",Pkg.FullName(true).c_str(),D.TargetPkg().FullName(true).c_str());
1074
1075 // Colour the node for recursion
1076 if (Show[D.TargetPkg()->ID] <= DoneNR)
1077 {
1078 /* If a conflicts does not meet anything in the database
1079 then show the relation but do not recurse */
1080 if (Hit == false &&
1081 (D->Type == pkgCache::Dep::Conflicts ||
1082 D->Type == pkgCache::Dep::Obsoletes))
1083 {
1084 if (Show[D.TargetPkg()->ID] == None &&
1085 Show[D.TargetPkg()->ID] != ToShow)
1086 Show[D.TargetPkg()->ID] = ToShowNR;
1087 }
1088 else
1089 {
1090 if (GivenOnly == true && Show[D.TargetPkg()->ID] != ToShow)
1091 Show[D.TargetPkg()->ID] = ToShowNR;
1092 else
1093 Show[D.TargetPkg()->ID] = ToShow;
1094 }
1095 }
1096
1097 // Edge colour
1098 switch(D->Type)
1099 {
1100 case pkgCache::Dep::Conflicts:
1101 case pkgCache::Dep::Obsoletes:
1102 printf("[color=springgreen];\n");
1103 break;
1104
1105 case pkgCache::Dep::PreDepends:
1106 printf("[color=blue];\n");
1107 break;
1108
1109 default:
1110 printf(";\n");
1111 break;
1112 }
1113 }
1114 }
1115 }
1116 }
1117
1118 /* Draw the box colours after the fact since we can not tell what colour
1119 they should be until everything is finished drawing */
1120 for (pkgCache::PkgIterator Pkg = Cache.PkgBegin(); Pkg.end() == false; Pkg++)
1121 {
1122 if (Show[Pkg->ID] < DoneNR)
1123 continue;
1124
1125 // Orange box for early recursion stoppage
1126 if (Show[Pkg->ID] == DoneNR)
1127 printf("\"%s\" [color=orange,shape=%s];\n",Pkg.FullName(true).c_str(),
1128 Shapes[ShapeMap[Pkg->ID]]);
1129 else
1130 printf("\"%s\" [shape=%s];\n",Pkg.FullName(true).c_str(),
1131 Shapes[ShapeMap[Pkg->ID]]);
1132 }
1133
1134 printf("}\n");
1135 return true;
1136 }
1137 /*}}}*/
1138 // DoAdd - Perform an adding operation /*{{{*/
1139 // ---------------------------------------------------------------------
1140 /* */
1141 bool DoAdd(CommandLine &CmdL)
1142 {
1143 return _error->Error("Unimplemented");
1144 #if 0
1145 // Make sure there is at least one argument
1146 if (CmdL.FileSize() <= 1)
1147 return _error->Error("You must give at least one file name");
1148
1149 // Open the cache
1150 FileFd CacheF(_config->FindFile("Dir::Cache::pkgcache"),FileFd::WriteAny);
1151 if (_error->PendingError() == true)
1152 return false;
1153
1154 DynamicMMap Map(CacheF,MMap::Public);
1155 if (_error->PendingError() == true)
1156 return false;
1157
1158 OpTextProgress Progress(*_config);
1159 pkgCacheGenerator Gen(Map,Progress);
1160 if (_error->PendingError() == true)
1161 return false;
1162
1163 unsigned long Length = CmdL.FileSize() - 1;
1164 for (const char **I = CmdL.FileList + 1; *I != 0; I++)
1165 {
1166 Progress.OverallProgress(I - CmdL.FileList,Length,1,"Generating cache");
1167 Progress.SubProgress(Length);
1168
1169 // Do the merge
1170 FileFd TagF(*I,FileFd::ReadOnly);
1171 debListParser Parser(TagF);
1172 if (_error->PendingError() == true)
1173 return _error->Error("Problem opening %s",*I);
1174
1175 if (Gen.SelectFile(*I,"") == false)
1176 return _error->Error("Problem with SelectFile");
1177
1178 if (Gen.MergeList(Parser) == false)
1179 return _error->Error("Problem with MergeList");
1180 }
1181
1182 Progress.Done();
1183 GCache = &Gen.GetCache();
1184 Stats(CmdL);
1185
1186 return true;
1187 #endif
1188 }
1189 /*}}}*/
1190 // DisplayRecord - Displays the complete record for the package /*{{{*/
1191 // ---------------------------------------------------------------------
1192 /* This displays the package record from the proper package index file.
1193 It is not used by DumpAvail for performance reasons. */
1194 bool DisplayRecord(pkgCache::VerIterator V)
1195 {
1196 // Find an appropriate file
1197 pkgCache::VerFileIterator Vf = V.FileList();
1198 for (; Vf.end() == false; Vf++)
1199 if ((Vf.File()->Flags & pkgCache::Flag::NotSource) == 0)
1200 break;
1201 if (Vf.end() == true)
1202 Vf = V.FileList();
1203
1204 // Check and load the package list file
1205 pkgCache::PkgFileIterator I = Vf.File();
1206 if (I.IsOk() == false)
1207 return _error->Error(_("Package file %s is out of sync."),I.FileName());
1208
1209 FileFd PkgF(I.FileName(),FileFd::ReadOnly);
1210 if (_error->PendingError() == true)
1211 return false;
1212
1213 // Read the record
1214 unsigned char *Buffer = new unsigned char[GCache->HeaderP->MaxVerFileSize+1];
1215 Buffer[V.FileList()->Size] = '\n';
1216 if (PkgF.Seek(V.FileList()->Offset) == false ||
1217 PkgF.Read(Buffer,V.FileList()->Size) == false)
1218 {
1219 delete [] Buffer;
1220 return false;
1221 }
1222
1223 // Get a pointer to start of Description field
1224 const unsigned char *DescP = (unsigned char*)strstr((char*)Buffer, "Description:");
1225
1226 // Write all but Description
1227 if (fwrite(Buffer,1,DescP - Buffer,stdout) < (size_t)(DescP - Buffer))
1228 {
1229 delete [] Buffer;
1230 return false;
1231 }
1232
1233 // Show the right description
1234 pkgRecords Recs(*GCache);
1235 pkgCache::DescIterator Desc = V.TranslatedDescription();
1236 pkgRecords::Parser &P = Recs.Lookup(Desc.FileList());
1237 cout << "Description" << ( (strcmp(Desc.LanguageCode(),"") != 0) ? "-" : "" ) << Desc.LanguageCode() << ": " << P.LongDesc();
1238
1239 // Find the first field after the description (if there is any)
1240 for(DescP++;DescP != &Buffer[V.FileList()->Size];DescP++)
1241 {
1242 if(*DescP == '\n' && *(DescP+1) != ' ')
1243 {
1244 // write the rest of the buffer
1245 const unsigned char *end=&Buffer[V.FileList()->Size];
1246 if (fwrite(DescP,1,end-DescP,stdout) < (size_t)(end-DescP))
1247 {
1248 delete [] Buffer;
1249 return false;
1250 }
1251
1252 break;
1253 }
1254 }
1255 // write a final newline (after the description)
1256 cout<<endl;
1257 delete [] Buffer;
1258
1259 return true;
1260 }
1261 /*}}}*/
1262
1263 struct ExDescFile
1264 {
1265 pkgCache::DescFile *Df;
1266 bool NameMatch;
1267 };
1268
1269 // Search - Perform a search /*{{{*/
1270 // ---------------------------------------------------------------------
1271 /* This searches the package names and package descriptions for a pattern */
1272 bool Search(CommandLine &CmdL)
1273 {
1274 pkgCache &Cache = *GCache;
1275 bool ShowFull = _config->FindB("APT::Cache::ShowFull",false);
1276 bool NamesOnly = _config->FindB("APT::Cache::NamesOnly",false);
1277 unsigned NumPatterns = CmdL.FileSize() -1;
1278
1279 pkgDepCache::Policy Plcy;
1280
1281 // Make sure there is at least one argument
1282 if (NumPatterns < 1)
1283 return _error->Error(_("You must give exactly one pattern"));
1284
1285 // Compile the regex pattern
1286 regex_t *Patterns = new regex_t[NumPatterns];
1287 memset(Patterns,0,sizeof(*Patterns)*NumPatterns);
1288 for (unsigned I = 0; I != NumPatterns; I++)
1289 {
1290 if (regcomp(&Patterns[I],CmdL.FileList[I+1],REG_EXTENDED | REG_ICASE |
1291 REG_NOSUB) != 0)
1292 {
1293 for (; I != 0; I--)
1294 regfree(&Patterns[I]);
1295 return _error->Error("Regex compilation error");
1296 }
1297 }
1298
1299 // Create the text record parser
1300 pkgRecords Recs(Cache);
1301 if (_error->PendingError() == true)
1302 {
1303 for (unsigned I = 0; I != NumPatterns; I++)
1304 regfree(&Patterns[I]);
1305 return false;
1306 }
1307
1308 ExDescFile *DFList = new ExDescFile[Cache.HeaderP->PackageCount+1];
1309 memset(DFList,0,sizeof(*DFList)*Cache.HeaderP->PackageCount+1);
1310
1311 // Map versions that we want to write out onto the VerList array.
1312 for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; P++)
1313 {
1314 DFList[P->ID].NameMatch = NumPatterns != 0;
1315 for (unsigned I = 0; I != NumPatterns; I++)
1316 {
1317 if (regexec(&Patterns[I],P.Name(),0,0,0) == 0)
1318 DFList[P->ID].NameMatch &= true;
1319 else
1320 DFList[P->ID].NameMatch = false;
1321 }
1322
1323 // Doing names only, drop any that dont match..
1324 if (NamesOnly == true && DFList[P->ID].NameMatch == false)
1325 continue;
1326
1327 // Find the proper version to use.
1328 pkgCache::VerIterator V = Plcy.GetCandidateVer(P);
1329 if (V.end() == false)
1330 DFList[P->ID].Df = V.DescriptionList().FileList();
1331 }
1332
1333 // Include all the packages that provide matching names too
1334 for (pkgCache::PkgIterator P = Cache.PkgBegin(); P.end() == false; P++)
1335 {
1336 if (DFList[P->ID].NameMatch == false)
1337 continue;
1338
1339 for (pkgCache::PrvIterator Prv = P.ProvidesList() ; Prv.end() == false; Prv++)
1340 {
1341 pkgCache::VerIterator V = Plcy.GetCandidateVer(Prv.OwnerPkg());
1342 if (V.end() == false)
1343 {
1344 DFList[Prv.OwnerPkg()->ID].Df = V.DescriptionList().FileList();
1345 DFList[Prv.OwnerPkg()->ID].NameMatch = true;
1346 }
1347 }
1348 }
1349
1350 LocalitySort(&DFList->Df,Cache.HeaderP->PackageCount,sizeof(*DFList));
1351
1352 // Iterate over all the version records and check them
1353 for (ExDescFile *J = DFList; J->Df != 0; J++)
1354 {
1355 pkgRecords::Parser &P = Recs.Lookup(pkgCache::DescFileIterator(Cache,J->Df));
1356
1357 bool Match = true;
1358 if (J->NameMatch == false)
1359 {
1360 string LongDesc = P.LongDesc();
1361 Match = NumPatterns != 0;
1362 for (unsigned I = 0; I != NumPatterns; I++)
1363 {
1364 if (regexec(&Patterns[I],LongDesc.c_str(),0,0,0) == 0)
1365 Match &= true;
1366 else
1367 Match = false;
1368 }
1369 }
1370
1371 if (Match == true)
1372 {
1373 if (ShowFull == true)
1374 {
1375 const char *Start;
1376 const char *End;
1377 P.GetRec(Start,End);
1378 fwrite(Start,End-Start,1,stdout);
1379 putc('\n',stdout);
1380 }
1381 else
1382 printf("%s - %s\n",P.Name().c_str(),P.ShortDesc().c_str());
1383 }
1384 }
1385
1386 delete [] DFList;
1387 for (unsigned I = 0; I != NumPatterns; I++)
1388 regfree(&Patterns[I]);
1389 if (ferror(stdout))
1390 return _error->Error("Write to stdout failed");
1391 return true;
1392 }
1393
1394
1395 /* show automatically installed packages (sorted) */
1396 bool ShowAuto(CommandLine &CmdL)
1397 {
1398 OpProgress op;
1399 pkgDepCache DepCache(GCache);
1400 DepCache.Init(&op);
1401
1402 std::vector<string> packages;
1403 packages.reserve(GCache->HeaderP->PackageCount / 3);
1404
1405 for (pkgCache::PkgIterator P = GCache->PkgBegin(); P.end() == false; P++)
1406 if (DepCache[P].Flags & pkgCache::Flag::Auto)
1407 packages.push_back(P.Name());
1408
1409 std::sort(packages.begin(), packages.end());
1410
1411 for (vector<string>::iterator I = packages.begin(); I != packages.end(); I++)
1412 cout << *I << "\n";
1413
1414 return true;
1415 }
1416 /*}}}*/
1417 // ShowPackage - Dump the package record to the screen /*{{{*/
1418 // ---------------------------------------------------------------------
1419 /* */
1420 bool ShowPackage(CommandLine &CmdL)
1421 {
1422 pkgCache &Cache = *GCache;
1423 pkgDepCache::Policy Plcy;
1424
1425 APT::PackageSet pkgset = APT::PackageSet::FromCommandLine(Cache, CmdL.FileList);
1426 for (APT::PackageSet::const_iterator Pkg = pkgset.begin(); Pkg != pkgset.end(); ++Pkg)
1427 {
1428 // Find the proper version to use.
1429 if (_config->FindB("APT::Cache::AllVersions","true") == true)
1430 {
1431 pkgCache::VerIterator V;
1432 for (V = Pkg.VersionList(); V.end() == false; V++)
1433 {
1434 if (DisplayRecord(V) == false)
1435 return false;
1436 }
1437 }
1438 else
1439 {
1440 pkgCache::VerIterator V = Plcy.GetCandidateVer(Pkg);
1441 if (V.end() == true || V.FileList().end() == true)
1442 continue;
1443 if (DisplayRecord(V) == false)
1444 return false;
1445 }
1446 }
1447
1448 if (pkgset.empty() == false)
1449 return true;
1450 return _error->Error(_("No packages found"));
1451 }
1452 /*}}}*/
1453 // ShowPkgNames - Show package names /*{{{*/
1454 // ---------------------------------------------------------------------
1455 /* This does a prefix match on the first argument */
1456 bool ShowPkgNames(CommandLine &CmdL)
1457 {
1458 pkgCache &Cache = *GCache;
1459 pkgCache::GrpIterator I = Cache.GrpBegin();
1460 bool const All = _config->FindB("APT::Cache::AllNames","false");
1461
1462 if (CmdL.FileList[1] != 0)
1463 {
1464 for (;I.end() != true; I++)
1465 {
1466 if (All == false && I->FirstPackage == 0)
1467 continue;
1468 if (I.FindPkg("any")->VersionList == 0)
1469 continue;
1470 if (strncmp(I.Name(),CmdL.FileList[1],strlen(CmdL.FileList[1])) == 0)
1471 cout << I.Name() << endl;
1472 }
1473
1474 return true;
1475 }
1476
1477 // Show all pkgs
1478 for (;I.end() != true; I++)
1479 {
1480 if (All == false && I->FirstPackage == 0)
1481 continue;
1482 if (I.FindPkg("any")->VersionList == 0)
1483 continue;
1484 cout << I.Name() << endl;
1485 }
1486
1487 return true;
1488 }
1489 /*}}}*/
1490 // ShowSrcPackage - Show source package records /*{{{*/
1491 // ---------------------------------------------------------------------
1492 /* */
1493 bool ShowSrcPackage(CommandLine &CmdL)
1494 {
1495 pkgSourceList List;
1496 List.ReadMainList();
1497
1498 // Create the text record parsers
1499 pkgSrcRecords SrcRecs(List);
1500 if (_error->PendingError() == true)
1501 return false;
1502
1503 unsigned found = 0;
1504 for (const char **I = CmdL.FileList + 1; *I != 0; I++)
1505 {
1506 SrcRecs.Restart();
1507
1508 pkgSrcRecords::Parser *Parse;
1509 unsigned found_this = 0;
1510 while ((Parse = SrcRecs.Find(*I,false)) != 0) {
1511 cout << Parse->AsStr() << endl;;
1512 found++;
1513 found_this++;
1514 }
1515 if (found_this == 0) {
1516 _error->Warning(_("Unable to locate package %s"),*I);
1517 continue;
1518 }
1519 }
1520 if (found > 0)
1521 return true;
1522 return _error->Error(_("No packages found"));
1523 }
1524 /*}}}*/
1525 // Policy - Show the results of the preferences file /*{{{*/
1526 // ---------------------------------------------------------------------
1527 /* */
1528 bool Policy(CommandLine &CmdL)
1529 {
1530 if (SrcList == 0)
1531 return _error->Error("Generate must be enabled for this function");
1532
1533 pkgCache &Cache = *GCache;
1534 pkgPolicy Plcy(&Cache);
1535 if (ReadPinFile(Plcy) == false || ReadPinDir(Plcy) == false)
1536 return false;
1537
1538 // Print out all of the package files
1539 if (CmdL.FileList[1] == 0)
1540 {
1541 cout << _("Package files:") << endl;
1542 for (pkgCache::PkgFileIterator F = Cache.FileBegin(); F.end() == false; F++)
1543 {
1544 // Locate the associated index files so we can derive a description
1545 pkgIndexFile *Indx;
1546 if (SrcList->FindIndex(F,Indx) == false &&
1547 _system->FindIndex(F,Indx) == false)
1548 return _error->Error(_("Cache is out of sync, can't x-ref a package file"));
1549
1550 printf("%4i %s\n",
1551 Plcy.GetPriority(F),Indx->Describe(true).c_str());
1552
1553 // Print the reference information for the package
1554 string Str = F.RelStr();
1555 if (Str.empty() == false)
1556 printf(" release %s\n",F.RelStr().c_str());
1557 if (F.Site() != 0 && F.Site()[0] != 0)
1558 printf(" origin %s\n",F.Site());
1559 }
1560
1561 // Show any packages have explicit pins
1562 cout << _("Pinned packages:") << endl;
1563 pkgCache::PkgIterator I = Cache.PkgBegin();
1564 for (;I.end() != true; I++)
1565 {
1566 if (Plcy.GetPriority(I) == 0)
1567 continue;
1568
1569 // Print the package name and the version we are forcing to
1570 cout << " " << I.FullName(true) << " -> ";
1571
1572 pkgCache::VerIterator V = Plcy.GetMatch(I);
1573 if (V.end() == true)
1574 cout << _("(not found)") << endl;
1575 else
1576 cout << V.VerStr() << endl;
1577 }
1578
1579 return true;
1580 }
1581
1582 string const myArch = _config->Find("APT::Architecture");
1583 char const * const msgInstalled = _(" Installed: ");
1584 char const * const msgCandidate = _(" Candidate: ");
1585 short const InstalledLessCandidate =
1586 mbstowcs(NULL, msgInstalled, 0) - mbstowcs(NULL, msgCandidate, 0);
1587 short const deepInstalled =
1588 (InstalledLessCandidate < 0 ? (InstalledLessCandidate*-1) : 0) - 1;
1589 short const deepCandidate =
1590 (InstalledLessCandidate > 0 ? (InstalledLessCandidate) : 0) - 1;
1591
1592 // Print out detailed information for each package
1593 APT::PackageSet pkgset = APT::PackageSet::FromCommandLine(Cache, CmdL.FileList);
1594 for (APT::PackageSet::const_iterator I = pkgset.begin(); I != pkgset.end(); ++I)
1595 {
1596 pkgCache::PkgIterator Pkg = I.Group().FindPkg("any");
1597
1598 for (; Pkg.end() != true; Pkg = Grp.NextPkg(Pkg)) {
1599 if (strcmp(Pkg.Arch(),"all") == 0)
1600 continue;
1601
1602 cout << Pkg.FullName(true) << ":" << endl;
1603
1604 // Installed version
1605 cout << msgInstalled << OutputInDepth(deepInstalled, " ");
1606 if (Pkg->CurrentVer == 0)
1607 cout << _("(none)") << endl;
1608 else
1609 cout << Pkg.CurrentVer().VerStr() << endl;
1610
1611 // Candidate Version
1612 cout << msgCandidate << OutputInDepth(deepCandidate, " ");
1613 pkgCache::VerIterator V = Plcy.GetCandidateVer(Pkg);
1614 if (V.end() == true)
1615 cout << _("(none)") << endl;
1616 else
1617 cout << V.VerStr() << endl;
1618
1619 // Pinned version
1620 if (Plcy.GetPriority(Pkg) != 0)
1621 {
1622 cout << _(" Package pin: ");
1623 V = Plcy.GetMatch(Pkg);
1624 if (V.end() == true)
1625 cout << _("(not found)") << endl;
1626 else
1627 cout << V.VerStr() << endl;
1628 }
1629
1630 // Show the priority tables
1631 cout << _(" Version table:") << endl;
1632 for (V = Pkg.VersionList(); V.end() == false; V++)
1633 {
1634 if (Pkg.CurrentVer() == V)
1635 cout << " *** " << V.VerStr();
1636 else
1637 cout << " " << V.VerStr();
1638 cout << " " << Plcy.GetPriority(Pkg) << endl;
1639 for (pkgCache::VerFileIterator VF = V.FileList(); VF.end() == false; VF++)
1640 {
1641 // Locate the associated index files so we can derive a description
1642 pkgIndexFile *Indx;
1643 if (SrcList->FindIndex(VF.File(),Indx) == false &&
1644 _system->FindIndex(VF.File(),Indx) == false)
1645 return _error->Error(_("Cache is out of sync, can't x-ref a package file"));
1646 printf(" %4i %s\n",Plcy.GetPriority(VF.File()),
1647 Indx->Describe(true).c_str());
1648 }
1649 }
1650 }
1651 }
1652
1653 return true;
1654 }
1655 /*}}}*/
1656 // Madison - Look a bit like katie's madison /*{{{*/
1657 // ---------------------------------------------------------------------
1658 /* */
1659 bool Madison(CommandLine &CmdL)
1660 {
1661 if (SrcList == 0)
1662 return _error->Error("Generate must be enabled for this function");
1663
1664 SrcList->ReadMainList();
1665
1666 pkgCache &Cache = *GCache;
1667
1668 // Create the src text record parsers and ignore errors about missing
1669 // deb-src lines that are generated from pkgSrcRecords::pkgSrcRecords
1670 pkgSrcRecords SrcRecs(*SrcList);
1671 if (_error->PendingError() == true)
1672 _error->Discard();
1673
1674 APT::PackageSet pkgset = APT::PackageSet::FromCommandLine(Cache, CmdL.FileList);
1675 for (APT::PackageSet::const_iterator Pkg = pkgset.begin(); Pkg != pkgset.end(); ++Pkg)
1676 {
1677 if (Pkg.end() == false)
1678 {
1679 for (pkgCache::VerIterator V = Pkg.VersionList(); V.end() == false; V++)
1680 {
1681 for (pkgCache::VerFileIterator VF = V.FileList(); VF.end() == false; VF++)
1682 {
1683 // This might be nice, but wouldn't uniquely identify the source -mdz
1684 // if (VF.File().Archive() != 0)
1685 // {
1686 // cout << setw(10) << Pkg.Name() << " | " << setw(10) << V.VerStr() << " | "
1687 // << VF.File().Archive() << endl;
1688 // }
1689
1690 // Locate the associated index files so we can derive a description
1691 for (pkgSourceList::const_iterator S = SrcList->begin(); S != SrcList->end(); S++)
1692 {
1693 vector<pkgIndexFile *> *Indexes = (*S)->GetIndexFiles();
1694 for (vector<pkgIndexFile *>::const_iterator IF = Indexes->begin();
1695 IF != Indexes->end(); IF++)
1696 {
1697 if ((*IF)->FindInCache(*(VF.File().Cache())) == VF.File())
1698 {
1699 cout << setw(10) << Pkg.FullName(true) << " | " << setw(10) << V.VerStr() << " | "
1700 << (*IF)->Describe(true) << endl;
1701 }
1702 }
1703 }
1704 }
1705 }
1706 }
1707
1708
1709 SrcRecs.Restart();
1710 pkgSrcRecords::Parser *SrcParser;
1711 while ((SrcParser = SrcRecs.Find(Pkg.Name(),false)) != 0)
1712 {
1713 // Maybe support Release info here too eventually
1714 cout << setw(10) << SrcParser->Package() << " | "
1715 << setw(10) << SrcParser->Version() << " | "
1716 << SrcParser->Index().Describe(true) << endl;
1717 }
1718 }
1719
1720 return true;
1721 }
1722 /*}}}*/
1723 // GenCaches - Call the main cache generator /*{{{*/
1724 // ---------------------------------------------------------------------
1725 /* */
1726 bool GenCaches(CommandLine &Cmd)
1727 {
1728 OpTextProgress Progress(*_config);
1729
1730 pkgSourceList List;
1731 if (List.ReadMainList() == false)
1732 return false;
1733 return pkgMakeStatusCache(List,Progress);
1734 }
1735 /*}}}*/
1736 // ShowHelp - Show a help screen /*{{{*/
1737 // ---------------------------------------------------------------------
1738 /* */
1739 bool ShowHelp(CommandLine &Cmd)
1740 {
1741 ioprintf(cout,_("%s %s for %s compiled on %s %s\n"),PACKAGE,VERSION,
1742 COMMON_ARCH,__DATE__,__TIME__);
1743
1744 if (_config->FindB("version") == true)
1745 return true;
1746
1747 cout <<
1748 _("Usage: apt-cache [options] command\n"
1749 " apt-cache [options] add file1 [file2 ...]\n"
1750 " apt-cache [options] showpkg pkg1 [pkg2 ...]\n"
1751 " apt-cache [options] showsrc pkg1 [pkg2 ...]\n"
1752 "\n"
1753 "apt-cache is a low-level tool used to manipulate APT's binary\n"
1754 "cache files, and query information from them\n"
1755 "\n"
1756 "Commands:\n"
1757 " add - Add a package file to the source cache\n"
1758 " gencaches - Build both the package and source cache\n"
1759 " showpkg - Show some general information for a single package\n"
1760 " showsrc - Show source records\n"
1761 " stats - Show some basic statistics\n"
1762 " dump - Show the entire file in a terse form\n"
1763 " dumpavail - Print an available file to stdout\n"
1764 " unmet - Show unmet dependencies\n"
1765 " search - Search the package list for a regex pattern\n"
1766 " show - Show a readable record for the package\n"
1767 " showauto - Display a list of automatically installed packages\n"
1768 " depends - Show raw dependency information for a package\n"
1769 " rdepends - Show reverse dependency information for a package\n"
1770 " pkgnames - List the names of all packages in the system\n"
1771 " dotty - Generate package graphs for GraphViz\n"
1772 " xvcg - Generate package graphs for xvcg\n"
1773 " policy - Show policy settings\n"
1774 "\n"
1775 "Options:\n"
1776 " -h This help text.\n"
1777 " -p=? The package cache.\n"
1778 " -s=? The source cache.\n"
1779 " -q Disable progress indicator.\n"
1780 " -i Show only important deps for the unmet command.\n"
1781 " -c=? Read this configuration file\n"
1782 " -o=? Set an arbitrary configuration option, eg -o dir::cache=/tmp\n"
1783 "See the apt-cache(8) and apt.conf(5) manual pages for more information.\n");
1784 return true;
1785 }
1786 /*}}}*/
1787 // CacheInitialize - Initialize things for apt-cache /*{{{*/
1788 // ---------------------------------------------------------------------
1789 /* */
1790 void CacheInitialize()
1791 {
1792 _config->Set("quiet",0);
1793 _config->Set("help",false);
1794 }
1795 /*}}}*/
1796 int main(int argc,const char *argv[]) /*{{{*/
1797 {
1798 CommandLine::Args Args[] = {
1799 {'h',"help","help",0},
1800 {'v',"version","version",0},
1801 {'p',"pkg-cache","Dir::Cache::pkgcache",CommandLine::HasArg},
1802 {'s',"src-cache","Dir::Cache::srcpkgcache",CommandLine::HasArg},
1803 {'q',"quiet","quiet",CommandLine::IntLevel},
1804 {'i',"important","APT::Cache::Important",0},
1805 {'f',"full","APT::Cache::ShowFull",0},
1806 {'g',"generate","APT::Cache::Generate",0},
1807 {'a',"all-versions","APT::Cache::AllVersions",0},
1808 {'n',"names-only","APT::Cache::NamesOnly",0},
1809 {0,"all-names","APT::Cache::AllNames",0},
1810 {0,"recurse","APT::Cache::RecurseDepends",0},
1811 {'c',"config-file",0,CommandLine::ConfigFile},
1812 {'o',"option",0,CommandLine::ArbItem},
1813 {0,"installed","APT::Cache::Installed",0},
1814 {0,0,0,0}};
1815 CommandLine::Dispatch CmdsA[] = {{"help",&ShowHelp},
1816 {"add",&DoAdd},
1817 {"gencaches",&GenCaches},
1818 {"showsrc",&ShowSrcPackage},
1819 {0,0}};
1820 CommandLine::Dispatch CmdsB[] = {{"showpkg",&DumpPackage},
1821 {"stats",&Stats},
1822 {"dump",&Dump},
1823 {"dumpavail",&DumpAvail},
1824 {"unmet",&UnMet},
1825 {"search",&Search},
1826 {"depends",&Depends},
1827 {"rdepends",&RDepends},
1828 {"dotty",&Dotty},
1829 {"xvcg",&XVcg},
1830 {"show",&ShowPackage},
1831 {"pkgnames",&ShowPkgNames},
1832 {"showauto",&ShowAuto},
1833 {"policy",&Policy},
1834 {"madison",&Madison},
1835 {0,0}};
1836
1837 CacheInitialize();
1838
1839 // Set up gettext support
1840 setlocale(LC_ALL,"");
1841 textdomain(PACKAGE);
1842
1843 // Parse the command line and initialize the package library
1844 CommandLine CmdL(Args,_config);
1845 if (pkgInitConfig(*_config) == false ||
1846 CmdL.Parse(argc,argv) == false ||
1847 pkgInitSystem(*_config,_system) == false)
1848 {
1849 _error->DumpErrors();
1850 return 100;
1851 }
1852
1853 // See if the help should be shown
1854 if (_config->FindB("help") == true ||
1855 CmdL.FileSize() == 0)
1856 {
1857 ShowHelp(CmdL);
1858 return 0;
1859 }
1860
1861 // Deal with stdout not being a tty
1862 if (isatty(STDOUT_FILENO) && _config->FindI("quiet",0) < 1)
1863 _config->Set("quiet","1");
1864
1865 if (CmdL.DispatchArg(CmdsA,false) == false && _error->PendingError() == false)
1866 {
1867 MMap *Map = 0;
1868 if (_config->FindB("APT::Cache::Generate",true) == false)
1869 {
1870 Map = new MMap(*new FileFd(_config->FindFile("Dir::Cache::pkgcache"),
1871 FileFd::ReadOnly),MMap::Public|MMap::ReadOnly);
1872 }
1873 else
1874 {
1875 // Open the cache file
1876 SrcList = new pkgSourceList;
1877 SrcList->ReadMainList();
1878
1879 // Generate it and map it
1880 OpProgress Prog;
1881 pkgMakeStatusCache(*SrcList,Prog,&Map,true);
1882 }
1883
1884 if (_error->PendingError() == false)
1885 {
1886 pkgCache Cache(Map);
1887 GCache = &Cache;
1888 if (_error->PendingError() == false)
1889 CmdL.DispatchArg(CmdsB);
1890 }
1891 delete Map;
1892 }
1893
1894 // Print any errors or warnings found during parsing
1895 if (_error->empty() == false)
1896 {
1897 bool Errors = _error->PendingError();
1898 _error->DumpErrors();
1899 return Errors == true?100:0;
1900 }
1901
1902 return 0;
1903 }
1904 /*}}}*/