1 /* shared.cc: shared data area support.
3 Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
4 2006, 2007, 2008, 2009, 2010, 2011 Red Hat, Inc.
6 This file is part of Cygwin.
8 This software is a copyrighted work licensed under the terms of the
9 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
13 #include "miscfuncs.h"
22 #include "shared_info_magic.h"
24 #include "cygwin_version.h"
32 shared_info NO_COPY *cygwin_shared;
33 user_info NO_COPY *user_shared;
34 HANDLE NO_COPY cygwin_shared_h;
35 HANDLE NO_COPY cygwin_user_h;
37 WCHAR installation_root[PATH_MAX] __attribute__((section (".cygwin_dll_common"), shared));
38 UNICODE_STRING installation_key __attribute__((section (".cygwin_dll_common"), shared));
39 WCHAR installation_key_buf[18] __attribute__((section (".cygwin_dll_common"), shared));
40 static LONG installation_root_inited __attribute__((section (".cygwin_dll_common"), shared));
42 #define SPIN_WAIT 10000
44 /* Use absolute path of cygwin1.dll to derive the Win32 dir which
45 is our installation_root. Note that we can't handle Cygwin installation
46 root dirs of more than 4K path length. I assume that's ok...
48 This function also generates the installation_key value. It's a 64 bit
49 hash value based on the path of the Cygwin DLL itself. It's subsequently
50 used when generating shared object names. Thus, different Cygwin
51 installations generate different object names and so are isolated from
54 Having this information, the installation key together with the
55 installation root path is written to the registry. The idea is that
56 cygcheck can print the paths into which the Cygwin DLL has been
57 installed for debugging purposes.
59 Last but not least, the new cygwin properties datastrcuture is checked
60 for the "disabled_key" value, which is used to determine whether the
61 installation key is actually added to all object names or not. This is
62 used as a last resort for debugging purposes, usually. However, there
63 could be another good reason to re-enable object name collisions between
64 multiple Cygwin DLLs, which we're just not aware of right now. Cygcheck
65 can be used to change the value in an existing Cygwin DLL binary. */
68 init_installation_root ()
70 spinlock iri (installation_root_inited);
73 if (!GetModuleFileNameW (cygwin_hmodule, installation_root, PATH_MAX))
74 api_fatal ("Can't initialize Cygwin installation root dir.\n"
75 "GetModuleFileNameW(%p, %p, %u), %E",
76 cygwin_hmodule, installation_root, PATH_MAX);
77 PWCHAR p = installation_root;
78 if (wcsncmp (p, L"\\\\?\\", 4)) /* No long path prefix. */
80 if (!wcsncasecmp (p, L"\\\\", 2)) /* UNC */
82 p = wcpcpy (p, L"\\??\\UN");
83 GetModuleFileNameW (cygwin_hmodule, p, PATH_MAX - 6);
88 p = wcpcpy (p, L"\\??\\");
89 GetModuleFileNameW (cygwin_hmodule, p, PATH_MAX - 4);
92 installation_root[1] = L'?';
94 RtlInitEmptyUnicodeString (&installation_key, installation_key_buf,
95 sizeof installation_key_buf);
96 RtlInt64ToHexUnicodeString (hash_path_name (0, installation_root),
97 &installation_key, FALSE);
99 PWCHAR w = wcsrchr (installation_root, L'\\');
103 w = wcsrchr (installation_root, L'\\');
106 api_fatal ("Can't initialize Cygwin installation root dir.\n"
110 for (int i = 1; i >= 0; --i)
112 reg_key r (i, KEY_WRITE, _WIDE (CYGWIN_INFO_INSTALLATIONS_NAME),
114 if (NT_SUCCESS (r.set_string (installation_key_buf,
119 if (cygwin_props.disable_key)
121 installation_key.Length = 0;
122 installation_key.Buffer[0] = L'\0';
127 /* This function returns a handle to the top-level directory in the global
128 NT namespace used to implement global objects including shared memory. */
130 static HANDLE NO_COPY shared_parent_dir;
133 get_shared_parent_dir ()
135 UNICODE_STRING uname;
136 OBJECT_ATTRIBUTES attr;
139 if (!shared_parent_dir)
141 WCHAR bnoname[MAX_PATH];
142 __small_swprintf (bnoname, L"\\BaseNamedObjects\\%s%s-%S",
143 cygwin_version.shared_id,
144 _cygwin_testing ? cygwin_version.dll_build_date : "",
146 RtlInitUnicodeString (&uname, bnoname);
147 InitializeObjectAttributes (&attr, &uname, OBJ_OPENIF, NULL,
148 everyone_sd (CYG_SHARED_DIR_ACCESS));
149 status = NtCreateDirectoryObject (&shared_parent_dir,
150 CYG_SHARED_DIR_ACCESS, &attr);
151 if (!NT_SUCCESS (status))
152 api_fatal ("NtCreateDirectoryObject(%S): %p", &uname, status);
154 return shared_parent_dir;
157 static HANDLE NO_COPY session_parent_dir;
160 get_session_parent_dir ()
162 UNICODE_STRING uname;
163 OBJECT_ATTRIBUTES attr;
166 if (!session_parent_dir)
168 PROCESS_SESSION_INFORMATION psi;
169 status = NtQueryInformationProcess (NtCurrentProcess (),
170 ProcessSessionInformation,
171 &psi, sizeof psi, NULL);
172 if (!NT_SUCCESS (status) || psi.SessionId == 0)
173 session_parent_dir = get_shared_parent_dir ();
176 WCHAR bnoname[MAX_PATH];
177 __small_swprintf (bnoname,
178 L"\\Sessions\\BNOLINKS\\%d\\%s%s-%S",
179 psi.SessionId, cygwin_version.shared_id,
180 _cygwin_testing ? cygwin_version.dll_build_date : "",
182 RtlInitUnicodeString (&uname, bnoname);
183 InitializeObjectAttributes (&attr, &uname, OBJ_OPENIF, NULL,
184 everyone_sd(CYG_SHARED_DIR_ACCESS));
185 status = NtCreateDirectoryObject (&session_parent_dir,
186 CYG_SHARED_DIR_ACCESS, &attr);
187 if (!NT_SUCCESS (status))
188 api_fatal ("NtCreateDirectoryObject(%S): %p", &uname, status);
191 return session_parent_dir;
195 shared_name (char *ret_buf, const char *str, int num)
197 __small_sprintf (ret_buf, "%s.%d", str, num);
202 shared_name (WCHAR *ret_buf, const WCHAR *str, int num)
204 __small_swprintf (ret_buf, L"%W.%d", str, num);
208 #define page_const (65535)
209 #define pround(n) (((size_t) (n) + page_const) & ~page_const)
211 /* The order in offsets is so that the constant blocks shared_info
212 and user_info are right below the cygwin DLL, then the pinfo block
213 which changes with each process. Below that is the console_state,
214 an optional block which only exists when running in a Windows console
215 window. Therefore, if we are not running in a console, we have 64K
216 more of contiguous memory below the Cygwin DLL. */
217 static ptrdiff_t offsets[] =
219 - pround (sizeof (shared_info)), /* SH_CYGWIN_SHARED */
220 - pround (sizeof (shared_info)) /* SH_USER_SHARED */
221 - pround (sizeof (user_info)),
222 - pround (sizeof (shared_info)) /* SH_MYSELF */
223 - pround (sizeof (user_info))
224 - pround (sizeof (_pinfo)),
225 - pround (sizeof (shared_info)) /* SH_SHARED_CONSOLE */
226 - pround (sizeof (user_info))
227 - pround (sizeof (_pinfo))
228 - pround (sizeof (fhandler_console::console_state)),
232 #define off_addr(x) ((void *)((caddr_t) cygwin_hmodule + offsets[x]))
235 open_shared (const WCHAR *name, int n, HANDLE& shared_h, DWORD size,
236 shared_locations m, PSECURITY_ATTRIBUTES psa, DWORD access)
238 return open_shared (name, n, shared_h, size, &m, psa, access);
242 open_shared (const WCHAR *name, int n, HANDLE& shared_h, DWORD size,
243 shared_locations *m, PSECURITY_ATTRIBUTES psa, DWORD access)
248 if (*m == SH_JUSTCREATE || *m == SH_JUSTOPEN)
252 addr = off_addr (*m);
253 VirtualFree (addr, 0, MEM_RELEASE);
256 WCHAR map_buf[MAX_PATH];
257 WCHAR *mapname = NULL;
264 mapname = shared_name (map_buf, name, n);
265 if (*m == SH_JUSTOPEN)
266 shared_h = OpenFileMappingW (access, FALSE, mapname);
269 shared_h = CreateFileMappingW (INVALID_HANDLE_VALUE, psa,
270 PAGE_READWRITE, 0, size, mapname);
271 if (GetLastError () == ERROR_ALREADY_EXISTS)
276 else if (*m != SH_JUSTOPEN)
277 api_fatal ("CreateFileMapping %W, %E. Terminating.", mapname);
282 shared = (shared_info *) MapViewOfFileEx (shared_h, access, 0, 0, 0, addr);
286 shared = (shared_info *) MapViewOfFileEx (shared_h,
287 FILE_MAP_READ|FILE_MAP_WRITE,
290 system_printf ("relocating shared object %W(%d) from %p to %p", name, n, addr, shared);
296 api_fatal ("MapViewOfFileEx '%W'(%p), %E. Terminating.", mapname, shared_h);
298 if (*m == SH_CYGWIN_SHARED && offsets[0])
300 /* Reserve subsequent shared memory areas in non-relocated case only.
301 There's no good reason to reserve the console shmem, because it's
302 not yet known if we will allocate it at all. */
303 for (int i = SH_USER_SHARED; i < SH_SHARED_CONSOLE; i++)
305 DWORD size = offsets[i - 1] - offsets[i];
306 if (!VirtualAlloc (off_addr (i), size, MEM_RESERVE, PAGE_NOACCESS))
307 continue; /* oh well */
311 debug_printf ("name %W, n %d, shared %p (wanted %p), h %p, *m %d",
312 mapname, n, shared, addr, shared_h, *m);
317 /* Second half of user shared initialization: Initialize content. */
319 user_info::initialize ()
321 /* Wait for initialization of the Cygwin per-user shared, if necessary */
322 spinlock sversion (version, CURR_USER_MAGIC);
325 cb = sizeof (*user_shared);
326 cygpsid sid (cygheap->user.sid ());
327 struct passwd *pw = internal_getpwsid (sid);
328 /* Correct the user name with what's defined in /etc/passwd before
329 loading the user fstab file. */
331 cygheap->user.set_name (pw->pw_name);
332 mountinfo.init (); /* Initialize the mount table. */
334 else if (sversion != CURR_USER_MAGIC)
335 sversion.multiple_cygwin_problem ("user shared memory version", version,
337 else if (user_shared->cb != sizeof (*user_shared))
338 sversion.multiple_cygwin_problem ("user shared memory size", cb,
339 sizeof (*user_shared));
342 /* First half of user shared initialization: Create shared mem region. */
344 user_info::create (bool reinit)
346 WCHAR name[UNLEN + 1] = L""; /* Large enough for SID */
350 if (!UnmapViewOfFile (user_shared))
351 debug_printf("UnmapViewOfFile %E");
352 if (!ForceCloseHandle (cygwin_user_h))
353 debug_printf("CloseHandle %E");
354 cygwin_user_h = NULL;
358 cygheap->user.get_windows_id (name);
360 user_shared = (user_info *) open_shared (name, USER_VERSION,
361 cygwin_user_h, sizeof (user_info),
362 SH_USER_SHARED, &sec_none);
363 debug_printf ("opening user shared for '%W' at %p", name, user_shared);
364 ProtectHandleINH (cygwin_user_h);
365 debug_printf ("user shared version %x", user_shared->version);
367 user_shared->initialize ();
373 ForceCloseHandle (cygwin_shared_h);
374 UnmapViewOfFile (cygwin_shared);
375 ForceCloseHandle (cygwin_user_h);
376 UnmapViewOfFile (user_shared);
379 /* Initialize obcaseinsensitive. Default to case insensitive on pre-XP. */
381 shared_info::init_obcaseinsensitive ()
384 DWORD def_obcaseinsensitive = 1;
386 obcaseinsensitive = def_obcaseinsensitive;
387 RTL_QUERY_REGISTRY_TABLE tab[2] = {
388 { NULL, RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOSTRING,
389 L"obcaseinsensitive", &obcaseinsensitive, REG_DWORD,
390 &def_obcaseinsensitive, sizeof (DWORD) },
391 { NULL, 0, NULL, NULL, 0, NULL, 0 }
393 status = RtlQueryRegistryValues (RTL_REGISTRY_CONTROL,
394 L"Session Manager\\kernel",
399 shared_info::create ()
401 cygwin_shared = (shared_info *) open_shared (L"shared",
402 CYGWIN_VERSION_SHARED_DATA,
404 sizeof (*cygwin_shared),
407 cygwin_shared->initialize ();
411 shared_info::initialize ()
413 spinlock sversion (version, CURR_SHARED_MAGIC);
417 get_session_parent_dir (); /* Create session dir if first process. */
418 init_obcaseinsensitive (); /* Initialize obcaseinsensitive */
419 tty.init (); /* Initialize tty table */
420 mt.initialize (); /* Initialize shared tape information */
421 /* Defer debug output printing the installation root and installation key
422 up to this point. Debug output except for system_printf requires
423 the global shared memory to exist. */
424 debug_printf ("Installation root: <%W> key: <%S>",
425 installation_root, &installation_key);
427 else if (sversion != (LONG) CURR_SHARED_MAGIC)
428 sversion.multiple_cygwin_problem ("system shared memory version",
429 sversion, CURR_SHARED_MAGIC);
430 else if (cb != sizeof (*this))
431 system_printf ("size of shared memory region changed from %u to %u",
437 memory_init (bool init_cygheap)
441 /* Initialize the Cygwin heap, if necessary */
445 cygheap->user.init ();
448 init_installation_root (); /* Initialize installation root dir */
449 shared_info::create (); /* Initialize global shared memory */
450 user_info::create (false); /* Initialize per-user shared memory */