Don't use safe_new but new throughout. Fix copyright dates

throughout.
	* Makefile.in: Accomodate all new files and name changes.
	Add a *.d dependency.
	(sbindir): Add.
	(etcdir): Drop in favor of more appropriate sysconfdir definition.
	(sysconfdir): Add.
	(CXXFLAGS): Add -MMD flag. Add SYSCONFDIR definition.
	(.SUFFIXES): Add.
	(install): Add action items.
	(libclean): New target.
	(fullclean): Ditto.
	* bsd_helper.cc: New file.
	* bsd_helper.h: Ditto.
	* bsd_log.cc: Ditto.
	* bsd_log.h: Ditto.
	* bsd_mutex.cc: Ditto.
	* bsd_mutex.h: Ditto.
	* client.cc: Rearrange to build as less as possible if
	__INSIDE_CYGWIN__.
	(client_request::handle_request): Add Message Queue and Semaphore
	handling.
	* cygserver.cc: Rearrange to build as less as possible if
	__INSIDE_CYGWIN__. Use new debug/log/panic logging functions.
	(DEF_CONFIG_FILE): New definition for configuration file.  Use
	throughout.
	(getfunc): Remove.
	(__cygserver__printf): Remove.
	(client_request_attach_tty::serve): Return error if impersonation
	fails.
	(print_usage): Pump up help message.
	(print_version): Add output of default configuration file.
	(main): Accommodate new options.  Allow overwrite of threading options
	from config file.  Call several new initialization functions.  Drop
	printing dots.  Don't define SIGHANDLE inline.
	* cygserver.conf: New file.
	* cygserver_process.h: Rename to process.h.
	* cygserver_transport.h: Rename to transport.h.
	* cygserver_transport_pipes.h: Rename to transport_pipes.h.
	* cygserver_transport_sockets.h: Rename to transport_sockets.h.
	* msg.cc: Rewrite.
	* sem.cc: Rewrite.
	* shm.cc: Rewrite.
	* sysv_msg.cc: New file, derived from FreeBSD version 1.52.
	* sysv_sem.cc: New file, derived from FreeBSD version 1.66.
	* sysv_shm.cc: New file, derived from FreeBSD version 1.89.
	* threaded_queue.cc: Rearrange to build as less as possible if
	__INSIDE_CYGWIN__.
	* transport.cc (transport_layer_base::impersonate_client): Define bool.
	(transport_layer_base::revert_to_self): Ditto.
	* transport.h (transport_layer_base::impersonate_client): Declare bool.
	(transport_layer_base::revert_to_self): Ditto.
	* transport_pipes.cc (transport_layer_pipes::transport_layer_pipes):
	Don't call init_security.
	(init_security): Remove.
	(transport_layer_pipes::accept): Use global sec_all_nih.
	(transport_layer_pipes::connect): Ditto.
	(transport_layer_pipes::impersonate_client): Define bool.
	(transport_layer_pipes::revert_to_self): Ditt.
	* transport_pipes.h (transport_layer_pipes::impersonate_client): Declare
	bool.
	(transport_layer_pipes::revert_to_self): Ditto.
	* woutsup.h: Include bsd compatibility headers.
	(SIGHANDLE): Add definition.
	(__cygserver__printf): Remove definition.
	(__noop_printf): Ditto.
	(debug_printf): Define using debug.
	(syscall_printf): Define using log.
	(system_printf): Ditto.
	Drop all other _printf definitions.
This commit is contained in:
Corinna Vinschen 2003-11-19 18:49:41 +00:00
parent 64cfc6f213
commit 282113ba89
27 changed files with 5658 additions and 1370 deletions

View File

@ -1,3 +1,76 @@
2003-11-19 Corinna Vinschen <corinna@vinschen.de>
Don't use safe_new but new throughout. Fix copyright dates
throughout.
* Makefile.in: Accomodate all new files and name changes.
Add a *.d dependency.
(sbindir): Add.
(etcdir): Drop in favor of more appropriate sysconfdir definition.
(sysconfdir): Add.
(CXXFLAGS): Add -MMD flag. Add SYSCONFDIR definition.
(.SUFFIXES): Add.
(install): Add action items.
(libclean): New target.
(fullclean): Ditto.
* bsd_helper.cc: New file.
* bsd_helper.h: Ditto.
* bsd_log.cc: Ditto.
* bsd_log.h: Ditto.
* bsd_mutex.cc: Ditto.
* bsd_mutex.h: Ditto.
* client.cc: Rearrange to build as less as possible if
__INSIDE_CYGWIN__.
(client_request::handle_request): Add Message Queue and Semaphore
handling.
* cygserver.cc: Rearrange to build as less as possible if
__INSIDE_CYGWIN__. Use new debug/log/panic logging functions.
(DEF_CONFIG_FILE): New definition for configuration file. Use
throughout.
(getfunc): Remove.
(__cygserver__printf): Remove.
(client_request_attach_tty::serve): Return error if impersonation
fails.
(print_usage): Pump up help message.
(print_version): Add output of default configuration file.
(main): Accommodate new options. Allow overwrite of threading options
from config file. Call several new initialization functions. Drop
printing dots. Don't define SIGHANDLE inline.
* cygserver.conf: New file.
* cygserver_process.h: Rename to process.h.
* cygserver_transport.h: Rename to transport.h.
* cygserver_transport_pipes.h: Rename to transport_pipes.h.
* cygserver_transport_sockets.h: Rename to transport_sockets.h.
* msg.cc: Rewrite.
* sem.cc: Rewrite.
* shm.cc: Rewrite.
* sysv_msg.cc: New file, derived from FreeBSD version 1.52.
* sysv_sem.cc: New file, derived from FreeBSD version 1.66.
* sysv_shm.cc: New file, derived from FreeBSD version 1.89.
* threaded_queue.cc: Rearrange to build as less as possible if
__INSIDE_CYGWIN__.
* transport.cc (transport_layer_base::impersonate_client): Define bool.
(transport_layer_base::revert_to_self): Ditto.
* transport.h (transport_layer_base::impersonate_client): Declare bool.
(transport_layer_base::revert_to_self): Ditto.
* transport_pipes.cc (transport_layer_pipes::transport_layer_pipes):
Don't call init_security.
(init_security): Remove.
(transport_layer_pipes::accept): Use global sec_all_nih.
(transport_layer_pipes::connect): Ditto.
(transport_layer_pipes::impersonate_client): Define bool.
(transport_layer_pipes::revert_to_self): Ditt.
* transport_pipes.h (transport_layer_pipes::impersonate_client): Declare
bool.
(transport_layer_pipes::revert_to_self): Ditto.
* woutsup.h: Include bsd compatibility headers.
(SIGHANDLE): Add definition.
(__cygserver__printf): Remove definition.
(__noop_printf): Ditto.
(debug_printf): Define using debug.
(syscall_printf): Define using log.
(system_printf): Ditto.
Drop all other _printf definitions.
2003-10-22 Corinna Vinschen <corinna@vinschen.de> 2003-10-22 Corinna Vinschen <corinna@vinschen.de>
Accomodate moving cygserver header files from cygwin/include/cygwin Accomodate moving cygserver header files from cygwin/include/cygwin

View File

@ -15,7 +15,8 @@ prefix:=@prefix@
exec_prefix:=@exec_prefix@ exec_prefix:=@exec_prefix@
bindir:=@bindir@ bindir:=@bindir@
etcdir:=$(exec_prefix)/etc sbindir:=@sbindir@
sysconfdir:=@sysconfdir@
program_transform_name:=@program_transform_name@ program_transform_name:=@program_transform_name@
INSTALL:=@INSTALL@ INSTALL:=@INSTALL@
@ -28,14 +29,18 @@ CXX:=@CXX@
CXX_FOR_TARGET:=$(CXX) CXX_FOR_TARGET:=$(CXX)
AR:=@AR@ AR:=@AR@
CFLAGS:=@CFLAGS@ -I$(cygwin_source)
CXXFLAGS:=@CXXFLAGS@ -I$(cygwin_source)
override CXXFLAGS+=-fno-exceptions -fno-rtti -DHAVE_DECL_GETOPT=0 -D__OUTSIDE_CYGWIN__
include $(srcdir)/../Makefile.common include $(srcdir)/../Makefile.common
CFLAGS:=@CFLAGS@ -I$(cygwin_source)
CXXFLAGS:=@CXXFLAGS@ -I$(cygwin_source)
override CXXFLAGS+=-MMD -fno-exceptions -fno-rtti -DHAVE_DECL_GETOPT=0 -D__OUTSIDE_CYGWIN__ -DSYSCONFDIR="\"$(sysconfdir)\""
.SUFFIXES: .c .cc .a .o .d
OBJS:= cygserver.o client.o process.o msg.o sem.o shm.o threaded_queue.o \ OBJS:= cygserver.o client.o process.o msg.o sem.o shm.o threaded_queue.o \
transport.o transport_pipes.o transport_sockets.o transport.o transport_pipes.o transport_sockets.o \
bsd_helper.o bsd_log.o bsd_mutex.o \
sysv_msg.o sysv_sem.o sysv_shm.o
LIBOBJS:=${patsubst %.o,lib%.o,$(OBJS)} LIBOBJS:=${patsubst %.o,lib%.o,$(OBJS)}
CYGWIN_OBJS:=$(cygwin_build)/smallprint.o $(cygwin_build)/version.o \ CYGWIN_OBJS:=$(cygwin_build)/smallprint.o $(cygwin_build)/version.o \
@ -43,10 +48,17 @@ CYGWIN_OBJS:=$(cygwin_build)/smallprint.o $(cygwin_build)/version.o \
all: cygserver.exe all: cygserver.exe
install: all install: all cygserver.conf
$(INSTALL_PROGRAM) cygserver.exe $(sbindir)/cygserver.exe
$(INSTALL_DATA) $(srcdir)/cygserver.conf $(sysconfdir)/cygserver.conf
clean: clean:
rm -f $(OBJS) rm -f $(OBJS) ${patsubst %.o,%.d,$(OBJS)} cygserver.exe
libclean:
rm -f $(LIBOBJS) ${patsubst %.o,%.d,$(LIBOBJS)} libcygserver.a
fullclean: clean libclean
cygserver.exe: $(OBJS) $(CYGWIN_OBJS) cygserver.exe: $(OBJS) $(CYGWIN_OBJS)
$(CXX) -o $@ $^ $(CXX) -o $@ $^
@ -64,3 +76,8 @@ lib%.o: %.cc
libcygserver.a: $(LIBOBJS) libcygserver.a: $(LIBOBJS)
$(AR) crus $@ $? $(AR) crus $@ $?
deps:=${wildcard *.d}
ifneq (,$(deps))
include $(deps)
endif

View File

@ -0,0 +1,694 @@
/* bsd_helper.cc
Copyright 2003 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. */
#ifdef __OUTSIDE_CYGWIN__
#include "woutsup.h"
#include "cygerrno.h"
#define _KERNEL 1
#define __BSD_VISIBLE 1
#include <sys/smallprint.h>
#include <sys/cygwin.h>
#include <sys/ipc.h>
#include <sys/param.h>
#include <sys/msg.h>
#include <sys/queue.h>
#include <malloc.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "security.h"
#include "cygserver.h"
#include "process.h"
#include "cygserver_ipc.h"
#include "cygserver_msg.h"
#include "cygserver_sem.h"
#include "cygserver_shm.h"
/*
* Copy a piece of memory from the client process into the server process.
* Returns an error code.
*/
int
win_copyin (struct thread *td, const void *client_src,
void *server_tgt, size_t len)
{
if (!ReadProcessMemory (td->client->handle (), client_src, server_tgt,
len, NULL))
return cygwin_internal (CW_GET_ERRNO_FROM_WINERROR,
GetLastError (), EINVAL);
return 0;
}
/*
* Copy a piece of memory from the server process into the client process.
* Returns an error code.
*/
int
win_copyout (struct thread *td, const void *server_src,
void *client_tgt, size_t len)
{
if (!WriteProcessMemory (td->client->handle (), client_tgt, server_src,
len, NULL))
return cygwin_internal (CW_GET_ERRNO_FROM_WINERROR,
GetLastError (), EINVAL);
return 0;
}
#define enter_critical_section(c) _enter_critical_section((c),__FILE__,__LINE__)
static void
_enter_critical_section (LPCRITICAL_SECTION pcs, const char *file, int line)
{
_log (file, line, LOG_DEBUG, "Try enter critical section(%p)", pcs);
EnterCriticalSection (pcs);
_log (file, line, LOG_DEBUG, "Entered critical section(%p)", pcs);
}
#define leave_critical_section(c) _leave_critical_section((c),__FILE__,__LINE__)
static void
_leave_critical_section (LPCRITICAL_SECTION pcs, const char *file, int line)
{
LeaveCriticalSection (pcs);
_log (file, line, LOG_DEBUG, "Left critical section(%p)", pcs);
}
CRITICAL_SECTION ipcht_cs;
struct ipc_hookthread_storage {
HANDLE process_hdl;
proc ipcblk;
};
struct ipc_hookthread {
SLIST_ENTRY(ipc_hookthread) sht_next;
HANDLE thread;
DWORD winpid;
struct vmspace vmspace;
};
static SLIST_HEAD(, ipc_hookthread) ipcht_list; /* list of hook threads */
static HANDLE ipcexit_event;
struct vmspace *
ipc_p_vmspace (struct proc *proc)
{
struct vmspace *ret = NULL;
ipc_hookthread *ipcht_entry;
enter_critical_section (&ipcht_cs);
SLIST_FOREACH (ipcht_entry, &ipcht_list, sht_next)
{
if (ipcht_entry->winpid == proc->winpid)
{
ret = proc->p_vmspace = &ipcht_entry->vmspace;
break;
}
}
leave_critical_section (&ipcht_cs);
return ret;
}
static DWORD WINAPI
ipcexit_hookthread(const LPVOID param)
{
ipc_hookthread_storage *shs = (ipc_hookthread_storage *) param;
HANDLE obj[2] = { ipcexit_event, shs->process_hdl };
switch (WaitForMultipleObjects (2, obj, FALSE, INFINITE))
{
case WAIT_OBJECT_0:
/* Cygserver shutdown. */
/*FALLTHRU*/
case WAIT_OBJECT_0 + 1:
/* Process exited. Call semexit_myhook to handle SEM_UNDOs for the
exiting process and shmexit_myhook to keep track of shared
memory. */
if (Giant.owner == shs->ipcblk.winpid)
mtx_unlock (&Giant);
if (support_semaphores == TUN_TRUE)
semexit_myhook (NULL, &shs->ipcblk);
if (support_sharedmem == TUN_TRUE)
{
_mtx_lock (&Giant, shs->ipcblk.winpid, __FILE__, __LINE__);
ipc_p_vmspace (&shs->ipcblk);
shmexit_myhook (shs->ipcblk.p_vmspace);
mtx_unlock (&Giant);
}
break;
default:
/* FIXME: Panic? */
break;
}
CloseHandle (shs->process_hdl);
ipc_hookthread *ipcht_entry, *sav_entry;
enter_critical_section (&ipcht_cs);
SLIST_FOREACH_SAFE (ipcht_entry, &ipcht_list, sht_next, sav_entry)
{
if (ipcht_entry->winpid == shs->ipcblk.winpid)
{
SLIST_REMOVE (&ipcht_list, ipcht_entry, ipc_hookthread, sht_next);
delete ipcht_entry;
}
}
leave_critical_section (&ipcht_cs);
delete shs;
return 0;
}
/* Deletes all pending hook threads. Called by ipcunload() which in turn
is called by the cygserver main routine. */
static void
ipcexit_dispose_hookthreads(void)
{
SetEvent (ipcexit_event);
ipc_hookthread *ipcht_entry;
enter_critical_section (&ipcht_cs);
SLIST_FOREACH (ipcht_entry, &ipcht_list, sht_next)
{
WaitForSingleObject (ipcht_entry->thread, 1000);
/* Don't bother removing the linked list on cygserver shutdown. */
/* FIXME: Error handling? */
}
leave_critical_section (&ipcht_cs);
}
/* Creates the per process wait thread. Called by semget() under locked
Giant mutex condition. */
int
ipcexit_creat_hookthread(struct thread *td)
{
ipc_hookthread *ipcht_entry;
int ret = -1;
enter_critical_section (&ipcht_cs);
SLIST_FOREACH (ipcht_entry, &ipcht_list, sht_next)
{
if (ipcht_entry->winpid == td->ipcblk->winpid)
ret = 0;
}
leave_critical_section (&ipcht_cs);
if (!ret)
return 0;
DWORD tid;
ipc_hookthread_storage *shs = new ipc_hookthread_storage;
if (!DuplicateHandle (GetCurrentProcess (), td->client->handle (),
GetCurrentProcess (), &shs->process_hdl,
0, FALSE, DUPLICATE_SAME_ACCESS))
{
log (LOG_CRIT, "failed to duplicate process handle, error = %lu",
GetLastError ());
return cygwin_internal (CW_GET_ERRNO_FROM_WINERROR,
GetLastError (), ENOMEM);
}
shs->ipcblk = *td->ipcblk;
HANDLE thread = CreateThread (NULL, 0, ipcexit_hookthread, shs, 0, &tid);
if (!thread)
{
log (LOG_CRIT, "failed to create thread, error = %lu", GetLastError ());
return cygwin_internal (CW_GET_ERRNO_FROM_WINERROR,
GetLastError (), ENOMEM);
}
ipcht_entry = new ipc_hookthread;
ipcht_entry->thread = thread;
ipcht_entry->winpid = td->ipcblk->winpid;
ipcht_entry->vmspace.vm_map = NULL;
ipcht_entry->vmspace.vm_shm = NULL;
enter_critical_section (&ipcht_cs);
SLIST_INSERT_HEAD (&ipcht_list, ipcht_entry, sht_next);
leave_critical_section (&ipcht_cs);
return 0;
}
/*
* Need the admins group SID to compare with groups in client token.
*/
PSID admininstrator_group_sid;
static void
init_admin_sid (void)
{
if (wincap.has_security ())
{
SID_IDENTIFIER_AUTHORITY nt_auth = {SECURITY_NT_AUTHORITY};
if (! AllocateAndInitializeSid (&nt_auth, 2, 32, 544, 0, 0, 0, 0, 0, 0,
&admininstrator_group_sid))
panic ("failed to create well known sids, error = %lu",
GetLastError ());
}
}
SECURITY_DESCRIPTOR sec_all_nih_sd;
SECURITY_ATTRIBUTES sec_all_nih = { sizeof (SECURITY_ATTRIBUTES),
&sec_all_nih_sd,
FALSE };
/* Global vars, determining whether the IPC stuff should be started or not. */
tun_bool_t support_sharedmem = TUN_UNDEF;
tun_bool_t support_msgqueues = TUN_UNDEF;
tun_bool_t support_semaphores = TUN_UNDEF;
void
ipcinit ()
{
InitializeSecurityDescriptor (&sec_all_nih_sd, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl (&sec_all_nih_sd, TRUE, 0, FALSE);
init_admin_sid ();
mtx_init(&Giant, "Giant", NULL, MTX_DEF);
msleep_init ();
ipcexit_event = CreateEvent (NULL, TRUE, FALSE, NULL);
if (!ipcexit_event)
panic ("Failed to create ipcexit event object");
InitializeCriticalSection (&ipcht_cs);
if (support_msgqueues == TUN_TRUE)
msginit ();
if (support_semaphores == TUN_TRUE)
seminit ();
if (support_sharedmem == TUN_TRUE)
shminit ();
}
int
ipcunload ()
{
ipcexit_dispose_hookthreads();
CloseHandle (ipcexit_event);
wakeup_all ();
if (support_semaphores == TUN_TRUE)
semunload ();
if (support_sharedmem == TUN_TRUE)
shmunload ();
if (support_msgqueues == TUN_TRUE)
msgunload();
mtx_destroy(&Giant);
return 0;
}
/*
* Helper function to find a gid in a list of gids.
*/
static bool
is_grp_member (gid_t grp, gid_t *grplist, int listsize)
{
if (grplist)
for (; listsize > 0; --listsize)
if (grp == grplist[listsize - 1])
return true;
return false;
}
/*
* Helper function to get a specific token information from a token.
* This function mallocs the necessary buffer spcae by itself. It
* must be free'd by the calling function.
*/
static void *
get_token_info (HANDLE tok, TOKEN_INFORMATION_CLASS tic)
{
void *buf;
DWORD size;
if (!GetTokenInformation (tok, tic, NULL, 0, &size)
&& GetLastError () != ERROR_INSUFFICIENT_BUFFER)
return NULL;
if (!(buf = malloc (size)))
return NULL;
if (!GetTokenInformation (tok, tic, buf, size, &size))
{
free (buf);
return NULL;
}
return buf;
}
/*
* Check if client user helds "mode" permission when accessing object
* associated with "perm" permission record.
* Returns an error code.
*/
int
ipcperm (struct thread *td, ipc_perm *perm, unsigned int mode)
{
proc *p = td->ipcblk;
if (!suser (td))
return 0;
if (mode & IPC_M)
{
return (p->uid != perm->cuid && p->uid != perm->uid)
? EACCES : 0;
}
if (p->uid != perm->cuid && p->uid != perm->uid)
{
/* If the user is a member of the creator or owner group, test
against group bits, otherwise against other bits. */
mode >>= p->gid != perm->gid && p->gid != perm->cgid
&& !is_grp_member (perm->gid, p->gidlist, p->gidcnt)
&& !is_grp_member (perm->cgid, p->gidlist, p->gidcnt)
? 6 : 3;
}
return (mode & perm->mode) != mode ? EACCES : 0;
}
/*
* Check for client user being superuser.
* Returns an error code.
*/
int
suser (struct thread *td)
{
/* Always superuser on 9x. */
if (!wincap.has_security ())
return 0;
/* This value has been set at ImpersonateNamedPipeClient() time
using the token information. See adjust_identity_info() below. */
return td->ipcblk->is_admin ? 0 : EACCES;
}
/*
* Retrieves user and group info from impersonated token and creates the
* correct uid, gid, gidlist and is_admin entries in p from that.
*/
bool
adjust_identity_info (struct proc *p)
{
HANDLE tok;
/* No access tokens on 9x. */
if (!wincap.has_security ())
return true;
if (!OpenThreadToken (GetCurrentThread (), TOKEN_READ, TRUE, &tok))
{
debug ("Failed to open worker thread access token for pid %d, winpid %d",
p->cygpid, p->winpid);
return false;
}
/* Get uid from user SID in token. */
PTOKEN_USER user;
if (!(user = (PTOKEN_USER)get_token_info (tok, TokenUser)))
goto faulty;
p->uid = cygwin_internal (CW_GET_UID_FROM_SID, user->User.Sid);
free (user);
if (p->uid == (uid_t)-1)
log (LOG_WARNING, "WARNING: User not found in /etc/passwd! Using uid -1!");
/* Get gid from primary group SID in token. */
PTOKEN_PRIMARY_GROUP pgrp;
if (!(pgrp = (PTOKEN_PRIMARY_GROUP)get_token_info (tok, TokenPrimaryGroup)))
goto faulty;
p->gid = cygwin_internal (CW_GET_GID_FROM_SID, pgrp->PrimaryGroup);
free (pgrp);
if (p->gid == (gid_t)-1)
log (LOG_WARNING,"WARNING: Group not found in /etc/passwd! Using gid -1!");
/* Generate gid list from token group's SID list. Also look if the token
has an enabled admin group SID. That means, the process has admin
privileges. That knowledge is used in suser(). */
PTOKEN_GROUPS gsids;
if (!(gsids = (PTOKEN_GROUPS)get_token_info (tok, TokenGroups)))
goto faulty;
if (gsids->GroupCount)
{
p->gidlist = (gid_t *) calloc (gsids->GroupCount, sizeof (gid_t));
if (p->gidlist)
p->gidcnt = gsids->GroupCount;
}
for (DWORD i = 0; i < gsids->GroupCount; ++i)
{
if (p->gidlist)
p->gidlist[i] = cygwin_internal (CW_GET_GID_FROM_SID,
gsids->Groups[i].Sid);
if (EqualSid (gsids->Groups[i].Sid, admininstrator_group_sid)
&& (gsids->Groups[i].Attributes & SE_GROUP_ENABLED))
p->is_admin = true;
}
free (gsids);
CloseHandle (tok);
return true;
faulty:
CloseHandle (tok);
log (LOG_CRIT, "Failed to get token information for pid %d, winpid %d",
p->cygpid, p->winpid);
return false;
}
/*
* Windows wrapper implementation of the VM functions called by sysv_shm.cc.
*/
vm_object_t
_vm_pager_allocate (int size, int shmflg)
{
/* Create the file mapping object with full access for everyone. This is
necessary to allow later calls to shmctl(..., IPC_SET,...) to
change the access rights and ownership of a shared memory region.
The access rights are tested at the beginning of every shm... function.
Note that this does not influence the actual read or write access
defined in a call to shmat. */
vm_object_t object = CreateFileMapping (INVALID_HANDLE_VALUE, &sec_all_nih,
PAGE_READWRITE, 0, size, NULL);
if (!object)
panic ("CreateFileMapping in _vm_pager_allocate failed, %E");
return object;
}
vm_object_t
vm_object_duplicate (struct thread *td, vm_object_t object)
{
vm_object_t dup_object;
if (!DuplicateHandle(GetCurrentProcess (), object,
td->client->handle (), &dup_object,
0, TRUE, DUPLICATE_SAME_ACCESS))
panic ("!DuplicateHandle in vm_object_duplicate failed, %E");
return dup_object;
}
void
vm_object_deallocate (vm_object_t object)
{
if (object)
CloseHandle (object);
}
/*
* Tunable parameters are read from a system wide cygserver.conf file.
* On the first call to tunable_int_fetch, the file is read and the
* parameters are set accordingly. Each parameter has default, max and
* min settings.
*/
enum tun_params_type {
TUN_NULL,
TUN_INT,
TUN_BOOL
};
union tun_value {
long ival;
tun_bool_t bval;
};
struct tun_struct {
const char *name;
tun_params_type type;
union tun_value value;
union tun_value min;
union tun_value max;
void (*check_func)(tun_struct *, char *, const char *);
};
static void
default_tun_check (tun_struct *that, char *value, const char *fname)
{
char *c = NULL;
tun_value val;
switch (that->type)
{
case TUN_INT:
val.ival = strtoul (value, &c, 10);
if (!val.ival || (c && *c))
panic ("Error in config file %s: Value of parameter %s malformed",
fname, that->name);
if (val.ival < that->min.ival || val.ival > that->max.ival)
panic ("Error in config file %s: Value of parameter %s must be "
"between %lu and %lu",
fname, that->name, that->min.ival, that->max.ival);
if (that->value.ival)
panic ("Error in config file %s: Parameter %s set twice.\n",
fname, that->name);
that->value.ival = val.ival;
break;
case TUN_BOOL:
if (!strcasecmp (value, "no") || !strcasecmp (value, "n")
|| !strcasecmp (value, "false") || !strcasecmp (value, "f")
|| !strcasecmp (value, "0"))
val.bval = TUN_FALSE;
else if (!strcasecmp (value, "yes") || !strcasecmp (value, "y")
|| !strcasecmp (value, "true") || !strcasecmp (value, "t")
|| !strcasecmp (value, "1"))
val.bval = TUN_TRUE;
else
panic ("Error in config file %s: Value of parameter %s malformed\n"
"Allowed values: \"yes\", \"no\", \"y\", \"n\", \"true\", \"false\", \"t\", \"f\", \"1\" and \"0\"", fname, that->name);
that->value.bval = val.bval;
break;
default:
/* Shouldn't happen. */
panic ("Internal error: Wrong type of tunable parameter");
break;
}
}
static tun_struct tunable_params[] =
{
/* SRV */
{ "kern.srv.cleanup_threads", TUN_INT, {0}, {1}, {16}, default_tun_check},
{ "kern.srv.request_threads", TUN_INT, {0}, {1}, {64}, default_tun_check},
{ "kern.srv.sharedmem", TUN_BOOL, {TUN_UNDEF}, {TUN_FALSE}, {TUN_TRUE}, default_tun_check},
{ "kern.srv.msgqueues", TUN_BOOL, {TUN_UNDEF}, {TUN_FALSE}, {TUN_TRUE}, default_tun_check},
{ "kern.srv.semaphores", TUN_BOOL, {TUN_UNDEF}, {TUN_FALSE}, {TUN_TRUE}, default_tun_check},
/* LOG */
{ "kern.log.syslog", TUN_BOOL, {TUN_UNDEF}, {TUN_FALSE}, {TUN_TRUE}, default_tun_check},
{ "kern.log.stderr", TUN_BOOL, {TUN_UNDEF}, {TUN_FALSE}, {TUN_TRUE}, default_tun_check},
{ "kern.log.debug", TUN_BOOL, {TUN_UNDEF}, {TUN_FALSE}, {TUN_TRUE}, default_tun_check},
{ "kern.log.level", TUN_INT, {0}, {1}, {7}, default_tun_check},
/* MSG */
{ "kern.ipc.msgseg", TUN_INT, {0}, {256}, {32767}, default_tun_check},
{ "kern.ipc.msgssz", TUN_INT, {0}, {8}, {1024}, default_tun_check},
{ "kern.ipc.msgmni", TUN_INT, {0}, {1}, {1024}, default_tun_check},
/* SEM */
//{ "kern.ipc.semmap", TUN_INT, {0}, {1}, {1024}, default_tun_check},
{ "kern.ipc.semmni", TUN_INT, {0}, {1}, {1024}, default_tun_check},
{ "kern.ipc.semmns", TUN_INT, {0}, {1}, {1024}, default_tun_check},
{ "kern.ipc.semmnu", TUN_INT, {0}, {1}, {1024}, default_tun_check},
{ "kern.ipc.semmsl", TUN_INT, {0}, {1}, {1024}, default_tun_check},
{ "kern.ipc.semopm", TUN_INT, {0}, {1}, {1024}, default_tun_check},
{ "kern.ipc.semume", TUN_INT, {0}, {1}, {1024}, default_tun_check},
//{ "kern.ipc.semusz", TUN_INT, {0}, {1}, {1024}, default_tun_check},
{ "kern.ipc.semvmx", TUN_INT, {0}, {1}, {32767}, default_tun_check},
{ "kern.ipc.semaem", TUN_INT, {0}, {1}, {32767}, default_tun_check},
/* SHM */
{ "kern.ipc.shmmaxpgs", TUN_INT, {0}, {1}, {32767}, default_tun_check},
//{ "kern.ipc.shmmin", TUN_INT, {0}, {1}, {32767}, default_tun_check},
{ "kern.ipc.shmmni", TUN_INT, {0}, {1}, {32767}, default_tun_check},
{ "kern.ipc.shmseg", TUN_INT, {0}, {1}, {32767}, default_tun_check},
//{ "kern.ipc.shm_use_phys", TUN_INT, {0}, {1}, {32767}, default_tun_check},
{ NULL, TUN_NULL, {0}, {0}, {0}, NULL}
};
#define skip_whitespace(c) while (*(c) && isspace (*(c))) ++(c)
#define skip_nonwhitespace(c) while (*(c) && !isspace (*(c)) && *(c) != '#') ++(c)
#define end_of_content(c) (!*(c) || *(c) == '#')
void
tunable_param_init (const char *config_file, bool force)
{
FILE *fp = fopen (config_file, "rt");
if (!fp)
{
if (force)
panic ("can't open config file %s\n", config_file);
return;
}
char line[1024];
while (fgets (line, 1024, fp))
{
char *c = strrchr (line, '\n');
if (!c)
panic ("Line too long in confg file %s\n", config_file);
/* Overwrite trailing NL. */
*c = '\0';
c = line;
skip_whitespace (c);
if (end_of_content (c))
continue;
/* So we are on the first character of a parameter name. */
char *name = c;
/* Find end of name. */
skip_nonwhitespace (c);
if (end_of_content (c))
{
*c++ = '\0';
panic ("Error in config file %s: Parameter %s has no value.\n",
config_file, name);
}
/* Mark end of name. */
*c++ = '\0';
skip_whitespace (c);
if (end_of_content (c))
panic ("Error in config file %s: Parameter %s has no value.\n",
config_file, name);
/* Now we are on the first character of a parameter's value. */
char *value = c;
/* This only works for simple parameters. If complex string parameters
are added at one point, the scanning routine must be changed here. */
/* Find end of value. */
skip_nonwhitespace (c);
/* Mark end of value. */
*c++ = '\0';
/* Now look if name is one from our list. */
tun_struct *s;
for (s = &tunable_params[0]; s->name; ++s)
if (!strcmp (name, s->name))
{
/* Now read value and check for validity. check_func doesn't
return on error. */
s->check_func (s, value, config_file);
break;
}
if (!s->name)
panic ("Error in config file %s: Unknown parameter %s.\n",
config_file, name);
}
fclose (fp);
}
void
tunable_int_fetch (const char *name, long *tunable_target)
{
tun_struct *s;
for (s = &tunable_params[0]; s->name; ++s)
if (!strcmp (name, s->name))
break;
if (!s) /* Not found */
return;
if (s->type != TUN_INT) /* Wrong type */
return;
if (!s->value.ival) /* Not set in config file */
return;
*tunable_target = s->value.ival;
debug ("\nSet %s to %lu\n", name, *tunable_target);
}
void
tunable_bool_fetch (const char *name, tun_bool_t *tunable_target)
{
tun_struct *s;
const char *tun_bool_val_string[] = { "undefined", "no", "yes" };
for (s = &tunable_params[0]; s->name; ++s)
if (!strcmp (name, s->name))
break;
if (!s) /* Not found */
return;
if (s->type != TUN_BOOL) /* Wrong type */
return;
if (!s->value.ival) /* Not set in config file */
return;
*tunable_target = s->value.bval;
debug ("\nSet %s to %s\n", name, tun_bool_val_string[*tunable_target]);
}
#endif /* __OUTSIDE_CYGWIN__ */

View File

@ -0,0 +1,63 @@
/* bsd_helper.h: Helps integrating BSD kernel code
Copyright 2003 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. */
#ifndef _BSD_HELPER_H
#define _BSD_HELPER_H
#include <sys/types.h>
#include <sys/syslog.h>
enum tun_bool_t {
TUN_UNDEF = 0,
TUN_FALSE = 1,
TUN_TRUE = 2
};
#define TUNABLE_INT_FETCH(a,b) tunable_int_fetch((a),(b))
#define TUNABLE_BOOL_FETCH(a,b) tunable_bool_fetch((a),(b))
#define sys_malloc(a,b,c) (malloc(a)?:(panic("malloc failed in %s, line %d"),(void*)NULL))
#define sys_free(a,b) free(a)
#define jail_sysvipc_allowed true
#define jailed(a) false
extern const char *__progname;
/* Global vars, determining whether the IPC stuff should be started or not. */
extern tun_bool_t support_sharedmem;
extern tun_bool_t support_msgqueues;
extern tun_bool_t support_semaphores;
extern SECURITY_ATTRIBUTES sec_all_nih;
int win_copyin (struct thread *, const void *, void *, size_t);
int win_copyout (struct thread *, const void *, void *, size_t);
#define copyin(a,b,c) win_copyin((td),(a),(b),(c))
#define copyout(a,b,c) win_copyout((td),(a),(b),(c))
int ipcperm (struct thread *, struct ipc_perm *, unsigned int);
int suser (struct thread *);
bool adjust_identity_info (struct proc *p);
struct vmspace *ipc_p_vmspace (struct proc *);
int ipcexit_creat_hookthread(struct thread *);
void ipcinit (void);
int ipcunload (void);
vm_object_t _vm_pager_allocate (int, int);
#define vm_pager_allocate(a,b,s,c,d) _vm_pager_allocate((s),(mode))
vm_object_t vm_object_duplicate (struct thread *td, vm_object_t object);
void vm_object_deallocate (vm_object_t object);
void tunable_param_init (const char *, bool);
void tunable_int_fetch (const char *, long *);
void tunable_bool_fetch (const char *, tun_bool_t *);
#endif /* _BSD_HELPER_H */

View File

@ -0,0 +1,95 @@
/* bsd_log.cc
Copyright 2003 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. */
#ifdef __OUTSIDE_CYGWIN__
#include "woutsup.h"
#define _KERNEL 1
#define __BSD_VISIBLE 1
#include <sys/smallprint.h>
#include <stdio.h>
#include <stdlib.h>
long log_level = 8; /* Illegal value. Don't change! */
tun_bool_t log_debug = TUN_UNDEF;
tun_bool_t log_syslog = TUN_UNDEF;
tun_bool_t log_stderr = TUN_UNDEF;
void
loginit (tun_bool_t opt_stderr, tun_bool_t opt_syslog)
{
if (log_debug == TUN_UNDEF)
TUNABLE_BOOL_FETCH ("kern.log.debug", &log_debug);
if (log_debug == TUN_UNDEF)
log_debug = TUN_FALSE;
if (opt_stderr != TUN_UNDEF)
log_stderr = opt_stderr;
else
TUNABLE_BOOL_FETCH ("kern.log.stderr", &log_stderr);
if (log_stderr == TUN_UNDEF)
log_stderr = TUN_FALSE;
if (opt_syslog != TUN_UNDEF)
log_syslog = opt_syslog;
else
TUNABLE_BOOL_FETCH ("kern.log.syslog", &log_syslog);
if (log_syslog == TUN_UNDEF)
log_syslog = TUN_FALSE;
if (log_level == 8)
TUNABLE_INT_FETCH ("kern.log.level", &log_level);
if (log_level == 8)
log_level = 6;
}
void
_vlog (const char *file, int line, int level,
const char *fmt, va_list ap)
{
char buf[16384];
if ((level == LOG_DEBUG && log_debug != TUN_TRUE)
|| (level != LOG_DEBUG && level >= log_level))
return;
strcpy (buf, "cygserver: ");
if (file && log_debug == TUN_TRUE)
__small_sprintf (strchr (buf, '\0'), "%s, line %d: ", file, line);
__small_vsprintf (strchr (buf, '\0'), fmt, ap);
if (log_syslog == TUN_TRUE && level != LOG_DEBUG)
syslog (level, buf);
if (log_stderr == TUN_TRUE || level == LOG_DEBUG)
{
fputs (buf, stderr);
fputc ('\n', stderr);
}
}
void
_log (const char *file, int line, int level, const char *fmt, ...)
{
va_list ap;
va_start (ap, fmt);
_vlog (file, line, level, fmt, ap);
}
void
_vpanic (const char *file, int line, const char *fmt, va_list ap)
{
_vlog (file, line, LOG_EMERG, fmt, ap);
exit (1);
}
void
_panic (const char *file, int line, const char *fmt, ...)
{
va_list ap;
va_start (ap, fmt);
_vpanic (file, line, fmt, ap);
}
#endif /* __OUTSIDE_CYGWIN__ */

View File

@ -0,0 +1,33 @@
/* bsd_log.h: Helps integrating BSD kernel code
Copyright 2003 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. */
#ifndef _BSD_LOG_H
#define _BSD_LOG_H
#include <sys/types.h>
#include <sys/syslog.h>
extern long log_level;
extern tun_bool_t log_debug;
extern tun_bool_t log_syslog;
extern tun_bool_t log_stderr;
void loginit (tun_bool_t, tun_bool_t);
void _vlog (const char *, int, int, const char *, va_list);
void _log (const char *, int, int, const char *, ...);
void _vpanic (const char *, int, const char *, va_list) __attribute__ ((noreturn));
void _panic (const char *, int, const char *, ...) __attribute__ ((noreturn));
#define vlog(l,f,a) _vlog(NULL,0,(l),(f),(a))
#define log(l,f,...) _log(NULL,0,(l),(f),##__VA_ARGS__)
#define vdebug(f,a) _vlog(__FILE__,__LINE__,LOG_DEBUG,(f),(a))
#define debug(f,...) _log(__FILE__,__LINE__,LOG_DEBUG,(f),##__VA_ARGS__)
#define vpanic(f,a) _vpanic(__FILE__,__LINE__,(f),(a))
#define panic(f,...) _panic(__FILE__,__LINE__,(f),##__VA_ARGS__)
#endif /* _BSD_LOG_H */

View File

@ -0,0 +1,253 @@
/* bsd_mutex.cc
Copyright 2003 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. */
#ifdef __OUTSIDE_CYGWIN__
#include "woutsup.h"
#include "cygerrno.h"
#define _KERNEL 1
#define __BSD_VISIBLE 1
#include <sys/smallprint.h>
#include "process.h"
#include "cygserver_ipc.h"
/* A BSD kernel global mutex. */
struct mtx Giant;
void
mtx_init (mtx *m, const char *name, const void *, int)
{
m->name = name;
m->owner = 0;
/* Can't use Windows Mutexes here since Windows Mutexes are only
unlockable by the lock owner. */
m->h = CreateSemaphore (NULL, 1, 1, NULL);
if (!m->h)
panic ("couldn't allocate %s mutex, %E\n", name);
}
void
_mtx_lock (mtx *m, DWORD winpid, const char *file, int line)
{
_log (file, line, LOG_DEBUG, "Try locking mutex %s", m->name);
if (WaitForSingleObject (m->h, INFINITE) != WAIT_OBJECT_0)
_panic (file, line, "wait for %s in %d failed, %E", m->name, winpid);
m->owner = winpid;
_log (file, line, LOG_DEBUG, "Locked mutex %s", m->name);
}
int
mtx_owned (mtx *m)
{
return m->owner > 0;
}
void
_mtx_assert(mtx *m, int what, const char *file, int line)
{
switch (what)
{
case MA_OWNED:
if (!mtx_owned (m))
_panic(file, line, "Mutex %s not owned", m->name);
break;
case MA_NOTOWNED:
if (mtx_owned (m))
_panic(file, line, "Mutex %s is owned", m->name);
break;
default:
break;
}
}
void
_mtx_unlock (mtx *m, const char *file, int line)
{
m->owner = 0;
/* Cautiously check if mtx_destroy has been called (shutdown).
In that case, m->h is NULL. */
if (m->h && !ReleaseSemaphore (m->h, 1, NULL))
{
/* Check if the semaphore was already on it's max value. In this case,
ReleaseSemaphore returns FALSE with an error code which *sic* depends
on the OS. */
if ( (!wincap.is_winnt () && GetLastError () != ERROR_INVALID_PARAMETER)
|| (wincap.is_winnt () && GetLastError () != ERROR_TOO_MANY_POSTS))
_panic (file, line, "release of mutex %s failed, %E", m->name);
}
_log (file, line, LOG_DEBUG, "Unlocked mutex %s", m->name);
}
void
mtx_destroy (mtx *m)
{
HANDLE tmp = m->h;
m->h = NULL;
if (tmp)
CloseHandle (tmp);
}
/*
* Helper functions for msleep/wakeup.
*/
static char *
msleep_event_name (void *ident, char *name)
{
if (wincap.has_terminal_services ())
__small_sprintf (name, "Global\\cygserver.msleep.evt.%08x", ident);
else
__small_sprintf (name, "cygserver.msleep.evt.%08x", ident);
return name;
}
/*
* Original description from BSD code:
*
* General sleep call. Suspends the current process until a wakeup is
* performed on the specified identifier. The process will then be made
* runnable with the specified priority. Sleeps at most timo/hz seconds
* (0 means no timeout). If pri includes PCATCH flag, signals are checked
* before and after sleeping, else signals are not checked. Returns 0 if
* awakened, EWOULDBLOCK if the timeout expires. If PCATCH is set and a
* signal needs to be delivered, ERESTART is returned if the current system
* call should be restarted if possible, and EINTR is returned if the system
* call should be interrupted by the signal (return EINTR).
*
* The mutex argument is exited before the caller is suspended, and
* entered before msleep returns. If priority includes the PDROP
* flag the mutex is not entered before returning.
*/
static HANDLE msleep_glob_evt;
void
msleep_init (void)
{
msleep_glob_evt = CreateEvent (NULL, TRUE, FALSE, NULL);
if (!msleep_glob_evt)
panic ("CreateEvent in msleep_init failed: %E");
}
static int
win_priority (int priority)
{
int p = (int)((p) & PRIO_MASK) - PZERO;
/* Generating a valid priority value is a bit tricky. The only valid
values on 9x and NT4 are -15, -2, -1, 0, 1, 2, 15. */
switch (p)
{
case -15: case -14: case -13: case -12: case -11:
return THREAD_PRIORITY_IDLE;
case -10: case -9: case -8: case -7: case -6:
return THREAD_PRIORITY_LOWEST;
case -5: case -4: case -3: case -2: case -1:
return THREAD_PRIORITY_BELOW_NORMAL;
case 0:
return THREAD_PRIORITY_NORMAL;
case 1: case 2: case 3: case 4: case 5:
return THREAD_PRIORITY_ABOVE_NORMAL;
case 6: case 7: case 8: case 9: case 10:
return THREAD_PRIORITY_HIGHEST;
case 11: case 12: case 13: case 14: case 15:
return THREAD_PRIORITY_TIME_CRITICAL;
}
return THREAD_PRIORITY_NORMAL;
}
/*
* Sets the thread priority, returns the old priority.
*/
static int
set_priority (int priority)
{
int old_prio = GetThreadPriority (GetCurrentThread ());
if (!SetThreadPriority (GetCurrentThread (), win_priority(priority)))
log (LOG_WARNING,
"Warning: Setting thread priority to %d failed with error %lu\n",
win_priority(priority), GetLastError ());
return old_prio;
}
int
_msleep (void *ident, struct mtx *mtx, int priority,
const char *wmesg, int timo, struct thread *td)
{
int ret = -1;
char name[64];
msleep_event_name (ident, name);
HANDLE evt = OpenEvent (EVENT_ALL_ACCESS, FALSE, name);
if (!evt)
evt = CreateEvent (NULL, TRUE, FALSE, name);
if (!evt)
panic ("CreateEvent in msleep (%s) failed: %E", wmesg);
if (mtx)
mtx_unlock (mtx);
int old_priority = set_priority (priority);
/* PCATCH can't be handled here. */
HANDLE obj[3] = { evt, td->client->handle (), msleep_glob_evt };
switch (WaitForMultipleObjects (3, obj, FALSE, timo ?: INFINITE))
{
case WAIT_OBJECT_0: /* wakeup() has been called. */
ret = 0;
break;
case WAIT_OBJECT_0 + 2: /* Shutdown event (triggered by wakeup_all). */
priority |= PDROP;
/*FALLTHRU*/
case WAIT_OBJECT_0 + 1: /* The dependent process has exited. */
ret = EIDRM;
break;
case WAIT_TIMEOUT:
ret = EWOULDBLOCK;
break;
default:
panic ("wait in msleep (%s) failed, %E", wmesg);
break;
}
set_priority (old_priority);
if (!(priority & PDROP) && mtx)
mtx_lock (mtx);
CloseHandle (evt);
return ret;
}
/*
* Make all threads sleeping on the specified identifier runnable.
*/
int
wakeup (void *ident)
{
char name[64];
msleep_event_name (ident, name);
HANDLE evt = OpenEvent (EVENT_MODIFY_STATE, FALSE, name);
if (!evt)
{
/* Another round of different error codes returned by 9x and NT
systems. Oh boy... */
if ( (!wincap.is_winnt () && GetLastError () != ERROR_INVALID_NAME)
|| (wincap.is_winnt () && GetLastError () != ERROR_FILE_NOT_FOUND))
panic ("OpenEvent (%s) in wakeup failed: %E", name);
}
if (evt)
{
if (!SetEvent (evt))
panic ("SetEvent (%s) in wakeup failed, %E", name);
CloseHandle (evt);
}
return 0;
}
/*
* Wakeup all sleeping threads. Only called in the context of cygserver
* shutdown.
*/
void
wakeup_all (void)
{
SetEvent (msleep_glob_evt);
}
#endif /* __OUTSIDE_CYGWIN__ */

View File

@ -0,0 +1,51 @@
/* bsd_mutex.h: BSD Mutex helper
Copyright 2003 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. */
#ifndef _BSD_MUTEX_H
#define _BSD_MUTEX_H
#define MTX_DEF 0
#define MA_OWNED 1
#define MA_NOTOWNED 2
#define PZERO (0x20)
#define PRIO_MASK (0x1f)
#define PDROP 0x1000
#define PCATCH 0x2000
#define PLOCK 0x3000
struct mtx {
HANDLE h;
const char *name;
DWORD owner;
};
/* Some BSD kernel global mutex. */
extern struct mtx Giant;
void mtx_init (mtx *, const char *, const void *, int);
void _mtx_lock (mtx *, DWORD winpid, const char *, int);
#define mtx_lock(m) _mtx_lock((m), (td->ipcblk->winpid), __FILE__, __LINE__)
int mtx_owned (mtx *);
void _mtx_assert(mtx *, int, const char *, int);
#define mtx_assert(m,w) _mtx_assert((m),(w),__FILE__,__LINE__)
void _mtx_unlock (mtx *, const char *, int);
#define mtx_unlock(m) _mtx_unlock((m),__FILE__,__LINE__)
void mtx_destroy (mtx *);
void msleep_init (void);
int _msleep (void *, struct mtx *, int, const char *, int, struct thread *);
#define msleep(i,m,p,w,t) _msleep((i),(m),(p),(w),(t),(td))
#define tsleep(i,p,w,t) _msleep((i),NULL,(p),(w),(t),(td))
int wakeup (void *);
void wakeup_all (void);
#endif /* _BSD_MUTEX_H */

View File

@ -1,6 +1,6 @@
/* cygserver_client.cc /* client.cc
Copyright 2001, 2002 Red Hat Inc. Copyright 2001, 2002, 2003 Red Hat Inc.
Written by Egor Duda <deo@logos-m.ru> Written by Egor Duda <deo@logos-m.ru>
@ -22,11 +22,12 @@ details. */
#include <unistd.h> #include <unistd.h>
#include "cygerrno.h" #include "cygerrno.h"
#include "cygserver_msg.h"
#include "cygserver_sem.h"
#include "cygserver_shm.h" #include "cygserver_shm.h"
#include "safe_memory.h"
#include "cygserver.h" #include "cygserver.h"
#include "cygserver_transport.h" #include "transport.h"
int cygserver_running = CYGSERVER_UNKNOWN; // Nb: inherited by children. int cygserver_running = CYGSERVER_UNKNOWN; // Nb: inherited by children.
@ -48,6 +49,8 @@ client_request_get_version::client_request_get_version ()
* the first numbers match, that is). * the first numbers match, that is).
*/ */
#ifdef __INSIDE_CYGWIN__
bool bool
client_request_get_version::check_version () const client_request_get_version::check_version () const
{ {
@ -71,8 +74,6 @@ client_request_get_version::check_version () const
return ok; return ok;
} }
#ifdef __INSIDE_CYGWIN__
client_request_attach_tty::client_request_attach_tty (DWORD nmaster_pid, client_request_attach_tty::client_request_attach_tty (DWORD nmaster_pid,
HANDLE nfrom_master, HANDLE nfrom_master,
HANDLE nto_master) HANDLE nto_master)
@ -87,15 +88,6 @@ client_request_attach_tty::client_request_attach_tty (DWORD nmaster_pid,
"from_master = %lu, to_master = %lu"), "from_master = %lu, to_master = %lu"),
req.pid, req.master_pid, req.from_master, req.to_master); req.pid, req.master_pid, req.from_master, req.to_master);
} }
#else /* !__INSIDE_CYGWIN__ */
client_request_attach_tty::client_request_attach_tty ()
: client_request (CYGSERVER_REQUEST_ATTACH_TTY, &req, sizeof (req))
{
// verbose: syscall_printf ("created");
}
#endif /* __INSIDE_CYGWIN__ */ #endif /* __INSIDE_CYGWIN__ */
/* /*
@ -230,7 +222,12 @@ client_request::send (transport_layer_base * const conn)
// sizeof (_header), msglen ()); // sizeof (_header), msglen ());
} }
#ifndef __INSIDE_CYGWIN__ #ifdef __OUTSIDE_CYGWIN__
client_request_attach_tty::client_request_attach_tty ()
: client_request (CYGSERVER_REQUEST_ATTACH_TTY, &req, sizeof (req))
{
}
/* /*
* client_request::handle_request () * client_request::handle_request ()
@ -277,16 +274,22 @@ client_request::handle_request (transport_layer_base *const conn,
switch (header.request_code) switch (header.request_code)
{ {
case CYGSERVER_REQUEST_GET_VERSION: case CYGSERVER_REQUEST_GET_VERSION:
req = safe_new0 (client_request_get_version); req = new client_request_get_version;
break; break;
case CYGSERVER_REQUEST_SHUTDOWN: case CYGSERVER_REQUEST_SHUTDOWN:
req = safe_new0 (client_request_shutdown); req = new client_request_shutdown;
break; break;
case CYGSERVER_REQUEST_ATTACH_TTY: case CYGSERVER_REQUEST_ATTACH_TTY:
req = safe_new0 (client_request_attach_tty); req = new client_request_attach_tty;
break;
case CYGSERVER_REQUEST_MSG:
req = new client_request_msg;
break;
case CYGSERVER_REQUEST_SEM:
req = new client_request_sem;
break; break;
case CYGSERVER_REQUEST_SHM: case CYGSERVER_REQUEST_SHM:
req = safe_new0 (client_request_shm); req = new client_request_shm;
break; break;
default: default:
syscall_printf ("unknown request code %d received: request ignored", syscall_printf ("unknown request code %d received: request ignored",
@ -299,74 +302,9 @@ client_request::handle_request (transport_layer_base *const conn,
req->msglen (header.msglen); req->msglen (header.msglen);
req->handle (conn, cache); req->handle (conn, cache);
safe_delete (req); delete req;
#ifndef DEBUGGING
printf ("."); // A little noise when we're being quiet.
#endif
} }
#endif /* !__INSIDE_CYGWIN__ */
client_request::client_request (request_code_t const id,
void * const buf,
size_t const buflen)
: _header (id, buflen),
_buf (buf),
_buflen (buflen)
{
assert ((!_buf && !_buflen) || (_buf && _buflen));
}
client_request::~client_request ()
{}
int
client_request::make_request ()
{
assert (cygserver_running == CYGSERVER_UNKNOWN \
|| cygserver_running == CYGSERVER_OK \
|| cygserver_running == CYGSERVER_UNAVAIL);
if (cygserver_running == CYGSERVER_UNKNOWN)
cygserver_init ();
assert (cygserver_running == CYGSERVER_OK \
|| cygserver_running == CYGSERVER_UNAVAIL);
/* Don't retry every request if the server's not there */
if (cygserver_running == CYGSERVER_UNAVAIL)
{
syscall_printf ("cygserver un-available");
error_code (ENOSYS);
return -1;
}
transport_layer_base *const transport = create_server_transport ();
assert (transport);
if (transport->connect () == -1)
{
if (errno)
error_code (errno);
else
error_code (ENOSYS);
safe_delete (transport);
return -1;
}
// verbose: debug_printf ("connected to server %p", transport);
send (transport);
safe_delete (transport);
return 0;
}
#ifndef __INSIDE_CYGWIN__
/* /*
* client_request::handle () * client_request::handle ()
* *
@ -470,7 +408,84 @@ client_request::handle (transport_layer_base *const conn,
// sizeof (_header), msglen ()); // sizeof (_header), msglen ());
} }
#endif /* !__INSIDE_CYGWIN__ */ /* The server side implementation of make_request. Very simple. */
int
client_request::make_request ()
{
transport_layer_base *const transport = create_server_transport ();
assert (transport);
if (transport->connect () == -1)
{
if (errno)
error_code (errno);
else
error_code (ENOSYS);
delete transport;
return -1;
}
send (transport);
delete transport;
return 0;
}
#endif /* __OUTSIDE_CYGWIN__ */
client_request::client_request (request_code_t const id,
void * const buf,
size_t const buflen)
: _header (id, buflen),
_buf (buf),
_buflen (buflen)
{
assert ((!_buf && !_buflen) || (_buf && _buflen));
}
client_request::~client_request ()
{}
#ifdef __INSIDE_CYGWIN__
int
client_request::make_request ()
{
assert (cygserver_running == CYGSERVER_UNKNOWN \
|| cygserver_running == CYGSERVER_OK \
|| cygserver_running == CYGSERVER_UNAVAIL);
if (cygserver_running == CYGSERVER_UNKNOWN)
cygserver_init ();
assert (cygserver_running == CYGSERVER_OK \
|| cygserver_running == CYGSERVER_UNAVAIL);
/* Don't retry every request if the server's not there */
if (cygserver_running == CYGSERVER_UNAVAIL)
{
syscall_printf ("cygserver un-available");
error_code (ENOSYS);
return -1;
}
transport_layer_base *const transport = create_server_transport ();
assert (transport);
if (transport->connect () == -1)
{
if (errno)
error_code (errno);
else
error_code (ENOSYS);
delete transport;
return -1;
}
// verbose: debug_printf ("connected to server %p", transport);
send (transport);
delete transport;
return 0;
}
bool bool
check_cygserver_available () check_cygserver_available ()
@ -523,3 +538,4 @@ cygserver_init ()
if (!check_cygserver_available ()) if (!check_cygserver_available ())
cygserver_running = CYGSERVER_UNAVAIL; cygserver_running = CYGSERVER_UNAVAIL;
} }
#endif /* __INSIDE_CYGWIN__ */

View File

@ -1,6 +1,6 @@
/* cygserver.cc /* cygserver.cc
Copyright 2001, 2002 Red Hat Inc. Copyright 2001, 2002, 2003 Red Hat Inc.
Written by Egor Duda <deo@logos-m.ru> Written by Egor Duda <deo@logos-m.ru>
@ -10,6 +10,7 @@ This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */ details. */
#ifdef __OUTSIDE_CYGWIN__
#include "woutsup.h" #include "woutsup.h"
#include <sys/types.h> #include <sys/types.h>
@ -27,100 +28,21 @@ details. */
#include "cygwin_version.h" #include "cygwin_version.h"
#include "cygserver.h" #include "cygserver.h"
#include "cygserver_process.h" #include "process.h"
#include "cygserver_transport.h" #include "transport.h"
#include "cygserver_ipc.h"
#include "cygserver_msg.h"
#include "cygserver_sem.h"
#define DEF_CONFIG_FILE "" SYSCONFDIR "/cygserver.conf"
// Version string. // Version string.
static const char version[] = "$Revision$"; static const char version[] = "$Revision$";
/*
* Support function for the XXX_printf () macros in "woutsup.h".
* Copied verbatim from "strace.cc".
*/
static int
getfunc (char *in_dst, const char *func)
{
const char *p;
const char *pe;
char *dst = in_dst;
for (p = func; (pe = strchr (p, '(')); p = pe + 1)
if (isalnum ((int)pe[-1]) || pe[-1] == '_')
break;
else if (isspace ((int)pe[-1]))
{
pe--;
break;
}
if (!pe)
pe = strchr (func, '\0');
for (p = pe; p > func; p--)
if (p != pe && *p == ' ')
{
p++;
break;
}
if (*p == '*')
p++;
while (p < pe)
*dst++ = *p++;
*dst++ = ':';
*dst++ = ' ';
*dst = '\0';
return dst - in_dst;
}
/*
* Support function for the XXX_printf () macros in "woutsup.h".
*/
extern "C" void
__cygserver__printf (const char *const function, const char *const fmt, ...)
{
const DWORD lasterror = GetLastError ();
const int lasterrno = errno;
va_list ap;
char *const buf = (char *) alloca (BUFSIZ);
assert (buf);
int len = 0;
if (function)
len += getfunc (buf, function);
va_start (ap, fmt);
len += vsnprintf (buf + len, BUFSIZ - len, fmt, ap);
va_end (ap);
len += snprintf (buf + len, BUFSIZ - len, "\n");
const int actual = (len > BUFSIZ ? BUFSIZ : len);
write (2, buf, actual);
errno = lasterrno;
SetLastError (lasterror);
return;
}
#ifdef DEBUGGING
int __stdcall
__set_errno (const char *func, int ln, int val)
{
debug_printf ("%s:%d val %d", func, ln, val);
return _impure_ptr->_errno = val;
}
#endif /* DEBUGGING */
GENERIC_MAPPING access_mapping; GENERIC_MAPPING access_mapping;
static BOOL static bool
setup_privileges () setup_privileges ()
{ {
BOOL rc, ret_val; BOOL rc, ret_val;
@ -130,15 +52,14 @@ setup_privileges ()
rc = OpenProcessToken (GetCurrentProcess () , TOKEN_ALL_ACCESS , &hToken) ; rc = OpenProcessToken (GetCurrentProcess () , TOKEN_ALL_ACCESS , &hToken) ;
if (!rc) if (!rc)
{ {
system_printf ("error opening process token (%lu)", GetLastError ()); debug ("error opening process token (%lu)", GetLastError ());
ret_val = FALSE; return false;
goto out;
} }
rc = LookupPrivilegeValue (NULL, SE_DEBUG_NAME, &sPrivileges.Privileges[0].Luid); rc = LookupPrivilegeValue (NULL, SE_DEBUG_NAME, &sPrivileges.Privileges[0].Luid);
if (!rc) if (!rc)
{ {
system_printf ("error getting privilege luid (%lu)", GetLastError ()); debug ("error getting privilege luid (%lu)", GetLastError ());
ret_val = FALSE; ret_val = false;
goto out; goto out;
} }
sPrivileges.PrivilegeCount = 1 ; sPrivileges.PrivilegeCount = 1 ;
@ -146,9 +67,8 @@ setup_privileges ()
rc = AdjustTokenPrivileges (hToken, FALSE, &sPrivileges, 0, NULL, NULL) ; rc = AdjustTokenPrivileges (hToken, FALSE, &sPrivileges, 0, NULL, NULL) ;
if (!rc) if (!rc)
{ {
system_printf ("error adjusting privilege level. (%lu)", debug ("error adjusting privilege level. (%lu)", GetLastError ());
GetLastError ()); ret_val = false;
ret_val = FALSE;
goto out; goto out;
} }
@ -157,7 +77,7 @@ setup_privileges ()
access_mapping.GenericExecute = 0; access_mapping.GenericExecute = 0;
access_mapping.GenericAll = FILE_READ_DATA | FILE_WRITE_DATA; access_mapping.GenericAll = FILE_READ_DATA | FILE_WRITE_DATA;
ret_val = TRUE; ret_val = true;
out: out:
CloseHandle (hToken); CloseHandle (hToken);
@ -181,7 +101,7 @@ check_and_dup_handle (HANDLE from_process, HANDLE to_process,
0, bInheritHandle, 0, bInheritHandle,
DUPLICATE_SAME_ACCESS)) DUPLICATE_SAME_ACCESS))
{ {
system_printf ("error getting handle(%u) to server (%lu)", log (LOG_ERR, "error getting handle(%u) to server (%lu)",
(unsigned int)from_handle, GetLastError ()); (unsigned int)from_handle, GetLastError ());
goto out; goto out;
} }
@ -205,7 +125,7 @@ check_and_dup_handle (HANDLE from_process, HANDLE to_process,
| DACL_SECURITY_INFORMATION), | DACL_SECURITY_INFORMATION),
sd, sizeof (sd_buf), &bytes_needed)) sd, sizeof (sd_buf), &bytes_needed))
{ {
system_printf ("error getting handle SD (%lu)", GetLastError ()); log (LOG_ERR, "error getting handle SD (%lu)", GetLastError ());
goto out; goto out;
} }
@ -214,14 +134,14 @@ check_and_dup_handle (HANDLE from_process, HANDLE to_process,
if (!AccessCheck (sd, from_process_token, access, &access_mapping, if (!AccessCheck (sd, from_process_token, access, &access_mapping,
&ps, &ps_len, &access, &status)) &ps, &ps_len, &access, &status))
{ {
system_printf ("error checking access rights (%lu)", log (LOG_ERR, "error checking access rights (%lu)",
GetLastError ()); GetLastError ());
goto out; goto out;
} }
if (!status) if (!status)
{ {
system_printf ("access to object denied"); log (LOG_ERR, "access to object denied");
goto out; goto out;
} }
} }
@ -230,11 +150,11 @@ check_and_dup_handle (HANDLE from_process, HANDLE to_process,
to_process, to_handle_ptr, to_process, to_handle_ptr,
access, bInheritHandle, 0)) access, bInheritHandle, 0))
{ {
system_printf ("error getting handle to client (%lu)", GetLastError ()); log (LOG_ERR, "error getting handle to client (%lu)", GetLastError ());
goto out; goto out;
} }
// verbose: debug_printf ("Duplicated %p to %p", from_handle, *to_handle_ptr); debug ("Duplicated %p to %p", from_handle, *to_handle_ptr);
ret_val = 0; ret_val = 0;
@ -259,7 +179,7 @@ client_request_attach_tty::serve (transport_layer_base *const conn,
if (!wincap.has_security ()) if (!wincap.has_security ())
{ {
syscall_printf ("operation only supported on systems with security"); log (LOG_NOTICE, "operation only supported on systems with security");
error_code (EINVAL); error_code (EINVAL);
msglen (0); msglen (0);
return; return;
@ -267,7 +187,7 @@ client_request_attach_tty::serve (transport_layer_base *const conn,
if (msglen () != sizeof (req)) if (msglen () != sizeof (req))
{ {
syscall_printf ("bad request body length: expecting %lu bytes, got %lu", log (LOG_ERR, "bad request body length: expecting %lu bytes, got %lu",
sizeof (req), msglen ()); sizeof (req), msglen ());
error_code (EINVAL); error_code (EINVAL);
msglen (0); msglen (0);
@ -276,54 +196,65 @@ client_request_attach_tty::serve (transport_layer_base *const conn,
msglen (0); // Until we fill in some fields. msglen (0); // Until we fill in some fields.
// verbose: debug_printf ("pid %ld:(%p,%p) -> pid %ld", debug ("pid %ld:(%p,%p) -> pid %ld", req.master_pid, req.from_master,
// req.master_pid, req.from_master, req.to_master, req.to_master, req.pid);
// req.pid);
// verbose: debug_printf ("opening process %ld", req.master_pid); debug ("opening process %ld", req.master_pid);
const HANDLE from_process_handle = const HANDLE from_process_handle =
OpenProcess (PROCESS_DUP_HANDLE, FALSE, req.master_pid); OpenProcess (PROCESS_DUP_HANDLE, FALSE, req.master_pid);
if (!from_process_handle) if (!from_process_handle)
{ {
system_printf ("error opening `from' process, error = %lu", log (LOG_ERR, "error opening `from' process, error = %lu",
GetLastError ()); GetLastError ());
error_code (EACCES); error_code (EACCES);
return; return;
} }
// verbose: debug_printf ("opening process %ld", req.pid); debug ("opening process %ld", req.pid);
const HANDLE to_process_handle = const HANDLE to_process_handle =
OpenProcess (PROCESS_DUP_HANDLE, FALSE, req.pid); OpenProcess (PROCESS_DUP_HANDLE, FALSE, req.pid);
if (!to_process_handle) if (!to_process_handle)
{ {
system_printf ("error opening `to' process, error = %lu", log (LOG_ERR, "error opening `to' process, error = %lu",
GetLastError ()); GetLastError ());
CloseHandle (from_process_handle); CloseHandle (from_process_handle);
error_code (EACCES); error_code (EACCES);
return; return;
} }
// verbose: debug_printf ("Impersonating client"); debug ("Impersonating client");
conn->impersonate_client (); if (!conn->impersonate_client ())
{
CloseHandle (from_process_handle);
CloseHandle (to_process_handle);
error_code (EACCES);
return;
}
HANDLE token_handle = NULL; HANDLE token_handle = NULL;
// verbose: debug_printf ("about to open thread token"); debug ("about to open thread token");
const DWORD rc = OpenThreadToken (GetCurrentThread (), const DWORD rc = OpenThreadToken (GetCurrentThread (),
TOKEN_QUERY, TOKEN_QUERY,
TRUE, TRUE,
&token_handle); &token_handle);
// verbose: debug_printf ("opened thread token, rc=%lu", rc); debug ("opened thread token, rc=%lu", rc);
conn->revert_to_self (); if (!conn->revert_to_self ())
{
CloseHandle (from_process_handle);
CloseHandle (to_process_handle);
error_code (EACCES);
return;
}
if (!rc) if (!rc)
{ {
system_printf ("error opening thread token, error = %lu", log (LOG_ERR, "error opening thread token, error = %lu",
GetLastError ()); GetLastError ());
CloseHandle (from_process_handle); CloseHandle (from_process_handle);
CloseHandle (to_process_handle); CloseHandle (to_process_handle);
@ -348,7 +279,7 @@ client_request_attach_tty::serve (transport_layer_base *const conn,
from_master, from_master,
&req.from_master, TRUE) != 0) &req.from_master, TRUE) != 0)
{ {
system_printf ("error duplicating from_master handle, error = %lu", log (LOG_ERR, "error duplicating from_master handle, error = %lu",
GetLastError ()); GetLastError ());
error_code (EACCES); error_code (EACCES);
} }
@ -360,7 +291,7 @@ client_request_attach_tty::serve (transport_layer_base *const conn,
to_master, to_master,
&req.to_master, TRUE) != 0) &req.to_master, TRUE) != 0)
{ {
system_printf ("error duplicating to_master handle, error = %lu", log (LOG_ERR, "error duplicating to_master handle, error = %lu",
GetLastError ()); GetLastError ());
error_code (EACCES); error_code (EACCES);
} }
@ -369,7 +300,7 @@ client_request_attach_tty::serve (transport_layer_base *const conn,
CloseHandle (to_process_handle); CloseHandle (to_process_handle);
CloseHandle (token_handle); CloseHandle (token_handle);
debug_printf ("%lu(%lu, %lu) -> %lu(%lu,%lu)", debug ("%lu(%lu, %lu) -> %lu(%lu,%lu)",
req.master_pid, from_master, to_master, req.master_pid, from_master, to_master,
req.pid, req.from_master, req.to_master); req.pid, req.from_master, req.to_master);
@ -382,7 +313,7 @@ client_request_get_version::serve (transport_layer_base *, process_cache *)
assert (!error_code ()); assert (!error_code ());
if (msglen ()) if (msglen ())
syscall_printf ("unexpected request body ignored: %lu bytes", msglen ()); log (LOG_ERR, "unexpected request body ignored: %lu bytes", msglen ());
msglen (sizeof (version)); msglen (sizeof (version));
@ -401,7 +332,7 @@ public:
virtual ~server_request () virtual ~server_request ()
{ {
safe_delete (_conn); delete _conn;
} }
virtual void process () virtual void process ()
@ -455,8 +386,8 @@ server_submission_loop::request_loop ()
*/ */
if (!SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_HIGHEST + 1)) if (!SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_HIGHEST + 1))
if (!SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_HIGHEST)) if (!SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_HIGHEST))
debug_printf ("failed to raise accept thread priority, error = %lu", debug ("failed to raise accept thread priority, error = %lu",
GetLastError ()); GetLastError ());
while (_running) while (_running)
{ {
@ -464,7 +395,7 @@ server_submission_loop::request_loop ()
transport_layer_base *const conn = _transport->accept (&recoverable); transport_layer_base *const conn = _transport->accept (&recoverable);
if (!conn && !recoverable) if (!conn && !recoverable)
{ {
system_printf ("fatal error on IPC transport: closing down"); log (LOG_ERR, "fatal error on IPC transport: closing down");
return; return;
} }
// EINTR probably implies a shutdown request; so back off for a // EINTR probably implies a shutdown request; so back off for a
@ -474,26 +405,25 @@ server_submission_loop::request_loop ()
if (!conn && errno == EINTR) if (!conn && errno == EINTR)
{ {
if (!SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_NORMAL)) if (!SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_NORMAL))
debug_printf ("failed to reset thread priority, error = %lu", debug ("failed to reset thread priority, error = %lu",
GetLastError ()); GetLastError ());
Sleep (0); Sleep (0);
if (!SetThreadPriority (GetCurrentThread (), if (!SetThreadPriority (GetCurrentThread (),
THREAD_PRIORITY_HIGHEST + 1)) THREAD_PRIORITY_HIGHEST + 1))
if (!SetThreadPriority (GetCurrentThread (), if (!SetThreadPriority (GetCurrentThread (),
THREAD_PRIORITY_HIGHEST)) THREAD_PRIORITY_HIGHEST))
debug_printf ("failed to raise thread priority, error = %lu", debug ("failed to raise thread priority, error = %lu",
GetLastError ()); GetLastError ());
} }
if (conn) if (conn)
_queue->add (safe_new (server_request, conn, _cache)); _queue->add (new server_request (conn, _cache));
} }
} }
client_request_shutdown::client_request_shutdown () client_request_shutdown::client_request_shutdown ()
: client_request (CYGSERVER_REQUEST_SHUTDOWN) : client_request (CYGSERVER_REQUEST_SHUTDOWN)
{ {
// verbose: syscall_printf ("created");
} }
void void
@ -502,7 +432,7 @@ client_request_shutdown::serve (transport_layer_base *, process_cache *)
assert (!error_code ()); assert (!error_code ());
if (msglen ()) if (msglen ())
syscall_printf ("unexpected request body ignored: %lu bytes", msglen ()); log (LOG_ERR, "unexpected request body ignored: %lu bytes", msglen ());
/* FIXME: link upwards, and then this becomes a trivial method call to /* FIXME: link upwards, and then this becomes a trivial method call to
* only shutdown _this queue_ * only shutdown _this queue_
@ -530,12 +460,33 @@ handle_signal (const int signum)
static void static void
print_usage (const char *const pgm) print_usage (const char *const pgm)
{ {
printf ("Usage: %s [OPTIONS]\n", pgm); log (LOG_NOTICE, "Usage: %s [OPTIONS]\n"
printf (" -c, --cleanup-threads number of cleanup threads to use\n"); "Configuration option:\n"
printf (" -h, --help output usage information and exit\n"); " -f, --config-file <file> Use <file> as config file. Default is\n"
printf (" -r, --request-threads number of request threads to use\n"); "\n"
printf (" -s, --shutdown shutdown the daemon\n"); "Performance options:\n"
printf (" -v, --version output version information and exit\n"); " -c, --cleanup-threads <num> Number of cleanup threads to use.\n"
" -r, --request-threads <num> Number of request threads to use.\n"
"\n"
"Logging options:\n"
" -d, --debug Log debug messages to stderr.\n"
" -e, --stderr Log to stderr (default if stderr is a tty).\n"
" -E, --no-stderr Don't log to stderr (see -y, -Y options).\n"
" " DEF_CONFIG_FILE "\n"
" -l, --log-level <level> Verbosity of logging (1..7). Default: 6\n"
" -y, --syslog Log to syslog (default if stderr is no tty).\n"
" -Y, --no-syslog Don't log to syslog (See -e, -E options).\n"
"\n"
"Support options:\n"
" -m, --no-sharedmem Don't start XSI Shared Memory support.\n"
" -q, --no-msgqueues Don't start XSI Message Queue support.\n"
" -s, --no-semaphores Don't start XSI Semaphore support.\n"
"\n"
"Miscellaneous:\n"
" -S, --shutdown Shutdown the daemon.\n"
" -h, --help Output usage information and exit.\n"
" -v, --version Output version information and exit."
, pgm);
} }
/* /*
@ -543,7 +494,7 @@ print_usage (const char *const pgm)
*/ */
static void static void
print_version (const char *const pgm) print_version ()
{ {
char *vn = NULL; char *vn = NULL;
@ -578,10 +529,12 @@ print_version (const char *const pgm)
cygwin_version.mount_registry, cygwin_version.mount_registry,
cygwin_version.dll_build_date); cygwin_version.dll_build_date);
printf ("%s (cygwin) %s\n", pgm, vn); log (LOG_INFO, "(cygwin) %s\n"
printf ("API version %s\n", buf); "API version %s\n"
printf ("Copyright 2001, 2002 Red Hat, Inc.\n"); "Copyright 2001, 2002, 2003 Red Hat, Inc.\n"
printf ("Compiled on %s\n", __DATE__); "Compiled on %s\n"
"Default configuration file is %s",
vn, buf, __DATE__, DEF_CONFIG_FILE);
free (vn); free (vn);
} }
@ -595,79 +548,127 @@ main (const int argc, char *argv[])
{ {
const struct option longopts[] = { const struct option longopts[] = {
{"cleanup-threads", required_argument, NULL, 'c'}, {"cleanup-threads", required_argument, NULL, 'c'},
{"debug", no_argument, NULL, 'd'},
{"stderr", no_argument, NULL, 'e'},
{"no-stderr", no_argument, NULL, 'E'},
{"config-file", required_argument, NULL, 'f'},
{"help", no_argument, NULL, 'h'}, {"help", no_argument, NULL, 'h'},
{"log-level", required_argument, NULL, 'l'},
{"no-sharedmem", no_argument, NULL, 'm'},
{"no-msgqueues", no_argument, NULL, 'q'},
{"request-threads", required_argument, NULL, 'r'}, {"request-threads", required_argument, NULL, 'r'},
{"shutdown", no_argument, NULL, 's'}, {"no-semaphores", no_argument, NULL, 's'},
{"shutdown", no_argument, NULL, 'S'},
{"version", no_argument, NULL, 'v'}, {"version", no_argument, NULL, 'v'},
{"syslog", no_argument, NULL, 'y'},
{"no-syslog", no_argument, NULL, 'Y'},
{0, no_argument, NULL, 0} {0, no_argument, NULL, 0}
}; };
const char opts[] = "c:hr:sv"; const char opts[] = "c:deEf:hl:mqr:sSvyY";
int cleanup_threads = 2; long cleanup_threads = 0;
int request_threads = 10; long request_threads = 0;
bool shutdown = false; bool shutdown = false;
const char *config_file = DEF_CONFIG_FILE;
bool force_config_file = false;
tun_bool_t option_log_stderr = TUN_UNDEF;
tun_bool_t option_log_syslog = TUN_UNDEF;
const char *pgm = NULL; char *c = NULL;
if (!(pgm = strrchr (*argv, '\\')) && !(pgm = strrchr (*argv, '/'))) /* Check if we have a terminal. If so, default to stderr logging,
pgm = *argv; otherwise default to syslog logging. This must be done early
to allow default logging already in option processing state. */
openlog ("cygserver", LOG_PID, LOG_KERN);
if (isatty (2))
log_stderr = TUN_TRUE;
else else
pgm++; log_syslog = TUN_TRUE;
wincap.init ();
if (wincap.has_security ())
setup_privileges ();
int opt; int opt;
opterr = 0;
while ((opt = getopt_long (argc, argv, opts, longopts, NULL)) != EOF) while ((opt = getopt_long (argc, argv, opts, longopts, NULL)) != EOF)
switch (opt) switch (opt)
{ {
case 'c': case 'c':
cleanup_threads = atoi (optarg); c = NULL;
if (cleanup_threads <= 0) cleanup_threads = strtol (optarg, &c, 10);
{ if (cleanup_threads <= 0 || cleanup_threads > 16 || (c && *c))
fprintf (stderr, panic ("Number of cleanup threads must be between 1 and 16");
"%s: number of cleanup threads must be positive\n",
pgm);
exit (1);
}
break; break;
case 'd':
log_debug = TUN_TRUE;
break;
case 'e':
option_log_stderr = TUN_TRUE;
break;
case 'E':
option_log_stderr = TUN_FALSE;
break;
case 'f':
config_file = optarg;
force_config_file = true;
break;
case 'h': case 'h':
print_usage (pgm); print_usage (getprogname ());
return 0; return 0;
case 'l':
c = NULL;
log_level = strtoul (optarg, &c, 10);
if (!log_level || log_level > 7 || (c && *c))
panic ("Log level must be between 1 and 7");
break;
case 'm':
support_sharedmem = TUN_FALSE;
break;
case 'q':
support_msgqueues = TUN_FALSE;
break;
case 'r': case 'r':
request_threads = atoi (optarg); c = NULL;
if (request_threads <= 0) request_threads = strtol (optarg, &c, 10);
{ if (request_threads <= 0 || request_threads > 64 || (c && *c))
fprintf (stderr, panic ("Number of request threads must be between 1 and 64");
"%s: number of request threads must be positive\n",
pgm);
exit (1);
}
break; break;
case 's': case 's':
support_semaphores = TUN_FALSE;
break;
case 'S':
shutdown = true; shutdown = true;
break; break;
case 'v': case 'v':
print_version (pgm); print_version ();
return 0; return 0;
case 'y':
option_log_syslog = TUN_TRUE;
break;
case 'Y':
option_log_syslog = TUN_FALSE;
break;
case '?': case '?':
fprintf (stderr, "Try `%s --help' for more information.\n", pgm); panic ("unknown option -- %c\n"
exit (1); "Try `%s --help' for more information.", optopt, getprogname ());
} }
if (optind != argc) if (optind != argc)
{ panic ("Too many arguments");
fprintf (stderr, "%s: too many arguments\n", pgm);
exit (1);
}
if (shutdown) if (shutdown)
{ {
@ -679,71 +680,76 @@ main (const int argc, char *argv[])
client_request_shutdown req; client_request_shutdown req;
if (req.make_request () == -1 || req.error_code ()) if (req.make_request () == -1 || req.error_code ())
{ panic("Shutdown request failed: %s", strerror (req.error_code ()));
fprintf (stderr, "%s: shutdown request failed: %s\n",
pgm, strerror (req.error_code ()));
exit (1);
}
// FIXME: It would be nice to wait here for the daemon to exit. // FIXME: It would be nice to wait here for the daemon to exit.
return 0; return 0;
} }
#define SIGHANDLE(SIG) \
do \
{ \
struct sigaction act; \
\
act.sa_handler = &handle_signal; \
act.sa_mask = 0; \
act.sa_flags = 0; \
\
if (sigaction (SIG, &act, NULL) == -1) \
{ \
system_printf ("failed to install handler for " #SIG ": %s", \
strerror (errno)); \
exit (1); \
} \
} while (false)
SIGHANDLE (SIGHUP); SIGHANDLE (SIGHUP);
SIGHANDLE (SIGINT); SIGHANDLE (SIGINT);
SIGHANDLE (SIGTERM); SIGHANDLE (SIGTERM);
print_version (pgm); tunable_param_init (config_file, force_config_file);
setbuf (stdout, NULL);
printf ("daemon starting up");
loginit (option_log_stderr, option_log_syslog);
log (LOG_INFO, "daemon starting up");
if (!cleanup_threads)
TUNABLE_INT_FETCH ("kern.srv.cleanup_threads", &cleanup_threads);
if (!cleanup_threads)
cleanup_threads = 2;
if (!request_threads)
TUNABLE_INT_FETCH ("kern.srv.request_threads", &request_threads);
if (!request_threads)
request_threads = 10;
if (support_sharedmem == TUN_UNDEF)
TUNABLE_BOOL_FETCH ("kern.srv.sharedmem", &support_sharedmem);
if (support_sharedmem == TUN_UNDEF)
support_sharedmem = TUN_TRUE;
if (support_msgqueues == TUN_UNDEF)
TUNABLE_BOOL_FETCH ("kern.srv.msgqueues", &support_msgqueues);
if (support_msgqueues == TUN_UNDEF)
support_msgqueues = TUN_TRUE;
if (support_semaphores == TUN_UNDEF)
TUNABLE_BOOL_FETCH ("kern.srv.semaphores", &support_semaphores);
if (support_semaphores == TUN_UNDEF)
support_semaphores = TUN_TRUE;
wincap.init ();
if (wincap.has_security () && !setup_privileges ())
panic ("Setting process privileges failed.");
/*XXXXX*/
threaded_queue request_queue (request_threads); threaded_queue request_queue (request_threads);
printf (".");
transport_layer_base *const transport = create_server_transport (); transport_layer_base *const transport = create_server_transport ();
assert (transport); assert (transport);
printf (".");
process_cache cache (cleanup_threads); process_cache cache (cleanup_threads);
printf (".");
server_submission_loop submission_loop (&request_queue, transport, &cache); server_submission_loop submission_loop (&request_queue, transport, &cache);
printf (".");
request_queue.add_submission_loop (&submission_loop); request_queue.add_submission_loop (&submission_loop);
printf (".");
if (transport->listen () == -1) if (transport->listen () == -1)
{ {
exit (1); exit (1);
} }
printf (".");
ipcinit ();
cache.start (); cache.start ();
printf (".");
request_queue.start (); request_queue.start ();
printf (".");
printf ("complete\n"); log (LOG_NOTICE, "Initialization complete. Waiting for requests.");
/* TODO: wait on multiple objects - the thread handle for each /* TODO: wait on multiple objects - the thread handle for each
* request loop + all the process handles. This should be done by * request loop + all the process handles. This should be done by
@ -758,16 +764,25 @@ main (const int argc, char *argv[])
-- if signal event then retrigger it -- if signal event then retrigger it
*/ */
while (!shutdown_server && request_queue.running () && cache.running ()) while (!shutdown_server && request_queue.running () && cache.running ())
pause (); {
pause ();
if (ipcunload ())
{
shutdown_server = false;
log (LOG_WARNING, "Shutdown request received but ignored. "
"Dependent processes still running.");
}
}
printf ("\nShutdown request received - new requests will be denied\n"); log (LOG_INFO, "Shutdown request received - new requests will be denied");
request_queue.stop (); request_queue.stop ();
printf ("All pending requests processed\n"); log (LOG_INFO, "All pending requests processed");
safe_delete (transport); delete transport;
printf ("No longer accepting requests - cygwin will operate in daemonless mode\n"); log (LOG_INFO, "No longer accepting requests - cygwin will operate in daemonless mode");
cache.stop (); cache.stop ();
printf ("All outstanding process-cache activities completed\n"); log (LOG_INFO, "All outstanding process-cache activities completed");
printf ("daemon shutdown\n"); log (LOG_NOTICE, "Shutdown finished.");
return 0; return 0;
} }
#endif /* __OUTSIDE_CYGWIN__ */

View File

@ -0,0 +1,126 @@
# cygserver.conf, Copyright(C) 2003 Red Hat Inc.
#
# Contains configurable parameters for the cygserver.
#
# The format of this file is easy. Lines beginning with a hash `#' are
# comments and ignored. Lines consisting of only whitespaces are ignored.
# Any other line is a setting for cygserver.
# A setting consists of a name/value pair, separated by whitespace.
# Each line must only consist of one name/value pair.
# Lines must not be longer than 1023 characters.
#
# Some settings can be overridden by a command line switch. If so, it's
# mentioned below.
#
# Settings which are commented out will use the default values. These are
# mentioned below, too.
# kern.srv.cleanup_threads: No. of cygserver threads used for cleanup tasks.
# Default: 2, Min: 1, Max: 16, command line option -c, --cleanup-threads
#kern.srv.cleanup_threads 2
# kern.srv.request_threads: No. of cygserver threads used to serve
# application requests.
# Default: 10, Min: 1, Max: 64, command line option -r, --request-threads
#kern.srv.request_threads 10
# kern.srv.msgqueues: Determines whether XSI Message Queue support should be
# started, "yes" (or "true", "y", "t", "1") or "no" (or "false", "n", "f", "0").
# These values are valid for all binary type options.
# Default is "yes". Command line option -q, --no-msgqueues
#kern.srv.msgqueues yes
# kern.srv.semaphores: Determines whether XSI Semaphore support should be
# started. Default is "yes". Command line option -s, --no-semaphores
#kern.srv.semaphores yes
# kern.srv.sharedmem: Determines whether XSI Shared Memory support should be
# started. Default is "yes". Command line option -m, --no-sharedmem
#kern.srv.sharedmem yes
# LOGGING
# kern.log.syslog: Determines whether logging should go to the syslog,
# Default is "yes", if stderr is no tty, "no" otherwise.
# Command line option -y, --syslog or -Y, --no-syslog.
#kern.log.syslog no
# kern.log.stderr: Determines whether logging should go to stderr,
# Default is "yes", if stderr is a tty, "no" otherwise.
# Command line option -e, --stderr or -E, --no-stderr.
#kern.log.stderr no
# kern.log.level: Logging level. Valid values are 1 to 7 with a bigger
# value emitting more logging output. Default level is 6.
# Command line option -l, --log-level.
#kern.log.level 6
# kern.log.debug: Determines whether debug output should be printed to stderr.
# Default is "no". Command line option -d, --debug
#kern.log.debug no
# XSI message queue parameters.
#
# Each message is broken up and stored in segments that are msgssz bytes
# long. For efficiency reasons, this should be a power of two. Also,
# it doesn't make sense if it is less than 8 or greater than about 256.
# kern.ipc.msgseg: Maximum no. of message queue segments hold concurrently.
# Default: 2048, Min: 256, Max: 32767
#kern.ipc.msgseg 2048
# kern.ipc.msgssz: Size of segment in bytes. Must be a power of 2 value.
# Default: 8, Min: 8, Max: 1024
#kern.ipc.msgssz 8
# kern.ipc.msgmni: Maximum no. of message queue identifiers hold concurrently.
# Default: 40, Min: 1, Max: 1024
#kern.ipc.msgmni 40
# XSI semaphore parameters
# kern.ipc.semmni: Maximum no. of semaphore identifiers hold concurrently.
# Default: 10, Min: 1, Max: 1024
#kern.ipc.semmni 10
# kern.ipc.semmns: Maximum no. of semaphores hold concurrently.
# Default: 60, Min: 1, Max: 1024
#kern.ipc.semmns 60
# kern.ipc.semmnu: Total no. of undo structures hold by server.
# Default: 30, Min: 1, Max: 1024
#kern.ipc.semmnu 30
# kern.ipc.semmsl: Maximum no. of semaphores per semaphore id.
# Default: 60, Min: 1, Max: 1024
#kern.ipc.semmsl 60
# kern.ipc.semopm: Maximum no. of operations per semop call.
# Default: 100, Min: 1, Max: 1024
#kern.ipc.semopm 100
# kern.ipc.semume: Maximum no. of undo entries per process.
# Default: 10, Min: 1, Max: 1024
#kern.ipc.semume 10
# kern.ipc.semvmx: Maximum value of a semaphore.
# Default: 32767, Min: 1, Max: 32767
#kern.ipc.semvmx 32767
# kern.ipc.semaem: Maximum value to adjust on process exit.
# Default: 16384, Min: 1, Max: 32767
#kern.ipc.semaem 16384
# XSI shared memory parameters
# kern.ipc.shmmaxpgs: Maximum pages available for XSI shared memory.
# Default: 8192, Min: 1, Max: 32767
#kern.ipc.shmmaxpgs 8192
# kern.ipc.shmmni: Maximum number of shared memory segments, system wide.
# Default: 192, Min: 1, Max: 32767
#kern.ipc.shmmni 192
# kern.ipc.shmseg: Maximum number of shared memory segments per process.
# Default: 128, Min: 1, Max: 32767
#kern.ipc.shmseg 128

View File

@ -1,8 +1,6 @@
/* msg.cc: Single unix specification IPC interface for Cygwin. /* msg.cc: Single unix specification IPC interface for Cygwin.
Copyright 2002 Red Hat, Inc. Copyright 2003 Red Hat, Inc.
Written by Conrad Scott <conrad.scott@dsl.pipex.com>.
This file is part of Cygwin. This file is part of Cygwin.
@ -10,38 +8,103 @@ This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */ details. */
#include "winsup.h" #ifdef __OUTSIDE_CYGWIN__
#include "woutsup.h"
#include <sys/types.h> #include <errno.h>
#include <cygwin/msg.h> #include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "cygserver.h"
#include "process.h"
#include "transport.h"
#include "cygerrno.h" #include "cygserver_ipc.h"
#include "cygserver_msg.h"
extern "C" int client_request_msg::client_request_msg ()
msgctl (int msqid, int cmd, struct msqid_ds *buf) : client_request (CYGSERVER_REQUEST_MSG,
{ &_parameters, sizeof (_parameters))
set_errno (ENOSYS); {
return -1;
} }
extern "C" int void
msgget (key_t key, int msgflg) client_request_msg::serve (transport_layer_base *const conn,
process_cache *const cache)
{ {
set_errno (ENOSYS); if (msglen () != sizeof (_parameters.in))
return -1; {
} syscall_printf ("bad request body length: expecting %lu bytes, got %lu",
sizeof (_parameters), msglen ());
extern "C" ssize_t error_code (EINVAL);
msgrcv (int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg) msglen (0);
{ return;
set_errno (ENOSYS); }
return -1; if (support_msgqueues == TUN_FALSE)
} {
syscall_printf ("Message queue support not started");
extern "C" int error_code (ENOSYS);
msgsnd (int msqid, const void *msgp, size_t msgsz, int msgflg) if (_parameters.in.msgop == MSGOP_msgrcv)
{ _parameters.out.rcv = -1;
set_errno (ENOSYS); else
return -1; _parameters.out.ret = -1;
msglen (sizeof (_parameters.out));
return;
}
process *const client = cache->process (_parameters.in.ipcblk.cygpid,
_parameters.in.ipcblk.winpid);
if (!client)
{
error_code (EAGAIN);
msglen (0);
return;
}
if (!conn->impersonate_client ())
{
client->release ();
error_code (EACCES);
msglen (0);
return;
}
if (!adjust_identity_info (&_parameters.in.ipcblk))
{
conn->revert_to_self ();
error_code (EACCES);
msglen (0);
return;
}
/* Early revert_to_self since IPC code runs in kernel mode. */
conn->revert_to_self ();
thread td = { client, &_parameters.in.ipcblk, {-1, -1} };
int res;
msgop_t msgop = _parameters.in.msgop; /* Get's overwritten otherwise. */
switch (msgop)
{
case MSGOP_msgctl:
res = msgctl (&td, &_parameters.in.ctlargs);
break;
case MSGOP_msgget:
res = msgget (&td, &_parameters.in.getargs);
break;
case MSGOP_msgrcv:
res = msgrcv (&td, &_parameters.in.rcvargs);
break;
case MSGOP_msgsnd:
res = msgsnd (&td, &_parameters.in.sndargs);
break;
}
/* Allocated by the call to adjust_identity_info(). */
if (_parameters.in.ipcblk.gidlist)
free (_parameters.in.ipcblk.gidlist);
client->release ();
error_code (res);
if (msgop == MSGOP_msgrcv)
_parameters.out.rcv = td.td_retval[0];
else
_parameters.out.ret = td.td_retval[0];
msglen (sizeof (_parameters.out));
} }
#endif /* __OUTSIDE_CYGWIN__ */

View File

@ -1,4 +1,4 @@
/* cygserver_process.cc /* process.cc
Copyright 2001, 2002 Red Hat Inc. Copyright 2001, 2002 Red Hat Inc.
@ -19,7 +19,7 @@ details. */
#include "cygerrno.h" #include "cygerrno.h"
#include "cygserver_process.h" #include "process.h"
/*****************************************************************************/ /*****************************************************************************/
@ -29,7 +29,7 @@ details. */
process_cleanup::~process_cleanup () process_cleanup::~process_cleanup ()
{ {
safe_delete (_process); delete _process;
} }
void void
@ -139,7 +139,7 @@ process::remove (const cleanup_routine *const entry)
else else
_routines_head = ptr->_next; _routines_head = ptr->_next;
safe_delete (ptr); delete ptr;
res = true; res = true;
break; break;
} }
@ -170,7 +170,7 @@ process::cleanup ()
cleanup_routine *const ptr = entry; cleanup_routine *const ptr = entry;
entry = entry->_next; entry = entry->_next;
ptr->cleanup (this); ptr->cleanup (this);
safe_delete (ptr); delete ptr;
} }
} }
@ -250,11 +250,11 @@ process_cache::process (const pid_t cygpid, const DWORD winpid)
return NULL; return NULL;
} }
entry = safe_new (class process, cygpid, winpid); entry = new class process (cygpid, winpid);
if (!entry->is_active ()) if (!entry->is_active ())
{ {
LeaveCriticalSection (&_cache_write_access); LeaveCriticalSection (&_cache_write_access);
safe_delete (entry); delete entry;
set_errno (ESRCH); set_errno (ESRCH);
return NULL; return NULL;
} }
@ -408,7 +408,7 @@ process_cache::check_and_remove_process (const size_t index)
LeaveCriticalSection (&_cache_write_access); LeaveCriticalSection (&_cache_write_access);
/* Schedule any cleanup tasks for this process. */ /* Schedule any cleanup tasks for this process. */
_queue.add (safe_new (process_cleanup, process)); _queue.add (new process_cleanup (process));
} }
class process * class process *

View File

@ -1,4 +1,4 @@
/* cygserver_process.h /* process.h
Copyright 2001, 2002 Red Hat Inc. Copyright 2001, 2002 Red Hat Inc.
@ -10,8 +10,8 @@ This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */ details. */
#ifndef _CYGSERVER_PROCESS_ #ifndef _PROCESS_H
#define _CYGSERVER_PROCESS_ #define _PROCESS_H
#include <assert.h> #include <assert.h>
@ -161,4 +161,4 @@ private:
class process *find (DWORD winpid, class process **previous = NULL); class process *find (DWORD winpid, class process **previous = NULL);
}; };
#endif /* _CYGSERVER_PROCESS_ */ #endif /* _PROCESS_H */

View File

@ -1,8 +1,6 @@
/* sem.cc: Single unix specification IPC interface for Cygwin. /* sem.cc: Single unix specification IPC interface for Cygwin.
Copyright 2002 Red Hat, Inc. Copyright 2003 Red Hat, Inc.
Written by Conrad Scott <conrad.scott@dsl.pipex.com>.
This file is part of Cygwin. This file is part of Cygwin.
@ -10,31 +8,94 @@ This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */ details. */
#include "winsup.h" #ifdef __OUTSIDE_CYGWIN__
#include "woutsup.h"
#include <sys/types.h> #include <errno.h>
#include <cygwin/sem.h> #include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "cygserver.h"
#include "process.h"
#include "transport.h"
#include "cygerrno.h" #include "cygserver_ipc.h"
#include "cygserver_sem.h"
extern "C" int client_request_sem::client_request_sem ()
semctl (int semid, int semnum, int cmd, ...) : client_request (CYGSERVER_REQUEST_SEM,
{ &_parameters, sizeof (_parameters))
set_errno (ENOSYS); {
return -1;
} }
extern "C" int void
semget (key_t key, int nsems, int semflg) client_request_sem::serve (transport_layer_base *const conn,
process_cache *const cache)
{ {
set_errno (ENOSYS); if (msglen () != sizeof (_parameters.in))
return -1; {
} syscall_printf ("bad request body length: expecting %lu bytes, got %lu",
sizeof (_parameters), msglen ());
extern "C" int error_code (EINVAL);
semop (int semid, struct sembuf *sops, size_t nsops) msglen (0);
{ return;
set_errno (ENOSYS); }
return -1; if (support_semaphores == TUN_FALSE)
{
syscall_printf ("Semaphore support not started");
error_code (ENOSYS);
_parameters.out.ret = -1;
msglen (sizeof (_parameters.out));
return;
}
process *const client = cache->process (_parameters.in.ipcblk.cygpid,
_parameters.in.ipcblk.winpid);
if (!client)
{
error_code (EAGAIN);
msglen (0);
return;
}
if (!conn->impersonate_client ())
{
client->release ();
error_code (EACCES);
msglen (0);
return;
}
if (!adjust_identity_info (&_parameters.in.ipcblk))
{
client->release ();
conn->revert_to_self ();
error_code (EACCES);
msglen (0);
return;
}
/* Early revert_to_self since IPC code runs in kernel mode. */
conn->revert_to_self ();
thread td = { client, &_parameters.in.ipcblk, {-1, -1} };
int res;
switch (_parameters.in.semop)
{
case SEMOP_semctl:
res = semctl (&td, &_parameters.in.ctlargs);
break;
case SEMOP_semget:
res = semget (&td, &_parameters.in.getargs);
break;
case SEMOP_semop:
res = semop (&td, &_parameters.in.opargs);
break;
}
/* Allocated by the call to adjust_identity_info(). */
if (_parameters.in.ipcblk.gidlist)
free (_parameters.in.ipcblk.gidlist);
client->release ();
error_code (res);
_parameters.out.ret = td.td_retval[0];
msglen (sizeof (_parameters.out));
} }
#endif /* __OUTSIDE_CYGWIN__ */

View File

@ -1,9 +1,6 @@
/* cygserver_shm.cc: Single unix specification IPC interface for Cygwin. /* shm.cc: Single unix specification IPC interface for Cygwin.
Copyright 2002 Red Hat, Inc. Copyright 2003 Red Hat, Inc.
Written by Conrad Scott <conrad.scott@dsl.pipex.com>.
Based on code by Robert Collins <robert.collins@hotmail.com>.
This file is part of Cygwin. This file is part of Cygwin.
@ -11,824 +8,33 @@ This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */ details. */
#ifdef __OUTSIDE_CYGWIN__
#include "woutsup.h" #include "woutsup.h"
#include <errno.h> #include <errno.h>
#include <pthread.h> #include <pthread.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <time.h> #include <time.h>
#include "cygserver.h"
#include "process.h"
#include "transport.h"
#include "cygserver_ipc.h" #include "cygserver_ipc.h"
#include "cygserver_shm.h" #include "cygserver_shm.h"
#include "security.h"
#include "cygserver.h"
#include "cygserver_process.h"
#include "cygserver_transport.h"
/*---------------------------------------------------------------------------*
* class server_shmmgr
*
* A singleton class.
*---------------------------------------------------------------------------*/
#define shmmgr (server_shmmgr::instance ())
class server_shmmgr
{
private:
class attach_t
{
public:
class process *const _client;
unsigned int _refcnt;
attach_t *_next;
attach_t (class process *const client)
: _client (client),
_refcnt (0),
_next (NULL)
{}
};
class segment_t
{
private:
// Bits for the _flg field.
enum { IS_DELETED = 0x01 };
public:
const int _intid;
const int _shmid;
struct shmid_ds _ds;
segment_t *_next;
segment_t (const key_t key, const int intid, const HANDLE hFileMap);
~segment_t ();
bool is_deleted () const
{
return _flg & IS_DELETED;
}
bool is_pending_delete () const
{
return !_ds.shm_nattch && is_deleted ();
}
void mark_deleted ()
{
assert (!is_deleted ());
_flg |= IS_DELETED;
}
int attach (class process *, HANDLE & hFileMap);
int detach (class process *);
private:
static long _sequence;
int _flg;
const HANDLE _hFileMap;
attach_t *_attach_head; // A list sorted by winpid;
attach_t *find (const class process *, attach_t **previous = NULL);
};
class cleanup_t : public cleanup_routine
{
public:
cleanup_t (const segment_t *const segptr)
: cleanup_routine (reinterpret_cast<void *> (segptr->_shmid))
{
assert (key ());
}
int shmid () const { return reinterpret_cast<int> (key ()); }
virtual void cleanup (class process *const client)
{
const int res = shmmgr.shmdt (shmid (), client);
if (res != 0)
debug_printf ("process cleanup failed [shmid = %d]: %s",
shmid (), strerror (-res));
}
};
public:
static server_shmmgr & instance ();
int shmat (HANDLE & hFileMap,
int shmid, int shmflg, class process *);
int shmctl (int & out_shmid, struct shmid_ds & out_ds,
struct shminfo & out_shminfo, struct shm_info & out_shm_info,
const int shmid, int cmd, const struct shmid_ds &,
class process *);
int shmdt (int shmid, class process *);
int shmget (int & out_shmid, key_t, size_t, int shmflg, uid_t, gid_t,
class process *);
private:
static server_shmmgr *_instance;
static pthread_once_t _instance_once;
static void initialise_instance ();
CRITICAL_SECTION _segments_lock;
segment_t *_segments_head; // A list sorted by int_id.
int _shm_ids; // Number of shm segments (for ipcs(8)).
int _shm_tot; // Total bytes of shm segments (for ipcs(8)).
int _shm_atts; // Number of attached segments (for ipcs(8)).
int _intid_max; // Highest intid yet allocated (for ipcs(8)).
server_shmmgr ();
~server_shmmgr ();
// Undefined (as this class is a singleton):
server_shmmgr (const server_shmmgr &);
server_shmmgr & operator= (const server_shmmgr &);
segment_t *find_by_key (key_t);
segment_t *find (int intid, segment_t **previous = NULL);
int new_segment (key_t, size_t, int shmflg, pid_t, uid_t, gid_t);
segment_t *new_segment (key_t, size_t, HANDLE);
void delete_segment (segment_t *);
};
/* static */ long server_shmmgr::segment_t::_sequence = 0;
/* static */ server_shmmgr *server_shmmgr::_instance = NULL;
/* static */ pthread_once_t server_shmmgr::_instance_once = PTHREAD_ONCE_INIT;
/*---------------------------------------------------------------------------*
* server_shmmgr::segment_t::segment_t ()
*---------------------------------------------------------------------------*/
server_shmmgr::segment_t::segment_t (const key_t key,
const int intid,
const HANDLE hFileMap)
: _intid (intid),
_shmid (ipc_int2ext (intid, IPC_SHMOP, _sequence)),
_next (NULL),
_flg (0),
_hFileMap (hFileMap),
_attach_head (NULL)
{
assert (0 <= _intid && _intid < SHMMNI);
memset (&_ds, '\0', sizeof (_ds));
_ds.shm_perm.key = key;
}
/*---------------------------------------------------------------------------*
* server_shmmgr::segment_t::~segment_t ()
*---------------------------------------------------------------------------*/
server_shmmgr::segment_t::~segment_t ()
{
assert (!_attach_head);
if (!CloseHandle (_hFileMap))
syscall_printf ("failed to close file map [handle = 0x%x]: %E", _hFileMap);
}
/*---------------------------------------------------------------------------*
* server_shmmgr::segment_t::attach ()
*---------------------------------------------------------------------------*/
int
server_shmmgr::segment_t::attach (class process *const client,
HANDLE & hFileMap)
{
assert (client);
if (!DuplicateHandle (GetCurrentProcess (),
_hFileMap,
client->handle (),
&hFileMap,
0,
FALSE, // bInheritHandle
DUPLICATE_SAME_ACCESS))
{
syscall_printf (("failed to duplicate handle for client "
"[key = 0x%016llx, shmid = %d, handle = 0x%x]: %E"),
_ds.shm_perm.key, _shmid, _hFileMap);
return -EACCES; // FIXME: Case analysis?
}
_ds.shm_lpid = client->cygpid ();
_ds.shm_nattch += 1;
_ds.shm_atime = time (NULL); // FIXME: sub-second times.
attach_t *previous = NULL;
attach_t *attptr = find (client, &previous);
if (!attptr)
{
attptr = safe_new (attach_t, client);
if (previous)
{
attptr->_next = previous->_next;
previous->_next = attptr;
}
else
{
attptr->_next = _attach_head;
_attach_head = attptr;
}
}
attptr->_refcnt += 1;
cleanup_t *const cleanup = safe_new (cleanup_t, this);
// FIXME: ::add should only fail if the process object is already
// cleaning up; but it can't be doing that since this thread has it
// locked.
const bool result = client->add (cleanup);
assert (result);
return 0;
}
/*---------------------------------------------------------------------------*
* server_shmmgr::segment_t::detach ()
*---------------------------------------------------------------------------*/
int
server_shmmgr::segment_t::detach (class process *const client)
{
attach_t *previous = NULL;
attach_t *const attptr = find (client, &previous);
if (!attptr)
return -EINVAL;
if (client->is_active ())
{
const cleanup_t key (this);
if (!client->remove (&key))
syscall_printf (("failed to remove cleanup routine for %d(%lu) "
"[shmid = %d]"),
client->cygpid (), client->winpid (),
_shmid);
}
attptr->_refcnt -= 1;
if (!attptr->_refcnt)
{
assert (previous ? previous->_next == attptr : _attach_head == attptr);
if (previous)
previous->_next = attptr->_next;
else
_attach_head = attptr->_next;
safe_delete (attptr);
}
assert (_ds.shm_nattch > 0);
_ds.shm_lpid = client->cygpid ();
_ds.shm_nattch -= 1;
_ds.shm_dtime = time (NULL); // FIXME: sub-second times.
return 0;
}
/*---------------------------------------------------------------------------*
* server_shmmgr::segment_t::find ()
*---------------------------------------------------------------------------*/
server_shmmgr::attach_t *
server_shmmgr::segment_t::find (const class process *const client,
attach_t **previous)
{
if (previous)
*previous = NULL;
// Nb. The _attach_head list is sorted by winpid.
for (attach_t *attptr = _attach_head; attptr; attptr = attptr->_next)
if (attptr->_client == client)
return attptr;
else if (attptr->_client->winpid () > client->winpid ())
return NULL;
else if (previous)
*previous = attptr;
return NULL;
}
/*---------------------------------------------------------------------------*
* server_shmmgr::instance ()
*---------------------------------------------------------------------------*/
/* static */ server_shmmgr &
server_shmmgr::instance ()
{
pthread_once (&_instance_once, &initialise_instance);
assert (_instance);
return *_instance;
}
/*---------------------------------------------------------------------------*
* server_shmmgr::shmat ()
*---------------------------------------------------------------------------*/
int
server_shmmgr::shmat (HANDLE & hFileMap,
const int shmid, const int shmflg,
class process *const client)
{
syscall_printf ("shmat (shmid = %d, shmflg = 0%o) for %d(%lu)",
shmid, shmflg, client->cygpid (), client->winpid ());
int result = 0;
EnterCriticalSection (&_segments_lock);
segment_t *const segptr = find (ipc_ext2int (shmid, IPC_SHMOP));
if (!segptr)
result = -EINVAL;
else
result = segptr->attach (client, hFileMap);
if (!result)
_shm_atts += 1;
LeaveCriticalSection (&_segments_lock);
if (result < 0)
syscall_printf (("-1 [%d] = shmat (shmid = %d, shmflg = 0%o) "
"for %d(%lu)"),
-result, shmid, shmflg,
client->cygpid (), client->winpid ());
else
syscall_printf (("0x%x = shmat (shmid = %d, shmflg = 0%o) "
"for %d(%lu)"),
hFileMap, shmid, shmflg,
client->cygpid (), client->winpid ());
return result;
}
/*---------------------------------------------------------------------------*
* server_shmmgr::shmctl ()
*---------------------------------------------------------------------------*/
int
server_shmmgr::shmctl (int & out_shmid,
struct shmid_ds & out_ds,
struct shminfo & out_shminfo,
struct shm_info & out_shm_info,
const int shmid, const int cmd,
const struct shmid_ds & ds,
class process *const client)
{
syscall_printf ("shmctl (shmid = %d, cmd = 0x%x) for %d(%lu)",
shmid, cmd, client->cygpid (), client->winpid ());
int result = 0;
EnterCriticalSection (&_segments_lock);
switch (cmd)
{
case IPC_STAT:
case SHM_STAT: // Uses intids rather than shmids.
case IPC_SET:
case IPC_RMID:
{
int intid;
if (cmd == SHM_STAT)
intid = shmid;
else
intid = ipc_ext2int (shmid, IPC_SHMOP);
segment_t *const segptr = find (intid);
if (!segptr)
result = -EINVAL;
else
switch (cmd)
{
case IPC_STAT:
out_ds = segptr->_ds;
break;
case IPC_SET:
segptr->_ds.shm_perm.uid = ds.shm_perm.uid;
segptr->_ds.shm_perm.gid = ds.shm_perm.gid;
segptr->_ds.shm_perm.mode = ds.shm_perm.mode & 0777;
segptr->_ds.shm_lpid = client->cygpid ();
segptr->_ds.shm_ctime = time (NULL); // FIXME: sub-second times.
break;
case IPC_RMID:
if (segptr->is_deleted ())
result = -EIDRM;
else
{
segptr->mark_deleted ();
if (segptr->is_pending_delete ())
delete_segment (segptr);
}
break;
case SHM_STAT: // ipcs(8) i'face.
out_ds = segptr->_ds;
out_shmid = segptr->_shmid;
break;
}
}
break;
case IPC_INFO:
out_shminfo.shmmax = SHMMAX;
out_shminfo.shmmin = SHMMIN;
out_shminfo.shmmni = SHMMNI;
out_shminfo.shmseg = SHMSEG;
out_shminfo.shmall = SHMALL;
break;
case SHM_INFO: // ipcs(8) i'face.
out_shmid = _intid_max;
out_shm_info.shm_ids = _shm_ids;
out_shm_info.shm_tot = _shm_tot;
out_shm_info.shm_atts = _shm_atts;
break;
default:
result = -EINVAL;
break;
}
LeaveCriticalSection (&_segments_lock);
if (result < 0)
syscall_printf (("-1 [%d] = "
"shmctl (shmid = %d, cmd = 0x%x) for %d(%lu)"),
-result,
shmid, cmd, client->cygpid (), client->winpid ());
else
syscall_printf (("%d = "
"shmctl (shmid = %d, cmd = 0x%x) for %d(%lu)"),
((cmd == SHM_STAT || cmd == SHM_INFO)
? out_shmid
: result),
shmid, cmd, client->cygpid (), client->winpid ());
return result;
}
/*---------------------------------------------------------------------------*
* server_shmmgr::shmdt ()
*---------------------------------------------------------------------------*/
int
server_shmmgr::shmdt (const int shmid, class process *const client)
{
syscall_printf ("shmdt (shmid = %d) for %d(%lu)",
shmid, client->cygpid (), client->winpid ());
int result = 0;
EnterCriticalSection (&_segments_lock);
segment_t *const segptr = find (ipc_ext2int (shmid, IPC_SHMOP));
if (!segptr)
result = -EINVAL;
else
result = segptr->detach (client);
if (!result)
_shm_atts -= 1;
if (!result && segptr->is_pending_delete ())
delete_segment (segptr);
LeaveCriticalSection (&_segments_lock);
if (result < 0)
syscall_printf ("-1 [%d] = shmdt (shmid = %d) for %d(%lu)",
-result, shmid, client->cygpid (), client->winpid ());
else
syscall_printf ("%d = shmdt (shmid = %d) for %d(%lu)",
result, shmid, client->cygpid (), client->winpid ());
return result;
}
/*---------------------------------------------------------------------------*
* server_shmmgr::shmget ()
*---------------------------------------------------------------------------*/
int
server_shmmgr::shmget (int & out_shmid,
const key_t key, const size_t size, const int shmflg,
const uid_t uid, const gid_t gid,
class process *const client)
{
syscall_printf (("shmget (key = 0x%016llx, size = %u, shmflg = 0%o) "
"for %d(%lu)"),
key, size, shmflg,
client->cygpid (), client->winpid ());
int result = 0;
EnterCriticalSection (&_segments_lock);
if (key == IPC_PRIVATE)
result = new_segment (key, size, shmflg,
client->cygpid (), uid, gid);
else
{
segment_t *const segptr = find_by_key (key);
if (!segptr)
if (shmflg & IPC_CREAT)
result = new_segment (key, size, shmflg,
client->cygpid (), uid, gid);
else
result = -ENOENT;
else if (segptr->is_deleted ())
result = -EIDRM;
else if ((shmflg & IPC_CREAT) && (shmflg & IPC_EXCL))
result = -EEXIST;
else if ((shmflg & ~(segptr->_ds.shm_perm.mode)) & 0777)
result = -EACCES;
else if (size && segptr->_ds.shm_segsz < size)
result = -EINVAL;
else
result = segptr->_shmid;
}
LeaveCriticalSection (&_segments_lock);
if (result >= 0)
{
out_shmid = result;
result = 0;
}
if (result < 0)
syscall_printf (("-1 [%d] = "
"shmget (key = 0x%016llx, size = %u, shmflg = 0%o) "
"for %d(%lu)"),
-result,
key, size, shmflg,
client->cygpid (), client->winpid ());
else
syscall_printf (("%d = "
"shmget (key = 0x%016llx, size = %u, shmflg = 0%o) "
"for %d(%lu)"),
out_shmid,
key, size, shmflg,
client->cygpid (), client->winpid ());
return result;
}
/*---------------------------------------------------------------------------*
* server_shmmgr::initialise_instance ()
*---------------------------------------------------------------------------*/
/* static */ void
server_shmmgr::initialise_instance ()
{
assert (!_instance);
_instance = safe_new0 (server_shmmgr);
assert (_instance);
}
/*---------------------------------------------------------------------------*
* server_shmmgr::server_shmmgr ()
*---------------------------------------------------------------------------*/
server_shmmgr::server_shmmgr ()
: _segments_head (NULL),
_shm_ids (0),
_shm_tot (0),
_shm_atts (0),
_intid_max (0)
{
InitializeCriticalSection (&_segments_lock);
}
/*---------------------------------------------------------------------------*
* server_shmmgr::~server_shmmgr ()
*---------------------------------------------------------------------------*/
server_shmmgr::~server_shmmgr ()
{
DeleteCriticalSection (&_segments_lock);
}
/*---------------------------------------------------------------------------*
* server_shmmgr::find_by_key ()
*---------------------------------------------------------------------------*/
server_shmmgr::segment_t *
server_shmmgr::find_by_key (const key_t key)
{
for (segment_t *segptr = _segments_head; segptr; segptr = segptr->_next)
if (segptr->_ds.shm_perm.key == key)
return segptr;
return NULL;
}
/*---------------------------------------------------------------------------*
* server_shmmgr::find ()
*---------------------------------------------------------------------------*/
server_shmmgr::segment_t *
server_shmmgr::find (const int intid, segment_t **previous)
{
if (previous)
*previous = NULL;
for (segment_t *segptr = _segments_head; segptr; segptr = segptr->_next)
if (segptr->_intid == intid)
return segptr;
else if (segptr->_intid > intid) // The list is sorted by intid.
return NULL;
else if (previous)
*previous = segptr;
return NULL;
}
/*---------------------------------------------------------------------------*
* server_shmmgr::new_segment ()
*---------------------------------------------------------------------------*/
int
server_shmmgr::new_segment (const key_t key,
const size_t size,
const int shmflg,
const pid_t cygpid,
const uid_t uid,
const gid_t gid)
{
if (size < SHMMIN || size > SHMMAX)
return -EINVAL;
const HANDLE hFileMap = CreateFileMapping (INVALID_HANDLE_VALUE,
NULL, PAGE_READWRITE,
0, size,
NULL);
if (!hFileMap)
{
syscall_printf ("failed to create file mapping [size = %lu]: %E", size);
return -ENOMEM; // FIXME
}
segment_t *const segptr = new_segment (key, size, hFileMap);
if (!segptr)
{
(void) CloseHandle (hFileMap);
return -ENOSPC;
}
segptr->_ds.shm_perm.cuid = segptr->_ds.shm_perm.uid = uid;
segptr->_ds.shm_perm.cgid = segptr->_ds.shm_perm.gid = gid;
segptr->_ds.shm_perm.mode = shmflg & 0777;
segptr->_ds.shm_segsz = size;
segptr->_ds.shm_cpid = cygpid;
segptr->_ds.shm_ctime = time (NULL); // FIXME: sub-second times.
return segptr->_shmid;
}
/*---------------------------------------------------------------------------*
* server_shmmgr::new_segment ()
*
* Allocate a new segment for the given key and file map with the
* lowest available intid and insert into the segment map.
*---------------------------------------------------------------------------*/
server_shmmgr::segment_t *
server_shmmgr::new_segment (const key_t key, const size_t size,
const HANDLE hFileMap)
{
// FIXME: Overflow risk.
if (_shm_tot + size > SHMALL)
return NULL;
int intid = 0; // Next expected intid value.
segment_t *previous = NULL; // Insert pointer.
// Find first unallocated intid.
for (segment_t *segptr = _segments_head;
segptr && segptr->_intid == intid;
segptr = segptr->_next, intid++)
{
previous = segptr;
}
/* By the time this condition is reached (given the default value of
* SHMMNI), the linear searches should all replaced by something
* just a *little* cleverer . . .
*/
if (intid >= SHMMNI)
return NULL;
segment_t *const segptr = safe_new (segment_t, key, intid, hFileMap);
assert (segptr);
if (previous)
{
segptr->_next = previous->_next;
previous->_next = segptr;
}
else
{
segptr->_next = _segments_head;
_segments_head = segptr;
}
_shm_ids += 1;
_shm_tot += size;
if (intid > _intid_max)
_intid_max = intid;
return segptr;
}
/*---------------------------------------------------------------------------*
* server_shmmgr::delete_segment ()
*---------------------------------------------------------------------------*/
void
server_shmmgr::delete_segment (segment_t *const segptr)
{
assert (segptr);
assert (segptr->is_pending_delete ());
segment_t *previous = NULL;
const segment_t *const tmp = find (segptr->_intid, &previous);
assert (tmp == segptr);
assert (previous ? previous->_next == segptr : _segments_head == segptr);
if (previous)
previous->_next = segptr->_next;
else
_segments_head = segptr->_next;
assert (_shm_ids > 0);
_shm_ids -= 1;
_shm_tot -= segptr->_ds.shm_segsz;
safe_delete (segptr);
}
/*---------------------------------------------------------------------------*
* client_request_shm::client_request_shm ()
*---------------------------------------------------------------------------*/
client_request_shm::client_request_shm () client_request_shm::client_request_shm ()
: client_request (CYGSERVER_REQUEST_SHM, : client_request (CYGSERVER_REQUEST_SHM,
&_parameters, sizeof (_parameters)) &_parameters, sizeof (_parameters))
{ {
// verbose: syscall_printf ("created");
} }
/*---------------------------------------------------------------------------*
* client_request_shm::serve ()
*---------------------------------------------------------------------------*/
void void
client_request_shm::serve (transport_layer_base *const conn, client_request_shm::serve (transport_layer_base *const conn,
process_cache *const cache) process_cache *const cache)
{ {
assert (conn);
assert (!error_code ());
if (msglen () != sizeof (_parameters.in)) if (msglen () != sizeof (_parameters.in))
{ {
syscall_printf ("bad request body length: expecting %lu bytes, got %lu", syscall_printf ("bad request body length: expecting %lu bytes, got %lu",
@ -837,60 +43,76 @@ client_request_shm::serve (transport_layer_base *const conn,
msglen (0); msglen (0);
return; return;
} }
if (support_sharedmem == TUN_FALSE)
// FIXME: Get a return code out of this and don't continue on error. {
conn->impersonate_client (); syscall_printf ("Shared memory support not started");
error_code (ENOSYS);
class process *const client = cache->process (_parameters.in.cygpid, if (_parameters.in.shmop == SHMOP_shmat)
_parameters.in.winpid); _parameters.out.ptr = (vm_offset_t)0;
else
_parameters.out.ret = -1;
msglen (sizeof (_parameters.out));
return;
}
process *const client = cache->process (_parameters.in.ipcblk.cygpid,
_parameters.in.ipcblk.winpid);
if (!client) if (!client)
{ {
error_code (EAGAIN); error_code (EAGAIN);
msglen (0); msglen (0);
return; return;
} }
if (!conn->impersonate_client ())
int result = -EINVAL;
switch (_parameters.in.shmop)
{ {
case SHMOP_shmget: client->release ();
result = shmmgr.shmget (_parameters.out.shmid, error_code (EACCES);
_parameters.in.key, _parameters.in.size,
_parameters.in.shmflg,
_parameters.in.uid, _parameters.in.gid,
client);
break;
case SHMOP_shmat:
result = shmmgr.shmat (_parameters.out.hFileMap,
_parameters.in.shmid, _parameters.in.shmflg,
client);
break;
case SHMOP_shmdt:
result = shmmgr.shmdt (_parameters.in.shmid, client);
break;
case SHMOP_shmctl:
result = shmmgr.shmctl (_parameters.out.shmid,
_parameters.out.ds, _parameters.out.shminfo,
_parameters.out.shm_info,
_parameters.in.shmid, _parameters.in.cmd,
_parameters.in.ds,
client);
break;
}
client->release ();
conn->revert_to_self ();
if (result < 0)
{
error_code (-result);
msglen (0); msglen (0);
return;
} }
if (!adjust_identity_info (&_parameters.in.ipcblk))
{
client->release ();
conn->revert_to_self ();
error_code (EACCES);
msglen (0);
return;
}
/* Early revert_to_self since IPC code runs in kernel mode. */
conn->revert_to_self ();
thread td = { client, &_parameters.in.ipcblk, {0, 0} };
int res;
shmop_t shmop = _parameters.in.shmop; /* Get's overwritten otherwise. */
switch (shmop)
{
case SHMOP_shmat:
ipc_p_vmspace (td.ipcblk);
res = shmat (&td, &_parameters.in.atargs);
break;
case SHMOP_shmctl:
res = shmctl (&td, &_parameters.in.ctlargs);
break;
case SHMOP_shmdt:
ipc_p_vmspace (td.ipcblk);
res = shmdt (&td, &_parameters.in.dtargs);
break;
case SHMOP_shmget:
res = shmget (&td, &_parameters.in.getargs);
break;
case SHMOP_shmfork:
res = cygwin_shmfork_myhook (&td, &_parameters.in.forkargs);
break;
}
/* Allocated by the call to adjust_identity_info(). */
if (_parameters.in.ipcblk.gidlist)
free (_parameters.in.ipcblk.gidlist);
client->release ();
error_code (res);
if (shmop == SHMOP_shmat)
_parameters.out.ptr = td.td_retval[0];
else else
msglen (sizeof (_parameters.out)); _parameters.out.ret = td.td_retval[0];
if (shmop == SHMOP_shmget)
_parameters.out.obj = td.td_retval[1];
msglen (sizeof (_parameters.out));
} }
#endif /* __OUTSIDE_CYGWIN__ */

1208
winsup/cygserver/sysv_msg.cc Normal file

File diff suppressed because it is too large Load Diff

1323
winsup/cygserver/sysv_sem.cc Normal file

File diff suppressed because it is too large Load Diff

1025
winsup/cygserver/sysv_shm.cc Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
/* threaded_queue.cc /* threaded_queue.cc
Copyright 2001, 2002 Red Hat Inc. Copyright 2001, 2002, 2003 Red Hat Inc.
Written by Robert Collins <rbtcollins@hotmail.com> Written by Robert Collins <rbtcollins@hotmail.com>
@ -10,6 +10,7 @@ This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */ details. */
#ifdef __OUTSIDE_CYGWIN__
#include "woutsup.h" #include "woutsup.h"
#include <assert.h> #include <assert.h>
@ -73,7 +74,7 @@ threaded_queue::~threaded_queue ()
{ {
queue_request *const ptr = reqptr; queue_request *const ptr = reqptr;
reqptr = reqptr->_next; reqptr = reqptr->_next;
safe_delete (ptr); delete ptr;
} }
DeleteCriticalSection (&_queue_lock); DeleteCriticalSection (&_queue_lock);
@ -267,7 +268,7 @@ threaded_queue::worker_loop ()
assert (reqptr); assert (reqptr);
reqptr->process (); reqptr->process ();
safe_delete (reqptr); delete reqptr;
} }
} }
@ -406,3 +407,4 @@ queue_submission_loop::start_routine (const LPVOID lpParam)
} }
/*****************************************************************************/ /*****************************************************************************/
#endif /* __OUTSIDE_CYGWIN__ */

View File

@ -1,6 +1,6 @@
/* cygserver_transport.cc /* transport.cc
Copyright 2001, 2002 Red Hat Inc. Copyright 2001, 2002, 2003 Red Hat Inc.
Written by Robert Collins <rbtcollins@hotmail.com> Written by Robert Collins <rbtcollins@hotmail.com>
@ -19,31 +19,33 @@ details. */
#include <sys/socket.h> #include <sys/socket.h>
#include "safe_memory.h" #include "transport.h"
#include "transport_pipes.h"
#include "cygserver_transport.h" #include "transport_sockets.h"
#include "cygserver_transport_pipes.h"
#include "cygserver_transport_sockets.h"
/* The factory */ /* The factory */
transport_layer_base * transport_layer_base *
create_server_transport () create_server_transport ()
{ {
if (wincap.is_winnt ()) if (wincap.is_winnt ())
return safe_new0 (transport_layer_pipes); return new transport_layer_pipes;
else else
return safe_new0 (transport_layer_sockets); return new transport_layer_sockets;
} }
#ifndef __INSIDE_CYGWIN__ #ifndef __INSIDE_CYGWIN__
void bool
transport_layer_base::impersonate_client () transport_layer_base::impersonate_client ()
{} {
return true;
}
void bool
transport_layer_base::revert_to_self () transport_layer_base::revert_to_self ()
{} {
return true;
}
#endif /* !__INSIDE_CYGWIN__ */ #endif /* !__INSIDE_CYGWIN__ */

View File

@ -1,6 +1,6 @@
/* cygserver_transport.h /* transport.h
Copyright 2001, 2002 Red Hat Inc. Copyright 2001, 2002, 2003 Red Hat Inc.
Written by Robert Collins <rbtcollins@hotmail.com> Written by Robert Collins <rbtcollins@hotmail.com>
@ -10,8 +10,8 @@ This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */ details. */
#ifndef _CYGSERVER_TRANSPORT_ #ifndef _TRANSPORT_H
#define _CYGSERVER_TRANSPORT_ #define _TRANSPORT_H
class transport_layer_base *create_server_transport (); class transport_layer_base *create_server_transport ();
@ -29,11 +29,11 @@ public:
virtual int connect () = 0; virtual int connect () = 0;
#ifndef __INSIDE_CYGWIN__ #ifndef __INSIDE_CYGWIN__
virtual void impersonate_client (); virtual bool impersonate_client ();
virtual void revert_to_self (); virtual bool revert_to_self ();
#endif #endif
virtual ~transport_layer_base (); virtual ~transport_layer_base ();
}; };
#endif /* _CYGSERVER_TRANSPORT_ */ #endif /* _TRANSPORT_H */

View File

@ -1,6 +1,6 @@
/* cygserver_transport_pipes.cc /* transport_pipes.cc
Copyright 2001, 2002 Red Hat Inc. Copyright 2001, 2002, 2003 Red Hat Inc.
Written by Robert Collins <rbtcollins@hotmail.com> Written by Robert Collins <rbtcollins@hotmail.com>
@ -25,11 +25,14 @@ details. */
#include <unistd.h> #include <unistd.h>
#include "cygerrno.h" #include "cygerrno.h"
#include "cygserver_transport.h" #include "transport.h"
#include "cygserver_transport_pipes.h" #include "transport_pipes.h"
#ifndef __INSIDE_CYGWIN__ #ifndef __INSIDE_CYGWIN__
#include "cygserver.h" #include "cygserver.h"
#include "cygserver_ipc.h"
#else
#include "security.h"
#endif #endif
enum enum
@ -64,7 +67,6 @@ transport_layer_pipes::transport_layer_pipes (const HANDLE hPipe)
assert (_hPipe); assert (_hPipe);
assert (_hPipe != INVALID_HANDLE_VALUE); assert (_hPipe != INVALID_HANDLE_VALUE);
init_security ();
} }
#endif /* !__INSIDE_CYGWIN__ */ #endif /* !__INSIDE_CYGWIN__ */
@ -75,22 +77,6 @@ transport_layer_pipes::transport_layer_pipes ()
_is_accepted_endpoint (false), _is_accepted_endpoint (false),
_is_listening_endpoint (false) _is_listening_endpoint (false)
{ {
init_security ();
}
void
transport_layer_pipes::init_security ()
{
assert (wincap.has_security ());
/* FIXME: pthread_once or equivalent needed */
InitializeSecurityDescriptor (&_sd, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl (&_sd, TRUE, NULL, FALSE);
_sec_all_nih.nLength = sizeof (SECURITY_ATTRIBUTES);
_sec_all_nih.lpSecurityDescriptor = &_sd;
_sec_all_nih.bInheritHandle = FALSE;
} }
transport_layer_pipes::~transport_layer_pipes () transport_layer_pipes::~transport_layer_pipes ()
@ -138,7 +124,7 @@ transport_layer_pipes::accept (bool *const recoverable)
(PIPE_TYPE_BYTE | PIPE_WAIT), (PIPE_TYPE_BYTE | PIPE_WAIT),
PIPE_UNLIMITED_INSTANCES, PIPE_UNLIMITED_INSTANCES,
0, 0, 1000, 0, 0, 1000,
&_sec_all_nih); &sec_all_nih);
const bool duplicate = (accept_pipe == INVALID_HANDLE_VALUE const bool duplicate = (accept_pipe == INVALID_HANDLE_VALUE
&& pipe_instance == 0 && pipe_instance == 0
@ -175,7 +161,7 @@ transport_layer_pipes::accept (bool *const recoverable)
return NULL; return NULL;
} }
return safe_new (transport_layer_pipes, accept_pipe); return new transport_layer_pipes (accept_pipe);
} }
#endif /* !__INSIDE_CYGWIN__ */ #endif /* !__INSIDE_CYGWIN__ */
@ -281,7 +267,7 @@ transport_layer_pipes::connect ()
_hPipe = CreateFile (_pipe_name, _hPipe = CreateFile (_pipe_name,
GENERIC_READ | GENERIC_WRITE, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
&_sec_all_nih, &sec_all_nih,
OPEN_EXISTING, OPEN_EXISTING,
SECURITY_IMPERSONATION, SECURITY_IMPERSONATION,
NULL); NULL);
@ -331,32 +317,33 @@ transport_layer_pipes::connect ()
#ifndef __INSIDE_CYGWIN__ #ifndef __INSIDE_CYGWIN__
void bool
transport_layer_pipes::impersonate_client () transport_layer_pipes::impersonate_client ()
{ {
assert (_hPipe); assert (_hPipe);
assert (_hPipe != INVALID_HANDLE_VALUE); assert (_hPipe != INVALID_HANDLE_VALUE);
assert (_is_accepted_endpoint); assert (_is_accepted_endpoint);
// verbose: debug_printf ("impersonating pipe %p", _hPipe); if (_hPipe && !ImpersonateNamedPipeClient (_hPipe))
if (_hPipe)
{ {
assert (_hPipe != INVALID_HANDLE_VALUE); debug_printf ("Failed to Impersonate client, (%lu)", GetLastError ());
return false;
if (!ImpersonateNamedPipeClient (_hPipe))
debug_printf ("Failed to Impersonate the client, (%lu)",
GetLastError ());
} }
// verbose: debug_printf ("I am who you are");
return true;
} }
void bool
transport_layer_pipes::revert_to_self () transport_layer_pipes::revert_to_self ()
{ {
assert (_is_accepted_endpoint); assert (_is_accepted_endpoint);
RevertToSelf (); if (!RevertToSelf ())
// verbose: debug_printf ("I am who I yam"); {
debug_printf ("Failed to RevertToSelf, (%lu)", GetLastError ());
return false;
}
return true;
} }
#endif /* !__INSIDE_CYGWIN__ */ #endif /* !__INSIDE_CYGWIN__ */

View File

@ -1,6 +1,6 @@
/* cygserver_transport_pipes.h /* transport_pipes.h
Copyright 2001, 2002 Red Hat Inc. Copyright 2001, 2002, 2003 Red Hat Inc.
Written by Robert Collins <rbtcollins@hotmail.com> Written by Robert Collins <rbtcollins@hotmail.com>
@ -10,8 +10,8 @@ This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */ details. */
#ifndef _CYGSERVER_TRANSPORT_PIPES_ #ifndef _TRANSPORT_PIPES_H
#define _CYGSERVER_TRANSPORT_PIPES_ #define _TRANSPORT_PIPES_H
/* Named pipes based transport, for security on NT */ /* Named pipes based transport, for security on NT */
class transport_layer_pipes : public transport_layer_base class transport_layer_pipes : public transport_layer_base
@ -28,20 +28,14 @@ public:
virtual int connect (); virtual int connect ();
#ifndef __INSIDE_CYGWIN__ #ifndef __INSIDE_CYGWIN__
virtual void impersonate_client (); virtual bool impersonate_client ();
virtual void revert_to_self (); virtual bool revert_to_self ();
#endif #endif
transport_layer_pipes (); transport_layer_pipes ();
virtual ~transport_layer_pipes (); virtual ~transport_layer_pipes ();
private: private:
/* for pipe based communications */
void init_security ();
//FIXME: allow inited, sd, all_nih_.. to be static members
SECURITY_DESCRIPTOR _sd;
SECURITY_ATTRIBUTES _sec_all_nih;
const char *const _pipe_name; const char *const _pipe_name;
HANDLE _hPipe; HANDLE _hPipe;
const bool _is_accepted_endpoint; const bool _is_accepted_endpoint;
@ -50,4 +44,4 @@ private:
transport_layer_pipes (HANDLE hPipe); transport_layer_pipes (HANDLE hPipe);
}; };
#endif /* _CYGSERVER_TRANSPORT_PIPES_ */ #endif /* _TRANSPORT_PIPES_H */

View File

@ -1,4 +1,4 @@
/* cygserver_transport_sockets.cc /* transport_sockets.cc
Copyright 2001, 2002 Red Hat Inc. Copyright 2001, 2002 Red Hat Inc.
@ -26,8 +26,8 @@ details. */
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
#include "cygserver_transport.h" #include "transport.h"
#include "cygserver_transport_sockets.h" #include "transport_sockets.h"
/* to allow this to link into cygwin and the .dll, a little magic is needed. */ /* to allow this to link into cygwin and the .dll, a little magic is needed. */
#ifndef __OUTSIDE_CYGWIN__ #ifndef __OUTSIDE_CYGWIN__
@ -219,7 +219,7 @@ transport_layer_sockets::accept (bool *const recoverable)
debug_printf ("%d = accept () [this = %p, fd = %d]", accept_fd, this, _fd); debug_printf ("%d = accept () [this = %p, fd = %d]", accept_fd, this, _fd);
return safe_new (transport_layer_sockets, accept_fd); return new transport_layer_sockets (accept_fd);
} }
#endif /* !__INSIDE_CYGWIN__ */ #endif /* !__INSIDE_CYGWIN__ */

View File

@ -1,4 +1,4 @@
/* cygserver_transport_sockets.h /* transport_sockets.h
Copyright 2001, 2002 Red Hat Inc. Copyright 2001, 2002 Red Hat Inc.
@ -10,8 +10,8 @@ This software is a copyrighted work licensed under the terms of the
Cygwin license. Please consult the file "CYGWIN_LICENSE" for Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */ details. */
#ifndef _CYGSERVER_TRANSPORT_SOCKETS_ #ifndef _TRANSPORT_SOCKETS_H
#define _CYGSERVER_TRANSPORT_SOCKETS_ #define _TRANSPORT_SOCKETS_H
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/un.h> #include <sys/un.h>
@ -43,4 +43,4 @@ private:
transport_layer_sockets (int fd); transport_layer_sockets (int fd);
}; };
#endif /* _CYGSERVER_TRANSPORT_SOCKETS_ */ #endif /* _TRANSPORT_SOCKETS_H */

View File

@ -1,6 +1,6 @@
/* woutsup.h: for Cygwin code compiled outside the DLL (i.e. cygserver). /* woutsup.h: for Cygwin code compiled outside the DLL (i.e. cygserver).
Copyright 2002 Red Hat, Inc. Copyright 2002, 2003 Red Hat, Inc.
This file is part of Cygwin. This file is part of Cygwin.
@ -42,67 +42,32 @@ details. */
#include "wincap.h" #include "wincap.h"
#include "bsd_helper.h"
#include "bsd_log.h"
#include "bsd_mutex.h"
/* The one function we use from winuser.h most of the time */ /* The one function we use from winuser.h most of the time */
extern "C" DWORD WINAPI GetLastError (void); extern "C" DWORD WINAPI GetLastError (void);
extern int cygserver_running; extern int cygserver_running;
#if !defined(__STDC_VERSION__) || __STDC_VERSION__ >= 199900L #define SIGHANDLE(SIG) \
#define NEW_MACRO_VARARGS do \
#endif { \
struct sigaction act; \
/* \
* A reproduction of the <sys/strace.h> macros. This allows code that act.sa_handler = &handle_signal; \
* runs both inside and outside the Cygwin DLL to use the same macros act.sa_mask = 0; \
* for logging messages. act.sa_flags = 0; \
*/ \
if (sigaction (SIG, &act, NULL) == -1) \
extern "C" void __cygserver__printf (const char *, const char *, ...); { \
panic ("failed to install handler for " #SIG ": %s", \
#ifdef NEW_MACRO_VARARGS strerror (errno)); \
exit (1); \
#define system_printf(...) \ } \
do \
{ \
__cygserver__printf (__PRETTY_FUNCTION__, __VA_ARGS__); \
} while (false) } while (false)
#define __noop_printf(...) do {;} while (false) #define debug_printf(f,...) debug((f),##__VA_ARGS__)
#define syscall_printf(f,...) log(LOG_ERR,(f),##__VA_ARGS__)
#else /* !NEW_MACRO_VARARGS */ #define system_printf(f,...) log(LOG_ERR,(f),##__VA_ARGS__)
#define system_printf(args...) \
do \
{ \
__cygserver__printf (__PRETTY_FUNCTION__, ## args); \
} while (false)
#define __noop_printf(args...) do {;} while (false)
#endif /* !NEW_MACRO_VARARGS */
#ifdef DEBUGGING
#define debug_printf system_printf
#define paranoid_printf system_printf
#define select_printf system_printf
#define sigproc_printf system_printf
#define syscall_printf system_printf
#define termios_printf system_printf
#define wm_printf system_printf
#define minimal_printf system_printf
#define malloc_printf system_printf
#define thread_printf system_printf
#else
#define debug_printf __noop_printf
#define paranoid_printf __noop_printf
#define select_printf __noop_printf
#define sigproc_printf __noop_printf
#define syscall_printf __noop_printf
#define termios_printf __noop_printf
#define wm_printf __noop_printf
#define minimal_printf __noop_printf
#define malloc_printf __noop_printf
#define thread_printf __noop_printf
#endif
#include "safe_memory.h"