3 Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
4 2006, 2007, 2008, 2009, 2010, 2011 Red Hat, Inc.
6 This file is part of Cygwin.
8 This software is a copyrighted work licensed under the terms of the
9 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
12 #define cygwin_internal cygwin_internal_dontuse
23 #include "wide_path.h"
25 #include "cygwin/include/sys/cygwin.h"
26 #include "cygwin/include/mntent.h"
27 #include "cygwin/cygprops.h"
28 #undef cygwin_internal
31 #define alloca __builtin_alloca
42 int grep_packages = 0;
43 int del_orphaned_reg = 0;
44 int unique_object_name_opt = 0;
46 static char emptystr[] = "";
48 /* This is global because it's used in both internet_display_error as well
50 BOOL (WINAPI *pInternetCloseHandle) (HINTERNET);
53 typedef long long longlong;
55 typedef __int64 longlong;
58 /* In dump_setup.cc */
59 void dump_setup (int, char **, bool);
60 void package_find (int, char **);
61 void package_list (int, char **);
63 void dump_dodgy_apps (int verbose);
64 /* Forward declaration */
65 static void usage (FILE *, int);
67 static const char version[] = "$Revision$";
69 static const char *known_env_vars[] = {
77 "gcc_default_options",
99 static common_apps[] = {
128 /* Options without ASCII single char representation. */
131 CO_DELETE_KEYS = 0x100,
132 CO_ENABLE_UON = 0x101,
133 CO_DISABLE_UON = 0x102,
137 static int num_paths, max_paths;
142 void check_existence (const char *fn, int showall, int verbose,
143 char* first, const char *ext1 = "",
144 const char *ext2 = "");
148 int first_nonsys_path;
151 eprintf (const char *format, ...)
154 va_start (ap, format);
155 vfprintf (stderr, format, ap);
160 * display_error() is used to report failure modes
163 display_error (const char *name, bool show_error, bool print_failed)
165 fprintf (stderr, "cygcheck: %s", name);
167 fprintf (stderr, "%s: %lu\n",
168 print_failed ? " failed" : "", GetLastError ());
170 fprintf (stderr, "%s\n",
171 print_failed ? " failed" : "");
176 display_error (const char *name)
178 return display_error (name, true, true);
182 display_error (const char *fmt, const char *x)
185 snprintf (buf, sizeof buf, fmt, x);
186 return display_error (buf, false, false);
190 display_error_fmt (const char *fmt, ...)
196 vsnprintf (buf, sizeof buf, fmt, va);
197 return display_error (buf, false, false);
200 /* Display a WinInet error message, and close a variable number of handles.
201 (Passed a list of handles terminated by NULL.) */
203 display_internet_error (const char *message, ...)
205 DWORD err = GetLastError ();
210 /* in the case of a successful connection but 404 response, there is no
211 win32 error message, but we still get passed a message to display. */
214 if (FormatMessage (FORMAT_MESSAGE_FROM_HMODULE,
215 GetModuleHandle ("wininet.dll"), err, 0, err_buf,
216 sizeof (err_buf), NULL) == 0)
217 strcpy (err_buf, "(Unknown error)");
219 fprintf (stderr, "cygcheck: %s: %s (win32 error %lu)\n", message,
223 fprintf (stderr, "cygcheck: %s\n", message);
225 va_start (hptr, message);
226 while ((h = va_arg (hptr, HINTERNET)) != 0)
227 pInternetCloseHandle (h);
234 add_path (char *s, int maxlen, bool issys)
236 if (num_paths >= max_paths)
239 /* Extend path array */
240 paths = (pathlike *) realloc (paths, (1 + max_paths) * sizeof (paths[0]));
243 pathlike *pth = paths + num_paths;
245 /* Allocate space for directory in path list */
246 char *dir = (char *) calloc (maxlen + 2, sizeof (char));
249 display_error ("add_path: calloc() failed");
253 /* Copy input directory to path list */
254 memcpy (dir, s, maxlen);
256 /* Add a trailing slash by default */
257 char *e = strchr (dir, '\0');
258 if (e != dir && e[-1] != '\\')
261 /* Fill out this element */
272 add_path ((char *) ".", 1, true); /* to be replaced later */
274 if (GetCurrentDirectory (4000, tmp))
275 add_path (tmp, strlen (tmp), true);
277 display_error ("init_paths: GetCurrentDirectory()");
279 if (GetSystemDirectory (tmp, 4000))
280 add_path (tmp, strlen (tmp), true);
282 display_error ("init_paths: GetSystemDirectory()");
283 sl = strrchr (tmp, '\\');
286 strcpy (sl, "\\SYSTEM");
287 add_path (tmp, strlen (tmp), true);
289 GetWindowsDirectory (tmp, 4000);
290 add_path (tmp, strlen (tmp), true);
292 char *wpath = getenv ("PATH");
294 display_error ("WARNING: PATH is not set\n", "");
301 for (e = b; *e && *e != ';'; e++)
302 continue; /* loop terminates at first ';' or EOS */
303 if (strncmp(b, ".\\", 2) != 0)
304 add_path (b, e - b, false);
312 #define LINK_EXTENSION ".lnk"
315 pathlike::check_existence (const char *fn, int showall, int verbose,
316 char* first, const char *ext1, const char *ext2)
324 wide_path wpath (file);
325 if (GetFileAttributesW (wpath) != (DWORD) - 1)
327 char *lastdot = strrchr (file, '.');
328 bool is_link = lastdot && !strcmp (lastdot, LINK_EXTENSION);
329 // If file is a link, fix up the extension before printing
333 printf ("Found: %s\n", file);
334 if (verbose && *first != '\0' && strcasecmp (first, file) != 0)
336 char *flastdot = strrchr (first, '.');
337 bool f_is_link = flastdot && !strcmp (flastdot, LINK_EXTENSION);
338 // if first is a link, fix up the extension before printing
341 printf ("Warning: %s hides %s\n", first, file);
348 strcpy (first, file);
353 find_on_path (const char *in_file, const char *ext, bool showall = false,
354 bool search_sys = false, bool checklinks = false)
356 static char rv[4000];
358 /* Sort of a kludge but we've already tested this once, so don't try it again */
362 static pathlike abspath[2] =
371 display_error ("internal error find_on_path: NULL pointer for file", false, false);
377 display_error ("internal error find_on_path: NULL pointer for default_extension", false, false);
382 pathlike *search_paths;
383 if (!strpbrk (in_file, ":/\\"))
386 search_paths = paths;
390 file = cygpath (in_file, NULL);
391 search_paths = abspath;
397 display_error ("internal error find_on_path: cygpath conversion failed for %s\n", in_file);
401 char *hasext = strrchr (file, '.');
402 if (hasext && !strpbrk (hasext, "/\\"))
405 for (pathlike *pth = search_paths; pth->dir; pth++)
406 if (!pth->issys || search_sys)
408 pth->check_existence (file, showall, verbose, rv, ext);
411 pth->check_existence (file, showall, verbose, rv, ext, LINK_EXTENSION);
416 pth->check_existence (file, showall, verbose, rv);
418 pth->check_existence (file, showall, verbose, rv, LINK_EXTENSION);
421 return *rv ? rv : NULL;
426 #define DID_INACTIVE 3
437 already_did (const char *file)
440 for (d = did; d; d = d->next)
441 if (strcasecmp (d->file, file) == 0)
443 d = (Did *) malloc (sizeof (Did));
444 d->file = strdup (file);
456 int size_of_raw_data;
457 int pointer_to_raw_data;
461 rva_to_offset (int rva, char *sections, int nsections, int *sz)
465 if (sections == NULL)
467 display_error ("rva_to_offset: NULL passed for sections", true, false);
471 for (i = 0; i < nsections; i++)
473 Section *s = (Section *) (sections + i * 40);
475 printf ("%08x < %08x < %08x ? %08x\n",
476 s->virtual_address, rva,
477 s->virtual_address + s->virtual_size, s->pointer_to_raw_data);
479 if (rva >= s->virtual_address
480 && rva < s->virtual_address + s->virtual_size)
483 *sz = s->virtual_address + s->virtual_size - rva;
484 return rva - s->virtual_address + s->pointer_to_raw_data;
501 unsigned characteristics;
503 unsigned forwarder_chain;
508 static bool track_down (const char *file, const char *suffix, int lvl);
510 #define CYGPREFIX (sizeof ("%%% Cygwin ") - 1)
512 cygwin_info (HANDLE h)
514 char *buf, *bufend, *buf_start = NULL;
515 const char *hello = " Cygwin DLL version info:\n";
516 DWORD size = GetFileSize (h, NULL);
519 if (size == 0xffffffff)
522 buf_start = buf = (char *) calloc (1, size + 1);
525 display_error ("cygwin_info: calloc()");
529 (void) SetFilePointer (h, 0, NULL, FILE_BEGIN);
530 if (!ReadFile (h, buf, size, &n, NULL))
536 static char dummy[] = "\0\0\0\0\0\0\0";
537 char *dll_major = dummy;
540 if ((buf = (char *) memchr (buf, '%', bufend - buf)) == NULL)
542 else if (strncmp ("%%% Cygwin ", buf, CYGPREFIX) != 0)
546 char *p = strchr (buf += CYGPREFIX, '\n');
549 if (strncasecmp (buf, "dll major:", 10) == 0)
551 dll_major = buf + 11;
557 if (strncasecmp (buf, "dll minor:", 10) != 0)
561 char c = dll_major[1];
563 int maj = atoi (dll_major);
565 int min = atoi (dll_major + 1);
566 sprintf (pbuf, "DLL version: %d.%d.%.*s", maj, min, len - 11,
568 len = strlen (s = pbuf);
570 if (strncmp (s, "dll", 3) == 0)
571 memcpy (s, "DLL", 3);
572 else if (strncmp (s, "api", 3) == 0)
573 memcpy (s, "API", 3);
574 else if (islower (*s))
576 fprintf (stdout, "%s %.*s", hello, len, s);
588 dll_info (const char *path, HANDLE fh, int lvl, int recurse)
592 int pe_header_offset = get_dword (fh, 0x3c);
593 if (GetLastError () != NO_ERROR)
594 display_error ("get_dword");
595 int opthdr_ofs = pe_header_offset + 4 + 20;
600 display_error ("dll_info: NULL passed for path", true, false);
604 if (SetFilePointer (fh, opthdr_ofs + 40, 0, FILE_BEGIN) ==
605 INVALID_SET_FILE_POINTER && GetLastError () != NO_ERROR)
606 display_error ("dll_info: SetFilePointer()");
608 if (!ReadFile (fh, &v, sizeof (v), &junk, 0))
609 display_error ("dll_info: Readfile()");
612 printf (" - os=%d.%d img=%d.%d sys=%d.%d\n",
613 v[0], v[1], v[2], v[3], v[4], v[5]);
617 int num_entries = get_dword (fh, opthdr_ofs + 92);
618 if (GetLastError () != NO_ERROR)
619 display_error ("get_dword");
620 int export_rva = get_dword (fh, opthdr_ofs + 96);
621 if (GetLastError () != NO_ERROR)
622 display_error ("get_dword");
623 int export_size = get_dword (fh, opthdr_ofs + 100);
624 if (GetLastError () != NO_ERROR)
625 display_error ("get_dword");
626 int import_rva = get_dword (fh, opthdr_ofs + 104);
627 if (GetLastError () != NO_ERROR)
628 display_error ("get_dword");
629 int import_size = get_dword (fh, opthdr_ofs + 108);
630 if (GetLastError () != NO_ERROR)
631 display_error ("get_dword");
633 int nsections = get_word (fh, pe_header_offset + 4 + 2);
635 display_error ("get_word");
636 char *sections = (char *) malloc (nsections * 40);
638 if (SetFilePointer (fh, pe_header_offset + 4 + 20 +
639 get_word (fh, pe_header_offset + 4 + 16), 0,
640 FILE_BEGIN) == INVALID_SET_FILE_POINTER
641 && GetLastError () != NO_ERROR)
642 display_error ("dll_info: SetFilePointer()");
644 if (!ReadFile (fh, sections, nsections * 40, &junk, 0))
645 display_error ("dll_info: Readfile()");
647 if (verbose && num_entries >= 1 && export_size > 0)
650 int expbase = rva_to_offset (export_rva, sections, nsections, &expsz);
654 if (SetFilePointer (fh, expbase, 0, FILE_BEGIN) ==
655 INVALID_SET_FILE_POINTER && GetLastError () != NO_ERROR)
656 display_error ("dll_info: SetFilePointer()");
658 unsigned char *exp = (unsigned char *) malloc (expsz);
660 if (!ReadFile (fh, exp, expsz, &junk, 0))
661 display_error ("dll_info: Readfile()");
663 ExpDirectory *ed = (ExpDirectory *) exp;
664 int ofs = ed->name_rva - export_rva;
665 struct tm *tm = localtime ((const time_t *) &(ed->timestamp));
666 if (tm->tm_year < 60)
668 if (tm->tm_year < 200)
670 printf ("%*c", lvl + 2, ' ');
671 printf ("\"%s\" v%d.%d ts=", exp + ofs,
672 ed->major_ver, ed->minor_ver);
673 printf ("%d/%d/%d %d:%02d\n",
674 tm->tm_year, tm->tm_mon + 1, tm->tm_mday,
675 tm->tm_hour, tm->tm_min);
679 if (num_entries >= 2 && import_size > 0 && recurse)
682 int impbase = rva_to_offset (import_rva, sections, nsections, &impsz);
685 if (SetFilePointer (fh, impbase, 0, FILE_BEGIN) ==
686 INVALID_SET_FILE_POINTER && GetLastError () != NO_ERROR)
687 display_error ("dll_info: SetFilePointer()");
689 unsigned char *imp = (unsigned char *) malloc (impsz);
692 display_error ("dll_info: malloc()");
696 if (!ReadFile (fh, imp, impsz, &junk, 0))
697 display_error ("dll_info: Readfile()");
699 ImpDirectory *id = (ImpDirectory *) imp;
700 for (i = 0; id[i].name_rva; i++)
702 /* int ofs = id[i].name_rva - import_rva; */
703 track_down ((char *) imp + id[i].name_rva - import_rva,
704 (char *) ".dll", lvl + 2);
708 if (strstr (path, "\\cygwin1.dll"))
712 // Return true on success, false if error printed
714 track_down (const char *file, const char *suffix, int lvl)
718 display_error ("track_down: NULL passed for file", true, false);
724 display_error ("track_down: NULL passed for suffix", false, false);
728 const char *path = find_on_path (file, suffix, false, true);
731 display_error ("track_down: could not find %s\n", file);
735 Did *d = already_did (file);
744 printf ("%*c", lvl, ' ');
746 printf (" (recursive)\n");
753 printf ("%*c", lvl, ' ');
755 printf (" (already done)\n");
763 printf ("%*c", lvl, ' ');
767 display_error ("file not found - '%s'\n", file);
773 wide_path wpath (path);
775 CreateFileW (wpath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
776 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
777 if (fh == INVALID_HANDLE_VALUE)
779 display_error ("cannot open - '%s'\n", path);
783 d->state = DID_ACTIVE;
786 dll_info (path, fh, lvl, 1);
787 else if (is_symlink (fh))
788 display_error ("%s is a symlink instead of a DLL\n", path);
791 int magic = get_word (fh, 0x0);
793 display_error ("get_word");
795 display_error_fmt ("%s is not a DLL: magic number %x (%d) '%s'\n",
796 path, magic, magic, (char *)&magic);
799 d->state = DID_INACTIVE;
800 if (!CloseHandle (fh))
801 display_error ("track_down: CloseHandle()");
809 HANDLE h = CreateFileW (wpath, GENERIC_READ,
810 FILE_SHARE_READ | FILE_SHARE_WRITE,
811 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
812 BY_HANDLE_FILE_INFORMATION info;
814 if (!GetFileInformationByHandle (h, &info))
815 display_error ("ls: GetFileInformationByHandle()");
819 if (!FileTimeToSystemTime (&info.ftLastWriteTime, &systime))
820 display_error ("ls: FileTimeToSystemTime()");
821 printf ("%5dk %04d/%02d/%02d %s",
822 (((int) info.nFileSizeLow) + 512) / 1024,
823 systime.wYear, systime.wMonth, systime.wDay, f);
824 dll_info (f, h, 16, 0);
825 if (!CloseHandle (h))
826 display_error ("ls: CloseHandle()");
829 /* Remove filename from 's' and return directory name without trailing
830 backslash, or NULL if 's' doesn't seem to have a dirname. */
832 dirname (const char *s)
834 static char buf[PATH_MAX];
839 strncpy (buf, s, PATH_MAX);
840 buf[PATH_MAX - 1] = '\0'; // in case strlen(s) > PATH_MAX
841 char *lastsep = strrchr (buf, '\\');
843 return NULL; // no backslash -> no dirname
844 else if (lastsep - buf <= 2 && buf[1] == ':')
845 lastsep[1] = '\0'; // can't remove backslash of "x:\"
851 // Find a real application on the path (possibly following symlinks)
853 find_app_on_path (const char *app, bool showall = false)
855 const char *papp = find_on_path (app, ".exe", showall, false, true);
860 wide_path wpath (papp);
862 CreateFileW (wpath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
863 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
864 if (fh == INVALID_HANDLE_VALUE)
869 static char tmp[SYMLINK_MAX + 1];
870 if (!readlink (fh, tmp, SYMLINK_MAX))
871 display_error("readlink failed");
873 /* Resolve the linkname relative to the directory of the link. */
874 char *ptr = cygpath_rel (dirname (papp), tmp, NULL);
875 printf (" -> %s\n", ptr);
876 if (!strchr (ptr, '\\'))
879 strncpy (tmp, cygpath (papp, NULL), SYMLINK_MAX);
880 lastsep = strrchr (tmp, '\\');
881 strncpy (lastsep+1, ptr, SYMLINK_MAX - (lastsep-tmp));
884 if (!CloseHandle (fh))
885 display_error ("find_app_on_path: CloseHandle()");
886 /* FIXME: We leak the ptr returned by cygpath() here which is a
888 return find_app_on_path (ptr, showall);
891 if (!CloseHandle (fh))
892 display_error ("find_app_on_path: CloseHandle()");
896 // Return true on success, false if error printed
898 cygcheck (const char *app)
900 const char *papp = find_app_on_path (app, 1);
903 display_error ("could not find '%s'\n", app);
908 char *sep = strpbrk (papp, ":/\\");
911 static char dot[] = ".";
917 s = (char *) malloc (n + 2);
918 memcpy ((char *) s, papp, n);
919 strcpy (s + n, "\\");
924 return track_down (papp, ".exe", 0);
935 show_reg (RegInfo * ri, int nest)
939 show_reg (ri->prev, 1);
941 printf ("%s\\", ri->name);
943 printf ("%s\n", ri->name);
947 scan_registry (RegInfo * prev, HKEY hKey, char *name, int cygwin, bool wow64)
955 for (cp = name; *cp; cp++)
956 if (strncasecmp (cp, "Cygwin", 6) == 0)
959 DWORD num_subkeys, max_subkey_len, num_values;
960 DWORD max_value_len, max_valdata_len, i;
961 if (RegQueryInfoKey (hKey, 0, 0, 0, &num_subkeys, &max_subkey_len, 0,
962 &num_values, &max_value_len, &max_valdata_len, 0, 0)
967 FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, 0, GetLastError (),
968 MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), tmp, 400, 0);
969 printf ("RegQueryInfoKey: %s\n", tmp);
978 char *value_name = (char *) malloc (max_value_len + 1);
979 if (value_name == NULL)
981 display_error ("scan_registry: malloc()");
985 char *value_data = (char *) malloc (max_valdata_len + 1);
986 if (value_data == NULL)
988 display_error ("scan_registry: malloc()");
992 for (i = 0; i < num_values; i++)
994 DWORD dlen = max_valdata_len + 1;
995 DWORD nlen = max_value_len + 1;
997 RegEnumValue (hKey, i, value_name, &nlen, 0,
998 &type, (BYTE *) value_data, &dlen);
1000 printf (" %s = ", i ? value_name : "(default)");
1004 printf ("0x%08x\n", *(unsigned *) value_data);
1008 printf ("'%s'\n", value_data);
1011 printf ("(unsupported type)\n");
1020 char *subkey_name = (char *) malloc (max_subkey_len + 1);
1021 for (i = 0; i < num_subkeys; i++)
1023 if (RegEnumKey (hKey, i, subkey_name, max_subkey_len + 1) ==
1027 /* Don't recurse more than one level into the WOW64 subkey since
1028 that would lead to an endless recursion. */
1029 if (!strcasecmp (subkey_name, "Wow6432Node"))
1035 if (RegOpenKeyEx (hKey, subkey_name, 0, KEY_READ, &sKey)
1038 scan_registry (&ri, sKey, subkey_name, cygwin, wow64);
1039 if (RegCloseKey (sKey) != ERROR_SUCCESS)
1040 display_error ("scan_registry: RegCloseKey()");
1050 char *groups[16384];
1052 char *id = cygpath ("/bin/id.exe", NULL);
1053 for (char *p = id; (p = strchr (p, '/')); p++)
1056 if (access (id, X_OK))
1058 fprintf (stderr, "'id' program not found\n");
1063 snprintf (buf, sizeof (buf), "\"%s\"", id);
1064 FILE *f = popen (buf, "rt");
1067 fgets (buf, sizeof (buf), f);
1069 char *uid = strtok (buf, ")");
1071 uid += strlen ("uid=");
1074 fprintf (stderr, "garbled output from 'id' command - no uid= found\n");
1077 char *gid = strtok (NULL, ")");
1079 gid += strlen ("gid=") + 1;
1082 fprintf (stderr, "garbled output from 'id' command - no gid= found\n");
1086 char **ng = groups - 1;
1087 size_t len_uid = strlen ("UID: )") + strlen (uid);
1088 size_t len_gid = strlen ("GID: )") + strlen (gid);
1089 *++ng = groups[0] = (char *) alloca (len_uid + 1);
1090 *++ng = groups[1] = (char *) alloca (len_gid + 1);
1091 sprintf (groups[0], "UID: %s)", uid);
1092 sprintf (groups[1], "GID: %s)", gid);
1093 size_t sz = max (len_uid, len_gid);
1094 while ((*++ng = strtok (NULL, ",")))
1096 char *p = strchr (*ng, '\n');
1099 if (ng == groups + 2)
1100 *ng += strlen (" groups=");
1101 size_t len = strlen (*ng);
1107 printf ("\nOutput from %s\n", id);
1108 int n = 80 / (int) ++sz;
1109 int i = n > 2 ? n - 2 : 0;
1111 for (char **g = groups; g <= ng; g++)
1112 if ((g != ng) && (++i < n))
1113 printf ("%*s", sz, *g);
1121 /* This dumps information about each installed cygwin service, if cygrunsrv
1124 dump_sysinfo_services ()
1129 bool no_services = false;
1132 printf ("\nChecking for any Cygwin services... %s\n\n",
1133 verbose ? "" : "(use -v for more detail)");
1135 fputc ('\n', stdout);
1137 /* find the location of cygrunsrv.exe */
1138 char *cygrunsrv = cygpath ("/bin/cygrunsrv.exe", NULL);
1139 for (char *p = cygrunsrv; (p = strchr (p, '/')); p++)
1142 if (access (cygrunsrv, X_OK))
1144 puts ("Can't find the cygrunsrv utility, skipping services check.\n");
1148 /* check for a recent cygrunsrv */
1149 snprintf (buf, sizeof (buf), "\"%s\" --version", cygrunsrv);
1150 if ((f = popen (buf, "rt")) == NULL)
1152 printf ("Failed to execute '%s', skipping services check.\n", buf);
1156 int ret = fscanf (f, "cygrunsrv V%u.%u", &maj, &min);
1157 if (ferror (f) || feof (f) || ret == EOF || maj < 1 || min < 10)
1159 puts ("The version of cygrunsrv installed is too old to dump service info.\n");
1164 /* For verbose mode, just run cygrunsrv --list --verbose and copy output
1165 verbatim; otherwise run cygrunsrv --list and then cygrunsrv --query for
1167 snprintf (buf, sizeof (buf), (verbose ? "\"%s\" --list --verbose" : "\"%s\" --list"),
1169 if ((f = popen (buf, "rt")) == NULL)
1171 printf ("Failed to execute '%s', skipping services check.\n", buf);
1177 /* copy output to stdout */
1179 while (!feof (f) && !ferror (f))
1180 nchars += fwrite ((void *) buf, 1,
1181 fread ((void *) buf, 1, sizeof (buf), f), stdout);
1183 /* cygrunsrv outputs nothing if there are no cygwin services found */
1190 /* read the output of --list, and then run --query for each service */
1191 size_t nchars = fread ((void *) buf, 1, sizeof (buf) - 1, f);
1196 for (char *srv = strtok (buf, "\n"); srv; srv = strtok (NULL, "\n"))
1198 snprintf (buf2, sizeof (buf2), "\"%s\" --query %s", cygrunsrv, srv);
1199 if ((f = popen (buf2, "rt")) == NULL)
1201 printf ("Failed to execute '%s', skipping services check.\n", buf2);
1205 /* copy output to stdout */
1206 while (!feof (f) && !ferror (f))
1207 fwrite ((void *) buf2, 1,
1208 fread ((void *) buf2, 1, sizeof (buf2), f), stdout);
1215 /* inform the user if nothing found */
1217 puts ("No Cygwin services found.\n");
1227 handle_reg_installation (handle_reg_t what)
1231 if (what == PRINT_KEY)
1232 printf ("Cygwin installations found in the registry:\n");
1233 for (int i = 0; i < 2; ++i)
1234 if (RegOpenKeyEx (i ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE,
1235 "SOFTWARE\\Cygwin\\Installations", 0,
1236 what == DELETE_KEY ? KEY_READ | KEY_WRITE : KEY_READ,
1240 char name[32], data[PATH_MAX];
1241 DWORD nsize, dsize, type;
1244 for (DWORD index = 0;
1245 (ret = RegEnumValue (key, index, name, (nsize = 32, &nsize), 0,
1246 &type, (PBYTE) data,
1247 (dsize = PATH_MAX, &dsize)))
1248 != ERROR_NO_MORE_ITEMS; ++index)
1249 if (ret == ERROR_SUCCESS && dsize > 5)
1251 char *path = data + 4;
1253 *(path += 2) = '\\';
1254 if (what == PRINT_KEY)
1255 printf (" %s Key: %s Path: %s", i ? "User: " : "System:",
1257 strcat (path, "\\bin\\cygwin1.dll");
1258 if (what == PRINT_KEY)
1259 printf ("%s\n", access (path, F_OK) ? " (ORPHANED)" : "");
1260 else if (access (path, F_OK))
1262 RegDeleteValue (key, name);
1263 /* Start over since index is not reliable anymore. */
1270 if (what == PRINT_KEY)
1275 print_reg_installations ()
1277 handle_reg_installation (PRINT_KEY);
1281 del_orphaned_reg_installations ()
1283 handle_reg_installation (DELETE_KEY);
1286 /* Unfortunately neither mingw nor Windows know this function. */
1288 memmem (char *haystack, size_t haystacklen,
1289 const char *needle, size_t needlelen)
1293 while (needlelen <= haystacklen)
1295 if (!memcmp (haystack, needle, needlelen))
1304 handle_unique_object_name (int opt, char *path)
1307 void *haystack = NULL;
1309 if (!path || !*path)
1312 DWORD access, share, protect, mapping;
1314 if (opt == CO_SHOW_UON)
1316 access = GENERIC_READ;
1317 share = FILE_SHARE_VALID_FLAGS;
1318 protect = PAGE_READONLY;
1319 mapping = FILE_MAP_READ;
1323 access = GENERIC_READ | GENERIC_WRITE;
1325 protect = PAGE_READWRITE;
1326 mapping = FILE_MAP_WRITE;
1329 fh = CreateFile (path, access, share, NULL, OPEN_EXISTING,
1330 FILE_FLAG_BACKUP_SEMANTICS, NULL);
1331 if (fh == INVALID_HANDLE_VALUE)
1333 DWORD err = GetLastError ();
1336 case ERROR_SHARING_VIOLATION:
1337 display_error ("%s still used by other Cygwin processes.\n"
1338 "Please stop all of them and retry.", path);
1340 case ERROR_ACCESS_DENIED:
1342 "Your permissions are not sufficient to change the file \"%s\"",
1345 case ERROR_FILE_NOT_FOUND:
1346 display_error ("%s: No such file.", path);
1349 display_error (path, true, false);
1354 if (!(fm = CreateFileMapping (fh, NULL, protect, 0, 0, NULL)))
1355 display_error ("CreateFileMapping");
1356 else if (!(haystack = MapViewOfFile (fm, mapping, 0, 0, 0)))
1357 display_error ("MapViewOfFile");
1360 size_t haystacklen = GetFileSize (fh, NULL);
1361 cygwin_props_t *cygwin_props = (cygwin_props_t *)
1362 memmem ((char *) haystack, haystacklen,
1363 CYGWIN_PROPS_MAGIC, sizeof (CYGWIN_PROPS_MAGIC));
1365 display_error ("Can't find Cygwin properties in %s", path);
1368 if (opt != CO_SHOW_UON)
1369 cygwin_props->disable_key = opt - CO_ENABLE_UON;
1370 printf ("Unique object names are %s\n",
1371 cygwin_props->disable_key ? "disabled" : "enabled");
1372 UnmapViewOfFile (haystack);
1379 UnmapViewOfFile (haystack);
1392 char *found_cygwin_dll;
1394 bool more_info = true;
1396 DWORD obcaseinsensitive = 1;
1399 printf ("\nCygwin Configuration Diagnostics\n");
1401 printf ("Current System Time: %s\n", ctime (&now));
1403 OSVERSIONINFOEX osversion;
1404 osversion.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEX);
1405 if (!GetVersionEx (reinterpret_cast<LPOSVERSIONINFO>(&osversion)))
1408 osversion.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
1409 if (!GetVersionEx (reinterpret_cast<LPOSVERSIONINFO>(&osversion)))
1410 display_error ("dump_sysinfo: GetVersionEx()");
1413 HMODULE k32 = GetModuleHandleW (L"kernel32.dll");
1415 switch (osversion.dwPlatformId)
1417 case VER_PLATFORM_WIN32s:
1418 strcpy (osname, "32s (not supported)");
1420 case VER_PLATFORM_WIN32_WINDOWS:
1421 strcpy (osname, "95/98/Me (not supported)");
1423 case VER_PLATFORM_WIN32_NT:
1425 if (osversion.dwMajorVersion == 6)
1427 BOOL (WINAPI *GetProductInfo) (DWORD, DWORD, DWORD, DWORD, PDWORD) =
1428 (BOOL (WINAPI *)(DWORD, DWORD, DWORD, DWORD, PDWORD))
1429 GetProcAddress (k32, "GetProductInfo");
1430 if (osversion.dwMinorVersion == 0)
1431 strcpy (osname, osversion.wProductType == VER_NT_WORKSTATION
1432 ? "Vista" : "2008");
1433 else if (osversion.dwMinorVersion == 1)
1434 strcpy (osname, osversion.wProductType == VER_NT_WORKSTATION
1437 if (GetProductInfo (osversion.dwMajorVersion,
1438 osversion.dwMinorVersion,
1439 osversion.wServicePackMajor,
1440 osversion.wServicePackMinor,
1443 #define PRODUCT_UNLICENSED 0xabcdabcd
1444 #define PRODUCT_ULTIMATE_E 0x00000047
1445 const char *products[] =
1447 /* 0x00000000 */ "",
1448 /* 0x00000001 */ " Ultimate",
1449 /* 0x00000002 */ " Home Basic",
1450 /* 0x00000003 */ " Home Premium",
1451 /* 0x00000004 */ " Enterprise",
1452 /* 0x00000005 */ " Home Basic N",
1453 /* 0x00000006 */ " Business",
1454 /* 0x00000007 */ " Server Standard",
1455 /* 0x00000008 */ " Server Datacenter",
1456 /* 0x00000009 */ " Small Business Server",
1457 /* 0x0000000a */ " Server Enterprise",
1458 /* 0x0000000b */ " Starter",
1459 /* 0x0000000c */ " Server Datacenter Core",
1460 /* 0x0000000d */ " Server Standard Core",
1461 /* 0x0000000e */ " Server Enterprise Core",
1462 /* 0x0000000f */ " Server Enterprise for Itanium-based Systems",
1463 /* 0x00000000 */ " Business N",
1464 /* 0x00000011 */ " Web Server",
1465 /* 0x00000012 */ " HPC Edition",
1466 /* 0x00000013 */ " Home Server",
1467 /* 0x00000014 */ " Storage Server Express",
1468 /* 0x00000015 */ " Storage Server Standard",
1469 /* 0x00000016 */ " Storage Server Workgroup",
1470 /* 0x00000017 */ " Storage Server Enterprise",
1471 /* 0x00000018 */ " for Windows Essential Server Solutions",
1472 /* 0x00000019 */ "",
1473 /* 0x0000001a */ " Home Premium N",
1474 /* 0x0000001b */ " Enterprise N",
1475 /* 0x0000001c */ " Ultimate N",
1476 /* 0x0000001d */ " Web Server Core",
1477 /* 0x0000001e */ " Essential Business Server Management Server",
1478 /* 0x0000001f */ " Essential Business Server Security Server"
1479 /* 0x00000020 */ " Essential Business Server Messaging Server",
1480 /* 0x00000021 */ " Server Foundation",
1481 /* 0x00000022 */ "",
1482 /* 0x00000023 */ " without Hyper-V for Windows Essential Server Solutions",
1483 /* 0x00000024 */ " Server Standard without Hyper-V",
1484 /* 0x00000025 */ " Server Datacenter without Hyper-V",
1485 /* 0x00000026 */ " Server Enterprise without Hyper-V",
1486 /* 0x00000027 */ " Server Datacenter Core without Hyper-V",
1487 /* 0x00000028 */ " Server Standard Core without Hyper-V",
1488 /* 0x00000029 */ " Server Enterprise Core without Hyper-V",
1489 /* 0x0000002a */ " Hyper-V Server",
1490 /* 0x0000002b */ "",
1491 /* 0x0000002c */ "",
1492 /* 0x0000002d */ "",
1493 /* 0x0000002e */ "",
1494 /* 0x0000002f */ " Starter N",
1495 /* 0x00000030 */ " Professional",
1496 /* 0x00000031 */ " Professional N",
1497 /* 0x00000032 */ "",
1498 /* 0x00000033 */ "",
1499 /* 0x00000034 */ "",
1500 /* 0x00000035 */ "",
1501 /* 0x00000036 */ "",
1502 /* 0x00000037 */ "",
1503 /* 0x00000038 */ "",
1504 /* 0x00000039 */ "",
1505 /* 0x0000003a */ "",
1506 /* 0x0000003b */ "",
1507 /* 0x0000003c */ "",
1508 /* 0x0000003d */ "",
1509 /* 0x0000003e */ "",
1510 /* 0x0000003f */ "",
1511 /* 0x00000040 */ "",
1512 /* 0x00000041 */ "",
1513 /* 0x00000042 */ " Starter E",
1514 /* 0x00000043 */ " Home Basic E",
1515 /* 0x00000044 */ " Home Premium E",
1516 /* 0x00000045 */ " Professional E",
1517 /* 0x00000046 */ " Enterprise E",
1518 /* 0x00000047 */ " Ultimate E"
1520 if (prod == PRODUCT_UNLICENSED)
1521 strcat (osname, "Unlicensed");
1522 else if (prod > PRODUCT_ULTIMATE_E)
1523 strcat (osname, "");
1525 strcat (osname, products[prod]);
1531 else if (osversion.dwMajorVersion == 5)
1533 if (osversion.dwMinorVersion == 0)
1535 strcpy (osname, "2000");
1536 if (osversion.wProductType == VER_NT_WORKSTATION)
1537 strcat (osname, " Professional");
1538 else if (osversion.wSuiteMask & VER_SUITE_DATACENTER)
1539 strcat (osname, " Datacenter Server");
1540 else if (osversion.wSuiteMask & VER_SUITE_ENTERPRISE)
1541 strcat (osname, " Advanced Server");
1543 strcat (osname, " Server");
1545 else if (osversion.dwMinorVersion == 1)
1547 strcpy (osname, "XP");
1548 if (GetSystemMetrics (SM_MEDIACENTER))
1549 strcat (osname, " Media Center Edition");
1550 else if (GetSystemMetrics (SM_TABLETPC))
1551 strcat (osname, " Tablet PC Edition");
1552 else if (GetSystemMetrics (SM_STARTER))
1553 strcat (osname, " Starter Edition");
1554 else if (osversion.wSuiteMask & VER_SUITE_PERSONAL)
1555 strcat (osname, " Home Edition");
1557 strcat (osname, " Professional");
1559 else if (osversion.dwMinorVersion == 2)
1561 strcpy (osname, "2003 Server");
1562 if (GetSystemMetrics (SM_SERVERR2))
1563 strcat (osname, " R2");
1564 if (osversion.wSuiteMask & VER_SUITE_BLADE)
1565 strcat (osname, " Web Edition");
1566 else if (osversion.wSuiteMask & VER_SUITE_DATACENTER)
1567 strcat (osname, " Datacenter Edition");
1568 else if (osversion.wSuiteMask & VER_SUITE_ENTERPRISE)
1569 strcat (osname, " Enterprise Edition");
1570 else if (osversion.wSuiteMask & VER_SUITE_COMPUTE_SERVER)
1571 strcat (osname, " Compute Cluster Edition");
1574 else if (osversion.dwMajorVersion == 4)
1576 strcpy (osname, "NT 4");
1579 if (osversion.wProductType == VER_NT_WORKSTATION)
1580 strcat (osname, " Workstation");
1583 strcat (osname, " Server");
1584 if (osversion.wSuiteMask & VER_SUITE_ENTERPRISE)
1585 strcat (osname, " Enterprise Edition");
1590 strcpy (osname, "NT");
1593 strcpy (osname, "??");
1596 printf ("Windows %s Ver %lu.%lu Build %lu %s\n", osname,
1597 osversion.dwMajorVersion, osversion.dwMinorVersion,
1598 osversion.dwPlatformId == VER_PLATFORM_WIN32_NT ?
1599 osversion.dwBuildNumber : (osversion.dwBuildNumber & 0xffff),
1600 osversion.dwPlatformId == VER_PLATFORM_WIN32_NT ?
1601 osversion.szCSDVersion : "");
1603 if (osversion.dwPlatformId == VER_PLATFORM_WIN32s
1604 || osversion.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
1605 exit (EXIT_FAILURE);
1607 BOOL (WINAPI *wow64_func) (HANDLE, PBOOL) = (BOOL (WINAPI *) (HANDLE, PBOOL))
1608 GetProcAddress (k32, "IsWow64Process");
1609 BOOL is_wow64 = FALSE;
1610 if (wow64_func && wow64_func (GetCurrentProcess (), &is_wow64) && is_wow64)
1612 void (WINAPI *nativinfo) (LPSYSTEM_INFO) = (void (WINAPI *)
1613 (LPSYSTEM_INFO)) GetProcAddress (k32, "GetNativeSystemInfo");
1614 SYSTEM_INFO natinfo;
1615 nativinfo (&natinfo);
1616 fputs ("\nRunning under WOW64 on ", stdout);
1617 switch (natinfo.wProcessorArchitecture)
1619 case PROCESSOR_ARCHITECTURE_IA64:
1622 case PROCESSOR_ARCHITECTURE_AMD64:
1631 if (GetSystemMetrics (SM_REMOTESESSION))
1632 printf ("\nRunning in Terminal Service session\n");
1635 char *s = getenv ("PATH"), *e;
1640 char sep = strchr (s, ';') ? ';' : ':';
1641 int count_path_items = 0;
1644 for (e = s; *e && *e != sep; e++);
1646 printf ("\t%.*s\n", e - s, s);
1660 if (!GetSystemDirectory (tmp, 4000))
1661 display_error ("dump_sysinfo: GetSystemDirectory()");
1662 printf ("\nSysDir: %s\n", tmp);
1664 GetWindowsDirectory (tmp, 4000);
1665 printf ("WinDir: %s\n\n", tmp);
1669 printf ("Here's some environment variables that may affect cygwin:\n");
1670 for (i = 0; environ[i]; i++)
1672 char *eq = strchr (environ[i], '=');
1675 /* int len = eq - environ[i]; */
1676 for (j = 0; known_env_vars[j]; j++)
1679 if (strcmp (environ[i], "PATH") == 0)
1680 continue; /* we handle this one specially */
1681 if (strcasecmp (environ[i], known_env_vars[j]) == 0)
1682 printf ("%s = '%s'\n", environ[i], eq + 1);
1691 printf ("Here's the rest of your environment variables:\n");
1692 for (i = 0; environ[i]; i++)
1695 char *eq = strchr (environ[i], '=');
1698 /* int len = eq - environ[i]; */
1699 for (j = 0; known_env_vars[j]; j++)
1702 if (strcasecmp (environ[i], known_env_vars[j]) == 0)
1709 printf ("%s = '%s'\n", environ[i], eq + 1);
1719 printf ("Scanning registry for keys with 'Cygwin' in them...\n");
1720 scan_registry (0, HKEY_CURRENT_USER,
1721 (char *) "HKEY_CURRENT_USER", 0, false);
1722 scan_registry (0, HKEY_LOCAL_MACHINE,
1723 (char *) "HKEY_LOCAL_MACHINE", 0, false);
1727 printf ("Use '-r' to scan registry\n\n");
1729 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE,
1730 "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\kernel",
1731 0, KEY_READ, &key) == ERROR_SUCCESS)
1734 RegQueryValueEx (key, "obcaseinsensitive", NULL, NULL,
1735 (LPBYTE) &obcaseinsensitive, &size);
1738 printf ("obcaseinsensitive set to %lu\n\n", obcaseinsensitive);
1740 print_reg_installations ();
1744 printf ("Listing available drives...\n");
1745 printf ("Drv Type Size Used Flags Name\n");
1748 SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
1749 int drivemask = GetLogicalDrives ();
1751 BOOL (WINAPI * gdfse) (LPCSTR, long long *, long long *, long long *) =
1752 (BOOL (WINAPI *) (LPCSTR, long long *, long long *, long long *))
1753 GetProcAddress (k32, "GetDiskFreeSpaceExA");
1755 for (i = 0; i < 26; i++)
1757 if (!(drivemask & (1 << i)))
1759 char drive[4], name[200], fsname[200];
1760 DWORD serno = 0, maxnamelen = 0, flags = 0;
1761 name[0] = fsname[0] = 0;
1762 sprintf (drive, "%c:\\", i + 'a');
1763 /* Report all errors, except if the Volume is ERROR_NOT_READY.
1764 ERROR_NOT_READY is returned when removeable media drives are empty
1765 (CD, floppy, etc.) */
1766 if (!GetVolumeInformation (drive, name, sizeof (name), &serno,
1767 &maxnamelen, &flags, fsname,
1769 && GetLastError () != ERROR_NOT_READY)
1771 # define FMT "dump_sysinfo: GetVolumeInformation() for drive %c:"
1772 char buf[sizeof (FMT)];
1773 sprintf (buf, FMT, 'A' + i);
1774 display_error (buf);
1778 int dtype = GetDriveType (drive);
1779 char drive_type[4] = "unk";
1782 case DRIVE_REMOVABLE:
1783 strcpy (drive_type, "fd ");
1786 strcpy (drive_type, "hd ");
1789 strcpy (drive_type, "net");
1792 strcpy (drive_type, "cd ");
1795 strcpy (drive_type, "ram");
1798 strcpy (drive_type, "unk");
1801 long capacity_mb = -1;
1802 int percent_full = -1;
1804 long long free_me = 0ULL, free_bytes = 0ULL, total_bytes = 1ULL;
1805 if (gdfse != NULL && gdfse (drive, &free_me, &total_bytes, &free_bytes))
1807 capacity_mb = total_bytes / (1024L * 1024L);
1808 percent_full = 100 - (int) ((100.0 * free_me) / total_bytes);
1812 DWORD spc = 0, bps = 0, fc = 0, tc = 1;
1813 if (GetDiskFreeSpace (drive, &spc, &bps, &fc, &tc))
1815 capacity_mb = (spc * bps * tc) / (1024 * 1024);
1816 percent_full = 100 - (int) ((100.0 * fc) / tc);
1820 printf ("%.2s %s %-6s ", drive, drive_type, fsname);
1821 if (capacity_mb >= 0)
1822 printf ("%7dMb %3d%% ", (int) capacity_mb, (int) percent_full);
1824 printf (" N/A N/A ");
1825 printf ("%s %s %s %s %s %s %s\n",
1826 flags & FS_CASE_IS_PRESERVED ? "CP" : " ",
1827 flags & FS_CASE_SENSITIVE ? "CS" : " ",
1828 flags & FS_UNICODE_STORED_ON_DISK ? "UN" : " ",
1829 flags & FS_PERSISTENT_ACLS ? "PA" : " ",
1830 flags & FS_FILE_COMPRESSION ? "FC" : " ",
1831 flags & FS_VOL_IS_COMPRESSED ? "VC" : " ",
1833 flags & FILE_SUPPORTS_ENCRYPTION ? "EN" : " ",
1834 flags & FILE_SUPPORTS_OBJECT_IDS ? "OI" : " ",
1835 flags & FILE_SUPPORTS_REPARSE_POINTS ? "RP" : " ",
1836 flags & FILE_SUPPORTS_SPARSE_FILES ? "SP" : " ",
1837 flags & FILE_VOLUME_QUOTAS ? "QU" : " ",
1842 SetErrorMode (prev_mode);
1846 "fd = floppy, hd = hard drive, cd = CD-ROM\n"
1847 "net= Network Share, ram= RAM drive, unk= Unknown\n"
1848 "CP = Case Preserving, CS = Case Sensitive, UN = Unicode\n"
1849 "PA = Persistent ACLS, FC = File Compression, VC = Volume Compression");
1853 unsigned ml_fsname = 4, ml_dir = 7, ml_type = 6;
1854 bool ml_trailing = false;
1858 while ((mnt = getmntent (0)))
1860 unsigned n = (int) strlen (mnt->mnt_fsname);
1861 ml_trailing |= (n > 1 && strchr ("\\/", mnt->mnt_fsname[n - 1]));
1864 n = (int) strlen (mnt->mnt_dir);
1865 ml_trailing |= (n > 1 && strchr ("\\/", mnt->mnt_dir[n - 1]));
1871 puts ("Warning: Mount entries should not have a trailing (back)slash\n");
1876 ("Mount entries: these map POSIX directories to your NT drives.\n");
1877 printf ("%-*s %-*s %-*s %s\n", ml_fsname, "-NT-", ml_dir, "-POSIX-",
1878 ml_type, "-Type-", "-Flags-");
1882 while ((mnt = getmntent (0)))
1884 printf ("%-*s %-*s %-*s %s\n",
1885 ml_fsname, mnt->mnt_fsname,
1886 ml_dir, mnt->mnt_dir, ml_type, mnt->mnt_type, mnt->mnt_opts);
1892 ("Looking to see where common programs can be found, if at all...\n");
1893 for (i = 0; common_apps[i].name; i++)
1894 if (!find_app_on_path ((char *) common_apps[i].name, 1))
1896 if (common_apps[i].missing_is_good)
1897 printf ("Not Found: %s (good!)\n", common_apps[i].name);
1899 printf ("Not Found: %s\n", common_apps[i].name);
1904 printf ("Looking for various Cygwin DLLs... (-v gives version info)\n");
1905 int cygwin_dll_count = 0;
1906 char cygdll_path[32768];
1907 for (pathlike *pth = paths; pth->dir; pth++)
1909 WIN32_FIND_DATAW ffinfo;
1910 sprintf (tmp, "%s*.*", pth->dir);
1911 wide_path wpath (tmp);
1912 HANDLE ff = FindFirstFileW (wpath, &ffinfo);
1913 int found = (ff != INVALID_HANDLE_VALUE);
1914 found_cygwin_dll = NULL;
1917 char f[FILENAME_MAX + 1];
1918 wcstombs (f, ffinfo.cFileName, sizeof f);
1919 if (strcasecmp (f + strlen (f) - 4, ".dll") == 0)
1921 if (strncasecmp (f, "cyg", 3) == 0)
1923 sprintf (tmp, "%s%s", pth->dir, f);
1924 if (strcasecmp (f, "cygwin1.dll") == 0)
1926 if (!cygwin_dll_count)
1927 strcpy (cygdll_path, pth->dir);
1928 if (!cygwin_dll_count
1929 || strcasecmp (cygdll_path, pth->dir) != 0)
1931 found_cygwin_dll = strdup (tmp);
1937 found = FindNextFileW (ff, &ffinfo);
1939 if (found_cygwin_dll)
1941 ls (found_cygwin_dll);
1942 free (found_cygwin_dll);
1947 if (cygwin_dll_count > 1)
1948 puts ("Warning: There are multiple cygwin1.dlls on your path");
1949 if (!cygwin_dll_count)
1950 puts ("Warning: cygwin1.dll not found on your path");
1952 dump_dodgy_apps (verbose);
1955 dump_sysinfo_services ();
1961 HANDLE h = CreateFileW (L"CONIN$", GENERIC_READ | GENERIC_WRITE,
1962 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
1963 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
1965 if (h == INVALID_HANDLE_VALUE || h == NULL)
1966 return (display_error ("check_keys: Opening CONIN$"));
1970 if (!GetConsoleMode (h, &mode))
1971 display_error ("check_keys: GetConsoleMode()");
1974 mode &= ~ENABLE_PROCESSED_INPUT;
1975 if (!SetConsoleMode (h, mode))
1976 display_error ("check_keys: SetConsoleMode()");
1979 fputs ("\nThis key check works only in a console window,", stderr);
1980 fputs (" _NOT_ in a terminal session!\n", stderr);
1981 fputs ("Abort with Ctrl+C if in a terminal session.\n\n", stderr);
1982 fputs ("Press 'q' to exit.\n", stderr);
1984 INPUT_RECORD in, prev_in;
1986 // Drop first <RETURN> key
1987 ReadConsoleInputW (h, &in, 1, &mode);
1989 memset (&in, 0, sizeof in);
1994 if (!ReadConsoleInputW (h, &in, 1, &mode))
1995 display_error ("check_keys: ReadConsoleInput()");
1997 if (!memcmp (&in, &prev_in, sizeof in))
2000 switch (in.EventType)
2003 printf ("%s %ux VK: 0x%04x VS: 0x%04x C: 0x%04x CTRL: ",
2004 in.Event.KeyEvent.bKeyDown ? "Pressed " : "Released",
2005 in.Event.KeyEvent.wRepeatCount,
2006 in.Event.KeyEvent.wVirtualKeyCode,
2007 in.Event.KeyEvent.wVirtualScanCode,
2008 (unsigned char) in.Event.KeyEvent.uChar.UnicodeChar);
2009 fputs (in.Event.KeyEvent.dwControlKeyState & CAPSLOCK_ON ?
2010 "CL " : "-- ", stdout);
2011 fputs (in.Event.KeyEvent.dwControlKeyState & ENHANCED_KEY ?
2012 "EK " : "-- ", stdout);
2013 fputs (in.Event.KeyEvent.dwControlKeyState & LEFT_ALT_PRESSED ?
2014 "LA " : "-- ", stdout);
2015 fputs (in.Event.KeyEvent.dwControlKeyState & LEFT_CTRL_PRESSED ?
2016 "LC " : "-- ", stdout);
2017 fputs (in.Event.KeyEvent.dwControlKeyState & NUMLOCK_ON ?
2018 "NL " : "-- ", stdout);
2019 fputs (in.Event.KeyEvent.dwControlKeyState & RIGHT_ALT_PRESSED ?
2020 "RA " : "-- ", stdout);
2021 fputs (in.Event.KeyEvent.dwControlKeyState & RIGHT_CTRL_PRESSED ?
2022 "RC " : "-- ", stdout);
2023 fputs (in.Event.KeyEvent.dwControlKeyState & SCROLLLOCK_ON ?
2024 "SL " : "-- ", stdout);
2025 fputs (in.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED ?
2026 "SH " : "-- ", stdout);
2027 fputc ('\n', stdout);
2034 while (in.EventType != KEY_EVENT ||
2035 in.Event.KeyEvent.bKeyDown != FALSE ||
2036 in.Event.KeyEvent.uChar.UnicodeChar != L'q');
2042 /* RFC1738 says that these do not need to be escaped. */
2043 static const char safe_chars[] = "$-_.+!*'(),";
2045 /* the URL to query. */
2046 static const char base_url[] =
2047 "http://cygwin.com/cgi-bin2/package-grep.cgi?text=1&grep=";
2049 /* Queries Cygwin web site for packages containing files matching a regexp.
2050 Return value is 1 if there was a problem, otherwise 0. */
2052 package_grep (char *search)
2056 /* Attempt to dynamically load the necessary WinInet API functions so that
2057 cygcheck can still function on older systems without IE. */
2059 if (!(hWinInet = LoadLibrary ("wininet.dll")))
2061 fputs ("Unable to locate WININET.DLL. This feature requires Microsoft "
2062 "Internet Explorer v3 or later to function.\n", stderr);
2066 /* InternetCloseHandle is used outside this function so it is declared
2067 global. The rest of these functions are only used here, so declare them
2068 and call GetProcAddress for each of them with the following macro. */
2070 pInternetCloseHandle = (BOOL (WINAPI *) (HINTERNET))
2071 GetProcAddress (hWinInet, "InternetCloseHandle");
2072 #define make_func_pointer(name, ret, args) ret (WINAPI * p##name) args = \
2073 (ret (WINAPI *) args) GetProcAddress (hWinInet, #name);
2074 make_func_pointer (InternetAttemptConnect, DWORD, (DWORD));
2075 make_func_pointer (InternetOpenA, HINTERNET, (LPCSTR, DWORD, LPCSTR, LPCSTR,
2077 make_func_pointer (InternetOpenUrlA, HINTERNET, (HINTERNET, LPCSTR, LPCSTR,
2078 DWORD, DWORD, DWORD));
2079 make_func_pointer (InternetReadFile, BOOL, (HINTERNET, PVOID, DWORD, PDWORD));
2080 make_func_pointer (HttpQueryInfoA, BOOL, (HINTERNET, DWORD, PVOID, PDWORD,
2082 #undef make_func_pointer
2084 if(!pInternetCloseHandle || !pInternetAttemptConnect || !pInternetOpenA
2085 || !pInternetOpenUrlA || !pInternetReadFile || !pHttpQueryInfoA)
2087 fputs ("Unable to load one or more functions from WININET.DLL. This "
2088 "feature requires Microsoft Internet Explorer v3 or later to "
2089 "function.\n", stderr);
2093 /* construct the actual URL by escaping */
2094 char *url = (char *) alloca (sizeof (base_url) + strlen (search) * 3);
2095 strcpy (url, base_url);
2098 for (dest = &url[sizeof (base_url) - 1]; *search; search++)
2100 if (isalnum (*search)
2101 || memchr (safe_chars, *search, sizeof (safe_chars) - 1))
2108 sprintf (dest, "%02x", (unsigned char) *search);
2114 /* Connect to the net and open the URL. */
2115 if (pInternetAttemptConnect (0) != ERROR_SUCCESS)
2117 fputs ("An internet connection is required for this function.\n", stderr);
2121 /* Initialize WinInet and attempt to fetch our URL. */
2122 HINTERNET hi = NULL, hurl = NULL;
2123 if (!(hi = pInternetOpenA ("cygcheck", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0)))
2124 return display_internet_error ("InternetOpen() failed", NULL);
2126 if (!(hurl = pInternetOpenUrlA (hi, url, NULL, 0, 0, 0)))
2127 return display_internet_error ("unable to contact cygwin.com site, "
2128 "InternetOpenUrl() failed", hi, NULL);
2130 /* Check the HTTP response code. */
2131 DWORD rc = 0, rc_s = sizeof (DWORD);
2132 if (!pHttpQueryInfoA (hurl, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER,
2133 (void *) &rc, &rc_s, NULL))
2134 return display_internet_error ("HttpQueryInfo() failed", hurl, hi, NULL);
2136 if (rc != HTTP_STATUS_OK)
2138 sprintf (buf, "error retrieving results from cygwin.com site, "
2139 "HTTP status code %lu", rc);
2140 return display_internet_error (buf, hurl, hi, NULL);
2143 /* Fetch result and print to stdout. */
2147 if (!pInternetReadFile (hurl, (void *) buf, sizeof (buf), &numread))
2148 return display_internet_error ("InternetReadFile failed", hurl, hi, NULL);
2150 fwrite ((void *) buf, (size_t) numread, 1, stdout);
2154 pInternetCloseHandle (hurl);
2155 pInternetCloseHandle (hi);
2160 usage (FILE * stream, int status)
2163 Usage: cygcheck [-v] [-h] PROGRAM\n\
2164 cygcheck -c [-d] [PACKAGE]\n\
2165 cygcheck -s [-r] [-v] [-h]\n\
2167 cygcheck -f FILE [FILE]...\n\
2168 cygcheck -l [PACKAGE]...\n\
2169 cygcheck -p REGEXP\n\
2170 cygcheck --delete-orphaned-installation-keys\n\
2171 cygcheck --enable-unique-object-names Cygwin-DLL\n\
2172 cygcheck --disable-unique-object-names Cygwin-DLL\n\
2173 cygcheck --show-unique-object-names Cygwin-DLL\n\
2175 List system information, check installed packages, or query package database.\n\
2177 At least one command option or a PROGRAM is required, as shown above.\n\
2179 PROGRAM list library (DLL) dependencies of PROGRAM\n\
2180 -c, --check-setup show installed version of PACKAGE and verify integrity\n\
2181 (or for all installed packages if none specified)\n\
2182 -d, --dump-only just list packages, do not verify (with -c)\n\
2183 -s, --sysinfo produce diagnostic system information (implies -c)\n\
2184 -r, --registry also scan registry for Cygwin settings (with -s)\n\
2185 -k, --keycheck perform a keyboard check session (must be run from a\n\
2186 plain console only, not from a pty/rxvt/xterm)\n\
2187 -f, --find-package find the package to which FILE belongs\n\
2188 -l, --list-package list contents of PACKAGE (or all packages if none given)\n\
2189 -p, --package-query search for REGEXP in the entire cygwin.com package\n\
2190 repository (requires internet connectivity)\n\
2191 --delete-orphaned-installation-keys\n\
2192 Delete installation keys of old, now unused\n\
2193 installations from the registry. Requires the right\n\
2194 to change the registry.\n\
2195 --enable-unique-object-names Cygwin-DLL\n\
2196 --disable-unique-object-names Cygwin-DLL\n\
2197 --show-unique-object-names Cygwin-DLL\n\
2198 Enable, disable, or show the setting of the\n\
2199 \"unique object names\" setting in the Cygwin DLL\n\
2200 given as argument to this option. The DLL path must\n\
2201 be given as valid Windows(!) path.\n\
2202 See the users guide for more information.\n\
2203 If you don't know what this means, don't change it.\n\
2204 -v, --verbose produce more verbose output\n\
2205 -h, --help annotate output with explanatory comments when given\n\
2206 with another command, otherwise print this help\n\
2207 -V, --version print the version of cygcheck and exit\n\
2209 Note: -c, -f, and -l only report on packages that are currently installed. To\n\
2210 search all official Cygwin packages use -p instead. The -p REGEXP matches\n\
2211 package names, descriptions, and names of files/paths within all packages.\n\
2216 struct option longopts[] = {
2217 {"check-setup", no_argument, NULL, 'c'},
2218 {"dump-only", no_argument, NULL, 'd'},
2219 {"sysinfo", no_argument, NULL, 's'},
2220 {"registry", no_argument, NULL, 'r'},
2221 {"verbose", no_argument, NULL, 'v'},
2222 {"keycheck", no_argument, NULL, 'k'},
2223 {"find-package", no_argument, NULL, 'f'},
2224 {"list-package", no_argument, NULL, 'l'},
2225 {"package-query", no_argument, NULL, 'p'},
2226 {"delete-orphaned-installation-keys", no_argument, NULL, CO_DELETE_KEYS},
2227 {"enable-unique-object-names", no_argument, NULL, CO_ENABLE_UON},
2228 {"disable-unique-object-names", no_argument, NULL, CO_DISABLE_UON},
2229 {"show-unique-object-names", no_argument, NULL, CO_SHOW_UON},
2230 {"help", no_argument, NULL, 'h'},
2231 {"version", no_argument, 0, 'V'},
2232 {0, no_argument, NULL, 0}
2235 static char opts[] = "cdsrvkflphV";
2240 const char *v = strchr (version, ':');
2250 len = strchr (v, ' ') - v;
2253 cygcheck version %.*s\n\
2254 System Checker for Cygwin\n\
2255 Copyright (C) 1998 - 2008 Red Hat, Inc.\n\
2257 ", len, v, __DATE__);
2263 int n = 1 + strchr (ev, '=') - ev;
2264 char *s = (char *) malloc (n + 1);
2271 unsigned long (*cygwin_internal) (int, ...);
2272 WCHAR cygwin_dll_path[32768];
2276 load_cygwin (int& argc, char **&argv)
2280 if (!(h = LoadLibrary ("cygwin1.dll")))
2282 GetModuleFileNameW (h, cygwin_dll_path, 32768);
2283 if ((cygwin_internal = (DWORD (*) (int, ...)) GetProcAddress (h, "cygwin_internal")))
2285 char **av = (char **) cygwin_internal (CW_ARGV);
2286 if (av && ((DWORD) av != (DWORD) -1))
2288 /* Copy cygwin's idea of the argument list into this Window application. */
2289 for (argc = 0; av[argc]; argc++)
2291 argv = (char **) calloc (argc + 1, sizeof (char *));
2292 for (char **argvp = argv; *av; av++)
2293 *argvp++ = strdup (*av);
2297 char **envp = (char **) cygwin_internal (CW_ENVP);
2298 if (envp && ((DWORD) envp != (DWORD) -1))
2300 /* Store path and revert to this value, otherwise path gets overwritten
2301 by the POSIXy Cygwin variation, which breaks cygcheck.
2302 Another approach would be to use the Cygwin PATH and convert it to
2306 while (*(env = _environ))
2308 if (strncmp (*env, "PATH=", 5) == 0)
2309 path = strdup (*env);
2312 for (char **ev = envp; *ev; ev++)
2313 if (strncmp (*ev, "PATH=", 5) != 0)
2314 putenv (strdup (*ev));
2323 main (int argc, char **argv)
2327 load_cygwin (argc, argv);
2329 /* Need POSIX sorting while parsing args, but don't forget the
2330 user's original environment. */
2331 char *posixly = getenv ("POSIXLY_CORRECT");
2332 if (posixly == NULL)
2333 (void) putenv ("POSIXLY_CORRECT=1");
2334 while ((i = getopt_long (argc, argv, opts, longopts, NULL)) != EOF)
2367 case CO_DELETE_KEYS:
2368 del_orphaned_reg = 1;
2371 case CO_DISABLE_UON:
2373 unique_object_name_opt = i;
2383 if (posixly == NULL)
2384 putenv ("POSIXLY_CORRECT=");
2386 if ((argc == 0) && !sysinfo && !keycheck && !check_setup && !list_package
2387 && !del_orphaned_reg)
2395 if ((check_setup || sysinfo || find_package || list_package || grep_packages
2396 || del_orphaned_reg || unique_object_name_opt)
2400 if ((find_package || list_package || grep_packages)
2401 && (check_setup || del_orphaned_reg))
2404 if ((check_setup || sysinfo || find_package || list_package || grep_packages
2405 || del_orphaned_reg)
2406 && unique_object_name_opt)
2409 if (dump_only && !check_setup && !sysinfo)
2412 if (find_package + list_package + grep_packages > 1)
2416 return check_keys ();
2417 if (unique_object_name_opt)
2418 return handle_unique_object_name (unique_object_name_opt, *argv);
2419 if (del_orphaned_reg)
2420 del_orphaned_reg_installations ();
2422 return package_grep (*argv);
2426 /* FIXME: Add help for check_setup and {list,find}_package */
2427 if (argc >= 1 && givehelp && !check_setup && !find_package && !list_package)
2429 printf("Here is where the OS will find your program%s, and which dlls\n",
2430 argc > 1 ? "s" : "");
2431 printf ("will be used for it. Use -v to see DLL version info\n");
2438 dump_setup (verbose, argv, !dump_only);
2439 else if (find_package)
2440 package_find (verbose, argv);
2441 else if (list_package)
2442 package_list (verbose, argv);
2444 for (i = 0; i < argc; i++)
2448 ok &= cygcheck (argv[i]);
2457 dump_setup (verbose, NULL, !dump_only);
2461 puts ("Use -h to see help about each section");
2464 return ok ? EXIT_SUCCESS : EXIT_FAILURE;