apt-extracttemplates.cc 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. // -*- mode: cpp; mode: fold -*-
  2. // Description /*{{{*/
  3. // $Id: apt-extracttemplates.cc,v 1.3 2001/02/25 05:25:29 tausq 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 <apt-pkg/init.h>
  14. #include <apt-pkg/cmndline.h>
  15. #include <apt-pkg/debversion.h>
  16. #include <apt-pkg/pkgcache.h>
  17. #include <apt-pkg/configuration.h>
  18. #include <apt-pkg/progress.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/extracttar.h>
  24. #include <apt-pkg/arfile.h>
  25. #include <apt-pkg/deblistparser.h>
  26. #include <apt-pkg/error.h>
  27. #include <apt-pkg/strutl.h>
  28. #include <stdio.h>
  29. #include <string.h>
  30. #include <stdlib.h>
  31. #include <unistd.h>
  32. #include <wait.h>
  33. #include <fstream.h>
  34. #include <config.h>
  35. #include <apti18n.h>
  36. #include "apt-extracttemplates.h"
  37. #define TMPDIR "/var/lib/debconf/"
  38. pkgCache *DebFile::Cache = 0;
  39. // DebFile::DebFile - Construct the DebFile object /*{{{*/
  40. // ---------------------------------------------------------------------
  41. /* */
  42. DebFile::DebFile(const char *debfile)
  43. : File(debfile, FileFd::ReadOnly), Control(0), DepOp(0), PreDepOp(0),
  44. Config(0), Template(0), Which(None)
  45. {
  46. }
  47. /*}}}*/
  48. // DebFile::~DebFile - Destruct the DebFile object /*{{{*/
  49. // ---------------------------------------------------------------------
  50. /* */
  51. DebFile::~DebFile()
  52. {
  53. delete [] Control;
  54. delete [] Config;
  55. delete [] Template;
  56. }
  57. /*}}}*/
  58. // DebFile::GetInstalledVer - Find out the installed version of a pkg /*{{{*/
  59. // ---------------------------------------------------------------------
  60. /* */
  61. char *DebFile::GetInstalledVer(const string &package)
  62. {
  63. char *ver = 0;
  64. pkgCache::PkgIterator Pkg = Cache->FindPkg(package);
  65. if (Pkg.end() == false)
  66. {
  67. pkgCache::VerIterator V = Pkg.CurrentVer();
  68. if (V.end() == false)
  69. {
  70. ver = strdup(V.VerStr());
  71. }
  72. }
  73. return ver;
  74. }
  75. /*}}}*/
  76. // DebFile::Go - Start extracting a debian package /*{{{*/
  77. // ---------------------------------------------------------------------
  78. /* */
  79. bool DebFile::Go()
  80. {
  81. ARArchive AR(File);
  82. const ARArchive::Member *Member = AR.FindMember("control.tar.gz");
  83. if (Member == 0)
  84. {
  85. fprintf(stderr, _("This is not a valid DEB package.\n"));
  86. return false;
  87. }
  88. if (File.Seek(Member->Start) == false)
  89. {
  90. return false;
  91. }
  92. ExtractTar Tar(File, Member->Size);
  93. return Tar.Go(*this);
  94. }
  95. /*}}}*/
  96. // DebFile::DoItem examine element in package and mark /*{{{*/
  97. // ---------------------------------------------------------------------
  98. /* */
  99. bool DebFile::DoItem(Item &I, int &Fd)
  100. {
  101. if (strcmp(I.Name, "control") == 0)
  102. {
  103. delete [] Control;
  104. Control = new char[I.Size+1];
  105. Control[I.Size] = 0;
  106. Which = IsControl;
  107. ControlLen = I.Size;
  108. // make it call the Process method below. this is so evil
  109. Fd = -2;
  110. }
  111. else if (strcmp(I.Name, "config") == 0)
  112. {
  113. delete [] Config;
  114. Config = new char[I.Size+1];
  115. Config[I.Size] = 0;
  116. Which = IsConfig;
  117. Fd = -2;
  118. }
  119. else if (strcmp(I.Name, "templates") == 0)
  120. {
  121. delete [] Template;
  122. Template = new char[I.Size+1];
  123. Template[I.Size] = 0;
  124. Which = IsTemplate;
  125. Fd = -2;
  126. }
  127. else
  128. {
  129. Fd = -1;
  130. }
  131. return true;
  132. }
  133. /*}}}*/
  134. // DebFile::Process examine element in package and copy /*{{{*/
  135. // ---------------------------------------------------------------------
  136. /* */
  137. bool DebFile::Process(Item &I, const unsigned char *data,
  138. unsigned long size, unsigned long pos)
  139. {
  140. switch (Which)
  141. {
  142. case IsControl:
  143. memcpy(Control + pos, data, size);
  144. break;
  145. case IsConfig:
  146. memcpy(Config + pos, data, size);
  147. break;
  148. case IsTemplate:
  149. memcpy(Template + pos, data, size);
  150. break;
  151. default: /* throw it away */ ;
  152. }
  153. return true;
  154. }
  155. /*}}}*/
  156. // DebFile::ParseInfo - Parse control file for dependency info /*{{{*/
  157. // ---------------------------------------------------------------------
  158. /* */
  159. bool DebFile::ParseInfo()
  160. {
  161. if (Control == NULL) return false;
  162. pkgTagSection Section;
  163. Section.Scan(Control, ControlLen);
  164. Package = Section.FindS("Package");
  165. Version = GetInstalledVer(Package);
  166. const char *Start, *Stop;
  167. if (Section.Find("Depends", Start, Stop) == true)
  168. {
  169. while (1)
  170. {
  171. string P, V;
  172. unsigned int Op;
  173. Start = debListParser::ParseDepends(Start, Stop, P, V, Op);
  174. if (Start == 0) return false;
  175. if (P == "debconf")
  176. {
  177. DepVer = V;
  178. DepOp = Op;
  179. break;
  180. }
  181. if (Start == Stop) break;
  182. }
  183. }
  184. if (Section.Find("Pre-Depends", Start, Stop) == true)
  185. {
  186. while (1)
  187. {
  188. string P, V;
  189. unsigned int Op;
  190. Start = debListParser::ParseDepends(Start, Stop, P, V, Op);
  191. if (Start == 0) return false;
  192. if (P == "debconf")
  193. {
  194. PreDepVer = V;
  195. PreDepOp = Op;
  196. break;
  197. }
  198. if (Start == Stop) break;
  199. }
  200. }
  201. return true;
  202. }
  203. /*}}}*/
  204. // ShowHelp - show a short help text /*{{{*/
  205. // ---------------------------------------------------------------------
  206. /* */
  207. void ShowHelp(void)
  208. {
  209. ioprintf(cout,_("%s %s for %s %s compiled on %s %s\n"),PACKAGE,VERSION,
  210. COMMON_OS,COMMON_CPU,__DATE__,__TIME__);
  211. if (_config->FindB("version") == true) return;
  212. fprintf(stderr,
  213. _("Usage: apt-extracttemplates file1 [file2 ...]\n"
  214. "\n"
  215. "apt-extracttemplates is a tool to extract config and template info\n"
  216. "from debian packages\n"));
  217. exit(0);
  218. }
  219. /*}}}*/
  220. // WriteFile - write the contents of the passed string to a file /*{{{*/
  221. // ---------------------------------------------------------------------
  222. /* */
  223. char *WriteFile(const char *prefix, const char *data)
  224. {
  225. char fn[512];
  226. static int i;
  227. snprintf(fn, sizeof(fn), "%s%s.%u%d", _config->Find("APT::ExtractTemplates::TempDir", TMPDIR).c_str(), prefix, getpid(), i++);
  228. ofstream ofs(fn);
  229. if (!ofs) return NULL;
  230. ofs << (data ? data : "");
  231. ofs.close();
  232. return strdup(fn);
  233. }
  234. /*}}}*/
  235. // WriteConfig - write out the config data from a debian package file /*{{{*/
  236. // ---------------------------------------------------------------------
  237. /* */
  238. void WriteConfig(const DebFile &file)
  239. {
  240. char *templatefile = WriteFile("template", file.Template);
  241. char *configscript = WriteFile("config", file.Config);
  242. if (templatefile == 0 || configscript == 0)
  243. {
  244. fprintf(stderr, _("Cannot write config script or templates\n"));
  245. return;
  246. }
  247. cout << file.Package << " " << file.Version << " "
  248. << templatefile << " " << configscript << endl;
  249. free(templatefile);
  250. free(configscript);
  251. }
  252. /*}}}*/
  253. // InitCache - initialize the package cache /*{{{*/
  254. // ---------------------------------------------------------------------
  255. /* */
  256. int InitCache(MMap *&Map, pkgCache *&Cache)
  257. {
  258. // Initialize the apt cache
  259. if (pkgInitConfig(*_config) == false || pkgInitSystem(*_config, _system) == false)
  260. {
  261. _error->DumpErrors();
  262. return -1;
  263. }
  264. pkgSourceList List;
  265. List.ReadMainList();
  266. OpProgress Prog;
  267. pkgMakeStatusCache(List,Prog,&Map,true);
  268. Cache = new pkgCache(Map);
  269. return 0;
  270. }
  271. /*}}}*/
  272. int main(int argc, const char **argv)
  273. {
  274. MMap *Map = 0;
  275. const char *debconfver = NULL;
  276. CommandLine::Args Args[] = {
  277. {'h',"help","help",0},
  278. {'v',"version","version",0},
  279. {'t',"tempdir","APT::ExtractTemplates::TempDir",CommandLine::HasArg},
  280. {'c',"config-file",0,CommandLine::ConfigFile},
  281. {'o',"option",0,CommandLine::ArbItem},
  282. {0,0,0,0}};
  283. // Initialize the package cache
  284. if (InitCache(Map, DebFile::Cache) < 0 || Map == 0 || DebFile::Cache == 0)
  285. {
  286. fprintf(stderr, _("Cannot initialize APT cache\n"));
  287. return 100;
  288. }
  289. // Parse the command line
  290. CommandLine CmdL(Args,_config);
  291. if (CmdL.Parse(argc,argv) == false)
  292. {
  293. fprintf(stderr, _("Cannot parse commandline options\n"));
  294. return 100;
  295. }
  296. // See if the help should be shown
  297. if (_config->FindB("help") == true || CmdL.FileSize() == 0)
  298. {
  299. ShowHelp();
  300. return 0;
  301. }
  302. // Find out what version of debconf is currently installed
  303. if ((debconfver = DebFile::GetInstalledVer("debconf")) == NULL)
  304. {
  305. fprintf(stderr, _("Cannot get debconf version. Is debconf installed?\n"));
  306. return 1;
  307. }
  308. // Process each package passsed in
  309. for (unsigned int I = 0; I != CmdL.FileSize(); I++)
  310. {
  311. DebFile file(CmdL.FileList[I]);
  312. if (file.Go() == false)
  313. {
  314. fprintf(stderr, _("Cannot read %s\n"), CmdL.FileList[I]);
  315. continue;
  316. }
  317. // Does the package have templates?
  318. if (file.Template != 0 && file.ParseInfo() == true)
  319. {
  320. // Check to make sure debconf dependencies are
  321. // satisfied
  322. if (file.DepVer != "" &&
  323. DebFile::Cache->VS->CheckDep(file.DepVer.c_str(),
  324. file.DepOp, debconfver) == false)
  325. continue;
  326. if (file.PreDepVer != "" &&
  327. DebFile::Cache->VS->CheckDep(file.PreDepVer.c_str(),
  328. file.PreDepOp, debconfver) == false)
  329. continue;
  330. WriteConfig(file);
  331. }
  332. }
  333. delete Map;
  334. delete DebFile::Cache;
  335. return 0;
  336. }