]> cygwin.com Git - cygwin-apps/setup.git/blob - setup.c
* setup.c (processdirlisting): Make "N" option a little less aggressive.
[cygwin-apps/setup.git] / setup.c
1 #include <windows.h>
2 #include <wininet.h>
3 #include <assert.h>
4 #include <ctype.h>
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
17 #include "setup.h"
18 #include "strarry.h"
19 #include "zlib/zlib.h"
20
21 #define CYGNUS_KEY "Software\\Cygnus Solutions"
22 #define DEF_ROOT "C:\\cygwin"
23 #define DOWNLOAD_SUBDIR "latest"
24 #define SCREEN_LINES 25
25 #define COMMAND9X "command.com /E:4096 /c "
26
27 #ifndef NFILE_LIST
28 #define NFILE_LIST 10000
29 #endif
30
31 #ifndef NFILE_SLOP
32 #define NFILE_SLOP 20
33 #endif
34
35 char *wd;
36
37 int downloaddir (HINTERNET session, const char *url);
38
39 static SA files = {NULL, 0, 0};
40
41 int
42 create_shortcut (const char *target, const char *shortcut)
43 {
44 HRESULT hres;
45 IShellLink *sl;
46 char *path, *args;
47
48 if (!SUCCEEDED (CoInitialize (NULL)))
49 return 0;
50
51 hres =
52 CoCreateInstance (&CLSID_ShellLink, NULL,
53 CLSCTX_INPROC_SERVER, &IID_IShellLink, (LPVOID *) & sl);
54 if (SUCCEEDED (hres))
55 {
56 IPersistFile *pf;
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 = "";
74
75 sl->lpVtbl->SetPath (sl, path);
76 sl->lpVtbl->SetArguments (sl, args);
77 xfree (path);
78
79 hres = sl->lpVtbl->QueryInterface (sl, &IID_IPersistFile, &pf);
80
81 if (SUCCEEDED (hres))
82 {
83 WCHAR widepath[_MAX_PATH];
84
85 // Ensure that the string is Unicode.
86 MultiByteToWideChar (CP_ACP, 0, shortcut, -1, widepath, MAX_PATH);
87
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 }
94
95 CoUninitialize ();
96
97 return SUCCEEDED (hres);
98 }
99
100
101 BOOL CALLBACK
102 output_file (HMODULE h, LPCTSTR type, LPTSTR name, LONG lparam)
103 {
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))
113 && (data = (char *) LockResource (res)) && (out = fopen (strlwr (name), "w+b")))
114 {
115 gzFile gzf;
116 char *buffer;
117 size_t bytes = SizeofResource (NULL, rsrc);
118
119 if (bytes != fwrite (data, 1, bytes, out))
120 printf ("Unable to write %s: %s", name, _strerror (""));
121
122 bytes_needed = *(int *) ((char *) data + bytes - sizeof (int));
123 buffer = (char *) xmalloc (bytes_needed);
124
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",
134 name, _strerror (""));
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,
145 errnum, msg);
146 }
147 xfree (buffer);
148 fclose (out);
149 }
150 else
151 {
152 printf ("Unable to write %s: %s", name, _strerror (""));
153 }
154
155 return retval;
156 }
157
158 static int
159 tarx (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;
167 int filehere;
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
189 filehere = files.index;
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;
200 fprintf (stderr, "%s\n", s);
201 }
202 else
203 {
204 if (++files.index >= files.count)
205 files.array = realloc (files.array,
206 NFILE_SLOP + (files.count += NFILE_LIST));
207 s = buffer;
208 if (*s != '/')
209 *--s = '/';
210 s = files.array[files.index] = utodpath (s);
211 }
212
213 fprintf (logfp, "%s\n", s);
214 }
215 fclose (fp);
216
217 while (++filehere <= files.index)
218 (void) chmod (files.array[files.index], 0777);
219
220 return 1;
221 }
222
223 int
224 recurse_dirs (const char *dir, FILE *logfp)
225 {
226 int err = 0;
227 int retval = 0;
228
229 char *pattern = pathcat (dir, "*");
230 if (pattern)
231 {
232 WIN32_FIND_DATA find_data;
233 HANDLE handle;
234
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;
244
245 if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY
246 /* && strlen(find_data.cFileName) */ )
247 {
248 char *subdir = pathcat (dir, find_data.cFileName);
249 if (subdir)
250 {
251 if (!recurse_dirs (subdir, logfp))
252 {
253 xfree (subdir);
254 err = 1;
255 break;
256 }
257
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)
269 {
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;
276
277 do
278 {
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
288 if (!tarx (dir, find_data.cFileName, logfp))
289 {
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 ();
306
307 return retval;
308 }
309
310
311 void
312 setpath (const char *element)
313 {
314 char *buffer = xmalloc (strlen (element) + 7);
315
316 sprintf (buffer, "PATH=%s", element);
317 putenv (buffer);
318
319 xfree (buffer);
320 }
321
322 char *
323 prompt (const char *text, const char *def)
324 {
325 char buffer[_MAX_PATH];
326
327
328 printf ((def ? "%s? [%s] " : "%s? "), text, def);
329 fgets (buffer, sizeof (buffer), stdin);
330 buffer[strcspn (buffer, "\r\n")] = '\0';
331
332 /* Duplicate the entered value or the default if nothing was entered. */
333 return xstrdup (strlen (buffer) ? buffer : def ? def : "");
334 }
335
336 int
337 optionprompt (const char *text, SA * options)
338 {
339 size_t n, lbound, response;
340 char buf[5];
341
342 n = 0;
343
344 do
345 {
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);
375 if (!fgets (buf, sizeof (buf), stdin))
376 continue;
377
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
386 response = atoi (buf);
387 }
388 while (response < lbound || response > n);
389
390 return response - 1;
391 }
392
393 int
394 geturl (HINTERNET session, const char *url, const char *file, int verbose)
395 {
396 DWORD type, size;
397 int authenticated = 0;
398 int retval = 0;
399 HINTERNET connect;
400 int tries = 20;
401
402 if (verbose)
403 {
404 printf ("Connecting to ftp site...");
405 fflush (stdout);
406 }
407 for (tries = 1; tries <= 20; tries++)
408 {
409 connect =
410 InternetOpenUrl (session, url, NULL, 0,
411 INTERNET_FLAG_DONT_CACHE |
412 INTERNET_FLAG_KEEP_CONNECTION |
413 INTERNET_FLAG_RELOAD, 0);
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);
422 }
423
424 if (!connect)
425 {
426 puts ("\nCouldn't connect to ftp site."); fflush (stdout);
427 winerror ();
428 }
429 else
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))
442 {
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;
462
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;
518
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);
530
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;
540
541 if (!InternetReadFile (connect, buffer, size, &readbytes))
542 winerror ();
543 else if (!readbytes)
544 {
545 retval = 1;
546 break;
547 }
548 else if (fwrite (buffer, 1, readbytes, out) != readbytes)
549 {
550 printf ("Error writing \"%s\": %s\n", file,
551 _strerror (""));
552 break;
553 }
554 }
555 fclose (out);
556 }
557 xfree (buffer);
558 }
559 InternetCloseHandle (connect);
560 }
561 }
562
563 return retval;
564 }
565
566 char *
567 findhref (char *buffer)
568 {
569 char *ref = strstr (buffer, "href=");
570
571 if (!ref)
572 ref = strstr (buffer, "HREF=");
573
574 if (ref)
575 {
576 int len;
577 ref += ref[5] == '"' ? 6 : 5;
578
579 len = strcspn (ref, "\" >");
580
581 ref[len] = '\0';
582 }
583
584 return ref;
585 }
586
587 int
588 processdirlisting (HINTERNET session, const char *urlbase, const char *file)
589 {
590 int retval;
591 char buffer[256];
592 static enum {UNKNOWN, ALWAYS, NEVER} download_when = {UNKNOWN};
593
594 FILE *in = fopen (file, "rt");
595
596 while (fgets (buffer, sizeof (buffer), in))
597 {
598 char *ref = findhref (buffer);
599
600 if (ref)
601 {
602 char url[256];
603 DWORD urlspace = sizeof (url);
604
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;
621 if (download_when == ALWAYS || _access (filename, 0) == -1)
622 download = 1;
623 else
624 {
625 char text[_MAX_PATH];
626 char *answer;
627
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 }
635
636 if (answer)
637 {
638 switch (*answer)
639 {
640 case 'a':
641 case 'A':
642 download_when = ALWAYS;
643 /* purposely fall through */
644 case 'y':
645 case 'Y':
646 download = 1;
647 break;
648 case 'N':
649 download_when = NEVER;
650 fprintf (stderr, "Skipping %s\n", filename);
651 case 'n':
652 default:
653 download = 0;
654 }
655 xfree (answer);
656 }
657 }
658
659 if (download)
660 {
661 printf ("Downloading: %s...", filename);
662 fflush (stdout);
663 if (geturl (session, url, filename, 0))
664 {
665 printf ("Done.\n");
666 }
667 else
668 {
669 printf ("\nUnable to retrieve %s\n", url);
670 }
671 }
672 }
673 }
674 }
675
676 fflush (stdout);
677 retval = feof (in);
678
679 fclose (in);
680
681 return retval;
682 }
683
684 char *
685 tmpfilename ()
686 {
687 return xstrdup (tmpnam (NULL));
688 }
689
690 int
691 downloaddir (HINTERNET session, const char *url)
692 {
693 int retval = 0;
694 char *file = tmpfilename ();
695
696 if (geturl (session, url, file, 1))
697 retval = processdirlisting (session, url, file);
698 xfree (file);
699
700 return retval;
701 }
702
703
704 HINTERNET opensession ()
705 {
706 return InternetOpen ("Cygwin Setup", INTERNET_OPEN_TYPE_PRECONFIG, NULL,
707 NULL, 0);
708 }
709
710 int
711 downloadfrom (const char *url)
712 {
713 int retval = 0;
714
715 HINTERNET session = opensession ();
716
717 if (!session)
718 winerror ();
719 else
720 {
721 char *file = tmpfilename ();
722
723 if (geturl (session, url, file, 1))
724 retval = processdirlisting (session, url, file);
725
726 xfree (file);
727
728 InternetCloseHandle (session);
729 }
730
731 return retval;
732 }
733
734 int
735 reverse_sort (const void *arg1, const void *arg2)
736 {
737 return -strcmp (*(char **) arg1, *(char **) arg2);
738 }
739
740 int
741 create_uninstall (const char *wd, const char *folder, const char *shellscut,
742 const char *shortcut)
743 {
744 int retval = 0;
745 char buffer[MAX_PATH];
746 clock_t start;
747 HINSTANCE lib;
748
749 printf ("Creating the uninstall file...");
750 fflush (stdout);
751 if (files.array)
752 {
753 size_t n;
754 FILE *uninst;
755 char cwd[MAX_PATH];
756 char *uninstfile;
757
758 getcwd (cwd, sizeof (cwd));
759 uninstfile = pathcat (cwd, "uninst.bat");
760 uninst = fopen (uninstfile, "wt");
761
762 if (uninst)
763 {
764 unsigned percent = 0;
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);
770
771 fprintf (uninst,
772 "@echo off\n" "%c:\n" "cd \"%s\"\n", *cwd, cwd);
773 for (n = 0; n < files.count; ++n)
774 {
775 char *dpath;
776
777 if (n && !strcmp (files.array[n], files.array[n - 1]))
778 continue;
779
780 dpath = files.array[n];
781
782 if (_stat (dpath, &st) == 0 && st.st_mode & _S_IFDIR)
783 fprintf (uninst, "rmdir \"%s\"\n", dpath);
784 else
785 {
786 if (access (dpath, 6) != 0)
787 fprintf (uninst, "attrib -r \"%s\"\n", dpath);
788 fprintf (uninst, "del \"%s\"\n", dpath);
789 }
790 }
791 fprintf (uninst,
792 "del \"%s\"\n"
793 "del \"%s\"\n"
794 "rmdir \"%s\"\n"
795 "del %s\n", shortcut, shellscut,
796 folder, uninstfile);
797 fclose (uninst);
798
799 create_shortcut (uninstfile, shortcut);
800 }
801 sa_cleanup (&files);
802 retval = 1;
803 }
804
805 if (lib)
806 FreeLibrary (lib);
807
808 printf ("Done.\n");
809 return retval;
810 }
811
812
813 /* Writes the startup batch file. */
814 int
815 do_start_menu (const char *root)
816 {
817 FILE *batch;
818 char *batch_name = pathcat (root, "bin\\cygwin.bat");
819 int retval = 0;
820
821 /* Create the batch file for the start menu. */
822 if (batch_name)
823 {
824 batch = fopen (batch_name, "wt");
825 if (batch)
826 {
827 LPITEMIDLIST progfiles;
828 char pfilespath[_MAX_PATH];
829 char *folder;
830
831 fprintf (batch,
832 "@echo off\n"
833 "SET MAKE_MODE=unix\n"
834 "SET PATH=%s\\bin;%s\\usr\\local\\bin;%%PATH%%\n"
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. */
847
848 shortcut = pathcat (folder, "Cygwin 1.1.0.lnk");
849 if (shortcut)
850 {
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))
873 {
874 char *uninstscut =
875 pathcat (folder, "Uninstall Cygwin 1.1.0.lnk");
876 if (uninstscut)
877 {
878 if (create_uninstall
879 (wd, folder, shortcut, uninstscut))
880 retval = 1;
881 xfree (uninstscut);
882 }
883 }
884 xfree (cmdline);
885 xfree (shortcut);
886 }
887 xfree (folder);
888 }
889 }
890
891 xfree (batch_name);
892 }
893 return retval;
894 }
895
896 char *
897 getdownloadsource ()
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",
907 filename, 1))
908 fputs ("Unable to retrieve the list of cygwin mirrors.\n", stderr);
909 else
910 {
911 FILE *in = fopen (filename, "rt");
912
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];
920 SA urls, names; /* These must stay sync'd. */
921
922 sa_init (&urls);
923 sa_init (&names);
924
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);
935
936 if (ref)
937 {
938 size_t len = strlen (ref);
939
940 if (ref[len - 1] == '/')
941 {
942 char *name;
943 char *url = xmalloc (len + 13);
944
945 strcat (strcpy (url, ref), DOWNLOAD_SUBDIR);
946 sa_add (&urls, url);
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
957 xfree (url);
958 }
959 }
960 }
961 }
962
963 sa_add (&urls, "Other");
964 sa_add (&names, "Other");
965 option =
966 optionprompt ("Select a download location close to you:", &names);
967 if (option == urls.count - 1)
968 retval = prompt ("Download url", NULL);
969 else
970 retval = xstrdup (urls.array[option]);
971
972 sa_cleanup (&urls);
973 sa_cleanup (&names);
974 }
975 }
976 unlink (filename);
977
978 return retval;
979 }
980
981
982 /* Basically a mkdir -p /somedir function. */
983 void
984 mkdirp (const char *dir)
985 {
986 if (mkdir (dir) == -1 && errno != EEXIST)
987 {
988 char *parent = strdup (dir);
989 char *slash = strrchr (parent, '\\');
990
991 if (slash)
992 {
993 *slash = '\0';
994 mkdirp (parent);
995 }
996
997 xfree (parent);
998
999 mkdir (dir);
1000 }
1001 }
1002
1003
1004 /* This routine assumes that the cwd is the root directory. */
1005 int
1006 mkmount (const char *mountexedir, const char *root, const char *dospath,
1007 const char *unixpath, int force)
1008 {
1009 char *mount, *bslashed, *fulldospath, *p;
1010 char buffer[1024];
1011
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 }
1022
1023 /* Make sure the target path exists. */
1024 mkdirp (fulldospath);
1025
1026 /* Mount the directory. */
1027 mount = pathcat (mountexedir, "mount");
1028 sprintf (buffer, "%s %s -b \"%s\" %s", mount, force ? "-f" : "",
1029 fulldospath, unixpath);
1030 xfree (mount);
1031 xfree (fulldospath);
1032
1033 return xsystem (buffer) == 0;
1034 }
1035
1036 int
1037 main ()
1038 {
1039 int retval = 1; /* Default to error code */
1040 clock_t start;
1041
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
1050 start = clock ();
1051 if (!EnumResourceNames (NULL, "FILE", output_file, 0))
1052 {
1053 winerror ();
1054 }
1055 else
1056 {
1057 char *defroot, *update;
1058 char *root;
1059 int done;
1060 HKEY cu = NULL, lm = NULL;
1061
1062 wd = _getcwd (NULL, 0);
1063 setpath (wd);
1064
1065 /* Begin prompting user for setup requirements. */
1066 printf ("Press <enter> to accept the default value.\n");
1067
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
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);
1083
1084 /* Get the root directory and warn the user if there are any spaces in
1085 the path. */
1086 for (done = 0; !done;)
1087 {
1088 root = prompt ("Root directory", defroot);
1089 if (strchr (root, ' '))
1090 {
1091 char *temp;
1092 temp =
1093 prompt
1094 ("Using spaces in the root directory path may cause problems."
1095 " Continue anyway", "no");
1096 if (toupper (*temp) == 'Y')
1097 done = 1;
1098 xfree (temp);
1099 }
1100 else
1101 done = 1;
1102 }
1103 xfree (defroot);
1104
1105 /* Create the root directory. */
1106 mkdir (root); /* Ignore any return value since it may
1107 already exist. */
1108 mkmount (wd, "", root, "/", 1);
1109
1110 update =
1111 prompt ("Install from the current directory (d) or from the Internet (i)", "i");
1112 if (toupper (*update) == 'I')
1113 {
1114 char *dir = getdownloadsource ();
1115
1116 if (dir)
1117 {
1118 downloadfrom (dir);
1119 xfree (dir);
1120 }
1121 }
1122 xfree (update);
1123
1124 /* Make the root directory the current directory so that recurse_dirs
1125 will * extract the packages into the correct path. */
1126 if (chdir (root) == -1)
1127 {
1128 printf ("Unable to make \"%s\" the current directory: %s\n",
1129 root, _strerror (""));
1130 }
1131 else
1132 {
1133 char *logpath = pathcat (wd, "setup.log");
1134
1135 if (logpath)
1136 {
1137 FILE *logfp = fopen (logpath, "w+t");
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
1146 _chdrive (toupper (*root) - 'A' + 1);
1147
1148 /* Make /bin point to /usr/bin and /lib point to /usr/lib. */
1149 mkmount (wd, root, "bin", "/usr/bin", 1);
1150 mkmount (wd, root, "lib", "/usr/lib", 1);
1151
1152 files.count = NFILE_LIST;
1153 files.array = calloc (sizeof (char *), NFILE_LIST + NFILE_SLOP);
1154 files.index = -1;
1155
1156 /* Extract all of the packages that are stored with setup or in
1157 subdirectories of its location */
1158 if (recurse_dirs (wd, logfp))
1159 {
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);
1167 if (xsystem (buffer))
1168 {
1169 printf
1170 ("Unable to mount \"%s\" as the root directory: %s",
1171 root, _strerror (""));
1172 }
1173 else
1174 {
1175 char **a;
1176 /* bash expects a /tmp */
1177 char *tmpdir = pathcat (root, "tmp");
1178
1179 if (tmpdir)
1180 {
1181 files.array[++files.index] = tmpdir;
1182 mkdir (tmpdir); /* Ignore the result, it may
1183 exist. */
1184 }
1185
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
1192 if (do_start_menu (root))
1193 retval = 0; /* Everything worked return
1194 successful code */
1195 }
1196 }
1197
1198 fclose (logfp);
1199 xfree (logpath);
1200 }
1201 }
1202
1203 xfree (root);
1204
1205 chdir (wd);
1206 _chdrive (toupper (*wd) - 'A' + 1);
1207 xfree (wd);
1208 }
1209
1210 printf ("\nInstallation took %.0f seconds.\n",
1211 (double) (clock () - start) / CLK_TCK);
1212
1213 return retval;
1214 }
This page took 0.091678 seconds and 5 git commands to generate.