private-show.cc 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  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/error.h>
  7. #include <apt-pkg/fileutl.h>
  8. #include <apt-pkg/indexfile.h>
  9. #include <apt-pkg/pkgrecords.h>
  10. #include <apt-pkg/pkgsystem.h>
  11. #include <apt-pkg/sourcelist.h>
  12. #include <apt-pkg/strutl.h>
  13. #include <apt-pkg/tagfile.h>
  14. #include <apt-pkg/cacheiterators.h>
  15. #include <apt-pkg/configuration.h>
  16. #include <apt-pkg/depcache.h>
  17. #include <apt-pkg/macros.h>
  18. #include <apt-pkg/pkgcache.h>
  19. #include <apt-private/private-cacheset.h>
  20. #include <apt-private/private-output.h>
  21. #include <apt-private/private-show.h>
  22. #include <stdio.h>
  23. #include <ostream>
  24. #include <string>
  25. #include <apti18n.h>
  26. /*}}}*/
  27. static bool OpenPackagesFile(pkgCacheFile &CacheFile, pkgCache::VerIterator const &V,/*{{{*/
  28. FileFd &PkgF, pkgCache::VerFileIterator &Vf)
  29. {
  30. pkgCache const * const Cache = CacheFile.GetPkgCache();
  31. if (unlikely(Cache == NULL))
  32. return false;
  33. // Find an appropriate file
  34. Vf = V.FileList();
  35. for (; Vf.end() == false; ++Vf)
  36. if ((Vf.File()->Flags & pkgCache::Flag::NotSource) == 0)
  37. break;
  38. if (Vf.end() == true)
  39. Vf = V.FileList();
  40. // Check and load the package list file
  41. pkgCache::PkgFileIterator I = Vf.File();
  42. if (I.IsOk() == false)
  43. return _error->Error(_("Package file %s is out of sync."),I.FileName());
  44. // Read the record
  45. return PkgF.Open(I.FileName(), FileFd::ReadOnly, FileFd::Extension);
  46. }
  47. /*}}}*/
  48. static APT_PURE unsigned char const* skipDescriptionFields(unsigned char const * DescP)/*{{{*/
  49. {
  50. char const * const TagName = "\nDescription";
  51. size_t const TagLen = strlen(TagName);
  52. while ((DescP = (unsigned char*)strchr((char*)DescP, '\n')) != NULL)
  53. {
  54. if (DescP[1] == ' ')
  55. DescP += 2;
  56. else if (strncmp((char*)DescP, TagName, TagLen) == 0)
  57. DescP += TagLen;
  58. else
  59. break;
  60. }
  61. if (DescP != NULL)
  62. ++DescP;
  63. return DescP;
  64. }
  65. /*}}}*/
  66. bool DisplayRecordV1(pkgCacheFile &CacheFile, pkgCache::VerIterator const &V,/*{{{*/
  67. std::ostream &out)
  68. {
  69. FileFd PkgF;
  70. pkgCache::VerFileIterator Vf;
  71. if (OpenPackagesFile(CacheFile, V, PkgF, Vf) == false)
  72. return false;
  73. pkgCache * const Cache = CacheFile.GetPkgCache();
  74. if (unlikely(Cache == NULL))
  75. return false;
  76. // Read the record (and ensure that it ends with a newline and NUL)
  77. unsigned char *Buffer = new unsigned char[Cache->HeaderP->MaxVerFileSize+2];
  78. Buffer[Vf->Size] = '\n';
  79. Buffer[Vf->Size+1] = '\0';
  80. if (PkgF.Seek(Vf->Offset) == false ||
  81. PkgF.Read(Buffer,Vf->Size) == false)
  82. {
  83. delete [] Buffer;
  84. return false;
  85. }
  86. // Get a pointer to start of Description field
  87. const unsigned char *DescP = (unsigned char*)strstr((char*)Buffer, "\nDescription");
  88. if (DescP != NULL)
  89. ++DescP;
  90. else
  91. DescP = Buffer + Vf->Size;
  92. // Write all but Description
  93. size_t const length = DescP - Buffer;
  94. if (length != 0 && FileFd::Write(STDOUT_FILENO, Buffer, length) == false)
  95. {
  96. delete [] Buffer;
  97. return false;
  98. }
  99. // Show the right description
  100. pkgRecords Recs(*Cache);
  101. pkgCache::DescIterator Desc = V.TranslatedDescription();
  102. if (Desc.end() == false)
  103. {
  104. pkgRecords::Parser &P = Recs.Lookup(Desc.FileList());
  105. out << "Description" << ( (strcmp(Desc.LanguageCode(),"") != 0) ? "-" : "" ) << Desc.LanguageCode() << ": " << P.LongDesc();
  106. out << std::endl << "Description-md5: " << Desc.md5() << std::endl;
  107. // Find the first field after the description (if there is any)
  108. DescP = skipDescriptionFields(DescP);
  109. }
  110. // else we have no translation, so we found a lonely Description-md5 -> don't skip it
  111. // write the rest of the buffer, but skip mixed in Descriptions* fields
  112. while (DescP != NULL)
  113. {
  114. const unsigned char * const Start = DescP;
  115. const unsigned char *End = (unsigned char*)strstr((char*)DescP, "\nDescription");
  116. if (End == NULL)
  117. {
  118. End = &Buffer[Vf->Size];
  119. DescP = NULL;
  120. }
  121. else
  122. {
  123. ++End; // get the newline into the output
  124. DescP = skipDescriptionFields(End + strlen("Description"));
  125. }
  126. size_t const length = End - Start;
  127. if (length != 0 && FileFd::Write(STDOUT_FILENO, Start, length) == false)
  128. {
  129. delete [] Buffer;
  130. return false;
  131. }
  132. }
  133. // write a final newline after the last field
  134. out << std::endl;
  135. delete [] Buffer;
  136. return true;
  137. }
  138. /*}}}*/
  139. static bool DisplayRecordV2(pkgCacheFile &CacheFile, pkgCache::VerIterator const &V,/*{{{*/
  140. std::ostream &out)
  141. {
  142. FileFd PkgF;
  143. pkgCache::VerFileIterator Vf;
  144. if (OpenPackagesFile(CacheFile, V, PkgF, Vf) == false)
  145. return false;
  146. // Check and load the package list file
  147. pkgCache::PkgFileIterator I = Vf.File();
  148. if (I.IsOk() == false)
  149. return _error->Error(_("Package file %s is out of sync."),I.FileName());
  150. // find matching sources.list metaindex
  151. pkgSourceList *SrcList = CacheFile.GetSourceList();
  152. pkgIndexFile *Index;
  153. if (SrcList->FindIndex(I, Index) == false &&
  154. _system->FindIndex(I, Index) == false)
  155. return _error->Error("Can not find indexfile for Package %s (%s)",
  156. V.ParentPkg().Name(), V.VerStr());
  157. std::string source_index_file = Index->Describe(true);
  158. // Read the record
  159. pkgTagSection Tags;
  160. pkgTagFile TagF(&PkgF);
  161. if (TagF.Jump(Tags, V.FileList()->Offset) == false)
  162. return _error->Error("Internal Error, Unable to parse a package record");
  163. // make size nice
  164. std::string installed_size;
  165. if (Tags.FindI("Installed-Size") > 0)
  166. strprintf(installed_size, "%sB", SizeToStr(Tags.FindI("Installed-Size")*1024).c_str());
  167. else
  168. installed_size = _("unknown");
  169. std::string package_size;
  170. if (Tags.FindI("Size") > 0)
  171. strprintf(package_size, "%sB", SizeToStr(Tags.FindI("Size")).c_str());
  172. else
  173. package_size = _("unknown");
  174. const char *manual_installed = nullptr;
  175. if (V.ParentPkg().CurrentVer() == V)
  176. {
  177. pkgDepCache *depCache = CacheFile.GetDepCache();
  178. if (unlikely(depCache == nullptr))
  179. return false;
  180. pkgDepCache::StateCache &state = (*depCache)[V.ParentPkg()];
  181. manual_installed = !(state.Flags & pkgCache::Flag::Auto) ? "yes" : "no";
  182. }
  183. // FIXME: add verbose that does not do the removal of the tags?
  184. std::vector<pkgTagSection::Tag> RW;
  185. // delete, apt-cache show has this info and most users do not care
  186. RW.push_back(pkgTagSection::Tag::Remove("MD5sum"));
  187. RW.push_back(pkgTagSection::Tag::Remove("SHA1"));
  188. RW.push_back(pkgTagSection::Tag::Remove("SHA256"));
  189. RW.push_back(pkgTagSection::Tag::Remove("SHA512"));
  190. RW.push_back(pkgTagSection::Tag::Remove("Filename"));
  191. RW.push_back(pkgTagSection::Tag::Remove("Multi-Arch"));
  192. RW.push_back(pkgTagSection::Tag::Remove("Architecture"));
  193. RW.push_back(pkgTagSection::Tag::Remove("Conffiles"));
  194. // we use the translated description
  195. RW.push_back(pkgTagSection::Tag::Remove("Description"));
  196. RW.push_back(pkgTagSection::Tag::Remove("Description-md5"));
  197. // improve
  198. RW.push_back(pkgTagSection::Tag::Rewrite("Installed-Size", installed_size));
  199. RW.push_back(pkgTagSection::Tag::Remove("Size"));
  200. RW.push_back(pkgTagSection::Tag::Rewrite("Download-Size", package_size));
  201. // add
  202. if (manual_installed != nullptr)
  203. RW.push_back(pkgTagSection::Tag::Rewrite("APT-Manual-Installed", manual_installed));
  204. RW.push_back(pkgTagSection::Tag::Rewrite("APT-Sources", source_index_file));
  205. FileFd stdoutfd;
  206. if (stdoutfd.OpenDescriptor(STDOUT_FILENO, FileFd::WriteOnly, false) == false ||
  207. Tags.Write(stdoutfd, TFRewritePackageOrder, RW) == false || stdoutfd.Close() == false)
  208. return _error->Error("Internal Error, Unable to parse a package record");
  209. // write the description
  210. pkgCache * const Cache = CacheFile.GetPkgCache();
  211. if (unlikely(Cache == NULL))
  212. return false;
  213. pkgRecords Recs(*Cache);
  214. // FIXME: show (optionally) all available translations(?)
  215. pkgCache::DescIterator Desc = V.TranslatedDescription();
  216. if (Desc.end() == false)
  217. {
  218. pkgRecords::Parser &P = Recs.Lookup(Desc.FileList());
  219. out << "Description: " << P.LongDesc();
  220. }
  221. // write a final newline (after the description)
  222. out << std::endl << std::endl;
  223. return true;
  224. }
  225. /*}}}*/
  226. bool ShowPackage(CommandLine &CmdL) /*{{{*/
  227. {
  228. pkgCacheFile CacheFile;
  229. CacheSetHelperVirtuals helper(true, GlobalError::NOTICE);
  230. APT::CacheSetHelper::VerSelector const select = _config->FindB("APT::Cache::AllVersions", true) ?
  231. APT::CacheSetHelper::ALL : APT::CacheSetHelper::CANDIDATE;
  232. APT::VersionList const verset = APT::VersionList::FromCommandLine(CacheFile, CmdL.FileList + 1, select, helper);
  233. int const ShowVersion = _config->FindI("APT::Cache::Show::Version", 1);
  234. for (APT::VersionList::const_iterator Ver = verset.begin(); Ver != verset.end(); ++Ver)
  235. if (ShowVersion <= 1)
  236. {
  237. if (DisplayRecordV1(CacheFile, Ver, std::cout) == false)
  238. return false;
  239. }
  240. else
  241. if (DisplayRecordV2(CacheFile, Ver, c1out) == false)
  242. return false;
  243. if (select == APT::CacheSetHelper::CANDIDATE)
  244. {
  245. APT::VersionList const verset_all = APT::VersionList::FromCommandLine(CacheFile, CmdL.FileList + 1, APT::CacheSetHelper::ALL, helper);
  246. int const records = verset_all.size() - verset.size();
  247. if (records > 0)
  248. _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);
  249. }
  250. if (_config->FindB("APT::Cache::ShowVirtuals", false) == true)
  251. for (APT::PackageSet::const_iterator Pkg = helper.virtualPkgs.begin();
  252. Pkg != helper.virtualPkgs.end(); ++Pkg)
  253. {
  254. c1out << "Package: " << Pkg.FullName(true) << std::endl;
  255. c1out << "State: " << _("not a real package (virtual)") << std::endl;
  256. // FIXME: show providers, see private-cacheset.h
  257. // CacheSetHelperAPTGet::showVirtualPackageErrors()
  258. }
  259. if (verset.empty() == true)
  260. {
  261. if (helper.virtualPkgs.empty() == true)
  262. return _error->Error(_("No packages found"));
  263. else
  264. _error->Notice(_("No packages found"));
  265. }
  266. return true;
  267. }
  268. /*}}}*/