3 This file is part of Cygwin.
5 This software is a copyrighted work licensed under the terms of the
6 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
9 #define _WIN32_WINNT 0x0a00
10 #define cygwin_internal cygwin_internal_dontuse
21 #include "wide_path.h"
23 #include "../cygwin/include/cygwin/version.h"
24 #include "../cygwin/include/sys/cygwin.h"
25 #define _NOMNTENT_MACROS
26 #include "../cygwin/include/mntent.h"
27 #undef cygwin_internal
35 #define alloca __builtin_alloca
47 int grep_packages
= 0;
48 int del_orphaned_reg
= 0;
50 static char emptystr
[] = "";
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 *known_env_vars
[] = {
75 "gcc_default_options",
97 static common_apps
[] = {
126 /* Options without ASCII single char representation. */
129 CO_DELETE_KEYS
= 0x100,
132 static int num_paths
, max_paths
;
137 void check_existence (const char *fn
, int showall
, int verbose
,
138 char* first
, const char *ext1
= "",
139 const char *ext2
= "");
143 int first_nonsys_path
;
146 eprintf (const char *format
, ...)
149 va_start (ap
, format
);
150 vfprintf (stderr
, format
, ap
);
155 * display_error() is used to report failure modes
158 display_error (const char *name
, bool show_error
, bool print_failed
)
160 fprintf (stderr
, "cygcheck: %s", name
);
162 fprintf (stderr
, "%s: %lu\n",
163 print_failed
? " failed" : "", GetLastError ());
165 fprintf (stderr
, "%s\n",
166 print_failed
? " failed" : "");
171 display_error (const char *name
)
173 return display_error (name
, true, true);
177 display_error (const char *fmt
, const char *x
)
180 snprintf (buf
, sizeof buf
, fmt
, x
);
181 return display_error (buf
, false, false);
185 display_error_fmt (const char *fmt
, ...)
191 vsnprintf (buf
, sizeof buf
, fmt
, va
);
192 return display_error (buf
, false, false);
195 /* Display a WinInet error message, and close a variable number of handles.
196 (Passed a list of handles terminated by NULL.) */
198 display_internet_error (const char *message
, ...)
200 DWORD err
= GetLastError ();
205 /* in the case of a successful connection but 404 response, there is no
206 win32 error message, but we still get passed a message to display. */
209 if (FormatMessage (FORMAT_MESSAGE_FROM_HMODULE
,
210 GetModuleHandle ("wininet.dll"), err
, 0, err_buf
,
211 sizeof (err_buf
), NULL
) == 0)
212 strcpy (err_buf
, "(Unknown error)");
214 fprintf (stderr
, "cygcheck: %s: %s (win32 error %lu)\n", message
,
218 fprintf (stderr
, "cygcheck: %s\n", message
);
220 va_start (hptr
, message
);
221 while ((h
= va_arg (hptr
, HINTERNET
)) != 0)
222 InternetCloseHandle (h
);
229 add_path (char *s
, int maxlen
, bool issys
)
231 if (num_paths
>= max_paths
)
234 /* Extend path array */
235 paths
= (pathlike
*) realloc (paths
, (1 + max_paths
) * sizeof (paths
[0]));
238 pathlike
*pth
= paths
+ num_paths
;
240 /* Allocate space for directory in path list */
241 char *dir
= (char *) calloc (maxlen
+ 2, sizeof (char));
244 display_error ("add_path: calloc() failed");
248 /* Copy input directory to path list */
249 memcpy (dir
, s
, maxlen
);
251 /* Add a trailing slash by default */
252 char *e
= strchr (dir
, '\0');
253 if (e
!= dir
&& e
[-1] != '\\')
256 /* Fill out this element */
267 add_path ((char *) ".", 1, true); /* to be replaced later */
269 if (GetCurrentDirectory (4000, tmp
))
270 add_path (tmp
, strlen (tmp
), true);
272 display_error ("init_paths: GetCurrentDirectory()");
274 if (GetSystemDirectory (tmp
, 4000))
275 add_path (tmp
, strlen (tmp
), true);
277 display_error ("init_paths: GetSystemDirectory()");
278 sl
= strrchr (tmp
, '\\');
281 strcpy (sl
, "\\SYSTEM");
282 add_path (tmp
, strlen (tmp
), true);
284 GetWindowsDirectory (tmp
, 4000);
285 add_path (tmp
, strlen (tmp
), true);
287 char *wpath
= getenv ("PATH");
289 display_error ("WARNING: PATH is not set\n", "");
296 for (e
= b
; *e
&& *e
!= ';'; e
++)
297 continue; /* loop terminates at first ';' or EOS */
298 if (strncmp(b
, ".\\", 2) != 0)
299 add_path (b
, e
- b
, false);
307 #define LINK_EXTENSION ".lnk"
310 pathlike::check_existence (const char *fn
, int showall
, int verbose
,
311 char* first
, const char *ext1
, const char *ext2
)
314 snprintf (file
, sizeof file
, "%s%s%s%s", dir
, fn
, ext1
, ext2
);
316 wide_path
wpath (file
);
317 if (GetFileAttributesW (wpath
) != (DWORD
) - 1)
319 char *lastdot
= strrchr (file
, '.');
320 bool is_link
= lastdot
&& !strcmp (lastdot
, LINK_EXTENSION
);
321 // If file is a link, fix up the extension before printing
325 printf ("Found: %s\n", file
);
326 if (verbose
&& *first
!= '\0' && strcasecmp (first
, file
) != 0)
328 char *flastdot
= strrchr (first
, '.');
329 bool f_is_link
= flastdot
&& !strcmp (flastdot
, LINK_EXTENSION
);
330 // if first is a link, fix up the extension before printing
333 printf ("Warning: %s hides %s\n", first
, file
);
340 strcpy (first
, file
);
345 find_on_path (const char *in_file
, const char *ext
, bool showall
= false,
346 bool search_sys
= false, bool checklinks
= false)
348 static char rv
[4000];
350 /* Sort of a kludge but we've already tested this once, so don't try it
355 static pathlike abspath
[2] =
364 display_error ("internal error find_on_path: NULL pointer for file",
371 display_error ("internal error find_on_path: "
372 "NULL pointer for default_extension", false, false);
377 pathlike
*search_paths
;
378 if (!strpbrk (in_file
, ":/\\"))
381 search_paths
= paths
;
385 file
= cygpath (in_file
, NULL
);
386 search_paths
= abspath
;
392 display_error ("internal error find_on_path: "
393 "cygpath conversion failed for %s\n", in_file
);
397 char *hasext
= strrchr (file
, '.');
398 if (hasext
&& !strpbrk (hasext
, "/\\"))
401 for (pathlike
*pth
= search_paths
; pth
->dir
; pth
++)
402 if (!pth
->issys
|| search_sys
)
404 pth
->check_existence (file
, showall
, verbose
, rv
, ext
);
407 pth
->check_existence (file
, showall
, verbose
, rv
, ext
,
413 pth
->check_existence (file
, showall
, verbose
, rv
);
415 pth
->check_existence (file
, showall
, verbose
, rv
, LINK_EXTENSION
);
418 return *rv
? rv
: NULL
;
423 #define DID_INACTIVE 3
434 already_did (const char *file
)
437 for (d
= did
; d
; d
= d
->next
)
438 if (strcasecmp (d
->file
, file
) == 0)
440 d
= (Did
*) malloc (sizeof (Did
));
441 d
->file
= strdup (file
);
453 int size_of_raw_data
;
454 int pointer_to_raw_data
;
458 rva_to_offset (int rva
, char *sections
, int nsections
, int *sz
)
462 if (sections
== NULL
)
464 display_error ("rva_to_offset: NULL passed for sections", true, false);
468 for (i
= 0; i
< nsections
; i
++)
470 Section
*s
= (Section
*) (sections
+ i
* 40);
472 printf ("%08x < %08x < %08x ? %08x\n",
473 s
->virtual_address
, rva
,
474 s
->virtual_address
+ s
->virtual_size
, s
->pointer_to_raw_data
);
476 if (rva
>= s
->virtual_address
477 && rva
< s
->virtual_address
+ s
->virtual_size
)
480 *sz
= s
->virtual_address
+ s
->virtual_size
- rva
;
481 return rva
- s
->virtual_address
+ s
->pointer_to_raw_data
;
498 unsigned characteristics
;
500 unsigned forwarder_chain
;
505 static bool track_down (const char *file
, const char *suffix
, int lvl
);
507 #define CYGPREFIX (sizeof ("%%% Cygwin ") - 1)
509 cygwin_info (HANDLE h
)
511 char *buf
, *bufend
, *buf_start
= NULL
;
512 const char *hello
= " Cygwin DLL version info:\n";
513 DWORD size
= GetFileSize (h
, NULL
);
516 if (size
== 0xffffffff)
519 buf_start
= buf
= (char *) calloc (1, size
+ 1);
522 display_error ("cygwin_info: calloc()");
526 (void) SetFilePointer (h
, 0, NULL
, FILE_BEGIN
);
527 if (!ReadFile (h
, buf
, size
, &n
, NULL
))
533 static char dummy
[] = "\0\0\0\0\0\0\0";
534 char *dll_major
= dummy
;
537 if ((buf
= (char *) memchr (buf
, '%', bufend
- buf
)) == NULL
)
539 else if (strncmp ("%%% Cygwin ", buf
, CYGPREFIX
) != 0)
543 char *p
= strchr (buf
+= CYGPREFIX
, '\n');
546 if (strncasecmp (buf
, "dll major:", 10) == 0)
548 dll_major
= buf
+ 11;
554 if (strncasecmp (buf
, "dll minor:", 10) != 0)
558 char c
= dll_major
[1];
560 int maj
= atoi (dll_major
);
562 int min
= atoi (dll_major
+ 1);
563 sprintf (pbuf
, "DLL version: %d.%d.%.*s", maj
, min
, len
- 11,
565 len
= strlen (s
= pbuf
);
567 if (strncmp (s
, "dll", 3) == 0)
568 memcpy (s
, "DLL", 3);
569 else if (strncmp (s
, "api", 3) == 0)
570 memcpy (s
, "API", 3);
571 else if (islower (*s
))
573 fprintf (stdout
, "%s %.*s", hello
, len
, s
);
585 dll_info (const char *path
, HANDLE fh
, int lvl
, int recurse
)
595 char buf
[PATH_MAX
+ 1] = "";
596 readlink (fh
, buf
, sizeof(buf
) - 1);
597 printf (" (symlink to %s)\n", buf
);
601 int pe_header_offset
= get_dword (fh
, 0x3c);
602 if (GetLastError () != NO_ERROR
)
603 display_error ("get_dword");
604 WORD arch
= get_word (fh
, pe_header_offset
+ 4);
605 if (GetLastError () != NO_ERROR
)
606 display_error ("get_word");
608 if (arch
!= IMAGE_FILE_MACHINE_AMD64
)
610 puts (verbose
? " (not x86_64 dll)" : "\n");
615 if (arch
!= IMAGE_FILE_MACHINE_I386
)
617 puts (verbose
? " (not x86 dll)" : "\n");
622 int opthdr_ofs
= pe_header_offset
+ 4 + 20;
627 display_error ("dll_info: NULL passed for path", true, false);
631 if (SetFilePointer (fh
, opthdr_ofs
+ 40, 0, FILE_BEGIN
) ==
632 INVALID_SET_FILE_POINTER
&& GetLastError () != NO_ERROR
)
633 display_error ("dll_info: SetFilePointer()");
635 if (!ReadFile (fh
, &v
, sizeof (v
), &junk
, 0))
636 display_error ("dll_info: Readfile()");
639 printf (" - os=%d.%d img=%d.%d sys=%d.%d\n",
640 v
[0], v
[1], v
[2], v
[3], v
[4], v
[5]);
644 int num_entries
= get_dword (fh
, opthdr_ofs
+ base_off
+ 0);
645 if (GetLastError () != NO_ERROR
)
646 display_error ("get_dword");
647 int export_rva
= get_dword (fh
, opthdr_ofs
+ base_off
+ 4);
648 if (GetLastError () != NO_ERROR
)
649 display_error ("get_dword");
650 int export_size
= get_dword (fh
, opthdr_ofs
+ base_off
+ 8);
651 if (GetLastError () != NO_ERROR
)
652 display_error ("get_dword");
653 int import_rva
= get_dword (fh
, opthdr_ofs
+ base_off
+ 12);
654 if (GetLastError () != NO_ERROR
)
655 display_error ("get_dword");
656 int import_size
= get_dword (fh
, opthdr_ofs
+ base_off
+ 16);
657 if (GetLastError () != NO_ERROR
)
658 display_error ("get_dword");
660 int nsections
= get_word (fh
, pe_header_offset
+ 4 + 2);
662 display_error ("get_word");
663 char *sections
= (char *) malloc (nsections
* 40);
665 if (SetFilePointer (fh
, pe_header_offset
+ 4 + 20 +
666 get_word (fh
, pe_header_offset
+ 4 + 16), 0,
667 FILE_BEGIN
) == INVALID_SET_FILE_POINTER
668 && GetLastError () != NO_ERROR
)
669 display_error ("dll_info: SetFilePointer()");
671 if (!ReadFile (fh
, sections
, nsections
* 40, &junk
, 0))
672 display_error ("dll_info: Readfile()");
674 if (verbose
&& num_entries
>= 1 && export_size
> 0)
677 int expbase
= rva_to_offset (export_rva
, sections
, nsections
, &expsz
);
681 if (SetFilePointer (fh
, expbase
, 0, FILE_BEGIN
) ==
682 INVALID_SET_FILE_POINTER
&& GetLastError () != NO_ERROR
)
683 display_error ("dll_info: SetFilePointer()");
685 unsigned char *exp
= (unsigned char *) malloc (expsz
);
687 if (!ReadFile (fh
, exp
, expsz
, &junk
, 0))
688 display_error ("dll_info: Readfile()");
690 ExpDirectory
*ed
= (ExpDirectory
*) exp
;
691 int ofs
= ed
->name_rva
- export_rva
;
692 time_t ts
= ed
->timestamp
; /* timestamp is only 4 bytes! */
693 struct tm
*tm
= localtime (&ts
);
694 if (tm
&& tm
->tm_year
< 60)
696 if (tm
&& tm
->tm_year
< 200)
698 printf ("%*c", lvl
+ 2, ' ');
699 printf ("\"%s\" v%d.%d", exp
+ ofs
,
700 ed
->major_ver
, ed
->minor_ver
);
702 printf (" ts=%04d-%02d-%02d %02d:%02d",
703 tm
->tm_year
, tm
->tm_mon
+ 1, tm
->tm_mday
,
704 tm
->tm_hour
, tm
->tm_min
);
709 if (num_entries
>= 2 && import_size
> 0 && recurse
)
712 int impbase
= rva_to_offset (import_rva
, sections
, nsections
, &impsz
);
715 if (SetFilePointer (fh
, impbase
, 0, FILE_BEGIN
) ==
716 INVALID_SET_FILE_POINTER
&& GetLastError () != NO_ERROR
)
717 display_error ("dll_info: SetFilePointer()");
719 unsigned char *imp
= (unsigned char *) malloc (impsz
);
722 display_error ("dll_info: malloc()");
726 if (!ReadFile (fh
, imp
, impsz
, &junk
, 0))
727 display_error ("dll_info: Readfile()");
729 ImpDirectory
*id
= (ImpDirectory
*) imp
;
730 for (i
= 0; id
[i
].name_rva
; i
++)
732 /* int ofs = id[i].name_rva - import_rva; */
733 track_down ((char *) imp
+ id
[i
].name_rva
- import_rva
,
734 (char *) ".dll", lvl
+ 2);
738 if (strstr (path
, "\\cygwin1.dll"))
742 // Return true on success, false if error printed
744 track_down (const char *file
, const char *suffix
, int lvl
)
748 display_error ("track_down: NULL passed for file", true, false);
754 display_error ("track_down: NULL passed for suffix", false, false);
758 const char *path
= find_on_path (file
, suffix
, false, true);
761 /* The api-ms-win-*.dll files are in system32/downlevel and not in the
762 DLL search path, so find_on_path doesn't find them. Since they are
763 never actually linked against by the executables, they are of no
764 interest to us. Skip any error message in not finding them. */
765 if (strncasecmp (file
, "api-ms-win-", 11) || strcasecmp (suffix
, ".dll"))
766 display_error ("track_down: could not find %s\n", file
);
770 Did
*d
= already_did (file
);
779 printf ("%*c", lvl
, ' ');
781 printf (" (recursive)\n");
788 printf ("%*c", lvl
, ' ');
790 printf (" (already done)\n");
798 printf ("%*c", lvl
, ' ');
802 wide_path
wpath (path
);
804 CreateFileW (wpath
, GENERIC_READ
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
805 NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
806 if (fh
== INVALID_HANDLE_VALUE
)
808 display_error ("cannot open - '%s'\n", path
);
812 d
->state
= DID_ACTIVE
;
815 dll_info (path
, fh
, lvl
, 1);
816 else if (is_symlink (fh
))
817 display_error ("%s is a symlink instead of a DLL\n", path
);
820 int magic
= get_word (fh
, 0x0);
822 display_error ("get_word");
824 display_error_fmt ("%s is not a DLL: magic number %x (%d) '%s'\n",
825 path
, magic
, magic
, (char *)&magic
);
828 d
->state
= DID_INACTIVE
;
829 if (!CloseHandle (fh
))
830 display_error ("track_down: CloseHandle()");
838 HANDLE h
= CreateFileW (wpath
, GENERIC_READ
,
839 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
840 0, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, 0);
841 BY_HANDLE_FILE_INFORMATION info
;
843 if (!GetFileInformationByHandle (h
, &info
))
844 display_error ("ls: GetFileInformationByHandle()");
848 if (!FileTimeToSystemTime (&info
.ftLastWriteTime
, &systime
))
849 display_error ("ls: FileTimeToSystemTime()");
850 printf ("%5dk %04d/%02d/%02d %s",
851 (((int) info
.nFileSizeLow
) + 512) / 1024,
852 systime
.wYear
, systime
.wMonth
, systime
.wDay
, f
);
853 dll_info (f
, h
, 16, 0);
854 if (!CloseHandle (h
))
855 display_error ("ls: CloseHandle()");
858 /* Remove filename from 's' and return directory name without trailing
859 backslash, or NULL if 's' doesn't seem to have a dirname. */
861 dirname (const char *s
)
863 static char buf
[PATH_MAX
];
868 strncpy (buf
, s
, PATH_MAX
);
869 buf
[PATH_MAX
- 1] = '\0'; // in case strlen(s) > PATH_MAX
870 char *lastsep
= strrchr (buf
, '\\');
872 return NULL
; // no backslash -> no dirname
873 else if (lastsep
- buf
<= 2 && buf
[1] == ':')
874 lastsep
[1] = '\0'; // can't remove backslash of "x:\"
880 // Find a real application on the path (possibly following symlinks)
882 find_app_on_path (const char *app
, bool showall
= false)
884 const char *papp
= find_on_path (app
, ".exe", showall
, false, true);
889 wide_path
wpath (papp
);
891 CreateFileW (wpath
, GENERIC_READ
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
892 NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
893 if (fh
== INVALID_HANDLE_VALUE
)
898 static char tmp
[SYMLINK_MAX
+ 1];
899 if (!readlink (fh
, tmp
, SYMLINK_MAX
))
900 display_error("readlink failed");
902 /* Resolve the linkname relative to the directory of the link. */
903 char *ptr
= cygpath_rel (dirname (papp
), tmp
, NULL
);
904 printf (" -> %s\n", ptr
);
905 if (!strchr (ptr
, '\\'))
908 strncpy (tmp
, cygpath (papp
, NULL
), SYMLINK_MAX
);
909 lastsep
= strrchr (tmp
, '\\');
910 strncpy (lastsep
+1, ptr
, SYMLINK_MAX
- (lastsep
-tmp
));
913 if (!CloseHandle (fh
))
914 display_error ("find_app_on_path: CloseHandle()");
915 /* FIXME: We leak the ptr returned by cygpath() here which is a
917 return find_app_on_path (ptr
, showall
);
920 if (!CloseHandle (fh
))
921 display_error ("find_app_on_path: CloseHandle()");
925 // Return true on success, false if error printed
927 cygcheck (const char *app
)
929 const char *papp
= find_app_on_path (app
, 1);
932 display_error ("could not find '%s'\n", app
);
937 char *sep
= strpbrk (papp
, ":/\\");
940 static char dot
[] = ".";
946 s
= (char *) malloc (n
+ 2);
947 memcpy ((char *) s
, papp
, n
);
948 strcpy (s
+ n
, "\\");
953 return track_down (papp
, ".exe", 0);
964 show_reg (RegInfo
* ri
, int nest
)
968 show_reg (ri
->prev
, 1);
970 printf ("%s\\", ri
->name
);
972 printf ("%s\n", ri
->name
);
976 scan_registry (RegInfo
* prev
, HKEY hKey
, char *name
, int cygwin
, bool wow64
)
984 for (cp
= name
; *cp
; cp
++)
985 if (strncasecmp (cp
, "Cygwin", 6) == 0)
988 DWORD num_subkeys
, max_subkey_len
, num_values
;
989 DWORD max_value_len
, max_valdata_len
, i
;
990 if (RegQueryInfoKey (hKey
, 0, 0, 0, &num_subkeys
, &max_subkey_len
, 0,
991 &num_values
, &max_value_len
, &max_valdata_len
, 0, 0)
996 FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM
, 0, GetLastError (),
997 MAKELANGID (LANG_NEUTRAL
, SUBLANG_DEFAULT
), tmp
, 400, 0);
998 printf ("RegQueryInfoKey: %s\n", tmp
);
1007 char *value_name
= (char *) malloc (max_value_len
+ 1);
1008 if (value_name
== NULL
)
1010 display_error ("scan_registry: malloc()");
1014 char *value_data
= (char *) malloc (max_valdata_len
+ 1);
1015 if (value_data
== NULL
)
1017 display_error ("scan_registry: malloc()");
1021 for (i
= 0; i
< num_values
; i
++)
1023 DWORD dlen
= max_valdata_len
+ 1;
1024 DWORD nlen
= max_value_len
+ 1;
1026 RegEnumValue (hKey
, i
, value_name
, &nlen
, 0,
1027 &type
, (BYTE
*) value_data
, &dlen
);
1029 printf (" %s = ", i
? value_name
: "(default)");
1033 printf ("0x%08x\n", *(unsigned *) value_data
);
1037 printf ("'%s'\n", value_data
);
1040 printf ("(unsupported type)\n");
1049 char *subkey_name
= (char *) malloc (max_subkey_len
+ 1);
1050 for (i
= 0; i
< num_subkeys
; i
++)
1052 if (RegEnumKey (hKey
, i
, subkey_name
, max_subkey_len
+ 1) ==
1056 /* Don't recurse more than one level into the WOW64 subkey since
1057 that would lead to an endless recursion. */
1058 if (!strcasecmp (subkey_name
, "Wow6432Node"))
1064 if (RegOpenKeyEx (hKey
, subkey_name
, 0, KEY_READ
, &sKey
)
1067 scan_registry (&ri
, sKey
, subkey_name
, cygwin
, wow64
);
1068 if (RegCloseKey (sKey
) != ERROR_SUCCESS
)
1069 display_error ("scan_registry: RegCloseKey()");
1079 char *groups
[16384];
1081 char *id
= cygpath ("/bin/id.exe", NULL
);
1082 for (char *p
= id
; (p
= strchr (p
, '/')); p
++)
1085 if (access (id
, X_OK
))
1087 fprintf (stderr
, "'id' program not found\n");
1092 snprintf (buf
, sizeof (buf
), "\"%s\"", id
);
1093 FILE *f
= popen (buf
, "rt");
1096 fgets (buf
, sizeof (buf
), f
);
1098 char *uid
= strtok (buf
, ")");
1100 uid
+= strlen ("uid=");
1103 fprintf (stderr
, "garbled output from 'id' command - no uid= found\n");
1106 char *gid
= strtok (NULL
, ")");
1108 gid
+= strlen ("gid=") + 1;
1111 fprintf (stderr
, "garbled output from 'id' command - no gid= found\n");
1115 char **ng
= groups
- 1;
1116 size_t len_uid
= strlen ("UID: )") + strlen (uid
);
1117 size_t len_gid
= strlen ("GID: )") + strlen (gid
);
1118 *++ng
= groups
[0] = (char *) alloca (len_uid
+ 1);
1119 *++ng
= groups
[1] = (char *) alloca (len_gid
+ 1);
1120 sprintf (groups
[0], "UID: %s)", uid
);
1121 sprintf (groups
[1], "GID: %s)", gid
);
1122 size_t sz
= max (len_uid
, len_gid
);
1123 while ((*++ng
= strtok (NULL
, ",")))
1125 char *p
= strchr (*ng
, '\n');
1128 if (ng
== groups
+ 2)
1129 *ng
+= strlen (" groups=");
1130 size_t len
= strlen (*ng
);
1136 printf ("\nOutput from %s\n", id
);
1137 int n
= 80 / (int) ++sz
;
1138 int i
= n
> 2 ? n
- 2 : 0;
1140 for (char **g
= groups
; g
<= ng
; g
++)
1141 if ((g
!= ng
) && (++i
< n
))
1142 printf ("%*s", (int) sz
, *g
);
1150 /* This dumps information about each installed cygwin service, if cygrunsrv
1153 dump_sysinfo_services ()
1158 bool no_services
= false;
1161 printf ("\nChecking for any Cygwin services... %s\n\n",
1162 verbose
? "" : "(use -v for more detail)");
1164 fputc ('\n', stdout
);
1166 /* find the location of cygrunsrv.exe */
1167 char *cygrunsrv
= cygpath ("/bin/cygrunsrv.exe", NULL
);
1168 for (char *p
= cygrunsrv
; (p
= strchr (p
, '/')); p
++)
1171 if (access (cygrunsrv
, X_OK
))
1173 puts ("Can't find the cygrunsrv utility, skipping services check.\n");
1177 /* check for a recent cygrunsrv */
1178 snprintf (buf
, sizeof (buf
), "\"%s\" --version", cygrunsrv
);
1179 if ((f
= popen (buf
, "rt")) == NULL
)
1181 printf ("Failed to execute '%s', skipping services check.\n", buf
);
1185 int ret
= fscanf (f
, "cygrunsrv V%u.%u", &maj
, &min
);
1186 if (ferror (f
) || feof (f
) || ret
== EOF
|| maj
< 1 || min
< 10)
1188 puts ("The version of cygrunsrv installed is too old to dump "
1194 /* For verbose mode, just run cygrunsrv --list --verbose and copy output
1195 verbatim; otherwise run cygrunsrv --list and then cygrunsrv --query for
1197 snprintf (buf
, sizeof (buf
),
1198 (verbose
? "\"%s\" --list --verbose" : "\"%s\" --list"),
1200 if ((f
= popen (buf
, "rt")) == NULL
)
1202 printf ("Failed to execute '%s', skipping services check.\n", buf
);
1208 /* copy output to stdout */
1210 while (!feof (f
) && !ferror (f
))
1211 nchars
+= fwrite ((void *) buf
, 1,
1212 fread ((void *) buf
, 1, sizeof (buf
), f
), stdout
);
1214 /* cygrunsrv outputs nothing if there are no cygwin services found */
1221 /* read the output of --list, and then run --query for each service */
1222 size_t nchars
= fread ((void *) buf
, 1, sizeof (buf
) - 1, f
);
1227 for (char *srv
= strtok (buf
, "\n"); srv
; srv
= strtok (NULL
, "\n"))
1229 snprintf (buf2
, sizeof (buf2
), "\"%s\" --query %s", cygrunsrv
, srv
);
1230 if ((f
= popen (buf2
, "rt")) == NULL
)
1232 printf ("Failed to execute '%s', skipping services check.\n",
1237 /* copy output to stdout */
1238 while (!feof (f
) && !ferror (f
))
1239 fwrite ((void *) buf2
, 1,
1240 fread ((void *) buf2
, 1, sizeof (buf2
), f
), stdout
);
1247 /* inform the user if nothing found */
1249 puts ("No Cygwin services found.\n");
1259 handle_reg_installation (handle_reg_t what
)
1263 if (what
== PRINT_KEY
)
1264 printf ("Cygwin installations found in the registry:\n");
1265 for (int i
= 0; i
< 2; ++i
)
1266 if (RegOpenKeyEx (i
? HKEY_CURRENT_USER
: HKEY_LOCAL_MACHINE
,
1267 "SOFTWARE\\Cygwin\\Installations", 0,
1268 what
== DELETE_KEY
? KEY_READ
| KEY_WRITE
: KEY_READ
,
1272 char name
[32], data
[PATH_MAX
];
1273 DWORD nsize
, dsize
, type
;
1276 for (DWORD index
= 0;
1277 (ret
= RegEnumValue (key
, index
, name
, (nsize
= 32, &nsize
), 0,
1278 &type
, (PBYTE
) data
,
1279 (dsize
= PATH_MAX
, &dsize
)))
1280 != ERROR_NO_MORE_ITEMS
; ++index
)
1281 if (ret
== ERROR_SUCCESS
&& dsize
> 5)
1283 char *path
= data
+ 4;
1285 *(path
+= 2) = '\\';
1286 if (what
== PRINT_KEY
)
1287 printf (" %s Key: %s Path: %s", i
? "User: " : "System:",
1289 strcat (path
, "\\bin\\cygwin1.dll");
1290 if (what
== PRINT_KEY
)
1291 printf ("%s\n", access (path
, F_OK
) ? " (ORPHANED)" : "");
1292 else if (access (path
, F_OK
))
1294 RegDeleteValue (key
, name
);
1295 /* Start over since index is not reliable anymore. */
1302 if (what
== PRINT_KEY
)
1307 print_reg_installations ()
1309 handle_reg_installation (PRINT_KEY
);
1313 del_orphaned_reg_installations ()
1315 handle_reg_installation (DELETE_KEY
);
1318 /* Unfortunately neither mingw nor Windows know this function. */
1320 memmem (char *haystack
, size_t haystacklen
,
1321 const char *needle
, size_t needlelen
)
1325 while (needlelen
<= haystacklen
)
1327 if (!memcmp (haystack
, needle
, needlelen
))
1335 extern "C" NTSTATUS NTAPI
RtlGetVersion (PRTL_OSVERSIONINFOEXW
);
1343 char *found_cygwin_dll
;
1346 DWORD obcaseinsensitive
= 1;
1349 /* MSVCRT popen (called by pretty_id and dump_sysinfo_services) SEGVs if
1350 COMSPEC isn't set correctly. Simply enforce it here. Using
1351 Get/SetEnvironmentVariable to set the dir does *not* help, btw.
1352 Apparently MSVCRT keeps its own copy of the environment and changing
1353 that requires to use _wputenv. */
1354 if (!_wgetenv (L
"COMSPEC"))
1356 WCHAR comspec
[MAX_PATH
+ 17];
1357 wcscpy (comspec
, L
"COMSPEC=");
1358 GetSystemDirectoryW (comspec
+ 8, MAX_PATH
);
1359 wcsncat (comspec
, L
"\\cmd.exe", sizeof comspec
);
1363 printf ("\nCygwin Configuration Diagnostics\n");
1365 printf ("Current System Time: %s\n", ctime (&now
));
1367 RTL_OSVERSIONINFOEXW osversion
;
1368 osversion
.dwOSVersionInfoSize
= sizeof (RTL_OSVERSIONINFOEXW
);
1369 RtlGetVersion (&osversion
);
1371 switch (osversion
.dwPlatformId
)
1373 case VER_PLATFORM_WIN32_NT
:
1375 if (osversion
.dwMajorVersion
>= 6)
1377 HMODULE k32
= GetModuleHandleW (L
"kernel32.dll");
1378 BOOL (WINAPI
*GetProductInfo
) (DWORD
, DWORD
, DWORD
, DWORD
, PDWORD
) =
1379 (BOOL (WINAPI
*)(DWORD
, DWORD
, DWORD
, DWORD
, PDWORD
))
1380 GetProcAddress (k32
, "GetProductInfo");
1381 if (osversion
.dwMajorVersion
== 6)
1382 switch (osversion
.dwMinorVersion
)
1385 strcpy (osname
, osversion
.wProductType
== VER_NT_WORKSTATION
1386 ? "Vista" : "2008");
1389 strcpy (osname
, osversion
.wProductType
== VER_NT_WORKSTATION
1393 strcpy (osname
, osversion
.wProductType
== VER_NT_WORKSTATION
1397 strcpy (osname
, osversion
.wProductType
== VER_NT_WORKSTATION
1398 ? "8.1" : "2012 R2");
1402 strcpy (osname
, osversion
.wProductType
== VER_NT_WORKSTATION
1403 ? "10 Preview" : "2016 Preview");
1406 else if (osversion
.dwMajorVersion
== 10)
1408 strcpy (osname
, osversion
.wProductType
== VER_NT_WORKSTATION
1412 if (GetProductInfo (osversion
.dwMajorVersion
,
1413 osversion
.dwMinorVersion
,
1414 osversion
.wServicePackMajor
,
1415 osversion
.wServicePackMinor
,
1418 const char *products
[] =
1420 /* 0x00000000 */ "",
1421 /* 0x00000001 */ " Ultimate",
1422 /* 0x00000002 */ " Home Basic",
1423 /* 0x00000003 */ " Home Premium",
1424 /* 0x00000004 */ " Enterprise",
1425 /* 0x00000005 */ " Home Basic N",
1426 /* 0x00000006 */ " Business",
1427 /* 0x00000007 */ " Server Standard",
1428 /* 0x00000008 */ " Server Datacenter",
1429 /* 0x00000009 */ " Small Business Server",
1430 /* 0x0000000a */ " Server Enterprise",
1431 /* 0x0000000b */ " Starter",
1432 /* 0x0000000c */ " Server Datacenter Core",
1433 /* 0x0000000d */ " Server Standard Core",
1434 /* 0x0000000e */ " Server Enterprise Core",
1435 /* 0x0000000f */ " Server Enterprise for Itanium-based Systems",
1436 /* 0x00000010 */ " Business N",
1437 /* 0x00000011 */ " Web Server",
1438 /* 0x00000012 */ " HPC Edition",
1439 /* 0x00000013 */ " Home Server",
1440 /* 0x00000014 */ " Storage Server Express",
1441 /* 0x00000015 */ " Storage Server Standard",
1442 /* 0x00000016 */ " Storage Server Workgroup",
1443 /* 0x00000017 */ " Storage Server Enterprise",
1444 /* 0x00000018 */ " for Windows Essential Server Solutions",
1445 /* 0x00000019 */ " Small Business Server Premium",
1446 /* 0x0000001a */ " Home Premium N",
1447 /* 0x0000001b */ " Enterprise N",
1448 /* 0x0000001c */ " Ultimate N",
1449 /* 0x0000001d */ " Web Server Core",
1450 /* 0x0000001e */ " Essential Business Server Management Server",
1451 /* 0x0000001f */ " Essential Business Server Security Server",
1452 /* 0x00000020 */ " Essential Business Server Messaging Server",
1453 /* 0x00000021 */ " Server Foundation",
1454 /* 0x00000022 */ " Home Server 2011",
1455 /* 0x00000023 */ " without Hyper-V for Windows Essential Server Solutions",
1456 /* 0x00000024 */ " Server Standard without Hyper-V",
1457 /* 0x00000025 */ " Server Datacenter without Hyper-V",
1458 /* 0x00000026 */ " Server Enterprise without Hyper-V",
1459 /* 0x00000027 */ " Server Datacenter Core without Hyper-V",
1460 /* 0x00000028 */ " Server Standard Core without Hyper-V",
1461 /* 0x00000029 */ " Server Enterprise Core without Hyper-V",
1462 /* 0x0000002a */ " Hyper-V Server",
1463 /* 0x0000002b */ " Storage Server Express Core",
1464 /* 0x0000002c */ " Storage Server Standard Core",
1465 /* 0x0000002d */ " Storage Server Workgroup Core",
1466 /* 0x0000002e */ " Storage Server Enterprise Core",
1467 /* 0x0000002f */ " Starter N",
1468 /* 0x00000030 */ " Professional",
1469 /* 0x00000031 */ " Professional N",
1470 /* 0x00000032 */ " Small Business Server 2011 Essentials",
1471 /* 0x00000033 */ " Server For SB Solutions",
1472 /* 0x00000034 */ " Server Solutions Premium",
1473 /* 0x00000035 */ " Server Solutions Premium Core",
1474 /* 0x00000036 */ " Server For SB Solutions EM", /* per MSDN, 2012-09-01 */
1475 /* 0x00000037 */ " Server For SB Solutions EM", /* per MSDN, 2012-09-01 */
1476 /* 0x00000038 */ " Multipoint Server",
1477 /* 0x00000039 */ "",
1478 /* 0x0000003a */ "",
1479 /* 0x0000003b */ " Essential Server Solution Management",
1480 /* 0x0000003c */ " Essential Server Solution Additional",
1481 /* 0x0000003d */ " Essential Server Solution Management SVC",
1482 /* 0x0000003e */ " Essential Server Solution Additional SVC",
1483 /* 0x0000003f */ " Small Business Server Premium Core",
1484 /* 0x00000040 */ " Server Hyper Core V",
1485 /* 0x00000041 */ "",
1486 /* 0x00000042 */ " Starter E",
1487 /* 0x00000043 */ " Home Basic E",
1488 /* 0x00000044 */ " Home Premium E",
1489 /* 0x00000045 */ " Professional E",
1490 /* 0x00000046 */ " Enterprise E",
1491 /* 0x00000047 */ " Ultimate E",
1492 /* 0x00000048 */ " Server Enterprise (Evaluation inst.)",
1493 /* 0x00000049 */ "",
1494 /* 0x0000004a */ "",
1495 /* 0x0000004b */ "",
1496 /* 0x0000004c */ " MultiPoint Server Standard",
1497 /* 0x0000004d */ " MultiPoint Server Premium",
1498 /* 0x0000004e */ "",
1499 /* 0x0000004f */ " Server Standard (Evaluation inst.)",
1500 /* 0x00000050 */ " Server Datacenter (Evaluation inst.)",
1501 /* 0x00000051 */ "",
1502 /* 0x00000052 */ "",
1503 /* 0x00000053 */ "",
1504 /* 0x00000054 */ " Enterprise N (Evaluation inst.)",
1505 /* 0x00000055 */ "",
1506 /* 0x00000056 */ "",
1507 /* 0x00000057 */ "",
1508 /* 0x00000058 */ "",
1509 /* 0x00000059 */ "",
1510 /* 0x0000005a */ "",
1511 /* 0x0000005b */ "",
1512 /* 0x0000005c */ "",
1513 /* 0x0000005d */ "",
1514 /* 0x0000005e */ "",
1515 /* 0x0000005f */ " Storage Server Workgroup (Evaluation inst.)",
1516 /* 0x00000060 */ " Storage Server Standard (Evaluation inst.)",
1517 /* 0x00000061 */ "",
1518 /* 0x00000062 */ " N",
1519 /* 0x00000063 */ " China",
1520 /* 0x00000064 */ " Single Language",
1521 /* 0x00000065 */ " Home",
1522 /* 0x00000066 */ "",
1523 /* 0x00000067 */ " Professional with Media Center",
1524 /* 0x00000068 */ " Mobile",
1525 /* 0x00000069 */ "",
1526 /* 0x0000006a */ "",
1527 /* 0x0000006b */ "",
1528 /* 0x0000006c */ "",
1529 /* 0x0000006d */ "",
1530 /* 0x0000006e */ "",
1531 /* 0x0000006f */ "",
1532 /* 0x00000070 */ "",
1533 /* 0x00000071 */ "",
1534 /* 0x00000072 */ "",
1535 /* 0x00000073 */ "",
1536 /* 0x00000074 */ "",
1537 /* 0x00000075 */ "",
1538 /* 0x00000076 */ "",
1539 /* 0x00000077 */ "",
1540 /* 0x00000078 */ "",
1541 /* 0x00000079 */ " Education",
1542 /* 0x0000007a */ " Education N",
1543 /* 0x0000007b */ "",
1544 /* 0x0000007c */ "",
1545 /* 0x0000007d */ "",
1546 /* 0x0000007e */ "",
1547 /* 0x0000007f */ "",
1548 /* 0x00000080 */ "",
1549 /* 0x00000081 */ "",
1550 /* 0x00000082 */ "",
1551 /* 0x00000083 */ "",
1552 /* 0x00000084 */ "",
1553 /* 0x00000085 */ " Mobile Enterprise",
1555 if (prod
== PRODUCT_UNLICENSED
)
1556 strcat (osname
, "Unlicensed");
1557 else if (prod
> 0x00000085)
1558 strcat (osname
, "");
1560 strcat (osname
, products
[prod
]);
1567 strcpy (osname
, "NT");
1570 strcpy (osname
, "??");
1573 printf ("Windows %s Ver %lu.%lu Build %lu %ls\n", osname
,
1574 osversion
.dwMajorVersion
, osversion
.dwMinorVersion
,
1575 osversion
.dwPlatformId
== VER_PLATFORM_WIN32_NT
?
1576 osversion
.dwBuildNumber
: (osversion
.dwBuildNumber
& 0xffff),
1577 osversion
.dwPlatformId
== VER_PLATFORM_WIN32_NT
?
1578 osversion
.szCSDVersion
: L
"");
1580 if (osversion
.dwPlatformId
== VER_PLATFORM_WIN32s
1581 || osversion
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
)
1582 exit (EXIT_FAILURE
);
1584 BOOL is_wow64
= FALSE
;
1585 if (IsWow64Process (GetCurrentProcess (), &is_wow64
) && is_wow64
)
1587 SYSTEM_INFO natinfo
;
1588 GetNativeSystemInfo (&natinfo
);
1589 fputs ("\nRunning under WOW64 on ", stdout
);
1590 switch (natinfo
.wProcessorArchitecture
)
1592 case PROCESSOR_ARCHITECTURE_IA64
:
1595 case PROCESSOR_ARCHITECTURE_AMD64
:
1604 if (GetSystemMetrics (SM_REMOTESESSION
))
1605 printf ("\nRunning in Terminal Service session\n");
1608 char *s
= getenv ("PATH"), *e
;
1613 char sep
= strchr (s
, ';') ? ';' : ':';
1614 int count_path_items
= 0;
1617 for (e
= s
; *e
&& *e
!= sep
; e
++);
1619 printf ("\t%.*s\n", (int) (e
- s
), s
);
1633 if (!GetSystemDirectory (tmp
, 4000))
1634 display_error ("dump_sysinfo: GetSystemDirectory()");
1635 printf ("\nSysDir: %s\n", tmp
);
1637 GetWindowsDirectory (tmp
, 4000);
1638 printf ("WinDir: %s\n\n", tmp
);
1642 printf ("Here's some environment variables that may affect cygwin:\n");
1643 for (i
= 0; environ
[i
]; i
++)
1645 char *eq
= strchr (environ
[i
], '=');
1648 /* int len = eq - environ[i]; */
1649 for (j
= 0; known_env_vars
[j
]; j
++)
1652 if (strcmp (environ
[i
], "PATH") == 0)
1653 continue; /* we handle this one specially */
1654 if (strcasecmp (environ
[i
], known_env_vars
[j
]) == 0)
1655 printf ("%s = '%s'\n", environ
[i
], eq
+ 1);
1664 printf ("Here's the rest of your environment variables:\n");
1665 for (i
= 0; environ
[i
]; i
++)
1668 char *eq
= strchr (environ
[i
], '=');
1671 /* int len = eq - environ[i]; */
1672 for (j
= 0; known_env_vars
[j
]; j
++)
1675 if (strcasecmp (environ
[i
], known_env_vars
[j
]) == 0)
1682 printf ("%s = '%s'\n", environ
[i
], eq
+ 1);
1692 printf ("Scanning registry for keys with 'Cygwin' in them...\n");
1693 scan_registry (0, HKEY_CURRENT_USER
,
1694 (char *) "HKEY_CURRENT_USER", 0, false);
1695 scan_registry (0, HKEY_LOCAL_MACHINE
,
1696 (char *) "HKEY_LOCAL_MACHINE", 0, false);
1700 printf ("Use '-r' to scan registry\n\n");
1702 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE
,
1703 "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\kernel",
1704 0, KEY_READ
, &key
) == ERROR_SUCCESS
)
1707 RegQueryValueEx (key
, "obcaseinsensitive", NULL
, NULL
,
1708 (LPBYTE
) &obcaseinsensitive
, &size
);
1711 printf ("obcaseinsensitive set to %lu\n\n", obcaseinsensitive
);
1713 print_reg_installations ();
1717 printf ("Listing available drives...\n");
1718 printf ("Drv Type Size Used Flags Name\n");
1721 SetErrorMode (SEM_FAILCRITICALERRORS
| SEM_NOOPENFILEERRORBOX
);
1722 int drivemask
= GetLogicalDrives ();
1724 for (i
= 0; i
< 26; i
++)
1726 if (!(drivemask
& (1 << i
)))
1728 char drive
[4], name
[200], fsname
[200];
1729 DWORD serno
= 0, maxnamelen
= 0, flags
= 0;
1730 name
[0] = fsname
[0] = 0;
1731 sprintf (drive
, "%c:\\", i
+ 'a');
1732 /* Report all errors, except if the Volume is ERROR_NOT_READY.
1733 ERROR_NOT_READY is returned when removeable media drives are empty
1734 (CD, floppy, etc.) */
1735 if (!GetVolumeInformation (drive
, name
, sizeof (name
), &serno
,
1736 &maxnamelen
, &flags
, fsname
,
1738 && GetLastError () != ERROR_NOT_READY
)
1740 # define FMT "dump_sysinfo: GetVolumeInformation() for drive %c:"
1741 char buf
[sizeof (FMT
)];
1742 sprintf (buf
, FMT
, 'A' + i
);
1743 display_error (buf
);
1747 int dtype
= GetDriveType (drive
);
1748 char drive_type
[4] = "unk";
1751 case DRIVE_REMOVABLE
:
1752 strcpy (drive_type
, "fd ");
1755 strcpy (drive_type
, "hd ");
1758 strcpy (drive_type
, "net");
1761 strcpy (drive_type
, "cd ");
1764 strcpy (drive_type
, "ram");
1767 strcpy (drive_type
, "unk");
1770 long capacity_mb
= -1;
1771 int percent_full
= -1;
1773 ULARGE_INTEGER free_me
, free_bytes
, total_bytes
;
1774 free_me
.QuadPart
= free_bytes
.QuadPart
= 0ULL;
1775 total_bytes
.QuadPart
= 1ULL;
1776 if (GetDiskFreeSpaceEx (drive
, &free_me
, &total_bytes
, &free_bytes
))
1778 capacity_mb
= total_bytes
.QuadPart
/ (1024L * 1024L);
1779 percent_full
= 100 - (int) ((100.0 * free_me
.QuadPart
)
1780 / total_bytes
.QuadPart
);
1784 DWORD spc
= 0, bps
= 0, fc
= 0, tc
= 1;
1785 if (GetDiskFreeSpace (drive
, &spc
, &bps
, &fc
, &tc
))
1787 capacity_mb
= (spc
* bps
* tc
) / (1024 * 1024);
1788 percent_full
= 100 - (int) ((100.0 * fc
) / tc
);
1792 printf ("%.2s %s %-6s ", drive
, drive_type
, fsname
);
1793 if (capacity_mb
>= 0)
1794 printf ("%7dMb %3d%% ", (int) capacity_mb
, (int) percent_full
);
1796 printf (" N/A N/A ");
1797 printf ("%s %s %s %s %s %s %s\n",
1798 flags
& FS_CASE_IS_PRESERVED
? "CP" : " ",
1799 flags
& FS_CASE_SENSITIVE
? "CS" : " ",
1800 flags
& FS_UNICODE_STORED_ON_DISK
? "UN" : " ",
1801 flags
& FS_PERSISTENT_ACLS
? "PA" : " ",
1802 flags
& FS_FILE_COMPRESSION
? "FC" : " ",
1803 flags
& FS_VOL_IS_COMPRESSED
? "VC" : " ",
1804 flags
& FILE_SUPPORTS_ENCRYPTION
? "EN" : " ",
1805 flags
& FILE_SUPPORTS_OBJECT_IDS
? "OI" : " ",
1806 flags
& FILE_SUPPORTS_REPARSE_POINTS
? "RP" : " ",
1807 flags
& FILE_SUPPORTS_SPARSE_FILES
? "SP" : " ",
1808 flags
& FILE_VOLUME_QUOTAS
? "QU" : " ",
1812 SetErrorMode (prev_mode
);
1816 "fd = floppy, hd = hard drive, cd = CD-ROM\n"
1817 "net= Network Share, ram= RAM drive, unk= Unknown\n"
1818 "CP = Case Preserving, CS = Case Sensitive, UN = Unicode\n"
1819 "PA = Persistent ACLS, FC = File Compression, VC = Volume Compression");
1823 unsigned ml_fsname
= 4, ml_dir
= 7, ml_type
= 6;
1824 bool ml_trailing
= false;
1828 while ((mnt
= getmntent (0)))
1830 unsigned n
= (int) strlen (mnt
->mnt_fsname
);
1831 ml_trailing
|= (n
> 1 && strchr ("\\/", mnt
->mnt_fsname
[n
- 1]));
1834 n
= (int) strlen (mnt
->mnt_dir
);
1835 ml_trailing
|= (n
> 1 && strchr ("\\/", mnt
->mnt_dir
[n
- 1]));
1841 puts ("Warning: Mount entries should not have a trailing (back)slash\n");
1846 ("Mount entries: these map POSIX directories to your NT drives.\n");
1847 printf ("%-*s %-*s %-*s %s\n", ml_fsname
, "-NT-", ml_dir
, "-POSIX-",
1848 ml_type
, "-Type-", "-Flags-");
1852 while ((mnt
= getmntent (0)))
1854 printf ("%-*s %-*s %-*s %s\n",
1855 ml_fsname
, mnt
->mnt_fsname
,
1856 ml_dir
, mnt
->mnt_dir
, ml_type
, mnt
->mnt_type
, mnt
->mnt_opts
);
1862 ("Looking to see where common programs can be found, if at all...\n");
1863 for (i
= 0; common_apps
[i
].name
; i
++)
1864 if (!find_app_on_path ((char *) common_apps
[i
].name
, 1))
1866 if (common_apps
[i
].missing_is_good
)
1867 printf ("Not Found: %s (good!)\n", common_apps
[i
].name
);
1869 printf ("Not Found: %s\n", common_apps
[i
].name
);
1874 printf ("Looking for various Cygwin DLLs... (-v gives version info)\n");
1875 int cygwin_dll_count
= 0;
1876 char cygdll_path
[32768];
1877 for (pathlike
*pth
= paths
; pth
->dir
; pth
++)
1879 WIN32_FIND_DATAW ffinfo
;
1880 sprintf (tmp
, "%s*.*", pth
->dir
);
1881 wide_path
wpath (tmp
);
1882 HANDLE ff
= FindFirstFileW (wpath
, &ffinfo
);
1883 int found
= (ff
!= INVALID_HANDLE_VALUE
);
1884 found_cygwin_dll
= NULL
;
1887 char f
[FILENAME_MAX
+ 1];
1888 wcstombs (f
, ffinfo
.cFileName
, sizeof f
);
1889 if (strcasecmp (f
+ strlen (f
) - 4, ".dll") == 0)
1891 if (strncasecmp (f
, "cyg", 3) == 0)
1893 sprintf (tmp
, "%s%s", pth
->dir
, f
);
1894 if (strcasecmp (f
, "cygwin1.dll") == 0)
1896 if (!cygwin_dll_count
)
1897 strcpy (cygdll_path
, pth
->dir
);
1898 if (!cygwin_dll_count
1899 || strcasecmp (cygdll_path
, pth
->dir
) != 0)
1901 found_cygwin_dll
= strdup (tmp
);
1907 found
= FindNextFileW (ff
, &ffinfo
);
1909 if (found_cygwin_dll
)
1911 ls (found_cygwin_dll
);
1912 free (found_cygwin_dll
);
1917 if (cygwin_dll_count
> 1)
1918 puts ("Warning: There are multiple cygwin1.dlls on your path");
1919 if (!cygwin_dll_count
)
1920 puts ("Warning: cygwin1.dll not found on your path");
1922 dump_dodgy_apps (verbose
);
1925 dump_sysinfo_services ();
1931 HANDLE h
= CreateFileW (L
"CONIN$", GENERIC_READ
| GENERIC_WRITE
,
1932 FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
,
1933 OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
1935 if (h
== INVALID_HANDLE_VALUE
|| h
== NULL
)
1936 return (display_error ("check_keys: Opening CONIN$"));
1940 if (!GetConsoleMode (h
, &mode
))
1941 display_error ("check_keys: GetConsoleMode()");
1944 mode
&= ~ENABLE_PROCESSED_INPUT
;
1945 if (!SetConsoleMode (h
, mode
))
1946 display_error ("check_keys: SetConsoleMode()");
1949 fputs ("\nThis key check works only in a console window,", stderr
);
1950 fputs (" _NOT_ in a terminal session!\n", stderr
);
1951 fputs ("Abort with Ctrl+C if in a terminal session.\n\n", stderr
);
1952 fputs ("Press 'q' to exit.\n", stderr
);
1954 INPUT_RECORD in
, prev_in
;
1956 // Drop first <RETURN> key
1957 ReadConsoleInputW (h
, &in
, 1, &mode
);
1959 memset (&in
, 0, sizeof in
);
1964 if (!ReadConsoleInputW (h
, &in
, 1, &mode
))
1965 display_error ("check_keys: ReadConsoleInput()");
1967 if (!memcmp (&in
, &prev_in
, sizeof in
))
1970 switch (in
.EventType
)
1973 printf ("%s %ux VK: 0x%04x VS: 0x%04x C: 0x%04x CTRL: ",
1974 in
.Event
.KeyEvent
.bKeyDown
? "Pressed " : "Released",
1975 in
.Event
.KeyEvent
.wRepeatCount
,
1976 in
.Event
.KeyEvent
.wVirtualKeyCode
,
1977 in
.Event
.KeyEvent
.wVirtualScanCode
,
1978 (unsigned char) in
.Event
.KeyEvent
.uChar
.UnicodeChar
);
1979 fputs (in
.Event
.KeyEvent
.dwControlKeyState
& CAPSLOCK_ON
?
1980 "CL " : "-- ", stdout
);
1981 fputs (in
.Event
.KeyEvent
.dwControlKeyState
& ENHANCED_KEY
?
1982 "EK " : "-- ", stdout
);
1983 fputs (in
.Event
.KeyEvent
.dwControlKeyState
& LEFT_ALT_PRESSED
?
1984 "LA " : "-- ", stdout
);
1985 fputs (in
.Event
.KeyEvent
.dwControlKeyState
& LEFT_CTRL_PRESSED
?
1986 "LC " : "-- ", stdout
);
1987 fputs (in
.Event
.KeyEvent
.dwControlKeyState
& NUMLOCK_ON
?
1988 "NL " : "-- ", stdout
);
1989 fputs (in
.Event
.KeyEvent
.dwControlKeyState
& RIGHT_ALT_PRESSED
?
1990 "RA " : "-- ", stdout
);
1991 fputs (in
.Event
.KeyEvent
.dwControlKeyState
& RIGHT_CTRL_PRESSED
?
1992 "RC " : "-- ", stdout
);
1993 fputs (in
.Event
.KeyEvent
.dwControlKeyState
& SCROLLLOCK_ON
?
1994 "SL " : "-- ", stdout
);
1995 fputs (in
.Event
.KeyEvent
.dwControlKeyState
& SHIFT_PRESSED
?
1996 "SH " : "-- ", stdout
);
1997 fputc ('\n', stdout
);
2004 while (in
.EventType
!= KEY_EVENT
||
2005 in
.Event
.KeyEvent
.bKeyDown
!= FALSE
||
2006 in
.Event
.KeyEvent
.uChar
.UnicodeChar
!= L
'q');
2012 /* RFC1738 says that these do not need to be escaped. */
2013 static const char safe_chars
[] = "$-_.+!*'(),";
2015 /* the URL to query. */
2016 static const char base_url
[] =
2017 "http://cygwin.com/cgi-bin2/package-grep.cgi?text=1&grep=";
2020 #define ARCH_STR "&arch=x86_64"
2022 #define ARCH_STR "&arch=x86"
2024 static const char *ARCH_str
= ARCH_STR
;
2026 /* Queries Cygwin web site for packages containing files matching a regexp.
2027 Return value is 1 if there was a problem, otherwise 0. */
2029 package_grep (char *search
)
2033 /* construct the actual URL by escaping */
2034 char *url
= (char *) alloca (sizeof (base_url
) + strlen (ARCH_str
)
2035 + strlen (search
) * 3);
2036 strcpy (url
, base_url
);
2039 for (dest
= &url
[sizeof (base_url
) - 1]; *search
; search
++)
2041 if (isalnum (*search
)
2042 || memchr (safe_chars
, *search
, sizeof (safe_chars
) - 1))
2049 sprintf (dest
, "%02x", (unsigned char) *search
);
2053 strcpy (dest
, ARCH_str
);
2055 /* Connect to the net and open the URL. */
2056 if (InternetAttemptConnect (0) != ERROR_SUCCESS
)
2058 fputs ("An internet connection is required for this function.\n", stderr
);
2062 /* Initialize WinInet and attempt to fetch our URL. */
2063 HINTERNET hi
= NULL
, hurl
= NULL
;
2064 if (!(hi
= InternetOpenA ("cygcheck", INTERNET_OPEN_TYPE_PRECONFIG
,
2066 return display_internet_error ("InternetOpen() failed", NULL
);
2068 if (!(hurl
= InternetOpenUrlA (hi
, url
, NULL
, 0, 0, 0)))
2069 return display_internet_error ("unable to contact cygwin.com site, "
2070 "InternetOpenUrl() failed", hi
, NULL
);
2072 /* Check the HTTP response code. */
2073 DWORD rc
= 0, rc_s
= sizeof (DWORD
);
2074 if (!HttpQueryInfoA (hurl
, HTTP_QUERY_STATUS_CODE
| HTTP_QUERY_FLAG_NUMBER
,
2075 (void *) &rc
, &rc_s
, NULL
))
2076 return display_internet_error ("HttpQueryInfo() failed", hurl
, hi
, NULL
);
2078 if (rc
!= HTTP_STATUS_OK
)
2080 sprintf (buf
, "error retrieving results from cygwin.com site, "
2081 "HTTP status code %lu", rc
);
2082 return display_internet_error (buf
, hurl
, hi
, NULL
);
2085 /* Fetch result and print to stdout. */
2089 if (!InternetReadFile (hurl
, (void *) buf
, sizeof (buf
), &numread
))
2090 return display_internet_error ("InternetReadFile failed", hurl
, hi
, NULL
);
2092 fwrite ((void *) buf
, (size_t) numread
, 1, stdout
);
2096 InternetCloseHandle (hurl
);
2097 InternetCloseHandle (hi
);
2102 usage (FILE * stream
, int status
)
2105 Usage: cygcheck [-v] [-h] PROGRAM\n\
2106 cygcheck -c [-d] [PACKAGE]\n\
2107 cygcheck -s [-r] [-v] [-h]\n\
2109 cygcheck -f FILE [FILE]...\n\
2110 cygcheck -l [PACKAGE]...\n\
2111 cygcheck -p REGEXP\n\
2112 cygcheck --delete-orphaned-installation-keys\n\
2114 List system information, check installed packages, or query package database.\n\
2116 At least one command option or a PROGRAM is required, as shown above.\n\
2118 PROGRAM list library (DLL) dependencies of PROGRAM\n\
2119 -c, --check-setup show installed version of PACKAGE and verify integrity\n\
2120 (or for all installed packages if none specified)\n\
2121 -d, --dump-only just list packages, do not verify (with -c)\n\
2122 -s, --sysinfo produce diagnostic system information (implies -c)\n\
2123 -r, --registry also scan registry for Cygwin settings (with -s)\n\
2124 -k, --keycheck perform a keyboard check session (must be run from a\n\
2125 plain console only, not from a pty/rxvt/xterm)\n\
2126 -f, --find-package find the package to which FILE belongs\n\
2127 -l, --list-package list contents of PACKAGE (or all packages if none given)\n\
2128 -p, --package-query search for REGEXP in the entire cygwin.com package\n\
2129 repository (requires internet connectivity)\n\
2130 --delete-orphaned-installation-keys\n\
2131 Delete installation keys of old, now unused\n\
2132 installations from the registry. Requires the right\n\
2133 to change the registry.\n\
2134 -v, --verbose produce more verbose output\n\
2135 -h, --help annotate output with explanatory comments when given\n\
2136 with another command, otherwise print this help\n\
2137 -V, --version print the version of cygcheck and exit\n\
2139 Note: -c, -f, and -l only report on packages that are currently installed. To\n\
2140 search all official Cygwin packages use -p instead. The -p REGEXP matches\n\
2141 package names, descriptions, and names of files/paths within all packages.\n\
2146 struct option longopts
[] = {
2147 {"check-setup", no_argument
, NULL
, 'c'},
2148 {"dump-only", no_argument
, NULL
, 'd'},
2149 {"sysinfo", no_argument
, NULL
, 's'},
2150 {"registry", no_argument
, NULL
, 'r'},
2151 {"verbose", no_argument
, NULL
, 'v'},
2152 {"keycheck", no_argument
, NULL
, 'k'},
2153 {"find-package", no_argument
, NULL
, 'f'},
2154 {"list-package", no_argument
, NULL
, 'l'},
2155 {"package-query", no_argument
, NULL
, 'p'},
2156 {"delete-orphaned-installation-keys", no_argument
, NULL
, CO_DELETE_KEYS
},
2157 {"help", no_argument
, NULL
, 'h'},
2158 {"version", no_argument
, 0, 'V'},
2159 {0, no_argument
, NULL
, 0}
2162 static char opts
[] = "cdsrvkflphV";
2167 printf ("cygcheck (cygwin) %d.%d.%d\n"
2168 "System Checker for Cygwin\n"
2169 "Copyright (C) 1998 - %s Cygwin Authors\n"
2170 "This is free software; see the source for copying conditions. "
2172 "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR "
2174 CYGWIN_VERSION_DLL_MAJOR
/ 1000,
2175 CYGWIN_VERSION_DLL_MAJOR
% 1000,
2176 CYGWIN_VERSION_DLL_MINOR
,
2177 strrchr (__DATE__
, ' ') + 1);
2183 int n
= 1 + strchr (ev
, '=') - ev
;
2184 char *s
= (char *) malloc (n
+ 1);
2191 uintptr_t (*cygwin_internal
) (int, ...);
2192 WCHAR cygwin_dll_path
[32768];
2196 load_cygwin (int& argc
, char **&argv
)
2200 if (!(h
= LoadLibrary ("cygwin1.dll")))
2202 GetModuleFileNameW (h
, cygwin_dll_path
, 32768);
2203 if ((cygwin_internal
= (uintptr_t (*) (int, ...))
2204 GetProcAddress (h
, "cygwin_internal")))
2206 char **av
= (char **) cygwin_internal (CW_ARGV
);
2207 if (av
&& ((uintptr_t) av
!= (uintptr_t) -1))
2209 /* Copy cygwin's idea of the argument list into this Window
2211 for (argc
= 0; av
[argc
]; argc
++)
2213 argv
= (char **) calloc (argc
+ 1, sizeof (char *));
2214 for (char **argvp
= argv
; *av
; av
++)
2215 *argvp
++ = strdup (*av
);
2219 char **envp
= (char **) cygwin_internal (CW_ENVP
);
2220 if (envp
&& ((uintptr_t) envp
!= (uintptr_t) -1))
2222 /* Store path and revert to this value, otherwise path gets
2223 overwritten by the POSIXy Cygwin variation, which breaks cygcheck.
2224 Another approach would be to use the Cygwin PATH and convert it to
2228 while (*(env
= _environ
))
2230 if (strncmp (*env
, "PATH=", 5) == 0)
2231 path
= strdup (*env
);
2234 for (char **ev
= envp
; *ev
; ev
++)
2235 if (strncmp (*ev
, "PATH=", 5) != 0)
2236 putenv (strdup (*ev
));
2241 /* GDB chokes when the DLL got unloaded and, for some reason, fails to set
2242 any breakpoint after the fact. */
2243 if (!IsDebuggerPresent ())
2248 main (int argc
, char **argv
)
2252 load_cygwin (argc
, argv
);
2254 /* Need POSIX sorting while parsing args, but don't forget the
2255 user's original environment. */
2256 char *posixly
= getenv ("POSIXLY_CORRECT");
2257 if (posixly
== NULL
)
2258 (void) putenv ("POSIXLY_CORRECT=1");
2259 while ((i
= getopt_long (argc
, argv
, opts
, longopts
, NULL
)) != EOF
)
2292 case CO_DELETE_KEYS
:
2293 del_orphaned_reg
= 1;
2299 fprintf (stderr
, "Try `cygcheck --help' for more information.\n");
2305 if (posixly
== NULL
)
2306 putenv ("POSIXLY_CORRECT=");
2308 if ((argc
== 0) && !sysinfo
&& !keycheck
&& !check_setup
&& !list_package
2309 && !del_orphaned_reg
)
2317 if ((check_setup
|| sysinfo
|| find_package
|| list_package
|| grep_packages
2318 || del_orphaned_reg
)
2322 if ((find_package
|| list_package
|| grep_packages
)
2323 && (check_setup
|| del_orphaned_reg
))
2326 if (dump_only
&& !check_setup
&& !sysinfo
)
2329 if (find_package
+ list_package
+ grep_packages
> 1)
2333 return check_keys ();
2334 if (del_orphaned_reg
)
2335 del_orphaned_reg_installations ();
2337 return package_grep (*argv
);
2341 /* FIXME: Add help for check_setup and {list,find}_package */
2342 if (argc
>= 1 && givehelp
&& !check_setup
&& !find_package
&& !list_package
)
2344 printf("Here is where the OS will find your program%s, and which dlls\n",
2345 argc
> 1 ? "s" : "");
2346 printf ("will be used for it. Use -v to see DLL version info\n");
2353 dump_setup (verbose
, argv
, !dump_only
);
2354 else if (find_package
)
2355 package_find (verbose
, argv
);
2356 else if (list_package
)
2357 package_list (verbose
, argv
);
2359 for (i
= 0; i
< argc
; i
++)
2363 ok
&= cygcheck (argv
[i
]);
2372 dump_setup (verbose
, NULL
, !dump_only
);
2376 puts ("Use -h to see help about each section");
2379 return ok
? EXIT_SUCCESS
: EXIT_FAILURE
;