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.
 
 
 
 
 
 

336 lines
8.5 KiB

  1. // -*- mode: cpp; mode: fold -*-
  2. // Description /*{{{*/
  3. /* ######################################################################
  4. APT Extract Templates - Program to extract debconf config and template
  5. files
  6. This is a simple program to extract config and template information
  7. from Debian packages. It can be used to speed up the preconfiguration
  8. process for debconf-enabled packages
  9. ##################################################################### */
  10. /*}}}*/
  11. // Include Files /*{{{*/
  12. #include <config.h>
  13. #include <apt-pkg/cmndline.h>
  14. #include <apt-pkg/configuration.h>
  15. #include <apt-pkg/debfile.h>
  16. #include <apt-pkg/deblistparser.h>
  17. #include <apt-pkg/dirstream.h>
  18. #include <apt-pkg/error.h>
  19. #include <apt-pkg/fileutl.h>
  20. #include <apt-pkg/init.h>
  21. #include <apt-pkg/mmap.h>
  22. #include <apt-pkg/pkgcache.h>
  23. #include <apt-pkg/pkgcachegen.h>
  24. #include <apt-pkg/pkgsystem.h>
  25. #include <apt-pkg/sourcelist.h>
  26. #include <apt-pkg/strutl.h>
  27. #include <apt-pkg/tagfile.h>
  28. #include <apt-pkg/version.h>
  29. #include <apt-private/private-cmndline.h>
  30. #include <apt-private/private-main.h>
  31. #include <iostream>
  32. #include <stdio.h>
  33. #include <stdlib.h>
  34. #include <string.h>
  35. #include <unistd.h>
  36. #include "apt-extracttemplates.h"
  37. #include <apti18n.h>
  38. /*}}}*/
  39. using namespace std;
  40. pkgCache *DebFile::Cache = 0;
  41. // DebFile::DebFile - Construct the DebFile object /*{{{*/
  42. // ---------------------------------------------------------------------
  43. /* */
  44. DebFile::DebFile(const char *debfile)
  45. : File(debfile, FileFd::ReadOnly), Control(NULL), ControlLen(0),
  46. DepOp(0), PreDepOp(0), Config(0), Template(0), Which(None)
  47. {
  48. }
  49. /*}}}*/
  50. // DebFile::~DebFile - Destruct the DebFile object /*{{{*/
  51. // ---------------------------------------------------------------------
  52. /* */
  53. DebFile::~DebFile()
  54. {
  55. delete [] Control;
  56. delete [] Config;
  57. delete [] Template;
  58. }
  59. /*}}}*/
  60. // DebFile::GetInstalledVer - Find out the installed version of a pkg /*{{{*/
  61. // ---------------------------------------------------------------------
  62. /* */
  63. string DebFile::GetInstalledVer(const string &package)
  64. {
  65. pkgCache::PkgIterator Pkg = Cache->FindPkg(package);
  66. if (Pkg.end() == false)
  67. {
  68. pkgCache::VerIterator V = Pkg.CurrentVer();
  69. if (V.end() == false)
  70. {
  71. return V.VerStr();
  72. }
  73. }
  74. return string();
  75. }
  76. /*}}}*/
  77. // DebFile::Go - Start extracting a debian package /*{{{*/
  78. // ---------------------------------------------------------------------
  79. /* */
  80. bool DebFile::Go()
  81. {
  82. debDebFile Deb(File);
  83. return Deb.ExtractTarMember(*this, "control.tar");
  84. }
  85. /*}}}*/
  86. // DebFile::DoItem examine element in package and mark /*{{{*/
  87. // ---------------------------------------------------------------------
  88. /* */
  89. bool DebFile::DoItem(Item &I, int &Fd)
  90. {
  91. if (strcmp(I.Name, "control") == 0)
  92. {
  93. delete [] Control;
  94. Control = new char[I.Size+3];
  95. Control[I.Size] = '\n';
  96. Control[I.Size + 1] = '\n';
  97. Control[I.Size + 2] = '\0';
  98. Which = IsControl;
  99. ControlLen = I.Size + 3;
  100. // make it call the Process method below. this is so evil
  101. Fd = -2;
  102. }
  103. else if (strcmp(I.Name, "config") == 0)
  104. {
  105. delete [] Config;
  106. Config = new char[I.Size+1];
  107. Config[I.Size] = 0;
  108. Which = IsConfig;
  109. Fd = -2;
  110. }
  111. else if (strcmp(I.Name, "templates") == 0)
  112. {
  113. delete [] Template;
  114. Template = new char[I.Size+1];
  115. Template[I.Size] = 0;
  116. Which = IsTemplate;
  117. Fd = -2;
  118. }
  119. else
  120. {
  121. // Ignore it
  122. Fd = -1;
  123. }
  124. return true;
  125. }
  126. /*}}}*/
  127. // DebFile::Process examine element in package and copy /*{{{*/
  128. // ---------------------------------------------------------------------
  129. /* */
  130. bool DebFile::Process(Item &/*I*/, const unsigned char *data,
  131. unsigned long long size, unsigned long long pos)
  132. {
  133. switch (Which)
  134. {
  135. case IsControl:
  136. memcpy(Control + pos, data, size);
  137. break;
  138. case IsConfig:
  139. memcpy(Config + pos, data, size);
  140. break;
  141. case IsTemplate:
  142. memcpy(Template + pos, data, size);
  143. break;
  144. default: /* throw it away */ ;
  145. }
  146. return true;
  147. }
  148. /*}}}*/
  149. // DebFile::ParseInfo - Parse control file for dependency info /*{{{*/
  150. // ---------------------------------------------------------------------
  151. /* */
  152. bool DebFile::ParseInfo()
  153. {
  154. if (Control == NULL) return false;
  155. pkgTagSection Section;
  156. if (Section.Scan(Control, ControlLen) == false)
  157. return false;
  158. Package = Section.FindS("Package");
  159. Version = GetInstalledVer(Package);
  160. const char *Start, *Stop;
  161. if (Section.Find("Depends", Start, Stop) == true)
  162. {
  163. while (1)
  164. {
  165. string P, V;
  166. unsigned int Op;
  167. Start = debListParser::ParseDepends(Start, Stop, P, V, Op);
  168. if (Start == 0) return false;
  169. if (P == "debconf")
  170. {
  171. DepVer = V;
  172. DepOp = Op;
  173. break;
  174. }
  175. if (Start == Stop) break;
  176. }
  177. }
  178. if (Section.Find("Pre-Depends", Start, Stop) == true)
  179. {
  180. while (1)
  181. {
  182. string P, V;
  183. unsigned int Op;
  184. Start = debListParser::ParseDepends(Start, Stop, P, V, Op);
  185. if (Start == 0) return false;
  186. if (P == "debconf")
  187. {
  188. PreDepVer = V;
  189. PreDepOp = Op;
  190. break;
  191. }
  192. if (Start == Stop) break;
  193. }
  194. }
  195. return true;
  196. }
  197. /*}}}*/
  198. static bool ShowHelp(CommandLine &) /*{{{*/
  199. {
  200. cout <<
  201. _("Usage: apt-extracttemplates file1 [file2 ...]\n"
  202. "\n"
  203. "apt-extracttemplates is used to extract config and template files\n"
  204. "from debian packages. It is used mainly by debconf(1) to prompt for\n"
  205. "configuration questions before installation of packages.\n");
  206. return true;
  207. }
  208. /*}}}*/
  209. // WriteFile - write the contents of the passed string to a file /*{{{*/
  210. // ---------------------------------------------------------------------
  211. /* */
  212. static string WriteFile(const char *package, const char *prefix, const char *data)
  213. {
  214. FileFd f;
  215. std::string tplname;
  216. strprintf(tplname, "%s.%s", package, prefix);
  217. GetTempFile(tplname, false, &f);
  218. if (data != nullptr)
  219. f.Write(data, strlen(data));
  220. return f.Name();
  221. }
  222. /*}}}*/
  223. // WriteConfig - write out the config data from a debian package file /*{{{*/
  224. // ---------------------------------------------------------------------
  225. /* */
  226. static void WriteConfig(const DebFile &file)
  227. {
  228. string templatefile = WriteFile(file.Package.c_str(), "template", file.Template);
  229. string configscript = WriteFile(file.Package.c_str(), "config", file.Config);
  230. if (templatefile.empty() == true || configscript.empty() == true)
  231. return;
  232. cout << file.Package << " " << file.Version << " "
  233. << templatefile << " " << configscript << endl;
  234. }
  235. /*}}}*/
  236. // InitCache - initialize the package cache /*{{{*/
  237. // ---------------------------------------------------------------------
  238. /* */
  239. static bool Go(CommandLine &CmdL)
  240. {
  241. // Initialize the apt cache
  242. MMap *Map = 0;
  243. pkgSourceList List;
  244. List.ReadMainList();
  245. pkgCacheGenerator::MakeStatusCache(List,NULL,&Map,true);
  246. if (Map == 0)
  247. return false;
  248. DebFile::Cache = new pkgCache(Map);
  249. if (_error->PendingError() == true)
  250. return false;
  251. // Find out what version of debconf is currently installed
  252. string debconfver = DebFile::GetInstalledVer("debconf");
  253. if (debconfver.empty() == true)
  254. return _error->Error( _("Cannot get debconf version. Is debconf installed?"));
  255. auto const tmpdir = _config->Find("APT::ExtractTemplates::TempDir");
  256. if (tmpdir.empty() == false)
  257. setenv("TMPDIR", tmpdir.c_str(), 1);
  258. // Process each package passsed in
  259. for (unsigned int I = 0; I != CmdL.FileSize(); I++)
  260. {
  261. // Will pick up the errors later..
  262. DebFile file(CmdL.FileList[I]);
  263. if (file.Go() == false)
  264. {
  265. _error->Error("Prior errors apply to %s",CmdL.FileList[I]);
  266. continue;
  267. }
  268. // Does the package have templates?
  269. if (file.Template != 0 && file.ParseInfo() == true)
  270. {
  271. // Check to make sure debconf dependencies are
  272. // satisfied
  273. // cout << "Check " << file.DepVer << ',' << debconfver << endl;
  274. if (file.DepVer != "" &&
  275. DebFile::Cache->VS->CheckDep(debconfver.c_str(),
  276. file.DepOp,file.DepVer.c_str()
  277. ) == false)
  278. continue;
  279. if (file.PreDepVer != "" &&
  280. DebFile::Cache->VS->CheckDep(debconfver.c_str(),
  281. file.PreDepOp,file.PreDepVer.c_str()
  282. ) == false)
  283. continue;
  284. WriteConfig(file);
  285. }
  286. }
  287. delete Map;
  288. delete DebFile::Cache;
  289. return !_error->PendingError();
  290. }
  291. /*}}}*/
  292. static std::vector<aptDispatchWithHelp> GetCommands() /*{{{*/
  293. {
  294. return {
  295. {nullptr, nullptr, nullptr}
  296. };
  297. }
  298. /*}}}*/
  299. int main(int argc, const char **argv) /*{{{*/
  300. {
  301. CommandLine CmdL;
  302. auto const Cmds = ParseCommandLine(CmdL, APT_CMD::APT_EXTRACTTEMPLATES, &_config, &_system, argc, argv, &ShowHelp, &GetCommands);
  303. Go(CmdL);
  304. return DispatchCommandLine(CmdL, {});
  305. }
  306. /*}}}*/