]> cygwin.com Git - cygwin-apps/setup.git/blob - ini.cc
whitespace cleanup.
[cygwin-apps/setup.git] / ini.cc
1 /*
2 * Copyright (c) 2000,2007 Red Hat, Inc.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * A copy of the GNU General Public License can be found at
10 * http://www.gnu.org/
11 *
12 * Written by DJ Delorie <dj@cygnus.com>
13 *
14 */
15
16 /* The purpose of this file is to get and parse the setup.ini file
17 from the mirror site. A few support routines for the bison and
18 flex parsers are provided also. We check to see if this setup.ini
19 is older than the one we used last time, and if so, warn the user. */
20
21 #include "ini.h"
22
23 #include "csu_util/rfc1738.h"
24 #include "csu_util/version_compare.h"
25
26 #include "setup_version.h"
27 #include "win32.h"
28 #include "LogSingleton.h"
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <stdarg.h>
33 #include <process.h>
34
35 #include "resource.h"
36 #include "state.h"
37 #include "geturl.h"
38 #include "dialog.h"
39 #include "msg.h"
40 #include "mount.h"
41 #include "site.h"
42 #include "find.h"
43 #include "IniParseFindVisitor.h"
44 #include "IniParseFeedback.h"
45
46 #include "io_stream.h"
47 #include "io_stream_memory.h"
48
49 #include "threebar.h"
50
51 #include "getopt++/BoolOption.h"
52 #include "IniDBBuilderPackage.h"
53 #include "compress.h"
54 #include "Exception.h"
55 #include "crypto.h"
56
57 extern ThreeBarProgressPage Progress;
58
59 unsigned int setup_timestamp = 0;
60 std::string ini_setup_version;
61 std::string current_ini_sig_name;
62
63 static BoolOption NoVerifyOption (false, 'X', "no-verify", "Don't verify setup.ini signatures");
64
65 extern int yyparse ();
66 /*extern int yydebug;*/
67
68 class GuiParseFeedback : public IniParseFeedback
69 {
70 public:
71 GuiParseFeedback () : lastpct (0)
72 {
73 Progress.SetText2 ("");
74 Progress.SetText3 ("");
75 Progress.SetText4 ("Progress:");
76 }
77 virtual void progress(unsigned long const pos, unsigned long const max)
78 {
79 if (!max)
80 /* length not known or eof */
81 return;
82 if (lastpct == 100)
83 /* rounding down should mean this only ever fires once */
84 lastpct = 0;
85 if (pos * 100 / max > lastpct)
86 {
87 lastpct = pos * 100 / max;
88 /* log (LOG_BABBLE) << lastpct << "% (" << pos << " of " << max
89 << " bytes of ini file read)" << endLog; */
90 }
91 Progress.SetBar1(pos, max);
92 }
93 virtual void iniName (const std::string& name)
94 {
95 Progress.SetText1 (("Parsing ini file \"" + name + "\"").c_str());
96 }
97 virtual void babble(const std::string& message)const
98 {
99 log (LOG_BABBLE) << message << endLog;
100 }
101 virtual void warning (const std::string& message)const
102 {
103 MessageBox (0, message.c_str(), "Warning", 0);
104 }
105 virtual void error(const std::string& message)const
106 {
107 MessageBox (0, message.c_str(), "Parse Errors", 0);
108 }
109 virtual ~ GuiParseFeedback ()
110 {
111 Progress.SetText4("Package:");
112 }
113 private:
114 unsigned int lastpct;
115 };
116
117 static int
118 do_local_ini (HWND owner)
119 {
120 GuiParseFeedback myFeedback;
121 IniDBBuilderPackage findBuilder(myFeedback);
122 IniParseFindVisitor myVisitor (findBuilder, local_dir, myFeedback);
123 Find (local_dir).accept(myVisitor);
124 setup_timestamp = myVisitor.timeStamp();
125 ini_setup_version = myVisitor.version();
126 return myVisitor.iniCount();
127 }
128
129 static int
130 do_remote_ini (HWND owner)
131 {
132 size_t ini_count = 0;
133 GuiParseFeedback myFeedback;
134 IniDBBuilderPackage aBuilder(myFeedback);
135 io_stream *ini_file, *ini_sig_file;
136
137 /* FIXME: Get rid of this io_stream pointer travesty. The need to
138 explicitly delete these things is ridiculous. Note that the
139 decompress io_stream "owns" the underlying compressed io_stream
140 instance, so it should not be deleted explicitly. */
141
142 for (SiteList::const_iterator n = site_list.begin();
143 n != site_list.end(); ++n)
144 {
145 bool sig_fail = false;
146 /* First try to fetch the .bz2 compressed ini file. */
147 current_ini_name = n->url + "/" + SETUP_BZ2_FILENAME;
148 current_ini_sig_name = n->url + "/" + SETUP_BZ2_FILENAME + ".sig";
149 ini_file = get_url_to_membuf (current_ini_name, owner);
150 if (!NoVerifyOption)
151 ini_sig_file = get_url_to_membuf (current_ini_sig_name, owner);
152 if (!NoVerifyOption && ini_file && !ini_sig_file)
153 {
154 note (owner, IDS_SETUPINI_MISSING, current_ini_sig_name.c_str(), n->url.c_str());
155 delete ini_file;
156 ini_file = NULL;
157 sig_fail = true;
158 }
159 else if (!NoVerifyOption && ini_file && !verify_ini_file_sig (ini_file, ini_sig_file, owner))
160 {
161 note (owner, IDS_SIG_INVALID, current_ini_sig_name.c_str(), n->url.c_str());
162 delete ini_file;
163 ini_file = NULL;
164 delete ini_sig_file;
165 ini_sig_file = NULL;
166 sig_fail = true;
167 }
168 if (ini_file)
169 {
170 /* Decompress the entire file in memory right now. This has the
171 advantage that input_stream->get_size() will work during parsing
172 and we'll have an accurate status bar. Also, we can't seek
173 bz2 streams, so when it comes time to write out a local cached
174 copy of the .ini file below, we'd otherwise have to delete this
175 stream and uncompress it again from the start, which is wasteful.
176 The current uncompresed size of the .ini file as of 2007 is less
177 than 600 kB, so this is not a great deal of memory. */
178 io_stream *bz2_stream = compress::decompress (ini_file);
179 if (!bz2_stream)
180 {
181 /* This isn't a valid bz2 file. */
182 delete ini_file;
183 ini_file = NULL;
184 }
185 else
186 {
187 io_stream *uncompressed = new io_stream_memory ();
188
189 if (io_stream::copy (bz2_stream, uncompressed) != 0 ||
190 bz2_stream->error () == EIO)
191 {
192 /* There was a problem decompressing bz2. */
193 delete bz2_stream;
194 delete uncompressed;
195 ini_file = NULL;
196 log (LOG_PLAIN) <<
197 "Warning: Problem encountered while uncompressing " <<
198 current_ini_name << " - possibly truncated or corrupt bzip2"
199 " file. Retrying with uncompressed version." << endLog;
200 }
201 else
202 {
203 delete bz2_stream;
204 ini_file = uncompressed;
205 ini_file->seek (0, IO_SEEK_SET);
206 }
207 }
208 }
209
210 if (!ini_file)
211 {
212 /* Try to look for a plain .ini file because one of the following
213 happened above:
214 - there was no .bz2 file found on the mirror.
215 - the .bz2 file didn't look like a valid bzip2 file.
216 - there was an error during bzip2 decompression. */
217 current_ini_name = n->url + "/" + SETUP_INI_FILENAME;
218 current_ini_sig_name = n->url + "/" + SETUP_INI_FILENAME + ".sig";
219 ini_file = get_url_to_membuf (current_ini_name, owner);
220 if (!NoVerifyOption)
221 ini_sig_file = get_url_to_membuf (current_ini_sig_name, owner);
222
223 if (!NoVerifyOption && ini_file && !ini_sig_file)
224 {
225 note (owner, IDS_SETUPINI_MISSING, current_ini_sig_name.c_str(), n->url.c_str());
226 delete ini_file;
227 ini_file = NULL;
228 sig_fail = true;
229 }
230 else if (!NoVerifyOption && ini_file && !verify_ini_file_sig (ini_file, ini_sig_file, owner))
231 {
232 note (owner, IDS_SIG_INVALID, current_ini_sig_name.c_str(), n->url.c_str());
233 delete ini_file;
234 ini_file = NULL;
235 delete ini_sig_file;
236 ini_sig_file = NULL;
237 sig_fail = true;
238 }
239 }
240
241 if (!ini_file)
242 {
243 if (!sig_fail)
244 note (owner, IDS_SETUPINI_MISSING, SETUP_INI_FILENAME, n->url.c_str());
245 continue;
246 }
247
248 myFeedback.iniName (current_ini_name);
249 aBuilder.parse_mirror = n->url;
250 ini_init (ini_file, &aBuilder, myFeedback);
251
252 /*yydebug = 1; */
253
254 if (yyparse () || yyerror_count > 0)
255 myFeedback.error (yyerror_messages);
256 else
257 {
258 /* save known-good setup.ini locally */
259 const std::string fp = "file://" + local_dir + "/" +
260 rfc1738_escape_part (n->url) +
261 "/" + SETUP_INI_FILENAME;
262 io_stream::mkpath_p (PATH_TO_FILE, fp, 0755);
263 if (io_stream *out = io_stream::open (fp, "wb"))
264 {
265 ini_file->seek (0, IO_SEEK_SET);
266 if (io_stream::copy (ini_file, out) != 0)
267 io_stream::remove (fp);
268 delete out;
269 }
270 ++ini_count;
271 }
272 if (aBuilder.timestamp > setup_timestamp)
273 {
274 setup_timestamp = aBuilder.timestamp;
275 ini_setup_version = aBuilder.version;
276 }
277 delete ini_file;
278 }
279 return ini_count;
280 }
281
282 static bool
283 do_ini_thread (HINSTANCE h, HWND owner)
284 {
285 size_t ini_count = 0;
286 if (source == IDC_SOURCE_CWD)
287 ini_count = do_local_ini (owner);
288 else
289 ini_count = do_remote_ini (owner);
290
291 if (ini_count == 0)
292 return false;
293
294 if (get_root_dir ().c_str())
295 {
296 io_stream::mkpath_p (PATH_TO_DIR, "cygfile:///etc/setup", 0755);
297
298 unsigned int old_timestamp = 0;
299 io_stream *ots =
300 io_stream::open ("cygfile:///etc/setup/timestamp", "rt");
301 if (ots)
302 {
303 char temp[20];
304 memset (temp, '\0', 20);
305 if (ots->read (temp, 19))
306 sscanf (temp, "%u", &old_timestamp);
307 delete ots;
308 if (old_timestamp && setup_timestamp
309 && (old_timestamp > setup_timestamp))
310 {
311 int yn = yesno (owner, IDS_OLD_SETUPINI);
312 if (yn == IDNO)
313 LogSingleton::GetInstance().exit (1);
314 }
315 }
316 if (setup_timestamp)
317 {
318 io_stream *nts =
319 io_stream::open ("cygfile:///etc/setup/timestamp", "wt");
320 if (nts)
321 {
322 char temp[20];
323 sprintf (temp, "%u", setup_timestamp);
324 nts->write (temp, strlen (temp));
325 delete nts;
326 }
327 }
328 }
329
330 msg (".ini setup_version is %s, our setup_version is %s", ini_setup_version.size() ?
331 ini_setup_version.c_str() : "(null)",
332 setup_version);
333 if (ini_setup_version.size())
334 {
335 if (version_compare(setup_version, ini_setup_version) < 0)
336 note (owner, IDS_OLD_SETUP_VERSION, setup_version,
337 ini_setup_version.c_str());
338 }
339
340 return true;
341 }
342
343 static DWORD WINAPI
344 do_ini_thread_reflector(void* p)
345 {
346 HANDLE *context;
347 context = (HANDLE*)p;
348
349 try
350 {
351 bool succeeded = do_ini_thread((HINSTANCE)context[0], (HWND)context[1]);
352
353 // Tell the progress page that we're done downloading
354 Progress.PostMessage(WM_APP_SETUP_INI_DOWNLOAD_COMPLETE, 0, succeeded);
355 }
356 TOPLEVEL_CATCH("ini");
357
358 ExitThread(0);
359 }
360
361 static HANDLE context[2];
362
363 void
364 do_ini (HINSTANCE h, HWND owner)
365 {
366 context[0] = h;
367 context[1] = owner;
368
369 DWORD threadID;
370 CreateThread (NULL, 0, do_ini_thread_reflector, context, 0, &threadID);
371 }
372
This page took 0.054508 seconds and 6 git commands to generate.