]> sourceware.org Git - newlib-cygwin.git/blob - winsup/utils/cygcheck.cc
cygcheck: Use snprintf instead of multiple strcat
[newlib-cygwin.git] / winsup / utils / cygcheck.cc
1 /* cygcheck.cc
2
3 This file is part of Cygwin.
4
5 This software is a copyrighted work licensed under the terms of the
6 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
7 details. */
8
9 #define _WIN32_WINNT 0x0a00
10 #define cygwin_internal cygwin_internal_dontuse
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <stdarg.h>
14 #include <string.h>
15 #include <sys/time.h>
16 #include <ctype.h>
17 #include <io.h>
18 #include <windows.h>
19 #include <wininet.h>
20 #include "path.h"
21 #include "wide_path.h"
22 #include <getopt.h>
23 #include "../cygwin/include/cygwin/version.h"
24 #include "../cygwin/include/sys/cygwin.h"
25 #define _NOMNTENT_MACROS
26 #include "../cygwin/include/mntent.h"
27 #undef cygwin_internal
28 #include "loadlib.h"
29
30 #ifndef max
31 #define max __max
32 #endif
33
34 #ifndef alloca
35 #define alloca __builtin_alloca
36 #endif
37
38 int verbose = 0;
39 int registry = 0;
40 int sysinfo = 0;
41 int givehelp = 0;
42 int keycheck = 0;
43 int check_setup = 0;
44 int dump_only = 0;
45 int find_package = 0;
46 int list_package = 0;
47 int grep_packages = 0;
48 int del_orphaned_reg = 0;
49
50 static char emptystr[] = "";
51
52 #ifdef __GNUC__
53 typedef long long longlong;
54 #else
55 typedef __int64 longlong;
56 #endif
57
58 /* In dump_setup.cc */
59 void dump_setup (int, char **, bool);
60 void package_find (int, char **);
61 void package_list (int, char **);
62 /* In bloda.cc */
63 void dump_dodgy_apps (int verbose);
64 /* Forward declaration */
65 static void usage (FILE *, int);
66
67 static const char *known_env_vars[] = {
68 "c_include_path",
69 "compiler_path",
70 "cxx_include_path",
71 "cygwin",
72 "cygwin32",
73 "dejagnu",
74 "expect",
75 "gcc_default_options",
76 "gcc_exec_prefix",
77 "home",
78 "ld_library_path",
79 "library_path",
80 "login",
81 "lpath",
82 "make_mode",
83 "makeflags",
84 "path",
85 "pwd",
86 "strace",
87 "tcl_library",
88 "user",
89 0
90 };
91
92 struct
93 {
94 const char *name;
95 int missing_is_good;
96 }
97 static common_apps[] = {
98 {"awk", 0},
99 {"bash", 0},
100 {"cat", 0},
101 {"cp", 0},
102 {"cpp", 1},
103 {"crontab", 0},
104 {"find", 0},
105 {"gcc", 0},
106 {"gdb", 0},
107 {"grep", 0},
108 {"kill", 0},
109 {"ld", 0},
110 {"ls", 0},
111 {"make", 0},
112 {"mv", 0},
113 {"patch", 0},
114 {"perl", 0},
115 {"rm", 0},
116 {"sed", 0},
117 {"ssh", 0},
118 {"sh", 0},
119 {"tar", 0},
120 {"test", 0},
121 {"vi", 0},
122 {"vim", 0},
123 {0, 0}
124 };
125
126 /* Options without ASCII single char representation. */
127 enum
128 {
129 CO_DELETE_KEYS = 0x100,
130 };
131
132 static int num_paths, max_paths;
133 struct pathlike
134 {
135 char *dir;
136 bool issys;
137 void check_existence (const char *fn, int showall, int verbose,
138 char* first, const char *ext1 = "",
139 const char *ext2 = "");
140 };
141
142 pathlike *paths;
143 int first_nonsys_path;
144
145 void
146 eprintf (const char *format, ...)
147 {
148 va_list ap;
149 va_start (ap, format);
150 vfprintf (stderr, format, ap);
151 va_end (ap);
152 }
153
154 /*
155 * display_error() is used to report failure modes
156 */
157 static int
158 display_error (const char *name, bool show_error, bool print_failed)
159 {
160 fprintf (stderr, "cygcheck: %s", name);
161 if (show_error)
162 fprintf (stderr, "%s: %lu\n",
163 print_failed ? " failed" : "", GetLastError ());
164 else
165 fprintf (stderr, "%s\n",
166 print_failed ? " failed" : "");
167 return 1;
168 }
169
170 static int
171 display_error (const char *name)
172 {
173 return display_error (name, true, true);
174 }
175
176 static int
177 display_error (const char *fmt, const char *x)
178 {
179 char buf[4000];
180 snprintf (buf, sizeof buf, fmt, x);
181 return display_error (buf, false, false);
182 }
183
184 static int
185 display_error_fmt (const char *fmt, ...)
186 {
187 char buf[4000];
188 va_list va;
189
190 va_start (va, fmt);
191 vsnprintf (buf, sizeof buf, fmt, va);
192 return display_error (buf, false, false);
193 }
194
195 /* Display a WinInet error message, and close a variable number of handles.
196 (Passed a list of handles terminated by NULL.) */
197 static int
198 display_internet_error (const char *message, ...)
199 {
200 DWORD err = GetLastError ();
201 TCHAR err_buf[256];
202 va_list hptr;
203 HINTERNET h;
204
205 /* in the case of a successful connection but 404 response, there is no
206 win32 error message, but we still get passed a message to display. */
207 if (err)
208 {
209 if (FormatMessage (FORMAT_MESSAGE_FROM_HMODULE,
210 GetModuleHandle ("wininet.dll"), err, 0, err_buf,
211 sizeof (err_buf), NULL) == 0)
212 strcpy (err_buf, "(Unknown error)");
213
214 fprintf (stderr, "cygcheck: %s: %s (win32 error %lu)\n", message,
215 err_buf, err);
216 }
217 else
218 fprintf (stderr, "cygcheck: %s\n", message);
219
220 va_start (hptr, message);
221 while ((h = va_arg (hptr, HINTERNET)) != 0)
222 InternetCloseHandle (h);
223 va_end (hptr);
224
225 return 1;
226 }
227
228 static void
229 add_path (char *s, int maxlen, bool issys)
230 {
231 if (num_paths >= max_paths)
232 {
233 max_paths += 10;
234 /* Extend path array */
235 paths = (pathlike *) realloc (paths, (1 + max_paths) * sizeof (paths[0]));
236 }
237
238 pathlike *pth = paths + num_paths;
239
240 /* Allocate space for directory in path list */
241 char *dir = (char *) calloc (maxlen + 2, sizeof (char));
242 if (dir == NULL)
243 {
244 display_error ("add_path: calloc() failed");
245 return;
246 }
247
248 /* Copy input directory to path list */
249 memcpy (dir, s, maxlen);
250
251 /* Add a trailing slash by default */
252 char *e = strchr (dir, '\0');
253 if (e != dir && e[-1] != '\\')
254 strcpy (e, "\\");
255
256 /* Fill out this element */
257 pth->dir = dir;
258 pth->issys = issys;
259 pth[1].dir = NULL;
260 num_paths++;
261 }
262
263 static void
264 init_paths ()
265 {
266 char tmp[4000], *sl;
267 add_path ((char *) ".", 1, true); /* to be replaced later */
268
269 if (GetCurrentDirectory (4000, tmp))
270 add_path (tmp, strlen (tmp), true);
271 else
272 display_error ("init_paths: GetCurrentDirectory()");
273
274 if (GetSystemDirectory (tmp, 4000))
275 add_path (tmp, strlen (tmp), true);
276 else
277 display_error ("init_paths: GetSystemDirectory()");
278 sl = strrchr (tmp, '\\');
279 if (sl)
280 {
281 strcpy (sl, "\\SYSTEM");
282 add_path (tmp, strlen (tmp), true);
283 }
284 GetWindowsDirectory (tmp, 4000);
285 add_path (tmp, strlen (tmp), true);
286
287 char *wpath = getenv ("PATH");
288 if (!wpath)
289 display_error ("WARNING: PATH is not set\n", "");
290 else
291 {
292 char *b, *e;
293 b = wpath;
294 while (1)
295 {
296 for (e = b; *e && *e != ';'; e++)
297 continue; /* loop terminates at first ';' or EOS */
298 if (strncmp(b, ".\\", 2) != 0)
299 add_path (b, e - b, false);
300 if (!*e)
301 break;
302 b = e + 1;
303 }
304 }
305 }
306
307 #define LINK_EXTENSION ".lnk"
308
309 void
310 pathlike::check_existence (const char *fn, int showall, int verbose,
311 char* first, const char *ext1, const char *ext2)
312 {
313 char file[4000];
314 snprintf (file, sizeof file, "%s%s%s%s", dir, fn, ext1, ext2);
315
316 wide_path wpath (file);
317 if (GetFileAttributesW (wpath) != (DWORD) - 1)
318 {
319 char *lastdot = strrchr (file, '.');
320 bool is_link = lastdot && !strcmp (lastdot, LINK_EXTENSION);
321 // If file is a link, fix up the extension before printing
322 if (is_link)
323 *lastdot = '\0';
324 if (showall)
325 printf ("Found: %s\n", file);
326 if (verbose && *first != '\0' && strcasecmp (first, file) != 0)
327 {
328 char *flastdot = strrchr (first, '.');
329 bool f_is_link = flastdot && !strcmp (flastdot, LINK_EXTENSION);
330 // if first is a link, fix up the extension before printing
331 if (f_is_link)
332 *flastdot = '\0';
333 printf ("Warning: %s hides %s\n", first, file);
334 if (f_is_link)
335 *flastdot = '.';
336 }
337 if (is_link)
338 *lastdot = '.';
339 if (!*first)
340 strcpy (first, file);
341 }
342 }
343
344 static const char *
345 find_on_path (const char *in_file, const char *ext, bool showall = false,
346 bool search_sys = false, bool checklinks = false)
347 {
348 static char rv[4000];
349
350 /* Sort of a kludge but we've already tested this once, so don't try it
351 again */
352 if (in_file == rv)
353 return in_file;
354
355 static pathlike abspath[2] =
356 {
357 {emptystr, 0},
358 {NULL, 0}
359 };
360
361 *rv = '\0';
362 if (!in_file)
363 {
364 display_error ("internal error find_on_path: NULL pointer for file",
365 false, false);
366 return 0;
367 }
368
369 if (!ext)
370 {
371 display_error ("internal error find_on_path: "
372 "NULL pointer for default_extension", false, false);
373 return 0;
374 }
375
376 const char *file;
377 pathlike *search_paths;
378 if (!strpbrk (in_file, ":/\\"))
379 {
380 file = in_file;
381 search_paths = paths;
382 }
383 else
384 {
385 file = cygpath (in_file, NULL);
386 search_paths = abspath;
387 showall = false;
388 }
389
390 if (!file)
391 {
392 display_error ("internal error find_on_path: "
393 "cygpath conversion failed for %s\n", in_file);
394 return 0;
395 }
396
397 char *hasext = strrchr (file, '.');
398 if (hasext && !strpbrk (hasext, "/\\"))
399 ext = "";
400
401 for (pathlike *pth = search_paths; pth->dir; pth++)
402 if (!pth->issys || search_sys)
403 {
404 pth->check_existence (file, showall, verbose, rv, ext);
405
406 if (checklinks)
407 pth->check_existence (file, showall, verbose, rv, ext,
408 LINK_EXTENSION);
409
410 if (!*ext)
411 continue;
412
413 pth->check_existence (file, showall, verbose, rv);
414 if (checklinks)
415 pth->check_existence (file, showall, verbose, rv, LINK_EXTENSION);
416 }
417
418 return *rv ? rv : NULL;
419 }
420
421 #define DID_NEW 1
422 #define DID_ACTIVE 2
423 #define DID_INACTIVE 3
424
425 struct Did
426 {
427 Did *next;
428 char *file;
429 int state;
430 };
431 static Did *did = 0;
432
433 static Did *
434 already_did (const char *file)
435 {
436 Did *d;
437 for (d = did; d; d = d->next)
438 if (strcasecmp (d->file, file) == 0)
439 return d;
440 d = (Did *) malloc (sizeof (Did));
441 d->file = strdup (file);
442 d->next = did;
443 d->state = DID_NEW;
444 did = d;
445 return d;
446 }
447
448 struct Section
449 {
450 char name[8];
451 int virtual_size;
452 int virtual_address;
453 int size_of_raw_data;
454 int pointer_to_raw_data;
455 };
456
457 static int
458 rva_to_offset (int rva, char *sections, int nsections, int *sz)
459 {
460 int i;
461
462 if (sections == NULL)
463 {
464 display_error ("rva_to_offset: NULL passed for sections", true, false);
465 return 0;
466 }
467
468 for (i = 0; i < nsections; i++)
469 {
470 Section *s = (Section *) (sections + i * 40);
471 #if 0
472 printf ("%08x < %08x < %08x ? %08x\n",
473 s->virtual_address, rva,
474 s->virtual_address + s->virtual_size, s->pointer_to_raw_data);
475 #endif
476 if (rva >= s->virtual_address
477 && rva < s->virtual_address + s->virtual_size)
478 {
479 if (sz)
480 *sz = s->virtual_address + s->virtual_size - rva;
481 return rva - s->virtual_address + s->pointer_to_raw_data;
482 }
483 }
484 return 0; /* punt */
485 }
486
487 struct ExpDirectory
488 {
489 int flags;
490 int timestamp;
491 short major_ver;
492 short minor_ver;
493 int name_rva;
494 };
495
496 struct ImpDirectory
497 {
498 unsigned characteristics;
499 unsigned timestamp;
500 unsigned forwarder_chain;
501 unsigned name_rva;
502 unsigned iat_rva;
503 };
504
505 static bool track_down (const char *file, const char *suffix, int lvl);
506
507 #define CYGPREFIX (sizeof ("%%% Cygwin ") - 1)
508 static void
509 cygwin_info (HANDLE h)
510 {
511 char *buf, *bufend, *buf_start = NULL;
512 const char *hello = " Cygwin DLL version info:\n";
513 DWORD size = GetFileSize (h, NULL);
514 DWORD n;
515
516 if (size == 0xffffffff)
517 return;
518
519 buf_start = buf = (char *) calloc (1, size + 1);
520 if (buf == NULL)
521 {
522 display_error ("cygwin_info: calloc()");
523 return;
524 }
525
526 (void) SetFilePointer (h, 0, NULL, FILE_BEGIN);
527 if (!ReadFile (h, buf, size, &n, NULL))
528 {
529 free (buf_start);
530 return;
531 }
532
533 static char dummy[] = "\0\0\0\0\0\0\0";
534 char *dll_major = dummy;
535 bufend = buf + size;
536 while (buf < bufend)
537 if ((buf = (char *) memchr (buf, '%', bufend - buf)) == NULL)
538 break;
539 else if (strncmp ("%%% Cygwin ", buf, CYGPREFIX) != 0)
540 buf++;
541 else
542 {
543 char *p = strchr (buf += CYGPREFIX, '\n');
544 if (!p)
545 break;
546 if (strncasecmp (buf, "dll major:", 10) == 0)
547 {
548 dll_major = buf + 11;
549 continue;
550 }
551 char *s, pbuf[80];
552 int len;
553 len = 1 + p - buf;
554 if (strncasecmp (buf, "dll minor:", 10) != 0)
555 s = buf;
556 else
557 {
558 char c = dll_major[1];
559 dll_major[1] = '\0';
560 int maj = atoi (dll_major);
561 dll_major[1] = c;
562 int min = atoi (dll_major + 1);
563 sprintf (pbuf, "DLL version: %d.%d.%.*s", maj, min, len - 11,
564 buf + 11);
565 len = strlen (s = pbuf);
566 }
567 if (strncmp (s, "dll", 3) == 0)
568 memcpy (s, "DLL", 3);
569 else if (strncmp (s, "api", 3) == 0)
570 memcpy (s, "API", 3);
571 else if (islower (*s))
572 *s = toupper (*s);
573 fprintf (stdout, "%s %.*s", hello, len, s);
574 hello = "";
575 }
576
577 if (!*hello)
578 puts ("");
579
580 free (buf_start);
581 return;
582 }
583
584 static void
585 dll_info (const char *path, HANDLE fh, int lvl, int recurse)
586 {
587 DWORD junk;
588 int i;
589 if (is_symlink (fh))
590 {
591 if (!verbose)
592 puts ("");
593 else
594 {
595 char buf[PATH_MAX + 1] = "";
596 readlink (fh, buf, sizeof(buf) - 1);
597 printf (" (symlink to %s)\n", buf);
598 }
599 return;
600 }
601 int pe_header_offset = get_dword (fh, 0x3c);
602 if (GetLastError () != NO_ERROR)
603 display_error ("get_dword");
604 WORD arch = get_word (fh, pe_header_offset + 4);
605 if (GetLastError () != NO_ERROR)
606 display_error ("get_word");
607 #ifdef __x86_64__
608 if (arch != IMAGE_FILE_MACHINE_AMD64)
609 {
610 puts (verbose ? " (not x86_64 dll)" : "\n");
611 return;
612 }
613 int base_off = 108;
614 #else
615 if (arch != IMAGE_FILE_MACHINE_I386)
616 {
617 puts (verbose ? " (not x86 dll)" : "\n");
618 return;
619 }
620 int base_off = 92;
621 #endif
622 int opthdr_ofs = pe_header_offset + 4 + 20;
623 unsigned short v[6];
624
625 if (path == NULL)
626 {
627 display_error ("dll_info: NULL passed for path", true, false);
628 return;
629 }
630
631 if (SetFilePointer (fh, opthdr_ofs + 40, 0, FILE_BEGIN) ==
632 INVALID_SET_FILE_POINTER && GetLastError () != NO_ERROR)
633 display_error ("dll_info: SetFilePointer()");
634
635 if (!ReadFile (fh, &v, sizeof (v), &junk, 0))
636 display_error ("dll_info: Readfile()");
637
638 if (verbose)
639 printf (" - os=%d.%d img=%d.%d sys=%d.%d\n",
640 v[0], v[1], v[2], v[3], v[4], v[5]);
641 else
642 printf ("\n");
643
644 int num_entries = get_dword (fh, opthdr_ofs + base_off + 0);
645 if (GetLastError () != NO_ERROR)
646 display_error ("get_dword");
647 int export_rva = get_dword (fh, opthdr_ofs + base_off + 4);
648 if (GetLastError () != NO_ERROR)
649 display_error ("get_dword");
650 int export_size = get_dword (fh, opthdr_ofs + base_off + 8);
651 if (GetLastError () != NO_ERROR)
652 display_error ("get_dword");
653 int import_rva = get_dword (fh, opthdr_ofs + base_off + 12);
654 if (GetLastError () != NO_ERROR)
655 display_error ("get_dword");
656 int import_size = get_dword (fh, opthdr_ofs + base_off + 16);
657 if (GetLastError () != NO_ERROR)
658 display_error ("get_dword");
659
660 int nsections = get_word (fh, pe_header_offset + 4 + 2);
661 if (nsections == -1)
662 display_error ("get_word");
663 char *sections = (char *) malloc (nsections * 40);
664
665 if (SetFilePointer (fh, pe_header_offset + 4 + 20 +
666 get_word (fh, pe_header_offset + 4 + 16), 0,
667 FILE_BEGIN) == INVALID_SET_FILE_POINTER
668 && GetLastError () != NO_ERROR)
669 display_error ("dll_info: SetFilePointer()");
670
671 if (!ReadFile (fh, sections, nsections * 40, &junk, 0))
672 display_error ("dll_info: Readfile()");
673
674 if (verbose && num_entries >= 1 && export_size > 0)
675 {
676 int expsz;
677 int expbase = rva_to_offset (export_rva, sections, nsections, &expsz);
678
679 if (expbase)
680 {
681 if (SetFilePointer (fh, expbase, 0, FILE_BEGIN) ==
682 INVALID_SET_FILE_POINTER && GetLastError () != NO_ERROR)
683 display_error ("dll_info: SetFilePointer()");
684
685 unsigned char *exp = (unsigned char *) malloc (expsz);
686
687 if (!ReadFile (fh, exp, expsz, &junk, 0))
688 display_error ("dll_info: Readfile()");
689
690 ExpDirectory *ed = (ExpDirectory *) exp;
691 int ofs = ed->name_rva - export_rva;
692 time_t ts = ed->timestamp; /* timestamp is only 4 bytes! */
693 struct tm *tm = localtime (&ts);
694 if (tm && tm->tm_year < 60)
695 tm->tm_year += 2000;
696 if (tm && tm->tm_year < 200)
697 tm->tm_year += 1900;
698 printf ("%*c", lvl + 2, ' ');
699 printf ("\"%s\" v%d.%d", exp + ofs,
700 ed->major_ver, ed->minor_ver);
701 if (tm)
702 printf (" ts=%04d-%02d-%02d %02d:%02d",
703 tm->tm_year, tm->tm_mon + 1, tm->tm_mday,
704 tm->tm_hour, tm->tm_min);
705 putchar ('\n');
706 }
707 }
708
709 if (num_entries >= 2 && import_size > 0 && recurse)
710 {
711 int impsz;
712 int impbase = rva_to_offset (import_rva, sections, nsections, &impsz);
713 if (impbase)
714 {
715 if (SetFilePointer (fh, impbase, 0, FILE_BEGIN) ==
716 INVALID_SET_FILE_POINTER && GetLastError () != NO_ERROR)
717 display_error ("dll_info: SetFilePointer()");
718
719 unsigned char *imp = (unsigned char *) malloc (impsz);
720 if (imp == NULL)
721 {
722 display_error ("dll_info: malloc()");
723 return;
724 }
725
726 if (!ReadFile (fh, imp, impsz, &junk, 0))
727 display_error ("dll_info: Readfile()");
728
729 ImpDirectory *id = (ImpDirectory *) imp;
730 for (i = 0; id[i].name_rva; i++)
731 {
732 /* int ofs = id[i].name_rva - import_rva; */
733 track_down ((char *) imp + id[i].name_rva - import_rva,
734 (char *) ".dll", lvl + 2);
735 }
736 }
737 }
738 if (strstr (path, "\\cygwin1.dll"))
739 cygwin_info (fh);
740 }
741
742 // Return true on success, false if error printed
743 static bool
744 track_down (const char *file, const char *suffix, int lvl)
745 {
746 if (file == NULL)
747 {
748 display_error ("track_down: NULL passed for file", true, false);
749 return false;
750 }
751
752 if (suffix == NULL)
753 {
754 display_error ("track_down: NULL passed for suffix", false, false);
755 return false;
756 }
757
758 const char *path = find_on_path (file, suffix, false, true);
759 if (!path)
760 {
761 /* The api-ms-win-*.dll files are in system32/downlevel and not in the
762 DLL search path, so find_on_path doesn't find them. Since they are
763 never actually linked against by the executables, they are of no
764 interest to us. Skip any error message in not finding them. */
765 if (strncasecmp (file, "api-ms-win-", 11) || strcasecmp (suffix, ".dll"))
766 display_error ("track_down: could not find %s\n", file);
767 return false;
768 }
769
770 Did *d = already_did (file);
771 switch (d->state)
772 {
773 case DID_NEW:
774 break;
775 case DID_ACTIVE:
776 if (verbose)
777 {
778 if (lvl)
779 printf ("%*c", lvl, ' ');
780 printf ("%s", path);
781 printf (" (recursive)\n");
782 }
783 return true;
784 case DID_INACTIVE:
785 if (verbose)
786 {
787 if (lvl)
788 printf ("%*c", lvl, ' ');
789 printf ("%s", path);
790 printf (" (already done)\n");
791 }
792 return true;
793 default:
794 break;
795 }
796
797 if (lvl)
798 printf ("%*c", lvl, ' ');
799
800 printf ("%s", path);
801
802 wide_path wpath (path);
803 HANDLE fh =
804 CreateFileW (wpath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
805 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
806 if (fh == INVALID_HANDLE_VALUE)
807 {
808 display_error ("cannot open - '%s'\n", path);
809 return false;
810 }
811
812 d->state = DID_ACTIVE;
813
814 if (is_exe (fh))
815 dll_info (path, fh, lvl, 1);
816 else if (is_symlink (fh))
817 display_error ("%s is a symlink instead of a DLL\n", path);
818 else
819 {
820 int magic = get_word (fh, 0x0);
821 if (magic == -1)
822 display_error ("get_word");
823 magic &= 0x00FFFFFF;
824 display_error_fmt ("%s is not a DLL: magic number %x (%d) '%s'\n",
825 path, magic, magic, (char *)&magic);
826 }
827
828 d->state = DID_INACTIVE;
829 if (!CloseHandle (fh))
830 display_error ("track_down: CloseHandle()");
831 return true;
832 }
833
834 static void
835 ls (char *f)
836 {
837 wide_path wpath (f);
838 HANDLE h = CreateFileW (wpath, GENERIC_READ,
839 FILE_SHARE_READ | FILE_SHARE_WRITE,
840 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
841 BY_HANDLE_FILE_INFORMATION info;
842
843 if (!GetFileInformationByHandle (h, &info))
844 display_error ("ls: GetFileInformationByHandle()");
845
846 SYSTEMTIME systime;
847
848 if (!FileTimeToSystemTime (&info.ftLastWriteTime, &systime))
849 display_error ("ls: FileTimeToSystemTime()");
850 printf ("%5dk %04d/%02d/%02d %s",
851 (((int) info.nFileSizeLow) + 512) / 1024,
852 systime.wYear, systime.wMonth, systime.wDay, f);
853 dll_info (f, h, 16, 0);
854 if (!CloseHandle (h))
855 display_error ("ls: CloseHandle()");
856 }
857
858 /* Remove filename from 's' and return directory name without trailing
859 backslash, or NULL if 's' doesn't seem to have a dirname. */
860 static char *
861 dirname (const char *s)
862 {
863 static char buf[PATH_MAX];
864
865 if (!s)
866 return NULL;
867
868 strncpy (buf, s, PATH_MAX);
869 buf[PATH_MAX - 1] = '\0'; // in case strlen(s) > PATH_MAX
870 char *lastsep = strrchr (buf, '\\');
871 if (!lastsep)
872 return NULL; // no backslash -> no dirname
873 else if (lastsep - buf <= 2 && buf[1] == ':')
874 lastsep[1] = '\0'; // can't remove backslash of "x:\"
875 else
876 *lastsep = '\0';
877 return buf;
878 }
879
880 // Find a real application on the path (possibly following symlinks)
881 static const char *
882 find_app_on_path (const char *app, bool showall = false)
883 {
884 const char *papp = find_on_path (app, ".exe", showall, false, true);
885
886 if (!papp)
887 return NULL;
888
889 wide_path wpath (papp);
890 HANDLE fh =
891 CreateFileW (wpath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
892 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
893 if (fh == INVALID_HANDLE_VALUE)
894 return NULL;
895
896 if (is_symlink (fh))
897 {
898 static char tmp[SYMLINK_MAX + 1];
899 if (!readlink (fh, tmp, SYMLINK_MAX))
900 display_error("readlink failed");
901
902 /* Resolve the linkname relative to the directory of the link. */
903 char *ptr = cygpath_rel (dirname (papp), tmp, NULL);
904 printf (" -> %s\n", ptr);
905 if (!strchr (ptr, '\\'))
906 {
907 char *lastsep;
908 strncpy (tmp, cygpath (papp, NULL), SYMLINK_MAX);
909 lastsep = strrchr (tmp, '\\');
910 strncpy (lastsep+1, ptr, SYMLINK_MAX - (lastsep-tmp));
911 ptr = tmp;
912 }
913 if (!CloseHandle (fh))
914 display_error ("find_app_on_path: CloseHandle()");
915 /* FIXME: We leak the ptr returned by cygpath() here which is a
916 malloc()d string. */
917 return find_app_on_path (ptr, showall);
918 }
919
920 if (!CloseHandle (fh))
921 display_error ("find_app_on_path: CloseHandle()");
922 return papp;
923 }
924
925 // Return true on success, false if error printed
926 static bool
927 cygcheck (const char *app)
928 {
929 const char *papp = find_app_on_path (app, 1);
930 if (!papp)
931 {
932 display_error ("could not find '%s'\n", app);
933 return false;
934 }
935
936 char *s;
937 char *sep = strpbrk (papp, ":/\\");
938 if (!sep)
939 {
940 static char dot[] = ".";
941 s = dot;
942 }
943 else
944 {
945 int n = sep - papp;
946 s = (char *) malloc (n + 2);
947 memcpy ((char *) s, papp, n);
948 strcpy (s + n, "\\");
949 }
950
951 paths[0].dir = s;
952 did = NULL;
953 return track_down (papp, ".exe", 0);
954 }
955
956 struct RegInfo
957 {
958 RegInfo *prev;
959 char *name;
960 HKEY key;
961 };
962
963 static void
964 show_reg (RegInfo * ri, int nest)
965 {
966 if (!ri)
967 return;
968 show_reg (ri->prev, 1);
969 if (nest)
970 printf ("%s\\", ri->name);
971 else
972 printf ("%s\n", ri->name);
973 }
974
975 static void
976 scan_registry (RegInfo * prev, HKEY hKey, char *name, int cygwin, bool wow64)
977 {
978 RegInfo ri;
979 ri.prev = prev;
980 ri.name = name;
981 ri.key = hKey;
982
983 char *cp;
984 for (cp = name; *cp; cp++)
985 if (strncasecmp (cp, "Cygwin", 6) == 0)
986 cygwin = 1;
987
988 DWORD num_subkeys, max_subkey_len, num_values;
989 DWORD max_value_len, max_valdata_len, i;
990 if (RegQueryInfoKey (hKey, 0, 0, 0, &num_subkeys, &max_subkey_len, 0,
991 &num_values, &max_value_len, &max_valdata_len, 0, 0)
992 != ERROR_SUCCESS)
993 {
994 #if 0
995 char tmp[400];
996 FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, 0, GetLastError (),
997 MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), tmp, 400, 0);
998 printf ("RegQueryInfoKey: %s\n", tmp);
999 #endif
1000 return;
1001 }
1002
1003 if (cygwin)
1004 {
1005 show_reg (&ri, 0);
1006
1007 char *value_name = (char *) malloc (max_value_len + 1);
1008 if (value_name == NULL)
1009 {
1010 display_error ("scan_registry: malloc()");
1011 return;
1012 }
1013
1014 char *value_data = (char *) malloc (max_valdata_len + 1);
1015 if (value_data == NULL)
1016 {
1017 display_error ("scan_registry: malloc()");
1018 return;
1019 }
1020
1021 for (i = 0; i < num_values; i++)
1022 {
1023 DWORD dlen = max_valdata_len + 1;
1024 DWORD nlen = max_value_len + 1;
1025 DWORD type;
1026 RegEnumValue (hKey, i, value_name, &nlen, 0,
1027 &type, (BYTE *) value_data, &dlen);
1028 {
1029 printf (" %s = ", i ? value_name : "(default)");
1030 switch (type)
1031 {
1032 case REG_DWORD:
1033 printf ("0x%08x\n", *(unsigned *) value_data);
1034 break;
1035 case REG_EXPAND_SZ:
1036 case REG_SZ:
1037 printf ("'%s'\n", value_data);
1038 break;
1039 default:
1040 printf ("(unsupported type)\n");
1041 break;
1042 }
1043 }
1044 }
1045 free (value_name);
1046 free (value_data);
1047 }
1048
1049 char *subkey_name = (char *) malloc (max_subkey_len + 1);
1050 for (i = 0; i < num_subkeys; i++)
1051 {
1052 if (RegEnumKey (hKey, i, subkey_name, max_subkey_len + 1) ==
1053 ERROR_SUCCESS)
1054 {
1055 HKEY sKey;
1056 /* Don't recurse more than one level into the WOW64 subkey since
1057 that would lead to an endless recursion. */
1058 if (!strcasecmp (subkey_name, "Wow6432Node"))
1059 {
1060 if (wow64)
1061 continue;
1062 wow64 = true;
1063 }
1064 if (RegOpenKeyEx (hKey, subkey_name, 0, KEY_READ, &sKey)
1065 == ERROR_SUCCESS)
1066 {
1067 scan_registry (&ri, sKey, subkey_name, cygwin, wow64);
1068 if (RegCloseKey (sKey) != ERROR_SUCCESS)
1069 display_error ("scan_registry: RegCloseKey()");
1070 }
1071 }
1072 }
1073 free (subkey_name);
1074 }
1075
1076 void
1077 pretty_id ()
1078 {
1079 char *groups[16384];
1080
1081 char *id = cygpath ("/bin/id.exe", NULL);
1082 for (char *p = id; (p = strchr (p, '/')); p++)
1083 *p = '\\';
1084
1085 if (access (id, X_OK))
1086 {
1087 fprintf (stderr, "'id' program not found\n");
1088 return;
1089 }
1090
1091 char buf[16384];
1092 snprintf (buf, sizeof (buf), "\"%s\"", id);
1093 FILE *f = popen (buf, "rt");
1094
1095 buf[0] = '\0';
1096 fgets (buf, sizeof (buf), f);
1097 pclose (f);
1098 char *uid = strtok (buf, ")");
1099 if (uid)
1100 uid += strlen ("uid=");
1101 else
1102 {
1103 fprintf (stderr, "garbled output from 'id' command - no uid= found\n");
1104 return;
1105 }
1106 char *gid = strtok (NULL, ")");
1107 if (gid)
1108 gid += strlen ("gid=") + 1;
1109 else
1110 {
1111 fprintf (stderr, "garbled output from 'id' command - no gid= found\n");
1112 return;
1113 }
1114
1115 char **ng = groups - 1;
1116 size_t len_uid = strlen ("UID: )") + strlen (uid);
1117 size_t len_gid = strlen ("GID: )") + strlen (gid);
1118 *++ng = groups[0] = (char *) alloca (len_uid + 1);
1119 *++ng = groups[1] = (char *) alloca (len_gid + 1);
1120 sprintf (groups[0], "UID: %s)", uid);
1121 sprintf (groups[1], "GID: %s)", gid);
1122 size_t sz = max (len_uid, len_gid);
1123 while ((*++ng = strtok (NULL, ",")))
1124 {
1125 char *p = strchr (*ng, '\n');
1126 if (p)
1127 *p = '\0';
1128 if (ng == groups + 2)
1129 *ng += strlen (" groups=");
1130 size_t len = strlen (*ng);
1131 if (sz < len)
1132 sz = len;
1133 }
1134 ng--;
1135
1136 printf ("\nOutput from %s\n", id);
1137 int n = 80 / (int) ++sz;
1138 int i = n > 2 ? n - 2 : 0;
1139 sz = -sz;
1140 for (char **g = groups; g <= ng; g++)
1141 if ((g != ng) && (++i < n))
1142 printf ("%*s", (int) sz, *g);
1143 else
1144 {
1145 puts (*g);
1146 i = 0;
1147 }
1148 }
1149
1150 /* This dumps information about each installed cygwin service, if cygrunsrv
1151 is available. */
1152 void
1153 dump_sysinfo_services ()
1154 {
1155 char buf[1024];
1156 char buf2[1024];
1157 FILE *f;
1158 bool no_services = false;
1159
1160 if (givehelp)
1161 printf ("\nChecking for any Cygwin services... %s\n\n",
1162 verbose ? "" : "(use -v for more detail)");
1163 else
1164 fputc ('\n', stdout);
1165
1166 /* find the location of cygrunsrv.exe */
1167 char *cygrunsrv = cygpath ("/bin/cygrunsrv.exe", NULL);
1168 for (char *p = cygrunsrv; (p = strchr (p, '/')); p++)
1169 *p = '\\';
1170
1171 if (access (cygrunsrv, X_OK))
1172 {
1173 puts ("Can't find the cygrunsrv utility, skipping services check.\n");
1174 return;
1175 }
1176
1177 /* check for a recent cygrunsrv */
1178 snprintf (buf, sizeof (buf), "\"%s\" --version", cygrunsrv);
1179 if ((f = popen (buf, "rt")) == NULL)
1180 {
1181 printf ("Failed to execute '%s', skipping services check.\n", buf);
1182 return;
1183 }
1184 int maj, min;
1185 int ret = fscanf (f, "cygrunsrv V%u.%u", &maj, &min);
1186 if (ferror (f) || feof (f) || ret == EOF || maj < 1 || min < 10)
1187 {
1188 puts ("The version of cygrunsrv installed is too old to dump "
1189 "service info.\n");
1190 return;
1191 }
1192 pclose (f);
1193
1194 /* For verbose mode, just run cygrunsrv --list --verbose and copy output
1195 verbatim; otherwise run cygrunsrv --list and then cygrunsrv --query for
1196 each service. */
1197 snprintf (buf, sizeof (buf),
1198 (verbose ? "\"%s\" --list --verbose" : "\"%s\" --list"),
1199 cygrunsrv);
1200 if ((f = popen (buf, "rt")) == NULL)
1201 {
1202 printf ("Failed to execute '%s', skipping services check.\n", buf);
1203 return;
1204 }
1205
1206 if (verbose)
1207 {
1208 /* copy output to stdout */
1209 size_t nchars = 0;
1210 while (!feof (f) && !ferror (f))
1211 nchars += fwrite ((void *) buf, 1,
1212 fread ((void *) buf, 1, sizeof (buf), f), stdout);
1213
1214 /* cygrunsrv outputs nothing if there are no cygwin services found */
1215 if (nchars < 1)
1216 no_services = true;
1217 pclose (f);
1218 }
1219 else
1220 {
1221 /* read the output of --list, and then run --query for each service */
1222 size_t nchars = fread ((void *) buf, 1, sizeof (buf) - 1, f);
1223 buf[nchars] = 0;
1224 pclose (f);
1225
1226 if (nchars > 0)
1227 for (char *srv = strtok (buf, "\n"); srv; srv = strtok (NULL, "\n"))
1228 {
1229 snprintf (buf2, sizeof (buf2), "\"%s\" --query %s", cygrunsrv, srv);
1230 if ((f = popen (buf2, "rt")) == NULL)
1231 {
1232 printf ("Failed to execute '%s', skipping services check.\n",
1233 buf2);
1234 return;
1235 }
1236
1237 /* copy output to stdout */
1238 while (!feof (f) && !ferror (f))
1239 fwrite ((void *) buf2, 1,
1240 fread ((void *) buf2, 1, sizeof (buf2), f), stdout);
1241 pclose (f);
1242 }
1243 else
1244 no_services = true;
1245 }
1246
1247 /* inform the user if nothing found */
1248 if (no_services)
1249 puts ("No Cygwin services found.\n");
1250 }
1251
1252 enum handle_reg_t
1253 {
1254 PRINT_KEY,
1255 DELETE_KEY
1256 };
1257
1258 void
1259 handle_reg_installation (handle_reg_t what)
1260 {
1261 HKEY key;
1262
1263 if (what == PRINT_KEY)
1264 printf ("Cygwin installations found in the registry:\n");
1265 for (int i = 0; i < 2; ++i)
1266 if (RegOpenKeyEx (i ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE,
1267 "SOFTWARE\\Cygwin\\Installations", 0,
1268 what == DELETE_KEY ? KEY_READ | KEY_WRITE : KEY_READ,
1269 &key)
1270 == ERROR_SUCCESS)
1271 {
1272 char name[32], data[PATH_MAX];
1273 DWORD nsize, dsize, type;
1274 LONG ret;
1275
1276 for (DWORD index = 0;
1277 (ret = RegEnumValue (key, index, name, (nsize = 32, &nsize), 0,
1278 &type, (PBYTE) data,
1279 (dsize = PATH_MAX, &dsize)))
1280 != ERROR_NO_MORE_ITEMS; ++index)
1281 if (ret == ERROR_SUCCESS && dsize > 5)
1282 {
1283 char *path = data + 4;
1284 if (path[1] != ':')
1285 *(path += 2) = '\\';
1286 if (what == PRINT_KEY)
1287 printf (" %s Key: %s Path: %s", i ? "User: " : "System:",
1288 name, path);
1289 strcat (path, "\\bin\\cygwin1.dll");
1290 if (what == PRINT_KEY)
1291 printf ("%s\n", access (path, F_OK) ? " (ORPHANED)" : "");
1292 else if (access (path, F_OK))
1293 {
1294 RegDeleteValue (key, name);
1295 /* Start over since index is not reliable anymore. */
1296 --i;
1297 break;
1298 }
1299 }
1300 RegCloseKey (key);
1301 }
1302 if (what == PRINT_KEY)
1303 printf ("\n");
1304 }
1305
1306 void
1307 print_reg_installations ()
1308 {
1309 handle_reg_installation (PRINT_KEY);
1310 }
1311
1312 void
1313 del_orphaned_reg_installations ()
1314 {
1315 handle_reg_installation (DELETE_KEY);
1316 }
1317
1318 /* Unfortunately neither mingw nor Windows know this function. */
1319 char *
1320 memmem (char *haystack, size_t haystacklen,
1321 const char *needle, size_t needlelen)
1322 {
1323 if (needlelen == 0)
1324 return haystack;
1325 while (needlelen <= haystacklen)
1326 {
1327 if (!memcmp (haystack, needle, needlelen))
1328 return haystack;
1329 haystack++;
1330 haystacklen--;
1331 }
1332 return NULL;
1333 }
1334
1335 extern "C" NTSTATUS NTAPI RtlGetVersion (PRTL_OSVERSIONINFOEXW);
1336
1337 static void
1338 dump_sysinfo ()
1339 {
1340 int i, j;
1341 char tmp[4000];
1342 time_t now;
1343 char *found_cygwin_dll;
1344 bool is_nt = false;
1345 char osname[128];
1346 DWORD obcaseinsensitive = 1;
1347 HKEY key;
1348
1349 /* MSVCRT popen (called by pretty_id and dump_sysinfo_services) SEGVs if
1350 COMSPEC isn't set correctly. Simply enforce it here. Using
1351 Get/SetEnvironmentVariable to set the dir does *not* help, btw.
1352 Apparently MSVCRT keeps its own copy of the environment and changing
1353 that requires to use _wputenv. */
1354 if (!_wgetenv (L"COMSPEC"))
1355 {
1356 WCHAR comspec[MAX_PATH + 17];
1357 wcscpy (comspec, L"COMSPEC=");
1358 GetSystemDirectoryW (comspec + 8, MAX_PATH);
1359 wcsncat (comspec, L"\\cmd.exe", sizeof comspec);
1360 _wputenv (comspec);
1361 }
1362
1363 printf ("\nCygwin Configuration Diagnostics\n");
1364 time (&now);
1365 printf ("Current System Time: %s\n", ctime (&now));
1366
1367 RTL_OSVERSIONINFOEXW osversion;
1368 osversion.dwOSVersionInfoSize = sizeof (RTL_OSVERSIONINFOEXW);
1369 RtlGetVersion (&osversion);
1370
1371 switch (osversion.dwPlatformId)
1372 {
1373 case VER_PLATFORM_WIN32_NT:
1374 is_nt = true;
1375 if (osversion.dwMajorVersion >= 6)
1376 {
1377 HMODULE k32 = GetModuleHandleW (L"kernel32.dll");
1378 BOOL (WINAPI *GetProductInfo) (DWORD, DWORD, DWORD, DWORD, PDWORD) =
1379 (BOOL (WINAPI *)(DWORD, DWORD, DWORD, DWORD, PDWORD))
1380 GetProcAddress (k32, "GetProductInfo");
1381 if (osversion.dwMajorVersion == 6)
1382 switch (osversion.dwMinorVersion)
1383 {
1384 case 0:
1385 strcpy (osname, osversion.wProductType == VER_NT_WORKSTATION
1386 ? "Vista" : "2008");
1387 break;
1388 case 1:
1389 strcpy (osname, osversion.wProductType == VER_NT_WORKSTATION
1390 ? "7" : "2008 R2");
1391 break;
1392 case 2:
1393 strcpy (osname, osversion.wProductType == VER_NT_WORKSTATION
1394 ? "8" : "2012");
1395 break;
1396 case 3:
1397 strcpy (osname, osversion.wProductType == VER_NT_WORKSTATION
1398 ? "8.1" : "2012 R2");
1399 break;
1400 case 4:
1401 default:
1402 strcpy (osname, osversion.wProductType == VER_NT_WORKSTATION
1403 ? "10 Preview" : "2016 Preview");
1404 break;
1405 }
1406 else if (osversion.dwMajorVersion == 10)
1407 {
1408 strcpy (osname, osversion.wProductType == VER_NT_WORKSTATION
1409 ? "10" : "2016");
1410 }
1411 DWORD prod;
1412 if (GetProductInfo (osversion.dwMajorVersion,
1413 osversion.dwMinorVersion,
1414 osversion.wServicePackMajor,
1415 osversion.wServicePackMinor,
1416 &prod))
1417 {
1418 const char *products[] =
1419 {
1420 /* 0x00000000 */ "",
1421 /* 0x00000001 */ " Ultimate",
1422 /* 0x00000002 */ " Home Basic",
1423 /* 0x00000003 */ " Home Premium",
1424 /* 0x00000004 */ " Enterprise",
1425 /* 0x00000005 */ " Home Basic N",
1426 /* 0x00000006 */ " Business",
1427 /* 0x00000007 */ " Server Standard",
1428 /* 0x00000008 */ " Server Datacenter",
1429 /* 0x00000009 */ " Small Business Server",
1430 /* 0x0000000a */ " Server Enterprise",
1431 /* 0x0000000b */ " Starter",
1432 /* 0x0000000c */ " Server Datacenter Core",
1433 /* 0x0000000d */ " Server Standard Core",
1434 /* 0x0000000e */ " Server Enterprise Core",
1435 /* 0x0000000f */ " Server Enterprise for Itanium-based Systems",
1436 /* 0x00000010 */ " Business N",
1437 /* 0x00000011 */ " Web Server",
1438 /* 0x00000012 */ " HPC Edition",
1439 /* 0x00000013 */ " Home Server",
1440 /* 0x00000014 */ " Storage Server Express",
1441 /* 0x00000015 */ " Storage Server Standard",
1442 /* 0x00000016 */ " Storage Server Workgroup",
1443 /* 0x00000017 */ " Storage Server Enterprise",
1444 /* 0x00000018 */ " for Windows Essential Server Solutions",
1445 /* 0x00000019 */ " Small Business Server Premium",
1446 /* 0x0000001a */ " Home Premium N",
1447 /* 0x0000001b */ " Enterprise N",
1448 /* 0x0000001c */ " Ultimate N",
1449 /* 0x0000001d */ " Web Server Core",
1450 /* 0x0000001e */ " Essential Business Server Management Server",
1451 /* 0x0000001f */ " Essential Business Server Security Server",
1452 /* 0x00000020 */ " Essential Business Server Messaging Server",
1453 /* 0x00000021 */ " Server Foundation",
1454 /* 0x00000022 */ " Home Server 2011",
1455 /* 0x00000023 */ " without Hyper-V for Windows Essential Server Solutions",
1456 /* 0x00000024 */ " Server Standard without Hyper-V",
1457 /* 0x00000025 */ " Server Datacenter without Hyper-V",
1458 /* 0x00000026 */ " Server Enterprise without Hyper-V",
1459 /* 0x00000027 */ " Server Datacenter Core without Hyper-V",
1460 /* 0x00000028 */ " Server Standard Core without Hyper-V",
1461 /* 0x00000029 */ " Server Enterprise Core without Hyper-V",
1462 /* 0x0000002a */ " Hyper-V Server",
1463 /* 0x0000002b */ " Storage Server Express Core",
1464 /* 0x0000002c */ " Storage Server Standard Core",
1465 /* 0x0000002d */ " Storage Server Workgroup Core",
1466 /* 0x0000002e */ " Storage Server Enterprise Core",
1467 /* 0x0000002f */ " Starter N",
1468 /* 0x00000030 */ " Professional",
1469 /* 0x00000031 */ " Professional N",
1470 /* 0x00000032 */ " Small Business Server 2011 Essentials",
1471 /* 0x00000033 */ " Server For SB Solutions",
1472 /* 0x00000034 */ " Server Solutions Premium",
1473 /* 0x00000035 */ " Server Solutions Premium Core",
1474 /* 0x00000036 */ " Server For SB Solutions EM", /* per MSDN, 2012-09-01 */
1475 /* 0x00000037 */ " Server For SB Solutions EM", /* per MSDN, 2012-09-01 */
1476 /* 0x00000038 */ " Multipoint Server",
1477 /* 0x00000039 */ "",
1478 /* 0x0000003a */ "",
1479 /* 0x0000003b */ " Essential Server Solution Management",
1480 /* 0x0000003c */ " Essential Server Solution Additional",
1481 /* 0x0000003d */ " Essential Server Solution Management SVC",
1482 /* 0x0000003e */ " Essential Server Solution Additional SVC",
1483 /* 0x0000003f */ " Small Business Server Premium Core",
1484 /* 0x00000040 */ " Server Hyper Core V",
1485 /* 0x00000041 */ "",
1486 /* 0x00000042 */ " Starter E",
1487 /* 0x00000043 */ " Home Basic E",
1488 /* 0x00000044 */ " Home Premium E",
1489 /* 0x00000045 */ " Professional E",
1490 /* 0x00000046 */ " Enterprise E",
1491 /* 0x00000047 */ " Ultimate E",
1492 /* 0x00000048 */ " Server Enterprise (Evaluation inst.)",
1493 /* 0x00000049 */ "",
1494 /* 0x0000004a */ "",
1495 /* 0x0000004b */ "",
1496 /* 0x0000004c */ " MultiPoint Server Standard",
1497 /* 0x0000004d */ " MultiPoint Server Premium",
1498 /* 0x0000004e */ "",
1499 /* 0x0000004f */ " Server Standard (Evaluation inst.)",
1500 /* 0x00000050 */ " Server Datacenter (Evaluation inst.)",
1501 /* 0x00000051 */ "",
1502 /* 0x00000052 */ "",
1503 /* 0x00000053 */ "",
1504 /* 0x00000054 */ " Enterprise N (Evaluation inst.)",
1505 /* 0x00000055 */ "",
1506 /* 0x00000056 */ "",
1507 /* 0x00000057 */ "",
1508 /* 0x00000058 */ "",
1509 /* 0x00000059 */ "",
1510 /* 0x0000005a */ "",
1511 /* 0x0000005b */ "",
1512 /* 0x0000005c */ "",
1513 /* 0x0000005d */ "",
1514 /* 0x0000005e */ "",
1515 /* 0x0000005f */ " Storage Server Workgroup (Evaluation inst.)",
1516 /* 0x00000060 */ " Storage Server Standard (Evaluation inst.)",
1517 /* 0x00000061 */ "",
1518 /* 0x00000062 */ " N",
1519 /* 0x00000063 */ " China",
1520 /* 0x00000064 */ " Single Language",
1521 /* 0x00000065 */ " Home",
1522 /* 0x00000066 */ "",
1523 /* 0x00000067 */ " Professional with Media Center",
1524 /* 0x00000068 */ " Mobile",
1525 /* 0x00000069 */ "",
1526 /* 0x0000006a */ "",
1527 /* 0x0000006b */ "",
1528 /* 0x0000006c */ "",
1529 /* 0x0000006d */ "",
1530 /* 0x0000006e */ "",
1531 /* 0x0000006f */ "",
1532 /* 0x00000070 */ "",
1533 /* 0x00000071 */ "",
1534 /* 0x00000072 */ "",
1535 /* 0x00000073 */ "",
1536 /* 0x00000074 */ "",
1537 /* 0x00000075 */ "",
1538 /* 0x00000076 */ "",
1539 /* 0x00000077 */ "",
1540 /* 0x00000078 */ "",
1541 /* 0x00000079 */ " Education",
1542 /* 0x0000007a */ " Education N",
1543 /* 0x0000007b */ "",
1544 /* 0x0000007c */ "",
1545 /* 0x0000007d */ "",
1546 /* 0x0000007e */ "",
1547 /* 0x0000007f */ "",
1548 /* 0x00000080 */ "",
1549 /* 0x00000081 */ "",
1550 /* 0x00000082 */ "",
1551 /* 0x00000083 */ "",
1552 /* 0x00000084 */ "",
1553 /* 0x00000085 */ " Mobile Enterprise",
1554 };
1555 if (prod == PRODUCT_UNLICENSED)
1556 strcat (osname, "Unlicensed");
1557 else if (prod > 0x00000085)
1558 strcat (osname, "");
1559 else
1560 strcat (osname, products[prod]);
1561 }
1562 else
1563 {
1564 }
1565 }
1566 else
1567 strcpy (osname, "NT");
1568 break;
1569 default:
1570 strcpy (osname, "??");
1571 break;
1572 }
1573 printf ("Windows %s Ver %lu.%lu Build %lu %ls\n", osname,
1574 osversion.dwMajorVersion, osversion.dwMinorVersion,
1575 osversion.dwPlatformId == VER_PLATFORM_WIN32_NT ?
1576 osversion.dwBuildNumber : (osversion.dwBuildNumber & 0xffff),
1577 osversion.dwPlatformId == VER_PLATFORM_WIN32_NT ?
1578 osversion.szCSDVersion : L"");
1579
1580 if (osversion.dwPlatformId == VER_PLATFORM_WIN32s
1581 || osversion.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
1582 exit (EXIT_FAILURE);
1583
1584 BOOL is_wow64 = FALSE;
1585 if (IsWow64Process (GetCurrentProcess (), &is_wow64) && is_wow64)
1586 {
1587 SYSTEM_INFO natinfo;
1588 GetNativeSystemInfo (&natinfo);
1589 fputs ("\nRunning under WOW64 on ", stdout);
1590 switch (natinfo.wProcessorArchitecture)
1591 {
1592 case PROCESSOR_ARCHITECTURE_IA64:
1593 puts ("IA64");
1594 break;
1595 case PROCESSOR_ARCHITECTURE_AMD64:
1596 puts ("AMD64");
1597 break;
1598 default:
1599 puts("??");
1600 break;
1601 }
1602 }
1603
1604 if (GetSystemMetrics (SM_REMOTESESSION))
1605 printf ("\nRunning in Terminal Service session\n");
1606
1607 printf ("\nPath:");
1608 char *s = getenv ("PATH"), *e;
1609 if (!s)
1610 puts ("");
1611 else
1612 {
1613 char sep = strchr (s, ';') ? ';' : ':';
1614 int count_path_items = 0;
1615 while (1)
1616 {
1617 for (e = s; *e && *e != sep; e++);
1618 if (e-s)
1619 printf ("\t%.*s\n", (int) (e - s), s);
1620 else
1621 puts ("\t.");
1622 count_path_items++;
1623 if (!*e)
1624 break;
1625 s = e + 1;
1626 }
1627 }
1628
1629 fflush (stdout);
1630
1631 pretty_id ();
1632
1633 if (!GetSystemDirectory (tmp, 4000))
1634 display_error ("dump_sysinfo: GetSystemDirectory()");
1635 printf ("\nSysDir: %s\n", tmp);
1636
1637 GetWindowsDirectory (tmp, 4000);
1638 printf ("WinDir: %s\n\n", tmp);
1639
1640
1641 if (givehelp)
1642 printf ("Here's some environment variables that may affect cygwin:\n");
1643 for (i = 0; environ[i]; i++)
1644 {
1645 char *eq = strchr (environ[i], '=');
1646 if (!eq)
1647 continue;
1648 /* int len = eq - environ[i]; */
1649 for (j = 0; known_env_vars[j]; j++)
1650 {
1651 *eq = 0;
1652 if (strcmp (environ[i], "PATH") == 0)
1653 continue; /* we handle this one specially */
1654 if (strcasecmp (environ[i], known_env_vars[j]) == 0)
1655 printf ("%s = '%s'\n", environ[i], eq + 1);
1656 *eq = '=';
1657 }
1658 }
1659 printf ("\n");
1660
1661 if (verbose)
1662 {
1663 if (givehelp)
1664 printf ("Here's the rest of your environment variables:\n");
1665 for (i = 0; environ[i]; i++)
1666 {
1667 int found = 0;
1668 char *eq = strchr (environ[i], '=');
1669 if (!eq)
1670 continue;
1671 /* int len = eq - environ[i]; */
1672 for (j = 0; known_env_vars[j]; j++)
1673 {
1674 *eq = 0;
1675 if (strcasecmp (environ[i], known_env_vars[j]) == 0)
1676 found = 1;
1677 *eq = '=';
1678 }
1679 if (!found)
1680 {
1681 *eq = 0;
1682 printf ("%s = '%s'\n", environ[i], eq + 1);
1683 *eq = '=';
1684 }
1685 }
1686 printf ("\n");
1687 }
1688
1689 if (registry)
1690 {
1691 if (givehelp)
1692 printf ("Scanning registry for keys with 'Cygwin' in them...\n");
1693 scan_registry (0, HKEY_CURRENT_USER,
1694 (char *) "HKEY_CURRENT_USER", 0, false);
1695 scan_registry (0, HKEY_LOCAL_MACHINE,
1696 (char *) "HKEY_LOCAL_MACHINE", 0, false);
1697 printf ("\n");
1698 }
1699 else
1700 printf ("Use '-r' to scan registry\n\n");
1701
1702 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE,
1703 "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\kernel",
1704 0, KEY_READ, &key) == ERROR_SUCCESS)
1705 {
1706 DWORD size;
1707 RegQueryValueEx (key, "obcaseinsensitive", NULL, NULL,
1708 (LPBYTE) &obcaseinsensitive, &size);
1709 RegCloseKey (key);
1710 }
1711 printf ("obcaseinsensitive set to %lu\n\n", obcaseinsensitive);
1712
1713 print_reg_installations ();
1714
1715 if (givehelp)
1716 {
1717 printf ("Listing available drives...\n");
1718 printf ("Drv Type Size Used Flags Name\n");
1719 }
1720 int prev_mode =
1721 SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
1722 int drivemask = GetLogicalDrives ();
1723
1724 for (i = 0; i < 26; i++)
1725 {
1726 if (!(drivemask & (1 << i)))
1727 continue;
1728 char drive[4], name[200], fsname[200];
1729 DWORD serno = 0, maxnamelen = 0, flags = 0;
1730 name[0] = fsname[0] = 0;
1731 sprintf (drive, "%c:\\", i + 'a');
1732 /* Report all errors, except if the Volume is ERROR_NOT_READY.
1733 ERROR_NOT_READY is returned when removeable media drives are empty
1734 (CD, floppy, etc.) */
1735 if (!GetVolumeInformation (drive, name, sizeof (name), &serno,
1736 &maxnamelen, &flags, fsname,
1737 sizeof (fsname))
1738 && GetLastError () != ERROR_NOT_READY)
1739 {
1740 # define FMT "dump_sysinfo: GetVolumeInformation() for drive %c:"
1741 char buf[sizeof (FMT)];
1742 sprintf (buf, FMT, 'A' + i);
1743 display_error (buf);
1744 # undef FMT
1745 }
1746
1747 int dtype = GetDriveType (drive);
1748 char drive_type[4] = "unk";
1749 switch (dtype)
1750 {
1751 case DRIVE_REMOVABLE:
1752 strcpy (drive_type, "fd ");
1753 break;
1754 case DRIVE_FIXED:
1755 strcpy (drive_type, "hd ");
1756 break;
1757 case DRIVE_REMOTE:
1758 strcpy (drive_type, "net");
1759 break;
1760 case DRIVE_CDROM:
1761 strcpy (drive_type, "cd ");
1762 break;
1763 case DRIVE_RAMDISK:
1764 strcpy (drive_type, "ram");
1765 break;
1766 default:
1767 strcpy (drive_type, "unk");
1768 }
1769
1770 long capacity_mb = -1;
1771 int percent_full = -1;
1772
1773 ULARGE_INTEGER free_me, free_bytes, total_bytes;
1774 free_me.QuadPart = free_bytes.QuadPart = 0ULL;
1775 total_bytes.QuadPart = 1ULL;
1776 if (GetDiskFreeSpaceEx (drive, &free_me, &total_bytes, &free_bytes))
1777 {
1778 capacity_mb = total_bytes.QuadPart / (1024L * 1024L);
1779 percent_full = 100 - (int) ((100.0 * free_me.QuadPart)
1780 / total_bytes.QuadPart);
1781 }
1782 else
1783 {
1784 DWORD spc = 0, bps = 0, fc = 0, tc = 1;
1785 if (GetDiskFreeSpace (drive, &spc, &bps, &fc, &tc))
1786 {
1787 capacity_mb = (spc * bps * tc) / (1024 * 1024);
1788 percent_full = 100 - (int) ((100.0 * fc) / tc);
1789 }
1790 }
1791
1792 printf ("%.2s %s %-6s ", drive, drive_type, fsname);
1793 if (capacity_mb >= 0)
1794 printf ("%7dMb %3d%% ", (int) capacity_mb, (int) percent_full);
1795 else
1796 printf (" N/A N/A ");
1797 printf ("%s %s %s %s %s %s %s\n",
1798 flags & FS_CASE_IS_PRESERVED ? "CP" : " ",
1799 flags & FS_CASE_SENSITIVE ? "CS" : " ",
1800 flags & FS_UNICODE_STORED_ON_DISK ? "UN" : " ",
1801 flags & FS_PERSISTENT_ACLS ? "PA" : " ",
1802 flags & FS_FILE_COMPRESSION ? "FC" : " ",
1803 flags & FS_VOL_IS_COMPRESSED ? "VC" : " ",
1804 flags & FILE_SUPPORTS_ENCRYPTION ? "EN" : " ",
1805 flags & FILE_SUPPORTS_OBJECT_IDS ? "OI" : " ",
1806 flags & FILE_SUPPORTS_REPARSE_POINTS ? "RP" : " ",
1807 flags & FILE_SUPPORTS_SPARSE_FILES ? "SP" : " ",
1808 flags & FILE_VOLUME_QUOTAS ? "QU" : " ",
1809 name);
1810 }
1811
1812 SetErrorMode (prev_mode);
1813 if (givehelp)
1814 {
1815 puts ("\n"
1816 "fd = floppy, hd = hard drive, cd = CD-ROM\n"
1817 "net= Network Share, ram= RAM drive, unk= Unknown\n"
1818 "CP = Case Preserving, CS = Case Sensitive, UN = Unicode\n"
1819 "PA = Persistent ACLS, FC = File Compression, VC = Volume Compression");
1820 }
1821 printf ("\n");
1822
1823 unsigned ml_fsname = 4, ml_dir = 7, ml_type = 6;
1824 bool ml_trailing = false;
1825
1826 struct mntent *mnt;
1827 setmntent (0, 0);
1828 while ((mnt = getmntent (0)))
1829 {
1830 unsigned n = (int) strlen (mnt->mnt_fsname);
1831 ml_trailing |= (n > 1 && strchr ("\\/", mnt->mnt_fsname[n - 1]));
1832 if (ml_fsname < n)
1833 ml_fsname = n;
1834 n = (int) strlen (mnt->mnt_dir);
1835 ml_trailing |= (n > 1 && strchr ("\\/", mnt->mnt_dir[n - 1]));
1836 if (ml_dir < n)
1837 ml_dir = n;
1838 }
1839
1840 if (ml_trailing)
1841 puts ("Warning: Mount entries should not have a trailing (back)slash\n");
1842
1843 if (givehelp)
1844 {
1845 printf
1846 ("Mount entries: these map POSIX directories to your NT drives.\n");
1847 printf ("%-*s %-*s %-*s %s\n", ml_fsname, "-NT-", ml_dir, "-POSIX-",
1848 ml_type, "-Type-", "-Flags-");
1849 }
1850
1851 setmntent (0, 0);
1852 while ((mnt = getmntent (0)))
1853 {
1854 printf ("%-*s %-*s %-*s %s\n",
1855 ml_fsname, mnt->mnt_fsname,
1856 ml_dir, mnt->mnt_dir, ml_type, mnt->mnt_type, mnt->mnt_opts);
1857 }
1858 printf ("\n");
1859
1860 if (givehelp)
1861 printf
1862 ("Looking to see where common programs can be found, if at all...\n");
1863 for (i = 0; common_apps[i].name; i++)
1864 if (!find_app_on_path ((char *) common_apps[i].name, 1))
1865 {
1866 if (common_apps[i].missing_is_good)
1867 printf ("Not Found: %s (good!)\n", common_apps[i].name);
1868 else
1869 printf ("Not Found: %s\n", common_apps[i].name);
1870 }
1871 printf ("\n");
1872
1873 if (givehelp)
1874 printf ("Looking for various Cygwin DLLs... (-v gives version info)\n");
1875 int cygwin_dll_count = 0;
1876 char cygdll_path[32768];
1877 for (pathlike *pth = paths; pth->dir; pth++)
1878 {
1879 WIN32_FIND_DATAW ffinfo;
1880 sprintf (tmp, "%s*.*", pth->dir);
1881 wide_path wpath (tmp);
1882 HANDLE ff = FindFirstFileW (wpath, &ffinfo);
1883 int found = (ff != INVALID_HANDLE_VALUE);
1884 found_cygwin_dll = NULL;
1885 while (found)
1886 {
1887 char f[FILENAME_MAX + 1];
1888 wcstombs (f, ffinfo.cFileName, sizeof f);
1889 if (strcasecmp (f + strlen (f) - 4, ".dll") == 0)
1890 {
1891 if (strncasecmp (f, "cyg", 3) == 0)
1892 {
1893 sprintf (tmp, "%s%s", pth->dir, f);
1894 if (strcasecmp (f, "cygwin1.dll") == 0)
1895 {
1896 if (!cygwin_dll_count)
1897 strcpy (cygdll_path, pth->dir);
1898 if (!cygwin_dll_count
1899 || strcasecmp (cygdll_path, pth->dir) != 0)
1900 cygwin_dll_count++;
1901 found_cygwin_dll = strdup (tmp);
1902 }
1903 else
1904 ls (tmp);
1905 }
1906 }
1907 found = FindNextFileW (ff, &ffinfo);
1908 }
1909 if (found_cygwin_dll)
1910 {
1911 ls (found_cygwin_dll);
1912 free (found_cygwin_dll);
1913 }
1914
1915 FindClose (ff);
1916 }
1917 if (cygwin_dll_count > 1)
1918 puts ("Warning: There are multiple cygwin1.dlls on your path");
1919 if (!cygwin_dll_count)
1920 puts ("Warning: cygwin1.dll not found on your path");
1921
1922 dump_dodgy_apps (verbose);
1923
1924 if (is_nt)
1925 dump_sysinfo_services ();
1926 }
1927
1928 static int
1929 check_keys ()
1930 {
1931 HANDLE h = CreateFileW (L"CONIN$", GENERIC_READ | GENERIC_WRITE,
1932 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1933 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1934
1935 if (h == INVALID_HANDLE_VALUE || h == NULL)
1936 return (display_error ("check_keys: Opening CONIN$"));
1937
1938 DWORD mode;
1939
1940 if (!GetConsoleMode (h, &mode))
1941 display_error ("check_keys: GetConsoleMode()");
1942 else
1943 {
1944 mode &= ~ENABLE_PROCESSED_INPUT;
1945 if (!SetConsoleMode (h, mode))
1946 display_error ("check_keys: SetConsoleMode()");
1947 }
1948
1949 fputs ("\nThis key check works only in a console window,", stderr);
1950 fputs (" _NOT_ in a terminal session!\n", stderr);
1951 fputs ("Abort with Ctrl+C if in a terminal session.\n\n", stderr);
1952 fputs ("Press 'q' to exit.\n", stderr);
1953
1954 INPUT_RECORD in, prev_in;
1955
1956 // Drop first <RETURN> key
1957 ReadConsoleInputW (h, &in, 1, &mode);
1958
1959 memset (&in, 0, sizeof in);
1960
1961 do
1962 {
1963 prev_in = in;
1964 if (!ReadConsoleInputW (h, &in, 1, &mode))
1965 display_error ("check_keys: ReadConsoleInput()");
1966
1967 if (!memcmp (&in, &prev_in, sizeof in))
1968 continue;
1969
1970 switch (in.EventType)
1971 {
1972 case KEY_EVENT:
1973 printf ("%s %ux VK: 0x%04x VS: 0x%04x C: 0x%04x CTRL: ",
1974 in.Event.KeyEvent.bKeyDown ? "Pressed " : "Released",
1975 in.Event.KeyEvent.wRepeatCount,
1976 in.Event.KeyEvent.wVirtualKeyCode,
1977 in.Event.KeyEvent.wVirtualScanCode,
1978 (unsigned char) in.Event.KeyEvent.uChar.UnicodeChar);
1979 fputs (in.Event.KeyEvent.dwControlKeyState & CAPSLOCK_ON ?
1980 "CL " : "-- ", stdout);
1981 fputs (in.Event.KeyEvent.dwControlKeyState & ENHANCED_KEY ?
1982 "EK " : "-- ", stdout);
1983 fputs (in.Event.KeyEvent.dwControlKeyState & LEFT_ALT_PRESSED ?
1984 "LA " : "-- ", stdout);
1985 fputs (in.Event.KeyEvent.dwControlKeyState & LEFT_CTRL_PRESSED ?
1986 "LC " : "-- ", stdout);
1987 fputs (in.Event.KeyEvent.dwControlKeyState & NUMLOCK_ON ?
1988 "NL " : "-- ", stdout);
1989 fputs (in.Event.KeyEvent.dwControlKeyState & RIGHT_ALT_PRESSED ?
1990 "RA " : "-- ", stdout);
1991 fputs (in.Event.KeyEvent.dwControlKeyState & RIGHT_CTRL_PRESSED ?
1992 "RC " : "-- ", stdout);
1993 fputs (in.Event.KeyEvent.dwControlKeyState & SCROLLLOCK_ON ?
1994 "SL " : "-- ", stdout);
1995 fputs (in.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED ?
1996 "SH " : "-- ", stdout);
1997 fputc ('\n', stdout);
1998 break;
1999
2000 default:
2001 break;
2002 }
2003 }
2004 while (in.EventType != KEY_EVENT ||
2005 in.Event.KeyEvent.bKeyDown != FALSE ||
2006 in.Event.KeyEvent.uChar.UnicodeChar != L'q');
2007
2008 CloseHandle (h);
2009 return 0;
2010 }
2011
2012 /* RFC1738 says that these do not need to be escaped. */
2013 static const char safe_chars[] = "$-_.+!*'(),";
2014
2015 /* the URL to query. */
2016 static const char base_url[] =
2017 "http://cygwin.com/cgi-bin2/package-grep.cgi?text=1&grep=";
2018
2019 #ifdef __x86_64__
2020 #define ARCH_STR "&arch=x86_64"
2021 #else
2022 #define ARCH_STR "&arch=x86"
2023 #endif
2024 static const char *ARCH_str = ARCH_STR;
2025
2026 /* Queries Cygwin web site for packages containing files matching a regexp.
2027 Return value is 1 if there was a problem, otherwise 0. */
2028 static int
2029 package_grep (char *search)
2030 {
2031 char buf[1024];
2032
2033 /* construct the actual URL by escaping */
2034 char *url = (char *) alloca (sizeof (base_url) + strlen (ARCH_str)
2035 + strlen (search) * 3);
2036 strcpy (url, base_url);
2037
2038 char *dest;
2039 for (dest = &url[sizeof (base_url) - 1]; *search; search++)
2040 {
2041 if (isalnum (*search)
2042 || memchr (safe_chars, *search, sizeof (safe_chars) - 1))
2043 {
2044 *dest++ = *search;
2045 }
2046 else
2047 {
2048 *dest++ = '%';
2049 sprintf (dest, "%02x", (unsigned char) *search);
2050 dest += 2;
2051 }
2052 }
2053 strcpy (dest, ARCH_str);
2054
2055 /* Connect to the net and open the URL. */
2056 if (InternetAttemptConnect (0) != ERROR_SUCCESS)
2057 {
2058 fputs ("An internet connection is required for this function.\n", stderr);
2059 return 1;
2060 }
2061
2062 /* Initialize WinInet and attempt to fetch our URL. */
2063 HINTERNET hi = NULL, hurl = NULL;
2064 if (!(hi = InternetOpenA ("cygcheck", INTERNET_OPEN_TYPE_PRECONFIG,
2065 NULL, NULL, 0)))
2066 return display_internet_error ("InternetOpen() failed", NULL);
2067
2068 if (!(hurl = InternetOpenUrlA (hi, url, NULL, 0, 0, 0)))
2069 return display_internet_error ("unable to contact cygwin.com site, "
2070 "InternetOpenUrl() failed", hi, NULL);
2071
2072 /* Check the HTTP response code. */
2073 DWORD rc = 0, rc_s = sizeof (DWORD);
2074 if (!HttpQueryInfoA (hurl, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER,
2075 (void *) &rc, &rc_s, NULL))
2076 return display_internet_error ("HttpQueryInfo() failed", hurl, hi, NULL);
2077
2078 if (rc != HTTP_STATUS_OK)
2079 {
2080 sprintf (buf, "error retrieving results from cygwin.com site, "
2081 "HTTP status code %lu", rc);
2082 return display_internet_error (buf, hurl, hi, NULL);
2083 }
2084
2085 /* Fetch result and print to stdout. */
2086 DWORD numread;
2087 do
2088 {
2089 if (!InternetReadFile (hurl, (void *) buf, sizeof (buf), &numread))
2090 return display_internet_error ("InternetReadFile failed", hurl, hi, NULL);
2091 if (numread)
2092 fwrite ((void *) buf, (size_t) numread, 1, stdout);
2093 }
2094 while (numread);
2095
2096 InternetCloseHandle (hurl);
2097 InternetCloseHandle (hi);
2098 return 0;
2099 }
2100
2101 static void
2102 usage (FILE * stream, int status)
2103 {
2104 fprintf (stream, "\
2105 Usage: cygcheck [-v] [-h] PROGRAM\n\
2106 cygcheck -c [-d] [PACKAGE]\n\
2107 cygcheck -s [-r] [-v] [-h]\n\
2108 cygcheck -k\n\
2109 cygcheck -f FILE [FILE]...\n\
2110 cygcheck -l [PACKAGE]...\n\
2111 cygcheck -p REGEXP\n\
2112 cygcheck --delete-orphaned-installation-keys\n\
2113 cygcheck -h\n\n\
2114 List system information, check installed packages, or query package database.\n\
2115 \n\
2116 At least one command option or a PROGRAM is required, as shown above.\n\
2117 \n\
2118 PROGRAM list library (DLL) dependencies of PROGRAM\n\
2119 -c, --check-setup show installed version of PACKAGE and verify integrity\n\
2120 (or for all installed packages if none specified)\n\
2121 -d, --dump-only just list packages, do not verify (with -c)\n\
2122 -s, --sysinfo produce diagnostic system information (implies -c)\n\
2123 -r, --registry also scan registry for Cygwin settings (with -s)\n\
2124 -k, --keycheck perform a keyboard check session (must be run from a\n\
2125 plain console only, not from a pty/rxvt/xterm)\n\
2126 -f, --find-package find the package to which FILE belongs\n\
2127 -l, --list-package list contents of PACKAGE (or all packages if none given)\n\
2128 -p, --package-query search for REGEXP in the entire cygwin.com package\n\
2129 repository (requires internet connectivity)\n\
2130 --delete-orphaned-installation-keys\n\
2131 Delete installation keys of old, now unused\n\
2132 installations from the registry. Requires the right\n\
2133 to change the registry.\n\
2134 -v, --verbose produce more verbose output\n\
2135 -h, --help annotate output with explanatory comments when given\n\
2136 with another command, otherwise print this help\n\
2137 -V, --version print the version of cygcheck and exit\n\
2138 \n\
2139 Note: -c, -f, and -l only report on packages that are currently installed. To\n\
2140 search all official Cygwin packages use -p instead. The -p REGEXP matches\n\
2141 package names, descriptions, and names of files/paths within all packages.\n\
2142 \n");
2143 exit (status);
2144 }
2145
2146 struct option longopts[] = {
2147 {"check-setup", no_argument, NULL, 'c'},
2148 {"dump-only", no_argument, NULL, 'd'},
2149 {"sysinfo", no_argument, NULL, 's'},
2150 {"registry", no_argument, NULL, 'r'},
2151 {"verbose", no_argument, NULL, 'v'},
2152 {"keycheck", no_argument, NULL, 'k'},
2153 {"find-package", no_argument, NULL, 'f'},
2154 {"list-package", no_argument, NULL, 'l'},
2155 {"package-query", no_argument, NULL, 'p'},
2156 {"delete-orphaned-installation-keys", no_argument, NULL, CO_DELETE_KEYS},
2157 {"help", no_argument, NULL, 'h'},
2158 {"version", no_argument, 0, 'V'},
2159 {0, no_argument, NULL, 0}
2160 };
2161
2162 static char opts[] = "cdsrvkflphV";
2163
2164 static void
2165 print_version ()
2166 {
2167 printf ("cygcheck (cygwin) %d.%d.%d\n"
2168 "System Checker for Cygwin\n"
2169 "Copyright (C) 1998 - %s Cygwin Authors\n"
2170 "This is free software; see the source for copying conditions. "
2171 "There is NO\n"
2172 "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR "
2173 "PURPOSE.\n",
2174 CYGWIN_VERSION_DLL_MAJOR / 1000,
2175 CYGWIN_VERSION_DLL_MAJOR % 1000,
2176 CYGWIN_VERSION_DLL_MINOR,
2177 strrchr (__DATE__, ' ') + 1);
2178 }
2179
2180 void
2181 nuke (char *ev)
2182 {
2183 int n = 1 + strchr (ev, '=') - ev;
2184 char *s = (char *) malloc (n + 1);
2185 memcpy (s, ev, n);
2186 s[n] = '\0';
2187 putenv (s);
2188 }
2189
2190 extern "C" {
2191 uintptr_t (*cygwin_internal) (int, ...);
2192 WCHAR cygwin_dll_path[32768];
2193 };
2194
2195 static void
2196 load_cygwin (int& argc, char **&argv)
2197 {
2198 HMODULE h;
2199
2200 if (!(h = LoadLibrary ("cygwin1.dll")))
2201 return;
2202 GetModuleFileNameW (h, cygwin_dll_path, 32768);
2203 if ((cygwin_internal = (uintptr_t (*) (int, ...))
2204 GetProcAddress (h, "cygwin_internal")))
2205 {
2206 char **av = (char **) cygwin_internal (CW_ARGV);
2207 if (av && ((uintptr_t) av != (uintptr_t) -1))
2208 {
2209 /* Copy cygwin's idea of the argument list into this Window
2210 application. */
2211 for (argc = 0; av[argc]; argc++)
2212 continue;
2213 argv = (char **) calloc (argc + 1, sizeof (char *));
2214 for (char **argvp = argv; *av; av++)
2215 *argvp++ = strdup (*av);
2216 }
2217
2218
2219 char **envp = (char **) cygwin_internal (CW_ENVP);
2220 if (envp && ((uintptr_t) envp != (uintptr_t) -1))
2221 {
2222 /* Store path and revert to this value, otherwise path gets
2223 overwritten by the POSIXy Cygwin variation, which breaks cygcheck.
2224 Another approach would be to use the Cygwin PATH and convert it to
2225 Win32 again. */
2226 char *path = NULL;
2227 char **env;
2228 while (*(env = _environ))
2229 {
2230 if (strncmp (*env, "PATH=", 5) == 0)
2231 path = strdup (*env);
2232 nuke (*env);
2233 }
2234 for (char **ev = envp; *ev; ev++)
2235 if (strncmp (*ev, "PATH=", 5) != 0)
2236 putenv (strdup (*ev));
2237 if (path)
2238 putenv (path);
2239 }
2240 }
2241 /* GDB chokes when the DLL got unloaded and, for some reason, fails to set
2242 any breakpoint after the fact. */
2243 if (!IsDebuggerPresent ())
2244 FreeLibrary (h);
2245 }
2246
2247 int
2248 main (int argc, char **argv)
2249 {
2250 int i;
2251 bool ok = true;
2252 load_cygwin (argc, argv);
2253
2254 /* Need POSIX sorting while parsing args, but don't forget the
2255 user's original environment. */
2256 char *posixly = getenv ("POSIXLY_CORRECT");
2257 if (posixly == NULL)
2258 (void) putenv ("POSIXLY_CORRECT=1");
2259 while ((i = getopt_long (argc, argv, opts, longopts, NULL)) != EOF)
2260 switch (i)
2261 {
2262 case 's':
2263 sysinfo = 1;
2264 break;
2265 case 'c':
2266 check_setup = 1;
2267 break;
2268 case 'd':
2269 dump_only = 1;
2270 break;
2271 case 'r':
2272 registry = 1;
2273 break;
2274 case 'v':
2275 verbose = 1;
2276 break;
2277 case 'k':
2278 keycheck = 1;
2279 break;
2280 case 'f':
2281 find_package = 1;
2282 break;
2283 case 'l':
2284 list_package = 1;
2285 break;
2286 case 'p':
2287 grep_packages = 1;
2288 break;
2289 case 'h':
2290 givehelp = 1;
2291 break;
2292 case CO_DELETE_KEYS:
2293 del_orphaned_reg = 1;
2294 break;
2295 case 'V':
2296 print_version ();
2297 exit (0);
2298 default:
2299 fprintf (stderr, "Try `cygcheck --help' for more information.\n");
2300 exit (1);
2301 /*NOTREACHED*/
2302 }
2303 argc -= optind;
2304 argv += optind;
2305 if (posixly == NULL)
2306 putenv ("POSIXLY_CORRECT=");
2307
2308 if ((argc == 0) && !sysinfo && !keycheck && !check_setup && !list_package
2309 && !del_orphaned_reg)
2310 {
2311 if (givehelp)
2312 usage (stdout, 0);
2313 else
2314 usage (stderr, 1);
2315 }
2316
2317 if ((check_setup || sysinfo || find_package || list_package || grep_packages
2318 || del_orphaned_reg)
2319 && keycheck)
2320 usage (stderr, 1);
2321
2322 if ((find_package || list_package || grep_packages)
2323 && (check_setup || del_orphaned_reg))
2324 usage (stderr, 1);
2325
2326 if (dump_only && !check_setup && !sysinfo)
2327 usage (stderr, 1);
2328
2329 if (find_package + list_package + grep_packages > 1)
2330 usage (stderr, 1);
2331
2332 if (keycheck)
2333 return check_keys ();
2334 if (del_orphaned_reg)
2335 del_orphaned_reg_installations ();
2336 if (grep_packages)
2337 return package_grep (*argv);
2338
2339 init_paths ();
2340
2341 /* FIXME: Add help for check_setup and {list,find}_package */
2342 if (argc >= 1 && givehelp && !check_setup && !find_package && !list_package)
2343 {
2344 printf("Here is where the OS will find your program%s, and which dlls\n",
2345 argc > 1 ? "s" : "");
2346 printf ("will be used for it. Use -v to see DLL version info\n");
2347
2348 if (!sysinfo)
2349 printf ("\n");
2350 }
2351
2352 if (check_setup)
2353 dump_setup (verbose, argv, !dump_only);
2354 else if (find_package)
2355 package_find (verbose, argv);
2356 else if (list_package)
2357 package_list (verbose, argv);
2358 else
2359 for (i = 0; i < argc; i++)
2360 {
2361 if (i)
2362 puts ("");
2363 ok &= cygcheck (argv[i]);
2364 }
2365
2366 if (sysinfo)
2367 {
2368 dump_sysinfo ();
2369 if (!check_setup)
2370 {
2371 puts ("");
2372 dump_setup (verbose, NULL, !dump_only);
2373 }
2374
2375 if (!givehelp)
2376 puts ("Use -h to see help about each section");
2377 }
2378
2379 return ok ? EXIT_SUCCESS : EXIT_FAILURE;
2380 }
This page took 0.14966 seconds and 6 git commands to generate.