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