Avoid collisions between parallel installations of Cygwin

Corinna Vinschen corinna-cygwin@cygwin.com
Tue Oct 20 19:19:00 GMT 2009


On Oct 20 20:36, Corinna Vinschen wrote:
> Well, I don't care, I can also add version info.  The real problem is
> that the BeginUpdateResource/UpdateResource/EndUpdateResource functions
> apparently destroy the DLL!
> [...]

Btw., for those who want to experiment, this is the current state of the
patch.  It's feature-complete, it's just missing a bit of cleanup, the
version info in the resource, and changing the resource value via
cygcheck is broken as outlined in my previous mail.  Oh yes, the
documentation is missing as well.

The new options in cygcheck are:

  --enable-unique-object-names
  --disable-unique-object-names
  --show-unique-object-names

  --delete-orphaned-installation-keys
  ... and -s additionally prints all the keys accumulated in HKLM and HKCU,
  together with it's orphan state.

I omit the ChangeLog for now.


Corinna

Index: cygserver/transport_pipes.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygserver/transport_pipes.cc,v
retrieving revision 1.10
diff -u -p -r1.10 transport_pipes.cc
--- cygserver/transport_pipes.cc	15 Sep 2004 10:17:53 -0000	1.10
+++ cygserver/transport_pipes.cc	20 Oct 2009 19:12:47 -0000
@@ -1,6 +1,6 @@
 /* transport_pipes.cc
 
-   Copyright 2001, 2002, 2003, 2004 Red Hat Inc.
+   Copyright 2001, 2002, 2003, 2004, 2009 Red Hat Inc.
 
    Written by Robert Collins <rbtcollins@hotmail.com>
 
@@ -23,6 +23,8 @@ details. */
 #include <netdb.h>
 #include <pthread.h>
 #include <unistd.h>
+#include <wchar.h>
+#include <sys/cygwin.h>
 
 #include "cygerrno.h"
 #include "transport.h"
@@ -65,24 +67,33 @@ initialise_pipe_instance_lock ()
 #ifndef __INSIDE_CYGWIN__
 
 transport_layer_pipes::transport_layer_pipes (const HANDLE hPipe)
-  : _pipe_name (""),
-    _hPipe (hPipe),
+  : _hPipe (hPipe),
     _is_accepted_endpoint (true),
     _is_listening_endpoint (false)
 {
   assert (_hPipe);
   assert (_hPipe != INVALID_HANDLE_VALUE);
-
+  _pipe_name[0] = L'\0';
 }
 
 #endif /* !__INSIDE_CYGWIN__ */
 
 transport_layer_pipes::transport_layer_pipes ()
-  : _pipe_name ("\\\\.\\pipe\\cygwin_lpc"),
-    _hPipe (NULL),
+  : _hPipe (NULL),
     _is_accepted_endpoint (false),
     _is_listening_endpoint (false)
 {
+#ifdef __INSIDE_CYGWIN__
+  extern WCHAR installation_key_buf[18];
+  wcpcpy (wcpcpy (wcpcpy (_pipe_name, PIPE_NAME_PREFIX), installation_key_buf),
+	  PIPE_NAME_SUFFIX);
+#else
+  wchar_t cyg_instkey[18];
+
+  wchar_t *p = wcpcpy (_pipe_name, PIPE_NAME_PREFIX);
+  if (cygwin_internal (CW_GET_INSTKEY, cyg_instkey))
+    wcpcpy (wcpcpy (p, cyg_instkey), PIPE_NAME_SUFFIX);
+#endif
 }
 
 transport_layer_pipes::~transport_layer_pipes ()
@@ -124,7 +135,7 @@ transport_layer_pipes::accept (bool *con
   const bool first_instance = (pipe_instance == 0);
 
   const HANDLE accept_pipe =
-    CreateNamedPipe (_pipe_name,
+    CreateNamedPipeW (_pipe_name,
 		     (PIPE_ACCESS_DUPLEX
 		      | (first_instance ? FILE_FLAG_FIRST_PIPE_INSTANCE : 0)),
 		     (PIPE_TYPE_BYTE | PIPE_WAIT),
@@ -270,13 +281,13 @@ transport_layer_pipes::connect ()
 
   while (rc)
     {
-      _hPipe = CreateFile (_pipe_name,
-			   GENERIC_READ | GENERIC_WRITE,
-			   FILE_SHARE_READ | FILE_SHARE_WRITE,
-			   &sec_all_nih,
-			   OPEN_EXISTING,
-			   SECURITY_IMPERSONATION,
-			   NULL);
+      _hPipe = CreateFileW (_pipe_name,
+			    GENERIC_READ | GENERIC_WRITE,
+			    FILE_SHARE_READ | FILE_SHARE_WRITE,
+			    &sec_all_nih,
+			    OPEN_EXISTING,
+			    SECURITY_IMPERSONATION,
+			    NULL);
 
       if (_hPipe != INVALID_HANDLE_VALUE)
 	{
@@ -302,7 +313,7 @@ transport_layer_pipes::connect ()
        * with ERROR_FILE_NOT_FOUND.
        */
       while (retries != MAX_WAIT_NAMED_PIPE_RETRY
-	     && !(rc = WaitNamedPipe (_pipe_name, WAIT_NAMED_PIPE_TIMEOUT)))
+	     && !(rc = WaitNamedPipeW (_pipe_name, WAIT_NAMED_PIPE_TIMEOUT)))
 	{
 	  if (GetLastError () == ERROR_FILE_NOT_FOUND)
 	    Sleep (0);		// Give the server a chance.
Index: cygserver/transport_pipes.h
===================================================================
RCS file: /cvs/src/src/winsup/cygserver/transport_pipes.h,v
retrieving revision 1.1
diff -u -p -r1.1 transport_pipes.h
--- cygserver/transport_pipes.h	19 Nov 2003 18:49:41 -0000	1.1
+++ cygserver/transport_pipes.h	20 Oct 2009 19:12:47 -0000
@@ -13,6 +13,9 @@ details. */
 #ifndef _TRANSPORT_PIPES_H
 #define _TRANSPORT_PIPES_H
 
+#define PIPE_NAME_PREFIX	L"\\\\.\\pipe\\cygwin-"
+#define PIPE_NAME_SUFFIX	L"-lpc"
+
 /* Named pipes based transport, for security on NT */
 class transport_layer_pipes : public transport_layer_base
 {
@@ -36,7 +39,7 @@ public:
   virtual ~transport_layer_pipes ();
 
 private:
-  const char *const _pipe_name;
+  wchar_t _pipe_name[40];
   HANDLE _hPipe;
   const bool _is_accepted_endpoint;
   bool _is_listening_endpoint;
Index: cygwin/dtable.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/dtable.cc,v
retrieving revision 1.206
diff -u -p -r1.206 dtable.cc
--- cygwin/dtable.cc	22 Sep 2009 04:09:02 -0000	1.206
+++ cygwin/dtable.cc	20 Oct 2009 19:12:47 -0000
@@ -929,6 +929,14 @@ handle_to_fn (HANDLE h, char *posix_fn)
 	  if (wcsncmp (w32, L"cygwin-", WCLEN (L"cygwin-")) != 0)
 	    return false;
 	  w32 += WCLEN (L"cygwin-");
+	  /* Check for installation key and trailing dash. */
+	  w32len = installation_key.Length / sizeof (WCHAR);
+	  if (w32len && wcsncmp (w32, installation_key.Buffer, w32len) != 0)
+	    return false;
+	  w32 += w32len;
+	  if (*w32 != L'-')
+	    return false;
+	  ++w32;
 	  bool istty = wcsncmp (w32, L"tty", WCLEN (L"tty")) == 0;
 	  if (istty)
 	    decode_tty (posix_fn, w32 + WCLEN (L"tty"));
Index: cygwin/external.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/external.cc,v
retrieving revision 1.111
diff -u -p -r1.111 external.cc
--- cygwin/external.cc	14 Oct 2009 04:17:05 -0000	1.111
+++ cygwin/external.cc	20 Oct 2009 19:12:47 -0000
@@ -460,6 +460,14 @@ cygwin_internal (cygwin_getinfo_types t,
 	  res = 0;
 	}
 	break;
+      case CW_GET_INSTKEY:
+	{
+	  extern WCHAR installation_key_buf[18];
+	  PWCHAR dest = va_arg (arg, PWCHAR);
+	  wcscpy (dest, installation_key_buf);
+	  res = 0;
+	}
+	break;
 
       default:
 	set_errno (ENOSYS);
Index: cygwin/fhandler_fifo.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/fhandler_fifo.cc,v
retrieving revision 1.35
diff -u -p -r1.35 fhandler_fifo.cc
--- cygwin/fhandler_fifo.cc	24 Jul 2009 20:54:33 -0000	1.35
+++ cygwin/fhandler_fifo.cc	20 Oct 2009 19:12:48 -0000
@@ -19,6 +19,7 @@
 #include "cygheap.h"
 #include "sigproc.h"
 #include "cygtls.h"
+#include "shared_info.h"
 
 fhandler_fifo::fhandler_fifo ():
   wait_state (fifo_unknown), dummy_client (NULL)
@@ -58,8 +59,8 @@ char *
 fhandler_fifo::fifo_name (char *buf)
 {
   /* Generate a semi-unique name to associate with this fifo. */
-  __small_sprintf (buf, "\\\\.\\pipe\\__cygfifo__%08x_%016X",
-		   get_dev (), get_ino ());
+  __small_sprintf (buf, "\\\\.\\pipe\\__cygfifo__%S_%08x_%016X",
+		   &installation_key, get_dev (), get_ino ());
   return buf;
 }
 
Index: cygwin/mount.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/mount.cc,v
retrieving revision 1.50
diff -u -p -r1.50 mount.cc
--- cygwin/mount.cc	25 Aug 2009 11:27:03 -0000	1.50
+++ cygwin/mount.cc	20 Oct 2009 19:12:48 -0000
@@ -350,7 +350,7 @@ mount_info::init ()
   PWCHAR pathend;
   WCHAR path[PATH_MAX];
 
-  pathend = wcpcpy (path, cygwin_shared->installation_root);
+  pathend = wcpcpy (path, installation_root);
   create_root_entry (path);
   pathend = wcpcpy (pathend, L"\\etc\\fstab");
 
Index: cygwin/pipe.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/pipe.cc,v
retrieving revision 1.117
diff -u -p -r1.117 pipe.cc
--- cygwin/pipe.cc	17 Aug 2009 12:45:51 -0000	1.117
+++ cygwin/pipe.cc	20 Oct 2009 19:12:48 -0000
@@ -21,6 +21,7 @@ details. */
 #include "dtable.h"
 #include "cygheap.h"
 #include "pinfo.h"
+#include "shared_info.h"
 
 fhandler_pipe::fhandler_pipe ()
   : fhandler_base (), popen_pid (0), overlapped (NULL)
@@ -216,7 +217,10 @@ fhandler_pipe::create_selectable (LPSECU
   if (psize < PIPE_BUF)
     psize = PIPE_BUF;
 
-  char pipename[MAX_PATH] = PIPE_INTRO;
+  char pipename[MAX_PATH];
+  const size_t len = __small_sprintf (pipename, PIPE_INTRO "%S-",
+				      &installation_key);
+
   /* FIXME: Eventually make ttys work with overlapped I/O. */
   DWORD overlapped = name ? 0 : FILE_FLAG_OVERLAPPED;
 
@@ -228,10 +232,10 @@ fhandler_pipe::create_selectable (LPSECU
     {
       static volatile ULONG pipe_unique_id;
       if (!name)
-	__small_sprintf (pipename + strlen(PIPE_INTRO), "pipe-%p-%p", myself->pid,
+	__small_sprintf (pipename + len, "pipe-%p-%p", myself->pid,
 			InterlockedIncrement ((LONG *) &pipe_unique_id));
       else
-	strcpy (pipename + strlen(PIPE_INTRO), name);
+	strcpy (pipename + len, name);
 
       debug_printf ("CreateNamedPipe: name %s, size %lu", pipename, psize);
 
Index: cygwin/shared.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/shared.cc,v
retrieving revision 1.127
diff -u -p -r1.127 shared.cc
--- cygwin/shared.cc	8 Jun 2009 03:53:40 -0000	1.127
+++ cygwin/shared.cc	20 Oct 2009 19:12:48 -0000
@@ -26,12 +26,111 @@ details. */
 #include "ntdll.h"
 #include <alloca.h>
 #include <wchar.h>
+#include <wingdi.h>
+#include <winuser.h>
 
 shared_info NO_COPY *cygwin_shared;
 user_info NO_COPY *user_shared;
 HANDLE NO_COPY cygwin_shared_h;
 HANDLE NO_COPY cygwin_user_h;
 
+WCHAR installation_root[PATH_MAX] __attribute__((section (".cygwin_dll_common"), shared));
+UNICODE_STRING installation_key __attribute__((section (".cygwin_dll_common"), shared));
+WCHAR installation_key_buf[18] __attribute__((section (".cygwin_dll_common"), shared));
+
+/* Use absolute path of cygwin1.dll to derive the Win32 dir which
+   is our installation_root.  Note that we can't handle Cygwin installation
+   root dirs of more than 4K path length.  I assume that's ok...
+
+   This function also generates the installation_key value.  It's a 64 bit
+   hash value based on the path of the Cygwin DLL itself.  It's subsequently
+   used when generating shared object names.  Thus, different Cygwin
+   installations generate different object names and so are isolated from
+   each other.
+   
+   Having this information, the installation key together with the
+   installation root path is written to the registry.  The idea is that
+   cygcheck can print the paths into which the Cygwin DLL has been
+   installed for debugging purposes.
+   
+   Last but not least, the resource section of the DLL is checked for the
+   value in the resource section, which is used to determine whether the
+   installation key is actually added to all object names or not.  This is
+   used as a last resort for debugging purposes, usually.  However, there
+   could be another good reason to re-enable object name collisions between
+   multiple Cygwin DLLs, which we're just not aware of right now. */
+void
+init_installation_root ()
+{
+  if (!GetModuleFileNameW (cygwin_hmodule, installation_root, PATH_MAX))
+    api_fatal ("Can't initialize Cygwin installation root dir.\n"
+	       "GetModuleFileNameW(%p, %p, %u), %E",
+	       cygwin_hmodule, installation_root, PATH_MAX);
+  PWCHAR p = installation_root;
+  if (wcsncmp (p, L"\\\\?\\", 4))	/* No long path prefix. */
+    {
+      if (!wcsncasecmp (p, L"\\\\", 2))	/* UNC */
+	{
+	  p = wcpcpy (p, L"\\??\\UN");
+	  GetModuleFileNameW (cygwin_hmodule, p, PATH_MAX - 6);
+	  *p = L'C';
+	}
+      else
+	{
+	  p = wcpcpy (p, L"\\??\\");
+	  GetModuleFileNameW (cygwin_hmodule, p, PATH_MAX - 4);
+	}
+    }
+  installation_root[1] = L'?';
+
+  RtlInitEmptyUnicodeString (&installation_key, installation_key_buf,
+			     sizeof installation_key_buf);
+  RtlInt64ToHexUnicodeString (hash_path_name (0, installation_root),
+			      &installation_key, FALSE);
+
+  PWCHAR w = wcsrchr (installation_root, L'\\');
+  if (w)
+    {
+      *w = L'\0';
+      w = wcsrchr (installation_root, L'\\');
+    }
+  if (!w)
+    api_fatal ("Can't initialize Cygwin installation root dir.\n"
+	       "Invalid DLL path");
+  *w = L'\0';
+
+  for (int i = 1; i >= 0; --i)
+    {
+      reg_key r (i, KEY_WRITE, CYGWIN_INFO_INSTALLATIONS_NAME, NULL);
+      if (r.set_string (installation_key_buf, installation_root)
+	  == ERROR_SUCCESS)
+      	break;
+    }
+
+  /* TODO: If we need more than just this one resource entry in future,
+	   then reading the properties from the resource section should
+	   be put into an extra function called very early. */
+  HRSRC res = FindResource (cygwin_hmodule, CYGWIN_RES_PROPS_NAME, RT_RCDATA);
+  if (res && SizeofResource (cygwin_hmodule, res) >= sizeof (ULONG))
+    {
+      HGLOBAL glb = LoadResource (cygwin_hmodule, res);
+      if (glb)
+	{
+	  LPVOID props = LockResource (glb);
+	  if (props)
+	    {
+	      ULONG disable_key = *(PULONG) props;
+	      if (disable_key)
+		{
+		  installation_key.Length = 0;
+		  installation_key.Buffer[0] = L'\0';
+		}
+	    }
+	  FreeResource (glb);
+	}
+    }
+}
+
 /* This function returns a handle to the top-level directory in the global
    NT namespace used to implement global objects including shared memory. */
 
@@ -46,9 +145,10 @@ get_shared_parent_dir ()
   if (!dir)
     {
       WCHAR bnoname[MAX_PATH];
-      __small_swprintf (bnoname, L"\\BaseNamedObjects\\%s%s",
+      __small_swprintf (bnoname, L"\\BaseNamedObjects\\%s%s-%S",
 			cygwin_version.shared_id,
-			_cygwin_testing ? cygwin_version.dll_build_date : "");
+			_cygwin_testing ? cygwin_version.dll_build_date : "",
+			&installation_key);
       RtlInitUnicodeString (&uname, bnoname);
       InitializeObjectAttributes (&attr, &uname, OBJ_INHERIT | OBJ_OPENIF,
 				  NULL, everyone_sd (CYG_SHARED_DIR_ACCESS));
@@ -79,9 +179,10 @@ get_session_parent_dir ()
 	{
 	  WCHAR bnoname[MAX_PATH];
 	  __small_swprintf (bnoname,
-			    L"\\Sessions\\BNOLINKS\\%d\\%s%s",
+			    L"\\Sessions\\BNOLINKS\\%d\\%s%s-%S",
 			    psi.SessionId, cygwin_version.shared_id,
-			    _cygwin_testing ? cygwin_version.dll_build_date : "");
+			    _cygwin_testing ? cygwin_version.dll_build_date : "",
+			    &installation_key);
 	  RtlInitUnicodeString (&uname, bnoname);
 	  InitializeObjectAttributes (&attr, &uname, OBJ_INHERIT | OBJ_OPENIF,
 				      NULL, everyone_sd(CYG_SHARED_DIR_ACCESS));
@@ -270,46 +371,6 @@ shared_destroy ()
   UnmapViewOfFile (user_shared);
 }
 
-/* Use absolute path of cygwin1.dll to derive the Win32 dir which
-   is our installation root.  Note that we can't handle Cygwin installation
-   root dirs of more than 4K path length.  I assume that's ok... */
-void
-shared_info::init_installation_root ()
-{
-  if (!GetModuleFileNameW (cygwin_hmodule, installation_root, PATH_MAX))
-    api_fatal ("Can't initialize Cygwin installation root dir.\n"
-	       "GetModuleFileNameW(%p, %p, %u), %E",
-	       cygwin_hmodule, installation_root, PATH_MAX);
-  PWCHAR p = installation_root;
-  if (wcsncmp (p, L"\\\\?\\", 4))	/* No long path prefix. */
-    {
-      if (!wcsncasecmp (p, L"\\\\", 2))	/* UNC */
-	{
-	  p = wcpcpy (p, L"\\??\\UN");
-	  GetModuleFileNameW (cygwin_hmodule, p, PATH_MAX - 6);
-	  *p = L'C';
-	}
-      else
-	{
-	  p = wcpcpy (p, L"\\??\\");
-	  GetModuleFileNameW (cygwin_hmodule, p, PATH_MAX - 4);
-	}
-    }
-  installation_root[1] = L'?';
-
-  PWCHAR w = wcsrchr (installation_root, L'\\');
-  if (w)
-    {
-      *w = L'\0';
-      w = wcsrchr (installation_root, L'\\');
-    }
-  if (!w)
-    api_fatal ("Can't initialize Cygwin installation root dir.\n"
-	       "Invalid DLL path");
-
-  *w = L'\0';
-}
-
 /* Initialize obcaseinsensitive.  Default to case insensitive on pre-XP. */
 void
 shared_info::init_obcaseinsensitive ()
@@ -349,7 +410,6 @@ shared_info::initialize ()
 
   if (!sversion)
     {
-      init_installation_root ();/* Initialize installation root dir. */
       init_obcaseinsensitive ();/* Initialize obcaseinsensitive. */
       tty.init ();		/* Initialize tty table.  */
       mt.initialize ();		/* Initialize shared tape information. */
@@ -373,6 +433,10 @@ memory_init (bool init_cygheap)
       cygheap->user.init ();
     }
 
+  /* Initialize installation root dir. */
+  if (!installation_root[0])
+    init_installation_root ();
+
   /* Initialize general shared memory */
   shared_locations sh_cygwin_shared;
   cygwin_shared = (shared_info *) open_shared (L"shared",
@@ -380,6 +444,11 @@ memory_init (bool init_cygheap)
 					       cygwin_shared_h,
 					       sizeof (*cygwin_shared),
 					       sh_cygwin_shared = SH_CYGWIN_SHARED);
+  /* Defer debug output printing the installation root and installation key
+     up to this point.  Debug output except for system_printf requires
+     the global shared memory to exist. */
+  debug_printf ("Installation root: <%W> key: <%S>",
+		installation_root, &installation_key);
   cygwin_shared->initialize ();
   user_shared_create (false);
 }
Index: cygwin/shared_info.h
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/shared_info.h,v
retrieving revision 1.84
diff -u -p -r1.84 shared_info.h
--- cygwin/shared_info.h	8 Jun 2009 03:53:40 -0000	1.84
+++ cygwin/shared_info.h	20 Oct 2009 19:12:48 -0000
@@ -29,9 +29,9 @@ public:
 				  cygwin_version.api_minor)
 #define SHARED_VERSION_MAGIC CYGWIN_VERSION_MAGIC (SHARED_MAGIC, SHARED_VERSION)
 
-#define SHARED_INFO_CB 39328
+#define SHARED_INFO_CB 31136
 
-#define CURR_SHARED_MAGIC 0x22f9ff0bU
+#define CURR_SHARED_MAGIC 0x18da899eU
 
 #define USER_VERSION	1	// increment when mount table changes and
 #define USER_VERSION_MAGIC CYGWIN_VERSION_MAGIC (USER_MAGIC, USER_VERSION)
@@ -51,12 +51,10 @@ class shared_info
   DWORD sys_mount_table_counter;
   tty_list tty;
   LONG last_used_bindresvport;
-  WCHAR installation_root[PATH_MAX];
   DWORD obcaseinsensitive;
   mtinfo mt;
 
   void initialize ();
-  void init_installation_root ();
   void init_obcaseinsensitive ();
   unsigned heap_chunk_size ();
   unsigned heap_slop_size ();
@@ -105,4 +103,6 @@ void *__stdcall open_shared (const WCHAR
 			     DWORD access = FILE_MAP_READ | FILE_MAP_WRITE);
 extern void user_shared_create (bool reinit);
 extern void user_shared_initialize ();
-
+extern void init_installation_root ();
+extern WCHAR installation_root[PATH_MAX];
+extern UNICODE_STRING installation_key;
Index: cygwin/uinfo.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/uinfo.cc,v
retrieving revision 1.170
diff -u -p -r1.170 uinfo.cc
--- cygwin/uinfo.cc	18 Oct 2009 09:07:13 -0000	1.170
+++ cygwin/uinfo.cc	20 Oct 2009 19:12:48 -0000
@@ -518,13 +518,13 @@ pwdgrp::load (const wchar_t *rel_path)
   curr_lines = 0;
 
   if (!path &&
-      !(path = (PWCHAR) malloc ((wcslen (cygwin_shared->installation_root)
+      !(path = (PWCHAR) malloc ((wcslen (installation_root)
 				 + wcslen (rel_path) + 1) * sizeof (WCHAR))))
     {
       paranoid_printf ("malloc (%W) failed", rel_path);
       goto out;
     }
-  wcpcpy (wcpcpy (path, cygwin_shared->installation_root), rel_path);
+  wcpcpy (wcpcpy (path, installation_root), rel_path);
   RtlInitUnicodeString (&upath, path);
 
   InitializeObjectAttributes (&attr, &upath, OBJ_CASE_INSENSITIVE, NULL, NULL);
Index: cygwin/winver.rc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/winver.rc,v
retrieving revision 1.8
diff -u -p -r1.8 winver.rc
--- cygwin/winver.rc	19 Feb 2009 16:12:02 -0000	1.8
+++ cygwin/winver.rc	20 Oct 2009 19:12:48 -0000
@@ -48,3 +48,9 @@ BEGIN
       VALUE "Translation", 0x409, 1200
   END
 END
+
+CYGWIN_RES_PROPS_NAME RCDATA
+BEGIN
+  0x0L	/* ULONG "disable_key".  Set to 0 means, enable unique installation
+	   key usage, disable with setting to != 0. */
+END
Index: cygwin/include/cygwin/version.h
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/include/cygwin/version.h,v
retrieving revision 1.301
diff -u -p -r1.301 version.h
--- cygwin/include/cygwin/version.h	13 Oct 2009 12:08:22 -0000	1.301
+++ cygwin/include/cygwin/version.h	20 Oct 2009 19:12:48 -0000
@@ -410,6 +410,11 @@ details. */
 
 #define CYGWIN_INFO_CYGWIN_REGISTRY_NAME "Cygwin"
 #define CYGWIN_INFO_PROGRAM_OPTIONS_NAME "Program Options"
+#define CYGWIN_INFO_INSTALLATIONS_NAME   "Installations"
+
+     /* Identifiers used in the DLLs resource section. */
+
+#define CYGWIN_RES_PROPS_NAME            "cygprops"
 
      /* The default cygdrive prefix. */
 
Index: cygwin/include/sys/cygwin.h
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/include/sys/cygwin.h,v
retrieving revision 1.82
diff -u -p -r1.82 cygwin.h
--- cygwin/include/sys/cygwin.h	13 Oct 2009 10:23:31 -0000	1.82
+++ cygwin/include/sys/cygwin.h	20 Oct 2009 19:12:48 -0000
@@ -144,7 +144,8 @@ typedef enum
     CW_SET_PRIV_KEY,
     CW_SETERRNO,
     CW_EXIT_PROCESS,
-    CW_SET_EXTERNAL_TOKEN
+    CW_SET_EXTERNAL_TOKEN,
+    CW_GET_INSTKEY
   } cygwin_getinfo_types;
 
 /* Token type for CW_SET_EXTERNAL_TOKEN */
Index: utils/cygcheck.cc
===================================================================
RCS file: /cvs/src/src/winsup/utils/cygcheck.cc,v
retrieving revision 1.119
diff -u -p -r1.119 cygcheck.cc
--- utils/cygcheck.cc	20 Oct 2009 15:26:33 -0000	1.119
+++ utils/cygcheck.cc	20 Oct 2009 19:12:49 -0000
@@ -24,6 +24,7 @@
 #include <getopt.h>
 #include "cygwin/include/sys/cygwin.h"
 #include "cygwin/include/mntent.h"
+#include "cygwin/include/cygwin/version.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: 1.119 $";
 
@@ -1207,6 +1211,137 @@ 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);
+}
+
+int
+handle_unique_object_name (int opt, char *path)
+{
+  HMODULE module;
+  HRSRC res;
+  HGLOBAL glb;
+  LPVOID props;
+
+  if (!path || !*path)
+    usage (stderr, 1);
+
+  if (!(module = LoadLibraryEx (path, NULL, LOAD_LIBRARY_AS_DATAFILE)))
+    display_error ("handle_unique_object_name: LoadLibraryEx()");
+  else if (!(res = FindResource (module, CYGWIN_RES_PROPS_NAME, RT_RCDATA)))
+    display_error ("handle_unique_object_name: FindResource()");
+  else if (!(glb = LoadResource (module, res)))
+    display_error ("handle_unique_object_name: LoadResource()");
+  else if (!(props = LockResource (glb)))
+    display_error ("handle_unique_object_name: LockResource()");
+  else
+    {
+      PULONG disable_key = (PULONG) props;
+      int ret = 1;
+
+      if (opt != 0x103)
+	{
+	  HANDLE update;
+	  DWORD size = SizeofResource (module, res);
+	  PVOID new_props = malloc (size);
+
+	  if (!new_props)
+	    display_error ("malloc", false, true);
+	  else
+	    {
+	      memcpy (new_props, props, size);
+	      disable_key = (PULONG) new_props;
+	      *disable_key = opt - 0x101;
+	      if (!(update = BeginUpdateResource (path, TRUE)))
+		display_error ("handle_unique_object_name: "
+			       "BeginUpdateResource()");
+	      else if (!UpdateResource (update, RT_RCDATA,
+	      				CYGWIN_RES_PROPS_NAME,
+					MAKELANGID (LANG_NEUTRAL,
+						    SUBLANG_NEUTRAL),
+					new_props, size))
+		{
+		  display_error ("handle_unique_object_name: UpdateResource()");
+		  EndUpdateResource (update, TRUE);
+		}
+	      else if (!EndUpdateResource (update, FALSE))
+		display_error ("handle_unique_object_name: "
+			       "EndUpdateResource()");
+	      else
+		ret = 0;
+	      if (ret)
+		return 1;
+	    }
+	}
+      printf ("Unique object names are %s\n",
+	      *disable_key ? "disabled" : "enabled");
+      return 0;
+    }
+  return 1;
+}
+
 static void
 dump_sysinfo ()
 {
@@ -1571,6 +1706,8 @@ dump_sysinfo ()
     }
   printf ("obcaseinsensitive set to %lu\n\n", obcaseinsensitive);
 
+  print_reg_installations ();
+
   if (givehelp)
     {
       printf ("Listing available drives...\n");
@@ -2018,6 +2155,19 @@ At least one command option or a PROGRAM
   -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\n\
+  --disable-unique-object-names\n\
+  --show-unique-object-names\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\
@@ -2040,6 +2190,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, 0x100},
+  {"enable-unique-object-names", no_argument, NULL, 0x101},
+  {"disable-unique-object-names", no_argument, NULL, 0x102},
+  {"show-unique-object-names", no_argument, NULL, 0x103},
   {"help", no_argument, NULL, 'h'},
   {"version", no_argument, 0, 'V'},
   {0, no_argument, NULL, 0}
@@ -2175,6 +2329,14 @@ main (int argc, char **argv)
       case 'h':
 	givehelp = 1;
 	break;
+      case 0x100:
+      	del_orphaned_reg = 1;
+	break;
+      case 0x101:
+      case 0x102:
+      case 0x103:
+      	unique_object_name_opt = i;
+	break;
       case 'V':
 	print_version ();
 	exit (0);
@@ -2186,7 +2348,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);
@@ -2194,11 +2357,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)
@@ -2209,6 +2379,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);
 



-- 
Corinna Vinschen                  Please, send mails regarding Cygwin to
Cygwin Project Co-Leader          cygwin AT cygwin DOT com
Red Hat



More information about the Cygwin-developers mailing list