]> cygwin.com Git - cygwin-apps/setup.git/blame - setup.c
* setup.c (processdirlisting): Make "N" option a little less aggressive.
[cygwin-apps/setup.git] / setup.c
CommitLineData
853b9e91
CF
1#include <windows.h>
2#include <wininet.h>
3#include <assert.h>
ea615d51 4#include <ctype.h>
853b9e91
CF
5#include <direct.h>
6#include <errno.h>
7#include <fcntl.h>
8#include <io.h>
9#include <shellapi.h>
10#include <shlguid.h>
11#include <shlobj.h>
12#include <stdio.h>
13#include <time.h>
14#include <sys/types.h>
15#include <sys/stat.h>
16
853b9e91
CF
17#include "setup.h"
18#include "strarry.h"
d6ef1f8f 19#include "zlib/zlib.h"
853b9e91
CF
20
21#define CYGNUS_KEY "Software\\Cygnus Solutions"
22#define DEF_ROOT "C:\\cygwin"
ea615d51
RP
23#define DOWNLOAD_SUBDIR "latest"
24#define SCREEN_LINES 25
25#define COMMAND9X "command.com /E:4096 /c "
26
20904de1
CF
27#ifndef NFILE_LIST
28#define NFILE_LIST 10000
29#endif
30
68cdfc92
CF
31#ifndef NFILE_SLOP
32#define NFILE_SLOP 20
33#endif
34
ea615d51 35char *wd;
93014d67
CF
36
37int downloaddir (HINTERNET session, const char *url);
ea615d51 38
20904de1 39static SA files = {NULL, 0, 0};
93014d67 40
853b9e91
CF
41int
42create_shortcut (const char *target, const char *shortcut)
93014d67 43{
608de931
CF
44 HRESULT hres;
45 IShellLink *sl;
ea615d51 46 char *path, *args;
853b9e91 47
608de931
CF
48 if (!SUCCEEDED (CoInitialize (NULL)))
49 return 0;
853b9e91 50
608de931 51 hres =
853b9e91 52 CoCreateInstance (&CLSID_ShellLink, NULL,
ea615d51 53 CLSCTX_INPROC_SERVER, &IID_IShellLink, (LPVOID *) & sl);
608de931 54 if (SUCCEEDED (hres))
93014d67 55 {
608de931 56 IPersistFile *pf;
ea615d51
RP
57 int quoted = 0;
58 char *c;
59
60 /* Get the command only. */
61 path = xstrdup (target);
62 for (c = path; quoted || (*c != ' ' && *c); ++c)
63 {
64 if (*c == '\"')
65 quoted = !quoted;
66 }
67 if (*c)
68 {
69 *c = '\0';
70 args = c + 1;
71 }
72 else
73 args = "";
853b9e91 74
ea615d51
RP
75 sl->lpVtbl->SetPath (sl, path);
76 sl->lpVtbl->SetArguments (sl, args);
77 xfree (path);
853b9e91 78
608de931 79 hres = sl->lpVtbl->QueryInterface (sl, &IID_IPersistFile, &pf);
93014d67 80
608de931 81 if (SUCCEEDED (hres))
93014d67 82 {
608de931 83 WCHAR widepath[_MAX_PATH];
853b9e91 84
608de931
CF
85 // Ensure that the string is Unicode.
86 MultiByteToWideChar (CP_ACP, 0, shortcut, -1, widepath, MAX_PATH);
853b9e91 87
608de931
CF
88 // Save the link by calling IPersistFile::Save.
89 hres = pf->lpVtbl->Save (pf, widepath, TRUE);
90 pf->lpVtbl->Release (pf);
91 }
92 sl->lpVtbl->Release (sl);
93 }
853b9e91 94
608de931 95 CoUninitialize ();
853b9e91 96
608de931 97 return SUCCEEDED (hres);
93014d67 98}
853b9e91 99
93014d67 100
853b9e91
CF
101BOOL CALLBACK
102output_file (HMODULE h, LPCTSTR type, LPTSTR name, LONG lparam)
93014d67 103{
608de931
CF
104 HRSRC rsrc;
105 HGLOBAL res;
106 char *data;
107 FILE *out;
108 BOOL retval = FALSE;
109
110 size_t bytes_needed;
111 if ((rsrc = FindResource (NULL, name, "FILE"))
112 && (res = LoadResource (NULL, rsrc))
20904de1 113 && (data = (char *) LockResource (res)) && (out = fopen (strlwr (name), "w+b")))
608de931
CF
114 {
115 gzFile gzf;
116 char *buffer;
117 size_t bytes = SizeofResource (NULL, rsrc);
853b9e91 118
608de931
CF
119 if (bytes != fwrite (data, 1, bytes, out))
120 printf ("Unable to write %s: %s", name, _strerror (""));
853b9e91 121
608de931
CF
122 bytes_needed = *(int *) ((char *) data + bytes - sizeof (int));
123 buffer = (char *) xmalloc (bytes_needed);
853b9e91 124
608de931
CF
125 rewind (out);
126 gzf = gzdopen (_dup (fileno (out)), "rb");
127 if (gzf && (size_t) gzread (gzf, buffer, bytes_needed) == bytes_needed)
128 {
129 gzclose (gzf);
130 if (fseek (out, 0, SEEK_SET)
131 || fwrite (buffer, 1, bytes_needed, out) != bytes_needed)
132 {
133 printf ("Unable to write decompressed file to %s: %s",
ea615d51 134 name, _strerror (""));
608de931
CF
135 }
136 else
137 retval = TRUE;
138 }
139 else
140 {
141 int errnum;
142 const char *msg = gzerror (gzf, &errnum);
143 printf ("bytes_needed = %d, ", bytes_needed);
144 printf ("Unable to decompress %s: Error #%d, %s\n", name,
ea615d51 145 errnum, msg);
608de931
CF
146 }
147 xfree (buffer);
148 fclose (out);
149 }
150 else
151 {
152 printf ("Unable to write %s: %s", name, _strerror (""));
153 }
93014d67 154
608de931
CF
155 return retval;
156}
853b9e91 157
20904de1
CF
158static int
159tarx (const char *dir, const char *fn, FILE *logfp)
160{
161 char *path, *dpath;
162 char buffer0[2049];
163 char *buffer = buffer0 + 1;
164 int hpipe[2];
165 HANDLE hin;
166 FILE *fp;
c73320de 167 int filehere;
20904de1
CF
168
169 dpath = pathcat (dir, fn);
170 path = dtoupath (dpath);
171 sprintf (buffer, "tar xvfUz \"%s\"", path);
172 xfree (path);
173 xfree (dpath);
174
175 printf ("Installing %s\n", fn);
176
177 if (_pipe (hpipe, 256, O_TEXT) == -1)
178 return 0;
179
180 hin = (HANDLE) _get_osfhandle (hpipe[1]);
181 if (xcreate_process (0, NULL, hin, hin, buffer) == 0)
182 {
183 printf ("Unable to extract \"%s\": %s", fn, _strerror (""));
184 return 0;
185 }
186 _close (hpipe[1]);
187 fp = fdopen (hpipe[0], "rt");
188
c73320de 189 filehere = files.index;
20904de1
CF
190 while (fgets (buffer, sizeof (buffer0), fp))
191 {
192 char *s = strchr (buffer, '\n');
193
194 if (s)
195 *s = '\0';
196
197 if (strchr (buffer, ':') != NULL)
198 {
199 s = buffer;
6185466b 200 fprintf (stderr, "%s\n", s);
20904de1
CF
201 }
202 else
203 {
204 if (++files.index >= files.count)
205 files.array = realloc (files.array,
68cdfc92 206 NFILE_SLOP + (files.count += NFILE_LIST));
20904de1
CF
207 s = buffer;
208 if (*s != '/')
209 *--s = '/';
210 s = files.array[files.index] = utodpath (s);
20904de1
CF
211 }
212
213 fprintf (logfp, "%s\n", s);
214 }
215 fclose (fp);
c73320de
CF
216
217 while (++filehere <= files.index)
218 (void) chmod (files.array[files.index], 0777);
219
20904de1
CF
220 return 1;
221}
222
608de931 223int
20904de1 224recurse_dirs (const char *dir, FILE *logfp)
608de931
CF
225{
226 int err = 0;
227 int retval = 0;
853b9e91 228
608de931
CF
229 char *pattern = pathcat (dir, "*");
230 if (pattern)
231 {
232 WIN32_FIND_DATA find_data;
233 HANDLE handle;
853b9e91 234
608de931
CF
235 handle = FindFirstFile (pattern, &find_data);
236 if (handle != INVALID_HANDLE_VALUE)
237 {
238 /* Recurse through all subdirectories */
239 do
240 {
241 if (strcmp (find_data.cFileName, ".") == 0
242 || strcmp (find_data.cFileName, "..") == 0)
243 continue;
853b9e91 244
608de931 245 if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY
ea615d51 246 /* && strlen(find_data.cFileName) */ )
608de931
CF
247 {
248 char *subdir = pathcat (dir, find_data.cFileName);
249 if (subdir)
250 {
20904de1 251 if (!recurse_dirs (subdir, logfp))
608de931
CF
252 {
253 xfree (subdir);
254 err = 1;
255 break;
256 }
853b9e91 257
608de931
CF
258 xfree (subdir);
259 }
260 else
261 lowmem ();
262 }
263 }
264 while (FindNextFile (handle, &find_data) && !err);
265 FindClose (handle);
266
267 /* Look for .tar.gz files */
268 if (!err)
93014d67 269 {
608de931
CF
270 xfree (pattern);
271 pattern = pathcat (dir, "*.tar.gz");
272 handle = FindFirstFile (pattern, &find_data);
273 if (handle != INVALID_HANDLE_VALUE)
274 {
275 int err = 0;
853b9e91 276
608de931
CF
277 do
278 {
608de931
CF
279 /* Skip source archives and meta-directories */
280 if (strstr (find_data.cFileName, "-src.tar.gz")
281 || strstr (find_data.cFileName, "-src-")
282 || strcmp (find_data.cFileName, ".") == 0
283 || strcmp (find_data.cFileName, "..") == 0)
284 {
285 continue;
286 }
287
20904de1 288 if (!tarx (dir, find_data.cFileName, logfp))
608de931 289 {
608de931
CF
290 err = 1;
291 break;
292 }
293 }
294 while (FindNextFile (handle, &find_data));
295 FindClose (handle);
296 }
297 if (!err)
298 retval = 1;
299 }
300 }
301
302 xfree (pattern);
303 }
304 else
305 lowmem ();
853b9e91 306
608de931 307 return retval;
93014d67 308}
853b9e91 309
853b9e91 310
608de931 311void
ea615d51 312setpath (const char *element)
608de931 313{
ea615d51 314 char *buffer = xmalloc (strlen (element) + 7);
853b9e91 315
ea615d51 316 sprintf (buffer, "PATH=%s", element);
608de931 317 putenv (buffer);
853b9e91 318
608de931
CF
319 xfree (buffer);
320}
853b9e91 321
608de931
CF
322char *
323prompt (const char *text, const char *def)
324{
325 char buffer[_MAX_PATH];
853b9e91 326
853b9e91 327
608de931
CF
328 printf ((def ? "%s? [%s] " : "%s? "), text, def);
329 fgets (buffer, sizeof (buffer), stdin);
330 buffer[strcspn (buffer, "\r\n")] = '\0';
853b9e91 331
608de931
CF
332 /* Duplicate the entered value or the default if nothing was entered. */
333 return xstrdup (strlen (buffer) ? buffer : def ? def : "");
93014d67 334}
853b9e91 335
608de931
CF
336int
337optionprompt (const char *text, SA * options)
338{
ea615d51 339 size_t n, lbound, response;
608de931 340 char buf[5];
853b9e91 341
ea615d51 342 n = 0;
853b9e91 343
608de931 344 do
93014d67 345 {
ea615d51
RP
346 char *or;
347 size_t base = n;
348 enum
349 { CONTINUE, REPEAT, ALL }
350 mode;
351
352 if (!base)
353 puts (text);
354
355 for (n = 0; n < base + SCREEN_LINES - 2 && n < options->count; ++n)
356 printf ("\t%d. %s\n", n + 1, options->array[n]);
357
358 lbound = n - (SCREEN_LINES - (base ? 2 : 3));
359 if (n < options->count)
360 {
361 mode = CONTINUE;
362 or = " or [continue]";
363 }
364 else if (options->count > SCREEN_LINES - 2)
365 {
366 mode = REPEAT;
367 or = " or [repeat]";
368 }
369 else
370 {
371 mode = ALL;
372 or = "";
373 }
374 printf ("Select an option from %d-%d%s: ", lbound, n, or);
608de931
CF
375 if (!fgets (buf, sizeof (buf), stdin))
376 continue;
853b9e91 377
ea615d51
RP
378 if (mode == CONTINUE && (!isalnum (*buf) || strchr ("cC", *buf)))
379 continue;
380 else if (mode == REPEAT && (!isalnum (*buf) || strchr ("rR", *buf)))
381 {
382 n = 0;
383 continue;
384 }
385
608de931
CF
386 response = atoi (buf);
387 }
ea615d51 388 while (response < lbound || response > n);
853b9e91 389
608de931 390 return response - 1;
93014d67 391}
853b9e91 392
608de931 393int
6f8e3b45 394geturl (HINTERNET session, const char *url, const char *file, int verbose)
608de931
CF
395{
396 DWORD type, size;
397 int authenticated = 0;
398 int retval = 0;
399 HINTERNET connect;
6f8e3b45 400 int tries = 20;
93014d67 401
6f8e3b45
CF
402 if (verbose)
403 {
404 printf ("Connecting to ftp site...");
405 fflush (stdout);
406 }
407 for (tries = 1; tries <= 20; tries++)
608de931
CF
408 {
409 connect =
410 InternetOpenUrl (session, url, NULL, 0,
411 INTERNET_FLAG_DONT_CACHE |
412 INTERNET_FLAG_KEEP_CONNECTION |
413 INTERNET_FLAG_RELOAD, 0);
6f8e3b45
CF
414 if (connect)
415 break;
416 if (!verbose || tries == 1)
417 /* nothing */;
418 else if (tries > 2)
419 printf ("\rConnecting to ftp site...(try %d) \b\b", tries);
420 else
421 printf ("\rConnecting to ftp site...(try %d)", tries);
608de931 422 }
608de931
CF
423
424 if (!connect)
6f8e3b45
CF
425 {
426 puts ("\nCouldn't connect to ftp site."); fflush (stdout);
427 winerror ();
428 }
608de931 429 else
6f8e3b45
CF
430 {
431 if (verbose)
432 {
433 if (tries > 1)
434 printf ("\rConnecting to ftp site... \b\b\b\b\b\b\b\b");
435 printf ("Done.\n"); fflush (stdout);
436 }
437 while (!authenticated)
438 {
439 size = sizeof (type);
440 if (!InternetQueryOption
441 (connect, INTERNET_OPTION_HANDLE_TYPE, &type, &size))
608de931 442 {
6f8e3b45
CF
443 winerror ();
444 return 0;
445 }
446 else
447 switch (type)
448 {
449 case INTERNET_HANDLE_TYPE_HTTP_REQUEST:
450 case INTERNET_HANDLE_TYPE_CONNECT_HTTP:
451 size = sizeof (DWORD);
452 if (!HttpQueryInfo
453 (connect, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER,
454 &type, &size, NULL))
455 {
456 winerror ();
457 return 0;
458 }
459 else if (type == HTTP_STATUS_PROXY_AUTH_REQ)
460 {
461 DWORD len;
93014d67 462
6f8e3b45
CF
463 if (!InternetQueryDataAvailable (connect, &len, 0, 0))
464 {
465 winerror ();
466 return 0;
467 }
468 else
469 {
470 char *user, *password;
471
472 /* Have to read any pending data, WININET peculiarity. */
473 char *buffer = xmalloc (len);
474 do
475 {
476 InternetReadFile (connect, buffer, len, &size);
477 }
478 while (size);
479 xfree (buffer);
480
481 puts ("Proxy authentication is required.\n");
482
483 user = prompt ("Proxy username", NULL);
484 if (!InternetSetOption
485 (connect, INTERNET_OPTION_PROXY_USERNAME, user,
486 strlen (user)))
487 {
488 xfree (user);
489 winerror ();
490 return 0;
491 }
492 else
493 {
494 xfree (user);
495 password = prompt ("Proxy password", NULL);
496 if (!InternetSetOption
497 (connect, INTERNET_OPTION_PROXY_PASSWORD,
498 password,
499 strlen (password))
500 || !HttpSendRequest (connect, NULL, 0, NULL, 0))
501 {
502 xfree (password);
503 winerror ();
504 return 0;
505 }
506 xfree (password);
507 }
508 }
509 }
510 else if (type != HTTP_STATUS_OK)
511 {
512 printf ("Error retrieving \"%s\".\n", url);
513 return 0;
514 }
515 else
516 authenticated = 1;
517 break;
93014d67 518
6f8e3b45
CF
519 default:
520 authenticated = 1;
521 break;
522 }
523
524 /* Now that authentication is complete read the file. */
525 if (!InternetQueryDataAvailable (connect, &size, 0, 0))
526 winerror ();
527 else
528 {
529 char *buffer = xmalloc (size);
93014d67 530
6f8e3b45
CF
531 FILE *out = fopen (file, "wb");
532 if (!out)
533 printf ("Unable to open \"%s\" for output: %s\n", file,
534 _strerror (""));
535 else
536 {
537 for (;;)
538 {
539 DWORD readbytes;
608de931 540
6f8e3b45
CF
541 if (!InternetReadFile (connect, buffer, size, &readbytes))
542 winerror ();
543 else if (!readbytes)
608de931 544 {
6f8e3b45
CF
545 retval = 1;
546 break;
608de931 547 }
6f8e3b45 548 else if (fwrite (buffer, 1, readbytes, out) != readbytes)
608de931 549 {
6f8e3b45
CF
550 printf ("Error writing \"%s\": %s\n", file,
551 _strerror (""));
552 break;
608de931
CF
553 }
554 }
6f8e3b45 555 fclose (out);
608de931 556 }
6f8e3b45 557 xfree (buffer);
608de931 558 }
6f8e3b45
CF
559 InternetCloseHandle (connect);
560 }
561 }
853b9e91 562
608de931
CF
563 return retval;
564}
853b9e91 565
608de931
CF
566char *
567findhref (char *buffer)
568{
569 char *ref = strstr (buffer, "href=");
853b9e91 570
608de931
CF
571 if (!ref)
572 ref = strstr (buffer, "HREF=");
853b9e91 573
608de931 574 if (ref)
93014d67 575 {
608de931
CF
576 int len;
577 ref += ref[5] == '"' ? 6 : 5;
853b9e91 578
608de931 579 len = strcspn (ref, "\" >");
853b9e91 580
608de931
CF
581 ref[len] = '\0';
582 }
853b9e91 583
608de931
CF
584 return ref;
585}
853b9e91 586
608de931
CF
587int
588processdirlisting (HINTERNET session, const char *urlbase, const char *file)
589{
590 int retval;
591 char buffer[256];
6f8e3b45 592 static enum {UNKNOWN, ALWAYS, NEVER} download_when = {UNKNOWN};
853b9e91 593
c1246750 594 FILE *in = fopen (file, "rt");
853b9e91 595
608de931
CF
596 while (fgets (buffer, sizeof (buffer), in))
597 {
598 char *ref = findhref (buffer);
853b9e91 599
608de931 600 if (ref)
93014d67 601 {
608de931
CF
602 char url[256];
603 DWORD urlspace = sizeof (url);
853b9e91 604
608de931
CF
605 if (!InternetCombineUrl
606 (urlbase, ref, url, &urlspace,
607 ICU_BROWSER_MODE | ICU_ENCODE_SPACES_ONLY | ICU_NO_META))
608 {
609 printf ("Unable to download from %s", ref);
610 winerror ();
611 }
612 else if (ref[strlen (ref) - 1] == '/')
613 {
614 if (strcmp (url + strlen (url) - 2, "./") != 0)
615 downloaddir (session, url);
616 }
617 else if (strstr (url, ".tar.gz") && !strstr (url, "-src"))
618 {
619 int download = 0;
620 char *filename = strrchr (url, '/') + 1;
36dc5fc8 621 if (download_when == ALWAYS || _access (filename, 0) == -1)
6f8e3b45
CF
622 download = 1;
623 else
608de931
CF
624 {
625 char text[_MAX_PATH];
626 char *answer;
853b9e91 627
36dc5fc8
CF
628 if (download_when == NEVER)
629 answer = "N";
630 else
631 {
632 sprintf (text, "Replace %s from the net (ynAN)", filename);
633 answer = prompt (text, "y");
634 }
853b9e91 635
608de931
CF
636 if (answer)
637 {
6f8e3b45
CF
638 switch (*answer)
639 {
640 case 'a':
641 case 'A':
642 download_when = ALWAYS;
35d18861 643 /* purposely fall through */
6f8e3b45
CF
644 case 'y':
645 case 'Y':
646 download = 1;
35d18861 647 break;
6f8e3b45
CF
648 case 'N':
649 download_when = NEVER;
36dc5fc8 650 fprintf (stderr, "Skipping %s\n", filename);
6f8e3b45
CF
651 case 'n':
652 default:
653 download = 0;
654 }
608de931
CF
655 xfree (answer);
656 }
657 }
853b9e91 658
608de931
CF
659 if (download)
660 {
36dc5fc8 661 printf ("Downloading: %s...", filename);
608de931 662 fflush (stdout);
6f8e3b45 663 if (geturl (session, url, filename, 0))
608de931
CF
664 {
665 printf ("Done.\n");
666 }
667 else
668 {
6f8e3b45 669 printf ("\nUnable to retrieve %s\n", url);
608de931
CF
670 }
671 }
672 }
673 }
674 }
853b9e91 675
6f8e3b45 676 fflush (stdout);
608de931 677 retval = feof (in);
853b9e91 678
608de931 679 fclose (in);
853b9e91 680
608de931 681 return retval;
93014d67 682}
853b9e91 683
608de931
CF
684char *
685tmpfilename ()
686{
687 return xstrdup (tmpnam (NULL));
93014d67 688}
853b9e91 689
608de931
CF
690int
691downloaddir (HINTERNET session, const char *url)
692{
693 int retval = 0;
694 char *file = tmpfilename ();
93014d67 695
6f8e3b45 696 if (geturl (session, url, file, 1))
608de931
CF
697 retval = processdirlisting (session, url, file);
698 xfree (file);
93014d67 699
608de931 700 return retval;
93014d67
CF
701}
702
703
ea615d51 704HINTERNET opensession ()
93014d67 705{
608de931
CF
706 return InternetOpen ("Cygwin Setup", INTERNET_OPEN_TYPE_PRECONFIG, NULL,
707 NULL, 0);
708}
853b9e91 709
608de931
CF
710int
711downloadfrom (const char *url)
712{
713 int retval = 0;
853b9e91 714
608de931 715 HINTERNET session = opensession ();
853b9e91 716
608de931
CF
717 if (!session)
718 winerror ();
719 else
720 {
721 char *file = tmpfilename ();
853b9e91 722
6f8e3b45 723 if (geturl (session, url, file, 1))
608de931 724 retval = processdirlisting (session, url, file);
853b9e91 725
608de931 726 xfree (file);
93014d67 727
608de931
CF
728 InternetCloseHandle (session);
729 }
93014d67 730
608de931 731 return retval;
93014d67
CF
732}
733
608de931
CF
734int
735reverse_sort (const void *arg1, const void *arg2)
736{
737 return -strcmp (*(char **) arg1, *(char **) arg2);
738}
93014d67 739
608de931 740int
6f8e3b45 741create_uninstall (const char *wd, const char *folder, const char *shellscut,
20904de1 742 const char *shortcut)
93014d67 743{
608de931
CF
744 int retval = 0;
745 char buffer[MAX_PATH];
608de931 746 clock_t start;
6f8e3b45
CF
747 HINSTANCE lib;
748
20904de1 749 printf ("Creating the uninstall file...");
608de931 750 fflush (stdout);
20904de1 751 if (files.array)
608de931 752 {
20904de1
CF
753 size_t n;
754 FILE *uninst;
68cdfc92
CF
755 char cwd[MAX_PATH];
756 char *uninstfile;
853b9e91 757
68cdfc92
CF
758 getcwd (cwd, sizeof (cwd));
759 uninstfile = pathcat (cwd, "uninst.bat");
760 uninst = fopen (uninstfile, "wt");
853b9e91 761
20904de1
CF
762 if (uninst)
763 {
20904de1 764 unsigned percent = 0;
68cdfc92
CF
765 struct _stat st;
766
767 files.array[++files.index] = pathcat (cwd, "bin\\cygwin.bat");
768 files.count = files.index + 1;
769 qsort (files.array, files.count, sizeof (char *), reverse_sort);
20904de1 770
20904de1
CF
771 fprintf (uninst,
772 "@echo off\n" "%c:\n" "cd \"%s\"\n", *cwd, cwd);
773 for (n = 0; n < files.count; ++n)
608de931 774 {
20904de1 775 char *dpath;
93014d67 776
20904de1
CF
777 if (n && !strcmp (files.array[n], files.array[n - 1]))
778 continue;
93014d67 779
20904de1 780 dpath = files.array[n];
93014d67 781
68cdfc92 782 if (_stat (dpath, &st) == 0 && st.st_mode & _S_IFDIR)
20904de1
CF
783 fprintf (uninst, "rmdir \"%s\"\n", dpath);
784 else
608de931 785 {
20904de1
CF
786 if (access (dpath, 6) != 0)
787 fprintf (uninst, "attrib -r \"%s\"\n", dpath);
788 fprintf (uninst, "del \"%s\"\n", dpath);
608de931
CF
789 }
790 }
20904de1
CF
791 fprintf (uninst,
792 "del \"%s\"\n"
793 "del \"%s\"\n"
794 "rmdir \"%s\"\n"
68cdfc92
CF
795 "del %s\n", shortcut, shellscut,
796 folder, uninstfile);
20904de1
CF
797 fclose (uninst);
798
68cdfc92 799 create_shortcut (uninstfile, shortcut);
608de931 800 }
20904de1
CF
801 sa_cleanup (&files);
802 retval = 1;
608de931 803 }
853b9e91 804
608de931
CF
805 if (lib)
806 FreeLibrary (lib);
853b9e91 807
ade98143 808 printf ("Done.\n");
608de931
CF
809 return retval;
810}
853b9e91 811
93014d67 812
608de931
CF
813/* Writes the startup batch file. */
814int
20904de1 815do_start_menu (const char *root)
608de931
CF
816{
817 FILE *batch;
6f8e3b45 818 char *batch_name = pathcat (root, "bin\\cygwin.bat");
608de931 819 int retval = 0;
853b9e91 820
608de931
CF
821 /* Create the batch file for the start menu. */
822 if (batch_name)
823 {
c1246750 824 batch = fopen (batch_name, "wt");
608de931
CF
825 if (batch)
826 {
827 LPITEMIDLIST progfiles;
828 char pfilespath[_MAX_PATH];
829 char *folder;
830
831 fprintf (batch,
832 "@echo off\n"
4b40edd0 833 "SET MAKE_MODE=unix\n"
68cdfc92 834 "SET PATH=%s\\bin;%s\\usr\\local\\bin;%%PATH%%\n"
608de931
CF
835 "bash\n", root, root);
836 fclose (batch);
837
838 /* Create a shortcut to the batch file */
839 SHGetSpecialFolderLocation (NULL, CSIDL_PROGRAMS, &progfiles);
840 SHGetPathFromIDList (progfiles, pfilespath);
841
842 folder = pathcat (pfilespath, "Cygnus Solutions");
843 if (folder)
844 {
845 char *shortcut;
846 mkdir (folder); /* Ignore the result, it may exist. */
853b9e91 847
608de931
CF
848 shortcut = pathcat (folder, "Cygwin 1.1.0.lnk");
849 if (shortcut)
850 {
ea615d51
RP
851 char *cmdline;
852 OSVERSIONINFO verinfo;
853 verinfo.dwOSVersionInfoSize = sizeof (verinfo);
854
855 /* If we are running Win9x, build a command line. */
856 GetVersionEx (&verinfo);
857 if (verinfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
858 cmdline = xstrdup (batch_name);
859 else
860 {
861 char *pccmd;
862 char windir[MAX_PATH];
863 GetWindowsDirectory (windir, sizeof (windir));
864
865 pccmd = pathcat (windir, COMMAND9X);
866 cmdline =
867 xmalloc (strlen (pccmd) + strlen (batch_name) + 1);
868 strcat (strcpy (cmdline, pccmd), batch_name);
869 xfree (pccmd);
870 }
871
872 if (create_shortcut (cmdline, shortcut))
608de931
CF
873 {
874 char *uninstscut =
ea615d51 875 pathcat (folder, "Uninstall Cygwin 1.1.0.lnk");
608de931
CF
876 if (uninstscut)
877 {
878 if (create_uninstall
20904de1 879 (wd, folder, shortcut, uninstscut))
608de931
CF
880 retval = 1;
881 xfree (uninstscut);
882 }
883 }
ea615d51 884 xfree (cmdline);
608de931
CF
885 xfree (shortcut);
886 }
887 xfree (folder);
888 }
889 }
890
891 xfree (batch_name);
892 }
893 return retval;
894}
853b9e91 895
608de931
CF
896char *
897getdownloadsource ()
898{
899 char *retval = NULL;
900 HINTERNET session = opensession ();
901 char *filename = tmpfilename ();
902
903 if (!session)
904 winerror ();
905 else if (!geturl
906 (session, "http://sourceware.cygnus.com/cygwin/mirrors.html",
6f8e3b45 907 filename, 1))
608de931
CF
908 fputs ("Unable to retrieve the list of cygwin mirrors.\n", stderr);
909 else
910 {
c1246750 911 FILE *in = fopen (filename, "rt");
853b9e91 912
608de931
CF
913 if (!in)
914 fprintf (stderr, "Unable to open %s for input.\n", filename);
915 else
916 {
917 size_t option;
918 int ready4urls = 0;
919 char buf[256];
ea615d51 920 SA urls, names; /* These must stay sync'd. */
853b9e91 921
608de931 922 sa_init (&urls);
ea615d51 923 sa_init (&names);
853b9e91 924
608de931
CF
925 while (fgets (buf, sizeof (buf), in))
926 {
927 if (!ready4urls)
928 {
929 if (strstr (buf, "Mirror Sites:"))
930 ready4urls = 1;
931 }
932 else
933 {
934 char *ref = findhref (buf);
93014d67 935
608de931
CF
936 if (ref)
937 {
938 size_t len = strlen (ref);
853b9e91 939
608de931
CF
940 if (ref[len - 1] == '/')
941 {
ea615d51 942 char *name;
608de931
CF
943 char *url = xmalloc (len + 13);
944
ea615d51 945 strcat (strcpy (url, ref), DOWNLOAD_SUBDIR);
608de931 946 sa_add (&urls, url);
ea615d51
RP
947
948 /* Get just the sites name. */
949 name = strstr (url, "//");
950 if (name)
951 name += 2;
952 else
953 name = url;
954 *strchr (name, '/') = '\0';
955 sa_add (&names, url);
956
608de931
CF
957 xfree (url);
958 }
959 }
960 }
961 }
962
963 sa_add (&urls, "Other");
ea615d51 964 sa_add (&names, "Other");
608de931 965 option =
ea615d51 966 optionprompt ("Select a download location close to you:", &names);
608de931
CF
967 if (option == urls.count - 1)
968 retval = prompt ("Download url", NULL);
969 else
970 retval = xstrdup (urls.array[option]);
93014d67 971
608de931 972 sa_cleanup (&urls);
ea615d51 973 sa_cleanup (&names);
608de931
CF
974 }
975 }
976 unlink (filename);
853b9e91 977
608de931
CF
978 return retval;
979}
853b9e91 980
93014d67 981
608de931
CF
982/* Basically a mkdir -p /somedir function. */
983void
984mkdirp (const char *dir)
985{
986 if (mkdir (dir) == -1 && errno != EEXIST)
987 {
988 char *parent = strdup (dir);
989 char *slash = strrchr (parent, '\\');
853b9e91 990
608de931
CF
991 if (slash)
992 {
993 *slash = '\0';
994 mkdirp (parent);
995 }
93014d67 996
608de931 997 xfree (parent);
93014d67 998
608de931
CF
999 mkdir (dir);
1000 }
93014d67
CF
1001}
1002
1003
608de931 1004/* This routine assumes that the cwd is the root directory. */
853b9e91 1005int
608de931
CF
1006mkmount (const char *mountexedir, const char *root, const char *dospath,
1007 const char *unixpath, int force)
93014d67 1008{
608de931
CF
1009 char *mount, *bslashed, *fulldospath, *p;
1010 char buffer[1024];
853b9e91 1011
20904de1
CF
1012 if (*root == '\0')
1013 fulldospath = xstrdup (dospath);
1014 else
1015 {
1016 /* Make sure the mount point exists. */
1017 mount = utodpath (unixpath);
1018 mkdirp (mount);
1019 xfree (mount);
1020 fulldospath = pathcat (root, dospath);
1021 }
853b9e91 1022
608de931 1023 /* Make sure the target path exists. */
608de931 1024 mkdirp (fulldospath);
853b9e91 1025
608de931
CF
1026 /* Mount the directory. */
1027 mount = pathcat (mountexedir, "mount");
1028 sprintf (buffer, "%s %s -b \"%s\" %s", mount, force ? "-f" : "",
ea615d51 1029 fulldospath, unixpath);
608de931
CF
1030 xfree (mount);
1031 xfree (fulldospath);
93014d67 1032
ea615d51 1033 return xsystem (buffer) == 0;
608de931 1034}
853b9e91 1035
608de931
CF
1036int
1037main ()
1038{
1039 int retval = 1; /* Default to error code */
20904de1
CF
1040 clock_t start;
1041
6f8e3b45
CF
1042 puts ( "\n\n\n\n"
1043"This is the Cygwin setup utility.\n\n"
1044"Use this program to install the latest version of the Cygwin Utilities\n"
1045"from the Internet.\n\n"
1046"Alternatively, if you already have already downloaded the appropriate files\n"
1047"to the current directory, this program can use those as the basis for your\n"
1048"installation.\n");
1049
20904de1 1050 start = clock ();
608de931 1051 if (!EnumResourceNames (NULL, "FILE", output_file, 0))
93014d67 1052 {
608de931
CF
1053 winerror ();
1054 }
1055 else
1056 {
608de931
CF
1057 char *defroot, *update;
1058 char *root;
1059 int done;
1060 HKEY cu = NULL, lm = NULL;
1061
ea615d51
RP
1062 wd = _getcwd (NULL, 0);
1063 setpath (wd);
608de931
CF
1064
1065 /* Begin prompting user for setup requirements. */
1066 printf ("Press <enter> to accept the default value.\n");
1067
ea615d51
RP
1068 /* If some Cygnus software has been installed, assume there is a root
1069 mount in the registry. Otherwise use C:\cygwin for the default root
608de931
CF
1070 directory. */
1071 if (RegOpenKey (HKEY_CURRENT_USER, CYGNUS_KEY, &cu) == ERROR_SUCCESS
1072 || RegOpenKey (HKEY_LOCAL_MACHINE, CYGNUS_KEY,
1073 &lm) == ERROR_SUCCESS)
1074 {
1075 defroot = utodpath ("/");
1076 if (cu)
1077 RegCloseKey (cu);
1078 if (lm)
1079 RegCloseKey (lm);
1080 }
1081 else
1082 defroot = xstrdup (DEF_ROOT);
853b9e91 1083
ea615d51 1084 /* Get the root directory and warn the user if there are any spaces in
608de931
CF
1085 the path. */
1086 for (done = 0; !done;)
93014d67 1087 {
608de931
CF
1088 root = prompt ("Root directory", defroot);
1089 if (strchr (root, ' '))
93014d67 1090 {
608de931
CF
1091 char *temp;
1092 temp =
1093 prompt
93014d67 1094 ("Using spaces in the root directory path may cause problems."
608de931
CF
1095 " Continue anyway", "no");
1096 if (toupper (*temp) == 'Y')
1097 done = 1;
1098 xfree (temp);
1099 }
93014d67 1100 else
608de931
CF
1101 done = 1;
1102 }
1103 xfree (defroot);
853b9e91 1104
608de931
CF
1105 /* Create the root directory. */
1106 mkdir (root); /* Ignore any return value since it may
93014d67 1107 already exist. */
20904de1 1108 mkmount (wd, "", root, "/", 1);
853b9e91 1109
608de931 1110 update =
6f8e3b45
CF
1111 prompt ("Install from the current directory (d) or from the Internet (i)", "i");
1112 if (toupper (*update) == 'I')
93014d67 1113 {
608de931 1114 char *dir = getdownloadsource ();
853b9e91 1115
608de931 1116 if (dir)
93014d67 1117 {
608de931
CF
1118 downloadfrom (dir);
1119 xfree (dir);
1120 }
1121 }
1122 xfree (update);
1123
ea615d51 1124 /* Make the root directory the current directory so that recurse_dirs
608de931
CF
1125 will * extract the packages into the correct path. */
1126 if (chdir (root) == -1)
93014d67 1127 {
608de931 1128 printf ("Unable to make \"%s\" the current directory: %s\n",
ea615d51 1129 root, _strerror (""));
608de931 1130 }
93014d67 1131 else
93014d67 1132 {
608de931 1133 char *logpath = pathcat (wd, "setup.log");
853b9e91 1134
608de931 1135 if (logpath)
93014d67 1136 {
c1246750 1137 FILE *logfp = fopen (logpath, "w+t");
4b40edd0
CF
1138
1139 if (logfp == NULL)
1140 {
1141 fprintf (stderr, "Unable to open log file '%s' for writing - %s\n",
1142 logpath, _strerror (""));
1143 exit (1);
1144 }
1145
608de931 1146 _chdrive (toupper (*root) - 'A' + 1);
853b9e91 1147
608de931 1148 /* Make /bin point to /usr/bin and /lib point to /usr/lib. */
6f8e3b45
CF
1149 mkmount (wd, root, "bin", "/usr/bin", 1);
1150 mkmount (wd, root, "lib", "/usr/lib", 1);
853b9e91 1151
20904de1 1152 files.count = NFILE_LIST;
68cdfc92 1153 files.array = calloc (sizeof (char *), NFILE_LIST + NFILE_SLOP);
20904de1
CF
1154 files.index = -1;
1155
ea615d51 1156 /* Extract all of the packages that are stored with setup or in
608de931 1157 subdirectories of its location */
20904de1 1158 if (recurse_dirs (wd, logfp))
93014d67 1159 {
608de931
CF
1160 char *mount;
1161 char buffer[1024];
1162
1163 /* Mount the new root directory. */
1164 mount = pathcat (wd, "mount");
1165 sprintf (buffer, "%s -f -b \"%s\" /", mount, root);
1166 xfree (mount);
ea615d51 1167 if (xsystem (buffer))
93014d67 1168 {
608de931 1169 printf
93014d67 1170 ("Unable to mount \"%s\" as the root directory: %s",
608de931
CF
1171 root, _strerror (""));
1172 }
93014d67 1173 else
93014d67 1174 {
68cdfc92 1175 char **a;
608de931 1176 /* bash expects a /tmp */
93014d67 1177 char *tmpdir = pathcat (root, "tmp");
853b9e91 1178
608de931 1179 if (tmpdir)
93014d67 1180 {
68cdfc92 1181 files.array[++files.index] = tmpdir;
608de931 1182 mkdir (tmpdir); /* Ignore the result, it may
93014d67 1183 exist. */
608de931 1184 }
853b9e91 1185
68cdfc92
CF
1186 files.array[++files.index] = pathcat (root, "usr\\local");
1187 files.array[++files.index] = pathcat (root, "usr\\local\\bin");
1188 files.array[++files.index] = pathcat (root, "usr\\local\\lib");
1189 mkdirp (files.array[files.index]);
1190 mkdir (files.array[files.index - 1]);
1191
20904de1 1192 if (do_start_menu (root))
608de931 1193 retval = 0; /* Everything worked return
93014d67 1194 successful code */
608de931
CF
1195 }
1196 }
853b9e91 1197
4b40edd0 1198 fclose (logfp);
608de931
CF
1199 xfree (logpath);
1200 }
1201 }
853b9e91 1202
608de931 1203 xfree (root);
93014d67 1204
608de931
CF
1205 chdir (wd);
1206 _chdrive (toupper (*wd) - 'A' + 1);
1207 xfree (wd);
1208 }
20904de1 1209
c73320de 1210 printf ("\nInstallation took %.0f seconds.\n",
20904de1
CF
1211 (double) (clock () - start) / CLK_TCK);
1212
608de931 1213 return retval;
93014d67 1214}
This page took 0.157463 seconds and 5 git commands to generate.