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