4
0
mirror of git://sourceware.org/git/newlib-cygwin.git synced 2025-01-15 19:09:58 +08:00
Christopher Faylor 44d2fc0a45 * autoload.cc: Call _api_fatal in asm.
* child_info.h: Redefine CURR_CHILD_INFO_MAGIC.
(child_info_fork::abort): Rename from handle_failure.  Change arguments.
* cygtls.h (_local_storage::ttybuf): New field.
* dcrt0.cc (vapi_fatal): Split api_fatal.  Add "in forked process" to message
when appropriate.
(api_fatal): Use vapi_fatal.
* devices.h: Make multiple inclusion safe.
(fh_devices): Add FH_CONS* stuff.  Reorder slightly.
(device): Eliminate anonymous union.  Add more ways to access minor/major.
(device::setunit): Accommodate no-longer-anonymous union.
(device::is_fs): Ditto.
(device::is_fs_special): Ditto.
(device::major): New function.
(device::minor): Ditto.
(device::is_device): New function.
(device::not_device): Ditto.
(device::operator int): New operator.
(device::operator fh_devices): Ditto.
(device::operator bool): Ditto.
(device::operator DWORD): Ditto.
(device::operator =): Ditto.
(isproc_dev): New function.
(isprocsys_dev): Ditto.
(iscons_dev): Ditto.
(istty_slave_dev): Ditto.
* devices.in: Add new "/dev/cons*" strings.  Accommodate no-longer-anonymous
union throughout.
(BRACK): Use more precise method for initialization.
* devices.cc: Regenerate.
* dtable.cc (dtable::stdio_init): Use get_cttyp instead of get_tty.
(dtable::find_archetype): Use new DWORD operator in device to test archetypes.
(dtable::init_std_file_from_handle): Use different method to initialize 'dev'.
Adapt to different ctty handling and accommodate /dev/cons*.
(fh_alloc): Accommodate no-longer-anonymous union.  Adapt to new /dev/cons*.
(build_fh_pc): Make debugging output more useful.
* exceptions.cc (ctrl_c_handler): Use get_cttyp instead of get_tty.
* external.cc (fillout_pinfo): Accommodate new cons* stuff.
* fhandler.cc (fhandler_base::read): Eliminate is_slow() test.
* fhandler.h (fhandler_base::*): Adapt to changes in device.h.
(fhandler_*::is_slow): Delete.
( fhandler_proc::get_proc_fhandler): Return fh_devices type.
* fhandler_console.cc (open_shared_console): New function.
(console_unit): New class.
(console_unit::console_unit): New constructor.
(enum_windows): New function.  Declare as friend to console_unit.
(fhandler_console::set_unit): New function.
(fhandler_console::get_tty_stuff): Call set_unit to set the unit number and
determine if initialization is needed.  Eliminate flags parameter.
(tty_list::get_cttyp): Rename (sorta) from get_tty.  Return pointer to correct
tty_min.
(fhandler_console::open): Adapt to elimination of argument to get_tty_stuff.
(fhandler_console::output_tcsetattr): Properly detect error condition.
(fhandler_console::fixup_after_fork_exec): Adapt to get_tty_stuff() setting tc
automatically.
* fhandler_proc.cc: Use FH_BAD rather than 0 throughout where using fh_devices
enum.
(fhandler_proc::get_proc_fhandler): Return fh_devices.  Adapt to devices.h
changes.
* fhandler_process.cc: Adapt to devices.h changes.  Use FH_BAD rather than 0
throughout where using fh_devices enum.
* fhandler_procnet.cc: Ditto.
* fhandler_procsys.cc: Ditto.
* fhandler_procsysvipc.cc: Ditto.
* fhandler_tape.cc (fhandler_dev_tape::fhandler_dev_tape): Ditto.
* fhandler_termios.cc (handler_termios::bg_check): Use tc->ttyname() rather
than assuming that we can construct a tty.
* fhandler_tty.cc (fhandler_tty_master::fhandler_tty_master): Just return
get_minor() of dev.
(fhandler_pty_master::process_slave_output): Add slightly more debugging info.
(fhandler_tty_slave::fhandler_tty_slave): Change name from ntty to unit.
(fhandler_pty_master::open): Ditto.
(fhandler_tty_slave::ioctl): Adapt to change which causes ctty to represent a
complete device.
(fhandler_tty_master::init_console): Add debugging for failure path.
(fhandler_pty_master::setup): Use get_unit() to retrieve unit number rather
than relying on raw ntty.
(fhandler_pty_master::setup): Ditto.
* fhandler_virtual.h (virt_tab_t): Redefine fhandler as fh_devices.
* fork.cc: Remove obsolete vfork stuff.
(frok::child): Don't assume that a ctty == 0 is valid.
* mount.cc (mount_info::conv_to_win32_path): Adapt to device struct changes.
(mount_info::conv_to_win32_path): Ditto.
* path.cc (path_conv::check): Retrive major/minor numbers via a method rather
than accessing them directly from device.  Rely on dev operators to
set/retrieve device information as required by device struct change.
* path.h (isproc_dev): Move to devices.h.
(isprocsys_dev): Ditto.
(isvirtual_dev): Ditto.
(path_conv:{isdevice,isfifo,isspecial,iscygdrive,issocket,get_devn,get_unitn}):
Use device methods to access/manipulate devices.
* pinfo.cc (pinfo::exit): Don't assume that ctty == 0 is valid.  Use iscons_dev
to determine if a device is a console.
(_pinfo::_ctty): Use device::parse to generate tty/cons name.
(_pinfo::set_ctty): Don't assume that ctty == 0 is valid.  Remove redundant
info from debugging.
* shared.cc (offsets): Remove console offset.
* shared_info.h (shared_locations): Ditto.
* syscalls.cc (umask): Use device methods to manipulate device information.
(ctermid): Use device::parse to generate term device name.
* tlsoffsets.h: Regenerate.
* tty.cc (ttyslot): Return minor number of ctty since ctty now represents a
full device.
(tty::create_master): Set ctty to a complete device.
(tty_list::attach): Rework to detect new /dev/cons* stuff.
(tty_list::terminate): Adapt to changes to ctty.
(tty_list::init): Adapt to change to setntty - pass in device major number.
(tty::exists): Use get_unit() to retrive tty unit number.
(tty::open_mutex): Ditto.
(tty::open_inuse): Ditto.
(tty::create_inuse): Ditto.
(tty::get_event): Ditto.
(tty_min::ttyname): Define new function.
* tty.h (tty_min::ntty): Redefine as fh_devices.
(tty::exists): Use get_unit() to retrive tty unit number.
(tty::open_mutex): Ditto.
(tty::open_inuse): Ditto.
(tty::create_inuse): Ditto.
(tty::get_event): Ditto.
(tty_min::ttyname): Declare new function.
(tty::getntty): Declare as const.
(tty_list::operator []): Assure that only minor part of argument is used.
* dll_init.cc (dll_list::alloc): Detect mismatch of data segments early issuing
an explicit error message if necessary.
* heap.cc (heap_init): Adapt to changes from fork->handle_failure to
fork->abort.
* pinfo.h (EXITCODE_FORK_FAILED): New enum.  (from Ryan Johnson)
* sigproc.cc (child_info_fork::abort): Rename from handle_failure.  Change
arguments to allow passing in a printf-like message.
* winsup.h (api_fatal): Delete macro definition.
(api_fatal): Redefine from __api_fatal.
(vapi_fatal): Declare new function.
* include/sys/strace.h (strace_vprintf): Define new macro.
* ntdll.h (_SYSTEM_INFORMATION_CLASS): Add SystemHandleInformation.
2011-05-28 18:17:09 +00:00

474 lines
14 KiB
C++

/* shared.cc: shared data area support.
Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
2006, 2007, 2008, 2009, 2010, 2011 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. */
#include "winsup.h"
#include "miscfuncs.h"
#include <unistd.h>
#include "cygerrno.h"
#include "pinfo.h"
#include "path.h"
#include "fhandler.h"
#include "dtable.h"
#include "cygheap.h"
#include "heap.h"
#include "shared_info_magic.h"
#include "registry.h"
#include "cygwin_version.h"
#include "pwdgrp.h"
#include "spinlock.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));
static LONG installation_root_inited __attribute__((section (".cygwin_dll_common"), shared));
#define SPIN_WAIT 10000
/* 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 inline
init_installation_root ()
{
spinlock iri (installation_root_inited);
if (!iri)
{
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, _WIDE (CYGWIN_INFO_INSTALLATIONS_NAME),
NULL);
if (NT_SUCCESS (r.set_string (installation_key_buf,
installation_root)))
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. */
HANDLE
get_shared_parent_dir ()
{
static HANDLE dir;
UNICODE_STRING uname;
OBJECT_ATTRIBUTES attr;
NTSTATUS status;
if (!dir)
{
WCHAR bnoname[MAX_PATH];
__small_swprintf (bnoname, L"\\BaseNamedObjects\\%s%s-%S",
cygwin_version.shared_id,
_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));
status = NtCreateDirectoryObject (&dir, CYG_SHARED_DIR_ACCESS, &attr);
if (!NT_SUCCESS (status))
api_fatal ("NtCreateDirectoryObject(%S): %p", &uname, status);
}
return dir;
}
HANDLE
get_session_parent_dir ()
{
static HANDLE dir;
UNICODE_STRING uname;
OBJECT_ATTRIBUTES attr;
NTSTATUS status;
if (!dir)
{
PROCESS_SESSION_INFORMATION psi;
status = NtQueryInformationProcess (NtCurrentProcess (),
ProcessSessionInformation,
&psi, sizeof psi, NULL);
if (!NT_SUCCESS (status) || psi.SessionId == 0)
dir = get_shared_parent_dir ();
else
{
WCHAR bnoname[MAX_PATH];
__small_swprintf (bnoname,
L"\\Sessions\\BNOLINKS\\%d\\%s%s-%S",
psi.SessionId, cygwin_version.shared_id,
_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));
status = NtCreateDirectoryObject (&dir, CYG_SHARED_DIR_ACCESS, &attr);
if (!NT_SUCCESS (status))
api_fatal ("NtCreateDirectoryObject(%S): %p", &uname, status);
}
}
return dir;
}
char * __stdcall
shared_name (char *ret_buf, const char *str, int num)
{
__small_sprintf (ret_buf, "%s.%d", str, num);
return ret_buf;
}
WCHAR * __stdcall
shared_name (WCHAR *ret_buf, const WCHAR *str, int num)
{
__small_swprintf (ret_buf, L"%W.%d", str, num);
return ret_buf;
}
#define page_const (65535)
#define pround(n) (((size_t) (n) + page_const) & ~page_const)
/* The order in offsets is so that the constant blocks shared_info
and user_info are right below the cygwin DLL, then the pinfo block
which changes with each process. */
static ptrdiff_t offsets[] =
{
- pround (sizeof (shared_info)),
- pround (sizeof (shared_info))
- pround (sizeof (user_info)),
- pround (sizeof (shared_info))
- pround (sizeof (user_info))
- pround (sizeof (_pinfo)),
- pround (sizeof (shared_info))
- pround (sizeof (user_info))
- pround (sizeof (_pinfo)),
0
};
#define off_addr(x) ((void *)((caddr_t) cygwin_hmodule + offsets[x]))
void * __stdcall
open_shared (const WCHAR *name, int n, HANDLE& shared_h, DWORD size,
shared_locations m, PSECURITY_ATTRIBUTES psa, DWORD access)
{
return open_shared (name, n, shared_h, size, &m, psa, access);
}
void * __stdcall
open_shared (const WCHAR *name, int n, HANDLE& shared_h, DWORD size,
shared_locations *m, PSECURITY_ATTRIBUTES psa, DWORD access)
{
void *shared;
void *addr;
if (*m == SH_JUSTCREATE || *m == SH_JUSTOPEN)
addr = NULL;
else
{
addr = off_addr (*m);
VirtualFree (addr, 0, MEM_RELEASE);
}
WCHAR map_buf[MAX_PATH];
WCHAR *mapname = NULL;
if (shared_h)
*m = SH_JUSTOPEN;
else
{
if (name)
mapname = shared_name (map_buf, name, n);
if (*m == SH_JUSTOPEN)
shared_h = OpenFileMappingW (access, FALSE, mapname);
else
{
shared_h = CreateFileMappingW (INVALID_HANDLE_VALUE, psa,
PAGE_READWRITE, 0, size, mapname);
if (GetLastError () == ERROR_ALREADY_EXISTS)
*m = SH_JUSTOPEN;
}
if (shared_h)
/* ok! */;
else if (*m != SH_JUSTOPEN)
api_fatal ("CreateFileMapping %W, %E. Terminating.", mapname);
else
return NULL;
}
shared = (shared_info *) MapViewOfFileEx (shared_h, access, 0, 0, 0, addr);
if (!shared && addr)
{
shared = (shared_info *) MapViewOfFileEx (shared_h,
FILE_MAP_READ|FILE_MAP_WRITE,
0, 0, 0, NULL);
#ifdef DEBUGGING
system_printf ("relocating shared object %W(%d) from %p to %p", name, n, addr, shared);
#endif
offsets[0] = 0;
}
if (!shared)
api_fatal ("MapViewOfFileEx '%W'(%p), %E. Terminating.", mapname, shared_h);
if (*m == SH_CYGWIN_SHARED && offsets[0])
{
ptrdiff_t delta = (caddr_t) shared - (caddr_t) off_addr (0);
offsets[0] = (caddr_t) shared - (caddr_t) cygwin_hmodule;
for (int i = SH_USER_SHARED + 1; i < SH_TOTAL_SIZE; i++)
{
unsigned size = offsets[i] - offsets[i + 1];
offsets[i] += delta;
if (!VirtualAlloc (off_addr (i), size, MEM_RESERVE, PAGE_NOACCESS))
continue; /* oh well */
}
offsets[SH_TOTAL_SIZE] += delta;
}
debug_printf ("name %W, n %d, shared %p (wanted %p), h %p", mapname, n, shared, addr, shared_h);
return shared;
}
/* Second half of user shared initialization: Initialize content. */
void
user_info::initialize ()
{
/* Wait for initialization of the Cygwin per-user shared, if necessary */
spinlock sversion (version, CURR_USER_MAGIC);
if (!sversion)
{
cb = sizeof (*user_shared);
cygpsid sid (cygheap->user.sid ());
struct passwd *pw = internal_getpwsid (sid);
/* Correct the user name with what's defined in /etc/passwd before
loading the user fstab file. */
if (pw)
cygheap->user.set_name (pw->pw_name);
mountinfo.init (); /* Initialize the mount table. */
}
else if (sversion != CURR_USER_MAGIC)
sversion.multiple_cygwin_problem ("user shared memory version", version,
sversion);
else if (user_shared->cb != sizeof (*user_shared))
sversion.multiple_cygwin_problem ("user shared memory size", cb,
sizeof (*user_shared));
}
/* First half of user shared initialization: Create shared mem region. */
void
user_info::create (bool reinit)
{
WCHAR name[UNLEN + 1] = L""; /* Large enough for SID */
if (reinit)
{
if (!UnmapViewOfFile (user_shared))
debug_printf("UnmapViewOfFile %E");
if (!ForceCloseHandle (cygwin_user_h))
debug_printf("CloseHandle %E");
cygwin_user_h = NULL;
}
if (!cygwin_user_h)
cygheap->user.get_windows_id (name);
user_shared = (user_info *) open_shared (name, USER_VERSION,
cygwin_user_h, sizeof (user_info),
SH_USER_SHARED, &sec_none);
debug_printf ("opening user shared for '%W' at %p", name, user_shared);
ProtectHandleINH (cygwin_user_h);
debug_printf ("user shared version %x", user_shared->version);
if (reinit)
user_shared->initialize ();
}
void __stdcall
shared_destroy ()
{
ForceCloseHandle (cygwin_shared_h);
UnmapViewOfFile (cygwin_shared);
ForceCloseHandle (cygwin_user_h);
UnmapViewOfFile (user_shared);
}
/* Initialize obcaseinsensitive. Default to case insensitive on pre-XP. */
void
shared_info::init_obcaseinsensitive ()
{
NTSTATUS status;
DWORD def_obcaseinsensitive = 1;
obcaseinsensitive = def_obcaseinsensitive;
RTL_QUERY_REGISTRY_TABLE tab[2] = {
{ NULL, RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOSTRING,
L"obcaseinsensitive", &obcaseinsensitive, REG_DWORD,
&def_obcaseinsensitive, sizeof (DWORD) },
{ NULL, 0, NULL, NULL, 0, NULL, 0 }
};
status = RtlQueryRegistryValues (RTL_REGISTRY_CONTROL,
L"Session Manager\\kernel",
tab, NULL, NULL);
}
void inline
shared_info::create ()
{
cygwin_shared = (shared_info *) open_shared (L"shared",
CYGWIN_VERSION_SHARED_DATA,
cygwin_shared_h,
sizeof (*cygwin_shared),
SH_CYGWIN_SHARED);
cygwin_shared->initialize ();
}
void
shared_info::initialize ()
{
spinlock sversion (version, CURR_SHARED_MAGIC);
if (!sversion)
{
cb = sizeof (*this);
get_session_parent_dir (); /* Create session dir if first process. */
init_obcaseinsensitive (); /* Initialize obcaseinsensitive */
tty.init (); /* Initialize tty table */
mt.initialize (); /* Initialize shared tape information */
/* 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);
}
else if (sversion != (LONG) CURR_SHARED_MAGIC)
sversion.multiple_cygwin_problem ("system shared memory version",
sversion, CURR_SHARED_MAGIC);
else if (cb != sizeof (*this))
system_printf ("size of shared memory region changed from %u to %u",
sizeof (*this), cb);
heap_init ();
}
void
memory_init (bool init_cygheap)
{
getpagesize ();
/* Initialize the Cygwin heap, if necessary */
if (init_cygheap)
{
cygheap_init ();
cygheap->user.init ();
}
init_installation_root (); /* Initialize installation root dir */
shared_info::create (); /* Initialize global shared memory */
user_info::create (false); /* Initialize per-user shared memory */
}
unsigned
shared_info::heap_chunk_size ()
{
if (!heap_chunk)
{
/* Fetch from registry, first user then local machine. */
for (int i = 0; i < 2; i++)
{
reg_key reg (i, KEY_READ, NULL);
/* Note that reserving a huge amount of heap space does not result in
the use of swap since we are not committing it. */
/* FIXME: We should not be restricted to a fixed size heap no matter
what the fixed size is. */
if ((heap_chunk = reg.get_dword (L"heap_chunk_in_mb", 0)))
break;
heap_chunk = 384; /* Default */
}
if (heap_chunk < 4)
heap_chunk = 4 * 1024 * 1024;
else
heap_chunk <<= 20;
if (!heap_chunk)
heap_chunk = 384 * 1024 * 1024;
}
return heap_chunk;
}