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