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