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