/* cygcheck.cc Copyright 1998 Cygnus Solutions. 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 int verbose = 0; int registry = 0; int sysinfo = 0; int givehelp = 0; #ifdef __GNUC__ typedef long long longlong; #else typedef __int64 longlong; #endif 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; } common_apps[] = { { "bash", 0 }, { "cat", 0 }, { "cpp", 1 }, { "find", 0 }, { "gcc", 0 }, { "gdb", 0 }, { "ld", 0 }, { "ls", 0 }, { "make", 0 }, { "sh", 0 }, { 0, 0 } }; int num_paths = 0, max_paths = 0; char **paths = 0; 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); 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) return; num_paths++; } void init_paths () { char tmp[4000], *sl; add_path ((char *) ".", 1); /* to be replaced later */ add_path ((char *) ".", 1); /* the current directory */ GetSystemDirectory (tmp, 4000); add_path (tmp, strlen (tmp)); sl = strrchr (tmp, '\\'); if (sl) { strcpy (sl, "\\SYSTEM"); add_path (tmp, strlen (tmp)); } GetWindowsDirectory (tmp, 4000); add_path (tmp, strlen (tmp)); char *path = getenv ("PATH"); if (path) { char wpath[4000]; cygwin_posix_to_win32_path_list (path, wpath); char *b, *e, sep = ':'; if (strchr (wpath, ';')) sep = ';'; b = wpath; while (1) { for (e = b; *e && *e != sep; e++); add_path (b, e - b); if (!*e) break; b = e + 1; } } else printf ("WARNING: PATH is not set at all!\n"); } 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 (strchr (file, ':') || strchr (file, '\\') || strchr (file, '/')) return file; 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; }; Did *did = 0; Did * already_did (char *file) { Did *d; for (d = did; d; d = d->next) if (strcasecmp (d->file, file) == 0) return d; d = new Did; d->file = strdup (file); d->next = did; d->state = DID_NEW; did = d; return d; } int get_word (HANDLE fh, int offset) { short rv; unsigned r; SetFilePointer (fh, offset, 0, FILE_BEGIN); ReadFile (fh, &rv, 2, (DWORD *) &r, 0); return rv; } int get_dword (HANDLE fh, int offset) { int rv; unsigned r; SetFilePointer (fh, offset, 0, FILE_BEGIN); ReadFile (fh, &rv, 4, (DWORD *) &r, 0); return rv; } struct Section { char name[8]; int virtual_size; int virtual_address; int size_of_raw_data; int pointer_to_raw_data; }; int rva_to_offset (int rva, char *sections, int nsections, int *sz) { int i; 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; }; void track_down (char *file, char *suffix, int lvl); void dll_info (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]; SetFilePointer (fh, opthdr_ofs + 40, 0, FILE_BEGIN); ReadFile (fh, &v, sizeof (v), &junk, 0); 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); SetFilePointer (fh, pe_header_offset + 4 + 20 + get_word (fh, pe_header_offset + 4 + 16), 0, FILE_BEGIN); ReadFile (fh, sections, nsections * 40, &junk, 0); if (verbose && num_entries >= 1 && export_size > 0) { int expsz; int expbase = rva_to_offset (export_rva, sections, nsections, &expsz); if (expbase) { SetFilePointer (fh, expbase, 0, FILE_BEGIN); unsigned char *exp = (unsigned char *) malloc (expsz); ReadFile (fh, exp, expsz, &junk, 0); 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) { SetFilePointer (fh, impbase, 0, FILE_BEGIN); unsigned char *imp = (unsigned char *) malloc (impsz); ReadFile (fh, imp, impsz, &junk, 0); 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); } } } } void track_down (char *file, char *suffix, int lvl) { 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; } 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 (fh, lvl, 1); d->state = DID_INACTIVE; CloseHandle (fh); } 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; GetFileInformationByHandle (h, &info); SYSTEMTIME systime; FileTimeToSystemTime (&info.ftLastWriteTime, &systime); printf ("%5dk %04d/%02d/%02d %s", (((int) info.nFileSizeLow) + 512) / 1024, systime.wYear, systime.wMonth, systime.wDay, f); dll_info (h, 16, 0); CloseHandle (h); } 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; }; 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); } 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); char *value_data = (char *) malloc (max_valdata_len + 1); 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; } } #if 0 else { char tmp[400]; FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, 0, GetLastError (), MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), tmp, 400, 0); printf ("RegEnumValue: %s\n", tmp); } #endif } 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_ALL_ACCESS, &sKey) == ERROR_SUCCESS) { scan_registry (&ri, sKey, subkey_name, cygnus); RegCloseKey (sKey); } } } free (subkey_name); } void dump_sysinfo () { int i, j; char tmp[4000]; time_t now; printf ("\nCygnus Win95/NT Configuration Diagnostics\n"); time (&now); printf ("Current System Time: %s\n", ctime (&now)); OSVERSIONINFO osversion; osversion.dwOSVersionInfoSize = sizeof (osversion); GetVersionEx (&osversion); char *osname = (char *) "unknown OS"; switch (osversion.dwPlatformId) { case VER_PLATFORM_WIN32s: osname = (char *) "win32s"; break; case VER_PLATFORM_WIN32_WINDOWS: switch (osversion.dwMinorVersion) { case 0: osname = (char *) "Win95"; break; case 1: osname = (char *) "Win98"; break; default: osname = (char *) "Win9X"; break; } break; case VER_PLATFORM_WIN32_NT: osname = (char *) "WinNT"; break; default: osname = (char *) "uknown-os"; break; } printf ("%s Ver %d.%d build %d %s\n\n", osname, (int) osversion.dwMajorVersion, (int) osversion.dwMinorVersion, (int) osversion.dwBuildNumber, 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++); printf ("\t%.*s\n", e - s, s); count_path_items++; if (!*e) break; s = e + 1; } GetSystemDirectory (tmp, 4000); 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'); GetVolumeInformation (drive, name, sizeof (name), &serno, &maxnamelen, &flags, fsname, sizeof (fsname)); 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; } 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); } FreeLibrary (k32); 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 int ml_fsname = 4, ml_dir = 7, ml_type = 6; 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-"); } struct mntent *mnt; 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); 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); ls (tmp); } } found = FindNextFile (ff, &ffinfo); } FindClose (ff); } } void usage () { fprintf (stderr, "Usage: cygcheck [-s] [-v] [-r] [-h] [program ...]\n"); fprintf (stderr, " -s = system information\n"); fprintf (stderr, " -v = verbose output (indented) (for -s or programs)\n"); fprintf (stderr, " -r = registry search (requires -s)\n"); fprintf (stderr, " -h = give help about the info\n"); fprintf (stderr, "You must at least give either -s or a program name\n"); exit (1); } int main (int argc, char **argv) { int i; while (argc > 1 && argv[1][0] == '-') { if (strcmp (argv[1], "-v") == 0) verbose = 1; if (strcmp (argv[1], "-r") == 0) registry = 1; if (strcmp (argv[1], "-s") == 0) sysinfo = 1; if (strcmp (argv[1], "-h") == 0) givehelp = 1; argc--; argv++; } if (argc == 1 && !sysinfo) usage (); init_paths (); if (argc > 1 && givehelp) { if (argc == 2) { printf ("Here is where the OS will find your program, and which dlls\n"); printf ("will be used for it. Use -v to see DLL version info\n"); } else { printf ("Here is where the OS will find your programs, and which dlls\n"); printf ("will be used for them. Use -v to see DLL version info\n"); } if (!sysinfo) printf ("\n"); } for (i = 1; i < argc; i++) { cygcheck (argv[i]); printf ("\n"); } if (sysinfo) dump_sysinfo (); if (!givehelp) printf ("Use -h to see help about each section\n"); return 0; }