448
+ − 1 /*
+ − 2 * Copyright (c) 2000, Red Hat, Inc.
+ − 3 *
+ − 4 * This program is free software; you can redistribute it and/or modify
+ − 5 * it under the terms of the GNU General Public License as published by
+ − 6 * the Free Software Foundation; either version 2 of the License, or
+ − 7 * (at your option) any later version.
+ − 8 *
+ − 9 * A copy of the GNU General Public License can be found at
+ − 10 * http://www.gnu.org/
+ − 11 *
+ − 12 * Written by DJ Delorie <dj@cygnus.com>
+ − 13 *
+ − 14 */
+ − 15
+ − 16 /* The purpose of this file is to intall all the packages selected in
+ − 17 the install list (in ini.h). Note that we use a separate thread to
+ − 18 maintain the progress dialog, so we avoid the complexity of
+ − 19 handling two tasks in one thread. We also create or update all the
+ − 20 files in /etc/setup and create the mount points. */
+ − 21
+ − 22 #include <io.h>
+ − 23 #include <stdio.h>
+ − 24 #include <stdlib.h>
+ − 25 #ifndef WIN32_NATIVE
+ − 26 #include <unistd.h>
+ − 27 #endif
+ − 28 #include <sys/types.h>
+ − 29 #include <sys/stat.h>
+ − 30 #include <errno.h>
+ − 31 #include <zlib.h>
+ − 32
+ − 33 #include "win32.h"
+ − 34 #include "commctrl.h"
+ − 35
+ − 36 #include "resource.h"
+ − 37 #include "ini.h"
+ − 38 #include "dialog.h"
+ − 39 #include "concat.h"
+ − 40 #include "geturl.h"
+ − 41 #include "mkdir.h"
+ − 42 #include "state.h"
+ − 43 #include "tar.h"
+ − 44 #include "diskfull.h"
+ − 45 #include "msg.h"
+ − 46 #include "regedit.h"
+ − 47 #include "reginfo.h"
+ − 48 #include "log.h"
+ − 49 #include "hash.h"
707
+ − 50 #include "desktop.h"
448
+ − 51 #include "port.h"
+ − 52
+ − 53 static HWND ins_dialog = 0;
+ − 54 static HWND ins_action = 0;
+ − 55 static HWND ins_pkgname = 0;
+ − 56 static HWND ins_filename = 0;
+ − 57 static HWND ins_pprogress = 0;
+ − 58 static HWND ins_iprogress = 0;
+ − 59 static HWND ins_diskfull = 0;
+ − 60 static HANDLE init_event;
+ − 61
+ − 62 static int total_bytes = 0;
+ − 63 static int total_bytes_sofar = 0;
+ − 64 static int package_bytes = 0;
+ − 65
+ − 66 static BOOL
+ − 67 dialog_cmd (HWND h, int id, HWND hwndctl, UINT code)
+ − 68 {
+ − 69 switch (id)
+ − 70 {
+ − 71 case IDCANCEL:
+ − 72 exit_setup (1);
+ − 73 }
+ − 74 return FALSE;
+ − 75 }
+ − 76
+ − 77 static BOOL CALLBACK
+ − 78 dialog_proc (HWND h, UINT message, WPARAM wParam, LPARAM lParam)
+ − 79 {
+ − 80 switch (message)
+ − 81 {
+ − 82 case WM_INITDIALOG:
+ − 83 ins_dialog = h;
+ − 84 ins_action = GetDlgItem (h, IDC_INS_ACTION);
+ − 85 ins_pkgname = GetDlgItem (h, IDC_INS_PKG);
+ − 86 ins_filename = GetDlgItem (h, IDC_INS_FILE);
+ − 87 ins_pprogress = GetDlgItem (h, IDC_INS_PPROGRESS);
+ − 88 ins_iprogress = GetDlgItem (h, IDC_INS_IPROGRESS);
+ − 89 ins_diskfull = GetDlgItem (h, IDC_INS_DISKFULL);
+ − 90 SetEvent (init_event);
+ − 91 return FALSE;
+ − 92 case WM_COMMAND:
+ − 93 return HANDLE_WM_COMMAND (h, wParam, lParam, dialog_cmd);
+ − 94 }
+ − 95 return FALSE;
+ − 96 }
+ − 97
+ − 98 static DWORD WINAPI
+ − 99 dialog (void *)
+ − 100 {
+ − 101 MSG m;
+ − 102 HWND new_dialog = CreateDialog (hinstance, MAKEINTRESOURCE (IDD_INSTATUS),
+ − 103 0, dialog_proc);
+ − 104 if (new_dialog == 0)
+ − 105 fatal ("create dialog");
+ − 106 ShowWindow (new_dialog, SW_SHOWNORMAL);
+ − 107 UpdateWindow (new_dialog);
+ − 108 while (GetMessage (&m, 0, 0, 0) > 0) {
+ − 109 TranslateMessage (&m);
+ − 110 DispatchMessage (&m);
+ − 111 }
+ − 112 return FALSE;
+ − 113 }
+ − 114
+ − 115 static void
+ − 116 init_dialog ()
+ − 117 {
+ − 118 if (ins_dialog == 0)
+ − 119 {
+ − 120 DWORD tid;
+ − 121 HANDLE thread;
+ − 122 init_event = CreateEvent (0, 0, 0, 0);
+ − 123 thread = CreateThread (0, 0, dialog, 0, 0, &tid);
+ − 124 WaitForSingleObject (init_event, 10000);
+ − 125 CloseHandle (init_event);
+ − 126 SendMessage (ins_pprogress, PBM_SETRANGE, 0, MAKELPARAM (0, 100));
+ − 127 SendMessage (ins_iprogress, PBM_SETRANGE, 0, MAKELPARAM (0, 100));
+ − 128 SendMessage (ins_diskfull, PBM_SETRANGE, 0, MAKELPARAM (0, 100));
+ − 129 }
+ − 130
+ − 131 SetWindowText (ins_pkgname, "");
+ − 132 SetWindowText (ins_filename, "");
+ − 133 SendMessage (ins_pprogress, PBM_SETPOS, (WPARAM) 0, 0);
+ − 134 SendMessage (ins_iprogress, PBM_SETPOS, (WPARAM) 0, 0);
+ − 135 SendMessage (ins_diskfull, PBM_SETPOS, (WPARAM) 0, 0);
+ − 136 ShowWindow (ins_dialog, SW_SHOWNORMAL);
+ − 137 SetForegroundWindow (ins_dialog);
+ − 138 }
+ − 139
+ − 140 static void
+ − 141 progress (int bytes)
+ − 142 {
+ − 143 int perc;
+ − 144
+ − 145 if (package_bytes > 100)
+ − 146 {
+ − 147 perc = bytes / (package_bytes / 100);
+ − 148 SendMessage (ins_pprogress, PBM_SETPOS, (WPARAM) perc, 0);
+ − 149 }
+ − 150
+ − 151 if (total_bytes > 100)
+ − 152 {
+ − 153 perc = (total_bytes_sofar + bytes) / (total_bytes / 100);
+ − 154 SendMessage (ins_iprogress, PBM_SETPOS, (WPARAM) perc, 0);
+ − 155 }
+ − 156 }
+ − 157
+ − 158 static void
+ − 159 badrename (char *o, char *n)
+ − 160 {
+ − 161 char *err = strerror (errno);
+ − 162 if (!err)
+ − 163 err = "(unknown error)";
+ − 164 note (IDS_ERR_RENAME, o, n, err);
+ − 165 }
+ − 166
+ − 167 static char *standard_dirs[] = {
+ − 168 0
+ − 169 };
+ − 170
+ − 171 void
+ − 172 hash::add_subdirs (char *path)
+ − 173 {
+ − 174 char *nonp, *pp;
+ − 175 for (nonp = path; *nonp == '\\' || *nonp == '/'; nonp++);
+ − 176 for (pp = path + strlen(path) - 1; pp>nonp; pp--)
+ − 177 if (*pp == '/' || *pp == '\\')
+ − 178 {
+ − 179 int i, s=0;
+ − 180 char c = *pp;
+ − 181 *pp = 0;
+ − 182 for (i=0; standard_dirs[i]; i++)
+ − 183 if (strcmp (standard_dirs[i]+1, path) == 0)
+ − 184 {
+ − 185 s = 1;
+ − 186 break;
+ − 187 }
+ − 188 if (s == 0)
+ − 189 add (path);
+ − 190 *pp = c;
+ − 191 }
+ − 192 }
+ − 193
+ − 194 char *
+ − 195 map_filename (char *fn, int type)
+ − 196 {
+ − 197 char *dest_file;
+ − 198 while (*fn == '/' || *fn == '\\')
+ − 199 fn++;
+ − 200 if (type == TY_GENERIC)
+ − 201 dest_file = concat (root_dir, XEMACS_PACKAGE_DIR, fn, 0);
+ − 202 else // TY_CYGWIN | TY_NATIVE
+ − 203 dest_file = concat (root_dir, "/", fn, 0);
+ − 204 return dest_file;
+ − 205 }
+ − 206
+ − 207 static int
+ − 208 exists (char *file)
+ − 209 {
+ − 210 if (_access (file, 0) == 0)
+ − 211 return 1;
+ − 212 return 0;
+ − 213 }
+ − 214
+ − 215
+ − 216 static int num_installs, num_uninstalls;
+ − 217
+ − 218 static void
+ − 219 uninstall_one (char *name, int action, int type)
+ − 220 {
+ − 221 hash dirs;
+ − 222 char line[_MAX_PATH];
+ − 223 char* fname = (type == TY_GENERIC ?
+ − 224 concat (root_dir, XEMACS_PACKAGE_DIR, "pkginfo/MANIFEST.",
+ − 225 name, 0) :
+ − 226 concat (root_dir, XEMACS_SETUP_DIR, "MANIFEST.", name, 0));
+ − 227
+ − 228 FILE* lst = fopen (fname, "rb");
+ − 229
+ − 230 if (lst)
+ − 231 {
+ − 232 SetWindowText (ins_pkgname, name);
+ − 233 SetWindowText (ins_action, "Uninstalling...");
707
+ − 234 // remove shortcuts and registry entries
+ − 235 if (type != TY_GENERIC)
+ − 236 remove_xemacs_setup();
+ − 237
448
+ − 238 if (action == ACTION_UPGRADE)
+ − 239 log (0, "Uninstalling old %s", name);
+ − 240 else
+ − 241 log (0, "Uninstalling %s", name);
+ − 242
+ − 243 while (fgets (line, sizeof (line), lst))
+ − 244 {
+ − 245 if (line[strlen(line)-1] == '\n')
+ − 246 line[strlen(line)-1] = 0;
+ − 247
+ − 248 dirs.add_subdirs (line);
+ − 249
+ − 250 char *d = map_filename (line, type);
+ − 251 DWORD dw = GetFileAttributes (d);
+ − 252 if (dw != 0xffffffff && !(dw & FILE_ATTRIBUTE_DIRECTORY))
+ − 253 {
+ − 254 log (LOG_BABBLE, "unlink %s", d);
+ − 255 DeleteFile (d);
+ − 256 }
+ − 257 }
+ − 258 fclose (lst);
+ − 259
+ − 260 remove (fname);
+ − 261
+ − 262 dirs.reverse_sort ();
+ − 263 char *subdir = 0;
+ − 264 while ((subdir = dirs.enumerate (subdir)) != 0)
+ − 265 {
+ − 266 char *d = map_filename (subdir, type);
+ − 267 if (RemoveDirectory (d))
+ − 268 log (LOG_BABBLE, "rmdir %s", d);
+ − 269 }
+ − 270 num_uninstalls ++;
+ − 271 }
+ − 272 }
+ − 273
+ − 274
+ − 275 static int
+ − 276 install_one (char *name, char *file, int file_size, int action, int type)
+ − 277 {
+ − 278 int errors = 0;
+ − 279 char *local = file, *cp, *fn, *base;
+ − 280
+ − 281 base = local;
+ − 282 for (cp=local; *cp; cp++)
+ − 283 if (*cp == '/' || *cp == '\\' || *cp == ':')
+ − 284 base = cp+1;
819
+ − 285
448
+ − 286 SetWindowText (ins_pkgname, base);
+ − 287
+ − 288 if (!exists (local) && exists (base))
+ − 289 local = base;
+ − 290 if (!exists (local))
+ − 291 {
+ − 292 note (IDS_ERR_OPEN_READ, local, "No such file");
+ − 293 return 1;
+ − 294 }
+ − 295
+ − 296 char* fname = (type == TY_GENERIC ?
+ − 297 concat (root_dir, XEMACS_PACKAGE_DIR, "pkginfo/MANIFEST.",
+ − 298 name, 0) :
+ − 299 concat (root_dir, XEMACS_SETUP_DIR, "MANIFEST.", name, 0));
+ − 300
+ − 301 FILE* lst = fopen (fname, "wb");
+ − 302
+ − 303 package_bytes = file_size;
+ − 304
+ − 305 switch (action)
+ − 306 {
+ − 307 case ACTION_NEW:
+ − 308 SetWindowText (ins_action, "Installing...");
+ − 309 break;
+ − 310 case ACTION_UPGRADE:
+ − 311 SetWindowText (ins_action, "Upgrading...");
+ − 312 break;
+ − 313 }
+ − 314
+ − 315 log (0, "Installing %s", local);
+ − 316 tar_open (local);
+ − 317 while ((fn = tar_next_file ()))
+ − 318 {
819
+ − 319 char *dest_file, *disp_file;
+ − 320 int len;
448
+ − 321
+ − 322 if (lst)
+ − 323 fprintf (lst, "%s\n", fn);
+ − 324
+ − 325 dest_file = map_filename (fn, type);
819
+ − 326
+ − 327 // The installer uses a variable width font. Assume roughly 32 chars
+ − 328 // will fit and munge the file accordingly.
+ − 329 #define MAX_DISP_SIZE 50
+ − 330 disp_file = strdup(dest_file);
+ − 331 if ((len = strlen(dest_file)) > MAX_DISP_SIZE) {
+ − 332 disp_file += (len - MAX_DISP_SIZE);
+ − 333 disp_file[0] = '.';
+ − 334 disp_file[1] = '.';
+ − 335 disp_file[2] = '.';
+ − 336 }
+ − 337 #undef MAX_DISP_SIZE
+ − 338 SetWindowText (ins_filename, disp_file);
448
+ − 339
+ − 340 log (LOG_BABBLE, "Installing file %s", dest_file);
+ − 341 if (tar_read_file (dest_file) != 0)
+ − 342 {
+ − 343 log (0, "Unable to install file %s", dest_file);
+ − 344 errors ++;
+ − 345 }
+ − 346
+ − 347 progress (tar_ftell ());
+ − 348 num_installs ++;
+ − 349 }
+ − 350 tar_close ();
+ − 351
+ − 352 total_bytes_sofar += file_size;
+ − 353 progress (0);
+ − 354
+ − 355 int df = diskfull (root_dir);
+ − 356 SendMessage (ins_diskfull, PBM_SETPOS, (WPARAM) df, 0);
+ − 357
+ − 358 if (lst)
+ − 359 fclose (lst);
+ − 360
+ − 361 return errors;
+ − 362 }
+ − 363
+ − 364 void
+ − 365 do_install (HINSTANCE h)
+ − 366 {
+ − 367 int i;
+ − 368 int errors = 0;
+ − 369
+ − 370 num_installs = 0, num_uninstalls = 0;
+ − 371
+ − 372 next_dialog = IDD_DESKTOP;
+ − 373
+ − 374 mkdir_p (1, root_dir);
+ − 375
+ − 376 for (i=0; standard_dirs[i]; i++)
+ − 377 {
+ − 378 char *p = concat (root_dir, standard_dirs[i], 0);
+ − 379 mkdir_p (1, p);
+ − 380 free (p);
+ − 381 }
+ − 382
+ − 383 dismiss_url_status_dialog ();
+ − 384
+ − 385 init_dialog ();
+ − 386
+ − 387 total_bytes = 0;
+ − 388 total_bytes_sofar = 0;
+ − 389
+ − 390 int df = diskfull (root_dir);
+ − 391 SendMessage (ins_diskfull, PBM_SETPOS, (WPARAM) df, 0);
+ − 392
+ − 393 LOOP_PACKAGES
+ − 394 {
+ − 395 total_bytes += pi.install_size;
+ − 396 }
+ − 397
+ − 398 for (i=0; i<npackages; i++)
+ − 399 {
+ − 400 if (package[i].action == ACTION_UNINSTALL
+ − 401 || (package[i].action == ACTION_UPGRADE && pi.install))
+ − 402 {
+ − 403 uninstall_one (package[i].name, package[i].action,
+ − 404 package[i].type);
+ − 405 uninstall_one (concat (package[i].name, "-src", 0), package[i].action,
+ − 406 package[i].type);
+ − 407 }
+ − 408
+ − 409 if ((package[i].action == ACTION_NEW
+ − 410 || package[i].action == ACTION_UPGRADE)
+ − 411 && pi.install)
+ − 412 {
+ − 413 int e = install_one (package[i].name, pi.install, pi.install_size, package[i].action,
+ − 414 package[i].type);
+ − 415 if (package[i].srcaction == SRCACTION_YES && pi.source)
+ − 416 e += install_one (concat (package[i].name, "-src", 0), pi.source, pi.source_size,
+ − 417 package[i].action, package[i].type);
+ − 418 if (e)
+ − 419 {
+ − 420 package[i].action = ACTION_ERROR;
+ − 421 errors++;
+ − 422 }
+ − 423 }
+ − 424 } // end of big package loop
+ − 425
+ − 426 ShowWindow (ins_dialog, SW_HIDE);
+ − 427
+ − 428 char *odbn = concat (root_dir, XEMACS_SETUP_DIR, "installed.db", 0);
+ − 429 char *ndbn = concat (root_dir, XEMACS_SETUP_DIR, "installed.db.new", 0);
+ − 430 char *sdbn = concat (root_dir, XEMACS_SETUP_DIR, "installed.db.old", 0);
+ − 431
+ − 432 mkdir_p (0, ndbn);
+ − 433
+ − 434 FILE *odb = fopen (odbn, "rt");
+ − 435 FILE *ndb = fopen (ndbn, "wb");
+ − 436
+ − 437 if (!ndb)
+ − 438 {
+ − 439 char *err = strerror (errno);
+ − 440 if (!err)
+ − 441 err = "(unknown error)";
+ − 442 fatal (IDS_ERR_OPEN_WRITE, ndb, err);
+ − 443 }
+ − 444
+ − 445 if (odb)
+ − 446 {
+ − 447 char line[1000], pkg[1000];
+ − 448 int printit;
+ − 449 while (fgets (line, 1000, odb))
+ − 450 {
+ − 451 printit = 1;
+ − 452 sscanf (line, "%s", pkg);
+ − 453 for (i=0; i<npackages; i++)
+ − 454 {
+ − 455 if (strcmp (pkg, package[i].name) == 0)
+ − 456 switch (package[i].action)
+ − 457 {
+ − 458 case ACTION_NEW:
+ − 459 case ACTION_UPGRADE:
+ − 460 case ACTION_UNINSTALL:
+ − 461 printit = 0;
+ − 462 break;
+ − 463 }
+ − 464 }
+ − 465 if (printit)
+ − 466 fputs (line, ndb);
+ − 467 }
+ − 468
+ − 469 }
+ − 470
+ − 471 LOOP_PACKAGES
+ − 472 {
+ − 473 if (package[i].srcaction == SRCACTION_YES)
+ − 474 fprintf (ndb, "%s %s %d %s %d\n", package[i].name,
+ − 475 pi.install, pi.install_size,
+ − 476 pi.source, pi.source_size);
+ − 477 else
+ − 478 fprintf (ndb, "%s %s %d\n", package[i].name,
+ − 479 pi.install, pi.install_size);
+ − 480 }
+ − 481
+ − 482 if (odb)
+ − 483 fclose (odb);
+ − 484 fclose (ndb);
+ − 485
+ − 486 remove (sdbn);
+ − 487 if (odb && rename (odbn, sdbn))
+ − 488 badrename (odbn, sdbn);
+ − 489
+ − 490 remove (odbn);
+ − 491 if (rename (ndbn, odbn))
+ − 492 badrename (ndbn, odbn);
+ − 493
+ − 494 if (num_installs == 0 && num_uninstalls == 0)
+ − 495 {
+ − 496 exit_msg = IDS_NOTHING_INSTALLED;
+ − 497 return;
+ − 498 }
+ − 499 if (num_installs == 0)
+ − 500 {
+ − 501 exit_msg = IDS_UNINSTALL_COMPLETE;
+ − 502 return;
+ − 503 }
+ − 504
+ − 505 if (errors)
+ − 506 exit_msg = IDS_INSTALL_INCOMPLETE;
+ − 507 else
+ − 508 exit_msg = IDS_INSTALL_COMPLETE;
+ − 509 }