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