/* cygcheck.cc
- Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Red Hat, Inc.
-
This file is part of Cygwin.
This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
+#define _WIN32_WINNT 0x0a00
#define cygwin_internal cygwin_internal_dontuse
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <ctype.h>
+#include <fcntl.h>
#include <io.h>
#include <windows.h>
#include <wininet.h>
#include "path.h"
+#include "wide_path.h"
#include <getopt.h>
-#include "cygwin/include/sys/cygwin.h"
-#include "cygwin/include/mntent.h"
+#include "../cygwin/include/cygwin/version.h"
+#include "../cygwin/include/sys/cygwin.h"
+#define _NOMNTENT_MACROS
+#include "../cygwin/include/mntent.h"
#undef cygwin_internal
+#include "loadlib.h"
+
+#ifndef max
+#define max __max
+#endif
+#ifndef alloca
#define alloca __builtin_alloca
+#endif
int verbose = 0;
int registry = 0;
int find_package = 0;
int list_package = 0;
int grep_packages = 0;
+int del_orphaned_reg = 0;
+
+static char emptystr[] = "";
#ifdef __GNUC__
typedef long long longlong;
typedef __int64 longlong;
#endif
+/* In dump_setup.cc */
void dump_setup (int, char **, bool);
void package_find (int, char **);
void package_list (int, char **);
-
-static const char version[] = "$Revision$";
+/* In bloda.cc */
+void dump_dodgy_apps (int verbose);
static const char *known_env_vars[] = {
"c_include_path",
{"awk", 0},
{"bash", 0},
{"cat", 0},
+ {"certutil", 0},
+ {"clinfo", 0},
+ {"comp", 0},
+ {"convert", 0},
{"cp", 0},
{"cpp", 1},
{"crontab", 0},
+ {"curl", 0},
+ {"expand", 0},
{"find", 0},
+ {"ftp", 0},
{"gcc", 0},
{"gdb", 0},
{"grep", 0},
+ {"hostname", 0},
{"kill", 0},
+ {"klist", 0},
{"ld", 0},
{"ls", 0},
{"make", 0},
{"mv", 0},
+ {"nslookup", 0},
+ {"patch", 0},
{"perl", 0},
+ {"replace", 0},
{"rm", 0},
{"sed", 0},
- {"ssh", 0},
{"sh", 0},
+ {"shutdown", 0},
+ {"sort", 0},
+ {"ssh", 0},
{"tar", 0},
{"test", 0},
+ {"timeout", 0},
{"vi", 0},
{"vim", 0},
+ {"whoami", 0},
{0, 0}
};
-static int num_paths = 0, max_paths = 0;
-static char **paths = 0;
+/* Options without ASCII single char representation. */
+enum
+{
+ CO_DELETE_KEYS = 0x100,
+};
+
+static int num_paths, max_paths;
+struct pathlike
+{
+ char *dir;
+ bool issys;
+ void check_existence (const char *fn, int showall, int verbose,
+ char* first, const char *ext1 = "",
+ const char *ext2 = "");
+};
+
+pathlike *paths;
+int first_nonsys_path;
void
eprintf (const char *format, ...)
* display_error() is used to report failure modes
*/
static int
-display_error (const char *name, bool show_error = true, bool print_failed = true)
+display_error (const char *name, bool show_error, bool print_failed)
{
+ fprintf (stderr, "cygcheck: %s", name);
if (show_error)
- fprintf (stderr, "cygcheck: %s%s: %lu\n", name,
+ fprintf (stderr, "%s: %lu\n",
print_failed ? " failed" : "", GetLastError ());
else
- fprintf (stderr, "cygcheck: %s%s\n", name,
+ fprintf (stderr, "%s\n",
print_failed ? " failed" : "");
return 1;
}
+static int
+display_error (const char *name)
+{
+ return display_error (name, true, true);
+}
+
+static int
+display_error (const char *fmt, const char *x)
+{
+ char buf[4000];
+ snprintf (buf, sizeof buf, fmt, x);
+ return display_error (buf, false, false);
+}
+
+static int
+display_error_fmt (const char *fmt, ...)
+{
+ char buf[4000];
+ va_list va;
+
+ va_start (va, fmt);
+ vsnprintf (buf, sizeof buf, fmt, va);
+ return display_error (buf, false, false);
+}
+
/* Display a WinInet error message, and close a variable number of handles.
(Passed a list of handles terminated by NULL.) */
static int
if (err)
{
if (FormatMessage (FORMAT_MESSAGE_FROM_HMODULE,
- GetModuleHandle ("wininet.dll"), err, 0, err_buf,
- sizeof (err_buf), NULL) == 0)
- strcpy (err_buf, "(Unknown error)");
+ GetModuleHandle ("wininet.dll"), err, 0, err_buf,
+ sizeof (err_buf), NULL) == 0)
+ strcpy (err_buf, "(Unknown error)");
- fprintf (stderr, "cygcheck: %s: %s (win32 error %d)\n", message,
- err_buf, err);
+ fprintf (stderr, "cygcheck: %s: %s (win32 error %lu)\n", message,
+ err_buf, err);
}
else
fprintf (stderr, "cygcheck: %s\n", message);
}
static void
-add_path (char *s, int maxlen)
+add_path (char *s, int maxlen, bool issys)
{
if (num_paths >= max_paths)
{
max_paths += 10;
- if (paths)
- paths = (char **) realloc (paths, max_paths * sizeof (char *));
- else
- paths = (char **) malloc (max_paths * sizeof (char *));
+ /* Extend path array */
+ paths = (pathlike *) realloc (paths, (1 + max_paths) * sizeof (paths[0]));
}
- paths[num_paths] = (char *) malloc (maxlen + 1);
- if (paths[num_paths] == NULL)
+
+ pathlike *pth = paths + num_paths;
+
+ /* Allocate space for directory in path list */
+ char *dir = (char *) calloc (maxlen + 2, sizeof (char));
+ if (dir == NULL)
{
- display_error ("add_path: malloc()");
+ display_error ("add_path: calloc() failed");
return;
}
- memcpy (paths[num_paths], s, maxlen);
- paths[num_paths][maxlen] = 0;
- char *e = paths[num_paths] + strlen (paths[num_paths]);
- if (e[-1] == '\\' && e[-2] != ':')
- *--e = 0;
- for (int i = 1; i < num_paths; i++)
- if (strcasecmp (paths[num_paths], paths[i]) == 0)
- {
- free (paths[num_paths]);
- return;
- }
+
+ /* Copy input directory to path list */
+ memcpy (dir, s, maxlen);
+
+ /* Add a trailing slash by default */
+ char *e = strchr (dir, '\0');
+ if (e != dir && e[-1] != '\\')
+ strcpy (e, "\\");
+
+ /* Fill out this element */
+ pth->dir = dir;
+ pth->issys = issys;
+ pth[1].dir = NULL;
num_paths++;
}
init_paths ()
{
char tmp[4000], *sl;
- add_path ((char *) ".", 1); /* to be replaced later */
+ add_path ((char *) ".", 1, true); /* to be replaced later */
if (GetCurrentDirectory (4000, tmp))
- add_path (tmp, strlen (tmp));
+ add_path (tmp, strlen (tmp), true);
else
display_error ("init_paths: GetCurrentDirectory()");
if (GetSystemDirectory (tmp, 4000))
- add_path (tmp, strlen (tmp));
+ add_path (tmp, strlen (tmp), true);
else
display_error ("init_paths: GetSystemDirectory()");
sl = strrchr (tmp, '\\');
if (sl)
{
strcpy (sl, "\\SYSTEM");
- add_path (tmp, strlen (tmp));
+ add_path (tmp, strlen (tmp), true);
}
GetWindowsDirectory (tmp, 4000);
- add_path (tmp, strlen (tmp));
+ add_path (tmp, strlen (tmp), true);
char *wpath = getenv ("PATH");
- if (wpath)
+ if (!wpath)
+ display_error ("WARNING: PATH is not set\n", "");
+ else
{
char *b, *e;
b = wpath;
while (1)
{
- for (e = b; *e && *e != ';'; e++);
- if (strncmp(b, ".", 1) && strncmp(b, ".\\", 2))
- add_path (b, e - b);
+ for (e = b; *e && *e != ';'; e++)
+ continue; /* loop terminates at first ';' or EOS */
+ if (strncmp(b, ".\\", 2) != 0)
+ add_path (b, e - b, false);
if (!*e)
break;
b = e + 1;
}
}
- else
- printf ("WARNING: PATH is not set at all!\n");
}
-static char *
-find_on_path (char *file, char *default_extension,
- int showall = 0, int search_sysdirs = 0)
+#define LINK_EXTENSION ".lnk"
+
+void
+pathlike::check_existence (const char *fn, int showall, int verbose,
+ char* first, const char *ext1, const char *ext2)
+{
+ char file[4000];
+ snprintf (file, sizeof file, "%s%s%s%s", dir, fn, ext1, ext2);
+
+ wide_path wpath (file);
+ if (GetFileAttributesW (wpath) != (DWORD) - 1)
+ {
+ char *lastdot = strrchr (file, '.');
+ bool is_link = lastdot && !strcmp (lastdot, LINK_EXTENSION);
+ // If file is a link, fix up the extension before printing
+ if (is_link)
+ *lastdot = '\0';
+ if (showall)
+ printf ("Found: %s\n", file);
+ if (verbose && *first != '\0' && strcasecmp (first, file) != 0)
+ {
+ char *flastdot = strrchr (first, '.');
+ bool f_is_link = flastdot && !strcmp (flastdot, LINK_EXTENSION);
+ // if first is a link, fix up the extension before printing
+ if (f_is_link)
+ *flastdot = '\0';
+ printf ("Warning: %s hides %s\n", first, file);
+ if (f_is_link)
+ *flastdot = '.';
+ }
+ if (is_link)
+ *lastdot = '.';
+ if (!*first)
+ strcpy (first, file);
+ }
+}
+
+static const char *
+find_on_path (const char *in_file, const char *ext, bool showall = false,
+ bool search_sys = false, bool checklinks = false)
{
static char rv[4000];
- char tmp[4000], *ptr = rv;
- if (!file)
+ /* Sort of a kludge but we've already tested this once, so don't try it
+ again */
+ if (in_file == rv)
+ return in_file;
+
+ static pathlike abspath[2] =
+ {
+ {emptystr, 0},
+ {NULL, 0}
+ };
+
+ *rv = '\0';
+ if (!in_file)
{
- display_error ("find_on_path: NULL pointer for file", false, false);
+ display_error ("internal error find_on_path: NULL pointer for file",
+ false, false);
return 0;
}
- if (default_extension == NULL)
+ if (!ext)
{
- display_error ("find_on_path: NULL pointer for default_extension", false, false);
+ display_error ("internal error find_on_path: "
+ "NULL pointer for default_extension", false, false);
return 0;
}
- if (strchr (file, ':') || strchr (file, '\\') || strchr (file, '/'))
+ const char *file;
+ pathlike *search_paths;
+ if (!strpbrk (in_file, ":/\\"))
{
- char *fn = cygpath (file, NULL);
- if (access (fn, F_OK) == 0)
- return fn;
- strcpy (rv, fn);
- strcat (rv, default_extension);
- return access (rv, F_OK) == 0 ? rv : fn;
+ file = in_file;
+ search_paths = paths;
+ }
+ else
+ {
+ file = cygpath (in_file, NULL);
+ search_paths = abspath;
+ showall = false;
}
- if (strchr (file, '.'))
- default_extension = (char *) "";
-
- for (int i = 0; i < num_paths; i++)
+ if (!file)
{
- if (!search_sysdirs && (i == 0 || i == 2 || i == 3))
- continue;
- if (i == 0 || !search_sysdirs || strcasecmp (paths[i], paths[0]))
- {
- sprintf (ptr, "%s\\%s%s", paths[i], file, default_extension);
- if (GetFileAttributes (ptr) != (DWORD) - 1)
- {
- if (showall)
- printf ("Found: %s\n", ptr);
- if (ptr == tmp && verbose)
- printf ("Warning: %s hides %s\n", rv, ptr);
- ptr = tmp;
- }
- }
+ display_error ("internal error find_on_path: "
+ "cygpath conversion failed for %s\n", in_file);
+ return 0;
}
- if (ptr == tmp)
- return rv;
+ char *hasext = strrchr (file, '.');
+ if (hasext && !strpbrk (hasext, "/\\"))
+ ext = "";
- return 0;
+ for (pathlike *pth = search_paths; pth->dir; pth++)
+ if (!pth->issys || search_sys)
+ {
+ pth->check_existence (file, showall, verbose, rv, ext);
+
+ if (checklinks)
+ pth->check_existence (file, showall, verbose, rv, ext,
+ LINK_EXTENSION);
+
+ if (!*ext)
+ continue;
+
+ pth->check_existence (file, showall, verbose, rv);
+ if (checklinks)
+ pth->check_existence (file, showall, verbose, rv, LINK_EXTENSION);
+ }
+
+ return *rv ? rv : NULL;
}
#define DID_NEW 1
static Did *did = 0;
static Did *
-already_did (char *file)
+already_did (const char *file)
{
Did *d;
for (d = did; d; d = d->next)
return d;
}
-static int
-get_word (HANDLE fh, int offset)
-{
- short rv;
- unsigned r;
-
- if (SetFilePointer (fh, offset, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER
- && GetLastError () != NO_ERROR)
- display_error ("get_word: SetFilePointer()");
-
- if (!ReadFile (fh, &rv, 2, (DWORD *) &r, 0))
- display_error ("get_word: Readfile()");
-
- return rv;
-}
-
-static int
-get_dword (HANDLE fh, int offset)
-{
- int rv;
- unsigned r;
-
- if (SetFilePointer (fh, offset, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER
- && GetLastError () != NO_ERROR)
- display_error ("get_dword: SetFilePointer()");
-
- if (!ReadFile (fh, &rv, 4, (DWORD *) &r, 0))
- display_error ("get_dword: Readfile()");
-
- return rv;
-}
-
struct Section
{
char name[8];
unsigned iat_rva;
};
-
-static bool track_down (char *file, char *suffix, int lvl);
+static bool track_down (const char *file, const char *suffix, int lvl);
#define CYGPREFIX (sizeof ("%%% Cygwin ") - 1)
static void
{
DWORD junk;
int i;
+ if (is_symlink (fh))
+ {
+ if (!verbose)
+ puts ("");
+ else
+ {
+ char buf[PATH_MAX + 1] = "";
+ readlink (fh, buf, sizeof(buf) - 1);
+ printf (" (symlink to %s)\n", buf);
+ }
+ return;
+ }
int pe_header_offset = get_dword (fh, 0x3c);
+ if (GetLastError () != NO_ERROR)
+ display_error ("get_dword");
+ WORD arch = get_word (fh, pe_header_offset + 4);
+ if (GetLastError () != NO_ERROR)
+ display_error ("get_word");
+#ifdef __x86_64__
+ if (arch != IMAGE_FILE_MACHINE_AMD64)
+ {
+ puts (verbose ? " (not x86_64 dll)" : "\n");
+ return;
+ }
+ int base_off = 108;
+#else
+ if (arch != IMAGE_FILE_MACHINE_I386)
+ {
+ puts (verbose ? " (not x86 dll)" : "\n");
+ return;
+ }
+ int base_off = 92;
+#endif
int opthdr_ofs = pe_header_offset + 4 + 20;
unsigned short v[6];
else
printf ("\n");
- int num_entries = get_dword (fh, opthdr_ofs + 92);
- int export_rva = get_dword (fh, opthdr_ofs + 96);
- int export_size = get_dword (fh, opthdr_ofs + 100);
- int import_rva = get_dword (fh, opthdr_ofs + 104);
- int import_size = get_dword (fh, opthdr_ofs + 108);
+ int num_entries = get_dword (fh, opthdr_ofs + base_off + 0);
+ if (GetLastError () != NO_ERROR)
+ display_error ("get_dword");
+ int export_rva = get_dword (fh, opthdr_ofs + base_off + 4);
+ if (GetLastError () != NO_ERROR)
+ display_error ("get_dword");
+ int export_size = get_dword (fh, opthdr_ofs + base_off + 8);
+ if (GetLastError () != NO_ERROR)
+ display_error ("get_dword");
+ int import_rva = get_dword (fh, opthdr_ofs + base_off + 12);
+ if (GetLastError () != NO_ERROR)
+ display_error ("get_dword");
+ int import_size = get_dword (fh, opthdr_ofs + base_off + 16);
+ if (GetLastError () != NO_ERROR)
+ display_error ("get_dword");
int nsections = get_word (fh, pe_header_offset + 4 + 2);
+ if (nsections == -1)
+ display_error ("get_word");
char *sections = (char *) malloc (nsections * 40);
if (SetFilePointer (fh, pe_header_offset + 4 + 20 +
ExpDirectory *ed = (ExpDirectory *) exp;
int ofs = ed->name_rva - export_rva;
- struct tm *tm = localtime ((const time_t *) &(ed->timestamp));
- if (tm->tm_year < 60)
+ time_t ts = ed->timestamp; /* timestamp is only 4 bytes! */
+ struct tm *tm = localtime (&ts);
+ if (tm && tm->tm_year < 60)
tm->tm_year += 2000;
- if (tm->tm_year < 200)
+ if (tm && tm->tm_year < 200)
tm->tm_year += 1900;
printf ("%*c", lvl + 2, ' ');
- printf ("\"%s\" v%d.%d ts=", exp + ofs,
+ printf ("\"%s\" v%d.%d", exp + ofs,
ed->major_ver, ed->minor_ver);
- printf ("%d/%d/%d %d:%02d\n",
- tm->tm_year, tm->tm_mon + 1, tm->tm_mday,
- tm->tm_hour, tm->tm_min);
+ if (tm)
+ printf (" ts=%04d-%02d-%02d %02d:%02d",
+ tm->tm_year, tm->tm_mon + 1, tm->tm_mday,
+ tm->tm_hour, tm->tm_min);
+ putchar ('\n');
}
}
// Return true on success, false if error printed
static bool
-track_down (char *file, char *suffix, int lvl)
+track_down (const char *file, const char *suffix, int lvl)
{
if (file == NULL)
{
return false;
}
- char *path = find_on_path (file, suffix, 0, 1);
+ const char *path = find_on_path (file, suffix, false, true);
if (!path)
{
- printf ("Error: could not find %s\n", file);
+ /* The api-ms-win-*.dll files are in system32/downlevel and not in the
+ DLL search path, so find_on_path doesn't find them. Since they are
+ never actually linked against by the executables, they are of no
+ interest to us. Skip any error message in not finding them. */
+ if (strncasecmp (file, "api-ms-win-", 11) || strcasecmp (suffix, ".dll"))
+ display_error ("track_down: could not find %s\n", file);
return false;
}
if (lvl)
printf ("%*c", lvl, ' ');
- if (!path)
- {
- printf ("%s not found\n", file);
- return false;
- }
-
printf ("%s", path);
+ wide_path wpath (path);
HANDLE fh =
- CreateFile (path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
- NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ CreateFileW (wpath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (fh == INVALID_HANDLE_VALUE)
{
- printf (" - Cannot open\n");
+ display_error ("cannot open - '%s'\n", path);
return false;
}
d->state = DID_ACTIVE;
- dll_info (path, fh, lvl, 1);
+ if (is_exe (fh))
+ dll_info (path, fh, lvl, 1);
+ else if (is_symlink (fh))
+ display_error ("%s is a symlink instead of a DLL\n", path);
+ else
+ {
+ int magic = get_word (fh, 0x0);
+ if (magic == -1)
+ display_error ("get_word");
+ magic &= 0x00FFFFFF;
+ display_error_fmt ("%s is not a DLL: magic number %x (%d) '%s'\n",
+ path, magic, magic, (char *)&magic);
+ }
+
d->state = DID_INACTIVE;
if (!CloseHandle (fh))
display_error ("track_down: CloseHandle()");
static void
ls (char *f)
{
- HANDLE h = CreateFile (f, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
- 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
+ wide_path wpath (f);
+ HANDLE h = CreateFileW (wpath, GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
BY_HANDLE_FILE_INFORMATION info;
if (!GetFileInformationByHandle (h, &info))
display_error ("ls: CloseHandle()");
}
+/* Remove filename from 's' and return directory name without trailing
+ backslash, or NULL if 's' doesn't seem to have a dirname. */
+static char *
+dirname (const char *s)
+{
+ static char buf[PATH_MAX];
+
+ if (!s)
+ return NULL;
+
+ strncpy (buf, s, PATH_MAX);
+ buf[PATH_MAX - 1] = '\0'; // in case strlen(s) > PATH_MAX
+ char *lastsep = strrchr (buf, '\\');
+ if (!lastsep)
+ return NULL; // no backslash -> no dirname
+ else if (lastsep - buf <= 2 && buf[1] == ':')
+ lastsep[1] = '\0'; // can't remove backslash of "x:\"
+ else
+ *lastsep = '\0';
+ return buf;
+}
+
+// Find a real application on the path (possibly following symlinks)
+static const char *
+find_app_on_path (const char *app, bool showall = false)
+{
+ const char *papp = find_on_path (app, ".exe", showall, false, true);
+
+ if (!papp)
+ return NULL;
+
+ wide_path wpath (papp);
+ HANDLE fh =
+ CreateFileW (wpath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (fh == INVALID_HANDLE_VALUE)
+ return NULL;
+
+ if (is_symlink (fh))
+ {
+ static char tmp[SYMLINK_MAX + 1];
+ if (!readlink (fh, tmp, SYMLINK_MAX))
+ display_error("readlink failed");
+
+ /* Resolve the linkname relative to the directory of the link. */
+ char *ptr = cygpath_rel (dirname (papp), tmp, NULL);
+ printf (" -> %s\n", ptr);
+ if (!strchr (ptr, '\\'))
+ {
+ char *lastsep;
+ strncpy (tmp, cygpath (papp, NULL), SYMLINK_MAX);
+ lastsep = strrchr (tmp, '\\');
+ strncpy (lastsep+1, ptr, SYMLINK_MAX - (lastsep-tmp));
+ ptr = tmp;
+ }
+ if (!CloseHandle (fh))
+ display_error ("find_app_on_path: CloseHandle()");
+ /* FIXME: We leak the ptr returned by cygpath() here which is a
+ malloc()d string. */
+ return find_app_on_path (ptr, showall);
+ }
+
+ if (!CloseHandle (fh))
+ display_error ("find_app_on_path: CloseHandle()");
+ return papp;
+}
+
// Return true on success, false if error printed
static bool
-cygcheck (char *app)
+cygcheck (const char *app)
{
- char *papp = find_on_path (app, (char *) ".exe", 1, 0);
+ const char *papp = find_app_on_path (app, 1);
if (!papp)
{
- printf ("Error: could not find %s\n", app);
+ display_error ("could not find '%s'\n", app);
return false;
}
- char *s = strdup (papp);
- char *sl = 0, *t;
- for (t = s; *t; t++)
- if (*t == '/' || *t == '\\' || *t == ':')
- sl = t;
- if (sl == 0)
- paths[0] = (char *) ".";
+
+ char *s;
+ char *sep = strpbrk (papp, ":/\\");
+ if (!sep)
+ {
+ static char dot[] = ".";
+ s = dot;
+ }
else
{
- *sl = 0;
- paths[0] = s;
+ int n = sep - papp;
+ s = (char *) malloc (n + 2);
+ memcpy ((char *) s, papp, n);
+ strcpy (s + n, "\\");
}
- did = 0;
- return track_down (papp, (char *) ".exe", 0);
-}
-
-extern char **environ;
+ paths[0].dir = s;
+ did = NULL;
+ return track_down (papp, ".exe", 0);
+}
struct RegInfo
{
}
static void
-scan_registry (RegInfo * prev, HKEY hKey, char *name, int cygnus)
+scan_registry (RegInfo * prev, HKEY hKey, char *name, int cygwin, bool wow64)
{
RegInfo ri;
ri.prev = prev;
char *cp;
for (cp = name; *cp; cp++)
- if (strncasecmp (cp, "cygnus", 6) == 0)
- cygnus = 1;
+ if (strncasecmp (cp, "Cygwin", 6) == 0)
+ cygwin = 1;
DWORD num_subkeys, max_subkey_len, num_values;
DWORD max_value_len, max_valdata_len, i;
return;
}
- if (cygnus)
+ if (cygwin)
{
show_reg (&ri, 0);
ERROR_SUCCESS)
{
HKEY sKey;
+ /* Don't recurse more than one level into the WOW64 subkey since
+ that would lead to an endless recursion. */
+ if (!strcasecmp (subkey_name, "Wow6432Node"))
+ {
+ if (wow64)
+ continue;
+ wow64 = true;
+ }
if (RegOpenKeyEx (hKey, subkey_name, 0, KEY_READ, &sKey)
== ERROR_SUCCESS)
{
- scan_registry (&ri, sKey, subkey_name, cygnus);
+ scan_registry (&ri, sKey, subkey_name, cygwin, wow64);
if (RegCloseKey (sKey) != ERROR_SUCCESS)
display_error ("scan_registry: RegCloseKey()");
}
}
void
-pretty_id (const char *s, char *cygwin, size_t cyglen)
+pretty_id ()
{
char *groups[16384];
- strcpy (cygwin + cyglen++, " ");
- strcpy (cygwin + cyglen, s);
- putenv (cygwin);
-
char *id = cygpath ("/bin/id.exe", NULL);
for (char *p = id; (p = strchr (p, '/')); p++)
*p = '\\';
return;
}
- FILE *f = popen (id, "rt");
-
char buf[16384];
+ snprintf (buf, sizeof (buf), "\"%s\"", id);
+ FILE *f = popen (buf, "rt");
+
buf[0] = '\0';
fgets (buf, sizeof (buf), f);
pclose (f);
}
ng--;
- printf ("\nOutput from %s (%s)\n", id, s);
+ printf ("\nOutput from %s\n", id);
int n = 80 / (int) ++sz;
int i = n > 2 ? n - 2 : 0;
sz = -sz;
for (char **g = groups; g <= ng; g++)
if ((g != ng) && (++i < n))
- printf ("%*s", sz, *g);
+ printf ("%*s", (int) sz, *g);
else
{
puts (*g);
}
/* check for a recent cygrunsrv */
- snprintf (buf, sizeof (buf), "%s --version", cygrunsrv);
+ snprintf (buf, sizeof (buf), "\"%s\" --version", cygrunsrv);
if ((f = popen (buf, "rt")) == NULL)
{
printf ("Failed to execute '%s', skipping services check.\n", buf);
int ret = fscanf (f, "cygrunsrv V%u.%u", &maj, &min);
if (ferror (f) || feof (f) || ret == EOF || maj < 1 || min < 10)
{
- puts ("The version of cygrunsrv installed is too old to dump service info.\n");
+ puts ("The version of cygrunsrv installed is too old to dump "
+ "service info.\n");
return;
}
- fclose (f);
+ pclose (f);
/* For verbose mode, just run cygrunsrv --list --verbose and copy output
verbatim; otherwise run cygrunsrv --list and then cygrunsrv --query for
each service. */
- snprintf (buf, sizeof (buf), (verbose ? "%s --list --verbose" : "%s --list"),
+ snprintf (buf, sizeof (buf),
+ (verbose ? "\"%s\" --list --verbose" : "\"%s\" --list"),
cygrunsrv);
if ((f = popen (buf, "rt")) == NULL)
{
if (nchars > 0)
for (char *srv = strtok (buf, "\n"); srv; srv = strtok (NULL, "\n"))
{
- snprintf (buf2, sizeof (buf2), "%s --query %s", cygrunsrv, srv);
+ snprintf (buf2, sizeof (buf2), "\"%s\" --query %s", cygrunsrv, srv);
if ((f = popen (buf2, "rt")) == NULL)
{
- printf ("Failed to execute '%s', skipping services check.\n", buf2);
+ printf ("Failed to execute '%s', skipping services check.\n",
+ buf2);
return;
}
puts ("No Cygwin services found.\n");
}
+enum handle_reg_t
+{
+ PRINT_KEY,
+ DELETE_KEY
+};
+
+void
+handle_reg_installation (handle_reg_t what)
+{
+ HKEY key;
+
+ if (what == PRINT_KEY)
+ printf ("Cygwin installations found in the registry:\n");
+ for (int i = 0; i < 2; ++i)
+ if (RegOpenKeyEx (i ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE,
+ "SOFTWARE\\Cygwin\\Installations", 0,
+ what == DELETE_KEY ? KEY_READ | KEY_WRITE : KEY_READ,
+ &key)
+ == ERROR_SUCCESS)
+ {
+ char name[32], data[PATH_MAX];
+ DWORD nsize, dsize, type;
+ LONG ret;
+
+ for (DWORD index = 0;
+ (ret = RegEnumValue (key, index, name, (nsize = 32, &nsize), 0,
+ &type, (PBYTE) data,
+ (dsize = PATH_MAX, &dsize)))
+ != ERROR_NO_MORE_ITEMS; ++index)
+ if (ret == ERROR_SUCCESS && dsize > 5)
+ {
+ char *path = data + 4;
+ if (path[1] != ':')
+ *(path += 2) = '\\';
+ if (what == PRINT_KEY)
+ printf (" %s Key: %s Path: %s", i ? "User: " : "System:",
+ name, path);
+ strcat (path, "\\bin\\cygwin1.dll");
+ if (what == PRINT_KEY)
+ printf ("%s\n", access (path, F_OK) ? " (ORPHANED)" : "");
+ else if (access (path, F_OK))
+ {
+ RegDeleteValue (key, name);
+ /* Start over since index is not reliable anymore. */
+ --i;
+ break;
+ }
+ }
+ RegCloseKey (key);
+ }
+ if (what == PRINT_KEY)
+ printf ("\n");
+}
+
+void
+print_reg_installations ()
+{
+ handle_reg_installation (PRINT_KEY);
+}
+
+void
+del_orphaned_reg_installations ()
+{
+ handle_reg_installation (DELETE_KEY);
+}
+
+/* Unfortunately neither mingw nor Windows know this function. */
+char *
+memmem (char *haystack, size_t haystacklen,
+ const char *needle, size_t needlelen)
+{
+ if (needlelen == 0)
+ return haystack;
+ while (needlelen <= haystacklen)
+ {
+ if (!memcmp (haystack, needle, needlelen))
+ return haystack;
+ haystack++;
+ haystacklen--;
+ }
+ return NULL;
+}
+
+extern "C" NTSTATUS NTAPI RtlGetVersion (PRTL_OSVERSIONINFOEXW);
+
static void
dump_sysinfo ()
{
time_t now;
char *found_cygwin_dll;
bool is_nt = false;
+ char osname[128];
+ DWORD obcaseinsensitive = 1;
+ HKEY key;
+
+ /* MSVCRT popen (called by pretty_id and dump_sysinfo_services) SEGVs if
+ COMSPEC isn't set correctly. Simply enforce it here. Using
+ Get/SetEnvironmentVariable to set the dir does *not* help, btw.
+ Apparently MSVCRT keeps its own copy of the environment and changing
+ that requires to use _wputenv. */
+ if (!_wgetenv (L"COMSPEC"))
+ {
+ WCHAR comspec[MAX_PATH + 17];
+ wcscpy (comspec, L"COMSPEC=");
+ GetSystemDirectoryW (comspec + 8, MAX_PATH);
+ wcsncat (comspec, L"\\cmd.exe", sizeof comspec);
+ _wputenv (comspec);
+ }
printf ("\nCygwin Configuration Diagnostics\n");
time (&now);
printf ("Current System Time: %s\n", ctime (&now));
- OSVERSIONINFO osversion;
- osversion.dwOSVersionInfoSize = sizeof (osversion);
- if (!GetVersionEx (&osversion))
- display_error ("dump_sysinfo: GetVersionEx()");
- const char *osname = "unknown OS";
+ RTL_OSVERSIONINFOEXW osversion;
+ osversion.dwOSVersionInfoSize = sizeof (RTL_OSVERSIONINFOEXW);
+ RtlGetVersion (&osversion);
+
switch (osversion.dwPlatformId)
{
- case VER_PLATFORM_WIN32s:
- osname = "32s";
- break;
- case VER_PLATFORM_WIN32_WINDOWS:
- switch (osversion.dwMinorVersion)
- {
- case 0:
- if (strchr (osversion.szCSDVersion, 'C'))
- osname = "95 OSR2";
- else
- osname = "95";
- break;
- case 10:
- if (strchr (osversion.szCSDVersion, 'A'))
- osname = "98 SE";
- else
- osname = "98";
- break;
- case 90:
- osname = "ME";
- break;
- default:
- osname = "9X";
- break;
- }
- break;
case VER_PLATFORM_WIN32_NT:
is_nt = true;
- if (osversion.dwMajorVersion == 6)
- osname = "Longhorn/Vista (not yet supported!)";
- else if (osversion.dwMajorVersion == 5)
+ if (osversion.dwMajorVersion >= 6)
{
- BOOL more_info = FALSE;
- OSVERSIONINFOEX osversionex;
- osversionex.dwOSVersionInfoSize = sizeof (osversionex);
- if (GetVersionEx ((OSVERSIONINFO *) &osversionex))
- more_info = TRUE;
- if (osversion.dwMinorVersion == 0)
+ HMODULE k32 = GetModuleHandleW (L"kernel32.dll");
+ BOOL (WINAPI *GetProductInfo) (DWORD, DWORD, DWORD, DWORD, PDWORD) =
+ (BOOL (WINAPI *)(DWORD, DWORD, DWORD, DWORD, PDWORD))
+ GetProcAddress (k32, "GetProductInfo");
+ if (osversion.dwMajorVersion == 6)
+ switch (osversion.dwMinorVersion)
+ {
+ case 0:
+ strcpy (osname, osversion.wProductType == VER_NT_WORKSTATION
+ ? "Vista" : "2008");
+ break;
+ case 1:
+ strcpy (osname, osversion.wProductType == VER_NT_WORKSTATION
+ ? "7" : "2008 R2");
+ break;
+ case 2:
+ strcpy (osname, osversion.wProductType == VER_NT_WORKSTATION
+ ? "8" : "2012");
+ break;
+ case 3:
+ strcpy (osname, osversion.wProductType == VER_NT_WORKSTATION
+ ? "8.1" : "2012 R2");
+ break;
+ case 4:
+ default:
+ strcpy (osname, osversion.wProductType == VER_NT_WORKSTATION
+ ? "10 Preview" : "2016 Preview");
+ break;
+ }
+ else if (osversion.dwMajorVersion == 10)
{
- if (!more_info)
- osname = "2000";
- else if (osversionex.wProductType == VER_NT_SERVER
- || osversionex.wProductType == VER_NT_DOMAIN_CONTROLLER)
- {
- if (osversionex.wSuiteMask & VER_SUITE_DATACENTER)
- osname = "2000 Datacenter Server";
- else if (osversionex.wSuiteMask & VER_SUITE_ENTERPRISE)
- osname = "2000 Advanced Server";
- else
- osname = "2000 Server";
- }
- else
- osname = "2000 Professional";
+ strcpy (osname, osversion.wProductType == VER_NT_WORKSTATION
+ ? "10" : "2016");
}
- else if (osversion.dwMinorVersion == 1)
+ DWORD prod;
+ if (GetProductInfo (osversion.dwMajorVersion,
+ osversion.dwMinorVersion,
+ osversion.wServicePackMajor,
+ osversion.wServicePackMinor,
+ &prod))
{
- if (GetSystemMetrics (SM_MEDIACENTER))
- osname = "XP Media Center Edition";
- else if (GetSystemMetrics (SM_TABLETPC))
- osname = "XP Tablet PC Edition";
- else if (!more_info)
- osname = "XP";
- else if (osversionex.wSuiteMask & VER_SUITE_PERSONAL)
- osname = "XP Home Edition";
+ const char *products[] =
+ {
+ /* 0x00000000 */ "",
+ /* 0x00000001 */ " Ultimate",
+ /* 0x00000002 */ " Home Basic",
+ /* 0x00000003 */ " Home Premium",
+ /* 0x00000004 */ " Enterprise",
+ /* 0x00000005 */ " Home Basic N",
+ /* 0x00000006 */ " Business",
+ /* 0x00000007 */ " Server Standard",
+ /* 0x00000008 */ " Server Datacenter",
+ /* 0x00000009 */ " Small Business Server",
+ /* 0x0000000a */ " Server Enterprise",
+ /* 0x0000000b */ " Starter",
+ /* 0x0000000c */ " Server Datacenter Core",
+ /* 0x0000000d */ " Server Standard Core",
+ /* 0x0000000e */ " Server Enterprise Core",
+ /* 0x0000000f */ " Server Enterprise for Itanium-based Systems",
+ /* 0x00000010 */ " Business N",
+ /* 0x00000011 */ " Web Server",
+ /* 0x00000012 */ " HPC Edition",
+ /* 0x00000013 */ " Home Server",
+ /* 0x00000014 */ " Storage Server Express",
+ /* 0x00000015 */ " Storage Server Standard",
+ /* 0x00000016 */ " Storage Server Workgroup",
+ /* 0x00000017 */ " Storage Server Enterprise",
+ /* 0x00000018 */ " for Windows Essential Server Solutions",
+ /* 0x00000019 */ " Small Business Server Premium",
+ /* 0x0000001a */ " Home Premium N",
+ /* 0x0000001b */ " Enterprise N",
+ /* 0x0000001c */ " Ultimate N",
+ /* 0x0000001d */ " Web Server Core",
+ /* 0x0000001e */ " Essential Business Server Management Server",
+ /* 0x0000001f */ " Essential Business Server Security Server",
+ /* 0x00000020 */ " Essential Business Server Messaging Server",
+ /* 0x00000021 */ " Server Foundation",
+ /* 0x00000022 */ " Home Server 2011",
+ /* 0x00000023 */ " without Hyper-V for Windows Essential Server Solutions",
+ /* 0x00000024 */ " Server Standard without Hyper-V",
+ /* 0x00000025 */ " Server Datacenter without Hyper-V",
+ /* 0x00000026 */ " Server Enterprise without Hyper-V",
+ /* 0x00000027 */ " Server Datacenter Core without Hyper-V",
+ /* 0x00000028 */ " Server Standard Core without Hyper-V",
+ /* 0x00000029 */ " Server Enterprise Core without Hyper-V",
+ /* 0x0000002a */ " Hyper-V Server",
+ /* 0x0000002b */ " Storage Server Express Core",
+ /* 0x0000002c */ " Storage Server Standard Core",
+ /* 0x0000002d */ " Storage Server Workgroup Core",
+ /* 0x0000002e */ " Storage Server Enterprise Core",
+ /* 0x0000002f */ " Starter N",
+ /* 0x00000030 */ " Professional",
+ /* 0x00000031 */ " Professional N",
+ /* 0x00000032 */ " Small Business Server 2011 Essentials",
+ /* 0x00000033 */ " Server For SB Solutions",
+ /* 0x00000034 */ " Server Solutions Premium",
+ /* 0x00000035 */ " Server Solutions Premium Core",
+ /* 0x00000036 */ " Server For SB Solutions EM", /* per MSDN, 2012-09-01 */
+ /* 0x00000037 */ " Server For SB Solutions EM", /* per MSDN, 2012-09-01 */
+ /* 0x00000038 */ " Multipoint Server",
+ /* 0x00000039 */ "",
+ /* 0x0000003a */ "",
+ /* 0x0000003b */ " Essential Server Solution Management",
+ /* 0x0000003c */ " Essential Server Solution Additional",
+ /* 0x0000003d */ " Essential Server Solution Management SVC",
+ /* 0x0000003e */ " Essential Server Solution Additional SVC",
+ /* 0x0000003f */ " Small Business Server Premium Core",
+ /* 0x00000040 */ " Server Hyper Core V",
+ /* 0x00000041 */ "",
+ /* 0x00000042 */ " Starter E",
+ /* 0x00000043 */ " Home Basic E",
+ /* 0x00000044 */ " Home Premium E",
+ /* 0x00000045 */ " Professional E",
+ /* 0x00000046 */ " Enterprise E",
+ /* 0x00000047 */ " Ultimate E",
+ /* 0x00000048 */ " Server Enterprise (Evaluation inst.)",
+ /* 0x00000049 */ "",
+ /* 0x0000004a */ "",
+ /* 0x0000004b */ "",
+ /* 0x0000004c */ " MultiPoint Server Standard",
+ /* 0x0000004d */ " MultiPoint Server Premium",
+ /* 0x0000004e */ "",
+ /* 0x0000004f */ " Server Standard (Evaluation inst.)",
+ /* 0x00000050 */ " Server Datacenter (Evaluation inst.)",
+ /* 0x00000051 */ "",
+ /* 0x00000052 */ "",
+ /* 0x00000053 */ "",
+ /* 0x00000054 */ " Enterprise N (Evaluation inst.)",
+ /* 0x00000055 */ "",
+ /* 0x00000056 */ "",
+ /* 0x00000057 */ "",
+ /* 0x00000058 */ "",
+ /* 0x00000059 */ "",
+ /* 0x0000005a */ "",
+ /* 0x0000005b */ "",
+ /* 0x0000005c */ "",
+ /* 0x0000005d */ "",
+ /* 0x0000005e */ "",
+ /* 0x0000005f */ " Storage Server Workgroup (Evaluation inst.)",
+ /* 0x00000060 */ " Storage Server Standard (Evaluation inst.)",
+ /* 0x00000061 */ "",
+ /* 0x00000062 */ " N",
+ /* 0x00000063 */ " China",
+ /* 0x00000064 */ " Single Language",
+ /* 0x00000065 */ " Home",
+ /* 0x00000066 */ "",
+ /* 0x00000067 */ " Professional with Media Center",
+ /* 0x00000068 */ " Mobile",
+ /* 0x00000069 */ "",
+ /* 0x0000006a */ "",
+ /* 0x0000006b */ "",
+ /* 0x0000006c */ "",
+ /* 0x0000006d */ "",
+ /* 0x0000006e */ "",
+ /* 0x0000006f */ "",
+ /* 0x00000070 */ "",
+ /* 0x00000071 */ "",
+ /* 0x00000072 */ "",
+ /* 0x00000073 */ "",
+ /* 0x00000074 */ "",
+ /* 0x00000075 */ "",
+ /* 0x00000076 */ "",
+ /* 0x00000077 */ "",
+ /* 0x00000078 */ "",
+ /* 0x00000079 */ " Education",
+ /* 0x0000007a */ " Education N",
+ /* 0x0000007b */ "",
+ /* 0x0000007c */ "",
+ /* 0x0000007d */ "",
+ /* 0x0000007e */ "",
+ /* 0x0000007f */ "",
+ /* 0x00000080 */ "",
+ /* 0x00000081 */ "",
+ /* 0x00000082 */ "",
+ /* 0x00000083 */ "",
+ /* 0x00000084 */ "",
+ /* 0x00000085 */ " Mobile Enterprise",
+ };
+ if (prod == PRODUCT_UNLICENSED)
+ strcat (osname, "Unlicensed");
+ else if (prod > 0x00000085)
+ strcat (osname, "");
else
- osname = "XP Professional";
+ strcat (osname, products[prod]);
}
- else if (osversion.dwMinorVersion == 2)
+ else
{
- if (!more_info)
- osname = "2003 Server";
- else if (osversionex.wSuiteMask & VER_SUITE_BLADE)
- osname = "2003 Web Server";
- else if (osversionex.wSuiteMask & VER_SUITE_DATACENTER)
- osname = "2003 Datacenter Server";
- else if (osversionex.wSuiteMask & VER_SUITE_ENTERPRISE)
- osname = "2003 Enterprise Server";
- else
- osname = "2003 Server";
}
}
else
- osname = "NT";
+ strcpy (osname, "NT");
break;
default:
- osname = "??";
+ strcpy (osname, "??");
break;
}
- printf ("Windows %s Ver %lu.%lu Build %lu %s\n", osname,
+ printf ("Windows %s Ver %lu.%lu Build %lu %ls\n", osname,
osversion.dwMajorVersion, osversion.dwMinorVersion,
osversion.dwPlatformId == VER_PLATFORM_WIN32_NT ?
osversion.dwBuildNumber : (osversion.dwBuildNumber & 0xffff),
osversion.dwPlatformId == VER_PLATFORM_WIN32_NT ?
- osversion.szCSDVersion : "");
+ osversion.szCSDVersion : L"");
- HMODULE k32 = LoadLibrary ("kernel32.dll");
+ if (osversion.dwPlatformId == VER_PLATFORM_WIN32s
+ || osversion.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
+ exit (EXIT_FAILURE);
- BOOL (WINAPI *wow64_func) (HANDLE, PBOOL) = (BOOL (WINAPI *) (HANDLE, PBOOL))
- GetProcAddress (k32, "IsWow64Process");
BOOL is_wow64 = FALSE;
- if (wow64_func && wow64_func (GetCurrentProcess (), &is_wow64) && is_wow64)
+ if (IsWow64Process (GetCurrentProcess (), &is_wow64) && is_wow64)
{
- void (WINAPI *nativinfo) (LPSYSTEM_INFO) = (void (WINAPI *)
- (LPSYSTEM_INFO)) GetProcAddress (k32, "GetNativeSystemInfo");
SYSTEM_INFO natinfo;
- nativinfo (&natinfo);
+ GetNativeSystemInfo (&natinfo);
fputs ("\nRunning under WOW64 on ", stdout);
switch (natinfo.wProcessorArchitecture)
- {
+ {
case PROCESSOR_ARCHITECTURE_IA64:
puts ("IA64");
break;
{
for (e = s; *e && *e != sep; e++);
if (e-s)
- printf ("\t%.*s\n", e - s, s);
+ printf ("\t%.*s\n", (int) (e - s), s);
else
puts ("\t.");
count_path_items++;
fflush (stdout);
- char *cygwin = getenv ("CYGWIN");
- if (cygwin)
- cygwin -= strlen ("CYGWIN=");
- else
- cygwin = const_cast <char *> ("CYGWIN=");
- size_t cyglen = strlen (cygwin);
- cygwin = strcpy ((char *) malloc (cyglen + sizeof (" nontsec")), cygwin);
- pretty_id ("nontsec", cygwin, cyglen);
- pretty_id ("ntsec", cygwin, cyglen);
- cygwin[cyglen] = 0;
- putenv (cygwin);
+ pretty_id ();
if (!GetSystemDirectory (tmp, 4000))
display_error ("dump_sysinfo: GetSystemDirectory()");
if (registry)
{
if (givehelp)
- printf ("Scanning registry for keys with 'Cygnus' in them...\n");
-#if 0
- /* big and not generally useful */
- scan_registry (0, HKEY_CLASSES_ROOT, (char *) "HKEY_CLASSES_ROOT", 0);
-#endif
- scan_registry (0, HKEY_CURRENT_CONFIG,
- (char *) "HKEY_CURRENT_CONFIG", 0);
- scan_registry (0, HKEY_CURRENT_USER, (char *) "HKEY_CURRENT_USER", 0);
- scan_registry (0, HKEY_LOCAL_MACHINE, (char *) "HKEY_LOCAL_MACHINE", 0);
-#if 0
- /* the parts we need are duplicated in HKEY_CURRENT_USER anyway */
- scan_registry (0, HKEY_USERS, (char *) "HKEY_USERS", 0);
-#endif
+ printf ("Scanning registry for keys with 'Cygwin' in them...\n");
+ scan_registry (0, HKEY_CURRENT_USER,
+ (char *) "HKEY_CURRENT_USER", 0, false);
+ scan_registry (0, HKEY_LOCAL_MACHINE,
+ (char *) "HKEY_LOCAL_MACHINE", 0, false);
printf ("\n");
}
else
printf ("Use '-r' to scan registry\n\n");
+ if (RegOpenKeyEx (HKEY_LOCAL_MACHINE,
+ "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\kernel",
+ 0, KEY_READ, &key) == ERROR_SUCCESS)
+ {
+ DWORD size;
+ RegQueryValueEx (key, "obcaseinsensitive", NULL, NULL,
+ (LPBYTE) &obcaseinsensitive, &size);
+ RegCloseKey (key);
+ }
+ printf ("obcaseinsensitive set to %lu\n\n", obcaseinsensitive);
+
+ print_reg_installations ();
+
if (givehelp)
{
printf ("Listing available drives...\n");
SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
int drivemask = GetLogicalDrives ();
- BOOL (WINAPI * gdfse) (LPCSTR, long long *, long long *, long long *) =
- (BOOL (WINAPI *) (LPCSTR, long long *, long long *, long long *))
- GetProcAddress (k32, "GetDiskFreeSpaceExA");
-
for (i = 0; i < 26; i++)
{
if (!(drivemask & (1 << i)))
continue;
char drive[4], name[200], fsname[200];
DWORD serno = 0, maxnamelen = 0, flags = 0;
- name[0] = name[0] = fsname[0] = 0;
+ name[0] = fsname[0] = 0;
sprintf (drive, "%c:\\", i + 'a');
/* Report all errors, except if the Volume is ERROR_NOT_READY.
ERROR_NOT_READY is returned when removeable media drives are empty
long capacity_mb = -1;
int percent_full = -1;
- long long free_me = 0ULL, free_bytes = 0ULL, total_bytes = 1ULL;
- if (gdfse != NULL && gdfse (drive, &free_me, &total_bytes, &free_bytes))
+ ULARGE_INTEGER free_me, free_bytes, total_bytes;
+ free_me.QuadPart = free_bytes.QuadPart = 0ULL;
+ total_bytes.QuadPart = 1ULL;
+ if (GetDiskFreeSpaceEx (drive, &free_me, &total_bytes, &free_bytes))
{
- capacity_mb = total_bytes / (1024L * 1024L);
- percent_full = 100 - (int) ((100.0 * free_me) / total_bytes);
+ capacity_mb = total_bytes.QuadPart / (1024L * 1024L);
+ percent_full = 100 - (int) ((100.0 * free_me.QuadPart)
+ / total_bytes.QuadPart);
}
else
{
printf ("%7dMb %3d%% ", (int) capacity_mb, (int) percent_full);
else
printf (" N/A N/A ");
- printf ("%s %s %s %s %s %s %s\n",
+ printf ("%s %s %s %s %s %s %s %s\n",
flags & FS_CASE_IS_PRESERVED ? "CP" : " ",
flags & FS_CASE_SENSITIVE ? "CS" : " ",
flags & FS_UNICODE_STORED_ON_DISK ? "UN" : " ",
flags & FS_PERSISTENT_ACLS ? "PA" : " ",
flags & FS_FILE_COMPRESSION ? "FC" : " ",
flags & FS_VOL_IS_COMPRESSED ? "VC" : " ",
-#if 0
- flags & FILE_SUPPORTS_ENCRYPTION ? "EN" : " ",
- flags & FILE_SUPPORTS_OBJECT_IDS ? "OI" : " ",
- flags & FILE_SUPPORTS_REPARSE_POINTS ? "RP" : " ",
- flags & FILE_SUPPORTS_SPARSE_FILES ? "SP" : " ",
flags & FILE_VOLUME_QUOTAS ? "QU" : " ",
-#endif
name);
}
- if (!FreeLibrary (k32))
- display_error ("dump_sysinfo: FreeLibrary()");
SetErrorMode (prev_mode);
if (givehelp)
{
}
printf ("\n");
- add_path ((char *) "\\bin", 4); /* just in case */
-
if (givehelp)
printf
("Looking to see where common programs can be found, if at all...\n");
for (i = 0; common_apps[i].name; i++)
- if (!find_on_path ((char *) common_apps[i].name, (char *) ".exe", 1, 0))
+ if (!find_app_on_path ((char *) common_apps[i].name, 1))
{
if (common_apps[i].missing_is_good)
printf ("Not Found: %s (good!)\n", common_apps[i].name);
if (givehelp)
printf ("Looking for various Cygwin DLLs... (-v gives version info)\n");
int cygwin_dll_count = 0;
- for (i = 1; i < num_paths; i++)
+ char cygdll_path[32768];
+ for (pathlike *pth = paths; pth->dir; pth++)
{
- WIN32_FIND_DATA ffinfo;
- sprintf (tmp, "%s/*.*", paths[i]);
- HANDLE ff = FindFirstFile (tmp, &ffinfo);
+ WIN32_FIND_DATAW ffinfo;
+ sprintf (tmp, "%s*.*", pth->dir);
+ wide_path wpath (tmp);
+ HANDLE ff = FindFirstFileW (wpath, &ffinfo);
int found = (ff != INVALID_HANDLE_VALUE);
found_cygwin_dll = NULL;
while (found)
{
- char *f = ffinfo.cFileName;
+ char f[FILENAME_MAX + 1];
+ wcstombs (f, ffinfo.cFileName, sizeof f);
if (strcasecmp (f + strlen (f) - 4, ".dll") == 0)
{
if (strncasecmp (f, "cyg", 3) == 0)
{
- sprintf (tmp, "%s\\%s", paths[i], f);
+ sprintf (tmp, "%s%s", pth->dir, f);
if (strcasecmp (f, "cygwin1.dll") == 0)
{
- cygwin_dll_count++;
+ if (!cygwin_dll_count)
+ strcpy (cygdll_path, pth->dir);
+ if (!cygwin_dll_count
+ || strcasecmp (cygdll_path, pth->dir) != 0)
+ cygwin_dll_count++;
found_cygwin_dll = strdup (tmp);
}
else
ls (tmp);
}
}
- found = FindNextFile (ff, &ffinfo);
+ found = FindNextFileW (ff, &ffinfo);
}
if (found_cygwin_dll)
{
if (!cygwin_dll_count)
puts ("Warning: cygwin1.dll not found on your path");
+ dump_dodgy_apps (verbose);
+
if (is_nt)
dump_sysinfo_services ();
}
static int
check_keys ()
{
- HANDLE h = CreateFileA ("CONIN$", GENERIC_READ | GENERIC_WRITE,
+ HANDLE h = CreateFileW (L"CONIN$", GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
INPUT_RECORD in, prev_in;
// Drop first <RETURN> key
- ReadConsoleInput (h, &in, 1, &mode);
+ ReadConsoleInputW (h, &in, 1, &mode);
memset (&in, 0, sizeof in);
do
{
prev_in = in;
- if (!ReadConsoleInput (h, &in, 1, &mode))
+ if (!ReadConsoleInputW (h, &in, 1, &mode))
display_error ("check_keys: ReadConsoleInput()");
if (!memcmp (&in, &prev_in, sizeof in))
switch (in.EventType)
{
case KEY_EVENT:
- printf ("%s %ux VK: 0x%02x VS: 0x%02x A: 0x%02x CTRL: ",
+ printf ("%s %ux VK: 0x%04x VS: 0x%04x C: 0x%04x CTRL: ",
in.Event.KeyEvent.bKeyDown ? "Pressed " : "Released",
in.Event.KeyEvent.wRepeatCount,
in.Event.KeyEvent.wVirtualKeyCode,
in.Event.KeyEvent.wVirtualScanCode,
- (unsigned char) in.Event.KeyEvent.uChar.AsciiChar);
+ (unsigned char) in.Event.KeyEvent.uChar.UnicodeChar);
fputs (in.Event.KeyEvent.dwControlKeyState & CAPSLOCK_ON ?
"CL " : "-- ", stdout);
fputs (in.Event.KeyEvent.dwControlKeyState & ENHANCED_KEY ?
}
while (in.EventType != KEY_EVENT ||
in.Event.KeyEvent.bKeyDown != FALSE ||
- in.Event.KeyEvent.uChar.AsciiChar != 'q');
+ in.Event.KeyEvent.uChar.UnicodeChar != L'q');
CloseHandle (h);
return 0;
}
-/* RFC1738 says that these do not need to be escaped. */
-static const char safe_chars[] = "$-_.+!*'(),";
+/* These do not need to be escaped in application/x-www-form-urlencoded */
+static const char safe_chars[] = "$-_.!*'(),";
/* the URL to query. */
static const char base_url[] =
- "http://cygwin.com/cgi-bin2/package-grep.cgi?text=1&grep=";
+ "http://cygwin.com/cgi-bin2/package-grep.cgi?text=1&grep=";
+
+#ifdef __x86_64__
+#define ARCH_STR "&arch=x86_64"
+#else
+#define ARCH_STR "&arch=x86"
+#endif
+static const char *ARCH_str = ARCH_STR;
/* Queries Cygwin web site for packages containing files matching a regexp.
Return value is 1 if there was a problem, otherwise 0. */
char buf[1024];
/* construct the actual URL by escaping */
- char *url = (char *) alloca (sizeof (base_url) + strlen (search) * 3);
+ char *url = (char *) alloca (sizeof (base_url) + strlen (ARCH_str)
+ + strlen (search) * 3);
strcpy (url, base_url);
char *dest;
for (dest = &url[sizeof (base_url) - 1]; *search; search++)
{
if (isalnum (*search)
- || memchr (safe_chars, *search, sizeof (safe_chars) - 1))
- {
- *dest++ = *search;
- }
+ || memchr (safe_chars, *search, sizeof (safe_chars) - 1))
+ {
+ *dest++ = *search;
+ }
else
- {
- *dest++ = '%';
- sprintf (dest, "%02x", (unsigned char) *search);
- dest += 2;
- }
+ {
+ *dest++ = '%';
+ sprintf (dest, "%02x", (unsigned char) *search);
+ dest += 2;
+ }
}
- *dest = 0;
+ strcpy (dest, ARCH_str);
/* Connect to the net and open the URL. */
if (InternetAttemptConnect (0) != ERROR_SUCCESS)
/* Initialize WinInet and attempt to fetch our URL. */
HINTERNET hi = NULL, hurl = NULL;
- if (!(hi = InternetOpen ("cygcheck", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0)))
+ if (!(hi = InternetOpenA ("cygcheck", INTERNET_OPEN_TYPE_PRECONFIG,
+ NULL, NULL, 0)))
return display_internet_error ("InternetOpen() failed", NULL);
- if (!(hurl = InternetOpenUrl (hi, url, NULL, 0, 0, 0)))
+ if (!(hurl = InternetOpenUrlA (hi, url, NULL, 0, 0, 0)))
return display_internet_error ("unable to contact cygwin.com site, "
- "InternetOpenUrl() failed", hi, NULL);
+ "InternetOpenUrl() failed", hi, NULL);
/* Check the HTTP response code. */
DWORD rc = 0, rc_s = sizeof (DWORD);
- if (!HttpQueryInfo (hurl, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER,
- (void *) &rc, &rc_s, NULL))
+ if (!HttpQueryInfoA (hurl, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER,
+ (void *) &rc, &rc_s, NULL))
return display_internet_error ("HttpQueryInfo() failed", hurl, hi, NULL);
if (rc != HTTP_STATUS_OK)
{
sprintf (buf, "error retrieving results from cygwin.com site, "
- "HTTP status code %lu", rc);
+ "HTTP status code %lu", rc);
return display_internet_error (buf, hurl, hi, NULL);
}
do
{
if (!InternetReadFile (hurl, (void *) buf, sizeof (buf), &numread))
- return display_internet_error ("InternetReadFile failed", hurl, hi, NULL);
+ return display_internet_error ("InternetReadFile failed", hurl, hi, NULL);
if (numread)
- fwrite ((void *) buf, (size_t) numread, 1, stdout);
+ fwrite ((void *) buf, (size_t) numread, 1, stdout);
}
while (numread);
return 0;
}
-static void
+static void __attribute__ ((__noreturn__))
usage (FILE * stream, int status)
{
fprintf (stream, "\
-Usage: cygcheck PROGRAM [ -v ] [ -h ]\n\
- cygcheck -c [ PACKAGE ] [ -d ]\n\
- cygcheck -s [ -r ] [ -v ] [ -h ]\n\
+Usage: cygcheck [-v] [-h] PROGRAM\n\
+ cygcheck -c [-d] [PACKAGE]\n\
+ cygcheck -s [-r] [-v] [-h]\n\
cygcheck -k\n\
- cygcheck -f FILE [ FILE ... ]\n\
- cygcheck -l [ PACKAGE ] [ PACKAGE ... ]\n\
+ cygcheck -f FILE [FILE]...\n\
+ cygcheck -l [PACKAGE]...\n\
cygcheck -p REGEXP\n\
+ cygcheck --delete-orphaned-installation-keys\n\
+ cygcheck -h\n\n\
List system information, check installed packages, or query package database.\n\
\n\
At least one command option or a PROGRAM is required, as shown above.\n\
\n\
PROGRAM list library (DLL) dependencies of PROGRAM\n\
-c, --check-setup show installed version of PACKAGE and verify integrity\n\
- (or for all installed packages if none specified)\n\
+ (or for all installed packages if none specified)\n\
-d, --dump-only just list packages, do not verify (with -c)\n\
- -s, --sysinfo produce diagnostic system information (implies -c -d)\n\
+ -s, --sysinfo produce diagnostic system information (implies -c)\n\
-r, --registry also scan registry for Cygwin settings (with -s)\n\
-k, --keycheck perform a keyboard check session (must be run from a\n\
- plain console only, not from a pty/rxvt/xterm)\n\
- -f, --find-package find the package that FILE belongs to\n\
+ plain console only, not from a pty/rxvt/xterm)\n\
+ -f, --find-package find the package to which FILE belongs\n\
-l, --list-package list contents of PACKAGE (or all packages if none given)\n\
-p, --package-query search for REGEXP in the entire cygwin.com package\n\
- repository (requies internet connectivity)\n\
+ repository (requires internet connectivity)\n\
+ --delete-orphaned-installation-keys\n\
+ Delete installation keys of old, now unused\n\
+ installations from the registry. Requires the right\n\
+ to change the registry.\n\
-v, --verbose produce more verbose output\n\
-h, --help annotate output with explanatory comments when given\n\
- with another command, otherwise print this help\n\
+ with another command, otherwise print this help\n\
-V, --version print the version of cygcheck and exit\n\
\n\
Note: -c, -f, and -l only report on packages that are currently installed. To\n\
{"find-package", no_argument, NULL, 'f'},
{"list-package", no_argument, NULL, 'l'},
{"package-query", no_argument, NULL, 'p'},
+ {"delete-orphaned-installation-keys", no_argument, NULL, CO_DELETE_KEYS},
{"help", no_argument, NULL, 'h'},
{"version", no_argument, 0, 'V'},
{0, no_argument, NULL, 0}
static void
print_version ()
{
- const char *v = strchr (version, ':');
- int len;
- if (!v)
- {
- v = "?";
- len = 1;
- }
- else
- {
- v += 2;
- len = strchr (v, ' ') - v;
- }
- printf ("\
-cygcheck version %.*s\n\
-System Checker for Cygwin\n\
-Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Red Hat, Inc.\n\
-Compiled on %s\n\
-", len, v, __DATE__);
+ printf ("cygcheck (cygwin) %d.%d.%d\n"
+ "System Checker for Cygwin\n"
+ "Copyright (C) 1998 - %s Cygwin Authors\n"
+ "This is free software; see the source for copying conditions. "
+ "There is NO\n"
+ "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR "
+ "PURPOSE.\n",
+ CYGWIN_VERSION_DLL_MAJOR / 1000,
+ CYGWIN_VERSION_DLL_MAJOR % 1000,
+ CYGWIN_VERSION_DLL_MINOR,
+ strrchr (__DATE__, ' ') + 1);
}
void
nuke (char *ev)
{
int n = 1 + strchr (ev, '=') - ev;
- char *s = (char *) alloca (n + 1);
+ char *s = (char *) malloc (n + 1);
memcpy (s, ev, n);
s[n] = '\0';
putenv (s);
}
extern "C" {
-unsigned long (*cygwin_internal) (int, ...);
+uintptr_t (*cygwin_internal) (int, ...);
+WCHAR cygwin_dll_path[32768];
};
static void
if (!(h = LoadLibrary ("cygwin1.dll")))
return;
- if (!(cygwin_internal = (DWORD (*) (int, ...)) GetProcAddress (h, "cygwin_internal")))
- return;
+ GetModuleFileNameW (h, cygwin_dll_path, 32768);
+ if ((cygwin_internal = (uintptr_t (*) (int, ...))
+ GetProcAddress (h, "cygwin_internal")))
+ {
+ char **av = (char **) cygwin_internal (CW_ARGV);
+ if (av && ((uintptr_t) av != (uintptr_t) -1))
+ {
+ /* Copy cygwin's idea of the argument list into this Window
+ application. */
+ for (argc = 0; av[argc]; argc++)
+ continue;
+ argv = (char **) calloc (argc + 1, sizeof (char *));
+ for (char **argvp = argv; *av; av++)
+ *argvp++ = strdup (*av);
+ }
+
- char **av = (char **) cygwin_internal (CW_ARGV);
- if (av && ((DWORD) av != (DWORD) -1))
- for (argc = 0, argv = av; *av; av++)
- argc++;
-
- char **envp = (char **) cygwin_internal (CW_ENVP);
- if (envp && ((DWORD) envp != (DWORD) -1))
- {
- /* Store path and revert to this value, otherwise path gets overwritten
- by the POSIXy Cygwin variation, which breaks cygcheck.
- Another approach would be to use the Cygwin PATH and convert it to
- Win32 again. */
- char *path = NULL;
- char **env;
- while (*(env = _environ))
+ char **envp = (char **) cygwin_internal (CW_ENVP);
+ if (envp && ((uintptr_t) envp != (uintptr_t) -1))
{
- if (strncmp (*env, "PATH=", 5) == 0)
- path = strdup (*env);
- nuke (*env);
+ /* Store path and revert to this value, otherwise path gets
+ overwritten by the POSIXy Cygwin variation, which breaks cygcheck.
+ Another approach would be to use the Cygwin PATH and convert it to
+ Win32 again. */
+ char *path = NULL;
+ char **env;
+ while (*(env = _environ))
+ {
+ if (strncmp (*env, "PATH=", 5) == 0)
+ path = strdup (*env);
+ nuke (*env);
+ }
+ for (char **ev = envp; *ev; ev++)
+ if (strncmp (*ev, "PATH=", 5) != 0)
+ putenv (strdup (*ev));
+ if (path)
+ putenv (path);
}
- for (char **ev = envp; *ev; ev++)
- if (strncmp (*ev, "PATH=", 5) != 0)
- putenv (*ev);
- if (path)
- putenv (path);
}
+ /* GDB chokes when the DLL got unloaded and, for some reason, fails to set
+ any breakpoint after the fact. */
+ if (!IsDebuggerPresent ())
+ FreeLibrary (h);
}
int
bool ok = true;
load_cygwin (argc, argv);
- (void) putenv("POSIXLY_CORRECT=1");
+ _setmode (1, _O_BINARY);
+ _setmode (2, _O_BINARY);
+
+ /* Need POSIX sorting while parsing args, but don't forget the
+ user's original environment. */
+ char *posixly = getenv ("POSIXLY_CORRECT");
+ if (posixly == NULL)
+ (void) putenv ("POSIXLY_CORRECT=1");
while ((i = getopt_long (argc, argv, opts, longopts, NULL)) != EOF)
switch (i)
{
list_package = 1;
break;
case 'p':
- grep_packages = 1;
- break;
+ grep_packages = 1;
+ break;
case 'h':
givehelp = 1;
break;
+ case CO_DELETE_KEYS:
+ del_orphaned_reg = 1;
+ break;
case 'V':
print_version ();
exit (0);
default:
- usage (stderr, 1);
- /*NOTREACHED*/}
+ fprintf (stderr, "Try `cygcheck --help' for more information.\n");
+ exit (1);
+ /*NOTREACHED*/
+ }
argc -= optind;
argv += optind;
+ if (posixly == NULL)
+ putenv ("POSIXLY_CORRECT=");
- if (argc == 0 && !sysinfo && !keycheck && !check_setup && !list_package)
- if (givehelp)
- usage (stdout, 0);
- else
- usage (stderr, 1);
+ if ((argc == 0) && !sysinfo && !keycheck && !check_setup && !list_package
+ && !del_orphaned_reg)
+ {
+ if (givehelp)
+ usage (stdout, 0);
+ else
+ usage (stderr, 1);
+ }
- if ((check_setup || sysinfo || find_package || list_package || grep_packages)
+ if ((check_setup || sysinfo || find_package || list_package || grep_packages
+ || del_orphaned_reg)
&& keycheck)
usage (stderr, 1);
- if ((find_package || list_package || grep_packages) && check_setup)
+ if ((find_package || list_package || grep_packages)
+ && (check_setup || del_orphaned_reg))
usage (stderr, 1);
- if (dump_only && !check_setup)
+ if (dump_only && !check_setup && !sysinfo)
usage (stderr, 1);
if (find_package + list_package + grep_packages > 1)
if (keycheck)
return check_keys ();
+ if (del_orphaned_reg)
+ del_orphaned_reg_installations ();
if (grep_packages)
return package_grep (*argv);
if (!check_setup)
{
puts ("");
- dump_setup (verbose, NULL, false);
+ dump_setup (verbose, NULL, !dump_only);
}
if (!givehelp)