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
22 #include "wide_path.h"
24 #include "../cygwin/include/cygwin/version.h"
25 #include "../cygwin/include/sys/cygwin.h"
26 #define _NOMNTENT_MACROS
27 #include "../cygwin/include/mntent.h"
28 #undef cygwin_internal
36 #define alloca __builtin_alloca
48 int grep_packages
= 0;
49 int del_orphaned_reg
= 0;
51 static char emptystr
[] = "";
54 typedef long long longlong
;
56 typedef __int64 longlong
;
59 /* In dump_setup.cc */
60 void dump_setup (int, char **, bool);
61 void package_find (int, char **);
62 void package_list (int, char **);
64 void dump_dodgy_apps (int verbose
);
66 static const char *known_env_vars
[] = {
74 "gcc_default_options",
96 static common_apps
[] = {
140 /* Options without ASCII single char representation. */
143 CO_DELETE_KEYS
= 0x100,
146 static int num_paths
, max_paths
;
151 void check_existence (const char *fn
, int showall
, int verbose
,
152 char* first
, const char *ext1
= "",
153 const char *ext2
= "");
157 int first_nonsys_path
;
160 eprintf (const char *format
, ...)
163 va_start (ap
, format
);
164 vfprintf (stderr
, format
, ap
);
169 * display_error() is used to report failure modes
172 display_error (const char *name
, bool show_error
, bool print_failed
)
174 fprintf (stderr
, "cygcheck: %s", name
);
176 fprintf (stderr
, "%s: %lu\n",
177 print_failed
? " failed" : "", GetLastError ());
179 fprintf (stderr
, "%s\n",
180 print_failed
? " failed" : "");
185 display_error (const char *name
)
187 return display_error (name
, true, true);
191 display_error (const char *fmt
, const char *x
)
194 snprintf (buf
, sizeof buf
, fmt
, x
);
195 return display_error (buf
, false, false);
199 display_error_fmt (const char *fmt
, ...)
205 vsnprintf (buf
, sizeof buf
, fmt
, va
);
206 return display_error (buf
, false, false);
209 /* Display a WinInet error message, and close a variable number of handles.
210 (Passed a list of handles terminated by NULL.) */
212 display_internet_error (const char *message
, ...)
214 DWORD err
= GetLastError ();
219 /* in the case of a successful connection but 404 response, there is no
220 win32 error message, but we still get passed a message to display. */
223 if (FormatMessage (FORMAT_MESSAGE_FROM_HMODULE
,
224 GetModuleHandle ("wininet.dll"), err
, 0, err_buf
,
225 sizeof (err_buf
), NULL
) == 0)
226 strcpy (err_buf
, "(Unknown error)");
228 fprintf (stderr
, "cygcheck: %s: %s (win32 error %lu)\n", message
,
232 fprintf (stderr
, "cygcheck: %s\n", message
);
234 va_start (hptr
, message
);
235 while ((h
= va_arg (hptr
, HINTERNET
)) != 0)
236 InternetCloseHandle (h
);
243 add_path (char *s
, int maxlen
, bool issys
)
245 if (num_paths
>= max_paths
)
248 /* Extend path array */
249 paths
= (pathlike
*) realloc (paths
, (1 + max_paths
) * sizeof (paths
[0]));
252 pathlike
*pth
= paths
+ num_paths
;
254 /* Allocate space for directory in path list */
255 char *dir
= (char *) calloc (maxlen
+ 2, sizeof (char));
258 display_error ("add_path: calloc() failed");
262 /* Copy input directory to path list */
263 memcpy (dir
, s
, maxlen
);
265 /* Add a trailing slash by default */
266 char *e
= strchr (dir
, '\0');
267 if (e
!= dir
&& e
[-1] != '\\')
270 /* Fill out this element */
281 add_path ((char *) ".", 1, true); /* to be replaced later */
283 if (GetCurrentDirectory (4000, tmp
))
284 add_path (tmp
, strlen (tmp
), true);
286 display_error ("init_paths: GetCurrentDirectory()");
288 if (GetSystemDirectory (tmp
, 4000))
289 add_path (tmp
, strlen (tmp
), true);
291 display_error ("init_paths: GetSystemDirectory()");
292 sl
= strrchr (tmp
, '\\');
295 strcpy (sl
, "\\SYSTEM");
296 add_path (tmp
, strlen (tmp
), true);
298 GetWindowsDirectory (tmp
, 4000);
299 add_path (tmp
, strlen (tmp
), true);
301 char *wpath
= getenv ("PATH");
303 display_error ("WARNING: PATH is not set\n", "");
310 for (e
= b
; *e
&& *e
!= ';'; e
++)
311 continue; /* loop terminates at first ';' or EOS */
312 if (strncmp(b
, ".\\", 2) != 0)
313 add_path (b
, e
- b
, false);
321 #define LINK_EXTENSION ".lnk"
324 pathlike::check_existence (const char *fn
, int showall
, int verbose
,
325 char* first
, const char *ext1
, const char *ext2
)
328 snprintf (file
, sizeof file
, "%s%s%s%s", dir
, fn
, ext1
, ext2
);
330 wide_path
wpath (file
);
331 if (GetFileAttributesW (wpath
) != (DWORD
) - 1)
333 char *lastdot
= strrchr (file
, '.');
334 bool is_link
= lastdot
&& !strcmp (lastdot
, LINK_EXTENSION
);
335 // If file is a link, fix up the extension before printing
339 printf ("Found: %s\n", file
);
340 if (verbose
&& *first
!= '\0' && strcasecmp (first
, file
) != 0)
342 char *flastdot
= strrchr (first
, '.');
343 bool f_is_link
= flastdot
&& !strcmp (flastdot
, LINK_EXTENSION
);
344 // if first is a link, fix up the extension before printing
347 printf ("Warning: %s hides %s\n", first
, file
);
354 strcpy (first
, file
);
359 find_on_path (const char *in_file
, const char *ext
, bool showall
= false,
360 bool search_sys
= false, bool checklinks
= false)
362 static char rv
[4000];
364 /* Sort of a kludge but we've already tested this once, so don't try it
369 static pathlike abspath
[2] =
378 display_error ("internal error find_on_path: NULL pointer for file",
385 display_error ("internal error find_on_path: "
386 "NULL pointer for default_extension", false, false);
391 pathlike
*search_paths
;
392 if (!strpbrk (in_file
, ":/\\"))
395 search_paths
= paths
;
399 file
= cygpath (in_file
, NULL
);
400 search_paths
= abspath
;
406 display_error ("internal error find_on_path: "
407 "cygpath conversion failed for %s\n", in_file
);
411 char *hasext
= strrchr (file
, '.');
412 if (hasext
&& !strpbrk (hasext
, "/\\"))
415 for (pathlike
*pth
= search_paths
; pth
->dir
; pth
++)
416 if (!pth
->issys
|| search_sys
)
418 pth
->check_existence (file
, showall
, verbose
, rv
, ext
);
421 pth
->check_existence (file
, showall
, verbose
, rv
, ext
,
427 pth
->check_existence (file
, showall
, verbose
, rv
);
429 pth
->check_existence (file
, showall
, verbose
, rv
, LINK_EXTENSION
);
432 return *rv
? rv
: NULL
;
437 #define DID_INACTIVE 3
448 already_did (const char *file
)
451 for (d
= did
; d
; d
= d
->next
)
452 if (strcasecmp (d
->file
, file
) == 0)
454 d
= (Did
*) malloc (sizeof (Did
));
455 d
->file
= strdup (file
);
467 int size_of_raw_data
;
468 int pointer_to_raw_data
;
472 rva_to_offset (int rva
, char *sections
, int nsections
, int *sz
)
476 if (sections
== NULL
)
478 display_error ("rva_to_offset: NULL passed for sections", true, false);
482 for (i
= 0; i
< nsections
; i
++)
484 Section
*s
= (Section
*) (sections
+ i
* 40);
486 printf ("%08x < %08x < %08x ? %08x\n",
487 s
->virtual_address
, rva
,
488 s
->virtual_address
+ s
->virtual_size
, s
->pointer_to_raw_data
);
490 if (rva
>= s
->virtual_address
491 && rva
< s
->virtual_address
+ s
->virtual_size
)
494 *sz
= s
->virtual_address
+ s
->virtual_size
- rva
;
495 return rva
- s
->virtual_address
+ s
->pointer_to_raw_data
;
512 unsigned characteristics
;
514 unsigned forwarder_chain
;
519 static bool track_down (const char *file
, const char *suffix
, int lvl
);
521 #define CYGPREFIX (sizeof ("%%% Cygwin ") - 1)
523 cygwin_info (HANDLE h
)
525 char *buf
, *bufend
, *buf_start
= NULL
;
526 const char *hello
= " Cygwin DLL version info:\n";
527 DWORD size
= GetFileSize (h
, NULL
);
530 if (size
== 0xffffffff)
533 buf_start
= buf
= (char *) calloc (1, size
+ 1);
536 display_error ("cygwin_info: calloc()");
540 (void) SetFilePointer (h
, 0, NULL
, FILE_BEGIN
);
541 if (!ReadFile (h
, buf
, size
, &n
, NULL
))
547 static char dummy
[] = "\0\0\0\0\0\0\0";
548 char *dll_major
= dummy
;
551 if ((buf
= (char *) memchr (buf
, '%', bufend
- buf
)) == NULL
)
553 else if (strncmp ("%%% Cygwin ", buf
, CYGPREFIX
) != 0)
557 char *p
= strchr (buf
+= CYGPREFIX
, '\n');
560 if (strncasecmp (buf
, "dll major:", 10) == 0)
562 dll_major
= buf
+ 11;
568 if (strncasecmp (buf
, "dll minor:", 10) != 0)
572 char c
= dll_major
[1];
574 int maj
= atoi (dll_major
);
576 int min
= atoi (dll_major
+ 1);
577 sprintf (pbuf
, "DLL version: %d.%d.%.*s", maj
, min
, len
- 11,
579 len
= strlen (s
= pbuf
);
581 if (strncmp (s
, "dll", 3) == 0)
582 memcpy (s
, "DLL", 3);
583 else if (strncmp (s
, "api", 3) == 0)
584 memcpy (s
, "API", 3);
585 else if (islower (*s
))
587 fprintf (stdout
, "%s %.*s", hello
, len
, s
);
599 dll_info (const char *path
, HANDLE fh
, int lvl
, int recurse
)
609 char buf
[PATH_MAX
+ 1] = "";
610 readlink (fh
, buf
, sizeof(buf
) - 1);
611 printf (" (symlink to %s)\n", buf
);
615 int pe_header_offset
= get_dword (fh
, 0x3c);
616 if (GetLastError () != NO_ERROR
)
617 display_error ("get_dword");
618 WORD arch
= get_word (fh
, pe_header_offset
+ 4);
619 if (GetLastError () != NO_ERROR
)
620 display_error ("get_word");
622 if (arch
!= IMAGE_FILE_MACHINE_AMD64
)
624 puts (verbose
? " (not x86_64 dll)" : "\n");
629 if (arch
!= IMAGE_FILE_MACHINE_I386
)
631 puts (verbose
? " (not x86 dll)" : "\n");
636 int opthdr_ofs
= pe_header_offset
+ 4 + 20;
641 display_error ("dll_info: NULL passed for path", true, false);
645 if (SetFilePointer (fh
, opthdr_ofs
+ 40, 0, FILE_BEGIN
) ==
646 INVALID_SET_FILE_POINTER
&& GetLastError () != NO_ERROR
)
647 display_error ("dll_info: SetFilePointer()");
649 if (!ReadFile (fh
, &v
, sizeof (v
), &junk
, 0))
650 display_error ("dll_info: Readfile()");
653 printf (" - os=%d.%d img=%d.%d sys=%d.%d\n",
654 v
[0], v
[1], v
[2], v
[3], v
[4], v
[5]);
658 int num_entries
= get_dword (fh
, opthdr_ofs
+ base_off
+ 0);
659 if (GetLastError () != NO_ERROR
)
660 display_error ("get_dword");
661 int export_rva
= get_dword (fh
, opthdr_ofs
+ base_off
+ 4);
662 if (GetLastError () != NO_ERROR
)
663 display_error ("get_dword");
664 int export_size
= get_dword (fh
, opthdr_ofs
+ base_off
+ 8);
665 if (GetLastError () != NO_ERROR
)
666 display_error ("get_dword");
667 int import_rva
= get_dword (fh
, opthdr_ofs
+ base_off
+ 12);
668 if (GetLastError () != NO_ERROR
)
669 display_error ("get_dword");
670 int import_size
= get_dword (fh
, opthdr_ofs
+ base_off
+ 16);
671 if (GetLastError () != NO_ERROR
)
672 display_error ("get_dword");
674 int nsections
= get_word (fh
, pe_header_offset
+ 4 + 2);
676 display_error ("get_word");
677 char *sections
= (char *) malloc (nsections
* 40);
679 if (SetFilePointer (fh
, pe_header_offset
+ 4 + 20 +
680 get_word (fh
, pe_header_offset
+ 4 + 16), 0,
681 FILE_BEGIN
) == INVALID_SET_FILE_POINTER
682 && GetLastError () != NO_ERROR
)
683 display_error ("dll_info: SetFilePointer()");
685 if (!ReadFile (fh
, sections
, nsections
* 40, &junk
, 0))
686 display_error ("dll_info: Readfile()");
688 if (verbose
&& num_entries
>= 1 && export_size
> 0)
691 int expbase
= rva_to_offset (export_rva
, sections
, nsections
, &expsz
);
695 if (SetFilePointer (fh
, expbase
, 0, FILE_BEGIN
) ==
696 INVALID_SET_FILE_POINTER
&& GetLastError () != NO_ERROR
)
697 display_error ("dll_info: SetFilePointer()");
699 unsigned char *exp
= (unsigned char *) malloc (expsz
);
701 if (!ReadFile (fh
, exp
, expsz
, &junk
, 0))
702 display_error ("dll_info: Readfile()");
704 ExpDirectory
*ed
= (ExpDirectory
*) exp
;
705 int ofs
= ed
->name_rva
- export_rva
;
706 time_t ts
= ed
->timestamp
; /* timestamp is only 4 bytes! */
707 struct tm
*tm
= localtime (&ts
);
708 if (tm
&& tm
->tm_year
< 60)
710 if (tm
&& tm
->tm_year
< 200)
712 printf ("%*c", lvl
+ 2, ' ');
713 printf ("\"%s\" v%d.%d", exp
+ ofs
,
714 ed
->major_ver
, ed
->minor_ver
);
716 printf (" ts=%04d-%02d-%02d %02d:%02d",
717 tm
->tm_year
, tm
->tm_mon
+ 1, tm
->tm_mday
,
718 tm
->tm_hour
, tm
->tm_min
);
723 if (num_entries
>= 2 && import_size
> 0 && recurse
)
726 int impbase
= rva_to_offset (import_rva
, sections
, nsections
, &impsz
);
729 if (SetFilePointer (fh
, impbase
, 0, FILE_BEGIN
) ==
730 INVALID_SET_FILE_POINTER
&& GetLastError () != NO_ERROR
)
731 display_error ("dll_info: SetFilePointer()");
733 unsigned char *imp
= (unsigned char *) malloc (impsz
);
736 display_error ("dll_info: malloc()");
740 if (!ReadFile (fh
, imp
, impsz
, &junk
, 0))
741 display_error ("dll_info: Readfile()");
743 ImpDirectory
*id
= (ImpDirectory
*) imp
;
744 for (i
= 0; id
[i
].name_rva
; i
++)
746 /* int ofs = id[i].name_rva - import_rva; */
747 track_down ((char *) imp
+ id
[i
].name_rva
- import_rva
,
748 (char *) ".dll", lvl
+ 2);
752 if (strstr (path
, "\\cygwin1.dll"))
756 // Return true on success, false if error printed
758 track_down (const char *file
, const char *suffix
, int lvl
)
762 display_error ("track_down: NULL passed for file", true, false);
768 display_error ("track_down: NULL passed for suffix", false, false);
772 const char *path
= find_on_path (file
, suffix
, false, true);
775 /* The api-ms-win-*.dll files are in system32/downlevel and not in the
776 DLL search path, so find_on_path doesn't find them. Since they are
777 never actually linked against by the executables, they are of no
778 interest to us. Skip any error message in not finding them. */
779 if (strncasecmp (file
, "api-ms-win-", 11) || strcasecmp (suffix
, ".dll"))
780 display_error ("track_down: could not find %s\n", file
);
784 Did
*d
= already_did (file
);
793 printf ("%*c", lvl
, ' ');
795 printf (" (recursive)\n");
802 printf ("%*c", lvl
, ' ');
804 printf (" (already done)\n");
812 printf ("%*c", lvl
, ' ');
816 wide_path
wpath (path
);
818 CreateFileW (wpath
, GENERIC_READ
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
819 NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
820 if (fh
== INVALID_HANDLE_VALUE
)
822 display_error ("cannot open - '%s'\n", path
);
826 d
->state
= DID_ACTIVE
;
829 dll_info (path
, fh
, lvl
, 1);
830 else if (is_symlink (fh
))
831 display_error ("%s is a symlink instead of a DLL\n", path
);
834 int magic
= get_word (fh
, 0x0);
836 display_error ("get_word");
838 display_error_fmt ("%s is not a DLL: magic number %x (%d) '%s'\n",
839 path
, magic
, magic
, (char *)&magic
);
842 d
->state
= DID_INACTIVE
;
843 if (!CloseHandle (fh
))
844 display_error ("track_down: CloseHandle()");
852 HANDLE h
= CreateFileW (wpath
, GENERIC_READ
,
853 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
854 0, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, 0);
855 BY_HANDLE_FILE_INFORMATION info
;
857 if (!GetFileInformationByHandle (h
, &info
))
858 display_error ("ls: GetFileInformationByHandle()");
862 if (!FileTimeToSystemTime (&info
.ftLastWriteTime
, &systime
))
863 display_error ("ls: FileTimeToSystemTime()");
864 printf ("%5dk %04d/%02d/%02d %s",
865 (((int) info
.nFileSizeLow
) + 512) / 1024,
866 systime
.wYear
, systime
.wMonth
, systime
.wDay
, f
);
867 dll_info (f
, h
, 16, 0);
868 if (!CloseHandle (h
))
869 display_error ("ls: CloseHandle()");
872 /* Remove filename from 's' and return directory name without trailing
873 backslash, or NULL if 's' doesn't seem to have a dirname. */
875 dirname (const char *s
)
877 static char buf
[PATH_MAX
];
882 strncpy (buf
, s
, PATH_MAX
);
883 buf
[PATH_MAX
- 1] = '\0'; // in case strlen(s) > PATH_MAX
884 char *lastsep
= strrchr (buf
, '\\');
886 return NULL
; // no backslash -> no dirname
887 else if (lastsep
- buf
<= 2 && buf
[1] == ':')
888 lastsep
[1] = '\0'; // can't remove backslash of "x:\"
894 // Find a real application on the path (possibly following symlinks)
896 find_app_on_path (const char *app
, bool showall
= false)
898 const char *papp
= find_on_path (app
, ".exe", showall
, false, true);
903 wide_path
wpath (papp
);
905 CreateFileW (wpath
, GENERIC_READ
, FILE_SHARE_READ
| FILE_SHARE_WRITE
,
906 NULL
, OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
907 if (fh
== INVALID_HANDLE_VALUE
)
912 static char tmp
[SYMLINK_MAX
+ 1];
913 if (!readlink (fh
, tmp
, SYMLINK_MAX
))
914 display_error("readlink failed");
916 /* Resolve the linkname relative to the directory of the link. */
917 char *ptr
= cygpath_rel (dirname (papp
), tmp
, NULL
);
918 printf (" -> %s\n", ptr
);
919 if (!strchr (ptr
, '\\'))
922 strncpy (tmp
, cygpath (papp
, NULL
), SYMLINK_MAX
);
923 lastsep
= strrchr (tmp
, '\\');
924 strncpy (lastsep
+1, ptr
, SYMLINK_MAX
- (lastsep
-tmp
));
927 if (!CloseHandle (fh
))
928 display_error ("find_app_on_path: CloseHandle()");
929 /* FIXME: We leak the ptr returned by cygpath() here which is a
931 return find_app_on_path (ptr
, showall
);
934 if (!CloseHandle (fh
))
935 display_error ("find_app_on_path: CloseHandle()");
939 // Return true on success, false if error printed
941 cygcheck (const char *app
)
943 const char *papp
= find_app_on_path (app
, 1);
946 display_error ("could not find '%s'\n", app
);
951 char *sep
= strpbrk (papp
, ":/\\");
954 static char dot
[] = ".";
960 s
= (char *) malloc (n
+ 2);
961 memcpy ((char *) s
, papp
, n
);
962 strcpy (s
+ n
, "\\");
967 return track_down (papp
, ".exe", 0);
978 show_reg (RegInfo
* ri
, int nest
)
982 show_reg (ri
->prev
, 1);
984 printf ("%s\\", ri
->name
);
986 printf ("%s\n", ri
->name
);
990 scan_registry (RegInfo
* prev
, HKEY hKey
, char *name
, int cygwin
, bool wow64
)
998 for (cp
= name
; *cp
; cp
++)
999 if (strncasecmp (cp
, "Cygwin", 6) == 0)
1002 DWORD num_subkeys
, max_subkey_len
, num_values
;
1003 DWORD max_value_len
, max_valdata_len
, i
;
1004 if (RegQueryInfoKey (hKey
, 0, 0, 0, &num_subkeys
, &max_subkey_len
, 0,
1005 &num_values
, &max_value_len
, &max_valdata_len
, 0, 0)
1010 FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM
, 0, GetLastError (),
1011 MAKELANGID (LANG_NEUTRAL
, SUBLANG_DEFAULT
), tmp
, 400, 0);
1012 printf ("RegQueryInfoKey: %s\n", tmp
);
1021 char *value_name
= (char *) malloc (max_value_len
+ 1);
1022 if (value_name
== NULL
)
1024 display_error ("scan_registry: malloc()");
1028 char *value_data
= (char *) malloc (max_valdata_len
+ 1);
1029 if (value_data
== NULL
)
1031 display_error ("scan_registry: malloc()");
1035 for (i
= 0; i
< num_values
; i
++)
1037 DWORD dlen
= max_valdata_len
+ 1;
1038 DWORD nlen
= max_value_len
+ 1;
1040 RegEnumValue (hKey
, i
, value_name
, &nlen
, 0,
1041 &type
, (BYTE
*) value_data
, &dlen
);
1043 printf (" %s = ", i
? value_name
: "(default)");
1047 printf ("0x%08x\n", *(unsigned *) value_data
);
1051 printf ("'%s'\n", value_data
);
1054 printf ("(unsupported type)\n");
1063 char *subkey_name
= (char *) malloc (max_subkey_len
+ 1);
1064 for (i
= 0; i
< num_subkeys
; i
++)
1066 if (RegEnumKey (hKey
, i
, subkey_name
, max_subkey_len
+ 1) ==
1070 /* Don't recurse more than one level into the WOW64 subkey since
1071 that would lead to an endless recursion. */
1072 if (!strcasecmp (subkey_name
, "Wow6432Node"))
1078 if (RegOpenKeyEx (hKey
, subkey_name
, 0, KEY_READ
, &sKey
)
1081 scan_registry (&ri
, sKey
, subkey_name
, cygwin
, wow64
);
1082 if (RegCloseKey (sKey
) != ERROR_SUCCESS
)
1083 display_error ("scan_registry: RegCloseKey()");
1093 char *groups
[16384];
1095 char *id
= cygpath ("/bin/id.exe", NULL
);
1096 for (char *p
= id
; (p
= strchr (p
, '/')); p
++)
1099 if (access (id
, X_OK
))
1101 fprintf (stderr
, "'id' program not found\n");
1106 snprintf (buf
, sizeof (buf
), "\"%s\"", id
);
1107 FILE *f
= popen (buf
, "rt");
1110 fgets (buf
, sizeof (buf
), f
);
1112 char *uid
= strtok (buf
, ")");
1114 uid
+= strlen ("uid=");
1117 fprintf (stderr
, "garbled output from 'id' command - no uid= found\n");
1120 char *gid
= strtok (NULL
, ")");
1122 gid
+= strlen ("gid=") + 1;
1125 fprintf (stderr
, "garbled output from 'id' command - no gid= found\n");
1129 char **ng
= groups
- 1;
1130 size_t len_uid
= strlen ("UID: )") + strlen (uid
);
1131 size_t len_gid
= strlen ("GID: )") + strlen (gid
);
1132 *++ng
= groups
[0] = (char *) alloca (len_uid
+ 1);
1133 *++ng
= groups
[1] = (char *) alloca (len_gid
+ 1);
1134 sprintf (groups
[0], "UID: %s)", uid
);
1135 sprintf (groups
[1], "GID: %s)", gid
);
1136 size_t sz
= max (len_uid
, len_gid
);
1137 while ((*++ng
= strtok (NULL
, ",")))
1139 char *p
= strchr (*ng
, '\n');
1142 if (ng
== groups
+ 2)
1143 *ng
+= strlen (" groups=");
1144 size_t len
= strlen (*ng
);
1150 printf ("\nOutput from %s\n", id
);
1151 int n
= 80 / (int) ++sz
;
1152 int i
= n
> 2 ? n
- 2 : 0;
1154 for (char **g
= groups
; g
<= ng
; g
++)
1155 if ((g
!= ng
) && (++i
< n
))
1156 printf ("%*s", (int) sz
, *g
);
1164 /* This dumps information about each installed cygwin service, if cygrunsrv
1167 dump_sysinfo_services ()
1172 bool no_services
= false;
1175 printf ("\nChecking for any Cygwin services... %s\n\n",
1176 verbose
? "" : "(use -v for more detail)");
1178 fputc ('\n', stdout
);
1180 /* find the location of cygrunsrv.exe */
1181 char *cygrunsrv
= cygpath ("/bin/cygrunsrv.exe", NULL
);
1182 for (char *p
= cygrunsrv
; (p
= strchr (p
, '/')); p
++)
1185 if (access (cygrunsrv
, X_OK
))
1187 puts ("Can't find the cygrunsrv utility, skipping services check.\n");
1191 /* check for a recent cygrunsrv */
1192 snprintf (buf
, sizeof (buf
), "\"%s\" --version", cygrunsrv
);
1193 if ((f
= popen (buf
, "rt")) == NULL
)
1195 printf ("Failed to execute '%s', skipping services check.\n", buf
);
1199 int ret
= fscanf (f
, "cygrunsrv V%u.%u", &maj
, &min
);
1200 if (ferror (f
) || feof (f
) || ret
== EOF
|| maj
< 1 || min
< 10)
1202 puts ("The version of cygrunsrv installed is too old to dump "
1208 /* For verbose mode, just run cygrunsrv --list --verbose and copy output
1209 verbatim; otherwise run cygrunsrv --list and then cygrunsrv --query for
1211 snprintf (buf
, sizeof (buf
),
1212 (verbose
? "\"%s\" --list --verbose" : "\"%s\" --list"),
1214 if ((f
= popen (buf
, "rt")) == NULL
)
1216 printf ("Failed to execute '%s', skipping services check.\n", buf
);
1222 /* copy output to stdout */
1224 while (!feof (f
) && !ferror (f
))
1225 nchars
+= fwrite ((void *) buf
, 1,
1226 fread ((void *) buf
, 1, sizeof (buf
), f
), stdout
);
1228 /* cygrunsrv outputs nothing if there are no cygwin services found */
1235 /* read the output of --list, and then run --query for each service */
1236 size_t nchars
= fread ((void *) buf
, 1, sizeof (buf
) - 1, f
);
1241 for (char *srv
= strtok (buf
, "\n"); srv
; srv
= strtok (NULL
, "\n"))
1243 snprintf (buf2
, sizeof (buf2
), "\"%s\" --query %s", cygrunsrv
, srv
);
1244 if ((f
= popen (buf2
, "rt")) == NULL
)
1246 printf ("Failed to execute '%s', skipping services check.\n",
1251 /* copy output to stdout */
1252 while (!feof (f
) && !ferror (f
))
1253 fwrite ((void *) buf2
, 1,
1254 fread ((void *) buf2
, 1, sizeof (buf2
), f
), stdout
);
1261 /* inform the user if nothing found */
1263 puts ("No Cygwin services found.\n");
1273 handle_reg_installation (handle_reg_t what
)
1277 if (what
== PRINT_KEY
)
1278 printf ("Cygwin installations found in the registry:\n");
1279 for (int i
= 0; i
< 2; ++i
)
1280 if (RegOpenKeyEx (i
? HKEY_CURRENT_USER
: HKEY_LOCAL_MACHINE
,
1281 "SOFTWARE\\Cygwin\\Installations", 0,
1282 what
== DELETE_KEY
? KEY_READ
| KEY_WRITE
: KEY_READ
,
1286 char name
[32], data
[PATH_MAX
];
1287 DWORD nsize
, dsize
, type
;
1290 for (DWORD index
= 0;
1291 (ret
= RegEnumValue (key
, index
, name
, (nsize
= 32, &nsize
), 0,
1292 &type
, (PBYTE
) data
,
1293 (dsize
= PATH_MAX
, &dsize
)))
1294 != ERROR_NO_MORE_ITEMS
; ++index
)
1295 if (ret
== ERROR_SUCCESS
&& dsize
> 5)
1297 char *path
= data
+ 4;
1299 *(path
+= 2) = '\\';
1300 if (what
== PRINT_KEY
)
1301 printf (" %s Key: %s Path: %s", i
? "User: " : "System:",
1303 strcat (path
, "\\bin\\cygwin1.dll");
1304 if (what
== PRINT_KEY
)
1305 printf ("%s\n", access (path
, F_OK
) ? " (ORPHANED)" : "");
1306 else if (access (path
, F_OK
))
1308 RegDeleteValue (key
, name
);
1309 /* Start over since index is not reliable anymore. */
1316 if (what
== PRINT_KEY
)
1321 print_reg_installations ()
1323 handle_reg_installation (PRINT_KEY
);
1327 del_orphaned_reg_installations ()
1329 handle_reg_installation (DELETE_KEY
);
1332 /* Unfortunately neither mingw nor Windows know this function. */
1334 memmem (char *haystack
, size_t haystacklen
,
1335 const char *needle
, size_t needlelen
)
1339 while (needlelen
<= haystacklen
)
1341 if (!memcmp (haystack
, needle
, needlelen
))
1349 extern "C" NTSTATUS NTAPI
RtlGetVersion (PRTL_OSVERSIONINFOEXW
);
1357 char *found_cygwin_dll
;
1360 DWORD obcaseinsensitive
= 1;
1363 /* MSVCRT popen (called by pretty_id and dump_sysinfo_services) SEGVs if
1364 COMSPEC isn't set correctly. Simply enforce it here. Using
1365 Get/SetEnvironmentVariable to set the dir does *not* help, btw.
1366 Apparently MSVCRT keeps its own copy of the environment and changing
1367 that requires to use _wputenv. */
1368 if (!_wgetenv (L
"COMSPEC"))
1370 WCHAR comspec
[MAX_PATH
+ 17];
1371 wcscpy (comspec
, L
"COMSPEC=");
1372 GetSystemDirectoryW (comspec
+ 8, MAX_PATH
);
1373 wcsncat (comspec
, L
"\\cmd.exe", sizeof comspec
);
1377 printf ("\nCygwin Configuration Diagnostics\n");
1379 printf ("Current System Time: %s\n", ctime (&now
));
1381 RTL_OSVERSIONINFOEXW osversion
;
1382 osversion
.dwOSVersionInfoSize
= sizeof (RTL_OSVERSIONINFOEXW
);
1383 RtlGetVersion (&osversion
);
1385 switch (osversion
.dwPlatformId
)
1387 case VER_PLATFORM_WIN32_NT
:
1389 if (osversion
.dwMajorVersion
>= 6)
1391 HMODULE k32
= GetModuleHandleW (L
"kernel32.dll");
1392 BOOL (WINAPI
*GetProductInfo
) (DWORD
, DWORD
, DWORD
, DWORD
, PDWORD
) =
1393 (BOOL (WINAPI
*)(DWORD
, DWORD
, DWORD
, DWORD
, PDWORD
))
1394 GetProcAddress (k32
, "GetProductInfo");
1395 if (osversion
.dwMajorVersion
== 6)
1396 switch (osversion
.dwMinorVersion
)
1399 strcpy (osname
, osversion
.wProductType
== VER_NT_WORKSTATION
1400 ? "Vista" : "2008");
1403 strcpy (osname
, osversion
.wProductType
== VER_NT_WORKSTATION
1407 strcpy (osname
, osversion
.wProductType
== VER_NT_WORKSTATION
1411 strcpy (osname
, osversion
.wProductType
== VER_NT_WORKSTATION
1412 ? "8.1" : "2012 R2");
1416 strcpy (osname
, osversion
.wProductType
== VER_NT_WORKSTATION
1417 ? "10 Preview" : "2016 Preview");
1420 else if (osversion
.dwMajorVersion
== 10)
1422 strcpy (osname
, osversion
.wProductType
== VER_NT_WORKSTATION
1426 if (GetProductInfo (osversion
.dwMajorVersion
,
1427 osversion
.dwMinorVersion
,
1428 osversion
.wServicePackMajor
,
1429 osversion
.wServicePackMinor
,
1432 const char *products
[] =
1434 /* 0x00000000 */ "",
1435 /* 0x00000001 */ " Ultimate",
1436 /* 0x00000002 */ " Home Basic",
1437 /* 0x00000003 */ " Home Premium",
1438 /* 0x00000004 */ " Enterprise",
1439 /* 0x00000005 */ " Home Basic N",
1440 /* 0x00000006 */ " Business",
1441 /* 0x00000007 */ " Server Standard",
1442 /* 0x00000008 */ " Server Datacenter",
1443 /* 0x00000009 */ " Small Business Server",
1444 /* 0x0000000a */ " Server Enterprise",
1445 /* 0x0000000b */ " Starter",
1446 /* 0x0000000c */ " Server Datacenter Core",
1447 /* 0x0000000d */ " Server Standard Core",
1448 /* 0x0000000e */ " Server Enterprise Core",
1449 /* 0x0000000f */ " Server Enterprise for Itanium-based Systems",
1450 /* 0x00000010 */ " Business N",
1451 /* 0x00000011 */ " Web Server",
1452 /* 0x00000012 */ " HPC Edition",
1453 /* 0x00000013 */ " Home Server",
1454 /* 0x00000014 */ " Storage Server Express",
1455 /* 0x00000015 */ " Storage Server Standard",
1456 /* 0x00000016 */ " Storage Server Workgroup",
1457 /* 0x00000017 */ " Storage Server Enterprise",
1458 /* 0x00000018 */ " for Windows Essential Server Solutions",
1459 /* 0x00000019 */ " Small Business Server Premium",
1460 /* 0x0000001a */ " Home Premium N",
1461 /* 0x0000001b */ " Enterprise N",
1462 /* 0x0000001c */ " Ultimate N",
1463 /* 0x0000001d */ " Web Server Core",
1464 /* 0x0000001e */ " Essential Business Server Management Server",
1465 /* 0x0000001f */ " Essential Business Server Security Server",
1466 /* 0x00000020 */ " Essential Business Server Messaging Server",
1467 /* 0x00000021 */ " Server Foundation",
1468 /* 0x00000022 */ " Home Server 2011",
1469 /* 0x00000023 */ " without Hyper-V for Windows Essential Server Solutions",
1470 /* 0x00000024 */ " Server Standard without Hyper-V",
1471 /* 0x00000025 */ " Server Datacenter without Hyper-V",
1472 /* 0x00000026 */ " Server Enterprise without Hyper-V",
1473 /* 0x00000027 */ " Server Datacenter Core without Hyper-V",
1474 /* 0x00000028 */ " Server Standard Core without Hyper-V",
1475 /* 0x00000029 */ " Server Enterprise Core without Hyper-V",
1476 /* 0x0000002a */ " Hyper-V Server",
1477 /* 0x0000002b */ " Storage Server Express Core",
1478 /* 0x0000002c */ " Storage Server Standard Core",
1479 /* 0x0000002d */ " Storage Server Workgroup Core",
1480 /* 0x0000002e */ " Storage Server Enterprise Core",
1481 /* 0x0000002f */ " Starter N",
1482 /* 0x00000030 */ " Professional",
1483 /* 0x00000031 */ " Professional N",
1484 /* 0x00000032 */ " Small Business Server 2011 Essentials",
1485 /* 0x00000033 */ " Server For SB Solutions",
1486 /* 0x00000034 */ " Server Solutions Premium",
1487 /* 0x00000035 */ " Server Solutions Premium Core",
1488 /* 0x00000036 */ " Server For SB Solutions EM", /* per MSDN, 2012-09-01 */
1489 /* 0x00000037 */ " Server For SB Solutions EM", /* per MSDN, 2012-09-01 */
1490 /* 0x00000038 */ " Multipoint Server",
1491 /* 0x00000039 */ "",
1492 /* 0x0000003a */ "",
1493 /* 0x0000003b */ " Essential Server Solution Management",
1494 /* 0x0000003c */ " Essential Server Solution Additional",
1495 /* 0x0000003d */ " Essential Server Solution Management SVC",
1496 /* 0x0000003e */ " Essential Server Solution Additional SVC",
1497 /* 0x0000003f */ " Small Business Server Premium Core",
1498 /* 0x00000040 */ " Server Hyper Core V",
1499 /* 0x00000041 */ "",
1500 /* 0x00000042 */ " Starter E",
1501 /* 0x00000043 */ " Home Basic E",
1502 /* 0x00000044 */ " Home Premium E",
1503 /* 0x00000045 */ " Professional E",
1504 /* 0x00000046 */ " Enterprise E",
1505 /* 0x00000047 */ " Ultimate E",
1506 /* 0x00000048 */ " Server Enterprise (Evaluation inst.)",
1507 /* 0x00000049 */ "",
1508 /* 0x0000004a */ "",
1509 /* 0x0000004b */ "",
1510 /* 0x0000004c */ " MultiPoint Server Standard",
1511 /* 0x0000004d */ " MultiPoint Server Premium",
1512 /* 0x0000004e */ "",
1513 /* 0x0000004f */ " Server Standard (Evaluation inst.)",
1514 /* 0x00000050 */ " Server Datacenter (Evaluation inst.)",
1515 /* 0x00000051 */ "",
1516 /* 0x00000052 */ "",
1517 /* 0x00000053 */ "",
1518 /* 0x00000054 */ " Enterprise N (Evaluation inst.)",
1519 /* 0x00000055 */ "",
1520 /* 0x00000056 */ "",
1521 /* 0x00000057 */ "",
1522 /* 0x00000058 */ "",
1523 /* 0x00000059 */ "",
1524 /* 0x0000005a */ "",
1525 /* 0x0000005b */ "",
1526 /* 0x0000005c */ "",
1527 /* 0x0000005d */ "",
1528 /* 0x0000005e */ "",
1529 /* 0x0000005f */ " Storage Server Workgroup (Evaluation inst.)",
1530 /* 0x00000060 */ " Storage Server Standard (Evaluation inst.)",
1531 /* 0x00000061 */ "",
1532 /* 0x00000062 */ " N",
1533 /* 0x00000063 */ " China",
1534 /* 0x00000064 */ " Single Language",
1535 /* 0x00000065 */ " Home",
1536 /* 0x00000066 */ "",
1537 /* 0x00000067 */ " Professional with Media Center",
1538 /* 0x00000068 */ " Mobile",
1539 /* 0x00000069 */ "",
1540 /* 0x0000006a */ "",
1541 /* 0x0000006b */ "",
1542 /* 0x0000006c */ "",
1543 /* 0x0000006d */ "",
1544 /* 0x0000006e */ "",
1545 /* 0x0000006f */ "",
1546 /* 0x00000070 */ "",
1547 /* 0x00000071 */ "",
1548 /* 0x00000072 */ "",
1549 /* 0x00000073 */ "",
1550 /* 0x00000074 */ "",
1551 /* 0x00000075 */ "",
1552 /* 0x00000076 */ "",
1553 /* 0x00000077 */ "",
1554 /* 0x00000078 */ "",
1555 /* 0x00000079 */ " Education",
1556 /* 0x0000007a */ " Education N",
1557 /* 0x0000007b */ "",
1558 /* 0x0000007c */ "",
1559 /* 0x0000007d */ "",
1560 /* 0x0000007e */ "",
1561 /* 0x0000007f */ "",
1562 /* 0x00000080 */ "",
1563 /* 0x00000081 */ "",
1564 /* 0x00000082 */ "",
1565 /* 0x00000083 */ "",
1566 /* 0x00000084 */ "",
1567 /* 0x00000085 */ " Mobile Enterprise",
1569 if (prod
== PRODUCT_UNLICENSED
)
1570 strcat (osname
, "Unlicensed");
1571 else if (prod
> 0x00000085)
1572 strcat (osname
, "");
1574 strcat (osname
, products
[prod
]);
1581 strcpy (osname
, "NT");
1584 strcpy (osname
, "??");
1587 printf ("Windows %s Ver %lu.%lu Build %lu %ls\n", osname
,
1588 osversion
.dwMajorVersion
, osversion
.dwMinorVersion
,
1589 osversion
.dwPlatformId
== VER_PLATFORM_WIN32_NT
?
1590 osversion
.dwBuildNumber
: (osversion
.dwBuildNumber
& 0xffff),
1591 osversion
.dwPlatformId
== VER_PLATFORM_WIN32_NT
?
1592 osversion
.szCSDVersion
: L
"");
1594 if (osversion
.dwPlatformId
== VER_PLATFORM_WIN32s
1595 || osversion
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
)
1596 exit (EXIT_FAILURE
);
1598 BOOL is_wow64
= FALSE
;
1599 if (IsWow64Process (GetCurrentProcess (), &is_wow64
) && is_wow64
)
1601 SYSTEM_INFO natinfo
;
1602 GetNativeSystemInfo (&natinfo
);
1603 fputs ("\nRunning under WOW64 on ", stdout
);
1604 switch (natinfo
.wProcessorArchitecture
)
1606 case PROCESSOR_ARCHITECTURE_IA64
:
1609 case PROCESSOR_ARCHITECTURE_AMD64
:
1618 if (GetSystemMetrics (SM_REMOTESESSION
))
1619 printf ("\nRunning in Terminal Service session\n");
1622 char *s
= getenv ("PATH"), *e
;
1627 char sep
= strchr (s
, ';') ? ';' : ':';
1628 int count_path_items
= 0;
1631 for (e
= s
; *e
&& *e
!= sep
; e
++);
1633 printf ("\t%.*s\n", (int) (e
- s
), s
);
1647 if (!GetSystemDirectory (tmp
, 4000))
1648 display_error ("dump_sysinfo: GetSystemDirectory()");
1649 printf ("\nSysDir: %s\n", tmp
);
1651 GetWindowsDirectory (tmp
, 4000);
1652 printf ("WinDir: %s\n\n", tmp
);
1656 printf ("Here's some environment variables that may affect cygwin:\n");
1657 for (i
= 0; environ
[i
]; i
++)
1659 char *eq
= strchr (environ
[i
], '=');
1662 /* int len = eq - environ[i]; */
1663 for (j
= 0; known_env_vars
[j
]; j
++)
1666 if (strcmp (environ
[i
], "PATH") == 0)
1667 continue; /* we handle this one specially */
1668 if (strcasecmp (environ
[i
], known_env_vars
[j
]) == 0)
1669 printf ("%s = '%s'\n", environ
[i
], eq
+ 1);
1678 printf ("Here's the rest of your environment variables:\n");
1679 for (i
= 0; environ
[i
]; i
++)
1682 char *eq
= strchr (environ
[i
], '=');
1685 /* int len = eq - environ[i]; */
1686 for (j
= 0; known_env_vars
[j
]; j
++)
1689 if (strcasecmp (environ
[i
], known_env_vars
[j
]) == 0)
1696 printf ("%s = '%s'\n", environ
[i
], eq
+ 1);
1706 printf ("Scanning registry for keys with 'Cygwin' in them...\n");
1707 scan_registry (0, HKEY_CURRENT_USER
,
1708 (char *) "HKEY_CURRENT_USER", 0, false);
1709 scan_registry (0, HKEY_LOCAL_MACHINE
,
1710 (char *) "HKEY_LOCAL_MACHINE", 0, false);
1714 printf ("Use '-r' to scan registry\n\n");
1716 if (RegOpenKeyEx (HKEY_LOCAL_MACHINE
,
1717 "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\kernel",
1718 0, KEY_READ
, &key
) == ERROR_SUCCESS
)
1721 RegQueryValueEx (key
, "obcaseinsensitive", NULL
, NULL
,
1722 (LPBYTE
) &obcaseinsensitive
, &size
);
1725 printf ("obcaseinsensitive set to %lu\n\n", obcaseinsensitive
);
1727 print_reg_installations ();
1731 printf ("Listing available drives...\n");
1732 printf ("Drv Type Size Used Flags Name\n");
1735 SetErrorMode (SEM_FAILCRITICALERRORS
| SEM_NOOPENFILEERRORBOX
);
1736 int drivemask
= GetLogicalDrives ();
1738 for (i
= 0; i
< 26; i
++)
1740 if (!(drivemask
& (1 << i
)))
1742 char drive
[4], name
[200], fsname
[200];
1743 DWORD serno
= 0, maxnamelen
= 0, flags
= 0;
1744 name
[0] = fsname
[0] = 0;
1745 sprintf (drive
, "%c:\\", i
+ 'a');
1746 /* Report all errors, except if the Volume is ERROR_NOT_READY.
1747 ERROR_NOT_READY is returned when removeable media drives are empty
1748 (CD, floppy, etc.) */
1749 if (!GetVolumeInformation (drive
, name
, sizeof (name
), &serno
,
1750 &maxnamelen
, &flags
, fsname
,
1752 && GetLastError () != ERROR_NOT_READY
)
1754 # define FMT "dump_sysinfo: GetVolumeInformation() for drive %c:"
1755 char buf
[sizeof (FMT
)];
1756 sprintf (buf
, FMT
, 'A' + i
);
1757 display_error (buf
);
1761 int dtype
= GetDriveType (drive
);
1762 char drive_type
[4] = "unk";
1765 case DRIVE_REMOVABLE
:
1766 strcpy (drive_type
, "fd ");
1769 strcpy (drive_type
, "hd ");
1772 strcpy (drive_type
, "net");
1775 strcpy (drive_type
, "cd ");
1778 strcpy (drive_type
, "ram");
1781 strcpy (drive_type
, "unk");
1784 long capacity_mb
= -1;
1785 int percent_full
= -1;
1787 ULARGE_INTEGER free_me
, free_bytes
, total_bytes
;
1788 free_me
.QuadPart
= free_bytes
.QuadPart
= 0ULL;
1789 total_bytes
.QuadPart
= 1ULL;
1790 if (GetDiskFreeSpaceEx (drive
, &free_me
, &total_bytes
, &free_bytes
))
1792 capacity_mb
= total_bytes
.QuadPart
/ (1024L * 1024L);
1793 percent_full
= 100 - (int) ((100.0 * free_me
.QuadPart
)
1794 / total_bytes
.QuadPart
);
1798 DWORD spc
= 0, bps
= 0, fc
= 0, tc
= 1;
1799 if (GetDiskFreeSpace (drive
, &spc
, &bps
, &fc
, &tc
))
1801 capacity_mb
= (spc
* bps
* tc
) / (1024 * 1024);
1802 percent_full
= 100 - (int) ((100.0 * fc
) / tc
);
1806 printf ("%.2s %s %-6s ", drive
, drive_type
, fsname
);
1807 if (capacity_mb
>= 0)
1808 printf ("%7dMb %3d%% ", (int) capacity_mb
, (int) percent_full
);
1810 printf (" N/A N/A ");
1811 printf ("%s %s %s %s %s %s %s %s\n",
1812 flags
& FS_CASE_IS_PRESERVED
? "CP" : " ",
1813 flags
& FS_CASE_SENSITIVE
? "CS" : " ",
1814 flags
& FS_UNICODE_STORED_ON_DISK
? "UN" : " ",
1815 flags
& FS_PERSISTENT_ACLS
? "PA" : " ",
1816 flags
& FS_FILE_COMPRESSION
? "FC" : " ",
1817 flags
& FS_VOL_IS_COMPRESSED
? "VC" : " ",
1818 flags
& FILE_VOLUME_QUOTAS
? "QU" : " ",
1822 SetErrorMode (prev_mode
);
1826 "fd = floppy, hd = hard drive, cd = CD-ROM\n"
1827 "net= Network Share, ram= RAM drive, unk= Unknown\n"
1828 "CP = Case Preserving, CS = Case Sensitive, UN = Unicode\n"
1829 "PA = Persistent ACLS, FC = File Compression, VC = Volume Compression");
1833 unsigned ml_fsname
= 4, ml_dir
= 7, ml_type
= 6;
1834 bool ml_trailing
= false;
1838 while ((mnt
= getmntent (0)))
1840 unsigned n
= (int) strlen (mnt
->mnt_fsname
);
1841 ml_trailing
|= (n
> 1 && strchr ("\\/", mnt
->mnt_fsname
[n
- 1]));
1844 n
= (int) strlen (mnt
->mnt_dir
);
1845 ml_trailing
|= (n
> 1 && strchr ("\\/", mnt
->mnt_dir
[n
- 1]));
1851 puts ("Warning: Mount entries should not have a trailing (back)slash\n");
1856 ("Mount entries: these map POSIX directories to your NT drives.\n");
1857 printf ("%-*s %-*s %-*s %s\n", ml_fsname
, "-NT-", ml_dir
, "-POSIX-",
1858 ml_type
, "-Type-", "-Flags-");
1862 while ((mnt
= getmntent (0)))
1864 printf ("%-*s %-*s %-*s %s\n",
1865 ml_fsname
, mnt
->mnt_fsname
,
1866 ml_dir
, mnt
->mnt_dir
, ml_type
, mnt
->mnt_type
, mnt
->mnt_opts
);
1872 ("Looking to see where common programs can be found, if at all...\n");
1873 for (i
= 0; common_apps
[i
].name
; i
++)
1874 if (!find_app_on_path ((char *) common_apps
[i
].name
, 1))
1876 if (common_apps
[i
].missing_is_good
)
1877 printf ("Not Found: %s (good!)\n", common_apps
[i
].name
);
1879 printf ("Not Found: %s\n", common_apps
[i
].name
);
1884 printf ("Looking for various Cygwin DLLs... (-v gives version info)\n");
1885 int cygwin_dll_count
= 0;
1886 char cygdll_path
[32768];
1887 for (pathlike
*pth
= paths
; pth
->dir
; pth
++)
1889 WIN32_FIND_DATAW ffinfo
;
1890 sprintf (tmp
, "%s*.*", pth
->dir
);
1891 wide_path
wpath (tmp
);
1892 HANDLE ff
= FindFirstFileW (wpath
, &ffinfo
);
1893 int found
= (ff
!= INVALID_HANDLE_VALUE
);
1894 found_cygwin_dll
= NULL
;
1897 char f
[FILENAME_MAX
+ 1];
1898 wcstombs (f
, ffinfo
.cFileName
, sizeof f
);
1899 if (strcasecmp (f
+ strlen (f
) - 4, ".dll") == 0)
1901 if (strncasecmp (f
, "cyg", 3) == 0)
1903 sprintf (tmp
, "%s%s", pth
->dir
, f
);
1904 if (strcasecmp (f
, "cygwin1.dll") == 0)
1906 if (!cygwin_dll_count
)
1907 strcpy (cygdll_path
, pth
->dir
);
1908 if (!cygwin_dll_count
1909 || strcasecmp (cygdll_path
, pth
->dir
) != 0)
1911 found_cygwin_dll
= strdup (tmp
);
1917 found
= FindNextFileW (ff
, &ffinfo
);
1919 if (found_cygwin_dll
)
1921 ls (found_cygwin_dll
);
1922 free (found_cygwin_dll
);
1927 if (cygwin_dll_count
> 1)
1928 puts ("Warning: There are multiple cygwin1.dlls on your path");
1929 if (!cygwin_dll_count
)
1930 puts ("Warning: cygwin1.dll not found on your path");
1932 dump_dodgy_apps (verbose
);
1935 dump_sysinfo_services ();
1941 HANDLE h
= CreateFileW (L
"CONIN$", GENERIC_READ
| GENERIC_WRITE
,
1942 FILE_SHARE_READ
| FILE_SHARE_WRITE
, NULL
,
1943 OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
1945 if (h
== INVALID_HANDLE_VALUE
|| h
== NULL
)
1946 return (display_error ("check_keys: Opening CONIN$"));
1950 if (!GetConsoleMode (h
, &mode
))
1951 display_error ("check_keys: GetConsoleMode()");
1954 mode
&= ~ENABLE_PROCESSED_INPUT
;
1955 if (!SetConsoleMode (h
, mode
))
1956 display_error ("check_keys: SetConsoleMode()");
1959 fputs ("\nThis key check works only in a console window,", stderr
);
1960 fputs (" _NOT_ in a terminal session!\n", stderr
);
1961 fputs ("Abort with Ctrl+C if in a terminal session.\n\n", stderr
);
1962 fputs ("Press 'q' to exit.\n", stderr
);
1964 INPUT_RECORD in
, prev_in
;
1966 // Drop first <RETURN> key
1967 ReadConsoleInputW (h
, &in
, 1, &mode
);
1969 memset (&in
, 0, sizeof in
);
1974 if (!ReadConsoleInputW (h
, &in
, 1, &mode
))
1975 display_error ("check_keys: ReadConsoleInput()");
1977 if (!memcmp (&in
, &prev_in
, sizeof in
))
1980 switch (in
.EventType
)
1983 printf ("%s %ux VK: 0x%04x VS: 0x%04x C: 0x%04x CTRL: ",
1984 in
.Event
.KeyEvent
.bKeyDown
? "Pressed " : "Released",
1985 in
.Event
.KeyEvent
.wRepeatCount
,
1986 in
.Event
.KeyEvent
.wVirtualKeyCode
,
1987 in
.Event
.KeyEvent
.wVirtualScanCode
,
1988 (unsigned char) in
.Event
.KeyEvent
.uChar
.UnicodeChar
);
1989 fputs (in
.Event
.KeyEvent
.dwControlKeyState
& CAPSLOCK_ON
?
1990 "CL " : "-- ", stdout
);
1991 fputs (in
.Event
.KeyEvent
.dwControlKeyState
& ENHANCED_KEY
?
1992 "EK " : "-- ", stdout
);
1993 fputs (in
.Event
.KeyEvent
.dwControlKeyState
& LEFT_ALT_PRESSED
?
1994 "LA " : "-- ", stdout
);
1995 fputs (in
.Event
.KeyEvent
.dwControlKeyState
& LEFT_CTRL_PRESSED
?
1996 "LC " : "-- ", stdout
);
1997 fputs (in
.Event
.KeyEvent
.dwControlKeyState
& NUMLOCK_ON
?
1998 "NL " : "-- ", stdout
);
1999 fputs (in
.Event
.KeyEvent
.dwControlKeyState
& RIGHT_ALT_PRESSED
?
2000 "RA " : "-- ", stdout
);
2001 fputs (in
.Event
.KeyEvent
.dwControlKeyState
& RIGHT_CTRL_PRESSED
?
2002 "RC " : "-- ", stdout
);
2003 fputs (in
.Event
.KeyEvent
.dwControlKeyState
& SCROLLLOCK_ON
?
2004 "SL " : "-- ", stdout
);
2005 fputs (in
.Event
.KeyEvent
.dwControlKeyState
& SHIFT_PRESSED
?
2006 "SH " : "-- ", stdout
);
2007 fputc ('\n', stdout
);
2014 while (in
.EventType
!= KEY_EVENT
||
2015 in
.Event
.KeyEvent
.bKeyDown
!= FALSE
||
2016 in
.Event
.KeyEvent
.uChar
.UnicodeChar
!= L
'q');
2022 /* These do not need to be escaped in application/x-www-form-urlencoded */
2023 static const char safe_chars
[] = "$-_.!*'(),";
2025 /* the URL to query. */
2026 static const char base_url
[] =
2027 "http://cygwin.com/cgi-bin2/package-grep.cgi?text=1&grep=";
2030 #define ARCH_STR "&arch=x86_64"
2032 #define ARCH_STR "&arch=x86"
2034 static const char *ARCH_str
= ARCH_STR
;
2036 /* Queries Cygwin web site for packages containing files matching a regexp.
2037 Return value is 1 if there was a problem, otherwise 0. */
2039 package_grep (char *search
)
2043 /* construct the actual URL by escaping */
2044 char *url
= (char *) alloca (sizeof (base_url
) + strlen (ARCH_str
)
2045 + strlen (search
) * 3);
2046 strcpy (url
, base_url
);
2049 for (dest
= &url
[sizeof (base_url
) - 1]; *search
; search
++)
2051 if (isalnum (*search
)
2052 || memchr (safe_chars
, *search
, sizeof (safe_chars
) - 1))
2059 sprintf (dest
, "%02x", (unsigned char) *search
);
2063 strcpy (dest
, ARCH_str
);
2065 /* Connect to the net and open the URL. */
2066 if (InternetAttemptConnect (0) != ERROR_SUCCESS
)
2068 fputs ("An internet connection is required for this function.\n", stderr
);
2072 /* Initialize WinInet and attempt to fetch our URL. */
2073 HINTERNET hi
= NULL
, hurl
= NULL
;
2074 if (!(hi
= InternetOpenA ("cygcheck", INTERNET_OPEN_TYPE_PRECONFIG
,
2076 return display_internet_error ("InternetOpen() failed", NULL
);
2078 if (!(hurl
= InternetOpenUrlA (hi
, url
, NULL
, 0, 0, 0)))
2079 return display_internet_error ("unable to contact cygwin.com site, "
2080 "InternetOpenUrl() failed", hi
, NULL
);
2082 /* Check the HTTP response code. */
2083 DWORD rc
= 0, rc_s
= sizeof (DWORD
);
2084 if (!HttpQueryInfoA (hurl
, HTTP_QUERY_STATUS_CODE
| HTTP_QUERY_FLAG_NUMBER
,
2085 (void *) &rc
, &rc_s
, NULL
))
2086 return display_internet_error ("HttpQueryInfo() failed", hurl
, hi
, NULL
);
2088 if (rc
!= HTTP_STATUS_OK
)
2090 sprintf (buf
, "error retrieving results from cygwin.com site, "
2091 "HTTP status code %lu", rc
);
2092 return display_internet_error (buf
, hurl
, hi
, NULL
);
2095 /* Fetch result and print to stdout. */
2099 if (!InternetReadFile (hurl
, (void *) buf
, sizeof (buf
), &numread
))
2100 return display_internet_error ("InternetReadFile failed", hurl
, hi
, NULL
);
2102 fwrite ((void *) buf
, (size_t) numread
, 1, stdout
);
2106 InternetCloseHandle (hurl
);
2107 InternetCloseHandle (hi
);
2111 static void __attribute__ ((__noreturn__
))
2112 usage (FILE * stream
, int status
)
2115 Usage: cygcheck [-v] [-h] PROGRAM\n\
2116 cygcheck -c [-d] [PACKAGE]\n\
2117 cygcheck -s [-r] [-v] [-h]\n\
2119 cygcheck -f FILE [FILE]...\n\
2120 cygcheck -l [PACKAGE]...\n\
2121 cygcheck -p REGEXP\n\
2122 cygcheck --delete-orphaned-installation-keys\n\
2124 List system information, check installed packages, or query package database.\n\
2126 At least one command option or a PROGRAM is required, as shown above.\n\
2128 PROGRAM list library (DLL) dependencies of PROGRAM\n\
2129 -c, --check-setup show installed version of PACKAGE and verify integrity\n\
2130 (or for all installed packages if none specified)\n\
2131 -d, --dump-only just list packages, do not verify (with -c)\n\
2132 -s, --sysinfo produce diagnostic system information (implies -c)\n\
2133 -r, --registry also scan registry for Cygwin settings (with -s)\n\
2134 -k, --keycheck perform a keyboard check session (must be run from a\n\
2135 plain console only, not from a pty/rxvt/xterm)\n\
2136 -f, --find-package find the package to which FILE belongs\n\
2137 -l, --list-package list contents of PACKAGE (or all packages if none given)\n\
2138 -p, --package-query search for REGEXP in the entire cygwin.com package\n\
2139 repository (requires internet connectivity)\n\
2140 --delete-orphaned-installation-keys\n\
2141 Delete installation keys of old, now unused\n\
2142 installations from the registry. Requires the right\n\
2143 to change the registry.\n\
2144 -v, --verbose produce more verbose output\n\
2145 -h, --help annotate output with explanatory comments when given\n\
2146 with another command, otherwise print this help\n\
2147 -V, --version print the version of cygcheck and exit\n\
2149 Note: -c, -f, and -l only report on packages that are currently installed. To\n\
2150 search all official Cygwin packages use -p instead. The -p REGEXP matches\n\
2151 package names, descriptions, and names of files/paths within all packages.\n\
2156 struct option longopts
[] = {
2157 {"check-setup", no_argument
, NULL
, 'c'},
2158 {"dump-only", no_argument
, NULL
, 'd'},
2159 {"sysinfo", no_argument
, NULL
, 's'},
2160 {"registry", no_argument
, NULL
, 'r'},
2161 {"verbose", no_argument
, NULL
, 'v'},
2162 {"keycheck", no_argument
, NULL
, 'k'},
2163 {"find-package", no_argument
, NULL
, 'f'},
2164 {"list-package", no_argument
, NULL
, 'l'},
2165 {"package-query", no_argument
, NULL
, 'p'},
2166 {"delete-orphaned-installation-keys", no_argument
, NULL
, CO_DELETE_KEYS
},
2167 {"help", no_argument
, NULL
, 'h'},
2168 {"version", no_argument
, 0, 'V'},
2169 {0, no_argument
, NULL
, 0}
2172 static char opts
[] = "cdsrvkflphV";
2177 printf ("cygcheck (cygwin) %d.%d.%d\n"
2178 "System Checker for Cygwin\n"
2179 "Copyright (C) 1998 - %s Cygwin Authors\n"
2180 "This is free software; see the source for copying conditions. "
2182 "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR "
2184 CYGWIN_VERSION_DLL_MAJOR
/ 1000,
2185 CYGWIN_VERSION_DLL_MAJOR
% 1000,
2186 CYGWIN_VERSION_DLL_MINOR
,
2187 strrchr (__DATE__
, ' ') + 1);
2193 int n
= 1 + strchr (ev
, '=') - ev
;
2194 char *s
= (char *) malloc (n
+ 1);
2201 uintptr_t (*cygwin_internal
) (int, ...);
2202 WCHAR cygwin_dll_path
[32768];
2206 load_cygwin (int& argc
, char **&argv
)
2210 if (!(h
= LoadLibrary ("cygwin1.dll")))
2212 GetModuleFileNameW (h
, cygwin_dll_path
, 32768);
2213 if ((cygwin_internal
= (uintptr_t (*) (int, ...))
2214 GetProcAddress (h
, "cygwin_internal")))
2216 char **av
= (char **) cygwin_internal (CW_ARGV
);
2217 if (av
&& ((uintptr_t) av
!= (uintptr_t) -1))
2219 /* Copy cygwin's idea of the argument list into this Window
2221 for (argc
= 0; av
[argc
]; argc
++)
2223 argv
= (char **) calloc (argc
+ 1, sizeof (char *));
2224 for (char **argvp
= argv
; *av
; av
++)
2225 *argvp
++ = strdup (*av
);
2229 char **envp
= (char **) cygwin_internal (CW_ENVP
);
2230 if (envp
&& ((uintptr_t) envp
!= (uintptr_t) -1))
2232 /* Store path and revert to this value, otherwise path gets
2233 overwritten by the POSIXy Cygwin variation, which breaks cygcheck.
2234 Another approach would be to use the Cygwin PATH and convert it to
2238 while (*(env
= _environ
))
2240 if (strncmp (*env
, "PATH=", 5) == 0)
2241 path
= strdup (*env
);
2244 for (char **ev
= envp
; *ev
; ev
++)
2245 if (strncmp (*ev
, "PATH=", 5) != 0)
2246 putenv (strdup (*ev
));
2251 /* GDB chokes when the DLL got unloaded and, for some reason, fails to set
2252 any breakpoint after the fact. */
2253 if (!IsDebuggerPresent ())
2258 main (int argc
, char **argv
)
2262 load_cygwin (argc
, argv
);
2264 _setmode (1, _O_BINARY
);
2265 _setmode (2, _O_BINARY
);
2267 /* Need POSIX sorting while parsing args, but don't forget the
2268 user's original environment. */
2269 char *posixly
= getenv ("POSIXLY_CORRECT");
2270 if (posixly
== NULL
)
2271 (void) putenv ("POSIXLY_CORRECT=1");
2272 while ((i
= getopt_long (argc
, argv
, opts
, longopts
, NULL
)) != EOF
)
2305 case CO_DELETE_KEYS
:
2306 del_orphaned_reg
= 1;
2312 fprintf (stderr
, "Try `cygcheck --help' for more information.\n");
2318 if (posixly
== NULL
)
2319 putenv ("POSIXLY_CORRECT=");
2321 if ((argc
== 0) && !sysinfo
&& !keycheck
&& !check_setup
&& !list_package
2322 && !del_orphaned_reg
)
2330 if ((check_setup
|| sysinfo
|| find_package
|| list_package
|| grep_packages
2331 || del_orphaned_reg
)
2335 if ((find_package
|| list_package
|| grep_packages
)
2336 && (check_setup
|| del_orphaned_reg
))
2339 if (dump_only
&& !check_setup
&& !sysinfo
)
2342 if (find_package
+ list_package
+ grep_packages
> 1)
2346 return check_keys ();
2347 if (del_orphaned_reg
)
2348 del_orphaned_reg_installations ();
2350 return package_grep (*argv
);
2354 /* FIXME: Add help for check_setup and {list,find}_package */
2355 if (argc
>= 1 && givehelp
&& !check_setup
&& !find_package
&& !list_package
)
2357 printf("Here is where the OS will find your program%s, and which dlls\n",
2358 argc
> 1 ? "s" : "");
2359 printf ("will be used for it. Use -v to see DLL version info\n");
2366 dump_setup (verbose
, argv
, !dump_only
);
2367 else if (find_package
)
2368 package_find (verbose
, argv
);
2369 else if (list_package
)
2370 package_list (verbose
, argv
);
2372 for (i
= 0; i
< argc
; i
++)
2376 ok
&= cygcheck (argv
[i
]);
2385 dump_setup (verbose
, NULL
, !dump_only
);
2389 puts ("Use -h to see help about each section");
2392 return ok
? EXIT_SUCCESS
: EXIT_FAILURE
;