]> cygwin.com Git - cygwin-apps/setup.git/blame - ini.cc
Make PrereqChecker::setTrust() a static method
[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
2b734ec7
MB
21#include "ini.h"
22
946198be 23#include "csu_util/rfc1738.h"
2b734ec7
MB
24#include "csu_util/version_compare.h"
25
26#include "setup_version.h"
23c9e63c 27#include "win32.h"
5fa64c3c 28#include "LogFile.h"
23c9e63c
DD
29
30#include <stdio.h>
b11b49f3 31#include <stdlib.h>
23c9e63c 32#include <stdarg.h>
ab57ceaa 33#include <process.h>
23c9e63c 34
23c9e63c 35#include "resource.h"
23c9e63c
DD
36#include "state.h"
37#include "geturl.h"
38#include "dialog.h"
a351e48c 39#include "mount.h"
de6a1a64 40#include "site.h"
de6a1a64 41#include "find.h"
67829ce0 42#include "IniParseFeedback.h"
23c9e63c 43
b24c88b3 44#include "io_stream.h"
eb20d728 45#include "io_stream_memory.h"
b24c88b3 46
ab57ceaa 47#include "threebar.h"
58ee6135 48
dbfe3c19 49#include "getopt++/BoolOption.h"
076654e7 50#include "IniDBBuilderPackage.h"
3272d625 51#include "compress.h"
072fb49a 52#include "Exception.h"
dbfe3c19 53#include "crypto.h"
f6d6c600 54#include "package_db.h"
30718d6f 55
ab57ceaa
RC
56extern ThreeBarProgressPage Progress;
57
23c9e63c 58unsigned int setup_timestamp = 0;
fd93eff9 59std::string ini_setup_version;
18837afa
AG
60// TODO: use C++11x initializer lists instead and drop the literal array
61IniList setup_ext_list (setup_exts,
62 setup_exts + (sizeof(setup_exts) / sizeof(*setup_exts)));
dbfe3c19
DK
63
64static BoolOption NoVerifyOption (false, 'X', "no-verify", "Don't verify setup.ini signatures");
23c9e63c 65
0af2d779 66extern int yyparse ();
18837afa 67
b11b49f3
DD
68/*extern int yydebug;*/
69
67829ce0
RC
70class GuiParseFeedback : public IniParseFeedback
71{
72public:
30718d6f 73 GuiParseFeedback () : lastpct (0)
aa1e3b4d
RC
74 {
75 Progress.SetText2 ("");
76 Progress.SetText3 ("");
77 Progress.SetText4 ("Progress:");
78 }
18837afa 79 virtual void progress (unsigned long const pos, unsigned long const max)
aa1e3b4d
RC
80 {
81 if (!max)
82 /* length not known or eof */
83 return;
84 if (lastpct == 100)
85 /* rounding down should mean this only ever fires once */
86 lastpct = 0;
87 if (pos * 100 / max > lastpct)
88 {
89 lastpct = pos * 100 / max;
157dc2b8 90 /* Log (LOG_BABBLE) << lastpct << "% (" << pos << " of " << max
30718d6f 91 << " bytes of ini file read)" << endLog; */
aa1e3b4d 92 }
18837afa 93 Progress.SetBar1 (pos, max);
10087ff4
JT
94
95 static char buf[100];
18837afa
AG
96 sprintf (buf, "%d %% (%ldk/%ldk)", lastpct, pos/1000, max/1000);
97 Progress.SetText3 (buf);
aa1e3b4d 98 }
fd93eff9 99 virtual void iniName (const std::string& name)
aa1e3b4d 100 {
10087ff4 101 Progress.SetText1 ("Parsing...");
18837afa 102 Progress.SetText2 (name.c_str ());
10087ff4 103 Progress.SetText3 ("");
aa1e3b4d 104 }
18837afa 105 virtual void babble (const std::string& message)const
67829ce0 106 {
157dc2b8 107 Log (LOG_BABBLE) << message << endLog;
67829ce0 108 }
fd93eff9 109 virtual void warning (const std::string& message)const
67829ce0 110 {
18837afa 111 mbox (0, message.c_str (), "Warning", 0);
67829ce0 112 }
18837afa 113 virtual void error (const std::string& message)const
67829ce0 114 {
18837afa 115 mbox (0, message.c_str (), "Parse Errors", 0);
67829ce0
RC
116 }
117 virtual ~ GuiParseFeedback ()
118 {
18837afa 119 Progress.SetText4 ("Package:");
67829ce0 120 }
aa1e3b4d 121private:
b4cf6208 122 unsigned int lastpct;
67829ce0
RC
123};
124
18837afa
AG
125static io_stream*
126decompress_ini (io_stream *ini_file)
de6a1a64 127{
18837afa
AG
128 // Replace the current compressed setup stream with its decompressed
129 // version. Which decompressor to use is determined by file magic.
130 io_stream *compressed_stream = compress::decompress (ini_file);
131 if (!compressed_stream)
132 {
133 /* This isn't a known compression format or an uncompressed file
134 stream. Pass it on in case it was uncompressed, it will
135 generate a parser error if it was some unknown format. */
136 delete compressed_stream;
137 }
138 else
139 {
140 /* Decompress the entire file in memory. This has the advantage
141 that input_stream->get_size () will work during parsing and
142 we'll have an accurate status bar. Also, we can't seek
143 compressed streams, so when we write out a local cached copy
144 of the .ini file below, we'd otherwise have to delete this
145 stream and uncompress it again from the start, which is
146 wasteful. The current uncompressed size of the setup.ini
147 file as of 2015 is about 5 MiB, so this is not a great deal
148 of memory. */
149 io_stream *uncompressed = new io_stream_memory ();
150 /* Note that the decompress io_stream now "owns" the underlying
151 compressed io_stream instance, so it need not be deleted
152 explicitly. */
153 if ((io_stream::copy (compressed_stream, uncompressed) != 0) ||
154 (compressed_stream->error () != 0))
155 {
156 /* There was a problem decompressing compressed_stream. */
157 Log (LOG_PLAIN) <<
158 "Warning: Error code " << compressed_stream->error () <<
159 " occurred while uncompressing " << current_ini_name <<
160 " - possibly truncated or corrupt file. " << endLog;
161 delete uncompressed;
162 ini_file = NULL;
163 }
164 else
165 {
166 ini_file = uncompressed;
167 ini_file->seek (0, IO_SEEK_SET);
168 }
169 }
170 return ini_file;
de6a1a64
RC
171}
172
18837afa
AG
173static io_stream*
174check_ini_sig (io_stream* ini_file, io_stream* ini_sig_file,
175 bool& sig_fail, const char* site, const char* sig_name, HWND owner)
de6a1a64 176{
18837afa
AG
177 /* Unless the NoVerifyOption is set, check the signature for the
178 current setup and record the result. On a failed signature check
179 the streams are invalidated so even if we tried to read in the
180 setup anyway there's be nothing to parse. */
181 if (!NoVerifyOption && ini_file)
dd3f7f9b 182 {
679f6a2e
AG
183 if (!ini_sig_file) {
184 // don't complain if the user installs from localdir and no
185 // signature file is present
186 // TODO: download the ini + signature file instead
187 if (casecompare (site, "localdir"))
188 {
189 note (owner, IDS_SETUPINI_MISSING, sig_name, site);
190 delete ini_file;
191 ini_file = NULL;
192 sig_fail = true;
193 }
194 }
18837afa 195 else if (!verify_ini_file_sig (ini_file, ini_sig_file, owner))
dbfe3c19 196 {
18837afa 197 note (owner, IDS_SIG_INVALID, sig_name, site);
dbfe3c19
DK
198 delete ini_sig_file;
199 ini_sig_file = NULL;
18837afa
AG
200 delete ini_file;
201 ini_file = NULL;
dbfe3c19
DK
202 sig_fail = true;
203 }
18837afa
AG
204 }
205 return ini_file;
206}
207
208static int
209do_local_ini (HWND owner)
210{
211 size_t ini_count = 0;
212 GuiParseFeedback myFeedback;
213 IniDBBuilderPackage aBuilder (myFeedback);
214 io_stream *ini_file, *ini_sig_file;
215 // iterate over all setup files found in do_from_local_dir
216 for (IniList::const_iterator n = found_ini_list.begin ();
217 n != found_ini_list.end (); ++n)
218 {
219 bool sig_fail = false;
220 std::string current_ini_ext, current_ini_name, current_ini_sig_name;
221
222 current_ini_name = *n;
223 current_ini_sig_name = current_ini_name + ".sig";
224 current_ini_ext = current_ini_name.substr (current_ini_name.rfind (".") + 1);
225 ini_sig_file = io_stream::open ("file://" + current_ini_sig_name, "rb", 0);
226 ini_file = io_stream::open ("file://" + current_ini_name, "rb", 0);
227 ini_file = check_ini_sig (ini_file, ini_sig_file, sig_fail,
228 "localdir", current_ini_sig_name.c_str (), owner);
dbfe3c19 229 if (ini_file)
18837afa
AG
230 ini_file = decompress_ini (ini_file);
231 if (!ini_file || sig_fail)
3272d625 232 {
18837afa
AG
233 // no setup found or signature invalid
234 note (owner, IDS_SETUPINI_MISSING, SetupBaseName.c_str (),
235 "localdir");
236 }
237 else
238 {
239 // grok information from setup
240 myFeedback.babble ("Found ini file - " + current_ini_name);
241 myFeedback.iniName (current_ini_name);
679f6a2e
AG
242 int ldl = local_dir.length () + 1;
243 int cap = current_ini_name.rfind ("/" + SetupArch);
244 aBuilder.parse_mirror =
245 rfc1738_unescape (current_ini_name.substr (ldl, cap - ldl));
18837afa
AG
246 ini_init (ini_file, &aBuilder, myFeedback);
247
248 /*yydebug = 1; */
249
250 if (yyparse () || yyerror_count > 0)
251 myFeedback.error (yyerror_messages);
eb20d728 252 else
18837afa 253 ++ini_count;
eb20d728 254
18837afa
AG
255 if (aBuilder.timestamp > setup_timestamp)
256 {
257 setup_timestamp = aBuilder.timestamp;
258 ini_setup_version = aBuilder.version;
30718d6f 259 }
18837afa
AG
260 delete ini_file;
261 ini_file = NULL;
eb20d728 262 }
18837afa
AG
263 }
264 return ini_count;
265}
30718d6f 266
18837afa
AG
267static int
268do_remote_ini (HWND owner)
269{
270 size_t ini_count = 0;
271 GuiParseFeedback myFeedback;
272 IniDBBuilderPackage aBuilder (myFeedback);
abad8c0c 273 io_stream *ini_file = NULL, *ini_sig_file;
18837afa
AG
274
275 /* FIXME: Get rid of this io_stream pointer travesty. The need to
276 explicitly delete these things is ridiculous. */
277
278 // iterate over all sites
279 for (SiteList::const_iterator n = site_list.begin ();
280 n != site_list.end (); ++n)
281 {
282 bool sig_fail = false;
283 std::string current_ini_ext, current_ini_name, current_ini_sig_name;
284 // iterate over known extensions for setup
285 for (IniList::const_iterator ext = setup_ext_list.begin ();
286 ext != setup_ext_list.end ();
287 ext++)
30718d6f 288 {
18837afa
AG
289 current_ini_ext = *ext;
290 current_ini_name = n->url + SetupIniDir + SetupBaseName + "." + current_ini_ext;
291 current_ini_sig_name = current_ini_name + ".sig";
292 ini_sig_file = get_url_to_membuf (current_ini_sig_name, owner);
eb20d728 293 ini_file = get_url_to_membuf (current_ini_name, owner);
18837afa
AG
294 ini_file = check_ini_sig (ini_file, ini_sig_file, sig_fail,
295 n->url.c_str (), current_ini_sig_name.c_str (), owner);
296 // stop searching as soon as we find a setup file
297 if (ini_file)
298 break;
3272d625 299 }
18837afa
AG
300 if (ini_file)
301 ini_file = decompress_ini (ini_file);
302 if (!ini_file || sig_fail)
de6a1a64 303 {
18837afa
AG
304 // no setup found or signature invalid
305 note (owner, IDS_SETUPINI_MISSING, SetupBaseName.c_str (), n->url.c_str ());
de6a1a64 306 }
de6a1a64
RC
307 else
308 {
18837afa
AG
309 // grok information from setup
310 myFeedback.iniName (current_ini_name);
311 aBuilder.parse_mirror = n->url;
312 ini_init (ini_file, &aBuilder, myFeedback);
313
314 /*yydebug = 1; */
315
316 if (yyparse () || yyerror_count > 0)
317 myFeedback.error (yyerror_messages);
318 else
de6a1a64 319 {
18837afa
AG
320 /* save known-good setup.ini locally */
321 const std::string fp = "file://" + local_dir + "/" +
322 rfc1738_escape_part (n->url) +
323 "/" + SetupIniDir + SetupBaseName + ".ini";
324 io_stream::mkpath_p (PATH_TO_FILE, fp, 0);
325 if (io_stream *out = io_stream::open (fp, "wb", 0))
326 {
327 ini_file->seek (0, IO_SEEK_SET);
328 if (io_stream::copy (ini_file, out) != 0)
329 io_stream::remove (fp);
330 delete out;
331 }
332 ++ini_count;
de6a1a64 333 }
18837afa
AG
334 if (aBuilder.timestamp > setup_timestamp)
335 {
336 setup_timestamp = aBuilder.timestamp;
337 ini_setup_version = aBuilder.version;
338 }
339 delete ini_file;
340 ini_file = NULL;
b92028a4 341 }
dd3f7f9b 342 }
de6a1a64
RC
343 return ini_count;
344}
345
d9f4a2ba 346static bool
ab57ceaa 347do_ini_thread (HINSTANCE h, HWND owner)
de6a1a64
RC
348{
349 size_t ini_count = 0;
7cc4d95e 350 if (source == IDC_SOURCE_LOCALDIR)
ab57ceaa 351 ini_count = do_local_ini (owner);
de6a1a64 352 else
ab57ceaa 353 ini_count = do_remote_ini (owner);
de6a1a64 354
f6d6c600
JT
355 packagedb db;
356 db.upgrade();
357
de6a1a64 358 if (ini_count == 0)
d9f4a2ba 359 return false;
23c9e63c 360
18837afa 361 if (get_root_dir ().c_str ())
23c9e63c 362 {
b41c2908 363 io_stream::mkpath_p (PATH_TO_DIR, "cygfile:///etc/setup", 0755);
04d6e06b
DD
364
365 unsigned int old_timestamp = 0;
b24c88b3 366 io_stream *ots =
26922cd2 367 io_stream::open ("cygfile:///etc/setup/timestamp", "rt", 0);
04d6e06b 368 if (ots)
23c9e63c 369 {
b24c88b3
RC
370 char temp[20];
371 memset (temp, '\0', 20);
372 if (ots->read (temp, 19))
373 sscanf (temp, "%u", &old_timestamp);
374 delete ots;
04d6e06b
DD
375 if (old_timestamp && setup_timestamp
376 && (old_timestamp > setup_timestamp))
377 {
ab57ceaa 378 int yn = yesno (owner, IDS_OLD_SETUPINI);
04d6e06b 379 if (yn == IDNO)
5fa64c3c 380 Logger ().exit (1);
04d6e06b 381 }
23c9e63c 382 }
04d6e06b 383 if (setup_timestamp)
23c9e63c 384 {
b24c88b3 385 io_stream *nts =
26922cd2 386 io_stream::open ("cygfile:///etc/setup/timestamp", "wt", 0);
04d6e06b
DD
387 if (nts)
388 {
b24c88b3
RC
389 char temp[20];
390 sprintf (temp, "%u", setup_timestamp);
391 nts->write (temp, strlen (temp));
392 delete nts;
04d6e06b 393 }
23c9e63c
DD
394 }
395 }
396
18837afa 397 LogBabblePrintf (".ini setup_version is %s, our setup_version is %s", ini_setup_version.size () ?
b3edf57f 398 ini_setup_version.c_str () : "(null)",
2b734ec7 399 setup_version);
b3edf57f 400 if (ini_setup_version.size ())
13d27274 401 {
b3edf57f 402 if (version_compare (setup_version, ini_setup_version) < 0)
2b734ec7 403 note (owner, IDS_OLD_SETUP_VERSION, setup_version,
b3edf57f 404 ini_setup_version.c_str ());
13d27274
DD
405 }
406
d9f4a2ba 407 return true;
23c9e63c
DD
408}
409
45e01f23 410static DWORD WINAPI
18837afa 411do_ini_thread_reflector (void* p)
ab57ceaa 412{
072fb49a
MB
413 HANDLE *context;
414 context = (HANDLE*)p;
ab57ceaa 415
072fb49a
MB
416 try
417 {
18837afa 418 bool succeeded = do_ini_thread ((HINSTANCE)context[0], (HWND)context[1]);
ab57ceaa 419
072fb49a 420 // Tell the progress page that we're done downloading
18837afa 421 Progress.PostMessageNow (WM_APP_SETUP_INI_DOWNLOAD_COMPLETE, 0, succeeded);
072fb49a 422 }
18837afa 423 TOPLEVEL_CATCH ("ini");
ab57ceaa 424
18837afa 425 ExitThread (0);
ab57ceaa
RC
426}
427
428static HANDLE context[2];
429
430void
431do_ini (HINSTANCE h, HWND owner)
432{
45e01f23
RC
433 context[0] = h;
434 context[1] = owner;
30718d6f
CF
435
436 DWORD threadID;
45e01f23 437 CreateThread (NULL, 0, do_ini_thread_reflector, context, 0, &threadID);
ab57ceaa 438}
This page took 0.119692 seconds and 5 git commands to generate.