]> cygwin.com Git - cygwin-apps/setup.git/blobdiff - install.cc
2001-12-22 Gary R. Van Sickle <g.r.vansickle@worldnet.att.net>
[cygwin-apps/setup.git] / install.cc
index 2a5852f2f07ca46e78a6b4f2543a1e33f99acbe9..b53c39ca3510d4c5af6cf1583c77a3513adc3605 100644 (file)
    the install list (in ini.h).  Note that we use a separate thread to
    maintain the progress dialog, so we avoid the complexity of
    handling two tasks in one thread.  We also create or update all the
-   files in /etc/setup/* and create the mount points. */
+   files in /etc/setup/\* and create the mount points. */
+
+#if 0
+static const char *cvsid =
+  "\n%%% $Id$\n";
+#endif
 
 #include "win32.h"
 #include "commctrl.h"
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <unistd.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <errno.h>
+#include <process.h>
+
 #include "zlib/zlib.h"
 
 #include "resource.h"
 #include "geturl.h"
 #include "mkdir.h"
 #include "state.h"
-#include "tar.h"
 #include "diskfull.h"
 #include "msg.h"
 #include "mount.h"
+#include "log.h"
+#include "mount.h"
+#include "filemanip.h"
+#include "io_stream.h"
+#include "compress.h"
+#include "compress_gz.h"
+#include "archive.h"
+#include "archive_tar.h"
+
+#include "package_db.h"
+#include "package_meta.h"
+#include "package_version.h"
+#include "package_source.h"
 
-static HWND ins_dialog = 0;
-static HWND ins_pkgname = 0;
-static HWND ins_filename = 0;
-static HWND ins_pprogress = 0;
-static HWND ins_iprogress = 0;
-static HWND ins_diskfull = 0;
-static HANDLE init_event;
+#include "port.h"
+
+#include "threebar.h"
+extern ThreeBarProgressPage Progress;
 
 static int total_bytes = 0;
 static int total_bytes_sofar = 0;
 static int package_bytes = 0;
 
-static BOOL
-dialog_cmd (HWND h, int id, HWND hwndctl, UINT code)
-{
-  switch (id)
-    {
-    case IDCANCEL:
-      ExitProcess(0);
-    }
-}
-
-static BOOL CALLBACK
-dialog_proc (HWND h, UINT message, WPARAM wParam, LPARAM lParam)
-{
-  int i, j;
-  HWND listbox;
-  switch (message)
-    {
-    case WM_INITDIALOG:
-      ins_dialog = h;
-      ins_pkgname = GetDlgItem (h, IDC_INS_PKG);
-      ins_filename = GetDlgItem (h, IDC_INS_FILE);
-      ins_pprogress = GetDlgItem (h, IDC_INS_PPROGRESS);
-      ins_iprogress = GetDlgItem (h, IDC_INS_IPROGRESS);
-      ins_diskfull = GetDlgItem (h, IDC_INS_DISKFULL);
-      SetEvent (init_event);
-      return FALSE;
-    case WM_COMMAND:
-      return HANDLE_WM_COMMAND(h, wParam, lParam, dialog_cmd);
-    }
-  return FALSE;
-}
-
-static WINAPI DWORD
-dialog (void *)
-{
-  int rv = 0;
-  MSG m;
-  HANDLE ins_dialog = CreateDialog (hinstance, MAKEINTRESOURCE (IDD_INSTATUS),
-                                  0, dialog_proc);
-  if (ins_dialog == 0)
-    fatal ("create dialog");
-  ShowWindow (ins_dialog, SW_SHOWNORMAL);
-  UpdateWindow (ins_dialog);
-  while (GetMessage (&m, 0, 0, 0) > 0) {
-    TranslateMessage (&m);
-    DispatchMessage (&m);
-  }
-}
-
-static DWORD start_tics;
-
 static void
 init_dialog ()
 {
-  if (ins_dialog == 0)
-    {
-      DWORD tid;
-      HANDLE thread;
-      init_event = CreateEvent (0, 0, 0, 0);
-      thread = CreateThread (0, 0, dialog, 0, 0, &tid);
-      WaitForSingleObject (init_event, 10000);
-      CloseHandle (init_event);
-      SendMessage (ins_pprogress, PBM_SETRANGE, 0, MAKELPARAM (0, 100));
-      SendMessage (ins_iprogress, PBM_SETRANGE, 0, MAKELPARAM (0, 100));
-      SendMessage (ins_diskfull, PBM_SETRANGE, 0, MAKELPARAM (0, 100));
-    }
-
-  SetWindowText (ins_pkgname, "");
-  SetWindowText (ins_filename, "");
-  SendMessage (ins_pprogress, PBM_SETPOS, (WPARAM) 0, 0);
-  SendMessage (ins_iprogress, PBM_SETPOS, (WPARAM) 0, 0);
-  SendMessage (ins_diskfull, PBM_SETPOS, (WPARAM) 0, 0);
-  ShowWindow (ins_dialog, SW_SHOWNORMAL);
-  SetForegroundWindow (ins_dialog);
+  Progress.SetText2 ("");
+  Progress.SetText3 ("");
 }
 
 static void
 progress (int bytes)
 {
-  int perc;
-
-  if (package_bytes > 100)
+  if (package_bytes > 0)
     {
-      perc = bytes / (package_bytes / 100);
-      SendMessage (ins_pprogress, PBM_SETPOS, (WPARAM) perc, 0);
+      Progress.SetBar1 (bytes, package_bytes);
     }
 
-  if (total_bytes > 100)
+  if (total_bytes > 0)
     {
-      perc = (total_bytes_sofar + bytes) / (total_bytes / 100);
-      SendMessage (ins_iprogress, PBM_SETPOS, (WPARAM) perc, 0);
+      Progress.SetBar2 (total_bytes_sofar + bytes, total_bytes);
     }
-
-  int df = diskfull (root_dir);
-  SendMessage (ins_diskfull, PBM_SETPOS, (WPARAM) df, 0);
 }
 
-static void
-badrename (char *o, char *n)
-{
-  char buf[1000];
-  char *err = strerror (errno);
-  if (!err)
-    err = "(unknown error)";
-  note (IDS_ERR_RENAME, o, n, err);
-}
-
-static char *standard_dirs[] = {
+static const char *standard_dirs[] = {
   "/bin",
   "/etc",
   "/lib",
   "/tmp",
+  "/usr",
   "/usr/bin",
   "/usr/lib",
+  "/usr/src",
+  "/usr/local",
   "/usr/local/bin",
   "/usr/local/etc",
   "/usr/local/lib",
@@ -176,177 +110,316 @@ static char *standard_dirs[] = {
   0
 };
 
-#define pi (package[i].info[package[i].trust])
-
-#define LOOP_PACKAGES \
-  for (i=0; i<npackages; i++) \
-    if (package[i].action == ACTION_NEW \
-       || package[i].action == ACTION_UPGRADE)
+static int num_installs, num_uninstalls;
 
-void
-do_install (HINSTANCE h)
+/* FIXME: upgrades should be a method too */
+static void
+uninstall_one (packagemeta & pkgm)
 {
-  int i, num_installs = 0;
-  next_dialog = 0;
+  Progress.SetText1 ("Uninstalling...");
+  Progress.SetText2 (pkgm.name);
+  log (0, "Uninstalling %s", pkgm.name);
+  pkgm.uninstall ();
+  num_uninstalls++;
+}
+
 
-  mkdir_p (1, root_dir);
 
-  for (i=0; standard_dirs[i]; i++)
+/* install one source at a given prefix. */
+static int
+install_one_source (packagemeta & pkgm, packagesource & source,
+                   char const *prefix, package_type_t type)
+{
+  int errors = 0;
+  Progress.SetText2 (source.Base ());
+  if (!io_stream::exists (source.Cached ()))
     {
-      char *p = concat (root_dir, standard_dirs[i], 0);
-      mkdir_p (1, p);
-      free (p);
+      note (NULL, IDS_ERR_OPEN_READ, source.Cached (), "No such file");
+      return 1;
+    }
+  io_stream *lst = 0;
+  if (type == package_binary)
+    {
+      io_stream *tmp =
+       io_stream::
+       open (concat ("cygfile:///etc/setup/", pkgm.name, ".lst.gz", 0),
+             "wb");
+      lst = new compress_gz (tmp, "w9");
+      if (lst->error ())
+       {
+         delete lst;
+         lst = NULL;
+       }
     }
 
-  /* Create /var/run/utmp */
-  char *utmp = concat (root_dir, "/var/run/utmp", 0);
-  FILE *ufp = fopen (utmp, "wb");
-  if (ufp)
-    fclose (ufp);
-  free (utmp);
+  package_bytes = source.size;
 
-  dismiss_url_status_dialog ();
+  char msg[64];
+  strcpy (msg, "Installing");
+  Progress.SetText1 (msg);
+  log (0, "%s%s", msg, source.Cached ());
+  io_stream *tmp = io_stream::open (source.Cached (), "rb");
+  archive *thefile = 0;
+  if (tmp)
+    {
+      io_stream *tmp2 = compress::decompress (tmp);
+      if (tmp2)
+       thefile = archive::extract (tmp2);
+      else
+       thefile = archive::extract (tmp);
+    }
+  /* FIXME: potential leak of either *tmp or *tmp2 */
+  if (thefile)
+    {
+      const char *fn;
+      while ((fn = thefile->next_file_name ()))
+       {
+         if (lst)
+           lst->write (concat (fn, "\n", 0), strlen (fn) + 1);
 
-  init_dialog ();
+         /* FIXME: concat leaks memory */
+         Progress.SetText3 (concat (prefix, fn, 0));
+         log (LOG_BABBLE, "Installing file %s%s", prefix, fn);
+         if (archive::extract_file (thefile, prefix) != 0)
+           {
+             log (0, "Unable to install file %s%s", prefix, fn);
+             errors++;
+           }
 
-  total_bytes = 0;
-  total_bytes_sofar = 0;
+         progress (tmp->tell ());
+         num_installs++;
+       }
+      delete thefile;
 
-  LOOP_PACKAGES
-    {
-      total_bytes += pi.install_size;
+      total_bytes_sofar += package_bytes;
     }
 
-  LOOP_PACKAGES
-    {
-      char *local = pi.install, *cp, *fn, *base;
 
-      base = local;
-      for (cp=pi.install; *cp; cp++)
-       if (*cp == '/' || *cp == '\\' || *cp == ':')
-         base = cp+1;
-      SetWindowText (ins_pkgname, base);
+  progress (0);
 
-      gzFile lst = gzopen (concat (root_dir, "/etc/setup/",
-                                  package[i].name, ".lst.gz", 0),
-                          "wb9");
+  int df = diskfull (get_root_dir ());
+  Progress.SetBar3 (df);
 
-      package_bytes = pi.install_size;
+  if (lst)
+    delete lst;
 
-      tar_open (local);
-      while (fn = tar_next_file ())
-       {
-         char *dest_file;
+  return errors;
+}
 
-         while (*fn == '/' || *fn == '\\')
-           fn++;
+/* install a package, install both the binary and source aspects if needed */
+static int
+install_one (packagemeta & pkg)
+{
+  int errors = 0;
 
-         if (lst)
-           gzprintf(lst, "%s\n", fn);
+  if (pkg.desired->binpicked)
+    {
+      errors +=
+       install_one_source (pkg, pkg.desired->bin, "cygfile:///",
+                           package_binary);
+      if (!errors)
+       pkg.installed = pkg.desired;
+    }
+  if (pkg.desired->srcpicked)
+    errors +=
+      install_one_source (pkg, pkg.desired->src, "cygfile:///usr/src",
+                         package_source);
+
+  /* FIXME: make a upgrade method and reinstate this */
+#if 0
+  char msg[64];
+  if (!pkg->installed)
+    strcpy (msg, "Installing");
+  else
+    {
+      int n = strcmp (pi->version, pkg->installed->version);
+      if (n < 0)
+       strcpy (msg, "Reverting");
+      else if (n == 0)
+       strcpy (msg, "Reinstalling");
+      else
+       strcpy (msg, "Upgrading");
+    }
 
-         if (strncmp (fn, "usr/bin/", 8) == 0)
-           dest_file = concat(root_dir, "/bin/", fn+8, 0);
-         else if (strncmp (fn, "usr/lib/", 8) == 0)
-           dest_file = concat(root_dir, "/lib/", fn+8, 0);
-         else
-           dest_file = concat(root_dir, "/", fn, 0);
+  switch (pkg->action)
+    {
+    case ACTION_PREV:
+      strcat (msg, " previous version...");
+      break;
+    case ACTION_CURR:
+      strcat (msg, "...");
+      break;
+    case ACTION_TEST:
+      strcat (msg, " test version...");
+      break;
+    default:
+      /* FIXME: log this somehow */
+      break;
+    }
+  SetWindowText (ins_action, msg);
+  log (0, "%s%s", msg, file);
+#endif
 
-         SetWindowText (ins_filename, dest_file);
-         tar_read_file (dest_file);
+  return errors;
+}
 
-         progress (tar_ftell ());
-         num_installs ++;
+static void
+check_for_old_cygwin ()
+{
+  char buf[_MAX_PATH + sizeof ("\\cygwin1.dll")];
+  if (!GetSystemDirectory (buf, sizeof (buf)))
+    return;
+  strcat (buf, "\\cygwin1.dll");
+  if (_access (buf, 0) != 0)
+    return;
+
+  char msg[sizeof (buf) + 132];
+  sprintf (msg,
+          "An old version of cygwin1.dll was found here:\r\n%s\r\nDelete?",
+          buf);
+  switch (MessageBox
+         (NULL, msg, "What's that doing there?",
+          MB_YESNO | MB_ICONQUESTION | MB_TASKMODAL))
+    {
+    case IDYES:
+      if (!DeleteFile (buf))
+       {
+         sprintf (msg, "Couldn't delete file %s.\r\n"
+                  "Is the DLL in use by another application?\r\n"
+                  "You should delete the old version of cygwin1.dll\r\n"
+                  "at your earliest convenience.", buf);
+         MessageBox (NULL, buf, "Couldn't delete file",
+                     MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
        }
-      tar_close ();
+      break;
+    default:
+      break;
+    }
 
-      total_bytes_sofar += pi.install_size;
-      progress (0);
+  return;
+}
 
-      if (lst)
-       gzclose (lst);
-    }
+static void
+do_install_thread (HINSTANCE h, HWND owner)
+{
+  int i;
+  int errors = 0;
 
-  ShowWindow (ins_dialog, SW_HIDE);
+  num_installs = 0, num_uninstalls = 0;
 
-  if (num_installs == 0)
+  next_dialog = IDD_DESKTOP;
+
+  mkdir_p (1, get_root_dir ());
+
+  for (i = 0; standard_dirs[i]; i++)
     {
-      note (IDS_NOTHING_INSTALLED);
-      return;
+      char *p = cygpath (standard_dirs[i], 0);
+      mkdir_p (1, p);
+      free (p);
     }
 
-  char *odbn = concat (root_dir, "/etc/setup/installed.db", 0);
-  char *ndbn = concat (root_dir, "/etc/setup/installed.db.new", 0);
-  char *sdbn = concat (root_dir, "/etc/setup/installed.db.old", 0);
+  /* Create /var/run/utmp */
+  io_stream *utmp = io_stream::open ("cygfile:///var/run/utmp", "wb");
+  delete utmp;
 
-  mkdir_p (0, ndbn);
+  init_dialog ();
 
-  FILE *odb = fopen (odbn, "rt");
-  FILE *ndb = fopen (ndbn, "wb");
+  total_bytes = 0;
+  total_bytes_sofar = 0;
 
-  if (!ndb)
+  int df = diskfull (get_root_dir ());
+  Progress.SetBar3 (df);
+
+  int istext = (root_text == IDC_ROOT_TEXT) ? 1 : 0;
+  int issystem = (root_scope == IDC_ROOT_SYSTEM) ? 1 : 0;
+
+  create_mount ("/", get_root_dir (), istext, issystem);
+  create_mount ("/usr/bin", cygpath ("/bin", 0), istext, issystem);
+  create_mount ("/usr/lib", cygpath ("/lib", 0), istext, issystem);
+  set_cygdrive_flags (istext, issystem);
+
+  packagedb db;
+  for (size_t n = 1; n < db.packages.number (); n++)
     {
-      char *err = strerror (errno);
-      if (!err)
-       err = "(unknown error)";
-      fatal (IDS_ERR_OPEN_WRITE, ndb, err);
+      packagemeta & pkg = *db.packages[n];
+
+      if (pkg.desired && (pkg.desired->srcpicked || pkg.desired->binpicked))
+       {
+         if (pkg.desired->srcpicked)
+           total_bytes += pkg.desired->src.size;
+         if (pkg.desired->binpicked)
+           total_bytes += pkg.desired->bin.size;
+       }
     }
 
-  if (odb)
+  for (size_t n = 1; n < db.packages.number (); n++)
     {
-      char line[1000], pkg[1000];
-      int printit;
-      while (fgets (line, 1000, odb))
+      packagemeta & pkg = *db.packages[n];
+      if (pkg.installed && (!pkg.desired || pkg.desired != pkg.installed))
        {
-         printit = 1;
-         sscanf(line, "%s", pkg);
-         LOOP_PACKAGES
+         uninstall_one (pkg);
+       }
+
+      if (pkg.desired && (pkg.desired->srcpicked || pkg.desired->binpicked))
+       {
+         int e = 0;
+         e += install_one (pkg);
+         if (e)
            {
-             if (strcmp (pkg, package[i].name) == 0)
-               {
-                 printit = 0;
-                 break;
-               }
+             errors++;
            }
-         if (printit)
-           fputs (line, ndb);
        }
-      
+    }                          // end of big package loop
+
+  int temperr;
+  if ((temperr = db.flush ()))
+    {
+      const char *err = strerror (temperr);
+      if (!err)
+       err = "(unknown error)";
+      fatal (owner, IDS_ERR_OPEN_WRITE, err);
     }
-  LOOP_PACKAGES
+
+  if (!errors)
+    check_for_old_cygwin ();
+  if (num_installs == 0 && num_uninstalls == 0)
     {
-      fprintf (ndb, "%s %s %d\n", package[i].name,
-              pi.install, pi.install_size);
+      exit_msg = IDS_NOTHING_INSTALLED;
+      return;
+    }
+  if (num_installs == 0)
+    {
+      exit_msg = IDS_UNINSTALL_COMPLETE;
+      return;
     }
 
-  if (odb)
-    fclose (odb);
-  fclose (ndb);
+  if (errors)
+    exit_msg = IDS_INSTALL_INCOMPLETE;
+  else
+    exit_msg = IDS_INSTALL_COMPLETE;
+}
 
-  remove (sdbn);
-  if (odb && rename (odbn, sdbn))
-    badrename (odbn, sdbn);
+static void
+do_install_reflector (void *p)
+{
+  HANDLE *context;
+  context = (HANDLE *) p;
 
-  remove (odbn);
-  if (rename (ndbn, odbn))
-    badrename (ndbn, odbn);
+  do_install_thread ((HINSTANCE) context[0], (HWND) context[1]);
 
-  remove_mount ("/");
-  remove_mount ("/usr");
-  remove_mount ("/usr/bin");
-  remove_mount ("/usr/lib");
-  remove_mount ("/var");
-  remove_mount ("/lib");
-  remove_mount ("/bin");
-  remove_mount ("/etc");
+  // Tell the progress page that we're done downloading
+  Progress.PostMessage (WM_APP_INSTALL_THREAD_COMPLETE);
 
-  int istext = (root_text == IDC_ROOT_TEXT) ? 1 : 0;
-  int issystem = (root_scope == IDC_ROOT_SYSTEM) ? 1 : 0;
+  _endthread ();
+}
 
-  create_mount ("/", root_dir, istext, issystem);
-  create_mount ("/usr/bin", concat (root_dir, "/bin", 0), istext, issystem);
-  create_mount ("/usr/lib", concat (root_dir, "/lib", 0), istext, issystem);
+static HANDLE context[2];
 
-  do_desktop(h);
+void
+do_install (HINSTANCE h, HWND owner)
+{
+  context[0] = h;
+  context[1] = owner;
 
-  note (IDS_INSTALL_COMPLETE);
+  _beginthread (do_install_reflector, 0, context);
 }
This page took 0.038798 seconds and 5 git commands to generate.