OSDN Git Service

* select.cc (select_stuff::wait): Temporarily disallow APCS.
[pf3gnuchains/pf3gnuchains4x.git] / winsup / cygwin / shared.cc
1 /* shared.cc: shared data area support.
2
3    Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
4    2006, 2007, 2008, 2009, 2010, 2011 Red Hat, Inc.
5
6 This file is part of Cygwin.
7
8 This software is a copyrighted work licensed under the terms of the
9 Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
10 details. */
11
12 #include "winsup.h"
13 #include "miscfuncs.h"
14 #include <unistd.h>
15 #include "cygerrno.h"
16 #include "pinfo.h"
17 #include "path.h"
18 #include "fhandler.h"
19 #include "dtable.h"
20 #include "cygheap.h"
21 #include "heap.h"
22 #include "shared_info_magic.h"
23 #include "registry.h"
24 #include "cygwin_version.h"
25 #include "pwdgrp.h"
26 #include "spinlock.h"
27 #include <alloca.h>
28 #include <wchar.h>
29 #include <wingdi.h>
30 #include <winuser.h>
31
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;
36
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));
41
42 #define SPIN_WAIT 10000
43
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...
47
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
52    each other.
53
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.
58
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. */
66
67 void inline
68 init_installation_root ()
69 {
70   spinlock iri (installation_root_inited);
71   if (!iri)
72     {
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. */
79         {
80           if (!wcsncasecmp (p, L"\\\\", 2))     /* UNC */
81             {
82               p = wcpcpy (p, L"\\??\\UN");
83               GetModuleFileNameW (cygwin_hmodule, p, PATH_MAX - 6);
84               *p = L'C';
85             }
86           else
87             {
88               p = wcpcpy (p, L"\\??\\");
89               GetModuleFileNameW (cygwin_hmodule, p, PATH_MAX - 4);
90             }
91         }
92       installation_root[1] = L'?';
93
94       RtlInitEmptyUnicodeString (&installation_key, installation_key_buf,
95                                  sizeof installation_key_buf);
96       RtlInt64ToHexUnicodeString (hash_path_name (0, installation_root),
97                                   &installation_key, FALSE);
98
99       PWCHAR w = wcsrchr (installation_root, L'\\');
100       if (w)
101         {
102           *w = L'\0';
103           w = wcsrchr (installation_root, L'\\');
104         }
105       if (!w)
106         api_fatal ("Can't initialize Cygwin installation root dir.\n"
107                    "Invalid DLL path");
108       *w = L'\0';
109
110       for (int i = 1; i >= 0; --i)
111         {
112           reg_key r (i, KEY_WRITE, _WIDE (CYGWIN_INFO_INSTALLATIONS_NAME),
113                      NULL);
114           if (NT_SUCCESS (r.set_string (installation_key_buf,
115                                         installation_root)))
116             break;
117         }
118
119       if (cygwin_props.disable_key)
120         {
121           installation_key.Length = 0;
122           installation_key.Buffer[0] = L'\0';
123         }
124     }
125 }
126
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. */
129
130 static HANDLE NO_COPY shared_parent_dir;
131
132 HANDLE
133 get_shared_parent_dir ()
134 {
135   UNICODE_STRING uname;
136   OBJECT_ATTRIBUTES attr;
137   NTSTATUS status;
138
139   if (!shared_parent_dir)
140     {
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 : "",
145                         &installation_key);
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);
153     }
154   return shared_parent_dir;
155 }
156
157 static HANDLE NO_COPY session_parent_dir;
158
159 HANDLE
160 get_session_parent_dir ()
161 {
162   UNICODE_STRING uname;
163   OBJECT_ATTRIBUTES attr;
164   NTSTATUS status;
165
166   if (!session_parent_dir)
167     {
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 ();
174       else
175         {
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 : "",
181                             &installation_key);
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);
189         }
190     }
191   return session_parent_dir;
192 }
193
194 char * __stdcall
195 shared_name (char *ret_buf, const char *str, int num)
196 {
197   __small_sprintf (ret_buf, "%s.%d", str, num);
198   return ret_buf;
199 }
200
201 WCHAR * __stdcall
202 shared_name (WCHAR *ret_buf, const WCHAR *str, int num)
203 {
204   __small_swprintf (ret_buf, L"%W.%d", str, num);
205   return ret_buf;
206 }
207
208 #define page_const (65535)
209 #define pround(n) (((size_t) (n) + page_const) & ~page_const)
210
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[] =
218 {
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)),
229   0
230 };
231
232 #define off_addr(x)     ((void *)((caddr_t) cygwin_hmodule + offsets[x]))
233
234 void * __stdcall
235 open_shared (const WCHAR *name, int n, HANDLE& shared_h, DWORD size,
236              shared_locations m, PSECURITY_ATTRIBUTES psa, DWORD access)
237 {
238   return open_shared (name, n, shared_h, size, &m, psa, access);
239 }
240
241 void * __stdcall
242 open_shared (const WCHAR *name, int n, HANDLE& shared_h, DWORD size,
243              shared_locations *m, PSECURITY_ATTRIBUTES psa, DWORD access)
244 {
245   void *shared;
246
247   void *addr;
248   if (*m == SH_JUSTCREATE || *m == SH_JUSTOPEN)
249     addr = NULL;
250   else
251     {
252       addr = off_addr (*m);
253       VirtualFree (addr, 0, MEM_RELEASE);
254     }
255
256   WCHAR map_buf[MAX_PATH];
257   WCHAR *mapname = NULL;
258
259   if (shared_h)
260     *m = SH_JUSTOPEN;
261   else
262     {
263       if (name)
264         mapname = shared_name (map_buf, name, n);
265       if (*m == SH_JUSTOPEN)
266         shared_h = OpenFileMappingW (access, FALSE, mapname);
267       else
268         {
269           shared_h = CreateFileMappingW (INVALID_HANDLE_VALUE, psa,
270                                         PAGE_READWRITE, 0, size, mapname);
271           if (GetLastError () == ERROR_ALREADY_EXISTS)
272             *m = SH_JUSTOPEN;
273         }
274       if (shared_h)
275         /* ok! */;
276       else if (*m != SH_JUSTOPEN)
277         api_fatal ("CreateFileMapping %W, %E.  Terminating.", mapname);
278       else
279         return NULL;
280     }
281
282   shared = (shared_info *) MapViewOfFileEx (shared_h, access, 0, 0, 0, addr);
283
284   if (!shared && addr)
285     {
286       shared = (shared_info *) MapViewOfFileEx (shared_h,
287                                        FILE_MAP_READ|FILE_MAP_WRITE,
288                                        0, 0, 0, NULL);
289 #ifdef DEBUGGING
290       system_printf ("relocating shared object %W(%d) from %p to %p", name, n, addr, shared);
291 #endif
292       offsets[0] = 0;
293     }
294
295   if (!shared)
296     api_fatal ("MapViewOfFileEx '%W'(%p), %E.  Terminating.", mapname, shared_h);
297
298   if (*m == SH_CYGWIN_SHARED && offsets[0])
299     {
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++)
304         {
305           DWORD size = offsets[i - 1] - offsets[i];
306           if (!VirtualAlloc (off_addr (i), size, MEM_RESERVE, PAGE_NOACCESS))
307             continue;  /* oh well */
308         }
309     }
310
311   debug_printf ("name %W, n %d, shared %p (wanted %p), h %p, *m %d",
312                 mapname, n, shared, addr, shared_h, *m);
313
314   return shared;
315 }
316
317 /* Second half of user shared initialization: Initialize content. */
318 void
319 user_info::initialize ()
320 {
321   /* Wait for initialization of the Cygwin per-user shared, if necessary */
322   spinlock sversion (version, CURR_USER_MAGIC);
323   if (!sversion)
324     {
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. */
330       if (pw)
331         cygheap->user.set_name (pw->pw_name);
332       mountinfo.init ();        /* Initialize the mount table.  */
333     }
334   else if (sversion != CURR_USER_MAGIC)
335     sversion.multiple_cygwin_problem ("user shared memory version", version,
336                                       sversion);
337   else if (user_shared->cb != sizeof (*user_shared))
338     sversion.multiple_cygwin_problem ("user shared memory size", cb,
339                                       sizeof (*user_shared));
340 }
341
342 /* First half of user shared initialization: Create shared mem region. */
343 void
344 user_info::create (bool reinit)
345 {
346   WCHAR name[UNLEN + 1] = L""; /* Large enough for SID */
347
348   if (reinit)
349     {
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;
355     }
356
357   if (!cygwin_user_h)
358     cygheap->user.get_windows_id (name);
359
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);
366   if (reinit)
367     user_shared->initialize ();
368 }
369
370 void __stdcall
371 shared_destroy ()
372 {
373   ForceCloseHandle (cygwin_shared_h);
374   UnmapViewOfFile (cygwin_shared);
375   ForceCloseHandle (cygwin_user_h);
376   UnmapViewOfFile (user_shared);
377 }
378
379 /* Initialize obcaseinsensitive.  Default to case insensitive on pre-XP. */
380 void
381 shared_info::init_obcaseinsensitive ()
382 {
383   NTSTATUS status;
384   DWORD def_obcaseinsensitive = 1;
385
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 }
392   };
393   status = RtlQueryRegistryValues (RTL_REGISTRY_CONTROL,
394                                    L"Session Manager\\kernel",
395                                    tab, NULL, NULL);
396 }
397
398 void inline
399 shared_info::create ()
400 {
401   cygwin_shared = (shared_info *) open_shared (L"shared",
402                                                CYGWIN_VERSION_SHARED_DATA,
403                                                cygwin_shared_h,
404                                                sizeof (*cygwin_shared),
405                                                SH_CYGWIN_SHARED,
406                                                &sec_all_nih);
407   cygwin_shared->initialize ();
408 }
409
410 void
411 shared_info::initialize ()
412 {
413   spinlock sversion (version, CURR_SHARED_MAGIC);
414   if (!sversion)
415     {
416       cb = sizeof (*this);
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);
426     }
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",
432                    sizeof (*this), cb);
433   heap_init ();
434 }
435
436 void
437 memory_init (bool init_cygheap)
438 {
439   getpagesize ();
440
441   /* Initialize the Cygwin heap, if necessary */
442   if (init_cygheap)
443     {
444       cygheap_init ();
445       cygheap->user.init ();
446     }
447
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 */
451 }