]>
Commit | Line | Data |
---|---|---|
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 | ||
8e9aa511 | 16 | /* The purpose of this file is to install all the packages selected in |
23c9e63c DD |
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 |
23 | static 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> | |
ab57ceaa RC |
36 | #include <process.h> |
37 | ||
87c42361 | 38 | #include "zlib/zlib.h" |
23c9e63c DD |
39 | |
40 | #include "resource.h" | |
41 | #include "ini.h" | |
42 | #include "dialog.h" | |
43 | #include "concat.h" | |
44 | #include "geturl.h" | |
45 | #include "mkdir.h" | |
46 | #include "state.h" | |
23c9e63c DD |
47 | #include "diskfull.h" |
48 | #include "msg.h" | |
49 | #include "mount.h" | |
89b1a15b | 50 | #include "log.h" |
a351e48c | 51 | #include "mount.h" |
c46a33a9 | 52 | #include "filemanip.h" |
b24c88b3 RC |
53 | #include "io_stream.h" |
54 | #include "compress.h" | |
55 | #include "compress_gz.h" | |
56 | #include "archive.h" | |
57 | #include "archive_tar.h" | |
8e9aa511 | 58 | #include "script.h" |
4a83b7b0 | 59 | |
fa0c0d10 RC |
60 | #include "package_db.h" |
61 | #include "package_meta.h" | |
bb849dbd RC |
62 | #include "package_version.h" |
63 | #include "package_source.h" | |
fa0c0d10 | 64 | |
4a83b7b0 | 65 | #include "port.h" |
23c9e63c | 66 | |
ab57ceaa RC |
67 | #include "threebar.h" |
68 | extern ThreeBarProgressPage Progress; | |
23c9e63c DD |
69 | |
70 | static int total_bytes = 0; | |
71 | static int total_bytes_sofar = 0; | |
72 | static int package_bytes = 0; | |
73 | ||
23c9e63c DD |
74 | static void |
75 | init_dialog () | |
76 | { | |
ab57ceaa RC |
77 | Progress.SetText2 (""); |
78 | Progress.SetText3 (""); | |
23c9e63c DD |
79 | } |
80 | ||
81 | static void | |
82 | progress (int bytes) | |
83 | { | |
ab57ceaa | 84 | if (package_bytes > 0) |
23c9e63c | 85 | { |
ab57ceaa | 86 | Progress.SetBar1 (bytes, package_bytes); |
23c9e63c DD |
87 | } |
88 | ||
ab57ceaa | 89 | if (total_bytes > 0) |
23c9e63c | 90 | { |
ab57ceaa | 91 | Progress.SetBar2 (total_bytes_sofar + bytes, total_bytes); |
23c9e63c | 92 | } |
23c9e63c DD |
93 | } |
94 | ||
b24c88b3 | 95 | static const char *standard_dirs[] = { |
1a18aed7 | 96 | "/bin", |
904d24fe | 97 | "/etc", |
1a18aed7 | 98 | "/lib", |
904d24fe | 99 | "/tmp", |
4a83b7b0 | 100 | "/usr", |
1a18aed7 DD |
101 | "/usr/bin", |
102 | "/usr/lib", | |
ef45c299 | 103 | "/usr/src", |
4a83b7b0 | 104 | "/usr/local", |
1a18aed7 DD |
105 | "/usr/local/bin", |
106 | "/usr/local/etc", | |
107 | "/usr/local/lib", | |
904d24fe | 108 | "/usr/tmp", |
1a18aed7 | 109 | "/var/run", |
904d24fe DD |
110 | "/var/tmp", |
111 | 0 | |
112 | }; | |
113 | ||
3b9077d4 DD |
114 | static int num_installs, num_uninstalls; |
115 | ||
fa0c0d10 | 116 | /* FIXME: upgrades should be a method too */ |
3b9077d4 | 117 | static void |
cbfc4215 | 118 | uninstall_one (packagemeta & pkgm) |
3b9077d4 | 119 | { |
ab57ceaa RC |
120 | Progress.SetText1 ("Uninstalling..."); |
121 | Progress.SetText2 (pkgm.name); | |
122 | log (0, "Uninstalling %s", pkgm.name); | |
123 | pkgm.uninstall (); | |
124 | num_uninstalls++; | |
3b9077d4 DD |
125 | } |
126 | ||
42bf5b92 | 127 | |
bb849dbd RC |
128 | |
129 | /* install one source at a given prefix. */ | |
3b9077d4 | 130 | static int |
bb849dbd RC |
131 | install_one_source (packagemeta & pkgm, packagesource & source, |
132 | char const *prefix, package_type_t type) | |
3b9077d4 DD |
133 | { |
134 | int errors = 0; | |
ab57ceaa | 135 | Progress.SetText2 (source.Base ()); |
bb849dbd | 136 | if (!io_stream::exists (source.Cached ())) |
c46a33a9 | 137 | { |
ab57ceaa | 138 | note (NULL, IDS_ERR_OPEN_READ, source.Cached (), "No such file"); |
bb849dbd | 139 | return 1; |
c46a33a9 | 140 | } |
bb849dbd RC |
141 | io_stream *lst = 0; |
142 | if (type == package_binary) | |
c46a33a9 | 143 | { |
bb849dbd RC |
144 | io_stream *tmp = |
145 | io_stream:: | |
146 | open (concat ("cygfile:///etc/setup/", pkgm.name, ".lst.gz", 0), | |
147 | "wb"); | |
148 | lst = new compress_gz (tmp, "w9"); | |
149 | if (lst->error ()) | |
150 | { | |
151 | delete lst; | |
152 | lst = NULL; | |
153 | } | |
c46a33a9 | 154 | } |
b24c88b3 | 155 | |
bb849dbd | 156 | package_bytes = source.size; |
3b9077d4 | 157 | |
bb849dbd RC |
158 | char msg[64]; |
159 | strcpy (msg, "Installing"); | |
ab57ceaa | 160 | Progress.SetText1 (msg); |
bb849dbd RC |
161 | log (0, "%s%s", msg, source.Cached ()); |
162 | io_stream *tmp = io_stream::open (source.Cached (), "rb"); | |
163 | archive *thefile = 0; | |
164 | if (tmp) | |
d4a4527d | 165 | { |
bb849dbd RC |
166 | io_stream *tmp2 = compress::decompress (tmp); |
167 | if (tmp2) | |
168 | thefile = archive::extract (tmp2); | |
169 | else | |
170 | thefile = archive::extract (tmp); | |
3b9077d4 | 171 | } |
bb849dbd RC |
172 | /* FIXME: potential leak of either *tmp or *tmp2 */ |
173 | if (thefile) | |
d4a4527d | 174 | { |
bb849dbd RC |
175 | const char *fn; |
176 | while ((fn = thefile->next_file_name ())) | |
177 | { | |
178 | if (lst) | |
179 | lst->write (concat (fn, "\n", 0), strlen (fn) + 1); | |
180 | ||
181 | /* FIXME: concat leaks memory */ | |
ab57ceaa | 182 | Progress.SetText3 (concat (prefix, fn, 0)); |
bb849dbd RC |
183 | log (LOG_BABBLE, "Installing file %s%s", prefix, fn); |
184 | if (archive::extract_file (thefile, prefix) != 0) | |
185 | { | |
186 | log (0, "Unable to install file %s%s", prefix, fn); | |
187 | errors++; | |
188 | } | |
189 | ||
190 | progress (tmp->tell ()); | |
191 | num_installs++; | |
192 | } | |
193 | delete thefile; | |
194 | ||
195 | total_bytes_sofar += package_bytes; | |
d4a4527d | 196 | } |
3b9077d4 | 197 | |
90d14922 | 198 | |
bb849dbd RC |
199 | progress (0); |
200 | ||
201 | int df = diskfull (get_root_dir ()); | |
ab57ceaa | 202 | Progress.SetBar3 (df); |
bb849dbd RC |
203 | |
204 | if (lst) | |
205 | delete lst; | |
206 | ||
207 | return errors; | |
208 | } | |
209 | ||
210 | /* install a package, install both the binary and source aspects if needed */ | |
211 | static int | |
212 | install_one (packagemeta & pkg) | |
213 | { | |
214 | int errors = 0; | |
215 | ||
216 | if (pkg.desired->binpicked) | |
ab57ceaa | 217 | { |
bb849dbd | 218 | errors += |
ab57ceaa RC |
219 | install_one_source (pkg, pkg.desired->bin, "cygfile:///", |
220 | package_binary); | |
221 | if (!errors) | |
222 | pkg.installed = pkg.desired; | |
223 | } | |
224 | if (pkg.desired->srcpicked) | |
225 | errors += | |
226 | install_one_source (pkg, pkg.desired->src, "cygfile:///usr/src", | |
227 | package_source); | |
bb849dbd RC |
228 | |
229 | /* FIXME: make a upgrade method and reinstate this */ | |
230 | #if 0 | |
c46a33a9 CF |
231 | char msg[64]; |
232 | if (!pkg->installed) | |
233 | strcpy (msg, "Installing"); | |
234 | else | |
235 | { | |
236 | int n = strcmp (pi->version, pkg->installed->version); | |
237 | if (n < 0) | |
238 | strcpy (msg, "Reverting"); | |
239 | else if (n == 0) | |
240 | strcpy (msg, "Reinstalling"); | |
241 | else | |
242 | strcpy (msg, "Upgrading"); | |
243 | } | |
244 | ||
245 | switch (pkg->action) | |
3b9077d4 | 246 | { |
c46a33a9 CF |
247 | case ACTION_PREV: |
248 | strcat (msg, " previous version..."); | |
3b9077d4 | 249 | break; |
c46a33a9 CF |
250 | case ACTION_CURR: |
251 | strcat (msg, "..."); | |
3b9077d4 | 252 | break; |
c46a33a9 CF |
253 | case ACTION_TEST: |
254 | strcat (msg, " test version..."); | |
42bf5b92 | 255 | break; |
b24c88b3 RC |
256 | default: |
257 | /* FIXME: log this somehow */ | |
258 | break; | |
3b9077d4 | 259 | } |
c46a33a9 CF |
260 | SetWindowText (ins_action, msg); |
261 | log (0, "%s%s", msg, file); | |
bb849dbd | 262 | #endif |
c46a33a9 | 263 | |
3b9077d4 DD |
264 | return errors; |
265 | } | |
266 | ||
72fd1d1e CF |
267 | static void |
268 | check_for_old_cygwin () | |
269 | { | |
270 | char buf[_MAX_PATH + sizeof ("\\cygwin1.dll")]; | |
271 | if (!GetSystemDirectory (buf, sizeof (buf))) | |
272 | return; | |
273 | strcat (buf, "\\cygwin1.dll"); | |
274 | if (_access (buf, 0) != 0) | |
275 | return; | |
276 | ||
277 | char msg[sizeof (buf) + 132]; | |
b24c88b3 RC |
278 | sprintf (msg, |
279 | "An old version of cygwin1.dll was found here:\r\n%s\r\nDelete?", | |
280 | buf); | |
281 | switch (MessageBox | |
282 | (NULL, msg, "What's that doing there?", | |
283 | MB_YESNO | MB_ICONQUESTION | MB_TASKMODAL)) | |
72fd1d1e CF |
284 | { |
285 | case IDYES: | |
286 | if (!DeleteFile (buf)) | |
287 | { | |
288 | sprintf (msg, "Couldn't delete file %s.\r\n" | |
b24c88b3 | 289 | "Is the DLL in use by another application?\r\n" |
7c7034e8 RC |
290 | "You should delete the old version of cygwin1.dll\r\n" |
291 | "at your earliest convenience.", buf); | |
b24c88b3 RC |
292 | MessageBox (NULL, buf, "Couldn't delete file", |
293 | MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL); | |
72fd1d1e CF |
294 | } |
295 | break; | |
296 | default: | |
b24c88b3 | 297 | break; |
72fd1d1e CF |
298 | } |
299 | ||
300 | return; | |
301 | } | |
302 | ||
ab57ceaa RC |
303 | static void |
304 | do_install_thread (HINSTANCE h, HWND owner) | |
23c9e63c | 305 | { |
3b9077d4 | 306 | int i; |
2a1a01e0 DD |
307 | int errors = 0; |
308 | ||
3b9077d4 DD |
309 | num_installs = 0, num_uninstalls = 0; |
310 | ||
50225eae | 311 | next_dialog = IDD_DESKTOP; |
23c9e63c | 312 | |
85b43844 | 313 | mkdir_p (1, get_root_dir ()); |
904d24fe | 314 | |
b24c88b3 | 315 | for (i = 0; standard_dirs[i]; i++) |
904d24fe | 316 | { |
a351e48c | 317 | char *p = cygpath (standard_dirs[i], 0); |
904d24fe DD |
318 | mkdir_p (1, p); |
319 | free (p); | |
320 | } | |
321 | ||
1a18aed7 | 322 | /* Create /var/run/utmp */ |
b24c88b3 RC |
323 | io_stream *utmp = io_stream::open ("cygfile:///var/run/utmp", "wb"); |
324 | delete utmp; | |
1a18aed7 | 325 | |
23c9e63c DD |
326 | init_dialog (); |
327 | ||
328 | total_bytes = 0; | |
329 | total_bytes_sofar = 0; | |
330 | ||
85b43844 | 331 | int df = diskfull (get_root_dir ()); |
ab57ceaa | 332 | Progress.SetBar3 (df); |
d07591a3 | 333 | |
0af2d779 CF |
334 | int istext = (root_text == IDC_ROOT_TEXT) ? 1 : 0; |
335 | int issystem = (root_scope == IDC_ROOT_SYSTEM) ? 1 : 0; | |
336 | ||
337 | create_mount ("/", get_root_dir (), istext, issystem); | |
338 | create_mount ("/usr/bin", cygpath ("/bin", 0), istext, issystem); | |
339 | create_mount ("/usr/lib", cygpath ("/lib", 0), istext, issystem); | |
340 | set_cygdrive_flags (istext, issystem); | |
341 | ||
8e9aa511 RC |
342 | /* Let's hope people won't uninstall packages before installing [b]ash */ |
343 | init_run_script (); | |
344 | ||
bb849dbd | 345 | packagedb db; |
bc78a6d5 | 346 | for (size_t n = 1; n <= db.packages.number (); n++) |
cbfc4215 | 347 | { |
ab57ceaa RC |
348 | packagemeta & pkg = *db.packages[n]; |
349 | ||
350 | if (pkg.desired && (pkg.desired->srcpicked || pkg.desired->binpicked)) | |
351 | { | |
352 | if (pkg.desired->srcpicked) | |
353 | total_bytes += pkg.desired->src.size; | |
354 | if (pkg.desired->binpicked) | |
355 | total_bytes += pkg.desired->bin.size; | |
356 | } | |
cbfc4215 | 357 | } |
bb849dbd | 358 | |
bc78a6d5 | 359 | for (size_t n = 1; n <= db.packages.number (); n++) |
23c9e63c | 360 | { |
ab57ceaa | 361 | packagemeta & pkg = *db.packages[n]; |
cbfc4215 | 362 | if (pkg.installed && (!pkg.desired || pkg.desired != pkg.installed)) |
4a83b7b0 | 363 | { |
fa0c0d10 | 364 | uninstall_one (pkg); |
4a83b7b0 | 365 | } |
23c9e63c | 366 | |
ab57ceaa | 367 | if (pkg.desired && (pkg.desired->srcpicked || pkg.desired->binpicked)) |
23c9e63c | 368 | { |
c46a33a9 | 369 | int e = 0; |
cbfc4215 | 370 | e += install_one (pkg); |
3b9077d4 | 371 | if (e) |
40aef45e | 372 | { |
3b9077d4 | 373 | errors++; |
40aef45e | 374 | } |
4a83b7b0 | 375 | } |
b24c88b3 | 376 | } // end of big package loop |
4a83b7b0 | 377 | |
7c7034e8 RC |
378 | int temperr; |
379 | if ((temperr = db.flush ())) | |
23c9e63c | 380 | { |
7c7034e8 | 381 | const char *err = strerror (temperr); |
23c9e63c DD |
382 | if (!err) |
383 | err = "(unknown error)"; | |
ab57ceaa | 384 | fatal (owner, IDS_ERR_OPEN_WRITE, err); |
23c9e63c DD |
385 | } |
386 | ||
72fd1d1e CF |
387 | if (!errors) |
388 | check_for_old_cygwin (); | |
4a83b7b0 DD |
389 | if (num_installs == 0 && num_uninstalls == 0) |
390 | { | |
391 | exit_msg = IDS_NOTHING_INSTALLED; | |
392 | return; | |
393 | } | |
394 | if (num_installs == 0) | |
395 | { | |
396 | exit_msg = IDS_UNINSTALL_COMPLETE; | |
397 | return; | |
398 | } | |
399 | ||
2a1a01e0 DD |
400 | if (errors) |
401 | exit_msg = IDS_INSTALL_INCOMPLETE; | |
402 | else | |
403 | exit_msg = IDS_INSTALL_COMPLETE; | |
23c9e63c | 404 | } |
ab57ceaa RC |
405 | |
406 | static void | |
407 | do_install_reflector (void *p) | |
408 | { | |
409 | HANDLE *context; | |
410 | context = (HANDLE *) p; | |
411 | ||
412 | do_install_thread ((HINSTANCE) context[0], (HWND) context[1]); | |
413 | ||
414 | // Tell the progress page that we're done downloading | |
415 | Progress.PostMessage (WM_APP_INSTALL_THREAD_COMPLETE); | |
416 | ||
417 | _endthread (); | |
418 | } | |
419 | ||
420 | static HANDLE context[2]; | |
421 | ||
422 | void | |
423 | do_install (HINSTANCE h, HWND owner) | |
424 | { | |
425 | context[0] = h; | |
426 | context[1] = owner; | |
427 | ||
428 | _beginthread (do_install_reflector, 0, context); | |
429 | } |