apt-extracttemplates.cc 9.4 KB

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