apt-extracttemplates.cc 9.2 KB

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