]> sourceware.org Git - newlib-cygwin.git/blob - winsup/utils/cygcheck.cc
* Makefile.in (cygcheck.exe): Do not link against libwininet.a.
[newlib-cygwin.git] / winsup / utils / cygcheck.cc
1 /* cygcheck.cc
2
3 Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Red Hat, Inc.
4
5 This file is part of Cygwin.
6
7 This software is a copyrighted work licensed under the terms of the
8 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
9 details. */
10
11 #define cygwin_internal cygwin_internal_dontuse
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <stdarg.h>
15 #include <string.h>
16 #include <sys/time.h>
17 #include <ctype.h>
18 #include <io.h>
19 #include <windows.h>
20 #include <wininet.h>
21 #include "path.h"
22 #include <getopt.h>
23 #include "cygwin/include/sys/cygwin.h"
24 #include "cygwin/include/mntent.h"
25 #undef cygwin_internal
26
27 #define alloca __builtin_alloca
28
29 int verbose = 0;
30 int registry = 0;
31 int sysinfo = 0;
32 int givehelp = 0;
33 int keycheck = 0;
34 int check_setup = 0;
35 int dump_only = 0;
36 int find_package = 0;
37 int list_package = 0;
38 int grep_packages = 0;
39
40 /* This is global because it's used in both internet_display_error as well
41 as package_grep. */
42 BOOL (WINAPI *pInternetCloseHandle) (HINTERNET);
43
44 #ifdef __GNUC__
45 typedef long long longlong;
46 #else
47 typedef __int64 longlong;
48 #endif
49
50 void dump_setup (int, char **, bool);
51 void package_find (int, char **);
52 void package_list (int, char **);
53
54 static const char version[] = "$Revision$";
55
56 static const char *known_env_vars[] = {
57 "c_include_path",
58 "compiler_path",
59 "cxx_include_path",
60 "cygwin",
61 "cygwin32",
62 "dejagnu",
63 "expect",
64 "gcc_default_options",
65 "gcc_exec_prefix",
66 "home",
67 "ld_library_path",
68 "library_path",
69 "login",
70 "lpath",
71 "make_mode",
72 "makeflags",
73 "path",
74 "pwd",
75 "strace",
76 "tcl_library",
77 "user",
78 0
79 };
80
81 struct
82 {
83 const char *name;
84 int missing_is_good;
85 }
86 static common_apps[] = {
87 {"awk", 0},
88 {"bash", 0},
89 {"cat", 0},
90 {"cp", 0},
91 {"cpp", 1},
92 {"crontab", 0},
93 {"find", 0},
94 {"gcc", 0},
95 {"gdb", 0},
96 {"grep", 0},
97 {"kill", 0},
98 {"ld", 0},
99 {"ls", 0},
100 {"make", 0},
101 {"mv", 0},
102 {"perl", 0},
103 {"rm", 0},
104 {"sed", 0},
105 {"ssh", 0},
106 {"sh", 0},
107 {"tar", 0},
108 {"test", 0},
109 {"vi", 0},
110 {"vim", 0},
111 {0, 0}
112 };
113
114 static int num_paths = 0, max_paths = 0;
115 static char **paths = 0;
116
117 void
118 eprintf (const char *format, ...)
119 {
120 va_list ap;
121 va_start (ap, format);
122 vfprintf (stderr, format, ap);
123 va_end (ap);
124 }
125
126 /*
127 * display_error() is used to report failure modes
128 */
129 static int
130 display_error (const char *name, bool show_error = true, bool print_failed = true)
131 {
132 if (show_error)
133 fprintf (stderr, "cygcheck: %s%s: %lu\n", name,
134 print_failed ? " failed" : "", GetLastError ());
135 else
136 fprintf (stderr, "cygcheck: %s%s\n", name,
137 print_failed ? " failed" : "");
138 return 1;
139 }
140
141 /* Display a WinInet error message, and close a variable number of handles.
142 (Passed a list of handles terminated by NULL.) */
143 static int
144 display_internet_error (const char *message, ...)
145 {
146 DWORD err = GetLastError ();
147 TCHAR err_buf[256];
148 va_list hptr;
149 HINTERNET h;
150
151 /* in the case of a successful connection but 404 response, there is no
152 win32 error message, but we still get passed a message to display. */
153 if (err)
154 {
155 if (FormatMessage (FORMAT_MESSAGE_FROM_HMODULE,
156 GetModuleHandle ("wininet.dll"), err, 0, err_buf,
157 sizeof (err_buf), NULL) == 0)
158 strcpy (err_buf, "(Unknown error)");
159
160 fprintf (stderr, "cygcheck: %s: %s (win32 error %d)\n", message,
161 err_buf, err);
162 }
163 else
164 fprintf (stderr, "cygcheck: %s\n", message);
165
166 va_start (hptr, message);
167 while ((h = va_arg (hptr, HINTERNET)) != 0)
168 pInternetCloseHandle (h);
169 va_end (hptr);
170
171 return 1;
172 }
173
174 static void
175 add_path (char *s, int maxlen)
176 {
177 if (num_paths >= max_paths)
178 {
179 max_paths += 10;
180 if (paths)
181 paths = (char **) realloc (paths, max_paths * sizeof (char *));
182 else
183 paths = (char **) malloc (max_paths * sizeof (char *));
184 }
185 paths[num_paths] = (char *) malloc (maxlen + 1);
186 if (paths[num_paths] == NULL)
187 {
188 display_error ("add_path: malloc()");
189 return;
190 }
191 memcpy (paths[num_paths], s, maxlen);
192 paths[num_paths][maxlen] = 0;
193 char *e = paths[num_paths] + strlen (paths[num_paths]);
194 if (e[-1] == '\\' && e[-2] != ':')
195 *--e = 0;
196 for (int i = 1; i < num_paths; i++)
197 if (strcasecmp (paths[num_paths], paths[i]) == 0)
198 {
199 free (paths[num_paths]);
200 return;
201 }
202 num_paths++;
203 }
204
205 static void
206 init_paths ()
207 {
208 char tmp[4000], *sl;
209 add_path ((char *) ".", 1); /* to be replaced later */
210
211 if (GetCurrentDirectory (4000, tmp))
212 add_path (tmp, strlen (tmp));
213 else
214 display_error ("init_paths: GetCurrentDirectory()");
215
216 if (GetSystemDirectory (tmp, 4000))
217 add_path (tmp, strlen (tmp));
218 else
219 display_error ("init_paths: GetSystemDirectory()");
220 sl = strrchr (tmp, '\\');
221 if (sl)
222 {
223 strcpy (sl, "\\SYSTEM");
224 add_path (tmp, strlen (tmp));
225 }
226 GetWindowsDirectory (tmp, 4000);
227 add_path (tmp, strlen (tmp));
228
229 char *wpath = getenv ("PATH");
230 if (wpath)
231 {
232 char *b, *e;
233 b = wpath;
234 while (1)
235 {
236 for (e = b; *e && *e != ';'; e++);
237 if (strncmp(b, ".", 1) && strncmp(b, ".\\", 2))
238 add_path (b, e - b);
239 if (!*e)
240 break;
241 b = e + 1;
242 }
243 }
244 else
245 printf ("WARNING: PATH is not set at all!\n");
246 }
247
248 static char *
249 find_on_path (char *file, char *default_extension,
250 int showall = 0, int search_sysdirs = 0)
251 {
252 static char rv[4000];
253 char tmp[4000], *ptr = rv;
254
255 if (!file)
256 {
257 display_error ("find_on_path: NULL pointer for file", false, false);
258 return 0;
259 }
260
261 if (default_extension == NULL)
262 {
263 display_error ("find_on_path: NULL pointer for default_extension", false, false);
264 return 0;
265 }
266
267 if (strchr (file, ':') || strchr (file, '\\') || strchr (file, '/'))
268 {
269 char *fn = cygpath (file, NULL);
270 if (access (fn, F_OK) == 0)
271 return fn;
272 strcpy (rv, fn);
273 strcat (rv, default_extension);
274 return access (rv, F_OK) == 0 ? rv : fn;
275 }
276
277 if (strchr (file, '.'))
278 default_extension = (char *) "";
279
280 for (int i = 0; i < num_paths; i++)
281 {
282 if (!search_sysdirs && (i == 0 || i == 2 || i == 3))
283 continue;
284 if (i == 0 || !search_sysdirs || strcasecmp (paths[i], paths[0]))
285 {
286 sprintf (ptr, "%s\\%s%s", paths[i], file, default_extension);
287 if (GetFileAttributes (ptr) != (DWORD) - 1)
288 {
289 if (showall)
290 printf ("Found: %s\n", ptr);
291 if (ptr == tmp && verbose)
292 printf ("Warning: %s hides %s\n", rv, ptr);
293 ptr = tmp;
294 }
295 }
296 }
297
298 if (ptr == tmp)
299 return rv;
300
301 return 0;
302 }
303
304 #define DID_NEW 1
305 #define DID_ACTIVE 2
306 #define DID_INACTIVE 3
307
308 struct Did
309 {
310 Did *next;
311 char *file;
312 int state;
313 };
314 static Did *did = 0;
315
316 static Did *
317 already_did (char *file)
318 {
319 Did *d;
320 for (d = did; d; d = d->next)
321 if (strcasecmp (d->file, file) == 0)
322 return d;
323 d = (Did *) malloc (sizeof (Did));
324 d->file = strdup (file);
325 d->next = did;
326 d->state = DID_NEW;
327 did = d;
328 return d;
329 }
330
331 static int
332 get_word (HANDLE fh, int offset)
333 {
334 short rv;
335 unsigned r;
336
337 if (SetFilePointer (fh, offset, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER
338 && GetLastError () != NO_ERROR)
339 display_error ("get_word: SetFilePointer()");
340
341 if (!ReadFile (fh, &rv, 2, (DWORD *) &r, 0))
342 display_error ("get_word: Readfile()");
343
344 return rv;
345 }
346
347 static int
348 get_dword (HANDLE fh, int offset)
349 {
350 int rv;
351 unsigned r;
352
353 if (SetFilePointer (fh, offset, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER
354 && GetLastError () != NO_ERROR)
355 display_error ("get_dword: SetFilePointer()");
356
357 if (!ReadFile (fh, &rv, 4, (DWORD *) &r, 0))
358 display_error ("get_dword: Readfile()");
359
360 return rv;
361 }
362
363 struct Section
364 {
365 char name[8];
366 int virtual_size;
367 int virtual_address;
368 int size_of_raw_data;
369 int pointer_to_raw_data;
370 };
371
372 static int
373 rva_to_offset (int rva, char *sections, int nsections, int *sz)
374 {
375 int i;
376
377 if (sections == NULL)
378 {
379 display_error ("rva_to_offset: NULL passed for sections", true, false);
380 return 0;
381 }
382
383 for (i = 0; i < nsections; i++)
384 {
385 Section *s = (Section *) (sections + i * 40);
386 #if 0
387 printf ("%08x < %08x < %08x ? %08x\n",
388 s->virtual_address, rva,
389 s->virtual_address + s->virtual_size, s->pointer_to_raw_data);
390 #endif
391 if (rva >= s->virtual_address
392 && rva < s->virtual_address + s->virtual_size)
393 {
394 if (sz)
395 *sz = s->virtual_address + s->virtual_size - rva;
396 return rva - s->virtual_address + s->pointer_to_raw_data;
397 }
398 }
399 return 0; /* punt */
400 }
401
402 struct ExpDirectory
403 {
404 int flags;
405 int timestamp;
406 short major_ver;
407 short minor_ver;
408 int name_rva;
409 };
410
411 struct ImpDirectory
412 {
413 unsigned characteristics;
414 unsigned timestamp;
415 unsigned forwarder_chain;
416 unsigned name_rva;
417 unsigned iat_rva;
418 };
419
420
421 static bool track_down (char *file, char *suffix, int lvl);
422
423 #define CYGPREFIX (sizeof ("%%% Cygwin ") - 1)
424 static void
425 cygwin_info (HANDLE h)
426 {
427 char *buf, *bufend, *buf_start = NULL;
428 const char *hello = " Cygwin DLL version info:\n";
429 DWORD size = GetFileSize (h, NULL);
430 DWORD n;
431
432 if (size == 0xffffffff)
433 return;
434
435 buf_start = buf = (char *) calloc (1, size + 1);
436 if (buf == NULL)
437 {
438 display_error ("cygwin_info: calloc()");
439 return;
440 }
441
442 (void) SetFilePointer (h, 0, NULL, FILE_BEGIN);
443 if (!ReadFile (h, buf, size, &n, NULL))
444 {
445 free (buf_start);
446 return;
447 }
448
449 static char dummy[] = "\0\0\0\0\0\0\0";
450 char *dll_major = dummy;
451 bufend = buf + size;
452 while (buf < bufend)
453 if ((buf = (char *) memchr (buf, '%', bufend - buf)) == NULL)
454 break;
455 else if (strncmp ("%%% Cygwin ", buf, CYGPREFIX) != 0)
456 buf++;
457 else
458 {
459 char *p = strchr (buf += CYGPREFIX, '\n');
460 if (!p)
461 break;
462 if (strncasecmp (buf, "dll major:", 10) == 0)
463 {
464 dll_major = buf + 11;
465 continue;
466 }
467 char *s, pbuf[80];
468 int len;
469 len = 1 + p - buf;
470 if (strncasecmp (buf, "dll minor:", 10) != 0)
471 s = buf;
472 else
473 {
474 char c = dll_major[1];
475 dll_major[1] = '\0';
476 int maj = atoi (dll_major);
477 dll_major[1] = c;
478 int min = atoi (dll_major + 1);
479 sprintf (pbuf, "DLL version: %d.%d.%.*s", maj, min, len - 11,
480 buf + 11);
481 len = strlen (s = pbuf);
482 }
483 if (strncmp (s, "dll", 3) == 0)
484 memcpy (s, "DLL", 3);
485 else if (strncmp (s, "api", 3) == 0)
486 memcpy (s, "API", 3);
487 else if (islower (*s))
488 *s = toupper (*s);
489 fprintf (stdout, "%s %.*s", hello, len, s);
490 hello = "";
491 }
492
493 if (!*hello)
494 puts ("");
495
496 free (buf_start);
497 return;
498 }
499
500 static void
501 dll_info (const char *path, HANDLE fh, int lvl, int recurse)
502 {
503 DWORD junk;
504 int i;
505 int pe_header_offset = get_dword (fh, 0x3c);
506 int opthdr_ofs = pe_header_offset + 4 + 20;
507 unsigned short v[6];
508
509 if (path == NULL)
510 {
511 display_error ("dll_info: NULL passed for path", true, false);
512 return;
513 }
514
515 if (SetFilePointer (fh, opthdr_ofs + 40, 0, FILE_BEGIN) ==
516 INVALID_SET_FILE_POINTER && GetLastError () != NO_ERROR)
517 display_error ("dll_info: SetFilePointer()");
518
519 if (!ReadFile (fh, &v, sizeof (v), &junk, 0))
520 display_error ("dll_info: Readfile()");
521
522 if (verbose)
523 printf (" - os=%d.%d img=%d.%d sys=%d.%d\n",
524 v[0], v[1], v[2], v[3], v[4], v[5]);
525 else
526 printf ("\n");
527
528 int num_entries = get_dword (fh, opthdr_ofs + 92);
529 int export_rva = get_dword (fh, opthdr_ofs + 96);
530 int export_size = get_dword (fh, opthdr_ofs + 100);
531 int import_rva = get_dword (fh, opthdr_ofs + 104);
532 int import_size = get_dword (fh, opthdr_ofs + 108);
533
534 int nsections = get_word (fh, pe_header_offset + 4 + 2);
535 char *sections = (char *) malloc (nsections * 40);
536
537 if (SetFilePointer (fh, pe_header_offset + 4 + 20 +
538 get_word (fh, pe_header_offset + 4 + 16), 0,
539 FILE_BEGIN) == INVALID_SET_FILE_POINTER
540 && GetLastError () != NO_ERROR)
541 display_error ("dll_info: SetFilePointer()");
542
543 if (!ReadFile (fh, sections, nsections * 40, &junk, 0))
544 display_error ("dll_info: Readfile()");
545
546 if (verbose && num_entries >= 1 && export_size > 0)
547 {
548 int expsz;
549 int expbase = rva_to_offset (export_rva, sections, nsections, &expsz);
550
551 if (expbase)
552 {
553 if (SetFilePointer (fh, expbase, 0, FILE_BEGIN) ==
554 INVALID_SET_FILE_POINTER && GetLastError () != NO_ERROR)
555 display_error ("dll_info: SetFilePointer()");
556
557 unsigned char *exp = (unsigned char *) malloc (expsz);
558
559 if (!ReadFile (fh, exp, expsz, &junk, 0))
560 display_error ("dll_info: Readfile()");
561
562 ExpDirectory *ed = (ExpDirectory *) exp;
563 int ofs = ed->name_rva - export_rva;
564 struct tm *tm = localtime ((const time_t *) &(ed->timestamp));
565 if (tm->tm_year < 60)
566 tm->tm_year += 2000;
567 if (tm->tm_year < 200)
568 tm->tm_year += 1900;
569 printf ("%*c", lvl + 2, ' ');
570 printf ("\"%s\" v%d.%d ts=", exp + ofs,
571 ed->major_ver, ed->minor_ver);
572 printf ("%d/%d/%d %d:%02d\n",
573 tm->tm_year, tm->tm_mon + 1, tm->tm_mday,
574 tm->tm_hour, tm->tm_min);
575 }
576 }
577
578 if (num_entries >= 2 && import_size > 0 && recurse)
579 {
580 int impsz;
581 int impbase = rva_to_offset (import_rva, sections, nsections, &impsz);
582 if (impbase)
583 {
584 if (SetFilePointer (fh, impbase, 0, FILE_BEGIN) ==
585 INVALID_SET_FILE_POINTER && GetLastError () != NO_ERROR)
586 display_error ("dll_info: SetFilePointer()");
587
588 unsigned char *imp = (unsigned char *) malloc (impsz);
589 if (imp == NULL)
590 {
591 display_error ("dll_info: malloc()");
592 return;
593 }
594
595 if (!ReadFile (fh, imp, impsz, &junk, 0))
596 display_error ("dll_info: Readfile()");
597
598 ImpDirectory *id = (ImpDirectory *) imp;
599 for (i = 0; id[i].name_rva; i++)
600 {
601 /* int ofs = id[i].name_rva - import_rva; */
602 track_down ((char *) imp + id[i].name_rva - import_rva,
603 (char *) ".dll", lvl + 2);
604 }
605 }
606 }
607 if (strstr (path, "\\cygwin1.dll"))
608 cygwin_info (fh);
609 }
610
611 // Return true on success, false if error printed
612 static bool
613 track_down (char *file, char *suffix, int lvl)
614 {
615 if (file == NULL)
616 {
617 display_error ("track_down: NULL passed for file", true, false);
618 return false;
619 }
620
621 if (suffix == NULL)
622 {
623 display_error ("track_down: NULL passed for suffix", false, false);
624 return false;
625 }
626
627 char *path = find_on_path (file, suffix, 0, 1);
628 if (!path)
629 {
630 printf ("Error: could not find %s\n", file);
631 return false;
632 }
633
634 Did *d = already_did (file);
635 switch (d->state)
636 {
637 case DID_NEW:
638 break;
639 case DID_ACTIVE:
640 if (verbose)
641 {
642 if (lvl)
643 printf ("%*c", lvl, ' ');
644 printf ("%s", path);
645 printf (" (recursive)\n");
646 }
647 return true;
648 case DID_INACTIVE:
649 if (verbose)
650 {
651 if (lvl)
652 printf ("%*c", lvl, ' ');
653 printf ("%s", path);
654 printf (" (already done)\n");
655 }
656 return true;
657 default:
658 break;
659 }
660
661 if (lvl)
662 printf ("%*c", lvl, ' ');
663
664 if (!path)
665 {
666 printf ("%s not found\n", file);
667 return false;
668 }
669
670 printf ("%s", path);
671
672 HANDLE fh =
673 CreateFile (path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
674 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
675 if (fh == INVALID_HANDLE_VALUE)
676 {
677 printf (" - Cannot open\n");
678 return false;
679 }
680
681 d->state = DID_ACTIVE;
682
683 dll_info (path, fh, lvl, 1);
684 d->state = DID_INACTIVE;
685 if (!CloseHandle (fh))
686 display_error ("track_down: CloseHandle()");
687 return true;
688 }
689
690 static void
691 ls (char *f)
692 {
693 HANDLE h = CreateFile (f, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
694 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
695 BY_HANDLE_FILE_INFORMATION info;
696
697 if (!GetFileInformationByHandle (h, &info))
698 display_error ("ls: GetFileInformationByHandle()");
699
700 SYSTEMTIME systime;
701
702 if (!FileTimeToSystemTime (&info.ftLastWriteTime, &systime))
703 display_error ("ls: FileTimeToSystemTime()");
704 printf ("%5dk %04d/%02d/%02d %s",
705 (((int) info.nFileSizeLow) + 512) / 1024,
706 systime.wYear, systime.wMonth, systime.wDay, f);
707 dll_info (f, h, 16, 0);
708 if (!CloseHandle (h))
709 display_error ("ls: CloseHandle()");
710 }
711
712 // Return true on success, false if error printed
713 static bool
714 cygcheck (char *app)
715 {
716 char *papp = find_on_path (app, (char *) ".exe", 1, 0);
717 if (!papp)
718 {
719 printf ("Error: could not find %s\n", app);
720 return false;
721 }
722 char *s = strdup (papp);
723 char *sl = 0, *t;
724 for (t = s; *t; t++)
725 if (*t == '/' || *t == '\\' || *t == ':')
726 sl = t;
727 if (sl == 0)
728 paths[0] = (char *) ".";
729 else
730 {
731 *sl = 0;
732 paths[0] = s;
733 }
734 did = 0;
735 return track_down (papp, (char *) ".exe", 0);
736 }
737
738
739 extern char **environ;
740
741 struct RegInfo
742 {
743 RegInfo *prev;
744 char *name;
745 HKEY key;
746 };
747
748 static void
749 show_reg (RegInfo * ri, int nest)
750 {
751 if (!ri)
752 return;
753 show_reg (ri->prev, 1);
754 if (nest)
755 printf ("%s\\", ri->name);
756 else
757 printf ("%s\n", ri->name);
758 }
759
760 static void
761 scan_registry (RegInfo * prev, HKEY hKey, char *name, int cygnus)
762 {
763 RegInfo ri;
764 ri.prev = prev;
765 ri.name = name;
766 ri.key = hKey;
767
768 char *cp;
769 for (cp = name; *cp; cp++)
770 if (strncasecmp (cp, "cygnus", 6) == 0)
771 cygnus = 1;
772
773 DWORD num_subkeys, max_subkey_len, num_values;
774 DWORD max_value_len, max_valdata_len, i;
775 if (RegQueryInfoKey (hKey, 0, 0, 0, &num_subkeys, &max_subkey_len, 0,
776 &num_values, &max_value_len, &max_valdata_len, 0, 0)
777 != ERROR_SUCCESS)
778 {
779 #if 0
780 char tmp[400];
781 FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, 0, GetLastError (),
782 MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), tmp, 400, 0);
783 printf ("RegQueryInfoKey: %s\n", tmp);
784 #endif
785 return;
786 }
787
788 if (cygnus)
789 {
790 show_reg (&ri, 0);
791
792 char *value_name = (char *) malloc (max_value_len + 1);
793 if (value_name == NULL)
794 {
795 display_error ("scan_registry: malloc()");
796 return;
797 }
798
799 char *value_data = (char *) malloc (max_valdata_len + 1);
800 if (value_data == NULL)
801 {
802 display_error ("scan_registry: malloc()");
803 return;
804 }
805
806 for (i = 0; i < num_values; i++)
807 {
808 DWORD dlen = max_valdata_len + 1;
809 DWORD nlen = max_value_len + 1;
810 DWORD type;
811 RegEnumValue (hKey, i, value_name, &nlen, 0,
812 &type, (BYTE *) value_data, &dlen);
813 {
814 printf (" %s = ", i ? value_name : "(default)");
815 switch (type)
816 {
817 case REG_DWORD:
818 printf ("0x%08x\n", *(unsigned *) value_data);
819 break;
820 case REG_EXPAND_SZ:
821 case REG_SZ:
822 printf ("'%s'\n", value_data);
823 break;
824 default:
825 printf ("(unsupported type)\n");
826 break;
827 }
828 }
829 }
830 free (value_name);
831 free (value_data);
832 }
833
834 char *subkey_name = (char *) malloc (max_subkey_len + 1);
835 for (i = 0; i < num_subkeys; i++)
836 {
837 if (RegEnumKey (hKey, i, subkey_name, max_subkey_len + 1) ==
838 ERROR_SUCCESS)
839 {
840 HKEY sKey;
841 if (RegOpenKeyEx (hKey, subkey_name, 0, KEY_READ, &sKey)
842 == ERROR_SUCCESS)
843 {
844 scan_registry (&ri, sKey, subkey_name, cygnus);
845 if (RegCloseKey (sKey) != ERROR_SUCCESS)
846 display_error ("scan_registry: RegCloseKey()");
847 }
848 }
849 }
850 free (subkey_name);
851 }
852
853 void
854 pretty_id (const char *s, char *cygwin, size_t cyglen)
855 {
856 char *groups[16384];
857
858 strcpy (cygwin + cyglen++, " ");
859 strcpy (cygwin + cyglen, s);
860 putenv (cygwin);
861
862 char *id = cygpath ("/bin/id.exe", NULL);
863 for (char *p = id; (p = strchr (p, '/')); p++)
864 *p = '\\';
865
866 if (access (id, X_OK))
867 {
868 fprintf (stderr, "'id' program not found\n");
869 return;
870 }
871
872 FILE *f = popen (id, "rt");
873
874 char buf[16384];
875 buf[0] = '\0';
876 fgets (buf, sizeof (buf), f);
877 pclose (f);
878 char *uid = strtok (buf, ")");
879 if (uid)
880 uid += strlen ("uid=");
881 else
882 {
883 fprintf (stderr, "garbled output from 'id' command - no uid= found\n");
884 return;
885 }
886 char *gid = strtok (NULL, ")");
887 if (gid)
888 gid += strlen ("gid=") + 1;
889 else
890 {
891 fprintf (stderr, "garbled output from 'id' command - no gid= found\n");
892 return;
893 }
894
895 char **ng = groups - 1;
896 size_t len_uid = strlen ("UID: )") + strlen (uid);
897 size_t len_gid = strlen ("GID: )") + strlen (gid);
898 *++ng = groups[0] = (char *) alloca (len_uid + 1);
899 *++ng = groups[1] = (char *) alloca (len_gid + 1);
900 sprintf (groups[0], "UID: %s)", uid);
901 sprintf (groups[1], "GID: %s)", gid);
902 size_t sz = max (len_uid, len_gid);
903 while ((*++ng = strtok (NULL, ",")))
904 {
905 char *p = strchr (*ng, '\n');
906 if (p)
907 *p = '\0';
908 if (ng == groups + 2)
909 *ng += strlen (" groups=");
910 size_t len = strlen (*ng);
911 if (sz < len)
912 sz = len;
913 }
914 ng--;
915
916 printf ("\nOutput from %s (%s)\n", id, s);
917 int n = 80 / (int) ++sz;
918 int i = n > 2 ? n - 2 : 0;
919 sz = -sz;
920 for (char **g = groups; g <= ng; g++)
921 if ((g != ng) && (++i < n))
922 printf ("%*s", sz, *g);
923 else
924 {
925 puts (*g);
926 i = 0;
927 }
928 }
929
930 /* This dumps information about each installed cygwin service, if cygrunsrv
931 is available. */
932 void
933 dump_sysinfo_services ()
934 {
935 char buf[1024];
936 char buf2[1024];
937 FILE *f;
938 bool no_services = false;
939
940 if (givehelp)
941 printf ("\nChecking for any Cygwin services... %s\n\n",
942 verbose ? "" : "(use -v for more detail)");
943 else
944 fputc ('\n', stdout);
945
946 /* find the location of cygrunsrv.exe */
947 char *cygrunsrv = cygpath ("/bin/cygrunsrv.exe", NULL);
948 for (char *p = cygrunsrv; (p = strchr (p, '/')); p++)
949 *p = '\\';
950
951 if (access (cygrunsrv, X_OK))
952 {
953 puts ("Can't find the cygrunsrv utility, skipping services check.\n");
954 return;
955 }
956
957 /* check for a recent cygrunsrv */
958 snprintf (buf, sizeof (buf), "%s --version", cygrunsrv);
959 if ((f = popen (buf, "rt")) == NULL)
960 {
961 printf ("Failed to execute '%s', skipping services check.\n", buf);
962 return;
963 }
964 int maj, min;
965 int ret = fscanf (f, "cygrunsrv V%u.%u", &maj, &min);
966 if (ferror (f) || feof (f) || ret == EOF || maj < 1 || min < 10)
967 {
968 puts ("The version of cygrunsrv installed is too old to dump service info.\n");
969 return;
970 }
971 fclose (f);
972
973 /* For verbose mode, just run cygrunsrv --list --verbose and copy output
974 verbatim; otherwise run cygrunsrv --list and then cygrunsrv --query for
975 each service. */
976 snprintf (buf, sizeof (buf), (verbose ? "%s --list --verbose" : "%s --list"),
977 cygrunsrv);
978 if ((f = popen (buf, "rt")) == NULL)
979 {
980 printf ("Failed to execute '%s', skipping services check.\n", buf);
981 return;
982 }
983
984 if (verbose)
985 {
986 /* copy output to stdout */
987 size_t nchars = 0;
988 while (!feof (f) && !ferror (f))
989 nchars += fwrite ((void *) buf, 1,
990 fread ((void *) buf, 1, sizeof (buf), f), stdout);
991
992 /* cygrunsrv outputs nothing if there are no cygwin services found */
993 if (nchars < 1)
994 no_services = true;
995 pclose (f);
996 }
997 else
998 {
999 /* read the output of --list, and then run --query for each service */
1000 size_t nchars = fread ((void *) buf, 1, sizeof (buf) - 1, f);
1001 buf[nchars] = 0;
1002 pclose (f);
1003
1004 if (nchars > 0)
1005 for (char *srv = strtok (buf, "\n"); srv; srv = strtok (NULL, "\n"))
1006 {
1007 snprintf (buf2, sizeof (buf2), "%s --query %s", cygrunsrv, srv);
1008 if ((f = popen (buf2, "rt")) == NULL)
1009 {
1010 printf ("Failed to execute '%s', skipping services check.\n", buf2);
1011 return;
1012 }
1013
1014 /* copy output to stdout */
1015 while (!feof (f) && !ferror (f))
1016 fwrite ((void *) buf2, 1,
1017 fread ((void *) buf2, 1, sizeof (buf2), f), stdout);
1018 pclose (f);
1019 }
1020 else
1021 no_services = true;
1022 }
1023
1024 /* inform the user if nothing found */
1025 if (no_services)
1026 puts ("No Cygwin services found.\n");
1027 }
1028
1029 static void
1030 dump_sysinfo ()
1031 {
1032 int i, j;
1033 char tmp[4000];
1034 time_t now;
1035 char *found_cygwin_dll;
1036 bool is_nt = false;
1037
1038 printf ("\nCygwin Configuration Diagnostics\n");
1039 time (&now);
1040 printf ("Current System Time: %s\n", ctime (&now));
1041
1042 OSVERSIONINFO osversion;
1043 osversion.dwOSVersionInfoSize = sizeof (osversion);
1044 if (!GetVersionEx (&osversion))
1045 display_error ("dump_sysinfo: GetVersionEx()");
1046 const char *osname = "unknown OS";
1047 switch (osversion.dwPlatformId)
1048 {
1049 case VER_PLATFORM_WIN32s:
1050 osname = "32s";
1051 break;
1052 case VER_PLATFORM_WIN32_WINDOWS:
1053 switch (osversion.dwMinorVersion)
1054 {
1055 case 0:
1056 if (strchr (osversion.szCSDVersion, 'C'))
1057 osname = "95 OSR2";
1058 else
1059 osname = "95";
1060 break;
1061 case 10:
1062 if (strchr (osversion.szCSDVersion, 'A'))
1063 osname = "98 SE";
1064 else
1065 osname = "98";
1066 break;
1067 case 90:
1068 osname = "ME";
1069 break;
1070 default:
1071 osname = "9X";
1072 break;
1073 }
1074 break;
1075 case VER_PLATFORM_WIN32_NT:
1076 is_nt = true;
1077 if (osversion.dwMajorVersion == 6)
1078 osname = "Longhorn/Vista (not yet supported!)";
1079 else if (osversion.dwMajorVersion == 5)
1080 {
1081 BOOL more_info = FALSE;
1082 OSVERSIONINFOEX osversionex;
1083 osversionex.dwOSVersionInfoSize = sizeof (osversionex);
1084 if (GetVersionEx ((OSVERSIONINFO *) &osversionex))
1085 more_info = TRUE;
1086 if (osversion.dwMinorVersion == 0)
1087 {
1088 if (!more_info)
1089 osname = "2000";
1090 else if (osversionex.wProductType == VER_NT_SERVER
1091 || osversionex.wProductType == VER_NT_DOMAIN_CONTROLLER)
1092 {
1093 if (osversionex.wSuiteMask & VER_SUITE_DATACENTER)
1094 osname = "2000 Datacenter Server";
1095 else if (osversionex.wSuiteMask & VER_SUITE_ENTERPRISE)
1096 osname = "2000 Advanced Server";
1097 else
1098 osname = "2000 Server";
1099 }
1100 else
1101 osname = "2000 Professional";
1102 }
1103 else if (osversion.dwMinorVersion == 1)
1104 {
1105 if (GetSystemMetrics (SM_MEDIACENTER))
1106 osname = "XP Media Center Edition";
1107 else if (GetSystemMetrics (SM_TABLETPC))
1108 osname = "XP Tablet PC Edition";
1109 else if (!more_info)
1110 osname = "XP";
1111 else if (osversionex.wSuiteMask & VER_SUITE_PERSONAL)
1112 osname = "XP Home Edition";
1113 else
1114 osname = "XP Professional";
1115 }
1116 else if (osversion.dwMinorVersion == 2)
1117 {
1118 if (!more_info)
1119 osname = "2003 Server";
1120 else if (osversionex.wSuiteMask & VER_SUITE_BLADE)
1121 osname = "2003 Web Server";
1122 else if (osversionex.wSuiteMask & VER_SUITE_DATACENTER)
1123 osname = "2003 Datacenter Server";
1124 else if (osversionex.wSuiteMask & VER_SUITE_ENTERPRISE)
1125 osname = "2003 Enterprise Server";
1126 else
1127 osname = "2003 Server";
1128 }
1129 }
1130 else
1131 osname = "NT";
1132 break;
1133 default:
1134 osname = "??";
1135 break;
1136 }
1137 printf ("Windows %s Ver %lu.%lu Build %lu %s\n", osname,
1138 osversion.dwMajorVersion, osversion.dwMinorVersion,
1139 osversion.dwPlatformId == VER_PLATFORM_WIN32_NT ?
1140 osversion.dwBuildNumber : (osversion.dwBuildNumber & 0xffff),
1141 osversion.dwPlatformId == VER_PLATFORM_WIN32_NT ?
1142 osversion.szCSDVersion : "");
1143
1144 HMODULE k32 = LoadLibrary ("kernel32.dll");
1145
1146 BOOL (WINAPI *wow64_func) (HANDLE, PBOOL) = (BOOL (WINAPI *) (HANDLE, PBOOL))
1147 GetProcAddress (k32, "IsWow64Process");
1148 BOOL is_wow64 = FALSE;
1149 if (wow64_func && wow64_func (GetCurrentProcess (), &is_wow64) && is_wow64)
1150 {
1151 void (WINAPI *nativinfo) (LPSYSTEM_INFO) = (void (WINAPI *)
1152 (LPSYSTEM_INFO)) GetProcAddress (k32, "GetNativeSystemInfo");
1153 SYSTEM_INFO natinfo;
1154 nativinfo (&natinfo);
1155 fputs ("\nRunning under WOW64 on ", stdout);
1156 switch (natinfo.wProcessorArchitecture)
1157 {
1158 case PROCESSOR_ARCHITECTURE_IA64:
1159 puts ("IA64");
1160 break;
1161 case PROCESSOR_ARCHITECTURE_AMD64:
1162 puts ("AMD64");
1163 break;
1164 default:
1165 puts("??");
1166 break;
1167 }
1168 }
1169
1170 if (GetSystemMetrics (SM_REMOTESESSION))
1171 printf ("\nRunning in Terminal Service session\n");
1172
1173 printf ("\nPath:");
1174 char *s = getenv ("PATH"), *e;
1175 if (!s)
1176 puts ("");
1177 else
1178 {
1179 char sep = strchr (s, ';') ? ';' : ':';
1180 int count_path_items = 0;
1181 while (1)
1182 {
1183 for (e = s; *e && *e != sep; e++);
1184 if (e-s)
1185 printf ("\t%.*s\n", e - s, s);
1186 else
1187 puts ("\t.");
1188 count_path_items++;
1189 if (!*e)
1190 break;
1191 s = e + 1;
1192 }
1193 }
1194
1195 fflush (stdout);
1196
1197 char *cygwin = getenv ("CYGWIN");
1198 if (cygwin)
1199 cygwin -= strlen ("CYGWIN=");
1200 else
1201 cygwin = const_cast <char *> ("CYGWIN=");
1202 size_t cyglen = strlen (cygwin);
1203 cygwin = strcpy ((char *) malloc (cyglen + sizeof (" nontsec")), cygwin);
1204 pretty_id ("nontsec", cygwin, cyglen);
1205 pretty_id ("ntsec", cygwin, cyglen);
1206 cygwin[cyglen] = 0;
1207 putenv (cygwin);
1208
1209 if (!GetSystemDirectory (tmp, 4000))
1210 display_error ("dump_sysinfo: GetSystemDirectory()");
1211 printf ("\nSysDir: %s\n", tmp);
1212
1213 GetWindowsDirectory (tmp, 4000);
1214 printf ("WinDir: %s\n\n", tmp);
1215
1216
1217 if (givehelp)
1218 printf ("Here's some environment variables that may affect cygwin:\n");
1219 for (i = 0; environ[i]; i++)
1220 {
1221 char *eq = strchr (environ[i], '=');
1222 if (!eq)
1223 continue;
1224 /* int len = eq - environ[i]; */
1225 for (j = 0; known_env_vars[j]; j++)
1226 {
1227 *eq = 0;
1228 if (strcmp (environ[i], "PATH") == 0)
1229 continue; /* we handle this one specially */
1230 if (strcasecmp (environ[i], known_env_vars[j]) == 0)
1231 printf ("%s = '%s'\n", environ[i], eq + 1);
1232 *eq = '=';
1233 }
1234 }
1235 printf ("\n");
1236
1237 if (verbose)
1238 {
1239 if (givehelp)
1240 printf ("Here's the rest of your environment variables:\n");
1241 for (i = 0; environ[i]; i++)
1242 {
1243 int found = 0;
1244 char *eq = strchr (environ[i], '=');
1245 if (!eq)
1246 continue;
1247 /* int len = eq - environ[i]; */
1248 for (j = 0; known_env_vars[j]; j++)
1249 {
1250 *eq = 0;
1251 if (strcasecmp (environ[i], known_env_vars[j]) == 0)
1252 found = 1;
1253 *eq = '=';
1254 }
1255 if (!found)
1256 {
1257 *eq = 0;
1258 printf ("%s = '%s'\n", environ[i], eq + 1);
1259 *eq = '=';
1260 }
1261 }
1262 printf ("\n");
1263 }
1264
1265 if (registry)
1266 {
1267 if (givehelp)
1268 printf ("Scanning registry for keys with 'Cygnus' in them...\n");
1269 #if 0
1270 /* big and not generally useful */
1271 scan_registry (0, HKEY_CLASSES_ROOT, (char *) "HKEY_CLASSES_ROOT", 0);
1272 #endif
1273 scan_registry (0, HKEY_CURRENT_CONFIG,
1274 (char *) "HKEY_CURRENT_CONFIG", 0);
1275 scan_registry (0, HKEY_CURRENT_USER, (char *) "HKEY_CURRENT_USER", 0);
1276 scan_registry (0, HKEY_LOCAL_MACHINE, (char *) "HKEY_LOCAL_MACHINE", 0);
1277 #if 0
1278 /* the parts we need are duplicated in HKEY_CURRENT_USER anyway */
1279 scan_registry (0, HKEY_USERS, (char *) "HKEY_USERS", 0);
1280 #endif
1281 printf ("\n");
1282 }
1283 else
1284 printf ("Use '-r' to scan registry\n\n");
1285
1286 if (givehelp)
1287 {
1288 printf ("Listing available drives...\n");
1289 printf ("Drv Type Size Used Flags Name\n");
1290 }
1291 int prev_mode =
1292 SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
1293 int drivemask = GetLogicalDrives ();
1294
1295 BOOL (WINAPI * gdfse) (LPCSTR, long long *, long long *, long long *) =
1296 (BOOL (WINAPI *) (LPCSTR, long long *, long long *, long long *))
1297 GetProcAddress (k32, "GetDiskFreeSpaceExA");
1298
1299 for (i = 0; i < 26; i++)
1300 {
1301 if (!(drivemask & (1 << i)))
1302 continue;
1303 char drive[4], name[200], fsname[200];
1304 DWORD serno = 0, maxnamelen = 0, flags = 0;
1305 name[0] = name[0] = fsname[0] = 0;
1306 sprintf (drive, "%c:\\", i + 'a');
1307 /* Report all errors, except if the Volume is ERROR_NOT_READY.
1308 ERROR_NOT_READY is returned when removeable media drives are empty
1309 (CD, floppy, etc.) */
1310 if (!GetVolumeInformation (drive, name, sizeof (name), &serno,
1311 &maxnamelen, &flags, fsname,
1312 sizeof (fsname))
1313 && GetLastError () != ERROR_NOT_READY)
1314 {
1315 # define FMT "dump_sysinfo: GetVolumeInformation() for drive %c:"
1316 char buf[sizeof (FMT)];
1317 sprintf (buf, FMT, 'A' + i);
1318 display_error (buf);
1319 # undef FMT
1320 }
1321
1322 int dtype = GetDriveType (drive);
1323 char drive_type[4] = "unk";
1324 switch (dtype)
1325 {
1326 case DRIVE_REMOVABLE:
1327 strcpy (drive_type, "fd ");
1328 break;
1329 case DRIVE_FIXED:
1330 strcpy (drive_type, "hd ");
1331 break;
1332 case DRIVE_REMOTE:
1333 strcpy (drive_type, "net");
1334 break;
1335 case DRIVE_CDROM:
1336 strcpy (drive_type, "cd ");
1337 break;
1338 case DRIVE_RAMDISK:
1339 strcpy (drive_type, "ram");
1340 break;
1341 default:
1342 strcpy (drive_type, "unk");
1343 }
1344
1345 long capacity_mb = -1;
1346 int percent_full = -1;
1347
1348 long long free_me = 0ULL, free_bytes = 0ULL, total_bytes = 1ULL;
1349 if (gdfse != NULL && gdfse (drive, &free_me, &total_bytes, &free_bytes))
1350 {
1351 capacity_mb = total_bytes / (1024L * 1024L);
1352 percent_full = 100 - (int) ((100.0 * free_me) / total_bytes);
1353 }
1354 else
1355 {
1356 DWORD spc = 0, bps = 0, fc = 0, tc = 1;
1357 if (GetDiskFreeSpace (drive, &spc, &bps, &fc, &tc))
1358 {
1359 capacity_mb = (spc * bps * tc) / (1024 * 1024);
1360 percent_full = 100 - (int) ((100.0 * fc) / tc);
1361 }
1362 }
1363
1364 printf ("%.2s %s %-6s ", drive, drive_type, fsname);
1365 if (capacity_mb >= 0)
1366 printf ("%7dMb %3d%% ", (int) capacity_mb, (int) percent_full);
1367 else
1368 printf (" N/A N/A ");
1369 printf ("%s %s %s %s %s %s %s\n",
1370 flags & FS_CASE_IS_PRESERVED ? "CP" : " ",
1371 flags & FS_CASE_SENSITIVE ? "CS" : " ",
1372 flags & FS_UNICODE_STORED_ON_DISK ? "UN" : " ",
1373 flags & FS_PERSISTENT_ACLS ? "PA" : " ",
1374 flags & FS_FILE_COMPRESSION ? "FC" : " ",
1375 flags & FS_VOL_IS_COMPRESSED ? "VC" : " ",
1376 #if 0
1377 flags & FILE_SUPPORTS_ENCRYPTION ? "EN" : " ",
1378 flags & FILE_SUPPORTS_OBJECT_IDS ? "OI" : " ",
1379 flags & FILE_SUPPORTS_REPARSE_POINTS ? "RP" : " ",
1380 flags & FILE_SUPPORTS_SPARSE_FILES ? "SP" : " ",
1381 flags & FILE_VOLUME_QUOTAS ? "QU" : " ",
1382 #endif
1383 name);
1384 }
1385
1386 if (!FreeLibrary (k32))
1387 display_error ("dump_sysinfo: FreeLibrary()");
1388 SetErrorMode (prev_mode);
1389 if (givehelp)
1390 {
1391 puts ("\n"
1392 "fd = floppy, hd = hard drive, cd = CD-ROM\n"
1393 "net= Network Share, ram= RAM drive, unk= Unknown\n"
1394 "CP = Case Preserving, CS = Case Sensitive, UN = Unicode\n"
1395 "PA = Persistent ACLS, FC = File Compression, VC = Volume Compression");
1396 }
1397 printf ("\n");
1398
1399 unsigned ml_fsname = 4, ml_dir = 7, ml_type = 6;
1400 bool ml_trailing = false;
1401
1402 struct mntent *mnt;
1403 setmntent (0, 0);
1404 while ((mnt = getmntent (0)))
1405 {
1406 unsigned n = (int) strlen (mnt->mnt_fsname);
1407 ml_trailing |= (n > 1 && strchr ("\\/", mnt->mnt_fsname[n - 1]));
1408 if (ml_fsname < n)
1409 ml_fsname = n;
1410 n = (int) strlen (mnt->mnt_dir);
1411 ml_trailing |= (n > 1 && strchr ("\\/", mnt->mnt_dir[n - 1]));
1412 if (ml_dir < n)
1413 ml_dir = n;
1414 }
1415
1416 if (ml_trailing)
1417 puts ("Warning: Mount entries should not have a trailing (back)slash\n");
1418
1419 if (givehelp)
1420 {
1421 printf
1422 ("Mount entries: these map POSIX directories to your NT drives.\n");
1423 printf ("%-*s %-*s %-*s %s\n", ml_fsname, "-NT-", ml_dir, "-POSIX-",
1424 ml_type, "-Type-", "-Flags-");
1425 }
1426
1427 setmntent (0, 0);
1428 while ((mnt = getmntent (0)))
1429 {
1430 printf ("%-*s %-*s %-*s %s\n",
1431 ml_fsname, mnt->mnt_fsname,
1432 ml_dir, mnt->mnt_dir, ml_type, mnt->mnt_type, mnt->mnt_opts);
1433 }
1434 printf ("\n");
1435
1436 add_path ((char *) "\\bin", 4); /* just in case */
1437
1438 if (givehelp)
1439 printf
1440 ("Looking to see where common programs can be found, if at all...\n");
1441 for (i = 0; common_apps[i].name; i++)
1442 if (!find_on_path ((char *) common_apps[i].name, (char *) ".exe", 1, 0))
1443 {
1444 if (common_apps[i].missing_is_good)
1445 printf ("Not Found: %s (good!)\n", common_apps[i].name);
1446 else
1447 printf ("Not Found: %s\n", common_apps[i].name);
1448 }
1449 printf ("\n");
1450
1451 if (givehelp)
1452 printf ("Looking for various Cygwin DLLs... (-v gives version info)\n");
1453 int cygwin_dll_count = 0;
1454 for (i = 1; i < num_paths; i++)
1455 {
1456 WIN32_FIND_DATA ffinfo;
1457 sprintf (tmp, "%s/*.*", paths[i]);
1458 HANDLE ff = FindFirstFile (tmp, &ffinfo);
1459 int found = (ff != INVALID_HANDLE_VALUE);
1460 found_cygwin_dll = NULL;
1461 while (found)
1462 {
1463 char *f = ffinfo.cFileName;
1464 if (strcasecmp (f + strlen (f) - 4, ".dll") == 0)
1465 {
1466 if (strncasecmp (f, "cyg", 3) == 0)
1467 {
1468 sprintf (tmp, "%s\\%s", paths[i], f);
1469 if (strcasecmp (f, "cygwin1.dll") == 0)
1470 {
1471 cygwin_dll_count++;
1472 found_cygwin_dll = strdup (tmp);
1473 }
1474 else
1475 ls (tmp);
1476 }
1477 }
1478 found = FindNextFile (ff, &ffinfo);
1479 }
1480 if (found_cygwin_dll)
1481 {
1482 ls (found_cygwin_dll);
1483 free (found_cygwin_dll);
1484 }
1485
1486 FindClose (ff);
1487 }
1488 if (cygwin_dll_count > 1)
1489 puts ("Warning: There are multiple cygwin1.dlls on your path");
1490 if (!cygwin_dll_count)
1491 puts ("Warning: cygwin1.dll not found on your path");
1492
1493 if (is_nt)
1494 dump_sysinfo_services ();
1495 }
1496
1497 static int
1498 check_keys ()
1499 {
1500 HANDLE h = CreateFileA ("CONIN$", GENERIC_READ | GENERIC_WRITE,
1501 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1502 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1503
1504 if (h == INVALID_HANDLE_VALUE || h == NULL)
1505 return (display_error ("check_keys: Opening CONIN$"));
1506
1507 DWORD mode;
1508
1509 if (!GetConsoleMode (h, &mode))
1510 display_error ("check_keys: GetConsoleMode()");
1511 else
1512 {
1513 mode &= ~ENABLE_PROCESSED_INPUT;
1514 if (!SetConsoleMode (h, mode))
1515 display_error ("check_keys: SetConsoleMode()");
1516 }
1517
1518 fputs ("\nThis key check works only in a console window,", stderr);
1519 fputs (" _NOT_ in a terminal session!\n", stderr);
1520 fputs ("Abort with Ctrl+C if in a terminal session.\n\n", stderr);
1521 fputs ("Press 'q' to exit.\n", stderr);
1522
1523 INPUT_RECORD in, prev_in;
1524
1525 // Drop first <RETURN> key
1526 ReadConsoleInput (h, &in, 1, &mode);
1527
1528 memset (&in, 0, sizeof in);
1529
1530 do
1531 {
1532 prev_in = in;
1533 if (!ReadConsoleInput (h, &in, 1, &mode))
1534 display_error ("check_keys: ReadConsoleInput()");
1535
1536 if (!memcmp (&in, &prev_in, sizeof in))
1537 continue;
1538
1539 switch (in.EventType)
1540 {
1541 case KEY_EVENT:
1542 printf ("%s %ux VK: 0x%02x VS: 0x%02x A: 0x%02x CTRL: ",
1543 in.Event.KeyEvent.bKeyDown ? "Pressed " : "Released",
1544 in.Event.KeyEvent.wRepeatCount,
1545 in.Event.KeyEvent.wVirtualKeyCode,
1546 in.Event.KeyEvent.wVirtualScanCode,
1547 (unsigned char) in.Event.KeyEvent.uChar.AsciiChar);
1548 fputs (in.Event.KeyEvent.dwControlKeyState & CAPSLOCK_ON ?
1549 "CL " : "-- ", stdout);
1550 fputs (in.Event.KeyEvent.dwControlKeyState & ENHANCED_KEY ?
1551 "EK " : "-- ", stdout);
1552 fputs (in.Event.KeyEvent.dwControlKeyState & LEFT_ALT_PRESSED ?
1553 "LA " : "-- ", stdout);
1554 fputs (in.Event.KeyEvent.dwControlKeyState & LEFT_CTRL_PRESSED ?
1555 "LC " : "-- ", stdout);
1556 fputs (in.Event.KeyEvent.dwControlKeyState & NUMLOCK_ON ?
1557 "NL " : "-- ", stdout);
1558 fputs (in.Event.KeyEvent.dwControlKeyState & RIGHT_ALT_PRESSED ?
1559 "RA " : "-- ", stdout);
1560 fputs (in.Event.KeyEvent.dwControlKeyState & RIGHT_CTRL_PRESSED ?
1561 "RC " : "-- ", stdout);
1562 fputs (in.Event.KeyEvent.dwControlKeyState & SCROLLLOCK_ON ?
1563 "SL " : "-- ", stdout);
1564 fputs (in.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED ?
1565 "SH " : "-- ", stdout);
1566 fputc ('\n', stdout);
1567 break;
1568
1569 default:
1570 break;
1571 }
1572 }
1573 while (in.EventType != KEY_EVENT ||
1574 in.Event.KeyEvent.bKeyDown != FALSE ||
1575 in.Event.KeyEvent.uChar.AsciiChar != 'q');
1576
1577 CloseHandle (h);
1578 return 0;
1579 }
1580
1581 /* RFC1738 says that these do not need to be escaped. */
1582 static const char safe_chars[] = "$-_.+!*'(),";
1583
1584 /* the URL to query. */
1585 static const char base_url[] =
1586 "http://cygwin.com/cgi-bin2/package-grep.cgi?text=1&grep=";
1587
1588 /* Queries Cygwin web site for packages containing files matching a regexp.
1589 Return value is 1 if there was a problem, otherwise 0. */
1590 static int
1591 package_grep (char *search)
1592 {
1593 char buf[1024];
1594
1595 /* Attempt to dynamically load the necessary WinInet API functions so that
1596 cygcheck can still function on older systems without IE. */
1597 HMODULE hWinInet;
1598 if (!(hWinInet = LoadLibrary ("wininet.dll")))
1599 {
1600 fputs ("Unable to locate WININET.DLL. This feature requires Microsoft "
1601 "Internet Explorer v3 or later to function.\n", stderr);
1602 return 1;
1603 }
1604
1605 /* InternetCloseHandle is used outside this function so it is declared
1606 global. The rest of these functions are only used here, so declare them
1607 and call GetProcAddress for each of them with the following macro. */
1608
1609 pInternetCloseHandle = (BOOL (WINAPI *) (HINTERNET))
1610 GetProcAddress (hWinInet, "InternetCloseHandle");
1611 #define make_func_pointer(name, ret, args) ret (WINAPI * p##name) args = \
1612 (ret (WINAPI *) args) GetProcAddress (hWinInet, #name);
1613 make_func_pointer (InternetAttemptConnect, DWORD, (DWORD));
1614 make_func_pointer (InternetOpenA, HINTERNET, (LPCSTR, DWORD, LPCSTR, LPCSTR,
1615 DWORD));
1616 make_func_pointer (InternetOpenUrlA, HINTERNET, (HINTERNET, LPCSTR, LPCSTR,
1617 DWORD, DWORD, DWORD));
1618 make_func_pointer (InternetReadFile, BOOL, (HINTERNET, PVOID, DWORD, PDWORD));
1619 make_func_pointer (HttpQueryInfoA, BOOL, (HINTERNET, DWORD, PVOID, PDWORD,
1620 PDWORD));
1621 #undef make_func_pointer
1622
1623 if(!pInternetCloseHandle || !pInternetAttemptConnect || !pInternetOpenA
1624 || !pInternetOpenUrlA || !pInternetReadFile || !pHttpQueryInfoA)
1625 {
1626 fputs ("Unable to load one or more functions from WININET.DLL. This "
1627 "feature requires Microsoft Internet Explorer v3 or later to "
1628 "function.\n", stderr);
1629 return 1;
1630 }
1631
1632 /* construct the actual URL by escaping */
1633 char *url = (char *) alloca (sizeof (base_url) + strlen (search) * 3);
1634 strcpy (url, base_url);
1635
1636 char *dest;
1637 for (dest = &url[sizeof (base_url) - 1]; *search; search++)
1638 {
1639 if (isalnum (*search)
1640 || memchr (safe_chars, *search, sizeof (safe_chars) - 1))
1641 {
1642 *dest++ = *search;
1643 }
1644 else
1645 {
1646 *dest++ = '%';
1647 sprintf (dest, "%02x", (unsigned char) *search);
1648 dest += 2;
1649 }
1650 }
1651 *dest = 0;
1652
1653 /* Connect to the net and open the URL. */
1654 if (pInternetAttemptConnect (0) != ERROR_SUCCESS)
1655 {
1656 fputs ("An internet connection is required for this function.\n", stderr);
1657 return 1;
1658 }
1659
1660 /* Initialize WinInet and attempt to fetch our URL. */
1661 HINTERNET hi = NULL, hurl = NULL;
1662 if (!(hi = pInternetOpenA ("cygcheck", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0)))
1663 return display_internet_error ("InternetOpen() failed", NULL);
1664
1665 if (!(hurl = pInternetOpenUrlA (hi, url, NULL, 0, 0, 0)))
1666 return display_internet_error ("unable to contact cygwin.com site, "
1667 "InternetOpenUrl() failed", hi, NULL);
1668
1669 /* Check the HTTP response code. */
1670 DWORD rc = 0, rc_s = sizeof (DWORD);
1671 if (!pHttpQueryInfoA (hurl, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER,
1672 (void *) &rc, &rc_s, NULL))
1673 return display_internet_error ("HttpQueryInfo() failed", hurl, hi, NULL);
1674
1675 if (rc != HTTP_STATUS_OK)
1676 {
1677 sprintf (buf, "error retrieving results from cygwin.com site, "
1678 "HTTP status code %lu", rc);
1679 return display_internet_error (buf, hurl, hi, NULL);
1680 }
1681
1682 /* Fetch result and print to stdout. */
1683 DWORD numread;
1684 do
1685 {
1686 if (!pInternetReadFile (hurl, (void *) buf, sizeof (buf), &numread))
1687 return display_internet_error ("InternetReadFile failed", hurl, hi, NULL);
1688 if (numread)
1689 fwrite ((void *) buf, (size_t) numread, 1, stdout);
1690 }
1691 while (numread);
1692
1693 pInternetCloseHandle (hurl);
1694 pInternetCloseHandle (hi);
1695 return 0;
1696 }
1697
1698 static void
1699 usage (FILE * stream, int status)
1700 {
1701 fprintf (stream, "\
1702 Usage: cygcheck PROGRAM [ -v ] [ -h ]\n\
1703 cygcheck -c [ PACKAGE ] [ -d ]\n\
1704 cygcheck -s [ -r ] [ -v ] [ -h ]\n\
1705 cygcheck -k\n\
1706 cygcheck -f FILE [ FILE ... ]\n\
1707 cygcheck -l [ PACKAGE ] [ PACKAGE ... ]\n\
1708 cygcheck -p REGEXP\n\
1709 List system information, check installed packages, or query package database.\n\
1710 \n\
1711 At least one command option or a PROGRAM is required, as shown above.\n\
1712 \n\
1713 PROGRAM list library (DLL) dependencies of PROGRAM\n\
1714 -c, --check-setup show installed version of PACKAGE and verify integrity\n\
1715 (or for all installed packages if none specified)\n\
1716 -d, --dump-only just list packages, do not verify (with -c)\n\
1717 -s, --sysinfo produce diagnostic system information (implies -c -d)\n\
1718 -r, --registry also scan registry for Cygwin settings (with -s)\n\
1719 -k, --keycheck perform a keyboard check session (must be run from a\n\
1720 plain console only, not from a pty/rxvt/xterm)\n\
1721 -f, --find-package find the package that FILE belongs to\n\
1722 -l, --list-package list contents of PACKAGE (or all packages if none given)\n\
1723 -p, --package-query search for REGEXP in the entire cygwin.com package\n\
1724 repository (requies internet connectivity)\n\
1725 -v, --verbose produce more verbose output\n\
1726 -h, --help annotate output with explanatory comments when given\n\
1727 with another command, otherwise print this help\n\
1728 -V, --version print the version of cygcheck and exit\n\
1729 \n\
1730 Note: -c, -f, and -l only report on packages that are currently installed. To\n\
1731 search all official Cygwin packages use -p instead. The -p REGEXP matches\n\
1732 package names, descriptions, and names of files/paths within all packages.\n\
1733 \n");
1734 exit (status);
1735 }
1736
1737 struct option longopts[] = {
1738 {"check-setup", no_argument, NULL, 'c'},
1739 {"dump-only", no_argument, NULL, 'd'},
1740 {"sysinfo", no_argument, NULL, 's'},
1741 {"registry", no_argument, NULL, 'r'},
1742 {"verbose", no_argument, NULL, 'v'},
1743 {"keycheck", no_argument, NULL, 'k'},
1744 {"find-package", no_argument, NULL, 'f'},
1745 {"list-package", no_argument, NULL, 'l'},
1746 {"package-query", no_argument, NULL, 'p'},
1747 {"help", no_argument, NULL, 'h'},
1748 {"version", no_argument, 0, 'V'},
1749 {0, no_argument, NULL, 0}
1750 };
1751
1752 static char opts[] = "cdsrvkflphV";
1753
1754 static void
1755 print_version ()
1756 {
1757 const char *v = strchr (version, ':');
1758 int len;
1759 if (!v)
1760 {
1761 v = "?";
1762 len = 1;
1763 }
1764 else
1765 {
1766 v += 2;
1767 len = strchr (v, ' ') - v;
1768 }
1769 printf ("\
1770 cygcheck version %.*s\n\
1771 System Checker for Cygwin\n\
1772 Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Red Hat, Inc.\n\
1773 Compiled on %s\n\
1774 ", len, v, __DATE__);
1775 }
1776
1777 void
1778 nuke (char *ev)
1779 {
1780 int n = 1 + strchr (ev, '=') - ev;
1781 char *s = (char *) alloca (n + 1);
1782 memcpy (s, ev, n);
1783 s[n] = '\0';
1784 putenv (s);
1785 }
1786
1787 extern "C" {
1788 unsigned long (*cygwin_internal) (int, ...);
1789 };
1790
1791 static void
1792 load_cygwin (int& argc, char **&argv)
1793 {
1794 HMODULE h;
1795
1796 if (!(h = LoadLibrary ("cygwin1.dll")))
1797 return;
1798 if (!(cygwin_internal = (DWORD (*) (int, ...)) GetProcAddress (h, "cygwin_internal")))
1799 return;
1800
1801 char **av = (char **) cygwin_internal (CW_ARGV);
1802 if (av && ((DWORD) av != (DWORD) -1))
1803 for (argc = 0, argv = av; *av; av++)
1804 argc++;
1805
1806 char **envp = (char **) cygwin_internal (CW_ENVP);
1807 if (envp && ((DWORD) envp != (DWORD) -1))
1808 {
1809 /* Store path and revert to this value, otherwise path gets overwritten
1810 by the POSIXy Cygwin variation, which breaks cygcheck.
1811 Another approach would be to use the Cygwin PATH and convert it to
1812 Win32 again. */
1813 char *path = NULL;
1814 char **env;
1815 while (*(env = _environ))
1816 {
1817 if (strncmp (*env, "PATH=", 5) == 0)
1818 path = strdup (*env);
1819 nuke (*env);
1820 }
1821 for (char **ev = envp; *ev; ev++)
1822 if (strncmp (*ev, "PATH=", 5) != 0)
1823 putenv (*ev);
1824 if (path)
1825 putenv (path);
1826 }
1827 }
1828
1829 int
1830 main (int argc, char **argv)
1831 {
1832 int i;
1833 bool ok = true;
1834 load_cygwin (argc, argv);
1835
1836 (void) putenv("POSIXLY_CORRECT=1");
1837 while ((i = getopt_long (argc, argv, opts, longopts, NULL)) != EOF)
1838 switch (i)
1839 {
1840 case 's':
1841 sysinfo = 1;
1842 break;
1843 case 'c':
1844 check_setup = 1;
1845 break;
1846 case 'd':
1847 dump_only = 1;
1848 break;
1849 case 'r':
1850 registry = 1;
1851 break;
1852 case 'v':
1853 verbose = 1;
1854 break;
1855 case 'k':
1856 keycheck = 1;
1857 break;
1858 case 'f':
1859 find_package = 1;
1860 break;
1861 case 'l':
1862 list_package = 1;
1863 break;
1864 case 'p':
1865 grep_packages = 1;
1866 break;
1867 case 'h':
1868 givehelp = 1;
1869 break;
1870 case 'V':
1871 print_version ();
1872 exit (0);
1873 default:
1874 usage (stderr, 1);
1875 /*NOTREACHED*/}
1876 argc -= optind;
1877 argv += optind;
1878
1879 if (argc == 0 && !sysinfo && !keycheck && !check_setup && !list_package)
1880 if (givehelp)
1881 usage (stdout, 0);
1882 else
1883 usage (stderr, 1);
1884
1885 if ((check_setup || sysinfo || find_package || list_package || grep_packages)
1886 && keycheck)
1887 usage (stderr, 1);
1888
1889 if ((find_package || list_package || grep_packages) && check_setup)
1890 usage (stderr, 1);
1891
1892 if (dump_only && !check_setup)
1893 usage (stderr, 1);
1894
1895 if (find_package + list_package + grep_packages > 1)
1896 usage (stderr, 1);
1897
1898 if (keycheck)
1899 return check_keys ();
1900 if (grep_packages)
1901 return package_grep (*argv);
1902
1903 init_paths ();
1904
1905 /* FIXME: Add help for check_setup and {list,find}_package */
1906 if (argc >= 1 && givehelp && !check_setup && !find_package && !list_package)
1907 {
1908 printf("Here is where the OS will find your program%s, and which dlls\n",
1909 argc > 1 ? "s" : "");
1910 printf ("will be used for it. Use -v to see DLL version info\n");
1911
1912 if (!sysinfo)
1913 printf ("\n");
1914 }
1915
1916 if (check_setup)
1917 dump_setup (verbose, argv, !dump_only);
1918 else if (find_package)
1919 package_find (verbose, argv);
1920 else if (list_package)
1921 package_list (verbose, argv);
1922 else
1923 for (i = 0; i < argc; i++)
1924 {
1925 if (i)
1926 puts ("");
1927 ok &= cygcheck (argv[i]);
1928 }
1929
1930 if (sysinfo)
1931 {
1932 dump_sysinfo ();
1933 if (!check_setup)
1934 {
1935 puts ("");
1936 dump_setup (verbose, NULL, false);
1937 }
1938
1939 if (!givehelp)
1940 puts ("Use -h to see help about each section");
1941 }
1942
1943 return ok ? EXIT_SUCCESS : EXIT_FAILURE;
1944 }
This page took 0.120385 seconds and 6 git commands to generate.