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:
		@@ -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>
 | 
			
		||||
 | 
			
		||||
	Accomodate moving cygserver header files from cygwin/include/cygwin
 | 
			
		||||
 
 | 
			
		||||
@@ -15,7 +15,8 @@ prefix:=@prefix@
 | 
			
		||||
exec_prefix:=@exec_prefix@
 | 
			
		||||
 | 
			
		||||
bindir:=@bindir@
 | 
			
		||||
etcdir:=$(exec_prefix)/etc
 | 
			
		||||
sbindir:=@sbindir@
 | 
			
		||||
sysconfdir:=@sysconfdir@
 | 
			
		||||
program_transform_name:=@program_transform_name@
 | 
			
		||||
 | 
			
		||||
INSTALL:=@INSTALL@
 | 
			
		||||
@@ -28,14 +29,18 @@ CXX:=@CXX@
 | 
			
		||||
CXX_FOR_TARGET:=$(CXX)
 | 
			
		||||
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
 | 
			
		||||
 | 
			
		||||
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 \
 | 
			
		||||
	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)}
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
 | 
			
		||||
install: all
 | 
			
		||||
install: all cygserver.conf
 | 
			
		||||
	$(INSTALL_PROGRAM) cygserver.exe $(sbindir)/cygserver.exe
 | 
			
		||||
	$(INSTALL_DATA) $(srcdir)/cygserver.conf $(sysconfdir)/cygserver.conf
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
	$(CXX) -o $@ $^
 | 
			
		||||
@@ -64,3 +76,8 @@ lib%.o: %.cc
 | 
			
		||||
 | 
			
		||||
libcygserver.a: $(LIBOBJS)
 | 
			
		||||
	$(AR) crus $@ $?
 | 
			
		||||
 | 
			
		||||
deps:=${wildcard *.d}
 | 
			
		||||
ifneq (,$(deps))
 | 
			
		||||
include $(deps)
 | 
			
		||||
endif
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										694
									
								
								winsup/cygserver/bsd_helper.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										694
									
								
								winsup/cygserver/bsd_helper.cc
									
									
									
									
									
										Normal 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__ */
 | 
			
		||||
							
								
								
									
										63
									
								
								winsup/cygserver/bsd_helper.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								winsup/cygserver/bsd_helper.h
									
									
									
									
									
										Normal 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 */
 | 
			
		||||
							
								
								
									
										95
									
								
								winsup/cygserver/bsd_log.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								winsup/cygserver/bsd_log.cc
									
									
									
									
									
										Normal 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__ */
 | 
			
		||||
							
								
								
									
										33
									
								
								winsup/cygserver/bsd_log.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								winsup/cygserver/bsd_log.h
									
									
									
									
									
										Normal 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 */
 | 
			
		||||
							
								
								
									
										253
									
								
								winsup/cygserver/bsd_mutex.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										253
									
								
								winsup/cygserver/bsd_mutex.cc
									
									
									
									
									
										Normal 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__ */
 | 
			
		||||
							
								
								
									
										51
									
								
								winsup/cygserver/bsd_mutex.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								winsup/cygserver/bsd_mutex.h
									
									
									
									
									
										Normal 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 */
 | 
			
		||||
@@ -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>
 | 
			
		||||
 | 
			
		||||
@@ -22,11 +22,12 @@ details. */
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
 | 
			
		||||
#include "cygerrno.h"
 | 
			
		||||
#include "cygserver_msg.h"
 | 
			
		||||
#include "cygserver_sem.h"
 | 
			
		||||
#include "cygserver_shm.h"
 | 
			
		||||
#include "safe_memory.h"
 | 
			
		||||
 | 
			
		||||
#include "cygserver.h"
 | 
			
		||||
#include "cygserver_transport.h"
 | 
			
		||||
#include "transport.h"
 | 
			
		||||
 | 
			
		||||
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).
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifdef __INSIDE_CYGWIN__
 | 
			
		||||
 | 
			
		||||
bool
 | 
			
		||||
client_request_get_version::check_version () const
 | 
			
		||||
{
 | 
			
		||||
@@ -71,8 +74,6 @@ client_request_get_version::check_version () const
 | 
			
		||||
  return ok;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef __INSIDE_CYGWIN__
 | 
			
		||||
 | 
			
		||||
client_request_attach_tty::client_request_attach_tty (DWORD nmaster_pid,
 | 
			
		||||
						      HANDLE nfrom_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"),
 | 
			
		||||
		  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__ */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
@@ -230,7 +222,12 @@ client_request::send (transport_layer_base * const conn)
 | 
			
		||||
  //			      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 ()
 | 
			
		||||
@@ -277,16 +274,22 @@ client_request::handle_request (transport_layer_base *const conn,
 | 
			
		||||
  switch (header.request_code)
 | 
			
		||||
    {
 | 
			
		||||
    case CYGSERVER_REQUEST_GET_VERSION:
 | 
			
		||||
      req = safe_new0 (client_request_get_version);
 | 
			
		||||
      req = new client_request_get_version;
 | 
			
		||||
      break;
 | 
			
		||||
    case CYGSERVER_REQUEST_SHUTDOWN:
 | 
			
		||||
      req = safe_new0 (client_request_shutdown);
 | 
			
		||||
      req = new client_request_shutdown;
 | 
			
		||||
      break;
 | 
			
		||||
    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;
 | 
			
		||||
    case CYGSERVER_REQUEST_SHM:
 | 
			
		||||
      req = safe_new0 (client_request_shm);
 | 
			
		||||
      req = new client_request_shm;
 | 
			
		||||
      break;
 | 
			
		||||
    default:
 | 
			
		||||
      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->handle (conn, cache);
 | 
			
		||||
 | 
			
		||||
  safe_delete (req);
 | 
			
		||||
 | 
			
		||||
#ifndef DEBUGGING
 | 
			
		||||
  printf (".");			// A little noise when we're being quiet.
 | 
			
		||||
#endif
 | 
			
		||||
  delete req;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#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 ()
 | 
			
		||||
 *
 | 
			
		||||
@@ -470,7 +408,84 @@ client_request::handle (transport_layer_base *const conn,
 | 
			
		||||
  //			      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
 | 
			
		||||
check_cygserver_available ()
 | 
			
		||||
@@ -523,3 +538,4 @@ cygserver_init ()
 | 
			
		||||
  if (!check_cygserver_available ())
 | 
			
		||||
    cygserver_running = CYGSERVER_UNAVAIL;
 | 
			
		||||
}
 | 
			
		||||
#endif /* __INSIDE_CYGWIN__ */
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
/* cygserver.cc
 | 
			
		||||
 | 
			
		||||
   Copyright 2001, 2002 Red Hat Inc.
 | 
			
		||||
   Copyright 2001, 2002, 2003 Red Hat Inc.
 | 
			
		||||
 | 
			
		||||
   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
 | 
			
		||||
details. */
 | 
			
		||||
 | 
			
		||||
#ifdef __OUTSIDE_CYGWIN__
 | 
			
		||||
#include "woutsup.h"
 | 
			
		||||
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
@@ -27,100 +28,21 @@ details. */
 | 
			
		||||
#include "cygwin_version.h"
 | 
			
		||||
 | 
			
		||||
#include "cygserver.h"
 | 
			
		||||
#include "cygserver_process.h"
 | 
			
		||||
#include "cygserver_transport.h"
 | 
			
		||||
#include "process.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.
 | 
			
		||||
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;
 | 
			
		||||
 | 
			
		||||
static BOOL
 | 
			
		||||
static bool
 | 
			
		||||
setup_privileges ()
 | 
			
		||||
{
 | 
			
		||||
  BOOL rc, ret_val;
 | 
			
		||||
@@ -130,15 +52,14 @@ setup_privileges ()
 | 
			
		||||
  rc = OpenProcessToken (GetCurrentProcess () , TOKEN_ALL_ACCESS , &hToken) ;
 | 
			
		||||
  if (!rc)
 | 
			
		||||
    {
 | 
			
		||||
      system_printf ("error opening process token (%lu)", GetLastError ());
 | 
			
		||||
      ret_val = FALSE;
 | 
			
		||||
      goto out;
 | 
			
		||||
      debug ("error opening process token (%lu)", GetLastError ());
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
  rc = LookupPrivilegeValue (NULL, SE_DEBUG_NAME, &sPrivileges.Privileges[0].Luid);
 | 
			
		||||
  if (!rc)
 | 
			
		||||
    {
 | 
			
		||||
      system_printf ("error getting privilege luid (%lu)", GetLastError ());
 | 
			
		||||
      ret_val = FALSE;
 | 
			
		||||
      debug ("error getting privilege luid (%lu)", GetLastError ());
 | 
			
		||||
      ret_val = false;
 | 
			
		||||
      goto out;
 | 
			
		||||
    }
 | 
			
		||||
  sPrivileges.PrivilegeCount = 1 ;
 | 
			
		||||
@@ -146,9 +67,8 @@ setup_privileges ()
 | 
			
		||||
  rc = AdjustTokenPrivileges (hToken, FALSE, &sPrivileges, 0, NULL, NULL) ;
 | 
			
		||||
  if (!rc)
 | 
			
		||||
    {
 | 
			
		||||
      system_printf ("error adjusting privilege level. (%lu)",
 | 
			
		||||
		     GetLastError ());
 | 
			
		||||
      ret_val = FALSE;
 | 
			
		||||
      debug ("error adjusting privilege level. (%lu)", GetLastError ());
 | 
			
		||||
      ret_val = false;
 | 
			
		||||
      goto out;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -157,7 +77,7 @@ setup_privileges ()
 | 
			
		||||
  access_mapping.GenericExecute = 0;
 | 
			
		||||
  access_mapping.GenericAll = FILE_READ_DATA | FILE_WRITE_DATA;
 | 
			
		||||
 | 
			
		||||
  ret_val = TRUE;
 | 
			
		||||
  ret_val = true;
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
  CloseHandle (hToken);
 | 
			
		||||
@@ -181,7 +101,7 @@ check_and_dup_handle (HANDLE from_process, HANDLE to_process,
 | 
			
		||||
			    0, bInheritHandle,
 | 
			
		||||
			    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 ());
 | 
			
		||||
	  goto out;
 | 
			
		||||
	}
 | 
			
		||||
@@ -205,7 +125,7 @@ check_and_dup_handle (HANDLE from_process, HANDLE to_process,
 | 
			
		||||
				     | DACL_SECURITY_INFORMATION),
 | 
			
		||||
				    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;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -214,14 +134,14 @@ check_and_dup_handle (HANDLE from_process, HANDLE to_process,
 | 
			
		||||
      if (!AccessCheck (sd, from_process_token, access, &access_mapping,
 | 
			
		||||
			&ps, &ps_len, &access, &status))
 | 
			
		||||
	{
 | 
			
		||||
	  system_printf ("error checking access rights (%lu)",
 | 
			
		||||
	  log (LOG_ERR, "error checking access rights (%lu)",
 | 
			
		||||
			 GetLastError ());
 | 
			
		||||
	  goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
      if (!status)
 | 
			
		||||
	{
 | 
			
		||||
	  system_printf ("access to object denied");
 | 
			
		||||
	  log (LOG_ERR, "access to object denied");
 | 
			
		||||
	  goto out;
 | 
			
		||||
	}
 | 
			
		||||
    }
 | 
			
		||||
@@ -230,11 +150,11 @@ check_and_dup_handle (HANDLE from_process, HANDLE to_process,
 | 
			
		||||
			to_process, to_handle_ptr,
 | 
			
		||||
			access, bInheritHandle, 0))
 | 
			
		||||
    {
 | 
			
		||||
      system_printf ("error getting handle to client (%lu)", GetLastError ());
 | 
			
		||||
      log (LOG_ERR, "error getting handle to client (%lu)", GetLastError ());
 | 
			
		||||
      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;
 | 
			
		||||
 | 
			
		||||
@@ -259,7 +179,7 @@ client_request_attach_tty::serve (transport_layer_base *const conn,
 | 
			
		||||
 | 
			
		||||
  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);
 | 
			
		||||
      msglen (0);
 | 
			
		||||
      return;
 | 
			
		||||
@@ -267,7 +187,7 @@ client_request_attach_tty::serve (transport_layer_base *const conn,
 | 
			
		||||
 | 
			
		||||
  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 ());
 | 
			
		||||
      error_code (EINVAL);
 | 
			
		||||
      msglen (0);
 | 
			
		||||
@@ -276,54 +196,65 @@ client_request_attach_tty::serve (transport_layer_base *const conn,
 | 
			
		||||
 | 
			
		||||
  msglen (0);			// Until we fill in some fields.
 | 
			
		||||
 | 
			
		||||
  // verbose: debug_printf ("pid %ld:(%p,%p) -> pid %ld",
 | 
			
		||||
  //			    req.master_pid, req.from_master, req.to_master,
 | 
			
		||||
  //			    req.pid);
 | 
			
		||||
  debug ("pid %ld:(%p,%p) -> pid %ld", req.master_pid, req.from_master,
 | 
			
		||||
				       req.to_master, req.pid);
 | 
			
		||||
 | 
			
		||||
  // verbose: debug_printf ("opening process %ld", req.master_pid);
 | 
			
		||||
  debug ("opening process %ld", req.master_pid);
 | 
			
		||||
 | 
			
		||||
  const HANDLE from_process_handle =
 | 
			
		||||
    OpenProcess (PROCESS_DUP_HANDLE, FALSE, req.master_pid);
 | 
			
		||||
 | 
			
		||||
  if (!from_process_handle)
 | 
			
		||||
    {
 | 
			
		||||
      system_printf ("error opening `from' process, error = %lu",
 | 
			
		||||
      log (LOG_ERR, "error opening `from' process, error = %lu",
 | 
			
		||||
		     GetLastError ());
 | 
			
		||||
      error_code (EACCES);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  // verbose: debug_printf ("opening process %ld", req.pid);
 | 
			
		||||
  debug ("opening process %ld", req.pid);
 | 
			
		||||
 | 
			
		||||
  const HANDLE to_process_handle =
 | 
			
		||||
    OpenProcess (PROCESS_DUP_HANDLE, FALSE, req.pid);
 | 
			
		||||
 | 
			
		||||
  if (!to_process_handle)
 | 
			
		||||
    {
 | 
			
		||||
      system_printf ("error opening `to' process, error = %lu",
 | 
			
		||||
      log (LOG_ERR, "error opening `to' process, error = %lu",
 | 
			
		||||
		     GetLastError ());
 | 
			
		||||
      CloseHandle (from_process_handle);
 | 
			
		||||
      error_code (EACCES);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  // verbose: debug_printf ("Impersonating client");
 | 
			
		||||
  conn->impersonate_client ();
 | 
			
		||||
  debug ("Impersonating client");
 | 
			
		||||
  if (!conn->impersonate_client ())
 | 
			
		||||
    {
 | 
			
		||||
      CloseHandle (from_process_handle);
 | 
			
		||||
      CloseHandle (to_process_handle);
 | 
			
		||||
      error_code (EACCES);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  HANDLE token_handle = NULL;
 | 
			
		||||
 | 
			
		||||
  // verbose: debug_printf ("about to open thread token");
 | 
			
		||||
  debug ("about to open thread token");
 | 
			
		||||
  const DWORD rc = OpenThreadToken (GetCurrentThread (),
 | 
			
		||||
				    TOKEN_QUERY,
 | 
			
		||||
				    TRUE,
 | 
			
		||||
				    &token_handle);
 | 
			
		||||
 | 
			
		||||
  // verbose: debug_printf ("opened thread token, rc=%lu", rc);
 | 
			
		||||
  conn->revert_to_self ();
 | 
			
		||||
  debug ("opened thread token, rc=%lu", rc);
 | 
			
		||||
  if (!conn->revert_to_self ())
 | 
			
		||||
    {
 | 
			
		||||
      CloseHandle (from_process_handle);
 | 
			
		||||
      CloseHandle (to_process_handle);
 | 
			
		||||
      error_code (EACCES);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  if (!rc)
 | 
			
		||||
    {
 | 
			
		||||
      system_printf ("error opening thread token, error = %lu",
 | 
			
		||||
      log (LOG_ERR, "error opening thread token, error = %lu",
 | 
			
		||||
		     GetLastError ());
 | 
			
		||||
      CloseHandle (from_process_handle);
 | 
			
		||||
      CloseHandle (to_process_handle);
 | 
			
		||||
@@ -348,7 +279,7 @@ client_request_attach_tty::serve (transport_layer_base *const conn,
 | 
			
		||||
			      from_master,
 | 
			
		||||
			      &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 ());
 | 
			
		||||
	error_code (EACCES);
 | 
			
		||||
      }
 | 
			
		||||
@@ -360,7 +291,7 @@ client_request_attach_tty::serve (transport_layer_base *const conn,
 | 
			
		||||
			      to_master,
 | 
			
		||||
			      &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 ());
 | 
			
		||||
	error_code (EACCES);
 | 
			
		||||
      }
 | 
			
		||||
@@ -369,7 +300,7 @@ client_request_attach_tty::serve (transport_layer_base *const conn,
 | 
			
		||||
  CloseHandle (to_process_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.pid, req.from_master, req.to_master);
 | 
			
		||||
 | 
			
		||||
@@ -382,7 +313,7 @@ client_request_get_version::serve (transport_layer_base *, process_cache *)
 | 
			
		||||
  assert (!error_code ());
 | 
			
		||||
 | 
			
		||||
  if (msglen ())
 | 
			
		||||
    syscall_printf ("unexpected request body ignored: %lu bytes", msglen ());
 | 
			
		||||
    log (LOG_ERR, "unexpected request body ignored: %lu bytes", msglen ());
 | 
			
		||||
 | 
			
		||||
  msglen (sizeof (version));
 | 
			
		||||
 | 
			
		||||
@@ -401,7 +332,7 @@ public:
 | 
			
		||||
 | 
			
		||||
  virtual ~server_request ()
 | 
			
		||||
  {
 | 
			
		||||
    safe_delete (_conn);
 | 
			
		||||
    delete _conn;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  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))
 | 
			
		||||
      debug_printf ("failed to raise accept thread priority, error = %lu",
 | 
			
		||||
		    GetLastError ());
 | 
			
		||||
      debug ("failed to raise accept thread priority, error = %lu",
 | 
			
		||||
	     GetLastError ());
 | 
			
		||||
 | 
			
		||||
  while (_running)
 | 
			
		||||
    {
 | 
			
		||||
@@ -464,7 +395,7 @@ server_submission_loop::request_loop ()
 | 
			
		||||
      transport_layer_base *const conn = _transport->accept (&recoverable);
 | 
			
		||||
      if (!conn && !recoverable)
 | 
			
		||||
	{
 | 
			
		||||
	  system_printf ("fatal error on IPC transport: closing down");
 | 
			
		||||
	  log (LOG_ERR, "fatal error on IPC transport: closing down");
 | 
			
		||||
	  return;
 | 
			
		||||
	}
 | 
			
		||||
      // 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 (!SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_NORMAL))
 | 
			
		||||
	    debug_printf ("failed to reset thread priority, error = %lu",
 | 
			
		||||
			  GetLastError ());
 | 
			
		||||
	    debug ("failed to reset thread priority, error = %lu",
 | 
			
		||||
		   GetLastError ());
 | 
			
		||||
 | 
			
		||||
	  Sleep (0);
 | 
			
		||||
	  if (!SetThreadPriority (GetCurrentThread (),
 | 
			
		||||
				  THREAD_PRIORITY_HIGHEST + 1))
 | 
			
		||||
	    if (!SetThreadPriority (GetCurrentThread (),
 | 
			
		||||
				    THREAD_PRIORITY_HIGHEST))
 | 
			
		||||
	      debug_printf ("failed to raise thread priority, error = %lu",
 | 
			
		||||
			    GetLastError ());
 | 
			
		||||
	      debug ("failed to raise thread priority, error = %lu",
 | 
			
		||||
		     GetLastError ());
 | 
			
		||||
	}
 | 
			
		||||
      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 (CYGSERVER_REQUEST_SHUTDOWN)
 | 
			
		||||
{
 | 
			
		||||
  // verbose: syscall_printf ("created");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
@@ -502,7 +432,7 @@ client_request_shutdown::serve (transport_layer_base *, process_cache *)
 | 
			
		||||
  assert (!error_code ());
 | 
			
		||||
 | 
			
		||||
  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
 | 
			
		||||
   * only shutdown _this queue_
 | 
			
		||||
@@ -530,12 +460,33 @@ handle_signal (const int signum)
 | 
			
		||||
static void
 | 
			
		||||
print_usage (const char *const pgm)
 | 
			
		||||
{
 | 
			
		||||
  printf ("Usage: %s [OPTIONS]\n", pgm);
 | 
			
		||||
  printf ("  -c, --cleanup-threads   number of cleanup threads to use\n");
 | 
			
		||||
  printf ("  -h, --help              output usage information and exit\n");
 | 
			
		||||
  printf ("  -r, --request-threads   number of request threads to use\n");
 | 
			
		||||
  printf ("  -s, --shutdown          shutdown the daemon\n");
 | 
			
		||||
  printf ("  -v, --version           output version information and exit\n");
 | 
			
		||||
  log (LOG_NOTICE, "Usage: %s [OPTIONS]\n"
 | 
			
		||||
"Configuration option:\n"
 | 
			
		||||
"  -f, --config-file <file>      Use <file> as config file.  Default is\n"
 | 
			
		||||
"\n"
 | 
			
		||||
"Performance options:\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
 | 
			
		||||
print_version (const char *const pgm)
 | 
			
		||||
print_version ()
 | 
			
		||||
{
 | 
			
		||||
  char *vn = NULL;
 | 
			
		||||
 | 
			
		||||
@@ -578,10 +529,12 @@ print_version (const char *const pgm)
 | 
			
		||||
	    cygwin_version.mount_registry,
 | 
			
		||||
	    cygwin_version.dll_build_date);
 | 
			
		||||
 | 
			
		||||
  printf ("%s (cygwin) %s\n", pgm, vn);
 | 
			
		||||
  printf ("API version %s\n", buf);
 | 
			
		||||
  printf ("Copyright 2001, 2002 Red Hat, Inc.\n");
 | 
			
		||||
  printf ("Compiled on %s\n", __DATE__);
 | 
			
		||||
  log (LOG_INFO, "(cygwin) %s\n"
 | 
			
		||||
		  "API version %s\n"
 | 
			
		||||
		  "Copyright 2001, 2002, 2003 Red Hat, Inc.\n"
 | 
			
		||||
		  "Compiled on %s\n"
 | 
			
		||||
		  "Default configuration file is %s",
 | 
			
		||||
		  vn, buf, __DATE__, DEF_CONFIG_FILE);
 | 
			
		||||
 | 
			
		||||
  free (vn);
 | 
			
		||||
}
 | 
			
		||||
@@ -595,79 +548,127 @@ main (const int argc, char *argv[])
 | 
			
		||||
{
 | 
			
		||||
  const struct option longopts[] = {
 | 
			
		||||
    {"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'},
 | 
			
		||||
    {"log-level", required_argument, NULL, 'l'},
 | 
			
		||||
    {"no-sharedmem", no_argument, NULL, 'm'},
 | 
			
		||||
    {"no-msgqueues", no_argument, NULL, 'q'},
 | 
			
		||||
    {"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'},
 | 
			
		||||
    {"syslog", no_argument, NULL, 'y'},
 | 
			
		||||
    {"no-syslog", no_argument, NULL, 'Y'},
 | 
			
		||||
    {0, no_argument, NULL, 0}
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const char opts[] = "c:hr:sv";
 | 
			
		||||
  const char opts[] = "c:deEf:hl:mqr:sSvyY";
 | 
			
		||||
 | 
			
		||||
  int cleanup_threads = 2;
 | 
			
		||||
  int request_threads = 10;
 | 
			
		||||
  long cleanup_threads = 0;
 | 
			
		||||
  long request_threads = 0;
 | 
			
		||||
  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, '/')))
 | 
			
		||||
    pgm = *argv;
 | 
			
		||||
  /* Check if we have a terminal.  If so, default to stderr logging,
 | 
			
		||||
     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
 | 
			
		||||
    pgm++;
 | 
			
		||||
 | 
			
		||||
  wincap.init ();
 | 
			
		||||
  if (wincap.has_security ())
 | 
			
		||||
    setup_privileges ();
 | 
			
		||||
    log_syslog = TUN_TRUE;
 | 
			
		||||
 | 
			
		||||
  int opt;
 | 
			
		||||
 | 
			
		||||
  opterr = 0;
 | 
			
		||||
  while ((opt = getopt_long (argc, argv, opts, longopts, NULL)) != EOF)
 | 
			
		||||
    switch (opt)
 | 
			
		||||
      {
 | 
			
		||||
      case 'c':
 | 
			
		||||
	cleanup_threads = atoi (optarg);
 | 
			
		||||
	if (cleanup_threads <= 0)
 | 
			
		||||
	  {
 | 
			
		||||
	    fprintf (stderr,
 | 
			
		||||
		     "%s: number of cleanup threads must be positive\n",
 | 
			
		||||
		     pgm);
 | 
			
		||||
	    exit (1);
 | 
			
		||||
	  }
 | 
			
		||||
	c = NULL;
 | 
			
		||||
	cleanup_threads = strtol (optarg, &c, 10);
 | 
			
		||||
	if (cleanup_threads <= 0 || cleanup_threads > 16 || (c && *c))
 | 
			
		||||
	  panic ("Number of cleanup threads must be between 1 and 16");
 | 
			
		||||
	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':
 | 
			
		||||
	print_usage (pgm);
 | 
			
		||||
	print_usage (getprogname ());
 | 
			
		||||
	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':
 | 
			
		||||
	request_threads = atoi (optarg);
 | 
			
		||||
	if (request_threads <= 0)
 | 
			
		||||
	  {
 | 
			
		||||
	    fprintf (stderr,
 | 
			
		||||
		     "%s: number of request threads must be positive\n",
 | 
			
		||||
		     pgm);
 | 
			
		||||
	    exit (1);
 | 
			
		||||
	  }
 | 
			
		||||
	c = NULL;
 | 
			
		||||
	request_threads = strtol (optarg, &c, 10);
 | 
			
		||||
	if (request_threads <= 0 || request_threads > 64 || (c && *c))
 | 
			
		||||
	  panic ("Number of request threads must be between 1 and 64");
 | 
			
		||||
	break;
 | 
			
		||||
 | 
			
		||||
      case 's':
 | 
			
		||||
        support_semaphores = TUN_FALSE;
 | 
			
		||||
	break;
 | 
			
		||||
 | 
			
		||||
      case 'S':
 | 
			
		||||
	shutdown = true;
 | 
			
		||||
	break;
 | 
			
		||||
 | 
			
		||||
      case 'v':
 | 
			
		||||
	print_version (pgm);
 | 
			
		||||
	print_version ();
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
      case 'y':
 | 
			
		||||
        option_log_syslog = TUN_TRUE;
 | 
			
		||||
	break;
 | 
			
		||||
 | 
			
		||||
      case 'Y':
 | 
			
		||||
        option_log_syslog = TUN_FALSE;
 | 
			
		||||
	break;
 | 
			
		||||
 | 
			
		||||
      case '?':
 | 
			
		||||
	fprintf (stderr, "Try `%s --help' for more information.\n", pgm);
 | 
			
		||||
	exit (1);
 | 
			
		||||
	panic ("unknown option -- %c\n"
 | 
			
		||||
	       "Try `%s --help' for more information.", optopt, getprogname ());
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
  if (optind != argc)
 | 
			
		||||
    {
 | 
			
		||||
      fprintf (stderr, "%s: too many arguments\n", pgm);
 | 
			
		||||
      exit (1);
 | 
			
		||||
    }
 | 
			
		||||
    panic ("Too many arguments");
 | 
			
		||||
 | 
			
		||||
  if (shutdown)
 | 
			
		||||
    {
 | 
			
		||||
@@ -679,71 +680,76 @@ main (const int argc, char *argv[])
 | 
			
		||||
      client_request_shutdown req;
 | 
			
		||||
 | 
			
		||||
      if (req.make_request () == -1 || req.error_code ())
 | 
			
		||||
	{
 | 
			
		||||
	  fprintf (stderr, "%s: shutdown request failed: %s\n",
 | 
			
		||||
		   pgm, strerror (req.error_code ()));
 | 
			
		||||
	  exit (1);
 | 
			
		||||
	}
 | 
			
		||||
	panic("Shutdown request failed: %s", strerror (req.error_code ()));
 | 
			
		||||
 | 
			
		||||
      // FIXME: It would be nice to wait here for the daemon to exit.
 | 
			
		||||
 | 
			
		||||
      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 (SIGINT);
 | 
			
		||||
  SIGHANDLE (SIGTERM);
 | 
			
		||||
 | 
			
		||||
  print_version (pgm);
 | 
			
		||||
  setbuf (stdout, NULL);
 | 
			
		||||
  printf ("daemon starting up");
 | 
			
		||||
  tunable_param_init (config_file, force_config_file);
 | 
			
		||||
 | 
			
		||||
  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);
 | 
			
		||||
  printf (".");
 | 
			
		||||
 | 
			
		||||
  transport_layer_base *const transport = create_server_transport ();
 | 
			
		||||
  assert (transport);
 | 
			
		||||
  printf (".");
 | 
			
		||||
 | 
			
		||||
  process_cache cache (cleanup_threads);
 | 
			
		||||
  printf (".");
 | 
			
		||||
 | 
			
		||||
  server_submission_loop submission_loop (&request_queue, transport, &cache);
 | 
			
		||||
  printf (".");
 | 
			
		||||
 | 
			
		||||
  request_queue.add_submission_loop (&submission_loop);
 | 
			
		||||
  printf (".");
 | 
			
		||||
 | 
			
		||||
  if (transport->listen () == -1)
 | 
			
		||||
    {
 | 
			
		||||
      exit (1);
 | 
			
		||||
    }
 | 
			
		||||
  printf (".");
 | 
			
		||||
 | 
			
		||||
  ipcinit ();
 | 
			
		||||
 | 
			
		||||
  cache.start ();
 | 
			
		||||
  printf (".");
 | 
			
		||||
 | 
			
		||||
  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
 | 
			
		||||
   * 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
 | 
			
		||||
  */
 | 
			
		||||
  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 ();
 | 
			
		||||
  printf ("All pending requests processed\n");
 | 
			
		||||
  safe_delete (transport);
 | 
			
		||||
  printf ("No longer accepting requests - cygwin will operate in daemonless mode\n");
 | 
			
		||||
  log (LOG_INFO, "All pending requests processed");
 | 
			
		||||
  delete transport;
 | 
			
		||||
  log (LOG_INFO, "No longer accepting requests - cygwin will operate in daemonless mode");
 | 
			
		||||
  cache.stop ();
 | 
			
		||||
  printf ("All outstanding process-cache activities completed\n");
 | 
			
		||||
  printf ("daemon shutdown\n");
 | 
			
		||||
  log (LOG_INFO, "All outstanding process-cache activities completed");
 | 
			
		||||
  log (LOG_NOTICE, "Shutdown finished.");
 | 
			
		||||
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
#endif /* __OUTSIDE_CYGWIN__ */
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										126
									
								
								winsup/cygserver/cygserver.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								winsup/cygserver/cygserver.conf
									
									
									
									
									
										Normal 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
 | 
			
		||||
@@ -1,8 +1,6 @@
 | 
			
		||||
/* msg.cc: Single unix specification IPC interface for Cygwin.
 | 
			
		||||
 | 
			
		||||
   Copyright 2002 Red Hat, Inc.
 | 
			
		||||
 | 
			
		||||
   Written by Conrad Scott <conrad.scott@dsl.pipex.com>.
 | 
			
		||||
   Copyright 2003 Red Hat, Inc.
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
details. */
 | 
			
		||||
 | 
			
		||||
#include "winsup.h"
 | 
			
		||||
#ifdef __OUTSIDE_CYGWIN__
 | 
			
		||||
#include "woutsup.h"
 | 
			
		||||
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <cygwin/msg.h>
 | 
			
		||||
#include <errno.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
 | 
			
		||||
msgctl (int msqid, int cmd, struct msqid_ds *buf)
 | 
			
		||||
{
 | 
			
		||||
  set_errno (ENOSYS);
 | 
			
		||||
  return -1;
 | 
			
		||||
client_request_msg::client_request_msg ()
 | 
			
		||||
  : client_request (CYGSERVER_REQUEST_MSG,
 | 
			
		||||
		    &_parameters, sizeof (_parameters))
 | 
			
		||||
{ 
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
extern "C" int
 | 
			
		||||
msgget (key_t key, int msgflg)
 | 
			
		||||
void
 | 
			
		||||
client_request_msg::serve (transport_layer_base *const conn,
 | 
			
		||||
                           process_cache *const cache)
 | 
			
		||||
{
 | 
			
		||||
  set_errno (ENOSYS);
 | 
			
		||||
  return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
extern "C" ssize_t
 | 
			
		||||
msgrcv (int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg)
 | 
			
		||||
{
 | 
			
		||||
  set_errno (ENOSYS);
 | 
			
		||||
  return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
extern "C" int
 | 
			
		||||
msgsnd (int msqid, const void *msgp, size_t msgsz, int msgflg)
 | 
			
		||||
{
 | 
			
		||||
  set_errno (ENOSYS);
 | 
			
		||||
  return -1;
 | 
			
		||||
  if (msglen () != sizeof (_parameters.in))
 | 
			
		||||
    {
 | 
			
		||||
      syscall_printf ("bad request body length: expecting %lu bytes, got %lu",
 | 
			
		||||
		      sizeof (_parameters), msglen ());
 | 
			
		||||
      error_code (EINVAL);
 | 
			
		||||
      msglen (0);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
  if (support_msgqueues == TUN_FALSE)
 | 
			
		||||
    {
 | 
			
		||||
      syscall_printf ("Message queue support not started");
 | 
			
		||||
      error_code (ENOSYS);
 | 
			
		||||
      if (_parameters.in.msgop == MSGOP_msgrcv)
 | 
			
		||||
	_parameters.out.rcv = -1;
 | 
			
		||||
      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)
 | 
			
		||||
    {
 | 
			
		||||
      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__ */
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
/* cygserver_process.cc
 | 
			
		||||
/* process.cc
 | 
			
		||||
 | 
			
		||||
   Copyright 2001, 2002 Red Hat Inc.
 | 
			
		||||
 | 
			
		||||
@@ -19,7 +19,7 @@ details. */
 | 
			
		||||
 | 
			
		||||
#include "cygerrno.h"
 | 
			
		||||
 | 
			
		||||
#include "cygserver_process.h"
 | 
			
		||||
#include "process.h"
 | 
			
		||||
 | 
			
		||||
/*****************************************************************************/
 | 
			
		||||
 | 
			
		||||
@@ -29,7 +29,7 @@ details. */
 | 
			
		||||
 | 
			
		||||
process_cleanup::~process_cleanup ()
 | 
			
		||||
{
 | 
			
		||||
  safe_delete (_process);
 | 
			
		||||
  delete _process;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
@@ -139,7 +139,7 @@ process::remove (const cleanup_routine *const entry)
 | 
			
		||||
	      else
 | 
			
		||||
		_routines_head = ptr->_next;
 | 
			
		||||
 | 
			
		||||
	      safe_delete (ptr);
 | 
			
		||||
	      delete ptr;
 | 
			
		||||
	      res = true;
 | 
			
		||||
	      break;
 | 
			
		||||
	    }
 | 
			
		||||
@@ -170,7 +170,7 @@ process::cleanup ()
 | 
			
		||||
      cleanup_routine *const ptr = entry;
 | 
			
		||||
      entry = entry->_next;
 | 
			
		||||
      ptr->cleanup (this);
 | 
			
		||||
      safe_delete (ptr);
 | 
			
		||||
      delete ptr;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -250,11 +250,11 @@ process_cache::process (const pid_t cygpid, const DWORD winpid)
 | 
			
		||||
	  return NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
      entry = safe_new (class process, cygpid, winpid);
 | 
			
		||||
      entry = new class process (cygpid, winpid);
 | 
			
		||||
      if (!entry->is_active ())
 | 
			
		||||
	{
 | 
			
		||||
	  LeaveCriticalSection (&_cache_write_access);
 | 
			
		||||
	  safe_delete (entry);
 | 
			
		||||
	  delete entry;
 | 
			
		||||
	  set_errno (ESRCH);
 | 
			
		||||
	  return NULL;
 | 
			
		||||
	}
 | 
			
		||||
@@ -408,7 +408,7 @@ process_cache::check_and_remove_process (const size_t index)
 | 
			
		||||
  LeaveCriticalSection (&_cache_write_access);
 | 
			
		||||
 | 
			
		||||
  /* Schedule any cleanup tasks for this process. */
 | 
			
		||||
  _queue.add (safe_new (process_cleanup, process));
 | 
			
		||||
  _queue.add (new process_cleanup (process));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class process *
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
/* cygserver_process.h
 | 
			
		||||
/* process.h
 | 
			
		||||
 | 
			
		||||
   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
 | 
			
		||||
details. */
 | 
			
		||||
 | 
			
		||||
#ifndef _CYGSERVER_PROCESS_
 | 
			
		||||
#define _CYGSERVER_PROCESS_
 | 
			
		||||
#ifndef _PROCESS_H
 | 
			
		||||
#define _PROCESS_H
 | 
			
		||||
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
 | 
			
		||||
@@ -161,4 +161,4 @@ private:
 | 
			
		||||
  class process *find (DWORD winpid, class process **previous = NULL);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif /* _CYGSERVER_PROCESS_ */
 | 
			
		||||
#endif /* _PROCESS_H */
 | 
			
		||||
@@ -1,8 +1,6 @@
 | 
			
		||||
/* sem.cc: Single unix specification IPC interface for Cygwin.
 | 
			
		||||
 | 
			
		||||
   Copyright 2002 Red Hat, Inc.
 | 
			
		||||
 | 
			
		||||
   Written by Conrad Scott <conrad.scott@dsl.pipex.com>.
 | 
			
		||||
   Copyright 2003 Red Hat, Inc.
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
details. */
 | 
			
		||||
 | 
			
		||||
#include "winsup.h"
 | 
			
		||||
#ifdef __OUTSIDE_CYGWIN__
 | 
			
		||||
#include "woutsup.h"
 | 
			
		||||
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#include <cygwin/sem.h>
 | 
			
		||||
#include <errno.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
 | 
			
		||||
semctl (int semid, int semnum, int cmd, ...)
 | 
			
		||||
{
 | 
			
		||||
  set_errno (ENOSYS);
 | 
			
		||||
  return -1;
 | 
			
		||||
client_request_sem::client_request_sem ()
 | 
			
		||||
  : client_request (CYGSERVER_REQUEST_SEM,
 | 
			
		||||
		    &_parameters, sizeof (_parameters))
 | 
			
		||||
{ 
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
extern "C" int
 | 
			
		||||
semget (key_t key, int nsems, int semflg)
 | 
			
		||||
void
 | 
			
		||||
client_request_sem::serve (transport_layer_base *const conn,
 | 
			
		||||
                           process_cache *const cache)
 | 
			
		||||
{
 | 
			
		||||
  set_errno (ENOSYS);
 | 
			
		||||
  return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
extern "C" int
 | 
			
		||||
semop (int semid, struct sembuf *sops, size_t nsops)
 | 
			
		||||
{
 | 
			
		||||
  set_errno (ENOSYS);
 | 
			
		||||
  return -1;
 | 
			
		||||
  if (msglen () != sizeof (_parameters.in))
 | 
			
		||||
    {
 | 
			
		||||
      syscall_printf ("bad request body length: expecting %lu bytes, got %lu",
 | 
			
		||||
		      sizeof (_parameters), msglen ());
 | 
			
		||||
      error_code (EINVAL);
 | 
			
		||||
      msglen (0);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
  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__ */
 | 
			
		||||
 
 | 
			
		||||
@@ -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.
 | 
			
		||||
 | 
			
		||||
   Written by Conrad Scott <conrad.scott@dsl.pipex.com>.
 | 
			
		||||
   Based on code by Robert Collins <robert.collins@hotmail.com>.
 | 
			
		||||
   Copyright 2003 Red Hat, Inc.
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
details. */
 | 
			
		||||
 | 
			
		||||
#ifdef __OUTSIDE_CYGWIN__
 | 
			
		||||
#include "woutsup.h"
 | 
			
		||||
 | 
			
		||||
#include <errno.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 "cygserver_ipc.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 (CYGSERVER_REQUEST_SHM,
 | 
			
		||||
		    &_parameters, sizeof (_parameters))
 | 
			
		||||
{
 | 
			
		||||
  // verbose: syscall_printf ("created");
 | 
			
		||||
{ 
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*---------------------------------------------------------------------------*
 | 
			
		||||
 * client_request_shm::serve ()
 | 
			
		||||
 *---------------------------------------------------------------------------*/
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
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))
 | 
			
		||||
    {
 | 
			
		||||
      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);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  // FIXME: Get a return code out of this and don't continue on error.
 | 
			
		||||
  conn->impersonate_client ();
 | 
			
		||||
 | 
			
		||||
  class process *const client = cache->process (_parameters.in.cygpid,
 | 
			
		||||
						_parameters.in.winpid);
 | 
			
		||||
 | 
			
		||||
  if (support_sharedmem == TUN_FALSE)
 | 
			
		||||
    {
 | 
			
		||||
      syscall_printf ("Shared memory support not started");
 | 
			
		||||
      error_code (ENOSYS);
 | 
			
		||||
      if (_parameters.in.shmop == SHMOP_shmat)
 | 
			
		||||
	_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)
 | 
			
		||||
    {
 | 
			
		||||
      error_code (EAGAIN);
 | 
			
		||||
      msglen (0);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  int result = -EINVAL;
 | 
			
		||||
 | 
			
		||||
  switch (_parameters.in.shmop)
 | 
			
		||||
  if (!conn->impersonate_client ())
 | 
			
		||||
    {
 | 
			
		||||
    case SHMOP_shmget:
 | 
			
		||||
      result = shmmgr.shmget (_parameters.out.shmid,
 | 
			
		||||
			      _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);
 | 
			
		||||
      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, {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
 | 
			
		||||
    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
									
								
							
							
						
						
									
										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
									
								
							
							
						
						
									
										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
									
								
							
							
						
						
									
										1025
									
								
								winsup/cygserver/sysv_shm.cc
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,6 +1,6 @@
 | 
			
		||||
/* threaded_queue.cc
 | 
			
		||||
 | 
			
		||||
   Copyright 2001, 2002 Red Hat Inc.
 | 
			
		||||
   Copyright 2001, 2002, 2003 Red Hat Inc.
 | 
			
		||||
 | 
			
		||||
   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
 | 
			
		||||
details. */
 | 
			
		||||
 | 
			
		||||
#ifdef __OUTSIDE_CYGWIN__
 | 
			
		||||
#include "woutsup.h"
 | 
			
		||||
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
@@ -73,7 +74,7 @@ threaded_queue::~threaded_queue ()
 | 
			
		||||
    {
 | 
			
		||||
      queue_request *const ptr = reqptr;
 | 
			
		||||
      reqptr = reqptr->_next;
 | 
			
		||||
      safe_delete (ptr);
 | 
			
		||||
      delete ptr;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  DeleteCriticalSection (&_queue_lock);
 | 
			
		||||
@@ -267,7 +268,7 @@ threaded_queue::worker_loop ()
 | 
			
		||||
 | 
			
		||||
      assert (reqptr);
 | 
			
		||||
      reqptr->process ();
 | 
			
		||||
      safe_delete (reqptr);
 | 
			
		||||
      delete reqptr;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -406,3 +407,4 @@ queue_submission_loop::start_routine (const LPVOID lpParam)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*****************************************************************************/
 | 
			
		||||
#endif /* __OUTSIDE_CYGWIN__ */
 | 
			
		||||
 
 | 
			
		||||
@@ -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>
 | 
			
		||||
 | 
			
		||||
@@ -19,31 +19,33 @@ details. */
 | 
			
		||||
 | 
			
		||||
#include <sys/socket.h>
 | 
			
		||||
 | 
			
		||||
#include "safe_memory.h"
 | 
			
		||||
 | 
			
		||||
#include "cygserver_transport.h"
 | 
			
		||||
#include "cygserver_transport_pipes.h"
 | 
			
		||||
#include "cygserver_transport_sockets.h"
 | 
			
		||||
#include "transport.h"
 | 
			
		||||
#include "transport_pipes.h"
 | 
			
		||||
#include "transport_sockets.h"
 | 
			
		||||
 | 
			
		||||
/* The factory */
 | 
			
		||||
transport_layer_base *
 | 
			
		||||
create_server_transport ()
 | 
			
		||||
{
 | 
			
		||||
  if (wincap.is_winnt ())
 | 
			
		||||
    return safe_new0 (transport_layer_pipes);
 | 
			
		||||
    return new transport_layer_pipes;
 | 
			
		||||
  else
 | 
			
		||||
    return safe_new0 (transport_layer_sockets);
 | 
			
		||||
    return new transport_layer_sockets;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifndef __INSIDE_CYGWIN__
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
bool
 | 
			
		||||
transport_layer_base::impersonate_client ()
 | 
			
		||||
{}
 | 
			
		||||
{
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
bool
 | 
			
		||||
transport_layer_base::revert_to_self ()
 | 
			
		||||
{}
 | 
			
		||||
{
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif /* !__INSIDE_CYGWIN__ */
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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>
 | 
			
		||||
 | 
			
		||||
@@ -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
 | 
			
		||||
details. */
 | 
			
		||||
 | 
			
		||||
#ifndef _CYGSERVER_TRANSPORT_
 | 
			
		||||
#define _CYGSERVER_TRANSPORT_
 | 
			
		||||
#ifndef _TRANSPORT_H
 | 
			
		||||
#define _TRANSPORT_H
 | 
			
		||||
 | 
			
		||||
class transport_layer_base *create_server_transport ();
 | 
			
		||||
 | 
			
		||||
@@ -29,11 +29,11 @@ public:
 | 
			
		||||
  virtual int connect () = 0;
 | 
			
		||||
 | 
			
		||||
#ifndef __INSIDE_CYGWIN__
 | 
			
		||||
  virtual void impersonate_client ();
 | 
			
		||||
  virtual void revert_to_self ();
 | 
			
		||||
  virtual bool impersonate_client ();
 | 
			
		||||
  virtual bool revert_to_self ();
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  virtual ~transport_layer_base ();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif /* _CYGSERVER_TRANSPORT_ */
 | 
			
		||||
#endif /* _TRANSPORT_H */
 | 
			
		||||
@@ -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>
 | 
			
		||||
 | 
			
		||||
@@ -25,11 +25,14 @@ details. */
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
 | 
			
		||||
#include "cygerrno.h"
 | 
			
		||||
#include "cygserver_transport.h"
 | 
			
		||||
#include "cygserver_transport_pipes.h"
 | 
			
		||||
#include "transport.h"
 | 
			
		||||
#include "transport_pipes.h"
 | 
			
		||||
 | 
			
		||||
#ifndef __INSIDE_CYGWIN__
 | 
			
		||||
#include "cygserver.h"
 | 
			
		||||
#include "cygserver_ipc.h"
 | 
			
		||||
#else
 | 
			
		||||
#include "security.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
enum
 | 
			
		||||
@@ -64,7 +67,6 @@ transport_layer_pipes::transport_layer_pipes (const HANDLE hPipe)
 | 
			
		||||
  assert (_hPipe);
 | 
			
		||||
  assert (_hPipe != INVALID_HANDLE_VALUE);
 | 
			
		||||
 | 
			
		||||
  init_security ();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif /* !__INSIDE_CYGWIN__ */
 | 
			
		||||
@@ -75,22 +77,6 @@ transport_layer_pipes::transport_layer_pipes ()
 | 
			
		||||
    _is_accepted_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 ()
 | 
			
		||||
@@ -138,7 +124,7 @@ transport_layer_pipes::accept (bool *const recoverable)
 | 
			
		||||
		     (PIPE_TYPE_BYTE | PIPE_WAIT),
 | 
			
		||||
		     PIPE_UNLIMITED_INSTANCES,
 | 
			
		||||
		     0, 0, 1000,
 | 
			
		||||
		     &_sec_all_nih);
 | 
			
		||||
		     &sec_all_nih);
 | 
			
		||||
 | 
			
		||||
  const bool duplicate = (accept_pipe == INVALID_HANDLE_VALUE
 | 
			
		||||
			  && pipe_instance == 0
 | 
			
		||||
@@ -175,7 +161,7 @@ transport_layer_pipes::accept (bool *const recoverable)
 | 
			
		||||
      return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return safe_new (transport_layer_pipes, accept_pipe);
 | 
			
		||||
  return new transport_layer_pipes (accept_pipe);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif /* !__INSIDE_CYGWIN__ */
 | 
			
		||||
@@ -281,7 +267,7 @@ transport_layer_pipes::connect ()
 | 
			
		||||
      _hPipe = CreateFile (_pipe_name,
 | 
			
		||||
			   GENERIC_READ | GENERIC_WRITE,
 | 
			
		||||
			   FILE_SHARE_READ | FILE_SHARE_WRITE,
 | 
			
		||||
			   &_sec_all_nih,
 | 
			
		||||
			   &sec_all_nih,
 | 
			
		||||
			   OPEN_EXISTING,
 | 
			
		||||
			   SECURITY_IMPERSONATION,
 | 
			
		||||
			   NULL);
 | 
			
		||||
@@ -331,32 +317,33 @@ transport_layer_pipes::connect ()
 | 
			
		||||
 | 
			
		||||
#ifndef __INSIDE_CYGWIN__
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
bool
 | 
			
		||||
transport_layer_pipes::impersonate_client ()
 | 
			
		||||
{
 | 
			
		||||
  assert (_hPipe);
 | 
			
		||||
  assert (_hPipe != INVALID_HANDLE_VALUE);
 | 
			
		||||
  assert (_is_accepted_endpoint);
 | 
			
		||||
 | 
			
		||||
  // verbose: debug_printf ("impersonating pipe %p", _hPipe);
 | 
			
		||||
  if (_hPipe)
 | 
			
		||||
  if (_hPipe && !ImpersonateNamedPipeClient (_hPipe))
 | 
			
		||||
    {
 | 
			
		||||
      assert (_hPipe != INVALID_HANDLE_VALUE);
 | 
			
		||||
 | 
			
		||||
      if (!ImpersonateNamedPipeClient (_hPipe))
 | 
			
		||||
	debug_printf ("Failed to Impersonate the client, (%lu)",
 | 
			
		||||
		      GetLastError ());
 | 
			
		||||
      debug_printf ("Failed to Impersonate client, (%lu)", GetLastError ());
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
  // verbose: debug_printf ("I am who you are");
 | 
			
		||||
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
bool
 | 
			
		||||
transport_layer_pipes::revert_to_self ()
 | 
			
		||||
{
 | 
			
		||||
  assert (_is_accepted_endpoint);
 | 
			
		||||
 | 
			
		||||
  RevertToSelf ();
 | 
			
		||||
  // verbose: debug_printf ("I am who I yam");
 | 
			
		||||
  if (!RevertToSelf ())
 | 
			
		||||
    {
 | 
			
		||||
      debug_printf ("Failed to RevertToSelf, (%lu)", GetLastError ());
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif /* !__INSIDE_CYGWIN__ */
 | 
			
		||||
 
 | 
			
		||||
@@ -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>
 | 
			
		||||
 | 
			
		||||
@@ -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
 | 
			
		||||
details. */
 | 
			
		||||
 | 
			
		||||
#ifndef _CYGSERVER_TRANSPORT_PIPES_
 | 
			
		||||
#define _CYGSERVER_TRANSPORT_PIPES_
 | 
			
		||||
#ifndef _TRANSPORT_PIPES_H
 | 
			
		||||
#define _TRANSPORT_PIPES_H
 | 
			
		||||
 | 
			
		||||
/* Named pipes based transport, for security on NT */
 | 
			
		||||
class transport_layer_pipes : public transport_layer_base
 | 
			
		||||
@@ -28,20 +28,14 @@ public:
 | 
			
		||||
  virtual int connect ();
 | 
			
		||||
 | 
			
		||||
#ifndef __INSIDE_CYGWIN__
 | 
			
		||||
  virtual void impersonate_client ();
 | 
			
		||||
  virtual void revert_to_self ();
 | 
			
		||||
  virtual bool impersonate_client ();
 | 
			
		||||
  virtual bool revert_to_self ();
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  transport_layer_pipes ();
 | 
			
		||||
  virtual ~transport_layer_pipes ();
 | 
			
		||||
 | 
			
		||||
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;
 | 
			
		||||
  HANDLE _hPipe;
 | 
			
		||||
  const bool _is_accepted_endpoint;
 | 
			
		||||
@@ -50,4 +44,4 @@ private:
 | 
			
		||||
  transport_layer_pipes (HANDLE hPipe);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif /* _CYGSERVER_TRANSPORT_PIPES_ */
 | 
			
		||||
#endif /* _TRANSPORT_PIPES_H */
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
/* cygserver_transport_sockets.cc
 | 
			
		||||
/* transport_sockets.cc
 | 
			
		||||
 | 
			
		||||
   Copyright 2001, 2002 Red Hat Inc.
 | 
			
		||||
 | 
			
		||||
@@ -26,8 +26,8 @@ details. */
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
 | 
			
		||||
#include "cygserver_transport.h"
 | 
			
		||||
#include "cygserver_transport_sockets.h"
 | 
			
		||||
#include "transport.h"
 | 
			
		||||
#include "transport_sockets.h"
 | 
			
		||||
 | 
			
		||||
/* to allow this to link into cygwin and the .dll, a little magic is needed. */
 | 
			
		||||
#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);
 | 
			
		||||
 | 
			
		||||
  return safe_new (transport_layer_sockets, accept_fd);
 | 
			
		||||
  return new transport_layer_sockets (accept_fd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif /* !__INSIDE_CYGWIN__ */
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
/* cygserver_transport_sockets.h
 | 
			
		||||
/* transport_sockets.h
 | 
			
		||||
 | 
			
		||||
   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
 | 
			
		||||
details. */
 | 
			
		||||
 | 
			
		||||
#ifndef _CYGSERVER_TRANSPORT_SOCKETS_
 | 
			
		||||
#define _CYGSERVER_TRANSPORT_SOCKETS_
 | 
			
		||||
#ifndef _TRANSPORT_SOCKETS_H
 | 
			
		||||
#define _TRANSPORT_SOCKETS_H
 | 
			
		||||
 | 
			
		||||
#include <sys/socket.h>
 | 
			
		||||
#include <sys/un.h>
 | 
			
		||||
@@ -43,4 +43,4 @@ private:
 | 
			
		||||
  transport_layer_sockets (int fd);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif /* _CYGSERVER_TRANSPORT_SOCKETS_ */
 | 
			
		||||
#endif /* _TRANSPORT_SOCKETS_H */
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
/* 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.
 | 
			
		||||
 | 
			
		||||
@@ -42,67 +42,32 @@ details. */
 | 
			
		||||
 | 
			
		||||
#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 */
 | 
			
		||||
extern "C" DWORD WINAPI GetLastError (void);
 | 
			
		||||
 | 
			
		||||
extern int cygserver_running;
 | 
			
		||||
 | 
			
		||||
#if !defined(__STDC_VERSION__) || __STDC_VERSION__ >= 199900L
 | 
			
		||||
#define NEW_MACRO_VARARGS
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * A reproduction of the <sys/strace.h> macros.  This allows code that
 | 
			
		||||
 * runs both inside and outside the Cygwin DLL to use the same macros
 | 
			
		||||
 * for logging messages.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
extern "C" void __cygserver__printf (const char *, const char *, ...);
 | 
			
		||||
 | 
			
		||||
#ifdef NEW_MACRO_VARARGS
 | 
			
		||||
 | 
			
		||||
#define system_printf(...)					\
 | 
			
		||||
  do								\
 | 
			
		||||
    {								\
 | 
			
		||||
      __cygserver__printf (__PRETTY_FUNCTION__, __VA_ARGS__);	\
 | 
			
		||||
#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)				\
 | 
			
		||||
	{								\
 | 
			
		||||
	  panic ("failed to install handler for " #SIG ": %s",		\
 | 
			
		||||
		 strerror (errno));					\
 | 
			
		||||
	  exit (1);							\
 | 
			
		||||
	}								\
 | 
			
		||||
    } while (false)
 | 
			
		||||
 | 
			
		||||
#define __noop_printf(...) do {;} while (false)
 | 
			
		||||
 | 
			
		||||
#else /* !NEW_MACRO_VARARGS */
 | 
			
		||||
 | 
			
		||||
#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"
 | 
			
		||||
#define debug_printf(f,...)	debug((f),##__VA_ARGS__)
 | 
			
		||||
#define syscall_printf(f,...)	log(LOG_ERR,(f),##__VA_ARGS__)
 | 
			
		||||
#define system_printf(f,...)	log(LOG_ERR,(f),##__VA_ARGS__)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user