]> cygwin.com Git - cygwin-apps/setup.git/blobdiff - ini.cc
Merged across diffs between setup_crypto_branch_branchpoint and
[cygwin-apps/setup.git] / ini.cc
diff --git a/ini.cc b/ini.cc
index 6afde38449bb8794216ba08eb036dc07d20e7015..5ba481eb5a02deb3a58280a956778be32350f87d 100644 (file)
--- a/ini.cc
+++ b/ini.cc
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, Red Hat, Inc.
+ * Copyright (c) 2000,2007 Red Hat, Inc.
  *
  *     This program is free software; you can redistribute it and/or modify
  *     it under the terms of the GNU General Public License as published by
@@ -23,70 +23,100 @@ static const char *cvsid =
   "\n%%% $Id$\n";
 #endif
 
+#include "ini.h"
+
+#include "csu_util/rfc1738.h"
+#include "csu_util/version_compare.h"
+
+#include "setup_version.h"
 #include "win32.h"
+#include "LogSingleton.h"
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdarg.h>
 #include <process.h>
 
-#include "ini.h"
 #include "resource.h"
-#include "String++.h"
 #include "state.h"
 #include "geturl.h"
 #include "dialog.h"
 #include "msg.h"
-#include "log.h"
-#include "version.h"
 #include "mount.h"
 #include "site.h"
-#include "rfc1738.h"
 #include "find.h"
 #include "IniParseFindVisitor.h"
 #include "IniParseFeedback.h"
-//#include "filemanip.h"
 
 #include "io_stream.h"
+#include "io_stream_memory.h"
 
 #include "threebar.h"
 
-#include "rfc1738.h"
-
+#include "getopt++/BoolOption.h"
 #include "IniDBBuilderPackage.h"
 #include "compress.h"
+#include "Exception.h"
+#include "crypto.h"
   
 extern ThreeBarProgressPage Progress;
 
 unsigned int setup_timestamp = 0;
-String setup_version;
+std::string ini_setup_version;
+std::string current_ini_sig_name;
+
+static BoolOption NoVerifyOption (false, 'X', "no-verify", "Don't verify setup.ini signatures");
 
 extern int yyparse ();
 /*extern int yydebug;*/
 
-static char *error_buf = 0;
-static int error_count = 0;
-
-static const char *ini_filename;
-
 class GuiParseFeedback : public IniParseFeedback
 {
 public:
-  virtual void babble(String const &message)const
+  GuiParseFeedback () : lastpct (0) 
+    {
+      Progress.SetText2 ("");
+      Progress.SetText3 ("");
+      Progress.SetText4 ("Progress:");
+    }
+  virtual void progress(unsigned long const pos, unsigned long const max)
+    {
+      if (!max)
+       /* length not known or eof */
+       return;
+      if (lastpct == 100)
+       /* rounding down should mean this only ever fires once */
+       lastpct = 0;
+      if (pos * 100 / max > lastpct)
+       {
+         lastpct = pos * 100 / max;
+         /* log (LOG_BABBLE) << lastpct << "% (" << pos << " of " << max
+            << " bytes of ini file read)" << endLog; */
+       }
+      Progress.SetBar1(pos, max);
+    }
+  virtual void iniName (const std::string& name)
     {
-      log (LOG_BABBLE, message);
+      Progress.SetText1 (("Parsing ini file \"" + name + "\"").c_str());
     }
-  virtual void warning (String const &message)const
+  virtual void babble(const std::string& message)const
     {
-      MessageBox (0, message.cstr_oneuse(), "Warning", 0);
+      log (LOG_BABBLE) << message << endLog;
     }
-  virtual void error(String const &message)const
+  virtual void warning (const std::string& message)const
     {
-      MessageBox (0, message.cstr_oneuse(), "Error parsing", 0);
+      MessageBox (0, message.c_str(), "Warning", 0);
+    }
+  virtual void error(const std::string& message)const
+    {
+      MessageBox (0, message.c_str(), "Parse Errors", 0);
     }
   virtual ~ GuiParseFeedback ()
     {
+      Progress.SetText4("Package:");
     }
+private:
+  unsigned int lastpct;
 };
 
 static int
@@ -97,7 +127,7 @@ do_local_ini (HWND owner)
   IniParseFindVisitor myVisitor (findBuilder, local_dir, myFeedback);
   Find (local_dir).accept(myVisitor);
   setup_timestamp = myVisitor.timeStamp();
-  setup_version = myVisitor.version();
+  ini_setup_version = myVisitor.version();
   return myVisitor.iniCount(); 
 }
 
@@ -107,69 +137,154 @@ do_remote_ini (HWND owner)
   size_t ini_count = 0;
   GuiParseFeedback myFeedback;
   IniDBBuilderPackage aBuilder(myFeedback);
-  
-  for (size_t n = 1; n <= site_list.number (); n++)
+  io_stream *ini_file, *ini_sig_file;
+
+  /* FIXME: Get rid of this io_stream pointer travesty.  The need to
+     explicitly delete these things is ridiculous.  Note that the
+     decompress io_stream "owns" the underlying compressed io_stream
+     instance, so it should not be deleted explicitly.  */
+
+  for (SiteList::const_iterator n = site_list.begin();
+       n != site_list.end(); ++n)
     {
-      io_stream *compressed_ini_file =
-       get_url_to_membuf (site_list[n]->url + "/setup.bz2", owner);
-      io_stream *ini_file = 0;
-      if (!compressed_ini_file)
-       ini_file = get_url_to_membuf (site_list[n]->url + "/setup.ini", owner);
-      else
+      bool sig_fail = false;
+      /* First try to fetch the .bz2 compressed ini file.  */
+      current_ini_name = n->url + "/" + SETUP_BZ2_FILENAME;
+      current_ini_sig_name = n->url + "/" + SETUP_BZ2_FILENAME + ".sig";
+      ini_file = get_url_to_membuf (current_ini_name, owner);
+      if (!NoVerifyOption)
+        ini_sig_file = get_url_to_membuf (current_ini_sig_name, owner);
+      if (!NoVerifyOption && ini_file && !ini_sig_file)
+       {
+         note (owner, IDS_SETUPINI_MISSING, current_ini_sig_name.c_str(), n->url.c_str());
+         delete ini_file;
+         ini_file = NULL;
+         sig_fail = true;
+       }
+      else if (!NoVerifyOption && ini_file && !verify_ini_file_sig (ini_file, ini_sig_file, owner))
+       {
+         note (owner, IDS_SIG_INVALID, current_ini_sig_name.c_str(), n->url.c_str());
+         delete ini_file;
+         ini_file = NULL;
+         delete ini_sig_file;
+         ini_sig_file = NULL;
+         sig_fail = true;
+       }
+      if (ini_file)
        {
-         ini_file = compress::decompress (compressed_ini_file);
+          /* Decompress the entire file in memory right now.  This has the
+             advantage that input_stream->get_size() will work during parsing
+             and we'll have an accurate status bar.  Also, we can't seek 
+             bz2 streams, so when it comes time to write out a local cached
+             copy of the .ini file below, we'd otherwise have to delete this
+             stream and uncompress it again from the start, which is wasteful.
+             The current uncompresed size of the .ini file as of 2007 is less
+             than 600 kB, so this is not a great deal of memory.  */
+         io_stream *bz2_stream = compress::decompress (ini_file);
+         if (!bz2_stream)
+           {
+             /* This isn't a valid bz2 file.  */
+             delete ini_file;
+             ini_file = NULL;
+           }
+         else
+            {
+             io_stream *uncompressed = new io_stream_memory ();
+
+              if (io_stream::copy (bz2_stream, uncompressed) != 0 ||
+                  bz2_stream->error () == EIO)
+                {
+                  /* There was a problem decompressing bz2.  */
+                  delete bz2_stream;
+                  delete uncompressed;
+                  ini_file = NULL;
+                  log (LOG_PLAIN) << 
+                    "Warning: Problem encountered while uncompressing " <<
+                    current_ini_name << " - possibly truncated or corrupt bzip2"
+                    " file.  Retrying with uncompressed version." << endLog;
+                }
+              else
+                {
+                  delete bz2_stream;
+                  ini_file = uncompressed;
+                  ini_file->seek (0, IO_SEEK_SET);
+                }
+            }
+       }
+      
+      if (!ini_file)
+        {
+          /* Try to look for a plain .ini file because one of the following
+             happened above:
+               - there was no .bz2 file found on the mirror.
+               - the .bz2 file didn't look like a valid bzip2 file.
+               - there was an error during bzip2 decompression.  */
+          current_ini_name = n->url + "/" + SETUP_INI_FILENAME;
+          current_ini_sig_name = n->url + "/" + SETUP_INI_FILENAME + ".sig";
+         ini_file = get_url_to_membuf (current_ini_name, owner);
+         if (!NoVerifyOption)
+           ini_sig_file = get_url_to_membuf (current_ini_sig_name, owner);
+
+         if (!NoVerifyOption && ini_file && !ini_sig_file)
+           {
+             note (owner, IDS_SETUPINI_MISSING, current_ini_sig_name.c_str(), n->url.c_str());
+             delete ini_file;
+             ini_file = NULL;
+             sig_fail = true;
+           }
+         else if (!NoVerifyOption && ini_file && !verify_ini_file_sig (ini_file, ini_sig_file, owner))
+           {
+             note (owner, IDS_SIG_INVALID, current_ini_sig_name.c_str(), n->url.c_str());
+             delete ini_file;
+             ini_file = NULL;
+             delete ini_sig_file;
+             ini_sig_file = NULL;
+             sig_fail = true;
+           }
        }
 
       if (!ini_file)
        {
-         note (owner, IDS_SETUPINI_MISSING, site_list[n]->url.cstr_oneuse());
+         if (!sig_fail)
+           note (owner, IDS_SETUPINI_MISSING, SETUP_INI_FILENAME, n->url.c_str());
          continue;
        }
 
-      aBuilder.parse_mirror = site_list[n]->url;
-      ini_init (ini_file, &aBuilder);
+      myFeedback.iniName (current_ini_name);
+      aBuilder.parse_mirror = n->url;
+      ini_init (ini_file, &aBuilder, myFeedback);
 
       /*yydebug = 1; */
 
-      if (yyparse () || error_count > 0)
-       MessageBox (0, error_buf,
-                   error_count == 1 ? "Parse Error" : "Parse Errors", 0);
+      if (yyparse () || yyerror_count > 0)
+        myFeedback.error (yyerror_messages);
       else
        {
          /* save known-good setup.ini locally */
-         String const fp = String ("file://") + local_dir + "/" +
-                                  rfc1738_escape_part (site_list[n]->url) +
-                                  "/setup.ini";
+         const std::string fp = "file://" + local_dir + "/" +
+                                  rfc1738_escape_part (n->url) +
+                                  "/" + SETUP_INI_FILENAME;
          io_stream::mkpath_p (PATH_TO_FILE, fp);
-         io_stream *inistream = io_stream::open (fp, "wb");
-         if (inistream)
+         if (io_stream *out = io_stream::open (fp, "wb"))
            {
-             if (compressed_ini_file)
-               {
-                 delete ini_file;
-                 compressed_ini_file->seek (0, IO_SEEK_SET);
-                 ini_file = compress::decompress (compressed_ini_file);
-               }
-             else
-               ini_file->seek (0, IO_SEEK_SET);
-             if (io_stream::copy (ini_file, inistream))
+              ini_file->seek (0, IO_SEEK_SET);
+             if (io_stream::copy (ini_file, out) != 0)
                io_stream::remove (fp);
-             delete inistream;
+             delete out;
            }
          ++ini_count;
        }
       if (aBuilder.timestamp > setup_timestamp)
        {
          setup_timestamp = aBuilder.timestamp;
-         setup_version = aBuilder.version;
+         ini_setup_version = aBuilder.version;
        }
       delete ini_file;
-      delete compressed_ini_file;
     }
   return ini_count;
 }
 
-static void
+static bool
 do_ini_thread (HINSTANCE h, HWND owner)
 {
   size_t ini_count = 0;
@@ -179,12 +294,9 @@ do_ini_thread (HINSTANCE h, HWND owner)
     ini_count = do_remote_ini (owner);
 
   if (ini_count == 0)
-    {
-      next_dialog = source == IDC_SOURCE_CWD ? IDD_S_FROM_CWD : IDD_SITE;
-      return;
-    }
+    return false;
 
-  if (get_root_dir ().cstr_oneuse())
+  if (get_root_dir ().c_str())
     {
       io_stream::mkpath_p (PATH_TO_DIR, "cygfile:///etc/setup");
 
@@ -220,33 +332,35 @@ do_ini_thread (HINSTANCE h, HWND owner)
        }
     }
 
-  msg ("setup_version is %s, our_version is %s", setup_version.size() ? 
-       setup_version.cstr_oneuse() : "(null)",
-       version);
-  if (setup_version.size())
+  msg (".ini setup_version is %s, our setup_version is %s", ini_setup_version.size() ? 
+       ini_setup_version.c_str() : "(null)",
+       setup_version);
+  if (ini_setup_version.size())
     {
-      String ini_version = canonicalize_version (setup_version);
-      String our_version = canonicalize_version (version);
-      // XXX useversion < operator
-      if (our_version.compare (ini_version) < 0)
-       note (owner, IDS_OLD_SETUP_VERSION, version, setup_version.cstr_oneuse());
+      if (version_compare(setup_version, ini_setup_version) < 0)
+       note (owner, IDS_OLD_SETUP_VERSION, setup_version,
+              ini_setup_version.c_str());
     }
 
-  next_dialog = IDD_CHOOSE;
+  return true;
 }
 
 static DWORD WINAPI
 do_ini_thread_reflector(void* p)
 {
-       HANDLE *context;
-       context = (HANDLE*)p;
+  HANDLE *context;
+  context = (HANDLE*)p;
 
-       do_ini_thread((HINSTANCE)context[0], (HWND)context[1]);
+  try
+  {
+    bool succeeded = do_ini_thread((HINSTANCE)context[0], (HWND)context[1]);
 
-       // Tell the progress page that we're done downloading
-       Progress.PostMessage(WM_APP_SETUP_INI_DOWNLOAD_COMPLETE, 0, next_dialog);
+    // Tell the progress page that we're done downloading
+    Progress.PostMessage(WM_APP_SETUP_INI_DOWNLOAD_COMPLETE, 0, succeeded);
+  }
+  TOPLEVEL_CATCH("ini");
 
-       ExitThread(0);
+  ExitThread(0);
 }
 
 static HANDLE context[2];
@@ -261,63 +375,3 @@ do_ini (HINSTANCE h, HWND owner)
   CreateThread (NULL, 0, do_ini_thread_reflector, context, 0, &threadID);
 }
 
-
-extern int yylineno;
-extern int yybol ();
-
-extern int
-yyerror (String const &s)
-{
-  char buf[MAX_PATH + 1000];
-  int len;
-  sprintf (buf, "%s line %d: ", ini_filename, yylineno - yybol ());
-  sprintf (buf + strlen (buf), s.cstr_oneuse());
-  OutputDebugString (buf);
-  if (error_buf)
-    {
-      strcat (error_buf, "\n");
-      len = strlen (error_buf) + strlen (buf) + 5;
-      error_buf = (char *) realloc (error_buf, len);
-      strcat (error_buf, buf);
-    }
-  else
-    {
-      len = strlen (buf) + 5;
-      error_buf = (char *) malloc (len);
-      strcpy (error_buf, buf);
-    }
-  error_count++;
-  /* TODO: is return 0 correct? */
-  return 0;
-}
-
-extern "C" int fprintf (FILE * f, const char *s, ...);
-
-static char stderrbuf[1000];
-
-int
-fprintf (FILE * f, const char *fmt, ...)
-{
-  char buf[1000];
-  int rv;
-  va_list args;
-  va_start (args, fmt);
-  if (f == stderr)
-    {
-      rv = vsprintf (buf, fmt, args);
-      strcat (stderrbuf, buf);
-      if (char *nl = strchr (stderrbuf, '\n'))
-       {
-         *nl = 0;
-         /*OutputDebugString (stderrbuf); */
-         MessageBox (0, buf, "Cygwin Setup", 0);
-         stderrbuf[0] = 0;
-       }
-
-    }
-  else
-    {
-      rv = vfprintf (f, fmt, args);
-    }
-  return rv;
-}
This page took 0.034515 seconds and 5 git commands to generate.