2 * Copyright (c) 2000,2007 Red Hat, Inc.
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.
9 * A copy of the GNU General Public License can be found at
12 * Written by DJ Delorie <dj@cygnus.com>
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. */
22 static const char *cvsid
=
28 #include "csu_util/rfc1738.h"
29 #include "csu_util/version_compare.h"
31 #include "setup_version.h"
33 #include "LogSingleton.h"
48 #include "IniParseFindVisitor.h"
49 #include "IniParseFeedback.h"
51 #include "io_stream.h"
52 #include "io_stream_memory.h"
56 #include "getopt++/BoolOption.h"
57 #include "IniDBBuilderPackage.h"
59 #include "Exception.h"
62 extern ThreeBarProgressPage Progress
;
64 unsigned int setup_timestamp
= 0;
65 std::string ini_setup_version
;
66 std::string current_ini_sig_name
;
68 static BoolOption
NoVerifyOption (false, 'X', "no-verify", "Don't verify setup.ini signatures");
70 extern int yyparse ();
71 /*extern int yydebug;*/
73 class GuiParseFeedback
: public IniParseFeedback
76 GuiParseFeedback () : lastpct (0)
78 Progress
.SetText2 ("");
79 Progress
.SetText3 ("");
80 Progress
.SetText4 ("Progress:");
82 virtual void progress(unsigned long const pos
, unsigned long const max
)
85 /* length not known or eof */
88 /* rounding down should mean this only ever fires once */
90 if (pos
* 100 / max
> lastpct
)
92 lastpct
= pos
* 100 / max
;
93 /* log (LOG_BABBLE) << lastpct << "% (" << pos << " of " << max
94 << " bytes of ini file read)" << endLog; */
96 Progress
.SetBar1(pos
, max
);
98 virtual void iniName (const std::string
& name
)
100 Progress
.SetText1 (("Parsing ini file \"" + name
+ "\"").c_str());
102 virtual void babble(const std::string
& message
)const
104 log (LOG_BABBLE
) << message
<< endLog
;
106 virtual void warning (const std::string
& message
)const
108 MessageBox (0, message
.c_str(), "Warning", 0);
110 virtual void error(const std::string
& message
)const
112 MessageBox (0, message
.c_str(), "Parse Errors", 0);
114 virtual ~ GuiParseFeedback ()
116 Progress
.SetText4("Package:");
119 unsigned int lastpct
;
123 do_local_ini (HWND owner
)
125 GuiParseFeedback myFeedback
;
126 IniDBBuilderPackage
findBuilder(myFeedback
);
127 IniParseFindVisitor
myVisitor (findBuilder
, local_dir
, myFeedback
);
128 Find (local_dir
).accept(myVisitor
);
129 setup_timestamp
= myVisitor
.timeStamp();
130 ini_setup_version
= myVisitor
.version();
131 return myVisitor
.iniCount();
135 do_remote_ini (HWND owner
)
137 size_t ini_count
= 0;
138 GuiParseFeedback myFeedback
;
139 IniDBBuilderPackage
aBuilder(myFeedback
);
140 io_stream
*ini_file
, *ini_sig_file
;
142 /* FIXME: Get rid of this io_stream pointer travesty. The need to
143 explicitly delete these things is ridiculous. Note that the
144 decompress io_stream "owns" the underlying compressed io_stream
145 instance, so it should not be deleted explicitly. */
147 for (SiteList::const_iterator n
= site_list
.begin();
148 n
!= site_list
.end(); ++n
)
150 bool sig_fail
= false;
151 /* First try to fetch the .bz2 compressed ini file. */
152 current_ini_name
= n
->url
+ "/" + SETUP_BZ2_FILENAME
;
153 current_ini_sig_name
= n
->url
+ "/" + SETUP_BZ2_FILENAME
+ ".sig";
154 ini_file
= get_url_to_membuf (current_ini_name
, owner
);
156 ini_sig_file
= get_url_to_membuf (current_ini_sig_name
, owner
);
157 if (!NoVerifyOption
&& ini_file
&& !ini_sig_file
)
159 note (owner
, IDS_SETUPINI_MISSING
, current_ini_sig_name
.c_str(), n
->url
.c_str());
164 else if (!NoVerifyOption
&& ini_file
&& !verify_ini_file_sig (ini_file
, ini_sig_file
, owner
))
166 note (owner
, IDS_SIG_INVALID
, current_ini_sig_name
.c_str(), n
->url
.c_str());
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
);
186 /* This isn't a valid bz2 file. */
192 io_stream
*uncompressed
= new io_stream_memory ();
194 if (io_stream::copy (bz2_stream
, uncompressed
) != 0 ||
195 bz2_stream
->error () == EIO
)
197 /* There was a problem decompressing bz2. */
202 "Warning: Problem encountered while uncompressing " <<
203 current_ini_name
<< " - possibly truncated or corrupt bzip2"
204 " file. Retrying with uncompressed version." << endLog
;
209 ini_file
= uncompressed
;
210 ini_file
->seek (0, IO_SEEK_SET
);
217 /* Try to look for a plain .ini file because one of the following
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
;
223 current_ini_sig_name
= n
->url
+ "/" + SETUP_INI_FILENAME
+ ".sig";
224 ini_file
= get_url_to_membuf (current_ini_name
, owner
);
226 ini_sig_file
= get_url_to_membuf (current_ini_sig_name
, owner
);
228 if (!NoVerifyOption
&& ini_file
&& !ini_sig_file
)
230 note (owner
, IDS_SETUPINI_MISSING
, current_ini_sig_name
.c_str(), n
->url
.c_str());
235 else if (!NoVerifyOption
&& ini_file
&& !verify_ini_file_sig (ini_file
, ini_sig_file
, owner
))
237 note (owner
, IDS_SIG_INVALID
, current_ini_sig_name
.c_str(), n
->url
.c_str());
249 note (owner
, IDS_SETUPINI_MISSING
, SETUP_INI_FILENAME
, n
->url
.c_str());
253 myFeedback
.iniName (current_ini_name
);
254 aBuilder
.parse_mirror
= n
->url
;
255 ini_init (ini_file
, &aBuilder
, myFeedback
);
259 if (yyparse () || yyerror_count
> 0)
260 myFeedback
.error (yyerror_messages
);
263 /* save known-good setup.ini locally */
264 const std::string fp
= "file://" + local_dir
+ "/" +
265 rfc1738_escape_part (n
->url
) +
266 "/" + SETUP_INI_FILENAME
;
267 io_stream::mkpath_p (PATH_TO_FILE
, fp
);
268 if (io_stream
*out
= io_stream::open (fp
, "wb"))
270 ini_file
->seek (0, IO_SEEK_SET
);
271 if (io_stream::copy (ini_file
, out
) != 0)
272 io_stream::remove (fp
);
277 if (aBuilder
.timestamp
> setup_timestamp
)
279 setup_timestamp
= aBuilder
.timestamp
;
280 ini_setup_version
= aBuilder
.version
;
288 do_ini_thread (HINSTANCE h
, HWND owner
)
290 size_t ini_count
= 0;
291 if (source
== IDC_SOURCE_CWD
)
292 ini_count
= do_local_ini (owner
);
294 ini_count
= do_remote_ini (owner
);
299 if (get_root_dir ().c_str())
301 io_stream::mkpath_p (PATH_TO_DIR
, "cygfile:///etc/setup");
303 unsigned int old_timestamp
= 0;
305 io_stream::open ("cygfile:///etc/setup/timestamp", "rt");
309 memset (temp
, '\0', 20);
310 if (ots
->read (temp
, 19))
311 sscanf (temp
, "%u", &old_timestamp
);
313 if (old_timestamp
&& setup_timestamp
314 && (old_timestamp
> setup_timestamp
))
316 int yn
= yesno (owner
, IDS_OLD_SETUPINI
);
318 LogSingleton::GetInstance().exit (1);
324 io_stream::open ("cygfile:///etc/setup/timestamp", "wt");
328 sprintf (temp
, "%u", setup_timestamp
);
329 nts
->write (temp
, strlen (temp
));
335 msg (".ini setup_version is %s, our setup_version is %s", ini_setup_version
.size() ?
336 ini_setup_version
.c_str() : "(null)",
338 if (ini_setup_version
.size())
340 if (version_compare(setup_version
, ini_setup_version
) < 0)
341 note (owner
, IDS_OLD_SETUP_VERSION
, setup_version
,
342 ini_setup_version
.c_str());
349 do_ini_thread_reflector(void* p
)
352 context
= (HANDLE
*)p
;
356 bool succeeded
= do_ini_thread((HINSTANCE
)context
[0], (HWND
)context
[1]);
358 // Tell the progress page that we're done downloading
359 Progress
.PostMessage(WM_APP_SETUP_INI_DOWNLOAD_COMPLETE
, 0, succeeded
);
361 TOPLEVEL_CATCH("ini");
366 static HANDLE context
[2];
369 do_ini (HINSTANCE h
, HWND owner
)
375 CreateThread (NULL
, 0, do_ini_thread_reflector
, context
, 0, &threadID
);