You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

534 lines
18 KiB

  1. // Includes /*{{{*/
  2. #include <config.h>
  3. #include <apt-pkg/cachefile.h>
  4. #include <apt-pkg/cacheset.h>
  5. #include <apt-pkg/cmndline.h>
  6. #include <apt-pkg/configuration.h>
  7. #include <apt-pkg/depcache.h>
  8. #include <apt-pkg/error.h>
  9. #include <apt-pkg/fileutl.h>
  10. #include <apt-pkg/indexfile.h>
  11. #include <apt-pkg/macros.h>
  12. #include <apt-pkg/pkgcache.h>
  13. #include <apt-pkg/pkgrecords.h>
  14. #include <apt-pkg/pkgsystem.h>
  15. #include <apt-pkg/policy.h>
  16. #include <apt-pkg/sourcelist.h>
  17. #include <apt-pkg/strutl.h>
  18. #include <apt-pkg/tagfile.h>
  19. #include <apt-private/private-cacheset.h>
  20. #include <apt-private/private-output.h>
  21. #include <apt-private/private-install.h>
  22. #include <apt-private/private-show.h>
  23. #include <ostream>
  24. #include <string>
  25. #include <stdio.h>
  26. #include <unistd.h>
  27. #include <apti18n.h>
  28. /*}}}*/
  29. pkgRecords::Parser &LookupParser(pkgRecords &Recs, pkgCache::VerIterator const &V, pkgCache::VerFileIterator &Vf) /*{{{*/
  30. {
  31. Vf = V.FileList();
  32. for (; Vf.end() == false; ++Vf)
  33. if ((Vf.File()->Flags & pkgCache::Flag::NotSource) == 0)
  34. break;
  35. if (Vf.end() == true)
  36. Vf = V.FileList();
  37. return Recs.Lookup(Vf);
  38. }
  39. /*}}}*/
  40. static APT_PURE char const *skipDescriptionFields(char const *DescP, size_t const Length) /*{{{*/
  41. {
  42. auto const backup = DescP;
  43. char const * const TagName = "\nDescription";
  44. size_t const TagLen = strlen(TagName);
  45. while ((DescP = static_cast<char const *>(memchr(DescP, '\n', Length - (DescP - backup)))) != nullptr)
  46. {
  47. if (DescP[1] == ' ')
  48. DescP += 2;
  49. else if (strncmp((char*)DescP, TagName, TagLen) == 0)
  50. DescP += TagLen;
  51. else
  52. break;
  53. }
  54. if (DescP != NULL)
  55. ++DescP;
  56. return DescP;
  57. }
  58. /*}}}*/
  59. static APT_PURE char const *findDescriptionField(char const *DescP, size_t const Length) /*{{{*/
  60. {
  61. auto const backup = DescP;
  62. char const * const TagName = "\nDescription";
  63. size_t const TagLen = strlen(TagName);
  64. while ((DescP = static_cast<char const *>(memchr(DescP, '\n', Length - (DescP - backup)))) != nullptr)
  65. {
  66. if (strncmp(DescP, TagName, TagLen) == 0)
  67. break;
  68. else
  69. ++DescP;
  70. }
  71. if (DescP != nullptr)
  72. ++DescP;
  73. return DescP;
  74. }
  75. /*}}}*/
  76. bool DisplayRecordV1(pkgCacheFile &, pkgRecords &Recs, /*{{{*/
  77. pkgCache::VerIterator const &V, pkgCache::VerFileIterator const &,
  78. char const *Buffer, size_t Length, std::ostream &out)
  79. {
  80. if (unlikely(Length == 0))
  81. return false;
  82. auto const Desc = V.TranslatedDescription();
  83. if (Desc.end())
  84. {
  85. // we have no translation output whatever we have got
  86. return FileFd::Write(STDOUT_FILENO, Buffer, Length);
  87. }
  88. // Get a pointer to start of Description field
  89. char const *DescP = findDescriptionField(Buffer, Length);
  90. if (DescP == nullptr)
  91. DescP = Buffer + Length;
  92. // Write all but Description
  93. size_t const untilDesc = DescP - Buffer;
  94. if (untilDesc != 0 && FileFd::Write(STDOUT_FILENO, Buffer, untilDesc) == false)
  95. return false;
  96. // Show the right description
  97. char desctag[50];
  98. auto const langcode = Desc.LanguageCode();
  99. if (strcmp(langcode, "") == 0)
  100. strcpy(desctag, "\nDescription");
  101. else
  102. snprintf(desctag, sizeof(desctag), "\nDescription-%s", langcode);
  103. out << desctag + 1 << ": ";
  104. auto const Df = Desc.FileList();
  105. if (Df.end() == false)
  106. {
  107. pkgRecords::Parser &P = Recs.Lookup(Df);
  108. out << P.LongDesc();
  109. }
  110. out << std::endl << "Description-md5: " << Desc.md5() << std::endl;
  111. // Find the first field after the description (if there is any)
  112. DescP = skipDescriptionFields(DescP, Length - (DescP - Buffer));
  113. // write the rest of the buffer, but skip mixed in Descriptions* fields
  114. while (DescP != nullptr)
  115. {
  116. char const *const Start = DescP;
  117. char const *End = findDescriptionField(DescP, Length - (DescP - Buffer));
  118. if (End == nullptr)
  119. {
  120. DescP = nullptr;
  121. End = Buffer + Length - 1;
  122. size_t endings = 0;
  123. while (*End == '\n')
  124. {
  125. --End;
  126. if (*End == '\r')
  127. --End;
  128. ++endings;
  129. }
  130. if (endings >= 1)
  131. {
  132. ++End;
  133. if (*End == '\r')
  134. ++End;
  135. }
  136. ++End;
  137. }
  138. else
  139. DescP = skipDescriptionFields(End + strlen("Description"), Length - (End - Buffer));
  140. size_t const length = End - Start;
  141. if (length != 0 && FileFd::Write(STDOUT_FILENO, Start, length) == false)
  142. return false;
  143. }
  144. // write a final newline after the last field
  145. out << std::endl;
  146. return true;
  147. }
  148. /*}}}*/
  149. static bool DisplayRecordV2(pkgCacheFile &CacheFile, pkgRecords &Recs, /*{{{*/
  150. pkgCache::VerIterator const &V, pkgCache::VerFileIterator const &Vf,
  151. char const *Buffer, size_t const Length, std::ostream &out)
  152. {
  153. // Check and load the package list file
  154. pkgCache::PkgFileIterator I = Vf.File();
  155. // find matching sources.list metaindex
  156. pkgSourceList *SrcList = CacheFile.GetSourceList();
  157. pkgIndexFile *Index;
  158. if (SrcList->FindIndex(I, Index) == false &&
  159. _system->FindIndex(I, Index) == false)
  160. return _error->Error("Can not find indexfile for Package %s (%s)",
  161. V.ParentPkg().Name(), V.VerStr());
  162. std::string source_index_file = Index->Describe(true);
  163. // Read the record
  164. pkgTagSection Tags;
  165. if (Tags.Scan(Buffer, Length, true) == false)
  166. return _error->Error("Internal Error, Unable to parse a package record");
  167. // make size nice
  168. std::string installed_size;
  169. if (Tags.FindULL("Installed-Size") > 0)
  170. strprintf(installed_size, "%sB", SizeToStr(Tags.FindULL("Installed-Size") * 1024).c_str());
  171. else
  172. installed_size = _("unknown");
  173. std::string package_size;
  174. if (Tags.FindULL("Size") > 0)
  175. strprintf(package_size, "%sB", SizeToStr(Tags.FindULL("Size")).c_str());
  176. else
  177. package_size = _("unknown");
  178. const char *manual_installed = nullptr;
  179. if (V.ParentPkg().CurrentVer() == V)
  180. {
  181. pkgDepCache *depCache = CacheFile.GetDepCache();
  182. if (unlikely(depCache == nullptr))
  183. return false;
  184. pkgDepCache::StateCache &state = (*depCache)[V.ParentPkg()];
  185. manual_installed = !(state.Flags & pkgCache::Flag::Auto) ? "yes" : "no";
  186. }
  187. // FIXME: add verbose that does not do the removal of the tags?
  188. std::vector<pkgTagSection::Tag> RW;
  189. // delete, apt-cache show has this info and most users do not care
  190. RW.push_back(pkgTagSection::Tag::Remove("MD5sum"));
  191. RW.push_back(pkgTagSection::Tag::Remove("SHA1"));
  192. RW.push_back(pkgTagSection::Tag::Remove("SHA256"));
  193. RW.push_back(pkgTagSection::Tag::Remove("SHA512"));
  194. RW.push_back(pkgTagSection::Tag::Remove("Filename"));
  195. RW.push_back(pkgTagSection::Tag::Remove("Multi-Arch"));
  196. RW.push_back(pkgTagSection::Tag::Remove("Architecture"));
  197. RW.push_back(pkgTagSection::Tag::Remove("Conffiles"));
  198. // we use the translated description
  199. RW.push_back(pkgTagSection::Tag::Remove("Description"));
  200. RW.push_back(pkgTagSection::Tag::Remove("Description-md5"));
  201. // improve
  202. RW.push_back(pkgTagSection::Tag::Rewrite("Package", V.ParentPkg().FullName(true)));
  203. RW.push_back(pkgTagSection::Tag::Rewrite("Installed-Size", installed_size));
  204. RW.push_back(pkgTagSection::Tag::Remove("Size"));
  205. RW.push_back(pkgTagSection::Tag::Rewrite("Download-Size", package_size));
  206. // add
  207. if (manual_installed != nullptr)
  208. RW.push_back(pkgTagSection::Tag::Rewrite("APT-Manual-Installed", manual_installed));
  209. RW.push_back(pkgTagSection::Tag::Rewrite("APT-Sources", source_index_file));
  210. FileFd stdoutfd;
  211. if (stdoutfd.OpenDescriptor(STDOUT_FILENO, FileFd::WriteOnly, false) == false ||
  212. Tags.Write(stdoutfd, TFRewritePackageOrder, RW) == false || stdoutfd.Close() == false)
  213. return _error->Error("Internal Error, Unable to parse a package record");
  214. // write the description
  215. // FIXME: show (optionally) all available translations(?)
  216. pkgCache::DescIterator Desc = V.TranslatedDescription();
  217. if (Desc.end() == false)
  218. {
  219. pkgRecords::Parser &P = Recs.Lookup(Desc.FileList());
  220. out << "Description: " << P.LongDesc();
  221. }
  222. // write a final newline (after the description)
  223. out << std::endl << std::endl;
  224. return true;
  225. }
  226. /*}}}*/
  227. bool ShowPackage(CommandLine &CmdL) /*{{{*/
  228. {
  229. pkgCacheFile CacheFile;
  230. auto VolatileCmdL = GetAllPackagesAsPseudo(CacheFile.GetSourceList(), CmdL, AddVolatileBinaryFile, "");
  231. if (unlikely(CacheFile.GetPkgCache() == nullptr))
  232. return false;
  233. CacheSetHelperVirtuals helper(true, GlobalError::NOTICE);
  234. APT::CacheSetHelper::VerSelector const select = _config->FindB("APT::Cache::AllVersions", true) ?
  235. APT::CacheSetHelper::ALL : APT::CacheSetHelper::CANDIDATE;
  236. if (select == APT::CacheSetHelper::CANDIDATE && CacheFile.GetDepCache() == nullptr)
  237. return false;
  238. APT::VersionList verset;
  239. size_t normalPackages = 0;
  240. for (auto const &I: VolatileCmdL)
  241. {
  242. if (I.index == -1)
  243. {
  244. APT::VersionContainerInterface::FromString(&verset, CacheFile, I.name, select, helper);
  245. ++normalPackages;
  246. }
  247. else
  248. {
  249. if (select != APT::CacheSetHelper::CANDIDATE && unlikely(CacheFile.GetDepCache() == nullptr))
  250. return false;
  251. pkgCache::PkgIterator const P = CacheFile->FindPkg(I.name);
  252. if (unlikely(P.end()))
  253. continue;
  254. // Set any version providing the .deb as the candidate.
  255. for (auto Prv = P.ProvidesList(); Prv.end() == false; ++Prv)
  256. {
  257. if (I.release.empty())
  258. CacheFile->SetCandidateVersion(Prv.OwnerVer());
  259. else
  260. CacheFile->SetCandidateRelease(Prv.OwnerVer(), I.release);
  261. // via cacheset to have our usual handling
  262. APT::VersionContainerInterface::FromPackage(&verset, CacheFile, Prv.OwnerPkg(), APT::CacheSetHelper::CANDIDATE, helper);
  263. }
  264. }
  265. }
  266. int const ShowVersion = _config->FindI("APT::Cache::Show::Version", 1);
  267. pkgRecords Recs(CacheFile);
  268. for (APT::VersionList::const_iterator Ver = verset.begin(); Ver != verset.end(); ++Ver)
  269. {
  270. pkgCache::VerFileIterator Vf;
  271. auto &Parser = LookupParser(Recs, Ver, Vf);
  272. char const *Start, *Stop;
  273. Parser.GetRec(Start, Stop);
  274. size_t const Length = Stop - Start;
  275. if (ShowVersion <= 1)
  276. {
  277. if (DisplayRecordV1(CacheFile, Recs, Ver, Vf, Start, Length, std::cout) == false)
  278. return false;
  279. }
  280. else if (DisplayRecordV2(CacheFile, Recs, Ver, Vf, Start, Length + 1, c1out) == false)
  281. return false;
  282. }
  283. if (select == APT::CacheSetHelper::CANDIDATE && normalPackages != 0)
  284. {
  285. APT::VersionList verset_all;
  286. for (auto const &I: VolatileCmdL)
  287. {
  288. if (I.index == -1)
  289. APT::VersionContainerInterface::FromString(&verset_all, CacheFile, I.name, APT::CacheSetHelper::ALL, helper);
  290. else
  291. {
  292. pkgCache::PkgIterator const P = CacheFile->FindPkg(I.name);
  293. if (unlikely(P.end()))
  294. continue;
  295. // Set any version providing the .deb as the candidate.
  296. for (auto Prv = P.ProvidesList(); Prv.end() == false; ++Prv)
  297. {
  298. if (I.release.empty())
  299. CacheFile->SetCandidateVersion(Prv.OwnerVer());
  300. else
  301. CacheFile->SetCandidateRelease(Prv.OwnerVer(), I.release);
  302. // via cacheset to have our usual virtual handling
  303. APT::VersionContainerInterface::FromPackage(&verset_all, CacheFile, Prv.OwnerPkg(), APT::CacheSetHelper::CANDIDATE, helper);
  304. }
  305. }
  306. }
  307. int const records = verset_all.size() - verset.size();
  308. if (records > 0)
  309. _error->Notice(P_("There is %i additional record. Please use the '-a' switch to see it", "There are %i additional records. Please use the '-a' switch to see them.", records), records);
  310. }
  311. if (_config->FindB("APT::Cache::ShowVirtuals", false) == true)
  312. for (APT::PackageSet::const_iterator Pkg = helper.virtualPkgs.begin();
  313. Pkg != helper.virtualPkgs.end(); ++Pkg)
  314. {
  315. c1out << "Package: " << Pkg.FullName(true) << std::endl;
  316. c1out << "State: " << _("not a real package (virtual)") << std::endl;
  317. // FIXME: show providers, see private-cacheset.h
  318. // CacheSetHelperAPTGet::showVirtualPackageErrors()
  319. }
  320. if (verset.empty() == true)
  321. {
  322. if (helper.virtualPkgs.empty() == true)
  323. return _error->Error(_("No packages found"));
  324. else
  325. _error->Notice(_("No packages found"));
  326. }
  327. return true;
  328. }
  329. /*}}}*/
  330. static std::string Sha1FromString(std::string const &input) /*{{{*/
  331. {
  332. // XXX: move to hashes.h: HashString::FromString() ?
  333. SHA1Summation sha1;
  334. sha1.Add(input.c_str(), input.length());
  335. return sha1.Result().Value();
  336. }
  337. /*}}}*/
  338. bool ShowSrcPackage(CommandLine &CmdL) /*{{{*/
  339. {
  340. pkgCacheFile CacheFile;
  341. pkgSourceList *List = CacheFile.GetSourceList();
  342. if (unlikely(List == NULL))
  343. return false;
  344. // Create the text record parsers
  345. pkgSrcRecords SrcRecs(*List);
  346. if (_error->PendingError() == true)
  347. return false;
  348. bool found = false;
  349. // avoid showing identical records
  350. std::set<std::string> seen;
  351. for (const char **I = CmdL.FileList + 1; *I != 0; I++)
  352. {
  353. SrcRecs.Restart();
  354. pkgSrcRecords::Parser *Parse;
  355. bool found_this = false;
  356. while ((Parse = SrcRecs.Find(*I,false)) != 0) {
  357. // SrcRecs.Find() will find both binary and source names
  358. if (_config->FindB("APT::Cache::Only-Source", false) == true)
  359. if (Parse->Package() != *I)
  360. continue;
  361. std::string sha1str = Sha1FromString(Parse->AsStr());
  362. if (std::find(seen.begin(), seen.end(), sha1str) == seen.end())
  363. {
  364. std::cout << Parse->AsStr() << std::endl;;
  365. found = true;
  366. found_this = true;
  367. seen.insert(sha1str);
  368. }
  369. }
  370. if (found_this == false) {
  371. _error->Warning(_("Unable to locate package %s"),*I);
  372. continue;
  373. }
  374. }
  375. if (found == false)
  376. _error->Notice(_("No packages found"));
  377. return true;
  378. }
  379. /*}}}*/
  380. // Policy - Show the results of the preferences file /*{{{*/
  381. bool Policy(CommandLine &CmdL)
  382. {
  383. pkgCacheFile CacheFile;
  384. pkgSourceList const * const SrcList = CacheFile.GetSourceList();
  385. if (unlikely(SrcList == nullptr))
  386. return false;
  387. pkgCache * const Cache = CacheFile.GetPkgCache();
  388. if (unlikely(Cache == nullptr))
  389. return false;
  390. pkgPolicy * const Plcy = CacheFile.GetPolicy();
  391. if (unlikely(Plcy == nullptr))
  392. return false;
  393. // Print out all of the package files
  394. if (CmdL.FileList[1] == 0)
  395. {
  396. std::cout << _("Package files:") << std::endl;
  397. for (pkgCache::PkgFileIterator F = Cache->FileBegin(); F.end() == false; ++F)
  398. {
  399. if (F.Flagged(pkgCache::Flag::NoPackages))
  400. continue;
  401. // Locate the associated index files so we can derive a description
  402. pkgIndexFile *Indx;
  403. if (SrcList->FindIndex(F,Indx) == false &&
  404. _system->FindIndex(F,Indx) == false)
  405. return _error->Error(_("Cache is out of sync, can't x-ref a package file"));
  406. printf("%4i %s\n",
  407. Plcy->GetPriority(F),Indx->Describe(true).c_str());
  408. // Print the reference information for the package
  409. std::string Str = F.RelStr();
  410. if (Str.empty() == false)
  411. printf(" release %s\n",F.RelStr().c_str());
  412. if (F.Site() != 0 && F.Site()[0] != 0)
  413. printf(" origin %s\n",F.Site());
  414. }
  415. // Show any packages have explicit pins
  416. std::cout << _("Pinned packages:") << std::endl;
  417. pkgCache::PkgIterator I = Cache->PkgBegin();
  418. for (;I.end() != true; ++I)
  419. {
  420. for (pkgCache::VerIterator V = I.VersionList(); !V.end(); ++V) {
  421. auto Prio = Plcy->GetPriority(V, false);
  422. if (Prio == 0)
  423. continue;
  424. std::cout << " ";
  425. // Print the package name and the version we are forcing to
  426. ioprintf(std::cout, _("%s -> %s with priority %d\n"), I.FullName(true).c_str(), V.VerStr(), Prio);
  427. }
  428. }
  429. return true;
  430. }
  431. char const * const msgInstalled = _(" Installed: ");
  432. char const * const msgCandidate = _(" Candidate: ");
  433. short const InstalledLessCandidate =
  434. mbstowcs(NULL, msgInstalled, 0) - mbstowcs(NULL, msgCandidate, 0);
  435. short const deepInstalled =
  436. (InstalledLessCandidate < 0 ? (InstalledLessCandidate*-1) : 0) - 1;
  437. short const deepCandidate =
  438. (InstalledLessCandidate > 0 ? (InstalledLessCandidate) : 0) - 1;
  439. // Print out detailed information for each package
  440. APT::CacheSetHelper helper(true, GlobalError::NOTICE);
  441. APT::PackageList pkgset = APT::PackageList::FromCommandLine(CacheFile, CmdL.FileList + 1, helper);
  442. for (APT::PackageList::const_iterator Pkg = pkgset.begin(); Pkg != pkgset.end(); ++Pkg)
  443. {
  444. std::cout << Pkg.FullName(true) << ":" << std::endl;
  445. // Installed version
  446. std::cout << msgInstalled << OutputInDepth(deepInstalled, " ");
  447. if (Pkg->CurrentVer == 0)
  448. std::cout << _("(none)") << std::endl;
  449. else
  450. std::cout << Pkg.CurrentVer().VerStr() << std::endl;
  451. // Candidate Version
  452. std::cout << msgCandidate << OutputInDepth(deepCandidate, " ");
  453. pkgCache::VerIterator V = Plcy->GetCandidateVer(Pkg);
  454. if (V.end() == true)
  455. std::cout << _("(none)") << std::endl;
  456. else
  457. std::cout << V.VerStr() << std::endl;
  458. // Show the priority tables
  459. std::cout << _(" Version table:") << std::endl;
  460. for (V = Pkg.VersionList(); V.end() == false; ++V)
  461. {
  462. if (Pkg.CurrentVer() == V)
  463. std::cout << " *** " << V.VerStr();
  464. else
  465. std::cout << " " << V.VerStr();
  466. std::cout << " " << Plcy->GetPriority(V) << std::endl;
  467. for (pkgCache::VerFileIterator VF = V.FileList(); VF.end() == false; ++VF)
  468. {
  469. // Locate the associated index files so we can derive a description
  470. pkgIndexFile *Indx;
  471. if (SrcList->FindIndex(VF.File(),Indx) == false &&
  472. _system->FindIndex(VF.File(),Indx) == false)
  473. return _error->Error(_("Cache is out of sync, can't x-ref a package file"));
  474. printf(" %4i %s\n",Plcy->GetPriority(VF.File()),
  475. Indx->Describe(true).c_str());
  476. }
  477. }
  478. }
  479. return true;
  480. }
  481. /*}}}*/