]> 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
    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 "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 <sys/types.h>
 #include <sys/stat.h>
 #include <errno.h>
+#include <process.h>
+
 #include "zlib/zlib.h"
 
 #include "resource.h"
 #include "zlib/zlib.h"
 
 #include "resource.h"
 #include "geturl.h"
 #include "mkdir.h"
 #include "state.h"
 #include "geturl.h"
 #include "mkdir.h"
 #include "state.h"
-#include "tar.h"
 #include "diskfull.h"
 #include "msg.h"
 #include "mount.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 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 ()
 {
 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)
 {
 }
 
 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",
   "/bin",
   "/etc",
   "/lib",
   "/tmp",
+  "/usr",
   "/usr/bin",
   "/usr/lib",
   "/usr/bin",
   "/usr/lib",
+  "/usr/src",
+  "/usr/local",
   "/usr/local/bin",
   "/usr/local/etc",
   "/usr/local/lib",
   "/usr/local/bin",
   "/usr/local/etc",
   "/usr/local/lib",
@@ -176,177 +110,316 @@ static char *standard_dirs[] = {
   0
 };
 
   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.039357 seconds and 5 git commands to generate.