]> cygwin.com Git - cygwin-apps/setup.git/blob - ini.cc
* ini.h (SETUP_BZ2_FILENAME): Reflect new architecture layout in ftp.
[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 static char buf[100];
94 sprintf(buf, "%d %% (%ldk/%ldk)", lastpct, pos/1000, max/1000);
95 Progress.SetText3(buf);
96 }
97 virtual void iniName (const std::string& name)
98 {
99 Progress.SetText1 ("Parsing...");
100 Progress.SetText2 (name.c_str());
101 Progress.SetText3 ("");
102 }
103 virtual void babble(const std::string& message)const
104 {
105 log (LOG_BABBLE) << message << endLog;
106 }
107 virtual void warning (const std::string& message)const
108 {
109 MessageBox (0, message.c_str(), "Warning", 0);
110 }
111 virtual void error(const std::string& message)const
112 {
113 MessageBox (0, message.c_str(), "Parse Errors", 0);
114 }
115 virtual ~ GuiParseFeedback ()
116 {
117 Progress.SetText4("Package:");
118 }
119 private:
120 unsigned int lastpct;
121 };
122
123 static int
124 do_local_ini (HWND owner)
125 {
126 GuiParseFeedback myFeedback;
127 IniDBBuilderPackage findBuilder(myFeedback);
128 IniParseFindVisitor myVisitor (findBuilder, local_dir, myFeedback);
129 Find (local_dir).accept(myVisitor);
130 setup_timestamp = myVisitor.timeStamp();
131 ini_setup_version = myVisitor.version();
132 return myVisitor.iniCount();
133 }
134
135 static int
136 do_remote_ini (HWND owner)
137 {
138 size_t ini_count = 0;
139 GuiParseFeedback myFeedback;
140 IniDBBuilderPackage aBuilder(myFeedback);
141 io_stream *ini_file, *ini_sig_file;
142
143 /* FIXME: Get rid of this io_stream pointer travesty. The need to
144 explicitly delete these things is ridiculous. Note that the
145 decompress io_stream "owns" the underlying compressed io_stream
146 instance, so it should not be deleted explicitly. */
147
148 for (SiteList::const_iterator n = site_list.begin();
149 n != site_list.end(); ++n)
150 {
151 bool sig_fail = false;
152 /* First try to fetch the .bz2 compressed ini file. */
153 current_ini_name = n->url + SETUP_BZ2_FILENAME;
154 current_ini_sig_name = n->url + SETUP_BZ2_FILENAME + ".sig";
155 ini_file = get_url_to_membuf (current_ini_name, owner);
156 if (!NoVerifyOption)
157 ini_sig_file = get_url_to_membuf (current_ini_sig_name, owner);
158 if (!NoVerifyOption && ini_file && !ini_sig_file)
159 {
160 note (owner, IDS_SETUPINI_MISSING, current_ini_sig_name.c_str(), n->url.c_str());
161 delete ini_file;
162 ini_file = NULL;
163 sig_fail = true;
164 }
165 else if (!NoVerifyOption && ini_file && !verify_ini_file_sig (ini_file, ini_sig_file, owner))
166 {
167 note (owner, IDS_SIG_INVALID, current_ini_sig_name.c_str(), n->url.c_str());
168 delete ini_file;
169 ini_file = NULL;
170 delete ini_sig_file;
171 ini_sig_file = NULL;
172 sig_fail = true;
173 }
174 if (ini_file)
175 {
176 /* Decompress the entire file in memory right now. This has the
177 advantage that input_stream->get_size() will work during parsing
178 and we'll have an accurate status bar. Also, we can't seek
179 bz2 streams, so when it comes time to write out a local cached
180 copy of the .ini file below, we'd otherwise have to delete this
181 stream and uncompress it again from the start, which is wasteful.
182 The current uncompresed size of the .ini file as of 2007 is less
183 than 600 kB, so this is not a great deal of memory. */
184 io_stream *bz2_stream = compress::decompress (ini_file);
185 if (!bz2_stream)
186 {
187 /* This isn't a valid bz2 file. */
188 delete ini_file;
189 ini_file = NULL;
190 }
191 else
192 {
193 io_stream *uncompressed = new io_stream_memory ();
194
195 if ((io_stream::copy (bz2_stream, uncompressed) != 0) ||
196 (bz2_stream->error() != 0))
197 {
198 /* There was a problem decompressing bz2. */
199 ini_file = NULL;
200 log (LOG_PLAIN) <<
201 "Warning: Error code " << bz2_stream->error() << " occurred while uncompressing " <<
202 current_ini_name << " - possibly truncated or corrupt bzip2"
203 " file. Retrying with uncompressed version." << endLog;
204 delete bz2_stream;
205 delete uncompressed;
206 }
207 else
208 {
209 delete bz2_stream;
210 ini_file = uncompressed;
211 ini_file->seek (0, IO_SEEK_SET);
212 }
213 }
214 }
215
216 if (!ini_file)
217 {
218 /* Try to look for a plain .ini file because one of the following
219 happened above:
220 - there was no .bz2 file found on the mirror.
221 - the .bz2 file didn't look like a valid bzip2 file.
222 - there was an error during bzip2 decompression. */
223 current_ini_name = n->url + SETUP_INI_FILENAME;
224 current_ini_sig_name = n->url + SETUP_INI_FILENAME + ".sig";
225 ini_file = get_url_to_membuf (current_ini_name, owner);
226 if (!NoVerifyOption)
227 ini_sig_file = get_url_to_membuf (current_ini_sig_name, owner);
228
229 if (!NoVerifyOption && ini_file && !ini_sig_file)
230 {
231 note (owner, IDS_SETUPINI_MISSING, current_ini_sig_name.c_str(), n->url.c_str());
232 delete ini_file;
233 ini_file = NULL;
234 sig_fail = true;
235 }
236 else if (!NoVerifyOption && ini_file && !verify_ini_file_sig (ini_file, ini_sig_file, owner))
237 {
238 note (owner, IDS_SIG_INVALID, current_ini_sig_name.c_str(), n->url.c_str());
239 delete ini_file;
240 ini_file = NULL;
241 delete ini_sig_file;
242 ini_sig_file = NULL;
243 sig_fail = true;
244 }
245 }
246
247 if (!ini_file)
248 {
249 if (!sig_fail)
250 note (owner, IDS_SETUPINI_MISSING, SETUP_INI_FILENAME, n->url.c_str());
251 continue;
252 }
253
254 myFeedback.iniName (current_ini_name);
255 aBuilder.parse_mirror = n->url;
256 ini_init (ini_file, &aBuilder, myFeedback);
257
258 /*yydebug = 1; */
259
260 if (yyparse () || yyerror_count > 0)
261 myFeedback.error (yyerror_messages);
262 else
263 {
264 /* save known-good setup.ini locally */
265 const std::string fp = "file://" + local_dir + "/" +
266 rfc1738_escape_part (n->url) +
267 "/" + SETUP_INI_FILENAME;
268 io_stream::mkpath_p (PATH_TO_FILE, fp, 0);
269 if (io_stream *out = io_stream::open (fp, "wb", 0))
270 {
271 ini_file->seek (0, IO_SEEK_SET);
272 if (io_stream::copy (ini_file, out) != 0)
273 io_stream::remove (fp);
274 delete out;
275 }
276 ++ini_count;
277 }
278 if (aBuilder.timestamp > setup_timestamp)
279 {
280 setup_timestamp = aBuilder.timestamp;
281 ini_setup_version = aBuilder.version;
282 }
283 delete ini_file;
284 }
285 return ini_count;
286 }
287
288 static bool
289 do_ini_thread (HINSTANCE h, HWND owner)
290 {
291 size_t ini_count = 0;
292 if (source == IDC_SOURCE_CWD)
293 ini_count = do_local_ini (owner);
294 else
295 ini_count = do_remote_ini (owner);
296
297 if (ini_count == 0)
298 return false;
299
300 if (get_root_dir ().c_str())
301 {
302 io_stream::mkpath_p (PATH_TO_DIR, "cygfile:///etc/setup", 0755);
303
304 unsigned int old_timestamp = 0;
305 io_stream *ots =
306 io_stream::open ("cygfile:///etc/setup/timestamp", "rt", 0);
307 if (ots)
308 {
309 char temp[20];
310 memset (temp, '\0', 20);
311 if (ots->read (temp, 19))
312 sscanf (temp, "%u", &old_timestamp);
313 delete ots;
314 if (old_timestamp && setup_timestamp
315 && (old_timestamp > setup_timestamp))
316 {
317 int yn = yesno (owner, IDS_OLD_SETUPINI);
318 if (yn == IDNO)
319 LogSingleton::GetInstance().exit (1);
320 }
321 }
322 if (setup_timestamp)
323 {
324 io_stream *nts =
325 io_stream::open ("cygfile:///etc/setup/timestamp", "wt", 0);
326 if (nts)
327 {
328 char temp[20];
329 sprintf (temp, "%u", setup_timestamp);
330 nts->write (temp, strlen (temp));
331 delete nts;
332 }
333 }
334 }
335
336 msg (".ini setup_version is %s, our setup_version is %s", ini_setup_version.size() ?
337 ini_setup_version.c_str() : "(null)",
338 setup_version);
339 if (ini_setup_version.size())
340 {
341 if (version_compare(setup_version, ini_setup_version) < 0)
342 note (owner, IDS_OLD_SETUP_VERSION, setup_version,
343 ini_setup_version.c_str());
344 }
345
346 return true;
347 }
348
349 static DWORD WINAPI
350 do_ini_thread_reflector(void* p)
351 {
352 HANDLE *context;
353 context = (HANDLE*)p;
354
355 try
356 {
357 bool succeeded = do_ini_thread((HINSTANCE)context[0], (HWND)context[1]);
358
359 // Tell the progress page that we're done downloading
360 Progress.PostMessageNow(WM_APP_SETUP_INI_DOWNLOAD_COMPLETE, 0, succeeded);
361 }
362 TOPLEVEL_CATCH("ini");
363
364 ExitThread(0);
365 }
366
367 static HANDLE context[2];
368
369 void
370 do_ini (HINSTANCE h, HWND owner)
371 {
372 context[0] = h;
373 context[1] = owner;
374
375 DWORD threadID;
376 CreateThread (NULL, 0, do_ini_thread_reflector, context, 0, &threadID);
377 }
378
This page took 0.056267 seconds and 5 git commands to generate.