2 * Copyright (c) 2000, Red Hat, Inc.
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.
9 * A copy of the GNU General Public License can be found at
12 * Written by DJ Delorie <dj@cygnus.com>
16 /* The purpose of this file is to install 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. */
23 static const char *cvsid
= "\n%%% $Id$\n";
32 #include <sys/types.h>
37 #include "zlib/zlib.h"
50 #include "filemanip.h"
51 #include "io_stream.h"
53 #include "compress_gz.h"
55 #include "archive_tar.h"
58 #include "package_db.h"
59 #include "package_meta.h"
60 #include "package_version.h"
61 #include "package_source.h"
66 extern ThreeBarProgressPage Progress
;
68 static int total_bytes
= 0;
69 static int total_bytes_sofar
= 0;
70 static int package_bytes
= 0;
75 Progress
.SetText2 ("");
76 Progress
.SetText3 ("");
82 if (package_bytes
> 0)
84 Progress
.SetBar1 (bytes
, package_bytes
);
89 Progress
.SetBar2 (total_bytes_sofar
+ bytes
, total_bytes
);
93 static const char *standard_dirs
[] = {
112 static int num_installs
, num_replacements
, num_uninstalls
;
113 static void uninstall_one (packagemeta
&);
114 static int replace_one (packagemeta
&);
115 static int install_one_source (packagemeta
&, packagesource
&, String
const &,
116 String
const &, package_type_t
);
117 static bool rebootneeded
;
119 /* FIXME: upgrades should be a method too */
121 uninstall_one (packagemeta
& pkgm
)
123 Progress
.SetText1 ("Uninstalling...");
124 Progress
.SetText2 (pkgm
.name
.cstr_oneuse());
125 log (LOG_TIMESTAMP
, String("Uninstalling ") + pkgm
.name
);
130 /* uninstall and install a package, preserving configuration
131 * files and the like.
132 * This method should also know about replacing in-use file.
133 * ASSUMPTIONS: pkgm is installed.
134 * pkgm has a desired package.
137 replace_one (packagemeta
& pkg
)
140 Progress
.SetText1 ("Replacing...");
141 Progress
.SetText2 (pkg
.name
.cstr_oneuse());
142 log (LOG_TIMESTAMP
, String( "Replacing ") + pkg
.name
);
146 install_one_source (pkg
, pkg
.desired
->bin
, "cygfile://","/", package_binary
);
148 pkg
.installed
= pkg
.desired
;
154 /* install one source at a given prefix. */
156 install_one_source (packagemeta
& pkgm
, packagesource
& source
,
157 String
const &prefixURL
, String
const &prefixPath
, package_type_t type
)
160 Progress
.SetText2 (source
.Base ());
161 if (!io_stream::exists (source
.Cached ()))
163 note (NULL
, IDS_ERR_OPEN_READ
, source
.Cached (), "No such file");
167 if (type
== package_binary
)
171 open (String ("cygfile:///etc/setup/") + pkgm
.name
+ ".lst.gz",
173 lst
= new compress_gz (tmp
, "w9");
181 package_bytes
= source
.size
;
184 strcpy (msg
, "Installing");
185 Progress
.SetText1 (msg
);
186 log (LOG_TIMESTAMP
, "%s %s", msg
, source
.Cached ());
187 io_stream
*tmp
= io_stream::open (source
.Cached (), "rb");
188 archive
*thefile
= 0;
191 io_stream
*tmp2
= compress::decompress (tmp
);
193 thefile
= archive::extract (tmp2
);
195 thefile
= archive::extract (tmp
);
197 /* FIXME: potential leak of either *tmp or *tmp2 */
201 while ((fn
= thefile
->next_file_name ()).size())
205 String tmp
=fn
+ "\n";
206 lst
->write (tmp
.cstr_oneuse(), tmp
.size() + 1);
209 String canonicalfn
= prefixPath
+ fn
;
211 Progress
.SetText3 (canonicalfn
.cstr_oneuse());
212 log (LOG_BABBLE
, String("Installing file ") + prefixURL
+ prefixPath
+ fn
);
213 if (archive::extract_file (thefile
, prefixURL
, prefixPath
) != 0)
215 //extract to temp location
216 if (archive::extract_file (thefile
, prefixURL
, prefixPath
, ".new") != 0)
218 log (LOG_TIMESTAMP
, String("Unable to install file ")+ prefixURL
+prefixPath
+ fn
);
224 switch (Win32::OS ())
227 /* Get the short file names */
228 char source
[MAX_PATH
];
230 GetShortPathName (cygpath ("/", fn
.cstr_oneuse(), ".new", 0).cstr_oneuse(),
232 if (!len
|| len
> MAX_PATH
)
235 "Unable to schedule reboot replacement of file %s with %s (Win32 Error %ld)",
236 cygpath ("/", fn
.cstr_oneuse(), 0).cstr_oneuse(), cygpath ("/", fn
.cstr_oneuse(), ".new", 0).cstr_oneuse(),
244 GetShortPathName (cygpath ("/", fn
.cstr_oneuse(), 0).cstr_oneuse(), dest
,
246 if (!len
|| len
> MAX_PATH
)
249 "Unable to schedule reboot replacement of file %s with %s (Win32 Error %ld)",
250 cygpath ("/", fn
.cstr_oneuse(), 0).cstr_oneuse(), cygpath ("/", fn
.cstr_oneuse(),
251 ".new", 0).cstr_oneuse(),
257 /* trigger a replacement on reboot */
258 if (!WritePrivateProfileString
259 ("rename", dest
, source
, "WININIT.INI"))
262 "Unable to schedule reboot replacement of file %s with %s (Win32 Error %ld)",
263 cygpath ("/", fn
.cstr_oneuse(), 0).cstr_oneuse(), cygpath ("/", fn
.cstr_oneuse(),
264 ".new", 0).cstr_oneuse(),
273 /* XXX FIXME: prefix may not be / for in use files -
274 * although it most likely is
275 * - we need a io method to get win32 paths
276 * or to wrap this system call
278 if (!MoveFileEx (cygpath ("/", fn
.cstr_oneuse(), ".new", 0).cstr_oneuse(),
279 cygpath ("/", fn
.cstr_oneuse(), 0).cstr_oneuse(),
280 MOVEFILE_DELAY_UNTIL_REBOOT
|
281 MOVEFILE_REPLACE_EXISTING
))
284 "Unable to schedule reboot replacement of file %s with %s (Win32 Error %ld)",
285 cygpath ("/", fn
.cstr_oneuse(), 0).cstr_oneuse(), cygpath ("/", fn
.cstr_oneuse(), ".new", 0).cstr_oneuse(),
296 progress (tmp
->tell ());
301 total_bytes_sofar
+= package_bytes
;
307 int df
= diskfull (get_root_dir ().cstr_oneuse());
308 Progress
.SetBar3 (df
);
316 /* install a package, install both the binary and source aspects if needed */
318 install_one (packagemeta
& pkg
)
322 if (pkg
.installed
!= pkg
.desired
&& pkg
.desired
->binpicked
)
325 install_one_source (pkg
, pkg
.desired
->bin
, "cygfile://","/",
328 pkg
.installed
= pkg
.desired
;
330 if (pkg
.desired
->srcpicked
)
332 install_one_source (pkg
, pkg
.desired
->src
, "cygfile://","/usr/src",
335 /* FIXME: make a upgrade method and reinstate this */
339 strcpy (msg
, "Installing");
342 int n
= strcmp (pi
->version
, pkg
->installed
->version
);
344 strcpy (msg
, "Reverting");
346 strcpy (msg
, "Reinstalling");
348 strcpy (msg
, "Upgrading");
354 strcat (msg
, " previous version...");
360 strcat (msg
, " test version...");
363 /* FIXME: log this somehow */
366 SetWindowText (ins_action
, msg
);
367 log (0, "%s%s", msg
, file
);
374 check_for_old_cygwin ()
376 char buf
[_MAX_PATH
+ sizeof ("\\cygwin1.dll")];
377 if (!GetSystemDirectory (buf
, sizeof (buf
)))
379 strcat (buf
, "\\cygwin1.dll");
380 if (_access (buf
, 0) != 0)
383 char msg
[sizeof (buf
) + 132];
385 "An old version of cygwin1.dll was found here:\r\n%s\r\nDelete?",
388 (NULL
, msg
, "What's that doing there?",
389 MB_YESNO
| MB_ICONQUESTION
| MB_TASKMODAL
))
392 if (!DeleteFile (buf
))
394 sprintf (msg
, "Couldn't delete file %s.\r\n"
395 "Is the DLL in use by another application?\r\n"
396 "You should delete the old version of cygwin1.dll\r\n"
397 "at your earliest convenience.", buf
);
398 MessageBox (NULL
, buf
, "Couldn't delete file",
399 MB_OK
| MB_ICONEXCLAMATION
| MB_TASKMODAL
);
410 do_install_thread (HINSTANCE h
, HWND owner
)
415 num_installs
= 0, num_uninstalls
= 0, num_replacements
= 0;
416 rebootneeded
= false;
418 next_dialog
= IDD_DESKTOP
;
420 io_stream::mkpath_p (PATH_TO_DIR
, get_root_dir ());
422 for (i
= 0; standard_dirs
[i
]; i
++)
424 String p
= cygpath (standard_dirs
[i
], 0);
426 io_stream::mkpath_p (PATH_TO_DIR
, p
);
429 /* Create /var/run/utmp */
430 io_stream
*utmp
= io_stream::open ("cygfile:///var/run/utmp", "wb");
436 total_bytes_sofar
= 0;
438 int df
= diskfull (get_root_dir ().cstr_oneuse());
439 Progress
.SetBar3 (df
);
441 int istext
= (root_text
== IDC_ROOT_TEXT
) ? 1 : 0;
442 int issystem
= (root_scope
== IDC_ROOT_SYSTEM
) ? 1 : 0;
444 create_mount ("/", get_root_dir ().cstr_oneuse(), istext
, issystem
);
445 create_mount ("/usr/bin", cygpath ("/bin", 0), istext
, issystem
);
446 create_mount ("/usr/lib", cygpath ("/lib", 0), istext
, issystem
);
447 set_cygdrive_flags (istext
, issystem
);
449 /* Let's hope people won't uninstall packages before installing [b]ash */
453 for (size_t n
= 1; n
<= db
.packages
.number (); n
++)
455 packagemeta
& pkg
= *db
.packages
[n
];
457 if (pkg
.desired
&& (pkg
.desired
->srcpicked
|| pkg
.desired
->binpicked
))
459 if (pkg
.desired
->srcpicked
)
460 total_bytes
+= pkg
.desired
->src
.size
;
461 if (pkg
.desired
->binpicked
)
462 total_bytes
+= pkg
.desired
->bin
.size
;
466 /* start with uninstalls - remove files that new packages may replace */
467 for (size_t n
= 1; n
<= db
.packages
.number (); n
++)
469 packagemeta
& pkg
= *db
.packages
[n
];
470 if (pkg
.installed
&& (!pkg
.desired
|| pkg
.desired
!= pkg
.installed
))
474 /* now in-place binary upgrades/reinstalls, as these may remove fils
475 * that have been moved into new packages
478 for (size_t n
= 1; n
<= db
.packages
.number (); n
++)
480 packagemeta
& pkg
= *db
.packages
[n
];
481 if (pkg
.installed
&& pkg
.desired
&& pkg
.desired
->binpicked
)
484 e
+= replace_one (pkg
);
490 for (size_t n
= 1; n
<= db
.packages
.number (); n
++)
492 packagemeta
& pkg
= *db
.packages
[n
];
494 if (pkg
.desired
&& (pkg
.desired
->srcpicked
|| pkg
.desired
->binpicked
))
497 e
+= install_one (pkg
);
503 } // end of big package loop
506 note (owner
, IDS_REBOOT_REQUIRED
);
509 if ((temperr
= db
.flush ()))
511 const char *err
= strerror (temperr
);
513 err
= "(unknown error)";
514 fatal (owner
, IDS_ERR_OPEN_WRITE
, "Package Database",
519 check_for_old_cygwin ();
520 if (num_installs
== 0 && num_uninstalls
== 0)
522 exit_msg
= IDS_NOTHING_INSTALLED
;
525 if (num_installs
== 0)
527 exit_msg
= IDS_UNINSTALL_COMPLETE
;
532 exit_msg
= IDS_INSTALL_INCOMPLETE
;
534 exit_msg
= IDS_INSTALL_COMPLETE
;
538 do_install_reflector (void *p
)
541 context
= (HANDLE
*) p
;
543 do_install_thread ((HINSTANCE
) context
[0], (HWND
) context
[1]);
545 // Tell the progress page that we're done downloading
546 Progress
.PostMessage (WM_APP_INSTALL_THREAD_COMPLETE
);
551 static HANDLE context
[2];
554 do_install (HINSTANCE h
, HWND owner
)
559 _beginthread (do_install_reflector
, 0, context
);