apt-extracttemplates.cc 9.0 KB

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