Avoid collisions between parallel [...], take 2

Corinna Vinschen corinna-cygwin@cygwin.com
Thu Oct 22 11:55:00 GMT 2009


Ok, so, after all the discussions, this is the patch which comes
out of it.  I decided to keep the code to tweak the properties
setting in cygcheck.  I made it quick and simple by using file mapping
and memmem to search for the magic string.  It's always possible
to read the value, but it's only possible to change the value if
no Cygwin process is running.

As before, cygcheck prints the installation keys in the registry using
the -s option.  It also has four new options.  From the --help output:

  --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.

I hope the magic string I used to mark the cygwin properties is unique
enough, See the new cygprops.h file.  What's missing is the
documentation.  I'll add that as soon as the code has gone in.

Comments?


Corinna


cygserver ChangeLog:

        * transport_pipes.h (PIPE_NAME_PREFIX): New define.
        (PIPE_NAME_SUFFIX): Ditto.
        (class transport_layer_pipes): Convert _pipe_name from char pointer
        to wchar_t array.
        * transport_pipes.cc (transport_layer_pipes::transport_layer_pipes):
        Accommodate the fact that _pipe_name is a wchar_t array, rather than
        a char pointer.
        (transport_layer_pipes::transport_layer_pipes): Initialize _pipe_name
        with variable pipe name based in installation key fetched from Cygwin
        DLL.
        (transport_layer_pipes::accept): Call CreateNamedPipeW explicitely.
        (transport_layer_pipes::connect): Call CreateFileW and WaitNamedPipeW
        explicitely.

cygwin ChangeLog:

	* cygprops.h: New file.
        * dtable.cc (handle_to_fn): Add check for correct installation_key
        string in object name for pipes and ttys.
        * external.cc (cygwin_internal): Add CW_GET_INSTKEY to allow fetching
        the installation_key from cygserver.
        * fhandler_fifo.cc (fhandler_fifo::fifo_name): Add installation_key
        to fifo name.
	* globals.cc: Include cygprops.h.
	(_RDATA): Move slightly and add comment.
	(cygwin_props): Define.
        * mount.cc (mount_info::init): Accommodate the fact that
        installation_root is now a global variable in DLL common shared memory,
        rather than a member of cygwin_shared.
        * pipe.cc (fhandler_pipe::create_selectable): Add installation_key to
        pipe name.
        * shared.cc (installation_root): Define here for storage in DLL
        common shared memory.
        (installation_key): Ditto.
        (installation_key_buf): Ditto.
        (init_installation_root): Convert from shared_info method to ordinary
        function.  Add initializing installation_key.  Invalidate
	installation_key depending of value of disable_key property.  Add
	comment to explain.
        (get_shared_parent_dir): Add installation_key to directory name.
        (get_session_parent_dir): Ditto.
        (shared_info::initialize): Move call to init_installation_root from
        here...
        (memory_init): ...to here.  Add debug output to print installation root
        and installation key.  Add comment to explain why.
        * shared_info.h (SHARED_INFO_CB): Recalculate.
        (CURR_SHARED_MAGIC): Ditto.
        (class shared_info): Remove definition of installation_root and
        declaration of init_installation_root.
        (init_installation_root): Declare.
        (installation_root): Declare.
        (installation_key): Declare.
        * uinfo.cc (pwdgrp::load): Accommodate the fact that installation_root
        is now a global variable in DLL common shared memory.
	* include/cygwin/version.h: Bump API minor number.
	(CYGWIN_INFO_INSTALLATIONS_NAME): Add.
        * include/sys/cygwin.h (cygwin_getinfo_types): Add CW_GET_INSTKEY.

utils ChangeLog:

	* 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.


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	22 Oct 2009 11:54:28 -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	22 Oct 2009 11:54:28 -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/cygprops.h
===================================================================
RCS file: cygwin/cygprops.h
diff -N cygwin/cygprops.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ cygwin/cygprops.h	22 Oct 2009 11:54:29 -0000
@@ -0,0 +1,20 @@
+/* cygprops.h: Cygwin DLL properties
+
+   Copyright 2009 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. */
+
+/* DLL properties data. */
+struct cygwin_props_t
+{
+  char magic[68];
+  ULONG size;
+  ULONG disable_key;
+};
+
+#define CYGWIN_PROPS_MAGIC \
+  "Fortunately, I keep my feathers numbered for just such an emergency"
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	22 Oct 2009 11:54:30 -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	22 Oct 2009 11:54:30 -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	22 Oct 2009 11:54:30 -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/globals.cc
===================================================================
RCS file: /cvs/src/src/winsup/cygwin/globals.cc,v
retrieving revision 1.10
diff -u -p -r1.10 globals.cc
--- cygwin/globals.cc	6 Oct 2009 03:39:38 -0000	1.10
+++ cygwin/globals.cc	22 Oct 2009 11:54:30 -0000
@@ -13,6 +13,7 @@ details. */
 #include "winsup.h"
 #include "cygtls.h"
 #include "perprocess.h"
+#include "cygprops.h"
 #include "thread.h"
 #include <malloc.h>
 #include <cygwin/version.h>
@@ -72,6 +73,9 @@ char NO_COPY almost_null[1];
 
 char *old_title;
 
+/* Define globally used, but readonly variables using the _RDATA attribute. */
+#define _RDATA __attribute__ ((section(".rdata")))
+
 /* Heavily-used const UNICODE_STRINGs are defined here once.  The idea is a
    speed improvement by not having to initialize a UNICODE_STRING every time
    we make a string comparison.  The strings are not defined as const,
@@ -83,7 +87,6 @@ char *old_title;
         { Length: sizeof (_s) - sizeof (WCHAR), \
           MaximumLength: sizeof (_s), \
           Buffer: (PWSTR) (_s) }
-#define _RDATA __attribute__ ((section(".rdata")))
 UNICODE_STRING _RDATA ro_u_empty = _ROU (L"");
 UNICODE_STRING _RDATA ro_u_lnk = _ROU (L".lnk");
 UNICODE_STRING _RDATA ro_u_exe = _ROU (L".exe");
@@ -102,9 +105,22 @@ UNICODE_STRING _RDATA ro_u_sunwnfs = _RO
 UNICODE_STRING _RDATA ro_u_udf = _ROU (L"UDF");
 UNICODE_STRING _RDATA ro_u_unixfs = _ROU (L"UNIXFS");
 UNICODE_STRING _RDATA ro_u_volume = _ROU (L"\\??\\Volume{");
-#undef _RDATA
 #undef _ROU
 
+/* Cygwin properties are meant to be readonly data placed in the DLL, but
+   which can be changed by external tools to make adjustments to the
+   behaviour of a DLL based on the binary of the DLL itself.  This is
+   different from $CYGWIN since it only affects that very DLL, not all
+   DLLs which have access to the $CYGWIN environment variable. */
+cygwin_props_t _RDATA cygwin_props =
+{
+  CYGWIN_PROPS_MAGIC,
+  sizeof (cygwin_props_t),
+  0
+};
+
+#undef _RDATA
+
 extern "C"
 {
   /* This is an exported copy of environ which can be used by DLLs
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	22 Oct 2009 11:54:30 -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	22 Oct 2009 11:54:30 -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	22 Oct 2009 11:54:30 -0000
@@ -26,12 +26,96 @@ 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 new cygwin properties datastrcuture is checked
+   for the "disabled_key" value, 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.  Cygcheck
+   can be used to change the value in an existing Cygwin DLL binary. */
+
+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;
+    }
+
+  if (cygwin_props.disable_key)
+    {
+      installation_key.Length = 0;
+      installation_key.Buffer[0] = L'\0';
+    }
+}
+
 /* 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 +130,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 +164,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 +356,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 +395,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 +418,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 +429,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	22 Oct 2009 11:54:30 -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	22 Oct 2009 11:54:30 -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/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	22 Oct 2009 11:54:30 -0000
@@ -370,12 +370,13 @@ details. */
       214: Export execvpe, fexecve.
       215: CW_EXIT_PROCESS added.
       216: CW_SET_EXTERNAL_TOKEN added.
+      217: CW_GET_INSTKEY added.
      */
 
      /* Note that we forgot to bump the api for ualarm, strtoll, strtoull */
 
 #define CYGWIN_VERSION_API_MAJOR 0
-#define CYGWIN_VERSION_API_MINOR 216
+#define CYGWIN_VERSION_API_MINOR 217
 
      /* There is also a compatibity version number associated with the
 	shared memory regions.  It is incremented when incompatible
@@ -410,6 +411,7 @@ details. */
 
 #define CYGWIN_INFO_CYGWIN_REGISTRY_NAME "Cygwin"
 #define CYGWIN_INFO_PROGRAM_OPTIONS_NAME "Program Options"
+#define CYGWIN_INFO_INSTALLATIONS_NAME   "Installations"
 
      /* 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	22 Oct 2009 11:54:30 -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	22 Oct 2009 11:54:31 -0000
@@ -24,6 +24,7 @@
 #include <getopt.h>
 #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: 1.119 $";
 
@@ -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
 {
@@ -1207,6 +1220,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 ()
 {
@@ -1571,6 +1750,8 @@ dump_sysinfo ()
     }
   printf ("obcaseinsensitive set to %lu\n\n", obcaseinsensitive);
 
+  print_reg_installations ();
+
   if (givehelp)
     {
       printf ("Listing available drives...\n");
@@ -2018,6 +2199,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 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\
@@ -2040,6 +2234,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}
@@ -2141,7 +2339,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)
       {
@@ -2175,6 +2373,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);
@@ -2186,7 +2392,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 +2401,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 +2423,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