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