| /* cygcheck.cc |
| |
| 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 <stdarg.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/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 sysinfo = 0; |
| int givehelp = 0; |
| int keycheck = 0; |
| int check_setup = 0; |
| int dump_only = 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; |
| #else |
| typedef __int64 longlong; |
| #endif |
| |
| /* In dump_setup.cc */ |
| void dump_setup (int, char **, bool); |
| void package_find (int, char **); |
| void package_list (int, char **); |
| /* In bloda.cc */ |
| void dump_dodgy_apps (int verbose); |
| /* Forward declaration */ |
| static void usage (FILE *, int); |
| |
| static const char *known_env_vars[] = { |
| "c_include_path", |
| "compiler_path", |
| "cxx_include_path", |
| "cygwin", |
| "cygwin32", |
| "dejagnu", |
| "expect", |
| "gcc_default_options", |
| "gcc_exec_prefix", |
| "home", |
| "ld_library_path", |
| "library_path", |
| "login", |
| "lpath", |
| "make_mode", |
| "makeflags", |
| "path", |
| "pwd", |
| "strace", |
| "tcl_library", |
| "user", |
| 0 |
| }; |
| |
| struct |
| { |
| const char *name; |
| int missing_is_good; |
| } |
| static common_apps[] = { |
| {"awk", 0}, |
| {"bash", 0}, |
| {"cat", 0}, |
| {"cp", 0}, |
| {"cpp", 1}, |
| {"crontab", 0}, |
| {"find", 0}, |
| {"gcc", 0}, |
| {"gdb", 0}, |
| {"grep", 0}, |
| {"kill", 0}, |
| {"ld", 0}, |
| {"ls", 0}, |
| {"make", 0}, |
| {"mv", 0}, |
| {"patch", 0}, |
| {"perl", 0}, |
| {"rm", 0}, |
| {"sed", 0}, |
| {"ssh", 0}, |
| {"sh", 0}, |
| {"tar", 0}, |
| {"test", 0}, |
| {"vi", 0}, |
| {"vim", 0}, |
| {0, 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, ...) |
| { |
| va_list ap; |
| va_start (ap, format); |
| vfprintf (stderr, format, ap); |
| va_end (ap); |
| } |
| |
| /* |
| * display_error() is used to report failure modes |
| */ |
| static int |
| display_error (const char *name, bool show_error, bool print_failed) |
| { |
| fprintf (stderr, "cygcheck: %s", name); |
| if (show_error) |
| fprintf (stderr, "%s: %lu\n", |
| print_failed ? " failed" : "", GetLastError ()); |
| else |
| 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 |
| display_internet_error (const char *message, ...) |
| { |
| DWORD err = GetLastError (); |
| TCHAR err_buf[256]; |
| va_list hptr; |
| HINTERNET h; |
| |
| /* in the case of a successful connection but 404 response, there is no |
| win32 error message, but we still get passed a message to display. */ |
| 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)"); |
| |
| fprintf (stderr, "cygcheck: %s: %s (win32 error %lu)\n", message, |
| err_buf, err); |
| } |
| else |
| fprintf (stderr, "cygcheck: %s\n", message); |
| |
| va_start (hptr, message); |
| while ((h = va_arg (hptr, HINTERNET)) != 0) |
| InternetCloseHandle (h); |
| va_end (hptr); |
| |
| return 1; |
| } |
| |
| static void |
| add_path (char *s, int maxlen, bool issys) |
| { |
| if (num_paths >= max_paths) |
| { |
| max_paths += 10; |
| /* Extend path array */ |
| paths = (pathlike *) realloc (paths, (1 + max_paths) * sizeof (paths[0])); |
| } |
| |
| 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: calloc() failed"); |
| 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++; |
| } |
| |
| static void |
| init_paths () |
| { |
| char tmp[4000], *sl; |
| add_path ((char *) ".", 1, true); /* to be replaced later */ |
| |
| if (GetCurrentDirectory (4000, tmp)) |
| add_path (tmp, strlen (tmp), true); |
| else |
| display_error ("init_paths: GetCurrentDirectory()"); |
| |
| if (GetSystemDirectory (tmp, 4000)) |
| 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), true); |
| } |
| GetWindowsDirectory (tmp, 4000); |
| add_path (tmp, strlen (tmp), true); |
| |
| char *wpath = getenv ("PATH"); |
| if (!wpath) |
| display_error ("WARNING: PATH is not set\n", ""); |
| else |
| { |
| char *b, *e; |
| b = wpath; |
| while (1) |
| { |
| 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; |
| } |
| } |
| } |
| |
| #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]; |
| |
| /* 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 ("internal error find_on_path: NULL pointer for file", |
| false, false); |
| return 0; |
| } |
| |
| if (!ext) |
| { |
| display_error ("internal error find_on_path: " |
| "NULL pointer for default_extension", false, false); |
| return 0; |
| } |
| |
| const char *file; |
| pathlike *search_paths; |
| if (!strpbrk (in_file, ":/\\")) |
| { |
| file = in_file; |
| search_paths = paths; |
| } |
| else |
| { |
| file = cygpath (in_file, NULL); |
| search_paths = abspath; |
| showall = false; |
| } |
| |
| if (!file) |
| { |
| display_error ("internal error find_on_path: " |
| "cygpath conversion failed for %s\n", in_file); |
| return 0; |
| } |
| |
| char *hasext = strrchr (file, '.'); |
| if (hasext && !strpbrk (hasext, "/\\")) |
| ext = ""; |
| |
| 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 |
| #define DID_ACTIVE 2 |
| #define DID_INACTIVE 3 |
| |
| struct Did |
| { |
| Did *next; |
| char *file; |
| int state; |
| }; |
| static Did *did = 0; |
| |
| static Did * |
| already_did (const char *file) |
| { |
| Did *d; |
| for (d = did; d; d = d->next) |
| if (strcasecmp (d->file, file) == 0) |
| return d; |
| d = (Did *) malloc (sizeof (Did)); |
| d->file = strdup (file); |
| d->next = did; |
| d->state = DID_NEW; |
| did = d; |
| return d; |
| } |
| |
| struct Section |
| { |
| char name[8]; |
| int virtual_size; |
| int virtual_address; |
| int size_of_raw_data; |
| int pointer_to_raw_data; |
| }; |
| |
| static int |
| rva_to_offset (int rva, char *sections, int nsections, int *sz) |
| { |
| int i; |
| |
| if (sections == NULL) |
| { |
| display_error ("rva_to_offset: NULL passed for sections", true, false); |
| return 0; |
| } |
| |
| for (i = 0; i < nsections; i++) |
| { |
| Section *s = (Section *) (sections + i * 40); |
| #if 0 |
| printf ("%08x < %08x < %08x ? %08x\n", |
| s->virtual_address, rva, |
| s->virtual_address + s->virtual_size, s->pointer_to_raw_data); |
| #endif |
| if (rva >= s->virtual_address |
| && rva < s->virtual_address + s->virtual_size) |
| { |
| if (sz) |
| *sz = s->virtual_address + s->virtual_size - rva; |
| return rva - s->virtual_address + s->pointer_to_raw_data; |
| } |
| } |
| return 0; /* punt */ |
| } |
| |
| struct ExpDirectory |
| { |
| int flags; |
| int timestamp; |
| short major_ver; |
| short minor_ver; |
| int name_rva; |
| }; |
| |
| struct ImpDirectory |
| { |
| unsigned characteristics; |
| unsigned timestamp; |
| unsigned forwarder_chain; |
| unsigned name_rva; |
| unsigned iat_rva; |
| }; |
| |
| static bool track_down (const char *file, const char *suffix, int lvl); |
| |
| #define CYGPREFIX (sizeof ("%%% Cygwin ") - 1) |
| static void |
| cygwin_info (HANDLE h) |
| { |
| char *buf, *bufend, *buf_start = NULL; |
| const char *hello = " Cygwin DLL version info:\n"; |
| DWORD size = GetFileSize (h, NULL); |
| DWORD n; |
| |
| if (size == 0xffffffff) |
| return; |
| |
| buf_start = buf = (char *) calloc (1, size + 1); |
| if (buf == NULL) |
| { |
| display_error ("cygwin_info: calloc()"); |
| return; |
| } |
| |
| (void) SetFilePointer (h, 0, NULL, FILE_BEGIN); |
| if (!ReadFile (h, buf, size, &n, NULL)) |
| { |
| free (buf_start); |
| return; |
| } |
| |
| static char dummy[] = "\0\0\0\0\0\0\0"; |
| char *dll_major = dummy; |
| bufend = buf + size; |
| while (buf < bufend) |
| if ((buf = (char *) memchr (buf, '%', bufend - buf)) == NULL) |
| break; |
| else if (strncmp ("%%% Cygwin ", buf, CYGPREFIX) != 0) |
| buf++; |
| else |
| { |
| char *p = strchr (buf += CYGPREFIX, '\n'); |
| if (!p) |
| break; |
| if (strncasecmp (buf, "dll major:", 10) == 0) |
| { |
| dll_major = buf + 11; |
| continue; |
| } |
| char *s, pbuf[80]; |
| int len; |
| len = 1 + p - buf; |
| if (strncasecmp (buf, "dll minor:", 10) != 0) |
| s = buf; |
| else |
| { |
| char c = dll_major[1]; |
| dll_major[1] = '\0'; |
| int maj = atoi (dll_major); |
| dll_major[1] = c; |
| int min = atoi (dll_major + 1); |
| sprintf (pbuf, "DLL version: %d.%d.%.*s", maj, min, len - 11, |
| buf + 11); |
| len = strlen (s = pbuf); |
| } |
| if (strncmp (s, "dll", 3) == 0) |
| memcpy (s, "DLL", 3); |
| else if (strncmp (s, "api", 3) == 0) |
| memcpy (s, "API", 3); |
| else if (islower (*s)) |
| *s = toupper (*s); |
| fprintf (stdout, "%s %.*s", hello, len, s); |
| hello = ""; |
| } |
| |
| if (!*hello) |
| puts (""); |
| |
| free (buf_start); |
| return; |
| } |
| |
| static void |
| dll_info (const char *path, HANDLE fh, int lvl, int recurse) |
| { |
| 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]; |
| |
| if (path == NULL) |
| { |
| display_error ("dll_info: NULL passed for path", true, false); |
| return; |
| } |
| |
| if (SetFilePointer (fh, opthdr_ofs + 40, 0, FILE_BEGIN) == |
| INVALID_SET_FILE_POINTER && GetLastError () != NO_ERROR) |
| display_error ("dll_info: SetFilePointer()"); |
| |
| if (!ReadFile (fh, &v, sizeof (v), &junk, 0)) |
| display_error ("dll_info: Readfile()"); |
| |
| if (verbose) |
| printf (" - os=%d.%d img=%d.%d sys=%d.%d\n", |
| v[0], v[1], v[2], v[3], v[4], v[5]); |
| else |
| printf ("\n"); |
| |
| 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 + |
| get_word (fh, pe_header_offset + 4 + 16), 0, |
| FILE_BEGIN) == INVALID_SET_FILE_POINTER |
| && GetLastError () != NO_ERROR) |
| display_error ("dll_info: SetFilePointer()"); |
| |
| if (!ReadFile (fh, sections, nsections * 40, &junk, 0)) |
| display_error ("dll_info: Readfile()"); |
| |
| if (verbose && num_entries >= 1 && export_size > 0) |
| { |
| int expsz; |
| int expbase = rva_to_offset (export_rva, sections, nsections, &expsz); |
| |
| if (expbase) |
| { |
| if (SetFilePointer (fh, expbase, 0, FILE_BEGIN) == |
| INVALID_SET_FILE_POINTER && GetLastError () != NO_ERROR) |
| display_error ("dll_info: SetFilePointer()"); |
| |
| unsigned char *exp = (unsigned char *) malloc (expsz); |
| |
| if (!ReadFile (fh, exp, expsz, &junk, 0)) |
| display_error ("dll_info: Readfile()"); |
| |
| ExpDirectory *ed = (ExpDirectory *) exp; |
| int ofs = ed->name_rva - export_rva; |
| 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->tm_year < 200) |
| tm->tm_year += 1900; |
| printf ("%*c", lvl + 2, ' '); |
| printf ("\"%s\" v%d.%d", exp + ofs, |
| ed->major_ver, ed->minor_ver); |
| 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'); |
| } |
| } |
| |
| if (num_entries >= 2 && import_size > 0 && recurse) |
| { |
| int impsz; |
| int impbase = rva_to_offset (import_rva, sections, nsections, &impsz); |
| if (impbase) |
| { |
| if (SetFilePointer (fh, impbase, 0, FILE_BEGIN) == |
| INVALID_SET_FILE_POINTER && GetLastError () != NO_ERROR) |
| display_error ("dll_info: SetFilePointer()"); |
| |
| unsigned char *imp = (unsigned char *) malloc (impsz); |
| if (imp == NULL) |
| { |
| display_error ("dll_info: malloc()"); |
| return; |
| } |
| |
| if (!ReadFile (fh, imp, impsz, &junk, 0)) |
| display_error ("dll_info: Readfile()"); |
| |
| ImpDirectory *id = (ImpDirectory *) imp; |
| for (i = 0; id[i].name_rva; i++) |
| { |
| /* int ofs = id[i].name_rva - import_rva; */ |
| track_down ((char *) imp + id[i].name_rva - import_rva, |
| (char *) ".dll", lvl + 2); |
| } |
| } |
| } |
| if (strstr (path, "\\cygwin1.dll")) |
| cygwin_info (fh); |
| } |
| |
| // Return true on success, false if error printed |
| static bool |
| track_down (const char *file, const char *suffix, int lvl) |
| { |
| if (file == NULL) |
| { |
| display_error ("track_down: NULL passed for file", true, false); |
| return false; |
| } |
| |
| if (suffix == NULL) |
| { |
| display_error ("track_down: NULL passed for suffix", false, false); |
| return false; |
| } |
| |
| const char *path = find_on_path (file, suffix, false, true); |
| if (!path) |
| { |
| /* 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; |
| } |
| |
| Did *d = already_did (file); |
| switch (d->state) |
| { |
| case DID_NEW: |
| break; |
| case DID_ACTIVE: |
| if (verbose) |
| { |
| if (lvl) |
| printf ("%*c", lvl, ' '); |
| printf ("%s", path); |
| printf (" (recursive)\n"); |
| } |
| return true; |
| case DID_INACTIVE: |
| if (verbose) |
| { |
| if (lvl) |
| printf ("%*c", lvl, ' '); |
| printf ("%s", path); |
| printf (" (already done)\n"); |
| } |
| return true; |
| default: |
| break; |
| } |
| |
| if (lvl) |
| printf ("%*c", lvl, ' '); |
| |
| printf ("%s", path); |
| |
| wide_path wpath (path); |
| HANDLE fh = |
| CreateFileW (wpath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, |
| NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); |
| if (fh == INVALID_HANDLE_VALUE) |
| { |
| display_error ("cannot open - '%s'\n", path); |
| return false; |
| } |
| |
| d->state = DID_ACTIVE; |
| |
| 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()"); |
| return true; |
| } |
| |
| static void |
| ls (char *f) |
| { |
| 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: GetFileInformationByHandle()"); |
| |
| SYSTEMTIME systime; |
| |
| if (!FileTimeToSystemTime (&info.ftLastWriteTime, &systime)) |
| display_error ("ls: FileTimeToSystemTime()"); |
| printf ("%5dk %04d/%02d/%02d %s", |
| (((int) info.nFileSizeLow) + 512) / 1024, |
| systime.wYear, systime.wMonth, systime.wDay, f); |
| dll_info (f, h, 16, 0); |
| if (!CloseHandle (h)) |
| 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 (const char *app) |
| { |
| const char *papp = find_app_on_path (app, 1); |
| if (!papp) |
| { |
| display_error ("could not find '%s'\n", app); |
| return false; |
| } |
| |
| char *s; |
| char *sep = strpbrk (papp, ":/\\"); |
| if (!sep) |
| { |
| static char dot[] = "."; |
| s = dot; |
| } |
| else |
| { |
| int n = sep - papp; |
| s = (char *) malloc (n + 2); |
| memcpy ((char *) s, papp, n); |
| strcpy (s + n, "\\"); |
| } |
| |
| paths[0].dir = s; |
| did = NULL; |
| return track_down (papp, ".exe", 0); |
| } |
| |
| struct RegInfo |
| { |
| RegInfo *prev; |
| char *name; |
| HKEY key; |
| }; |
| |
| static void |
| show_reg (RegInfo * ri, int nest) |
| { |
| if (!ri) |
| return; |
| show_reg (ri->prev, 1); |
| if (nest) |
| printf ("%s\\", ri->name); |
| else |
| printf ("%s\n", ri->name); |
| } |
| |
| static void |
| scan_registry (RegInfo * prev, HKEY hKey, char *name, int cygwin, bool wow64) |
| { |
| RegInfo ri; |
| ri.prev = prev; |
| ri.name = name; |
| ri.key = hKey; |
| |
| char *cp; |
| for (cp = name; *cp; cp++) |
| if (strncasecmp (cp, "Cygwin", 6) == 0) |
| cygwin = 1; |
| |
| DWORD num_subkeys, max_subkey_len, num_values; |
| DWORD max_value_len, max_valdata_len, i; |
| if (RegQueryInfoKey (hKey, 0, 0, 0, &num_subkeys, &max_subkey_len, 0, |
| &num_values, &max_value_len, &max_valdata_len, 0, 0) |
| != ERROR_SUCCESS) |
| { |
| #if 0 |
| char tmp[400]; |
| FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, 0, GetLastError (), |
| MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), tmp, 400, 0); |
| printf ("RegQueryInfoKey: %s\n", tmp); |
| #endif |
| return; |
| } |
| |
| if (cygwin) |
| { |
| show_reg (&ri, 0); |
| |
| char *value_name = (char *) malloc (max_value_len + 1); |
| if (value_name == NULL) |
| { |
| display_error ("scan_registry: malloc()"); |
| return; |
| } |
| |
| char *value_data = (char *) malloc (max_valdata_len + 1); |
| if (value_data == NULL) |
| { |
| display_error ("scan_registry: malloc()"); |
| return; |
| } |
| |
| for (i = 0; i < num_values; i++) |
| { |
| DWORD dlen = max_valdata_len + 1; |
| DWORD nlen = max_value_len + 1; |
| DWORD type; |
| RegEnumValue (hKey, i, value_name, &nlen, 0, |
| &type, (BYTE *) value_data, &dlen); |
| { |
| printf (" %s = ", i ? value_name : "(default)"); |
| switch (type) |
| { |
| case REG_DWORD: |
| printf ("0x%08x\n", *(unsigned *) value_data); |
| break; |
| case REG_EXPAND_SZ: |
| case REG_SZ: |
| printf ("'%s'\n", value_data); |
| break; |
| default: |
| printf ("(unsupported type)\n"); |
| break; |
| } |
| } |
| } |
| free (value_name); |
| free (value_data); |
| } |
| |
| char *subkey_name = (char *) malloc (max_subkey_len + 1); |
| for (i = 0; i < num_subkeys; i++) |
| { |
| if (RegEnumKey (hKey, i, subkey_name, max_subkey_len + 1) == |
| 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, cygwin, wow64); |
| if (RegCloseKey (sKey) != ERROR_SUCCESS) |
| display_error ("scan_registry: RegCloseKey()"); |
| } |
| } |
| } |
| free (subkey_name); |
| } |
| |
| void |
| pretty_id () |
| { |
| char *groups[16384]; |
| |
| char *id = cygpath ("/bin/id.exe", NULL); |
| for (char *p = id; (p = strchr (p, '/')); p++) |
| *p = '\\'; |
| |
| if (access (id, X_OK)) |
| { |
| fprintf (stderr, "'id' program not found\n"); |
| return; |
| } |
| |
| char buf[16384]; |
| snprintf (buf, sizeof (buf), "\"%s\"", id); |
| FILE *f = popen (buf, "rt"); |
| |
| buf[0] = '\0'; |
| fgets (buf, sizeof (buf), f); |
| pclose (f); |
| char *uid = strtok (buf, ")"); |
| if (uid) |
| uid += strlen ("uid="); |
| else |
| { |
| fprintf (stderr, "garbled output from 'id' command - no uid= found\n"); |
| return; |
| } |
| char *gid = strtok (NULL, ")"); |
| if (gid) |
| gid += strlen ("gid=") + 1; |
| else |
| { |
| fprintf (stderr, "garbled output from 'id' command - no gid= found\n"); |
| return; |
| } |
| |
| char **ng = groups - 1; |
| size_t len_uid = strlen ("UID: )") + strlen (uid); |
| size_t len_gid = strlen ("GID: )") + strlen (gid); |
| *++ng = groups[0] = (char *) alloca (len_uid + 1); |
| *++ng = groups[1] = (char *) alloca (len_gid + 1); |
| sprintf (groups[0], "UID: %s)", uid); |
| sprintf (groups[1], "GID: %s)", gid); |
| size_t sz = max (len_uid, len_gid); |
| while ((*++ng = strtok (NULL, ","))) |
| { |
| char *p = strchr (*ng, '\n'); |
| if (p) |
| *p = '\0'; |
| if (ng == groups + 2) |
| *ng += strlen (" groups="); |
| size_t len = strlen (*ng); |
| if (sz < len) |
| sz = len; |
| } |
| ng--; |
| |
| 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", (int) sz, *g); |
| else |
| { |
| puts (*g); |
| i = 0; |
| } |
| } |
| |
| /* This dumps information about each installed cygwin service, if cygrunsrv |
| is available. */ |
| void |
| dump_sysinfo_services () |
| { |
| char buf[1024]; |
| char buf2[1024]; |
| FILE *f; |
| bool no_services = false; |
| |
| if (givehelp) |
| printf ("\nChecking for any Cygwin services... %s\n\n", |
| verbose ? "" : "(use -v for more detail)"); |
| else |
| fputc ('\n', stdout); |
| |
| /* find the location of cygrunsrv.exe */ |
| char *cygrunsrv = cygpath ("/bin/cygrunsrv.exe", NULL); |
| for (char *p = cygrunsrv; (p = strchr (p, '/')); p++) |
| *p = '\\'; |
| |
| if (access (cygrunsrv, X_OK)) |
| { |
| puts ("Can't find the cygrunsrv utility, skipping services check.\n"); |
| return; |
| } |
| |
| /* check for a recent cygrunsrv */ |
| snprintf (buf, sizeof (buf), "\"%s\" --version", cygrunsrv); |
| if ((f = popen (buf, "rt")) == NULL) |
| { |
| printf ("Failed to execute '%s', skipping services check.\n", buf); |
| return; |
| } |
| int maj, min; |
| 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"); |
| return; |
| } |
| 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"), |
| cygrunsrv); |
| if ((f = popen (buf, "rt")) == NULL) |
| { |
| printf ("Failed to execute '%s', skipping services check.\n", buf); |
| return; |
| } |
| |
| if (verbose) |
| { |
| /* copy output to stdout */ |
| size_t nchars = 0; |
| while (!feof (f) && !ferror (f)) |
| nchars += fwrite ((void *) buf, 1, |
| fread ((void *) buf, 1, sizeof (buf), f), stdout); |
| |
| /* cygrunsrv outputs nothing if there are no cygwin services found */ |
| if (nchars < 1) |
| no_services = true; |
| pclose (f); |
| } |
| else |
| { |
| /* read the output of --list, and then run --query for each service */ |
| size_t nchars = fread ((void *) buf, 1, sizeof (buf) - 1, f); |
| buf[nchars] = 0; |
| pclose (f); |
| |
| if (nchars > 0) |
| for (char *srv = strtok (buf, "\n"); srv; srv = strtok (NULL, "\n")) |
| { |
| 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); |
| return; |
| } |
| |
| /* copy output to stdout */ |
| while (!feof (f) && !ferror (f)) |
| fwrite ((void *) buf2, 1, |
| fread ((void *) buf2, 1, sizeof (buf2), f), stdout); |
| pclose (f); |
| } |
| else |
| no_services = true; |
| } |
| |
| /* inform the user if nothing found */ |
| if (no_services) |
| 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 () |
| { |
| int i, j; |
| char tmp[4000]; |
| 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)); |
| |
| RTL_OSVERSIONINFOEXW osversion; |
| osversion.dwOSVersionInfoSize = sizeof (RTL_OSVERSIONINFOEXW); |
| RtlGetVersion (&osversion); |
| |
| switch (osversion.dwPlatformId) |
| { |
| case VER_PLATFORM_WIN32_NT: |
| is_nt = true; |
| if (osversion.dwMajorVersion >= 6) |
| { |
| 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) |
| { |
| strcpy (osname, osversion.wProductType == VER_NT_WORKSTATION |
| ? "10" : "2016"); |
| } |
| DWORD prod; |
| if (GetProductInfo (osversion.dwMajorVersion, |
| osversion.dwMinorVersion, |
| osversion.wServicePackMajor, |
| osversion.wServicePackMinor, |
| &prod)) |
| { |
| 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 |
| strcat (osname, products[prod]); |
| } |
| else |
| { |
| } |
| } |
| else |
| strcpy (osname, "NT"); |
| break; |
| default: |
| strcpy (osname, "??"); |
| break; |
| } |
| 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 : L""); |
| |
| if (osversion.dwPlatformId == VER_PLATFORM_WIN32s |
| || osversion.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) |
| exit (EXIT_FAILURE); |
| |
| BOOL is_wow64 = FALSE; |
| if (IsWow64Process (GetCurrentProcess (), &is_wow64) && is_wow64) |
| { |
| SYSTEM_INFO natinfo; |
| GetNativeSystemInfo (&natinfo); |
| fputs ("\nRunning under WOW64 on ", stdout); |
| switch (natinfo.wProcessorArchitecture) |
| { |
| case PROCESSOR_ARCHITECTURE_IA64: |
| puts ("IA64"); |
| break; |
| case PROCESSOR_ARCHITECTURE_AMD64: |
| puts ("AMD64"); |
| break; |
| default: |
| puts("??"); |
| break; |
| } |
| } |
| |
| if (GetSystemMetrics (SM_REMOTESESSION)) |
| printf ("\nRunning in Terminal Service session\n"); |
| |
| printf ("\nPath:"); |
| char *s = getenv ("PATH"), *e; |
| if (!s) |
| puts (""); |
| else |
| { |
| char sep = strchr (s, ';') ? ';' : ':'; |
| int count_path_items = 0; |
| while (1) |
| { |
| for (e = s; *e && *e != sep; e++); |
| if (e-s) |
| printf ("\t%.*s\n", (int) (e - s), s); |
| else |
| puts ("\t."); |
| count_path_items++; |
| if (!*e) |
| break; |
| s = e + 1; |
| } |
| } |
| |
| fflush (stdout); |
| |
| pretty_id (); |
| |
| if (!GetSystemDirectory (tmp, 4000)) |
| display_error ("dump_sysinfo: GetSystemDirectory()"); |
| printf ("\nSysDir: %s\n", tmp); |
| |
| GetWindowsDirectory (tmp, 4000); |
| printf ("WinDir: %s\n\n", tmp); |
| |
| |
| if (givehelp) |
| printf ("Here's some environment variables that may affect cygwin:\n"); |
| for (i = 0; environ[i]; i++) |
| { |
| char *eq = strchr (environ[i], '='); |
| if (!eq) |
| continue; |
| /* int len = eq - environ[i]; */ |
| for (j = 0; known_env_vars[j]; j++) |
| { |
| *eq = 0; |
| if (strcmp (environ[i], "PATH") == 0) |
| continue; /* we handle this one specially */ |
| if (strcasecmp (environ[i], known_env_vars[j]) == 0) |
| printf ("%s = '%s'\n", environ[i], eq + 1); |
| *eq = '='; |
| } |
| } |
| printf ("\n"); |
| |
| if (verbose) |
| { |
| if (givehelp) |
| printf ("Here's the rest of your environment variables:\n"); |
| for (i = 0; environ[i]; i++) |
| { |
| int found = 0; |
| char *eq = strchr (environ[i], '='); |
| if (!eq) |
| continue; |
| /* int len = eq - environ[i]; */ |
| for (j = 0; known_env_vars[j]; j++) |
| { |
| *eq = 0; |
| if (strcasecmp (environ[i], known_env_vars[j]) == 0) |
| found = 1; |
| *eq = '='; |
| } |
| if (!found) |
| { |
| *eq = 0; |
| printf ("%s = '%s'\n", environ[i], eq + 1); |
| *eq = '='; |
| } |
| } |
| printf ("\n"); |
| } |
| |
| if (registry) |
| { |
| if (givehelp) |
| 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"); |
| printf ("Drv Type Size Used Flags Name\n"); |
| } |
| int prev_mode = |
| SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX); |
| int drivemask = GetLogicalDrives (); |
| |
| 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] = 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 |
| (CD, floppy, etc.) */ |
| if (!GetVolumeInformation (drive, name, sizeof (name), &serno, |
| &maxnamelen, &flags, fsname, |
| sizeof (fsname)) |
| && GetLastError () != ERROR_NOT_READY) |
| { |
| # define FMT "dump_sysinfo: GetVolumeInformation() for drive %c:" |
| char buf[sizeof (FMT)]; |
| sprintf (buf, FMT, 'A' + i); |
| display_error (buf); |
| # undef FMT |
| } |
| |
| int dtype = GetDriveType (drive); |
| char drive_type[4] = "unk"; |
| switch (dtype) |
| { |
| case DRIVE_REMOVABLE: |
| strcpy (drive_type, "fd "); |
| break; |
| case DRIVE_FIXED: |
| strcpy (drive_type, "hd "); |
| break; |
| case DRIVE_REMOTE: |
| strcpy (drive_type, "net"); |
| break; |
| case DRIVE_CDROM: |
| strcpy (drive_type, "cd "); |
| break; |
| case DRIVE_RAMDISK: |
| strcpy (drive_type, "ram"); |
| break; |
| default: |
| strcpy (drive_type, "unk"); |
| } |
| |
| long capacity_mb = -1; |
| int percent_full = -1; |
| |
| 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.QuadPart / (1024L * 1024L); |
| percent_full = 100 - (int) ((100.0 * free_me.QuadPart) |
| / total_bytes.QuadPart); |
| } |
| else |
| { |
| DWORD spc = 0, bps = 0, fc = 0, tc = 1; |
| if (GetDiskFreeSpace (drive, &spc, &bps, &fc, &tc)) |
| { |
| capacity_mb = (spc * bps * tc) / (1024 * 1024); |
| percent_full = 100 - (int) ((100.0 * fc) / tc); |
| } |
| } |
| |
| printf ("%.2s %s %-6s ", drive, drive_type, fsname); |
| if (capacity_mb >= 0) |
| printf ("%7dMb %3d%% ", (int) capacity_mb, (int) percent_full); |
| else |
| printf (" N/A N/A "); |
| printf ("%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" : " ", |
| 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" : " ", |
| name); |
| } |
| |
| SetErrorMode (prev_mode); |
| if (givehelp) |
| { |
| puts ("\n" |
| "fd = floppy, hd = hard drive, cd = CD-ROM\n" |
| "net= Network Share, ram= RAM drive, unk= Unknown\n" |
| "CP = Case Preserving, CS = Case Sensitive, UN = Unicode\n" |
| "PA = Persistent ACLS, FC = File Compression, VC = Volume Compression"); |
| } |
| printf ("\n"); |
| |
| unsigned ml_fsname = 4, ml_dir = 7, ml_type = 6; |
| bool ml_trailing = false; |
| |
| struct mntent *mnt; |
| setmntent (0, 0); |
| while ((mnt = getmntent (0))) |
| { |
| unsigned n = (int) strlen (mnt->mnt_fsname); |
| ml_trailing |= (n > 1 && strchr ("\\/", mnt->mnt_fsname[n - 1])); |
| if (ml_fsname < n) |
| ml_fsname = n; |
| n = (int) strlen (mnt->mnt_dir); |
| ml_trailing |= (n > 1 && strchr ("\\/", mnt->mnt_dir[n - 1])); |
| if (ml_dir < n) |
| ml_dir = n; |
| } |
| |
| if (ml_trailing) |
| puts ("Warning: Mount entries should not have a trailing (back)slash\n"); |
| |
| if (givehelp) |
| { |
| printf |
| ("Mount entries: these map POSIX directories to your NT drives.\n"); |
| printf ("%-*s %-*s %-*s %s\n", ml_fsname, "-NT-", ml_dir, "-POSIX-", |
| ml_type, "-Type-", "-Flags-"); |
| } |
| |
| setmntent (0, 0); |
| while ((mnt = getmntent (0))) |
| { |
| printf ("%-*s %-*s %-*s %s\n", |
| ml_fsname, mnt->mnt_fsname, |
| ml_dir, mnt->mnt_dir, ml_type, mnt->mnt_type, mnt->mnt_opts); |
| } |
| printf ("\n"); |
| |
| 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_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); |
| else |
| printf ("Not Found: %s\n", common_apps[i].name); |
| } |
| printf ("\n"); |
| |
| if (givehelp) |
| printf ("Looking for various Cygwin DLLs... (-v gives version info)\n"); |
| int cygwin_dll_count = 0; |
| char cygdll_path[32768]; |
| for (pathlike *pth = paths; pth->dir; pth++) |
| { |
| 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[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", pth->dir, f); |
| if (strcasecmp (f, "cygwin1.dll") == 0) |
| { |
| 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 = FindNextFileW (ff, &ffinfo); |
| } |
| if (found_cygwin_dll) |
| { |
| ls (found_cygwin_dll); |
| free (found_cygwin_dll); |
| } |
| |
| FindClose (ff); |
| } |
| if (cygwin_dll_count > 1) |
| puts ("Warning: There are multiple cygwin1.dlls on your path"); |
| 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 = CreateFileW (L"CONIN$", GENERIC_READ | GENERIC_WRITE, |
| FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, |
| OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); |
| |
| if (h == INVALID_HANDLE_VALUE || h == NULL) |
| return (display_error ("check_keys: Opening CONIN$")); |
| |
| DWORD mode; |
| |
| if (!GetConsoleMode (h, &mode)) |
| display_error ("check_keys: GetConsoleMode()"); |
| else |
| { |
| mode &= ~ENABLE_PROCESSED_INPUT; |
| if (!SetConsoleMode (h, mode)) |
| display_error ("check_keys: SetConsoleMode()"); |
| } |
| |
| fputs ("\nThis key check works only in a console window,", stderr); |
| fputs (" _NOT_ in a terminal session!\n", stderr); |
| fputs ("Abort with Ctrl+C if in a terminal session.\n\n", stderr); |
| fputs ("Press 'q' to exit.\n", stderr); |
| |
| INPUT_RECORD in, prev_in; |
| |
| // Drop first <RETURN> key |
| ReadConsoleInputW (h, &in, 1, &mode); |
| |
| memset (&in, 0, sizeof in); |
| |
| do |
| { |
| prev_in = in; |
| if (!ReadConsoleInputW (h, &in, 1, &mode)) |
| display_error ("check_keys: ReadConsoleInput()"); |
| |
| if (!memcmp (&in, &prev_in, sizeof in)) |
| continue; |
| |
| switch (in.EventType) |
| { |
| case KEY_EVENT: |
| 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.UnicodeChar); |
| fputs (in.Event.KeyEvent.dwControlKeyState & CAPSLOCK_ON ? |
| "CL " : "-- ", stdout); |
| fputs (in.Event.KeyEvent.dwControlKeyState & ENHANCED_KEY ? |
| "EK " : "-- ", stdout); |
| fputs (in.Event.KeyEvent.dwControlKeyState & LEFT_ALT_PRESSED ? |
| "LA " : "-- ", stdout); |
| fputs (in.Event.KeyEvent.dwControlKeyState & LEFT_CTRL_PRESSED ? |
| "LC " : "-- ", stdout); |
| fputs (in.Event.KeyEvent.dwControlKeyState & NUMLOCK_ON ? |
| "NL " : "-- ", stdout); |
| fputs (in.Event.KeyEvent.dwControlKeyState & RIGHT_ALT_PRESSED ? |
| "RA " : "-- ", stdout); |
| fputs (in.Event.KeyEvent.dwControlKeyState & RIGHT_CTRL_PRESSED ? |
| "RC " : "-- ", stdout); |
| fputs (in.Event.KeyEvent.dwControlKeyState & SCROLLLOCK_ON ? |
| "SL " : "-- ", stdout); |
| fputs (in.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED ? |
| "SH " : "-- ", stdout); |
| fputc ('\n', stdout); |
| break; |
| |
| default: |
| break; |
| } |
| } |
| while (in.EventType != KEY_EVENT || |
| in.Event.KeyEvent.bKeyDown != FALSE || |
| in.Event.KeyEvent.uChar.UnicodeChar != L'q'); |
| |
| CloseHandle (h); |
| return 0; |
| } |
| |
| /* 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="; |
| |
| #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. */ |
| static int |
| package_grep (char *search) |
| { |
| char buf[1024]; |
| |
| /* construct the actual URL by escaping */ |
| 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; |
| } |
| else |
| { |
| *dest++ = '%'; |
| sprintf (dest, "%02x", (unsigned char) *search); |
| dest += 2; |
| } |
| } |
| strcpy (dest, ARCH_str); |
| |
| /* Connect to the net and open the URL. */ |
| if (InternetAttemptConnect (0) != ERROR_SUCCESS) |
| { |
| fputs ("An internet connection is required for this function.\n", stderr); |
| return 1; |
| } |
| |
| /* Initialize WinInet and attempt to fetch our URL. */ |
| HINTERNET hi = NULL, hurl = NULL; |
| if (!(hi = InternetOpenA ("cygcheck", INTERNET_OPEN_TYPE_PRECONFIG, |
| NULL, NULL, 0))) |
| return display_internet_error ("InternetOpen() failed", NULL); |
| |
| if (!(hurl = InternetOpenUrlA (hi, url, NULL, 0, 0, 0))) |
| return display_internet_error ("unable to contact cygwin.com site, " |
| "InternetOpenUrl() failed", hi, NULL); |
| |
| /* Check the HTTP response code. */ |
| DWORD rc = 0, rc_s = sizeof (DWORD); |
| 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); |
| return display_internet_error (buf, hurl, hi, NULL); |
| } |
| |
| /* Fetch result and print to stdout. */ |
| DWORD numread; |
| do |
| { |
| if (!InternetReadFile (hurl, (void *) buf, sizeof (buf), &numread)) |
| return display_internet_error ("InternetReadFile failed", hurl, hi, NULL); |
| if (numread) |
| fwrite ((void *) buf, (size_t) numread, 1, stdout); |
| } |
| while (numread); |
| |
| InternetCloseHandle (hurl); |
| InternetCloseHandle (hi); |
| return 0; |
| } |
| |
| static void |
| usage (FILE * stream, int status) |
| { |
| fprintf (stream, "\ |
| 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]...\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\ |
| -d, --dump-only just list packages, do not verify (with -c)\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 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 (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\ |
| -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\ |
| search all official Cygwin packages use -p instead. The -p REGEXP matches\n\ |
| package names, descriptions, and names of files/paths within all packages.\n\ |
| \n"); |
| exit (status); |
| } |
| |
| struct option longopts[] = { |
| {"check-setup", no_argument, NULL, 'c'}, |
| {"dump-only", no_argument, NULL, 'd'}, |
| {"sysinfo", no_argument, NULL, 's'}, |
| {"registry", no_argument, NULL, 'r'}, |
| {"verbose", no_argument, NULL, 'v'}, |
| {"keycheck", no_argument, NULL, 'k'}, |
| {"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 char opts[] = "cdsrvkflphV"; |
| |
| static void |
| print_version () |
| { |
| 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 *) malloc (n + 1); |
| memcpy (s, ev, n); |
| s[n] = '\0'; |
| putenv (s); |
| } |
| |
| extern "C" { |
| uintptr_t (*cygwin_internal) (int, ...); |
| WCHAR cygwin_dll_path[32768]; |
| }; |
| |
| static void |
| load_cygwin (int& argc, char **&argv) |
| { |
| HMODULE h; |
| |
| if (!(h = LoadLibrary ("cygwin1.dll"))) |
| 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 **envp = (char **) cygwin_internal (CW_ENVP); |
| if (envp && ((uintptr_t) envp != (uintptr_t) -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)) |
| { |
| 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); |
| } |
| } |
| /* GDB chokes when the DLL got unloaded and, for some reason, fails to set |
| any breakpoint after the fact. */ |
| if (!IsDebuggerPresent ()) |
| FreeLibrary (h); |
| } |
| |
| int |
| main (int argc, char **argv) |
| { |
| int i; |
| bool ok = true; |
| load_cygwin (argc, argv); |
| |
| _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) |
| { |
| case 's': |
| sysinfo = 1; |
| break; |
| case 'c': |
| check_setup = 1; |
| break; |
| case 'd': |
| dump_only = 1; |
| break; |
| case 'r': |
| registry = 1; |
| break; |
| case 'v': |
| verbose = 1; |
| break; |
| case 'k': |
| keycheck = 1; |
| break; |
| case 'f': |
| find_package = 1; |
| break; |
| case 'l': |
| list_package = 1; |
| break; |
| case 'p': |
| 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: |
| 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 |
| && !del_orphaned_reg) |
| { |
| if (givehelp) |
| usage (stdout, 0); |
| else |
| usage (stderr, 1); |
| } |
| |
| 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 || del_orphaned_reg)) |
| usage (stderr, 1); |
| |
| if (dump_only && !check_setup && !sysinfo) |
| usage (stderr, 1); |
| |
| if (find_package + list_package + grep_packages > 1) |
| usage (stderr, 1); |
| |
| if (keycheck) |
| return check_keys (); |
| if (del_orphaned_reg) |
| del_orphaned_reg_installations (); |
| if (grep_packages) |
| return package_grep (*argv); |
| |
| init_paths (); |
| |
| /* FIXME: Add help for check_setup and {list,find}_package */ |
| if (argc >= 1 && givehelp && !check_setup && !find_package && !list_package) |
| { |
| printf("Here is where the OS will find your program%s, and which dlls\n", |
| argc > 1 ? "s" : ""); |
| printf ("will be used for it. Use -v to see DLL version info\n"); |
| |
| if (!sysinfo) |
| printf ("\n"); |
| } |
| |
| if (check_setup) |
| dump_setup (verbose, argv, !dump_only); |
| else if (find_package) |
| package_find (verbose, argv); |
| else if (list_package) |
| package_list (verbose, argv); |
| else |
| for (i = 0; i < argc; i++) |
| { |
| if (i) |
| puts (""); |
| ok &= cygcheck (argv[i]); |
| } |
| |
| if (sysinfo) |
| { |
| dump_sysinfo (); |
| if (!check_setup) |
| { |
| puts (""); |
| dump_setup (verbose, NULL, !dump_only); |
| } |
| |
| if (!givehelp) |
| puts ("Use -h to see help about each section"); |
| } |
| |
| return ok ? EXIT_SUCCESS : EXIT_FAILURE; |
| } |