You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

393 lines
9.8 KiB

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