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