diff --git a/winsup/utils/ChangeLog b/winsup/utils/ChangeLog index 369f75ed3..5bdebcc85 100644 --- a/winsup/utils/ChangeLog +++ b/winsup/utils/ChangeLog @@ -1,3 +1,23 @@ +2009-10-31 Corinna Vinschen + + * cygcheck.cc: Include cygprops.h. + (del_orphaned_reg): New option variable. + (unique_object_name_opt): Ditto. + (handle_reg_installation): New function. + (print_reg_installations): Ditto. + (del_orphaned_reg_installations): Ditto. + (memmem): Ditto. + (handle_unique_object_name): Ditto. + (dump_sysinfo): Call print_reg_installations from here. + (usage): Add usage for new options --delete-orphaned-installation-keys, + --enable-unique-object-names, --disable-unique-object-names, and + --show-unique-object-names. + (longopts): Add new options --delete-orphaned-installation-keys, + --enable-unique-object-names, --disable-unique-object-names, and + --show-unique-object-names. + (main): Handle new options. + * utils.sgml (cygcheck): Change documentaion accordingly. + 2009-10-28 Corinna Vinschen * cygcheck.cc (pretty_id): Drop arguments. Don't change CYGWIN diff --git a/winsup/utils/cygcheck.cc b/winsup/utils/cygcheck.cc index a95ae0819..62065d25b 100644 --- a/winsup/utils/cygcheck.cc +++ b/winsup/utils/cygcheck.cc @@ -24,6 +24,7 @@ #include #include "cygwin/include/sys/cygwin.h" #include "cygwin/include/mntent.h" +#include "cygwin/cygprops.h" #undef cygwin_internal #define alloca __builtin_alloca @@ -38,6 +39,8 @@ int dump_only = 0; int find_package = 0; int list_package = 0; int grep_packages = 0; +int del_orphaned_reg = 0; +int unique_object_name_opt = 0; static char emptystr[] = ""; @@ -57,7 +60,8 @@ 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 version[] = "$Revision$"; @@ -120,6 +124,15 @@ static common_apps[] = { {0, 0} }; +/* Options without ASCII single char representation. */ +enum +{ + CO_DELETE_KEYS = 0x100, + CO_ENABLE_UON = 0x101, + CO_DISABLE_UON = 0x102, + CO_SHOW_UON = 0x103 +}; + static int num_paths, max_paths; struct pathlike { @@ -1203,6 +1216,172 @@ dump_sysinfo_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; +} + +int +handle_unique_object_name (int opt, char *path) +{ + HANDLE fh, fm; + void *haystack; + + if (!path || !*path) + usage (stderr, 1); + + DWORD access, share, protect, mapping; + + if (opt == CO_SHOW_UON) + { + access = GENERIC_READ; + share = FILE_SHARE_VALID_FLAGS; + protect = PAGE_READONLY; + mapping = FILE_MAP_READ; + } + else + { + access = GENERIC_READ | GENERIC_WRITE; + share = 0; + protect = PAGE_READWRITE; + mapping = FILE_MAP_WRITE; + } + + fh = CreateFile (path, access, share, NULL, OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, NULL); + if (fh == INVALID_HANDLE_VALUE) + { + DWORD err = GetLastError (); + switch (err) + { + case ERROR_SHARING_VIOLATION: + display_error ("%s still used by other Cygwin processes.\n" + "Please stop all of them and retry.", path); + break; + case ERROR_ACCESS_DENIED: + display_error ( + "Your permissions are not sufficient to change the file \"%s\"", + path); + break; + case ERROR_FILE_NOT_FOUND: + display_error ("%s: No such file.", path); + break; + default: + display_error (path, true, false); + break; + } + return 1; + } + if (!(fm = CreateFileMapping (fh, NULL, protect, 0, 0, NULL))) + display_error ("CreateFileMapping"); + else if (!(haystack = MapViewOfFile (fm, mapping, 0, 0, 0))) + display_error ("MapViewOfFile"); + else + { + size_t haystacklen = GetFileSize (fh, NULL); + cygwin_props_t *cygwin_props = (cygwin_props_t *) + memmem ((char *) haystack, haystacklen, + CYGWIN_PROPS_MAGIC, sizeof (CYGWIN_PROPS_MAGIC)); + if (!cygwin_props) + display_error ("Can't find Cygwin properties in %s", path); + else + { + if (opt != CO_SHOW_UON) + cygwin_props->disable_key = opt - CO_ENABLE_UON; + printf ("Unique object names are %s\n", + cygwin_props->disable_key ? "disabled" : "enabled"); + UnmapViewOfFile (haystack); + CloseHandle (fm); + CloseHandle (fh); + return 0; + } + } + if (haystack) + UnmapViewOfFile (haystack); + if (fm) + CloseHandle (fm); + CloseHandle (fh); + return 1; +} + static void dump_sysinfo () { @@ -1557,6 +1736,8 @@ dump_sysinfo () } printf ("obcaseinsensitive set to %lu\n\n", obcaseinsensitive); + print_reg_installations (); + if (givehelp) { printf ("Listing available drives...\n"); @@ -1987,6 +2168,10 @@ Usage: cygcheck [-v] [-h] PROGRAM\n\ cygcheck -f FILE [FILE]...\n\ cygcheck -l [PACKAGE]...\n\ cygcheck -p REGEXP\n\ + cygcheck --delete-orphaned-installation-keys\n\ + cygcheck --enable-unique-object-names Cygwin-DLL\n\ + cygcheck --disable-unique-object-names Cygwin-DLL\n\ + cygcheck --show-unique-object-names Cygwin-DLL\n\ cygcheck -h\n\n\ List system information, check installed packages, or query package database.\n\ \n\ @@ -2004,6 +2189,19 @@ At least one command option or a PROGRAM is required, as shown above.\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\ + --enable-unique-object-names Cygwin-DLL\n\ + --disable-unique-object-names Cygwin-DLL\n\ + --show-unique-object-names Cygwin-DLL\n\ + Enable, disable, or show the setting of the\n\ + \"unique object names\" setting in the Cygwin DLL\n\ + given as argument to this option. The DLL path must\n\ + be given as valid Windows(!) path.\n\ + See the users guide for more information.\n\ + If you don't know what this means, don't change it.\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\ @@ -2026,6 +2224,10 @@ struct option longopts[] = { {"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}, + {"enable-unique-object-names", no_argument, NULL, CO_ENABLE_UON}, + {"disable-unique-object-names", no_argument, NULL, CO_DISABLE_UON}, + {"show-unique-object-names", no_argument, NULL, CO_SHOW_UON}, {"help", no_argument, NULL, 'h'}, {"version", no_argument, 0, 'V'}, {0, no_argument, NULL, 0} @@ -2127,7 +2329,7 @@ main (int argc, char **argv) user's original environment. */ char *posixly = getenv ("POSIXLY_CORRECT"); if (posixly == NULL) - (void) putenv("POSIXLY_CORRECT=1"); + (void) putenv ("POSIXLY_CORRECT=1"); while ((i = getopt_long (argc, argv, opts, longopts, NULL)) != EOF) switch (i) { @@ -2161,6 +2363,14 @@ main (int argc, char **argv) case 'h': givehelp = 1; break; + case CO_DELETE_KEYS: + del_orphaned_reg = 1; + break; + case CO_ENABLE_UON: + case CO_DISABLE_UON: + case CO_SHOW_UON: + unique_object_name_opt = i; + break; case 'V': print_version (); exit (0); @@ -2172,7 +2382,8 @@ main (int argc, char **argv) if (posixly == NULL) putenv ("POSIXLY_CORRECT="); - if ((argc == 0) && !sysinfo && !keycheck && !check_setup && !list_package) + if ((argc == 0) && !sysinfo && !keycheck && !check_setup && !list_package + && !del_orphaned_reg) { if (givehelp) usage (stdout, 0); @@ -2180,11 +2391,18 @@ main (int argc, char **argv) usage (stderr, 1); } - if ((check_setup || sysinfo || find_package || list_package || grep_packages) + if ((check_setup || sysinfo || find_package || list_package || grep_packages + || del_orphaned_reg || unique_object_name_opt) && keycheck) usage (stderr, 1); - if ((find_package || list_package || grep_packages) && check_setup) + if ((find_package || list_package || grep_packages) + && (check_setup || del_orphaned_reg)) + usage (stderr, 1); + + if ((check_setup || sysinfo || find_package || list_package || grep_packages + || del_orphaned_reg) + && unique_object_name_opt) usage (stderr, 1); if (dump_only && !check_setup) @@ -2195,6 +2413,10 @@ main (int argc, char **argv) if (keycheck) return check_keys (); + if (unique_object_name_opt) + return handle_unique_object_name (unique_object_name_opt, *argv); + if (del_orphaned_reg) + del_orphaned_reg_installations (); if (grep_packages) return package_grep (*argv); diff --git a/winsup/utils/utils.sgml b/winsup/utils/utils.sgml index 2e6e9c1c0..e255779ab 100644 --- a/winsup/utils/utils.sgml +++ b/winsup/utils/utils.sgml @@ -13,13 +13,18 @@ command-line utilities support the --help and cygcheck -Usage: cygcheck PROGRAM [ -v ] [ -h ] - cygcheck -c [ PACKAGE ... ] [ -d ] - cygcheck -s [ -r ] [ -v ] [ -h ] +Usage: cygcheck [-v] [-h] PROGRAM + cygcheck -c [-d] [PACKAGE] + cygcheck -s [-r] [-v] [-h] cygcheck -k - cygcheck -f FILE [ FILE ... ] - cygcheck -l [ PACKAGE ... ] + cygcheck -f FILE [FILE]... + cygcheck -l [PACKAGE]... cygcheck -p REGEXP + cygcheck --delete-orphaned-installation-keys + cygcheck --enable-unique-object-names Cygwin-DLL + cygcheck --disable-unique-object-names Cygwin-DLL + cygcheck --show-unique-object-names Cygwin-DLL + cygcheck -h List system information, check installed packages, or query package database. At least one command option or a PROGRAM is required, as shown above. @@ -36,6 +41,19 @@ At least one command option or a PROGRAM is required, as shown above. -l, --list-package list contents of PACKAGE (or all packages if none given) -p, --package-query search for REGEXP in the entire cygwin.com package repository (requires internet connectivity) + --delete-orphaned-installation-keys + Delete installation keys of old, now unused + installations from the registry. Requires the right + to change the registry. + --enable-unique-object-names Cygwin-DLL + --disable-unique-object-names Cygwin-DLL + --show-unique-object-names Cygwin-DLL + Enable, disable, or show the setting of the + \"unique object names\" setting in the Cygwin DLL + given as argument to this option. The DLL path must + be given as valid Windows(!) path. + See the users guide for more information. + If you don't know what this means, don't change it. -v, --verbose produce more verbose output -h, --help annotate output with explanatory comments when given with another command, otherwise print this help @@ -184,6 +202,65 @@ for example: $ cygcheck -s -v -r -h > cygcheck_output.txt + +Each Cygwin DLL stores its path and installation key in the registry. +This allows troubleshooting of problems which could be a result of having +multiple concurrent Cygwin installations. However, if you're experimenting +a lot with different Cygwin installation paths, your registry could +accumulate a lot of old Cygwin installation entries for which the +installation doesn't exist anymore. To get rid of these orphaned registry +entries, use the cygcheck --delete-orphaned-installation-keys +command. + + +Each Cygwin DLL generates a key value from its installation path. This +value is not only stored in the registry, it's also used to generate +global object names used for interprocess communication. This keeps +different Cygwin installations separate. Processes running under a +Cygwin DLL installed in C:\cygwin don't see processes running under a +Cygwin DLL installed in C:\Program Files\cygwin. This allows +running multiple versions of Cygwin DLLs without these versions to +interfere with each other, or to run small third-party installations +for a specific purpose independently from a Cygwin net distribution. + + + +For debugging purposes it could be desired that the various Cygwin DLLs +use the same key, independently from their installation paths. If the +DLLs have different versions, trying to run processes under these DLLs +concurrently will result in error messages like this one: + + +*** shared version mismatch detected - 0x8A88009C/0x75BE0074. +This problem is probably due to using incompatible versions of the cygwin DLL. +Search for cygwin1.dll using the Windows Start->Find/Search facility +and delete all but the most recent version. The most recent version *should* +reside in x:\\cygwin\\bin, where 'x' is the drive on which you have +installed the cygwin distribution. Rebooting is also suggested if you +are unable to find another cygwin DLL. + + + +To disable the usage of a unique key value of a certain Cygwin DLL, use +the cygcheck --disable-unique-object-names Cygwin-DLL +command. Cygwin-DLL is the Windows path (*not* a +Cygwin POSIX path) to the DLL for which you want to disable this feature. +Note that you have to stop all Cygwin processes running under this DLL, +before you're allowed to change this setting. For instance, run +cygcheck from a DOS command line for this purpose. + +To re-enable the usage of a unique key, use the +cygcheck --enable-unique-object-names Cygwin-DLL command. +This option has the same characteristics as the +--disable-unique-object-names option + +Finally, you can use +cygcheck --show-unique-object-names Cygwin-DLL to find out +if the given Cygwin DLL use unique object names or not. In contrast to the +--disable-... and --enable-... options, +the --show-unique-object-names option also works for +Cygwin DLLs which are currently in use. + cygpath