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",
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 = IDD_S_DESKTOP;
+ 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++)
{
- exit_msg = 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 ();
+
+ total_bytes = 0;
+ total_bytes_sofar = 0;
- FILE *odb = fopen (odbn, "rt");
- FILE *ndb = fopen (ndbn, "wb");
+ 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;
- if (!ndb)
+ 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 (errors)
+ exit_msg = IDS_INSTALL_INCOMPLETE;
+ else
+ exit_msg = IDS_INSTALL_COMPLETE;
+}
- if (odb)
- fclose (odb);
- fclose (ndb);
+static void
+do_install_reflector (void *p)
+{
+ HANDLE *context;
+ context = (HANDLE *) p;
- remove (sdbn);
- if (odb && rename (odbn, sdbn))
- badrename (odbn, sdbn);
+ do_install_thread ((HINSTANCE) context[0], (HWND) context[1]);
- remove (odbn);
- if (rename (ndbn, odbn))
- badrename (ndbn, odbn);
+ // Tell the progress page that we're done downloading
+ Progress.PostMessage (WM_APP_INSTALL_THREAD_COMPLETE);
- 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");
+ _endthread ();
+}
- int istext = (root_text == IDC_ROOT_TEXT) ? 1 : 0;
- int issystem = (root_scope == IDC_ROOT_SYSTEM) ? 1 : 0;
+static HANDLE context[2];
- 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);
+void
+do_install (HINSTANCE h, HWND owner)
+{
+ context[0] = h;
+ context[1] = owner;
- exit_msg = IDS_INSTALL_COMPLETE;
+ _beginthread (do_install_reflector, 0, context);
}