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