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