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