apt-extracttemplates.cc 9.7 KB

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