Initial revision
[chise/xemacs-chise.git.1] / netinstall / install.cc
diff --git a/netinstall/install.cc b/netinstall/install.cc
new file mode 100644 (file)
index 0000000..5d64055
--- /dev/null
@@ -0,0 +1,491 @@
+/*
+ * Copyright (c) 2000, 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
+ *     the Free Software Foundation; either version 2 of the License, or
+ *     (at your option) any later version.
+ *
+ *     A copy of the GNU General Public License can be found at
+ *     http://www.gnu.org/
+ *
+ * Written by DJ Delorie <dj@cygnus.com>
+ *
+ */
+
+/* The purpose of this file is to intall all the packages selected in
+   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. */
+
+#include <io.h>
+#include <stdio.h>
+#include <stdlib.h>
+#ifndef WIN32_NATIVE
+#include <unistd.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <zlib.h>
+
+#include "win32.h"
+#include "commctrl.h"
+
+#include "resource.h"
+#include "ini.h"
+#include "dialog.h"
+#include "concat.h"
+#include "geturl.h"
+#include "mkdir.h"
+#include "state.h"
+#include "tar.h"
+#include "diskfull.h"
+#include "msg.h"
+#include "regedit.h"
+#include "reginfo.h"
+#include "log.h"
+#include "hash.h"
+
+#include "port.h"
+
+static HWND ins_dialog = 0;
+static HWND ins_action = 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;
+
+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:
+      exit_setup (1);
+    }
+  return FALSE;
+}
+
+static BOOL CALLBACK
+dialog_proc (HWND h, UINT message, WPARAM wParam, LPARAM lParam)
+{
+  switch (message)
+    {
+    case WM_INITDIALOG:
+      ins_dialog = h;
+      ins_action = GetDlgItem (h, IDC_INS_ACTION);
+      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 DWORD WINAPI
+dialog (void *)
+{
+  MSG m;
+  HWND new_dialog = CreateDialog (hinstance, MAKEINTRESOURCE (IDD_INSTATUS),
+                                  0, dialog_proc);
+  if (new_dialog == 0)
+    fatal ("create dialog");
+  ShowWindow (new_dialog, SW_SHOWNORMAL);
+  UpdateWindow (new_dialog);
+  while (GetMessage (&m, 0, 0, 0) > 0) {
+    TranslateMessage (&m);
+    DispatchMessage (&m);
+  }
+  return FALSE;
+}
+
+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);
+}
+
+static void
+progress (int bytes)
+{
+  int perc;
+
+  if (package_bytes > 100)
+    {
+      perc = bytes / (package_bytes / 100);
+      SendMessage (ins_pprogress, PBM_SETPOS, (WPARAM) perc, 0);
+    }
+
+  if (total_bytes > 100)
+    {
+      perc = (total_bytes_sofar + bytes) / (total_bytes / 100);
+      SendMessage (ins_iprogress, PBM_SETPOS, (WPARAM) perc, 0);
+    }
+}
+
+static void
+badrename (char *o, char *n)
+{
+  char *err = strerror (errno);
+  if (!err)
+    err = "(unknown error)";
+  note (IDS_ERR_RENAME, o, n, err);
+}
+
+static char *standard_dirs[] = {
+  0
+};
+
+void
+hash::add_subdirs (char *path)
+{
+  char *nonp, *pp;
+  for (nonp = path; *nonp == '\\' || *nonp == '/'; nonp++);
+  for (pp = path + strlen(path) - 1; pp>nonp; pp--)
+    if (*pp == '/' || *pp == '\\')
+      {
+       int i, s=0;
+       char c = *pp;
+       *pp = 0;
+       for (i=0; standard_dirs[i]; i++)
+         if (strcmp (standard_dirs[i]+1, path) == 0)
+           {
+             s = 1;
+             break;
+           }
+       if (s == 0)
+         add (path);
+       *pp = c;
+      }
+}
+
+char *
+map_filename (char *fn, int type)
+{
+  char *dest_file;
+  while (*fn == '/' || *fn == '\\')
+    fn++;
+  if (type == TY_GENERIC)
+    dest_file = concat (root_dir, XEMACS_PACKAGE_DIR, fn, 0);
+  else                         // TY_CYGWIN | TY_NATIVE
+    dest_file = concat (root_dir, "/", fn, 0);
+  return dest_file;
+}
+
+static int
+exists (char *file)
+{
+  if (_access (file, 0) == 0)
+    return 1;
+  return 0;
+}
+
+         
+static int num_installs, num_uninstalls;
+
+static void
+uninstall_one (char *name, int action, int type)
+{
+  hash dirs;
+  char line[_MAX_PATH];
+  char* fname = (type == TY_GENERIC ? 
+                concat (root_dir, XEMACS_PACKAGE_DIR, "pkginfo/MANIFEST.",
+                        name,  0) :
+                concat (root_dir, XEMACS_SETUP_DIR, "MANIFEST.", name,  0));
+
+  FILE* lst = fopen (fname, "rb");
+
+  if (lst)
+    {
+      SetWindowText (ins_pkgname, name);
+      SetWindowText (ins_action, "Uninstalling...");
+      if (action == ACTION_UPGRADE)
+       log (0, "Uninstalling old %s", name);
+      else
+       log (0, "Uninstalling %s", name);
+
+      while (fgets (line, sizeof (line), lst))
+       {
+         if (line[strlen(line)-1] == '\n')
+           line[strlen(line)-1] = 0;
+
+         dirs.add_subdirs (line);
+
+         char *d = map_filename (line, type);
+         DWORD dw = GetFileAttributes (d);
+         if (dw != 0xffffffff && !(dw & FILE_ATTRIBUTE_DIRECTORY))
+           {
+             log (LOG_BABBLE, "unlink %s", d);
+             DeleteFile (d);
+           }
+       }
+      fclose (lst);
+
+      remove (fname);
+
+      dirs.reverse_sort ();
+      char *subdir = 0;
+      while ((subdir = dirs.enumerate (subdir)) != 0)
+       {
+         char *d = map_filename (subdir, type);
+         if (RemoveDirectory (d))
+           log (LOG_BABBLE, "rmdir %s", d);
+       }
+      num_uninstalls ++;
+    }
+}
+
+         
+static int
+install_one (char *name, char *file, int file_size, int action, int type)
+{
+  int errors = 0;
+  char *local = file, *cp, *fn, *base;
+
+  base = local;
+  for (cp=local; *cp; cp++)
+    if (*cp == '/' || *cp == '\\' || *cp == ':')
+      base = cp+1;
+  SetWindowText (ins_pkgname, base);
+
+  if (!exists (local) && exists (base))
+    local = base;
+  if (!exists (local))
+    {
+      note (IDS_ERR_OPEN_READ, local, "No such file");
+      return 1;
+    }
+
+  char* fname = (type == TY_GENERIC ? 
+                concat (root_dir, XEMACS_PACKAGE_DIR, "pkginfo/MANIFEST.",
+                        name,  0) :
+                concat (root_dir, XEMACS_SETUP_DIR, "MANIFEST.", name,  0));
+
+  FILE* lst = fopen (fname, "wb");
+
+  package_bytes = file_size;
+
+  switch (action)
+    {
+    case ACTION_NEW:
+      SetWindowText (ins_action, "Installing...");
+      break;
+    case ACTION_UPGRADE:
+      SetWindowText (ins_action, "Upgrading...");
+      break;
+    }
+
+  log (0, "Installing %s", local);
+  tar_open (local);
+  while ((fn = tar_next_file ()))
+    {
+      char *dest_file;
+
+      if (lst)
+       fprintf (lst, "%s\n", fn);
+
+      dest_file = map_filename (fn, type);
+
+      SetWindowText (ins_filename, dest_file);
+      log (LOG_BABBLE, "Installing file %s", dest_file);
+      if (tar_read_file (dest_file) != 0)
+       {
+         log (0, "Unable to install file %s", dest_file);
+         errors ++;
+       }
+
+      progress (tar_ftell ());
+      num_installs ++;
+    }
+  tar_close ();
+
+  total_bytes_sofar += file_size;
+  progress (0);
+
+  int df = diskfull (root_dir);
+  SendMessage (ins_diskfull, PBM_SETPOS, (WPARAM) df, 0);
+
+  if (lst)
+    fclose (lst);
+
+  return errors;
+}
+
+void
+do_install (HINSTANCE h)
+{
+  int i;
+  int errors = 0;
+
+  num_installs = 0, num_uninstalls = 0;
+
+  next_dialog = IDD_DESKTOP;
+
+  mkdir_p (1, root_dir);
+
+  for (i=0; standard_dirs[i]; i++)
+    {
+      char *p = concat (root_dir, standard_dirs[i], 0);
+      mkdir_p (1, p);
+      free (p);
+    }
+
+  dismiss_url_status_dialog ();
+
+  init_dialog ();
+
+  total_bytes = 0;
+  total_bytes_sofar = 0;
+
+  int df = diskfull (root_dir);
+  SendMessage (ins_diskfull, PBM_SETPOS, (WPARAM) df, 0);
+
+  LOOP_PACKAGES
+    {
+      total_bytes += pi.install_size;
+    }
+
+  for (i=0; i<npackages; i++)
+    {
+      if (package[i].action == ACTION_UNINSTALL
+         || (package[i].action == ACTION_UPGRADE && pi.install))
+       {
+         uninstall_one (package[i].name, package[i].action,
+                        package[i].type);
+         uninstall_one (concat (package[i].name, "-src", 0), package[i].action,
+                        package[i].type);
+       }
+
+      if ((package[i].action == ACTION_NEW
+          || package[i].action == ACTION_UPGRADE)
+         && pi.install)
+       {
+         int e = install_one (package[i].name, pi.install, pi.install_size, package[i].action,
+                              package[i].type);
+         if (package[i].srcaction == SRCACTION_YES && pi.source)
+           e += install_one (concat (package[i].name, "-src", 0), pi.source, pi.source_size,
+                             package[i].action, package[i].type);
+         if (e)
+           {
+             package[i].action = ACTION_ERROR;
+             errors++;
+           }
+       }
+    } // end of big package loop
+
+  ShowWindow (ins_dialog, SW_HIDE);
+
+  char *odbn = concat (root_dir, XEMACS_SETUP_DIR, "installed.db", 0);
+  char *ndbn = concat (root_dir, XEMACS_SETUP_DIR, "installed.db.new", 0);
+  char *sdbn = concat (root_dir, XEMACS_SETUP_DIR, "installed.db.old", 0);
+
+  mkdir_p (0, ndbn);
+
+  FILE *odb = fopen (odbn, "rt");
+  FILE *ndb = fopen (ndbn, "wb");
+
+  if (!ndb)
+    {
+      char *err = strerror (errno);
+      if (!err)
+       err = "(unknown error)";
+      fatal (IDS_ERR_OPEN_WRITE, ndb, err);
+    }
+
+  if (odb)
+    {
+      char line[1000], pkg[1000];
+      int printit;
+      while (fgets (line, 1000, odb))
+       {
+         printit = 1;
+         sscanf (line, "%s", pkg);
+         for (i=0; i<npackages; i++)
+           {
+             if (strcmp (pkg, package[i].name) == 0)
+               switch (package[i].action)
+                 {
+                 case ACTION_NEW:
+                 case ACTION_UPGRADE:
+                 case ACTION_UNINSTALL:
+                   printit = 0;
+                   break;
+                 }
+           }
+         if (printit)
+           fputs (line, ndb);
+       }
+      
+    }
+
+  LOOP_PACKAGES
+    {
+      if (package[i].srcaction == SRCACTION_YES)
+       fprintf (ndb, "%s %s %d %s %d\n", package[i].name,
+                pi.install, pi.install_size,
+                pi.source, pi.source_size);
+      else
+       fprintf (ndb, "%s %s %d\n", package[i].name,
+                pi.install, pi.install_size);
+    }
+
+  if (odb)
+    fclose (odb);
+  fclose (ndb);
+
+  remove (sdbn);
+  if (odb && rename (odbn, sdbn))
+    badrename (odbn, sdbn);
+
+  remove (odbn);
+  if (rename (ndbn, odbn))
+    badrename (ndbn, odbn);
+
+  if (num_installs == 0 && num_uninstalls == 0)
+    {
+      exit_msg = IDS_NOTHING_INSTALLED;
+      return;
+    }
+  if (num_installs == 0)
+    {
+      exit_msg = IDS_UNINSTALL_COMPLETE;
+      return;
+    }
+
+  if (errors)
+    exit_msg = IDS_INSTALL_INCOMPLETE;
+  else
+    exit_msg = IDS_INSTALL_COMPLETE;
+}