/* cygcheck.cc Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004 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. */ #include #include #include #include #include #include #include #include "path.h" #include #include "cygwin/include/sys/cygwin.h" #include "cygwin/include/mntent.h" #define alloca __builtin_alloca 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; #ifdef __GNUC__ typedef long long longlong; #else typedef __int64 longlong; #endif void dump_setup (int, char **, bool); void package_find (int, char **); void package_list (int, char **); static const char version[] = "$Revision$"; 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}, {"find", 0}, {"gcc", 0}, {"gdb", 0}, {"grep", 0}, {"ld", 0}, {"ls", 0}, {"make", 0}, {"mv", 0}, {"rm", 0}, {"sed", 0}, {"sh", 0}, {"tar", 0}, {0, 0} }; static int num_paths = 0, max_paths = 0; static char **paths = 0; /* * keyeprint() is used to report failure modes */ static int keyeprint (const char *name) { fprintf (stderr, "cygcheck: %s failed: %lu\n", name, GetLastError ()); return 1; } static void add_path (char *s, int maxlen) { 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 *)); } paths[num_paths] = (char *) malloc (maxlen + 1); if (paths[num_paths] == NULL) { keyeprint ("add_path: malloc()"); 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; } num_paths++; } static void init_paths () { char tmp[4000], *sl; add_path ((char *) ".", 1); /* to be replaced later */ add_path ((char *) ".", 1); /* the current directory */ if (GetSystemDirectory (tmp, 4000)) add_path (tmp, strlen (tmp)); else keyeprint ("init_paths: GetSystemDirectory()"); sl = strrchr (tmp, '\\'); if (sl) { strcpy (sl, "\\SYSTEM"); add_path (tmp, strlen (tmp)); } GetWindowsDirectory (tmp, 4000); add_path (tmp, strlen (tmp)); char *wpath = getenv ("PATH"); if (wpath) { char *b, *e; b = wpath; while (1) { for (e = b; *e && *e != ';'; e++); add_path (b, e - b); 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) { static char rv[4000]; char tmp[4000], *ptr = rv; if (!file) { keyeprint ("find_on_path: NULL pointer for file"); return 0; } if (default_extension == NULL) { keyeprint ("find_on_path: NULL pointer for default_extension"); return 0; } if (strchr (file, ':') || strchr (file, '\\') || strchr (file, '/')) return cygpath (file, NULL); if (strchr (file, '.')) default_extension = (char *) ""; for (int i = 0; i < num_paths; i++) { 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; } } } if (ptr == tmp) return rv; return 0; } #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 (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; } 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) keyeprint ("get_word: SetFilePointer()"); if (!ReadFile (fh, &rv, 2, (DWORD *) &r, 0)) keyeprint ("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) keyeprint ("get_word: SetFilePointer()"); if (!ReadFile (fh, &rv, 4, (DWORD *) &r, 0)) keyeprint ("get_dword: Readfile()"); return rv; } 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) { keyeprint ("rva_to_offset: NULL passed for sections"); 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 void track_down (char *file, 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) { keyeprint ("cygwin_info: malloc()"); 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; int pe_header_offset = get_dword (fh, 0x3c); int opthdr_ofs = pe_header_offset + 4 + 20; unsigned short v[6]; if (path == NULL) { keyeprint ("dll_info: NULL passed for path"); return; } if (SetFilePointer (fh, opthdr_ofs + 40, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER && GetLastError () != NO_ERROR) keyeprint ("dll_info: SetFilePointer()"); if (!ReadFile (fh, &v, sizeof (v), &junk, 0)) keyeprint ("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 + 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 nsections = get_word (fh, pe_header_offset + 4 + 2); 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) keyeprint ("dll_info: SetFilePointer()"); if (!ReadFile (fh, sections, nsections * 40, &junk, 0)) keyeprint ("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) keyeprint ("dll_info: SetFilePointer()"); unsigned char *exp = (unsigned char *) malloc (expsz); if (!ReadFile (fh, exp, expsz, &junk, 0)) keyeprint ("dll_info: Readfile()"); 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) tm->tm_year += 2000; if (tm->tm_year < 200) tm->tm_year += 1900; printf ("%*c", lvl + 2, ' '); printf ("\"%s\" v%d.%d ts=", 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 (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) keyeprint ("dll_info: SetFilePointer()"); unsigned char *imp = (unsigned char *) malloc (impsz); if (imp == NULL) { keyeprint ("dll_info: malloc()"); return; } if (!ReadFile (fh, imp, impsz, &junk, 0)) keyeprint ("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); } static void track_down (char *file, char *suffix, int lvl) { if (file == NULL) { keyeprint ("track_down: malloc()"); return; } if (suffix == NULL) { keyeprint ("track_down: malloc()"); return; } char *path = find_on_path (file, suffix, 0, 1); if (!path) { printf ("Error: could not find %s\n", file); return; } 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; case DID_INACTIVE: if (verbose) { if (lvl) printf ("%*c", lvl, ' '); printf ("%s", path); printf (" (already done)\n"); } return; default: break; } if (lvl) printf ("%*c", lvl, ' '); if (!path) { printf ("%s not found\n", file); return; } printf ("%s", path); HANDLE fh = CreateFile (path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (fh == INVALID_HANDLE_VALUE) { printf (" - Cannot open\n"); return; } d->state = DID_ACTIVE; dll_info (path, fh, lvl, 1); d->state = DID_INACTIVE; if (!CloseHandle (fh)) keyeprint ("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); BY_HANDLE_FILE_INFORMATION info; if (!GetFileInformationByHandle (h, &info)) keyeprint ("ls: GetFileInformationByHandle()"); SYSTEMTIME systime; if (!FileTimeToSystemTime (&info.ftLastWriteTime, &systime)) keyeprint ("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)) keyeprint ("ls: CloseHandle()"); } static void cygcheck (char *app) { char *papp = find_on_path (app, (char *) ".exe", 1, 0); if (!papp) { printf ("Error: could not find %s\n", app); return; } 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 *) "."; else { *sl = 0; paths[0] = s; } did = 0; track_down (papp, (char *) ".exe", 0); } extern char **environ; 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 cygnus) { RegInfo ri; ri.prev = prev; ri.name = name; ri.key = hKey; char *cp; for (cp = name; *cp; cp++) if (strncasecmp (cp, "cygnus", 6) == 0) cygnus = 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 (cygnus) { show_reg (&ri, 0); char *value_name = (char *) malloc (max_value_len + 1); if (value_name == NULL) { keyeprint ("scan_registry: malloc()"); return; } char *value_data = (char *) malloc (max_valdata_len + 1); if (value_data == NULL) { keyeprint ("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; if (RegOpenKeyEx (hKey, subkey_name, 0, KEY_READ, &sKey) == ERROR_SUCCESS) { scan_registry (&ri, sKey, subkey_name, cygnus); if (RegCloseKey (sKey) != ERROR_SUCCESS) keyeprint ("scan_registry: RegCloseKey()"); } } } free (subkey_name); } void pretty_id (const char *s, char *cygwin, size_t cyglen) { 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 = '\\'; if (access (id, X_OK)) { fprintf (stderr, "`id' program not found\n"); return; } FILE *f = popen (id, "rt"); char buf[16384]; 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"); exit (1); } char *gid = strtok (NULL, ")"); if (gid) gid += strlen ("gid=") + 1; else { fprintf (stderr, "garbled output from `id' command - no gid= found\n"); exit (1); } char **ng = groups - 1; size_t len_uid = strlen (uid); size_t len_gid = strlen (gid); *++ng = groups[0] = (char *) alloca (len_uid += sizeof ("UID: )")); *++ng = groups[1] = (char *) alloca (len_uid += sizeof ("GID: )")); 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; } printf ("\nOutput from %s (%s)\n", id, s); int n = 80 / (int) sz; sz = -(sz + 1); int i = n - 2; for (char **g = groups; g < ng; g++) if ((g != ng - 1) && (++i < n)) printf ("%*s ", sz, *g); else { puts (*g); i = 0; } } static void dump_sysinfo () { int i, j; char tmp[4000]; time_t now; char *found_cygwin_dll; printf ("\nCygwin Configuration Diagnostics\n"); time (&now); printf ("Current System Time: %s\n", ctime (&now)); OSVERSIONINFO osversion; osversion.dwOSVersionInfoSize = sizeof (osversion); if (!GetVersionEx (&osversion)) keyeprint ("dump_sysinfo: GetVersionEx()"); char *osname = (char *) "unknown OS"; switch (osversion.dwPlatformId) { case VER_PLATFORM_WIN32s: osname = (char *) "32s"; break; case VER_PLATFORM_WIN32_WINDOWS: switch (osversion.dwMinorVersion) { case 0: if (strchr (osversion.szCSDVersion, 'C')) osname = (char *) "95 OSR2"; else osname = (char *) "95"; break; case 10: if (strchr (osversion.szCSDVersion, 'A')) osname = (char *) "98 SE"; else osname = (char *) "98"; break; case 90: osname = (char *) "ME"; break; default: osname = (char *) "9X"; break; } break; case VER_PLATFORM_WIN32_NT: if (osversion.dwMajorVersion == 5) { BOOL more_info = FALSE; OSVERSIONINFOEX osversionex; osversionex.dwOSVersionInfoSize = sizeof (osversionex); if (GetVersionEx ((OSVERSIONINFO *) &osversionex)) more_info = TRUE; if (osversion.dwMinorVersion == 0) { if (!more_info) osname = (char *) "2000"; else if (osversionex.wProductType == VER_NT_SERVER || osversionex.wProductType == VER_NT_DOMAIN_CONTROLLER) { if (osversionex.wSuiteMask &VER_SUITE_DATACENTER) osname = (char *) "2000 Datacenter Server"; else if (osversionex.wSuiteMask & VER_SUITE_ENTERPRISE) osname = (char *) "2000 Advanced Server"; else osname = (char *) "2000 Server"; } else osname = (char *) "2000 Professional"; } else { if (!more_info) osname = (char *) "XP"; else if (osversionex.wProductType == VER_NT_SERVER || osversionex.wProductType == VER_NT_DOMAIN_CONTROLLER) { if (osversionex.wSuiteMask & VER_SUITE_ENTERPRISE) osname = (char *) ".NET Enterprise Server"; else osname = (char *) ".NET Server"; } else if (osversionex.wSuiteMask & VER_SUITE_PERSONAL) osname = (char *) "XP Home Edition"; else osname = (char *) "XP Professional"; } } else osname = (char *) "NT"; break; default: osname = (char *) "??"; break; } printf ("Windows %s Ver %lu.%lu Build %lu %s\n\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 : ""); printf ("Path:"); char *s = getenv ("PATH"), *e; 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", e - s, s); else puts ("\t."); count_path_items++; if (!*e) break; s = e + 1; } fflush (stdout); char *cygwin = getenv ("CYGWIN"); if (cygwin) cygwin -= strlen ("CYGWIN="); else cygwin = const_cast ("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); if (!GetSystemDirectory (tmp, 4000)) keyeprint ("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 `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 ("\n"); } else printf ("Use `-r' to scan registry\n\n"); if (givehelp) { printf ("Listing available drives...\n"); printf ("Drv Type Size Free Flags Name\n"); } int prev_mode = SetErrorMode (SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX); int drivemask = GetLogicalDrives (); HINSTANCE k32 = LoadLibrary ("kernel32.dll"); 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; 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) keyeprint ("dump_sysinfo: GetVolumeInformation()"); 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; long long free_me = 0ULL, free_bytes = 0ULL, total_bytes = 1ULL; if (gdfse != NULL && gdfse (drive, &free_me, &total_bytes, &free_bytes)) { capacity_mb = total_bytes / (1024L * 1024L); percent_full = 100 - (int) ((100.0 * free_me) / total_bytes); } 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 ("%5dMb %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" : " ", #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)) keyeprint ("dump_sysinfo: FreeLibrary()"); SetErrorMode (prev_mode); if (givehelp) { printf ("fd=floppy, hd=hard drive, cd=CD-ROM, net=Network Share\n"); printf ("CP=Case Preserving, CS=Case Sensitive, UN=Unicode\n"); printf ("PA=Persistent ACLS, FC=File Compression, VC=Volume Compression\n"); } 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"); 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 (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 Cygnus DLLs... (-v gives version info)\n"); for (i = 0; i < num_paths; i++) { WIN32_FIND_DATA ffinfo; sprintf (tmp, "%s/*.*", paths[i]); HANDLE ff = FindFirstFile (tmp, &ffinfo); int found = (ff != INVALID_HANDLE_VALUE); found_cygwin_dll = NULL; while (found) { char *f = ffinfo.cFileName; if (strcasecmp (f + strlen (f) - 4, ".dll") == 0) { if (strncasecmp (f, "cyg", 3) == 0) { sprintf (tmp, "%s\\%s", paths[i], f); if (strcasecmp (f, "cygwin1.dll") == 0) found_cygwin_dll = strdup (tmp); else ls (tmp); } } found = FindNextFile (ff, &ffinfo); } if (found_cygwin_dll) { ls (found_cygwin_dll); free (found_cygwin_dll); } FindClose (ff); } } static int check_keys () { HANDLE h = CreateFileA ("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 (keyeprint ("check_key: Opening CONIN$")); DWORD mode; if (!GetConsoleMode (h, &mode)) keyeprint ("check_keys: GetConsoleMode()"); else { mode &= ~ENABLE_PROCESSED_INPUT; if (!SetConsoleMode (h, mode)) keyeprint ("check_keys: GetConsoleMode()"); } 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 key ReadConsoleInput (h, &in, 1, &mode); memset (&in, 0, sizeof in); do { prev_in = in; if (!ReadConsoleInput (h, &in, 1, &mode)) keyeprint ("ReadConsoleInput"); if (!memcmp (&in, &prev_in, sizeof in)) continue; switch (in.EventType) { case KEY_EVENT: printf ("%s %ux VK: 0x%02x VS: 0x%02x A: 0x%02x 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); 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.AsciiChar != 'q'); CloseHandle (h); return 0; } static void usage (FILE * stream, int status) { fprintf (stream, "\ Usage: cygcheck [OPTIONS] [PROGRAM...]\n\ Check system information or PROGRAM library dependencies\n\ \n\ -c, --check-setup check packages installed via setup.exe\n\ -d, --dump-only no integrity checking of package contents (requires -c)\n\ -s, --sysinfo system information (not with -k)\n\ -v, --verbose verbose output (indented) (for -[cfls] or programs)\n\ -r, --registry registry search (requires -s)\n\ -k, --keycheck perform a keyboard check session (not with -[scfl])\n\ -f, --find-package find installed packages containing files (not with -[cl])\n\ -l, --list-package list the contents of installed packages (not with -[cf])\n\ -h, --help give help about the info (not with -[cfl])\n\ -V, --version output version information and exit\n\ You must at least give either -s or -k or a program name\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'}, {"help", no_argument, NULL, 'h'}, {"version", no_argument, 0, 'V'}, {0, no_argument, NULL, 0} }; static char opts[] = "cdfhklrsvV"; 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 Red Hat, Inc.\n\ Compiled on %s\n\ ", len, v, __DATE__); } int main (int argc, char **argv) { int i; (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 'h': givehelp = 1; break; case 'V': print_version (); exit (0); default: usage (stderr, 1); /*NOTREACHED*/} argc -= optind; argv += optind; if (argc == 0 && !sysinfo && !keycheck && !check_setup) if (givehelp) usage (stdout, 0); else usage (stderr, 1); if ((check_setup || sysinfo || find_package || list_package) && keycheck) usage (stderr, 1); if ((find_package || list_package) && check_setup) usage (stderr, 1); if (dump_only && !check_setup) usage (stderr, 1); if (find_package && list_package) usage (stderr, 1); if (keycheck) return check_keys (); 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 (""); cygcheck (argv[i]); } if (sysinfo) { dump_sysinfo (); if (!check_setup) { puts (""); dump_setup (verbose, NULL, false); } if (!givehelp) puts ("Use -h to see help about each section"); } return 0; }