]> cygwin.com Git - cygwin-apps/setup.git/blame - install.cc
2001-11-13 Robert Collins <rbtcollins@hotmail.com>
[cygwin-apps/setup.git] / install.cc
CommitLineData
23c9e63c
DD
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
b24c88b3 20 files in /etc/setup/\* and create the mount points. */
23c9e63c 21
b24c88b3
RC
22#if 0
23static const char *cvsid =
24 "\n%%% $Id$\n";
25#endif
8507f105 26
23c9e63c
DD
27#include "win32.h"
28#include "commctrl.h"
29
30#include <stdio.h>
904d24fe 31#include <stdlib.h>
4a83b7b0 32#include <unistd.h>
23c9e63c
DD
33#include <sys/types.h>
34#include <sys/stat.h>
35#include <errno.h>
87c42361 36#include "zlib/zlib.h"
23c9e63c
DD
37
38#include "resource.h"
39#include "ini.h"
40#include "dialog.h"
41#include "concat.h"
42#include "geturl.h"
43#include "mkdir.h"
44#include "state.h"
23c9e63c
DD
45#include "diskfull.h"
46#include "msg.h"
47#include "mount.h"
89b1a15b 48#include "log.h"
4a83b7b0 49#include "hash.h"
a351e48c 50#include "mount.h"
c46a33a9 51#include "filemanip.h"
b24c88b3
RC
52#include "io_stream.h"
53#include "compress.h"
54#include "compress_gz.h"
55#include "archive.h"
56#include "archive_tar.h"
4a83b7b0
DD
57
58#include "port.h"
23c9e63c
DD
59
60static HWND ins_dialog = 0;
4a83b7b0 61static HWND ins_action = 0;
23c9e63c
DD
62static HWND ins_pkgname = 0;
63static HWND ins_filename = 0;
64static HWND ins_pprogress = 0;
65static HWND ins_iprogress = 0;
66static HWND ins_diskfull = 0;
67static HANDLE init_event;
68
69static int total_bytes = 0;
70static int total_bytes_sofar = 0;
71static int package_bytes = 0;
72
c46a33a9 73static bool
23c9e63c
DD
74dialog_cmd (HWND h, int id, HWND hwndctl, UINT code)
75{
76 switch (id)
77 {
78 case IDCANCEL:
89b1a15b 79 exit_setup (1);
23c9e63c 80 }
b24c88b3 81 return 0;
23c9e63c
DD
82}
83
84static BOOL CALLBACK
85dialog_proc (HWND h, UINT message, WPARAM wParam, LPARAM lParam)
86{
23c9e63c
DD
87 switch (message)
88 {
89 case WM_INITDIALOG:
90 ins_dialog = h;
4a83b7b0 91 ins_action = GetDlgItem (h, IDC_INS_ACTION);
23c9e63c
DD
92 ins_pkgname = GetDlgItem (h, IDC_INS_PKG);
93 ins_filename = GetDlgItem (h, IDC_INS_FILE);
94 ins_pprogress = GetDlgItem (h, IDC_INS_PPROGRESS);
95 ins_iprogress = GetDlgItem (h, IDC_INS_IPROGRESS);
96 ins_diskfull = GetDlgItem (h, IDC_INS_DISKFULL);
97 SetEvent (init_event);
7cefe128 98 return TRUE;
23c9e63c 99 case WM_COMMAND:
1fd6d0a2 100 return HANDLE_WM_COMMAND (h, wParam, lParam, dialog_cmd);
23c9e63c
DD
101 }
102 return FALSE;
103}
104
105static WINAPI DWORD
106dialog (void *)
107{
108 int rv = 0;
109 MSG m;
ed96c6da 110 HWND ins_dialog = CreateDialog (hinstance, MAKEINTRESOURCE (IDD_INSTATUS),
b24c88b3 111 0, dialog_proc);
23c9e63c
DD
112 if (ins_dialog == 0)
113 fatal ("create dialog");
114 ShowWindow (ins_dialog, SW_SHOWNORMAL);
115 UpdateWindow (ins_dialog);
b24c88b3
RC
116 while (GetMessage (&m, 0, 0, 0) > 0)
117 {
118 TranslateMessage (&m);
119 DispatchMessage (&m);
120 }
121 return rv;
23c9e63c
DD
122}
123
23c9e63c
DD
124static void
125init_dialog ()
126{
127 if (ins_dialog == 0)
128 {
129 DWORD tid;
130 HANDLE thread;
131 init_event = CreateEvent (0, 0, 0, 0);
132 thread = CreateThread (0, 0, dialog, 0, 0, &tid);
133 WaitForSingleObject (init_event, 10000);
134 CloseHandle (init_event);
135 SendMessage (ins_pprogress, PBM_SETRANGE, 0, MAKELPARAM (0, 100));
136 SendMessage (ins_iprogress, PBM_SETRANGE, 0, MAKELPARAM (0, 100));
137 SendMessage (ins_diskfull, PBM_SETRANGE, 0, MAKELPARAM (0, 100));
138 }
139
140 SetWindowText (ins_pkgname, "");
141 SetWindowText (ins_filename, "");
142 SendMessage (ins_pprogress, PBM_SETPOS, (WPARAM) 0, 0);
143 SendMessage (ins_iprogress, PBM_SETPOS, (WPARAM) 0, 0);
144 SendMessage (ins_diskfull, PBM_SETPOS, (WPARAM) 0, 0);
145 ShowWindow (ins_dialog, SW_SHOWNORMAL);
23c9e63c
DD
146}
147
148static void
149progress (int bytes)
150{
151 int perc;
152
bf1d5889 153 if (package_bytes > 100)
23c9e63c 154 {
bf1d5889 155 perc = bytes / (package_bytes / 100);
23c9e63c
DD
156 SendMessage (ins_pprogress, PBM_SETPOS, (WPARAM) perc, 0);
157 }
158
bf1d5889 159 if (total_bytes > 100)
23c9e63c 160 {
bf1d5889 161 perc = (total_bytes_sofar + bytes) / (total_bytes / 100);
23c9e63c
DD
162 SendMessage (ins_iprogress, PBM_SETPOS, (WPARAM) perc, 0);
163 }
23c9e63c
DD
164}
165
166static void
167badrename (char *o, char *n)
168{
b24c88b3 169 const char *err = strerror (errno);
23c9e63c
DD
170 if (!err)
171 err = "(unknown error)";
172 note (IDS_ERR_RENAME, o, n, err);
173}
174
b24c88b3 175static const char *standard_dirs[] = {
1a18aed7 176 "/bin",
904d24fe 177 "/etc",
1a18aed7 178 "/lib",
904d24fe 179 "/tmp",
4a83b7b0 180 "/usr",
1a18aed7
DD
181 "/usr/bin",
182 "/usr/lib",
ef45c299 183 "/usr/src",
4a83b7b0 184 "/usr/local",
1a18aed7
DD
185 "/usr/local/bin",
186 "/usr/local/etc",
187 "/usr/local/lib",
904d24fe 188 "/usr/tmp",
1a18aed7 189 "/var/run",
904d24fe
DD
190 "/var/tmp",
191 0
192};
193
4a83b7b0
DD
194void
195hash::add_subdirs (char *path)
196{
197 char *nonp, *pp;
198 for (nonp = path; *nonp == '\\' || *nonp == '/'; nonp++);
b24c88b3 199 for (pp = path + strlen (path) - 1; pp > nonp; pp--)
4a83b7b0
DD
200 if (*pp == '/' || *pp == '\\')
201 {
b24c88b3 202 int i, s = 0;
4a83b7b0
DD
203 char c = *pp;
204 *pp = 0;
b24c88b3
RC
205 for (i = 0; standard_dirs[i]; i++)
206 if (strcmp (standard_dirs[i] + 1, path) == 0)
4a83b7b0
DD
207 {
208 s = 1;
209 break;
210 }
211 if (s == 0)
212 add (path);
213 *pp = c;
214 }
215}
216
3b9077d4
DD
217static int num_installs, num_uninstalls;
218
219static void
b24c88b3 220uninstall_one (Package * pkg, bool src)
3b9077d4
DD
221{
222 hash dirs;
223 char line[_MAX_PATH];
224
b24c88b3
RC
225 io_stream *tmp =
226 io_stream::open (concat ("cygfile:///etc/setup/", pkg->name,
227 (src ? "-src.lst.gz" : ".lst.gz"), 0), "rb");
228 io_stream *lst = compress::decompress (tmp);
3b9077d4
DD
229 if (lst)
230 {
c46a33a9 231 SetWindowText (ins_pkgname, pkg->name);
3b9077d4 232 SetWindowText (ins_action, "Uninstalling...");
c46a33a9
CF
233 if (pkg->action == ACTION_UNINSTALL)
234 log (0, "Uninstalling %s", pkg->name);
3b9077d4 235 else
c46a33a9 236 log (0, "Uninstalling old %s", pkg->name);
3b9077d4 237
b24c88b3 238 while (lst->gets (line, sizeof (line)))
3b9077d4 239 {
b24c88b3
RC
240 if (line[strlen (line) - 1] == '\n')
241 line[strlen (line) - 1] = 0;
3b9077d4
DD
242
243 dirs.add_subdirs (line);
244
a351e48c 245 char *d = cygpath ("/", line, NULL);
3b9077d4
DD
246 DWORD dw = GetFileAttributes (d);
247 if (dw != 0xffffffff && !(dw & FILE_ATTRIBUTE_DIRECTORY))
248 {
249 log (LOG_BABBLE, "unlink %s", d);
250 DeleteFile (d);
251 }
252 }
b24c88b3 253 delete lst;
3b9077d4 254
c46a33a9 255 remove (cygpath ("/etc/setup/", pkg->name, ".lst.gz", 0));
3b9077d4
DD
256
257 dirs.reverse_sort ();
258 char *subdir = 0;
259 while ((subdir = dirs.enumerate (subdir)) != 0)
260 {
a351e48c 261 char *d = cygpath ("/", subdir, NULL);
3b9077d4
DD
262 if (RemoveDirectory (d))
263 log (LOG_BABBLE, "rmdir %s", d);
264 }
fb087b80 265 num_uninstalls++;
3ae6c15c
CF
266 pkg->installed_ix = TRUST_UNKNOWN;
267 if (pkg->installed)
268 {
269 free (pkg->installed);
270 pkg->installed = NULL;
271 }
3b9077d4
DD
272 }
273}
274
42bf5b92 275
3b9077d4 276static int
b24c88b3 277install_one (Package * pkg, bool isSrc)
3b9077d4
DD
278{
279 int errors = 0;
b24c88b3 280 const char *extra;
c46a33a9
CF
281 const char *file;
282 int file_size;
b24c88b3 283 archive *thefile = NULL;
c46a33a9 284 Info *pi = pkg->info + pkg->trust;
3b9077d4 285
c46a33a9
CF
286 if (!isSrc)
287 {
288 extra = "";
289 file_size = pi->install_size;
b24c88b3 290 file = concat ("file://", pi->install, 0);
c46a33a9
CF
291 }
292 else if (pi->source)
293 {
294 extra = "-src";
295 file_size = pi->source_size;
b24c88b3 296 file = concat ("file://", pi->source, 0);
c46a33a9
CF
297 }
298 else
299 return 0;
300
301 char name[strlen (pkg->name) + strlen (extra) + 1];
302 strcat (strcpy (name, pkg->name), extra);
b24c88b3
RC
303
304 /* FIXME: this may file now */
c46a33a9
CF
305 char *basef = base (file);
306 SetWindowText (ins_pkgname, basef);
3b9077d4 307
b24c88b3 308 if (!io_stream::exists (file))
c46a33a9 309 file = basef;
b24c88b3 310 if (!io_stream::exists (file))
3b9077d4 311 {
c46a33a9 312 note (IDS_ERR_OPEN_READ, file, "No such file");
3b9077d4
DD
313 return 1;
314 }
315
b24c88b3
RC
316 io_stream *tmp =
317 io_stream::open (concat ("cygfile:///etc/setup/", name, ".lst.gz", 0),
318 "wb");
319 io_stream *lst = new compress_gz (tmp, "w9");
320 if (lst->error ())
321 {
322 delete lst;
323 lst = NULL;
324 }
3b9077d4
DD
325
326 package_bytes = file_size;
327
c46a33a9
CF
328 char msg[64];
329 if (!pkg->installed)
330 strcpy (msg, "Installing");
331 else
332 {
333 int n = strcmp (pi->version, pkg->installed->version);
334 if (n < 0)
335 strcpy (msg, "Reverting");
336 else if (n == 0)
337 strcpy (msg, "Reinstalling");
338 else
339 strcpy (msg, "Upgrading");
340 }
341
342 switch (pkg->action)
3b9077d4 343 {
c46a33a9
CF
344 case ACTION_PREV:
345 strcat (msg, " previous version...");
3b9077d4 346 break;
c46a33a9
CF
347 case ACTION_CURR:
348 strcat (msg, "...");
3b9077d4 349 break;
c46a33a9
CF
350 case ACTION_TEST:
351 strcat (msg, " test version...");
42bf5b92 352 break;
b24c88b3
RC
353 default:
354 /* FIXME: log this somehow */
355 break;
3b9077d4
DD
356 }
357
c46a33a9
CF
358 SetWindowText (ins_action, msg);
359 log (0, "%s%s", msg, file);
b24c88b3
RC
360 tmp = io_stream::open (file, "rb");
361 if (tmp)
3b9077d4 362 {
b24c88b3
RC
363 io_stream *tmp2 = compress::decompress (tmp);
364 if (tmp2)
365 thefile = archive::extract (tmp2);
366 else
367 thefile = archive::extract (tmp);
368 /* FIXME: potential leak of either *tmp or *tmp2 */
369 if (thefile)
3b9077d4 370 {
b24c88b3
RC
371 const char *fn;
372 while ((fn = thefile->next_file_name ()))
373 {
374 char *dest_file;
375
376 if (lst)
377 lst->write (concat (fn, "\n", 0), strlen (fn) + 1);
378
379 dest_file =
380 concat ("cygfile://", isSrc ? "/usr/src/" : "/", NULL);
381
382 /* FIXME: concat leaks memory */
383 SetWindowText (ins_filename, concat (dest_file, fn, 0));
384 log (LOG_BABBLE, "Installing file %s%s", dest_file, fn);
385 if (archive::extract_file (thefile, dest_file) != 0)
386 {
387 log (0, "Unable to install file %s%s", dest_file, fn);
388 errors++;
389 }
390
391 progress (tmp->tell ());
392 free (dest_file);
393 num_installs++;
394 }
395 delete thefile;
3b9077d4 396
b24c88b3
RC
397 total_bytes_sofar += file_size;
398 }
3b9077d4 399 }
3b9077d4
DD
400 progress (0);
401
85b43844 402 int df = diskfull (get_root_dir ());
3b9077d4
DD
403 SendMessage (ins_diskfull, PBM_SETPOS, (WPARAM) df, 0);
404
405 if (lst)
b24c88b3 406 delete lst;
3b9077d4 407
c46a33a9 408 if (!errors)
3ae6c15c
CF
409 {
410 Info *inf = pkg->info + pkg->trust;
411 pkg->installed_ix = pkg->trust;
412 if (pkg->installed)
413 free (pkg->installed);
b24c88b3
RC
414 pkg->installed =
415 new Info (inf->install, inf->version, inf->install_size, inf->source,
416 inf->source_size);
3ae6c15c 417 }
c46a33a9 418
3b9077d4
DD
419 return errors;
420}
421
72fd1d1e
CF
422static void
423check_for_old_cygwin ()
424{
425 char buf[_MAX_PATH + sizeof ("\\cygwin1.dll")];
426 if (!GetSystemDirectory (buf, sizeof (buf)))
427 return;
428 strcat (buf, "\\cygwin1.dll");
429 if (_access (buf, 0) != 0)
430 return;
431
432 char msg[sizeof (buf) + 132];
b24c88b3
RC
433 sprintf (msg,
434 "An old version of cygwin1.dll was found here:\r\n%s\r\nDelete?",
435 buf);
436 switch (MessageBox
437 (NULL, msg, "What's that doing there?",
438 MB_YESNO | MB_ICONQUESTION | MB_TASKMODAL))
72fd1d1e
CF
439 {
440 case IDYES:
441 if (!DeleteFile (buf))
442 {
443 sprintf (msg, "Couldn't delete file %s.\r\n"
b24c88b3
RC
444 "Is the DLL in use by another application?\r\n"
445 "You should delete the old version of cygwin1.dll\r\nat your earliest convenience.",
446 buf);
447 MessageBox (NULL, buf, "Couldn't delete file",
448 MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
72fd1d1e
CF
449 }
450 break;
451 default:
b24c88b3 452 break;
72fd1d1e
CF
453 }
454
455 return;
456}
457
23c9e63c
DD
458void
459do_install (HINSTANCE h)
460{
3b9077d4 461 int i;
2a1a01e0
DD
462 int errors = 0;
463
3b9077d4
DD
464 num_installs = 0, num_uninstalls = 0;
465
50225eae 466 next_dialog = IDD_DESKTOP;
23c9e63c 467
85b43844 468 mkdir_p (1, get_root_dir ());
904d24fe 469
b24c88b3 470 for (i = 0; standard_dirs[i]; i++)
904d24fe 471 {
a351e48c 472 char *p = cygpath (standard_dirs[i], 0);
904d24fe
DD
473 mkdir_p (1, p);
474 free (p);
475 }
476
1a18aed7 477 /* Create /var/run/utmp */
b24c88b3
RC
478 io_stream *utmp = io_stream::open ("cygfile:///var/run/utmp", "wb");
479 delete utmp;
1a18aed7 480
23c9e63c
DD
481 dismiss_url_status_dialog ();
482
483 init_dialog ();
484
485 total_bytes = 0;
486 total_bytes_sofar = 0;
487
85b43844 488 int df = diskfull (get_root_dir ());
d07591a3
DD
489 SendMessage (ins_diskfull, PBM_SETPOS, (WPARAM) df, 0);
490
0af2d779
CF
491 int istext = (root_text == IDC_ROOT_TEXT) ? 1 : 0;
492 int issystem = (root_scope == IDC_ROOT_SYSTEM) ? 1 : 0;
493
494 create_mount ("/", get_root_dir (), istext, issystem);
495 create_mount ("/usr/bin", cygpath ("/bin", 0), istext, issystem);
496 create_mount ("/usr/lib", cygpath ("/lib", 0), istext, issystem);
497 set_cygdrive_flags (istext, issystem);
498
b24c88b3 499 for (Package * pkg = package; pkg->name; pkg++)
23c9e63c 500 {
c46a33a9
CF
501 Info *pi = pkg->info + pkg->trust;
502 if (pkg->action != ACTION_SRC_ONLY)
503 total_bytes += pi->install_size;
504 if (pkg->srcpicked)
505 total_bytes += pi->source_size;
23c9e63c
DD
506 }
507
b24c88b3 508 for (Package * pkg = package; pkg->name; pkg++)
23c9e63c 509 {
c46a33a9 510 if (is_uninstall_action (pkg))
4a83b7b0 511 {
c46a33a9
CF
512 uninstall_one (pkg, 0);
513 uninstall_one (pkg, 1);
4a83b7b0 514 }
23c9e63c 515
c46a33a9 516 if (is_download_action (pkg))
23c9e63c 517 {
c46a33a9
CF
518 int e = 0;
519 if (pkg->action != ACTION_SRC_ONLY)
520 e += install_one (pkg, FALSE);
521 if (pkg->srcpicked)
522 e += install_one (pkg, TRUE);
3b9077d4 523 if (e)
40aef45e 524 {
c46a33a9 525 pkg->action = ACTION_ERROR;
3b9077d4 526 errors++;
40aef45e 527 }
4a83b7b0 528 }
b24c88b3 529 } // end of big package loop
4a83b7b0
DD
530
531 ShowWindow (ins_dialog, SW_HIDE);
23c9e63c 532
a351e48c
CF
533 char *odbn = cygpath ("/etc/setup/installed.db", 0);
534 char *ndbn = cygpath ("/etc/setup/installed.db.new", 0);
535 char *sdbn = cygpath ("/etc/setup/installed.db.old", 0);
23c9e63c
DD
536
537 mkdir_p (0, ndbn);
538
539 FILE *odb = fopen (odbn, "rt");
540 FILE *ndb = fopen (ndbn, "wb");
541
542 if (!ndb)
543 {
b24c88b3 544 const char *err = strerror (errno);
23c9e63c
DD
545 if (!err)
546 err = "(unknown error)";
547 fatal (IDS_ERR_OPEN_WRITE, ndb, err);
548 }
549
550 if (odb)
551 {
c46a33a9 552 char line[1000], pkgname[1000];
23c9e63c
DD
553 while (fgets (line, 1000, odb))
554 {
c46a33a9
CF
555 sscanf (line, "%s", pkgname);
556 Package *pkg = getpkgbyname (pkgname);
b24c88b3
RC
557 if (!pkg
558 || (!is_download_action (pkg)
559 && pkg->action != ACTION_UNINSTALL))
23c9e63c
DD
560 fputs (line, ndb);
561 }
42bf5b92 562
23c9e63c 563 }
4a83b7b0 564
b24c88b3 565 for (Package * pkg = package; pkg->name; pkg++)
c46a33a9
CF
566 if (is_download_action (pkg))
567 {
568 Info *pi = pkg->info + pkg->installed_ix;
569 if (pkg->srcpicked)
570 fprintf (ndb, "%s %s %d %s %d\n", pkg->name,
571 pi->install, pi->install_size,
572 pi->source, pi->source_size);
573 else
574 fprintf (ndb, "%s %s %d\n", pkg->name,
575 pi->install, pi->install_size);
576 }
23c9e63c
DD
577
578 if (odb)
579 fclose (odb);
580 fclose (ndb);
581
582 remove (sdbn);
583 if (odb && rename (odbn, sdbn))
584 badrename (odbn, sdbn);
585
586 remove (odbn);
587 if (rename (ndbn, odbn))
588 badrename (ndbn, odbn);
589
72fd1d1e
CF
590 if (!errors)
591 check_for_old_cygwin ();
4a83b7b0
DD
592 if (num_installs == 0 && num_uninstalls == 0)
593 {
594 exit_msg = IDS_NOTHING_INSTALLED;
595 return;
596 }
597 if (num_installs == 0)
598 {
599 exit_msg = IDS_UNINSTALL_COMPLETE;
600 return;
601 }
602
2a1a01e0
DD
603 if (errors)
604 exit_msg = IDS_INSTALL_INCOMPLETE;
605 else
606 exit_msg = IDS_INSTALL_COMPLETE;
23c9e63c 607}
This page took 0.094622 seconds and 5 git commands to generate.